LCOV - code coverage report
Current view: top level - sw/source/core/undo - unovwr.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 241 0.0 %
Date: 2014-04-14 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>
      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             :         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, 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 :     sal_Int32 nTxtNdLen = pTxtNd->GetTxt().getLength();
      64           0 :     if( nSttCntnt < nTxtNdLen )     // no pure insert?
      65             :     {
      66           0 :         aDelStr += OUString( pTxtNd->GetTxt()[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( OUString(cIns), rPos.nContent,
      80           0 :             IDocumentContentOperations::INS_EMPTYEXPAND );
      81           0 :     aInsStr += OUString( 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.isEmpty()  ||
     105           0 :         ( !bGroup && aInsStr.getLength() != 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().getLength() != rPos.nContent.GetIndex() &&
     112           0 :             rPos.nContent.GetIndex() != ( nSttCntnt + aInsStr.getLength() )))
     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( OUString( cIns ), 0 ) !=
     120           0 :         rCC.isLetterNumeric( aInsStr, aInsStr.getLength()-1 ) )
     121           0 :         return sal_False;
     122             : 
     123             :     {
     124           0 :         SwRedlineSaveDatas aTmpSav;
     125             :         SwPaM aPam( rPos.nNode, rPos.nContent.GetIndex(),
     126           0 :                     rPos.nNode, rPos.nContent.GetIndex()+1 );
     127             : 
     128           0 :         const bool bSaved = FillSaveData( aPam, aTmpSav, false );
     129             : 
     130           0 :         bool bOk = ( !pRedlSaveData && !bSaved ) ||
     131           0 :                    ( pRedlSaveData && bSaved &&
     132             :                         SwUndo::CanRedlineGroup( *pRedlSaveData, aTmpSav,
     133           0 :                             nSttCntnt > rPos.nContent.GetIndex() ));
     134             :         // aTmpSav.DeleteAndDestroyAll();
     135           0 :         if( !bOk )
     136           0 :             return sal_False;
     137             : 
     138           0 :         pDoc->DeleteRedline( aPam, false, USHRT_MAX );
     139             :     }
     140             : 
     141             :     // both 'overwrites' can be combined so 'move' the corresponding character
     142           0 :     if( !bInsChar )
     143             :     {
     144           0 :         if (rPos.nContent.GetIndex() < pDelTxtNd->GetTxt().getLength())
     145             :         {
     146           0 :             aDelStr += OUString( pDelTxtNd->GetTxt()[rPos.nContent.GetIndex()] );
     147           0 :             rPos.nContent++;
     148             :         }
     149             :         else
     150           0 :             bInsChar = sal_True;
     151             :     }
     152             : 
     153           0 :     bool bOldExpFlg = pDelTxtNd->IsIgnoreDontExpand();
     154           0 :     pDelTxtNd->SetIgnoreDontExpand( true );
     155             : 
     156             :     OUString const ins( pDelTxtNd->InsertText(OUString(cIns), rPos.nContent,
     157           0 :             IDocumentContentOperations::INS_EMPTYEXPAND) );
     158             :     assert(ins.getLength() == 1); // check in SwDoc::Overwrite => cannot fail
     159             :     (void) ins;
     160           0 :     aInsStr += OUString( cIns );
     161             : 
     162           0 :     if( !bInsChar )
     163             :     {
     164           0 :         const SwIndex aTmpIndex( rPos.nContent, -2 );
     165           0 :         pDelTxtNd->EraseText( aTmpIndex, 1 );
     166             :     }
     167           0 :     pDelTxtNd->SetIgnoreDontExpand( bOldExpFlg );
     168             : 
     169           0 :     bGroup = sal_True;
     170           0 :     return sal_True;
     171             : }
     172             : 
     173           0 : void SwUndoOverwrite::UndoImpl(::sw::UndoRedoContext & rContext)
     174             : {
     175           0 :     SwDoc *const pDoc = & rContext.GetDoc();
     176           0 :     SwPaM *const pAktPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
     177             : 
     178           0 :     pAktPam->DeleteMark();
     179           0 :     pAktPam->GetPoint()->nNode = nSttNode;
     180           0 :     SwTxtNode* pTxtNd = pAktPam->GetNode()->GetTxtNode();
     181             :     OSL_ENSURE( pTxtNd, "Overwrite not in a TextNode?" );
     182           0 :     SwIndex& rIdx = pAktPam->GetPoint()->nContent;
     183           0 :     rIdx.Assign( pTxtNd, nSttCntnt );
     184             : 
     185           0 :     SwAutoCorrExceptWord* pACEWord = pDoc->GetAutoCorrExceptWord();
     186           0 :     if( pACEWord )
     187             :     {
     188           0 :         if( 1 == aInsStr.getLength() && 1 == aDelStr.getLength() )
     189           0 :             pACEWord->CheckChar( *pAktPam->GetPoint(), aDelStr[0] );
     190           0 :         pDoc->SetAutoCorrExceptWord( 0 );
     191             :     }
     192             : 
     193             :     // If there was not only a overwrite but also an insert, delete the surplus
     194           0 :     if( aInsStr.getLength() > aDelStr.getLength() )
     195             :     {
     196           0 :         rIdx += aDelStr.getLength();
     197           0 :         pTxtNd->EraseText( rIdx, aInsStr.getLength() - aDelStr.getLength() );
     198           0 :         rIdx = nSttCntnt;
     199             :     }
     200             : 
     201           0 :     if( !aDelStr.isEmpty() )
     202             :     {
     203           0 :         bool bOldExpFlg = pTxtNd->IsIgnoreDontExpand();
     204           0 :         pTxtNd->SetIgnoreDontExpand( true );
     205             : 
     206           0 :         ++rIdx;
     207           0 :         for( sal_Int32 n = 0; n < aDelStr.getLength(); n++  )
     208             :         {
     209             :             // do it individually, to keep the attributes!
     210           0 :             OUString aTmpStr(aDelStr[n]);
     211           0 :             OUString const ins( pTxtNd->InsertText(aTmpStr, rIdx) );
     212             :             assert(ins.getLength() == 1); // cannot fail
     213             :         (void) ins;
     214           0 :             rIdx -= 2;
     215           0 :             pTxtNd->EraseText( rIdx, 1 );
     216           0 :             rIdx += 2;
     217           0 :         }
     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.isEmpty() || 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, OUString(aInsStr[0]));
     250             :     }
     251           0 :     for( sal_Int32 n = 1; n < aInsStr.getLength(); ++n )
     252           0 :         rDoc.Overwrite( *pAktPam, OUString(aInsStr[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.getLength();
     271           0 :         pDoc->DeleteRedline( *pAktPam, false, USHRT_MAX );
     272           0 :         pAktPam->DeleteMark();
     273             :     }
     274           0 :     rIdx.Assign( pTxtNd, !aDelStr.isEmpty() ? nSttCntnt+1 : nSttCntnt );
     275             : 
     276           0 :     bool bOldExpFlg = pTxtNd->IsIgnoreDontExpand();
     277           0 :     pTxtNd->SetIgnoreDontExpand( true );
     278             : 
     279           0 :     for( sal_Int32 n = 0; n < aInsStr.getLength(); n++  )
     280             :     {
     281             :         // do it individually, to keep the attributes!
     282             :         OUString const ins(
     283           0 :                 pTxtNd->InsertText( OUString(aInsStr[n]), rIdx,
     284           0 :                 IDocumentContentOperations::INS_EMPTYEXPAND) );
     285             :         assert(ins.getLength() == 1); // cannot fail
     286             :         (void) ins;
     287           0 :         if( n < aDelStr.getLength() )
     288             :         {
     289           0 :             rIdx -= 2;
     290           0 :             pTxtNd->EraseText( rIdx, 1 );
     291           0 :             rIdx += n+1 < aDelStr.getLength() ? 2 : 1;
     292             :         }
     293           0 :     }
     294           0 :     pTxtNd->SetIgnoreDontExpand( bOldExpFlg );
     295             : 
     296             :     // get back old start position from UndoNodes array
     297           0 :     if( pHistory )
     298           0 :         pHistory->SetTmpEnd( pHistory->Count() );
     299           0 :     if( pAktPam->GetMark()->nContent.GetIndex() != nSttCntnt )
     300             :     {
     301           0 :         pAktPam->SetMark();
     302           0 :         pAktPam->GetMark()->nContent = nSttCntnt;
     303             :     }
     304           0 : }
     305             : 
     306           0 : SwRewriter SwUndoOverwrite::GetRewriter() const
     307             : {
     308           0 :     SwRewriter aResult;
     309             : 
     310           0 :     OUString aString;
     311             : 
     312           0 :     aString += SW_RES(STR_START_QUOTE);
     313           0 :     aString += ShortenString(aInsStr, nUndoStringLength,
     314           0 :                              OUString(SW_RES(STR_LDOTS)));
     315           0 :     aString += SW_RES(STR_END_QUOTE);
     316             : 
     317           0 :     aResult.AddRule(UndoArg1, aString);
     318             : 
     319           0 :     return aResult;
     320             : }
     321             : 
     322             : struct _UndoTransliterate_Data
     323             : {
     324             :     OUString        sText;
     325             :     SwHistory*      pHistory;
     326             :     Sequence< sal_Int32 >*  pOffsets;
     327             :     sal_uLong           nNdIdx;
     328             :     sal_Int32      nStart, nLen;
     329             : 
     330           0 :     _UndoTransliterate_Data( sal_uLong nNd, sal_Int32 nStt, sal_Int32 nStrLen, const OUString& rTxt )
     331             :         : sText( rTxt ), pHistory( 0 ), pOffsets( 0 ),
     332           0 :         nNdIdx( nNd ), nStart( nStt ), nLen( nStrLen )
     333           0 :     {}
     334           0 :     ~_UndoTransliterate_Data() { delete pOffsets; delete pHistory; }
     335             : 
     336             :     void SetChangeAtNode( SwDoc& rDoc );
     337             : };
     338             : 
     339           0 : SwUndoTransliterate::SwUndoTransliterate(
     340             :     const SwPaM& rPam,
     341             :     const utl::TransliterationWrapper& rTrans )
     342           0 :     : SwUndo( UNDO_TRANSLITERATE ), SwUndRng( rPam ), nType( rTrans.getType() )
     343             : {
     344           0 : }
     345             : 
     346           0 : SwUndoTransliterate::~SwUndoTransliterate()
     347             : {
     348           0 :     for (size_t i = 0; i < aChanges.size();  ++i)
     349           0 :         delete aChanges[i];
     350           0 : }
     351             : 
     352           0 : void SwUndoTransliterate::UndoImpl(::sw::UndoRedoContext & rContext)
     353             : {
     354           0 :     SwDoc & rDoc = rContext.GetDoc();
     355             : 
     356             :     // since the changes were added to the vector from the end of the string/node towards
     357             :     // the start, we need to revert them from the start towards the end now to keep the
     358             :     // offset information of the undo data in sync with the changing text.
     359             :     // Thus we need to iterate from the end of the vector to the start
     360           0 :     for (sal_Int32 i = aChanges.size() - 1; i >= 0;  --i)
     361           0 :         aChanges[i]->SetChangeAtNode( rDoc );
     362             : 
     363           0 :     AddUndoRedoPaM(rContext, true);
     364           0 : }
     365             : 
     366           0 : void SwUndoTransliterate::RedoImpl(::sw::UndoRedoContext & rContext)
     367             : {
     368           0 :     SwPaM & rPam( AddUndoRedoPaM(rContext) );
     369           0 :     DoTransliterate(rContext.GetDoc(), rPam);
     370           0 : }
     371             : 
     372           0 : void SwUndoTransliterate::RepeatImpl(::sw::RepeatContext & rContext)
     373             : {
     374           0 :     DoTransliterate(rContext.GetDoc(), rContext.GetRepeatPaM());
     375           0 : }
     376             : 
     377           0 : void SwUndoTransliterate::DoTransliterate(SwDoc & rDoc, SwPaM & rPam)
     378             : {
     379           0 :     utl::TransliterationWrapper aTrans( ::comphelper::getProcessComponentContext(), nType );
     380           0 :     rDoc.TransliterateText( rPam, aTrans );
     381           0 : }
     382             : 
     383           0 : void SwUndoTransliterate::AddChanges( SwTxtNode& rTNd,
     384             :                     sal_Int32 nStart, sal_Int32 nLen,
     385             :                     uno::Sequence <sal_Int32>& rOffsets )
     386             : {
     387           0 :     long nOffsLen = rOffsets.getLength();
     388             :     _UndoTransliterate_Data* pNew = new _UndoTransliterate_Data(
     389           0 :                         rTNd.GetIndex(), nStart, (sal_Int32)nOffsLen,
     390           0 :                         rTNd.GetTxt().copy(nStart, nLen));
     391             : 
     392           0 :     aChanges.push_back( pNew );
     393             : 
     394           0 :     const sal_Int32* pOffsets = rOffsets.getConstArray();
     395             :     // where did we need less memory ?
     396           0 :     const sal_Int32* p = pOffsets;
     397           0 :     for( long n = 0; n < nOffsLen; ++n, ++p )
     398           0 :     if( *p != ( nStart + n ))
     399             :     {
     400             :         // create the Offset array
     401           0 :         pNew->pOffsets = new Sequence <sal_Int32> ( nLen );
     402           0 :         sal_Int32* pIdx = pNew->pOffsets->getArray();
     403           0 :         p = pOffsets;
     404           0 :         long nMyOff, nNewVal = nStart;
     405           0 :         for( n = 0, nMyOff = nStart; n < nOffsLen; ++p, ++n, ++nMyOff )
     406             :         {
     407           0 :             if( *p < nMyOff )
     408             :             {
     409             :                 // something is deleted
     410           0 :                 nMyOff = *p;
     411           0 :                 *(pIdx-1) = nNewVal++;
     412             :             }
     413           0 :             else if( *p > nMyOff )
     414             :             {
     415           0 :                 for( ; *p > nMyOff; ++nMyOff )
     416           0 :                     *pIdx++ = nNewVal;
     417           0 :                 --nMyOff;
     418           0 :                 --n;
     419           0 :                 --p;
     420             :             }
     421             :             else
     422           0 :                 *pIdx++ = nNewVal++;
     423             :         }
     424             : 
     425             :         // and then we need to save the attributes/bookmarks
     426             :         // but this data must moved every time to the last in the chain!
     427           0 :         for (size_t i = 0; i + 1 < aChanges.size(); ++i)    // check all changes but not the current one
     428             :         {
     429           0 :             _UndoTransliterate_Data* pD = aChanges[i];
     430           0 :             if( pD->nNdIdx == pNew->nNdIdx && pD->pHistory )
     431             :             {
     432             :                 // same node and have a history?
     433           0 :                 pNew->pHistory = pD->pHistory;
     434           0 :                 pD->pHistory = 0;
     435           0 :                 break;          // more can't exist
     436             :             }
     437             :         }
     438             : 
     439           0 :         if( !pNew->pHistory )
     440             :         {
     441           0 :             pNew->pHistory = new SwHistory;
     442           0 :             SwRegHistory aRHst( rTNd, pNew->pHistory );
     443             :             pNew->pHistory->CopyAttr( rTNd.GetpSwpHints(),
     444           0 :                     pNew->nNdIdx, 0, rTNd.GetTxt().getLength(), false );
     445             :         }
     446           0 :         break;
     447             :     }
     448           0 : }
     449             : 
     450           0 : void _UndoTransliterate_Data::SetChangeAtNode( SwDoc& rDoc )
     451             : {
     452           0 :     SwTxtNode* pTNd = rDoc.GetNodes()[ nNdIdx ]->GetTxtNode();
     453           0 :     if( pTNd )
     454             :     {
     455           0 :         Sequence <sal_Int32> aOffsets( pOffsets ? pOffsets->getLength() : nLen );
     456           0 :         if( pOffsets )
     457           0 :             aOffsets = *pOffsets;
     458             :         else
     459             :         {
     460           0 :             sal_Int32* p = aOffsets.getArray();
     461           0 :             for( sal_Int32 n = 0; n < nLen; ++n, ++p )
     462           0 :                 *p = n + nStart;
     463             :         }
     464           0 :         pTNd->ReplaceTextOnly( nStart, nLen, sText, aOffsets );
     465             : 
     466           0 :         if( pHistory )
     467             :         {
     468           0 :             if( pTNd->GetpSwpHints() )
     469           0 :                 pTNd->ClearSwpHintsArr( false );
     470           0 :             pHistory->TmpRollback( &rDoc, 0, false );
     471           0 :             pHistory->SetTmpEnd( pHistory->Count() );
     472           0 :         }
     473             :     }
     474           0 : }
     475             : 
     476             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10