update dev300-m58
[ooovba.git] / sc / source / core / data / cell.cxx
blob69f4065ed8caf6e82a8a3aef89f5e683d07c7c57
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: cell.cxx,v $
10 * $Revision: 1.44.38.6 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include <svtools/zforlist.hxx>
38 #include "scitems.hxx"
39 #include "attrib.hxx"
40 #include "cell.hxx"
41 #include "compiler.hxx"
42 #include "interpre.hxx"
43 #include "document.hxx"
44 #include "scmatrix.hxx"
45 #include "dociter.hxx"
46 #include "docoptio.hxx"
47 #include "rechead.hxx"
48 #include "rangenam.hxx"
49 #include "brdcst.hxx"
50 #include "ddelink.hxx"
51 #include "validat.hxx"
52 #include "progress.hxx"
53 #include "editutil.hxx"
54 #include "recursionhelper.hxx"
55 #include "postit.hxx"
56 #include "externalrefmgr.hxx"
57 #include "macromgr.hxx"
58 #include <svx/editobj.hxx>
59 #include <svtools/intitem.hxx>
60 #include <svx/flditem.hxx>
61 #include <svtools/broadcast.hxx>
63 using namespace formula;
64 // More or less arbitrary, of course all recursions must fit into available
65 // stack space (which is what on all systems we don't know yet?). Choosing a
66 // lower value may be better than trying a much higher value that also isn't
67 // sufficient but temporarily leads to high memory consumption. On the other
68 // hand, if the value fits all recursions, execution is quicker as no resumes
69 // are necessary. Could be made a configurable option.
70 // Allow for a year's calendar (366).
71 const USHORT MAXRECURSION = 400;
73 // STATIC DATA -----------------------------------------------------------
75 #ifdef USE_MEMPOOL
76 // MemPools auf 4k Boundaries - 64 Bytes ausrichten
77 const USHORT nMemPoolValueCell = (0x8000 - 64) / sizeof(ScValueCell);
78 const USHORT nMemPoolFormulaCell = (0x8000 - 64) / sizeof(ScFormulaCell);
79 const USHORT nMemPoolStringCell = (0x4000 - 64) / sizeof(ScStringCell);
80 const USHORT nMemPoolNoteCell = (0x1000 - 64) / sizeof(ScNoteCell);
81 IMPL_FIXEDMEMPOOL_NEWDEL( ScValueCell, nMemPoolValueCell, nMemPoolValueCell )
82 IMPL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell, nMemPoolFormulaCell, nMemPoolFormulaCell )
83 IMPL_FIXEDMEMPOOL_NEWDEL( ScStringCell, nMemPoolStringCell, nMemPoolStringCell )
84 IMPL_FIXEDMEMPOOL_NEWDEL( ScNoteCell, nMemPoolNoteCell, nMemPoolNoteCell )
85 #endif
87 // ============================================================================
89 ScBaseCell::ScBaseCell( CellType eNewType ) :
90 mpNote( 0 ),
91 mpBroadcaster( 0 ),
92 nTextWidth( TEXTWIDTH_DIRTY ),
93 eCellType( sal::static_int_cast<BYTE>(eNewType) ),
94 nScriptType( SC_SCRIPTTYPE_UNKNOWN )
98 ScBaseCell::ScBaseCell( const ScBaseCell& rCell ) :
99 mpNote( 0 ),
100 mpBroadcaster( 0 ),
101 nTextWidth( rCell.nTextWidth ),
102 eCellType( rCell.eCellType ),
103 nScriptType( SC_SCRIPTTYPE_UNKNOWN )
107 ScBaseCell::~ScBaseCell()
109 delete mpNote;
110 delete mpBroadcaster;
111 DBG_ASSERT( eCellType == CELLTYPE_DESTROYED, "BaseCell Destructor" );
114 namespace {
116 ScBaseCell* lclCloneCell( const ScBaseCell& rSrcCell, ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags )
118 switch( rSrcCell.GetCellType() )
120 case CELLTYPE_VALUE:
121 return new ScValueCell( static_cast< const ScValueCell& >( rSrcCell ) );
122 case CELLTYPE_STRING:
123 return new ScStringCell( static_cast< const ScStringCell& >( rSrcCell ) );
124 case CELLTYPE_EDIT:
125 return new ScEditCell( static_cast< const ScEditCell& >( rSrcCell ), rDestDoc );
126 case CELLTYPE_FORMULA:
127 return new ScFormulaCell( static_cast< const ScFormulaCell& >( rSrcCell ), rDestDoc, rDestPos, nCloneFlags );
128 case CELLTYPE_NOTE:
129 return new ScNoteCell;
130 default:;
132 DBG_ERROR( "lclCloneCell - unknown cell type" );
133 return 0;
136 } // namespace
138 ScBaseCell* ScBaseCell::CloneWithoutNote( ScDocument& rDestDoc, int nCloneFlags ) const
140 // notes will not be cloned -> cell address only needed for formula cells
141 ScAddress aDestPos;
142 if( eCellType == CELLTYPE_FORMULA )
143 aDestPos = static_cast< const ScFormulaCell* >( this )->aPos;
144 return lclCloneCell( *this, rDestDoc, aDestPos, nCloneFlags );
147 ScBaseCell* ScBaseCell::CloneWithoutNote( ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags ) const
149 return lclCloneCell( *this, rDestDoc, rDestPos, nCloneFlags );
152 ScBaseCell* ScBaseCell::CloneWithNote( const ScAddress& rOwnPos, ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags ) const
154 ScBaseCell* pNewCell = lclCloneCell( *this, rDestDoc, rDestPos, nCloneFlags );
155 if( mpNote )
157 if( !pNewCell )
158 pNewCell = new ScNoteCell;
159 bool bCloneCaption = (nCloneFlags & SC_CLONECELL_NOCAPTION) == 0;
160 pNewCell->TakeNote( mpNote->Clone( rOwnPos, rDestDoc, rDestPos, bCloneCaption ) );
162 return pNewCell;
165 void ScBaseCell::Delete()
167 DeleteNote();
168 switch (eCellType)
170 case CELLTYPE_VALUE:
171 delete (ScValueCell*) this;
172 break;
173 case CELLTYPE_STRING:
174 delete (ScStringCell*) this;
175 break;
176 case CELLTYPE_EDIT:
177 delete (ScEditCell*) this;
178 break;
179 case CELLTYPE_FORMULA:
180 delete (ScFormulaCell*) this;
181 break;
182 case CELLTYPE_NOTE:
183 delete (ScNoteCell*) this;
184 break;
185 default:
186 DBG_ERROR("Unbekannter Zellentyp");
187 break;
191 bool ScBaseCell::IsBlank( bool bIgnoreNotes ) const
193 return (eCellType == CELLTYPE_NOTE) && (bIgnoreNotes || !mpNote);
196 void ScBaseCell::TakeNote( ScPostIt* pNote )
198 delete mpNote;
199 mpNote = pNote;
202 ScPostIt* ScBaseCell::ReleaseNote()
204 ScPostIt* pNote = mpNote;
205 mpNote = 0;
206 return pNote;
209 void ScBaseCell::DeleteNote()
211 DELETEZ( mpNote );
214 void ScBaseCell::TakeBroadcaster( SvtBroadcaster* pBroadcaster )
216 delete mpBroadcaster;
217 mpBroadcaster = pBroadcaster;
220 SvtBroadcaster* ScBaseCell::ReleaseBroadcaster()
222 SvtBroadcaster* pBroadcaster = mpBroadcaster;
223 mpBroadcaster = 0;
224 return pBroadcaster;
227 void ScBaseCell::DeleteBroadcaster()
229 DELETEZ( mpBroadcaster );
232 ScBaseCell* ScBaseCell::CreateTextCell( const String& rString, ScDocument* pDoc )
234 if ( rString.Search('\n') != STRING_NOTFOUND || rString.Search(CHAR_CR) != STRING_NOTFOUND )
235 return new ScEditCell( rString, pDoc );
236 else
237 return new ScStringCell( rString );
240 void ScBaseCell::StartListeningTo( ScDocument* pDoc )
242 if ( eCellType == CELLTYPE_FORMULA && !pDoc->IsClipOrUndo()
243 && !pDoc->GetNoListening()
244 && !((ScFormulaCell*)this)->IsInChangeTrack()
247 pDoc->SetDetectiveDirty(TRUE); // es hat sich was geaendert...
249 ScFormulaCell* pFormCell = (ScFormulaCell*)this;
250 ScTokenArray* pArr = pFormCell->GetCode();
251 if( pArr->IsRecalcModeAlways() )
252 pDoc->StartListeningArea( BCA_LISTEN_ALWAYS, pFormCell );
253 else
255 pArr->Reset();
256 ScToken* t;
257 while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
259 StackVar eType = t->GetType();
260 ScSingleRefData& rRef1 = t->GetSingleRef();
261 ScSingleRefData& rRef2 = (eType == svDoubleRef ?
262 t->GetDoubleRef().Ref2 : rRef1);
263 switch( eType )
265 case svSingleRef:
266 rRef1.CalcAbsIfRel( pFormCell->aPos );
267 if ( rRef1.Valid() )
269 pDoc->StartListeningCell(
270 ScAddress( rRef1.nCol,
271 rRef1.nRow,
272 rRef1.nTab ), pFormCell );
274 break;
275 case svDoubleRef:
276 t->CalcAbsIfRel( pFormCell->aPos );
277 if ( rRef1.Valid() && rRef2.Valid() )
279 if ( t->GetOpCode() == ocColRowNameAuto )
280 { // automagically
281 if ( rRef1.IsColRel() )
282 { // ColName
283 pDoc->StartListeningArea( ScRange (
285 rRef1.nRow,
286 rRef1.nTab,
287 MAXCOL,
288 rRef2.nRow,
289 rRef2.nTab ), pFormCell );
291 else
292 { // RowName
293 pDoc->StartListeningArea( ScRange (
294 rRef1.nCol,
296 rRef1.nTab,
297 rRef2.nCol,
298 MAXROW,
299 rRef2.nTab ), pFormCell );
302 else
304 pDoc->StartListeningArea( ScRange (
305 rRef1.nCol,
306 rRef1.nRow,
307 rRef1.nTab,
308 rRef2.nCol,
309 rRef2.nRow,
310 rRef2.nTab ), pFormCell );
313 break;
314 default:
315 ; // nothing
319 pFormCell->SetNeedsListening( FALSE);
323 // pArr gesetzt -> Referenzen von anderer Zelle nehmen
324 // dann muss auch aPos uebergeben werden!
326 void ScBaseCell::EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr,
327 ScAddress aPos )
329 if ( eCellType == CELLTYPE_FORMULA && !pDoc->IsClipOrUndo()
330 && !((ScFormulaCell*)this)->IsInChangeTrack()
333 pDoc->SetDetectiveDirty(TRUE); // es hat sich was geaendert...
335 ScFormulaCell* pFormCell = (ScFormulaCell*)this;
336 if( pFormCell->GetCode()->IsRecalcModeAlways() )
337 pDoc->EndListeningArea( BCA_LISTEN_ALWAYS, pFormCell );
338 else
340 if (!pArr)
342 pArr = pFormCell->GetCode();
343 aPos = pFormCell->aPos;
345 pArr->Reset();
346 ScToken* t;
347 while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
349 StackVar eType = t->GetType();
350 ScSingleRefData& rRef1 = t->GetSingleRef();
351 ScSingleRefData& rRef2 = (eType == svDoubleRef ?
352 t->GetDoubleRef().Ref2 : rRef1);
353 switch( eType )
355 case svSingleRef:
356 rRef1.CalcAbsIfRel( aPos );
357 if ( rRef1.Valid() )
359 pDoc->EndListeningCell(
360 ScAddress( rRef1.nCol,
361 rRef1.nRow,
362 rRef1.nTab ), pFormCell );
364 break;
365 case svDoubleRef:
366 t->CalcAbsIfRel( aPos );
367 if ( rRef1.Valid() && rRef2.Valid() )
369 if ( t->GetOpCode() == ocColRowNameAuto )
370 { // automagically
371 if ( rRef1.IsColRel() )
372 { // ColName
373 pDoc->EndListeningArea( ScRange (
375 rRef1.nRow,
376 rRef1.nTab,
377 MAXCOL,
378 rRef2.nRow,
379 rRef2.nTab ), pFormCell );
381 else
382 { // RowName
383 pDoc->EndListeningArea( ScRange (
384 rRef1.nCol,
386 rRef1.nTab,
387 rRef2.nCol,
388 MAXROW,
389 rRef2.nTab ), pFormCell );
392 else
394 pDoc->EndListeningArea( ScRange (
395 rRef1.nCol,
396 rRef1.nRow,
397 rRef1.nTab,
398 rRef2.nCol,
399 rRef2.nRow,
400 rRef2.nTab ), pFormCell );
403 break;
404 default:
405 ; // nothing
413 USHORT ScBaseCell::GetErrorCode() const
415 switch ( eCellType )
417 case CELLTYPE_FORMULA :
418 return ((ScFormulaCell*)this)->GetErrCode();
419 default:
420 return 0;
425 BOOL ScBaseCell::HasEmptyData() const
427 switch ( eCellType )
429 case CELLTYPE_NOTE :
430 return TRUE;
431 case CELLTYPE_FORMULA :
432 return ((ScFormulaCell*)this)->IsEmpty();
433 default:
434 return FALSE;
439 BOOL ScBaseCell::HasValueData() const
441 switch ( eCellType )
443 case CELLTYPE_VALUE :
444 return TRUE;
445 case CELLTYPE_FORMULA :
446 return ((ScFormulaCell*)this)->IsValue();
447 default:
448 return FALSE;
453 BOOL ScBaseCell::HasStringData() const
455 switch ( eCellType )
457 case CELLTYPE_STRING :
458 case CELLTYPE_EDIT :
459 return TRUE;
460 case CELLTYPE_FORMULA :
461 return !((ScFormulaCell*)this)->IsValue();
462 default:
463 return FALSE;
467 String ScBaseCell::GetStringData() const
469 String aStr;
470 switch ( eCellType )
472 case CELLTYPE_STRING:
473 ((const ScStringCell*)this)->GetString( aStr );
474 break;
475 case CELLTYPE_EDIT:
476 ((const ScEditCell*)this)->GetString( aStr );
477 break;
478 case CELLTYPE_FORMULA:
479 ((ScFormulaCell*)this)->GetString( aStr ); // an der Formelzelle nicht-const
480 break;
482 return aStr;
485 // static
486 BOOL ScBaseCell::CellEqual( const ScBaseCell* pCell1, const ScBaseCell* pCell2 )
488 CellType eType1 = CELLTYPE_NONE;
489 CellType eType2 = CELLTYPE_NONE;
490 if ( pCell1 )
492 eType1 = pCell1->GetCellType();
493 if (eType1 == CELLTYPE_EDIT)
494 eType1 = CELLTYPE_STRING;
495 else if (eType1 == CELLTYPE_NOTE)
496 eType1 = CELLTYPE_NONE;
498 if ( pCell2 )
500 eType2 = pCell2->GetCellType();
501 if (eType2 == CELLTYPE_EDIT)
502 eType2 = CELLTYPE_STRING;
503 else if (eType2 == CELLTYPE_NOTE)
504 eType2 = CELLTYPE_NONE;
506 if ( eType1 != eType2 )
507 return FALSE;
509 switch ( eType1 ) // beide Typen gleich
511 case CELLTYPE_NONE: // beide leer
512 return TRUE;
513 case CELLTYPE_VALUE: // wirklich Value-Zellen
514 return ( ((const ScValueCell*)pCell1)->GetValue() ==
515 ((const ScValueCell*)pCell2)->GetValue() );
516 case CELLTYPE_STRING: // String oder Edit
518 String aText1;
519 if ( pCell1->GetCellType() == CELLTYPE_STRING )
520 ((const ScStringCell*)pCell1)->GetString(aText1);
521 else
522 ((const ScEditCell*)pCell1)->GetString(aText1);
523 String aText2;
524 if ( pCell2->GetCellType() == CELLTYPE_STRING )
525 ((const ScStringCell*)pCell2)->GetString(aText2);
526 else
527 ((const ScEditCell*)pCell2)->GetString(aText2);
528 return ( aText1 == aText2 );
530 case CELLTYPE_FORMULA:
532 //! eingefuegte Zeilen / Spalten beruecksichtigen !!!!!
533 //! Vergleichsfunktion an der Formelzelle ???
534 //! Abfrage mit ScColumn::SwapRow zusammenfassen!
536 ScTokenArray* pCode1 = ((ScFormulaCell*)pCell1)->GetCode();
537 ScTokenArray* pCode2 = ((ScFormulaCell*)pCell2)->GetCode();
539 if (pCode1->GetLen() == pCode2->GetLen()) // nicht-UPN
541 BOOL bEqual = TRUE;
542 USHORT nLen = pCode1->GetLen();
543 FormulaToken** ppToken1 = pCode1->GetArray();
544 FormulaToken** ppToken2 = pCode2->GetArray();
545 for (USHORT i=0; i<nLen; i++)
546 if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) )
548 bEqual = FALSE;
549 break;
552 if (bEqual)
553 return TRUE;
556 return FALSE; // unterschiedlich lang oder unterschiedliche Tokens
558 default:
559 DBG_ERROR("huch, was fuer Zellen???");
561 return FALSE;
564 // ============================================================================
566 ScNoteCell::ScNoteCell( SvtBroadcaster* pBC ) :
567 ScBaseCell( CELLTYPE_NOTE )
569 TakeBroadcaster( pBC );
572 ScNoteCell::ScNoteCell( ScPostIt* pNote, SvtBroadcaster* pBC ) :
573 ScBaseCell( CELLTYPE_NOTE )
575 TakeNote( pNote );
576 TakeBroadcaster( pBC );
579 #ifdef DBG_UTIL
580 ScNoteCell::~ScNoteCell()
582 eCellType = CELLTYPE_DESTROYED;
584 #endif
586 // ============================================================================
588 ScValueCell::ScValueCell() :
589 ScBaseCell( CELLTYPE_VALUE ),
590 mfValue( 0.0 )
594 ScValueCell::ScValueCell( double fValue ) :
595 ScBaseCell( CELLTYPE_VALUE ),
596 mfValue( fValue )
600 #ifdef DBG_UTIL
601 ScValueCell::~ScValueCell()
603 eCellType = CELLTYPE_DESTROYED;
605 #endif
607 // ============================================================================
609 ScStringCell::ScStringCell() :
610 ScBaseCell( CELLTYPE_STRING )
614 ScStringCell::ScStringCell( const String& rString ) :
615 ScBaseCell( CELLTYPE_STRING ),
616 maString( rString.intern() )
620 #ifdef DBG_UTIL
621 ScStringCell::~ScStringCell()
623 eCellType = CELLTYPE_DESTROYED;
625 #endif
627 // ============================================================================
630 // ScFormulaCell
633 ScFormulaCell::ScFormulaCell() :
634 ScBaseCell( CELLTYPE_FORMULA ),
635 eTempGrammar( FormulaGrammar::GRAM_DEFAULT),
636 pCode( NULL ),
637 pDocument( NULL ),
638 pPrevious(0),
639 pNext(0),
640 pPreviousTrack(0),
641 pNextTrack(0),
642 nFormatIndex(0),
643 nFormatType( NUMBERFORMAT_NUMBER ),
644 nSeenInIteration(0),
645 cMatrixFlag ( MM_NONE ),
646 bDirty( FALSE ),
647 bChanged( FALSE ),
648 bRunning( FALSE ),
649 bCompile( FALSE ),
650 bSubTotal( FALSE ),
651 bIsIterCell( FALSE ),
652 bInChangeTrack( FALSE ),
653 bTableOpDirty( FALSE ),
654 bNeedListening( FALSE ),
655 aPos(0,0,0)
659 ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
660 const String& rFormula,
661 const FormulaGrammar::Grammar eGrammar,
662 BYTE cMatInd ) :
663 ScBaseCell( CELLTYPE_FORMULA ),
664 eTempGrammar( eGrammar),
665 pCode( NULL ),
666 pDocument( pDoc ),
667 pPrevious(0),
668 pNext(0),
669 pPreviousTrack(0),
670 pNextTrack(0),
671 nFormatIndex(0),
672 nFormatType( NUMBERFORMAT_NUMBER ),
673 nSeenInIteration(0),
674 cMatrixFlag ( cMatInd ),
675 bDirty( TRUE ), // -> wg. Benutzung im Fkt.AutoPiloten, war: cMatInd != 0
676 bChanged( FALSE ),
677 bRunning( FALSE ),
678 bCompile( FALSE ),
679 bSubTotal( FALSE ),
680 bIsIterCell( FALSE ),
681 bInChangeTrack( FALSE ),
682 bTableOpDirty( FALSE ),
683 bNeedListening( FALSE ),
684 aPos( rPos )
686 Compile( rFormula, TRUE, eGrammar ); // bNoListening, Insert does that
689 // Wird von den Importfiltern verwendet
691 ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
692 const ScTokenArray* pArr,
693 const FormulaGrammar::Grammar eGrammar, BYTE cInd ) :
694 ScBaseCell( CELLTYPE_FORMULA ),
695 eTempGrammar( eGrammar),
696 pCode( pArr ? new ScTokenArray( *pArr ) : new ScTokenArray ),
697 pDocument( pDoc ),
698 pPrevious(0),
699 pNext(0),
700 pPreviousTrack(0),
701 pNextTrack(0),
702 nFormatIndex(0),
703 nFormatType( NUMBERFORMAT_NUMBER ),
704 nSeenInIteration(0),
705 cMatrixFlag ( cInd ),
706 bDirty( NULL != pArr ), // -> wg. Benutzung im Fkt.AutoPiloten, war: cInd != 0
707 bChanged( FALSE ),
708 bRunning( FALSE ),
709 bCompile( FALSE ),
710 bSubTotal( FALSE ),
711 bIsIterCell( FALSE ),
712 bInChangeTrack( FALSE ),
713 bTableOpDirty( FALSE ),
714 bNeedListening( FALSE ),
715 aPos( rPos )
717 // UPN-Array erzeugen
718 if( pCode->GetLen() && !pCode->GetCodeError() && !pCode->GetCodeLen() )
720 ScCompiler aComp( pDocument, aPos, *pCode);
721 aComp.SetGrammar(eTempGrammar);
722 bSubTotal = aComp.CompileTokenArray();
723 nFormatType = aComp.GetNumFormatType();
725 else
727 pCode->Reset();
728 if ( pCode->GetNextOpCodeRPN( ocSubTotal ) )
729 bSubTotal = TRUE;
733 ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags ) :
734 ScBaseCell( rCell ),
735 SvtListener(),
736 aResult( rCell.aResult ),
737 eTempGrammar( rCell.eTempGrammar),
738 pDocument( &rDoc ),
739 pPrevious(0),
740 pNext(0),
741 pPreviousTrack(0),
742 pNextTrack(0),
743 nFormatIndex( &rDoc == rCell.pDocument ? rCell.nFormatIndex : 0 ),
744 nFormatType( rCell.nFormatType ),
745 nSeenInIteration(0),
746 cMatrixFlag ( rCell.cMatrixFlag ),
747 bDirty( rCell.bDirty ),
748 bChanged( rCell.bChanged ),
749 bRunning( FALSE ),
750 bCompile( rCell.bCompile ),
751 bSubTotal( rCell.bSubTotal ),
752 bIsIterCell( FALSE ),
753 bInChangeTrack( FALSE ),
754 bTableOpDirty( FALSE ),
755 bNeedListening( FALSE ),
756 aPos( rPos )
758 pCode = rCell.pCode->Clone();
760 if ( nCloneFlags & SC_CLONECELL_ADJUST3DREL )
761 pCode->ReadjustRelative3DReferences( rCell.aPos, aPos );
763 // evtl. Fehler zuruecksetzen und neu kompilieren
764 // nicht im Clipboard - da muss das Fehlerflag erhalten bleiben
765 // Spezialfall Laenge=0: als Fehlerzelle erzeugt, dann auch Fehler behalten
766 if ( pCode->GetCodeError() && !pDocument->IsClipboard() && pCode->GetLen() )
768 pCode->SetCodeError( 0 );
769 bCompile = TRUE;
771 //! Compile ColRowNames on URM_MOVE/URM_COPY _after_ UpdateReference
772 BOOL bCompileLater = FALSE;
773 BOOL bClipMode = rCell.pDocument->IsClipboard();
774 if( !bCompile )
775 { // Name references with references and ColRowNames
776 pCode->Reset();
777 ScToken* t;
778 while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceOrName()) ) != NULL && !bCompile )
780 if ( t->GetOpCode() == ocExternalRef )
782 // External name, cell, and area references.
783 bCompile = true;
785 else if ( t->GetType() == svIndex )
787 ScRangeData* pRangeData = rDoc.GetRangeName()->FindIndex( t->GetIndex() );
788 if( pRangeData )
790 if( pRangeData->HasReferences() )
791 bCompile = TRUE;
793 else
794 bCompile = TRUE; // invalid reference!
796 else if ( t->GetOpCode() == ocColRowName )
798 bCompile = TRUE; // new lookup needed
799 bCompileLater = bClipMode;
803 if( bCompile )
805 if ( !bCompileLater && bClipMode )
807 // Merging ranges needs the actual positions after UpdateReference.
808 // ColRowNames need new lookup after positions are adjusted.
809 bCompileLater = pCode->HasOpCode( ocRange) || pCode->HasOpCode( ocColRowName);
811 if ( !bCompileLater )
813 // bNoListening, not at all if in Clipboard/Undo,
814 // and not from Clipboard either, instead after Insert(Clone) and UpdateReference.
815 CompileTokenArray( TRUE );
819 if( nCloneFlags & SC_CLONECELL_STARTLISTENING )
820 StartListeningTo( &rDoc );
823 ScFormulaCell::~ScFormulaCell()
825 pDocument->RemoveFromFormulaTree( this );
826 if (pCode->HasOpCode(ocMacro))
827 pDocument->GetMacroManager()->RemoveDependentCell(this);
829 delete pCode;
830 #ifdef DBG_UTIL
831 eCellType = CELLTYPE_DESTROYED;
832 #endif
835 void ScFormulaCell::GetFormula( rtl::OUStringBuffer& rBuffer,
836 const FormulaGrammar::Grammar eGrammar ) const
838 if( pCode->GetCodeError() && !pCode->GetLen() )
840 rBuffer = rtl::OUStringBuffer( ScGlobal::GetErrorString( pCode->GetCodeError()));
841 return;
843 else if( cMatrixFlag == MM_REFERENCE )
845 // Reference to another cell that contains a matrix formula.
846 pCode->Reset();
847 ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
848 if( p )
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)
864 ((ScFormulaCell*)pCell)->GetFormula( rBuffer, eGrammar);
865 return;
867 else
869 ScCompiler aComp( pDocument, aPos, *pCode);
870 aComp.SetGrammar(eGrammar);
871 aComp.CreateStringFromTokenArray( rBuffer );
874 else
876 DBG_ERROR("ScFormulaCell::GetFormula: not a matrix");
879 else
881 ScCompiler aComp( pDocument, aPos, *pCode);
882 aComp.SetGrammar(eGrammar);
883 aComp.CreateStringFromTokenArray( rBuffer );
886 sal_Unicode ch('=');
887 rBuffer.insert( 0, &ch, 1 );
888 if( cMatrixFlag )
890 sal_Unicode ch2('{');
891 rBuffer.insert( 0, &ch2, 1);
892 rBuffer.append( sal_Unicode('}'));
896 void ScFormulaCell::GetFormula( String& rFormula, const FormulaGrammar::Grammar eGrammar ) const
898 rtl::OUStringBuffer rBuffer( rFormula );
899 GetFormula( rBuffer, eGrammar );
900 rFormula = rBuffer;
903 void ScFormulaCell::GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows )
905 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
906 Interpret();
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
914 rCols = 0;
915 rRows = 0;
919 void ScFormulaCell::Compile( const String& rFormula, BOOL bNoListening,
920 const FormulaGrammar::Grammar eGrammar )
922 if ( pDocument->IsClipOrUndo() ) return;
923 BOOL bWasInFormulaTree = pDocument->IsInFormulaTree( this );
924 if ( bWasInFormulaTree )
925 pDocument->RemoveFromFormulaTree( this );
926 // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein
927 if ( pCode )
928 pCode->Clear();
929 ScTokenArray* pCodeOld = pCode;
930 ScCompiler aComp( pDocument, aPos);
931 aComp.SetGrammar(eGrammar);
932 pCode = aComp.CompileString( rFormula );
933 if ( pCodeOld )
934 delete pCodeOld;
935 if( !pCode->GetCodeError() )
937 if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() && rFormula == aResult.GetHybridFormula() )
938 { // #65994# nicht rekursiv CompileTokenArray/Compile/CompileTokenArray
939 if ( rFormula.GetChar(0) == '=' )
940 pCode->AddBad( rFormula.GetBuffer() + 1 );
941 else
942 pCode->AddBad( rFormula.GetBuffer() );
944 bCompile = TRUE;
945 CompileTokenArray( bNoListening );
947 else
949 bChanged = TRUE;
950 SetTextWidth( TEXTWIDTH_DIRTY );
951 SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
953 if ( bWasInFormulaTree )
954 pDocument->PutInFormulaTree( this );
958 void ScFormulaCell::CompileTokenArray( BOOL bNoListening )
960 // Not already compiled?
961 if( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
962 Compile( aResult.GetHybridFormula(), bNoListening, eTempGrammar);
963 else if( bCompile && !pDocument->IsClipOrUndo() && !pCode->GetCodeError() )
965 // RPN length may get changed
966 BOOL bWasInFormulaTree = pDocument->IsInFormulaTree( this );
967 if ( bWasInFormulaTree )
968 pDocument->RemoveFromFormulaTree( this );
970 // Loading from within filter? No listening yet!
971 if( pDocument->IsInsertingFromOtherDoc() )
972 bNoListening = TRUE;
974 if( !bNoListening && pCode->GetCodeLen() )
975 EndListeningTo( pDocument );
976 ScCompiler aComp(pDocument, aPos, *pCode);
977 aComp.SetGrammar(pDocument->GetGrammar());
978 bSubTotal = aComp.CompileTokenArray();
979 if( !pCode->GetCodeError() )
981 nFormatType = aComp.GetNumFormatType();
982 nFormatIndex = 0;
983 bChanged = TRUE;
984 aResult.SetToken( NULL);
985 bCompile = FALSE;
986 if ( !bNoListening )
987 StartListeningTo( pDocument );
989 if ( bWasInFormulaTree )
990 pDocument->PutInFormulaTree( this );
995 void ScFormulaCell::CompileXML( ScProgress& rProgress )
997 if ( cMatrixFlag == MM_REFERENCE )
998 { // is already token code via ScDocFunc::EnterMatrix, ScDocument::InsertMatrixFormula
999 // just establish listeners
1000 StartListeningTo( pDocument );
1001 return ;
1004 ScCompiler aComp( pDocument, aPos, *pCode);
1005 aComp.SetGrammar(eTempGrammar);
1006 String aFormula, aFormulaNmsp;
1007 aComp.CreateStringFromXMLTokenArray( aFormula, aFormulaNmsp );
1008 pDocument->DecXMLImportedFormulaCount( aFormula.Len() );
1009 rProgress.SetStateCountDownOnPercent( pDocument->GetXMLImportedFormulaCount() );
1010 // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein
1011 if ( pCode )
1012 pCode->Clear();
1013 ScTokenArray* pCodeOld = pCode;
1014 pCode = aComp.CompileString( aFormula, aFormulaNmsp );
1015 delete pCodeOld;
1016 if( !pCode->GetCodeError() )
1018 if ( !pCode->GetLen() )
1020 if ( aFormula.GetChar(0) == '=' )
1021 pCode->AddBad( aFormula.GetBuffer() + 1 );
1022 else
1023 pCode->AddBad( aFormula.GetBuffer() );
1025 bSubTotal = aComp.CompileTokenArray();
1026 if( !pCode->GetCodeError() )
1028 nFormatType = aComp.GetNumFormatType();
1029 nFormatIndex = 0;
1030 bChanged = TRUE;
1031 bCompile = FALSE;
1032 StartListeningTo( pDocument );
1035 else
1037 bChanged = TRUE;
1038 SetTextWidth( TEXTWIDTH_DIRTY );
1039 SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
1042 // Same as in Load: after loading, it must be known if ocMacro is in any formula
1043 // (for macro warning, CompileXML is called at the end of loading XML file)
1044 if ( !pDocument->GetHasMacroFunc() && pCode->HasOpCodeRPN( ocMacro ) )
1045 pDocument->SetHasMacroFunc( TRUE );
1049 void ScFormulaCell::CalcAfterLoad()
1051 BOOL bNewCompiled = FALSE;
1052 // Falls ein Calc 1.0-Doc eingelesen wird, haben wir ein Ergebnis,
1053 // aber kein TokenArray
1054 if( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
1056 Compile( aResult.GetHybridFormula(), TRUE, eTempGrammar);
1057 aResult.SetToken( NULL);
1058 bDirty = TRUE;
1059 bNewCompiled = TRUE;
1061 // Das UPN-Array wird nicht erzeugt, wenn ein Calc 3.0-Doc eingelesen
1062 // wurde, da die RangeNames erst jetzt existieren.
1063 if( pCode->GetLen() && !pCode->GetCodeLen() && !pCode->GetCodeError() )
1065 ScCompiler aComp(pDocument, aPos, *pCode);
1066 aComp.SetGrammar(pDocument->GetGrammar());
1067 bSubTotal = aComp.CompileTokenArray();
1068 nFormatType = aComp.GetNumFormatType();
1069 nFormatIndex = 0;
1070 bDirty = TRUE;
1071 bCompile = FALSE;
1072 bNewCompiled = TRUE;
1074 // irgendwie koennen unter os/2 mit rotter FPU-Exception /0 ohne Err503
1075 // gespeichert werden, woraufhin spaeter im NumberFormatter die BLC Lib
1076 // bei einem fabs(-NAN) abstuerzt (#32739#)
1077 // hier fuer alle Systeme ausbuegeln, damit da auch Err503 steht
1078 if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
1080 DBG_ERRORFILE("Formelzelle INFINITY !!! Woher kommt das Dokument?");
1081 aResult.SetResultError( errIllegalFPOperation );
1082 bDirty = TRUE;
1084 // DoubleRefs bei binaeren Operatoren waren vor v5.0 immer Matrix,
1085 // jetzt nur noch wenn in Matrixformel, sonst implizite Schnittmenge
1086 if ( pDocument->GetSrcVersion() < SC_MATRIX_DOUBLEREF &&
1087 GetMatrixFlag() == MM_NONE && pCode->HasMatrixDoubleRefOps() )
1089 cMatrixFlag = MM_FORMULA;
1090 SetMatColsRows( 1, 1);
1092 // Muss die Zelle berechnet werden?
1093 // Nach Load koennen Zellen einen Fehlercode enthalten, auch dann
1094 // Listener starten und ggbf. neu berechnen wenn nicht RECALCMODE_NORMAL
1095 if( !bNewCompiled || !pCode->GetCodeError() )
1097 StartListeningTo( pDocument );
1098 if( !pCode->IsRecalcModeNormal() )
1099 bDirty = TRUE;
1101 if ( pCode->IsRecalcModeAlways() )
1102 { // zufall(), heute(), jetzt() bleiben immer im FormulaTree, damit sie
1103 // auch bei jedem F9 berechnet werden.
1104 bDirty = TRUE;
1106 // Noch kein SetDirty weil noch nicht alle Listener bekannt, erst in
1107 // SetDirtyAfterLoad.
1111 bool ScFormulaCell::MarkUsedExternalReferences()
1113 return pCode && pDocument->MarkUsedExternalReferences( *pCode);
1117 // FIXME: set to 0
1118 #define erDEBUGDOT 0
1119 // If set to 1, write output that's suitable for graphviz tools like dot.
1120 // Only node1 -> node2 entries are written, you'll have to manually surround
1121 // the file content with [strict] digraph name { ... }
1122 // The ``strict'' keyword might be necessary in case of multiple identical
1123 // paths like they occur in iterations, otherwise dot may consume too much
1124 // memory when generating the layout, or you'll get unreadable output. On the
1125 // other hand, information about recurring calculation is lost then.
1126 // Generates output only if variable nDebug is set in debugger, see below.
1127 // FIXME: currently doesn't cope with iterations and recursions. Code fragments
1128 // are a leftover from a previous debug session, meant as a pointer.
1129 #if erDEBUGDOT
1130 #include <cstdio>
1131 using ::std::fopen;
1132 using ::std::fprintf;
1133 #include <vector>
1134 static const char aDebugDotFile[] = "ttt_debug.dot";
1135 #endif
1137 void ScFormulaCell::Interpret()
1140 #if erDEBUGDOT
1141 static int nDebug = 0;
1142 static const int erDEBUGDOTRUN = 3;
1143 static FILE* pDebugFile = 0;
1144 static sal_Int32 nDebugRootCount = 0;
1145 static unsigned int nDebugPathCount = 0;
1146 static ScAddress aDebugLastPos( ScAddress::INITIALIZE_INVALID);
1147 static ScAddress aDebugThisPos( ScAddress::INITIALIZE_INVALID);
1148 typedef ::std::vector< ByteString > DebugVector;
1149 static DebugVector aDebugVec;
1150 class DebugElement
1152 public:
1153 static void push( ScFormulaCell* pCell )
1155 aDebugThisPos = pCell->aPos;
1156 if (aDebugVec.empty())
1158 ByteString aR( "root_");
1159 aR += ByteString::CreateFromInt32( ++nDebugRootCount);
1160 aDebugVec.push_back( aR);
1162 String aStr;
1163 pCell->aPos.Format( aStr, SCA_VALID | SCA_TAB_3D, pCell->GetDocument(),
1164 pCell->GetDocument()->GetAddressConvention() );
1165 ByteString aB( aStr, RTL_TEXTENCODING_UTF8);
1166 aDebugVec.push_back( aB);
1168 static void pop()
1170 aDebugLastPos = aDebugThisPos;
1171 if (!aDebugVec.empty())
1173 aDebugVec.pop_back();
1174 if (aDebugVec.size() == 1)
1176 aDebugVec.pop_back();
1177 aDebugLastPos = ScAddress( ScAddress::INITIALIZE_INVALID);
1181 DebugElement( ScFormulaCell* p ) { push(p); }
1182 ~DebugElement() { pop(); }
1184 class DebugDot
1186 public:
1187 static void out( const char* pColor )
1189 if (nDebug != erDEBUGDOTRUN)
1190 return;
1191 char pColorString[256];
1192 sprintf( pColorString, (*pColor ?
1193 ",color=\"%s\",fontcolor=\"%s\"" : "%s%s"), pColor,
1194 pColor);
1195 size_t n = aDebugVec.size();
1196 fprintf( pDebugFile,
1197 "\"%s\" -> \"%s\" [label=\"%u\"%s]; // v:%d\n",
1198 aDebugVec[n-2].GetBuffer(), aDebugVec[n-1].GetBuffer(),
1199 ++nDebugPathCount, pColorString, n-1);
1200 fflush( pDebugFile);
1203 #define erDEBUGDOT_OUT( p ) (DebugDot::out(p))
1204 #define erDEBUGDOT_ELEMENT_PUSH( p ) (DebugElement::push(p))
1205 #define erDEBUGDOT_ELEMENT_POP() (DebugElement::pop())
1206 #else
1207 #define erDEBUGDOT_OUT( p )
1208 #define erDEBUGDOT_ELEMENT_PUSH( p )
1209 #define erDEBUGDOT_ELEMENT_POP()
1210 #endif
1212 if (!IsDirtyOrInTableOpDirty() || pDocument->GetRecursionHelper().IsInReturn())
1213 return; // no double/triple processing
1215 //! HACK:
1216 // Wenn der Aufruf aus einem Reschedule im DdeLink-Update kommt, dirty stehenlassen
1217 // Besser: Dde-Link Update ohne Reschedule oder ganz asynchron !!!
1219 if ( pDocument->IsInDdeLinkUpdate() )
1220 return;
1222 #if erDEBUGDOT
1223 // set nDebug=1 in debugger to init things
1224 if (nDebug == 1)
1226 ++nDebug;
1227 pDebugFile = fopen( aDebugDotFile, "a");
1228 if (!pDebugFile)
1229 nDebug = 0;
1230 else
1231 nDebug = erDEBUGDOTRUN;
1233 // set nDebug=3 (erDEBUGDOTRUN) in debugger to get any output
1234 DebugElement aDebugElem( this);
1235 // set nDebug=5 in debugger to close output
1236 if (nDebug == 5)
1238 nDebug = 0;
1239 fclose( pDebugFile);
1240 pDebugFile = 0;
1242 #endif
1244 if (bRunning)
1247 #if erDEBUGDOT
1248 if (!pDocument->GetRecursionHelper().IsDoingIteration() ||
1249 aDebugThisPos != aDebugLastPos)
1250 erDEBUGDOT_OUT(aDebugThisPos == aDebugLastPos ? "orange" :
1251 (pDocument->GetRecursionHelper().GetIteration() ? "blue" :
1252 "red"));
1253 #endif
1255 if (!pDocument->GetDocOptions().IsIter())
1257 aResult.SetResultError( errCircularReference );
1258 return;
1261 if (aResult.GetResultError() == errCircularReference)
1262 aResult.SetResultError( 0 );
1264 // Start or add to iteration list.
1265 if (!pDocument->GetRecursionHelper().IsDoingIteration() ||
1266 !pDocument->GetRecursionHelper().GetRecursionInIterationStack().top()->bIsIterCell)
1267 pDocument->GetRecursionHelper().SetInIterationReturn( true);
1269 return;
1271 // #63038# no multiple interprets for GetErrCode, IsValue, GetValue and
1272 // different entry point recursions. Would also lead to premature
1273 // convergence in iterations.
1274 if (pDocument->GetRecursionHelper().GetIteration() && nSeenInIteration ==
1275 pDocument->GetRecursionHelper().GetIteration())
1276 return ;
1278 erDEBUGDOT_OUT( pDocument->GetRecursionHelper().GetIteration() ? "magenta" : "");
1280 ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper();
1281 BOOL bOldRunning = bRunning;
1282 if (rRecursionHelper.GetRecursionCount() > MAXRECURSION)
1284 bRunning = TRUE;
1285 rRecursionHelper.SetInRecursionReturn( true);
1287 else
1289 InterpretTail( SCITP_NORMAL);
1292 // While leaving a recursion or iteration stack, insert its cells to the
1293 // recursion list in reverse order.
1294 if (rRecursionHelper.IsInReturn())
1296 if (rRecursionHelper.GetRecursionCount() > 0 ||
1297 !rRecursionHelper.IsDoingRecursion())
1298 rRecursionHelper.Insert( this, bOldRunning, aResult);
1299 bool bIterationFromRecursion = false;
1300 bool bResumeIteration = false;
1303 if ((rRecursionHelper.IsInIterationReturn() &&
1304 rRecursionHelper.GetRecursionCount() == 0 &&
1305 !rRecursionHelper.IsDoingIteration()) ||
1306 bIterationFromRecursion || bResumeIteration)
1308 ScFormulaCell* pIterCell = this; // scope for debug convenience
1309 bool & rDone = rRecursionHelper.GetConvergingReference();
1310 rDone = false;
1311 if (!bIterationFromRecursion && bResumeIteration)
1313 bResumeIteration = false;
1314 // Resuming iteration expands the range.
1315 ScFormulaRecursionList::const_iterator aOldStart(
1316 rRecursionHelper.GetLastIterationStart());
1317 rRecursionHelper.ResumeIteration();
1318 // Mark new cells being in iteration.
1319 for (ScFormulaRecursionList::const_iterator aIter(
1320 rRecursionHelper.GetIterationStart()); aIter !=
1321 aOldStart; ++aIter)
1323 pIterCell = (*aIter).pCell;
1324 pIterCell->bIsIterCell = TRUE;
1326 // Mark older cells dirty again, in case they converted
1327 // without accounting for all remaining cells in the circle
1328 // that weren't touched so far, e.g. conditional. Restore
1329 // backuped result.
1330 USHORT nIteration = rRecursionHelper.GetIteration();
1331 for (ScFormulaRecursionList::const_iterator aIter(
1332 aOldStart); aIter !=
1333 rRecursionHelper.GetIterationEnd(); ++aIter)
1335 pIterCell = (*aIter).pCell;
1336 if (pIterCell->nSeenInIteration == nIteration)
1338 if (!pIterCell->bDirty || aIter == aOldStart)
1340 pIterCell->aResult = (*aIter).aPreviousResult;
1342 --pIterCell->nSeenInIteration;
1344 pIterCell->bDirty = TRUE;
1347 else
1349 bResumeIteration = false;
1350 // Close circle once.
1351 rRecursionHelper.GetList().back().pCell->InterpretTail(
1352 SCITP_CLOSE_ITERATION_CIRCLE);
1353 // Start at 1, init things.
1354 rRecursionHelper.StartIteration();
1355 // Mark all cells being in iteration.
1356 for (ScFormulaRecursionList::const_iterator aIter(
1357 rRecursionHelper.GetIterationStart()); aIter !=
1358 rRecursionHelper.GetIterationEnd(); ++aIter)
1360 pIterCell = (*aIter).pCell;
1361 pIterCell->bIsIterCell = TRUE;
1364 bIterationFromRecursion = false;
1365 USHORT nIterMax = pDocument->GetDocOptions().GetIterCount();
1366 for ( ; rRecursionHelper.GetIteration() <= nIterMax && !rDone;
1367 rRecursionHelper.IncIteration())
1369 rDone = true;
1370 for ( ScFormulaRecursionList::iterator aIter(
1371 rRecursionHelper.GetIterationStart()); aIter !=
1372 rRecursionHelper.GetIterationEnd() &&
1373 !rRecursionHelper.IsInReturn(); ++aIter)
1375 pIterCell = (*aIter).pCell;
1376 if (pIterCell->IsDirtyOrInTableOpDirty() &&
1377 rRecursionHelper.GetIteration() !=
1378 pIterCell->GetSeenInIteration())
1380 (*aIter).aPreviousResult = pIterCell->aResult;
1381 pIterCell->InterpretTail( SCITP_FROM_ITERATION);
1383 rDone = rDone && !pIterCell->IsDirtyOrInTableOpDirty();
1385 if (rRecursionHelper.IsInReturn())
1387 bResumeIteration = true;
1388 break; // for
1389 // Don't increment iteration.
1392 if (!bResumeIteration)
1394 if (rDone)
1396 for (ScFormulaRecursionList::const_iterator aIter(
1397 rRecursionHelper.GetIterationStart());
1398 aIter != rRecursionHelper.GetIterationEnd();
1399 ++aIter)
1401 pIterCell = (*aIter).pCell;
1402 pIterCell->bIsIterCell = FALSE;
1403 pIterCell->nSeenInIteration = 0;
1404 pIterCell->bRunning = (*aIter).bOldRunning;
1407 else
1409 for (ScFormulaRecursionList::const_iterator aIter(
1410 rRecursionHelper.GetIterationStart());
1411 aIter != rRecursionHelper.GetIterationEnd();
1412 ++aIter)
1414 pIterCell = (*aIter).pCell;
1415 pIterCell->bIsIterCell = FALSE;
1416 pIterCell->nSeenInIteration = 0;
1417 pIterCell->bRunning = (*aIter).bOldRunning;
1418 // If one cell didn't converge, all cells of this
1419 // circular dependency don't, no matter whether
1420 // single cells did.
1421 pIterCell->bDirty = FALSE;
1422 pIterCell->bTableOpDirty = FALSE;
1423 pIterCell->aResult.SetResultError( errNoConvergence);
1424 pIterCell->bChanged = TRUE;
1425 pIterCell->SetTextWidth( TEXTWIDTH_DIRTY);
1426 pIterCell->SetScriptType( SC_SCRIPTTYPE_UNKNOWN);
1429 // End this iteration and remove entries.
1430 rRecursionHelper.EndIteration();
1431 bResumeIteration = rRecursionHelper.IsDoingIteration();
1434 if (rRecursionHelper.IsInRecursionReturn() &&
1435 rRecursionHelper.GetRecursionCount() == 0 &&
1436 !rRecursionHelper.IsDoingRecursion())
1438 bIterationFromRecursion = false;
1439 // Iterate over cells known so far, start with the last cell
1440 // encountered, inserting new cells if another recursion limit
1441 // is reached. Repeat until solved.
1442 rRecursionHelper.SetDoingRecursion( true);
1445 rRecursionHelper.SetInRecursionReturn( false);
1446 for (ScFormulaRecursionList::const_iterator aIter(
1447 rRecursionHelper.GetStart());
1448 !rRecursionHelper.IsInReturn() && aIter !=
1449 rRecursionHelper.GetEnd(); ++aIter)
1451 ScFormulaCell* pCell = (*aIter).pCell;
1452 if (pCell->IsDirtyOrInTableOpDirty())
1454 pCell->InterpretTail( SCITP_NORMAL);
1455 if (!pCell->IsDirtyOrInTableOpDirty() && !pCell->IsIterCell())
1456 pCell->bRunning = (*aIter).bOldRunning;
1459 } while (rRecursionHelper.IsInRecursionReturn());
1460 rRecursionHelper.SetDoingRecursion( false);
1461 if (rRecursionHelper.IsInIterationReturn())
1463 if (!bResumeIteration)
1464 bIterationFromRecursion = true;
1466 else if (bResumeIteration ||
1467 rRecursionHelper.IsDoingIteration())
1468 rRecursionHelper.GetList().erase(
1469 rRecursionHelper.GetStart(),
1470 rRecursionHelper.GetLastIterationStart());
1471 else
1472 rRecursionHelper.Clear();
1474 } while (bIterationFromRecursion || bResumeIteration);
1477 // Fire worksheet calculate event
1478 pDocument->FireCalculateEvent( aPos.Tab() );
1481 void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam )
1483 class RecursionCounter
1485 ScRecursionHelper& rRec;
1486 bool bStackedInIteration;
1487 public:
1488 RecursionCounter( ScRecursionHelper& r, ScFormulaCell* p ) : rRec(r)
1490 bStackedInIteration = rRec.IsDoingIteration();
1491 if (bStackedInIteration)
1492 rRec.GetRecursionInIterationStack().push( p);
1493 rRec.IncRecursionCount();
1495 ~RecursionCounter()
1497 rRec.DecRecursionCount();
1498 if (bStackedInIteration)
1499 rRec.GetRecursionInIterationStack().pop();
1501 } aRecursionCounter( pDocument->GetRecursionHelper(), this);
1502 nSeenInIteration = pDocument->GetRecursionHelper().GetIteration();
1503 if( !pCode->GetCodeLen() && !pCode->GetCodeError() )
1505 // #i11719# no UPN and no error and no token code but result string present
1506 // => interpretation of this cell during name-compilation and unknown names
1507 // => can't exchange underlying code array in CompileTokenArray() /
1508 // Compile() because interpreter's token iterator would crash.
1509 // This should only be a temporary condition and, since we set an
1510 // error, if ran into it again we'd bump into the dirty-clearing
1511 // condition further down.
1512 if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
1514 pCode->SetCodeError( errNoCode );
1515 // This is worth an assertion; if encountered in daily work
1516 // documents we might need another solution. Or just confirm correctness.
1517 DBG_ERRORFILE( "ScFormulaCell::Interpret: no UPN, no error, no token, but string" );
1518 return;
1520 CompileTokenArray();
1523 if( pCode->GetCodeLen() && pDocument )
1525 class StackCleaner
1527 ScDocument* pDoc;
1528 ScInterpreter* pInt;
1529 public:
1530 StackCleaner( ScDocument* pD, ScInterpreter* pI )
1531 : pDoc(pD), pInt(pI)
1533 ~StackCleaner()
1535 delete pInt;
1536 pDoc->DecInterpretLevel();
1539 pDocument->IncInterpretLevel();
1540 ScInterpreter* p = new ScInterpreter( this, pDocument, aPos, *pCode );
1541 StackCleaner aStackCleaner( pDocument, p);
1542 USHORT nOldErrCode = aResult.GetResultError();
1543 if ( nSeenInIteration == 0 )
1544 { // Only the first time
1545 // With bChanged=FALSE, if a newly compiled cell has a result of
1546 // 0.0, no change is detected and the cell will not be repainted.
1547 // bChanged = FALSE;
1548 aResult.SetResultError( 0 );
1551 switch ( aResult.GetResultError() )
1553 case errCircularReference : // will be determined again if so
1554 aResult.SetResultError( 0 );
1555 break;
1558 BOOL bOldRunning = bRunning;
1559 bRunning = TRUE;
1560 p->Interpret();
1561 if (pDocument->GetRecursionHelper().IsInReturn() && eTailParam != SCITP_CLOSE_ITERATION_CIRCLE)
1563 if (nSeenInIteration > 0)
1564 --nSeenInIteration; // retry when iteration is resumed
1565 return;
1567 bRunning = bOldRunning;
1569 // #i102616# For single-sheet saving consider only content changes, not format type,
1570 // because format type isn't set on loading (might be changed later)
1571 BOOL bContentChanged = FALSE;
1573 // Do not create a HyperLink() cell if the formula results in an error.
1574 if( p->GetError() && pCode->IsHyperLink())
1575 pCode->SetHyperLink(FALSE);
1577 if( p->GetError() && p->GetError() != errCircularReference)
1579 bDirty = FALSE;
1580 bTableOpDirty = FALSE;
1581 bChanged = TRUE;
1583 if (eTailParam == SCITP_FROM_ITERATION && IsDirtyOrInTableOpDirty())
1585 bool bIsValue = aResult.IsValue(); // the previous type
1586 // Did it converge?
1587 if ((bIsValue && p->GetResultType() == svDouble && fabs(
1588 p->GetNumResult() - aResult.GetDouble()) <=
1589 pDocument->GetDocOptions().GetIterEps()) ||
1590 (!bIsValue && p->GetResultType() == svString &&
1591 p->GetStringResult() == aResult.GetString()))
1593 // A convergence in the first iteration doesn't necessarily
1594 // mean that it's done, it may be because not all related cells
1595 // of a circle changed their values yet. If the set really
1596 // converges it will do so also during the next iteration. This
1597 // fixes situations like of #i44115#. If this wasn't wanted an
1598 // initial "uncalculated" value would be needed for all cells
1599 // of a circular dependency => graph needed before calculation.
1600 if (nSeenInIteration > 1 ||
1601 pDocument->GetDocOptions().GetIterCount() == 1)
1603 bDirty = FALSE;
1604 bTableOpDirty = FALSE;
1609 // New error code?
1610 if( p->GetError() != nOldErrCode )
1612 bChanged = TRUE;
1613 // bContentChanged only has to be set if the file content would be changed
1614 if ( aResult.GetCellResultType() != svUnknown )
1615 bContentChanged = TRUE;
1617 // Different number format?
1618 if( nFormatType != p->GetRetFormatType() )
1620 nFormatType = p->GetRetFormatType();
1621 bChanged = TRUE;
1623 if( nFormatIndex != p->GetRetFormatIndex() )
1625 nFormatIndex = p->GetRetFormatIndex();
1626 bChanged = TRUE;
1629 // In case of changes just obtain the result, no temporary and
1630 // comparison needed anymore.
1631 if (bChanged)
1633 // #i102616# Compare anyway if the sheet is still marked unchanged for single-sheet saving
1634 // Also handle special cases of initial results after loading.
1636 if ( !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
1638 ScFormulaResult aNewResult( p->GetResultToken());
1639 StackVar eOld = aResult.GetCellResultType();
1640 StackVar eNew = aNewResult.GetCellResultType();
1641 if ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) )
1643 // ScXMLTableRowCellContext::EndElement doesn't call SetFormulaResultDouble for 0
1644 // -> no change
1646 else
1648 if ( eOld == svHybridCell ) // string result from SetFormulaResultString?
1649 eOld = svString; // ScHybridCellToken has a valid GetString method
1651 bContentChanged = (eOld != eNew ||
1652 (eNew == svDouble && aResult.GetDouble() != aNewResult.GetDouble()) ||
1653 (eNew == svString && aResult.GetString() != aNewResult.GetString()));
1657 aResult.SetToken( p->GetResultToken() );
1659 else
1661 ScFormulaResult aNewResult( p->GetResultToken());
1662 StackVar eOld = aResult.GetCellResultType();
1663 StackVar eNew = aNewResult.GetCellResultType();
1664 bChanged = (eOld != eNew ||
1665 (eNew == svDouble && aResult.GetDouble() != aNewResult.GetDouble()) ||
1666 (eNew == svString && aResult.GetString() != aNewResult.GetString()));
1668 // #i102616# handle special cases of initial results after loading (only if the sheet is still marked unchanged)
1669 if ( bChanged && !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) )
1671 if ( ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) ) ||
1672 ( eOld == svHybridCell && eNew == svString && aResult.GetString() == aNewResult.GetString() ) )
1674 // no change, see above
1676 else
1677 bContentChanged = TRUE;
1680 aResult.Assign( aNewResult);
1683 // Precision as shown?
1684 if ( aResult.IsValue() && !p->GetError()
1685 && pDocument->GetDocOptions().IsCalcAsShown()
1686 && nFormatType != NUMBERFORMAT_DATE
1687 && nFormatType != NUMBERFORMAT_TIME
1688 && nFormatType != NUMBERFORMAT_DATETIME )
1690 ULONG nFormat = pDocument->GetNumberFormat( aPos );
1691 if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1692 nFormat = nFormatIndex;
1693 if ( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1694 nFormat = ScGlobal::GetStandardFormat(
1695 *pDocument->GetFormatTable(), nFormat, nFormatType );
1696 aResult.SetDouble( pDocument->RoundValueAsShown(
1697 aResult.GetDouble(), nFormat));
1699 if (eTailParam == SCITP_NORMAL)
1701 bDirty = FALSE;
1702 bTableOpDirty = FALSE;
1704 if( aResult.GetMatrix().Is() )
1706 // If the formula wasn't entered as a matrix formula, live on with
1707 // the upper left corner and let reference counting delete the matrix.
1708 if( cMatrixFlag != MM_FORMULA && !pCode->IsHyperLink() )
1709 aResult.SetToken( aResult.GetCellResultToken());
1711 if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
1713 // Coded double error may occur via filter import.
1714 USHORT nErr = GetDoubleErrorValue( aResult.GetDouble());
1715 aResult.SetResultError( nErr);
1716 bChanged = bContentChanged = true;
1718 if( bChanged )
1720 SetTextWidth( TEXTWIDTH_DIRTY );
1721 SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
1723 if (bContentChanged && pDocument->IsStreamValid(aPos.Tab()))
1725 // pass bIgnoreLock=TRUE, because even if called from pending row height update,
1726 // a changed result must still reset the stream flag
1727 pDocument->SetStreamValid(aPos.Tab(), FALSE, TRUE);
1729 if ( !pCode->IsRecalcModeAlways() )
1730 pDocument->RemoveFromFormulaTree( this );
1732 // FORCED Zellen auch sofort auf Gueltigkeit testen (evtl. Makro starten)
1734 if ( pCode->IsRecalcModeForced() )
1736 ULONG nValidation = ((const SfxUInt32Item*) pDocument->GetAttr(
1737 aPos.Col(), aPos.Row(), aPos.Tab(), ATTR_VALIDDATA ))->GetValue();
1738 if ( nValidation )
1740 const ScValidationData* pData = pDocument->GetValidationEntry( nValidation );
1741 if ( pData && !pData->IsDataValid( this, aPos ) )
1742 pData->DoCalcError( this );
1746 // Reschedule verlangsamt das ganze erheblich, nur bei Prozentaenderung ausfuehren
1747 ScProgress::GetInterpretProgress()->SetStateCountDownOnPercent(
1748 pDocument->GetFormulaCodeInTree()/MIN_NO_CODES_PER_PROGRESS_UPDATE );
1750 switch (p->GetVolatileType())
1752 case ScInterpreter::VOLATILE:
1753 // Volatile via built-in volatile functions. No actions needed.
1754 break;
1755 case ScInterpreter::VOLATILE_MACRO:
1756 // The formula contains a volatile macro.
1757 pCode->SetRecalcModeAlways();
1758 pDocument->PutInFormulaTree(this);
1759 StartListeningTo(pDocument);
1760 break;
1761 case ScInterpreter::NOT_VOLATILE:
1762 if (pCode->IsRecalcModeAlways())
1764 // The formula was previously volatile, but no more.
1765 EndListeningTo(pDocument);
1766 pCode->SetRecalcModeNormal();
1768 else
1770 // non-volatile formula. End listening to the area in case
1771 // it's listening due to macro module change.
1772 pDocument->EndListeningArea(BCA_LISTEN_ALWAYS, this);
1774 pDocument->RemoveFromFormulaTree(this);
1775 break;
1776 default:
1780 else
1782 // Zelle bei Compiler-Fehlern nicht ewig auf dirty stehenlassen
1783 DBG_ASSERT( pCode->GetCodeError(), "kein UPN-Code und kein Fehler ?!?!" );
1784 bDirty = FALSE;
1785 bTableOpDirty = FALSE;
1790 void ScFormulaCell::SetMatColsRows( SCCOL nCols, SCROW nRows )
1792 ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellTokenNonConst();
1793 if (pMat)
1794 pMat->SetMatColsRows( nCols, nRows);
1795 else if (nCols || nRows)
1796 aResult.SetToken( new ScMatrixFormulaCellToken( nCols, nRows));
1800 void ScFormulaCell::GetMatColsRows( SCCOL & nCols, SCROW & nRows ) const
1802 const ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellToken();
1803 if (pMat)
1804 pMat->GetMatColsRows( nCols, nRows);
1805 else
1807 nCols = 0;
1808 nRows = 0;
1813 ULONG ScFormulaCell::GetStandardFormat( SvNumberFormatter& rFormatter, ULONG nFormat ) const
1815 if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1816 return nFormatIndex;
1817 //! not ScFormulaCell::IsValue(), that could reinterpret the formula again.
1818 if ( aResult.IsValue() )
1819 return ScGlobal::GetStandardFormat( aResult.GetDouble(), rFormatter, nFormat, nFormatType );
1820 else
1821 return ScGlobal::GetStandardFormat( rFormatter, nFormat, nFormatType );
1825 void __EXPORT ScFormulaCell::Notify( SvtBroadcaster&, const SfxHint& rHint)
1827 if ( !pDocument->IsInDtorClear() && !pDocument->GetHardRecalcState() )
1829 const ScHint* p = PTR_CAST( ScHint, &rHint );
1830 ULONG nHint = (p ? p->GetId() : 0);
1831 if (nHint & (SC_HINT_DATACHANGED | SC_HINT_DYING | SC_HINT_TABLEOPDIRTY))
1833 BOOL bForceTrack = FALSE;
1834 if ( nHint & SC_HINT_TABLEOPDIRTY )
1836 bForceTrack = !bTableOpDirty;
1837 if ( !bTableOpDirty )
1839 pDocument->AddTableOpFormulaCell( this );
1840 bTableOpDirty = TRUE;
1843 else
1845 bForceTrack = !bDirty;
1846 SetDirtyVar();
1848 // #35962# Don't remove from FormulaTree to put in FormulaTrack to
1849 // put in FormulaTree again and again, only if necessary.
1850 // Any other means except RECALCMODE_ALWAYS by which a cell could
1851 // be in FormulaTree if it would notify other cells through
1852 // FormulaTrack which weren't in FormulaTrack/FormulaTree before?!?
1853 // #87866# Yes. The new TableOpDirty made it necessary to have a
1854 // forced mode where formulas may still be in FormulaTree from
1855 // TableOpDirty but have to notify dependents for normal dirty.
1856 if ( (bForceTrack || !pDocument->IsInFormulaTree( this )
1857 || pCode->IsRecalcModeAlways())
1858 && !pDocument->IsInFormulaTrack( this ) )
1859 pDocument->AppendToFormulaTrack( this );
1864 void ScFormulaCell::SetDirty()
1866 if ( !IsInChangeTrack() )
1868 if ( pDocument->GetHardRecalcState() )
1869 SetDirtyVar();
1870 else
1872 // Mehrfach-FormulaTracking in Load und in CompileAll
1873 // nach CopyScenario und CopyBlockFromClip vermeiden.
1874 // Wenn unbedingtes FormulaTracking noetig, vor SetDirty bDirty=FALSE
1875 // setzen, z.B. in CompileTokenArray
1876 if ( !bDirty || !pDocument->IsInFormulaTree( this ) )
1878 SetDirtyVar();
1879 pDocument->AppendToFormulaTrack( this );
1880 pDocument->TrackFormulas();
1884 if (pDocument->IsStreamValid(aPos.Tab()))
1885 pDocument->SetStreamValid(aPos.Tab(), FALSE);
1889 void ScFormulaCell::SetDirtyVar()
1891 bDirty = TRUE;
1892 // mark the sheet of this cell to be calculated
1893 pDocument->AddCalculateTable( aPos.Tab() );
1896 void ScFormulaCell::SetDirtyAfterLoad()
1898 if ( bDirty && !pDocument->GetHardRecalcState() )
1899 pDocument->PutInFormulaTree( this );
1902 void ScFormulaCell::SetTableOpDirty()
1904 if ( !IsInChangeTrack() )
1906 if ( pDocument->GetHardRecalcState() )
1907 bTableOpDirty = TRUE;
1908 else
1910 if ( !bTableOpDirty || !pDocument->IsInFormulaTree( this ) )
1912 if ( !bTableOpDirty )
1914 pDocument->AddTableOpFormulaCell( this );
1915 bTableOpDirty = TRUE;
1917 pDocument->AppendToFormulaTrack( this );
1918 pDocument->TrackFormulas( SC_HINT_TABLEOPDIRTY );
1925 BOOL ScFormulaCell::IsDirtyOrInTableOpDirty() const
1927 return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp());
1931 void ScFormulaCell::SetErrCode( USHORT n )
1933 /* FIXME: check the numerous places where ScTokenArray::GetCodeError() is
1934 * used whether it is solely for transport of a simple result error and get
1935 * rid of that abuse. */
1936 pCode->SetCodeError( n );
1937 // Hard set errors are transported as result type value per convention,
1938 // e.g. via clipboard. ScFormulaResult::IsValue() and
1939 // ScFormulaResult::GetDouble() handle that.
1940 aResult.SetResultError( n );
1943 void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits )
1945 if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL )
1946 bDirty = TRUE;
1947 if ( nBits & RECALCMODE_ONLOAD_ONCE )
1948 { // OnLoadOnce nur zum Dirty setzen nach Filter-Import
1949 nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL;
1951 pCode->AddRecalcMode( nBits );
1954 // Dynamically create the URLField on a mouse-over action on a hyperlink() cell.
1955 void ScFormulaCell::GetURLResult( String& rURL, String& rCellText )
1957 String aCellString;
1959 Color* pColor;
1961 // Cell Text uses the Cell format while the URL uses
1962 // the default format for the type.
1963 ULONG nCellFormat = pDocument->GetNumberFormat( aPos );
1964 SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
1966 if ( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1967 nCellFormat = GetStandardFormat( *pFormatter,nCellFormat );
1969 ULONG nURLFormat = ScGlobal::GetStandardFormat( *pFormatter,nCellFormat, NUMBERFORMAT_NUMBER);
1971 if ( IsValue() )
1973 double fValue = GetValue();
1974 pFormatter->GetOutputString( fValue, nCellFormat, rCellText, &pColor );
1976 else
1978 GetString( aCellString );
1979 pFormatter->GetOutputString( aCellString, nCellFormat, rCellText, &pColor );
1981 ScConstMatrixRef xMat( aResult.GetMatrix());
1982 if (xMat)
1984 ScMatValType nMatValType;
1985 // determine if the matrix result is a string or value.
1986 const ScMatrixValue* pMatVal = xMat->Get(0, 1, nMatValType);
1987 if (pMatVal)
1989 if (!ScMatrix::IsValueType( nMatValType))
1990 rURL = pMatVal->GetString();
1991 else
1992 pFormatter->GetOutputString( pMatVal->fVal, nURLFormat, rURL, &pColor );
1996 if(!rURL.Len())
1998 if(IsValue())
1999 pFormatter->GetOutputString( GetValue(), nURLFormat, rURL, &pColor );
2000 else
2001 pFormatter->GetOutputString( aCellString, nURLFormat, rURL, &pColor );
2005 bool ScFormulaCell::IsMultilineResult()
2007 if (!IsValue())
2008 return aResult.IsMultiline();
2009 return false;
2012 EditTextObject* ScFormulaCell::CreateURLObject()
2014 String aCellText;
2015 String aURL;
2016 GetURLResult( aURL, aCellText );
2018 SvxURLField aUrlField( aURL, aCellText, SVXURLFORMAT_APPDEFAULT);
2019 EditEngine& rEE = pDocument->GetEditEngine();
2020 rEE.SetText( EMPTY_STRING );
2021 rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection( 0xFFFF, 0xFFFF ) );
2023 return rEE.CreateTextObject();
2026 // ============================================================================
2028 ScDetectiveRefIter::ScDetectiveRefIter( ScFormulaCell* pCell )
2030 pCode = pCell->GetCode();
2031 pCode->Reset();
2032 aPos = pCell->aPos;
2035 BOOL lcl_ScDetectiveRefIter_SkipRef( ScToken* p )
2037 ScSingleRefData& rRef1 = p->GetSingleRef();
2038 if ( rRef1.IsColDeleted() || rRef1.IsRowDeleted() || rRef1.IsTabDeleted()
2039 || !rRef1.Valid() )
2040 return TRUE;
2041 if ( p->GetType() == svDoubleRef || p->GetType() == svExternalDoubleRef )
2043 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
2044 if ( rRef2.IsColDeleted() || rRef2.IsRowDeleted() || rRef2.IsTabDeleted()
2045 || !rRef2.Valid() )
2046 return TRUE;
2048 return FALSE;
2051 BOOL ScDetectiveRefIter::GetNextRef( ScRange& rRange )
2053 BOOL bRet = FALSE;
2054 ScToken* p = GetNextRefToken();
2055 if( p )
2057 SingleDoubleRefProvider aProv( *p );
2058 rRange.aStart.Set( aProv.Ref1.nCol, aProv.Ref1.nRow, aProv.Ref1.nTab );
2059 rRange.aEnd.Set( aProv.Ref2.nCol, aProv.Ref2.nRow, aProv.Ref2.nTab );
2060 bRet = TRUE;
2063 return bRet;
2066 ScToken* ScDetectiveRefIter::GetNextRefToken()
2068 ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
2069 if (p)
2070 p->CalcAbsIfRel( aPos );
2072 while ( p && lcl_ScDetectiveRefIter_SkipRef( p ) )
2074 p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
2075 if (p)
2076 p->CalcAbsIfRel( aPos );
2078 return p;
2081 // ============================================================================