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