LCOV - code coverage report
Current view: top level - sc/source/core/tool - dbdata.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 466 0.0 %
Date: 2014-04-14 Functions: 0 87 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 <unotools/transliterationwrapper.hxx>
      21             : 
      22             : #include "dbdata.hxx"
      23             : #include "globalnames.hxx"
      24             : #include "refupdat.hxx"
      25             : #include "rechead.hxx"
      26             : #include "document.hxx"
      27             : #include "queryparam.hxx"
      28             : #include "queryentry.hxx"
      29             : #include "globstr.hrc"
      30             : #include "subtotalparam.hxx"
      31             : #include "sortparam.hxx"
      32             : 
      33             : #include <memory>
      34             : 
      35             : using ::std::auto_ptr;
      36             : using ::std::unary_function;
      37             : using ::std::for_each;
      38             : using ::std::find_if;
      39             : using ::std::remove_if;
      40             : using ::std::pair;
      41             : 
      42           0 : bool ScDBData::less::operator() (const ScDBData& left, const ScDBData& right) const
      43             : {
      44           0 :     return ScGlobal::GetpTransliteration()->compareString(left.GetUpperName(), right.GetUpperName()) < 0;
      45             : }
      46             : 
      47           0 : ScDBData::ScDBData( const OUString& rName,
      48             :                     SCTAB nTab,
      49             :                     SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
      50             :                     bool bByR, bool bHasH) :
      51           0 :     mpSortParam(new ScSortParam),
      52           0 :     mpQueryParam(new ScQueryParam),
      53           0 :     mpSubTotal(new ScSubTotalParam),
      54           0 :     mpImportParam(new ScImportParam),
      55             :     aName       (rName),
      56             :     aUpper      (rName),
      57             :     nTable      (nTab),
      58             :     nStartCol   (nCol1),
      59             :     nStartRow   (nRow1),
      60             :     nEndCol     (nCol2),
      61             :     nEndRow     (nRow2),
      62             :     bByRow      (bByR),
      63             :     bHasHeader  (bHasH),
      64             :     bDoSize     (false),
      65             :     bKeepFmt    (false),
      66             :     bStripData  (false),
      67             :     bIsAdvanced (false),
      68             :     bDBSelection(false),
      69             :     nIndex      (0),
      70             :     bAutoFilter (false),
      71           0 :     bModified   (false)
      72             : {
      73           0 :     aUpper = ScGlobal::pCharClass->uppercase(aUpper);
      74           0 : }
      75             : 
      76           0 : ScDBData::ScDBData( const ScDBData& rData ) :
      77             :     ScRefreshTimer      ( rData ),
      78           0 :     mpSortParam(new ScSortParam(*rData.mpSortParam)),
      79           0 :     mpQueryParam(new ScQueryParam(*rData.mpQueryParam)),
      80           0 :     mpSubTotal(new ScSubTotalParam(*rData.mpSubTotal)),
      81           0 :     mpImportParam(new ScImportParam(*rData.mpImportParam)),
      82             :     aName               (rData.aName),
      83             :     aUpper              (rData.aUpper),
      84             :     nTable              (rData.nTable),
      85             :     nStartCol           (rData.nStartCol),
      86             :     nStartRow           (rData.nStartRow),
      87             :     nEndCol             (rData.nEndCol),
      88             :     nEndRow             (rData.nEndRow),
      89             :     bByRow              (rData.bByRow),
      90             :     bHasHeader          (rData.bHasHeader),
      91             :     bDoSize             (rData.bDoSize),
      92             :     bKeepFmt            (rData.bKeepFmt),
      93             :     bStripData          (rData.bStripData),
      94             :     bIsAdvanced         (rData.bIsAdvanced),
      95             :     aAdvSource          (rData.aAdvSource),
      96             :     bDBSelection        (rData.bDBSelection),
      97             :     nIndex              (rData.nIndex),
      98             :     bAutoFilter         (rData.bAutoFilter),
      99           0 :     bModified           (rData.bModified)
     100             : {
     101           0 : }
     102             : 
     103           0 : ScDBData::ScDBData( const OUString& rName, const ScDBData& rData ) :
     104             :     ScRefreshTimer      ( rData ),
     105           0 :     mpSortParam(new ScSortParam(*rData.mpSortParam)),
     106           0 :     mpQueryParam(new ScQueryParam(*rData.mpQueryParam)),
     107           0 :     mpSubTotal(new ScSubTotalParam(*rData.mpSubTotal)),
     108           0 :     mpImportParam(new ScImportParam(*rData.mpImportParam)),
     109             :     aName               (rName),
     110             :     aUpper              (rName),
     111             :     nTable              (rData.nTable),
     112             :     nStartCol           (rData.nStartCol),
     113             :     nStartRow           (rData.nStartRow),
     114             :     nEndCol             (rData.nEndCol),
     115             :     nEndRow             (rData.nEndRow),
     116             :     bByRow              (rData.bByRow),
     117             :     bHasHeader          (rData.bHasHeader),
     118             :     bDoSize             (rData.bDoSize),
     119             :     bKeepFmt            (rData.bKeepFmt),
     120             :     bStripData          (rData.bStripData),
     121             :     bIsAdvanced         (rData.bIsAdvanced),
     122             :     aAdvSource          (rData.aAdvSource),
     123             :     bDBSelection        (rData.bDBSelection),
     124             :     nIndex              (rData.nIndex),
     125             :     bAutoFilter         (rData.bAutoFilter),
     126           0 :     bModified           (rData.bModified)
     127             : {
     128           0 :     aUpper = ScGlobal::pCharClass->uppercase(aUpper);
     129           0 : }
     130             : 
     131           0 : ScDBData& ScDBData::operator= (const ScDBData& rData)
     132             : {
     133             :     // Don't modify the name.  The name is not mutable as it is used as a key
     134             :     // in the container to keep the db ranges sorted by the name.
     135           0 :     ScRefreshTimer::operator=( rData );
     136           0 :     mpSortParam.reset(new ScSortParam(*rData.mpSortParam));
     137           0 :     mpQueryParam.reset(new ScQueryParam(*rData.mpQueryParam));
     138           0 :     mpSubTotal.reset(new ScSubTotalParam(*rData.mpSubTotal));
     139           0 :     mpImportParam.reset(new ScImportParam(*rData.mpImportParam));
     140           0 :     nTable              = rData.nTable;
     141           0 :     nStartCol           = rData.nStartCol;
     142           0 :     nStartRow           = rData.nStartRow;
     143           0 :     nEndCol             = rData.nEndCol;
     144           0 :     nEndRow             = rData.nEndRow;
     145           0 :     bByRow              = rData.bByRow;
     146           0 :     bHasHeader          = rData.bHasHeader;
     147           0 :     bDoSize             = rData.bDoSize;
     148           0 :     bKeepFmt            = rData.bKeepFmt;
     149           0 :     bStripData          = rData.bStripData;
     150           0 :     bIsAdvanced         = rData.bIsAdvanced;
     151           0 :     aAdvSource          = rData.aAdvSource;
     152           0 :     bDBSelection        = rData.bDBSelection;
     153           0 :     nIndex              = rData.nIndex;
     154           0 :     bAutoFilter         = rData.bAutoFilter;
     155             : 
     156           0 :     return *this;
     157             : }
     158             : 
     159           0 : bool ScDBData::operator== (const ScDBData& rData) const
     160             : {
     161             :     //  Daten, die nicht in den Params sind
     162             : 
     163           0 :     if ( nTable     != rData.nTable     ||
     164           0 :          bDoSize    != rData.bDoSize    ||
     165           0 :          bKeepFmt   != rData.bKeepFmt   ||
     166           0 :          bIsAdvanced!= rData.bIsAdvanced||
     167           0 :          bStripData != rData.bStripData ||
     168             : //       SAB: I think this should be here, but I don't want to break something
     169             : //         bAutoFilter!= rData.bAutoFilter||
     170           0 :          ScRefreshTimer::operator!=( rData )
     171             :         )
     172           0 :         return false;
     173             : 
     174           0 :     if ( bIsAdvanced && aAdvSource != rData.aAdvSource )
     175           0 :         return false;
     176             : 
     177           0 :     ScSortParam aSort1, aSort2;
     178           0 :     GetSortParam(aSort1);
     179           0 :     rData.GetSortParam(aSort2);
     180           0 :     if (!(aSort1 == aSort2))
     181           0 :         return false;
     182             : 
     183           0 :     ScQueryParam aQuery1, aQuery2;
     184           0 :     GetQueryParam(aQuery1);
     185           0 :     rData.GetQueryParam(aQuery2);
     186           0 :     if (!(aQuery1 == aQuery2))
     187           0 :         return false;
     188             : 
     189           0 :     ScSubTotalParam aSubTotal1, aSubTotal2;
     190           0 :     GetSubTotalParam(aSubTotal1);
     191           0 :     rData.GetSubTotalParam(aSubTotal2);
     192           0 :     if (!(aSubTotal1 == aSubTotal2))
     193           0 :         return false;
     194             : 
     195           0 :     ScImportParam aImport1, aImport2;
     196           0 :     GetImportParam(aImport1);
     197           0 :     rData.GetImportParam(aImport2);
     198           0 :     if (!(aImport1 == aImport2))
     199           0 :         return false;
     200             : 
     201           0 :     return true;
     202             : }
     203             : 
     204           0 : ScDBData::~ScDBData()
     205             : {
     206           0 :     StopRefreshTimer();
     207           0 : }
     208             : 
     209           0 : OUString ScDBData::GetSourceString() const
     210             : {
     211           0 :     OUStringBuffer aBuf;
     212           0 :     if (mpImportParam->bImport)
     213             :     {
     214           0 :         aBuf.append(mpImportParam->aDBName);
     215           0 :         aBuf.append('/');
     216           0 :         aBuf.append(mpImportParam->aStatement);
     217             :     }
     218           0 :     return aBuf.makeStringAndClear();
     219             : }
     220             : 
     221           0 : OUString ScDBData::GetOperations() const
     222             : {
     223           0 :     OUStringBuffer aBuf;
     224           0 :     if (mpQueryParam->GetEntryCount())
     225             :     {
     226           0 :         const ScQueryEntry& rEntry = mpQueryParam->GetEntry(0);
     227           0 :         if (rEntry.bDoQuery)
     228           0 :             aBuf.append(ScGlobal::GetRscString(STR_OPERATION_FILTER));
     229             :     }
     230             : 
     231           0 :     if (mpSortParam->maKeyState[0].bDoSort)
     232             :     {
     233           0 :         if (!aBuf.isEmpty())
     234           0 :             aBuf.append(", ");
     235           0 :         aBuf.append(ScGlobal::GetRscString(STR_OPERATION_SORT));
     236             :     }
     237             : 
     238           0 :     if (mpSubTotal->bGroupActive[0] && !mpSubTotal->bRemoveOnly)
     239             :     {
     240           0 :         if (!aBuf.isEmpty())
     241           0 :             aBuf.append(", ");
     242           0 :         aBuf.append(ScGlobal::GetRscString(STR_OPERATION_SUBTOTAL));
     243             :     }
     244             : 
     245           0 :     if (aBuf.isEmpty())
     246           0 :         aBuf.append(ScGlobal::GetRscString(STR_OPERATION_NONE));
     247             : 
     248           0 :     return aBuf.makeStringAndClear();
     249             : }
     250             : 
     251           0 : void ScDBData::GetArea(SCTAB& rTab, SCCOL& rCol1, SCROW& rRow1, SCCOL& rCol2, SCROW& rRow2) const
     252             : {
     253           0 :     rTab  = nTable;
     254           0 :     rCol1 = nStartCol;
     255           0 :     rRow1 = nStartRow;
     256           0 :     rCol2 = nEndCol;
     257           0 :     rRow2 = nEndRow;
     258           0 : }
     259             : 
     260           0 : void ScDBData::GetArea(ScRange& rRange) const
     261             : {
     262           0 :     SCROW nNewEndRow = nEndRow;
     263           0 :     rRange = ScRange( nStartCol, nStartRow, nTable, nEndCol, nNewEndRow, nTable );
     264           0 : }
     265             : 
     266           0 : void ScDBData::SetArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
     267             : {
     268           0 :     nTable  = nTab;
     269           0 :     nStartCol = nCol1;
     270           0 :     nStartRow = nRow1;
     271           0 :     nEndCol   = nCol2;
     272           0 :     nEndRow   = nRow2;
     273           0 : }
     274             : 
     275           0 : void ScDBData::MoveTo(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
     276             : {
     277             :     sal_uInt16 i;
     278           0 :     long nDifX = ((long) nCol1) - ((long) nStartCol);
     279           0 :     long nDifY = ((long) nRow1) - ((long) nStartRow);
     280             : 
     281           0 :     long nSortDif = bByRow ? nDifX : nDifY;
     282           0 :     long nSortEnd = bByRow ? static_cast<long>(nCol2) : static_cast<long>(nRow2);
     283             : 
     284           0 :     for (i=0; i<mpSortParam->GetSortKeyCount(); i++)
     285             :     {
     286           0 :         mpSortParam->maKeyState[i].nField += nSortDif;
     287           0 :         if (mpSortParam->maKeyState[i].nField > nSortEnd)
     288             :         {
     289           0 :             mpSortParam->maKeyState[i].nField = 0;
     290           0 :             mpSortParam->maKeyState[i].bDoSort = false;
     291             :         }
     292             :     }
     293             : 
     294           0 :     SCSIZE nCount = mpQueryParam->GetEntryCount();
     295           0 :     for (i = 0; i < nCount; ++i)
     296             :     {
     297           0 :         ScQueryEntry& rEntry = mpQueryParam->GetEntry(i);
     298           0 :         rEntry.nField += nDifX;
     299           0 :         if (rEntry.nField > nCol2)
     300             :         {
     301           0 :             rEntry.nField = 0;
     302           0 :             rEntry.bDoQuery = false;
     303             :         }
     304             :     }
     305           0 :     for (i=0; i<MAXSUBTOTAL; i++)
     306             :     {
     307           0 :         mpSubTotal->nField[i] = sal::static_int_cast<SCCOL>( mpSubTotal->nField[i] + nDifX );
     308           0 :         if (mpSubTotal->nField[i] > nCol2)
     309             :         {
     310           0 :             mpSubTotal->nField[i] = 0;
     311           0 :             mpSubTotal->bGroupActive[i] = false;
     312             :         }
     313             :     }
     314             : 
     315           0 :     SetArea( nTab, nCol1, nRow1, nCol2, nRow2 );
     316           0 : }
     317             : 
     318           0 : void ScDBData::GetSortParam( ScSortParam& rSortParam ) const
     319             : {
     320           0 :     rSortParam = *mpSortParam;
     321           0 :     rSortParam.nCol1 = nStartCol;
     322           0 :     rSortParam.nRow1 = nStartRow;
     323           0 :     rSortParam.nCol2 = nEndCol;
     324           0 :     rSortParam.nRow2 = nEndRow;
     325           0 :     rSortParam.bByRow = bByRow;
     326           0 :     rSortParam.bHasHeader = bHasHeader;
     327           0 : }
     328             : 
     329           0 : void ScDBData::SetSortParam( const ScSortParam& rSortParam )
     330             : {
     331           0 :     mpSortParam.reset(new ScSortParam(rSortParam));
     332           0 :     bByRow = rSortParam.bByRow;
     333           0 : }
     334             : 
     335           0 : void ScDBData::GetQueryParam( ScQueryParam& rQueryParam ) const
     336             : {
     337           0 :     rQueryParam = *mpQueryParam;
     338           0 :     rQueryParam.nCol1 = nStartCol;
     339           0 :     rQueryParam.nRow1 = nStartRow;
     340           0 :     rQueryParam.nCol2 = nEndCol;
     341           0 :     rQueryParam.nRow2 = nEndRow;
     342           0 :     rQueryParam.nTab  = nTable;
     343           0 :     rQueryParam.bByRow = bByRow;
     344           0 :     rQueryParam.bHasHeader = bHasHeader;
     345           0 : }
     346             : 
     347           0 : void ScDBData::SetQueryParam(const ScQueryParam& rQueryParam)
     348             : {
     349           0 :     mpQueryParam.reset(new ScQueryParam(rQueryParam));
     350             : 
     351             :     //  set bIsAdvanced to false for everything that is not from the
     352             :     //  advanced filter dialog
     353           0 :     bIsAdvanced = false;
     354           0 : }
     355             : 
     356           0 : void ScDBData::SetAdvancedQuerySource(const ScRange* pSource)
     357             : {
     358           0 :     if (pSource)
     359             :     {
     360           0 :         aAdvSource = *pSource;
     361           0 :         bIsAdvanced = true;
     362             :     }
     363             :     else
     364           0 :         bIsAdvanced = false;
     365           0 : }
     366             : 
     367           0 : bool ScDBData::GetAdvancedQuerySource(ScRange& rSource) const
     368             : {
     369           0 :     rSource = aAdvSource;
     370           0 :     return bIsAdvanced;
     371             : }
     372             : 
     373           0 : void ScDBData::GetSubTotalParam(ScSubTotalParam& rSubTotalParam) const
     374             : {
     375           0 :     rSubTotalParam = *mpSubTotal;
     376             : 
     377             :     // Share the data range with the parent db data.  The range in the subtotal
     378             :     // param struct is not used.
     379           0 :     rSubTotalParam.nCol1 = nStartCol;
     380           0 :     rSubTotalParam.nRow1 = nStartRow;
     381           0 :     rSubTotalParam.nCol2 = nEndCol;
     382           0 :     rSubTotalParam.nRow2 = nEndRow;
     383           0 : }
     384             : 
     385           0 : void ScDBData::SetSubTotalParam(const ScSubTotalParam& rSubTotalParam)
     386             : {
     387           0 :     mpSubTotal.reset(new ScSubTotalParam(rSubTotalParam));
     388           0 : }
     389             : 
     390           0 : void ScDBData::GetImportParam(ScImportParam& rImportParam) const
     391             : {
     392           0 :     rImportParam = *mpImportParam;
     393             :     // set the range.
     394           0 :     rImportParam.nCol1 = nStartCol;
     395           0 :     rImportParam.nRow1 = nStartRow;
     396           0 :     rImportParam.nCol2 = nEndCol;
     397           0 :     rImportParam.nRow2 = nEndRow;
     398           0 : }
     399             : 
     400           0 : void ScDBData::SetImportParam(const ScImportParam& rImportParam)
     401             : {
     402             :     // the range is ignored.
     403           0 :     mpImportParam.reset(new ScImportParam(rImportParam));
     404           0 : }
     405             : 
     406           0 : bool ScDBData::IsDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bStartOnly) const
     407             : {
     408           0 :     if (nTab == nTable)
     409             :     {
     410           0 :         if ( bStartOnly )
     411           0 :             return ( nCol == nStartCol && nRow == nStartRow );
     412             :         else
     413           0 :             return ( nCol >= nStartCol && nCol <= nEndCol &&
     414           0 :                      nRow >= nStartRow && nRow <= nEndRow );
     415             :     }
     416             : 
     417           0 :     return false;
     418             : }
     419             : 
     420           0 : bool ScDBData::IsDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
     421             : {
     422           0 :     return (bool)((nTab == nTable)
     423           0 :                     && (nCol1 == nStartCol) && (nRow1 == nStartRow)
     424           0 :                     && (nCol2 == nEndCol) && (nRow2 == nEndRow));
     425             : }
     426             : 
     427           0 : bool ScDBData::HasImportParam() const
     428             : {
     429           0 :     return mpImportParam && mpImportParam->bImport;
     430             : }
     431             : 
     432           0 : bool ScDBData::HasQueryParam() const
     433             : {
     434           0 :     if (!mpQueryParam)
     435           0 :         return false;
     436             : 
     437           0 :     if (!mpQueryParam->GetEntryCount())
     438           0 :         return false;
     439             : 
     440           0 :     return mpQueryParam->GetEntry(0).bDoQuery;
     441             : }
     442             : 
     443           0 : bool ScDBData::HasSortParam() const
     444             : {
     445           0 :     return mpSortParam &&
     446           0 :         !mpSortParam->maKeyState.empty() &&
     447           0 :         mpSortParam->maKeyState[0].bDoSort;
     448             : }
     449             : 
     450           0 : bool ScDBData::HasSubTotalParam() const
     451             : {
     452           0 :     return mpSubTotal && mpSubTotal->bGroupActive[0];
     453             : }
     454             : 
     455           0 : void ScDBData::UpdateMoveTab(SCTAB nOldPos, SCTAB nNewPos)
     456             : {
     457           0 :         ScRange aRange;
     458           0 :         GetArea( aRange );
     459           0 :         SCTAB nTab = aRange.aStart.Tab();               // hat nur eine Tabelle
     460             : 
     461             :         //  anpassen wie die aktuelle Tabelle bei ScTablesHint (tabvwsh5.cxx)
     462             : 
     463           0 :         if ( nTab == nOldPos )                          // verschobene Tabelle
     464           0 :             nTab = nNewPos;
     465           0 :         else if ( nOldPos < nNewPos )                   // nach hinten verschoben
     466             :         {
     467           0 :             if ( nTab > nOldPos && nTab <= nNewPos )    // nachrueckender Bereich
     468           0 :                 --nTab;
     469             :         }
     470             :         else                                            // nach vorne verschoben
     471             :         {
     472           0 :             if ( nTab >= nNewPos && nTab < nOldPos )    // nachrueckender Bereich
     473           0 :                 ++nTab;
     474             :         }
     475             : 
     476           0 :         bool bChanged = ( nTab != aRange.aStart.Tab() );
     477           0 :         if (bChanged)
     478           0 :             SetArea( nTab, aRange.aStart.Col(), aRange.aStart.Row(),
     479           0 :                                     aRange.aEnd.Col(),aRange.aEnd .Row() );
     480             : 
     481             :         //  MoveTo ist nicht noetig, wenn nur die Tabelle geaendert ist
     482             : 
     483           0 :         SetModified(bChanged);
     484             : 
     485           0 : }
     486             : 
     487           0 : void ScDBData::UpdateReference(ScDocument* pDoc, UpdateRefMode eUpdateRefMode,
     488             :                                 SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
     489             :                                 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
     490             :                                 SCsCOL nDx, SCsROW nDy, SCsTAB nDz)
     491             : {
     492             :     SCCOL theCol1;
     493             :     SCROW theRow1;
     494             :     SCTAB theTab1;
     495             :     SCCOL theCol2;
     496             :     SCROW theRow2;
     497             :     SCTAB theTab2;
     498           0 :     GetArea( theTab1, theCol1, theRow1, theCol2, theRow2 );
     499           0 :     theTab2 = theTab1;
     500             : 
     501             :     bool bDoUpdate = ScRefUpdate::Update( pDoc, eUpdateRefMode,
     502             :                                             nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
     503           0 :                                             theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) != UR_NOTHING;
     504           0 :     if (bDoUpdate)
     505           0 :         MoveTo( theTab1, theCol1, theRow1, theCol2, theRow2 );
     506             : 
     507           0 :     ScRange aRangeAdvSource;
     508           0 :     if ( GetAdvancedQuerySource(aRangeAdvSource) )
     509             :     {
     510           0 :         aRangeAdvSource.GetVars( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
     511           0 :         if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
     512             :                                     nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
     513           0 :                                     theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) )
     514             :         {
     515           0 :             aRangeAdvSource.aStart.Set( theCol1,theRow1,theTab1 );
     516           0 :             aRangeAdvSource.aEnd.Set( theCol2,theRow2,theTab2 );
     517           0 :             SetAdvancedQuerySource( &aRangeAdvSource );
     518             : 
     519           0 :             bDoUpdate = true;       // DBData is modified
     520             :         }
     521             :     }
     522             : 
     523           0 :     SetModified(bDoUpdate);
     524             : 
     525             :     //!     Testen, ob mitten aus dem Bereich geloescht/eingefuegt wurde !!!
     526           0 : }
     527             : 
     528           0 : void ScDBData::ExtendDataArea(ScDocument* pDoc)
     529             : {
     530             :     // Extend the DB area to include data rows immediately below.
     531             :     // or shrink it if all cells are empty
     532           0 :     pDoc->GetDataArea(nTable, nStartCol, nStartRow, nEndCol, nEndRow, false, true);
     533           0 : }
     534             : 
     535             : namespace {
     536             : 
     537             : class FindByTable : public unary_function<ScDBData, bool>
     538             : {
     539             :     SCTAB mnTab;
     540             : public:
     541           0 :     FindByTable(SCTAB nTab) : mnTab(nTab) {}
     542             : 
     543           0 :     bool operator() (const ScDBData& r) const
     544             :     {
     545           0 :         ScRange aRange;
     546           0 :         r.GetArea(aRange);
     547           0 :         return aRange.aStart.Tab() == mnTab;
     548             :     }
     549             : };
     550             : 
     551             : class UpdateRefFunc : public unary_function<ScDBData, void>
     552             : {
     553             :     ScDocument* mpDoc;
     554             :     UpdateRefMode meMode;
     555             :     SCCOL mnCol1;
     556             :     SCROW mnRow1;
     557             :     SCTAB mnTab1;
     558             :     SCCOL mnCol2;
     559             :     SCROW mnRow2;
     560             :     SCTAB mnTab2;
     561             :     SCsCOL mnDx;
     562             :     SCsROW mnDy;
     563             :     SCsTAB mnDz;
     564             : 
     565             : public:
     566           0 :     UpdateRefFunc(ScDocument* pDoc, UpdateRefMode eMode,
     567             :                     SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
     568             :                     SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
     569             :                     SCsCOL nDx, SCsROW nDy, SCsTAB nDz) :
     570             :         mpDoc(pDoc), meMode(eMode),
     571             :         mnCol1(nCol1), mnRow1(nRow1), mnTab1(nTab1),
     572             :         mnCol2(nCol2), mnRow2(nRow2), mnTab2(nTab2),
     573           0 :         mnDx(nDx), mnDy(nDy), mnDz(nDz) {}
     574             : 
     575           0 :     void operator() (ScDBData& r)
     576             :     {
     577           0 :         r.UpdateReference(mpDoc, meMode, mnCol1, mnRow1, mnTab1, mnCol2, mnRow2, mnTab2, mnDx, mnDy, mnDz);
     578           0 :     }
     579             : };
     580             : 
     581             : class UpdateMoveTabFunc : public unary_function<ScDBData, void>
     582             : {
     583             :     SCTAB mnOldTab;
     584             :     SCTAB mnNewTab;
     585             : public:
     586           0 :     UpdateMoveTabFunc(SCTAB nOld, SCTAB nNew) : mnOldTab(nOld), mnNewTab(nNew) {}
     587           0 :     void operator() (ScDBData& r)
     588             :     {
     589           0 :         r.UpdateMoveTab(mnOldTab, mnNewTab);
     590           0 :     }
     591             : };
     592             : 
     593             : class FindByCursor : public unary_function<ScDBData, bool>
     594             : {
     595             :     SCCOL mnCol;
     596             :     SCROW mnRow;
     597             :     SCTAB mnTab;
     598             :     bool mbStartOnly;
     599             : public:
     600           0 :     FindByCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bStartOnly) :
     601           0 :         mnCol(nCol), mnRow(nRow), mnTab(nTab), mbStartOnly(bStartOnly) {}
     602             : 
     603           0 :     bool operator() (const ScDBData& r)
     604             :     {
     605           0 :         return r.IsDBAtCursor(mnCol, mnRow, mnTab, mbStartOnly);
     606             :     }
     607             : };
     608             : 
     609             : class FindByRange : public unary_function<ScDBData, bool>
     610             : {
     611             :     const ScRange& mrRange;
     612             : public:
     613           0 :     FindByRange(const ScRange& rRange) : mrRange(rRange) {}
     614             : 
     615           0 :     bool operator() (const ScDBData& r)
     616             :     {
     617             :         return r.IsDBAtArea(
     618           0 :             mrRange.aStart.Tab(), mrRange.aStart.Col(), mrRange.aStart.Row(), mrRange.aEnd.Col(), mrRange.aEnd.Row());
     619             :     }
     620             : };
     621             : 
     622             : class FindByIndex : public unary_function<ScDBData, bool>
     623             : {
     624             :     sal_uInt16 mnIndex;
     625             : public:
     626           0 :     FindByIndex(sal_uInt16 nIndex) : mnIndex(nIndex) {}
     627           0 :     bool operator() (const ScDBData& r) const
     628             :     {
     629           0 :         return r.GetIndex() == mnIndex;
     630             :     }
     631             : };
     632             : 
     633             : class FindByUpperName : public unary_function<ScDBData, bool>
     634             : {
     635             :     const OUString& mrName;
     636             : public:
     637           0 :     FindByUpperName(const OUString& rName) : mrName(rName) {}
     638           0 :     bool operator() (const ScDBData& r) const
     639             :     {
     640           0 :         return r.GetUpperName() == mrName;
     641             :     }
     642             : };
     643             : 
     644             : }
     645             : 
     646           0 : ScDBCollection::NamedDBs::NamedDBs(ScDBCollection& rParent, ScDocument& rDoc) :
     647           0 :     mrParent(rParent), mrDoc(rDoc) {}
     648             : 
     649           0 : ScDBCollection::NamedDBs::NamedDBs(const NamedDBs& r) :
     650           0 :     maDBs(r.maDBs), mrParent(r.mrParent), mrDoc(r.mrDoc) {}
     651             : 
     652           0 : ScDBCollection::NamedDBs::iterator ScDBCollection::NamedDBs::begin()
     653             : {
     654           0 :     return maDBs.begin();
     655             : }
     656             : 
     657           0 : ScDBCollection::NamedDBs::iterator ScDBCollection::NamedDBs::end()
     658             : {
     659           0 :     return maDBs.end();
     660             : }
     661             : 
     662           0 : ScDBCollection::NamedDBs::const_iterator ScDBCollection::NamedDBs::begin() const
     663             : {
     664           0 :     return maDBs.begin();
     665             : }
     666             : 
     667           0 : ScDBCollection::NamedDBs::const_iterator ScDBCollection::NamedDBs::end() const
     668             : {
     669           0 :     return maDBs.end();
     670             : }
     671             : 
     672           0 : ScDBData* ScDBCollection::NamedDBs::findByIndex(sal_uInt16 nIndex)
     673             : {
     674             :     DBsType::iterator itr = find_if(
     675           0 :         maDBs.begin(), maDBs.end(), FindByIndex(nIndex));
     676           0 :     return itr == maDBs.end() ? NULL : &(*itr);
     677             : }
     678             : 
     679           0 : ScDBData* ScDBCollection::NamedDBs::findByUpperName(const OUString& rName)
     680             : {
     681             :     DBsType::iterator itr = find_if(
     682           0 :         maDBs.begin(), maDBs.end(), FindByUpperName(rName));
     683           0 :     return itr == maDBs.end() ? NULL : &(*itr);
     684             : }
     685             : 
     686           0 : bool ScDBCollection::NamedDBs::insert(ScDBData* p)
     687             : {
     688             :     SAL_WNODEPRECATED_DECLARATIONS_PUSH
     689           0 :     auto_ptr<ScDBData> pData(p);
     690             :     SAL_WNODEPRECATED_DECLARATIONS_POP
     691           0 :     if (!pData->GetIndex())
     692           0 :         pData->SetIndex(mrParent.nEntryIndex++);
     693             : 
     694           0 :     pair<DBsType::iterator, bool> r = maDBs.insert(pData);
     695             : 
     696           0 :     if (r.second && p->HasImportParam() && !p->HasImportSelection())
     697             :     {
     698           0 :         p->SetRefreshHandler(mrParent.GetRefreshHandler());
     699           0 :         p->SetRefreshControl(mrDoc.GetRefreshTimerControlAddress());
     700             :     }
     701           0 :     return r.second;
     702             : }
     703             : 
     704           0 : void ScDBCollection::NamedDBs::erase(iterator itr)
     705             : {
     706           0 :     maDBs.erase(itr);
     707           0 : }
     708             : 
     709           0 : void ScDBCollection::NamedDBs::erase(const ScDBData& r)
     710             : {
     711           0 :     maDBs.erase(r);
     712           0 : }
     713             : 
     714           0 : bool ScDBCollection::NamedDBs::empty() const
     715             : {
     716           0 :     return maDBs.empty();
     717             : }
     718             : 
     719           0 : size_t ScDBCollection::NamedDBs::size() const
     720             : {
     721           0 :     return maDBs.size();
     722             : }
     723             : 
     724           0 : bool ScDBCollection::NamedDBs::operator== (const NamedDBs& r) const
     725             : {
     726           0 :     return maDBs == r.maDBs;
     727             : }
     728             : 
     729           0 : ScDBCollection::AnonDBs::iterator ScDBCollection::AnonDBs::begin()
     730             : {
     731           0 :     return maDBs.begin();
     732             : }
     733             : 
     734           0 : ScDBCollection::AnonDBs::iterator ScDBCollection::AnonDBs::end()
     735             : {
     736           0 :     return maDBs.end();
     737             : }
     738             : 
     739           0 : ScDBCollection::AnonDBs::const_iterator ScDBCollection::AnonDBs::begin() const
     740             : {
     741           0 :     return maDBs.begin();
     742             : }
     743             : 
     744           0 : ScDBCollection::AnonDBs::const_iterator ScDBCollection::AnonDBs::end() const
     745             : {
     746           0 :     return maDBs.end();
     747             : }
     748             : 
     749           0 : const ScDBData* ScDBCollection::AnonDBs::findAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bStartOnly) const
     750             : {
     751             :     DBsType::const_iterator itr = find_if(
     752           0 :         maDBs.begin(), maDBs.end(), FindByCursor(nCol, nRow, nTab, bStartOnly));
     753           0 :     return itr == maDBs.end() ? NULL : &(*itr);
     754             : }
     755             : 
     756           0 : const ScDBData* ScDBCollection::AnonDBs::findByRange(const ScRange& rRange) const
     757             : {
     758             :     DBsType::const_iterator itr = find_if(
     759           0 :         maDBs.begin(), maDBs.end(), FindByRange(rRange));
     760           0 :     return itr == maDBs.end() ? NULL : &(*itr);
     761             : }
     762             : 
     763           0 : ScDBData* ScDBCollection::AnonDBs::getByRange(const ScRange& rRange)
     764             : {
     765           0 :     const ScDBData* pData = findByRange(rRange);
     766           0 :     if (!pData)
     767             :     {
     768             :         // Insert a new db data.  They all have identical names.
     769           0 :         OUString aName(STR_DB_GLOBAL_NONAME);
     770             :         SAL_WNODEPRECATED_DECLARATIONS_PUSH
     771             :         ::std::auto_ptr<ScDBData> pNew(new ScDBData(
     772           0 :             aName, rRange.aStart.Tab(), rRange.aStart.Col(), rRange.aStart.Row(),
     773           0 :             rRange.aEnd.Col(), rRange.aEnd.Row(), true, false));
     774             :         SAL_WNODEPRECATED_DECLARATIONS_POP
     775           0 :         pData = pNew.get();
     776           0 :         maDBs.push_back(pNew);
     777             :     }
     778           0 :     return const_cast<ScDBData*>(pData);
     779             : }
     780             : 
     781           0 : void ScDBCollection::AnonDBs::insert(ScDBData* p)
     782             : {
     783             :     SAL_WNODEPRECATED_DECLARATIONS_PUSH
     784           0 :     ::std::auto_ptr<ScDBData> pNew(p);
     785             :         SAL_WNODEPRECATED_DECLARATIONS_POP
     786           0 :     maDBs.push_back(pNew);
     787           0 : }
     788             : 
     789           0 : bool ScDBCollection::AnonDBs::empty() const
     790             : {
     791           0 :     return maDBs.empty();
     792             : }
     793             : 
     794           0 : bool ScDBCollection::AnonDBs::operator== (const AnonDBs& r) const
     795             : {
     796           0 :     return maDBs == r.maDBs;
     797             : }
     798             : 
     799           0 : ScDBCollection::ScDBCollection(ScDocument* pDocument) :
     800           0 :     pDoc(pDocument), nEntryIndex(SC_START_INDEX_DB_COLL), maNamedDBs(*this, *pDocument) {}
     801             : 
     802           0 : ScDBCollection::ScDBCollection(const ScDBCollection& r) :
     803           0 :     pDoc(r.pDoc), nEntryIndex(r.nEntryIndex), maNamedDBs(r.maNamedDBs), maAnonDBs(r.maAnonDBs) {}
     804             : 
     805           0 : ScDBCollection::NamedDBs& ScDBCollection::getNamedDBs()
     806             : {
     807           0 :     return maNamedDBs;
     808             : }
     809             : 
     810           0 : const ScDBCollection::NamedDBs& ScDBCollection::getNamedDBs() const
     811             : {
     812           0 :     return maNamedDBs;
     813             : }
     814             : 
     815           0 : ScDBCollection::AnonDBs& ScDBCollection::getAnonDBs()
     816             : {
     817           0 :     return maAnonDBs;
     818             : }
     819             : 
     820           0 : const ScDBCollection::AnonDBs& ScDBCollection::getAnonDBs() const
     821             : {
     822           0 :     return maAnonDBs;
     823             : }
     824             : 
     825           0 : const ScDBData* ScDBCollection::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bStartOnly) const
     826             : {
     827             :     // First, search the global named db ranges.
     828             :     NamedDBs::DBsType::const_iterator itr = find_if(
     829           0 :         maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, bStartOnly));
     830           0 :     if (itr != maNamedDBs.end())
     831           0 :         return &(*itr);
     832             : 
     833             :     // Check for the sheet-local anonymous db range.
     834           0 :     const ScDBData* pNoNameData = pDoc->GetAnonymousDBData(nTab);
     835           0 :     if (pNoNameData)
     836           0 :         if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,bStartOnly))
     837           0 :             return pNoNameData;
     838             : 
     839             :     // Check the global anonymous db ranges.
     840           0 :     const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, bStartOnly);
     841           0 :     if (pData)
     842           0 :         return pData;
     843             : 
     844           0 :     return NULL;
     845             : }
     846             : 
     847           0 : ScDBData* ScDBCollection::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, bool bStartOnly)
     848             : {
     849             :     // First, search the global named db ranges.
     850             :     NamedDBs::DBsType::iterator itr = find_if(
     851           0 :         maNamedDBs.begin(), maNamedDBs.end(), FindByCursor(nCol, nRow, nTab, bStartOnly));
     852           0 :     if (itr != maNamedDBs.end())
     853           0 :         return &(*itr);
     854             : 
     855             :     // Check for the sheet-local anonymous db range.
     856           0 :     ScDBData* pNoNameData = pDoc->GetAnonymousDBData(nTab);
     857           0 :     if (pNoNameData)
     858           0 :         if (pNoNameData->IsDBAtCursor(nCol,nRow,nTab,bStartOnly))
     859           0 :             return pNoNameData;
     860             : 
     861             :     // Check the global anonymous db ranges.
     862           0 :     const ScDBData* pData = getAnonDBs().findAtCursor(nCol, nRow, nTab, bStartOnly);
     863           0 :     if (pData)
     864           0 :         return const_cast<ScDBData*>(pData);
     865             : 
     866           0 :     return NULL;
     867             : }
     868             : 
     869           0 : const ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
     870             : {
     871             :     // First, search the global named db ranges.
     872           0 :     ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
     873             :     NamedDBs::DBsType::const_iterator itr = find_if(
     874           0 :         maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
     875           0 :     if (itr != maNamedDBs.end())
     876           0 :         return &(*itr);
     877             : 
     878             :     // Check for the sheet-local anonymous db range.
     879           0 :     ScDBData* pNoNameData = pDoc->GetAnonymousDBData(nTab);
     880           0 :     if (pNoNameData)
     881           0 :         if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
     882           0 :             return pNoNameData;
     883             : 
     884             :     // Lastly, check the global anonymous db ranges.
     885           0 :     return maAnonDBs.findByRange(aRange);
     886             : }
     887             : 
     888           0 : ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
     889             : {
     890             :     // First, search the global named db ranges.
     891           0 :     ScRange aRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
     892             :     NamedDBs::DBsType::iterator itr = find_if(
     893           0 :         maNamedDBs.begin(), maNamedDBs.end(), FindByRange(aRange));
     894           0 :     if (itr != maNamedDBs.end())
     895           0 :         return &(*itr);
     896             : 
     897             :     // Check for the sheet-local anonymous db range.
     898           0 :     ScDBData* pNoNameData = pDoc->GetAnonymousDBData(nTab);
     899           0 :     if (pNoNameData)
     900           0 :         if (pNoNameData->IsDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2))
     901           0 :             return pNoNameData;
     902             : 
     903             :     // Lastly, check the global anonymous db ranges.
     904           0 :     const ScDBData* pData = getAnonDBs().findByRange(aRange);
     905           0 :     if (pData)
     906           0 :         return const_cast<ScDBData*>(pData);
     907             : 
     908           0 :     return NULL;
     909             : }
     910             : 
     911           0 : void ScDBCollection::DeleteOnTab( SCTAB nTab )
     912             : {
     913           0 :     FindByTable func(nTab);
     914             :     // First, collect the positions of all items that need to be deleted.
     915           0 :     ::std::vector<NamedDBs::DBsType::iterator> v;
     916             :     {
     917           0 :         NamedDBs::DBsType::iterator itr = maNamedDBs.begin(), itrEnd = maNamedDBs.end();
     918           0 :         for (; itr != itrEnd; ++itr)
     919             :         {
     920           0 :             if (func(*itr))
     921           0 :                 v.push_back(itr);
     922             :         }
     923             :     }
     924             : 
     925             :     // Delete them all.
     926           0 :     ::std::vector<NamedDBs::DBsType::iterator>::iterator itr = v.begin(), itrEnd = v.end();
     927           0 :     for (; itr != itrEnd; ++itr)
     928           0 :         maNamedDBs.erase(*itr);
     929             : 
     930           0 :     remove_if(maAnonDBs.begin(), maAnonDBs.end(), func);
     931           0 : }
     932             : 
     933           0 : void ScDBCollection::UpdateReference(UpdateRefMode eUpdateRefMode,
     934             :                                 SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
     935             :                                 SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
     936             :                                 SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
     937             : {
     938           0 :     ScDBData* pData = pDoc->GetAnonymousDBData(nTab1);
     939           0 :     if (pData)
     940             :     {
     941           0 :         if (nTab1 == nTab2 && nDz == 0)
     942             :         {
     943             :             pData->UpdateReference(
     944             :                 pDoc, eUpdateRefMode,
     945           0 :                 nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz);
     946             :         }
     947             :         else
     948             :         {
     949             :             //this will perhabs break undo
     950             :         }
     951             :     }
     952             : 
     953           0 :     UpdateRefFunc func(pDoc, eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz);
     954           0 :     for_each(maNamedDBs.begin(), maNamedDBs.end(), func);
     955           0 :     for_each(maAnonDBs.begin(), maAnonDBs.end(), func);
     956           0 : }
     957             : 
     958           0 : void ScDBCollection::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
     959             : {
     960           0 :     UpdateMoveTabFunc func(nOldPos, nNewPos);
     961           0 :     for_each(maNamedDBs.begin(), maNamedDBs.end(), func);
     962           0 :     for_each(maAnonDBs.begin(), maAnonDBs.end(), func);
     963           0 : }
     964             : 
     965           0 : ScDBData* ScDBCollection::GetDBNearCursor(SCCOL nCol, SCROW nRow, SCTAB nTab )
     966             : {
     967           0 :     ScDBData* pNearData = NULL;
     968           0 :     NamedDBs::DBsType::iterator itr = maNamedDBs.begin(), itrEnd = maNamedDBs.end();
     969           0 :     for (; itr != itrEnd; ++itr)
     970             :     {
     971             :         SCTAB nAreaTab;
     972             :         SCCOL nStartCol, nEndCol;
     973             :         SCROW nStartRow, nEndRow;
     974           0 :         itr->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
     975           0 :         if ( nTab == nAreaTab && nCol+1 >= nStartCol && nCol <= nEndCol+1 &&
     976           0 :                                  nRow+1 >= nStartRow && nRow <= nEndRow+1 )
     977             :         {
     978           0 :             if ( nCol < nStartCol || nCol > nEndCol || nRow < nStartRow || nRow > nEndRow )
     979             :             {
     980           0 :                 if (!pNearData)
     981           0 :                     pNearData = &(*itr);    // ersten angrenzenden Bereich merken
     982             :             }
     983             :             else
     984           0 :                 return &(*itr);             // nicht "unbenannt" und Cursor steht wirklich drin
     985             :         }
     986             :     }
     987           0 :     if (pNearData)
     988           0 :         return pNearData;               // angrenzender, wenn nichts direkt getroffen
     989           0 :     return pDoc->GetAnonymousDBData(nTab);                  // "unbenannt" nur zurueck, wenn sonst nichts gefunden
     990             : }
     991             : 
     992           0 : bool ScDBCollection::empty() const
     993             : {
     994           0 :     return maNamedDBs.empty() && maAnonDBs.empty();
     995             : }
     996             : 
     997           0 : bool ScDBCollection::operator== (const ScDBCollection& r) const
     998             : {
     999           0 :     return maNamedDBs == r.maNamedDBs && maAnonDBs == r.maAnonDBs &&
    1000           0 :         nEntryIndex == r.nEntryIndex && pDoc == r.pDoc && aRefreshHandler == r.aRefreshHandler;
    1001             : }
    1002             : 
    1003             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10