LibreOffice Module sc (master) 1
token.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <functional>
21
22#include <string.h>
23#include <osl/diagnose.h>
24#include <sal/log.hxx>
25
26#include <token.hxx>
27#include <tokenarray.hxx>
28#include <reftokenhelper.hxx>
29#include <clipparam.hxx>
30#include <compiler.hxx>
31#include <interpre.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>
42#include <types.hxx>
43#include <addincol.hxx>
44#include <dbdata.hxx>
45#include <reordermap.hxx>
46#include <svl/sharedstring.hxx>
47#include <scmatrix.hxx>
48
49using ::std::vector;
50
51#include <com/sun/star/sheet/ComplexReference.hpp>
52#include <com/sun/star/sheet/ExternalReference.hpp>
53#include <com/sun/star/sheet/FormulaToken.hpp>
54#include <com/sun/star/sheet/ReferenceFlags.hpp>
55#include <com/sun/star/sheet/NameToken.hpp>
56#include <utility>
57#include <o3tl/safeint.hxx>
59
60using namespace formula;
61using namespace com::sun::star;
62
63namespace
64{
65 void lcl_SingleRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI )
66 {
67 rRef.InitFlags();
68
69 rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 );
70 rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 );
71 rRef.SetTabRel( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_RELATIVE ) != 0 );
72 rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 );
73 rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 );
74 rRef.SetTabDeleted( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_DELETED ) != 0 );
75 rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 );
76 rRef.SetRelName( ( rAPI.Flags & sheet::ReferenceFlags::RELATIVE_NAME ) != 0 );
77
78 if (rRef.IsColRel())
79 rRef.SetRelCol(static_cast<SCCOL>(rAPI.RelativeColumn));
80 else
81 rRef.SetAbsCol(static_cast<SCCOL>(rAPI.Column));
82
83 if (rRef.IsRowRel())
84 rRef.SetRelRow(static_cast<SCROW>(rAPI.RelativeRow));
85 else
86 rRef.SetAbsRow(static_cast<SCROW>(rAPI.Row));
87
88 if (rRef.IsTabRel())
89 rRef.SetRelTab(static_cast<SCTAB>(rAPI.RelativeSheet));
90 else
91 rRef.SetAbsTab(static_cast<SCTAB>(rAPI.Sheet));
92 }
93
94 void lcl_ExternalRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI )
95 {
96 rRef.InitFlags();
97
98 rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 );
99 rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 );
100 rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 );
101 rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 );
102 rRef.SetTabDeleted( false ); // sheet must not be deleted for external refs
103 rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 );
104 rRef.SetRelName( false );
105
106 if (rRef.IsColRel())
107 rRef.SetRelCol(static_cast<SCCOL>(rAPI.RelativeColumn));
108 else
109 rRef.SetAbsCol(static_cast<SCCOL>(rAPI.Column));
110
111 if (rRef.IsRowRel())
112 rRef.SetRelRow(static_cast<SCROW>(rAPI.RelativeRow));
113 else
114 rRef.SetAbsRow(static_cast<SCROW>(rAPI.Row));
115
116 // sheet index must be absolute for external refs
117 rRef.SetAbsTab(0);
118 }
119
120 struct TokenPointerRange
121 {
123 FormulaToken** mpStop;
124
125 TokenPointerRange() : mpStart(nullptr), mpStop(nullptr) {}
126 TokenPointerRange( FormulaToken** p, sal_uInt16 n ) :
127 mpStart(p), mpStop( p + static_cast<size_t>(n)) {}
128 };
129 struct TokenPointers
130 {
131 TokenPointerRange maPointerRange[2];
132 bool mbSkipRelName;
133
134 TokenPointers( FormulaToken** pCode, sal_uInt16 nLen, FormulaToken** pRPN, sal_uInt16 nRPN,
135 bool bSkipRelName = true ) :
136 mbSkipRelName(bSkipRelName)
137 {
138 maPointerRange[0] = TokenPointerRange( pCode, nLen);
139 maPointerRange[1] = TokenPointerRange( pRPN, nRPN);
140 }
141
142 bool skipToken( size_t i, const FormulaToken* const * pp )
143 {
144 // Handle all code tokens, and tokens in RPN only if they have a
145 // reference count of 1, which means they are not referenced in the
146 // code array. Doing it the other way would skip code tokens that
147 // are held by flat copied token arrays and thus are shared. For
148 // flat copy arrays the caller has to know what it does and should
149 // discard all RPN, update only one array and regenerate all RPN.
150 if (i == 1)
151 {
152 if ((*pp)->GetRef() > 1)
153 return true;
154
155 if (mbSkipRelName)
156 {
157 // Skip (do not adjust) relative references resulting from
158 // named expressions. Resolved expressions are only in RPN.
159 switch ((*pp)->GetType())
160 {
161 case svSingleRef:
162 return (*pp)->GetSingleRef()->IsRelName();
163 case svDoubleRef:
164 {
165 const ScComplexRefData& rRef = *(*pp)->GetDoubleRef();
166 return rRef.Ref1.IsRelName() || rRef.Ref2.IsRelName();
167 }
168 default:
169 ; // nothing
170 }
171 }
172 }
173
174 return false;
175 }
176
177 FormulaToken* getHandledToken( size_t i, FormulaToken* const * pp )
178 {
179 if (skipToken( i, pp))
180 return nullptr;
181
182 FormulaToken* p = *pp;
183 if (p->GetOpCode() == ocTableRef)
184 {
185 // Return the inner reference token if it is not in RPN.
186 ScTableRefToken* pTR = dynamic_cast<ScTableRefToken*>(p);
187 if (!pTR)
188 return p;
189 p = pTR->GetAreaRefRPN();
190 if (!p)
191 return pTR;
192 if (p->GetRef() > 1)
193 // Reference handled in RPN, but do not return nullptr so
194 // loops will process ocTableRef via pp instead of issuing
195 // a continue.
196 return pTR;
197 }
198 return p;
199 }
200 };
201
202} // namespace
203
204
205// --- class ScRawToken -----------------------------------------------------
206
208{
209 eOp = e;
210 switch (eOp)
211 {
212 case ocIf:
213 eType = svJump;
214 nJump[ 0 ] = 3; // If, Else, Behind
215 break;
216 case ocIfError:
217 case ocIfNA:
218 eType = svJump;
219 nJump[ 0 ] = 2; // If, Behind
220 break;
221 case ocChoose:
222 eType = svJump;
223 nJump[ 0 ] = FORMULA_MAXJUMPCOUNT + 1;
224 break;
225 case ocMissing:
227 break;
228 case ocSep:
229 case ocOpen:
230 case ocClose:
231 case ocArrayRowSep:
232 case ocArrayColSep:
233 case ocArrayOpen:
234 case ocArrayClose:
235 case ocTableRefOpen:
236 case ocTableRefClose:
237 eType = svSep;
238 break;
239 case ocWhitespace:
240 eType = svByte;
241 whitespace.nCount = 1;
242 whitespace.cChar = 0x20;
243 break;
244 default:
245 eType = svByte;
246 sbyte.cByte = 0;
247 sbyte.eInForceArray = ParamClass::Unknown;
248 }
249}
250
251void ScRawToken::SetString( rtl_uString* pData, rtl_uString* pDataIgnoreCase )
252{
253 eOp = ocPush;
254 eType = svString;
255
256 sharedstring.mpData = pData;
257 sharedstring.mpDataIgnoreCase = pDataIgnoreCase;
258}
259
261{
262 eOp = ocPush;
264 aRef.Ref1 =
265 aRef.Ref2 = rRef;
266}
267
269{
270 eOp = ocPush;
272 aRef = rRef;
273}
274
275void ScRawToken::SetDouble(double rVal)
276{
277 eOp = ocPush;
278 eType = svDouble;
279 nValue = rVal;
280}
281
283{
284 eOp = ocPush;
285 eType = svError;
286 nError = nErr;
287}
288
289void ScRawToken::SetName(sal_Int16 nSheet, sal_uInt16 nIndex)
290{
291 eOp = ocName;
292 eType = svIndex;
293
294 name.nSheet = nSheet;
295 name.nIndex = nIndex;
296}
297
298void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const OUString& rTabName, const ScSingleRefData& rRef )
299{
300 eOp = ocPush;
302
303 extref.nFileId = nFileId;
304 extref.aRef.Ref1 =
305 extref.aRef.Ref2 = rRef;
306 maExternalName = rTabName;
307}
308
309void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const OUString& rTabName, const ScComplexRefData& rRef )
310{
311 eOp = ocPush;
313
314 extref.nFileId = nFileId;
315 extref.aRef = rRef;
316 maExternalName = rTabName;
317}
318
319void ScRawToken::SetExternalName( sal_uInt16 nFileId, const OUString& rName )
320{
321 eOp = ocPush;
323
324 extname.nFileId = nFileId;
325 maExternalName = rName;
326}
327
328void ScRawToken::SetExternal( const OUString& rStr )
329{
330 eOp = ocExternal;
332 maExternalName = rStr;
333}
334
336{
337 switch (eType)
338 {
339 case svSingleRef:
340 return aRef.Ref1.Valid(rDoc);
341 case svDoubleRef:
342 return aRef.Valid(rDoc);
345 return true;
346 default:
347 ; // nothing
348 }
349 return false;
350}
351
353{
354#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!")
355 switch ( GetType() )
356 {
357 case svByte :
358 if (eOp == ocWhitespace)
359 return new FormulaSpaceToken( whitespace.nCount, whitespace.cChar );
360 else
361 return new FormulaByteToken( eOp, sbyte.cByte, sbyte.eInForceArray );
362 case svDouble :
364 return new FormulaDoubleToken( nValue );
365 case svString :
366 {
367 svl::SharedString aSS(sharedstring.mpData, sharedstring.mpDataIgnoreCase);
368 if (eOp == ocPush)
369 return new FormulaStringToken(std::move(aSS));
370 else
371 return new FormulaStringOpToken(eOp, std::move(aSS));
372 }
373 case svSingleRef :
374 if (eOp == ocPush)
375 return new ScSingleRefToken(rLimits, aRef.Ref1 );
376 else
377 return new ScSingleRefToken(rLimits, aRef.Ref1, eOp );
378 case svDoubleRef :
379 if (eOp == ocPush)
380 return new ScDoubleRefToken(rLimits, aRef );
381 else
382 return new ScDoubleRefToken(rLimits, aRef, eOp );
383 case svMatrix :
385 return new ScMatrixToken( pMat );
386 case svIndex :
387 if (eOp == ocTableRef)
388 return new ScTableRefToken( table.nIndex, table.eItem);
389 else
390 return new FormulaIndexToken( eOp, name.nIndex, name.nSheet);
392 {
393 svl::SharedString aTabName(maExternalName); // string not interned
394 return new ScExternalSingleRefToken(extref.nFileId, std::move(aTabName), extref.aRef.Ref1);
395 }
397 {
398 svl::SharedString aTabName(maExternalName); // string not interned
399 return new ScExternalDoubleRefToken(extref.nFileId, std::move(aTabName), extref.aRef);
400 }
401 case svExternalName:
402 {
403 svl::SharedString aName(maExternalName); // string not interned
404 return new ScExternalNameToken( extname.nFileId, std::move(aName) );
405 }
406 case svJump :
407 return new FormulaJumpToken( eOp, nJump );
408 case svExternal :
409 return new FormulaExternalToken( eOp, sbyte.cByte, maExternalName );
410 case svFAP :
411 return new FormulaFAPToken( eOp, sbyte.cByte, nullptr );
412 case svMissing :
414 return new FormulaMissingToken;
415 case svSep :
416 return new FormulaToken( svSep,eOp );
417 case svError :
418 return new FormulaErrorToken( nError );
419 case svUnknown :
420 return new FormulaUnknownToken( eOp );
421 default:
422 {
423 SAL_WARN("sc.core", "unknown ScRawToken::CreateToken() type " << int(GetType()));
424 return new FormulaUnknownToken( ocBad );
425 }
426 }
427#undef IF_NOT_OPCODE_ERROR
428}
429
430namespace {
431
432// TextEqual: if same formula entered (for optimization in sort)
433bool checkTextEqual( const ScSheetLimits& rLimits, const FormulaToken& _rToken1, const FormulaToken& _rToken2 )
434{
435 assert(
436 (_rToken1.GetType() == svSingleRef || _rToken1.GetType() == svDoubleRef)
437 && _rToken1.FormulaToken::operator ==(_rToken2));
438
439 // in relative Refs only compare relative parts
440
441 ScComplexRefData aTemp1;
442 if ( _rToken1.GetType() == svSingleRef )
443 {
444 aTemp1.Ref1 = *_rToken1.GetSingleRef();
445 aTemp1.Ref2 = aTemp1.Ref1;
446 }
447 else
448 aTemp1 = *_rToken1.GetDoubleRef();
449
450 ScComplexRefData aTemp2;
451 if ( _rToken2.GetType() == svSingleRef )
452 {
453 aTemp2.Ref1 = *_rToken2.GetSingleRef();
454 aTemp2.Ref2 = aTemp2.Ref1;
455 }
456 else
457 aTemp2 = *_rToken2.GetDoubleRef();
458
459 ScAddress aPos;
460 ScRange aRange1 = aTemp1.toAbs(rLimits, aPos), aRange2 = aTemp2.toAbs(rLimits, aPos);
461
462 // memcmp doesn't work because of the alignment byte after bFlags.
463 // After SmartRelAbs only absolute parts have to be compared.
464 return aRange1 == aRange2 && aTemp1.Ref1.FlagValue() == aTemp2.Ref1.FlagValue() && aTemp1.Ref2.FlagValue() == aTemp2.Ref2.FlagValue();
465}
466
467}
468
469#if DEBUG_FORMULA_COMPILER
470void DumpToken(formula::FormulaToken const & rToken)
471{
472 switch (rToken.GetType()) {
473 case svSingleRef:
474 cout << "-- ScSingleRefToken" << endl;
475 rToken.GetSingleRef()->Dump(1);
476 break;
477 case svDoubleRef:
478 cout << "-- ScDoubleRefToken" << endl;
479 rToken.GetDoubleRef()->Dump(1);
480 break;
481 default:
482 cout << "-- FormulaToken" << endl;
483 cout << " opcode: " << int(rToken.GetOpCode()) << " " <<
484 formula::FormulaCompiler::GetNativeSymbol( rToken.GetOpCode()).toUtf8().getStr() << endl;
485 cout << " type: " << static_cast<int>(rToken.GetType()) << endl;
486 switch (rToken.GetType())
487 {
488 case svDouble:
489 cout << " value: " << rToken.GetDouble() << endl;
490 break;
491 case svString:
492 cout << " string: "
493 << OUStringToOString(rToken.GetString().getString(), RTL_TEXTENCODING_UTF8).getStr()
494 << endl;
495 break;
496 default:
497 ;
498 }
499 break;
500 }
501}
502#endif
503
505 const ScAddress & rPos, bool bReuseDoubleRef )
506{
507
508 StackVar sv1 = rTok1.GetType();
509 // Doing a RangeOp with RefList is probably utter nonsense, but Xcl
510 // supports it, so do we.
511 if (sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList
512 && sv1 != svExternalSingleRef && sv1 != svExternalDoubleRef)
513 return nullptr;
514 StackVar sv2 = rTok2.GetType();
515 if (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList)
516 return nullptr;
517
518 ScTokenRef xRes;
519 bool bExternal = (sv1 == svExternalSingleRef);
520 if ((sv1 == svSingleRef || bExternal) && sv2 == svSingleRef)
521 {
522 // Range references like Sheet1.A1:A2 are generalized and built by
523 // first creating a DoubleRef from the first SingleRef, effectively
524 // generating Sheet1.A1:A1, and then extending that with A2 as if
525 // Sheet1.A1:A1:A2 was encountered, so the mechanisms to adjust the
526 // references apply as well.
527
528 /* Given the current structure of external references an external
529 * reference can only be extended if the second reference does not
530 * point to a different sheet. 'file'#Sheet1.A1:A2 is ok,
531 * 'file'#Sheet1.A1:Sheet2.A2 is not. Since we can't determine from a
532 * svSingleRef whether the sheet would be different from the one given
533 * in the external reference, we have to bail out if there is any sheet
534 * specified. NOTE: Xcl does handle external 3D references as in
535 * '[file]Sheet1:Sheet2'!A1:A2
536 *
537 * FIXME: For OOo syntax be smart and remember an external singleref
538 * encountered and if followed by ocRange and singleref, create an
539 * external singleref for the second singleref. Both could then be
540 * merged here. For Xcl syntax already parse an external range
541 * reference entirely, cumbersome. */
542
543 const ScSingleRefData& rRef2 = *rTok2.GetSingleRef();
544 if (bExternal && rRef2.IsFlag3D())
545 return nullptr;
546
547 ScComplexRefData aRef;
548 aRef.Ref1 = aRef.Ref2 = *rTok1.GetSingleRef();
549 aRef.Ref2.SetFlag3D( false);
550 aRef.Extend(rLimits, rRef2, rPos);
551 if (bExternal)
552 xRes = new ScExternalDoubleRefToken( rTok1.GetIndex(), rTok1.GetString(), aRef);
553 else
554 xRes = new ScDoubleRefToken(rLimits, aRef);
555 }
556 else
557 {
558 bExternal |= (sv1 == svExternalDoubleRef);
559 const ScRefList* pRefList = nullptr;
560 if (sv1 == svDoubleRef)
561 {
562 xRes = (bReuseDoubleRef && rTok1.GetRef() == 1 ? &rTok1 : rTok1.Clone());
563 sv1 = svUnknown; // mark as handled
564 }
565 else if (sv2 == svDoubleRef)
566 {
567 xRes = (bReuseDoubleRef && rTok2.GetRef() == 1 ? &rTok2 : rTok2.Clone());
568 sv2 = svUnknown; // mark as handled
569 }
570 else if (sv1 == svRefList)
571 pRefList = rTok1.GetRefList();
572 else if (sv2 == svRefList)
573 pRefList = rTok2.GetRefList();
574 if (pRefList)
575 {
576 if (pRefList->empty())
577 return nullptr;
578 if (bExternal)
579 return nullptr; // external reference list not possible
580 xRes = new ScDoubleRefToken(rLimits, (*pRefList)[0] );
581 }
582 if (!xRes)
583 return nullptr; // shouldn't happen...
584 StackVar sv[2] = { sv1, sv2 };
585 formula::FormulaToken* pt[2] = { &rTok1, &rTok2 };
586 ScComplexRefData& rRef = *xRes->GetDoubleRef();
587 for (size_t i=0; i<2; ++i)
588 {
589 switch (sv[i])
590 {
591 case svSingleRef:
592 rRef.Extend(rLimits, *pt[i]->GetSingleRef(), rPos);
593 break;
594 case svDoubleRef:
595 rRef.Extend(rLimits, *pt[i]->GetDoubleRef(), rPos);
596 break;
597 case svRefList:
598 {
599 const ScRefList* p = pt[i]->GetRefList();
600 if (p->empty())
601 return nullptr;
602 for (const auto& rRefData : *p)
603 {
604 rRef.Extend(rLimits, rRefData, rPos);
605 }
606 }
607 break;
609 if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D())
610 return nullptr; // no other sheets with external refs
611 else
612 rRef.Extend(rLimits, *pt[i]->GetSingleRef(), rPos);
613 break;
615 if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D())
616 return nullptr; // no other sheets with external refs
617 else
618 rRef.Extend(rLimits, *pt[i]->GetDoubleRef(), rPos);
619 break;
620 default:
621 ; // nothing, prevent compiler warning
622 }
623 }
624 }
625 return FormulaTokenRef(xRes.get());
626}
627
628// real implementations of virtual functions
629
632bool ScSingleRefToken::TextEqual( const FormulaToken& _rToken ) const
633{
634 return FormulaToken::operator ==(_rToken) && checkTextEqual(mrSheetLimits, *this, _rToken);
635}
637{
638 return FormulaToken::operator==( r ) && aSingleRef == *r.GetSingleRef();
639}
640
647bool ScDoubleRefToken::TextEqual( const FormulaToken& _rToken ) const
648{
649 return FormulaToken::operator ==(_rToken) && checkTextEqual(mrSheetLimits, *this, _rToken);
650}
652{
653 return FormulaToken::operator==( r ) && aDoubleRef == *r.GetDoubleRef();
654}
655
660{
661 if (!FormulaToken::operator==( r ) || &aRefList != r.GetRefList())
662 return false;
663 const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(&r);
664 return p && mbArrayResult == p->IsArrayResult();
665}
666
668 FormulaToken(formula::svMatrix), pMatrix(std::move(p)) {}
669
671
672const ScMatrix* ScMatrixToken::GetMatrix() const { return pMatrix.get(); }
675{
676 return FormulaToken::operator==( r ) && pMatrix == r.GetMatrix();
677}
678
680 FormulaToken(formula::svMatrix), mpMatrix(rMat.mpMat)
681{
682 maRef.InitRange(rMat.mnCol1, rMat.mnRow1, rMat.mnTab1, rMat.mnCol2, rMat.mnRow2, rMat.mnTab2);
683}
684
686
688{
690}
691
693{
694 return mpMatrix.get();
695}
696
698{
699 return mpMatrix.get();
700}
701
703{
704 return &maRef;
705}
706
708{
709 return &maRef;
710}
711
713{
714 return FormulaToken::operator==(r) && mpMatrix == r.GetMatrix();
715}
716
718{
719 return new ScMatrixRangeToken(*this);
720}
721
724 mnFileId(nFileId),
725 maTabName(std::move(aTabName)),
726 maSingleRef(r)
727{
728}
729
731{
732}
733
735{
736 return mnFileId;
737}
738
740{
741 return maTabName;
742}
743
745{
746 return &maSingleRef;
747}
748
750{
751 return &maSingleRef;
752}
753
755{
756 if (!FormulaToken::operator==(r))
757 return false;
758
759 if (mnFileId != r.GetIndex())
760 return false;
761
762 if (maTabName != r.GetString())
763 return false;
764
765 return maSingleRef == *r.GetSingleRef();
766}
767
770 mnFileId(nFileId),
771 maTabName(std::move(aTabName)),
772 maDoubleRef(r)
773{
774}
775
777{
778}
779
781{
782 return mnFileId;
783}
784
786{
787 return maTabName;
788}
789
791{
792 return &maDoubleRef.Ref1;
793}
794
796{
797 return &maDoubleRef.Ref1;
798}
799
801{
802 return &maDoubleRef.Ref2;
803}
804
806{
807 return &maDoubleRef.Ref2;
808}
809
811{
812 return &maDoubleRef;
813}
814
816{
817 return &maDoubleRef;
818}
819
821{
822 if (!FormulaToken::operator==(r))
823 return false;
824
825 if (mnFileId != r.GetIndex())
826 return false;
827
828 if (maTabName != r.GetString())
829 return false;
830
831 return maDoubleRef == *r.GetDoubleRef();
832}
833
836 mnFileId(nFileId),
837 maName(std::move(aName))
838{
839}
840
842
844{
845 return mnFileId;
846}
847
849{
850 return maName;
851}
852
854{
855 if ( !FormulaToken::operator==(r) )
856 return false;
857
858 if (mnFileId != r.GetIndex())
859 return false;
860
861 return maName.getData() == r.GetString().getData();
862}
863
867 meItem(eItem)
868{
869}
870
872 FormulaToken(r),
873 mxAreaRefRPN( r.mxAreaRefRPN ? r.mxAreaRefRPN->Clone() : nullptr),
874 mnIndex(r.mnIndex),
875 meItem(r.meItem)
876{
877}
878
880
882{
883 return mnIndex;
884}
885
886void ScTableRefToken::SetIndex( sal_uInt16 n )
887{
888 mnIndex = n;
889}
890
892{
893 // Code asking for this may have to be adapted as it might assume an
894 // svIndex token would always be ocName or ocDBArea.
895 SAL_WARN("sc.core","ScTableRefToken::GetSheet - maybe adapt caller to know about TableRef?");
896 // Database range is always global.
897 return -1;
898}
899
901{
902 return meItem;
903}
904
906{
907 meItem = static_cast<ScTableRefToken::Item>(meItem | eItem);
908}
909
911{
912 mxAreaRefRPN = pToken;
913}
914
916{
917 return mxAreaRefRPN.get();
918}
919
921{
922 if ( !FormulaToken::operator==(r) )
923 return false;
924
925 if (mnIndex != r.GetIndex())
926 return false;
927
928 const ScTableRefToken* p = dynamic_cast<const ScTableRefToken*>(&r);
929 if (!p)
930 return false;
931
932 if (meItem != p->GetItem())
933 return false;
934
935 if (!mxAreaRefRPN && !p->mxAreaRefRPN)
936 ; // nothing
937 else if (!mxAreaRefRPN || !p->mxAreaRefRPN)
938 return false;
939 else if (!(*mxAreaRefRPN == *(p->mxAreaRefRPN)))
940 return false;
941
942 return true;
943}
944
945ScJumpMatrixToken::ScJumpMatrixToken(std::shared_ptr<ScJumpMatrix> p)
947 , mpJumpMatrix(std::move(p))
948{}
949
951
953{
954 return mpJumpMatrix.get();
955}
956
958{
959 return FormulaToken::operator==( r ) && mpJumpMatrix.get() == r.GetJumpMatrix();
960}
961
963{
964}
965
966double ScEmptyCellToken::GetDouble() const { return 0.0; }
967
969{
971}
972
974{
975 return FormulaToken::operator==( r ) &&
976 bInherited == static_cast< const ScEmptyCellToken & >(r).IsInherited() &&
977 bDisplayedAsString == static_cast< const ScEmptyCellToken & >(r).IsDisplayedAsString();
978}
979
981 FormulaToken(formula::svMatrixCell), xMatrix(std::move(pMat)), xUpperLeft(pUL) {}
982
984
985double ScMatrixCellResultToken::GetDouble() const { return xUpperLeft->GetDouble(); }
986
988
990{
991 return xUpperLeft->GetString();
992}
993
995// Non-const GetMatrix() is private and unused but must be implemented to
996// satisfy vtable linkage.
998{
999 return const_cast<ScMatrix*>(xMatrix.get());
1000}
1001
1003{
1004 return FormulaToken::operator==( r ) &&
1005 xUpperLeft == static_cast<const ScMatrixCellResultToken &>(r).xUpperLeft &&
1006 xMatrix == static_cast<const ScMatrixCellResultToken &>(r).xMatrix;
1007}
1008
1010{
1011 return new ScMatrixCellResultToken(*this);
1012}
1013
1015{
1016 xMatrix = r.xMatrix;
1018}
1019
1021 SCCOL nC, SCROW nR, const ScConstMatrixRef& pMat, const formula::FormulaToken* pUL ) :
1022 ScMatrixCellResultToken(pMat, pUL), nRows(nR), nCols(nC)
1023{
1025}
1026
1028 ScMatrixCellResultToken(nullptr, nullptr), nRows(nR), nCols(nC) {}
1029
1031 ScMatrixCellResultToken(r), nRows(r.nRows), nCols(r.nCols)
1032{
1034}
1035
1037
1039{
1040 const ScMatrixFormulaCellToken* p = dynamic_cast<const ScMatrixFormulaCellToken*>(&r);
1041 return p && ScMatrixCellResultToken::operator==( r ) &&
1042 nCols == p->nCols && nRows == p->nRows;
1043}
1044
1046{
1047 if (xUpperLeft && xUpperLeft->GetType() == svDouble)
1048 xUpperLeft = xUpperLeft->Clone();
1049}
1050
1052{
1054
1056}
1057
1059{
1060 if (this == &r)
1061 return;
1062 const ScMatrixCellResultToken* p = dynamic_cast<const ScMatrixCellResultToken*>(&r);
1063 if (p)
1065 else
1066 {
1067 OSL_ENSURE( r.GetType() != svMatrix, "ScMatrixFormulaCellToken::operator=: assigning ScMatrixToken to ScMatrixFormulaCellToken is not proper, use ScMatrixCellResultToken instead");
1068 if (r.GetType() == svMatrix)
1069 {
1070 xUpperLeft = nullptr;
1071 xMatrix = r.GetMatrix();
1072 }
1073 else
1074 {
1075 xUpperLeft = &r;
1076 xMatrix = nullptr;
1078 }
1079 }
1080}
1081
1083{
1084 switch (GetUpperLeftType())
1085 {
1086 case svDouble:
1087 const_cast<FormulaToken*>(xUpperLeft.get())->GetDoubleAsReference() = f;
1088 break;
1089 case svString:
1091 break;
1092 case svUnknown:
1093 if (!xUpperLeft)
1094 {
1096 break;
1097 }
1098 [[fallthrough]];
1099 default:
1100 {
1101 OSL_FAIL("ScMatrixFormulaCellToken::SetUpperLeftDouble: not modifying unhandled token type");
1102 }
1103 }
1104}
1105
1107{
1108 xMatrix = nullptr;
1109 xUpperLeft = nullptr;
1110}
1111
1113 double f, const svl::SharedString & rStr, OUString aFormula, bool bEmptyDisplayedAsString ) :
1115 mfDouble( f ), maString( rStr ),
1116 maFormula(std::move( aFormula )),
1117 mbEmptyDisplayedAsString( bEmptyDisplayedAsString)
1118{
1119 // caller, make up your mind...
1120 assert( !bEmptyDisplayedAsString || (f == 0.0 && rStr.getString().isEmpty()));
1121}
1122
1123double ScHybridCellToken::GetDouble() const { return mfDouble; }
1124
1126{
1127 return maString;
1128}
1129
1131{
1132 return FormulaToken::operator==( r ) &&
1133 mfDouble == r.GetDouble() && maString == r.GetString() &&
1134 maFormula == static_cast<const ScHybridCellToken &>(r).GetFormula();
1135}
1136
1138 const css::sheet::FormulaToken& rToken, svl::SharedStringPool& rSPool, formula::ExternalReferenceHelper* pExtRef)
1139{
1140 bool bError = FormulaTokenArray::AddFormulaToken(rToken, rSPool, pExtRef);
1141 if ( bError )
1142 {
1143 bError = false;
1144 const OpCode eOpCode = static_cast<OpCode>(rToken.OpCode); // assuming equal values for the moment
1145
1146 const uno::TypeClass eClass = rToken.Data.getValueTypeClass();
1147 switch ( eClass )
1148 {
1149 case uno::TypeClass_STRUCT:
1150 {
1151 uno::Type aType = rToken.Data.getValueType();
1152 if ( aType.equals( cppu::UnoType<sheet::SingleReference>::get() ) )
1153 {
1154 ScSingleRefData aSingleRef;
1155 sheet::SingleReference aApiRef;
1156 rToken.Data >>= aApiRef;
1157 lcl_SingleRefToCalc( aSingleRef, aApiRef );
1158 if ( eOpCode == ocPush )
1159 AddSingleReference( aSingleRef );
1160 else if ( eOpCode == ocColRowName )
1161 AddColRowName( aSingleRef );
1162 else
1163 bError = true;
1164 }
1165 else if ( aType.equals( cppu::UnoType<sheet::ComplexReference>::get() ) )
1166 {
1167 ScComplexRefData aComplRef;
1168 sheet::ComplexReference aApiRef;
1169 rToken.Data >>= aApiRef;
1170 lcl_SingleRefToCalc( aComplRef.Ref1, aApiRef.Reference1 );
1171 lcl_SingleRefToCalc( aComplRef.Ref2, aApiRef.Reference2 );
1172
1173 if ( eOpCode == ocPush )
1174 AddDoubleReference( aComplRef );
1175 else
1176 bError = true;
1177 }
1178 else if ( aType.equals( cppu::UnoType<sheet::NameToken>::get() ) )
1179 {
1180 sheet::NameToken aTokenData;
1181 rToken.Data >>= aTokenData;
1182 if ( eOpCode == ocName )
1183 {
1184 SAL_WARN_IF( aTokenData.Sheet < -1 || std::numeric_limits<sal_Int16>::max() < aTokenData.Sheet,
1185 "sc.core",
1186 "ScTokenArray::AddFormulaToken - NameToken.Sheet out of limits: " << aTokenData.Sheet);
1187 sal_Int16 nSheet = static_cast<sal_Int16>(aTokenData.Sheet);
1188 AddRangeName(aTokenData.Index, nSheet);
1189 }
1190 else if (eOpCode == ocDBArea)
1191 AddDBRange(aTokenData.Index);
1192 else if (eOpCode == ocTableRef)
1193 bError = true; /* TODO: implementation */
1194 else
1195 bError = true;
1196 }
1197 else if ( aType.equals( cppu::UnoType<sheet::ExternalReference>::get() ) )
1198 {
1199 sheet::ExternalReference aApiExtRef;
1200 if( (eOpCode == ocPush) && (rToken.Data >>= aApiExtRef) && (0 <= aApiExtRef.Index) && (aApiExtRef.Index <= SAL_MAX_UINT16) )
1201 {
1202 sal_uInt16 nFileId = static_cast< sal_uInt16 >( aApiExtRef.Index );
1203 sheet::SingleReference aApiSRef;
1204 sheet::ComplexReference aApiCRef;
1205 OUString aName;
1206 if( aApiExtRef.Reference >>= aApiSRef )
1207 {
1208 // try to resolve cache index to sheet name
1209 size_t nCacheId = static_cast< size_t >( aApiSRef.Sheet );
1210 OUString aTabName = pExtRef->getCacheTableName( nFileId, nCacheId );
1211 if( !aTabName.isEmpty() )
1212 {
1213 ScSingleRefData aSingleRef;
1214 // convert column/row settings, set sheet index to absolute
1215 lcl_ExternalRefToCalc( aSingleRef, aApiSRef );
1216 AddExternalSingleReference( nFileId, rSPool.intern( aTabName), aSingleRef );
1217 }
1218 else
1219 bError = true;
1220 }
1221 else if( aApiExtRef.Reference >>= aApiCRef )
1222 {
1223 // try to resolve cache index to sheet name.
1224 size_t nCacheId = static_cast< size_t >( aApiCRef.Reference1.Sheet );
1225 OUString aTabName = pExtRef->getCacheTableName( nFileId, nCacheId );
1226 if( !aTabName.isEmpty() )
1227 {
1228 ScComplexRefData aComplRef;
1229 // convert column/row settings, set sheet index to absolute
1230 lcl_ExternalRefToCalc( aComplRef.Ref1, aApiCRef.Reference1 );
1231 lcl_ExternalRefToCalc( aComplRef.Ref2, aApiCRef.Reference2 );
1232 // NOTE: This assumes that cached sheets are in consecutive order!
1233 aComplRef.Ref2.SetAbsTab(
1234 aComplRef.Ref1.Tab() + static_cast<SCTAB>(aApiCRef.Reference2.Sheet - aApiCRef.Reference1.Sheet));
1235 AddExternalDoubleReference( nFileId, rSPool.intern( aTabName), aComplRef );
1236 }
1237 else
1238 bError = true;
1239 }
1240 else if( aApiExtRef.Reference >>= aName )
1241 {
1242 if( !aName.isEmpty() )
1243 AddExternalName( nFileId, rSPool.intern( aName) );
1244 else
1245 bError = true;
1246 }
1247 else
1248 bError = true;
1249 }
1250 else
1251 bError = true;
1252 }
1253 else
1254 bError = true; // unknown struct
1255 }
1256 break;
1257 case uno::TypeClass_SEQUENCE:
1258 {
1259 if ( eOpCode != ocPush )
1260 bError = true; // not an inline array
1261 else if (!rToken.Data.getValueType().equals( cppu::UnoType<
1262 uno::Sequence< uno::Sequence< uno::Any >>>::get()))
1263 bError = true; // unexpected sequence type
1264 else
1265 {
1267 if (xMat)
1268 AddMatrix( xMat);
1269 else
1270 bError = true;
1271 }
1272 }
1273 break;
1274 default:
1275 bError = true;
1276 }
1277 }
1278 return bError;
1279}
1280
1282{
1283#if HAVE_CPP_CONSTINIT_SORTED_VECTOR
1284 constinit
1285#endif
1286 static const o3tl::sorted_vector<OpCode> aThreadedCalcDenyList({
1287 ocIndirect,
1288 ocMacro,
1289 ocOffset,
1290 ocTableOp,
1291 ocCell,
1292 ocMatch,
1293 ocInfo,
1294 ocStyle,
1296 ocDBCount,
1297 ocDBCount2,
1298 ocDBGet,
1299 ocDBMax,
1300 ocDBMin,
1302 ocDBStdDev,
1304 ocDBSum,
1305 ocDBVar,
1306 ocDBVarP,
1307 ocText,
1308 ocSheet,
1309 ocExternal,
1310 ocDde,
1313 });
1314
1315 // Don't enable threading once we decided to disable it.
1316 if (!mbThreadingEnabled)
1317 return;
1318
1319 static const bool bThreadingProhibited = std::getenv("SC_NO_THREADED_CALCULATION");
1320
1321 if (bThreadingProhibited)
1322 {
1323 mbThreadingEnabled = false;
1324 return;
1325 }
1326
1327 OpCode eOp = r.GetOpCode();
1328
1329 if (aThreadedCalcDenyList.find(eOp) != aThreadedCalcDenyList.end())
1330 {
1331 SAL_INFO("sc.core.formulagroup", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1332 << "(" << int(eOp) << ") disables threaded calculation of formula group");
1333 mbThreadingEnabled = false;
1334 return;
1335 }
1336
1337 if (eOp != ocPush)
1338 return;
1339
1340 switch (r.GetType())
1341 {
1344 case svExternalName:
1345 case svMatrix:
1346 SAL_INFO("sc.core.formulagroup", "opcode ocPush: variable type " << StackVarEnumToString(r.GetType())
1347 << " disables threaded calculation of formula group");
1348 mbThreadingEnabled = false;
1349 return;
1350 default:
1351 break;
1352 }
1353}
1354
1356{
1359
1361 return; // It's already disabled. No more checking needed.
1362
1363 OpCode eOp = r.GetOpCode();
1364
1366 {
1367 if (ScInterpreter::GetGlobalConfig().mbOpenCLSubsetOnly &&
1368 ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes->find(eOp) == ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes->end())
1369 {
1370 SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1371 << "(" << int(eOp) << ") disables vectorisation for formula group");
1373 mbOpenCLEnabled = false;
1374 return;
1375 }
1376
1377 // We support vectorization for the following opcodes.
1378 switch (eOp)
1379 {
1380 case ocAverage:
1381 case ocMin:
1382 case ocMinA:
1383 case ocMax:
1384 case ocMaxA:
1385 case ocSum:
1386 case ocSumIfs:
1387 case ocSumProduct:
1388 case ocCount:
1389 case ocCount2:
1390 case ocVLookup:
1391 case ocSLN:
1392 case ocIRR:
1393 case ocMIRR:
1394 case ocPMT:
1395 case ocRate:
1396 case ocRRI:
1397 case ocPpmt:
1398 case ocFisher:
1399 case ocFisherInv:
1400 case ocGamma:
1401 case ocGammaLn:
1402 case ocNotAvail:
1403 case ocGauss:
1404 case ocGeoMean:
1405 case ocHarMean:
1406 case ocSYD:
1407 case ocCorrel:
1408 case ocNegBinomVert:
1409 case ocPearson:
1410 case ocRSQ:
1411 case ocCos:
1412 case ocCosecant:
1413 case ocCosecantHyp:
1414 case ocISPMT:
1415 case ocPDuration:
1416 case ocSinHyp:
1417 case ocAbs:
1418 case ocPV:
1419 case ocSin:
1420 case ocTan:
1421 case ocTanHyp:
1422 case ocStandard:
1423 case ocWeibull:
1424 case ocMedian:
1425 case ocDDB:
1426 case ocFV:
1427 case ocVBD:
1428 case ocKurt:
1429 case ocNper:
1430 case ocNormDist:
1431 case ocArcCos:
1432 case ocSqrt:
1433 case ocArcCosHyp:
1434 case ocNPV:
1435 case ocStdNormDist:
1436 case ocNormInv:
1437 case ocSNormInv:
1438 case ocPermut:
1439 case ocPermutationA:
1440 case ocPhi:
1441 case ocIpmt:
1442 case ocConfidence:
1443 case ocIntercept:
1444 case ocDB:
1445 case ocLogInv:
1446 case ocArcCot:
1447 case ocCosHyp:
1448 case ocCritBinom:
1449 case ocArcCotHyp:
1450 case ocArcSin:
1451 case ocArcSinHyp:
1452 case ocArcTan:
1453 case ocArcTanHyp:
1454 case ocBitAnd:
1455 case ocForecast:
1456 case ocLogNormDist:
1457 case ocGammaDist:
1458 case ocLn:
1459 case ocRound:
1460 case ocCot:
1461 case ocCotHyp:
1462 case ocFDist:
1463 case ocVar:
1464 case ocChiDist:
1465 case ocPower:
1466 case ocOdd:
1467 case ocChiSqDist:
1468 case ocChiSqInv:
1469 case ocGammaInv:
1470 case ocFloor:
1471 case ocFInv:
1472 case ocFTest:
1473 case ocB:
1474 case ocBetaDist:
1475 case ocExp:
1476 case ocLog10:
1477 case ocExpDist:
1478 case ocAverageIfs:
1479 case ocCountIfs:
1480 case ocCombinA:
1481 case ocEven:
1482 case ocLog:
1483 case ocMod:
1484 case ocTrunc:
1485 case ocSkew:
1486 case ocArcTan2:
1487 case ocBitOr:
1488 case ocBitLshift:
1489 case ocBitRshift:
1490 case ocBitXor:
1491 case ocChiInv:
1492 case ocPoissonDist:
1493 case ocSumSQ:
1494 case ocSkewp:
1495 case ocBinomDist:
1496 case ocVarP:
1497 case ocCeil:
1498 case ocCombin:
1499 case ocDevSq:
1500 case ocStDev:
1501 case ocSlope:
1502 case ocSTEYX:
1503 case ocZTest:
1504 case ocPi:
1505 case ocRandom:
1506 case ocProduct:
1507 case ocHypGeomDist:
1508 case ocSumX2MY2:
1509 case ocSumX2DY2:
1510 case ocBetaInv:
1511 case ocTTest:
1512 case ocTDist:
1513 case ocTInv:
1514 case ocSumXMY2:
1515 case ocStDevP:
1516 case ocCovar:
1517 case ocAnd:
1518 case ocOr:
1519 case ocNot:
1520 case ocXor:
1521 case ocDBMax:
1522 case ocDBMin:
1523 case ocDBProduct:
1524 case ocDBAverage:
1525 case ocDBStdDev:
1526 case ocDBStdDevP:
1527 case ocDBSum:
1528 case ocDBVar:
1529 case ocDBVarP:
1530 case ocAverageIf:
1531 case ocDBCount:
1532 case ocDBCount2:
1533 case ocDeg:
1534 case ocRoundUp:
1535 case ocRoundDown:
1536 case ocInt:
1537 case ocRad:
1538 case ocCountIf:
1539 case ocIsEven:
1540 case ocIsOdd:
1541 case ocFact:
1542 case ocAverageA:
1543 case ocVarA:
1544 case ocVarPA:
1545 case ocStDevA:
1546 case ocStDevPA:
1547 case ocSecant:
1548 case ocSecantHyp:
1549 case ocSumIf:
1550 case ocNegSub:
1551 case ocAveDev:
1552 // Don't change the state.
1553 break;
1554 default:
1555 SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1556 << "(" << int(eOp) << ") disables vectorisation for formula group");
1558 mbOpenCLEnabled = false;
1559 return;
1560 }
1561 }
1562 else if (eOp == ocPush)
1563 {
1564 // This is a stack variable. See if this is a reference.
1565
1566 switch (r.GetType())
1567 {
1568 case svByte:
1569 case svDouble:
1570 case svString:
1571 // Don't change the state.
1572 break;
1573 case svSingleRef:
1574 case svDoubleRef:
1575 // Depends on the reference state.
1577 break;
1578 case svError:
1579 case svEmptyCell:
1580 case svExternal:
1582 case svExternalName:
1584 case svFAP:
1585 case svHybridCell:
1586 case svIndex:
1587 case svJump:
1588 case svJumpMatrix:
1589 case svMatrix:
1590 case svMatrixCell:
1591 case svMissing:
1592 case svRefList:
1593 case svSep:
1594 case svUnknown:
1595 // We don't support vectorization on these.
1596 SAL_INFO("sc.opencl", "opcode ocPush: variable type " << StackVarEnumToString(r.GetType()) << " disables vectorisation for formula group");
1598 mbOpenCLEnabled = false;
1599 return;
1600 default:
1601 ;
1602 }
1603 }
1604 else if (SC_OPCODE_START_BIN_OP <= eOp && eOp < SC_OPCODE_STOP_UN_OP)
1605 {
1606 if (ScInterpreter::GetGlobalConfig().mbOpenCLSubsetOnly &&
1607 ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes->find(eOp) == ScInterpreter::GetGlobalConfig().mpOpenCLSubsetOpCodes->end())
1608 {
1609 SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1610 << "(" << int(eOp) << ") disables vectorisation for formula group");
1612 mbOpenCLEnabled = false;
1613 return;
1614 }
1615 }
1616 else
1617 {
1618 // All the rest, special commands, separators, error codes, ...
1619 switch (eOp)
1620 {
1621 default:
1622 // Default is off, no vectorization.
1623 // Mentioning some specific values below to indicate why.
1624
1625 case ocName:
1626 // Named expression would need "recursive" handling of its
1627 // token array for vector state in
1628 // ScFormulaCell::InterpretFormulaGroup() and below.
1629
1630 case ocDBArea:
1631 // Certainly not a vectorization of the entire area...
1632
1633 case ocTableRef:
1634 // May result in a single cell or range reference, depending on
1635 // context.
1636
1637 case ocColRowName:
1638 // The associated reference is the name cell with which to
1639 // create the implicit intersection.
1640
1641 case ocColRowNameAuto:
1642 // Auto column/row names lead to references computed in
1643 // interpreter.
1644
1645 SAL_INFO("sc.opencl", "opcode " << formula::FormulaCompiler().GetOpCodeMap(sheet::FormulaLanguage::ENGLISH)->getSymbol(eOp)
1646 << "(" << int(eOp) << ") disables vectorisation for formula group");
1648 mbOpenCLEnabled = false;
1649 return;
1650
1651 // Known good, don't change state.
1652 case ocStop:
1653 case ocExternal:
1654 case ocOpen:
1655 case ocClose:
1656 case ocSep:
1657 case ocArrayOpen:
1658 case ocArrayRowSep:
1659 case ocArrayColSep:
1660 case ocArrayClose:
1661 case ocMissing:
1662 case ocBad:
1663 case ocSpaces:
1664 case ocWhitespace:
1665 case ocSkip:
1666 case ocPercentSign:
1667 case ocErrNull:
1668 case ocErrDivZero:
1669 case ocErrValue:
1670 case ocErrRef:
1671 case ocErrName:
1672 case ocErrNum:
1673 case ocErrNA:
1674 break;
1675 case ocIf:
1676 case ocIfError:
1677 case ocIfNA:
1678 case ocChoose:
1679 // Jump commands are now supported.
1680 break;
1681 }
1682 }
1683}
1684
1685bool ScTokenArray::ImplGetReference( ScRange& rRange, const ScAddress& rPos, bool bValidOnly ) const
1686{
1687 bool bIs = false;
1688 if ( pCode && nLen == 1 )
1689 {
1690 const FormulaToken* pToken = pCode[0];
1691 if ( pToken )
1692 {
1693 if ( pToken->GetType() == svSingleRef )
1694 {
1695 const ScSingleRefData& rRef = *static_cast<const ScSingleRefToken*>(pToken)->GetSingleRef();
1696 rRange.aStart = rRange.aEnd = rRef.toAbs(*mxSheetLimits, rPos);
1697 bIs = !bValidOnly || mxSheetLimits->ValidAddress(rRange.aStart);
1698 }
1699 else if ( pToken->GetType() == svDoubleRef )
1700 {
1701 const ScComplexRefData& rCompl = *static_cast<const ScDoubleRefToken*>(pToken)->GetDoubleRef();
1702 const ScSingleRefData& rRef1 = rCompl.Ref1;
1703 const ScSingleRefData& rRef2 = rCompl.Ref2;
1704 rRange.aStart = rRef1.toAbs(*mxSheetLimits, rPos);
1705 rRange.aEnd = rRef2.toAbs(*mxSheetLimits, rPos);
1706 bIs = !bValidOnly || mxSheetLimits->ValidRange(rRange);
1707 }
1708 }
1709 }
1710 return bIs;
1711}
1712
1713namespace {
1714
1715// we want to compare for similar not identical formulae
1716// so we can't use actual row & column indices.
1717size_t HashSingleRef( const ScSingleRefData& rRef )
1718{
1719 size_t nVal = 0;
1720
1721 nVal += size_t(rRef.IsColRel());
1722 nVal += (size_t(rRef.IsRowRel()) << 1);
1723 nVal += (size_t(rRef.IsTabRel()) << 2);
1724
1725 return nVal;
1726}
1727
1728}
1729
1731{
1732 static const OUStringHash aHasher;
1733
1734 size_t nHash = 1;
1735 OpCode eOp;
1737 const formula::FormulaToken* p;
1738 sal_uInt16 n = std::min<sal_uInt16>(nLen, 20);
1739 for (sal_uInt16 i = 0; i < n; ++i)
1740 {
1741 p = pCode[i];
1742 eOp = p->GetOpCode();
1743 if (eOp == ocPush)
1744 {
1745 // This is stack variable. Do additional differentiation.
1746 eType = p->GetType();
1747 switch (eType)
1748 {
1749 case svByte:
1750 {
1751 // Constant value.
1752 sal_uInt8 nVal = p->GetByte();
1753 nHash += static_cast<size_t>(nVal);
1754 }
1755 break;
1756 case svDouble:
1757 {
1758 // Constant value.
1759 double fVal = p->GetDouble();
1760 nHash += std::hash<double>()(fVal);
1761 }
1762 break;
1763 case svString:
1764 {
1765 // Constant string.
1766 OUString aStr = p->GetString().getString();
1767 nHash += aHasher(aStr);
1768 }
1769 break;
1770 case svSingleRef:
1771 {
1772 size_t nVal = HashSingleRef(*p->GetSingleRef());
1773 nHash += nVal;
1774 }
1775 break;
1776 case svDoubleRef:
1777 {
1778 const ScComplexRefData& rRef = *p->GetDoubleRef();
1779 size_t nVal1 = HashSingleRef(rRef.Ref1);
1780 size_t nVal2 = HashSingleRef(rRef.Ref2);
1781 nHash += nVal1;
1782 nHash += nVal2;
1783 }
1784 break;
1785 default:
1786 // Use the opcode value in all the other cases.
1787 nHash += static_cast<size_t>(eOp);
1788 }
1789 }
1790 else
1791 // Use the opcode value in all the other cases.
1792 nHash += static_cast<size_t>(eOp);
1793
1794 nHash = (nHash << 4) - nHash;
1795 }
1796
1797 mnHashValue = nHash;
1798}
1799
1801{
1805}
1806
1808{
1809 switch (meVectorState)
1810 {
1815 return true;
1816 default:
1817 ;
1818 }
1819
1820 return false;
1821}
1822
1824{
1825 FormulaToken** p = pCode.get();
1826 FormulaToken** pEnd = p + static_cast<size_t>(nLen);
1827 for (; p != pEnd; ++p)
1828 {
1829 switch ((*p)->GetType())
1830 {
1831 case svSingleRef:
1833 {
1834 const ScSingleRefData& rRef = *(*p)->GetSingleRef();
1835 if (rRef.IsRowRel())
1836 return false;
1837 }
1838 break;
1839 case svDoubleRef:
1841 {
1842 const ScComplexRefData& rRef = *(*p)->GetDoubleRef();
1843 if (rRef.Ref1.IsRowRel() || rRef.Ref2.IsRowRel())
1844 return false;
1845 }
1846 break;
1847 case svIndex:
1848 return false;
1849 default:
1850 ;
1851 }
1852 }
1853
1854 return true;
1855}
1856
1857bool ScTokenArray::IsReference( ScRange& rRange, const ScAddress& rPos ) const
1858{
1859 return ImplGetReference(rRange, rPos, false);
1860}
1861
1862bool ScTokenArray::IsValidReference( ScRange& rRange, const ScAddress& rPos ) const
1863{
1864 return ImplGetReference(rRange, rPos, true);
1865}
1866
1868 mxSheetLimits(&rDoc.GetSheetLimits()),
1869 mnHashValue(0)
1870{
1872}
1873
1875 mxSheetLimits(&rLimits),
1876 mnHashValue(0)
1877{
1879}
1880
1882{
1883}
1884
1886{
1887 Clear();
1888 Assign( rArr );
1889 mnHashValue = rArr.mnHashValue;
1893 return *this;
1894}
1895
1897{
1898 mxSheetLimits = std::move(rArr.mxSheetLimits);
1899 mnHashValue = rArr.mnHashValue;
1900 meVectorState = rArr.meVectorState;
1901 mbOpenCLEnabled = rArr.mbOpenCLEnabled;
1902 mbThreadingEnabled = rArr.mbThreadingEnabled;
1903 Move(std::move(rArr));
1904 return *this;
1905}
1906
1908{
1909 // We only compare the non-RPN array
1910 if ( pArr2->nLen != nLen )
1911 return false;
1912
1913 FormulaToken** ppToken1 = GetArray();
1914 FormulaToken** ppToken2 = pArr2->GetArray();
1915 for (sal_uInt16 i=0; i<nLen; i++)
1916 {
1917 if ( ppToken1[i] != ppToken2[i] &&
1918 !(*ppToken1[i] == *ppToken2[i]) )
1919 return false; // Difference
1920 }
1921 return true; // All entries are the same
1922}
1923
1925{
1926 mnHashValue = 0;
1928 FormulaTokenArray::Clear();
1929}
1930
1931std::unique_ptr<ScTokenArray> ScTokenArray::Clone() const
1932{
1933 std::unique_ptr<ScTokenArray> p(new ScTokenArray(*mxSheetLimits));
1934 p->nLen = nLen;
1935 p->nRPN = nRPN;
1936 p->nMode = nMode;
1937 p->nError = nError;
1938 p->bHyperLink = bHyperLink;
1939 p->mnHashValue = mnHashValue;
1940 p->meVectorState = meVectorState;
1941 p->mbOpenCLEnabled = mbOpenCLEnabled;
1942 p->mbThreadingEnabled = mbThreadingEnabled;
1943 p->mbFromRangeName = mbFromRangeName;
1944 p->mbShareable = mbShareable;
1945
1946 FormulaToken** pp;
1947 if( nLen )
1948 {
1949 p->pCode.reset(new FormulaToken*[ nLen ]);
1950 pp = p->pCode.get();
1951 memcpy( pp, pCode.get(), nLen * sizeof( formula::FormulaToken* ) );
1952 for( sal_uInt16 i = 0; i < nLen; i++, pp++ )
1953 {
1954 *pp = (*pp)->Clone();
1955 (*pp)->IncRef();
1956 }
1957 }
1958 if( nRPN )
1959 {
1960 pp = p->pRPN = new FormulaToken*[ nRPN ];
1961 memcpy( pp, pRPN, nRPN * sizeof( formula::FormulaToken* ) );
1962 for( sal_uInt16 i = 0; i < nRPN; i++, pp++ )
1963 {
1964 FormulaToken* t = *pp;
1965 if( t->GetRef() > 1 )
1966 {
1967 FormulaToken** p2 = pCode.get();
1968 sal_uInt16 nIdx = 0xFFFF;
1969 for( sal_uInt16 j = 0; j < nLen; j++, p2++ )
1970 {
1971 if( *p2 == t )
1972 {
1973 nIdx = j; break;
1974 }
1975 }
1976 if( nIdx == 0xFFFF )
1977 *pp = t->Clone();
1978 else
1979 *pp = p->pCode[ nIdx ];
1980 }
1981 else
1982 *pp = t->Clone();
1983 (*pp)->IncRef();
1984 }
1985 }
1986 return p;
1987}
1988
1990{
1992 aNew.nLen = nLen;
1993 aNew.nRPN = nRPN;
1994 aNew.nMode = nMode;
1995 aNew.nError = nError;
1996 aNew.bHyperLink = bHyperLink;
1997 aNew.mnHashValue = mnHashValue;
2002 aNew.mbShareable = mbShareable;
2003
2004 FormulaToken** pp;
2005 if( nLen )
2006 {
2007 aNew.pCode.reset(new FormulaToken*[ nLen ]);
2008 pp = aNew.pCode.get();
2009 memcpy( pp, pCode.get(), nLen * sizeof( formula::FormulaToken* ) );
2010 for( sal_uInt16 i = 0; i < nLen; i++, pp++ )
2011 {
2012 *pp = (*pp)->Clone();
2013 (*pp)->IncRef();
2014 }
2015 }
2016 if( nRPN )
2017 {
2018 pp = aNew.pRPN = new FormulaToken*[ nRPN ];
2019 memcpy( pp, pRPN, nRPN * sizeof( formula::FormulaToken* ) );
2020 for( sal_uInt16 i = 0; i < nRPN; i++, pp++ )
2021 {
2022 FormulaToken* t = *pp;
2023 if( t->GetRef() > 1 )
2024 {
2025 FormulaToken** p2 = pCode.get();
2026 sal_uInt16 nIdx = 0xFFFF;
2027 for( sal_uInt16 j = 0; j < nLen; j++, p2++ )
2028 {
2029 if( *p2 == t )
2030 {
2031 nIdx = j; break;
2032 }
2033 }
2034 if( nIdx == 0xFFFF )
2035 *pp = t->Clone();
2036 else
2037 *pp = aNew.pCode[ nIdx ];
2038 }
2039 else
2040 *pp = t->Clone();
2041 (*pp)->IncRef();
2042 }
2043 }
2044 return aNew;
2045}
2046
2048{
2049 return Add( r.CreateToken(*mxSheetLimits) );
2050}
2051
2052// Utility function to ensure that there is strict alternation of values and
2053// separators.
2054static bool
2055checkArraySep( bool & bPrevWasSep, bool bNewVal )
2056{
2057 bool bResult = (bPrevWasSep == bNewVal);
2058 bPrevWasSep = bNewVal;
2059 return bResult;
2060}
2061
2063{
2064 int nCol = -1, nRow = 0;
2065 int i, nPrevRowSep = -1, nStart = 0;
2066 bool bPrevWasSep = false; // top of stack is ocArrayClose
2067 FormulaToken* t;
2068 bool bNumeric = false; // numeric value encountered in current element
2069
2070 // (1) Iterate from the end to the start to find matrix dims
2071 // and do basic validation.
2072 for ( i = nLen ; i-- > nStart ; )
2073 {
2074 t = pCode[i];
2075 switch ( t->GetOpCode() )
2076 {
2077 case ocPush :
2078 if( checkArraySep( bPrevWasSep, false ) )
2079 {
2080 return nullptr;
2081 }
2082
2083 // no references or nested arrays
2084 if ( t->GetType() != svDouble && t->GetType() != svString )
2085 {
2086 return nullptr;
2087 }
2088 bNumeric = (t->GetType() == svDouble);
2089 break;
2090
2091 case ocMissing :
2092 case ocTrue :
2093 case ocFalse :
2094 if( checkArraySep( bPrevWasSep, false ) )
2095 {
2096 return nullptr;
2097 }
2098 bNumeric = false;
2099 break;
2100
2101 case ocArrayColSep :
2102 case ocSep :
2103 if( checkArraySep( bPrevWasSep, true ) )
2104 {
2105 return nullptr;
2106 }
2107 bNumeric = false;
2108 break;
2109
2110 case ocArrayClose :
2111 // not possible with the , but check just in case
2112 // something changes in the future
2113 if( i != (nLen-1))
2114 {
2115 return nullptr;
2116 }
2117
2118 if( checkArraySep( bPrevWasSep, true ) )
2119 {
2120 return nullptr;
2121 }
2122
2123 nPrevRowSep = i;
2124 bNumeric = false;
2125 break;
2126
2127 case ocArrayOpen :
2128 nStart = i; // stop iteration
2129 [[fallthrough]]; // to ArrayRowSep
2130
2131 case ocArrayRowSep :
2132 if( checkArraySep( bPrevWasSep, true ) )
2133 {
2134 return nullptr;
2135 }
2136
2137 if( nPrevRowSep < 0 || // missing ocArrayClose
2138 ((nPrevRowSep - i) % 2) == 1) // no complex elements
2139 {
2140 return nullptr;
2141 }
2142
2143 if( nCol < 0 )
2144 {
2145 nCol = (nPrevRowSep - i) / 2;
2146 }
2147 else if( (nPrevRowSep - i)/2 != nCol) // irregular array
2148 {
2149 return nullptr;
2150 }
2151
2152 nPrevRowSep = i;
2153 nRow++;
2154 bNumeric = false;
2155 break;
2156
2157 case ocNegSub :
2158 case ocAdd :
2159 // negation or unary plus must precede numeric value
2160 if( !bNumeric )
2161 {
2162 return nullptr;
2163 }
2164 --nPrevRowSep; // shorten this row by 1
2165 bNumeric = false; // one level only, no --42
2166 break;
2167
2168 case ocSpaces :
2169 case ocWhitespace :
2170 // ignore spaces
2171 --nPrevRowSep; // shorten this row by 1
2172 break;
2173
2174 default :
2175 // no functions or operators
2176 return nullptr;
2177 }
2178 }
2179 if( nCol <= 0 || nRow <= 0 )
2180 return nullptr;
2181
2182 int nSign = 1;
2183 ScMatrix* pArray = new ScMatrix(nCol, nRow, 0.0);
2184 for ( i = nStart, nCol = 0, nRow = 0 ; i < nLen ; i++ )
2185 {
2186 t = pCode[i];
2187
2188 switch ( t->GetOpCode() )
2189 {
2190 case ocPush :
2191 if ( t->GetType() == svDouble )
2192 {
2193 pArray->PutDouble( t->GetDouble() * nSign, nCol, nRow );
2194 nSign = 1;
2195 }
2196 else if ( t->GetType() == svString )
2197 {
2198 pArray->PutString(t->GetString(), nCol, nRow);
2199 }
2200 break;
2201
2202 case ocMissing :
2203 pArray->PutEmpty( nCol, nRow );
2204 break;
2205
2206 case ocTrue :
2207 pArray->PutBoolean( true, nCol, nRow );
2208 break;
2209
2210 case ocFalse :
2211 pArray->PutBoolean( false, nCol, nRow );
2212 break;
2213
2214 case ocArrayColSep :
2215 case ocSep :
2216 nCol++;
2217 break;
2218
2219 case ocArrayRowSep :
2220 nRow++; nCol = 0;
2221 break;
2222
2223 case ocNegSub :
2224 nSign = -nSign;
2225 break;
2226
2227 default :
2228 break;
2229 }
2230 pCode[i] = nullptr;
2231 t->DecRef();
2232 }
2233 nLen = sal_uInt16( nStart );
2234 return AddMatrix( pArray );
2235}
2236
2238{
2239 if (!pCode || !nLen)
2240 return;
2241 sal_uInt16 nIdx = nLen;
2242
2243 // The actual types are checked in extendRangeReference().
2244 FormulaToken *p3 = PeekPrev(nIdx); // ref
2245 if (!p3)
2246 return;
2247 FormulaToken *p2 = PeekPrev(nIdx); // ocRange
2248 if (!p2 || p2->GetOpCode() != ocRange)
2249 return;
2250 FormulaToken *p1 = PeekPrev(nIdx); // ref
2251 if (!p1)
2252 return;
2253 FormulaTokenRef p = extendRangeReference( *mxSheetLimits, *p1, *p3, rPos, true);
2254 if (p)
2255 {
2256 p->IncRef();
2257 p1->DecRef();
2258 p2->DecRef();
2259 p3->DecRef();
2260 nLen -= 2;
2261 pCode[ nLen-1 ] = p.get();
2262 }
2263}
2264
2266{
2267 ScRawToken t;
2268 t.SetOpCode( e );
2269 return AddRawToken( t );
2270}
2271
2273{
2274 return Add( new ScSingleRefToken( *mxSheetLimits, rRef ) );
2275}
2276
2278{
2279 return Add( new ScSingleRefToken(*mxSheetLimits, rRef, ocMatRef ) );
2280}
2281
2283{
2284 return Add( new ScDoubleRefToken(*mxSheetLimits, rRef ) );
2285}
2286
2288{
2289 return Add( new ScMatrixToken( p ) );
2290}
2291
2292void ScTokenArray::AddRangeName( sal_uInt16 n, sal_Int16 nSheet )
2293{
2294 Add( new FormulaIndexToken( ocName, n, nSheet));
2295}
2296
2298{
2299 return Add( new FormulaIndexToken( ocDBArea, n));
2300}
2301
2303{
2304 return Add( new ScExternalNameToken(nFileId, rName) );
2305}
2306
2307void ScTokenArray::AddExternalSingleReference( sal_uInt16 nFileId, const svl::SharedString& rTabName,
2308 const ScSingleRefData& rRef )
2309{
2310 Add( new ScExternalSingleRefToken(nFileId, rTabName, rRef) );
2311}
2312
2314 const ScComplexRefData& rRef )
2315{
2316 return Add( new ScExternalDoubleRefToken(nFileId, rTabName, rRef) );
2317}
2318
2320{
2321 return Add( new ScSingleRefToken(*mxSheetLimits, rRef, ocColRowName ) );
2322}
2323
2324void ScTokenArray::AssignXMLString( const OUString &rText, const OUString &rFormulaNmsp )
2325{
2326 sal_uInt16 nTokens = 1;
2327 FormulaToken *aTokens[2];
2328
2329 aTokens[0] = new FormulaStringOpToken( ocStringXML, svl::SharedString( rText) ); // string not interned
2330 if( !rFormulaNmsp.isEmpty() )
2331 aTokens[ nTokens++ ] = new FormulaStringOpToken( ocStringXML,
2332 svl::SharedString( rFormulaNmsp) ); // string not interned
2333
2334 Assign( nTokens, aTokens );
2335}
2336
2338 const ScAddress& rPos, ScDirection eDir )
2339{
2340 SCCOL nCol = 0;
2341 SCROW nRow = 0;
2342 switch ( eDir )
2343 {
2344 case DIR_BOTTOM :
2345 if ( rPos.Row() >= mxSheetLimits->mnMaxRow )
2346 return false;
2347 nExtend = rPos.Row();
2348 nRow = nExtend + 1;
2349 break;
2350 case DIR_RIGHT :
2351 if ( rPos.Col() >= mxSheetLimits->mnMaxCol )
2352 return false;
2353 nExtend = rPos.Col();
2354 nCol = static_cast<SCCOL>(nExtend) + 1;
2355 break;
2356 case DIR_TOP :
2357 if ( rPos.Row() <= 0 )
2358 return false;
2359 nExtend = rPos.Row();
2360 nRow = nExtend - 1;
2361 break;
2362 case DIR_LEFT :
2363 if ( rPos.Col() <= 0 )
2364 return false;
2365 nExtend = rPos.Col();
2366 nCol = static_cast<SCCOL>(nExtend) - 1;
2367 break;
2368 default:
2369 OSL_FAIL( "unknown Direction" );
2370 return false;
2371 }
2372 if ( pRPN && nRPN )
2373 {
2374 FormulaToken* t = pRPN[nRPN-1];
2375 if ( t->GetType() == svByte )
2376 {
2377 sal_uInt8 nParamCount = t->GetByte();
2378 if ( nParamCount && nRPN > nParamCount )
2379 {
2380 bool bRet = false;
2381 sal_uInt16 nParam = nRPN - nParamCount - 1;
2382 for ( ; nParam < nRPN-1; nParam++ )
2383 {
2384 FormulaToken* p = pRPN[nParam];
2385 switch ( p->GetType() )
2386 {
2387 case svSingleRef :
2388 {
2389 ScSingleRefData& rRef = *p->GetSingleRef();
2390 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rPos);
2391 switch ( eDir )
2392 {
2393 case DIR_BOTTOM :
2394 if (aAbs.Row() == nRow && aAbs.Row() > nExtend)
2395 {
2396 nExtend = aAbs.Row();
2397 bRet = true;
2398 }
2399 break;
2400 case DIR_RIGHT :
2401 if (aAbs.Col() == nCol && static_cast<SCCOLROW>(aAbs.Col()) > nExtend)
2402 {
2403 nExtend = aAbs.Col();
2404 bRet = true;
2405 }
2406 break;
2407 case DIR_TOP :
2408 if (aAbs.Row() == nRow && aAbs.Row() < nExtend)
2409 {
2410 nExtend = aAbs.Row();
2411 bRet = true;
2412 }
2413 break;
2414 case DIR_LEFT :
2415 if (aAbs.Col() == nCol && static_cast<SCCOLROW>(aAbs.Col()) < nExtend)
2416 {
2417 nExtend = aAbs.Col();
2418 bRet = true;
2419 }
2420 break;
2421 }
2422 }
2423 break;
2424 case svDoubleRef :
2425 {
2426 ScComplexRefData& rRef = *p->GetDoubleRef();
2427 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rPos);
2428 switch ( eDir )
2429 {
2430 case DIR_BOTTOM :
2431 if (aAbs.aStart.Row() == nRow && aAbs.aEnd.Row() > nExtend)
2432 {
2433 nExtend = aAbs.aEnd.Row();
2434 bRet = true;
2435 }
2436 break;
2437 case DIR_RIGHT :
2438 if (aAbs.aStart.Col() == nCol && static_cast<SCCOLROW>(aAbs.aEnd.Col()) > nExtend)
2439 {
2440 nExtend = aAbs.aEnd.Col();
2441 bRet = true;
2442 }
2443 break;
2444 case DIR_TOP :
2445 if (aAbs.aEnd.Row() == nRow && aAbs.aStart.Row() < nExtend)
2446 {
2447 nExtend = aAbs.aStart.Row();
2448 bRet = true;
2449 }
2450 break;
2451 case DIR_LEFT :
2452 if (aAbs.aEnd.Col() == nCol && static_cast<SCCOLROW>(aAbs.aStart.Col()) < nExtend)
2453 {
2454 nExtend = aAbs.aStart.Col();
2455 bRet = true;
2456 }
2457 break;
2458 }
2459 }
2460 break;
2461 default:
2462 {
2463 // added to avoid warnings
2464 }
2465 } // switch
2466 } // for
2467 return bRet;
2468 }
2469 }
2470 }
2471 return false;
2472}
2473
2474namespace {
2475
2476void GetExternalTableData(const ScDocument* pOldDoc, const ScDocument* pNewDoc, const SCTAB nTab, OUString& rTabName, sal_uInt16& rFileId)
2477{
2478 const OUString& aFileName = pOldDoc->GetFileURL();
2479 rFileId = pNewDoc->GetExternalRefManager()->getExternalFileId(aFileName);
2480 rTabName = pOldDoc->GetCopyTabName(nTab);
2481 if (rTabName.isEmpty())
2482 pOldDoc->GetName(nTab, rTabName);
2483}
2484
2485bool IsInCopyRange( const ScRange& rRange, const ScDocument* pClipDoc )
2486{
2487 ScClipParam& rClipParam = const_cast<ScDocument*>(pClipDoc)->GetClipParam();
2488 return rClipParam.maRanges.Contains(rRange);
2489}
2490
2491bool SkipReference(formula::FormulaToken* pToken, const ScAddress& rPos, const ScDocument& rOldDoc, bool bRangeName, bool bCheckCopyArea)
2492{
2493 ScRange aRange;
2494
2495 if (!ScRefTokenHelper::getRangeFromToken(&rOldDoc, aRange, pToken, rPos))
2496 return true;
2497
2498 if (bRangeName && aRange.aStart.Tab() == rPos.Tab())
2499 {
2500 switch (pToken->GetType())
2501 {
2502 case svDoubleRef:
2503 {
2504 ScSingleRefData& rRef = *pToken->GetSingleRef2();
2505 if (rRef.IsColRel() || rRef.IsRowRel())
2506 return true;
2507 }
2508 [[fallthrough]];
2509 case svSingleRef:
2510 {
2511 ScSingleRefData& rRef = *pToken->GetSingleRef();
2512 if (rRef.IsColRel() || rRef.IsRowRel())
2513 return true;
2514 }
2515 break;
2516 default:
2517 break;
2518 }
2519 }
2520
2521 if (bCheckCopyArea && IsInCopyRange(aRange, &rOldDoc))
2522 return true;
2523
2524 return false;
2525}
2526
2527void AdjustSingleRefData( ScSingleRefData& rRef, const ScAddress& rOldPos, const ScAddress& rNewPos)
2528{
2529 SCCOL nCols = rNewPos.Col() - rOldPos.Col();
2530 SCROW nRows = rNewPos.Row() - rOldPos.Row();
2531 SCTAB nTabs = rNewPos.Tab() - rOldPos.Tab();
2532
2533 if (!rRef.IsColRel())
2534 rRef.IncCol(nCols);
2535
2536 if (!rRef.IsRowRel())
2537 rRef.IncRow(nRows);
2538
2539 if (!rRef.IsTabRel())
2540 rRef.IncTab(nTabs);
2541}
2542
2543}
2544
2545void ScTokenArray::ReadjustAbsolute3DReferences( const ScDocument& rOldDoc, ScDocument& rNewDoc, const ScAddress& rPos, bool bRangeName )
2546{
2547 for ( sal_uInt16 j=0; j<nLen; ++j )
2548 {
2549 switch ( pCode[j]->GetType() )
2550 {
2551 case svDoubleRef :
2552 {
2553 if (SkipReference(pCode[j], rPos, rOldDoc, bRangeName, true))
2554 continue;
2555
2556 ScComplexRefData& rRef = *pCode[j]->GetDoubleRef();
2557 ScSingleRefData& rRef2 = rRef.Ref2;
2558 ScSingleRefData& rRef1 = rRef.Ref1;
2559
2560 if ( (rRef2.IsFlag3D() && !rRef2.IsTabRel()) || (rRef1.IsFlag3D() && !rRef1.IsTabRel()) )
2561 {
2562 OUString aTabName;
2563 sal_uInt16 nFileId;
2564 GetExternalTableData(&rOldDoc, &rNewDoc, rRef1.Tab(), aTabName, nFileId);
2565 ReplaceToken( j, new ScExternalDoubleRefToken( nFileId,
2566 rNewDoc.GetSharedStringPool().intern( aTabName), rRef), CODE_AND_RPN);
2567 // ATTENTION: rRef can't be used after this point
2568 }
2569 }
2570 break;
2571 case svSingleRef :
2572 {
2573 if (SkipReference(pCode[j], rPos, rOldDoc, bRangeName, true))
2574 continue;
2575
2576 ScSingleRefData& rRef = *pCode[j]->GetSingleRef();
2577
2578 if ( rRef.IsFlag3D() && !rRef.IsTabRel() )
2579 {
2580 OUString aTabName;
2581 sal_uInt16 nFileId;
2582 GetExternalTableData(&rOldDoc, &rNewDoc, rRef.Tab(), aTabName, nFileId);
2583 ReplaceToken( j, new ScExternalSingleRefToken( nFileId,
2584 rNewDoc.GetSharedStringPool().intern( aTabName), rRef), CODE_AND_RPN);
2585 // ATTENTION: rRef can't be used after this point
2586 }
2587 }
2588 break;
2589 default:
2590 {
2591 // added to avoid warnings
2592 }
2593 }
2594 }
2595}
2596
2597void ScTokenArray::AdjustAbsoluteRefs( const ScDocument& rOldDoc, const ScAddress& rOldPos, const ScAddress& rNewPos,
2598 bool bCheckCopyRange)
2599{
2600 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN, true);
2601 for (size_t j=0; j<2; ++j)
2602 {
2603 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
2604 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
2605 for (; pp != pEnd; ++pp)
2606 {
2607 FormulaToken* p = aPtrs.getHandledToken(j,pp);
2608 if (!p)
2609 continue;
2610
2611 switch ( p->GetType() )
2612 {
2613 case svDoubleRef :
2614 {
2615 if (!SkipReference(p, rOldPos, rOldDoc, false, bCheckCopyRange))
2616 continue;
2617
2618 ScComplexRefData& rRef = *p->GetDoubleRef();
2619 ScSingleRefData& rRef2 = rRef.Ref2;
2620 ScSingleRefData& rRef1 = rRef.Ref1;
2621
2622 AdjustSingleRefData( rRef1, rOldPos, rNewPos );
2623 AdjustSingleRefData( rRef2, rOldPos, rNewPos );
2624 }
2625 break;
2626 case svSingleRef :
2627 {
2628 if (!SkipReference(p, rOldPos, rOldDoc, false, bCheckCopyRange))
2629 continue;
2630
2631 ScSingleRefData& rRef = *p->GetSingleRef();
2632
2633 AdjustSingleRefData( rRef, rOldPos, rNewPos );
2634 }
2635 break;
2636 default:
2637 {
2638 // added to avoid warnings
2639 }
2640 }
2641 }
2642 }
2643}
2644
2646{
2647 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN, false);
2648 for (size_t j=0; j<2; ++j)
2649 {
2650 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
2651 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
2652 for (; pp != pEnd; ++pp)
2653 {
2654 FormulaToken* p = aPtrs.getHandledToken(j,pp);
2655 if (!p)
2656 continue;
2657
2658 switch ( p->GetType() )
2659 {
2660 case svDoubleRef :
2661 {
2662 ScComplexRefData& rRef = *p->GetDoubleRef();
2663 ScSingleRefData& rRef2 = rRef.Ref2;
2664 ScSingleRefData& rRef1 = rRef.Ref1;
2665
2666 if (!rRef1.IsTabRel() && rRef1.Tab() == nOldTab)
2667 rRef1.SetAbsTab( nNewTab);
2668 if (!rRef2.IsTabRel() && rRef2.Tab() == nOldTab)
2669 rRef2.SetAbsTab( nNewTab);
2670 if (!rRef1.IsTabRel() && !rRef2.IsTabRel() && rRef1.Tab() > rRef2.Tab())
2671 {
2672 SCTAB nTab = rRef1.Tab();
2673 rRef1.SetAbsTab( rRef2.Tab());
2674 rRef2.SetAbsTab( nTab);
2675 }
2676 }
2677 break;
2678 case svSingleRef :
2679 {
2680 ScSingleRefData& rRef = *p->GetSingleRef();
2681
2682 if (!rRef.IsTabRel() && rRef.Tab() == nOldTab)
2683 rRef.SetAbsTab( nNewTab);
2684 }
2685 break;
2686 default:
2687 ;
2688 }
2689 }
2690 }
2691}
2692
2693bool ScTokenArray::ReferencesSheet( SCTAB nTab, SCTAB nPosTab ) const
2694{
2695 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN, false);
2696 for (size_t j=0; j<2; ++j)
2697 {
2698 FormulaToken* const * pp = aPtrs.maPointerRange[j].mpStart;
2699 FormulaToken* const * const pEnd = aPtrs.maPointerRange[j].mpStop;
2700 for (; pp != pEnd; ++pp)
2701 {
2702 const FormulaToken* p = aPtrs.getHandledToken(j,pp);
2703 if (!p)
2704 continue;
2705
2706 switch ( p->GetType() )
2707 {
2708 case svDoubleRef :
2709 {
2710 const ScComplexRefData& rRef = *p->GetDoubleRef();
2711 const ScSingleRefData& rRef2 = rRef.Ref2;
2712 const ScSingleRefData& rRef1 = rRef.Ref1;
2713
2714 SCTAB nTab1 = (rRef1.IsTabRel() ? rRef1.Tab() + nPosTab : rRef1.Tab());
2715 SCTAB nTab2 = (rRef2.IsTabRel() ? rRef2.Tab() + nPosTab : rRef2.Tab());
2716 if (nTab1 <= nTab && nTab <= nTab2)
2717 return true;
2718 }
2719 break;
2720 case svSingleRef :
2721 {
2722 const ScSingleRefData& rRef = *p->GetSingleRef();
2723 if (rRef.IsTabRel())
2724 {
2725 if (rRef.Tab() + nPosTab == nTab)
2726 return true;
2727 }
2728 else
2729 {
2730 if (rRef.Tab() == nTab)
2731 return true;
2732 }
2733 }
2734 break;
2735 default:
2736 ;
2737 }
2738 }
2739 }
2740 return false;
2741}
2742
2743namespace {
2744
2745ScRange getSelectedRange( const sc::RefUpdateContext& rCxt )
2746{
2747 ScRange aSelectedRange(ScAddress::INITIALIZE_INVALID);
2748 if (rCxt.mnColDelta < 0)
2749 {
2750 // Delete and shift to left.
2751 aSelectedRange.aStart = ScAddress(rCxt.maRange.aStart.Col()+rCxt.mnColDelta, rCxt.maRange.aStart.Row(), rCxt.maRange.aStart.Tab());
2752 aSelectedRange.aEnd = ScAddress(rCxt.maRange.aStart.Col()-1, rCxt.maRange.aEnd.Row(), rCxt.maRange.aEnd.Tab());
2753 }
2754 else if (rCxt.mnRowDelta < 0)
2755 {
2756 // Delete and shift up.
2757 aSelectedRange.aStart = ScAddress(rCxt.maRange.aStart.Col(), rCxt.maRange.aStart.Row()+rCxt.mnRowDelta, rCxt.maRange.aStart.Tab());
2758 aSelectedRange.aEnd = ScAddress(rCxt.maRange.aEnd.Col(), rCxt.maRange.aStart.Row()-1, rCxt.maRange.aEnd.Tab());
2759 }
2760 else if (rCxt.mnTabDelta < 0)
2761 {
2762 // Deleting sheets.
2763 // TODO : Figure out what to do here.
2764 }
2765 else if (rCxt.mnColDelta > 0)
2766 {
2767 // Insert and shift to the right.
2768 aSelectedRange.aStart = rCxt.maRange.aStart;
2769 aSelectedRange.aEnd = ScAddress(rCxt.maRange.aStart.Col()+rCxt.mnColDelta-1, rCxt.maRange.aEnd.Row(), rCxt.maRange.aEnd.Tab());
2770 }
2771 else if (rCxt.mnRowDelta > 0)
2772 {
2773 // Insert and shift down.
2774 aSelectedRange.aStart = rCxt.maRange.aStart;
2775 aSelectedRange.aEnd = ScAddress(rCxt.maRange.aEnd.Col(), rCxt.maRange.aStart.Row()+rCxt.mnRowDelta-1, rCxt.maRange.aEnd.Tab());
2776 }
2777 else if (rCxt.mnTabDelta > 0)
2778 {
2779 // Inserting sheets.
2780 // TODO : Figure out what to do here.
2781 }
2782
2783 return aSelectedRange;
2784}
2785
2786void setRefDeleted( ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt )
2787{
2788 if (rCxt.mnColDelta < 0)
2789 rRef.SetColDeleted(true);
2790 else if (rCxt.mnRowDelta < 0)
2791 rRef.SetRowDeleted(true);
2792 else if (rCxt.mnTabDelta < 0)
2793 rRef.SetTabDeleted(true);
2794}
2795
2796void restoreDeletedRef( ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt )
2797{
2798 if (rCxt.mnColDelta)
2799 {
2800 if (rRef.IsColDeleted())
2801 rRef.SetColDeleted(false);
2802 }
2803 else if (rCxt.mnRowDelta)
2804 {
2805 if (rRef.IsRowDeleted())
2806 rRef.SetRowDeleted(false);
2807 }
2808 else if (rCxt.mnTabDelta)
2809 {
2810 if (rRef.IsTabDeleted())
2811 rRef.SetTabDeleted(false);
2812 }
2813}
2814
2815void setRefDeleted( ScComplexRefData& rRef, const sc::RefUpdateContext& rCxt )
2816{
2817 if (rCxt.mnColDelta < 0)
2818 {
2819 rRef.Ref1.SetColDeleted(true);
2820 rRef.Ref2.SetColDeleted(true);
2821 }
2822 else if (rCxt.mnRowDelta < 0)
2823 {
2824 rRef.Ref1.SetRowDeleted(true);
2825 rRef.Ref2.SetRowDeleted(true);
2826 }
2827 else if (rCxt.mnTabDelta < 0)
2828 {
2829 rRef.Ref1.SetTabDeleted(true);
2830 rRef.Ref2.SetTabDeleted(true);
2831 }
2832}
2833
2834void restoreDeletedRef( ScComplexRefData& rRef, const sc::RefUpdateContext& rCxt )
2835{
2836 restoreDeletedRef(rRef.Ref1, rCxt);
2837 restoreDeletedRef(rRef.Ref2, rCxt);
2838}
2839
2840enum ShrinkResult
2841{
2842 UNMODIFIED,
2843 SHRUNK,
2844 STICKY
2845};
2846
2847ShrinkResult shrinkRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const ScRange& rDeletedRange,
2848 const ScComplexRefData& rRef )
2849{
2850 if (!rDeletedRange.Intersects(rRefRange))
2851 return UNMODIFIED;
2852
2853 if (rCxt.mnColDelta < 0)
2854 {
2855 if (rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits()))
2856 // Entire rows are not affected, columns are anchored.
2857 return STICKY;
2858
2859 // Shifting left.
2860 if (rRefRange.aStart.Row() < rDeletedRange.aStart.Row() || rDeletedRange.aEnd.Row() < rRefRange.aEnd.Row())
2861 // Deleted range is only partially overlapping in vertical direction. Bail out.
2862 return UNMODIFIED;
2863
2864 if (rDeletedRange.aStart.Col() <= rRefRange.aStart.Col())
2865 {
2866 if (rRefRange.aEnd.Col() <= rDeletedRange.aEnd.Col())
2867 {
2868 // Reference is entirely deleted.
2869 rRefRange.SetInvalid();
2870 }
2871 else
2872 {
2873 // The reference range is truncated on the left.
2874 SCCOL nOffset = rDeletedRange.aStart.Col() - rRefRange.aStart.Col();
2875 SCCOL nDelta = rRefRange.aStart.Col() - rDeletedRange.aEnd.Col() - 1;
2876 rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta+nOffset);
2877 rRefRange.aStart.IncCol(nOffset);
2878 }
2879 }
2880 else if (rDeletedRange.aEnd.Col() < rRefRange.aEnd.Col())
2881 {
2882 if (rRefRange.IsEndColSticky(rCxt.mrDoc))
2883 // Sticky end not affected.
2884 return STICKY;
2885
2886 // Reference is deleted in the middle. Move the last column
2887 // position to the left.
2888 SCCOL nDelta = rDeletedRange.aStart.Col() - rDeletedRange.aEnd.Col() - 1;
2889 rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta);
2890 }
2891 else
2892 {
2893 if (rRefRange.IsEndColSticky(rCxt.mrDoc))
2894 // Sticky end not affected.
2895 return STICKY;
2896
2897 // The reference range is truncated on the right.
2898 SCCOL nDelta = rDeletedRange.aStart.Col() - rRefRange.aEnd.Col() - 1;
2899 rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta);
2900 }
2901 return SHRUNK;
2902 }
2903 else if (rCxt.mnRowDelta < 0)
2904 {
2905 if (rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
2906 // Entire columns are not affected, rows are anchored.
2907 return STICKY;
2908
2909 // Shifting up.
2910
2911 if (rRefRange.aStart.Col() < rDeletedRange.aStart.Col() || rDeletedRange.aEnd.Col() < rRefRange.aEnd.Col())
2912 // Deleted range is only partially overlapping in horizontal direction. Bail out.
2913 return UNMODIFIED;
2914
2915 if (rDeletedRange.aStart.Row() <= rRefRange.aStart.Row())
2916 {
2917 if (rRefRange.aEnd.Row() <= rDeletedRange.aEnd.Row())
2918 {
2919 // Reference is entirely deleted.
2920 rRefRange.SetInvalid();
2921 }
2922 else
2923 {
2924 // The reference range is truncated on the top.
2925 SCROW nOffset = rDeletedRange.aStart.Row() - rRefRange.aStart.Row();
2926 SCROW nDelta = rRefRange.aStart.Row() - rDeletedRange.aEnd.Row() - 1;
2927 rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta+nOffset);
2928 rRefRange.aStart.IncRow(nOffset);
2929 }
2930 }
2931 else if (rDeletedRange.aEnd.Row() < rRefRange.aEnd.Row())
2932 {
2933 if (rRefRange.IsEndRowSticky(rCxt.mrDoc))
2934 // Sticky end not affected.
2935 return STICKY;
2936
2937 // Reference is deleted in the middle. Move the last row
2938 // position upward.
2939 SCROW nDelta = rDeletedRange.aStart.Row() - rDeletedRange.aEnd.Row() - 1;
2940 rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta);
2941 }
2942 else
2943 {
2944 if (rRefRange.IsEndRowSticky(rCxt.mrDoc))
2945 // Sticky end not affected.
2946 return STICKY;
2947
2948 // The reference range is truncated on the bottom.
2949 SCROW nDelta = rDeletedRange.aStart.Row() - rRefRange.aEnd.Row() - 1;
2950 rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta);
2951 }
2952 return SHRUNK;
2953 }
2954
2955 return UNMODIFIED;
2956}
2957
2958bool expandRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const ScRange& rSelectedRange,
2959 const ScComplexRefData& rRef )
2960{
2961 if (!rSelectedRange.Intersects(rRefRange))
2962 return false;
2963
2964 if (rCxt.mnColDelta > 0)
2965 {
2966 if (rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits()))
2967 // Entire rows are not affected, columns are anchored.
2968 return false;
2969
2970 // Insert and shifting right.
2971 if (rRefRange.aStart.Row() < rSelectedRange.aStart.Row() || rSelectedRange.aEnd.Row() < rRefRange.aEnd.Row())
2972 // Selected range is only partially overlapping in vertical direction. Bail out.
2973 return false;
2974
2975 if (rCxt.mrDoc.IsExpandRefs())
2976 {
2977 if (rRefRange.aEnd.Col() - rRefRange.aStart.Col() < 1)
2978 // Reference must be at least two columns wide.
2979 return false;
2980 }
2981 else
2982 {
2983 if (rSelectedRange.aStart.Col() <= rRefRange.aStart.Col())
2984 // Selected range is at the left end and the edge expansion is turned off. No expansion.
2985 return false;
2986 }
2987
2988 if (rRefRange.IsEndColSticky(rCxt.mrDoc))
2989 // Sticky end not affected.
2990 return false;
2991
2992 // Move the last column position to the right.
2993 SCCOL nDelta = rSelectedRange.aEnd.Col() - rSelectedRange.aStart.Col() + 1;
2994 rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta);
2995 return true;
2996 }
2997 else if (rCxt.mnRowDelta > 0)
2998 {
2999 if (rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
3000 // Entire columns are not affected, rows are anchored.
3001 return false;
3002
3003 // Insert and shifting down.
3004 if (rRefRange.aStart.Col() < rSelectedRange.aStart.Col() || rSelectedRange.aEnd.Col() < rRefRange.aEnd.Col())
3005 // Selected range is only partially overlapping in horizontal direction. Bail out.
3006 return false;
3007
3008 if (rCxt.mrDoc.IsExpandRefs())
3009 {
3010 if (rRefRange.aEnd.Row() - rRefRange.aStart.Row() < 1)
3011 // Reference must be at least two rows tall.
3012 return false;
3013 }
3014 else
3015 {
3016 if (rSelectedRange.aStart.Row() <= rRefRange.aStart.Row())
3017 // Selected range is at the top end and the edge expansion is turned off. No expansion.
3018 return false;
3019 }
3020
3021 if (rRefRange.IsEndRowSticky(rCxt.mrDoc))
3022 // Sticky end not affected.
3023 return false;
3024
3025 // Move the last row position down.
3026 SCROW nDelta = rSelectedRange.aEnd.Row() - rSelectedRange.aStart.Row() + 1;
3027 rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta);
3028 return true;
3029 }
3030 return false;
3031}
3032
3037bool expandRangeByEdge( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const ScRange& rSelectedRange,
3038 const ScComplexRefData& rRef )
3039{
3040 if (!rCxt.mrDoc.IsExpandRefs())
3041 // Edge-expansion is turned off.
3042 return false;
3043
3044 if (rSelectedRange.aStart.Tab() > rRefRange.aStart.Tab() || rRefRange.aEnd.Tab() > rSelectedRange.aEnd.Tab())
3045 // Sheet references not within selected range.
3046 return false;
3047
3048 if (rCxt.mnColDelta > 0)
3049 {
3050 if (rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits()))
3051 // Entire rows are not affected, columns are anchored.
3052 return false;
3053
3054 // Insert and shift right.
3055
3056 if (rRefRange.aEnd.Col() - rRefRange.aStart.Col() < 1)
3057 // Reference must be at least two columns wide.
3058 return false;
3059
3060 if (rRefRange.aStart.Row() < rSelectedRange.aStart.Row() || rSelectedRange.aEnd.Row() < rRefRange.aEnd.Row())
3061 // Selected range is only partially overlapping in vertical direction. Bail out.
3062 return false;
3063
3064 if (rSelectedRange.aStart.Col() - rRefRange.aEnd.Col() != 1)
3065 // Selected range is not immediately adjacent. Bail out.
3066 return false;
3067
3068 if (rRefRange.IsEndColSticky(rCxt.mrDoc))
3069 // Sticky end not affected.
3070 return false;
3071
3072 // Move the last column position to the right.
3073 SCCOL nDelta = rSelectedRange.aEnd.Col() - rSelectedRange.aStart.Col() + 1;
3074 rRefRange.IncEndColSticky(rCxt.mrDoc, nDelta);
3075 return true;
3076 }
3077 else if (rCxt.mnRowDelta > 0)
3078 {
3079 if (rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
3080 // Entire columns are not affected, rows are anchored.
3081 return false;
3082
3083 if (rRefRange.aEnd.Row() - rRefRange.aStart.Row() < 1)
3084 // Reference must be at least two rows tall.
3085 return false;
3086
3087 if (rRefRange.aStart.Col() < rSelectedRange.aStart.Col() || rSelectedRange.aEnd.Col() < rRefRange.aEnd.Col())
3088 // Selected range is only partially overlapping in horizontal direction. Bail out.
3089 return false;
3090
3091 if (rSelectedRange.aStart.Row() - rRefRange.aEnd.Row() != 1)
3092 // Selected range is not immediately adjacent. Bail out.
3093 return false;
3094
3095 if (rRefRange.IsEndRowSticky(rCxt.mrDoc))
3096 // Sticky end not affected.
3097 return false;
3098
3099 // Move the last row position down.
3100 SCROW nDelta = rSelectedRange.aEnd.Row() - rSelectedRange.aStart.Row() + 1;
3101 rRefRange.IncEndRowSticky(rCxt.mrDoc, nDelta);
3102 return true;
3103 }
3104
3105 return false;
3106}
3107
3108bool isNameModified( const sc::UpdatedRangeNames& rUpdatedNames, SCTAB nOldTab, const formula::FormulaToken& rToken )
3109{
3110 SCTAB nTab = -1;
3111 if (rToken.GetSheet() >= 0)
3112 nTab = nOldTab;
3113
3114 // Check if this named expression has been modified.
3115 return rUpdatedNames.isNameUpdated(nTab, rToken.GetIndex());
3116}
3117
3118bool isDBDataModified( const ScDocument& rDoc, const formula::FormulaToken& rToken )
3119{
3120 // Check if this DBData has been modified.
3121 const ScDBData* pDBData = rDoc.GetDBCollection()->getNamedDBs().findByIndex( rToken.GetIndex());
3122 if (!pDBData)
3123 return true;
3124
3125 return pDBData->IsModified();
3126}
3127
3128}
3129
3131{
3132 ScRange aSelectedRange = getSelectedRange(rCxt);
3133
3135 ScAddress aNewPos = rOldPos;
3136 bool bCellShifted = rCxt.maRange.Contains(rOldPos);
3137 if (bCellShifted)
3138 {
3140 if (!aNewPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos, rCxt.mrDoc))
3141 {
3142 assert(!"can't move");
3143 }
3144 }
3145
3146 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3147 for (size_t j=0; j<2; ++j)
3148 {
3149 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3150 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3151 for (; pp != pEnd; ++pp)
3152 {
3153 FormulaToken* p = aPtrs.getHandledToken(j,pp);
3154 if (!p)
3155 continue;
3156
3157 switch (p->GetType())
3158 {
3159 case svSingleRef:
3160 {
3161 ScSingleRefData& rRef = *p->GetSingleRef();
3162 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3163
3164 if (rCxt.isDeleted() && aSelectedRange.Contains(aAbs))
3165 {
3166 // This reference is in the deleted region.
3167 setRefDeleted(rRef, rCxt);
3168 aRes.mbValueChanged = true;
3169 break;
3170 }
3171
3172 if (!rCxt.isDeleted() && rRef.IsDeleted())
3173 {
3174 // Check if the token has reference to previously deleted region.
3175 ScAddress aCheckPos = rRef.toAbs(*mxSheetLimits, aNewPos);
3176 if (rCxt.maRange.Contains(aCheckPos))
3177 {
3178 restoreDeletedRef(rRef, rCxt);
3179 aRes.mbValueChanged = true;
3180 break;
3181 }
3182 }
3183
3184 if (rCxt.maRange.Contains(aAbs))
3185 {
3187 if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos, rCxt.mrDoc))
3188 aAbs = aErrorPos;
3189 aRes.mbReferenceModified = true;
3190 }
3191
3192 rRef.SetAddress(*mxSheetLimits, aAbs, aNewPos);
3193 }
3194 break;
3195 case svDoubleRef:
3196 {
3197 ScComplexRefData& rRef = *p->GetDoubleRef();
3198 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3199
3200 if (rCxt.isDeleted())
3201 {
3202 if (aSelectedRange.Contains(aAbs))
3203 {
3204 // This reference is in the deleted region.
3205 setRefDeleted(rRef, rCxt);
3206 aRes.mbValueChanged = true;
3207 break;
3208 }
3209 else if (aSelectedRange.Intersects(aAbs))
3210 {
3211 const ShrinkResult eSR = shrinkRange(rCxt, aAbs, aSelectedRange, rRef);
3212 if (eSR == SHRUNK)
3213 {
3214 // The reference range has been shrunk.
3215 rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3216 aRes.mbValueChanged = true;
3217 aRes.mbReferenceModified = true;
3218 break;
3219 }
3220 else if (eSR == STICKY)
3221 {
3222 // The reference range stays the same but a
3223 // new (empty) cell range is shifted in and
3224 // may change the calculation result.
3225 aRes.mbValueChanged = true;
3226 // Sticky when intersecting the selected
3227 // range means also that the other
3228 // conditions below are not met,
3229 // specifically not the
3230 // if (rCxt.maRange.Contains(aAbs))
3231 // that is able to update the reference,
3232 // but aSelectedRange does not intersect
3233 // with rCxt.maRange so that can't happen
3234 // and we can bail out early without
3235 // updating the reference.
3236 break;
3237 }
3238 }
3239 }
3240
3241 if (!rCxt.isDeleted() && rRef.IsDeleted())
3242 {
3243 // Check if the token has reference to previously deleted region.
3244 ScRange aCheckRange = rRef.toAbs(*mxSheetLimits, aNewPos);
3245 if (aSelectedRange.Contains(aCheckRange))
3246 {
3247 // This reference was previously in the deleted region. Restore it.
3248 restoreDeletedRef(rRef, rCxt);
3249 aRes.mbValueChanged = true;
3250 break;
3251 }
3252 }
3253
3254 if (rCxt.isInserted())
3255 {
3256 if (expandRange(rCxt, aAbs, aSelectedRange, rRef))
3257 {
3258 // The reference range has been expanded.
3259 rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3260 aRes.mbValueChanged = true;
3261 aRes.mbReferenceModified = true;
3262 break;
3263 }
3264
3265 if (expandRangeByEdge(rCxt, aAbs, aSelectedRange, rRef))
3266 {
3267 // The reference range has been expanded on the edge.
3268 rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3269 aRes.mbValueChanged = true;
3270 aRes.mbReferenceModified = true;
3271 break;
3272 }
3273 }
3274
3275 if (rCxt.maRange.Contains(aAbs))
3276 {
3277 // We shift either by column or by row, not both,
3278 // so moving the reference has only to be done in
3279 // the non-sticky case.
3280 if ((rCxt.mnRowDelta && rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
3281 || (rCxt.mnColDelta && rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits())))
3282 {
3283 // In entire col/row, values are shifted within
3284 // the reference, which affects all positional
3285 // results like in MATCH or matrix positions.
3286 aRes.mbValueChanged = true;
3287 }
3288 else
3289 {
3290 ScRange aErrorRange( ScAddress::UNINITIALIZED );
3291 if (!aAbs.MoveSticky(rCxt.mrDoc, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorRange))
3292 aAbs = aErrorRange;
3293 aRes.mbReferenceModified = true;
3294 }
3295 }
3296 else if (rCxt.maRange.Intersects(aAbs))
3297 {
3298 // Part of the referenced range is being shifted. This
3299 // will change the values of the range.
3300 aRes.mbValueChanged = true;
3301 }
3302
3303 rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3304 }
3305 break;
3307 {
3308 // For external reference, just reset the reference with
3309 // respect to the new cell position.
3310 ScSingleRefData& rRef = *p->GetSingleRef();
3311 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3312 rRef.SetAddress(*mxSheetLimits, aAbs, aNewPos);
3313 }
3314 break;
3316 {
3317 // Same as above.
3318 ScComplexRefData& rRef = *p->GetDoubleRef();
3319 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3320 rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
3321 }
3322 break;
3323 default:
3324 ;
3325 }
3326
3327 // For ocTableRef p is the inner token of *pp, so have a separate
3328 // condition here.
3329 if ((*pp)->GetType() == svIndex)
3330 {
3331 switch ((*pp)->GetOpCode())
3332 {
3333 case ocName:
3334 {
3335 SCTAB nOldTab = (*pp)->GetSheet();
3336 if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
3337 aRes.mbNameModified = true;
3338 if (rCxt.mnTabDelta &&
3339 rCxt.maRange.aStart.Tab() <= nOldTab && nOldTab <= rCxt.maRange.aEnd.Tab())
3340 {
3341 aRes.mbNameModified = true;
3342 (*pp)->SetSheet( nOldTab + rCxt.mnTabDelta);
3343 }
3344 }
3345 break;
3346 case ocDBArea:
3347 case ocTableRef:
3348 if (isDBDataModified(rCxt.mrDoc, **pp))
3349 aRes.mbNameModified = true;
3350 break;
3351 default:
3352 ; // nothing
3353 }
3354 }
3355 }
3356 }
3357
3358 return aRes;
3359}
3360
3362 const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos, const ScAddress& rNewPos )
3363{
3365
3366 if (!rCxt.mnColDelta && !rCxt.mnRowDelta && !rCxt.mnTabDelta)
3367 // The cell hasn't moved at all.
3368 return aRes;
3369
3370 // When moving, the range in the context is the destination range. We need
3371 // to use the old range prior to the move for hit analysis.
3372 ScRange aOldRange = rCxt.maRange;
3373 ScRange aErrorMoveRange( ScAddress::UNINITIALIZED );
3374 if (!aOldRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta, aErrorMoveRange, rCxt.mrDoc))
3375 {
3376 assert(!"can't move");
3377 }
3378
3379 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3380 for (size_t j=0; j<2; ++j)
3381 {
3382 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3383 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3384 for (; pp != pEnd; ++pp)
3385 {
3386 FormulaToken* p = aPtrs.getHandledToken(j,pp);
3387 if (!p)
3388 continue;
3389
3390 switch (p->GetType())
3391 {
3392 case svSingleRef:
3393 {
3394 ScSingleRefData& rRef = *p->GetSingleRef();
3395 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3396
3397 // Do not update the reference in transposed case (cut paste transposed).
3398 // The reference will be updated in UpdateTranspose().
3399 // Additionally, do not update the references from cells within the moved
3400 // range as they lead to #REF! errors here. These #REF! cannot by fixed
3401 // later in UpdateTranspose().
3402 if (rCxt.mbTransposed && (aOldRange.Contains(rOldPos) || aOldRange.Contains(aAbs)))
3403 break;
3404
3405 if (aOldRange.Contains(aAbs))
3406 {
3408 if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos, rCxt.mrDoc))
3409 aAbs = aErrorPos;
3410 aRes.mbReferenceModified = true;
3411 }
3412 else if (rCxt.maRange.Contains(aAbs))
3413 {
3414 // Referenced cell has been overwritten.
3415 aRes.mbValueChanged = true;
3416 }
3417
3418 rRef.SetAddress(*mxSheetLimits, aAbs, rNewPos);
3419 rRef.SetFlag3D(aAbs.Tab() != rNewPos.Tab() || !rRef.IsTabRel());
3420 }
3421 break;
3422 case svDoubleRef:
3423 {
3424 ScComplexRefData& rRef = *p->GetDoubleRef();
3425 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3426
3427 // Do not update the reference in transposed case (cut paste transposed).
3428 // The reference will be updated in UpdateTranspose().
3429 // Additionally, do not update the references from cells within the moved
3430 // range as they lead to #REF! errors here. These #REF! cannot by fixed
3431 // later in UpdateTranspose().
3432 if (rCxt.mbTransposed && (aOldRange.Contains(rOldPos) || aOldRange.Contains(aAbs)))
3433 break;
3434
3435 if (aOldRange.Contains(aAbs))
3436 {
3437 ScRange aErrorRange( ScAddress::UNINITIALIZED );
3438 if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorRange, rCxt.mrDoc))
3439 aAbs = aErrorRange;
3440 aRes.mbReferenceModified = true;
3441 }
3442 else if (rCxt.maRange.Contains(aAbs))
3443 {
3444 // Referenced range has been entirely overwritten.
3445 aRes.mbValueChanged = true;
3446 }
3447
3448 rRef.SetRange(*mxSheetLimits, aAbs, rNewPos);
3449 // Absolute sheet reference => set 3D flag.
3450 // More than one sheet referenced => has to have both 3D flags.
3451 // If end part has 3D flag => start part must have it too.
3452 rRef.Ref2.SetFlag3D(aAbs.aStart.Tab() != aAbs.aEnd.Tab() || !rRef.Ref2.IsTabRel());
3453 rRef.Ref1.SetFlag3D(aAbs.aStart.Tab() != rNewPos.Tab() || !rRef.Ref1.IsTabRel() ||
3454 rRef.Ref2.IsFlag3D());
3455 }
3456 break;
3458 {
3459 ScSingleRefData& rRef = *p->GetSingleRef();
3460 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3461 rRef.SetAddress(*mxSheetLimits, aAbs, rNewPos);
3462 }
3463 break;
3465 {
3466 ScComplexRefData& rRef = *p->GetDoubleRef();
3467 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
3468 rRef.SetRange(*mxSheetLimits, aAbs, rNewPos);
3469 }
3470 break;
3471 default:
3472 ;
3473 }
3474
3475 // For ocTableRef p is the inner token of *pp, so have a separate
3476 // condition here.
3477 if ((*pp)->GetType() == svIndex)
3478 {
3479 switch ((*pp)->GetOpCode())
3480 {
3481 case ocName:
3482 {
3483 SCTAB nOldTab = (*pp)->GetSheet();
3484 if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
3485 aRes.mbNameModified = true;
3486 }
3487 break;
3488 case ocDBArea:
3489 case ocTableRef:
3490 if (isDBDataModified(rCxt.mrDoc, **pp))
3491 aRes.mbNameModified = true;
3492 break;
3493 default:
3494 ; // nothing
3495 }
3496 }
3497 }
3498 }
3499
3500 return aRes;
3501}
3502
3504 const ScAddress& rPos, SCTAB nTab, SCROW nRow1, SCROW nRow2, const sc::ColRowReorderMapType& rColMap )
3505{
3506 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3507 for (size_t j=0; j<2; ++j)
3508 {
3509 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3510 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3511 for (; pp != pEnd; ++pp)
3512 {
3513 FormulaToken* p = aPtrs.getHandledToken(j,pp);
3514 if (!p)
3515 continue;
3516
3517 switch (p->GetType())
3518 {
3519 case svSingleRef:
3520 {
3521 ScSingleRefData& rRef = *p->GetSingleRef();
3522 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rPos);
3523
3524 if (aAbs.Tab() == nTab && nRow1 <= aAbs.Row() && aAbs.Row() <= nRow2)
3525 {
3526 // Inside reordered row range.
3528 if (it != rColMap.end())
3529 {
3530 // This column is reordered.
3531 SCCOL nNewCol = it->second;
3532 aAbs.SetCol(nNewCol);
3533 rRef.SetAddress(*mxSheetLimits, aAbs, rPos);
3534 }
3535 }
3536 }
3537 break;
3538 case svDoubleRef:
3539 {
3540 ScComplexRefData& rRef = *p->GetDoubleRef();
3541 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rPos);
3542
3543 if (aAbs.aStart.Tab() != aAbs.aEnd.Tab())
3544 // Must be a single-sheet reference.
3545 break;
3546
3547 if (aAbs.aStart.Col() != aAbs.aEnd.Col())
3548 // Whole range must fit in a single column.
3549 break;
3550
3551 if (aAbs.aStart.Tab() == nTab && nRow1 <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= nRow2)
3552 {
3553 // Inside reordered row range.
3555 if (it != rColMap.end())
3556 {
3557 // This column is reordered.
3558 SCCOL nNewCol = it->second;
3559 aAbs.aStart.SetCol(nNewCol);
3560 aAbs.aEnd.SetCol(nNewCol);
3561 rRef.SetRange(*mxSheetLimits, aAbs, rPos);
3562 }
3563 }
3564 }
3565 break;
3566 default:
3567 ;
3568 }
3569 }
3570 }
3571}
3572
3573void ScTokenArray::MoveReferenceRowReorder( const ScAddress& rPos, SCTAB nTab, SCCOL nCol1, SCCOL nCol2, const sc::ColRowReorderMapType& rRowMap )
3574{
3575 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3576 for (size_t j=0; j<2; ++j)
3577 {
3578 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3579 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3580 for (; pp != pEnd; ++pp)
3581 {
3582 FormulaToken* p = aPtrs.getHandledToken(j,pp);
3583 if (!p)
3584 continue;
3585
3586 switch (p->GetType())
3587 {
3588 case svSingleRef:
3589 {
3590 ScSingleRefData& rRef = *p->GetSingleRef();
3591 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rPos);
3592
3593 if (aAbs.Tab() == nTab && nCol1 <= aAbs.Col() && aAbs.Col() <= nCol2)
3594 {
3595 // Inside reordered column range.
3597 if (it != rRowMap.end())
3598 {
3599 // This column is reordered.
3600 SCROW nNewRow = it->second;
3601 aAbs.SetRow(nNewRow);
3602 rRef.SetAddress(*mxSheetLimits, aAbs, rPos);
3603 }
3604 }
3605 }
3606 break;
3607 case svDoubleRef:
3608 {
3609 ScComplexRefData& rRef = *p->GetDoubleRef();
3610 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rPos);
3611
3612 if (aAbs.aStart.Tab() != aAbs.aEnd.Tab())
3613 // Must be a single-sheet reference.
3614 break;
3615
3616 if (aAbs.aStart.Row() != aAbs.aEnd.Row())
3617 // Whole range must fit in a single row.
3618 break;
3619
3620 if (aAbs.aStart.Tab() == nTab && nCol1 <= aAbs.aStart.Col() && aAbs.aEnd.Col() <= nCol2)
3621 {
3622 // Inside reordered column range.
3624 if (it != rRowMap.end())
3625 {
3626 // This row is reordered.
3627 SCROW nNewRow = it->second;
3628 aAbs.aStart.SetRow(nNewRow);
3629 aAbs.aEnd.SetRow(nNewRow);
3630 rRef.SetRange(*mxSheetLimits, aAbs, rPos);
3631 }
3632 }
3633 }
3634 break;
3635 default:
3636 ;
3637 }
3638 }
3639 }
3640}
3641
3642namespace {
3643
3644bool adjustSingleRefInName(
3645 ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt, const ScAddress& rPos,
3646 ScComplexRefData* pEndOfComplex )
3647{
3648 ScAddress aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3649
3650 if (aAbs.Tab() < rCxt.maRange.aStart.Tab() || rCxt.maRange.aEnd.Tab() < aAbs.Tab())
3651 {
3652 // This references a sheet that has not shifted. Don't change it.
3653 return false;
3654 }
3655
3656 if (!rCxt.maRange.Contains(rRef.toAbs(rCxt.mrDoc, rPos)))
3657 return false;
3658
3659 bool bChanged = false;
3660
3661 if (rCxt.mnColDelta && !rRef.IsColRel())
3662 {
3663 // Adjust absolute column reference.
3664 if (rCxt.maRange.aStart.Col() <= rRef.Col() && rRef.Col() <= rCxt.maRange.aEnd.Col())
3665 {
3666 if (pEndOfComplex)
3667 {
3668 if (pEndOfComplex->IncEndColSticky(rCxt.mrDoc, rCxt.mnColDelta, rPos))
3669 bChanged = true;
3670 }
3671 else
3672 {
3673 rRef.IncCol(rCxt.mnColDelta);
3674 bChanged = true;
3675 }
3676 }
3677 }
3678
3679 if (rCxt.mnRowDelta && !rRef.IsRowRel())
3680 {
3681 // Adjust absolute row reference.
3682 if (rCxt.maRange.aStart.Row() <= rRef.Row() && rRef.Row() <= rCxt.maRange.aEnd.Row())
3683 {
3684 if (pEndOfComplex)
3685 {
3686 if (pEndOfComplex->IncEndRowSticky(rCxt.mrDoc, rCxt.mnRowDelta, rPos))
3687 bChanged = true;
3688 }
3689 else
3690 {
3691 rRef.IncRow(rCxt.mnRowDelta);
3692 bChanged = true;
3693 }
3694 }
3695 }
3696
3697 if (!rRef.IsTabRel() && rCxt.mnTabDelta)
3698 {
3699 // Sheet range has already been checked above.
3700 rRef.IncTab(rCxt.mnTabDelta);
3701 bChanged = true;
3702 }
3703
3704 return bChanged;
3705}
3706
3707bool adjustDoubleRefInName(
3708 ScComplexRefData& rRef, const sc::RefUpdateContext& rCxt, const ScAddress& rPos )
3709{
3710 bool bRefChanged = false;
3711 if (rCxt.mrDoc.IsExpandRefs())
3712 {
3713 if (rCxt.mnRowDelta > 0 && !rRef.Ref1.IsRowRel() && !rRef.Ref2.IsRowRel())
3714 {
3715 ScRange aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3716 // Expand only if at least two rows tall.
3717 if (aAbs.aStart.Row() < aAbs.aEnd.Row())
3718 {
3719 // Check and see if we should expand the range at the top.
3720 ScRange aSelectedRange = getSelectedRange(rCxt);
3721 if (aSelectedRange.Intersects(aAbs))
3722 {
3723 // Selection intersects the referenced range. Only expand the
3724 // bottom position.
3725 rRef.IncEndRowSticky(rCxt.mrDoc, rCxt.mnRowDelta, rPos);
3726 return true;
3727 }
3728 }
3729 }
3730 if (rCxt.mnColDelta > 0 && !rRef.Ref1.IsColRel() && !rRef.Ref2.IsColRel())
3731 {
3732 ScRange aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3733 // Expand only if at least two columns wide.
3734 if (aAbs.aStart.Col() < aAbs.aEnd.Col())
3735 {
3736 // Check and see if we should expand the range at the left.
3737 ScRange aSelectedRange = getSelectedRange(rCxt);
3738 if (aSelectedRange.Intersects(aAbs))
3739 {
3740 // Selection intersects the referenced range. Only expand the
3741 // right position.
3742 rRef.IncEndColSticky(rCxt.mrDoc, rCxt.mnColDelta, rPos);
3743 return true;
3744 }
3745 }
3746 }
3747 }
3748
3749 if ((rCxt.mnRowDelta && rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
3750 || (rCxt.mnColDelta && rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits())))
3751 {
3752 sc::RefUpdateContext aCxt( rCxt.mrDoc);
3753 // We only need a few parameters of RefUpdateContext.
3754 aCxt.maRange = rCxt.maRange;
3755 aCxt.mnColDelta = rCxt.mnColDelta;
3756 aCxt.mnRowDelta = rCxt.mnRowDelta;
3757 aCxt.mnTabDelta = rCxt.mnTabDelta;
3758
3759 // References to entire col/row are not to be adjusted in the other axis.
3760 if (aCxt.mnRowDelta && rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
3761 aCxt.mnRowDelta = 0;
3762 if (aCxt.mnColDelta && rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits()))
3763 aCxt.mnColDelta = 0;
3764 if (!aCxt.mnColDelta && !aCxt.mnRowDelta && !aCxt.mnTabDelta)
3765 // early bailout
3766 return bRefChanged;
3767
3768 // Ref2 before Ref1 for sticky ends.
3769 if (adjustSingleRefInName(rRef.Ref2, aCxt, rPos, &rRef))
3770 bRefChanged = true;
3771
3772 if (adjustSingleRefInName(rRef.Ref1, aCxt, rPos, nullptr))
3773 bRefChanged = true;
3774 }
3775 else
3776 {
3777 // Ref2 before Ref1 for sticky ends.
3778 if (adjustSingleRefInName(rRef.Ref2, rCxt, rPos, &rRef))
3779 bRefChanged = true;
3780
3781 if (adjustSingleRefInName(rRef.Ref1, rCxt, rPos, nullptr))
3782 bRefChanged = true;
3783 }
3784
3785 return bRefChanged;
3786}
3787
3788}
3789
3791 const sc::RefUpdateContext& rCxt, const ScAddress& rPos )
3792{
3793 if (rCxt.meMode == URM_MOVE)
3794 return AdjustReferenceInMovedName(rCxt, rPos);
3795
3797
3798 if (rCxt.meMode == URM_COPY)
3799 // Copying cells does not modify named expressions.
3800 return aRes;
3801
3802 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
3803 for (size_t j=0; j<2; ++j)
3804 {
3805 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
3806 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
3807 for (; pp != pEnd; ++pp)
3808 {
3809 FormulaToken* p = aPtrs.getHandledToken(j,pp);
3810 if (!p)
3811 continue;
3812
3813 switch (p->GetType())
3814 {
3815 case svSingleRef:
3816 {
3817 ScSingleRefData& rRef = *p->GetSingleRef();
3818 if (rCxt.mnRowDelta < 0)
3819 {
3820 // row(s) deleted.
3821
3822 if (rRef.IsRowRel())
3823 // Don't modify relative references in names.
3824 break;
3825
3826 ScAddress aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3827
3828 if (aAbs.Col() < rCxt.maRange.aStart.Col() || rCxt.maRange.aEnd.Col() < aAbs.Col())
3829 // column of the reference is not in the deleted column range.
3830 break;
3831
3832 if (aAbs.Tab() > rCxt.maRange.aEnd.Tab() || aAbs.Tab() < rCxt.maRange.aStart.Tab())
3833 // wrong tables
3834 break;
3835
3836 const SCROW nDelStartRow = rCxt.maRange.aStart.Row() + rCxt.mnRowDelta;
3837 const SCROW nDelEndRow = nDelStartRow - rCxt.mnRowDelta - 1;
3838
3839 if (nDelStartRow <= aAbs.Row() && aAbs.Row() <= nDelEndRow)
3840 {
3841 // This reference is deleted.
3842 rRef.SetRowDeleted(true);
3843 aRes.mbReferenceModified = true;
3844 break;
3845 }
3846 }
3847 else if (rCxt.mnColDelta < 0)
3848 {
3849 // column(s) deleted.
3850
3851 if (rRef.IsColRel())
3852 // Don't modify relative references in names.
3853 break;
3854
3855 ScAddress aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3856
3857 if (aAbs.Row() < rCxt.maRange.aStart.Row() || rCxt.maRange.aEnd.Row() < aAbs.Row())
3858 // row of the reference is not in the deleted row range.
3859 break;
3860
3861 if (aAbs.Tab() > rCxt.maRange.aEnd.Tab() || aAbs.Tab() < rCxt.maRange.aStart.Tab())
3862 // wrong tables
3863 break;
3864
3865 const SCCOL nDelStartCol = rCxt.maRange.aStart.Col() + rCxt.mnColDelta;
3866 const SCCOL nDelEndCol = nDelStartCol - rCxt.mnColDelta - 1;
3867
3868 if (nDelStartCol <= aAbs.Col() && aAbs.Col() <= nDelEndCol)
3869 {
3870 // This reference is deleted.
3871 rRef.SetColDeleted(true);
3872 aRes.mbReferenceModified = true;
3873 break;
3874 }
3875 }
3876
3877 if (adjustSingleRefInName(rRef, rCxt, rPos, nullptr))
3878 aRes.mbReferenceModified = true;
3879 }
3880 break;
3881 case svDoubleRef:
3882 {
3883 ScComplexRefData& rRef = *p->GetDoubleRef();
3884 ScRange aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
3885
3886 if (aAbs.aStart.Tab() > rCxt.maRange.aEnd.Tab() || aAbs.aEnd.Tab() < rCxt.maRange.aStart.Tab())
3887 // Sheet references not affected.
3888 break;
3889
3890 if (rCxt.maRange.Contains(aAbs))
3891 {
3892 // This range is entirely within the shifted region.
3893 if (adjustDoubleRefInName(rRef, rCxt, rPos))
3894 aRes.mbReferenceModified = true;
3895 }
3896 else if (rCxt.mnRowDelta < 0)
3897 {
3898 // row(s) deleted.
3899
3900 if (rRef.IsEntireCol(rCxt.mrDoc.GetSheetLimits()))
3901 // Rows of entire columns are not affected.
3902 break;
3903
3904 if (rRef.Ref1.IsRowRel() || rRef.Ref2.IsRowRel())
3905 // Don't modify relative references in names.
3906 break;
3907
3908 if (aAbs.aStart.Col() < rCxt.maRange.aStart.Col() || rCxt.maRange.aEnd.Col() < aAbs.aEnd.Col())
3909 // column range of the reference is not entirely in the deleted column range.
3910 break;
3911
3912 ScRange aDeleted = rCxt.maRange;
3913 aDeleted.aStart.IncRow(rCxt.mnRowDelta);
3914 aDeleted.aEnd.SetRow(aDeleted.aStart.Row()-rCxt.mnRowDelta-1);
3915
3916 if (aAbs.aEnd.Row() < aDeleted.aStart.Row() || aDeleted.aEnd.Row() < aAbs.aStart.Row())
3917 // reference range doesn't intersect with the deleted range.
3918 break;
3919
3920 if (aDeleted.aStart.Row() <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= aDeleted.aEnd.Row())
3921 {
3922 // This reference is entirely deleted.
3923 rRef.Ref1.SetRowDeleted(true);
3924 rRef.Ref2.SetRowDeleted(true);
3925 aRes.mbReferenceModified = true;
3926 break;
3927 }
3928
3929 if (aAbs.aStart.Row() < aDeleted.aStart.Row())
3930 {
3931 if (!aAbs.IsEndRowSticky(rCxt.mrDoc))
3932 {
3933 if (aDeleted.aEnd.Row() < aAbs.aEnd.Row())
3934 // Deleted in the middle. Make the reference shorter.
3935 rRef.Ref2.IncRow(rCxt.mnRowDelta);
3936 else
3937 // Deleted at tail end. Cut off the lower part.
3938 rRef.Ref2.SetAbsRow(aDeleted.aStart.Row()-1);
3939 }
3940 }
3941 else
3942 {
3943 // Deleted at the top. Cut the top off and shift up.
3944 rRef.Ref1.SetAbsRow(aDeleted.aEnd.Row()+1);
3945 rRef.Ref1.IncRow(rCxt.mnRowDelta);
3946 if (!aAbs.IsEndRowSticky(rCxt.mrDoc))
3947 rRef.Ref2.IncRow(rCxt.mnRowDelta);
3948 }
3949
3950 aRes.mbReferenceModified = true;
3951 }
3952 else if (rCxt.mnColDelta < 0)
3953 {
3954 // column(s) deleted.
3955
3956 if (rRef.IsEntireRow(rCxt.mrDoc.GetSheetLimits()))
3957 // Rows of entire rows are not affected.
3958 break;
3959
3960 if (rRef.Ref1.IsColRel() || rRef.Ref2.IsColRel())
3961 // Don't modify relative references in names.
3962 break;
3963
3964 if (aAbs.aStart.Row() < rCxt.maRange.aStart.Row() || rCxt.maRange.aEnd.Row() < aAbs.aEnd.Row())
3965 // row range of the reference is not entirely in the deleted row range.
3966 break;
3967
3968 ScRange aDeleted = rCxt.maRange;
3969 aDeleted.aStart.IncCol(rCxt.mnColDelta);
3970 aDeleted.aEnd.SetCol(aDeleted.aStart.Col()-rCxt.mnColDelta-1);
3971
3972 if (aAbs.aEnd.Col() < aDeleted.aStart.Col() || aDeleted.aEnd.Col() < aAbs.aStart.Col())
3973 // reference range doesn't intersect with the deleted range.
3974 break;
3975
3976 if (aDeleted.aStart.Col() <= aAbs.aStart.Col() && aAbs.aEnd.Col() <= aDeleted.aEnd.Col())
3977 {
3978 // This reference is entirely deleted.
3979 rRef.Ref1.SetColDeleted(true);
3980 rRef.Ref2.SetColDeleted(true);
3981 aRes.mbReferenceModified = true;
3982 break;
3983 }
3984
3985 if (aAbs.aStart.Col() < aDeleted.aStart.Col())
3986 {
3987 if (!aAbs.IsEndColSticky(rCxt.mrDoc))
3988 {
3989 if (aDeleted.aEnd.Col() < aAbs.aEnd.Col())
3990 // Deleted in the middle. Make the reference shorter.
3991 rRef.Ref2.IncCol(rCxt.mnColDelta);
3992 else
3993 // Deleted at tail end. Cut off the right part.
3994 rRef.Ref2.SetAbsCol(aDeleted.aStart.Col()-1);
3995 }
3996 }
3997 else
3998 {
3999 // Deleted at the left. Cut the left off and shift left.
4000 rRef.Ref1.SetAbsCol(aDeleted.aEnd.Col()+1);
4001 rRef.Ref1.IncCol(rCxt.mnColDelta);
4002 if (!aAbs.IsEndColSticky(rCxt.mrDoc))
4003 rRef.Ref2.IncCol(rCxt.mnColDelta);
4004 }
4005
4006 aRes.mbReferenceModified = true;
4007 }
4008 else if (rCxt.maRange.Intersects(aAbs))
4009 {
4010 if (rCxt.mnColDelta && rCxt.maRange.aStart.Row() <= aAbs.aStart.Row() && aAbs.aEnd.Row() <= rCxt.maRange.aEnd.Row())
4011 {
4012 if (adjustDoubleRefInName(rRef, rCxt, rPos))
4013 aRes.mbReferenceModified = true;
4014 }
4015 if (rCxt.mnRowDelta && rCxt.maRange.aStart.Col() <= aAbs.aStart.Col() && aAbs.aEnd.Col() <= rCxt.maRange.aEnd.Col())
4016 {
4017 if (adjustDoubleRefInName(rRef, rCxt, rPos))
4018 aRes.mbReferenceModified = true;
4019 }
4020 }
4021 else if (rCxt.mnRowDelta > 0 && rCxt.mrDoc.IsExpandRefs())
4022 {
4023 // Check if we could expand range reference by the bottom
4024 // edge. For named expressions, we only expand absolute
4025 // references. Reference must be at least two rows
4026 // tall.
4027 if (!rRef.Ref1.IsRowRel() && !rRef.Ref2.IsRowRel() &&
4028 aAbs.aStart.Row() < aAbs.aEnd.Row() &&
4029 aAbs.aEnd.Row()+1 == rCxt.maRange.aStart.Row())
4030 {
4031 // Expand by the bottom edge.
4032 rRef.Ref2.IncRow(rCxt.mnRowDelta);
4033 aRes.mbReferenceModified = true;
4034 }
4035 }
4036 else if (rCxt.mnColDelta > 0 && rCxt.mrDoc.IsExpandRefs())
4037 {
4038 // Check if we could expand range reference by the right
4039 // edge. For named expressions, we only expand absolute
4040 // references. Reference must be at least two
4041 // columns wide.
4042 if (!rRef.Ref1.IsColRel() && !rRef.Ref2.IsColRel() &&
4043 aAbs.aStart.Col() < aAbs.aEnd.Col() &&
4044 aAbs.aEnd.Col()+1 == rCxt.maRange.aStart.Col())
4045 {
4046 // Expand by the right edge.
4047 rRef.Ref2.IncCol(rCxt.mnColDelta);
4048 aRes.mbReferenceModified = true;
4049 }
4050 }
4051 }
4052 break;
4053 default:
4054 ;
4055 }
4056 }
4057 }
4058
4059 return aRes;
4060}
4061
4063{
4064 // When moving, the range is the destination range.
4065 ScRange aOldRange = rCxt.maRange;
4066 ScRange aErrorMoveRange( ScAddress::UNINITIALIZED );
4067 if (!aOldRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta, aErrorMoveRange, rCxt.mrDoc))
4068 {
4069 assert(!"can't move");
4070 }
4071
4072 // In a named expression, we'll move the reference only when the reference
4073 // is entirely absolute.
4074
4076
4077 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4078 for (size_t j=0; j<2; ++j)
4079 {
4080 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4081 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4082 for (; pp != pEnd; ++pp)
4083 {
4084 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4085 if (!p)
4086 continue;
4087
4088 switch (p->GetType())
4089 {
4090 case svSingleRef:
4091 {
4092 ScSingleRefData& rRef = *p->GetSingleRef();
4093 if (rRef.IsColRel() || rRef.IsRowRel() || rRef.IsTabRel())
4094 continue;
4095
4096 ScAddress aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
4097
4098 // Do not update the reference in transposed case (cut paste transposed).
4099 // The reference will be updated in UpdateTranspose().
4100 if (rCxt.mbTransposed && aOldRange.Contains(aAbs))
4101 break;
4102
4103 if (aOldRange.Contains(aAbs))
4104 {
4106 if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos, rCxt.mrDoc))
4107 aAbs = aErrorPos;
4108 aRes.mbReferenceModified = true;
4109 }
4110
4111 rRef.SetAddress(rCxt.mrDoc.GetSheetLimits(), aAbs, rPos);
4112 }
4113 break;
4114 case svDoubleRef:
4115 {
4116 ScComplexRefData& rRef = *p->GetDoubleRef();
4117 if (rRef.Ref1.IsColRel() || rRef.Ref1.IsRowRel() || rRef.Ref1.IsTabRel() ||
4118 rRef.Ref2.IsColRel() || rRef.Ref2.IsRowRel() || rRef.Ref2.IsTabRel())
4119 continue;
4120
4121 ScRange aAbs = rRef.toAbs(rCxt.mrDoc, rPos);
4122
4123 // Do not update the reference in transposed case (cut paste transposed).
4124 // The reference will be updated in UpdateTranspose().
4125 if (rCxt.mbTransposed && aOldRange.Contains(aAbs))
4126 break;
4127
4128 if (aOldRange.Contains(aAbs))
4129 {
4130 ScRange aErrorRange( ScAddress::UNINITIALIZED );
4131 if (!aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorRange, rCxt.mrDoc))
4132 aAbs = aErrorRange;
4133 aRes.mbReferenceModified = true;
4134 }
4135
4136 rRef.SetRange(rCxt.mrDoc.GetSheetLimits(), aAbs, rPos);
4137 }
4138 break;
4139 default:
4140 ;
4141 }
4142 }
4143 }
4144
4145 return aRes;
4146}
4147
4148namespace {
4149
4150bool adjustSingleRefOnDeletedTab( const ScSheetLimits& rLimits, ScSingleRefData& rRef, SCTAB nDelPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos )
4151{
4152 ScAddress aAbs = rRef.toAbs(rLimits, rOldPos);
4153 if (nDelPos <= aAbs.Tab() && aAbs.Tab() < nDelPos + nSheets)
4154 {
4155 rRef.SetTabDeleted(true);
4156 return true;
4157 }
4158
4159 if (nDelPos < aAbs.Tab())
4160 {
4161 // Reference sheet needs to be adjusted.
4162 aAbs.IncTab(-1*nSheets);
4163 rRef.SetAddress(rLimits, aAbs, rNewPos);
4164 return true;
4165 }
4166 else if (rOldPos.Tab() != rNewPos.Tab())
4167 {
4168 // Cell itself has moved.
4169 rRef.SetAddress(rLimits, aAbs, rNewPos);
4170 return true;
4171 }
4172
4173 return false;
4174}
4175
4176bool adjustSingleRefOnInsertedTab( const ScSheetLimits& rLimits, ScSingleRefData& rRef, SCTAB nInsPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos )
4177{
4178 ScAddress aAbs = rRef.toAbs(rLimits, rOldPos);
4179 if (nInsPos <= aAbs.Tab())
4180 {
4181 // Reference sheet needs to be adjusted.
4182 aAbs.IncTab(nSheets);
4183 rRef.SetAddress(rLimits, aAbs, rNewPos);
4184 return true;
4185 }
4186 else if (rOldPos.Tab() != rNewPos.Tab())
4187 {
4188 // Cell itself has moved.
4189 rRef.SetAddress(rLimits, aAbs, rNewPos);
4190 return true;
4191 }
4192
4193 return false;
4194}
4195
4196bool adjustDoubleRefOnDeleteTab(const ScSheetLimits& rLimits, ScComplexRefData& rRef, SCTAB nDelPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos)
4197{
4198 ScSingleRefData& rRef1 = rRef.Ref1;
4199 ScSingleRefData& rRef2 = rRef.Ref2;
4200 ScAddress aStartPos = rRef1.toAbs(rLimits, rOldPos);
4201 ScAddress aEndPos = rRef2.toAbs(rLimits, rOldPos);
4202 bool bMoreThanOneTab = aStartPos.Tab() != aEndPos.Tab();
4203 bool bModified = false;
4204 if (bMoreThanOneTab && aStartPos.Tab() == nDelPos && nDelPos + nSheets <= aEndPos.Tab())
4205 {
4206 if (rRef1.IsTabRel() && aStartPos.Tab() < rOldPos.Tab())
4207 {
4208 rRef1.IncTab(nSheets);
4209 bModified = true;
4210 }
4211 }
4212 else
4213 {
4214 bModified = adjustSingleRefOnDeletedTab(rLimits, rRef1, nDelPos, nSheets, rOldPos, rNewPos);
4215 }
4216
4217 if (bMoreThanOneTab && aEndPos.Tab() == nDelPos && aStartPos.Tab() <= nDelPos - nSheets)
4218 {
4219 if (!rRef2.IsTabRel() || rOldPos.Tab() < aEndPos.Tab())
4220 {
4221 rRef2.IncTab(-nSheets);
4222 bModified = true;
4223 }
4224 }
4225 else
4226 {
4227 bModified |= adjustSingleRefOnDeletedTab(rLimits, rRef2, nDelPos, nSheets, rOldPos, rNewPos);
4228 }
4229 return bModified;
4230}
4231
4232}
4233
4235{
4237 ScAddress aNewPos = rOldPos;
4238 ScRangeUpdater::UpdateDeleteTab( aNewPos, rCxt);
4239
4240 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4241 for (size_t j=0; j<2; ++j)
4242 {
4243 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4244 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4245 for (; pp != pEnd; ++pp)
4246 {
4247 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4248 if (!p)
4249 continue;
4250
4251 switch (p->GetType())
4252 {
4253 case svSingleRef:
4254 {
4255 ScSingleRefData& rRef = *p->GetSingleRef();
4256 if (adjustSingleRefOnDeletedTab(*mxSheetLimits, rRef, rCxt.mnDeletePos, rCxt.mnSheets, rOldPos, aNewPos))
4257 aRes.mbReferenceModified = true;
4258 }
4259 break;
4260 case svDoubleRef:
4261 {
4262 ScComplexRefData& rRef = *p->GetDoubleRef();
4263 aRes.mbReferenceModified |= adjustDoubleRefOnDeleteTab(*mxSheetLimits, rRef, rCxt.mnDeletePos, rCxt.mnSheets, rOldPos, aNewPos);
4264 }
4265 break;
4266 default:
4267 ;
4268 }
4269
4270 // For ocTableRef p is the inner token of *pp, so have a separate
4271 // condition here.
4272 if ((*pp)->GetType() == svIndex)
4273 {
4274 switch ((*pp)->GetOpCode())
4275 {
4276 case ocName:
4277 {
4278 SCTAB nOldTab = (*pp)->GetSheet();
4279 if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
4280 aRes.mbNameModified = true;
4281 if (rCxt.mnDeletePos <= nOldTab)
4282 {
4283 aRes.mbNameModified = true;
4284 if (rCxt.mnDeletePos + rCxt.mnSheets <= nOldTab)
4285 (*pp)->SetSheet( nOldTab - rCxt.mnSheets);
4286 else
4287 // Would point to a deleted sheet. Invalidate.
4288 (*pp)->SetSheet( SCTAB_MAX);
4289 }
4290 }
4291 break;
4292 case ocDBArea:
4293 case ocTableRef:
4294 if (isDBDataModified(rCxt.mrDoc, **pp))
4295 aRes.mbNameModified = true;
4296 break;
4297 default:
4298 ; // nothing
4299 }
4300 }
4301 }
4302 }
4303 return aRes;
4304}
4305
4307{
4309 ScAddress aNewPos = rOldPos;
4310 if (rCxt.mnInsertPos <= rOldPos.Tab())
4311 aNewPos.IncTab(rCxt.mnSheets);
4312
4313 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4314 for (size_t j=0; j<2; ++j)
4315 {
4316 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4317 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4318 for (; pp != pEnd; ++pp)
4319 {
4320 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4321 if (!p)
4322 continue;
4323
4324 switch (p->GetType())
4325 {
4326 case svSingleRef:
4327 {
4328 ScSingleRefData& rRef = *p->GetSingleRef();
4329 if (adjustSingleRefOnInsertedTab(*mxSheetLimits, rRef, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
4330 aRes.mbReferenceModified = true;
4331 }
4332 break;
4333 case svDoubleRef:
4334 {
4335 ScComplexRefData& rRef = *p->GetDoubleRef();
4336 if (adjustSingleRefOnInsertedTab(*mxSheetLimits, rRef.Ref1, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
4337 aRes.mbReferenceModified = true;
4338 if (adjustSingleRefOnInsertedTab(*mxSheetLimits, rRef.Ref2, rCxt.mnInsertPos, rCxt.mnSheets, rOldPos, aNewPos))
4339 aRes.mbReferenceModified = true;
4340 }
4341 break;
4342 default:
4343 ;
4344 }
4345
4346 // For ocTableRef p is the inner token of *pp, so have a separate
4347 // condition here.
4348 if ((*pp)->GetType() == svIndex)
4349 {
4350 switch ((*pp)->GetOpCode())
4351 {
4352 case ocName:
4353 {
4354 SCTAB nOldTab = (*pp)->GetSheet();
4355 if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
4356 aRes.mbNameModified = true;
4357 if (rCxt.mnInsertPos <= nOldTab)
4358 {
4359 aRes.mbNameModified = true;
4360 (*pp)->SetSheet( nOldTab + rCxt.mnSheets);
4361 }
4362 }
4363 break;
4364 case ocDBArea:
4365 case ocTableRef:
4366 if (isDBDataModified(rCxt.mrDoc, **pp))
4367 aRes.mbNameModified = true;
4368 break;
4369 default:
4370 ; // nothing
4371 }
4372 }
4373 }
4374 }
4375 return aRes;
4376}
4377
4378namespace {
4379
4380bool adjustTabOnMove( ScAddress& rPos, const sc::RefUpdateMoveTabContext& rCxt )
4381{
4382 SCTAB nNewTab = rCxt.getNewTab(rPos.Tab());
4383 if (nNewTab == rPos.Tab())
4384 return false;
4385
4386 rPos.SetTab(nNewTab);
4387 return true;
4388}
4389
4390}
4391
4393{
4395 if (rCxt.mnOldPos == rCxt.mnNewPos)
4396 return aRes;
4397
4398 ScAddress aNewPos = rOldPos;
4399 if (adjustTabOnMove(aNewPos, rCxt))
4400 aRes.mbReferenceModified = true;
4401
4402 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4403 for (size_t j=0; j<2; ++j)
4404 {
4405 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4406 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4407 for (; pp != pEnd; ++pp)
4408 {
4409 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4410 if (!p)
4411 continue;
4412
4413 switch (p->GetType())
4414 {
4415 case svSingleRef:
4416 {
4417 ScSingleRefData& rRef = *p->GetSingleRef();
4418 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
4419 if (adjustTabOnMove(aAbs, rCxt))
4420 aRes.mbReferenceModified = true;
4421 rRef.SetAddress(*mxSheetLimits, aAbs, aNewPos);
4422 }
4423 break;
4424 case svDoubleRef:
4425 {
4426 ScComplexRefData& rRef = *p->GetDoubleRef();
4427 ScRange aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
4428 if (adjustTabOnMove(aAbs.aStart, rCxt))
4429 aRes.mbReferenceModified = true;
4430 if (adjustTabOnMove(aAbs.aEnd, rCxt))
4431 aRes.mbReferenceModified = true;
4432 rRef.SetRange(*mxSheetLimits, aAbs, aNewPos);
4433 }
4434 break;
4435 default:
4436 ;
4437 }
4438
4439 // For ocTableRef p is the inner token of *pp, so have a separate
4440 // condition here.
4441 if ((*pp)->GetType() == svIndex)
4442 {
4443 switch ((*pp)->GetOpCode())
4444 {
4445 case ocName:
4446 {
4447 SCTAB nOldTab = (*pp)->GetSheet();
4448 if (isNameModified(rCxt.maUpdatedNames, nOldTab, **pp))
4449 aRes.mbNameModified = true;
4450 SCTAB nNewTab = rCxt.getNewTab( nOldTab);
4451 if (nNewTab != nOldTab)
4452 {
4453 aRes.mbNameModified = true;
4454 (*pp)->SetSheet( nNewTab);
4455 }
4456 }
4457 break;
4458 case ocDBArea:
4459 case ocTableRef:
4460 if (isDBDataModified(rCxt.mrDoc, **pp))
4461 aRes.mbNameModified = true;
4462 break;
4463 default:
4464 ; // nothing
4465 }
4466 }
4467 }
4468 }
4469
4470 return aRes;
4471}
4472
4474{
4475 TokenPointers aPtrs( pCode.get(), nLen, pRPN, nRPN);
4476 for (size_t j=0; j<2; ++j)
4477 {
4478 FormulaToken** pp = aPtrs.maPointerRange[j].mpStart;
4479 FormulaToken** pEnd = aPtrs.maPointerRange[j].mpStop;
4480 for (; pp != pEnd; ++pp)
4481 {
4482 FormulaToken* p = aPtrs.getHandledToken(j,pp);
4483 if (!p)
4484 continue;
4485
4486 switch (p->GetType())
4487 {
4488 case svSingleRef:
4490 {
4491 ScSingleRefData& rRef = *p->GetSingleRef();
4492 ScAddress aAbs = rRef.toAbs(*mxSheetLimits, rOldPos);
4493 rRef.SetAddress(*mxSheetLimits, aAbs, rNewPos);
4494 }
4495 break;
4496 case svDoubleRef: