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