diff options
Diffstat (limited to 'binfilter/bf_sc/source/core/data/sc_cell.cxx')
-rw-r--r-- | binfilter/bf_sc/source/core/data/sc_cell.cxx | 1611 |
1 files changed, 1611 insertions, 0 deletions
diff --git a/binfilter/bf_sc/source/core/data/sc_cell.cxx b/binfilter/bf_sc/source/core/data/sc_cell.cxx new file mode 100644 index 000000000000..99ed87c7904e --- /dev/null +++ b/binfilter/bf_sc/source/core/data/sc_cell.cxx @@ -0,0 +1,1611 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifdef _MSC_VER +#pragma hdrstop +#endif + +// INCLUDE --------------------------------------------------------------- + +#ifdef MAC + // StackSpace +#include <mac_start.h> +#include <Memory.h> +#include <fp.h> +#include <mac_end.h> +#endif + +#if defined (SOLARIS) || defined (FREEBSD) || defined (OPENBSD) +#include <ieeefp.h> +#elif ( defined ( LINUX ) && ( GLIBC < 2 ) ) +#include <i386/ieeefp.h> +#endif + +#include <bf_svtools/zforlist.hxx> +#include <float.h> // _finite + +#include "interpre.hxx" +#include "scmatrix.hxx" +#include "docoptio.hxx" +#include "rechead.hxx" +#include "rangenam.hxx" +#include "progress.hxx" +#include "bclist.hxx" +namespace binfilter { + +// jetzt fuer alle Systeme niedriger Wert, Rest wird per FormulaTree ausgebuegelt, +// falls wirklich eine tiefe Rekursion ist, geht das schneller, als zu versuchen +// und dann doch nicht zu schaffen.. +#define SIMPLEMAXRECURSION +#ifdef SIMPLEMAXRECURSION + #define MAXRECURSION 50 +#else +#if defined( WIN ) || defined( OS2 ) + #define MAXRECURSION 50 +#elif defined( MAC ) + // wird per StackSpace() ermittelt +#else + #define MAXRECURSION 1000 +#endif +#endif + +// STATIC DATA ----------------------------------------------------------- + +#ifdef USE_MEMPOOL +// MemPools auf 4k Boundaries - 64 Bytes ausrichten +/*N*/ const USHORT nMemPoolValueCell = (0x8000 - 64) / sizeof(ScValueCell); +/*N*/ const USHORT nMemPoolFormulaCell = (0x8000 - 64) / sizeof(ScFormulaCell); +/*N*/ const USHORT nMemPoolStringCell = (0x4000 - 64) / sizeof(ScStringCell); +/*N*/ const USHORT nMemPoolNoteCell = (0x1000 - 64) / sizeof(ScNoteCell); +/*N*/ IMPL_FIXEDMEMPOOL_NEWDEL( ScValueCell, nMemPoolValueCell, nMemPoolValueCell ) +/*N*/ IMPL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell, nMemPoolFormulaCell, nMemPoolFormulaCell ) +/*N*/ IMPL_FIXEDMEMPOOL_NEWDEL( ScStringCell, nMemPoolStringCell, nMemPoolStringCell ) +/*N*/ IMPL_FIXEDMEMPOOL_NEWDEL( ScNoteCell, nMemPoolNoteCell, nMemPoolNoteCell ) +#endif + +#ifdef _MSC_VER +#pragma code_seg() +#endif + +INT8 ScFormulaCell::nIterMode = 0; + +#ifdef DBG_UTIL +static const sal_Char __FAR_DATA msgDbgInfinity[] = + "Formelzelle INFINITY ohne Err503 !!! (os/2?)\n" + "NICHTS anruehren und ER bescheid sagen!"; +#endif + +// ----------------------------------------------------------------------- + +DECLARE_LIST (ScFormulaCellList, ScFormulaCell*)//STRIP008 ; + + +/*N*/ ScBaseCell* ScBaseCell::Clone(ScDocument* pDoc) const +/*N*/ { +/*N*/ switch (eCellType) +/*N*/ { +/*N*/ case CELLTYPE_VALUE: +/*N*/ return new ScValueCell(*(const ScValueCell*)this); +/*N*/ case CELLTYPE_STRING: +/*N*/ return new ScStringCell(*(const ScStringCell*)this); +/*N*/ case CELLTYPE_EDIT: +/*N*/ return new ScEditCell(*(const ScEditCell*)this, pDoc); +/*N*/ case CELLTYPE_FORMULA: +/*N*/ return new ScFormulaCell(pDoc, ((ScFormulaCell*)this)->aPos, +/*N*/ *(const ScFormulaCell*)this); +/*N*/ case CELLTYPE_NOTE: +/*N*/ return new ScNoteCell(*(const ScNoteCell*)this); +/*N*/ default: +/*N*/ DBG_ERROR("Unbekannter Zellentyp"); +/*N*/ return NULL; +/*N*/ } +/*N*/ } + +/*N*/ ScBaseCell::~ScBaseCell() +/*N*/ { +/*N*/ delete pNote; +/*N*/ delete pBroadcaster; +/*N*/ DBG_ASSERT( eCellType == CELLTYPE_DESTROYED, "BaseCell Destructor" ); +/*N*/ } + +/*N*/ void ScBaseCell::Delete() +/*N*/ { +/*N*/ DELETEZ(pNote); +/*N*/ switch (eCellType) +/*N*/ { +/*N*/ case CELLTYPE_VALUE: +/*N*/ delete (ScValueCell*) this; +/*N*/ break; +/*N*/ case CELLTYPE_STRING: +/*N*/ delete (ScStringCell*) this; +/*N*/ break; +/*N*/ case CELLTYPE_EDIT: +/*N*/ delete (ScEditCell*) this; +/*N*/ break; +/*N*/ case CELLTYPE_FORMULA: +/*N*/ delete (ScFormulaCell*) this; +/*N*/ break; +/*N*/ case CELLTYPE_NOTE: +/*N*/ delete (ScNoteCell*) this; +/*N*/ break; +/*N*/ default: +/*N*/ DBG_ERROR("Unbekannter Zellentyp"); +/*N*/ break; +/*N*/ } +/*N*/ } + +/*N*/ void ScBaseCell::SetNote( const ScPostIt& rNote ) +/*N*/ { +/*N*/ if (rNote.GetText().Len() > 0) +/*N*/ { +/*N*/ if (!pNote) +/*N*/ pNote = new ScPostIt(rNote); +/*N*/ else +/*N*/ *pNote = rNote; +/*N*/ } +/*N*/ else +/*?*/ DELETEZ(pNote); +/*N*/ } + +/*N*/ BOOL ScBaseCell::GetNote( ScPostIt& rNote ) const +/*N*/ { +/*N*/ if ( pNote ) +/*N*/ rNote = *pNote; +/*N*/ else +/*?*/ rNote.Clear(); +/*N*/ +/*N*/ return ( pNote != NULL ); +/*N*/ } + +/*N*/ ScBaseCell* ScBaseCell::CreateTextCell( const String& rString, ScDocument* pDoc ) +/*N*/ { +/*N*/ if ( rString.Search('\n') != STRING_NOTFOUND || rString.Search(CHAR_CR) != STRING_NOTFOUND ) +/*?*/ return new ScEditCell( rString, pDoc ); +/*N*/ else +/*N*/ return new ScStringCell( rString ); +/*N*/ } + +/*N*/ void ScBaseCell::LoadNote( SvStream& rStream ) +/*N*/ { +/*N*/ pNote = new ScPostIt; +/*N*/ rStream >> *pNote; +/*N*/ } + +/*N*/ void ScBaseCell::SetBroadcaster(ScBroadcasterList* pNew) +/*N*/ { +/*N*/ delete pBroadcaster; +/*N*/ pBroadcaster = pNew; +/*N*/ } + +/*M*/ void ScBaseCell::StartListeningTo( ScDocument* pDoc, USHORT nOnlyNames ) +/*M*/ { +/*M*/ if ( eCellType == CELLTYPE_FORMULA && !pDoc->IsClipOrUndo() +/*M*/ && !pDoc->GetNoListening() +/*M*/ && !((ScFormulaCell*)this)->IsInChangeTrack() +/*M*/ ) +/*M*/ { +/*M*/ pDoc->SetDetectiveDirty(TRUE); // es hat sich was geaendert... +/*M*/ +/*M*/ ScFormulaCell* pFormCell = (ScFormulaCell*)this; +/*M*/ ScTokenArray* pArr = pFormCell->GetCode(); +/*M*/ if( pArr->IsRecalcModeAlways() ) +/*M*/ pDoc->StartListeningArea( BCA_LISTEN_ALWAYS, pFormCell ); +/*M*/ else +/*M*/ { +/*M*/ if ( nOnlyNames && ((nOnlyNames & SC_LISTENING_EXCEPT) == 0) && +/*M*/ pArr->IsReplacedSharedFormula() ) +/*M*/ nOnlyNames = 0; +/*M*/ pArr->Reset(); +/*M*/ for( ScToken* t = pArr->GetNextReferenceRPN(); t; +/*M*/ t = pArr->GetNextReferenceRPN() ) +/*M*/ { +/*M*/ StackVar eType = t->GetType(); +/*M*/ SingleRefData& rRef1 = t->GetSingleRef(); +/*M*/ SingleRefData& rRef2 = (eType == svDoubleRef ? +/*M*/ t->GetDoubleRef().Ref2 : rRef1); +/*M*/ BOOL bDo = FALSE; +/*M*/ if ( !nOnlyNames ) +/*M*/ bDo = TRUE; +/*M*/ else +/*M*/ { +/*M*/ DBG_BF_ASSERT(0, "STRIP"); //STRIP001 bDo = pArr->IsReplacedSharedFormula(); +/*M*/ } +/*M*/ if ( bDo ) +/*M*/ { +/*M*/ switch( eType ) +/*M*/ { +/*M*/ case svSingleRef: +/*M*/ rRef1.CalcAbsIfRel( pFormCell->aPos ); +/*M*/ if ( rRef1.Valid() ) +/*M*/ { +/*M*/ pDoc->StartListeningCell( +/*M*/ ScAddress( rRef1.nCol, +/*M*/ rRef1.nRow, +/*M*/ rRef1.nTab ), pFormCell ); +/*M*/ } +/*M*/ break; +/*M*/ case svDoubleRef: +/*M*/ t->CalcAbsIfRel( pFormCell->aPos ); +/*M*/ if ( rRef1.Valid() && rRef2.Valid() ) +/*M*/ { +/*M*/ if ( t->GetOpCode() == ocColRowNameAuto ) +/*M*/ { // automagically +/*?*/ if ( rRef1.IsColRel() ) +/*?*/ { // ColName +/*?*/ pDoc->StartListeningArea( ScRange ( +/*?*/ 0, +/*?*/ rRef1.nRow, +/*?*/ rRef1.nTab, +/*?*/ MAXCOL, +/*?*/ rRef2.nRow, +/*?*/ rRef2.nTab ), pFormCell ); +/*?*/ } +/*?*/ else +/*?*/ { // RowName +/*?*/ pDoc->StartListeningArea( ScRange ( +/*?*/ rRef1.nCol, +/*?*/ 0, +/*?*/ rRef1.nTab, +/*?*/ rRef2.nCol, +/*?*/ MAXROW, +/*?*/ rRef2.nTab ), pFormCell ); +/*?*/ } +/*M*/ } +/*M*/ else +/*M*/ { +/*M*/ pDoc->StartListeningArea( ScRange ( +/*M*/ rRef1.nCol, +/*M*/ rRef1.nRow, +/*M*/ rRef1.nTab, +/*M*/ rRef2.nCol, +/*M*/ rRef2.nRow, +/*M*/ rRef2.nTab ), pFormCell ); +/*M*/ } +/*M*/ } +/*M*/ break; +/*M*/ } +/*M*/ } +/*M*/ } +/*M*/ } +/*M*/ pArr->SetReplacedSharedFormula( FALSE ); +/*M*/ } +/*M*/ } + +// pArr gesetzt -> Referenzen von anderer Zelle nehmen +// dann muss auch aPos uebergeben werden! + +/*N*/ void ScBaseCell::EndListeningTo( ScDocument* pDoc, USHORT nOnlyNames, +/*N*/ ScTokenArray* pArr, ScAddress aPos ) +/*N*/ { +/*N*/ if ( eCellType == CELLTYPE_FORMULA && !pDoc->IsClipOrUndo() +/*N*/ && !((ScFormulaCell*)this)->IsInChangeTrack() +/*N*/ ) +/*N*/ { +/*N*/ pDoc->SetDetectiveDirty(TRUE); // es hat sich was geaendert... +/*N*/ +/*N*/ ScFormulaCell* pFormCell = (ScFormulaCell*)this; +/*N*/ if( pFormCell->GetCode()->IsRecalcModeAlways() ) +/*?*/ pDoc->EndListeningArea( BCA_LISTEN_ALWAYS, pFormCell ); +/*N*/ else +/*N*/ { +/*N*/ if (!pArr) +/*N*/ { +/*N*/ pArr = pFormCell->GetCode(); +/*N*/ aPos = pFormCell->aPos; +/*N*/ } +/*N*/ pArr->Reset(); +/*N*/ for( ScToken* t = pArr->GetNextReferenceRPN(); t; +/*N*/ t = pArr->GetNextReferenceRPN() ) +/*N*/ { +/*N*/ StackVar eType = t->GetType(); +/*N*/ SingleRefData& rRef1 = t->GetSingleRef(); +/*N*/ SingleRefData& rRef2 = (eType == svDoubleRef ? +/*N*/ t->GetDoubleRef().Ref2 : rRef1); +/*N*/ BOOL bDo; +/*N*/ if ( !nOnlyNames ) +/*N*/ bDo = TRUE; +/*N*/ else +/*N*/ { +/*?*/ bDo = FALSE; +/*?*/ if ( nOnlyNames & SC_LISTENING_NAMES_REL ) +/*?*/ bDo |= (rRef1.IsRelName() || rRef2.IsRelName()); +/*?*/ if ( nOnlyNames & SC_LISTENING_NAMES_ABS ) +/*?*/ { DBG_BF_ASSERT(0, "STRIP");} //STRIP001 bDo |= t->IsRPNReferenceAbsName(); +/*?*/ if ( nOnlyNames & SC_LISTENING_EXCEPT ) +/*?*/ bDo = !bDo; +/*N*/ } +/*N*/ if ( bDo ) +/*N*/ { +/*N*/ switch( t->GetType() ) +/*N*/ { +/*N*/ case svSingleRef: +/*N*/ rRef1.CalcAbsIfRel( aPos ); +/*N*/ if ( rRef1.Valid() ) +/*N*/ { +/*N*/ pDoc->EndListeningCell( +/*N*/ ScAddress( rRef1.nCol, +/*N*/ rRef1.nRow, +/*N*/ rRef1.nTab ), pFormCell ); +/*N*/ } +/*N*/ break; +/*N*/ case svDoubleRef: +/*N*/ t->CalcAbsIfRel( aPos ); +/*N*/ if ( rRef1.Valid() && rRef2.Valid() ) +/*N*/ { +/*N*/ if ( t->GetOpCode() == ocColRowNameAuto ) +/*N*/ { // automagically +/*?*/ if ( rRef1.IsColRel() ) +/*?*/ { // ColName +/*?*/ pDoc->EndListeningArea( ScRange ( +/*?*/ 0, +/*?*/ rRef1.nRow, +/*?*/ rRef1.nTab, +/*?*/ MAXCOL, +/*?*/ rRef2.nRow, +/*?*/ rRef2.nTab ), pFormCell ); +/*?*/ } +/*?*/ else +/*?*/ { // RowName +/*?*/ pDoc->EndListeningArea( ScRange ( +/*?*/ rRef1.nCol, +/*?*/ 0, +/*?*/ rRef1.nTab, +/*?*/ rRef2.nCol, +/*?*/ MAXROW, +/*?*/ rRef2.nTab ), pFormCell ); +/*?*/ } +/*N*/ } +/*N*/ else +/*N*/ { +/*N*/ pDoc->EndListeningArea( ScRange ( +/*N*/ rRef1.nCol, +/*N*/ rRef1.nRow, +/*N*/ rRef1.nTab, +/*N*/ rRef2.nCol, +/*N*/ rRef2.nRow, +/*N*/ rRef2.nTab ), pFormCell ); +/*N*/ } +/*N*/ } +/*N*/ break; +/*N*/ } +/*N*/ } +/*N*/ } +/*N*/ } +/*N*/ } +/*N*/ } + + +/*N*/ BOOL ScBaseCell::HasValueData() const +/*N*/ { +/*N*/ switch ( eCellType ) +/*N*/ { +/*N*/ case CELLTYPE_VALUE : +/*N*/ return TRUE; +/*N*/ case CELLTYPE_FORMULA : +/*N*/ return ((ScFormulaCell*)this)->IsValue(); +/*N*/ default: +/*N*/ return FALSE; +/*N*/ } +/*N*/ } + + +/*N*/ BOOL ScBaseCell::HasStringData() const +/*N*/ { +/*N*/ switch ( eCellType ) +/*N*/ { +/*N*/ case CELLTYPE_STRING : +/*N*/ case CELLTYPE_EDIT : +/*N*/ return TRUE; +/*N*/ case CELLTYPE_FORMULA : +/*N*/ return !((ScFormulaCell*)this)->IsValue(); +/*N*/ default: +/*N*/ return FALSE; +/*N*/ } +/*N*/ } + +/*N*/ String ScBaseCell::GetStringData() const +/*N*/ { +/*N*/ String aStr; +/*N*/ switch ( eCellType ) +/*N*/ { +/*N*/ case CELLTYPE_STRING: +/*N*/ ((const ScStringCell*)this)->GetString( aStr ); +/*N*/ break; +/*N*/ case CELLTYPE_EDIT: +/*N*/ ((const ScEditCell*)this)->GetString( aStr ); +/*N*/ break; +/*N*/ case CELLTYPE_FORMULA: +/*N*/ ((ScFormulaCell*)this)->GetString( aStr ); // an der Formelzelle nicht-const +/*N*/ break; +/*N*/ } +/*N*/ return aStr; +/*N*/ } + +// static +/*N*/ BOOL ScBaseCell::CellEqual( const ScBaseCell* pCell1, const ScBaseCell* pCell2 ) +/*N*/ { +/*N*/ CellType eType1 = CELLTYPE_NONE; +/*N*/ CellType eType2 = CELLTYPE_NONE; +/*N*/ if ( pCell1 ) +/*N*/ { +/*N*/ eType1 = pCell1->GetCellType(); +/*N*/ if (eType1 == CELLTYPE_EDIT) +/*N*/ eType1 = CELLTYPE_STRING; +/*N*/ else if (eType1 == CELLTYPE_NOTE) +/*N*/ eType1 = CELLTYPE_NONE; +/*N*/ } +/*N*/ if ( pCell2 ) +/*N*/ { +/*N*/ eType2 = pCell2->GetCellType(); +/*N*/ if (eType2 == CELLTYPE_EDIT) +/*N*/ eType2 = CELLTYPE_STRING; +/*N*/ else if (eType2 == CELLTYPE_NOTE) +/*N*/ eType2 = CELLTYPE_NONE; +/*N*/ } +/*N*/ if ( eType1 != eType2 ) +/*N*/ return FALSE; +/*N*/ +/*N*/ switch ( eType1 ) // beide Typen gleich +/*N*/ { +/*N*/ case CELLTYPE_NONE: // beide leer +/*N*/ return TRUE; +/*N*/ case CELLTYPE_VALUE: // wirklich Value-Zellen +/*N*/ return ( ((const ScValueCell*)pCell1)->GetValue() == +/*N*/ ((const ScValueCell*)pCell2)->GetValue() ); +/*N*/ case CELLTYPE_STRING: // String oder Edit +/*N*/ { +/*N*/ String aText1; +/*N*/ if ( pCell1->GetCellType() == CELLTYPE_STRING ) +/*N*/ ((const ScStringCell*)pCell1)->GetString(aText1); +/*N*/ else +/*N*/ ((const ScEditCell*)pCell1)->GetString(aText1); +/*N*/ String aText2; +/*N*/ if ( pCell2->GetCellType() == CELLTYPE_STRING ) +/*N*/ ((const ScStringCell*)pCell2)->GetString(aText2); +/*N*/ else +/*N*/ ((const ScEditCell*)pCell2)->GetString(aText2); +/*N*/ return ( aText1 == aText2 ); +/*N*/ } +/*N*/ case CELLTYPE_FORMULA: +/*N*/ { +/*N*/ //! eingefuegte Zeilen / Spalten beruecksichtigen !!!!! +/*N*/ //! Vergleichsfunktion an der Formelzelle ??? +/*N*/ //! Abfrage mit ScColumn::SwapRow zusammenfassen! +/*N*/ +/*N*/ ScTokenArray* pCode1 = ((ScFormulaCell*)pCell1)->GetCode(); +/*N*/ ScTokenArray* pCode2 = ((ScFormulaCell*)pCell2)->GetCode(); +/*N*/ +/*N*/ if (pCode1->GetLen() == pCode2->GetLen()) // nicht-UPN +/*N*/ { +/*N*/ BOOL bEqual = TRUE; +/*N*/ USHORT nLen = pCode1->GetLen(); +/*N*/ ScToken** ppToken1 = pCode1->GetArray(); +/*N*/ ScToken** ppToken2 = pCode2->GetArray(); +/*N*/ for (USHORT i=0; i<nLen; i++) +/*N*/ if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) ) +/*N*/ { +/*N*/ bEqual = FALSE; +/*N*/ break; +/*N*/ } +/*N*/ +/*N*/ if (bEqual) +/*N*/ return TRUE; +/*N*/ } +/*N*/ +/*N*/ return FALSE; // unterschiedlich lang oder unterschiedliche Tokens +/*N*/ } +/*N*/ default: +/*N*/ DBG_ERROR("huch, was fuer Zellen???"); +/*N*/ } +/*N*/ return FALSE; +/*N*/ } + +//----------------------------------------------------------------------------------- + +/*N*/ ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, +/*N*/ const String& rFormula, BYTE cMatInd ) : +/*N*/ ScBaseCell( CELLTYPE_FORMULA ), +/*N*/ aPos( rPos ), +/*N*/ pCode( NULL ), +/*N*/ nErgValue( 0.0 ), +/*N*/ bIsValue( TRUE ), +/*N*/ bDirty( TRUE ), // -> wg. Benutzung im Fkt.AutoPiloten, war: cMatInd != 0 +/*N*/ bChanged( FALSE ), +/*N*/ bRunning( FALSE ), +/*N*/ bCompile( FALSE ), +/*N*/ bSubTotal( FALSE ), +/*N*/ pDocument( pDoc ), +/*N*/ nFormatType( NUMBERFORMAT_NUMBER ), +/*N*/ nFormatIndex(0), +/*N*/ cMatrixFlag ( cMatInd ), +/*N*/ pMatrix( NULL ), +/*N*/ bIsIterCell (FALSE), +/*N*/ bInChangeTrack( FALSE ), +/*N*/ bTableOpDirty( FALSE ), +/*N*/ pPrevious(0), +/*N*/ pNext(0), +/*N*/ pPreviousTrack(0), +/*N*/ pNextTrack(0), +/*N*/ nMatCols(0), +/*N*/ nMatRows(0) +/*N*/ { +/*N*/ Compile( rFormula, TRUE ); // bNoListening, erledigt Insert +/*N*/ } + +// Wird von den Importfiltern verwendet + +/*N*/ ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, +/*N*/ const ScTokenArray* pArr, BYTE cInd ) : +/*N*/ ScBaseCell( CELLTYPE_FORMULA ), +/*N*/ aPos( rPos ), +/*N*/ pCode( pArr ? new ScTokenArray( *pArr ) : new ScTokenArray ), +/*N*/ nErgValue( 0.0 ), +/*N*/ bIsValue( TRUE ), +/*N*/ bDirty( NULL != pArr ), // -> wg. Benutzung im Fkt.AutoPiloten, war: cInd != 0 +/*N*/ bChanged( FALSE ), +/*N*/ bRunning( FALSE ), +/*N*/ bCompile( FALSE ), +/*N*/ bSubTotal( FALSE ), +/*N*/ pDocument( pDoc ), +/*N*/ nFormatType( NUMBERFORMAT_NUMBER ), +/*N*/ nFormatIndex(0), +/*N*/ cMatrixFlag ( cInd ), +/*N*/ pMatrix ( NULL ), +/*N*/ bIsIterCell (FALSE), +/*N*/ bInChangeTrack( FALSE ), +/*N*/ bTableOpDirty( FALSE ), +/*N*/ pPrevious(0), +/*N*/ pNext(0), +/*N*/ pPreviousTrack(0), +/*N*/ pNextTrack(0), +/*N*/ nMatCols(0), +/*N*/ nMatRows(0) +/*N*/ { +/*N*/ // UPN-Array erzeugen +/*N*/ if( pCode->GetLen() && !pCode->GetError() && !pCode->GetCodeLen() ) +/*N*/ { +/*N*/ ScCompiler aComp(pDocument, aPos, *pCode); +/*N*/ bSubTotal = aComp.CompileTokenArray(); +/*N*/ nFormatType = aComp.GetNumFormatType(); +/*N*/ } +/*N*/ else +/*N*/ { +/*N*/ pCode->Reset(); +/*N*/ if ( pCode->GetNextOpCodeRPN( ocSubTotal ) ) +/*N*/ bSubTotal = TRUE; +/*N*/ } +/*N*/ } + +/*N*/ ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rNewPos, +/*N*/ const ScFormulaCell& rScFormulaCell, USHORT nCopyFlags ) : +/*N*/ ScBaseCell( rScFormulaCell ), +/*N*/ SfxListener(), +/*N*/ aErgString( rScFormulaCell.aErgString ), +/*N*/ nErgValue( rScFormulaCell.nErgValue ), +/*N*/ bIsValue( rScFormulaCell.bIsValue ), +/*N*/ bDirty( rScFormulaCell.bDirty ), +/*N*/ bChanged( rScFormulaCell.bChanged ), +/*N*/ bRunning( rScFormulaCell.bRunning ), +/*N*/ bCompile( rScFormulaCell.bCompile ), +/*N*/ bSubTotal( rScFormulaCell.bSubTotal ), +/*N*/ pDocument( pDoc ), +/*N*/ nFormatType( rScFormulaCell.nFormatType ), +/*N*/ nFormatIndex( pDoc == rScFormulaCell.pDocument ? rScFormulaCell.nFormatIndex : 0 ), +/*N*/ cMatrixFlag ( rScFormulaCell.cMatrixFlag ), +/*N*/ bIsIterCell (FALSE), +/*N*/ bInChangeTrack( FALSE ), +/*N*/ bTableOpDirty( FALSE ), +/*N*/ pPrevious(0), +/*N*/ pNext(0), +/*N*/ pPreviousTrack(0), +/*N*/ pNextTrack(0), +/*N*/ aPos( rNewPos ), +/*N*/ nMatCols( rScFormulaCell.nMatCols ), +/*N*/ nMatRows( rScFormulaCell.nMatRows ) +/*N*/ { +/*N*/ if (rScFormulaCell.pMatrix) +/*?*/ pMatrix = rScFormulaCell.pMatrix->Clone(); +/*N*/ else +/*N*/ pMatrix = NULL; +/*N*/ pCode = rScFormulaCell.pCode->Clone(); +/*N*/ +/*N*/ if ( nCopyFlags & 0x0001 ) +/*?*/ DBG_BF_ASSERT(0, "STRIP"); //STRIP001 pCode->ReadjustRelative3DReferences( rScFormulaCell.aPos, aPos ); +/*N*/ +/*N*/ // evtl. Fehler zuruecksetzen und neu kompilieren +/*N*/ // nicht im Clipboard - da muss das Fehlerflag erhalten bleiben +/*N*/ // Spezialfall Laenge=0: als Fehlerzelle erzeugt, dann auch Fehler behalten +/*N*/ if ( pCode->GetError() && !pDocument->IsClipboard() && pCode->GetLen() ) +/*N*/ { +/*N*/ pCode->SetError( 0 ); +/*N*/ bCompile = TRUE; +/*N*/ } +/*N*/ //! Compile ColRowNames on URM_MOVE/URM_COPY _after_ UpdateReference +/*N*/ BOOL bCompileLater = FALSE; +/*N*/ BOOL bClipMode = rScFormulaCell.pDocument->IsClipboard(); +/*N*/ if( !bCompile ) +/*N*/ { // Name references with references and ColRowNames +/*N*/ pCode->Reset(); +/*N*/ for( ScToken* t = pCode->GetNextReferenceOrName(); t && !bCompile; +/*N*/ t = pCode->GetNextReferenceOrName() ) +/*N*/ { +/*N*/ if ( t->GetType() == svIndex ) +/*N*/ { +/*?*/ ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( t->GetIndex() ); +/*?*/ if( pRangeData ) +/*?*/ { +/*?*/ if( pRangeData->HasReferences() ) +/*?*/ bCompile = TRUE; +/*?*/ } +/*?*/ else +/*?*/ bCompile = TRUE; // invalid reference! +/*N*/ } +/*N*/ else if ( t->GetOpCode() == ocColRowName ) +/*N*/ { +/*N*/ bCompile = TRUE; // new lookup needed +/*N*/ bCompileLater = bClipMode; +/*N*/ } +/*N*/ } +/*N*/ } +/*N*/ if( bCompile ) +/*N*/ { +/*N*/ if ( !bCompileLater && bClipMode ) +/*N*/ { +/*?*/ DBG_BF_ASSERT(0, "STRIP"); //STRIP001 pCode->Reset(); +/*N*/ } +/*N*/ if ( !bCompileLater ) +/*N*/ { +/*N*/ // bNoListening, bei in Clip/Undo sowieso nicht, +/*N*/ // bei aus Clip auch nicht, sondern nach Insert(Clone) und UpdateReference +/*N*/ CompileTokenArray( TRUE ); +/*N*/ } +/*N*/ } +/*N*/ } + +// +---+---+---+---+---+---+---+---+ +// | |Str|Num|Dir|cMatrix| +// +---+---+---+---+---+---+---+---+ + +/*N*/ ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, +/*N*/ SvStream& rStream, ScMultipleReadHeader& rHdr ) : +/*N*/ ScBaseCell( CELLTYPE_FORMULA ), +/*N*/ aPos( rPos ), +/*N*/ pCode( new ScTokenArray ), +/*N*/ nErgValue( 0.0 ), +/*N*/ bIsValue( TRUE ), +/*N*/ bDirty( FALSE ), +/*N*/ bChanged( FALSE ), +/*N*/ bRunning( FALSE ), +/*N*/ bCompile( FALSE ), +/*N*/ bSubTotal( FALSE ), +/*N*/ pDocument( pDoc ), +/*N*/ nFormatType( 0 ), +/*N*/ nFormatIndex(0), +/*N*/ pMatrix ( NULL ), +/*N*/ bIsIterCell (FALSE), +/*N*/ bInChangeTrack( FALSE ), +/*N*/ bTableOpDirty( FALSE ), +/*N*/ pPrevious(0), +/*N*/ pNext(0), +/*N*/ pPreviousTrack(0), +/*N*/ pNextTrack(0), +/*N*/ nMatCols(0), +/*N*/ nMatRows(0) +/*N*/ { +/*N*/ // ScReadHeader aHdr( rStream ); +/*N*/ rHdr.StartEntry(); +/*N*/ +/*N*/ USHORT nVer = (USHORT) pDoc->GetSrcVersion(); +/*N*/ +/*N*/ if( nVer >= SC_NUMFMT ) +/*N*/ { +/*N*/ BYTE cData; +/*N*/ rStream >> cData; +/*N*/ #ifdef DBG_UTIL +/*N*/ // static BOOL bShown = 0; +/*N*/ // if ( !bShown && SOFFICE_FILEFORMAT_NOW > SOFFICE_FILEFORMAT_50 ) +/*N*/ // { +/*N*/ // bShown = 1; +/*N*/ // DBG_ERRORFILE( "bei inkompatiblem FileFormat den FormatIndex umheben!" ); +/*N*/ // } +/*N*/ #endif +/*N*/ if( cData & 0x0F ) +/*N*/ { +/*N*/ BYTE nSkip = cData & 0x0F; +/*N*/ if ( (cData & 0x10) && nSkip >= sizeof(UINT32) ) +/*N*/ { +/*N*/ UINT32 n; +/*N*/ rStream >> n; +/*N*/ nFormatIndex = n; +/*N*/ nSkip -= sizeof(UINT32); +/*N*/ } +/*N*/ if ( nSkip ) +/*?*/ rStream.SeekRel( nSkip ); +/*N*/ } +/*N*/ BYTE cFlags; +/*N*/ rStream >> cFlags >> nFormatType; +/*N*/ cMatrixFlag = (BYTE) ( cFlags & 0x03 ); +/*N*/ bDirty = BOOL( ( cFlags & 0x04 ) != 0 ); +/*N*/ if( cFlags & 0x08 ) +/*N*/ rStream >> nErgValue; +/*N*/ if( cFlags & 0x10 ) +/*N*/ { +/*N*/ rStream.ReadByteString( aErgString, rStream.GetStreamCharSet() ); +/*N*/ bIsValue = FALSE; +/*N*/ } +/*N*/ pCode->Load( rStream, nVer, aPos ); +/*N*/ if ( (cFlags & 0x18) == 0 ) +/*N*/ bDirty = TRUE; // #67161# no result stored => recalc +/*N*/ if( cFlags & 0x20 ) +/*N*/ bSubTotal = TRUE; +/*N*/ else if ( nVer < SC_SUBTOTAL_BUGFIX ) +/*N*/ { // #65285# in alten Dokumenten war Flag nicht gesetzt, wenn Formel +/*?*/ // manuell eingegeben wurde (nicht via Daten->Teilergebnisse) +/*N*/ if ( pCode->HasOpCodeRPN( ocSubTotal ) ) +/*N*/ { +/*?*/ bDirty = TRUE; // neu berechnen +/*?*/ bSubTotal = TRUE; +/*N*/ } +/*N*/ } +/*N*/ if ( cMatrixFlag == MM_FORMULA && rHdr.BytesLeft() ) +/*N*/ rStream >> nMatCols >> nMatRows; +/*N*/ } +/*N*/ else +/*N*/ { +/*N*/ UINT16 nCodeLen; +/*N*/ if( pDoc->GetSrcVersion() >= SC_FORMULA_LCLVER ) +/*N*/ rStream.SeekRel( 2 ); +/*N*/ rStream >> cMatrixFlag >> nCodeLen; +/*N*/ if( cMatrixFlag == 5 ) +/*N*/ cMatrixFlag = 0; +/*N*/ cMatrixFlag &= 3; +/*N*/ if( nCodeLen ) +/*N*/ pCode->Load30( rStream, aPos ); +/*N*/ // Wir koennen hier bei Calc 3.0-Docs noch kein UPN-Array +/*N*/ // erzeugen, da die Named Ranges noch nicht eingelesen sind +/*N*/ } +/*N*/ +/*N*/ rHdr.EndEntry(); +/*N*/ +/*N*/ // after loading, it must be known if ocMacro is in any formula +/*N*/ // (for macro warning, and to insert the hidden view) +/*N*/ if ( !pDoc->GetHasMacroFunc() && pCode->HasOpCodeRPN( ocMacro ) ) +/*N*/ pDoc->SetHasMacroFunc( TRUE ); +/*N*/ } + +/*N*/ BOOL lcl_IsBeyond( ScTokenArray* pCode, USHORT nMaxRow ) +/*N*/ { +/*N*/ ScToken* t; +/*N*/ pCode->Reset(); +/*N*/ while ( t = pCode->GetNextReferenceRPN() ) // RPN -> auch in Namen +/*N*/ if ( t->GetSingleRef().nRow > nMaxRow || +/*N*/ (t->GetType() == svDoubleRef && +/*N*/ t->GetDoubleRef().Ref2.nRow > nMaxRow) ) +/*N*/ return TRUE; +/*N*/ return FALSE; +/*N*/ } + +/*N*/ void ScFormulaCell::Save( SvStream& rStream, ScMultipleWriteHeader& rHdr ) const +/*N*/ { +/*N*/ USHORT nSaveMaxRow = pDocument->GetSrcMaxRow(); +/*N*/ if ( nSaveMaxRow < MAXROW && lcl_IsBeyond( pCode, nSaveMaxRow ) ) +/*N*/ { +/*?*/ // Zelle mit Ref-Error erzeugen und speichern +/*?*/ // StartEntry/EndEntry passiert beim Speichern der neuen Zelle +/*?*/ +/*?*/ SingleRefData aRef; +/*?*/ aRef.InitAddress(ScAddress()); +/*?*/ aRef.SetColRel(TRUE); +/*?*/ aRef.SetColDeleted(TRUE); +/*?*/ aRef.SetRowRel(TRUE); +/*?*/ aRef.SetRowDeleted(TRUE); +/*?*/ aRef.CalcRelFromAbs(aPos); +/*?*/ ScTokenArray aArr; +/*?*/ aArr.AddSingleReference(aRef); +/*?*/ aArr.AddOpCode(ocStop); +/*?*/ ScFormulaCell* pErrCell = new ScFormulaCell( pDocument, aPos, &aArr ); +/*?*/ pErrCell->Save( rStream, rHdr ); +/*?*/ delete pErrCell; +/*?*/ +/*?*/ pDocument->SetLostData(); // Warnung ausgeben +/*?*/ return; +/*N*/ } +/*N*/ +/*N*/ rHdr.StartEntry(); +/*N*/ +/*N*/ if ( bIsValue && !pCode->GetError() && !::rtl::math::isFinite( nErgValue ) ) +/*N*/ { +/*N*/ DBG_ERRORFILE( msgDbgInfinity ); +/*N*/ pCode->SetError( errIllegalFPOperation ); +/*N*/ } +/*N*/ BYTE cFlags = cMatrixFlag & 0x03; +/*N*/ if( bDirty ) +/*N*/ cFlags |= 0x04; +/*N*/ // Daten speichern? +/*N*/ if( pCode->IsRecalcModeNormal() && !pCode->GetError() ) +/*N*/ cFlags |= bIsValue ? 0x08 : 0x10; +/*N*/ if ( bSubTotal ) +/*N*/ cFlags |= 0x20; +/*N*/ #ifdef DBG_UTIL +/*N*/ static BOOL bShown = 0; +/*N*/ if ( !bShown && rStream.GetVersion() > SOFFICE_FILEFORMAT_50 ) +/*N*/ { +/*N*/ bShown = 1; +/*N*/ DBG_ERRORFILE( "bei inkompatiblem FileFormat den FormatIndex umheben!" ); +/*N*/ } +/*N*/ // rStream << (BYTE) 0x00; +/*N*/ #endif +/*N*/ if ( nFormatIndex ) +/*N*/ rStream << (BYTE) (0x10 | sizeof(UINT32)) << static_cast<sal_uInt32>(nFormatIndex); +/*N*/ else +/*N*/ rStream << (BYTE) 0x00; +/*N*/ rStream << cFlags << (UINT16) nFormatType; +/*N*/ if( cFlags & 0x08 ) +/*N*/ rStream << nErgValue; +/*N*/ if( cFlags & 0x10 ) +/*N*/ rStream.WriteByteString( aErgString, rStream.GetStreamCharSet() ); +/*N*/ pCode->Store( rStream, aPos ); +/*N*/ if ( cMatrixFlag == MM_FORMULA ) +/*N*/ rStream << nMatCols << nMatRows; +/*N*/ +/*N*/ rHdr.EndEntry(); +/*N*/ } + +/*N*/ ScBaseCell* ScFormulaCell::Clone( ScDocument* pDoc, const ScAddress& rPos, +/*N*/ BOOL bNoListening ) const +/*N*/ { +/*N*/ ScFormulaCell* pCell = new ScFormulaCell( pDoc, rPos, *this ); +/*N*/ if ( !bNoListening ) +/*N*/ pCell->StartListeningTo( pDoc ); +/*N*/ return pCell; +/*N*/ } + +/*N*/ void ScFormulaCell::GetFormula( String& rFormula ) const +/*N*/ { +/*N*/ if( pCode->GetError() && !pCode->GetLen() ) +/*N*/ { +/*?*/ rFormula = ScGlobal::GetErrorString( pCode->GetError() ); return; +/*N*/ } +/*N*/ else if( cMatrixFlag == MM_REFERENCE ) +/*N*/ { +/*N*/ // Referenz auf eine andere Zelle, die eine Matrixformel enthaelt +/*N*/ pCode->Reset(); +/*N*/ ScToken* p = pCode->GetNextReferenceRPN(); +/*N*/ if( p ) +/*N*/ { +/*N*/ ScBaseCell* pCell = NULL; +/*N*/ if ( !IsInChangeTrack() ) +/*N*/ { +/*N*/ SingleRefData& rRef = p->GetSingleRef(); +/*N*/ rRef.CalcAbsIfRel( aPos ); +/*N*/ if ( rRef.Valid() ) +/*N*/ pCell = pDocument->GetCell( ScAddress( rRef.nCol, +/*N*/ rRef.nRow, rRef.nTab ) ); +/*N*/ } +/*N*/ if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA) +/*N*/ { +/*N*/ ((ScFormulaCell*)pCell)->GetFormula(rFormula); +/*N*/ return; +/*N*/ } +/*N*/ else +/*N*/ { +/*?*/ ScCompiler aComp( pDocument, aPos, *pCode ); +/*?*/ aComp.CreateStringFromTokenArray( rFormula ); +/*N*/ } +/*N*/ } +/*N*/ else +/*N*/ { +/*N*/ DBG_ERROR("ScFormulaCell::GetFormula: Keine Matrix"); +/*N*/ } +/*N*/ } +/*N*/ else +/*N*/ { +/*N*/ ScCompiler aComp( pDocument, aPos, *pCode ); +/*N*/ aComp.CreateStringFromTokenArray( rFormula ); +/*N*/ } +/*N*/ +/*N*/ rFormula.Insert( '=',0 ); +/*N*/ if( cMatrixFlag ) +/*N*/ { +/*N*/ rFormula.Insert('{', 0); +/*N*/ rFormula += '}'; +/*N*/ } +/*N*/ } + +/*N*/ void ScFormulaCell::Compile( const String& rFormula, BOOL bNoListening ) +/*N*/ { +/*N*/ if ( pDocument->IsClipOrUndo() ) return; +/*N*/ BOOL bWasInFormulaTree = pDocument->IsInFormulaTree( this ); +/*N*/ if ( bWasInFormulaTree ) +/*?*/ pDocument->RemoveFromFormulaTree( this ); +/*N*/ // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein +/*N*/ if ( pCode ) +/*N*/ pCode->Clear(); +/*N*/ ScTokenArray* pCodeOld = pCode; +/*N*/ ScCompiler aComp(pDocument, aPos); +/*N*/ if ( pDocument->IsImportingXML() ) +/*?*/ aComp.SetCompileEnglish( TRUE ); +/*N*/ pCode = aComp.CompileString( rFormula ); +/*N*/ if ( pCodeOld ) +/*N*/ delete pCodeOld; +/*N*/ if( !pCode->GetError() ) +/*N*/ { +/*N*/ if ( !pCode->GetLen() && aErgString.Len() && rFormula == aErgString ) +/*N*/ { // #65994# nicht rekursiv CompileTokenArray/Compile/CompileTokenArray +/*?*/ DBG_BF_ASSERT(0, "STRIP"); //STRIP001 if ( rFormula.GetChar(0) == '=' ) +/*N*/ } +/*N*/ bCompile = TRUE; +/*N*/ CompileTokenArray( bNoListening ); +/*N*/ } +/*N*/ else +/*N*/ { +/*N*/ bChanged = TRUE; +/*N*/ SetTextWidth( TEXTWIDTH_DIRTY ); +/*N*/ SetScriptType( SC_SCRIPTTYPE_UNKNOWN ); +/*N*/ } +/*N*/ if ( bWasInFormulaTree ) +/*?*/ pDocument->PutInFormulaTree( this ); +/*N*/ } + + +/*N*/ void ScFormulaCell::CompileTokenArray( BOOL bNoListening ) +/*N*/ { +/*N*/ // Noch nicht compiliert? +/*N*/ if( !pCode->GetLen() && aErgString.Len() ) +/*N*/ Compile( aErgString ); +/*N*/ else if( bCompile && !pDocument->IsClipOrUndo() && !pCode->GetError() ) +/*N*/ { +/*N*/ // RPN-Laenge kann sich aendern +/*N*/ BOOL bWasInFormulaTree = pDocument->IsInFormulaTree( this ); +/*N*/ if ( bWasInFormulaTree ) +/*?*/ pDocument->RemoveFromFormulaTree( this ); +/*N*/ +/*N*/ // Laden aus Filter? Dann noch nix machen! +/*N*/ if( pDocument->IsInsertingFromOtherDoc() ) +/*N*/ bNoListening = TRUE; +/*N*/ +/*N*/ if( !bNoListening && pCode->GetCodeLen() ) +/*?*/ EndListeningTo( pDocument ); +/*N*/ ScCompiler aComp(pDocument, aPos, *pCode ); +/*N*/ bSubTotal = aComp.CompileTokenArray(); +/*N*/ if( !pCode->GetError() ) +/*N*/ { +/*N*/ nFormatType = aComp.GetNumFormatType(); +/*N*/ nFormatIndex = 0; +/*N*/ bChanged = TRUE; +/*N*/ nErgValue = 0.0; +/*N*/ aErgString.Erase(); +/*N*/ bCompile = FALSE; +/*N*/ if ( !bNoListening ) +/*N*/ StartListeningTo( pDocument ); +/*N*/ } +/*N*/ if ( bWasInFormulaTree ) +/*?*/ pDocument->PutInFormulaTree( this ); +/*N*/ } +/*N*/ } + + +/*N*/ void ScFormulaCell::CompileXML( ScProgress& rProgress ) +/*N*/ { +/*N*/ if ( cMatrixFlag == MM_REFERENCE ) +/*N*/ { // is already token code via ScDocFunc::EnterMatrix, ScDocument::InsertMatrixFormula +/*N*/ // just establish listeners +/*N*/ StartListeningTo( pDocument ); +/*N*/ return ; +/*N*/ } +/*N*/ +/*N*/ ScCompiler aComp( pDocument, aPos, *pCode ); +/*N*/ aComp.SetCompileEnglish( TRUE ); +/*N*/ aComp.SetImportXML( TRUE ); +/*N*/ String aFormula; +/*N*/ aComp.CreateStringFromTokenArray( aFormula ); +/*N*/ pDocument->DecXMLImportedFormulaCount( aFormula.Len() ); +/*N*/ rProgress.SetStateCountDownOnPercent( pDocument->GetXMLImportedFormulaCount() ); +/*N*/ // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein +/*N*/ if ( pCode ) +/*N*/ pCode->Clear(); +/*N*/ ScTokenArray* pCodeOld = pCode; +/*N*/ pCode = aComp.CompileString( aFormula ); +/*N*/ delete pCodeOld; +/*N*/ if( !pCode->GetError() ) +/*N*/ { +/*N*/ if ( !pCode->GetLen() ) +/*N*/ { +/*?*/ DBG_BF_ASSERT(0, "STRIP"); //STRIP001 if ( aFormula.GetChar(0) == '=' ) +/*N*/ } +/*N*/ bSubTotal = aComp.CompileTokenArray(); +/*N*/ if( !pCode->GetError() ) +/*N*/ { +/*N*/ nFormatType = aComp.GetNumFormatType(); +/*N*/ nFormatIndex = 0; +/*N*/ bChanged = TRUE; +/*N*/ bCompile = FALSE; +/*N*/ StartListeningTo( pDocument ); +/*N*/ } +/*N*/ } +/*N*/ else +/*N*/ { +/*N*/ bChanged = TRUE; +/*N*/ SetTextWidth( TEXTWIDTH_DIRTY ); +/*N*/ SetScriptType( SC_SCRIPTTYPE_UNKNOWN ); +/*N*/ } +/*N*/ +/*N*/ // Same as in Load: after loading, it must be known if ocMacro is in any formula +/*N*/ // (for macro warning, CompileXML is called at the end of loading XML file) +/*N*/ if ( !pDocument->GetHasMacroFunc() && pCode->HasOpCodeRPN( ocMacro ) ) +/*N*/ pDocument->SetHasMacroFunc( TRUE ); +/*N*/ } + + +/*N*/ void ScFormulaCell::CalcAfterLoad() +/*N*/ { +/*N*/ BOOL bNewCompiled = FALSE; +/*N*/ // Falls ein Calc 1.0-Doc eingelesen wird, haben wir ein Ergebnis, +/*N*/ // aber kein TokenArray +/*N*/ if( !pCode->GetLen() && aErgString.Len() ) +/*N*/ { +/*?*/ Compile( aErgString, TRUE ); +/*?*/ aErgString.Erase(); +/*?*/ bDirty = TRUE; +/*?*/ bNewCompiled = TRUE; +/*N*/ } +/*N*/ // Das UPN-Array wird nicht erzeugt, wenn ein Calc 3.0-Doc eingelesen +/*N*/ // wurde, da die RangeNames erst jetzt existieren. +/*N*/ if( pCode->GetLen() && !pCode->GetCodeLen() && !pCode->GetError() ) +/*N*/ { +/*N*/ ScCompiler aComp(pDocument, aPos, *pCode); +/*N*/ bSubTotal = aComp.CompileTokenArray(); +/*N*/ nFormatType = aComp.GetNumFormatType(); +/*N*/ nFormatIndex = 0; +/*N*/ bDirty = TRUE; +/*N*/ bCompile = FALSE; +/*N*/ bNewCompiled = TRUE; +/*N*/ } +/*N*/ // irgendwie koennen unter os/2 mit rotter FPU-Exception /0 ohne Err503 +/*N*/ // gespeichert werden, woraufhin spaeter im NumberFormatter die BLC Lib +/*N*/ // bei einem fabs(-NAN) abstuerzt (#32739#) +/*N*/ // hier fuer alle Systeme ausbuegeln, damit da auch Err503 steht +/*N*/ if ( bIsValue && !::rtl::math::isFinite( nErgValue ) ) +/*N*/ { +/*?*/ DBG_ERRORFILE("Formelzelle INFINITY !!! Woher kommt das Dokument?"); +/*?*/ nErgValue = 0.0; +/*?*/ pCode->SetError( errIllegalFPOperation ); +/*?*/ bDirty = TRUE; +/*N*/ } +/*N*/ // DoubleRefs bei binaeren Operatoren waren vor v5.0 immer Matrix, +/*N*/ // jetzt nur noch wenn in Matrixformel, sonst implizite Schnittmenge +/*N*/ if ( pDocument->GetSrcVersion() < SC_MATRIX_DOUBLEREF && +/*N*/ GetMatrixFlag() == MM_NONE && pCode->HasMatrixDoubleRefOps() ) +/*N*/ { +/*N*/ cMatrixFlag = MM_FORMULA; +/*N*/ nMatCols = 1; +/*N*/ nMatRows = 1; +/*N*/ } +/*N*/ // Muss die Zelle berechnet werden? +/*N*/ // Nach Load koennen Zellen einen Fehlercode enthalten, auch dann +/*N*/ // Listener starten und ggbf. neu berechnen wenn nicht RECALCMODE_NORMAL +/*N*/ if( !bNewCompiled || !pCode->GetError() ) +/*N*/ { +/*N*/ StartListeningTo( pDocument ); +/*N*/ if( !pCode->IsRecalcModeNormal() ) +/*N*/ bDirty = TRUE; +/*N*/ } +/*N*/ if ( pCode->GetError() == errInterpOverflow ) +/*N*/ { // versuchen Err527 wegzubuegeln +/*N*/ bDirty = TRUE; +/*N*/ } +/*N*/ else if ( pCode->IsRecalcModeAlways() ) +/*N*/ { // zufall(), heute(), jetzt() bleiben immer im FormulaTree, damit sie +/*N*/ // auch bei jedem F9 berechnet werden. +/*N*/ bDirty = TRUE; +/*N*/ } +/*N*/ // Noch kein SetDirty weil noch nicht alle Listener bekannt, erst in +/*N*/ // SetDirtyAfterLoad. +/*N*/ } + +/*N*/ void ScFormulaCell::Interpret() +/*N*/ { +/*N*/ static USHORT nRecCount = 0; +/*N*/ static ScFormulaCell* pLastIterInterpreted = NULL; +/*N*/ if ( !IsDirtyOrInTableOpDirty() ) +/*N*/ return; // fuer IterCircRef, nix doppelt +/*N*/ +/*N*/ //! HACK: +/*N*/ // Wenn der Aufruf aus einem Reschedule im DdeLink-Update kommt, dirty stehenlassen +/*N*/ // Besser: Dde-Link Update ohne Reschedule oder ganz asynchron !!! +/*N*/ +/*N*/ if ( pDocument->IsInDdeLinkUpdate() ) +/*N*/ return; +/*N*/ +/*N*/ if (bRunning) +/*N*/ { +/*N*/ // Keine Iterierung? +/*N*/ if (!pDocument->GetDocOptions().IsIter()) +/*N*/ pCode->SetError( errCircularReference ); +/*N*/ else +/*N*/ { +/*?*/ if (pCode->GetError() == errCircularReference) +/*?*/ pCode->SetError( 0 ); +/*?*/ nIterMode = 1; +/*?*/ bIsIterCell = TRUE; +/*?*/ pLastIterInterpreted = NULL; +/*N*/ } +/*N*/ return; +/*N*/ } +/*N*/ // #63038# fuer GetErrCode, IsValue, GetValue nicht mehrfach interpretieren +/*N*/ if ( nIterMode && pLastIterInterpreted == this ) +/*N*/ return ; +/*N*/ +/*N*/ if( !pCode->GetCodeLen() && !pCode->GetError() ) +/*N*/ { +/*N*/ // #i11719# no UPN and no error and no token code but result string present +/*N*/ // => interpretation of this cell during name-compilation and unknown names +/*N*/ // => can't exchange underlying code array in CompileTokenArray() / +/*N*/ // Compile() because interpreter's token iterator would crash. +/*N*/ // This should only be a temporary condition and, since we set an +/*N*/ // error, if ran into it again we'd bump into the dirty-clearing +/*N*/ // condition further down. +/*N*/ if ( !pCode->GetLen() && aErgString.Len() ) +/*N*/ { +/*N*/ pCode->SetError( errNoCode ); +/*N*/ // This is worth an assertion; if encountered in daily work +/*N*/ // documents we might need another solution. Or just confirm correctness. +/*N*/ DBG_ERRORFILE( "ScFormulaCell::Interpret: no UPN, no error, no token, but string" ); +/*N*/ return; +/*N*/ } +/*?*/ CompileTokenArray(); +/*N*/ } +/*N*/ +/*N*/ if( pCode->GetCodeLen() && pDocument ) +/*N*/ { +/*N*/ #if defined(MAC) && !defined(SIMPLEMAXRECURSION) +/*N*/ if( StackSpace() < 2048 ) // 2K Stack noch uebriglassen +/*N*/ #else +/*N*/ if( nRecCount > MAXRECURSION ) +/*N*/ #endif +/*N*/ { +/*?*/ pCode->SetError( errInterpOverflow ); +/*?*/ // Zelle bleibt in FormulaTree, naechstes Mal sind evtl. +/*?*/ // Vorgaenger bereits berechnet worden bzw. von der View wird +/*?*/ // via ScCellFormat::GetString CalcFormulaTree angeworfen +/*?*/ bDirty = FALSE; +/*?*/ bTableOpDirty = FALSE; +/*?*/ nErgValue = 0.0; +/*?*/ bIsValue = TRUE; +/*?*/ nIterMode = 0; +/*?*/ bIsIterCell = FALSE; +/*?*/ pLastIterInterpreted = NULL; +/*?*/ bChanged = TRUE; +/*?*/ SetTextWidth( TEXTWIDTH_DIRTY ); +/*?*/ SetScriptType( SC_SCRIPTTYPE_UNKNOWN ); +/*?*/ return; +/*N*/ } +/*N*/ nRecCount++; +/*N*/ pDocument->IncInterpretLevel(); +/*N*/ ScInterpreter* p = new ScInterpreter( this, pDocument, aPos, *pCode ); +/*N*/ USHORT nOldErrCode = pCode->GetError(); +/*N*/ USHORT nIterCount = 0; +/*N*/ if ( nIterMode == 0 ) +/*N*/ { // nur beim ersten Mal +/*N*/ // wenn neu kompilierte Zelle 0.0 ergibt wird kein Changed erkannt +/*N*/ // und die Zelle wird nicht sofort repainted! +/*N*/ // bChanged = FALSE; +/*N*/ if ( nOldErrCode == errNoConvergence +/*N*/ && pDocument->GetDocOptions().IsIter() ) +/*?*/ pCode->SetError( 0 ); +/*N*/ } +/*N*/ BOOL bRepeat = TRUE; +/*N*/ while( bRepeat ) +/*N*/ { +/*N*/ if ( pMatrix ) +/*N*/ { +/*?*/ delete pMatrix; +/*?*/ pMatrix = NULL; +/*N*/ } +/*N*/ +/*N*/ switch ( pCode->GetError() ) +/*N*/ { +/*?*/ case errCircularReference : // wird neu festgestellt +/*?*/ case errInterpOverflow : // Err527 eine Chance geben +/*?*/ pCode->SetError( 0 ); +/*?*/ break; +/*N*/ } +/*N*/ +/*N*/ bRunning = TRUE; +/*N*/ p->Interpret(); +/*N*/ bRunning = FALSE; +/*N*/ if( pCode->GetError() +/*N*/ && pCode->GetError() != errCircularReference ) +/*N*/ { +/*N*/ bDirty = FALSE; +/*N*/ bTableOpDirty = FALSE; +/*N*/ nIterMode = 0; +/*N*/ bIsIterCell = FALSE; +/*N*/ pLastIterInterpreted = NULL; +/*N*/ bChanged = TRUE; +/*N*/ bIsValue = TRUE; +/*N*/ break; +/*N*/ } +/*N*/ if( nIterMode == 1 && bIsIterCell ) +/*N*/ { +/*?*/ pLastIterInterpreted = NULL; +/*?*/ ++nIterCount; +/*?*/ // schoen konvergiert? +/*?*/ if( (p->GetResultType() == svDouble +/*?*/ && fabs( p->GetNumResult() - nErgValue ) <= +/*?*/ pDocument->GetDocOptions().GetIterEps()) +/*?*/ ) +/*?*/ { +/*?*/ nIterMode = 0; +/*?*/ bIsIterCell = FALSE; +/*?*/ bDirty = FALSE; +/*?*/ bTableOpDirty = FALSE; +/*?*/ bRepeat = FALSE; +/*?*/ } +/*?*/ // Zu oft rumgelaufen? +/*?*/ else if( nIterCount >= pDocument->GetDocOptions().GetIterCount() ) +/*?*/ { +/*?*/ nIterMode = 0; +/*?*/ bIsIterCell = FALSE; +/*?*/ bDirty = FALSE; +/*?*/ bTableOpDirty = FALSE; +/*?*/ bRepeat = FALSE; +/*?*/ pCode->SetError( errNoConvergence ); +/*?*/ } +/*?*/ if ( p->GetResultType() == svDouble ) +/*?*/ { +/*?*/ if( !bIsValue || nErgValue != p->GetNumResult() ) +/*?*/ bChanged = TRUE; +/*?*/ bIsValue = TRUE; +/*?*/ nErgValue = p->GetNumResult(); +/*?*/ } +/*N*/ } +/*N*/ else +/*N*/ bRepeat = FALSE; +/*N*/ } +/*N*/ +/*N*/ switch( p->GetResultType() ) +/*N*/ { +/*N*/ case svDouble: +/*N*/ if( nErgValue != p->GetNumResult() || !bIsValue ) +/*N*/ { +/*N*/ bChanged = TRUE; +/*N*/ bIsValue = TRUE; +/*N*/ nErgValue = p->GetNumResult(); +/*N*/ } +/*N*/ break; +/*N*/ case svString: +/*N*/ if( aErgString != p->GetStringResult() || bIsValue ) +/*N*/ { +/*N*/ bChanged = TRUE; +/*N*/ bIsValue = FALSE; +/*N*/ aErgString = p->GetStringResult(); +/*N*/ } +/*N*/ break; +/*N*/ } +/*N*/ +/*N*/ // Neuer Fehlercode? +/*N*/ if( !bChanged && pCode->GetError() != nOldErrCode ) +/*N*/ bChanged = TRUE; +/*N*/ // Anderes Zahlenformat? +/*N*/ if( nFormatType != p->GetRetFormatType() ) +/*N*/ { +/*N*/ nFormatType = p->GetRetFormatType(); +/*N*/ bChanged = TRUE; +/*N*/ } +/*N*/ if( nFormatIndex != p->GetRetFormatIndex() ) +/*N*/ { +/*N*/ nFormatIndex = p->GetRetFormatIndex(); +/*N*/ bChanged = TRUE; +/*N*/ } +/*N*/ // Genauigkeit wie angezeigt? +/*N*/ if ( bIsValue && !pCode->GetError() +/*N*/ && pDocument->GetDocOptions().IsCalcAsShown() +/*N*/ && nFormatType != NUMBERFORMAT_DATE +/*N*/ && nFormatType != NUMBERFORMAT_TIME +/*N*/ && nFormatType != NUMBERFORMAT_DATETIME ) +/*N*/ { +/*?*/ ULONG nFormat = pDocument->GetNumberFormat( aPos ); +/*?*/ if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) +/*?*/ nFormat = nFormatIndex; +/*?*/ if ( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) +/*?*/ nFormat = ScGlobal::GetStandardFormat( +/*?*/ *pDocument->GetFormatTable(), nFormat, nFormatType ); +/*?*/ nErgValue = pDocument->RoundValueAsShown( nErgValue, nFormat ); +/*N*/ } +/*N*/ if ( nIterMode == 0 ) +/*N*/ { +/*N*/ bDirty = FALSE; +/*N*/ bTableOpDirty = FALSE; +/*N*/ } +/*N*/ else +/*N*/ pLastIterInterpreted = this; +/*N*/ pMatrix = p->GetMatrixResult(); +/*N*/ if( pMatrix ) +/*N*/ { +/*N*/ #if 0 +/*?*/ //! MatrixFormel immer changed?!? +/*?*/ // ist bei MD's Rundumschlag von r1.167 --> r1.168 reingekommen +/*?*/ // => ewiges Repaint von MatrixFormel, besonders bei DDE laestig +/*?*/ // ab r1.260 (sv369b) probieren wir's mal ohne.. +/*?*/ if( cMatrixFlag == MM_FORMULA ) +/*?*/ bChanged = TRUE; +/*?*/ else +/*N*/ #else +/*N*/ if( cMatrixFlag != MM_FORMULA ) +/*N*/ #endif +/*N*/ { // mit linker oberer Ecke weiterleben +/*?*/ delete pMatrix; +/*?*/ pMatrix = NULL; +/*N*/ } +/*N*/ } +/*N*/ if( bChanged ) +/*N*/ { +/*N*/ SetTextWidth( TEXTWIDTH_DIRTY ); +/*N*/ SetScriptType( SC_SCRIPTTYPE_UNKNOWN ); +/*N*/ } +/*N*/ delete p; +/*N*/ nRecCount--; +/*N*/ pDocument->DecInterpretLevel(); +/*N*/ if ( pCode->GetError() != errInterpOverflow +/*N*/ && !pCode->IsRecalcModeAlways() ) +/*N*/ pDocument->RemoveFromFormulaTree( this ); +/*N*/ #ifdef DBG_UTIL +/*N*/ if ( bIsValue && !pCode->GetError() && !::rtl::math::isFinite( nErgValue ) ) +/*N*/ { +/*N*/ DBG_ERRORFILE( msgDbgInfinity ); +/*N*/ nErgValue = 0.0; +/*N*/ pCode->SetError( errIllegalFPOperation ); +/*N*/ } +/*N*/ #endif +/*N*/ +/*N*/ // FORCED Zellen auch sofort auf Gueltigkeit testen (evtl. Makro starten) +/*N*/ +/*N*/ if ( pCode->IsRecalcModeForced() ) +/*N*/ { +DBG_BF_ASSERT(0, "STRIP"); //STRIP001 /*?*/ ULONG nValidation = ((const SfxUInt32Item*) pDocument->GetAttr( +/*N*/ } +/*N*/ +/*N*/ // Reschedule verlangsamt das ganze erheblich, nur bei Prozentaenderung ausfuehren +/*N*/ ScProgress::GetInterpretProgress()->SetStateCountDownOnPercent( +/*N*/ pDocument->GetFormulaCodeInTree() ); +/*N*/ } +/*N*/ else +/*N*/ { +/*N*/ // Zelle bei Compiler-Fehlern nicht ewig auf dirty stehenlassen +/*N*/ DBG_ASSERT( pCode->GetError(), "kein UPN-Code und kein Fehler ?!?!" ); +/*N*/ bDirty = FALSE; +/*N*/ bTableOpDirty = FALSE; +/*N*/ } +/*N*/ } + +/*N*/ ULONG ScFormulaCell::GetStandardFormat( SvNumberFormatter& rFormatter, ULONG nFormat ) const +/*N*/ { +/*N*/ if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) +/*N*/ return nFormatIndex; +/*N*/ if ( bIsValue ) //! nicht IsValue() +/*N*/ return ScGlobal::GetStandardFormat( nErgValue, rFormatter, nFormat, nFormatType ); +/*N*/ else +/*N*/ return ScGlobal::GetStandardFormat( rFormatter, nFormat, nFormatType ); +/*N*/ } + + +/*N*/ void __EXPORT ScFormulaCell::SFX_NOTIFY( SfxBroadcaster& rBC, +/*N*/ const TypeId& rBCType, const SfxHint& rHint, const TypeId& rHintType ) +/*N*/ { +/*N*/ if ( !pDocument->IsInDtorClear() && !pDocument->GetHardRecalcState() ) +/*N*/ { +/*N*/ const ScHint* p = PTR_CAST( ScHint, &rHint ); +/*N*/ if( p && (p->GetId() & (SC_HINT_DATACHANGED | SC_HINT_DYING | +/*N*/ SC_HINT_TABLEOPDIRTY)) ) +/*N*/ { +/*N*/ BOOL bForceTrack = FALSE; +/*N*/ if ( p->GetId() & SC_HINT_TABLEOPDIRTY ) +/*N*/ { +/*?*/ bForceTrack = !bTableOpDirty; +/*?*/ if ( !bTableOpDirty ) +/*?*/ { +/*?*/ DBG_BF_ASSERT(0, "STRIP"); //STRIP001 pDocument->AddTableOpFormulaCell( this ); +/*?*/ } +/*N*/ } +/*N*/ else +/*N*/ { +/*N*/ bForceTrack = !bDirty; +/*N*/ bDirty = TRUE; +/*N*/ } +/*N*/ // #35962# Don't remove from FormulaTree to put in FormulaTrack to +/*N*/ // put in FormulaTree again and again, only if necessary. +/*N*/ // Any other means except RECALCMODE_ALWAYS by which a cell could +/*N*/ // be in FormulaTree if it would notify other cells through +/*N*/ // FormulaTrack which weren't in FormulaTrack/FormulaTree before?!? +/*N*/ // #87866# Yes. The new TableOpDirty made it necessary to have a +/*N*/ // forced mode where formulas may still be in FormulaTree from +/*N*/ // TableOpDirty but have to notify dependents for normal dirty. +/*N*/ if ( (bForceTrack || !pDocument->IsInFormulaTree( this ) +/*N*/ || pCode->IsRecalcModeAlways()) +/*N*/ && !pDocument->IsInFormulaTrack( this ) ) +/*N*/ pDocument->AppendToFormulaTrack( this ); +/*N*/ } +/*N*/ } +/*N*/ } + +/*N*/ void ScFormulaCell::SetDirty() +/*N*/ { +/*N*/ if ( !IsInChangeTrack() ) +/*N*/ { +/*N*/ if ( pDocument->GetHardRecalcState() ) +/*N*/ bDirty = TRUE; +/*N*/ else +/*N*/ { +/*N*/ // Mehrfach-FormulaTracking in Load und in CompileAll +/*N*/ // nach CopyScenario und CopyBlockFromClip vermeiden. +/*N*/ // Wenn unbedingtes FormulaTracking noetig, vor SetDirty bDirty=FALSE +/*N*/ // setzen, z.B. in CompileTokenArray +/*N*/ if ( !bDirty || !pDocument->IsInFormulaTree( this ) ) +/*N*/ { +/*N*/ bDirty = TRUE; +/*N*/ pDocument->AppendToFormulaTrack( this ); +/*N*/ pDocument->TrackFormulas(); +/*N*/ } +/*N*/ } +/*N*/ } +/*N*/ } + +/*N*/ void ScFormulaCell::SetTableOpDirty() +/*N*/ { +/*N*/ if ( !IsInChangeTrack() ) +/*N*/ { +/*N*/ if ( pDocument->GetHardRecalcState() ) +/*N*/ bTableOpDirty = TRUE; +/*N*/ else +/*N*/ { +/*N*/ if ( !bTableOpDirty || !pDocument->IsInFormulaTree( this ) ) +/*N*/ { +/*N*/ if ( !bTableOpDirty ) +/*N*/ { +/*N*/ pDocument->AddTableOpFormulaCell( this ); +/*N*/ bTableOpDirty = TRUE; +/*N*/ } +/*N*/ pDocument->AppendToFormulaTrack( this ); +/*N*/ pDocument->TrackFormulas( SC_HINT_TABLEOPDIRTY ); +/*N*/ } +/*N*/ } +/*N*/ } +/*N*/ } + + +/*N*/ BOOL ScFormulaCell::IsDirtyOrInTableOpDirty() +/*N*/ { +/*N*/ return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp()); +/*N*/ } + + +/*N*/ void ScFormulaCell::SetErrCode( USHORT n ) +/*N*/ { +/*N*/ pCode->SetError( n ); +/*N*/ bIsValue = FALSE; +/*N*/ } + +//------------------------------------------------------------------------ + +/*N*/ ScDetectiveRefIter::ScDetectiveRefIter( ScFormulaCell* pCell ) +/*N*/ { +/*N*/ pCode = pCell->GetCode(); +/*N*/ pCode->Reset(); +/*N*/ aPos = pCell->aPos; +/*N*/ } + +/*N*/ BOOL lcl_ScDetectiveRefIter_SkipRef( ScToken* p ) +/*N*/ { +/*N*/ SingleRefData& rRef1 = p->GetSingleRef(); +/*N*/ if ( rRef1.IsColDeleted() || rRef1.IsRowDeleted() || rRef1.IsTabDeleted() +/*N*/ || !rRef1.Valid() ) +/*N*/ return TRUE; +/*N*/ if ( p->GetType() == svDoubleRef ) +/*N*/ { +/*N*/ SingleRefData& rRef2 = p->GetDoubleRef().Ref2; +/*N*/ if ( rRef2.IsColDeleted() || rRef2.IsRowDeleted() || rRef2.IsTabDeleted() +/*N*/ || !rRef2.Valid() ) +/*N*/ return TRUE; +/*N*/ } +/*N*/ return FALSE; +/*N*/ } + +/*N*/ BOOL ScDetectiveRefIter::GetNextRef( ScTripel& rStart, ScTripel& rEnd ) +/*N*/ { +/*N*/ BOOL bRet = FALSE; +/*N*/ +/*N*/ ScToken* p = pCode->GetNextReferenceRPN(); +/*N*/ if (p) +/*N*/ p->CalcAbsIfRel( aPos ); +/*N*/ +/*N*/ while ( p && lcl_ScDetectiveRefIter_SkipRef( p ) ) +/*N*/ { +/*N*/ p = pCode->GetNextReferenceRPN(); +/*N*/ if (p) +/*N*/ p->CalcAbsIfRel( aPos ); +/*N*/ } +/*N*/ +/*N*/ if( p ) +/*N*/ { +/*N*/ SingleDoubleRefProvider aProv( *p ); +/*N*/ rStart.Put( aProv.Ref1.nCol, +/*N*/ aProv.Ref1.nRow, +/*N*/ aProv.Ref1.nTab ); +/*N*/ rEnd.Put( aProv.Ref2.nCol, +/*N*/ aProv.Ref2.nRow, +/*N*/ aProv.Ref2.nTab ); +/*N*/ bRet = TRUE; +/*N*/ } +/*N*/ +/*N*/ return bRet; +/*N*/ } + +//----------------------------------------------------------------------------------- + +/*N*/ ScFormulaCell::~ScFormulaCell() +/*N*/ { +/*N*/ pDocument->RemoveFromFormulaTree( this ); +/*N*/ delete pCode; +/*N*/ delete pMatrix; +/*N*/ pMatrix = NULL; +/*N*/ #ifdef DBG_UTIL +/*N*/ eCellType = CELLTYPE_DESTROYED; +/*N*/ #endif +/*N*/ } + + +/*N*/ #ifdef DBG_UTIL +/*N*/ +/*N*/ ScStringCell::~ScStringCell() +/*N*/ { +/*N*/ eCellType = CELLTYPE_DESTROYED; +/*N*/ } +/*N*/ #endif + //! ValueCell auch nur bei DBG_UTIL, + //! auch in cell.hxx aendern !!!!!!!!!!!!!!!!!!!! + +/*N*/ ScValueCell::~ScValueCell() +/*N*/ { +/*N*/ eCellType = CELLTYPE_DESTROYED; +/*N*/ } + +/*N*/ #ifdef DBG_UTIL +/*N*/ +/*N*/ ScNoteCell::~ScNoteCell() +/*N*/ { +/*N*/ eCellType = CELLTYPE_DESTROYED; +/*N*/ } +/*N*/ #endif + + + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |