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 <fmtanchr.hxx>
21 : #include <fmtcntnt.hxx>
22 : #include <txtftn.hxx>
23 : #include <acorrect.hxx>
24 : #include <UndoManager.hxx>
25 : #include <docsh.hxx>
26 : #include <docary.hxx>
27 : #include <doctxm.hxx>
28 : #include <ftnidx.hxx>
29 : #include <mdiexp.hxx>
30 : #include <mvsave.hxx>
31 : #include <redline.hxx>
32 : #include <rootfrm.hxx>
33 : #include <splargs.hxx>
34 : #include <txtfrm.hxx>
35 : #include <UndoSplitMove.hxx>
36 : #include <UndoRedline.hxx>
37 : #include <UndoOverwrite.hxx>
38 : #include <UndoInsert.hxx>
39 : #include <UndoDelete.hxx>
40 : #include <breakit.hxx>
41 : #include <vcl/layout.hxx>
42 : #include "comcore.hrc"
43 : #include "editsh.hxx"
44 : #include <fmtfld.hxx>
45 : #include <docufld.hxx>
46 : #include <unoflatpara.hxx>
47 : #include <SwGrammarMarkUp.hxx>
48 :
49 : #include <vector>
50 :
51 : using namespace ::com::sun::star;
52 : using namespace ::com::sun::star::linguistic2;
53 : using namespace ::com::sun::star::i18n;
54 :
55 : struct _SaveRedline
56 : {
57 : SwRangeRedline* pRedl;
58 : sal_uInt32 nStt, nEnd;
59 : sal_Int32 nSttCnt;
60 : sal_Int32 nEndCnt;
61 :
62 0 : _SaveRedline( SwRangeRedline* pR, const SwNodeIndex& rSttIdx )
63 : : pRedl(pR)
64 : , nEnd(0)
65 0 : , nEndCnt(0)
66 : {
67 0 : const SwPosition* pStt = pR->Start(),
68 0 : * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
69 0 : sal_uInt32 nSttIdx = rSttIdx.GetIndex();
70 0 : nStt = pStt->nNode.GetIndex() - nSttIdx;
71 0 : nSttCnt = pStt->nContent.GetIndex();
72 0 : if( pR->HasMark() )
73 : {
74 0 : nEnd = pEnd->nNode.GetIndex() - nSttIdx;
75 0 : nEndCnt = pEnd->nContent.GetIndex();
76 : }
77 :
78 0 : pRedl->GetPoint()->nNode = 0;
79 0 : pRedl->GetPoint()->nContent.Assign( 0, 0 );
80 0 : pRedl->GetMark()->nNode = 0;
81 0 : pRedl->GetMark()->nContent.Assign( 0, 0 );
82 0 : }
83 :
84 0 : _SaveRedline( SwRangeRedline* pR, const SwPosition& rPos )
85 : : pRedl(pR)
86 : , nEnd(0)
87 0 : , nEndCnt(0)
88 : {
89 0 : const SwPosition* pStt = pR->Start(),
90 0 : * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
91 0 : sal_uInt32 nSttIdx = rPos.nNode.GetIndex();
92 0 : nStt = pStt->nNode.GetIndex() - nSttIdx;
93 0 : nSttCnt = pStt->nContent.GetIndex();
94 0 : if( nStt == 0 )
95 0 : nSttCnt = nSttCnt - rPos.nContent.GetIndex();
96 0 : if( pR->HasMark() )
97 : {
98 0 : nEnd = pEnd->nNode.GetIndex() - nSttIdx;
99 0 : nEndCnt = pEnd->nContent.GetIndex();
100 0 : if( nEnd == 0 )
101 0 : nEndCnt = nEndCnt - rPos.nContent.GetIndex();
102 : }
103 :
104 0 : pRedl->GetPoint()->nNode = 0;
105 0 : pRedl->GetPoint()->nContent.Assign( 0, 0 );
106 0 : pRedl->GetMark()->nNode = 0;
107 0 : pRedl->GetMark()->nContent.Assign( 0, 0 );
108 0 : }
109 :
110 0 : void SetPos( sal_uInt32 nInsPos )
111 : {
112 0 : pRedl->GetPoint()->nNode = nInsPos + nStt;
113 0 : pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt );
114 0 : if( pRedl->HasMark() )
115 : {
116 0 : pRedl->GetMark()->nNode = nInsPos + nEnd;
117 0 : pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(false), nEndCnt );
118 : }
119 0 : }
120 :
121 0 : void SetPos( const SwPosition& aPos )
122 : {
123 0 : pRedl->GetPoint()->nNode = aPos.nNode.GetIndex() + nStt;
124 0 : pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt + ( nStt == 0 ? aPos.nContent.GetIndex() : 0 ) );
125 0 : if( pRedl->HasMark() )
126 : {
127 0 : pRedl->GetMark()->nNode = aPos.nNode.GetIndex() + nEnd;
128 0 : pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(false), nEndCnt + ( nEnd == 0 ? aPos.nContent.GetIndex() : 0 ) );
129 : }
130 0 : }
131 : };
132 :
133 : typedef boost::ptr_vector< _SaveRedline > _SaveRedlines;
134 :
135 0 : static bool lcl_MayOverwrite( const SwTxtNode *pNode, const sal_Int32 nPos )
136 : {
137 0 : sal_Unicode const cChr = pNode->GetTxt()[nPos];
138 0 : switch (cChr)
139 : {
140 : case CH_TXTATR_BREAKWORD:
141 : case CH_TXTATR_INWORD:
142 0 : return !pNode->GetTxtAttrForCharAt(nPos);// how could there be none?
143 : case CH_TXT_ATR_FIELDSTART:
144 : case CH_TXT_ATR_FIELDEND:
145 : case CH_TXT_ATR_FORMELEMENT:
146 0 : return false;
147 : default:
148 0 : return true;
149 : }
150 : }
151 :
152 0 : static void lcl_SkipAttr( const SwTxtNode *pNode, SwIndex &rIdx, sal_Int32 &rStart )
153 : {
154 0 : if( !lcl_MayOverwrite( pNode, rStart ) )
155 : {
156 : // skip all special attributes
157 0 : do {
158 0 : ++rIdx;
159 0 : rStart = rIdx.GetIndex();
160 0 : } while (rStart < pNode->GetTxt().getLength()
161 0 : && !lcl_MayOverwrite(pNode, rStart) );
162 : }
163 0 : }
164 :
165 0 : void _RestFlyInRange( _SaveFlyArr & rArr, const SwNodeIndex& rSttIdx,
166 : const SwNodeIndex* pInsertPos )
167 : {
168 0 : SwPosition aPos( rSttIdx );
169 0 : for( size_t n = 0; n < rArr.size(); ++n )
170 : {
171 : // create new anchor
172 0 : _SaveFly& rSave = rArr[n];
173 0 : SwFrmFmt* pFmt = rSave.pFrmFmt;
174 :
175 0 : if( rSave.bInsertPosition )
176 : {
177 0 : if( pInsertPos != NULL )
178 0 : aPos.nNode = *pInsertPos;
179 : else
180 0 : aPos.nNode = rSttIdx.GetIndex();
181 : }
182 : else
183 0 : aPos.nNode = rSttIdx.GetIndex() + rSave.nNdDiff;
184 :
185 0 : aPos.nContent.Assign( 0, 0 );
186 0 : SwFmtAnchor aAnchor( pFmt->GetAnchor() );
187 0 : aAnchor.SetAnchor( &aPos );
188 0 : pFmt->GetDoc()->GetSpzFrmFmts()->push_back( pFmt );
189 0 : pFmt->SetFmtAttr( aAnchor );
190 0 : SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode();
191 0 : if( pCNd && pCNd->getLayoutFrm( pFmt->GetDoc()->GetCurrentLayout(), 0, 0, false ) )
192 0 : pFmt->MakeFrms();
193 0 : }
194 0 : }
195 :
196 0 : void _SaveFlyInRange( const SwNodeRange& rRg, _SaveFlyArr& rArr )
197 : {
198 0 : SwFrmFmts& rFmts = *rRg.aStart.GetNode().GetDoc()->GetSpzFrmFmts();
199 0 : for( sal_uInt16 n = 0; n < rFmts.size(); ++n )
200 : {
201 0 : SwFrmFmt *const pFmt = static_cast<SwFrmFmt*>(rFmts[n]);
202 0 : SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
203 0 : SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
204 0 : if (pAPos &&
205 0 : ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
206 0 : (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
207 0 : rRg.aStart <= pAPos->nNode && pAPos->nNode < rRg.aEnd )
208 : {
209 0 : _SaveFly aSave( pAPos->nNode.GetIndex() - rRg.aStart.GetIndex(),
210 0 : pFmt, false );
211 0 : rArr.push_back( aSave );
212 0 : pFmt->DelFrms();
213 0 : rFmts.erase( rFmts.begin() + n-- );
214 : }
215 : }
216 0 : }
217 :
218 0 : void _SaveFlyInRange( const SwPaM& rPam, const SwNodeIndex& rInsPos,
219 : _SaveFlyArr& rArr, bool bMoveAllFlys )
220 : {
221 0 : SwFrmFmts& rFmts = *rPam.GetPoint()->nNode.GetNode().GetDoc()->GetSpzFrmFmts();
222 : SwFrmFmt* pFmt;
223 : const SwFmtAnchor* pAnchor;
224 :
225 0 : const SwPosition* pPos = rPam.Start();
226 0 : const SwNodeIndex& rSttNdIdx = pPos->nNode;
227 0 : short nSttOff = (!bMoveAllFlys && rSttNdIdx.GetNode().IsCntntNode() &&
228 0 : pPos->nContent.GetIndex()) ? 1 : 0;
229 :
230 0 : pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint();
231 0 : const SwNodeIndex& rEndNdIdx = pPos->nNode;
232 0 : short nOff = ( bMoveAllFlys || ( rEndNdIdx.GetNode().IsCntntNode() &&
233 0 : pPos->nContent == rEndNdIdx.GetNode().GetCntntNode()->Len() ))
234 0 : ? 0 : 1;
235 :
236 : const SwNodeIndex* pCntntIdx;
237 :
238 0 : for( sal_uInt16 n = 0; n < rFmts.size(); ++n )
239 : {
240 0 : bool bInsPos = false;
241 0 : pFmt = (SwFrmFmt*)rFmts[n];
242 0 : pAnchor = &pFmt->GetAnchor();
243 0 : const SwPosition* pAPos = pAnchor->GetCntntAnchor();
244 0 : if (pAPos &&
245 0 : ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
246 0 : (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
247 : // do not move if the InsPos is in the CntntArea of the Fly
248 0 : ( 0 == ( pCntntIdx = pFmt->GetCntnt().GetCntntIdx() ) ||
249 0 : !( *pCntntIdx < rInsPos &&
250 0 : rInsPos < pCntntIdx->GetNode().EndOfSectionIndex() )) )
251 : {
252 0 : if( !bMoveAllFlys && rEndNdIdx == pAPos->nNode )
253 : {
254 : // Do not touch Anchor, if only a part of the EndNode
255 : // or the whole EndNode is identical with the SttNode
256 0 : if( rSttNdIdx != pAPos->nNode )
257 : {
258 : // Only attach an anchor to the beginning or end
259 0 : SwPosition aPos( rSttNdIdx );
260 0 : SwFmtAnchor aAnchor( *pAnchor );
261 0 : aAnchor.SetAnchor( &aPos );
262 0 : pFmt->SetFmtAttr( aAnchor );
263 : }
264 : }
265 0 : else if( ( rSttNdIdx.GetIndex() + nSttOff <= pAPos->nNode.GetIndex()
266 0 : && pAPos->nNode.GetIndex() <= rEndNdIdx.GetIndex() - nOff ) ||
267 0 : ( bInsPos = (rInsPos == pAPos->nNode) ))
268 :
269 : {
270 0 : _SaveFly aSave( pAPos->nNode.GetIndex() - rSttNdIdx.GetIndex(),
271 0 : pFmt, bInsPos );
272 0 : rArr.push_back( aSave );
273 0 : pFmt->DelFrms();
274 0 : rFmts.erase( rFmts.begin() + n-- );
275 : }
276 : }
277 : }
278 0 : }
279 :
280 : /// Delete and move all Flys at the paragraph, that are within the selection.
281 : /// If there is a Fly at the SPoint, it is moved onto the Mark.
282 0 : void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
283 : const SwNodeIndex& rPtNdIdx )
284 : {
285 0 : const bool bDelFwrd = rMkNdIdx.GetIndex() <= rPtNdIdx.GetIndex();
286 :
287 0 : SwDoc* pDoc = rMkNdIdx.GetNode().GetDoc();
288 0 : SwFrmFmts& rTbl = *pDoc->GetSpzFrmFmts();
289 0 : for ( sal_uInt16 i = rTbl.size(); i; )
290 : {
291 0 : SwFrmFmt *pFmt = rTbl[--i];
292 0 : const SwFmtAnchor &rAnch = pFmt->GetAnchor();
293 0 : SwPosition const*const pAPos = rAnch.GetCntntAnchor();
294 0 : if (pAPos &&
295 0 : ((rAnch.GetAnchorId() == FLY_AT_PARA) ||
296 0 : (rAnch.GetAnchorId() == FLY_AT_CHAR)) &&
297 : ( bDelFwrd
298 0 : ? rMkNdIdx < pAPos->nNode && pAPos->nNode <= rPtNdIdx
299 0 : : rPtNdIdx <= pAPos->nNode && pAPos->nNode < rMkNdIdx ))
300 : {
301 : // Only move the Anchor??
302 0 : if( rPtNdIdx == pAPos->nNode )
303 : {
304 0 : SwFmtAnchor aAnch( pFmt->GetAnchor() );
305 0 : SwPosition aPos( rMkNdIdx );
306 0 : aAnch.SetAnchor( &aPos );
307 0 : pFmt->SetFmtAttr( aAnch );
308 : }
309 : else
310 : {
311 : // If the Fly is deleted, all Flys in it's content have to be deleted too.
312 0 : const SwFmtCntnt &rCntnt = pFmt->GetCntnt();
313 0 : if( rCntnt.GetCntntIdx() )
314 : {
315 0 : DelFlyInRange( *rCntnt.GetCntntIdx(),
316 : SwNodeIndex( *rCntnt.GetCntntIdx()->
317 0 : GetNode().EndOfSectionNode() ));
318 : // Position could have been moved!
319 0 : if( i > rTbl.size() )
320 0 : i = rTbl.size();
321 0 : else if( pFmt != rTbl[i] )
322 0 : i = rTbl.GetPos( pFmt );
323 : }
324 :
325 0 : pDoc->DelLayoutFmt( pFmt );
326 :
327 : // DelLayoutFmt can also trigger the deletion of objects.
328 0 : if( i > rTbl.size() )
329 0 : i = rTbl.size();
330 : }
331 : }
332 : }
333 0 : }
334 :
335 0 : static bool lcl_SaveFtn( const SwNodeIndex& rSttNd, const SwNodeIndex& rEndNd,
336 : const SwNodeIndex& rInsPos,
337 : SwFtnIdxs& rFtnArr, SwFtnIdxs& rSaveArr,
338 : const SwIndex* pSttCnt = 0, const SwIndex* pEndCnt = 0 )
339 : {
340 0 : bool bUpdateFtn = false;
341 0 : const SwNodes& rNds = rInsPos.GetNodes();
342 0 : const bool bDelFtn = rInsPos.GetIndex() < rNds.GetEndOfAutotext().GetIndex() &&
343 0 : rSttNd.GetIndex() >= rNds.GetEndOfAutotext().GetIndex();
344 0 : const bool bSaveFtn = !bDelFtn &&
345 0 : rInsPos.GetIndex() >= rNds.GetEndOfExtras().GetIndex();
346 0 : if( !rFtnArr.empty() )
347 : {
348 :
349 : sal_uInt16 nPos;
350 0 : rFtnArr.SeekEntry( rSttNd, &nPos );
351 : SwTxtFtn* pSrch;
352 : const SwNode* pFtnNd;
353 :
354 : // Delete/save all that come after it
355 0 : while( nPos < rFtnArr.size() && ( pFtnNd =
356 0 : &( pSrch = rFtnArr[ nPos ] )->GetTxtNode())->GetIndex()
357 0 : <= rEndNd.GetIndex() )
358 : {
359 0 : const sal_Int32 nFtnSttIdx = *pSrch->GetStart();
360 0 : if( ( pEndCnt && pSttCnt )
361 0 : ? (( &rSttNd.GetNode() == pFtnNd &&
362 0 : pSttCnt->GetIndex() > nFtnSttIdx) ||
363 0 : ( &rEndNd.GetNode() == pFtnNd &&
364 0 : nFtnSttIdx >= pEndCnt->GetIndex() ))
365 0 : : ( &rEndNd.GetNode() == pFtnNd ))
366 : {
367 0 : ++nPos; // continue searching
368 : }
369 : else
370 : {
371 : // delete it
372 0 : if( bDelFtn )
373 : {
374 0 : SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
375 0 : SwIndex aIdx( &rTxtNd, nFtnSttIdx );
376 0 : rTxtNd.EraseText( aIdx, 1 );
377 : }
378 : else
379 : {
380 0 : pSrch->DelFrms(0);
381 0 : rFtnArr.erase( rFtnArr.begin() + nPos );
382 0 : if( bSaveFtn )
383 0 : rSaveArr.insert( pSrch );
384 : }
385 0 : bUpdateFtn = true;
386 : }
387 : }
388 :
389 0 : while( nPos-- && ( pFtnNd = &( pSrch = rFtnArr[ nPos ] )->
390 0 : GetTxtNode())->GetIndex() >= rSttNd.GetIndex() )
391 : {
392 0 : const sal_Int32 nFtnSttIdx = *pSrch->GetStart();
393 0 : if( !pEndCnt || !pSttCnt ||
394 0 : !( (( &rSttNd.GetNode() == pFtnNd &&
395 0 : pSttCnt->GetIndex() > nFtnSttIdx ) ||
396 0 : ( &rEndNd.GetNode() == pFtnNd &&
397 0 : nFtnSttIdx >= pEndCnt->GetIndex() )) ))
398 : {
399 0 : if( bDelFtn )
400 : {
401 : // delete it
402 0 : SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
403 0 : SwIndex aIdx( &rTxtNd, nFtnSttIdx );
404 0 : rTxtNd.EraseText( aIdx, 1 );
405 : }
406 : else
407 : {
408 0 : pSrch->DelFrms(0);
409 0 : rFtnArr.erase( rFtnArr.begin() + nPos );
410 0 : if( bSaveFtn )
411 0 : rSaveArr.insert( pSrch );
412 : }
413 0 : bUpdateFtn = true;
414 : }
415 : }
416 : }
417 : // When moving from redline section into document content section, e.g.
418 : // after loading a document with (delete-)redlines, the footnote array
419 : // has to be adjusted... (#i70572)
420 0 : if( bSaveFtn )
421 : {
422 0 : SwNodeIndex aIdx( rSttNd );
423 0 : while( aIdx < rEndNd ) // Check the moved section
424 : {
425 0 : SwNode* pNode = &aIdx.GetNode();
426 0 : if( pNode->IsTxtNode() ) // Looking for text nodes...
427 : {
428 : SwpHints *pHints =
429 0 : static_cast<SwTxtNode*>(pNode)->GetpSwpHints();
430 0 : if( pHints && pHints->HasFtn() ) //...with footnotes
431 : {
432 0 : bUpdateFtn = true; // Heureka
433 0 : sal_uInt16 nCount = pHints->Count();
434 0 : for( sal_uInt16 i = 0; i < nCount; ++i )
435 : {
436 0 : SwTxtAttr *pAttr = pHints->GetTextHint( i );
437 0 : if ( pAttr->Which() == RES_TXTATR_FTN )
438 : {
439 0 : rSaveArr.insert( static_cast<SwTxtFtn*>(pAttr) );
440 : }
441 : }
442 : }
443 : }
444 0 : ++aIdx;
445 0 : }
446 : }
447 0 : return bUpdateFtn;
448 : }
449 :
450 0 : static void lcl_SaveRedlines( const SwPaM& aPam, _SaveRedlines& rArr )
451 : {
452 0 : SwDoc* pDoc = aPam.GetNode()->GetDoc();
453 :
454 0 : const SwPosition* pStart = aPam.Start();
455 0 : const SwPosition* pEnd = aPam.End();
456 :
457 : // get first relevant redline
458 : sal_uInt16 nCurrentRedline;
459 0 : pDoc->GetRedline( *pStart, &nCurrentRedline );
460 0 : if( nCurrentRedline > 0)
461 0 : nCurrentRedline--;
462 :
463 : // redline mode REDLINE_IGNORE|REDLINE_ON; save old mode
464 0 : RedlineMode_t eOld = pDoc->GetRedlineMode();
465 0 : pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
466 :
467 : // iterate over relevant redlines and decide for each whether it should
468 : // be saved, or split + saved
469 0 : SwRedlineTbl& rRedlineTable = const_cast<SwRedlineTbl&>( pDoc->GetRedlineTbl() );
470 0 : for( ; nCurrentRedline < rRedlineTable.size(); nCurrentRedline++ )
471 : {
472 0 : SwRangeRedline* pCurrent = rRedlineTable[ nCurrentRedline ];
473 : SwComparePosition eCompare =
474 0 : ComparePosition( *pCurrent->Start(), *pCurrent->End(),
475 0 : *pStart, *pEnd);
476 :
477 : // we must save this redline if it overlaps aPam
478 : // (we may have to split it, too)
479 0 : if( eCompare == POS_OVERLAP_BEHIND ||
480 0 : eCompare == POS_OVERLAP_BEFORE ||
481 0 : eCompare == POS_OUTSIDE ||
482 0 : eCompare == POS_INSIDE ||
483 : eCompare == POS_EQUAL )
484 : {
485 0 : rRedlineTable.Remove( nCurrentRedline-- );
486 :
487 : // split beginning, if necessary
488 0 : if( eCompare == POS_OVERLAP_BEFORE ||
489 : eCompare == POS_OUTSIDE )
490 : {
491 0 : SwRangeRedline* pNewRedline = new SwRangeRedline( *pCurrent );
492 0 : *pNewRedline->End() = *pStart;
493 0 : *pCurrent->Start() = *pStart;
494 0 : pDoc->AppendRedline( pNewRedline, true );
495 : }
496 :
497 : // split end, if necessary
498 0 : if( eCompare == POS_OVERLAP_BEHIND ||
499 : eCompare == POS_OUTSIDE )
500 : {
501 0 : SwRangeRedline* pNewRedline = new SwRangeRedline( *pCurrent );
502 0 : *pNewRedline->Start() = *pEnd;
503 0 : *pCurrent->End() = *pEnd;
504 0 : pDoc->AppendRedline( pNewRedline, true );
505 : }
506 :
507 : // save the current redline
508 0 : _SaveRedline* pSave = new _SaveRedline( pCurrent, *pStart );
509 0 : rArr.push_back( pSave );
510 : }
511 : }
512 :
513 : // restore old redline mode
514 0 : pDoc->SetRedlineMode_intern( eOld );
515 0 : }
516 :
517 0 : static void lcl_RestoreRedlines( SwDoc* pDoc, const SwPosition& rPos, _SaveRedlines& rArr )
518 : {
519 0 : RedlineMode_t eOld = pDoc->GetRedlineMode();
520 0 : pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
521 :
522 0 : for( size_t n = 0; n < rArr.size(); ++n )
523 : {
524 0 : rArr[ n ].SetPos( rPos );
525 0 : pDoc->AppendRedline( rArr[ n ].pRedl, true );
526 : }
527 :
528 0 : pDoc->SetRedlineMode_intern( eOld );
529 0 : }
530 :
531 0 : static void lcl_SaveRedlines( const SwNodeRange& rRg, _SaveRedlines& rArr )
532 : {
533 0 : SwDoc* pDoc = rRg.aStart.GetNode().GetDoc();
534 : sal_uInt16 nRedlPos;
535 0 : SwPosition aSrchPos( rRg.aStart ); aSrchPos.nNode--;
536 0 : aSrchPos.nContent.Assign( aSrchPos.nNode.GetNode().GetCntntNode(), 0 );
537 0 : if( pDoc->GetRedline( aSrchPos, &nRedlPos ) && nRedlPos )
538 0 : --nRedlPos;
539 0 : else if( nRedlPos >= pDoc->GetRedlineTbl().size() )
540 0 : return ;
541 :
542 0 : RedlineMode_t eOld = pDoc->GetRedlineMode();
543 0 : pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
544 0 : SwRedlineTbl& rRedlTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl();
545 :
546 0 : do {
547 0 : SwRangeRedline* pTmp = rRedlTbl[ nRedlPos ];
548 :
549 0 : const SwPosition* pRStt = pTmp->Start(),
550 0 : * pREnd = pTmp->GetMark() == pRStt
551 0 : ? pTmp->GetPoint() : pTmp->GetMark();
552 :
553 0 : if( pRStt->nNode < rRg.aStart )
554 : {
555 0 : if( pREnd->nNode > rRg.aStart && pREnd->nNode < rRg.aEnd )
556 : {
557 : // Create a copy and set the end of the original to the end of the MoveArea.
558 : // The copy is moved too.
559 0 : SwRangeRedline* pNewRedl = new SwRangeRedline( *pTmp );
560 0 : SwPosition* pTmpPos = pNewRedl->Start();
561 0 : pTmpPos->nNode = rRg.aStart;
562 : pTmpPos->nContent.Assign(
563 0 : pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
564 :
565 0 : _SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
566 0 : rArr.push_back( pSave );
567 :
568 0 : pTmpPos = pTmp->End();
569 0 : pTmpPos->nNode = rRg.aEnd;
570 : pTmpPos->nContent.Assign(
571 0 : pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
572 : }
573 0 : else if( pREnd->nNode == rRg.aStart )
574 : {
575 0 : SwPosition* pTmpPos = pTmp->End();
576 0 : pTmpPos->nNode = rRg.aEnd;
577 : pTmpPos->nContent.Assign(
578 0 : pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
579 : }
580 : }
581 0 : else if( pRStt->nNode < rRg.aEnd )
582 : {
583 0 : rRedlTbl.Remove( nRedlPos-- );
584 0 : if( pREnd->nNode < rRg.aEnd ||
585 0 : ( pREnd->nNode == rRg.aEnd && !pREnd->nContent.GetIndex()) )
586 : {
587 : // move everything
588 0 : _SaveRedline* pSave = new _SaveRedline( pTmp, rRg.aStart );
589 0 : rArr.push_back( pSave );
590 : }
591 : else
592 : {
593 : // split
594 0 : SwRangeRedline* pNewRedl = new SwRangeRedline( *pTmp );
595 0 : SwPosition* pTmpPos = pNewRedl->End();
596 0 : pTmpPos->nNode = rRg.aEnd;
597 : pTmpPos->nContent.Assign(
598 0 : pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
599 :
600 0 : _SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
601 0 : rArr.push_back( pSave );
602 :
603 0 : pTmpPos = pTmp->Start();
604 0 : pTmpPos->nNode = rRg.aEnd;
605 : pTmpPos->nContent.Assign(
606 0 : pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
607 0 : pDoc->AppendRedline( pTmp, true );
608 : }
609 : }
610 : else
611 0 : break;
612 :
613 0 : } while( ++nRedlPos < pDoc->GetRedlineTbl().size() );
614 0 : pDoc->SetRedlineMode_intern( eOld );
615 : }
616 :
617 0 : static void lcl_RestoreRedlines( SwDoc* pDoc, sal_uInt32 nInsPos, _SaveRedlines& rArr )
618 : {
619 0 : RedlineMode_t eOld = pDoc->GetRedlineMode();
620 0 : pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
621 :
622 0 : for( size_t n = 0; n < rArr.size(); ++n )
623 : {
624 0 : rArr[ n ].SetPos( nInsPos );
625 0 : pDoc->AppendRedline( rArr[ n ].pRedl, true );
626 : }
627 :
628 0 : pDoc->SetRedlineMode_intern( eOld );
629 0 : }
630 :
631 : // #i59534: Redo of insertion of multiple text nodes runs into trouble
632 : // because of unnecessary expanded redlines
633 : // From now on this class saves the redline positions of all redlines which ends exact at the
634 : // insert position (node _and_ content index)
635 0 : _SaveRedlEndPosForRestore::_SaveRedlEndPosForRestore( const SwNodeIndex& rInsIdx, sal_Int32 nCnt )
636 0 : : pSavArr( 0 ), pSavIdx( 0 ), nSavCntnt( nCnt )
637 : {
638 0 : SwNode& rNd = rInsIdx.GetNode();
639 0 : SwDoc* pDest = rNd.GetDoc();
640 0 : if( !pDest->GetRedlineTbl().empty() )
641 : {
642 : sal_uInt16 nFndPos;
643 : const SwPosition* pEnd;
644 0 : SwPosition aSrcPos( rInsIdx, SwIndex( rNd.GetCntntNode(), nCnt ));
645 0 : pDest->GetRedline( aSrcPos, &nFndPos );
646 : const SwRangeRedline* pRedl;
647 0 : while( nFndPos--
648 0 : && *( pEnd = ( pRedl = pDest->GetRedlineTbl()[ nFndPos ] )->End() ) == aSrcPos
649 0 : && *pRedl->Start() < aSrcPos )
650 : {
651 0 : if( !pSavArr )
652 : {
653 0 : pSavArr = new std::vector<SwPosition*>;
654 0 : pSavIdx = new SwNodeIndex( rInsIdx, -1 );
655 : }
656 0 : pSavArr->push_back( (SwPosition*)pEnd );
657 0 : }
658 : }
659 0 : }
660 :
661 0 : _SaveRedlEndPosForRestore::~_SaveRedlEndPosForRestore()
662 : {
663 0 : delete pSavArr;
664 0 : delete pSavIdx;
665 0 : }
666 :
667 0 : void _SaveRedlEndPosForRestore::_Restore()
668 : {
669 0 : ++(*pSavIdx);
670 0 : SwCntntNode* pNode = pSavIdx->GetNode().GetCntntNode();
671 : // If there's no content node at the remembered position, we will not restore the old position
672 : // This may happen if a table (or section?) will be inserted.
673 0 : if( pNode )
674 : {
675 0 : SwPosition aPos( *pSavIdx, SwIndex( pNode, nSavCntnt ));
676 0 : for( sal_uInt16 n = pSavArr->size(); n; )
677 0 : *(*pSavArr)[ --n ] = aPos;
678 : }
679 0 : }
680 :
681 : /// Delete a full Section of the NodeArray.
682 : /// The passed Node is located somewhere in the designated Section.
683 0 : void SwDoc::DeleteSection( SwNode *pNode )
684 : {
685 : OSL_ENSURE( pNode, "Didn't pass a Node." );
686 0 : SwStartNode* pSttNd = pNode->IsStartNode() ? (SwStartNode*)pNode
687 0 : : pNode->StartOfSectionNode();
688 0 : SwNodeIndex aSttIdx( *pSttNd ), aEndIdx( *pNode->EndOfSectionNode() );
689 :
690 : // delete all Flys, Bookmarks, ...
691 0 : DelFlyInRange( aSttIdx, aEndIdx );
692 0 : DeleteRedline( *pSttNd, true, USHRT_MAX );
693 0 : _DelBookmarks(aSttIdx, aEndIdx);
694 :
695 : {
696 : // move all Crsr/StkCrsr/UnoCrsr out of the to-be-deleted area
697 0 : SwNodeIndex aMvStt( aSttIdx, 1 );
698 0 : CorrAbs( aMvStt, aEndIdx, SwPosition( aSttIdx ), sal_True );
699 : }
700 :
701 0 : GetNodes().DelNodes( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() + 1 );
702 0 : }
703 :
704 0 : void SwDoc::SetModified(SwPaM &rPaM)
705 : {
706 0 : SwDataChanged aTmp( rPaM );
707 0 : SetModified();
708 0 : }
709 :
710 0 : bool SwDoc::Overwrite( const SwPaM &rRg, const OUString &rStr )
711 : {
712 0 : SwPosition& rPt = *(SwPosition*)rRg.GetPoint();
713 0 : if( mpACEWord ) // Add to AutoCorrect
714 : {
715 0 : if( 1 == rStr.getLength() )
716 0 : mpACEWord->CheckChar( rPt, rStr[ 0 ] );
717 0 : delete mpACEWord, mpACEWord = 0;
718 : }
719 :
720 0 : SwTxtNode *pNode = rPt.nNode.GetNode().GetTxtNode();
721 0 : if (!pNode || rStr.getLength() > pNode->GetSpaceLeft()) // worst case: no erase
722 : {
723 0 : return false;
724 : }
725 :
726 0 : if (GetIDocumentUndoRedo().DoesUndo())
727 : {
728 0 : GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called
729 : }
730 :
731 0 : sal_uInt16 nOldAttrCnt = pNode->GetpSwpHints()
732 0 : ? pNode->GetpSwpHints()->Count() : 0;
733 0 : SwDataChanged aTmp( rRg );
734 0 : SwIndex& rIdx = rPt.nContent;
735 0 : sal_Int32 nStart = 0;
736 :
737 0 : bool bOldExpFlg = pNode->IsIgnoreDontExpand();
738 0 : pNode->SetIgnoreDontExpand( true );
739 :
740 0 : for( sal_Int32 nCnt = 0; nCnt < rStr.getLength(); ++nCnt )
741 : {
742 : // start behind the characters (to fix the attributes!)
743 0 : nStart = rIdx.GetIndex();
744 0 : if (nStart < pNode->GetTxt().getLength())
745 : {
746 0 : lcl_SkipAttr( pNode, rIdx, nStart );
747 : }
748 0 : sal_Unicode c = rStr[ nCnt ];
749 0 : if (GetIDocumentUndoRedo().DoesUndo())
750 : {
751 0 : bool bMerged(false);
752 0 : if (GetIDocumentUndoRedo().DoesGroupUndo())
753 : {
754 0 : SwUndo *const pUndo = GetUndoManager().GetLastUndo();
755 : SwUndoOverwrite *const pUndoOW(
756 0 : dynamic_cast<SwUndoOverwrite *>(pUndo) );
757 0 : if (pUndoOW)
758 : {
759 : // if CanGrouping() returns true it's already merged
760 0 : bMerged = pUndoOW->CanGrouping( this, rPt, c );
761 : }
762 : }
763 0 : if (!bMerged)
764 : {
765 0 : SwUndo *const pUndoOW( new SwUndoOverwrite(this, rPt, c) );
766 0 : GetIDocumentUndoRedo().AppendUndo(pUndoOW);
767 : }
768 : }
769 : else
770 : {
771 : // start behind the characters (to fix the attributes!)
772 0 : if (nStart < pNode->GetTxt().getLength())
773 0 : ++rIdx;
774 0 : pNode->InsertText( OUString(c), rIdx, INS_EMPTYEXPAND );
775 0 : if( nStart+1 < rIdx.GetIndex() )
776 : {
777 0 : rIdx = nStart;
778 0 : pNode->EraseText( rIdx, 1 );
779 0 : ++rIdx;
780 : }
781 : }
782 : }
783 0 : pNode->SetIgnoreDontExpand( bOldExpFlg );
784 :
785 0 : sal_uInt16 nNewAttrCnt = pNode->GetpSwpHints()
786 0 : ? pNode->GetpSwpHints()->Count() : 0;
787 0 : if( nOldAttrCnt != nNewAttrCnt )
788 : {
789 0 : SwUpdateAttr aHint( 0, 0, 0 );
790 0 : pNode->ModifyBroadcast( 0, &aHint, TYPE( SwCrsrShell ) );
791 : }
792 :
793 0 : if (!GetIDocumentUndoRedo().DoesUndo() &&
794 0 : !IsIgnoreRedline() && !GetRedlineTbl().empty())
795 : {
796 0 : SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
797 0 : DeleteRedline( aPam, true, USHRT_MAX );
798 : }
799 0 : else if( IsRedlineOn() )
800 : {
801 : // FIXME: this redline is WRONG: there is no DELETE, and the skipped
802 : // characters are also included in aPam
803 0 : SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
804 0 : AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
805 : }
806 :
807 0 : SetModified();
808 0 : return true;
809 : }
810 :
811 0 : bool SwDoc::MoveAndJoin( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
812 : {
813 0 : SwNodeIndex aIdx( rPaM.Start()->nNode );
814 0 : sal_Bool bJoinTxt = aIdx.GetNode().IsTxtNode();
815 0 : sal_Bool bOneNode = rPaM.GetPoint()->nNode == rPaM.GetMark()->nNode;
816 0 : aIdx--; // in front of the move area!
817 :
818 0 : bool bRet = MoveRange( rPaM, rPos, eMvFlags );
819 0 : if( bRet && !bOneNode )
820 : {
821 0 : if( bJoinTxt )
822 0 : ++aIdx;
823 0 : SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode();
824 0 : SwNodeIndex aNxtIdx( aIdx );
825 0 : if( pTxtNd && pTxtNd->CanJoinNext( &aNxtIdx ) )
826 : {
827 : { // Block so SwIndex into node is deleted before Join
828 : CorrRel( aNxtIdx, SwPosition( aIdx, SwIndex(pTxtNd,
829 0 : pTxtNd->GetTxt().getLength()) ), 0, sal_True );
830 : }
831 0 : pTxtNd->JoinNext();
832 0 : }
833 : }
834 0 : return bRet;
835 : }
836 :
837 : // It seems that this is mostly used by SwDoc internals; the only
838 : // way to call this from the outside seems to be the special case in
839 : // SwDoc::CopyRange (but I have not managed to actually hit that case).
840 0 : bool SwDoc::MoveRange( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
841 : {
842 : // nothing moved: return
843 0 : const SwPosition *pStt = rPaM.Start(), *pEnd = rPaM.End();
844 0 : if( !rPaM.HasMark() || *pStt >= *pEnd || (*pStt <= rPos && rPos < *pEnd))
845 0 : return false;
846 :
847 : // Save the paragraph anchored Flys, so that they can be moved.
848 0 : _SaveFlyArr aSaveFlyArr;
849 0 : _SaveFlyInRange( rPaM, rPos.nNode, aSaveFlyArr, 0 != ( DOC_MOVEALLFLYS & eMvFlags ) );
850 :
851 : // save redlines (if DOC_MOVEREDLINES is used)
852 0 : _SaveRedlines aSaveRedl;
853 0 : if( DOC_MOVEREDLINES & eMvFlags && !GetRedlineTbl().empty() )
854 : {
855 0 : lcl_SaveRedlines( rPaM, aSaveRedl );
856 :
857 : // #i17764# unfortunately, code below relies on undos being
858 : // in a particular order, and presence of bookmarks
859 : // will change this order. Hence, we delete bookmarks
860 : // here without undo.
861 0 : ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
862 : _DelBookmarks(
863 : pStt->nNode,
864 : pEnd->nNode,
865 : NULL,
866 : &pStt->nContent,
867 0 : &pEnd->nContent);
868 : }
869 :
870 0 : bool bUpdateFtn = false;
871 0 : SwFtnIdxs aTmpFntIdx;
872 :
873 0 : SwUndoMove * pUndoMove = 0;
874 0 : if (GetIDocumentUndoRedo().DoesUndo())
875 : {
876 0 : GetIDocumentUndoRedo().ClearRedo();
877 0 : pUndoMove = new SwUndoMove( rPaM, rPos );
878 0 : pUndoMove->SetMoveRedlines( eMvFlags == DOC_MOVEREDLINES );
879 : }
880 : else
881 : {
882 : bUpdateFtn = lcl_SaveFtn( pStt->nNode, pEnd->nNode, rPos.nNode,
883 0 : GetFtnIdxs(), aTmpFntIdx,
884 0 : &pStt->nContent, &pEnd->nContent );
885 : }
886 :
887 0 : sal_Bool bSplit = sal_False;
888 0 : SwPaM aSavePam( rPos, rPos );
889 :
890 : // Move the SPoint to the beginning of the range
891 0 : if( rPaM.GetPoint() == pEnd )
892 0 : rPaM.Exchange();
893 :
894 : // If there is a TextNode before and after the Move, create a JoinNext in the EditShell.
895 0 : SwTxtNode* pSrcNd = rPaM.GetPoint()->nNode.GetNode().GetTxtNode();
896 0 : sal_Bool bCorrSavePam = pSrcNd && pStt->nNode != pEnd->nNode;
897 :
898 : // If one ore more TextNodes are moved, SwNodes::Move will do a SplitNode.
899 : // However, this does not update the cursor. So we create a TextNode to keep
900 : // updating the indices. After the Move the Node is optionally deleted.
901 0 : SwTxtNode * pTNd = rPos.nNode.GetNode().GetTxtNode();
902 0 : if( pTNd && rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode &&
903 0 : ( rPos.nContent.GetIndex() || ( pTNd->Len() && bCorrSavePam )) )
904 : {
905 0 : bSplit = sal_True;
906 0 : const sal_Int32 nMkCntnt = rPaM.GetMark()->nContent.GetIndex();
907 :
908 0 : std::vector<sal_uLong> aBkmkArr;
909 : _SaveCntntIdx( this, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(),
910 0 : aBkmkArr, SAVEFLY_SPLIT );
911 :
912 0 : pTNd = static_cast<SwTxtNode*>(pTNd->SplitCntntNode( rPos ));
913 :
914 0 : if( !aBkmkArr.empty() )
915 0 : _RestoreCntntIdx( this, aBkmkArr, rPos.nNode.GetIndex()-1, 0, true );
916 :
917 : // correct the PaM!
918 0 : if( rPos.nNode == rPaM.GetMark()->nNode )
919 : {
920 0 : rPaM.GetMark()->nNode = rPos.nNode.GetIndex()-1;
921 0 : rPaM.GetMark()->nContent.Assign( pTNd, nMkCntnt );
922 0 : }
923 : }
924 :
925 : // Put back the Pam by one "content"; so that it's always outside of
926 : // the manipulated range.
927 : // If there's no content anymore, set it to the StartNode (that's
928 : // always there).
929 0 : const bool bNullCntnt = !aSavePam.Move( fnMoveBackward, fnGoCntnt );
930 0 : if( bNullCntnt )
931 : {
932 0 : aSavePam.GetPoint()->nNode--;
933 : }
934 :
935 : // Copy all Bookmarks that are within the Move range into an array,
936 : // that saves the positon as an offset.
937 0 : ::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
938 : _DelBookmarks(
939 : pStt->nNode,
940 : pEnd->nNode,
941 : &aSaveBkmks,
942 : &pStt->nContent,
943 0 : &pEnd->nContent);
944 :
945 : // If there is no range anymore due to the above deletions (e.g. the
946 : // footnotes got deleted), it's still a valid Move!
947 0 : if( *rPaM.GetPoint() != *rPaM.GetMark() )
948 : {
949 : // now do the actual move
950 0 : GetNodes().MoveRange( rPaM, rPos, GetNodes() );
951 :
952 : // after a MoveRange() the Mark is deleted
953 0 : if ( rPaM.HasMark() ) // => no Move occurred!
954 : {
955 0 : delete pUndoMove;
956 0 : return false;
957 : }
958 : }
959 : else
960 0 : rPaM.DeleteMark();
961 :
962 : OSL_ENSURE( *aSavePam.GetMark() == rPos ||
963 : ( aSavePam.GetMark()->nNode.GetNode().GetCntntNode() == NULL ),
964 : "PaM was not moved. Aren't there ContentNodes at the beginning/end?" );
965 0 : *aSavePam.GetMark() = rPos;
966 :
967 0 : rPaM.SetMark(); // create a Sel. around the new range
968 0 : pTNd = aSavePam.GetNode()->GetTxtNode();
969 0 : if (GetIDocumentUndoRedo().DoesUndo())
970 : {
971 : // correct the SavePam's Content first
972 0 : if( bNullCntnt )
973 : {
974 0 : aSavePam.GetPoint()->nContent = 0;
975 : }
976 :
977 : // The method SwEditShell::Move() merges the TextNode after the Move,
978 : // where the rPaM is located.
979 : // If the Content was moved to the back and the SavePam's SPoint is
980 : // in the next Node, we have to deal with this when saving the Undo object!
981 0 : SwTxtNode * pPamTxtNd = 0;
982 :
983 : // Is passed to SwUndoMove, which happens when subsequently calling Undo JoinNext.
984 : // If it's not possible to call Undo JoinNext here.
985 0 : sal_Bool bJoin = bSplit && pTNd;
986 0 : bCorrSavePam = bCorrSavePam &&
987 0 : 0 != ( pPamTxtNd = rPaM.GetNode()->GetTxtNode() )
988 0 : && pPamTxtNd->CanJoinNext()
989 0 : && (*rPaM.GetPoint() <= *aSavePam.GetPoint());
990 :
991 : // Do two Nodes have to be joined at the SavePam?
992 0 : if( bJoin && pTNd->CanJoinNext() )
993 : {
994 0 : pTNd->JoinNext();
995 : // No temporary Index when using &&.
996 : // We probably only want to compare the indices.
997 0 : if( bCorrSavePam && rPaM.GetPoint()->nNode.GetIndex()+1 ==
998 0 : aSavePam.GetPoint()->nNode.GetIndex() )
999 : {
1000 0 : aSavePam.GetPoint()->nContent += pPamTxtNd->Len();
1001 : }
1002 0 : bJoin = sal_False;
1003 : }
1004 0 : else if ( !aSavePam.Move( fnMoveForward, fnGoCntnt ) )
1005 : {
1006 0 : aSavePam.GetPoint()->nNode++;
1007 : }
1008 :
1009 : // The newly inserted range is now inbetween SPoint and GetMark.
1010 0 : pUndoMove->SetDestRange( aSavePam, *rPaM.GetPoint(),
1011 0 : bJoin, bCorrSavePam );
1012 0 : GetIDocumentUndoRedo().AppendUndo( pUndoMove );
1013 : }
1014 : else
1015 : {
1016 0 : bool bRemove = true;
1017 : // Do two Nodes have to be joined at the SavePam?
1018 0 : if( bSplit && pTNd )
1019 : {
1020 0 : if( pTNd->CanJoinNext())
1021 : {
1022 : // Always join next, because <pTNd> has to stay as it is.
1023 : // A join previous from its next would more or less delete <pTNd>
1024 0 : pTNd->JoinNext();
1025 0 : bRemove = false;
1026 : }
1027 : }
1028 0 : if( bNullCntnt )
1029 : {
1030 0 : aSavePam.GetPoint()->nNode++;
1031 0 : aSavePam.GetPoint()->nContent.Assign( aSavePam.GetCntntNode(), 0 );
1032 : }
1033 0 : else if( bRemove ) // No move forward after joining with next paragraph
1034 : {
1035 0 : aSavePam.Move( fnMoveForward, fnGoCntnt );
1036 : }
1037 : }
1038 :
1039 : // Insert the Bookmarks back into the Document.
1040 0 : *rPaM.GetMark() = *aSavePam.Start();
1041 0 : for(
1042 0 : ::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
1043 0 : pBkmk != aSaveBkmks.end();
1044 : ++pBkmk)
1045 : pBkmk->SetInDoc(
1046 : this,
1047 0 : rPaM.GetMark()->nNode,
1048 0 : &rPaM.GetMark()->nContent);
1049 0 : *rPaM.GetPoint() = *aSavePam.End();
1050 :
1051 : // Move the Flys to the new position.
1052 0 : _RestFlyInRange( aSaveFlyArr, rPaM.Start()->nNode, &(rPos.nNode) );
1053 :
1054 : // restore redlines (if DOC_MOVEREDLINES is used)
1055 0 : if( !aSaveRedl.empty() )
1056 : {
1057 0 : lcl_RestoreRedlines( this, *aSavePam.Start(), aSaveRedl );
1058 : }
1059 :
1060 0 : if( bUpdateFtn )
1061 : {
1062 0 : if( !aTmpFntIdx.empty() )
1063 : {
1064 0 : GetFtnIdxs().insert( aTmpFntIdx );
1065 0 : aTmpFntIdx.clear();
1066 : }
1067 :
1068 0 : GetFtnIdxs().UpdateAllFtn();
1069 : }
1070 :
1071 0 : SetModified();
1072 0 : return true;
1073 : }
1074 :
1075 0 : bool SwDoc::MoveNodeRange( SwNodeRange& rRange, SwNodeIndex& rPos,
1076 : SwMoveFlags eMvFlags )
1077 : {
1078 : // Moves all Nodes to the new position.
1079 : // Bookmarks are moved too (currently without Undo support).
1080 :
1081 : // If footnotes are being moved to the special section, remove them now.
1082 :
1083 : // Or else delete the Frames for all footnotes that are being moved
1084 : // and have it rebuild after the Move (footnotes can change pages).
1085 : // Additionally we have to correct the FtnIdx array's sorting.
1086 0 : bool bUpdateFtn = false;
1087 0 : SwFtnIdxs aTmpFntIdx;
1088 :
1089 0 : SwUndoMove* pUndo = 0;
1090 0 : if ((DOC_CREATEUNDOOBJ & eMvFlags ) && GetIDocumentUndoRedo().DoesUndo())
1091 : {
1092 0 : pUndo = new SwUndoMove( this, rRange, rPos );
1093 : }
1094 : else
1095 : {
1096 : bUpdateFtn = lcl_SaveFtn( rRange.aStart, rRange.aEnd, rPos,
1097 0 : GetFtnIdxs(), aTmpFntIdx );
1098 : }
1099 :
1100 0 : _SaveRedlines aSaveRedl;
1101 0 : std::vector<SwRangeRedline*> aSavRedlInsPosArr;
1102 0 : if( DOC_MOVEREDLINES & eMvFlags && !GetRedlineTbl().empty() )
1103 : {
1104 0 : lcl_SaveRedlines( rRange, aSaveRedl );
1105 :
1106 : // Find all RedLines that end at the InsPos.
1107 : // These have to be moved back to the "old" position after the Move.
1108 0 : sal_uInt16 nRedlPos = GetRedlinePos( rPos.GetNode(), USHRT_MAX );
1109 0 : if( USHRT_MAX != nRedlPos )
1110 : {
1111 : const SwPosition *pRStt, *pREnd;
1112 0 : do {
1113 0 : SwRangeRedline* pTmp = GetRedlineTbl()[ nRedlPos ];
1114 0 : pRStt = pTmp->Start();
1115 0 : pREnd = pTmp->End();
1116 0 : if( pREnd->nNode == rPos && pRStt->nNode < rPos )
1117 : {
1118 0 : aSavRedlInsPosArr.push_back( pTmp );
1119 : }
1120 0 : } while( pRStt->nNode < rPos && ++nRedlPos < GetRedlineTbl().size());
1121 : }
1122 : }
1123 :
1124 : // Copy all Bookmarks that are within the Move range into an array
1125 : // that stores all references to positions as an offset.
1126 : // The final mapping happens after the Move.
1127 0 : ::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
1128 0 : _DelBookmarks(rRange.aStart, rRange.aEnd, &aSaveBkmks);
1129 :
1130 : // Save the paragraph-bound Flys, so that they can be moved.
1131 0 : _SaveFlyArr aSaveFlyArr;
1132 0 : if( !GetSpzFrmFmts()->empty() )
1133 0 : _SaveFlyInRange( rRange, aSaveFlyArr );
1134 :
1135 : // Set it to before the Position, so that it cannot be moved further.
1136 0 : SwNodeIndex aIdx( rPos, -1 );
1137 :
1138 0 : SwNodeIndex* pSaveInsPos = 0;
1139 0 : if( pUndo )
1140 0 : pSaveInsPos = new SwNodeIndex( rRange.aStart, -1 );
1141 :
1142 : // move the Nodes
1143 0 : sal_Bool bNoDelFrms = 0 != (DOC_NO_DELFRMS & eMvFlags);
1144 0 : if( GetNodes()._MoveNodes( rRange, GetNodes(), rPos, !bNoDelFrms ) )
1145 : {
1146 0 : ++aIdx; // again back to old position
1147 0 : if( pSaveInsPos )
1148 0 : ++(*pSaveInsPos);
1149 : }
1150 : else
1151 : {
1152 0 : aIdx = rRange.aStart;
1153 0 : delete pUndo, pUndo = 0;
1154 : }
1155 :
1156 : // move the Flys to the new position
1157 0 : if( !aSaveFlyArr.empty() )
1158 0 : _RestFlyInRange( aSaveFlyArr, aIdx, NULL );
1159 :
1160 : // Add the Bookmarks back to the Document
1161 0 : for(
1162 0 : ::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
1163 0 : pBkmk != aSaveBkmks.end();
1164 : ++pBkmk)
1165 0 : pBkmk->SetInDoc(this, aIdx);
1166 :
1167 0 : if( !aSavRedlInsPosArr.empty() )
1168 : {
1169 0 : SwNode* pNewNd = &aIdx.GetNode();
1170 0 : for( sal_uInt16 n = 0; n < aSavRedlInsPosArr.size(); ++n )
1171 : {
1172 0 : SwRangeRedline* pTmp = aSavRedlInsPosArr[ n ];
1173 0 : if( GetRedlineTbl().Contains( pTmp ) )
1174 : {
1175 0 : SwPosition* pEnd = pTmp->End();
1176 0 : pEnd->nNode = aIdx;
1177 0 : pEnd->nContent.Assign( pNewNd->GetCntntNode(), 0 );
1178 : }
1179 : }
1180 : }
1181 :
1182 0 : if( !aSaveRedl.empty() )
1183 0 : lcl_RestoreRedlines( this, aIdx.GetIndex(), aSaveRedl );
1184 :
1185 0 : if( pUndo )
1186 : {
1187 0 : pUndo->SetDestRange( aIdx, rPos, *pSaveInsPos );
1188 0 : GetIDocumentUndoRedo().AppendUndo(pUndo);
1189 : }
1190 :
1191 0 : delete pSaveInsPos;
1192 :
1193 0 : if( bUpdateFtn )
1194 : {
1195 0 : if( !aTmpFntIdx.empty() )
1196 : {
1197 0 : GetFtnIdxs().insert( aTmpFntIdx );
1198 0 : aTmpFntIdx.clear();
1199 : }
1200 :
1201 0 : GetFtnIdxs().UpdateAllFtn();
1202 : }
1203 :
1204 0 : SetModified();
1205 0 : return true;
1206 : }
1207 :
1208 : /// Convert list of ranges of whichIds to a corresponding list of whichIds
1209 0 : static std::vector<sal_uInt16> * lcl_RangesToVector(sal_uInt16 * pRanges)
1210 : {
1211 0 : std::vector<sal_uInt16> * pResult = new std::vector<sal_uInt16>();
1212 :
1213 0 : int i = 0;
1214 0 : while (pRanges[i] != 0)
1215 : {
1216 : OSL_ENSURE(pRanges[i+1] != 0, "malformed ranges");
1217 :
1218 0 : for (sal_uInt16 j = pRanges[i]; j < pRanges[i+1]; j++)
1219 0 : pResult->push_back(j);
1220 :
1221 0 : i += 2;
1222 : }
1223 :
1224 0 : return pResult;
1225 : }
1226 :
1227 0 : static bool lcl_StrLenOverflow( const SwPaM& rPam )
1228 : {
1229 : // If we try to merge two paragraphs we have to test if afterwards
1230 : // the string doesn't exceed the allowed string length
1231 0 : if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
1232 : {
1233 0 : const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
1234 0 : const SwTxtNode* pEndNd = pEnd->nNode.GetNode().GetTxtNode();
1235 0 : if( (0 != pEndNd) && pStt->nNode.GetNode().IsTxtNode() )
1236 : {
1237 0 : const sal_uInt64 nSum = pStt->nContent.GetIndex() +
1238 0 : pEndNd->GetTxt().getLength() - pEnd->nContent.GetIndex();
1239 0 : return nSum > static_cast<sal_uInt64>(SAL_MAX_INT32);
1240 : }
1241 : }
1242 0 : return false;
1243 : }
1244 :
1245 0 : void sw_GetJoinFlags( SwPaM& rPam, sal_Bool& rJoinTxt, sal_Bool& rJoinPrev )
1246 : {
1247 0 : rJoinTxt = sal_False;
1248 0 : rJoinPrev = sal_False;
1249 0 : if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
1250 : {
1251 0 : const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
1252 0 : SwTxtNode *pSttNd = pStt->nNode.GetNode().GetTxtNode();
1253 0 : if( pSttNd )
1254 : {
1255 0 : SwTxtNode *pEndNd = pEnd->nNode.GetNode().GetTxtNode();
1256 0 : rJoinTxt = 0 != pEndNd;
1257 0 : if( rJoinTxt )
1258 : {
1259 0 : bool bExchange = pStt == rPam.GetPoint();
1260 0 : if( !pStt->nContent.GetIndex() &&
1261 0 : pEndNd->GetTxt().getLength() != pEnd->nContent.GetIndex())
1262 0 : bExchange = !bExchange;
1263 0 : if( bExchange )
1264 0 : rPam.Exchange();
1265 0 : rJoinPrev = rPam.GetPoint() == pStt;
1266 : OSL_ENSURE( !pStt->nContent.GetIndex() &&
1267 : pEndNd->GetTxt().getLength() != pEnd->nContent.GetIndex()
1268 : ? rPam.GetPoint()->nNode < rPam.GetMark()->nNode
1269 : : rPam.GetPoint()->nNode > rPam.GetMark()->nNode,
1270 : "sw_GetJoinFlags");
1271 : }
1272 : }
1273 : }
1274 0 : }
1275 :
1276 0 : void sw_JoinText( SwPaM& rPam, sal_Bool bJoinPrev )
1277 : {
1278 0 : SwNodeIndex aIdx( rPam.GetPoint()->nNode );
1279 0 : SwTxtNode *pTxtNd = aIdx.GetNode().GetTxtNode();
1280 0 : SwNodeIndex aOldIdx( aIdx );
1281 0 : SwTxtNode *pOldTxtNd = pTxtNd;
1282 :
1283 0 : if( pTxtNd && pTxtNd->CanJoinNext( &aIdx ) )
1284 : {
1285 0 : SwDoc* pDoc = rPam.GetDoc();
1286 0 : if( bJoinPrev )
1287 : {
1288 : // We do not need to handle xmlids in this case, because
1289 : // it is only invoked if one paragraph is completely empty
1290 : // (see sw_GetJoinFlags)
1291 : {
1292 : // If PageBreaks are deleted/set, it must not be added to the Undo history!
1293 : // Also, deleteing the Node is not added to the Undo histroy!
1294 0 : ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
1295 :
1296 : /* PageBreaks, PageDesc, ColumnBreaks */
1297 : // If we need to change something about the logic to copy the PageBreaks,
1298 : // PageDesc, etc. we also have to change SwUndoDelete.
1299 : // There, we copy the AUTO PageBreak from the GetMarkNode!
1300 :
1301 : /* The GetMarkNode */
1302 0 : if( ( pTxtNd = aIdx.GetNode().GetTxtNode())->HasSwAttrSet() )
1303 : {
1304 : const SfxPoolItem* pItem;
1305 0 : if( SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState(
1306 0 : RES_BREAK, false, &pItem ) )
1307 0 : pTxtNd->ResetAttr( RES_BREAK );
1308 0 : if( pTxtNd->HasSwAttrSet() &&
1309 0 : SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState(
1310 0 : RES_PAGEDESC, false, &pItem ) )
1311 0 : pTxtNd->ResetAttr( RES_PAGEDESC );
1312 : }
1313 :
1314 : /* The PointNode */
1315 0 : if( pOldTxtNd->HasSwAttrSet() )
1316 : {
1317 : const SfxPoolItem* pItem;
1318 0 : SfxItemSet aSet( pDoc->GetAttrPool(), aBreakSetRange );
1319 0 : const SfxItemSet* pSet = pOldTxtNd->GetpSwAttrSet();
1320 0 : if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
1321 0 : false, &pItem ) )
1322 0 : aSet.Put( *pItem );
1323 0 : if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
1324 0 : false, &pItem ) )
1325 0 : aSet.Put( *pItem );
1326 0 : if( aSet.Count() )
1327 0 : pTxtNd->SetAttr( aSet );
1328 : }
1329 0 : pOldTxtNd->FmtToTxtAttr( pTxtNd );
1330 :
1331 0 : std::vector<sal_uLong> aBkmkArr;
1332 : ::_SaveCntntIdx( pDoc, aOldIdx.GetIndex(),
1333 0 : pOldTxtNd->Len(), aBkmkArr );
1334 :
1335 0 : SwIndex aAlphaIdx(pTxtNd);
1336 0 : pOldTxtNd->CutText( pTxtNd, aAlphaIdx, SwIndex(pOldTxtNd),
1337 0 : pOldTxtNd->Len() );
1338 0 : SwPosition aAlphaPos( aIdx, aAlphaIdx );
1339 0 : pDoc->CorrRel( rPam.GetPoint()->nNode, aAlphaPos, 0, sal_True );
1340 :
1341 : // move all Bookmarks/TOXMarks
1342 0 : if( !aBkmkArr.empty() )
1343 0 : ::_RestoreCntntIdx( pDoc, aBkmkArr, aIdx.GetIndex() );
1344 :
1345 : // If the passed PaM is not in the Crsr ring,
1346 : // treat it separately (e.g. when it's being called from AutoFormat)
1347 0 : if( pOldTxtNd == rPam.GetBound( true ).nContent.GetIdxReg() )
1348 0 : rPam.GetBound( true ) = aAlphaPos;
1349 0 : if( pOldTxtNd == rPam.GetBound( false ).nContent.GetIdxReg() )
1350 0 : rPam.GetBound( false ) = aAlphaPos;
1351 : }
1352 : // delete the Node, at last!
1353 0 : pDoc->GetNodes().Delete( aOldIdx, 1 );
1354 : }
1355 : else
1356 : {
1357 0 : SwTxtNode* pDelNd = aIdx.GetNode().GetTxtNode();
1358 0 : if( pTxtNd->Len() )
1359 0 : pDelNd->FmtToTxtAttr( pTxtNd );
1360 : else
1361 : {
1362 : /* This case was missed:
1363 :
1364 : <something></something> <-- pTxtNd
1365 : <other>ccc</other> <-- pDelNd
1366 :
1367 : <something> and <other> are paragraph
1368 : attributes. The attribute <something> stayed if not
1369 : overwritten by an attribute in "ccc". Fixed by
1370 : first resetting all character attributes in first
1371 : paragraph (pTxtNd).
1372 : */
1373 : std::vector<sal_uInt16> * pShorts =
1374 0 : lcl_RangesToVector(aCharFmtSetRange);
1375 0 : pTxtNd->ResetAttr(*pShorts);
1376 0 : delete pShorts;
1377 :
1378 0 : if( pDelNd->HasSwAttrSet() )
1379 : {
1380 : // only copy the character attributes
1381 0 : SfxItemSet aTmpSet( pDoc->GetAttrPool(), aCharFmtSetRange );
1382 0 : aTmpSet.Put( *pDelNd->GetpSwAttrSet() );
1383 0 : pTxtNd->SetAttr( aTmpSet );
1384 : }
1385 : }
1386 :
1387 0 : pDoc->CorrRel( aIdx, *rPam.GetPoint(), 0, sal_True );
1388 : // #i100466# adjust given <rPam>, if it does not belong to the cursors
1389 0 : if ( pDelNd == rPam.GetBound( true ).nContent.GetIdxReg() )
1390 : {
1391 0 : rPam.GetBound( true ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
1392 : }
1393 0 : if( pDelNd == rPam.GetBound( false ).nContent.GetIdxReg() )
1394 : {
1395 0 : rPam.GetBound( false ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
1396 : }
1397 0 : pTxtNd->JoinNext();
1398 : }
1399 0 : }
1400 0 : }
1401 :
1402 : static void
1403 0 : lcl_CalcBreaks( ::std::vector<sal_Int32> & rBreaks, SwPaM const & rPam )
1404 : {
1405 : SwTxtNode const * const pTxtNode(
1406 0 : rPam.End()->nNode.GetNode().GetTxtNode() );
1407 0 : if (!pTxtNode)
1408 0 : return; // left-overlap only possible at end of selection...
1409 :
1410 0 : const sal_Int32 nStart(rPam.Start()->nContent.GetIndex());
1411 0 : const sal_Int32 nEnd (rPam.End ()->nContent.GetIndex());
1412 0 : if (nEnd == pTxtNode->Len())
1413 0 : return; // paragraph selected until the end
1414 :
1415 0 : for (sal_Int32 i = nStart; i < nEnd; ++i)
1416 : {
1417 0 : const sal_Unicode c(pTxtNode->GetTxt()[i]);
1418 0 : if ((CH_TXTATR_INWORD == c) || (CH_TXTATR_BREAKWORD == c))
1419 : {
1420 0 : SwTxtAttr const * const pAttr( pTxtNode->GetTxtAttrForCharAt(i) );
1421 0 : if (pAttr && pAttr->End() && (*pAttr->End() > nEnd))
1422 : {
1423 : OSL_ENSURE(pAttr->HasDummyChar(), "GetTxtAttrForCharAt broken?");
1424 0 : rBreaks.push_back(i);
1425 : }
1426 : }
1427 : }
1428 : }
1429 :
1430 0 : static bool lcl_DoWithBreaks(SwDoc & rDoc, SwPaM & rPam,
1431 : bool (SwDoc::*pFunc)(SwPaM&, bool), const bool bForceJoinNext = false)
1432 : {
1433 0 : ::std::vector<sal_Int32> Breaks;
1434 :
1435 0 : lcl_CalcBreaks(Breaks, rPam);
1436 :
1437 0 : if (!Breaks.size())
1438 : {
1439 0 : return (rDoc.*pFunc)(rPam, bForceJoinNext);
1440 : }
1441 :
1442 : // Deletion must be split into several parts if the text node
1443 : // contains a text attribute with end and with dummy character
1444 : // and the selection does not contain the text attribute completely,
1445 : // but overlaps its start (left), where the dummy character is.
1446 :
1447 0 : SwPosition const & rSelectionEnd( *rPam.End() );
1448 :
1449 0 : bool bRet( true );
1450 : // iterate from end to start, to avoid invalidating the offsets!
1451 0 : ::std::vector<sal_Int32>::reverse_iterator iter( Breaks.rbegin() );
1452 0 : SwPaM aPam( rSelectionEnd, rSelectionEnd ); // end node!
1453 0 : SwPosition & rEnd( *aPam.End() );
1454 0 : SwPosition & rStart( *aPam.Start() );
1455 :
1456 0 : while (iter != Breaks.rend())
1457 : {
1458 0 : rStart.nContent = *iter + 1;
1459 0 : if (rEnd.nContent > rStart.nContent) // check if part is empty
1460 : {
1461 0 : bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext);
1462 : }
1463 0 : rEnd.nContent = *iter;
1464 0 : ++iter;
1465 : }
1466 :
1467 0 : rStart = *rPam.Start(); // set to original start
1468 0 : if (rEnd.nContent > rStart.nContent) // check if part is empty
1469 : {
1470 0 : bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext);
1471 : }
1472 :
1473 0 : return bRet;
1474 : }
1475 :
1476 0 : bool SwDoc::DeleteAndJoinWithRedlineImpl( SwPaM & rPam, const bool )
1477 : {
1478 : OSL_ENSURE( IsRedlineOn(), "DeleteAndJoinWithRedline: redline off" );
1479 :
1480 : {
1481 0 : SwUndoRedlineDelete* pUndo = 0;
1482 0 : RedlineMode_t eOld = GetRedlineMode();
1483 0 : checkRedlining( eOld );
1484 0 : if (GetIDocumentUndoRedo().DoesUndo())
1485 : {
1486 :
1487 : /* please don't translate -- for cultural reasons this comment is protected
1488 : until the redline implementation is finally fixed some day */
1489 : //JP 06.01.98: MUSS noch optimiert werden!!!
1490 : SetRedlineMode(
1491 0 : (RedlineMode_t) ( nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE ) );
1492 :
1493 0 : GetIDocumentUndoRedo().StartUndo( UNDO_DELETE, NULL );
1494 0 : pUndo = new SwUndoRedlineDelete( rPam, UNDO_DELETE );
1495 0 : GetIDocumentUndoRedo().AppendUndo( pUndo );
1496 : }
1497 :
1498 0 : if ( *rPam.GetPoint() != *rPam.GetMark() )
1499 0 : AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_DELETE, rPam ), true );
1500 0 : SetModified();
1501 :
1502 0 : if ( pUndo )
1503 : {
1504 0 : GetIDocumentUndoRedo().EndUndo( UNDO_EMPTY, NULL );
1505 : // ??? why the hell is the AppendUndo not below the
1506 : // CanGrouping, so this hideous cleanup wouldn't be necessary?
1507 : // bah, this is redlining, probably changing this would break it...
1508 0 : if ( GetIDocumentUndoRedo().DoesGroupUndo() )
1509 : {
1510 0 : SwUndo * const pLastUndo( GetUndoManager().GetLastUndo() );
1511 0 : SwUndoRedlineDelete * const pUndoRedlineDel( dynamic_cast< SwUndoRedlineDelete* >( pLastUndo ) );
1512 0 : if ( pUndoRedlineDel )
1513 : {
1514 0 : bool const bMerged = pUndoRedlineDel->CanGrouping( *pUndo );
1515 0 : if ( bMerged )
1516 : {
1517 0 : ::sw::UndoGuard const undoGuard( GetIDocumentUndoRedo() );
1518 0 : SwUndo const* const pDeleted = GetUndoManager().RemoveLastUndo();
1519 : OSL_ENSURE( pDeleted == pUndo, "DeleteAndJoinWithRedlineImpl: "
1520 : "undo removed is not undo inserted?" );
1521 0 : delete pDeleted;
1522 : }
1523 : }
1524 : }
1525 : //JP 06.01.98: MUSS noch optimiert werden!!!
1526 0 : SetRedlineMode( eOld );
1527 : }
1528 0 : return true;
1529 : }
1530 : }
1531 :
1532 0 : bool SwDoc::DeleteAndJoinImpl( SwPaM & rPam,
1533 : const bool bForceJoinNext )
1534 : {
1535 : sal_Bool bJoinTxt, bJoinPrev;
1536 0 : sw_GetJoinFlags( rPam, bJoinTxt, bJoinPrev );
1537 : // #i100466#
1538 0 : if ( bForceJoinNext )
1539 : {
1540 0 : bJoinPrev = sal_False;
1541 : }
1542 :
1543 : {
1544 0 : bool const bSuccess( DeleteRangeImpl( rPam ) );
1545 0 : if (!bSuccess)
1546 0 : return false;
1547 : }
1548 :
1549 0 : if( bJoinTxt )
1550 : {
1551 0 : sw_JoinText( rPam, bJoinPrev );
1552 : }
1553 :
1554 0 : return true;
1555 : }
1556 :
1557 0 : bool SwDoc::DeleteRangeImpl(SwPaM & rPam, const bool)
1558 : {
1559 : // Move all cursors out of the deleted range, but first copy the
1560 : // passed PaM, because it could be a cursor that would be moved!
1561 0 : SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
1562 0 : ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
1563 :
1564 0 : bool const bSuccess( DeleteRangeImplImpl( aDelPam ) );
1565 0 : if (bSuccess)
1566 : { // now copy position from temp copy to given PaM
1567 0 : *rPam.GetPoint() = *aDelPam.GetPoint();
1568 : }
1569 :
1570 0 : return bSuccess;
1571 : }
1572 :
1573 0 : bool SwDoc::DeleteRangeImplImpl(SwPaM & rPam)
1574 : {
1575 0 : SwPosition *pStt = (SwPosition*)rPam.Start(), *pEnd = (SwPosition*)rPam.End();
1576 :
1577 0 : if( !rPam.HasMark() || *pStt >= *pEnd )
1578 0 : return false;
1579 :
1580 0 : if( mpACEWord )
1581 : {
1582 : // if necessary the saved Word for the exception
1583 0 : if( mpACEWord->IsDeleted() || pStt->nNode != pEnd->nNode ||
1584 0 : pStt->nContent.GetIndex() + 1 != pEnd->nContent.GetIndex() ||
1585 0 : !mpACEWord->CheckDelChar( *pStt ))
1586 0 : delete mpACEWord, mpACEWord = 0;
1587 : }
1588 :
1589 : {
1590 : // Delete all empty TextHints at the Mark's position
1591 0 : SwTxtNode* pTxtNd = rPam.GetMark()->nNode.GetNode().GetTxtNode();
1592 : SwpHints* pHts;
1593 0 : if( pTxtNd && 0 != ( pHts = pTxtNd->GetpSwpHints()) && pHts->Count() )
1594 : {
1595 : const sal_Int32 *pEndIdx;
1596 0 : const sal_Int32 nMkCntPos = rPam.GetMark()->nContent.GetIndex();
1597 0 : for( sal_uInt16 n = pHts->Count(); n; )
1598 : {
1599 0 : const SwTxtAttr* pAttr = (*pHts)[ --n ];
1600 0 : if( nMkCntPos > *pAttr->GetStart() )
1601 0 : break;
1602 :
1603 0 : if( nMkCntPos == *pAttr->GetStart() &&
1604 0 : 0 != (pEndIdx = pAttr->End()) &&
1605 0 : *pEndIdx == *pAttr->GetStart() )
1606 0 : pTxtNd->DestroyAttr( pHts->Cut( n ) );
1607 : }
1608 : }
1609 : }
1610 :
1611 : {
1612 : // Send DataChanged before deletion, so that we still know
1613 : // which objects are in the range.
1614 : // Afterwards they could be before/after the Position.
1615 0 : SwDataChanged aTmp( rPam );
1616 : }
1617 :
1618 0 : if (GetIDocumentUndoRedo().DoesUndo())
1619 : {
1620 0 : GetIDocumentUndoRedo().ClearRedo();
1621 0 : bool bMerged(false);
1622 0 : if (GetIDocumentUndoRedo().DoesGroupUndo())
1623 : {
1624 0 : SwUndo *const pLastUndo( GetUndoManager().GetLastUndo() );
1625 : SwUndoDelete *const pUndoDelete(
1626 0 : dynamic_cast<SwUndoDelete *>(pLastUndo) );
1627 0 : if (pUndoDelete)
1628 : {
1629 0 : bMerged = pUndoDelete->CanGrouping( this, rPam );
1630 : // if CanGrouping() returns true it's already merged
1631 : }
1632 : }
1633 0 : if (!bMerged)
1634 : {
1635 0 : GetIDocumentUndoRedo().AppendUndo( new SwUndoDelete( rPam ) );
1636 : }
1637 :
1638 0 : SetModified();
1639 :
1640 0 : return true;
1641 : }
1642 :
1643 0 : if( !IsIgnoreRedline() && !GetRedlineTbl().empty() )
1644 0 : DeleteRedline( rPam, true, USHRT_MAX );
1645 :
1646 : // Delete and move all "Flys at the paragraph", which are within the Selection
1647 0 : DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode);
1648 : _DelBookmarks(
1649 : pStt->nNode,
1650 : pEnd->nNode,
1651 : NULL,
1652 : &pStt->nContent,
1653 0 : &pEnd->nContent);
1654 :
1655 0 : SwNodeIndex aSttIdx( pStt->nNode );
1656 0 : SwCntntNode * pCNd = aSttIdx.GetNode().GetCntntNode();
1657 :
1658 : do { // middle checked loop!
1659 0 : if( pCNd )
1660 : {
1661 0 : SwTxtNode * pStartTxtNode( pCNd->GetTxtNode() );
1662 0 : if ( pStartTxtNode )
1663 : {
1664 : // now move the Content to the new Node
1665 0 : sal_Bool bOneNd = pStt->nNode == pEnd->nNode;
1666 0 : const sal_Int32 nLen = ( bOneNd ? pEnd->nContent.GetIndex()
1667 0 : : pCNd->Len() )
1668 0 : - pStt->nContent.GetIndex();
1669 :
1670 : // Don't call again, if already empty
1671 0 : if( nLen )
1672 : {
1673 0 : pStartTxtNode->EraseText( pStt->nContent, nLen );
1674 :
1675 0 : if( !pStartTxtNode->Len() )
1676 : {
1677 : // METADATA: remove reference if empty (consider node deleted)
1678 0 : pStartTxtNode->RemoveMetadataReference();
1679 : }
1680 : }
1681 :
1682 0 : if( bOneNd ) // that's it
1683 0 : break;
1684 :
1685 0 : ++aSttIdx;
1686 : }
1687 : else
1688 : {
1689 : // So that there are no indices left registered when deleted,
1690 : // we remove a SwPaM from the Content here.
1691 0 : pStt->nContent.Assign( 0, 0 );
1692 : }
1693 : }
1694 :
1695 0 : pCNd = pEnd->nNode.GetNode().GetCntntNode();
1696 0 : if( pCNd )
1697 : {
1698 0 : SwTxtNode * pEndTxtNode( pCNd->GetTxtNode() );
1699 0 : if( pEndTxtNode )
1700 : {
1701 : // if already empty, don't call again
1702 0 : if( pEnd->nContent.GetIndex() )
1703 : {
1704 0 : SwIndex aIdx( pCNd, 0 );
1705 0 : pEndTxtNode->EraseText( aIdx, pEnd->nContent.GetIndex() );
1706 :
1707 0 : if( !pEndTxtNode->Len() )
1708 : {
1709 : // METADATA: remove reference if empty (consider node deleted)
1710 0 : pEndTxtNode->RemoveMetadataReference();
1711 0 : }
1712 : }
1713 : }
1714 : else
1715 : {
1716 : // So that there are no indices left registered when deleted,
1717 : // we remove a SwPaM from the Content here.
1718 0 : pEnd->nContent.Assign( 0, 0 );
1719 : }
1720 : }
1721 :
1722 : // if the end is not a content node, delete it as well
1723 0 : sal_uInt32 nEnde = pEnd->nNode.GetIndex();
1724 0 : if( pCNd == NULL )
1725 0 : nEnde++;
1726 :
1727 0 : if( aSttIdx != nEnde )
1728 : {
1729 : // delete the Nodes into the NodesArary
1730 0 : GetNodes().Delete( aSttIdx, nEnde - aSttIdx.GetIndex() );
1731 : }
1732 :
1733 : // If the Node that contained the Cursor has been deleted,
1734 : // the Content has to be assigned to the current Content.
1735 0 : pStt->nContent.Assign( pStt->nNode.GetNode().GetCntntNode(),
1736 0 : pStt->nContent.GetIndex() );
1737 :
1738 : // If we deleted across Node boundaries we have to correct the PaM,
1739 : // because they are in different Nodes now.
1740 : // Also, the Selection is revoked.
1741 0 : *pEnd = *pStt;
1742 0 : rPam.DeleteMark();
1743 :
1744 : } while( false );
1745 :
1746 0 : if( !IsIgnoreRedline() && !GetRedlineTbl().empty() )
1747 0 : CompressRedlines();
1748 0 : SetModified();
1749 :
1750 0 : return true;
1751 : }
1752 :
1753 : // #i100466# Add handling of new optional parameter <bForceJoinNext>
1754 0 : bool SwDoc::DeleteAndJoin( SwPaM & rPam,
1755 : const bool bForceJoinNext )
1756 : {
1757 0 : if ( lcl_StrLenOverflow( rPam ) )
1758 0 : return false;
1759 :
1760 0 : return lcl_DoWithBreaks( *this, rPam, (IsRedlineOn())
1761 : ? &SwDoc::DeleteAndJoinWithRedlineImpl
1762 : : &SwDoc::DeleteAndJoinImpl,
1763 0 : bForceJoinNext );
1764 : }
1765 :
1766 0 : bool SwDoc::DeleteRange( SwPaM & rPam )
1767 : {
1768 0 : return lcl_DoWithBreaks( *this, rPam, &SwDoc::DeleteRangeImpl );
1769 : }
1770 :
1771 0 : static void lcl_syncGrammarError( SwTxtNode &rTxtNode, linguistic2::ProofreadingResult& rResult,
1772 : const ModelToViewHelper &rConversionMap )
1773 : {
1774 0 : if( rTxtNode.IsGrammarCheckDirty() )
1775 0 : return;
1776 0 : SwGrammarMarkUp* pWrong = rTxtNode.GetGrammarCheck();
1777 0 : linguistic2::SingleProofreadingError* pArray = rResult.aErrors.getArray();
1778 0 : sal_uInt16 i, j = 0;
1779 0 : if( pWrong )
1780 : {
1781 0 : for( i = 0; i < rResult.aErrors.getLength(); ++i )
1782 : {
1783 0 : const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i];
1784 0 : const sal_Int32 nStart = rConversionMap.ConvertToModelPosition( rError.nErrorStart ).mnPos;
1785 0 : const sal_Int32 nEnd = rConversionMap.ConvertToModelPosition( rError.nErrorStart + rError.nErrorLength ).mnPos;
1786 0 : if( i != j )
1787 0 : pArray[j] = pArray[i];
1788 0 : if( pWrong->LookForEntry( nStart, nEnd ) )
1789 0 : ++j;
1790 : }
1791 : }
1792 0 : if( rResult.aErrors.getLength() > j )
1793 0 : rResult.aErrors.realloc( j );
1794 : }
1795 :
1796 0 : uno::Any SwDoc::Spell( SwPaM& rPaM,
1797 : uno::Reference< XSpellChecker1 > &xSpeller,
1798 : sal_uInt16* pPageCnt, sal_uInt16* pPageSt,
1799 : bool bGrammarCheck,
1800 : SwConversionArgs *pConvArgs ) const
1801 : {
1802 0 : SwPosition* pSttPos = rPaM.Start(), *pEndPos = rPaM.End();
1803 :
1804 0 : SwSpellArgs *pSpellArgs = 0;
1805 0 : if (pConvArgs)
1806 : {
1807 0 : pConvArgs->SetStart(pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent);
1808 0 : pConvArgs->SetEnd( pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent );
1809 : }
1810 : else
1811 : pSpellArgs = new SwSpellArgs( xSpeller,
1812 0 : pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent,
1813 0 : pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent,
1814 0 : bGrammarCheck );
1815 :
1816 0 : sal_uLong nCurrNd = pSttPos->nNode.GetIndex();
1817 0 : sal_uLong nEndNd = pEndPos->nNode.GetIndex();
1818 :
1819 0 : uno::Any aRet;
1820 0 : if( nCurrNd <= nEndNd )
1821 : {
1822 : SwCntntFrm* pCntFrm;
1823 0 : bool bGoOn = true;
1824 0 : while( bGoOn )
1825 : {
1826 0 : SwNode* pNd = GetNodes()[ nCurrNd ];
1827 0 : switch( pNd->GetNodeType() )
1828 : {
1829 : case ND_TEXTNODE:
1830 0 : if( 0 != ( pCntFrm = ((SwTxtNode*)pNd)->getLayoutFrm( GetCurrentLayout() )) )
1831 : {
1832 : // skip protected and hidden Cells and Flys
1833 0 : if( pCntFrm->IsProtected() )
1834 : {
1835 0 : nCurrNd = pNd->EndOfSectionIndex();
1836 : }
1837 0 : else if( !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
1838 : {
1839 0 : if( pPageCnt && *pPageCnt && pPageSt )
1840 : {
1841 0 : sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
1842 0 : if( !*pPageSt )
1843 : {
1844 0 : *pPageSt = nPageNr;
1845 0 : if( *pPageCnt < *pPageSt )
1846 0 : *pPageCnt = *pPageSt;
1847 : }
1848 : long nStat;
1849 0 : if( nPageNr >= *pPageSt )
1850 0 : nStat = nPageNr - *pPageSt + 1;
1851 : else
1852 0 : nStat = nPageNr + *pPageCnt - *pPageSt + 1;
1853 0 : ::SetProgressState( nStat, (SwDocShell*)GetDocShell() );
1854 : }
1855 : //Spell() changes the pSpellArgs in case an error is found
1856 0 : sal_Int32 nBeginGrammarCheck = 0;
1857 0 : sal_Int32 nEndGrammarCheck = 0;
1858 0 : if( pSpellArgs && pSpellArgs->bIsGrammarCheck)
1859 : {
1860 0 : nBeginGrammarCheck = pSpellArgs->pStartNode == pNd ? pSpellArgs->pStartIdx->GetIndex() : 0;
1861 : // if grammar checking starts inside of a sentence the start position has to be adjusted
1862 0 : if( nBeginGrammarCheck )
1863 : {
1864 0 : SwIndex aStartIndex( dynamic_cast< SwTxtNode* >( pNd ), nBeginGrammarCheck );
1865 0 : SwPosition aStart( *pNd, aStartIndex );
1866 0 : SwCursor aCrsr(aStart, 0, false);
1867 0 : SwPosition aOrigPos = *aCrsr.GetPoint();
1868 0 : aCrsr.GoSentence( SwCursor::START_SENT );
1869 0 : if( aOrigPos != *aCrsr.GetPoint() )
1870 : {
1871 0 : nBeginGrammarCheck = aCrsr.GetPoint()->nContent.GetIndex();
1872 0 : }
1873 : }
1874 0 : nEndGrammarCheck = (pSpellArgs->pEndNode == pNd)
1875 0 : ? pSpellArgs->pEndIdx->GetIndex()
1876 : : static_cast<SwTxtNode const*>(pNd)
1877 0 : ->GetTxt().getLength();
1878 : }
1879 :
1880 : sal_Int32 nSpellErrorPosition =
1881 0 : static_cast<SwTxtNode const*>(pNd)->GetTxt().getLength();
1882 0 : if( (!pConvArgs &&
1883 0 : ((SwTxtNode*)pNd)->Spell( pSpellArgs )) ||
1884 0 : ( pConvArgs &&
1885 0 : ((SwTxtNode*)pNd)->Convert( *pConvArgs )))
1886 : {
1887 : // Cancel and remember position
1888 0 : pSttPos->nNode = nCurrNd;
1889 0 : pEndPos->nNode = nCurrNd;
1890 0 : nCurrNd = nEndNd;
1891 0 : if( pSpellArgs )
1892 0 : nSpellErrorPosition = pSpellArgs->pStartIdx->GetIndex() > pSpellArgs->pEndIdx->GetIndex() ?
1893 0 : pSpellArgs->pEndIdx->GetIndex() :
1894 0 : pSpellArgs->pStartIdx->GetIndex();
1895 : }
1896 :
1897 0 : if( pSpellArgs && pSpellArgs->bIsGrammarCheck )
1898 : {
1899 0 : uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( GetGCIterator() );
1900 0 : if (xGCIterator.is())
1901 : {
1902 0 : uno::Reference< lang::XComponent > xDoc( ((SwDocShell*)GetDocShell())->GetBaseModel(), uno::UNO_QUERY );
1903 : // Expand the string:
1904 0 : const ModelToViewHelper aConversionMap(*(SwTxtNode*)pNd);
1905 0 : OUString aExpandText = aConversionMap.getViewText();
1906 :
1907 : // get XFlatParagraph to use...
1908 0 : uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *((SwTxtNode*)pNd), aExpandText, aConversionMap );
1909 :
1910 : // get error position of cursor in XFlatParagraph
1911 0 : linguistic2::ProofreadingResult aResult;
1912 : sal_Int32 nGrammarErrors;
1913 0 : do
1914 : {
1915 0 : aConversionMap.ConvertToViewPosition( nBeginGrammarCheck );
1916 0 : aResult = xGCIterator->checkSentenceAtPosition(
1917 0 : xDoc, xFlatPara, aExpandText, lang::Locale(), nBeginGrammarCheck, -1, -1 );
1918 :
1919 0 : lcl_syncGrammarError( *((SwTxtNode*)pNd), aResult, aConversionMap );
1920 :
1921 : // get suggestions to use for the specific error position
1922 0 : nGrammarErrors = aResult.aErrors.getLength();
1923 : // if grammar checking doesn't have any progress then quit
1924 0 : if( aResult.nStartOfNextSentencePosition <= nBeginGrammarCheck )
1925 0 : break;
1926 : // prepare next iteration
1927 0 : nBeginGrammarCheck = aResult.nStartOfNextSentencePosition;
1928 : }
1929 0 : while( nSpellErrorPosition > aResult.nBehindEndOfSentencePosition && !nGrammarErrors && aResult.nBehindEndOfSentencePosition < nEndGrammarCheck );
1930 :
1931 0 : if( nGrammarErrors > 0 && nSpellErrorPosition >= aResult.nBehindEndOfSentencePosition )
1932 : {
1933 0 : aRet <<= aResult;
1934 : //put the cursor to the current error
1935 0 : const linguistic2::SingleProofreadingError &rError = aResult.aErrors[0];
1936 0 : nCurrNd = pNd->GetIndex();
1937 0 : pSttPos->nNode = nCurrNd;
1938 0 : pEndPos->nNode = nCurrNd;
1939 0 : pSpellArgs->pStartNode = ((SwTxtNode*)pNd);
1940 0 : pSpellArgs->pEndNode = ((SwTxtNode*)pNd);
1941 0 : pSpellArgs->pStartIdx->Assign(((SwTxtNode*)pNd), aConversionMap.ConvertToModelPosition( rError.nErrorStart ).mnPos );
1942 0 : pSpellArgs->pEndIdx->Assign(((SwTxtNode*)pNd), aConversionMap.ConvertToModelPosition( rError.nErrorStart + rError.nErrorLength ).mnPos );
1943 0 : nCurrNd = nEndNd;
1944 0 : }
1945 0 : }
1946 : }
1947 : }
1948 : }
1949 0 : break;
1950 : case ND_SECTIONNODE:
1951 0 : if( ( ((SwSectionNode*)pNd)->GetSection().IsProtect() ||
1952 0 : ((SwSectionNode*)pNd)->GetSection().IsHidden() ) )
1953 0 : nCurrNd = pNd->EndOfSectionIndex();
1954 0 : break;
1955 : case ND_ENDNODE:
1956 : {
1957 0 : break;
1958 : }
1959 : }
1960 :
1961 0 : bGoOn = nCurrNd < nEndNd;
1962 0 : ++nCurrNd;
1963 : }
1964 : }
1965 :
1966 0 : if( !aRet.hasValue() )
1967 : {
1968 0 : if (pConvArgs)
1969 0 : aRet <<= pConvArgs->aConvText;
1970 : else
1971 0 : aRet <<= pSpellArgs->xSpellAlt;
1972 : }
1973 0 : delete pSpellArgs;
1974 :
1975 0 : return aRet;
1976 : }
1977 :
1978 0 : class SwHyphArgs : public SwInterHyphInfo
1979 : {
1980 : const SwNode *pStart;
1981 : const SwNode *pEnd;
1982 : SwNode *pNode;
1983 : sal_uInt16 *pPageCnt;
1984 : sal_uInt16 *pPageSt;
1985 :
1986 : sal_uInt32 nNode;
1987 : sal_Int32 nPamStart;
1988 : sal_Int32 nPamLen;
1989 :
1990 : public:
1991 : SwHyphArgs( const SwPaM *pPam, const Point &rPoint,
1992 : sal_uInt16* pPageCount, sal_uInt16* pPageStart );
1993 : void SetPam( SwPaM *pPam ) const;
1994 0 : inline void SetNode( SwNode *pNew ) { pNode = pNew; }
1995 : inline const SwNode *GetNode() const { return pNode; }
1996 : inline void SetRange( const SwNode *pNew );
1997 0 : inline void NextNode() { ++nNode; }
1998 0 : inline sal_uInt16 *GetPageCnt() { return pPageCnt; }
1999 0 : inline sal_uInt16 *GetPageSt() { return pPageSt; }
2000 : };
2001 :
2002 0 : SwHyphArgs::SwHyphArgs( const SwPaM *pPam, const Point &rCrsrPos,
2003 : sal_uInt16* pPageCount, sal_uInt16* pPageStart )
2004 : : SwInterHyphInfo( rCrsrPos ), pNode(0),
2005 0 : pPageCnt( pPageCount ), pPageSt( pPageStart )
2006 : {
2007 : // The following constraints have to be met:
2008 : // 1) there is at least one Selection
2009 : // 2) SPoint() == Start()
2010 : OSL_ENSURE( pPam->HasMark(), "SwDoc::Hyphenate: blowing in the wind");
2011 : OSL_ENSURE( *pPam->GetPoint() <= *pPam->GetMark(),
2012 : "SwDoc::Hyphenate: New York, New York");
2013 :
2014 0 : const SwPosition *pPoint = pPam->GetPoint();
2015 0 : nNode = pPoint->nNode.GetIndex();
2016 :
2017 : // Set start
2018 0 : pStart = pPoint->nNode.GetNode().GetTxtNode();
2019 0 : nPamStart = pPoint->nContent.GetIndex();
2020 :
2021 : // Set End and Length
2022 0 : const SwPosition *pMark = pPam->GetMark();
2023 0 : pEnd = pMark->nNode.GetNode().GetTxtNode();
2024 0 : nPamLen = pMark->nContent.GetIndex();
2025 0 : if( pPoint->nNode == pMark->nNode )
2026 0 : nPamLen = nPamLen - pPoint->nContent.GetIndex();
2027 0 : }
2028 :
2029 0 : inline void SwHyphArgs::SetRange( const SwNode *pNew )
2030 : {
2031 0 : nStart = pStart == pNew ? nPamStart : 0;
2032 0 : nEnd = pEnd == pNew ? nPamStart + nPamLen : SAL_MAX_INT32;
2033 0 : }
2034 :
2035 0 : void SwHyphArgs::SetPam( SwPaM *pPam ) const
2036 : {
2037 0 : if( !pNode )
2038 0 : *pPam->GetPoint() = *pPam->GetMark();
2039 : else
2040 : {
2041 0 : pPam->GetPoint()->nNode = nNode;
2042 0 : pPam->GetPoint()->nContent.Assign( pNode->GetCntntNode(), nWordStart );
2043 0 : pPam->GetMark()->nNode = nNode;
2044 0 : pPam->GetMark()->nContent.Assign( pNode->GetCntntNode(),
2045 0 : nWordStart + nWordLen );
2046 : OSL_ENSURE( nNode == pNode->GetIndex(),
2047 : "SwHyphArgs::SetPam: Pam disaster" );
2048 : }
2049 0 : }
2050 :
2051 : // Returns sal_True if we can proceed.
2052 0 : static bool lcl_HyphenateNode( const SwNodePtr& rpNd, void* pArgs )
2053 : {
2054 : // Hyphenate returns true if there is a hyphenation point and sets pPam
2055 0 : SwTxtNode *pNode = rpNd->GetTxtNode();
2056 0 : SwHyphArgs *pHyphArgs = (SwHyphArgs*)pArgs;
2057 0 : if( pNode )
2058 : {
2059 0 : SwCntntFrm* pCntFrm = pNode->getLayoutFrm( pNode->GetDoc()->GetCurrentLayout() );
2060 0 : if( pCntFrm && !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
2061 : {
2062 0 : sal_uInt16 *pPageSt = pHyphArgs->GetPageSt();
2063 0 : sal_uInt16 *pPageCnt = pHyphArgs->GetPageCnt();
2064 0 : if( pPageCnt && *pPageCnt && pPageSt )
2065 : {
2066 0 : sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
2067 0 : if( !*pPageSt )
2068 : {
2069 0 : *pPageSt = nPageNr;
2070 0 : if( *pPageCnt < *pPageSt )
2071 0 : *pPageCnt = *pPageSt;
2072 : }
2073 0 : long nStat = nPageNr >= *pPageSt ? nPageNr - *pPageSt + 1
2074 0 : : nPageNr + *pPageCnt - *pPageSt + 1;
2075 0 : ::SetProgressState( nStat, (SwDocShell*)pNode->GetDoc()->GetDocShell() );
2076 : }
2077 0 : pHyphArgs->SetRange( rpNd );
2078 0 : if( pNode->Hyphenate( *pHyphArgs ) )
2079 : {
2080 0 : pHyphArgs->SetNode( rpNd );
2081 0 : return false;
2082 : }
2083 : }
2084 : }
2085 0 : pHyphArgs->NextNode();
2086 0 : return true;
2087 : }
2088 :
2089 0 : uno::Reference< XHyphenatedWord > SwDoc::Hyphenate(
2090 : SwPaM *pPam, const Point &rCrsrPos,
2091 : sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
2092 : {
2093 : OSL_ENSURE(this == pPam->GetDoc(), "SwDoc::Hyphenate: strangers in the night");
2094 :
2095 0 : if( *pPam->GetPoint() > *pPam->GetMark() )
2096 0 : pPam->Exchange();
2097 :
2098 0 : SwHyphArgs aHyphArg( pPam, rCrsrPos, pPageCnt, pPageSt );
2099 0 : SwNodeIndex aTmpIdx( pPam->GetMark()->nNode, 1 );
2100 0 : GetNodes().ForEach( pPam->GetPoint()->nNode, aTmpIdx,
2101 0 : lcl_HyphenateNode, &aHyphArg );
2102 0 : aHyphArg.SetPam( pPam );
2103 0 : return aHyphArg.GetHyphWord(); // will be set by lcl_HyphenateNode
2104 : }
2105 :
2106 0 : static bool lcl_GetTokenToParaBreak( OUString& rStr, OUString& rRet, bool bRegExpRplc )
2107 : {
2108 0 : if( bRegExpRplc )
2109 : {
2110 0 : sal_Int32 nPos = 0;
2111 0 : const OUString sPara("\\n");
2112 : for (;;)
2113 : {
2114 0 : nPos = rStr.indexOf( sPara, nPos );
2115 0 : if (nPos<0)
2116 : {
2117 0 : break;
2118 : }
2119 : // Has this been escaped?
2120 0 : if( nPos && '\\' == rStr[nPos-1])
2121 : {
2122 0 : ++nPos;
2123 0 : if( nPos >= rStr.getLength() )
2124 : {
2125 0 : break;
2126 : }
2127 : }
2128 : else
2129 : {
2130 0 : rRet = rStr.copy( 0, nPos );
2131 0 : rStr = rStr.copy( nPos + sPara.getLength() );
2132 0 : return true;
2133 : }
2134 0 : }
2135 : }
2136 0 : rRet = rStr;
2137 0 : rStr = OUString();
2138 0 : return false;
2139 : }
2140 :
2141 0 : bool SwDoc::ReplaceRange( SwPaM& rPam, const OUString& rStr,
2142 : const bool bRegExReplace )
2143 : {
2144 : // unfortunately replace works slightly differently from delete,
2145 : // so we cannot use lcl_DoWithBreaks here...
2146 :
2147 0 : ::std::vector<sal_Int32> Breaks;
2148 :
2149 0 : SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
2150 0 : aPam.Normalize(false);
2151 0 : if (aPam.GetPoint()->nNode != aPam.GetMark()->nNode)
2152 : {
2153 0 : aPam.Move(fnMoveBackward);
2154 : }
2155 : OSL_ENSURE((aPam.GetPoint()->nNode == aPam.GetMark()->nNode), "invalid pam?");
2156 :
2157 0 : lcl_CalcBreaks(Breaks, aPam);
2158 :
2159 0 : while (!Breaks.empty() // skip over prefix of dummy chars
2160 0 : && (aPam.GetMark()->nContent.GetIndex() == *Breaks.begin()) )
2161 : {
2162 : // skip!
2163 0 : ++aPam.GetMark()->nContent; // always in bounds if Breaks valid
2164 0 : Breaks.erase(Breaks.begin());
2165 : }
2166 0 : *rPam.Start() = *aPam.GetMark(); // update start of original pam w/ prefix
2167 :
2168 0 : if (!Breaks.size())
2169 : {
2170 : // park aPam somewhere so it does not point to node that is deleted
2171 0 : aPam.DeleteMark();
2172 0 : *aPam.GetPoint() = SwPosition(GetNodes().GetEndOfContent());
2173 0 : return ReplaceRangeImpl(rPam, rStr, bRegExReplace); // original pam!
2174 : }
2175 :
2176 : // Deletion must be split into several parts if the text node
2177 : // contains a text attribute with end and with dummy character
2178 : // and the selection does not contain the text attribute completely,
2179 : // but overlaps its start (left), where the dummy character is.
2180 :
2181 0 : bool bRet( true );
2182 : // iterate from end to start, to avoid invalidating the offsets!
2183 0 : ::std::vector<sal_Int32>::reverse_iterator iter( Breaks.rbegin() );
2184 : OSL_ENSURE(aPam.GetPoint() == aPam.End(), "wrong!");
2185 0 : SwPosition & rEnd( *aPam.End() );
2186 0 : SwPosition & rStart( *aPam.Start() );
2187 :
2188 : // set end of temp pam to original end (undo Move backward above)
2189 0 : rEnd = *rPam.End();
2190 : // after first deletion, rEnd will point into the original text node again!
2191 :
2192 0 : while (iter != Breaks.rend())
2193 : {
2194 0 : rStart.nContent = *iter + 1;
2195 0 : if (rEnd.nContent != rStart.nContent) // check if part is empty
2196 : {
2197 0 : bRet &= (IsRedlineOn())
2198 : ? DeleteAndJoinWithRedlineImpl(aPam)
2199 0 : : DeleteAndJoinImpl(aPam, false);
2200 : }
2201 0 : rEnd.nContent = *iter;
2202 0 : ++iter;
2203 : }
2204 :
2205 0 : rStart = *rPam.Start(); // set to original start
2206 : OSL_ENSURE(rEnd.nContent > rStart.nContent, "replace part empty!");
2207 0 : if (rEnd.nContent > rStart.nContent) // check if part is empty
2208 : {
2209 0 : bRet &= ReplaceRangeImpl(aPam, rStr, bRegExReplace);
2210 : }
2211 :
2212 0 : rPam = aPam; // update original pam (is this required?)
2213 :
2214 0 : return bRet;
2215 : }
2216 :
2217 : // It's possible to call Replace with a PaM that spans 2 paragraphs:
2218 : // search with regex for "$", then replace _all_
2219 0 : bool SwDoc::ReplaceRangeImpl( SwPaM& rPam, const OUString& rStr,
2220 : const bool bRegExReplace )
2221 : {
2222 0 : if( !rPam.HasMark() || *rPam.GetPoint() == *rPam.GetMark() )
2223 0 : return false;
2224 :
2225 : sal_Bool bJoinTxt, bJoinPrev;
2226 0 : sw_GetJoinFlags( rPam, bJoinTxt, bJoinPrev );
2227 :
2228 : {
2229 : // Create a copy of the Cursor in order to move all Pams from
2230 : // the other views out of the deletion range.
2231 : // Except for itself!
2232 0 : SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
2233 0 : ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
2234 :
2235 0 : SwPosition *pStt = (SwPosition*)aDelPam.Start(),
2236 0 : *pEnd = (SwPosition*)aDelPam.End();
2237 : OSL_ENSURE( pStt->nNode == pEnd->nNode ||
2238 : ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() &&
2239 : !pEnd->nContent.GetIndex() ),
2240 : "invalid range: Point and Mark on different nodes" );
2241 0 : sal_Bool bOneNode = pStt->nNode == pEnd->nNode;
2242 :
2243 : // Own Undo?
2244 0 : OUString sRepl( rStr );
2245 0 : SwTxtNode* pTxtNd = pStt->nNode.GetNode().GetTxtNode();
2246 0 : sal_Int32 nStt = pStt->nContent.GetIndex();
2247 0 : sal_Int32 nEnd = bOneNode ? pEnd->nContent.GetIndex()
2248 0 : : pTxtNd->GetTxt().getLength();
2249 :
2250 0 : SwDataChanged aTmp( aDelPam );
2251 :
2252 0 : if( IsRedlineOn() )
2253 : {
2254 0 : RedlineMode_t eOld = GetRedlineMode();
2255 0 : checkRedlining(eOld);
2256 0 : if (GetIDocumentUndoRedo().DoesUndo())
2257 : {
2258 0 : GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
2259 :
2260 : // If any Redline will change (split!) the node
2261 0 : const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, OUString(), IDocumentMarkAccess::UNO_BOOKMARK );
2262 :
2263 : //JP 06.01.98: MUSS noch optimiert werden!!!
2264 : SetRedlineMode(
2265 0 : (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE ));
2266 :
2267 0 : *aDelPam.GetPoint() = pBkmk->GetMarkPos();
2268 0 : if(pBkmk->IsExpanded())
2269 0 : *aDelPam.GetMark() = pBkmk->GetOtherMarkPos();
2270 0 : getIDocumentMarkAccess()->deleteMark(pBkmk);
2271 0 : pStt = aDelPam.Start();
2272 0 : pTxtNd = pStt->nNode.GetNode().GetTxtNode();
2273 0 : nStt = pStt->nContent.GetIndex();
2274 : }
2275 :
2276 0 : if( !sRepl.isEmpty() )
2277 : {
2278 : // Apply the first character's attributes to the ReplaceText
2279 0 : SfxItemSet aSet( GetAttrPool(),
2280 : RES_CHRATR_BEGIN, RES_TXTATR_WITHEND_END - 1,
2281 : RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
2282 0 : 0 );
2283 0 : pTxtNd->GetAttr( aSet, nStt+1, nStt+1 );
2284 :
2285 0 : aSet.ClearItem( RES_TXTATR_REFMARK );
2286 0 : aSet.ClearItem( RES_TXTATR_TOXMARK );
2287 0 : aSet.ClearItem( RES_TXTATR_CJK_RUBY );
2288 0 : aSet.ClearItem( RES_TXTATR_INETFMT );
2289 0 : aSet.ClearItem( RES_TXTATR_META );
2290 0 : aSet.ClearItem( RES_TXTATR_METAFIELD );
2291 :
2292 0 : if( aDelPam.GetPoint() != aDelPam.End() )
2293 0 : aDelPam.Exchange();
2294 :
2295 : // Remember the End
2296 0 : SwNodeIndex aPtNd( aDelPam.GetPoint()->nNode, -1 );
2297 0 : const sal_Int32 nPtCnt = aDelPam.GetPoint()->nContent.GetIndex();
2298 :
2299 0 : bool bFirst = true;
2300 0 : OUString sIns;
2301 0 : while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
2302 : {
2303 0 : InsertString( aDelPam, sIns );
2304 0 : if( bFirst )
2305 : {
2306 0 : SwNodeIndex aMkNd( aDelPam.GetMark()->nNode, -1 );
2307 0 : const sal_Int32 nMkCnt = aDelPam.GetMark()->nContent.GetIndex();
2308 :
2309 0 : SplitNode( *aDelPam.GetPoint(), false );
2310 :
2311 0 : ++aMkNd;
2312 0 : aDelPam.GetMark()->nNode = aMkNd;
2313 0 : aDelPam.GetMark()->nContent.Assign(
2314 0 : aMkNd.GetNode().GetCntntNode(), nMkCnt );
2315 0 : bFirst = false;
2316 : }
2317 : else
2318 0 : SplitNode( *aDelPam.GetPoint(), false );
2319 : }
2320 0 : if( !sIns.isEmpty() )
2321 : {
2322 0 : InsertString( aDelPam, sIns );
2323 : }
2324 :
2325 0 : SwPaM aTmpRange( *aDelPam.GetPoint() );
2326 0 : aTmpRange.SetMark();
2327 :
2328 0 : ++aPtNd;
2329 0 : aDelPam.GetPoint()->nNode = aPtNd;
2330 0 : aDelPam.GetPoint()->nContent.Assign( aPtNd.GetNode().GetCntntNode(),
2331 0 : nPtCnt);
2332 0 : *aTmpRange.GetMark() = *aDelPam.GetPoint();
2333 :
2334 0 : RstTxtAttrs( aTmpRange );
2335 0 : InsertItemSet( aTmpRange, aSet, 0 );
2336 : }
2337 :
2338 0 : if (GetIDocumentUndoRedo().DoesUndo())
2339 : {
2340 : SwUndo *const pUndoRD =
2341 0 : new SwUndoRedlineDelete( aDelPam, UNDO_REPLACE );
2342 0 : GetIDocumentUndoRedo().AppendUndo(pUndoRD);
2343 : }
2344 0 : AppendRedline( new SwRangeRedline( nsRedlineType_t::REDLINE_DELETE, aDelPam ), true);
2345 :
2346 0 : *rPam.GetMark() = *aDelPam.GetMark();
2347 0 : if (GetIDocumentUndoRedo().DoesUndo())
2348 : {
2349 0 : *aDelPam.GetPoint() = *rPam.GetPoint();
2350 0 : GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
2351 :
2352 : // If any Redline will change (split!) the node
2353 0 : const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, OUString(), IDocumentMarkAccess::UNO_BOOKMARK );
2354 :
2355 0 : SwIndex& rIdx = aDelPam.GetPoint()->nContent;
2356 0 : rIdx.Assign( 0, 0 );
2357 0 : aDelPam.GetMark()->nContent = rIdx;
2358 0 : rPam.GetPoint()->nNode = 0;
2359 0 : rPam.GetPoint()->nContent = rIdx;
2360 0 : *rPam.GetMark() = *rPam.GetPoint();
2361 : //JP 06.01.98: MUSS noch optimiert werden!!!
2362 0 : SetRedlineMode( eOld );
2363 :
2364 0 : *rPam.GetPoint() = pBkmk->GetMarkPos();
2365 0 : if(pBkmk->IsExpanded())
2366 0 : *rPam.GetMark() = pBkmk->GetOtherMarkPos();
2367 0 : getIDocumentMarkAccess()->deleteMark(pBkmk);
2368 : }
2369 0 : bJoinTxt = sal_False;
2370 : }
2371 : else
2372 : {
2373 0 : if( !IsIgnoreRedline() && GetRedlineTbl().size() )
2374 0 : DeleteRedline( aDelPam, true, USHRT_MAX );
2375 :
2376 0 : SwUndoReplace* pUndoRpl = 0;
2377 0 : bool const bDoesUndo = GetIDocumentUndoRedo().DoesUndo();
2378 0 : if (bDoesUndo)
2379 : {
2380 0 : pUndoRpl = new SwUndoReplace(aDelPam, sRepl, bRegExReplace);
2381 0 : GetIDocumentUndoRedo().AppendUndo(pUndoRpl);
2382 : }
2383 0 : ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
2384 :
2385 0 : if( aDelPam.GetPoint() != pStt )
2386 0 : aDelPam.Exchange();
2387 :
2388 0 : SwNodeIndex aPtNd( pStt->nNode, -1 );
2389 0 : const sal_Int32 nPtCnt = pStt->nContent.GetIndex();
2390 :
2391 : // Set the values again, if Frames or footnotes on the Text have been removed.
2392 0 : nStt = nPtCnt;
2393 0 : nEnd = bOneNode ? pEnd->nContent.GetIndex()
2394 0 : : pTxtNd->GetTxt().getLength();
2395 :
2396 0 : bool bFirst = true;
2397 0 : OUString sIns;
2398 0 : while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
2399 : {
2400 0 : if (!bFirst || nStt == pTxtNd->GetTxt().getLength())
2401 : {
2402 0 : InsertString( aDelPam, sIns );
2403 : }
2404 0 : else if( nStt < nEnd || !sIns.isEmpty() )
2405 : {
2406 0 : pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
2407 : }
2408 0 : SplitNode( *pStt, false);
2409 0 : bFirst = false;
2410 : }
2411 :
2412 0 : if( bFirst || !sIns.isEmpty() )
2413 : {
2414 0 : if (!bFirst || nStt == pTxtNd->GetTxt().getLength())
2415 : {
2416 0 : InsertString( aDelPam, sIns );
2417 : }
2418 0 : else if( nStt < nEnd || !sIns.isEmpty() )
2419 : {
2420 0 : pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
2421 : }
2422 : }
2423 :
2424 0 : *rPam.GetPoint() = *aDelPam.GetMark();
2425 0 : ++aPtNd;
2426 0 : rPam.GetMark()->nNode = aPtNd;
2427 0 : rPam.GetMark()->nContent.Assign( aPtNd.GetNode().GetCntntNode(),
2428 0 : nPtCnt );
2429 :
2430 0 : if (bJoinTxt)
2431 : {
2432 : assert(rPam.GetPoint() == rPam.End());
2433 : // move so that SetEnd remembers position after sw_JoinText
2434 0 : rPam.Move(fnMoveBackward);
2435 : }
2436 0 : else if (aDelPam.GetPoint() == pStt) // backward selection?
2437 : {
2438 : assert(*rPam.GetMark() <= *rPam.GetPoint());
2439 0 : rPam.Exchange(); // swap so that rPam is backwards
2440 : }
2441 :
2442 0 : if( pUndoRpl )
2443 : {
2444 0 : pUndoRpl->SetEnd(rPam);
2445 0 : }
2446 0 : }
2447 : }
2448 :
2449 0 : if( bJoinTxt )
2450 0 : sw_JoinText( rPam, bJoinPrev );
2451 :
2452 0 : SetModified();
2453 0 : return true;
2454 : }
2455 :
2456 : // Save the current values to add them as automatic entries to to AutoCorrect.
2457 0 : void SwDoc::SetAutoCorrExceptWord( SwAutoCorrExceptWord* pNew )
2458 : {
2459 0 : if( pNew != mpACEWord )
2460 0 : delete mpACEWord;
2461 0 : mpACEWord = pNew;
2462 0 : }
2463 :
2464 0 : bool SwDoc::DelFullPara( SwPaM& rPam )
2465 : {
2466 0 : const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
2467 0 : const SwNode* pNd = &rStt.nNode.GetNode();
2468 0 : sal_uInt32 nSectDiff = pNd->StartOfSectionNode()->EndOfSectionIndex() -
2469 0 : pNd->StartOfSectionIndex();
2470 0 : sal_uInt32 nNodeDiff = rEnd.nNode.GetIndex() - rStt.nNode.GetIndex();
2471 :
2472 0 : if ( nSectDiff-2 <= nNodeDiff || IsRedlineOn() ||
2473 : /* #i9185# Prevent getting the node after the end node (see below) */
2474 0 : rEnd.nNode.GetIndex() + 1 == GetNodes().Count() )
2475 : {
2476 0 : return false;
2477 : }
2478 :
2479 : // Move hard page brakes to the following Node.
2480 0 : sal_Bool bSavePageBreak = sal_False, bSavePageDesc = sal_False;
2481 :
2482 : /* #i9185# This whould lead to a segmentation fault if not caught above. */
2483 0 : sal_uLong nNextNd = rEnd.nNode.GetIndex() + 1;
2484 0 : SwTableNode *const pTblNd = GetNodes()[ nNextNd ]->GetTableNode();
2485 :
2486 0 : if( pTblNd && pNd->IsCntntNode() )
2487 : {
2488 0 : SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
2489 :
2490 : {
2491 : const SfxPoolItem *pItem;
2492 0 : const SfxItemSet* pSet = ((SwCntntNode*)pNd)->GetpSwAttrSet();
2493 0 : if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
2494 0 : false, &pItem ) )
2495 : {
2496 0 : pTableFmt->SetFmtAttr( *pItem );
2497 0 : bSavePageDesc = sal_True;
2498 : }
2499 :
2500 0 : if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
2501 0 : false, &pItem ) )
2502 : {
2503 0 : pTableFmt->SetFmtAttr( *pItem );
2504 0 : bSavePageBreak = sal_True;
2505 : }
2506 : }
2507 : }
2508 :
2509 0 : bool const bDoesUndo = GetIDocumentUndoRedo().DoesUndo();
2510 0 : if( bDoesUndo )
2511 : {
2512 0 : if( !rPam.HasMark() )
2513 0 : rPam.SetMark();
2514 0 : else if( rPam.GetPoint() == &rStt )
2515 0 : rPam.Exchange();
2516 0 : rPam.GetPoint()->nNode++;
2517 :
2518 0 : SwCntntNode *pTmpNode = rPam.GetPoint()->nNode.GetNode().GetCntntNode();
2519 0 : rPam.GetPoint()->nContent.Assign( pTmpNode, 0 );
2520 0 : bool bGoNext = (0 == pTmpNode);
2521 0 : pTmpNode = rPam.GetMark()->nNode.GetNode().GetCntntNode();
2522 0 : rPam.GetMark()->nContent.Assign( pTmpNode, 0 );
2523 :
2524 0 : GetIDocumentUndoRedo().ClearRedo();
2525 :
2526 0 : SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
2527 : {
2528 0 : SwPosition aTmpPos( *aDelPam.GetPoint() );
2529 0 : if( bGoNext )
2530 : {
2531 0 : pTmpNode = GetNodes().GoNext( &aTmpPos.nNode );
2532 0 : aTmpPos.nContent.Assign( pTmpNode, 0 );
2533 : }
2534 0 : ::PaMCorrAbs( aDelPam, aTmpPos );
2535 : }
2536 :
2537 0 : SwUndoDelete* pUndo = new SwUndoDelete( aDelPam, sal_True );
2538 :
2539 0 : *rPam.GetPoint() = *aDelPam.GetPoint();
2540 0 : pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
2541 0 : GetIDocumentUndoRedo().AppendUndo(pUndo);
2542 : }
2543 : else
2544 : {
2545 0 : SwNodeRange aRg( rStt.nNode, rEnd.nNode );
2546 0 : if( rPam.GetPoint() != &rEnd )
2547 0 : rPam.Exchange();
2548 :
2549 : // Try to move past the End
2550 0 : if( !rPam.Move( fnMoveForward, fnGoNode ) )
2551 : {
2552 : // Fair enough, at the Beginning then
2553 0 : rPam.Exchange();
2554 0 : if( !rPam.Move( fnMoveBackward, fnGoNode ))
2555 : {
2556 : OSL_FAIL( "no more Nodes" );
2557 0 : return false;
2558 : }
2559 : }
2560 : // move bookmarks, redlines etc.
2561 0 : if (aRg.aStart == aRg.aEnd) // only first CorrAbs variant handles this
2562 : {
2563 0 : CorrAbs( aRg.aStart, *rPam.GetPoint(), 0, sal_True );
2564 : }
2565 : else
2566 : {
2567 0 : CorrAbs( aRg.aStart, aRg.aEnd, *rPam.GetPoint(), sal_True );
2568 : }
2569 :
2570 : // What's with Flys?
2571 : {
2572 : // If there are FlyFrames left, delete these too
2573 0 : for( sal_uInt16 n = 0; n < GetSpzFrmFmts()->size(); ++n )
2574 : {
2575 0 : SwFrmFmt* pFly = (*GetSpzFrmFmts())[n];
2576 0 : const SwFmtAnchor* pAnchor = &pFly->GetAnchor();
2577 0 : SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
2578 0 : if (pAPos &&
2579 0 : ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
2580 0 : (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
2581 0 : aRg.aStart <= pAPos->nNode && pAPos->nNode <= aRg.aEnd )
2582 : {
2583 0 : DelLayoutFmt( pFly );
2584 0 : --n;
2585 : }
2586 : }
2587 : }
2588 :
2589 0 : SwCntntNode *pTmpNode = rPam.GetBound( true ).nNode.GetNode().GetCntntNode();
2590 0 : rPam.GetBound( true ).nContent.Assign( pTmpNode, 0 );
2591 0 : pTmpNode = rPam.GetBound( false ).nNode.GetNode().GetCntntNode();
2592 0 : rPam.GetBound( false ).nContent.Assign( pTmpNode, 0 );
2593 0 : GetNodes().Delete( aRg.aStart, nNodeDiff+1 );
2594 : }
2595 0 : rPam.DeleteMark();
2596 0 : SetModified();
2597 :
2598 0 : return true;
2599 : }
2600 :
2601 0 : void SwDoc::TransliterateText(
2602 : const SwPaM& rPaM,
2603 : utl::TransliterationWrapper& rTrans )
2604 : {
2605 0 : SwUndoTransliterate *const pUndo = (GetIDocumentUndoRedo().DoesUndo())
2606 0 : ? new SwUndoTransliterate( rPaM, rTrans )
2607 0 : : 0;
2608 :
2609 0 : const SwPosition* pStt = rPaM.Start(),
2610 0 : * pEnd = rPaM.End();
2611 0 : sal_uLong nSttNd = pStt->nNode.GetIndex(),
2612 0 : nEndNd = pEnd->nNode.GetIndex();
2613 0 : sal_Int32 nSttCnt = pStt->nContent.GetIndex();
2614 0 : sal_Int32 nEndCnt = pEnd->nContent.GetIndex();
2615 :
2616 0 : SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
2617 0 : if( pStt == pEnd && pTNd ) // no selection?
2618 : {
2619 : // set current word as 'area of effect'
2620 :
2621 0 : Boundary aBndry;
2622 0 : if( g_pBreakIt->GetBreakIter().is() )
2623 0 : aBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
2624 0 : pTNd->GetTxt(), nSttCnt,
2625 0 : g_pBreakIt->GetLocale( pTNd->GetLang( nSttCnt ) ),
2626 : WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/,
2627 0 : sal_True );
2628 :
2629 0 : if( aBndry.startPos < nSttCnt && nSttCnt < aBndry.endPos )
2630 : {
2631 0 : nSttCnt = aBndry.startPos;
2632 0 : nEndCnt = aBndry.endPos;
2633 : }
2634 : }
2635 :
2636 0 : if( nSttNd != nEndNd ) // is more than one text node involved?
2637 : {
2638 : // iterate over all effected text nodes, the first and the last one
2639 : // may be incomplete because the selection starts and/or ends there
2640 :
2641 0 : SwNodeIndex aIdx( pStt->nNode );
2642 0 : if( nSttCnt )
2643 : {
2644 0 : ++aIdx;
2645 0 : if( pTNd )
2646 : pTNd->TransliterateText(
2647 0 : rTrans, nSttCnt, pTNd->GetTxt().getLength(), pUndo);
2648 : }
2649 :
2650 0 : for( ; aIdx.GetIndex() < nEndNd; ++aIdx )
2651 : {
2652 0 : pTNd = aIdx.GetNode().GetTxtNode();
2653 0 : if (pTNd)
2654 : {
2655 : pTNd->TransliterateText(
2656 0 : rTrans, 0, pTNd->GetTxt().getLength(), pUndo);
2657 : }
2658 : }
2659 :
2660 0 : if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
2661 0 : pTNd->TransliterateText( rTrans, 0, nEndCnt, pUndo );
2662 : }
2663 0 : else if( pTNd && nSttCnt < nEndCnt )
2664 0 : pTNd->TransliterateText( rTrans, nSttCnt, nEndCnt, pUndo );
2665 :
2666 0 : if( pUndo )
2667 : {
2668 0 : if( pUndo->HasData() )
2669 : {
2670 0 : GetIDocumentUndoRedo().AppendUndo(pUndo);
2671 : }
2672 : else
2673 0 : delete pUndo;
2674 : }
2675 0 : SetModified();
2676 0 : }
2677 :
2678 : #define MAX_REDLINE_COUNT 250
2679 :
2680 0 : void SwDoc::checkRedlining(RedlineMode_t& _rReadlineMode)
2681 : {
2682 0 : const SwRedlineTbl& rRedlineTbl = GetRedlineTbl();
2683 0 : SwEditShell* pEditShell = GetEditShell();
2684 0 : Window* pParent = pEditShell ? pEditShell->GetWin() : NULL;
2685 0 : if ( pParent && !mbReadlineChecked && rRedlineTbl.size() > MAX_REDLINE_COUNT
2686 0 : && !((_rReadlineMode & nsRedlineMode_t::REDLINE_SHOW_DELETE) == nsRedlineMode_t::REDLINE_SHOW_DELETE) )
2687 : {
2688 0 : MessageDialog aQuery(pParent, "QueryShowChangesDialog", "modules/swriter/ui/queryshowchangesdialog.ui");
2689 0 : sal_uInt16 nResult = aQuery.Execute();
2690 0 : mbReadlineChecked = true;
2691 0 : if ( nResult == RET_YES )
2692 : {
2693 0 : sal_Int32 nMode = (sal_Int32)_rReadlineMode;
2694 0 : nMode |= nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE;
2695 0 : _rReadlineMode = (RedlineMode_t)nMode;
2696 0 : }
2697 : }
2698 0 : }
2699 :
2700 0 : void SwDoc::CountWords( const SwPaM& rPaM, SwDocStat& rStat ) const
2701 : {
2702 : // This is a modified version of SwDoc::TransliterateText
2703 0 : const SwPosition* pStt = rPaM.Start();
2704 0 : const SwPosition* pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
2705 0 : : rPaM.GetPoint();
2706 :
2707 0 : const sal_uLong nSttNd = pStt->nNode.GetIndex();
2708 0 : const sal_uLong nEndNd = pEnd->nNode.GetIndex();
2709 :
2710 0 : const sal_Int32 nSttCnt = pStt->nContent.GetIndex();
2711 0 : const sal_Int32 nEndCnt = pEnd->nContent.GetIndex();
2712 :
2713 0 : const SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
2714 0 : if( pStt == pEnd && pTNd ) // no region ?
2715 : {
2716 : // do nothing
2717 0 : return;
2718 : }
2719 :
2720 0 : if( nSttNd != nEndNd )
2721 : {
2722 0 : SwNodeIndex aIdx( pStt->nNode );
2723 0 : if( nSttCnt )
2724 : {
2725 0 : ++aIdx;
2726 0 : if( pTNd )
2727 0 : pTNd->CountWords( rStat, nSttCnt, pTNd->GetTxt().getLength() );
2728 : }
2729 :
2730 0 : for( ; aIdx.GetIndex() < nEndNd; ++aIdx )
2731 0 : if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() ))
2732 0 : pTNd->CountWords( rStat, 0, pTNd->GetTxt().getLength() );
2733 :
2734 0 : if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
2735 0 : pTNd->CountWords( rStat, 0, nEndCnt );
2736 : }
2737 0 : else if( pTNd && nSttCnt < nEndCnt )
2738 0 : pTNd->CountWords( rStat, nSttCnt, nEndCnt );
2739 : }
2740 :
2741 0 : void SwDoc::RemoveLeadingWhiteSpace(const SwPosition & rPos )
2742 : {
2743 0 : const SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode();
2744 0 : if ( pTNd )
2745 : {
2746 0 : const OUString& rTxt = pTNd->GetTxt();
2747 0 : sal_Int32 nIdx = 0;
2748 0 : while (nIdx < rTxt.getLength())
2749 : {
2750 0 : sal_Unicode const cCh = rTxt[nIdx];
2751 0 : if (('\t' != cCh) && (' ' != cCh))
2752 : {
2753 0 : break;
2754 : }
2755 0 : ++nIdx;
2756 : }
2757 :
2758 0 : if ( nIdx > 0 )
2759 : {
2760 0 : SwPaM aPam(rPos);
2761 0 : aPam.GetPoint()->nContent = 0;
2762 0 : aPam.SetMark();
2763 0 : aPam.GetMark()->nContent = nIdx;
2764 0 : DeleteRange( aPam );
2765 : }
2766 : }
2767 0 : }
2768 :
2769 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|