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 "externalrefmgr.hxx"
57 #include "scitems.hxx"
58 #include "patattr.hxx"
60 using namespace formula
;
62 // STATIC DATA -----------------------------------------------------------
65 const USHORT nMemPoolEditCell
= (0x1000 - 64) / sizeof(ScNoteCell
);
66 IMPL_FIXEDMEMPOOL_NEWDEL( ScEditCell
, nMemPoolEditCell
, nMemPoolEditCell
)
69 // ============================================================================
71 ScEditCell::ScEditCell( const EditTextObject
* pObject
, ScDocument
* pDocP
,
72 const SfxItemPool
* pFromPool
) :
73 ScBaseCell( CELLTYPE_EDIT
),
77 SetTextObject( pObject
, pFromPool
);
80 ScEditCell::ScEditCell( const ScEditCell
& rCell
, ScDocument
& rDoc
) :
85 SetTextObject( rCell
.pData
, rCell
.pDoc
->GetEditPool() );
88 ScEditCell::ScEditCell( const String
& rString
, ScDocument
* pDocP
) :
89 ScBaseCell( CELLTYPE_EDIT
),
93 DBG_ASSERT( rString
.Search('\n') != STRING_NOTFOUND
||
94 rString
.Search(CHAR_CR
) != STRING_NOTFOUND
,
95 "EditCell mit einfachem Text !?!?" );
97 EditEngine
& rEngine
= pDoc
->GetEditEngine();
98 rEngine
.SetText( rString
);
99 pData
= rEngine
.CreateTextObject();
102 ScEditCell::~ScEditCell()
108 eCellType
= CELLTYPE_DESTROYED
;
112 void ScEditCell::SetData( const EditTextObject
* pObject
,
113 const SfxItemPool
* pFromPool
)
121 SetTextObject( pObject
, pFromPool
);
124 void ScEditCell::GetData( const EditTextObject
*& rpObject
) const
129 void ScEditCell::GetString( String
& rString
) const
135 // auch Text von URL-Feldern, Doc-Engine ist eine ScFieldEditEngine
136 EditEngine
& rEngine
= pDoc
->GetEditEngine();
137 rEngine
.SetText( *pData
);
138 rString
= ScEditUtil::GetMultilineString(rEngine
); // string with line separators between paragraphs
139 // cache short strings for formulas
140 if ( rString
.Len() < 256 )
141 ((ScEditCell
*)this)->pString
= new String( rString
); //! non-const
147 void ScEditCell::RemoveCharAttribs( const ScPatternAttr
& rAttr
)
153 { ATTR_FONT
, EE_CHAR_FONTINFO
},
154 { ATTR_FONT_HEIGHT
, EE_CHAR_FONTHEIGHT
},
155 { ATTR_FONT_WEIGHT
, EE_CHAR_WEIGHT
},
156 { ATTR_FONT_COLOR
, EE_CHAR_COLOR
}
158 USHORT nMapCount
= sizeof(AttrTypeMap
) / sizeof(AttrTypeMap
[0]);
160 const SfxItemSet
& rSet
= rAttr
.GetItemSet();
161 const SfxPoolItem
* pItem
;
162 for (USHORT i
= 0; i
< nMapCount
; ++i
)
164 if ( rSet
.GetItemState(AttrTypeMap
[i
].nAttrType
, false, &pItem
) == SFX_ITEM_SET
)
165 pData
->RemoveCharAttribs(AttrTypeMap
[i
].nCharType
);
169 void ScEditCell::SetTextObject( const EditTextObject
* pObject
,
170 const SfxItemPool
* pFromPool
)
174 if ( pFromPool
&& pDoc
->GetEditPool() == pFromPool
)
175 pData
= pObject
->Clone();
178 // Leider gibt es keinen anderen Weg, um den Pool umzuhaengen,
179 // als das Object durch eine entsprechende Engine zu schleusen..
180 EditEngine
& rEngine
= pDoc
->GetEditEngine();
181 if ( pObject
->HasOnlineSpellErrors() )
183 ULONG nControl
= rEngine
.GetControlWord();
184 const ULONG nSpellControl
= EE_CNTRL_ONLINESPELLING
| EE_CNTRL_ALLOWBIGOBJS
;
185 BOOL bNewControl
= ( (nControl
& nSpellControl
) != nSpellControl
);
187 rEngine
.SetControlWord( nControl
| nSpellControl
);
188 rEngine
.SetText( *pObject
);
189 pData
= rEngine
.CreateTextObject();
191 rEngine
.SetControlWord( nControl
);
195 rEngine
.SetText( *pObject
);
196 pData
= rEngine
.CreateTextObject();
204 ScEditDataArray::ScEditDataArray()
208 ScEditDataArray::~ScEditDataArray()
212 void ScEditDataArray::AddItem(SCTAB nTab
, SCCOL nCol
, SCROW nRow
,
213 EditTextObject
* pOldData
, EditTextObject
* pNewData
)
215 maArray
.push_back(Item(nTab
, nCol
, nRow
, pOldData
, pNewData
));
218 const ScEditDataArray::Item
* ScEditDataArray::First()
220 maIter
= maArray
.begin();
221 if (maIter
== maArray
.end())
226 const ScEditDataArray::Item
* ScEditDataArray::Next()
228 if (maIter
== maArray
.end())
233 // ============================================================================
235 ScEditDataArray::Item::Item(SCTAB nTab
, SCCOL nCol
, SCROW nRow
,
236 EditTextObject
* pOldData
, EditTextObject
* pNewData
) :
241 mpOldData
.reset(pOldData
);
242 mpNewData
.reset(pNewData
);
245 ScEditDataArray::Item::~Item()
249 const EditTextObject
* ScEditDataArray::Item::GetOldData() const
251 return mpOldData
.get();
254 const EditTextObject
* ScEditDataArray::Item::GetNewData() const
256 return mpNewData
.get();
259 SCTAB
ScEditDataArray::Item::GetTab() const
264 SCCOL
ScEditDataArray::Item::GetCol() const
269 SCROW
ScEditDataArray::Item::GetRow() const
274 // ============================================================================
281 typedef SCCOLROW(*DimensionSelector
)(const ScSingleRefData
&);
284 static SCCOLROW
lcl_GetCol(const ScSingleRefData
& rData
)
290 static SCCOLROW
lcl_GetRow(const ScSingleRefData
& rData
)
296 static SCCOLROW
lcl_GetTab(const ScSingleRefData
& rData
)
302 /** Check if both references span the same range in selected dimension.
305 lcl_checkRangeDimension(
306 const SingleDoubleRefProvider
& rRef1
,
307 const SingleDoubleRefProvider
& rRef2
,
308 const DimensionSelector aWhich
)
311 aWhich(rRef1
.Ref1
) == aWhich(rRef2
.Ref1
)
312 && aWhich(rRef1
.Ref2
) == aWhich(rRef2
.Ref2
);
317 lcl_checkRangeDimensions(
318 const SingleDoubleRefProvider
& rRef1
,
319 const SingleDoubleRefProvider
& rRef2
,
320 bool& bCol
, bool& bRow
, bool& bTab
)
322 const bool bSameCols(lcl_checkRangeDimension(rRef1
, rRef2
, lcl_GetCol
));
323 const bool bSameRows(lcl_checkRangeDimension(rRef1
, rRef2
, lcl_GetRow
));
324 const bool bSameTabs(lcl_checkRangeDimension(rRef1
, rRef2
, lcl_GetTab
));
326 // Test if exactly two dimensions are equal
327 if (!(bSameCols
^ bSameRows
^ bSameTabs
)
328 && (bSameCols
|| bSameRows
|| bSameTabs
))
339 /** Check if references in given reference list can possibly
340 form a range. To do that, two of their dimensions must be the same.
343 lcl_checkRangeDimensions(
344 const deque
<ScToken
*>::const_iterator aBegin
,
345 const deque
<ScToken
*>::const_iterator aEnd
,
346 bool& bCol
, bool& bRow
, bool& bTab
)
348 deque
<ScToken
*>::const_iterator
aCur(aBegin
);
350 const SingleDoubleRefProvider
aRef(**aBegin
);
353 const SingleDoubleRefProvider
aRefCur(**aCur
);
354 bOk
= lcl_checkRangeDimensions(aRef
, aRefCur
, bCol
, bRow
, bTab
);
356 while (bOk
&& aCur
!= aEnd
)
358 const SingleDoubleRefProvider
aRefCur(**aCur
);
362 bOk
= lcl_checkRangeDimensions(aRef
, aRefCur
, bColTmp
, bRowTmp
, bTabTmp
);
363 bOk
= bOk
&& (bCol
== bColTmp
&& bRow
== bRowTmp
&& bTab
== bTabTmp
);
367 if (bOk
&& aCur
== aEnd
)
380 const ScToken
* const pRef1
, const ScToken
* const pRef2
,
381 const DimensionSelector aWhich
)
383 const SingleDoubleRefProvider
rRef1(*pRef1
);
384 const SingleDoubleRefProvider
rRef2(*pRef2
);
385 return aWhich(rRef1
.Ref1
) < aWhich(rRef2
.Ref1
);
389 /** Returns true if range denoted by token pRef2 starts immediately after
390 range denoted by token pRef1. Dimension, in which the comparison takes
391 place, is given by aWhich.
394 lcl_isImmediatelyFollowing(
395 const ScToken
* const pRef1
, const ScToken
* const pRef2
,
396 const DimensionSelector aWhich
)
398 const SingleDoubleRefProvider
rRef1(*pRef1
);
399 const SingleDoubleRefProvider
rRef2(*pRef2
);
400 return aWhich(rRef2
.Ref1
) - aWhich(rRef1
.Ref2
) == 1;
406 const deque
<ScToken
*>& rReferences
,
407 const DimensionSelector aWhich
)
409 typedef deque
<ScToken
*>::const_iterator Iter
;
410 Iter
aBegin(rReferences
.begin());
411 Iter
aEnd(rReferences
.end());
412 Iter
aBegin1(aBegin
);
415 aBegin
, aEnd
, aBegin1
,
416 boost::bind(lcl_isImmediatelyFollowing
, _1
, _2
, aWhich
));
421 lcl_fillRangeFromRefList(
422 const deque
<ScToken
*>& rReferences
, ScRange
& rRange
)
424 const ScSingleRefData
aStart(
425 SingleDoubleRefProvider(*rReferences
.front()).Ref1
);
426 rRange
.aStart
.Set(aStart
.nCol
, aStart
.nRow
, aStart
.nTab
);
427 const ScSingleRefData
aEnd(
428 SingleDoubleRefProvider(*rReferences
.back()).Ref2
);
429 rRange
.aEnd
.Set(aEnd
.nCol
, aEnd
.nRow
, aEnd
.nTab
);
434 lcl_refListFormsOneRange(
435 const ScAddress
& aPos
, deque
<ScToken
*>& rReferences
,
439 rReferences
.begin(), rReferences
.end(),
440 bind(&ScToken::CalcAbsIfRel
, _1
, aPos
))
442 if (rReferences
.size() == 1) {
443 lcl_fillRangeFromRefList(rReferences
, rRange
);
450 if (lcl_checkRangeDimensions(rReferences
.begin(), rReferences
.end(),
453 DimensionSelector aWhich
;
468 OSL_ENSURE(false, "lcl_checkRangeDimensions shouldn't allow that!");
469 aWhich
= lcl_GetRow
; // initialize to avoid warning
471 // Sort the references by start of range
472 std::sort(rReferences
.begin(), rReferences
.end(),
473 boost::bind(lcl_lessReferenceBy
, _1
, _2
, aWhich
));
474 if (lcl_checkIfAdjacent(rReferences
, aWhich
))
476 lcl_fillRangeFromRefList(rReferences
, rRange
);
484 bool lcl_isReference(const FormulaToken
& rToken
)
487 rToken
.GetType() == svSingleRef
||
488 rToken
.GetType() == svDoubleRef
;
493 BOOL
ScFormulaCell::IsEmpty()
495 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
497 return aResult
.GetCellResultType() == formula::svEmptyCell
;
500 BOOL
ScFormulaCell::IsEmptyDisplayedAsString()
502 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
504 return aResult
.IsEmptyDisplayedAsString();
507 BOOL
ScFormulaCell::IsValue()
509 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
511 return aResult
.IsValue();
514 double ScFormulaCell::GetValue()
516 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
518 if ((!pCode
->GetCodeError() || pCode
->GetCodeError() == errDoubleRef
) &&
519 !aResult
.GetResultError())
520 return aResult
.GetDouble();
524 double ScFormulaCell::GetValueAlways()
526 // for goal seek: return result value even if error code is set
528 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
530 return aResult
.GetDouble();
533 void ScFormulaCell::GetString( String
& rString
)
535 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
537 if ((!pCode
->GetCodeError() || pCode
->GetCodeError() == errDoubleRef
) &&
538 !aResult
.GetResultError())
539 rString
= aResult
.GetString();
544 const ScMatrix
* ScFormulaCell::GetMatrix()
546 if ( pDocument
->GetAutoCalc() )
548 // Was stored !bDirty but an accompanying matrix cell was bDirty?
549 // => we need to get the matrix.
550 if (!bDirty
&& cMatrixFlag
== MM_FORMULA
&& !aResult
.GetMatrix().Is())
552 if ( IsDirtyOrInTableOpDirty() )
555 return aResult
.GetMatrix();
558 BOOL
ScFormulaCell::GetMatrixOrigin( ScAddress
& rPos
) const
560 switch ( cMatrixFlag
)
569 ScToken
* t
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
572 ScSingleRefData
& rRef
= t
->GetSingleRef();
573 rRef
.CalcAbsIfRel( aPos
);
576 rPos
.Set( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
);
596 (reserviert: offen: 32)
599 USHORT
ScFormulaCell::GetMatrixEdge( ScAddress
& rOrgPos
)
601 switch ( cMatrixFlag
)
609 if ( !GetMatrixOrigin( aOrg
) )
610 return 0; // dumm gelaufen..
611 if ( aOrg
!= rOrgPos
)
612 { // erstes Mal oder andere Matrix als letztes Mal
614 ScFormulaCell
* pFCell
;
615 if ( cMatrixFlag
== MM_REFERENCE
)
616 pFCell
= (ScFormulaCell
*) pDocument
->GetCell( aOrg
);
618 pFCell
= this; // this MM_FORMULA
619 // this gibt's nur einmal, kein Vergleich auf pFCell==this
620 if ( pFCell
&& pFCell
->GetCellType() == CELLTYPE_FORMULA
621 && pFCell
->cMatrixFlag
== MM_FORMULA
)
623 pFCell
->GetMatColsRows( nC
, nR
);
624 if ( nC
== 0 || nR
== 0 )
625 { // aus altem Dokument geladen, neu erzeugen
630 ScAddress
aAdr( aOrg
);
635 pCell
= pDocument
->GetCell( aAdr
);
636 if ( pCell
&& pCell
->GetCellType() == CELLTYPE_FORMULA
637 && ((ScFormulaCell
*)pCell
)->cMatrixFlag
== MM_REFERENCE
638 && GetMatrixOrigin( aTmpOrg
) && aTmpOrg
== aOrg
)
651 pCell
= pDocument
->GetCell( aAdr
);
652 if ( pCell
&& pCell
->GetCellType() == CELLTYPE_FORMULA
653 && ((ScFormulaCell
*)pCell
)->cMatrixFlag
== MM_REFERENCE
654 && GetMatrixOrigin( aTmpOrg
) && aTmpOrg
== aOrg
)
662 pFCell
->SetMatColsRows( nC
, nR
);
669 ByteString
aMsg( "broken Matrix, no MatFormula at origin, Pos: " );
670 aPos
.Format( aTmp
, SCA_VALID_COL
| SCA_VALID_ROW
, pDocument
);
671 aMsg
+= ByteString( aTmp
, RTL_TEXTENCODING_ASCII_US
);
672 aMsg
+= ", MatOrg: ";
673 aOrg
.Format( aTmp
, SCA_VALID_COL
| SCA_VALID_ROW
, pDocument
);
674 aMsg
+= ByteString( aTmp
, RTL_TEXTENCODING_ASCII_US
);
675 DBG_ERRORFILE( aMsg
.GetBuffer() );
677 return 0; // bad luck ...
680 // here we are, healthy and clean, somewhere in between
681 SCsCOL dC
= aPos
.Col() - aOrg
.Col();
682 SCsROW dR
= aPos
.Row() - aOrg
.Row();
684 if ( dC
>= 0 && dR
>= 0 && dC
< nC
&& dR
< nR
)
687 nEdges
|= 4; // linke Kante
689 nEdges
|= 16; // rechte Kante
691 nEdges
|= 8; // obere Kante
693 nEdges
|= 2; // untere Kante
695 nEdges
= 1; // mittendrin
701 ByteString
aMsg( "broken Matrix, Pos: " );
702 aPos
.Format( aTmp
, SCA_VALID_COL
| SCA_VALID_ROW
, pDocument
);
703 aMsg
+= ByteString( aTmp
, RTL_TEXTENCODING_ASCII_US
);
704 aMsg
+= ", MatOrg: ";
705 aOrg
.Format( aTmp
, SCA_VALID_COL
| SCA_VALID_ROW
, pDocument
);
706 aMsg
+= ByteString( aTmp
, RTL_TEXTENCODING_ASCII_US
);
707 aMsg
+= ", MatCols: ";
708 aMsg
+= ByteString::CreateFromInt32( nC
);
709 aMsg
+= ", MatRows: ";
710 aMsg
+= ByteString::CreateFromInt32( nR
);
711 aMsg
+= ", DiffCols: ";
712 aMsg
+= ByteString::CreateFromInt32( dC
);
713 aMsg
+= ", DiffRows: ";
714 aMsg
+= ByteString::CreateFromInt32( dR
);
715 DBG_ERRORFILE( aMsg
.GetBuffer() );
726 USHORT
ScFormulaCell::GetErrCode()
728 if (IsDirtyOrInTableOpDirty() && pDocument
->GetAutoCalc())
730 /* FIXME: If ScTokenArray::SetCodeError() was really only for code errors
731 * and not also abused for signaling other error conditions we could bail
732 * out even before attempting to interpret broken code. */
733 USHORT nErr
= pCode
->GetCodeError();
736 return aResult
.GetResultError();
739 USHORT
ScFormulaCell::GetRawError()
741 USHORT nErr
= pCode
->GetCodeError();
744 return aResult
.GetResultError();
747 BOOL
ScFormulaCell::HasOneReference( ScRange
& r
) const
750 ScToken
* p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
751 if( p
&& !pCode
->GetNextReferenceRPN() ) // nur eine!
753 p
->CalcAbsIfRel( aPos
);
754 SingleDoubleRefProvider
aProv( *p
);
755 r
.aStart
.Set( aProv
.Ref1
.nCol
,
758 r
.aEnd
.Set( aProv
.Ref2
.nCol
,
768 ScFormulaCell::HasRefListExpressibleAsOneReference(ScRange
& rRange
) const
770 /* If there appears just one reference in the formula, it's the same
771 as HasOneReference(). If there are more of them, they can denote
772 one range if they are (sole) arguments of one function.
773 Union of these references must form one range and their
774 intersection must be empty set.
777 // Get first reference, if any
778 ScToken
* const pFirstReference(
779 dynamic_cast<ScToken
*>(pCode
->GetNextReferenceRPN()));
782 // Collect all consecutive references, starting by the one
784 std::deque
<ScToken
*> aReferences
;
785 aReferences
.push_back(pFirstReference
);
786 FormulaToken
* pToken(pCode
->NextRPN());
787 FormulaToken
* pFunction(0);
790 if (lcl_isReference(*pToken
))
792 aReferences
.push_back(dynamic_cast<ScToken
*>(pToken
));
793 pToken
= pCode
->NextRPN();
797 if (pToken
->IsFunction())
804 if (pFunction
&& !pCode
->GetNextReferenceRPN()
805 && (pFunction
->GetParamCount() == aReferences
.size()))
807 return lcl_refListFormsOneRange(aPos
, aReferences
, rRange
);
813 BOOL
ScFormulaCell::HasRelNameReference() const
817 while ( ( t
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN()) ) != NULL
)
819 if ( t
->GetSingleRef().IsRelName() ||
820 (t
->GetType() == formula::svDoubleRef
&&
821 t
->GetDoubleRef().Ref2
.IsRelName()) )
827 BOOL
ScFormulaCell::HasColRowName() const
830 return (pCode
->GetNextColRowName() != NULL
);
833 void ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode
,
835 SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
,
836 ScDocument
* pUndoDoc
, const ScAddress
* pUndoCellPos
)
838 SCCOL nCol1
= r
.aStart
.Col();
839 SCROW nRow1
= r
.aStart
.Row();
840 SCTAB nTab1
= r
.aStart
.Tab();
841 SCCOL nCol2
= r
.aEnd
.Col();
842 SCROW nRow2
= r
.aEnd
.Row();
843 SCTAB nTab2
= r
.aEnd
.Tab();
844 SCCOL nCol
= aPos
.Col();
845 SCROW nRow
= aPos
.Row();
846 SCTAB nTab
= aPos
.Tab();
847 ScAddress
aUndoPos( aPos
); // position for undo cell in pUndoDoc
849 aUndoPos
= *pUndoCellPos
;
850 ScAddress
aOldPos( aPos
);
851 // BOOL bPosChanged = FALSE; // ob diese Zelle bewegt wurde
852 BOOL bIsInsert
= FALSE
;
853 if (eUpdateRefMode
== URM_INSDEL
)
855 bIsInsert
= (nDx
>= 0 && nDy
>= 0 && nDz
>= 0);
856 if ( nDx
&& nRow
>= nRow1
&& nRow
<= nRow2
&&
857 nTab
>= nTab1
&& nTab
<= nTab2
)
861 nCol
= sal::static_int_cast
<SCCOL
>( nCol
+ nDx
);
862 if ((SCsCOL
) nCol
< 0)
864 else if ( nCol
> MAXCOL
)
867 // bPosChanged = TRUE;
870 if ( nDy
&& nCol
>= nCol1
&& nCol
<= nCol2
&&
871 nTab
>= nTab1
&& nTab
<= nTab2
)
875 nRow
= sal::static_int_cast
<SCROW
>( nRow
+ nDy
);
876 if ((SCsROW
) nRow
< 0)
878 else if ( nRow
> MAXROW
)
881 // bPosChanged = TRUE;
884 if ( nDz
&& nCol
>= nCol1
&& nCol
<= nCol2
&&
885 nRow
>= nRow1
&& nRow
<= nRow2
)
889 SCTAB nMaxTab
= pDocument
->GetTableCount() - 1;
890 nTab
= sal::static_int_cast
<SCTAB
>( nTab
+ nDz
);
891 if ((SCsTAB
) nTab
< 0)
893 else if ( nTab
> nMaxTab
)
896 // bPosChanged = TRUE;
900 else if ( r
.In( aPos
) )
902 aOldPos
.Set( nCol
- nDx
, nRow
- nDy
, nTab
- nDz
);
903 // bPosChanged = TRUE;
906 BOOL bHasRefs
= FALSE
;
907 BOOL bHasColRowNames
= FALSE
;
908 BOOL bOnRefMove
= FALSE
;
909 if ( !pDocument
->IsClipOrUndo() )
912 bHasRefs
= (pCode
->GetNextReferenceRPN() != NULL
);
913 if ( !bHasRefs
|| eUpdateRefMode
== URM_COPY
)
916 bHasColRowNames
= (pCode
->GetNextColRowName() != NULL
);
917 bHasRefs
= bHasRefs
|| bHasColRowNames
;
919 bOnRefMove
= pCode
->IsRecalcModeOnRefMove();
921 if( bHasRefs
|| bOnRefMove
)
923 ScTokenArray
* pOld
= pUndoDoc
? pCode
->Clone() : NULL
;
925 ScRangeData
* pRangeData
;
926 BOOL bRangeModified
; // any range, not only shared formula
927 BOOL bRefSizeChanged
;
930 ScCompiler
aComp(pDocument
, aPos
, *pCode
);
931 aComp
.SetGrammar(pDocument
->GetGrammar());
932 pRangeData
= aComp
.UpdateReference(eUpdateRefMode
, aOldPos
, r
,
934 bValChanged
, bRefSizeChanged
);
935 bRangeModified
= aComp
.HasModifiedRange();
941 bRangeModified
= FALSE
;
942 bRefSizeChanged
= FALSE
;
945 bOnRefMove
= (bValChanged
|| (aPos
!= aOldPos
));
946 // Cell may reference itself, e.g. ocColumn, ocRow without parameter
948 BOOL bColRowNameCompile
, bHasRelName
, bNewListening
, bInDeleteUndo
;
951 // Upon Insert ColRowNames have to be recompiled in case the
952 // insertion occurs right in front of the range.
954 (eUpdateRefMode
== URM_INSDEL
&& (nDx
> 0 || nDy
> 0));
955 if ( bColRowNameCompile
)
957 bColRowNameCompile
= FALSE
;
959 ScRangePairList
* pColList
= pDocument
->GetColNameRanges();
960 ScRangePairList
* pRowList
= pDocument
->GetRowNameRanges();
962 while ( !bColRowNameCompile
&& (t
= static_cast<ScToken
*>(pCode
->GetNextColRowName())) != NULL
)
964 ScSingleRefData
& rRef
= t
->GetSingleRef();
965 if ( nDy
> 0 && rRef
.IsColRel() )
967 rRef
.CalcAbsIfRel( aPos
);
968 ScAddress
aAdr( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
);
969 ScRangePair
* pR
= pColList
->Find( aAdr
);
972 if ( pR
->GetRange(1).aStart
.Row() == nRow1
)
973 bColRowNameCompile
= TRUE
;
977 if ( rRef
.nRow
+ 1 == nRow1
)
978 bColRowNameCompile
= TRUE
;
981 if ( nDx
> 0 && rRef
.IsRowRel() )
983 rRef
.CalcAbsIfRel( aPos
);
984 ScAddress
aAdr( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
);
985 ScRangePair
* pR
= pRowList
->Find( aAdr
);
988 if ( pR
->GetRange(1).aStart
.Col() == nCol1
)
989 bColRowNameCompile
= TRUE
;
993 if ( rRef
.nCol
+ 1 == nCol1
)
994 bColRowNameCompile
= TRUE
;
999 else if ( eUpdateRefMode
== URM_MOVE
)
1000 { // bei Move/D&D neu kompilieren wenn ColRowName verschoben wurde
1001 // oder diese Zelle auf einen zeigt und verschoben wurde
1002 bColRowNameCompile
= bCompile
; // evtl. aus Copy-ctor
1003 if ( !bColRowNameCompile
)
1005 BOOL bMoved
= (aPos
!= aOldPos
);
1007 ScToken
* t
= static_cast<ScToken
*>(pCode
->GetNextColRowName());
1009 bColRowNameCompile
= TRUE
;
1010 while ( t
&& !bColRowNameCompile
)
1012 ScSingleRefData
& rRef
= t
->GetSingleRef();
1013 rRef
.CalcAbsIfRel( aPos
);
1016 ScAddress
aAdr( rRef
.nCol
, rRef
.nRow
, rRef
.nTab
);
1018 bColRowNameCompile
= TRUE
;
1020 t
= static_cast<ScToken
*>(pCode
->GetNextColRowName());
1024 else if ( eUpdateRefMode
== URM_COPY
&& bHasColRowNames
&& bValChanged
)
1026 bColRowNameCompile
= TRUE
;
1028 ScChangeTrack
* pChangeTrack
= pDocument
->GetChangeTrack();
1029 if ( pChangeTrack
&& pChangeTrack
->IsInDeleteUndo() )
1030 bInDeleteUndo
= TRUE
;
1032 bInDeleteUndo
= FALSE
;
1033 // RelNameRefs are always moved
1034 bHasRelName
= HasRelNameReference();
1035 // Reference changed and new listening needed?
1036 // Except in Insert/Delete without specialties.
1037 bNewListening
= (bRangeModified
|| pRangeData
|| bColRowNameCompile
1038 || (bValChanged
&& (eUpdateRefMode
!= URM_INSDEL
||
1039 bInDeleteUndo
|| bRefSizeChanged
)) ||
1040 (bHasRelName
&& eUpdateRefMode
!= URM_COPY
))
1041 // #i36299# Don't duplicate action during cut&paste / drag&drop
1042 // on a cell in the range moved, start/end listeners is done
1043 // via ScDocument::DeleteArea() and ScDocument::CopyFromClip().
1044 && !(eUpdateRefMode
== URM_MOVE
&&
1045 pDocument
->IsInsertingFromOtherDoc() && r
.In(aPos
));
1046 if ( bNewListening
)
1047 EndListeningTo( pDocument
, pOld
, aOldPos
);
1051 bColRowNameCompile
= bHasRelName
= bNewListening
= bInDeleteUndo
=
1056 // NeedDirty bei Aenderungen ausser Copy und Move/Insert ohne RelNames
1057 if ( bRangeModified
|| pRangeData
|| bColRowNameCompile
||
1058 (bValChanged
&& eUpdateRefMode
!= URM_COPY
&&
1059 (eUpdateRefMode
!= URM_MOVE
|| bHasRelName
) &&
1060 (!bIsInsert
|| bHasRelName
|| bInDeleteUndo
||
1061 bRefSizeChanged
)) || bOnRefMove
)
1065 if (pUndoDoc
&& (bValChanged
|| pRangeData
|| bOnRefMove
))
1067 // Copy the cell to aUndoPos, which is its current position in the document,
1068 // so this works when UpdateReference is called before moving the cells
1069 // (InsertCells/DeleteCells - aPos is changed above) as well as when UpdateReference
1070 // is called after moving the cells (MoveBlock/PasteFromClip - aOldPos is changed).
1072 // If there is already a formula cell in the undo document, don't overwrite it,
1073 // the first (oldest) is the important cell.
1074 if ( pUndoDoc
->GetCellType( aUndoPos
) != CELLTYPE_FORMULA
)
1076 ScFormulaCell
* pFCell
= new ScFormulaCell( pUndoDoc
, aUndoPos
,
1077 pOld
, eTempGrammar
, cMatrixFlag
);
1078 pFCell
->aResult
.SetToken( NULL
); // to recognize it as changed later (Cut/Paste!)
1079 pUndoDoc
->PutCell( aUndoPos
, pFCell
);
1082 bValChanged
= FALSE
;
1084 { // Replace shared formula with own formula
1085 pDocument
->RemoveFromFormulaTree( this ); // update formula count
1087 pCode
= pRangeData
->GetCode()->Clone();
1088 ScCompiler
aComp2(pDocument
, aPos
, *pCode
);
1089 aComp2
.SetGrammar(pDocument
->GetGrammar());
1090 aComp2
.UpdateSharedFormulaReference( eUpdateRefMode
, aOldPos
, r
,
1095 if ( ( bCompile
= (bCompile
|| bValChanged
|| bRangeModified
|| bColRowNameCompile
) ) != 0 )
1097 CompileTokenArray( bNewListening
); // kein Listening
1100 if ( !bInDeleteUndo
)
1101 { // In ChangeTrack Delete-Reject listeners are established in
1102 // InsertCol/InsertRow
1103 if ( bNewListening
)
1105 if ( eUpdateRefMode
== URM_INSDEL
)
1107 // Inserts/Deletes re-establish listeners after all
1108 // UpdateReference calls.
1109 // All replaced shared formula listeners have to be
1110 // established after an Insert or Delete. Do nothing here.
1111 SetNeedsListening( TRUE
);
1114 StartListeningTo( pDocument
);
1117 if ( bNeedDirty
&& (!(eUpdateRefMode
== URM_INSDEL
&& bHasRelName
) || pRangeData
) )
1118 { // Referenzen abgeschnitten, ungueltig o.ae.?
1119 BOOL bOldAutoCalc
= pDocument
->GetAutoCalc();
1120 // kein Interpret in SubMinimalRecalc wegen evtl. falscher Referenzen
1121 pDocument
->SetAutoCalc( FALSE
);
1123 pDocument
->SetAutoCalc( bOldAutoCalc
);
1130 for ( formula::FormulaToken
* t
= pCode
->GetNextReferenceOrName(); t
; t
= pCode
->GetNextReferenceOrName() )
1132 StackVar sv
= t
->GetType();
1133 if (sv
== svExternalSingleRef
|| sv
== svExternalDoubleRef
|| sv
== svExternalName
)
1135 pDocument
->GetExternalRefManager()->updateRefCell(aOldPos
, aPos
, eUpdateRefMode
== URM_COPY
);
1141 void ScFormulaCell::UpdateInsertTab(SCTAB nTable
)
1143 BOOL bPosChanged
= ( aPos
.Tab() >= nTable
? TRUE
: FALSE
);
1145 if( pCode
->GetNextReferenceRPN() && !pDocument
->IsClipOrUndo() )
1147 EndListeningTo( pDocument
);
1148 // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateInsertTab !
1151 ScRangeData
* pRangeData
;
1152 ScCompiler
aComp(pDocument
, aPos
, *pCode
);
1153 aComp
.SetGrammar(pDocument
->GetGrammar());
1154 pRangeData
= aComp
.UpdateInsertTab( nTable
, FALSE
);
1155 if (pRangeData
) // Shared Formula gegen echte Formel
1158 pDocument
->RemoveFromFormulaTree( this ); // update formula count
1160 pCode
= new ScTokenArray( *pRangeData
->GetCode() );
1161 ScCompiler
aComp2(pDocument
, aPos
, *pCode
);
1162 aComp2
.SetGrammar(pDocument
->GetGrammar());
1163 aComp2
.MoveRelWrap(pRangeData
->GetMaxCol(), pRangeData
->GetMaxRow());
1164 aComp2
.UpdateInsertTab( nTable
, FALSE
);
1165 // If the shared formula contained a named range/formula containing
1166 // an absolute reference to a sheet, those have to be readjusted.
1167 aComp2
.UpdateDeleteTab( nTable
, FALSE
, TRUE
, bRefChanged
);
1170 // kein StartListeningTo weil pTab[nTab] noch nicht existiert!
1172 else if ( bPosChanged
)
1176 BOOL
ScFormulaCell::UpdateDeleteTab(SCTAB nTable
, BOOL bIsMove
)
1178 BOOL bRefChanged
= FALSE
;
1179 BOOL bPosChanged
= ( aPos
.Tab() > nTable
? TRUE
: FALSE
);
1181 if( pCode
->GetNextReferenceRPN() && !pDocument
->IsClipOrUndo() )
1183 EndListeningTo( pDocument
);
1184 // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateDeleteTab !
1187 ScRangeData
* pRangeData
;
1188 ScCompiler
aComp(pDocument
, aPos
, *pCode
);
1189 aComp
.SetGrammar(pDocument
->GetGrammar());
1190 pRangeData
= aComp
.UpdateDeleteTab(nTable
, bIsMove
, FALSE
, bRefChanged
);
1191 if (pRangeData
) // Shared Formula gegen echte Formel
1193 pDocument
->RemoveFromFormulaTree( this ); // update formula count
1195 pCode
= pRangeData
->GetCode()->Clone();
1196 ScCompiler
aComp2(pDocument
, aPos
, *pCode
);
1197 aComp2
.SetGrammar(pDocument
->GetGrammar());
1198 aComp2
.CompileTokenArray();
1199 aComp2
.MoveRelWrap(pRangeData
->GetMaxCol(), pRangeData
->GetMaxRow());
1200 aComp2
.UpdateDeleteTab( nTable
, FALSE
, FALSE
, bRefChanged
);
1201 // If the shared formula contained a named range/formula containing
1202 // an absolute reference to a sheet, those have to be readjusted.
1203 aComp2
.UpdateInsertTab( nTable
,TRUE
);
1204 // bRefChanged kann beim letzten UpdateDeleteTab zurueckgesetzt worden sein
1208 // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
1210 else if ( bPosChanged
)
1216 void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos
, SCTAB nNewPos
, SCTAB nTabNo
)
1219 if( pCode
->GetNextReferenceRPN() && !pDocument
->IsClipOrUndo() )
1221 EndListeningTo( pDocument
);
1222 // SetTab _nach_ EndListeningTo und _vor_ Compiler UpdateMoveTab !
1223 aPos
.SetTab( nTabNo
);
1224 ScRangeData
* pRangeData
;
1225 ScCompiler
aComp(pDocument
, aPos
, *pCode
);
1226 aComp
.SetGrammar(pDocument
->GetGrammar());
1227 pRangeData
= aComp
.UpdateMoveTab( nOldPos
, nNewPos
, FALSE
);
1228 if (pRangeData
) // Shared Formula gegen echte Formel
1230 pDocument
->RemoveFromFormulaTree( this ); // update formula count
1232 pCode
= pRangeData
->GetCode()->Clone();
1233 ScCompiler
aComp2(pDocument
, aPos
, *pCode
);
1234 aComp2
.SetGrammar(pDocument
->GetGrammar());
1235 aComp2
.CompileTokenArray();
1236 aComp2
.MoveRelWrap(pRangeData
->GetMaxCol(), pRangeData
->GetMaxRow());
1237 aComp2
.UpdateMoveTab( nOldPos
, nNewPos
, TRUE
);
1240 // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
1243 aPos
.SetTab( nTabNo
);
1246 void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable
)
1248 if( !pDocument
->IsClipOrUndo() )
1251 ScToken
* p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
1254 ScSingleRefData
& rRef1
= p
->GetSingleRef();
1255 if( !rRef1
.IsTabRel() && (SCsTAB
) nTable
<= rRef1
.nTab
)
1257 if( p
->GetType() == formula::svDoubleRef
)
1259 ScSingleRefData
& rRef2
= p
->GetDoubleRef().Ref2
;
1260 if( !rRef2
.IsTabRel() && (SCsTAB
) nTable
<= rRef2
.nTab
)
1263 p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
1268 BOOL
ScFormulaCell::TestTabRefAbs(SCTAB nTable
)
1271 if( !pDocument
->IsClipOrUndo() )
1274 ScToken
* p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
1277 ScSingleRefData
& rRef1
= p
->GetSingleRef();
1278 if( !rRef1
.IsTabRel() )
1280 if( (SCsTAB
) nTable
!= rRef1
.nTab
)
1282 else if (nTable
!= aPos
.Tab())
1283 rRef1
.nTab
= aPos
.Tab();
1285 if( p
->GetType() == formula::svDoubleRef
)
1287 ScSingleRefData
& rRef2
= p
->GetDoubleRef().Ref2
;
1288 if( !rRef2
.IsTabRel() )
1290 if( (SCsTAB
) nTable
!= rRef2
.nTab
)
1292 else if (nTable
!= aPos
.Tab())
1293 rRef2
.nTab
= aPos
.Tab();
1296 p
= static_cast<ScToken
*>(pCode
->GetNextReferenceRPN());
1302 void ScFormulaCell::UpdateCompile( BOOL bForceIfNameInUse
)
1304 if ( bForceIfNameInUse
&& !bCompile
)
1305 bCompile
= pCode
->HasNameOrColRowName();
1307 pCode
->SetCodeError( 0 ); // make sure it will really be compiled
1308 CompileTokenArray();
1311 // Referenzen transponieren - wird nur in Clipboard-Dokumenten aufgerufen
1313 void ScFormulaCell::TransposeReference()
1315 BOOL bFound
= FALSE
;
1318 while ( ( t
= static_cast<ScToken
*>(pCode
->GetNextReference()) ) != NULL
)
1320 ScSingleRefData
& rRef1
= t
->GetSingleRef();
1321 if ( rRef1
.IsColRel() && rRef1
.IsRowRel() )
1323 BOOL bDouble
= (t
->GetType() == formula::svDoubleRef
);
1324 ScSingleRefData
& rRef2
= (bDouble
? t
->GetDoubleRef().Ref2
: rRef1
);
1325 if ( !bDouble
|| (rRef2
.IsColRel() && rRef2
.IsRowRel()) )
1329 nTemp
= rRef1
.nRelCol
;
1330 rRef1
.nRelCol
= static_cast<SCCOL
>(rRef1
.nRelRow
);
1331 rRef1
.nRelRow
= static_cast<SCROW
>(nTemp
);
1335 nTemp
= rRef2
.nRelCol
;
1336 rRef2
.nRelCol
= static_cast<SCCOL
>(rRef2
.nRelRow
);
1337 rRef2
.nRelRow
= static_cast<SCROW
>(nTemp
);
1349 void ScFormulaCell::UpdateTranspose( const ScRange
& rSource
, const ScAddress
& rDest
,
1350 ScDocument
* pUndoDoc
)
1352 EndListeningTo( pDocument
);
1354 ScAddress aOldPos
= aPos
;
1355 BOOL bPosChanged
= FALSE
; // ob diese Zelle bewegt wurde
1357 ScRange
aDestRange( rDest
, ScAddress(
1358 static_cast<SCCOL
>(rDest
.Col() + rSource
.aEnd
.Row() - rSource
.aStart
.Row()),
1359 static_cast<SCROW
>(rDest
.Row() + rSource
.aEnd
.Col() - rSource
.aStart
.Col()),
1360 rDest
.Tab() + rSource
.aEnd
.Tab() - rSource
.aStart
.Tab() ) );
1361 if ( aDestRange
.In( aOldPos
) )
1363 // Position zurueckrechnen
1364 SCsCOL nRelPosX
= aOldPos
.Col();
1365 SCsROW nRelPosY
= aOldPos
.Row();
1366 SCsTAB nRelPosZ
= aOldPos
.Tab();
1367 ScRefUpdate::DoTranspose( nRelPosX
, nRelPosY
, nRelPosZ
, pDocument
, aDestRange
, rSource
.aStart
);
1368 aOldPos
.Set( nRelPosX
, nRelPosY
, nRelPosZ
);
1372 ScTokenArray
* pOld
= pUndoDoc
? pCode
->Clone() : NULL
;
1373 BOOL bRefChanged
= FALSE
;
1376 ScRangeData
* pShared
= NULL
;
1378 while( (t
= static_cast<ScToken
*>(pCode
->GetNextReferenceOrName())) != NULL
)
1380 if( t
->GetOpCode() == ocName
)
1382 ScRangeData
* pName
= pDocument
->GetRangeName()->FindIndex( t
->GetIndex() );
1385 if (pName
->IsModified())
1387 if (pName
->HasType(RT_SHAREDMOD
))
1391 else if( t
->GetType() != svIndex
)
1393 t
->CalcAbsIfRel( aOldPos
);
1395 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1396 SingleDoubleRefModifier
aMod( *t
);
1397 ScComplexRefData
& rRef
= aMod
.Ref();
1398 bMod
= (ScRefUpdate::UpdateTranspose( pDocument
, rSource
,
1399 rDest
, rRef
) != UR_NOTHING
|| bPosChanged
);
1403 t
->CalcRelFromAbs( aPos
);
1409 if (pShared
) // Shared Formula gegen echte Formel austauschen
1411 pDocument
->RemoveFromFormulaTree( this ); // update formula count
1413 pCode
= new ScTokenArray( *pShared
->GetCode() );
1416 while( (t
= static_cast<ScToken
*>(pCode
->GetNextReference())) != NULL
)
1418 if( t
->GetType() != svIndex
)
1420 t
->CalcAbsIfRel( aOldPos
);
1422 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1423 SingleDoubleRefModifier
aMod( *t
);
1424 ScComplexRefData
& rRef
= aMod
.Ref();
1425 bMod
= (ScRefUpdate::UpdateTranspose( pDocument
, rSource
,
1426 rDest
, rRef
) != UR_NOTHING
|| bPosChanged
);
1429 t
->CalcRelFromAbs( aPos
);
1438 ScFormulaCell
* pFCell
= new ScFormulaCell( pUndoDoc
, aPos
, pOld
,
1439 eTempGrammar
, cMatrixFlag
);
1440 pFCell
->aResult
.SetToken( NULL
); // to recognize it as changed later (Cut/Paste!)
1441 pUndoDoc
->PutCell( aPos
.Col(), aPos
.Row(), aPos
.Tab(), pFCell
);
1445 CompileTokenArray(); // ruft auch StartListeningTo
1449 StartListeningTo( pDocument
); // Listener wie vorher
1454 void ScFormulaCell::UpdateGrow( const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
)
1456 EndListeningTo( pDocument
);
1458 BOOL bRefChanged
= FALSE
;
1460 ScRangeData
* pShared
= NULL
;
1463 while( (t
= static_cast<ScToken
*>(pCode
->GetNextReferenceOrName())) != NULL
)
1465 if( t
->GetOpCode() == ocName
)
1467 ScRangeData
* pName
= pDocument
->GetRangeName()->FindIndex( t
->GetIndex() );
1470 if (pName
->IsModified())
1472 if (pName
->HasType(RT_SHAREDMOD
))
1476 else if( t
->GetType() != svIndex
)
1478 t
->CalcAbsIfRel( aPos
);
1480 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1481 SingleDoubleRefModifier
aMod( *t
);
1482 ScComplexRefData
& rRef
= aMod
.Ref();
1483 bMod
= (ScRefUpdate::UpdateGrow( rArea
,nGrowX
,nGrowY
,
1484 rRef
) != UR_NOTHING
);
1488 t
->CalcRelFromAbs( aPos
);
1494 if (pShared
) // Shared Formula gegen echte Formel austauschen
1496 pDocument
->RemoveFromFormulaTree( this ); // update formula count
1498 pCode
= new ScTokenArray( *pShared
->GetCode() );
1501 while( (t
= static_cast<ScToken
*>(pCode
->GetNextReference())) != NULL
)
1503 if( t
->GetType() != svIndex
)
1505 t
->CalcAbsIfRel( aPos
);
1507 { // own scope for SingleDoubleRefModifier dtor if SingleRef
1508 SingleDoubleRefModifier
aMod( *t
);
1509 ScComplexRefData
& rRef
= aMod
.Ref();
1510 bMod
= (ScRefUpdate::UpdateGrow( rArea
,nGrowX
,nGrowY
,
1511 rRef
) != UR_NOTHING
);
1514 t
->CalcRelFromAbs( aPos
);
1522 CompileTokenArray(); // ruft auch StartListeningTo
1526 StartListeningTo( pDocument
); // Listener wie vorher
1529 BOOL
lcl_IsRangeNameInUse(USHORT nIndex
, ScTokenArray
* pCode
, ScRangeName
* pNames
)
1531 for (FormulaToken
* p
= pCode
->First(); p
; p
= pCode
->Next())
1533 if (p
->GetOpCode() == ocName
)
1535 if (p
->GetIndex() == nIndex
)
1539 // RangeData kann Null sein in bestimmten Excel-Dateien (#31168#)
1540 ScRangeData
* pSubName
= pNames
->FindIndex(p
->GetIndex());
1541 if (pSubName
&& lcl_IsRangeNameInUse(nIndex
,
1542 pSubName
->GetCode(), pNames
))
1550 BOOL
ScFormulaCell::IsRangeNameInUse(USHORT nIndex
) const
1552 return lcl_IsRangeNameInUse( nIndex
, pCode
, pDocument
->GetRangeName() );
1555 void lcl_FindRangeNamesInUse(std::set
<USHORT
>& rIndexes
, ScTokenArray
* pCode
, ScRangeName
* pNames
)
1557 for (FormulaToken
* p
= pCode
->First(); p
; p
= pCode
->Next())
1559 if (p
->GetOpCode() == ocName
)
1561 USHORT nTokenIndex
= p
->GetIndex();
1562 rIndexes
.insert( nTokenIndex
);
1564 ScRangeData
* pSubName
= pNames
->FindIndex(p
->GetIndex());
1566 lcl_FindRangeNamesInUse(rIndexes
, pSubName
->GetCode(), pNames
);
1571 void ScFormulaCell::FindRangeNamesInUse(std::set
<USHORT
>& rIndexes
) const
1573 lcl_FindRangeNamesInUse( rIndexes
, pCode
, pDocument
->GetRangeName() );
1576 void ScFormulaCell::ReplaceRangeNamesInUse( const ScRangeData::IndexMap
& rMap
)
1578 for( FormulaToken
* p
= pCode
->First(); p
; p
= pCode
->Next() )
1580 if( p
->GetOpCode() == ocName
)
1582 sal_uInt16 nIndex
= p
->GetIndex();
1583 ScRangeData::IndexMap::const_iterator itr
= rMap
.find(nIndex
);
1584 sal_uInt16 nNewIndex
= itr
== rMap
.end() ? nIndex
: itr
->second
;
1585 if ( nIndex
!= nNewIndex
)
1587 p
->SetIndex( nNewIndex
);
1593 CompileTokenArray();
1596 void ScFormulaCell::CompileDBFormula()
1598 for( FormulaToken
* p
= pCode
->First(); p
; p
= pCode
->Next() )
1600 if ( p
->GetOpCode() == ocDBArea
1601 || (p
->GetOpCode() == ocName
&& p
->GetIndex() >= SC_START_INDEX_DB_COLL
) )
1604 CompileTokenArray();
1611 void ScFormulaCell::CompileDBFormula( BOOL bCreateFormulaString
)
1613 // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
1614 // 1. FormelString mit alten Namen erzeugen
1615 // 2. FormelString mit neuen Namen kompilieren
1616 if ( bCreateFormulaString
)
1618 BOOL bRecompile
= FALSE
;
1620 for ( FormulaToken
* p
= pCode
->First(); p
&& !bRecompile
; p
= pCode
->Next() )
1622 switch ( p
->GetOpCode() )
1624 case ocBad
: // DB-Bereich evtl. zugefuegt
1625 case ocColRowName
: // #36762# falls Namensgleichheit
1626 case ocDBArea
: // DB-Bereich
1630 if ( p
->GetIndex() >= SC_START_INDEX_DB_COLL
)
1631 bRecompile
= TRUE
; // DB-Bereich
1640 GetFormula( aFormula
, formula::FormulaGrammar::GRAM_NATIVE
);
1641 if ( GetMatrixFlag() != MM_NONE
&& aFormula
.Len() )
1643 if ( aFormula
.GetChar( aFormula
.Len()-1 ) == '}' )
1644 aFormula
.Erase( aFormula
.Len()-1 , 1 );
1645 if ( aFormula
.GetChar(0) == '{' )
1646 aFormula
.Erase( 0, 1 );
1648 EndListeningTo( pDocument
);
1649 pDocument
->RemoveFromFormulaTree( this );
1651 SetHybridFormula( aFormula
, formula::FormulaGrammar::GRAM_NATIVE
);
1654 else if ( !pCode
->GetLen() && aResult
.GetHybridFormula().Len() )
1656 Compile( aResult
.GetHybridFormula(), FALSE
, eTempGrammar
);
1657 aResult
.SetToken( NULL
);
1662 void ScFormulaCell::CompileNameFormula( BOOL bCreateFormulaString
)
1664 // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
1665 // 1. FormelString mit alten RangeNames erzeugen
1666 // 2. FormelString mit neuen RangeNames kompilieren
1667 if ( bCreateFormulaString
)
1669 BOOL bRecompile
= FALSE
;
1671 for ( FormulaToken
* p
= pCode
->First(); p
&& !bRecompile
; p
= pCode
->Next() )
1673 switch ( p
->GetOpCode() )
1675 case ocBad
: // RangeName evtl. zugefuegt
1676 case ocColRowName
: // #36762# falls Namensgleichheit
1680 if ( p
->GetType() == svIndex
)
1681 bRecompile
= TRUE
; // RangeName
1687 GetFormula( aFormula
, formula::FormulaGrammar::GRAM_NATIVE
);
1688 if ( GetMatrixFlag() != MM_NONE
&& aFormula
.Len() )
1690 if ( aFormula
.GetChar( aFormula
.Len()-1 ) == '}' )
1691 aFormula
.Erase( aFormula
.Len()-1 , 1 );
1692 if ( aFormula
.GetChar(0) == '{' )
1693 aFormula
.Erase( 0, 1 );
1695 EndListeningTo( pDocument
);
1696 pDocument
->RemoveFromFormulaTree( this );
1698 SetHybridFormula( aFormula
, formula::FormulaGrammar::GRAM_NATIVE
);
1701 else if ( !pCode
->GetLen() && aResult
.GetHybridFormula().Len() )
1703 Compile( aResult
.GetHybridFormula(), FALSE
, eTempGrammar
);
1704 aResult
.SetToken( NULL
);
1709 void ScFormulaCell::CompileColRowNameFormula()
1712 for ( FormulaToken
* p
= pCode
->First(); p
; p
= pCode
->Next() )
1714 if ( p
->GetOpCode() == ocColRowName
)
1717 CompileTokenArray();
1724 // ============================================================================