Rework FormulaTokenArray ScRecalcMode in preparation for tdf#94925

Strictly order the exclusive bits by priority, let AddRecalcMode()
handle all sets except forced ALWAYS or NORMAL.

Introduce ONLOAD_LENIENT and ONLOAD_MUST splitting ONLOAD to be
able to distinguish later during OOXML import.

Change-Id: I188de2d53a2d54df32d24eeeb148c4f9e87e7cfc
Reviewed-on: https://gerrit.libreoffice.org/57402
Reviewed-by: Eike Rathke <erack@redhat.com>
Tested-by: Jenkins
This commit is contained in:
Eike Rathke
2018-07-13 19:29:12 +02:00
parent e92dcc0632
commit a5803a66fd
7 changed files with 65 additions and 64 deletions

View File

@@ -1428,14 +1428,15 @@ void FormulaCompiler::Factor()
switch( eOp ) switch( eOp )
{ {
// Functions recalculated on every document load. // Functions recalculated on every document load.
// Don't use SetExclusiveRecalcModeOnLoad() which would // ONLOAD_LENIENT here to be able to distinguish and not
// override ModeAlways, use // force a recalc (if not in an ALWAYS or ONLOAD_MUST
// AddRecalcMode(ScRecalcMode::ONLOAD) instead. // context) but keep an imported result from for example
// OOXML a DDE call. Will be recalculated for ODFF.
case ocConvertOOo : case ocConvertOOo :
case ocDde: case ocDde:
case ocMacro: case ocMacro:
case ocExternal: case ocExternal:
pArr->AddRecalcMode( ScRecalcMode::ONLOAD ); pArr->AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT );
break; break;
// If the referred cell is moved the value changes. // If the referred cell is moved the value changes.
case ocColumn : case ocColumn :
@@ -1443,15 +1444,15 @@ void FormulaCompiler::Factor()
pArr->SetRecalcModeOnRefMove(); pArr->SetRecalcModeOnRefMove();
break; break;
// ocCell needs recalc on move for some possible type values. // ocCell needs recalc on move for some possible type values.
// and recalc mode on load, fdo#60646 // And recalc mode on load, tdf#60645
case ocCell : case ocCell :
pArr->SetRecalcModeOnRefMove(); pArr->SetRecalcModeOnRefMove();
pArr->AddRecalcMode( ScRecalcMode::ONLOAD ); pArr->AddRecalcMode( ScRecalcMode::ONLOAD_MUST );
break; break;
case ocHyperLink : case ocHyperLink :
// cell with hyperlink needs to be calculated on load to // Cell with hyperlink needs to be calculated on load to
// get its matrix result generated. // get its matrix result generated.
pArr->AddRecalcMode( ScRecalcMode::ONLOAD ); pArr->AddRecalcMode( ScRecalcMode::ONLOAD_MUST );
pArr->SetHyperLink( true); pArr->SetHyperLink( true);
break; break;
default: default:

View File

@@ -845,15 +845,27 @@ FormulaToken* FormulaTokenArray::AddStringXML( const OUString& rStr )
void FormulaTokenArray::AddRecalcMode( ScRecalcMode nBits ) void FormulaTokenArray::AddRecalcMode( ScRecalcMode nBits )
{ {
//! Order is important. const unsigned nExclusive = static_cast<sal_uInt8>(nBits & ScRecalcMode::EMask);
if ( nBits & ScRecalcMode::ALWAYS ) if (nExclusive)
SetExclusiveRecalcModeAlways();
else if ( !IsRecalcModeAlways() )
{ {
if ( nBits & ScRecalcMode::ONLOAD ) unsigned nExBit;
SetExclusiveRecalcModeOnLoad(); if (nExclusive & (nExclusive - 1))
else if ( nBits & ScRecalcMode::ONLOAD_ONCE && !IsRecalcModeOnLoad() ) {
SetExclusiveRecalcModeOnLoadOnce(); // More than one bit set, use highest priority.
for (nExBit = 1; (nExBit & static_cast<sal_uInt8>(ScRecalcMode::EMask)) != 0; nExBit <<= 1)
{
if (nExclusive & nExBit)
break;
}
}
else
{
// Only one bit is set.
nExBit = nExclusive;
}
// Set exclusive bit if priority is higher than existing.
if (nExBit < static_cast<sal_uInt8>(nMode & ScRecalcMode::EMask))
SetMaskedRecalcMode( static_cast<ScRecalcMode>(nExBit));
} }
SetCombinedBitsRecalcMode( nBits ); SetCombinedBitsRecalcMode( nBits );
} }

View File

@@ -48,24 +48,26 @@ class SharedStringPool;
} }
// RecalcMode access only via TokenArray SetRecalcMode / IsRecalcMode... // RecalcMode access only via TokenArray SetExclusiveRecalcMode...() /
// IsRecalcMode...()
// Only one of the exclusive bits can be set, // Only one of the exclusive bits can be set and one must be set,
// handled by TokenArray SetRecalcMode... methods // handled by TokenArray SetExclusiveRecalcMode...() methods.
// Exclusive bits are ordered by priority, AddRecalcMode() relies on that.
enum class ScRecalcMode : sal_uInt8 enum class ScRecalcMode : sal_uInt8
{ {
NORMAL = 0x01, // exclusive ALWAYS = 0x01, // exclusive, always
ALWAYS = 0x02, // exclusive, always ONLOAD_MUST = 0x02, // exclusive, always after load
ONLOAD = 0x04, // exclusive, always after load ONLOAD_LENIENT = 0x04, // exclusive, lenient after load (eg. macros not always, aliens, ...)
ONLOAD_ONCE = 0x08, // exclusive, once after load ONLOAD_ONCE = 0x08, // exclusive, once after load, import filter
FORCED = 0x10, // combined, also if cell isn't visible NORMAL = 0x10, // exclusive
ONREFMOVE = 0x20, // combined, if reference was moved FORCED = 0x20, // combined, also if cell isn't visible, for macros with side effects
EMask = NORMAL | ALWAYS | ONLOAD | ONLOAD_ONCE // mask of exclusive bits ONREFMOVE = 0x40, // combined, if reference was moved
EMask = ALWAYS | ONLOAD_MUST | ONLOAD_LENIENT | ONLOAD_ONCE | NORMAL // mask of exclusive bits
}; };
// If new bits are to be defined, AddRecalcMode has to be adjusted!
namespace o3tl namespace o3tl
{ {
template<> struct typed_flags<ScRecalcMode> : is_typed_flags<ScRecalcMode, 0x3f> {}; template<> struct typed_flags<ScRecalcMode> : is_typed_flags<ScRecalcMode, 0x7f> {};
} }
namespace formula namespace formula
@@ -281,16 +283,6 @@ public:
*/ */
sal_uInt16 RemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount ); sal_uInt16 RemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount );
void SetCombinedBitsRecalcMode( ScRecalcMode nBits )
{ nMode |= (nBits & ~ScRecalcMode::EMask); }
ScRecalcMode GetCombinedBitsRecalcMode() const
{ return nMode & ~ScRecalcMode::EMask; }
/** Exclusive bits already set in nMode are
zero'ed, nBits may contain combined bits, but
only one exclusive bit may be set! */
void SetMaskedRecalcMode( ScRecalcMode nBits )
{ nMode = GetCombinedBitsRecalcMode() | nBits; }
FormulaTokenArray(); FormulaTokenArray();
/** Assignment with incrementing references of FormulaToken entries /** Assignment with incrementing references of FormulaToken entries
(not copied!) */ (not copied!) */
@@ -390,9 +382,21 @@ public:
bool IsHyperLink() const { return bHyperLink; } bool IsHyperLink() const { return bHyperLink; }
ScRecalcMode GetRecalcMode() const { return nMode; } ScRecalcMode GetRecalcMode() const { return nMode; }
/** Bits aren't set directly but validated and
maybe handled according to priority if more void SetCombinedBitsRecalcMode( ScRecalcMode nBits )
than one exclusive bit was set. */ { nMode |= (nBits & ~ScRecalcMode::EMask); }
ScRecalcMode GetCombinedBitsRecalcMode() const
{ return nMode & ~ScRecalcMode::EMask; }
/** Exclusive bits already set in nMode are zero'ed, nBits
may contain combined bits, but only one exclusive bit
may be set! */
void SetMaskedRecalcMode( ScRecalcMode nBits )
{ nMode = GetCombinedBitsRecalcMode() | nBits; }
/** Bits aren't set directly but validated and handled
according to priority if more than one exclusive bit
was set. */
void AddRecalcMode( ScRecalcMode nBits ); void AddRecalcMode( ScRecalcMode nBits );
void ClearRecalcMode() { nMode = ScRecalcMode::NORMAL; } void ClearRecalcMode() { nMode = ScRecalcMode::NORMAL; }
@@ -400,10 +404,6 @@ public:
{ SetMaskedRecalcMode( ScRecalcMode::NORMAL ); } { SetMaskedRecalcMode( ScRecalcMode::NORMAL ); }
void SetExclusiveRecalcModeAlways() void SetExclusiveRecalcModeAlways()
{ SetMaskedRecalcMode( ScRecalcMode::ALWAYS ); } { SetMaskedRecalcMode( ScRecalcMode::ALWAYS ); }
void SetExclusiveRecalcModeOnLoad()
{ SetMaskedRecalcMode( ScRecalcMode::ONLOAD ); }
void SetExclusiveRecalcModeOnLoadOnce()
{ SetMaskedRecalcMode( ScRecalcMode::ONLOAD_ONCE ); }
void SetRecalcModeForced() void SetRecalcModeForced()
{ nMode |= ScRecalcMode::FORCED; } { nMode |= ScRecalcMode::FORCED; }
void SetRecalcModeOnRefMove() void SetRecalcModeOnRefMove()
@@ -412,10 +412,6 @@ public:
{ return bool(nMode & ScRecalcMode::NORMAL); } { return bool(nMode & ScRecalcMode::NORMAL); }
bool IsRecalcModeAlways() const bool IsRecalcModeAlways() const
{ return bool(nMode & ScRecalcMode::ALWAYS); } { return bool(nMode & ScRecalcMode::ALWAYS); }
bool IsRecalcModeOnLoad() const
{ return bool(nMode & ScRecalcMode::ONLOAD); }
bool IsRecalcModeOnLoadOnce() const
{ return bool(nMode & ScRecalcMode::ONLOAD_ONCE); }
bool IsRecalcModeForced() const bool IsRecalcModeForced() const
{ return bool(nMode & ScRecalcMode::FORCED); } { return bool(nMode & ScRecalcMode::FORCED); }
bool IsRecalcModeOnRefMove() const bool IsRecalcModeOnRefMove() const

View File

@@ -1371,8 +1371,7 @@ void ScFormulaCell::CompileXML( sc::CompileFormulaContext& rCxt, ScProgress& rPr
pDocument->CheckLinkFormulaNeedingCheck(*pCode); pDocument->CheckLinkFormulaNeedingCheck(*pCode);
//volatile cells must be added here for import //volatile cells must be added here for import
if( pCode->IsRecalcModeAlways() || pCode->IsRecalcModeForced() || if( !pCode->IsRecalcModeNormal() || pCode->IsRecalcModeForced())
pCode->IsRecalcModeOnLoad() || pCode->IsRecalcModeOnLoadOnce() )
{ {
// During load, only those cells that are marked explicitly dirty get // During load, only those cells that are marked explicitly dirty get
// recalculated. So we need to set it dirty here. // recalculated. So we need to set it dirty here.

View File

@@ -2744,9 +2744,7 @@ void ScInterpreter::ScDde()
} }
// Need to reinterpret after loading (build links) // Need to reinterpret after loading (build links)
rArr.AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT );
if ( rArr.IsRecalcModeNormal() )
rArr.SetExclusiveRecalcModeOnLoad();
// while the link is not evaluated, idle must be disabled (to avoid circular references) // while the link is not evaluated, idle must be disabled (to avoid circular references)

