update dev300-m57
[ooovba.git] / sc / source / core / data / cell2.cxx
blobbb9ef6e7300f31927ef79305e4e1876a206a6b94
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 <algorithm>
38 #include <deque>
40 #include <boost/bind.hpp>
42 #include <vcl/mapmod.hxx>
43 #include <svx/editobj.hxx>
44 #include <svx/editstat.hxx>
46 #include "cell.hxx"
47 #include "compiler.hxx"
48 #include "formula/errorcodes.hxx"
49 #include "document.hxx"
50 #include "rangenam.hxx"
51 #include "rechead.hxx"
52 #include "refupdat.hxx"
53 #include "scmatrix.hxx"
54 #include "editutil.hxx"
55 #include "chgtrack.hxx"
56 #include "indexmap.hxx"
57 #include "externalrefmgr.hxx"
58 #include "scitems.hxx"
59 #include "patattr.hxx"
61 using namespace formula;
63 // STATIC DATA -----------------------------------------------------------
65 #ifdef USE_MEMPOOL
66 const USHORT nMemPoolEditCell = (0x1000 - 64) / sizeof(ScNoteCell);
67 IMPL_FIXEDMEMPOOL_NEWDEL( ScEditCell, nMemPoolEditCell, nMemPoolEditCell )
68 #endif
70 // ============================================================================
72 ScEditCell::ScEditCell( const EditTextObject* pObject, ScDocument* pDocP,
73 const SfxItemPool* pFromPool ) :
74 ScBaseCell( CELLTYPE_EDIT ),
75 pString( NULL ),
76 pDoc( pDocP )
78 SetTextObject( pObject, pFromPool );
81 ScEditCell::ScEditCell( const ScEditCell& rCell, ScDocument& rDoc ) :
82 ScBaseCell( rCell ),
83 pString( NULL ),
84 pDoc( &rDoc )
86 SetTextObject( rCell.pData, rCell.pDoc->GetEditPool() );
89 ScEditCell::ScEditCell( const String& rString, ScDocument* pDocP ) :
90 ScBaseCell( CELLTYPE_EDIT ),
91 pString( NULL ),
92 pDoc( pDocP )
94 DBG_ASSERT( rString.Search('\n') != STRING_NOTFOUND ||
95 rString.Search(CHAR_CR) != STRING_NOTFOUND,
96 "EditCell mit einfachem Text !?!?" );
98 EditEngine& rEngine = pDoc->GetEditEngine();
99 rEngine.SetText( rString );
100 pData = rEngine.CreateTextObject();
103 ScEditCell::~ScEditCell()
105 delete pData;
106 delete pString;
108 #ifdef DBG_UTIL
109 eCellType = CELLTYPE_DESTROYED;
110 #endif
113 void ScEditCell::SetData( const EditTextObject* pObject,
114 const SfxItemPool* pFromPool )
116 if ( pString )
118 delete pString;
119 pString = NULL;
121 delete pData;
122 SetTextObject( pObject, pFromPool );
125 void ScEditCell::GetData( const EditTextObject*& rpObject ) const
127 rpObject = pData;
130 void ScEditCell::GetString( String& rString ) const
132 if ( pString )
133 rString = *pString;
134 else if ( pData )
136 // auch Text von URL-Feldern, Doc-Engine ist eine ScFieldEditEngine
137 EditEngine& rEngine = pDoc->GetEditEngine();
138 rEngine.SetText( *pData );
139 rString = ScEditUtil::GetMultilineString(rEngine); // string with line separators between paragraphs
140 // kurze Strings fuer Formeln merken
141 if ( rString.Len() < MAXSTRLEN )
142 ((ScEditCell*)this)->pString = new String( rString ); //! non-const
144 else
145 rString.Erase();
148 bool ScEditCell::HasPhonetic() const
150 return false;
153 void ScEditCell::RemoveCharAttribs( const ScPatternAttr& rAttr )
155 const struct {
156 USHORT nAttrType;
157 USHORT nCharType;
158 } AttrTypeMap[] = {
159 { ATTR_FONT, EE_CHAR_FONTINFO },
160 { ATTR_FONT_HEIGHT, EE_CHAR_FONTHEIGHT },
161 { ATTR_FONT_WEIGHT, EE_CHAR_WEIGHT },
162 { ATTR_FONT_COLOR, EE_CHAR_COLOR }
164 USHORT nMapCount = sizeof(AttrTypeMap) / sizeof(AttrTypeMap[0]);
166 const SfxItemSet& rSet = rAttr.GetItemSet();
167 const SfxPoolItem* pItem;
168 for (USHORT i = 0; i < nMapCount; ++i)
170 if ( rSet.GetItemState(AttrTypeMap[i].nAttrType, false, &pItem) == SFX_ITEM_SET )
171 pData->RemoveCharAttribs(AttrTypeMap[i].nCharType);
175 void ScEditCell::SetTextObject( const EditTextObject* pObject,
176 const SfxItemPool* pFromPool )
178 if ( pObject )
180 if ( pFromPool && pDoc->GetEditPool() == pFromPool )
181 pData = pObject->Clone();
182 else
183 { //! anderer Pool
184 // Leider gibt es keinen anderen Weg, um den Pool umzuhaengen,
185 // als das Object durch eine entsprechende Engine zu schleusen..
186 EditEngine& rEngine = pDoc->GetEditEngine();
187 if ( pObject->HasOnlineSpellErrors() )
189 ULONG nControl = rEngine.GetControlWord();
190 const ULONG nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
191 BOOL bNewControl = ( (nControl & nSpellControl) != nSpellControl );
192 if ( bNewControl )
193 rEngine.SetControlWord( nControl | nSpellControl );
194 rEngine.SetText( *pObject );
195 pData = rEngine.CreateTextObject();
196 if ( bNewControl )
197 rEngine.SetControlWord( nControl );
199 else
201 rEngine.SetText( *pObject );
202 pData = rEngine.CreateTextObject();
206 else
207 pData = NULL;
210 ScEditDataArray::ScEditDataArray()
214 ScEditDataArray::~ScEditDataArray()
218 void ScEditDataArray::AddItem(SCTAB nTab, SCCOL nCol, SCROW nRow,
219 EditTextObject* pOldData, EditTextObject* pNewData)
221 maArray.push_back(Item(nTab, nCol, nRow, pOldData, pNewData));
224 const ScEditDataArray::Item* ScEditDataArray::First()
226 maIter = maArray.begin();
227 if (maIter == maArray.end())
228 return NULL;
229 return &(*maIter++);
232 const ScEditDataArray::Item* ScEditDataArray::Next()
234 if (maIter == maArray.end())
235 return NULL;
236 return &(*maIter++);
239 // ============================================================================
241 ScEditDataArray::Item::Item(SCTAB nTab, SCCOL nCol, SCROW nRow,
242 EditTextObject* pOldData, EditTextObject* pNewData) :
243 mnTab(nTab),
244 mnCol(nCol),
245 mnRow(nRow)
247 mpOldData.reset(pOldData);
248 mpNewData.reset(pNewData);
251 ScEditDataArray::Item::~Item()
255 const EditTextObject* ScEditDataArray::Item::GetOldData() const
257 return mpOldData.get();
260 const EditTextObject* ScEditDataArray::Item::GetNewData() const
262 return mpNewData.get();
265 SCTAB ScEditDataArray::Item::GetTab() const
267 return mnTab;
270 SCCOL ScEditDataArray::Item::GetCol() const
272 return mnCol;
275 SCROW ScEditDataArray::Item::GetRow() const
277 return mnRow;
280 // ============================================================================
282 namespace
285 using std::deque;
287 typedef SCCOLROW(*DimensionSelector)(const ScSingleRefData&);
290 static SCCOLROW lcl_GetCol(const ScSingleRefData& rData)
292 return rData.nCol;
296 static SCCOLROW lcl_GetRow(const ScSingleRefData& rData)
298 return rData.nRow;
302 static SCCOLROW lcl_GetTab(const ScSingleRefData& rData)
304 return rData.nTab;
308 /** Check if both references span the same range in selected dimension.
310 static bool
311 lcl_checkRangeDimension(
312 const SingleDoubleRefProvider& rRef1,
313 const SingleDoubleRefProvider& rRef2,
314 const DimensionSelector aWhich)
316 return
317 aWhich(rRef1.Ref1) == aWhich(rRef2.Ref1)
318 && aWhich(rRef1.Ref2) == aWhich(rRef2.Ref2);
322 static bool
323 lcl_checkRangeDimensions(
324 const SingleDoubleRefProvider& rRef1,
325 const SingleDoubleRefProvider& rRef2,
326 bool& bCol, bool& bRow, bool& bTab)
328 const bool bSameCols(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetCol));
329 const bool bSameRows(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetRow));
330 const bool bSameTabs(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetTab));
332 // Test if exactly two dimensions are equal
333 if (!(bSameCols ^ bSameRows ^ bSameTabs)
334 && (bSameCols || bSameRows || bSameTabs))
336 bCol = !bSameCols;
337 bRow = !bSameRows;
338 bTab = !bSameTabs;
339 return true;
341 return false;
345 /** Check if references in given reference list can possibly
346 form a range. To do that, two of their dimensions must be the same.
348 static bool
349 lcl_checkRangeDimensions(
350 const deque<ScToken*>::const_iterator aBegin,
351 const deque<ScToken*>::const_iterator aEnd,
352 bool& bCol, bool& bRow, bool& bTab)
354 deque<ScToken*>::const_iterator aCur(aBegin);
355 ++aCur;
356 const SingleDoubleRefProvider aRef(**aBegin);
357 bool bOk(false);
359 const SingleDoubleRefProvider aRefCur(**aCur);
360 bOk = lcl_checkRangeDimensions(aRef, aRefCur, bCol, bRow, bTab);
362 while (bOk && aCur != aEnd)
364 const SingleDoubleRefProvider aRefCur(**aCur);
365 bool bColTmp(false);
366 bool bRowTmp(false);
367 bool bTabTmp(false);
368 bOk = lcl_checkRangeDimensions(aRef, aRefCur, bColTmp, bRowTmp, bTabTmp);
369 bOk = bOk && (bCol == bColTmp && bRow == bRowTmp && bTab == bTabTmp);
370 ++aCur;
373 if (bOk && aCur == aEnd)
375 bCol = bCol;
376 bRow = bRow;
377 bTab = bTab;
378 return true;
380 return false;
384 bool
385 lcl_lessReferenceBy(
386 const ScToken* const pRef1, const ScToken* const pRef2,
387 const DimensionSelector aWhich)
389 const SingleDoubleRefProvider rRef1(*pRef1);
390 const SingleDoubleRefProvider rRef2(*pRef2);
391 return aWhich(rRef1.Ref1) < aWhich(rRef2.Ref1);
395 /** Returns true if range denoted by token pRef2 starts immediately after
396 range denoted by token pRef1. Dimension, in which the comparison takes
397 place, is given by aWhich.
399 bool
400 lcl_isImmediatelyFollowing(
401 const ScToken* const pRef1, const ScToken* const pRef2,
402 const DimensionSelector aWhich)
404 const SingleDoubleRefProvider rRef1(*pRef1);
405 const SingleDoubleRefProvider rRef2(*pRef2);
406 return aWhich(rRef2.Ref1) - aWhich(rRef1.Ref2) == 1;
410 static bool
411 lcl_checkIfAdjacent(
412 const deque<ScToken*>& rReferences,
413 const DimensionSelector aWhich)
415 typedef deque<ScToken*>::const_iterator Iter;
416 Iter aBegin(rReferences.begin());
417 Iter aEnd(rReferences.end());
418 Iter aBegin1(aBegin);
419 ++aBegin1, --aEnd;
420 return std::equal(
421 aBegin, aEnd, aBegin1,
422 boost::bind(lcl_isImmediatelyFollowing, _1, _2, aWhich));
426 static void
427 lcl_fillRangeFromRefList(
428 const deque<ScToken*>& rReferences, ScRange& rRange)
430 const ScSingleRefData aStart(
431 SingleDoubleRefProvider(*rReferences.front()).Ref1);
432 rRange.aStart.Set(aStart.nCol, aStart.nRow, aStart.nTab);
433 const ScSingleRefData aEnd(
434 SingleDoubleRefProvider(*rReferences.back()).Ref2);
435 rRange.aEnd.Set(aEnd.nCol, aEnd.nRow, aEnd.nTab);
439 static bool
440 lcl_refListFormsOneRange(
441 const ScAddress& aPos, deque<ScToken*>& rReferences,
442 ScRange& rRange)
444 std::for_each(
445 rReferences.begin(), rReferences.end(),
446 bind(&ScToken::CalcAbsIfRel, _1, aPos))
448 if (rReferences.size() == 1) {
449 lcl_fillRangeFromRefList(rReferences, rRange);
450 return true;
453 bool bCell(false);
454 bool bRow(false);
455 bool bTab(false);
456 if (lcl_checkRangeDimensions(rReferences.begin(), rReferences.end(),
457 bCell, bRow, bTab))
459 DimensionSelector aWhich;
460 if (bCell)
462 aWhich = lcl_GetCol;
464 else if (bRow)
466 aWhich = lcl_GetRow;
468 else if (bTab)
470 aWhich = lcl_GetTab;
472 else
474 OSL_ENSURE(false, "lcl_checkRangeDimensions shouldn't allow that!");
475 aWhich = lcl_GetRow; // initialize to avoid warning
477 // Sort the references by start of range
478 std::sort(rReferences.begin(), rReferences.end(),
479 boost::bind(lcl_lessReferenceBy, _1, _2, aWhich));
480 if (lcl_checkIfAdjacent(rReferences, aWhich))
482 lcl_fillRangeFromRefList(rReferences, rRange);
483 return true;
486 return false;
490 bool lcl_isReference(const FormulaToken& rToken)
492 return
493 rToken.GetType() == svSingleRef ||
494 rToken.GetType() == svDoubleRef;
499 BOOL ScFormulaCell::IsEmpty()
501 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
502 Interpret();
503 return aResult.GetCellResultType() == formula::svEmptyCell;
506 BOOL ScFormulaCell::IsEmptyDisplayedAsString()
508 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
509 Interpret();
510 return aResult.IsEmptyDisplayedAsString();
513 BOOL ScFormulaCell::IsValue()
515 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
516 Interpret();
517 return aResult.IsValue();
520 double ScFormulaCell::GetValue()
522 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
523 Interpret();
524 if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) &&
525 !aResult.GetResultError())
526 return aResult.GetDouble();
527 return 0.0;
530 double ScFormulaCell::GetValueAlways()
532 // for goal seek: return result value even if error code is set
534 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
535 Interpret();
536 return aResult.GetDouble();
539 void ScFormulaCell::GetString( String& rString )
541 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
542 Interpret();
543 if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) &&
544 !aResult.GetResultError())
545 rString = aResult.GetString();
546 else
547 rString.Erase();
550 const ScMatrix* ScFormulaCell::GetMatrix()
552 if ( pDocument->GetAutoCalc() )
554 // Was stored !bDirty but an accompanying matrix cell was bDirty?
555 // => we need to get the matrix.
556 if (!bDirty && cMatrixFlag == MM_FORMULA && !aResult.GetMatrix().Is())
557 bDirty = TRUE;
558 if ( IsDirtyOrInTableOpDirty() )
559 Interpret();
561 return aResult.GetMatrix();
564 BOOL ScFormulaCell::GetMatrixOrigin( ScAddress& rPos ) const
566 switch ( cMatrixFlag )
568 case MM_FORMULA :
569 rPos = aPos;
570 return TRUE;
571 // break;
572 case MM_REFERENCE :
574 pCode->Reset();
575 ScToken* t = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
576 if( t )
578 ScSingleRefData& rRef = t->GetSingleRef();
579 rRef.CalcAbsIfRel( aPos );
580 if ( rRef.Valid() )
582 rPos.Set( rRef.nCol, rRef.nRow, rRef.nTab );
583 return TRUE;
587 break;
589 return FALSE;
594 Edge-Values:
597 4 16
600 innerhalb: 1
601 ausserhalb: 0
602 (reserviert: offen: 32)
605 USHORT ScFormulaCell::GetMatrixEdge( ScAddress& rOrgPos )
607 switch ( cMatrixFlag )
609 case MM_FORMULA :
610 case MM_REFERENCE :
612 static SCCOL nC;
613 static SCROW nR;
614 ScAddress aOrg;
615 if ( !GetMatrixOrigin( aOrg ) )
616 return 0; // dumm gelaufen..
617 if ( aOrg != rOrgPos )
618 { // erstes Mal oder andere Matrix als letztes Mal
619 rOrgPos = aOrg;
620 ScFormulaCell* pFCell;
621 if ( cMatrixFlag == MM_REFERENCE )
622 pFCell = (ScFormulaCell*) pDocument->GetCell( aOrg );
623 else
624 pFCell = this; // this MM_FORMULA
625 // this gibt's nur einmal, kein Vergleich auf pFCell==this
626 if ( pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA
627 && pFCell->cMatrixFlag == MM_FORMULA )
629 pFCell->GetMatColsRows( nC, nR );
630 if ( nC == 0 || nR == 0 )
631 { // aus altem Dokument geladen, neu erzeugen
632 nC = 1;
633 nR = 1;
634 ScAddress aTmpOrg;
635 ScBaseCell* pCell;
636 ScAddress aAdr( aOrg );
637 aAdr.IncCol();
638 BOOL bCont = TRUE;
641 pCell = pDocument->GetCell( aAdr );
642 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA
643 && ((ScFormulaCell*)pCell)->cMatrixFlag == MM_REFERENCE
644 && GetMatrixOrigin( aTmpOrg ) && aTmpOrg == aOrg )
646 nC++;
647 aAdr.IncCol();
649 else
650 bCont = FALSE;
651 } while ( bCont );
652 aAdr = aOrg;
653 aAdr.IncRow();
654 bCont = TRUE;
657 pCell = pDocument->GetCell( aAdr );
658 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA
659 && ((ScFormulaCell*)pCell)->cMatrixFlag == MM_REFERENCE
660 && GetMatrixOrigin( aTmpOrg ) && aTmpOrg == aOrg )
662 nR++;
663 aAdr.IncRow();
665 else
666 bCont = FALSE;
667 } while ( bCont );
668 pFCell->SetMatColsRows( nC, nR );
671 else
673 #ifndef PRODUCT
674 String aTmp;
675 ByteString aMsg( "broken Matrix, no MatFormula at origin, Pos: " );
676 aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
677 aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
678 aMsg += ", MatOrg: ";
679 aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
680 aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
681 DBG_ERRORFILE( aMsg.GetBuffer() );
682 #endif
683 return 0; // bad luck ...
686 // here we are, healthy and clean, somewhere in between
687 SCsCOL dC = aPos.Col() - aOrg.Col();
688 SCsROW dR = aPos.Row() - aOrg.Row();
689 USHORT nEdges = 0;
690 if ( dC >= 0 && dR >= 0 && dC < nC && dR < nR )
692 if ( dC == 0 )
693 nEdges |= 4; // linke Kante
694 if ( dC+1 == nC )
695 nEdges |= 16; // rechte Kante
696 if ( dR == 0 )
697 nEdges |= 8; // obere Kante
698 if ( dR+1 == nR )
699 nEdges |= 2; // untere Kante
700 if ( !nEdges )
701 nEdges = 1; // mittendrin
703 #ifndef PRODUCT
704 else
706 String aTmp;
707 ByteString aMsg( "broken Matrix, Pos: " );
708 aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
709 aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
710 aMsg += ", MatOrg: ";
711 aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
712 aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
713 aMsg += ", MatCols: ";
714 aMsg += ByteString::CreateFromInt32( nC );
715 aMsg += ", MatRows: ";
716 aMsg += ByteString::CreateFromInt32( nR );
717 aMsg += ", DiffCols: ";
718 aMsg += ByteString::CreateFromInt32( dC );
719 aMsg += ", DiffRows: ";
720 aMsg += ByteString::CreateFromInt32( dR );
721 DBG_ERRORFILE( aMsg.GetBuffer() );
723 #endif
724 return nEdges;
725 // break;
727 default:
728 return 0;
732 USHORT ScFormulaCell::GetErrCode()
734 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
735 Interpret();
736 /* FIXME: If ScTokenArray::SetCodeError() was really only for code errors
737 * and not also abused for signaling other error conditions we could bail
738 * out even before attempting to interpret broken code. */
739 USHORT nErr = pCode->GetCodeError();
740 if (nErr)
741 return nErr;
742 return aResult.GetResultError();
745 USHORT ScFormulaCell::GetRawError()
747 USHORT nErr = pCode->GetCodeError();
748 if (nErr)
749 return nErr;
750 return aResult.GetResultError();
753 BOOL ScFormulaCell::HasOneReference( ScRange& r ) const
755 pCode->Reset();
756 ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
757 if( p && !pCode->GetNextReferenceRPN() ) // nur eine!
759 p->CalcAbsIfRel( aPos );
760 SingleDoubleRefProvider aProv( *p );
761 r.aStart.Set( aProv.Ref1.nCol,
762 aProv.Ref1.nRow,
763 aProv.Ref1.nTab );
764 r.aEnd.Set( aProv.Ref2.nCol,
765 aProv.Ref2.nRow,
766 aProv.Ref2.nTab );
767 return TRUE;
769 else
770 return FALSE;
773 bool
774 ScFormulaCell::HasRefListExpressibleAsOneReference(ScRange& rRange) const
776 /* If there appears just one reference in the formula, it's the same
777 as HasOneReference(). If there are more of them, they can denote
778 one range if they are (sole) arguments of one function.
779 Union of these references must form one range and their
780 intersection must be empty set.
782 pCode->Reset();
783 // Get first reference, if any
784 ScToken* const pFirstReference(
785 dynamic_cast<ScToken*>(pCode->GetNextReferenceRPN()));
786 if (pFirstReference)
788 // Collect all consecutive references, starting by the one
789 // already found
790 std::deque<ScToken*> aReferences;
791 aReferences.push_back(pFirstReference);
792 FormulaToken* pToken(pCode->NextRPN());
793 FormulaToken* pFunction(0);
794 while (pToken)
796 if (lcl_isReference(*pToken))
798 aReferences.push_back(dynamic_cast<ScToken*>(pToken));
799 pToken = pCode->NextRPN();
801 else
803 if (pToken->IsFunction())
805 pFunction = pToken;
807 break;
810 if (pFunction && !pCode->GetNextReferenceRPN()
811 && (pFunction->GetParamCount() == aReferences.size()))
813 return lcl_refListFormsOneRange(aPos, aReferences, rRange);
816 return false;
819 BOOL ScFormulaCell::HasRelNameReference() const
821 pCode->Reset();
822 ScToken* t;
823 while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceRPN()) ) != NULL )
825 if ( t->GetSingleRef().IsRelName() ||
826 (t->GetType() == formula::svDoubleRef &&
827 t->GetDoubleRef().Ref2.IsRelName()) )
828 return TRUE;
830 return FALSE;
833 BOOL ScFormulaCell::HasColRowName() const
835 pCode->Reset();
836 return (pCode->GetNextColRowName() != NULL);
839 void ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode,
840 const ScRange& r,
841 SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
842 ScDocument* pUndoDoc, const ScAddress* pUndoCellPos )
844 SCCOL nCol1 = r.aStart.Col();
845 SCROW nRow1 = r.aStart.Row();
846 SCTAB nTab1 = r.aStart.Tab();
847 SCCOL nCol2 = r.aEnd.Col();
848 SCROW nRow2 = r.aEnd.Row();
849 SCTAB nTab2 = r.aEnd.Tab();
850 SCCOL nCol = aPos.Col();
851 SCROW nRow = aPos.Row();
852 SCTAB nTab = aPos.Tab();
853 ScAddress aUndoPos( aPos ); // position for undo cell in pUndoDoc
854 if ( pUndoCellPos )
855 aUndoPos = *pUndoCellPos;
856 ScAddress aOldPos( aPos );
857 // BOOL bPosChanged = FALSE; // ob diese Zelle bewegt wurde
858 BOOL bIsInsert = FALSE;
859 if (eUpdateRefMode == URM_INSDEL)
861 bIsInsert = (nDx >= 0 && nDy >= 0 && nDz >= 0);
862 if ( nDx && nRow >= nRow1 && nRow <= nRow2 &&
863 nTab >= nTab1 && nTab <= nTab2 )
865 if (nCol >= nCol1)
867 nCol = sal::static_int_cast<SCCOL>( nCol + nDx );
868 if ((SCsCOL) nCol < 0)
869 nCol = 0;
870 else if ( nCol > MAXCOL )
871 nCol = MAXCOL;
872 aPos.SetCol( nCol );
873 // bPosChanged = TRUE;
876 if ( nDy && nCol >= nCol1 && nCol <= nCol2 &&
877 nTab >= nTab1 && nTab <= nTab2 )
879 if (nRow >= nRow1)
881 nRow = sal::static_int_cast<SCROW>( nRow + nDy );
882 if ((SCsROW) nRow < 0)
883 nRow = 0;
884 else if ( nRow > MAXROW )
885 nRow = MAXROW;
886 aPos.SetRow( nRow );
887 // bPosChanged = TRUE;
890 if ( nDz && nCol >= nCol1 && nCol <= nCol2 &&
891 nRow >= nRow1 && nRow <= nRow2 )
893 if (nTab >= nTab1)
895 SCTAB nMaxTab = pDocument->GetTableCount() - 1;
896 nTab = sal::static_int_cast<SCTAB>( nTab + nDz );
897 if ((SCsTAB) nTab < 0)
898 nTab = 0;
899 else if ( nTab > nMaxTab )
900 nTab = nMaxTab;
901 aPos.SetTab( nTab );
902 // bPosChanged = TRUE;
906 else if ( r.In( aPos ) )
908 aOldPos.Set( nCol - nDx, nRow - nDy, nTab - nDz );
909 // bPosChanged = TRUE;
912 BOOL bHasRefs = FALSE;
913 BOOL bHasColRowNames = FALSE;
914 BOOL bOnRefMove = FALSE;
915 if ( !pDocument->IsClipOrUndo() )
917 pCode->Reset();
918 bHasRefs = (pCode->GetNextReferenceRPN() != NULL);
919 if ( !bHasRefs || eUpdateRefMode == URM_COPY )
921 pCode->Reset();
922 bHasColRowNames = (pCode->GetNextColRowName() != NULL);
923 bHasRefs = bHasRefs || bHasColRowNames;
925 bOnRefMove = pCode->IsRecalcModeOnRefMove();
927 if( bHasRefs || bOnRefMove )
929 ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL;
930 BOOL bValChanged;
931 ScRangeData* pRangeData;
932 BOOL bRangeModified; // any range, not only shared formula
933 BOOL bRefSizeChanged;
934 if ( bHasRefs )
936 ScCompiler aComp(pDocument, aPos, *pCode);
937 aComp.SetGrammar(pDocument->GetGrammar());
938 pRangeData = aComp.UpdateReference(eUpdateRefMode, aOldPos, r,
939 nDx, nDy, nDz,
940 bValChanged, bRefSizeChanged);
941 bRangeModified = aComp.HasModifiedRange();
943 else
945 bValChanged = FALSE;
946 pRangeData = NULL;
947 bRangeModified = FALSE;
948 bRefSizeChanged = FALSE;
950 if ( bOnRefMove )
951 bOnRefMove = (bValChanged || (aPos != aOldPos));
952 // Cell may reference itself, e.g. ocColumn, ocRow without parameter
954 BOOL bColRowNameCompile, bHasRelName, bNewListening, bInDeleteUndo;
955 if ( bHasRefs )
957 // Upon Insert ColRowNames have to be recompiled in case the
958 // insertion occurs right in front of the range.
959 bColRowNameCompile =
960 (eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0));
961 if ( bColRowNameCompile )
963 bColRowNameCompile = FALSE;
964 ScToken* t;
965 ScRangePairList* pColList = pDocument->GetColNameRanges();
966 ScRangePairList* pRowList = pDocument->GetRowNameRanges();
967 pCode->Reset();
968 while ( !bColRowNameCompile && (t = static_cast<ScToken*>(pCode->GetNextColRowName())) != NULL )
970 ScSingleRefData& rRef = t->GetSingleRef();
971 if ( nDy > 0 && rRef.IsColRel() )
972 { // ColName
973 rRef.CalcAbsIfRel( aPos );
974 ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
975 ScRangePair* pR = pColList->Find( aAdr );
976 if ( pR )
977 { // definiert
978 if ( pR->GetRange(1).aStart.Row() == nRow1 )
979 bColRowNameCompile = TRUE;
981 else
982 { // on the fly
983 if ( rRef.nRow + 1 == nRow1 )
984 bColRowNameCompile = TRUE;
987 if ( nDx > 0 && rRef.IsRowRel() )
988 { // RowName
989 rRef.CalcAbsIfRel( aPos );
990 ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
991 ScRangePair* pR = pRowList->Find( aAdr );
992 if ( pR )
993 { // definiert
994 if ( pR->GetRange(1).aStart.Col() == nCol1 )
995 bColRowNameCompile = TRUE;
997 else
998 { // on the fly
999 if ( rRef.nCol + 1 == nCol1 )
1000 bColRowNameCompile = TRUE;
1005 else if ( eUpdateRefMode == URM_MOVE )
1006 { // bei Move/D&D neu kompilieren wenn ColRowName verschoben wurde
1007 // oder diese Zelle auf einen zeigt und verschoben wurde
1008 bColRowNameCompile = bCompile; // evtl. aus Copy-ctor
1009 if ( !bColRowNameCompile )
1011 BOOL bMoved = (aPos != aOldPos);
1012 pCode->Reset();
1013 ScToken* t = static_cast<ScToken*>(pCode->GetNextColRowName());
1014 if ( t && bMoved )
1015 bColRowNameCompile = TRUE;
1016 while ( t && !bColRowNameCompile )
1018 ScSingleRefData& rRef = t->GetSingleRef();
1019 rRef.CalcAbsIfRel( aPos );
1020 if ( rRef.Valid() )
1022 ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
1023 if ( r.In( aAdr ) )
1024 bColRowNameCompile = TRUE;
1026 t = static_cast<ScToken*>(pCode->GetNextColRowName());
1030 else if ( eUpdateRefMode == URM_COPY && bHasColRowNames && bValChanged )
1032 bColRowNameCompile = TRUE;
1034 ScChangeTrack* pChangeTrack = pDocument->GetChangeTrack();
1035 if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
1036 bInDeleteUndo = TRUE;
1037 else
1038 bInDeleteUndo = FALSE;
1039 // RelNameRefs are always moved
1040 bHasRelName = HasRelNameReference();
1041 // Reference changed and new listening needed?
1042 // Except in Insert/Delete without specialties.
1043 bNewListening = (bRangeModified || pRangeData || bColRowNameCompile
1044 || (bValChanged && (eUpdateRefMode != URM_INSDEL ||
1045 bInDeleteUndo || bRefSizeChanged)) ||
1046 (bHasRelName && eUpdateRefMode != URM_COPY))
1047 // #i36299# Don't duplicate action during cut&paste / drag&drop
1048 // on a cell in the range moved, start/end listeners is done
1049 // via ScDocument::DeleteArea() and ScDocument::CopyFromClip().
1050 && !(eUpdateRefMode == URM_MOVE &&
1051 pDocument->IsInsertingFromOtherDoc() && r.In(aPos));
1052 if ( bNewListening )
1053 EndListeningTo( pDocument, pOld, aOldPos );
1055 else
1057 bColRowNameCompile = bHasRelName = bNewListening = bInDeleteUndo =
1058 FALSE;
1061 BOOL bNeedDirty;
1062 // NeedDirty bei Aenderungen ausser Copy und Move/Insert ohne RelNames
1063 if ( bRangeModified || pRangeData || bColRowNameCompile ||
1064 (bValChanged && eUpdateRefMode != URM_COPY &&
1065 (eUpdateRefMode != URM_MOVE || bHasRelName) &&
1066 (!bIsInsert || bHasRelName || bInDeleteUndo ||
1067 bRefSizeChanged)) || bOnRefMove)
1068 bNeedDirty = TRUE;
1069 else
1070 bNeedDirty = FALSE;
1071 if (pUndoDoc && (bValChanged || pRangeData || bOnRefMove))
1073 // Copy the cell to aUndoPos, which is its current position in the document,
1074 // so this works when UpdateReference is called before moving the cells
1075 // (InsertCells/DeleteCells - aPos is changed above) as well as when UpdateReference
1076 // is called after moving the cells (MoveBlock/PasteFromClip - aOldPos is changed).
1078 // If there is already a formula cell in the undo document, don't overwrite it,
1079 // the first (oldest) is the important cell.
1080 if ( pUndoDoc->GetCellType( aUndoPos ) != CELLTYPE_FORMULA )
1082 ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aUndoPos,
1083 pOld, eTempGrammar, cMatrixFlag );
1084 pFCell->aResult.SetToken( NULL); // to recognize it as changed later (Cut/Paste!)
1085 pUndoDoc->PutCell( aUndoPos, pFCell );
1088 bValChanged = FALSE;
1089 if ( pRangeData )
1090 { // Replace shared formula with own formula
1091 pDocument->RemoveFromFormulaTree( this ); // update formula count
1092 delete pCode;
1093 pCode = pRangeData->GetCode()->Clone();
1094 ScCompiler aComp2(pDocument, aPos, *pCode);
1095 aComp2.SetGrammar(pDocument->GetGrammar());
1096 aComp2.UpdateSharedFormulaReference( eUpdateRefMode, aOldPos, r,
1097 nDx, nDy, nDz );
1098 bValChanged = TRUE;
1099 bNeedDirty = TRUE;
1101 if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 )
1103 CompileTokenArray( bNewListening ); // kein Listening
1104 bNeedDirty = TRUE;
1106 if ( !bInDeleteUndo )
1107 { // In ChangeTrack Delete-Reject listeners are established in
1108 // InsertCol/InsertRow
1109 if ( bNewListening )
1111 if ( eUpdateRefMode == URM_INSDEL )
1113 // Inserts/Deletes re-establish listeners after all
1114 // UpdateReference calls.
1115 // All replaced shared formula listeners have to be
1116 // established after an Insert or Delete. Do nothing here.
1117 SetNeedsListening( TRUE);
1119 else
1120 StartListeningTo( pDocument );
1123 if ( bNeedDirty && (!(eUpdateRefMode == URM_INSDEL && bHasRelName) || pRangeData) )
1124 { // Referenzen abgeschnitten, ungueltig o.ae.?
1125 BOOL bOldAutoCalc = pDocument->GetAutoCalc();
1126 // kein Interpret in SubMinimalRecalc wegen evtl. falscher Referenzen
1127 pDocument->SetAutoCalc( FALSE );
1128 SetDirty();
1129 pDocument->SetAutoCalc( bOldAutoCalc );
1132 delete pOld;
1135 pCode->Reset();
1136 for ( formula::FormulaToken* t = pCode->GetNextReferenceOrName(); t; t = pCode->GetNextReferenceOrName() )
1138 StackVar sv = t->GetType();
1139 if (sv == svExternalSingleRef || sv == svExternalDoubleRef || sv == svExternalName)
1141 pDocument->GetExternalRefManager()->updateRefCell(aOldPos, aPos, eUpdateRefMode == URM_COPY);
1142 break;
1147 void ScFormulaCell::UpdateInsertTab(SCTAB nTable)
1149 BOOL bPosChanged = ( aPos.Tab() >= nTable ? TRUE : FALSE );
1150 pCode->Reset();
1151 if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
1153 EndListeningTo( pDocument );
1154 // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateInsertTab !
1155 if ( bPosChanged )
1156 aPos.IncTab();
1157 ScRangeData* pRangeData;
1158 ScCompiler aComp(pDocument, aPos, *pCode);
1159 aComp.SetGrammar(pDocument->GetGrammar());
1160 pRangeData = aComp.UpdateInsertTab( nTable, FALSE );
1161 if (pRangeData) // Shared Formula gegen echte Formel
1162 { // austauschen
1163 BOOL bRefChanged;
1164 pDocument->RemoveFromFormulaTree( this ); // update formula count
1165 delete pCode;
1166 pCode = new ScTokenArray( *pRangeData->GetCode() );
1167 ScCompiler aComp2(pDocument, aPos, *pCode);
1168 aComp2.SetGrammar(pDocument->GetGrammar());
1169 aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
1170 aComp2.UpdateInsertTab( nTable, FALSE );
1171 // If the shared formula contained a named range/formula containing
1172 // an absolute reference to a sheet, those have to be readjusted.
1173 aComp2.UpdateDeleteTab( nTable, FALSE, TRUE, bRefChanged );
1174 bCompile = TRUE;
1176 // kein StartListeningTo weil pTab[nTab] noch nicht existiert!
1178 else if ( bPosChanged )
1179 aPos.IncTab();
1182 BOOL ScFormulaCell::UpdateDeleteTab(SCTAB nTable, BOOL bIsMove)
1184 BOOL bRefChanged = FALSE;
1185 BOOL bPosChanged = ( aPos.Tab() > nTable ? TRUE : FALSE );
1186 pCode->Reset();
1187 if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
1189 EndListeningTo( pDocument );
1190 // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateDeleteTab !
1191 if ( bPosChanged )
1192 aPos.IncTab(-1);
1193 ScRangeData* pRangeData;
1194 ScCompiler aComp(pDocument, aPos, *pCode);
1195 aComp.SetGrammar(pDocument->GetGrammar());
1196 pRangeData = aComp.UpdateDeleteTab(nTable, bIsMove, FALSE, bRefChanged);
1197 if (pRangeData) // Shared Formula gegen echte Formel
1198 { // austauschen
1199 pDocument->RemoveFromFormulaTree( this ); // update formula count
1200 delete pCode;
1201 pCode = pRangeData->GetCode()->Clone();
1202 ScCompiler aComp2(pDocument, aPos, *pCode);
1203 aComp2.SetGrammar(pDocument->GetGrammar());
1204 aComp2.CompileTokenArray();
1205 aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
1206 aComp2.UpdateDeleteTab( nTable, FALSE, FALSE, bRefChanged );
1207 // If the shared formula contained a named range/formula containing
1208 // an absolute reference to a sheet, those have to be readjusted.
1209 aComp2.UpdateInsertTab( nTable,TRUE );
1210 // bRefChanged kann beim letzten UpdateDeleteTab zurueckgesetzt worden sein
1211 bRefChanged = TRUE;
1212 bCompile = TRUE;
1214 // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
1216 else if ( bPosChanged )
1217 aPos.IncTab(-1);
1219 return bRefChanged;
1222 void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
1224 pCode->Reset();
1225 if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
1227 EndListeningTo( pDocument );
1228 // SetTab _nach_ EndListeningTo und _vor_ Compiler UpdateMoveTab !
1229 aPos.SetTab( nTabNo );
1230 ScRangeData* pRangeData;
1231 ScCompiler aComp(pDocument, aPos, *pCode);
1232 aComp.SetGrammar(pDocument->GetGrammar());
1233 pRangeData = aComp.UpdateMoveTab( nOldPos, nNewPos, FALSE );
1234 if (pRangeData) // Shared Formula gegen echte Formel
1235 { // austauschen
1236 pDocument->RemoveFromFormulaTree( this ); // update formula count
1237 delete pCode;
1238 pCode = pRangeData->GetCode()->Clone();
1239 ScCompiler aComp2(pDocument, aPos, *pCode);
1240 aComp2.SetGrammar(pDocument->GetGrammar());
1241 aComp2.CompileTokenArray();
1242 aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow());
1243 aComp2.UpdateMoveTab( nOldPos, nNewPos, TRUE );
1244 bCompile = TRUE;
1246 // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
1248 else
1249 aPos.SetTab( nTabNo );
1252 void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable)
1254 if( !pDocument->IsClipOrUndo() )
1256 pCode->Reset();
1257 ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
1258 while( p )
1260 ScSingleRefData& rRef1 = p->GetSingleRef();
1261 if( !rRef1.IsTabRel() && (SCsTAB) nTable <= rRef1.nTab )
1262 rRef1.nTab++;
1263 if( p->GetType() == formula::svDoubleRef )
1265 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
1266 if( !rRef2.IsTabRel() && (SCsTAB) nTable <= rRef2.nTab )
1267 rRef2.nTab++;
1269 p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
1274 BOOL ScFormulaCell::TestTabRefAbs(SCTAB nTable)
1276 BOOL bRet = FALSE;
1277 if( !pDocument->IsClipOrUndo() )
1279 pCode->Reset();
1280 ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
1281 while( p )
1283 ScSingleRefData& rRef1 = p->GetSingleRef();
1284 if( !rRef1.IsTabRel() )
1286 if( (SCsTAB) nTable != rRef1.nTab )
1287 bRet = TRUE;
1288 else if (nTable != aPos.Tab())
1289 rRef1.nTab = aPos.Tab();
1291 if( p->GetType() == formula::svDoubleRef )
1293 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
1294 if( !rRef2.IsTabRel() )
1296 if( (SCsTAB) nTable != rRef2.nTab )
1297 bRet = TRUE;
1298 else if (nTable != aPos.Tab())
1299 rRef2.nTab = aPos.Tab();
1302 p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
1305 return bRet;
1308 void ScFormulaCell::UpdateCompile( BOOL bForceIfNameInUse )
1310 if ( bForceIfNameInUse && !bCompile )
1311 bCompile = pCode->HasNameOrColRowName();
1312 if ( bCompile )
1313 pCode->SetCodeError( 0 ); // make sure it will really be compiled
1314 CompileTokenArray();
1317 // Referenzen transponieren - wird nur in Clipboard-Dokumenten aufgerufen
1319 void ScFormulaCell::TransposeReference()
1321 BOOL bFound = FALSE;
1322 pCode->Reset();
1323 ScToken* t;
1324 while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
1326 ScSingleRefData& rRef1 = t->GetSingleRef();
1327 if ( rRef1.IsColRel() && rRef1.IsRowRel() )
1329 BOOL bDouble = (t->GetType() == formula::svDoubleRef);
1330 ScSingleRefData& rRef2 = (bDouble ? t->GetDoubleRef().Ref2 : rRef1);
1331 if ( !bDouble || (rRef2.IsColRel() && rRef2.IsRowRel()) )
1333 INT16 nTemp;
1335 nTemp = rRef1.nRelCol;
1336 rRef1.nRelCol = static_cast<SCCOL>(rRef1.nRelRow);
1337 rRef1.nRelRow = static_cast<SCROW>(nTemp);
1339 if ( bDouble )
1341 nTemp = rRef2.nRelCol;
1342 rRef2.nRelCol = static_cast<SCCOL>(rRef2.nRelRow);
1343 rRef2.nRelRow = static_cast<SCROW>(nTemp);
1346 bFound = TRUE;
1351 if (bFound)
1352 bCompile = TRUE;
1355 void ScFormulaCell::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
1356 ScDocument* pUndoDoc )
1358 EndListeningTo( pDocument );
1360 ScAddress aOldPos = aPos;
1361 BOOL bPosChanged = FALSE; // ob diese Zelle bewegt wurde
1363 ScRange aDestRange( rDest, ScAddress(
1364 static_cast<SCCOL>(rDest.Col() + rSource.aEnd.Row() - rSource.aStart.Row()),
1365 static_cast<SCROW>(rDest.Row() + rSource.aEnd.Col() - rSource.aStart.Col()),
1366 rDest.Tab() + rSource.aEnd.Tab() - rSource.aStart.Tab() ) );
1367 if ( aDestRange.In( aOldPos ) )
1369 // Position zurueckrechnen
1370 SCsCOL nRelPosX = aOldPos.Col();
1371 SCsROW nRelPosY = aOldPos.Row();
1372 SCsTAB nRelPosZ = aOldPos.Tab();
1373 ScRefUpdate::DoTranspose( nRelPosX, nRelPosY, nRelPosZ, pDocument, aDestRange, rSource.aStart );
1374 aOldPos.Set( nRelPosX, nRelPosY, nRelPosZ );
1375 bPosChanged = TRUE;
1378 ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL;
1379 BOOL bRefChanged = FALSE;
1380 ScToken* t;
1382 ScRangeData* pShared = NULL;
1383 pCode->Reset();
1384 while( (t = static_cast<ScToken*>(pCode->GetNextReferenceOrName())) != NULL )
1386 if( t->GetOpCode() == ocName )
1388 ScRangeData* pName = pDocument->GetRangeName()->FindIndex( t->GetIndex() );
1389 if (pName)
1391 if (pName->IsModified())
1392 bRefChanged = TRUE;
1393 if (pName->HasType(RT_SHAREDMOD))
1394 pShared = pName;
1397 else if( t->GetType() != svIndex )
1399 t->CalcAbsIfRel( aOldPos );
1400 BOOL bMod;
1401 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1402 SingleDoubleRefModifier aMod( *t );
1403 ScComplexRefData& rRef = aMod.Ref();
1404 bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource,
1405 rDest, rRef ) != UR_NOTHING || bPosChanged);
1407 if ( bMod )
1409 t->CalcRelFromAbs( aPos );
1410 bRefChanged = TRUE;
1415 if (pShared) // Shared Formula gegen echte Formel austauschen
1417 pDocument->RemoveFromFormulaTree( this ); // update formula count
1418 delete pCode;
1419 pCode = new ScTokenArray( *pShared->GetCode() );
1420 bRefChanged = TRUE;
1421 pCode->Reset();
1422 while( (t = static_cast<ScToken*>(pCode->GetNextReference())) != NULL )
1424 if( t->GetType() != svIndex )
1426 t->CalcAbsIfRel( aOldPos );
1427 BOOL bMod;
1428 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1429 SingleDoubleRefModifier aMod( *t );
1430 ScComplexRefData& rRef = aMod.Ref();
1431 bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource,
1432 rDest, rRef ) != UR_NOTHING || bPosChanged);
1434 if ( bMod )
1435 t->CalcRelFromAbs( aPos );
1440 if (bRefChanged)
1442 if (pUndoDoc)
1444 ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aPos, pOld,
1445 eTempGrammar, cMatrixFlag);
1446 pFCell->aResult.SetToken( NULL); // to recognize it as changed later (Cut/Paste!)
1447 pUndoDoc->PutCell( aPos.Col(), aPos.Row(), aPos.Tab(), pFCell );
1450 bCompile = TRUE;
1451 CompileTokenArray(); // ruft auch StartListeningTo
1452 SetDirty();
1454 else
1455 StartListeningTo( pDocument ); // Listener wie vorher
1457 delete pOld;
1460 void ScFormulaCell::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
1462 EndListeningTo( pDocument );
1464 BOOL bRefChanged = FALSE;
1465 ScToken* t;
1466 ScRangeData* pShared = NULL;
1468 pCode->Reset();
1469 while( (t = static_cast<ScToken*>(pCode->GetNextReferenceOrName())) != NULL )
1471 if( t->GetOpCode() == ocName )
1473 ScRangeData* pName = pDocument->GetRangeName()->FindIndex( t->GetIndex() );
1474 if (pName)
1476 if (pName->IsModified())
1477 bRefChanged = TRUE;
1478 if (pName->HasType(RT_SHAREDMOD))
1479 pShared = pName;
1482 else if( t->GetType() != svIndex )
1484 t->CalcAbsIfRel( aPos );
1485 BOOL bMod;
1486 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1487 SingleDoubleRefModifier aMod( *t );
1488 ScComplexRefData& rRef = aMod.Ref();
1489 bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY,
1490 rRef ) != UR_NOTHING);
1492 if ( bMod )
1494 t->CalcRelFromAbs( aPos );
1495 bRefChanged = TRUE;
1500 if (pShared) // Shared Formula gegen echte Formel austauschen
1502 pDocument->RemoveFromFormulaTree( this ); // update formula count
1503 delete pCode;
1504 pCode = new ScTokenArray( *pShared->GetCode() );
1505 bRefChanged = TRUE;
1506 pCode->Reset();
1507 while( (t = static_cast<ScToken*>(pCode->GetNextReference())) != NULL )
1509 if( t->GetType() != svIndex )
1511 t->CalcAbsIfRel( aPos );
1512 BOOL bMod;
1513 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1514 SingleDoubleRefModifier aMod( *t );
1515 ScComplexRefData& rRef = aMod.Ref();
1516 bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY,
1517 rRef ) != UR_NOTHING);
1519 if ( bMod )
1520 t->CalcRelFromAbs( aPos );
1525 if (bRefChanged)
1527 bCompile = TRUE;
1528 CompileTokenArray(); // ruft auch StartListeningTo
1529 SetDirty();
1531 else
1532 StartListeningTo( pDocument ); // Listener wie vorher
1535 BOOL lcl_IsRangeNameInUse(USHORT nIndex, ScTokenArray* pCode, ScRangeName* pNames)
1537 for (FormulaToken* p = pCode->First(); p; p = pCode->Next())
1539 if (p->GetOpCode() == ocName)
1541 if (p->GetIndex() == nIndex)
1542 return TRUE;
1543 else
1545 // RangeData kann Null sein in bestimmten Excel-Dateien (#31168#)
1546 ScRangeData* pSubName = pNames->FindIndex(p->GetIndex());
1547 if (pSubName && lcl_IsRangeNameInUse(nIndex,
1548 pSubName->GetCode(), pNames))
1549 return TRUE;
1553 return FALSE;
1556 BOOL ScFormulaCell::IsRangeNameInUse(USHORT nIndex) const
1558 return lcl_IsRangeNameInUse( nIndex, pCode, pDocument->GetRangeName() );
1561 void lcl_FindRangeNamesInUse(std::set<USHORT>& rIndexes, ScTokenArray* pCode, ScRangeName* pNames)
1563 for (FormulaToken* p = pCode->First(); p; p = pCode->Next())
1565 if (p->GetOpCode() == ocName)
1567 USHORT nTokenIndex = p->GetIndex();
1568 rIndexes.insert( nTokenIndex );
1570 ScRangeData* pSubName = pNames->FindIndex(p->GetIndex());
1571 if (pSubName)
1572 lcl_FindRangeNamesInUse(rIndexes, pSubName->GetCode(), pNames);
1577 void ScFormulaCell::FindRangeNamesInUse(std::set<USHORT>& rIndexes) const
1579 lcl_FindRangeNamesInUse( rIndexes, pCode, pDocument->GetRangeName() );
1582 void ScFormulaCell::ReplaceRangeNamesInUse( const ScIndexMap& rMap )
1584 for( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
1586 if( p->GetOpCode() == ocName )
1588 USHORT nIndex = p->GetIndex();
1589 USHORT nNewIndex = rMap.Find( nIndex );
1590 if ( nIndex != nNewIndex )
1592 p->SetIndex( nNewIndex );
1593 bCompile = TRUE;
1597 if( bCompile )
1598 CompileTokenArray();
1601 void ScFormulaCell::ReplaceRangeNamesInUse( const ScRangeData::IndexMap& rMap )
1603 for( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
1605 if( p->GetOpCode() == ocName )
1607 sal_uInt16 nIndex = p->GetIndex();
1608 ScRangeData::IndexMap::const_iterator itr = rMap.find(nIndex);
1609 sal_uInt16 nNewIndex = itr == rMap.end() ? nIndex : nNewIndex;
1610 if ( nIndex != nNewIndex )
1612 p->SetIndex( nNewIndex );
1613 bCompile = TRUE;
1617 if( bCompile )
1618 CompileTokenArray();
1621 void ScFormulaCell::CompileDBFormula()
1623 for( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
1625 if ( p->GetOpCode() == ocDBArea
1626 || (p->GetOpCode() == ocName && p->GetIndex() >= SC_START_INDEX_DB_COLL) )
1628 bCompile = TRUE;
1629 CompileTokenArray();
1630 SetDirty();
1631 break;
1636 void ScFormulaCell::CompileDBFormula( BOOL bCreateFormulaString )
1638 // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
1639 // 1. FormelString mit alten Namen erzeugen
1640 // 2. FormelString mit neuen Namen kompilieren
1641 if ( bCreateFormulaString )
1643 BOOL bRecompile = FALSE;
1644 pCode->Reset();
1645 for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() )
1647 switch ( p->GetOpCode() )
1649 case ocBad: // DB-Bereich evtl. zugefuegt
1650 case ocColRowName: // #36762# falls Namensgleichheit
1651 case ocDBArea: // DB-Bereich
1652 bRecompile = TRUE;
1653 break;
1654 case ocName:
1655 if ( p->GetIndex() >= SC_START_INDEX_DB_COLL )
1656 bRecompile = TRUE; // DB-Bereich
1657 break;
1658 default:
1659 ; // nothing
1662 if ( bRecompile )
1664 String aFormula;
1665 GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
1666 if ( GetMatrixFlag() != MM_NONE && aFormula.Len() )
1668 if ( aFormula.GetChar( aFormula.Len()-1 ) == '}' )
1669 aFormula.Erase( aFormula.Len()-1 , 1 );
1670 if ( aFormula.GetChar(0) == '{' )
1671 aFormula.Erase( 0, 1 );
1673 EndListeningTo( pDocument );
1674 pDocument->RemoveFromFormulaTree( this );
1675 pCode->Clear();
1676 SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
1679 else if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
1681 Compile( aResult.GetHybridFormula(), FALSE, eTempGrammar );
1682 aResult.SetToken( NULL);
1683 SetDirty();
1687 void ScFormulaCell::CompileNameFormula( BOOL bCreateFormulaString )
1689 // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
1690 // 1. FormelString mit alten RangeNames erzeugen
1691 // 2. FormelString mit neuen RangeNames kompilieren
1692 if ( bCreateFormulaString )
1694 BOOL bRecompile = FALSE;
1695 pCode->Reset();
1696 for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() )
1698 switch ( p->GetOpCode() )
1700 case ocBad: // RangeName evtl. zugefuegt
1701 case ocColRowName: // #36762# falls Namensgleichheit
1702 bRecompile = TRUE;
1703 break;
1704 default:
1705 if ( p->GetType() == svIndex )
1706 bRecompile = TRUE; // RangeName
1709 if ( bRecompile )
1711 String aFormula;
1712 GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
1713 if ( GetMatrixFlag() != MM_NONE && aFormula.Len() )
1715 if ( aFormula.GetChar( aFormula.Len()-1 ) == '}' )
1716 aFormula.Erase( aFormula.Len()-1 , 1 );
1717 if ( aFormula.GetChar(0) == '{' )
1718 aFormula.Erase( 0, 1 );
1720 EndListeningTo( pDocument );
1721 pDocument->RemoveFromFormulaTree( this );
1722 pCode->Clear();
1723 SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
1726 else if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
1728 Compile( aResult.GetHybridFormula(), FALSE, eTempGrammar );
1729 aResult.SetToken( NULL);
1730 SetDirty();
1734 void ScFormulaCell::CompileColRowNameFormula()
1736 pCode->Reset();
1737 for ( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
1739 if ( p->GetOpCode() == ocColRowName )
1741 bCompile = TRUE;
1742 CompileTokenArray();
1743 SetDirty();
1744 break;
1749 // ============================================================================