1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: cell.cxx,v $
10 * $Revision: 1.44.38.6 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include <svtools/zforlist.hxx>
38 #include "scitems.hxx"
41 #include "compiler.hxx"
42 #include "interpre.hxx"
43 #include "document.hxx"
44 #include "scmatrix.hxx"
45 #include "dociter.hxx"
46 #include "docoptio.hxx"
47 #include "rechead.hxx"
48 #include "rangenam.hxx"
50 #include "ddelink.hxx"
51 #include "validat.hxx"
52 #include "progress.hxx"
53 #include "editutil.hxx"
54 #include "recursionhelper.hxx"
56 #include "externalrefmgr.hxx"
57 #include "macromgr.hxx"
58 #include <svx/editobj.hxx>
59 #include <svtools/intitem.hxx>
60 #include <svx/flditem.hxx>
61 #include <svtools/broadcast.hxx>
63 using namespace formula
;
64 // More or less arbitrary, of course all recursions must fit into available
65 // stack space (which is what on all systems we don't know yet?). Choosing a
66 // lower value may be better than trying a much higher value that also isn't
67 // sufficient but temporarily leads to high memory consumption. On the other
68 // hand, if the value fits all recursions, execution is quicker as no resumes
69 // are necessary. Could be made a configurable option.
70 // Allow for a year's calendar (366).
71 const USHORT MAXRECURSION
= 400;
73 // STATIC DATA -----------------------------------------------------------
76 // MemPools auf 4k Boundaries - 64 Bytes ausrichten
77 const USHORT nMemPoolValueCell
= (0x8000 - 64) / sizeof(ScValueCell
);
78 const USHORT nMemPoolFormulaCell
= (0x8000 - 64) / sizeof(ScFormulaCell
);
79 const USHORT nMemPoolStringCell
= (0x4000 - 64) / sizeof(ScStringCell
);
80 const USHORT nMemPoolNoteCell
= (0x1000 - 64) / sizeof(ScNoteCell
);
81 const USHORT nMemPoolAsianStringCell
= (0x4000 - 64) / sizeof(ScAsianStringCell
);
82 const USHORT nMemPoolAsianEditCell
= (0x4000 - 64) / sizeof(ScAsianEditCell
);
83 IMPL_FIXEDMEMPOOL_NEWDEL( ScValueCell
, nMemPoolValueCell
, nMemPoolValueCell
)
84 IMPL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell
, nMemPoolFormulaCell
, nMemPoolFormulaCell
)
85 IMPL_FIXEDMEMPOOL_NEWDEL( ScStringCell
, nMemPoolStringCell
, nMemPoolStringCell
)
86 IMPL_FIXEDMEMPOOL_NEWDEL( ScNoteCell
, nMemPoolNoteCell
, nMemPoolNoteCell
)
87 IMPL_FIXEDMEMPOOL_NEWDEL( ScAsianStringCell
, nMemPoolAsianStringCell
, nMemPoolAsianStringCell
)
88 IMPL_FIXEDMEMPOOL_NEWDEL( ScAsianEditCell
, nMemPoolAsianEditCell
, nMemPoolAsianEditCell
)
91 // ============================================================================
93 ScBaseCell::ScBaseCell( CellType eNewType
) :
96 nTextWidth( TEXTWIDTH_DIRTY
),
97 eCellType( sal::static_int_cast
<BYTE
>(eNewType
) ),
98 nScriptType( SC_SCRIPTTYPE_UNKNOWN
)
102 ScBaseCell::ScBaseCell( const ScBaseCell
& rCell
) :
105 nTextWidth( rCell
.nTextWidth
),
106 eCellType( rCell
.eCellType
),
107 nScriptType( SC_SCRIPTTYPE_UNKNOWN
)
111 ScBaseCell::~ScBaseCell()
114 delete mpBroadcaster
;
115 DBG_ASSERT( eCellType
== CELLTYPE_DESTROYED
, "BaseCell Destructor" );
120 ScBaseCell
* lclCloneCell( const ScBaseCell
& rSrcCell
, ScDocument
& rDestDoc
, const ScAddress
& rDestPos
, int nCloneFlags
)
122 switch( rSrcCell
.GetCellType() )
125 return new ScValueCell( static_cast< const ScValueCell
& >( rSrcCell
) );
126 case CELLTYPE_STRING
:
127 return new ScStringCell( static_cast< const ScStringCell
& >( rSrcCell
) );
129 return new ScEditCell( static_cast< const ScEditCell
& >( rSrcCell
), rDestDoc
);
130 case CELLTYPE_FORMULA
:
131 return new ScFormulaCell( static_cast< const ScFormulaCell
& >( rSrcCell
), rDestDoc
, rDestPos
, nCloneFlags
);
133 return new ScNoteCell
;
136 DBG_ERROR( "lclCloneCell - unknown cell type" );
142 ScBaseCell
* ScBaseCell::CloneWithoutNote( ScDocument
& rDestDoc
, int nCloneFlags
) const
144 // notes will not be cloned -> cell address only needed for formula cells
146 if( eCellType
== CELLTYPE_FORMULA
)
147 aDestPos
= static_cast< const ScFormulaCell
* >( this )->aPos
;
148 return lclCloneCell( *this, rDestDoc
, aDestPos
, nCloneFlags
);
151 ScBaseCell
* ScBaseCell::CloneWithoutNote( ScDocument
& rDestDoc
, const ScAddress
& rDestPos
, int nCloneFlags
) const
153 return lclCloneCell( *this, rDestDoc
, rDestPos
, nCloneFlags
);
156 ScBaseCell
* ScBaseCell::CloneWithNote( const ScAddress
& rOwnPos
, ScDocument
& rDestDoc
, const ScAddress
& rDestPos
, int nCloneFlags
) const
158 ScBaseCell
* pNewCell
= lclCloneCell( *this, rDestDoc
, rDestPos
, nCloneFlags
);
162 pNewCell
= new ScNoteCell
;
163 bool bCloneCaption
= (nCloneFlags
& SC_CLONECELL_NOCAPTION
) == 0;
164 pNewCell
->TakeNote( mpNote
->Clone( rOwnPos
, rDestDoc
, rDestPos
, bCloneCaption
) );
169 void ScBaseCell::Delete()
175 delete (ScValueCell
*) this;
177 case CELLTYPE_STRING
:
178 delete (ScStringCell
*) this;
181 delete (ScEditCell
*) this;
183 case CELLTYPE_FORMULA
:
184 delete (ScFormulaCell
*) this;
187 delete (ScNoteCell
*) this;
190 DBG_ERROR("Unbekannter Zellentyp");
195 bool ScBaseCell::IsBlank( bool bIgnoreNotes
) const
197 return (eCellType
== CELLTYPE_NOTE
) && (bIgnoreNotes
|| !mpNote
);
200 void ScBaseCell::TakeNote( ScPostIt
* pNote
)
206 ScPostIt
* ScBaseCell::ReleaseNote()
208 ScPostIt
* pNote
= mpNote
;
213 void ScBaseCell::DeleteNote()
218 void ScBaseCell::TakeBroadcaster( SvtBroadcaster
* pBroadcaster
)
220 delete mpBroadcaster
;
221 mpBroadcaster
= pBroadcaster
;
224 SvtBroadcaster
* ScBaseCell::ReleaseBroadcaster()
226 SvtBroadcaster
* pBroadcaster
= mpBroadcaster
;
231 void ScBaseCell::DeleteBroadcaster()
233 DELETEZ( mpBroadcaster
);
236 ScBaseCell
* ScBaseCell::CreateTextCell( const String
& rString
, ScDocument
* pDoc
)
238 if ( rString
.Search('\n') != STRING_NOTFOUND
|| rString
.Search(CHAR_CR
) != STRING_NOTFOUND
)
239 return new ScEditCell( rString
, pDoc
);
241 return new ScStringCell( rString
);
244 void ScBaseCell::StartListeningTo( ScDocument
* pDoc
)
246 if ( eCellType
== CELLTYPE_FORMULA
&& !pDoc
->IsClipOrUndo()
247 && !pDoc
->GetNoListening()
248 && !((ScFormulaCell
*)this)->IsInChangeTrack()
251 pDoc
->SetDetectiveDirty(TRUE
); // es hat sich was geaendert...
253 ScFormulaCell
* pFormCell
= (ScFormulaCell
*)this;
254 ScTokenArray
* pArr
= pFormCell
->GetCode();
255 if( pArr
->IsRecalcModeAlways() )
256 pDoc
->StartListeningArea( BCA_LISTEN_ALWAYS
, pFormCell
);
261 while ( ( t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN()) ) != NULL
)
263 StackVar eType
= t
->GetType();
264 ScSingleRefData
& rRef1
= t
->GetSingleRef();
265 ScSingleRefData
& rRef2
= (eType
== svDoubleRef
?
266 t
->GetDoubleRef().Ref2
: rRef1
);
270 rRef1
.CalcAbsIfRel( pFormCell
->aPos
);
273 pDoc
->StartListeningCell(
274 ScAddress( rRef1
.nCol
,
276 rRef1
.nTab
), pFormCell
);
280 t
->CalcAbsIfRel( pFormCell
->aPos
);
281 if ( rRef1
.Valid() && rRef2
.Valid() )
283 if ( t
->GetOpCode() == ocColRowNameAuto
)
285 if ( rRef1
.IsColRel() )
287 pDoc
->StartListeningArea( ScRange (
293 rRef2
.nTab
), pFormCell
);
297 pDoc
->StartListeningArea( ScRange (
303 rRef2
.nTab
), pFormCell
);
308 pDoc
->StartListeningArea( ScRange (
314 rRef2
.nTab
), pFormCell
);
323 pFormCell
->SetNeedsListening( FALSE
);
327 // pArr gesetzt -> Referenzen von anderer Zelle nehmen
328 // dann muss auch aPos uebergeben werden!
330 void ScBaseCell::EndListeningTo( ScDocument
* pDoc
, ScTokenArray
* pArr
,
333 if ( eCellType
== CELLTYPE_FORMULA
&& !pDoc
->IsClipOrUndo()
334 && !((ScFormulaCell
*)this)->IsInChangeTrack()
337 pDoc
->SetDetectiveDirty(TRUE
); // es hat sich was geaendert...
339 ScFormulaCell
* pFormCell
= (ScFormulaCell
*)this;
340 if( pFormCell
->GetCode()->IsRecalcModeAlways() )
341 pDoc
->EndListeningArea( BCA_LISTEN_ALWAYS
, pFormCell
);
346 pArr
= pFormCell
->GetCode();
347 aPos
= pFormCell
->aPos
;
351 while ( ( t
= static_cast<ScToken
*>(pArr
->GetNextReferenceRPN()) ) != NULL
)
353 StackVar eType
= t
->GetType();
354 ScSingleRefData
& rRef1
= t
->GetSingleRef();
355 ScSingleRefData
& rRef2
= (eType
== svDoubleRef
?
356 t
->GetDoubleRef().Ref2
: rRef1
);
360 rRef1
.CalcAbsIfRel( aPos
);
363 pDoc
->EndListeningCell(
364 ScAddress( rRef1
.nCol
,
366 rRef1
.nTab
), pFormCell
);
370 t
->CalcAbsIfRel( aPos
);
371 if ( rRef1
.Valid() && rRef2
.Valid() )
373 if ( t
->GetOpCode() == ocColRowNameAuto
)
375 if ( rRef1
.IsColRel() )
377 pDoc
->EndListeningArea( ScRange (
383 rRef2
.nTab
), pFormCell
);
387 pDoc
->EndListeningArea( ScRange (
393 rRef2
.nTab
), pFormCell
);
398 pDoc
->EndListeningArea( ScRange (
404 rRef2
.nTab
), pFormCell
);
417 USHORT
ScBaseCell::GetErrorCode() const
421 case CELLTYPE_FORMULA
:
422 return ((ScFormulaCell
*)this)->GetErrCode();
429 BOOL
ScBaseCell::HasEmptyData() const
435 case CELLTYPE_FORMULA
:
436 return ((ScFormulaCell
*)this)->IsEmpty();
443 BOOL
ScBaseCell::HasValueData() const
447 case CELLTYPE_VALUE
:
449 case CELLTYPE_FORMULA
:
450 return ((ScFormulaCell
*)this)->IsValue();
457 BOOL
ScBaseCell::HasStringData() const
461 case CELLTYPE_STRING
:
464 case CELLTYPE_FORMULA
:
465 return !((ScFormulaCell
*)this)->IsValue();
471 String
ScBaseCell::GetStringData() const
476 case CELLTYPE_STRING
:
477 ((const ScStringCell
*)this)->GetString( aStr
);
480 ((const ScEditCell
*)this)->GetString( aStr
);
482 case CELLTYPE_FORMULA
:
483 ((ScFormulaCell
*)this)->GetString( aStr
); // an der Formelzelle nicht-const
490 BOOL
ScBaseCell::CellEqual( const ScBaseCell
* pCell1
, const ScBaseCell
* pCell2
)
492 CellType eType1
= CELLTYPE_NONE
;
493 CellType eType2
= CELLTYPE_NONE
;
496 eType1
= pCell1
->GetCellType();
497 if (eType1
== CELLTYPE_EDIT
)
498 eType1
= CELLTYPE_STRING
;
499 else if (eType1
== CELLTYPE_NOTE
)
500 eType1
= CELLTYPE_NONE
;
504 eType2
= pCell2
->GetCellType();
505 if (eType2
== CELLTYPE_EDIT
)
506 eType2
= CELLTYPE_STRING
;
507 else if (eType2
== CELLTYPE_NOTE
)
508 eType2
= CELLTYPE_NONE
;
510 if ( eType1
!= eType2
)
513 switch ( eType1
) // beide Typen gleich
515 case CELLTYPE_NONE
: // beide leer
517 case CELLTYPE_VALUE
: // wirklich Value-Zellen
518 return ( ((const ScValueCell
*)pCell1
)->GetValue() ==
519 ((const ScValueCell
*)pCell2
)->GetValue() );
520 case CELLTYPE_STRING
: // String oder Edit
522 String aText1
, aText2
;
523 const ScStringCell
* pStrCell1
= static_cast<const ScStringCell
*>(pCell1
);
524 const ScStringCell
* pStrCell2
= static_cast<const ScStringCell
*>(pCell2
);
525 pStrCell1
->GetString( aText1
);
526 pStrCell2
->GetString( aText2
);
527 if (aText1
!= aText2
)
530 ScPhonetic aPhonetic1
, aPhonetic2
;
531 if (pStrCell1
->HasPhonetic())
533 const ScAsianStringCell
* pPhoCell1
=
534 static_cast<const ScAsianStringCell
*>(pStrCell1
);
535 pPhoCell1
->GetPhonetic(aPhonetic1
);
537 if (pStrCell2
->HasPhonetic())
539 const ScAsianStringCell
* pPhoCell2
=
540 static_cast<const ScAsianStringCell
*>(pStrCell2
);
541 pPhoCell2
->GetPhonetic(aPhonetic2
);
544 return aPhonetic1
== aPhonetic2
;
546 case CELLTYPE_FORMULA
:
548 //! eingefuegte Zeilen / Spalten beruecksichtigen !!!!!
549 //! Vergleichsfunktion an der Formelzelle ???
550 //! Abfrage mit ScColumn::SwapRow zusammenfassen!
552 ScTokenArray
* pCode1
= ((ScFormulaCell
*)pCell1
)->GetCode();
553 ScTokenArray
* pCode2
= ((ScFormulaCell
*)pCell2
)->GetCode();
555 if (pCode1
->GetLen() == pCode2
->GetLen()) // nicht-UPN
558 USHORT nLen
= pCode1
->GetLen();
559 FormulaToken
** ppToken1
= pCode1
->GetArray();
560 FormulaToken
** ppToken2
= pCode2
->GetArray();
561 for (USHORT i
=0; i
<nLen
; i
++)
562 if ( !ppToken1
[i
]->TextEqual(*(ppToken2
[i
])) )
572 return FALSE
; // unterschiedlich lang oder unterschiedliche Tokens
575 DBG_ERROR("huch, was fuer Zellen???");
580 // ============================================================================
582 ScNoteCell::ScNoteCell( SvtBroadcaster
* pBC
) :
583 ScBaseCell( CELLTYPE_NOTE
)
585 TakeBroadcaster( pBC
);
588 ScNoteCell::ScNoteCell( ScPostIt
* pNote
, SvtBroadcaster
* pBC
) :
589 ScBaseCell( CELLTYPE_NOTE
)
592 TakeBroadcaster( pBC
);
596 ScNoteCell::~ScNoteCell()
598 eCellType
= CELLTYPE_DESTROYED
;
602 // ============================================================================
604 ScValueCell::ScValueCell() :
605 ScBaseCell( CELLTYPE_VALUE
),
610 ScValueCell::ScValueCell( double fValue
) :
611 ScBaseCell( CELLTYPE_VALUE
),
617 ScValueCell::~ScValueCell()
619 eCellType
= CELLTYPE_DESTROYED
;
623 // ============================================================================
625 ScStringCell::ScStringCell() :
626 ScBaseCell( CELLTYPE_STRING
)
630 ScStringCell::ScStringCell( const String
& rString
) :
631 ScBaseCell( CELLTYPE_STRING
),
632 maString( rString
.intern() )
637 ScStringCell::~ScStringCell()
639 eCellType
= CELLTYPE_DESTROYED
;
643 // ============================================================================
649 ScFormulaCell::ScFormulaCell() :
650 ScBaseCell( CELLTYPE_FORMULA
),
651 eTempGrammar( FormulaGrammar::GRAM_DEFAULT
),
659 nFormatType( NUMBERFORMAT_NUMBER
),
661 cMatrixFlag ( MM_NONE
),
667 bIsIterCell( FALSE
),
668 bInChangeTrack( FALSE
),
669 bTableOpDirty( FALSE
),
670 bNeedListening( FALSE
),
675 ScFormulaCell::ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
,
676 const String
& rFormula
,
677 const FormulaGrammar::Grammar eGrammar
,
679 ScBaseCell( CELLTYPE_FORMULA
),
680 eTempGrammar( eGrammar
),
688 nFormatType( NUMBERFORMAT_NUMBER
),
690 cMatrixFlag ( cMatInd
),
691 bDirty( TRUE
), // -> wg. Benutzung im Fkt.AutoPiloten, war: cMatInd != 0
696 bIsIterCell( FALSE
),
697 bInChangeTrack( FALSE
),
698 bTableOpDirty( FALSE
),
699 bNeedListening( FALSE
),
702 Compile( rFormula
, TRUE
, eGrammar
); // bNoListening, Insert does that
705 // Wird von den Importfiltern verwendet
707 ScFormulaCell::ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
,
708 const ScTokenArray
* pArr
,
709 const FormulaGrammar::Grammar eGrammar
, BYTE cInd
) :
710 ScBaseCell( CELLTYPE_FORMULA
),
711 eTempGrammar( eGrammar
),
712 pCode( pArr
? new ScTokenArray( *pArr
) : new ScTokenArray
),
719 nFormatType( NUMBERFORMAT_NUMBER
),
721 cMatrixFlag ( cInd
),
722 bDirty( NULL
!= pArr
), // -> wg. Benutzung im Fkt.AutoPiloten, war: cInd != 0
727 bIsIterCell( FALSE
),
728 bInChangeTrack( FALSE
),
729 bTableOpDirty( FALSE
),
730 bNeedListening( FALSE
),
733 // UPN-Array erzeugen
734 if( pCode
->GetLen() && !pCode
->GetCodeError() && !pCode
->GetCodeLen() )
736 ScCompiler
aComp( pDocument
, aPos
, *pCode
);
737 aComp
.SetGrammar(eTempGrammar
);
738 bSubTotal
= aComp
.CompileTokenArray();
739 nFormatType
= aComp
.GetNumFormatType();
744 if ( pCode
->GetNextOpCodeRPN( ocSubTotal
) )
749 ScFormulaCell::ScFormulaCell( const ScFormulaCell
& rCell
, ScDocument
& rDoc
, const ScAddress
& rPos
, int nCloneFlags
) :
752 aResult( rCell
.aResult
),
753 eTempGrammar( rCell
.eTempGrammar
),
759 nFormatIndex( &rDoc
== rCell
.pDocument
? rCell
.nFormatIndex
: 0 ),
760 nFormatType( rCell
.nFormatType
),
762 cMatrixFlag ( rCell
.cMatrixFlag
),
763 bDirty( rCell
.bDirty
),
764 bChanged( rCell
.bChanged
),
766 bCompile( rCell
.bCompile
),
767 bSubTotal( rCell
.bSubTotal
),
768 bIsIterCell( FALSE
),
769 bInChangeTrack( FALSE
),
770 bTableOpDirty( FALSE
),
771 bNeedListening( FALSE
),
774 pCode
= rCell
.pCode
->Clone();
776 if ( nCloneFlags
& SC_CLONECELL_ADJUST3DREL
)
777 pCode
->ReadjustRelative3DReferences( rCell
.aPos
, aPos
);
779 // evtl. Fehler zuruecksetzen und neu kompilieren
780 // nicht im Clipboard - da muss das Fehlerflag erhalten bleiben
781 // Spezialfall Laenge=0: als Fehlerzelle erzeugt, dann auch Fehler behalten
782 if ( pCode
->GetCodeError() && !pDocument
->IsClipboard() && pCode
->GetLen() )
784 pCode
->SetCodeError( 0 );
787 //! Compile ColRowNames on URM_MOVE/URM_COPY _after_ UpdateReference
788 BOOL bCompileLater
= FALSE
;
789 BOOL bClipMode
= rCell
.pDocument
->IsClipboard();
791 { // Name references with references and ColRowNames
794 while ( ( t
= static_cast<ScToken
*>(pCode
->GetNextReferenceOrName()) ) != NULL
&& !bCompile
)
796 if ( t
->GetOpCode() == ocExternalRef
)
798 // External name, cell, and area references.
801 else if ( t
->GetType() == svIndex
)
803 ScRangeData
* pRangeData
= rDoc
.GetRangeName()->FindIndex( t
->GetIndex() );
806 if( pRangeData
->HasReferences() )
810 bCompile
= TRUE
; // invalid reference!
812 else if ( t
->GetOpCode() == ocColRowName
)
814 bCompile
= TRUE
; // new lookup needed
815 bCompileLater
= bClipMode
;
821 if ( !bCompileLater
&& bClipMode
)
823 // Merging ranges needs the actual positions after UpdateReference.
824 // ColRowNames need new lookup after positions are adjusted.
825 bCompileLater
= pCode
->HasOpCode( ocRange
) || pCode
->HasOpCode( ocColRowName
);
827 if ( !bCompileLater
)
829 // bNoListening, not at all if in Clipboard/Undo,
830 // and not from Clipboard either, instead after Insert(Clone) and UpdateReference.
831 CompileTokenArray( TRUE
);
835 if( nCloneFlags
& SC_CLONECELL_STARTLISTENING
)
836 StartListeningTo( &rDoc
);
839 ScFormulaCell::~ScFormulaCell()
841 pDocument
->RemoveFromFormulaTree( this );
842 if (pCode
->HasOpCode(ocMacro
))
843 pDocument
->GetMacroManager()->RemoveDependentCell(this);
847 eCellType
= CELLTYPE_DESTROYED
;
851 void ScFormulaCell::GetFormula( rtl::OUStringBuffer
& rBuffer
,
852 const FormulaGrammar::Grammar eGrammar
) const
854 if( pCode
->GetCodeError() && !pCode
->GetLen() )
856 rBuffer
= rtl::OUStringBuffer( ScGlobal::GetErrorString( pCode
->GetCodeError()));
859 else if( cMatrixFlag
== MM_REFERENCE
)
861 // Reference to another cell that contains a matrix formula.
863 ScToken
* p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
866 /* FIXME: original GetFormula() code obtained
867 * pCell only if (!this->IsInChangeTrack()),
868 * GetEnglishFormula() omitted that test.
869 * Can we live without in all cases? */
871 ScSingleRefData
& rRef
= p
->GetSingleRef();
872 rRef
.CalcAbsIfRel( aPos
);
874 pCell
= pDocument
->GetCell( ScAddress( rRef
.nCol
,
875 rRef
.nRow
, rRef
.nTab
) );
878 if (pCell
&& pCell
->GetCellType() == CELLTYPE_FORMULA
)
880 ((ScFormulaCell
*)pCell
)->GetFormula( rBuffer
, eGrammar
);
885 ScCompiler
aComp( pDocument
, aPos
, *pCode
);
886 aComp
.SetGrammar(eGrammar
);
887 aComp
.CreateStringFromTokenArray( rBuffer
);
892 DBG_ERROR("ScFormulaCell::GetFormula: not a matrix");
897 ScCompiler
aComp( pDocument
, aPos
, *pCode
);
898 aComp
.SetGrammar(eGrammar
);
899 aComp
.CreateStringFromTokenArray( rBuffer
);
903 rBuffer
.insert( 0, &ch
, 1 );
906 sal_Unicode
ch2('{');
907 rBuffer
.insert( 0, &ch2
, 1);
908 rBuffer
.append( sal_Unicode('}'));
912 void ScFormulaCell::GetFormula( String
& rFormula
, const FormulaGrammar::Grammar eGrammar
) const
914 rtl::OUStringBuffer
rBuffer( rFormula
);
915 GetFormula( rBuffer
, eGrammar
);
919 void ScFormulaCell::GetResultDimensions( SCSIZE
& rCols
, SCSIZE
& rRows
)
921 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
924 const ScMatrix
* pMat
= NULL
;
925 if (!pCode
->GetCodeError() && aResult
.GetType() == svMatrixCell
&&
926 ((pMat
= static_cast<const ScToken
*>(aResult
.GetToken().get())->GetMatrix()) != 0))
927 pMat
->GetDimensions( rCols
, rRows
);
935 void ScFormulaCell::Compile( const String
& rFormula
, BOOL bNoListening
,
936 const FormulaGrammar::Grammar eGrammar
)
938 if ( pDocument
->IsClipOrUndo() ) return;
939 BOOL bWasInFormulaTree
= pDocument
->IsInFormulaTree( this );
940 if ( bWasInFormulaTree
)
941 pDocument
->RemoveFromFormulaTree( this );
942 // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein
945 ScTokenArray
* pCodeOld
= pCode
;
946 ScCompiler
aComp( pDocument
, aPos
);
947 aComp
.SetGrammar(eGrammar
);
948 pCode
= aComp
.CompileString( rFormula
);
951 if( !pCode
->GetCodeError() )
953 if ( !pCode
->GetLen() && aResult
.GetHybridFormula().Len() && rFormula
== aResult
.GetHybridFormula() )
954 { // #65994# nicht rekursiv CompileTokenArray/Compile/CompileTokenArray
955 if ( rFormula
.GetChar(0) == '=' )
956 pCode
->AddBad( rFormula
.GetBuffer() + 1 );
958 pCode
->AddBad( rFormula
.GetBuffer() );
961 CompileTokenArray( bNoListening
);
966 SetTextWidth( TEXTWIDTH_DIRTY
);
967 SetScriptType( SC_SCRIPTTYPE_UNKNOWN
);
969 if ( bWasInFormulaTree
)
970 pDocument
->PutInFormulaTree( this );
974 void ScFormulaCell::CompileTokenArray( BOOL bNoListening
)
976 // Not already compiled?
977 if( !pCode
->GetLen() && aResult
.GetHybridFormula().Len() )
978 Compile( aResult
.GetHybridFormula(), bNoListening
, eTempGrammar
);
979 else if( bCompile
&& !pDocument
->IsClipOrUndo() && !pCode
->GetCodeError() )
981 // RPN length may get changed
982 BOOL bWasInFormulaTree
= pDocument
->IsInFormulaTree( this );
983 if ( bWasInFormulaTree
)
984 pDocument
->RemoveFromFormulaTree( this );
986 // Loading from within filter? No listening yet!
987 if( pDocument
->IsInsertingFromOtherDoc() )
990 if( !bNoListening
&& pCode
->GetCodeLen() )
991 EndListeningTo( pDocument
);
992 ScCompiler
aComp(pDocument
, aPos
, *pCode
);
993 aComp
.SetGrammar(pDocument
->GetGrammar());
994 bSubTotal
= aComp
.CompileTokenArray();
995 if( !pCode
->GetCodeError() )
997 nFormatType
= aComp
.GetNumFormatType();
1000 aResult
.SetToken( NULL
);
1002 if ( !bNoListening
)
1003 StartListeningTo( pDocument
);
1005 if ( bWasInFormulaTree
)
1006 pDocument
->PutInFormulaTree( this );
1011 void ScFormulaCell::CompileXML( ScProgress
& rProgress
)
1013 if ( cMatrixFlag
== MM_REFERENCE
)
1014 { // is already token code via ScDocFunc::EnterMatrix, ScDocument::InsertMatrixFormula
1015 // just establish listeners
1016 StartListeningTo( pDocument
);
1020 ScCompiler
aComp( pDocument
, aPos
, *pCode
);
1021 aComp
.SetGrammar(eTempGrammar
);
1022 String aFormula
, aFormulaNmsp
;
1023 aComp
.CreateStringFromXMLTokenArray( aFormula
, aFormulaNmsp
);
1024 pDocument
->DecXMLImportedFormulaCount( aFormula
.Len() );
1025 rProgress
.SetStateCountDownOnPercent( pDocument
->GetXMLImportedFormulaCount() );
1026 // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein
1029 ScTokenArray
* pCodeOld
= pCode
;
1030 pCode
= aComp
.CompileString( aFormula
, aFormulaNmsp
);
1032 if( !pCode
->GetCodeError() )
1034 if ( !pCode
->GetLen() )
1036 if ( aFormula
.GetChar(0) == '=' )
1037 pCode
->AddBad( aFormula
.GetBuffer() + 1 );
1039 pCode
->AddBad( aFormula
.GetBuffer() );
1041 bSubTotal
= aComp
.CompileTokenArray();
1042 if( !pCode
->GetCodeError() )
1044 nFormatType
= aComp
.GetNumFormatType();
1048 StartListeningTo( pDocument
);
1054 SetTextWidth( TEXTWIDTH_DIRTY
);
1055 SetScriptType( SC_SCRIPTTYPE_UNKNOWN
);
1058 // Same as in Load: after loading, it must be known if ocMacro is in any formula
1059 // (for macro warning, CompileXML is called at the end of loading XML file)
1060 if ( !pDocument
->GetHasMacroFunc() && pCode
->HasOpCodeRPN( ocMacro
) )
1061 pDocument
->SetHasMacroFunc( TRUE
);
1065 void ScFormulaCell::CalcAfterLoad()
1067 BOOL bNewCompiled
= FALSE
;
1068 // Falls ein Calc 1.0-Doc eingelesen wird, haben wir ein Ergebnis,
1069 // aber kein TokenArray
1070 if( !pCode
->GetLen() && aResult
.GetHybridFormula().Len() )
1072 Compile( aResult
.GetHybridFormula(), TRUE
, eTempGrammar
);
1073 aResult
.SetToken( NULL
);
1075 bNewCompiled
= TRUE
;
1077 // Das UPN-Array wird nicht erzeugt, wenn ein Calc 3.0-Doc eingelesen
1078 // wurde, da die RangeNames erst jetzt existieren.
1079 if( pCode
->GetLen() && !pCode
->GetCodeLen() && !pCode
->GetCodeError() )
1081 ScCompiler
aComp(pDocument
, aPos
, *pCode
);
1082 aComp
.SetGrammar(pDocument
->GetGrammar());
1083 bSubTotal
= aComp
.CompileTokenArray();
1084 nFormatType
= aComp
.GetNumFormatType();
1088 bNewCompiled
= TRUE
;
1090 // irgendwie koennen unter os/2 mit rotter FPU-Exception /0 ohne Err503
1091 // gespeichert werden, woraufhin spaeter im NumberFormatter die BLC Lib
1092 // bei einem fabs(-NAN) abstuerzt (#32739#)
1093 // hier fuer alle Systeme ausbuegeln, damit da auch Err503 steht
1094 if ( aResult
.IsValue() && !::rtl::math::isFinite( aResult
.GetDouble() ) )
1096 DBG_ERRORFILE("Formelzelle INFINITY !!! Woher kommt das Dokument?");
1097 aResult
.SetResultError( errIllegalFPOperation
);
1100 // DoubleRefs bei binaeren Operatoren waren vor v5.0 immer Matrix,
1101 // jetzt nur noch wenn in Matrixformel, sonst implizite Schnittmenge
1102 if ( pDocument
->GetSrcVersion() < SC_MATRIX_DOUBLEREF
&&
1103 GetMatrixFlag() == MM_NONE
&& pCode
->HasMatrixDoubleRefOps() )
1105 cMatrixFlag
= MM_FORMULA
;
1106 SetMatColsRows( 1, 1);
1108 // Muss die Zelle berechnet werden?
1109 // Nach Load koennen Zellen einen Fehlercode enthalten, auch dann
1110 // Listener starten und ggbf. neu berechnen wenn nicht RECALCMODE_NORMAL
1111 if( !bNewCompiled
|| !pCode
->GetCodeError() )
1113 StartListeningTo( pDocument
);
1114 if( !pCode
->IsRecalcModeNormal() )
1117 if ( pCode
->IsRecalcModeAlways() )
1118 { // zufall(), heute(), jetzt() bleiben immer im FormulaTree, damit sie
1119 // auch bei jedem F9 berechnet werden.
1122 // Noch kein SetDirty weil noch nicht alle Listener bekannt, erst in
1123 // SetDirtyAfterLoad.
1127 bool ScFormulaCell::MarkUsedExternalReferences()
1129 return pCode
&& pDocument
->MarkUsedExternalReferences( *pCode
);
1134 #define erDEBUGDOT 0
1135 // If set to 1, write output that's suitable for graphviz tools like dot.
1136 // Only node1 -> node2 entries are written, you'll have to manually surround
1137 // the file content with [strict] digraph name { ... }
1138 // The ``strict'' keyword might be necessary in case of multiple identical
1139 // paths like they occur in iterations, otherwise dot may consume too much
1140 // memory when generating the layout, or you'll get unreadable output. On the
1141 // other hand, information about recurring calculation is lost then.
1142 // Generates output only if variable nDebug is set in debugger, see below.
1143 // FIXME: currently doesn't cope with iterations and recursions. Code fragments
1144 // are a leftover from a previous debug session, meant as a pointer.
1148 using ::std::fprintf
;
1150 static const char aDebugDotFile
[] = "ttt_debug.dot";
1153 void ScFormulaCell::Interpret()
1157 static int nDebug
= 0;
1158 static const int erDEBUGDOTRUN
= 3;
1159 static FILE* pDebugFile
= 0;
1160 static sal_Int32 nDebugRootCount
= 0;
1161 static unsigned int nDebugPathCount
= 0;
1162 static ScAddress
aDebugLastPos( ScAddress::INITIALIZE_INVALID
);
1163 static ScAddress
aDebugThisPos( ScAddress::INITIALIZE_INVALID
);
1164 typedef ::std::vector
< ByteString
> DebugVector
;
1165 static DebugVector aDebugVec
;
1169 static void push( ScFormulaCell
* pCell
)
1171 aDebugThisPos
= pCell
->aPos
;
1172 if (aDebugVec
.empty())
1174 ByteString
aR( "root_");
1175 aR
+= ByteString::CreateFromInt32( ++nDebugRootCount
);
1176 aDebugVec
.push_back( aR
);
1179 pCell
->aPos
.Format( aStr
, SCA_VALID
| SCA_TAB_3D
, pCell
->GetDocument(),
1180 pCell
->GetDocument()->GetAddressConvention() );
1181 ByteString
aB( aStr
, RTL_TEXTENCODING_UTF8
);
1182 aDebugVec
.push_back( aB
);
1186 aDebugLastPos
= aDebugThisPos
;
1187 if (!aDebugVec
.empty())
1189 aDebugVec
.pop_back();
1190 if (aDebugVec
.size() == 1)
1192 aDebugVec
.pop_back();
1193 aDebugLastPos
= ScAddress( ScAddress::INITIALIZE_INVALID
);
1197 DebugElement( ScFormulaCell
* p
) { push(p
); }
1198 ~DebugElement() { pop(); }
1203 static void out( const char* pColor
)
1205 if (nDebug
!= erDEBUGDOTRUN
)
1207 char pColorString
[256];
1208 sprintf( pColorString
, (*pColor
?
1209 ",color=\"%s\",fontcolor=\"%s\"" : "%s%s"), pColor
,
1211 size_t n
= aDebugVec
.size();
1212 fprintf( pDebugFile
,
1213 "\"%s\" -> \"%s\" [label=\"%u\"%s]; // v:%d\n",
1214 aDebugVec
[n
-2].GetBuffer(), aDebugVec
[n
-1].GetBuffer(),
1215 ++nDebugPathCount
, pColorString
, n
-1);
1216 fflush( pDebugFile
);
1219 #define erDEBUGDOT_OUT( p ) (DebugDot::out(p))
1220 #define erDEBUGDOT_ELEMENT_PUSH( p ) (DebugElement::push(p))
1221 #define erDEBUGDOT_ELEMENT_POP() (DebugElement::pop())
1223 #define erDEBUGDOT_OUT( p )
1224 #define erDEBUGDOT_ELEMENT_PUSH( p )
1225 #define erDEBUGDOT_ELEMENT_POP()
1228 if (!IsDirtyOrInTableOpDirty() || pDocument
->GetRecursionHelper().IsInReturn())
1229 return; // no double/triple processing
1232 // Wenn der Aufruf aus einem Reschedule im DdeLink-Update kommt, dirty stehenlassen
1233 // Besser: Dde-Link Update ohne Reschedule oder ganz asynchron !!!
1235 if ( pDocument
->IsInDdeLinkUpdate() )
1239 // set nDebug=1 in debugger to init things
1243 pDebugFile
= fopen( aDebugDotFile
, "a");
1247 nDebug
= erDEBUGDOTRUN
;
1249 // set nDebug=3 (erDEBUGDOTRUN) in debugger to get any output
1250 DebugElement
aDebugElem( this);
1251 // set nDebug=5 in debugger to close output
1255 fclose( pDebugFile
);
1264 if (!pDocument
->GetRecursionHelper().IsDoingIteration() ||
1265 aDebugThisPos
!= aDebugLastPos
)
1266 erDEBUGDOT_OUT(aDebugThisPos
== aDebugLastPos
? "orange" :
1267 (pDocument
->GetRecursionHelper().GetIteration() ? "blue" :
1271 if (!pDocument
->GetDocOptions().IsIter())
1273 aResult
.SetResultError( errCircularReference
);
1277 if (aResult
.GetResultError() == errCircularReference
)
1278 aResult
.SetResultError( 0 );
1280 // Start or add to iteration list.
1281 if (!pDocument
->GetRecursionHelper().IsDoingIteration() ||
1282 !pDocument
->GetRecursionHelper().GetRecursionInIterationStack().top()->bIsIterCell
)
1283 pDocument
->GetRecursionHelper().SetInIterationReturn( true);
1287 // #63038# no multiple interprets for GetErrCode, IsValue, GetValue and
1288 // different entry point recursions. Would also lead to premature
1289 // convergence in iterations.
1290 if (pDocument
->GetRecursionHelper().GetIteration() && nSeenInIteration
==
1291 pDocument
->GetRecursionHelper().GetIteration())
1294 erDEBUGDOT_OUT( pDocument
->GetRecursionHelper().GetIteration() ? "magenta" : "");
1296 ScRecursionHelper
& rRecursionHelper
= pDocument
->GetRecursionHelper();
1297 BOOL bOldRunning
= bRunning
;
1298 if (rRecursionHelper
.GetRecursionCount() > MAXRECURSION
)
1301 rRecursionHelper
.SetInRecursionReturn( true);
1305 InterpretTail( SCITP_NORMAL
);
1308 // While leaving a recursion or iteration stack, insert its cells to the
1309 // recursion list in reverse order.
1310 if (rRecursionHelper
.IsInReturn())
1312 if (rRecursionHelper
.GetRecursionCount() > 0 ||
1313 !rRecursionHelper
.IsDoingRecursion())
1314 rRecursionHelper
.Insert( this, bOldRunning
, aResult
);
1315 bool bIterationFromRecursion
= false;
1316 bool bResumeIteration
= false;
1319 if ((rRecursionHelper
.IsInIterationReturn() &&
1320 rRecursionHelper
.GetRecursionCount() == 0 &&
1321 !rRecursionHelper
.IsDoingIteration()) ||
1322 bIterationFromRecursion
|| bResumeIteration
)
1324 ScFormulaCell
* pIterCell
= this; // scope for debug convenience
1325 bool & rDone
= rRecursionHelper
.GetConvergingReference();
1327 if (!bIterationFromRecursion
&& bResumeIteration
)
1329 bResumeIteration
= false;
1330 // Resuming iteration expands the range.
1331 ScFormulaRecursionList::const_iterator
aOldStart(
1332 rRecursionHelper
.GetLastIterationStart());
1333 rRecursionHelper
.ResumeIteration();
1334 // Mark new cells being in iteration.
1335 for (ScFormulaRecursionList::const_iterator
aIter(
1336 rRecursionHelper
.GetIterationStart()); aIter
!=
1339 pIterCell
= (*aIter
).pCell
;
1340 pIterCell
->bIsIterCell
= TRUE
;
1342 // Mark older cells dirty again, in case they converted
1343 // without accounting for all remaining cells in the circle
1344 // that weren't touched so far, e.g. conditional. Restore
1346 USHORT nIteration
= rRecursionHelper
.GetIteration();
1347 for (ScFormulaRecursionList::const_iterator
aIter(
1348 aOldStart
); aIter
!=
1349 rRecursionHelper
.GetIterationEnd(); ++aIter
)
1351 pIterCell
= (*aIter
).pCell
;
1352 if (pIterCell
->nSeenInIteration
== nIteration
)
1354 if (!pIterCell
->bDirty
|| aIter
== aOldStart
)
1356 pIterCell
->aResult
= (*aIter
).aPreviousResult
;
1358 --pIterCell
->nSeenInIteration
;
1360 pIterCell
->bDirty
= TRUE
;
1365 bResumeIteration
= false;
1366 // Close circle once.
1367 rRecursionHelper
.GetList().back().pCell
->InterpretTail(
1368 SCITP_CLOSE_ITERATION_CIRCLE
);
1369 // Start at 1, init things.
1370 rRecursionHelper
.StartIteration();
1371 // Mark all cells being in iteration.
1372 for (ScFormulaRecursionList::const_iterator
aIter(
1373 rRecursionHelper
.GetIterationStart()); aIter
!=
1374 rRecursionHelper
.GetIterationEnd(); ++aIter
)
1376 pIterCell
= (*aIter
).pCell
;
1377 pIterCell
->bIsIterCell
= TRUE
;
1380 bIterationFromRecursion
= false;
1381 USHORT nIterMax
= pDocument
->GetDocOptions().GetIterCount();
1382 for ( ; rRecursionHelper
.GetIteration() <= nIterMax
&& !rDone
;
1383 rRecursionHelper
.IncIteration())
1386 for ( ScFormulaRecursionList::iterator
aIter(
1387 rRecursionHelper
.GetIterationStart()); aIter
!=
1388 rRecursionHelper
.GetIterationEnd() &&
1389 !rRecursionHelper
.IsInReturn(); ++aIter
)
1391 pIterCell
= (*aIter
).pCell
;
1392 if (pIterCell
->IsDirtyOrInTableOpDirty() &&
1393 rRecursionHelper
.GetIteration() !=
1394 pIterCell
->GetSeenInIteration())
1396 (*aIter
).aPreviousResult
= pIterCell
->aResult
;
1397 pIterCell
->InterpretTail( SCITP_FROM_ITERATION
);
1399 rDone
= rDone
&& !pIterCell
->IsDirtyOrInTableOpDirty();
1401 if (rRecursionHelper
.IsInReturn())
1403 bResumeIteration
= true;
1405 // Don't increment iteration.
1408 if (!bResumeIteration
)
1412 for (ScFormulaRecursionList::const_iterator
aIter(
1413 rRecursionHelper
.GetIterationStart());
1414 aIter
!= rRecursionHelper
.GetIterationEnd();
1417 pIterCell
= (*aIter
).pCell
;
1418 pIterCell
->bIsIterCell
= FALSE
;
1419 pIterCell
->nSeenInIteration
= 0;
1420 pIterCell
->bRunning
= (*aIter
).bOldRunning
;
1425 for (ScFormulaRecursionList::const_iterator
aIter(
1426 rRecursionHelper
.GetIterationStart());
1427 aIter
!= rRecursionHelper
.GetIterationEnd();
1430 pIterCell
= (*aIter
).pCell
;
1431 pIterCell
->bIsIterCell
= FALSE
;
1432 pIterCell
->nSeenInIteration
= 0;
1433 pIterCell
->bRunning
= (*aIter
).bOldRunning
;
1434 // If one cell didn't converge, all cells of this
1435 // circular dependency don't, no matter whether
1436 // single cells did.
1437 pIterCell
->bDirty
= FALSE
;
1438 pIterCell
->bTableOpDirty
= FALSE
;
1439 pIterCell
->aResult
.SetResultError( errNoConvergence
);
1440 pIterCell
->bChanged
= TRUE
;
1441 pIterCell
->SetTextWidth( TEXTWIDTH_DIRTY
);
1442 pIterCell
->SetScriptType( SC_SCRIPTTYPE_UNKNOWN
);
1445 // End this iteration and remove entries.
1446 rRecursionHelper
.EndIteration();
1447 bResumeIteration
= rRecursionHelper
.IsDoingIteration();
1450 if (rRecursionHelper
.IsInRecursionReturn() &&
1451 rRecursionHelper
.GetRecursionCount() == 0 &&
1452 !rRecursionHelper
.IsDoingRecursion())
1454 bIterationFromRecursion
= false;
1455 // Iterate over cells known so far, start with the last cell
1456 // encountered, inserting new cells if another recursion limit
1457 // is reached. Repeat until solved.
1458 rRecursionHelper
.SetDoingRecursion( true);
1461 rRecursionHelper
.SetInRecursionReturn( false);
1462 for (ScFormulaRecursionList::const_iterator
aIter(
1463 rRecursionHelper
.GetStart());
1464 !rRecursionHelper
.IsInReturn() && aIter
!=
1465 rRecursionHelper
.GetEnd(); ++aIter
)
1467 ScFormulaCell
* pCell
= (*aIter
).pCell
;
1468 if (pCell
->IsDirtyOrInTableOpDirty())
1470 pCell
->InterpretTail( SCITP_NORMAL
);
1471 if (!pCell
->IsDirtyOrInTableOpDirty() && !pCell
->IsIterCell())
1472 pCell
->bRunning
= (*aIter
).bOldRunning
;
1475 } while (rRecursionHelper
.IsInRecursionReturn());
1476 rRecursionHelper
.SetDoingRecursion( false);
1477 if (rRecursionHelper
.IsInIterationReturn())
1479 if (!bResumeIteration
)
1480 bIterationFromRecursion
= true;
1482 else if (bResumeIteration
||
1483 rRecursionHelper
.IsDoingIteration())
1484 rRecursionHelper
.GetList().erase(
1485 rRecursionHelper
.GetStart(),
1486 rRecursionHelper
.GetLastIterationStart());
1488 rRecursionHelper
.Clear();
1490 } while (bIterationFromRecursion
|| bResumeIteration
);
1493 // Fire worksheet calculate event
1494 pDocument
->FireCalculateEvent( aPos
.Tab() );
1497 void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam
)
1499 class RecursionCounter
1501 ScRecursionHelper
& rRec
;
1502 bool bStackedInIteration
;
1504 RecursionCounter( ScRecursionHelper
& r
, ScFormulaCell
* p
) : rRec(r
)
1506 bStackedInIteration
= rRec
.IsDoingIteration();
1507 if (bStackedInIteration
)
1508 rRec
.GetRecursionInIterationStack().push( p
);
1509 rRec
.IncRecursionCount();
1513 rRec
.DecRecursionCount();
1514 if (bStackedInIteration
)
1515 rRec
.GetRecursionInIterationStack().pop();
1517 } aRecursionCounter( pDocument
->GetRecursionHelper(), this);
1518 nSeenInIteration
= pDocument
->GetRecursionHelper().GetIteration();
1519 if( !pCode
->GetCodeLen() && !pCode
->GetCodeError() )
1521 // #i11719# no UPN and no error and no token code but result string present
1522 // => interpretation of this cell during name-compilation and unknown names
1523 // => can't exchange underlying code array in CompileTokenArray() /
1524 // Compile() because interpreter's token iterator would crash.
1525 // This should only be a temporary condition and, since we set an
1526 // error, if ran into it again we'd bump into the dirty-clearing
1527 // condition further down.
1528 if ( !pCode
->GetLen() && aResult
.GetHybridFormula().Len() )
1530 pCode
->SetCodeError( errNoCode
);
1531 // This is worth an assertion; if encountered in daily work
1532 // documents we might need another solution. Or just confirm correctness.
1533 DBG_ERRORFILE( "ScFormulaCell::Interpret: no UPN, no error, no token, but string" );
1536 CompileTokenArray();
1539 if( pCode
->GetCodeLen() && pDocument
)
1544 ScInterpreter
* pInt
;
1546 StackCleaner( ScDocument
* pD
, ScInterpreter
* pI
)
1547 : pDoc(pD
), pInt(pI
)
1552 pDoc
->DecInterpretLevel();
1555 pDocument
->IncInterpretLevel();
1556 ScInterpreter
* p
= new ScInterpreter( this, pDocument
, aPos
, *pCode
);
1557 StackCleaner
aStackCleaner( pDocument
, p
);
1558 USHORT nOldErrCode
= aResult
.GetResultError();
1559 if ( nSeenInIteration
== 0 )
1560 { // Only the first time
1561 // With bChanged=FALSE, if a newly compiled cell has a result of
1562 // 0.0, no change is detected and the cell will not be repainted.
1563 // bChanged = FALSE;
1564 aResult
.SetResultError( 0 );
1567 switch ( aResult
.GetResultError() )
1569 case errCircularReference
: // will be determined again if so
1570 aResult
.SetResultError( 0 );
1574 BOOL bOldRunning
= bRunning
;
1577 if (pDocument
->GetRecursionHelper().IsInReturn() && eTailParam
!= SCITP_CLOSE_ITERATION_CIRCLE
)
1579 if (nSeenInIteration
> 0)
1580 --nSeenInIteration
; // retry when iteration is resumed
1583 bRunning
= bOldRunning
;
1585 // Do not create a HyperLink() cell if the formula results in an error.
1586 if( p
->GetError() && pCode
->IsHyperLink())
1587 pCode
->SetHyperLink(FALSE
);
1589 if( p
->GetError() && p
->GetError() != errCircularReference
)
1592 bTableOpDirty
= FALSE
;
1595 if (eTailParam
== SCITP_FROM_ITERATION
&& IsDirtyOrInTableOpDirty())
1597 bool bIsValue
= aResult
.IsValue(); // the previous type
1599 if ((bIsValue
&& p
->GetResultType() == svDouble
&& fabs(
1600 p
->GetNumResult() - aResult
.GetDouble()) <=
1601 pDocument
->GetDocOptions().GetIterEps()) ||
1602 (!bIsValue
&& p
->GetResultType() == svString
&&
1603 p
->GetStringResult() == aResult
.GetString()))
1605 // A convergence in the first iteration doesn't necessarily
1606 // mean that it's done, it may be because not all related cells
1607 // of a circle changed their values yet. If the set really
1608 // converges it will do so also during the next iteration. This
1609 // fixes situations like of #i44115#. If this wasn't wanted an
1610 // initial "uncalculated" value would be needed for all cells
1611 // of a circular dependency => graph needed before calculation.
1612 if (nSeenInIteration
> 1 ||
1613 pDocument
->GetDocOptions().GetIterCount() == 1)
1616 bTableOpDirty
= FALSE
;
1622 if( p
->GetError() != nOldErrCode
)
1624 // Different number format?
1625 if( nFormatType
!= p
->GetRetFormatType() )
1627 nFormatType
= p
->GetRetFormatType();
1630 if( nFormatIndex
!= p
->GetRetFormatIndex() )
1632 nFormatIndex
= p
->GetRetFormatIndex();
1636 // In case of changes just obtain the result, no temporary and
1637 // comparison needed anymore.
1639 aResult
.SetToken( p
->GetResultToken() );
1642 ScFormulaResult
aNewResult( p
->GetResultToken());
1643 StackVar eOld
= aResult
.GetCellResultType();
1644 StackVar eNew
= aNewResult
.GetCellResultType();
1645 bChanged
= (eOld
!= eNew
||
1646 (eNew
== svDouble
&& aResult
.GetDouble() != aNewResult
.GetDouble()) ||
1647 (eNew
== svString
&& aResult
.GetString() != aNewResult
.GetString()));
1648 aResult
.Assign( aNewResult
);
1651 // Precision as shown?
1652 if ( aResult
.IsValue() && !p
->GetError()
1653 && pDocument
->GetDocOptions().IsCalcAsShown()
1654 && nFormatType
!= NUMBERFORMAT_DATE
1655 && nFormatType
!= NUMBERFORMAT_TIME
1656 && nFormatType
!= NUMBERFORMAT_DATETIME
)
1658 ULONG nFormat
= pDocument
->GetNumberFormat( aPos
);
1659 if ( nFormatIndex
&& (nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
) == 0 )
1660 nFormat
= nFormatIndex
;
1661 if ( (nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
) == 0 )
1662 nFormat
= ScGlobal::GetStandardFormat(
1663 *pDocument
->GetFormatTable(), nFormat
, nFormatType
);
1664 aResult
.SetDouble( pDocument
->RoundValueAsShown(
1665 aResult
.GetDouble(), nFormat
));
1667 if (eTailParam
== SCITP_NORMAL
)
1670 bTableOpDirty
= FALSE
;
1672 if( aResult
.GetMatrix().Is() )
1674 // If the formula wasn't entered as a matrix formula, live on with
1675 // the upper left corner and let reference counting delete the matrix.
1676 if( cMatrixFlag
!= MM_FORMULA
&& !pCode
->IsHyperLink() )
1677 aResult
.SetToken( aResult
.GetCellResultToken());
1679 if ( aResult
.IsValue() && !::rtl::math::isFinite( aResult
.GetDouble() ) )
1681 // Coded double error may occur via filter import.
1682 USHORT nErr
= GetDoubleErrorValue( aResult
.GetDouble());
1683 aResult
.SetResultError( nErr
);
1688 SetTextWidth( TEXTWIDTH_DIRTY
);
1689 SetScriptType( SC_SCRIPTTYPE_UNKNOWN
);
1691 if ( !pCode
->IsRecalcModeAlways() )
1692 pDocument
->RemoveFromFormulaTree( this );
1694 // FORCED Zellen auch sofort auf Gueltigkeit testen (evtl. Makro starten)
1696 if ( pCode
->IsRecalcModeForced() )
1698 ULONG nValidation
= ((const SfxUInt32Item
*) pDocument
->GetAttr(
1699 aPos
.Col(), aPos
.Row(), aPos
.Tab(), ATTR_VALIDDATA
))->GetValue();
1702 const ScValidationData
* pData
= pDocument
->GetValidationEntry( nValidation
);
1703 if ( pData
&& !pData
->IsDataValid( this, aPos
) )
1704 pData
->DoCalcError( this );
1708 // Reschedule verlangsamt das ganze erheblich, nur bei Prozentaenderung ausfuehren
1709 ScProgress::GetInterpretProgress()->SetStateCountDownOnPercent(
1710 pDocument
->GetFormulaCodeInTree()/MIN_NO_CODES_PER_PROGRESS_UPDATE
);
1712 switch (p
->GetVolatileType())
1714 case ScInterpreter::VOLATILE
:
1715 // Volatile via built-in volatile functions. No actions needed.
1717 case ScInterpreter::VOLATILE_MACRO
:
1718 // The formula contains a volatile macro.
1719 pCode
->SetRecalcModeAlways();
1720 pDocument
->PutInFormulaTree(this);
1721 StartListeningTo(pDocument
);
1723 case ScInterpreter::NOT_VOLATILE
:
1724 if (pCode
->IsRecalcModeAlways())
1726 // The formula was previously volatile, but no more.
1727 EndListeningTo(pDocument
);
1728 pCode
->SetRecalcModeNormal();
1732 // non-volatile formula. End listening to the area in case
1733 // it's listening due to macro module change.
1734 pDocument
->EndListeningArea(BCA_LISTEN_ALWAYS
, this);
1736 pDocument
->RemoveFromFormulaTree(this);
1744 // Zelle bei Compiler-Fehlern nicht ewig auf dirty stehenlassen
1745 DBG_ASSERT( pCode
->GetCodeError(), "kein UPN-Code und kein Fehler ?!?!" );
1747 bTableOpDirty
= FALSE
;
1752 void ScFormulaCell::SetMatColsRows( SCCOL nCols
, SCROW nRows
)
1754 ScMatrixFormulaCellToken
* pMat
= aResult
.GetMatrixFormulaCellTokenNonConst();
1756 pMat
->SetMatColsRows( nCols
, nRows
);
1757 else if (nCols
|| nRows
)
1758 aResult
.SetToken( new ScMatrixFormulaCellToken( nCols
, nRows
));
1762 void ScFormulaCell::GetMatColsRows( SCCOL
& nCols
, SCROW
& nRows
) const
1764 const ScMatrixFormulaCellToken
* pMat
= aResult
.GetMatrixFormulaCellToken();
1766 pMat
->GetMatColsRows( nCols
, nRows
);
1775 ULONG
ScFormulaCell::GetStandardFormat( SvNumberFormatter
& rFormatter
, ULONG nFormat
) const
1777 if ( nFormatIndex
&& (nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
) == 0 )
1778 return nFormatIndex
;
1779 //! not ScFormulaCell::IsValue(), that could reinterpret the formula again.
1780 if ( aResult
.IsValue() )
1781 return ScGlobal::GetStandardFormat( aResult
.GetDouble(), rFormatter
, nFormat
, nFormatType
);
1783 return ScGlobal::GetStandardFormat( rFormatter
, nFormat
, nFormatType
);
1787 void __EXPORT
ScFormulaCell::Notify( SvtBroadcaster
&, const SfxHint
& rHint
)
1789 if ( !pDocument
->IsInDtorClear() && !pDocument
->GetHardRecalcState() )
1791 const ScHint
* p
= PTR_CAST( ScHint
, &rHint
);
1792 ULONG nHint
= (p
? p
->GetId() : 0);
1793 if (nHint
& (SC_HINT_DATACHANGED
| SC_HINT_DYING
| SC_HINT_TABLEOPDIRTY
))
1795 BOOL bForceTrack
= FALSE
;
1796 if ( nHint
& SC_HINT_TABLEOPDIRTY
)
1798 bForceTrack
= !bTableOpDirty
;
1799 if ( !bTableOpDirty
)
1801 pDocument
->AddTableOpFormulaCell( this );
1802 bTableOpDirty
= TRUE
;
1807 bForceTrack
= !bDirty
;
1810 // #35962# Don't remove from FormulaTree to put in FormulaTrack to
1811 // put in FormulaTree again and again, only if necessary.
1812 // Any other means except RECALCMODE_ALWAYS by which a cell could
1813 // be in FormulaTree if it would notify other cells through
1814 // FormulaTrack which weren't in FormulaTrack/FormulaTree before?!?
1815 // #87866# Yes. The new TableOpDirty made it necessary to have a
1816 // forced mode where formulas may still be in FormulaTree from
1817 // TableOpDirty but have to notify dependents for normal dirty.
1818 if ( (bForceTrack
|| !pDocument
->IsInFormulaTree( this )
1819 || pCode
->IsRecalcModeAlways())
1820 && !pDocument
->IsInFormulaTrack( this ) )
1821 pDocument
->AppendToFormulaTrack( this );
1826 void ScFormulaCell::SetDirty()
1828 if ( !IsInChangeTrack() )
1830 if ( pDocument
->GetHardRecalcState() )
1834 // Mehrfach-FormulaTracking in Load und in CompileAll
1835 // nach CopyScenario und CopyBlockFromClip vermeiden.
1836 // Wenn unbedingtes FormulaTracking noetig, vor SetDirty bDirty=FALSE
1837 // setzen, z.B. in CompileTokenArray
1838 if ( !bDirty
|| !pDocument
->IsInFormulaTree( this ) )
1841 pDocument
->AppendToFormulaTrack( this );
1842 pDocument
->TrackFormulas();
1848 void ScFormulaCell::SetDirtyVar()
1851 // mark the sheet of this cell to be calculated
1852 pDocument
->AddCalculateTable( aPos
.Tab() );
1855 void ScFormulaCell::SetDirtyAfterLoad()
1858 if ( !pDocument
->GetHardRecalcState() )
1859 pDocument
->PutInFormulaTree( this );
1862 void ScFormulaCell::SetTableOpDirty()
1864 if ( !IsInChangeTrack() )
1866 if ( pDocument
->GetHardRecalcState() )
1867 bTableOpDirty
= TRUE
;
1870 if ( !bTableOpDirty
|| !pDocument
->IsInFormulaTree( this ) )
1872 if ( !bTableOpDirty
)
1874 pDocument
->AddTableOpFormulaCell( this );
1875 bTableOpDirty
= TRUE
;
1877 pDocument
->AppendToFormulaTrack( this );
1878 pDocument
->TrackFormulas( SC_HINT_TABLEOPDIRTY
);
1885 BOOL
ScFormulaCell::IsDirtyOrInTableOpDirty() const
1887 return bDirty
|| (bTableOpDirty
&& pDocument
->IsInInterpreterTableOp());
1891 void ScFormulaCell::SetErrCode( USHORT n
)
1893 /* FIXME: check the numerous places where ScTokenArray::GetCodeError() is
1894 * used whether it is solely for transport of a simple result error and get
1895 * rid of that abuse. */
1896 pCode
->SetCodeError( n
);
1897 // Hard set errors are transported as result type value per convention,
1898 // e.g. via clipboard. ScFormulaResult::IsValue() and
1899 // ScFormulaResult::GetDouble() handle that.
1900 aResult
.SetResultError( n
);
1903 void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits
)
1905 if ( (nBits
& RECALCMODE_EMASK
) != RECALCMODE_NORMAL
)
1907 if ( nBits
& RECALCMODE_ONLOAD_ONCE
)
1908 { // OnLoadOnce nur zum Dirty setzen nach Filter-Import
1909 nBits
= (nBits
& ~RECALCMODE_EMASK
) | RECALCMODE_NORMAL
;
1911 pCode
->AddRecalcMode( nBits
);
1914 // Dynamically create the URLField on a mouse-over action on a hyperlink() cell.
1915 void ScFormulaCell::GetURLResult( String
& rURL
, String
& rCellText
)
1921 // Cell Text uses the Cell format while the URL uses
1922 // the default format for the type.
1923 ULONG nCellFormat
= pDocument
->GetNumberFormat( aPos
);
1924 SvNumberFormatter
* pFormatter
= pDocument
->GetFormatTable();
1926 if ( (nCellFormat
% SV_COUNTRY_LANGUAGE_OFFSET
) == 0 )
1927 nCellFormat
= GetStandardFormat( *pFormatter
,nCellFormat
);
1929 ULONG nURLFormat
= ScGlobal::GetStandardFormat( *pFormatter
,nCellFormat
, NUMBERFORMAT_NUMBER
);
1933 double fValue
= GetValue();
1934 pFormatter
->GetOutputString( fValue
, nCellFormat
, rCellText
, &pColor
);
1938 GetString( aCellString
);
1939 pFormatter
->GetOutputString( aCellString
, nCellFormat
, rCellText
, &pColor
);
1941 ScConstMatrixRef
xMat( aResult
.GetMatrix());
1944 ScMatValType nMatValType
;
1945 // determine if the matrix result is a string or value.
1946 const ScMatrixValue
* pMatVal
= xMat
->Get(0, 1, nMatValType
);
1949 if (!ScMatrix::IsValueType( nMatValType
))
1950 rURL
= pMatVal
->GetString();
1952 pFormatter
->GetOutputString( pMatVal
->fVal
, nURLFormat
, rURL
, &pColor
);
1959 pFormatter
->GetOutputString( GetValue(), nURLFormat
, rURL
, &pColor
);
1961 pFormatter
->GetOutputString( aCellString
, nURLFormat
, rURL
, &pColor
);
1965 bool ScFormulaCell::IsMultilineResult()
1968 return aResult
.IsMultiline();
1972 EditTextObject
* ScFormulaCell::CreateURLObject()
1976 GetURLResult( aURL
, aCellText
);
1978 SvxURLField
aUrlField( aURL
, aCellText
, SVXURLFORMAT_APPDEFAULT
);
1979 EditEngine
& rEE
= pDocument
->GetEditEngine();
1980 rEE
.SetText( EMPTY_STRING
);
1981 rEE
.QuickInsertField( SvxFieldItem( aUrlField
, EE_FEATURE_FIELD
), ESelection( 0xFFFF, 0xFFFF ) );
1983 return rEE
.CreateTextObject();
1986 // ============================================================================
1988 ScDetectiveRefIter::ScDetectiveRefIter( ScFormulaCell
* pCell
)
1990 pCode
= pCell
->GetCode();
1995 BOOL
lcl_ScDetectiveRefIter_SkipRef( ScToken
* p
)
1997 ScSingleRefData
& rRef1
= p
->GetSingleRef();
1998 if ( rRef1
.IsColDeleted() || rRef1
.IsRowDeleted() || rRef1
.IsTabDeleted()
2001 if ( p
->GetType() == svDoubleRef
|| p
->GetType() == svExternalDoubleRef
)
2003 ScSingleRefData
& rRef2
= p
->GetDoubleRef().Ref2
;
2004 if ( rRef2
.IsColDeleted() || rRef2
.IsRowDeleted() || rRef2
.IsTabDeleted()
2011 BOOL
ScDetectiveRefIter::GetNextRef( ScRange
& rRange
)
2014 ScToken
* p
= GetNextRefToken();
2017 SingleDoubleRefProvider
aProv( *p
);
2018 rRange
.aStart
.Set( aProv
.Ref1
.nCol
, aProv
.Ref1
.nRow
, aProv
.Ref1
.nTab
);
2019 rRange
.aEnd
.Set( aProv
.Ref2
.nCol
, aProv
.Ref2
.nRow
, aProv
.Ref2
.nTab
);
2026 ScToken
* ScDetectiveRefIter::GetNextRefToken()
2028 ScToken
* p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
2030 p
->CalcAbsIfRel( aPos
);
2032 while ( p
&& lcl_ScDetectiveRefIter_SkipRef( p
) )
2034 p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
2036 p
->CalcAbsIfRel( aPos
);
2041 // ============================================================================