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