LCOV - code coverage report
Current view: top level - libreoffice/sc/source/core/data - cell.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 521 935 55.7 %
Date: 2012-12-27 Functions: 56 65 86.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 <svl/zforlist.hxx>
      21             : 
      22             : #include "scitems.hxx"
      23             : #include "attrib.hxx"
      24             : #include "cell.hxx"
      25             : #include "compiler.hxx"
      26             : #include "interpre.hxx"
      27             : #include "document.hxx"
      28             : #include "scmatrix.hxx"
      29             : #include "dociter.hxx"
      30             : #include "docoptio.hxx"
      31             : #include "rechead.hxx"
      32             : #include "rangenam.hxx"
      33             : #include "brdcst.hxx"
      34             : #include "ddelink.hxx"
      35             : #include "validat.hxx"
      36             : #include "progress.hxx"
      37             : #include "editutil.hxx"
      38             : #include "recursionhelper.hxx"
      39             : #include "postit.hxx"
      40             : #include "externalrefmgr.hxx"
      41             : #include "macromgr.hxx"
      42             : #include "dbdata.hxx"
      43             : 
      44             : #include <editeng/editobj.hxx>
      45             : #include <svl/intitem.hxx>
      46             : #include <editeng/flditem.hxx>
      47             : #include <svl/broadcast.hxx>
      48             : 
      49             : using namespace formula;
      50             : // More or less arbitrary, of course all recursions must fit into available
      51             : // stack space (which is what on all systems we don't know yet?). Choosing a
      52             : // lower value may be better than trying a much higher value that also isn't
      53             : // sufficient but temporarily leads to high memory consumption. On the other
      54             : // hand, if the value fits all recursions, execution is quicker as no resumes
      55             : // are necessary. Could be made a configurable option.
      56             : // Allow for a year's calendar (366).
      57             : const sal_uInt16 MAXRECURSION = 400;
      58             : 
      59             : // STATIC DATA -----------------------------------------------------------
      60             : 
      61             : #ifdef USE_MEMPOOL
      62           5 : IMPL_FIXEDMEMPOOL_NEWDEL( ScValueCell )
      63           5 : IMPL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell )
      64           5 : IMPL_FIXEDMEMPOOL_NEWDEL( ScStringCell )
      65           5 : IMPL_FIXEDMEMPOOL_NEWDEL( ScNoteCell )
      66             : #endif
      67             : 
      68             : // ============================================================================
      69             : 
      70       34530 : ScBaseCell::ScBaseCell( CellType eNewType ) :
      71             :     mpBroadcaster( 0 ),
      72             :     nTextWidth( TEXTWIDTH_DIRTY ),
      73       34530 :     eCellType( sal::static_int_cast<sal_uInt8>(eNewType) ),
      74       69060 :     nScriptType( SC_SCRIPTTYPE_UNKNOWN )
      75             : {
      76       34530 : }
      77             : 
      78          36 : ScBaseCell::ScBaseCell( const ScBaseCell& rCell ) :
      79             :     mpBroadcaster( 0 ),
      80             :     nTextWidth( rCell.nTextWidth ),
      81             :     eCellType( rCell.eCellType ),
      82          36 :     nScriptType( SC_SCRIPTTYPE_UNKNOWN )
      83             : {
      84          36 : }
      85             : 
      86       33535 : ScBaseCell::~ScBaseCell()
      87             : {
      88       33535 :     delete mpBroadcaster;
      89             :     OSL_ENSURE( eCellType == CELLTYPE_DESTROYED, "BaseCell Destructor" );
      90       33535 : }
      91             : 
      92             : namespace {
      93             : 
      94          36 : ScBaseCell* lclCloneCell( const ScBaseCell& rSrcCell, ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags )
      95             : {
      96          36 :     switch( rSrcCell.GetCellType() )
      97             :     {
      98             :         case CELLTYPE_VALUE:
      99           4 :             return new ScValueCell( static_cast< const ScValueCell& >( rSrcCell ) );
     100             :         case CELLTYPE_STRING:
     101           6 :             return new ScStringCell( static_cast< const ScStringCell& >( rSrcCell ) );
     102             :         case CELLTYPE_EDIT:
     103           0 :             return new ScEditCell(static_cast<const ScEditCell&>(rSrcCell), rDestDoc, rDestPos);
     104             :         case CELLTYPE_FORMULA:
     105          26 :             return new ScFormulaCell( static_cast< const ScFormulaCell& >( rSrcCell ), rDestDoc, rDestPos, nCloneFlags );
     106             :         case CELLTYPE_NOTE:
     107           0 :             return new ScNoteCell;
     108             :         default:;
     109             :     }
     110             :     OSL_FAIL( "lclCloneCell - unknown cell type" );
     111           0 :     return 0;
     112             : }
     113             : 
     114           6 : void adjustRangeName(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldDoc, const ScAddress& aNewPos, const ScAddress& aOldPos)
     115             : {
     116           6 :     bool bOldGlobal = pToken->IsGlobal();
     117           6 :     SCTAB aOldTab = aOldPos.Tab();
     118           6 :     rtl::OUString aRangeName;
     119           6 :     int nOldIndex = pToken->GetIndex();
     120           6 :     ScRangeData* pOldRangeData = NULL;
     121             : 
     122             :     //search the name of the RangeName
     123           6 :     if (!bOldGlobal)
     124             :     {
     125           3 :         pOldRangeData = pOldDoc->GetRangeName(aOldTab)->findByIndex(nOldIndex);
     126           3 :         if (!pOldRangeData)
     127             :             return;     //might be an error in the formula array
     128           3 :         aRangeName = pOldRangeData->GetUpperName();
     129             :     }
     130             :     else
     131             :     {
     132           3 :         pOldRangeData = pOldDoc->GetRangeName()->findByIndex(nOldIndex);
     133           3 :         if (!pOldRangeData)
     134             :             return;     //might be an error in the formula array
     135           3 :         aRangeName = pOldRangeData->GetUpperName();
     136             :     }
     137             : 
     138             :     //find corresponding range name in new document
     139             :     //first search for local range name then global range names
     140           6 :     SCTAB aNewTab = aNewPos.Tab();
     141           6 :     ScRangeName* pRangeName = rNewDoc.GetRangeName(aNewTab);
     142           6 :     ScRangeData* pRangeData = NULL;
     143           6 :     bool bNewGlobal = false;
     144             :     //search local range names
     145           6 :     if (pRangeName)
     146             :     {
     147           6 :         pRangeData = pRangeName->findByUpperName(aRangeName);
     148             :     }
     149             :     //search global range names
     150           6 :     if (!pRangeData)
     151             :     {
     152           5 :         bNewGlobal = true;
     153           5 :         pRangeName = rNewDoc.GetRangeName();
     154           5 :         if (pRangeName)
     155           5 :             pRangeData = pRangeName->findByUpperName(aRangeName);
     156             :     }
     157             :     //if no range name was found copy it
     158           6 :     if (!pRangeData)
     159             :     {
     160           3 :         bNewGlobal = bOldGlobal;
     161           3 :         pRangeData = new ScRangeData(*pOldRangeData, &rNewDoc);
     162           3 :         ScTokenArray* pRangeNameToken = pRangeData->GetCode();
     163           3 :         if (rNewDoc.GetPool() != const_cast<ScDocument*>(pOldDoc)->GetPool())
     164             :         {
     165           0 :             pRangeNameToken->ReadjustAbsolute3DReferences(pOldDoc, &rNewDoc, pRangeData->GetPos(), true);
     166           0 :             pRangeNameToken->AdjustAbsoluteRefs(pOldDoc, aOldPos, aNewPos, false, true);
     167             :         }
     168             : 
     169             :         bool bInserted;
     170           3 :         if (bNewGlobal)
     171           1 :             bInserted = rNewDoc.GetRangeName()->insert(pRangeData);
     172             :         else
     173           2 :             bInserted = rNewDoc.GetRangeName(aNewTab)->insert(pRangeData);
     174           3 :         if (!bInserted)
     175             :         {
     176             :             //if this happened we have a real problem
     177           0 :             pRangeData = NULL;
     178           0 :             pToken->SetIndex(0);
     179             :             OSL_FAIL("inserting the range name should not fail");
     180             :             return;
     181             :         }
     182             :     }
     183           6 :     sal_Int32 nIndex = pRangeData->GetIndex();
     184           6 :     pToken->SetIndex(nIndex);
     185           6 :     pToken->SetGlobal(bNewGlobal);
     186             : }
     187             : 
     188           0 : void adjustDBRange(ScToken* pToken, ScDocument& rNewDoc, const ScDocument* pOldDoc)
     189             : {
     190           0 :     ScDBCollection* pOldDBCollection = pOldDoc->GetDBCollection();
     191           0 :     if (!pOldDBCollection)
     192             :         return;//strange error case, don't do anything
     193           0 :     ScDBCollection::NamedDBs& aOldNamedDBs = pOldDBCollection->getNamedDBs();
     194           0 :     ScDBData* pDBData = aOldNamedDBs.findByIndex(pToken->GetIndex());
     195           0 :     if (!pDBData)
     196             :         return; //invalid index
     197           0 :     rtl::OUString aDBName = pDBData->GetUpperName();
     198             : 
     199             :     //search in new document
     200           0 :     ScDBCollection* pNewDBCollection = rNewDoc.GetDBCollection();
     201           0 :     if (!pNewDBCollection)
     202             :     {
     203           0 :         pNewDBCollection = new ScDBCollection(&rNewDoc);
     204             :     }
     205           0 :     ScDBCollection::NamedDBs& aNewNamedDBs = pNewDBCollection->getNamedDBs();
     206           0 :     ScDBData* pNewDBData = aNewNamedDBs.findByUpperName(aDBName);
     207           0 :     if (!pNewDBData)
     208             :     {
     209           0 :         pNewDBData = new ScDBData(*pDBData);
     210           0 :         aNewNamedDBs.insert(pNewDBData);
     211             :     }
     212           0 :     pToken->SetIndex(pNewDBData->GetIndex());
     213             : }
     214             : 
     215             : } // namespace
     216             : 
     217           2 : ScBaseCell* ScBaseCell::Clone( ScDocument& rDestDoc, int nCloneFlags ) const
     218             : {
     219             :     // notes will not be cloned -> cell address only needed for formula cells
     220           2 :     ScAddress aDestPos;
     221           2 :     if( eCellType == CELLTYPE_FORMULA )
     222           0 :         aDestPos = static_cast< const ScFormulaCell* >( this )->aPos;
     223           2 :     return lclCloneCell( *this, rDestDoc, aDestPos, nCloneFlags );
     224             : }
     225             : 
     226          34 : ScBaseCell* ScBaseCell::Clone( ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags ) const
     227             : {
     228          34 :     return lclCloneCell( *this, rDestDoc, rDestPos, nCloneFlags );
     229             : }
     230             : 
     231       33457 : void ScBaseCell::Delete()
     232             : {
     233       33457 :     switch (eCellType)
     234             :     {
     235             :         case CELLTYPE_VALUE:
     236       18132 :             delete (ScValueCell*) this;
     237       18132 :             break;
     238             :         case CELLTYPE_STRING:
     239       12136 :             delete (ScStringCell*) this;
     240       12136 :             break;
     241             :         case CELLTYPE_EDIT:
     242          84 :             delete (ScEditCell*) this;
     243          84 :             break;
     244             :         case CELLTYPE_FORMULA:
     245        2988 :             delete (ScFormulaCell*) this;
     246        2988 :             break;
     247             :         case CELLTYPE_NOTE:
     248         117 :             delete (ScNoteCell*) this;
     249         117 :             break;
     250             :         default:
     251             :             OSL_FAIL("Attempt to Delete() an unknown CELLTYPE");
     252           0 :             break;
     253             :     }
     254       33457 : }
     255             : 
     256        1113 : bool ScBaseCell::IsBlank() const
     257             : {
     258        1113 :     if(eCellType == CELLTYPE_NOTE)
     259          43 :         return true;
     260             : 
     261        1070 :     return false;
     262             : }
     263             : 
     264        3881 : void ScBaseCell::TakeBroadcaster( SvtBroadcaster* pBroadcaster )
     265             : {
     266        3881 :     delete mpBroadcaster;
     267        3881 :     mpBroadcaster = pBroadcaster;
     268        3881 : }
     269             : 
     270         160 : SvtBroadcaster* ScBaseCell::ReleaseBroadcaster()
     271             : {
     272         160 :     SvtBroadcaster* pBroadcaster = mpBroadcaster;
     273         160 :     mpBroadcaster = 0;
     274         160 :     return pBroadcaster;
     275             : }
     276             : 
     277         102 : void ScBaseCell::DeleteBroadcaster()
     278             : {
     279         102 :     DELETEZ( mpBroadcaster );
     280         102 : }
     281             : 
     282       11701 : ScBaseCell* ScBaseCell::CreateTextCell( const rtl::OUString& rString, ScDocument* pDoc )
     283             : {
     284       11701 :     if ( rString.indexOf('\n') != -1 || rString.indexOf(CHAR_CR) != -1 )
     285          13 :         return new ScEditCell( rString, pDoc );
     286             :     else
     287       11688 :         return new ScStringCell( rString );
     288             : }
     289             : 
     290        4213 : void ScBaseCell::StartListeningTo( ScDocument* pDoc )
     291             : {
     292       10481 :     if ( eCellType == CELLTYPE_FORMULA && !pDoc->IsClipOrUndo()
     293        3134 :             && !pDoc->GetNoListening()
     294        3134 :             && !((ScFormulaCell*)this)->IsInChangeTrack()
     295             :         )
     296             :     {
     297        3134 :         pDoc->SetDetectiveDirty(true);  // It has changed something
     298             : 
     299        3134 :         ScFormulaCell* pFormCell = (ScFormulaCell*)this;
     300        3134 :         ScTokenArray* pArr = pFormCell->GetCode();
     301        3134 :         if( pArr->IsRecalcModeAlways() )
     302          22 :             pDoc->StartListeningArea( BCA_LISTEN_ALWAYS, pFormCell );
     303             :         else
     304             :         {
     305        3112 :             pArr->Reset();
     306             :             ScToken* t;
     307       13495 :             while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
     308             :             {
     309        7271 :                 StackVar eType = t->GetType();
     310        7271 :                 ScSingleRefData& rRef1 = t->GetSingleRef();
     311             :                 ScSingleRefData& rRef2 = (eType == svDoubleRef ?
     312        7271 :                     t->GetDoubleRef().Ref2 : rRef1);
     313        7271 :                 switch( eType )
     314             :                 {
     315             :                     case svSingleRef:
     316        5039 :                         rRef1.CalcAbsIfRel( pFormCell->aPos );
     317        5039 :                         if ( rRef1.Valid() )
     318             :                         {
     319             :                             pDoc->StartListeningCell(
     320             :                                 ScAddress( rRef1.nCol,
     321             :                                            rRef1.nRow,
     322        5026 :                                            rRef1.nTab ), pFormCell );
     323             :                         }
     324        5039 :                     break;
     325             :                     case svDoubleRef:
     326        2200 :                         t->CalcAbsIfRel( pFormCell->aPos );
     327        2200 :                         if ( rRef1.Valid() && rRef2.Valid() )
     328             :                         {
     329        2200 :                             if ( t->GetOpCode() == ocColRowNameAuto )
     330             :                             {   // automagically
     331           0 :                                 if ( rRef1.IsColRel() )
     332             :                                 {   // ColName
     333             :                                     pDoc->StartListeningArea( ScRange (
     334             :                                         rRef1.nCol,
     335             :                                         rRef1.nRow,
     336             :                                         rRef1.nTab,
     337             :                                         rRef2.nCol,
     338             :                                         MAXROW,
     339           0 :                                         rRef2.nTab ), pFormCell );
     340             :                                 }
     341             :                                 else
     342             :                                 {   // RowName
     343             :                                     pDoc->StartListeningArea( ScRange (
     344             :                                         rRef1.nCol,
     345             :                                         rRef1.nRow,
     346             :                                         rRef1.nTab,
     347             :                                         MAXCOL,
     348             :                                         rRef2.nRow,
     349           0 :                                         rRef2.nTab ), pFormCell );
     350             :                                 }
     351             :                             }
     352             :                             else
     353             :                             {
     354             :                                 pDoc->StartListeningArea( ScRange (
     355             :                                     rRef1.nCol,
     356             :                                     rRef1.nRow,
     357             :                                     rRef1.nTab,
     358             :                                     rRef2.nCol,
     359             :                                     rRef2.nRow,
     360        2200 :                                     rRef2.nTab ), pFormCell );
     361             :                             }
     362             :                         }
     363        2200 :                     break;
     364             :                     default:
     365             :                         ;   // nothing
     366             :                 }
     367             :             }
     368             :         }
     369        3134 :         pFormCell->SetNeedsListening( false);
     370             :     }
     371        4213 : }
     372             : 
     373             : //  pArr gesetzt -> Referenzen von anderer Zelle nehmen
     374             : // Then aPos must also be commited
     375             : 
     376         207 : void ScBaseCell::EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr,
     377             :         ScAddress aPos )
     378             : {
     379         371 :     if ( eCellType == CELLTYPE_FORMULA && !pDoc->IsClipOrUndo()
     380         164 :             && !((ScFormulaCell*)this)->IsInChangeTrack()
     381             :         )
     382             :     {
     383         164 :         pDoc->SetDetectiveDirty(true);  // It has changed something
     384             : 
     385         164 :         ScFormulaCell* pFormCell = (ScFormulaCell*)this;
     386         164 :         if( pFormCell->GetCode()->IsRecalcModeAlways() )
     387           0 :             pDoc->EndListeningArea( BCA_LISTEN_ALWAYS, pFormCell );
     388             :         else
     389             :         {
     390         164 :             if (!pArr)
     391             :             {
     392         164 :                 pArr = pFormCell->GetCode();
     393         164 :                 aPos = pFormCell->aPos;
     394             :             }
     395         164 :             pArr->Reset();
     396             :             ScToken* t;
     397         585 :             while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
     398             :             {
     399         257 :                 StackVar eType = t->GetType();
     400         257 :                 ScSingleRefData& rRef1 = t->GetSingleRef();
     401             :                 ScSingleRefData& rRef2 = (eType == svDoubleRef ?
     402         257 :                     t->GetDoubleRef().Ref2 : rRef1);
     403         257 :                 switch( eType )
     404             :                 {
     405             :                     case svSingleRef:
     406         175 :                         rRef1.CalcAbsIfRel( aPos );
     407         175 :                         if ( rRef1.Valid() )
     408             :                         {
     409             :                             pDoc->EndListeningCell(
     410             :                                 ScAddress( rRef1.nCol,
     411             :                                            rRef1.nRow,
     412         174 :                                            rRef1.nTab ), pFormCell );
     413             :                         }
     414         175 :                     break;
     415             :                     case svDoubleRef:
     416          76 :                         t->CalcAbsIfRel( aPos );
     417          76 :                         if ( rRef1.Valid() && rRef2.Valid() )
     418             :                         {
     419          76 :                             if ( t->GetOpCode() == ocColRowNameAuto )
     420             :                             {   // automagically
     421           0 :                                 if ( rRef1.IsColRel() )
     422             :                                 {   // ColName
     423             :                                     pDoc->EndListeningArea( ScRange (
     424             :                                         rRef1.nCol,
     425             :                                         rRef1.nRow,
     426             :                                         rRef1.nTab,
     427             :                                         rRef2.nCol,
     428             :                                         MAXROW,
     429           0 :                                         rRef2.nTab ), pFormCell );
     430             :                                 }
     431             :                                 else
     432             :                                 {   // RowName
     433             :                                     pDoc->EndListeningArea( ScRange (
     434             :                                         rRef1.nCol,
     435             :                                         rRef1.nRow,
     436             :                                         rRef1.nTab,
     437             :                                         MAXCOL,
     438             :                                         rRef2.nRow,
     439           0 :                                         rRef2.nTab ), pFormCell );
     440             :                                 }
     441             :                             }
     442             :                             else
     443             :                             {
     444             :                                 pDoc->EndListeningArea( ScRange (
     445             :                                     rRef1.nCol,
     446             :                                     rRef1.nRow,
     447             :                                     rRef1.nTab,
     448             :                                     rRef2.nCol,
     449             :                                     rRef2.nRow,
     450          76 :                                     rRef2.nTab ), pFormCell );
     451             :                             }
     452             :                         }
     453          76 :                     break;
     454             :                     default:
     455             :                         ;   // nothing
     456             :                 }
     457             :             }
     458             :         }
     459             :     }
     460         207 : }
     461             : 
     462             : 
     463         463 : sal_uInt16 ScBaseCell::GetErrorCode() const
     464             : {
     465         463 :     switch ( eCellType )
     466             :     {
     467             :         case CELLTYPE_FORMULA :
     468          94 :             return ((ScFormulaCell*)this)->GetErrCode();
     469             :         default:
     470         369 :             return 0;
     471             :     }
     472             : }
     473             : 
     474             : 
     475         256 : bool ScBaseCell::HasEmptyData() const
     476             : {
     477         256 :     switch ( eCellType )
     478             :     {
     479             :         case CELLTYPE_NOTE :
     480          11 :             return true;
     481             :         case CELLTYPE_FORMULA :
     482          49 :             return ((ScFormulaCell*)this)->IsEmpty();
     483             :         default:
     484         196 :             return false;
     485             :     }
     486             : }
     487             : 
     488             : 
     489         970 : bool ScBaseCell::HasValueData() const
     490             : {
     491         970 :     switch ( eCellType )
     492             :     {
     493             :         case CELLTYPE_VALUE :
     494         563 :             return true;
     495             :         case CELLTYPE_FORMULA :
     496         188 :             return ((ScFormulaCell*)this)->IsValue();
     497             :         default:
     498         219 :             return false;
     499             :     }
     500             : }
     501             : 
     502             : 
     503        1577 : bool ScBaseCell::HasStringData() const
     504             : {
     505        1577 :     switch ( eCellType )
     506             :     {
     507             :         case CELLTYPE_STRING :
     508             :         case CELLTYPE_EDIT :
     509         245 :             return true;
     510             :         case CELLTYPE_FORMULA :
     511         370 :             return !((ScFormulaCell*)this)->IsValue();
     512             :         default:
     513         962 :             return false;
     514             :     }
     515             : }
     516             : 
     517           0 : rtl::OUString ScBaseCell::GetStringData() const
     518             : {
     519           0 :     rtl::OUString aStr;
     520           0 :     switch ( eCellType )
     521             :     {
     522             :         case CELLTYPE_STRING:
     523           0 :             aStr = ((const ScStringCell*)this)->GetString();
     524           0 :             break;
     525             :         case CELLTYPE_EDIT:
     526           0 :             aStr = ((const ScEditCell*)this)->GetString();
     527           0 :             break;
     528             :         case CELLTYPE_FORMULA:
     529           0 :             aStr = ((ScFormulaCell*)this)->GetString();      // On the Formula cells are not constant
     530           0 :             break;
     531             :     }
     532           0 :     return aStr;
     533             : }
     534             : 
     535           0 : bool ScBaseCell::CellEqual( const ScBaseCell* pCell1, const ScBaseCell* pCell2 )
     536             : {
     537           0 :     CellType eType1 = CELLTYPE_NONE;
     538           0 :     CellType eType2 = CELLTYPE_NONE;
     539           0 :     if ( pCell1 )
     540             :     {
     541           0 :         eType1 = pCell1->GetCellType();
     542           0 :         if (eType1 == CELLTYPE_EDIT)
     543           0 :             eType1 = CELLTYPE_STRING;
     544           0 :         else if (eType1 == CELLTYPE_NOTE)
     545           0 :             eType1 = CELLTYPE_NONE;
     546             :     }
     547           0 :     if ( pCell2 )
     548             :     {
     549           0 :         eType2 = pCell2->GetCellType();
     550           0 :         if (eType2 == CELLTYPE_EDIT)
     551           0 :             eType2 = CELLTYPE_STRING;
     552           0 :         else if (eType2 == CELLTYPE_NOTE)
     553           0 :             eType2 = CELLTYPE_NONE;
     554             :     }
     555           0 :     if ( eType1 != eType2 )
     556           0 :         return false;
     557             : 
     558           0 :     switch ( eType1 )               // Both Types are the same
     559             :     {
     560             :         case CELLTYPE_NONE:         // Both Empty
     561           0 :             return true;
     562             :         case CELLTYPE_VALUE:        // Really Value-Cells
     563           0 :             return ( ((const ScValueCell*)pCell1)->GetValue() ==
     564           0 :                      ((const ScValueCell*)pCell2)->GetValue() );
     565             :         case CELLTYPE_STRING:       // String or Edit
     566             :             {
     567           0 :                 rtl::OUString aText1;
     568           0 :                 if ( pCell1->GetCellType() == CELLTYPE_STRING )
     569           0 :                     aText1 = ((const ScStringCell*)pCell1)->GetString();
     570             :                 else
     571           0 :                     aText1 = ((const ScEditCell*)pCell1)->GetString();
     572           0 :                 rtl::OUString aText2;
     573           0 :                 if ( pCell2->GetCellType() == CELLTYPE_STRING )
     574           0 :                     aText2 = ((const ScStringCell*)pCell2)->GetString();
     575             :                 else
     576           0 :                     aText2 = ((const ScEditCell*)pCell2)->GetString();
     577           0 :                 return ( aText1 == aText2 );
     578             :             }
     579             :         case CELLTYPE_FORMULA:
     580             :             {
     581             :                 //! pasted Lines / allow Slots!!!!!
     582             :                 //! Comparsion Function of the Formula Cell???
     583             :                 //! To request with ScColumn::SwapRow to catch together!
     584             : 
     585           0 :                 ScTokenArray* pCode1 = ((ScFormulaCell*)pCell1)->GetCode();
     586           0 :                 ScTokenArray* pCode2 = ((ScFormulaCell*)pCell2)->GetCode();
     587             : 
     588           0 :                 if (pCode1->GetLen() == pCode2->GetLen())       // nicht-UPN
     589             :                 {
     590           0 :                     bool bEqual = true;
     591           0 :                     sal_uInt16 nLen = pCode1->GetLen();
     592           0 :                     FormulaToken** ppToken1 = pCode1->GetArray();
     593           0 :                     FormulaToken** ppToken2 = pCode2->GetArray();
     594           0 :                     for (sal_uInt16 i=0; i<nLen; i++)
     595           0 :                         if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) )
     596             :                         {
     597           0 :                             bEqual = false;
     598           0 :                             break;
     599             :                         }
     600             : 
     601           0 :                     if (bEqual)
     602           0 :                         return true;
     603             :                 }
     604             : 
     605           0 :                 return false;       // varying long or varying Tokens
     606             :             }
     607             :         default:
     608             :             OSL_FAIL("oops, something for the Cells???");
     609             :     }
     610           0 :     return false;
     611             : }
     612             : 
     613             : // ============================================================================
     614             : 
     615         201 : ScNoteCell::ScNoteCell( SvtBroadcaster* pBC ) :
     616         201 :     ScBaseCell( CELLTYPE_NOTE )
     617             : {
     618         201 :     TakeBroadcaster( pBC );
     619         201 : }
     620             : 
     621             : #if OSL_DEBUG_LEVEL > 0
     622             : ScNoteCell::~ScNoteCell()
     623             : {
     624             :     eCellType = CELLTYPE_DESTROYED;
     625             : }
     626             : #endif
     627             : 
     628             : // ============================================================================
     629             : 
     630       18791 : ScValueCell::ScValueCell( double fValue ) :
     631             :     ScBaseCell( CELLTYPE_VALUE ),
     632       18791 :     mfValue( fValue )
     633             : {
     634       18791 : }
     635             : 
     636             : #if OSL_DEBUG_LEVEL > 0
     637             : ScValueCell::~ScValueCell()
     638             : {
     639             :     eCellType = CELLTYPE_DESTROYED;
     640             : }
     641             : #endif
     642             : 
     643             : // ============================================================================
     644             : 
     645       12345 : ScStringCell::ScStringCell( const rtl::OUString& rString ) :
     646             :     ScBaseCell( CELLTYPE_STRING ),
     647       12345 :     maString( rString.intern() )
     648             : {
     649       12345 : }
     650             : 
     651             : #if OSL_DEBUG_LEVEL > 0
     652             : ScStringCell::~ScStringCell()
     653             : {
     654             :     eCellType = CELLTYPE_DESTROYED;
     655             : }
     656             : #endif
     657             : 
     658             : // ============================================================================
     659             : 
     660             : //
     661             : //      ScFormulaCell
     662             : //
     663             : 
     664         224 : ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
     665             :                               const rtl::OUString& rFormula,
     666             :                               const FormulaGrammar::Grammar eGrammar,
     667             :                               sal_uInt8 cMatInd ) :
     668             :     ScBaseCell( CELLTYPE_FORMULA ),
     669             :     eTempGrammar( eGrammar),
     670             :     pCode( NULL ),
     671             :     pDocument( pDoc ),
     672             :     pPrevious(0),
     673             :     pNext(0),
     674             :     pPreviousTrack(0),
     675             :     pNextTrack(0),
     676             :     nFormatIndex(0),
     677             :     nFormatType( NUMBERFORMAT_NUMBER ),
     678             :     nSeenInIteration(0),
     679             :     cMatrixFlag ( cMatInd ),
     680             :     bDirty( true ), // -> Because of the use of the Auto Pilot Function was: cMatInd != 0
     681             :     bChanged( false ),
     682             :     bRunning( false ),
     683             :     bCompile( false ),
     684             :     bSubTotal( false ),
     685             :     bIsIterCell( false ),
     686             :     bInChangeTrack( false ),
     687             :     bTableOpDirty( false ),
     688             :     bNeedListening( false ),
     689         224 :     aPos( rPos )
     690             : {
     691         224 :     Compile( rFormula, true, eGrammar );    // bNoListening, Insert does that
     692         224 :     if (!pCode)
     693             :         // We need to have a non-NULL token array instance at all times.
     694           0 :         pCode = new ScTokenArray;
     695         224 : }
     696             : 
     697             : // Used by import filters
     698             : 
     699        2885 : ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
     700             :                               const ScTokenArray* pArr,
     701             :                               const FormulaGrammar::Grammar eGrammar, sal_uInt8 cInd ) :
     702             :     ScBaseCell( CELLTYPE_FORMULA ),
     703             :     eTempGrammar( eGrammar),
     704        2885 :     pCode( pArr ? new ScTokenArray( *pArr ) : new ScTokenArray ),
     705             :     pDocument( pDoc ),
     706             :     pPrevious(0),
     707             :     pNext(0),
     708             :     pPreviousTrack(0),
     709             :     pNextTrack(0),
     710             :     nFormatIndex(0),
     711             :     nFormatType( NUMBERFORMAT_NUMBER ),
     712             :     nSeenInIteration(0),
     713             :     cMatrixFlag ( cInd ),
     714             :     bDirty( NULL != pArr ), // -> Because of the use of the Auto Pilot Function was: cInd != 0
     715             :     bChanged( false ),
     716             :     bRunning( false ),
     717             :     bCompile( false ),
     718             :     bSubTotal( false ),
     719             :     bIsIterCell( false ),
     720             :     bInChangeTrack( false ),
     721             :     bTableOpDirty( false ),
     722             :     bNeedListening( false ),
     723        5770 :     aPos( rPos )
     724             : {
     725             :     // UPN-Array generation
     726        2885 :     if( pCode->GetLen() && !pCode->GetCodeError() && !pCode->GetCodeLen() )
     727             :     {
     728        2885 :         ScCompiler aComp( pDocument, aPos, *pCode);
     729        2885 :         aComp.SetGrammar(eTempGrammar);
     730        2885 :         bSubTotal = aComp.CompileTokenArray();
     731        2885 :         nFormatType = aComp.GetNumFormatType();
     732             :     }
     733             :     else
     734             :     {
     735           0 :         pCode->Reset();
     736           0 :         if ( pCode->GetNextOpCodeRPN( ocSubTotal ) )
     737           0 :             bSubTotal = true;
     738             :     }
     739             : 
     740        2885 :     if (bSubTotal)
     741           0 :         pDocument->AddSubTotalCell(this);
     742        2885 : }
     743             : 
     744          26 : ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags ) :
     745             :     ScBaseCell( rCell ),
     746             :     SvtListener(),
     747             :     aResult( rCell.aResult ),
     748             :     eTempGrammar( rCell.eTempGrammar),
     749             :     pDocument( &rDoc ),
     750             :     pPrevious(0),
     751             :     pNext(0),
     752             :     pPreviousTrack(0),
     753             :     pNextTrack(0),
     754             :     nFormatIndex( &rDoc == rCell.pDocument ? rCell.nFormatIndex : 0 ),
     755             :     nFormatType( rCell.nFormatType ),
     756             :     nSeenInIteration(0),
     757             :     cMatrixFlag ( rCell.cMatrixFlag ),
     758             :     bDirty( rCell.bDirty ),
     759             :     bChanged( rCell.bChanged ),
     760             :     bRunning( false ),
     761             :     bCompile( rCell.bCompile ),
     762             :     bSubTotal( rCell.bSubTotal ),
     763             :     bIsIterCell( false ),
     764             :     bInChangeTrack( false ),
     765             :     bTableOpDirty( false ),
     766             :     bNeedListening( false ),
     767          26 :     aPos( rPos )
     768             : {
     769          26 :     pCode = rCell.pCode->Clone();
     770             : 
     771             :     //  set back any errors and recompile
     772             :     //  not in the Clipboard - it must keep the recieved error flag
     773             :     //  Special Length=0: as bad cells are generated, then they are also retained
     774          26 :     if ( pCode->GetCodeError() && !pDocument->IsClipboard() && pCode->GetLen() )
     775             :     {
     776           0 :         pCode->SetCodeError( 0 );
     777           0 :         bCompile = true;
     778             :     }
     779             :     //! Compile ColRowNames on URM_MOVE/URM_COPY _after_ UpdateReference
     780          26 :     bool bCompileLater = false;
     781          26 :     bool bClipMode = rCell.pDocument->IsClipboard();
     782             : 
     783             :     //update ScNameTokens
     784          26 :     if (!pDocument->IsClipOrUndo() || rDoc.IsUndo())
     785             :     {
     786          14 :         if (!pDocument->IsClipboardSource() || aPos.Tab() != rCell.aPos.Tab())
     787             :         {
     788          14 :             ScToken* pToken = NULL;
     789          34 :             while((pToken = static_cast<ScToken*>(pCode->GetNextName()))!= NULL)
     790             :             {
     791           6 :                 OpCode eOpCode = pToken->GetOpCode();
     792           6 :                 if (eOpCode == ocName)
     793           6 :                     adjustRangeName(pToken, rDoc, rCell.pDocument, aPos, rCell.aPos);
     794           0 :                 else if (eOpCode == ocDBArea)
     795           0 :                     adjustDBRange(pToken, rDoc, rCell.pDocument);
     796             :             }
     797             :         }
     798             : 
     799          14 :         bool bCopyBetweenDocs = pDocument->GetPool() != rCell.pDocument->GetPool();
     800          14 :         if (bCopyBetweenDocs && !(nCloneFlags & SC_CLONECELL_NOMAKEABS_EXTERNAL))
     801             :         {
     802           6 :             pCode->ReadjustAbsolute3DReferences( rCell.pDocument, &rDoc, rCell.aPos);
     803             :         }
     804             : 
     805          14 :         pCode->AdjustAbsoluteRefs( rCell.pDocument, rCell.aPos, aPos, false, bCopyBetweenDocs );
     806             :     }
     807             : 
     808          26 :     if ( nCloneFlags & SC_CLONECELL_ADJUST3DREL )
     809           0 :         pCode->ReadjustRelative3DReferences( rCell.aPos, aPos );
     810             : 
     811          26 :     if( !bCompile )
     812             :     {   // Name references with references and ColRowNames
     813          24 :         pCode->Reset();
     814             :         ScToken* t;
     815          76 :         while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceOrName()) ) != NULL && !bCompile )
     816             :         {
     817          28 :             if ( t->IsExternalRef() )
     818             :             {
     819             :                 // External name, cell, and area references.
     820           3 :                 bCompile = true;
     821             :             }
     822          25 :             else if ( t->GetType() == svIndex )
     823             :             {
     824           2 :                 ScRangeData* pRangeData = rDoc.GetRangeName()->findByIndex( t->GetIndex() );
     825           2 :                 if( pRangeData )
     826             :                 {
     827           2 :                     if( pRangeData->HasReferences() )
     828           2 :                         bCompile = true;
     829             :                 }
     830             :                 else
     831           0 :                     bCompile = true;    // invalid reference!
     832             :             }
     833          23 :             else if ( t->GetOpCode() == ocColRowName )
     834             :             {
     835           0 :                 bCompile = true;        // new lookup needed
     836           0 :                 bCompileLater = bClipMode;
     837             :             }
     838             :         }
     839             :     }
     840          26 :     if( bCompile )
     841             :     {
     842           7 :         if ( !bCompileLater && bClipMode )
     843             :         {
     844             :             // Merging ranges needs the actual positions after UpdateReference.
     845             :             // ColRowNames need new lookup after positions are adjusted.
     846           4 :             bCompileLater = pCode->HasOpCode( ocRange) || pCode->HasOpCode( ocColRowName);
     847             :         }
     848           7 :         if ( !bCompileLater )
     849             :         {
     850             :             // bNoListening, not at all if in Clipboard/Undo,
     851             :             // and not from Clipboard either, instead after Insert(Clone) and UpdateReference.
     852           7 :             CompileTokenArray( true );
     853             :         }
     854             :     }
     855             : 
     856          26 :     if( nCloneFlags & SC_CLONECELL_STARTLISTENING )
     857           0 :         StartListeningTo( &rDoc );
     858             : 
     859          26 :     if (bSubTotal)
     860           0 :         pDocument->AddSubTotalCell(this);
     861          26 : }
     862             : 
     863        8997 : ScFormulaCell::~ScFormulaCell()
     864             : {
     865        2999 :     pDocument->RemoveFromFormulaTree( this );
     866        2999 :     pDocument->RemoveSubTotalCell(this);
     867        2999 :     if (pCode->HasOpCode(ocMacro))
     868           1 :         pDocument->GetMacroManager()->RemoveDependentCell(this);
     869             : 
     870        2999 :     if (pDocument->HasExternalRefManager())
     871          10 :         pDocument->GetExternalRefManager()->removeRefCell(this);
     872             : 
     873        2999 :     delete pCode;
     874             : #if OSL_DEBUG_LEVEL > 0
     875             :     eCellType = CELLTYPE_DESTROYED;
     876             : #endif
     877        5998 : }
     878             : 
     879          20 : void ScFormulaCell::GetFormula( rtl::OUStringBuffer& rBuffer,
     880             :                                 const FormulaGrammar::Grammar eGrammar ) const
     881             : {
     882          20 :     if( pCode->GetCodeError() && !pCode->GetLen() )
     883             :     {
     884           0 :         rBuffer = rtl::OUStringBuffer( ScGlobal::GetErrorString( pCode->GetCodeError()));
     885             :         return;
     886             :     }
     887          20 :     else if( cMatrixFlag == MM_REFERENCE )
     888             :     {
     889             :         // Reference to another cell that contains a matrix formula.
     890           0 :         pCode->Reset();
     891           0 :         ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
     892           0 :         if( p )
     893             :         {
     894             :             /* FIXME: original GetFormula() code obtained
     895             :              * pCell only if (!this->IsInChangeTrack()),
     896             :              * GetEnglishFormula() omitted that test.
     897             :              * Can we live without in all cases? */
     898             :             ScBaseCell* pCell;
     899           0 :             ScSingleRefData& rRef = p->GetSingleRef();
     900           0 :             rRef.CalcAbsIfRel( aPos );
     901           0 :             if ( rRef.Valid() )
     902             :                 pCell = pDocument->GetCell( ScAddress( rRef.nCol,
     903           0 :                             rRef.nRow, rRef.nTab ) );
     904             :             else
     905           0 :                 pCell = NULL;
     906           0 :             if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
     907             :             {
     908           0 :                 ((ScFormulaCell*)pCell)->GetFormula( rBuffer, eGrammar);
     909             :                 return;
     910             :             }
     911             :             else
     912             :             {
     913           0 :                 ScCompiler aComp( pDocument, aPos, *pCode);
     914           0 :                 aComp.SetGrammar(eGrammar);
     915           0 :                 aComp.CreateStringFromTokenArray( rBuffer );
     916             :             }
     917             :         }
     918             :         else
     919             :         {
     920             :             OSL_FAIL("ScFormulaCell::GetFormula: not a matrix");
     921             :         }
     922             :     }
     923             :     else
     924             :     {
     925          20 :         ScCompiler aComp( pDocument, aPos, *pCode);
     926          20 :         aComp.SetGrammar(eGrammar);
     927          20 :         aComp.CreateStringFromTokenArray( rBuffer );
     928             :     }
     929             : 
     930          20 :     sal_Unicode ch('=');
     931          20 :     rBuffer.insert( 0, &ch, 1 );
     932          20 :     if( cMatrixFlag )
     933             :     {
     934           0 :         sal_Unicode ch2('{');
     935           0 :         rBuffer.insert( 0, &ch2, 1);
     936           0 :         rBuffer.append( sal_Unicode('}'));
     937             :     }
     938             : }
     939             : 
     940          20 : void ScFormulaCell::GetFormula( rtl::OUString& rFormula, const FormulaGrammar::Grammar eGrammar ) const
     941             : {
     942          20 :     rtl::OUStringBuffer rBuffer( rFormula );
     943          20 :     GetFormula( rBuffer, eGrammar );
     944          20 :     rFormula = rBuffer.makeStringAndClear();
     945          20 : }
     946             : 
     947           0 : void ScFormulaCell::GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows )
     948             : {
     949           0 :     MaybeInterpret();
     950             : 
     951           0 :     const ScMatrix* pMat = NULL;
     952           0 :     if (!pCode->GetCodeError() && aResult.GetType() == svMatrixCell &&
     953           0 :             ((pMat = static_cast<const ScToken*>(aResult.GetToken().get())->GetMatrix()) != 0))
     954           0 :         pMat->GetDimensions( rCols, rRows );
     955             :     else
     956             :     {
     957           0 :         rCols = 0;
     958           0 :         rRows = 0;
     959             :     }
     960           0 : }
     961             : 
     962         224 : void ScFormulaCell::Compile( const rtl::OUString& rFormula, bool bNoListening,
     963             :                             const FormulaGrammar::Grammar eGrammar )
     964             : {
     965         224 :     if ( pDocument->IsClipOrUndo() )
     966         224 :         return;
     967         224 :     bool bWasInFormulaTree = pDocument->IsInFormulaTree( this );
     968         224 :     if ( bWasInFormulaTree )
     969           0 :         pDocument->RemoveFromFormulaTree( this );
     970             :     // pCode may not deleted for queries, but must be empty
     971         224 :     if ( pCode )
     972           0 :         pCode->Clear();
     973         224 :     ScTokenArray* pCodeOld = pCode;
     974         224 :     ScCompiler aComp( pDocument, aPos);
     975         224 :     aComp.SetGrammar(eGrammar);
     976         224 :     pCode = aComp.CompileString( rFormula );
     977         224 :     if ( pCodeOld )
     978           0 :         delete pCodeOld;
     979         224 :     if( !pCode->GetCodeError() )
     980             :     {
     981         224 :         if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() && rFormula == rtl::OUString(aResult.GetHybridFormula()) )
     982             :         {   // not recursive CompileTokenArray/Compile/CompileTokenArray
     983           0 :             if ( rFormula[0] == '=' )
     984           0 :                 pCode->AddBad( rFormula.copy(1) );
     985             :             else
     986           0 :                 pCode->AddBad( rFormula );
     987             :         }
     988         224 :         bCompile = true;
     989         224 :         CompileTokenArray( bNoListening );
     990             :     }
     991             :     else
     992             :     {
     993           0 :         bChanged = true;
     994           0 :         SetTextWidth( TEXTWIDTH_DIRTY );
     995           0 :         SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
     996             :     }
     997         224 :     if ( bWasInFormulaTree )
     998           0 :         pDocument->PutInFormulaTree( this );
     999             : }
    1000             : 
    1001             : 
    1002         285 : void ScFormulaCell::CompileTokenArray( bool bNoListening )
    1003             : {
    1004             :     // Not already compiled?
    1005         285 :     if( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
    1006           0 :         Compile( aResult.GetHybridFormula(), bNoListening, eTempGrammar);
    1007         285 :     else if( bCompile && !pDocument->IsClipOrUndo() && !pCode->GetCodeError() )
    1008             :     {
    1009             :         // RPN length may get changed
    1010         230 :         bool bWasInFormulaTree = pDocument->IsInFormulaTree( this );
    1011         230 :         if ( bWasInFormulaTree )
    1012           0 :             pDocument->RemoveFromFormulaTree( this );
    1013             : 
    1014             :         // Loading from within filter? No listening yet!
    1015         230 :         if( pDocument->IsInsertingFromOtherDoc() )
    1016           4 :             bNoListening = true;
    1017             : 
    1018         230 :         if( !bNoListening && pCode->GetCodeLen() )
    1019           1 :             EndListeningTo( pDocument );
    1020         230 :         ScCompiler aComp(pDocument, aPos, *pCode);
    1021         230 :         aComp.SetGrammar(pDocument->GetGrammar());
    1022         230 :         bSubTotal = aComp.CompileTokenArray();
    1023         230 :         if( !pCode->GetCodeError() )
    1024             :         {
    1025         230 :             nFormatType = aComp.GetNumFormatType();
    1026         230 :             nFormatIndex = 0;
    1027         230 :             bChanged = true;
    1028         230 :             aResult.SetToken( NULL);
    1029         230 :             bCompile = false;
    1030         230 :             if ( !bNoListening )
    1031           1 :                 StartListeningTo( pDocument );
    1032             :         }
    1033         230 :         if ( bWasInFormulaTree )
    1034           0 :             pDocument->PutInFormulaTree( this );
    1035             : 
    1036         230 :         if (bSubTotal)
    1037           0 :             pDocument->AddSubTotalCell(this);
    1038             :     }
    1039         285 : }
    1040             : 
    1041             : 
    1042         404 : void ScFormulaCell::CompileXML( ScProgress& rProgress )
    1043             : {
    1044         404 :     if ( cMatrixFlag == MM_REFERENCE )
    1045             :     {   // is already token code via ScDocFunc::EnterMatrix, ScDocument::InsertMatrixFormula
    1046             :         // just establish listeners
    1047          45 :         StartListeningTo( pDocument );
    1048         404 :         return ;
    1049             :     }
    1050             : 
    1051         359 :     ScCompiler aComp( pDocument, aPos, *pCode);
    1052         359 :     aComp.SetGrammar(eTempGrammar);
    1053         359 :     rtl::OUString aFormula, aFormulaNmsp;
    1054         359 :     aComp.CreateStringFromXMLTokenArray( aFormula, aFormulaNmsp );
    1055         359 :     pDocument->DecXMLImportedFormulaCount( aFormula.getLength() );
    1056         359 :     rProgress.SetStateCountDownOnPercent( pDocument->GetXMLImportedFormulaCount() );
    1057             :     // pCode may not deleted for queries, but must be empty
    1058         359 :     if ( pCode )
    1059         359 :         pCode->Clear();
    1060         359 :     ScTokenArray* pCodeOld = pCode;
    1061         359 :     pCode = aComp.CompileString( aFormula, aFormulaNmsp );
    1062         359 :     delete pCodeOld;
    1063         359 :     if( !pCode->GetCodeError() )
    1064             :     {
    1065         359 :         if ( !pCode->GetLen() )
    1066             :         {
    1067           0 :             if ( aFormula[0] == '=' )
    1068           0 :                 pCode->AddBad( aFormula.copy( 1 ) );
    1069             :             else
    1070           0 :                 pCode->AddBad( aFormula );
    1071             :         }
    1072         359 :         bSubTotal = aComp.CompileTokenArray();
    1073         359 :         if( !pCode->GetCodeError() )
    1074             :         {
    1075         359 :             nFormatType = aComp.GetNumFormatType();
    1076         359 :             nFormatIndex = 0;
    1077         359 :             bChanged = true;
    1078         359 :             bCompile = false;
    1079         359 :             StartListeningTo( pDocument );
    1080             :         }
    1081             : 
    1082         359 :         if (bSubTotal)
    1083           0 :             pDocument->AddSubTotalCell(this);
    1084             :     }
    1085             :     else
    1086             :     {
    1087           0 :         bChanged = true;
    1088           0 :         SetTextWidth( TEXTWIDTH_DIRTY );
    1089           0 :         SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
    1090             :     }
    1091             : 
    1092             :     //  Same as in Load: after loading, it must be known if ocMacro is in any formula
    1093             :     //  (for macro warning, CompileXML is called at the end of loading XML file)
    1094         359 :     if ( !pDocument->GetHasMacroFunc() && pCode->HasOpCodeRPN( ocMacro ) )
    1095           0 :         pDocument->SetHasMacroFunc( true );
    1096             : 
    1097             :     //volatile cells must be added here for import
    1098        1043 :     if( pCode->IsRecalcModeAlways() || pCode->IsRecalcModeForced() ||
    1099         684 :         pCode->IsRecalcModeOnLoad() || pCode->IsRecalcModeOnLoadOnce() )
    1100             :     {
    1101             :         // During load, only those cells that are marked explicitly dirty get
    1102             :         // recalculated.  So we need to set it dirty here.
    1103          17 :         SetDirtyVar();
    1104          17 :         pDocument->PutInFormulaTree(this);
    1105         359 :     }
    1106             : }
    1107             : 
    1108             : 
    1109        2433 : void ScFormulaCell::CalcAfterLoad()
    1110             : {
    1111        2433 :     bool bNewCompiled = false;
    1112             :     // If a Calc 1.0-doc is read, we have a result, but no token array
    1113        2433 :     if( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
    1114             :     {
    1115           0 :         Compile( aResult.GetHybridFormula(), true, eTempGrammar);
    1116           0 :         aResult.SetToken( NULL);
    1117           0 :         bDirty = true;
    1118           0 :         bNewCompiled = true;
    1119             :     }
    1120             :     // The UPN array is not created when a Calc 3.0-Doc has been read as the Range Names exist until now.
    1121        2433 :     if( pCode->GetLen() && !pCode->GetCodeLen() && !pCode->GetCodeError() )
    1122             :     {
    1123           0 :         ScCompiler aComp(pDocument, aPos, *pCode);
    1124           0 :         aComp.SetGrammar(pDocument->GetGrammar());
    1125           0 :         bSubTotal = aComp.CompileTokenArray();
    1126           0 :         nFormatType = aComp.GetNumFormatType();
    1127           0 :         nFormatIndex = 0;
    1128           0 :         bDirty = true;
    1129           0 :         bCompile = false;
    1130           0 :         bNewCompiled = true;
    1131             : 
    1132           0 :         if (bSubTotal)
    1133           0 :             pDocument->AddSubTotalCell(this);
    1134             :     }
    1135             : 
    1136             :     // irgendwie koennen unter os/2 mit rotter FPU-Exception /0 ohne Err503 gespeichert
    1137             :     // werden, woraufhin spaeter im NumberFormatter die BLC Lib bei einem fabs(-NAN) abstuerzt
    1138             :     //(#32739#) hier fuer alle Systeme ausbuegeln, damit da auch Err503 steht
    1139             : 
    1140             :     // somehow we can under os / 2 store without Err503 with rotter FPU / 0, followed later
    1141             :     // in the BLC Lib NumberFormatter a fabs (NAN) is crashing (# 32739 #) iron out here for all
    1142             :     // the systems, so there is also Err503
    1143             : 
    1144        2433 :     if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
    1145             :     {
    1146             :         OSL_FAIL("Formelzelle INFINITY !!! Woher kommt das Dokument?");
    1147           0 :         aResult.SetResultError( errIllegalFPOperation );
    1148           0 :         bDirty = true;
    1149             :     }
    1150             :     // DoubleRefs bei binaeren Operatoren waren vor v5.0 immer Matrix,
    1151             :     // jetzt nur noch wenn in Matrixformel, sonst implizite Schnittmenge
    1152             : 
    1153             :     // Double Refs in binary operators were always in front of Matrix v5.0, now only when in an
    1154             :     // array formula, otherwise an implicit intersection
    1155        2433 :     if ( pDocument->GetSrcVersion() < SC_MATRIX_DOUBLEREF &&
    1156           0 :             GetMatrixFlag() == MM_NONE && pCode->HasMatrixDoubleRefOps() )
    1157             :     {
    1158           0 :         cMatrixFlag = MM_FORMULA;
    1159           0 :         SetMatColsRows( 1, 1);
    1160             :     }
    1161             : 
    1162             :     // Must the cells be calculated? After Load cells can contain an error code, and then start
    1163             :     // the listener and ggbf. Recalculate if not RECALCMODE_NORMAL
    1164             : 
    1165        2433 :     if( !bNewCompiled || !pCode->GetCodeError() )
    1166             :     {
    1167        2433 :         StartListeningTo( pDocument );
    1168        2433 :         if( !pCode->IsRecalcModeNormal() )
    1169           0 :             bDirty = true;
    1170             :     }
    1171        2433 :     if ( pCode->IsRecalcModeAlways() )
    1172             :     {   // zufall(), heute(), jetzt() bleiben immer im FormulaTree, damit sie
    1173             :         // auch bei jedem F9 berechnet werden.
    1174             : 
    1175             :         // accident(), today(), now() always stay in the FormulaTree, so that they
    1176             :         // can also be calculated for each F9.
    1177           0 :         bDirty = true;
    1178             :     }
    1179             :     // Noch kein SetDirty weil noch nicht alle Listener bekannt, erst in
    1180             :     // SetDirtyAfterLoad.
    1181             :     // Still no SetDirty because all Listeners are not know, first in SetDirtyAfterLoad.
    1182        2433 : }
    1183             : 
    1184             : 
    1185           0 : bool ScFormulaCell::MarkUsedExternalReferences()
    1186             : {
    1187           0 :     return pCode && pDocument->MarkUsedExternalReferences( *pCode);
    1188             : }
    1189             : 
    1190             : 
    1191        3078 : void ScFormulaCell::Interpret()
    1192             : {
    1193        3078 :     if (!IsDirtyOrInTableOpDirty() || pDocument->GetRecursionHelper().IsInReturn())
    1194          68 :         return;     // no double/triple processing
    1195             : 
    1196             :     //! HACK:
    1197             :     //  Wenn der Aufruf aus einem Reschedule im DdeLink-Update kommt, dirty stehenlassen
    1198             :     //  Besser: Dde-Link Update ohne Reschedule oder ganz asynchron !!!
    1199             : 
    1200             :     //  If the call comes from a Reschedule in the DdeLink-Update, dirty let stand
    1201             :     //  Better: Dde-Link Update without Reschdule or completely asynchronously !!!
    1202             : 
    1203        3010 :     if ( pDocument->IsInDdeLinkUpdate() )
    1204           0 :         return;
    1205             : 
    1206        3010 :     if (bRunning)
    1207             :     {
    1208           0 :         if (!pDocument->GetDocOptions().IsIter())
    1209             :         {
    1210           0 :             aResult.SetResultError( errCircularReference );
    1211           0 :             return;
    1212             :         }
    1213             : 
    1214           0 :         if (aResult.GetResultError() == errCircularReference)
    1215           0 :             aResult.SetResultError( 0 );
    1216             : 
    1217             :         // Start or add to iteration list.
    1218           0 :         if (!pDocument->GetRecursionHelper().IsDoingIteration() ||
    1219           0 :                 !pDocument->GetRecursionHelper().GetRecursionInIterationStack().top()->bIsIterCell)
    1220           0 :             pDocument->GetRecursionHelper().SetInIterationReturn( true);
    1221             : 
    1222           0 :         return;
    1223             :     }
    1224             :     // no multiple interprets for GetErrCode, IsValue, GetValue and
    1225             :     // different entry point recursions. Would also lead to premature
    1226             :     // convergence in iterations.
    1227        3010 :     if (pDocument->GetRecursionHelper().GetIteration() && nSeenInIteration ==
    1228           0 :             pDocument->GetRecursionHelper().GetIteration())
    1229           0 :         return ;
    1230             : 
    1231        3010 :     ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper();
    1232        3010 :     bool bOldRunning = bRunning;
    1233        3010 :     if (rRecursionHelper.GetRecursionCount() > MAXRECURSION)
    1234             :     {
    1235           0 :         bRunning = true;
    1236           0 :         rRecursionHelper.SetInRecursionReturn( true);
    1237             :     }
    1238             :     else
    1239             :     {
    1240        3010 :         InterpretTail( SCITP_NORMAL);
    1241             :     }
    1242             : 
    1243             :     // While leaving a recursion or iteration stack, insert its cells to the
    1244             :     // recursion list in reverse order.
    1245        3010 :     if (rRecursionHelper.IsInReturn())
    1246             :     {
    1247           0 :         if (rRecursionHelper.GetRecursionCount() > 0 ||
    1248           0 :                 !rRecursionHelper.IsDoingRecursion())
    1249           0 :             rRecursionHelper.Insert( this, bOldRunning, aResult);
    1250           0 :         bool bIterationFromRecursion = false;
    1251           0 :         bool bResumeIteration = false;
    1252           0 :         do
    1253             :         {
    1254           0 :             if ((rRecursionHelper.IsInIterationReturn() &&
    1255           0 :                         rRecursionHelper.GetRecursionCount() == 0 &&
    1256           0 :                         !rRecursionHelper.IsDoingIteration()) ||
    1257             :                     bIterationFromRecursion || bResumeIteration)
    1258             :             {
    1259           0 :                 ScFormulaCell* pIterCell = this; // scope for debug convenience
    1260           0 :                 bool & rDone = rRecursionHelper.GetConvergingReference();
    1261           0 :                 rDone = false;
    1262           0 :                 if (!bIterationFromRecursion && bResumeIteration)
    1263             :                 {
    1264           0 :                     bResumeIteration = false;
    1265             :                     // Resuming iteration expands the range.
    1266             :                     ScFormulaRecursionList::const_iterator aOldStart(
    1267           0 :                             rRecursionHelper.GetLastIterationStart());
    1268           0 :                     rRecursionHelper.ResumeIteration();
    1269             :                     // Mark new cells being in iteration.
    1270           0 :                     for (ScFormulaRecursionList::const_iterator aIter(
    1271           0 :                                 rRecursionHelper.GetIterationStart()); aIter !=
    1272             :                             aOldStart; ++aIter)
    1273             :                     {
    1274           0 :                         pIterCell = (*aIter).pCell;
    1275           0 :                         pIterCell->bIsIterCell = true;
    1276             :                     }
    1277             :                     // Mark older cells dirty again, in case they converted
    1278             :                     // without accounting for all remaining cells in the circle
    1279             :                     // that weren't touched so far, e.g. conditional. Restore
    1280             :                     // backuped result.
    1281           0 :                     sal_uInt16 nIteration = rRecursionHelper.GetIteration();
    1282           0 :                     for (ScFormulaRecursionList::const_iterator aIter(
    1283           0 :                                 aOldStart); aIter !=
    1284           0 :                             rRecursionHelper.GetIterationEnd(); ++aIter)
    1285             :                     {
    1286           0 :                         pIterCell = (*aIter).pCell;
    1287           0 :                         if (pIterCell->nSeenInIteration == nIteration)
    1288             :                         {
    1289           0 :                             if (!pIterCell->bDirty || aIter == aOldStart)
    1290             :                             {
    1291           0 :                                 pIterCell->aResult = (*aIter).aPreviousResult;
    1292             :                             }
    1293           0 :                             --pIterCell->nSeenInIteration;
    1294             :                         }
    1295           0 :                         pIterCell->bDirty = true;
    1296           0 :                     }
    1297             :                 }
    1298             :                 else
    1299             :                 {
    1300           0 :                     bResumeIteration = false;
    1301             :                     // Close circle once.
    1302           0 :                     rRecursionHelper.GetList().back().pCell->InterpretTail(
    1303           0 :                             SCITP_CLOSE_ITERATION_CIRCLE);
    1304             :                     // Start at 1, init things.
    1305           0 :                     rRecursionHelper.StartIteration();
    1306             :                     // Mark all cells being in iteration.
    1307           0 :                     for (ScFormulaRecursionList::const_iterator aIter(
    1308           0 :                                 rRecursionHelper.GetIterationStart()); aIter !=
    1309           0 :                             rRecursionHelper.GetIterationEnd(); ++aIter)
    1310             :                     {
    1311           0 :                         pIterCell = (*aIter).pCell;
    1312           0 :                         pIterCell->bIsIterCell = true;
    1313             :                     }
    1314             :                 }
    1315           0 :                 bIterationFromRecursion = false;
    1316           0 :                 sal_uInt16 nIterMax = pDocument->GetDocOptions().GetIterCount();
    1317           0 :                 for ( ; rRecursionHelper.GetIteration() <= nIterMax && !rDone;
    1318           0 :                         rRecursionHelper.IncIteration())
    1319             :                 {
    1320           0 :                     rDone = true;
    1321           0 :                     for ( ScFormulaRecursionList::iterator aIter(
    1322           0 :                                 rRecursionHelper.GetIterationStart()); aIter !=
    1323           0 :                             rRecursionHelper.GetIterationEnd() &&
    1324           0 :                             !rRecursionHelper.IsInReturn(); ++aIter)
    1325             :                     {
    1326           0 :                         pIterCell = (*aIter).pCell;
    1327           0 :                         if (pIterCell->IsDirtyOrInTableOpDirty() &&
    1328           0 :                                 rRecursionHelper.GetIteration() !=
    1329           0 :                                 pIterCell->GetSeenInIteration())
    1330             :                         {
    1331           0 :                             (*aIter).aPreviousResult = pIterCell->aResult;
    1332           0 :                             pIterCell->InterpretTail( SCITP_FROM_ITERATION);
    1333             :                         }
    1334           0 :                         rDone = rDone && !pIterCell->IsDirtyOrInTableOpDirty();
    1335             :                     }
    1336           0 :                     if (rRecursionHelper.IsInReturn())
    1337             :                     {
    1338           0 :                         bResumeIteration = true;
    1339           0 :                         break;  // for
    1340             :                         // Don't increment iteration.
    1341             :                     }
    1342             :                 }
    1343           0 :                 if (!bResumeIteration)
    1344             :                 {
    1345           0 :                     if (rDone)
    1346             :                     {
    1347           0 :                         for (ScFormulaRecursionList::const_iterator aIter(
    1348           0 :                                     rRecursionHelper.GetIterationStart());
    1349           0 :                                 aIter != rRecursionHelper.GetIterationEnd();
    1350             :                                 ++aIter)
    1351             :                         {
    1352           0 :                             pIterCell = (*aIter).pCell;
    1353           0 :                             pIterCell->bIsIterCell = false;
    1354           0 :                             pIterCell->nSeenInIteration = 0;
    1355           0 :                             pIterCell->bRunning = (*aIter).bOldRunning;
    1356             :                         }
    1357             :                     }
    1358             :                     else
    1359             :                     {
    1360           0 :                         for (ScFormulaRecursionList::const_iterator aIter(
    1361           0 :                                     rRecursionHelper.GetIterationStart());
    1362           0 :                                 aIter != rRecursionHelper.GetIterationEnd();
    1363             :                                 ++aIter)
    1364             :                         {
    1365           0 :                             pIterCell = (*aIter).pCell;
    1366           0 :                             pIterCell->bIsIterCell = false;
    1367           0 :                             pIterCell->nSeenInIteration = 0;
    1368           0 :                             pIterCell->bRunning = (*aIter).bOldRunning;
    1369             :                             // If one cell didn't converge, all cells of this
    1370             :                             // circular dependency don't, no matter whether
    1371             :                             // single cells did.
    1372           0 :                             pIterCell->bDirty = false;
    1373           0 :                             pIterCell->bTableOpDirty = false;
    1374           0 :                             pIterCell->aResult.SetResultError( errNoConvergence);
    1375           0 :                             pIterCell->bChanged = true;
    1376           0 :                             pIterCell->SetTextWidth( TEXTWIDTH_DIRTY);
    1377           0 :                             pIterCell->SetScriptType( SC_SCRIPTTYPE_UNKNOWN);
    1378             :                         }
    1379             :                     }
    1380             :                     // End this iteration and remove entries.
    1381           0 :                     rRecursionHelper.EndIteration();
    1382           0 :                     bResumeIteration = rRecursionHelper.IsDoingIteration();
    1383             :                 }
    1384             :             }
    1385           0 :             if (rRecursionHelper.IsInRecursionReturn() &&
    1386           0 :                     rRecursionHelper.GetRecursionCount() == 0 &&
    1387           0 :                     !rRecursionHelper.IsDoingRecursion())
    1388             :             {
    1389           0 :                 bIterationFromRecursion = false;
    1390             :                 // Iterate over cells known so far, start with the last cell
    1391             :                 // encountered, inserting new cells if another recursion limit
    1392             :                 // is reached. Repeat until solved.
    1393           0 :                 rRecursionHelper.SetDoingRecursion( true);
    1394           0 :                 do
    1395             :                 {
    1396           0 :                     rRecursionHelper.SetInRecursionReturn( false);
    1397           0 :                     for (ScFormulaRecursionList::const_iterator aIter(
    1398           0 :                                 rRecursionHelper.GetIterationStart());
    1399           0 :                             !rRecursionHelper.IsInReturn() && aIter !=
    1400           0 :                             rRecursionHelper.GetIterationEnd(); ++aIter)
    1401             :                     {
    1402           0 :                         ScFormulaCell* pCell = (*aIter).pCell;
    1403           0 :                         if (pCell->IsDirtyOrInTableOpDirty())
    1404             :                         {
    1405           0 :                             pCell->InterpretTail( SCITP_NORMAL);
    1406           0 :                             if (!pCell->IsDirtyOrInTableOpDirty() && !pCell->IsIterCell())
    1407           0 :                                 pCell->bRunning = (*aIter).bOldRunning;
    1408             :                         }
    1409             :                     }
    1410             :                 } while (rRecursionHelper.IsInRecursionReturn());
    1411           0 :                 rRecursionHelper.SetDoingRecursion( false);
    1412           0 :                 if (rRecursionHelper.IsInIterationReturn())
    1413             :                 {
    1414           0 :                     if (!bResumeIteration)
    1415           0 :                         bIterationFromRecursion = true;
    1416             :                 }
    1417           0 :                 else if (bResumeIteration ||
    1418           0 :                         rRecursionHelper.IsDoingIteration())
    1419           0 :                     rRecursionHelper.GetList().erase(
    1420             :                             rRecursionHelper.GetIterationStart(),
    1421           0 :                             rRecursionHelper.GetLastIterationStart());
    1422             :                 else
    1423           0 :                     rRecursionHelper.Clear();
    1424             :             }
    1425             :         } while (bIterationFromRecursion || bResumeIteration);
    1426             :     }
    1427             : }
    1428             : 
    1429        3010 : void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam )
    1430             : {
    1431             :     class RecursionCounter
    1432             :     {
    1433             :         ScRecursionHelper&  rRec;
    1434             :         bool                bStackedInIteration;
    1435             :         public:
    1436        3010 :         RecursionCounter( ScRecursionHelper& r, ScFormulaCell* p ) : rRec(r)
    1437             :         {
    1438        3010 :             bStackedInIteration = rRec.IsDoingIteration();
    1439        3010 :             if (bStackedInIteration)
    1440           0 :                 rRec.GetRecursionInIterationStack().push( p);
    1441        3010 :             rRec.IncRecursionCount();
    1442        3010 :         }
    1443        3010 :         ~RecursionCounter()
    1444             :         {
    1445        3010 :             rRec.DecRecursionCount();
    1446        3010 :             if (bStackedInIteration)
    1447           0 :                 rRec.GetRecursionInIterationStack().pop();
    1448        3010 :         }
    1449        3010 :     } aRecursionCounter( pDocument->GetRecursionHelper(), this);
    1450        3010 :     nSeenInIteration = pDocument->GetRecursionHelper().GetIteration();
    1451        3010 :     if( !pCode->GetCodeLen() && !pCode->GetCodeError() )
    1452             :     {
    1453             :         // #i11719# no UPN and no error and no token code but result string present
    1454             :         // => interpretation of this cell during name-compilation and unknown names
    1455             :         // => can't exchange underlying code array in CompileTokenArray() /
    1456             :         // Compile() because interpreter's token iterator would crash or pCode
    1457             :         // would be deleted twice if this cell was interpreted during
    1458             :         // compilation.
    1459             :         // This should only be a temporary condition and, since we set an
    1460             :         // error, if ran into it again we'd bump into the dirty-clearing
    1461             :         // condition further down.
    1462           0 :         if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
    1463             :         {
    1464           0 :             pCode->SetCodeError( errNoCode );
    1465             :             // This is worth an assertion; if encountered in daily work
    1466             :             // documents we might need another solution. Or just confirm correctness.
    1467             :             OSL_FAIL( "ScFormulaCell::Interpret: no UPN, no error, no token, but hybrid formula string" );
    1468             :             return;
    1469             :         }
    1470           0 :         CompileTokenArray();
    1471             :     }
    1472             : 
    1473        3010 :     if( pCode->GetCodeLen() && pDocument )
    1474             :     {
    1475             :         class StackCleaner
    1476             :         {
    1477             :             ScDocument*     pDoc;
    1478             :             ScInterpreter*  pInt;
    1479             :             public:
    1480        3010 :             StackCleaner( ScDocument* pD, ScInterpreter* pI )
    1481        3010 :                 : pDoc(pD), pInt(pI)
    1482        3010 :                 {}
    1483        3010 :             ~StackCleaner()
    1484             :             {
    1485        3010 :                 delete pInt;
    1486        3010 :                 pDoc->DecInterpretLevel();
    1487        3010 :             }
    1488             :         };
    1489        3010 :         pDocument->IncInterpretLevel();
    1490        3010 :         ScInterpreter* p = new ScInterpreter( this, pDocument, aPos, *pCode );
    1491        3010 :         StackCleaner aStackCleaner( pDocument, p);
    1492        3010 :         sal_uInt16 nOldErrCode = aResult.GetResultError();
    1493        3010 :         if ( nSeenInIteration == 0 )
    1494             :         {   // Only the first time
    1495             :             // With bChanged=false, if a newly compiled cell has a result of
    1496             :             // 0.0, no change is detected and the cell will not be repainted.
    1497             :             // bChanged = false;
    1498        3010 :             aResult.SetResultError( 0 );
    1499             :         }
    1500             : 
    1501        3010 :         switch ( aResult.GetResultError() )
    1502             :         {
    1503             :             case errCircularReference :     // will be determined again if so
    1504           0 :                 aResult.SetResultError( 0 );
    1505           0 :             break;
    1506             :         }
    1507             : 
    1508        3010 :         bool bOldRunning = bRunning;
    1509        3010 :         bRunning = true;
    1510        3010 :         p->Interpret();
    1511        3010 :         if (pDocument->GetRecursionHelper().IsInReturn() && eTailParam != SCITP_CLOSE_ITERATION_CIRCLE)
    1512             :         {
    1513           0 :             if (nSeenInIteration > 0)
    1514           0 :                 --nSeenInIteration;     // retry when iteration is resumed
    1515             :             return;
    1516             :         }
    1517        3010 :         bRunning = bOldRunning;
    1518             : 
    1519             :         // #i102616# For single-sheet saving consider only content changes, not format type,
    1520             :         // because format type isn't set on loading (might be changed later)
    1521        3010 :         bool bContentChanged = false;
    1522             : 
    1523             :         // Do not create a HyperLink() cell if the formula results in an error.
    1524        3010 :         if( p->GetError() && pCode->IsHyperLink())
    1525           0 :             pCode->SetHyperLink(false);
    1526             : 
    1527        3010 :         if( p->GetError() && p->GetError() != errCircularReference)
    1528             :         {
    1529          62 :             bDirty = false;
    1530          62 :             bTableOpDirty = false;
    1531          62 :             bChanged = true;
    1532             :         }
    1533        3010 :         if (eTailParam == SCITP_FROM_ITERATION && IsDirtyOrInTableOpDirty())
    1534             :         {
    1535           0 :             bool bIsValue = aResult.IsValue();  // the previous type
    1536             :             // Did it converge?
    1537           0 :             if ((bIsValue && p->GetResultType() == svDouble && fabs(
    1538           0 :                             p->GetNumResult() - aResult.GetDouble()) <=
    1539           0 :                         pDocument->GetDocOptions().GetIterEps()) ||
    1540           0 :                     (!bIsValue && p->GetResultType() == svString &&
    1541           0 :                      p->GetStringResult() == aResult.GetString()))
    1542             :             {
    1543             :                 // A convergence in the first iteration doesn't necessarily
    1544             :                 // mean that it's done, it may be because not all related cells
    1545             :                 // of a circle changed their values yet. If the set really
    1546             :                 // converges it will do so also during the next iteration. This
    1547             :                 // fixes situations like of #i44115#. If this wasn't wanted an
    1548             :                 // initial "uncalculated" value would be needed for all cells
    1549             :                 // of a circular dependency => graph needed before calculation.
    1550           0 :                 if (nSeenInIteration > 1 ||
    1551           0 :                         pDocument->GetDocOptions().GetIterCount() == 1)
    1552             :                 {
    1553           0 :                     bDirty = false;
    1554           0 :                     bTableOpDirty = false;
    1555             :                 }
    1556             :             }
    1557             :         }
    1558             : 
    1559             :         // New error code?
    1560        3010 :         if( p->GetError() != nOldErrCode )
    1561             :         {
    1562          43 :             bChanged = true;
    1563             :             // bContentChanged only has to be set if the file content would be changed
    1564          43 :             if ( aResult.GetCellResultType() != svUnknown )
    1565          33 :                 bContentChanged = true;
    1566             :         }
    1567             :         // Different number format?
    1568        3010 :         if( nFormatType != p->GetRetFormatType() )
    1569             :         {
    1570          78 :             nFormatType = p->GetRetFormatType();
    1571          78 :             bChanged = true;
    1572             :         }
    1573        3010 :         if( nFormatIndex != p->GetRetFormatIndex() )
    1574             :         {
    1575           0 :             nFormatIndex = p->GetRetFormatIndex();
    1576           0 :             bChanged = true;
    1577             :         }
    1578             : 
    1579             :         // In case of changes just obtain the result, no temporary and
    1580             :         // comparison needed anymore.
    1581        3010 :         if (bChanged)
    1582             :         {
    1583             :             // #i102616# Compare anyway if the sheet is still marked unchanged for single-sheet saving
    1584             :             // Also handle special cases of initial results after loading.
    1585             : 
    1586         689 :             if ( !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
    1587             :             {
    1588         111 :                 ScFormulaResult aNewResult( p->GetResultToken().get());
    1589         111 :                 StackVar eOld = aResult.GetCellResultType();
    1590         111 :                 StackVar eNew = aNewResult.GetCellResultType();
    1591         111 :                 if ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) )
    1592             :                 {
    1593             :                     // ScXMLTableRowCellContext::EndElement doesn't call SetFormulaResultDouble for 0
    1594             :                     // -> no change
    1595             :                 }
    1596             :                 else
    1597             :                 {
    1598         111 :                     if ( eOld == svHybridCell )     // string result from SetFormulaResultString?
    1599          13 :                         eOld = svString;            // ScHybridCellToken has a valid GetString method
    1600             : 
    1601             :                     // #i106045# use approxEqual to compare with stored value
    1602             :                     bContentChanged = (eOld != eNew ||
    1603          97 :                             (eNew == svDouble && !rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() )) ||
    1604         208 :                             (eNew == svString && aResult.GetString() != aNewResult.GetString()));
    1605         111 :                 }
    1606             :             }
    1607             : 
    1608         689 :             aResult.SetToken( p->GetResultToken().get() );
    1609             :         }
    1610             :         else
    1611             :         {
    1612        2321 :             ScFormulaResult aNewResult( p->GetResultToken().get());
    1613        2321 :             StackVar eOld = aResult.GetCellResultType();
    1614        2321 :             StackVar eNew = aNewResult.GetCellResultType();
    1615             :             bChanged = (eOld != eNew ||
    1616        2293 :                     (eNew == svDouble && aResult.GetDouble() != aNewResult.GetDouble()) ||
    1617        4614 :                     (eNew == svString && aResult.GetString() != aNewResult.GetString()));
    1618             : 
    1619             :             // #i102616# handle special cases of initial results after loading (only if the sheet is still marked unchanged)
    1620        2321 :             if ( bChanged && !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
    1621             :             {
    1622           0 :                 if ( ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) ) ||
    1623           0 :                      ( eOld == svHybridCell && eNew == svString && aResult.GetString() == aNewResult.GetString() ) ||
    1624           0 :                      ( eOld == svDouble && eNew == svDouble && rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() ) ) )
    1625             :                 {
    1626             :                     // no change, see above
    1627             :                 }
    1628             :                 else
    1629           0 :                     bContentChanged = true;
    1630             :             }
    1631             : 
    1632        2321 :             aResult.Assign( aNewResult);
    1633             :         }
    1634             : 
    1635             :         // Precision as shown?
    1636        5903 :         if ( aResult.IsValue() && !p->GetError()
    1637        2893 :           && pDocument->GetDocOptions().IsCalcAsShown()
    1638             :           && nFormatType != NUMBERFORMAT_DATE
    1639             :           && nFormatType != NUMBERFORMAT_TIME
    1640             :           && nFormatType != NUMBERFORMAT_DATETIME )
    1641             :         {
    1642           0 :             sal_uLong nFormat = pDocument->GetNumberFormat( aPos );
    1643           0 :             if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
    1644           0 :                 nFormat = nFormatIndex;
    1645           0 :             if ( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
    1646             :                 nFormat = ScGlobal::GetStandardFormat(
    1647           0 :                     *pDocument->GetFormatTable(), nFormat, nFormatType );
    1648             :             aResult.SetDouble( pDocument->RoundValueAsShown(
    1649           0 :                         aResult.GetDouble(), nFormat));
    1650             :         }
    1651        3010 :         if (eTailParam == SCITP_NORMAL)
    1652             :         {
    1653        3010 :             bDirty = false;
    1654        3010 :             bTableOpDirty = false;
    1655             :         }
    1656        3010 :         if( aResult.GetMatrix() )
    1657             :         {
    1658             :             // If the formula wasn't entered as a matrix formula, live on with
    1659             :             // the upper left corner and let reference counting delete the matrix.
    1660          12 :             if( cMatrixFlag != MM_FORMULA && !pCode->IsHyperLink() )
    1661           3 :                 aResult.SetToken( aResult.GetCellResultToken().get());
    1662             :         }
    1663        3010 :         if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
    1664             :         {
    1665             :             // Coded double error may occur via filter import.
    1666           0 :             sal_uInt16 nErr = GetDoubleErrorValue( aResult.GetDouble());
    1667           0 :             aResult.SetResultError( nErr);
    1668           0 :             bChanged = bContentChanged = true;
    1669             :         }
    1670        3010 :         if( bChanged )
    1671             :         {
    1672         767 :             SetTextWidth( TEXTWIDTH_DIRTY );
    1673         767 :             SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
    1674             :         }
    1675        3010 :         if (bContentChanged && pDocument->IsStreamValid(aPos.Tab()))
    1676             :         {
    1677             :             // pass bIgnoreLock=true, because even if called from pending row height update,
    1678             :             // a changed result must still reset the stream flag
    1679           6 :             pDocument->SetStreamValid(aPos.Tab(), false, true);
    1680             :         }
    1681        3010 :         if ( !pCode->IsRecalcModeAlways() )
    1682        2966 :             pDocument->RemoveFromFormulaTree( this );
    1683             : 
    1684             :     //  FORCED cells also immediately tested for validity (start macro possibly)
    1685             : 
    1686        3010 :         if ( pCode->IsRecalcModeForced() )
    1687             :         {
    1688             :             sal_uLong nValidation = ((const SfxUInt32Item*) pDocument->GetAttr(
    1689           0 :                     aPos.Col(), aPos.Row(), aPos.Tab(), ATTR_VALIDDATA ))->GetValue();
    1690           0 :             if ( nValidation )
    1691             :             {
    1692           0 :                 const ScValidationData* pData = pDocument->GetValidationEntry( nValidation );
    1693           0 :                 if ( pData && !pData->IsDataValid( this, aPos ) )
    1694           0 :                     pData->DoCalcError( this );
    1695             :             }
    1696             :         }
    1697             : 
    1698             :         // Reschedule verlangsamt das ganze erheblich, nur bei Prozentaenderung ausfuehren
    1699             :         ScProgress::GetInterpretProgress()->SetStateCountDownOnPercent(
    1700        3010 :             pDocument->GetFormulaCodeInTree()/MIN_NO_CODES_PER_PROGRESS_UPDATE );
    1701             : 
    1702        3010 :         switch (p->GetVolatileType())
    1703             :         {
    1704             :             case ScInterpreter::VOLATILE:
    1705             :                 // Volatile via built-in volatile functions.  No actions needed.
    1706          44 :             break;
    1707             :             case ScInterpreter::VOLATILE_MACRO:
    1708             :                 // The formula contains a volatile macro.
    1709           0 :                 pCode->SetRecalcModeAlways();
    1710           0 :                 pDocument->PutInFormulaTree(this);
    1711           0 :                 StartListeningTo(pDocument);
    1712           0 :             break;
    1713             :             case ScInterpreter::NOT_VOLATILE:
    1714        2966 :                 if (pCode->IsRecalcModeAlways())
    1715             :                 {
    1716             :                     // The formula was previously volatile, but no more.
    1717           0 :                     EndListeningTo(pDocument);
    1718           0 :                     pCode->SetRecalcModeNormal();
    1719             :                 }
    1720             :                 else
    1721             :                 {
    1722             :                     // non-volatile formula.  End listening to the area in case
    1723             :                     // it's listening due to macro module change.
    1724        2966 :                     pDocument->EndListeningArea(BCA_LISTEN_ALWAYS, this);
    1725             :                 }
    1726        2966 :                 pDocument->RemoveFromFormulaTree(this);
    1727        2966 :             break;
    1728             :             default:
    1729             :                 ;
    1730        3010 :         }
    1731             :     }
    1732             :     else
    1733             :     {
    1734             :     //  Cells with compiler errors should not be marked dirty forever
    1735             :         OSL_ENSURE( pCode->GetCodeError(), "no UPN-Code und no errors ?!?!" );
    1736           0 :         bDirty = false;
    1737           0 :         bTableOpDirty = false;
    1738        3010 :     }
    1739             : }
    1740             : 
    1741             : 
    1742          28 : void ScFormulaCell::SetMatColsRows( SCCOL nCols, SCROW nRows, bool bDirtyFlag )
    1743             : {
    1744          28 :     ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellTokenNonConst();
    1745          28 :     if (pMat)
    1746           0 :         pMat->SetMatColsRows( nCols, nRows );
    1747          28 :     else if (nCols || nRows)
    1748             :     {
    1749          28 :         aResult.SetToken( new ScMatrixFormulaCellToken( nCols, nRows));
    1750             :         // Setting the new token actually forces an empty result at this top
    1751             :         // left cell, so have that recalculated.
    1752          28 :         SetDirty( bDirtyFlag );
    1753             :     }
    1754          28 : }
    1755             : 
    1756             : 
    1757           2 : void ScFormulaCell::GetMatColsRows( SCCOL & nCols, SCROW & nRows ) const
    1758             : {
    1759           2 :     const ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellToken();
    1760           2 :     if (pMat)
    1761           2 :         pMat->GetMatColsRows( nCols, nRows);
    1762             :     else
    1763             :     {
    1764           0 :         nCols = 0;
    1765           0 :         nRows = 0;
    1766             :     }
    1767           2 : }
    1768             : 
    1769             : 
    1770         364 : sal_uLong ScFormulaCell::GetStandardFormat( SvNumberFormatter& rFormatter, sal_uLong nFormat ) const
    1771             : {
    1772         364 :     if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
    1773           0 :         return nFormatIndex;
    1774             :     //! not ScFormulaCell::IsValue(), that could reinterpret the formula again.
    1775         364 :     if ( aResult.IsValue() )
    1776         296 :         return ScGlobal::GetStandardFormat( aResult.GetDouble(), rFormatter, nFormat, nFormatType );
    1777             :     else
    1778          68 :         return ScGlobal::GetStandardFormat( rFormatter, nFormat, nFormatType );
    1779             : }
    1780             : 
    1781             : 
    1782        3220 : void ScFormulaCell::Notify( SvtBroadcaster&, const SfxHint& rHint)
    1783             : {
    1784        3220 :     if ( !pDocument->IsInDtorClear() && !pDocument->GetHardRecalcState() )
    1785             :     {
    1786         426 :         const ScHint* p = PTR_CAST( ScHint, &rHint );
    1787         426 :         sal_uLong nHint = (p ? p->GetId() : 0);
    1788         426 :         if (nHint & (SC_HINT_DATACHANGED | SC_HINT_DYING | SC_HINT_TABLEOPDIRTY))
    1789             :         {
    1790         425 :             bool bForceTrack = false;
    1791         425 :             if ( nHint & SC_HINT_TABLEOPDIRTY )
    1792             :             {
    1793           0 :                 bForceTrack = !bTableOpDirty;
    1794           0 :                 if ( !bTableOpDirty )
    1795             :                 {
    1796           0 :                     pDocument->AddTableOpFormulaCell( this );
    1797           0 :                     bTableOpDirty = true;
    1798             :                 }
    1799             :             }
    1800             :             else
    1801             :             {
    1802         425 :                 bForceTrack = !bDirty;
    1803         425 :                 SetDirtyVar();
    1804             :             }
    1805             :             // Don't remove from FormulaTree to put in FormulaTrack to
    1806             :             // put in FormulaTree again and again, only if necessary.
    1807             :             // Any other means except RECALCMODE_ALWAYS by which a cell could
    1808             :             // be in FormulaTree if it would notify other cells through
    1809             :             // FormulaTrack which weren't in FormulaTrack/FormulaTree before?!?
    1810             :             // Yes. The new TableOpDirty made it necessary to have a
    1811             :             // forced mode where formulas may still be in FormulaTree from
    1812             :             // TableOpDirty but have to notify dependents for normal dirty.
    1813         850 :             if ( (bForceTrack || !pDocument->IsInFormulaTree( this )
    1814         298 :                     || pCode->IsRecalcModeAlways())
    1815         127 :                     && !pDocument->IsInFormulaTrack( this ) )
    1816         125 :                 pDocument->AppendToFormulaTrack( this );
    1817             :         }
    1818             :     }
    1819        3220 : }
    1820             : 
    1821         272 : void ScFormulaCell::SetDirty( bool bDirtyFlag )
    1822             : {
    1823         272 :     if ( !IsInChangeTrack() )
    1824             :     {
    1825         272 :         if ( pDocument->GetHardRecalcState() )
    1826           0 :             SetDirtyVar();
    1827             :         else
    1828             :         {
    1829             :             // Mehrfach-FormulaTracking in Load und in CompileAll
    1830             :             // nach CopyScenario und CopyBlockFromClip vermeiden.
    1831             :             // Wenn unbedingtes FormulaTracking noetig, vor SetDirty bDirty=false
    1832             :             // setzen, z.B. in CompileTokenArray
    1833             : 
    1834             :             // Multiple Formulas avoid tracking in Load and Copy compileAll
    1835             :             // by Scenario and Copy Block From Clip.
    1836             :             // If unconditional required Formula tracking is set before SetDirty
    1837             :             // bDirty = false, eg in CompileTokenArray
    1838         272 :             if ( !bDirty || !pDocument->IsInFormulaTree( this ) )
    1839             :             {
    1840         269 :                 if( bDirtyFlag )
    1841         244 :                     SetDirtyVar();
    1842         269 :                 pDocument->AppendToFormulaTrack( this );
    1843         269 :                 pDocument->TrackFormulas();
    1844             :             }
    1845             :         }
    1846             : 
    1847         272 :         if (pDocument->IsStreamValid(aPos.Tab()))
    1848           0 :             pDocument->SetStreamValid(aPos.Tab(), false);
    1849             :     }
    1850         272 : }
    1851             : 
    1852        1308 : void ScFormulaCell::SetDirtyVar()
    1853             : {
    1854        1308 :     bDirty = true;
    1855             :     // mark the sheet of this cell to be calculated
    1856             :     //#FIXME do we need to revert this remnant of old fake vba events? pDocument->AddCalculateTable( aPos.Tab() );
    1857        1308 : }
    1858             : 
    1859        2433 : void ScFormulaCell::SetDirtyAfterLoad()
    1860             : {
    1861        2433 :     bDirty = true;
    1862        2433 :     if ( !pDocument->GetHardRecalcState() )
    1863        2433 :         pDocument->PutInFormulaTree( this );
    1864        2433 : }
    1865             : 
    1866           0 : void ScFormulaCell::SetTableOpDirty()
    1867             : {
    1868           0 :     if ( !IsInChangeTrack() )
    1869             :     {
    1870           0 :         if ( pDocument->GetHardRecalcState() )
    1871           0 :             bTableOpDirty = true;
    1872             :         else
    1873             :         {
    1874           0 :             if ( !bTableOpDirty || !pDocument->IsInFormulaTree( this ) )
    1875             :             {
    1876           0 :                 if ( !bTableOpDirty )
    1877             :                 {
    1878           0 :                     pDocument->AddTableOpFormulaCell( this );
    1879           0 :                     bTableOpDirty = true;
    1880             :                 }
    1881           0 :                 pDocument->AppendToFormulaTrack( this );
    1882           0 :                 pDocument->TrackFormulas( SC_HINT_TABLEOPDIRTY );
    1883             :             }
    1884             :         }
    1885             :     }
    1886           0 : }
    1887             : 
    1888             : 
    1889       14174 : bool ScFormulaCell::IsDirtyOrInTableOpDirty() const
    1890             : {
    1891       14174 :     return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp());
    1892             : }
    1893             : 
    1894             : 
    1895           1 : void ScFormulaCell::SetErrCode( sal_uInt16 n )
    1896             : {
    1897             :     /* FIXME: check the numerous places where ScTokenArray::GetCodeError() is
    1898             :      * used whether it is solely for transport of a simple result error and get
    1899             :      * rid of that abuse. */
    1900           1 :     pCode->SetCodeError( n );
    1901             :     // Hard set errors are transported as result type value per convention,
    1902             :     // e.g. via clipboard. ScFormulaResult::IsValue() and
    1903             :     // ScFormulaResult::GetDouble() handle that.
    1904           1 :     aResult.SetResultError( n );
    1905           1 : }
    1906             : 
    1907          20 : void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits )
    1908             : {
    1909          20 :     if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL )
    1910          20 :         bDirty = true;
    1911          20 :     if ( nBits & RECALCMODE_ONLOAD_ONCE )
    1912             :     {   // OnLoadOnce nur zum Dirty setzen nach Filter-Import
    1913          20 :         nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL;
    1914             :     }
    1915          20 :     pCode->AddRecalcMode( nBits );
    1916          20 : }
    1917             : 
    1918             : // Dynamically create the URLField on a mouse-over action on a hyperlink() cell.
    1919           0 : void ScFormulaCell::GetURLResult( rtl::OUString& rURL, rtl::OUString& rCellText )
    1920             : {
    1921           0 :     rtl::OUString aCellString;
    1922             : 
    1923             :     Color* pColor;
    1924             : 
    1925             :     // Cell Text uses the Cell format while the URL uses
    1926             :     // the default format for the type.
    1927           0 :     sal_uLong nCellFormat = pDocument->GetNumberFormat( aPos );
    1928           0 :     SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
    1929             : 
    1930           0 :     if ( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
    1931           0 :         nCellFormat = GetStandardFormat( *pFormatter,nCellFormat );
    1932             : 
    1933           0 :    sal_uLong nURLFormat = ScGlobal::GetStandardFormat( *pFormatter,nCellFormat, NUMBERFORMAT_NUMBER);
    1934             : 
    1935           0 :     if ( IsValue() )
    1936             :     {
    1937           0 :         double fValue = GetValue();
    1938           0 :         pFormatter->GetOutputString( fValue, nCellFormat, rCellText, &pColor );
    1939             :     }
    1940             :     else
    1941             :     {
    1942           0 :         aCellString = GetString();
    1943           0 :         pFormatter->GetOutputString( aCellString, nCellFormat, rCellText, &pColor );
    1944             :     }
    1945           0 :     ScConstMatrixRef xMat( aResult.GetMatrix());
    1946           0 :     if (xMat)
    1947             :     {
    1948             :         // determine if the matrix result is a string or value.
    1949           0 :         if (!xMat->IsValue(0, 1))
    1950           0 :             rURL = xMat->GetString(0, 1);
    1951             :         else
    1952             :             pFormatter->GetOutputString(
    1953           0 :                 xMat->GetDouble(0, 1), nURLFormat, rURL, &pColor);
    1954             :     }
    1955             : 
    1956           0 :     if(rURL.isEmpty())
    1957             :     {
    1958           0 :         if(IsValue())
    1959           0 :             pFormatter->GetOutputString( GetValue(), nURLFormat, rURL, &pColor );
    1960             :         else
    1961           0 :             pFormatter->GetOutputString( aCellString, nURLFormat, rURL, &pColor );
    1962           0 :     }
    1963           0 : }
    1964             : 
    1965          13 : bool ScFormulaCell::IsMultilineResult()
    1966             : {
    1967          13 :     if (!IsValue())
    1968           0 :         return aResult.IsMultiline();
    1969          13 :     return false;
    1970             : }
    1971             : 
    1972       11054 : void ScFormulaCell::MaybeInterpret()
    1973             : {
    1974       11054 :     if (!IsDirtyOrInTableOpDirty())
    1975       19681 :         return;
    1976             : 
    1977        2427 :     if (pDocument->GetAutoCalc() || (cMatrixFlag != MM_NONE))
    1978        2411 :         Interpret();
    1979             : }
    1980             : 
    1981           0 : EditTextObject* ScFormulaCell::CreateURLObject()
    1982             : {
    1983           0 :     rtl::OUString aCellText;
    1984           0 :     rtl::OUString aURL;
    1985           0 :     GetURLResult( aURL, aCellText );
    1986             : 
    1987           0 :     SvxURLField aUrlField( aURL, aCellText, SVXURLFORMAT_APPDEFAULT);
    1988           0 :     EditEngine& rEE = pDocument->GetEditEngine();
    1989           0 :     rEE.SetText( EMPTY_STRING );
    1990           0 :     rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection( 0xFFFF, 0xFFFF ) );
    1991             : 
    1992           0 :     return rEE.CreateTextObject();
    1993             : }
    1994             : 
    1995             : // ============================================================================
    1996             : 
    1997           4 : ScDetectiveRefIter::ScDetectiveRefIter( ScFormulaCell* pCell )
    1998             : {
    1999           4 :     pCode = pCell->GetCode();
    2000           4 :     pCode->Reset();
    2001           4 :     aPos = pCell->aPos;
    2002           4 : }
    2003             : 
    2004           8 : static bool lcl_ScDetectiveRefIter_SkipRef( ScToken* p )
    2005             : {
    2006           8 :     ScSingleRefData& rRef1 = p->GetSingleRef();
    2007          16 :     if ( rRef1.IsColDeleted() || rRef1.IsRowDeleted() || rRef1.IsTabDeleted()
    2008           8 :             || !rRef1.Valid() )
    2009           0 :         return true;
    2010           8 :     if ( p->GetType() == svDoubleRef || p->GetType() == svExternalDoubleRef )
    2011             :     {
    2012           0 :         ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
    2013           0 :         if ( rRef2.IsColDeleted() || rRef2.IsRowDeleted() || rRef2.IsTabDeleted()
    2014           0 :                 || !rRef2.Valid() )
    2015           0 :             return true;
    2016             :     }
    2017           8 :     return false;
    2018             : }
    2019             : 
    2020           0 : bool ScDetectiveRefIter::GetNextRef( ScRange& rRange )
    2021             : {
    2022           0 :     bool bRet = false;
    2023           0 :     ScToken* p = GetNextRefToken();
    2024           0 :     if( p )
    2025             :     {
    2026           0 :         SingleDoubleRefProvider aProv( *p );
    2027           0 :         rRange.aStart.Set( aProv.Ref1.nCol, aProv.Ref1.nRow, aProv.Ref1.nTab );
    2028           0 :         rRange.aEnd.Set( aProv.Ref2.nCol, aProv.Ref2.nRow, aProv.Ref2.nTab );
    2029           0 :         bRet = true;
    2030             :     }
    2031             : 
    2032           0 :     return bRet;
    2033             : }
    2034             : 
    2035          12 : ScToken* ScDetectiveRefIter::GetNextRefToken()
    2036             : {
    2037          12 :     ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
    2038          12 :     if (p)
    2039           8 :         p->CalcAbsIfRel( aPos );
    2040             : 
    2041          24 :     while ( p && lcl_ScDetectiveRefIter_SkipRef( p ) )
    2042             :     {
    2043           0 :         p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
    2044           0 :         if (p)
    2045           0 :             p->CalcAbsIfRel( aPos );
    2046             :     }
    2047          12 :     return p;
    2048          15 : }
    2049             : 
    2050             : // ============================================================================
    2051             : 
    2052             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10