LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/sc/source/core/data - formulacell.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 795 1706 46.6 %
Date: 2013-07-09 Functions: 76 108 70.4 %
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 "formulacell.hxx"
      21             : 
      22             : #include "compiler.hxx"
      23             : #include "document.hxx"
      24             : #include "globalnames.hxx"
      25             : #include "cellvalue.hxx"
      26             : #include "interpre.hxx"
      27             : #include "macromgr.hxx"
      28             : #include "refupdat.hxx"
      29             : #include "recursionhelper.hxx"
      30             : #include "docoptio.hxx"
      31             : #include "rangenam.hxx"
      32             : #include "dbdata.hxx"
      33             : #include "progress.hxx"
      34             : #include "scmatrix.hxx"
      35             : #include "rechead.hxx"
      36             : #include "scitems.hxx"
      37             : #include "validat.hxx"
      38             : #include "editutil.hxx"
      39             : #include "chgtrack.hxx"
      40             : #include "tokenarray.hxx"
      41             : 
      42             : #include "formula/errorcodes.hxx"
      43             : #include "formula/vectortoken.hxx"
      44             : #include "svl/intitem.hxx"
      45             : #include "rtl/strbuf.hxx"
      46             : #include "formulagroup.hxx"
      47             : #include "listenercontext.hxx"
      48             : #include "types.hxx"
      49             : #include "scopetools.hxx"
      50             : 
      51             : #include <boost/bind.hpp>
      52             : #include <boost/scoped_ptr.hpp>
      53             : 
      54             : using namespace formula;
      55             : 
      56             : #ifdef USE_MEMPOOL
      57             : IMPL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell )
      58             : #endif
      59             : 
      60             : namespace {
      61             : 
      62             : // More or less arbitrary, of course all recursions must fit into available
      63             : // stack space (which is what on all systems we don't know yet?). Choosing a
      64             : // lower value may be better than trying a much higher value that also isn't
      65             : // sufficient but temporarily leads to high memory consumption. On the other
      66             : // hand, if the value fits all recursions, execution is quicker as no resumes
      67             : // are necessary. Could be made a configurable option.
      68             : // Allow for a year's calendar (366).
      69             : const sal_uInt16 MAXRECURSION = 400;
      70             : 
      71             : using std::deque;
      72             : 
      73             : typedef SCCOLROW(*DimensionSelector)(const ScSingleRefData&);
      74             : 
      75             : 
      76           0 : static SCCOLROW lcl_GetCol(const ScSingleRefData& rData)
      77             : {
      78           0 :     return rData.nCol;
      79             : }
      80             : 
      81             : 
      82           0 : static SCCOLROW lcl_GetRow(const ScSingleRefData& rData)
      83             : {
      84           0 :     return rData.nRow;
      85             : }
      86             : 
      87             : 
      88           0 : static SCCOLROW lcl_GetTab(const ScSingleRefData& rData)
      89             : {
      90           0 :     return rData.nTab;
      91             : }
      92             : 
      93             : 
      94             : /** Check if both references span the same range in selected dimension.
      95             :  */
      96             : static bool
      97           0 : lcl_checkRangeDimension(
      98             :         const SingleDoubleRefProvider& rRef1,
      99             :         const SingleDoubleRefProvider& rRef2,
     100             :         const DimensionSelector aWhich)
     101             : {
     102             :     return
     103           0 :         aWhich(rRef1.Ref1) == aWhich(rRef2.Ref1)
     104           0 :         && aWhich(rRef1.Ref2) == aWhich(rRef2.Ref2);
     105             : }
     106             : 
     107             : 
     108             : static bool
     109           0 : lcl_checkRangeDimensions(
     110             :         const SingleDoubleRefProvider& rRef1,
     111             :         const SingleDoubleRefProvider& rRef2,
     112             :         bool& bCol, bool& bRow, bool& bTab)
     113             : {
     114           0 :     const bool bSameCols(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetCol));
     115           0 :     const bool bSameRows(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetRow));
     116           0 :     const bool bSameTabs(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetTab));
     117             : 
     118             :     // Test if exactly two dimensions are equal
     119           0 :     if (!(bSameCols ^ bSameRows ^ bSameTabs)
     120           0 :             && (bSameCols || bSameRows || bSameTabs))
     121             :     {
     122           0 :         bCol = !bSameCols;
     123           0 :         bRow = !bSameRows;
     124           0 :         bTab = !bSameTabs;
     125           0 :         return true;
     126             :     }
     127           0 :     return false;
     128             : }
     129             : 
     130             : 
     131             : /** Check if references in given reference list can possibly
     132             :     form a range. To do that, two of their dimensions must be the same.
     133             :  */
     134             : static bool
     135           0 : lcl_checkRangeDimensions(
     136             :         const deque<ScToken*>::const_iterator aBegin,
     137             :         const deque<ScToken*>::const_iterator aEnd,
     138             :         bool& bCol, bool& bRow, bool& bTab)
     139             : {
     140           0 :     deque<ScToken*>::const_iterator aCur(aBegin);
     141           0 :     ++aCur;
     142           0 :     const SingleDoubleRefProvider aRef(**aBegin);
     143           0 :     bool bOk(false);
     144             :     {
     145           0 :         const SingleDoubleRefProvider aRefCur(**aCur);
     146           0 :         bOk = lcl_checkRangeDimensions(aRef, aRefCur, bCol, bRow, bTab);
     147             :     }
     148           0 :     while (bOk && aCur != aEnd)
     149             :     {
     150           0 :         const SingleDoubleRefProvider aRefCur(**aCur);
     151           0 :         bool bColTmp(false);
     152           0 :         bool bRowTmp(false);
     153           0 :         bool bTabTmp(false);
     154           0 :         bOk = lcl_checkRangeDimensions(aRef, aRefCur, bColTmp, bRowTmp, bTabTmp);
     155           0 :         bOk = bOk && (bCol == bColTmp && bRow == bRowTmp && bTab == bTabTmp);
     156           0 :         ++aCur;
     157           0 :     }
     158             : 
     159           0 :     if (bOk && aCur == aEnd)
     160             :     {
     161           0 :         return true;
     162             :     }
     163           0 :     return false;
     164             : }
     165             : 
     166             : 
     167             : bool
     168           0 : lcl_lessReferenceBy(
     169             :         const ScToken* const pRef1, const ScToken* const pRef2,
     170             :         const DimensionSelector aWhich)
     171             : {
     172           0 :     const SingleDoubleRefProvider rRef1(*pRef1);
     173           0 :     const SingleDoubleRefProvider rRef2(*pRef2);
     174           0 :     return aWhich(rRef1.Ref1) < aWhich(rRef2.Ref1);
     175             : }
     176             : 
     177             : 
     178             : /** Returns true if range denoted by token pRef2 starts immediately after
     179             :     range denoted by token pRef1. Dimension, in which the comparison takes
     180             :     place, is given by aWhich.
     181             :  */
     182             : bool
     183           0 : lcl_isImmediatelyFollowing(
     184             :         const ScToken* const pRef1, const ScToken* const pRef2,
     185             :         const DimensionSelector aWhich)
     186             : {
     187           0 :     const SingleDoubleRefProvider rRef1(*pRef1);
     188           0 :     const SingleDoubleRefProvider rRef2(*pRef2);
     189           0 :     return aWhich(rRef2.Ref1) - aWhich(rRef1.Ref2) == 1;
     190             : }
     191             : 
     192             : 
     193             : static bool
     194           0 : lcl_checkIfAdjacent(
     195             :         const deque<ScToken*>& rReferences,
     196             :         const DimensionSelector aWhich)
     197             : {
     198             :     typedef deque<ScToken*>::const_iterator Iter;
     199           0 :     Iter aBegin(rReferences.begin());
     200           0 :     Iter aEnd(rReferences.end());
     201           0 :     Iter aBegin1(aBegin);
     202           0 :     ++aBegin1, --aEnd;
     203             :     return std::equal(
     204             :             aBegin, aEnd, aBegin1,
     205           0 :             boost::bind(lcl_isImmediatelyFollowing, _1, _2, aWhich));
     206             : }
     207             : 
     208             : 
     209             : static void
     210           0 : lcl_fillRangeFromRefList(
     211             :         const deque<ScToken*>& rReferences, ScRange& rRange)
     212             : {
     213             :     const ScSingleRefData aStart(
     214           0 :             SingleDoubleRefProvider(*rReferences.front()).Ref1);
     215           0 :     rRange.aStart.Set(aStart.nCol, aStart.nRow, aStart.nTab);
     216             :     const ScSingleRefData aEnd(
     217           0 :             SingleDoubleRefProvider(*rReferences.back()).Ref2);
     218           0 :     rRange.aEnd.Set(aEnd.nCol, aEnd.nRow, aEnd.nTab);
     219           0 : }
     220             : 
     221             : 
     222             : static bool
     223           0 : lcl_refListFormsOneRange(
     224             :         const ScAddress& aPos, deque<ScToken*>& rReferences,
     225             :         ScRange& rRange)
     226             : {
     227             :     std::for_each(
     228             :             rReferences.begin(), rReferences.end(),
     229             :             bind(&ScToken::CalcAbsIfRel, _1, aPos))
     230           0 :         ;
     231           0 :     if (rReferences.size() == 1) {
     232           0 :         lcl_fillRangeFromRefList(rReferences, rRange);
     233           0 :         return true;
     234             :     }
     235             : 
     236           0 :     bool bCell(false);
     237           0 :     bool bRow(false);
     238           0 :     bool bTab(false);
     239           0 :     if (lcl_checkRangeDimensions(rReferences.begin(), rReferences.end(),
     240           0 :             bCell, bRow, bTab))
     241             :     {
     242             :         DimensionSelector aWhich;
     243           0 :         if (bCell)
     244             :         {
     245           0 :             aWhich = lcl_GetCol;
     246             :         }
     247           0 :         else if (bRow)
     248             :         {
     249           0 :             aWhich = lcl_GetRow;
     250             :         }
     251           0 :         else if (bTab)
     252             :         {
     253           0 :             aWhich = lcl_GetTab;
     254             :         }
     255             :         else
     256             :         {
     257             :             OSL_FAIL( "lcl_checkRangeDimensions shouldn't allow that!");
     258           0 :             aWhich = lcl_GetRow;    // initialize to avoid warning
     259             :         }
     260             :         // Sort the references by start of range
     261             :         std::sort(rReferences.begin(), rReferences.end(),
     262           0 :                 boost::bind(lcl_lessReferenceBy, _1, _2, aWhich));
     263           0 :         if (lcl_checkIfAdjacent(rReferences, aWhich))
     264             :         {
     265           0 :             lcl_fillRangeFromRefList(rReferences, rRange);
     266           0 :             return true;
     267             :         }
     268             :     }
     269           0 :     return false;
     270             : }
     271             : 
     272             : 
     273           0 : bool lcl_isReference(const FormulaToken& rToken)
     274             : {
     275             :     return
     276           0 :         rToken.GetType() == svSingleRef ||
     277           0 :         rToken.GetType() == svDoubleRef;
     278             : }
     279             : 
     280          10 : void adjustRangeName(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldDoc, const ScAddress& aNewPos, const ScAddress& aOldPos)
     281             : {
     282          10 :     bool bOldGlobal = pToken->IsGlobal();
     283          10 :     SCTAB aOldTab = aOldPos.Tab();
     284          10 :     OUString aRangeName;
     285          10 :     int nOldIndex = pToken->GetIndex();
     286          10 :     ScRangeData* pOldRangeData = NULL;
     287             : 
     288             :     //search the name of the RangeName
     289          10 :     if (!bOldGlobal)
     290             :     {
     291           3 :         pOldRangeData = pOldDoc->GetRangeName(aOldTab)->findByIndex(nOldIndex);
     292           3 :         if (!pOldRangeData)
     293           0 :             return;     //might be an error in the formula array
     294           3 :         aRangeName = pOldRangeData->GetUpperName();
     295             :     }
     296             :     else
     297             :     {
     298           7 :         pOldRangeData = pOldDoc->GetRangeName()->findByIndex(nOldIndex);
     299           7 :         if (!pOldRangeData)
     300           0 :             return;     //might be an error in the formula array
     301           7 :         aRangeName = pOldRangeData->GetUpperName();
     302             :     }
     303             : 
     304             :     //find corresponding range name in new document
     305             :     //first search for local range name then global range names
     306          10 :     SCTAB aNewTab = aNewPos.Tab();
     307          10 :     ScRangeName* pRangeName = rNewDoc.GetRangeName(aNewTab);
     308          10 :     ScRangeData* pRangeData = NULL;
     309          10 :     bool bNewGlobal = false;
     310             :     //search local range names
     311          10 :     if (pRangeName)
     312             :     {
     313          10 :         pRangeData = pRangeName->findByUpperName(aRangeName);
     314             :     }
     315             :     //search global range names
     316          10 :     if (!pRangeData)
     317             :     {
     318           9 :         bNewGlobal = true;
     319           9 :         pRangeName = rNewDoc.GetRangeName();
     320           9 :         if (pRangeName)
     321           9 :             pRangeData = pRangeName->findByUpperName(aRangeName);
     322             :     }
     323             :     //if no range name was found copy it
     324          10 :     if (!pRangeData)
     325             :     {
     326           5 :         bNewGlobal = bOldGlobal;
     327           5 :         pRangeData = new ScRangeData(*pOldRangeData, &rNewDoc);
     328           5 :         ScTokenArray* pRangeNameToken = pRangeData->GetCode();
     329           5 :         if (rNewDoc.GetPool() != const_cast<ScDocument*>(pOldDoc)->GetPool())
     330             :         {
     331           2 :             pRangeNameToken->ReadjustAbsolute3DReferences(pOldDoc, &rNewDoc, pRangeData->GetPos(), true);
     332           2 :             pRangeNameToken->AdjustAbsoluteRefs(pOldDoc, aOldPos, aNewPos, false, true);
     333             :         }
     334             : 
     335             :         bool bInserted;
     336           5 :         if (bNewGlobal)
     337           3 :             bInserted = rNewDoc.GetRangeName()->insert(pRangeData);
     338             :         else
     339           2 :             bInserted = rNewDoc.GetRangeName(aNewTab)->insert(pRangeData);
     340           5 :         if (!bInserted)
     341             :         {
     342             :             //if this happened we have a real problem
     343           0 :             pRangeData = NULL;
     344           0 :             pToken->SetIndex(0);
     345             :             OSL_FAIL("inserting the range name should not fail");
     346           0 :             return;
     347             :         }
     348             :     }
     349          10 :     sal_Int32 nIndex = pRangeData->GetIndex();
     350          10 :     pToken->SetIndex(nIndex);
     351          10 :     pToken->SetGlobal(bNewGlobal);
     352             : }
     353             : 
     354           0 : void adjustDBRange(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldDoc)
     355             : {
     356           0 :     ScDBCollection* pOldDBCollection = pOldDoc->GetDBCollection();
     357           0 :     if (!pOldDBCollection)
     358           0 :         return;//strange error case, don't do anything
     359           0 :     ScDBCollection::NamedDBs& aOldNamedDBs = pOldDBCollection->getNamedDBs();
     360           0 :     ScDBData* pDBData = aOldNamedDBs.findByIndex(pToken->GetIndex());
     361           0 :     if (!pDBData)
     362           0 :         return; //invalid index
     363           0 :     OUString aDBName = pDBData->GetUpperName();
     364             : 
     365             :     //search in new document
     366           0 :     ScDBCollection* pNewDBCollection = rNewDoc.GetDBCollection();
     367           0 :     if (!pNewDBCollection)
     368             :     {
     369           0 :         pNewDBCollection = new ScDBCollection(&rNewDoc);
     370           0 :         rNewDoc.SetDBCollection(pNewDBCollection);
     371             :     }
     372           0 :     ScDBCollection::NamedDBs& aNewNamedDBs = pNewDBCollection->getNamedDBs();
     373           0 :     ScDBData* pNewDBData = aNewNamedDBs.findByUpperName(aDBName);
     374           0 :     if (!pNewDBData)
     375             :     {
     376           0 :         pNewDBData = new ScDBData(*pDBData);
     377           0 :         aNewNamedDBs.insert(pNewDBData);
     378             :     }
     379           0 :     pToken->SetIndex(pNewDBData->GetIndex());
     380             : }
     381             : 
     382             : }
     383             : 
     384         499 : ScFormulaCellGroup::ScFormulaCellGroup() :
     385             :     mnRefCount(0),
     386             :     mnStart(0),
     387             :     mnLength(0),
     388             :     mbInvariant(false),
     389         499 :     meCalcState(sc::GroupCalcEnabled)
     390             : {
     391         499 : }
     392             : 
     393         484 : ScFormulaCellGroup::~ScFormulaCellGroup()
     394             : {
     395         484 : }
     396             : 
     397             : // ============================================================================
     398             : 
     399         659 : ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
     400             :                               const OUString& rFormula,
     401             :                               const FormulaGrammar::Grammar eGrammar,
     402             :                               sal_uInt8 cMatInd ) :
     403             :     eTempGrammar( eGrammar),
     404             :     pCode( NULL ),
     405             :     pDocument( pDoc ),
     406             :     pPrevious(0),
     407             :     pNext(0),
     408             :     pPreviousTrack(0),
     409             :     pNextTrack(0),
     410             :     nSeenInIteration(0),
     411             :     cMatrixFlag ( cMatInd ),
     412             :     nFormatType ( NUMBERFORMAT_NUMBER ),
     413             :     bDirty( true ), // -> Because of the use of the Auto Pilot Function was: cMatInd != 0
     414             :     bChanged( false ),
     415             :     bRunning( false ),
     416             :     bCompile( false ),
     417             :     bSubTotal( false ),
     418             :     bIsIterCell( false ),
     419             :     bInChangeTrack( false ),
     420             :     bTableOpDirty( false ),
     421             :     bNeedListening( false ),
     422             :     mbNeedsNumberFormat( false ),
     423         659 :     aPos( rPos )
     424             : {
     425         659 :     Compile( rFormula, true, eGrammar );    // bNoListening, Insert does that
     426         659 :     if (!pCode)
     427             :         // We need to have a non-NULL token array instance at all times.
     428           0 :         pCode = new ScTokenArray;
     429         659 : }
     430             : 
     431             : // Used by import filters
     432             : 
     433        3963 : ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
     434             :                               const ScTokenArray* pArr,
     435             :                               const FormulaGrammar::Grammar eGrammar, sal_uInt8 cInd ) :
     436             :     eTempGrammar( eGrammar),
     437        3963 :     pCode( pArr ? new ScTokenArray( *pArr ) : new ScTokenArray ),
     438             :     pDocument( pDoc ),
     439             :     pPrevious(0),
     440             :     pNext(0),
     441             :     pPreviousTrack(0),
     442             :     pNextTrack(0),
     443             :     nSeenInIteration(0),
     444             :     cMatrixFlag ( cInd ),
     445             :     nFormatType ( NUMBERFORMAT_NUMBER ),
     446        3963 :     bDirty( NULL != pArr ), // -> Because of the use of the Auto Pilot Function was: cInd != 0
     447             :     bChanged( false ),
     448             :     bRunning( false ),
     449             :     bCompile( false ),
     450             :     bSubTotal( false ),
     451             :     bIsIterCell( false ),
     452             :     bInChangeTrack( false ),
     453             :     bTableOpDirty( false ),
     454             :     bNeedListening( false ),
     455             :     mbNeedsNumberFormat( false ),
     456       11889 :     aPos( rPos )
     457             : {
     458             :     // UPN-Array generation
     459        3963 :     if( pCode->GetLen() && !pCode->GetCodeError() && !pCode->GetCodeLen() )
     460             :     {
     461        3939 :         ScCompiler aComp( pDocument, aPos, *pCode);
     462        3939 :         aComp.SetGrammar(eTempGrammar);
     463        3939 :         bSubTotal = aComp.CompileTokenArray();
     464        3939 :         nFormatType = aComp.GetNumFormatType();
     465             :     }
     466             :     else
     467             :     {
     468          24 :         pCode->Reset();
     469          24 :         if ( pCode->GetNextOpCodeRPN( ocSubTotal ) )
     470           0 :             bSubTotal = true;
     471             :     }
     472             : 
     473        3963 :     if (bSubTotal)
     474           6 :         pDocument->AddSubTotalCell(this);
     475             : 
     476        3963 :     pCode->GenHash();
     477        3963 : }
     478             : 
     479         786 : ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags ) :
     480             :     SvtListener(),
     481             :     aResult( rCell.aResult ),
     482             :     eTempGrammar( rCell.eTempGrammar),
     483             :     pDocument( &rDoc ),
     484             :     pPrevious(0),
     485             :     pNext(0),
     486             :     pPreviousTrack(0),
     487             :     pNextTrack(0),
     488             :     nSeenInIteration(0),
     489             :     cMatrixFlag ( rCell.cMatrixFlag ),
     490             :     nFormatType( rCell.nFormatType ),
     491             :     bDirty( rCell.bDirty ),
     492             :     bChanged( rCell.bChanged ),
     493             :     bRunning( false ),
     494             :     bCompile( rCell.bCompile ),
     495             :     bSubTotal( rCell.bSubTotal ),
     496             :     bIsIterCell( false ),
     497             :     bInChangeTrack( false ),
     498             :     bTableOpDirty( false ),
     499             :     bNeedListening( false ),
     500             :     mbNeedsNumberFormat( false ),
     501         786 :     aPos( rPos )
     502             : {
     503         786 :     pCode = rCell.pCode->Clone();
     504             : 
     505             :     //  set back any errors and recompile
     506             :     //  not in the Clipboard - it must keep the received error flag
     507             :     //  Special Length=0: as bad cells are generated, then they are also retained
     508         786 :     if ( pCode->GetCodeError() && !pDocument->IsClipboard() && pCode->GetLen() )
     509             :     {
     510           0 :         pCode->SetCodeError( 0 );
     511           0 :         bCompile = true;
     512             :     }
     513             :     //! Compile ColRowNames on URM_MOVE/URM_COPY _after_ UpdateReference
     514         786 :     bool bCompileLater = false;
     515         786 :     bool bClipMode = rCell.pDocument->IsClipboard();
     516             : 
     517             :     //update ScNameTokens
     518         786 :     if (!pDocument->IsClipOrUndo() || rDoc.IsUndo())
     519             :     {
     520         764 :         if (!pDocument->IsClipboardSource() || aPos.Tab() != rCell.aPos.Tab())
     521             :         {
     522         764 :             ScToken* pToken = NULL;
     523        1538 :             while((pToken = static_cast<ScToken*>(pCode->GetNextName()))!= NULL)
     524             :             {
     525          10 :                 OpCode eOpCode = pToken->GetOpCode();
     526          10 :                 if (eOpCode == ocName)
     527          10 :                     adjustRangeName(pToken, rDoc, rCell.pDocument, aPos, rCell.aPos);
     528           0 :                 else if (eOpCode == ocDBArea)
     529           0 :                     adjustDBRange(pToken, rDoc, rCell.pDocument);
     530             :             }
     531             :         }
     532             : 
     533         764 :         bool bCopyBetweenDocs = pDocument->GetPool() != rCell.pDocument->GetPool();
     534         764 :         if (bCopyBetweenDocs && !(nCloneFlags & SC_CLONECELL_NOMAKEABS_EXTERNAL))
     535             :         {
     536          11 :             pCode->ReadjustAbsolute3DReferences( rCell.pDocument, &rDoc, rCell.aPos);
     537             :         }
     538             : 
     539         764 :         pCode->AdjustAbsoluteRefs( rCell.pDocument, rCell.aPos, aPos, false, bCopyBetweenDocs );
     540             :     }
     541             : 
     542         786 :     if ( nCloneFlags & SC_CLONECELL_ADJUST3DREL )
     543           0 :         pCode->ReadjustRelative3DReferences( rCell.aPos, aPos );
     544             : 
     545         786 :     if( !bCompile )
     546             :     {   // Name references with references and ColRowNames
     547         784 :         pCode->Reset();
     548             :         ScToken* t;
     549        2135 :         while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceOrName()) ) != NULL && !bCompile )
     550             :         {
     551         567 :             if ( t->IsExternalRef() )
     552             :             {
     553             :                 // External name, cell, and area references.
     554           3 :                 bCompile = true;
     555             :             }
     556         564 :             else if ( t->GetType() == svIndex )
     557             :             {
     558           6 :                 ScRangeData* pRangeData = rDoc.GetRangeName()->findByIndex( t->GetIndex() );
     559           6 :                 if( pRangeData )
     560             :                 {
     561           6 :                     if( pRangeData->HasReferences() )
     562           6 :                         bCompile = true;
     563             :                 }
     564             :                 else
     565           0 :                     bCompile = true;    // invalid reference!
     566             :             }
     567         558 :             else if ( t->GetOpCode() == ocColRowName )
     568             :             {
     569           0 :                 bCompile = true;        // new lookup needed
     570           0 :                 bCompileLater = bClipMode;
     571             :             }
     572             :         }
     573             :     }
     574         786 :     if( bCompile )
     575             :     {
     576          11 :         if ( !bCompileLater && bClipMode )
     577             :         {
     578             :             // Merging ranges needs the actual positions after UpdateReference.
     579             :             // ColRowNames need new lookup after positions are adjusted.
     580           4 :             bCompileLater = pCode->HasOpCode( ocRange) || pCode->HasOpCode( ocColRowName);
     581             :         }
     582          11 :         if ( !bCompileLater )
     583             :         {
     584             :             // bNoListening, not at all if in Clipboard/Undo,
     585             :             // and not from Clipboard either, instead after Insert(Clone) and UpdateReference.
     586          11 :             CompileTokenArray( true );
     587             :         }
     588             :     }
     589             : 
     590         786 :     if( nCloneFlags & SC_CLONECELL_STARTLISTENING )
     591          30 :         StartListeningTo( &rDoc );
     592             : 
     593         786 :     if (bSubTotal)
     594           6 :         pDocument->AddSubTotalCell(this);
     595         786 : }
     596             : 
     597       15309 : ScFormulaCell::~ScFormulaCell()
     598             : {
     599        5104 :     pDocument->RemoveFromFormulaTree( this );
     600        5104 :     pDocument->RemoveSubTotalCell(this);
     601        5104 :     if (pCode->HasOpCode(ocMacro))
     602           1 :         pDocument->GetMacroManager()->RemoveDependentCell(this);
     603             : 
     604        5104 :     if (pDocument->HasExternalRefManager())
     605        1764 :         pDocument->GetExternalRefManager()->removeRefCell(this);
     606             : 
     607        5104 :     delete pCode;
     608       10205 : }
     609             : 
     610         560 : ScFormulaCell* ScFormulaCell::Clone() const
     611             : {
     612         560 :     return new ScFormulaCell(*this, *pDocument, aPos);
     613             : }
     614             : 
     615        4790 : size_t ScFormulaCell::GetHash() const
     616             : {
     617        4790 :     return pCode->GetHash();
     618             : }
     619             : 
     620           6 : ScFormulaVectorState ScFormulaCell::GetVectorState() const
     621             : {
     622           6 :     return pCode->GetVectorState();
     623             : }
     624             : 
     625         125 : void ScFormulaCell::GetFormula( OUStringBuffer& rBuffer,
     626             :                                 const FormulaGrammar::Grammar eGrammar ) const
     627             : {
     628         125 :     if( pCode->GetCodeError() && !pCode->GetLen() )
     629             :     {
     630           0 :         rBuffer = OUStringBuffer( ScGlobal::GetErrorString( pCode->GetCodeError()));
     631           0 :         return;
     632             :     }
     633         125 :     else if( cMatrixFlag == MM_REFERENCE )
     634             :     {
     635             :         // Reference to another cell that contains a matrix formula.
     636           0 :         pCode->Reset();
     637           0 :         ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
     638           0 :         if( p )
     639             :         {
     640             :             /* FIXME: original GetFormula() code obtained
     641             :              * pCell only if (!this->IsInChangeTrack()),
     642             :              * GetEnglishFormula() omitted that test.
     643             :              * Can we live without in all cases? */
     644           0 :             ScFormulaCell* pCell = NULL;
     645           0 :             ScSingleRefData& rRef = p->GetSingleRef();
     646           0 :             rRef.CalcAbsIfRel( aPos );
     647           0 :             if ( rRef.Valid() )
     648             :                 pCell = pDocument->GetFormulaCell(
     649           0 :                     ScAddress(rRef.nCol, rRef.nRow, rRef.nTab));
     650             : 
     651           0 :             if (pCell)
     652             :             {
     653           0 :                 pCell->GetFormula( rBuffer, eGrammar);
     654           0 :                 return;
     655             :             }
     656             :             else
     657             :             {
     658           0 :                 ScCompiler aComp( pDocument, aPos, *pCode);
     659           0 :                 aComp.SetGrammar(eGrammar);
     660           0 :                 aComp.CreateStringFromTokenArray( rBuffer );
     661             :             }
     662             :         }
     663             :         else
     664             :         {
     665             :             OSL_FAIL("ScFormulaCell::GetFormula: not a matrix");
     666             :         }
     667             :     }
     668             :     else
     669             :     {
     670         125 :         ScCompiler aComp( pDocument, aPos, *pCode);
     671         125 :         aComp.SetGrammar(eGrammar);
     672         125 :         aComp.CreateStringFromTokenArray( rBuffer );
     673             :     }
     674             : 
     675         125 :     sal_Unicode ch('=');
     676         125 :     rBuffer.insert( 0, &ch, 1 );
     677         125 :     if( cMatrixFlag )
     678             :     {
     679           1 :         sal_Unicode ch2('{');
     680           1 :         rBuffer.insert( 0, &ch2, 1);
     681           1 :         rBuffer.append( sal_Unicode('}'));
     682             :     }
     683             : }
     684             : 
     685         125 : void ScFormulaCell::GetFormula( OUString& rFormula, const FormulaGrammar::Grammar eGrammar ) const
     686             : {
     687         125 :     OUStringBuffer rBuffer( rFormula );
     688         125 :     GetFormula( rBuffer, eGrammar );
     689         125 :     rFormula = rBuffer.makeStringAndClear();
     690         125 : }
     691             : 
     692           0 : void ScFormulaCell::GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows )
     693             : {
     694           0 :     MaybeInterpret();
     695             : 
     696           0 :     const ScMatrix* pMat = NULL;
     697           0 :     if (!pCode->GetCodeError() && aResult.GetType() == svMatrixCell &&
     698           0 :             ((pMat = static_cast<const ScToken*>(aResult.GetToken().get())->GetMatrix()) != 0))
     699           0 :         pMat->GetDimensions( rCols, rRows );
     700             :     else
     701             :     {
     702           0 :         rCols = 0;
     703           0 :         rRows = 0;
     704             :     }
     705           0 : }
     706             : 
     707         659 : void ScFormulaCell::Compile( const OUString& rFormula, bool bNoListening,
     708             :                             const FormulaGrammar::Grammar eGrammar )
     709             : {
     710         659 :     if ( pDocument->IsClipOrUndo() )
     711         659 :         return;
     712         659 :     bool bWasInFormulaTree = pDocument->IsInFormulaTree( this );
     713         659 :     if ( bWasInFormulaTree )
     714           0 :         pDocument->RemoveFromFormulaTree( this );
     715             :     // pCode may not deleted for queries, but must be empty
     716         659 :     if ( pCode )
     717           0 :         pCode->Clear();
     718         659 :     ScTokenArray* pCodeOld = pCode;
     719         659 :     ScCompiler aComp( pDocument, aPos);
     720         659 :     aComp.SetGrammar(eGrammar);
     721         659 :     pCode = aComp.CompileString( rFormula );
     722         659 :     if ( pCodeOld )
     723           0 :         delete pCodeOld;
     724         659 :     if( !pCode->GetCodeError() )
     725             :     {
     726         659 :         if ( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() && rFormula == aResult.GetHybridFormula() )
     727             :         {   // not recursive CompileTokenArray/Compile/CompileTokenArray
     728           0 :             if ( rFormula[0] == '=' )
     729           0 :                 pCode->AddBad( rFormula.copy(1) );
     730             :             else
     731           0 :                 pCode->AddBad( rFormula );
     732             :         }
     733         659 :         bCompile = true;
     734         659 :         CompileTokenArray( bNoListening );
     735             :     }
     736             :     else
     737           0 :         bChanged = true;
     738             : 
     739         659 :     if ( bWasInFormulaTree )
     740           0 :         pDocument->PutInFormulaTree( this );
     741             : }
     742             : 
     743             : 
     744         734 : void ScFormulaCell::CompileTokenArray( bool bNoListening )
     745             : {
     746             :     // Not already compiled?
     747         734 :     if( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() )
     748           0 :         Compile( aResult.GetHybridFormula(), bNoListening, eTempGrammar);
     749         734 :     else if( bCompile && !pDocument->IsClipOrUndo() && !pCode->GetCodeError() )
     750             :     {
     751             :         // RPN length may get changed
     752         674 :         bool bWasInFormulaTree = pDocument->IsInFormulaTree( this );
     753         674 :         if ( bWasInFormulaTree )
     754           0 :             pDocument->RemoveFromFormulaTree( this );
     755             : 
     756             :         // Loading from within filter? No listening yet!
     757         674 :         if( pDocument->IsInsertingFromOtherDoc() )
     758          27 :             bNoListening = true;
     759             : 
     760         674 :         if( !bNoListening && pCode->GetCodeLen() )
     761           6 :             EndListeningTo( pDocument );
     762         674 :         ScCompiler aComp(pDocument, aPos, *pCode);
     763         674 :         aComp.SetGrammar(pDocument->GetGrammar());
     764         674 :         bSubTotal = aComp.CompileTokenArray();
     765         674 :         if( !pCode->GetCodeError() )
     766             :         {
     767         665 :             nFormatType = aComp.GetNumFormatType();
     768         665 :             bChanged = true;
     769         665 :             aResult.SetToken( NULL);
     770         665 :             bCompile = false;
     771         665 :             if ( !bNoListening )
     772           6 :                 StartListeningTo( pDocument );
     773             :         }
     774         674 :         if ( bWasInFormulaTree )
     775           0 :             pDocument->PutInFormulaTree( this );
     776             : 
     777         674 :         if (bSubTotal)
     778           0 :             pDocument->AddSubTotalCell(this);
     779             :     }
     780         734 : }
     781             : 
     782             : 
     783         448 : void ScFormulaCell::CompileXML( ScProgress& rProgress )
     784             : {
     785         448 :     if ( cMatrixFlag == MM_REFERENCE )
     786             :     {   // is already token code via ScDocFunc::EnterMatrix, ScDocument::InsertMatrixFormula
     787             :         // just establish listeners
     788          53 :         StartListeningTo( pDocument );
     789         501 :         return ;
     790             :     }
     791             : 
     792         395 :     ScCompiler aComp( pDocument, aPos, *pCode);
     793         395 :     aComp.SetGrammar(eTempGrammar);
     794         790 :     OUString aFormula, aFormulaNmsp;
     795         395 :     aComp.CreateStringFromXMLTokenArray( aFormula, aFormulaNmsp );
     796         395 :     pDocument->DecXMLImportedFormulaCount( aFormula.getLength() );
     797         395 :     rProgress.SetStateCountDownOnPercent( pDocument->GetXMLImportedFormulaCount() );
     798             :     // pCode may not deleted for queries, but must be empty
     799         395 :     if ( pCode )
     800         395 :         pCode->Clear();
     801         395 :     ScTokenArray* pCodeOld = pCode;
     802         395 :     pCode = aComp.CompileString( aFormula, aFormulaNmsp );
     803         395 :     delete pCodeOld;
     804         395 :     if( !pCode->GetCodeError() )
     805             :     {
     806         395 :         if ( !pCode->GetLen() )
     807             :         {
     808           0 :             if ( aFormula[0] == '=' )
     809           0 :                 pCode->AddBad( aFormula.copy( 1 ) );
     810             :             else
     811           0 :                 pCode->AddBad( aFormula );
     812             :         }
     813         395 :         bSubTotal = aComp.CompileTokenArray();
     814         395 :         if( !pCode->GetCodeError() )
     815             :         {
     816         395 :             nFormatType = aComp.GetNumFormatType();
     817         395 :             bChanged = true;
     818         395 :             bCompile = false;
     819         395 :             StartListeningTo( pDocument );
     820             :         }
     821             : 
     822         395 :         if (bSubTotal)
     823           0 :             pDocument->AddSubTotalCell(this);
     824             :     }
     825             :     else
     826           0 :         bChanged = true;
     827             : 
     828             :     //  Same as in Load: after loading, it must be known if ocMacro is in any formula
     829             :     //  (for macro warning, CompileXML is called at the end of loading XML file)
     830         395 :     if ( !pDocument->GetHasMacroFunc() && pCode->HasOpCodeRPN( ocMacro ) )
     831           0 :         pDocument->SetHasMacroFunc( true );
     832             : 
     833             :     //volatile cells must be added here for import
     834        1544 :     if( pCode->IsRecalcModeAlways() || pCode->IsRecalcModeForced() ||
     835        1131 :         pCode->IsRecalcModeOnLoad() || pCode->IsRecalcModeOnLoadOnce() )
     836             :     {
     837             :         // During load, only those cells that are marked explicitly dirty get
     838             :         // recalculated.  So we need to set it dirty here.
     839          36 :         SetDirtyVar();
     840          36 :         pDocument->PutInFormulaTree(this);
     841         395 :     }
     842             : }
     843             : 
     844             : 
     845        2473 : void ScFormulaCell::CalcAfterLoad()
     846             : {
     847        2473 :     bool bNewCompiled = false;
     848             :     // If a Calc 1.0-doc is read, we have a result, but no token array
     849        2473 :     if( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() )
     850             :     {
     851           0 :         Compile( aResult.GetHybridFormula(), true, eTempGrammar);
     852           0 :         aResult.SetToken( NULL);
     853           0 :         bDirty = true;
     854           0 :         bNewCompiled = true;
     855             :     }
     856             :     // The UPN array is not created when a Calc 3.0-Doc has been read as the Range Names exist until now.
     857        2473 :     if( pCode->GetLen() && !pCode->GetCodeLen() && !pCode->GetCodeError() )
     858             :     {
     859           0 :         ScCompiler aComp(pDocument, aPos, *pCode);
     860           0 :         aComp.SetGrammar(pDocument->GetGrammar());
     861           0 :         bSubTotal = aComp.CompileTokenArray();
     862           0 :         nFormatType = aComp.GetNumFormatType();
     863           0 :         bDirty = true;
     864           0 :         bCompile = false;
     865           0 :         bNewCompiled = true;
     866             : 
     867           0 :         if (bSubTotal)
     868           0 :             pDocument->AddSubTotalCell(this);
     869             :     }
     870             : 
     871             :     // On OS/2 with broken FPU exception, we can somehow store /0 without Err503. Later on in
     872             :     // the BLC Lib NumberFormatter crashes when doing a fabs (NAN) (# 32739 #).
     873             :     // We iron this out here for all systems, such that we also have an Err503 here.
     874        2473 :     if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
     875             :     {
     876             :         OSL_FAIL("Formula cell INFINITY!!! Where does this document come from?");
     877           0 :         aResult.SetResultError( errIllegalFPOperation );
     878           0 :         bDirty = true;
     879             :     }
     880             : 
     881             :     // DoubleRefs for binary operators were always a Matrix before version v5.0.
     882             :     // Now this is only the case when when in an array formula, otherwise it's an implicit intersection
     883        4946 :     if ( pDocument->GetSrcVersion() < SC_MATRIX_DOUBLEREF &&
     884        2473 :             GetMatrixFlag() == MM_NONE && pCode->HasMatrixDoubleRefOps() )
     885             :     {
     886           0 :         cMatrixFlag = MM_FORMULA;
     887           0 :         SetMatColsRows( 1, 1);
     888             :     }
     889             : 
     890             :     // Do the cells need to be calculated? After Load cells can contain an error code, and then start
     891             :     // the listener and Recalculate (if needed) if not RECALCMODE_NORMAL
     892        2473 :     if( !bNewCompiled || !pCode->GetCodeError() )
     893             :     {
     894        2473 :         StartListeningTo( pDocument );
     895        2473 :         if( !pCode->IsRecalcModeNormal() )
     896           1 :             bDirty = true;
     897             :     }
     898        2473 :     if ( pCode->IsRecalcModeAlways() )
     899             :     {   // random(), today(), now() always stay in the FormulaTree, so that they are calculated
     900             :         // for each F9
     901           0 :         bDirty = true;
     902             :     }
     903             :     // No SetDirty yet, as no all Listeners are known yet (only in SetDirtyAfterLoad)
     904        2473 : }
     905             : 
     906             : 
     907           0 : bool ScFormulaCell::MarkUsedExternalReferences()
     908             : {
     909           0 :     return pCode && pDocument->MarkUsedExternalReferences( *pCode);
     910             : }
     911             : 
     912             : 
     913        4763 : void ScFormulaCell::Interpret()
     914             : {
     915        4763 :     if (!IsDirtyOrInTableOpDirty() || pDocument->GetRecursionHelper().IsInReturn())
     916          83 :         return;     // no double/triple processing
     917             : 
     918             :     //! HACK:
     919             :     //  If the call originates from a Reschedule in DdeLink update, leave dirty
     920             :     //  Better: Do a Dde Link Update without Reschedule or do it completely asynchronously!
     921        4680 :     if ( pDocument->IsInDdeLinkUpdate() )
     922           0 :         return;
     923             : 
     924        4680 :     if (bRunning)
     925             :     {
     926           1 :         if (!pDocument->GetDocOptions().IsIter())
     927             :         {
     928           1 :             aResult.SetResultError( errCircularReference );
     929           1 :             return;
     930             :         }
     931             : 
     932           0 :         if (aResult.GetResultError() == errCircularReference)
     933           0 :             aResult.SetResultError( 0 );
     934             : 
     935             :         // Start or add to iteration list.
     936           0 :         if (!pDocument->GetRecursionHelper().IsDoingIteration() ||
     937           0 :                 !pDocument->GetRecursionHelper().GetRecursionInIterationStack().top()->bIsIterCell)
     938           0 :             pDocument->GetRecursionHelper().SetInIterationReturn( true);
     939             : 
     940           0 :         return;
     941             :     }
     942             :     // no multiple interprets for GetErrCode, IsValue, GetValue and
     943             :     // different entry point recursions. Would also lead to premature
     944             :     // convergence in iterations.
     945        4679 :     if (pDocument->GetRecursionHelper().GetIteration() && nSeenInIteration ==
     946           0 :             pDocument->GetRecursionHelper().GetIteration())
     947           0 :         return ;
     948             : 
     949        4679 :     ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper();
     950        4679 :     bool bOldRunning = bRunning;
     951        4679 :     if (rRecursionHelper.GetRecursionCount() > MAXRECURSION)
     952             :     {
     953           0 :         bRunning = true;
     954           0 :         rRecursionHelper.SetInRecursionReturn( true);
     955             :     }
     956             :     else
     957             :     {
     958        4679 :         if ( ! InterpretFormulaGroup() )
     959        4679 :             InterpretTail( SCITP_NORMAL);
     960             :     }
     961             : 
     962             :     // While leaving a recursion or iteration stack, insert its cells to the
     963             :     // recursion list in reverse order.
     964        4679 :     if (rRecursionHelper.IsInReturn())
     965             :     {
     966           0 :         if (rRecursionHelper.GetRecursionCount() > 0 ||
     967           0 :                 !rRecursionHelper.IsDoingRecursion())
     968           0 :             rRecursionHelper.Insert( this, bOldRunning, aResult);
     969           0 :         bool bIterationFromRecursion = false;
     970           0 :         bool bResumeIteration = false;
     971           0 :         do
     972             :         {
     973           0 :             if ((rRecursionHelper.IsInIterationReturn() &&
     974           0 :                         rRecursionHelper.GetRecursionCount() == 0 &&
     975           0 :                         !rRecursionHelper.IsDoingIteration()) ||
     976           0 :                     bIterationFromRecursion || bResumeIteration)
     977             :             {
     978           0 :                 ScFormulaCell* pIterCell = this; // scope for debug convenience
     979           0 :                 bool & rDone = rRecursionHelper.GetConvergingReference();
     980           0 :                 rDone = false;
     981           0 :                 if (!bIterationFromRecursion && bResumeIteration)
     982             :                 {
     983           0 :                     bResumeIteration = false;
     984             :                     // Resuming iteration expands the range.
     985             :                     ScFormulaRecursionList::const_iterator aOldStart(
     986           0 :                             rRecursionHelper.GetLastIterationStart());
     987           0 :                     rRecursionHelper.ResumeIteration();
     988             :                     // Mark new cells being in iteration.
     989           0 :                     for (ScFormulaRecursionList::const_iterator aIter(
     990           0 :                                 rRecursionHelper.GetIterationStart()); aIter !=
     991             :                             aOldStart; ++aIter)
     992             :                     {
     993           0 :                         pIterCell = (*aIter).pCell;
     994           0 :                         pIterCell->bIsIterCell = true;
     995             :                     }
     996             :                     // Mark older cells dirty again, in case they converted
     997             :                     // without accounting for all remaining cells in the circle
     998             :                     // that weren't touched so far, e.g. conditional. Restore
     999             :                     // backuped result.
    1000           0 :                     sal_uInt16 nIteration = rRecursionHelper.GetIteration();
    1001           0 :                     for (ScFormulaRecursionList::const_iterator aIter(
    1002           0 :                                 aOldStart); aIter !=
    1003             :                             rRecursionHelper.GetIterationEnd(); ++aIter)
    1004             :                     {
    1005           0 :                         pIterCell = (*aIter).pCell;
    1006           0 :                         if (pIterCell->nSeenInIteration == nIteration)
    1007             :                         {
    1008           0 :                             if (!pIterCell->bDirty || aIter == aOldStart)
    1009             :                             {
    1010           0 :                                 pIterCell->aResult = (*aIter).aPreviousResult;
    1011             :                             }
    1012           0 :                             --pIterCell->nSeenInIteration;
    1013             :                         }
    1014           0 :                         pIterCell->bDirty = true;
    1015           0 :                     }
    1016             :                 }
    1017             :                 else
    1018             :                 {
    1019           0 :                     bResumeIteration = false;
    1020             :                     // Close circle once.
    1021           0 :                     rRecursionHelper.GetList().back().pCell->InterpretTail(
    1022           0 :                             SCITP_CLOSE_ITERATION_CIRCLE);
    1023             :                     // Start at 1, init things.
    1024           0 :                     rRecursionHelper.StartIteration();
    1025             :                     // Mark all cells being in iteration.
    1026           0 :                     for (ScFormulaRecursionList::const_iterator aIter(
    1027           0 :                                 rRecursionHelper.GetIterationStart()); aIter !=
    1028             :                             rRecursionHelper.GetIterationEnd(); ++aIter)
    1029             :                     {
    1030           0 :                         pIterCell = (*aIter).pCell;
    1031           0 :                         pIterCell->bIsIterCell = true;
    1032             :                     }
    1033             :                 }
    1034           0 :                 bIterationFromRecursion = false;
    1035           0 :                 sal_uInt16 nIterMax = pDocument->GetDocOptions().GetIterCount();
    1036           0 :                 for ( ; rRecursionHelper.GetIteration() <= nIterMax && !rDone;
    1037           0 :                         rRecursionHelper.IncIteration())
    1038             :                 {
    1039           0 :                     rDone = true;
    1040           0 :                     for ( ScFormulaRecursionList::iterator aIter(
    1041           0 :                                 rRecursionHelper.GetIterationStart()); aIter !=
    1042           0 :                             rRecursionHelper.GetIterationEnd() &&
    1043           0 :                             !rRecursionHelper.IsInReturn(); ++aIter)
    1044             :                     {
    1045           0 :                         pIterCell = (*aIter).pCell;
    1046           0 :                         if (pIterCell->IsDirtyOrInTableOpDirty() &&
    1047           0 :                                 rRecursionHelper.GetIteration() !=
    1048           0 :                                 pIterCell->GetSeenInIteration())
    1049             :                         {
    1050           0 :                             (*aIter).aPreviousResult = pIterCell->aResult;
    1051           0 :                             pIterCell->InterpretTail( SCITP_FROM_ITERATION);
    1052             :                         }
    1053           0 :                         rDone = rDone && !pIterCell->IsDirtyOrInTableOpDirty();
    1054             :                     }
    1055           0 :                     if (rRecursionHelper.IsInReturn())
    1056             :                     {
    1057           0 :                         bResumeIteration = true;
    1058           0 :                         break;  // for
    1059             :                         // Don't increment iteration.
    1060             :                     }
    1061             :                 }
    1062           0 :                 if (!bResumeIteration)
    1063             :                 {
    1064           0 :                     if (rDone)
    1065             :                     {
    1066           0 :                         for (ScFormulaRecursionList::const_iterator aIter(
    1067           0 :                                     rRecursionHelper.GetIterationStart());
    1068           0 :                                 aIter != rRecursionHelper.GetIterationEnd();
    1069             :                                 ++aIter)
    1070             :                         {
    1071           0 :                             pIterCell = (*aIter).pCell;
    1072           0 :                             pIterCell->bIsIterCell = false;
    1073           0 :                             pIterCell->nSeenInIteration = 0;
    1074           0 :                             pIterCell->bRunning = (*aIter).bOldRunning;
    1075             :                         }
    1076             :                     }
    1077             :                     else
    1078             :                     {
    1079           0 :                         for (ScFormulaRecursionList::const_iterator aIter(
    1080           0 :                                     rRecursionHelper.GetIterationStart());
    1081           0 :                                 aIter != rRecursionHelper.GetIterationEnd();
    1082             :                                 ++aIter)
    1083             :                         {
    1084           0 :                             pIterCell = (*aIter).pCell;
    1085           0 :                             pIterCell->bIsIterCell = false;
    1086           0 :                             pIterCell->nSeenInIteration = 0;
    1087           0 :                             pIterCell->bRunning = (*aIter).bOldRunning;
    1088             :                             // If one cell didn't converge, all cells of this
    1089             :                             // circular dependency don't, no matter whether
    1090             :                             // single cells did.
    1091           0 :                             pIterCell->bDirty = false;
    1092           0 :                             pIterCell->bTableOpDirty = false;
    1093           0 :                             pIterCell->aResult.SetResultError( errNoConvergence);
    1094           0 :                             pIterCell->bChanged = true;
    1095             :                         }
    1096             :                     }
    1097             :                     // End this iteration and remove entries.
    1098           0 :                     rRecursionHelper.EndIteration();
    1099           0 :                     bResumeIteration = rRecursionHelper.IsDoingIteration();
    1100             :                 }
    1101             :             }
    1102           0 :             if (rRecursionHelper.IsInRecursionReturn() &&
    1103           0 :                     rRecursionHelper.GetRecursionCount() == 0 &&
    1104           0 :                     !rRecursionHelper.IsDoingRecursion())
    1105             :             {
    1106           0 :                 bIterationFromRecursion = false;
    1107             :                 // Iterate over cells known so far, start with the last cell
    1108             :                 // encountered, inserting new cells if another recursion limit
    1109             :                 // is reached. Repeat until solved.
    1110           0 :                 rRecursionHelper.SetDoingRecursion( true);
    1111           0 :                 do
    1112             :                 {
    1113           0 :                     rRecursionHelper.SetInRecursionReturn( false);
    1114           0 :                     for (ScFormulaRecursionList::const_iterator aIter(
    1115           0 :                                 rRecursionHelper.GetIterationStart());
    1116           0 :                             !rRecursionHelper.IsInReturn() && aIter !=
    1117             :                             rRecursionHelper.GetIterationEnd(); ++aIter)
    1118             :                     {
    1119           0 :                         ScFormulaCell* pCell = (*aIter).pCell;
    1120           0 :                         if (pCell->IsDirtyOrInTableOpDirty())
    1121             :                         {
    1122           0 :                             pCell->InterpretTail( SCITP_NORMAL);
    1123           0 :                             if (!pCell->IsDirtyOrInTableOpDirty() && !pCell->IsIterCell())
    1124           0 :                                 pCell->bRunning = (*aIter).bOldRunning;
    1125             :                         }
    1126             :                     }
    1127             :                 } while (rRecursionHelper.IsInRecursionReturn());
    1128           0 :                 rRecursionHelper.SetDoingRecursion( false);
    1129           0 :                 if (rRecursionHelper.IsInIterationReturn())
    1130             :                 {
    1131           0 :                     if (!bResumeIteration)
    1132           0 :                         bIterationFromRecursion = true;
    1133             :                 }
    1134           0 :                 else if (bResumeIteration ||
    1135           0 :                         rRecursionHelper.IsDoingIteration())
    1136           0 :                     rRecursionHelper.GetList().erase(
    1137             :                             rRecursionHelper.GetIterationStart(),
    1138           0 :                             rRecursionHelper.GetLastIterationStart());
    1139             :                 else
    1140           0 :                     rRecursionHelper.Clear();
    1141             :             }
    1142           0 :         } while (bIterationFromRecursion || bResumeIteration);
    1143             :     }
    1144             : }
    1145             : 
    1146        4679 : void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam )
    1147             : {
    1148             :     class RecursionCounter
    1149             :     {
    1150             :         ScRecursionHelper&  rRec;
    1151             :         bool                bStackedInIteration;
    1152             :         public:
    1153        4679 :         RecursionCounter( ScRecursionHelper& r, ScFormulaCell* p ) : rRec(r)
    1154             :         {
    1155        4679 :             bStackedInIteration = rRec.IsDoingIteration();
    1156        4679 :             if (bStackedInIteration)
    1157           0 :                 rRec.GetRecursionInIterationStack().push( p);
    1158        4679 :             rRec.IncRecursionCount();
    1159        4679 :         }
    1160        4679 :         ~RecursionCounter()
    1161             :         {
    1162        4679 :             rRec.DecRecursionCount();
    1163        4679 :             if (bStackedInIteration)
    1164           0 :                 rRec.GetRecursionInIterationStack().pop();
    1165        4679 :         }
    1166        4679 :     } aRecursionCounter( pDocument->GetRecursionHelper(), this);
    1167        4679 :     nSeenInIteration = pDocument->GetRecursionHelper().GetIteration();
    1168        4679 :     if( !pCode->GetCodeLen() && !pCode->GetCodeError() )
    1169             :     {
    1170             :         // #i11719# no UPN and no error and no token code but result string present
    1171             :         // => interpretation of this cell during name-compilation and unknown names
    1172             :         // => can't exchange underlying code array in CompileTokenArray() /
    1173             :         // Compile() because interpreter's token iterator would crash or pCode
    1174             :         // would be deleted twice if this cell was interpreted during
    1175             :         // compilation.
    1176             :         // This should only be a temporary condition and, since we set an
    1177             :         // error, if ran into it again we'd bump into the dirty-clearing
    1178             :         // condition further down.
    1179           0 :         if ( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() )
    1180             :         {
    1181           0 :             pCode->SetCodeError( errNoCode );
    1182             :             // This is worth an assertion; if encountered in daily work
    1183             :             // documents we might need another solution. Or just confirm correctness.
    1184             :             OSL_FAIL( "ScFormulaCell::Interpret: no UPN, no error, no token, but hybrid formula string" );
    1185           0 :             return;
    1186             :         }
    1187           0 :         CompileTokenArray();
    1188             :     }
    1189             : 
    1190        4679 :     if( pCode->GetCodeLen() && pDocument )
    1191             :     {
    1192             :         class StackCleaner
    1193             :         {
    1194             :             ScDocument*     pDoc;
    1195             :             ScInterpreter*  pInt;
    1196             :             public:
    1197        4634 :             StackCleaner( ScDocument* pD, ScInterpreter* pI )
    1198        4634 :                 : pDoc(pD), pInt(pI)
    1199        4634 :                 {}
    1200        4634 :             ~StackCleaner()
    1201             :             {
    1202        4634 :                 delete pInt;
    1203        4634 :                 pDoc->DecInterpretLevel();
    1204        4634 :             }
    1205             :         };
    1206        4634 :         pDocument->IncInterpretLevel();
    1207        4634 :         ScInterpreter* p = new ScInterpreter( this, pDocument, aPos, *pCode );
    1208        4634 :         StackCleaner aStackCleaner( pDocument, p);
    1209        4634 :         sal_uInt16 nOldErrCode = aResult.GetResultError();
    1210        4634 :         if ( nSeenInIteration == 0 )
    1211             :         {   // Only the first time
    1212             :             // With bChanged=false, if a newly compiled cell has a result of
    1213             :             // 0.0, no change is detected and the cell will not be repainted.
    1214             :             // bChanged = false;
    1215        4634 :             aResult.SetResultError( 0 );
    1216             :         }
    1217             : 
    1218        4634 :         switch ( aResult.GetResultError() )
    1219             :         {
    1220             :             case errCircularReference :     // will be determined again if so
    1221           0 :                 aResult.SetResultError( 0 );
    1222           0 :             break;
    1223             :         }
    1224             : 
    1225        4634 :         bool bOldRunning = bRunning;
    1226        4634 :         bRunning = true;
    1227        4634 :         p->Interpret();
    1228        4634 :         if (pDocument->GetRecursionHelper().IsInReturn() && eTailParam != SCITP_CLOSE_ITERATION_CIRCLE)
    1229             :         {
    1230           0 :             if (nSeenInIteration > 0)
    1231           0 :                 --nSeenInIteration;     // retry when iteration is resumed
    1232           0 :             return;
    1233             :         }
    1234        4634 :         bRunning = bOldRunning;
    1235             : 
    1236             :         // #i102616# For single-sheet saving consider only content changes, not format type,
    1237             :         // because format type isn't set on loading (might be changed later)
    1238        4634 :         bool bContentChanged = false;
    1239             : 
    1240             :         // Do not create a HyperLink() cell if the formula results in an error.
    1241        4634 :         if( p->GetError() && pCode->IsHyperLink())
    1242           0 :             pCode->SetHyperLink(false);
    1243             : 
    1244        4634 :         if( p->GetError() && p->GetError() != errCircularReference)
    1245             :         {
    1246         182 :             bDirty = false;
    1247         182 :             bTableOpDirty = false;
    1248         182 :             bChanged = true;
    1249             :         }
    1250        4634 :         if (eTailParam == SCITP_FROM_ITERATION && IsDirtyOrInTableOpDirty())
    1251             :         {
    1252           0 :             bool bIsValue = aResult.IsValue();  // the previous type
    1253             :             // Did it converge?
    1254           0 :             if ((bIsValue && p->GetResultType() == svDouble && fabs(
    1255           0 :                             p->GetNumResult() - aResult.GetDouble()) <=
    1256           0 :                         pDocument->GetDocOptions().GetIterEps()) ||
    1257           0 :                     (!bIsValue && p->GetResultType() == svString &&
    1258           0 :                      p->GetStringResult() == aResult.GetString()))
    1259             :             {
    1260             :                 // A convergence in the first iteration doesn't necessarily
    1261             :                 // mean that it's done, it may be as not all related cells
    1262             :                 // of a circle changed their values yet. If the set really
    1263             :                 // converges it will do so also during the next iteration. This
    1264             :                 // fixes situations like of #i44115#. If this wasn't wanted an
    1265             :                 // initial "uncalculated" value would be needed for all cells
    1266             :                 // of a circular dependency => graph needed before calculation.
    1267           0 :                 if (nSeenInIteration > 1 ||
    1268           0 :                         pDocument->GetDocOptions().GetIterCount() == 1)
    1269             :                 {
    1270           0 :                     bDirty = false;
    1271           0 :                     bTableOpDirty = false;
    1272             :                 }
    1273             :             }
    1274             :         }
    1275             : 
    1276             :         // New error code?
    1277        4634 :         if( p->GetError() != nOldErrCode )
    1278             :         {
    1279         110 :             bChanged = true;
    1280             :             // bContentChanged only has to be set if the file content would be changed
    1281         110 :             if ( aResult.GetCellResultType() != svUnknown )
    1282          44 :                 bContentChanged = true;
    1283             :         }
    1284             : 
    1285        4634 :         if( mbNeedsNumberFormat )
    1286             :         {
    1287         866 :             nFormatType = p->GetRetFormatType();
    1288         866 :             sal_Int32 nFormatIndex = p->GetRetFormatIndex();
    1289             : 
    1290             :             // don't set text format as hard format
    1291         866 :             if(nFormatType == NUMBERFORMAT_TEXT)
    1292          70 :                 nFormatIndex = 0;
    1293         796 :             else if((nFormatIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
    1294         795 :                 nFormatIndex = ScGlobal::GetStandardFormat(*pDocument->GetFormatTable(),
    1295        1590 :                         nFormatIndex, nFormatType);
    1296             : 
    1297             :             // set number format explicitly
    1298         866 :             pDocument->SetNumberFormat( aPos, nFormatIndex );
    1299             : 
    1300         866 :             bChanged = true;
    1301         866 :             mbNeedsNumberFormat = false;
    1302             :         }
    1303             : 
    1304             :         // In case of changes just obtain the result, no temporary and
    1305             :         // comparison needed anymore.
    1306        4634 :         if (bChanged)
    1307             :         {
    1308             :             // #i102616# Compare anyway if the sheet is still marked unchanged for single-sheet saving
    1309             :             // Also handle special cases of initial results after loading.
    1310        1257 :             if ( !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
    1311             :             {
    1312         358 :                 ScFormulaResult aNewResult( p->GetResultToken().get());
    1313         358 :                 StackVar eOld = aResult.GetCellResultType();
    1314         358 :                 StackVar eNew = aNewResult.GetCellResultType();
    1315         358 :                 if ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) )
    1316             :                 {
    1317             :                     // ScXMLTableRowCellContext::EndElement doesn't call SetFormulaResultDouble for 0
    1318             :                     // -> no change
    1319             :                 }
    1320             :                 else
    1321             :                 {
    1322         320 :                     if ( eOld == svHybridCell || eOld == svHybridValueCell )     // string result from SetFormulaResultString?
    1323          22 :                         eOld = svString;            // ScHybridCellToken has a valid GetString method
    1324             : 
    1325             :                     // #i106045# use approxEqual to compare with stored value
    1326         316 :                     bContentChanged = (eOld != eNew ||
    1327         613 :                             (eNew == svDouble && !rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() )) ||
    1328         348 :                             (eNew == svString && aResult.GetString() != aNewResult.GetString()));
    1329         358 :                 }
    1330             :             }
    1331             : 
    1332        1257 :             aResult.SetToken( p->GetResultToken().get() );
    1333             :         }
    1334             :         else
    1335             :         {
    1336        3377 :             ScFormulaResult aNewResult( p->GetResultToken().get());
    1337        3377 :             StackVar eOld = aResult.GetCellResultType();
    1338        3377 :             StackVar eNew = aNewResult.GetCellResultType();
    1339        2427 :             bChanged = (eOld != eNew ||
    1340        6759 :                     (eNew == svDouble && aResult.GetDouble() != aNewResult.GetDouble()) ||
    1341        3385 :                     (eNew == svString && aResult.GetString() != aNewResult.GetString()));
    1342             : 
    1343             :             // #i102616# handle special cases of initial results after loading (only if the sheet is still marked unchanged)
    1344        3377 :             if ( bChanged && !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
    1345             :             {
    1346           0 :                 if ( ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) ) ||
    1347           0 :                      ( (eOld == svHybridCell || eOld == svHybridValueCell) && eNew == svString && aResult.GetString() == aNewResult.GetString() ) ||
    1348           0 :                      ( eOld == svDouble && eNew == svDouble && rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() ) ) )
    1349             :                 {
    1350             :                     // no change, see above
    1351             :                 }
    1352             :                 else
    1353           0 :                     bContentChanged = true;
    1354             :             }
    1355             : 
    1356        3377 :             aResult.Assign( aNewResult);
    1357             :         }
    1358             : 
    1359             :         // Precision as shown?
    1360       13805 :         if ( aResult.IsValue() && !p->GetError()
    1361        4354 :           && pDocument->GetDocOptions().IsCalcAsShown()
    1362          14 :           && nFormatType != NUMBERFORMAT_DATE
    1363          14 :           && nFormatType != NUMBERFORMAT_TIME
    1364        4648 :           && nFormatType != NUMBERFORMAT_DATETIME )
    1365             :         {
    1366          14 :             sal_uLong nFormat = pDocument->GetNumberFormat( aPos );
    1367             :             aResult.SetDouble( pDocument->RoundValueAsShown(
    1368          14 :                         aResult.GetDouble(), nFormat));
    1369             :         }
    1370        4634 :         if (eTailParam == SCITP_NORMAL)
    1371             :         {
    1372        4634 :             bDirty = false;
    1373        4634 :             bTableOpDirty = false;
    1374             :         }
    1375        4634 :         if( aResult.GetMatrix() )
    1376             :         {
    1377             :             // If the formula wasn't entered as a matrix formula, live on with
    1378             :             // the upper left corner and let reference counting delete the matrix.
    1379          42 :             if( cMatrixFlag != MM_FORMULA && !pCode->IsHyperLink() )
    1380          23 :                 aResult.SetToken( aResult.GetCellResultToken().get());
    1381             :         }
    1382        4634 :         if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
    1383             :         {
    1384             :             // Coded double error may occur via filter import.
    1385           0 :             sal_uInt16 nErr = GetDoubleErrorValue( aResult.GetDouble());
    1386           0 :             aResult.SetResultError( nErr);
    1387           0 :             bChanged = bContentChanged = true;
    1388             :         }
    1389             : 
    1390        4634 :         if (bContentChanged && pDocument->IsStreamValid(aPos.Tab()))
    1391             :         {
    1392             :             // pass bIgnoreLock=true, because even if called from pending row height update,
    1393             :             // a changed result must still reset the stream flag
    1394           6 :             pDocument->SetStreamValid(aPos.Tab(), false, true);
    1395             :         }
    1396        4634 :         if ( !pCode->IsRecalcModeAlways() )
    1397        4598 :             pDocument->RemoveFromFormulaTree( this );
    1398             : 
    1399             :         //  FORCED cells also immediately tested for validity (start macro possibly)
    1400             : 
    1401        4634 :         if ( pCode->IsRecalcModeForced() )
    1402             :         {
    1403             :             sal_uLong nValidation = ((const SfxUInt32Item*) pDocument->GetAttr(
    1404           0 :                     aPos.Col(), aPos.Row(), aPos.Tab(), ATTR_VALIDDATA ))->GetValue();
    1405           0 :             if ( nValidation )
    1406             :             {
    1407           0 :                 const ScValidationData* pData = pDocument->GetValidationEntry( nValidation );
    1408           0 :                 ScRefCellValue aTmpCell(this);
    1409           0 :                 if ( pData && !pData->IsDataValid(aTmpCell, aPos))
    1410           0 :                     pData->DoCalcError( this );
    1411             :             }
    1412             :         }
    1413             : 
    1414             :         // Reschedule slows the whole thing down considerably, thus only execute on percent change
    1415             :         ScProgress::GetInterpretProgress()->SetStateCountDownOnPercent(
    1416        4634 :             pDocument->GetFormulaCodeInTree()/MIN_NO_CODES_PER_PROGRESS_UPDATE );
    1417             : 
    1418        4634 :         switch (p->GetVolatileType())
    1419             :         {
    1420             :             case ScInterpreter::VOLATILE:
    1421             :                 // Volatile via built-in volatile functions.  No actions needed.
    1422          36 :             break;
    1423             :             case ScInterpreter::VOLATILE_MACRO:
    1424             :                 // The formula contains a volatile macro.
    1425           0 :                 pCode->SetExclusiveRecalcModeAlways();
    1426           0 :                 pDocument->PutInFormulaTree(this);
    1427           0 :                 StartListeningTo(pDocument);
    1428           0 :             break;
    1429             :             case ScInterpreter::NOT_VOLATILE:
    1430        4598 :                 if (pCode->IsRecalcModeAlways())
    1431             :                 {
    1432             :                     // The formula was previously volatile, but no more.
    1433           0 :                     EndListeningTo(pDocument);
    1434           0 :                     pCode->SetExclusiveRecalcModeNormal();
    1435             :                 }
    1436             :                 else
    1437             :                 {
    1438             :                     // non-volatile formula.  End listening to the area in case
    1439             :                     // it's listening due to macro module change.
    1440        4598 :                     pDocument->EndListeningArea(BCA_LISTEN_ALWAYS, this);
    1441             :                 }
    1442        4598 :                 pDocument->RemoveFromFormulaTree(this);
    1443        4598 :             break;
    1444             :             default:
    1445             :                 ;
    1446        4634 :         }
    1447             :     }
    1448             :     else
    1449             :     {
    1450             :         // Cells with compiler errors should not be marked dirty forever
    1451             :         OSL_ENSURE( pCode->GetCodeError(), "no UPN-Code und no errors ?!?!" );
    1452          45 :         bDirty = false;
    1453          45 :         bTableOpDirty = false;
    1454        4679 :     }
    1455             : }
    1456             : 
    1457             : 
    1458          36 : void ScFormulaCell::SetMatColsRows( SCCOL nCols, SCROW nRows, bool bDirtyFlag )
    1459             : {
    1460          36 :     ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellTokenNonConst();
    1461          36 :     if (pMat)
    1462           0 :         pMat->SetMatColsRows( nCols, nRows );
    1463          36 :     else if (nCols || nRows)
    1464             :     {
    1465          36 :         aResult.SetToken( new ScMatrixFormulaCellToken( nCols, nRows));
    1466             :         // Setting the new token actually forces an empty result at this top
    1467             :         // left cell, so have that recalculated.
    1468          36 :         SetDirty( bDirtyFlag );
    1469             :     }
    1470          36 : }
    1471             : 
    1472             : 
    1473           4 : void ScFormulaCell::GetMatColsRows( SCCOL & nCols, SCROW & nRows ) const
    1474             : {
    1475           4 :     const ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellToken();
    1476           4 :     if (pMat)
    1477           4 :         pMat->GetMatColsRows( nCols, nRows);
    1478             :     else
    1479             :     {
    1480           0 :         nCols = 0;
    1481           0 :         nRows = 0;
    1482             :     }
    1483           4 : }
    1484             : 
    1485             : 
    1486        3339 : void ScFormulaCell::Notify( SvtBroadcaster&, const SfxHint& rHint)
    1487             : {
    1488        3339 :     if ( !pDocument->IsInDtorClear() && !pDocument->GetHardRecalcState() )
    1489             :     {
    1490         674 :         const ScHint* p = PTR_CAST( ScHint, &rHint );
    1491         674 :         sal_uLong nHint = (p ? p->GetId() : 0);
    1492         674 :         if (nHint & (SC_HINT_DATACHANGED | SC_HINT_TABLEOPDIRTY))
    1493             :         {
    1494         672 :             bool bForceTrack = false;
    1495         672 :             if ( nHint & SC_HINT_TABLEOPDIRTY )
    1496             :             {
    1497           0 :                 bForceTrack = !bTableOpDirty;
    1498           0 :                 if ( !bTableOpDirty )
    1499             :                 {
    1500           0 :                     pDocument->AddTableOpFormulaCell( this );
    1501           0 :                     bTableOpDirty = true;
    1502             :                 }
    1503             :             }
    1504             :             else
    1505             :             {
    1506         672 :                 bForceTrack = !bDirty;
    1507         672 :                 SetDirtyVar();
    1508             :             }
    1509             :             // Don't remove from FormulaTree to put in FormulaTrack to
    1510             :             // put in FormulaTree again and again, only if necessary.
    1511             :             // Any other means except RECALCMODE_ALWAYS by which a cell could
    1512             :             // be in FormulaTree if it would notify other cells through
    1513             :             // FormulaTrack which weren't in FormulaTrack/FormulaTree before?!?
    1514             :             // Yes. The new TableOpDirty made it necessary to have a
    1515             :             // forced mode where formulas may still be in FormulaTree from
    1516             :             // TableOpDirty but have to notify dependents for normal dirty.
    1517        1076 :             if ( (bForceTrack || !pDocument->IsInFormulaTree( this )
    1518         394 :                     || pCode->IsRecalcModeAlways())
    1519         968 :                     && !pDocument->IsInFormulaTrack( this ) )
    1520         291 :                 pDocument->AppendToFormulaTrack( this );
    1521             :         }
    1522             :     }
    1523        3339 : }
    1524             : 
    1525        1114 : void ScFormulaCell::SetDirty( bool bDirtyFlag )
    1526             : {
    1527        1114 :     if ( !IsInChangeTrack() )
    1528             :     {
    1529        1114 :         if ( pDocument->GetHardRecalcState() )
    1530           0 :             SetDirtyVar();
    1531             :         else
    1532             :         {
    1533             :             // Multiple Formulas avoid tracking in Load and Copy compileAll
    1534             :             // by Scenario and Copy Block From Clip.
    1535             :             // If unconditional required Formula tracking is set before SetDirty
    1536             :             // bDirty = false, eg in CompileTokenArray
    1537        1114 :             if ( !bDirty || !pDocument->IsInFormulaTree( this ) )
    1538             :             {
    1539        1041 :                 if( bDirtyFlag )
    1540        1010 :                     SetDirtyVar();
    1541        1041 :                 pDocument->AppendToFormulaTrack( this );
    1542        1041 :                 pDocument->TrackFormulas();
    1543             :             }
    1544             :         }
    1545             : 
    1546        1114 :         if (pDocument->IsStreamValid(aPos.Tab()))
    1547           1 :             pDocument->SetStreamValid(aPos.Tab(), false);
    1548             :     }
    1549        1114 : }
    1550             : 
    1551        2616 : void ScFormulaCell::SetDirtyVar()
    1552             : {
    1553        2616 :     bDirty = true;
    1554        2616 :     if (xGroup)
    1555         424 :         xGroup->meCalcState = sc::GroupCalcEnabled;
    1556             : 
    1557             :     // mark the sheet of this cell to be calculated
    1558             :     //#FIXME do we need to revert this remnant of old fake vba events? pDocument->AddCalculateTable( aPos.Tab() );
    1559        2616 : }
    1560             : 
    1561        2473 : void ScFormulaCell::SetDirtyAfterLoad()
    1562             : {
    1563        2473 :     bDirty = true;
    1564        2473 :     if ( !pDocument->GetHardRecalcState() )
    1565        2473 :         pDocument->PutInFormulaTree( this );
    1566        2473 : }
    1567             : 
    1568           0 : void ScFormulaCell::SetTableOpDirty()
    1569             : {
    1570           0 :     if ( !IsInChangeTrack() )
    1571             :     {
    1572           0 :         if ( pDocument->GetHardRecalcState() )
    1573           0 :             bTableOpDirty = true;
    1574             :         else
    1575             :         {
    1576           0 :             if ( !bTableOpDirty || !pDocument->IsInFormulaTree( this ) )
    1577             :             {
    1578           0 :                 if ( !bTableOpDirty )
    1579             :                 {
    1580           0 :                     pDocument->AddTableOpFormulaCell( this );
    1581           0 :                     bTableOpDirty = true;
    1582             :                 }
    1583           0 :                 pDocument->AppendToFormulaTrack( this );
    1584           0 :                 pDocument->TrackFormulas( SC_HINT_TABLEOPDIRTY );
    1585             :             }
    1586             :         }
    1587             :     }
    1588           0 : }
    1589             : 
    1590             : 
    1591       30563 : bool ScFormulaCell::IsDirtyOrInTableOpDirty() const
    1592             : {
    1593       30563 :     return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp());
    1594             : }
    1595             : 
    1596           0 : void ScFormulaCell::SetResultToken( const formula::FormulaToken* pToken )
    1597             : {
    1598           0 :     aResult.SetToken(pToken);
    1599           0 : }
    1600             : 
    1601          25 : void ScFormulaCell::SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL )
    1602             : {
    1603          25 :     aResult.SetMatrix(nCols, nRows, pMat, pUL);
    1604          25 : }
    1605             : 
    1606          25 : void ScFormulaCell::SetErrCode( sal_uInt16 n )
    1607             : {
    1608             :     /* FIXME: check the numerous places where ScTokenArray::GetCodeError() is
    1609             :      * used whether it is solely for transport of a simple result error and get
    1610             :      * rid of that abuse. */
    1611          25 :     pCode->SetCodeError( n );
    1612             :     // Hard set errors are transported as result type value per convention,
    1613             :     // e.g. via clipboard. ScFormulaResult::IsValue() and
    1614             :     // ScFormulaResult::GetDouble() handle that.
    1615          25 :     aResult.SetResultError( n );
    1616          25 : }
    1617             : 
    1618          20 : void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits )
    1619             : {
    1620          20 :     if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL )
    1621          20 :         SetDirtyVar();
    1622          20 :     if ( nBits & RECALCMODE_ONLOAD_ONCE )
    1623             :     {   // OnLoadOnce nur zum Dirty setzen nach Filter-Import
    1624          20 :         nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL;
    1625             :     }
    1626          20 :     pCode->AddRecalcMode( nBits );
    1627          20 : }
    1628             : 
    1629             : // Dynamically create the URLField on a mouse-over action on a hyperlink() cell.
    1630           0 : void ScFormulaCell::GetURLResult( OUString& rURL, OUString& rCellText )
    1631             : {
    1632           0 :     OUString aCellString;
    1633             : 
    1634             :     Color* pColor;
    1635             : 
    1636             :     // Cell Text uses the Cell format while the URL uses
    1637             :     // the default format for the type.
    1638           0 :     sal_uLong nCellFormat = pDocument->GetNumberFormat( aPos );
    1639           0 :     SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
    1640             : 
    1641           0 :     sal_uLong nURLFormat = ScGlobal::GetStandardFormat( *pFormatter, nCellFormat, NUMBERFORMAT_NUMBER);
    1642             : 
    1643           0 :     if ( IsValue() )
    1644             :     {
    1645           0 :         double fValue = GetValue();
    1646           0 :         pFormatter->GetOutputString( fValue, nCellFormat, rCellText, &pColor );
    1647             :     }
    1648             :     else
    1649             :     {
    1650           0 :         aCellString = GetString();
    1651           0 :         pFormatter->GetOutputString( aCellString, nCellFormat, rCellText, &pColor );
    1652             :     }
    1653           0 :     ScConstMatrixRef xMat( aResult.GetMatrix());
    1654           0 :     if (xMat)
    1655             :     {
    1656             :         // determine if the matrix result is a string or value.
    1657           0 :         if (!xMat->IsValue(0, 1))
    1658           0 :             rURL = xMat->GetString(0, 1);
    1659             :         else
    1660             :             pFormatter->GetOutputString(
    1661           0 :                 xMat->GetDouble(0, 1), nURLFormat, rURL, &pColor);
    1662             :     }
    1663             : 
    1664           0 :     if(rURL.isEmpty())
    1665             :     {
    1666           0 :         if(IsValue())
    1667           0 :             pFormatter->GetOutputString( GetValue(), nURLFormat, rURL, &pColor );
    1668             :         else
    1669           0 :             pFormatter->GetOutputString( aCellString, nURLFormat, rURL, &pColor );
    1670           0 :     }
    1671           0 : }
    1672             : 
    1673         526 : bool ScFormulaCell::IsMultilineResult()
    1674             : {
    1675         526 :     if (!IsValue())
    1676         120 :         return aResult.IsMultiline();
    1677         406 :     return false;
    1678             : }
    1679             : 
    1680       25714 : void ScFormulaCell::MaybeInterpret()
    1681             : {
    1682       25714 :     if (!IsDirtyOrInTableOpDirty())
    1683       47354 :         return;
    1684             : 
    1685        4074 :     if (pDocument->GetAutoCalc() || (cMatrixFlag != MM_NONE))
    1686        3924 :         Interpret();
    1687             : }
    1688             : 
    1689           0 : bool ScFormulaCell::IsHyperLinkCell() const
    1690             : {
    1691           0 :     return pCode && pCode->IsHyperLink();
    1692             : }
    1693             : 
    1694           0 : EditTextObject* ScFormulaCell::CreateURLObject()
    1695             : {
    1696           0 :     OUString aCellText;
    1697           0 :     OUString aURL;
    1698           0 :     GetURLResult( aURL, aCellText );
    1699             : 
    1700           0 :     return ScEditUtil::CreateURLObjectFromURL( *pDocument, aURL, aCellText );
    1701             : }
    1702             : 
    1703         251 : bool ScFormulaCell::IsEmpty()
    1704             : {
    1705         251 :     MaybeInterpret();
    1706         251 :     return aResult.GetCellResultType() == formula::svEmptyCell;
    1707             : }
    1708             : 
    1709        1130 : bool ScFormulaCell::IsEmptyDisplayedAsString()
    1710             : {
    1711        1130 :     MaybeInterpret();
    1712        1130 :     return aResult.IsEmptyDisplayedAsString();
    1713             : }
    1714             : 
    1715        8680 : bool ScFormulaCell::IsValue()
    1716             : {
    1717        8680 :     MaybeInterpret();
    1718        8680 :     return aResult.IsValue();
    1719             : }
    1720             : 
    1721          12 : bool ScFormulaCell::IsValueNoError()
    1722             : {
    1723          12 :     MaybeInterpret();
    1724          12 :     if (pCode->GetCodeError())
    1725           0 :         return false;
    1726             : 
    1727          12 :     return aResult.IsValueNoError();
    1728             : }
    1729             : 
    1730         977 : bool ScFormulaCell::IsHybridValueCell()
    1731             : {
    1732         977 :     return aResult.GetType() == formula::svHybridValueCell;
    1733             : }
    1734             : 
    1735       10637 : double ScFormulaCell::GetValue()
    1736             : {
    1737       10637 :     MaybeInterpret();
    1738       21182 :     if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) &&
    1739       10545 :             !aResult.GetResultError())
    1740       10445 :         return aResult.GetDouble();
    1741         192 :     return 0.0;
    1742             : }
    1743             : 
    1744           5 : double ScFormulaCell::GetValueAlways()
    1745             : {
    1746             :     // for goal seek: return result value even if error code is set
    1747           5 :     MaybeInterpret();
    1748           5 :     return aResult.GetDouble();
    1749             : }
    1750             : 
    1751         177 : OUString ScFormulaCell::GetString()
    1752             : {
    1753         177 :     MaybeInterpret();
    1754         338 :     if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) &&
    1755         161 :             !aResult.GetResultError())
    1756         161 :         return aResult.GetString();
    1757          16 :     return OUString();
    1758             : }
    1759             : 
    1760          86 : const ScMatrix* ScFormulaCell::GetMatrix()
    1761             : {
    1762          86 :     if ( pDocument->GetAutoCalc() )
    1763             :     {
    1764         258 :         if( IsDirtyOrInTableOpDirty()
    1765             :         // Was stored !bDirty but an accompanying matrix cell was bDirty?
    1766         344 :         || (!bDirty && cMatrixFlag == MM_FORMULA && !aResult.GetMatrix()))
    1767          33 :             Interpret();
    1768             :     }
    1769          86 :     return aResult.GetMatrix().get();
    1770             : }
    1771             : 
    1772          14 : bool ScFormulaCell::GetMatrixOrigin( ScAddress& rPos ) const
    1773             : {
    1774          14 :     switch ( cMatrixFlag )
    1775             :     {
    1776             :         case MM_FORMULA :
    1777           1 :             rPos = aPos;
    1778           1 :             return true;
    1779             :         case MM_REFERENCE :
    1780             :         {
    1781          13 :             pCode->Reset();
    1782          13 :             ScToken* t = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
    1783          13 :             if( t )
    1784             :             {
    1785          13 :                 ScSingleRefData& rRef = t->GetSingleRef();
    1786          13 :                 rRef.CalcAbsIfRel( aPos );
    1787          13 :                 if ( rRef.Valid() )
    1788             :                 {
    1789          13 :                     rPos.Set( rRef.nCol, rRef.nRow, rRef.nTab );
    1790          13 :                     return true;
    1791             :                 }
    1792             :             }
    1793             :         }
    1794           0 :         break;
    1795             :     }
    1796           0 :     return false;
    1797             : }
    1798             : 
    1799             : 
    1800             : /*
    1801             :  Edge-Values:
    1802             : 
    1803             :    8
    1804             :  4   16
    1805             :    2
    1806             : 
    1807             :  inside: 1
    1808             :  outside: 0
    1809             :  (reserved: open: 32)
    1810             :  */
    1811             : 
    1812           0 : sal_uInt16 ScFormulaCell::GetMatrixEdge( ScAddress& rOrgPos ) const
    1813             : {
    1814           0 :     switch ( cMatrixFlag )
    1815             :     {
    1816             :         case MM_FORMULA :
    1817             :         case MM_REFERENCE :
    1818             :         {
    1819             :             static SCCOL nC;
    1820             :             static SCROW nR;
    1821           0 :             ScAddress aOrg;
    1822           0 :             if ( !GetMatrixOrigin( aOrg ) )
    1823           0 :                 return 0;               // bad luck..
    1824           0 :             if ( aOrg != rOrgPos )
    1825             :             {   // First time or a different matrix than last time.
    1826           0 :                 rOrgPos = aOrg;
    1827             :                 const ScFormulaCell* pFCell;
    1828           0 :                 if ( cMatrixFlag == MM_REFERENCE )
    1829           0 :                     pFCell = pDocument->GetFormulaCell(aOrg);
    1830             :                 else
    1831           0 :                     pFCell = this;      // this MM_FORMULA
    1832             :                 // There's only one this, don't compare pFCell==this.
    1833           0 :                 if (pFCell && pFCell->cMatrixFlag == MM_FORMULA)
    1834             :                 {
    1835           0 :                     pFCell->GetMatColsRows( nC, nR );
    1836           0 :                     if ( nC == 0 || nR == 0 )
    1837             :                     {
    1838             :                         // No ScMatrixFormulaCellToken available yet, calculate new.
    1839           0 :                         nC = 1;
    1840           0 :                         nR = 1;
    1841           0 :                         ScAddress aTmpOrg;
    1842             :                         ScFormulaCell* pCell;
    1843           0 :                         ScAddress aAdr( aOrg );
    1844           0 :                         aAdr.IncCol();
    1845           0 :                         bool bCont = true;
    1846           0 :                         do
    1847             :                         {
    1848           0 :                             pCell = pDocument->GetFormulaCell(aAdr);
    1849           0 :                             if (pCell && pCell->cMatrixFlag == MM_REFERENCE &&
    1850           0 :                                 pCell->GetMatrixOrigin(aTmpOrg) && aTmpOrg == aOrg)
    1851             :                             {
    1852           0 :                                 nC++;
    1853           0 :                                 aAdr.IncCol();
    1854             :                             }
    1855             :                             else
    1856           0 :                                 bCont = false;
    1857             :                         } while ( bCont );
    1858           0 :                         aAdr = aOrg;
    1859           0 :                         aAdr.IncRow();
    1860           0 :                         bCont = true;
    1861           0 :                         do
    1862             :                         {
    1863           0 :                             pCell = pDocument->GetFormulaCell(aAdr);
    1864           0 :                             if (pCell && pCell->cMatrixFlag == MM_REFERENCE &&
    1865           0 :                                 pCell->GetMatrixOrigin(aTmpOrg) && aTmpOrg == aOrg)
    1866             :                             {
    1867           0 :                                 nR++;
    1868           0 :                                 aAdr.IncRow();
    1869             :                             }
    1870             :                             else
    1871           0 :                                 bCont = false;
    1872             :                         } while ( bCont );
    1873             : 
    1874           0 :                         const_cast<ScFormulaCell*>(pFCell)->SetMatColsRows(nC, nR);
    1875           0 :                     }
    1876             :                 }
    1877             :                 else
    1878             :                 {
    1879             : #if OSL_DEBUG_LEVEL > 0
    1880             :                     OUString aTmp;
    1881             :                     OStringBuffer aMsg(RTL_CONSTASCII_STRINGPARAM(
    1882             :                         "broken Matrix, no MatFormula at origin, Pos: "));
    1883             :                     aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
    1884             :                     aMsg.append(OUStringToOString(aTmp, RTL_TEXTENCODING_ASCII_US));
    1885             :                     aMsg.append(RTL_CONSTASCII_STRINGPARAM(", MatOrg: "));
    1886             :                     aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
    1887             :                     aMsg.append(OUStringToOString(aTmp, RTL_TEXTENCODING_ASCII_US));
    1888             :                     OSL_FAIL(aMsg.getStr());
    1889             : #endif
    1890           0 :                     return 0;           // bad luck ...
    1891             :                 }
    1892             :             }
    1893             :             // here we are, healthy and clean, somewhere in between
    1894           0 :             SCsCOL dC = aPos.Col() - aOrg.Col();
    1895           0 :             SCsROW dR = aPos.Row() - aOrg.Row();
    1896           0 :             sal_uInt16 nEdges = 0;
    1897           0 :             if ( dC >= 0 && dR >= 0 && dC < nC && dR < nR )
    1898             :             {
    1899           0 :                 if ( dC == 0 )
    1900           0 :                     nEdges |= sc::MatrixEdgeLeft;            // left edge
    1901           0 :                 if ( dC+1 == nC )
    1902           0 :                     nEdges |= sc::MatrixEdgeRight;           // right edge
    1903           0 :                 if ( dR == 0 )
    1904           0 :                     nEdges |= sc::MatrixEdgeTop;            // top edge
    1905           0 :                 if ( dR+1 == nR )
    1906           0 :                     nEdges |= sc::MatrixEdgeBottom;            // bottom edge
    1907           0 :                 if ( !nEdges )
    1908           0 :                     nEdges = sc::MatrixEdgeInside;             // inside
    1909             :             }
    1910             : #if OSL_DEBUG_LEVEL > 0
    1911             :             else
    1912             :             {
    1913             :                 OUString aTmp;
    1914             :                 OStringBuffer aMsg( "broken Matrix, Pos: " );
    1915             :                 aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
    1916             :                 aMsg.append(OUStringToOString(aTmp, RTL_TEXTENCODING_UTF8 ));
    1917             :                 aMsg.append(RTL_CONSTASCII_STRINGPARAM(", MatOrg: "));
    1918             :                 aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
    1919             :                 aMsg.append(OUStringToOString(aTmp, RTL_TEXTENCODING_UTF8 ));
    1920             :                 aMsg.append(RTL_CONSTASCII_STRINGPARAM(", MatCols: "));
    1921             :                 aMsg.append(static_cast<sal_Int32>( nC ));
    1922             :                 aMsg.append(RTL_CONSTASCII_STRINGPARAM(", MatRows: "));
    1923             :                 aMsg.append(static_cast<sal_Int32>( nR ));
    1924             :                 aMsg.append(RTL_CONSTASCII_STRINGPARAM(", DiffCols: "));
    1925             :                 aMsg.append(static_cast<sal_Int32>( dC ));
    1926             :                 aMsg.append(RTL_CONSTASCII_STRINGPARAM(", DiffRows: "));
    1927             :                 aMsg.append(static_cast<sal_Int32>( dR ));
    1928             :                 OSL_FAIL( aMsg.makeStringAndClear().getStr());
    1929             :             }
    1930             : #endif
    1931           0 :             return nEdges;
    1932             : //            break;
    1933             :         }
    1934             :         default:
    1935           0 :             return 0;
    1936             :     }
    1937             : }
    1938             : 
    1939        4053 : sal_uInt16 ScFormulaCell::GetErrCode()
    1940             : {
    1941        4053 :     MaybeInterpret();
    1942             : 
    1943             :     /* FIXME: If ScTokenArray::SetCodeError() was really only for code errors
    1944             :      * and not also abused for signaling other error conditions we could bail
    1945             :      * out even before attempting to interpret broken code. */
    1946        4053 :     sal_uInt16 nErr =  pCode->GetCodeError();
    1947        4053 :     if (nErr)
    1948          73 :         return nErr;
    1949        3980 :     return aResult.GetResultError();
    1950             : }
    1951             : 
    1952          36 : sal_uInt16 ScFormulaCell::GetRawError()
    1953             : {
    1954          36 :     sal_uInt16 nErr =  pCode->GetCodeError();
    1955          36 :     if (nErr)
    1956           0 :         return nErr;
    1957          36 :     return aResult.GetResultError();
    1958             : }
    1959             : 
    1960           5 : bool ScFormulaCell::GetErrorOrValue( sal_uInt16& rErr, double& rVal )
    1961             : {
    1962           5 :     MaybeInterpret();
    1963             : 
    1964           5 :     rErr = pCode->GetCodeError();
    1965           5 :     if (rErr)
    1966           0 :         return true;
    1967             : 
    1968           5 :     return aResult.GetErrorOrDouble(rErr, rVal);
    1969             : }
    1970             : 
    1971           9 : bool ScFormulaCell::HasOneReference( ScRange& r ) const
    1972             : {
    1973           9 :     pCode->Reset();
    1974           9 :     ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
    1975           9 :     if( p && !pCode->GetNextReferenceRPN() )        // only one!
    1976             :     {
    1977           9 :         p->CalcAbsIfRel( aPos );
    1978           9 :         SingleDoubleRefProvider aProv( *p );
    1979             :         r.aStart.Set( aProv.Ref1.nCol,
    1980             :                       aProv.Ref1.nRow,
    1981           9 :                       aProv.Ref1.nTab );
    1982             :         r.aEnd.Set( aProv.Ref2.nCol,
    1983             :                     aProv.Ref2.nRow,
    1984           9 :                     aProv.Ref2.nTab );
    1985           9 :         return true;
    1986             :     }
    1987             :     else
    1988           0 :         return false;
    1989             : }
    1990             : 
    1991             : bool
    1992           9 : ScFormulaCell::HasRefListExpressibleAsOneReference(ScRange& rRange) const
    1993             : {
    1994             :     /* If there appears just one reference in the formula, it's the same
    1995             :        as HasOneReference(). If there are more of them, they can denote
    1996             :        one range if they are (sole) arguments of one function.
    1997             :        Union of these references must form one range and their
    1998             :        intersection must be empty set.
    1999             :     */
    2000             : 
    2001             :     // Detect the simple case of exactly one reference in advance without all
    2002             :     // overhead.
    2003             :     // #i107741# Doing so actually makes outlines using SUBTOTAL(x;reference)
    2004             :     // work again, where the function does not have only references.
    2005           9 :     if (HasOneReference( rRange))
    2006           9 :         return true;
    2007             : 
    2008           0 :     pCode->Reset();
    2009             :     // Get first reference, if any
    2010             :     ScToken* const pFirstReference(
    2011           0 :             dynamic_cast<ScToken*>(pCode->GetNextReferenceRPN()));
    2012           0 :     if (pFirstReference)
    2013             :     {
    2014             :         // Collect all consecutive references, starting by the one
    2015             :         // already found
    2016           0 :         std::deque<ScToken*> aReferences;
    2017           0 :         aReferences.push_back(pFirstReference);
    2018           0 :         FormulaToken* pToken(pCode->NextRPN());
    2019           0 :         FormulaToken* pFunction(0);
    2020           0 :         while (pToken)
    2021             :         {
    2022           0 :             if (lcl_isReference(*pToken))
    2023             :             {
    2024           0 :                 aReferences.push_back(dynamic_cast<ScToken*>(pToken));
    2025           0 :                 pToken = pCode->NextRPN();
    2026             :             }
    2027             :             else
    2028             :             {
    2029           0 :                 if (pToken->IsFunction())
    2030             :                 {
    2031           0 :                     pFunction = pToken;
    2032             :                 }
    2033           0 :                 break;
    2034             :             }
    2035             :         }
    2036           0 :         if (pFunction && !pCode->GetNextReferenceRPN()
    2037           0 :                 && (pFunction->GetParamCount() == aReferences.size()))
    2038             :         {
    2039           0 :             return lcl_refListFormsOneRange(aPos, aReferences, rRange);
    2040           0 :         }
    2041             :     }
    2042           0 :     return false;
    2043             : }
    2044             : 
    2045          72 : bool ScFormulaCell::HasRelNameReference() const
    2046             : {
    2047          72 :     pCode->Reset();
    2048             :     ScToken* t;
    2049          72 :     while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceRPN()) ) != NULL )
    2050             :     {
    2051         158 :         if ( t->GetSingleRef().IsRelName() ||
    2052          89 :                 (t->GetType() == formula::svDoubleRef &&
    2053          10 :                 t->GetDoubleRef().Ref2.IsRelName()) )
    2054           0 :             return true;
    2055             :     }
    2056          72 :     return false;
    2057             : }
    2058             : 
    2059           0 : bool ScFormulaCell::HasColRowName() const
    2060             : {
    2061           0 :     pCode->Reset();
    2062           0 :     return (pCode->GetNextColRowName() != NULL);
    2063             : }
    2064             : 
    2065          51 : bool ScFormulaCell::UpdateReference(
    2066             :     UpdateRefMode eUpdateRefMode, const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
    2067             :     ScDocument* pUndoDoc, const ScAddress* pUndoCellPos )
    2068             : {
    2069          51 :     bool bCellStateChanged = false;
    2070             : 
    2071          51 :     SCCOL nCol1 = rRange.aStart.Col();
    2072          51 :     SCROW nRow1 = rRange.aStart.Row();
    2073          51 :     SCCOL nCol = aPos.Col();
    2074          51 :     SCROW nRow = aPos.Row();
    2075          51 :     SCTAB nTab = aPos.Tab();
    2076          51 :     ScAddress aUndoPos( aPos );         // position for undo cell in pUndoDoc
    2077          51 :     if ( pUndoCellPos )
    2078          34 :         aUndoPos = *pUndoCellPos;
    2079          51 :     ScAddress aOldPos( aPos );
    2080          51 :     bool bIsInsert = (eUpdateRefMode == URM_INSDEL && nDx >= 0 && nDy >= 0 && nDz >= 0);
    2081             : 
    2082          51 :     if (eUpdateRefMode == URM_INSDEL && rRange.In(aPos))
    2083             :     {
    2084             :         // This formula cell itself is being shifted during cell range
    2085             :         // insertion or deletion. Update its position.
    2086           3 :         aPos.Move(nDx, nDy, nDz);
    2087           3 :         bCellStateChanged = aPos != aOldPos;
    2088             :     }
    2089          48 :     else if (rRange.In(aPos))
    2090             :     {
    2091             :         // The cell is being moved or copied to a new position. I guess the
    2092             :         // position has been updated prior to this call?  Determine
    2093             :         // its original position before the move which will be used to adjust
    2094             :         // relative references later.
    2095          17 :         aOldPos.Set( nCol - nDx, nRow - nDy, nTab - nDz );
    2096             :     }
    2097             : 
    2098          51 :     bool bHasRefs = false;
    2099          51 :     bool bHasColRowNames = false;
    2100          51 :     bool bOnRefMove = false;
    2101          51 :     if ( !pDocument->IsClipOrUndo() )
    2102             :     {
    2103             :         // Check presence of any references or column row names.
    2104          51 :         pCode->Reset();
    2105          51 :         bHasRefs = (pCode->GetNextReferenceRPN() != NULL);
    2106          51 :         if ( !bHasRefs || eUpdateRefMode == URM_COPY )
    2107             :         {
    2108          25 :             pCode->Reset();
    2109          25 :             bHasColRowNames = (pCode->GetNextColRowName() != NULL);
    2110          25 :             bHasRefs = bHasRefs || bHasColRowNames;
    2111             :         }
    2112          51 :         bOnRefMove = pCode->IsRecalcModeOnRefMove();
    2113             :     }
    2114             : 
    2115          51 :     if (!bHasRefs && !bOnRefMove)
    2116             :         // This formula cell contains no references, nor needs recalculating
    2117             :         // on reference update. Bail out.
    2118           5 :         return bCellStateChanged;
    2119             : 
    2120          46 :     boost::scoped_ptr<ScTokenArray> pOldCode;
    2121          46 :     if (pUndoDoc)
    2122           5 :         pOldCode.reset(pCode->Clone());
    2123             : 
    2124          46 :     ScRangeData* pSharedCode = NULL;
    2125          46 :     bool bValChanged = false;
    2126          46 :     bool bRangeModified = false;    // any range, not only shared formula
    2127          46 :     bool bRefSizeChanged = false;
    2128             : 
    2129          46 :     if (bHasRefs)
    2130             :     {
    2131             :         // Update cell or range references.
    2132          43 :         ScCompiler aComp(pDocument, aPos, *pCode);
    2133          43 :         aComp.SetGrammar(pDocument->GetGrammar());
    2134             :         pSharedCode = aComp.UpdateReference(eUpdateRefMode, aOldPos, rRange,
    2135             :                                          nDx, nDy, nDz,
    2136          43 :                                          bValChanged, bRefSizeChanged);
    2137          43 :         bRangeModified = aComp.HasModifiedRange();
    2138             :     }
    2139             : 
    2140          46 :     bCellStateChanged |= bValChanged;
    2141             : 
    2142          46 :     if (bOnRefMove)
    2143             :         // Cell may reference itself, e.g. ocColumn, ocRow without parameter
    2144           5 :         bOnRefMove = (bValChanged || (aPos != aOldPos));
    2145             : 
    2146          46 :     bool bColRowNameCompile = false;
    2147          46 :     bool bHasRelName = false;
    2148          46 :     bool bNewListening = false;
    2149          46 :     bool bInDeleteUndo = false;
    2150             : 
    2151          46 :     if (bHasRefs)
    2152             :     {
    2153             :         // Upon Insert ColRowNames have to be recompiled in case the
    2154             :         // insertion occurs right in front of the range.
    2155             :         bColRowNameCompile =
    2156          43 :             (eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0));
    2157             : 
    2158          43 :         if ( bColRowNameCompile )
    2159             :         {
    2160          11 :             bColRowNameCompile = false;
    2161             :             ScToken* t;
    2162          11 :             ScRangePairList* pColList = pDocument->GetColNameRanges();
    2163          11 :             ScRangePairList* pRowList = pDocument->GetRowNameRanges();
    2164          11 :             pCode->Reset();
    2165          22 :             while ( !bColRowNameCompile && (t = static_cast<ScToken*>(pCode->GetNextColRowName())) != NULL )
    2166             :             {
    2167           0 :                 ScSingleRefData& rRef = t->GetSingleRef();
    2168           0 :                 if ( nDy > 0 && rRef.IsColRel() )
    2169             :                 {   // ColName
    2170           0 :                     rRef.CalcAbsIfRel( aPos );
    2171           0 :                     ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
    2172           0 :                     ScRangePair* pR = pColList->Find( aAdr );
    2173           0 :                     if ( pR )
    2174             :                     {   // defined
    2175           0 :                         if ( pR->GetRange(1).aStart.Row() == nRow1 )
    2176           0 :                             bColRowNameCompile = true;
    2177             :                     }
    2178             :                     else
    2179             :                     {   // on the fly
    2180           0 :                         if ( rRef.nRow + 1 == nRow1 )
    2181           0 :                             bColRowNameCompile = true;
    2182             :                     }
    2183             :                 }
    2184           0 :                 if ( nDx > 0 && rRef.IsRowRel() )
    2185             :                 {   // RowName
    2186           0 :                     rRef.CalcAbsIfRel( aPos );
    2187           0 :                     ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
    2188           0 :                     ScRangePair* pR = pRowList->Find( aAdr );
    2189           0 :                     if ( pR )
    2190             :                     {   // defined
    2191           0 :                         if ( pR->GetRange(1).aStart.Col() == nCol1 )
    2192           0 :                             bColRowNameCompile = true;
    2193             :                     }
    2194             :                     else
    2195             :                     {   // on the fly
    2196           0 :                         if ( rRef.nCol + 1 == nCol1 )
    2197           0 :                             bColRowNameCompile = true;
    2198             :                     }
    2199             :                 }
    2200             :             }
    2201             :         }
    2202          32 :         else if ( eUpdateRefMode == URM_MOVE )
    2203             :         {   // Recomplie for Move/D&D when ColRowName was moved or this Cell
    2204             :             // points to one and was moved.
    2205           1 :             bColRowNameCompile = bCompile;      // Possibly from Copy ctor
    2206           1 :             if ( !bColRowNameCompile )
    2207             :             {
    2208           1 :                 bool bMoved = (aPos != aOldPos);
    2209           1 :                 pCode->Reset();
    2210           1 :                 ScToken* t = static_cast<ScToken*>(pCode->GetNextColRowName());
    2211           1 :                 if ( t && bMoved )
    2212           0 :                     bColRowNameCompile = true;
    2213           2 :                 while ( t && !bColRowNameCompile )
    2214             :                 {
    2215           0 :                     ScSingleRefData& rRef = t->GetSingleRef();
    2216           0 :                     rRef.CalcAbsIfRel( aPos );
    2217           0 :                     if ( rRef.Valid() )
    2218             :                     {
    2219           0 :                         ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
    2220           0 :                         if ( rRange.In( aAdr ) )
    2221           0 :                             bColRowNameCompile = true;
    2222             :                     }
    2223           0 :                     t = static_cast<ScToken*>(pCode->GetNextColRowName());
    2224             :                 }
    2225             :             }
    2226             :         }
    2227          31 :         else if ( eUpdateRefMode == URM_COPY && bHasColRowNames && bValChanged )
    2228             :         {
    2229           0 :             bColRowNameCompile = true;
    2230             :         }
    2231             : 
    2232          43 :         ScChangeTrack* pChangeTrack = pDocument->GetChangeTrack();
    2233          43 :         bInDeleteUndo = (pChangeTrack && pChangeTrack->IsInDeleteUndo());
    2234             : 
    2235             :         // RelNameRefs are always moved
    2236          43 :         bHasRelName = HasRelNameReference();
    2237             :         // Reference changed and new listening needed?
    2238             :         // Except in Insert/Delete without specialties.
    2239          43 :         bNewListening = (bRangeModified || pSharedCode || bColRowNameCompile
    2240          43 :                 || (bValChanged && (eUpdateRefMode != URM_INSDEL ||
    2241          11 :                         bInDeleteUndo || bRefSizeChanged)) ||
    2242           0 :                 (bHasRelName && eUpdateRefMode != URM_COPY))
    2243             :             // #i36299# Don't duplicate action during cut&paste / drag&drop
    2244             :             // on a cell in the range moved, start/end listeners is done
    2245             :             // via ScDocument::DeleteArea() and ScDocument::CopyFromClip().
    2246          43 :             && !(eUpdateRefMode == URM_MOVE &&
    2247          43 :                     pDocument->IsInsertingFromOtherDoc() && rRange.In(aPos));
    2248             : 
    2249          43 :         if ( bNewListening )
    2250           0 :             EndListeningTo(pDocument, pOldCode.get(), aOldPos);
    2251             :     }
    2252             : 
    2253          46 :     bool bNeedDirty = false;
    2254             :     // NeedDirty for changes except for Copy and Move/Insert without RelNames
    2255          46 :     if ( bRangeModified || pSharedCode || bColRowNameCompile ||
    2256          11 :             (bValChanged && eUpdateRefMode != URM_COPY &&
    2257          11 :              (eUpdateRefMode != URM_MOVE || bHasRelName) &&
    2258          18 :              (!bIsInsert || bHasRelName || bInDeleteUndo ||
    2259          42 :               bRefSizeChanged)) || bOnRefMove)
    2260           8 :         bNeedDirty = true;
    2261             : 
    2262          46 :     if (pUndoDoc && (bValChanged || pSharedCode || bOnRefMove))
    2263             :     {
    2264             :         // Copy the cell to aUndoPos, which is its current position in the document,
    2265             :         // so this works when UpdateReference is called before moving the cells
    2266             :         // (InsertCells/DeleteCells - aPos is changed above) as well as when UpdateReference
    2267             :         // is called after moving the cells (MoveBlock/PasteFromClip - aOldPos is changed).
    2268             : 
    2269             :         // If there is already a formula cell in the undo document, don't overwrite it,
    2270             :         // the first (oldest) is the important cell.
    2271           0 :         if ( pUndoDoc->GetCellType( aUndoPos ) != CELLTYPE_FORMULA )
    2272             :         {
    2273             :             ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aUndoPos,
    2274           0 :                     pOldCode.get(), eTempGrammar, cMatrixFlag );
    2275           0 :             pFCell->aResult.SetToken( NULL);  // to recognize it as changed later (Cut/Paste!)
    2276           0 :             pUndoDoc->SetFormulaCell(aUndoPos, pFCell);
    2277             :         }
    2278             :     }
    2279             : 
    2280          46 :     bValChanged = false;
    2281             : 
    2282          46 :     if ( pSharedCode )
    2283             :     {   // Replace shared formula with own formula
    2284           0 :         pDocument->RemoveFromFormulaTree( this );   // update formula count
    2285           0 :         delete pCode;
    2286           0 :         pCode = pSharedCode->GetCode()->Clone();
    2287             :         // #i18937# #i110008# call MoveRelWrap, but with the old position
    2288           0 :         ScCompiler::MoveRelWrap(*pCode, pDocument, aOldPos, pSharedCode->GetMaxCol(), pSharedCode->GetMaxRow());
    2289           0 :         ScCompiler aComp2(pDocument, aPos, *pCode);
    2290           0 :         aComp2.SetGrammar(pDocument->GetGrammar());
    2291             :         aComp2.UpdateSharedFormulaReference( eUpdateRefMode, aOldPos, rRange,
    2292           0 :             nDx, nDy, nDz );
    2293           0 :         bValChanged = true;
    2294           0 :         bNeedDirty = true;
    2295             :     }
    2296             : 
    2297          46 :     if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 )
    2298             :     {
    2299           0 :         CompileTokenArray( bNewListening ); // no Listening
    2300           0 :         bNeedDirty = true;
    2301             :     }
    2302             : 
    2303          46 :     if ( !bInDeleteUndo )
    2304             :     {   // In ChangeTrack Delete-Reject listeners are established in
    2305             :         // InsertCol/InsertRow
    2306          46 :         if ( bNewListening )
    2307             :         {
    2308           0 :             if ( eUpdateRefMode == URM_INSDEL )
    2309             :             {
    2310             :                 // Inserts/Deletes re-establish listeners after all
    2311             :                 // UpdateReference calls.
    2312             :                 // All replaced shared formula listeners have to be
    2313             :                 // established after an Insert or Delete. Do nothing here.
    2314           0 :                 SetNeedsListening( true);
    2315             :             }
    2316             :             else
    2317           0 :                 StartListeningTo( pDocument );
    2318             :         }
    2319             :     }
    2320             : 
    2321          46 :     if ( bNeedDirty && (!(eUpdateRefMode == URM_INSDEL && bHasRelName) || pSharedCode) )
    2322             :     {   // Cut off references, invalid or similar?
    2323           8 :         sc::AutoCalcSwitch(*pDocument, false);
    2324           8 :         SetDirty();
    2325             :     }
    2326             : 
    2327          46 :     return bCellStateChanged;
    2328             : }
    2329             : 
    2330           6 : void ScFormulaCell::UpdateInsertTab(SCTAB nTable, SCTAB nNewSheets)
    2331             : {
    2332           6 :     bool bPosChanged = ( aPos.Tab() >= nTable ? true : false );
    2333           6 :     pCode->Reset();
    2334           6 :     if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
    2335             :     {
    2336           6 :         EndListeningTo( pDocument );
    2337             :         // IncTab _after_ EndListeningTo and _before_ Compiler UpdateInsertTab!
    2338           6 :         if ( bPosChanged )
    2339           6 :             aPos.IncTab(nNewSheets);
    2340             :         ScRangeData* pRangeData;
    2341           6 :         ScCompiler aComp(pDocument, aPos, *pCode);
    2342           6 :         aComp.SetGrammar(pDocument->GetGrammar());
    2343           6 :         pRangeData = aComp.UpdateInsertTab( nTable, false, nNewSheets );
    2344           6 :         if (pRangeData) // Exchange Shared Formula with real Formula
    2345             :         {
    2346             :             bool bRefChanged;
    2347           0 :             pDocument->RemoveFromFormulaTree( this );   // update formula count
    2348           0 :             delete pCode;
    2349           0 :             pCode = new ScTokenArray( *pRangeData->GetCode() );
    2350           0 :             ScCompiler aComp2(pDocument, aPos, *pCode);
    2351           0 :             aComp2.SetGrammar(pDocument->GetGrammar());
    2352           0 :             aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
    2353           0 :             aComp2.UpdateInsertTab( nTable, false, nNewSheets );
    2354             :             // If the shared formula contained a named range/formula containing
    2355             :             // an absolute reference to a sheet, those have to be readjusted.
    2356           0 :             aComp2.UpdateDeleteTab( nTable, false, true, bRefChanged, nNewSheets );
    2357           0 :             bCompile = true;
    2358           6 :         }
    2359             :         // no StartListeningTo because pTab[nTab] does not exsist!
    2360             :     }
    2361           0 :     else if ( bPosChanged )
    2362           0 :         aPos.IncTab();
    2363           6 : }
    2364             : 
    2365          60 : bool ScFormulaCell::UpdateDeleteTab(SCTAB nTable, bool bIsMove, SCTAB nSheets)
    2366             : {
    2367          60 :     bool bRefChanged = false;
    2368          60 :     bool bPosChanged = ( aPos.Tab() >= nTable + nSheets ? true : false );
    2369          60 :     pCode->Reset();
    2370          60 :     if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
    2371             :     {
    2372          59 :         EndListeningTo( pDocument );
    2373             :         // IncTab _after_ EndListeningTo und _before_ Compiler UpdateDeleteTab!
    2374          59 :         if ( bPosChanged )
    2375          17 :             aPos.IncTab(-1*nSheets);
    2376             :         ScRangeData* pRangeData;
    2377          59 :         ScCompiler aComp(pDocument, aPos, *pCode);
    2378          59 :         aComp.SetGrammar(pDocument->GetGrammar());
    2379          59 :         pRangeData = aComp.UpdateDeleteTab(nTable, bIsMove, false, bRefChanged, nSheets);
    2380          59 :         if (pRangeData) // Exchange Shared Formula with real Formula
    2381             :         {
    2382           0 :             pDocument->RemoveFromFormulaTree( this );   // update formula count
    2383           0 :             delete pCode;
    2384           0 :             pCode = pRangeData->GetCode()->Clone();
    2385           0 :             ScCompiler aComp2(pDocument, aPos, *pCode);
    2386           0 :             aComp2.SetGrammar(pDocument->GetGrammar());
    2387           0 :             aComp2.CompileTokenArray();
    2388           0 :             aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
    2389           0 :             aComp2.UpdateDeleteTab( nTable, false, false, bRefChanged, nSheets );
    2390             :             // If the shared formula contained a named range/formula containing
    2391             :             // an absolute reference to a sheet, those have to be readjusted.
    2392           0 :             aComp2.UpdateInsertTab( nTable,true, nSheets );
    2393             :             // bRefChanged could have been reset at the last UpdateDeleteTab
    2394           0 :             bRefChanged = true;
    2395           0 :             bCompile = true;
    2396          59 :         }
    2397             :         // no StartListeningTo because pTab[nTab] not yet correct!
    2398             :     }
    2399           1 :     else if ( bPosChanged )
    2400           0 :         aPos.IncTab(-1*nSheets);
    2401             : 
    2402          60 :     return bRefChanged;
    2403             : }
    2404             : 
    2405           0 : void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
    2406             : {
    2407           0 :     pCode->Reset();
    2408           0 :     if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
    2409             :     {
    2410           0 :         EndListeningTo( pDocument );
    2411             :         // SetTab _after_ EndListeningTo und _before_ Compiler UpdateMoveTab !
    2412           0 :         aPos.SetTab( nTabNo );
    2413             :         ScRangeData* pRangeData;
    2414           0 :         ScCompiler aComp(pDocument, aPos, *pCode);
    2415           0 :         aComp.SetGrammar(pDocument->GetGrammar());
    2416           0 :         pRangeData = aComp.UpdateMoveTab( nOldPos, nNewPos, false );
    2417           0 :         if (pRangeData) // Exchange Shared Formula with real Formula
    2418             :         {
    2419           0 :             pDocument->RemoveFromFormulaTree( this );   // update formula count
    2420           0 :             delete pCode;
    2421           0 :             pCode = pRangeData->GetCode()->Clone();
    2422           0 :             ScCompiler aComp2(pDocument, aPos, *pCode);
    2423           0 :             aComp2.SetGrammar(pDocument->GetGrammar());
    2424           0 :             aComp2.CompileTokenArray();
    2425           0 :             aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
    2426           0 :             aComp2.UpdateMoveTab( nOldPos, nNewPos, true );
    2427           0 :             bCompile = true;
    2428           0 :         }
    2429             :         // no StartListeningTo because pTab[nTab] not yet correct!
    2430             :     }
    2431             :     else
    2432           0 :         aPos.SetTab( nTabNo );
    2433           0 : }
    2434             : 
    2435           0 : void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable)
    2436             : {
    2437           0 :     if( !pDocument->IsClipOrUndo() )
    2438             :     {
    2439           0 :         pCode->Reset();
    2440           0 :         ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
    2441           0 :         while( p )
    2442             :         {
    2443           0 :             ScSingleRefData& rRef1 = p->GetSingleRef();
    2444           0 :             if( !rRef1.IsTabRel() && (SCsTAB) nTable <= rRef1.nTab )
    2445           0 :                 rRef1.nTab++;
    2446           0 :             if( p->GetType() == formula::svDoubleRef )
    2447             :             {
    2448           0 :                 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
    2449           0 :                 if( !rRef2.IsTabRel() && (SCsTAB) nTable <= rRef2.nTab )
    2450           0 :                     rRef2.nTab++;
    2451             :             }
    2452           0 :             p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
    2453             :         }
    2454             :     }
    2455           0 : }
    2456             : 
    2457           2 : bool ScFormulaCell::TestTabRefAbs(SCTAB nTable)
    2458             : {
    2459           2 :     bool bRet = false;
    2460           2 :     if( !pDocument->IsClipOrUndo() )
    2461             :     {
    2462           2 :         pCode->Reset();
    2463           2 :         ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
    2464           7 :         while( p )
    2465             :         {
    2466           3 :             ScSingleRefData& rRef1 = p->GetSingleRef();
    2467           3 :             if( !rRef1.IsTabRel() )
    2468             :             {
    2469           1 :                 if( (SCsTAB) nTable != rRef1.nTab )
    2470           1 :                     bRet = true;
    2471           0 :                 else if (nTable != aPos.Tab())
    2472           0 :                     rRef1.nTab = aPos.Tab();
    2473             :             }
    2474           3 :             if( p->GetType() == formula::svDoubleRef )
    2475             :             {
    2476           0 :                 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
    2477           0 :                 if( !rRef2.IsTabRel() )
    2478             :                 {
    2479           0 :                     if( (SCsTAB) nTable != rRef2.nTab )
    2480           0 :                         bRet = true;
    2481           0 :                     else if (nTable != aPos.Tab())
    2482           0 :                         rRef2.nTab = aPos.Tab();
    2483             :                 }
    2484             :             }
    2485           3 :             p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
    2486             :         }
    2487             :     }
    2488           2 :     return bRet;
    2489             : }
    2490             : 
    2491          58 : void ScFormulaCell::UpdateCompile( bool bForceIfNameInUse )
    2492             : {
    2493          58 :     if ( bForceIfNameInUse && !bCompile )
    2494           0 :         bCompile = pCode->HasNameOrColRowName();
    2495          58 :     if ( bCompile )
    2496           0 :         pCode->SetCodeError( 0 );   // make sure it will really be compiled
    2497          58 :     CompileTokenArray();
    2498          58 : }
    2499             : 
    2500             : // Reference transposition is only called in Clipboard Document
    2501           0 : void ScFormulaCell::TransposeReference()
    2502             : {
    2503           0 :     bool bFound = false;
    2504           0 :     pCode->Reset();
    2505             :     ScToken* t;
    2506           0 :     while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
    2507             :     {
    2508           0 :         ScSingleRefData& rRef1 = t->GetSingleRef();
    2509           0 :         if ( rRef1.IsColRel() && rRef1.IsRowRel() )
    2510             :         {
    2511           0 :             bool bDouble = (t->GetType() == formula::svDoubleRef);
    2512           0 :             ScSingleRefData& rRef2 = (bDouble ? t->GetDoubleRef().Ref2 : rRef1);
    2513           0 :             if ( !bDouble || (rRef2.IsColRel() && rRef2.IsRowRel()) )
    2514             :             {
    2515             :                 sal_Int16 nTemp;
    2516             : 
    2517           0 :                 nTemp = rRef1.nRelCol;
    2518           0 :                 rRef1.nRelCol = static_cast<SCCOL>(rRef1.nRelRow);
    2519           0 :                 rRef1.nRelRow = static_cast<SCROW>(nTemp);
    2520             : 
    2521           0 :                 if ( bDouble )
    2522             :                 {
    2523           0 :                     nTemp = rRef2.nRelCol;
    2524           0 :                     rRef2.nRelCol = static_cast<SCCOL>(rRef2.nRelRow);
    2525           0 :                     rRef2.nRelRow = static_cast<SCROW>(nTemp);
    2526             :                 }
    2527             : 
    2528           0 :                 bFound = true;
    2529             :             }
    2530             :         }
    2531             :     }
    2532             : 
    2533           0 :     if (bFound)
    2534           0 :         bCompile = true;
    2535           0 : }
    2536             : 
    2537           0 : void ScFormulaCell::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
    2538             :                                         ScDocument* pUndoDoc )
    2539             : {
    2540           0 :     EndListeningTo( pDocument );
    2541             : 
    2542           0 :     ScAddress aOldPos = aPos;
    2543           0 :     bool bPosChanged = false; // Whether this cell has been moved
    2544             : 
    2545             :     ScRange aDestRange( rDest, ScAddress(
    2546           0 :                 static_cast<SCCOL>(rDest.Col() + rSource.aEnd.Row() - rSource.aStart.Row()),
    2547           0 :                 static_cast<SCROW>(rDest.Row() + rSource.aEnd.Col() - rSource.aStart.Col()),
    2548           0 :                 rDest.Tab() + rSource.aEnd.Tab() - rSource.aStart.Tab() ) );
    2549           0 :     if ( aDestRange.In( aOldPos ) )
    2550             :     {
    2551             :         // Count back Positions
    2552           0 :         SCsCOL nRelPosX = aOldPos.Col();
    2553           0 :         SCsROW nRelPosY = aOldPos.Row();
    2554           0 :         SCsTAB nRelPosZ = aOldPos.Tab();
    2555           0 :         ScRefUpdate::DoTranspose( nRelPosX, nRelPosY, nRelPosZ, pDocument, aDestRange, rSource.aStart );
    2556           0 :         aOldPos.Set( nRelPosX, nRelPosY, nRelPosZ );
    2557           0 :         bPosChanged = true;
    2558             :     }
    2559             : 
    2560           0 :     ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL;
    2561           0 :     bool bRefChanged = false;
    2562             :     ScToken* t;
    2563             : 
    2564           0 :     ScRangeData* pShared = NULL;
    2565           0 :     pCode->Reset();
    2566           0 :     while( (t = static_cast<ScToken*>(pCode->GetNextReferenceOrName())) != NULL )
    2567             :     {
    2568           0 :         if( t->GetOpCode() == ocName )
    2569             :         {
    2570           0 :             ScRangeData* pName = pDocument->GetRangeName()->findByIndex( t->GetIndex() );
    2571           0 :             if (pName)
    2572             :             {
    2573           0 :                 if (pName->IsModified())
    2574           0 :                     bRefChanged = true;
    2575           0 :                 if (pName->HasType(RT_SHAREDMOD))
    2576           0 :                     pShared = pName;
    2577             :             }
    2578             :         }
    2579           0 :         else if( t->GetType() != svIndex )
    2580             :         {
    2581           0 :             t->CalcAbsIfRel( aOldPos );
    2582             :             bool bMod;
    2583             :             {   // Own scope for SingleDoubleRefModifier dtor if SingleRef
    2584           0 :                 SingleDoubleRefModifier aMod( *t );
    2585           0 :                 ScComplexRefData& rRef = aMod.Ref();
    2586             :                 bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource,
    2587           0 :                     rDest, rRef ) != UR_NOTHING || bPosChanged);
    2588             :             }
    2589           0 :             if ( bMod )
    2590             :             {
    2591           0 :                 t->CalcRelFromAbs( aPos );
    2592           0 :                 bRefChanged = true;
    2593             :             }
    2594             :         }
    2595             :     }
    2596             : 
    2597           0 :     if (pShared) // Exchange Shared Formula with real Formula
    2598             :     {
    2599           0 :         pDocument->RemoveFromFormulaTree( this ); // update formula count
    2600           0 :         delete pCode;
    2601           0 :         pCode = new ScTokenArray( *pShared->GetCode() );
    2602           0 :         bRefChanged = true;
    2603           0 :         pCode->Reset();
    2604           0 :         while( (t = static_cast<ScToken*>(pCode->GetNextReference())) != NULL )
    2605             :         {
    2606           0 :             if( t->GetType() != svIndex )
    2607             :             {
    2608           0 :                 t->CalcAbsIfRel( aOldPos );
    2609             :                 bool bMod;
    2610             :                 {   // Own scope for SingleDoubleRefModifier dtor if SingleRef
    2611           0 :                     SingleDoubleRefModifier aMod( *t );
    2612           0 :                     ScComplexRefData& rRef = aMod.Ref();
    2613             :                     bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource,
    2614           0 :                         rDest, rRef ) != UR_NOTHING || bPosChanged);
    2615             :                 }
    2616           0 :                 if ( bMod )
    2617           0 :                     t->CalcRelFromAbs( aPos );
    2618             :             }
    2619             :         }
    2620             :     }
    2621             : 
    2622           0 :     if (bRefChanged)
    2623             :     {
    2624           0 :         if (pUndoDoc)
    2625             :         {
    2626             :             ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aPos, pOld,
    2627           0 :                     eTempGrammar, cMatrixFlag);
    2628           0 :             pFCell->aResult.SetToken( NULL);  // to recognize it as changed later (Cut/Paste!)
    2629           0 :             pUndoDoc->SetFormulaCell(aPos, pFCell);
    2630             :         }
    2631             : 
    2632           0 :         bCompile = true;
    2633           0 :         CompileTokenArray(); // also call StartListeningTo
    2634           0 :         SetDirty();
    2635             :     }
    2636             :     else
    2637           0 :         StartListeningTo( pDocument ); // Listener as previous
    2638             : 
    2639           0 :     delete pOld;
    2640           0 : }
    2641             : 
    2642           0 : void ScFormulaCell::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
    2643             : {
    2644           0 :     EndListeningTo( pDocument );
    2645             : 
    2646           0 :     bool bRefChanged = false;
    2647             :     ScToken* t;
    2648           0 :     ScRangeData* pShared = NULL;
    2649             : 
    2650           0 :     pCode->Reset();
    2651           0 :     while( (t = static_cast<ScToken*>(pCode->GetNextReferenceOrName())) != NULL )
    2652             :     {
    2653           0 :         if( t->GetOpCode() == ocName )
    2654             :         {
    2655           0 :             ScRangeData* pName = pDocument->GetRangeName()->findByIndex( t->GetIndex() );
    2656           0 :             if (pName)
    2657             :             {
    2658           0 :                 if (pName->IsModified())
    2659           0 :                     bRefChanged = true;
    2660           0 :                 if (pName->HasType(RT_SHAREDMOD))
    2661           0 :                     pShared = pName;
    2662             :             }
    2663             :         }
    2664           0 :         else if( t->GetType() != svIndex )
    2665             :         {
    2666           0 :             t->CalcAbsIfRel( aPos );
    2667             :             bool bMod;
    2668             :             {   // Own scope for SingleDoubleRefModifier dtor if SingleRef
    2669           0 :                 SingleDoubleRefModifier aMod( *t );
    2670           0 :                 ScComplexRefData& rRef = aMod.Ref();
    2671             :                 bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY,
    2672           0 :                     rRef ) != UR_NOTHING);
    2673             :             }
    2674           0 :             if ( bMod )
    2675             :             {
    2676           0 :                 t->CalcRelFromAbs( aPos );
    2677           0 :                 bRefChanged = true;
    2678             :             }
    2679             :         }
    2680             :     }
    2681             : 
    2682           0 :     if (pShared) // Exchange Shared Formula with real Formula
    2683             :     {
    2684           0 :         pDocument->RemoveFromFormulaTree( this ); // Update formula count
    2685           0 :         delete pCode;
    2686           0 :         pCode = new ScTokenArray( *pShared->GetCode() );
    2687           0 :         bRefChanged = true;
    2688           0 :         pCode->Reset();
    2689           0 :         while( (t = static_cast<ScToken*>(pCode->GetNextReference())) != NULL )
    2690             :         {
    2691           0 :             if( t->GetType() != svIndex )
    2692             :             {
    2693           0 :                 t->CalcAbsIfRel( aPos );
    2694             :                 bool bMod;
    2695             :                 {   // Own scope for SingleDoubleRefModifier dtor if SingleRef
    2696           0 :                     SingleDoubleRefModifier aMod( *t );
    2697           0 :                     ScComplexRefData& rRef = aMod.Ref();
    2698             :                     bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY,
    2699           0 :                         rRef ) != UR_NOTHING);
    2700             :                 }
    2701           0 :                 if ( bMod )
    2702           0 :                     t->CalcRelFromAbs( aPos );
    2703             :             }
    2704             :         }
    2705             :     }
    2706             : 
    2707           0 :     if (bRefChanged)
    2708             :     {
    2709           0 :         bCompile = true;
    2710           0 :         CompileTokenArray(); // Also call StartListeningTo
    2711           0 :         SetDirty();
    2712             :     }
    2713             :     else
    2714           0 :         StartListeningTo( pDocument ); // Listener as previous
    2715           0 : }
    2716             : 
    2717           3 : static void lcl_FindRangeNamesInUse(std::set<sal_uInt16>& rIndexes, ScTokenArray* pCode, ScRangeName* pNames)
    2718             : {
    2719          13 :     for (FormulaToken* p = pCode->First(); p; p = pCode->Next())
    2720             :     {
    2721          10 :         if (p->GetOpCode() == ocName)
    2722             :         {
    2723           2 :             sal_uInt16 nTokenIndex = p->GetIndex();
    2724           2 :             rIndexes.insert( nTokenIndex );
    2725             : 
    2726           2 :             ScRangeData* pSubName = pNames->findByIndex(p->GetIndex());
    2727           2 :             if (pSubName)
    2728           2 :                 lcl_FindRangeNamesInUse(rIndexes, pSubName->GetCode(), pNames);
    2729             :         }
    2730             :     }
    2731           3 : }
    2732             : 
    2733           1 : void ScFormulaCell::FindRangeNamesInUse(std::set<sal_uInt16>& rIndexes) const
    2734             : {
    2735           1 :     lcl_FindRangeNamesInUse( rIndexes, pCode, pDocument->GetRangeName() );
    2736           1 : }
    2737             : 
    2738        4050 : bool ScFormulaCell::IsChanged() const
    2739             : {
    2740        4050 :     return bChanged;
    2741             : }
    2742             : 
    2743         291 : void ScFormulaCell::SetChanged(bool b)
    2744             : {
    2745         291 :     bChanged = b;
    2746         291 : }
    2747             : 
    2748           3 : void ScFormulaCell::CompileDBFormula()
    2749             : {
    2750          24 :     for( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
    2751             :     {
    2752          42 :         if ( p->GetOpCode() == ocDBArea
    2753          21 :             || (p->GetOpCode() == ocName && p->GetIndex() >= SC_START_INDEX_DB_COLL) )
    2754             :         {
    2755           0 :             bCompile = true;
    2756           0 :             CompileTokenArray();
    2757           0 :             SetDirty();
    2758           0 :             break;
    2759             :         }
    2760             :     }
    2761           3 : }
    2762             : 
    2763          14 : void ScFormulaCell::CompileDBFormula( bool bCreateFormulaString )
    2764             : {
    2765             :     // Two phases must be called after each other
    2766             :     // 1. Formula String with old generated names
    2767             :     // 2. Formula String with new generated names
    2768          14 :     if ( bCreateFormulaString )
    2769             :     {
    2770           7 :         bool bRecompile = false;
    2771           7 :         pCode->Reset();
    2772          35 :         for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() )
    2773             :         {
    2774          28 :             switch ( p->GetOpCode() )
    2775             :             {
    2776             :                 case ocBad:             // DB Area eventually goes bad
    2777             :                 case ocColRowName:      // in case of the same names
    2778             :                 case ocDBArea:          // DB Area
    2779           0 :                     bRecompile = true;
    2780           0 :                 break;
    2781             :                 case ocName:
    2782           0 :                     if ( p->GetIndex() >= SC_START_INDEX_DB_COLL )
    2783           0 :                         bRecompile = true;  // DB Area
    2784           0 :                 break;
    2785             :                 default:
    2786             :                     ; // nothing
    2787             :             }
    2788             :         }
    2789           7 :         if ( bRecompile )
    2790             :         {
    2791           0 :             OUString aFormula;
    2792           0 :             GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
    2793           0 :             if ( GetMatrixFlag() != MM_NONE && !aFormula.isEmpty() )
    2794             :             {
    2795           0 :                 if ( aFormula[ aFormula.getLength()-1 ] == '}' )
    2796           0 :                     aFormula = aFormula.copy( 0, aFormula.getLength()-1 );
    2797           0 :                 if ( aFormula[0] == '{' )
    2798           0 :                     aFormula = aFormula.copy( 1 );
    2799             :             }
    2800           0 :             EndListeningTo( pDocument );
    2801           0 :             pDocument->RemoveFromFormulaTree( this );
    2802           0 :             pCode->Clear();
    2803           0 :             SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
    2804             :         }
    2805             :     }
    2806           7 :     else if ( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() )
    2807             :     {
    2808           0 :         Compile( aResult.GetHybridFormula(), false, eTempGrammar );
    2809           0 :         aResult.SetToken( NULL);
    2810           0 :         SetDirty();
    2811             :     }
    2812          14 : }
    2813             : 
    2814          42 : void ScFormulaCell::CompileNameFormula( bool bCreateFormulaString )
    2815             : {
    2816             :     // Two phases must be called after each other
    2817             :     // 1. Formula String with old generated names
    2818             :     // 2. Formula String with new generated names
    2819          42 :     if ( bCreateFormulaString )
    2820             :     {
    2821           0 :         bool bRecompile = false;
    2822           0 :         pCode->Reset();
    2823           0 :         for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() )
    2824             :         {
    2825           0 :             switch ( p->GetOpCode() )
    2826             :             {
    2827             :                 case ocBad:             // in case RangeName goes bad
    2828             :                 case ocColRowName:      // in case the names are the same
    2829           0 :                     bRecompile = true;
    2830           0 :                 break;
    2831             :                 default:
    2832           0 :                     if ( p->GetType() == svIndex )
    2833           0 :                         bRecompile = true;  // RangeName
    2834             :             }
    2835             :         }
    2836           0 :         if ( bRecompile )
    2837             :         {
    2838           0 :             OUString aFormula;
    2839           0 :             GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
    2840           0 :             if ( GetMatrixFlag() != MM_NONE && !aFormula.isEmpty() )
    2841             :             {
    2842           0 :                 if ( aFormula[ aFormula.getLength()-1 ] == '}' )
    2843           0 :                     aFormula = aFormula.copy( 0, aFormula.getLength()-1 );
    2844           0 :                 if ( aFormula[0] == '{' )
    2845           0 :                     aFormula = aFormula.copy( 1 );
    2846             :             }
    2847           0 :             EndListeningTo( pDocument );
    2848           0 :             pDocument->RemoveFromFormulaTree( this );
    2849           0 :             pCode->Clear();
    2850           0 :             SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
    2851             :         }
    2852             :     }
    2853          42 :     else if ( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() )
    2854             :     {
    2855           0 :         Compile( aResult.GetHybridFormula(), false, eTempGrammar );
    2856           0 :         aResult.SetToken( NULL);
    2857           0 :         SetDirty();
    2858             :     }
    2859          42 : }
    2860             : 
    2861           0 : void ScFormulaCell::CompileColRowNameFormula()
    2862             : {
    2863           0 :     pCode->Reset();
    2864           0 :     for ( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
    2865             :     {
    2866           0 :         if ( p->GetOpCode() == ocColRowName )
    2867             :         {
    2868           0 :             bCompile = true;
    2869           0 :             CompileTokenArray();
    2870           0 :             SetDirty();
    2871           0 :             break;
    2872             :         }
    2873             :     }
    2874           0 : }
    2875             : 
    2876        2469 : ScFormulaCell::CompareState ScFormulaCell::CompareByTokenArray( ScFormulaCell& rOther ) const
    2877             : {
    2878             :     // no Matrix formulae yet.
    2879        2469 :     if ( GetMatrixFlag() != MM_NONE )
    2880          93 :         return NotEqual;
    2881             : 
    2882             :     // are these formule at all similar ?
    2883        2376 :     if ( GetHash() != rOther.GetHash() )
    2884         670 :         return NotEqual;
    2885             : 
    2886        1706 :     FormulaToken **pThis = pCode->GetCode();
    2887        1706 :     sal_uInt16     nThisLen = pCode->GetCodeLen();
    2888        1706 :     FormulaToken **pOther = rOther.pCode->GetCode();
    2889        1706 :     sal_uInt16     nOtherLen = rOther.pCode->GetCodeLen();
    2890             : 
    2891        1706 :     if ( !pThis || !pOther )
    2892             :     {
    2893             :         // Error: no compiled code for cells !"
    2894         241 :         return NotEqual;
    2895             :     }
    2896             : 
    2897        1465 :     if ( nThisLen != nOtherLen )
    2898           0 :         return NotEqual;
    2899             : 
    2900        1465 :     bool bInvariant = true;
    2901             : 
    2902             :     // check we are basically the same function
    2903       11992 :     for ( sal_uInt16 i = 0; i < nThisLen; i++ )
    2904             :     {
    2905       10662 :         ScToken *pThisTok = static_cast<ScToken*>( pThis[i] );
    2906       10662 :         ScToken *pOtherTok = static_cast<ScToken*>( pOther[i] );
    2907             : 
    2908       31985 :         if ( pThisTok->GetType() != pOtherTok->GetType() ||
    2909       21323 :              pThisTok->GetOpCode() != pOtherTok->GetOpCode() ||
    2910       10661 :              pThisTok->GetParamCount() != pOtherTok->GetParamCount() )
    2911             :         {
    2912             :             // Incompatible type, op-code or param counts.
    2913           1 :             return NotEqual;
    2914             :         }
    2915             : 
    2916       10661 :         switch (pThisTok->GetType())
    2917             :         {
    2918             :             case formula::svMatrix:
    2919             :             case formula::svExternalSingleRef:
    2920             :             case formula::svExternalDoubleRef:
    2921             :                 // Ignoring matrix and external references for now.
    2922          18 :                 return NotEqual;
    2923             : 
    2924             :             case formula::svSingleRef:
    2925             :             {
    2926             :                 // Single cell reference.
    2927        2360 :                 const ScSingleRefData& rRef = pThisTok->GetSingleRef();
    2928        2360 :                 if (rRef != pOtherTok->GetSingleRef())
    2929          52 :                     return NotEqual;
    2930             : 
    2931        2308 :                 if (rRef.IsRowRel())
    2932        2248 :                     bInvariant = false;
    2933             :             }
    2934        2308 :             break;
    2935             :             case formula::svDoubleRef:
    2936             :             {
    2937             :                 // Range reference.
    2938        1194 :                 const ScSingleRefData& rRef1 = pThisTok->GetSingleRef();
    2939        1194 :                 const ScSingleRefData& rRef2 = pThisTok->GetSingleRef2();
    2940        1194 :                 if (rRef1 != pOtherTok->GetSingleRef())
    2941          64 :                     return NotEqual;
    2942             : 
    2943        1130 :                 if (rRef2 != pOtherTok->GetSingleRef2())
    2944           0 :                     return NotEqual;
    2945             : 
    2946        1130 :                 if (rRef1.IsRowRel())
    2947        1130 :                     bInvariant = false;
    2948             : 
    2949        1130 :                 if (rRef2.IsRowRel())
    2950        1130 :                     bInvariant = false;
    2951             :             }
    2952        1130 :             break;
    2953             :             default:
    2954             :                 ;
    2955             :         }
    2956             :     }
    2957             : 
    2958        1330 :     return bInvariant ? EqualInvariant : EqualRelativeRef;
    2959             : }
    2960             : 
    2961             : namespace {
    2962             : 
    2963             : class GroupTokenConverter
    2964             : {
    2965             :     sc::FormulaGroupContext& mrCxt;
    2966             :     ScTokenArray& mrGroupTokens;
    2967             :     ScDocument& mrDoc;
    2968             :     ScFormulaCell& mrCell;
    2969             :     const ScAddress& mrPos;
    2970             : public:
    2971           0 :     GroupTokenConverter(sc::FormulaGroupContext& rCxt, ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) :
    2972           0 :         mrCxt(rCxt), mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos) {}
    2973             : 
    2974           0 :     bool convert(ScTokenArray& rCode)
    2975             :     {
    2976           0 :         rCode.Reset();
    2977           0 :         for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
    2978             :         {
    2979             :             // A reference can be either absolute or relative.  If it's absolute,
    2980             :             // convert it to a static value token.  If relative, convert it to a
    2981             :             // vector reference token.  Note: we only care about relative vs
    2982             :             // absolute reference state for row directions.
    2983             : 
    2984           0 :             const ScToken* pToken = static_cast<const ScToken*>(p);
    2985           0 :             switch (pToken->GetType())
    2986             :             {
    2987             :                 case svSingleRef:
    2988             :                 {
    2989           0 :                     ScSingleRefData aRef = pToken->GetSingleRef();
    2990           0 :                     ScAddress aRefPos = aRef.toAbs(mrPos);
    2991           0 :                     if (aRef.IsRowRel())
    2992             :                     {
    2993             :                         // Fetch double array guarantees that the length of the
    2994             :                         // returned array equals or greater than the requested
    2995             :                         // length.
    2996             : 
    2997             :                         // TODO: For now, it returns an array pointer only when
    2998             :                         // the entire array is in contiguous memory space.  Once
    2999             :                         // we finish cell storage rework, we'll support temporary
    3000             :                         // generation of a double array which is a combination of
    3001             :                         // multiple cell array segments.
    3002           0 :                         const double* pArray = mrDoc.FetchDoubleArray(mrCxt, aRefPos, mrCell.GetCellGroup()->mnLength);
    3003           0 :                         if (!pArray)
    3004           0 :                             return false;
    3005             : 
    3006           0 :                         formula::SingleVectorRefToken aTok(pArray, mrCell.GetCellGroup()->mnLength);
    3007           0 :                         mrGroupTokens.AddToken(aTok);
    3008             :                     }
    3009             :                     else
    3010             :                     {
    3011             :                         // Absolute row reference.
    3012           0 :                         formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefPos);
    3013           0 :                         if (!pNewToken)
    3014           0 :                             return false;
    3015             : 
    3016           0 :                         mrGroupTokens.AddToken(*pNewToken);
    3017             :                     }
    3018             :                 }
    3019           0 :                 break;
    3020             :                 case svDoubleRef:
    3021             :                 {
    3022           0 :                     ScComplexRefData aRef = pToken->GetDoubleRef();
    3023           0 :                     aRef.CalcAbsIfRel(mrCell.aPos);
    3024           0 :                     if (aRef.Ref1.IsRowRel() || aRef.Ref2.IsRowRel())
    3025             :                     {
    3026             :                         // Row reference is relative.
    3027           0 :                         bool bAbsFirst = !aRef.Ref1.IsRowRel();
    3028           0 :                         bool bAbsLast = !aRef.Ref2.IsRowRel();
    3029           0 :                         ScAddress aRefPos(aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab);
    3030           0 :                         size_t nCols = aRef.Ref2.nCol - aRef.Ref1.nCol + 1;
    3031           0 :                         std::vector<const double*> aArrays;
    3032           0 :                         aArrays.reserve(nCols);
    3033           0 :                         SCROW nArrayLength = mrCell.GetCellGroup()->mnLength;
    3034           0 :                         SCROW nRefRowSize = aRef.Ref2.nRow - aRef.Ref1.nRow + 1;
    3035           0 :                         if (!bAbsLast)
    3036             :                         {
    3037             :                             // range end position is relative. Extend the array length.
    3038           0 :                             nArrayLength += nRefRowSize - 1;
    3039             :                         }
    3040             : 
    3041           0 :                         for (SCCOL i = aRef.Ref1.nCol; i <= aRef.Ref2.nCol; ++i)
    3042             :                         {
    3043           0 :                             aRefPos.SetCol(i);
    3044           0 :                             const double* pArray = mrDoc.FetchDoubleArray(mrCxt, aRefPos, nArrayLength);
    3045           0 :                             if (!pArray)
    3046           0 :                                 return false;
    3047             : 
    3048           0 :                             aArrays.push_back(pArray);
    3049             :                         }
    3050             : 
    3051           0 :                         formula::DoubleVectorRefToken aTok(aArrays, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast);
    3052           0 :                         mrGroupTokens.AddToken(aTok);
    3053             :                     }
    3054             :                     else
    3055             :                     {
    3056             :                         // Absolute row reference.
    3057             :                         ScRange aRefRange(
    3058             :                             aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab,
    3059           0 :                             aRef.Ref2.nCol, aRef.Ref2.nRow, aRef.Ref2.nTab);
    3060             : 
    3061           0 :                         formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefRange);
    3062           0 :                         if (!pNewToken)
    3063           0 :                             return false;
    3064             : 
    3065           0 :                         mrGroupTokens.AddToken(*pNewToken);
    3066             :                     }
    3067             :                 }
    3068           0 :                 break;
    3069             :                 case svIndex:
    3070             :                 {
    3071             :                     // Named range.
    3072           0 :                     ScRangeName* pNames = mrDoc.GetRangeName();
    3073           0 :                     if (!pNames)
    3074             :                         // This should never fail.
    3075           0 :                         return false;
    3076             : 
    3077           0 :                     ScRangeData* pRange = pNames->findByIndex(p->GetIndex());
    3078           0 :                     if (!pRange)
    3079             :                         // No named range exists by that index.
    3080           0 :                         return false;
    3081             : 
    3082           0 :                     ScTokenArray* pNamedTokens = pRange->GetCode();
    3083           0 :                     if (!pNamedTokens)
    3084             :                         // This named range is empty.
    3085           0 :                         return false;
    3086             : 
    3087           0 :                     mrGroupTokens.AddOpCode(ocOpen);
    3088             : 
    3089           0 :                     if (!convert(*pNamedTokens))
    3090           0 :                         return false;
    3091             : 
    3092           0 :                     mrGroupTokens.AddOpCode(ocClose);
    3093             :                 }
    3094           0 :                 break;
    3095             :                 default:
    3096           0 :                     mrGroupTokens.AddToken(*pToken);
    3097             :             }
    3098             :         }
    3099             : 
    3100           0 :         return true;
    3101             :     }
    3102             : };
    3103             : 
    3104             : }
    3105             : 
    3106        4679 : bool ScFormulaCell::InterpretFormulaGroup()
    3107             : {
    3108        4679 :     if (!ScInterpreter::GetGlobalConfig().mbOpenCLEnabled)
    3109        4679 :         return false;
    3110             : 
    3111             :     // Re-build formulae groups if necessary - ideally this is done at
    3112             :     // import / insert / delete etc. and is integral to the data structures
    3113           0 :     pDocument->RebuildFormulaGroups();
    3114             : 
    3115           0 :     if (!xGroup || !pCode)
    3116           0 :         return false;
    3117             : 
    3118           0 :     if (xGroup->meCalcState == sc::GroupCalcDisabled)
    3119           0 :         return false;
    3120             : 
    3121           0 :     switch (pCode->GetVectorState())
    3122             :     {
    3123             :         case FormulaVectorEnabled:
    3124             :         case FormulaVectorCheckReference:
    3125             :             // Good.
    3126           0 :         break;
    3127             :         case FormulaVectorDisabled:
    3128             :         case FormulaVectorUnknown:
    3129             :         default:
    3130             :             // Not good.
    3131           0 :             return false;
    3132             :     }
    3133             : 
    3134           0 :     if (xGroup->mbInvariant)
    3135           0 :         return InterpretInvariantFormulaGroup();
    3136             : 
    3137           0 :     sc::FormulaGroupContext aCxt;
    3138           0 :     ScTokenArray aCode;
    3139           0 :     ScAddress aTopPos = aPos;
    3140           0 :     aTopPos.SetRow(xGroup->mnStart);
    3141           0 :     GroupTokenConverter aConverter(aCxt, aCode, *pDocument, *this, aTopPos);
    3142           0 :     if (!aConverter.convert(*pCode))
    3143             :     {
    3144           0 :         xGroup->meCalcState = sc::GroupCalcDisabled;
    3145           0 :         return false;
    3146             :     }
    3147             : 
    3148           0 :     xGroup->meCalcState = sc::GroupCalcRunning;
    3149           0 :     if (!sc::FormulaGroupInterpreter::getStatic()->interpret(*pDocument, aTopPos, xGroup, aCode))
    3150             :     {
    3151           0 :         xGroup->meCalcState = sc::GroupCalcDisabled;
    3152           0 :         return false;
    3153             :     }
    3154             : 
    3155           0 :     xGroup->meCalcState = sc::GroupCalcEnabled;
    3156           0 :     return true;
    3157             : }
    3158             : 
    3159           0 : bool ScFormulaCell::InterpretInvariantFormulaGroup()
    3160             : {
    3161           0 :     if (pCode->GetVectorState() == FormulaVectorCheckReference)
    3162             :     {
    3163             :         // An invariant group should only have absolute row references, and no
    3164             :         // external references are allowed.
    3165             : 
    3166           0 :         ScTokenArray aCode;
    3167           0 :         pCode->Reset();
    3168           0 :         for (const formula::FormulaToken* p = pCode->First(); p; p = pCode->Next())
    3169             :         {
    3170           0 :             const ScToken* pToken = static_cast<const ScToken*>(p);
    3171           0 :             switch (pToken->GetType())
    3172             :             {
    3173             :                 case svSingleRef:
    3174             :                 {
    3175           0 :                     ScSingleRefData aRef = pToken->GetSingleRef();
    3176           0 :                     aRef.CalcAbsIfRel(aPos); // column may be relative.
    3177           0 :                     ScAddress aRefPos(aRef.nCol, aRef.nRow, aRef.nTab);
    3178           0 :                     formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefPos);
    3179           0 :                     if (!pNewToken)
    3180           0 :                         return false;
    3181             : 
    3182           0 :                     aCode.AddToken(*pNewToken);
    3183             :                 }
    3184           0 :                 break;
    3185             :                 case svDoubleRef:
    3186             :                 {
    3187           0 :                     ScComplexRefData aRef = pToken->GetDoubleRef();
    3188           0 :                     aRef.CalcAbsIfRel(aPos); // column may be relative.
    3189             :                     ScRange aRefRange(
    3190             :                         aRef.Ref1.nCol, aRef.Ref1.nRow, aRef.Ref1.nTab,
    3191           0 :                         aRef.Ref2.nCol, aRef.Ref2.nRow, aRef.Ref2.nTab);
    3192             : 
    3193           0 :                     formula::FormulaTokenRef pNewToken = pDocument->ResolveStaticReference(aRefRange);
    3194           0 :                     if (!pNewToken)
    3195           0 :                         return false;
    3196             : 
    3197           0 :                     aCode.AddToken(*pNewToken);
    3198             :                 }
    3199           0 :                 break;
    3200             :                 default:
    3201           0 :                     aCode.AddToken(*pToken);
    3202             :             }
    3203             :         }
    3204             : 
    3205           0 :         ScCompiler aComp(pDocument, aPos, aCode);
    3206           0 :         aComp.SetGrammar(pDocument->GetGrammar());
    3207           0 :         aComp.CompileTokenArray(); // Create RPN token array.
    3208           0 :         ScInterpreter aInterpreter(this, pDocument, aPos, aCode);
    3209           0 :         aInterpreter.Interpret();
    3210           0 :         aResult.SetToken(aInterpreter.GetResultToken().get());
    3211             :     }
    3212             :     else
    3213             :     {
    3214             :         // Formula contains no references.
    3215           0 :         ScInterpreter aInterpreter(this, pDocument, aPos, *pCode);
    3216           0 :         aInterpreter.Interpret();
    3217           0 :         aResult.SetToken(aInterpreter.GetResultToken().get());
    3218             :     }
    3219             : 
    3220           0 :     for ( sal_Int32 i = 0; i < xGroup->mnLength; i++ )
    3221             :     {
    3222           0 :         ScAddress aTmpPos = aPos;
    3223           0 :         aTmpPos.SetRow(xGroup->mnStart + i);
    3224           0 :         ScFormulaCell* pCell = pDocument->GetFormulaCell(aTmpPos);
    3225             :         assert( pCell != NULL );
    3226             : 
    3227             :         // FIXME: this set of horrors is unclear to me ... certainly
    3228             :         // the above GetCell is profoundly nasty & slow ...
    3229             : 
    3230             :         // Ensure the cell truly has a result:
    3231           0 :         pCell->aResult = aResult;
    3232           0 :         pCell->ResetDirty();
    3233           0 :         pCell->SetChanged(true);
    3234             :     }
    3235             : 
    3236           0 :     return true;
    3237             : }
    3238             : 
    3239             : namespace {
    3240             : 
    3241        2292 : void startListeningArea(
    3242             :     ScFormulaCell* pCell, ScDocument& rDoc, const ScAddress& rPos, const ScToken& rToken)
    3243             : {
    3244        2292 :     const ScSingleRefData& rRef1 = rToken.GetSingleRef();
    3245        2292 :     const ScSingleRefData& rRef2 = rToken.GetSingleRef2();
    3246        2292 :     ScAddress aCell1 = rRef1.toAbs(rPos);
    3247        2292 :     ScAddress aCell2 = rRef2.toAbs(rPos);
    3248        2292 :     if (aCell1.IsValid() && aCell2.IsValid())
    3249             :     {
    3250        2292 :         if (rToken.GetOpCode() == ocColRowNameAuto)
    3251             :         {   // automagically
    3252           0 :             if ( rRef1.IsColRel() )
    3253             :             {   // ColName
    3254           0 :                 aCell2.SetRow(MAXROW);
    3255             :             }
    3256             :             else
    3257             :             {   // RowName
    3258           0 :                 aCell2.SetCol(MAXCOL);
    3259             :             }
    3260             :         }
    3261        2292 :         rDoc.StartListeningArea(ScRange(aCell1, aCell2), pCell);
    3262             :     }
    3263        2292 : }
    3264             : 
    3265             : }
    3266             : 
    3267        4256 : void ScFormulaCell::StartListeningTo( ScDocument* pDoc )
    3268             : {
    3269        4256 :     if (pDoc->IsClipOrUndo() || pDoc->GetNoListening() || IsInChangeTrack())
    3270           8 :         return;
    3271             : 
    3272        4248 :     pDoc->SetDetectiveDirty(true);  // It has changed something
    3273             : 
    3274        4248 :     ScTokenArray* pArr = GetCode();
    3275        4248 :     if( pArr->IsRecalcModeAlways() )
    3276             :     {
    3277          24 :         pDoc->StartListeningArea(BCA_LISTEN_ALWAYS, this);
    3278          24 :         SetNeedsListening( false);
    3279          24 :         return;
    3280             :     }
    3281             : 
    3282        4224 :     pArr->Reset();
    3283             :     ScToken* t;
    3284       16404 :     while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
    3285             :     {
    3286        7956 :         switch (t->GetType())
    3287             :         {
    3288             :             case svSingleRef:
    3289             :             {
    3290        5635 :                 ScAddress aCell =  t->GetSingleRef().toAbs(aPos);
    3291        5635 :                 if (aCell.IsValid())
    3292        5622 :                     pDoc->StartListeningCell(aCell, this);
    3293             :             }
    3294        5635 :             break;
    3295             :             case svDoubleRef:
    3296        2291 :                 startListeningArea(this, *pDoc, aPos, *t);
    3297        2291 :             break;
    3298             :             default:
    3299             :                 ;   // nothing
    3300             :         }
    3301             :     }
    3302        4224 :     SetNeedsListening( false);
    3303             : }
    3304             : 
    3305          12 : void ScFormulaCell::StartListeningTo( sc::StartListeningContext& rCxt )
    3306             : {
    3307          12 :     ScDocument& rDoc = rCxt.getDoc();
    3308             : 
    3309          12 :     if (rDoc.IsClipOrUndo() || rDoc.GetNoListening() || IsInChangeTrack())
    3310           0 :         return;
    3311             : 
    3312          12 :     rDoc.SetDetectiveDirty(true);  // It has changed something
    3313             : 
    3314          12 :     ScTokenArray* pArr = GetCode();
    3315          12 :     if( pArr->IsRecalcModeAlways() )
    3316             :     {
    3317           0 :         rDoc.StartListeningArea(BCA_LISTEN_ALWAYS, this);
    3318           0 :         SetNeedsListening( false);
    3319           0 :         return;
    3320             :     }
    3321             : 
    3322          12 :     pArr->Reset();
    3323             :     ScToken* t;
    3324          40 :     while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
    3325             :     {
    3326          16 :         switch (t->GetType())
    3327             :         {
    3328             :             case svSingleRef:
    3329             :             {
    3330          12 :                 ScAddress aCell = t->GetSingleRef().toAbs(aPos);
    3331          12 :                 if (aCell.IsValid())
    3332          12 :                     rDoc.StartListeningCell(rCxt, aCell, *this);
    3333             :             }
    3334          12 :             break;
    3335             :             case svDoubleRef:
    3336           1 :                 startListeningArea(this, rDoc, aPos, *t);
    3337           1 :             break;
    3338             :             default:
    3339             :                 ;   // nothing
    3340             :         }
    3341             :     }
    3342          12 :     SetNeedsListening( false);
    3343             : }
    3344             : 
    3345             : namespace {
    3346             : 
    3347          65 : void endListeningArea(
    3348             :     ScFormulaCell* pCell, ScDocument& rDoc, const ScAddress& rPos, const ScToken& rToken)
    3349             : {
    3350          65 :     const ScSingleRefData& rRef1 = rToken.GetSingleRef();
    3351          65 :     const ScSingleRefData& rRef2 = rToken.GetSingleRef2();
    3352          65 :     ScAddress aCell1 = rRef1.toAbs(rPos);
    3353          65 :     ScAddress aCell2 = rRef2.toAbs(rPos);
    3354          65 :     if (aCell1.IsValid() && aCell2.IsValid())
    3355             :     {
    3356          65 :         if (rToken.GetOpCode() == ocColRowNameAuto)
    3357             :         {   // automagically
    3358           0 :             if ( rRef1.IsColRel() )
    3359             :             {   // ColName
    3360           0 :                 aCell2.SetRow(MAXROW);
    3361             :             }
    3362             :             else
    3363             :             {   // RowName
    3364           0 :                 aCell2.SetCol(MAXCOL);
    3365             :             }
    3366             :         }
    3367             : 
    3368          65 :         rDoc.EndListeningArea(ScRange(aCell1, aCell2), pCell);
    3369             :     }
    3370          65 : }
    3371             : 
    3372             : }
    3373             : 
    3374         281 : void ScFormulaCell::EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr,
    3375             :         ScAddress aCellPos )
    3376             : {
    3377         281 :     if (pDoc->IsClipOrUndo() || IsInChangeTrack())
    3378           0 :         return;
    3379             : 
    3380         281 :     pDoc->SetDetectiveDirty(true);  // It has changed something
    3381             : 
    3382         281 :     if ( GetCode()->IsRecalcModeAlways() )
    3383             :     {
    3384           0 :         pDoc->EndListeningArea( BCA_LISTEN_ALWAYS, this );
    3385           0 :         return;
    3386             :     }
    3387             : 
    3388         281 :     if (!pArr)
    3389             :     {
    3390         281 :         pArr = GetCode();
    3391         281 :         aCellPos = aPos;
    3392             :     }
    3393         281 :     pArr->Reset();
    3394             :     ScToken* t;
    3395         874 :     while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
    3396             :     {
    3397         312 :         switch (t->GetType())
    3398             :         {
    3399             :             case svSingleRef:
    3400             :             {
    3401         249 :                 ScAddress aCell = t->GetSingleRef().toAbs(aPos);
    3402         249 :                 if (aCell.IsValid())
    3403         248 :                     pDoc->EndListeningCell(aCell, this);
    3404             :             }
    3405         249 :             break;
    3406             :             case svDoubleRef:
    3407          57 :                 endListeningArea(this, *pDoc, aCellPos, *t);
    3408          57 :             break;
    3409             :             default:
    3410             :                 ;   // nothing
    3411             :         }
    3412             :     }
    3413             : }
    3414             : 
    3415         117 : void ScFormulaCell::EndListeningTo( sc::EndListeningContext& rCxt )
    3416             : {
    3417         117 :     if (rCxt.getDoc().IsClipOrUndo() || IsInChangeTrack())
    3418           0 :         return;
    3419             : 
    3420         117 :     ScDocument& rDoc = rCxt.getDoc();
    3421         117 :     rDoc.SetDetectiveDirty(true);  // It has changed something
    3422             : 
    3423         117 :     if (pCode->IsRecalcModeAlways())
    3424             :     {
    3425           0 :         rDoc.EndListeningArea(BCA_LISTEN_ALWAYS, this);
    3426           0 :         return;
    3427             :     }
    3428             : 
    3429         117 :     pCode->Reset();
    3430             :     ScToken* t;
    3431         281 :     while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceRPN()) ) != NULL )
    3432             :     {
    3433          47 :         switch (t->GetType())
    3434             :         {
    3435             :             case svSingleRef:
    3436             :             {
    3437          38 :                 ScAddress aCell = t->GetSingleRef().toAbs(aPos);
    3438          38 :                 if (aCell.IsValid())
    3439          38 :                     rDoc.EndListeningCell(rCxt, aCell, *this);
    3440             :             }
    3441          38 :             break;
    3442             :             case svDoubleRef:
    3443           8 :                 endListeningArea(this, rDoc, aPos, *t);
    3444           8 :             break;
    3445             :             default:
    3446             :                 ;   // nothing
    3447             :         }
    3448             :     }
    3449             : }
    3450             : 
    3451         284 : bool ScFormulaCell::IsShared() const
    3452             : {
    3453         284 :     return xGroup.get() != NULL;
    3454             : }
    3455             : 
    3456           0 : bool ScFormulaCell::IsSharedInvariant() const
    3457             : {
    3458           0 :     return xGroup ? xGroup->mbInvariant : false;
    3459             : }
    3460             : 
    3461         152 : SCROW ScFormulaCell::GetSharedTopRow() const
    3462             : {
    3463         152 :     return xGroup ? xGroup->mnStart : -1;
    3464             : }
    3465          74 : SCROW ScFormulaCell::GetSharedLength() const
    3466             : {
    3467          74 :     return xGroup ? xGroup->mnLength : 0;
    3468          93 : }
    3469             : 
    3470             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10