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

Generated by: LCOV version 1.10