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