1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
23 #include <osl/diagnose.h>
24 #include <sal/log.hxx>
27 #include <tokenarray.hxx>
28 #include <reftokenhelper.hxx>
29 #include <clipparam.hxx>
30 #include <compiler.hxx>
31 #include <interpre.hxx>
32 #include <formula/FormulaCompiler.hxx>
33 #include <formula/compiler.hxx>
34 #include <formula/opcode.hxx>
35 #include <jumpmatrix.hxx>
36 #include <rangeseq.hxx>
37 #include <rangeutl.hxx>
38 #include <externalrefmgr.hxx>
39 #include <document.hxx>
40 #include <refupdatecontext.hxx>
41 #include <tokenstringcontext.hxx>
43 #include <addincol.hxx>
45 #include <reordermap.hxx>
46 #include <svl/sharedstring.hxx>
47 #include <scmatrix.hxx>
49 #include <com/sun/star/sheet/ComplexReference.hpp>
50 #include <com/sun/star/sheet/ExternalReference.hpp>
51 #include <com/sun/star/sheet/FormulaToken.hpp>
52 #include <com/sun/star/sheet/ReferenceFlags.hpp>
53 #include <com/sun/star/sheet/NameToken.hpp>
55 #include <o3tl/safeint.hxx>
56 #include <o3tl/sorted_vector.hxx>
59 using namespace formula
;
60 using namespace com::sun::star
;
64 void lcl_SingleRefToCalc( ScSingleRefData
& rRef
, const sheet::SingleReference
& rAPI
)
68 rRef
.SetColRel( ( rAPI
.Flags
& sheet::ReferenceFlags::COLUMN_RELATIVE
) != 0 );
69 rRef
.SetRowRel( ( rAPI
.Flags
& sheet::ReferenceFlags::ROW_RELATIVE
) != 0 );
70 rRef
.SetTabRel( ( rAPI
.Flags
& sheet::ReferenceFlags::SHEET_RELATIVE
) != 0 );
71 rRef
.SetColDeleted( ( rAPI
.Flags
& sheet::ReferenceFlags::COLUMN_DELETED
) != 0 );
72 rRef
.SetRowDeleted( ( rAPI
.Flags
& sheet::ReferenceFlags::ROW_DELETED
) != 0 );
73 rRef
.SetTabDeleted( ( rAPI
.Flags
& sheet::ReferenceFlags::SHEET_DELETED
) != 0 );
74 rRef
.SetFlag3D( ( rAPI
.Flags
& sheet::ReferenceFlags::SHEET_3D
) != 0 );
75 rRef
.SetRelName( ( rAPI
.Flags
& sheet::ReferenceFlags::RELATIVE_NAME
) != 0 );
78 rRef
.SetRelCol(static_cast<SCCOL
>(rAPI
.RelativeColumn
));
80 rRef
.SetAbsCol(static_cast<SCCOL
>(rAPI
.Column
));
83 rRef
.SetRelRow(static_cast<SCROW
>(rAPI
.RelativeRow
));
85 rRef
.SetAbsRow(static_cast<SCROW
>(rAPI
.Row
));
88 rRef
.SetRelTab(static_cast<SCTAB
>(rAPI
.RelativeSheet
));
90 rRef
.SetAbsTab(static_cast<SCTAB
>(rAPI
.Sheet
));
93 void lcl_ExternalRefToCalc( ScSingleRefData
& rRef
, const sheet::SingleReference
& rAPI
)
97 rRef
.SetColRel( ( rAPI
.Flags
& sheet::ReferenceFlags::COLUMN_RELATIVE
) != 0 );
98 rRef
.SetRowRel( ( rAPI
.Flags
& sheet::ReferenceFlags::ROW_RELATIVE
) != 0 );
99 rRef
.SetColDeleted( ( rAPI
.Flags
& sheet::ReferenceFlags::COLUMN_DELETED
) != 0 );
100 rRef
.SetRowDeleted( ( rAPI
.Flags
& sheet::ReferenceFlags::ROW_DELETED
) != 0 );
101 rRef
.SetTabDeleted( false ); // sheet must not be deleted for external refs
102 rRef
.SetFlag3D( ( rAPI
.Flags
& sheet::ReferenceFlags::SHEET_3D
) != 0 );
103 rRef
.SetRelName( false );
106 rRef
.SetRelCol(static_cast<SCCOL
>(rAPI
.RelativeColumn
));
108 rRef
.SetAbsCol(static_cast<SCCOL
>(rAPI
.Column
));
111 rRef
.SetRelRow(static_cast<SCROW
>(rAPI
.RelativeRow
));
113 rRef
.SetAbsRow(static_cast<SCROW
>(rAPI
.Row
));
115 // sheet index must be absolute for external refs
119 struct TokenPointerRange
121 FormulaToken
** mpStart
;
122 FormulaToken
** mpStop
;
124 TokenPointerRange() : mpStart(nullptr), mpStop(nullptr) {}
125 TokenPointerRange( FormulaToken
** p
, sal_uInt16 n
) :
126 mpStart(p
), mpStop( p
+ static_cast<size_t>(n
)) {}
130 TokenPointerRange maPointerRange
[2];
133 TokenPointers( FormulaToken
** pCode
, sal_uInt16 nLen
, FormulaToken
** pRPN
, sal_uInt16 nRPN
,
134 bool bSkipRelName
= true ) :
135 mbSkipRelName(bSkipRelName
)
137 maPointerRange
[0] = TokenPointerRange( pCode
, nLen
);
138 maPointerRange
[1] = TokenPointerRange( pRPN
, nRPN
);
141 bool skipToken( size_t i
, const FormulaToken
* const * pp
)
143 // Handle all code tokens, and tokens in RPN only if they have a
144 // reference count of 1, which means they are not referenced in the
145 // code array. Doing it the other way would skip code tokens that
146 // are held by flat copied token arrays and thus are shared. For
147 // flat copy arrays the caller has to know what it does and should
148 // discard all RPN, update only one array and regenerate all RPN.
151 if ((*pp
)->GetRef() > 1)
156 // Skip (do not adjust) relative references resulting from
157 // named expressions. Resolved expressions are only in RPN.
158 switch ((*pp
)->GetType())
161 return (*pp
)->GetSingleRef()->IsRelName();
164 const ScComplexRefData
& rRef
= *(*pp
)->GetDoubleRef();
165 return rRef
.Ref1
.IsRelName() || rRef
.Ref2
.IsRelName();
176 FormulaToken
* getHandledToken( size_t i
, FormulaToken
* const * pp
)
178 if (skipToken( i
, pp
))
181 FormulaToken
* p
= *pp
;
182 if (p
->GetOpCode() == ocTableRef
)
184 // Return the inner reference token if it is not in RPN.
185 ScTableRefToken
* pTR
= dynamic_cast<ScTableRefToken
*>(p
);
188 p
= pTR
->GetAreaRefRPN();
192 // Reference handled in RPN, but do not return nullptr so
193 // loops will process ocTableRef via pp instead of issuing
204 // --- class ScRawToken -----------------------------------------------------
206 void ScRawToken::SetOpCode( OpCode e
)
213 nJump
[ 0 ] = 3; // If, Else, Behind
218 nJump
[ 0 ] = 2; // If, Behind
222 nJump
[ 0 ] = FORMULA_MAXJUMPCOUNT
+ 1;
226 nJump
[ 0 ] = FORMULA_MAXPARAMS
+ 1;
239 case ocTableRefClose
:
244 whitespace
.nCount
= 1;
245 whitespace
.cChar
= 0x20;
250 sbyte
.eInForceArray
= ParamClass::Unknown
;
254 void ScRawToken::SetString( rtl_uString
* pData
, rtl_uString
* pDataIgnoreCase
)
259 sharedstring
.mpData
= pData
;
260 sharedstring
.mpDataIgnoreCase
= pDataIgnoreCase
;
263 void ScRawToken::SetStringName( rtl_uString
* pData
, rtl_uString
* pDataIgnoreCase
)
268 sharedstring
.mpData
= pData
;
269 sharedstring
.mpDataIgnoreCase
= pDataIgnoreCase
;
272 void ScRawToken::SetSingleReference( const ScSingleRefData
& rRef
)
280 void ScRawToken::SetDoubleReference( const ScComplexRefData
& rRef
)
287 void ScRawToken::SetDouble(double rVal
)
294 void ScRawToken::SetErrorConstant( FormulaError nErr
)
301 void ScRawToken::SetName(sal_Int16 nSheet
, sal_uInt16 nIndex
)
306 name
.nSheet
= nSheet
;
307 name
.nIndex
= nIndex
;
310 void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScSingleRefData
& rRef
)
313 eType
= svExternalSingleRef
;
315 extref
.nFileId
= nFileId
;
317 extref
.aRef
.Ref2
= rRef
;
318 maExternalName
= rTabName
;
321 void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId
, const OUString
& rTabName
, const ScComplexRefData
& rRef
)
324 eType
= svExternalDoubleRef
;
326 extref
.nFileId
= nFileId
;
328 maExternalName
= rTabName
;
331 void ScRawToken::SetExternalName( sal_uInt16 nFileId
, const OUString
& rName
)
334 eType
= svExternalName
;
336 extname
.nFileId
= nFileId
;
337 maExternalName
= rName
;
340 void ScRawToken::SetExternal( const OUString
& rStr
)
344 maExternalName
= rStr
;
347 bool ScRawToken::IsValidReference(const ScDocument
& rDoc
) const
352 return aRef
.Ref1
.Valid(rDoc
);
354 return aRef
.Valid(rDoc
);
355 case svExternalSingleRef
:
356 case svExternalDoubleRef
:
364 FormulaToken
* ScRawToken::CreateToken(ScSheetLimits
& rLimits
) const
366 #define IF_NOT_OPCODE_ERROR(o,c) SAL_WARN_IF((eOp!=o), "sc.core", #c "::ctor: OpCode " << static_cast<int>(eOp) << " lost, converted to " #o "; maybe inherit from FormulaToken instead!")
370 if (eOp
== ocWhitespace
)
371 return new FormulaSpaceToken( whitespace
.nCount
, whitespace
.cChar
);
373 return new FormulaByteToken( eOp
, sbyte
.cByte
, sbyte
.eInForceArray
);
375 IF_NOT_OPCODE_ERROR( ocPush
, FormulaDoubleToken
);
376 return new FormulaDoubleToken( nValue
);
379 svl::SharedString
aSS(sharedstring
.mpData
, sharedstring
.mpDataIgnoreCase
);
381 return new FormulaStringToken(std::move(aSS
));
383 return new FormulaStringOpToken(eOp
, std::move(aSS
));
386 return new ScSingleRefToken(rLimits
, aRef
.Ref1
, eOp
);
388 return new ScDoubleRefToken(rLimits
, aRef
, eOp
);
390 IF_NOT_OPCODE_ERROR( ocPush
, ScMatrixToken
);
391 return new ScMatrixToken( pMat
);
393 if (eOp
== ocTableRef
)
394 return new ScTableRefToken( table
.nIndex
, table
.eItem
);
396 return new FormulaIndexToken( eOp
, name
.nIndex
, name
.nSheet
);
397 case svExternalSingleRef
:
399 svl::SharedString
aTabName(maExternalName
); // string not interned
400 return new ScExternalSingleRefToken(extref
.nFileId
, std::move(aTabName
), extref
.aRef
.Ref1
);
402 case svExternalDoubleRef
:
404 svl::SharedString
aTabName(maExternalName
); // string not interned
405 return new ScExternalDoubleRefToken(extref
.nFileId
, std::move(aTabName
), extref
.aRef
);
409 svl::SharedString
aName(maExternalName
); // string not interned
410 return new ScExternalNameToken( extname
.nFileId
, std::move(aName
) );
413 return new FormulaJumpToken( eOp
, nJump
);
415 return new FormulaExternalToken( eOp
, sbyte
.cByte
, maExternalName
);
417 return new FormulaFAPToken( eOp
, sbyte
.cByte
, nullptr );
419 IF_NOT_OPCODE_ERROR( ocMissing
, FormulaMissingToken
);
420 return new FormulaMissingToken
;
422 return new FormulaToken( svSep
,eOp
);
424 return new FormulaErrorToken( nError
);
426 return new FormulaUnknownToken( eOp
);
429 SAL_WARN("sc.core", "unknown ScRawToken::CreateToken() type " << int(GetType()));
430 return new FormulaUnknownToken( ocBad
);
433 #undef IF_NOT_OPCODE_ERROR
438 // TextEqual: if same formula entered (for optimization in sort)
439 bool checkTextEqual( const ScSheetLimits
& rLimits
, const FormulaToken
& _rToken1
, const FormulaToken
& _rToken2
)
442 (_rToken1
.GetType() == svSingleRef
|| _rToken1
.GetType() == svDoubleRef
)
443 && _rToken1
.FormulaToken::operator ==(_rToken2
));
445 // in relative Refs only compare relative parts
447 ScComplexRefData aTemp1
;
448 if ( _rToken1
.GetType() == svSingleRef
)
450 aTemp1
.Ref1
= *_rToken1
.GetSingleRef();
451 aTemp1
.Ref2
= aTemp1
.Ref1
;
454 aTemp1
= *_rToken1
.GetDoubleRef();
456 ScComplexRefData aTemp2
;
457 if ( _rToken2
.GetType() == svSingleRef
)
459 aTemp2
.Ref1
= *_rToken2
.GetSingleRef();
460 aTemp2
.Ref2
= aTemp2
.Ref1
;
463 aTemp2
= *_rToken2
.GetDoubleRef();
466 ScRange aRange1
= aTemp1
.toAbs(rLimits
, aPos
), aRange2
= aTemp2
.toAbs(rLimits
, aPos
);
468 // memcmp doesn't work because of the alignment byte after bFlags.
469 // After SmartRelAbs only absolute parts have to be compared.
470 return aRange1
== aRange2
&& aTemp1
.Ref1
.FlagValue() == aTemp2
.Ref1
.FlagValue() && aTemp1
.Ref2
.FlagValue() == aTemp2
.Ref2
.FlagValue();
475 #if DEBUG_FORMULA_COMPILER
476 void DumpToken(formula::FormulaToken
const & rToken
)
478 switch (rToken
.GetType()) {
480 cout
<< "-- ScSingleRefToken" << endl
;
481 rToken
.GetSingleRef()->Dump(1);
484 cout
<< "-- ScDoubleRefToken" << endl
;
485 rToken
.GetDoubleRef()->Dump(1);
488 cout
<< "-- FormulaToken" << endl
;
489 cout
<< " opcode: " << int(rToken
.GetOpCode()) << " " <<
490 formula::FormulaCompiler::GetNativeSymbol( rToken
.GetOpCode()).toUtf8().getStr() << endl
;
491 cout
<< " type: " << static_cast<int>(rToken
.GetType()) << endl
;
492 switch (rToken
.GetType())
495 cout
<< " value: " << rToken
.GetDouble() << endl
;
499 << OUStringToOString(rToken
.GetString().getString(), RTL_TEXTENCODING_UTF8
).getStr()
510 FormulaTokenRef
extendRangeReference( ScSheetLimits
& rLimits
, FormulaToken
& rTok1
, FormulaToken
& rTok2
,
511 const ScAddress
& rPos
, bool bReuseDoubleRef
)
514 StackVar sv1
= rTok1
.GetType();
515 // Doing a RangeOp with RefList is probably utter nonsense, but Xcl
516 // supports it, so do we.
517 if (sv1
!= svSingleRef
&& sv1
!= svDoubleRef
&& sv1
!= svRefList
518 && sv1
!= svExternalSingleRef
&& sv1
!= svExternalDoubleRef
)
520 StackVar sv2
= rTok2
.GetType();
521 if (sv2
!= svSingleRef
&& sv2
!= svDoubleRef
&& sv2
!= svRefList
)
525 bool bExternal
= (sv1
== svExternalSingleRef
);
526 if ((sv1
== svSingleRef
|| bExternal
) && sv2
== svSingleRef
)
528 // Range references like Sheet1.A1:A2 are generalized and built by
529 // first creating a DoubleRef from the first SingleRef, effectively
530 // generating Sheet1.A1:A1, and then extending that with A2 as if
531 // Sheet1.A1:A1:A2 was encountered, so the mechanisms to adjust the
532 // references apply as well.
534 /* Given the current structure of external references an external
535 * reference can only be extended if the second reference does not
536 * point to a different sheet. 'file'#Sheet1.A1:A2 is ok,
537 * 'file'#Sheet1.A1:Sheet2.A2 is not. Since we can't determine from a
538 * svSingleRef whether the sheet would be different from the one given
539 * in the external reference, we have to bail out if there is any sheet
540 * specified. NOTE: Xcl does handle external 3D references as in
541 * '[file]Sheet1:Sheet2'!A1:A2
543 * FIXME: For OOo syntax be smart and remember an external singleref
544 * encountered and if followed by ocRange and singleref, create an
545 * external singleref for the second singleref. Both could then be
546 * merged here. For Xcl syntax already parse an external range
547 * reference entirely, cumbersome. */
549 const ScSingleRefData
& rRef2
= *rTok2
.GetSingleRef();
550 if (bExternal
&& rRef2
.IsFlag3D())
553 ScComplexRefData aRef
;
554 aRef
.Ref1
= aRef
.Ref2
= *rTok1
.GetSingleRef();
555 aRef
.Ref2
.SetFlag3D( false);
556 aRef
.Extend(rLimits
, rRef2
, rPos
);
558 xRes
= new ScExternalDoubleRefToken( rTok1
.GetIndex(), rTok1
.GetString(), aRef
);
560 xRes
= new ScDoubleRefToken(rLimits
, aRef
);
564 bExternal
|= (sv1
== svExternalDoubleRef
);
565 const ScRefList
* pRefList
= nullptr;
566 if (sv1
== svDoubleRef
)
568 xRes
= (bReuseDoubleRef
&& rTok1
.GetRef() == 1 ? &rTok1
: rTok1
.Clone());
569 sv1
= svUnknown
; // mark as handled
571 else if (sv2
== svDoubleRef
)
573 xRes
= (bReuseDoubleRef
&& rTok2
.GetRef() == 1 ? &rTok2
: rTok2
.Clone());
574 sv2
= svUnknown
; // mark as handled
576 else if (sv1
== svRefList
)
577 pRefList
= rTok1
.GetRefList();
578 else if (sv2
== svRefList
)
579 pRefList
= rTok2
.GetRefList();
582 if (pRefList
->empty())
585 return nullptr; // external reference list not possible
586 xRes
= new ScDoubleRefToken(rLimits
, (*pRefList
)[0] );
589 return nullptr; // shouldn't happen...
590 StackVar sv
[2] = { sv1
, sv2
};
591 formula::FormulaToken
* pt
[2] = { &rTok1
, &rTok2
};
592 ScComplexRefData
& rRef
= *xRes
->GetDoubleRef();
593 for (size_t i
=0; i
<2; ++i
)
598 rRef
.Extend(rLimits
, *pt
[i
]->GetSingleRef(), rPos
);
601 rRef
.Extend(rLimits
, *pt
[i
]->GetDoubleRef(), rPos
);
605 const ScRefList
* p
= pt
[i
]->GetRefList();
608 for (const auto& rRefData
: *p
)
610 rRef
.Extend(rLimits
, rRefData
, rPos
);
614 case svExternalSingleRef
:
615 if (rRef
.Ref1
.IsFlag3D() || rRef
.Ref2
.IsFlag3D())
616 return nullptr; // no other sheets with external refs
618 rRef
.Extend(rLimits
, *pt
[i
]->GetSingleRef(), rPos
);
620 case svExternalDoubleRef
:
621 if (rRef
.Ref1
.IsFlag3D() || rRef
.Ref2
.IsFlag3D())
622 return nullptr; // no other sheets with external refs
624 rRef
.Extend(rLimits
, *pt
[i
]->GetDoubleRef(), rPos
);
627 ; // nothing, prevent compiler warning
631 return FormulaTokenRef(xRes
.get());
634 // real implementations of virtual functions
636 const ScSingleRefData
* ScSingleRefToken::GetSingleRef() const { return &aSingleRef
; }
637 ScSingleRefData
* ScSingleRefToken::GetSingleRef() { return &aSingleRef
; }
638 bool ScSingleRefToken::TextEqual( const FormulaToken
& _rToken
) const
640 return FormulaToken::operator ==(_rToken
) && checkTextEqual(mrSheetLimits
, *this, _rToken
);
642 bool ScSingleRefToken::operator==( const FormulaToken
& r
) const
644 return FormulaToken::operator==( r
) && aSingleRef
== *r
.GetSingleRef();
647 const ScSingleRefData
* ScDoubleRefToken::GetSingleRef() const { return &aDoubleRef
.Ref1
; }
648 ScSingleRefData
* ScDoubleRefToken::GetSingleRef() { return &aDoubleRef
.Ref1
; }
649 const ScComplexRefData
* ScDoubleRefToken::GetDoubleRef() const { return &aDoubleRef
; }
650 ScComplexRefData
* ScDoubleRefToken::GetDoubleRef() { return &aDoubleRef
; }
651 const ScSingleRefData
* ScDoubleRefToken::GetSingleRef2() const { return &aDoubleRef
.Ref2
; }
652 ScSingleRefData
* ScDoubleRefToken::GetSingleRef2() { return &aDoubleRef
.Ref2
; }
653 bool ScDoubleRefToken::TextEqual( const FormulaToken
& _rToken
) const
655 return FormulaToken::operator ==(_rToken
) && checkTextEqual(mrSheetLimits
, *this, _rToken
);
657 bool ScDoubleRefToken::operator==( const FormulaToken
& r
) const
659 return FormulaToken::operator==( r
) && aDoubleRef
== *r
.GetDoubleRef();
662 const ScRefList
* ScRefListToken::GetRefList() const { return &aRefList
; }
663 ScRefList
* ScRefListToken::GetRefList() { return &aRefList
; }
664 bool ScRefListToken::IsArrayResult() const { return mbArrayResult
; }
665 bool ScRefListToken::operator==( const FormulaToken
& r
) const
667 if (!FormulaToken::operator==( r
) || &aRefList
!= r
.GetRefList())
669 const ScRefListToken
* p
= dynamic_cast<const ScRefListToken
*>(&r
);
670 return p
&& mbArrayResult
== p
->IsArrayResult();
673 ScMatrixToken::ScMatrixToken( ScMatrixRef p
) :
674 FormulaToken(formula::svMatrix
), pMatrix(std::move(p
)) {}
676 ScMatrixToken::ScMatrixToken( const ScMatrixToken
& ) = default;
678 const ScMatrix
* ScMatrixToken::GetMatrix() const { return pMatrix
.get(); }
679 ScMatrix
* ScMatrixToken::GetMatrix() { return pMatrix
.get(); }
680 bool ScMatrixToken::operator==( const FormulaToken
& r
) const
682 return FormulaToken::operator==( r
) && pMatrix
== r
.GetMatrix();
685 ScMatrixRangeToken::ScMatrixRangeToken( const sc::RangeMatrix
& rMat
) :
686 FormulaToken(formula::svMatrix
), mpMatrix(rMat
.mpMat
)
688 maRef
.InitRange(rMat
.mnCol1
, rMat
.mnRow1
, rMat
.mnTab1
, rMat
.mnCol2
, rMat
.mnRow2
, rMat
.mnTab2
);
691 ScMatrixRangeToken::ScMatrixRangeToken( const ScMatrixRangeToken
& ) = default;
693 sal_uInt8
ScMatrixRangeToken::GetByte() const
695 return MATRIX_TOKEN_HAS_RANGE
;
698 const ScMatrix
* ScMatrixRangeToken::GetMatrix() const
700 return mpMatrix
.get();
703 ScMatrix
* ScMatrixRangeToken::GetMatrix()
705 return mpMatrix
.get();
708 const ScComplexRefData
* ScMatrixRangeToken::GetDoubleRef() const
713 ScComplexRefData
* ScMatrixRangeToken::GetDoubleRef()
718 bool ScMatrixRangeToken::operator==( const FormulaToken
& r
) const
720 return FormulaToken::operator==(r
) && mpMatrix
== r
.GetMatrix();
723 FormulaToken
* ScMatrixRangeToken::Clone() const
725 return new ScMatrixRangeToken(*this);
728 ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId
, svl::SharedString aTabName
, const ScSingleRefData
& r
) :
729 FormulaToken( svExternalSingleRef
, ocPush
),
731 maTabName(std::move(aTabName
)),
736 ScExternalSingleRefToken::~ScExternalSingleRefToken()
740 sal_uInt16
ScExternalSingleRefToken::GetIndex() const
745 const svl::SharedString
& ScExternalSingleRefToken::GetString() const
750 const ScSingleRefData
* ScExternalSingleRefToken::GetSingleRef() const
755 ScSingleRefData
* ScExternalSingleRefToken::GetSingleRef()
760 bool ScExternalSingleRefToken::operator ==( const FormulaToken
& r
) const
762 if (!FormulaToken::operator==(r
))
765 if (mnFileId
!= r
.GetIndex())
768 if (maTabName
!= r
.GetString())
771 return maSingleRef
== *r
.GetSingleRef();
774 ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId
, svl::SharedString aTabName
, const ScComplexRefData
& r
) :
775 FormulaToken( svExternalDoubleRef
, ocPush
),
777 maTabName(std::move(aTabName
)),
782 ScExternalDoubleRefToken::~ScExternalDoubleRefToken()
786 sal_uInt16
ScExternalDoubleRefToken::GetIndex() const
791 const svl::SharedString
& ScExternalDoubleRefToken::GetString() const
796 const ScSingleRefData
* ScExternalDoubleRefToken::GetSingleRef() const
798 return &maDoubleRef
.Ref1
;
801 ScSingleRefData
* ScExternalDoubleRefToken::GetSingleRef()
803 return &maDoubleRef
.Ref1
;
806 const ScSingleRefData
* ScExternalDoubleRefToken::GetSingleRef2() const
808 return &maDoubleRef
.Ref2
;
811 ScSingleRefData
* ScExternalDoubleRefToken::GetSingleRef2()
813 return &maDoubleRef
.Ref2
;
816 const ScComplexRefData
* ScExternalDoubleRefToken::GetDoubleRef() const
821 ScComplexRefData
* ScExternalDoubleRefToken::GetDoubleRef()
826 bool ScExternalDoubleRefToken::operator ==( const FormulaToken
& r
) const
828 if (!FormulaToken::operator==(r
))
831 if (mnFileId
!= r
.GetIndex())
834 if (maTabName
!= r
.GetString())
837 return maDoubleRef
== *r
.GetDoubleRef();
840 ScExternalNameToken::ScExternalNameToken( sal_uInt16 nFileId
, svl::SharedString aName
) :
841 FormulaToken( svExternalName
, ocPush
),
843 maName(std::move(aName
))
847 ScExternalNameToken::~ScExternalNameToken() {}
849 sal_uInt16
ScExternalNameToken::GetIndex() const
854 const svl::SharedString
& ScExternalNameToken::GetString() const
859 bool ScExternalNameToken::operator==( const FormulaToken
& r
) const
861 if ( !FormulaToken::operator==(r
) )
864 if (mnFileId
!= r
.GetIndex())
867 return maName
.getData() == r
.GetString().getData();
870 ScTableRefToken::ScTableRefToken( sal_uInt16 nIndex
, ScTableRefToken::Item eItem
) :
871 FormulaToken( svIndex
, ocTableRef
),
877 ScTableRefToken::ScTableRefToken( const ScTableRefToken
& r
) :
879 mxAreaRefRPN( r
.mxAreaRefRPN
? r
.mxAreaRefRPN
->Clone() : nullptr),
885 ScTableRefToken::~ScTableRefToken() {}
887 sal_uInt16
ScTableRefToken::GetIndex() const
892 void ScTableRefToken::SetIndex( sal_uInt16 n
)
897 sal_Int16
ScTableRefToken::GetSheet() const
899 // Code asking for this may have to be adapted as it might assume an
900 // svIndex token would always be ocName or ocDBArea.
901 SAL_WARN("sc.core","ScTableRefToken::GetSheet - maybe adapt caller to know about TableRef?");
902 // Database range is always global.
906 ScTableRefToken::Item
ScTableRefToken::GetItem() const
911 void ScTableRefToken::AddItem( ScTableRefToken::Item eItem
)
913 meItem
= static_cast<ScTableRefToken::Item
>(meItem
| eItem
);
916 void ScTableRefToken::SetAreaRefRPN( formula::FormulaToken
* pToken
)
918 mxAreaRefRPN
= pToken
;
921 formula::FormulaToken
* ScTableRefToken::GetAreaRefRPN() const
923 return mxAreaRefRPN
.get();
926 bool ScTableRefToken::operator==( const FormulaToken
& r
) const
928 if ( !FormulaToken::operator==(r
) )
931 if (mnIndex
!= r
.GetIndex())
934 const ScTableRefToken
* p
= dynamic_cast<const ScTableRefToken
*>(&r
);
938 if (meItem
!= p
->GetItem())
941 if (!mxAreaRefRPN
&& !p
->mxAreaRefRPN
)
943 else if (!mxAreaRefRPN
|| !p
->mxAreaRefRPN
)
945 else if (!(*mxAreaRefRPN
== *(p
->mxAreaRefRPN
)))
951 ScJumpMatrixToken::ScJumpMatrixToken(std::shared_ptr
<ScJumpMatrix
> p
)
952 : FormulaToken(formula::svJumpMatrix
)
953 , mpJumpMatrix(std::move(p
))
956 ScJumpMatrixToken::ScJumpMatrixToken( const ScJumpMatrixToken
& ) = default;
958 ScJumpMatrix
* ScJumpMatrixToken::GetJumpMatrix() const
960 return mpJumpMatrix
.get();
963 bool ScJumpMatrixToken::operator==( const FormulaToken
& r
) const
965 return FormulaToken::operator==( r
) && mpJumpMatrix
.get() == r
.GetJumpMatrix();
968 ScJumpMatrixToken::~ScJumpMatrixToken()
972 double ScEmptyCellToken::GetDouble() const { return 0.0; }
974 const svl::SharedString
& ScEmptyCellToken::GetString() const
976 return svl::SharedString::getEmptyString();
979 bool ScEmptyCellToken::operator==( const FormulaToken
& r
) const
981 return FormulaToken::operator==( r
) &&
982 bInherited
== static_cast< const ScEmptyCellToken
& >(r
).IsInherited() &&
983 bDisplayedAsString
== static_cast< const ScEmptyCellToken
& >(r
).IsDisplayedAsString();
986 ScMatrixCellResultToken::ScMatrixCellResultToken( ScConstMatrixRef pMat
, const formula::FormulaToken
* pUL
) :
987 FormulaToken(formula::svMatrixCell
), xMatrix(std::move(pMat
)), xUpperLeft(pUL
) {}
989 ScMatrixCellResultToken::ScMatrixCellResultToken( const ScMatrixCellResultToken
& ) = default;
991 double ScMatrixCellResultToken::GetDouble() const { return xUpperLeft
->GetDouble(); }
993 ScMatrixCellResultToken::~ScMatrixCellResultToken() {}
995 const svl::SharedString
& ScMatrixCellResultToken::GetString() const
997 return xUpperLeft
->GetString();
1000 const ScMatrix
* ScMatrixCellResultToken::GetMatrix() const { return xMatrix
.get(); }
1001 // Non-const GetMatrix() is private and unused but must be implemented to
1002 // satisfy vtable linkage.
1003 ScMatrix
* ScMatrixCellResultToken::GetMatrix()
1005 return const_cast<ScMatrix
*>(xMatrix
.get());
1008 bool ScMatrixCellResultToken::operator==( const FormulaToken
& r
) const
1010 return FormulaToken::operator==( r
) &&
1011 xUpperLeft
== static_cast<const ScMatrixCellResultToken
&>(r
).xUpperLeft
&&
1012 xMatrix
== static_cast<const ScMatrixCellResultToken
&>(r
).xMatrix
;
1015 FormulaToken
* ScMatrixCellResultToken::Clone() const
1017 return new ScMatrixCellResultToken(*this);
1020 void ScMatrixCellResultToken::Assign( const ScMatrixCellResultToken
& r
)
1022 xMatrix
= r
.xMatrix
;
1023 xUpperLeft
= r
.xUpperLeft
;
1026 ScMatrixFormulaCellToken::ScMatrixFormulaCellToken(
1027 SCCOL nC
, SCROW nR
, const ScConstMatrixRef
& pMat
, const formula::FormulaToken
* pUL
) :
1028 ScMatrixCellResultToken(pMat
, pUL
), nRows(nR
), nCols(nC
)
1030 CloneUpperLeftIfNecessary();
1033 ScMatrixFormulaCellToken::ScMatrixFormulaCellToken( SCCOL nC
, SCROW nR
) :
1034 ScMatrixCellResultToken(nullptr, nullptr), nRows(nR
), nCols(nC
) {}
1036 ScMatrixFormulaCellToken::ScMatrixFormulaCellToken( const ScMatrixFormulaCellToken
& r
) :
1037 ScMatrixCellResultToken(r
), nRows(r
.nRows
), nCols(r
.nCols
)
1039 CloneUpperLeftIfNecessary();
1042 ScMatrixFormulaCellToken::~ScMatrixFormulaCellToken() {}
1044 bool ScMatrixFormulaCellToken::operator==( const FormulaToken
& r
) const
1046 const ScMatrixFormulaCellToken
* p
= dynamic_cast<const ScMatrixFormulaCellToken
*>(&r
);
1047 return p
&& ScMatrixCellResultToken::operator==( r
) &&
1048 nCols
== p
->nCols
&& nRows
== p
->nRows
;
1051 void ScMatrixFormulaCellToken::CloneUpperLeftIfNecessary()
1053 if (xUpperLeft
&& xUpperLeft
->GetType() == svDouble
)
1054 xUpperLeft
= xUpperLeft
->Clone();
1057 void ScMatrixFormulaCellToken::Assign( const ScMatrixCellResultToken
& r
)
1059 ScMatrixCellResultToken::Assign( r
);
1061 CloneUpperLeftIfNecessary();
1064 void ScMatrixFormulaCellToken::Assign( const formula::FormulaToken
& r
)
1068 const ScMatrixCellResultToken
* p
= dynamic_cast<const ScMatrixCellResultToken
*>(&r
);
1070 ScMatrixCellResultToken::Assign( *p
);
1073 OSL_ENSURE( r
.GetType() != svMatrix
, "ScMatrixFormulaCellToken::operator=: assigning ScMatrixToken to ScMatrixFormulaCellToken is not proper, use ScMatrixCellResultToken instead");
1074 if (r
.GetType() == svMatrix
)
1076 xUpperLeft
= nullptr;
1077 xMatrix
= r
.GetMatrix();
1083 CloneUpperLeftIfNecessary();
1088 void ScMatrixFormulaCellToken::SetUpperLeftDouble( double f
)
1090 switch (GetUpperLeftType())
1093 const_cast<FormulaToken
*>(xUpperLeft
.get())->SetDouble(f
);
1096 xUpperLeft
= new FormulaDoubleToken( f
);
1101 xUpperLeft
= new FormulaDoubleToken( f
);
1107 OSL_FAIL("ScMatrixFormulaCellToken::SetUpperLeftDouble: not modifying unhandled token type");
1112 void ScMatrixFormulaCellToken::ResetResult()
1115 xUpperLeft
= nullptr;
1118 ScHybridCellToken::ScHybridCellToken(
1119 double f
, const svl::SharedString
& rStr
, OUString aFormula
, bool bEmptyDisplayedAsString
) :
1120 FormulaToken( formula::svHybridCell
),
1121 mfDouble( f
), maString( rStr
),
1122 maFormula(std::move( aFormula
)),
1123 mbEmptyDisplayedAsString( bEmptyDisplayedAsString
)
1125 // caller, make up your mind...
1126 assert( !bEmptyDisplayedAsString
|| (f
== 0.0 && rStr
.getString().isEmpty()));
1129 double ScHybridCellToken::GetDouble() const { return mfDouble
; }
1131 const svl::SharedString
& ScHybridCellToken::GetString() const
1136 bool ScHybridCellToken::operator==( const FormulaToken
& r
) const
1138 return FormulaToken::operator==( r
) &&
1139 mfDouble
== r
.GetDouble() && maString
== r
.GetString() &&
1140 maFormula
== static_cast<const ScHybridCellToken
&>(r
).GetFormula();
1143 bool ScTokenArray::AddFormulaToken(
1144 const css::sheet::FormulaToken
& rToken
, svl::SharedStringPool
& rSPool
, formula::ExternalReferenceHelper
* pExtRef
)
1146 bool bError
= FormulaTokenArray::AddFormulaToken(rToken
, rSPool
, pExtRef
);
1150 const OpCode eOpCode
= static_cast<OpCode
>(rToken
.OpCode
); // assuming equal values for the moment
1152 const uno::TypeClass eClass
= rToken
.Data
.getValueTypeClass();
1155 case uno::TypeClass_STRUCT
:
1157 uno::Type aType
= rToken
.Data
.getValueType();
1158 if ( aType
.equals( cppu::UnoType
<sheet::SingleReference
>::get() ) )
1160 ScSingleRefData aSingleRef
;
1161 sheet::SingleReference aApiRef
;
1162 rToken
.Data
>>= aApiRef
;
1163 lcl_SingleRefToCalc( aSingleRef
, aApiRef
);
1164 if ( eOpCode
== ocPush
)
1165 AddSingleReference( aSingleRef
);
1166 else if ( eOpCode
== ocColRowName
)
1167 AddColRowName( aSingleRef
);
1171 else if ( aType
.equals( cppu::UnoType
<sheet::ComplexReference
>::get() ) )
1173 ScComplexRefData aComplRef
;
1174 sheet::ComplexReference aApiRef
;
1175 rToken
.Data
>>= aApiRef
;
1176 lcl_SingleRefToCalc( aComplRef
.Ref1
, aApiRef
.Reference1
);
1177 lcl_SingleRefToCalc( aComplRef
.Ref2
, aApiRef
.Reference2
);
1179 if ( eOpCode
== ocPush
)
1180 AddDoubleReference( aComplRef
);
1184 else if ( aType
.equals( cppu::UnoType
<sheet::NameToken
>::get() ) )
1186 sheet::NameToken aTokenData
;
1187 rToken
.Data
>>= aTokenData
;
1188 if ( eOpCode
== ocName
)
1190 SAL_WARN_IF( aTokenData
.Sheet
< -1 || std::numeric_limits
<sal_Int16
>::max() < aTokenData
.Sheet
,
1192 "ScTokenArray::AddFormulaToken - NameToken.Sheet out of limits: " << aTokenData
.Sheet
);
1193 sal_Int16 nSheet
= static_cast<sal_Int16
>(aTokenData
.Sheet
);
1194 AddRangeName(aTokenData
.Index
, nSheet
);
1196 else if (eOpCode
== ocDBArea
)
1197 AddDBRange(aTokenData
.Index
);
1198 else if (eOpCode
== ocTableRef
)
1199 bError
= true; /* TODO: implementation */
1203 else if ( aType
.equals( cppu::UnoType
<sheet::ExternalReference
>::get() ) )
1205 sheet::ExternalReference aApiExtRef
;
1206 if( (eOpCode
== ocPush
) && (rToken
.Data
>>= aApiExtRef
) && (0 <= aApiExtRef
.Index
) && (aApiExtRef
.Index
<= SAL_MAX_UINT16
) )
1208 sal_uInt16 nFileId
= static_cast< sal_uInt16
>( aApiExtRef
.Index
);
1209 sheet::SingleReference aApiSRef
;
1210 sheet::ComplexReference aApiCRef
;
1212 if( aApiExtRef
.Reference
>>= aApiSRef
)
1214 // try to resolve cache index to sheet name
1215 size_t nCacheId
= static_cast< size_t >( aApiSRef
.Sheet
);
1216 OUString aTabName
= pExtRef
->getCacheTableName( nFileId
, nCacheId
);
1217 if( !aTabName
.isEmpty() )
1219 ScSingleRefData aSingleRef
;
1220 // convert column/row settings, set sheet index to absolute
1221 lcl_ExternalRefToCalc( aSingleRef
, aApiSRef
);
1222 AddExternalSingleReference( nFileId
, rSPool
.intern( aTabName
), aSingleRef
);
1227 else if( aApiExtRef
.Reference
>>= aApiCRef
)
1229 // try to resolve cache index to sheet name.
1230 size_t nCacheId
= static_cast< size_t >( aApiCRef
.Reference1
.Sheet
);
1231 OUString aTabName
= pExtRef
->getCacheTableName( nFileId
, nCacheId
);
1232 if( !aTabName
.isEmpty() )
1234 ScComplexRefData aComplRef
;
1235 // convert column/row settings, set sheet index to absolute
1236 lcl_ExternalRefToCalc( aComplRef
.Ref1
, aApiCRef
.Reference1
);
1237 lcl_ExternalRefToCalc( aComplRef
.Ref2
, aApiCRef
.Reference2
);
1238 // NOTE: This assumes that cached sheets are in consecutive order!
1239 aComplRef
.Ref2
.SetAbsTab(
1240 aComplRef
.Ref1
.Tab() + static_cast<SCTAB
>(aApiCRef
.Reference2
.Sheet
- aApiCRef
.Reference1
.Sheet
));
1241 AddExternalDoubleReference( nFileId
, rSPool
.intern( aTabName
), aComplRef
);
1246 else if( aApiExtRef
.Reference
>>= aName
)
1248 if( !aName
.isEmpty() )
1249 AddExternalName( nFileId
, rSPool
.intern( aName
) );
1260 bError
= true; // unknown struct
1263 case uno::TypeClass_SEQUENCE
:
1265 if ( eOpCode
!= ocPush
)
1266 bError
= true; // not an inline array
1267 else if (!rToken
.Data
.getValueType().equals( cppu::UnoType
<
1268 uno::Sequence
< uno::Sequence
< uno::Any
>>>::get()))
1269 bError
= true; // unexpected sequence type
1272 ScMatrixRef xMat
= ScSequenceToMatrix::CreateMixedMatrix( rToken
.Data
);
1287 void ScTokenArray::CheckForThreading( const FormulaToken
& r
)
1289 #if HAVE_CPP_CONSTINIT_SORTED_VECTOR
1292 static const o3tl::sorted_vector
<OpCode
> aThreadedCalcDenyList({
1321 // Don't enable threading once we decided to disable it.
1322 if (!mbThreadingEnabled
)
1325 static const bool bThreadingProhibited
= std::getenv("SC_NO_THREADED_CALCULATION");
1327 if (bThreadingProhibited
)
1329 mbThreadingEnabled
= false;
1333 OpCode eOp
= r
.GetOpCode();
1335 if (aThreadedCalcDenyList
.find(eOp
) != aThreadedCalcDenyList
.end())
1337 SAL_INFO("sc.core.formulagroup", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH
)->getSymbol(eOp
)
1338 << "(" << int(eOp
) << ") disables threaded calculation of formula group");
1339 mbThreadingEnabled
= false;
1346 switch (r
.GetType())
1348 case svExternalDoubleRef
:
1349 case svExternalSingleRef
:
1350 case svExternalName
:
1352 SAL_INFO("sc.core.formulagroup", "opcode ocPush: variable type " << StackVarEnumToString(r
.GetType())
1353 << " disables threaded calculation of formula group");
1354 mbThreadingEnabled
= false;
1361 void ScTokenArray::CheckToken( const FormulaToken
& r
)
1363 if (mbThreadingEnabled
)
1364 CheckForThreading(r
);
1366 if (IsFormulaVectorDisabled())
1367 return; // It's already disabled. No more checking needed.
1369 OpCode eOp
= r
.GetOpCode();
1371 if (SC_OPCODE_START_FUNCTION
<= eOp
&& eOp
< SC_OPCODE_STOP_FUNCTION
)
1373 if (ScInterpreter::GetGlobalConfig().mbOpenCLSubsetOnly
&&
1374 ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes
->find(eOp
) == ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes
->end())
1376 SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH
)->getSymbol(eOp
)
1377 << "(" << int(eOp
) << ") disables vectorisation for formula group");
1378 meVectorState
= FormulaVectorDisabledNotInSubSet
;
1379 mbOpenCLEnabled
= false;
1383 // We support vectorization for the following opcodes.
1419 case ocNegBinomVert
:
1450 case ocPermutationA
:
1566 // Don't change the state.
1569 SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH
)->getSymbol(eOp
)
1570 << "(" << int(eOp
) << ") disables vectorisation for formula group");
1571 meVectorState
= FormulaVectorDisabledByOpCode
;
1572 mbOpenCLEnabled
= false;
1576 else if (eOp
== ocPush
)
1578 // This is a stack variable. See if this is a reference.
1580 switch (r
.GetType())
1585 // Don't change the state.
1589 // Depends on the reference state.
1590 meVectorState
= FormulaVectorCheckReference
;
1595 case svExternalDoubleRef
:
1596 case svExternalName
:
1597 case svExternalSingleRef
:
1609 // We don't support vectorization on these.
1610 SAL_INFO("sc.opencl", "opcode ocPush: variable type " << StackVarEnumToString(r
.GetType()) << " disables vectorisation for formula group");
1611 meVectorState
= FormulaVectorDisabledByStackVariable
;
1612 mbOpenCLEnabled
= false;
1618 else if (SC_OPCODE_START_BIN_OP
<= eOp
&& eOp
< SC_OPCODE_STOP_UN_OP
)
1620 if (ScInterpreter::GetGlobalConfig().mbOpenCLSubsetOnly
&&
1621 ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes
->find(eOp
) == ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes
->end())
1623 SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH
)->getSymbol(eOp
)
1624 << "(" << int(eOp
) << ") disables vectorisation for formula group");
1625 meVectorState
= FormulaVectorDisabledNotInSubSet
;
1626 mbOpenCLEnabled
= false;
1632 // All the rest, special commands, separators, error codes, ...
1636 // Default is off, no vectorization.
1637 // Mentioning some specific values below to indicate why.
1640 // Named expression would need "recursive" handling of its
1641 // token array for vector state in
1642 // ScFormulaCell::InterpretFormulaGroup() and below.
1645 // Certainly not a vectorization of the entire area...
1648 // May result in a single cell or range reference, depending on
1652 // The associated reference is the name cell with which to
1653 // create the implicit intersection.
1655 case ocColRowNameAuto
:
1656 // Auto column/row names lead to references computed in
1659 SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH
)->getSymbol(eOp
)
1660 << "(" << int(eOp
) << ") disables vectorisation for formula group");
1661 meVectorState
= FormulaVectorDisabledByOpCode
;
1662 mbOpenCLEnabled
= false;
1665 // Known good, don't change state.
1694 // Jump commands are now supported.
1700 bool ScTokenArray::ImplGetReference( ScRange
& rRange
, const ScAddress
& rPos
, bool bValidOnly
) const
1703 if ( pCode
&& nLen
== 1 )
1705 const FormulaToken
* pToken
= pCode
[0];
1708 if ( pToken
->GetType() == svSingleRef
)
1710 const ScSingleRefData
& rRef
= *static_cast<const ScSingleRefToken
*>(pToken
)->GetSingleRef();
1711 rRange
.aStart
= rRange
.aEnd
= rRef
.toAbs(*mxSheetLimits
, rPos
);
1712 bIs
= !bValidOnly
|| mxSheetLimits
->ValidAddress(rRange
.aStart
);
1714 else if ( pToken
->GetType() == svDoubleRef
)
1716 const ScComplexRefData
& rCompl
= *static_cast<const ScDoubleRefToken
*>(pToken
)->GetDoubleRef();
1717 const ScSingleRefData
& rRef1
= rCompl
.Ref1
;
1718 const ScSingleRefData
& rRef2
= rCompl
.Ref2
;
1719 rRange
.aStart
= rRef1
.toAbs(*mxSheetLimits
, rPos
);
1720 rRange
.aEnd
= rRef2
.toAbs(*mxSheetLimits
, rPos
);
1721 bIs
= !bValidOnly
|| mxSheetLimits
->ValidRange(rRange
);
1730 // we want to compare for similar not identical formulae
1731 // so we can't use actual row & column indices.
1732 size_t HashSingleRef( const ScSingleRefData
& rRef
)
1736 nVal
+= size_t(rRef
.IsColRel());
1737 nVal
+= (size_t(rRef
.IsRowRel()) << 1);
1738 nVal
+= (size_t(rRef
.IsTabRel()) << 2);
1745 void ScTokenArray::GenHash()
1747 static const OUStringHash aHasher
;
1752 const formula::FormulaToken
* p
;
1753 sal_uInt16 n
= std::min
<sal_uInt16
>(nLen
, 20);
1754 for (sal_uInt16 i
= 0; i
< n
; ++i
)
1757 eOp
= p
->GetOpCode();
1760 // This is stack variable. Do additional differentiation.
1761 eType
= p
->GetType();
1767 sal_uInt8 nVal
= p
->GetByte();
1768 nHash
+= static_cast<size_t>(nVal
);
1774 double fVal
= p
->GetDouble();
1775 nHash
+= std::hash
<double>()(fVal
);
1781 OUString aStr
= p
->GetString().getString();
1782 nHash
+= aHasher(aStr
);
1787 size_t nVal
= HashSingleRef(*p
->GetSingleRef());
1793 const ScComplexRefData
& rRef
= *p
->GetDoubleRef();
1794 size_t nVal1
= HashSingleRef(rRef
.Ref1
);
1795 size_t nVal2
= HashSingleRef(rRef
.Ref2
);
1801 // Use the opcode value in all the other cases.
1802 nHash
+= static_cast<size_t>(eOp
);
1806 // Use the opcode value in all the other cases.
1807 nHash
+= static_cast<size_t>(eOp
);
1809 nHash
= (nHash
<< 4) - nHash
;
1812 mnHashValue
= nHash
;
1815 void ScTokenArray::ResetVectorState()
1817 mbOpenCLEnabled
= ScCalcConfig::isOpenCLEnabled();
1818 meVectorState
= mbOpenCLEnabled
? FormulaVectorEnabled
: FormulaVectorDisabled
;
1819 mbThreadingEnabled
= ScCalcConfig::isThreadingEnabled();
1822 bool ScTokenArray::IsFormulaVectorDisabled() const
1824 switch (meVectorState
)
1826 case FormulaVectorDisabled
:
1827 case FormulaVectorDisabledByOpCode
:
1828 case FormulaVectorDisabledByStackVariable
:
1829 case FormulaVectorDisabledNotInSubSet
:
1838 bool ScTokenArray::IsInvariant() const
1840 FormulaToken
** p
= pCode
.get();
1841 FormulaToken
** pEnd
= p
+ static_cast<size_t>(nLen
);
1842 for (; p
!= pEnd
; ++p
)
1844 switch ((*p
)->GetType())
1847 case svExternalSingleRef
:
1849 const ScSingleRefData
& rRef
= *(*p
)->GetSingleRef();
1850 if (rRef
.IsRowRel())
1855 case svExternalDoubleRef
:
1857 const ScComplexRefData
& rRef
= *(*p
)->GetDoubleRef();
1858 if (rRef
.Ref1
.IsRowRel() || rRef
.Ref2
.IsRowRel())
1872 bool ScTokenArray::IsReference( ScRange
& rRange
, const ScAddress
& rPos
) const
1874 return ImplGetReference(rRange
, rPos
, false);
1877 bool ScTokenArray::IsValidReference( ScRange
& rRange
, const ScAddress
& rPos
) const
1879 return ImplGetReference(rRange
, rPos
, true);
1882 ScTokenArray::ScTokenArray(const ScDocument
& rDoc
) :
1883 mxSheetLimits(&rDoc
.GetSheetLimits()),
1889 ScTokenArray::ScTokenArray(ScSheetLimits
& rLimits
) :
1890 mxSheetLimits(&rLimits
),
1896 ScTokenArray::~ScTokenArray()
1900 ScTokenArray
& ScTokenArray::operator=( const ScTokenArray
& rArr
)
1904 mnHashValue
= rArr
.mnHashValue
;
1905 meVectorState
= rArr
.meVectorState
;
1906 mbOpenCLEnabled
= rArr
.mbOpenCLEnabled
;
1907 mbThreadingEnabled
= rArr
.mbThreadingEnabled
;
1911 ScTokenArray
& ScTokenArray::operator=( ScTokenArray
&& rArr
)
1913 mxSheetLimits
= std::move(rArr
.mxSheetLimits
);
1914 mnHashValue
= rArr
.mnHashValue
;
1915 meVectorState
= rArr
.meVectorState
;
1916 mbOpenCLEnabled
= rArr
.mbOpenCLEnabled
;
1917 mbThreadingEnabled
= rArr
.mbThreadingEnabled
;
1918 Move(std::move(rArr
));
1922 bool ScTokenArray::EqualTokens( const ScTokenArray
* pArr2
) const
1924 // We only compare the non-RPN array
1925 if ( pArr2
->nLen
!= nLen
)
1928 FormulaToken
** ppToken1
= GetArray();
1929 FormulaToken
** ppToken2
= pArr2
->GetArray();
1930 for (sal_uInt16 i
=0; i
<nLen
; i
++)
1932 if ( ppToken1
[i
] != ppToken2
[i
] &&
1933 !(*ppToken1
[i
] == *ppToken2
[i
]) )
1934 return false; // Difference
1936 return true; // All entries are the same
1939 void ScTokenArray::Clear()
1943 FormulaTokenArray::Clear();
1946 std::unique_ptr
<ScTokenArray
> ScTokenArray::Clone() const
1948 std::unique_ptr
<ScTokenArray
> p(new ScTokenArray(*mxSheetLimits
));
1953 p
->bHyperLink
= bHyperLink
;
1954 p
->mnHashValue
= mnHashValue
;
1955 p
->meVectorState
= meVectorState
;
1956 p
->mbOpenCLEnabled
= mbOpenCLEnabled
;
1957 p
->mbThreadingEnabled
= mbThreadingEnabled
;
1958 p
->mbFromRangeName
= mbFromRangeName
;
1959 p
->mbShareable
= mbShareable
;
1964 p
->pCode
.reset(new FormulaToken
*[ nLen
]);
1965 pp
= p
->pCode
.get();
1966 memcpy( pp
, pCode
.get(), nLen
* sizeof( formula::FormulaToken
* ) );
1967 for( sal_uInt16 i
= 0; i
< nLen
; i
++, pp
++ )
1969 *pp
= (*pp
)->Clone();
1975 pp
= p
->pRPN
= new FormulaToken
*[ nRPN
];
1976 memcpy( pp
, pRPN
, nRPN
* sizeof( formula::FormulaToken
* ) );
1977 for( sal_uInt16 i
= 0; i
< nRPN
; i
++, pp
++ )
1979 FormulaToken
* t
= *pp
;
1980 if( t
->GetRef() > 1 )
1982 FormulaToken
** p2
= pCode
.get();
1983 sal_uInt16 nIdx
= 0xFFFF;
1984 for( sal_uInt16 j
= 0; j
< nLen
; j
++, p2
++ )
1991 if( nIdx
== 0xFFFF )
1994 *pp
= p
->pCode
[ nIdx
];
2004 ScTokenArray
ScTokenArray::CloneValue() const
2006 ScTokenArray
aNew(*mxSheetLimits
);
2010 aNew
.nError
= nError
;
2011 aNew
.bHyperLink
= bHyperLink
;
2012 aNew
.mnHashValue
= mnHashValue
;
2013 aNew
.meVectorState
= meVectorState
;
2014 aNew
.mbOpenCLEnabled
= mbOpenCLEnabled
;
2015 aNew
.mbThreadingEnabled
= mbThreadingEnabled
;
2016 aNew
.mbFromRangeName
= mbFromRangeName
;
2017 aNew
.mbShareable
= mbShareable
;
2022 aNew
.pCode
.reset(new FormulaToken
*[ nLen
]);
2023 pp
= aNew
.pCode
.get();
2024 memcpy( pp
, pCode
.get(), nLen
* sizeof( formula::FormulaToken
* ) );
2025 for( sal_uInt16 i
= 0; i
< nLen
; i
++, pp
++ )
2027 *pp
= (*pp
)->Clone();
2033 pp
= aNew
.pRPN
= new FormulaToken
*[ nRPN
];
2034 memcpy( pp
, pRPN
, nRPN
* sizeof( formula::FormulaToken
* ) );
2035 for( sal_uInt16 i
= 0; i
< nRPN
; i
++, pp
++ )
2037 FormulaToken
* t
= *pp
;
2038 if( t
->GetRef() > 1 )
2040 FormulaToken
** p2
= pCode
.get();
2041 sal_uInt16 nIdx
= 0xFFFF;
2042 for( sal_uInt16 j
= 0; j
< nLen
; j
++, p2
++ )
2049 if( nIdx
== 0xFFFF )
2052 *pp
= aNew
.pCode
[ nIdx
];
2062 FormulaToken
* ScTokenArray::AddRawToken( const ScRawToken
& r
)
2064 return Add( r
.CreateToken(*mxSheetLimits
) );
2067 // Utility function to ensure that there is strict alternation of values and
2070 checkArraySep( bool & bPrevWasSep
, bool bNewVal
)
2072 bool bResult
= (bPrevWasSep
== bNewVal
);
2073 bPrevWasSep
= bNewVal
;
2077 FormulaToken
* ScTokenArray::MergeArray( )
2079 int nCol
= -1, nRow
= 0;
2080 int i
, nPrevRowSep
= -1, nStart
= 0;
2081 bool bPrevWasSep
= false; // top of stack is ocArrayClose
2083 bool bNumeric
= false; // numeric value encountered in current element
2085 // (1) Iterate from the end to the start to find matrix dims
2086 // and do basic validation.
2087 for ( i
= nLen
; i
-- > nStart
; )
2090 switch ( t
->GetOpCode() )
2093 if( checkArraySep( bPrevWasSep
, false ) )
2098 // no references or nested arrays
2099 if ( t
->GetType() != svDouble
&& t
->GetType() != svString
)
2103 bNumeric
= (t
->GetType() == svDouble
);
2109 if( checkArraySep( bPrevWasSep
, false ) )
2116 case ocArrayColSep
:
2118 if( checkArraySep( bPrevWasSep
, true ) )
2126 // not possible with the , but check just in case
2127 // something changes in the future
2133 if( checkArraySep( bPrevWasSep
, true ) )
2143 nStart
= i
; // stop iteration
2144 [[fallthrough
]]; // to ArrayRowSep
2146 case ocArrayRowSep
:
2147 if( checkArraySep( bPrevWasSep
, true ) )
2152 if( nPrevRowSep
< 0 || // missing ocArrayClose
2153 ((nPrevRowSep
- i
) % 2) == 1) // no complex elements
2160 nCol
= (nPrevRowSep
- i
) / 2;
2162 else if( (nPrevRowSep
- i
)/2 != nCol
) // irregular array
2174 // negation or unary plus must precede numeric value
2179 --nPrevRowSep
; // shorten this row by 1
2180 bNumeric
= false; // one level only, no --42
2186 --nPrevRowSep
; // shorten this row by 1
2190 // no functions or operators
2194 if( nCol
<= 0 || nRow
<= 0 )
2198 ScMatrix
* pArray
= new ScMatrix(nCol
, nRow
, 0.0);
2199 for ( i
= nStart
, nCol
= 0, nRow
= 0 ; i
< nLen
; i
++ )
2203 switch ( t
->GetOpCode() )
2206 if ( t
->GetType() == svDouble
)
2208 pArray
->PutDouble( t
->GetDouble() * nSign
, nCol
, nRow
);
2211 else if ( t
->GetType() == svString
)
2213 pArray
->PutString(t
->GetString(), nCol
, nRow
);
2218 pArray
->PutEmpty( nCol
, nRow
);
2222 pArray
->PutBoolean( true, nCol
, nRow
);
2226 pArray
->PutBoolean( false, nCol
, nRow
);
2229 case ocArrayColSep
:
2234 case ocArrayRowSep
:
2248 nLen
= sal_uInt16( nStart
);
2249 return AddMatrix( pArray
);
2252 void ScTokenArray::MergeRangeReference( const ScAddress
& rPos
)
2254 if (!pCode
|| !nLen
)
2256 sal_uInt16 nIdx
= nLen
;
2258 // The actual types are checked in extendRangeReference().
2259 FormulaToken
*p3
= PeekPrev(nIdx
); // ref
2262 FormulaToken
*p2
= PeekPrev(nIdx
); // ocRange
2263 if (!p2
|| p2
->GetOpCode() != ocRange
)
2265 FormulaToken
*p1
= PeekPrev(nIdx
); // ref
2268 FormulaTokenRef p
= extendRangeReference( *mxSheetLimits
, *p1
, *p3
, rPos
, true);
2276 pCode
[ nLen
-1 ] = p
.get();
2280 FormulaToken
* ScTokenArray::AddOpCode( OpCode e
)
2284 return AddRawToken( t
);
2287 FormulaToken
* ScTokenArray::AddSingleReference( const ScSingleRefData
& rRef
)
2289 return Add( new ScSingleRefToken( *mxSheetLimits
, rRef
) );
2292 FormulaToken
* ScTokenArray::AddMatrixSingleReference( const ScSingleRefData
& rRef
)
2294 return Add( new ScSingleRefToken(*mxSheetLimits
, rRef
, ocMatRef
) );
2297 FormulaToken
* ScTokenArray::AddDoubleReference( const ScComplexRefData
& rRef
)
2299 return Add( new ScDoubleRefToken(*mxSheetLimits
, rRef
) );
2302 FormulaToken
* ScTokenArray::AddMatrix( const ScMatrixRef
& p
)
2304 return Add( new ScMatrixToken( p
) );
2307 void ScTokenArray::AddRangeName( sal_uInt16 n
, sal_Int16 nSheet
)
2309 Add( new FormulaIndexToken( ocName
, n
, nSheet
));
2312 FormulaToken
* ScTokenArray::AddDBRange( sal_uInt16 n
)
2314 return Add( new FormulaIndexToken( ocDBArea
, n
));
2317 FormulaToken
* ScTokenArray::AddExternalName( sal_uInt16 nFileId
, const svl::SharedString
& rName
)
2319 return Add( new ScExternalNameToken(nFileId
, rName
) );
2322 void ScTokenArray::AddExternalSingleReference( sal_uInt16 nFileId
, const svl::SharedString
& rTabName
,
2323 const ScSingleRefData
& rRef
)
2325 Add( new ScExternalSingleRefToken(nFileId
, rTabName
, rRef
) );
2328 FormulaToken
* ScTokenArray::AddExternalDoubleReference( sal_uInt16 nFileId
, const svl::SharedString
& rTabName
,
2329 const ScComplexRefData
& rRef
)
2331 return Add( new ScExternalDoubleRefToken(nFileId
, rTabName
, rRef
) );
2334 FormulaToken
* ScTokenArray::AddColRowName( const ScSingleRefData
& rRef
)
2336 return Add( new ScSingleRefToken(*mxSheetLimits
, rRef
, ocColRowName
) );
2339 void ScTokenArray::AssignXMLString( const OUString
&rText
, const OUString
&rFormulaNmsp
)
2341 sal_uInt16 nTokens
= 1;
2342 FormulaToken
*aTokens
[2];
2344 aTokens
[0] = new FormulaStringOpToken( ocStringXML
, svl::SharedString( rText
) ); // string not interned
2345 if( !rFormulaNmsp
.isEmpty() )
2346 aTokens
[ nTokens
++ ] = new FormulaStringOpToken( ocStringXML
,
2347 svl::SharedString( rFormulaNmsp
) ); // string not interned
2349 Assign( nTokens
, aTokens
);
2352 bool ScTokenArray::GetAdjacentExtendOfOuterFuncRefs( SCCOLROW
& nExtend
,
2353 const ScAddress
& rPos
, ScDirection eDir
)
2360 if ( rPos
.Row() >= mxSheetLimits
->mnMaxRow
)
2362 nExtend
= rPos
.Row();
2366 if ( rPos
.Col() >= mxSheetLimits
->mnMaxCol
)
2368 nExtend
= rPos
.Col();
2369 nCol
= static_cast<SCCOL
>(nExtend
) + 1;
2372 if ( rPos
.Row() <= 0 )
2374 nExtend
= rPos
.Row();
2378 if ( rPos
.Col() <= 0 )
2380 nExtend
= rPos
.Col();
2381 nCol
= static_cast<SCCOL
>(nExtend
) - 1;
2384 OSL_FAIL( "unknown Direction" );
2389 FormulaToken
* t
= pRPN
[nRPN
-1];
2390 if ( t
->GetType() == svByte
)
2392 sal_uInt8 nParamCount
= t
->GetByte();
2393 if ( nParamCount
&& nRPN
> nParamCount
)
2396 sal_uInt16 nParam
= nRPN
- nParamCount
- 1;
2397 for ( ; nParam
< nRPN
-1; nParam
++ )
2399 FormulaToken
* p
= pRPN
[nParam
];
2400 switch ( p
->GetType() )
2404 ScSingleRefData
& rRef
= *p
->GetSingleRef();
2405 ScAddress aAbs
= rRef
.toAbs(*mxSheetLimits
, rPos
);
2409 if (aAbs
.Row() == nRow
&& aAbs
.Row() > nExtend
)
2411 nExtend
= aAbs
.Row();
2416 if (aAbs
.Col() == nCol
&& static_cast<SCCOLROW
>(aAbs
.Col()) > nExtend
)
2418 nExtend
= aAbs
.Col();
2423 if (aAbs
.Row() == nRow
&& aAbs
.Row() < nExtend
)
2425 nExtend
= aAbs
.Row();
2430 if (aAbs
.Col() == nCol
&& static_cast<SCCOLROW
>(aAbs
.Col()) < nExtend
)
2432 nExtend
= aAbs
.Col();
2441 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
2442 ScRange aAbs
= rRef
.toAbs(*mxSheetLimits
, rPos
);
2446 if (aAbs
.aStart
.Row() == nRow
&& aAbs
.aEnd
.Row() > nExtend
)
2448 nExtend
= aAbs
.aEnd
.Row();
2453 if (aAbs
.aStart
.Col() == nCol
&& static_cast<SCCOLROW
>(aAbs
.aEnd
.Col()) > nExtend
)
2455 nExtend
= aAbs
.aEnd
.Col();
2460 if (aAbs
.aEnd
.Row() == nRow
&& aAbs
.aStart
.Row() < nExtend
)
2462 nExtend
= aAbs
.aStart
.Row();
2467 if (aAbs
.aEnd
.Col() == nCol
&& static_cast<SCCOLROW
>(aAbs
.aStart
.Col()) < nExtend
)
2469 nExtend
= aAbs
.aStart
.Col();
2478 // added to avoid warnings
2491 void GetExternalTableData(const ScDocument
* pOldDoc
, const ScDocument
* pNewDoc
, const SCTAB nTab
, OUString
& rTabName
, sal_uInt16
& rFileId
)
2493 const OUString
& aFileName
= pOldDoc
->GetFileURL();
2494 rFileId
= pNewDoc
->GetExternalRefManager()->getExternalFileId(aFileName
);
2495 rTabName
= pOldDoc
->GetCopyTabName(nTab
);
2496 if (rTabName
.isEmpty())
2497 pOldDoc
->GetName(nTab
, rTabName
);
2500 bool IsInCopyRange( const ScRange
& rRange
, const ScDocument
* pClipDoc
)
2502 ScClipParam
& rClipParam
= const_cast<ScDocument
*>(pClipDoc
)->GetClipParam();
2503 return rClipParam
.maRanges
.Contains(rRange
);
2506 bool SkipReference(formula::FormulaToken
* pToken
, const ScAddress
& rPos
, const ScDocument
& rOldDoc
, bool bRangeName
, bool bCheckCopyArea
)
2510 if (!ScRefTokenHelper::getRangeFromToken(&rOldDoc
, aRange
, pToken
, rPos
))
2513 if (bRangeName
&& aRange
.aStart
.Tab() == rPos
.Tab())
2515 switch (pToken
->GetType())
2519 ScSingleRefData
& rRef
= *pToken
->GetSingleRef2();
2520 if (rRef
.IsColRel() || rRef
.IsRowRel())
2526 ScSingleRefData
& rRef
= *pToken
->GetSingleRef();
2527 if (rRef
.IsColRel() || rRef
.IsRowRel())
2536 if (bCheckCopyArea
&& IsInCopyRange(aRange
, &rOldDoc
))
2542 void AdjustSingleRefData( ScSingleRefData
& rRef
, const ScAddress
& rOldPos
, const ScAddress
& rNewPos
)
2544 SCCOL nCols
= rNewPos
.Col() - rOldPos
.Col();
2545 SCROW nRows
= rNewPos
.Row() - rOldPos
.Row();
2546 SCTAB nTabs
= rNewPos
.Tab() - rOldPos
.Tab();
2548 if (!rRef
.IsColRel())
2551 if (!rRef
.IsRowRel())
2554 if (!rRef
.IsTabRel())
2560 void ScTokenArray::ReadjustAbsolute3DReferences( const ScDocument
& rOldDoc
, ScDocument
& rNewDoc
, const ScAddress
& rPos
, bool bRangeName
)
2562 for ( sal_uInt16 j
=0; j
<nLen
; ++j
)
2564 switch ( pCode
[j
]->GetType() )
2568 if (SkipReference(pCode
[j
], rPos
, rOldDoc
, bRangeName
, true))
2571 ScComplexRefData
& rRef
= *pCode
[j
]->GetDoubleRef();
2572 ScSingleRefData
& rRef2
= rRef
.Ref2
;
2573 ScSingleRefData
& rRef1
= rRef
.Ref1
;
2575 if ( (rRef2
.IsFlag3D() && !rRef2
.IsTabRel()) || (rRef1
.IsFlag3D() && !rRef1
.IsTabRel()) )
2579 GetExternalTableData(&rOldDoc
, &rNewDoc
, rRef1
.Tab(), aTabName
, nFileId
);
2580 ReplaceToken( j
, new ScExternalDoubleRefToken( nFileId
,
2581 rNewDoc
.GetSharedStringPool().intern( aTabName
), rRef
), CODE_AND_RPN
);
2582 // ATTENTION: rRef can't be used after this point
2588 if (SkipReference(pCode
[j
], rPos
, rOldDoc
, bRangeName
, true))
2591 ScSingleRefData
& rRef
= *pCode
[j
]->GetSingleRef();
2593 if ( rRef
.IsFlag3D() && !rRef
.IsTabRel() )
2597 GetExternalTableData(&rOldDoc
, &rNewDoc
, rRef
.Tab(), aTabName
, nFileId
);
2598 ReplaceToken( j
, new ScExternalSingleRefToken( nFileId
,
2599 rNewDoc
.GetSharedStringPool().intern( aTabName
), rRef
), CODE_AND_RPN
);
2600 // ATTENTION: rRef can't be used after this point
2606 // added to avoid warnings
2612 void ScTokenArray::AdjustAbsoluteRefs( const ScDocument
& rOldDoc
, const ScAddress
& rOldPos
, const ScAddress
& rNewPos
,
2613 bool bCheckCopyRange
)
2615 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
, true);
2616 for (size_t j
=0; j
<2; ++j
)
2618 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
2619 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
2620 for (; pp
!= pEnd
; ++pp
)
2622 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
2626 switch ( p
->GetType() )
2630 if (!SkipReference(p
, rOldPos
, rOldDoc
, false, bCheckCopyRange
))
2633 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
2634 ScSingleRefData
& rRef2
= rRef
.Ref2
;
2635 ScSingleRefData
& rRef1
= rRef
.Ref1
;
2637 AdjustSingleRefData( rRef1
, rOldPos
, rNewPos
);
2638 AdjustSingleRefData( rRef2
, rOldPos
, rNewPos
);
2643 if (!SkipReference(p
, rOldPos
, rOldDoc
, false, bCheckCopyRange
))
2646 ScSingleRefData
& rRef
= *p
->GetSingleRef();
2648 AdjustSingleRefData( rRef
, rOldPos
, rNewPos
);
2653 // added to avoid warnings
2660 void ScTokenArray::AdjustSheetLocalNameReferences( SCTAB nOldTab
, SCTAB nNewTab
)
2662 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
, false);
2663 for (size_t j
=0; j
<2; ++j
)
2665 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
2666 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
2667 for (; pp
!= pEnd
; ++pp
)
2669 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
2673 switch ( p
->GetType() )
2677 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
2678 ScSingleRefData
& rRef2
= rRef
.Ref2
;
2679 ScSingleRefData
& rRef1
= rRef
.Ref1
;
2681 if (!rRef1
.IsTabRel() && rRef1
.Tab() == nOldTab
)
2682 rRef1
.SetAbsTab( nNewTab
);
2683 if (!rRef2
.IsTabRel() && rRef2
.Tab() == nOldTab
)
2684 rRef2
.SetAbsTab( nNewTab
);
2685 if (!rRef1
.IsTabRel() && !rRef2
.IsTabRel() && rRef1
.Tab() > rRef2
.Tab())
2687 SCTAB nTab
= rRef1
.Tab();
2688 rRef1
.SetAbsTab( rRef2
.Tab());
2689 rRef2
.SetAbsTab( nTab
);
2695 ScSingleRefData
& rRef
= *p
->GetSingleRef();
2697 if (!rRef
.IsTabRel() && rRef
.Tab() == nOldTab
)
2698 rRef
.SetAbsTab( nNewTab
);
2708 bool ScTokenArray::ReferencesSheet( SCTAB nTab
, SCTAB nPosTab
) const
2710 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
, false);
2711 for (size_t j
=0; j
<2; ++j
)
2713 FormulaToken
* const * pp
= aPtrs
.maPointerRange
[j
].mpStart
;
2714 FormulaToken
* const * const pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
2715 for (; pp
!= pEnd
; ++pp
)
2717 const FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
2721 switch ( p
->GetType() )
2725 const ScComplexRefData
& rRef
= *p
->GetDoubleRef();
2726 const ScSingleRefData
& rRef2
= rRef
.Ref2
;
2727 const ScSingleRefData
& rRef1
= rRef
.Ref1
;
2729 SCTAB nTab1
= (rRef1
.IsTabRel() ? rRef1
.Tab() + nPosTab
: rRef1
.Tab());
2730 SCTAB nTab2
= (rRef2
.IsTabRel() ? rRef2
.Tab() + nPosTab
: rRef2
.Tab());
2731 if (nTab1
<= nTab
&& nTab
<= nTab2
)
2737 const ScSingleRefData
& rRef
= *p
->GetSingleRef();
2738 if (rRef
.IsTabRel())
2740 if (rRef
.Tab() + nPosTab
== nTab
)
2745 if (rRef
.Tab() == nTab
)
2760 ScRange
getSelectedRange( const sc::RefUpdateContext
& rCxt
)
2762 ScRange
aSelectedRange(ScAddress::INITIALIZE_INVALID
);
2763 if (rCxt
.mnColDelta
< 0)
2765 // Delete and shift to left.
2766 aSelectedRange
.aStart
= ScAddress(rCxt
.maRange
.aStart
.Col()+rCxt
.mnColDelta
, rCxt
.maRange
.aStart
.Row(), rCxt
.maRange
.aStart
.Tab());
2767 aSelectedRange
.aEnd
= ScAddress(rCxt
.maRange
.aStart
.Col()-1, rCxt
.maRange
.aEnd
.Row(), rCxt
.maRange
.aEnd
.Tab());
2769 else if (rCxt
.mnRowDelta
< 0)
2771 // Delete and shift up.
2772 aSelectedRange
.aStart
= ScAddress(rCxt
.maRange
.aStart
.Col(), rCxt
.maRange
.aStart
.Row()+rCxt
.mnRowDelta
, rCxt
.maRange
.aStart
.Tab());
2773 aSelectedRange
.aEnd
= ScAddress(rCxt
.maRange
.aEnd
.Col(), rCxt
.maRange
.aStart
.Row()-1, rCxt
.maRange
.aEnd
.Tab());
2775 else if (rCxt
.mnTabDelta
< 0)
2778 // TODO : Figure out what to do here.
2780 else if (rCxt
.mnColDelta
> 0)
2782 // Insert and shift to the right.
2783 aSelectedRange
.aStart
= rCxt
.maRange
.aStart
;
2784 aSelectedRange
.aEnd
= ScAddress(rCxt
.maRange
.aStart
.Col()+rCxt
.mnColDelta
-1, rCxt
.maRange
.aEnd
.Row(), rCxt
.maRange
.aEnd
.Tab());
2786 else if (rCxt
.mnRowDelta
> 0)
2788 // Insert and shift down.
2789 aSelectedRange
.aStart
= rCxt
.maRange
.aStart
;
2790 aSelectedRange
.aEnd
= ScAddress(rCxt
.maRange
.aEnd
.Col(), rCxt
.maRange
.aStart
.Row()+rCxt
.mnRowDelta
-1, rCxt
.maRange
.aEnd
.Tab());
2792 else if (rCxt
.mnTabDelta
> 0)
2794 // Inserting sheets.
2795 // TODO : Figure out what to do here.
2798 return aSelectedRange
;
2801 void setRefDeleted( ScSingleRefData
& rRef
, const sc::RefUpdateContext
& rCxt
)
2803 if (rCxt
.mnColDelta
< 0)
2804 rRef
.SetColDeleted(true);
2805 else if (rCxt
.mnRowDelta
< 0)
2806 rRef
.SetRowDeleted(true);
2807 else if (rCxt
.mnTabDelta
< 0)
2808 rRef
.SetTabDeleted(true);
2811 void restoreDeletedRef( ScSingleRefData
& rRef
, const sc::RefUpdateContext
& rCxt
)
2813 if (rCxt
.mnColDelta
)
2815 if (rRef
.IsColDeleted())
2816 rRef
.SetColDeleted(false);
2818 else if (rCxt
.mnRowDelta
)
2820 if (rRef
.IsRowDeleted())
2821 rRef
.SetRowDeleted(false);
2823 else if (rCxt
.mnTabDelta
)
2825 if (rRef
.IsTabDeleted())
2826 rRef
.SetTabDeleted(false);
2830 void setRefDeleted( ScComplexRefData
& rRef
, const sc::RefUpdateContext
& rCxt
)
2832 if (rCxt
.mnColDelta
< 0)
2834 rRef
.Ref1
.SetColDeleted(true);
2835 rRef
.Ref2
.SetColDeleted(true);
2837 else if (rCxt
.mnRowDelta
< 0)
2839 rRef
.Ref1
.SetRowDeleted(true);
2840 rRef
.Ref2
.SetRowDeleted(true);
2842 else if (rCxt
.mnTabDelta
< 0)
2844 rRef
.Ref1
.SetTabDeleted(true);
2845 rRef
.Ref2
.SetTabDeleted(true);
2849 void restoreDeletedRef( ScComplexRefData
& rRef
, const sc::RefUpdateContext
& rCxt
)
2851 restoreDeletedRef(rRef
.Ref1
, rCxt
);
2852 restoreDeletedRef(rRef
.Ref2
, rCxt
);
2862 ShrinkResult
shrinkRange( const sc::RefUpdateContext
& rCxt
, ScRange
& rRefRange
, const ScRange
& rDeletedRange
,
2863 const ScComplexRefData
& rRef
)
2865 if (!rDeletedRange
.Intersects(rRefRange
))
2868 if (rCxt
.mnColDelta
< 0)
2870 if (rRef
.IsEntireRow(rCxt
.mrDoc
.GetSheetLimits()))
2871 // Entire rows are not affected, columns are anchored.
2875 if (rRefRange
.aStart
.Row() < rDeletedRange
.aStart
.Row() || rDeletedRange
.aEnd
.Row() < rRefRange
.aEnd
.Row())
2876 // Deleted range is only partially overlapping in vertical direction. Bail out.
2879 if (rDeletedRange
.aStart
.Col() <= rRefRange
.aStart
.Col())
2881 if (rRefRange
.aEnd
.Col() <= rDeletedRange
.aEnd
.Col())
2883 // Reference is entirely deleted.
2884 rRefRange
.SetInvalid();
2888 // The reference range is truncated on the left.
2889 SCCOL nOffset
= rDeletedRange
.aStart
.Col() - rRefRange
.aStart
.Col();
2890 SCCOL nDelta
= rRefRange
.aStart
.Col() - rDeletedRange
.aEnd
.Col() - 1;
2891 rRefRange
.IncEndColSticky(rCxt
.mrDoc
, nDelta
+nOffset
);
2892 rRefRange
.aStart
.IncCol(nOffset
);
2895 else if (rDeletedRange
.aEnd
.Col() < rRefRange
.aEnd
.Col())
2897 if (rRefRange
.IsEndColSticky(rCxt
.mrDoc
))
2898 // Sticky end not affected.
2901 // Reference is deleted in the middle. Move the last column
2902 // position to the left.
2903 SCCOL nDelta
= rDeletedRange
.aStart
.Col() - rDeletedRange
.aEnd
.Col() - 1;
2904 rRefRange
.IncEndColSticky(rCxt
.mrDoc
, nDelta
);
2908 if (rRefRange
.IsEndColSticky(rCxt
.mrDoc
))
2909 // Sticky end not affected.
2912 // The reference range is truncated on the right.
2913 SCCOL nDelta
= rDeletedRange
.aStart
.Col() - rRefRange
.aEnd
.Col() - 1;
2914 rRefRange
.IncEndColSticky(rCxt
.mrDoc
, nDelta
);
2918 else if (rCxt
.mnRowDelta
< 0)
2920 if (rRef
.IsEntireCol(rCxt
.mrDoc
.GetSheetLimits()))
2921 // Entire columns are not affected, rows are anchored.
2926 if (rRefRange
.aStart
.Col() < rDeletedRange
.aStart
.Col() || rDeletedRange
.aEnd
.Col() < rRefRange
.aEnd
.Col())
2927 // Deleted range is only partially overlapping in horizontal direction. Bail out.
2930 if (rDeletedRange
.aStart
.Row() <= rRefRange
.aStart
.Row())
2932 if (rRefRange
.aEnd
.Row() <= rDeletedRange
.aEnd
.Row())
2934 // Reference is entirely deleted.
2935 rRefRange
.SetInvalid();
2939 // The reference range is truncated on the top.
2940 SCROW nOffset
= rDeletedRange
.aStart
.Row() - rRefRange
.aStart
.Row();
2941 SCROW nDelta
= rRefRange
.aStart
.Row() - rDeletedRange
.aEnd
.Row() - 1;
2942 rRefRange
.IncEndRowSticky(rCxt
.mrDoc
, nDelta
+nOffset
);
2943 rRefRange
.aStart
.IncRow(nOffset
);
2946 else if (rDeletedRange
.aEnd
.Row() < rRefRange
.aEnd
.Row())
2948 if (rRefRange
.IsEndRowSticky(rCxt
.mrDoc
))
2949 // Sticky end not affected.
2952 // Reference is deleted in the middle. Move the last row
2954 SCROW nDelta
= rDeletedRange
.aStart
.Row() - rDeletedRange
.aEnd
.Row() - 1;
2955 rRefRange
.IncEndRowSticky(rCxt
.mrDoc
, nDelta
);
2959 if (rRefRange
.IsEndRowSticky(rCxt
.mrDoc
))
2960 // Sticky end not affected.
2963 // The reference range is truncated on the bottom.
2964 SCROW nDelta
= rDeletedRange
.aStart
.Row() - rRefRange
.aEnd
.Row() - 1;
2965 rRefRange
.IncEndRowSticky(rCxt
.mrDoc
, nDelta
);
2973 bool expandRange( const sc::RefUpdateContext
& rCxt
, ScRange
& rRefRange
, const ScRange
& rSelectedRange
,
2974 const ScComplexRefData
& rRef
)
2976 if (!rSelectedRange
.Intersects(rRefRange
))
2979 if (rCxt
.mnColDelta
> 0)
2981 if (rRef
.IsEntireRow(rCxt
.mrDoc
.GetSheetLimits()))
2982 // Entire rows are not affected, columns are anchored.
2985 // Insert and shifting right.
2986 if (rRefRange
.aStart
.Row() < rSelectedRange
.aStart
.Row() || rSelectedRange
.aEnd
.Row() < rRefRange
.aEnd
.Row())
2987 // Selected range is only partially overlapping in vertical direction. Bail out.
2990 if (rCxt
.mrDoc
.IsExpandRefs())
2992 if (rRefRange
.aEnd
.Col() - rRefRange
.aStart
.Col() < 1)
2993 // Reference must be at least two columns wide.
2998 if (rSelectedRange
.aStart
.Col() <= rRefRange
.aStart
.Col())
2999 // Selected range is at the left end and the edge expansion is turned off. No expansion.
3003 if (rRefRange
.IsEndColSticky(rCxt
.mrDoc
))
3004 // Sticky end not affected.
3007 // Move the last column position to the right.
3008 SCCOL nDelta
= rSelectedRange
.aEnd
.Col() - rSelectedRange
.aStart
.Col() + 1;
3009 rRefRange
.IncEndColSticky(rCxt
.mrDoc
, nDelta
);
3012 else if (rCxt
.mnRowDelta
> 0)
3014 if (rRef
.IsEntireCol(rCxt
.mrDoc
.GetSheetLimits()))
3015 // Entire columns are not affected, rows are anchored.
3018 // Insert and shifting down.
3019 if (rRefRange
.aStart
.Col() < rSelectedRange
.aStart
.Col() || rSelectedRange
.aEnd
.Col() < rRefRange
.aEnd
.Col())
3020 // Selected range is only partially overlapping in horizontal direction. Bail out.
3023 if (rCxt
.mrDoc
.IsExpandRefs())
3025 if (rRefRange
.aEnd
.Row() - rRefRange
.aStart
.Row() < 1)
3026 // Reference must be at least two rows tall.
3031 if (rSelectedRange
.aStart
.Row() <= rRefRange
.aStart
.Row())
3032 // Selected range is at the top end and the edge expansion is turned off. No expansion.
3036 if (rRefRange
.IsEndRowSticky(rCxt
.mrDoc
))
3037 // Sticky end not affected.
3040 // Move the last row position down.
3041 SCROW nDelta
= rSelectedRange
.aEnd
.Row() - rSelectedRange
.aStart
.Row() + 1;
3042 rRefRange
.IncEndRowSticky(rCxt
.mrDoc
, nDelta
);
3049 * Check if the referenced range is expandable when the selected range is
3050 * not overlapping the referenced range.
3052 bool expandRangeByEdge( const sc::RefUpdateContext
& rCxt
, ScRange
& rRefRange
, const ScRange
& rSelectedRange
,
3053 const ScComplexRefData
& rRef
)
3055 if (!rCxt
.mrDoc
.IsExpandRefs())
3056 // Edge-expansion is turned off.
3059 if (rSelectedRange
.aStart
.Tab() > rRefRange
.aStart
.Tab() || rRefRange
.aEnd
.Tab() > rSelectedRange
.aEnd
.Tab())
3060 // Sheet references not within selected range.
3063 if (rCxt
.mnColDelta
> 0)
3065 if (rRef
.IsEntireRow(rCxt
.mrDoc
.GetSheetLimits()))
3066 // Entire rows are not affected, columns are anchored.
3069 // Insert and shift right.
3071 if (rRefRange
.aEnd
.Col() - rRefRange
.aStart
.Col() < 1)
3072 // Reference must be at least two columns wide.
3075 if (rRefRange
.aStart
.Row() < rSelectedRange
.aStart
.Row() || rSelectedRange
.aEnd
.Row() < rRefRange
.aEnd
.Row())
3076 // Selected range is only partially overlapping in vertical direction. Bail out.
3079 if (rSelectedRange
.aStart
.Col() - rRefRange
.aEnd
.Col() != 1)
3080 // Selected range is not immediately adjacent. Bail out.
3083 if (rRefRange
.IsEndColSticky(rCxt
.mrDoc
))
3084 // Sticky end not affected.
3087 // Move the last column position to the right.
3088 SCCOL nDelta
= rSelectedRange
.aEnd
.Col() - rSelectedRange
.aStart
.Col() + 1;
3089 rRefRange
.IncEndColSticky(rCxt
.mrDoc
, nDelta
);
3092 else if (rCxt
.mnRowDelta
> 0)
3094 if (rRef
.IsEntireCol(rCxt
.mrDoc
.GetSheetLimits()))
3095 // Entire columns are not affected, rows are anchored.
3098 if (rRefRange
.aEnd
.Row() - rRefRange
.aStart
.Row() < 1)
3099 // Reference must be at least two rows tall.
3102 if (rRefRange
.aStart
.Col() < rSelectedRange
.aStart
.Col() || rSelectedRange
.aEnd
.Col() < rRefRange
.aEnd
.Col())
3103 // Selected range is only partially overlapping in horizontal direction. Bail out.
3106 if (rSelectedRange
.aStart
.Row() - rRefRange
.aEnd
.Row() != 1)
3107 // Selected range is not immediately adjacent. Bail out.
3110 if (rRefRange
.IsEndRowSticky(rCxt
.mrDoc
))
3111 // Sticky end not affected.
3114 // Move the last row position down.
3115 SCROW nDelta
= rSelectedRange
.aEnd
.Row() - rSelectedRange
.aStart
.Row() + 1;
3116 rRefRange
.IncEndRowSticky(rCxt
.mrDoc
, nDelta
);
3123 bool isNameModified( const sc::UpdatedRangeNames
& rUpdatedNames
, SCTAB nOldTab
, const formula::FormulaToken
& rToken
)
3126 if (rToken
.GetSheet() >= 0)
3129 // Check if this named expression has been modified.
3130 return rUpdatedNames
.isNameUpdated(nTab
, rToken
.GetIndex());
3133 bool isDBDataModified( const ScDocument
& rDoc
, const formula::FormulaToken
& rToken
)
3135 // Check if this DBData has been modified.
3136 const ScDBData
* pDBData
= rDoc
.GetDBCollection()->getNamedDBs().findByIndex( rToken
.GetIndex());
3140 return pDBData
->IsModified();
3145 sc::RefUpdateResult
ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateContext
& rCxt
, const ScAddress
& rOldPos
)
3147 ScRange aSelectedRange
= getSelectedRange(rCxt
);
3149 sc::RefUpdateResult aRes
;
3150 ScAddress aNewPos
= rOldPos
;
3151 bool bCellShifted
= rCxt
.maRange
.Contains(rOldPos
);
3154 ScAddress
aErrorPos( ScAddress::UNINITIALIZED
);
3155 if (!aNewPos
.Move(rCxt
.mnColDelta
, rCxt
.mnRowDelta
, rCxt
.mnTabDelta
, aErrorPos
, rCxt
.mrDoc
))
3157 assert(!"can't move");
3161 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
3162 for (size_t j
=0; j
<2; ++j
)
3164 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
3165 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
3166 for (; pp
!= pEnd
; ++pp
)
3168 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
3172 switch (p
->GetType())
3176 ScSingleRefData
& rRef
= *p
->GetSingleRef();
3177 ScAddress aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
3179 if (rCxt
.isDeleted() && aSelectedRange
.Contains(aAbs
))
3181 // This reference is in the deleted region.
3182 setRefDeleted(rRef
, rCxt
);
3183 aRes
.mbValueChanged
= true;
3187 if (!rCxt
.isDeleted() && rRef
.IsDeleted())
3189 // Check if the token has reference to previously deleted region.
3190 ScAddress aCheckPos
= rRef
.toAbs(*mxSheetLimits
, aNewPos
);
3191 if (rCxt
.maRange
.Contains(aCheckPos
))
3193 restoreDeletedRef(rRef
, rCxt
);
3194 aRes
.mbValueChanged
= true;
3199 if (rCxt
.maRange
.Contains(aAbs
))
3201 ScAddress
aErrorPos( ScAddress::UNINITIALIZED
);
3202 if (!aAbs
.Move(rCxt
.mnColDelta
, rCxt
.mnRowDelta
, rCxt
.mnTabDelta
, aErrorPos
, rCxt
.mrDoc
))
3204 aRes
.mbReferenceModified
= true;
3207 rRef
.SetAddress(*mxSheetLimits
, aAbs
, aNewPos
);
3212 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
3213 ScRange aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
3215 if (rCxt
.isDeleted())
3217 if (aSelectedRange
.Contains(aAbs
))
3219 // This reference is in the deleted region.
3220 setRefDeleted(rRef
, rCxt
);
3221 aRes
.mbValueChanged
= true;
3224 else if (aSelectedRange
.Intersects(aAbs
))
3226 const ShrinkResult eSR
= shrinkRange(rCxt
, aAbs
, aSelectedRange
, rRef
);
3229 // The reference range has been shrunk.
3230 rRef
.SetRange(*mxSheetLimits
, aAbs
, aNewPos
);
3231 aRes
.mbValueChanged
= true;
3232 aRes
.mbReferenceModified
= true;
3235 else if (eSR
== STICKY
)
3237 // The reference range stays the same but a
3238 // new (empty) cell range is shifted in and
3239 // may change the calculation result.
3240 aRes
.mbValueChanged
= true;
3241 // Sticky when intersecting the selected
3242 // range means also that the other
3243 // conditions below are not met,
3244 // specifically not the
3245 // if (rCxt.maRange.Contains(aAbs))
3246 // that is able to update the reference,
3247 // but aSelectedRange does not intersect
3248 // with rCxt.maRange so that can't happen
3249 // and we can bail out early without
3250 // updating the reference.
3256 if (!rCxt
.isDeleted() && rRef
.IsDeleted())
3258 // Check if the token has reference to previously deleted region.
3259 ScRange aCheckRange
= rRef
.toAbs(*mxSheetLimits
, aNewPos
);
3260 if (aSelectedRange
.Contains(aCheckRange
))
3262 // This reference was previously in the deleted region. Restore it.
3263 restoreDeletedRef(rRef
, rCxt
);
3264 aRes
.mbValueChanged
= true;
3269 if (rCxt
.isInserted())
3271 if (expandRange(rCxt
, aAbs
, aSelectedRange
, rRef
))
3273 // The reference range has been expanded.
3274 rRef
.SetRange(*mxSheetLimits
, aAbs
, aNewPos
);
3275 aRes
.mbValueChanged
= true;
3276 aRes
.mbReferenceModified
= true;
3280 if (expandRangeByEdge(rCxt
, aAbs
, aSelectedRange
, rRef
))
3282 // The reference range has been expanded on the edge.
3283 rRef
.SetRange(*mxSheetLimits
, aAbs
, aNewPos
);
3284 aRes
.mbValueChanged
= true;
3285 aRes
.mbReferenceModified
= true;
3290 if (rCxt
.maRange
.Contains(aAbs
))
3292 // We shift either by column or by row, not both,
3293 // so moving the reference has only to be done in
3294 // the non-sticky case.
3295 if ((rCxt
.mnRowDelta
&& rRef
.IsEntireCol(rCxt
.mrDoc
.GetSheetLimits()))
3296 || (rCxt
.mnColDelta
&& rRef
.IsEntireRow(rCxt
.mrDoc
.GetSheetLimits())))
3298 // In entire col/row, values are shifted within
3299 // the reference, which affects all positional
3300 // results like in MATCH or matrix positions.
3301 aRes
.mbValueChanged
= true;
3305 ScRange
aErrorRange( ScAddress::UNINITIALIZED
);
3306 if (!aAbs
.MoveSticky(rCxt
.mrDoc
, rCxt
.mnColDelta
, rCxt
.mnRowDelta
, rCxt
.mnTabDelta
, aErrorRange
))
3308 aRes
.mbReferenceModified
= true;
3311 else if (rCxt
.maRange
.Intersects(aAbs
))
3313 // Part of the referenced range is being shifted. This
3314 // will change the values of the range.
3315 aRes
.mbValueChanged
= true;
3318 rRef
.SetRange(*mxSheetLimits
, aAbs
, aNewPos
);
3321 case svExternalSingleRef
:
3323 // For external reference, just reset the reference with
3324 // respect to the new cell position.
3325 ScSingleRefData
& rRef
= *p
->GetSingleRef();
3326 ScAddress aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
3327 rRef
.SetAddress(*mxSheetLimits
, aAbs
, aNewPos
);
3330 case svExternalDoubleRef
:
3333 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
3334 ScRange aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
3335 rRef
.SetRange(*mxSheetLimits
, aAbs
, aNewPos
);
3342 // For ocTableRef p is the inner token of *pp, so have a separate
3344 if ((*pp
)->GetType() == svIndex
)
3346 switch ((*pp
)->GetOpCode())
3350 SCTAB nOldTab
= (*pp
)->GetSheet();
3351 if (isNameModified(rCxt
.maUpdatedNames
, nOldTab
, **pp
))
3352 aRes
.mbNameModified
= true;
3353 if (rCxt
.mnTabDelta
&&
3354 rCxt
.maRange
.aStart
.Tab() <= nOldTab
&& nOldTab
<= rCxt
.maRange
.aEnd
.Tab())
3356 aRes
.mbNameModified
= true;
3357 (*pp
)->SetSheet( nOldTab
+ rCxt
.mnTabDelta
);
3363 if (isDBDataModified(rCxt
.mrDoc
, **pp
))
3364 aRes
.mbNameModified
= true;
3376 sc::RefUpdateResult
ScTokenArray::AdjustReferenceOnMove(
3377 const sc::RefUpdateContext
& rCxt
, const ScAddress
& rOldPos
, const ScAddress
& rNewPos
)
3379 sc::RefUpdateResult aRes
;
3381 if (!rCxt
.mnColDelta
&& !rCxt
.mnRowDelta
&& !rCxt
.mnTabDelta
)
3382 // The cell hasn't moved at all.
3385 // When moving, the range in the context is the destination range. We need
3386 // to use the old range prior to the move for hit analysis.
3387 ScRange aOldRange
= rCxt
.maRange
;
3388 ScRange
aErrorMoveRange( ScAddress::UNINITIALIZED
);
3389 if (!aOldRange
.Move(-rCxt
.mnColDelta
, -rCxt
.mnRowDelta
, -rCxt
.mnTabDelta
, aErrorMoveRange
, rCxt
.mrDoc
))
3391 assert(!"can't move");
3394 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
3395 for (size_t j
=0; j
<2; ++j
)
3397 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
3398 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
3399 for (; pp
!= pEnd
; ++pp
)
3401 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
3405 switch (p
->GetType())
3409 ScSingleRefData
& rRef
= *p
->GetSingleRef();
3410 ScAddress aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
3412 // Do not update the reference in transposed case (cut paste transposed).
3413 // The reference will be updated in UpdateTranspose().
3414 // Additionally, do not update the references from cells within the moved
3415 // range as they lead to #REF! errors here. These #REF! cannot by fixed
3416 // later in UpdateTranspose().
3417 if (rCxt
.mbTransposed
&& (aOldRange
.Contains(rOldPos
) || aOldRange
.Contains(aAbs
)))
3420 if (aOldRange
.Contains(aAbs
))
3422 ScAddress
aErrorPos( ScAddress::UNINITIALIZED
);
3423 if (!aAbs
.Move(rCxt
.mnColDelta
, rCxt
.mnRowDelta
, rCxt
.mnTabDelta
, aErrorPos
, rCxt
.mrDoc
))
3425 aRes
.mbReferenceModified
= true;
3427 else if (rCxt
.maRange
.Contains(aAbs
))
3429 // Referenced cell has been overwritten.
3430 aRes
.mbValueChanged
= true;
3433 rRef
.SetAddress(*mxSheetLimits
, aAbs
, rNewPos
);
3434 rRef
.SetFlag3D(rRef
.IsFlag3D() || !rRef
.IsTabRel() || aAbs
.Tab() != rNewPos
.Tab());
3439 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
3440 ScRange aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
3442 // Do not update the reference in transposed case (cut paste transposed).
3443 // The reference will be updated in UpdateTranspose().
3444 // Additionally, do not update the references from cells within the moved
3445 // range as they lead to #REF! errors here. These #REF! cannot by fixed
3446 // later in UpdateTranspose().
3447 if (rCxt
.mbTransposed
&& (aOldRange
.Contains(rOldPos
) || aOldRange
.Contains(aAbs
)))
3450 if (aOldRange
.Contains(aAbs
))
3452 ScRange
aErrorRange( ScAddress::UNINITIALIZED
);
3453 if (!aAbs
.Move(rCxt
.mnColDelta
, rCxt
.mnRowDelta
, rCxt
.mnTabDelta
, aErrorRange
, rCxt
.mrDoc
))
3455 aRes
.mbReferenceModified
= true;
3457 else if (rCxt
.maRange
.Contains(aAbs
))
3459 // Referenced range has been entirely overwritten.
3460 aRes
.mbValueChanged
= true;
3463 rRef
.SetRange(*mxSheetLimits
, aAbs
, rNewPos
);
3465 if (aAbs
.aStart
.Tab() != aAbs
.aEnd
.Tab())
3467 // More than one sheet referenced => has to have
3473 // Keep given 3D flag even for relative sheet
3474 // reference to same sheet.
3475 // Absolute sheet reference => set 3D flag.
3476 // Reference to another sheet => set 3D flag.
3477 b1
= rRef
.Ref1
.IsFlag3D() || !rRef
.Ref1
.IsTabRel() || rNewPos
.Tab() != aAbs
.aStart
.Tab();
3478 b2
= rRef
.Ref2
.IsFlag3D() || !rRef
.Ref2
.IsTabRel() || rNewPos
.Tab() != aAbs
.aEnd
.Tab();
3479 // End part has 3D flag => start part must have it too.
3482 // End part sheet reference is identical to start
3483 // part sheet reference and end part sheet
3484 // reference was not explicitly given => clear end
3486 if (b1
&& b2
&& rRef
.Ref1
.IsTabRel() == rRef
.Ref2
.IsTabRel() && !rRef
.Ref2
.IsFlag3D())
3489 rRef
.Ref1
.SetFlag3D(b1
);
3490 rRef
.Ref2
.SetFlag3D(b2
);
3493 case svExternalSingleRef
:
3495 ScSingleRefData
& rRef
= *p
->GetSingleRef();
3496 ScAddress aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
3497 rRef
.SetAddress(*mxSheetLimits
, aAbs
, rNewPos
);
3500 case svExternalDoubleRef
:
3502 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
3503 ScRange aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
3504 rRef
.SetRange(*mxSheetLimits
, aAbs
, rNewPos
);
3511 // For ocTableRef p is the inner token of *pp, so have a separate
3513 if ((*pp
)->GetType() == svIndex
)
3515 switch ((*pp
)->GetOpCode())
3519 SCTAB nOldTab
= (*pp
)->GetSheet();
3520 if (isNameModified(rCxt
.maUpdatedNames
, nOldTab
, **pp
))
3521 aRes
.mbNameModified
= true;
3526 if (isDBDataModified(rCxt
.mrDoc
, **pp
))
3527 aRes
.mbNameModified
= true;
3539 void ScTokenArray::MoveReferenceColReorder(
3540 const ScAddress
& rPos
, SCTAB nTab
, SCROW nRow1
, SCROW nRow2
, const sc::ColRowReorderMapType
& rColMap
)
3542 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
3543 for (size_t j
=0; j
<2; ++j
)
3545 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
3546 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
3547 for (; pp
!= pEnd
; ++pp
)
3549 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
3553 switch (p
->GetType())
3557 ScSingleRefData
& rRef
= *p
->GetSingleRef();
3558 ScAddress aAbs
= rRef
.toAbs(*mxSheetLimits
, rPos
);
3560 if (aAbs
.Tab() == nTab
&& nRow1
<= aAbs
.Row() && aAbs
.Row() <= nRow2
)
3562 // Inside reordered row range.
3563 sc::ColRowReorderMapType::const_iterator it
= rColMap
.find(aAbs
.Col());
3564 if (it
!= rColMap
.end())
3566 // This column is reordered.
3567 SCCOL nNewCol
= it
->second
;
3568 aAbs
.SetCol(nNewCol
);
3569 rRef
.SetAddress(*mxSheetLimits
, aAbs
, rPos
);
3576 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
3577 ScRange aAbs
= rRef
.toAbs(*mxSheetLimits
, rPos
);
3579 if (aAbs
.aStart
.Tab() != aAbs
.aEnd
.Tab())
3580 // Must be a single-sheet reference.
3583 if (aAbs
.aStart
.Col() != aAbs
.aEnd
.Col())
3584 // Whole range must fit in a single column.
3587 if (aAbs
.aStart
.Tab() == nTab
&& nRow1
<= aAbs
.aStart
.Row() && aAbs
.aEnd
.Row() <= nRow2
)
3589 // Inside reordered row range.
3590 sc::ColRowReorderMapType::const_iterator it
= rColMap
.find(aAbs
.aStart
.Col());
3591 if (it
!= rColMap
.end())
3593 // This column is reordered.
3594 SCCOL nNewCol
= it
->second
;
3595 aAbs
.aStart
.SetCol(nNewCol
);
3596 aAbs
.aEnd
.SetCol(nNewCol
);
3597 rRef
.SetRange(*mxSheetLimits
, aAbs
, rPos
);
3609 void ScTokenArray::MoveReferenceRowReorder( const ScAddress
& rPos
, SCTAB nTab
, SCCOL nCol1
, SCCOL nCol2
, const sc::ColRowReorderMapType
& rRowMap
)
3611 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
3612 for (size_t j
=0; j
<2; ++j
)
3614 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
3615 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
3616 for (; pp
!= pEnd
; ++pp
)
3618 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
3622 switch (p
->GetType())
3626 ScSingleRefData
& rRef
= *p
->GetSingleRef();
3627 ScAddress aAbs
= rRef
.toAbs(*mxSheetLimits
, rPos
);
3629 if (aAbs
.Tab() == nTab
&& nCol1
<= aAbs
.Col() && aAbs
.Col() <= nCol2
)
3631 // Inside reordered column range.
3632 sc::ColRowReorderMapType::const_iterator it
= rRowMap
.find(aAbs
.Row());
3633 if (it
!= rRowMap
.end())
3635 // This column is reordered.
3636 SCROW nNewRow
= it
->second
;
3637 aAbs
.SetRow(nNewRow
);
3638 rRef
.SetAddress(*mxSheetLimits
, aAbs
, rPos
);
3645 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
3646 ScRange aAbs
= rRef
.toAbs(*mxSheetLimits
, rPos
);
3648 if (aAbs
.aStart
.Tab() != aAbs
.aEnd
.Tab())
3649 // Must be a single-sheet reference.
3652 if (aAbs
.aStart
.Row() != aAbs
.aEnd
.Row())
3653 // Whole range must fit in a single row.
3656 if (aAbs
.aStart
.Tab() == nTab
&& nCol1
<= aAbs
.aStart
.Col() && aAbs
.aEnd
.Col() <= nCol2
)
3658 // Inside reordered column range.
3659 sc::ColRowReorderMapType::const_iterator it
= rRowMap
.find(aAbs
.aStart
.Row());
3660 if (it
!= rRowMap
.end())
3662 // This row is reordered.
3663 SCROW nNewRow
= it
->second
;
3664 aAbs
.aStart
.SetRow(nNewRow
);
3665 aAbs
.aEnd
.SetRow(nNewRow
);
3666 rRef
.SetRange(*mxSheetLimits
, aAbs
, rPos
);
3680 bool adjustSingleRefInName(
3681 ScSingleRefData
& rRef
, const sc::RefUpdateContext
& rCxt
, const ScAddress
& rPos
,
3682 ScComplexRefData
* pEndOfComplex
)
3684 ScAddress aAbs
= rRef
.toAbs(rCxt
.mrDoc
, rPos
);
3686 if (aAbs
.Tab() < rCxt
.maRange
.aStart
.Tab() || rCxt
.maRange
.aEnd
.Tab() < aAbs
.Tab())
3688 // This references a sheet that has not shifted. Don't change it.
3692 if (!rCxt
.maRange
.Contains(rRef
.toAbs(rCxt
.mrDoc
, rPos
)))
3695 bool bChanged
= false;
3697 if (rCxt
.mnColDelta
&& !rRef
.IsColRel())
3699 // Adjust absolute column reference.
3700 if (rCxt
.maRange
.aStart
.Col() <= rRef
.Col() && rRef
.Col() <= rCxt
.maRange
.aEnd
.Col())
3704 if (pEndOfComplex
->IncEndColSticky(rCxt
.mrDoc
, rCxt
.mnColDelta
, rPos
))
3709 rRef
.IncCol(rCxt
.mnColDelta
);
3715 if (rCxt
.mnRowDelta
&& !rRef
.IsRowRel())
3717 // Adjust absolute row reference.
3718 if (rCxt
.maRange
.aStart
.Row() <= rRef
.Row() && rRef
.Row() <= rCxt
.maRange
.aEnd
.Row())
3722 if (pEndOfComplex
->IncEndRowSticky(rCxt
.mrDoc
, rCxt
.mnRowDelta
, rPos
))
3727 rRef
.IncRow(rCxt
.mnRowDelta
);
3733 if (!rRef
.IsTabRel() && rCxt
.mnTabDelta
)
3735 // Sheet range has already been checked above.
3736 rRef
.IncTab(rCxt
.mnTabDelta
);
3743 bool adjustDoubleRefInName(
3744 ScComplexRefData
& rRef
, const sc::RefUpdateContext
& rCxt
, const ScAddress
& rPos
)
3746 bool bRefChanged
= false;
3747 if (rCxt
.mrDoc
.IsExpandRefs())
3749 if (rCxt
.mnRowDelta
> 0 && !rRef
.Ref1
.IsRowRel() && !rRef
.Ref2
.IsRowRel())
3751 ScRange aAbs
= rRef
.toAbs(rCxt
.mrDoc
, rPos
);
3752 // Expand only if at least two rows tall.
3753 if (aAbs
.aStart
.Row() < aAbs
.aEnd
.Row())
3755 // Check and see if we should expand the range at the top.
3756 ScRange aSelectedRange
= getSelectedRange(rCxt
);
3757 if (aSelectedRange
.Intersects(aAbs
))
3759 // Selection intersects the referenced range. Only expand the
3761 rRef
.IncEndRowSticky(rCxt
.mrDoc
, rCxt
.mnRowDelta
, rPos
);
3766 if (rCxt
.mnColDelta
> 0 && !rRef
.Ref1
.IsColRel() && !rRef
.Ref2
.IsColRel())
3768 ScRange aAbs
= rRef
.toAbs(rCxt
.mrDoc
, rPos
);
3769 // Expand only if at least two columns wide.
3770 if (aAbs
.aStart
.Col() < aAbs
.aEnd
.Col())
3772 // Check and see if we should expand the range at the left.
3773 ScRange aSelectedRange
= getSelectedRange(rCxt
);
3774 if (aSelectedRange
.Intersects(aAbs
))
3776 // Selection intersects the referenced range. Only expand the
3778 rRef
.IncEndColSticky(rCxt
.mrDoc
, rCxt
.mnColDelta
, rPos
);
3785 if ((rCxt
.mnRowDelta
&& rRef
.IsEntireCol(rCxt
.mrDoc
.GetSheetLimits()))
3786 || (rCxt
.mnColDelta
&& rRef
.IsEntireRow(rCxt
.mrDoc
.GetSheetLimits())))
3788 sc::RefUpdateContext
aCxt( rCxt
.mrDoc
);
3789 // We only need a few parameters of RefUpdateContext.
3790 aCxt
.maRange
= rCxt
.maRange
;
3791 aCxt
.mnColDelta
= rCxt
.mnColDelta
;
3792 aCxt
.mnRowDelta
= rCxt
.mnRowDelta
;
3793 aCxt
.mnTabDelta
= rCxt
.mnTabDelta
;
3795 // References to entire col/row are not to be adjusted in the other axis.
3796 if (aCxt
.mnRowDelta
&& rRef
.IsEntireCol(rCxt
.mrDoc
.GetSheetLimits()))
3797 aCxt
.mnRowDelta
= 0;
3798 if (aCxt
.mnColDelta
&& rRef
.IsEntireRow(rCxt
.mrDoc
.GetSheetLimits()))
3799 aCxt
.mnColDelta
= 0;
3800 if (!aCxt
.mnColDelta
&& !aCxt
.mnRowDelta
&& !aCxt
.mnTabDelta
)
3804 // Ref2 before Ref1 for sticky ends.
3805 if (adjustSingleRefInName(rRef
.Ref2
, aCxt
, rPos
, &rRef
))
3808 if (adjustSingleRefInName(rRef
.Ref1
, aCxt
, rPos
, nullptr))
3813 // Ref2 before Ref1 for sticky ends.
3814 if (adjustSingleRefInName(rRef
.Ref2
, rCxt
, rPos
, &rRef
))
3817 if (adjustSingleRefInName(rRef
.Ref1
, rCxt
, rPos
, nullptr))
3826 sc::RefUpdateResult
ScTokenArray::AdjustReferenceInName(
3827 const sc::RefUpdateContext
& rCxt
, const ScAddress
& rPos
)
3829 if (rCxt
.meMode
== URM_MOVE
)
3830 return AdjustReferenceInMovedName(rCxt
, rPos
);
3832 sc::RefUpdateResult aRes
;
3834 if (rCxt
.meMode
== URM_COPY
)
3835 // Copying cells does not modify named expressions.
3838 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
3839 for (size_t j
=0; j
<2; ++j
)
3841 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
3842 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
3843 for (; pp
!= pEnd
; ++pp
)
3845 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
3849 switch (p
->GetType())
3853 ScSingleRefData
& rRef
= *p
->GetSingleRef();
3854 if (rCxt
.mnRowDelta
< 0)
3858 if (rRef
.IsRowRel())
3859 // Don't modify relative references in names.
3862 ScAddress aAbs
= rRef
.toAbs(rCxt
.mrDoc
, rPos
);
3864 if (aAbs
.Col() < rCxt
.maRange
.aStart
.Col() || rCxt
.maRange
.aEnd
.Col() < aAbs
.Col())
3865 // column of the reference is not in the deleted column range.
3868 if (aAbs
.Tab() > rCxt
.maRange
.aEnd
.Tab() || aAbs
.Tab() < rCxt
.maRange
.aStart
.Tab())
3872 const SCROW nDelStartRow
= rCxt
.maRange
.aStart
.Row() + rCxt
.mnRowDelta
;
3873 const SCROW nDelEndRow
= nDelStartRow
- rCxt
.mnRowDelta
- 1;
3875 if (nDelStartRow
<= aAbs
.Row() && aAbs
.Row() <= nDelEndRow
)
3877 // This reference is deleted.
3878 rRef
.SetRowDeleted(true);
3879 aRes
.mbReferenceModified
= true;
3883 else if (rCxt
.mnColDelta
< 0)
3885 // column(s) deleted.
3887 if (rRef
.IsColRel())
3888 // Don't modify relative references in names.
3891 ScAddress aAbs
= rRef
.toAbs(rCxt
.mrDoc
, rPos
);
3893 if (aAbs
.Row() < rCxt
.maRange
.aStart
.Row() || rCxt
.maRange
.aEnd
.Row() < aAbs
.Row())
3894 // row of the reference is not in the deleted row range.
3897 if (aAbs
.Tab() > rCxt
.maRange
.aEnd
.Tab() || aAbs
.Tab() < rCxt
.maRange
.aStart
.Tab())
3901 const SCCOL nDelStartCol
= rCxt
.maRange
.aStart
.Col() + rCxt
.mnColDelta
;
3902 const SCCOL nDelEndCol
= nDelStartCol
- rCxt
.mnColDelta
- 1;
3904 if (nDelStartCol
<= aAbs
.Col() && aAbs
.Col() <= nDelEndCol
)
3906 // This reference is deleted.
3907 rRef
.SetColDeleted(true);
3908 aRes
.mbReferenceModified
= true;
3913 if (adjustSingleRefInName(rRef
, rCxt
, rPos
, nullptr))
3914 aRes
.mbReferenceModified
= true;
3919 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
3920 ScRange aAbs
= rRef
.toAbs(rCxt
.mrDoc
, rPos
);
3922 if (aAbs
.aStart
.Tab() > rCxt
.maRange
.aEnd
.Tab() || aAbs
.aEnd
.Tab() < rCxt
.maRange
.aStart
.Tab())
3923 // Sheet references not affected.
3926 if (rCxt
.maRange
.Contains(aAbs
))
3928 // This range is entirely within the shifted region.
3929 if (adjustDoubleRefInName(rRef
, rCxt
, rPos
))
3930 aRes
.mbReferenceModified
= true;
3932 else if (rCxt
.mnRowDelta
< 0)
3936 if (rRef
.IsEntireCol(rCxt
.mrDoc
.GetSheetLimits()))
3937 // Rows of entire columns are not affected.
3940 if (rRef
.Ref1
.IsRowRel() || rRef
.Ref2
.IsRowRel())
3941 // Don't modify relative references in names.
3944 if (aAbs
.aStart
.Col() < rCxt
.maRange
.aStart
.Col() || rCxt
.maRange
.aEnd
.Col() < aAbs
.aEnd
.Col())
3945 // column range of the reference is not entirely in the deleted column range.
3948 ScRange aDeleted
= rCxt
.maRange
;
3949 aDeleted
.aStart
.IncRow(rCxt
.mnRowDelta
);
3950 aDeleted
.aEnd
.SetRow(aDeleted
.aStart
.Row()-rCxt
.mnRowDelta
-1);
3952 if (aAbs
.aEnd
.Row() < aDeleted
.aStart
.Row() || aDeleted
.aEnd
.Row() < aAbs
.aStart
.Row())
3953 // reference range doesn't intersect with the deleted range.
3956 if (aDeleted
.aStart
.Row() <= aAbs
.aStart
.Row() && aAbs
.aEnd
.Row() <= aDeleted
.aEnd
.Row())
3958 // This reference is entirely deleted.
3959 rRef
.Ref1
.SetRowDeleted(true);
3960 rRef
.Ref2
.SetRowDeleted(true);
3961 aRes
.mbReferenceModified
= true;
3965 if (aAbs
.aStart
.Row() < aDeleted
.aStart
.Row())
3967 if (!aAbs
.IsEndRowSticky(rCxt
.mrDoc
))
3969 if (aDeleted
.aEnd
.Row() < aAbs
.aEnd
.Row())
3970 // Deleted in the middle. Make the reference shorter.
3971 rRef
.Ref2
.IncRow(rCxt
.mnRowDelta
);
3973 // Deleted at tail end. Cut off the lower part.
3974 rRef
.Ref2
.SetAbsRow(aDeleted
.aStart
.Row()-1);
3979 // Deleted at the top. Cut the top off and shift up.
3980 rRef
.Ref1
.SetAbsRow(aDeleted
.aEnd
.Row()+1);
3981 rRef
.Ref1
.IncRow(rCxt
.mnRowDelta
);
3982 if (!aAbs
.IsEndRowSticky(rCxt
.mrDoc
))
3983 rRef
.Ref2
.IncRow(rCxt
.mnRowDelta
);
3986 aRes
.mbReferenceModified
= true;
3988 else if (rCxt
.mnColDelta
< 0)
3990 // column(s) deleted.
3992 if (rRef
.IsEntireRow(rCxt
.mrDoc
.GetSheetLimits()))
3993 // Rows of entire rows are not affected.
3996 if (rRef
.Ref1
.IsColRel() || rRef
.Ref2
.IsColRel())
3997 // Don't modify relative references in names.
4000 if (aAbs
.aStart
.Row() < rCxt
.maRange
.aStart
.Row() || rCxt
.maRange
.aEnd
.Row() < aAbs
.aEnd
.Row())
4001 // row range of the reference is not entirely in the deleted row range.
4004 ScRange aDeleted
= rCxt
.maRange
;
4005 aDeleted
.aStart
.IncCol(rCxt
.mnColDelta
);
4006 aDeleted
.aEnd
.SetCol(aDeleted
.aStart
.Col()-rCxt
.mnColDelta
-1);
4008 if (aAbs
.aEnd
.Col() < aDeleted
.aStart
.Col() || aDeleted
.aEnd
.Col() < aAbs
.aStart
.Col())
4009 // reference range doesn't intersect with the deleted range.
4012 if (aDeleted
.aStart
.Col() <= aAbs
.aStart
.Col() && aAbs
.aEnd
.Col() <= aDeleted
.aEnd
.Col())
4014 // This reference is entirely deleted.
4015 rRef
.Ref1
.SetColDeleted(true);
4016 rRef
.Ref2
.SetColDeleted(true);
4017 aRes
.mbReferenceModified
= true;
4021 if (aAbs
.aStart
.Col() < aDeleted
.aStart
.Col())
4023 if (!aAbs
.IsEndColSticky(rCxt
.mrDoc
))
4025 if (aDeleted
.aEnd
.Col() < aAbs
.aEnd
.Col())
4026 // Deleted in the middle. Make the reference shorter.
4027 rRef
.Ref2
.IncCol(rCxt
.mnColDelta
);
4029 // Deleted at tail end. Cut off the right part.
4030 rRef
.Ref2
.SetAbsCol(aDeleted
.aStart
.Col()-1);
4035 // Deleted at the left. Cut the left off and shift left.
4036 rRef
.Ref1
.SetAbsCol(aDeleted
.aEnd
.Col()+1);
4037 rRef
.Ref1
.IncCol(rCxt
.mnColDelta
);
4038 if (!aAbs
.IsEndColSticky(rCxt
.mrDoc
))
4039 rRef
.Ref2
.IncCol(rCxt
.mnColDelta
);
4042 aRes
.mbReferenceModified
= true;
4044 else if (rCxt
.maRange
.Intersects(aAbs
))
4046 if (rCxt
.mnColDelta
&& rCxt
.maRange
.aStart
.Row() <= aAbs
.aStart
.Row() && aAbs
.aEnd
.Row() <= rCxt
.maRange
.aEnd
.Row())
4048 if (adjustDoubleRefInName(rRef
, rCxt
, rPos
))
4049 aRes
.mbReferenceModified
= true;
4051 if (rCxt
.mnRowDelta
&& rCxt
.maRange
.aStart
.Col() <= aAbs
.aStart
.Col() && aAbs
.aEnd
.Col() <= rCxt
.maRange
.aEnd
.Col())
4053 if (adjustDoubleRefInName(rRef
, rCxt
, rPos
))
4054 aRes
.mbReferenceModified
= true;
4057 else if (rCxt
.mnRowDelta
> 0 && rCxt
.mrDoc
.IsExpandRefs())
4059 // Check if we could expand range reference by the bottom
4060 // edge. For named expressions, we only expand absolute
4061 // references. Reference must be at least two rows
4063 if (!rRef
.Ref1
.IsRowRel() && !rRef
.Ref2
.IsRowRel() &&
4064 aAbs
.aStart
.Row() < aAbs
.aEnd
.Row() &&
4065 aAbs
.aEnd
.Row()+1 == rCxt
.maRange
.aStart
.Row())
4067 // Expand by the bottom edge.
4068 rRef
.Ref2
.IncRow(rCxt
.mnRowDelta
);
4069 aRes
.mbReferenceModified
= true;
4072 else if (rCxt
.mnColDelta
> 0 && rCxt
.mrDoc
.IsExpandRefs())
4074 // Check if we could expand range reference by the right
4075 // edge. For named expressions, we only expand absolute
4076 // references. Reference must be at least two
4078 if (!rRef
.Ref1
.IsColRel() && !rRef
.Ref2
.IsColRel() &&
4079 aAbs
.aStart
.Col() < aAbs
.aEnd
.Col() &&
4080 aAbs
.aEnd
.Col()+1 == rCxt
.maRange
.aStart
.Col())
4082 // Expand by the right edge.
4083 rRef
.Ref2
.IncCol(rCxt
.mnColDelta
);
4084 aRes
.mbReferenceModified
= true;
4098 sc::RefUpdateResult
ScTokenArray::AdjustReferenceInMovedName( const sc::RefUpdateContext
& rCxt
, const ScAddress
& rPos
)
4100 // When moving, the range is the destination range.
4101 ScRange aOldRange
= rCxt
.maRange
;
4102 ScRange
aErrorMoveRange( ScAddress::UNINITIALIZED
);
4103 if (!aOldRange
.Move(-rCxt
.mnColDelta
, -rCxt
.mnRowDelta
, -rCxt
.mnTabDelta
, aErrorMoveRange
, rCxt
.mrDoc
))
4105 assert(!"can't move");
4108 // In a named expression, we'll move the reference only when the reference
4109 // is entirely absolute.
4111 sc::RefUpdateResult aRes
;
4113 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
4114 for (size_t j
=0; j
<2; ++j
)
4116 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
4117 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
4118 for (; pp
!= pEnd
; ++pp
)
4120 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
4124 switch (p
->GetType())
4128 ScSingleRefData
& rRef
= *p
->GetSingleRef();
4129 if (rRef
.IsColRel() || rRef
.IsRowRel() || rRef
.IsTabRel())
4132 ScAddress aAbs
= rRef
.toAbs(rCxt
.mrDoc
, rPos
);
4134 // Do not update the reference in transposed case (cut paste transposed).
4135 // The reference will be updated in UpdateTranspose().
4136 if (rCxt
.mbTransposed
&& aOldRange
.Contains(aAbs
))
4139 if (aOldRange
.Contains(aAbs
))
4141 ScAddress
aErrorPos( ScAddress::UNINITIALIZED
);
4142 if (!aAbs
.Move(rCxt
.mnColDelta
, rCxt
.mnRowDelta
, rCxt
.mnTabDelta
, aErrorPos
, rCxt
.mrDoc
))
4144 aRes
.mbReferenceModified
= true;
4147 rRef
.SetAddress(rCxt
.mrDoc
.GetSheetLimits(), aAbs
, rPos
);
4152 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
4153 if (rRef
.Ref1
.IsColRel() || rRef
.Ref1
.IsRowRel() || rRef
.Ref1
.IsTabRel() ||
4154 rRef
.Ref2
.IsColRel() || rRef
.Ref2
.IsRowRel() || rRef
.Ref2
.IsTabRel())
4157 ScRange aAbs
= rRef
.toAbs(rCxt
.mrDoc
, rPos
);
4159 // Do not update the reference in transposed case (cut paste transposed).
4160 // The reference will be updated in UpdateTranspose().
4161 if (rCxt
.mbTransposed
&& aOldRange
.Contains(aAbs
))
4164 if (aOldRange
.Contains(aAbs
))
4166 ScRange
aErrorRange( ScAddress::UNINITIALIZED
);
4167 if (!aAbs
.Move(rCxt
.mnColDelta
, rCxt
.mnRowDelta
, rCxt
.mnTabDelta
, aErrorRange
, rCxt
.mrDoc
))
4169 aRes
.mbReferenceModified
= true;
4172 rRef
.SetRange(rCxt
.mrDoc
.GetSheetLimits(), aAbs
, rPos
);
4186 bool adjustSingleRefOnDeletedTab( const ScSheetLimits
& rLimits
, ScSingleRefData
& rRef
, SCTAB nDelPos
, SCTAB nSheets
, const ScAddress
& rOldPos
, const ScAddress
& rNewPos
)
4188 ScAddress aAbs
= rRef
.toAbs(rLimits
, rOldPos
);
4189 if (nDelPos
<= aAbs
.Tab() && aAbs
.Tab() < nDelPos
+ nSheets
)
4191 rRef
.SetTabDeleted(true);
4195 if (nDelPos
< aAbs
.Tab())
4197 // Reference sheet needs to be adjusted.
4198 aAbs
.IncTab(-1*nSheets
);
4199 rRef
.SetAddress(rLimits
, aAbs
, rNewPos
);
4202 else if (rOldPos
.Tab() != rNewPos
.Tab())
4204 // Cell itself has moved.
4205 rRef
.SetAddress(rLimits
, aAbs
, rNewPos
);
4212 bool adjustSingleRefOnInsertedTab( const ScSheetLimits
& rLimits
, ScSingleRefData
& rRef
, SCTAB nInsPos
, SCTAB nSheets
, const ScAddress
& rOldPos
, const ScAddress
& rNewPos
)
4214 ScAddress aAbs
= rRef
.toAbs(rLimits
, rOldPos
);
4215 if (nInsPos
<= aAbs
.Tab())
4217 // Reference sheet needs to be adjusted.
4218 aAbs
.IncTab(nSheets
);
4219 rRef
.SetAddress(rLimits
, aAbs
, rNewPos
);
4222 else if (rOldPos
.Tab() != rNewPos
.Tab())
4224 // Cell itself has moved.
4225 rRef
.SetAddress(rLimits
, aAbs
, rNewPos
);
4232 bool adjustDoubleRefOnDeleteTab(const ScSheetLimits
& rLimits
, ScComplexRefData
& rRef
, SCTAB nDelPos
, SCTAB nSheets
, const ScAddress
& rOldPos
, const ScAddress
& rNewPos
)
4234 ScSingleRefData
& rRef1
= rRef
.Ref1
;
4235 ScSingleRefData
& rRef2
= rRef
.Ref2
;
4236 ScAddress aStartPos
= rRef1
.toAbs(rLimits
, rOldPos
);
4237 ScAddress aEndPos
= rRef2
.toAbs(rLimits
, rOldPos
);
4238 bool bMoreThanOneTab
= aStartPos
.Tab() != aEndPos
.Tab();
4239 bool bModified
= false;
4240 if (bMoreThanOneTab
&& aStartPos
.Tab() == nDelPos
&& nDelPos
+ nSheets
<= aEndPos
.Tab())
4242 if (rRef1
.IsTabRel() && aStartPos
.Tab() < rOldPos
.Tab())
4244 rRef1
.IncTab(nSheets
);
4250 bModified
= adjustSingleRefOnDeletedTab(rLimits
, rRef1
, nDelPos
, nSheets
, rOldPos
, rNewPos
);
4253 if (bMoreThanOneTab
&& aEndPos
.Tab() == nDelPos
&& aStartPos
.Tab() <= nDelPos
- nSheets
)
4255 if (!rRef2
.IsTabRel() || rOldPos
.Tab() < aEndPos
.Tab())
4257 rRef2
.IncTab(-nSheets
);
4263 bModified
|= adjustSingleRefOnDeletedTab(rLimits
, rRef2
, nDelPos
, nSheets
, rOldPos
, rNewPos
);
4270 sc::RefUpdateResult
ScTokenArray::AdjustReferenceOnDeletedTab( const sc::RefUpdateDeleteTabContext
& rCxt
, const ScAddress
& rOldPos
)
4272 sc::RefUpdateResult aRes
;
4273 ScAddress aNewPos
= rOldPos
;
4274 ScRangeUpdater::UpdateDeleteTab( aNewPos
, rCxt
);
4276 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
4277 for (size_t j
=0; j
<2; ++j
)
4279 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
4280 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
4281 for (; pp
!= pEnd
; ++pp
)
4283 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
4287 switch (p
->GetType())
4291 ScSingleRefData
& rRef
= *p
->GetSingleRef();
4292 if (adjustSingleRefOnDeletedTab(*mxSheetLimits
, rRef
, rCxt
.mnDeletePos
, rCxt
.mnSheets
, rOldPos
, aNewPos
))
4293 aRes
.mbReferenceModified
= true;
4298 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
4299 aRes
.mbReferenceModified
|= adjustDoubleRefOnDeleteTab(*mxSheetLimits
, rRef
, rCxt
.mnDeletePos
, rCxt
.mnSheets
, rOldPos
, aNewPos
);
4306 // For ocTableRef p is the inner token of *pp, so have a separate
4308 if ((*pp
)->GetType() == svIndex
)
4310 switch ((*pp
)->GetOpCode())
4314 SCTAB nOldTab
= (*pp
)->GetSheet();
4315 if (isNameModified(rCxt
.maUpdatedNames
, nOldTab
, **pp
))
4316 aRes
.mbNameModified
= true;
4317 if (rCxt
.mnDeletePos
<= nOldTab
)
4319 aRes
.mbNameModified
= true;
4320 if (rCxt
.mnDeletePos
+ rCxt
.mnSheets
<= nOldTab
)
4321 (*pp
)->SetSheet( nOldTab
- rCxt
.mnSheets
);
4323 // Would point to a deleted sheet. Invalidate.
4324 (*pp
)->SetSheet( SCTAB_MAX
);
4330 if (isDBDataModified(rCxt
.mrDoc
, **pp
))
4331 aRes
.mbNameModified
= true;
4342 sc::RefUpdateResult
ScTokenArray::AdjustReferenceOnInsertedTab( const sc::RefUpdateInsertTabContext
& rCxt
, const ScAddress
& rOldPos
)
4344 sc::RefUpdateResult aRes
;
4345 ScAddress aNewPos
= rOldPos
;
4346 if (rCxt
.mnInsertPos
<= rOldPos
.Tab())
4347 aNewPos
.IncTab(rCxt
.mnSheets
);
4349 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
4350 for (size_t j
=0; j
<2; ++j
)
4352 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
4353 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
4354 for (; pp
!= pEnd
; ++pp
)
4356 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
4360 switch (p
->GetType())
4364 ScSingleRefData
& rRef
= *p
->GetSingleRef();
4365 if (adjustSingleRefOnInsertedTab(*mxSheetLimits
, rRef
, rCxt
.mnInsertPos
, rCxt
.mnSheets
, rOldPos
, aNewPos
))
4366 aRes
.mbReferenceModified
= true;
4371 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
4372 if (adjustSingleRefOnInsertedTab(*mxSheetLimits
, rRef
.Ref1
, rCxt
.mnInsertPos
, rCxt
.mnSheets
, rOldPos
, aNewPos
))
4373 aRes
.mbReferenceModified
= true;
4374 if (adjustSingleRefOnInsertedTab(*mxSheetLimits
, rRef
.Ref2
, rCxt
.mnInsertPos
, rCxt
.mnSheets
, rOldPos
, aNewPos
))
4375 aRes
.mbReferenceModified
= true;
4382 // For ocTableRef p is the inner token of *pp, so have a separate
4384 if ((*pp
)->GetType() == svIndex
)
4386 switch ((*pp
)->GetOpCode())
4390 SCTAB nOldTab
= (*pp
)->GetSheet();
4391 if (isNameModified(rCxt
.maUpdatedNames
, nOldTab
, **pp
))
4392 aRes
.mbNameModified
= true;
4393 if (rCxt
.mnInsertPos
<= nOldTab
)
4395 aRes
.mbNameModified
= true;
4396 (*pp
)->SetSheet( nOldTab
+ rCxt
.mnSheets
);
4402 if (isDBDataModified(rCxt
.mrDoc
, **pp
))
4403 aRes
.mbNameModified
= true;
4416 bool adjustTabOnMove( ScAddress
& rPos
, const sc::RefUpdateMoveTabContext
& rCxt
)
4418 SCTAB nNewTab
= rCxt
.getNewTab(rPos
.Tab());
4419 if (nNewTab
== rPos
.Tab())
4422 rPos
.SetTab(nNewTab
);
4428 sc::RefUpdateResult
ScTokenArray::AdjustReferenceOnMovedTab( const sc::RefUpdateMoveTabContext
& rCxt
, const ScAddress
& rOldPos
)
4430 sc::RefUpdateResult aRes
;
4431 if (rCxt
.mnOldPos
== rCxt
.mnNewPos
)
4434 ScAddress aNewPos
= rOldPos
;
4435 if (adjustTabOnMove(aNewPos
, rCxt
))
4437 aRes
.mbReferenceModified
= true;
4438 aRes
.mbValueChanged
= true;
4439 aRes
.mnTab
= aNewPos
.Tab(); // this sets the new tab position used when deleting
4442 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
4443 for (size_t j
=0; j
<2; ++j
)
4445 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
4446 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
4447 for (; pp
!= pEnd
; ++pp
)
4449 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
4453 switch (p
->GetType())
4457 ScSingleRefData
& rRef
= *p
->GetSingleRef();
4458 ScAddress aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
4459 if (adjustTabOnMove(aAbs
, rCxt
))
4460 aRes
.mbReferenceModified
= true;
4461 rRef
.SetAddress(*mxSheetLimits
, aAbs
, aNewPos
);
4466 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
4467 ScRange aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
4468 if (adjustTabOnMove(aAbs
.aStart
, rCxt
))
4469 aRes
.mbReferenceModified
= true;
4470 if (adjustTabOnMove(aAbs
.aEnd
, rCxt
))
4471 aRes
.mbReferenceModified
= true;
4472 rRef
.SetRange(*mxSheetLimits
, aAbs
, aNewPos
);
4479 // For ocTableRef p is the inner token of *pp, so have a separate
4481 if ((*pp
)->GetType() == svIndex
)
4483 switch ((*pp
)->GetOpCode())
4487 SCTAB nOldTab
= (*pp
)->GetSheet();
4488 if (isNameModified(rCxt
.maUpdatedNames
, nOldTab
, **pp
))
4489 aRes
.mbNameModified
= true;
4490 SCTAB nNewTab
= rCxt
.getNewTab( nOldTab
);
4491 if (nNewTab
!= nOldTab
)
4493 aRes
.mbNameModified
= true;
4494 (*pp
)->SetSheet( nNewTab
);
4500 if (isDBDataModified(rCxt
.mrDoc
, **pp
))
4501 aRes
.mbNameModified
= true;
4513 void ScTokenArray::AdjustReferenceOnMovedOrigin( const ScAddress
& rOldPos
, const ScAddress
& rNewPos
)
4515 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
4516 for (size_t j
=0; j
<2; ++j
)
4518 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
4519 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
4520 for (; pp
!= pEnd
; ++pp
)
4522 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
4526 switch (p
->GetType())
4529 case svExternalSingleRef
:
4531 ScSingleRefData
& rRef
= *p
->GetSingleRef();
4532 ScAddress aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
4533 rRef
.SetAddress(*mxSheetLimits
, aAbs
, rNewPos
);
4537 case svExternalDoubleRef
:
4539 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
4540 ScRange aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
4541 rRef
.SetRange(*mxSheetLimits
, aAbs
, rNewPos
);
4551 void ScTokenArray::AdjustReferenceOnMovedOriginIfOtherSheet( const ScAddress
& rOldPos
, const ScAddress
& rNewPos
)
4553 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
4554 for (size_t j
=0; j
<2; ++j
)
4556 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
4557 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
4558 for (; pp
!= pEnd
; ++pp
)
4560 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
4564 bool bAdjust
= false;
4565 switch (p
->GetType())
4567 case svExternalSingleRef
:
4568 bAdjust
= true; // always
4572 ScSingleRefData
& rRef
= *p
->GetSingleRef();
4573 ScAddress aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
4575 bAdjust
= (aAbs
.Tab() != rOldPos
.Tab());
4577 rRef
.SetAddress(*mxSheetLimits
, aAbs
, rNewPos
);
4580 case svExternalDoubleRef
:
4581 bAdjust
= true; // always
4585 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
4586 ScRange aAbs
= rRef
.toAbs(*mxSheetLimits
, rOldPos
);
4588 bAdjust
= (rOldPos
.Tab() < aAbs
.aStart
.Tab() || aAbs
.aEnd
.Tab() < rOldPos
.Tab());
4590 rRef
.SetRange(*mxSheetLimits
, aAbs
, rNewPos
);
4600 void ScTokenArray::AdjustReferenceOnCopy( const ScAddress
& rNewPos
)
4602 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
, false);
4603 for (size_t j
=0; j
<2; ++j
)
4605 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
4606 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
4607 for (; pp
!= pEnd
; ++pp
)
4609 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
4613 switch (p
->GetType())
4617 ScComplexRefData
& rRef
= *p
->GetDoubleRef();
4618 rRef
.PutInOrder( rNewPos
);
4630 void clearTabDeletedFlag( const ScSheetLimits
& rLimits
, ScSingleRefData
& rRef
, const ScAddress
& rPos
, SCTAB nStartTab
, SCTAB nEndTab
)
4632 if (!rRef
.IsTabDeleted())
4635 ScAddress aAbs
= rRef
.toAbs(rLimits
, rPos
);
4636 if (nStartTab
<= aAbs
.Tab() && aAbs
.Tab() <= nEndTab
)
4637 rRef
.SetTabDeleted(false);
4642 void ScTokenArray::ClearTabDeleted( const ScAddress
& rPos
, SCTAB nStartTab
, SCTAB nEndTab
)
4644 if (nEndTab
< nStartTab
)
4647 FormulaToken
** p
= pCode
.get();
4648 FormulaToken
** pEnd
= p
+ static_cast<size_t>(nLen
);
4649 for (; p
!= pEnd
; ++p
)
4651 switch ((*p
)->GetType())
4655 formula::FormulaToken
* pToken
= *p
;
4656 ScSingleRefData
& rRef
= *pToken
->GetSingleRef();
4657 clearTabDeletedFlag(*mxSheetLimits
, rRef
, rPos
, nStartTab
, nEndTab
);
4662 formula::FormulaToken
* pToken
= *p
;
4663 ScComplexRefData
& rRef
= *pToken
->GetDoubleRef();
4664 clearTabDeletedFlag(*mxSheetLimits
, rRef
.Ref1
, rPos
, nStartTab
, nEndTab
);
4665 clearTabDeletedFlag(*mxSheetLimits
, rRef
.Ref2
, rPos
, nStartTab
, nEndTab
);
4677 const ScSheetLimits
& rLimits
,
4678 const ScAddress
& rPos
, SCROW nGroupLen
, const ScRange
& rCheckRange
,
4679 const ScSingleRefData
& rRef
, std::vector
<SCROW
>& rBounds
, const ScRange
* pDeletedRange
)
4681 if (!rRef
.IsRowRel())
4684 ScRange
aAbs(rRef
.toAbs(rLimits
, rPos
));
4685 aAbs
.aEnd
.IncRow(nGroupLen
-1);
4686 if (!rCheckRange
.Intersects(aAbs
) && (!pDeletedRange
|| !pDeletedRange
->Intersects(aAbs
)))
4689 // Get the boundary row positions.
4690 if (aAbs
.aEnd
.Row() < rCheckRange
.aStart
.Row() && (!pDeletedRange
|| aAbs
.aEnd
.Row() < pDeletedRange
->aStart
.Row()))
4691 // No intersections.
4694 // rCheckRange may be a virtual non-existent row being shifted in.
4695 if (aAbs
.aStart
.Row() <= rCheckRange
.aStart
.Row() && rCheckRange
.aStart
.Row() < rLimits
.GetMaxRowCount())
4699 // +--+-+--+ <---- boundary row position
4704 // Add offset from the reference top to the cell position.
4705 SCROW nOffset
= rCheckRange
.aStart
.Row() - aAbs
.aStart
.Row();
4706 rBounds
.push_back(rPos
.Row()+nOffset
);
4708 // Same for deleted range.
4709 if (pDeletedRange
&& aAbs
.aStart
.Row() <= pDeletedRange
->aStart
.Row())
4711 SCROW nOffset
= pDeletedRange
->aStart
.Row() - aAbs
.aStart
.Row();
4712 SCROW nRow
= rPos
.Row() + nOffset
;
4713 // Unlike for rCheckRange, for pDeletedRange nRow can be anywhere>=0.
4714 if (rLimits
.ValidRow(nRow
))
4715 rBounds
.push_back(nRow
);
4718 if (aAbs
.aEnd
.Row() >= rCheckRange
.aEnd
.Row())
4720 // only check for end range
4725 // +--+-+--+ <---- boundary row position
4730 SCROW nOffset
= rCheckRange
.aEnd
.Row() + 1 - aAbs
.aStart
.Row();
4731 rBounds
.push_back(rPos
.Row()+nOffset
);
4733 // Same for deleted range.
4734 if (pDeletedRange
&& aAbs
.aEnd
.Row() >= pDeletedRange
->aEnd
.Row())
4736 SCROW nOffset
= pDeletedRange
->aEnd
.Row() + 1 - aAbs
.aStart
.Row();
4737 SCROW nRow
= rPos
.Row() + nOffset
;
4738 // Unlike for rCheckRange, for pDeletedRange nRow can be ~anywhere.
4739 if (rLimits
.ValidRow(nRow
))
4740 rBounds
.push_back(nRow
);
4745 const sc::RefUpdateContext
& rCxt
, const ScAddress
& rPos
, SCROW nGroupLen
,
4746 const ScSingleRefData
& rRef
, std::vector
<SCROW
>& rBounds
)
4748 if (!rRef
.IsRowRel())
4751 ScRange
aDeletedRange( ScAddress::UNINITIALIZED
);
4752 const ScRange
* pDeletedRange
= nullptr;
4754 ScRange aCheckRange
= rCxt
.maRange
;
4755 if (rCxt
.meMode
== URM_MOVE
)
4757 // Check bounds against the old range prior to the move.
4758 ScRange
aErrorRange( ScAddress::UNINITIALIZED
);
4759 if (!aCheckRange
.Move(-rCxt
.mnColDelta
, -rCxt
.mnRowDelta
, -rCxt
.mnTabDelta
, aErrorRange
, rCxt
.mrDoc
))
4761 assert(!"can't move");
4764 // Check bounds also against the range moved into.
4765 pDeletedRange
= &rCxt
.maRange
;
4767 else if (rCxt
.meMode
== URM_INSDEL
&&
4768 ((rCxt
.mnColDelta
< 0 && rCxt
.maRange
.aStart
.Col() > 0) ||
4769 (rCxt
.mnRowDelta
< 0 && rCxt
.maRange
.aStart
.Row() > 0)))
4771 // Check bounds also against deleted range where cells are shifted
4772 // into and references need to be invalidated.
4773 aDeletedRange
= getSelectedRange( rCxt
);
4774 pDeletedRange
= &aDeletedRange
;
4777 checkBounds(rCxt
.mrDoc
.GetSheetLimits(), rPos
, nGroupLen
, aCheckRange
, rRef
, rBounds
, pDeletedRange
);
4782 void ScTokenArray::CheckRelativeReferenceBounds(
4783 const sc::RefUpdateContext
& rCxt
, const ScAddress
& rPos
, SCROW nGroupLen
, std::vector
<SCROW
>& rBounds
) const
4785 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
4786 for (size_t j
=0; j
<2; ++j
)
4788 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
4789 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
4790 for (; pp
!= pEnd
; ++pp
)
4792 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
4796 switch (p
->GetType())
4800 checkBounds(rCxt
, rPos
, nGroupLen
, *p
->GetSingleRef(), rBounds
);
4805 const ScComplexRefData
& rRef
= *p
->GetDoubleRef();
4806 checkBounds(rCxt
, rPos
, nGroupLen
, rRef
.Ref1
, rBounds
);
4807 checkBounds(rCxt
, rPos
, nGroupLen
, rRef
.Ref2
, rBounds
);
4817 void ScTokenArray::CheckRelativeReferenceBounds(
4818 const ScAddress
& rPos
, SCROW nGroupLen
, const ScRange
& rRange
, std::vector
<SCROW
>& rBounds
) const
4820 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
4821 for (size_t j
=0; j
<2; ++j
)
4823 FormulaToken
** pp
= aPtrs
.maPointerRange
[j
].mpStart
;
4824 FormulaToken
** pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
4825 for (; pp
!= pEnd
; ++pp
)
4827 FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
4831 switch (p
->GetType())
4835 const ScSingleRefData
& rRef
= *p
->GetSingleRef();
4836 checkBounds(*mxSheetLimits
, rPos
, nGroupLen
, rRange
, rRef
, rBounds
, nullptr);
4841 const ScComplexRefData
& rRef
= *p
->GetDoubleRef();
4842 checkBounds(*mxSheetLimits
, rPos
, nGroupLen
, rRange
, rRef
.Ref1
, rBounds
, nullptr);
4843 checkBounds(*mxSheetLimits
, rPos
, nGroupLen
, rRange
, rRef
.Ref2
, rBounds
, nullptr);
4853 void ScTokenArray::CheckExpandReferenceBounds(
4854 const sc::RefUpdateContext
& rCxt
, const ScAddress
& rPos
, SCROW nGroupLen
, std::vector
<SCROW
>& rBounds
) const
4856 const SCROW nInsRow
= rCxt
.maRange
.aStart
.Row();
4857 TokenPointers
aPtrs( pCode
.get(), nLen
, pRPN
, nRPN
);
4858 for (size_t j
=0; j
<2; ++j
)
4860 FormulaToken
* const * pp
= aPtrs
.maPointerRange
[j
].mpStart
;
4861 const FormulaToken
* const * pEnd
= aPtrs
.maPointerRange
[j
].mpStop
;
4862 for (; pp
!= pEnd
; ++pp
)
4864 const FormulaToken
* p
= aPtrs
.getHandledToken(j
,pp
);
4868 switch (p
->GetType())
4872 const ScComplexRefData
& rRef
= *p
->GetDoubleRef();
4873 bool bStartRowRelative
= rRef
.Ref1
.IsRowRel();
4874 bool bEndRowRelative
= rRef
.Ref2
.IsRowRel();
4876 // For absolute references nothing needs to be done, they stay
4877 // the same for all and if to be expanded the group will be
4879 if (!bStartRowRelative
&& !bEndRowRelative
)
4882 ScRange
aAbsStart(rRef
.toAbs(*mxSheetLimits
, rPos
));
4883 ScAddress
aPos(rPos
);
4884 aPos
.IncRow(nGroupLen
);
4885 ScRange
aAbsEnd(rRef
.toAbs(*mxSheetLimits
, aPos
));
4886 // References must be at least two rows to be expandable.
4887 if ((aAbsStart
.aEnd
.Row() - aAbsStart
.aStart
.Row() < 1) &&
4888 (aAbsEnd
.aEnd
.Row() - aAbsEnd
.aStart
.Row() < 1))
4891 // Only need to process if an edge may be touching the
4892 // insertion row anywhere within the run of the group.
4893 if (!((aAbsStart
.aStart
.Row() <= nInsRow
&& nInsRow
<= aAbsEnd
.aStart
.Row()) ||
4894 (aAbsStart
.aEnd
.Row() <= nInsRow
&& nInsRow
<= aAbsEnd
.aEnd
.Row())))
4897 SCROW nStartRow
= aAbsStart
.aStart
.Row();
4898 SCROW nEndRow
= aAbsStart
.aEnd
.Row();
4899 // Position on first relevant range.
4901 if (nEndRow
+ 1 < nInsRow
)
4903 if (bEndRowRelative
)
4905 nOffset
= nInsRow
- nEndRow
- 1;
4907 if (bStartRowRelative
)
4908 nStartRow
+= nOffset
;
4910 else // bStartRowRelative==true
4912 nOffset
= nInsRow
- nStartRow
;
4913 nStartRow
+= nOffset
;
4914 // Start is overtaking End, swap.
4915 bStartRowRelative
= false;
4916 bEndRowRelative
= true;
4919 for (SCROW i
= nOffset
; i
< nGroupLen
; ++i
)
4921 bool bSplit
= (nStartRow
== nInsRow
|| nEndRow
+ 1 == nInsRow
);
4923 rBounds
.push_back( rPos
.Row() + i
);
4925 if (bEndRowRelative
)
4927 if (bStartRowRelative
)
4930 if (!bEndRowRelative
&& nStartRow
== nEndRow
)
4932 // Start is overtaking End, swap.
4933 bStartRowRelative
= false;
4934 bEndRowRelative
= true;
4937 if (nInsRow
< nStartRow
|| (!bStartRowRelative
&& nInsRow
<= nEndRow
))
4939 if (bSplit
&& (++i
< nGroupLen
))
4940 rBounds
.push_back( rPos
.Row() + i
);
4941 break; // for, out of range now
4955 void appendDouble( const sc::TokenStringContext
& rCxt
, OUStringBuffer
& rBuf
, double fVal
)
4957 if (rCxt
.mxOpCodeMap
->isEnglish())
4959 rtl::math::doubleToUStringBuffer(
4960 rBuf
, fVal
, rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
, '.', true);
4964 SvtSysLocale aSysLocale
;
4965 rtl::math::doubleToUStringBuffer(
4967 rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
,
4968 aSysLocale
.GetLocaleData().getNumDecimalSep()[0], true);
4972 void appendString( OUStringBuffer
& rBuf
, const OUString
& rStr
)
4975 rBuf
.append(rStr
.replaceAll("\"", "\"\""));
4979 void appendTokenByType( ScSheetLimits
& rLimits
, sc::TokenStringContext
& rCxt
, OUStringBuffer
& rBuf
, const FormulaToken
& rToken
,
4980 const ScAddress
& rPos
, bool bFromRangeName
)
4982 if (rToken
.IsExternalRef())
4984 size_t nFileId
= rToken
.GetIndex();
4985 OUString aTabName
= rToken
.GetString().getString();
4986 if (nFileId
>= rCxt
.maExternalFileNames
.size())
4990 OUString aFileName
= rCxt
.maExternalFileNames
[nFileId
];
4992 switch (rToken
.GetType())
4994 case svExternalName
:
4995 rBuf
.append(rCxt
.mpRefConv
->makeExternalNameStr(nFileId
, aFileName
, aTabName
));
4997 case svExternalSingleRef
:
4998 rCxt
.mpRefConv
->makeExternalRefStr(
4999 rLimits
, rBuf
, rPos
, nFileId
, aFileName
, aTabName
, *rToken
.GetSingleRef());
5001 case svExternalDoubleRef
:
5003 sc::TokenStringContext::IndexNamesMapType::const_iterator it
=
5004 rCxt
.maExternalCachedTabNames
.find(nFileId
);
5006 if (it
== rCxt
.maExternalCachedTabNames
.end())
5009 rCxt
.mpRefConv
->makeExternalRefStr(
5010 rLimits
, rBuf
, rPos
, nFileId
, aFileName
, it
->second
, aTabName
,
5011 *rToken
.GetDoubleRef());
5015 // warning, not error, otherwise we may end up with a never
5016 // ending message box loop if this was the cursor cell to be redrawn.
5017 OSL_FAIL("appendTokenByType: unknown type of ocExternalRef");
5022 OpCode eOp
= rToken
.GetOpCode();
5023 switch (rToken
.GetType())
5026 appendDouble(rCxt
, rBuf
, rToken
.GetDouble());
5030 OUString aStr
= rToken
.GetString().getString();
5031 if (eOp
== ocBad
|| eOp
== ocStringXML
|| eOp
== ocStringName
)
5037 appendString(rBuf
, aStr
);
5044 const ScSingleRefData
& rRef
= *rToken
.GetSingleRef();
5045 ScComplexRefData aRef
;
5048 rCxt
.mpRefConv
->makeRefStr(rLimits
, rBuf
, rCxt
.meGram
, rPos
, rCxt
.maErrRef
, rCxt
.maTabNames
, aRef
, true,
5052 rBuf
.append(rCxt
.maErrRef
);
5059 const ScComplexRefData
& rRef
= *rToken
.GetDoubleRef();
5060 rCxt
.mpRefConv
->makeRefStr(rLimits
, rBuf
, rCxt
.meGram
, rPos
, rCxt
.maErrRef
, rCxt
.maTabNames
, rRef
, false,
5064 rBuf
.append(rCxt
.maErrRef
);
5069 const ScMatrix
* pMat
= rToken
.GetMatrix();
5073 size_t nC
, nMaxC
, nR
, nMaxR
;
5074 pMat
->GetDimensions(nMaxC
, nMaxR
);
5076 rBuf
.append(rCxt
.mxOpCodeMap
->getSymbol(ocArrayOpen
));
5077 for (nR
= 0 ; nR
< nMaxR
; ++nR
)
5081 rBuf
.append(rCxt
.mxOpCodeMap
->getSymbol(ocArrayRowSep
));
5084 for (nC
= 0 ; nC
< nMaxC
; ++nC
)
5088 rBuf
.append(rCxt
.mxOpCodeMap
->getSymbol(ocArrayColSep
));
5091 if (pMat
->IsValue(nC
, nR
))
5093 if (pMat
->IsBoolean(nC
, nR
))
5095 bool bVal
= pMat
->GetDouble(nC
, nR
) != 0.0;
5096 rBuf
.append(rCxt
.mxOpCodeMap
->getSymbol(bVal
? ocTrue
: ocFalse
));
5100 FormulaError nErr
= pMat
->GetError(nC
, nR
);
5101 if (nErr
!= FormulaError::NONE
)
5102 rBuf
.append(ScGlobal::GetErrorString(nErr
));
5104 appendDouble(rCxt
, rBuf
, pMat
->GetDouble(nC
, nR
));
5107 else if (pMat
->IsEmpty(nC
, nR
))
5111 else if (pMat
->IsStringOrEmpty(nC
, nR
))
5112 appendString(rBuf
, pMat
->GetString(nC
, nR
).getString());
5115 rBuf
.append(rCxt
.mxOpCodeMap
->getSymbol(ocArrayClose
));
5120 typedef sc::TokenStringContext::IndexNameMapType NameType
;
5122 sal_uInt16 nIndex
= rToken
.GetIndex();
5127 SCTAB nTab
= rToken
.GetSheet();
5130 // global named range
5131 NameType::const_iterator it
= rCxt
.maGlobalRangeNames
.find(nIndex
);
5132 if (it
== rCxt
.maGlobalRangeNames
.end())
5134 rBuf
.append(ScCompiler::GetNativeSymbol(ocErrName
));
5138 rBuf
.append(it
->second
);
5142 // sheet-local named range
5143 if (nTab
!= rPos
.Tab())
5147 if (o3tl::make_unsigned(nTab
) < rCxt
.maTabNames
.size())
5148 aName
= rCxt
.maTabNames
[nTab
];
5149 if (!aName
.isEmpty())
5151 ScCompiler::CheckTabQuotes( aName
, rCxt
.mpRefConv
->meConv
);
5152 rBuf
.append( aName
);
5155 rBuf
.append(ScCompiler::GetNativeSymbol(ocErrName
));
5156 rBuf
.append( rCxt
.mpRefConv
->getSpecialSymbol( ScCompiler::Convention::SHEET_SEPARATOR
));
5159 sc::TokenStringContext::TabIndexMapType::const_iterator itTab
= rCxt
.maSheetRangeNames
.find(nTab
);
5160 if (itTab
== rCxt
.maSheetRangeNames
.end())
5162 rBuf
.append(ScCompiler::GetNativeSymbol(ocErrName
));
5166 const NameType
& rNames
= itTab
->second
;
5167 NameType::const_iterator it
= rNames
.find(nIndex
);
5168 if (it
== rNames
.end())
5170 rBuf
.append(ScCompiler::GetNativeSymbol(ocErrName
));
5174 rBuf
.append(it
->second
);
5181 NameType::const_iterator it
= rCxt
.maNamedDBs
.find(nIndex
);
5182 if (it
!= rCxt
.maNamedDBs
.end())
5183 rBuf
.append(it
->second
);
5187 rBuf
.append(ScCompiler::GetNativeSymbol(ocErrName
));
5193 // mapped or translated name of AddIns
5194 OUString aAddIn
= rToken
.GetExternal();
5195 bool bMapped
= rCxt
.mxOpCodeMap
->isPODF(); // ODF 1.1 directly uses programmatical name
5196 if (!bMapped
&& rCxt
.mxOpCodeMap
->hasExternals())
5198 const ExternalHashMap
& rExtMap
= rCxt
.mxOpCodeMap
->getReverseExternalHashMap();
5199 ExternalHashMap::const_iterator it
= rExtMap
.find(aAddIn
);
5200 if (it
!= rExtMap
.end())
5202 aAddIn
= it
->second
;
5207 if (!bMapped
&& !rCxt
.mxOpCodeMap
->isEnglish())
5208 ScGlobal::GetAddInCollection()->LocalizeString(aAddIn
);
5210 rBuf
.append(aAddIn
);
5215 FormulaError nErr
= rToken
.GetError();
5220 case FormulaError::DivisionByZero
:
5221 eOpErr
= ocErrDivZero
;
5223 case FormulaError::NoValue
:
5224 eOpErr
= ocErrValue
;
5226 case FormulaError::NoRef
:
5229 case FormulaError::NoName
:
5232 case FormulaError::IllegalFPOperation
:
5235 case FormulaError::NotAvailable
:
5238 case FormulaError::NoCode
:
5242 rBuf
.append(rCxt
.mxOpCodeMap
->getSymbol(eOpErr
));
5257 OUString
ScTokenArray::CreateString( sc::TokenStringContext
& rCxt
, const ScAddress
& rPos
) const
5262 OUStringBuffer aBuf
;
5264 FormulaToken
** p
= pCode
.get();
5265 FormulaToken
** pEnd
= p
+ static_cast<size_t>(nLen
);
5266 for (; p
!= pEnd
; ++p
)
5268 const FormulaToken
* pToken
= *p
;
5269 OpCode eOp
= pToken
->GetOpCode();
5270 /* FIXME: why does this ignore the count of spaces? */
5271 if (eOp
== ocSpaces
)
5273 // TODO : Handle intersection operator '!!'.
5277 else if (eOp
== ocWhitespace
)
5279 aBuf
.append( pToken
->GetChar());
5283 if (eOp
< rCxt
.mxOpCodeMap
->getSymbolCount())
5284 aBuf
.append(rCxt
.mxOpCodeMap
->getSymbol(eOp
));
5286 appendTokenByType(*mxSheetLimits
, rCxt
, aBuf
, *pToken
, rPos
, IsFromRangeName());
5289 return aBuf
.makeStringAndClear();
5294 void wrapAddress( ScAddress
& rPos
, SCCOL nMaxCol
, SCROW nMaxRow
)
5296 if (rPos
.Col() > nMaxCol
)
5297 rPos
.SetCol(rPos
.Col() % (nMaxCol
+1));
5298 if (rPos
.Row() > nMaxRow
)
5299 rPos
.SetRow(rPos
.Row() % (nMaxRow
+1));
5302 template<typename T
> void wrapRange( T
& n1
, T
& n2
, T nMax
)
5307 n2
= nMax
; // Truncate to full range instead of wrapping to a weird range.
5315 void wrapColRange( ScRange
& rRange
, SCCOL nMaxCol
)
5317 SCCOL nCol1
= rRange
.aStart
.Col();
5318 SCCOL nCol2
= rRange
.aEnd
.Col();
5319 wrapRange( nCol1
, nCol2
, nMaxCol
);
5320 rRange
.aStart
.SetCol( nCol1
);
5321 rRange
.aEnd
.SetCol( nCol2
);
5324 void wrapRowRange( ScRange
& rRange
, SCROW nMaxRow
)
5326 SCROW nRow1
= rRange
.aStart
.Row();
5327 SCROW nRow2
= rRange
.aEnd
.Row();
5328 wrapRange( nRow1
, nRow2
, nMaxRow
);
5329 rRange
.aStart
.SetRow( nRow1
);
5330 rRange
.aEnd
.SetRow( nRow2
);
5335 void ScTokenArray::WrapReference( const ScAddress
& rPos
, SCCOL nMaxCol
, SCROW nMaxRow
)
5337 FormulaToken
** p
= pCode
.get();
5338 FormulaToken
** pEnd
= p
+ static_cast<size_t>(nLen
);
5339 for (; p
!= pEnd
; ++p
)
5341 switch ((*p
)->GetType())
5345 formula::FormulaToken
* pToken
= *p
;
5346 ScSingleRefData
& rRef
= *pToken
->GetSingleRef();
5347 ScAddress aAbs
= rRef
.toAbs(*mxSheetLimits
, rPos
);
5348 wrapAddress(aAbs
, nMaxCol
, nMaxRow
);
5349 rRef
.SetAddress(*mxSheetLimits
, aAbs
, rPos
);
5354 formula::FormulaToken
* pToken
= *p
;
5355 ScComplexRefData
& rRef
= *pToken
->GetDoubleRef();
5356 ScRange aAbs
= rRef
.toAbs(*mxSheetLimits
, rPos
);
5357 // Entire columns/rows are sticky.
5358 if (!rRef
.IsEntireCol(*mxSheetLimits
) && !rRef
.IsEntireRow(*mxSheetLimits
))
5360 wrapColRange( aAbs
, nMaxCol
);
5361 wrapRowRange( aAbs
, nMaxRow
);
5363 else if (rRef
.IsEntireCol(*mxSheetLimits
) && !rRef
.IsEntireRow(*mxSheetLimits
))
5364 wrapColRange( aAbs
, nMaxCol
);
5365 else if (!rRef
.IsEntireCol(*mxSheetLimits
) && rRef
.IsEntireRow(*mxSheetLimits
))
5366 wrapRowRange( aAbs
, nMaxRow
);
5367 // else nothing if both, column and row, are entire.
5369 rRef
.SetRange(*mxSheetLimits
, aAbs
, rPos
);
5378 sal_Int32
ScTokenArray::GetWeight() const
5380 sal_Int32 nResult
= 0;
5381 for (auto i
= 0; i
< nRPN
; ++i
)
5383 switch ((*pRPN
[i
]).GetType())
5387 const auto pComplexRef
= (*pRPN
[i
]).GetDoubleRef();
5389 // Number of cells referenced divided by 10.
5390 const double nRows
= 1 + (pComplexRef
->Ref2
.Row() - pComplexRef
->Ref1
.Row());
5391 const double nCols
= 1 + (pComplexRef
->Ref2
.Col() - pComplexRef
->Ref1
.Col());
5392 const double nNumCellsTerm
= nRows
* nCols
/ 10.0;
5394 if (nNumCellsTerm
+ nResult
< SAL_MAX_INT32
)
5395 nResult
+= nNumCellsTerm
;
5397 nResult
= SAL_MAX_INT32
;
5411 #if DEBUG_FORMULA_COMPILER
5413 void ScTokenArray::Dump() const
5415 cout
<< "+++ Normal Tokens +++" << endl
;
5416 for (sal_uInt16 i
= 0; i
< nLen
; ++i
)
5418 DumpToken(*pCode
[i
]);
5421 cout
<< "+++ RPN Tokens +++" << endl
;
5422 for (sal_uInt16 i
= 0; i
< nRPN
; ++i
)
5424 DumpToken(*pRPN
[i
]);
5429 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */