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