LCOV - code coverage report
Current view: top level - sc/source/core/data - documen4.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 323 696 46.4 %
Date: 2015-06-13 12:38:46 Functions: 21 35 60.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 <svl/intitem.hxx>
      21             : #include <svl/zforlist.hxx>
      22             : #include <formula/token.hxx>
      23             : 
      24             : #include "document.hxx"
      25             : #include "table.hxx"
      26             : #include "globstr.hrc"
      27             : #include "subtotal.hxx"
      28             : #include "docoptio.hxx"
      29             : #include "interpre.hxx"
      30             : #include "markdata.hxx"
      31             : #include "validat.hxx"
      32             : #include "scitems.hxx"
      33             : #include "stlpool.hxx"
      34             : #include "poolhelp.hxx"
      35             : #include "detdata.hxx"
      36             : #include "patattr.hxx"
      37             : #include "chgtrack.hxx"
      38             : #include "progress.hxx"
      39             : #include "paramisc.hxx"
      40             : #include "compiler.hxx"
      41             : #include "externalrefmgr.hxx"
      42             : #include "colorscale.hxx"
      43             : #include "attrib.hxx"
      44             : #include "formulacell.hxx"
      45             : #include "tokenarray.hxx"
      46             : #include "scmatrix.hxx"
      47             : #include <tokenstringcontext.hxx>
      48             : #include <boost/scoped_array.hpp>
      49             : 
      50             : using namespace formula;
      51             : 
      52             : /** (Goal Seek) Find a value of x that is a root of f(x)
      53             : 
      54             :     This function is used internally for the goal seek operation.  It uses the
      55             :     Regula Falsi (aka false position) algorithm to find a root of f(x).  The
      56             :     start value and the target value are to be given by the user in the
      57             :     goal seek dialog.  The f(x) in this case is defined as the formula in the
      58             :     formula cell minus target value.  This function may also perform additional
      59             :     search in the horizontal directions when the f(x) is discrete in order to
      60             :     ensure a non-zero slope necessary for deriving a subsequent x that is
      61             :     reasonably close to the root of interest.
      62             : 
      63             :     @change 24.10.2004 by Kohei Yoshida (kohei@openoffice.org)
      64             : 
      65             :     @see #i28955#
      66             : 
      67             :     @change 6 Aug 2013, fdo37341
      68             : */
      69           5 : bool ScDocument::Solver(SCCOL nFCol, SCROW nFRow, SCTAB nFTab,
      70             :                         SCCOL nVCol, SCROW nVRow, SCTAB nVTab,
      71             :                         const OUString& sValStr, double& nX)
      72             : {
      73           5 :     bool bRet = false;
      74           5 :     nX = 0.0;
      75          20 :     if ( ValidColRow( nFCol, nFRow ) && ValidTab( nFTab ) &&
      76          15 :          ValidColRow( nVCol, nVRow ) && ValidTab( nVTab ) &&
      77          15 :          nFTab < static_cast<SCTAB>( maTabs.size() ) && maTabs[nFTab] &&
      78          15 :          nVTab < static_cast<SCTAB>( maTabs.size() ) && maTabs[nVTab] )
      79             :     {
      80             :         CellType eFType, eVType;
      81           5 :         GetCellType(nFCol, nFRow, nFTab, eFType);
      82           5 :         GetCellType(nVCol, nVRow, nVTab, eVType);
      83             :         // #i108005# convert target value to number using default format,
      84             :         // as previously done in ScInterpreter::GetDouble
      85           5 :         ScFormulaCell* pFormula = NULL;
      86           5 :         double fTargetVal = 0.0;
      87           5 :         sal_uInt32 nFIndex = 0;
      88          10 :         if ( eFType == CELLTYPE_FORMULA && eVType == CELLTYPE_VALUE &&
      89           5 :              GetFormatTable()->IsNumberFormat( sValStr, nFIndex, fTargetVal ) )
      90             :         {
      91           5 :             ScAddress aFormulaAdr( nFCol, nFRow, nFTab );
      92           5 :             pFormula = GetFormulaCell( aFormulaAdr );
      93             :         }
      94           5 :         if (pFormula)
      95             :         {
      96           5 :             bool bDoneIteration = false;
      97           5 :             ScAddress aValueAdr( nVCol, nVRow, nVTab );
      98           5 :             double* pVCell = GetValueCell( aValueAdr );
      99             : 
     100           5 :             ScRange aVRange( aValueAdr, aValueAdr );    // for SetDirty
     101             :             // Original value to be restored later if necessary
     102           5 :             double fSaveVal = *pVCell;
     103             : 
     104           5 :             const sal_uInt16 nMaxIter = 100;
     105           5 :             const double fEps = 1E-10;
     106           5 :             const double fDelta = 1E-6;
     107             : 
     108             :             double fBestX, fXPrev;
     109             :             double fBestF, fFPrev;
     110           5 :             fBestX = fXPrev = fSaveVal;
     111             : 
     112           5 :             pFormula->Interpret();
     113           5 :             bool bError = ( pFormula->GetErrCode() != 0 );
     114             :             // bError always corresponds with fF
     115             : 
     116           5 :             fFPrev = pFormula->GetValue() - fTargetVal;
     117             : 
     118           5 :             fBestF = fabs( fFPrev );
     119           5 :             if ( fBestF < fDelta )
     120           0 :                 bDoneIteration = true;
     121             : 
     122           5 :             double fX = fXPrev + fEps;
     123           5 :             double fF = fFPrev;
     124             :             double fSlope;
     125             : 
     126           5 :             sal_uInt16 nIter = 0;
     127             : 
     128           5 :             bool bHorMoveError = false;
     129             :             // Conform Regula Falsi Method
     130         132 :             while ( !bDoneIteration && ( nIter++ < nMaxIter ) )
     131             :             {
     132         122 :                 *pVCell = fX;
     133         122 :                 SetDirty( aVRange, false );
     134         122 :                 pFormula->Interpret();
     135         122 :                 bError = ( pFormula->GetErrCode() != 0 );
     136         122 :                 fF = pFormula->GetValue() - fTargetVal;
     137             : 
     138         122 :                 if ( fF == fFPrev && !bError )
     139             :                 {
     140             :                     // HORIZONTAL SEARCH: Keep moving x in both directions until the f(x)
     141             :                     // becomes different from the previous f(x).  This routine is needed
     142             :                     // when a given function is discrete, in which case the resulting slope
     143             :                     // may become zero which ultimately causes the goal seek operation
     144             :                     // to fail. #i28955#
     145             : 
     146           0 :                     sal_uInt16 nHorIter = 0;
     147           0 :                     const double fHorStepAngle = 5.0;
     148           0 :                     const double fHorMaxAngle = 80.0;
     149           0 :                     int nHorMaxIter = static_cast<int>( fHorMaxAngle / fHorStepAngle );
     150           0 :                     bool bDoneHorMove = false;
     151             : 
     152           0 :                     while ( !bDoneHorMove && !bHorMoveError && nHorIter++ < nHorMaxIter )
     153             :                     {
     154           0 :                         double fHorAngle = fHorStepAngle * static_cast<double>( nHorIter );
     155           0 :                         double fHorTangent = ::rtl::math::tan( fHorAngle * F_PI / 180 );
     156             : 
     157           0 :                         sal_uInt16 nIdx = 0;
     158           0 :                         while( nIdx++ < 2 && !bDoneHorMove )
     159             :                         {
     160             :                             double fHorX;
     161           0 :                             if ( nIdx == 1 )
     162           0 :                                 fHorX = fX + fabs( fF ) * fHorTangent;
     163             :                             else
     164           0 :                                 fHorX = fX - fabs( fF ) * fHorTangent;
     165             : 
     166           0 :                             *pVCell = fHorX;
     167           0 :                             SetDirty( aVRange, false );
     168           0 :                             pFormula->Interpret();
     169           0 :                             bHorMoveError = ( pFormula->GetErrCode() != 0 );
     170           0 :                             if ( bHorMoveError )
     171           0 :                                 break;
     172             : 
     173           0 :                             fF = pFormula->GetValue() - fTargetVal;
     174           0 :                             if ( fF != fFPrev )
     175             :                             {
     176           0 :                                 fX = fHorX;
     177           0 :                                 bDoneHorMove = true;
     178             :                             }
     179             :                         }
     180             :                     }
     181           0 :                     if ( !bDoneHorMove )
     182           0 :                         bHorMoveError = true;
     183             :                 }
     184             : 
     185         122 :                 if ( bError )
     186             :                 {
     187             :                     // move closer to last valid value (fXPrev), keep fXPrev & fFPrev
     188          93 :                     double fDiff = ( fXPrev - fX ) / 2;
     189          93 :                     if ( fabs( fDiff ) < fEps )
     190           0 :                         fDiff = ( fDiff < 0.0 ? - fEps : fEps );
     191          93 :                     fX += fDiff;
     192             :                 }
     193          29 :                 else if ( bHorMoveError )
     194           0 :                     break;
     195          29 :                 else if ( fabs(fF) < fDelta )
     196             :                 {
     197             :                     // converged to root
     198           4 :                     fBestX = fX;
     199           4 :                     bDoneIteration = true;
     200             :                 }
     201             :                 else
     202             :                 {
     203          25 :                     if ( fabs(fF) + fDelta < fBestF )
     204             :                     {
     205          20 :                         fBestX = fX;
     206          20 :                         fBestF = fabs( fF );
     207             :                     }
     208             : 
     209          25 :                     if ( ( fXPrev - fX ) != 0 )
     210             :                     {
     211          25 :                         fSlope = ( fFPrev - fF ) / ( fXPrev - fX );
     212          25 :                         if ( fabs( fSlope ) < fEps )
     213           0 :                             fSlope = fSlope < 0.0 ? -fEps : fEps;
     214             :                     }
     215             :                     else
     216           0 :                         fSlope = fEps;
     217             : 
     218          25 :                     fXPrev = fX;
     219          25 :                     fFPrev = fF;
     220          25 :                     fX = fX - ( fF / fSlope );
     221             :                 }
     222             :             }
     223             : 
     224             :             // Try a nice rounded input value if possible.
     225           5 :             const double fNiceDelta = ( bDoneIteration && fabs( fBestX ) >= 1e-3 ? 1e-3 : fDelta );
     226           5 :             nX = ::rtl::math::approxFloor( ( fBestX / fNiceDelta ) + 0.5 ) * fNiceDelta;
     227             : 
     228           5 :             if ( bDoneIteration )
     229             :             {
     230           4 :                 *pVCell = nX;
     231           4 :                 SetDirty( aVRange, false );
     232           4 :                 pFormula->Interpret();
     233           4 :                 if ( fabs( pFormula->GetValue() - fTargetVal ) > fabs( fF ) )
     234           1 :                     nX = fBestX;
     235           4 :                 bRet = true;
     236             :             }
     237           1 :             else if ( bError || bHorMoveError )
     238             :             {
     239           1 :                 nX = fBestX;
     240             :             }
     241           5 :             *pVCell = fSaveVal;
     242           5 :             SetDirty( aVRange, false );
     243           5 :             pFormula->Interpret();
     244           5 :             if ( !bDoneIteration )
     245             :             {
     246           1 :                 SetError( nVCol, nVRow, nVTab, NOTAVAILABLE );
     247             :             }
     248             :         }
     249             :         else
     250             :         {
     251           0 :             SetError( nVCol, nVRow, nVTab, NOTAVAILABLE );
     252             :         }
     253             :     }
     254           5 :     return bRet;
     255             : }
     256             : 
     257          10 : void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1,
     258             :                                      SCCOL nCol2, SCROW nRow2,
     259             :                                      const ScMarkData& rMark,
     260             :                                      const OUString& rFormula,
     261             :                                      const ScTokenArray* pArr,
     262             :                                      const formula::FormulaGrammar::Grammar eGram,
     263             :                                      bool bDirtyFlag )
     264             : {
     265          10 :     PutInOrder(nCol1, nCol2);
     266          10 :     PutInOrder(nRow1, nRow2);
     267          10 :     nCol2 = std::min<SCCOL>(nCol2, MAXCOL);
     268          10 :     nRow2 = std::min<SCROW>(nRow2, MAXROW);
     269          10 :     if (!rMark.GetSelectCount())
     270             :     {
     271             :         SAL_WARN("sc", "ScDocument::InsertMatrixFormula: No table marked");
     272           0 :         return;
     273             :     }
     274             : 
     275          10 :     SCTAB nTab1 = *rMark.begin();
     276             : 
     277             :     ScFormulaCell* pCell;
     278          10 :     ScAddress aPos( nCol1, nRow1, nTab1 );
     279          10 :     if (pArr)
     280           2 :         pCell = new ScFormulaCell(this, aPos, *pArr, eGram, MM_FORMULA);
     281             :     else
     282           8 :         pCell = new ScFormulaCell( this, aPos, rFormula, eGram, MM_FORMULA );
     283          10 :     pCell->SetMatColsRows( nCol2 - nCol1 + 1, nRow2 - nRow1 + 1, bDirtyFlag );
     284          10 :     ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
     285          10 :     SCTAB nMax = static_cast<SCTAB>(maTabs.size());
     286          20 :     for (; itr != itrEnd && *itr < nMax; ++itr)
     287             :     {
     288          10 :         if (!maTabs[*itr])
     289           0 :             continue;
     290             : 
     291          10 :         if (*itr == nTab1)
     292             :         {
     293          10 :             pCell = maTabs[*itr]->SetFormulaCell(nCol1, nRow1, pCell);
     294          10 :             if (!pCell) //NULL if nCol1/nRow1 is invalid, which it can't be here
     295           0 :                 break;
     296             :         }
     297             :         else
     298           0 :             maTabs[*itr]->SetFormulaCell(
     299             :                 nCol1, nRow1,
     300             :                 new ScFormulaCell(
     301           0 :                     *pCell, *this, ScAddress(nCol1, nRow1, *itr), SC_CLONECELL_STARTLISTENING));
     302             :     }
     303             : 
     304          10 :     ScAddress aBasePos(nCol1, nRow1, nTab1);
     305             :     ScSingleRefData aRefData;
     306          10 :     aRefData.InitFlags();
     307          10 :     aRefData.SetColRel( true );
     308          10 :     aRefData.SetRowRel( true );
     309          10 :     aRefData.SetTabRel( true );
     310          10 :     aRefData.SetAddress(aBasePos, aBasePos);
     311             : 
     312          10 :     ScTokenArray aArr; // consists only of one single reference token.
     313          10 :     formula::FormulaToken* t = aArr.AddMatrixSingleReference( aRefData);
     314             : 
     315          10 :     itr = rMark.begin();
     316          20 :     for (; itr != itrEnd && *itr < nMax; ++itr)
     317             :     {
     318          10 :         SCTAB nTab = *itr;
     319          10 :         ScTable* pTab = FetchTable(nTab);
     320          10 :         if (!pTab)
     321           0 :             continue;
     322             : 
     323          10 :         if (nTab != nTab1)
     324             :         {
     325           0 :             aRefData.SetRelTab(nTab - aBasePos.Tab());
     326           0 :             *t->GetSingleRef() = aRefData;
     327             :         }
     328             : 
     329          26 :         for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
     330             :         {
     331          68 :             for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
     332             :             {
     333          52 :                 if (nCol == nCol1 && nRow == nRow1)
     334             :                     // Skip the base position.
     335          10 :                     continue;
     336             : 
     337             :                 // Token array must be cloned so that each formula cell receives its own copy.
     338          42 :                 aPos = ScAddress(nCol, nRow, nTab);
     339             :                 // Reference in each cell must point to the origin cell relative to the current cell.
     340          42 :                 aRefData.SetAddress(aBasePos, aPos);
     341          42 :                 *t->GetSingleRef() = aRefData;
     342          42 :                 boost::scoped_ptr<ScTokenArray> pTokArr(aArr.Clone());
     343          42 :                 pCell = new ScFormulaCell(this, aPos, *pTokArr, eGram, MM_REFERENCE);
     344          42 :                 pTab->SetFormulaCell(nCol, nRow, pCell);
     345          42 :             }
     346             :         }
     347          10 :     }
     348             : }
     349             : 
     350           5 : void ScDocument::InsertTableOp(const ScTabOpParam& rParam,  // multiple (repeated?) operation
     351             :                                SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
     352             :                                const ScMarkData& rMark)
     353             : {
     354           5 :     PutInOrder(nCol1, nCol2);
     355           5 :     PutInOrder(nRow1, nRow2);
     356             :     SCTAB i, nTab1;
     357             :     SCCOL j;
     358             :     SCROW k;
     359           5 :     i = 0;
     360           5 :     bool bStop = false;
     361           5 :     SCTAB nMax = static_cast<SCTAB>(maTabs.size());
     362           5 :     ScMarkData::const_iterator itr = rMark.begin(), itrEnd = rMark.end();
     363           5 :     for (; itr != itrEnd && *itr < nMax; ++itr)
     364             :     {
     365           5 :         if (maTabs[*itr])
     366             :         {
     367           5 :             i = *itr;
     368           5 :             bStop = true;
     369           5 :             break;
     370             :         }
     371             :     }
     372           5 :     nTab1 = i;
     373           5 :     if (!bStop)
     374             :     {
     375             :         OSL_FAIL("ScDocument::InsertTableOp: No table marked");
     376           5 :         return;
     377             :     }
     378             : 
     379           5 :     ScRefAddress aRef;
     380           5 :     OUStringBuffer aForString;
     381           5 :     aForString.append('=');
     382           5 :     aForString.append(ScCompiler::GetNativeSymbol(ocTableOp));
     383           5 :     aForString.append(ScCompiler::GetNativeSymbol( ocOpen));
     384             : 
     385           5 :     const OUString& sSep = ScCompiler::GetNativeSymbol( ocSep);
     386           5 :     if (rParam.meMode == ScTabOpParam::Column) // column only
     387             :     {
     388           3 :         aRef.Set( rParam.aRefFormulaCell.GetAddress(), true, false, false );
     389           3 :         aForString.append(aRef.GetRefString(this, nTab1));
     390           3 :         aForString.append(sSep);
     391           3 :         aForString.append(rParam.aRefColCell.GetRefString(this, nTab1));
     392           3 :         aForString.append(sSep);
     393           3 :         aRef.Set( nCol1, nRow1, nTab1, false, true, true );
     394           3 :         aForString.append(aRef.GetRefString(this, nTab1));
     395           3 :         nCol1++;
     396           3 :         nCol2 = std::min( nCol2, (SCCOL)(rParam.aRefFormulaEnd.Col() -
     397           3 :                     rParam.aRefFormulaCell.Col() + nCol1 + 1));
     398             :     }
     399           2 :     else if (rParam.meMode == ScTabOpParam::Row) // row only
     400             :     {
     401           1 :         aRef.Set( rParam.aRefFormulaCell.GetAddress(), false, true, false );
     402           1 :         aForString.append(aRef.GetRefString(this, nTab1));
     403           1 :         aForString.append(sSep);
     404           1 :         aForString.append(rParam.aRefRowCell.GetRefString(this, nTab1));
     405           1 :         aForString.append(sSep);
     406           1 :         aRef.Set( nCol1, nRow1, nTab1, true, false, true );
     407           1 :         aForString.append(aRef.GetRefString(this, nTab1));
     408           1 :         nRow1++;
     409           2 :         nRow2 = std::min( nRow2, (SCROW)(rParam.aRefFormulaEnd.Row() -
     410           2 :                     rParam.aRefFormulaCell.Row() + nRow1 + 1));
     411             :     }
     412             :     else // both
     413             :     {
     414           1 :         aForString.append(rParam.aRefFormulaCell.GetRefString(this, nTab1));
     415           1 :         aForString.append(sSep);
     416           1 :         aForString.append(rParam.aRefColCell.GetRefString(this, nTab1));
     417           1 :         aForString.append(sSep);
     418           1 :         aRef.Set( nCol1, nRow1 + 1, nTab1, false, true, true );
     419           1 :         aForString.append(aRef.GetRefString(this, nTab1));
     420           1 :         aForString.append(sSep);
     421           1 :         aForString.append(rParam.aRefRowCell.GetRefString(this, nTab1));
     422           1 :         aForString.append(sSep);
     423           1 :         aRef.Set( nCol1 + 1, nRow1, nTab1, true, false, true );
     424           1 :         aForString.append(aRef.GetRefString(this, nTab1));
     425           1 :         nCol1++; nRow1++;
     426             :     }
     427           5 :     aForString.append(ScCompiler::GetNativeSymbol( ocClose ));
     428             : 
     429             :     ScFormulaCell aRefCell( this, ScAddress( nCol1, nRow1, nTab1 ), aForString.makeStringAndClear(),
     430          10 :            formula::FormulaGrammar::GRAM_NATIVE, MM_NONE );
     431          16 :     for( j = nCol1; j <= nCol2; j++ )
     432          47 :         for( k = nRow1; k <= nRow2; k++ )
     433          72 :             for (i = 0; i < static_cast<SCTAB>(maTabs.size()); i++)
     434             :             {
     435          36 :                 itr = rMark.begin();
     436          72 :                 for (; itr != itrEnd && *itr < nMax; ++itr)
     437          36 :                 if( maTabs[*itr] )
     438          36 :                     maTabs[*itr]->SetFormulaCell(
     439          72 :                         j, k, new ScFormulaCell(aRefCell, *this, ScAddress(j, k, *itr), SC_CLONECELL_STARTLISTENING));
     440           5 :             }
     441             : }
     442             : 
     443             : namespace {
     444             : 
     445           0 : bool setCacheTableReferenced(formula::FormulaToken& rToken, ScExternalRefManager& rRefMgr, const ScAddress& rPos)
     446             : {
     447           0 :     switch (rToken.GetType())
     448             :     {
     449             :         case svExternalSingleRef:
     450             :             return rRefMgr.setCacheTableReferenced(
     451           0 :                 rToken.GetIndex(), rToken.GetString().getString(), 1);
     452             :         case svExternalDoubleRef:
     453             :         {
     454           0 :             const ScComplexRefData& rRef = *rToken.GetDoubleRef();
     455           0 :             ScRange aAbs = rRef.toAbs(rPos);
     456           0 :             size_t nSheets = aAbs.aEnd.Tab() - aAbs.aStart.Tab() + 1;
     457             :             return rRefMgr.setCacheTableReferenced(
     458           0 :                     rToken.GetIndex(), rToken.GetString().getString(), nSheets);
     459             :         }
     460             :         case svExternalName:
     461             :             /* TODO: external names aren't supported yet, but would
     462             :              * have to be marked as well, if so. Mechanism would be
     463             :              * different. */
     464             :             OSL_FAIL("ScDocument::MarkUsedExternalReferences: implement the svExternalName case!");
     465             :         default:
     466             :             ;
     467             :     }
     468           0 :     return false;
     469             : }
     470             : 
     471             : }
     472             : 
     473           0 : bool ScDocument::MarkUsedExternalReferences( ScTokenArray& rArr, const ScAddress& rPos )
     474             : {
     475           0 :     if (!rArr.GetLen())
     476           0 :         return false;
     477             : 
     478           0 :     ScExternalRefManager* pRefMgr = NULL;
     479           0 :     rArr.Reset();
     480           0 :     formula::FormulaToken* t = NULL;
     481           0 :     bool bAllMarked = false;
     482           0 :     while (!bAllMarked && (t = rArr.GetNextReferenceOrName()) != NULL)
     483             :     {
     484           0 :         if (t->IsExternalRef())
     485             :         {
     486           0 :             if (!pRefMgr)
     487           0 :                 pRefMgr = GetExternalRefManager();
     488             : 
     489           0 :             bAllMarked = setCacheTableReferenced(*t, *pRefMgr, rPos);
     490             :         }
     491           0 :         else if (t->GetType() == svIndex)
     492             :         {
     493             :             // this is a named range.  Check if the range contains an external
     494             :             // reference.
     495           0 :             ScRangeData* pRangeData = GetRangeName()->findByIndex(t->GetIndex());
     496           0 :             if (!pRangeData)
     497           0 :                 continue;
     498             : 
     499           0 :             ScTokenArray* pArray = pRangeData->GetCode();
     500           0 :             for (t = pArray->First(); t; t = pArray->Next())
     501             :             {
     502           0 :                 if (!t->IsExternalRef())
     503           0 :                     continue;
     504             : 
     505           0 :                 if (!pRefMgr)
     506           0 :                     pRefMgr = GetExternalRefManager();
     507             : 
     508           0 :                 bAllMarked = setCacheTableReferenced(*t, *pRefMgr, rPos);
     509             :             }
     510             :         }
     511             :     }
     512           0 :     return bAllMarked;
     513             : }
     514             : 
     515           0 : bool ScDocument::GetNextSpellingCell(SCCOL& nCol, SCROW& nRow, SCTAB nTab,
     516             :                         bool bInSel, const ScMarkData& rMark) const
     517             : {
     518           0 :     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
     519           0 :         return maTabs[nTab]->GetNextSpellingCell( nCol, nRow, bInSel, rMark );
     520             :     else
     521           0 :         return false;
     522             : }
     523             : 
     524          31 : bool ScDocument::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, SCTAB nTab,
     525             :                                         const ScMarkData& rMark )
     526             : {
     527          31 :     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
     528          31 :         return maTabs[nTab]->GetNextMarkedCell( rCol, rRow, rMark );
     529             :     else
     530           0 :         return false;
     531             : }
     532             : 
     533           0 : bool ScDocument::ReplaceStyle(const SvxSearchItem& rSearchItem,
     534             :                               SCCOL nCol, SCROW nRow, SCTAB nTab,
     535             :                               ScMarkData& rMark,
     536             :                               bool bIsUndoP)
     537             : {
     538           0 :     if (nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
     539           0 :         return maTabs[nTab]->ReplaceStyle(rSearchItem, nCol, nRow, rMark, bIsUndoP);
     540             :     else
     541           0 :         return false;
     542             : }
     543             : 
     544           7 : void ScDocument::CompileDBFormula()
     545             : {
     546           7 :     sc::CompileFormulaContext aCxt(this);
     547           7 :     TableContainer::iterator it = maTabs.begin();
     548          16 :     for (;it != maTabs.end(); ++it)
     549             :     {
     550           9 :         if (*it)
     551           9 :             (*it)->CompileDBFormula(aCxt);
     552           7 :     }
     553           7 : }
     554             : 
     555           7 : void ScDocument::CompileColRowNameFormula()
     556             : {
     557           7 :     sc::CompileFormulaContext aCxt(this);
     558           7 :     TableContainer::iterator it = maTabs.begin();
     559          14 :     for (;it != maTabs.end(); ++it)
     560             :     {
     561           7 :         if (*it)
     562           7 :             (*it)->CompileColRowNameFormula(aCxt);
     563           7 :     }
     564           7 : }
     565             : 
     566       15990 : void ScDocument::InvalidateTableArea()
     567             : {
     568       15990 :     TableContainer::iterator it = maTabs.begin();
     569       52478 :     for (;it != maTabs.end() && *it; ++it)
     570             :     {
     571       36488 :         (*it)->InvalidateTableArea();
     572       36488 :         if ( (*it)->IsScenario() )
     573           1 :             (*it)->InvalidateScenarioRanges();
     574             :     }
     575       15990 : }
     576             : 
     577           0 : sal_Int32 ScDocument::GetMaxStringLen( SCTAB nTab, SCCOL nCol,
     578             :         SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
     579             : {
     580           0 :     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
     581           0 :         return maTabs[nTab]->GetMaxStringLen( nCol, nRowStart, nRowEnd, eCharSet );
     582             :     else
     583           0 :         return 0;
     584             : }
     585             : 
     586           0 : sal_Int32 ScDocument::GetMaxNumberStringLen( sal_uInt16& nPrecision, SCTAB nTab,
     587             :                                     SCCOL nCol,
     588             :                                     SCROW nRowStart, SCROW nRowEnd ) const
     589             : {
     590           0 :     if (ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
     591           0 :         return maTabs[nTab]->GetMaxNumberStringLen( nPrecision, nCol,
     592           0 :             nRowStart, nRowEnd );
     593             :     else
     594           0 :         return 0;
     595             : }
     596             : 
     597         212 : bool ScDocument::GetSelectionFunction( ScSubTotalFunc eFunc,
     598             :                                         const ScAddress& rCursor, const ScMarkData& rMark,
     599             :                                         double& rResult )
     600             : {
     601         212 :     ScFunctionData aData(eFunc);
     602             : 
     603         212 :     ScMarkData aMark(rMark);
     604         212 :     aMark.MarkToMulti();
     605         212 :     if (!aMark.IsMultiMarked() && !aMark.IsCellMarked(rCursor.Col(), rCursor.Row(), false))
     606         194 :         aMark.SetMarkArea(rCursor);
     607             : 
     608         212 :     SCTAB nMax = static_cast<SCTAB>(maTabs.size());
     609         212 :     ScMarkData::const_iterator itr = aMark.begin(), itrEnd = aMark.end();
     610             : 
     611         424 :     for (; itr != itrEnd && *itr < nMax && !aData.bError; ++itr)
     612         212 :         if (maTabs[*itr])
     613         212 :             maTabs[*itr]->UpdateSelectionFunction(aData, aMark);
     614             : 
     615             :             //TODO: pass rMark to UpdateSelection Function !!!!!
     616             : 
     617         212 :     if (!aData.bError)
     618         212 :         switch (eFunc)
     619             :         {
     620             :             case SUBTOTAL_FUNC_SUM:
     621         185 :                 rResult = aData.nVal;
     622         185 :                 break;
     623             :             case SUBTOTAL_FUNC_SELECTION_COUNT:
     624           9 :                 rResult = aData.nCount;
     625           9 :                 break;
     626             :             case SUBTOTAL_FUNC_CNT:
     627             :             case SUBTOTAL_FUNC_CNT2:
     628           9 :                 rResult = aData.nCount;
     629           9 :                 break;
     630             :             case SUBTOTAL_FUNC_AVE:
     631           3 :                 if (aData.nCount)
     632           3 :                     rResult = aData.nVal / (double) aData.nCount;
     633             :                 else
     634           0 :                     aData.bError = true;
     635           3 :                 break;
     636             :             case SUBTOTAL_FUNC_MAX:
     637             :             case SUBTOTAL_FUNC_MIN:
     638           6 :                 if (aData.nCount)
     639           6 :                     rResult = aData.nVal;
     640             :                 else
     641           0 :                     aData.bError = true;
     642           6 :                 break;
     643             :             default:
     644             :             {
     645             :                 // added to avoid warnings
     646             :             }
     647             :         }
     648             : 
     649         212 :     if (aData.bError)
     650           0 :         rResult = 0.0;
     651             : 
     652         212 :     return !aData.bError;
     653             : }
     654             : 
     655          56 : double ScDocument::RoundValueAsShown( double fVal, sal_uInt32 nFormat ) const
     656             : {
     657             :     short nType;
     658         112 :     if ( (nType = GetFormatTable()->GetType( nFormat )) != css::util::NumberFormat::DATE
     659          56 :       && nType != css::util::NumberFormat::TIME && nType != css::util::NumberFormat::DATETIME )
     660             :     {
     661             :         short nPrecision;
     662          56 :         if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
     663             :         {
     664           0 :             nPrecision = (short)GetFormatTable()->GetFormatPrecision( nFormat );
     665           0 :             switch ( nType )
     666             :             {
     667             :                 case css::util::NumberFormat::PERCENT:      // 0.41% == 0.0041
     668           0 :                     nPrecision += 2;
     669           0 :                     break;
     670             :                 case css::util::NumberFormat::SCIENTIFIC:   // 1.23e-3 == 0.00123
     671             :                 {
     672           0 :                     if ( fVal > 0.0 )
     673           0 :                         nPrecision = sal::static_int_cast<short>( nPrecision - (short)floor( log10( fVal ) ) );
     674           0 :                     else if ( fVal < 0.0 )
     675           0 :                         nPrecision = sal::static_int_cast<short>( nPrecision - (short)floor( log10( -fVal ) ) );
     676           0 :                     break;
     677             :                 }
     678             :             }
     679             :         }
     680             :         else
     681             :         {
     682          56 :             nPrecision = (short)GetDocOptions().GetStdPrecision();
     683             :             // #i115512# no rounding for automatic decimals
     684          56 :             if (nPrecision == static_cast<short>(SvNumberFormatter::UNLIMITED_PRECISION))
     685           8 :                 return fVal;
     686             :         }
     687          48 :         double fRound = ::rtl::math::round( fVal, nPrecision );
     688          48 :         if ( ::rtl::math::approxEqual( fVal, fRound ) )
     689          42 :             return fVal;        // rounding might introduce some error
     690             :         else
     691           6 :             return fRound;
     692             :     }
     693             :     else
     694           0 :         return fVal;
     695             : }
     696             : 
     697             : // conditional formats and validation ranges
     698             : 
     699         171 : sal_uLong ScDocument::AddCondFormat( ScConditionalFormat* pNew, SCTAB nTab )
     700             : {
     701         171 :     if(!pNew)
     702           0 :         return 0;
     703             : 
     704         171 :     if(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
     705         171 :         return maTabs[nTab]->AddCondFormat( pNew );
     706             : 
     707           0 :     return 0;
     708             : }
     709             : 
     710          34 : sal_uLong ScDocument::AddValidationEntry( const ScValidationData& rNew )
     711             : {
     712          34 :     if (rNew.IsEmpty())
     713           0 :         return 0;                   // empty is always 0
     714             : 
     715          34 :     if (!pValidationList)
     716           7 :         pValidationList = new ScValidationDataList;
     717             : 
     718          34 :     sal_uLong nMax = 0;
     719          96 :     for( ScValidationDataList::iterator it = pValidationList->begin(); it != pValidationList->end(); ++it )
     720             :     {
     721          79 :         const ScValidationData* pData = *it;
     722          79 :         sal_uLong nKey = pData->GetKey();
     723          79 :         if ( pData->EqualEntries( rNew ) )
     724          17 :             return nKey;
     725          62 :         if ( nKey > nMax )
     726          62 :             nMax = nKey;
     727             :     }
     728             : 
     729             :     // might be called from ScPatternAttr::PutInPool; thus clone (real copy)
     730             : 
     731          17 :     sal_uLong nNewKey = nMax + 1;
     732          17 :     ScValidationData* pInsert = rNew.Clone(this);
     733          17 :     pInsert->SetKey( nNewKey );
     734          17 :     pValidationList->InsertNew( pInsert );
     735          17 :     return nNewKey;
     736             : }
     737             : 
     738         886 : const SfxPoolItem* ScDocument::GetEffItem(
     739             :                         SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich ) const
     740             : {
     741         886 :     const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
     742         886 :     if ( pPattern )
     743             :     {
     744         886 :         const SfxItemSet& rSet = pPattern->GetItemSet();
     745             :         const SfxPoolItem* pItem;
     746         886 :         if ( rSet.GetItemState( ATTR_CONDITIONAL, true, &pItem ) == SfxItemState::SET )
     747             :         {
     748           0 :             const std::vector<sal_uInt32>& rIndex = static_cast<const ScCondFormatItem&>(pPattern->GetItem(ATTR_CONDITIONAL)).GetCondFormatData();
     749           0 :             ScConditionalFormatList* pCondFormList = GetCondFormList( nTab );
     750           0 :             if (!rIndex.empty() && pCondFormList)
     751             :             {
     752           0 :                 for(std::vector<sal_uInt32>::const_iterator itr = rIndex.begin(), itrEnd = rIndex.end();
     753             :                         itr != itrEnd; ++itr)
     754             :                 {
     755           0 :                     const ScConditionalFormat* pForm = pCondFormList->GetFormat( *itr );
     756           0 :                     if ( pForm )
     757             :                     {
     758           0 :                         ScAddress aPos(nCol, nRow, nTab);
     759           0 :                         ScRefCellValue aCell;
     760           0 :                         aCell.assign(const_cast<ScDocument&>(*this), aPos);
     761           0 :                         OUString aStyle = pForm->GetCellStyle(aCell, aPos);
     762           0 :                         if (!aStyle.isEmpty())
     763             :                         {
     764           0 :                             SfxStyleSheetBase* pStyleSheet = xPoolHelper->GetStylePool()->Find(
     765           0 :                                     aStyle, SFX_STYLE_FAMILY_PARA );
     766           0 :                             if ( pStyleSheet && pStyleSheet->GetItemSet().GetItemState(
     767           0 :                                         nWhich, true, &pItem ) == SfxItemState::SET )
     768           0 :                                 return pItem;
     769           0 :                         }
     770             :                     }
     771             :                 }
     772             :             }
     773             :         }
     774         886 :         return &rSet.Get( nWhich );
     775             :     }
     776             :     OSL_FAIL("no pattern");
     777           0 :     return NULL;
     778             : }
     779             : 
     780        5478 : const SfxItemSet* ScDocument::GetCondResult( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
     781             : {
     782        5478 :     ScConditionalFormatList* pFormatList = GetCondFormList(nTab);
     783        5478 :     if (!pFormatList)
     784           0 :         return NULL;
     785             : 
     786        5478 :     ScAddress aPos(nCol, nRow, nTab);
     787        5478 :     ScRefCellValue aCell;
     788        5478 :     aCell.assign(const_cast<ScDocument&>(*this), aPos);
     789        5478 :     const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
     790             :     const std::vector<sal_uInt32>& rIndex =
     791        5478 :         static_cast<const ScCondFormatItem&>(pPattern->GetItem(ATTR_CONDITIONAL)).GetCondFormatData();
     792             : 
     793        5478 :     return GetCondResult(aCell, aPos, *pFormatList, rIndex);
     794             : }
     795             : 
     796       30707 : const SfxItemSet* ScDocument::GetCondResult(
     797             :     ScRefCellValue& rCell, const ScAddress& rPos, const ScConditionalFormatList& rList,
     798             :     const std::vector<sal_uInt32>& rIndex ) const
     799             : {
     800       30707 :     std::vector<sal_uInt32>::const_iterator itr = rIndex.begin(), itrEnd = rIndex.end();
     801       31142 :     for (; itr != itrEnd; ++itr)
     802             :     {
     803         695 :         const ScConditionalFormat* pForm = rList.GetFormat(*itr);
     804         695 :         if (!pForm)
     805           0 :             continue;
     806             : 
     807         695 :         const OUString& aStyle = pForm->GetCellStyle(rCell, rPos);
     808         695 :         if (!aStyle.isEmpty())
     809             :         {
     810             :             SfxStyleSheetBase* pStyleSheet =
     811         260 :                 xPoolHelper->GetStylePool()->Find(aStyle, SFX_STYLE_FAMILY_PARA);
     812             : 
     813         260 :             if (pStyleSheet)
     814         260 :                 return &pStyleSheet->GetItemSet();
     815             : 
     816             :             // if style is not there, treat like no condition
     817             :         }
     818             :     }
     819             : 
     820       30447 :     return NULL;
     821             : }
     822             : 
     823          27 : ScConditionalFormat* ScDocument::GetCondFormat(
     824             :                             SCCOL nCol, SCROW nRow, SCTAB nTab ) const
     825             : {
     826          27 :     sal_uInt32 nIndex = 0;
     827          27 :     const std::vector<sal_uInt32>& rCondFormats = static_cast<const ScCondFormatItem*>(GetAttr(nCol, nRow, nTab, ATTR_CONDITIONAL))->GetCondFormatData();
     828             : 
     829          27 :     if(!rCondFormats.empty())
     830          27 :         nIndex = rCondFormats[0];
     831             : 
     832          27 :     if (nIndex)
     833             :     {
     834          27 :         ScConditionalFormatList* pCondFormList = GetCondFormList(nTab);
     835          27 :         if (pCondFormList)
     836          27 :             return pCondFormList->GetFormat( nIndex );
     837             :         else
     838             :         {
     839             :             OSL_FAIL("pCondFormList is 0");
     840             :         }
     841             :     }
     842             : 
     843           0 :     return NULL;
     844             : }
     845             : 
     846      144501 : ScConditionalFormatList* ScDocument::GetCondFormList(SCTAB nTab) const
     847             : {
     848      144501 :     if(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
     849      144501 :         return maTabs[nTab]->GetCondFormList();
     850             : 
     851           0 :     return NULL;
     852             : }
     853             : 
     854          24 : void ScDocument::SetCondFormList( ScConditionalFormatList* pList, SCTAB nTab )
     855             : {
     856          24 :     if(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
     857          24 :         maTabs[nTab]->SetCondFormList(pList);
     858          24 : }
     859             : 
     860          83 : const ScValidationData* ScDocument::GetValidationEntry( sal_uLong nIndex ) const
     861             : {
     862          83 :     if ( pValidationList )
     863          83 :         return pValidationList->GetData( nIndex );
     864             :     else
     865           0 :         return NULL;
     866             : }
     867             : 
     868           0 : void ScDocument::DeleteConditionalFormat(sal_uLong nOldIndex, SCTAB nTab)
     869             : {
     870           0 :     if(ValidTab(nTab) && nTab < static_cast<SCTAB>(maTabs.size()) && maTabs[nTab])
     871           0 :         maTabs[nTab]->DeleteConditionalFormat(nOldIndex);
     872           0 : }
     873             : 
     874           0 : bool ScDocument::HasDetectiveOperations() const
     875             : {
     876           0 :     return pDetOpList && pDetOpList->Count();
     877             : }
     878             : 
     879          11 : void ScDocument::AddDetectiveOperation( const ScDetOpData& rData )
     880             : {
     881          11 :     if (!pDetOpList)
     882           6 :         pDetOpList = new ScDetOpList;
     883             : 
     884          11 :     pDetOpList->Append( new ScDetOpData( rData ) );
     885          11 : }
     886             : 
     887           0 : void ScDocument::ClearDetectiveOperations()
     888             : {
     889           0 :     delete pDetOpList;      // deletes also the entries
     890           0 :     pDetOpList = NULL;
     891           0 : }
     892             : 
     893           0 : void ScDocument::SetDetOpList(ScDetOpList* pNew)
     894             : {
     895           0 :     delete pDetOpList;      // deletes also the entries
     896           0 :     pDetOpList = pNew;
     897           0 : }
     898             : 
     899             : // Comparison of Documents
     900             : 
     901             : //  Pfriemel-Factors
     902             : #define SC_DOCCOMP_MAXDIFF  256
     903             : #define SC_DOCCOMP_MINGOOD  128
     904             : #define SC_DOCCOMP_COLUMNS  10
     905             : #define SC_DOCCOMP_ROWS     100
     906             : 
     907           0 : sal_uInt16 ScDocument::RowDifferences( SCROW nThisRow, SCTAB nThisTab,
     908             :                                     ScDocument& rOtherDoc, SCROW nOtherRow, SCTAB nOtherTab,
     909             :                                     SCCOL nMaxCol, SCCOLROW* pOtherCols )
     910             : {
     911           0 :     sal_uLong nDif = 0;
     912           0 :     sal_uLong nUsed = 0;
     913           0 :     for (SCCOL nThisCol=0; nThisCol<=nMaxCol; nThisCol++)
     914             :     {
     915             :         SCCOL nOtherCol;
     916           0 :         if ( pOtherCols )
     917           0 :             nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
     918             :         else
     919           0 :             nOtherCol = nThisCol;
     920             : 
     921           0 :         if (ValidCol(nOtherCol))    // only compare columns that are common to both docs
     922             :         {
     923           0 :             ScRefCellValue aThisCell, aOtherCell;
     924           0 :             aThisCell.assign(*this, ScAddress(nThisCol, nThisRow, nThisTab));
     925           0 :             aOtherCell.assign(rOtherDoc, ScAddress(nOtherCol, nOtherRow, nOtherTab));
     926           0 :             if (!aThisCell.equalsWithoutFormat(aOtherCell))
     927             :             {
     928           0 :                 if (!aThisCell.isEmpty() && !aOtherCell.isEmpty())
     929           0 :                     nDif += 3;
     930             :                 else
     931           0 :                     nDif += 4;      // content <-> empty counts more
     932             :             }
     933             : 
     934           0 :             if (!aThisCell.isEmpty() || !aOtherCell.isEmpty())
     935           0 :                 ++nUsed;
     936             :         }
     937             :     }
     938             : 
     939           0 :     if (nUsed > 0)
     940           0 :         return static_cast<sal_uInt16>((nDif*64)/nUsed);            // max.256 (SC_DOCCOMP_MAXDIFF)
     941             : 
     942             :     OSL_ENSURE(!nDif,"Diff withoud Used");
     943           0 :     return 0;
     944             : }
     945             : 
     946           0 : sal_uInt16 ScDocument::ColDifferences( SCCOL nThisCol, SCTAB nThisTab,
     947             :                                     ScDocument& rOtherDoc, SCCOL nOtherCol, SCTAB nOtherTab,
     948             :                                     SCROW nMaxRow, SCCOLROW* pOtherRows )
     949             : {
     950             : 
     951             :     //TODO: optimize e.g. with iterator?
     952             : 
     953           0 :     sal_uLong nDif = 0;
     954           0 :     sal_uLong nUsed = 0;
     955           0 :     for (SCROW nThisRow=0; nThisRow<=nMaxRow; nThisRow++)
     956             :     {
     957             :         SCROW nOtherRow;
     958           0 :         if ( pOtherRows )
     959           0 :             nOtherRow = pOtherRows[nThisRow];
     960             :         else
     961           0 :             nOtherRow = nThisRow;
     962             : 
     963           0 :         if (ValidRow(nOtherRow))    // only compare rows that are common to both docs
     964             :         {
     965           0 :             ScRefCellValue aThisCell, aOtherCell;
     966           0 :             aThisCell.assign(*this, ScAddress(nThisCol, nThisRow, nThisTab));
     967           0 :             aOtherCell.assign(rOtherDoc, ScAddress(nOtherCol, nOtherRow, nOtherTab));
     968           0 :             if (!aThisCell.equalsWithoutFormat(aOtherCell))
     969             :             {
     970           0 :                 if (!aThisCell.isEmpty() && !aOtherCell.isEmpty())
     971           0 :                     nDif += 3;
     972             :                 else
     973           0 :                     nDif += 4;      // content <-> empty counts more
     974             :             }
     975             : 
     976           0 :             if (!aThisCell.isEmpty() || !aOtherCell.isEmpty())
     977           0 :                 ++nUsed;
     978             :         }
     979             :     }
     980             : 
     981           0 :     if (nUsed > 0)
     982           0 :         return static_cast<sal_uInt16>((nDif*64)/nUsed);    // max.256
     983             : 
     984             :     OSL_ENSURE(!nDif,"Diff without Used");
     985           0 :     return 0;
     986             : }
     987             : 
     988           0 : void ScDocument::FindOrder( SCCOLROW* pOtherRows, SCCOLROW nThisEndRow, SCCOLROW nOtherEndRow,
     989             :                             bool bColumns, ScDocument& rOtherDoc, SCTAB nThisTab, SCTAB nOtherTab,
     990             :                             SCCOLROW nEndCol, SCCOLROW* pTranslate, ScProgress* pProgress, sal_uLong nProAdd )
     991             : {
     992             :     //  bColumns=true: rows are columns and vice versa
     993             : 
     994             :     SCCOLROW nMaxCont;                      // continue by how much
     995             :     SCCOLROW nMinGood;                      // what is a hit (incl.)
     996           0 :     if ( bColumns )
     997             :     {
     998           0 :         nMaxCont = SC_DOCCOMP_COLUMNS;      // 10 columns
     999           0 :         nMinGood = SC_DOCCOMP_MINGOOD;
    1000             : 
    1001             :         //TODO: additional pass with nMinGood = 0 ????
    1002             : 
    1003             :     }
    1004             :     else
    1005             :     {
    1006           0 :         nMaxCont = SC_DOCCOMP_ROWS;         // 100 rows
    1007           0 :         nMinGood = SC_DOCCOMP_MINGOOD;
    1008             :     }
    1009           0 :     bool bUseTotal = bColumns && !pTranslate;       // only for the 1st pass
    1010             : 
    1011           0 :     SCCOLROW nOtherRow = 0;
    1012             :     sal_uInt16 nComp;
    1013             :     SCCOLROW nThisRow;
    1014           0 :     bool bTotal = false;        // hold for several nThisRow
    1015           0 :     SCCOLROW nUnknown = 0;
    1016           0 :     for (nThisRow = 0; nThisRow <= nThisEndRow; nThisRow++)
    1017             :     {
    1018           0 :         SCCOLROW nTempOther = nOtherRow;
    1019           0 :         bool bFound = false;
    1020           0 :         sal_uInt16 nBest = SC_DOCCOMP_MAXDIFF;
    1021           0 :         SCCOLROW nMax = std::min( nOtherEndRow, static_cast<SCCOLROW>(( nTempOther + nMaxCont + nUnknown )) );
    1022           0 :         for (SCCOLROW i=nTempOther; i<=nMax && nBest>0; i++)    // stop at 0
    1023             :         {
    1024           0 :             if (bColumns)
    1025           0 :                 nComp = ColDifferences( static_cast<SCCOL>(nThisRow), nThisTab, rOtherDoc, static_cast<SCCOL>(i), nOtherTab, nEndCol, pTranslate );
    1026             :             else
    1027           0 :                 nComp = RowDifferences( nThisRow, nThisTab, rOtherDoc, i, nOtherTab, static_cast<SCCOL>(nEndCol), pTranslate );
    1028           0 :             if ( nComp < nBest && ( nComp <= nMinGood || bTotal ) )
    1029             :             {
    1030           0 :                 nTempOther = i;
    1031           0 :                 nBest = nComp;
    1032           0 :                 bFound = true;
    1033             :             }
    1034           0 :             if ( nComp < SC_DOCCOMP_MAXDIFF || bFound )
    1035           0 :                 bTotal = false;
    1036           0 :             else if ( i == nTempOther && bUseTotal )
    1037           0 :                 bTotal = true;                          // only at the very top
    1038             :         }
    1039           0 :         if ( bFound )
    1040             :         {
    1041           0 :             pOtherRows[nThisRow] = nTempOther;
    1042           0 :             nOtherRow = nTempOther + 1;
    1043           0 :             nUnknown = 0;
    1044             :         }
    1045             :         else
    1046             :         {
    1047           0 :             pOtherRows[nThisRow] = SCROW_MAX;
    1048           0 :             ++nUnknown;
    1049             :         }
    1050             : 
    1051           0 :         if (pProgress)
    1052           0 :             pProgress->SetStateOnPercent(nProAdd+static_cast<sal_uLong>(nThisRow));
    1053             :     }
    1054             : 
    1055             :     // fill in blocks that don't match
    1056             : 
    1057           0 :     SCROW nFillStart = 0;
    1058           0 :     SCROW nFillPos = 0;
    1059           0 :     bool bInFill = false;
    1060           0 :     for (nThisRow = 0; nThisRow <= nThisEndRow+1; nThisRow++)
    1061             :     {
    1062           0 :         SCROW nThisOther = ( nThisRow <= nThisEndRow ) ? pOtherRows[nThisRow] : (nOtherEndRow+1);
    1063           0 :         if ( ValidRow(nThisOther) )
    1064             :         {
    1065           0 :             if ( bInFill )
    1066             :             {
    1067           0 :                 if ( nThisOther > nFillStart )      // is there something to distribute?
    1068             :                 {
    1069           0 :                     SCROW nDiff1 = nThisOther - nFillStart;
    1070           0 :                     SCROW nDiff2 = nThisRow   - nFillPos;
    1071           0 :                     SCROW nMinDiff = std::min(nDiff1, nDiff2);
    1072           0 :                     for (SCROW i=0; i<nMinDiff; i++)
    1073           0 :                         pOtherRows[nFillPos+i] = nFillStart+i;
    1074             :                 }
    1075             : 
    1076           0 :                 bInFill = false;
    1077             :             }
    1078           0 :             nFillStart = nThisOther + 1;
    1079           0 :             nFillPos = nThisRow + 1;
    1080             :         }
    1081             :         else
    1082           0 :             bInFill = true;
    1083             :     }
    1084           0 : }
    1085             : 
    1086           0 : void ScDocument::CompareDocument( ScDocument& rOtherDoc )
    1087             : {
    1088           0 :     if (!pChangeTrack)
    1089           0 :         return;
    1090             : 
    1091           0 :     SCTAB nThisCount = GetTableCount();
    1092           0 :     SCTAB nOtherCount = rOtherDoc.GetTableCount();
    1093           0 :     boost::scoped_array<SCTAB> pOtherTabs(new SCTAB[nThisCount]);
    1094             :     SCTAB nThisTab;
    1095             : 
    1096             :     //  compare tables with identical names
    1097           0 :     OUString aThisName;
    1098           0 :     OUString aOtherName;
    1099           0 :     for (nThisTab=0; nThisTab<nThisCount; nThisTab++)
    1100             :     {
    1101           0 :         SCTAB nOtherTab = SCTAB_MAX;
    1102           0 :         if (!IsScenario(nThisTab))  // skip scenarios
    1103             :         {
    1104           0 :             GetName( nThisTab, aThisName );
    1105           0 :             for (SCTAB nTemp=0; nTemp<nOtherCount && nOtherTab>MAXTAB; nTemp++)
    1106           0 :                 if (!rOtherDoc.IsScenario(nTemp))
    1107             :                 {
    1108           0 :                     rOtherDoc.GetName( nTemp, aOtherName );
    1109           0 :                     if ( aThisName.equals(aOtherName) )
    1110           0 :                         nOtherTab = nTemp;
    1111             :                 }
    1112             :         }
    1113           0 :         pOtherTabs[nThisTab] = nOtherTab;
    1114             :     }
    1115             :     //  fill in, so that un-named tables don't get lost
    1116           0 :     SCTAB nFillStart = 0;
    1117           0 :     SCTAB nFillPos = 0;
    1118           0 :     bool bInFill = false;
    1119           0 :     for (nThisTab = 0; nThisTab <= nThisCount; nThisTab++)
    1120             :     {
    1121           0 :         SCTAB nThisOther = ( nThisTab < nThisCount ) ? pOtherTabs[nThisTab] : nOtherCount;
    1122           0 :         if ( ValidTab(nThisOther) )
    1123             :         {
    1124           0 :             if ( bInFill )
    1125             :             {
    1126           0 :                 if ( nThisOther > nFillStart )      // is there something to distribute?
    1127             :                 {
    1128           0 :                     SCTAB nDiff1 = nThisOther - nFillStart;
    1129           0 :                     SCTAB nDiff2 = nThisTab   - nFillPos;
    1130           0 :                     SCTAB nMinDiff = std::min(nDiff1, nDiff2);
    1131           0 :                     for (SCTAB i=0; i<nMinDiff; i++)
    1132           0 :                         if ( !IsScenario(nFillPos+i) && !rOtherDoc.IsScenario(nFillStart+i) )
    1133           0 :                             pOtherTabs[nFillPos+i] = nFillStart+i;
    1134             :                 }
    1135             : 
    1136           0 :                 bInFill = false;
    1137             :             }
    1138           0 :             nFillStart = nThisOther + 1;
    1139           0 :             nFillPos = nThisTab + 1;
    1140             :         }
    1141             :         else
    1142           0 :             bInFill = true;
    1143             :     }
    1144             : 
    1145             :     //  compare tables in the original order
    1146             : 
    1147           0 :     for (nThisTab=0; nThisTab<nThisCount; nThisTab++)
    1148             :     {
    1149           0 :         SCTAB nOtherTab = pOtherTabs[nThisTab];
    1150           0 :         if ( ValidTab(nOtherTab) )
    1151             :         {
    1152           0 :             SCCOL nThisEndCol = 0;
    1153           0 :             SCROW nThisEndRow = 0;
    1154           0 :             SCCOL nOtherEndCol = 0;
    1155           0 :             SCROW nOtherEndRow = 0;
    1156           0 :             GetCellArea( nThisTab, nThisEndCol, nThisEndRow );
    1157           0 :             rOtherDoc.GetCellArea( nOtherTab, nOtherEndCol, nOtherEndRow );
    1158           0 :             SCCOL nEndCol = std::max(nThisEndCol, nOtherEndCol);
    1159           0 :             SCROW nEndRow = std::max(nThisEndRow, nOtherEndRow);
    1160             :             SCCOL nThisCol;
    1161             :             SCROW nThisRow;
    1162             :             sal_uLong n1,n2;    // for AppendDeleteRange
    1163             : 
    1164             :             //TODO: one Progress over all tables ???
    1165             : 
    1166           0 :             OUString aTabName;
    1167           0 :             GetName( nThisTab, aTabName );
    1168           0 :             OUString aTemplate = ScGlobal::GetRscString(STR_PROGRESS_COMPARING);
    1169           0 :             sal_Int32 nIndex = 0;
    1170           0 :             OUStringBuffer aProText = aTemplate.getToken( 0, '#', nIndex );
    1171           0 :             aProText.append(aTabName);
    1172           0 :             nIndex = 0;
    1173           0 :             aProText.append(aTemplate.getToken( 1, '#', nIndex ));
    1174             :             ScProgress aProgress( GetDocumentShell(),
    1175           0 :                                         aProText.makeStringAndClear(), 3*nThisEndRow );  // 2x FindOrder, 1x here
    1176           0 :             long nProgressStart = 2*nThisEndRow;                    // start for here
    1177             : 
    1178           0 :             boost::scoped_array<SCCOLROW> pTempRows(new SCCOLROW[nThisEndRow+1]);
    1179           0 :             boost::scoped_array<SCCOLROW> pOtherRows(new SCCOLROW[nThisEndRow+1]);
    1180           0 :             boost::scoped_array<SCCOLROW> pOtherCols(new SCCOLROW[nThisEndCol+1]);
    1181             : 
    1182             :             //  find inserted/deleted columns/rows:
    1183             :             //  Two attempts:
    1184             :             //  1) compare original rows                    (pTempRows)
    1185             :             //  2) compare original columns                 (pOtherCols)
    1186             :             //     with this column order compare rows      (pOtherRows)
    1187             : 
    1188             :             //TODO: compare columns twice with different nMinGood ???
    1189             : 
    1190             :             // 1
    1191             :             FindOrder( pTempRows.get(), nThisEndRow, nOtherEndRow, false,
    1192           0 :                         rOtherDoc, nThisTab, nOtherTab, nEndCol, NULL, &aProgress, 0 );
    1193             :             // 2
    1194             :             FindOrder( pOtherCols.get(), nThisEndCol, nOtherEndCol, true,
    1195           0 :                         rOtherDoc, nThisTab, nOtherTab, nEndRow, NULL, NULL, 0 );
    1196             :             FindOrder( pOtherRows.get(), nThisEndRow, nOtherEndRow, false,
    1197             :                         rOtherDoc, nThisTab, nOtherTab, nThisEndCol,
    1198           0 :                        pOtherCols.get(), &aProgress, nThisEndRow );
    1199             : 
    1200           0 :             sal_uLong nMatch1 = 0;  // pTempRows, no columns
    1201           0 :             for (nThisRow = 0; nThisRow<=nThisEndRow; nThisRow++)
    1202           0 :                 if (ValidRow(pTempRows[nThisRow]))
    1203           0 :                     nMatch1 += SC_DOCCOMP_MAXDIFF -
    1204           0 :                                RowDifferences( nThisRow, nThisTab, rOtherDoc, pTempRows[nThisRow],
    1205           0 :                                                 nOtherTab, nEndCol, NULL );
    1206             : 
    1207           0 :             sal_uLong nMatch2 = 0;  // pOtherRows, pOtherCols
    1208           0 :             for (nThisRow = 0; nThisRow<=nThisEndRow; nThisRow++)
    1209           0 :                 if (ValidRow(pOtherRows[nThisRow]))
    1210           0 :                     nMatch2 += SC_DOCCOMP_MAXDIFF -
    1211           0 :                                RowDifferences( nThisRow, nThisTab, rOtherDoc, pOtherRows[nThisRow],
    1212           0 :                                                nOtherTab, nThisEndCol, pOtherCols.get() );
    1213             : 
    1214           0 :             if ( nMatch1 >= nMatch2 )           // without columns ?
    1215             :             {
    1216             :                 //  reset columns
    1217           0 :                 for (nThisCol = 0; nThisCol<=nThisEndCol; nThisCol++)
    1218           0 :                     pOtherCols[nThisCol] = nThisCol;
    1219             : 
    1220             :                 //  swap row-arrays (they get both deleted anyway)
    1221           0 :                 pTempRows.swap(pOtherRows);
    1222             :             }
    1223             :             else
    1224             :             {
    1225             :                 //  remains for pOtherCols, pOtherRows
    1226             :             }
    1227             : 
    1228             :             //  Generate Change-Actions
    1229             :             //  1) columns from the right
    1230             :             //  2) rows from below
    1231             :             //  3) single cells in normal order
    1232             : 
    1233             :             //  Actions for inserted/deleted columns
    1234             : 
    1235           0 :             SCCOL nLastOtherCol = static_cast<SCCOL>(nOtherEndCol + 1);
    1236             :             //  nThisEndCol ... 0
    1237           0 :             for ( nThisCol = nThisEndCol+1; nThisCol > 0; )
    1238             :             {
    1239           0 :                 --nThisCol;
    1240           0 :                 SCCOL nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
    1241           0 :                 if ( ValidCol(nOtherCol) && nOtherCol+1 < nLastOtherCol )
    1242             :                 {
    1243             :                     // gap -> deleted
    1244             :                     ScRange aDelRange( nOtherCol+1, 0, nOtherTab,
    1245           0 :                                         nLastOtherCol-1, MAXROW, nOtherTab );
    1246           0 :                     pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
    1247             :                 }
    1248           0 :                 if ( nOtherCol > MAXCOL )                       // inserted
    1249             :                 {
    1250             :                     //  combine
    1251           0 :                     if ( nThisCol == nThisEndCol || ValidCol(static_cast<SCCOL>(pOtherCols[nThisCol+1])) )
    1252             :                     {
    1253           0 :                         SCCOL nFirstNew = static_cast<SCCOL>(nThisCol);
    1254           0 :                         while ( nFirstNew > 0 && pOtherCols[nFirstNew-1] > MAXCOL )
    1255           0 :                             --nFirstNew;
    1256           0 :                         SCCOL nDiff = nThisCol - nFirstNew;
    1257             :                         ScRange aRange( nLastOtherCol, 0, nOtherTab,
    1258           0 :                                         nLastOtherCol+nDiff, MAXROW, nOtherTab );
    1259           0 :                         pChangeTrack->AppendInsert( aRange );
    1260             :                     }
    1261             :                 }
    1262             :                 else
    1263           0 :                     nLastOtherCol = nOtherCol;
    1264             :             }
    1265           0 :             if ( nLastOtherCol > 0 )                            // deleted at the very top
    1266             :             {
    1267             :                 ScRange aDelRange( 0, 0, nOtherTab,
    1268           0 :                                     nLastOtherCol-1, MAXROW, nOtherTab );
    1269           0 :                 pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
    1270             :             }
    1271             : 
    1272             :             //  Actions for inserted/deleted rows
    1273             : 
    1274           0 :             SCROW nLastOtherRow = nOtherEndRow + 1;
    1275             :             //  nThisEndRow ... 0
    1276           0 :             for ( nThisRow = nThisEndRow+1; nThisRow > 0; )
    1277             :             {
    1278           0 :                 --nThisRow;
    1279           0 :                 SCROW nOtherRow = pOtherRows[nThisRow];
    1280           0 :                 if ( ValidRow(nOtherRow) && nOtherRow+1 < nLastOtherRow )
    1281             :                 {
    1282             :                     // gap -> deleted
    1283             :                     ScRange aDelRange( 0, nOtherRow+1, nOtherTab,
    1284           0 :                                         MAXCOL, nLastOtherRow-1, nOtherTab );
    1285           0 :                     pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
    1286             :                 }
    1287           0 :                 if ( nOtherRow > MAXROW )                       // inserted
    1288             :                 {
    1289             :                     //  combine
    1290           0 :                     if ( nThisRow == nThisEndRow || ValidRow(pOtherRows[nThisRow+1]) )
    1291             :                     {
    1292           0 :                         SCROW nFirstNew = nThisRow;
    1293           0 :                         while ( nFirstNew > 0 && pOtherRows[nFirstNew-1] > MAXROW )
    1294           0 :                             --nFirstNew;
    1295           0 :                         SCROW nDiff = nThisRow - nFirstNew;
    1296             :                         ScRange aRange( 0, nLastOtherRow, nOtherTab,
    1297           0 :                                         MAXCOL, nLastOtherRow+nDiff, nOtherTab );
    1298           0 :                         pChangeTrack->AppendInsert( aRange );
    1299             :                     }
    1300             :                 }
    1301             :                 else
    1302           0 :                     nLastOtherRow = nOtherRow;
    1303             :             }
    1304           0 :             if ( nLastOtherRow > 0 )                            // deleted at the very top
    1305             :             {
    1306             :                 ScRange aDelRange( 0, 0, nOtherTab,
    1307           0 :                                     MAXCOL, nLastOtherRow-1, nOtherTab );
    1308           0 :                 pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
    1309             :             }
    1310             : 
    1311             :              //  walk rows to find single cells
    1312             : 
    1313           0 :             for (nThisRow = 0; nThisRow <= nThisEndRow; nThisRow++)
    1314             :             {
    1315           0 :                 SCROW nOtherRow = pOtherRows[nThisRow];
    1316           0 :                 for (nThisCol = 0; nThisCol <= nThisEndCol; nThisCol++)
    1317             :                 {
    1318           0 :                     SCCOL nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
    1319           0 :                     ScAddress aThisPos( nThisCol, nThisRow, nThisTab );
    1320           0 :                     ScCellValue aThisCell;
    1321           0 :                     aThisCell.assign(*this, aThisPos);
    1322           0 :                     ScCellValue aOtherCell; // start empty
    1323           0 :                     if ( ValidCol(nOtherCol) && ValidRow(nOtherRow) )
    1324             :                     {
    1325           0 :                         ScAddress aOtherPos( nOtherCol, nOtherRow, nOtherTab );
    1326           0 :                         aOtherCell.assign(rOtherDoc, aOtherPos);
    1327             :                     }
    1328             : 
    1329           0 :                     if (!aThisCell.equalsWithoutFormat(aOtherCell))
    1330             :                     {
    1331           0 :                         ScRange aRange( aThisPos );
    1332           0 :                         ScChangeActionContent* pAction = new ScChangeActionContent( aRange );
    1333           0 :                         pAction->SetOldValue(aOtherCell, &rOtherDoc, this);
    1334           0 :                         pAction->SetNewValue(aThisCell, this);
    1335           0 :                         pChangeTrack->Append( pAction );
    1336             :                     }
    1337           0 :                 }
    1338           0 :                 aProgress.SetStateOnPercent(nProgressStart+nThisRow);
    1339           0 :             }
    1340             :         }
    1341           0 :     }
    1342         156 : }
    1343             : 
    1344             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11