Update ooo320-m1
[ooovba.git] / sw / source / core / doc / docedt.cxx
blobf741f2fc041f3500a1bb8b554dbc7313329b1f30
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: docedt.cxx,v $
10 * $Revision: 1.48 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
34 #include <string.h> // fuer strchr()
35 #include <hintids.hxx>
37 #include <vcl/sound.hxx>
38 #include <svx/cscoitem.hxx>
39 #include <svx/brkitem.hxx>
40 #include <linguistic/lngprops.hxx>
41 #include <com/sun/star/beans/XPropertySet.hpp>
42 #include <com/sun/star/i18n/WordType.hdl>
43 #include <unotools/charclass.hxx>
44 #include <fmtanchr.hxx>
45 #include <fmtcntnt.hxx>
46 #include <fmtpdsc.hxx>
47 #include <txtftn.hxx>
48 #include <acorrect.hxx> // Autokorrektur
49 #include <IMark.hxx> // fuer SwBookmark
50 #include <cntfrm.hxx> // fuers Spell
51 #include <crsrsh.hxx>
52 #include <doc.hxx>
53 #include <docsh.hxx>
54 #include <docary.hxx>
55 #include <doctxm.hxx> // beim Move: Verzeichnisse korrigieren
56 #include <ftnidx.hxx>
57 #include <ftninfo.hxx>
58 #include <mdiexp.hxx> // Statusanzeige
59 #include <mvsave.hxx> // Strukturen zum Sichern beim Move/Delete
60 #include <ndtxt.hxx>
61 #include <pam.hxx>
62 #include <redline.hxx>
63 #include <rootfrm.hxx> // fuers UpdateFtn
64 #include <splargs.hxx> // fuer Spell
65 #include <swtable.hxx>
66 #include <swundo.hxx> // fuer die UndoIds
67 #include <txtfrm.hxx>
68 #include <undobj.hxx>
69 #include <breakit.hxx>
70 #include <hhcwrp.hxx>
71 #include <breakit.hxx>
72 #include <vcl/msgbox.hxx>
73 #include "comcore.hrc"
74 #include "editsh.hxx"
75 #include <unoflatpara.hxx>
76 #include <SwGrammarMarkUp.hxx>
78 using ::rtl::OUString;
79 using namespace ::com::sun::star;
80 using namespace ::com::sun::star::linguistic2;
81 using namespace ::com::sun::star::i18n;
83 //using namespace ::utl;
84 #ifndef S2U
85 #define S2U(rString) OUString::createFromAscii(rString)
86 #endif
88 struct _SaveRedline
90 SwRedline* pRedl;
91 sal_uInt32 nStt, nEnd;
92 xub_StrLen nSttCnt, nEndCnt;
94 _SaveRedline( SwRedline* pR, const SwNodeIndex& rSttIdx )
95 : pRedl( pR )
97 const SwPosition* pStt = pR->Start(),
98 * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
99 sal_uInt32 nSttIdx = rSttIdx.GetIndex();
100 nStt = pStt->nNode.GetIndex() - nSttIdx;
101 nSttCnt = pStt->nContent.GetIndex();
102 if( pR->HasMark() )
104 nEnd = pEnd->nNode.GetIndex() - nSttIdx;
105 nEndCnt = pEnd->nContent.GetIndex();
108 pRedl->GetPoint()->nNode = 0;
109 pRedl->GetPoint()->nContent.Assign( 0, 0 );
110 pRedl->GetMark()->nNode = 0;
111 pRedl->GetMark()->nContent.Assign( 0, 0 );
114 _SaveRedline( SwRedline* pR, const SwPosition& rPos )
115 : pRedl( pR )
117 const SwPosition* pStt = pR->Start(),
118 * pEnd = pR->GetMark() == pStt ? pR->GetPoint() : pR->GetMark();
119 sal_uInt32 nSttIdx = rPos.nNode.GetIndex();
120 nStt = pStt->nNode.GetIndex() - nSttIdx;
121 nSttCnt = pStt->nContent.GetIndex();
122 if( nStt == 0 )
123 nSttCnt = nSttCnt - rPos.nContent.GetIndex();
124 if( pR->HasMark() )
126 nEnd = pEnd->nNode.GetIndex() - nSttIdx;
127 nEndCnt = pEnd->nContent.GetIndex();
128 if( nEnd == 0 )
129 nEndCnt = nEndCnt - rPos.nContent.GetIndex();
132 pRedl->GetPoint()->nNode = 0;
133 pRedl->GetPoint()->nContent.Assign( 0, 0 );
134 pRedl->GetMark()->nNode = 0;
135 pRedl->GetMark()->nContent.Assign( 0, 0 );
138 void SetPos( sal_uInt32 nInsPos )
140 pRedl->GetPoint()->nNode = nInsPos + nStt;
141 pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt );
142 if( pRedl->HasMark() )
144 pRedl->GetMark()->nNode = nInsPos + nEnd;
145 pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(sal_False), nEndCnt );
149 void SetPos( const SwPosition& aPos )
151 pRedl->GetPoint()->nNode = aPos.nNode.GetIndex() + nStt;
152 pRedl->GetPoint()->nContent.Assign( pRedl->GetCntntNode(), nSttCnt + ( nStt == 0 ? aPos.nContent.GetIndex() : 0 ) );
153 if( pRedl->HasMark() )
155 pRedl->GetMark()->nNode = aPos.nNode.GetIndex() + nEnd;
156 pRedl->GetMark()->nContent.Assign( pRedl->GetCntntNode(sal_False), nEndCnt + ( nEnd == 0 ? aPos.nContent.GetIndex() : 0 ) );
161 SV_DECL_PTRARR_DEL( _SaveRedlines, _SaveRedline*, 0, 4 )
163 SV_IMPL_VARARR( _SaveFlyArr, _SaveFly )
164 SV_IMPL_PTRARR( _SaveRedlines, _SaveRedline* )
166 bool lcl_MayOverwrite( const SwTxtNode *pNode, const xub_StrLen nPos )
168 sal_Unicode cChr = pNode->GetTxt().GetChar( nPos );
169 return !( ( CH_TXTATR_BREAKWORD == cChr || CH_TXTATR_INWORD == cChr ) &&
170 (0 != pNode->GetTxtAttrForCharAt( nPos ) ) );
173 void lcl_SkipAttr( const SwTxtNode *pNode, SwIndex &rIdx, xub_StrLen &rStart )
175 if( !lcl_MayOverwrite( pNode, rStart ) )
177 // ueberspringe alle SonderAttribute
178 do {
179 // "Beep" bei jedem ausgelassenen
180 Sound::Beep(SOUND_ERROR);
181 rIdx++;
182 } while( (rStart = rIdx.GetIndex()) < pNode->GetTxt().Len()
183 && !lcl_MayOverwrite(pNode, rStart) );
187 // -----------------------------------------------------------------
189 void _RestFlyInRange( _SaveFlyArr & rArr, const SwNodeIndex& rSttIdx,
190 const SwNodeIndex* pInsertPos )
192 SwPosition aPos( rSttIdx );
193 for( sal_uInt16 n = 0; n < rArr.Count(); ++n )
195 // neuen Anker anlegen
196 _SaveFly& rSave = rArr[n];
197 SwFrmFmt* pFmt = rSave.pFrmFmt;
199 if( rSave.bInsertPosition )
201 if( pInsertPos != NULL )
202 aPos.nNode = *pInsertPos;
203 else
204 aPos.nNode = rSttIdx.GetIndex();
206 else
207 aPos.nNode = rSttIdx.GetIndex() + rSave.nNdDiff;
209 aPos.nContent.Assign( 0, 0 );
210 SwFmtAnchor aAnchor( pFmt->GetAnchor() );
211 aAnchor.SetAnchor( &aPos );
212 pFmt->GetDoc()->GetSpzFrmFmts()->Insert(
213 pFmt, pFmt->GetDoc()->GetSpzFrmFmts()->Count() );
214 pFmt->SetFmtAttr( aAnchor );
215 SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode();
216 if( pCNd && pCNd->GetFrm( 0, 0, sal_False ) )
217 pFmt->MakeFrms();
221 void _SaveFlyInRange( const SwNodeRange& rRg, _SaveFlyArr& rArr )
223 SwFrmFmt* pFmt;
224 const SwFmtAnchor* pAnchor;
225 const SwPosition* pAPos;
226 SwSpzFrmFmts& rFmts = *rRg.aStart.GetNode().GetDoc()->GetSpzFrmFmts();
227 for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
229 pFmt = (SwFrmFmt*)rFmts[n];
230 pAnchor = &pFmt->GetAnchor();
231 if( ( FLY_AT_CNTNT == pAnchor->GetAnchorId() ||
232 FLY_AUTO_CNTNT == pAnchor->GetAnchorId() ) &&
233 0 != ( pAPos = pAnchor->GetCntntAnchor() ) &&
234 rRg.aStart <= pAPos->nNode && pAPos->nNode < rRg.aEnd )
236 _SaveFly aSave( pAPos->nNode.GetIndex() - rRg.aStart.GetIndex(),
237 pFmt, sal_False );
238 rArr.Insert( aSave, rArr.Count());
239 pFmt->DelFrms();
240 rFmts.Remove( n--, 1 );
245 void _SaveFlyInRange( const SwPaM& rPam, const SwNodeIndex& rInsPos,
246 _SaveFlyArr& rArr, bool bMoveAllFlys )
248 SwSpzFrmFmts& rFmts = *rPam.GetPoint()->nNode.GetNode().GetDoc()->GetSpzFrmFmts();
249 SwFrmFmt* pFmt;
250 const SwFmtAnchor* pAnchor;
252 const SwPosition* pPos = rPam.Start();
253 const SwNodeIndex& rSttNdIdx = pPos->nNode;
254 short nSttOff = (!bMoveAllFlys && rSttNdIdx.GetNode().IsCntntNode() &&
255 pPos->nContent.GetIndex()) ? 1 : 0;
257 pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint();
258 const SwNodeIndex& rEndNdIdx = pPos->nNode;
259 short nOff = ( bMoveAllFlys || ( rEndNdIdx.GetNode().IsCntntNode() &&
260 pPos->nContent == rEndNdIdx.GetNode().GetCntntNode()->Len() ))
261 ? 0 : 1;
263 const SwPosition* pAPos;
264 const SwNodeIndex* pCntntIdx;
266 for( sal_uInt16 n = 0; n < rFmts.Count(); ++n )
268 sal_Bool bInsPos = sal_False;
269 pFmt = (SwFrmFmt*)rFmts[n];
270 pAnchor = &pFmt->GetAnchor();
271 if( ( FLY_AT_CNTNT == pAnchor->GetAnchorId() ||
272 FLY_AUTO_CNTNT == pAnchor->GetAnchorId() ) &&
273 0 != ( pAPos = pAnchor->GetCntntAnchor() ) &&
274 // nicht verschieben, wenn die InsPos im CntntBereich vom Fly ist
275 ( 0 == ( pCntntIdx = pFmt->GetCntnt().GetCntntIdx() ) ||
276 !( *pCntntIdx < rInsPos &&
277 rInsPos < pCntntIdx->GetNode().EndOfSectionIndex() )) )
279 if( !bMoveAllFlys && rEndNdIdx == pAPos->nNode )
281 // wenn nur teil vom EndNode oder der EndNode und SttNode
282 // identisch sind, chaos::Anchor nicht anfassen
283 if( rSttNdIdx != pAPos->nNode )
285 // Anker nur an Anfang/Ende haengen
286 SwPosition aPos( rSttNdIdx );
287 SwFmtAnchor aAnchor( *pAnchor );
288 aAnchor.SetAnchor( &aPos );
289 pFmt->SetFmtAttr( aAnchor );
290 // ((SwFmtAnchor*)pAnchor)->SetAnchor( &aPos );
293 else if( ( rSttNdIdx.GetIndex() + nSttOff <= pAPos->nNode.GetIndex()
294 && pAPos->nNode.GetIndex() <= rEndNdIdx.GetIndex() - nOff ) ||
295 0 != ( bInsPos = rInsPos == pAPos->nNode ))
298 _SaveFly aSave( pAPos->nNode.GetIndex() - rSttNdIdx.GetIndex(),
299 pFmt, bInsPos );
300 rArr.Insert( aSave, rArr.Count());
301 pFmt->DelFrms();
302 rFmts.Remove( n--, 1 );
308 // -----------------------------------------------------------------
310 // loesche und verschiebe alle "Fly's am Absatz", die in der SSelection
311 // liegen. Steht am SPoint ein Fly, wird dieser auf den Mark verschoben.
313 void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
314 const SwNodeIndex& rPtNdIdx )
316 const sal_Bool bDelFwrd = rMkNdIdx.GetIndex() <= rPtNdIdx.GetIndex();
318 SwDoc* pDoc = rMkNdIdx.GetNode().GetDoc();
319 SwSpzFrmFmts& rTbl = *pDoc->GetSpzFrmFmts();
320 const SwPosition* pAPos;
321 for ( sal_uInt16 i = rTbl.Count(); i; )
323 SwFrmFmt *pFmt = rTbl[--i];
324 const SwFmtAnchor &rAnch = pFmt->GetAnchor();
325 if( ( rAnch.GetAnchorId() == FLY_AT_CNTNT ||
326 rAnch.GetAnchorId() == FLY_AUTO_CNTNT ) &&
327 0 != ( pAPos = rAnch.GetCntntAnchor() ) &&
328 ( bDelFwrd
329 ? rMkNdIdx < pAPos->nNode && pAPos->nNode <= rPtNdIdx
330 : rPtNdIdx <= pAPos->nNode && pAPos->nNode < rMkNdIdx ))
332 // nur den Anker verschieben ??
333 if( rPtNdIdx == pAPos->nNode )
335 SwFmtAnchor aAnch( pFmt->GetAnchor() );
336 SwPosition aPos( rMkNdIdx );
337 aAnch.SetAnchor( &aPos );
338 pFmt->SetFmtAttr( aAnch );
340 else
342 // wird der Fly geloescht muss auch im seinem Inhalt alle
343 // Flys geloescht werden !!
344 const SwFmtCntnt &rCntnt = pFmt->GetCntnt();
345 if( rCntnt.GetCntntIdx() )
347 DelFlyInRange( *rCntnt.GetCntntIdx(),
348 SwNodeIndex( *rCntnt.GetCntntIdx()->
349 GetNode().EndOfSectionNode() ));
350 // Position kann sich verschoben haben !
351 if( i > rTbl.Count() )
352 i = rTbl.Count();
353 else if( pFmt != rTbl[i] )
354 i = rTbl.GetPos( pFmt );
357 pDoc->DelLayoutFmt( pFmt );
359 // --> FME 2004-10-06 #117913# DelLayoutFmt can also
360 // trigger the deletion of objects.
361 if( i > rTbl.Count() )
362 i = rTbl.Count();
363 // <--
370 bool lcl_SaveFtn( const SwNodeIndex& rSttNd, const SwNodeIndex& rEndNd,
371 const SwNodeIndex& rInsPos,
372 SwFtnIdxs& rFtnArr, SwFtnIdxs& rSaveArr,
373 const SwIndex* pSttCnt = 0, const SwIndex* pEndCnt = 0 )
375 bool bUpdateFtn = sal_False;
376 const SwNodes& rNds = rInsPos.GetNodes();
377 const bool bDelFtn = rInsPos.GetIndex() < rNds.GetEndOfAutotext().GetIndex() &&
378 rSttNd.GetIndex() >= rNds.GetEndOfAutotext().GetIndex();
379 const bool bSaveFtn = !bDelFtn &&
380 rInsPos.GetIndex() >= rNds.GetEndOfExtras().GetIndex();
381 if( rFtnArr.Count() )
384 sal_uInt16 nPos;
385 rFtnArr.SeekEntry( rSttNd, &nPos );
386 SwTxtFtn* pSrch;
387 const SwNode* pFtnNd;
389 // loesche/sicher erstmal alle, die dahinter stehen
390 while( nPos < rFtnArr.Count() && ( pFtnNd =
391 &( pSrch = rFtnArr[ nPos ] )->GetTxtNode())->GetIndex()
392 <= rEndNd.GetIndex() )
394 xub_StrLen nFtnSttIdx = *pSrch->GetStart();
395 if( ( pEndCnt && pSttCnt )
396 ? (( &rSttNd.GetNode() == pFtnNd &&
397 pSttCnt->GetIndex() > nFtnSttIdx) ||
398 ( &rEndNd.GetNode() == pFtnNd &&
399 nFtnSttIdx >= pEndCnt->GetIndex() ))
400 : ( &rEndNd.GetNode() == pFtnNd ))
402 ++nPos; // weiter suchen
404 else
406 // dann weg damit
407 if( bDelFtn )
409 SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
410 SwIndex aIdx( &rTxtNd, nFtnSttIdx );
411 rTxtNd.EraseText( aIdx, 1 );
413 else
415 pSrch->DelFrms();
416 rFtnArr.Remove( nPos );
417 if( bSaveFtn )
418 rSaveArr.Insert( pSrch );
420 bUpdateFtn = sal_True;
424 while( nPos-- && ( pFtnNd = &( pSrch = rFtnArr[ nPos ] )->
425 GetTxtNode())->GetIndex() >= rSttNd.GetIndex() )
427 xub_StrLen nFtnSttIdx = *pSrch->GetStart();
428 if( !pEndCnt || !pSttCnt ||
429 !( (( &rSttNd.GetNode() == pFtnNd &&
430 pSttCnt->GetIndex() > nFtnSttIdx ) ||
431 ( &rEndNd.GetNode() == pFtnNd &&
432 nFtnSttIdx >= pEndCnt->GetIndex() )) ))
434 if( bDelFtn )
436 // dann weg damit
437 SwTxtNode& rTxtNd = (SwTxtNode&)pSrch->GetTxtNode();
438 SwIndex aIdx( &rTxtNd, nFtnSttIdx );
439 rTxtNd.EraseText( aIdx, 1 );
441 else
443 pSrch->DelFrms();
444 rFtnArr.Remove( nPos );
445 if( bSaveFtn )
446 rSaveArr.Insert( pSrch );
448 bUpdateFtn = sal_True;
452 // When moving from redline section into document content section, e.g.
453 // after loading a document with (delete-)redlines, the footnote array
454 // has to be adjusted... (#i70572)
455 if( bSaveFtn )
457 SwNodeIndex aIdx( rSttNd );
458 while( aIdx < rEndNd ) // Check the moved section
460 SwNode* pNode = &aIdx.GetNode();
461 if( pNode->IsTxtNode() ) // Looking for text nodes...
463 SwpHints *pHints =
464 static_cast<SwTxtNode*>(pNode)->GetpSwpHints();
465 if( pHints && pHints->HasFtn() ) //...with footnotes
467 bUpdateFtn = sal_True; // Heureka
468 USHORT nCount = pHints->Count();
469 for( USHORT i = 0; i < nCount; ++i )
471 SwTxtAttr *pAttr = pHints->GetTextHint( i );
472 if ( pAttr->Which() == RES_TXTATR_FTN )
474 rSaveArr.Insert( static_cast<SwTxtFtn*>(pAttr) );
479 ++aIdx;
482 return bUpdateFtn;
485 void lcl_SaveRedlines( const SwPaM& aPam, _SaveRedlines& rArr )
487 SwDoc* pDoc = aPam.GetNode()->GetDoc();
489 const SwPosition* pStart = aPam.Start();
490 const SwPosition* pEnd = aPam.End();
492 // get first relevant redline
493 sal_uInt16 nCurrentRedline;
494 pDoc->GetRedline( *pStart, &nCurrentRedline );
495 if( nCurrentRedline > 0)
496 nCurrentRedline--;
498 // redline mode REDLINE_IGNORE|REDLINE_ON; save old mode
499 RedlineMode_t eOld = pDoc->GetRedlineMode();
500 pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
502 // iterate over relevant redlines and decide for each whether it should
503 // be saved, or split + saved
504 SwRedlineTbl& rRedlineTable = const_cast<SwRedlineTbl&>( pDoc->GetRedlineTbl() );
505 for( ; nCurrentRedline < rRedlineTable.Count(); nCurrentRedline++ )
507 SwRedline* pCurrent = rRedlineTable[ nCurrentRedline ];
508 SwComparePosition eCompare =
509 ComparePosition( *pCurrent->Start(), *pCurrent->End(),
510 *pStart, *pEnd);
512 // we must save this redline if it overlaps aPam
513 // (we may have to split it, too)
514 if( eCompare == POS_OVERLAP_BEHIND ||
515 eCompare == POS_OVERLAP_BEFORE ||
516 eCompare == POS_OUTSIDE ||
517 eCompare == POS_INSIDE ||
518 eCompare == POS_EQUAL )
520 rRedlineTable.Remove( nCurrentRedline-- );
522 // split beginning, if necessary
523 if( eCompare == POS_OVERLAP_BEFORE ||
524 eCompare == POS_OUTSIDE )
527 SwRedline* pNewRedline = new SwRedline( *pCurrent );
528 *pNewRedline->End() = *pStart;
529 *pCurrent->Start() = *pStart;
530 pDoc->AppendRedline( pNewRedline, true );
533 // split end, if necessary
534 if( eCompare == POS_OVERLAP_BEHIND ||
535 eCompare == POS_OUTSIDE )
537 SwRedline* pNewRedline = new SwRedline( *pCurrent );
538 *pNewRedline->Start() = *pEnd;
539 *pCurrent->End() = *pEnd;
540 pDoc->AppendRedline( pNewRedline, true );
543 // save the current redline
544 _SaveRedline* pSave = new _SaveRedline( pCurrent, *pStart );
545 rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
549 // restore old redline mode
550 pDoc->SetRedlineMode_intern( eOld );
553 void lcl_RestoreRedlines( SwDoc* pDoc, const SwPosition& rPos, _SaveRedlines& rArr )
555 RedlineMode_t eOld = pDoc->GetRedlineMode();
556 pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
558 for( sal_uInt16 n = 0; n < rArr.Count(); ++n )
560 _SaveRedline* pSave = rArr[ n ];
561 pSave->SetPos( rPos );
562 pDoc->AppendRedline( pSave->pRedl, true );
565 pDoc->SetRedlineMode_intern( eOld );
569 void lcl_SaveRedlines( const SwNodeRange& rRg, _SaveRedlines& rArr )
571 SwDoc* pDoc = rRg.aStart.GetNode().GetDoc();
572 sal_uInt16 nRedlPos;
573 SwPosition aSrchPos( rRg.aStart ); aSrchPos.nNode--;
574 aSrchPos.nContent.Assign( aSrchPos.nNode.GetNode().GetCntntNode(), 0 );
575 if( pDoc->GetRedline( aSrchPos, &nRedlPos ) && nRedlPos )
576 --nRedlPos;
577 else if( nRedlPos >= pDoc->GetRedlineTbl().Count() )
578 return ;
580 RedlineMode_t eOld = pDoc->GetRedlineMode();
581 pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
582 SwRedlineTbl& rRedlTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl();
584 do {
585 SwRedline* pTmp = rRedlTbl[ nRedlPos ];
587 const SwPosition* pRStt = pTmp->Start(),
588 * pREnd = pTmp->GetMark() == pRStt
589 ? pTmp->GetPoint() : pTmp->GetMark();
591 if( pRStt->nNode < rRg.aStart )
593 if( pREnd->nNode > rRg.aStart && pREnd->nNode < rRg.aEnd )
595 // Kopie erzeugen und Ende vom Original ans Ende des
596 // MoveBereiches setzen. Die Kopie wird mit verschoben
597 SwRedline* pNewRedl = new SwRedline( *pTmp );
598 SwPosition* pTmpPos = pNewRedl->Start();
599 pTmpPos->nNode = rRg.aStart;
600 pTmpPos->nContent.Assign(
601 pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
603 _SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
604 // rArr.Insert( pSave, rArr.Count() );
605 rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
607 pTmpPos = pTmp->End();
608 pTmpPos->nNode = rRg.aEnd;
609 pTmpPos->nContent.Assign(
610 pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
612 else if( pREnd->nNode == rRg.aStart )
614 SwPosition* pTmpPos = pTmp->End();
615 pTmpPos->nNode = rRg.aEnd;
616 pTmpPos->nContent.Assign(
617 pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
620 else if( pRStt->nNode < rRg.aEnd )
622 rRedlTbl.Remove( nRedlPos-- );
623 if( pREnd->nNode < rRg.aEnd ||
624 ( pREnd->nNode == rRg.aEnd && !pREnd->nContent.GetIndex()) )
626 // gesamt verschieben
627 _SaveRedline* pSave = new _SaveRedline( pTmp, rRg.aStart );
628 // rArr.Insert( pSave, rArr.Count() );
629 rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
631 else
633 // aufsplitten
634 SwRedline* pNewRedl = new SwRedline( *pTmp );
635 SwPosition* pTmpPos = pNewRedl->End();
636 pTmpPos->nNode = rRg.aEnd;
637 pTmpPos->nContent.Assign(
638 pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
640 _SaveRedline* pSave = new _SaveRedline( pNewRedl, rRg.aStart );
641 // rArr.Insert( pSave, rArr.Count() );
642 rArr.C40_INSERT( _SaveRedline, pSave, rArr.Count() );
644 pTmpPos = pTmp->Start();
645 pTmpPos->nNode = rRg.aEnd;
646 pTmpPos->nContent.Assign(
647 pTmpPos->nNode.GetNode().GetCntntNode(), 0 );
648 pDoc->AppendRedline( pTmp, true );
651 else
652 break;
654 } while( ++nRedlPos < pDoc->GetRedlineTbl().Count() );
655 pDoc->SetRedlineMode_intern( eOld );
658 void lcl_RestoreRedlines( SwDoc* pDoc, sal_uInt32 nInsPos, _SaveRedlines& rArr )
660 RedlineMode_t eOld = pDoc->GetRedlineMode();
661 pDoc->SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
663 for( sal_uInt16 n = 0; n < rArr.Count(); ++n )
665 _SaveRedline* pSave = rArr[ n ];
666 pSave->SetPos( nInsPos );
667 pDoc->AppendRedline( pSave->pRedl, true );
670 pDoc->SetRedlineMode_intern( eOld );
673 // ------------------------------------------------------------------------
674 // #i59534: Redo of insertion of multiple text nodes runs into trouble
675 // because of unnecessary expanded redlines
676 // From now on this class saves the redline positions of all redlines which ends exact at the
677 // insert position (node _and_ content index)
679 _SaveRedlEndPosForRestore::_SaveRedlEndPosForRestore( const SwNodeIndex& rInsIdx, xub_StrLen nCnt )
680 : pSavArr( 0 ), pSavIdx( 0 ), nSavCntnt( nCnt )
682 SwNode& rNd = rInsIdx.GetNode();
683 SwDoc* pDest = rNd.GetDoc();
684 if( pDest->GetRedlineTbl().Count() )
686 sal_uInt16 nFndPos;
687 const SwPosition* pEnd;
688 SwPosition aSrcPos( rInsIdx, SwIndex( rNd.GetCntntNode(), nCnt ));
689 const SwRedline* pRedl = pDest->GetRedline( aSrcPos, &nFndPos );
690 while( nFndPos-- && *( pEnd = ( pRedl =
691 pDest->GetRedlineTbl()[ nFndPos ] )->End() ) == aSrcPos && *pRedl->Start() < aSrcPos )
693 if( !pSavArr )
695 pSavArr = new SvPtrarr( 2, 2 );
696 pSavIdx = new SwNodeIndex( rInsIdx, -1 );
698 void* p = (void*)pEnd;
699 pSavArr->Insert( p, pSavArr->Count() );
704 _SaveRedlEndPosForRestore::~_SaveRedlEndPosForRestore()
706 if( pSavArr )
708 delete pSavArr;
709 delete pSavIdx;
713 void _SaveRedlEndPosForRestore::_Restore()
715 (*pSavIdx)++;
716 SwCntntNode* pNode = pSavIdx->GetNode().GetCntntNode();
717 // If there's no content node at the remembered position, we will not restore the old position
718 // This may happen if a table (or section?) will be inserted.
719 if( pNode )
721 SwPosition aPos( *pSavIdx, SwIndex( pNode, nSavCntnt ));
722 for( sal_uInt16 n = pSavArr->Count(); n; )
723 *((SwPosition*)pSavArr->GetObject( --n )) = aPos;
728 // ------------------------------------------------------------------------
730 // Loeschen einer vollstaendigen Section des NodesArray.
731 // Der uebergebene Node steht irgendwo in der gewuenschten Section
732 void SwDoc::DeleteSection( SwNode *pNode )
734 ASSERT( pNode, "Kein Node uebergeben." );
735 SwStartNode* pSttNd = pNode->IsStartNode() ? (SwStartNode*)pNode
736 : pNode->StartOfSectionNode();
737 SwNodeIndex aSttIdx( *pSttNd ), aEndIdx( *pNode->EndOfSectionNode() );
739 // dann loesche mal alle Fly's, text::Bookmarks, ...
740 DelFlyInRange( aSttIdx, aEndIdx );
741 DeleteRedline( *pSttNd, true, USHRT_MAX );
742 _DelBookmarks(aSttIdx, aEndIdx);
745 // alle Crsr/StkCrsr/UnoCrsr aus dem Loeschbereich verschieben
746 SwNodeIndex aMvStt( aSttIdx, 1 );
747 CorrAbs( aMvStt, aEndIdx, SwPosition( aSttIdx ), sal_True );
750 GetNodes().DelNodes( aSttIdx, aEndIdx.GetIndex() - aSttIdx.GetIndex() + 1 );
754 void SwDoc::SetModified(SwPaM &rPaM)
756 SwDataChanged aTmp( rPaM, 0 );
757 SetModified();
760 /*************************************************************************
761 * SwDoc::Overwrite()
762 ************************************************************************/
764 bool SwDoc::Overwrite( const SwPaM &rRg, const String &rStr )
766 SwPosition& rPt = *(SwPosition*)rRg.GetPoint();
767 if( pACEWord ) // Aufnahme in die Autokorrektur
769 if( 1 == rStr.Len() )
770 pACEWord->CheckChar( rPt, rStr.GetChar( 0 ) );
771 delete pACEWord, pACEWord = 0;
774 SwTxtNode *pNode = rPt.nNode.GetNode().GetTxtNode();
775 if(!pNode)
776 return sal_False;
778 if( DoesUndo() )
779 ClearRedo();
781 sal_uInt16 nOldAttrCnt = pNode->GetpSwpHints()
782 ? pNode->GetpSwpHints()->Count() : 0;
783 SwDataChanged aTmp( rRg, 0 );
784 SwIndex& rIdx = rPt.nContent;
785 xub_StrLen nStart = 0;
787 sal_uInt16 nUndoSize = pUndos->Count();
788 SwUndo * pUndo;
789 sal_Unicode c;
790 String aStr;
792 BOOL bOldExpFlg = pNode->IsIgnoreDontExpand();
793 pNode->SetIgnoreDontExpand( TRUE );
795 for( xub_StrLen nCnt = 0; nCnt < rStr.Len(); ++nCnt )
797 // hinter das Zeichen (zum aufspannen der Attribute !!)
798 nStart = rIdx.GetIndex();
799 if ( nStart < pNode->GetTxt().Len() )
801 lcl_SkipAttr( pNode, rIdx, nStart );
803 c = rStr.GetChar( nCnt );
804 if( DoesUndo() )
806 if( DoesGroupUndo() && nUndoSize &&
807 UNDO_OVERWRITE == ( pUndo = (*pUndos)[ nUndoSize-1 ])->GetId() &&
808 ((SwUndoOverwrite*)pUndo)->CanGrouping( this, rPt, c ))
809 ;// wenn CanGrouping() sal_True returnt, ist schon alles erledigt
810 else
812 AppendUndo( new SwUndoOverwrite( this, rPt, c ));
813 nUndoSize = pUndos->Count();
816 else
818 // hinter das Zeichen (zum Aufspannen der Attribute !!)
819 if( nStart < pNode->GetTxt().Len() )
820 rIdx++;
821 pNode->InsertText( c, rIdx, INS_EMPTYEXPAND );
822 if( nStart+1 < rIdx.GetIndex() )
824 rIdx = nStart;
825 pNode->EraseText( rIdx, 1 );
826 rIdx++;
830 pNode->SetIgnoreDontExpand( bOldExpFlg );
832 sal_uInt16 nNewAttrCnt = pNode->GetpSwpHints()
833 ? pNode->GetpSwpHints()->Count() : 0;
834 if( nOldAttrCnt != nNewAttrCnt )
836 SwUpdateAttr aHint( 0, 0, 0 );
837 SwClientIter aIter( *pNode );
838 SwClient* pGTO = aIter.First(TYPE( SwCrsrShell ));
839 while( pGTO )
841 pGTO->Modify( 0, &aHint );
842 pGTO = aIter.Next();
846 if( !DoesUndo() && !IsIgnoreRedline() && GetRedlineTbl().Count() )
848 SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
849 DeleteRedline( aPam, true, USHRT_MAX );
851 else if( IsRedlineOn() )
853 // FIXME: this redline is WRONG: there is no DELETE, and the skipped
854 // characters are also included in aPam
855 SwPaM aPam( rPt.nNode, nStart, rPt.nNode, rPt.nContent.GetIndex() );
856 AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, aPam ), true);
859 SetModified();
860 return sal_True;
864 bool SwDoc::MoveAndJoin( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
866 SwNodeIndex aIdx( rPaM.Start()->nNode );
867 sal_Bool bJoinTxt = aIdx.GetNode().IsTxtNode();
868 sal_Bool bOneNode = rPaM.GetPoint()->nNode == rPaM.GetMark()->nNode;
869 aIdx--; // vor den Move Bereich !!
871 bool bRet = MoveRange( rPaM, rPos, eMvFlags );
872 if( bRet && !bOneNode )
874 if( bJoinTxt )
875 aIdx++;
876 SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode();
877 SwNodeIndex aNxtIdx( aIdx );
878 if( pTxtNd && pTxtNd->CanJoinNext( &aNxtIdx ) )
880 { // Block wegen SwIndex in den Node !!
881 CorrRel( aNxtIdx, SwPosition( aIdx, SwIndex( pTxtNd,
882 pTxtNd->GetTxt().Len() ) ), 0, sal_True );
884 pTxtNd->JoinNext();
887 return bRet;
890 // mst: it seems that this is mostly used by SwDoc internals; the only
891 // way to call this from the outside seems to be the special case in
892 // SwDoc::CopyRange (but i have not managed to actually hit that case)
893 bool SwDoc::MoveRange( SwPaM& rPaM, SwPosition& rPos, SwMoveFlags eMvFlags )
895 // keine Moves-Abfangen
896 const SwPosition *pStt = rPaM.Start(), *pEnd = rPaM.End();
897 if( !rPaM.HasMark() || *pStt >= *pEnd || (*pStt <= rPos && rPos < *pEnd))
898 return false;
900 // sicher die absatzgebundenen Flys, damit sie verschoben werden koennen.
901 _SaveFlyArr aSaveFlyArr;
902 _SaveFlyInRange( rPaM, rPos.nNode, aSaveFlyArr, 0 != ( DOC_MOVEALLFLYS & eMvFlags ) );
904 // save redlines (if DOC_MOVEREDLINES is used)
905 _SaveRedlines aSaveRedl( 0, 4 );
906 if( DOC_MOVEREDLINES & eMvFlags && GetRedlineTbl().Count() )
908 lcl_SaveRedlines( rPaM, aSaveRedl );
910 // #i17764# unfortunately, code below relies on undos being
911 // in a particular order, and presence of bookmarks
912 // will change this order. Hence, we delete bookmarks
913 // here without undo.
914 BOOL bDoesUndo = DoesUndo();
915 DoUndo( FALSE );
916 _DelBookmarks(
917 pStt->nNode,
918 pEnd->nNode,
919 NULL,
920 &pStt->nContent,
921 &pEnd->nContent);
922 DoUndo( bDoesUndo );
926 int bUpdateFtn = sal_False;
927 SwFtnIdxs aTmpFntIdx;
929 // falls Undo eingeschaltet, erzeuge das UndoMove-Objekt
930 SwUndoMove * pUndoMove = 0;
931 if( DoesUndo() )
933 ClearRedo();
934 pUndoMove = new SwUndoMove( rPaM, rPos );
935 pUndoMove->SetMoveRedlines( eMvFlags == DOC_MOVEREDLINES );
937 else
939 bUpdateFtn = lcl_SaveFtn( pStt->nNode, pEnd->nNode, rPos.nNode,
940 GetFtnIdxs(), aTmpFntIdx,
941 &pStt->nContent, &pEnd->nContent );
944 sal_Bool bSplit = sal_False;
945 SwPaM aSavePam( rPos, rPos );
947 // stelle den SPoint an den Anfang vom Bereich (Definition)
948 if( rPaM.GetPoint() == pEnd )
949 rPaM.Exchange();
951 // in der EditShell wird nach dem Move ein JoinNext erzeugt, wenn
952 // vor und nach dem Move ein Text-Node steht.
953 SwTxtNode* pSrcNd = rPaM.GetPoint()->nNode.GetNode().GetTxtNode();
954 sal_Bool bCorrSavePam = pSrcNd && pStt->nNode != pEnd->nNode;
956 // werden ein oder mehr TextNodes bewegt, so wird
957 // im SwNodes::Move ein SplitNode erzeugt. Dieser Updated aber nicht
958 // den Cursor. Um das zu verhindern, wird hier ein TextNode angelegt,
959 // um die Updaterei der Indizies zu erhalten. Nach dem Move wird
960 // evt. der Node geloescht.
962 SwTxtNode * pTNd = rPos.nNode.GetNode().GetTxtNode();
963 if( pTNd && rPaM.GetPoint()->nNode != rPaM.GetMark()->nNode &&
964 ( rPos.nContent.GetIndex() || ( pTNd->Len() && bCorrSavePam )) )
966 bSplit = sal_True;
967 xub_StrLen nMkCntnt = rPaM.GetMark()->nContent.GetIndex();
969 SvULongs aBkmkArr( 15, 15 );
970 _SaveCntntIdx( this, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(),
971 aBkmkArr, SAVEFLY_SPLIT );
973 pTNd = static_cast<SwTxtNode*>(pTNd->SplitCntntNode( rPos ));
975 if( aBkmkArr.Count() )
976 _RestoreCntntIdx( this, aBkmkArr, rPos.nNode.GetIndex()-1, 0, sal_True );
978 // jetzt noch den Pam berichtigen !!
979 if( rPos.nNode == rPaM.GetMark()->nNode )
981 rPaM.GetMark()->nNode = rPos.nNode.GetIndex()-1;
982 rPaM.GetMark()->nContent.Assign( pTNd, nMkCntnt );
986 // setze den Pam um einen "Inhalt" zurueck; dadurch steht er immer
987 // ausserhalb des manipulierten Bereiches. Falls kein Inhalt mehr vor-
988 // handen, dann auf den StartNode (es ist immer einer vorhanden !!!)
989 sal_Bool bNullCntnt = !aSavePam.Move( fnMoveBackward, fnGoCntnt );
990 if( bNullCntnt )
992 aSavePam.GetPoint()->nNode--;
995 // kopiere alle Bookmarks, die im Move Bereich stehen in ein
996 // Array, das alle Angaben auf die Position als Offset speichert.
997 // Die neue Zuordung erfolgt nach dem Moven.
998 ::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
999 _DelBookmarks(
1000 pStt->nNode,
1001 pEnd->nNode,
1002 &aSaveBkmks,
1003 &pStt->nContent,
1004 &pEnd->nContent);
1006 // falls durch die vorherigen Loeschungen (z.B. der Fussnoten) kein
1007 // Bereich mehr existiert, ist das immernoch ein gueltiger Move!
1008 if( *rPaM.GetPoint() != *rPaM.GetMark() )
1010 // now do the actual move
1011 GetNodes().MoveRange( rPaM, rPos, GetNodes() );
1013 // after a MoveRange() the Mark is deleted
1014 if ( rPaM.HasMark() ) // => no Move occurred!
1016 delete pUndoMove;
1017 return false;
1020 else
1021 rPaM.DeleteMark();
1023 ASSERT( *aSavePam.GetMark() == rPos ||
1024 ( aSavePam.GetMark()->nNode.GetNode().GetCntntNode() == NULL ),
1025 "PaM wurde nicht verschoben, am Anfang/Ende keine ContentNodes?" );
1026 *aSavePam.GetMark() = rPos;
1028 rPaM.SetMark(); // um den neuen Bereich eine Sel. aufspannen
1029 pTNd = aSavePam.GetNode()->GetTxtNode();
1030 if( DoesUndo() )
1032 // korrigiere erstmal den Content vom SavePam
1033 if( bNullCntnt )
1035 aSavePam.GetPoint()->nContent = 0;
1038 // die Methode SwEditShell::Move() fuegt nach dem Move den Text-Node
1039 // zusammen, in dem der rPaM steht. Wurde der Inhalt nach hinten
1040 // geschoben und liegt der SPoint vom SavePam im naechsten Node, so
1041 // muss beim Speichern vom Undo-Object das beachtet werden !!
1042 SwTxtNode * pPamTxtNd = 0;
1044 // wird ans SwUndoMove weitergegeben, das dann beim Undo JoinNext
1045 // aufruft. (falls es hier nicht moeglich ist).
1046 sal_Bool bJoin = bSplit && pTNd;
1047 bCorrSavePam = bCorrSavePam &&
1048 0 != ( pPamTxtNd = rPaM.GetNode()->GetTxtNode() )
1049 && pPamTxtNd->CanJoinNext()
1050 && (*rPaM.GetPoint() <= *aSavePam.GetPoint());
1052 // muessen am SavePam 2 Nodes zusammengefasst werden ??
1053 if( bJoin && pTNd->CanJoinNext() )
1055 pTNd->JoinNext();
1056 // kein temp. sdbcx::Index bei &&
1057 // es sollten wohl nur die Indexwerte verglichen werden.
1058 if( bCorrSavePam && rPaM.GetPoint()->nNode.GetIndex()+1 ==
1059 aSavePam.GetPoint()->nNode.GetIndex() )
1061 aSavePam.GetPoint()->nContent += pPamTxtNd->Len();
1063 bJoin = sal_False;
1065 // else if( !bCorrSavePam && !pSavePam->Move( fnMoveForward, fnGoCntnt ))
1066 else if ( !aSavePam.Move( fnMoveForward, fnGoCntnt ) )
1068 aSavePam.GetPoint()->nNode++;
1071 // zwischen SPoint und GetMark steht jetzt der neu eingefuegte Bereich
1072 pUndoMove->SetDestRange( aSavePam, *rPaM.GetPoint(),
1073 bJoin, bCorrSavePam );
1074 AppendUndo( pUndoMove );
1076 else
1078 bool bRemove = true;
1079 // muessen am SavePam 2 Nodes zusammengefasst werden ??
1080 if( bSplit && pTNd )
1082 if( pTNd->CanJoinNext())
1084 // --> OD 2009-08-20 #i100466#
1085 // Always join next, because <pTNd> has to stay as it is.
1086 // A join previous from its next would more or less delete <pTNd>
1087 pTNd->JoinNext();
1088 // <--
1089 bRemove = false;
1092 if( bNullCntnt )
1094 aSavePam.GetPoint()->nNode++;
1095 aSavePam.GetPoint()->nContent.Assign( aSavePam.GetCntntNode(), 0 );
1097 else if( bRemove ) // No move forward after joining with next paragraph
1099 aSavePam.Move( fnMoveForward, fnGoCntnt );
1103 // setze jetzt wieder die text::Bookmarks in das Dokument
1104 *rPaM.GetMark() = *aSavePam.Start();
1105 for(
1106 ::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
1107 pBkmk != aSaveBkmks.end();
1108 ++pBkmk)
1109 pBkmk->SetInDoc(
1110 this,
1111 rPaM.GetMark()->nNode,
1112 &rPaM.GetMark()->nContent);
1113 *rPaM.GetPoint() = *aSavePam.End();
1115 // verschiebe die Flys an die neue Position
1116 _RestFlyInRange( aSaveFlyArr, rPaM.Start()->nNode, &(rPos.nNode) );
1118 // restore redlines (if DOC_MOVEREDLINES is used)
1119 if( aSaveRedl.Count() )
1121 lcl_RestoreRedlines( this, *aSavePam.Start(), aSaveRedl );
1124 if( bUpdateFtn )
1126 if( aTmpFntIdx.Count() )
1128 GetFtnIdxs().Insert( &aTmpFntIdx );
1129 aTmpFntIdx.Remove( sal_uInt16( 0 ), aTmpFntIdx.Count() );
1132 GetFtnIdxs().UpdateAllFtn();
1135 SetModified();
1136 return true;
1139 bool SwDoc::MoveNodeRange( SwNodeRange& rRange, SwNodeIndex& rPos,
1140 SwMoveFlags eMvFlags )
1142 // bewegt alle Nodes an die neue Position. Dabei werden die
1143 // text::Bookmarks mit verschoben !! (zur Zeit ohne Undo)
1145 // falls durchs Move Fussnoten in den Sonderbereich kommen sollten,
1146 // dann entferne sie jetzt.
1147 //JP 13.07.95:
1148 // ansonsten bei allen Fussnoten, die verschoben werden, die Frames
1149 // loeschen und nach dem Move wieder aufbauen lassen (Fussnoten koennen
1150 // die Seite wechseln). Zusaetzlich muss natuerlich die Sortierung
1151 // der FtnIdx-Array wieder korrigiert werden.
1153 int bUpdateFtn = sal_False;
1154 SwFtnIdxs aTmpFntIdx;
1156 SwUndoMove* pUndo = 0;
1157 if( (DOC_CREATEUNDOOBJ & eMvFlags ) && DoesUndo() )
1158 pUndo = new SwUndoMove( this, rRange, rPos );
1159 else
1160 bUpdateFtn = lcl_SaveFtn( rRange.aStart, rRange.aEnd, rPos,
1161 GetFtnIdxs(), aTmpFntIdx );
1163 _SaveRedlines aSaveRedl( 0, 4 );
1164 SvPtrarr aSavRedlInsPosArr( 0, 4 );
1165 if( DOC_MOVEREDLINES & eMvFlags && GetRedlineTbl().Count() )
1167 lcl_SaveRedlines( rRange, aSaveRedl );
1169 // suche alle Redlines, die an der InsPos aufhoeren. Diese muessen
1170 // nach dem Move wieder an die "alte" Position verschoben werden
1171 sal_uInt16 nRedlPos = GetRedlinePos( rPos.GetNode(), USHRT_MAX );
1172 if( USHRT_MAX != nRedlPos )
1174 const SwPosition *pRStt, *pREnd;
1175 do {
1176 SwRedline* pTmp = GetRedlineTbl()[ nRedlPos ];
1177 pRStt = pTmp->Start();
1178 pREnd = pTmp->End();
1179 if( pREnd->nNode == rPos && pRStt->nNode < rPos )
1181 void* p = pTmp;
1182 aSavRedlInsPosArr.Insert( p, aSavRedlInsPosArr.Count() );
1184 } while( pRStt->nNode < rPos && ++nRedlPos < GetRedlineTbl().Count());
1188 // kopiere alle Bookmarks, die im Move Bereich stehen in ein
1189 // Array, das alle Angaben auf die Position als Offset speichert.
1190 // Die neue Zuordung erfolgt nach dem Moven.
1191 ::std::vector< ::sw::mark::SaveBookmark> aSaveBkmks;
1192 _DelBookmarks(rRange.aStart, rRange.aEnd, &aSaveBkmks);
1194 // sicher die absatzgebundenen Flys, damit verschoben werden koennen.
1195 _SaveFlyArr aSaveFlyArr;
1196 if( GetSpzFrmFmts()->Count() )
1197 _SaveFlyInRange( rRange, aSaveFlyArr );
1199 // vor die Position setzen, damit er nicht weitergeschoben wird
1200 SwNodeIndex aIdx( rPos, -1 );
1202 SwNodeIndex* pSaveInsPos = 0;
1203 if( pUndo )
1204 pSaveInsPos = new SwNodeIndex( rRange.aStart, -1 );
1206 // verschiebe die Nodes
1207 BOOL bNoDelFrms = 0 != (DOC_NO_DELFRMS & eMvFlags);
1208 if( GetNodes()._MoveNodes( rRange, GetNodes(), rPos, !bNoDelFrms ) )
1210 aIdx++; // wieder auf alte Position
1211 if( pSaveInsPos )
1212 (*pSaveInsPos)++;
1214 else
1216 aIdx = rRange.aStart;
1217 delete pUndo, pUndo = 0;
1220 // verschiebe die Flys an die neue Position
1221 if( aSaveFlyArr.Count() )
1222 _RestFlyInRange( aSaveFlyArr, aIdx, NULL );
1224 // setze jetzt wieder die text::Bookmarks in das Dokument
1225 for(
1226 ::std::vector< ::sw::mark::SaveBookmark>::iterator pBkmk = aSaveBkmks.begin();
1227 pBkmk != aSaveBkmks.end();
1228 ++pBkmk)
1229 pBkmk->SetInDoc(this, aIdx);
1231 if( aSavRedlInsPosArr.Count() )
1233 SwNode* pNewNd = &aIdx.GetNode();
1234 for( sal_uInt16 n = 0; n < aSavRedlInsPosArr.Count(); ++n )
1236 SwRedline* pTmp = (SwRedline*)aSavRedlInsPosArr[ n ];
1237 if( USHRT_MAX != GetRedlineTbl().GetPos( pTmp ) )
1239 SwPosition* pEnd = pTmp->End();
1240 pEnd->nNode = aIdx;
1241 pEnd->nContent.Assign( pNewNd->GetCntntNode(), 0 );
1246 if( aSaveRedl.Count() )
1247 lcl_RestoreRedlines( this, aIdx.GetIndex(), aSaveRedl );
1249 if( pUndo )
1251 ClearRedo();
1252 pUndo->SetDestRange( aIdx, rPos, *pSaveInsPos );
1253 AppendUndo( pUndo );
1256 if( pSaveInsPos )
1257 delete pSaveInsPos;
1259 if( bUpdateFtn )
1261 if( aTmpFntIdx.Count() )
1263 GetFtnIdxs().Insert( &aTmpFntIdx );
1264 aTmpFntIdx.Remove( sal_uInt16( 0 ), aTmpFntIdx.Count() );
1267 GetFtnIdxs().UpdateAllFtn();
1270 SetModified();
1271 return sal_True;
1274 /* #107318# Convert list of ranges of whichIds to a corresponding list
1275 of whichIds*/
1276 SvUShorts * lcl_RangesToUShorts(USHORT * pRanges)
1278 SvUShorts * pResult = new SvUShorts();
1280 int i = 0;
1281 while (pRanges[i] != 0)
1283 ASSERT(pRanges[i+1] != 0, "malformed ranges");
1285 for (USHORT j = pRanges[i]; j < pRanges[i+1]; j++)
1286 pResult->Insert(j, pResult->Count());
1288 i += 2;
1291 return pResult;
1294 bool lcl_StrLenOverFlow( const SwPaM& rPam )
1296 // If we try to merge two paragraph we have to test if afterwards
1297 // the string doesn't exceed the allowed string length
1298 bool bRet = false;
1299 if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
1301 const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
1302 const SwTxtNode* pEndNd = pEnd->nNode.GetNode().GetTxtNode();
1303 if( (0 != pEndNd) && pStt->nNode.GetNode().IsTxtNode() )
1305 sal_uInt64 nSum = pStt->nContent.GetIndex() +
1306 pEndNd->GetTxt().Len() - pEnd->nContent.GetIndex();
1307 if( nSum > STRING_LEN )
1308 bRet = true;
1311 return bRet;
1314 void lcl_GetJoinFlags( SwPaM& rPam, sal_Bool& rJoinTxt, sal_Bool& rJoinPrev )
1316 rJoinTxt = sal_False;
1317 rJoinPrev = sal_False;
1318 if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
1320 const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
1321 SwTxtNode *pSttNd = pStt->nNode.GetNode().GetTxtNode();
1322 if( pSttNd )
1324 SwTxtNode *pEndNd = pEnd->nNode.GetNode().GetTxtNode();
1325 rJoinTxt = 0 != pEndNd;
1326 if( rJoinTxt )
1328 bool bExchange = pStt == rPam.GetPoint();
1329 if( !pStt->nContent.GetIndex() &&
1330 pEndNd->GetTxt().Len() != pEnd->nContent.GetIndex() )
1331 bExchange = !bExchange;
1332 if( bExchange )
1333 rPam.Exchange();
1334 rJoinPrev = rPam.GetPoint() == pStt;
1335 ASSERT( !pStt->nContent.GetIndex() &&
1336 pEndNd->GetTxt().Len() != pEnd->nContent.GetIndex()
1337 ? rPam.GetPoint()->nNode < rPam.GetMark()->nNode
1338 : rPam.GetPoint()->nNode > rPam.GetMark()->nNode,
1339 "lcl_GetJoinFlags");
1345 void lcl_JoinText( SwPaM& rPam, sal_Bool bJoinPrev )
1347 SwNodeIndex aIdx( rPam.GetPoint()->nNode );
1348 SwTxtNode *pTxtNd = aIdx.GetNode().GetTxtNode();
1349 SwNodeIndex aOldIdx( aIdx );
1350 SwTxtNode *pOldTxtNd = pTxtNd;
1352 if( pTxtNd && pTxtNd->CanJoinNext( &aIdx ) )
1354 SwDoc* pDoc = rPam.GetDoc();
1355 if( bJoinPrev )
1357 // N.B.: we do not need to handle xmlids in this case, because
1358 // it is only invoked if one paragraph is completely empty
1359 // (see lcl_GetJoinFlags)
1361 // falls PageBreaks geloescht / gesetzt werden, darf das
1362 // nicht in die Undo-History aufgenommen werden !!
1363 // (das loeschen vom Node geht auch am Undo vorbei !!!)
1364 sal_Bool bDoUndo = pDoc->DoesUndo();
1365 pDoc->DoUndo( sal_False );
1367 /* PageBreaks, PageDesc, ColumnBreaks */
1368 // Sollte an der Logik zum Kopieren der PageBreak's ...
1369 // etwas geaendert werden, muss es auch im SwUndoDelete
1370 // geandert werden. Dort wird sich das AUTO-PageBreak
1371 // aus dem GetMarkNode kopiert.!!!
1373 /* Der GetMarkNode */
1374 if( ( pTxtNd = aIdx.GetNode().GetTxtNode())->HasSwAttrSet() )
1376 const SfxPoolItem* pItem;
1377 if( SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState(
1378 RES_BREAK, sal_False, &pItem ) )
1379 pTxtNd->ResetAttr( RES_BREAK );
1380 if( pTxtNd->HasSwAttrSet() &&
1381 SFX_ITEM_SET == pTxtNd->GetpSwAttrSet()->GetItemState(
1382 RES_PAGEDESC, sal_False, &pItem ) )
1383 pTxtNd->ResetAttr( RES_PAGEDESC );
1386 /* Der PointNode */
1387 if( pOldTxtNd->HasSwAttrSet() )
1389 const SfxPoolItem* pItem;
1390 SfxItemSet aSet( pDoc->GetAttrPool(), aBreakSetRange );
1391 const SfxItemSet* pSet = pOldTxtNd->GetpSwAttrSet();
1392 if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
1393 sal_False, &pItem ) )
1394 aSet.Put( *pItem );
1395 if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
1396 sal_False, &pItem ) )
1397 aSet.Put( *pItem );
1398 if( aSet.Count() )
1399 pTxtNd->SetAttr( aSet );
1401 pOldTxtNd->FmtToTxtAttr( pTxtNd );
1403 SvULongs aBkmkArr( 15, 15 );
1404 ::_SaveCntntIdx( pDoc, aOldIdx.GetIndex(),
1405 pOldTxtNd->Len(), aBkmkArr );
1407 SwIndex aAlphaIdx(pTxtNd);
1408 pOldTxtNd->CutText( pTxtNd, aAlphaIdx, SwIndex(pOldTxtNd),
1409 pOldTxtNd->Len() );
1410 SwPosition aAlphaPos( aIdx, aAlphaIdx );
1411 pDoc->CorrRel( rPam.GetPoint()->nNode, aAlphaPos, 0, sal_True );
1413 // verschiebe noch alle Bookmarks/TOXMarks
1414 if( aBkmkArr.Count() )
1415 ::_RestoreCntntIdx( pDoc, aBkmkArr, aIdx.GetIndex() );
1417 pDoc->DoUndo( bDoUndo );
1419 // falls der uebergebene PaM nicht im Crsr-Ring steht,
1420 // gesondert behandeln (z.B. Aufruf aus dem Auto-Format)
1421 if( pOldTxtNd == rPam.GetBound( sal_True ).nContent.GetIdxReg() )
1422 rPam.GetBound( sal_True ) = aAlphaPos;
1423 if( pOldTxtNd == rPam.GetBound( sal_False ).nContent.GetIdxReg() )
1424 rPam.GetBound( sal_False ) = aAlphaPos;
1426 // jetzt nur noch den Node loeschen
1427 pDoc->GetNodes().Delete( aOldIdx, 1 );
1429 else
1431 SwTxtNode* pDelNd = aIdx.GetNode().GetTxtNode();
1432 if( pTxtNd->Len() )
1433 pDelNd->FmtToTxtAttr( pTxtNd );
1434 else
1436 /* #107318# This case was missed:
1438 <something></something> <-- pTxtNd
1439 <other>ccc</other> <-- pDelNd
1441 <something> and <other> are paragraph
1442 attributes. The attribute <something> stayed if not
1443 overwritten by an attribute in "ccc". Fixed by
1444 first resetting all character attributes in first
1445 paragraph (pTxtNd).
1447 SvUShorts * pShorts =
1448 lcl_RangesToUShorts(aCharFmtSetRange);
1449 pTxtNd->ResetAttr(*pShorts);
1450 delete pShorts;
1452 if( pDelNd->HasSwAttrSet() )
1454 // nur die Zeichenattribute kopieren
1455 SfxItemSet aTmpSet( pDoc->GetAttrPool(), aCharFmtSetRange );
1456 aTmpSet.Put( *pDelNd->GetpSwAttrSet() );
1457 pTxtNd->SetAttr( aTmpSet );
1461 pDoc->CorrRel( aIdx, *rPam.GetPoint(), 0, sal_True );
1462 // --> OD 2009-08-20 #i100466#
1463 // adjust given <rPam>, if it does not belong to the cursors
1464 if ( pDelNd == rPam.GetBound( sal_True ).nContent.GetIdxReg() )
1466 rPam.GetBound( sal_True ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
1468 if( pDelNd == rPam.GetBound( sal_False ).nContent.GetIdxReg() )
1470 rPam.GetBound( sal_False ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
1472 // <--
1473 pTxtNd->JoinNext();
1478 static void
1479 lcl_CalcBreaks( ::std::vector<xub_StrLen> & rBreaks, SwPaM const & rPam )
1481 SwTxtNode const * const pTxtNode(
1482 rPam.End()->nNode.GetNode().GetTxtNode() );
1483 if (!pTxtNode)
1484 return; // left-overlap only possible at end of selection...
1486 const xub_StrLen nStart(rPam.Start()->nContent.GetIndex());
1487 const xub_StrLen nEnd (rPam.End ()->nContent.GetIndex());
1488 if (nEnd == pTxtNode->Len())
1489 return; // paragraph selected until the end
1491 for (xub_StrLen i = nStart; i < nEnd; ++i)
1493 const sal_Unicode c(pTxtNode->GetTxt().GetChar(i));
1494 if ((CH_TXTATR_INWORD == c) || (CH_TXTATR_BREAKWORD == c))
1496 SwTxtAttr const * const pAttr( pTxtNode->GetTxtAttrForCharAt(i) );
1497 if (pAttr && pAttr->GetEnd() && (*pAttr->GetEnd() > nEnd))
1499 ASSERT(pAttr->HasDummyChar(), "GetTxtAttrForCharAt broken?");
1500 rBreaks.push_back(i);
1506 bool lcl_DoWithBreaks(SwDoc & rDoc, SwPaM & rPam,
1507 bool (SwDoc::*pFunc)(SwPaM&, bool), const bool bForceJoinNext = false)
1509 ::std::vector<xub_StrLen> Breaks;
1511 lcl_CalcBreaks(Breaks, rPam);
1513 if (!Breaks.size())
1515 return (rDoc.*pFunc)(rPam, bForceJoinNext);
1518 // N.B.: deletion must be split into several parts if the text node
1519 // contains a text attribute with end and with dummy character
1520 // and the selection does not contain the text attribute completely,
1521 // but overlaps its start (left), where the dummy character is.
1523 SwPosition const & rSelectionEnd( *rPam.End() );
1525 bool bRet( true );
1526 // iterate from end to start, to avoid invalidating the offsets!
1527 ::std::vector<xub_StrLen>::reverse_iterator iter( Breaks.rbegin() );
1528 SwPaM aPam( rSelectionEnd, rSelectionEnd ); // end node!
1529 SwPosition & rEnd( *aPam.End() );
1530 SwPosition & rStart( *aPam.Start() );
1532 while (iter != Breaks.rend())
1534 rStart.nContent = *iter + 1;
1535 if (rEnd.nContent > rStart.nContent) // check if part is empty
1537 bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext);
1539 rEnd.nContent = *iter;
1540 ++iter;
1543 rStart = *rPam.Start(); // set to original start
1544 if (rEnd.nContent > rStart.nContent) // check if part is empty
1546 bRet &= (rDoc.*pFunc)(aPam, bForceJoinNext);
1549 return bRet;
1553 bool SwDoc::DeleteAndJoinWithRedlineImpl( SwPaM & rPam, const bool )
1555 ASSERT( IsRedlineOn(), "DeleteAndJoinWithRedline: redline off" );
1558 sal_uInt16 nUndoSize = 0;
1559 SwUndoRedlineDelete* pUndo = 0;
1560 RedlineMode_t eOld = GetRedlineMode();
1561 checkRedlining(eOld);
1562 if( DoesUndo() )
1564 ClearRedo();
1566 //JP 06.01.98: MUSS noch optimiert werden!!!
1567 SetRedlineMode(
1568 (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE ));
1570 nUndoSize = pUndos->Count();
1571 StartUndo(UNDO_EMPTY, NULL);
1572 AppendUndo( pUndo = new SwUndoRedlineDelete( rPam, UNDO_DELETE ));
1574 if( *rPam.GetPoint() != *rPam.GetMark() )
1575 AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, rPam ), true);
1576 SetModified();
1578 if( pUndo )
1580 EndUndo(UNDO_EMPTY, NULL);
1581 SwUndo* pPrevUndo;
1582 if( nUndoSize && DoesGroupUndo() &&
1583 nUndoSize + 1 == pUndos->Count() &&
1584 UNDO_REDLINE == ( pPrevUndo = (*pUndos)[ nUndoSize-1 ])->GetId() &&
1585 UNDO_DELETE == ((SwUndoRedline*)pPrevUndo)->GetUserId() &&
1586 ((SwUndoRedlineDelete*)pPrevUndo)->CanGrouping( *pUndo ))
1588 DoUndo( sal_False );
1589 pUndos->DeleteAndDestroy( nUndoSize, 1 );
1590 --nUndoPos, --nUndoCnt;
1591 DoUndo( sal_True );
1593 //JP 06.01.98: MUSS noch optimiert werden!!!
1594 SetRedlineMode( eOld );
1596 return true;
1600 bool SwDoc::DeleteAndJoinImpl( SwPaM & rPam,
1601 const bool bForceJoinNext )
1603 sal_Bool bJoinTxt, bJoinPrev;
1604 lcl_GetJoinFlags( rPam, bJoinTxt, bJoinPrev );
1605 // --> OD 2009-08-20 #i100466#
1606 if ( bForceJoinNext )
1608 bJoinPrev = sal_False;
1610 // <--
1612 // dann eine Kopie vom Cursor erzeugen um alle Pams aus den
1613 // anderen Sichten aus dem Loeschbereich zu verschieben
1614 // ABER NICHT SICH SELBST !!
1615 SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
1616 ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
1618 const bool bSuccess( DeleteRangeImpl( aDelPam ) );
1619 if (!bSuccess)
1620 return false;
1622 *rPam.GetPoint() = *aDelPam.GetPoint();
1625 if( bJoinTxt )
1627 lcl_JoinText( rPam, bJoinPrev );
1630 return true;
1633 bool SwDoc::DeleteRangeImpl( SwPaM & rPam, const bool )
1635 SwPosition *pStt = (SwPosition*)rPam.Start(), *pEnd = (SwPosition*)rPam.End();
1637 if( !rPam.HasMark() || *pStt >= *pEnd )
1638 return false;
1640 if( pACEWord )
1642 // ggfs. das gesicherte Word fuer die Ausnahme
1643 if( pACEWord->IsDeleted() || pStt->nNode != pEnd->nNode ||
1644 pStt->nContent.GetIndex() + 1 != pEnd->nContent.GetIndex() ||
1645 !pACEWord->CheckDelChar( *pStt ))
1646 delete pACEWord, pACEWord = 0;
1650 // loesche alle leeren TextHints an der Mark-Position
1651 SwTxtNode* pTxtNd = rPam.GetMark()->nNode.GetNode().GetTxtNode();
1652 SwpHints* pHts;
1653 if( pTxtNd && 0 != ( pHts = pTxtNd->GetpSwpHints()) && pHts->Count() )
1655 const xub_StrLen *pEndIdx;
1656 xub_StrLen nMkCntPos = rPam.GetMark()->nContent.GetIndex();
1657 for( sal_uInt16 n = pHts->Count(); n; )
1659 const SwTxtAttr* pAttr = (*pHts)[ --n ];
1660 if( nMkCntPos > *pAttr->GetStart() )
1661 break;
1663 if( nMkCntPos == *pAttr->GetStart() &&
1664 0 != (pEndIdx = pAttr->GetEnd()) &&
1665 *pEndIdx == *pAttr->GetStart() )
1666 pTxtNd->DestroyAttr( pHts->Cut( n ) );
1672 // Bug 26675: DataChanged vorm loeschen verschicken, dann bekommt
1673 // man noch mit, welche Objecte sich im Bereich befinden.
1674 // Danach koennen sie vor/hinter der Position befinden.
1675 SwDataChanged aTmp( rPam, 0 );
1679 if( DoesUndo() )
1681 ClearRedo();
1682 sal_uInt16 nUndoSize = pUndos->Count();
1683 SwUndo * pUndo;
1684 if( DoesGroupUndo() && nUndoSize-- &&
1685 UNDO_DELETE == ( pUndo = (*pUndos)[ nUndoSize ])->GetId() &&
1686 ((SwUndoDelete*)pUndo)->CanGrouping( this, rPam ))
1687 ;// wenn CanGrouping() sal_True returnt, ist schon alles erledigt
1688 else
1689 AppendUndo( new SwUndoDelete( rPam ) );
1691 SetModified();
1693 return true;
1696 if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
1697 DeleteRedline( rPam, true, USHRT_MAX );
1699 // loesche und verschiebe erstmal alle "Fly's am Absatz", die in der
1700 // Selection liegen
1701 DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode);
1702 _DelBookmarks(
1703 pStt->nNode,
1704 pEnd->nNode,
1705 NULL,
1706 &pStt->nContent,
1707 &pEnd->nContent);
1709 SwNodeIndex aSttIdx( pStt->nNode );
1710 SwCntntNode * pCNd = aSttIdx.GetNode().GetCntntNode();
1712 do { // middle checked loop!
1713 if( pCNd )
1715 SwTxtNode * pStartTxtNode( pCNd->GetTxtNode() );
1716 if ( pStartTxtNode )
1718 // verschiebe jetzt noch den Inhalt in den neuen Node
1719 sal_Bool bOneNd = pStt->nNode == pEnd->nNode;
1720 xub_StrLen nLen = ( bOneNd ? pEnd->nContent.GetIndex()
1721 : pCNd->Len() )
1722 - pStt->nContent.GetIndex();
1724 // falls schon leer, dann nicht noch aufrufen
1725 if( nLen )
1727 pStartTxtNode->EraseText( pStt->nContent, nLen );
1729 if( !pStartTxtNode->Len() )
1731 // METADATA: remove reference if empty (consider node deleted)
1732 pStartTxtNode->RemoveMetadataReference();
1736 if( bOneNd ) // das wars schon
1737 break;
1739 aSttIdx++;
1741 else
1743 // damit beim loeschen keine Indizies mehr angemeldet sind,
1744 // wird hier der SwPaM aus dem Content entfernt !!
1745 pStt->nContent.Assign( 0, 0 );
1749 pCNd = pEnd->nNode.GetNode().GetCntntNode();
1750 if( pCNd )
1752 SwTxtNode * pEndTxtNode( pCNd->GetTxtNode() );
1753 if( pEndTxtNode )
1755 // falls schon leer, dann nicht noch aufrufen
1756 if( pEnd->nContent.GetIndex() )
1758 SwIndex aIdx( pCNd, 0 );
1759 pEndTxtNode->EraseText( aIdx, pEnd->nContent.GetIndex() );
1761 if( !pEndTxtNode->Len() )
1763 // METADATA: remove reference if empty (consider node deleted)
1764 pEndTxtNode->RemoveMetadataReference();
1768 else
1770 // damit beim Loeschen keine Indizies mehr angemeldet sind,
1771 // wird hier der SwPaM aus dem Content entfernt !!
1772 pEnd->nContent.Assign( 0, 0 );
1776 // if the end is not a content node, delete it as well
1777 sal_uInt32 nEnde = pEnd->nNode.GetIndex();
1778 if( pCNd == NULL )
1779 nEnde++;
1781 if( aSttIdx != nEnde )
1783 // loesche jetzt die Nodes in das NodesArary
1784 GetNodes().Delete( aSttIdx, nEnde - aSttIdx.GetIndex() );
1787 // falls der Node geloescht wurde, in dem der Cursor stand, so
1788 // muss der Content im akt. Content angemeldet werden !!!
1789 pStt->nContent.Assign( pStt->nNode.GetNode().GetCntntNode(),
1790 pStt->nContent.GetIndex() );
1792 // der PaM wird korrigiert, denn falls ueber Nodegrenzen geloescht
1793 // wurde, so stehen sie in unterschieden Nodes. Auch die Selektion
1794 // wird aufgehoben !
1795 *pEnd = *pStt;
1796 rPam.DeleteMark();
1798 } while( sal_False );
1800 if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
1801 CompressRedlines();
1802 SetModified();
1804 return true;
1807 // OD 2009-08-20 #i100466#
1808 // Add handling of new optional parameter <bForceJoinNext>
1809 bool SwDoc::DeleteAndJoin( SwPaM & rPam,
1810 const bool bForceJoinNext )
1812 if ( lcl_StrLenOverFlow( rPam ) )
1813 return false;
1815 return lcl_DoWithBreaks( *this, rPam, (IsRedlineOn())
1816 ? &SwDoc::DeleteAndJoinWithRedlineImpl
1817 : &SwDoc::DeleteAndJoinImpl,
1818 bForceJoinNext );
1821 bool SwDoc::DeleteRange( SwPaM & rPam )
1823 return lcl_DoWithBreaks( *this, rPam, &SwDoc::DeleteRangeImpl );
1827 void lcl_syncGrammarError( SwTxtNode &rTxtNode, linguistic2::ProofreadingResult& rResult,
1828 xub_StrLen /*nBeginGrammarCheck*/, const ModelToViewHelper::ConversionMap* pConversionMap )
1830 if( rTxtNode.IsGrammarCheckDirty() )
1831 return;
1832 SwGrammarMarkUp* pWrong = rTxtNode.GetGrammarCheck();
1833 linguistic2::SingleProofreadingError* pArray = rResult.aErrors.getArray();
1834 USHORT i, j = 0;
1835 if( pWrong )
1837 for( i = 0; i < rResult.aErrors.getLength(); ++i )
1839 const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i];
1840 xub_StrLen nStart = (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart ).mnPos;
1841 xub_StrLen nEnd = (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart + rError.nErrorLength ).mnPos;
1842 if( i != j )
1843 pArray[j] = pArray[i];
1844 if( pWrong->LookForEntry( nStart, nEnd ) )
1845 ++j;
1848 if( rResult.aErrors.getLength() > j )
1849 rResult.aErrors.realloc( j );
1853 uno::Any SwDoc::Spell( SwPaM& rPaM,
1854 uno::Reference< XSpellChecker1 > &xSpeller,
1855 sal_uInt16* pPageCnt, sal_uInt16* pPageSt,
1856 bool bGrammarCheck,
1857 SwConversionArgs *pConvArgs ) const
1859 SwPosition* pSttPos = rPaM.Start(), *pEndPos = rPaM.End();
1860 uno::Reference< beans::XPropertySet > xProp( ::GetLinguPropertySet() );
1862 SwSpellArgs *pSpellArgs = 0;
1863 //SwConversionArgs *pConvArgs = 0;
1864 if (pConvArgs)
1866 pConvArgs->SetStart(pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent);
1867 pConvArgs->SetEnd( pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent );
1869 else
1870 pSpellArgs = new SwSpellArgs( xSpeller,
1871 pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent,
1872 pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent,
1873 bGrammarCheck );
1875 ULONG nCurrNd = pSttPos->nNode.GetIndex();
1876 ULONG nEndNd = pEndPos->nNode.GetIndex();
1878 uno::Any aRet;
1879 if( nCurrNd <= nEndNd )
1881 SwCntntFrm* pCntFrm;
1882 sal_Bool bGoOn = sal_True;
1883 while( bGoOn )
1885 SwNode* pNd = GetNodes()[ nCurrNd ];
1886 switch( pNd->GetNodeType() )
1888 case ND_TEXTNODE:
1889 if( 0 != ( pCntFrm = ((SwTxtNode*)pNd)->GetFrm()) )
1891 // geschutze Cellen/Flys ueberspringen, ausgeblendete
1892 //ebenfalls
1893 if( pCntFrm->IsProtected() )
1895 nCurrNd = pNd->EndOfSectionIndex();
1897 else if( !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
1899 if( pPageCnt && *pPageCnt && pPageSt )
1901 sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
1902 if( !*pPageSt )
1904 *pPageSt = nPageNr;
1905 if( *pPageCnt < *pPageSt )
1906 *pPageCnt = *pPageSt;
1908 long nStat;
1909 if( nPageNr >= *pPageSt )
1910 nStat = nPageNr - *pPageSt + 1;
1911 else
1912 nStat = nPageNr + *pPageCnt - *pPageSt + 1;
1913 ::SetProgressState( nStat, (SwDocShell*)GetDocShell() );
1915 //Spell() changes the pSpellArgs in case an error is found
1916 xub_StrLen nBeginGrammarCheck = 0;
1917 xub_StrLen nEndGrammarCheck = 0;
1918 if( pSpellArgs && pSpellArgs->bIsGrammarCheck)
1920 nBeginGrammarCheck = pSpellArgs->pStartNode == pNd ? pSpellArgs->pStartIdx->GetIndex() : 0;
1921 // if grammar checking starts inside of a sentence the start position has to be adjusted
1922 if( nBeginGrammarCheck )
1924 SwIndex aStartIndex( dynamic_cast< SwTxtNode* >( pNd ), nBeginGrammarCheck );
1925 SwPosition aStart( *pNd, aStartIndex );
1926 SwCursor aCrsr(aStart, 0, false);
1927 SwPosition aOrigPos = *aCrsr.GetPoint();
1928 aCrsr.GoSentence( SwCursor::START_SENT );
1929 if( aOrigPos != *aCrsr.GetPoint() )
1931 nBeginGrammarCheck = aCrsr.GetPoint()->nContent.GetIndex();
1934 nEndGrammarCheck = pSpellArgs->pEndNode == pNd ? pSpellArgs->pEndIdx->GetIndex() : ((SwTxtNode*)pNd)->GetTxt().Len();
1937 xub_StrLen nSpellErrorPosition = ((SwTxtNode*)pNd)->GetTxt().Len();
1938 if( (!pConvArgs &&
1939 ((SwTxtNode*)pNd)->Spell( pSpellArgs )) ||
1940 ( pConvArgs &&
1941 ((SwTxtNode*)pNd)->Convert( *pConvArgs )))
1943 // Abbrechen und Position merken
1944 pSttPos->nNode = nCurrNd;
1945 pEndPos->nNode = nCurrNd;
1946 nCurrNd = nEndNd;
1947 if( pSpellArgs )
1948 nSpellErrorPosition = pSpellArgs->pStartIdx->GetIndex() > pSpellArgs->pEndIdx->GetIndex() ?
1949 pSpellArgs->pEndIdx->GetIndex() :
1950 pSpellArgs->pStartIdx->GetIndex();
1954 if( pSpellArgs && pSpellArgs->bIsGrammarCheck )
1956 uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( GetGCIterator() );
1957 if (xGCIterator.is())
1959 String aText( ((SwTxtNode*)pNd)->GetTxt().Copy( nBeginGrammarCheck, nEndGrammarCheck - nBeginGrammarCheck ) );
1960 uno::Reference< lang::XComponent > xDoc( ((SwDocShell*)GetDocShell())->GetBaseModel(), uno::UNO_QUERY );
1961 // Expand the string:
1962 rtl::OUString aExpandText;
1963 const ModelToViewHelper::ConversionMap* pConversionMap =
1964 ((SwTxtNode*)pNd)->BuildConversionMap( aExpandText );
1965 // get XFlatParagraph to use...
1966 uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *((SwTxtNode*)pNd), aExpandText, pConversionMap );
1968 // get error position of cursor in XFlatParagraph
1969 sal_Int32 nGrammarErrorPosInText;
1970 linguistic2::ProofreadingResult aResult;
1971 sal_Int32 nGrammarErrors;
1974 nGrammarErrorPosInText = ModelToViewHelper::ConvertToViewPosition( pConversionMap, nBeginGrammarCheck );
1975 aResult = xGCIterator->checkSentenceAtPosition(
1976 xDoc, xFlatPara, aExpandText, lang::Locale(), nBeginGrammarCheck, -1, -1 );
1978 lcl_syncGrammarError( *((SwTxtNode*)pNd), aResult, nBeginGrammarCheck, pConversionMap );
1980 // get suggestions to use for the specific error position
1981 nGrammarErrors = aResult.aErrors.getLength();
1982 // if grammar checking doesn't have any progress then quit
1983 if( aResult.nStartOfNextSentencePosition <= nBeginGrammarCheck )
1984 break;
1985 // prepare next iteration
1986 nBeginGrammarCheck = (xub_StrLen)aResult.nStartOfNextSentencePosition;
1988 while( nSpellErrorPosition > aResult.nBehindEndOfSentencePosition && !nGrammarErrors && aResult.nBehindEndOfSentencePosition < nEndGrammarCheck );
1990 if( nGrammarErrors > 0 && nSpellErrorPosition >= aResult.nBehindEndOfSentencePosition )
1992 aRet <<= aResult;
1993 //put the cursor to the current error
1994 const linguistic2::SingleProofreadingError &rError = aResult.aErrors[0];
1995 nCurrNd = pNd->GetIndex();
1996 pSttPos->nNode = nCurrNd;
1997 pEndPos->nNode = nCurrNd;
1998 pSpellArgs->pStartNode = ((SwTxtNode*)pNd);
1999 pSpellArgs->pEndNode = ((SwTxtNode*)pNd);
2000 pSpellArgs->pStartIdx->Assign(((SwTxtNode*)pNd), (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart ).mnPos );
2001 pSpellArgs->pEndIdx->Assign(((SwTxtNode*)pNd), (xub_StrLen)ModelToViewHelper::ConvertToModelPosition( pConversionMap, rError.nErrorStart + rError.nErrorLength ).mnPos );
2002 nCurrNd = nEndNd;
2008 break;
2009 case ND_SECTIONNODE:
2010 if( ( ((SwSectionNode*)pNd)->GetSection().IsProtect() ||
2011 ((SwSectionNode*)pNd)->GetSection().IsHidden() ) )
2012 nCurrNd = pNd->EndOfSectionIndex();
2013 break;
2014 case ND_ENDNODE:
2016 break;
2020 bGoOn = nCurrNd < nEndNd;
2021 ++nCurrNd;
2025 if( !aRet.hasValue() )
2027 if (pConvArgs)
2028 aRet <<= pConvArgs->aConvText;
2029 else
2030 aRet <<= pSpellArgs->xSpellAlt;
2032 delete pSpellArgs;
2034 return aRet;
2037 class SwHyphArgs : public SwInterHyphInfo
2039 const SwNode *pStart;
2040 const SwNode *pEnd;
2041 SwNode *pNode;
2042 sal_uInt16 *pPageCnt;
2043 sal_uInt16 *pPageSt;
2045 sal_uInt32 nNode;
2046 xub_StrLen nPamStart;
2047 xub_StrLen nPamLen;
2049 public:
2050 SwHyphArgs( const SwPaM *pPam, const Point &rPoint,
2051 sal_uInt16* pPageCount, sal_uInt16* pPageStart );
2052 void SetPam( SwPaM *pPam ) const;
2053 inline void SetNode( SwNode *pNew ) { pNode = pNew; }
2054 inline const SwNode *GetNode() const { return pNode; }
2055 inline void SetRange( const SwNode *pNew );
2056 inline void NextNode() { ++nNode; }
2057 inline sal_uInt16 *GetPageCnt() { return pPageCnt; }
2058 inline sal_uInt16 *GetPageSt() { return pPageSt; }
2061 SwHyphArgs::SwHyphArgs( const SwPaM *pPam, const Point &rCrsrPos,
2062 sal_uInt16* pPageCount, sal_uInt16* pPageStart )
2063 : SwInterHyphInfo( rCrsrPos ), pNode(0),
2064 pPageCnt( pPageCount ), pPageSt( pPageStart )
2066 // Folgende Bedingungen muessen eingehalten werden:
2067 // 1) es gibt mindestens eine Selektion
2068 // 2) SPoint() == Start()
2069 ASSERT( pPam->HasMark(), "SwDoc::Hyphenate: blowing in the wind");
2070 ASSERT( *pPam->GetPoint() <= *pPam->GetMark(),
2071 "SwDoc::Hyphenate: New York, New York");
2073 const SwPosition *pPoint = pPam->GetPoint();
2074 nNode = pPoint->nNode.GetIndex();
2076 // Start einstellen
2077 pStart = pPoint->nNode.GetNode().GetTxtNode();
2078 nPamStart = pPoint->nContent.GetIndex();
2080 // Ende und Laenge einstellen.
2081 const SwPosition *pMark = pPam->GetMark();
2082 pEnd = pMark->nNode.GetNode().GetTxtNode();
2083 nPamLen = pMark->nContent.GetIndex();
2084 if( pPoint->nNode == pMark->nNode )
2085 nPamLen = nPamLen - pPoint->nContent.GetIndex();
2088 inline void SwHyphArgs::SetRange( const SwNode *pNew )
2090 nStart = pStart == pNew ? nPamStart : 0;
2091 nLen = pEnd == pNew ? nPamLen : STRING_NOTFOUND;
2094 void SwHyphArgs::SetPam( SwPaM *pPam ) const
2096 if( !pNode )
2097 *pPam->GetPoint() = *pPam->GetMark();
2098 else
2100 pPam->GetPoint()->nNode = nNode;
2101 pPam->GetPoint()->nContent.Assign( pNode->GetCntntNode(), nWordStart );
2102 pPam->GetMark()->nNode = nNode;
2103 pPam->GetMark()->nContent.Assign( pNode->GetCntntNode(),
2104 nWordStart + nWordLen );
2105 ASSERT( nNode == pNode->GetIndex(),
2106 "SwHyphArgs::SetPam: Pam desaster" );
2110 // liefert sal_True zurueck, wenn es weitergehen soll.
2111 sal_Bool lcl_HyphenateNode( const SwNodePtr& rpNd, void* pArgs )
2113 // Hyphenate liefert sal_True zurueck, wenn eine Trennstelle anliegt
2114 // und stellt pPam ein.
2115 SwTxtNode *pNode = rpNd->GetTxtNode();
2116 SwHyphArgs *pHyphArgs = (SwHyphArgs*)pArgs;
2117 if( pNode )
2119 SwCntntFrm* pCntFrm = pNode->GetFrm();
2120 if( pCntFrm && !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
2122 sal_uInt16 *pPageSt = pHyphArgs->GetPageSt();
2123 sal_uInt16 *pPageCnt = pHyphArgs->GetPageCnt();
2124 if( pPageCnt && *pPageCnt && pPageSt )
2126 sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
2127 if( !*pPageSt )
2129 *pPageSt = nPageNr;
2130 if( *pPageCnt < *pPageSt )
2131 *pPageCnt = *pPageSt;
2133 long nStat = nPageNr >= *pPageSt ? nPageNr - *pPageSt + 1
2134 : nPageNr + *pPageCnt - *pPageSt + 1;
2135 ::SetProgressState( nStat, (SwDocShell*)pNode->GetDoc()->GetDocShell() );
2137 pHyphArgs->SetRange( rpNd );
2138 if( pNode->Hyphenate( *pHyphArgs ) )
2140 pHyphArgs->SetNode( rpNd );
2141 return sal_False;
2145 pHyphArgs->NextNode();
2146 return sal_True;
2149 uno::Reference< XHyphenatedWord > SwDoc::Hyphenate(
2150 SwPaM *pPam, const Point &rCrsrPos,
2151 sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
2153 ASSERT(this == pPam->GetDoc(), "SwDoc::Hyphenate: strangers in the night");
2155 if( *pPam->GetPoint() > *pPam->GetMark() )
2156 pPam->Exchange();
2158 SwHyphArgs aHyphArg( pPam, rCrsrPos, pPageCnt, pPageSt );
2159 SwNodeIndex aTmpIdx( pPam->GetMark()->nNode, 1 );
2160 GetNodes().ForEach( pPam->GetPoint()->nNode, aTmpIdx,
2161 lcl_HyphenateNode, &aHyphArg );
2162 aHyphArg.SetPam( pPam );
2163 return aHyphArg.GetHyphWord(); // will be set by lcl_HyphenateNode
2167 sal_Bool lcl_GetTokenToParaBreak( String& rStr, String& rRet, sal_Bool bRegExpRplc )
2169 sal_Bool bRet = sal_False;
2170 if( bRegExpRplc )
2172 xub_StrLen nPos = 0;
2173 String sPara( String::CreateFromAscii(
2174 RTL_CONSTASCII_STRINGPARAM( "\\n" )));
2175 while( STRING_NOTFOUND != ( nPos = rStr.Search( sPara, nPos )) )
2177 // wurde das escaped?
2178 if( nPos && '\\' == rStr.GetChar( nPos-1 ))
2180 if( ++nPos >= rStr.Len() )
2181 break;
2183 else
2185 rRet = rStr.Copy( 0, nPos );
2186 rStr.Erase( 0, nPos + sPara.Len() );
2187 bRet = sal_True;
2188 break;
2192 if( !bRet )
2194 rRet = rStr;
2195 rStr.Erase();
2197 return bRet;
2200 bool SwDoc::ReplaceRange( SwPaM& rPam, const String& rStr,
2201 const bool bRegExReplace )
2203 // unfortunately replace works slightly differently from delete,
2204 // so we cannot use lcl_DoWithBreaks here...
2206 ::std::vector<xub_StrLen> Breaks;
2208 SwPaM aPam( *rPam.GetMark(), *rPam.GetPoint() );
2209 aPam.Normalize(FALSE);
2210 if (aPam.GetPoint()->nNode != aPam.GetMark()->nNode)
2212 aPam.Move(fnMoveBackward);
2214 ASSERT((aPam.GetPoint()->nNode == aPam.GetMark()->nNode), "invalid pam?");
2216 lcl_CalcBreaks(Breaks, aPam);
2218 while (!Breaks.empty() // skip over prefix of dummy chars
2219 && (aPam.GetMark()->nContent.GetIndex() == *Breaks.begin()) )
2221 // skip!
2222 ++aPam.GetMark()->nContent; // always in bounds if Breaks valid
2223 Breaks.erase(Breaks.begin());
2225 *rPam.Start() = *aPam.GetMark(); // update start of original pam w/ prefix
2227 if (!Breaks.size())
2229 return ReplaceRangeImpl(rPam, rStr, bRegExReplace); // original pam!
2232 // N.B.: deletion must be split into several parts if the text node
2233 // contains a text attribute with end and with dummy character
2234 // and the selection does not contain the text attribute completely,
2235 // but overlaps its start (left), where the dummy character is.
2237 bool bRet( true );
2238 // iterate from end to start, to avoid invalidating the offsets!
2239 ::std::vector<xub_StrLen>::reverse_iterator iter( Breaks.rbegin() );
2240 ASSERT(aPam.GetPoint() == aPam.End(), "wrong!");
2241 SwPosition & rEnd( *aPam.End() );
2242 SwPosition & rStart( *aPam.Start() );
2244 // set end of temp pam to original end (undo Move backward above)
2245 rEnd = *rPam.End();
2246 // after first deletion, rEnd will point into the original text node again!
2248 while (iter != Breaks.rend())
2250 rStart.nContent = *iter + 1;
2251 if (rEnd.nContent != rStart.nContent) // check if part is empty
2253 bRet &= (IsRedlineOn())
2254 ? DeleteAndJoinWithRedlineImpl(aPam)
2255 : DeleteAndJoinImpl(aPam, false);
2257 rEnd.nContent = *iter;
2258 ++iter;
2261 rStart = *rPam.Start(); // set to original start
2262 ASSERT(rEnd.nContent > rStart.nContent, "replace part empty!");
2263 if (rEnd.nContent > rStart.nContent) // check if part is empty
2265 bRet &= ReplaceRangeImpl(aPam, rStr, bRegExReplace);
2268 rPam = aPam; // update original pam (is this required?)
2270 return bRet;
2273 // N.B.: it is possible to call Replace with a PaM that spans 2 paragraphs:
2274 // search with regex for "$", then replace _all_
2275 bool SwDoc::ReplaceRangeImpl( SwPaM& rPam, const String& rStr,
2276 const bool bRegExReplace )
2278 if( !rPam.HasMark() || *rPam.GetPoint() == *rPam.GetMark() )
2279 return false;
2281 sal_Bool bJoinTxt, bJoinPrev;
2282 lcl_GetJoinFlags( rPam, bJoinTxt, bJoinPrev );
2285 // dann eine Kopie vom Cursor erzeugen um alle Pams aus den
2286 // anderen Sichten aus dem Loeschbereich zu verschieben
2287 // ABER NICHT SICH SELBST !!
2288 SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
2289 ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
2291 SwPosition *pStt = (SwPosition*)aDelPam.Start(),
2292 *pEnd = (SwPosition*)aDelPam.End();
2293 ASSERT( pStt->nNode == pEnd->nNode ||
2294 ( pStt->nNode.GetIndex() + 1 == pEnd->nNode.GetIndex() &&
2295 !pEnd->nContent.GetIndex() ),
2296 "invalid range: Point and Mark on different nodes" );
2297 sal_Bool bOneNode = pStt->nNode == pEnd->nNode;
2299 // eigenes Undo ????
2300 String sRepl( rStr );
2301 SwTxtNode* pTxtNd = pStt->nNode.GetNode().GetTxtNode();
2302 xub_StrLen nStt = pStt->nContent.GetIndex(),
2303 nEnd = bOneNode ? pEnd->nContent.GetIndex()
2304 : pTxtNd->GetTxt().Len();
2306 SwDataChanged aTmp( aDelPam, 0 );
2308 if( IsRedlineOn() )
2310 RedlineMode_t eOld = GetRedlineMode();
2311 checkRedlining(eOld);
2312 if( DoesUndo() )
2314 StartUndo(UNDO_EMPTY, NULL);
2316 // Bug 68584 - if any Redline will change (split!) the node
2317 const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, ::rtl::OUString(), IDocumentMarkAccess::UNO_BOOKMARK );
2319 //JP 06.01.98: MUSS noch optimiert werden!!!
2320 SetRedlineMode(
2321 (RedlineMode_t)(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE ));
2323 *aDelPam.GetPoint() = pBkmk->GetMarkPos();
2324 if(pBkmk->IsExpanded())
2325 *aDelPam.GetMark() = pBkmk->GetOtherMarkPos();
2326 getIDocumentMarkAccess()->deleteMark(pBkmk);
2327 pStt = aDelPam.Start();
2328 pTxtNd = pStt->nNode.GetNode().GetTxtNode();
2329 nStt = pStt->nContent.GetIndex();
2332 if( sRepl.Len() )
2334 // Attribute des 1. Zeichens ueber den ReplaceText setzen
2335 SfxItemSet aSet( GetAttrPool(),
2336 RES_CHRATR_BEGIN, RES_TXTATR_WITHEND_END - 1,
2337 RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
2338 0 );
2339 pTxtNd->GetAttr( aSet, nStt+1, nStt+1 );
2341 aSet.ClearItem( RES_TXTATR_REFMARK );
2342 aSet.ClearItem( RES_TXTATR_TOXMARK );
2343 aSet.ClearItem( RES_TXTATR_CJK_RUBY );
2344 aSet.ClearItem( RES_TXTATR_INETFMT );
2345 aSet.ClearItem( RES_TXTATR_META );
2346 aSet.ClearItem( RES_TXTATR_METAFIELD );
2348 if( aDelPam.GetPoint() != aDelPam.End() )
2349 aDelPam.Exchange();
2351 // das Ende merken
2352 SwNodeIndex aPtNd( aDelPam.GetPoint()->nNode, -1 );
2353 xub_StrLen nPtCnt = aDelPam.GetPoint()->nContent.GetIndex();
2355 sal_Bool bFirst = sal_True;
2356 String sIns;
2357 while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
2359 InsertString( aDelPam, sIns );
2360 if( bFirst )
2362 SwNodeIndex aMkNd( aDelPam.GetMark()->nNode, -1 );
2363 xub_StrLen nMkCnt = aDelPam.GetMark()->nContent.GetIndex();
2365 SplitNode( *aDelPam.GetPoint(), false );
2367 aMkNd++;
2368 aDelPam.GetMark()->nNode = aMkNd;
2369 aDelPam.GetMark()->nContent.Assign(
2370 aMkNd.GetNode().GetCntntNode(), nMkCnt );
2371 bFirst = sal_False;
2373 else
2374 SplitNode( *aDelPam.GetPoint(), false );
2376 if( sIns.Len() )
2378 InsertString( aDelPam, sIns );
2381 SwPaM aTmpRange( *aDelPam.GetPoint() );
2382 aTmpRange.SetMark();
2384 aPtNd++;
2385 aDelPam.GetPoint()->nNode = aPtNd;
2386 aDelPam.GetPoint()->nContent.Assign( aPtNd.GetNode().GetCntntNode(),
2387 nPtCnt);
2388 *aTmpRange.GetMark() = *aDelPam.GetPoint();
2390 RstTxtAttrs( aTmpRange );
2391 InsertItemSet( aTmpRange, aSet, 0 );
2394 if( DoesUndo() )
2395 AppendUndo( new SwUndoRedlineDelete( aDelPam, UNDO_REPLACE ));
2396 AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, aDelPam ), true);
2398 *rPam.GetMark() = *aDelPam.GetMark();
2399 if( DoesUndo() )
2401 *aDelPam.GetPoint() = *rPam.GetPoint();
2402 EndUndo(UNDO_EMPTY, NULL);
2404 // Bug 68584 - if any Redline will change (split!) the node
2405 const ::sw::mark::IMark* pBkmk = getIDocumentMarkAccess()->makeMark( aDelPam, ::rtl::OUString(), IDocumentMarkAccess::UNO_BOOKMARK );
2407 SwIndex& rIdx = aDelPam.GetPoint()->nContent;
2408 rIdx.Assign( 0, 0 );
2409 aDelPam.GetMark()->nContent = rIdx;
2410 rPam.GetPoint()->nNode = 0;
2411 rPam.GetPoint()->nContent = rIdx;
2412 *rPam.GetMark() = *rPam.GetPoint();
2413 //JP 06.01.98: MUSS noch optimiert werden!!!
2414 SetRedlineMode( eOld );
2416 *rPam.GetPoint() = pBkmk->GetMarkPos();
2417 if(pBkmk->IsExpanded())
2418 *rPam.GetMark() = pBkmk->GetOtherMarkPos();
2419 getIDocumentMarkAccess()->deleteMark(pBkmk);
2421 bJoinTxt = sal_False;
2423 else
2425 if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
2426 DeleteRedline( aDelPam, true, USHRT_MAX );
2428 SwUndoReplace* pUndoRpl = 0;
2429 if( DoesUndo() )
2431 ClearRedo();
2432 SwUndo* pU;
2434 if( !pUndos->Count() ||
2435 UNDO_REPLACE != ( pU = (*pUndos)[ pUndos->Count()-1 ])->GetId() ||
2436 ( pUndoRpl = (SwUndoReplace*)pU )->IsFull() )
2438 pUndoRpl = new SwUndoReplace();
2439 AppendUndo( pUndoRpl );
2441 pUndoRpl->AddEntry( aDelPam, sRepl, bRegExReplace );
2442 DoUndo( sal_False );
2445 if( aDelPam.GetPoint() != pStt )
2446 aDelPam.Exchange();
2448 SwNodeIndex aPtNd( pStt->nNode, -1 );
2449 xub_StrLen nPtCnt = pStt->nContent.GetIndex();
2451 // die Werte nochmal setzen, falls schohn Rahmen oder Fussnoten
2452 // auf dem Text entfernt wurden!
2453 nStt = nPtCnt;
2454 nEnd = bOneNode ? pEnd->nContent.GetIndex()
2455 : pTxtNd->GetTxt().Len();
2457 sal_Bool bFirst = sal_True;
2458 String sIns;
2459 while ( lcl_GetTokenToParaBreak( sRepl, sIns, bRegExReplace ) )
2461 if( !bFirst || nStt == pTxtNd->GetTxt().Len() )
2463 InsertString( aDelPam, sIns );
2465 else if( nStt < nEnd || sIns.Len() )
2467 pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
2469 SplitNode( *pStt, false);
2470 bFirst = sal_False;
2473 if( bFirst || sIns.Len() )
2475 if( !bFirst || nStt == pTxtNd->GetTxt().Len() )
2477 InsertString( aDelPam, sIns );
2479 else if( nStt < nEnd || sIns.Len() )
2481 pTxtNd->ReplaceText( pStt->nContent, nEnd - nStt, sIns );
2485 *rPam.GetMark() = *aDelPam.GetMark();
2487 aPtNd++;
2488 rPam.GetMark()->nNode = aPtNd;
2489 rPam.GetMark()->nContent.Assign( aPtNd.GetNode().GetCntntNode(),
2490 nPtCnt );
2491 if( bJoinTxt )
2492 rPam.Move( fnMoveBackward );
2494 if( pUndoRpl )
2496 pUndoRpl->SetEntryEnd( rPam );
2497 DoUndo( sal_True );
2502 if( bJoinTxt )
2503 lcl_JoinText( rPam, bJoinPrev );
2505 SetModified();
2506 return true;
2509 // speicher die akt. Werte fuer die automatische Aufnahme von Ausnahmen
2510 // in die Autokorrektur
2511 void SwDoc::SetAutoCorrExceptWord( SwAutoCorrExceptWord* pNew )
2513 if( pACEWord && pNew != pACEWord )
2514 delete pACEWord;
2515 pACEWord = pNew;
2518 bool SwDoc::DelFullPara( SwPaM& rPam )
2520 const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
2521 const SwNode* pNd = &rStt.nNode.GetNode();
2522 sal_uInt32 nSectDiff = pNd->StartOfSectionNode()->EndOfSectionIndex() -
2523 pNd->StartOfSectionIndex();
2524 sal_uInt32 nNodeDiff = rEnd.nNode.GetIndex() - rStt.nNode.GetIndex();
2526 if ( nSectDiff-2 <= nNodeDiff || IsRedlineOn() ||
2527 /* #i9185# Prevent getting the node after the end node (see below) */
2528 rEnd.nNode.GetIndex() + 1 == aNodes.Count() )
2529 return sal_False;
2531 // harte SeitenUmbrueche am nachfolgenden Node verschieben
2532 sal_Bool bSavePageBreak = sal_False, bSavePageDesc = sal_False;
2534 /* #i9185# This whould lead to a segmentation fault if not catched
2535 above. */
2536 ULONG nNextNd = rEnd.nNode.GetIndex() + 1;
2537 SwTableNode* pTblNd = aNodes[ nNextNd ]->GetTableNode();
2539 if( pTblNd && pNd->IsCntntNode() )
2541 SwFrmFmt* pTableFmt = pTblNd->GetTable().GetFrmFmt();
2542 //JP 24.08.98: will man wirklich den PageDesc/Break vom
2543 // nachfolgen Absatz ueberbuegeln?
2544 // const SwAttrSet& rAttrSet = pTableFmt->GetAttrSet();
2545 // if( SFX_ITEM_SET != rAttrSet.GetItemState( RES_PAGEDESC ) &&
2546 // SFX_ITEM_SET != rAttrSet.GetItemState( RES_BREAK ))
2548 const SfxPoolItem *pItem;
2549 const SfxItemSet* pSet = ((SwCntntNode*)pNd)->GetpSwAttrSet();
2550 if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC,
2551 sal_False, &pItem ) )
2553 pTableFmt->SetFmtAttr( *pItem );
2554 bSavePageDesc = sal_True;
2557 if( pSet && SFX_ITEM_SET == pSet->GetItemState( RES_BREAK,
2558 sal_False, &pItem ) )
2560 pTableFmt->SetFmtAttr( *pItem );
2561 bSavePageBreak = sal_True;
2566 sal_Bool bDoesUndo = DoesUndo();
2567 if( bDoesUndo )
2569 if( !rPam.HasMark() )
2570 rPam.SetMark();
2571 else if( rPam.GetPoint() == &rStt )
2572 rPam.Exchange();
2573 rPam.GetPoint()->nNode++;
2575 SwCntntNode *pTmpNode = rPam.GetPoint()->nNode.GetNode().GetCntntNode();
2576 rPam.GetPoint()->nContent.Assign( pTmpNode, 0 );
2577 bool bGoNext = (0 == pTmpNode);
2578 pTmpNode = rPam.GetMark()->nNode.GetNode().GetCntntNode();
2579 rPam.GetMark()->nContent.Assign( pTmpNode, 0 );
2581 ClearRedo();
2583 SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
2585 SwPosition aTmpPos( *aDelPam.GetPoint() );
2586 if( bGoNext )
2588 pTmpNode = GetNodes().GoNext( &aTmpPos.nNode );
2589 aTmpPos.nContent.Assign( pTmpNode, 0 );
2591 ::PaMCorrAbs( aDelPam, aTmpPos );
2594 SwUndoDelete* pUndo = new SwUndoDelete( aDelPam, sal_True );
2596 *rPam.GetPoint() = *aDelPam.GetPoint();
2597 pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
2598 AppendUndo( pUndo );
2600 else
2602 SwNodeRange aRg( rStt.nNode, rEnd.nNode );
2603 if( rPam.GetPoint() != &rEnd )
2604 rPam.Exchange();
2606 // versuche hinters Ende zu verschieben
2607 if( !rPam.Move( fnMoveForward, fnGoNode ) )
2609 // na gut, dann an den Anfang
2610 rPam.Exchange();
2611 if( !rPam.Move( fnMoveBackward, fnGoNode ))
2613 ASSERT( sal_False, "kein Node mehr vorhanden" );
2614 return sal_False;
2617 // text::Bookmarks usw. verschieben
2618 CorrAbs( aRg.aStart, aRg.aEnd, *rPam.GetPoint(), sal_True );
2620 // was ist mit Fly's ??
2622 // stehen noch FlyFrames rum, loesche auch diese
2623 const SwPosition* pAPos;
2624 for( sal_uInt16 n = 0; n < GetSpzFrmFmts()->Count(); ++n )
2626 SwFrmFmt* pFly = (*GetSpzFrmFmts())[n];
2627 const SwFmtAnchor* pAnchor = &pFly->GetAnchor();
2628 if( ( FLY_AT_CNTNT == pAnchor->GetAnchorId() ||
2629 FLY_AUTO_CNTNT == pAnchor->GetAnchorId() ) &&
2630 0 != ( pAPos = pAnchor->GetCntntAnchor() ) &&
2631 aRg.aStart <= pAPos->nNode && pAPos->nNode <= aRg.aEnd )
2633 DelLayoutFmt( pFly );
2634 --n;
2639 SwCntntNode *pTmpNode = rPam.GetBound( TRUE ).nNode.GetNode().GetCntntNode();
2640 rPam.GetBound( TRUE ).nContent.Assign( pTmpNode, 0 );
2641 pTmpNode = rPam.GetBound( FALSE ).nNode.GetNode().GetCntntNode();
2642 rPam.GetBound( FALSE ).nContent.Assign( pTmpNode, 0 );
2643 GetNodes().Delete( aRg.aStart, nNodeDiff+1 );
2645 rPam.DeleteMark();
2646 SetModified();
2648 return sal_True;
2652 void SwDoc::TransliterateText( const SwPaM& rPaM,
2653 utl::TransliterationWrapper& rTrans )
2655 SwUndoTransliterate* pUndo;
2656 if( DoesUndo() )
2657 pUndo = new SwUndoTransliterate( rPaM, rTrans );
2658 else
2659 pUndo = 0;
2661 const SwPosition* pStt = rPaM.Start(),
2662 * pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
2663 : rPaM.GetPoint();
2664 ULONG nSttNd = pStt->nNode.GetIndex(), nEndNd = pEnd->nNode.GetIndex();
2665 xub_StrLen nSttCnt = pStt->nContent.GetIndex(),
2666 nEndCnt = pEnd->nContent.GetIndex();
2668 SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
2669 if( pStt == pEnd && pTNd ) // no region ?
2671 Boundary aBndry;
2672 if( pBreakIt->GetBreakIter().is() )
2673 aBndry = pBreakIt->GetBreakIter()->getWordBoundary(
2674 pTNd->GetTxt(), nSttCnt,
2675 pBreakIt->GetLocale( pTNd->GetLang( nSttCnt ) ),
2676 WordType::ANY_WORD /*ANYWORD_IGNOREWHITESPACES*/,
2677 TRUE );
2679 if( aBndry.startPos < nSttCnt && nSttCnt < aBndry.endPos )
2681 nSttCnt = (xub_StrLen)aBndry.startPos;
2682 nEndCnt = (xub_StrLen)aBndry.endPos;
2686 if( nSttNd != nEndNd )
2688 SwNodeIndex aIdx( pStt->nNode );
2689 if( nSttCnt )
2691 aIdx++;
2692 if( pTNd )
2693 pTNd->TransliterateText( rTrans, nSttCnt,
2694 pTNd->GetTxt().Len(), pUndo );
2697 for( ; aIdx.GetIndex() < nEndNd; aIdx++ )
2698 if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() ))
2699 pTNd->TransliterateText( rTrans, 0, pTNd->GetTxt().Len(),
2700 pUndo );
2702 if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
2703 pTNd->TransliterateText( rTrans, 0, nEndCnt, pUndo );
2705 else if( pTNd && nSttCnt < nEndCnt )
2706 pTNd->TransliterateText( rTrans, nSttCnt, nEndCnt, pUndo );
2708 if( pUndo )
2710 if( pUndo->HasData() )
2712 ClearRedo();
2713 AppendUndo( pUndo );
2715 else
2716 delete pUndo;
2718 SetModified();
2720 #define MAX_REDLINE_COUNT 250
2721 // -----------------------------------------------------------------------------
2722 void SwDoc::checkRedlining(RedlineMode_t& _rReadlineMode)
2724 const SwRedlineTbl& rRedlineTbl = GetRedlineTbl();
2725 SwEditShell* pEditShell = GetEditShell();
2726 Window* pParent = pEditShell ? pEditShell->GetWin() : NULL;
2727 if ( pParent && !mbReadlineChecked && rRedlineTbl.Count() > MAX_REDLINE_COUNT
2728 && !((_rReadlineMode & nsRedlineMode_t::REDLINE_SHOW_DELETE) == nsRedlineMode_t::REDLINE_SHOW_DELETE) )
2730 WarningBox aWarning( pParent,SW_RES(MSG_DISABLE_READLINE_QUESTION));
2731 USHORT nResult = aWarning.Execute();
2732 mbReadlineChecked = sal_True;
2733 if ( nResult == RET_YES )
2735 sal_Int32 nMode = (sal_Int32)_rReadlineMode;
2736 nMode |= nsRedlineMode_t::REDLINE_SHOW_INSERT | nsRedlineMode_t::REDLINE_SHOW_DELETE;
2737 _rReadlineMode = (RedlineMode_t)nMode;
2741 // -----------------------------------------------------------------------------
2743 void SwDoc::CountWords( const SwPaM& rPaM, SwDocStat& rStat ) const
2745 // This is a modified version of SwDoc::TransliterateText
2746 const SwPosition* pStt = rPaM.Start();
2747 const SwPosition* pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
2748 : rPaM.GetPoint();
2750 const ULONG nSttNd = pStt->nNode.GetIndex();
2751 const ULONG nEndNd = pEnd->nNode.GetIndex();
2753 const xub_StrLen nSttCnt = pStt->nContent.GetIndex();
2754 const xub_StrLen nEndCnt = pEnd->nContent.GetIndex();
2756 const SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
2757 if( pStt == pEnd && pTNd ) // no region ?
2759 // do nothing
2760 return;
2763 if( nSttNd != nEndNd )
2765 SwNodeIndex aIdx( pStt->nNode );
2766 if( nSttCnt )
2768 aIdx++;
2769 if( pTNd )
2770 pTNd->CountWords( rStat, nSttCnt, pTNd->GetTxt().Len() );
2773 for( ; aIdx.GetIndex() < nEndNd; aIdx++ )
2774 if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() ))
2775 pTNd->CountWords( rStat, 0, pTNd->GetTxt().Len() );
2777 if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
2778 pTNd->CountWords( rStat, 0, nEndCnt );
2780 else if( pTNd && nSttCnt < nEndCnt )
2781 pTNd->CountWords( rStat, nSttCnt, nEndCnt );
2784 void SwDoc::RemoveLeadingWhiteSpace(const SwPosition & rPos )
2786 const SwTxtNode* pTNd = rPos.nNode.GetNode().GetTxtNode();
2787 if ( pTNd )
2789 const String& rTxt = pTNd->GetTxt();
2790 xub_StrLen nIdx = 0;
2791 sal_Unicode cCh;
2792 while( nIdx < rTxt.Len() &&
2793 ( '\t' == ( cCh = rTxt.GetChar( nIdx ) ) ||
2794 ( ' ' == cCh ) ) )
2795 ++nIdx;
2797 if ( nIdx > 0 )
2799 SwPaM aPam(rPos);
2800 aPam.GetPoint()->nContent = 0;
2801 aPam.SetMark();
2802 aPam.GetMark()->nContent = nIdx;
2803 DeleteRange( aPam );