LCOV - code coverage report
Current view: top level - vcl/source/edit - texteng.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 710 1673 42.4 %
Date: 2012-08-25 Functions: 57 117 48.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 520 2146 24.2 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*************************************************************************
       3                 :            :  *
       4                 :            :  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       5                 :            :  *
       6                 :            :  * Copyright 2000, 2010 Oracle and/or its affiliates.
       7                 :            :  *
       8                 :            :  * OpenOffice.org - a multi-platform office productivity suite
       9                 :            :  *
      10                 :            :  * This file is part of OpenOffice.org.
      11                 :            :  *
      12                 :            :  * OpenOffice.org is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU Lesser General Public License version 3
      14                 :            :  * only, as published by the Free Software Foundation.
      15                 :            :  *
      16                 :            :  * OpenOffice.org is distributed in the hope that it will be useful,
      17                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19                 :            :  * GNU Lesser General Public License version 3 for more details
      20                 :            :  * (a copy is included in the LICENSE file that accompanied this code).
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU Lesser General Public License
      23                 :            :  * version 3 along with OpenOffice.org.  If not, see
      24                 :            :  * <http://www.openoffice.org/license.html>
      25                 :            :  * for a copy of the LGPLv3 License.
      26                 :            :  *
      27                 :            :  ************************************************************************/
      28                 :            : 
      29                 :            : #include <tools/stream.hxx>
      30                 :            : 
      31                 :            : #include <vcl/texteng.hxx>
      32                 :            : #include <vcl/textview.hxx>
      33                 :            : #include <textdoc.hxx>
      34                 :            : #include <textdat2.hxx>
      35                 :            : #include <textundo.hxx>
      36                 :            : #include <textund2.hxx>
      37                 :            : #include <svl/ctloptions.hxx>
      38                 :            : #include <vcl/window.hxx>
      39                 :            : 
      40                 :            : #include <vcl/edit.hxx>
      41                 :            : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
      42                 :            : #include <com/sun/star/beans/PropertyValues.hpp>
      43                 :            : 
      44                 :            : #include <com/sun/star/i18n/XBreakIterator.hpp>
      45                 :            : 
      46                 :            : #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
      47                 :            : 
      48                 :            : #include <com/sun/star/i18n/WordType.hpp>
      49                 :            : 
      50                 :            : #include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp>
      51                 :            : #include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
      52                 :            : #include <com/sun/star/i18n/ScriptType.hpp>
      53                 :            : 
      54                 :            : #include <comphelper/processfactory.hxx>
      55                 :            : 
      56                 :            : #include <unotools/localedatawrapper.hxx>
      57                 :            : #include <vcl/unohelp.hxx>
      58                 :            : 
      59                 :            : #include <vcl/svapp.hxx>
      60                 :            : #include <vcl/metric.hxx>
      61                 :            : 
      62                 :            : #include <unicode/ubidi.h>
      63                 :            : 
      64                 :            : #include <set>
      65                 :            : #include <vector>
      66                 :            : #include <boost/foreach.hpp>
      67                 :            : 
      68                 :            : using namespace ::com::sun::star;
      69                 :            : using namespace ::com::sun::star::uno;
      70                 :            : using namespace ::rtl;
      71                 :            : 
      72                 :            : 
      73                 :            : // -------------------------------------------------------------------------
      74                 :            : // (-) class TextEngine
      75                 :            : // -------------------------------------------------------------------------
      76 [ +  - ][ +  - ]:         90 : TextEngine::TextEngine()
      77                 :            : {
      78                 :         90 :     mpDoc = 0;
      79                 :         90 :     mpTEParaPortions = 0;
      80                 :            : 
      81 [ +  - ][ +  - ]:         90 :     mpViews = new TextViews;
      82                 :         90 :     mpActiveView = NULL;
      83                 :            : 
      84                 :         90 :     mbIsFormatting      = sal_False;
      85                 :         90 :     mbFormatted         = sal_False;
      86                 :         90 :     mbUpdate            = sal_True;
      87                 :         90 :     mbModified          = sal_False;
      88                 :         90 :     mbUndoEnabled       = sal_False;
      89                 :         90 :     mbIsInUndo          = sal_False;
      90                 :         90 :     mbDowning           = sal_False;
      91                 :         90 :     mbRightToLeft       = sal_False;
      92                 :         90 :     mbHasMultiLineParas = sal_False;
      93                 :            : 
      94                 :         90 :     meAlign         = TXTALIGN_LEFT;
      95                 :            : 
      96                 :         90 :     mnMaxTextWidth  = 0;
      97                 :         90 :     mnMaxTextLen    = 0;
      98                 :         90 :     mnCurTextWidth  = 0xFFFFFFFF;
      99                 :         90 :     mnCurTextHeight = 0;
     100                 :            : 
     101                 :         90 :     mpUndoManager   = NULL;
     102                 :         90 :        mpIMEInfos       = NULL;
     103                 :         90 :     mpLocaleDataWrapper = NULL;
     104                 :            : 
     105 [ +  - ][ +  - ]:         90 :     mpIdleFormatter = new IdleFormatter;
     106         [ +  - ]:         90 :     mpIdleFormatter->SetTimeoutHdl( LINK( this, TextEngine, IdleFormatHdl ) );
     107                 :            : 
     108 [ +  - ][ +  - ]:         90 :     mpRefDev = new VirtualDevice;
     109                 :            : 
     110         [ +  - ]:         90 :     ImpInitLayoutMode( mpRefDev );
     111                 :            : 
     112         [ +  - ]:         90 :     ImpInitDoc();
     113                 :            : 
     114                 :         90 :     maTextColor = COL_BLACK;
     115         [ +  - ]:         90 :     Font aFont;
     116         [ +  - ]:         90 :     aFont.SetTransparent( sal_False );
     117         [ +  - ]:         90 :     Color aFillColor( aFont.GetFillColor() );
     118         [ +  - ]:         90 :     aFillColor.SetTransparency( 0 );
     119         [ +  - ]:         90 :     aFont.SetFillColor( aFillColor );
     120 [ +  - ][ +  - ]:         90 :     SetFont( aFont );
     121                 :         90 : }
     122                 :            : 
     123         [ +  - ]:         90 : TextEngine::~TextEngine()
     124                 :            : {
     125                 :         90 :     mbDowning = sal_True;
     126                 :            : 
     127 [ +  - ][ +  - ]:         90 :     delete mpIdleFormatter;
     128 [ +  - ][ +  - ]:         90 :     delete mpDoc;
     129 [ +  - ][ +  - ]:         90 :     delete mpTEParaPortions;
     130         [ +  - ]:         90 :     delete mpViews; // nur die Liste, nicht die Vies
     131 [ +  - ][ +  - ]:         90 :     delete mpRefDev;
     132 [ -  + ][ #  # ]:         90 :     delete mpUndoManager;
     133 [ -  + ][ #  # ]:         90 :     delete mpIMEInfos;
     134 [ -  + ][ #  # ]:         90 :     delete mpLocaleDataWrapper;
     135         [ -  + ]:         90 : }
     136                 :            : 
     137                 :         90 : void TextEngine::InsertView( TextView* pTextView )
     138                 :            : {
     139                 :         90 :     mpViews->push_back( pTextView );
     140         [ +  - ]:         90 :     pTextView->SetSelection( TextSelection() );
     141                 :            : 
     142         [ +  - ]:         90 :     if ( !GetActiveView() )
     143                 :         90 :         SetActiveView( pTextView );
     144                 :         90 : }
     145                 :            : 
     146                 :          0 : void TextEngine::RemoveView( TextView* pTextView )
     147                 :            : {
     148         [ #  # ]:          0 :     TextViews::iterator it = std::find( mpViews->begin(), mpViews->end(), pTextView );
     149 [ #  # ][ #  # ]:          0 :     if( it != mpViews->end() )
     150                 :            :     {
     151         [ #  # ]:          0 :         pTextView->HideCursor();
     152         [ #  # ]:          0 :         mpViews->erase( it );
     153 [ #  # ][ #  # ]:          0 :         if ( pTextView == GetActiveView() )
     154         [ #  # ]:          0 :             SetActiveView( 0 );
     155                 :            :     }
     156                 :          0 : }
     157                 :            : 
     158                 :          0 : sal_uInt16 TextEngine::GetViewCount() const
     159                 :            : {
     160                 :          0 :     return mpViews->size();
     161                 :            : }
     162                 :            : 
     163                 :          0 : TextView* TextEngine::GetView( sal_uInt16 nView ) const
     164                 :            : {
     165                 :          0 :     return (*mpViews)[ nView ];
     166                 :            : }
     167                 :            : 
     168                 :         90 : TextView* TextEngine::GetActiveView() const
     169                 :            : {
     170                 :         90 :     return mpActiveView;
     171                 :            : }
     172                 :            : 
     173                 :         90 : void TextEngine::SetActiveView( TextView* pTextView )
     174                 :            : {
     175         [ +  - ]:         90 :     if ( pTextView != mpActiveView )
     176                 :            :     {
     177         [ -  + ]:         90 :         if ( mpActiveView )
     178                 :          0 :             mpActiveView->HideSelection();
     179                 :            : 
     180                 :         90 :         mpActiveView = pTextView;
     181                 :            : 
     182         [ +  - ]:         90 :         if ( mpActiveView )
     183                 :         90 :             mpActiveView->ShowSelection();
     184                 :            :     }
     185                 :         90 : }
     186                 :            : 
     187                 :        432 : void TextEngine::SetFont( const Font& rFont )
     188                 :            : {
     189         [ +  - ]:        432 :     if ( rFont != maFont )
     190                 :            :     {
     191         [ +  - ]:        432 :         maFont = rFont;
     192                 :            :         // #i40221# As the font's color now defaults to transparent (since i35764)
     193                 :            :         //  we have to choose a useful textcolor in this case.
     194                 :            :         // Otherwise maTextColor and maFont.GetColor() are both transparent....
     195 [ +  - ][ +  + ]:        432 :         if( rFont.GetColor() == COL_TRANSPARENT )
     196                 :         90 :             maTextColor = COL_BLACK;
     197                 :            :         else
     198         [ +  - ]:        342 :             maTextColor = rFont.GetColor();
     199                 :            : 
     200                 :            :         // Wegen Selektion keinen Transparenten Font zulassen...
     201                 :            :         // (Sonst spaeter in ImplPaint den Hintergrund anders loeschen...)
     202         [ +  - ]:        432 :         maFont.SetTransparent( sal_False );
     203                 :            :         // Tell VCL not to use the font color, use text color from OutputDevice
     204         [ +  - ]:        432 :         maFont.SetColor( COL_TRANSPARENT );
     205         [ +  - ]:        432 :         Color aFillColor( maFont.GetFillColor() );
     206         [ +  - ]:        432 :         aFillColor.SetTransparency( 0 );
     207         [ +  - ]:        432 :         maFont.SetFillColor( aFillColor );
     208                 :            : 
     209         [ +  - ]:        432 :         maFont.SetAlign( ALIGN_TOP );
     210         [ +  - ]:        432 :         mpRefDev->SetFont( maFont);
     211                 :        432 :         Size aTextSize;
     212 [ +  - ][ +  - ]:        432 :         aTextSize.Width() = mpRefDev->GetTextWidth(rtl::OUString("    "));
                 [ +  - ]
     213         [ +  - ]:        432 :         aTextSize.Height() = mpRefDev->GetTextHeight();
     214         [ -  + ]:        432 :         if ( !aTextSize.Width() )
     215 [ #  # ][ #  # ]:          0 :             aTextSize.Width() = mpRefDev->GetTextWidth(rtl::OUString("XXXX"));
                 [ #  # ]
     216                 :            : 
     217                 :        432 :         mnDefTab = (sal_uInt16)aTextSize.Width();
     218         [ -  + ]:        432 :         if ( !mnDefTab )
     219                 :          0 :             mnDefTab = 1;
     220                 :        432 :         mnCharHeight = (sal_uInt16)aTextSize.Height();
     221                 :        432 :         mnFixCharWidth100 = 0;
     222                 :            : 
     223         [ +  - ]:        432 :         FormatFullDoc();
     224         [ +  - ]:        432 :         UpdateViews();
     225                 :            : 
     226         [ +  + ]:        774 :         for ( sal_uInt16 nView = mpViews->size(); nView; )
     227                 :            :         {
     228         [ +  - ]:        342 :             TextView* pView = (*mpViews)[ --nView ];
     229 [ +  - ][ +  + ]:        342 :             pView->GetWindow()->SetInputContext( InputContext( GetFont(), !pView->IsReadOnly() ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) );
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     230                 :            :         }
     231                 :            :     }
     232                 :        432 : }
     233                 :            : 
     234                 :        184 : void TextEngine::SetMaxTextLen( sal_uLong nLen )
     235                 :            : {
     236                 :        184 :     mnMaxTextLen = nLen;
     237                 :        184 : }
     238                 :            : 
     239                 :         76 : void TextEngine::SetMaxTextWidth( sal_uLong nMaxWidth )
     240                 :            : {
     241         [ +  + ]:         76 :     if ( nMaxWidth != mnMaxTextWidth )
     242                 :            :     {
     243                 :         16 :         mnMaxTextWidth = Min( nMaxWidth, (sal_uLong)0x7FFFFFFF );
     244                 :         16 :         FormatFullDoc();
     245                 :         16 :         UpdateViews();
     246                 :            :     }
     247                 :         76 : }
     248                 :            : 
     249                 :            : static sal_Unicode static_aLFText[] = { '\n', 0 };
     250                 :            : static sal_Unicode static_aCRText[] = { '\r', 0 };
     251                 :            : static sal_Unicode static_aCRLFText[] = { '\r', '\n', 0 };
     252                 :            : 
     253                 :          0 : static inline const sal_Unicode* static_getLineEndText( LineEnd aLineEnd )
     254                 :            : {
     255                 :          0 :     const sal_Unicode* pRet = NULL;
     256                 :            : 
     257   [ #  #  #  # ]:          0 :     switch( aLineEnd )
     258                 :            :     {
     259                 :          0 :     case LINEEND_LF: pRet = static_aLFText;break;
     260                 :          0 :     case LINEEND_CR: pRet = static_aCRText;break;
     261                 :          0 :     case LINEEND_CRLF: pRet = static_aCRLFText;break;
     262                 :            :     }
     263                 :          0 :     return pRet;
     264                 :            : }
     265                 :            : 
     266                 :          0 : void  TextEngine::ReplaceText(const TextSelection& rSel, const String& rText)
     267                 :            : {
     268                 :          0 :     ImpInsertText( rSel, rText );
     269                 :          0 : }
     270                 :            : 
     271                 :          0 : String TextEngine::GetText( LineEnd aSeparator ) const
     272                 :            : {
     273                 :          0 :     return mpDoc->GetText( static_getLineEndText( aSeparator ) );
     274                 :            : }
     275                 :            : 
     276                 :          0 : String TextEngine::GetTextLines( LineEnd aSeparator ) const
     277                 :            : {
     278                 :          0 :     String aText;
     279                 :          0 :     sal_uLong nParas = mpTEParaPortions->Count();
     280                 :          0 :     const sal_Unicode* pSep = static_getLineEndText( aSeparator );
     281         [ #  # ]:          0 :     for ( sal_uLong nP = 0; nP < nParas; nP++ )
     282                 :            :     {
     283         [ #  # ]:          0 :         TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nP );
     284                 :            : 
     285                 :          0 :         sal_uInt16 nLines = pTEParaPortion->GetLines().size();
     286         [ #  # ]:          0 :         for ( sal_uInt16 nL = 0; nL < nLines; nL++ )
     287                 :            :         {
     288                 :          0 :             TextLine* pLine = pTEParaPortion->GetLines()[nL];
     289 [ #  # ][ #  # ]:          0 :             aText += pTEParaPortion->GetNode()->GetText().Copy( pLine->GetStart(), pLine->GetEnd() - pLine->GetStart() );
                 [ #  # ]
     290 [ #  # ][ #  # ]:          0 :             if ( pSep && ( ( (nP+1) < nParas ) || ( (nL+1) < nLines ) ) )
                 [ #  # ]
     291         [ #  # ]:          0 :                 aText += pSep;
     292                 :            :         }
     293                 :            :     }
     294                 :          0 :     return aText;
     295                 :            : }
     296                 :            : 
     297                 :          0 : String TextEngine::GetText( sal_uLong nPara ) const
     298                 :            : {
     299                 :          0 :     return mpDoc->GetText( nPara );
     300                 :            : }
     301                 :            : 
     302                 :          0 : sal_uLong TextEngine::GetTextLen( LineEnd aSeparator ) const
     303                 :            : {
     304                 :          0 :     return mpDoc->GetTextLen( static_getLineEndText( aSeparator ) );
     305                 :            : }
     306                 :            : 
     307                 :          0 : sal_uLong TextEngine::GetTextLen( const TextSelection& rSel, LineEnd aSeparator ) const
     308                 :            : {
     309                 :          0 :     TextSelection aSel( rSel );
     310         [ #  # ]:          0 :     aSel.Justify();
     311         [ #  # ]:          0 :     ValidateSelection( aSel );
     312         [ #  # ]:          0 :     return mpDoc->GetTextLen( static_getLineEndText( aSeparator ), &aSel );
     313                 :            : }
     314                 :            : 
     315                 :        436 : sal_uInt16 TextEngine::GetTextLen( sal_uLong nPara ) const
     316                 :            : {
     317                 :        436 :     return mpDoc->GetNodes().GetObject( nPara )->GetText().Len();
     318                 :            : }
     319                 :            : 
     320                 :          0 : void TextEngine::SetUpdateMode( sal_Bool bUpdate )
     321                 :            : {
     322         [ #  # ]:          0 :     if ( bUpdate != mbUpdate )
     323                 :            :     {
     324                 :          0 :         mbUpdate = bUpdate;
     325         [ #  # ]:          0 :         if ( mbUpdate )
     326                 :            :         {
     327                 :          0 :             FormatAndUpdate( GetActiveView() );
     328         [ #  # ]:          0 :             if ( GetActiveView() )
     329                 :          0 :                 GetActiveView()->ShowCursor();
     330                 :            :         }
     331                 :            :     }
     332                 :          0 : }
     333                 :            : 
     334                 :          0 : sal_Bool TextEngine::DoesKeyChangeText( const KeyEvent& rKeyEvent )
     335                 :            : {
     336                 :          0 :     sal_Bool bDoesChange = sal_False;
     337                 :            : 
     338                 :          0 :     KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction();
     339         [ #  # ]:          0 :     if ( eFunc != KEYFUNC_DONTKNOW )
     340                 :            :     {
     341         [ #  # ]:          0 :         switch ( eFunc )
     342                 :            :         {
     343                 :            :             case KEYFUNC_UNDO:
     344                 :            :             case KEYFUNC_REDO:
     345                 :            :             case KEYFUNC_CUT:
     346                 :          0 :             case KEYFUNC_PASTE: bDoesChange = sal_True;
     347                 :          0 :             break;
     348                 :            :             default:    // wird dann evtl. unten bearbeitet.
     349                 :          0 :                         eFunc = KEYFUNC_DONTKNOW;
     350                 :            :         }
     351                 :            :     }
     352         [ #  # ]:          0 :     if ( eFunc == KEYFUNC_DONTKNOW )
     353                 :            :     {
     354      [ #  #  # ]:          0 :         switch ( rKeyEvent.GetKeyCode().GetCode() )
     355                 :            :         {
     356                 :            :             case KEY_DELETE:
     357                 :            :             case KEY_BACKSPACE:
     358                 :            :             {
     359         [ #  # ]:          0 :                 if ( !rKeyEvent.GetKeyCode().IsMod2() )
     360                 :          0 :                     bDoesChange = sal_True;
     361                 :            :             }
     362                 :          0 :             break;
     363                 :            :             case KEY_RETURN:
     364                 :            :             case KEY_TAB:
     365                 :            :             {
     366 [ #  # ][ #  # ]:          0 :                 if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() )
                 [ #  # ]
     367                 :          0 :                     bDoesChange = sal_True;
     368                 :            :             }
     369                 :          0 :             break;
     370                 :            :             default:
     371                 :            :             {
     372                 :          0 :                 bDoesChange = TextEngine::IsSimpleCharInput( rKeyEvent );
     373                 :            :             }
     374                 :            :         }
     375                 :            :     }
     376                 :          0 :     return bDoesChange;
     377                 :            : }
     378                 :            : 
     379                 :          0 : sal_Bool TextEngine::IsSimpleCharInput( const KeyEvent& rKeyEvent )
     380                 :            : {
     381 [ #  # ][ #  #  :          0 :     if( rKeyEvent.GetCharCode() >= 32 && rKeyEvent.GetCharCode() != 127 &&
             #  #  #  # ]
                 [ #  # ]
     382                 :          0 :         KEY_MOD1 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT) && // (ssa) #i45714#:
     383                 :          0 :         KEY_MOD2 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT) )  // check for Ctrl and Alt separately
     384                 :            :     {
     385                 :          0 :         return sal_True;
     386                 :            :     }
     387                 :          0 :     return sal_False;
     388                 :            : }
     389                 :            : 
     390                 :        218 : void TextEngine::ImpInitDoc()
     391                 :            : {
     392         [ +  + ]:        218 :     if ( mpDoc )
     393                 :        128 :         mpDoc->Clear();
     394                 :            :     else
     395         [ +  - ]:         90 :         mpDoc = new TextDoc;
     396                 :            : 
     397         [ +  + ]:        218 :     delete mpTEParaPortions;
     398         [ +  - ]:        218 :     mpTEParaPortions = new TEParaPortions;
     399                 :            : 
     400 [ +  - ][ +  - ]:        218 :     TextNode* pNode = new TextNode( String() );
     401                 :        218 :     mpDoc->GetNodes().Insert( pNode, 0 );
     402                 :            : 
     403         [ +  - ]:        218 :     TEParaPortion* pIniPortion = new TEParaPortion( pNode );
     404                 :        218 :     mpTEParaPortions->Insert( pIniPortion, (sal_uLong)0 );
     405                 :            : 
     406                 :        218 :     mbFormatted = sal_False;
     407                 :            : 
     408                 :        218 :     ImpParagraphRemoved( TEXT_PARA_ALL );
     409                 :        218 :     ImpParagraphInserted( 0 );
     410                 :        218 : }
     411                 :            : 
     412                 :          0 : String TextEngine::GetText( const TextSelection& rSel, LineEnd aSeparator ) const
     413                 :            : {
     414         [ #  # ]:          0 :     String aText;
     415                 :            : 
     416         [ #  # ]:          0 :     if ( !rSel.HasRange() )
     417                 :            :         return aText;
     418                 :            : 
     419                 :          0 :     TextSelection aSel( rSel );
     420         [ #  # ]:          0 :     aSel.Justify();
     421                 :            : 
     422                 :          0 :     sal_uLong nStartPara = aSel.GetStart().GetPara();
     423                 :          0 :     sal_uLong nEndPara = aSel.GetEnd().GetPara();
     424                 :          0 :     const sal_Unicode* pSep = static_getLineEndText( aSeparator );
     425         [ #  # ]:          0 :     for ( sal_uLong nNode = aSel.GetStart().GetPara(); nNode <= nEndPara; nNode++ )
     426                 :            :     {
     427         [ #  # ]:          0 :         TextNode* pNode = mpDoc->GetNodes().GetObject( nNode );
     428                 :            : 
     429                 :          0 :         sal_uInt16 nStartPos = 0;
     430                 :          0 :         sal_uInt16 nEndPos = pNode->GetText().Len();
     431         [ #  # ]:          0 :         if ( nNode == nStartPara )
     432                 :          0 :             nStartPos = aSel.GetStart().GetIndex();
     433         [ #  # ]:          0 :         if ( nNode == nEndPara ) // kann auch == nStart sein!
     434                 :          0 :             nEndPos = aSel.GetEnd().GetIndex();
     435                 :            : 
     436 [ #  # ][ #  # ]:          0 :         aText += pNode->GetText().Copy( nStartPos, nEndPos-nStartPos );
                 [ #  # ]
     437         [ #  # ]:          0 :         if ( nNode < nEndPara )
     438         [ #  # ]:          0 :             aText += pSep;
     439                 :            :     }
     440                 :          0 :     return aText;
     441                 :            : }
     442                 :            : 
     443                 :        128 : void TextEngine::ImpRemoveText()
     444                 :            : {
     445         [ +  - ]:        128 :     ImpInitDoc();
     446                 :            : 
     447                 :        128 :     TextPaM aStartPaM( 0, 0 );
     448         [ +  - ]:        128 :     TextSelection aEmptySel( aStartPaM, aStartPaM );
     449         [ +  + ]:        256 :     for ( sal_uInt16 nView = 0; nView < mpViews->size(); nView++ )
     450                 :            :     {
     451         [ +  - ]:        128 :         TextView* pView = (*mpViews)[ nView ];
     452         [ +  - ]:        128 :         pView->ImpSetSelection( aEmptySel );
     453                 :            :     }
     454         [ +  - ]:        128 :     ResetUndo();
     455                 :        128 : }
     456                 :            : 
     457                 :        128 : void TextEngine::SetText( const XubString& rText )
     458                 :            : {
     459         [ +  - ]:        128 :     ImpRemoveText();
     460                 :            : 
     461                 :        128 :     sal_Bool bUndoCurrentlyEnabled = IsUndoEnabled();
     462                 :            :     // Der von Hand reingesteckte Text kann nicht vom Anwender rueckgaengig gemacht werden.
     463         [ +  - ]:        128 :     EnableUndo( sal_False );
     464                 :            : 
     465                 :        128 :     TextPaM aStartPaM( 0, 0 );
     466         [ +  - ]:        128 :     TextSelection aEmptySel( aStartPaM, aStartPaM );
     467                 :            : 
     468                 :        128 :     TextPaM aPaM = aStartPaM;
     469         [ +  + ]:        128 :     if ( rText.Len() )
     470         [ +  - ]:         52 :         aPaM = ImpInsertText( aEmptySel, rText );
     471                 :            : 
     472         [ +  + ]:        256 :     for ( sal_uInt16 nView = 0; nView < mpViews->size(); nView++ )
     473                 :            :     {
     474         [ +  - ]:        128 :         TextView* pView = (*mpViews)[ nView ];
     475         [ +  - ]:        128 :         pView->ImpSetSelection( aEmptySel );
     476                 :            : 
     477                 :            :         // Wenn kein Text, dann auch Kein Format&Update
     478                 :            :         // => Der Text bleibt stehen.
     479 [ +  + ][ +  - ]:        128 :         if ( !rText.Len() && GetUpdateMode() )
                 [ +  + ]
     480         [ +  - ]:         76 :             pView->Invalidate();
     481                 :            :     }
     482                 :            : 
     483         [ +  + ]:        128 :     if( !rText.Len() )  // sonst muss spaeter noch invalidiert werden, !bFormatted reicht.
     484                 :         76 :         mnCurTextHeight = 0;
     485                 :            : 
     486         [ +  - ]:        128 :     FormatAndUpdate();
     487                 :            : 
     488         [ +  - ]:        128 :     EnableUndo( bUndoCurrentlyEnabled );
     489                 :            :     DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Undo nach SetText?" );
     490                 :        128 : }
     491                 :            : 
     492                 :            : 
     493                 :        218 : void TextEngine::CursorMoved( sal_uLong nNode )
     494                 :            : {
     495                 :            :     // Leere Attribute loeschen, aber nur, wenn Absatz nicht leer!
     496                 :        218 :     TextNode* pNode = mpDoc->GetNodes().GetObject( nNode );
     497 [ -  + ][ #  # ]:        218 :     if ( pNode && pNode->GetCharAttribs().HasEmptyAttribs() && pNode->GetText().Len() )
         [ -  + ][ +  - ]
     498                 :          0 :         pNode->GetCharAttribs().DeleteEmptyAttribs();
     499                 :        218 : }
     500                 :            : 
     501                 :          0 : void TextEngine::ImpRemoveChars( const TextPaM& rPaM, sal_uInt16 nChars, SfxUndoAction* )
     502                 :            : {
     503                 :            :     DBG_ASSERT( nChars, "ImpRemoveChars - 0 Chars?!" );
     504 [ #  # ][ #  # ]:          0 :     if ( IsUndoEnabled() && !IsInUndo() )
                 [ #  # ]
     505                 :            :     {
     506                 :            :         // Attribute muessen hier vorm RemoveChars fuer UNDO gesichert werden!
     507         [ #  # ]:          0 :         TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() );
     508         [ #  # ]:          0 :         XubString aStr( pNode->GetText().Copy( rPaM.GetIndex(), nChars ) );
     509                 :            : 
     510                 :            :         // Pruefen, ob Attribute geloescht oder geaendert werden:
     511                 :          0 :         sal_uInt16 nStart = rPaM.GetIndex();
     512                 :          0 :         sal_uInt16 nEnd = nStart + nChars;
     513         [ #  # ]:          0 :         for ( sal_uInt16 nAttr = pNode->GetCharAttribs().Count(); nAttr; )
     514                 :            :         {
     515         [ #  # ]:          0 :             TextCharAttrib* pAttr = pNode->GetCharAttribs().GetAttrib( --nAttr );
     516 [ #  # ][ #  # ]:          0 :             if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetStart() < nEnd ) )
                 [ #  # ]
     517                 :            :             {
     518                 :          0 :                 break;  // for
     519                 :            :             }
     520                 :            :         }
     521 [ #  # ][ #  # ]:          0 :             InsertUndo( new TextUndoRemoveChars( this, rPaM, aStr ) );
         [ #  # ][ #  # ]
     522                 :            :     }
     523                 :            : 
     524                 :          0 :     mpDoc->RemoveChars( rPaM, nChars );
     525                 :          0 :     ImpCharsRemoved( rPaM.GetPara(), rPaM.GetIndex(), nChars );
     526                 :          0 : }
     527                 :            : 
     528                 :          0 : TextPaM TextEngine::ImpConnectParagraphs( sal_uLong nLeft, sal_uLong nRight )
     529                 :            : {
     530                 :            :     DBG_ASSERT( nLeft != nRight, "Den gleichen Absatz zusammenfuegen ?" );
     531                 :            : 
     532                 :          0 :     TextNode* pLeft = mpDoc->GetNodes().GetObject( nLeft );
     533                 :          0 :     TextNode* pRight = mpDoc->GetNodes().GetObject( nRight );
     534                 :            : 
     535 [ #  # ][ #  # ]:          0 :     if ( IsUndoEnabled() && !IsInUndo() )
                 [ #  # ]
     536         [ #  # ]:          0 :         InsertUndo( new TextUndoConnectParas( this, nLeft, pLeft->GetText().Len() ) );
     537                 :            : 
     538                 :            :     // Erstmal Portions suchen, da pRight nach ConnectParagraphs weg.
     539                 :          0 :     TEParaPortion* pLeftPortion = mpTEParaPortions->GetObject( nLeft );
     540                 :          0 :     TEParaPortion* pRightPortion = mpTEParaPortions->GetObject( nRight );
     541                 :            :     DBG_ASSERT( pLeft && pLeftPortion, "Blinde Portion in ImpConnectParagraphs(1)" );
     542                 :            :     DBG_ASSERT( pRight && pRightPortion, "Blinde Portion in ImpConnectParagraphs(2)" );
     543                 :            : 
     544                 :          0 :     TextPaM aPaM = mpDoc->ConnectParagraphs( pLeft, pRight );
     545                 :          0 :     ImpParagraphRemoved( nRight );
     546                 :            : 
     547                 :          0 :     pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex(), pLeft->GetText().Len() );
     548                 :            : 
     549                 :          0 :     mpTEParaPortions->Remove( nRight );
     550         [ #  # ]:          0 :     delete pRightPortion;
     551                 :            :     // der rechte Node wird von EditDoc::ConnectParagraphs() geloescht.
     552                 :            : 
     553                 :          0 :     return aPaM;
     554                 :            : }
     555                 :            : 
     556                 :          0 : TextPaM TextEngine::ImpDeleteText( const TextSelection& rSel )
     557                 :            : {
     558         [ #  # ]:          0 :     if ( !rSel.HasRange() )
     559                 :          0 :         return rSel.GetStart();
     560                 :            : 
     561                 :          0 :     TextSelection aSel( rSel );
     562         [ #  # ]:          0 :     aSel.Justify();
     563                 :          0 :     TextPaM aStartPaM( aSel.GetStart() );
     564                 :          0 :     TextPaM aEndPaM( aSel.GetEnd() );
     565                 :            : 
     566         [ #  # ]:          0 :     CursorMoved( aStartPaM.GetPara() ); // nur damit neu eingestellte Attribute verschwinden...
     567         [ #  # ]:          0 :     CursorMoved( aEndPaM.GetPara() );   // nur damit neu eingestellte Attribute verschwinden...
     568                 :            : 
     569                 :            :     DBG_ASSERT( mpDoc->IsValidPaM( aStartPaM ), "Index im Wald in ImpDeleteText" );
     570                 :            :     DBG_ASSERT( mpDoc->IsValidPaM( aEndPaM ), "Index im Wald in ImpDeleteText" );
     571                 :            : 
     572                 :          0 :     sal_uLong nStartNode = aStartPaM.GetPara();
     573                 :          0 :     sal_uLong nEndNode = aEndPaM.GetPara();
     574                 :            : 
     575                 :            :     // Alle Nodes dazwischen entfernen....
     576         [ #  # ]:          0 :     for ( sal_uLong z = nStartNode+1; z < nEndNode; z++ )
     577                 :            :     {
     578                 :            :         // Immer nStartNode+1, wegen Remove()!
     579         [ #  # ]:          0 :         ImpRemoveParagraph( nStartNode+1 );
     580                 :            :     }
     581                 :            : 
     582         [ #  # ]:          0 :     if ( nStartNode != nEndNode )
     583                 :            :     {
     584                 :            :         // Den Rest des StartNodes...
     585         [ #  # ]:          0 :         TextNode* pLeft = mpDoc->GetNodes().GetObject( nStartNode );
     586                 :          0 :         sal_uInt16 nChars = pLeft->GetText().Len() - aStartPaM.GetIndex();
     587         [ #  # ]:          0 :         if ( nChars )
     588                 :            :         {
     589         [ #  # ]:          0 :             ImpRemoveChars( aStartPaM, nChars );
     590         [ #  # ]:          0 :             TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode );
     591                 :            :             DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(3)" );
     592         [ #  # ]:          0 :             pPortion->MarkSelectionInvalid( aStartPaM.GetIndex(), pLeft->GetText().Len() );
     593                 :            :         }
     594                 :            : 
     595                 :            :         // Den Anfang des EndNodes....
     596                 :          0 :         nEndNode = nStartNode+1;    // Die anderen Absaetze wurden geloescht
     597                 :          0 :         nChars = aEndPaM.GetIndex();
     598         [ #  # ]:          0 :         if ( nChars )
     599                 :            :         {
     600                 :          0 :             aEndPaM.GetPara() = nEndNode;
     601                 :          0 :             aEndPaM.GetIndex() = 0;
     602         [ #  # ]:          0 :             ImpRemoveChars( aEndPaM, nChars );
     603         [ #  # ]:          0 :             TEParaPortion* pPortion = mpTEParaPortions->GetObject( nEndNode );
     604                 :            :             DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(4)" );
     605         [ #  # ]:          0 :             pPortion->MarkSelectionInvalid( 0, pPortion->GetNode()->GetText().Len() );
     606                 :            :         }
     607                 :            : 
     608                 :            :         // Zusammenfuegen....
     609         [ #  # ]:          0 :         aStartPaM = ImpConnectParagraphs( nStartNode, nEndNode );
     610                 :            :     }
     611                 :            :     else
     612                 :            :     {
     613                 :            :         sal_uInt16 nChars;
     614                 :          0 :         nChars = aEndPaM.GetIndex() - aStartPaM.GetIndex();
     615         [ #  # ]:          0 :         ImpRemoveChars( aStartPaM, nChars );
     616         [ #  # ]:          0 :         TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode );
     617                 :            :         DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteText(5)" );
     618         [ #  # ]:          0 :         pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() );
     619                 :            :     }
     620                 :            : 
     621                 :            : //  UpdateSelections();
     622         [ #  # ]:          0 :     TextModified();
     623                 :          0 :     return aStartPaM;
     624                 :            : }
     625                 :            : 
     626                 :          0 : void TextEngine::ImpRemoveParagraph( sal_uLong nPara )
     627                 :            : {
     628                 :          0 :     TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
     629                 :          0 :     TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara );
     630                 :            : 
     631                 :            :     // Der Node wird vom Undo verwaltet und ggf. zerstoert!
     632                 :          0 :     /* delete */ mpDoc->GetNodes().Remove( nPara );
     633 [ #  # ][ #  # ]:          0 :     if ( IsUndoEnabled() && !IsInUndo() )
                 [ #  # ]
     634         [ #  # ]:          0 :         InsertUndo( new TextUndoDelPara( this, pNode, nPara ) );
     635                 :            :     else
     636         [ #  # ]:          0 :         delete pNode;
     637                 :            : 
     638                 :          0 :     mpTEParaPortions->Remove( nPara );
     639         [ #  # ]:          0 :     delete pPortion;
     640                 :            : 
     641                 :          0 :     ImpParagraphRemoved( nPara );
     642                 :          0 : }
     643                 :            : 
     644                 :          0 : uno::Reference < i18n::XExtendedInputSequenceChecker > TextEngine::GetInputSequenceChecker() const
     645                 :            : {
     646                 :          0 :     uno::Reference < i18n::XExtendedInputSequenceChecker > xISC;
     647                 :            : //    if ( !xISC.is() )
     648                 :            :     {
     649         [ #  # ]:          0 :         uno::Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
     650 [ #  # ][ #  # ]:          0 :         uno::Reference< uno::XInterface > xI = xMSF->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.InputSequenceChecker" )) );
                 [ #  # ]
     651         [ #  # ]:          0 :         if ( xI.is() )
     652                 :            :         {
     653 [ #  # ][ #  # ]:          0 :             Any x = xI->queryInterface( ::getCppuType((const uno::Reference< i18n::XExtendedInputSequenceChecker >*)0) );
                 [ #  # ]
     654         [ #  # ]:          0 :             x >>= xISC;
     655                 :          0 :         }
     656                 :            :     }
     657                 :          0 :     return xISC;
     658                 :            : }
     659                 :            : 
     660                 :          0 : sal_Bool TextEngine::IsInputSequenceCheckingRequired( sal_Unicode c, const TextSelection& rCurSel ) const
     661                 :            : {
     662         [ #  # ]:          0 :     uno::Reference< i18n::XBreakIterator > xBI = ((TextEngine *) this)->GetBreakIterator();
     663         [ #  # ]:          0 :     SvtCTLOptions aCTLOptions;
     664                 :            : 
     665                 :            :     // get the index that really is first
     666                 :          0 :     sal_uInt16 nFirstPos = rCurSel.GetStart().GetIndex();
     667                 :          0 :     sal_uInt16 nMaxPos   = rCurSel.GetEnd().GetIndex();
     668         [ #  # ]:          0 :     if (nMaxPos < nFirstPos)
     669                 :          0 :         nFirstPos = nMaxPos;
     670                 :            : 
     671                 :            :     sal_Bool bIsSequenceChecking =
     672         [ #  # ]:          0 :         aCTLOptions.IsCTLFontEnabled() &&
     673         [ #  # ]:          0 :         aCTLOptions.IsCTLSequenceChecking() &&
     674                 :            :         nFirstPos != 0 && /* first char needs not to be checked */
     675 [ #  # ][ #  # ]:          0 :         xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( rtl::OUString( c ), 0 );
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     676                 :            : 
     677         [ #  # ]:          0 :     return bIsSequenceChecking;
     678                 :            : }
     679                 :            : 
     680                 :          0 : TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, sal_Unicode c, sal_Bool bOverwrite )
     681                 :            : {
     682                 :          0 :     return ImpInsertText( c, rCurSel, bOverwrite, sal_False );
     683                 :            : }
     684                 :            : 
     685                 :          0 : TextPaM TextEngine::ImpInsertText( sal_Unicode c, const TextSelection& rCurSel, sal_Bool bOverwrite, sal_Bool bIsUserInput )
     686                 :            : {
     687                 :            :     DBG_ASSERT( c != '\n', "Zeilenumbruch bei InsertText ?" );
     688                 :            :     DBG_ASSERT( c != '\r', "Zeilenumbruch bei InsertText ?" );
     689                 :            : 
     690                 :          0 :     TextPaM aPaM( rCurSel.GetStart() );
     691         [ #  # ]:          0 :     TextNode* pNode = mpDoc->GetNodes().GetObject( aPaM.GetPara() );
     692                 :            : 
     693         [ #  # ]:          0 :     if ( pNode->GetText().Len() < STRING_MAXLEN )
     694                 :            :     {
     695                 :            :         sal_Bool bDoOverwrite = ( bOverwrite &&
     696 [ #  # ][ #  # ]:          0 :                 ( aPaM.GetIndex() < pNode->GetText().Len() ) ) ? sal_True : sal_False;
     697                 :            : 
     698 [ #  # ][ #  # ]:          0 :         sal_Bool bUndoAction = ( rCurSel.HasRange() || bDoOverwrite );
     699                 :            : 
     700         [ #  # ]:          0 :         if ( bUndoAction )
     701         [ #  # ]:          0 :             UndoActionStart();
     702                 :            : 
     703         [ #  # ]:          0 :         if ( rCurSel.HasRange() )
     704                 :            :         {
     705         [ #  # ]:          0 :             aPaM = ImpDeleteText( rCurSel );
     706                 :            :         }
     707         [ #  # ]:          0 :         else if ( bDoOverwrite )
     708                 :            :         {
     709                 :            :             // Wenn Selektion, dann kein Zeichen ueberschreiben
     710         [ #  # ]:          0 :             TextSelection aTmpSel( aPaM );
     711                 :          0 :             aTmpSel.GetEnd().GetIndex()++;
     712         [ #  # ]:          0 :             ImpDeleteText( aTmpSel );
     713                 :            :         }
     714                 :            : 
     715 [ #  # ][ #  # ]:          0 :         if (bIsUserInput && IsInputSequenceCheckingRequired( c, rCurSel ))
         [ #  # ][ #  # ]
     716                 :            :         {
     717         [ #  # ]:          0 :             uno::Reference < i18n::XExtendedInputSequenceChecker > xISC = GetInputSequenceChecker();
     718         [ #  # ]:          0 :             SvtCTLOptions aCTLOptions;
     719                 :            : 
     720         [ #  # ]:          0 :             if (xISC.is())
     721                 :            :             {
     722                 :          0 :                 xub_StrLen nTmpPos = aPaM.GetIndex();
     723         [ #  # ]:          0 :                 sal_Int16 nCheckMode = aCTLOptions.IsCTLSequenceCheckingRestricted() ?
     724         [ #  # ]:          0 :                         i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
     725                 :            : 
     726                 :            :                 // the text that needs to be checked is only the one
     727                 :            :                 // before the current cursor position
     728 [ #  # ][ #  # ]:          0 :                 rtl::OUString aOldText( mpDoc->GetText( aPaM.GetPara() ).Copy(0, nTmpPos) );
         [ #  # ][ #  # ]
                 [ #  # ]
     729                 :          0 :                 rtl::OUString aNewText( aOldText );
     730 [ #  # ][ #  # ]:          0 :                 if (aCTLOptions.IsCTLSequenceCheckingTypeAndReplace())
     731                 :            :                 {
     732 [ #  # ][ #  # ]:          0 :                     xISC->correctInputSequence( aNewText, nTmpPos - 1, c, nCheckMode );
     733                 :            : 
     734                 :            :                     // find position of first character that has changed
     735                 :          0 :                     sal_Int32 nOldLen = aOldText.getLength();
     736                 :          0 :                     sal_Int32 nNewLen = aNewText.getLength();
     737                 :          0 :                     const sal_Unicode *pOldTxt = aOldText.getStr();
     738                 :          0 :                     const sal_Unicode *pNewTxt = aNewText.getStr();
     739                 :          0 :                     sal_Int32 nChgPos = 0;
     740 [ #  # ][ #  # ]:          0 :                     while ( nChgPos < nOldLen && nChgPos < nNewLen &&
         [ #  # ][ #  # ]
     741                 :          0 :                             pOldTxt[nChgPos] == pNewTxt[nChgPos] )
     742                 :          0 :                         ++nChgPos;
     743                 :            : 
     744         [ #  # ]:          0 :                     String aChgText( aNewText.copy( nChgPos ) );
     745                 :            : 
     746                 :            :                     // select text from first pos to be changed to current pos
     747         [ #  # ]:          0 :                     TextSelection aSel( TextPaM( aPaM.GetPara(), (sal_uInt16) nChgPos ), aPaM );
     748                 :            : 
     749         [ #  # ]:          0 :                     if (aChgText.Len())
     750                 :            :                         // ImpInsertText implicitly handles undo...
     751         [ #  # ]:          0 :                         return ImpInsertText( aSel, aChgText );
     752                 :            :                     else
     753         [ #  # ]:          0 :                         return aPaM;
     754                 :            :                 }
     755                 :            :                 else
     756                 :            :                 {
     757                 :            :                     // should the character be ignored (i.e. not get inserted) ?
     758 [ #  # ][ #  # ]:          0 :                     if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, c, nCheckMode ))
                 [ #  # ]
     759                 :          0 :                         return aPaM;    // nothing to be done -> no need for undo
     760 [ #  # ][ #  # ]:          0 :                 }
     761 [ #  # ][ #  # ]:          0 :             }
                 [ #  # ]
     762                 :            : 
     763                 :            :             // at this point now we will insert the character 'normally' some lines below...
     764                 :            :         }
     765                 :            : 
     766                 :            : 
     767 [ #  # ][ #  # ]:          0 :         if ( IsUndoEnabled() && !IsInUndo() )
                 [ #  # ]
     768                 :            :         {
     769 [ #  # ][ #  # ]:          0 :             TextUndoInsertChars* pNewUndo = new TextUndoInsertChars( this, aPaM, rtl::OUString(c) );
         [ #  # ][ #  # ]
     770 [ #  # ][ #  # ]:          0 :             sal_Bool bTryMerge = ( !bDoOverwrite && ( c != ' ' ) ) ? sal_True : sal_False;
     771         [ #  # ]:          0 :             InsertUndo( pNewUndo, bTryMerge );
     772                 :            :         }
     773                 :            : 
     774         [ #  # ]:          0 :         TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() );
     775         [ #  # ]:          0 :         pPortion->MarkInvalid( aPaM.GetIndex(), 1 );
     776         [ #  # ]:          0 :         if ( c == '\t' )
     777                 :          0 :             pPortion->SetNotSimpleInvalid();
     778         [ #  # ]:          0 :         aPaM = mpDoc->InsertText( aPaM, c );
     779         [ #  # ]:          0 :         ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-1, 1 );
     780                 :            : 
     781         [ #  # ]:          0 :         TextModified();
     782                 :            : 
     783         [ #  # ]:          0 :         if ( bUndoAction )
     784         [ #  # ]:          0 :             UndoActionEnd();
     785                 :            :     }
     786                 :            : 
     787                 :          0 :     return aPaM;
     788                 :            : }
     789                 :            : 
     790                 :            : 
     791                 :         52 : TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, const XubString& rStr )
     792                 :            : {
     793         [ +  - ]:         52 :     UndoActionStart();
     794                 :            : 
     795                 :         52 :     TextPaM aPaM;
     796                 :            : 
     797         [ -  + ]:         52 :     if ( rCurSel.HasRange() )
     798         [ #  # ]:          0 :         aPaM = ImpDeleteText( rCurSel );
     799                 :            :     else
     800                 :         52 :         aPaM = rCurSel.GetEnd();
     801                 :            : 
     802 [ +  - ][ +  - ]:         52 :     XubString aText(convertLineEnd(rStr, LINEEND_LF));
                 [ +  - ]
     803                 :            : 
     804                 :         52 :     sal_uInt16 nStart = 0;
     805         [ +  + ]:        104 :     while ( nStart < aText.Len() )
     806                 :            :     {
     807         [ +  - ]:         52 :         sal_uInt16 nEnd = aText.Search( LINE_SEP, nStart );
     808         [ +  - ]:         52 :         if ( nEnd == STRING_NOTFOUND )
     809                 :         52 :             nEnd = aText.Len(); // nicht dereferenzieren!
     810                 :            : 
     811                 :            :         // Start == End => Leerzeile
     812         [ +  - ]:         52 :         if ( nEnd > nStart )
     813                 :            :         {
     814                 :         52 :             sal_uLong nL = aPaM.GetIndex();
     815                 :         52 :             nL += ( nEnd-nStart );
     816         [ -  + ]:         52 :             if ( nL > STRING_MAXLEN )
     817                 :            :             {
     818                 :          0 :                 sal_uInt16 nDiff = (sal_uInt16) (nL-STRING_MAXLEN);
     819                 :          0 :                 nEnd = nEnd - nDiff;
     820                 :            :             }
     821                 :            : 
     822         [ +  - ]:         52 :             XubString aLine( aText, nStart, nEnd-nStart );
     823 [ -  + ][ #  # ]:         52 :             if ( IsUndoEnabled() && !IsInUndo() )
                 [ -  + ]
     824 [ #  # ][ #  # ]:          0 :                 InsertUndo( new TextUndoInsertChars( this, aPaM, aLine ) );
                 [ #  # ]
     825                 :            : 
     826         [ +  - ]:         52 :             TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() );
     827         [ +  - ]:         52 :             pPortion->MarkInvalid( aPaM.GetIndex(), aLine.Len() );
     828 [ +  - ][ -  + ]:         52 :             if ( aLine.Search( '\t' ) != STRING_NOTFOUND )
     829                 :          0 :                 pPortion->SetNotSimpleInvalid();
     830                 :            : 
     831         [ +  - ]:         52 :             aPaM = mpDoc->InsertText( aPaM, aLine );
     832 [ +  - ][ +  - ]:         52 :             ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-aLine.Len(), aLine.Len() );
     833                 :            : 
     834                 :            :         }
     835         [ -  + ]:         52 :         if ( nEnd < aText.Len() )
     836         [ #  # ]:          0 :             aPaM = ImpInsertParaBreak( aPaM );
     837                 :            : 
     838                 :         52 :         nStart = nEnd+1;
     839                 :            : 
     840         [ -  + ]:         52 :         if ( nStart < nEnd )    // #108611# overflow
     841                 :          0 :             break;
     842                 :            :     }
     843                 :            : 
     844         [ +  - ]:         52 :     UndoActionEnd();
     845                 :            : 
     846         [ +  - ]:         52 :     TextModified();
     847         [ +  - ]:         52 :     return aPaM;
     848                 :            : }
     849                 :            : 
     850                 :          0 : TextPaM TextEngine::ImpInsertParaBreak( const TextSelection& rCurSel, sal_Bool bKeepEndingAttribs )
     851                 :            : {
     852                 :          0 :     TextPaM aPaM;
     853         [ #  # ]:          0 :     if ( rCurSel.HasRange() )
     854         [ #  # ]:          0 :         aPaM = ImpDeleteText( rCurSel );
     855                 :            :     else
     856                 :          0 :         aPaM = rCurSel.GetEnd();
     857                 :            : 
     858         [ #  # ]:          0 :     return ImpInsertParaBreak( aPaM, bKeepEndingAttribs );
     859                 :            : }
     860                 :            : 
     861                 :          0 : TextPaM TextEngine::ImpInsertParaBreak( const TextPaM& rPaM, sal_Bool bKeepEndingAttribs )
     862                 :            : {
     863 [ #  # ][ #  # ]:          0 :     if ( IsUndoEnabled() && !IsInUndo() )
                 [ #  # ]
     864         [ #  # ]:          0 :         InsertUndo( new TextUndoSplitPara( this, rPaM.GetPara(), rPaM.GetIndex() ) );
     865                 :            : 
     866                 :          0 :     TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() );
     867                 :          0 :     sal_Bool bFirstParaContentChanged = rPaM.GetIndex() < pNode->GetText().Len();
     868                 :            : 
     869                 :          0 :     TextPaM aPaM( mpDoc->InsertParaBreak( rPaM, bKeepEndingAttribs ) );
     870                 :            : 
     871                 :          0 :     TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() );
     872                 :            :     DBG_ASSERT( pPortion, "Blinde Portion in ImpInsertParaBreak" );
     873                 :          0 :     pPortion->MarkInvalid( rPaM.GetIndex(), 0 );
     874                 :            : 
     875                 :          0 :     TextNode* pNewNode = mpDoc->GetNodes().GetObject( aPaM.GetPara() );
     876         [ #  # ]:          0 :     TEParaPortion* pNewPortion = new TEParaPortion( pNewNode );
     877                 :          0 :     mpTEParaPortions->Insert( pNewPortion, aPaM.GetPara() );
     878                 :          0 :     ImpParagraphInserted( aPaM.GetPara() );
     879                 :            : 
     880                 :          0 :     CursorMoved( rPaM.GetPara() );  // falls leeres Attribut entstanden.
     881                 :          0 :     TextModified();
     882                 :            : 
     883         [ #  # ]:          0 :     if ( bFirstParaContentChanged )
     884         [ #  # ]:          0 :         Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, rPaM.GetPara() ) );
     885                 :            : 
     886                 :          0 :     return aPaM;
     887                 :            : }
     888                 :            : 
     889                 :        308 : Rectangle TextEngine::PaMtoEditCursor( const TextPaM& rPaM, sal_Bool bSpecial )
     890                 :            : {
     891                 :            :     DBG_ASSERT( GetUpdateMode(), "Darf bei Update=sal_False nicht erreicht werden: PaMtoEditCursor" );
     892                 :            : 
     893                 :        308 :     Rectangle aEditCursor;
     894                 :        308 :     long nY = 0;
     895                 :            : 
     896         [ +  - ]:        308 :     if ( !mbHasMultiLineParas )
     897                 :            :     {
     898                 :        308 :         nY = rPaM.GetPara() * mnCharHeight;
     899                 :            :     }
     900                 :            :     else
     901                 :            :     {
     902         [ #  # ]:          0 :         for ( sal_uLong nPortion = 0; nPortion < rPaM.GetPara(); nPortion++ )
     903                 :            :         {
     904                 :          0 :             TEParaPortion* pPortion = mpTEParaPortions->GetObject(nPortion);
     905                 :          0 :             nY += pPortion->GetLines().size() * mnCharHeight;
     906                 :            :         }
     907                 :            :     }
     908                 :            : 
     909                 :        308 :     aEditCursor = GetEditCursor( rPaM, bSpecial );
     910                 :        308 :     aEditCursor.Top() += nY;
     911                 :        308 :     aEditCursor.Bottom() += nY;
     912                 :        308 :     return aEditCursor;
     913                 :            : }
     914                 :            : 
     915                 :        308 : Rectangle TextEngine::GetEditCursor( const TextPaM& rPaM, sal_Bool bSpecial, sal_Bool bPreferPortionStart )
     916                 :            : {
     917 [ -  + ][ #  # ]:        308 :     if ( !IsFormatted() && !IsFormatting() )
                 [ -  + ]
     918                 :          0 :         FormatAndUpdate();
     919                 :            : 
     920                 :        308 :     TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() );
     921                 :            :     //TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() );
     922                 :            : 
     923                 :            :     /*
     924                 :            :      bSpecial:  Wenn hinter dem letzten Zeichen einer umgebrochenen Zeile,
     925                 :            :      am Ende der Zeile bleiben, nicht am Anfang der naechsten.
     926                 :            :      Zweck:     - END => wirklich hinter das letzte Zeichen
     927                 :            :                 - Selektion....
     928                 :            :       bSpecial: If behind the last character of a made up line, stay at the
     929                 :            :                   end of the line, not at the start of the next line.
     930                 :            :       Purpose:  - really END = > behind the last character
     931                 :            :                   - to selection...
     932                 :            : 
     933                 :            :     */
     934                 :            : 
     935                 :        308 :     long nY = 0;
     936                 :        308 :     sal_uInt16 nCurIndex = 0;
     937                 :        308 :     TextLine* pLine = 0;
     938         [ +  - ]:        308 :     for ( sal_uInt16 nLine = 0; nLine < pPortion->GetLines().size(); nLine++ )
     939                 :            :     {
     940                 :        308 :         TextLine* pTmpLine = pPortion->GetLines()[ nLine ];
     941 [ #  # ][ +  - ]:        308 :         if ( ( pTmpLine->GetStart() == rPaM.GetIndex() ) || ( pTmpLine->IsIn( rPaM.GetIndex(), bSpecial ) ) )
                 [ -  + ]
     942                 :            :         {
     943                 :        308 :             pLine = pTmpLine;
     944                 :        308 :             break;
     945                 :            :         }
     946                 :            : 
     947                 :          0 :         nCurIndex = nCurIndex + pTmpLine->GetLen();
     948                 :          0 :         nY += mnCharHeight;
     949                 :            :     }
     950         [ -  + ]:        308 :     if ( !pLine )
     951                 :            :     {
     952                 :            :         // Cursor am Ende des Absatzes.
     953                 :            :         DBG_ASSERT( rPaM.GetIndex() == nCurIndex, "Index voll daneben in GetEditCursor!" );
     954                 :            : 
     955                 :          0 :         pLine = pPortion->GetLines().back();
     956                 :          0 :         nY -= mnCharHeight;
     957                 :          0 :         nCurIndex = nCurIndex - pLine->GetLen();
     958                 :            :     }
     959                 :            : 
     960                 :        308 :     Rectangle aEditCursor;
     961                 :            : 
     962                 :        308 :     aEditCursor.Top() = nY;
     963                 :        308 :     nY += mnCharHeight;
     964                 :        308 :     aEditCursor.Bottom() = nY-1;
     965                 :            : 
     966                 :            :     // innerhalb der Zeile suchen....
     967                 :        308 :     long nX = ImpGetXPos( rPaM.GetPara(), pLine, rPaM.GetIndex(), bPreferPortionStart );
     968                 :        308 :     aEditCursor.Left() = aEditCursor.Right() = nX;
     969                 :        308 :     return aEditCursor;
     970                 :            : }
     971                 :            : 
     972                 :        406 : long TextEngine::ImpGetXPos( sal_uLong nPara, TextLine* pLine, sal_uInt16 nIndex, sal_Bool bPreferPortionStart )
     973                 :            : {
     974                 :            :     DBG_ASSERT( ( nIndex >= pLine->GetStart() ) && ( nIndex <= pLine->GetEnd() ) , "ImpGetXPos muss richtig gerufen werden!" );
     975                 :            : 
     976                 :        406 :     sal_Bool bDoPreferPortionStart = bPreferPortionStart;
     977                 :            :     // Assure that the portion belongs to this line:
     978         [ +  + ]:        406 :     if ( nIndex == pLine->GetStart() )
     979                 :        357 :         bDoPreferPortionStart = sal_True;
     980         [ +  - ]:         49 :     else if ( nIndex == pLine->GetEnd() )
     981                 :         49 :         bDoPreferPortionStart = sal_False;
     982                 :            : 
     983         [ +  - ]:        406 :     TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara );
     984                 :            : 
     985                 :        406 :     sal_uInt16 nTextPortionStart = 0;
     986         [ +  - ]:        406 :     size_t nTextPortion = pParaPortion->GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart );
     987                 :            : 
     988                 :            :     DBG_ASSERT( ( nTextPortion >= pLine->GetStartPortion() ) && ( nTextPortion <= pLine->GetEndPortion() ), "GetXPos: Portion not in current line! " );
     989                 :            : 
     990                 :        406 :     TETextPortion* pPortion = pParaPortion->GetTextPortions()[ nTextPortion ];
     991                 :            : 
     992         [ +  - ]:        406 :     long nX = ImpGetPortionXOffset( nPara, pLine, nTextPortion );
     993                 :            : 
     994                 :        406 :     long nPortionTextWidth = pPortion->GetWidth();
     995                 :            : 
     996         [ +  + ]:        406 :     if ( nTextPortionStart != nIndex )
     997                 :            :     {
     998                 :            :         // Search within portion...
     999         [ +  - ]:         49 :         if ( nIndex == ( nTextPortionStart + pPortion->GetLen() ) )
    1000                 :            :         {
    1001                 :            :             // End of Portion
    1002   [ +  -  +  -  :        147 :             if ( ( pPortion->GetKind() == PORTIONKIND_TAB ) ||
          -  +  #  #  #  
              # ][ +  - ]
    1003                 :         98 :                  ( !IsRightToLeft() && !pPortion->IsRightToLeft() ) ||
    1004                 :          0 :                  ( IsRightToLeft() && pPortion->IsRightToLeft() ) )
    1005                 :            :             {
    1006                 :         49 :                 nX += nPortionTextWidth;
    1007 [ -  + ][ #  # ]:         49 :                 if ( ( pPortion->GetKind() == PORTIONKIND_TAB ) && ( (nTextPortion+1) < pParaPortion->GetTextPortions().size() ) )
                 [ -  + ]
    1008                 :            :                 {
    1009                 :          0 :                     TETextPortion* pNextPortion = pParaPortion->GetTextPortions()[ nTextPortion+1 ];
    1010 [ #  # ][ #  #  :          0 :                     if ( ( pNextPortion->GetKind() != PORTIONKIND_TAB ) && (
          #  #  #  #  #  
                #  #  # ]
    1011                 :          0 :                               ( !IsRightToLeft() && pNextPortion->IsRightToLeft() ) ||
    1012                 :          0 :                               ( IsRightToLeft() && !pNextPortion->IsRightToLeft() ) ) )
    1013                 :            :                     {
    1014                 :            : //                        nX += pNextPortion->GetWidth();
    1015                 :            :                         // End of the tab portion, use start of next for cursor pos
    1016                 :            :                         DBG_ASSERT( !bPreferPortionStart, "ImpGetXPos - How can we this tab portion here???" );
    1017         [ #  # ]:          0 :                         nX = ImpGetXPos( nPara, pLine, nIndex, sal_True );
    1018                 :            :                     }
    1019                 :            : 
    1020                 :            :                 }
    1021                 :            :             }
    1022                 :            :         }
    1023         [ #  # ]:          0 :         else if ( pPortion->GetKind() == PORTIONKIND_TEXT )
    1024                 :            :         {
    1025                 :            :             DBG_ASSERT( nIndex != pLine->GetStart(), "Strange behavior in new ImpGetXPos()" );
    1026                 :            : 
    1027         [ #  # ]:          0 :             long nPosInPortion = (long)CalcTextWidth( nPara, nTextPortionStart, nIndex-nTextPortionStart );
    1028                 :            : 
    1029 [ #  # ][ #  #  :          0 :             if ( ( !IsRightToLeft() && !pPortion->IsRightToLeft() ) ||
             #  #  #  # ]
                 [ #  # ]
    1030                 :          0 :                  ( IsRightToLeft() && pPortion->IsRightToLeft() ) )
    1031                 :            :             {
    1032                 :          0 :                 nX += nPosInPortion;
    1033                 :            :             }
    1034                 :            :             else
    1035                 :            :             {
    1036                 :          0 :                 nX += nPortionTextWidth - nPosInPortion;
    1037                 :            :             }
    1038                 :            :         }
    1039                 :            :     }
    1040                 :            :     else // if ( nIndex == pLine->GetStart() )
    1041                 :            :     {
    1042   [ +  -  +  -  :       1428 :         if ( ( pPortion->GetKind() != PORTIONKIND_TAB ) &&
          +  -  -  +  #  
              # ][ -  + ]
    1043                 :        714 :                 ( ( !IsRightToLeft() && pPortion->IsRightToLeft() ) ||
    1044                 :        357 :                 ( IsRightToLeft() && !pPortion->IsRightToLeft() ) ) )
    1045                 :            :         {
    1046                 :          0 :             nX += nPortionTextWidth;
    1047                 :            :         }
    1048                 :            :     }
    1049                 :            : 
    1050                 :        406 :     return nX;
    1051                 :            : }
    1052                 :            : 
    1053                 :          0 : const TextAttrib* TextEngine::FindAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const
    1054                 :            : {
    1055                 :          0 :     const TextAttrib* pAttr = NULL;
    1056                 :          0 :     const TextCharAttrib* pCharAttr = FindCharAttrib( rPaM, nWhich );
    1057         [ #  # ]:          0 :     if ( pCharAttr )
    1058                 :          0 :         pAttr = &pCharAttr->GetAttr();
    1059                 :          0 :     return pAttr;
    1060                 :            : }
    1061                 :            : 
    1062                 :          0 : const TextCharAttrib* TextEngine::FindCharAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const
    1063                 :            : {
    1064                 :          0 :     const TextCharAttrib* pAttr = NULL;
    1065                 :          0 :     TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() );
    1066 [ #  # ][ #  # ]:          0 :     if ( pNode && ( rPaM.GetIndex() < pNode->GetText().Len() ) )
                 [ #  # ]
    1067                 :          0 :         pAttr = pNode->GetCharAttribs().FindAttrib( nWhich, rPaM.GetIndex() );
    1068                 :          0 :     return pAttr;
    1069                 :            : }
    1070                 :            : 
    1071                 :          0 : sal_Bool TextEngine::HasAttrib( sal_uInt16 nWhich ) const
    1072                 :            : {
    1073                 :          0 :     sal_Bool bAttr = sal_False;
    1074 [ #  # ][ #  # ]:          0 :     for ( sal_uLong n = mpDoc->GetNodes().Count(); --n && !bAttr; )
                 [ #  # ]
    1075                 :            :     {
    1076                 :          0 :         TextNode* pNode = mpDoc->GetNodes().GetObject( n );
    1077                 :          0 :         bAttr = pNode->GetCharAttribs().HasAttrib( nWhich );
    1078                 :            :     }
    1079                 :          0 :     return bAttr;
    1080                 :            : }
    1081                 :            : 
    1082                 :          0 : TextPaM TextEngine::GetPaM( const Point& rDocPos, sal_Bool bSmart )
    1083                 :            : {
    1084                 :            :     DBG_ASSERT( GetUpdateMode(), "Darf bei Update=sal_False nicht erreicht werden: GetPaM" );
    1085                 :            : 
    1086                 :          0 :     long nY = 0;
    1087         [ #  # ]:          0 :     for ( sal_uLong nPortion = 0; nPortion < mpTEParaPortions->Count(); nPortion++ )
    1088                 :            :     {
    1089                 :          0 :         TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion );
    1090                 :          0 :         long nTmpHeight = pPortion->GetLines().size() * mnCharHeight;
    1091                 :          0 :         nY += nTmpHeight;
    1092         [ #  # ]:          0 :         if ( nY > rDocPos.Y() )
    1093                 :            :         {
    1094                 :          0 :             nY -= nTmpHeight;
    1095                 :          0 :             Point aPosInPara( rDocPos );
    1096                 :          0 :             aPosInPara.Y() -= nY;
    1097                 :            : 
    1098                 :          0 :             TextPaM aPaM( nPortion, 0 );
    1099         [ #  # ]:          0 :             aPaM.GetIndex() = ImpFindIndex( nPortion, aPosInPara, bSmart );
    1100                 :          0 :             return aPaM;
    1101                 :            :         }
    1102                 :            :     }
    1103                 :            : 
    1104                 :            :     // Nicht gefunden - Dann den letzten sichtbare...
    1105                 :          0 :     sal_uLong nLastNode = mpDoc->GetNodes().Count() - 1;
    1106                 :          0 :     TextNode* pLast = mpDoc->GetNodes().GetObject( nLastNode );
    1107                 :          0 :     return TextPaM( nLastNode, pLast->GetText().Len() );
    1108                 :            : }
    1109                 :            : 
    1110                 :          0 : sal_uInt16 TextEngine::ImpFindIndex( sal_uLong nPortion, const Point& rPosInPara, sal_Bool bSmart )
    1111                 :            : {
    1112                 :            :     DBG_ASSERT( IsFormatted(), "GetPaM: Nicht formatiert" );
    1113                 :          0 :     TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion );
    1114                 :            : 
    1115                 :          0 :     sal_uInt16 nCurIndex = 0;
    1116                 :            : 
    1117                 :          0 :     long nY = 0;
    1118                 :          0 :     TextLine* pLine = 0;
    1119                 :            :     sal_uInt16 nLine;
    1120         [ #  # ]:          0 :     for ( nLine = 0; nLine < pPortion->GetLines().size(); nLine++ )
    1121                 :            :     {
    1122                 :          0 :         TextLine* pTmpLine = pPortion->GetLines()[ nLine ];
    1123                 :          0 :         nY += mnCharHeight;
    1124         [ #  # ]:          0 :         if ( nY > rPosInPara.Y() )  // das war 'se
    1125                 :            :         {
    1126                 :          0 :             pLine = pTmpLine;
    1127                 :          0 :             break;                  // richtige Y-Position intressiert nicht
    1128                 :            :         }
    1129                 :            :     }
    1130                 :            :     DBG_ASSERT( pLine, "ImpFindIndex: pLine ?" );
    1131                 :            : 
    1132                 :          0 :     nCurIndex = GetCharPos( nPortion, nLine, rPosInPara.X(), bSmart );
    1133                 :            : 
    1134   [ #  #  #  # ]:          0 :     if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) &&
         [ #  # ][ #  # ]
    1135                 :          0 :          ( pLine != pPortion->GetLines().back() ) )
    1136                 :            :     {
    1137         [ #  # ]:          0 :         uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator();
    1138                 :          0 :         sal_Int32 nCount = 1;
    1139 [ #  # ][ #  # ]:          0 :         nCurIndex = (sal_uInt16)xBI->previousCharacters( pPortion->GetNode()->GetText(), nCurIndex, GetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount );
         [ #  # ][ #  # ]
    1140                 :            :     }
    1141                 :          0 :     return nCurIndex;
    1142                 :            : }
    1143                 :            : 
    1144                 :          0 : sal_uInt16 TextEngine::GetCharPos( sal_uLong nPortion, sal_uInt16 nLine, long nXPos, sal_Bool )
    1145                 :            : {
    1146                 :            : 
    1147                 :          0 :     TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion );
    1148                 :          0 :     TextLine* pLine = pPortion->GetLines()[ nLine ];
    1149                 :            : 
    1150                 :          0 :     sal_uInt16 nCurIndex = pLine->GetStart();
    1151                 :            : 
    1152                 :          0 :     long nTmpX = pLine->GetStartX();
    1153         [ #  # ]:          0 :     if ( nXPos <= nTmpX )
    1154                 :          0 :         return nCurIndex;
    1155                 :            : 
    1156         [ #  # ]:          0 :     for ( sal_uInt16 i = pLine->GetStartPortion(); i <= pLine->GetEndPortion(); i++ )
    1157                 :            :     {
    1158                 :          0 :         TETextPortion* pTextPortion = pPortion->GetTextPortions()[ i ];
    1159                 :          0 :         nTmpX += pTextPortion->GetWidth();
    1160                 :            : 
    1161         [ #  # ]:          0 :         if ( nTmpX > nXPos )
    1162                 :            :         {
    1163         [ #  # ]:          0 :             if( pTextPortion->GetLen() > 1 )
    1164                 :            :             {
    1165                 :          0 :                 nTmpX -= pTextPortion->GetWidth();  // vor die Portion stellen
    1166                 :            :                 // Optimieren: Kein GetTextBreak, wenn feste Fontbreite...
    1167         [ #  # ]:          0 :                 Font aFont;
    1168         [ #  # ]:          0 :                 SeekCursor( nPortion, nCurIndex+1, aFont, NULL );
    1169         [ #  # ]:          0 :                 mpRefDev->SetFont( aFont);
    1170                 :          0 :                 long nPosInPortion = nXPos-nTmpX;
    1171         [ #  # ]:          0 :                 if ( IsRightToLeft() != pTextPortion->IsRightToLeft() )
    1172                 :          0 :                     nPosInPortion = pTextPortion->GetWidth() - nPosInPortion;
    1173 [ #  # ][ #  # ]:          0 :                 nCurIndex = mpRefDev->GetTextBreak( pPortion->GetNode()->GetText(), nPosInPortion, nCurIndex );
    1174                 :            :                 // MT: GetTextBreak should assure that we are not withing a CTL cell...
    1175                 :            :             }
    1176                 :          0 :             return nCurIndex;
    1177                 :            :         }
    1178                 :          0 :         nCurIndex = nCurIndex + pTextPortion->GetLen();
    1179                 :            :     }
    1180                 :          0 :     return nCurIndex;
    1181                 :            : }
    1182                 :            : 
    1183                 :            : 
    1184                 :        260 : sal_uLong TextEngine::GetTextHeight() const
    1185                 :            : {
    1186                 :            :     DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=sal_False nicht verwendet werden: GetTextHeight" );
    1187                 :            : 
    1188 [ -  + ][ #  # ]:        260 :     if ( !IsFormatted() && !IsFormatting() )
                 [ -  + ]
    1189                 :          0 :         ((TextEngine*)this)->FormatAndUpdate();
    1190                 :            : 
    1191                 :        260 :     return mnCurTextHeight;
    1192                 :            : }
    1193                 :            : 
    1194                 :          0 : sal_uLong TextEngine::GetTextHeight( sal_uLong nParagraph ) const
    1195                 :            : {
    1196                 :            :     DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=sal_False nicht verwendet werden: GetTextHeight" );
    1197                 :            : 
    1198 [ #  # ][ #  # ]:          0 :       if ( !IsFormatted() && !IsFormatting() )
                 [ #  # ]
    1199                 :          0 :         ((TextEngine*)this)->FormatAndUpdate();
    1200                 :            : 
    1201                 :          0 :     return CalcParaHeight( nParagraph );
    1202                 :            : }
    1203                 :            : 
    1204                 :        612 : sal_uLong TextEngine::CalcTextWidth( sal_uLong nPara )
    1205                 :            : {
    1206                 :        612 :     sal_uLong nParaWidth = 0;
    1207                 :        612 :     TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara );
    1208         [ +  + ]:       1118 :     for ( sal_uInt16 nLine = pPortion->GetLines().size(); nLine; )
    1209                 :            :     {
    1210                 :        506 :         sal_uLong nLineWidth = 0;
    1211                 :        506 :         TextLine* pLine = pPortion->GetLines()[ --nLine ];
    1212         [ +  + ]:       1012 :         for ( sal_uInt16 nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ )
    1213                 :            :         {
    1214                 :        506 :             TETextPortion* pTextPortion = pPortion->GetTextPortions()[ nTP ];
    1215                 :        506 :             nLineWidth += pTextPortion->GetWidth();
    1216                 :            :         }
    1217         [ +  + ]:        506 :         if ( nLineWidth > nParaWidth )
    1218                 :        112 :             nParaWidth = nLineWidth;
    1219                 :            :     }
    1220                 :        612 :     return nParaWidth;
    1221                 :            : }
    1222                 :            : 
    1223                 :        262 : sal_uLong TextEngine::CalcTextWidth()
    1224                 :            : {
    1225 [ -  + ][ #  # ]:        262 :     if ( !IsFormatted() && !IsFormatting() )
                 [ -  + ]
    1226                 :          0 :         FormatAndUpdate();
    1227                 :            : 
    1228         [ +  + ]:        262 :     if ( mnCurTextWidth == 0xFFFFFFFF )
    1229                 :            :     {
    1230                 :         28 :         mnCurTextWidth = 0;
    1231         [ +  + ]:         56 :         for ( sal_uLong nPara = mpTEParaPortions->Count(); nPara; )
    1232                 :            :         {
    1233                 :         28 :             sal_uLong nParaWidth = CalcTextWidth( --nPara );
    1234         [ +  + ]:         28 :             if ( nParaWidth > mnCurTextWidth )
    1235                 :          4 :                 mnCurTextWidth = nParaWidth;
    1236                 :            :         }
    1237                 :            :     }
    1238                 :        262 :     return mnCurTextWidth+1;// Ein breiter, da in CreateLines bei >= umgebrochen wird.
    1239                 :            : }
    1240                 :            : 
    1241                 :        596 : sal_uLong TextEngine::CalcTextHeight()
    1242                 :            : {
    1243                 :            :     DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=sal_False nicht verwendet werden: CalcTextHeight" );
    1244                 :            : 
    1245                 :        596 :     sal_uLong nY = 0;
    1246         [ +  + ]:       1192 :     for ( sal_uLong nPortion = mpTEParaPortions->Count(); nPortion; )
    1247                 :        596 :         nY += CalcParaHeight( --nPortion );
    1248                 :        596 :     return nY;
    1249                 :            : }
    1250                 :            : 
    1251                 :         92 : sal_uLong TextEngine::CalcTextWidth( sal_uLong nPara, sal_uInt16 nPortionStart, sal_uInt16 nLen, const Font* pFont )
    1252                 :            : {
    1253                 :            :     // Innerhalb des Textes darf es keinen Portionwechsel (Attribut/Tab) geben!
    1254                 :            :     DBG_ASSERT( mpDoc->GetNodes().GetObject( nPara )->GetText().Search( '\t', nPortionStart ) >= (nPortionStart+nLen), "CalcTextWidth: Tab!" );
    1255                 :            : 
    1256                 :            :     sal_uLong nWidth;
    1257         [ -  + ]:         92 :     if ( mnFixCharWidth100 )
    1258                 :            :     {
    1259                 :          0 :         nWidth = (sal_uLong)nLen*mnFixCharWidth100/100;
    1260                 :            :     }
    1261                 :            :     else
    1262                 :            :     {
    1263         [ -  + ]:         92 :         if ( pFont )
    1264                 :            :         {
    1265         [ #  # ]:          0 :             if ( !mpRefDev->GetFont().IsSameInstance( *pFont ) )
    1266                 :          0 :                 mpRefDev->SetFont( *pFont );
    1267                 :            :         }
    1268                 :            :         else
    1269                 :            :         {
    1270         [ +  - ]:         92 :             Font aFont;
    1271         [ +  - ]:         92 :             SeekCursor( nPara, nPortionStart+1, aFont, NULL );
    1272 [ +  - ][ +  - ]:         92 :             mpRefDev->SetFont( aFont );
    1273                 :            :         }
    1274                 :         92 :         TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
    1275                 :         92 :         nWidth = (sal_uLong)mpRefDev->GetTextWidth( pNode->GetText(), nPortionStart, nLen );
    1276                 :            : 
    1277                 :            :     }
    1278                 :         92 :     return nWidth;
    1279                 :            : }
    1280                 :            : 
    1281                 :            : 
    1282                 :          0 : sal_uInt16 TextEngine::GetLineCount( sal_uLong nParagraph ) const
    1283                 :            : {
    1284                 :            :     DBG_ASSERT( nParagraph < mpTEParaPortions->Count(), "GetLineCount: Out of range" );
    1285                 :            : 
    1286                 :          0 :     TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph );
    1287         [ #  # ]:          0 :     if ( pPPortion )
    1288                 :          0 :         return pPPortion->GetLines().size();
    1289                 :            : 
    1290                 :          0 :     return 0xFFFF;
    1291                 :            : }
    1292                 :            : 
    1293                 :          0 : sal_uInt16 TextEngine::GetLineLen( sal_uLong nParagraph, sal_uInt16 nLine ) const
    1294                 :            : {
    1295                 :            :     DBG_ASSERT( nParagraph < mpTEParaPortions->Count(), "GetLineCount: Out of range" );
    1296                 :            : 
    1297                 :          0 :     TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph );
    1298 [ #  # ][ #  # ]:          0 :     if ( pPPortion && ( nLine < pPPortion->GetLines().size() ) )
                 [ #  # ]
    1299                 :            :     {
    1300                 :          0 :         TextLine* pLine = pPPortion->GetLines()[ nLine ];
    1301                 :          0 :         return pLine->GetLen();
    1302                 :            :     }
    1303                 :            : 
    1304                 :          0 :     return 0xFFFF;
    1305                 :            : }
    1306                 :            : 
    1307                 :       1281 : sal_uLong TextEngine::CalcParaHeight( sal_uLong nParagraph ) const
    1308                 :            : {
    1309                 :       1281 :     sal_uLong nHeight = 0;
    1310                 :            : 
    1311                 :       1281 :     TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph );
    1312                 :            :     DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetParaHeight" );
    1313         [ +  - ]:       1281 :     if ( pPPortion )
    1314                 :       1281 :         nHeight = pPPortion->GetLines().size() * mnCharHeight;
    1315                 :            : 
    1316                 :       1281 :     return nHeight;
    1317                 :            : }
    1318                 :            : 
    1319                 :          0 : void TextEngine::UpdateSelections()
    1320                 :            : {
    1321                 :          0 : }
    1322                 :            : 
    1323                 :        596 : Range TextEngine::GetInvalidYOffsets( sal_uLong nPortion )
    1324                 :            : {
    1325                 :        596 :     TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion );
    1326                 :        596 :     sal_uInt16 nLines = pTEParaPortion->GetLines().size();
    1327                 :        596 :     sal_uInt16 nLastInvalid, nFirstInvalid = 0;
    1328                 :            :     sal_uInt16 nLine;
    1329         [ +  - ]:        596 :     for ( nLine = 0; nLine < nLines; nLine++ )
    1330                 :            :     {
    1331                 :        596 :         TextLine* pL = pTEParaPortion->GetLines()[ nLine ];
    1332         [ +  - ]:        596 :         if ( pL->IsInvalid() )
    1333                 :            :         {
    1334                 :        596 :             nFirstInvalid = nLine;
    1335                 :        596 :             break;
    1336                 :            :         }
    1337                 :            :     }
    1338                 :            : 
    1339         [ +  + ]:       1192 :     for ( nLastInvalid = nFirstInvalid; nLastInvalid < nLines; nLastInvalid++ )
    1340                 :            :     {
    1341                 :        596 :         TextLine* pL = pTEParaPortion->GetLines()[ nLine ];
    1342         [ -  + ]:        596 :         if ( pL->IsValid() )
    1343                 :          0 :             break;
    1344                 :            :     }
    1345                 :            : 
    1346         [ +  - ]:        596 :     if ( nLastInvalid >= nLines )
    1347                 :        596 :         nLastInvalid = nLines-1;
    1348                 :            : 
    1349                 :        596 :     return Range( nFirstInvalid*mnCharHeight, ((nLastInvalid+1)*mnCharHeight)-1 );
    1350                 :            : }
    1351                 :            : 
    1352                 :          0 : sal_uLong TextEngine::GetParagraphCount() const
    1353                 :            : {
    1354                 :          0 :     return mpDoc->GetNodes().Count();
    1355                 :            : }
    1356                 :            : 
    1357                 :        346 : void TextEngine::EnableUndo( sal_Bool bEnable )
    1358                 :            : {
    1359                 :            :     // Beim Umschalten des Modus Liste loeschen:
    1360         [ +  - ]:        346 :     if ( bEnable != IsUndoEnabled() )
    1361                 :        346 :         ResetUndo();
    1362                 :            : 
    1363                 :        346 :     mbUndoEnabled = bEnable;
    1364                 :        346 : }
    1365                 :            : 
    1366                 :          0 : ::svl::IUndoManager& TextEngine::GetUndoManager()
    1367                 :            : {
    1368         [ #  # ]:          0 :     if ( !mpUndoManager )
    1369         [ #  # ]:          0 :         mpUndoManager = new TextUndoManager( this );
    1370                 :          0 :     return *mpUndoManager;
    1371                 :            : }
    1372                 :            : 
    1373                 :         52 : void TextEngine::UndoActionStart( sal_uInt16 nId )
    1374                 :            : {
    1375 [ -  + ][ #  # ]:         52 :     if ( IsUndoEnabled() && !IsInUndo() )
                 [ -  + ]
    1376                 :            :     {
    1377         [ #  # ]:          0 :         String aComment;
    1378                 :            :         // ...
    1379 [ #  # ][ #  # ]:          0 :         GetUndoManager().EnterListAction( aComment, XubString(), nId );
         [ #  # ][ #  # ]
                 [ #  # ]
    1380                 :            :     }
    1381                 :         52 : }
    1382                 :            : 
    1383                 :         52 : void TextEngine::UndoActionEnd()
    1384                 :            : {
    1385 [ -  + ][ #  # ]:         52 :     if ( IsUndoEnabled() && !IsInUndo() )
                 [ -  + ]
    1386                 :          0 :         GetUndoManager().LeaveListAction();
    1387                 :         52 : }
    1388                 :            : 
    1389                 :          0 : void TextEngine::InsertUndo( TextUndo* pUndo, sal_Bool bTryMerge )
    1390                 :            : {
    1391                 :            :     DBG_ASSERT( !IsInUndo(), "InsertUndo im Undomodus!" );
    1392                 :          0 :     GetUndoManager().AddUndoAction( pUndo, bTryMerge );
    1393                 :          0 : }
    1394                 :            : 
    1395                 :        474 : void TextEngine::ResetUndo()
    1396                 :            : {
    1397         [ -  + ]:        474 :     if ( mpUndoManager )
    1398                 :          0 :         mpUndoManager->Clear();
    1399                 :        474 : }
    1400                 :            : 
    1401                 :          0 : void TextEngine::InsertContent( TextNode* pNode, sal_uLong nPara )
    1402                 :            : {
    1403                 :            :     DBG_ASSERT( pNode, "NULL-Pointer in InsertContent! " );
    1404                 :            :     DBG_ASSERT( IsInUndo(), "InsertContent nur fuer Undo()!" );
    1405         [ #  # ]:          0 :     TEParaPortion* pNew = new TEParaPortion( pNode );
    1406                 :          0 :     mpTEParaPortions->Insert( pNew, nPara );
    1407                 :          0 :     mpDoc->GetNodes().Insert( pNode, nPara );
    1408                 :          0 :     ImpParagraphInserted( nPara );
    1409                 :          0 : }
    1410                 :            : 
    1411                 :          0 : TextPaM TextEngine::SplitContent( sal_uLong nNode, sal_uInt16 nSepPos )
    1412                 :            : {
    1413                 :            :     #ifdef DBG_UTIL
    1414                 :            :     TextNode* pNode = mpDoc->GetNodes().GetObject( nNode );
    1415                 :            :     DBG_ASSERT( pNode, "Ungueltiger Node in SplitContent" );
    1416                 :            :     DBG_ASSERT( IsInUndo(), "SplitContent nur fuer Undo()!" );
    1417                 :            :     DBG_ASSERT( nSepPos <= pNode->GetText().Len(), "Index im Wald: SplitContent" );
    1418                 :            :     #endif
    1419                 :          0 :     TextPaM aPaM( nNode, nSepPos );
    1420         [ #  # ]:          0 :     return ImpInsertParaBreak( aPaM );
    1421                 :            : }
    1422                 :            : 
    1423                 :          0 : TextPaM TextEngine::ConnectContents( sal_uLong nLeftNode )
    1424                 :            : {
    1425                 :            :     DBG_ASSERT( IsInUndo(), "ConnectContent nur fuer Undo()!" );
    1426                 :          0 :     return ImpConnectParagraphs( nLeftNode, nLeftNode+1 );
    1427                 :            : }
    1428                 :            : 
    1429                 :        181 : void TextEngine::SeekCursor( sal_uLong nPara, sal_uInt16 nPos, Font& rFont, OutputDevice* pOutDev )
    1430                 :            : {
    1431                 :        181 :     rFont = maFont;
    1432         [ +  + ]:        181 :     if ( pOutDev )
    1433                 :         89 :         pOutDev->SetTextColor( maTextColor );
    1434                 :            : 
    1435                 :        181 :     TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
    1436                 :        181 :     sal_uInt16 nAttribs = pNode->GetCharAttribs().Count();
    1437         [ -  + ]:        181 :     for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
    1438                 :            :     {
    1439                 :          0 :         TextCharAttrib* pAttrib = pNode->GetCharAttribs().GetAttrib( nAttr );
    1440         [ #  # ]:          0 :         if ( pAttrib->GetStart() > nPos )
    1441                 :          0 :             break;
    1442                 :            : 
    1443                 :            :         // Beim Seeken nicht die Attr beruecksichtigen, die dort beginnen!
    1444                 :            :         // Leere Attribute werden beruecksichtigt( verwendet), da diese
    1445                 :            :         // gerade eingestellt wurden.
    1446                 :            :         // 12.4.95: Doch keine Leeren Attribute verwenden:
    1447                 :            :         // - Wenn gerade eingestellt und leer => keine Auswirkung auf Font
    1448                 :            :         // In einem leeren Absatz eingestellte Zeichen werden sofort wirksam.
    1449         [ #  # ]:          0 :         if ( ( ( pAttrib->GetStart() < nPos ) && ( pAttrib->GetEnd() >= nPos ) )
           [ #  #  #  # ]
                 [ #  # ]
    1450                 :          0 :                     || !pNode->GetText().Len() )
    1451                 :            :         {
    1452         [ #  # ]:          0 :             if ( pAttrib->Which() != TEXTATTR_FONTCOLOR )
    1453                 :            :             {
    1454                 :          0 :                 pAttrib->GetAttr().SetFont(rFont);
    1455                 :            :             }
    1456                 :            :             else
    1457                 :            :             {
    1458         [ #  # ]:          0 :                 if ( pOutDev )
    1459                 :          0 :                     pOutDev->SetTextColor( ((TextAttribFontColor&)pAttrib->GetAttr()).GetColor() );
    1460                 :            :             }
    1461                 :            :         }
    1462                 :            :     }
    1463                 :            : 
    1464 [ -  + ][ #  # ]:        181 :     if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) &&
           [ #  #  #  #  
           #  # ][ -  + ]
    1465                 :          0 :         ( nPos > mpIMEInfos->aPos.GetIndex() ) && ( nPos <= ( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ) ) )
    1466                 :            :     {
    1467                 :          0 :         sal_uInt16 nAttr = mpIMEInfos->pAttribs[ nPos - mpIMEInfos->aPos.GetIndex() - 1 ];
    1468         [ #  # ]:          0 :         if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE )
    1469                 :          0 :             rFont.SetUnderline( UNDERLINE_SINGLE );
    1470         [ #  # ]:          0 :         else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE )
    1471                 :          0 :             rFont.SetUnderline( UNDERLINE_BOLD );
    1472         [ #  # ]:          0 :         else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE )
    1473                 :          0 :             rFont.SetUnderline( UNDERLINE_DOTTED );
    1474         [ #  # ]:          0 :         else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE )
    1475                 :          0 :             rFont.SetUnderline( UNDERLINE_DOTTED );
    1476         [ #  # ]:          0 :         if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT )
    1477         [ #  # ]:          0 :             rFont.SetColor( Color( COL_RED ) );
    1478         [ #  # ]:          0 :         else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT )
    1479         [ #  # ]:          0 :             rFont.SetColor( Color( COL_LIGHTGRAY ) );
    1480         [ #  # ]:          0 :         if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT )
    1481                 :            :         {
    1482                 :          0 :             const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    1483                 :          0 :             rFont.SetColor( rStyleSettings.GetHighlightTextColor() );
    1484                 :          0 :             rFont.SetFillColor( rStyleSettings.GetHighlightColor() );
    1485                 :          0 :             rFont.SetTransparent( sal_False );
    1486                 :            :         }
    1487         [ #  # ]:          0 :         else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE )
    1488                 :            :         {
    1489                 :          0 :             rFont.SetUnderline( UNDERLINE_WAVE );
    1490                 :            : //          if( pOut )
    1491                 :            : //              pOut->SetTextLineColor( Color( COL_LIGHTGRAY ) );
    1492                 :            :         }
    1493                 :            :     }
    1494                 :        181 : }
    1495                 :            : 
    1496                 :        128 : void TextEngine::FormatAndUpdate( TextView* pCurView )
    1497                 :            : {
    1498         [ -  + ]:        128 :     if ( mbDowning )
    1499                 :        128 :         return ;
    1500                 :            : 
    1501         [ -  + ]:        128 :     if ( IsInUndo() )
    1502                 :          0 :         IdleFormatAndUpdate( pCurView );
    1503                 :            :     else
    1504                 :            :     {
    1505                 :        128 :         FormatDoc();
    1506                 :        128 :         UpdateViews( pCurView );
    1507                 :            :     }
    1508                 :            : }
    1509                 :            : 
    1510                 :            : 
    1511                 :          0 : void TextEngine::IdleFormatAndUpdate( TextView* pCurView, sal_uInt16 nMaxTimerRestarts )
    1512                 :            : {
    1513                 :          0 :     mpIdleFormatter->DoIdleFormat( pCurView, nMaxTimerRestarts );
    1514                 :          0 : }
    1515                 :            : 
    1516                 :         52 : void TextEngine::TextModified()
    1517                 :            : {
    1518                 :         52 :     mbFormatted = sal_False;
    1519                 :         52 :     mbModified = sal_True;
    1520                 :         52 : }
    1521                 :            : 
    1522                 :        596 : void TextEngine::UpdateViews( TextView* pCurView )
    1523                 :            : {
    1524 [ +  - ][ +  - ]:        596 :     if ( !GetUpdateMode() || IsFormatting() || maInvalidRec.IsEmpty() )
         [ -  + ][ -  + ]
    1525                 :        596 :         return;
    1526                 :            : 
    1527                 :            :     DBG_ASSERT( IsFormatted(), "UpdateViews: Doc nicht formatiert!" );
    1528                 :            : 
    1529         [ +  + ]:       1102 :     for ( sal_uInt16 nView = 0; nView < mpViews->size(); nView++ )
    1530                 :            :     {
    1531         [ +  - ]:        506 :         TextView* pView = (*mpViews)[ nView ];
    1532         [ +  - ]:        506 :         pView->HideCursor();
    1533                 :            : 
    1534                 :        506 :         Rectangle aClipRec( maInvalidRec );
    1535         [ +  - ]:        506 :         Size aOutSz = pView->GetWindow()->GetOutputSizePixel();
    1536 [ +  - ][ +  - ]:        506 :         Rectangle aVisArea( pView->GetStartDocPos(), aOutSz );
    1537         [ +  - ]:        506 :         aClipRec.Intersection( aVisArea );
    1538 [ +  - ][ +  + ]:        506 :         if ( !aClipRec.IsEmpty() )
    1539                 :            :         {
    1540                 :            :             // in Fensterkoordinaten umwandeln....
    1541         [ +  - ]:        296 :             Point aNewPos = pView->GetWindowPos( aClipRec.TopLeft() );
    1542         [ -  + ]:        296 :             if ( IsRightToLeft() )
    1543                 :          0 :                 aNewPos.X() -= aOutSz.Width() - 1;
    1544                 :        296 :             aClipRec.SetPos( aNewPos );
    1545                 :            : 
    1546         [ -  + ]:        296 :             if ( pView == pCurView )
    1547 [ #  # ][ #  # ]:          0 :                 pView->ImpPaint( aClipRec, !pView->GetWindow()->IsPaintTransparent() );
                 [ #  # ]
    1548                 :            :             else
    1549 [ +  - ][ +  - ]:        296 :                 pView->GetWindow()->Invalidate( aClipRec );
    1550                 :            :         }
    1551                 :            :     }
    1552                 :            : 
    1553         [ -  + ]:        596 :     if ( pCurView )
    1554                 :            :     {
    1555                 :          0 :         pCurView->ShowCursor( pCurView->IsAutoScroll() );
    1556                 :            :     }
    1557                 :            : 
    1558                 :        596 :     maInvalidRec = Rectangle();
    1559                 :            : }
    1560                 :            : 
    1561                 :          0 : IMPL_LINK_NOARG(TextEngine, IdleFormatHdl)
    1562                 :            : {
    1563                 :          0 :     FormatAndUpdate( mpIdleFormatter->GetView() );
    1564                 :          0 :     return 0;
    1565                 :            : }
    1566                 :            : 
    1567                 :        526 : void TextEngine::CheckIdleFormatter()
    1568                 :            : {
    1569                 :        526 :     mpIdleFormatter->ForceTimeout();
    1570                 :        526 : }
    1571                 :            : 
    1572                 :        468 : void TextEngine::FormatFullDoc()
    1573                 :            : {
    1574         [ +  + ]:        936 :     for ( sal_uLong nPortion = 0; nPortion < mpTEParaPortions->Count(); nPortion++ )
    1575                 :            :     {
    1576                 :        468 :         TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion );        sal_uInt16 nLen = pTEParaPortion->GetNode()->GetText().Len();
    1577                 :        468 :         pTEParaPortion->MarkSelectionInvalid( 0, nLen );
    1578                 :            :     }
    1579                 :        468 :     mbFormatted = sal_False;
    1580                 :        468 :     FormatDoc();
    1581                 :        468 : }
    1582                 :            : 
    1583                 :        596 : void TextEngine::FormatDoc()
    1584                 :            : {
    1585 [ +  - ][ +  - ]:        596 :     if ( IsFormatted() || !GetUpdateMode() || IsFormatting() )
         [ -  + ][ -  + ]
    1586                 :        596 :         return;
    1587                 :            : 
    1588                 :        596 :     mbIsFormatting = sal_True;
    1589                 :        596 :     mbHasMultiLineParas = sal_False;
    1590                 :            : 
    1591                 :        596 :     long nY = 0;
    1592                 :        596 :     sal_Bool bGrow = sal_False;
    1593                 :            : 
    1594                 :        596 :     maInvalidRec = Rectangle(); // leermachen
    1595         [ +  + ]:       1192 :     for ( sal_uLong nPara = 0; nPara < mpTEParaPortions->Count(); nPara++ )
    1596                 :            :     {
    1597                 :        596 :         TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
    1598         [ +  - ]:        596 :         if ( pTEParaPortion->IsInvalid() )
    1599                 :            :         {
    1600                 :        596 :             sal_uLong nOldParaWidth = 0xFFFFFFFF;
    1601         [ +  + ]:        596 :             if ( mnCurTextWidth != 0xFFFFFFFF )
    1602                 :        292 :                 nOldParaWidth = CalcTextWidth( nPara );
    1603                 :            : 
    1604                 :        596 :             ImpFormattingParagraph( nPara );
    1605                 :            : 
    1606         [ +  + ]:        596 :             if ( CreateLines( nPara ) )
    1607                 :        218 :                 bGrow = sal_True;
    1608                 :            : 
    1609                 :            :             // InvalidRec nur einmal setzen...
    1610         [ +  - ]:        596 :             if ( maInvalidRec.IsEmpty() )
    1611                 :            :             {
    1612                 :            :                 // Bei Paperwidth 0 (AutoPageSize) bleibt es sonst Empty()...
    1613                 :        596 :                 long nWidth = (long)mnMaxTextWidth;
    1614         [ +  + ]:        596 :                 if ( !nWidth )
    1615                 :        384 :                     nWidth = 0x7FFFFFFF;
    1616         [ +  - ]:        596 :                 Range aInvRange( GetInvalidYOffsets( nPara ) );
    1617                 :        596 :                 maInvalidRec = Rectangle( Point( 0, nY+aInvRange.Min() ),
    1618         [ +  - ]:       1192 :                     Size( nWidth, aInvRange.Len() ) );
    1619                 :            :             }
    1620                 :            :             else
    1621                 :            :             {
    1622                 :          0 :                 maInvalidRec.Bottom() = nY + CalcParaHeight( nPara );
    1623                 :            :             }
    1624                 :            : 
    1625         [ +  + ]:        596 :             if ( mnCurTextWidth != 0xFFFFFFFF )
    1626                 :            :             {
    1627                 :        292 :                 sal_uLong nNewParaWidth = CalcTextWidth( nPara );
    1628         [ +  + ]:        292 :                 if ( nNewParaWidth >= mnCurTextWidth )
    1629                 :        258 :                     mnCurTextWidth = nNewParaWidth;
    1630 [ +  - ][ -  + ]:         34 :                 else if ( ( nOldParaWidth != 0xFFFFFFFF ) && ( nOldParaWidth >= mnCurTextWidth ) )
    1631                 :          0 :                     mnCurTextWidth = 0xFFFFFFFF;
    1632                 :            :             }
    1633                 :            :         }
    1634         [ #  # ]:          0 :         else if ( bGrow )
    1635                 :            :         {
    1636                 :          0 :             maInvalidRec.Bottom() = nY + CalcParaHeight( nPara );
    1637                 :            :         }
    1638                 :        596 :         nY += CalcParaHeight( nPara );
    1639 [ -  + ][ -  + ]:        596 :         if ( !mbHasMultiLineParas && pTEParaPortion->GetLines().size() > 1 )
                 [ +  - ]
    1640                 :          0 :             mbHasMultiLineParas = sal_True;
    1641                 :            :     }
    1642                 :            : 
    1643         [ +  - ]:        596 :     if ( !maInvalidRec.IsEmpty() )
    1644                 :            :     {
    1645                 :        596 :         sal_uLong nNewHeight = CalcTextHeight();
    1646                 :        596 :         long nDiff = nNewHeight - mnCurTextHeight;
    1647         [ +  + ]:        596 :         if ( nNewHeight < mnCurTextHeight )
    1648                 :            :         {
    1649                 :        110 :             maInvalidRec.Bottom() = (long)Max( nNewHeight, mnCurTextHeight );
    1650         [ -  + ]:        110 :             if ( maInvalidRec.IsEmpty() )
    1651                 :            :             {
    1652                 :          0 :                 maInvalidRec.Top() = 0;
    1653                 :            :                 // Left und Right werden nicht ausgewertet, aber wegen IsEmpty gesetzt.
    1654                 :          0 :                 maInvalidRec.Left() = 0;
    1655                 :          0 :                 maInvalidRec.Right() = mnMaxTextWidth;
    1656                 :            :             }
    1657                 :            :         }
    1658                 :            : 
    1659                 :        596 :         mnCurTextHeight = nNewHeight;
    1660         [ +  + ]:        596 :         if ( nDiff )
    1661                 :            :         {
    1662                 :        300 :             mbFormatted = sal_True;
    1663                 :        300 :             ImpTextHeightChanged();
    1664                 :            :         }
    1665                 :            :     }
    1666                 :            : 
    1667                 :        596 :     mbIsFormatting = sal_False;
    1668                 :        596 :     mbFormatted = sal_True;
    1669                 :            : 
    1670                 :        596 :     ImpTextFormatted();
    1671                 :            : }
    1672                 :            : 
    1673                 :        504 : void TextEngine::CreateAndInsertEmptyLine( sal_uLong nPara )
    1674                 :            : {
    1675         [ +  - ]:        504 :     TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
    1676         [ +  - ]:        504 :     TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
    1677                 :            : 
    1678         [ +  - ]:        504 :     TextLine* pTmpLine = new TextLine;
    1679                 :        504 :     pTmpLine->SetStart( pNode->GetText().Len() );
    1680                 :        504 :     pTmpLine->SetEnd( pTmpLine->GetStart() );
    1681         [ +  - ]:        504 :     pTEParaPortion->GetLines().push_back( pTmpLine );
    1682                 :            : 
    1683 [ +  - ][ +  + ]:        504 :     if ( ImpGetAlign() == TXTALIGN_CENTER )
    1684                 :        144 :         pTmpLine->SetStartX( (short)(mnMaxTextWidth / 2) );
    1685 [ +  - ][ -  + ]:        360 :     else if ( ImpGetAlign() == TXTALIGN_RIGHT )
    1686                 :          0 :         pTmpLine->SetStartX( (short)mnMaxTextWidth );
    1687                 :            :     else
    1688                 :        360 :         pTmpLine->SetStartX( mpDoc->GetLeftMargin() );
    1689                 :            : 
    1690         [ -  + ]:        504 :     sal_Bool bLineBreak = pNode->GetText().Len() ? sal_True : sal_False;
    1691                 :            : 
    1692         [ +  - ]:        504 :     TETextPortion* pDummyPortion = new TETextPortion( 0 );
    1693                 :        504 :     pDummyPortion->GetWidth() = 0;
    1694         [ +  - ]:        504 :     pTEParaPortion->GetTextPortions().push_back( pDummyPortion );
    1695                 :            : 
    1696         [ -  + ]:        504 :     if ( bLineBreak == sal_True )
    1697                 :            :     {
    1698                 :            :         // -2: The new one is already inserted.
    1699                 :            :         OSL_ENSURE(
    1700                 :            :             pTEParaPortion->GetLines()[pTEParaPortion->GetLines().size()-2],
    1701                 :            :             "Soft Break, no Line?!");
    1702                 :          0 :         sal_uInt16 nPos = (sal_uInt16) pTEParaPortion->GetTextPortions().size() - 1 ;
    1703                 :          0 :         pTmpLine->SetStartPortion( nPos );
    1704                 :          0 :         pTmpLine->SetEndPortion( nPos );
    1705                 :            :     }
    1706                 :        504 : }
    1707                 :            : 
    1708                 :          0 : void TextEngine::ImpBreakLine( sal_uLong nPara, TextLine* pLine, TETextPortion*, sal_uInt16 nPortionStart, long nRemainingWidth )
    1709                 :            : {
    1710         [ #  # ]:          0 :     TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
    1711                 :            : 
    1712                 :            :     // Font sollte noch eingestellt sein.
    1713         [ #  # ]:          0 :     sal_uInt16 nMaxBreakPos = mpRefDev->GetTextBreak( pNode->GetText(), nRemainingWidth, nPortionStart );
    1714                 :            : 
    1715                 :            :     DBG_ASSERT( nMaxBreakPos < pNode->GetText().Len(), "Break?!" );
    1716                 :            : 
    1717         [ #  # ]:          0 :     if ( nMaxBreakPos == STRING_LEN )   // GetTextBreak() ist anderer Auffassung als GetTextSize()
    1718                 :          0 :         nMaxBreakPos = pNode->GetText().Len() - 1;
    1719                 :            : 
    1720         [ #  # ]:          0 :     uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator();
    1721 [ #  # ][ #  # ]:          0 :     i18n::LineBreakHyphenationOptions aHyphOptions( NULL, uno::Sequence< beans::PropertyValue >(), 1 );
         [ #  # ][ #  # ]
    1722                 :            : 
    1723                 :          0 :     i18n::LineBreakUserOptions aUserOptions;
    1724 [ #  # ][ #  # ]:          0 :     aUserOptions.forbiddenBeginCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().beginLine;
    1725 [ #  # ][ #  # ]:          0 :     aUserOptions.forbiddenEndCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().endLine;
    1726                 :          0 :     aUserOptions.applyForbiddenRules = sal_True;
    1727                 :          0 :     aUserOptions.allowPunctuationOutsideMargin = sal_False;
    1728                 :          0 :     aUserOptions.allowHyphenateEnglish = sal_False;
    1729                 :            : 
    1730 [ #  # ][ #  # ]:          0 :     static const com::sun::star::lang::Locale aDefLocale;
    1731 [ #  # ][ #  # ]:          0 :     i18n::LineBreakResults aLBR = xBI->getLineBreak( pNode->GetText(), nMaxBreakPos, aDefLocale, pLine->GetStart(), aHyphOptions, aUserOptions );
                 [ #  # ]
    1732                 :          0 :     sal_uInt16 nBreakPos = (sal_uInt16)aLBR.breakIndex;
    1733         [ #  # ]:          0 :     if ( nBreakPos <= pLine->GetStart() )
    1734                 :            :     {
    1735                 :          0 :         nBreakPos = nMaxBreakPos;
    1736         [ #  # ]:          0 :         if ( nBreakPos <= pLine->GetStart() )
    1737                 :          0 :             nBreakPos = pLine->GetStart() + 1;  // Sonst Endlosschleife!
    1738                 :            :     }
    1739                 :            : 
    1740                 :            : 
    1741                 :            :     // die angeknackste Portion ist die End-Portion
    1742                 :          0 :     pLine->SetEnd( nBreakPos );
    1743         [ #  # ]:          0 :     sal_uInt16 nEndPortion = SplitTextPortion( nPara, nBreakPos );
    1744                 :            : 
    1745                 :          0 :     sal_Bool bBlankSeparator = ( ( nBreakPos >= pLine->GetStart() ) &&
    1746 [ #  # ][ #  # ]:          0 :                                  ( pNode->GetText().GetChar( nBreakPos ) == ' ' ) ) ? sal_True : sal_False;
    1747         [ #  # ]:          0 :     if ( bBlankSeparator )
    1748                 :            :     {
    1749                 :            :         // Blanks am Zeilenende generell unterdruecken...
    1750         [ #  # ]:          0 :         TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
    1751                 :          0 :         TETextPortion* pTP = pTEParaPortion->GetTextPortions()[ nEndPortion ];
    1752                 :            :         DBG_ASSERT( nBreakPos > pLine->GetStart(), "SplitTextPortion am Anfang der Zeile?" );
    1753         [ #  # ]:          0 :         pTP->GetWidth() = (long)CalcTextWidth( nPara, nBreakPos-pTP->GetLen(), pTP->GetLen()-1 );
    1754                 :            :     }
    1755 [ #  # ][ #  # ]:          0 :     pLine->SetEndPortion( nEndPortion );
    1756                 :          0 : }
    1757                 :            : 
    1758                 :          0 : sal_uInt16 TextEngine::SplitTextPortion( sal_uLong nPara, sal_uInt16 nPos )
    1759                 :            : {
    1760                 :            : 
    1761                 :            :     // Die Portion bei nPos wird geplittet, wenn bei nPos nicht
    1762                 :            :     // sowieso ein Wechsel ist
    1763         [ #  # ]:          0 :     if ( nPos == 0 )
    1764                 :          0 :         return 0;
    1765                 :            : 
    1766                 :            :     sal_uInt16 nSplitPortion;
    1767                 :          0 :     sal_uInt16 nTmpPos = 0;
    1768                 :          0 :     TETextPortion* pTextPortion = 0;
    1769         [ #  # ]:          0 :     TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
    1770                 :          0 :     sal_uInt16 nPortions = pTEParaPortion->GetTextPortions().size();
    1771         [ #  # ]:          0 :     for ( nSplitPortion = 0; nSplitPortion < nPortions; nSplitPortion++ )
    1772                 :            :     {
    1773                 :          0 :         TETextPortion* pTP = pTEParaPortion->GetTextPortions()[nSplitPortion];
    1774                 :          0 :         nTmpPos = nTmpPos + pTP->GetLen();
    1775         [ #  # ]:          0 :         if ( nTmpPos >= nPos )
    1776                 :            :         {
    1777         [ #  # ]:          0 :             if ( nTmpPos == nPos )  // dann braucht nichts geteilt werden
    1778                 :          0 :                 return nSplitPortion;
    1779                 :          0 :             pTextPortion = pTP;
    1780                 :          0 :             break;
    1781                 :            :         }
    1782                 :            :     }
    1783                 :            : 
    1784                 :            :     DBG_ASSERT( pTextPortion, "Position ausserhalb des Bereichs!" );
    1785                 :            : 
    1786                 :          0 :     sal_uInt16 nOverlapp = nTmpPos - nPos;
    1787                 :          0 :     pTextPortion->GetLen() = pTextPortion->GetLen() - nOverlapp;
    1788         [ #  # ]:          0 :     TETextPortion* pNewPortion = new TETextPortion( nOverlapp );
    1789 [ #  # ][ #  # ]:          0 :     pTEParaPortion->GetTextPortions().insert( pTEParaPortion->GetTextPortions().begin() + nSplitPortion + 1, pNewPortion );
                 [ #  # ]
    1790         [ #  # ]:          0 :     pTextPortion->GetWidth() = (long)CalcTextWidth( nPara, nPos-pTextPortion->GetLen(), pTextPortion->GetLen() );
    1791                 :            : 
    1792                 :          0 :     return nSplitPortion;
    1793                 :            : }
    1794                 :            : 
    1795                 :         92 : void TextEngine::CreateTextPortions( sal_uLong nPara, sal_uInt16 nStartPos )
    1796                 :            : {
    1797         [ +  - ]:         92 :     TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
    1798                 :         92 :     TextNode* pNode = pTEParaPortion->GetNode();
    1799                 :            :     DBG_ASSERT( pNode->GetText().Len(), "CreateTextPortions sollte nicht fuer leere Absaetze verwendet werden!" );
    1800                 :            : 
    1801         [ +  - ]:         92 :     std::set<sal_uInt16> aPositions;
    1802         [ +  - ]:         92 :     std::set<sal_uInt16>::iterator aPositionsIt;
    1803         [ +  - ]:         92 :     aPositions.insert(0);
    1804                 :            : 
    1805                 :         92 :     sal_uInt16 nAttribs = pNode->GetCharAttribs().Count();
    1806         [ -  + ]:         92 :     for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ )
    1807                 :            :     {
    1808         [ #  # ]:          0 :         TextCharAttrib* pAttrib = pNode->GetCharAttribs().GetAttrib( nAttr );
    1809                 :            : 
    1810         [ #  # ]:          0 :         aPositions.insert( pAttrib->GetStart() );
    1811         [ #  # ]:          0 :         aPositions.insert( pAttrib->GetEnd() );
    1812                 :            :     }
    1813         [ +  - ]:         92 :     aPositions.insert( pNode->GetText().Len() );
    1814                 :            : 
    1815                 :         92 :     const std::vector<TEWritingDirectionInfo>& rWritingDirections = pTEParaPortion->GetWritingDirectionInfos();
    1816 [ +  - ][ +  + ]:        184 :     for ( std::vector<TEWritingDirectionInfo>::const_iterator it = rWritingDirections.begin(); it != rWritingDirections.end(); ++it )
    1817         [ +  - ]:         92 :         aPositions.insert( (*it).nStartPos );
    1818                 :            : 
    1819 [ -  + ][ #  # ]:         92 :     if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) )
         [ #  # ][ -  + ]
    1820                 :            :     {
    1821                 :          0 :         sal_uInt16 nLastAttr = 0xFFFF;
    1822         [ #  # ]:          0 :         for( sal_uInt16 n = 0; n < mpIMEInfos->nLen; n++ )
    1823                 :            :         {
    1824         [ #  # ]:          0 :             if ( mpIMEInfos->pAttribs[n] != nLastAttr )
    1825                 :            :             {
    1826         [ #  # ]:          0 :                 aPositions.insert( mpIMEInfos->aPos.GetIndex() + n );
    1827                 :          0 :                 nLastAttr = mpIMEInfos->pAttribs[n];
    1828                 :            :             }
    1829                 :            :         }
    1830                 :            :     }
    1831                 :            : 
    1832         [ +  - ]:         92 :     sal_uInt16 nTabPos = pNode->GetText().Search( '\t', 0 );
    1833         [ -  + ]:         92 :     while ( nTabPos != STRING_NOTFOUND )
    1834                 :            :     {
    1835         [ #  # ]:          0 :         aPositions.insert( nTabPos );
    1836         [ #  # ]:          0 :         aPositions.insert( nTabPos + 1 );
    1837         [ #  # ]:          0 :         nTabPos = pNode->GetText().Search( '\t', nTabPos+1 );
    1838                 :            :     }
    1839                 :            : 
    1840                 :            :     // Ab ... loeschen:
    1841                 :            :     // Leider muss die Anzahl der TextPortions mit aPositions.Count()
    1842                 :            :     // nicht uebereinstimmen, da evtl. Zeilenumbrueche...
    1843                 :         92 :     sal_uInt16 nPortionStart = 0;
    1844                 :         92 :     sal_uInt16 nInvPortion = 0;
    1845                 :            :     sal_uInt16 nP;
    1846         [ +  + ]:         92 :     for ( nP = 0; nP < pTEParaPortion->GetTextPortions().size(); nP++ )
    1847                 :            :     {
    1848                 :         40 :         TETextPortion* pTmpPortion = pTEParaPortion->GetTextPortions()[nP];
    1849                 :         40 :         nPortionStart = nPortionStart + pTmpPortion->GetLen();
    1850         [ +  - ]:         40 :         if ( nPortionStart >= nStartPos )
    1851                 :            :         {
    1852                 :         40 :             nPortionStart = nPortionStart - pTmpPortion->GetLen();
    1853                 :         40 :             nInvPortion = nP;
    1854                 :         40 :             break;
    1855                 :            :         }
    1856                 :            :     }
    1857                 :            :     OSL_ENSURE(nP < pTEParaPortion->GetTextPortions().size()
    1858                 :            :             || pTEParaPortion->GetTextPortions().empty(),
    1859                 :            :             "Nothing to delete: CreateTextPortions");
    1860 [ -  + ][ #  # ]:         92 :     if ( nInvPortion && ( nPortionStart+pTEParaPortion->GetTextPortions()[nInvPortion]->GetLen() > nStartPos ) )
                 [ -  + ]
    1861                 :            :     {
    1862                 :            :         // lieber eine davor...
    1863                 :            :         // Aber nur wenn es mitten in der Portion war, sonst ist es evtl.
    1864                 :            :         // die einzige in der Zeile davor !
    1865                 :          0 :         nInvPortion--;
    1866                 :          0 :         nPortionStart = nPortionStart - pTEParaPortion->GetTextPortions()[nInvPortion]->GetLen();
    1867                 :            :     }
    1868         [ +  - ]:         92 :     pTEParaPortion->GetTextPortions().DeleteFromPortion( nInvPortion );
    1869                 :            : 
    1870                 :            :     // Eine Portion kann auch durch einen Zeilenumbruch entstanden sein:
    1871         [ +  - ]:         92 :     aPositions.insert( nPortionStart );
    1872                 :            : 
    1873         [ +  - ]:         92 :     aPositionsIt = aPositions.find( nPortionStart );
    1874                 :            :     DBG_ASSERT( aPositionsIt != aPositions.end(), "nPortionStart not found" );
    1875                 :            : 
    1876 [ +  - ][ +  - ]:         92 :     if ( aPositionsIt != aPositions.end() )
    1877                 :            :     {
    1878                 :         92 :         std::set<sal_uInt16>::iterator nextIt = aPositionsIt;
    1879 [ +  - ][ +  - ]:        184 :         for ( ++nextIt; nextIt != aPositions.end(); ++aPositionsIt, ++nextIt )
         [ +  - ][ +  - ]
                 [ +  + ]
    1880                 :            :         {
    1881 [ +  - ][ +  - ]:         92 :             TETextPortion* pNew = new TETextPortion( *nextIt - *aPositionsIt );
                 [ +  - ]
    1882         [ +  - ]:         92 :             pTEParaPortion->GetTextPortions().push_back( pNew );
    1883                 :            :         }
    1884                 :            :     }
    1885                 :         92 :     OSL_ENSURE(pTEParaPortion->GetTextPortions().size(), "No Portions?!");
    1886                 :         92 : }
    1887                 :            : 
    1888                 :          0 : void TextEngine::RecalcTextPortion( sal_uLong nPara, sal_uInt16 nStartPos, short nNewChars )
    1889                 :            : {
    1890                 :          0 :     TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
    1891                 :            :     OSL_ENSURE(pTEParaPortion->GetTextPortions().size(), "no Portions!");
    1892                 :            :     OSL_ENSURE(nNewChars, "RecalcTextPortion with Diff == 0");
    1893                 :            : 
    1894                 :          0 :     TextNode* const pNode = pTEParaPortion->GetNode();
    1895         [ #  # ]:          0 :     if ( nNewChars > 0 )
    1896                 :            :     {
    1897                 :            :         // Wenn an nStartPos ein Attribut beginnt/endet, oder vor nStartPos
    1898                 :            :         // ein Tab steht, faengt eine neue Portion an,
    1899                 :            :         // ansonsten wird die Portion an nStartPos erweitert.
    1900                 :            :         // Oder wenn ganz vorne ( StartPos 0 ) und dann ein Tab
    1901                 :            : 
    1902         [ #  # ]:          0 :         if ( ( pNode->GetCharAttribs().HasBoundingAttrib( nStartPos ) ) ||
           [ #  #  #  # ]
           [ #  #  #  #  
           #  # ][ #  # ]
    1903                 :          0 :              ( nStartPos && ( pNode->GetText().GetChar( nStartPos - 1 ) == '\t' ) ) ||
    1904                 :          0 :              ( ( !nStartPos && ( nNewChars < pNode->GetText().Len() ) && pNode->GetText().GetChar( nNewChars ) == '\t' ) ) )
    1905                 :            :         {
    1906                 :          0 :             sal_uInt16 nNewPortionPos = 0;
    1907         [ #  # ]:          0 :             if ( nStartPos )
    1908                 :          0 :                 nNewPortionPos = SplitTextPortion( nPara, nStartPos ) + 1;
    1909                 :            : 
    1910                 :            :             // Eine leere Portion kann hier stehen, wenn der Absatz leer war,
    1911                 :            :             // oder eine Zeile durch einen harten Zeilenumbruch entstanden ist.
    1912   [ #  #  #  # ]:          0 :             if ( ( nNewPortionPos < pTEParaPortion->GetTextPortions().size() ) &&
                 [ #  # ]
    1913                 :          0 :                     !pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() )
    1914                 :            :             {
    1915                 :            :                 // Dann die leere Portion verwenden.
    1916                 :            :                 sal_uInt16 & r =
    1917                 :          0 :                     pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen();
    1918                 :          0 :                 r = r + nNewChars;
    1919                 :            :             }
    1920                 :            :             else
    1921                 :            :             {
    1922         [ #  # ]:          0 :                 TETextPortion* pNewPortion = new TETextPortion( nNewChars );
    1923 [ #  # ][ #  # ]:          0 :                 pTEParaPortion->GetTextPortions().insert( pTEParaPortion->GetTextPortions().begin() + nNewPortionPos, pNewPortion );
    1924                 :            :             }
    1925                 :            :         }
    1926                 :            :         else
    1927                 :            :         {
    1928                 :            :             sal_uInt16 nPortionStart;
    1929                 :          0 :             const sal_uInt16 nTP = pTEParaPortion->GetTextPortions().
    1930         [ #  # ]:          0 :                 FindPortion( nStartPos, nPortionStart );
    1931                 :          0 :             TETextPortion* const pTP = pTEParaPortion->GetTextPortions()[ nTP ];
    1932                 :            :             DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden"  );
    1933                 :          0 :             pTP->GetLen() = pTP->GetLen() + nNewChars;
    1934                 :          0 :             pTP->GetWidth() = (-1);
    1935                 :            :         }
    1936                 :            :     }
    1937                 :            :     else
    1938                 :            :     {
    1939                 :            :         // Portion schrumpfen oder ggf. entfernen.
    1940                 :            :         // Vor Aufruf dieser Methode muss sichergestellt sein, dass
    1941                 :            :         // keine Portions in dem geloeschten Bereich lagen!
    1942                 :            : 
    1943                 :            :         // Es darf keine reinragende oder im Bereich startende Portion geben,
    1944                 :            :         // also muss nStartPos <= nPos <= nStartPos - nNewChars(neg.) sein
    1945                 :          0 :         sal_uInt16 nPortion = 0;
    1946                 :          0 :         sal_uInt16 nPos = 0;
    1947                 :          0 :         sal_uInt16 nEnd = nStartPos-nNewChars;
    1948                 :          0 :         sal_uInt16 nPortions = pTEParaPortion->GetTextPortions().size();
    1949                 :          0 :         TETextPortion* pTP = 0;
    1950         [ #  # ]:          0 :         for ( nPortion = 0; nPortion < nPortions; nPortion++ )
    1951                 :            :         {
    1952                 :          0 :             pTP = pTEParaPortion->GetTextPortions()[ nPortion ];
    1953         [ #  # ]:          0 :             if ( ( nPos+pTP->GetLen() ) > nStartPos )
    1954                 :            :             {
    1955                 :            :                 DBG_ASSERT( nPos <= nStartPos, "Start falsch!" );
    1956                 :            :                 DBG_ASSERT( nPos+pTP->GetLen() >= nEnd, "End falsch!" );
    1957                 :          0 :                 break;
    1958                 :            :             }
    1959                 :          0 :             nPos = nPos + pTP->GetLen();
    1960                 :            :         }
    1961                 :            :         DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" );
    1962 [ #  # ][ #  # ]:          0 :         if ( ( nPos == nStartPos ) && ( (nPos+pTP->GetLen()) == nEnd ) )
                 [ #  # ]
    1963                 :            :         {
    1964                 :            :             // Portion entfernen;
    1965 [ #  # ][ #  # ]:          0 :             pTEParaPortion->GetTextPortions().erase( pTEParaPortion->GetTextPortions().begin() + nPortion );
    1966                 :          0 :             delete pTP;
    1967                 :            :         }
    1968                 :            :         else
    1969                 :            :         {
    1970                 :            :             DBG_ASSERT( pTP->GetLen() > (-nNewChars), "Portion zu klein zum schrumpfen!" );
    1971                 :          0 :             pTP->GetLen() = pTP->GetLen() + nNewChars;
    1972                 :            :         }
    1973                 :            :         OSL_ENSURE( pTEParaPortion->GetTextPortions().size(),
    1974                 :            :                 "RecalcTextPortions: none are left!" );
    1975                 :            :     }
    1976                 :          0 : }
    1977                 :            : 
    1978                 :         89 : void TextEngine::ImpPaint( OutputDevice* pOutDev, const Point& rStartPos, Rectangle const* pPaintArea, TextSelection const* pPaintRange, TextSelection const* pSelection )
    1979                 :            : {
    1980         [ -  + ]:         89 :     if ( !GetUpdateMode() )
    1981                 :          0 :         return;
    1982                 :            : 
    1983         [ -  + ]:         89 :     if ( !IsFormatted() )
    1984                 :          0 :         FormatDoc();
    1985                 :            : 
    1986                 :         89 :     bool bTransparent = false;
    1987         [ -  + ]:         89 :     Window* pOutWin = dynamic_cast<Window*>(pOutDev);
    1988 [ +  - ][ +  + ]:         89 :     bTransparent = (pOutWin && pOutWin->IsPaintTransparent());
    1989                 :            : 
    1990                 :         89 :     long nY = rStartPos.Y();
    1991                 :            : 
    1992                 :         89 :     TextPaM const* pSelStart = 0;
    1993                 :         89 :     TextPaM const* pSelEnd = 0;
    1994 [ #  # ][ -  + ]:         89 :     if ( pSelection && pSelection->HasRange() )
                 [ -  + ]
    1995                 :            :     {
    1996                 :          0 :         sal_Bool bInvers = pSelection->GetEnd() < pSelection->GetStart();
    1997         [ #  # ]:          0 :         pSelStart = !bInvers ? &pSelection->GetStart() : &pSelection->GetEnd();
    1998         [ #  # ]:          0 :         pSelEnd = bInvers ? &pSelection->GetStart() : &pSelection->GetEnd();
    1999                 :            :     }
    2000                 :            :     DBG_ASSERT( !pPaintRange || ( pPaintRange->GetStart() < pPaintRange->GetEnd() ), "ImpPaint: Paint-Range?!" );
    2001                 :            : 
    2002                 :         89 :     const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
    2003                 :            : 
    2004                 :            :     // --------------------------------------------------
    2005                 :            :     // Ueber alle Absaetze...
    2006                 :            :     // --------------------------------------------------
    2007         [ +  + ]:        178 :     for ( sal_uLong nPara = 0; nPara < mpTEParaPortions->Count(); nPara++ )
    2008                 :            :     {
    2009                 :         89 :         TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara );
    2010                 :            :         // falls beim Tippen Idle-Formatierung, asynchrones Paint.
    2011         [ -  + ]:         89 :         if ( pPortion->IsInvalid() )
    2012                 :          0 :             return;
    2013                 :            : 
    2014                 :         89 :         sal_uLong nParaHeight = CalcParaHeight( nPara );
    2015 [ +  - ][ -  +  :         89 :         if ( ( !pPaintArea || ( ( nY + (long)nParaHeight ) > pPaintArea->Top() ) )
             #  #  #  # ]
         [ +  - ][ +  - ]
    2016                 :          0 :                 && ( !pPaintRange || ( ( nPara >= pPaintRange->GetStart().GetPara() ) && ( nPara <= pPaintRange->GetEnd().GetPara() ) ) ) )
    2017                 :            :         {
    2018                 :            :             // --------------------------------------------------
    2019                 :            :             // Ueber die Zeilen des Absatzes...
    2020                 :            :             // --------------------------------------------------
    2021                 :         89 :             sal_uInt16 nLines = pPortion->GetLines().size();
    2022                 :         89 :             sal_uInt16 nIndex = 0;
    2023         [ +  + ]:        178 :             for ( sal_uInt16 nLine = 0; nLine < nLines; nLine++ )
    2024                 :            :             {
    2025                 :         89 :                 TextLine* pLine = pPortion->GetLines()[nLine];
    2026                 :         89 :                 Point aTmpPos( rStartPos.X() + pLine->GetStartX(), nY );
    2027                 :            : 
    2028 [ +  - ][ -  +  :        178 :                 if ( ( !pPaintArea || ( ( nY + mnCharHeight ) > pPaintArea->Top() ) )
             #  #  #  # ]
         [ +  - ][ +  - ]
    2029                 :            :                     && ( !pPaintRange || (
    2030         [ -  + ]:         89 :                         ( TextPaM( nPara, pLine->GetStart() ) < pPaintRange->GetEnd() ) &&
    2031         [ -  + ]:         89 :                         ( TextPaM( nPara, pLine->GetEnd() ) > pPaintRange->GetStart() ) ) ) )
    2032                 :            :                 {
    2033                 :            :                     // --------------------------------------------------
    2034                 :            :                     // Ueber die Portions der Zeile...
    2035                 :            :                     // --------------------------------------------------
    2036                 :         89 :                     nIndex = pLine->GetStart();
    2037         [ +  + ]:        178 :                     for ( sal_uInt16 y = pLine->GetStartPortion(); y <= pLine->GetEndPortion(); y++ )
    2038                 :            :                     {
    2039                 :            :                         OSL_ENSURE(pPortion->GetTextPortions().size(),
    2040                 :            :                                 "Line without Textportion in Paint!");
    2041                 :         89 :                         TETextPortion* pTextPortion = pPortion->GetTextPortions()[ y ];
    2042                 :            :                         DBG_ASSERT( pTextPortion, "NULL-Pointer im Portioniterator in UpdateViews" );
    2043                 :            : 
    2044         [ +  - ]:         89 :                         ImpInitLayoutMode( pOutDev /*, pTextPortion->IsRightToLeft() */);
    2045                 :            : 
    2046                 :         89 :                         long nTxtWidth = pTextPortion->GetWidth();
    2047         [ +  - ]:         89 :                         aTmpPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nIndex, nIndex );
    2048                 :            : 
    2049                 :            :                         // nur ausgeben, was im sichtbaren Bereich beginnt:
    2050 [ +  - ][ -  +  :        178 :                         if ( ( ( aTmpPos.X() + nTxtWidth ) >= 0 )
             #  #  #  # ]
                 [ +  - ]
    2051                 :            :                             && ( !pPaintRange || (
    2052         [ -  + ]:         89 :                                 ( TextPaM( nPara, nIndex ) < pPaintRange->GetEnd() ) &&
    2053         [ -  + ]:         89 :                                     ( TextPaM( nPara, nIndex + pTextPortion->GetLen() ) > pPaintRange->GetStart() ) ) ) )
    2054                 :            :                         {
    2055      [ +  -  - ]:         89 :                             switch ( pTextPortion->GetKind() )
    2056                 :            :                             {
    2057                 :            :                                 case PORTIONKIND_TEXT:
    2058                 :            :                                 {
    2059                 :            :                                     {
    2060         [ +  - ]:         89 :                                         Font aFont;
    2061         [ +  - ]:         89 :                                         SeekCursor( nPara, nIndex+1, aFont, pOutDev );
    2062         [ +  + ]:         89 :                                         if( bTransparent )
    2063         [ +  - ]:         48 :                                             aFont.SetTransparent( sal_True );
    2064         [ -  + ]:         41 :                                         else if ( pSelection )
    2065         [ #  # ]:          0 :                                             aFont.SetTransparent( sal_False );
    2066         [ +  - ]:         89 :                                         pOutDev->SetFont( aFont );
    2067                 :            : 
    2068                 :         89 :                                         sal_uInt16 nTmpIndex = nIndex;
    2069                 :         89 :                                         sal_uInt16 nEnd = nTmpIndex + pTextPortion->GetLen();
    2070                 :         89 :                                         Point aPos = aTmpPos;
    2071         [ -  + ]:         89 :                                         if ( pPaintRange )
    2072                 :            :                                         {
    2073                 :            :                                             // evtl soll nicht alles ausgegeben werden...
    2074   [ #  #  #  # ]:          0 :                                             if ( ( pPaintRange->GetStart().GetPara() == nPara )
                 [ #  # ]
    2075                 :          0 :                                                     && ( nTmpIndex < pPaintRange->GetStart().GetIndex() ) )
    2076                 :            :                                             {
    2077                 :          0 :                                                 nTmpIndex = pPaintRange->GetStart().GetIndex();
    2078                 :            :                                             }
    2079   [ #  #  #  # ]:          0 :                                             if ( ( pPaintRange->GetEnd().GetPara() == nPara )
                 [ #  # ]
    2080                 :          0 :                                                     && ( nEnd > pPaintRange->GetEnd().GetIndex() ) )
    2081                 :            :                                             {
    2082                 :          0 :                                                 nEnd = pPaintRange->GetEnd().GetIndex();
    2083                 :            :                                             }
    2084                 :            :                                         }
    2085                 :            : 
    2086                 :         89 :                                         sal_Bool bDone = sal_False;
    2087         [ -  + ]:         89 :                                         if ( pSelStart )
    2088                 :            :                                         {
    2089                 :            :                                             // liegt ein Teil in der Selektion???
    2090                 :          0 :                                             TextPaM aTextStart( nPara, nTmpIndex );
    2091                 :          0 :                                             TextPaM aTextEnd( nPara, nEnd );
    2092 [ #  # ][ #  # ]:          0 :                                             if ( ( aTextStart < *pSelEnd ) && ( aTextEnd > *pSelStart ) )
                 [ #  # ]
    2093                 :            :                                             {
    2094                 :            :                                                 sal_uInt16 nL;
    2095                 :            : 
    2096                 :            :                                                 // 1) Bereich vor Selektion
    2097         [ #  # ]:          0 :                                                 if ( aTextStart < *pSelStart )
    2098                 :            :                                                 {
    2099                 :          0 :                                                     nL = pSelStart->GetIndex() - nTmpIndex;
    2100         [ #  # ]:          0 :                                                     pOutDev->SetFont( aFont);
    2101         [ #  # ]:          0 :                                                     aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL );
    2102         [ #  # ]:          0 :                                                     pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL );
    2103                 :          0 :                                                     nTmpIndex = nTmpIndex + nL;
    2104                 :            : 
    2105                 :            :                                                 }
    2106                 :            :                                                 // 2) Bereich mit Selektion
    2107                 :          0 :                                                 nL = nEnd-nTmpIndex;
    2108         [ #  # ]:          0 :                                                 if ( aTextEnd > *pSelEnd )
    2109                 :          0 :                                                     nL = pSelEnd->GetIndex() - nTmpIndex;
    2110         [ #  # ]:          0 :                                                 if ( nL )
    2111                 :            :                                                 {
    2112                 :          0 :                                                     Color aOldTextColor = pOutDev->GetTextColor();
    2113         [ #  # ]:          0 :                                                     pOutDev->SetTextColor( rStyleSettings.GetHighlightTextColor() );
    2114         [ #  # ]:          0 :                                                     pOutDev->SetTextFillColor( rStyleSettings.GetHighlightColor() );
    2115         [ #  # ]:          0 :                                                     aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL );
    2116         [ #  # ]:          0 :                                                     pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL );
    2117         [ #  # ]:          0 :                                                     pOutDev->SetTextColor( aOldTextColor );
    2118         [ #  # ]:          0 :                                                     pOutDev->SetTextFillColor();
    2119                 :          0 :                                                     nTmpIndex = nTmpIndex + nL;
    2120                 :            :                                                 }
    2121                 :            : 
    2122                 :            :                                                 // 3) Bereich nach Selektion
    2123         [ #  # ]:          0 :                                                 if ( nTmpIndex < nEnd )
    2124                 :            :                                                 {
    2125                 :          0 :                                                     nL = nEnd-nTmpIndex;
    2126         [ #  # ]:          0 :                                                     aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nTmpIndex+nL );
    2127         [ #  # ]:          0 :                                                     pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex );
    2128                 :            :                                                 }
    2129                 :          0 :                                                 bDone = sal_True;
    2130                 :            :                                             }
    2131                 :            :                                         }
    2132         [ +  - ]:         89 :                                         if ( !bDone )
    2133                 :            :                                         {
    2134         [ +  - ]:         89 :                                             aPos.X() = rStartPos.X() + ImpGetOutputOffset( nPara, pLine, nTmpIndex, nEnd );
    2135         [ +  - ]:         89 :                                             pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex );
    2136         [ +  - ]:         89 :                                         }
    2137                 :            :                                     }
    2138                 :            : 
    2139                 :            :                                 }
    2140                 :         89 :                                 break;
    2141                 :            :                                 case PORTIONKIND_TAB:
    2142                 :            :                                 {
    2143                 :            :                                     // Bei HideSelection() nur Range, pSelection = 0.
    2144 [ #  # ][ #  # ]:          0 :                                     if ( pSelStart || pPaintRange )
    2145                 :            :                                     {
    2146         [ #  # ]:          0 :                                         Rectangle aTabArea( aTmpPos, Point( aTmpPos.X()+nTxtWidth, aTmpPos.Y()+mnCharHeight-1 ) );
    2147                 :          0 :                                         sal_Bool bDone = sal_False;
    2148         [ #  # ]:          0 :                                         if ( pSelStart )
    2149                 :            :                                         {
    2150                 :            :                                             // liegt der Tab in der Selektion???
    2151                 :          0 :                                             TextPaM aTextStart( nPara, nIndex );
    2152                 :          0 :                                             TextPaM aTextEnd( nPara, nIndex+1 );
    2153 [ #  # ][ #  # ]:          0 :                                             if ( ( aTextStart < *pSelEnd ) && ( aTextEnd > *pSelStart ) )
                 [ #  # ]
    2154                 :            :                                             {
    2155                 :          0 :                                                 Color aOldColor = pOutDev->GetFillColor();
    2156         [ #  # ]:          0 :                                                 pOutDev->SetFillColor( rStyleSettings.GetHighlightColor() );
    2157         [ #  # ]:          0 :                                                 pOutDev->DrawRect( aTabArea );
    2158         [ #  # ]:          0 :                                                 pOutDev->SetFillColor( aOldColor );
    2159                 :          0 :                                                 bDone = sal_True;
    2160                 :            :                                             }
    2161                 :            :                                         }
    2162         [ #  # ]:          0 :                                         if ( !bDone )
    2163                 :            :                                         {
    2164         [ #  # ]:          0 :                                             pOutDev->Erase( aTabArea );
    2165                 :            :                                         }
    2166                 :            :                                     }
    2167                 :            :                                 }
    2168                 :         89 :                                 break;
    2169                 :            :                                 default:    OSL_FAIL( "ImpPaint: Unknown Portion-Type !" );
    2170                 :            :                             }
    2171                 :            :                         }
    2172                 :            : 
    2173                 :         89 :                         nIndex = nIndex + pTextPortion->GetLen();
    2174                 :            :                     }
    2175                 :            :                 }
    2176                 :            : 
    2177                 :         89 :                 nY += mnCharHeight;
    2178                 :            : 
    2179 [ +  - ][ +  + ]:         89 :                 if ( pPaintArea && ( nY >= pPaintArea->Bottom() ) )
                 [ +  + ]
    2180                 :            :                     break;  // keine sichtbaren Aktionen mehr...
    2181                 :            :             }
    2182                 :            :         }
    2183                 :            :         else
    2184                 :            :         {
    2185                 :          0 :             nY += nParaHeight;
    2186                 :            :         }
    2187                 :            : 
    2188 [ +  - ][ +  + ]:         89 :         if ( pPaintArea && ( nY > pPaintArea->Bottom() ) )
                 [ +  + ]
    2189                 :          6 :             break;  // keine sichtbaren Aktionen mehr...
    2190                 :            :     }
    2191                 :            : }
    2192                 :            : 
    2193                 :        596 : sal_Bool TextEngine::CreateLines( sal_uLong nPara )
    2194                 :            : {
    2195                 :            :     // sal_Bool: Aenderung der Hoehe des Absatzes Ja/Nein - sal_True/sal_False
    2196                 :            : 
    2197         [ +  - ]:        596 :     TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
    2198         [ +  - ]:        596 :     TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
    2199                 :            :     DBG_ASSERT( pTEParaPortion->IsInvalid(), "CreateLines: Portion nicht invalid!" );
    2200                 :            : 
    2201                 :        596 :     sal_uInt16 nOldLineCount = pTEParaPortion->GetLines().size();
    2202                 :            : 
    2203                 :            :     // ---------------------------------------------------------------
    2204                 :            :     // Schnelle Sonderbehandlung fuer leere Absaetze...
    2205                 :            :     // ---------------------------------------------------------------
    2206         [ +  + ]:        596 :     if ( pTEParaPortion->GetNode()->GetText().Len() == 0 )
    2207                 :            :     {
    2208                 :            :         // schnelle Sonderbehandlung...
    2209         [ +  + ]:        504 :         if ( !pTEParaPortion->GetTextPortions().empty() )
    2210         [ +  - ]:        338 :             pTEParaPortion->GetTextPortions().Reset();
    2211         [ +  + ]:        504 :         if ( !pTEParaPortion->GetLines().empty() )
    2212                 :            :         {
    2213 [ +  - ][ +  - ]:       1014 :             BOOST_FOREACH(TextLine* pLine, pTEParaPortion->GetLines())
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  + ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
                 [ +  + ]
    2214                 :        338 :                 delete pLine;
    2215                 :        338 :             pTEParaPortion->GetLines().clear();
    2216                 :            :         }
    2217         [ +  - ]:        504 :         CreateAndInsertEmptyLine( nPara );
    2218                 :        504 :         pTEParaPortion->SetValid();
    2219                 :        504 :         return nOldLineCount != pTEParaPortion->GetLines().size();
    2220                 :            :     }
    2221                 :            : 
    2222                 :            :     // ---------------------------------------------------------------
    2223                 :            :     // Initialisierung......
    2224                 :            :     // ---------------------------------------------------------------
    2225                 :            : 
    2226         [ +  + ]:         92 :     if ( pTEParaPortion->GetLines().empty() )
    2227                 :            :     {
    2228         [ +  - ]:         52 :         TextLine* pL = new TextLine;
    2229         [ +  - ]:         52 :         pTEParaPortion->GetLines().push_back( pL );
    2230                 :            :     }
    2231                 :            : 
    2232                 :         92 :     const short nInvalidDiff = pTEParaPortion->GetInvalidDiff();
    2233                 :         92 :     const sal_uInt16 nInvalidStart = pTEParaPortion->GetInvalidPosStart();
    2234                 :         92 :     const sal_uInt16 nInvalidEnd =  nInvalidStart + Abs( nInvalidDiff );
    2235                 :         92 :     sal_Bool bQuickFormat = sal_False;
    2236                 :            : 
    2237         [ +  - ]:         92 :     if ( pTEParaPortion->GetWritingDirectionInfos().empty() )
    2238         [ +  - ]:         92 :         ImpInitWritingDirections( nPara );
    2239                 :            : 
    2240         [ +  - ]:         92 :     if ( pTEParaPortion->GetWritingDirectionInfos().size() == 1 )
    2241                 :            :     {
    2242 [ -  + ][ #  # ]:         92 :         if ( pTEParaPortion->IsSimpleInvalid() && ( nInvalidDiff > 0 ) )
                 [ -  + ]
    2243                 :            :         {
    2244                 :          0 :             bQuickFormat = sal_True;
    2245                 :            :         }
    2246 [ -  + ][ #  # ]:         92 :         else if ( ( pTEParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff < 0 ) )
                 [ -  + ]
    2247                 :            :         {
    2248                 :            :             // pruefen, ob loeschen ueber Portiongrenzen erfolgte...
    2249                 :          0 :             sal_uInt16 nStart = nInvalidStart;  // DOPPELT !!!!!!!!!!!!!!!
    2250                 :          0 :             sal_uInt16 nEnd = nStart - nInvalidDiff;  // neg.
    2251                 :          0 :             bQuickFormat = sal_True;
    2252                 :          0 :             sal_uInt16 nPos = 0;
    2253                 :          0 :             sal_uInt16 nPortions = pTEParaPortion->GetTextPortions().size();
    2254         [ #  # ]:          0 :             for ( sal_uInt16 nTP = 0; nTP < nPortions; nTP++ )
    2255                 :            :             {
    2256                 :            :                 // Es darf kein Start/Ende im geloeschten Bereich liegen.
    2257                 :          0 :                 TETextPortion* const pTP = pTEParaPortion->GetTextPortions()[ nTP ];
    2258                 :          0 :                 nPos = nPos + pTP->GetLen();
    2259 [ #  # ][ #  # ]:          0 :                 if ( ( nPos > nStart ) && ( nPos < nEnd ) )
    2260                 :            :                 {
    2261                 :          0 :                     bQuickFormat = sal_False;
    2262                 :          0 :                     break;
    2263                 :            :                 }
    2264                 :            :             }
    2265                 :            :         }
    2266                 :            :     }
    2267                 :            : 
    2268         [ -  + ]:         92 :     if ( bQuickFormat )
    2269         [ #  # ]:          0 :         RecalcTextPortion( nPara, nInvalidStart, nInvalidDiff );
    2270                 :            :     else
    2271         [ +  - ]:         92 :         CreateTextPortions( nPara, nInvalidStart );
    2272                 :            : 
    2273                 :            :     // ---------------------------------------------------------------
    2274                 :            :     // Zeile mit InvalidPos suchen, eine Zeile davor beginnen...
    2275                 :            :     // Zeilen flaggen => nicht removen !
    2276                 :            :     // ---------------------------------------------------------------
    2277                 :            : 
    2278                 :         92 :     sal_uInt16 nLine = pTEParaPortion->GetLines().size()-1;
    2279         [ +  + ]:        144 :     for ( sal_uInt16 nL = 0; nL <= nLine; nL++ )
    2280                 :            :     {
    2281                 :         92 :         TextLine* pLine = pTEParaPortion->GetLines()[ nL ];
    2282         [ +  + ]:         92 :         if ( pLine->GetEnd() > nInvalidStart )
    2283                 :            :         {
    2284                 :         40 :             nLine = nL;
    2285                 :         40 :             break;
    2286                 :            :         }
    2287                 :         52 :         pLine->SetValid();
    2288                 :            :     }
    2289                 :            :     // Eine Zeile davor beginnen...
    2290                 :            :     // Wenn ganz hinten getippt wird, kann sich die Zeile davor nicht aendern.
    2291 [ -  + ][ #  # ]:         92 :     if ( nLine && ( !pTEParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->GetText().Len() ) || ( nInvalidDiff <= 0 ) ) )
         [ #  # ][ #  # ]
                 [ -  + ]
    2292                 :          0 :         nLine--;
    2293                 :            : 
    2294                 :         92 :     TextLine* pLine = pTEParaPortion->GetLines()[ nLine ];
    2295                 :            : 
    2296                 :            :     // ---------------------------------------------------------------
    2297                 :            :     // Ab hier alle Zeilen durchformatieren...
    2298                 :            :     // ---------------------------------------------------------------
    2299                 :         92 :     size_t nDelFromLine = std::numeric_limits<size_t>::max();
    2300                 :         92 :     sal_Bool bLineBreak = sal_False;
    2301                 :            : 
    2302                 :         92 :     sal_uInt16 nIndex = pLine->GetStart();
    2303                 :         92 :     TextLine aSaveLine( *pLine );
    2304                 :            : 
    2305         [ +  - ]:         92 :     Font aFont;
    2306                 :            : 
    2307                 :         92 :     sal_Bool bCalcPortion = sal_True;
    2308                 :            : 
    2309         [ +  + ]:        184 :     while ( nIndex < pNode->GetText().Len() )
    2310                 :            :     {
    2311                 :         92 :         sal_Bool bEOL = sal_False;
    2312                 :         92 :         sal_uInt16 nPortionStart = 0;
    2313                 :         92 :         sal_uInt16 nPortionEnd = 0;
    2314                 :            : 
    2315                 :         92 :         sal_uInt16 nTmpPos = nIndex;
    2316                 :         92 :         sal_uInt16 nTmpPortion = pLine->GetStartPortion();
    2317                 :         92 :         long nTmpWidth = mpDoc->GetLeftMargin();
    2318                 :            : //      long nXWidth = mnMaxTextWidth ? ( mnMaxTextWidth - mpDoc->GetLeftMargin() ) : 0x7FFFFFFF;
    2319                 :            :         // Margin nicht abziehen, ist schon in TmpWidth enthalten.
    2320         [ +  + ]:         92 :         long nXWidth = mnMaxTextWidth ? mnMaxTextWidth : 0x7FFFFFFF;
    2321         [ -  + ]:         92 :         if ( nXWidth < nTmpWidth )
    2322                 :          0 :             nXWidth = nTmpWidth;
    2323                 :            : 
    2324                 :            :         // Portion suchen, die nicht mehr in Zeile passt....
    2325                 :         92 :         TETextPortion* pPortion = 0;
    2326                 :         92 :         sal_Bool bBrokenLine = sal_False;
    2327                 :         92 :         bLineBreak = sal_False;
    2328                 :            : 
    2329 [ +  - ][ +  - ]:        184 :         while ( ( nTmpWidth <= nXWidth ) && !bEOL && ( nTmpPortion < pTEParaPortion->GetTextPortions().size() ) )
         [ +  + ][ +  + ]
    2330                 :            :         {
    2331                 :         92 :             nPortionStart = nTmpPos;
    2332                 :         92 :             pPortion = pTEParaPortion->GetTextPortions()[ nTmpPortion ];
    2333                 :            :             DBG_ASSERT( pPortion->GetLen(), "Leere Portion in CreateLines ?!" );
    2334         [ -  + ]:         92 :             if ( pNode->GetText().GetChar( nTmpPos ) == '\t' )
    2335                 :            :             {
    2336                 :          0 :                 long nCurPos = nTmpWidth-mpDoc->GetLeftMargin();
    2337                 :          0 :                 nTmpWidth = ((nCurPos/mnDefTab)+1)*mnDefTab+mpDoc->GetLeftMargin();
    2338                 :          0 :                 pPortion->GetWidth() = nTmpWidth - nCurPos - mpDoc->GetLeftMargin();
    2339                 :            :                 // Wenn dies das erste Token in der Zeile ist, und
    2340                 :            :                 // nTmpWidth > aPaperSize.Width, habe ich eine Endlos-Schleife!
    2341 [ #  # ][ #  # ]:          0 :                 if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) )
                 [ #  # ]
    2342                 :            :                 {
    2343                 :            :                     // Aber was jetzt ? Tab passend machen!
    2344                 :          0 :                     pPortion->GetWidth() = nXWidth-1;
    2345                 :          0 :                     nTmpWidth = pPortion->GetWidth();
    2346                 :          0 :                     bEOL = sal_True;
    2347                 :          0 :                     bBrokenLine = sal_True;
    2348                 :            :                 }
    2349                 :          0 :                 pPortion->GetKind() = PORTIONKIND_TAB;
    2350                 :            :             }
    2351                 :            :             else
    2352                 :            :             {
    2353                 :            : 
    2354 [ -  + ][ #  # ]:         92 :                 if ( bCalcPortion || !pPortion->HasValidSize() )
                 [ +  - ]
    2355         [ +  - ]:         92 :                     pPortion->GetWidth() = (long)CalcTextWidth( nPara, nTmpPos, pPortion->GetLen() );
    2356                 :         92 :                 nTmpWidth += pPortion->GetWidth();
    2357                 :            : 
    2358         [ +  - ]:         92 :                 pPortion->GetRightToLeft() = ImpGetRightToLeft( nPara, nTmpPos+1 );
    2359                 :         92 :                 pPortion->GetKind() = PORTIONKIND_TEXT;
    2360                 :            :             }
    2361                 :            : 
    2362                 :         92 :             nTmpPos = nTmpPos + pPortion->GetLen();
    2363                 :         92 :             nPortionEnd = nTmpPos;
    2364                 :         92 :             nTmpPortion++;
    2365                 :            :         }
    2366                 :            : 
    2367                 :            :         // das war evtl. eine Portion zu weit:
    2368                 :         92 :         sal_Bool bFixedEnd = sal_False;
    2369         [ -  + ]:         92 :         if ( nTmpWidth > nXWidth )
    2370                 :            :         {
    2371                 :          0 :             nPortionEnd = nTmpPos;
    2372                 :          0 :             nTmpPos = nTmpPos - pPortion->GetLen();
    2373                 :          0 :             nPortionStart = nTmpPos;
    2374                 :          0 :             nTmpPortion--;
    2375                 :          0 :             bEOL = sal_False;
    2376                 :            : 
    2377                 :          0 :             nTmpWidth -= pPortion->GetWidth();
    2378         [ #  # ]:          0 :             if ( pPortion->GetKind() == PORTIONKIND_TAB )
    2379                 :            :             {
    2380                 :          0 :                 bEOL = sal_True;
    2381                 :          0 :                 bFixedEnd = sal_True;
    2382                 :            :             }
    2383                 :            :         }
    2384                 :            :         else
    2385                 :            :         {
    2386                 :         92 :             bEOL = sal_True;
    2387                 :         92 :             pLine->SetEnd( nPortionEnd );
    2388                 :            :             OSL_ENSURE(pTEParaPortion->GetTextPortions().size(),
    2389                 :            :                     "No TextPortions?");
    2390                 :         92 :             pLine->SetEndPortion( (sal_uInt16)pTEParaPortion->GetTextPortions().size() - 1 );
    2391                 :            :         }
    2392                 :            : 
    2393         [ -  + ]:         92 :         if ( bFixedEnd )
    2394                 :            :         {
    2395                 :          0 :             pLine->SetEnd( nPortionStart );
    2396                 :          0 :             pLine->SetEndPortion( nTmpPortion-1 );
    2397                 :            :         }
    2398 [ +  - ][ -  + ]:         92 :         else if ( bLineBreak || bBrokenLine )
    2399                 :            :         {
    2400                 :          0 :             pLine->SetEnd( nPortionStart+1 );
    2401                 :          0 :             pLine->SetEndPortion( nTmpPortion-1 );
    2402                 :            :         }
    2403         [ -  + ]:         92 :         else if ( !bEOL )
    2404                 :            :         {
    2405                 :            :             DBG_ASSERT( (nPortionEnd-nPortionStart) == pPortion->GetLen(), "Doch eine andere Portion?!" );
    2406                 :          0 :             long nRemainingWidth = mnMaxTextWidth - nTmpWidth;
    2407         [ #  # ]:          0 :             ImpBreakLine( nPara, pLine, pPortion, nPortionStart, nRemainingWidth );
    2408                 :            :         }
    2409                 :            : 
    2410 [ +  - ][ +  + ]:         92 :         if ( ( ImpGetAlign() == TXTALIGN_CENTER ) || ( ImpGetAlign() == TXTALIGN_RIGHT ) )
         [ +  - ][ -  + ]
                 [ +  + ]
    2411                 :            :         {
    2412                 :            :             // Ausrichten...
    2413                 :         32 :             long nTextWidth = 0;
    2414         [ +  + ]:         64 :             for ( sal_uInt16 nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ )
    2415                 :            :             {
    2416                 :         32 :                 TETextPortion* pTextPortion = pTEParaPortion->GetTextPortions()[ nTP ];
    2417                 :         32 :                 nTextWidth += pTextPortion->GetWidth();
    2418                 :            :             }
    2419                 :         32 :             long nSpace = mnMaxTextWidth - nTextWidth;
    2420         [ +  + ]:         32 :             if ( nSpace > 0 )
    2421                 :            :             {
    2422 [ +  - ][ +  - ]:          6 :                 if ( ImpGetAlign() == TXTALIGN_CENTER )
    2423                 :          6 :                     pLine->SetStartX( (sal_uInt16)(nSpace / 2) );
    2424                 :            :                 else    // TXTALIGN_RIGHT
    2425                 :          0 :                     pLine->SetStartX( (sal_uInt16)nSpace );
    2426                 :            :             }
    2427                 :            :         }
    2428                 :            :         else
    2429                 :            :         {
    2430                 :         60 :             pLine->SetStartX( mpDoc->GetLeftMargin() );
    2431                 :            :         }
    2432                 :            : 
    2433                 :            :         // -----------------------------------------------------------------
    2434                 :            :         // pruefen, ob die Zeile neu ausgegeben werden muss...
    2435                 :            :         // -----------------------------------------------------------------
    2436                 :         92 :         pLine->SetInvalid();
    2437                 :            : 
    2438         [ -  + ]:         92 :         if ( pTEParaPortion->IsSimpleInvalid() )
    2439                 :            :         {
    2440                 :            :             // Aenderung durch einfache Textaenderung...
    2441                 :            :             // Formatierung nicht abbrechen, da Portions evtl. wieder
    2442                 :            :             // gesplittet werden muessen!
    2443                 :            :             // Wenn irgendwann mal abbrechbar, dann fogende Zeilen Validieren!
    2444                 :            :             // Aber ggf. als Valid markieren, damit weniger Ausgabe...
    2445         [ #  # ]:          0 :             if ( pLine->GetEnd() < nInvalidStart )
    2446                 :            :             {
    2447         [ #  # ]:          0 :                 if ( *pLine == aSaveLine )
    2448                 :            :                 {
    2449                 :          0 :                     pLine->SetValid();
    2450                 :            :                 }
    2451                 :            :             }
    2452                 :            :             else
    2453                 :            :             {
    2454                 :          0 :                 sal_uInt16 nStart = pLine->GetStart();
    2455                 :          0 :                 sal_uInt16 nEnd = pLine->GetEnd();
    2456                 :            : 
    2457         [ #  # ]:          0 :                 if ( nStart > nInvalidEnd )
    2458                 :            :                 {
    2459   [ #  #  #  # ]:          0 :                     if ( ( ( nStart-nInvalidDiff ) == aSaveLine.GetStart() ) &&
                 [ #  # ]
    2460                 :          0 :                             ( ( nEnd-nInvalidDiff ) == aSaveLine.GetEnd() ) )
    2461                 :            :                     {
    2462                 :          0 :                         pLine->SetValid();
    2463 [ #  # ][ #  # ]:          0 :                         if ( bCalcPortion && bQuickFormat )
    2464                 :            :                         {
    2465                 :          0 :                             bCalcPortion = sal_False;
    2466         [ #  # ]:          0 :                             pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine );
    2467                 :          0 :                             break;
    2468                 :            :                         }
    2469                 :            :                     }
    2470                 :            :                 }
    2471 [ #  # ][ #  # ]:          0 :                 else if ( bQuickFormat && ( nEnd > nInvalidEnd) )
    2472                 :            :                 {
    2473                 :            :                     // Wenn die ungueltige Zeile so endet, dass die naechste an
    2474                 :            :                     // der 'gleichen' Textstelle wie vorher beginnt, also nicht
    2475                 :            :                     // anders umgebrochen wird, brauche ich dort auch nicht die
    2476                 :            :                     // textbreiten neu bestimmen:
    2477         [ #  # ]:          0 :                     if ( nEnd == ( aSaveLine.GetEnd() + nInvalidDiff ) )
    2478                 :            :                     {
    2479                 :          0 :                         bCalcPortion = sal_False;
    2480         [ #  # ]:          0 :                         pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine );
    2481                 :          0 :                         break;
    2482                 :            :                     }
    2483                 :            :                 }
    2484                 :            :             }
    2485                 :            :         }
    2486                 :            : 
    2487                 :         92 :         nIndex = pLine->GetEnd();   // naechste Zeile Start = letzte Zeile Ende
    2488                 :            :                                     // weil nEnd hinter das letzte Zeichen zeigt!
    2489                 :            : 
    2490                 :         92 :         sal_uInt16 nEndPortion = pLine->GetEndPortion();
    2491                 :            : 
    2492                 :            :         // Naechste Zeile oder ggf. neue Zeile....
    2493                 :         92 :         pLine = 0;
    2494         [ -  + ]:         92 :         if ( nLine < pTEParaPortion->GetLines().size()-1 )
    2495                 :          0 :             pLine = pTEParaPortion->GetLines()[ ++nLine ];
    2496 [ -  + ][ #  # ]:         92 :         if ( pLine && ( nIndex >= pNode->GetText().Len() ) )
                 [ -  + ]
    2497                 :            :         {
    2498                 :          0 :             nDelFromLine = nLine;
    2499                 :          0 :             break;
    2500                 :            :         }
    2501 [ +  - ][ -  + ]:         92 :         if ( !pLine && ( nIndex < pNode->GetText().Len() )  )
                 [ -  + ]
    2502                 :            :         {
    2503         [ #  # ]:          0 :             pLine = new TextLine;
    2504 [ #  # ][ #  # ]:          0 :             pTEParaPortion->GetLines().insert( pTEParaPortion->GetLines().begin() + ++nLine, pLine );
    2505                 :            :         }
    2506         [ -  + ]:         92 :         if ( pLine )
    2507                 :            :         {
    2508                 :          0 :             aSaveLine = *pLine;
    2509                 :          0 :             pLine->SetStart( nIndex );
    2510                 :          0 :             pLine->SetEnd( nIndex );
    2511                 :          0 :             pLine->SetStartPortion( nEndPortion+1 );
    2512                 :          0 :             pLine->SetEndPortion( nEndPortion+1 );
    2513                 :            :         }
    2514                 :            :     }   // while ( Index < Len )
    2515                 :            : 
    2516         [ -  + ]:         92 :     if (nDelFromLine != std::numeric_limits<size_t>::max())
    2517                 :            :     {
    2518 [ #  # ][ #  # ]:          0 :         for( TextLines::iterator it = pTEParaPortion->GetLines().begin() + nDelFromLine;
                 [ #  # ]
    2519                 :          0 :              it != pTEParaPortion->GetLines().end(); ++it )
    2520                 :            :         {
    2521                 :          0 :             delete *it;
    2522                 :            :         }
    2523                 :          0 :         pTEParaPortion->GetLines().erase( pTEParaPortion->GetLines().begin() + nDelFromLine,
    2524   [ #  #  #  # ]:          0 :                                           pTEParaPortion->GetLines().end() );
    2525                 :            :     }
    2526                 :            : 
    2527                 :            :     DBG_ASSERT( pTEParaPortion->GetLines().size(), "Keine Zeile nach CreateLines!" );
    2528                 :            : 
    2529         [ -  + ]:         92 :     if ( bLineBreak == sal_True )
    2530         [ #  # ]:          0 :         CreateAndInsertEmptyLine( nPara );
    2531                 :            : 
    2532                 :         92 :     pTEParaPortion->SetValid();
    2533                 :            : 
    2534         [ +  - ]:        596 :     return nOldLineCount != pTEParaPortion->GetLines().size();
    2535                 :            : }
    2536                 :            : 
    2537                 :          0 : String TextEngine::GetWord( const TextPaM& rCursorPos, TextPaM* pStartOfWord )
    2538                 :            : {
    2539                 :          0 :     String aWord;
    2540         [ #  # ]:          0 :     if ( rCursorPos.GetPara() < mpDoc->GetNodes().Count() )
    2541                 :            :     {
    2542         [ #  # ]:          0 :         TextSelection aSel( rCursorPos );
    2543         [ #  # ]:          0 :         TextNode* pNode = mpDoc->GetNodes().GetObject(  rCursorPos.GetPara() );
    2544         [ #  # ]:          0 :         uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator();
    2545 [ #  # ][ #  # ]:          0 :         i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rCursorPos.GetIndex(), GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
         [ #  # ][ #  # ]
    2546                 :          0 :         aSel.GetStart().GetIndex() = (sal_uInt16)aBoundary.startPos;
    2547                 :          0 :         aSel.GetEnd().GetIndex() = (sal_uInt16)aBoundary.endPos;
    2548 [ #  # ][ #  # ]:          0 :         aWord = pNode->GetText().Copy( aSel.GetStart().GetIndex(), aSel.GetEnd().GetIndex() - aSel.GetStart().GetIndex() );
                 [ #  # ]
    2549         [ #  # ]:          0 :         if ( pStartOfWord )
    2550                 :          0 :             *pStartOfWord = aSel.GetStart();
    2551                 :            :     }
    2552                 :          0 :     return aWord;
    2553                 :            : }
    2554                 :            : 
    2555                 :          0 : sal_Bool TextEngine::Read( SvStream& rInput, const TextSelection* pSel )
    2556                 :            : {
    2557                 :          0 :     sal_Bool bUpdate = GetUpdateMode();
    2558         [ #  # ]:          0 :     SetUpdateMode( sal_False );
    2559                 :            : 
    2560         [ #  # ]:          0 :     UndoActionStart();
    2561         [ #  # ]:          0 :     TextSelection aSel;
    2562         [ #  # ]:          0 :     if ( pSel )
    2563                 :          0 :         aSel = *pSel;
    2564                 :            :     else
    2565                 :            :     {
    2566                 :          0 :         sal_uLong nParas = mpDoc->GetNodes().Count();
    2567         [ #  # ]:          0 :         TextNode* pNode = mpDoc->GetNodes().GetObject( nParas - 1 );
    2568         [ #  # ]:          0 :         aSel = TextPaM( nParas-1 , pNode->GetText().Len() );
    2569                 :            :     }
    2570                 :            : 
    2571         [ #  # ]:          0 :     if ( aSel.HasRange() )
    2572 [ #  # ][ #  # ]:          0 :         aSel = ImpDeleteText( aSel );
    2573                 :            : 
    2574                 :          0 :     rtl::OString aLine;
    2575         [ #  # ]:          0 :     sal_Bool bDone = rInput.ReadLine( aLine );
    2576         [ #  # ]:          0 :     rtl::OUString aTmpStr(rtl::OStringToOUString(aLine, rInput.GetStreamCharSet())), aStr;
    2577         [ #  # ]:          0 :     while ( bDone )
    2578                 :            :     {
    2579 [ #  # ][ #  # ]:          0 :         aSel = ImpInsertText( aSel, aTmpStr );
         [ #  # ][ #  # ]
    2580         [ #  # ]:          0 :         bDone = rInput.ReadLine( aLine );
    2581         [ #  # ]:          0 :         aTmpStr = rtl::OStringToOUString(aLine, rInput.GetStreamCharSet());
    2582         [ #  # ]:          0 :         if ( bDone )
    2583 [ #  # ][ #  # ]:          0 :             aSel = ImpInsertParaBreak( aSel.GetEnd() );
    2584                 :            :     }
    2585                 :            : 
    2586         [ #  # ]:          0 :     UndoActionEnd();
    2587                 :            : 
    2588         [ #  # ]:          0 :     TextSelection aNewSel( aSel.GetEnd(), aSel.GetEnd() );
    2589                 :            : 
    2590                 :            :     // Damit bei FormatAndUpdate nicht auf die ungueltige Selektion zugegriffen wird.
    2591 [ #  # ][ #  # ]:          0 :     if ( GetActiveView() )
    2592 [ #  # ][ #  # ]:          0 :         GetActiveView()->ImpSetSelection( aNewSel );
    2593                 :            : 
    2594         [ #  # ]:          0 :     SetUpdateMode( bUpdate );
    2595 [ #  # ][ #  # ]:          0 :     FormatAndUpdate( GetActiveView() );
    2596                 :            : 
    2597                 :          0 :     return rInput.GetError() ? sal_False : sal_True;
    2598                 :            : }
    2599                 :            : 
    2600                 :          0 : sal_Bool TextEngine::Write( SvStream& rOutput, const TextSelection* pSel, sal_Bool bHTML )
    2601                 :            : {
    2602         [ #  # ]:          0 :     TextSelection aSel;
    2603         [ #  # ]:          0 :     if ( pSel )
    2604                 :          0 :         aSel = *pSel;
    2605                 :            :     else
    2606                 :            :     {
    2607                 :          0 :         sal_uLong nParas = mpDoc->GetNodes().Count();
    2608         [ #  # ]:          0 :         TextNode* pNode = mpDoc->GetNodes().GetObject( nParas - 1 );
    2609                 :          0 :         aSel.GetStart() = TextPaM( 0, 0 );
    2610                 :          0 :         aSel.GetEnd() = TextPaM( nParas-1, pNode->GetText().Len() );
    2611                 :            :     }
    2612                 :            : 
    2613         [ #  # ]:          0 :     if ( bHTML )
    2614                 :            :     {
    2615         [ #  # ]:          0 :         rOutput.WriteLine( "<HTML>" );
    2616         [ #  # ]:          0 :         rOutput.WriteLine( "<BODY>" );
    2617                 :            :     }
    2618                 :            : 
    2619         [ #  # ]:          0 :     for ( sal_uLong nPara = aSel.GetStart().GetPara(); nPara <= aSel.GetEnd().GetPara(); nPara++  )
    2620                 :            :     {
    2621         [ #  # ]:          0 :         TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
    2622                 :            : 
    2623                 :          0 :         sal_uInt16 nStartPos = 0;
    2624                 :          0 :         sal_uInt16 nEndPos = pNode->GetText().Len();
    2625         [ #  # ]:          0 :         if ( nPara == aSel.GetStart().GetPara() )
    2626                 :          0 :             nStartPos = aSel.GetStart().GetIndex();
    2627         [ #  # ]:          0 :         if ( nPara == aSel.GetEnd().GetPara() )
    2628                 :          0 :             nEndPos = aSel.GetEnd().GetIndex();
    2629                 :            : 
    2630         [ #  # ]:          0 :         String aText;
    2631         [ #  # ]:          0 :         if ( !bHTML )
    2632                 :            :         {
    2633 [ #  # ][ #  # ]:          0 :             aText = pNode->GetText().Copy( nStartPos, nEndPos-nStartPos );
                 [ #  # ]
    2634                 :            :         }
    2635                 :            :         else
    2636                 :            :         {
    2637         [ #  # ]:          0 :             aText.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "<P STYLE=\"margin-bottom: 0cm\">" ) );
    2638                 :            : 
    2639         [ #  # ]:          0 :             if ( nStartPos == nEndPos )
    2640                 :            :             {
    2641                 :            :                 // Leerzeilen werden von Writer wegoptimiert
    2642         [ #  # ]:          0 :                 aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "<BR>" ) );
    2643                 :            :             }
    2644                 :            :             else
    2645                 :            :             {
    2646                 :          0 :                 sal_uInt16 nTmpStart = nStartPos;
    2647                 :          0 :                 sal_uInt16 nTmpEnd = nEndPos;
    2648         [ #  # ]:          0 :                 do
    2649                 :            :                 {
    2650         [ #  # ]:          0 :                     TextCharAttrib* pAttr = pNode->GetCharAttribs().FindNextAttrib( TEXTATTR_HYPERLINK, nTmpStart, nEndPos );
    2651         [ #  # ]:          0 :                     nTmpEnd = pAttr ? pAttr->GetStart() : nEndPos;
    2652                 :            : 
    2653                 :            :                     // Text vor dem Attribut
    2654 [ #  # ][ #  # ]:          0 :                     aText += pNode->GetText().Copy( nTmpStart, nTmpEnd-nTmpStart );
                 [ #  # ]
    2655                 :            : 
    2656         [ #  # ]:          0 :                     if ( pAttr )
    2657                 :            :                     {
    2658                 :          0 :                         nTmpEnd = Min( pAttr->GetEnd(), nEndPos );
    2659                 :            : 
    2660                 :            :                         // z.B. <A HREF="http://www.mopo.de/">Morgenpost</A>
    2661         [ #  # ]:          0 :                         aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "<A HREF=\"" ) );
    2662         [ #  # ]:          0 :                         aText += ((const TextAttribHyperLink&) pAttr->GetAttr() ).GetURL();
    2663         [ #  # ]:          0 :                         aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "\">" ) );
    2664                 :          0 :                         nTmpStart = pAttr->GetStart();
    2665 [ #  # ][ #  # ]:          0 :                         aText += pNode->GetText().Copy( nTmpStart, nTmpEnd-nTmpStart );
                 [ #  # ]
    2666         [ #  # ]:          0 :                         aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "</A>" ) );
    2667                 :            : 
    2668                 :          0 :                         nTmpStart = pAttr->GetEnd();
    2669                 :            :                     }
    2670                 :            :                 } while ( nTmpEnd < nEndPos );
    2671                 :            :             }
    2672                 :            : 
    2673         [ #  # ]:          0 :             aText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "</P>" ) );
    2674                 :            :         }
    2675                 :            :         rOutput.WriteLine(rtl::OUStringToOString(aText,
    2676 [ #  # ][ #  # ]:          0 :             rOutput.GetStreamCharSet()));
                 [ #  # ]
    2677         [ #  # ]:          0 :     }
    2678                 :            : 
    2679         [ #  # ]:          0 :     if ( bHTML )
    2680                 :            :     {
    2681         [ #  # ]:          0 :         rOutput.WriteLine( "</BODY>" );
    2682         [ #  # ]:          0 :         rOutput.WriteLine( "</HTML>" );
    2683                 :            :     }
    2684                 :            : 
    2685                 :          0 :     return rOutput.GetError() ? sal_False : sal_True;
    2686                 :            : }
    2687                 :            : 
    2688                 :          0 : void TextEngine::RemoveAttribs( sal_uLong nPara, sal_Bool bIdleFormatAndUpdate )
    2689                 :            : {
    2690         [ #  # ]:          0 :     if ( nPara < mpDoc->GetNodes().Count() )
    2691                 :            :     {
    2692                 :          0 :         TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
    2693         [ #  # ]:          0 :         if ( pNode->GetCharAttribs().Count() )
    2694                 :            :         {
    2695                 :          0 :             pNode->GetCharAttribs().Clear( sal_True );
    2696                 :            : 
    2697                 :          0 :             TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
    2698                 :          0 :             pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() );
    2699                 :            : 
    2700                 :          0 :             mbFormatted = sal_False;
    2701                 :            : 
    2702         [ #  # ]:          0 :             if ( bIdleFormatAndUpdate )
    2703                 :          0 :                 IdleFormatAndUpdate( NULL, 0xFFFF );
    2704                 :            :             else
    2705                 :          0 :                 FormatAndUpdate( NULL );
    2706                 :            :         }
    2707                 :            :     }
    2708                 :          0 : }
    2709                 :          0 : void TextEngine::RemoveAttribs( sal_uLong nPara, sal_uInt16 nWhich, sal_Bool bIdleFormatAndUpdate )
    2710                 :            : {
    2711         [ #  # ]:          0 :     if ( nPara < mpDoc->GetNodes().Count() )
    2712                 :            :     {
    2713                 :          0 :         TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
    2714         [ #  # ]:          0 :         if ( pNode->GetCharAttribs().Count() )
    2715                 :            :         {
    2716                 :          0 :             TextCharAttribList& rAttribs = pNode->GetCharAttribs();
    2717                 :          0 :             sal_uInt16 nAttrCount = rAttribs.Count();
    2718         [ #  # ]:          0 :             for(sal_uInt16 nAttr = nAttrCount; nAttr; --nAttr)
    2719                 :            :             {
    2720         [ #  # ]:          0 :                 if(rAttribs.GetAttrib( nAttr - 1 )->Which() == nWhich)
    2721                 :          0 :                     rAttribs.RemoveAttrib( nAttr -1 );
    2722                 :            :             }
    2723                 :          0 :             TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
    2724                 :          0 :             pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() );
    2725                 :          0 :             mbFormatted = sal_False;
    2726         [ #  # ]:          0 :             if(bIdleFormatAndUpdate)
    2727                 :          0 :                 IdleFormatAndUpdate( NULL, 0xFFFF );
    2728                 :            :             else
    2729                 :          0 :                 FormatAndUpdate( NULL );
    2730                 :            :         }
    2731                 :            :     }
    2732                 :          0 : }
    2733                 :          0 : void TextEngine::RemoveAttrib( sal_uLong nPara, const TextCharAttrib& rAttrib )
    2734                 :            : {
    2735         [ #  # ]:          0 :     if ( nPara < mpDoc->GetNodes().Count() )
    2736                 :            :     {
    2737                 :          0 :         TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
    2738         [ #  # ]:          0 :         if ( pNode->GetCharAttribs().Count() )
    2739                 :            :         {
    2740                 :          0 :             TextCharAttribList& rAttribs = pNode->GetCharAttribs();
    2741                 :          0 :             sal_uInt16 nAttrCount = rAttribs.Count();
    2742         [ #  # ]:          0 :             for(sal_uInt16 nAttr = nAttrCount; nAttr; --nAttr)
    2743                 :            :             {
    2744         [ #  # ]:          0 :                 if(rAttribs.GetAttrib( nAttr - 1 ) == &rAttrib)
    2745                 :            :                 {
    2746                 :          0 :                     rAttribs.RemoveAttrib( nAttr -1 );
    2747                 :          0 :                     break;
    2748                 :            :                 }
    2749                 :            :             }
    2750                 :          0 :             TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
    2751                 :          0 :             pTEParaPortion->MarkSelectionInvalid( 0, pNode->GetText().Len() );
    2752                 :          0 :             mbFormatted = sal_False;
    2753                 :          0 :             FormatAndUpdate( NULL );
    2754                 :            :         }
    2755                 :            :     }
    2756                 :          0 : }
    2757                 :            : 
    2758                 :          0 : void TextEngine::SetAttrib( const TextAttrib& rAttr, sal_uLong nPara, sal_uInt16 nStart, sal_uInt16 nEnd, sal_Bool bIdleFormatAndUpdate )
    2759                 :            : {
    2760                 :            :     // Es wird hier erstmal nicht geprueft, ob sich Attribute ueberlappen!
    2761                 :            :     // Diese Methode ist erstmal nur fuer einen Editor, der fuer eine Zeile
    2762                 :            :     // _schnell_ das Syntax-Highlight einstellen will.
    2763                 :            : 
    2764                 :            :     // Da die TextEngine z.Zt fuer Editoren gedacht ist gibt es auch kein
    2765                 :            :     // Undo fuer Attribute!
    2766                 :            : 
    2767         [ #  # ]:          0 :     if ( nPara < mpDoc->GetNodes().Count() )
    2768                 :            :     {
    2769                 :          0 :         TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
    2770                 :          0 :         TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara );
    2771                 :            : 
    2772                 :          0 :         sal_uInt16 nMax = pNode->GetText().Len();
    2773         [ #  # ]:          0 :         if ( nStart > nMax )
    2774                 :          0 :             nStart = nMax;
    2775         [ #  # ]:          0 :         if ( nEnd > nMax )
    2776                 :          0 :             nEnd = nMax;
    2777                 :            : 
    2778         [ #  # ]:          0 :         pNode->GetCharAttribs().InsertAttrib( new TextCharAttrib( rAttr, nStart, nEnd ) );
    2779                 :          0 :         pTEParaPortion->MarkSelectionInvalid( nStart, nEnd );
    2780                 :            : 
    2781                 :          0 :         mbFormatted = sal_False;
    2782         [ #  # ]:          0 :         if ( bIdleFormatAndUpdate )
    2783                 :          0 :             IdleFormatAndUpdate( NULL, 0xFFFF );
    2784                 :            :         else
    2785                 :          0 :             FormatAndUpdate( NULL );
    2786                 :            :     }
    2787                 :          0 : }
    2788                 :            : 
    2789                 :        272 : void TextEngine::SetTextAlign( TxtAlign eAlign )
    2790                 :            : {
    2791         [ +  + ]:        272 :     if ( eAlign != meAlign )
    2792                 :            :     {
    2793                 :         20 :         meAlign = eAlign;
    2794                 :         20 :         FormatFullDoc();
    2795                 :         20 :         UpdateViews();
    2796                 :            :     }
    2797                 :        272 : }
    2798                 :            : 
    2799                 :            : 
    2800                 :        218 : void TextEngine::ValidateSelection( TextSelection& rSel ) const
    2801                 :            : {
    2802                 :        218 :     ValidatePaM( rSel.GetStart() );
    2803                 :        218 :     ValidatePaM( rSel.GetEnd() );
    2804                 :        218 : }
    2805                 :            : 
    2806                 :        436 : void TextEngine::ValidatePaM( TextPaM& rPaM ) const
    2807                 :            : {
    2808                 :        436 :     sal_uLong nMaxPara = mpDoc->GetNodes().Count() - 1;
    2809         [ -  + ]:        436 :     if ( rPaM.GetPara() > nMaxPara )
    2810                 :            :     {
    2811                 :          0 :         rPaM.GetPara() = nMaxPara;
    2812                 :          0 :         rPaM.GetIndex() = 0xFFFF;
    2813                 :            :     }
    2814                 :            : 
    2815                 :        436 :     sal_uInt16 nMaxIndex = GetTextLen( rPaM.GetPara() );
    2816         [ -  + ]:        436 :     if ( rPaM.GetIndex() > nMaxIndex )
    2817                 :          0 :         rPaM.GetIndex() = nMaxIndex;
    2818                 :        436 : }
    2819                 :            : 
    2820                 :            : 
    2821                 :            : // Status & Selektionsanpassung
    2822                 :            : 
    2823                 :        218 : void TextEngine::ImpParagraphInserted( sal_uLong nPara )
    2824                 :            : {
    2825                 :            :     // Die aktive View braucht nicht angepasst werden, aber bei allen
    2826                 :            :     // passiven muss die Selektion angepasst werden:
    2827         [ -  + ]:        218 :     if ( mpViews->size() > 1 )
    2828                 :            :     {
    2829         [ #  # ]:          0 :         for ( sal_uInt16 nView = mpViews->size(); nView; )
    2830                 :            :         {
    2831                 :          0 :             TextView* pView = (*mpViews)[ --nView ];
    2832         [ #  # ]:          0 :             if ( pView != GetActiveView() )
    2833                 :            :             {
    2834         [ #  # ]:          0 :                 for ( int n = 0; n <= 1; n++ )
    2835                 :            :                 {
    2836         [ #  # ]:          0 :                     TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd();
    2837         [ #  # ]:          0 :                     if ( rPaM.GetPara() >= nPara )
    2838                 :          0 :                         rPaM.GetPara()++;
    2839                 :            :                 }
    2840                 :            :             }
    2841                 :            :         }
    2842                 :            :     }
    2843         [ +  - ]:        218 :     Broadcast( TextHint( TEXT_HINT_PARAINSERTED, nPara ) );
    2844                 :        218 : }
    2845                 :            : 
    2846                 :        218 : void TextEngine::ImpParagraphRemoved( sal_uLong nPara )
    2847                 :            : {
    2848         [ -  + ]:        218 :     if ( mpViews->size() > 1 )
    2849                 :            :     {
    2850         [ #  # ]:          0 :         for ( sal_uInt16 nView = mpViews->size(); nView; )
    2851                 :            :         {
    2852                 :          0 :             TextView* pView = (*mpViews)[ --nView ];
    2853         [ #  # ]:          0 :             if ( pView != GetActiveView() )
    2854                 :            :             {
    2855                 :          0 :                 sal_uLong nParas = mpDoc->GetNodes().Count();
    2856         [ #  # ]:          0 :                 for ( int n = 0; n <= 1; n++ )
    2857                 :            :                 {
    2858         [ #  # ]:          0 :                     TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd();
    2859         [ #  # ]:          0 :                     if ( rPaM.GetPara() > nPara )
    2860                 :          0 :                         rPaM.GetPara()--;
    2861         [ #  # ]:          0 :                     else if ( rPaM.GetPara() == nPara )
    2862                 :            :                     {
    2863                 :          0 :                         rPaM.GetIndex() = 0;
    2864         [ #  # ]:          0 :                         if ( rPaM.GetPara() >= nParas )
    2865                 :          0 :                             rPaM.GetPara()--;
    2866                 :            :                     }
    2867                 :            :                 }
    2868                 :            :             }
    2869                 :            :         }
    2870                 :            :     }
    2871         [ +  - ]:        218 :     Broadcast( TextHint( TEXT_HINT_PARAREMOVED, nPara ) );
    2872                 :        218 : }
    2873                 :            : 
    2874                 :          0 : void TextEngine::ImpCharsRemoved( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16 nChars )
    2875                 :            : {
    2876         [ #  # ]:          0 :     if ( mpViews->size() > 1 )
    2877                 :            :     {
    2878         [ #  # ]:          0 :         for ( sal_uInt16 nView = mpViews->size(); nView; )
    2879                 :            :         {
    2880                 :          0 :             TextView* pView = (*mpViews)[ --nView ];
    2881         [ #  # ]:          0 :             if ( pView != GetActiveView() )
    2882                 :            :             {
    2883                 :          0 :                 sal_uInt16 nEnd = nPos+nChars;
    2884         [ #  # ]:          0 :                 for ( int n = 0; n <= 1; n++ )
    2885                 :            :                 {
    2886         [ #  # ]:          0 :                     TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd();
    2887         [ #  # ]:          0 :                     if ( rPaM.GetPara() == nPara )
    2888                 :            :                     {
    2889         [ #  # ]:          0 :                         if ( rPaM.GetIndex() > nEnd )
    2890                 :          0 :                             rPaM.GetIndex() = rPaM.GetIndex() - nChars;
    2891         [ #  # ]:          0 :                         else if ( rPaM.GetIndex() > nPos )
    2892                 :          0 :                             rPaM.GetIndex() = nPos;
    2893                 :            :                     }
    2894                 :            :                 }
    2895                 :            :             }
    2896                 :            :         }
    2897                 :            :     }
    2898         [ #  # ]:          0 :     Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, nPara ) );
    2899                 :          0 : }
    2900                 :            : 
    2901                 :         52 : void TextEngine::ImpCharsInserted( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16 nChars )
    2902                 :            : {
    2903         [ -  + ]:         52 :     if ( mpViews->size() > 1 )
    2904                 :            :     {
    2905         [ #  # ]:          0 :         for ( sal_uInt16 nView = mpViews->size(); nView; )
    2906                 :            :         {
    2907                 :          0 :             TextView* pView = (*mpViews)[ --nView ];
    2908         [ #  # ]:          0 :             if ( pView != GetActiveView() )
    2909                 :            :             {
    2910         [ #  # ]:          0 :                 for ( int n = 0; n <= 1; n++ )
    2911                 :            :                 {
    2912         [ #  # ]:          0 :                     TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd();
    2913         [ #  # ]:          0 :                     if ( rPaM.GetPara() == nPara )
    2914                 :            :                     {
    2915         [ #  # ]:          0 :                         if ( rPaM.GetIndex() >= nPos )
    2916                 :          0 :                             rPaM.GetIndex() = rPaM.GetIndex() + nChars;
    2917                 :            :                     }
    2918                 :            :                 }
    2919                 :            :             }
    2920                 :            :         }
    2921                 :            :     }
    2922         [ +  - ]:         52 :     Broadcast( TextHint( TEXT_HINT_PARACONTENTCHANGED, nPara ) );
    2923                 :         52 : }
    2924                 :            : 
    2925                 :        596 : void TextEngine::ImpFormattingParagraph( sal_uLong nPara )
    2926                 :            : {
    2927         [ +  - ]:        596 :     Broadcast( TextHint( TEXT_HINT_FORMATPARA, nPara ) );
    2928                 :        596 : }
    2929                 :            : 
    2930                 :        300 : void TextEngine::ImpTextHeightChanged()
    2931                 :            : {
    2932         [ +  - ]:        300 :     Broadcast( TextHint( TEXT_HINT_TEXTHEIGHTCHANGED ) );
    2933                 :        300 : }
    2934                 :            : 
    2935                 :        596 : void TextEngine::ImpTextFormatted()
    2936                 :            : {
    2937         [ +  - ]:        596 :     Broadcast( TextHint( TEXT_HINT_TEXTFORMATTED ) );
    2938                 :        596 : }
    2939                 :            : 
    2940                 :          0 : void TextEngine::Draw( OutputDevice* pDev, const Point& rPos )
    2941                 :            : {
    2942                 :          0 :     ImpPaint( pDev, rPos, NULL );
    2943                 :          0 : }
    2944                 :            : 
    2945                 :         22 : void TextEngine::SetLeftMargin( sal_uInt16 n )
    2946                 :            : {
    2947                 :         22 :     mpDoc->SetLeftMargin( n );
    2948                 :         22 : }
    2949                 :            : 
    2950                 :          0 : sal_uInt16 TextEngine::GetLeftMargin() const
    2951                 :            : {
    2952                 :          0 :     return mpDoc->GetLeftMargin();
    2953                 :            : }
    2954                 :            : 
    2955                 :          0 : uno::Reference< i18n::XBreakIterator > TextEngine::GetBreakIterator()
    2956                 :            : {
    2957         [ #  # ]:          0 :     if ( !mxBreakIterator.is() )
    2958         [ #  # ]:          0 :         mxBreakIterator = vcl::unohelper::CreateBreakIterator();
    2959                 :            :     DBG_ASSERT( mxBreakIterator.is(), "Could not create BreakIterator" );
    2960                 :          0 :     return mxBreakIterator;
    2961                 :            : }
    2962                 :            : 
    2963                 :         90 : void TextEngine::SetLocale( const ::com::sun::star::lang::Locale& rLocale )
    2964                 :            : {
    2965                 :         90 :     maLocale = rLocale;
    2966         [ -  + ]:         90 :     delete mpLocaleDataWrapper;
    2967                 :         90 :     mpLocaleDataWrapper = NULL;
    2968                 :         90 : }
    2969                 :            : 
    2970                 :          0 : ::com::sun::star::lang::Locale TextEngine::GetLocale()
    2971                 :            : {
    2972         [ #  # ]:          0 :     if ( maLocale.Language.isEmpty() )
    2973                 :            :     {
    2974                 :          0 :         maLocale = Application::GetSettings().GetUILocale();
    2975                 :            :     }
    2976                 :          0 :     return maLocale;
    2977                 :            : }
    2978                 :            : 
    2979                 :          0 : LocaleDataWrapper* TextEngine::ImpGetLocaleDataWrapper()
    2980                 :            : {
    2981         [ #  # ]:          0 :     if ( !mpLocaleDataWrapper )
    2982 [ #  # ][ #  # ]:          0 :         mpLocaleDataWrapper = new LocaleDataWrapper( vcl::unohelper::GetMultiServiceFactory(), GetLocale() );
                 [ #  # ]
    2983                 :            : 
    2984                 :          0 :     return mpLocaleDataWrapper;
    2985                 :            : }
    2986                 :            : 
    2987                 :        272 : void TextEngine::SetRightToLeft( sal_Bool bR2L )
    2988                 :            : {
    2989         [ -  + ]:        272 :     if ( mbRightToLeft != bR2L )
    2990                 :            :     {
    2991                 :          0 :         mbRightToLeft = bR2L;
    2992         [ #  # ]:          0 :         meAlign = bR2L ? TXTALIGN_RIGHT : TXTALIGN_LEFT;
    2993                 :          0 :         FormatFullDoc();
    2994                 :          0 :         UpdateViews();
    2995                 :            :     }
    2996                 :        272 : }
    2997                 :            : 
    2998                 :         92 : void TextEngine::ImpInitWritingDirections( sal_uLong nPara )
    2999                 :            : {
    3000                 :         92 :     TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara );
    3001                 :         92 :     std::vector<TEWritingDirectionInfo>& rInfos = pParaPortion->GetWritingDirectionInfos();
    3002                 :         92 :     rInfos.clear();
    3003                 :            : 
    3004         [ +  - ]:         92 :     if ( pParaPortion->GetNode()->GetText().Len() )
    3005                 :            :     {
    3006         [ -  + ]:         92 :         const UBiDiLevel nBidiLevel = IsRightToLeft() ? 1 /*RTL*/ : 0 /*LTR*/;
    3007         [ +  - ]:         92 :         String aText( pParaPortion->GetNode()->GetText() );
    3008                 :            : 
    3009                 :            :         //
    3010                 :            :         // Bidi functions from icu 2.0
    3011                 :            :         //
    3012                 :         92 :         UErrorCode nError = U_ZERO_ERROR;
    3013         [ +  - ]:         92 :         UBiDi* pBidi = ubidi_openSized( aText.Len(), 0, &nError );
    3014                 :         92 :         nError = U_ZERO_ERROR;
    3015                 :            : 
    3016         [ +  - ]:         92 :         ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aText.GetBuffer()), aText.Len(), nBidiLevel, NULL, &nError ); // UChar != sal_Unicode in MinGW
    3017                 :         92 :         nError = U_ZERO_ERROR;
    3018                 :            : 
    3019         [ +  - ]:         92 :         long nCount = ubidi_countRuns( pBidi, &nError );
    3020                 :            : 
    3021                 :         92 :         int32_t nStart = 0;
    3022                 :            :         int32_t nEnd;
    3023                 :            :         UBiDiLevel nCurrDir;
    3024                 :            : 
    3025         [ +  + ]:        184 :         for ( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx )
    3026                 :            :         {
    3027         [ +  - ]:         92 :             ubidi_getLogicalRun( pBidi, nStart, &nEnd, &nCurrDir );
    3028         [ +  - ]:         92 :             rInfos.push_back( TEWritingDirectionInfo( nCurrDir, (sal_uInt16)nStart, (sal_uInt16)nEnd ) );
    3029                 :         92 :             nStart = nEnd;
    3030                 :            :         }
    3031                 :            : 
    3032 [ +  - ][ +  - ]:         92 :         ubidi_close( pBidi );
    3033                 :            :     }
    3034                 :            : 
    3035                 :            :     // No infos mean no CTL and default dir is L2R...
    3036         [ -  + ]:         92 :     if ( rInfos.empty() )
    3037         [ #  # ]:          0 :         rInfos.push_back( TEWritingDirectionInfo( 0, 0, (sal_uInt16)pParaPortion->GetNode()->GetText().Len() ) );
    3038                 :            : 
    3039                 :         92 : }
    3040                 :            : 
    3041                 :         92 : sal_uInt8 TextEngine::ImpGetRightToLeft( sal_uLong nPara, sal_uInt16 nPos, sal_uInt16* pStart, sal_uInt16* pEnd )
    3042                 :            : {
    3043                 :         92 :     sal_uInt8 nRightToLeft = 0;
    3044                 :            : 
    3045                 :         92 :     TextNode* pNode = mpDoc->GetNodes().GetObject( nPara );
    3046 [ +  - ][ +  - ]:         92 :     if ( pNode && pNode->GetText().Len() )
                 [ +  - ]
    3047                 :            :     {
    3048                 :         92 :         TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara );
    3049         [ -  + ]:         92 :         if ( pParaPortion->GetWritingDirectionInfos().empty() )
    3050                 :          0 :             ImpInitWritingDirections( nPara );
    3051                 :            : 
    3052                 :         92 :         std::vector<TEWritingDirectionInfo>& rDirInfos = pParaPortion->GetWritingDirectionInfos();
    3053 [ +  - ][ +  - ]:        184 :         for ( std::vector<TEWritingDirectionInfo>::const_iterator rDirInfosIt = rDirInfos.begin(); rDirInfosIt != rDirInfos.end(); ++rDirInfosIt )
                 [ +  - ]
    3054                 :            :         {
    3055 [ +  - ][ +  - ]:         92 :             if ( ( (*rDirInfosIt).nStartPos <= nPos ) && ( (*rDirInfosIt).nEndPos >= nPos ) )
                 [ +  - ]
    3056                 :            :                {
    3057                 :         92 :                 nRightToLeft = (*rDirInfosIt).nType;
    3058         [ -  + ]:         92 :                 if ( pStart )
    3059                 :          0 :                     *pStart = (*rDirInfosIt).nStartPos;
    3060         [ -  + ]:         92 :                 if ( pEnd )
    3061                 :          0 :                     *pEnd = (*rDirInfosIt).nEndPos;
    3062                 :         92 :                 break;
    3063                 :            :             }
    3064                 :            :         }
    3065                 :            :     }
    3066                 :         92 :     return nRightToLeft;
    3067                 :            : }
    3068                 :            : 
    3069                 :        535 : long TextEngine::ImpGetPortionXOffset( sal_uLong nPara, TextLine* pLine, sal_uInt16 nTextPortion )
    3070                 :            : {
    3071                 :        535 :     long nX = pLine->GetStartX();
    3072                 :            : 
    3073                 :        535 :     TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara );
    3074                 :            : 
    3075         [ -  + ]:        535 :     for ( sal_uInt16 i = pLine->GetStartPortion(); i < nTextPortion; i++ )
    3076                 :            :     {
    3077                 :          0 :         TETextPortion* pPortion = pParaPortion->GetTextPortions()[ i ];
    3078                 :          0 :         nX += pPortion->GetWidth();
    3079                 :            :     }
    3080                 :            : 
    3081                 :        535 :     TETextPortion* pDestPortion = pParaPortion->GetTextPortions()[ nTextPortion ];
    3082         [ +  - ]:        535 :     if ( pDestPortion->GetKind() != PORTIONKIND_TAB )
    3083                 :            :     {
    3084 [ +  - ][ -  + ]:        535 :         if ( !IsRightToLeft() && pDestPortion->GetRightToLeft() )
                 [ -  + ]
    3085                 :            :         {
    3086                 :            :             // Portions behind must be added, visual before this portion
    3087                 :          0 :             sal_uInt16 nTmpPortion = nTextPortion+1;
    3088         [ #  # ]:          0 :             while ( nTmpPortion <= pLine->GetEndPortion() )
    3089                 :            :             {
    3090                 :          0 :                 TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ];
    3091 [ #  # ][ #  # ]:          0 :                 if ( pNextTextPortion->GetRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) )
                 [ #  # ]
    3092                 :          0 :                     nX += pNextTextPortion->GetWidth();
    3093                 :            :                 else
    3094                 :          0 :                     break;
    3095                 :          0 :                 nTmpPortion++;
    3096                 :            :             }
    3097                 :            :             // Portions before must be removed, visual behind this portion
    3098                 :          0 :             nTmpPortion = nTextPortion;
    3099         [ #  # ]:          0 :             while ( nTmpPortion > pLine->GetStartPortion() )
    3100                 :            :             {
    3101                 :          0 :                 --nTmpPortion;
    3102                 :          0 :                 TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ];
    3103 [ #  # ][ #  # ]:          0 :                 if ( pPrevTextPortion->GetRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) )
                 [ #  # ]
    3104                 :          0 :                     nX -= pPrevTextPortion->GetWidth();
    3105                 :            :                 else
    3106                 :          0 :                     break;
    3107                 :            :             }
    3108                 :            :         }
    3109 [ -  + ][ #  # ]:        535 :         else if ( IsRightToLeft() && !pDestPortion->IsRightToLeft() )
                 [ -  + ]
    3110                 :            :         {
    3111                 :            :             // Portions behind must be removed, visual behind this portion
    3112                 :          0 :             sal_uInt16 nTmpPortion = nTextPortion+1;
    3113         [ #  # ]:          0 :             while ( nTmpPortion <= pLine->GetEndPortion() )
    3114                 :            :             {
    3115                 :          0 :                 TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ];
    3116 [ #  # ][ #  # ]:          0 :                 if ( !pNextTextPortion->IsRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) )
                 [ #  # ]
    3117                 :          0 :                     nX += pNextTextPortion->GetWidth();
    3118                 :            :                 else
    3119                 :          0 :                     break;
    3120                 :          0 :                 nTmpPortion++;
    3121                 :            :             }
    3122                 :            :             // Portions before must be added, visual before this portion
    3123                 :          0 :             nTmpPortion = nTextPortion;
    3124         [ #  # ]:          0 :             while ( nTmpPortion > pLine->GetStartPortion() )
    3125                 :            :             {
    3126                 :          0 :                 --nTmpPortion;
    3127                 :          0 :                 TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ];
    3128 [ #  # ][ #  # ]:          0 :                 if ( !pPrevTextPortion->IsRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) )
                 [ #  # ]
    3129                 :          0 :                     nX -= pPrevTextPortion->GetWidth();
    3130                 :            :                 else
    3131                 :          0 :                     break;
    3132                 :            :             }
    3133                 :            :         }
    3134                 :            :     }
    3135                 :            : 
    3136                 :        535 :     return nX;
    3137                 :            : }
    3138                 :            : 
    3139                 :        179 : void TextEngine::ImpInitLayoutMode( OutputDevice* pOutDev, sal_Bool bDrawingR2LPortion )
    3140                 :            : {
    3141                 :        179 :     sal_uLong nLayoutMode = pOutDev->GetLayoutMode();
    3142                 :            : 
    3143                 :        179 :     nLayoutMode &= ~(TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG );
    3144         [ -  + ]:        179 :     if ( bDrawingR2LPortion )
    3145                 :          0 :         nLayoutMode |= TEXT_LAYOUT_BIDI_RTL;
    3146                 :            : 
    3147                 :        179 :     pOutDev->SetLayoutMode( nLayoutMode );
    3148                 :        179 : }
    3149                 :            : 
    3150                 :       1022 : TxtAlign TextEngine::ImpGetAlign() const
    3151                 :            : {
    3152                 :       1022 :     TxtAlign eAlign = meAlign;
    3153         [ -  + ]:       1022 :     if ( IsRightToLeft() )
    3154                 :            :     {
    3155         [ #  # ]:          0 :         if ( eAlign == TXTALIGN_LEFT )
    3156                 :          0 :             eAlign = TXTALIGN_RIGHT;
    3157         [ #  # ]:          0 :         else if ( eAlign == TXTALIGN_RIGHT )
    3158                 :          0 :             eAlign = TXTALIGN_LEFT;
    3159                 :            :     }
    3160                 :       1022 :     return eAlign;
    3161                 :            : }
    3162                 :            : 
    3163                 :        178 : long TextEngine::ImpGetOutputOffset( sal_uLong nPara, TextLine* pLine, sal_uInt16 nIndex, sal_uInt16 nIndex2 )
    3164                 :            : {
    3165         [ +  - ]:        178 :     TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara );
    3166                 :            : 
    3167                 :            :     sal_uInt16 nPortionStart;
    3168         [ +  - ]:        178 :     sal_uInt16 nPortion = pPortion->GetTextPortions().FindPortion( nIndex, nPortionStart, sal_True );
    3169                 :            : 
    3170                 :        178 :     TETextPortion* pTextPortion = pPortion->GetTextPortions()[ nPortion ];
    3171                 :            : 
    3172                 :            :     long nX;
    3173                 :            : 
    3174 [ +  + ][ +  - ]:        178 :     if ( ( nIndex == nPortionStart ) && ( nIndex == nIndex2 )  )
    3175                 :            :     {
    3176                 :            :         // Output of full portion, so we need portion x offset.
    3177                 :            :         // Use ImpGetPortionXOffset, because GetXPos may deliver left or right position from portioon, depending on R2L, L2R
    3178         [ +  - ]:        129 :         nX = ImpGetPortionXOffset( nPara, pLine, nPortion );
    3179         [ -  + ]:        129 :         if ( IsRightToLeft() )
    3180                 :            :         {
    3181                 :          0 :             nX = -nX -pTextPortion->GetWidth();
    3182                 :            :         }
    3183                 :            :     }
    3184                 :            :     else
    3185                 :            :     {
    3186         [ +  - ]:         49 :         nX = ImpGetXPos( nPara, pLine, nIndex, nIndex == nPortionStart );
    3187         [ +  - ]:         49 :         if ( nIndex2 != nIndex )
    3188                 :            :         {
    3189         [ +  - ]:         49 :             long nX2 = ImpGetXPos( nPara, pLine, nIndex2, sal_False );
    3190         [ +  - ]:         98 :             if ( ( !IsRightToLeft() && ( nX2 < nX ) ) ||
           [ +  -  -  + ]
         [ #  # ][ -  + ]
    3191                 :         49 :                  ( IsRightToLeft() && ( nX2 > nX ) ) )
    3192                 :            :             {
    3193                 :          0 :                 nX = nX2;
    3194                 :            :             }
    3195                 :            :         }
    3196         [ -  + ]:         49 :         if ( IsRightToLeft() )
    3197                 :            :         {
    3198                 :          0 :             nX = -nX;
    3199                 :            :         }
    3200                 :            :     }
    3201                 :            : 
    3202                 :        178 :     return nX;
    3203                 :            : }
    3204                 :            : 
    3205                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10