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