update credits
[LibreOffice.git] / sw / source / core / doc / docedt.cxx
blobb0794e66d1ef08057be27f7169ba4cb0eac8375c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <fmtanchr.hxx>
22 #include <fmtcntnt.hxx>
23 #include <txtftn.hxx>
24 #include <acorrect.hxx> // AutoCorrect
25 #include <UndoManager.hxx>
26 #include <docsh.hxx>
27 #include <docary.hxx>
28 #include <doctxm.hxx> // when moving: correct indexes
29 #include <ftnidx.hxx>
30 #include <mdiexp.hxx> // status bar
31 #include <mvsave.hxx> // structures to save when moving/deleting
32 #include <redline.hxx>
33 #include <rootfrm.hxx> // for UpdateFtn
34 #include <splargs.hxx> // for Spell
35 #include <txtfrm.hxx>
36 #include <UndoSplitMove.hxx>
37 #include <UndoRedline.hxx>
38 #include <UndoOverwrite.hxx>
39 #include <UndoInsert.hxx>
40 #include <UndoDelete.hxx>
41 #include <breakit.hxx>
42 #include <vcl/msgbox.hxx>
43 #include "comcore.hrc"
44 #include "editsh.hxx"
45 #include <fmtfld.hxx>
46 #include <docufld.hxx>
47 #include <unoflatpara.hxx>
48 #include <SwGrammarMarkUp.hxx>
50 #include <vector>
52 using namespace ::com::sun::star;
53 using namespace ::com::sun::star::linguistic2;
54 using namespace ::com::sun::star::i18n;
56 struct _SaveRedline
58 SwRedline* pRedl;
59 sal_uInt32 nStt, nEnd;
60 xub_StrLen nSttCnt, nEndCnt;
62 _SaveRedline( SwRedline* pR, const SwNodeIndex& rSttIdx )
63 : pRedl( pR )
65 const SwPosition* pStt = pR->Start(),
66 * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
67 sal_uInt32 nSttIdx = rSttIdx.GetIndex();
68 nStt = pStt->nNode.GetIndex() - nSttIdx;
69 nSttCnt = pStt->nContent.GetIndex();
70 if( pR->HasMark() )
72 nEnd = pEnd->nNode.GetIndex() - nSttIdx;
73 nEndCnt = pEnd->nContent.GetIndex();
76 pRedl->GetPoint()->nNode = 0;
77 pRedl->GetPoint()->nContent.Assign( 0, 0 );
78 pRedl->GetMark()->nNode = 0;
79 pRedl->GetMark()->nContent.Assign( 0, 0 );
82 _SaveRedline( SwRedline* pR, const SwPosition& rPos )
83 : pRedl( pR )
85 const SwPosition* pStt = pR->Start(),
86 * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
87 sal_uInt32 nSttIdx = rPos.nNode.GetIndex();
88 nStt = pStt->nNode.GetIndex() - nSttIdx;
89 nSttCnt = pStt->nContent.GetIndex();
90 if( nStt == 0 )
91 nSttCnt = nSttCnt - rPos.nContent.GetIndex();
92 if( pR->HasMark() )
94 nEnd = pEnd->nNode.GetIndex() - nSttIdx;
95 nEndCnt = pEnd->nContent.GetIndex();
96 if( nEnd == 0 )
97 nEndCnt = nEndCnt - rPos.nContent.GetIndex();
100 pRedl->GetPoint()->nNode = 0;
101 pRedl->GetPoint()->nContent.Assign( 0, 0 );
102 pRedl->GetMark()->nNode = 0;
103 pRedl->GetMark()->nContent.Assign( 0, 0 );
106 void SetPos( sal_uInt32 nInsPos )
108 pRedl->GetPoint()->nNode = nInsPos + nStt;
109 pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt );
110 if( pRedl->HasMark() )
112 pRedl->GetMark()->nNode = nInsPos + nEnd;
113 pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(sal_False), nEndCnt );
117 void SetPos( const SwPosition& aPos )
119 pRedl->GetPoint()->nNode = aPos.nNode.GetIndex() + nStt;
120 pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt + ( nStt == 0 ? aPos.nContent.GetIndex() : 0 ) );
121 if( pRedl->HasMark() )
123 pRedl->GetMark()->nNode = aPos.nNode.GetIndex() + nEnd;
124 pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(sal_False), nEndCnt + ( nEnd == 0 ? aPos.nContent.GetIndex() : 0 ) );
129 typedef boost::ptr_vector< _SaveRedline > _SaveRedlines;
131 static bool lcl_MayOverwrite( const SwTxtNode *pNode, const xub_StrLen nPos )
133 sal_Unicode const cChr = pNode->GetTxt()[nPos];
134 switch (cChr)
136 case CH_TXTATR_BREAKWORD:
137 case CH_TXTATR_INWORD:
138 return !pNode->GetTxtAttrForCharAt(nPos);// how could there be none?
139 case CH_TXT_ATR_FIELDSTART:
140 case CH_TXT_ATR_FIELDEND:
141 case CH_TXT_ATR_FORMELEMENT:
142 return false;
143 default:
144 return true;
148 static void lcl_SkipAttr( const SwTxtNode *pNode, SwIndex &rIdx, xub_StrLen &rStart )
150 if( !lcl_MayOverwrite( pNode, rStart ) )
152 // skip all special attributes
153 do {
154 ++rIdx;
155 rStart = rIdx.GetIndex();
156 } while (rStart < pNode->GetTxt().getLength()
157 && !lcl_MayOverwrite(pNode, rStart) );
161 void _RestFlyInRange( _SaveFlyArr & rArr, const SwNodeIndex& rSttIdx,
162 const SwNodeIndex* pInsertPos )
164 SwPosition aPos( rSttIdx );
165 for( size_t n = 0; n < rArr.size(); ++n )
167 // create new anchor
168 _SaveFly& rSave = rArr[n];
169 SwFrmFmt* pFmt = rSave.pFrmFmt;
171 if( rSave.bInsertPosition )
173 if( pInsertPos != NULL )
174 aPos.nNode = *pInsertPos;
175 else
176 aPos.nNode = rSttIdx.GetIndex();
178 else
179 aPos.nNode = rSttIdx.GetIndex() + rSave.nNdDiff;
181 aPos.nContent.Assign( 0, 0 );
182 SwFmtAnchor aAnchor( pFmt->GetAnchor() );
183 aAnchor.SetAnchor( &aPos );
184 pFmt->GetDoc()->GetSpzFrmFmts()->push_back( pFmt );
185 pFmt->SetFmtAttr( aAnchor );
186 SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode();
187 if( pCNd && pCNd->getLayoutFrm( pFmt->GetDoc()->GetCurrentLayout(), 0, 0, sal_False ) )
188 pFmt->MakeFrms();
192 void _SaveFlyInRange( const SwNodeRange& rRg, _SaveFlyArr& rArr )
194 SwFrmFmts& rFmts = *rRg.aStart.GetNode().GetDoc()->GetSpzFrmFmts();
195 for( sal_uInt16 n = 0; n < rFmts.size(); ++n )
197 SwFrmFmt *const pFmt = static_cast<SwFrmFmt*>(rFmts[n]);
198 SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
199 SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
200 if (pAPos &&
201 ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
202 (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
203 rRg.aStart <= pAPos->nNode && pAPos->nNode < rRg.aEnd )
205 _SaveFly aSave( pAPos->nNode.GetIndex() - rRg.aStart.GetIndex(),
206 pFmt, false );
207 rArr.push_back( aSave );
208 pFmt->DelFrms();
209 rFmts.erase( rFmts.begin() + n-- );
214 void _SaveFlyInRange( const SwPaM& rPam, const SwNodeIndex& rInsPos,
215 _SaveFlyArr& rArr, bool bMoveAllFlys )
217 SwFrmFmts& rFmts = *rPam.GetPoint()->nNode.GetNode().GetDoc()->GetSpzFrmFmts();
218 SwFrmFmt* pFmt;
219 const SwFmtAnchor* pAnchor;
221 const SwPosition* pPos = rPam.Start();
222 const SwNodeIndex& rSttNdIdx = pPos->nNode;
223 short nSttOff = (!bMoveAllFlys && rSttNdIdx.GetNode().IsCntntNode() &&
224 pPos->nContent.GetIndex()) ? 1 : 0;
226 pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint();
227 const SwNodeIndex& rEndNdIdx = pPos->nNode;
228 short nOff = ( bMoveAllFlys || ( rEndNdIdx.GetNode().IsCntntNode() &&
229 pPos->nContent == rEndNdIdx.GetNode().GetCntntNode()->Len() ))
230 ? 0 : 1;
232 const SwNodeIndex* pCntntIdx;
234 for( sal_uInt16 n = 0; n < rFmts.size(); ++n )
236 bool bInsPos = false;
237 pFmt = (SwFrmFmt*)rFmts[n];
238 pAnchor = &pFmt->GetAnchor();
239 const SwPosition* pAPos = pAnchor->GetCntntAnchor();
240 if (pAPos &&
241 ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
242 (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
243 // do not move if the InsPos is in the CntntArea of the Fly
244 ( 0 == ( pCntntIdx = pFmt->GetCntnt().GetCntntIdx() ) ||
245 !( *pCntntIdx < rInsPos &&
246 rInsPos < pCntntIdx->GetNode().EndOfSectionIndex() )) )
248 if( !bMoveAllFlys && rEndNdIdx == pAPos->nNode )
250 // Do not touch Anchor, if only a part of the EndNode
251 // or the whole EndNode is identical with the SttNode
252 if( rSttNdIdx != pAPos->nNode )
254 // Only attach an anchor to the beginning or end
255 SwPosition aPos( rSttNdIdx );
256 SwFmtAnchor aAnchor( *pAnchor );
257 aAnchor.SetAnchor( &aPos );
258 pFmt->SetFmtAttr( aAnchor );
261 else if( ( rSttNdIdx.GetIndex() + nSttOff <= pAPos->nNode.GetIndex()
262 && pAPos->nNode.GetIndex() <= rEndNdIdx.GetIndex() - nOff ) ||
263 0 != ( bInsPos = rInsPos == pAPos->nNode ))
266 _SaveFly aSave( pAPos->nNode.GetIndex() - rSttNdIdx.GetIndex(),
267 pFmt, bInsPos );
268 rArr.push_back( aSave );
269 pFmt->DelFrms();
270 rFmts.erase( rFmts.begin() + n-- );
276 /// Delete and move all Flys at the paragraph, that are within the selection.
277 /// If there is a Fly at the SPoint, it is moved onto the Mark.
278 void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
279 const SwNodeIndex& rPtNdIdx )
281 const bool bDelFwrd = rMkNdIdx.GetIndex() <= rPtNdIdx.GetIndex();
283 SwDoc* pDoc = rMkNdIdx.GetNode().GetDoc();
284 SwFrmFmts& rTbl = *pDoc->GetSpzFrmFmts();
285 for ( sal_uInt16 i = rTbl.size(); i; )
287 SwFrmFmt *pFmt = rTbl[--i];
288 const SwFmtAnchor &rAnch = pFmt->GetAnchor();
289 SwPosition const*const pAPos = rAnch.GetCntntAnchor();
290 if (pAPos &&
291 ((rAnch.GetAnchorId() == FLY_AT_PARA) ||
292 (rAnch.GetAnchorId() == FLY_AT_CHAR)) &&
293 ( bDelFwrd
294 ? rMkNdIdx < pAPos->nNode && pAPos->nNode <= rPtNdIdx
295 : rPtNdIdx <= pAPos->nNode && pAPos->nNode < rMkNdIdx ))
297 // Only move the Anchor??
298 if( rPtNdIdx == pAPos->nNode )
300 SwFmtAnchor aAnch( pFmt->GetAnchor() );
301 SwPosition aPos( rMkNdIdx );
302 aAnch.SetAnchor( &aPos );
303 pFmt->SetFmtAttr( aAnch );
305 else
307 // If the Fly is deleted, all Flys in it's content have to be deleted too.
308 const SwFmtCntnt &rCntnt = pFmt->GetCntnt();
309 if( rCntnt.GetCntntIdx() )
311 DelFlyInRange( *rCntnt.GetCntntIdx(),
312 SwNodeIndex( *rCntnt.GetCntntIdx()->
313 GetNode().EndOfSectionNode() ));
314 // Position could have been moved!
315 if( i > rTbl.size() )
316 i = rTbl.size();
317 else if( pFmt != rTbl[i] )
318 i = rTbl.GetPos( pFmt );
321 pDoc->DelLayoutFmt( pFmt );
323 // DelLayoutFmt can also trigger the deletion of objects.
324 if( i > rTbl.size() )
325 i = rTbl.size();
331 static bool lcl_SaveFtn( const SwNodeIndex& rSttNd, const SwNodeIndex& rEndNd,
332 const SwNodeIndex& rInsPos,
333 SwFtnIdxs& rFtnArr, SwFtnIdxs& rSaveArr,
334 const SwIndex* pSttCnt = 0, const SwIndex* pEndCnt = 0 )
336 bool bUpdateFtn = sal_False;
337 const SwNodes& rNds = rInsPos.GetNodes();
338 const bool bDelFtn = rInsPos.GetIndex() < rNds.GetEndOfAutotext().GetIndex() &&
339 rSttNd.GetIndex() >= rNds.GetEndOfAutotext().GetIndex();
340 const bool bSaveFtn = !bDelFtn &&
341 rInsPos.GetIndex() >= rNds.GetEndOfExtras().GetIndex();
342 if( !rFtnArr.empty() )
345 sal_uInt16 nPos;
346 rFtnArr.SeekEntry( rSttNd, &nPos );
347 SwTxtFtn* pSrch;
348 const SwNode* pFtnNd;
350 // Delete/save all that come after it
351 while( nPos < rFtnArr.size() && ( pFtnNd =
352 &( pSrch = rFtnArr[ nPos ] )->GetTxtNode())->GetIndex()
353 <= rEndNd.GetIndex() )
355 xub_StrLen nFtnSttIdx = *pSrch->GetStart();
356 if( ( pEndCnt && pSttCnt )
357 ? (( &rSttNd.GetNode() == pFtnNd &&
358 pSttCnt->GetIndex() > nFtnSttIdx) ||
359 ( &rEndNd.GetNode() == pFtnNd &&
360 nFtnSttIdx >= pEndCnt->GetIndex() ))
361 : ( &rEndNd.GetNode() == pFtnNd ))
363 ++nPos; // continue searching
365 else
367 // delete it
368 if( bDelFtn )
370 SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
371 SwIndex aIdx( &rTxtNd, nFtnSttIdx );
372 rTxtNd.EraseText( aIdx, 1 );
374 else
376 pSrch->DelFrms(0);
377 rFtnArr.erase( rFtnArr.begin() + nPos );
378 if( bSaveFtn )
379 rSaveArr.insert( pSrch );
381 bUpdateFtn = sal_True;
385 while( nPos-- && ( pFtnNd = &( pSrch = rFtnArr[ nPos ] )->
386 GetTxtNode())->GetIndex() >= rSttNd.GetIndex() )
388 xub_StrLen nFtnSttIdx = *pSrch->GetStart();
389 if( !pEndCnt || !pSttCnt ||
390 !( (( &rSttNd.GetNode() == pFtnNd &&
391 pSttCnt->GetIndex() > nFtnSttIdx ) ||
392 ( &rEndNd.GetNode() == pFtnNd &&
393 nFtnSttIdx >= pEndCnt->GetIndex() )) ))
395 if( bDelFtn )
397 // delete it
398 SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
399 SwIndex aIdx( &rTxtNd, nFtnSttIdx );
400 rTxtNd.EraseText( aIdx, 1 );
402 else
404 pSrch->DelFrms(0);
405 rFtnArr.erase( rFtnArr.begin() + nPos );
406 if( bSaveFtn )
407 rSaveArr.insert( pSrch );
409 bUpdateFtn = sal_True;
413 // When moving from redline section into document content section, e.g.
414 // after loading a document with (delete-)redlines, the footnote array
415 // has to be adjusted... (#i70572)
416 if( bSaveFtn )
418 SwNodeIndex aIdx( rSttNd );
419 while( aIdx < rEndNd ) // Check the moved section
421 SwNode* pNode = &aIdx.GetNode();
422 if( pNode->IsTxtNode() ) // Looking for text nodes...
424 SwpHints *pHints =
425 static_cast<SwTxtNode*>(pNode)->GetpSwpHints();
426 if( pHints && pHints->HasFtn() ) //...with footnotes
428 bUpdateFtn = sal_True; // Heureka
429 sal_uInt16 nCount = pHints->Count();
430 for( sal_uInt16 i = 0; i < nCount; ++i )
432 SwTxtAttr *pAttr = pHints->GetTextHint( i );
433 if ( pAttr->Which() == RES_TXTATR_FTN )
435 rSaveArr.insert( static_cast<SwTxtFtn*>(pAttr) );
440 ++aIdx;
443 return bUpdateFtn;
446 static void lcl_SaveRedlines( const SwPaM& aPam, _SaveRedlines& rArr )
448 SwDoc* pDoc = aPam.GetNode()->GetDoc();
450 const SwPosition* pStart = aPam.Start();
451 const SwPosition* pEnd = aPam.End();
453 // get first relevant redline
454 sal_uInt16 nCurrentRedline;
455 pDoc->GetRedline( *pStart, &nCurrentRedline );
456 if( nCurrentRedline > 0)
457 nCurrentRedline--;
459 // redline mode REDLINE_IGNORE|REDLINE_ON; save old mode
460 RedlineMode_t eOld = pDoc->GetRedlineMode();
461 pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
463 // iterate over relevant redlines and decide for each whether it should
464 // be saved, or split + saved
465 SwRedlineTbl& rRedlineTable = const_cast<SwRedlineTbl&>( pDoc->GetRedlineTbl() );
466 for( ; nCurrentRedline < rRedlineTable.size(); nCurrentRedline++ )
468 SwRedline* pCurrent = rRedlineTable[ nCurrentRedline ];
469 SwComparePosition eCompare =
470 ComparePosition( *pCurrent->Start(), *pCurrent->End(),
471 *pStart, *pEnd);
473 // we must save this redline if it overlaps aPam
474 // (we may have to split it, too)
475 if( eCompare == POS_OVERLAP_BEHIND ||
476 eCompare == POS_OVERLAP_BEFORE ||
477 eCompare == POS_OUTSIDE ||
478 eCompare == POS_INSIDE ||
479 eCompare == POS_EQUAL )
481 rRedlineTable.Remove( nCurrentRedline-- );
483 // split beginning, if necessary
484 if( eCompare == POS_OVERLAP_BEFORE ||
485 eCompare == POS_OUTSIDE )
488 SwRedline* pNewRedline = new SwRedline( *pCurrent );
489 *pNewRedline->End() = *pStart;
490 *pCurrent->Start() = *pStart;
491 pDoc->AppendRedline( pNewRedline, true );
494 // split end, if necessary
495 if( eCompare == POS_OVERLAP_BEHIND ||
496 eCompare == POS_OUTSIDE )
498 SwRedline* pNewRedline = new SwRedline( *pCurrent );
499 *pNewRedline->Start() = *pEnd;
500 *pCurrent->End() = *pEnd;
501 pDoc->AppendRedline( pNewRedline, true );
504 // save the current redline
505 _SaveRedline* pSave = new _SaveRedline( pCurrent, *pStart );
506 rArr.push_back( pSave );
510 // restore old redline mode
511 pDoc->SetRedlineMode_intern( eOld );
514 static void lcl_RestoreRedlines( SwDoc* pDoc, const SwPosition& rPos, _SaveRedlines& rArr )
516 RedlineMode_t eOld = pDoc->GetRedlineMode();
517 pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
519 for( size_t n = 0; n < rArr.size(); ++n )
521 rArr[ n ].SetPos( rPos );
522 pDoc->AppendRedline( rArr[ n ].pRedl, true );
525 pDoc->SetRedlineMode_intern( eOld );
528 static void lcl_SaveRedlines( const SwNodeRange& rRg, _SaveRedlines& rArr )
530 SwDoc* pDoc = rRg.aStart.GetNode().GetDoc();
531 sal_uInt16 nRedlPos;
532 SwPosition aSrchPos( rRg.aStart ); aSrchPos.nNode--;
533 aSrchPos.nContent.Assign( aSrchPos.nNode.GetNode().GetCntntNode(), 0 );
534 if( pDoc->GetRedline( aSrchPos, &nRedlPos ) && nRedlPos )
535 --nRedlPos;
536 else if( nRedlPos >= pDoc->GetRedlineTbl().size() )
537 return ;
539 RedlineMode_t eOld = pDoc->GetRedlineMode();
540 pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
541 SwRedlineTbl& rRedlTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl();
543 do {
544 SwRedline* pTmp = rRedlTbl[ nRedlPos ];
546 const SwPosition* pRStt = pTmp->Start(),
547 * pREnd = pTmp->GetMark() == pRStt
548 ? pTmp->GetPoint() : pTmp->GetMark();
550 if( pRStt->nNode < rRg.aStart )
552 if( pREnd->nNode > rRg.aStart && pREnd->nNode < rRg.aEnd )
554 // Create a copy and set the end of the original to the end of the MoveArea.
555 // The copy is moved too.
556 SwRedline* pNewRedl = new SwRedline( *pTmp );
557 SwPosition* pTmpPos = pNewRedl->Start();
558 pTmpPos->nNode = rRg.aStart;
559 pTmpPos->nContent.Assign(
560 pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
562 _SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
563 rArr.push_back( pSave );
565 pTmpPos = pTmp->End();
566 pTmpPos->nNode = rRg.aEnd;
567 pTmpPos->nContent.Assign(
568 pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
570 else if( pREnd->nNode == rRg.aStart )
572 SwPosition* pTmpPos = pTmp->End();
573 pTmpPos->nNode = rRg.aEnd;
574 pTmpPos->nContent.Assign(
575 pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
578 else if( pRStt->nNode < rRg.aEnd )
580 rRedlTbl.Remove( nRedlPos-- );
581 if( pREnd->nNode < rRg.aEnd ||
582 ( pREnd->nNode == rRg.aEnd && !pREnd->nContent.GetIndex()) )
584 // move everything
585 _SaveRedline* pSave = new _SaveRedline( pTmp, rRg.aStart );
586 rArr.push_back( pSave );
588 else
590 // split
591 SwRedline* pNewRedl = new SwRedline( *pTmp );
592 SwPosition* pTmpPos = pNewRedl->End();
593 pTmpPos->nNode = rRg.aEnd;
594 pTmpPos->nContent.Assign(
595 pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
597 _SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
598 rArr.push_back( pSave );
600 pTmpPos = pTmp->Start();
601 pTmpPos->nNode = rRg.aEnd;
602 pTmpPos->nContent.Assign(
603 pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
604 pDoc->AppendRedline( pTmp, true );
607 else
608 break;
610 } while( ++nRedlPos < pDoc->GetRedlineTbl().size() );
611 pDoc->SetRedlineMode_intern( eOld );
614 static void lcl_RestoreRedlines( SwDoc* pDoc, sal_uInt32 nInsPos, _SaveRedlines& rArr )
616 RedlineMode_t eOld = pDoc->GetRedlineMode();
617 pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
619 for( size_t n = 0; n < rArr.size(); ++n )
621 rArr[ n ].SetPos( nInsPos );
622 pDoc->AppendRedline( rArr[ n ].pRedl, true );
625 pDoc->SetRedlineMode_intern( eOld );
628 // #i59534: Redo of insertion of multiple text nodes runs into trouble
629 // because of unnecessary expanded redlines
630 // From now on this class saves the redline positions of all redlines which ends exact at the
631 // insert position (node _and_ content index)
632 _SaveRedlEndPosForRestore::_SaveRedlEndPosForRestore( const SwNodeIndex& rInsIdx, xub_StrLen nCnt )
633 : pSavArr( 0 ), pSavIdx( 0 ), nSavCntnt( nCnt )
635 SwNode& rNd = rInsIdx.GetNode();
636 SwDoc* pDest = rNd.GetDoc();
637 if( !pDest->GetRedlineTbl().empty() )
639 sal_uInt16 nFndPos;
640 const SwPosition* pEnd;
641 SwPosition aSrcPos( rInsIdx, SwIndex( rNd.GetCntntNode(), nCnt ));
642 const SwRedline* pRedl = pDest->GetRedline( aSrcPos, &nFndPos );
643 while( nFndPos--
644 && *( pEnd = ( pRedl = pDest->GetRedlineTbl()[ nFndPos ] )->End() ) == aSrcPos
645 && *pRedl->Start() < aSrcPos )
647 if( !pSavArr )
649 pSavArr = new std::vector<SwPosition*>;
650 pSavIdx = new SwNodeIndex( rInsIdx, -1 );
652 pSavArr->push_back( (SwPosition*)pEnd );
657 _SaveRedlEndPosForRestore::~_SaveRedlEndPosForRestore()
659 delete pSavArr;
660 delete pSavIdx;
663 void _SaveRedlEndPosForRestore::_Restore()
665 ++(*pSavIdx);
666 SwCntntNode* pNode = pSavIdx->GetNode().GetCntntNode();
667 // If there's no content node at the remembered position, we will not restore the old position
668 // This may happen if a table (or section?) will be inserted.
669 if( pNode )
671 SwPosition aPos( *pSavIdx, SwIndex( pNode, nSavCntnt ));
672 for( sal_uInt16 n = pSavArr->size(); n; )
673 *(*pSavArr)[ --n ] = aPos;
677 /// Delete a full Section of the NodeArray.
678 /// The passed Node is located somewhere in the designated Section.
679 void SwDoc::DeleteSection( SwNode *pNode )
681 OSL_ENSURE( pNode, "Didn't pass a Node." );
682 SwStartNode* pSttNd = pNode->IsStartNode() ? (SwStartNode*)pNode
683 : pNode->StartOfSectionNode();
684 SwNodeIndex aSttIdx( *pSttNd ), aEndIdx( *pNode->EndOfSectionNode() );
686 // delete all Flys, Bookmarks, ...
687 DelFlyInRange( aSttIdx, aEndIdx );
688 DeleteRedline( *pSttNd, true, USHRT_MAX );
689 _DelBookmarks(aSttIdx, aEndIdx);
692 // move all Crsr/StkCrsr/UnoCrsr out of the to-be-deleted area
693 SwNodeIndex aMvStt( aSttIdx, 1 );
694 CorrAbs( aMvStt, aEndIdx, SwPosition( aSttIdx ), sal_True );
697 GetNodes().DelNodes( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() + 1 );
700 void SwDoc::SetModified(SwPaM &rPaM)
702 SwDataChanged aTmp( rPaM );
703 SetModified();
706 bool SwDoc::Overwrite( const SwPaM &rRg, const String &rStr )
708 SwPosition& rPt = *(SwPosition*)rRg.GetPoint();
709 if( mpACEWord ) // Add to AutoCorrect
711 if( 1 == rStr.Len() )
712 mpACEWord->CheckChar( rPt, rStr.GetChar( 0 ) );
713 delete mpACEWord, mpACEWord = 0;
716 SwTxtNode *pNode = rPt.nNode.GetNode().GetTxtNode();
717 if (!pNode || ( static_cast<size_t>(rStr.Len()) // worst case: no erase
718 + static_cast<size_t>(pNode->GetTxt().getLength()) > TXTNODE_MAX))
720 return false;
723 if (GetIDocumentUndoRedo().DoesUndo())
725 GetIDocumentUndoRedo().ClearRedo(); // AppendUndo not always called
728 sal_uInt16 nOldAttrCnt = pNode->GetpSwpHints()
729 ? pNode->GetpSwpHints()->Count() : 0;
730 SwDataChanged aTmp( rRg );
731 SwIndex& rIdx = rPt.nContent;
732 xub_StrLen nStart = 0;
734 bool bOldExpFlg = pNode->IsIgnoreDontExpand();
735 pNode->SetIgnoreDontExpand( true );
737 for( xub_StrLen nCnt = 0; nCnt < rStr.Len(); ++nCnt )
739 // start behind the characters (to fix the attributes!)
740 nStart = rIdx.GetIndex();
741 if (nStart < pNode->GetTxt().getLength())
743 lcl_SkipAttr( pNode, rIdx, nStart );
745 sal_Unicode c = rStr.GetChar( nCnt );
746 if (GetIDocumentUndoRedo().DoesUndo())
748 bool bMerged(false);
749 if (GetIDocumentUndoRedo().DoesGroupUndo())
751 SwUndo *const pUndo = GetUndoManager().GetLastUndo();
752 SwUndoOverwrite *const pUndoOW(
753 dynamic_cast<SwUndoOverwrite *>(pUndo) );
754 if (pUndoOW)
756 // if CanGrouping() returns true it's already merged
757 bMerged = pUndoOW->CanGrouping( this, rPt, c );
760 if (!bMerged)
762 SwUndo *const pUndoOW( new SwUndoOverwrite(this, rPt, c) );
763 GetIDocumentUndoRedo().AppendUndo(pUndoOW);
766 else
768 // start behind the characters (to fix the attributes!)
769 if (nStart < pNode->GetTxt().getLength())
770 ++rIdx;
771 pNode->InsertText( OUString(c), rIdx, INS_EMPTYEXPAND );
772 if( nStart+1 < rIdx.GetIndex() )
774 rIdx = nStart;
775 pNode->EraseText( rIdx, 1 );
776 ++rIdx;
780 pNode->SetIgnoreDontExpand( bOldExpFlg );
782 sal_uInt16 nNewAttrCnt = pNode->GetpSwpHints()
783 ? pNode->GetpSwpHints()->Count() : 0;
784 if( nOldAttrCnt != nNewAttrCnt )
786 SwUpdateAttr aHint( 0, 0, 0 );
787 pNode->ModifyBroadcast( 0, &aHint, TYPE( SwCrsrShell ) );
790 if (!GetIDocumentUndoRedo().DoesUndo() &&
791 !IsIgnoreRedline() && !GetRedlineTbl().empty())
793 SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
794 DeleteRedline( aPam, true, USHRT_MAX );
796 else if( IsRedlineOn() )
798 // FIXME: this redline is WRONG: there is no DELETE, and the skipped
799 // characters are also included in aPam
800 SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
801 AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
804 SetModified();
805 return sal_True;
808 bool SwDoc::MoveAndJoin( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
810 SwNodeIndex aIdx( rPaM.Start()->nNode );
811 sal_Bool bJoinTxt = aIdx.GetNode().IsTxtNode();
812 sal_Bool bOneNode = rPaM.GetPoint()->nNode == rPaM.GetMark()->nNode;
813 aIdx--; // in front of the move area!
815 bool bRet = MoveRange( rPaM, rPos, eMvFlags );
816 if( bRet && !bOneNode )
818 if( bJoinTxt )
819 ++aIdx;
820 SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode();
821 SwNodeIndex aNxtIdx( aIdx );
822 if( pTxtNd && pTxtNd->CanJoinNext( &aNxtIdx ) )
824 { // Block so SwIndex into node is deleted before Join
825 CorrRel( aNxtIdx, SwPosition( aIdx, SwIndex(pTxtNd,
826 pTxtNd->GetTxt().getLength()) ), 0, sal_True );
828 pTxtNd->JoinNext();
831 return bRet;
834 // It seems that this is mostly used by SwDoc internals; the only
835 // way to call this from the outside seems to be the special case in
836 // SwDoc::CopyRange (but I have not managed to actually hit that case).
837 bool SwDoc::MoveRange( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
839 // nothing moved: return
840 const SwPosition *pStt = rPaM.Start(), *pEnd = rPaM.End();
841 if( !rPaM.HasMark() || *pStt >= *pEnd || (*pStt <= rPos && rPos < *pEnd))
842 return false;
844 // Save the paragraph anchored Flys, so that they can be moved.
845 _SaveFlyArr aSaveFlyArr;
846 _SaveFlyInRange( rPaM, rPos.nNode, aSaveFlyArr, 0 != ( DOC_MOVEALLFLYS & eMvFlags ) );
848 // save redlines (if DOC_MOVEREDLINES is used)
849 _SaveRedlines aSaveRedl;
850 if( DOC_MOVEREDLINES & eMvFlags && !GetRedlineTbl().empty() )
852 lcl_SaveRedlines( rPaM, aSaveRedl );
854 // #i17764# unfortunately, code below relies on undos being
855 // in a particular order, and presence of bookmarks
856 // will change this order. Hence, we delete bookmarks
857 // here without undo.
858 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
859 _DelBookmarks(
860 pStt->nNode,
861 pEnd->nNode,
862 NULL,
863 &pStt->nContent,
864 &pEnd->nContent);
868 int bUpdateFtn = sal_False;
869 SwFtnIdxs aTmpFntIdx;
871 SwUndoMove * pUndoMove = 0;
872 if (GetIDocumentUndoRedo().DoesUndo())
874 GetIDocumentUndoRedo().ClearRedo();
875 pUndoMove = new SwUndoMove( rPaM, rPos );
876 pUndoMove->SetMoveRedlines( eMvFlags == DOC_MOVEREDLINES );
878 else
880 bUpdateFtn = lcl_SaveFtn( pStt->nNode, pEnd->nNode, rPos.nNode,
881 GetFtnIdxs(), aTmpFntIdx,
882 &pStt->nContent, &pEnd->nContent );
885 sal_Bool bSplit = sal_False;
886 SwPaM aSavePam( rPos, rPos );
888 // Move the SPoint to the beginning of the range
889 if( rPaM.GetPoint() == pEnd )
890 rPaM.Exchange();
892 // If there is a TextNode before and after the Move, create a JoinNext in the EditShell.
893 SwTxtNode* pSrcNd = rPaM.GetPoint()->nNode.GetNode().GetTxtNode();
894 sal_Bool bCorrSavePam = pSrcNd && pStt->nNode != pEnd->nNode;
896 // If one ore more TextNodes are moved, SwNodes::Move will do a SplitNode.
897 // However, this does not update the cursor. So we create a TextNode to keep
898 // updating the indices. After the Move the Node is optionally deleted.
899 SwTxtNode * pTNd = rPos.nNode.GetNode().GetTxtNode();
900 if( pTNd && rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode &&
901 ( rPos.nContent.GetIndex() || ( pTNd->Len() && bCorrSavePam )) )
903 bSplit = sal_True;
904 xub_StrLen nMkCntnt = rPaM.GetMark()->nContent.GetIndex();
906 std::vector<sal_uLong> aBkmkArr;
907 _SaveCntntIdx( this, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(),
908 aBkmkArr, SAVEFLY_SPLIT );
910 pTNd = static_cast<SwTxtNode*>(pTNd->SplitCntntNode( rPos ));
912 if( !aBkmkArr.empty() )
913 _RestoreCntntIdx( this, aBkmkArr, rPos.nNode.GetIndex()-1, 0, true );
915 // correct the PaM!
916 if( rPos.nNode == rPaM.GetMark()->nNode )
918 rPaM.GetMark()->nNode = rPos.nNode.GetIndex()-1;
919 rPaM.GetMark()->nContent.Assign( pTNd, nMkCntnt );
923 // Put back the Pam by one "content"; so that it's always outside of
924 // the manipulated range.
925 // If there's no content anymore, set it to the StartNode (that's
926 // always there).
927 sal_Bool bNullCntnt = !aSavePam.Move( fnMoveBackward, fnGoCntnt );
928 if( bNullCntnt )
930 aSavePam.GetPoint()->nNode--;
933 // Copy all Bookmarks that are within the Move range into an array,
934 // that saves the positon as an offset.
935 ::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
936 _DelBookmarks(
937 pStt->nNode,
938 pEnd->nNode,
939 &aSaveBkmks,
940 &pStt->nContent,
941 &pEnd->nContent);
943 // If there is no range anymore due to the above deletions (e.g. the
944 // footnotes got deleted), it's still a valid Move!
945 if( *rPaM.GetPoint() != *rPaM.GetMark() )
947 // now do the actual move
948 GetNodes().MoveRange( rPaM, rPos, GetNodes() );
950 // after a MoveRange() the Mark is deleted
951 if ( rPaM.HasMark() ) // => no Move occurred!
953 delete pUndoMove;
954 return false;
957 else
958 rPaM.DeleteMark();
960 OSL_ENSURE( *aSavePam.GetMark() == rPos ||
961 ( aSavePam.GetMark()->nNode.GetNode().GetCntntNode() == NULL ),
962 "PaM was not moved. Aren't there ContentNodes at the beginning/end?" );
963 *aSavePam.GetMark() = rPos;
965 rPaM.SetMark(); // create a Sel. around the new range
966 pTNd = aSavePam.GetNode()->GetTxtNode();
967 if (GetIDocumentUndoRedo().DoesUndo())
969 // correct the SavePam's Content first
970 if( bNullCntnt )
972 aSavePam.GetPoint()->nContent = 0;
975 // The method SwEditShell::Move() merges the TextNode after the Move,
976 // where the rPaM is located.
977 // If the Content was moved to the back and the SavePam's SPoint is
978 // in the next Node, we have to deal with this when saving the Undo object!
979 SwTxtNode * pPamTxtNd = 0;
981 // Is passed to SwUndoMove, which happens when subsequently calling Undo JoinNext.
982 // If it's not possible to call Undo JoinNext here.
983 sal_Bool bJoin = bSplit && pTNd;
984 bCorrSavePam = bCorrSavePam &&
985 0 != ( pPamTxtNd = rPaM.GetNode()->GetTxtNode() )
986 && pPamTxtNd->CanJoinNext()
987 && (*rPaM.GetPoint() <= *aSavePam.GetPoint());
989 // Do two Nodes have to be joined at the SavePam?
990 if( bJoin && pTNd->CanJoinNext() )
992 pTNd->JoinNext();
993 // No temporary Index when using &&.
994 // We probably only want to compare the indices.
995 if( bCorrSavePam && rPaM.GetPoint()->nNode.GetIndex()+1 ==
996 aSavePam.GetPoint()->nNode.GetIndex() )
998 aSavePam.GetPoint()->nContent += pPamTxtNd->Len();
1000 bJoin = sal_False;
1002 else if ( !aSavePam.Move( fnMoveForward, fnGoCntnt ) )
1004 aSavePam.GetPoint()->nNode++;
1007 // The newly inserted range is now inbetween SPoint and GetMark.
1008 pUndoMove->SetDestRange( aSavePam, *rPaM.GetPoint(),
1009 bJoin, bCorrSavePam );
1010 GetIDocumentUndoRedo().AppendUndo( pUndoMove );
1012 else
1014 bool bRemove = true;
1015 // Do two Nodes have to be joined at the SavePam?
1016 if( bSplit && pTNd )
1018 if( pTNd->CanJoinNext())
1020 // Always join next, because <pTNd> has to stay as it is.
1021 // A join previous from its next would more or less delete <pTNd>
1022 pTNd->JoinNext();
1023 bRemove = false;
1026 if( bNullCntnt )
1028 aSavePam.GetPoint()->nNode++;
1029 aSavePam.GetPoint()->nContent.Assign( aSavePam.GetCntntNode(), 0 );
1031 else if( bRemove ) // No move forward after joining with next paragraph
1033 aSavePam.Move( fnMoveForward, fnGoCntnt );
1037 // Insert the Bookmarks back into the Document.
1038 *rPaM.GetMark() = *aSavePam.Start();
1039 for(
1040 ::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
1041 pBkmk != aSaveBkmks.end();
1042 ++pBkmk)
1043 pBkmk->SetInDoc(
1044 this,
1045 rPaM.GetMark()->nNode,
1046 &rPaM.GetMark()->nContent);
1047 *rPaM.GetPoint() = *aSavePam.End();
1049 // Move the Flys to the new position.
1050 _RestFlyInRange( aSaveFlyArr, rPaM.Start()->nNode, &(rPos.nNode) );
1052 // restore redlines (if DOC_MOVEREDLINES is used)
1053 if( !aSaveRedl.empty() )
1055 lcl_RestoreRedlines( this, *aSavePam.Start(), aSaveRedl );
1058 if( bUpdateFtn )
1060 if( !aTmpFntIdx.empty() )
1062 GetFtnIdxs().insert( aTmpFntIdx );
1063 aTmpFntIdx.clear();
1066 GetFtnIdxs().UpdateAllFtn();
1069 SetModified();
1070 return true;
1073 bool SwDoc::MoveNodeRange( SwNodeRange& rRange, SwNodeIndex& rPos,
1074 SwMoveFlags eMvFlags )
1076 // Moves all Nodes to the new position.
1077 // Bookmarks are moved too (currently without Undo support).
1079 // If footnotes are being moved to the special section, remove them now.
1081 // Or else delete the Frames for all footnotes that are being moved
1082 // and have it rebuild after the Move (footnotes can change pages).
1083 // Additionally we have to correct the FtnIdx array's sorting.
1084 int bUpdateFtn = sal_False;
1085 SwFtnIdxs aTmpFntIdx;
1087 SwUndoMove* pUndo = 0;
1088 if ((DOC_CREATEUNDOOBJ & eMvFlags ) && GetIDocumentUndoRedo().DoesUndo())
1090 pUndo = new SwUndoMove( this, rRange, rPos );
1092 else
1094 bUpdateFtn = lcl_SaveFtn( rRange.aStart, rRange.aEnd, rPos,
1095 GetFtnIdxs(), aTmpFntIdx );
1098 _SaveRedlines aSaveRedl;
1099 std::vector<SwRedline*> aSavRedlInsPosArr;
1100 if( DOC_MOVEREDLINES & eMvFlags && !GetRedlineTbl().empty() )
1102 lcl_SaveRedlines( rRange, aSaveRedl );
1104 // Find all RedLines that end at the InsPos.
1105 // These have to be moved back to the "old" position after the Move.
1106 sal_uInt16 nRedlPos = GetRedlinePos( rPos.GetNode(), USHRT_MAX );
1107 if( USHRT_MAX != nRedlPos )
1109 const SwPosition *pRStt, *pREnd;
1110 do {
1111 SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ];
1112 pRStt = pTmp->Start();
1113 pREnd = pTmp->End();
1114 if( pREnd->nNode == rPos && pRStt->nNode < rPos )
1116 aSavRedlInsPosArr.push_back( pTmp );
1118 } while( pRStt->nNode < rPos && ++nRedlPos < GetRedlineTbl().size());
1122 // Copy all Bookmarks that are within the Move range into an array
1123 // that stores all references to positions as an offset.
1124 // The final mapping happens after the Move.
1125 ::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
1126 _DelBookmarks(rRange.aStart, rRange.aEnd, &aSaveBkmks);
1128 // Save the paragraph-bound Flys, so that they can be moved.
1129 _SaveFlyArr aSaveFlyArr;
1130 if( !GetSpzFrmFmts()->empty() )
1131 _SaveFlyInRange( rRange, aSaveFlyArr );
1133 // Set it to before the Position, so that it cannot be moved further.
1134 SwNodeIndex aIdx( rPos, -1 );
1136 SwNodeIndex* pSaveInsPos = 0;
1137 if( pUndo )
1138 pSaveInsPos = new SwNodeIndex( rRange.aStart, -1 );
1140 // move the Nodes
1141 sal_Bool bNoDelFrms = 0 != (DOC_NO_DELFRMS & eMvFlags);
1142 if( GetNodes()._MoveNodes( rRange, GetNodes(), rPos, !bNoDelFrms ) )
1144 ++aIdx; // again back to old position
1145 if( pSaveInsPos )
1146 ++(*pSaveInsPos);
1148 else
1150 aIdx = rRange.aStart;
1151 delete pUndo, pUndo = 0;
1154 // move the Flys to the new position
1155 if( !aSaveFlyArr.empty() )
1156 _RestFlyInRange( aSaveFlyArr, aIdx, NULL );
1158 // Add the Bookmarks back to the Document
1159 for(
1160 ::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
1161 pBkmk != aSaveBkmks.end();
1162 ++pBkmk)
1163 pBkmk->SetInDoc(this, aIdx);
1165 if( !aSavRedlInsPosArr.empty() )
1167 SwNode* pNewNd = &aIdx.GetNode();
1168 for( sal_uInt16 n = 0; n < aSavRedlInsPosArr.size(); ++n )
1170 SwRedline* pTmp = aSavRedlInsPosArr[ n ];
1171 if( GetRedlineTbl().Contains( pTmp ) )
1173 SwPosition* pEnd = pTmp->End();
1174 pEnd->nNode = aIdx;
1175 pEnd->nContent.Assign( pNewNd->GetCntntNode(), 0 );
1180 if( !aSaveRedl.empty() )
1181 lcl_RestoreRedlines( this, aIdx.GetIndex(), aSaveRedl );
1183 if( pUndo )
1185 pUndo->SetDestRange( aIdx, rPos, *pSaveInsPos );
1186 GetIDocumentUndoRedo().AppendUndo(pUndo);
1189 delete pSaveInsPos;
1191 if( bUpdateFtn )
1193 if( !aTmpFntIdx.empty() )
1195 GetFtnIdxs().insert( aTmpFntIdx );
1196 aTmpFntIdx.clear();
1199 GetFtnIdxs().UpdateAllFtn();
1202 SetModified();
1203 return sal_True;
1206 /// Convert list of ranges of whichIds to a corresponding list of whichIds
1207 static std::vector<sal_uInt16> * lcl_RangesToVector(sal_uInt16 * pRanges)
1209 std::vector<sal_uInt16> * pResult = new std::vector<sal_uInt16>();
1211 int i = 0;
1212 while (pRanges[i] != 0)
1214 OSL_ENSURE(pRanges[i+1] != 0, "malformed ranges");
1216 for (sal_uInt16 j = pRanges[i]; j < pRanges[i+1]; j++)
1217 pResult->push_back(j);
1219 i += 2;
1222 return pResult;
1225 static bool lcl_StrLenOverFlow( const SwPaM& rPam )
1227 // If we try to merge two paragraph we have to test if afterwards
1228 // the string doesn't exceed the allowed string length
1229 bool bRet = false;
1230 if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
1232 const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
1233 const SwTxtNode* pEndNd = pEnd->nNode.GetNode().GetTxtNode();
1234 if( (0 != pEndNd) && pStt->nNode.GetNode().IsTxtNode() )
1236 sal_uInt64 nSum = pStt->nContent.GetIndex() +
1237 pEndNd->GetTxt().getLength() - pEnd->nContent.GetIndex();
1238 if( nSum > STRING_LEN )
1239 bRet = true;
1242 return bRet;
1245 void sw_GetJoinFlags( SwPaM& rPam, sal_Bool& rJoinTxt, sal_Bool& rJoinPrev )
1247 rJoinTxt = sal_False;
1248 rJoinPrev = sal_False;
1249 if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
1251 const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
1252 SwTxtNode *pSttNd = pStt->nNode.GetNode().GetTxtNode();
1253 if( pSttNd )
1255 SwTxtNode *pEndNd = pEnd->nNode.GetNode().GetTxtNode();
1256 rJoinTxt = 0 != pEndNd;
1257 if( rJoinTxt )
1259 bool bExchange = pStt == rPam.GetPoint();
1260 if( !pStt->nContent.GetIndex() &&
1261 pEndNd->GetTxt().getLength() != pEnd->nContent.GetIndex())
1262 bExchange = !bExchange;
1263 if( bExchange )
1264 rPam.Exchange();
1265 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");
1276 void sw_JoinText( SwPaM& rPam, sal_Bool bJoinPrev )
1278 SwNodeIndex aIdx( rPam.GetPoint()->nNode );
1279 SwTxtNode *pTxtNd = aIdx.GetNode().GetTxtNode();
1280 SwNodeIndex aOldIdx( aIdx );
1281 SwTxtNode *pOldTxtNd = pTxtNd;
1283 if( pTxtNd && pTxtNd->CanJoinNext( &aIdx ) )
1285 SwDoc* pDoc = rPam.GetDoc();
1286 if( bJoinPrev )
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)
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 ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
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!
1301 /* The GetMarkNode */
1302 if( ( pTxtNd = aIdx.GetNode().GetTxtNode())->HasSwAttrSet() )
1304 const SfxPoolItem* pItem;
1305 if( SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState(
1306 RES_BREAK, sal_False, &pItem ) )
1307 pTxtNd->ResetAttr( RES_BREAK );
1308 if( pTxtNd->HasSwAttrSet() &&
1309 SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState(
1310 RES_PAGEDESC, sal_False, &pItem ) )
1311 pTxtNd->ResetAttr( RES_PAGEDESC );
1314 /* The PointNode */
1315 if( pOldTxtNd->HasSwAttrSet() )
1317 const SfxPoolItem* pItem;
1318 SfxItemSet aSet( pDoc->GetAttrPool(), aBreakSetRange );
1319 const SfxItemSet* pSet = pOldTxtNd->GetpSwAttrSet();
1320 if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
1321 sal_False, &pItem ) )
1322 aSet.Put( *pItem );
1323 if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
1324 sal_False, &pItem ) )
1325 aSet.Put( *pItem );
1326 if( aSet.Count() )
1327 pTxtNd->SetAttr( aSet );
1329 pOldTxtNd->FmtToTxtAttr( pTxtNd );
1331 std::vector<sal_uLong> aBkmkArr;
1332 ::_SaveCntntIdx( pDoc, aOldIdx.GetIndex(),
1333 pOldTxtNd->Len(), aBkmkArr );
1335 SwIndex aAlphaIdx(pTxtNd);
1336 pOldTxtNd->CutText( pTxtNd, aAlphaIdx, SwIndex(pOldTxtNd),
1337 pOldTxtNd->Len() );
1338 SwPosition aAlphaPos( aIdx, aAlphaIdx );
1339 pDoc->CorrRel( rPam.GetPoint()->nNode, aAlphaPos, 0, sal_True );
1341 // move all Bookmarks/TOXMarks
1342 if( !aBkmkArr.empty() )
1343 ::_RestoreCntntIdx( pDoc, aBkmkArr, aIdx.GetIndex() );
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 if( pOldTxtNd == rPam.GetBound( sal_True ).nContent.GetIdxReg() )
1348 rPam.GetBound( sal_True ) = aAlphaPos;
1349 if( pOldTxtNd == rPam.GetBound( sal_False ).nContent.GetIdxReg() )
1350 rPam.GetBound( sal_False ) = aAlphaPos;
1352 // delete the Node, at last!
1353 pDoc->GetNodes().Delete( aOldIdx, 1 );
1355 else
1357 SwTxtNode* pDelNd = aIdx.GetNode().GetTxtNode();
1358 if( pTxtNd->Len() )
1359 pDelNd->FmtToTxtAttr( pTxtNd );
1360 else
1362 /* This case was missed:
1364 <something></something> <-- pTxtNd
1365 <other>ccc</other> <-- pDelNd
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).
1373 std::vector<sal_uInt16> * pShorts =
1374 lcl_RangesToVector(aCharFmtSetRange);
1375 pTxtNd->ResetAttr(*pShorts);
1376 delete pShorts;
1378 if( pDelNd->HasSwAttrSet() )
1380 // only copy the character attributes
1381 SfxItemSet aTmpSet( pDoc->GetAttrPool(), aCharFmtSetRange );
1382 aTmpSet.Put( *pDelNd->GetpSwAttrSet() );
1383 pTxtNd->SetAttr( aTmpSet );
1387 pDoc->CorrRel( aIdx, *rPam.GetPoint(), 0, sal_True );
1388 // #i100466# adjust given <rPam>, if it does not belong to the cursors
1389 if ( pDelNd == rPam.GetBound( sal_True ).nContent.GetIdxReg() )
1391 rPam.GetBound( sal_True ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
1393 if( pDelNd == rPam.GetBound( sal_False ).nContent.GetIdxReg() )
1395 rPam.GetBound( sal_False ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
1397 pTxtNd->JoinNext();
1402 static void
1403 lcl_CalcBreaks( ::std::vector<xub_StrLen> & rBreaks, SwPaM const & rPam )
1405 SwTxtNode const * const pTxtNode(
1406 rPam.End()->nNode.GetNode().GetTxtNode() );
1407 if (!pTxtNode)
1408 return; // left-overlap only possible at end of selection...
1410 const xub_StrLen nStart(rPam.Start()->nContent.GetIndex());
1411 const xub_StrLen nEnd (rPam.End ()->nContent.GetIndex());
1412 if (nEnd == pTxtNode->Len())
1413 return; // paragraph selected until the end
1415 for (xub_StrLen i = nStart; i < nEnd; ++i)
1417 const sal_Unicode c(pTxtNode->GetTxt()[i]);
1418 if ((CH_TXTATR_INWORD == c) || (CH_TXTATR_BREAKWORD == c))
1420 SwTxtAttr const * const pAttr( pTxtNode->GetTxtAttrForCharAt(i) );
1421 if (pAttr && pAttr->GetEnd() && (*pAttr->GetEnd() > nEnd))
1423 OSL_ENSURE(pAttr->HasDummyChar(), "GetTxtAttrForCharAt broken?");
1424 rBreaks.push_back(i);
1430 static bool lcl_DoWithBreaks(SwDoc & rDoc, SwPaM & rPam,
1431 bool (SwDoc::*pFunc)(SwPaM&, bool), const bool bForceJoinNext = false)
1433 ::std::vector<xub_StrLen> Breaks;
1435 lcl_CalcBreaks(Breaks, rPam);
1437 if (!Breaks.size())
1439 return (rDoc.*pFunc)(rPam, bForceJoinNext);
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.
1447 SwPosition const & rSelectionEnd( *rPam.End() );
1449 bool bRet( true );
1450 // iterate from end to start, to avoid invalidating the offsets!
1451 ::std::vector<xub_StrLen>::reverse_iterator iter( Breaks.rbegin() );
1452 SwPaM aPam( rSelectionEnd, rSelectionEnd ); // end node!
1453 SwPosition & rEnd( *aPam.End() );
1454 SwPosition & rStart( *aPam.Start() );
1456 while (iter != Breaks.rend())
1458 rStart.nContent = *iter + 1;
1459 if (rEnd.nContent > rStart.nContent) // check if part is empty
1461 bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext);
1463 rEnd.nContent = *iter;
1464 ++iter;
1467 rStart = *rPam.Start(); // set to original start
1468 if (rEnd.nContent > rStart.nContent) // check if part is empty
1470 bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext);
1473 return bRet;
1476 bool SwDoc::DeleteAndJoinWithRedlineImpl( SwPaM & rPam, const bool )
1478 OSL_ENSURE( IsRedlineOn(), "DeleteAndJoinWithRedline: redline off" );
1481 SwUndoRedlineDelete* pUndo = 0;
1482 RedlineMode_t eOld = GetRedlineMode();
1483 checkRedlining(eOld);
1484 if (GetIDocumentUndoRedo().DoesUndo())
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 (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE ));
1493 GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
1494 pUndo = new SwUndoRedlineDelete( rPam, UNDO_DELETE );
1495 GetIDocumentUndoRedo().AppendUndo(pUndo);
1497 if( *rPam.GetPoint() != *rPam.GetMark() )
1498 AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, rPam ), true);
1499 SetModified();
1501 if( pUndo )
1503 GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
1504 // ??? why the hell is the AppendUndo not below the
1505 // CanGrouping, so this hideous cleanup wouldn't be necessary?
1506 // bah, this is redlining, probably changing this would break it...
1507 if (GetIDocumentUndoRedo().DoesGroupUndo())
1509 SwUndo *const pLastUndo( GetUndoManager().GetLastUndo() );
1510 SwUndoRedlineDelete *const pUndoRedlineDel(
1511 dynamic_cast<SwUndoRedlineDelete*>(pLastUndo) );
1512 if (pUndoRedlineDel)
1514 bool const bMerged = pUndoRedlineDel->CanGrouping(*pUndo);
1515 if (bMerged)
1517 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
1518 SwUndo const*const pDeleted =
1519 GetUndoManager().RemoveLastUndo();
1520 OSL_ENSURE(pDeleted == pUndo,
1521 "DeleteAndJoinWithRedlineImpl: "
1522 "undo removed is not undo inserted?");
1523 delete pDeleted;
1527 //JP 06.01.98: MUSS noch optimiert werden!!!
1528 SetRedlineMode( eOld );
1530 return true;
1534 bool SwDoc::DeleteAndJoinImpl( SwPaM & rPam,
1535 const bool bForceJoinNext )
1537 sal_Bool bJoinTxt, bJoinPrev;
1538 sw_GetJoinFlags( rPam, bJoinTxt, bJoinPrev );
1539 // #i100466#
1540 if ( bForceJoinNext )
1542 bJoinPrev = sal_False;
1546 bool const bSuccess( DeleteRangeImpl( rPam ) );
1547 if (!bSuccess)
1548 return false;
1551 if( bJoinTxt )
1553 sw_JoinText( rPam, bJoinPrev );
1556 return true;
1559 bool SwDoc::DeleteRangeImpl(SwPaM & rPam, const bool)
1561 // Move all cursors out of the deleted range, but first copy the
1562 // passed PaM, because it could be a cursor that would be moved!
1563 SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
1564 ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
1566 bool const bSuccess( DeleteRangeImplImpl( aDelPam ) );
1567 if (bSuccess)
1568 { // now copy position from temp copy to given PaM
1569 *rPam.GetPoint() = *aDelPam.GetPoint();
1572 return bSuccess;
1575 bool SwDoc::DeleteRangeImplImpl(SwPaM & rPam)
1577 SwPosition *pStt = (SwPosition*)rPam.Start(), *pEnd = (SwPosition*)rPam.End();
1579 if( !rPam.HasMark() || *pStt >= *pEnd )
1580 return false;
1582 if( mpACEWord )
1584 // if necessary the saved Word for the exception
1585 if( mpACEWord->IsDeleted() || pStt->nNode != pEnd->nNode ||
1586 pStt->nContent.GetIndex() + 1 != pEnd->nContent.GetIndex() ||
1587 !mpACEWord->CheckDelChar( *pStt ))
1588 delete mpACEWord, mpACEWord = 0;
1592 // Delete all empty TextHints at the Mark's position
1593 SwTxtNode* pTxtNd = rPam.GetMark()->nNode.GetNode().GetTxtNode();
1594 SwpHints* pHts;
1595 if( pTxtNd && 0 != ( pHts = pTxtNd->GetpSwpHints()) && pHts->Count() )
1597 const xub_StrLen *pEndIdx;
1598 xub_StrLen nMkCntPos = rPam.GetMark()->nContent.GetIndex();
1599 for( sal_uInt16 n = pHts->Count(); n; )
1601 const SwTxtAttr* pAttr = (*pHts)[ --n ];
1602 if( nMkCntPos > *pAttr->GetStart() )
1603 break;
1605 if( nMkCntPos == *pAttr->GetStart() &&
1606 0 != (pEndIdx = pAttr->GetEnd()) &&
1607 *pEndIdx == *pAttr->GetStart() )
1608 pTxtNd->DestroyAttr( pHts->Cut( n ) );
1613 // Delete fieldmarks before postits, but let's leave them alone during import.
1614 if (GetIDocumentUndoRedo().DoesUndo() && pStt->nNode == pEnd->nNode && (pEnd->nContent.GetIndex() - pStt->nContent.GetIndex()) == 1)
1616 SwTxtNode* pTxtNd = rPam.Start()->nNode.GetNode().GetTxtNode();
1617 xub_StrLen nIndex = rPam.Start()->nContent.GetIndex();
1618 // We may have a postit here.
1619 if (pTxtNd->GetTxt()[nIndex] == CH_TXTATR_INWORD)
1621 SwTxtAttr* pTxtAttr = pTxtNd->GetTxtAttrForCharAt(nIndex, RES_TXTATR_FIELD);
1622 if (pTxtAttr && pTxtAttr->GetFld().GetFld()->Which() == RES_POSTITFLD)
1624 const SwPostItField* pField = dynamic_cast<const SwPostItField*>(pTxtAttr->GetFld().GetFld());
1625 IDocumentMarkAccess::const_iterator_t ppMark = getIDocumentMarkAccess()->findMark(pField->GetName());
1626 if (ppMark != getIDocumentMarkAccess()->getMarksEnd())
1627 getIDocumentMarkAccess()->deleteMark(ppMark);
1633 // Send DataChanged before deletion, so that we still know
1634 // which objects are in the range.
1635 // Afterwards they could be before/after the Position.
1636 SwDataChanged aTmp( rPam );
1640 if (GetIDocumentUndoRedo().DoesUndo())
1642 GetIDocumentUndoRedo().ClearRedo();
1643 bool bMerged(false);
1644 if (GetIDocumentUndoRedo().DoesGroupUndo())
1646 SwUndo *const pLastUndo( GetUndoManager().GetLastUndo() );
1647 SwUndoDelete *const pUndoDelete(
1648 dynamic_cast<SwUndoDelete *>(pLastUndo) );
1649 if (pUndoDelete)
1651 bMerged = pUndoDelete->CanGrouping( this, rPam );
1652 // if CanGrouping() returns true it's already merged
1655 if (!bMerged)
1657 GetIDocumentUndoRedo().AppendUndo( new SwUndoDelete( rPam ) );
1660 SetModified();
1662 return true;
1665 if( !IsIgnoreRedline() && !GetRedlineTbl().empty() )
1666 DeleteRedline( rPam, true, USHRT_MAX );
1668 // Delete and move all "Flys at the paragraph", which are within the Selection
1669 DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode);
1670 _DelBookmarks(
1671 pStt->nNode,
1672 pEnd->nNode,
1673 NULL,
1674 &pStt->nContent,
1675 &pEnd->nContent);
1677 SwNodeIndex aSttIdx( pStt->nNode );
1678 SwCntntNode * pCNd = aSttIdx.GetNode().GetCntntNode();
1680 do { // middle checked loop!
1681 if( pCNd )
1683 SwTxtNode * pStartTxtNode( pCNd->GetTxtNode() );
1684 if ( pStartTxtNode )
1686 // now move the Content to the new Node
1687 sal_Bool bOneNd = pStt->nNode == pEnd->nNode;
1688 xub_StrLen nLen = ( bOneNd ? pEnd->nContent.GetIndex()
1689 : pCNd->Len() )
1690 - pStt->nContent.GetIndex();
1692 // Don't call again, if already empty
1693 if( nLen )
1695 pStartTxtNode->EraseText( pStt->nContent, nLen );
1697 if( !pStartTxtNode->Len() )
1699 // METADATA: remove reference if empty (consider node deleted)
1700 pStartTxtNode->RemoveMetadataReference();
1704 if( bOneNd ) // that's it
1705 break;
1707 ++aSttIdx;
1709 else
1711 // So that there are no indices left registered when deleted,
1712 // we remove a SwPaM from the Content here.
1713 pStt->nContent.Assign( 0, 0 );
1717 pCNd = pEnd->nNode.GetNode().GetCntntNode();
1718 if( pCNd )
1720 SwTxtNode * pEndTxtNode( pCNd->GetTxtNode() );
1721 if( pEndTxtNode )
1723 // if already empty, don't call again
1724 if( pEnd->nContent.GetIndex() )
1726 SwIndex aIdx( pCNd, 0 );
1727 pEndTxtNode->EraseText( aIdx, pEnd->nContent.GetIndex() );
1729 if( !pEndTxtNode->Len() )
1731 // METADATA: remove reference if empty (consider node deleted)
1732 pEndTxtNode->RemoveMetadataReference();
1736 else
1738 // So that there are no indices left registered when deleted,
1739 // we remove a SwPaM from the Content here.
1740 pEnd->nContent.Assign( 0, 0 );
1744 // if the end is not a content node, delete it as well
1745 sal_uInt32 nEnde = pEnd->nNode.GetIndex();
1746 if( pCNd == NULL )
1747 nEnde++;
1749 if( aSttIdx != nEnde )
1751 // delete the Nodes into the NodesArary
1752 GetNodes().Delete( aSttIdx, nEnde - aSttIdx.GetIndex() );
1755 // If the Node that contained the Cursor has been deleted,
1756 // the Content has to be assigned to the current Content.
1757 pStt->nContent.Assign( pStt->nNode.GetNode().GetCntntNode(),
1758 pStt->nContent.GetIndex() );
1760 // If we deleted across Node boundaries we have to correct the PaM,
1761 // because they are in different Nodes now.
1762 // Also, the Selection is revoked.
1763 *pEnd = *pStt;
1764 rPam.DeleteMark();
1766 } while( false );
1768 if( !IsIgnoreRedline() && !GetRedlineTbl().empty() )
1769 CompressRedlines();
1770 SetModified();
1772 return true;
1775 // #i100466# Add handling of new optional parameter <bForceJoinNext>
1776 bool SwDoc::DeleteAndJoin( SwPaM & rPam,
1777 const bool bForceJoinNext )
1779 if ( lcl_StrLenOverFlow( rPam ) )
1780 return false;
1782 return lcl_DoWithBreaks( *this, rPam, (IsRedlineOn())
1783 ? &SwDoc::DeleteAndJoinWithRedlineImpl
1784 : &SwDoc::DeleteAndJoinImpl,
1785 bForceJoinNext );
1788 bool SwDoc::DeleteRange( SwPaM & rPam )
1790 return lcl_DoWithBreaks( *this, rPam, &SwDoc::DeleteRangeImpl );
1794 static void lcl_syncGrammarError( SwTxtNode &rTxtNode, linguistic2::ProofreadingResult& rResult,
1795 xub_StrLen /*nBeginGrammarCheck*/, const ModelToViewHelper &rConversionMap )
1797 if( rTxtNode.IsGrammarCheckDirty() )
1798 return;
1799 SwGrammarMarkUp* pWrong = rTxtNode.GetGrammarCheck();
1800 linguistic2::SingleProofreadingError* pArray = rResult.aErrors.getArray();
1801 sal_uInt16 i, j = 0;
1802 if( pWrong )
1804 for( i = 0; i < rResult.aErrors.getLength(); ++i )
1806 const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i];
1807 xub_StrLen nStart = (xub_StrLen)rConversionMap.ConvertToModelPosition( rError.nErrorStart ).mnPos;
1808 xub_StrLen nEnd = (xub_StrLen)rConversionMap.ConvertToModelPosition( rError.nErrorStart + rError.nErrorLength ).mnPos;
1809 if( i != j )
1810 pArray[j] = pArray[i];
1811 if( pWrong->LookForEntry( nStart, nEnd ) )
1812 ++j;
1815 if( rResult.aErrors.getLength() > j )
1816 rResult.aErrors.realloc( j );
1819 uno::Any SwDoc::Spell( SwPaM& rPaM,
1820 uno::Reference< XSpellChecker1 > &xSpeller,
1821 sal_uInt16* pPageCnt, sal_uInt16* pPageSt,
1822 bool bGrammarCheck,
1823 SwConversionArgs *pConvArgs ) const
1825 SwPosition* pSttPos = rPaM.Start(), *pEndPos = rPaM.End();
1827 SwSpellArgs *pSpellArgs = 0;
1828 if (pConvArgs)
1830 pConvArgs->SetStart(pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent);
1831 pConvArgs->SetEnd( pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent );
1833 else
1834 pSpellArgs = new SwSpellArgs( xSpeller,
1835 pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent,
1836 pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent,
1837 bGrammarCheck );
1839 sal_uLong nCurrNd = pSttPos->nNode.GetIndex();
1840 sal_uLong nEndNd = pEndPos->nNode.GetIndex();
1842 uno::Any aRet;
1843 if( nCurrNd <= nEndNd )
1845 SwCntntFrm* pCntFrm;
1846 bool bGoOn = true;
1847 while( bGoOn )
1849 SwNode* pNd = GetNodes()[ nCurrNd ];
1850 switch( pNd->GetNodeType() )
1852 case ND_TEXTNODE:
1853 if( 0 != ( pCntFrm = ((SwTxtNode*)pNd)->getLayoutFrm( GetCurrentLayout() )) )
1855 // skip protected and hidden Cells and Flys
1856 if( pCntFrm->IsProtected() )
1858 nCurrNd = pNd->EndOfSectionIndex();
1860 else if( !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
1862 if( pPageCnt && *pPageCnt && pPageSt )
1864 sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
1865 if( !*pPageSt )
1867 *pPageSt = nPageNr;
1868 if( *pPageCnt < *pPageSt )
1869 *pPageCnt = *pPageSt;
1871 long nStat;
1872 if( nPageNr >= *pPageSt )
1873 nStat = nPageNr - *pPageSt + 1;
1874 else
1875 nStat = nPageNr + *pPageCnt - *pPageSt + 1;
1876 ::SetProgressState( nStat, (SwDocShell*)GetDocShell() );
1878 //Spell() changes the pSpellArgs in case an error is found
1879 xub_StrLen nBeginGrammarCheck = 0;
1880 xub_StrLen nEndGrammarCheck = 0;
1881 if( pSpellArgs && pSpellArgs->bIsGrammarCheck)
1883 nBeginGrammarCheck = pSpellArgs->pStartNode == pNd ? pSpellArgs->pStartIdx->GetIndex() : 0;
1884 // if grammar checking starts inside of a sentence the start position has to be adjusted
1885 if( nBeginGrammarCheck )
1887 SwIndex aStartIndex( dynamic_cast< SwTxtNode* >( pNd ), nBeginGrammarCheck );
1888 SwPosition aStart( *pNd, aStartIndex );
1889 SwCursor aCrsr(aStart, 0, false);
1890 SwPosition aOrigPos = *aCrsr.GetPoint();
1891 aCrsr.GoSentence( SwCursor::START_SENT );
1892 if( aOrigPos != *aCrsr.GetPoint() )
1894 nBeginGrammarCheck = aCrsr.GetPoint()->nContent.GetIndex();
1897 nEndGrammarCheck = (pSpellArgs->pEndNode == pNd)
1898 ? pSpellArgs->pEndIdx->GetIndex()
1899 : static_cast<SwTxtNode const*>(pNd)
1900 ->GetTxt().getLength();
1903 xub_StrLen nSpellErrorPosition =
1904 static_cast<SwTxtNode const*>(pNd)->GetTxt().getLength();
1905 if( (!pConvArgs &&
1906 ((SwTxtNode*)pNd)->Spell( pSpellArgs )) ||
1907 ( pConvArgs &&
1908 ((SwTxtNode*)pNd)->Convert( *pConvArgs )))
1910 // Cancel and remember position
1911 pSttPos->nNode = nCurrNd;
1912 pEndPos->nNode = nCurrNd;
1913 nCurrNd = nEndNd;
1914 if( pSpellArgs )
1915 nSpellErrorPosition = pSpellArgs->pStartIdx->GetIndex() > pSpellArgs->pEndIdx->GetIndex() ?
1916 pSpellArgs->pEndIdx->GetIndex() :
1917 pSpellArgs->pStartIdx->GetIndex();
1921 if( pSpellArgs && pSpellArgs->bIsGrammarCheck )
1923 uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( GetGCIterator() );
1924 if (xGCIterator.is())
1926 uno::Reference< lang::XComponent > xDoc( ((SwDocShell*)GetDocShell())->GetBaseModel(), uno::UNO_QUERY );
1927 // Expand the string:
1928 const ModelToViewHelper aConversionMap(*(SwTxtNode*)pNd);
1929 OUString aExpandText = aConversionMap.getViewText();
1931 // get XFlatParagraph to use...
1932 uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *((SwTxtNode*)pNd), aExpandText, aConversionMap );
1934 // get error position of cursor in XFlatParagraph
1935 linguistic2::ProofreadingResult aResult;
1936 sal_Int32 nGrammarErrors;
1939 aConversionMap.ConvertToViewPosition( nBeginGrammarCheck );
1940 aResult = xGCIterator->checkSentenceAtPosition(
1941 xDoc, xFlatPara, aExpandText, lang::Locale(), nBeginGrammarCheck, -1, -1 );
1943 lcl_syncGrammarError( *((SwTxtNode*)pNd), aResult, nBeginGrammarCheck, aConversionMap );
1945 // get suggestions to use for the specific error position
1946 nGrammarErrors = aResult.aErrors.getLength();
1947 // if grammar checking doesn't have any progress then quit
1948 if( aResult.nStartOfNextSentencePosition <= nBeginGrammarCheck )
1949 break;
1950 // prepare next iteration
1951 nBeginGrammarCheck = (xub_StrLen)aResult.nStartOfNextSentencePosition;
1953 while( nSpellErrorPosition > aResult.nBehindEndOfSentencePosition && !nGrammarErrors && aResult.nBehindEndOfSentencePosition < nEndGrammarCheck );
1955 if( nGrammarErrors > 0 && nSpellErrorPosition >= aResult.nBehindEndOfSentencePosition )
1957 aRet <<= aResult;
1958 //put the cursor to the current error
1959 const linguistic2::SingleProofreadingError &rError = aResult.aErrors[0];
1960 nCurrNd = pNd->GetIndex();
1961 pSttPos->nNode = nCurrNd;
1962 pEndPos->nNode = nCurrNd;
1963 pSpellArgs->pStartNode = ((SwTxtNode*)pNd);
1964 pSpellArgs->pEndNode = ((SwTxtNode*)pNd);
1965 pSpellArgs->pStartIdx->Assign(((SwTxtNode*)pNd), (xub_StrLen)aConversionMap.ConvertToModelPosition( rError.nErrorStart ).mnPos );
1966 pSpellArgs->pEndIdx->Assign(((SwTxtNode*)pNd), (xub_StrLen)aConversionMap.ConvertToModelPosition( rError.nErrorStart + rError.nErrorLength ).mnPos );
1967 nCurrNd = nEndNd;
1973 break;
1974 case ND_SECTIONNODE:
1975 if( ( ((SwSectionNode*)pNd)->GetSection().IsProtect() ||
1976 ((SwSectionNode*)pNd)->GetSection().IsHidden() ) )
1977 nCurrNd = pNd->EndOfSectionIndex();
1978 break;
1979 case ND_ENDNODE:
1981 break;
1985 bGoOn = nCurrNd < nEndNd;
1986 ++nCurrNd;
1990 if( !aRet.hasValue() )
1992 if (pConvArgs)
1993 aRet <<= pConvArgs->aConvText;
1994 else
1995 aRet <<= pSpellArgs->xSpellAlt;
1997 delete pSpellArgs;
1999 return aRet;
2002 class SwHyphArgs : public SwInterHyphInfo
2004 const SwNode *pStart;
2005 const SwNode *pEnd;
2006 SwNode *pNode;
2007 sal_uInt16 *pPageCnt;
2008 sal_uInt16 *pPageSt;
2010 sal_uInt32 nNode;
2011 xub_StrLen nPamStart;
2012 xub_StrLen nPamLen;
2014 public:
2015 SwHyphArgs( const SwPaM *pPam, const Point &rPoint,
2016 sal_uInt16* pPageCount, sal_uInt16* pPageStart );
2017 void SetPam( SwPaM *pPam ) const;
2018 inline void SetNode( SwNode *pNew ) { pNode = pNew; }
2019 inline const SwNode *GetNode() const { return pNode; }
2020 inline void SetRange( const SwNode *pNew );
2021 inline void NextNode() { ++nNode; }
2022 inline sal_uInt16 *GetPageCnt() { return pPageCnt; }
2023 inline sal_uInt16 *GetPageSt() { return pPageSt; }
2026 SwHyphArgs::SwHyphArgs( const SwPaM *pPam, const Point &rCrsrPos,
2027 sal_uInt16* pPageCount, sal_uInt16* pPageStart )
2028 : SwInterHyphInfo( rCrsrPos ), pNode(0),
2029 pPageCnt( pPageCount ), pPageSt( pPageStart )
2031 // The following constraints have to be met:
2032 // 1) there is at least one Selection
2033 // 2) SPoint() == Start()
2034 OSL_ENSURE( pPam->HasMark(), "SwDoc::Hyphenate: blowing in the wind");
2035 OSL_ENSURE( *pPam->GetPoint() <= *pPam->GetMark(),
2036 "SwDoc::Hyphenate: New York, New York");
2038 const SwPosition *pPoint = pPam->GetPoint();
2039 nNode = pPoint->nNode.GetIndex();
2041 // Set start
2042 pStart = pPoint->nNode.GetNode().GetTxtNode();
2043 nPamStart = pPoint->nContent.GetIndex();
2045 // Set End and Length
2046 const SwPosition *pMark = pPam->GetMark();
2047 pEnd = pMark->nNode.GetNode().GetTxtNode();
2048 nPamLen = pMark->nContent.GetIndex();
2049 if( pPoint->nNode == pMark->nNode )
2050 nPamLen = nPamLen - pPoint->nContent.GetIndex();
2053 inline void SwHyphArgs::SetRange( const SwNode *pNew )
2055 nStart = pStart == pNew ? nPamStart : 0;
2056 nLen = pEnd == pNew ? nPamLen : STRING_NOTFOUND;
2059 void SwHyphArgs::SetPam( SwPaM *pPam ) const
2061 if( !pNode )
2062 *pPam->GetPoint() = *pPam->GetMark();
2063 else
2065 pPam->GetPoint()->nNode = nNode;
2066 pPam->GetPoint()->nContent.Assign( pNode->GetCntntNode(), nWordStart );
2067 pPam->GetMark()->nNode = nNode;
2068 pPam->GetMark()->nContent.Assign( pNode->GetCntntNode(),
2069 nWordStart + nWordLen );
2070 OSL_ENSURE( nNode == pNode->GetIndex(),
2071 "SwHyphArgs::SetPam: Pam disaster" );
2075 // Returns sal_True if we can proceed.
2076 static bool lcl_HyphenateNode( const SwNodePtr& rpNd, void* pArgs )
2078 // Hyphenate returns true if there is a hyphenation point and sets pPam
2079 SwTxtNode *pNode = rpNd->GetTxtNode();
2080 SwHyphArgs *pHyphArgs = (SwHyphArgs*)pArgs;
2081 if( pNode )
2083 SwCntntFrm* pCntFrm = pNode->getLayoutFrm( pNode->GetDoc()->GetCurrentLayout() );
2084 if( pCntFrm && !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
2086 sal_uInt16 *pPageSt = pHyphArgs->GetPageSt();
2087 sal_uInt16 *pPageCnt = pHyphArgs->GetPageCnt();
2088 if( pPageCnt && *pPageCnt && pPageSt )
2090 sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
2091 if( !*pPageSt )
2093 *pPageSt = nPageNr;
2094 if( *pPageCnt < *pPageSt )
2095 *pPageCnt = *pPageSt;
2097 long nStat = nPageNr >= *pPageSt ? nPageNr - *pPageSt + 1
2098 : nPageNr + *pPageCnt - *pPageSt + 1;
2099 ::SetProgressState( nStat, (SwDocShell*)pNode->GetDoc()->GetDocShell() );
2101 pHyphArgs->SetRange( rpNd );
2102 if( pNode->Hyphenate( *pHyphArgs ) )
2104 pHyphArgs->SetNode( rpNd );
2105 return false;
2109 pHyphArgs->NextNode();
2110 return true;
2113 uno::Reference< XHyphenatedWord > SwDoc::Hyphenate(
2114 SwPaM *pPam, const Point &rCrsrPos,
2115 sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
2117 OSL_ENSURE(this == pPam->GetDoc(), "SwDoc::Hyphenate: strangers in the night");
2119 if( *pPam->GetPoint() > *pPam->GetMark() )
2120 pPam->Exchange();
2122 SwHyphArgs aHyphArg( pPam, rCrsrPos, pPageCnt, pPageSt );
2123 SwNodeIndex aTmpIdx( pPam->GetMark()->nNode, 1 );
2124 GetNodes().ForEach( pPam->GetPoint()->nNode, aTmpIdx,
2125 lcl_HyphenateNode, &aHyphArg );
2126 aHyphArg.SetPam( pPam );
2127 return aHyphArg.GetHyphWord(); // will be set by lcl_HyphenateNode
2130 static bool lcl_GetTokenToParaBreak( String& rStr, String& rRet, bool bRegExpRplc )
2132 bool bRet = false;
2133 if( bRegExpRplc )
2135 xub_StrLen nPos = 0;
2136 OUString sPara("\\n");
2137 while( STRING_NOTFOUND != ( nPos = rStr.Search( sPara, nPos )) )
2139 // Has this been escaped?
2140 if( nPos && '\\' == rStr.GetChar( nPos-1 ))
2142 if( ++nPos >= rStr.Len() )
2143 break;
2145 else
2147 rRet = rStr.Copy( 0, nPos );
2148 rStr.Erase( 0, nPos + sPara.getLength() );
2149 bRet = true;
2150 break;
2154 if( !bRet )
2156 rRet = rStr;
2157 rStr.Erase();
2159 return bRet;
2162 bool SwDoc::ReplaceRange( SwPaM& rPam, const String& rStr,
2163 const bool bRegExReplace )
2165 // unfortunately replace works slightly differently from delete,
2166 // so we cannot use lcl_DoWithBreaks here...
2168 ::std::vector<xub_StrLen> Breaks;
2170 SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
2171 aPam.Normalize(sal_False);
2172 if (aPam.GetPoint()->nNode != aPam.GetMark()->nNode)
2174 aPam.Move(fnMoveBackward);
2176 OSL_ENSURE((aPam.GetPoint()->nNode == aPam.GetMark()->nNode), "invalid pam?");
2178 lcl_CalcBreaks(Breaks, aPam);
2180 while (!Breaks.empty() // skip over prefix of dummy chars
2181 && (aPam.GetMark()->nContent.GetIndex() == *Breaks.begin()) )
2183 // skip!
2184 ++aPam.GetMark()->nContent; // always in bounds if Breaks valid
2185 Breaks.erase(Breaks.begin());
2187 *rPam.Start() = *aPam.GetMark(); // update start of original pam w/ prefix
2189 if (!Breaks.size())
2191 // park aPam somewhere so it does not point to node that is deleted
2192 aPam.DeleteMark();
2193 *aPam.GetPoint() = SwPosition(GetNodes().GetEndOfContent());
2194 return ReplaceRangeImpl(rPam, rStr, bRegExReplace); // original pam!
2197 // Deletion must be split into several parts if the text node
2198 // contains a text attribute with end and with dummy character
2199 // and the selection does not contain the text attribute completely,
2200 // but overlaps its start (left), where the dummy character is.
2202 bool bRet( true );
2203 // iterate from end to start, to avoid invalidating the offsets!
2204 ::std::vector<xub_StrLen>::reverse_iterator iter( Breaks.rbegin() );
2205 OSL_ENSURE(aPam.GetPoint() == aPam.End(), "wrong!");
2206 SwPosition & rEnd( *aPam.End() );
2207 SwPosition & rStart( *aPam.Start() );
2209 // set end of temp pam to original end (undo Move backward above)
2210 rEnd = *rPam.End();
2211 // after first deletion, rEnd will point into the original text node again!
2213 while (iter != Breaks.rend())
2215 rStart.nContent = *iter + 1;
2216 if (rEnd.nContent != rStart.nContent) // check if part is empty
2218 bRet &= (IsRedlineOn())
2219 ? DeleteAndJoinWithRedlineImpl(aPam)
2220 : DeleteAndJoinImpl(aPam, false);
2222 rEnd.nContent = *iter;
2223 ++iter;
2226 rStart = *rPam.Start(); // set to original start
2227 OSL_ENSURE(rEnd.nContent > rStart.nContent, "replace part empty!");
2228 if (rEnd.nContent > rStart.nContent) // check if part is empty
2230 bRet &= ReplaceRangeImpl(aPam, rStr, bRegExReplace);
2233 rPam = aPam; // update original pam (is this required?)
2235 return bRet;
2238 // It's possible to call Replace with a PaM that spans 2 paragraphs:
2239 // search with regex for "$", then replace _all_
2240 bool SwDoc::ReplaceRangeImpl( SwPaM& rPam, const String& rStr,
2241 const bool bRegExReplace )
2243 if( !rPam.HasMark() || *rPam.GetPoint() == *rPam.GetMark() )
2244 return false;
2246 sal_Bool bJoinTxt, bJoinPrev;
2247 sw_GetJoinFlags( rPam, bJoinTxt, bJoinPrev );
2250 // Create a copy of the Cursor in order to move all Pams from
2251 // the other views out of the deletion range.
2252 // Except for itself!
2253 SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
2254 ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
2256 SwPosition *pStt = (SwPosition*)aDelPam.Start(),
2257 *pEnd = (SwPosition*)aDelPam.End();
2258 OSL_ENSURE( pStt->nNode == pEnd->nNode ||
2259 ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() &&
2260 !pEnd->nContent.GetIndex() ),
2261 "invalid range: Point and Mark on different nodes" );
2262 sal_Bool bOneNode = pStt->nNode == pEnd->nNode;
2264 // Own Undo?
2265 String sRepl( rStr );
2266 SwTxtNode* pTxtNd = pStt->nNode.GetNode().GetTxtNode();
2267 xub_StrLen nStt = pStt->nContent.GetIndex(),
2268 nEnd = bOneNode ? pEnd->nContent.GetIndex()
2269 : pTxtNd->GetTxt().getLength();
2271 SwDataChanged aTmp( aDelPam );
2273 if( IsRedlineOn() )
2275 RedlineMode_t eOld = GetRedlineMode();
2276 checkRedlining(eOld);
2277 if (GetIDocumentUndoRedo().DoesUndo())
2279 GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
2281 // If any Redline will change (split!) the node
2282 const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, OUString(), IDocumentMarkAccess::UNO_BOOKMARK );
2284 //JP 06.01.98: MUSS noch optimiert werden!!!
2285 SetRedlineMode(
2286 (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE ));
2288 *aDelPam.GetPoint() = pBkmk->GetMarkPos();
2289 if(pBkmk->IsExpanded())
2290 *aDelPam.GetMark() = pBkmk->GetOtherMarkPos();
2291 getIDocumentMarkAccess()->deleteMark(pBkmk);
2292 pStt = aDelPam.Start();
2293 pTxtNd = pStt->nNode.GetNode().GetTxtNode();
2294 nStt = pStt->nContent.GetIndex();
2297 if( sRepl.Len() )
2299 // Apply the first character's attributes to the ReplaceText
2300 SfxItemSet aSet( GetAttrPool(),
2301 RES_CHRATR_BEGIN, RES_TXTATR_WITHEND_END - 1,
2302 RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
2303 0 );
2304 pTxtNd->GetAttr( aSet, nStt+1, nStt+1 );
2306 aSet.ClearItem( RES_TXTATR_REFMARK );
2307 aSet.ClearItem( RES_TXTATR_TOXMARK );
2308 aSet.ClearItem( RES_TXTATR_CJK_RUBY );
2309 aSet.ClearItem( RES_TXTATR_INETFMT );
2310 aSet.ClearItem( RES_TXTATR_META );
2311 aSet.ClearItem( RES_TXTATR_METAFIELD );
2313 if( aDelPam.GetPoint() != aDelPam.End() )
2314 aDelPam.Exchange();
2316 // Remember the End
2317 SwNodeIndex aPtNd( aDelPam.GetPoint()->nNode, -1 );
2318 xub_StrLen nPtCnt = aDelPam.GetPoint()->nContent.GetIndex();
2320 bool bFirst = true;
2321 String sIns;
2322 while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
2324 InsertString( aDelPam, sIns );
2325 if( bFirst )
2327 SwNodeIndex aMkNd( aDelPam.GetMark()->nNode, -1 );
2328 xub_StrLen nMkCnt = aDelPam.GetMark()->nContent.GetIndex();
2330 SplitNode( *aDelPam.GetPoint(), false );
2332 ++aMkNd;
2333 aDelPam.GetMark()->nNode = aMkNd;
2334 aDelPam.GetMark()->nContent.Assign(
2335 aMkNd.GetNode().GetCntntNode(), nMkCnt );
2336 bFirst = false;
2338 else
2339 SplitNode( *aDelPam.GetPoint(), false );
2341 if( sIns.Len() )
2343 InsertString( aDelPam, sIns );
2346 SwPaM aTmpRange( *aDelPam.GetPoint() );
2347 aTmpRange.SetMark();
2349 ++aPtNd;
2350 aDelPam.GetPoint()->nNode = aPtNd;
2351 aDelPam.GetPoint()->nContent.Assign( aPtNd.GetNode().GetCntntNode(),
2352 nPtCnt);
2353 *aTmpRange.GetMark() = *aDelPam.GetPoint();
2355 RstTxtAttrs( aTmpRange );
2356 InsertItemSet( aTmpRange, aSet, 0 );
2359 if (GetIDocumentUndoRedo().DoesUndo())
2361 SwUndo *const pUndoRD =
2362 new SwUndoRedlineDelete( aDelPam, UNDO_REPLACE );
2363 GetIDocumentUndoRedo().AppendUndo(pUndoRD);
2365 AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDelPam ), true);
2367 *rPam.GetMark() = *aDelPam.GetMark();
2368 if (GetIDocumentUndoRedo().DoesUndo())
2370 *aDelPam.GetPoint() = *rPam.GetPoint();
2371 GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
2373 // If any Redline will change (split!) the node
2374 const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, OUString(), IDocumentMarkAccess::UNO_BOOKMARK );
2376 SwIndex& rIdx = aDelPam.GetPoint()->nContent;
2377 rIdx.Assign( 0, 0 );
2378 aDelPam.GetMark()->nContent = rIdx;
2379 rPam.GetPoint()->nNode = 0;
2380 rPam.GetPoint()->nContent = rIdx;
2381 *rPam.GetMark() = *rPam.GetPoint();
2382 //JP 06.01.98: MUSS noch optimiert werden!!!
2383 SetRedlineMode( eOld );
2385 *rPam.GetPoint() = pBkmk->GetMarkPos();
2386 if(pBkmk->IsExpanded())
2387 *rPam.GetMark() = pBkmk->GetOtherMarkPos();
2388 getIDocumentMarkAccess()->deleteMark(pBkmk);
2390 bJoinTxt = sal_False;
2392 else
2394 if( !IsIgnoreRedline() && GetRedlineTbl().size() )
2395 DeleteRedline( aDelPam, true, USHRT_MAX );
2397 SwUndoReplace* pUndoRpl = 0;
2398 bool const bDoesUndo = GetIDocumentUndoRedo().DoesUndo();
2399 if (bDoesUndo)
2401 pUndoRpl = new SwUndoReplace(aDelPam, sRepl, bRegExReplace);
2402 GetIDocumentUndoRedo().AppendUndo(pUndoRpl);
2404 ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
2406 if( aDelPam.GetPoint() != pStt )
2407 aDelPam.Exchange();
2409 SwNodeIndex aPtNd( pStt->nNode, -1 );
2410 xub_StrLen nPtCnt = pStt->nContent.GetIndex();
2412 // Set the values again, if Frames or footnotes on the Text have been removed.
2413 nStt = nPtCnt;
2414 nEnd = bOneNode ? pEnd->nContent.GetIndex()
2415 : pTxtNd->GetTxt().getLength();
2417 bool bFirst = true;
2418 String sIns;
2419 while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
2421 if (!bFirst || nStt == pTxtNd->GetTxt().getLength())
2423 InsertString( aDelPam, sIns );
2425 else if( nStt < nEnd || sIns.Len() )
2427 pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
2429 SplitNode( *pStt, false);
2430 bFirst = false;
2433 if( bFirst || sIns.Len() )
2435 if (!bFirst || nStt == pTxtNd->GetTxt().getLength())
2437 InsertString( aDelPam, sIns );
2439 else if( nStt < nEnd || sIns.Len() )
2441 pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
2445 *rPam.GetPoint() = *aDelPam.GetMark();
2446 ++aPtNd;
2447 rPam.GetMark()->nNode = aPtNd;
2448 rPam.GetMark()->nContent.Assign( aPtNd.GetNode().GetCntntNode(),
2449 nPtCnt );
2451 if (bJoinTxt)
2453 assert(rPam.GetPoint() == rPam.End());
2454 // move so that SetEnd remembers position after sw_JoinText
2455 rPam.Move(fnMoveBackward);
2457 else if (aDelPam.GetPoint() == pStt) // backward selection?
2459 assert(*rPam.GetMark() <= *rPam.GetPoint());
2460 rPam.Exchange(); // swap so that rPam is backwards
2463 if( pUndoRpl )
2465 pUndoRpl->SetEnd(rPam);
2470 if( bJoinTxt )
2471 sw_JoinText( rPam, bJoinPrev );
2473 SetModified();
2474 return true;
2477 // Save the current values to add them as automatic entries to to AutoCorrect.
2478 void SwDoc::SetAutoCorrExceptWord( SwAutoCorrExceptWord* pNew )
2480 if( pNew != mpACEWord )
2481 delete mpACEWord;
2482 mpACEWord = pNew;
2485 bool SwDoc::DelFullPara( SwPaM& rPam )
2487 const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
2488 const SwNode* pNd = &rStt.nNode.GetNode();
2489 sal_uInt32 nSectDiff = pNd->StartOfSectionNode()->EndOfSectionIndex() -
2490 pNd->StartOfSectionIndex();
2491 sal_uInt32 nNodeDiff = rEnd.nNode.GetIndex() - rStt.nNode.GetIndex();
2493 if ( nSectDiff-2 <= nNodeDiff || IsRedlineOn() ||
2494 /* #i9185# Prevent getting the node after the end node (see below) */
2495 rEnd.nNode.GetIndex() + 1 == GetNodes().Count() )
2497 return sal_False;
2500 // Move hard page brakes to the following Node.
2501 sal_Bool bSavePageBreak = sal_False, bSavePageDesc = sal_False;
2503 /* #i9185# This whould lead to a segmentation fault if not caught above. */
2504 sal_uLong nNextNd = rEnd.nNode.GetIndex() + 1;
2505 SwTableNode *const pTblNd = GetNodes()[ nNextNd ]->GetTableNode();
2507 if( pTblNd && pNd->IsCntntNode() )
2509 SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
2512 const SfxPoolItem *pItem;
2513 const SfxItemSet* pSet = ((SwCntntNode*)pNd)->GetpSwAttrSet();
2514 if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
2515 sal_False, &pItem ) )
2517 pTableFmt->SetFmtAttr( *pItem );
2518 bSavePageDesc = sal_True;
2521 if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
2522 sal_False, &pItem ) )
2524 pTableFmt->SetFmtAttr( *pItem );
2525 bSavePageBreak = sal_True;
2530 bool const bDoesUndo = GetIDocumentUndoRedo().DoesUndo();
2531 if( bDoesUndo )
2533 if( !rPam.HasMark() )
2534 rPam.SetMark();
2535 else if( rPam.GetPoint() == &rStt )
2536 rPam.Exchange();
2537 rPam.GetPoint()->nNode++;
2539 SwCntntNode *pTmpNode = rPam.GetPoint()->nNode.GetNode().GetCntntNode();
2540 rPam.GetPoint()->nContent.Assign( pTmpNode, 0 );
2541 bool bGoNext = (0 == pTmpNode);
2542 pTmpNode = rPam.GetMark()->nNode.GetNode().GetCntntNode();
2543 rPam.GetMark()->nContent.Assign( pTmpNode, 0 );
2545 GetIDocumentUndoRedo().ClearRedo();
2547 SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
2549 SwPosition aTmpPos( *aDelPam.GetPoint() );
2550 if( bGoNext )
2552 pTmpNode = GetNodes().GoNext( &aTmpPos.nNode );
2553 aTmpPos.nContent.Assign( pTmpNode, 0 );
2555 ::PaMCorrAbs( aDelPam, aTmpPos );
2558 SwUndoDelete* pUndo = new SwUndoDelete( aDelPam, sal_True );
2560 *rPam.GetPoint() = *aDelPam.GetPoint();
2561 pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
2562 GetIDocumentUndoRedo().AppendUndo(pUndo);
2564 else
2566 SwNodeRange aRg( rStt.nNode, rEnd.nNode );
2567 if( rPam.GetPoint() != &rEnd )
2568 rPam.Exchange();
2570 // Try to move past the End
2571 if( !rPam.Move( fnMoveForward, fnGoNode ) )
2573 // Fair enough, at the Beginning then
2574 rPam.Exchange();
2575 if( !rPam.Move( fnMoveBackward, fnGoNode ))
2577 OSL_FAIL( "no more Nodes" );
2578 return sal_False;
2581 // move bookmarks, redlines etc.
2582 if (aRg.aStart == aRg.aEnd) // only first CorrAbs variant handles this
2584 CorrAbs( aRg.aStart, *rPam.GetPoint(), 0, sal_True );
2586 else
2588 CorrAbs( aRg.aStart, aRg.aEnd, *rPam.GetPoint(), sal_True );
2591 // What's with Flys?
2593 // If there are FlyFrames left, delete these too
2594 for( sal_uInt16 n = 0; n < GetSpzFrmFmts()->size(); ++n )
2596 SwFrmFmt* pFly = (*GetSpzFrmFmts())[n];
2597 const SwFmtAnchor* pAnchor = &pFly->GetAnchor();
2598 SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
2599 if (pAPos &&
2600 ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
2601 (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
2602 aRg.aStart <= pAPos->nNode && pAPos->nNode <= aRg.aEnd )
2604 DelLayoutFmt( pFly );
2605 --n;
2610 SwCntntNode *pTmpNode = rPam.GetBound( sal_True ).nNode.GetNode().GetCntntNode();
2611 rPam.GetBound( sal_True ).nContent.Assign( pTmpNode, 0 );
2612 pTmpNode = rPam.GetBound( sal_False ).nNode.GetNode().GetCntntNode();
2613 rPam.GetBound( sal_False ).nContent.Assign( pTmpNode, 0 );
2614 GetNodes().Delete( aRg.aStart, nNodeDiff+1 );
2616 rPam.DeleteMark();
2617 SetModified();
2619 return sal_True;
2622 void SwDoc::TransliterateText(
2623 const SwPaM& rPaM,
2624 utl::TransliterationWrapper& rTrans )
2626 SwUndoTransliterate *const pUndo = (GetIDocumentUndoRedo().DoesUndo())
2627 ? new SwUndoTransliterate( rPaM, rTrans )
2628 : 0;
2630 const SwPosition* pStt = rPaM.Start(),
2631 * pEnd = rPaM.End();
2632 sal_uLong nSttNd = pStt->nNode.GetIndex(),
2633 nEndNd = pEnd->nNode.GetIndex();
2634 xub_StrLen nSttCnt = pStt->nContent.GetIndex(),
2635 nEndCnt = pEnd->nContent.GetIndex();
2637 SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
2638 if( pStt == pEnd && pTNd ) // no selection?
2640 // set current word as 'area of effect'
2642 Boundary aBndry;
2643 if( g_pBreakIt->GetBreakIter().is() )
2644 aBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
2645 pTNd->GetTxt(), nSttCnt,
2646 g_pBreakIt->GetLocale( pTNd->GetLang( nSttCnt ) ),
2647 WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/,
2648 sal_True );
2650 if( aBndry.startPos < nSttCnt && nSttCnt < aBndry.endPos )
2652 nSttCnt = (xub_StrLen)aBndry.startPos;
2653 nEndCnt = (xub_StrLen)aBndry.endPos;
2657 if( nSttNd != nEndNd ) // is more than one text node involved?
2659 // iterate over all effected text nodes, the first and the last one
2660 // may be incomplete because the selection starts and/or ends there
2662 SwNodeIndex aIdx( pStt->nNode );
2663 if( nSttCnt )
2665 ++aIdx;
2666 if( pTNd )
2667 pTNd->TransliterateText(
2668 rTrans, nSttCnt, pTNd->GetTxt().getLength(), pUndo);
2671 for( ; aIdx.GetIndex() < nEndNd; ++aIdx )
2673 pTNd = aIdx.GetNode().GetTxtNode();
2674 if (pTNd)
2676 pTNd->TransliterateText(
2677 rTrans, 0, pTNd->GetTxt().getLength(), pUndo);
2681 if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
2682 pTNd->TransliterateText( rTrans, 0, nEndCnt, pUndo );
2684 else if( pTNd && nSttCnt < nEndCnt )
2685 pTNd->TransliterateText( rTrans, nSttCnt, nEndCnt, pUndo );
2687 if( pUndo )
2689 if( pUndo->HasData() )
2691 GetIDocumentUndoRedo().AppendUndo(pUndo);
2693 else
2694 delete pUndo;
2696 SetModified();
2699 #define MAX_REDLINE_COUNT 250
2701 void SwDoc::checkRedlining(RedlineMode_t& _rReadlineMode)
2703 const SwRedlineTbl& rRedlineTbl = GetRedlineTbl();
2704 SwEditShell* pEditShell = GetEditShell();
2705 Window* pParent = pEditShell ? pEditShell->GetWin() : NULL;
2706 if ( pParent && !mbReadlineChecked && rRedlineTbl.size() > MAX_REDLINE_COUNT
2707 && !((_rReadlineMode & nsRedlineMode_t::REDLINE_SHOW_DELETE) == nsRedlineMode_t::REDLINE_SHOW_DELETE) )
2709 WarningBox aWarning( pParent,SW_RES(MSG_DISABLE_READLINE_QUESTION));
2710 sal_uInt16 nResult = aWarning.Execute();
2711 mbReadlineChecked = sal_True;
2712 if ( nResult == RET_YES )
2714 sal_Int32 nMode = (sal_Int32)_rReadlineMode;
2715 nMode |= nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE;
2716 _rReadlineMode = (RedlineMode_t)nMode;
2721 void SwDoc::CountWords( const SwPaM& rPaM, SwDocStat& rStat ) const
2723 // This is a modified version of SwDoc::TransliterateText
2724 const SwPosition* pStt = rPaM.Start();
2725 const SwPosition* pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
2726 : rPaM.GetPoint();
2728 const sal_uLong nSttNd = pStt->nNode.GetIndex();
2729 const sal_uLong nEndNd = pEnd->nNode.GetIndex();
2731 const xub_StrLen nSttCnt = pStt->nContent.GetIndex();
2732 const xub_StrLen nEndCnt = pEnd->nContent.GetIndex();
2734 const SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
2735 if( pStt == pEnd && pTNd ) // no region ?
2737 // do nothing
2738 return;
2741 if( nSttNd != nEndNd )
2743 SwNodeIndex aIdx( pStt->nNode );
2744 if( nSttCnt )
2746 ++aIdx;
2747 if( pTNd )
2748 pTNd->CountWords( rStat, nSttCnt, pTNd->GetTxt().getLength() );
2751 for( ; aIdx.GetIndex() < nEndNd; ++aIdx )
2752 if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() ))
2753 pTNd->CountWords( rStat, 0, pTNd->GetTxt().getLength() );
2755 if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
2756 pTNd->CountWords( rStat, 0, nEndCnt );
2758 else if( pTNd && nSttCnt < nEndCnt )
2759 pTNd->CountWords( rStat, nSttCnt, nEndCnt );
2762 void SwDoc::RemoveLeadingWhiteSpace(const SwPosition & rPos )
2764 const SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode();
2765 if ( pTNd )
2767 const OUString& rTxt = pTNd->GetTxt();
2768 xub_StrLen nIdx = 0;
2769 while (nIdx < rTxt.getLength())
2771 sal_Unicode const cCh = rTxt[nIdx];
2772 if (('\t' != cCh) && (' ' != cCh))
2774 break;
2776 ++nIdx;
2779 if ( nIdx > 0 )
2781 SwPaM aPam(rPos);
2782 aPam.GetPoint()->nContent = 0;
2783 aPam.SetMark();
2784 aPam.GetMark()->nContent = nIdx;
2785 DeleteRange( aPam );
2790 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */