LCOV - code coverage report
Current view: top level - sw/source/core/txtnode - txtedt.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 694 1060 65.5 %
Date: 2014-11-03 Functions: 46 52 88.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10