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 <com/sun/star/linguistic2/ProofreadingResult.hpp>
21 : #include <com/sun/star/linguistic2/XProofreader.hpp>
22 : #include <com/sun/star/linguistic2/XProofreadingIterator.hpp>
23 : #include <com/sun/star/text/XFlatParagraph.hpp>
24 : #include <comphelper/string.hxx>
25 :
26 : #include <unoflatpara.hxx>
27 :
28 : #include <comcore.hrc>
29 : #include <hintids.hxx>
30 : #include <linguistic/lngprops.hxx>
31 : #include <vcl/msgbox.hxx>
32 : #include <editeng/unolingu.hxx>
33 : #include <editeng/svxacorr.hxx>
34 : #include <editeng/langitem.hxx>
35 : #include <editeng/SpellPortions.hxx>
36 : #include <editeng/scripttypeitem.hxx>
37 : #include <charatr.hxx>
38 : #include <editsh.hxx>
39 : #include <doc.hxx>
40 : #include <IDocumentUndoRedo.hxx>
41 : #include <rootfrm.hxx>
42 : #include <pam.hxx>
43 : #include <swundo.hxx>
44 : #include <ndtxt.hxx>
45 : #include <viewopt.hxx>
46 : #include <viscrs.hxx>
47 : #include <SwGrammarMarkUp.hxx>
48 : #include <mdiexp.hxx>
49 : #include <statstr.hrc>
50 : #include <cntfrm.hxx>
51 : #include <crsskip.hxx>
52 : #include <splargs.hxx>
53 : #include <redline.hxx>
54 : #include <docary.hxx>
55 : #include <docsh.hxx>
56 : #include <txatbase.hxx>
57 : #include <txtfrm.hxx>
58 :
59 : using namespace ::svx;
60 : using namespace ::com::sun::star;
61 : using namespace ::com::sun::star::uno;
62 : using namespace ::com::sun::star::beans;
63 : using namespace ::com::sun::star::linguistic2;
64 :
65 : class SwLinguIter
66 : {
67 : SwEditShell *pSh;
68 : SwPosition *pStart;
69 : SwPosition *pEnd;
70 : SwPosition *pCurr;
71 : SwPosition *pCurrX;
72 : sal_uInt16 nCrsrCnt;
73 : public:
74 : SwLinguIter();
75 :
76 0 : inline SwEditShell *GetSh() { return pSh; }
77 : inline const SwEditShell *GetSh() const { return pSh; }
78 :
79 0 : inline const SwPosition *GetEnd() const { return pEnd; }
80 0 : inline void SetEnd( SwPosition* pNew ){ delete pEnd; pEnd = pNew; }
81 :
82 0 : inline const SwPosition *GetStart() const { return pStart; }
83 0 : inline void SetStart( SwPosition* pNew ){ delete pStart; pStart = pNew; }
84 :
85 0 : inline const SwPosition *GetCurr() const { return pCurr; }
86 0 : inline void SetCurr( SwPosition* pNew ){ delete pCurr; pCurr = pNew; }
87 :
88 0 : inline const SwPosition *GetCurrX() const { return pCurrX; }
89 0 : inline void SetCurrX( SwPosition* pNew ){ delete pCurrX; pCurrX = pNew; }
90 :
91 0 : inline sal_uInt16& GetCrsrCnt(){ return nCrsrCnt; }
92 :
93 : // for the UI:
94 : void _Start( SwEditShell *pSh, SwDocPositions eStart,
95 : SwDocPositions eEnd );
96 : void _End(bool bRestoreSelection = true);
97 : };
98 :
99 : // #i18881# to be able to identify the postions of the changed words
100 : // the content positions of each portion need to be saved
101 : struct SpellContentPosition
102 : {
103 : sal_Int32 nLeft;
104 : sal_Int32 nRight;
105 : };
106 :
107 : typedef std::vector<SpellContentPosition> SpellContentPositions;
108 :
109 0 : class SwSpellIter : public SwLinguIter
110 : {
111 : uno::Reference< XSpellChecker1 > xSpeller;
112 : ::svx::SpellPortions aLastPortions;
113 :
114 : SpellContentPositions aLastPositions;
115 : bool bBackToStartOfSentence;
116 : bool bMoveToEndOfSentence;
117 :
118 : void CreatePortion(uno::Reference< XSpellAlternatives > xAlt,
119 : linguistic2::ProofreadingResult* pGrammarResult,
120 : bool bIsField, bool bIsHidden);
121 :
122 : void AddPortion(uno::Reference< XSpellAlternatives > xAlt,
123 : linguistic2::ProofreadingResult* pGrammarResult,
124 : const SpellContentPositions& rDeletedRedlines);
125 : public:
126 0 : SwSpellIter() :
127 0 : bBackToStartOfSentence(false), bMoveToEndOfSentence(false) {}
128 :
129 : void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd );
130 :
131 : uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt );
132 :
133 : bool SpellSentence(::svx::SpellPortions& rPortions, bool bIsGrammarCheck);
134 : void ToSentenceStart();
135 0 : const ::svx::SpellPortions GetLastPortions() const { return aLastPortions;}
136 0 : SpellContentPositions GetLastPositions() const {return aLastPositions;}
137 0 : void ContinueAfterThisSentence() { bMoveToEndOfSentence = true; }
138 : };
139 :
140 : /// used for text conversion
141 : class SwConvIter : public SwLinguIter
142 : {
143 : SwConversionArgs &rArgs;
144 : public:
145 0 : SwConvIter( SwConversionArgs &rConvArgs ) :
146 0 : rArgs( rConvArgs )
147 0 : {}
148 :
149 : void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd );
150 :
151 : uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt );
152 : };
153 :
154 : class SwHyphIter : public SwLinguIter
155 : {
156 : sal_Bool bOldIdle;
157 : void DelSoftHyph( SwPaM &rPam );
158 :
159 : public:
160 0 : SwHyphIter() : bOldIdle(sal_False) {}
161 :
162 : void Start( SwEditShell *pSh, SwDocPositions eStart, SwDocPositions eEnd );
163 : void End();
164 :
165 : void Ignore();
166 :
167 : uno::Any Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt );
168 :
169 : sal_Bool IsAuto();
170 : void InsertSoftHyph( const sal_Int32 nHyphPos );
171 : void ShowSelection();
172 : };
173 :
174 : static SwSpellIter* pSpellIter = 0;
175 : static SwConvIter* pConvIter = 0;
176 : static SwHyphIter* pHyphIter = 0;
177 :
178 : // With that we save a GetFrm() in Hyphenate.
179 : // Caution: There are external declaration to these pointers in txtedt.cxx!
180 : const SwTxtNode *pLinguNode;
181 : SwTxtFrm *pLinguFrm;
182 :
183 0 : SwLinguIter::SwLinguIter()
184 : : pSh(0)
185 : , pStart(0)
186 : , pEnd(0)
187 : , pCurr(0)
188 : , pCurrX(0)
189 0 : , nCrsrCnt(0)
190 : {
191 : // TODO missing: ensurance of re-entrance, OSL_ENSURE( etc.
192 0 : }
193 :
194 0 : void SwLinguIter::_Start( SwEditShell *pShell, SwDocPositions eStart,
195 : SwDocPositions eEnd )
196 : {
197 : // TODO missing: ensurance of re-entrance, locking
198 0 : if( pSh )
199 0 : return;
200 :
201 : bool bSetCurr;
202 :
203 0 : pSh = pShell;
204 :
205 0 : SET_CURR_SHELL( pSh );
206 :
207 : OSL_ENSURE( !pEnd, "SwLinguIter::_Start without End?");
208 :
209 0 : SwPaM *pCrsr = pSh->GetCrsr();
210 :
211 0 : if( pShell->HasSelection() || pCrsr != pCrsr->GetNext() )
212 : {
213 0 : bSetCurr = 0 != GetCurr();
214 0 : nCrsrCnt = pSh->GetCrsrCnt();
215 0 : if( pSh->IsTableMode() )
216 0 : pSh->TblCrsrToCursor();
217 :
218 0 : pSh->Push();
219 : sal_uInt16 n;
220 0 : for( n = 0; n < nCrsrCnt; ++n )
221 : {
222 0 : pSh->Push();
223 0 : pSh->DestroyCrsr();
224 : }
225 0 : pSh->Pop( sal_False );
226 : }
227 : else
228 : {
229 0 : bSetCurr = false;
230 0 : nCrsrCnt = 1;
231 0 : pSh->Push();
232 0 : pSh->SetLinguRange( eStart, eEnd );
233 : }
234 :
235 0 : pCrsr = pSh->GetCrsr();
236 0 : if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
237 0 : pCrsr->Exchange();
238 :
239 0 : pStart = new SwPosition( *pCrsr->GetPoint() );
240 0 : pEnd = new SwPosition( *pCrsr->GetMark() );
241 0 : if( bSetCurr )
242 : {
243 0 : SwPosition* pNew = new SwPosition( *GetStart() );
244 0 : SetCurr( pNew );
245 0 : pNew = new SwPosition( *pNew );
246 0 : SetCurrX( pNew );
247 : }
248 :
249 0 : pCrsr->SetMark();
250 :
251 0 : pLinguFrm = 0;
252 0 : pLinguNode = 0;
253 : }
254 :
255 0 : void SwLinguIter::_End(bool bRestoreSelection)
256 : {
257 0 : if( !pSh )
258 0 : return;
259 :
260 : OSL_ENSURE( pEnd, "SwLinguIter::_End without end?");
261 0 : if(bRestoreSelection)
262 : {
263 0 : while( nCrsrCnt-- )
264 0 : pSh->Pop( sal_False );
265 :
266 0 : pSh->KillPams();
267 0 : pSh->ClearMark();
268 : }
269 0 : DELETEZ(pStart);
270 0 : DELETEZ(pEnd);
271 0 : DELETEZ(pCurr);
272 0 : DELETEZ(pCurrX);
273 :
274 0 : pSh = 0;
275 : }
276 :
277 0 : void SwSpellIter::Start( SwEditShell *pShell, SwDocPositions eStart,
278 : SwDocPositions eEnd )
279 : {
280 0 : if( GetSh() )
281 0 : return;
282 :
283 0 : xSpeller = ::GetSpellChecker();
284 0 : if ( xSpeller.is() )
285 0 : _Start( pShell, eStart, eEnd );
286 0 : aLastPortions.clear();
287 0 : aLastPositions.clear();
288 : }
289 :
290 : // This method is the origin of SwEditShell::SpellContinue()
291 0 : uno::Any SwSpellIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
292 : {
293 : //!!
294 : //!! Please check SwConvIter also when modifying this
295 : //!!
296 :
297 0 : uno::Any aSpellRet;
298 0 : SwEditShell *pMySh = GetSh();
299 0 : if( !pMySh )
300 0 : return aSpellRet;
301 :
302 : OSL_ENSURE( GetEnd(), "SwSpellIter::Continue without start?");
303 :
304 0 : uno::Reference< uno::XInterface > xSpellRet;
305 0 : bool bGoOn = true;
306 0 : do {
307 0 : SwPaM *pCrsr = pMySh->GetCrsr();
308 0 : if ( !pCrsr->HasMark() )
309 0 : pCrsr->SetMark();
310 :
311 0 : uno::Reference< beans::XPropertySet > xProp( GetLinguPropertySet() );
312 0 : *pMySh->GetCrsr()->GetPoint() = *GetCurr();
313 0 : *pMySh->GetCrsr()->GetMark() = *GetEnd();
314 0 : pMySh->GetDoc()->Spell(*pMySh->GetCrsr(),
315 0 : xSpeller, pPageCnt, pPageSt, false ) >>= xSpellRet;
316 0 : bGoOn = GetCrsrCnt() > 1;
317 0 : if( xSpellRet.is() )
318 : {
319 0 : bGoOn = false;
320 0 : SwPosition* pNewPoint = new SwPosition( *pCrsr->GetPoint() );
321 0 : SwPosition* pNewMark = new SwPosition( *pCrsr->GetMark() );
322 0 : SetCurr( pNewPoint );
323 0 : SetCurrX( pNewMark );
324 : }
325 0 : if( bGoOn )
326 : {
327 0 : pMySh->Pop( sal_False );
328 0 : pCrsr = pMySh->GetCrsr();
329 0 : if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
330 0 : pCrsr->Exchange();
331 0 : SwPosition* pNew = new SwPosition( *pCrsr->GetPoint() );
332 0 : SetStart( pNew );
333 0 : pNew = new SwPosition( *pCrsr->GetMark() );
334 0 : SetEnd( pNew );
335 0 : pNew = new SwPosition( *GetStart() );
336 0 : SetCurr( pNew );
337 0 : pNew = new SwPosition( *pNew );
338 0 : SetCurrX( pNew );
339 0 : pCrsr->SetMark();
340 0 : --GetCrsrCnt();
341 0 : }
342 : }while ( bGoOn );
343 0 : aSpellRet <<= xSpellRet;
344 0 : return aSpellRet;
345 : }
346 :
347 0 : void SwConvIter::Start( SwEditShell *pShell, SwDocPositions eStart,
348 : SwDocPositions eEnd )
349 : {
350 0 : if( GetSh() )
351 0 : return;
352 0 : _Start( pShell, eStart, eEnd );
353 : }
354 :
355 0 : uno::Any SwConvIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
356 : {
357 : //!!
358 : //!! Please check SwSpellIter also when modifying this
359 : //!!
360 :
361 0 : uno::Any aConvRet( makeAny( OUString() ) );
362 0 : SwEditShell *pMySh = GetSh();
363 0 : if( !pMySh )
364 0 : return aConvRet;
365 :
366 : OSL_ENSURE( GetEnd(), "SwConvIter::Continue() without Start?");
367 :
368 0 : OUString aConvText;
369 0 : bool bGoOn = true;
370 0 : do {
371 0 : SwPaM *pCrsr = pMySh->GetCrsr();
372 0 : if ( !pCrsr->HasMark() )
373 0 : pCrsr->SetMark();
374 :
375 0 : *pMySh->GetCrsr()->GetPoint() = *GetCurr();
376 0 : *pMySh->GetCrsr()->GetMark() = *GetEnd();
377 :
378 : // call function to find next text portion to be converted
379 0 : uno::Reference< linguistic2::XSpellChecker1 > xEmpty;
380 0 : pMySh->GetDoc()->Spell( *pMySh->GetCrsr(),
381 0 : xEmpty, pPageCnt, pPageSt, false, &rArgs ) >>= aConvText;
382 :
383 0 : bGoOn = GetCrsrCnt() > 1;
384 0 : if( !aConvText.isEmpty() )
385 : {
386 0 : bGoOn = false;
387 0 : SwPosition* pNewPoint = new SwPosition( *pCrsr->GetPoint() );
388 0 : SwPosition* pNewMark = new SwPosition( *pCrsr->GetMark() );
389 :
390 0 : SetCurr( pNewPoint );
391 0 : SetCurrX( pNewMark );
392 : }
393 0 : if( bGoOn )
394 : {
395 0 : pMySh->Pop( sal_False );
396 0 : pCrsr = pMySh->GetCrsr();
397 0 : if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
398 0 : pCrsr->Exchange();
399 0 : SwPosition* pNew = new SwPosition( *pCrsr->GetPoint() );
400 0 : SetStart( pNew );
401 0 : pNew = new SwPosition( *pCrsr->GetMark() );
402 0 : SetEnd( pNew );
403 0 : pNew = new SwPosition( *GetStart() );
404 0 : SetCurr( pNew );
405 0 : pNew = new SwPosition( *pNew );
406 0 : SetCurrX( pNew );
407 0 : pCrsr->SetMark();
408 0 : --GetCrsrCnt();
409 0 : }
410 : }while ( bGoOn );
411 0 : return makeAny( aConvText );
412 : }
413 :
414 0 : sal_Bool SwHyphIter::IsAuto()
415 : {
416 0 : uno::Reference< beans::XPropertySet > xProp( ::GetLinguPropertySet() );
417 0 : return xProp.is() ? *(sal_Bool*)xProp->getPropertyValue(
418 0 : OUString(UPN_IS_HYPH_AUTO) ).getValue()
419 0 : : sal_False;
420 : }
421 :
422 0 : void SwHyphIter::ShowSelection()
423 : {
424 0 : SwEditShell *pMySh = GetSh();
425 0 : if( pMySh )
426 : {
427 0 : pMySh->StartAction();
428 : // Caution! Due to EndAction() formatting is started which can lead to the fact that new
429 : // words are added to/set in the Hyphenator. Thus: save!
430 0 : pMySh->EndAction();
431 : }
432 0 : }
433 :
434 0 : void SwHyphIter::Start( SwEditShell *pShell, SwDocPositions eStart, SwDocPositions eEnd )
435 : {
436 : // robust
437 0 : if( GetSh() || GetEnd() )
438 : {
439 : OSL_ENSURE( !GetSh(), "SwHyphIter::Start: missing HyphEnd()" );
440 0 : return;
441 : }
442 :
443 : // nothing to do (at least not in the way as in the "else" part)
444 0 : bOldIdle = pShell->GetViewOptions()->IsIdle();
445 0 : ((SwViewOption*)pShell->GetViewOptions())->SetIdle( sal_False );
446 0 : _Start( pShell, eStart, eEnd );
447 : }
448 :
449 : // restore selections
450 0 : void SwHyphIter::End()
451 : {
452 0 : if( !GetSh() )
453 0 : return;
454 0 : ((SwViewOption*)GetSh()->GetViewOptions())->SetIdle( bOldIdle );
455 0 : _End();
456 : }
457 :
458 0 : uno::Any SwHyphIter::Continue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
459 : {
460 0 : uno::Any aHyphRet;
461 0 : SwEditShell *pMySh = GetSh();
462 0 : if( !pMySh )
463 0 : return aHyphRet;
464 :
465 0 : const bool bAuto = IsAuto();
466 0 : uno::Reference< XHyphenatedWord > xHyphWord;
467 0 : bool bGoOn = false;
468 0 : do {
469 : SwPaM *pCrsr;
470 0 : do {
471 : OSL_ENSURE( GetEnd(), "SwHyphIter::Continue without Start?" );
472 0 : pCrsr = pMySh->GetCrsr();
473 0 : if ( !pCrsr->HasMark() )
474 0 : pCrsr->SetMark();
475 0 : if ( *pCrsr->GetPoint() < *pCrsr->GetMark() )
476 : {
477 0 : pCrsr->Exchange();
478 0 : pCrsr->SetMark();
479 : }
480 :
481 0 : if ( *pCrsr->End() <= *GetEnd() )
482 : {
483 0 : *pCrsr->GetMark() = *GetEnd();
484 :
485 : // Do we need to break the word at the current cursor position?
486 0 : const Point aCrsrPos( pMySh->GetCharRect().Pos() );
487 0 : xHyphWord = pMySh->GetDoc()->Hyphenate( pCrsr, aCrsrPos,
488 0 : pPageCnt, pPageSt );
489 : }
490 :
491 0 : if( bAuto && xHyphWord.is() )
492 : {
493 0 : pMySh->InsertSoftHyph( xHyphWord->getHyphenationPos() + 1);
494 : }
495 0 : } while( bAuto && xHyphWord.is() ); //end of do-while
496 0 : bGoOn = !xHyphWord.is() && GetCrsrCnt() > 1;
497 :
498 0 : if( bGoOn )
499 : {
500 0 : pMySh->Pop( sal_False );
501 0 : pCrsr = pMySh->GetCrsr();
502 0 : if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
503 0 : pCrsr->Exchange();
504 0 : SwPosition* pNew = new SwPosition(*pCrsr->End());
505 0 : SetEnd( pNew );
506 0 : pCrsr->SetMark();
507 0 : --GetCrsrCnt();
508 : }
509 : } while ( bGoOn );
510 0 : aHyphRet <<= xHyphWord;
511 0 : return aHyphRet;
512 : }
513 :
514 : /// ignore hyphenation
515 0 : void SwHyphIter::Ignore()
516 : {
517 0 : SwEditShell *pMySh = GetSh();
518 0 : SwPaM *pCrsr = pMySh->GetCrsr();
519 :
520 : // delete old SoftHyphen
521 0 : DelSoftHyph( *pCrsr );
522 :
523 : // and continue
524 0 : pCrsr->Start()->nContent = pCrsr->End()->nContent;
525 0 : pCrsr->SetMark();
526 0 : }
527 :
528 0 : void SwHyphIter::DelSoftHyph( SwPaM &rPam )
529 : {
530 0 : const SwPosition* pStt = rPam.Start();
531 0 : const sal_Int32 nStart = pStt->nContent.GetIndex();
532 0 : const sal_Int32 nEnd = rPam.End()->nContent.GetIndex();
533 0 : SwTxtNode *pNode = pStt->nNode.GetNode().GetTxtNode();
534 0 : pNode->DelSoftHyph( nStart, nEnd );
535 0 : }
536 :
537 0 : void SwHyphIter::InsertSoftHyph( const sal_Int32 nHyphPos )
538 : {
539 0 : SwEditShell *pMySh = GetSh();
540 : OSL_ENSURE( pMySh, "SwHyphIter::InsertSoftHyph: missing HyphStart()");
541 0 : if( !pMySh )
542 0 : return;
543 :
544 0 : SwPaM *pCrsr = pMySh->GetCrsr();
545 0 : SwPosition* pSttPos = pCrsr->Start();
546 0 : SwPosition* pEndPos = pCrsr->End();
547 :
548 0 : const sal_Int32 nLastHyphLen = GetEnd()->nContent.GetIndex() -
549 0 : pSttPos->nContent.GetIndex();
550 :
551 0 : if( pSttPos->nNode != pEndPos->nNode || !nLastHyphLen )
552 : {
553 : OSL_ENSURE( pSttPos->nNode == pEndPos->nNode,
554 : "SwHyphIter::InsertSoftHyph: node warp during hyphenation" );
555 : OSL_ENSURE(nLastHyphLen, "SwHyphIter::InsertSoftHyph: missing HyphContinue()");
556 0 : *pSttPos = *pEndPos;
557 0 : return;
558 : }
559 :
560 0 : pMySh->StartAction();
561 : {
562 0 : SwDoc *pDoc = pMySh->GetDoc();
563 0 : DelSoftHyph( *pCrsr );
564 0 : pSttPos->nContent += nHyphPos;
565 0 : SwPaM aRg( *pSttPos );
566 0 : pDoc->InsertString( aRg, OUString(CHAR_SOFTHYPHEN) );
567 : }
568 : // revoke selection
569 0 : pCrsr->DeleteMark();
570 0 : pMySh->EndAction();
571 0 : pCrsr->SetMark();
572 : }
573 :
574 0 : bool SwEditShell::HasLastSentenceGotGrammarChecked() const
575 : {
576 0 : bool bTextWasGrammarChecked = false;
577 0 : if (pSpellIter)
578 : {
579 0 : ::svx::SpellPortions aLastPortions( pSpellIter->GetLastPortions() );
580 0 : for (size_t i = 0; i < aLastPortions.size() && !bTextWasGrammarChecked; ++i)
581 : {
582 : // bIsGrammarError is also true if the text was only checked but no
583 : // grammar error was found. (That is if a ProofreadingResult was obtained in
584 : // SwDoc::Spell and in turn bIsGrammarError was set in SwSpellIter::CreatePortion)
585 0 : if (aLastPortions[i].bIsGrammarError)
586 0 : bTextWasGrammarChecked = true;
587 0 : }
588 : }
589 0 : return bTextWasGrammarChecked;
590 : }
591 :
592 0 : sal_Bool SwEditShell::HasConvIter() const
593 : {
594 0 : return 0 != pConvIter;
595 : }
596 :
597 0 : sal_Bool SwEditShell::HasHyphIter() const
598 : {
599 0 : return 0 != pHyphIter;
600 : }
601 :
602 0 : void SwEditShell::SetLinguRange( SwDocPositions eStart, SwDocPositions eEnd )
603 : {
604 0 : SwPaM *pCrsr = GetCrsr();
605 0 : MakeFindRange( static_cast<sal_uInt16>(eStart), static_cast<sal_uInt16>(eEnd), pCrsr );
606 0 : if( *pCrsr->GetPoint() > *pCrsr->GetMark() )
607 0 : pCrsr->Exchange();
608 0 : }
609 :
610 0 : void SwEditShell::SpellStart(
611 : SwDocPositions eStart, SwDocPositions eEnd, SwDocPositions eCurr,
612 : SwConversionArgs *pConvArgs )
613 : {
614 0 : SwLinguIter *pLinguIter = 0;
615 :
616 : // do not spell if interactive spelling is active elsewhere
617 0 : if (!pConvArgs && !pSpellIter)
618 : {
619 : OSL_ENSURE( !pSpellIter, "wer ist da schon am spellen?" );
620 0 : pSpellIter = new SwSpellIter;
621 0 : pLinguIter = pSpellIter;
622 : }
623 : // do not do text conversion if it is active elsewhere
624 0 : if (pConvArgs && !pConvIter)
625 : {
626 : OSL_ENSURE( !pConvIter, "text conversion already active!" );
627 0 : pConvIter = new SwConvIter( *pConvArgs );
628 0 : pLinguIter = pConvIter;
629 : }
630 :
631 0 : if (pLinguIter)
632 : {
633 0 : SwCursor* pSwCrsr = GetSwCrsr();
634 :
635 0 : SwPosition *pTmp = new SwPosition( *pSwCrsr->GetPoint() );
636 0 : pSwCrsr->FillFindPos( eCurr, *pTmp );
637 0 : pLinguIter->SetCurr( pTmp );
638 :
639 0 : pTmp = new SwPosition( *pTmp );
640 0 : pLinguIter->SetCurrX( pTmp );
641 : }
642 :
643 0 : if (!pConvArgs && pSpellIter)
644 0 : pSpellIter->Start( this, eStart, eEnd );
645 0 : if (pConvArgs && pConvIter)
646 0 : pConvIter->Start( this, eStart, eEnd );
647 0 : }
648 :
649 0 : void SwEditShell::SpellEnd( SwConversionArgs *pConvArgs, bool bRestoreSelection )
650 : {
651 0 : if (!pConvArgs && pSpellIter && pSpellIter->GetSh() == this)
652 : {
653 : OSL_ENSURE( pSpellIter, "wo ist mein Iterator?" );
654 0 : pSpellIter->_End(bRestoreSelection);
655 0 : delete pSpellIter, pSpellIter = 0;
656 : }
657 0 : if (pConvArgs && pConvIter && pConvIter->GetSh() == this)
658 : {
659 : OSL_ENSURE( pConvIter, "wo ist mein Iterator?" );
660 0 : pConvIter->_End();
661 0 : delete pConvIter, pConvIter = 0;
662 : }
663 0 : }
664 :
665 : /// @returns SPL_ return values as in splchk.hxx
666 0 : uno::Any SwEditShell::SpellContinue(
667 : sal_uInt16* pPageCnt, sal_uInt16* pPageSt,
668 : SwConversionArgs *pConvArgs )
669 : {
670 0 : uno::Any aRes;
671 :
672 0 : if ((!pConvArgs && pSpellIter->GetSh() != this) ||
673 0 : ( pConvArgs && pConvIter->GetSh() != this))
674 0 : return aRes;
675 :
676 0 : if( pPageCnt && !*pPageCnt )
677 : {
678 0 : sal_uInt16 nEndPage = GetLayout()->GetPageNum();
679 0 : nEndPage += nEndPage * 10 / 100;
680 0 : *pPageCnt = nEndPage;
681 0 : if( nEndPage )
682 0 : ::StartProgress( STR_STATSTR_SPELL, 0, nEndPage, GetDoc()->GetDocShell() );
683 : }
684 :
685 : OSL_ENSURE( pConvArgs || pSpellIter, "SpellIter missing" );
686 : OSL_ENSURE( !pConvArgs || pConvIter, "ConvIter missing" );
687 : //JP 18.07.95: prevent displaying selection on error messages. NO StartAction so that all
688 : // Paints are also disabled.
689 0 : ++mnStartAction;
690 0 : OUString aRet;
691 0 : uno::Reference< uno::XInterface > xRet;
692 0 : if (pConvArgs)
693 : {
694 0 : pConvIter->Continue( pPageCnt, pPageSt ) >>= aRet;
695 0 : aRes <<= aRet;
696 : }
697 : else
698 : {
699 0 : pSpellIter->Continue( pPageCnt, pPageSt ) >>= xRet;
700 0 : aRes <<= xRet;
701 : }
702 0 : --mnStartAction;
703 :
704 0 : if( !aRet.isEmpty() || xRet.is() )
705 : {
706 : // then make awt::Selection again visible
707 0 : StartAction();
708 0 : EndAction();
709 : }
710 0 : return aRes;
711 : }
712 :
713 : /* Interactive Hyphenation (BP 10.03.93)
714 : *
715 : * 1) HyphStart
716 : * - Revoke all Selections
717 : * - Save current Cursor
718 : * - if no selections existant:
719 : * - create new selection reaching until document end
720 : * 2) HyphContinue
721 : * - add nLastHyphLen onto SelectionStart
722 : * - iterate over all selected areas
723 : * - pDoc->Hyphenate() iterates over all Nodes of a selection
724 : * - pTxtNode->Hyphenate() calls SwTxtFrm::Hyphenate of the EditShell
725 : * - SwTxtFrm:Hyphenate() iterates over all rows of the Pam
726 : * - LineIter::Hyphenate() sets the Hyphenator and the Pam based on
727 : * the to be separated word.
728 : * - Returns sal_True if there is a hyphenation and sal_False if the Pam is processed.
729 : * - If sal_True, show the selected word and set nLastHyphLen.
730 : * - If sal_False, delete current selection and select next one. Returns HYPH_OK if no more.
731 : * 3) InsertSoftHyph (might be called by UI if needed)
732 : * - Place current cursor and add attribute.
733 : * 4) HyphEnd
734 : * - Restore old cursor, EndAction
735 : */
736 0 : void SwEditShell::HyphStart( SwDocPositions eStart, SwDocPositions eEnd )
737 : {
738 : // do not hyphenate if interactive hyphenationg is active elsewhere
739 0 : if (!pHyphIter)
740 : {
741 : OSL_ENSURE( !pHyphIter, "wer ist da schon am hyphinieren?" );
742 0 : pHyphIter = new SwHyphIter;
743 0 : pHyphIter->Start( this, eStart, eEnd );
744 : }
745 0 : }
746 :
747 : /// restore selections
748 0 : void SwEditShell::HyphEnd()
749 : {
750 0 : if (pHyphIter->GetSh() == this)
751 : {
752 : OSL_ENSURE( pHyphIter, "No Iterator" );
753 0 : pHyphIter->End();
754 0 : delete pHyphIter, pHyphIter = 0;
755 : }
756 0 : }
757 :
758 : /// @returns HYPH_CONTINUE if hyphenation, HYPH_OK if selected area was processed.
759 : uno::Reference< uno::XInterface >
760 0 : SwEditShell::HyphContinue( sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
761 : {
762 0 : if (pHyphIter->GetSh() != this)
763 0 : return 0;
764 :
765 0 : if( pPageCnt && !*pPageCnt && !*pPageSt )
766 : {
767 0 : sal_uInt16 nEndPage = GetLayout()->GetPageNum();
768 0 : nEndPage += nEndPage * 10 / 100;
769 0 : if( nEndPage > 14 )
770 : {
771 0 : *pPageCnt = nEndPage;
772 0 : ::StartProgress( STR_STATSTR_HYPHEN, 0, nEndPage, GetDoc()->GetDocShell());
773 : }
774 : else // here we once and for all suppress StatLineStartPercent
775 0 : *pPageSt = 1;
776 : }
777 :
778 : OSL_ENSURE( pHyphIter, "No Iterator" );
779 : //JP 18.07.95: prevent displaying selection on error messages. NO StartAction so that all
780 : // Paints are also disabled.
781 0 : ++mnStartAction;
782 0 : uno::Reference< uno::XInterface > xRet;
783 0 : pHyphIter->Continue( pPageCnt, pPageSt ) >>= xRet;
784 0 : --mnStartAction;
785 :
786 0 : if( xRet.is() )
787 0 : pHyphIter->ShowSelection();
788 :
789 0 : return xRet;
790 : }
791 :
792 : /** Insert soft hyphen
793 : *
794 : * @param nHyphPos Offset in the to be separated word
795 : */
796 0 : void SwEditShell::InsertSoftHyph( const sal_Int32 nHyphPos )
797 : {
798 : OSL_ENSURE( pHyphIter, "wo ist mein Iterator?" );
799 0 : pHyphIter->InsertSoftHyph( nHyphPos );
800 0 : }
801 :
802 : /// ignore hyphenation
803 0 : void SwEditShell::HyphIgnore()
804 : {
805 : OSL_ENSURE( pHyphIter, "No Iterator" );
806 : //JP 18.07.95: prevent displaying selection on error messages. NO StartAction so that all
807 : // Paints are also disabled.
808 0 : ++mnStartAction;
809 0 : pHyphIter->Ignore();
810 0 : --mnStartAction;
811 :
812 0 : pHyphIter->ShowSelection();
813 0 : }
814 :
815 : /** Get a list of potential corrections for misspelled word.
816 : *
817 : * If empty, word is unknown but there are no corrections available.
818 : * If NULL then the word is not misspelled but correct.
819 : *
820 : * @brief SwEditShell::GetCorrection
821 : * @return list or NULL pointer
822 : */
823 : uno::Reference< XSpellAlternatives >
824 0 : SwEditShell::GetCorrection( const Point* pPt, SwRect& rSelectRect )
825 : {
826 0 : uno::Reference< XSpellAlternatives > xSpellAlt;
827 :
828 0 : if( IsTableMode() )
829 0 : return NULL;
830 0 : SwPaM* pCrsr = GetCrsr();
831 0 : SwPosition aPos( *pCrsr->GetPoint() );
832 0 : Point aPt( *pPt );
833 0 : SwCrsrMoveState eTmpState( MV_SETONLYTEXT );
834 : SwTxtNode *pNode;
835 : SwWrongList *pWrong;
836 0 : if( GetLayout()->GetCrsrOfst( &aPos, aPt, &eTmpState ) &&
837 0 : 0 != (pNode = aPos.nNode.GetNode().GetTxtNode()) &&
838 0 : 0 != (pWrong = pNode->GetWrong()) &&
839 0 : !pNode->IsInProtectSect() )
840 : {
841 0 : sal_Int32 nBegin = aPos.nContent.GetIndex();
842 0 : sal_Int32 nLen = 1;
843 0 : if( pWrong->InWrongWord(nBegin,nLen) && !pNode->IsSymbol(nBegin) )
844 : {
845 0 : const OUString aText(pNode->GetTxt().copy(nBegin, nLen));
846 0 : OUString aWord( aText );
847 0 : aWord = comphelper::string::remove(aWord, CH_TXTATR_BREAKWORD);
848 0 : aWord = comphelper::string::remove(aWord, CH_TXTATR_INWORD);
849 :
850 0 : uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() );
851 0 : if( xSpell.is() )
852 : {
853 0 : LanguageType eActLang = (LanguageType)pNode->GetLang( nBegin, nLen );
854 0 : if( xSpell->hasLanguage( eActLang ))
855 : {
856 : // restrict the maximal number of suggestions displayed
857 : // in the context menu.
858 : // Note: That could of course be done by clipping the
859 : // resulting sequence but the current third party
860 : // implementations result differs greatly if the number of
861 : // suggestions to be retuned gets changed. Statistically
862 : // it gets much better if told to return e.g. only 7 strings
863 : // than returning e.g. 16 suggestions and using only the
864 : // first 7. Thus we hand down the value to use to that
865 : // implementation here by providing an additional parameter.
866 0 : Sequence< PropertyValue > aPropVals(1);
867 0 : PropertyValue &rVal = aPropVals.getArray()[0];
868 0 : rVal.Name = OUString( UPN_MAX_NUMBER_OF_SUGGESTIONS );
869 0 : rVal.Value <<= (sal_Int16) 7;
870 :
871 0 : xSpellAlt = xSpell->spell( aWord, eActLang, aPropVals );
872 : }
873 : }
874 :
875 0 : if ( xSpellAlt.is() ) // error found?
876 : {
877 : // save the start and end positons of the line and the starting point
878 0 : Push();
879 0 : LeftMargin();
880 0 : const sal_Int32 nLineStart = GetCrsr()->GetPoint()->nContent.GetIndex();
881 0 : RightMargin();
882 0 : const sal_Int32 nLineEnd = GetCrsr()->GetPoint()->nContent.GetIndex();
883 0 : Pop(sal_False);
884 :
885 : // make sure the selection build later from the data below does
886 : // not "in word" character to the left and right in order to
887 : // preserve those. Therefore count those "in words" in order to
888 : // modify the selection accordingly.
889 0 : const sal_Unicode* pChar = aText.getStr();
890 0 : sal_Int32 nLeft = 0;
891 0 : while (pChar && *pChar++ == CH_TXTATR_INWORD)
892 0 : ++nLeft;
893 0 : pChar = aText.getLength() ? aText.getStr() + aText.getLength() - 1 : 0;
894 0 : sal_Int32 nRight = 0;
895 0 : while (pChar && *pChar-- == CH_TXTATR_INWORD)
896 0 : ++nRight;
897 :
898 0 : aPos.nContent = nBegin + nLeft;
899 0 : pCrsr = GetCrsr();
900 0 : *pCrsr->GetPoint() = aPos;
901 0 : pCrsr->SetMark();
902 0 : ExtendSelection( sal_True, nLen - nLeft - nRight );
903 : // don't determine the rectangle in the current line
904 0 : const sal_Int32 nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft;
905 : // take one less than the line end - otherwise the next line would be calculated
906 : const sal_Int32 nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd
907 0 : ? nLineEnd : (nBegin + nLen - nLeft - nRight);
908 0 : Push();
909 0 : pCrsr->DeleteMark();
910 0 : SwIndex& rContent = GetCrsr()->GetPoint()->nContent;
911 0 : rContent = nWordStart;
912 0 : SwRect aStartRect;
913 0 : SwCrsrMoveState aState;
914 0 : aState.bRealWidth = sal_True;
915 0 : SwCntntNode* pCntntNode = pCrsr->GetCntntNode();
916 0 : SwCntntFrm *pCntntFrame = pCntntNode->getLayoutFrm( GetLayout(), pPt, pCrsr->GetPoint(), false);
917 :
918 0 : pCntntFrame->GetCharRect( aStartRect, *pCrsr->GetPoint(), &aState );
919 0 : rContent = nWordEnd - 1;
920 0 : SwRect aEndRect;
921 0 : pCntntFrame->GetCharRect( aEndRect, *pCrsr->GetPoint(),&aState );
922 0 : rSelectRect = aStartRect.Union( aEndRect );
923 0 : Pop(sal_False);
924 0 : }
925 : }
926 : }
927 0 : return xSpellAlt;
928 : }
929 :
930 0 : bool SwEditShell::GetGrammarCorrection(
931 : linguistic2::ProofreadingResult /*out*/ &rResult, // the complete result
932 : sal_Int32 /*out*/ &rErrorPosInText, // offset of error position in string that was grammar checked...
933 : sal_Int32 /*out*/ &rErrorIndexInResult, // index of error in rResult.aGrammarErrors
934 : uno::Sequence< OUString > /*out*/ &rSuggestions, // suggestions to be used for the error found
935 : const Point *pPt, SwRect &rSelectRect )
936 : {
937 0 : bool bRes = false;
938 :
939 0 : if( IsTableMode() )
940 0 : return bRes;
941 :
942 0 : SwPaM* pCrsr = GetCrsr();
943 0 : SwPosition aPos( *pCrsr->GetPoint() );
944 0 : Point aPt( *pPt );
945 0 : SwCrsrMoveState eTmpState( MV_SETONLYTEXT );
946 : SwTxtNode *pNode;
947 : SwGrammarMarkUp *pWrong;
948 0 : if( GetLayout()->GetCrsrOfst( &aPos, aPt, &eTmpState ) &&
949 0 : 0 != (pNode = aPos.nNode.GetNode().GetTxtNode()) &&
950 0 : 0 != (pWrong = pNode->GetGrammarCheck()) &&
951 0 : !pNode->IsInProtectSect() )
952 : {
953 0 : sal_Int32 nBegin = aPos.nContent.GetIndex();
954 0 : sal_Int32 nLen = 1;
955 0 : if (pWrong->InWrongWord(nBegin, nLen))
956 : {
957 0 : const OUString aText(pNode->GetTxt().copy(nBegin, nLen));
958 :
959 0 : uno::Reference< linguistic2::XProofreadingIterator > xGCIterator( mpDoc->GetGCIterator() );
960 0 : if (xGCIterator.is())
961 : {
962 0 : uno::Reference< lang::XComponent > xDoc( mpDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY );
963 :
964 : // Expand the string:
965 0 : const ModelToViewHelper aConversionMap(*pNode);
966 0 : OUString aExpandText = aConversionMap.getViewText();
967 : // get XFlatParagraph to use...
968 0 : uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *pNode, aExpandText, aConversionMap );
969 :
970 : // get error position of cursor in XFlatParagraph
971 0 : rErrorPosInText = aConversionMap.ConvertToViewPosition( nBegin );
972 :
973 0 : const sal_Int32 nStartOfSentence = aConversionMap.ConvertToViewPosition( pWrong->getSentenceStart( nBegin ) );
974 0 : const sal_Int32 nEndOfSentence = aConversionMap.ConvertToViewPosition( pWrong->getSentenceEnd( nBegin ) );
975 :
976 0 : rResult = xGCIterator->checkSentenceAtPosition(
977 : xDoc, xFlatPara, aExpandText, lang::Locale(), nStartOfSentence,
978 : nEndOfSentence == COMPLETE_STRING ? aExpandText.getLength() : nEndOfSentence,
979 0 : rErrorPosInText );
980 0 : bRes = true;
981 :
982 : // get suggestions to use for the specific error position
983 0 : sal_Int32 nErrors = rResult.aErrors.getLength();
984 0 : rSuggestions.realloc( 0 );
985 0 : for (sal_Int32 i = 0; i < nErrors; ++i )
986 : {
987 : // return suggestions for first error that includes the given error position
988 0 : const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i];
989 0 : if (rError.nErrorStart <= rErrorPosInText &&
990 0 : rErrorPosInText + nLen <= rError.nErrorStart + rError.nErrorLength)
991 : {
992 0 : rSuggestions = rError.aSuggestions;
993 0 : rErrorIndexInResult = i;
994 0 : break;
995 : }
996 0 : }
997 : }
998 :
999 0 : if (rResult.aErrors.getLength() > 0) // error found?
1000 : {
1001 : // save the start and end positons of the line and the starting point
1002 0 : Push();
1003 0 : LeftMargin();
1004 0 : const sal_Int32 nLineStart = GetCrsr()->GetPoint()->nContent.GetIndex();
1005 0 : RightMargin();
1006 0 : const sal_Int32 nLineEnd = GetCrsr()->GetPoint()->nContent.GetIndex();
1007 0 : Pop(sal_False);
1008 :
1009 : // make sure the selection build later from the data below does
1010 : // not include "in word" character to the left and right in
1011 : // order to preserve those. Therefore count those "in words" in
1012 : // order to modify the selection accordingly.
1013 0 : const sal_Unicode* pChar = aText.getStr();
1014 0 : sal_Int32 nLeft = 0;
1015 0 : while (pChar && *pChar++ == CH_TXTATR_INWORD)
1016 0 : ++nLeft;
1017 0 : pChar = aText.getLength() ? aText.getStr() + aText.getLength() - 1 : 0;
1018 0 : sal_Int32 nRight = 0;
1019 0 : while (pChar && *pChar-- == CH_TXTATR_INWORD)
1020 0 : ++nRight;
1021 :
1022 0 : aPos.nContent = nBegin + nLeft;
1023 0 : pCrsr = GetCrsr();
1024 0 : *pCrsr->GetPoint() = aPos;
1025 0 : pCrsr->SetMark();
1026 0 : ExtendSelection( sal_True, nLen - nLeft - nRight );
1027 : // don't determine the rectangle in the current line
1028 0 : const sal_Int32 nWordStart = (nBegin + nLeft) < nLineStart ? nLineStart : nBegin + nLeft;
1029 : // take one less than the line end - otherwise the next line would be calculated
1030 : const sal_Int32 nWordEnd = (nBegin + nLen - nLeft - nRight) > nLineEnd
1031 0 : ? nLineEnd : (nBegin + nLen - nLeft - nRight);
1032 0 : Push();
1033 0 : pCrsr->DeleteMark();
1034 0 : SwIndex& rContent = GetCrsr()->GetPoint()->nContent;
1035 0 : rContent = nWordStart;
1036 0 : SwRect aStartRect;
1037 0 : SwCrsrMoveState aState;
1038 0 : aState.bRealWidth = sal_True;
1039 0 : SwCntntNode* pCntntNode = pCrsr->GetCntntNode();
1040 0 : SwCntntFrm *pCntntFrame = pCntntNode->getLayoutFrm( GetLayout(), pPt, pCrsr->GetPoint(), false);
1041 :
1042 0 : pCntntFrame->GetCharRect( aStartRect, *pCrsr->GetPoint(), &aState );
1043 0 : rContent = nWordEnd - 1;
1044 0 : SwRect aEndRect;
1045 0 : pCntntFrame->GetCharRect( aEndRect, *pCrsr->GetPoint(),&aState );
1046 0 : rSelectRect = aStartRect.Union( aEndRect );
1047 0 : Pop(sal_False);
1048 0 : }
1049 : }
1050 : }
1051 :
1052 0 : return bRes;
1053 : }
1054 :
1055 0 : bool SwEditShell::SpellSentence(::svx::SpellPortions& rPortions, bool bIsGrammarCheck)
1056 : {
1057 : OSL_ENSURE( pSpellIter, "SpellIter missing" );
1058 0 : if(!pSpellIter)
1059 0 : return false;
1060 0 : bool bRet = pSpellIter->SpellSentence(rPortions, bIsGrammarCheck);
1061 :
1062 : // make Selection visible - this should simply move the
1063 : // cursor to the end of the sentence
1064 0 : StartAction();
1065 0 : EndAction();
1066 0 : return bRet;
1067 : }
1068 :
1069 : ///make SpellIter start with the current sentence when called next time
1070 0 : void SwEditShell::PutSpellingToSentenceStart()
1071 : {
1072 : OSL_ENSURE( pSpellIter, "SpellIter missing" );
1073 0 : if(!pSpellIter)
1074 0 : return;
1075 0 : pSpellIter->ToSentenceStart();
1076 : }
1077 :
1078 0 : static sal_uInt32 lcl_CountRedlines(const ::svx::SpellPortions& rLastPortions)
1079 : {
1080 0 : sal_uInt32 nRet = 0;
1081 0 : SpellPortions::const_iterator aIter = rLastPortions.begin();
1082 0 : for( ; aIter != rLastPortions.end(); ++aIter)
1083 : {
1084 0 : if( aIter->bIsHidden )
1085 0 : ++nRet;
1086 : }
1087 0 : return nRet;
1088 : }
1089 :
1090 0 : void SwEditShell::MoveContinuationPosToEndOfCheckedSentence()
1091 : {
1092 : // give hint that continuation position for spell/grammar checking is
1093 : // at the end of this sentence
1094 0 : if (pSpellIter)
1095 : {
1096 0 : pSpellIter->SetCurr( new SwPosition( *pSpellIter->GetCurrX() ) );
1097 0 : pSpellIter->ContinueAfterThisSentence();
1098 : }
1099 0 : }
1100 :
1101 0 : void SwEditShell::ApplyChangedSentence(const ::svx::SpellPortions& rNewPortions, bool bRecheck)
1102 : {
1103 : // Note: rNewPortions.size() == 0 is valid and happens when the whole
1104 : // sentence got removed in the dialog
1105 :
1106 : OSL_ENSURE( pSpellIter, "SpellIter missing" );
1107 0 : if(pSpellIter &&
1108 0 : pSpellIter->GetLastPortions().size() > 0) // no portions -> no text to be changed
1109 : {
1110 0 : const SpellPortions& rLastPortions = pSpellIter->GetLastPortions();
1111 0 : const SpellContentPositions rLastPositions = pSpellIter->GetLastPositions();
1112 : OSL_ENSURE(rLastPortions.size() > 0 &&
1113 : rLastPortions.size() == rLastPositions.size(),
1114 : "last vectors of spelling results are not set or not equal");
1115 :
1116 : // iterate over the new portions, beginning at the end to take advantage of the previously
1117 : // saved content positions
1118 :
1119 0 : mpDoc->GetIDocumentUndoRedo().StartUndo( UNDO_UI_TEXT_CORRECTION, NULL );
1120 0 : StartAction();
1121 :
1122 0 : SwPaM *pCrsr = GetCrsr();
1123 : // save cursor position (which should be at the end of the current sentence)
1124 : // for later restoration
1125 0 : Push();
1126 :
1127 0 : sal_uInt32 nRedlinePortions = lcl_CountRedlines(rLastPortions);
1128 0 : if((rLastPortions.size() - nRedlinePortions) == rNewPortions.size())
1129 : {
1130 : OSL_ENSURE( !rNewPortions.empty(), "rNewPortions should not be empty here" );
1131 : OSL_ENSURE( !rLastPortions.empty(), "rLastPortions should not be empty here" );
1132 : OSL_ENSURE( !rLastPositions.empty(), "rLastPositions should not be empty here" );
1133 :
1134 : // the simple case: the same number of elements on both sides
1135 : // each changed element has to be applied to the corresponding source element
1136 0 : svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.end();
1137 0 : SpellPortions::const_iterator aCurrentOldPortion = rLastPortions.end();
1138 0 : SpellContentPositions::const_iterator aCurrentOldPosition = rLastPositions.end();
1139 0 : do
1140 : {
1141 0 : --aCurrentNewPortion;
1142 0 : --aCurrentOldPortion;
1143 0 : --aCurrentOldPosition;
1144 : //jump over redline portions
1145 0 : while(aCurrentOldPortion->bIsHidden)
1146 : {
1147 0 : if (aCurrentOldPortion != rLastPortions.begin() &&
1148 0 : aCurrentOldPosition != rLastPositions.begin())
1149 : {
1150 0 : --aCurrentOldPortion;
1151 0 : --aCurrentOldPosition;
1152 : }
1153 : else
1154 : {
1155 : OSL_FAIL("ApplyChangedSentence: iterator positions broken" );
1156 0 : break;
1157 : }
1158 : }
1159 0 : if ( !pCrsr->HasMark() )
1160 0 : pCrsr->SetMark();
1161 0 : pCrsr->GetPoint()->nContent = aCurrentOldPosition->nLeft;
1162 0 : pCrsr->GetMark()->nContent = aCurrentOldPosition->nRight;
1163 0 : sal_uInt16 nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage );
1164 0 : sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE;
1165 0 : switch(nScriptType)
1166 : {
1167 0 : case SCRIPTTYPE_ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1168 0 : case SCRIPTTYPE_COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1169 : }
1170 0 : if(aCurrentNewPortion->sText != aCurrentOldPortion->sText)
1171 : {
1172 : // change text ...
1173 0 : mpDoc->DeleteAndJoin(*pCrsr);
1174 : // ... and apply language if necessary
1175 0 : if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
1176 0 : SetAttrItem( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId), nLangWhichId );
1177 0 : mpDoc->InsertString(*pCrsr, aCurrentNewPortion->sText);
1178 : }
1179 0 : else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
1180 : {
1181 : // apply language
1182 0 : SetAttrItem( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId), nLangWhichId );
1183 : }
1184 0 : else if( aCurrentNewPortion->bIgnoreThisError )
1185 : {
1186 : // add the 'ignore' markup to the TextNode's grammar ignore markup list
1187 0 : IgnoreGrammarErrorAt( *pCrsr );
1188 : OSL_FAIL("TODO: add ignore mark to text node");
1189 : }
1190 0 : if(aCurrentNewPortion == rNewPortions.begin())
1191 0 : break;
1192 : }
1193 0 : while(aCurrentNewPortion != rNewPortions.begin());
1194 : }
1195 : else
1196 : {
1197 : OSL_ENSURE( !rLastPositions.empty(), "rLastPositions should not be empty here" );
1198 :
1199 : // select the complete sentence
1200 0 : SpellContentPositions::const_iterator aCurrentEndPosition = rLastPositions.end();
1201 0 : --aCurrentEndPosition;
1202 0 : SpellContentPositions::const_iterator aCurrentStartPosition = rLastPositions.begin();
1203 0 : pCrsr->GetPoint()->nContent = aCurrentStartPosition->nLeft;
1204 0 : pCrsr->GetMark()->nContent = aCurrentEndPosition->nRight;
1205 :
1206 : // delete the sentence completely
1207 0 : mpDoc->DeleteAndJoin(*pCrsr);
1208 0 : svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.begin();
1209 0 : while(aCurrentNewPortion != rNewPortions.end())
1210 : {
1211 : // set the language attribute
1212 0 : sal_uInt16 nScriptType = GetScriptType();
1213 0 : sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE;
1214 0 : switch(nScriptType)
1215 : {
1216 0 : case SCRIPTTYPE_ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1217 0 : case SCRIPTTYPE_COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1218 : }
1219 0 : SfxItemSet aSet(GetAttrPool(), nLangWhichId, nLangWhichId, 0);
1220 0 : GetCurAttr( aSet );
1221 0 : const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId));
1222 0 : if(rLang.GetLanguage() != aCurrentNewPortion->eLanguage)
1223 0 : SetAttrItem( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId) );
1224 : // insert the new string
1225 0 : mpDoc->InsertString(*pCrsr, aCurrentNewPortion->sText);
1226 :
1227 : // set the cursor to the end of the inserted string
1228 0 : *pCrsr->Start() = *pCrsr->End();
1229 0 : ++aCurrentNewPortion;
1230 0 : }
1231 : }
1232 :
1233 : // restore cursor to the end of the sentence
1234 : // (will work also if the sentence length has changed,
1235 : // since cursors get updated automatically!)
1236 0 : Pop( sal_False );
1237 :
1238 : // collapse cursor to the end of the modified sentence
1239 0 : *pCrsr->Start() = *pCrsr->End();
1240 0 : if (bRecheck)
1241 : {
1242 : // in grammar check the current sentence has to be checked again
1243 0 : GoStartSentence();
1244 : }
1245 : // set continuation position for spell/grammar checking to the end of this sentence
1246 0 : pSpellIter->SetCurr( new SwPosition( *pCrsr->Start() ) );
1247 :
1248 0 : mpDoc->GetIDocumentUndoRedo().EndUndo( UNDO_UI_TEXT_CORRECTION, NULL );
1249 0 : EndAction();
1250 : }
1251 0 : }
1252 : /** Collect all deleted redlines of the current text node
1253 : * beginning at the start of the cursor position
1254 : */
1255 0 : static SpellContentPositions lcl_CollectDeletedRedlines(SwEditShell* pSh)
1256 : {
1257 0 : SpellContentPositions aRedlines;
1258 0 : SwDoc* pDoc = pSh->GetDoc();
1259 0 : const bool bShowChg = IDocumentRedlineAccess::IsShowChanges( pDoc->GetRedlineMode() );
1260 0 : if ( bShowChg )
1261 : {
1262 0 : SwPaM *pCrsr = pSh->GetCrsr();
1263 0 : const SwPosition* pStartPos = pCrsr->Start();
1264 0 : const SwTxtNode* pTxtNode = pCrsr->GetNode()->GetTxtNode();
1265 :
1266 0 : sal_uInt16 nAct = pDoc->GetRedlinePos( *pTxtNode, USHRT_MAX );
1267 0 : const sal_Int32 nStartIndex = pStartPos->nContent.GetIndex();
1268 0 : for ( ; nAct < pDoc->GetRedlineTbl().size(); nAct++ )
1269 : {
1270 0 : const SwRangeRedline* pRed = pDoc->GetRedlineTbl()[ nAct ];
1271 :
1272 0 : if ( pRed->Start()->nNode > pTxtNode->GetIndex() )
1273 0 : break;
1274 :
1275 0 : if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() )
1276 : {
1277 : sal_Int32 nStart_, nEnd_;
1278 0 : pRed->CalcStartEnd( pTxtNode->GetIndex(), nStart_, nEnd_ );
1279 0 : sal_Int32 nStart = nStart_;
1280 0 : sal_Int32 nEnd = nEnd_;
1281 0 : if(nStart >= nStartIndex || nEnd >= nStartIndex)
1282 : {
1283 : SpellContentPosition aAdd;
1284 0 : aAdd.nLeft = nStart;
1285 0 : aAdd.nRight = nEnd;
1286 0 : aRedlines.push_back(aAdd);
1287 : }
1288 : }
1289 : }
1290 : }
1291 0 : return aRedlines;
1292 : }
1293 :
1294 : /// remove the redline positions after the current selection
1295 0 : static void lcl_CutRedlines( SpellContentPositions& aDeletedRedlines, SwEditShell* pSh )
1296 : {
1297 0 : if(!aDeletedRedlines.empty())
1298 : {
1299 0 : SwPaM *pCrsr = pSh->GetCrsr();
1300 0 : const SwPosition* pEndPos = pCrsr->End();
1301 0 : const sal_Int32 nEnd = pEndPos->nContent.GetIndex();
1302 0 : while(!aDeletedRedlines.empty() &&
1303 0 : aDeletedRedlines.back().nLeft > nEnd)
1304 : {
1305 0 : aDeletedRedlines.pop_back();
1306 : }
1307 : }
1308 0 : }
1309 :
1310 0 : static SpellContentPosition lcl_FindNextDeletedRedline(
1311 : const SpellContentPositions& rDeletedRedlines,
1312 : sal_Int32 nSearchFrom )
1313 : {
1314 : SpellContentPosition aRet;
1315 0 : aRet.nLeft = aRet.nRight = SAL_MAX_INT32;
1316 0 : if(!rDeletedRedlines.empty())
1317 : {
1318 0 : SpellContentPositions::const_iterator aIter = rDeletedRedlines.begin();
1319 0 : for( ; aIter != rDeletedRedlines.end(); ++aIter)
1320 : {
1321 0 : if(aIter->nLeft < nSearchFrom)
1322 0 : continue;
1323 0 : aRet = *aIter;
1324 0 : break;
1325 : }
1326 : }
1327 0 : return aRet;
1328 : }
1329 :
1330 0 : bool SwSpellIter::SpellSentence(::svx::SpellPortions& rPortions, bool bIsGrammarCheck)
1331 : {
1332 0 : bool bRet = false;
1333 0 : aLastPortions.clear();
1334 0 : aLastPositions.clear();
1335 :
1336 0 : SwEditShell *pMySh = GetSh();
1337 0 : if( !pMySh )
1338 0 : return false;
1339 :
1340 : OSL_ENSURE( GetEnd(), "SwSpellIter::SpellSentence without Start?");
1341 :
1342 0 : uno::Reference< XSpellAlternatives > xSpellRet;
1343 0 : linguistic2::ProofreadingResult aGrammarResult;
1344 0 : bool bGoOn = true;
1345 0 : bool bGrammarErrorFound = false;
1346 0 : do {
1347 0 : SwPaM *pCrsr = pMySh->GetCrsr();
1348 0 : if ( !pCrsr->HasMark() )
1349 0 : pCrsr->SetMark();
1350 :
1351 0 : *pCrsr->GetPoint() = *GetCurr();
1352 0 : *pCrsr->GetMark() = *GetEnd();
1353 :
1354 0 : if( bBackToStartOfSentence )
1355 : {
1356 0 : pMySh->GoStartSentence();
1357 0 : bBackToStartOfSentence = false;
1358 : }
1359 : uno::Any aSpellRet =
1360 : pMySh->GetDoc()->Spell(*pCrsr,
1361 0 : xSpeller, 0, 0, bIsGrammarCheck );
1362 0 : aSpellRet >>= xSpellRet;
1363 0 : aSpellRet >>= aGrammarResult;
1364 0 : bGoOn = GetCrsrCnt() > 1;
1365 0 : bGrammarErrorFound = aGrammarResult.aErrors.getLength() > 0;
1366 0 : if( xSpellRet.is() || bGrammarErrorFound )
1367 : {
1368 0 : bGoOn = false;
1369 0 : SwPosition* pNewPoint = new SwPosition( *pCrsr->GetPoint() );
1370 0 : SwPosition* pNewMark = new SwPosition( *pCrsr->GetMark() );
1371 :
1372 0 : SetCurr( pNewPoint );
1373 0 : SetCurrX( pNewMark );
1374 : }
1375 0 : if( bGoOn )
1376 : {
1377 0 : pMySh->Pop( sal_False );
1378 0 : pCrsr = pMySh->GetCrsr();
1379 0 : if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
1380 0 : pCrsr->Exchange();
1381 0 : SwPosition* pNew = new SwPosition( *pCrsr->GetPoint() );
1382 0 : SetStart( pNew );
1383 0 : pNew = new SwPosition( *pCrsr->GetMark() );
1384 0 : SetEnd( pNew );
1385 0 : pNew = new SwPosition( *GetStart() );
1386 0 : SetCurr( pNew );
1387 0 : pNew = new SwPosition( *pNew );
1388 0 : SetCurrX( pNew );
1389 0 : pCrsr->SetMark();
1390 0 : --GetCrsrCnt();
1391 0 : }
1392 : } while ( bGoOn );
1393 :
1394 0 : if(xSpellRet.is() || bGrammarErrorFound)
1395 : {
1396 : // an error has been found
1397 : // To fill the spell portions the beginning of the sentence has to be found
1398 0 : SwPaM *pCrsr = pMySh->GetCrsr();
1399 : // set the mark to the right if necessary
1400 0 : if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
1401 0 : pCrsr->Exchange();
1402 : // the cursor has to be collapsed on the left to go to the start of the sentence - if sentence ends inside of the error
1403 0 : pCrsr->DeleteMark();
1404 0 : pCrsr->SetMark();
1405 0 : bool bStartSent = 0 != pMySh->GoStartSentence();
1406 0 : SpellContentPositions aDeletedRedlines = lcl_CollectDeletedRedlines(pMySh);
1407 0 : if(bStartSent)
1408 : {
1409 : // create a portion from the start part
1410 0 : AddPortion(0, 0, aDeletedRedlines);
1411 : }
1412 : // Set the cursor to the error already found
1413 0 : *pCrsr->GetPoint() = *GetCurrX();
1414 0 : *pCrsr->GetMark() = *GetCurr();
1415 0 : AddPortion(xSpellRet, &aGrammarResult, aDeletedRedlines);
1416 :
1417 : // save the end position of the error to continue from here
1418 0 : SwPosition aSaveStartPos = *pCrsr->End();
1419 : // determine the end of the current sentence
1420 0 : if ( *pCrsr->GetPoint() < *pCrsr->GetMark() )
1421 0 : pCrsr->Exchange();
1422 : // again collapse to start marking after the end of the error
1423 0 : pCrsr->DeleteMark();
1424 0 : pCrsr->SetMark();
1425 :
1426 0 : pMySh->GoEndSentence();
1427 0 : if( bGrammarErrorFound )
1428 : {
1429 0 : const ModelToViewHelper aConversionMap(*(SwTxtNode*)pCrsr->GetNode());
1430 0 : OUString aExpandText = aConversionMap.getViewText();
1431 : sal_Int32 nSentenceEnd =
1432 0 : aConversionMap.ConvertToViewPosition( aGrammarResult.nBehindEndOfSentencePosition );
1433 : // remove trailing space
1434 0 : if( aExpandText[nSentenceEnd - 1] == ' ' )
1435 0 : --nSentenceEnd;
1436 0 : if( pCrsr->End()->nContent.GetIndex() < nSentenceEnd )
1437 : {
1438 0 : pCrsr->End()->nContent.Assign(
1439 0 : pCrsr->End()->nNode.GetNode().GetCntntNode(), nSentenceEnd);
1440 0 : }
1441 : }
1442 :
1443 0 : lcl_CutRedlines( aDeletedRedlines, pMySh );
1444 : // save the 'global' end of the spellchecking
1445 0 : const SwPosition aSaveEndPos = *GetEnd();
1446 : // set the sentence end as 'local' end
1447 0 : SetEnd( new SwPosition( *pCrsr->End() ));
1448 :
1449 0 : *pCrsr->GetPoint() = aSaveStartPos;
1450 0 : *pCrsr->GetMark() = *GetEnd();
1451 : // now the rest of the sentence has to be searched for errors
1452 : // for each error the non-error text between the current and the last error has
1453 : // to be added to the portions - if necessary broken into same-language-portions
1454 0 : if( !bGrammarErrorFound ) //in grammar check there's only one error returned
1455 : {
1456 0 : do
1457 : {
1458 0 : xSpellRet = 0;
1459 : // don't search for grammar errors here anymore!
1460 : pMySh->GetDoc()->Spell(*pCrsr,
1461 0 : xSpeller, 0, 0, false ) >>= xSpellRet;
1462 0 : if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
1463 0 : pCrsr->Exchange();
1464 0 : SetCurr( new SwPosition( *pCrsr->GetPoint() ));
1465 0 : SetCurrX( new SwPosition( *pCrsr->GetMark() ));
1466 :
1467 : // if an error has been found go back to the text preceeding the error
1468 0 : if(xSpellRet.is())
1469 : {
1470 0 : *pCrsr->GetPoint() = aSaveStartPos;
1471 0 : *pCrsr->GetMark() = *GetCurr();
1472 : }
1473 : // add the portion
1474 0 : AddPortion(0, 0, aDeletedRedlines);
1475 :
1476 0 : if(xSpellRet.is())
1477 : {
1478 0 : *pCrsr->GetPoint() = *GetCurr();
1479 0 : *pCrsr->GetMark() = *GetCurrX();
1480 0 : AddPortion(xSpellRet, 0, aDeletedRedlines);
1481 : // move the cursor to the end of the error string
1482 0 : *pCrsr->GetPoint() = *GetCurrX();
1483 : // and save the end of the error as new start position
1484 0 : aSaveStartPos = *GetCurrX();
1485 : // and the end of the sentence
1486 0 : *pCrsr->GetMark() = *GetEnd();
1487 : }
1488 : // if the end of the sentence has already been reached then break here
1489 0 : if(*GetCurrX() >= *GetEnd())
1490 0 : break;
1491 : }
1492 : while(xSpellRet.is());
1493 : }
1494 : else
1495 : {
1496 : // go to the end of sentence as the grammar check returned it
1497 : // at this time the Point is behind the grammar error
1498 : // and the mark points to the sentence end as
1499 0 : if ( *pCrsr->GetPoint() < *pCrsr->GetMark() )
1500 0 : pCrsr->Exchange();
1501 : }
1502 :
1503 : // the part between the last error and the end of the sentence has to be added
1504 0 : *pMySh->GetCrsr()->GetPoint() = *GetEnd();
1505 0 : if(*GetCurrX() < *GetEnd())
1506 : {
1507 0 : AddPortion(0, 0, aDeletedRedlines);
1508 : }
1509 : // set the shell cursor to the end of the sentence to prevent a visible selection
1510 0 : *pCrsr->GetMark() = *GetEnd();
1511 0 : if( !bIsGrammarCheck )
1512 : {
1513 : // set the current position to the end of the sentence
1514 0 : SetCurr( new SwPosition(*GetEnd()) );
1515 : }
1516 : // restore the 'global' end
1517 0 : SetEnd( new SwPosition(aSaveEndPos) );
1518 0 : rPortions = aLastPortions;
1519 0 : bRet = true;
1520 : }
1521 : else
1522 : {
1523 : // if no error could be found the selection has to be corrected - at least if it's not in the body
1524 0 : *pMySh->GetCrsr()->GetPoint() = *GetEnd();
1525 0 : pMySh->GetCrsr()->DeleteMark();
1526 : }
1527 :
1528 0 : return bRet;
1529 : }
1530 :
1531 0 : void SwSpellIter::ToSentenceStart()
1532 : {
1533 0 : bBackToStartOfSentence = true;
1534 0 : }
1535 :
1536 0 : static LanguageType lcl_GetLanguage(SwEditShell& rSh)
1537 : {
1538 0 : sal_uInt16 nScriptType = rSh.GetScriptType();
1539 0 : sal_uInt16 nLangWhichId = RES_CHRATR_LANGUAGE;
1540 :
1541 0 : switch(nScriptType)
1542 : {
1543 0 : case SCRIPTTYPE_ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
1544 0 : case SCRIPTTYPE_COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
1545 : }
1546 0 : SfxItemSet aSet(rSh.GetAttrPool(), nLangWhichId, nLangWhichId, 0);
1547 0 : rSh.GetCurAttr( aSet );
1548 0 : const SvxLanguageItem& rLang = static_cast<const SvxLanguageItem& >(aSet.Get(nLangWhichId));
1549 0 : return rLang.GetLanguage();
1550 : }
1551 :
1552 : /// create a text portion at the given position
1553 0 : void SwSpellIter::CreatePortion(uno::Reference< XSpellAlternatives > xAlt,
1554 : linguistic2::ProofreadingResult* pGrammarResult,
1555 : bool bIsField, bool bIsHidden)
1556 : {
1557 0 : svx::SpellPortion aPortion;
1558 0 : OUString sText;
1559 0 : GetSh()->GetSelectedText( sText );
1560 0 : if(!sText.isEmpty())
1561 : {
1562 : // in case of redlined deletions the selection of an error is not the same as the _real_ word
1563 0 : if(xAlt.is())
1564 0 : aPortion.sText = xAlt->getWord();
1565 0 : else if(pGrammarResult)
1566 : {
1567 0 : aPortion.bIsGrammarError = true;
1568 0 : if(pGrammarResult->aErrors.getLength())
1569 : {
1570 0 : aPortion.aGrammarError = pGrammarResult->aErrors[0];
1571 0 : aPortion.sText = pGrammarResult->aText.copy( aPortion.aGrammarError.nErrorStart, aPortion.aGrammarError.nErrorLength );
1572 0 : aPortion.xGrammarChecker = pGrammarResult->xProofreader;
1573 0 : const beans::PropertyValue* pProperties = pGrammarResult->aProperties.getConstArray();
1574 0 : for( sal_Int32 nProp = 0; nProp < pGrammarResult->aProperties.getLength(); ++nProp )
1575 : {
1576 0 : if ( pProperties->Name == "DialogTitle" )
1577 : {
1578 0 : pProperties->Value >>= aPortion.sDialogTitle;
1579 0 : break;
1580 : }
1581 : }
1582 : }
1583 : }
1584 : else
1585 0 : aPortion.sText = sText;
1586 0 : aPortion.eLanguage = lcl_GetLanguage(*GetSh());
1587 0 : aPortion.bIsField = bIsField;
1588 0 : aPortion.bIsHidden = bIsHidden;
1589 0 : aPortion.xAlternatives = xAlt;
1590 : SpellContentPosition aPosition;
1591 0 : SwPaM *pCrsr = GetSh()->GetCrsr();
1592 0 : aPosition.nLeft = pCrsr->Start()->nContent.GetIndex();
1593 0 : aPosition.nRight = pCrsr->End()->nContent.GetIndex();
1594 0 : aLastPortions.push_back(aPortion);
1595 0 : aLastPositions.push_back(aPosition);
1596 0 : }
1597 0 : }
1598 :
1599 0 : void SwSpellIter::AddPortion(uno::Reference< XSpellAlternatives > xAlt,
1600 : linguistic2::ProofreadingResult* pGrammarResult,
1601 : const SpellContentPositions& rDeletedRedlines)
1602 : {
1603 0 : SwEditShell *pMySh = GetSh();
1604 0 : OUString sText;
1605 0 : pMySh->GetSelectedText( sText );
1606 0 : if(!sText.isEmpty())
1607 : {
1608 0 : if(xAlt.is() || pGrammarResult != 0)
1609 : {
1610 0 : CreatePortion(xAlt, pGrammarResult, false, false);
1611 : }
1612 : else
1613 : {
1614 0 : SwPaM *pCrsr = GetSh()->GetCrsr();
1615 0 : if ( *pCrsr->GetPoint() > *pCrsr->GetMark() )
1616 0 : pCrsr->Exchange();
1617 : // save the start and end positions
1618 0 : SwPosition aStart(*pCrsr->GetPoint());
1619 0 : SwPosition aEnd(*pCrsr->GetMark());
1620 : // iterate over the text to find changes in language
1621 : // set the mark equal to the point
1622 0 : *pCrsr->GetMark() = aStart;
1623 0 : SwTxtNode* pTxtNode = pCrsr->GetNode()->GetTxtNode();
1624 0 : LanguageType eStartLanguage = lcl_GetLanguage(*GetSh());
1625 : SpellContentPosition aNextRedline = lcl_FindNextDeletedRedline(
1626 0 : rDeletedRedlines, aStart.nContent.GetIndex() );
1627 0 : if( aNextRedline.nLeft == aStart.nContent.GetIndex() )
1628 : {
1629 : // select until the end of the current redline
1630 0 : const sal_Int32 nEnd = aEnd.nContent.GetIndex() < aNextRedline.nRight ?
1631 0 : aEnd.nContent.GetIndex() : aNextRedline.nRight;
1632 0 : pCrsr->GetPoint()->nContent.Assign( pTxtNode, nEnd );
1633 0 : CreatePortion(xAlt, pGrammarResult, false, true);
1634 0 : aStart = *pCrsr->End();
1635 : // search for next redline
1636 : aNextRedline = lcl_FindNextDeletedRedline(
1637 0 : rDeletedRedlines, aStart.nContent.GetIndex() );
1638 : }
1639 0 : while(*pCrsr->GetPoint() < aEnd)
1640 : {
1641 : // #125786 in table cell with fixed row height the cursor might not move forward
1642 0 : if(!GetSh()->Right(1, CRSR_SKIP_CELLS))
1643 0 : break;
1644 :
1645 0 : bool bField = false;
1646 : // read the character at the current position to check if it's a field
1647 : sal_Unicode const cChar =
1648 0 : pTxtNode->GetTxt()[pCrsr->GetMark()->nContent.GetIndex()];
1649 0 : if( CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar)
1650 : {
1651 : const SwTxtAttr* pTxtAttr = pTxtNode->GetTxtAttrForCharAt(
1652 0 : pCrsr->GetMark()->nContent.GetIndex() );
1653 : const sal_uInt16 nWhich = pTxtAttr
1654 : ? pTxtAttr->Which()
1655 0 : : static_cast<sal_uInt16>(RES_TXTATR_END);
1656 0 : switch (nWhich)
1657 : {
1658 : case RES_TXTATR_FIELD:
1659 : case RES_TXTATR_ANNOTATION:
1660 : case RES_TXTATR_FTN:
1661 : case RES_TXTATR_FLYCNT:
1662 0 : bField = true;
1663 0 : break;
1664 0 : }
1665 : }
1666 0 : else if (cChar == CH_TXT_ATR_FORMELEMENT)
1667 : {
1668 0 : SwPosition aPos(*pCrsr->GetMark());
1669 0 : bField = pMySh->GetDoc()->getIDocumentMarkAccess()->getDropDownFor(aPos);
1670 : }
1671 :
1672 0 : LanguageType eCurLanguage = lcl_GetLanguage(*GetSh());
1673 0 : bool bRedline = aNextRedline.nLeft == pCrsr->GetPoint()->nContent.GetIndex();
1674 : // create a portion if the next character
1675 : // - is a field,
1676 : // - is at the beginning of a deleted redline
1677 : // - has a different language
1678 0 : if(bField || bRedline || eCurLanguage != eStartLanguage)
1679 : {
1680 0 : eStartLanguage = eCurLanguage;
1681 : // go one step back - the cursor currently selects the first character
1682 : // with a different language
1683 : // in the case of redlining it's different
1684 0 : if(eCurLanguage != eStartLanguage || bField)
1685 0 : *pCrsr->GetPoint() = *pCrsr->GetMark();
1686 : // set to the last start
1687 0 : *pCrsr->GetMark() = aStart;
1688 : // create portion should only be called if a selection exists
1689 : // there's no selection if there's a field at the beginning
1690 0 : if(*pCrsr->Start() != *pCrsr->End())
1691 0 : CreatePortion(xAlt, pGrammarResult, false, false);
1692 0 : aStart = *pCrsr->End();
1693 : // now export the field - if there is any
1694 0 : if(bField)
1695 : {
1696 0 : *pCrsr->GetMark() = *pCrsr->GetPoint();
1697 0 : GetSh()->Right(1, CRSR_SKIP_CELLS);
1698 0 : CreatePortion(xAlt, pGrammarResult, true, false);
1699 0 : aStart = *pCrsr->End();
1700 : }
1701 : }
1702 : // if a redline start then create a portion for it
1703 0 : if(bRedline)
1704 : {
1705 0 : *pCrsr->GetMark() = *pCrsr->GetPoint();
1706 : // select until the end of the current redline
1707 0 : const sal_Int32 nEnd = aEnd.nContent.GetIndex() < aNextRedline.nRight ?
1708 0 : aEnd.nContent.GetIndex() : aNextRedline.nRight;
1709 0 : pCrsr->GetPoint()->nContent.Assign( pTxtNode, nEnd );
1710 0 : CreatePortion(xAlt, pGrammarResult, false, true);
1711 0 : aStart = *pCrsr->End();
1712 : // search for next redline
1713 : aNextRedline = lcl_FindNextDeletedRedline(
1714 0 : rDeletedRedlines, aStart.nContent.GetIndex() );
1715 : }
1716 0 : *pCrsr->GetMark() = *pCrsr->GetPoint();
1717 : }
1718 0 : pCrsr->SetMark();
1719 0 : *pCrsr->GetMark() = aStart;
1720 0 : CreatePortion(xAlt, pGrammarResult, false, false);
1721 : }
1722 0 : }
1723 0 : }
1724 :
1725 0 : void SwEditShell::IgnoreGrammarErrorAt( SwPaM& rErrorPosition )
1726 : {
1727 : SwTxtNode *pNode;
1728 : SwWrongList *pWrong;
1729 0 : SwNodeIndex aIdx = rErrorPosition.Start()->nNode;
1730 0 : SwNodeIndex aEndIdx = rErrorPosition.Start()->nNode;
1731 0 : sal_Int32 nStart = rErrorPosition.Start()->nContent.GetIndex();
1732 0 : sal_Int32 nEnd = COMPLETE_STRING;
1733 0 : while( aIdx <= aEndIdx )
1734 : {
1735 0 : pNode = aIdx.GetNode().GetTxtNode();
1736 0 : if( pNode ) {
1737 0 : if( aIdx == aEndIdx )
1738 0 : nEnd = rErrorPosition.End()->nContent.GetIndex();
1739 0 : pWrong = pNode->GetGrammarCheck();
1740 0 : if( pWrong )
1741 0 : pWrong->RemoveEntry( nStart, nEnd );
1742 0 : pWrong = pNode->GetWrong();
1743 0 : if( pWrong )
1744 0 : pWrong->RemoveEntry( nStart, nEnd );
1745 0 : SwTxtFrm::repaintTextFrames( *pNode );
1746 : }
1747 0 : ++aIdx;
1748 0 : nStart = 0;
1749 0 : }
1750 0 : }
1751 :
1752 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|