LCOV - code coverage report
Current view: top level - sw/source/core/edit - edlingu.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 124 894 13.9 %
Date: 2015-06-13 12:38:46 Functions: 18 62 29.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11