xref: /aoo41x/main/sc/source/core/data/cell.cxx (revision dfb14cdc)
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);
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 
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 
97 ScBaseCell::~ScBaseCell()
98 {
99     delete mpNote;
100     delete mpBroadcaster;
101     DBG_ASSERT( eCellType == CELLTYPE_DESTROYED, "BaseCell Destructor" );
102 }
103 
104 namespace {
105 
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 
128 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 
137 ScBaseCell* ScBaseCell::CloneWithoutNote( ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags ) const
138 {
139     return lclCloneCell( *this, rDestDoc, rDestPos, nCloneFlags );
140 }
141 
142 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 
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 
181 bool ScBaseCell::IsBlank( bool bIgnoreNotes ) const
182 {
183     return (eCellType == CELLTYPE_NOTE) && (bIgnoreNotes || !mpNote);
184 }
185 
186 void ScBaseCell::TakeNote( ScPostIt* pNote )
187 {
188     delete mpNote;
189     mpNote = pNote;
190 }
191 
192 ScPostIt* ScBaseCell::ReleaseNote()
193 {
194     ScPostIt* pNote = mpNote;
195     mpNote = 0;
196     return pNote;
197 }
198 
199 void ScBaseCell::DeleteNote()
200 {
201     DELETEZ( mpNote );
202 }
203 
204 void ScBaseCell::TakeBroadcaster( SvtBroadcaster* pBroadcaster )
205 {
206     delete mpBroadcaster;
207     mpBroadcaster = pBroadcaster;
208 }
209 
210 SvtBroadcaster* ScBaseCell::ReleaseBroadcaster()
211 {
212     SvtBroadcaster* pBroadcaster = mpBroadcaster;
213     mpBroadcaster = 0;
214     return pBroadcaster;
215 }
216 
217 void ScBaseCell::DeleteBroadcaster()
218 {
219     DELETEZ( mpBroadcaster );
220 }
221 
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 
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 
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 
403 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 
415 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 
429 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 
443 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 
457 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
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 
556 ScNoteCell::ScNoteCell( SvtBroadcaster* pBC ) :
557 	ScBaseCell( CELLTYPE_NOTE )
558 {
559     TakeBroadcaster( pBC );
560 }
561 
562 ScNoteCell::ScNoteCell( ScPostIt* pNote, SvtBroadcaster* pBC ) :
563 	ScBaseCell( CELLTYPE_NOTE )
564 {
565     TakeNote( pNote );
566     TakeBroadcaster( pBC );
567 }
568 
569 #ifdef DBG_UTIL
570 ScNoteCell::~ScNoteCell()
571 {
572 	eCellType = CELLTYPE_DESTROYED;
573 }
574 #endif
575 
576 // ============================================================================
577 
578 ScValueCell::ScValueCell() :
579 	ScBaseCell( CELLTYPE_VALUE ),
580 	mfValue( 0.0 )
581 {
582 }
583 
584 ScValueCell::ScValueCell( double fValue ) :
585 	ScBaseCell( CELLTYPE_VALUE ),
586 	mfValue( fValue )
587 {
588 }
589 
590 #ifdef DBG_UTIL
591 ScValueCell::~ScValueCell()
592 {
593 	eCellType = CELLTYPE_DESTROYED;
594 }
595 #endif
596 
597 // ============================================================================
598 
599 ScStringCell::ScStringCell() :
600 	ScBaseCell( CELLTYPE_STRING )
601 {
602 }
603 
604 ScStringCell::ScStringCell( const String& rString ) :
605 	ScBaseCell( CELLTYPE_STRING ),
606     maString( rString.intern() )
607 {
608 }
609 
610 #ifdef DBG_UTIL
611 ScStringCell::~ScStringCell()
612 {
613 	eCellType = CELLTYPE_DESTROYED;
614 }
615 #endif
616 
617 // ============================================================================
618 
619 //
620 //		ScFormulaCell
621 //
622 
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 
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 
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 
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 	pValidRefToken( rCell.pValidRefToken ),
750 	aPos( rPos )
751 {
752 	pCode = (rCell.pCode) ? rCell.pCode->Clone() : NULL;
753 
754     if ( nCloneFlags & SC_CLONECELL_ADJUST3DREL )
755         pCode->ReadjustRelative3DReferences( rCell.aPos, aPos );
756 
757 	// evtl. Fehler zuruecksetzen und neu kompilieren
758 	//	nicht im Clipboard - da muss das Fehlerflag erhalten bleiben
759 	//	Spezialfall Laenge=0: als Fehlerzelle erzeugt, dann auch Fehler behalten
760 	if ( pCode->GetCodeError() && !pDocument->IsClipboard() && pCode->GetLen() )
761 	{
762 		pCode->SetCodeError( 0 );
763 		bCompile = sal_True;
764 	}
765     //! Compile ColRowNames on URM_MOVE/URM_COPY _after_ UpdateReference
766     sal_Bool bCompileLater = sal_False;
767     sal_Bool bClipMode = rCell.pDocument->IsClipboard();
768 	if( !bCompile )
769     {   // Name references with references and ColRowNames
770         pCode->Reset();
771         ScToken* t;
772         while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceOrName()) ) != NULL && !bCompile )
773 		{
774             if ( t->GetOpCode() == ocExternalRef )
775             {
776                 // External name, cell, and area references.
777                 bCompile = true;
778             }
779 			else if ( t->GetType() == svIndex )
780 			{
781 				ScRangeData* pRangeData = rDoc.GetRangeName()->FindIndex( t->GetIndex() );
782 				if( pRangeData )
783 				{
784 					if( pRangeData->HasReferences() )
785 						bCompile = sal_True;
786 				}
787 				else
788                     bCompile = sal_True;    // invalid reference!
789 			}
790 			else if ( t->GetOpCode() == ocColRowName )
791 			{
792                 bCompile = sal_True;        // new lookup needed
793                 bCompileLater = bClipMode;
794 			}
795 		}
796 	}
797 	if( bCompile )
798 	{
799         if ( !bCompileLater && bClipMode )
800 		{
801             // Merging ranges needs the actual positions after UpdateReference.
802             // ColRowNames need new lookup after positions are adjusted.
803             bCompileLater = pCode->HasOpCode( ocRange) || pCode->HasOpCode( ocColRowName);
804 		}
805         if ( !bCompileLater )
806         {
807             // bNoListening, not at all if in Clipboard/Undo,
808             // and not from Clipboard either, instead after Insert(Clone) and UpdateReference.
809             CompileTokenArray( sal_True );
810         }
811 	}
812 
813     if( nCloneFlags & SC_CLONECELL_STARTLISTENING )
814         StartListeningTo( &rDoc );
815 }
816 
817 ScFormulaCell::~ScFormulaCell()
818 {
819 	pDocument->RemoveFromFormulaTree( this );
820 
821     if (pDocument->HasExternalRefManager())
822         pDocument->GetExternalRefManager()->removeRefCell(this);
823 
824 	delete pCode;
825 #ifdef DBG_UTIL
826 	eCellType = CELLTYPE_DESTROYED;
827 #endif
828     DELETEZ(pValidRefToken);
829 }
830 
831 void ScFormulaCell::GetFormula( rtl::OUStringBuffer& rBuffer,
832                                 const FormulaGrammar::Grammar eGrammar ) const
833 {
834     if( pCode->GetCodeError() && !pCode->GetLen() )
835     {
836         rBuffer = rtl::OUStringBuffer( ScGlobal::GetErrorString( pCode->GetCodeError()));
837         return;
838     }
839     else if( cMatrixFlag == MM_REFERENCE )
840     {
841         // Reference to another cell that contains a matrix formula.
842         pCode->Reset();
843         ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
844         if( p )
845         {
846             /* FIXME: original GetFormula() code obtained
847              * pCell only if (!this->IsInChangeTrack()),
848              * GetEnglishFormula() omitted that test.
849              * Can we live without in all cases? */
850             ScBaseCell* pCell;
851             ScSingleRefData& rRef = p->GetSingleRef();
852             rRef.CalcAbsIfRel( aPos );
853             if ( rRef.Valid() )
854                 pCell = pDocument->GetCell( ScAddress( rRef.nCol,
855                             rRef.nRow, rRef.nTab ) );
856             else
857                 pCell = NULL;
858             if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
859             {
860                 ((ScFormulaCell*)pCell)->GetFormula( rBuffer, eGrammar);
861                 return;
862             }
863             else
864             {
865                 ScCompiler aComp( pDocument, aPos, *pCode);
866                 aComp.SetGrammar(eGrammar);
867                 aComp.CreateStringFromTokenArray( rBuffer );
868             }
869         }
870         else
871         {
872             DBG_ERROR("ScFormulaCell::GetFormula: not a matrix");
873         }
874     }
875     else
876     {
877         ScCompiler aComp( pDocument, aPos, *pCode);
878         aComp.SetGrammar(eGrammar);
879         aComp.CreateStringFromTokenArray( rBuffer );
880     }
881 
882     sal_Unicode ch('=');
883     rBuffer.insert( 0, &ch, 1 );
884     if( cMatrixFlag )
885     {
886         sal_Unicode ch2('{');
887         rBuffer.insert( 0, &ch2, 1);
888         rBuffer.append( sal_Unicode('}'));
889     }
890 }
891 
892 void ScFormulaCell::GetFormula( String& rFormula, const FormulaGrammar::Grammar eGrammar ) const
893 {
894     rtl::OUStringBuffer rBuffer( rFormula );
895     GetFormula( rBuffer, eGrammar );
896     rFormula = rBuffer;
897 }
898 
899 void ScFormulaCell::GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows )
900 {
901 	if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
902 		Interpret();
903 
904     const ScMatrix* pMat = NULL;
905     if (!pCode->GetCodeError() && aResult.GetType() == svMatrixCell &&
906             ((pMat = static_cast<const ScToken*>(aResult.GetToken().get())->GetMatrix()) != 0))
907 		pMat->GetDimensions( rCols, rRows );
908 	else
909 	{
910 		rCols = 0;
911 		rRows = 0;
912 	}
913 }
914 
915 void ScFormulaCell::Compile( const String& rFormula, sal_Bool bNoListening,
916                             const FormulaGrammar::Grammar eGrammar )
917 {
918 	//#118851#, the initialization code for pCode after it can not be gnored if it is still NULL
919 	if ( pCode && 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 //-> i120962: If the cell was applied reference formula, get the valid token
1563         if (pValidRefToken)
1564             DELETEZ(pValidRefToken);
1565         if (p->IsReferenceFunc() && p->GetLastStackRefToken())
1566             pValidRefToken = static_cast<ScToken*>(p->GetLastStackRefToken()->Clone());
1567 //<- i120962
1568 
1569         // #i102616# For single-sheet saving consider only content changes, not format type,
1570         // because format type isn't set on loading (might be changed later)
1571         sal_Bool bContentChanged = sal_False;
1572 
1573         // Do not create a HyperLink() cell if the formula results in an error.
1574         if( p->GetError() && pCode->IsHyperLink())
1575             pCode->SetHyperLink(sal_False);
1576 
1577         if( p->GetError() && p->GetError() != errCircularReference)
1578         {
1579             bDirty = sal_False;
1580             bTableOpDirty = sal_False;
1581             bChanged = sal_True;
1582         }
1583         if (eTailParam == SCITP_FROM_ITERATION && IsDirtyOrInTableOpDirty())
1584         {
1585             bool bIsValue = aResult.IsValue();  // the previous type
1586             // Did it converge?
1587             if ((bIsValue && p->GetResultType() == svDouble && fabs(
1588                             p->GetNumResult() - aResult.GetDouble()) <=
1589                         pDocument->GetDocOptions().GetIterEps()) ||
1590                     (!bIsValue && p->GetResultType() == svString &&
1591                      p->GetStringResult() == aResult.GetString()))
1592             {
1593                 // A convergence in the first iteration doesn't necessarily
1594                 // mean that it's done, it may be because not all related cells
1595                 // of a circle changed their values yet. If the set really
1596                 // converges it will do so also during the next iteration. This
1597                 // fixes situations like of #i44115#. If this wasn't wanted an
1598                 // initial "uncalculated" value would be needed for all cells
1599                 // of a circular dependency => graph needed before calculation.
1600                 if (nSeenInIteration > 1 ||
1601                         pDocument->GetDocOptions().GetIterCount() == 1)
1602                 {
1603                     bDirty = sal_False;
1604                     bTableOpDirty = sal_False;
1605                 }
1606             }
1607         }
1608 
1609         // New error code?
1610         if( p->GetError() != nOldErrCode )
1611         {
1612             bChanged = sal_True;
1613             // bContentChanged only has to be set if the file content would be changed
1614             if ( aResult.GetCellResultType() != svUnknown )
1615                 bContentChanged = sal_True;
1616         }
1617         // Different number format?
1618         if( nFormatType != p->GetRetFormatType() )
1619         {
1620             nFormatType = p->GetRetFormatType();
1621             bChanged = sal_True;
1622         }
1623         if( nFormatIndex != p->GetRetFormatIndex() )
1624         {
1625             nFormatIndex = p->GetRetFormatIndex();
1626             bChanged = sal_True;
1627         }
1628 
1629         // In case of changes just obtain the result, no temporary and
1630         // comparison needed anymore.
1631         if (bChanged)
1632         {
1633             // #i102616# Compare anyway if the sheet is still marked unchanged for single-sheet saving
1634             // Also handle special cases of initial results after loading.
1635 
1636             if ( !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
1637             {
1638                 ScFormulaResult aNewResult( p->GetResultToken());
1639                 StackVar eOld = aResult.GetCellResultType();
1640                 StackVar eNew = aNewResult.GetCellResultType();
1641                 if ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) )
1642                 {
1643                     // ScXMLTableRowCellContext::EndElement doesn't call SetFormulaResultDouble for 0
1644                     // -> no change
1645                 }
1646                 else
1647                 {
1648                     if ( eOld == svHybridCell )     // string result from SetFormulaResultString?
1649                         eOld = svString;            // ScHybridCellToken has a valid GetString method
1650 
1651                     // #i106045# use approxEqual to compare with stored value
1652                     bContentChanged = (eOld != eNew ||
1653                             (eNew == svDouble && !rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() )) ||
1654                             (eNew == svString && aResult.GetString() != aNewResult.GetString()));
1655                 }
1656             }
1657 
1658             aResult.SetToken( p->GetResultToken() );
1659         }
1660         else
1661         {
1662             ScFormulaResult aNewResult( p->GetResultToken());
1663             StackVar eOld = aResult.GetCellResultType();
1664             StackVar eNew = aNewResult.GetCellResultType();
1665             bChanged = (eOld != eNew ||
1666                     (eNew == svDouble && aResult.GetDouble() != aNewResult.GetDouble()) ||
1667                     (eNew == svString && aResult.GetString() != aNewResult.GetString()));
1668 
1669             // #i102616# handle special cases of initial results after loading (only if the sheet is still marked unchanged)
1670             if ( bChanged && !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
1671             {
1672                 if ( ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) ) ||
1673                      ( eOld == svHybridCell && eNew == svString && aResult.GetString() == aNewResult.GetString() ) ||
1674                      ( eOld == svDouble && eNew == svDouble && rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() ) ) )
1675                 {
1676                     // no change, see above
1677                 }
1678                 else
1679                     bContentChanged = sal_True;
1680             }
1681 
1682             aResult.Assign( aNewResult);
1683         }
1684 
1685         // Precision as shown?
1686         if ( aResult.IsValue() && !p->GetError()
1687           && pDocument->GetDocOptions().IsCalcAsShown()
1688           && nFormatType != NUMBERFORMAT_DATE
1689           && nFormatType != NUMBERFORMAT_TIME
1690           && nFormatType != NUMBERFORMAT_DATETIME )
1691         {
1692             sal_uLong nFormat = pDocument->GetNumberFormat( aPos );
1693             if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1694                 nFormat = nFormatIndex;
1695             if ( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1696                 nFormat = ScGlobal::GetStandardFormat(
1697                     *pDocument->GetFormatTable(), nFormat, nFormatType );
1698             aResult.SetDouble( pDocument->RoundValueAsShown(
1699                         aResult.GetDouble(), nFormat));
1700         }
1701         if (eTailParam == SCITP_NORMAL)
1702         {
1703             bDirty = sal_False;
1704             bTableOpDirty = sal_False;
1705         }
1706         if( aResult.GetMatrix().Is() )
1707         {
1708             // If the formula wasn't entered as a matrix formula, live on with
1709             // the upper left corner and let reference counting delete the matrix.
1710             if( cMatrixFlag != MM_FORMULA && !pCode->IsHyperLink() )
1711                 aResult.SetToken( aResult.GetCellResultToken());
1712         }
1713         if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
1714         {
1715             // Coded double error may occur via filter import.
1716             sal_uInt16 nErr = GetDoubleErrorValue( aResult.GetDouble());
1717             aResult.SetResultError( nErr);
1718             bChanged = bContentChanged = true;
1719         }
1720         if( bChanged )
1721         {
1722             SetTextWidth( TEXTWIDTH_DIRTY );
1723             SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
1724         }
1725         if (bContentChanged && pDocument->IsStreamValid(aPos.Tab()))
1726         {
1727             // pass bIgnoreLock=sal_True, because even if called from pending row height update,
1728             // a changed result must still reset the stream flag
1729             pDocument->SetStreamValid(aPos.Tab(), sal_False, sal_True);
1730         }
1731         if ( !pCode->IsRecalcModeAlways() )
1732             pDocument->RemoveFromFormulaTree( this );
1733 
1734         //  FORCED Zellen auch sofort auf Gueltigkeit testen (evtl. Makro starten)
1735 
1736         if ( pCode->IsRecalcModeForced() )
1737         {
1738             sal_uLong nValidation = ((const SfxUInt32Item*) pDocument->GetAttr(
1739                     aPos.Col(), aPos.Row(), aPos.Tab(), ATTR_VALIDDATA ))->GetValue();
1740             if ( nValidation )
1741             {
1742                 const ScValidationData* pData = pDocument->GetValidationEntry( nValidation );
1743                 if ( pData && !pData->IsDataValid( this, aPos ) )
1744                     pData->DoCalcError( this );
1745             }
1746         }
1747 
1748         // Reschedule verlangsamt das ganze erheblich, nur bei Prozentaenderung ausfuehren
1749         ScProgress::GetInterpretProgress()->SetStateCountDownOnPercent(
1750             pDocument->GetFormulaCodeInTree()/MIN_NO_CODES_PER_PROGRESS_UPDATE );
1751     }
1752     else
1753     {
1754         //  Zelle bei Compiler-Fehlern nicht ewig auf dirty stehenlassen
1755         DBG_ASSERT( pCode->GetCodeError(), "kein UPN-Code und kein Fehler ?!?!" );
1756         bDirty = sal_False;
1757         bTableOpDirty = sal_False;
1758     }
1759 }
1760 
1761 
1762 void ScFormulaCell::SetMatColsRows( SCCOL nCols, SCROW nRows )
1763 {
1764     ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellTokenNonConst();
1765     if (pMat)
1766         pMat->SetMatColsRows( nCols, nRows);
1767     else if (nCols || nRows)
1768         aResult.SetToken( new ScMatrixFormulaCellToken( nCols, nRows));
1769 }
1770 
1771 
1772 void ScFormulaCell::GetMatColsRows( SCCOL & nCols, SCROW & nRows ) const
1773 {
1774     const ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellToken();
1775     if (pMat)
1776         pMat->GetMatColsRows( nCols, nRows);
1777     else
1778     {
1779         nCols = 0;
1780         nRows = 0;
1781     }
1782 }
1783 
1784 
1785 sal_uLong ScFormulaCell::GetStandardFormat( SvNumberFormatter& rFormatter, sal_uLong nFormat ) const
1786 {
1787 	if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1788 		return nFormatIndex;
1789     //! not ScFormulaCell::IsValue(), that could reinterpret the formula again.
1790 	if ( aResult.IsValue() )
1791 		return ScGlobal::GetStandardFormat(	aResult.GetDouble(), rFormatter, nFormat, nFormatType );
1792 	else
1793 		return ScGlobal::GetStandardFormat(	rFormatter, nFormat, nFormatType );
1794 }
1795 
1796 
1797 void __EXPORT ScFormulaCell::Notify( SvtBroadcaster&, const SfxHint& rHint)
1798 {
1799 	if ( !pDocument->IsInDtorClear() && !pDocument->GetHardRecalcState() )
1800 	{
1801 		const ScHint* p = PTR_CAST( ScHint, &rHint );
1802         sal_uLong nHint = (p ? p->GetId() : 0);
1803         if (nHint & (SC_HINT_DATACHANGED | SC_HINT_DYING | SC_HINT_TABLEOPDIRTY))
1804 		{
1805             sal_Bool bForceTrack = sal_False;
1806 			if ( nHint & SC_HINT_TABLEOPDIRTY )
1807             {
1808                 bForceTrack = !bTableOpDirty;
1809                 if ( !bTableOpDirty )
1810                 {
1811                     pDocument->AddTableOpFormulaCell( this );
1812                     bTableOpDirty = sal_True;
1813                 }
1814             }
1815 			else
1816             {
1817                 bForceTrack = !bDirty;
1818 				bDirty = sal_True;
1819             }
1820             // #35962# Don't remove from FormulaTree to put in FormulaTrack to
1821             // put in FormulaTree again and again, only if necessary.
1822             // Any other means except RECALCMODE_ALWAYS by which a cell could
1823             // be in FormulaTree if it would notify other cells through
1824             // FormulaTrack which weren't in FormulaTrack/FormulaTree before?!?
1825             // #87866# Yes. The new TableOpDirty made it necessary to have a
1826             // forced mode where formulas may still be in FormulaTree from
1827             // TableOpDirty but have to notify dependents for normal dirty.
1828             if ( (bForceTrack || !pDocument->IsInFormulaTree( this )
1829 					|| pCode->IsRecalcModeAlways())
1830 					&& !pDocument->IsInFormulaTrack( this ) )
1831 				pDocument->AppendToFormulaTrack( this );
1832 		}
1833 	}
1834 }
1835 
1836 void ScFormulaCell::SetDirty()
1837 {
1838 	if ( !IsInChangeTrack() )
1839 	{
1840 		if ( pDocument->GetHardRecalcState() )
1841 			bDirty = sal_True;
1842 		else
1843 		{
1844 			// Mehrfach-FormulaTracking in Load und in CompileAll
1845 			// nach CopyScenario und CopyBlockFromClip vermeiden.
1846 			// Wenn unbedingtes FormulaTracking noetig, vor SetDirty bDirty=sal_False
1847 			// setzen, z.B. in CompileTokenArray
1848 			if ( !bDirty || !pDocument->IsInFormulaTree( this ) )
1849 			{
1850 				bDirty = sal_True;
1851 				pDocument->AppendToFormulaTrack( this );
1852 				pDocument->TrackFormulas();
1853 			}
1854 		}
1855 
1856         if (pDocument->IsStreamValid(aPos.Tab()))
1857             pDocument->SetStreamValid(aPos.Tab(), sal_False);
1858 	}
1859 }
1860 
1861 void ScFormulaCell::SetDirtyAfterLoad()
1862 {
1863     bDirty = sal_True;
1864     if ( !pDocument->GetHardRecalcState() )
1865         pDocument->PutInFormulaTree( this );
1866 }
1867 
1868 void ScFormulaCell::SetTableOpDirty()
1869 {
1870 	if ( !IsInChangeTrack() )
1871 	{
1872 		if ( pDocument->GetHardRecalcState() )
1873 			bTableOpDirty = sal_True;
1874 		else
1875 		{
1876 			if ( !bTableOpDirty || !pDocument->IsInFormulaTree( this ) )
1877 			{
1878                 if ( !bTableOpDirty )
1879                 {
1880                     pDocument->AddTableOpFormulaCell( this );
1881                     bTableOpDirty = sal_True;
1882                 }
1883 				pDocument->AppendToFormulaTrack( this );
1884 				pDocument->TrackFormulas( SC_HINT_TABLEOPDIRTY );
1885 			}
1886 		}
1887 	}
1888 }
1889 
1890 
1891 sal_Bool ScFormulaCell::IsDirtyOrInTableOpDirty() const
1892 {
1893 	return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp());
1894 }
1895 
1896 
1897 void ScFormulaCell::SetErrCode( sal_uInt16 n )
1898 {
1899     /* FIXME: check the numerous places where ScTokenArray::GetCodeError() is
1900      * used whether it is solely for transport of a simple result error and get
1901      * rid of that abuse. */
1902 	pCode->SetCodeError( n );
1903     // Hard set errors are transported as result type value per convention,
1904     // e.g. via clipboard. ScFormulaResult::IsValue() and
1905     // ScFormulaResult::GetDouble() handle that.
1906     aResult.SetResultError( n );
1907 }
1908 
1909 void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits )
1910 {
1911 	if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL )
1912 		bDirty = sal_True;
1913 	if ( nBits & RECALCMODE_ONLOAD_ONCE )
1914 	{	// OnLoadOnce nur zum Dirty setzen nach Filter-Import
1915 		nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL;
1916 	}
1917 	pCode->AddRecalcMode( nBits );
1918 }
1919 
1920 // Dynamically create the URLField on a mouse-over action on a hyperlink() cell.
1921 void ScFormulaCell::GetURLResult( String& rURL, String& rCellText )
1922 {
1923     String aCellString;
1924 
1925     Color* pColor;
1926 
1927     // Cell Text uses the Cell format while the URL uses
1928     // the default format for the type.
1929     sal_uLong nCellFormat = pDocument->GetNumberFormat( aPos );
1930     SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
1931 
1932     if ( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1933         nCellFormat = GetStandardFormat( *pFormatter,nCellFormat );
1934 
1935    sal_uLong nURLFormat = ScGlobal::GetStandardFormat( *pFormatter,nCellFormat, NUMBERFORMAT_NUMBER);
1936 
1937     if ( IsValue() )
1938     {
1939         double fValue = GetValue();
1940         pFormatter->GetOutputString( fValue, nCellFormat, rCellText, &pColor );
1941     }
1942     else
1943     {
1944         GetString( aCellString );
1945         pFormatter->GetOutputString( aCellString, nCellFormat, rCellText, &pColor );
1946     }
1947     ScConstMatrixRef xMat( aResult.GetMatrix());
1948     if (xMat)
1949     {
1950         ScMatValType nMatValType;
1951         // determine if the matrix result is a string or value.
1952         const ScMatrixValue* pMatVal = xMat->Get(0, 1, nMatValType);
1953         if (pMatVal)
1954         {
1955             if (!ScMatrix::IsValueType( nMatValType))
1956                 rURL = pMatVal->GetString();
1957             else
1958                 pFormatter->GetOutputString( pMatVal->fVal, nURLFormat, rURL, &pColor );
1959         }
1960     }
1961 
1962     if(!rURL.Len())
1963     {
1964         if(IsValue())
1965             pFormatter->GetOutputString( GetValue(), nURLFormat, rURL, &pColor );
1966         else
1967             pFormatter->GetOutputString( aCellString, nURLFormat, rURL, &pColor );
1968     }
1969 }
1970 
1971 bool ScFormulaCell::IsMultilineResult()
1972 {
1973     if (!IsValue())
1974         return aResult.IsMultiline();
1975     return false;
1976 }
1977 
1978 EditTextObject* ScFormulaCell::CreateURLObject()
1979 {
1980     String aCellText;
1981     String aURL;
1982     GetURLResult( aURL, aCellText );
1983 
1984     SvxURLField aUrlField( aURL, aCellText, SVXURLFORMAT_APPDEFAULT);
1985     EditEngine& rEE = pDocument->GetEditEngine();
1986     rEE.SetText( EMPTY_STRING );
1987     rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection( 0xFFFF, 0xFFFF ) );
1988 
1989     return rEE.CreateTextObject();
1990 }
1991 
1992 // ============================================================================
1993 
1994 ScDetectiveRefIter::ScDetectiveRefIter( ScFormulaCell* pCell )
1995 {
1996 	pCode = pCell->GetCode();
1997 	pCode->Reset();
1998 	aPos = pCell->aPos;
1999 }
2000 
2001 sal_Bool lcl_ScDetectiveRefIter_SkipRef( ScToken* p )
2002 {
2003 	ScSingleRefData& rRef1 = p->GetSingleRef();
2004 	if ( rRef1.IsColDeleted() || rRef1.IsRowDeleted() || rRef1.IsTabDeleted()
2005 			|| !rRef1.Valid() )
2006 		return sal_True;
2007 	if ( p->GetType() == svDoubleRef )
2008 	{
2009 		ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
2010 		if ( rRef2.IsColDeleted() || rRef2.IsRowDeleted() || rRef2.IsTabDeleted()
2011 				|| !rRef2.Valid() )
2012 			return sal_True;
2013 	}
2014 	return sal_False;
2015 }
2016 
2017 sal_Bool ScDetectiveRefIter::GetNextRef( ScRange& rRange )
2018 {
2019 	sal_Bool bRet = sal_False;
2020 
2021 	ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
2022 	if (p)
2023 		p->CalcAbsIfRel( aPos );
2024 
2025 	while ( p && lcl_ScDetectiveRefIter_SkipRef( p ) )
2026 	{
2027 		p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
2028 		if (p)
2029 			p->CalcAbsIfRel( aPos );
2030 	}
2031 
2032 	if( p )
2033 	{
2034 		SingleDoubleRefProvider aProv( *p );
2035 		rRange.aStart.Set( aProv.Ref1.nCol, aProv.Ref1.nRow, aProv.Ref1.nTab );
2036 		rRange.aEnd.Set( aProv.Ref2.nCol, aProv.Ref2.nRow, aProv.Ref2.nTab );
2037 		bRet = sal_True;
2038 	}
2039 
2040 	return bRet;
2041 }
2042 
2043 // ============================================================================
2044