update ooo310-m15
[ooovba.git] / sc / source / core / data / cell2.cxx
blob4c38b399318f2a0a3a94a1c8acfc802deffd31de
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: cell2.cxx,v $
10 * $Revision: 1.34.102.2 $
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"
36 // INCLUDE ---------------------------------------------------------------
37 #include <vcl/mapmod.hxx>
38 #include <svx/editobj.hxx>
39 #include <svx/editstat.hxx>
41 #include "cell.hxx"
42 #include "compiler.hxx"
43 #include "formula/errorcodes.hxx"
44 #include "document.hxx"
45 #include "rangenam.hxx"
46 #include "rechead.hxx"
47 #include "refupdat.hxx"
48 #include "scmatrix.hxx"
49 #include "editutil.hxx"
50 #include "chgtrack.hxx"
51 #include "indexmap.hxx"
52 #include "externalrefmgr.hxx"
53 #include "scitems.hxx"
54 #include "patattr.hxx"
56 using namespace formula;
58 // STATIC DATA -----------------------------------------------------------
60 #ifdef USE_MEMPOOL
61 const USHORT nMemPoolEditCell = (0x1000 - 64) / sizeof(ScNoteCell);
62 IMPL_FIXEDMEMPOOL_NEWDEL( ScEditCell, nMemPoolEditCell, nMemPoolEditCell )
63 #endif
65 // ============================================================================
67 ScEditCell::ScEditCell( const EditTextObject* pObject, ScDocument* pDocP,
68 const SfxItemPool* pFromPool ) :
69 ScBaseCell( CELLTYPE_EDIT ),
70 pString( NULL ),
71 pDoc( pDocP )
73 SetTextObject( pObject, pFromPool );
76 ScEditCell::ScEditCell( const ScEditCell& rCell, ScDocument& rDoc ) :
77 ScBaseCell( rCell ),
78 pString( NULL ),
79 pDoc( &rDoc )
81 SetTextObject( rCell.pData, rCell.pDoc->GetEditPool() );
84 ScEditCell::ScEditCell( const String& rString, ScDocument* pDocP ) :
85 ScBaseCell( CELLTYPE_EDIT ),
86 pString( NULL ),
87 pDoc( pDocP )
89 DBG_ASSERT( rString.Search('\n') != STRING_NOTFOUND ||
90 rString.Search(CHAR_CR) != STRING_NOTFOUND,
91 "EditCell mit einfachem Text !?!?" );
93 EditEngine& rEngine = pDoc->GetEditEngine();
94 rEngine.SetText( rString );
95 pData = rEngine.CreateTextObject();
98 ScEditCell::~ScEditCell()
100 delete pData;
101 delete pString;
103 #ifdef DBG_UTIL
104 eCellType = CELLTYPE_DESTROYED;
105 #endif
108 void ScEditCell::SetData( const EditTextObject* pObject,
109 const SfxItemPool* pFromPool )
111 if ( pString )
113 delete pString;
114 pString = NULL;
116 delete pData;
117 SetTextObject( pObject, pFromPool );
120 void ScEditCell::GetData( const EditTextObject*& rpObject ) const
122 rpObject = pData;
125 void ScEditCell::GetString( String& rString ) const
127 if ( pString )
128 rString = *pString;
129 else if ( pData )
131 // auch Text von URL-Feldern, Doc-Engine ist eine ScFieldEditEngine
132 EditEngine& rEngine = pDoc->GetEditEngine();
133 rEngine.SetText( *pData );
134 rString = ScEditUtil::GetMultilineString(rEngine); // string with line separators between paragraphs
135 // kurze Strings fuer Formeln merken
136 if ( rString.Len() < MAXSTRLEN )
137 ((ScEditCell*)this)->pString = new String( rString ); //! non-const
139 else
140 rString.Erase();
143 bool ScEditCell::HasPhonetic() const
145 return false;
148 void ScEditCell::RemoveCharAttribs( const ScPatternAttr& rAttr )
150 const struct {
151 USHORT nAttrType;
152 USHORT nCharType;
153 } AttrTypeMap[] = {
154 { ATTR_FONT, EE_CHAR_FONTINFO },
155 { ATTR_FONT_HEIGHT, EE_CHAR_FONTHEIGHT },
156 { ATTR_FONT_WEIGHT, EE_CHAR_WEIGHT },
157 { ATTR_FONT_COLOR, EE_CHAR_COLOR }
159 USHORT nMapCount = sizeof(AttrTypeMap) / sizeof(AttrTypeMap[0]);
161 const SfxItemSet& rSet = rAttr.GetItemSet();
162 const SfxPoolItem* pItem;
163 for (USHORT i = 0; i < nMapCount; ++i)
165 if ( rSet.GetItemState(AttrTypeMap[i].nAttrType, false, &pItem) == SFX_ITEM_SET )
166 pData->RemoveCharAttribs(AttrTypeMap[i].nCharType);
170 void ScEditCell::SetTextObject( const EditTextObject* pObject,
171 const SfxItemPool* pFromPool )
173 if ( pObject )
175 if ( pFromPool && pDoc->GetEditPool() == pFromPool )
176 pData = pObject->Clone();
177 else
178 { //! anderer Pool
179 // Leider gibt es keinen anderen Weg, um den Pool umzuhaengen,
180 // als das Object durch eine entsprechende Engine zu schleusen..
181 EditEngine& rEngine = pDoc->GetEditEngine();
182 if ( pObject->HasOnlineSpellErrors() )
184 ULONG nControl = rEngine.GetControlWord();
185 const ULONG nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
186 BOOL bNewControl = ( (nControl & nSpellControl) != nSpellControl );
187 if ( bNewControl )
188 rEngine.SetControlWord( nControl | nSpellControl );
189 rEngine.SetText( *pObject );
190 pData = rEngine.CreateTextObject();
191 if ( bNewControl )
192 rEngine.SetControlWord( nControl );
194 else
196 rEngine.SetText( *pObject );
197 pData = rEngine.CreateTextObject();
201 else
202 pData = NULL;
205 ScEditDataArray::ScEditDataArray()
209 ScEditDataArray::~ScEditDataArray()
213 void ScEditDataArray::AddItem(SCTAB nTab, SCCOL nCol, SCROW nRow,
214 EditTextObject* pOldData, EditTextObject* pNewData)
216 maArray.push_back(Item(nTab, nCol, nRow, pOldData, pNewData));
219 const ScEditDataArray::Item* ScEditDataArray::First()
221 maIter = maArray.begin();
222 if (maIter == maArray.end())
223 return NULL;
224 return &(*maIter++);
227 const ScEditDataArray::Item* ScEditDataArray::Next()
229 if (maIter == maArray.end())
230 return NULL;
231 return &(*maIter++);
234 // ============================================================================
236 ScEditDataArray::Item::Item(SCTAB nTab, SCCOL nCol, SCROW nRow,
237 EditTextObject* pOldData, EditTextObject* pNewData) :
238 mnTab(nTab),
239 mnCol(nCol),
240 mnRow(nRow)
242 mpOldData.reset(pOldData);
243 mpNewData.reset(pNewData);
246 ScEditDataArray::Item::~Item()
250 const EditTextObject* ScEditDataArray::Item::GetOldData() const
252 return mpOldData.get();
255 const EditTextObject* ScEditDataArray::Item::GetNewData() const
257 return mpNewData.get();
260 SCTAB ScEditDataArray::Item::GetTab() const
262 return mnTab;
265 SCCOL ScEditDataArray::Item::GetCol() const
267 return mnCol;
270 SCROW ScEditDataArray::Item::GetRow() const
272 return mnRow;
275 // ============================================================================
277 BOOL ScFormulaCell::IsEmpty()
279 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
280 Interpret();
281 return aResult.GetCellResultType() == formula::svEmptyCell;
284 BOOL ScFormulaCell::IsEmptyDisplayedAsString()
286 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
287 Interpret();
288 return aResult.IsEmptyDisplayedAsString();
291 BOOL ScFormulaCell::IsValue()
293 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
294 Interpret();
295 return aResult.IsValue();
298 double ScFormulaCell::GetValue()
300 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
301 Interpret();
302 if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) &&
303 !aResult.GetResultError())
304 return aResult.GetDouble();
305 return 0.0;
308 double ScFormulaCell::GetValueAlways()
310 // for goal seek: return result value even if error code is set
312 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
313 Interpret();
314 return aResult.GetDouble();
317 void ScFormulaCell::GetString( String& rString )
319 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
320 Interpret();
321 if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) &&
322 !aResult.GetResultError())
323 rString = aResult.GetString();
324 else
325 rString.Erase();
328 const ScMatrix* ScFormulaCell::GetMatrix()
330 if ( pDocument->GetAutoCalc() )
332 // Was stored !bDirty but an accompanying matrix cell was bDirty?
333 // => we need to get the matrix.
334 if (!bDirty && cMatrixFlag == MM_FORMULA && !aResult.GetMatrix().Is())
335 bDirty = TRUE;
336 if ( IsDirtyOrInTableOpDirty() )
337 Interpret();
339 return aResult.GetMatrix();
342 BOOL ScFormulaCell::GetMatrixOrigin( ScAddress& rPos ) const
344 switch ( cMatrixFlag )
346 case MM_FORMULA :
347 rPos = aPos;
348 return TRUE;
349 // break;
350 case MM_REFERENCE :
352 pCode->Reset();
353 ScToken* t = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
354 if( t )
356 ScSingleRefData& rRef = t->GetSingleRef();
357 rRef.CalcAbsIfRel( aPos );
358 if ( rRef.Valid() )
360 rPos.Set( rRef.nCol, rRef.nRow, rRef.nTab );
361 return TRUE;
365 break;
367 return FALSE;
372 Edge-Values:
375 4 16
378 innerhalb: 1
379 ausserhalb: 0
380 (reserviert: offen: 32)
383 USHORT ScFormulaCell::GetMatrixEdge( ScAddress& rOrgPos )
385 switch ( cMatrixFlag )
387 case MM_FORMULA :
388 case MM_REFERENCE :
390 static SCCOL nC;
391 static SCROW nR;
392 ScAddress aOrg;
393 if ( !GetMatrixOrigin( aOrg ) )
394 return 0; // dumm gelaufen..
395 if ( aOrg != rOrgPos )
396 { // erstes Mal oder andere Matrix als letztes Mal
397 rOrgPos = aOrg;
398 ScFormulaCell* pFCell;
399 if ( cMatrixFlag == MM_REFERENCE )
400 pFCell = (ScFormulaCell*) pDocument->GetCell( aOrg );
401 else
402 pFCell = this; // this MM_FORMULA
403 // this gibt's nur einmal, kein Vergleich auf pFCell==this
404 if ( pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA
405 && pFCell->cMatrixFlag == MM_FORMULA )
407 pFCell->GetMatColsRows( nC, nR );
408 if ( nC == 0 || nR == 0 )
409 { // aus altem Dokument geladen, neu erzeugen
410 nC = 1;
411 nR = 1;
412 ScAddress aTmpOrg;
413 ScBaseCell* pCell;
414 ScAddress aAdr( aOrg );
415 aAdr.IncCol();
416 BOOL bCont = TRUE;
419 pCell = pDocument->GetCell( aAdr );
420 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA
421 && ((ScFormulaCell*)pCell)->cMatrixFlag == MM_REFERENCE
422 && GetMatrixOrigin( aTmpOrg ) && aTmpOrg == aOrg )
424 nC++;
425 aAdr.IncCol();
427 else
428 bCont = FALSE;
429 } while ( bCont );
430 aAdr = aOrg;
431 aAdr.IncRow();
432 bCont = TRUE;
435 pCell = pDocument->GetCell( aAdr );
436 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA
437 && ((ScFormulaCell*)pCell)->cMatrixFlag == MM_REFERENCE
438 && GetMatrixOrigin( aTmpOrg ) && aTmpOrg == aOrg )
440 nR++;
441 aAdr.IncRow();
443 else
444 bCont = FALSE;
445 } while ( bCont );
446 pFCell->SetMatColsRows( nC, nR );
449 else
451 #ifndef PRODUCT
452 String aTmp;
453 ByteString aMsg( "broken Matrix, no MatFormula at origin, Pos: " );
454 aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
455 aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
456 aMsg += ", MatOrg: ";
457 aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
458 aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
459 DBG_ERRORFILE( aMsg.GetBuffer() );
460 #endif
461 return 0; // bad luck ...
464 // here we are, healthy and clean, somewhere in between
465 SCsCOL dC = aPos.Col() - aOrg.Col();
466 SCsROW dR = aPos.Row() - aOrg.Row();
467 USHORT nEdges = 0;
468 if ( dC >= 0 && dR >= 0 && dC < nC && dR < nR )
470 if ( dC == 0 )
471 nEdges |= 4; // linke Kante
472 if ( dC+1 == nC )
473 nEdges |= 16; // rechte Kante
474 if ( dR == 0 )
475 nEdges |= 8; // obere Kante
476 if ( dR+1 == nR )
477 nEdges |= 2; // untere Kante
478 if ( !nEdges )
479 nEdges = 1; // mittendrin
481 #ifndef PRODUCT
482 else
484 String aTmp;
485 ByteString aMsg( "broken Matrix, Pos: " );
486 aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
487 aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
488 aMsg += ", MatOrg: ";
489 aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
490 aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
491 aMsg += ", MatCols: ";
492 aMsg += ByteString::CreateFromInt32( nC );
493 aMsg += ", MatRows: ";
494 aMsg += ByteString::CreateFromInt32( nR );
495 aMsg += ", DiffCols: ";
496 aMsg += ByteString::CreateFromInt32( dC );
497 aMsg += ", DiffRows: ";
498 aMsg += ByteString::CreateFromInt32( dR );
499 DBG_ERRORFILE( aMsg.GetBuffer() );
501 #endif
502 return nEdges;
503 // break;
505 default:
506 return 0;
510 USHORT ScFormulaCell::GetErrCode()
512 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
513 Interpret();
514 /* FIXME: If ScTokenArray::SetCodeError() was really only for code errors
515 * and not also abused for signaling other error conditions we could bail
516 * out even before attempting to interpret broken code. */
517 USHORT nErr = pCode->GetCodeError();
518 if (nErr)
519 return nErr;
520 return aResult.GetResultError();
523 USHORT ScFormulaCell::GetRawError()
525 USHORT nErr = pCode->GetCodeError();
526 if (nErr)
527 return nErr;
528 return aResult.GetResultError();
531 BOOL ScFormulaCell::HasOneReference( ScRange& r ) const
533 pCode->Reset();
534 ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
535 if( p && !pCode->GetNextReferenceRPN() ) // nur eine!
537 p->CalcAbsIfRel( aPos );
538 SingleDoubleRefProvider aProv( *p );
539 r.aStart.Set( aProv.Ref1.nCol,
540 aProv.Ref1.nRow,
541 aProv.Ref1.nTab );
542 r.aEnd.Set( aProv.Ref2.nCol,
543 aProv.Ref2.nRow,
544 aProv.Ref2.nTab );
545 return TRUE;
547 else
548 return FALSE;
551 BOOL ScFormulaCell::HasRelNameReference() const
553 pCode->Reset();
554 ScToken* t;
555 while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceRPN()) ) != NULL )
557 if ( t->GetSingleRef().IsRelName() ||
558 (t->GetType() == formula::svDoubleRef &&
559 t->GetDoubleRef().Ref2.IsRelName()) )
560 return TRUE;
562 return FALSE;
565 BOOL ScFormulaCell::HasColRowName() const
567 pCode->Reset();
568 return (pCode->GetNextColRowName() != NULL);
571 void ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode,
572 const ScRange& r,
573 SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
574 ScDocument* pUndoDoc )
576 SCCOL nCol1 = r.aStart.Col();
577 SCROW nRow1 = r.aStart.Row();
578 SCTAB nTab1 = r.aStart.Tab();
579 SCCOL nCol2 = r.aEnd.Col();
580 SCROW nRow2 = r.aEnd.Row();
581 SCTAB nTab2 = r.aEnd.Tab();
582 SCCOL nCol = aPos.Col();
583 SCROW nRow = aPos.Row();
584 SCTAB nTab = aPos.Tab();
585 ScAddress aUndoPos( aPos ); // position for undo cell in pUndoDoc
586 ScAddress aOldPos( aPos );
587 // BOOL bPosChanged = FALSE; // ob diese Zelle bewegt wurde
588 BOOL bIsInsert = FALSE;
589 if (eUpdateRefMode == URM_INSDEL)
591 bIsInsert = (nDx >= 0 && nDy >= 0 && nDz >= 0);
592 if ( nDx && nRow >= nRow1 && nRow <= nRow2 &&
593 nTab >= nTab1 && nTab <= nTab2 )
595 if (nCol >= nCol1)
597 nCol = sal::static_int_cast<SCCOL>( nCol + nDx );
598 if ((SCsCOL) nCol < 0)
599 nCol = 0;
600 else if ( nCol > MAXCOL )
601 nCol = MAXCOL;
602 aPos.SetCol( nCol );
603 // bPosChanged = TRUE;
606 if ( nDy && nCol >= nCol1 && nCol <= nCol2 &&
607 nTab >= nTab1 && nTab <= nTab2 )
609 if (nRow >= nRow1)
611 nRow = sal::static_int_cast<SCROW>( nRow + nDy );
612 if ((SCsROW) nRow < 0)
613 nRow = 0;
614 else if ( nRow > MAXROW )
615 nRow = MAXROW;
616 aPos.SetRow( nRow );
617 // bPosChanged = TRUE;
620 if ( nDz && nCol >= nCol1 && nCol <= nCol2 &&
621 nRow >= nRow1 && nRow <= nRow2 )
623 if (nTab >= nTab1)
625 SCTAB nMaxTab = pDocument->GetTableCount() - 1;
626 nTab = sal::static_int_cast<SCTAB>( nTab + nDz );
627 if ((SCsTAB) nTab < 0)
628 nTab = 0;
629 else if ( nTab > nMaxTab )
630 nTab = nMaxTab;
631 aPos.SetTab( nTab );
632 // bPosChanged = TRUE;
636 else if ( r.In( aPos ) )
638 aOldPos.Set( nCol - nDx, nRow - nDy, nTab - nDz );
639 // bPosChanged = TRUE;
642 BOOL bHasRefs = FALSE;
643 BOOL bHasColRowNames = FALSE;
644 BOOL bOnRefMove = FALSE;
645 if ( !pDocument->IsClipOrUndo() )
647 pCode->Reset();
648 bHasRefs = (pCode->GetNextReferenceRPN() != NULL);
649 if ( !bHasRefs || eUpdateRefMode == URM_COPY )
651 pCode->Reset();
652 bHasColRowNames = (pCode->GetNextColRowName() != NULL);
653 bHasRefs = bHasRefs || bHasColRowNames;
655 bOnRefMove = pCode->IsRecalcModeOnRefMove();
657 if( bHasRefs || bOnRefMove )
659 ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL;
660 BOOL bValChanged;
661 ScRangeData* pRangeData;
662 BOOL bRangeModified; // any range, not only shared formula
663 BOOL bRefSizeChanged;
664 if ( bHasRefs )
666 ScCompiler aComp(pDocument, aPos, *pCode);
667 aComp.SetGrammar(pDocument->GetGrammar());
668 pRangeData = aComp.UpdateReference(eUpdateRefMode, aOldPos, r,
669 nDx, nDy, nDz,
670 bValChanged, bRefSizeChanged);
671 bRangeModified = aComp.HasModifiedRange();
673 else
675 bValChanged = FALSE;
676 pRangeData = NULL;
677 bRangeModified = FALSE;
678 bRefSizeChanged = FALSE;
680 if ( bOnRefMove )
681 bOnRefMove = (bValChanged || (aPos != aOldPos));
682 // Cell may reference itself, e.g. ocColumn, ocRow without parameter
684 BOOL bColRowNameCompile, bHasRelName, bNewListening, bInDeleteUndo;
685 if ( bHasRefs )
687 // Upon Insert ColRowNames have to be recompiled in case the
688 // insertion occurs right in front of the range.
689 bColRowNameCompile =
690 (eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0));
691 if ( bColRowNameCompile )
693 bColRowNameCompile = FALSE;
694 ScToken* t;
695 ScRangePairList* pColList = pDocument->GetColNameRanges();
696 ScRangePairList* pRowList = pDocument->GetRowNameRanges();
697 pCode->Reset();
698 while ( !bColRowNameCompile && (t = static_cast<ScToken*>(pCode->GetNextColRowName())) != NULL )
700 ScSingleRefData& rRef = t->GetSingleRef();
701 if ( nDy > 0 && rRef.IsColRel() )
702 { // ColName
703 rRef.CalcAbsIfRel( aPos );
704 ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
705 ScRangePair* pR = pColList->Find( aAdr );
706 if ( pR )
707 { // definiert
708 if ( pR->GetRange(1).aStart.Row() == nRow1 )
709 bColRowNameCompile = TRUE;
711 else
712 { // on the fly
713 if ( rRef.nRow + 1 == nRow1 )
714 bColRowNameCompile = TRUE;
717 if ( nDx > 0 && rRef.IsRowRel() )
718 { // RowName
719 rRef.CalcAbsIfRel( aPos );
720 ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
721 ScRangePair* pR = pRowList->Find( aAdr );
722 if ( pR )
723 { // definiert
724 if ( pR->GetRange(1).aStart.Col() == nCol1 )
725 bColRowNameCompile = TRUE;
727 else
728 { // on the fly
729 if ( rRef.nCol + 1 == nCol1 )
730 bColRowNameCompile = TRUE;
735 else if ( eUpdateRefMode == URM_MOVE )
736 { // bei Move/D&D neu kompilieren wenn ColRowName verschoben wurde
737 // oder diese Zelle auf einen zeigt und verschoben wurde
738 bColRowNameCompile = bCompile; // evtl. aus Copy-ctor
739 if ( !bColRowNameCompile )
741 BOOL bMoved = (aPos != aOldPos);
742 pCode->Reset();
743 ScToken* t = static_cast<ScToken*>(pCode->GetNextColRowName());
744 if ( t && bMoved )
745 bColRowNameCompile = TRUE;
746 while ( t && !bColRowNameCompile )
748 ScSingleRefData& rRef = t->GetSingleRef();
749 rRef.CalcAbsIfRel( aPos );
750 if ( rRef.Valid() )
752 ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
753 if ( r.In( aAdr ) )
754 bColRowNameCompile = TRUE;
756 t = static_cast<ScToken*>(pCode->GetNextColRowName());
760 else if ( eUpdateRefMode == URM_COPY && bHasColRowNames && bValChanged )
762 bColRowNameCompile = TRUE;
764 ScChangeTrack* pChangeTrack = pDocument->GetChangeTrack();
765 if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
766 bInDeleteUndo = TRUE;
767 else
768 bInDeleteUndo = FALSE;
769 // RelNameRefs are always moved
770 bHasRelName = HasRelNameReference();
771 // Reference changed and new listening needed?
772 // Except in Insert/Delete without specialties.
773 bNewListening = (bRangeModified || pRangeData || bColRowNameCompile
774 || (bValChanged && (eUpdateRefMode != URM_INSDEL ||
775 bInDeleteUndo || bRefSizeChanged)) ||
776 (bHasRelName && eUpdateRefMode != URM_COPY))
777 // #i36299# Don't duplicate action during cut&paste / drag&drop
778 // on a cell in the range moved, start/end listeners is done
779 // via ScDocument::DeleteArea() and ScDocument::CopyFromClip().
780 && !(eUpdateRefMode == URM_MOVE &&
781 pDocument->IsInsertingFromOtherDoc() && r.In(aPos));
782 if ( bNewListening )
783 EndListeningTo( pDocument, pOld, aOldPos );
785 else
787 bColRowNameCompile = bHasRelName = bNewListening = bInDeleteUndo =
788 FALSE;
791 BOOL bNeedDirty;
792 // NeedDirty bei Aenderungen ausser Copy und Move/Insert ohne RelNames
793 if ( bRangeModified || pRangeData || bColRowNameCompile ||
794 (bValChanged && eUpdateRefMode != URM_COPY &&
795 (eUpdateRefMode != URM_MOVE || bHasRelName) &&
796 (!bIsInsert || bHasRelName || bInDeleteUndo ||
797 bRefSizeChanged)) || bOnRefMove)
798 bNeedDirty = TRUE;
799 else
800 bNeedDirty = FALSE;
801 if (pUndoDoc && (bValChanged || pRangeData || bOnRefMove))
803 // Copy the cell to aUndoPos, which is its current position in the document,
804 // so this works when UpdateReference is called before moving the cells
805 // (InsertCells/DeleteCells - aPos is changed above) as well as when UpdateReference
806 // is called after moving the cells (MoveBlock/PasteFromClip - aOldPos is changed).
808 ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aUndoPos,
809 pOld, eTempGrammar, cMatrixFlag );
810 pFCell->aResult.SetToken( NULL); // to recognize it as changed later (Cut/Paste!)
811 pUndoDoc->PutCell( aUndoPos, pFCell );
813 bValChanged = FALSE;
814 if ( pRangeData )
815 { // Replace shared formula with own formula
816 pDocument->RemoveFromFormulaTree( this ); // update formula count
817 delete pCode;
818 pCode = pRangeData->GetCode()->Clone();
819 ScCompiler aComp2(pDocument, aPos, *pCode);
820 aComp2.SetGrammar(pDocument->GetGrammar());
821 aComp2.UpdateSharedFormulaReference( eUpdateRefMode, aOldPos, r,
822 nDx, nDy, nDz );
823 bValChanged = TRUE;
824 bNeedDirty = TRUE;
826 if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 )
828 CompileTokenArray( bNewListening ); // kein Listening
829 bNeedDirty = TRUE;
831 if ( !bInDeleteUndo )
832 { // In ChangeTrack Delete-Reject listeners are established in
833 // InsertCol/InsertRow
834 if ( bNewListening )
836 if ( eUpdateRefMode == URM_INSDEL )
838 // Inserts/Deletes re-establish listeners after all
839 // UpdateReference calls.
840 // All replaced shared formula listeners have to be
841 // established after an Insert or Delete. Do nothing here.
842 SetNeedsListening( TRUE);
844 else
845 StartListeningTo( pDocument );
848 if ( bNeedDirty && (!(eUpdateRefMode == URM_INSDEL && bHasRelName) || pRangeData) )
849 { // Referenzen abgeschnitten, ungueltig o.ae.?
850 BOOL bOldAutoCalc = pDocument->GetAutoCalc();
851 // kein Interpret in SubMinimalRecalc wegen evtl. falscher Referenzen
852 pDocument->SetAutoCalc( FALSE );
853 SetDirty();
854 pDocument->SetAutoCalc( bOldAutoCalc );
857 delete pOld;
860 pCode->Reset();
861 for ( formula::FormulaToken* t = pCode->GetNextReferenceOrName(); t; t = pCode->GetNextReferenceOrName() )
863 StackVar sv = t->GetType();
864 if (sv == svExternalSingleRef || sv == svExternalDoubleRef || sv == svExternalName)
866 pDocument->GetExternalRefManager()->updateRefCell(aOldPos, aPos, eUpdateRefMode == URM_COPY);
867 break;
872 void ScFormulaCell::UpdateInsertTab(SCTAB nTable)
874 BOOL bPosChanged = ( aPos.Tab() >= nTable ? TRUE : FALSE );
875 pCode->Reset();
876 if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
878 EndListeningTo( pDocument );
879 // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateInsertTab !
880 if ( bPosChanged )
881 aPos.IncTab();
882 ScRangeData* pRangeData;
883 ScCompiler aComp(pDocument, aPos, *pCode);
884 aComp.SetGrammar(pDocument->GetGrammar());
885 pRangeData = aComp.UpdateInsertTab( nTable, FALSE );
886 if (pRangeData) // Shared Formula gegen echte Formel
887 { // austauschen
888 BOOL bRefChanged;
889 pDocument->RemoveFromFormulaTree( this ); // update formula count
890 delete pCode;
891 pCode = new ScTokenArray( *pRangeData->GetCode() );
892 ScCompiler aComp2(pDocument, aPos, *pCode);
893 aComp2.SetGrammar(pDocument->GetGrammar());
894 aComp2.MoveRelWrap();
895 aComp2.UpdateInsertTab( nTable, FALSE );
896 // If the shared formula contained a named range/formula containing
897 // an absolute reference to a sheet, those have to be readjusted.
898 aComp2.UpdateDeleteTab( nTable, FALSE, TRUE, bRefChanged );
899 bCompile = TRUE;
901 // kein StartListeningTo weil pTab[nTab] noch nicht existiert!
903 else if ( bPosChanged )
904 aPos.IncTab();
907 BOOL ScFormulaCell::UpdateDeleteTab(SCTAB nTable, BOOL bIsMove)
909 BOOL bRefChanged = FALSE;
910 BOOL bPosChanged = ( aPos.Tab() > nTable ? TRUE : FALSE );
911 pCode->Reset();
912 if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
914 EndListeningTo( pDocument );
915 // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateDeleteTab !
916 if ( bPosChanged )
917 aPos.IncTab(-1);
918 ScRangeData* pRangeData;
919 ScCompiler aComp(pDocument, aPos, *pCode);
920 aComp.SetGrammar(pDocument->GetGrammar());
921 pRangeData = aComp.UpdateDeleteTab(nTable, bIsMove, FALSE, bRefChanged);
922 if (pRangeData) // Shared Formula gegen echte Formel
923 { // austauschen
924 pDocument->RemoveFromFormulaTree( this ); // update formula count
925 delete pCode;
926 pCode = pRangeData->GetCode()->Clone();
927 ScCompiler aComp2(pDocument, aPos, *pCode);
928 aComp2.SetGrammar(pDocument->GetGrammar());
929 aComp2.CompileTokenArray();
930 aComp2.MoveRelWrap();
931 aComp2.UpdateDeleteTab( nTable, FALSE, FALSE, bRefChanged );
932 // If the shared formula contained a named range/formula containing
933 // an absolute reference to a sheet, those have to be readjusted.
934 aComp2.UpdateInsertTab( nTable,TRUE );
935 // bRefChanged kann beim letzten UpdateDeleteTab zurueckgesetzt worden sein
936 bRefChanged = TRUE;
937 bCompile = TRUE;
939 // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
941 else if ( bPosChanged )
942 aPos.IncTab(-1);
944 return bRefChanged;
947 void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
949 pCode->Reset();
950 if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
952 EndListeningTo( pDocument );
953 // SetTab _nach_ EndListeningTo und _vor_ Compiler UpdateMoveTab !
954 aPos.SetTab( nTabNo );
955 ScRangeData* pRangeData;
956 ScCompiler aComp(pDocument, aPos, *pCode);
957 aComp.SetGrammar(pDocument->GetGrammar());
958 pRangeData = aComp.UpdateMoveTab( nOldPos, nNewPos, FALSE );
959 if (pRangeData) // Shared Formula gegen echte Formel
960 { // austauschen
961 pDocument->RemoveFromFormulaTree( this ); // update formula count
962 delete pCode;
963 pCode = pRangeData->GetCode()->Clone();
964 ScCompiler aComp2(pDocument, aPos, *pCode);
965 aComp2.SetGrammar(pDocument->GetGrammar());
966 aComp2.CompileTokenArray();
967 aComp2.MoveRelWrap();
968 aComp2.UpdateMoveTab( nOldPos, nNewPos, TRUE );
969 bCompile = TRUE;
971 // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
973 else
974 aPos.SetTab( nTabNo );
977 void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable)
979 if( !pDocument->IsClipOrUndo() )
981 pCode->Reset();
982 ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
983 while( p )
985 ScSingleRefData& rRef1 = p->GetSingleRef();
986 if( !rRef1.IsTabRel() && (SCsTAB) nTable <= rRef1.nTab )
987 rRef1.nTab++;
988 if( p->GetType() == formula::svDoubleRef )
990 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
991 if( !rRef2.IsTabRel() && (SCsTAB) nTable <= rRef2.nTab )
992 rRef2.nTab++;
994 p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
999 BOOL ScFormulaCell::TestTabRefAbs(SCTAB nTable)
1001 BOOL bRet = FALSE;
1002 if( !pDocument->IsClipOrUndo() )
1004 pCode->Reset();
1005 ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
1006 while( p )
1008 ScSingleRefData& rRef1 = p->GetSingleRef();
1009 if( !rRef1.IsTabRel() )
1011 if( (SCsTAB) nTable != rRef1.nTab )
1012 bRet = TRUE;
1013 else if (nTable != aPos.Tab())
1014 rRef1.nTab = aPos.Tab();
1016 if( p->GetType() == formula::svDoubleRef )
1018 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
1019 if( !rRef2.IsTabRel() )
1021 if( (SCsTAB) nTable != rRef2.nTab )
1022 bRet = TRUE;
1023 else if (nTable != aPos.Tab())
1024 rRef2.nTab = aPos.Tab();
1027 p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
1030 return bRet;
1033 void ScFormulaCell::UpdateCompile( BOOL bForceIfNameInUse )
1035 if ( bForceIfNameInUse && !bCompile )
1036 bCompile = pCode->HasNameOrColRowName();
1037 if ( bCompile )
1038 pCode->SetCodeError( 0 ); // make sure it will really be compiled
1039 CompileTokenArray();
1042 // Referenzen transponieren - wird nur in Clipboard-Dokumenten aufgerufen
1044 void ScFormulaCell::TransposeReference()
1046 BOOL bFound = FALSE;
1047 pCode->Reset();
1048 ScToken* t;
1049 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
1051 ScSingleRefData& rRef1 = t->GetSingleRef();
1052 if ( rRef1.IsColRel() && rRef1.IsRowRel() )
1054 BOOL bDouble = (t->GetType() == formula::svDoubleRef);
1055 ScSingleRefData& rRef2 = (bDouble ? t->GetDoubleRef().Ref2 : rRef1);
1056 if ( !bDouble || (rRef2.IsColRel() && rRef2.IsRowRel()) )
1058 INT16 nTemp;
1060 nTemp = rRef1.nRelCol;
1061 rRef1.nRelCol = static_cast<SCCOL>(rRef1.nRelRow);
1062 rRef1.nRelRow = static_cast<SCROW>(nTemp);
1064 if ( bDouble )
1066 nTemp = rRef2.nRelCol;
1067 rRef2.nRelCol = static_cast<SCCOL>(rRef2.nRelRow);
1068 rRef2.nRelRow = static_cast<SCROW>(nTemp);
1071 bFound = TRUE;
1076 if (bFound)
1077 bCompile = TRUE;
1080 void ScFormulaCell::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
1081 ScDocument* pUndoDoc )
1083 EndListeningTo( pDocument );
1085 ScAddress aOldPos = aPos;
1086 BOOL bPosChanged = FALSE; // ob diese Zelle bewegt wurde
1088 ScRange aDestRange( rDest, ScAddress(
1089 static_cast<SCCOL>(rDest.Col() + rSource.aEnd.Row() - rSource.aStart.Row()),
1090 static_cast<SCROW>(rDest.Row() + rSource.aEnd.Col() - rSource.aStart.Col()),
1091 rDest.Tab() + rSource.aEnd.Tab() - rSource.aStart.Tab() ) );
1092 if ( aDestRange.In( aOldPos ) )
1094 // Position zurueckrechnen
1095 SCsCOL nRelPosX = aOldPos.Col();
1096 SCsROW nRelPosY = aOldPos.Row();
1097 SCsTAB nRelPosZ = aOldPos.Tab();
1098 ScRefUpdate::DoTranspose( nRelPosX, nRelPosY, nRelPosZ, pDocument, aDestRange, rSource.aStart );
1099 aOldPos.Set( nRelPosX, nRelPosY, nRelPosZ );
1100 bPosChanged = TRUE;
1103 ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL;
1104 BOOL bRefChanged = FALSE;
1105 ScToken* t;
1107 ScRangeData* pShared = NULL;
1108 pCode->Reset();
1109 while( (t = static_cast<ScToken*>(pCode->GetNextReferenceOrName())) != NULL )
1111 if( t->GetOpCode() == ocName )
1113 ScRangeData* pName = pDocument->GetRangeName()->FindIndex( t->GetIndex() );
1114 if (pName)
1116 if (pName->IsModified())
1117 bRefChanged = TRUE;
1118 if (pName->HasType(RT_SHAREDMOD))
1119 pShared = pName;
1122 else if( t->GetType() != svIndex )
1124 t->CalcAbsIfRel( aOldPos );
1125 BOOL bMod;
1126 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1127 SingleDoubleRefModifier aMod( *t );
1128 ScComplexRefData& rRef = aMod.Ref();
1129 bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource,
1130 rDest, rRef ) != UR_NOTHING || bPosChanged);
1132 if ( bMod )
1134 t->CalcRelFromAbs( aPos );
1135 bRefChanged = TRUE;
1140 if (pShared) // Shared Formula gegen echte Formel austauschen
1142 pDocument->RemoveFromFormulaTree( this ); // update formula count
1143 delete pCode;
1144 pCode = new ScTokenArray( *pShared->GetCode() );
1145 bRefChanged = TRUE;
1146 pCode->Reset();
1147 while( (t = static_cast<ScToken*>(pCode->GetNextReference())) != NULL )
1149 if( t->GetType() != svIndex )
1151 t->CalcAbsIfRel( aOldPos );
1152 BOOL bMod;
1153 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1154 SingleDoubleRefModifier aMod( *t );
1155 ScComplexRefData& rRef = aMod.Ref();
1156 bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource,
1157 rDest, rRef ) != UR_NOTHING || bPosChanged);
1159 if ( bMod )
1160 t->CalcRelFromAbs( aPos );
1165 if (bRefChanged)
1167 if (pUndoDoc)
1169 ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aPos, pOld,
1170 eTempGrammar, cMatrixFlag);
1171 pFCell->aResult.SetToken( NULL); // to recognize it as changed later (Cut/Paste!)
1172 pUndoDoc->PutCell( aPos.Col(), aPos.Row(), aPos.Tab(), pFCell );
1175 bCompile = TRUE;
1176 CompileTokenArray(); // ruft auch StartListeningTo
1177 SetDirty();
1179 else
1180 StartListeningTo( pDocument ); // Listener wie vorher
1182 delete pOld;
1185 void ScFormulaCell::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
1187 EndListeningTo( pDocument );
1189 BOOL bRefChanged = FALSE;
1190 ScToken* t;
1191 ScRangeData* pShared = NULL;
1193 pCode->Reset();
1194 while( (t = static_cast<ScToken*>(pCode->GetNextReferenceOrName())) != NULL )
1196 if( t->GetOpCode() == ocName )
1198 ScRangeData* pName = pDocument->GetRangeName()->FindIndex( t->GetIndex() );
1199 if (pName)
1201 if (pName->IsModified())
1202 bRefChanged = TRUE;
1203 if (pName->HasType(RT_SHAREDMOD))
1204 pShared = pName;
1207 else if( t->GetType() != svIndex )
1209 t->CalcAbsIfRel( aPos );
1210 BOOL bMod;
1211 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1212 SingleDoubleRefModifier aMod( *t );
1213 ScComplexRefData& rRef = aMod.Ref();
1214 bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY,
1215 rRef ) != UR_NOTHING);
1217 if ( bMod )
1219 t->CalcRelFromAbs( aPos );
1220 bRefChanged = TRUE;
1225 if (pShared) // Shared Formula gegen echte Formel austauschen
1227 pDocument->RemoveFromFormulaTree( this ); // update formula count
1228 delete pCode;
1229 pCode = new ScTokenArray( *pShared->GetCode() );
1230 bRefChanged = TRUE;
1231 pCode->Reset();
1232 while( (t = static_cast<ScToken*>(pCode->GetNextReference())) != NULL )
1234 if( t->GetType() != svIndex )
1236 t->CalcAbsIfRel( aPos );
1237 BOOL bMod;
1238 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1239 SingleDoubleRefModifier aMod( *t );
1240 ScComplexRefData& rRef = aMod.Ref();
1241 bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY,
1242 rRef ) != UR_NOTHING);
1244 if ( bMod )
1245 t->CalcRelFromAbs( aPos );
1250 if (bRefChanged)
1252 bCompile = TRUE;
1253 CompileTokenArray(); // ruft auch StartListeningTo
1254 SetDirty();
1256 else
1257 StartListeningTo( pDocument ); // Listener wie vorher
1260 BOOL lcl_IsRangeNameInUse(USHORT nIndex, ScTokenArray* pCode, ScRangeName* pNames)
1262 for (FormulaToken* p = pCode->First(); p; p = pCode->Next())
1264 if (p->GetOpCode() == ocName)
1266 if (p->GetIndex() == nIndex)
1267 return TRUE;
1268 else
1270 // RangeData kann Null sein in bestimmten Excel-Dateien (#31168#)
1271 ScRangeData* pSubName = pNames->FindIndex(p->GetIndex());
1272 if (pSubName && lcl_IsRangeNameInUse(nIndex,
1273 pSubName->GetCode(), pNames))
1274 return TRUE;
1278 return FALSE;
1281 BOOL ScFormulaCell::IsRangeNameInUse(USHORT nIndex) const
1283 return lcl_IsRangeNameInUse( nIndex, pCode, pDocument->GetRangeName() );
1286 void lcl_FindRangeNamesInUse(std::set<USHORT>& rIndexes, ScTokenArray* pCode, ScRangeName* pNames)
1288 for (FormulaToken* p = pCode->First(); p; p = pCode->Next())
1290 if (p->GetOpCode() == ocName)
1292 USHORT nTokenIndex = p->GetIndex();
1293 rIndexes.insert( nTokenIndex );
1295 ScRangeData* pSubName = pNames->FindIndex(p->GetIndex());
1296 if (pSubName)
1297 lcl_FindRangeNamesInUse(rIndexes, pSubName->GetCode(), pNames);
1302 void ScFormulaCell::FindRangeNamesInUse(std::set<USHORT>& rIndexes) const
1304 lcl_FindRangeNamesInUse( rIndexes, pCode, pDocument->GetRangeName() );
1307 void ScFormulaCell::ReplaceRangeNamesInUse( const ScIndexMap& rMap )
1309 for( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
1311 if( p->GetOpCode() == ocName )
1313 USHORT nIndex = p->GetIndex();
1314 USHORT nNewIndex = rMap.Find( nIndex );
1315 if ( nIndex != nNewIndex )
1317 p->SetIndex( nNewIndex );
1318 bCompile = TRUE;
1322 if( bCompile )
1323 CompileTokenArray();
1326 void ScFormulaCell::ReplaceRangeNamesInUse( const ScRangeData::IndexMap& rMap )
1328 for( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
1330 if( p->GetOpCode() == ocName )
1332 sal_uInt16 nIndex = p->GetIndex();
1333 ScRangeData::IndexMap::const_iterator itr = rMap.find(nIndex);
1334 sal_uInt16 nNewIndex = itr == rMap.end() ? nIndex : nNewIndex;
1335 if ( nIndex != nNewIndex )
1337 p->SetIndex( nNewIndex );
1338 bCompile = TRUE;
1342 if( bCompile )
1343 CompileTokenArray();
1346 void ScFormulaCell::CompileDBFormula()
1348 for( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
1350 if ( p->GetOpCode() == ocDBArea
1351 || (p->GetOpCode() == ocName && p->GetIndex() >= SC_START_INDEX_DB_COLL) )
1353 bCompile = TRUE;
1354 CompileTokenArray();
1355 SetDirty();
1356 break;
1361 void ScFormulaCell::CompileDBFormula( BOOL bCreateFormulaString )
1363 // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
1364 // 1. FormelString mit alten Namen erzeugen
1365 // 2. FormelString mit neuen Namen kompilieren
1366 if ( bCreateFormulaString )
1368 BOOL bRecompile = FALSE;
1369 pCode->Reset();
1370 for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() )
1372 switch ( p->GetOpCode() )
1374 case ocBad: // DB-Bereich evtl. zugefuegt
1375 case ocColRowName: // #36762# falls Namensgleichheit
1376 case ocDBArea: // DB-Bereich
1377 bRecompile = TRUE;
1378 break;
1379 case ocName:
1380 if ( p->GetIndex() >= SC_START_INDEX_DB_COLL )
1381 bRecompile = TRUE; // DB-Bereich
1382 break;
1383 default:
1384 ; // nothing
1387 if ( bRecompile )
1389 String aFormula;
1390 GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
1391 if ( GetMatrixFlag() != MM_NONE && aFormula.Len() )
1393 if ( aFormula.GetChar( aFormula.Len()-1 ) == '}' )
1394 aFormula.Erase( aFormula.Len()-1 , 1 );
1395 if ( aFormula.GetChar(0) == '{' )
1396 aFormula.Erase( 0, 1 );
1398 EndListeningTo( pDocument );
1399 pDocument->RemoveFromFormulaTree( this );
1400 pCode->Clear();
1401 SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
1404 else if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
1406 Compile( aResult.GetHybridFormula(), FALSE, eTempGrammar );
1407 aResult.SetToken( NULL);
1408 SetDirty();
1412 void ScFormulaCell::CompileNameFormula( BOOL bCreateFormulaString )
1414 // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
1415 // 1. FormelString mit alten RangeNames erzeugen
1416 // 2. FormelString mit neuen RangeNames kompilieren
1417 if ( bCreateFormulaString )
1419 BOOL bRecompile = FALSE;
1420 pCode->Reset();
1421 for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() )
1423 switch ( p->GetOpCode() )
1425 case ocBad: // RangeName evtl. zugefuegt
1426 case ocColRowName: // #36762# falls Namensgleichheit
1427 bRecompile = TRUE;
1428 break;
1429 default:
1430 if ( p->GetType() == svIndex )
1431 bRecompile = TRUE; // RangeName
1434 if ( bRecompile )
1436 String aFormula;
1437 GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
1438 if ( GetMatrixFlag() != MM_NONE && aFormula.Len() )
1440 if ( aFormula.GetChar( aFormula.Len()-1 ) == '}' )
1441 aFormula.Erase( aFormula.Len()-1 , 1 );
1442 if ( aFormula.GetChar(0) == '{' )
1443 aFormula.Erase( 0, 1 );
1445 EndListeningTo( pDocument );
1446 pDocument->RemoveFromFormulaTree( this );
1447 pCode->Clear();
1448 SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
1451 else if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
1453 Compile( aResult.GetHybridFormula(), FALSE, eTempGrammar );
1454 aResult.SetToken( NULL);
1455 SetDirty();
1459 void ScFormulaCell::CompileColRowNameFormula()
1461 pCode->Reset();
1462 for ( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
1464 if ( p->GetOpCode() == ocColRowName )
1466 bCompile = TRUE;
1467 CompileTokenArray();
1468 SetDirty();
1469 break;
1474 // ============================================================================