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