xref: /aoo42x/main/sc/source/core/data/cell.cxx (revision 09a04e03)
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 	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 
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 
835 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 
896 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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
1776 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 
1789 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 
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 
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 
1865 void ScFormulaCell::SetDirtyAfterLoad()
1866 {
1867     bDirty = sal_True;
1868     if ( !pDocument->GetHardRecalcState() )
1869         pDocument->PutInFormulaTree( this );
1870 }
1871 
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 
1895 sal_Bool ScFormulaCell::IsDirtyOrInTableOpDirty() const
1896 {
1897 	return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp());
1898 }
1899 
1900 
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 
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.
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 
1975 bool ScFormulaCell::IsMultilineResult()
1976 {
1977     if (!IsValue())
1978         return aResult.IsMultiline();
1979     return false;
1980 }
1981 
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 
1998 ScDetectiveRefIter::ScDetectiveRefIter( ScFormulaCell* pCell )
1999 {
2000 	pCode = pCell->GetCode();
2001 	pCode->Reset();
2002 	aPos = pCell->aPos;
2003 }
2004 
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 
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