LCOV - code coverage report
Current view: top level - libreoffice/sw/source/core/undo - unovwr.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 243 0.0 %
Date: 2012-12-17 Functions: 0 19 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <UndoOverwrite.hxx>
      21             : #include <tools/resid.hxx>
      22             : #include <unotools/charclass.hxx>
      23             : #include <unotools/transliterationwrapper.hxx>
      24             : #include <comphelper/processfactory.hxx>
      25             : #include <doc.hxx>
      26             : #include <IDocumentUndoRedo.hxx>
      27             : #include <IShellCursorSupplier.hxx>
      28             : #include <swundo.hxx>
      29             : #include <pam.hxx>
      30             : #include <ndtxt.hxx>
      31             : #include <UndoCore.hxx>
      32             : #include <rolbck.hxx>
      33             : #include <acorrect.hxx>
      34             : #include <docary.hxx>
      35             : #include <comcore.hrc> // #111827#
      36             : #include <undo.hrc>
      37             : 
      38             : using namespace ::com::sun::star;
      39             : using namespace ::com::sun::star::i18n;
      40             : using namespace ::com::sun::star::uno;
      41             : 
      42           0 : SwUndoOverwrite::SwUndoOverwrite( SwDoc* pDoc, SwPosition& rPos,
      43             :                                     sal_Unicode cIns )
      44             :     : SwUndo(UNDO_OVERWRITE),
      45           0 :       pRedlSaveData( 0 ), bGroup( sal_False )
      46             : {
      47           0 :     if( !pDoc->IsIgnoreRedline() && !pDoc->GetRedlineTbl().empty() )
      48             :     {
      49           0 :         SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(),
      50           0 :                     rPos.nNode, rPos.nContent.GetIndex()+1 );
      51           0 :         pRedlSaveData = new SwRedlineSaveDatas;
      52           0 :         if( !FillSaveData( aPam, *pRedlSaveData, sal_False ))
      53           0 :             delete pRedlSaveData, pRedlSaveData = 0;
      54             :     }
      55             : 
      56           0 :     nSttNode = rPos.nNode.GetIndex();
      57           0 :     nSttCntnt = rPos.nContent.GetIndex();
      58             : 
      59           0 :     SwTxtNode* pTxtNd = rPos.nNode.GetNode().GetTxtNode();
      60             :     OSL_ENSURE( pTxtNd, "Overwrite not in a TextNode?" );
      61             : 
      62           0 :     bInsChar = sal_True;
      63           0 :     xub_StrLen nTxtNdLen = pTxtNd->GetTxt().Len();
      64           0 :     if( nSttCntnt < nTxtNdLen )     // no pure insert?
      65             :     {
      66           0 :         aDelStr.Insert( pTxtNd->GetTxt().GetChar( nSttCntnt ) );
      67           0 :         if( !pHistory )
      68           0 :             pHistory = new SwHistory;
      69           0 :         SwRegHistory aRHst( *pTxtNd, pHistory );
      70             :         pHistory->CopyAttr( pTxtNd->GetpSwpHints(), nSttNode, 0,
      71           0 :                             nTxtNdLen, false );
      72           0 :         rPos.nContent++;
      73           0 :         bInsChar = sal_False;
      74             :     }
      75             : 
      76           0 :     bool bOldExpFlg = pTxtNd->IsIgnoreDontExpand();
      77           0 :     pTxtNd->SetIgnoreDontExpand( true );
      78             : 
      79             :     pTxtNd->InsertText( rtl::OUString(cIns), rPos.nContent,
      80           0 :             IDocumentContentOperations::INS_EMPTYEXPAND );
      81           0 :     aInsStr.Insert( cIns );
      82             : 
      83           0 :     if( !bInsChar )
      84             :     {
      85           0 :         const SwIndex aTmpIndex( rPos.nContent, -2 );
      86           0 :         pTxtNd->EraseText( aTmpIndex, 1 );
      87             :     }
      88           0 :     pTxtNd->SetIgnoreDontExpand( bOldExpFlg );
      89             : 
      90           0 :     bCacheComment = false;
      91           0 : }
      92             : 
      93           0 : SwUndoOverwrite::~SwUndoOverwrite()
      94             : {
      95           0 :     delete pRedlSaveData;
      96           0 : }
      97             : 
      98           0 : sal_Bool SwUndoOverwrite::CanGrouping( SwDoc* pDoc, SwPosition& rPos,
      99             :                                     sal_Unicode cIns )
     100             : {
     101             : // What is with only inserted characters?
     102             : 
     103             :     // Only deletion of single chars can be combined.
     104           0 :     if( rPos.nNode != nSttNode || !aInsStr.Len()  ||
     105           0 :         ( !bGroup && aInsStr.Len() != 1 ))
     106           0 :         return sal_False;
     107             : 
     108             :     // Is the node a TextNode at all?
     109           0 :     SwTxtNode * pDelTxtNd = rPos.nNode.GetNode().GetTxtNode();
     110           0 :     if( !pDelTxtNd ||
     111           0 :         ( pDelTxtNd->GetTxt().Len() != rPos.nContent.GetIndex() &&
     112           0 :             rPos.nContent.GetIndex() != ( nSttCntnt + aInsStr.Len() )))
     113           0 :         return sal_False;
     114             : 
     115           0 :     CharClass& rCC = GetAppCharClass();
     116             : 
     117             :     // ask the char that should be inserted
     118           0 :     if (( CH_TXTATR_BREAKWORD == cIns || CH_TXTATR_INWORD == cIns ) ||
     119           0 :         rCC.isLetterNumeric( rtl::OUString( cIns ), 0 ) !=
     120           0 :         rCC.isLetterNumeric( aInsStr, aInsStr.Len()-1 ) )
     121           0 :         return sal_False;
     122             : 
     123             :     {
     124           0 :         SwRedlineSaveDatas* pTmpSav = new SwRedlineSaveDatas;
     125           0 :         SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(),
     126           0 :                     rPos.nNode, rPos.nContent.GetIndex()+1 );
     127             : 
     128           0 :         if( !FillSaveData( aPam, *pTmpSav, sal_False ))
     129           0 :             delete pTmpSav, pTmpSav = 0;
     130             : 
     131           0 :         bool bOk = ( !pRedlSaveData && !pTmpSav ) ||
     132             :                    ( pRedlSaveData && pTmpSav &&
     133             :                         SwUndo::CanRedlineGroup( *pRedlSaveData, *pTmpSav,
     134           0 :                             nSttCntnt > rPos.nContent.GetIndex() ));
     135           0 :         delete pTmpSav;
     136           0 :         if( !bOk )
     137           0 :             return sal_False;
     138             : 
     139           0 :         pDoc->DeleteRedline( aPam, false, USHRT_MAX );
     140             :     }
     141             : 
     142             :     // both 'overwrites' can be combined so 'move' the corresponding character
     143           0 :     if( !bInsChar )
     144             :     {
     145           0 :         if( rPos.nContent.GetIndex() < pDelTxtNd->GetTxt().Len() )
     146             :         {
     147           0 :             aDelStr.Insert( pDelTxtNd->GetTxt().GetChar(rPos.nContent.GetIndex()) );
     148           0 :             rPos.nContent++;
     149             :         }
     150             :         else
     151           0 :             bInsChar = sal_True;
     152             :     }
     153             : 
     154           0 :     bool bOldExpFlg = pDelTxtNd->IsIgnoreDontExpand();
     155           0 :     pDelTxtNd->SetIgnoreDontExpand( true );
     156             : 
     157             :     pDelTxtNd->InsertText( rtl::OUString(cIns), rPos.nContent,
     158           0 :             IDocumentContentOperations::INS_EMPTYEXPAND );
     159           0 :     aInsStr.Insert( cIns );
     160             : 
     161           0 :     if( !bInsChar )
     162             :     {
     163           0 :         const SwIndex aTmpIndex( rPos.nContent, -2 );
     164           0 :         pDelTxtNd->EraseText( aTmpIndex, 1 );
     165             :     }
     166           0 :     pDelTxtNd->SetIgnoreDontExpand( bOldExpFlg );
     167             : 
     168           0 :     bGroup = sal_True;
     169           0 :     return sal_True;
     170             : }
     171             : 
     172           0 : void SwUndoOverwrite::UndoImpl(::sw::UndoRedoContext & rContext)
     173             : {
     174           0 :     SwDoc *const pDoc = & rContext.GetDoc();
     175           0 :     SwPaM *const pAktPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
     176             : 
     177           0 :     pAktPam->DeleteMark();
     178           0 :     pAktPam->GetPoint()->nNode = nSttNode;
     179           0 :     SwTxtNode* pTxtNd = pAktPam->GetNode()->GetTxtNode();
     180             :     OSL_ENSURE( pTxtNd, "Overwrite not in a TextNode?" );
     181           0 :     SwIndex& rIdx = pAktPam->GetPoint()->nContent;
     182           0 :     rIdx.Assign( pTxtNd, nSttCntnt );
     183             : 
     184           0 :     SwAutoCorrExceptWord* pACEWord = pDoc->GetAutoCorrExceptWord();
     185           0 :     if( pACEWord )
     186             :     {
     187           0 :         if( 1 == aInsStr.Len() && 1 == aDelStr.Len() )
     188           0 :             pACEWord->CheckChar( *pAktPam->GetPoint(), aDelStr.GetChar( 0 ) );
     189           0 :         pDoc->SetAutoCorrExceptWord( 0 );
     190             :     }
     191             : 
     192             :     // If there was not only a overwrite but also an insert, delete the surplus
     193           0 :     if( aInsStr.Len() > aDelStr.Len() )
     194             :     {
     195           0 :         rIdx += aDelStr.Len();
     196           0 :         pTxtNd->EraseText( rIdx, aInsStr.Len() - aDelStr.Len() );
     197           0 :         rIdx = nSttCntnt;
     198             :     }
     199             : 
     200           0 :     if( aDelStr.Len() )
     201             :     {
     202           0 :         String aTmpStr = rtl::OUString('1');
     203           0 :         sal_Unicode* pTmpStr = aTmpStr.GetBufferAccess();
     204             : 
     205           0 :         bool bOldExpFlg = pTxtNd->IsIgnoreDontExpand();
     206           0 :         pTxtNd->SetIgnoreDontExpand( true );
     207             : 
     208           0 :         ++rIdx;
     209           0 :         for( xub_StrLen n = 0; n < aDelStr.Len(); n++  )
     210             :         {
     211             :             // do it individually, to keep the attributes!
     212           0 :             *pTmpStr = aDelStr.GetChar( n );
     213           0 :             pTxtNd->InsertText( aTmpStr, rIdx /*???, SETATTR_NOTXTATRCHR*/ );
     214           0 :             rIdx -= 2;
     215           0 :             pTxtNd->EraseText( rIdx, 1 );
     216           0 :             rIdx += 2;
     217             :         }
     218           0 :         pTxtNd->SetIgnoreDontExpand( bOldExpFlg );
     219           0 :         rIdx--;
     220             :     }
     221             : 
     222           0 :     if( pHistory )
     223             :     {
     224           0 :         if( pTxtNd->GetpSwpHints() )
     225           0 :             pTxtNd->ClearSwpHintsArr( false );
     226           0 :         pHistory->TmpRollback( pDoc, 0, false );
     227             :     }
     228             : 
     229           0 :     if( pAktPam->GetMark()->nContent.GetIndex() != nSttCntnt )
     230             :     {
     231           0 :         pAktPam->SetMark();
     232           0 :         pAktPam->GetMark()->nContent = nSttCntnt;
     233             :     }
     234             : 
     235           0 :     if( pRedlSaveData )
     236           0 :         SetSaveData( *pDoc, *pRedlSaveData );
     237           0 : }
     238             : 
     239           0 : void SwUndoOverwrite::RepeatImpl(::sw::RepeatContext & rContext)
     240             : {
     241           0 :     SwPaM *const pAktPam = & rContext.GetRepeatPaM();
     242           0 :     if( !aInsStr.Len() || pAktPam->HasMark() )
     243           0 :         return;
     244             : 
     245           0 :     SwDoc & rDoc = rContext.GetDoc();
     246             : 
     247             :     {
     248           0 :         ::sw::GroupUndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
     249           0 :         rDoc.Overwrite(*pAktPam, rtl::OUString(aInsStr.GetChar(0)));
     250             :     }
     251           0 :     for( xub_StrLen n = 1; n < aInsStr.Len(); ++n )
     252           0 :         rDoc.Overwrite( *pAktPam, rtl::OUString(aInsStr.GetChar(n)) );
     253             : }
     254             : 
     255           0 : void SwUndoOverwrite::RedoImpl(::sw::UndoRedoContext & rContext)
     256             : {
     257           0 :     SwDoc *const pDoc = & rContext.GetDoc();
     258           0 :     SwPaM *const pAktPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
     259             : 
     260           0 :     pAktPam->DeleteMark();
     261           0 :     pAktPam->GetPoint()->nNode = nSttNode;
     262           0 :     SwTxtNode* pTxtNd = pAktPam->GetNode()->GetTxtNode();
     263             :     OSL_ENSURE( pTxtNd, "Overwrite not in TextNode?" );
     264           0 :     SwIndex& rIdx = pAktPam->GetPoint()->nContent;
     265             : 
     266           0 :     if( pRedlSaveData )
     267             :     {
     268           0 :         rIdx.Assign( pTxtNd, nSttCntnt );
     269           0 :         pAktPam->SetMark();
     270           0 :         pAktPam->GetMark()->nContent += aInsStr.Len();
     271           0 :         pDoc->DeleteRedline( *pAktPam, false, USHRT_MAX );
     272           0 :         pAktPam->DeleteMark();
     273             :     }
     274           0 :     rIdx.Assign( pTxtNd, aDelStr.Len() ? nSttCntnt+1 : nSttCntnt );
     275             : 
     276           0 :     bool bOldExpFlg = pTxtNd->IsIgnoreDontExpand();
     277           0 :     pTxtNd->SetIgnoreDontExpand( true );
     278             : 
     279           0 :     for( xub_StrLen n = 0; n < aInsStr.Len(); n++  )
     280             :     {
     281             :         // do it individually, to keep the attributes!
     282           0 :         pTxtNd->InsertText( rtl::OUString(aInsStr.GetChar(n)), rIdx,
     283           0 :                 IDocumentContentOperations::INS_EMPTYEXPAND );
     284           0 :         if( n < aDelStr.Len() )
     285             :         {
     286           0 :             rIdx -= 2;
     287           0 :             pTxtNd->EraseText( rIdx, 1 );
     288           0 :             rIdx += n+1 < aDelStr.Len() ? 2 : 1;
     289             :         }
     290             :     }
     291           0 :     pTxtNd->SetIgnoreDontExpand( bOldExpFlg );
     292             : 
     293             :     // get back old start position from UndoNodes array
     294           0 :     if( pHistory )
     295           0 :         pHistory->SetTmpEnd( pHistory->Count() );
     296           0 :     if( pAktPam->GetMark()->nContent.GetIndex() != nSttCntnt )
     297             :     {
     298           0 :         pAktPam->SetMark();
     299           0 :         pAktPam->GetMark()->nContent = nSttCntnt;
     300             :     }
     301           0 : }
     302             : 
     303           0 : SwRewriter SwUndoOverwrite::GetRewriter() const
     304             : {
     305           0 :     SwRewriter aResult;
     306             : 
     307           0 :     String aString;
     308             : 
     309           0 :     aString += String(SW_RES(STR_START_QUOTE));
     310             :     aString += ShortenString(aInsStr, nUndoStringLength,
     311           0 :                              String(SW_RES(STR_LDOTS)));
     312           0 :     aString += String(SW_RES(STR_END_QUOTE));
     313             : 
     314           0 :     aResult.AddRule(UndoArg1, aString);
     315             : 
     316           0 :     return aResult;
     317             : }
     318             : 
     319             : struct _UndoTransliterate_Data
     320             : {
     321             :     String          sText;
     322             :     SwHistory*      pHistory;
     323             :     Sequence< sal_Int32 >*  pOffsets;
     324             :     sal_uLong           nNdIdx;
     325             :     xub_StrLen      nStart, nLen;
     326             : 
     327           0 :     _UndoTransliterate_Data( sal_uLong nNd, xub_StrLen nStt, xub_StrLen nStrLen, const String& rTxt )
     328             :         : sText( rTxt ), pHistory( 0 ), pOffsets( 0 ),
     329           0 :         nNdIdx( nNd ), nStart( nStt ), nLen( nStrLen )
     330           0 :     {}
     331           0 :     ~_UndoTransliterate_Data() { delete pOffsets; delete pHistory; }
     332             : 
     333             :     void SetChangeAtNode( SwDoc& rDoc );
     334             : };
     335             : 
     336           0 : SwUndoTransliterate::SwUndoTransliterate(
     337             :     const SwPaM& rPam,
     338             :     const utl::TransliterationWrapper& rTrans )
     339           0 :     : SwUndo( UNDO_TRANSLITERATE ), SwUndRng( rPam ), nType( rTrans.getType() )
     340             : {
     341           0 : }
     342             : 
     343           0 : SwUndoTransliterate::~SwUndoTransliterate()
     344             : {
     345           0 :     for (size_t i = 0; i < aChanges.size();  ++i)
     346           0 :         delete aChanges[i];
     347           0 : }
     348             : 
     349           0 : void SwUndoTransliterate::UndoImpl(::sw::UndoRedoContext & rContext)
     350             : {
     351           0 :     SwDoc & rDoc = rContext.GetDoc();
     352             : 
     353             :     // since the changes were added to the vector from the end of the string/node towards
     354             :     // the start, we need to revert them from the start towards the end now to keep the
     355             :     // offset information of the undo data in sync with the changing text.
     356             :     // Thus we need to iterate from the end of the vector to the start
     357           0 :     for (sal_Int32 i = aChanges.size() - 1; i >= 0;  --i)
     358           0 :         aChanges[i]->SetChangeAtNode( rDoc );
     359             : 
     360           0 :     AddUndoRedoPaM(rContext, true);
     361           0 : }
     362             : 
     363           0 : void SwUndoTransliterate::RedoImpl(::sw::UndoRedoContext & rContext)
     364             : {
     365           0 :     SwPaM & rPam( AddUndoRedoPaM(rContext) );
     366           0 :     DoTransliterate(rContext.GetDoc(), rPam);
     367           0 : }
     368             : 
     369           0 : void SwUndoTransliterate::RepeatImpl(::sw::RepeatContext & rContext)
     370             : {
     371           0 :     DoTransliterate(rContext.GetDoc(), rContext.GetRepeatPaM());
     372           0 : }
     373             : 
     374           0 : void SwUndoTransliterate::DoTransliterate(SwDoc & rDoc, SwPaM & rPam)
     375             : {
     376           0 :     utl::TransliterationWrapper aTrans( ::comphelper::getProcessComponentContext(), nType );
     377           0 :     rDoc.TransliterateText( rPam, aTrans );
     378           0 : }
     379             : 
     380           0 : void SwUndoTransliterate::AddChanges( SwTxtNode& rTNd,
     381             :                     xub_StrLen nStart, xub_StrLen nLen,
     382             :                     uno::Sequence <sal_Int32>& rOffsets )
     383             : {
     384           0 :     long nOffsLen = rOffsets.getLength();
     385             :     _UndoTransliterate_Data* pNew = new _UndoTransliterate_Data(
     386           0 :                         rTNd.GetIndex(), nStart, (xub_StrLen)nOffsLen,
     387           0 :                         rTNd.GetTxt().Copy( nStart, nLen ));
     388             : 
     389           0 :     aChanges.push_back( pNew );
     390             : 
     391           0 :     const sal_Int32* pOffsets = rOffsets.getConstArray();
     392             :     // where did we need less memory ?
     393           0 :     const sal_Int32* p = pOffsets;
     394           0 :     for( long n = 0; n < nOffsLen; ++n, ++p )
     395           0 :     if( *p != ( nStart + n ))
     396             :     {
     397             :         // create the Offset array
     398           0 :         pNew->pOffsets = new Sequence <sal_Int32> ( nLen );
     399           0 :         sal_Int32* pIdx = pNew->pOffsets->getArray();
     400           0 :         p = pOffsets;
     401           0 :         long nMyOff, nNewVal = nStart;
     402           0 :         for( n = 0, nMyOff = nStart; n < nOffsLen; ++p, ++n, ++nMyOff )
     403             :         {
     404           0 :             if( *p < nMyOff )
     405             :             {
     406             :                 // something is deleted
     407           0 :                 nMyOff = *p;
     408           0 :                 *(pIdx-1) = nNewVal++;
     409             :             }
     410           0 :             else if( *p > nMyOff )
     411             :             {
     412           0 :                 for( ; *p > nMyOff; ++nMyOff )
     413           0 :                     *pIdx++ = nNewVal;
     414           0 :                 --nMyOff;
     415           0 :                 --n;
     416           0 :                 --p;
     417             :             }
     418             :             else
     419           0 :                 *pIdx++ = nNewVal++;
     420             :         }
     421             : 
     422             :         // and then we need to save the attributes/bookmarks
     423             :         // but this data must moved every time to the last in the chain!
     424           0 :         for (size_t i = 0; i + 1 < aChanges.size(); ++i)    // check all changes but not the current one
     425             :         {
     426           0 :             _UndoTransliterate_Data* pD = aChanges[i];
     427           0 :             if( pD->nNdIdx == pNew->nNdIdx && pD->pHistory )
     428             :             {
     429             :                 // same node and have a history?
     430           0 :                 pNew->pHistory = pD->pHistory;
     431           0 :                 pD->pHistory = 0;
     432           0 :                 break;          // more can't exist
     433             :             }
     434             :         }
     435             : 
     436           0 :         if( !pNew->pHistory )
     437             :         {
     438           0 :             pNew->pHistory = new SwHistory;
     439           0 :             SwRegHistory aRHst( rTNd, pNew->pHistory );
     440             :             pNew->pHistory->CopyAttr( rTNd.GetpSwpHints(),
     441           0 :                     pNew->nNdIdx, 0, rTNd.GetTxt().Len(), false );
     442             :         }
     443           0 :         break;
     444             :     }
     445           0 : }
     446             : 
     447           0 : void _UndoTransliterate_Data::SetChangeAtNode( SwDoc& rDoc )
     448             : {
     449           0 :     SwTxtNode* pTNd = rDoc.GetNodes()[ nNdIdx ]->GetTxtNode();
     450           0 :     if( pTNd )
     451             :     {
     452           0 :         Sequence <sal_Int32> aOffsets( pOffsets ? pOffsets->getLength() : nLen );
     453           0 :         if( pOffsets )
     454           0 :             aOffsets = *pOffsets;
     455             :         else
     456             :         {
     457           0 :             sal_Int32* p = aOffsets.getArray();
     458           0 :             for( xub_StrLen n = 0; n < nLen; ++n, ++p )
     459           0 :                 *p = n + nStart;
     460             :         }
     461           0 :         pTNd->ReplaceTextOnly( nStart, nLen, sText, aOffsets );
     462             : 
     463           0 :         if( pHistory )
     464             :         {
     465           0 :             if( pTNd->GetpSwpHints() )
     466           0 :                 pTNd->ClearSwpHintsArr( false );
     467           0 :             pHistory->TmpRollback( &rDoc, 0, false );
     468           0 :             pHistory->SetTmpEnd( pHistory->Count() );
     469           0 :         }
     470             :     }
     471           0 : }
     472             : 
     473             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10