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 ---------------------------------------------------------------
40 #include <boost/bind.hpp>
42 #include <vcl/mapmod.hxx>
43 #include <svx/editobj.hxx>
44 #include <svx/editstat.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 -----------------------------------------------------------
66 const USHORT nMemPoolEditCell
= (0x1000 - 64) / sizeof(ScNoteCell
);
67 IMPL_FIXEDMEMPOOL_NEWDEL( ScEditCell
, nMemPoolEditCell
, nMemPoolEditCell
)
70 // ============================================================================
72 ScEditCell::ScEditCell( const EditTextObject
* pObject
, ScDocument
* pDocP
,
73 const SfxItemPool
* pFromPool
) :
74 ScBaseCell( CELLTYPE_EDIT
),
78 SetTextObject( pObject
, pFromPool
);
81 ScEditCell::ScEditCell( const ScEditCell
& rCell
, ScDocument
& rDoc
) :
86 SetTextObject( rCell
.pData
, rCell
.pDoc
->GetEditPool() );
89 ScEditCell::ScEditCell( const String
& rString
, ScDocument
* pDocP
) :
90 ScBaseCell( CELLTYPE_EDIT
),
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()
109 eCellType
= CELLTYPE_DESTROYED
;
113 void ScEditCell::SetData( const EditTextObject
* pObject
,
114 const SfxItemPool
* pFromPool
)
122 SetTextObject( pObject
, pFromPool
);
125 void ScEditCell::GetData( const EditTextObject
*& rpObject
) const
130 void ScEditCell::GetString( String
& rString
) const
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
148 bool ScEditCell::HasPhonetic() const
153 void ScEditCell::RemoveCharAttribs( const ScPatternAttr
& rAttr
)
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
)
180 if ( pFromPool
&& pDoc
->GetEditPool() == pFromPool
)
181 pData
= pObject
->Clone();
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
);
193 rEngine
.SetControlWord( nControl
| nSpellControl
);
194 rEngine
.SetText( *pObject
);
195 pData
= rEngine
.CreateTextObject();
197 rEngine
.SetControlWord( nControl
);
201 rEngine
.SetText( *pObject
);
202 pData
= rEngine
.CreateTextObject();
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())
232 const ScEditDataArray::Item
* ScEditDataArray::Next()
234 if (maIter
== maArray
.end())
239 // ============================================================================
241 ScEditDataArray::Item::Item(SCTAB nTab
, SCCOL nCol
, SCROW nRow
,
242 EditTextObject
* pOldData
, EditTextObject
* pNewData
) :
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
270 SCCOL
ScEditDataArray::Item::GetCol() const
275 SCROW
ScEditDataArray::Item::GetRow() const
280 // ============================================================================
287 typedef SCCOLROW(*DimensionSelector
)(const ScSingleRefData
&);
290 static SCCOLROW
lcl_GetCol(const ScSingleRefData
& rData
)
296 static SCCOLROW
lcl_GetRow(const ScSingleRefData
& rData
)
302 static SCCOLROW
lcl_GetTab(const ScSingleRefData
& rData
)
308 /** Check if both references span the same range in selected dimension.
311 lcl_checkRangeDimension(
312 const SingleDoubleRefProvider
& rRef1
,
313 const SingleDoubleRefProvider
& rRef2
,
314 const DimensionSelector aWhich
)
317 aWhich(rRef1
.Ref1
) == aWhich(rRef2
.Ref1
)
318 && aWhich(rRef1
.Ref2
) == aWhich(rRef2
.Ref2
);
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
))
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.
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
);
356 const SingleDoubleRefProvider
aRef(**aBegin
);
359 const SingleDoubleRefProvider
aRefCur(**aCur
);
360 bOk
= lcl_checkRangeDimensions(aRef
, aRefCur
, bCol
, bRow
, bTab
);
362 while (bOk
&& aCur
!= aEnd
)
364 const SingleDoubleRefProvider
aRefCur(**aCur
);
368 bOk
= lcl_checkRangeDimensions(aRef
, aRefCur
, bColTmp
, bRowTmp
, bTabTmp
);
369 bOk
= bOk
&& (bCol
== bColTmp
&& bRow
== bRowTmp
&& bTab
== bTabTmp
);
373 if (bOk
&& aCur
== aEnd
)
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.
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;
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
);
421 aBegin
, aEnd
, aBegin1
,
422 boost::bind(lcl_isImmediatelyFollowing
, _1
, _2
, aWhich
));
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
);
440 lcl_refListFormsOneRange(
441 const ScAddress
& aPos
, deque
<ScToken
*>& rReferences
,
445 rReferences
.begin(), rReferences
.end(),
446 bind(&ScToken::CalcAbsIfRel
, _1
, aPos
))
448 if (rReferences
.size() == 1) {
449 lcl_fillRangeFromRefList(rReferences
, rRange
);
456 if (lcl_checkRangeDimensions(rReferences
.begin(), rReferences
.end(),
459 DimensionSelector aWhich
;
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
);
490 bool lcl_isReference(const FormulaToken
& rToken
)
493 rToken
.GetType() == svSingleRef
||
494 rToken
.GetType() == svDoubleRef
;
499 BOOL
ScFormulaCell::IsEmpty()
501 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
503 return aResult
.GetCellResultType() == formula::svEmptyCell
;
506 BOOL
ScFormulaCell::IsEmptyDisplayedAsString()
508 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
510 return aResult
.IsEmptyDisplayedAsString();
513 BOOL
ScFormulaCell::IsValue()
515 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
517 return aResult
.IsValue();
520 double ScFormulaCell::GetValue()
522 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
524 if ((!pCode
->GetCodeError() || pCode
->GetCodeError() == errDoubleRef
) &&
525 !aResult
.GetResultError())
526 return aResult
.GetDouble();
530 double ScFormulaCell::GetValueAlways()
532 // for goal seek: return result value even if error code is set
534 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
536 return aResult
.GetDouble();
539 void ScFormulaCell::GetString( String
& rString
)
541 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
543 if ((!pCode
->GetCodeError() || pCode
->GetCodeError() == errDoubleRef
) &&
544 !aResult
.GetResultError())
545 rString
= aResult
.GetString();
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())
558 if ( IsDirtyOrInTableOpDirty() )
561 return aResult
.GetMatrix();
564 BOOL
ScFormulaCell::GetMatrixOrigin( ScAddress
& rPos
) const
566 switch ( cMatrixFlag
)
575 ScToken
* t
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
578 ScSingleRefData
& rRef
= t
->GetSingleRef();
579 rRef
.CalcAbsIfRel( aPos
);
582 rPos
.Set( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
);
602 (reserviert: offen: 32)
605 USHORT
ScFormulaCell::GetMatrixEdge( ScAddress
& rOrgPos
)
607 switch ( cMatrixFlag
)
615 if ( !GetMatrixOrigin( aOrg
) )
616 return 0; // dumm gelaufen..
617 if ( aOrg
!= rOrgPos
)
618 { // erstes Mal oder andere Matrix als letztes Mal
620 ScFormulaCell
* pFCell
;
621 if ( cMatrixFlag
== MM_REFERENCE
)
622 pFCell
= (ScFormulaCell
*) pDocument
->GetCell( aOrg
);
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
636 ScAddress
aAdr( aOrg
);
641 pCell
= pDocument
->GetCell( aAdr
);
642 if ( pCell
&& pCell
->GetCellType() == CELLTYPE_FORMULA
643 && ((ScFormulaCell
*)pCell
)->cMatrixFlag
== MM_REFERENCE
644 && GetMatrixOrigin( aTmpOrg
) && aTmpOrg
== aOrg
)
657 pCell
= pDocument
->GetCell( aAdr
);
658 if ( pCell
&& pCell
->GetCellType() == CELLTYPE_FORMULA
659 && ((ScFormulaCell
*)pCell
)->cMatrixFlag
== MM_REFERENCE
660 && GetMatrixOrigin( aTmpOrg
) && aTmpOrg
== aOrg
)
668 pFCell
->SetMatColsRows( nC
, nR
);
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() );
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();
690 if ( dC
>= 0 && dR
>= 0 && dC
< nC
&& dR
< nR
)
693 nEdges
|= 4; // linke Kante
695 nEdges
|= 16; // rechte Kante
697 nEdges
|= 8; // obere Kante
699 nEdges
|= 2; // untere Kante
701 nEdges
= 1; // mittendrin
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() );
732 USHORT
ScFormulaCell::GetErrCode()
734 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
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();
742 return aResult
.GetResultError();
745 USHORT
ScFormulaCell::GetRawError()
747 USHORT nErr
= pCode
->GetCodeError();
750 return aResult
.GetResultError();
753 BOOL
ScFormulaCell::HasOneReference( ScRange
& r
) const
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
,
764 r
.aEnd
.Set( aProv
.Ref2
.nCol
,
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.
783 // Get first reference, if any
784 ScToken
* const pFirstReference(
785 dynamic_cast<ScToken
*>(pCode
->GetNextReferenceRPN()));
788 // Collect all consecutive references, starting by the one
790 std::deque
<ScToken
*> aReferences
;
791 aReferences
.push_back(pFirstReference
);
792 FormulaToken
* pToken(pCode
->NextRPN());
793 FormulaToken
* pFunction(0);
796 if (lcl_isReference(*pToken
))
798 aReferences
.push_back(dynamic_cast<ScToken
*>(pToken
));
799 pToken
= pCode
->NextRPN();
803 if (pToken
->IsFunction())
810 if (pFunction
&& !pCode
->GetNextReferenceRPN()
811 && (pFunction
->GetParamCount() == aReferences
.size()))
813 return lcl_refListFormsOneRange(aPos
, aReferences
, rRange
);
819 BOOL
ScFormulaCell::HasRelNameReference() const
823 while ( ( t
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN()) ) != NULL
)
825 if ( t
->GetSingleRef().IsRelName() ||
826 (t
->GetType() == formula::svDoubleRef
&&
827 t
->GetDoubleRef().Ref2
.IsRelName()) )
833 BOOL
ScFormulaCell::HasColRowName() const
836 return (pCode
->GetNextColRowName() != NULL
);
839 void ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode
,
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
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
)
867 nCol
= sal::static_int_cast
<SCCOL
>( nCol
+ nDx
);
868 if ((SCsCOL
) nCol
< 0)
870 else if ( nCol
> MAXCOL
)
873 // bPosChanged = TRUE;
876 if ( nDy
&& nCol
>= nCol1
&& nCol
<= nCol2
&&
877 nTab
>= nTab1
&& nTab
<= nTab2
)
881 nRow
= sal::static_int_cast
<SCROW
>( nRow
+ nDy
);
882 if ((SCsROW
) nRow
< 0)
884 else if ( nRow
> MAXROW
)
887 // bPosChanged = TRUE;
890 if ( nDz
&& nCol
>= nCol1
&& nCol
<= nCol2
&&
891 nRow
>= nRow1
&& nRow
<= nRow2
)
895 SCTAB nMaxTab
= pDocument
->GetTableCount() - 1;
896 nTab
= sal::static_int_cast
<SCTAB
>( nTab
+ nDz
);
897 if ((SCsTAB
) nTab
< 0)
899 else if ( nTab
> nMaxTab
)
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() )
918 bHasRefs
= (pCode
->GetNextReferenceRPN() != NULL
);
919 if ( !bHasRefs
|| eUpdateRefMode
== URM_COPY
)
922 bHasColRowNames
= (pCode
->GetNextColRowName() != NULL
);
923 bHasRefs
= bHasRefs
|| bHasColRowNames
;
925 bOnRefMove
= pCode
->IsRecalcModeOnRefMove();
927 if( bHasRefs
|| bOnRefMove
)
929 ScTokenArray
* pOld
= pUndoDoc
? pCode
->Clone() : NULL
;
931 ScRangeData
* pRangeData
;
932 BOOL bRangeModified
; // any range, not only shared formula
933 BOOL bRefSizeChanged
;
936 ScCompiler
aComp(pDocument
, aPos
, *pCode
);
937 aComp
.SetGrammar(pDocument
->GetGrammar());
938 pRangeData
= aComp
.UpdateReference(eUpdateRefMode
, aOldPos
, r
,
940 bValChanged
, bRefSizeChanged
);
941 bRangeModified
= aComp
.HasModifiedRange();
947 bRangeModified
= FALSE
;
948 bRefSizeChanged
= FALSE
;
951 bOnRefMove
= (bValChanged
|| (aPos
!= aOldPos
));
952 // Cell may reference itself, e.g. ocColumn, ocRow without parameter
954 BOOL bColRowNameCompile
, bHasRelName
, bNewListening
, bInDeleteUndo
;
957 // Upon Insert ColRowNames have to be recompiled in case the
958 // insertion occurs right in front of the range.
960 (eUpdateRefMode
== URM_INSDEL
&& (nDx
> 0 || nDy
> 0));
961 if ( bColRowNameCompile
)
963 bColRowNameCompile
= FALSE
;
965 ScRangePairList
* pColList
= pDocument
->GetColNameRanges();
966 ScRangePairList
* pRowList
= pDocument
->GetRowNameRanges();
968 while ( !bColRowNameCompile
&& (t
= static_cast<ScToken
*>(pCode
->GetNextColRowName())) != NULL
)
970 ScSingleRefData
& rRef
= t
->GetSingleRef();
971 if ( nDy
> 0 && rRef
.IsColRel() )
973 rRef
.CalcAbsIfRel( aPos
);
974 ScAddress
aAdr( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
);
975 ScRangePair
* pR
= pColList
->Find( aAdr
);
978 if ( pR
->GetRange(1).aStart
.Row() == nRow1
)
979 bColRowNameCompile
= TRUE
;
983 if ( rRef
.nRow
+ 1 == nRow1
)
984 bColRowNameCompile
= TRUE
;
987 if ( nDx
> 0 && rRef
.IsRowRel() )
989 rRef
.CalcAbsIfRel( aPos
);
990 ScAddress
aAdr( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
);
991 ScRangePair
* pR
= pRowList
->Find( aAdr
);
994 if ( pR
->GetRange(1).aStart
.Col() == nCol1
)
995 bColRowNameCompile
= TRUE
;
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
);
1013 ScToken
* t
= static_cast<ScToken
*>(pCode
->GetNextColRowName());
1015 bColRowNameCompile
= TRUE
;
1016 while ( t
&& !bColRowNameCompile
)
1018 ScSingleRefData
& rRef
= t
->GetSingleRef();
1019 rRef
.CalcAbsIfRel( aPos
);
1022 ScAddress
aAdr( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
);
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
;
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
);
1057 bColRowNameCompile
= bHasRelName
= bNewListening
= bInDeleteUndo
=
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
)
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
;
1090 { // Replace shared formula with own formula
1091 pDocument
->RemoveFromFormulaTree( this ); // update formula count
1093 pCode
= pRangeData
->GetCode()->Clone();
1094 ScCompiler
aComp2(pDocument
, aPos
, *pCode
);
1095 aComp2
.SetGrammar(pDocument
->GetGrammar());
1096 aComp2
.UpdateSharedFormulaReference( eUpdateRefMode
, aOldPos
, r
,
1101 if ( ( bCompile
= (bCompile
|| bValChanged
|| bRangeModified
|| bColRowNameCompile
) ) != 0 )
1103 CompileTokenArray( bNewListening
); // kein Listening
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
);
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
);
1129 pDocument
->SetAutoCalc( bOldAutoCalc
);
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
);
1147 void ScFormulaCell::UpdateInsertTab(SCTAB nTable
)
1149 BOOL bPosChanged
= ( aPos
.Tab() >= nTable
? TRUE
: FALSE
);
1151 if( pCode
->GetNextReferenceRPN() && !pDocument
->IsClipOrUndo() )
1153 EndListeningTo( pDocument
);
1154 // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateInsertTab !
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
1164 pDocument
->RemoveFromFormulaTree( this ); // update formula count
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
);
1176 // kein StartListeningTo weil pTab[nTab] noch nicht existiert!
1178 else if ( bPosChanged
)
1182 BOOL
ScFormulaCell::UpdateDeleteTab(SCTAB nTable
, BOOL bIsMove
)
1184 BOOL bRefChanged
= FALSE
;
1185 BOOL bPosChanged
= ( aPos
.Tab() > nTable
? TRUE
: FALSE
);
1187 if( pCode
->GetNextReferenceRPN() && !pDocument
->IsClipOrUndo() )
1189 EndListeningTo( pDocument
);
1190 // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateDeleteTab !
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
1199 pDocument
->RemoveFromFormulaTree( this ); // update formula count
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
1214 // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
1216 else if ( bPosChanged
)
1222 void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos
, SCTAB nNewPos
, SCTAB nTabNo
)
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
1236 pDocument
->RemoveFromFormulaTree( this ); // update formula count
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
);
1246 // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
1249 aPos
.SetTab( nTabNo
);
1252 void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable
)
1254 if( !pDocument
->IsClipOrUndo() )
1257 ScToken
* p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
1260 ScSingleRefData
& rRef1
= p
->GetSingleRef();
1261 if( !rRef1
.IsTabRel() && (SCsTAB
) nTable
<= rRef1
.nTab
)
1263 if( p
->GetType() == formula::svDoubleRef
)
1265 ScSingleRefData
& rRef2
= p
->GetDoubleRef().Ref2
;
1266 if( !rRef2
.IsTabRel() && (SCsTAB
) nTable
<= rRef2
.nTab
)
1269 p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
1274 BOOL
ScFormulaCell::TestTabRefAbs(SCTAB nTable
)
1277 if( !pDocument
->IsClipOrUndo() )
1280 ScToken
* p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
1283 ScSingleRefData
& rRef1
= p
->GetSingleRef();
1284 if( !rRef1
.IsTabRel() )
1286 if( (SCsTAB
) nTable
!= rRef1
.nTab
)
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
)
1298 else if (nTable
!= aPos
.Tab())
1299 rRef2
.nTab
= aPos
.Tab();
1302 p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
1308 void ScFormulaCell::UpdateCompile( BOOL bForceIfNameInUse
)
1310 if ( bForceIfNameInUse
&& !bCompile
)
1311 bCompile
= pCode
->HasNameOrColRowName();
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
;
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()) )
1335 nTemp
= rRef1
.nRelCol
;
1336 rRef1
.nRelCol
= static_cast<SCCOL
>(rRef1
.nRelRow
);
1337 rRef1
.nRelRow
= static_cast<SCROW
>(nTemp
);
1341 nTemp
= rRef2
.nRelCol
;
1342 rRef2
.nRelCol
= static_cast<SCCOL
>(rRef2
.nRelRow
);
1343 rRef2
.nRelRow
= static_cast<SCROW
>(nTemp
);
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
);
1378 ScTokenArray
* pOld
= pUndoDoc
? pCode
->Clone() : NULL
;
1379 BOOL bRefChanged
= FALSE
;
1382 ScRangeData
* pShared
= NULL
;
1384 while( (t
= static_cast<ScToken
*>(pCode
->GetNextReferenceOrName())) != NULL
)
1386 if( t
->GetOpCode() == ocName
)
1388 ScRangeData
* pName
= pDocument
->GetRangeName()->FindIndex( t
->GetIndex() );
1391 if (pName
->IsModified())
1393 if (pName
->HasType(RT_SHAREDMOD
))
1397 else if( t
->GetType() != svIndex
)
1399 t
->CalcAbsIfRel( aOldPos
);
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
);
1409 t
->CalcRelFromAbs( aPos
);
1415 if (pShared
) // Shared Formula gegen echte Formel austauschen
1417 pDocument
->RemoveFromFormulaTree( this ); // update formula count
1419 pCode
= new ScTokenArray( *pShared
->GetCode() );
1422 while( (t
= static_cast<ScToken
*>(pCode
->GetNextReference())) != NULL
)
1424 if( t
->GetType() != svIndex
)
1426 t
->CalcAbsIfRel( aOldPos
);
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
);
1435 t
->CalcRelFromAbs( aPos
);
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
);
1451 CompileTokenArray(); // ruft auch StartListeningTo
1455 StartListeningTo( pDocument
); // Listener wie vorher
1460 void ScFormulaCell::UpdateGrow( const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
)
1462 EndListeningTo( pDocument
);
1464 BOOL bRefChanged
= FALSE
;
1466 ScRangeData
* pShared
= NULL
;
1469 while( (t
= static_cast<ScToken
*>(pCode
->GetNextReferenceOrName())) != NULL
)
1471 if( t
->GetOpCode() == ocName
)
1473 ScRangeData
* pName
= pDocument
->GetRangeName()->FindIndex( t
->GetIndex() );
1476 if (pName
->IsModified())
1478 if (pName
->HasType(RT_SHAREDMOD
))
1482 else if( t
->GetType() != svIndex
)
1484 t
->CalcAbsIfRel( aPos
);
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
);
1494 t
->CalcRelFromAbs( aPos
);
1500 if (pShared
) // Shared Formula gegen echte Formel austauschen
1502 pDocument
->RemoveFromFormulaTree( this ); // update formula count
1504 pCode
= new ScTokenArray( *pShared
->GetCode() );
1507 while( (t
= static_cast<ScToken
*>(pCode
->GetNextReference())) != NULL
)
1509 if( t
->GetType() != svIndex
)
1511 t
->CalcAbsIfRel( aPos
);
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
);
1520 t
->CalcRelFromAbs( aPos
);
1528 CompileTokenArray(); // ruft auch StartListeningTo
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
)
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
))
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());
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
);
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
);
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
) )
1629 CompileTokenArray();
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
;
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
1655 if ( p
->GetIndex() >= SC_START_INDEX_DB_COLL
)
1656 bRecompile
= TRUE
; // DB-Bereich
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 );
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
);
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
;
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
1705 if ( p
->GetType() == svIndex
)
1706 bRecompile
= TRUE
; // RangeName
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 );
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
);
1734 void ScFormulaCell::CompileColRowNameFormula()
1737 for ( FormulaToken
* p
= pCode
->First(); p
; p
= pCode
->Next() )
1739 if ( p
->GetOpCode() == ocColRowName
)
1742 CompileTokenArray();
1749 // ============================================================================