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 : #include <fmtanchr.hxx>
21 : #include <fmtcntnt.hxx>
22 : #include <txtftn.hxx>
23 : #include <acorrect.hxx>
24 : #include <UndoManager.hxx>
25 : #include <IDocumentRedlineAccess.hxx>
26 : #include <IDocumentState.hxx>
27 : #include <IDocumentLayoutAccess.hxx>
28 : #include <docsh.hxx>
29 : #include <docary.hxx>
30 : #include <doctxm.hxx>
31 : #include <ftnidx.hxx>
32 : #include <mdiexp.hxx>
33 : #include <mvsave.hxx>
34 : #include <redline.hxx>
35 : #include <rootfrm.hxx>
36 : #include <splargs.hxx>
37 : #include <txtfrm.hxx>
38 : #include <breakit.hxx>
39 : #include <vcl/layout.hxx>
40 : #include "comcore.hrc"
41 : #include "editsh.hxx"
42 : #include <fmtfld.hxx>
43 : #include <docufld.hxx>
44 : #include <unoflatpara.hxx>
45 : #include <SwGrammarMarkUp.hxx>
46 : #include <docedt.hxx>
47 :
48 : #include <vector>
49 :
50 : using namespace ::com::sun::star;
51 : using namespace ::com::sun::star::linguistic2;
52 : using namespace ::com::sun::star::i18n;
53 :
54 :
55 12 : void _RestFlyInRange( _SaveFlyArr & rArr, const SwNodeIndex& rSttIdx,
56 : const SwNodeIndex* pInsertPos )
57 : {
58 12 : SwPosition aPos( rSttIdx );
59 12 : for( size_t n = 0; n < rArr.size(); ++n )
60 : {
61 : // create new anchor
62 0 : _SaveFly& rSave = rArr[n];
63 0 : SwFrmFmt* pFmt = rSave.pFrmFmt;
64 :
65 0 : if( rSave.bInsertPosition )
66 : {
67 0 : if( pInsertPos != NULL )
68 0 : aPos.nNode = *pInsertPos;
69 : else
70 0 : aPos.nNode = rSttIdx.GetIndex();
71 : }
72 : else
73 0 : aPos.nNode = rSttIdx.GetIndex() + rSave.nNdDiff;
74 :
75 0 : aPos.nContent.Assign( 0, 0 );
76 0 : SwFmtAnchor aAnchor( pFmt->GetAnchor() );
77 0 : aAnchor.SetAnchor( &aPos );
78 0 : pFmt->GetDoc()->GetSpzFrmFmts()->push_back( pFmt );
79 0 : pFmt->SetFmtAttr( aAnchor );
80 0 : SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode();
81 0 : if( pCNd && pCNd->getLayoutFrm( pFmt->GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout(), 0, 0, false ) )
82 0 : pFmt->MakeFrms();
83 12 : }
84 12 : }
85 :
86 0 : void _SaveFlyInRange( const SwNodeRange& rRg, _SaveFlyArr& rArr )
87 : {
88 0 : SwFrmFmts& rFmts = *rRg.aStart.GetNode().GetDoc()->GetSpzFrmFmts();
89 0 : for( sal_uInt16 n = 0; n < rFmts.size(); ++n )
90 : {
91 0 : SwFrmFmt *const pFmt = static_cast<SwFrmFmt*>(rFmts[n]);
92 0 : SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
93 0 : SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
94 0 : if (pAPos &&
95 0 : ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
96 0 : (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
97 0 : rRg.aStart <= pAPos->nNode && pAPos->nNode < rRg.aEnd )
98 : {
99 0 : _SaveFly aSave( pAPos->nNode.GetIndex() - rRg.aStart.GetIndex(),
100 0 : pFmt, false );
101 0 : rArr.push_back( aSave );
102 0 : pFmt->DelFrms();
103 0 : rFmts.erase( rFmts.begin() + n-- );
104 : }
105 : }
106 0 : }
107 :
108 12 : void _SaveFlyInRange( const SwPaM& rPam, const SwNodeIndex& rInsPos,
109 : _SaveFlyArr& rArr, bool bMoveAllFlys )
110 : {
111 12 : SwFrmFmts& rFmts = *rPam.GetPoint()->nNode.GetNode().GetDoc()->GetSpzFrmFmts();
112 : SwFrmFmt* pFmt;
113 : const SwFmtAnchor* pAnchor;
114 :
115 12 : const SwPosition* pPos = rPam.Start();
116 12 : const SwNodeIndex& rSttNdIdx = pPos->nNode;
117 12 : short nSttOff = (!bMoveAllFlys && rSttNdIdx.GetNode().IsCntntNode() &&
118 12 : pPos->nContent.GetIndex()) ? 1 : 0;
119 :
120 12 : pPos = rPam.GetPoint() == pPos ? rPam.GetMark() : rPam.GetPoint();
121 12 : const SwNodeIndex& rEndNdIdx = pPos->nNode;
122 0 : short nOff = ( bMoveAllFlys || ( rEndNdIdx.GetNode().IsCntntNode() &&
123 0 : pPos->nContent == rEndNdIdx.GetNode().GetCntntNode()->Len() ))
124 12 : ? 0 : 1;
125 :
126 : const SwNodeIndex* pCntntIdx;
127 :
128 12 : for( sal_uInt16 n = 0; n < rFmts.size(); ++n )
129 : {
130 0 : bool bInsPos = false;
131 0 : pFmt = (SwFrmFmt*)rFmts[n];
132 0 : pAnchor = &pFmt->GetAnchor();
133 0 : const SwPosition* pAPos = pAnchor->GetCntntAnchor();
134 0 : if (pAPos &&
135 0 : ((FLY_AT_PARA == pAnchor->GetAnchorId()) ||
136 0 : (FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
137 : // do not move if the InsPos is in the CntntArea of the Fly
138 0 : ( 0 == ( pCntntIdx = pFmt->GetCntnt().GetCntntIdx() ) ||
139 0 : !( *pCntntIdx < rInsPos &&
140 0 : rInsPos < pCntntIdx->GetNode().EndOfSectionIndex() )) )
141 : {
142 0 : if( !bMoveAllFlys && rEndNdIdx == pAPos->nNode )
143 : {
144 : // Do not touch Anchor, if only a part of the EndNode
145 : // or the whole EndNode is identical with the SttNode
146 0 : if( rSttNdIdx != pAPos->nNode )
147 : {
148 : // Only attach an anchor to the beginning or end
149 0 : SwPosition aPos( rSttNdIdx );
150 0 : SwFmtAnchor aAnchor( *pAnchor );
151 0 : aAnchor.SetAnchor( &aPos );
152 0 : pFmt->SetFmtAttr( aAnchor );
153 : }
154 : }
155 0 : else if( ( rSttNdIdx.GetIndex() + nSttOff <= pAPos->nNode.GetIndex()
156 0 : && pAPos->nNode.GetIndex() <= rEndNdIdx.GetIndex() - nOff ) ||
157 0 : ( bInsPos = (rInsPos == pAPos->nNode) ))
158 :
159 : {
160 0 : _SaveFly aSave( pAPos->nNode.GetIndex() - rSttNdIdx.GetIndex(),
161 0 : pFmt, bInsPos );
162 0 : rArr.push_back( aSave );
163 0 : pFmt->DelFrms();
164 0 : rFmts.erase( rFmts.begin() + n-- );
165 : }
166 : }
167 : }
168 12 : }
169 :
170 : /// Delete and move all Flys at the paragraph, that are within the selection.
171 : /// If there is a Fly at the SPoint, it is moved onto the Mark.
172 14310 : void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
173 : const SwNodeIndex& rPtNdIdx )
174 : {
175 14310 : const bool bDelFwrd = rMkNdIdx.GetIndex() <= rPtNdIdx.GetIndex();
176 :
177 14310 : SwDoc* pDoc = rMkNdIdx.GetNode().GetDoc();
178 14310 : SwFrmFmts& rTbl = *pDoc->GetSpzFrmFmts();
179 93780 : for ( sal_uInt16 i = rTbl.size(); i; )
180 : {
181 65160 : SwFrmFmt *pFmt = rTbl[--i];
182 65160 : const SwFmtAnchor &rAnch = pFmt->GetAnchor();
183 65160 : SwPosition const*const pAPos = rAnch.GetCntntAnchor();
184 129246 : if (pAPos &&
185 80222 : ((rAnch.GetAnchorId() == FLY_AT_PARA) ||
186 188242 : (rAnch.GetAnchorId() == FLY_AT_CHAR)) &&
187 : ( bDelFwrd
188 89478 : ? rMkNdIdx < pAPos->nNode && pAPos->nNode <= rPtNdIdx
189 184 : : rPtNdIdx <= pAPos->nNode && pAPos->nNode < rMkNdIdx ))
190 : {
191 : // Only move the Anchor??
192 814 : if( rPtNdIdx == pAPos->nNode )
193 : {
194 32 : SwFmtAnchor aAnch( pFmt->GetAnchor() );
195 64 : SwPosition aPos( rMkNdIdx );
196 32 : aAnch.SetAnchor( &aPos );
197 64 : pFmt->SetFmtAttr( aAnch );
198 : }
199 : else
200 : {
201 : // If the Fly is deleted, all Flys in it's content have to be deleted too.
202 782 : const SwFmtCntnt &rCntnt = pFmt->GetCntnt();
203 782 : if( rCntnt.GetCntntIdx() )
204 : {
205 612 : DelFlyInRange( *rCntnt.GetCntntIdx(),
206 : SwNodeIndex( *rCntnt.GetCntntIdx()->
207 1224 : GetNode().EndOfSectionNode() ));
208 : // Position could have been moved!
209 612 : if( i > rTbl.size() )
210 0 : i = rTbl.size();
211 612 : else if( pFmt != rTbl[i] )
212 0 : i = rTbl.GetPos( pFmt );
213 : }
214 :
215 782 : pDoc->getIDocumentLayoutAccess().DelLayoutFmt( pFmt );
216 :
217 : // DelLayoutFmt can also trigger the deletion of objects.
218 782 : if( i > rTbl.size() )
219 0 : i = rTbl.size();
220 : }
221 : }
222 : }
223 14310 : }
224 :
225 : // #i59534: Redo of insertion of multiple text nodes runs into trouble
226 : // because of unnecessary expanded redlines
227 : // From now on this class saves the redline positions of all redlines which ends exact at the
228 : // insert position (node _and_ content index)
229 954 : _SaveRedlEndPosForRestore::_SaveRedlEndPosForRestore( const SwNodeIndex& rInsIdx, sal_Int32 nCnt )
230 954 : : pSavArr( 0 ), pSavIdx( 0 ), nSavCntnt( nCnt )
231 : {
232 954 : SwNode& rNd = rInsIdx.GetNode();
233 954 : SwDoc* pDest = rNd.GetDoc();
234 954 : if( !pDest->getIDocumentRedlineAccess().GetRedlineTbl().empty() )
235 : {
236 : sal_uInt16 nFndPos;
237 : const SwPosition* pEnd;
238 24 : SwPosition aSrcPos( rInsIdx, SwIndex( rNd.GetCntntNode(), nCnt ));
239 24 : pDest->getIDocumentRedlineAccess().GetRedline( aSrcPos, &nFndPos );
240 : const SwRangeRedline* pRedl;
241 48 : while( nFndPos--
242 6 : && *( pEnd = ( pRedl = pDest->getIDocumentRedlineAccess().GetRedlineTbl()[ nFndPos ] )->End() ) == aSrcPos
243 24 : && *pRedl->Start() < aSrcPos )
244 : {
245 0 : if( !pSavArr )
246 : {
247 0 : pSavArr = new std::vector<SwPosition*>;
248 0 : pSavIdx = new SwNodeIndex( rInsIdx, -1 );
249 : }
250 0 : pSavArr->push_back( (SwPosition*)pEnd );
251 24 : }
252 : }
253 954 : }
254 :
255 954 : _SaveRedlEndPosForRestore::~_SaveRedlEndPosForRestore()
256 : {
257 954 : delete pSavArr;
258 954 : delete pSavIdx;
259 954 : }
260 :
261 0 : void _SaveRedlEndPosForRestore::_Restore()
262 : {
263 0 : ++(*pSavIdx);
264 0 : SwCntntNode* pNode = pSavIdx->GetNode().GetCntntNode();
265 : // If there's no content node at the remembered position, we will not restore the old position
266 : // This may happen if a table (or section?) will be inserted.
267 0 : if( pNode )
268 : {
269 0 : SwPosition aPos( *pSavIdx, SwIndex( pNode, nSavCntnt ));
270 0 : for( sal_uInt16 n = pSavArr->size(); n; )
271 0 : *(*pSavArr)[ --n ] = aPos;
272 : }
273 0 : }
274 :
275 0 : void SwDoc::SetModified(SwPaM &rPaM)
276 : {
277 0 : SwDataChanged aTmp( rPaM );
278 0 : getIDocumentState().SetModified();
279 0 : }
280 :
281 : /// Convert list of ranges of whichIds to a corresponding list of whichIds
282 2314 : static std::vector<sal_uInt16> * lcl_RangesToVector(sal_uInt16 * pRanges)
283 : {
284 2314 : std::vector<sal_uInt16> * pResult = new std::vector<sal_uInt16>();
285 :
286 2314 : int i = 0;
287 9256 : while (pRanges[i] != 0)
288 : {
289 : OSL_ENSURE(pRanges[i+1] != 0, "malformed ranges");
290 :
291 106444 : for (sal_uInt16 j = pRanges[i]; j < pRanges[i+1]; j++)
292 101816 : pResult->push_back(j);
293 :
294 4628 : i += 2;
295 : }
296 :
297 2314 : return pResult;
298 : }
299 :
300 9266 : void sw_GetJoinFlags( SwPaM& rPam, bool& rJoinTxt, bool& rJoinPrev )
301 : {
302 9266 : rJoinTxt = false;
303 9266 : rJoinPrev = false;
304 9266 : if( rPam.GetPoint()->nNode != rPam.GetMark()->nNode )
305 : {
306 5022 : const SwPosition* pStt = rPam.Start(), *pEnd = rPam.End();
307 5022 : SwTxtNode *pSttNd = pStt->nNode.GetNode().GetTxtNode();
308 5022 : if( pSttNd )
309 : {
310 5018 : SwTxtNode *pEndNd = pEnd->nNode.GetNode().GetTxtNode();
311 5018 : rJoinTxt = 0 != pEndNd;
312 5018 : if( rJoinTxt )
313 : {
314 5018 : bool bExchange = pStt == rPam.GetPoint();
315 7462 : if( !pStt->nContent.GetIndex() &&
316 2444 : pEndNd->GetTxt().getLength() != pEnd->nContent.GetIndex())
317 130 : bExchange = !bExchange;
318 5018 : if( bExchange )
319 4860 : rPam.Exchange();
320 5018 : rJoinPrev = rPam.GetPoint() == pStt;
321 : OSL_ENSURE( !pStt->nContent.GetIndex() &&
322 : pEndNd->GetTxt().getLength() != pEnd->nContent.GetIndex()
323 : ? rPam.GetPoint()->nNode < rPam.GetMark()->nNode
324 : : rPam.GetPoint()->nNode > rPam.GetMark()->nNode,
325 : "sw_GetJoinFlags");
326 : }
327 : }
328 : }
329 9266 : }
330 :
331 5018 : void sw_JoinText( SwPaM& rPam, bool bJoinPrev )
332 : {
333 5018 : SwNodeIndex aIdx( rPam.GetPoint()->nNode );
334 5018 : SwTxtNode *pTxtNd = aIdx.GetNode().GetTxtNode();
335 10036 : SwNodeIndex aOldIdx( aIdx );
336 5018 : SwTxtNode *pOldTxtNd = pTxtNd;
337 :
338 5018 : if( pTxtNd && pTxtNd->CanJoinNext( &aIdx ) )
339 : {
340 5018 : SwDoc* pDoc = rPam.GetDoc();
341 5018 : if( bJoinPrev )
342 : {
343 : // We do not need to handle xmlids in this case, because
344 : // it is only invoked if one paragraph is completely empty
345 : // (see sw_GetJoinFlags)
346 : {
347 : // If PageBreaks are deleted/set, it must not be added to the Undo history!
348 : // Also, deleteing the Node is not added to the Undo histroy!
349 130 : ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
350 :
351 : /* PageBreaks, PageDesc, ColumnBreaks */
352 : // If we need to change something about the logic to copy the PageBreaks,
353 : // PageDesc, etc. we also have to change SwUndoDelete.
354 : // There, we copy the AUTO PageBreak from the GetMarkNode!
355 :
356 : /* The GetMarkNode */
357 130 : if( ( pTxtNd = aIdx.GetNode().GetTxtNode())->HasSwAttrSet() )
358 : {
359 : const SfxPoolItem* pItem;
360 0 : if( SfxItemState::SET == pTxtNd->GetpSwAttrSet()->GetItemState(
361 0 : RES_BREAK, false, &pItem ) )
362 0 : pTxtNd->ResetAttr( RES_BREAK );
363 0 : if( pTxtNd->HasSwAttrSet() &&
364 0 : SfxItemState::SET == pTxtNd->GetpSwAttrSet()->GetItemState(
365 0 : RES_PAGEDESC, false, &pItem ) )
366 0 : pTxtNd->ResetAttr( RES_PAGEDESC );
367 : }
368 :
369 : /* The PointNode */
370 130 : if( pOldTxtNd->HasSwAttrSet() )
371 : {
372 : const SfxPoolItem* pItem;
373 0 : SfxItemSet aSet( pDoc->GetAttrPool(), aBreakSetRange );
374 0 : const SfxItemSet* pSet = pOldTxtNd->GetpSwAttrSet();
375 0 : if( SfxItemState::SET == pSet->GetItemState( RES_BREAK,
376 0 : false, &pItem ) )
377 0 : aSet.Put( *pItem );
378 0 : if( SfxItemState::SET == pSet->GetItemState( RES_PAGEDESC,
379 0 : false, &pItem ) )
380 0 : aSet.Put( *pItem );
381 0 : if( aSet.Count() )
382 0 : pTxtNd->SetAttr( aSet );
383 : }
384 130 : pOldTxtNd->FmtToTxtAttr( pTxtNd );
385 :
386 260 : const boost::shared_ptr< sw::mark::CntntIdxStore> pCntntStore(sw::mark::CntntIdxStore::Create());
387 130 : pCntntStore->Save( pDoc, aOldIdx.GetIndex(), pOldTxtNd->Len() );
388 :
389 260 : SwIndex aAlphaIdx(pTxtNd);
390 130 : pOldTxtNd->CutText( pTxtNd, aAlphaIdx, SwIndex(pOldTxtNd),
391 260 : pOldTxtNd->Len() );
392 260 : SwPosition aAlphaPos( aIdx, aAlphaIdx );
393 130 : pDoc->CorrRel( rPam.GetPoint()->nNode, aAlphaPos, 0, true );
394 :
395 : // move all Bookmarks/TOXMarks
396 130 : if( !pCntntStore->Empty() )
397 0 : pCntntStore->Restore( pDoc, aIdx.GetIndex() );
398 :
399 : // If the passed PaM is not in the Crsr ring,
400 : // treat it separately (e.g. when it's being called from AutoFormat)
401 130 : if( pOldTxtNd == rPam.GetBound( true ).nContent.GetIdxReg() )
402 0 : rPam.GetBound( true ) = aAlphaPos;
403 130 : if( pOldTxtNd == rPam.GetBound( false ).nContent.GetIdxReg() )
404 130 : rPam.GetBound( false ) = aAlphaPos;
405 : }
406 : // delete the Node, at last!
407 130 : pDoc->GetNodes().Delete( aOldIdx, 1 );
408 : }
409 : else
410 : {
411 4888 : SwTxtNode* pDelNd = aIdx.GetNode().GetTxtNode();
412 4888 : if( pTxtNd->Len() )
413 2574 : pDelNd->FmtToTxtAttr( pTxtNd );
414 : else
415 : {
416 : /* This case was missed:
417 :
418 : <something></something> <-- pTxtNd
419 : <other>ccc</other> <-- pDelNd
420 :
421 : <something> and <other> are paragraph
422 : attributes. The attribute <something> stayed if not
423 : overwritten by an attribute in "ccc". Fixed by
424 : first resetting all character attributes in first
425 : paragraph (pTxtNd).
426 : */
427 : std::vector<sal_uInt16> * pShorts =
428 2314 : lcl_RangesToVector(aCharFmtSetRange);
429 2314 : pTxtNd->ResetAttr(*pShorts);
430 2314 : delete pShorts;
431 :
432 2314 : if( pDelNd->HasSwAttrSet() )
433 : {
434 : // only copy the character attributes
435 260 : SfxItemSet aTmpSet( pDoc->GetAttrPool(), aCharFmtSetRange );
436 260 : aTmpSet.Put( *pDelNd->GetpSwAttrSet() );
437 260 : pTxtNd->SetAttr( aTmpSet );
438 : }
439 : }
440 :
441 4888 : pDoc->CorrRel( aIdx, *rPam.GetPoint(), 0, true );
442 : // #i100466# adjust given <rPam>, if it does not belong to the cursors
443 4888 : if ( pDelNd == rPam.GetBound( true ).nContent.GetIdxReg() )
444 : {
445 0 : rPam.GetBound( true ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
446 : }
447 4888 : if( pDelNd == rPam.GetBound( false ).nContent.GetIdxReg() )
448 : {
449 0 : rPam.GetBound( false ) = SwPosition( SwNodeIndex( *pTxtNd ), SwIndex( pTxtNd ) );
450 : }
451 4888 : pTxtNd->JoinNext();
452 : }
453 5018 : }
454 5018 : }
455 :
456 0 : static void lcl_syncGrammarError( SwTxtNode &rTxtNode, linguistic2::ProofreadingResult& rResult,
457 : const ModelToViewHelper &rConversionMap )
458 : {
459 0 : if( rTxtNode.IsGrammarCheckDirty() )
460 0 : return;
461 0 : SwGrammarMarkUp* pWrong = rTxtNode.GetGrammarCheck();
462 0 : linguistic2::SingleProofreadingError* pArray = rResult.aErrors.getArray();
463 0 : sal_uInt16 i, j = 0;
464 0 : if( pWrong )
465 : {
466 0 : for( i = 0; i < rResult.aErrors.getLength(); ++i )
467 : {
468 0 : const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i];
469 0 : const sal_Int32 nStart = rConversionMap.ConvertToModelPosition( rError.nErrorStart ).mnPos;
470 0 : const sal_Int32 nEnd = rConversionMap.ConvertToModelPosition( rError.nErrorStart + rError.nErrorLength ).mnPos;
471 0 : if( i != j )
472 0 : pArray[j] = pArray[i];
473 0 : if( pWrong->LookForEntry( nStart, nEnd ) )
474 0 : ++j;
475 : }
476 : }
477 0 : if( rResult.aErrors.getLength() > j )
478 0 : rResult.aErrors.realloc( j );
479 : }
480 :
481 12 : uno::Any SwDoc::Spell( SwPaM& rPaM,
482 : uno::Reference< XSpellChecker1 > &xSpeller,
483 : sal_uInt16* pPageCnt, sal_uInt16* pPageSt,
484 : bool bGrammarCheck,
485 : SwConversionArgs *pConvArgs ) const
486 : {
487 12 : SwPosition* pSttPos = rPaM.Start(), *pEndPos = rPaM.End();
488 :
489 12 : SwSpellArgs *pSpellArgs = 0;
490 12 : if (pConvArgs)
491 : {
492 12 : pConvArgs->SetStart(pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent);
493 12 : pConvArgs->SetEnd( pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent );
494 : }
495 : else
496 : pSpellArgs = new SwSpellArgs( xSpeller,
497 0 : pSttPos->nNode.GetNode().GetTxtNode(), pSttPos->nContent,
498 0 : pEndPos->nNode.GetNode().GetTxtNode(), pEndPos->nContent,
499 0 : bGrammarCheck );
500 :
501 12 : sal_uLong nCurrNd = pSttPos->nNode.GetIndex();
502 12 : sal_uLong nEndNd = pEndPos->nNode.GetIndex();
503 :
504 12 : uno::Any aRet;
505 12 : if( nCurrNd <= nEndNd )
506 : {
507 : SwCntntFrm* pCntFrm;
508 12 : bool bGoOn = true;
509 36 : while( bGoOn )
510 : {
511 12 : SwNode* pNd = GetNodes()[ nCurrNd ];
512 12 : switch( pNd->GetNodeType() )
513 : {
514 : case ND_TEXTNODE:
515 12 : if( 0 != ( pCntFrm = ((SwTxtNode*)pNd)->getLayoutFrm( getIDocumentLayoutAccess().GetCurrentLayout() )) )
516 : {
517 : // skip protected and hidden Cells and Flys
518 12 : if( pCntFrm->IsProtected() )
519 : {
520 0 : nCurrNd = pNd->EndOfSectionIndex();
521 : }
522 12 : else if( !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
523 : {
524 12 : if( pPageCnt && *pPageCnt && pPageSt )
525 : {
526 12 : sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
527 12 : if( !*pPageSt )
528 : {
529 8 : *pPageSt = nPageNr;
530 8 : if( *pPageCnt < *pPageSt )
531 0 : *pPageCnt = *pPageSt;
532 : }
533 : long nStat;
534 12 : if( nPageNr >= *pPageSt )
535 12 : nStat = nPageNr - *pPageSt + 1;
536 : else
537 0 : nStat = nPageNr + *pPageCnt - *pPageSt + 1;
538 12 : ::SetProgressState( nStat, (SwDocShell*)GetDocShell() );
539 : }
540 : //Spell() changes the pSpellArgs in case an error is found
541 12 : sal_Int32 nBeginGrammarCheck = 0;
542 12 : sal_Int32 nEndGrammarCheck = 0;
543 12 : if( pSpellArgs && pSpellArgs->bIsGrammarCheck)
544 : {
545 0 : nBeginGrammarCheck = pSpellArgs->pStartNode == pNd ? pSpellArgs->pStartIdx->GetIndex() : 0;
546 : // if grammar checking starts inside of a sentence the start position has to be adjusted
547 0 : if( nBeginGrammarCheck )
548 : {
549 0 : SwIndex aStartIndex( dynamic_cast< SwTxtNode* >( pNd ), nBeginGrammarCheck );
550 0 : SwPosition aStart( *pNd, aStartIndex );
551 0 : SwCursor aCrsr(aStart, 0, false);
552 0 : SwPosition aOrigPos = *aCrsr.GetPoint();
553 0 : aCrsr.GoSentence( SwCursor::START_SENT );
554 0 : if( aOrigPos != *aCrsr.GetPoint() )
555 : {
556 0 : nBeginGrammarCheck = aCrsr.GetPoint()->nContent.GetIndex();
557 0 : }
558 : }
559 0 : nEndGrammarCheck = (pSpellArgs->pEndNode == pNd)
560 0 : ? pSpellArgs->pEndIdx->GetIndex()
561 : : static_cast<SwTxtNode const*>(pNd)
562 0 : ->GetTxt().getLength();
563 : }
564 :
565 : sal_Int32 nSpellErrorPosition =
566 12 : static_cast<SwTxtNode const*>(pNd)->GetTxt().getLength();
567 12 : if( (!pConvArgs &&
568 28 : ((SwTxtNode*)pNd)->Spell( pSpellArgs )) ||
569 12 : ( pConvArgs &&
570 12 : ((SwTxtNode*)pNd)->Convert( *pConvArgs )))
571 : {
572 : // Cancel and remember position
573 4 : pSttPos->nNode = nCurrNd;
574 4 : pEndPos->nNode = nCurrNd;
575 4 : nCurrNd = nEndNd;
576 4 : if( pSpellArgs )
577 0 : nSpellErrorPosition = pSpellArgs->pStartIdx->GetIndex() > pSpellArgs->pEndIdx->GetIndex() ?
578 0 : pSpellArgs->pEndIdx->GetIndex() :
579 0 : pSpellArgs->pStartIdx->GetIndex();
580 : }
581 :
582 12 : if( pSpellArgs && pSpellArgs->bIsGrammarCheck )
583 : {
584 0 : uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( GetGCIterator() );
585 0 : if (xGCIterator.is())
586 : {
587 0 : uno::Reference< lang::XComponent > xDoc( ((SwDocShell*)GetDocShell())->GetBaseModel(), uno::UNO_QUERY );
588 : // Expand the string:
589 0 : const ModelToViewHelper aConversionMap(*(SwTxtNode*)pNd);
590 0 : OUString aExpandText = aConversionMap.getViewText();
591 :
592 : // get XFlatParagraph to use...
593 0 : uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *((SwTxtNode*)pNd), aExpandText, aConversionMap );
594 :
595 : // get error position of cursor in XFlatParagraph
596 0 : linguistic2::ProofreadingResult aResult;
597 : sal_Int32 nGrammarErrors;
598 0 : do
599 : {
600 0 : aConversionMap.ConvertToViewPosition( nBeginGrammarCheck );
601 0 : aResult = xGCIterator->checkSentenceAtPosition(
602 0 : xDoc, xFlatPara, aExpandText, lang::Locale(), nBeginGrammarCheck, -1, -1 );
603 :
604 0 : lcl_syncGrammarError( *((SwTxtNode*)pNd), aResult, aConversionMap );
605 :
606 : // get suggestions to use for the specific error position
607 0 : nGrammarErrors = aResult.aErrors.getLength();
608 : // if grammar checking doesn't have any progress then quit
609 0 : if( aResult.nStartOfNextSentencePosition <= nBeginGrammarCheck )
610 0 : break;
611 : // prepare next iteration
612 0 : nBeginGrammarCheck = aResult.nStartOfNextSentencePosition;
613 : }
614 0 : while( nSpellErrorPosition > aResult.nBehindEndOfSentencePosition && !nGrammarErrors && aResult.nBehindEndOfSentencePosition < nEndGrammarCheck );
615 :
616 0 : if( nGrammarErrors > 0 && nSpellErrorPosition >= aResult.nBehindEndOfSentencePosition )
617 : {
618 0 : aRet <<= aResult;
619 : //put the cursor to the current error
620 0 : const linguistic2::SingleProofreadingError &rError = aResult.aErrors[0];
621 0 : nCurrNd = pNd->GetIndex();
622 0 : pSttPos->nNode = nCurrNd;
623 0 : pEndPos->nNode = nCurrNd;
624 0 : pSpellArgs->pStartNode = ((SwTxtNode*)pNd);
625 0 : pSpellArgs->pEndNode = ((SwTxtNode*)pNd);
626 0 : pSpellArgs->pStartIdx->Assign(((SwTxtNode*)pNd), aConversionMap.ConvertToModelPosition( rError.nErrorStart ).mnPos );
627 0 : pSpellArgs->pEndIdx->Assign(((SwTxtNode*)pNd), aConversionMap.ConvertToModelPosition( rError.nErrorStart + rError.nErrorLength ).mnPos );
628 0 : nCurrNd = nEndNd;
629 0 : }
630 0 : }
631 : }
632 : }
633 : }
634 12 : break;
635 : case ND_SECTIONNODE:
636 0 : if( ( ((SwSectionNode*)pNd)->GetSection().IsProtect() ||
637 0 : ((SwSectionNode*)pNd)->GetSection().IsHidden() ) )
638 0 : nCurrNd = pNd->EndOfSectionIndex();
639 0 : break;
640 : case ND_ENDNODE:
641 : {
642 0 : break;
643 : }
644 : }
645 :
646 12 : bGoOn = nCurrNd < nEndNd;
647 12 : ++nCurrNd;
648 : }
649 : }
650 :
651 12 : if( !aRet.hasValue() )
652 : {
653 12 : if (pConvArgs)
654 12 : aRet <<= pConvArgs->aConvText;
655 : else
656 0 : aRet <<= pSpellArgs->xSpellAlt;
657 : }
658 12 : delete pSpellArgs;
659 :
660 12 : return aRet;
661 : }
662 :
663 0 : class SwHyphArgs : public SwInterHyphInfo
664 : {
665 : const SwNode *pStart;
666 : const SwNode *pEnd;
667 : SwNode *pNode;
668 : sal_uInt16 *pPageCnt;
669 : sal_uInt16 *pPageSt;
670 :
671 : sal_uInt32 nNode;
672 : sal_Int32 nPamStart;
673 : sal_Int32 nPamLen;
674 :
675 : public:
676 : SwHyphArgs( const SwPaM *pPam, const Point &rPoint,
677 : sal_uInt16* pPageCount, sal_uInt16* pPageStart );
678 : void SetPam( SwPaM *pPam ) const;
679 0 : inline void SetNode( SwNode *pNew ) { pNode = pNew; }
680 : inline void SetRange( const SwNode *pNew );
681 0 : inline void NextNode() { ++nNode; }
682 0 : inline sal_uInt16 *GetPageCnt() { return pPageCnt; }
683 0 : inline sal_uInt16 *GetPageSt() { return pPageSt; }
684 : };
685 :
686 0 : SwHyphArgs::SwHyphArgs( const SwPaM *pPam, const Point &rCrsrPos,
687 : sal_uInt16* pPageCount, sal_uInt16* pPageStart )
688 : : SwInterHyphInfo( rCrsrPos ), pNode(0),
689 0 : pPageCnt( pPageCount ), pPageSt( pPageStart )
690 : {
691 : // The following constraints have to be met:
692 : // 1) there is at least one Selection
693 : // 2) SPoint() == Start()
694 : OSL_ENSURE( pPam->HasMark(), "SwDoc::Hyphenate: blowing in the wind");
695 : OSL_ENSURE( *pPam->GetPoint() <= *pPam->GetMark(),
696 : "SwDoc::Hyphenate: New York, New York");
697 :
698 0 : const SwPosition *pPoint = pPam->GetPoint();
699 0 : nNode = pPoint->nNode.GetIndex();
700 :
701 : // Set start
702 0 : pStart = pPoint->nNode.GetNode().GetTxtNode();
703 0 : nPamStart = pPoint->nContent.GetIndex();
704 :
705 : // Set End and Length
706 0 : const SwPosition *pMark = pPam->GetMark();
707 0 : pEnd = pMark->nNode.GetNode().GetTxtNode();
708 0 : nPamLen = pMark->nContent.GetIndex();
709 0 : if( pPoint->nNode == pMark->nNode )
710 0 : nPamLen = nPamLen - pPoint->nContent.GetIndex();
711 0 : }
712 :
713 0 : inline void SwHyphArgs::SetRange( const SwNode *pNew )
714 : {
715 0 : nStart = pStart == pNew ? nPamStart : 0;
716 0 : nEnd = pEnd == pNew ? nPamStart + nPamLen : SAL_MAX_INT32;
717 0 : }
718 :
719 0 : void SwHyphArgs::SetPam( SwPaM *pPam ) const
720 : {
721 0 : if( !pNode )
722 0 : *pPam->GetPoint() = *pPam->GetMark();
723 : else
724 : {
725 0 : pPam->GetPoint()->nNode = nNode;
726 0 : pPam->GetPoint()->nContent.Assign( pNode->GetCntntNode(), nWordStart );
727 0 : pPam->GetMark()->nNode = nNode;
728 0 : pPam->GetMark()->nContent.Assign( pNode->GetCntntNode(),
729 0 : nWordStart + nWordLen );
730 : OSL_ENSURE( nNode == pNode->GetIndex(),
731 : "SwHyphArgs::SetPam: Pam disaster" );
732 : }
733 0 : }
734 :
735 : // Returns sal_True if we can proceed.
736 0 : static bool lcl_HyphenateNode( const SwNodePtr& rpNd, void* pArgs )
737 : {
738 : // Hyphenate returns true if there is a hyphenation point and sets pPam
739 0 : SwTxtNode *pNode = rpNd->GetTxtNode();
740 0 : SwHyphArgs *pHyphArgs = (SwHyphArgs*)pArgs;
741 0 : if( pNode )
742 : {
743 0 : SwCntntFrm* pCntFrm = pNode->getLayoutFrm( pNode->GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout() );
744 0 : if( pCntFrm && !((SwTxtFrm*)pCntFrm)->IsHiddenNow() )
745 : {
746 0 : sal_uInt16 *pPageSt = pHyphArgs->GetPageSt();
747 0 : sal_uInt16 *pPageCnt = pHyphArgs->GetPageCnt();
748 0 : if( pPageCnt && *pPageCnt && pPageSt )
749 : {
750 0 : sal_uInt16 nPageNr = pCntFrm->GetPhyPageNum();
751 0 : if( !*pPageSt )
752 : {
753 0 : *pPageSt = nPageNr;
754 0 : if( *pPageCnt < *pPageSt )
755 0 : *pPageCnt = *pPageSt;
756 : }
757 0 : long nStat = nPageNr >= *pPageSt ? nPageNr - *pPageSt + 1
758 0 : : nPageNr + *pPageCnt - *pPageSt + 1;
759 0 : ::SetProgressState( nStat, (SwDocShell*)pNode->GetDoc()->GetDocShell() );
760 : }
761 0 : pHyphArgs->SetRange( rpNd );
762 0 : if( pNode->Hyphenate( *pHyphArgs ) )
763 : {
764 0 : pHyphArgs->SetNode( rpNd );
765 0 : return false;
766 : }
767 : }
768 : }
769 0 : pHyphArgs->NextNode();
770 0 : return true;
771 : }
772 :
773 0 : uno::Reference< XHyphenatedWord > SwDoc::Hyphenate(
774 : SwPaM *pPam, const Point &rCrsrPos,
775 : sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
776 : {
777 : OSL_ENSURE(this == pPam->GetDoc(), "SwDoc::Hyphenate: strangers in the night");
778 :
779 0 : if( *pPam->GetPoint() > *pPam->GetMark() )
780 0 : pPam->Exchange();
781 :
782 0 : SwHyphArgs aHyphArg( pPam, rCrsrPos, pPageCnt, pPageSt );
783 0 : SwNodeIndex aTmpIdx( pPam->GetMark()->nNode, 1 );
784 0 : GetNodes().ForEach( pPam->GetPoint()->nNode, aTmpIdx,
785 0 : lcl_HyphenateNode, &aHyphArg );
786 0 : aHyphArg.SetPam( pPam );
787 0 : return aHyphArg.GetHyphWord(); // will be set by lcl_HyphenateNode
788 : }
789 :
790 : // Save the current values to add them as automatic entries to to AutoCorrect.
791 0 : void SwDoc::SetAutoCorrExceptWord( SwAutoCorrExceptWord* pNew )
792 : {
793 0 : if( pNew != mpACEWord )
794 0 : delete mpACEWord;
795 0 : mpACEWord = pNew;
796 0 : }
797 :
798 0 : void SwDoc::DeleteAutoCorrExceptWord()
799 : {
800 0 : delete mpACEWord;
801 0 : mpACEWord = 0;
802 0 : }
803 :
804 16 : void SwDoc::CountWords( const SwPaM& rPaM, SwDocStat& rStat ) const
805 : {
806 : // This is a modified version of SwDoc::TransliterateText
807 16 : const SwPosition* pStt = rPaM.Start();
808 16 : const SwPosition* pEnd = pStt == rPaM.GetPoint() ? rPaM.GetMark()
809 16 : : rPaM.GetPoint();
810 :
811 16 : const sal_uLong nSttNd = pStt->nNode.GetIndex();
812 16 : const sal_uLong nEndNd = pEnd->nNode.GetIndex();
813 :
814 16 : const sal_Int32 nSttCnt = pStt->nContent.GetIndex();
815 16 : const sal_Int32 nEndCnt = pEnd->nContent.GetIndex();
816 :
817 16 : const SwTxtNode* pTNd = pStt->nNode.GetNode().GetTxtNode();
818 16 : if( pStt == pEnd && pTNd ) // no region ?
819 : {
820 : // do nothing
821 16 : return;
822 : }
823 :
824 16 : if( nSttNd != nEndNd )
825 : {
826 0 : SwNodeIndex aIdx( pStt->nNode );
827 0 : if( nSttCnt )
828 : {
829 0 : ++aIdx;
830 0 : if( pTNd )
831 0 : pTNd->CountWords( rStat, nSttCnt, pTNd->GetTxt().getLength() );
832 : }
833 :
834 0 : for( ; aIdx.GetIndex() < nEndNd; ++aIdx )
835 0 : if( 0 != ( pTNd = aIdx.GetNode().GetTxtNode() ))
836 0 : pTNd->CountWords( rStat, 0, pTNd->GetTxt().getLength() );
837 :
838 0 : if( nEndCnt && 0 != ( pTNd = pEnd->nNode.GetNode().GetTxtNode() ))
839 0 : pTNd->CountWords( rStat, 0, nEndCnt );
840 : }
841 16 : else if( pTNd && nSttCnt < nEndCnt )
842 0 : pTNd->CountWords( rStat, nSttCnt, nEndCnt );
843 270 : }
844 :
845 :
846 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|