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