LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/sw/source/core/txtnode - txtedt.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 602 1039 57.9 %
Date: 2013-07-09 Functions: 44 52 84.6 %
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             : 
      21             : #include <hintids.hxx>
      22             : #include <vcl/svapp.hxx>
      23             : #include <svl/itemiter.hxx>
      24             : #include <editeng/splwrap.hxx>
      25             : #include <editeng/langitem.hxx>
      26             : #include <editeng/fontitem.hxx>
      27             : #include <editeng/scripttypeitem.hxx>
      28             : #include <editeng/hangulhanja.hxx>
      29             : #include <SwSmartTagMgr.hxx>
      30             : #include <linguistic/lngprops.hxx>
      31             : #include <officecfg/Office/Writer.hxx>
      32             : #include <unotools/transliterationwrapper.hxx>
      33             : #include <unotools/charclass.hxx>
      34             : #include <dlelstnr.hxx>
      35             : #include <swmodule.hxx>
      36             : #include <splargs.hxx>
      37             : #include <viewopt.hxx>
      38             : #include <acmplwrd.hxx>
      39             : #include <doc.hxx>      // GetDoc()
      40             : #include <docsh.hxx>
      41             : #include <txtfld.hxx>
      42             : #include <fmtfld.hxx>
      43             : #include <txatbase.hxx>
      44             : #include <charatr.hxx>
      45             : #include <fldbas.hxx>
      46             : #include <pam.hxx>
      47             : #include <hints.hxx>
      48             : #include <ndtxt.hxx>
      49             : #include <txtfrm.hxx>
      50             : #include <SwGrammarMarkUp.hxx>
      51             : 
      52             : #include <txttypes.hxx>
      53             : #include <breakit.hxx>
      54             : #include <crstate.hxx>
      55             : #include <UndoOverwrite.hxx>
      56             : #include <txatritr.hxx>
      57             : #include <redline.hxx>      // SwRedline
      58             : #include <docary.hxx>       // SwRedlineTbl
      59             : #include <scriptinfo.hxx>
      60             : #include <docstat.hxx>
      61             : #include <editsh.hxx>
      62             : #include <unotextmarkup.hxx>
      63             : #include <txtatr.hxx>
      64             : #include <fmtautofmt.hxx>
      65             : #include <istyleaccess.hxx>
      66             : #include <unicode/uchar.h>
      67             : 
      68             : #include <unomid.h>
      69             : 
      70             : #include <com/sun/star/beans/XPropertySet.hpp>
      71             : #include <com/sun/star/i18n/WordType.hpp>
      72             : #include <com/sun/star/i18n/ScriptType.hpp>
      73             : #include <com/sun/star/i18n/TransliterationModules.hpp>
      74             : #include <com/sun/star/i18n/TransliterationModulesExtra.hpp>
      75             : 
      76             : #include <vector>
      77             : #include <utility>
      78             : 
      79             : #include <unotextrange.hxx>
      80             : 
      81             : using namespace ::com::sun::star;
      82             : using namespace ::com::sun::star::frame;
      83             : using namespace ::com::sun::star::i18n;
      84             : using namespace ::com::sun::star::beans;
      85             : using namespace ::com::sun::star::uno;
      86             : using namespace ::com::sun::star::linguistic2;
      87             : using namespace ::com::sun::star::smarttags;
      88             : 
      89             : // Wir ersparen uns in Hyphenate ein GetFrm()
      90             : // Achtung: in edlingu.cxx stehen die Variablen!
      91             : extern const SwTxtNode *pLinguNode;
      92             : extern       SwTxtFrm  *pLinguFrm;
      93             : 
      94             : /*
      95             :  * This has basically the same function as SwScriptInfo::MaskHiddenRanges,
      96             :  * only for deleted redlines
      97             :  */
      98             : 
      99             : static sal_uInt16
     100        1725 : lcl_MaskRedlines( const SwTxtNode& rNode, OUStringBuffer& rText,
     101             :                          const xub_StrLen nStt, const xub_StrLen nEnd,
     102             :                          const sal_Unicode cChar )
     103             : {
     104        1725 :     sal_uInt16 nNumOfMaskedRedlines = 0;
     105             : 
     106        1725 :     const SwDoc& rDoc = *rNode.GetDoc();
     107        1725 :     sal_uInt16 nAct = rDoc.GetRedlinePos( rNode, USHRT_MAX );
     108             : 
     109        1725 :     for ( ; nAct < rDoc.GetRedlineTbl().size(); nAct++ )
     110             :     {
     111           0 :         const SwRedline* pRed = rDoc.GetRedlineTbl()[ nAct ];
     112             : 
     113           0 :         if ( pRed->Start()->nNode > rNode.GetIndex() )
     114           0 :             break;
     115             : 
     116           0 :         if( nsRedlineType_t::REDLINE_DELETE == pRed->GetType() )
     117             :         {
     118             :             xub_StrLen nRedlineEnd;
     119             :             xub_StrLen nRedlineStart;
     120             : 
     121           0 :             pRed->CalcStartEnd( rNode.GetIndex(), nRedlineStart, nRedlineEnd );
     122             : 
     123           0 :             if ( nRedlineEnd < nStt || nRedlineStart > nEnd )
     124           0 :                 continue;
     125             : 
     126           0 :             while ( nRedlineStart < nRedlineEnd && nRedlineStart < nEnd )
     127             :             {
     128           0 :                 if ( nRedlineStart >= nStt && nRedlineStart < nEnd )
     129             :                 {
     130           0 :                     rText[nRedlineStart] = cChar;
     131           0 :                     ++nNumOfMaskedRedlines;
     132             :                 }
     133           0 :                 ++nRedlineStart;
     134             :             }
     135             :         }
     136             :     }
     137             : 
     138        1725 :     return nNumOfMaskedRedlines;
     139             : }
     140             : 
     141             : /*
     142             :  * Used for spell checking. Deleted redlines and hidden characters are masked
     143             :  */
     144             : 
     145             : static sal_uInt16
     146        1725 : lcl_MaskRedlinesAndHiddenText( const SwTxtNode& rNode, OUStringBuffer& rText,
     147             :                                       const xub_StrLen nStt, const xub_StrLen nEnd,
     148             :                                       const sal_Unicode cChar = CH_TXTATR_INWORD,
     149             :                                       bool bCheckShowHiddenChar = true )
     150             : {
     151        1725 :     sal_uInt16 nRedlinesMasked = 0;
     152        1725 :     sal_uInt16 nHiddenCharsMasked = 0;
     153             : 
     154        1725 :     const SwDoc& rDoc = *rNode.GetDoc();
     155        1725 :     const bool bShowChg = 0 != IDocumentRedlineAccess::IsShowChanges( rDoc.GetRedlineMode() );
     156             : 
     157             :     // If called from word count or from spell checking, deleted redlines
     158             :     // should be masked:
     159        1725 :     if ( bShowChg )
     160             :     {
     161        1725 :         nRedlinesMasked = lcl_MaskRedlines( rNode, rText, nStt, nEnd, cChar );
     162             :     }
     163             : 
     164        1725 :     const bool bHideHidden = !SW_MOD()->GetViewOption(rDoc.get(IDocumentSettingAccess::HTML_MODE))->IsShowHiddenChar();
     165             : 
     166             :     // If called from word count, we want to mask the hidden ranges even
     167             :     // if they are visible:
     168        1725 :     if ( !bCheckShowHiddenChar || bHideHidden )
     169             :     {
     170             :         nHiddenCharsMasked =
     171        1725 :             SwScriptInfo::MaskHiddenRanges( rNode, rText, nStt, nEnd, cChar );
     172             :     }
     173             : 
     174        1725 :     return nRedlinesMasked + nHiddenCharsMasked;
     175             : }
     176             : 
     177             : /*
     178             :  * Used for spell checking. Calculates a rectangle for repaint.
     179             :  */
     180             : 
     181          54 : static SwRect lcl_CalculateRepaintRect( SwTxtFrm& rTxtFrm, xub_StrLen nChgStart, xub_StrLen nChgEnd )
     182             : {
     183          54 :     SwRect aRect;
     184             : 
     185          54 :     SwTxtNode *pNode = rTxtFrm.GetTxtNode();
     186             : 
     187          54 :     SwNodeIndex aNdIdx( *pNode );
     188         108 :     SwPosition aPos( aNdIdx, SwIndex( pNode, nChgEnd ) );
     189          54 :     SwCrsrMoveState aTmpState( MV_NONE );
     190          54 :     aTmpState.b2Lines = sal_True;
     191          54 :     rTxtFrm.GetCharRect( aRect, aPos, &aTmpState );
     192             :     // information about end of repaint area
     193          54 :     Sw2LinesPos* pEnd2Pos = aTmpState.p2Lines;
     194             : 
     195          54 :     const SwTxtFrm *pEndFrm = &rTxtFrm;
     196             : 
     197         108 :     while( pEndFrm->HasFollow() &&
     198           0 :            nChgEnd >= pEndFrm->GetFollow()->GetOfst() )
     199           0 :         pEndFrm = pEndFrm->GetFollow();
     200             : 
     201          54 :     if ( pEnd2Pos )
     202             :     {
     203             :         // we are inside a special portion, take left border
     204           0 :         SWRECTFN( pEndFrm )
     205           0 :         (aRect.*fnRect->fnSetTop)( (pEnd2Pos->aLine.*fnRect->fnGetTop)() );
     206           0 :         if ( pEndFrm->IsRightToLeft() )
     207           0 :             (aRect.*fnRect->fnSetLeft)( (pEnd2Pos->aPortion.*fnRect->fnGetLeft)() );
     208             :         else
     209           0 :             (aRect.*fnRect->fnSetLeft)( (pEnd2Pos->aPortion.*fnRect->fnGetRight)() );
     210           0 :         (aRect.*fnRect->fnSetWidth)( 1 );
     211           0 :         (aRect.*fnRect->fnSetHeight)( (pEnd2Pos->aLine.*fnRect->fnGetHeight)() );
     212           0 :         delete pEnd2Pos;
     213             :     }
     214             : 
     215          54 :     aTmpState.p2Lines = NULL;
     216          54 :     SwRect aTmp;
     217          54 :     aPos = SwPosition( aNdIdx, SwIndex( pNode, nChgStart ) );
     218          54 :     rTxtFrm.GetCharRect( aTmp, aPos, &aTmpState );
     219             : 
     220             :     // i63141: GetCharRect(..) could cause a formatting,
     221             :     // during the formatting SwTxtFrms could be joined, deleted, created...
     222             :     // => we have to reinit pStartFrm and pEndFrm after the formatting
     223          54 :     const SwTxtFrm* pStartFrm = &rTxtFrm;
     224         108 :     while( pStartFrm->HasFollow() &&
     225           0 :            nChgStart >= pStartFrm->GetFollow()->GetOfst() )
     226           0 :         pStartFrm = pStartFrm->GetFollow();
     227          54 :     pEndFrm = pStartFrm;
     228         108 :     while( pEndFrm->HasFollow() &&
     229           0 :            nChgEnd >= pEndFrm->GetFollow()->GetOfst() )
     230           0 :         pEndFrm = pEndFrm->GetFollow();
     231             : 
     232             :     // information about start of repaint area
     233          54 :     Sw2LinesPos* pSt2Pos = aTmpState.p2Lines;
     234          54 :     if ( pSt2Pos )
     235             :     {
     236             :         // we are inside a special portion, take right border
     237           0 :         SWRECTFN( pStartFrm )
     238           0 :         (aTmp.*fnRect->fnSetTop)( (pSt2Pos->aLine.*fnRect->fnGetTop)() );
     239           0 :         if ( pStartFrm->IsRightToLeft() )
     240           0 :             (aTmp.*fnRect->fnSetLeft)( (pSt2Pos->aPortion.*fnRect->fnGetRight)() );
     241             :         else
     242           0 :             (aTmp.*fnRect->fnSetLeft)( (pSt2Pos->aPortion.*fnRect->fnGetLeft)() );
     243           0 :         (aTmp.*fnRect->fnSetWidth)( 1 );
     244           0 :         (aTmp.*fnRect->fnSetHeight)( (pSt2Pos->aLine.*fnRect->fnGetHeight)() );
     245           0 :         delete pSt2Pos;
     246             :     }
     247             : 
     248          54 :     bool bSameFrame = true;
     249             : 
     250          54 :     if( rTxtFrm.HasFollow() )
     251             :     {
     252           0 :         if( pEndFrm != pStartFrm )
     253             :         {
     254           0 :             bSameFrame = false;
     255           0 :             SwRect aStFrm( pStartFrm->PaintArea() );
     256             :             {
     257           0 :                 SWRECTFN( pStartFrm )
     258           0 :                 (aTmp.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)() );
     259           0 :                 (aTmp.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)() );
     260           0 :                 (aTmp.*fnRect->fnSetBottom)( (aStFrm.*fnRect->fnGetBottom)() );
     261             :             }
     262           0 :             aStFrm = pEndFrm->PaintArea();
     263             :             {
     264           0 :                 SWRECTFN( pEndFrm )
     265           0 :                 (aRect.*fnRect->fnSetTop)( (aStFrm.*fnRect->fnGetTop)() );
     266           0 :                 (aRect.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)() );
     267           0 :                 (aRect.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)() );
     268             :             }
     269           0 :             aRect.Union( aTmp );
     270             :             while( true )
     271             :             {
     272           0 :                 pStartFrm = pStartFrm->GetFollow();
     273           0 :                 if( pStartFrm == pEndFrm )
     274           0 :                     break;
     275           0 :                 aRect.Union( pStartFrm->PaintArea() );
     276           0 :             }
     277             :         }
     278             :     }
     279          54 :     if( bSameFrame )
     280             :     {
     281          54 :         SWRECTFN( pStartFrm )
     282          54 :         if( (aTmp.*fnRect->fnGetTop)() == (aRect.*fnRect->fnGetTop)() )
     283          45 :             (aRect.*fnRect->fnSetLeft)( (aTmp.*fnRect->fnGetLeft)() );
     284             :         else
     285             :         {
     286           9 :             SwRect aStFrm( pStartFrm->PaintArea() );
     287           9 :             (aRect.*fnRect->fnSetLeft)( (aStFrm.*fnRect->fnGetLeft)() );
     288           9 :             (aRect.*fnRect->fnSetRight)( (aStFrm.*fnRect->fnGetRight)() );
     289           9 :             (aRect.*fnRect->fnSetTop)( (aTmp.*fnRect->fnGetTop)() );
     290             :         }
     291             : 
     292          54 :         if( aTmp.Height() > aRect.Height() )
     293           0 :             aRect.Height( aTmp.Height() );
     294             :     }
     295             : 
     296         108 :     return aRect;
     297             : }
     298             : 
     299             : /*
     300             :  * Used for automatic styles. Used during RstAttr.
     301             :  */
     302             : 
     303         323 : static bool lcl_HaveCommonAttributes( IStyleAccess& rStyleAccess,
     304             :                                       const SfxItemSet* pSet1,
     305             :                                       sal_uInt16 nWhichId,
     306             :                                       const SfxItemSet& rSet2,
     307             :                                       boost::shared_ptr<SfxItemSet>& pStyleHandle )
     308             : {
     309         323 :     bool bRet = false;
     310             : 
     311         323 :     SfxItemSet* pNewSet = 0;
     312             : 
     313         323 :     if ( !pSet1 )
     314             :     {
     315             :         OSL_ENSURE( nWhichId, "lcl_HaveCommonAttributes not used correctly" );
     316           0 :         if ( SFX_ITEM_SET == rSet2.GetItemState( nWhichId, sal_False ) )
     317             :         {
     318           0 :             pNewSet = rSet2.Clone( sal_True );
     319           0 :             pNewSet->ClearItem( nWhichId );
     320             :         }
     321             :     }
     322         323 :     else if ( pSet1->Count() )
     323             :     {
     324         323 :         SfxItemIter aIter( *pSet1 );
     325         323 :         const SfxPoolItem* pItem = aIter.GetCurItem();
     326             :         while( true )
     327             :         {
     328         323 :             if ( SFX_ITEM_SET == rSet2.GetItemState( pItem->Which(), sal_False ) )
     329             :             {
     330          24 :                 if ( !pNewSet )
     331          24 :                     pNewSet = rSet2.Clone( sal_True );
     332          24 :                 pNewSet->ClearItem( pItem->Which() );
     333             :             }
     334             : 
     335         323 :             if( aIter.IsAtEnd() )
     336         323 :                 break;
     337             : 
     338           0 :             pItem = aIter.NextItem();
     339         323 :         }
     340             :     }
     341             : 
     342         323 :     if ( pNewSet )
     343             :     {
     344          24 :         if ( pNewSet->Count() )
     345          23 :             pStyleHandle = rStyleAccess.getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
     346          24 :         delete pNewSet;
     347          24 :         bRet = true;
     348             :     }
     349             : 
     350         323 :     return bRet;
     351             : }
     352             : 
     353             : /*
     354             :  * void SwTxtNode::RstAttr(const SwIndex &rIdx, sal_uInt16 nLen)
     355             :  *
     356             :  * Deletes all attributes, starting at position rIdx, for length nLen.
     357             :  */
     358             : 
     359             : /* 5 cases:
     360             :  * 1) The attribute is completely in the deletion range:
     361             :  *    -> delete it
     362             :  * 2) The end of the attribute is in the deletion range:
     363             :  *    -> delete it, then re-insert it with new end
     364             :  * 3) The start of the attribute is in the deletion range:
     365             :  *    -> delete it, then re-insert it with new start
     366             :  * 4) The attribute contains the deletion range:
     367             :  *       Split, i.e.,
     368             :  *    -> Delete, re-insert from old start to start of deletion range
     369             :  *    -> insert new attribute from end of deletion range to old end
     370             :  * 5) The attribute is outside the deletion range
     371             :  *    -> nothing to do
     372             :  */
     373             : 
     374         506 : void SwTxtNode::RstAttr(const SwIndex &rIdx, xub_StrLen nLen, sal_uInt16 nWhich,
     375             :                         const SfxItemSet* pSet, sal_Bool bInclRefToxMark )
     376             : {
     377             :     // Attribute?
     378         506 :     if ( !GetpSwpHints() )
     379         506 :         return;
     380             : 
     381         506 :     sal_uInt16 i = 0;
     382         506 :     xub_StrLen nStt = rIdx.GetIndex();
     383         506 :     xub_StrLen nEnd = nStt + nLen;
     384             :     xub_StrLen nAttrStart;
     385             :     SwTxtAttr *pHt;
     386             : 
     387         506 :     bool bChanged = false;
     388             : 
     389             :     // nMin and nMax initialized to maximum / minimum (inverse)
     390         506 :     xub_StrLen nMin = m_Text.getLength();
     391         506 :     xub_StrLen nMax = nStt;
     392             : 
     393         506 :     const bool bNoLen = !nMin;
     394             : 
     395             :     // We have to remember the "new" attributes, which have
     396             :     // been introduced by splitting surrounding attributes (case 4).
     397             :     // They may not be forgotten inside the "Forget" function
     398             :     //std::vector< const SwTxtAttr* > aNewAttributes;
     399             : 
     400             :     // iterate over attribute array until start of attribute is behind
     401             :     // deletion range
     402        3140 :     while ((i < m_pSwpHints->Count()) &&
     403         949 :         ((( nAttrStart = *(*m_pSwpHints)[i]->GetStart()) < nEnd ) || nLen==0) )
     404             :     {
     405         700 :         pHt = m_pSwpHints->GetTextHint(i);
     406             : 
     407             :         // attributes without end stay in!
     408         700 :         xub_StrLen * const pAttrEnd = pHt->GetEnd();
     409         700 :         if ( !pAttrEnd /*|| pHt->HasDummyChar()*/ ) // see bInclRefToxMark
     410             :         {
     411          55 :             i++;
     412         755 :             continue;
     413             :         }
     414             : 
     415             :         // Default behavior is to process all attributes:
     416         645 :         bool bSkipAttr = false;
     417         645 :         boost::shared_ptr<SfxItemSet> pStyleHandle;
     418             : 
     419             :         // 1. case: We want to reset only the attributes listed in pSet:
     420         645 :         if ( pSet )
     421             :         {
     422         645 :             bSkipAttr = SFX_ITEM_SET != pSet->GetItemState( pHt->Which(), sal_False );
     423         645 :             if ( bSkipAttr && RES_TXTATR_AUTOFMT == pHt->Which() )
     424             :             {
     425             :                 // if the current attribute is an autostyle, we have to check if the autostyle
     426             :                 // and pSet have any attributes in common. If so, pStyleHandle will contain
     427             :                 // a handle to AutoStyle / pSet:
     428         323 :                 bSkipAttr = !lcl_HaveCommonAttributes( getIDocumentStyleAccess(), pSet, 0, *static_cast<const SwFmtAutoFmt&>(pHt->GetAttr()).GetStyleHandle(), pStyleHandle );
     429             :             }
     430             :         }
     431           0 :         else if ( nWhich )
     432             :         {
     433             :             // 2. case: We want to reset only the attributes with WhichId nWhich:
     434           0 :             bSkipAttr = nWhich != pHt->Which();
     435           0 :             if ( bSkipAttr && RES_TXTATR_AUTOFMT == pHt->Which() )
     436             :             {
     437           0 :                 bSkipAttr = !lcl_HaveCommonAttributes( getIDocumentStyleAccess(), 0, nWhich, *static_cast<const SwFmtAutoFmt&>(pHt->GetAttr()).GetStyleHandle(), pStyleHandle );
     438             :             }
     439             :         }
     440           0 :         else if ( !bInclRefToxMark )
     441             :         {
     442             :             // 3. case: Reset all attributes except from ref/toxmarks:
     443             :             // skip hints with CH_TXTATR here
     444             :             // (deleting those is ONLY allowed for UNDO!)
     445           0 :             bSkipAttr = RES_TXTATR_REFMARK   == pHt->Which()
     446           0 :                      || RES_TXTATR_TOXMARK   == pHt->Which()
     447           0 :                      || RES_TXTATR_META      == pHt->Which()
     448           0 :                      || RES_TXTATR_METAFIELD == pHt->Which();
     449             :         }
     450             : 
     451         645 :         if ( bSkipAttr )
     452             :         {
     453         609 :             i++;
     454         609 :             continue;
     455             :         }
     456             : 
     457          36 :         if( nStt <= nAttrStart )          // Faelle: 1,3,5
     458             :         {
     459          36 :             if( nEnd > nAttrStart
     460           0 :                 || ( nEnd == *pAttrEnd && nEnd==nAttrStart ) )
     461             :             {
     462             :                 // Faelle: 1,3
     463          36 :                 if ( nMin > nAttrStart )
     464          36 :                     nMin = nAttrStart;
     465          36 :                 if ( nMax < *pAttrEnd )
     466          20 :                     nMax = *pAttrEnd;
     467             :                 // Falls wir nur ein nichtaufgespanntes Attribut entfernen,
     468             :                 // tun wir mal so, als ob sich nichts geaendert hat.
     469          36 :                 bChanged = bChanged || nEnd > nAttrStart || bNoLen;
     470          36 :                 if( *pAttrEnd <= nEnd )     // Fall: 1
     471             :                 {
     472          36 :                     const xub_StrLen nAttrEnd = *pAttrEnd;
     473             : 
     474          36 :                     m_pSwpHints->DeleteAtPos(i);
     475          36 :                     DestroyAttr( pHt );
     476             : 
     477          36 :                     if ( pStyleHandle.get() )
     478             :                     {
     479          23 :                         SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
     480          46 :                                 *pStyleHandle, nAttrStart, nAttrEnd );
     481          23 :                         InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
     482             :                     }
     483             : 
     484             :                     // if the last attribute is a Field, the HintsArray is
     485             :                     // deleted!
     486          36 :                     if ( !m_pSwpHints )
     487           0 :                         break;
     488             : 
     489             :                     //JP 26.11.96:
     490             :                     // beim DeleteAtPos wird ein Resort ausgefuehrt!!
     491             :                     // darum muessen wir wieder bei 0 anfangen!!!
     492             :                     // ueber den Fall 3 koennen Attribute nach hinten
     493             :                     // verschoben worden sein; damit stimmt jetzt das i
     494             :                     // nicht mehr!!!
     495          36 :                     i = 0;
     496             : 
     497          36 :                     continue;
     498             :                 }
     499             :                 else                        // Fall: 3
     500             :                 {
     501           0 :                     m_pSwpHints->NoteInHistory( pHt );
     502           0 :                     *pHt->GetStart() = nEnd;
     503           0 :                     m_pSwpHints->NoteInHistory( pHt, sal_True );
     504             : 
     505           0 :                     if ( pStyleHandle.get() && nAttrStart < nEnd )
     506             :                     {
     507           0 :                         SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
     508           0 :                                 *pStyleHandle, nAttrStart, nEnd );
     509           0 :                         InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
     510             :                     }
     511             : 
     512           0 :                     bChanged = true;
     513             :                 }
     514             :             }
     515             :         }
     516             :         else                                // Faelle: 2,4,5
     517           0 :             if( *pAttrEnd > nStt )     // Faelle: 2,4
     518             :             {
     519           0 :                 if( *pAttrEnd < nEnd )      // Fall: 2
     520             :                 {
     521           0 :                     if ( nMin > nAttrStart )
     522           0 :                         nMin = nAttrStart;
     523           0 :                     if ( nMax < *pAttrEnd )
     524           0 :                         nMax = *pAttrEnd;
     525           0 :                     bChanged = true;
     526             : 
     527           0 :                     const xub_StrLen nAttrEnd = *pAttrEnd;
     528             : 
     529           0 :                     m_pSwpHints->NoteInHistory( pHt );
     530           0 :                     *pAttrEnd = nStt;
     531           0 :                     m_pSwpHints->NoteInHistory( pHt, sal_True );
     532             : 
     533           0 :                     if ( pStyleHandle.get() )
     534             :                     {
     535           0 :                         SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
     536           0 :                                 *pStyleHandle, nStt, nAttrEnd );
     537           0 :                         InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
     538             :                     }
     539             :                 }
     540           0 :                 else if( nLen )             // Fall: 4
     541             :                 {       // bei Lange 0 werden beide Hints vom Insert(Ht)
     542             :                         // wieder zu einem zusammengezogen !!!!
     543           0 :                     if ( nMin > nAttrStart )
     544           0 :                         nMin = nAttrStart;
     545           0 :                     if ( nMax < *pAttrEnd )
     546           0 :                         nMax = *pAttrEnd;
     547           0 :                     bChanged = true;
     548           0 :                     xub_StrLen nTmpEnd = *pAttrEnd;
     549           0 :                     m_pSwpHints->NoteInHistory( pHt );
     550           0 :                     *pAttrEnd = nStt;
     551           0 :                     m_pSwpHints->NoteInHistory( pHt, sal_True );
     552             : 
     553           0 :                     if ( pStyleHandle.get() && nStt < nEnd )
     554             :                     {
     555           0 :                         SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
     556           0 :                                 *pStyleHandle, nStt, nEnd );
     557           0 :                         InsertHint( pNew, nsSetAttrMode::SETATTR_NOHINTADJUST );
     558             :                     }
     559             : 
     560           0 :                     if( nEnd < nTmpEnd )
     561             :                     {
     562           0 :                         SwTxtAttr* pNew = MakeTxtAttr( *GetDoc(),
     563           0 :                                 pHt->GetAttr(), nEnd, nTmpEnd );
     564           0 :                         if ( pNew )
     565             :                         {
     566           0 :                             SwTxtCharFmt* pCharFmt = dynamic_cast<SwTxtCharFmt*>(pHt);
     567           0 :                             if ( pCharFmt )
     568           0 :                                 static_cast<SwTxtCharFmt*>(pNew)->SetSortNumber( pCharFmt->GetSortNumber() );
     569             : 
     570             :                             InsertHint( pNew,
     571           0 :                                 nsSetAttrMode::SETATTR_NOHINTADJUST );
     572             :                         }
     573             : 
     574             :                         // jetzt kein i+1, weil das eingefuegte Attribut
     575             :                         // ein anderes auf die Position geschoben hat !
     576           0 :                         continue;
     577             :                     }
     578             :                 }
     579             :             }
     580           0 :         ++i;
     581           0 :     }
     582             : 
     583         506 :     TryDeleteSwpHints();
     584         506 :     if (bChanged)
     585             :     {
     586          36 :         if ( HasHints() )
     587             :         {   // possibly sometimes Resort would be sufficient, but...
     588          33 :             m_pSwpHints->MergePortions(*this);
     589             :         }
     590             :         //TxtFrm's reagieren auf aHint, andere auf aNew
     591          36 :         SwUpdateAttr aHint( nMin, nMax, 0 );
     592          36 :         NotifyClients( 0, &aHint );
     593          72 :         SwFmtChg aNew( GetFmtColl() );
     594          72 :         NotifyClients( 0, &aNew );
     595             :     }
     596             : }
     597             : 
     598           0 : sal_Int32 clipIndexBounds(const OUString &rStr, sal_Int32 nPos)
     599             : {
     600           0 :     if (nPos < 0)
     601           0 :         return 0;
     602           0 :     if (nPos > rStr.getLength())
     603           0 :         return rStr.getLength();
     604           0 :     return nPos;
     605             : }
     606             : 
     607             : /*************************************************************************
     608             :  *                SwTxtNode::GetCurWord()
     609             :  *
     610             :  * Aktuelles Wort zurueckliefern:
     611             :  * Wir suchen immer von links nach rechts, es wird also das Wort
     612             :  * vor nPos gesucht. Es sei denn, wir befinden uns am Anfang des
     613             :  * Absatzes, dann wird das erste Wort zurueckgeliefert.
     614             :  * Wenn dieses erste Wort nur aus Whitespaces besteht, returnen wir
     615             :  * einen leeren String.
     616             :  *************************************************************************/
     617             : 
     618           0 : XubString SwTxtNode::GetCurWord( xub_StrLen nPos ) const
     619             : {
     620             :     assert(nPos <= m_Text.getLength()); // invalid index
     621             : 
     622           0 :     if (m_Text.isEmpty())
     623           0 :         return m_Text;
     624             : 
     625           0 :     Boundary aBndry;
     626           0 :     const uno::Reference< XBreakIterator > &rxBreak = g_pBreakIt->GetBreakIter();
     627           0 :     if (rxBreak.is())
     628             :     {
     629           0 :         sal_Int16 nWordType = WordType::DICTIONARY_WORD;
     630           0 :         lang::Locale aLocale( g_pBreakIt->GetLocale( GetLang( nPos ) ) );
     631             : #if OSL_DEBUG_LEVEL > 1
     632             :         sal_Bool bBegin = rxBreak->isBeginWord( m_Text, nPos, aLocale, nWordType );
     633             :         sal_Bool bEnd   = rxBreak->isEndWord  ( m_Text, nPos, aLocale, nWordType );
     634             :         (void)bBegin;
     635             :         (void)bEnd;
     636             : #endif
     637             :         aBndry =
     638           0 :             rxBreak->getWordBoundary( m_Text, nPos, aLocale, nWordType, sal_True );
     639             : 
     640             :         // if no word was found use previous word (if any)
     641           0 :         if (aBndry.startPos == aBndry.endPos)
     642             :         {
     643           0 :             aBndry = rxBreak->previousWord( m_Text, nPos, aLocale, nWordType );
     644           0 :         }
     645             :     }
     646             : 
     647             :     // check if word was found and if it uses a symbol font, if so
     648             :     // enforce returning an empty string
     649           0 :     if (aBndry.endPos != aBndry.startPos && IsSymbol( (xub_StrLen)aBndry.startPos ))
     650           0 :         aBndry.endPos = aBndry.startPos;
     651             : 
     652             :     // can have -1 as start/end of bounds not found
     653           0 :     aBndry.startPos = clipIndexBounds(m_Text, aBndry.startPos);
     654           0 :     aBndry.endPos = clipIndexBounds(m_Text, aBndry.endPos);
     655             : 
     656             :     return m_Text.copy(aBndry.startPos,
     657           0 :                        aBndry.endPos - aBndry.startPos);
     658             : }
     659             : 
     660        1681 : SwScanner::SwScanner( const SwTxtNode& rNd, const OUString& rTxt,
     661             :     const LanguageType* pLang, const ModelToViewHelper& rConvMap,
     662             :     sal_uInt16 nType, sal_Int32 nStart, sal_Int32 nEnde, sal_Bool bClp )
     663             :     : rNode( rNd )
     664             :     , aPreDashReplacementText(rTxt)
     665             :     , pLanguage( pLang )
     666             :     , rConversionMap( rConvMap )
     667             :     , nLen( 0 )
     668             :     , nOverriddenDashCount( 0 )
     669             :     , nWordType( nType )
     670        1681 :     , bClip( bClp )
     671             : {
     672             :     OSL_ENSURE( !aPreDashReplacementText.isEmpty(), "SwScanner: EmptyString" );
     673        1681 :     nStartPos = nBegin = nStart;
     674        1681 :     nEndPos = nEnde;
     675             : 
     676             :     //MSWord f.e has special emdash and endash behaviour in that they break
     677             :     //words for the purposes of word counting, while a hyphen etc. doesn't.
     678             :     //
     679             :     //The default configuration treats emdash/endash as a word break, but
     680             :     //additional ones can be added in under tools->options
     681        1681 :     if (nWordType == i18n::WordType::WORD_COUNT)
     682             :     {
     683         538 :         OUString sDashes = officecfg::Office::Writer::WordCount::AdditionalSeparators::get();
     684        1076 :         OUStringBuffer aBuf(aPreDashReplacementText);
     685      110123 :         for (sal_Int32 i = nStartPos; i < nEndPos; ++i)
     686             :         {
     687      109585 :             sal_Unicode cChar = aBuf[i];
     688      109585 :             if (sDashes.indexOf(cChar) != -1)
     689             :             {
     690           7 :                 aBuf[i] = ' ';
     691           7 :                 ++nOverriddenDashCount;
     692             :             }
     693             :         }
     694        1076 :         aText = aBuf.makeStringAndClear();
     695             :     }
     696             :     else
     697        1143 :         aText = aPreDashReplacementText;
     698             : 
     699             :     assert(aPreDashReplacementText.getLength() == aText.getLength());
     700             : 
     701        1681 :     if ( pLanguage )
     702             :     {
     703          19 :         aCurrLang = *pLanguage;
     704             :     }
     705             :     else
     706             :     {
     707        1662 :         ModelToViewHelper::ModelPosition aModelBeginPos = rConversionMap.ConvertToModelPosition( nBegin );
     708        1662 :         const sal_Int32 nModelBeginPos = aModelBeginPos.mnPos;
     709        1662 :         aCurrLang = rNd.GetLang( nModelBeginPos );
     710             :     }
     711        1681 : }
     712             : 
     713             : namespace
     714             : {
     715             :     //fdo#45271 for Asian words count characters instead of words
     716        9578 :     sal_Int32 forceEachAsianCodePointToWord(const OUString &rText, sal_Int32 nBegin, sal_Int32 nLen)
     717             :     {
     718        9578 :         if (nLen > 1)
     719             :         {
     720        9387 :             const uno::Reference< XBreakIterator > &rxBreak = g_pBreakIt->GetBreakIter();
     721             : 
     722        9387 :             sal_uInt16 nCurrScript = rxBreak->getScriptType( rText, nBegin );
     723             : 
     724        9387 :             sal_Int32 indexUtf16 = nBegin;
     725        9387 :             rText.iterateCodePoints(&indexUtf16, 1);
     726             : 
     727             :             //First character is Asian, consider it a word :-(
     728        9387 :             if (nCurrScript == i18n::ScriptType::ASIAN)
     729             :             {
     730           6 :                 nLen = indexUtf16 - nBegin;
     731           6 :                 return nLen;
     732             :             }
     733             : 
     734             :             //First character was not Asian, consider appearance of any Asian character
     735             :             //to be the end of the word
     736      109606 :             while (indexUtf16 < nBegin + nLen)
     737             :             {
     738       90844 :                 nCurrScript = rxBreak->getScriptType( rText, indexUtf16 );
     739       90844 :                 if (nCurrScript == i18n::ScriptType::ASIAN)
     740             :                 {
     741           0 :                     nLen = indexUtf16 - nBegin;
     742           0 :                     return nLen;
     743             :                 }
     744       90844 :                 rText.iterateCodePoints(&indexUtf16, 1);
     745        9381 :             }
     746             :         }
     747        9572 :         return nLen;
     748             :     }
     749             : }
     750             : 
     751       20560 : sal_Bool SwScanner::NextWord()
     752             : {
     753       20560 :     nBegin = nBegin + nLen;
     754       20560 :     Boundary aBound;
     755             : 
     756       20560 :     CharClass& rCC = GetAppCharClass();
     757       20560 :     LanguageTag aOldLanguageTag = rCC.getLanguageTag();
     758             : 
     759             :     while ( true )
     760             :     {
     761             :         // skip non-letter characters:
     762       59326 :         while ( nBegin < aText.getLength() )
     763             :         {
     764       37113 :             if ( !u_isspace( aText[nBegin] ) )
     765             :             {
     766       20387 :                 if ( !pLanguage )
     767             :                 {
     768       20368 :                     const sal_uInt16 nNextScriptType = g_pBreakIt->GetBreakIter()->getScriptType( aText, nBegin );
     769       20368 :                     ModelToViewHelper::ModelPosition aModelBeginPos = rConversionMap.ConvertToModelPosition( nBegin );
     770       20368 :                     const sal_Int32 nBeginModelPos = aModelBeginPos.mnPos;
     771       20368 :                     aCurrLang = rNode.GetLang( nBeginModelPos, 1, nNextScriptType );
     772             :                 }
     773             : 
     774       20387 :                 if ( nWordType != i18n::WordType::WORD_COUNT )
     775             :                 {
     776       10809 :                     rCC.setLanguageTag( LanguageTag( g_pBreakIt->GetLocale( aCurrLang )) );
     777       10809 :                     if ( rCC.isLetterNumeric(OUString(aText[nBegin])) )
     778        9329 :                         break;
     779             :                 }
     780             :                 else
     781        9578 :                     break;
     782             :             }
     783       18206 :             ++nBegin;
     784             :         }
     785             : 
     786       20560 :         if ( nBegin >= aText.getLength() || nBegin >= nEndPos )
     787        1680 :             return sal_False;
     788             : 
     789             :         // get the word boundaries
     790       37760 :         aBound = g_pBreakIt->GetBreakIter()->getWordBoundary( aText, nBegin,
     791       18880 :                 g_pBreakIt->GetLocale( aCurrLang ), nWordType, sal_True );
     792             :         OSL_ENSURE( aBound.endPos >= aBound.startPos, "broken aBound result" );
     793             : 
     794             :         // we don't want to include preceeding text
     795             :         // to count words in text with mixed script punctuation correctly,
     796             :         // but we want to include preceeding symbols (eg. percent sign, section sign,
     797             :         // degree sign defined by dict_word_hu to spell check their affixed forms).
     798       18880 :         if (nWordType == i18n::WordType::WORD_COUNT && aBound.startPos < nBegin)
     799           5 :             aBound.startPos = nBegin;
     800             : 
     801             :         //no word boundaries could be found
     802       18880 :         if(aBound.endPos == aBound.startPos)
     803           0 :             return sal_False;
     804             : 
     805             :         //if a word before is found it has to be searched for the next
     806       18880 :         if(aBound.endPos == nBegin)
     807           0 :             ++nBegin;
     808             :         else
     809       18880 :             break;
     810             :     } // end while( true )
     811             : 
     812       18880 :     rCC.setLanguageTag( aOldLanguageTag );
     813             : 
     814             :     // #i89042, as discussed with HDU: don't evaluate script changes for word count. Use whole word.
     815       18880 :     if ( nWordType == i18n::WordType::WORD_COUNT )
     816             :     {
     817        9578 :         nBegin = std::max(aBound.startPos, nBegin);
     818        9578 :         nLen   = 0;
     819        9578 :         if (aBound.endPos > nBegin)
     820        9578 :             nLen = aBound.endPos - nBegin;
     821             :     }
     822             :     else
     823             :     {
     824             :         // we have to differenciate between these cases:
     825        9302 :         if ( aBound.startPos <= nBegin )
     826             :         {
     827             :             OSL_ENSURE( aBound.endPos >= nBegin, "Unexpected aBound result" );
     828             : 
     829             :             // restrict boundaries to script boundaries and nEndPos
     830        9302 :             const sal_uInt16 nCurrScript = g_pBreakIt->GetBreakIter()->getScriptType( aText, nBegin );
     831        9302 :             OUString aTmpWord = aText.copy( nBegin, aBound.endPos - nBegin );
     832       18604 :             const sal_Int32 nScriptEnd = nBegin +
     833       18604 :                 g_pBreakIt->GetBreakIter()->endOfScript( aTmpWord, 0, nCurrScript );
     834        9302 :             const sal_Int32 nEnd = std::min( aBound.endPos, nScriptEnd );
     835             : 
     836             :             // restrict word start to last script change position
     837        9302 :             sal_Int32 nScriptBegin = 0;
     838        9302 :             if ( aBound.startPos < nBegin )
     839             :             {
     840             :                 // search from nBegin backwards until the next script change
     841           0 :                 aTmpWord = aText.copy( aBound.startPos,
     842           0 :                                        nBegin - aBound.startPos + 1 );
     843           0 :                 nScriptBegin = aBound.startPos +
     844           0 :                     g_pBreakIt->GetBreakIter()->beginOfScript( aTmpWord, nBegin - aBound.startPos,
     845           0 :                                                     nCurrScript );
     846             :             }
     847             : 
     848        9302 :             nBegin = std::max( aBound.startPos, nScriptBegin );
     849        9302 :             nLen = nEnd - nBegin;
     850             :         }
     851             :         else
     852             :         {
     853           0 :             const sal_uInt16 nCurrScript = g_pBreakIt->GetBreakIter()->getScriptType( aText, aBound.startPos );
     854             :             OUString aTmpWord = aText.copy( aBound.startPos,
     855           0 :                                              aBound.endPos - aBound.startPos );
     856           0 :             const sal_Int32 nScriptEnd = aBound.startPos +
     857           0 :                 g_pBreakIt->GetBreakIter()->endOfScript( aTmpWord, 0, nCurrScript );
     858           0 :             const sal_Int32 nEnd = std::min( aBound.endPos, nScriptEnd );
     859           0 :             nBegin = aBound.startPos;
     860           0 :             nLen = nEnd - nBegin;
     861             :         }
     862             :     }
     863             : 
     864             :     // optionally clip the result of getWordBoundaries:
     865       18880 :     if ( bClip )
     866             :     {
     867        9578 :         aBound.startPos = std::max( aBound.startPos, nStartPos );
     868        9578 :         aBound.endPos = std::min( aBound.endPos, nEndPos );
     869        9578 :         nBegin = aBound.startPos;
     870        9578 :         nLen = aBound.endPos - nBegin;
     871             :     }
     872             : 
     873       18880 :     if( ! nLen )
     874           0 :         return sal_False;
     875             : 
     876       18880 :     if ( nWordType == i18n::WordType::WORD_COUNT )
     877        9578 :         nLen = forceEachAsianCodePointToWord(aText, nBegin, nLen);
     878             : 
     879       18880 :     aWord = aPreDashReplacementText.copy( nBegin, nLen );
     880             : 
     881       18880 :     return sal_True;
     882             : }
     883             : 
     884           0 : sal_uInt16 SwTxtNode::Spell(SwSpellArgs* pArgs)
     885             : {
     886             :     // Die Aehnlichkeiten zu SwTxtFrm::_AutoSpell sind beabsichtigt ...
     887             :     // ACHTUNG: Ev. Bugs in beiden Routinen fixen!
     888             : 
     889             :     xub_StrLen nBegin, nEnd;
     890             : 
     891             :     // modify string according to redline information and hidden text
     892           0 :     const OUString aOldTxt( m_Text );
     893           0 :     OUStringBuffer buf(m_Text);
     894             :     const bool bRestoreString =
     895           0 :         lcl_MaskRedlinesAndHiddenText(*this, buf, 0, m_Text.getLength()) > 0;
     896           0 :     if (bRestoreString)
     897             :     {   // ??? UGLY: is it really necessary to modify m_Text here?
     898           0 :         m_Text = buf.makeStringAndClear();
     899             :     }
     900             : 
     901           0 :     if ( pArgs->pStartNode != this )
     902           0 :         nBegin = 0;
     903             :     else
     904           0 :         nBegin = pArgs->pStartIdx->GetIndex();
     905             : 
     906           0 :     nEnd = ( pArgs->pEndNode != this )
     907           0 :             ? m_Text.getLength()
     908           0 :             : pArgs->pEndIdx->GetIndex();
     909             : 
     910           0 :     pArgs->xSpellAlt = NULL;
     911             : 
     912             :     // 4 cases:
     913             :     //
     914             :     // 1. IsWrongDirty = 0 and GetWrong = 0
     915             :     //      Everything is checked and correct
     916             :     // 2. IsWrongDirty = 0 and GetWrong = 1
     917             :     //      Everything is checked and errors are identified in the wrong list
     918             :     // 3. IsWrongDirty = 1 and GetWrong = 0
     919             :     //      Nothing has been checked
     920             :     // 4. IsWrongDirty = 1 and GetWrong = 1
     921             :     //      Text has been checked but there is an invalid range in the wrong list
     922             :     //
     923             :     // Nothing has to be done for case 1.
     924           0 :     if ( ( IsWrongDirty() || GetWrong() ) && m_Text.getLength() )
     925             :     {
     926           0 :         if (nBegin > m_Text.getLength())
     927             :         {
     928           0 :             nBegin = m_Text.getLength();
     929             :         }
     930           0 :         if (nEnd > m_Text.getLength())
     931             :         {
     932           0 :             nEnd = m_Text.getLength();
     933             :         }
     934             :         //
     935           0 :         if(!IsWrongDirty())
     936             :         {
     937           0 :             xub_StrLen nTemp = GetWrong()->NextWrong( nBegin );
     938           0 :             if(nTemp > nEnd)
     939             :             {
     940             :                 // reset original text
     941           0 :                 if ( bRestoreString )
     942             :                 {
     943           0 :                     m_Text = aOldTxt;
     944             :                 }
     945           0 :                 return 0;
     946             :             }
     947           0 :             if(nTemp > nBegin)
     948           0 :                 nBegin = nTemp;
     949             : 
     950             :         }
     951             : 
     952             :         // In case 2. we pass the wrong list to the scanned, because only
     953             :         // the words in the wrong list have to be checked
     954             :         SwScanner aScanner( *this, m_Text, 0, ModelToViewHelper(),
     955             :                             WordType::DICTIONARY_WORD,
     956           0 :                             nBegin, nEnd );
     957           0 :         while( !pArgs->xSpellAlt.is() && aScanner.NextWord() )
     958             :         {
     959           0 :             const XubString& rWord = aScanner.GetWord();
     960             : 
     961             :             // get next language for next word, consider language attributes
     962             :             // within the word
     963           0 :             LanguageType eActLang = aScanner.GetCurrentLanguage();
     964             : 
     965           0 :             if( rWord.Len() > 0 && LANGUAGE_NONE != eActLang )
     966             :             {
     967           0 :                 if (pArgs->xSpeller.is())
     968             :                 {
     969           0 :                     SvxSpellWrapper::CheckSpellLang( pArgs->xSpeller, eActLang );
     970           0 :                     pArgs->xSpellAlt = pArgs->xSpeller->spell( rWord, eActLang,
     971           0 :                                             Sequence< PropertyValue >() );
     972             :                 }
     973           0 :                 if( (pArgs->xSpellAlt).is() )
     974             :                 {
     975           0 :                     if( IsSymbol( aScanner.GetBegin() ) )
     976             :                     {
     977           0 :                         pArgs->xSpellAlt = NULL;
     978             :                     }
     979             :                     else
     980             :                     {
     981             :                         // make sure the selection build later from the data
     982             :                         // below does not include "in word" character to the
     983             :                         // left and right in order to preserve those. Therefore
     984             :                         // count those "in words" in order to modify the
     985             :                         // selection accordingly.
     986           0 :                         const sal_Unicode* pChar = rWord.GetBuffer();
     987           0 :                         xub_StrLen nLeft = 0;
     988           0 :                         while (pChar && *pChar++ == CH_TXTATR_INWORD)
     989           0 :                             ++nLeft;
     990           0 :                         pChar = rWord.Len() ? rWord.GetBuffer() + rWord.Len() - 1 : 0;
     991           0 :                         xub_StrLen nRight = 0;
     992           0 :                         while (pChar && *pChar-- == CH_TXTATR_INWORD)
     993           0 :                             ++nRight;
     994             : 
     995           0 :                         pArgs->pStartNode = this;
     996           0 :                         pArgs->pEndNode = this;
     997           0 :                         pArgs->pStartIdx->Assign(this, aScanner.GetEnd() - nRight );
     998           0 :                         pArgs->pEndIdx->Assign(this, aScanner.GetBegin() + nLeft );
     999             :                     }
    1000             :                 }
    1001             :             }
    1002           0 :         }
    1003             :     }
    1004             : 
    1005             :     // reset original text
    1006           0 :     if ( bRestoreString )
    1007             :     {
    1008           0 :         m_Text = aOldTxt;
    1009             :     }
    1010             : 
    1011           0 :     return pArgs->xSpellAlt.is() ? 1 : 0;
    1012             : }
    1013             : 
    1014           0 : void SwTxtNode::SetLanguageAndFont( const SwPaM &rPaM,
    1015             :     LanguageType nLang, sal_uInt16 nLangWhichId,
    1016             :     const Font *pFont,  sal_uInt16 nFontWhichId )
    1017             : {
    1018             :     sal_uInt16 aRanges[] = {
    1019             :             nLangWhichId, nLangWhichId,
    1020             :             nFontWhichId, nFontWhichId,
    1021           0 :             0, 0, 0 };
    1022           0 :     if (!pFont)
    1023           0 :         aRanges[2] = aRanges[3] = 0;    // clear entries with font WhichId
    1024             : 
    1025           0 :     SwEditShell *pEditShell = GetDoc()->GetEditShell();
    1026           0 :     SfxItemSet aSet( pEditShell->GetAttrPool(), aRanges );
    1027           0 :     aSet.Put( SvxLanguageItem( nLang, nLangWhichId ) );
    1028             : 
    1029             :     OSL_ENSURE( pFont, "target font missing?" );
    1030           0 :     if (pFont)
    1031             :     {
    1032           0 :         SvxFontItem aFontItem = (SvxFontItem&) aSet.Get( nFontWhichId );
    1033           0 :         aFontItem.SetFamilyName(   pFont->GetName());
    1034           0 :         aFontItem.SetFamily(       pFont->GetFamily());
    1035           0 :         aFontItem.SetStyleName(    pFont->GetStyleName());
    1036           0 :         aFontItem.SetPitch(        pFont->GetPitch());
    1037           0 :         aFontItem.SetCharSet( pFont->GetCharSet() );
    1038           0 :         aSet.Put( aFontItem );
    1039             :     }
    1040             : 
    1041           0 :     GetDoc()->InsertItemSet( rPaM, aSet, 0 );
    1042             :     // SetAttr( aSet );    <- Does not set language attribute of empty paragraphs correctly,
    1043             :     //                     <- because since there is no selection the flag to garbage
    1044             :     //                     <- collect all attributes is set, and therefore attributes spanned
    1045             :     //                     <- over empty selection are removed.
    1046             : 
    1047           0 : }
    1048             : 
    1049           0 : sal_uInt16 SwTxtNode::Convert( SwConversionArgs &rArgs )
    1050             : {
    1051             :     // get range of text within node to be converted
    1052             :     // (either all the text or the text within the selection
    1053             :     // when the conversion was started)
    1054             :     xub_StrLen nTextBegin, nTextEnd;
    1055             :     //
    1056           0 :     if ( rArgs.pStartNode != this )
    1057             :     {
    1058           0 :         nTextBegin = 0;
    1059             :     }
    1060             :     else
    1061           0 :         nTextBegin = rArgs.pStartIdx->GetIndex();
    1062           0 :     if (nTextBegin > m_Text.getLength())
    1063             :     {
    1064           0 :         nTextBegin = m_Text.getLength();
    1065             :     }
    1066             : 
    1067           0 :     nTextEnd = ( rArgs.pEndNode != this )
    1068           0 :         ?  m_Text.getLength()
    1069           0 :         :  ::std::min<xub_StrLen>(rArgs.pEndIdx->GetIndex(), m_Text.getLength());
    1070             : 
    1071           0 :     rArgs.aConvText = OUString();
    1072             : 
    1073             :     // modify string according to redline information and hidden text
    1074           0 :     const OUString aOldTxt( m_Text );
    1075           0 :     OUStringBuffer buf(m_Text);
    1076             :     const bool bRestoreString =
    1077           0 :         lcl_MaskRedlinesAndHiddenText(*this, buf, 0, m_Text.getLength()) > 0;
    1078           0 :     if (bRestoreString)
    1079             :     {   // ??? UGLY: is it really necessary to modify m_Text here?
    1080           0 :         m_Text = buf.makeStringAndClear();
    1081             :     }
    1082             : 
    1083           0 :     bool    bFound  = false;
    1084           0 :     xub_StrLen  nBegin  = nTextBegin;
    1085           0 :     xub_StrLen  nLen = 0;
    1086           0 :     LanguageType nLangFound = LANGUAGE_NONE;
    1087           0 :     if (m_Text.isEmpty())
    1088             :     {
    1089           0 :         if (rArgs.bAllowImplicitChangesForNotConvertibleText)
    1090             :         {
    1091             :             // create SwPaM with mark & point spanning empty paragraph
    1092             :             //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
    1093           0 :             SwPaM aCurPaM( *this, 0 );
    1094             : 
    1095             :             SetLanguageAndFont( aCurPaM,
    1096             :                     rArgs.nConvTargetLang, RES_CHRATR_CJK_LANGUAGE,
    1097           0 :                     rArgs.pTargetFont, RES_CHRATR_CJK_FONT );
    1098             :         }
    1099             :     }
    1100             :     else
    1101             :     {
    1102           0 :         SwLanguageIterator aIter( *this, nBegin );
    1103             : 
    1104             :         // Implicit changes require setting new attributes, which in turn destroys
    1105             :         // the attribute sequence on which aIter iterates. We store the necessary
    1106             :         // coordinates and apply those changes after iterating through the text.
    1107             :         typedef std::pair<xub_StrLen, xub_StrLen> ImplicitChangesRange;
    1108           0 :         std::vector<ImplicitChangesRange> aImplicitChanges;
    1109             : 
    1110             :         // find non zero length text portion of appropriate language
    1111           0 :         do {
    1112           0 :             nLangFound = aIter.GetLanguage();
    1113           0 :             bool bLangOk =  (nLangFound == rArgs.nConvSrcLang) ||
    1114           0 :                                 (editeng::HangulHanjaConversion::IsChinese( nLangFound ) &&
    1115           0 :                                  editeng::HangulHanjaConversion::IsChinese( rArgs.nConvSrcLang ));
    1116             : 
    1117           0 :             xub_StrLen nChPos = aIter.GetChgPos();
    1118             :             // the position at the end of the paragraph returns -1
    1119             :             // which becomes 65535 when converted to xub_StrLen,
    1120             :             // and thus must be cut to the end of the actual string.
    1121           0 :             if (nChPos == (xub_StrLen) -1)
    1122             :             {
    1123           0 :                 nChPos = m_Text.getLength();
    1124             :             }
    1125             : 
    1126           0 :             nLen = nChPos - nBegin;
    1127           0 :             bFound = bLangOk && nLen > 0;
    1128           0 :             if (!bFound)
    1129             :             {
    1130             :                 // create SwPaM with mark & point spanning the attributed text
    1131             :                 //SwPaM aCurPaM( *this, *this, nBegin, nBegin + nLen ); <-- wrong c-tor, does sth different
    1132           0 :                 SwPaM aCurPaM( *this, nBegin );
    1133           0 :                 aCurPaM.SetMark();
    1134           0 :                 aCurPaM.GetPoint()->nContent = nBegin + nLen;
    1135             : 
    1136             :                 // check script type of selected text
    1137           0 :                 SwEditShell *pEditShell = GetDoc()->GetEditShell();
    1138           0 :                 pEditShell->Push();             // save current cursor on stack
    1139           0 :                 pEditShell->SetSelection( aCurPaM );
    1140           0 :                 bool bIsAsianScript = (SCRIPTTYPE_ASIAN == pEditShell->GetScriptType());
    1141           0 :                 pEditShell->Pop( sal_False );   // restore cursor from stack
    1142             : 
    1143           0 :                 if (!bIsAsianScript && rArgs.bAllowImplicitChangesForNotConvertibleText)
    1144             :                 {
    1145             :                     // Store for later use
    1146           0 :                     aImplicitChanges.push_back(ImplicitChangesRange(nBegin, nBegin+nLen));
    1147             :                 }
    1148           0 :                 nBegin = nChPos;    // start of next language portion
    1149             :             }
    1150           0 :         } while (!bFound && aIter.Next());  /* loop while nothing was found and still sth is left to be searched */
    1151             : 
    1152             :         // Apply implicit changes, if any, now that aIter is no longer used
    1153           0 :         for (size_t i = 0; i < aImplicitChanges.size(); ++i)
    1154             :         {
    1155           0 :             SwPaM aPaM( *this, aImplicitChanges[i].first );
    1156           0 :             aPaM.SetMark();
    1157           0 :             aPaM.GetPoint()->nContent = aImplicitChanges[i].second;
    1158           0 :             SetLanguageAndFont( aPaM, rArgs.nConvTargetLang, RES_CHRATR_CJK_LANGUAGE, rArgs.pTargetFont, RES_CHRATR_CJK_FONT );
    1159           0 :         }
    1160             : 
    1161             :     }
    1162             : 
    1163             :     // keep resulting text within selection / range of text to be converted
    1164           0 :     if (nBegin < nTextBegin)
    1165           0 :         nBegin = nTextBegin;
    1166           0 :     if (nBegin + nLen > nTextEnd)
    1167           0 :         nLen = nTextEnd - nBegin;
    1168           0 :     bool bInSelection = nBegin < nTextEnd;
    1169             : 
    1170           0 :     if (bFound && bInSelection)     // convertible text found within selection/range?
    1171             :     {
    1172             :         OSL_ENSURE( !m_Text.isEmpty(), "convertible text portion missing!" );
    1173           0 :         rArgs.aConvText     = m_Text.copy(nBegin, nLen);
    1174           0 :         rArgs.nConvTextLang = nLangFound;
    1175             : 
    1176             :         // position where to start looking in next iteration (after current ends)
    1177           0 :         rArgs.pStartNode = this;
    1178           0 :         rArgs.pStartIdx->Assign(this, nBegin + nLen );
    1179             :         // end position (when we have travelled over the whole document)
    1180           0 :         rArgs.pEndNode = this;
    1181           0 :         rArgs.pEndIdx->Assign(this, nBegin );
    1182             :     }
    1183             : 
    1184             :     // restore original text
    1185           0 :     if ( bRestoreString )
    1186             :     {
    1187           0 :         m_Text = aOldTxt;
    1188             :     }
    1189             : 
    1190           0 :     return rArgs.aConvText.isEmpty() ? 0 : 1;
    1191             : }
    1192             : 
    1193             : // Die Aehnlichkeiten zu SwTxtNode::Spell sind beabsichtigt ...
    1194             : // ACHTUNG: Ev. Bugs in beiden Routinen fixen!
    1195        1725 : SwRect SwTxtFrm::_AutoSpell( const SwCntntNode* pActNode, const SwViewOption& rViewOpt, xub_StrLen nActPos )
    1196             : {
    1197        1725 :     SwRect aRect;
    1198             : #if OSL_DEBUG_LEVEL > 1
    1199             :     static bool bStop = false;
    1200             :     if ( bStop )
    1201             :         return aRect;
    1202             : #endif
    1203             :     // Die Aehnlichkeiten zu SwTxtNode::Spell sind beabsichtigt ...
    1204             :     // ACHTUNG: Ev. Bugs in beiden Routinen fixen!
    1205        1725 :     SwTxtNode *pNode = GetTxtNode();
    1206        1725 :     if( pNode != pActNode || !nActPos )
    1207         829 :         nActPos = STRING_LEN;
    1208             : 
    1209        1725 :     SwAutoCompleteWord& rACW = SwDoc::GetAutoCompleteWords();
    1210             : 
    1211             :     // modify string according to redline information and hidden text
    1212        1725 :     const OUString aOldTxt( pNode->GetTxt() );
    1213        3450 :     OUStringBuffer buf(pNode->m_Text);
    1214             :     const bool bRestoreString = lcl_MaskRedlinesAndHiddenText( *pNode, buf,
    1215        1725 :                 0, pNode->GetTxt().getLength()) > 0;
    1216        1725 :     if (bRestoreString)
    1217             :     {   // ??? UGLY: is it really necessary to modify m_Text here?
    1218           0 :         pNode->m_Text = buf.makeStringAndClear();
    1219             :     }
    1220             : 
    1221             :     // a change of data indicates that at least one word has been modified
    1222        1725 :     const bool bRedlineChg = (pNode->GetTxt().getStr() != aOldTxt.getStr());
    1223             : 
    1224        1725 :     xub_StrLen nBegin = 0;
    1225        1725 :     xub_StrLen nEnd = pNode->GetTxt().getLength();
    1226        1725 :     xub_StrLen nInsertPos = 0;
    1227        1725 :     xub_StrLen nChgStart = STRING_LEN;
    1228        1725 :     xub_StrLen nChgEnd = 0;
    1229        1725 :     xub_StrLen nInvStart = STRING_LEN;
    1230        1725 :     xub_StrLen nInvEnd = 0;
    1231             : 
    1232        2835 :     const bool bAddAutoCmpl = pNode->IsAutoCompleteWordDirty() &&
    1233        2835 :                                   rViewOpt.IsAutoCompleteWords();
    1234             : 
    1235        1725 :     if( pNode->GetWrong() )
    1236             :     {
    1237         877 :         nBegin = pNode->GetWrong()->GetBeginInv();
    1238         877 :         if( STRING_LEN != nBegin )
    1239             :         {
    1240         877 :             nEnd = pNode->GetWrong()->GetEndInv();
    1241         877 :             if (nEnd > pNode->GetTxt().getLength())
    1242             :             {
    1243          57 :                 nEnd = pNode->GetTxt().getLength();
    1244             :             }
    1245             :         }
    1246             : 
    1247             :         // get word around nBegin, we start at nBegin - 1
    1248         877 :         if ( STRING_LEN != nBegin )
    1249             :         {
    1250         877 :             if ( nBegin )
    1251         125 :                 --nBegin;
    1252             : 
    1253         877 :             LanguageType eActLang = pNode->GetLang( nBegin );
    1254             :             Boundary aBound =
    1255        2631 :                 g_pBreakIt->GetBreakIter()->getWordBoundary( pNode->GetTxt(), nBegin,
    1256         877 :                     g_pBreakIt->GetLocale( eActLang ),
    1257        2631 :                     WordType::DICTIONARY_WORD, sal_True );
    1258         877 :             nBegin = xub_StrLen(aBound.startPos);
    1259             :         }
    1260             : 
    1261             :         // get the position in the wrong list
    1262         877 :         nInsertPos = pNode->GetWrong()->GetWrongPos( nBegin );
    1263             : 
    1264             :         // sometimes we have to skip one entry
    1265         892 :         if( nInsertPos < pNode->GetWrong()->Count() &&
    1266          30 :             nBegin == pNode->GetWrong()->Pos( nInsertPos ) +
    1267          15 :                       pNode->GetWrong()->Len( nInsertPos ) )
    1268           0 :                 nInsertPos++;
    1269             :     }
    1270             : 
    1271        1725 :     bool bFresh = nBegin < nEnd;
    1272             : 
    1273        1725 :     if( nBegin < nEnd )
    1274             :     {
    1275             :         //! register listener to LinguServiceEvents now in order to get
    1276             :         //! notified about relevant changes in the future
    1277        1139 :         SwModule *pModule = SW_MOD();
    1278        1139 :         if (!pModule->GetLngSvcEvtListener().is())
    1279          10 :             pModule->CreateLngSvcEvtListener();
    1280             : 
    1281        1139 :         uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() );
    1282        1139 :         SwDoc* pDoc = pNode->GetDoc();
    1283             : 
    1284        1139 :         SwScanner aScanner( *pNode, pNode->GetTxt(), 0, ModelToViewHelper(),
    1285        3417 :                             WordType::DICTIONARY_WORD, nBegin, nEnd);
    1286             : 
    1287       11578 :         while( aScanner.NextWord() )
    1288             :         {
    1289        9300 :             const XubString& rWord = aScanner.GetWord();
    1290        9300 :             nBegin = aScanner.GetBegin();
    1291        9300 :             xub_StrLen nLen = aScanner.GetLen();
    1292             : 
    1293             :             // get next language for next word, consider language attributes
    1294             :             // within the word
    1295        9300 :             LanguageType eActLang = aScanner.GetCurrentLanguage();
    1296             : 
    1297        9300 :             sal_Bool bSpell = xSpell.is() ? xSpell->hasLanguage( eActLang ) : sal_False;
    1298        9300 :             if( bSpell && rWord.Len() > 0 )
    1299             :             {
    1300             :                 // check for: bAlter => xHyphWord.is()
    1301             :                 OSL_ENSURE(!bSpell || xSpell.is(), "NULL pointer");
    1302             : 
    1303        9234 :                 if( !xSpell->isValid( rWord, eActLang, Sequence< PropertyValue >() ) )
    1304             :                 {
    1305         924 :                     xub_StrLen nSmartTagStt = nBegin;
    1306         924 :                     xub_StrLen nDummy = 1;
    1307         924 :                     if ( !pNode->GetSmartTags() || !pNode->GetSmartTags()->InWrongWord( nSmartTagStt, nDummy ) )
    1308             :                     {
    1309         924 :                         if( !pNode->GetWrong() )
    1310             :                         {
    1311          60 :                             pNode->SetWrong( new SwWrongList( WRONGLIST_SPELL ) );
    1312          60 :                             pNode->GetWrong()->SetInvalid( 0, nEnd );
    1313             :                         }
    1314         924 :                         if( pNode->GetWrong()->Fresh( nChgStart, nChgEnd,
    1315         924 :                             nBegin, nLen, nInsertPos, nActPos ) )
    1316         284 :                             pNode->GetWrong()->Insert( OUString(), 0, nBegin, nLen, nInsertPos++ );
    1317             :                         else
    1318             :                         {
    1319         640 :                             nInvStart = nBegin;
    1320         640 :                             nInvEnd = nBegin + nLen;
    1321             :                         }
    1322             :                     }
    1323             :                 }
    1324        8310 :                 else if( bAddAutoCmpl && rACW.GetMinWordLen() <= rWord.Len() )
    1325             :                 {
    1326        4474 :                     if ( bRedlineChg )
    1327             :                     {
    1328           0 :                         XubString rNewWord( rWord );
    1329           0 :                         rACW.InsertWord( rNewWord, *pDoc );
    1330             :                     }
    1331             :                     else
    1332        4474 :                         rACW.InsertWord( rWord, *pDoc );
    1333             :                 }
    1334             :             }
    1335       10439 :         }
    1336             :     }
    1337             : 
    1338             :     // reset original text
    1339             :     // i63141 before calling GetCharRect(..) with formatting!
    1340        1725 :     if ( bRestoreString )
    1341             :     {
    1342           0 :         pNode->m_Text = aOldTxt;
    1343             :     }
    1344        1725 :     if( pNode->GetWrong() )
    1345             :     {
    1346         937 :         if( bFresh )
    1347             :             pNode->GetWrong()->Fresh( nChgStart, nChgEnd,
    1348         903 :                                       nEnd, 0, nInsertPos, nActPos );
    1349             : 
    1350             :         //
    1351             :         // Calculate repaint area:
    1352             :         //
    1353         937 :         if( nChgStart < nChgEnd )
    1354             :         {
    1355          54 :             aRect = lcl_CalculateRepaintRect( *this, nChgStart, nChgEnd );
    1356             :         }
    1357             : 
    1358         937 :         pNode->GetWrong()->SetInvalid( nInvStart, nInvEnd );
    1359         937 :         pNode->SetWrongDirty( STRING_LEN != pNode->GetWrong()->GetBeginInv() );
    1360         937 :         if( !pNode->GetWrong()->Count() && ! pNode->IsWrongDirty() )
    1361         236 :             pNode->SetWrong( NULL );
    1362             :     }
    1363             :     else
    1364         788 :         pNode->SetWrongDirty( false );
    1365             : 
    1366        1725 :     if( bAddAutoCmpl )
    1367        1110 :         pNode->SetAutoCompleteWordDirty( false );
    1368             : 
    1369        3450 :     return aRect;
    1370             : }
    1371             : 
    1372             : /** Function: SmartTagScan
    1373             : 
    1374             :     Function scans words in current text and checks them in the
    1375             :     smarttag libraries. If the check returns true to bounds of the
    1376             :     recognized words are stored into a list which is used later for drawing
    1377             :     the underline.
    1378             : 
    1379             :     @param SwCntntNode* pActNode
    1380             : 
    1381             :     @param xub_StrLen nActPos
    1382             : 
    1383             :     @return SwRect: Repaint area
    1384             : */
    1385           0 : SwRect SwTxtFrm::SmartTagScan( SwCntntNode* /*pActNode*/, xub_StrLen /*nActPos*/ )
    1386             : {
    1387           0 :     SwRect aRet;
    1388           0 :     SwTxtNode *pNode = GetTxtNode();
    1389           0 :     const OUString& rText = pNode->GetTxt();
    1390             : 
    1391             :     // Iterate over language portions
    1392           0 :     SmartTagMgr& rSmartTagMgr = SwSmartTagMgr::Get();
    1393             : 
    1394           0 :     SwWrongList* pSmartTagList = pNode->GetSmartTags();
    1395             : 
    1396           0 :     xub_StrLen nBegin = 0;
    1397           0 :     xub_StrLen nEnd = static_cast< xub_StrLen >(rText.getLength());
    1398             : 
    1399           0 :     if ( pSmartTagList )
    1400             :     {
    1401           0 :         if ( pSmartTagList->GetBeginInv() != STRING_LEN )
    1402             :         {
    1403           0 :             nBegin = pSmartTagList->GetBeginInv();
    1404           0 :             nEnd = std::min( pSmartTagList->GetEndInv(), (xub_StrLen)rText.getLength() );
    1405             : 
    1406           0 :             if ( nBegin < nEnd )
    1407             :             {
    1408           0 :                 const LanguageType aCurrLang = pNode->GetLang( nBegin );
    1409           0 :                 const com::sun::star::lang::Locale aCurrLocale = g_pBreakIt->GetLocale( aCurrLang );
    1410           0 :                 nBegin = static_cast< xub_StrLen >(g_pBreakIt->GetBreakIter()->beginOfSentence( rText, nBegin, aCurrLocale ));
    1411           0 :                 nEnd = static_cast< xub_StrLen >(std::min( rText.getLength(), g_pBreakIt->GetBreakIter()->endOfSentence( rText, nEnd, aCurrLocale ) ));
    1412             :             }
    1413             :         }
    1414             :     }
    1415             : 
    1416           0 :     const sal_uInt16 nNumberOfEntries = pSmartTagList ? pSmartTagList->Count() : 0;
    1417           0 :     sal_uInt16 nNumberOfRemovedEntries = 0;
    1418           0 :     sal_uInt16 nNumberOfInsertedEntries = 0;
    1419             : 
    1420             :     // clear smart tag list between nBegin and nEnd:
    1421           0 :     if ( 0 != nNumberOfEntries )
    1422             :     {
    1423           0 :         xub_StrLen nChgStart = STRING_LEN;
    1424           0 :         xub_StrLen nChgEnd = 0;
    1425           0 :         const sal_uInt16 nCurrentIndex = pSmartTagList->GetWrongPos( nBegin );
    1426           0 :         pSmartTagList->Fresh( nChgStart, nChgEnd, nBegin, nEnd - nBegin, nCurrentIndex, STRING_LEN );
    1427           0 :         nNumberOfRemovedEntries = nNumberOfEntries - pSmartTagList->Count();
    1428             :     }
    1429             : 
    1430           0 :     if ( nBegin < nEnd )
    1431             :     {
    1432             :         // Expand the string:
    1433           0 :         const ModelToViewHelper aConversionMap(*pNode);
    1434           0 :         OUString aExpandText = aConversionMap.getViewText();
    1435             : 
    1436             :         // Ownership ov ConversionMap is passed to SwXTextMarkup object!
    1437             :         com::sun::star::uno::Reference< com::sun::star::text::XTextMarkup > xTextMarkup =
    1438           0 :              new SwXTextMarkup( *pNode, aConversionMap );
    1439             : 
    1440           0 :         com::sun::star::uno::Reference< ::com::sun::star::frame::XController > xController = pNode->GetDoc()->GetDocShell()->GetController();
    1441             : 
    1442           0 :         SwPosition start(*pNode, nBegin);
    1443           0 :         SwPosition end  (*pNode, nEnd);
    1444           0 :         Reference< ::com::sun::star::text::XTextRange > xRange = SwXTextRange::CreateXTextRange(*pNode->GetDoc(), start, &end);
    1445             : 
    1446           0 :         rSmartTagMgr.RecognizeTextRange(xRange, xTextMarkup, xController);
    1447             : 
    1448             : 
    1449           0 :         xub_StrLen nLangBegin = nBegin;
    1450           0 :         xub_StrLen nLangEnd = nEnd;
    1451             : 
    1452             :         // smart tag recognization has to be done for each language portion:
    1453           0 :         SwLanguageIterator aIter( *pNode, nLangBegin );
    1454             : 
    1455           0 :         do
    1456             :         {
    1457           0 :             const LanguageType nLang = aIter.GetLanguage();
    1458           0 :             const com::sun::star::lang::Locale aLocale = g_pBreakIt->GetLocale( nLang );
    1459           0 :             nLangEnd = std::min( nEnd, aIter.GetChgPos() );
    1460             : 
    1461           0 :             const sal_uInt32 nExpandBegin = aConversionMap.ConvertToViewPosition( nLangBegin );
    1462           0 :             const sal_uInt32 nExpandEnd   = aConversionMap.ConvertToViewPosition( nLangEnd );
    1463             : 
    1464           0 :             rSmartTagMgr.RecognizeString(aExpandText, xTextMarkup, xController, aLocale, nExpandBegin, nExpandEnd - nExpandBegin );
    1465             : 
    1466           0 :             nLangBegin = nLangEnd;
    1467             :         }
    1468           0 :         while ( aIter.Next() && nLangEnd < nEnd );
    1469             : 
    1470           0 :         pSmartTagList = pNode->GetSmartTags();
    1471             : 
    1472           0 :         const sal_uInt16 nNumberOfEntriesAfterRecognize = pSmartTagList ? pSmartTagList->Count() : 0;
    1473           0 :         nNumberOfInsertedEntries = nNumberOfEntriesAfterRecognize - ( nNumberOfEntries - nNumberOfRemovedEntries );
    1474             :     }
    1475             : 
    1476           0 :     if( pSmartTagList )
    1477             :     {
    1478             :         //
    1479             :         // Update WrongList stuff
    1480             :         //
    1481           0 :         pSmartTagList->SetInvalid( STRING_LEN, 0 );
    1482           0 :         pNode->SetSmartTagDirty( STRING_LEN != pSmartTagList->GetBeginInv() );
    1483             : 
    1484           0 :         if( !pSmartTagList->Count() && !pNode->IsSmartTagDirty() )
    1485           0 :             pNode->SetSmartTags( NULL );
    1486             : 
    1487             :         //
    1488             :         // Calculate repaint area:
    1489             :         //
    1490             : #if OSL_DEBUG_LEVEL > 1
    1491             :         const sal_uInt16 nNumberOfEntriesAfterRecognize2 = pSmartTagList->Count();
    1492             :         (void) nNumberOfEntriesAfterRecognize2;
    1493             : #endif
    1494           0 :         if ( nBegin < nEnd && ( 0 != nNumberOfRemovedEntries ||
    1495             :                                 0 != nNumberOfInsertedEntries ) )
    1496             :         {
    1497           0 :             aRet = lcl_CalculateRepaintRect( *this, nBegin, nEnd );
    1498             :         }
    1499             :     }
    1500             :     else
    1501           0 :         pNode->SetSmartTagDirty( false );
    1502             : 
    1503           0 :     return aRet;
    1504             : }
    1505             : 
    1506             : // Wird vom CollectAutoCmplWords gerufen
    1507           3 : void SwTxtFrm::CollectAutoCmplWrds( SwCntntNode* pActNode, xub_StrLen nActPos )
    1508             : {
    1509           3 :     SwTxtNode *pNode = GetTxtNode();
    1510           3 :     if( pNode != pActNode || !nActPos )
    1511           3 :         nActPos = STRING_LEN;
    1512             : 
    1513           3 :     SwDoc* pDoc = pNode->GetDoc();
    1514           3 :     SwAutoCompleteWord& rACW = SwDoc::GetAutoCompleteWords();
    1515             : 
    1516           3 :     xub_StrLen nBegin = 0;
    1517           3 :     xub_StrLen nEnd = pNode->GetTxt().getLength();
    1518             :     xub_StrLen nLen;
    1519           3 :     bool bACWDirty = false, bAnyWrd = false;
    1520             : 
    1521           3 :     if( nBegin < nEnd )
    1522             :     {
    1523           3 :         sal_uInt16 nCnt = 200;
    1524           3 :         SwScanner aScanner( *pNode, pNode->GetTxt(), 0, ModelToViewHelper(),
    1525           6 :                             WordType::DICTIONARY_WORD, nBegin, nEnd );
    1526           6 :         while( aScanner.NextWord() )
    1527             :         {
    1528           0 :             nBegin = aScanner.GetBegin();
    1529           0 :             nLen = aScanner.GetLen();
    1530           0 :             if( rACW.GetMinWordLen() <= nLen )
    1531             :             {
    1532           0 :                 const XubString& rWord = aScanner.GetWord();
    1533             : 
    1534           0 :                 if( nActPos < nBegin || ( nBegin + nLen ) < nActPos )
    1535             :                 {
    1536           0 :                     if( rACW.GetMinWordLen() <= rWord.Len() )
    1537           0 :                         rACW.InsertWord( rWord, *pDoc );
    1538           0 :                     bAnyWrd = true;
    1539             :                 }
    1540             :                 else
    1541           0 :                     bACWDirty = true;
    1542             :             }
    1543           0 :             if( !--nCnt )
    1544             :             {
    1545           0 :                 if ( Application::AnyInput( VCL_INPUT_ANY ) )
    1546           3 :                     return;
    1547           0 :                 nCnt = 100;
    1548             :             }
    1549           3 :         }
    1550             :     }
    1551             : 
    1552           3 :     if( bAnyWrd && !bACWDirty )
    1553           0 :         pNode->SetAutoCompleteWordDirty( sal_False );
    1554             : }
    1555             : 
    1556             : /*************************************************************************
    1557             :  *                      SwTxtNode::Hyphenate
    1558             :  *************************************************************************/
    1559             : // Findet den TxtFrm und sucht dessen CalcHyph
    1560             : 
    1561           0 : sal_Bool SwTxtNode::Hyphenate( SwInterHyphInfo &rHyphInf )
    1562             : {
    1563             :     // Abkuerzung: am Absatz ist keine Sprache eingestellt:
    1564           0 :     if ( LANGUAGE_NONE == sal_uInt16( GetSwAttrSet().GetLanguage().GetLanguage() )
    1565           0 :          && USHRT_MAX == GetLang(0, m_Text.getLength()))
    1566             :     {
    1567           0 :         if( !rHyphInf.IsCheck() )
    1568           0 :             rHyphInf.SetNoLang( sal_True );
    1569           0 :         return sal_False;
    1570             :     }
    1571             : 
    1572           0 :     if( pLinguNode != this )
    1573             :     {
    1574           0 :         pLinguNode = this;
    1575           0 :         pLinguFrm = (SwTxtFrm*)getLayoutFrm( GetDoc()->GetCurrentLayout(), (Point*)(rHyphInf.GetCrsrPos()) );
    1576             :     }
    1577           0 :     SwTxtFrm *pFrm = pLinguFrm;
    1578           0 :     if( pFrm )
    1579           0 :         pFrm = &(pFrm->GetFrmAtOfst( rHyphInf.nStart ));
    1580             :     else
    1581             :     {
    1582             :         // 4935: Seit der Trennung ueber Sonderbereiche sind Faelle
    1583             :         // moeglich, in denen kein Frame zum Node vorliegt.
    1584             :         // Also keinOSL_ENSURE
    1585             :         OSL_ENSURE( pFrm, "!SwTxtNode::Hyphenate: can't find any frame" );
    1586           0 :         return sal_False;
    1587             :     }
    1588             : 
    1589           0 :     while( pFrm )
    1590             :     {
    1591           0 :         if( pFrm->Hyphenate( rHyphInf ) )
    1592             :         {
    1593             :             // Das Layout ist nicht robust gegen "Direktformatierung"
    1594             :             // (7821, 7662, 7408); vgl. layact.cxx,
    1595             :             // SwLayAction::_TurboAction(), if( !pCnt->IsValid() ...
    1596           0 :             pFrm->SetCompletePaint();
    1597           0 :             return sal_True;
    1598             :         }
    1599           0 :         pFrm = (SwTxtFrm*)(pFrm->GetFollow());
    1600           0 :         if( pFrm )
    1601             :         {
    1602           0 :             rHyphInf.nLen = rHyphInf.nLen - (pFrm->GetOfst() - rHyphInf.nStart);
    1603           0 :             rHyphInf.nStart = pFrm->GetOfst();
    1604             :         }
    1605             :     }
    1606           0 :     return sal_False;
    1607             : }
    1608             : 
    1609             : namespace
    1610             : {
    1611          22 :     struct swTransliterationChgData
    1612             :     {
    1613             :         xub_StrLen              nStart;
    1614             :         xub_StrLen              nLen;
    1615             :         String                  sChanged;
    1616             :         Sequence< sal_Int32 >   aOffsets;
    1617             :     };
    1618             : }
    1619             : 
    1620             : // change text to Upper/Lower/Hiragana/Katagana/...
    1621           6 : void SwTxtNode::TransliterateText(
    1622             :     utl::TransliterationWrapper& rTrans,
    1623             :     xub_StrLen nStt, xub_StrLen nEnd,
    1624             :     SwUndoTransliterate* pUndo )
    1625             : {
    1626           6 :     if (nStt < nEnd && g_pBreakIt->GetBreakIter().is())
    1627             :     {
    1628             :         // since we don't use Hiragana/Katakana or half-width/full-width transliterations here
    1629             :         // it is fine to use ANYWORD_IGNOREWHITESPACES. (ANY_WORD btw is broken and will
    1630             :         // occasionaly miss words in consecutive sentences). Also with ANYWORD_IGNOREWHITESPACES
    1631             :         // text like 'just-in-time' will be converted to 'Just-In-Time' which seems to be the
    1632             :         // proper thing to do.
    1633           6 :         const sal_Int16 nWordType = WordType::ANYWORD_IGNOREWHITESPACES;
    1634             : 
    1635             :         //! In order to have less trouble with changing text size, e.g. because
    1636             :         //! of ligatures or � (German small sz) being resolved, we need to process
    1637             :         //! the text replacements from end to start.
    1638             :         //! This way the offsets for the yet to be changed words will be
    1639             :         //! left unchanged by the already replaced text.
    1640             :         //! For this we temporarily save the changes to be done in this vector
    1641           6 :         std::vector< swTransliterationChgData >   aChanges;
    1642          12 :         swTransliterationChgData                  aChgData;
    1643             : 
    1644           6 :         if (rTrans.getType() == (sal_uInt32)TransliterationModulesExtra::TITLE_CASE)
    1645             :         {
    1646             :             // for 'capitalize every word' we need to iterate over each word
    1647             : 
    1648           1 :             Boundary aSttBndry;
    1649           1 :             Boundary aEndBndry;
    1650           2 :             aSttBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
    1651           1 :                         GetTxt(), nStt,
    1652           1 :                         g_pBreakIt->GetLocale( GetLang( nStt ) ),
    1653             :                         nWordType,
    1654           3 :                         sal_True /*prefer forward direction*/);
    1655           2 :             aEndBndry = g_pBreakIt->GetBreakIter()->getWordBoundary(
    1656           1 :                         GetTxt(), nEnd,
    1657           1 :                         g_pBreakIt->GetLocale( GetLang( nEnd ) ),
    1658             :                         nWordType,
    1659           3 :                         sal_False /*prefer backward direction*/);
    1660             : 
    1661             :             // prevent backtracking to the previous word if selection is at word boundary
    1662           1 :             if (aSttBndry.endPos <= nStt)
    1663             :             {
    1664           0 :                 aSttBndry = g_pBreakIt->GetBreakIter()->nextWord(
    1665           0 :                         GetTxt(), aSttBndry.endPos,
    1666           0 :                         g_pBreakIt->GetLocale( GetLang( aSttBndry.endPos ) ),
    1667           0 :                         nWordType);
    1668             :             }
    1669             :             // prevent advancing to the next word if selection is at word boundary
    1670           1 :             if (aEndBndry.startPos >= nEnd)
    1671             :             {
    1672           0 :                 aEndBndry = g_pBreakIt->GetBreakIter()->previousWord(
    1673           0 :                         GetTxt(), aEndBndry.startPos,
    1674           0 :                         g_pBreakIt->GetLocale( GetLang( aEndBndry.startPos ) ),
    1675           0 :                         nWordType);
    1676             :             }
    1677             : 
    1678           1 :             Boundary aCurWordBndry( aSttBndry );
    1679           3 :             while (aCurWordBndry.startPos <= aEndBndry.startPos)
    1680             :             {
    1681           1 :                 nStt = (xub_StrLen)aCurWordBndry.startPos;
    1682           1 :                 nEnd = (xub_StrLen)aCurWordBndry.endPos;
    1683           1 :                 sal_Int32 nLen = nEnd - nStt;
    1684             :                 OSL_ENSURE( nLen > 0, "invalid word length of 0" );
    1685             : 
    1686           1 :                 Sequence <sal_Int32> aOffsets;
    1687             :                 OUString const sChgd( rTrans.transliterate(
    1688           2 :                             GetTxt(), GetLang(nStt), nStt, nLen, &aOffsets) );
    1689             : 
    1690             :                 assert(nStt < m_Text.getLength());
    1691           1 :                 if (0 != rtl_ustr_shortenedCompare_WithLength(
    1692           2 :                             m_Text.getStr() + nStt, m_Text.getLength() - nStt,
    1693           3 :                             sChgd.getStr(), sChgd.getLength(), nLen))
    1694             :                 {
    1695           1 :                     aChgData.nStart     = nStt;
    1696           1 :                     aChgData.nLen       = nLen;
    1697           1 :                     aChgData.sChanged   = sChgd;
    1698           1 :                     aChgData.aOffsets   = aOffsets;
    1699           1 :                     aChanges.push_back( aChgData );
    1700             :                 }
    1701             : 
    1702           2 :                 aCurWordBndry = g_pBreakIt->GetBreakIter()->nextWord(
    1703           1 :                         GetTxt(), nEnd,
    1704           1 :                         g_pBreakIt->GetLocale( GetLang( nEnd ) ),
    1705           3 :                         nWordType);
    1706           1 :             }
    1707             :         }
    1708           5 :         else if (rTrans.getType() == (sal_uInt32)TransliterationModulesExtra::SENTENCE_CASE)
    1709             :         {
    1710             :             // for 'sentence case' we need to iterate sentence by sentence
    1711             : 
    1712           2 :             sal_Int32 nLastStart = g_pBreakIt->GetBreakIter()->beginOfSentence(
    1713           1 :                     GetTxt(), nEnd,
    1714           2 :                     g_pBreakIt->GetLocale( GetLang( nEnd ) ) );
    1715           2 :             sal_Int32 nLastEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
    1716           1 :                     GetTxt(), nLastStart,
    1717           2 :                     g_pBreakIt->GetLocale( GetLang( nLastStart ) ) );
    1718             : 
    1719             :             // extend nStt, nEnd to the current sentence boundaries
    1720           2 :             sal_Int32 nCurrentStart = g_pBreakIt->GetBreakIter()->beginOfSentence(
    1721           1 :                     GetTxt(), nStt,
    1722           2 :                     g_pBreakIt->GetLocale( GetLang( nStt ) ) );
    1723           2 :             sal_Int32 nCurrentEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
    1724           1 :                     GetTxt(), nCurrentStart,
    1725           2 :                     g_pBreakIt->GetLocale( GetLang( nCurrentStart ) ) );
    1726             : 
    1727             :             // prevent backtracking to the previous sentence if selection starts at end of a sentence
    1728           1 :             if (nCurrentEnd <= nStt)
    1729             :             {
    1730             :                 // now nCurrentStart is probably located on a non-letter word. (unless we
    1731             :                 // are in Asian text with no spaces...)
    1732             :                 // Thus to get the real sentence start we should locate the next real word,
    1733             :                 // that is one found by DICTIONARY_WORD
    1734           0 :                 i18n::Boundary aBndry = g_pBreakIt->GetBreakIter()->nextWord(
    1735           0 :                         GetTxt(), nCurrentEnd,
    1736           0 :                         g_pBreakIt->GetLocale( GetLang( nCurrentEnd ) ),
    1737           0 :                         i18n::WordType::DICTIONARY_WORD);
    1738             : 
    1739             :                 // now get new current sentence boundaries
    1740           0 :                 nCurrentStart = g_pBreakIt->GetBreakIter()->beginOfSentence(
    1741           0 :                         GetTxt(), aBndry.startPos,
    1742           0 :                         g_pBreakIt->GetLocale( GetLang( aBndry.startPos) ) );
    1743           0 :                 nCurrentEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
    1744           0 :                         GetTxt(), nCurrentStart,
    1745           0 :                         g_pBreakIt->GetLocale( GetLang( nCurrentStart) ) );
    1746             :             }
    1747             :             // prevent advancing to the next sentence if selection ends at start of a sentence
    1748           1 :             if (nLastStart >= nEnd)
    1749             :             {
    1750             :                 // now nCurrentStart is probably located on a non-letter word. (unless we
    1751             :                 // are in Asian text with no spaces...)
    1752             :                 // Thus to get the real sentence start we should locate the previous real word,
    1753             :                 // that is one found by DICTIONARY_WORD
    1754           0 :                 i18n::Boundary aBndry = g_pBreakIt->GetBreakIter()->previousWord(
    1755           0 :                         GetTxt(), nLastStart,
    1756           0 :                         g_pBreakIt->GetLocale( GetLang( nLastStart) ),
    1757           0 :                         i18n::WordType::DICTIONARY_WORD);
    1758           0 :                 nLastEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
    1759           0 :                         GetTxt(), aBndry.startPos,
    1760           0 :                         g_pBreakIt->GetLocale( GetLang( aBndry.startPos) ) );
    1761           0 :                 if (nCurrentEnd > nLastEnd)
    1762           0 :                     nCurrentEnd = nLastEnd;
    1763             :             }
    1764             : 
    1765           3 :             while (nCurrentStart < nLastEnd)
    1766             :             {
    1767           1 :                 sal_Int32 nLen = nCurrentEnd - nCurrentStart;
    1768             :                 OSL_ENSURE( nLen > 0, "invalid word length of 0" );
    1769             : 
    1770           1 :                 Sequence <sal_Int32> aOffsets;
    1771           1 :                 OUString const sChgd( rTrans.transliterate(GetTxt(),
    1772           3 :                     GetLang(nCurrentStart), nCurrentStart, nLen, &aOffsets) );
    1773             : 
    1774             :                 assert(nStt < m_Text.getLength());
    1775           1 :                 if (0 != rtl_ustr_shortenedCompare_WithLength(
    1776           2 :                             m_Text.getStr() + nStt, m_Text.getLength() - nStt,
    1777           3 :                             sChgd.getStr(), sChgd.getLength(), nLen))
    1778             :                 {
    1779           1 :                     aChgData.nStart     = nCurrentStart;
    1780           1 :                     aChgData.nLen       = nLen;
    1781           1 :                     aChgData.sChanged   = sChgd;
    1782           1 :                     aChgData.aOffsets   = aOffsets;
    1783           1 :                     aChanges.push_back( aChgData );
    1784             :                 }
    1785             : 
    1786           1 :                 Boundary aFirstWordBndry;
    1787           2 :                 aFirstWordBndry = g_pBreakIt->GetBreakIter()->nextWord(
    1788           1 :                         GetTxt(), nCurrentEnd,
    1789           1 :                         g_pBreakIt->GetLocale( GetLang( nCurrentEnd ) ),
    1790           2 :                         nWordType);
    1791           1 :                 nCurrentStart = aFirstWordBndry.startPos;
    1792           2 :                 nCurrentEnd = g_pBreakIt->GetBreakIter()->endOfSentence(
    1793           1 :                         GetTxt(), nCurrentStart,
    1794           2 :                         g_pBreakIt->GetLocale( GetLang( nCurrentStart ) ) );
    1795           1 :             }
    1796             :         }
    1797             :         else
    1798             :         {
    1799             :             // here we may transliterate over complete language portions...
    1800             : 
    1801             :             SwLanguageIterator* pIter;
    1802           4 :             if( rTrans.needLanguageForTheMode() )
    1803           3 :                 pIter = new SwLanguageIterator( *this, nStt );
    1804             :             else
    1805           1 :                 pIter = 0;
    1806             : 
    1807             :             xub_StrLen nEndPos;
    1808             :             sal_uInt16 nLang;
    1809           4 :             do {
    1810           4 :                 if( pIter )
    1811             :                 {
    1812           3 :                     nLang = pIter->GetLanguage();
    1813           3 :                     nEndPos = pIter->GetChgPos();
    1814           3 :                     if( nEndPos > nEnd )
    1815           0 :                         nEndPos = nEnd;
    1816             :                 }
    1817             :                 else
    1818             :                 {
    1819           1 :                     nLang = LANGUAGE_SYSTEM;
    1820           1 :                     nEndPos = nEnd;
    1821             :                 }
    1822           4 :                 xub_StrLen nLen = nEndPos - nStt;
    1823             : 
    1824           4 :                 Sequence <sal_Int32> aOffsets;
    1825             :                 OUString const sChgd( rTrans.transliterate(
    1826           8 :                             m_Text, nLang, nStt, nLen, &aOffsets) );
    1827             : 
    1828             :                 assert(nStt < m_Text.getLength());
    1829           4 :                 if (0 != rtl_ustr_shortenedCompare_WithLength(
    1830           8 :                             m_Text.getStr() + nStt, m_Text.getLength() - nStt,
    1831          12 :                             sChgd.getStr(), sChgd.getLength(), nLen))
    1832             :                 {
    1833           3 :                     aChgData.nStart     = nStt;
    1834           3 :                     aChgData.nLen       = nLen;
    1835           3 :                     aChgData.sChanged   = sChgd;
    1836           3 :                     aChgData.aOffsets   = aOffsets;
    1837           3 :                     aChanges.push_back( aChgData );
    1838             :                 }
    1839             : 
    1840           8 :                 nStt = nEndPos;
    1841           4 :             } while( nEndPos < nEnd && pIter && pIter->Next() );
    1842           4 :             delete pIter;
    1843             :         }
    1844             : 
    1845           6 :         if (!aChanges.empty())
    1846             :         {
    1847             :             // now apply the changes from end to start to leave the offsets of the
    1848             :             // yet unchanged text parts remain the same.
    1849           5 :             size_t nSum(m_Text.getLength());
    1850          10 :             for (size_t i = 0; i < aChanges.size(); ++i)
    1851             :             {   // check this here since AddChanges cannot be moved below
    1852             :                 // call to ReplaceTextOnly
    1853             :                 swTransliterationChgData & rData =
    1854           5 :                     aChanges[ aChanges.size() - 1 - i ];
    1855           5 :                 nSum = nSum + rData.sChanged.Len() - rData.nLen;
    1856           5 :                 if (nSum > TXTNODE_MAX)
    1857             :                 {
    1858             :                     SAL_WARN("sw.core", "SwTxtNode::ReplaceTextOnly: "
    1859             :                             "node text with insertion > TXTNODE_MAX.");
    1860           6 :                     return;
    1861             :                 }
    1862           5 :                 if (pUndo)
    1863           0 :                     pUndo->AddChanges( *this, rData.nStart, rData.nLen, rData.aOffsets );
    1864           5 :                 ReplaceTextOnly( rData.nStart, rData.nLen, rData.sChanged, rData.aOffsets );
    1865             :             }
    1866           6 :         }
    1867             :     }
    1868             : }
    1869             : 
    1870           5 : void SwTxtNode::ReplaceTextOnly( xub_StrLen nPos, xub_StrLen nLen,
    1871             :                                 const XubString& rText,
    1872             :                                 const Sequence<sal_Int32>& rOffsets )
    1873             : {
    1874             :     assert(static_cast<size_t>(m_Text.getLength()) +
    1875             :         static_cast<size_t>(rText.Len()) - nLen <= TXTNODE_MAX);
    1876             : 
    1877           5 :     m_Text = m_Text.replaceAt(nPos, nLen, rText);
    1878             : 
    1879           5 :     xub_StrLen nTLen = rText.Len();
    1880           5 :     const sal_Int32* pOffsets = rOffsets.getConstArray();
    1881             :     // now look for no 1-1 mapping -> move the indizies!
    1882             :     xub_StrLen nI, nMyOff;
    1883          35 :     for( nI = 0, nMyOff = nPos; nI < nTLen; ++nI, ++nMyOff )
    1884             :     {
    1885          30 :         xub_StrLen nOff = (xub_StrLen)pOffsets[ nI ];
    1886          30 :         if( nOff < nMyOff )
    1887             :         {
    1888             :             // something is inserted
    1889           0 :             xub_StrLen nCnt = 1;
    1890           0 :             while( nI + nCnt < nTLen && nOff == pOffsets[ nI + nCnt ] )
    1891           0 :                 ++nCnt;
    1892             : 
    1893           0 :             Update( SwIndex( this, nMyOff ), nCnt, sal_False );
    1894           0 :             nMyOff = nOff;
    1895             :             //nMyOff -= nCnt;
    1896           0 :             nI += nCnt - 1;
    1897             :         }
    1898          30 :         else if( nOff > nMyOff )
    1899             :         {
    1900             :             // something is deleted
    1901           0 :             Update( SwIndex( this, nMyOff+1 ), nOff - nMyOff, sal_True );
    1902           0 :             nMyOff = nOff;
    1903             :         }
    1904             :     }
    1905           5 :     if( nMyOff < nLen )
    1906             :         // something is deleted at the end
    1907           0 :         Update( SwIndex( this, nMyOff ), nLen - nMyOff, sal_True );
    1908             : 
    1909             :     // notify the layout!
    1910           5 :     SwDelTxt aDelHint( nPos, nTLen );
    1911           5 :     NotifyClients( 0, &aDelHint );
    1912             : 
    1913          10 :     SwInsTxt aHint( nPos, nTLen );
    1914          10 :     NotifyClients( 0, &aHint );
    1915           5 : }
    1916             : 
    1917             : // the return values allows us to see if we did the heavy-
    1918             : // lifting required to actually break and count the words.
    1919        3581 : bool SwTxtNode::CountWords( SwDocStat& rStat,
    1920             :                             xub_StrLen nStt, xub_StrLen nEnd ) const
    1921             : {
    1922        3581 :     if( nStt > nEnd )
    1923             :     {   // bad call
    1924           0 :         return false;
    1925             :     }
    1926        3581 :     if (IsInRedlines())
    1927             :     {   //not counting txtnodes used to hold deleted redline content
    1928           1 :         return false;
    1929             :     }
    1930        3580 :     bool bCountAll = ( (0 == nStt) && (GetTxt().getLength() == nEnd) );
    1931        3580 :     ++rStat.nAllPara; // #i93174#: count _all_ paragraphs
    1932        3580 :     if ( IsHidden() )
    1933             :     {   // not counting hidden paras
    1934          20 :         return false;
    1935             :     }
    1936             :     // count words in numbering string if started at beginning of para:
    1937        3560 :     bool bCountNumbering = nStt == 0;
    1938        3560 :     bool bHasBullet = false, bHasNumbering = false;
    1939        3560 :     OUString sNumString;
    1940        3560 :     if (bCountNumbering)
    1941             :     {
    1942        3560 :         sNumString = GetNumString();
    1943        3560 :         bHasNumbering = !sNumString.isEmpty();
    1944        3560 :         if (!bHasNumbering)
    1945        3164 :             bHasBullet = HasBullet();
    1946        3560 :         bCountNumbering = bHasNumbering || bHasBullet;
    1947             :     }
    1948             : 
    1949        3560 :     if( nStt == nEnd && !bCountNumbering)
    1950             :     {   // unnumbered empty node or empty selection
    1951        1815 :         return false;
    1952             :     }
    1953             : 
    1954             :     // count of non-empty paras
    1955        1745 :     ++rStat.nPara;
    1956             : 
    1957             :     // Shortcut when counting whole paragraph and current count is clean
    1958        1745 :     if ( bCountAll && !IsWordCountDirty() )
    1959             :     {
    1960             :         // accumulate into DocStat record to return the values
    1961         813 :         rStat.nWord += GetParaNumberOfWords();
    1962         813 :         rStat.nAsianWord += GetParaNumberOfAsianWords();
    1963         813 :         rStat.nChar += GetParaNumberOfChars();
    1964         813 :         rStat.nCharExcludingSpaces += GetParaNumberOfCharsExcludingSpaces();
    1965         813 :         return false;
    1966             :     }
    1967             : 
    1968             :     // ConversionMap to expand fields, remove invisible and redline deleted text for scanner
    1969        1864 :     const ModelToViewHelper aConversionMap(*this, EXPANDFIELDS | HIDEINVISIBLE | HIDEREDLINED);
    1970        1864 :     OUString aExpandText = aConversionMap.getViewText();
    1971             : 
    1972             :     // map start and end points onto the ConversionMap
    1973         932 :     const sal_uInt32 nExpandBegin = aConversionMap.ConvertToViewPosition( nStt );
    1974         932 :     const sal_uInt32 nExpandEnd   = aConversionMap.ConvertToViewPosition( nEnd );
    1975             : 
    1976         932 :     if (aExpandText.isEmpty() && !bCountNumbering)
    1977             :     {
    1978         412 :         return false;
    1979             :     }
    1980             : 
    1981             :     //do the count
    1982             :     // all counts exclude hidden paras and hidden+redlined within para
    1983             :     // definition of space/white chars in SwScanner (and BreakIter!)
    1984             :     // uses both u_isspace and BreakIter getWordBoundary in SwScanner
    1985         520 :     sal_uInt32 nTmpWords = 0;        // count of all words
    1986         520 :     sal_uInt32 nTmpAsianWords = 0;   //count of all Asian codepoints
    1987         520 :     sal_uInt32 nTmpChars = 0;        // count of all chars
    1988         520 :     sal_uInt32 nTmpCharsExcludingSpaces = 0;  // all non-white chars
    1989             : 
    1990             :     // count words in masked and expanded text:
    1991         520 :     if (!aExpandText.isEmpty())
    1992             :     {
    1993         519 :         if (g_pBreakIt->GetBreakIter().is())
    1994             :         {
    1995             :             // zero is NULL for pLanguage -----------v               last param = true for clipping
    1996             :             SwScanner aScanner( *this, aExpandText, 0, aConversionMap, i18n::WordType::WORD_COUNT,
    1997         519 :                                 nExpandBegin, nExpandEnd, true );
    1998             : 
    1999             :             // used to filter out scanner returning almost empty strings (len=1; unichar=0x0001)
    2000        1038 :             const OUString aBreakWord( CH_TXTATR_BREAKWORD );
    2001             : 
    2002       10597 :             while ( aScanner.NextWord() )
    2003             :             {
    2004             :                 //  1 is len(CH_TXTATR_BREAKWORD) : match returns length of match
    2005        9559 :                 if( 1 != aExpandText.match(aBreakWord, aScanner.GetBegin() ))
    2006             :                 {
    2007        9559 :                     ++nTmpWords;
    2008        9559 :                     const OUString &rWord = aScanner.GetWord();
    2009        9559 :                     if (g_pBreakIt->GetBreakIter()->getScriptType(rWord, 0) == i18n::ScriptType::ASIAN)
    2010          44 :                         ++nTmpAsianWords;
    2011        9559 :                     nTmpCharsExcludingSpaces += g_pBreakIt->getGraphemeCount(rWord);
    2012             :                 }
    2013             :             }
    2014             : 
    2015        1038 :             nTmpCharsExcludingSpaces += aScanner.getOverriddenDashCount();
    2016             :         }
    2017             : 
    2018         519 :         nTmpChars = g_pBreakIt->getGraphemeCount(aExpandText, nExpandBegin, nExpandEnd);
    2019             :     }
    2020             : 
    2021             :     // no nTmpCharsExcludingSpaces adjust needed neither for blanked out MaskedChars
    2022             :     // nor for mid-word selection - set scanner bClip = true at creation
    2023             : 
    2024             :     // count outline number label - ? no expansion into map
    2025             :     // always counts all of number-ish label
    2026         520 :     if (bHasNumbering) // count words in numbering string
    2027             :     {
    2028          19 :         LanguageType aLanguage = GetLang( 0 );
    2029             : 
    2030             :         SwScanner aScanner( *this, sNumString, &aLanguage, ModelToViewHelper(),
    2031          19 :                             i18n::WordType::WORD_COUNT, 0, sNumString.getLength(), true );
    2032             : 
    2033          57 :         while ( aScanner.NextWord() )
    2034             :         {
    2035          19 :             ++nTmpWords;
    2036          19 :             const OUString &rWord = aScanner.GetWord();
    2037          19 :             if (g_pBreakIt->GetBreakIter()->getScriptType(rWord, 0) == i18n::ScriptType::ASIAN)
    2038           0 :                 ++nTmpAsianWords;
    2039          19 :             nTmpCharsExcludingSpaces += g_pBreakIt->getGraphemeCount(rWord);
    2040             :         }
    2041             : 
    2042          19 :         nTmpCharsExcludingSpaces += aScanner.getOverriddenDashCount();
    2043          19 :         nTmpChars += g_pBreakIt->getGraphemeCount(sNumString);
    2044             :     }
    2045         501 :     else if ( bHasBullet )
    2046             :     {
    2047          15 :         ++nTmpWords;
    2048          15 :         ++nTmpChars;
    2049          15 :         ++nTmpCharsExcludingSpaces;
    2050             :     }
    2051             : 
    2052             :     // If counting the whole para then update cached values and mark clean
    2053         520 :     if ( bCountAll )
    2054             :     {
    2055         520 :         SetParaNumberOfWords( nTmpWords );
    2056         520 :         SetParaNumberOfAsianWords( nTmpAsianWords );
    2057         520 :         SetParaNumberOfChars( nTmpChars );
    2058         520 :         SetParaNumberOfCharsExcludingSpaces( nTmpCharsExcludingSpaces );
    2059         520 :         SetWordCountDirty( false );
    2060             :     }
    2061             :     // accumulate into DocStat record to return the values
    2062         520 :     rStat.nWord += nTmpWords;
    2063         520 :     rStat.nAsianWord += nTmpAsianWords;
    2064         520 :     rStat.nChar += nTmpChars;
    2065         520 :     rStat.nCharExcludingSpaces += nTmpCharsExcludingSpaces;
    2066             : 
    2067        4080 :     return true;
    2068             : }
    2069             : 
    2070             : //
    2071             : // Paragraph statistics start
    2072             : //
    2073             : struct SwParaIdleData_Impl
    2074             : {
    2075             :     SwWrongList* pWrong;                // for spell checking
    2076             :     SwGrammarMarkUp* pGrammarCheck;     // for grammar checking /  proof reading
    2077             :     SwWrongList* pSmartTags;
    2078             :     sal_uLong nNumberOfWords;
    2079             :     sal_uLong nNumberOfAsianWords;
    2080             :     sal_uLong nNumberOfChars;
    2081             :     sal_uLong nNumberOfCharsExcludingSpaces;
    2082             :     bool bWordCountDirty;
    2083             :     bool bWrongDirty;                   // Ist das Wrong-Feld auf invalid?
    2084             :     bool bGrammarCheckDirty;
    2085             :     bool bSmartTagDirty;
    2086             :     bool bAutoComplDirty;               // die ACompl-Liste muss angepasst werden
    2087             : 
    2088        8981 :     SwParaIdleData_Impl() :
    2089             :         pWrong              ( 0 ),
    2090             :         pGrammarCheck       ( 0 ),
    2091             :         pSmartTags          ( 0 ),
    2092             :         nNumberOfWords      ( 0 ),
    2093             :         nNumberOfAsianWords ( 0 ),
    2094             :         nNumberOfChars      ( 0 ),
    2095             :         nNumberOfCharsExcludingSpaces ( 0 ),
    2096             :         bWordCountDirty     ( true ),
    2097             :         bWrongDirty         ( true ),
    2098             :         bGrammarCheckDirty  ( true ),
    2099             :         bSmartTagDirty      ( true ),
    2100        8981 :         bAutoComplDirty     ( true ) {};
    2101             : };
    2102             : 
    2103       17922 : void SwTxtNode::InitSwParaStatistics( bool bNew )
    2104             : {
    2105       17922 :     if ( bNew )
    2106             :     {
    2107        8981 :         m_pParaIdleData_Impl = new SwParaIdleData_Impl;
    2108             :     }
    2109        8941 :     else if ( m_pParaIdleData_Impl )
    2110             :     {
    2111        8941 :         delete m_pParaIdleData_Impl->pWrong;
    2112        8941 :         delete m_pParaIdleData_Impl->pGrammarCheck;
    2113        8941 :         delete m_pParaIdleData_Impl->pSmartTags;
    2114        8941 :         delete m_pParaIdleData_Impl;
    2115        8941 :         m_pParaIdleData_Impl = 0;
    2116             :     }
    2117       17922 : }
    2118             : 
    2119        3040 : void SwTxtNode::SetWrong( SwWrongList* pNew, bool bDelete )
    2120             : {
    2121        3040 :     if ( m_pParaIdleData_Impl )
    2122             :     {
    2123        2464 :         if ( bDelete )
    2124             :         {
    2125        1483 :             delete m_pParaIdleData_Impl->pWrong;
    2126             :         }
    2127        2464 :         m_pParaIdleData_Impl->pWrong = pNew;
    2128             :     }
    2129        3040 : }
    2130             : 
    2131       35035 : SwWrongList* SwTxtNode::GetWrong()
    2132             : {
    2133       35035 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pWrong : 0;
    2134             : }
    2135             : 
    2136             : // #i71360#
    2137           0 : const SwWrongList* SwTxtNode::GetWrong() const
    2138             : {
    2139           0 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pWrong : 0;
    2140             : }
    2141             : 
    2142        2308 : void SwTxtNode::SetGrammarCheck( SwGrammarMarkUp* pNew, bool bDelete )
    2143             : {
    2144        2308 :     if ( m_pParaIdleData_Impl )
    2145             :     {
    2146        1732 :         if ( bDelete )
    2147             :         {
    2148         776 :             delete m_pParaIdleData_Impl->pGrammarCheck;
    2149             :         }
    2150        1732 :         m_pParaIdleData_Impl->pGrammarCheck = pNew;
    2151             :     }
    2152        2308 : }
    2153             : 
    2154       16190 : SwGrammarMarkUp* SwTxtNode::GetGrammarCheck()
    2155             : {
    2156       16190 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pGrammarCheck : 0;
    2157             : }
    2158             : 
    2159        2308 : void SwTxtNode::SetSmartTags( SwWrongList* pNew, bool bDelete )
    2160             : {
    2161             :     OSL_ENSURE( !pNew || SwSmartTagMgr::Get().IsSmartTagsEnabled(),
    2162             :             "Weird - we have a smart tag list without any recognizers?" );
    2163             : 
    2164        2308 :     if ( m_pParaIdleData_Impl )
    2165             :     {
    2166        1732 :         if ( bDelete )
    2167             :         {
    2168         776 :             delete m_pParaIdleData_Impl->pSmartTags;
    2169             :         }
    2170        1732 :         m_pParaIdleData_Impl->pSmartTags = pNew;
    2171             :     }
    2172        2308 : }
    2173             : 
    2174       19542 : SwWrongList* SwTxtNode::GetSmartTags()
    2175             : {
    2176       19542 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pSmartTags : 0;
    2177             : }
    2178             : 
    2179         520 : void SwTxtNode::SetParaNumberOfWords( sal_uLong nNew ) const
    2180             : {
    2181         520 :     if ( m_pParaIdleData_Impl )
    2182             :     {
    2183         520 :         m_pParaIdleData_Impl->nNumberOfWords = nNew;
    2184             :     }
    2185         520 : }
    2186             : 
    2187         813 : sal_uLong SwTxtNode::GetParaNumberOfWords() const
    2188             : {
    2189         813 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfWords : 0;
    2190             : }
    2191             : 
    2192         520 : void SwTxtNode::SetParaNumberOfAsianWords( sal_uLong nNew ) const
    2193             : {
    2194         520 :     if ( m_pParaIdleData_Impl )
    2195             :     {
    2196         520 :         m_pParaIdleData_Impl->nNumberOfAsianWords = nNew;
    2197             :     }
    2198         520 : }
    2199             : 
    2200         813 : sal_uLong SwTxtNode::GetParaNumberOfAsianWords() const
    2201             : {
    2202         813 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfAsianWords : 0;
    2203             : }
    2204             : 
    2205         520 : void SwTxtNode::SetParaNumberOfChars( sal_uLong nNew ) const
    2206             : {
    2207         520 :     if ( m_pParaIdleData_Impl )
    2208             :     {
    2209         520 :         m_pParaIdleData_Impl->nNumberOfChars = nNew;
    2210             :     }
    2211         520 : }
    2212             : 
    2213         813 : sal_uLong SwTxtNode::GetParaNumberOfChars() const
    2214             : {
    2215         813 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfChars : 0;
    2216             : }
    2217             : 
    2218        9926 : void SwTxtNode::SetWordCountDirty( bool bNew ) const
    2219             : {
    2220        9926 :     if ( m_pParaIdleData_Impl )
    2221             :     {
    2222        9350 :         m_pParaIdleData_Impl->bWordCountDirty = bNew;
    2223             :     }
    2224        9926 : }
    2225             : 
    2226         813 : sal_uLong SwTxtNode::GetParaNumberOfCharsExcludingSpaces() const
    2227             : {
    2228         813 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->nNumberOfCharsExcludingSpaces : 0;
    2229             : }
    2230             : 
    2231         520 : void SwTxtNode::SetParaNumberOfCharsExcludingSpaces( sal_uLong nNew ) const
    2232             : {
    2233         520 :     if ( m_pParaIdleData_Impl )
    2234             :     {
    2235         520 :         m_pParaIdleData_Impl->nNumberOfCharsExcludingSpaces = nNew;
    2236             :     }
    2237         520 : }
    2238             : 
    2239        3129 : bool SwTxtNode::IsWordCountDirty() const
    2240             : {
    2241        3129 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bWordCountDirty : 0;
    2242             : }
    2243        8858 : void SwTxtNode::SetWrongDirty( bool bNew ) const
    2244             : {
    2245        8858 :     if ( m_pParaIdleData_Impl )
    2246             :     {
    2247        8282 :         m_pParaIdleData_Impl->bWrongDirty = bNew;
    2248             :     }
    2249        8858 : }
    2250        7562 : bool SwTxtNode::IsWrongDirty() const
    2251             : {
    2252        7562 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bWrongDirty : 0;
    2253             : }
    2254        7121 : void SwTxtNode::SetGrammarCheckDirty( bool bNew ) const
    2255             : {
    2256        7121 :     if ( m_pParaIdleData_Impl )
    2257             :     {
    2258        6545 :         m_pParaIdleData_Impl->bGrammarCheckDirty = bNew;
    2259             :     }
    2260        7121 : }
    2261       21237 : bool SwTxtNode::IsGrammarCheckDirty() const
    2262             : {
    2263       21237 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bGrammarCheckDirty : 0;
    2264             : }
    2265        7121 : void SwTxtNode::SetSmartTagDirty( bool bNew ) const
    2266             : {
    2267        7121 :     if ( m_pParaIdleData_Impl )
    2268             :     {
    2269        6545 :         m_pParaIdleData_Impl->bSmartTagDirty = bNew;
    2270             :     }
    2271        7121 : }
    2272        5258 : bool SwTxtNode::IsSmartTagDirty() const
    2273             : {
    2274        5258 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bSmartTagDirty : 0;
    2275             : }
    2276       70078 : void SwTxtNode::SetAutoCompleteWordDirty( bool bNew ) const
    2277             : {
    2278       70078 :     if ( m_pParaIdleData_Impl )
    2279             :     {
    2280       69502 :         m_pParaIdleData_Impl->bAutoComplDirty = bNew;
    2281             :     }
    2282       70078 : }
    2283        4572 : bool SwTxtNode::IsAutoCompleteWordDirty() const
    2284             : {
    2285        4572 :     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->bAutoComplDirty : 0;
    2286          99 : }
    2287             : //
    2288             : // Paragraph statistics end
    2289             : //
    2290             : 
    2291             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10