LCOV - code coverage report
Current view: top level - sc/source/core/data - formulacell.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1280 1986 64.5 %
Date: 2015-06-13 12:38:46 Functions: 130 160 81.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11