View File

@@ -2645,8 +2645,7 @@ void ScInterpreter::ScExternal()
else else
{ {
// enable asyncs after loading // enable asyncs after loading
if ( rArr.IsRecalcModeNormal() ) rArr.AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT );
rArr.SetExclusiveRecalcModeOnLoad();
// assure identical handler with identical call? // assure identical handler with identical call?
double nErg = 0.0; double nErg = 0.0;
ppParam[0] = &nErg; ppParam[0] = &nErg;
@@ -3006,10 +3005,7 @@ void ScInterpreter::ScExternal()
if ( aCall.HasVarRes() ) // handle async functions if ( aCall.HasVarRes() ) // handle async functions
{ {
if ( rArr.IsRecalcModeNormal() ) rArr.AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT );
{
rArr.SetExclusiveRecalcModeOnLoad();
}
uno::Reference<sheet::XVolatileResult> xRes = aCall.GetVarRes(); uno::Reference<sheet::XVolatileResult> xRes = aCall.GetVarRes();
ScAddInListener* pLis = ScAddInListener::Get( xRes ); ScAddInListener* pLis = ScAddInListener::Get( xRes );
if ( !pLis ) if ( !pLis )

View File

@@ -310,8 +310,7 @@ void ScInterpreter::ScWebservice()
} }
// Need to reinterpret after loading (build links) // Need to reinterpret after loading (build links)
if (rArr.IsRecalcModeNormal()) rArr.AddRecalcMode( ScRecalcMode::ONLOAD_LENIENT );
rArr.SetExclusiveRecalcModeOnLoad();
// while the link is not evaluated, idle must be disabled (to avoid circular references) // while the link is not evaluated, idle must be disabled (to avoid circular references)
bool bOldEnabled = pDok->IsIdleEnabled(); bool bOldEnabled = pDok->IsIdleEnabled();