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

Generated by: LCOV version 1.10