LCOV - code coverage report
Current view: top level - sw/source/core/undo - unovwr.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 39 241 16.2 %
Date: 2015-06-13 12:38:46 Functions: 6 21 28.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11