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

Generated by: LCOV version 1.10