LCOV - code coverage report
Current view: top level - sc/source/core/data - formulacell.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1205 1916 62.9 %
Date: 2014-11-03 Functions: 121 151 80.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10