From 1706760769018662a50b494b2e4a0ca85c93ca42 Mon Sep 17 00:00:00 2001 From: Winfried Donkers Date: Fri, 8 Aug 2014 17:39:04 +0200 Subject: fdo#81596 export to OOXML that need argument changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://gerrit.libreoffice.org/10831 Reviewed-by: Eike Rathke Tested-by: Eike Rathke (cherry picked from commit 4feaf96f50fa89eccb4e7a638220099e9a8482f1) sensible indenting, fdo#81596 related (cherry picked from commit 3dd241c52d6db424bd4696ff8f223976542e411b) simplify RewriteMissing() and switch in Add...(), fdo#81596 related (cherry picked from commit 14aabee5a73e57e26b2062b1ebf00c3f1dff1250) write TRUE() for 2nd IF() parameter, fdo#81596 related (cherry picked from commit 8f031861f590ba914321816657a003375d93ef5d) f7eb11a950b45793d04837d02f9546a93673fa2f f2ca37e1fda87ce56282fc2d2fc57a0784851139 52d0b43b19e10bee82109b635b3b7ce4f43650a3 Change-Id: I3a99e416be9f3f04175939e4560f8f7c55497185 Reviewed-on: https://gerrit.libreoffice.org/14388 Reviewed-by: Eike Rathke Tested-by: Eike Rathke Reviewed-by: Caolán McNamara Tested-by: Caolán McNamara --- formula/source/core/api/FormulaCompiler.cxx | 13 +- formula/source/core/api/token.cxx | 343 ++++++++++++++++++++-------- include/formula/tokenarray.hxx | 47 +++- 3 files changed, 299 insertions(+), 104 deletions(-) diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx index 5b2e8ea35e26..5cb40fc6bb21 100644 --- a/formula/source/core/api/FormulaCompiler.cxx +++ b/formula/source/core/api/FormulaCompiler.cxx @@ -1742,9 +1742,16 @@ void FormulaCompiler::CreateStringFromTokenArray( OUStringBuffer& rBuffer ) if (bODFF || FormulaGrammar::isPODF( meGrammar) ) { // Scan token array for missing args and re-write if present. - MissingConvention aConv( bODFF); - if (pArr->NeedsPofRewrite( aConv)) - pArr = pArr->RewriteMissingToPof( aConv); + MissingConventionODF aConv( bODFF); + if (pArr->NeedsPodfRewrite( aConv)) + pArr = pArr->RewriteMissing( aConv ); + } + else if ( FormulaGrammar::isOOXML( meGrammar ) ) + { + // Scan token array for missing args and rewrite if present. + MissingConventionOOXML aConv; + if (pArr->NeedsOoxmlRewrite( aConv)) + pArr = pArr->RewriteMissing( aConv ); } // At least one character per token, plus some are references, some are diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx index 92486dca19d4..a414a4b12cb9 100644 --- a/formula/source/core/api/token.cxx +++ b/formula/source/core/api/token.cxx @@ -995,11 +995,9 @@ bool FormulaTokenArray::HasMatrixDoubleRefOps() return false; } +// --- Formula rewrite of a token array - -// --- POF (plain old formula) rewrite of a token array --------------------- - -inline bool MissingConvention::isRewriteNeeded( OpCode eOp ) const +inline bool MissingConventionODF::isRewriteNeeded( OpCode eOp ) const { switch (eOp) { @@ -1011,7 +1009,62 @@ inline bool MissingConvention::isRewriteNeeded( OpCode eOp ) const return true; case ocMissing: case ocLog: - return !isODFF(); // rewrite only for PODF + return isPODF(); // rewrite only for PODF + default: + return false; + } +} + +/* + * fdo 81596 +Test status ( . : in progress , v : tested , - not applicable ) +finished: +- ocCosecant: // for OOXML not rewritten anymore +- ocSecant: // for OOXML not rewritten anymore +- ocCot: // for OOXML not rewritten anymore +- ocCosecantHyp: // for OOXML not rewritten anymore +- ocSecantHyp: // for OOXML not rewritten anymore +- ocCotHyp: // for OOXML not rewritten anymore +- ocArcCot: // for OOXML not rewritten anymore +- ocArcCotHyp: // ACOTH(x), not needed for Excel2013 and later +- ocChose: // CHOOSE() - no rewrite needed, it seems +v ocEuroConvert: +v ocIf: +v ocRound: +v ocRoundUp: +v ocRoundDown: +v ocGammaDist: +v ocPoissonDist: +v ocNormDist: +v ocLogNormDist: + +To be implemented yet: + ocExternal: ? + ocMacro: ? + ocIndex: INDEX() ? + ocFDist: // later, fdo40835 +*/ +inline bool MissingConventionOOXML::isRewriteNeeded( OpCode eOp ) const +{ + switch (eOp) + { + case ocIf: + + case ocExternal: + case ocEuroConvert: + case ocMacro: + + case ocRound: + case ocRoundUp: + case ocRoundDown: + + case ocIndex: + + case ocGammaDist: + case ocPoissonDist: + case ocNormDist: + case ocLogNormDist: + return true; default: return false; } @@ -1035,51 +1088,129 @@ void FormulaMissingContext::AddMoreArgs( FormulaTokenArray *pNewArr, const Missi if ( !mpFunc ) return; - switch (mpFunc->GetOpCode()) + switch (rConv.getConvention()) { - case ocGammaDist: - if (mnCurArg == 2) - { - pNewArr->AddOpCode( ocSep ); - pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true() - } - break; - case ocPoissonDist: - if (mnCurArg == 1) - { - pNewArr->AddOpCode( ocSep ); - pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true() - } - break; - case ocNormDist: - if ( mnCurArg == 2 ) - { - pNewArr->AddOpCode( ocSep ); - pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true() - } - break; - case ocLogNormDist: - if ( mnCurArg == 0 ) - { - pNewArr->AddOpCode( ocSep ); - pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0 - } - if ( mnCurArg <= 1 ) + case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF: + case MissingConvention::FORMULA_MISSING_CONVENTION_PODF: { - pNewArr->AddOpCode( ocSep ); - pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0 + switch (mpFunc->GetOpCode()) + { + case ocGammaDist: + if (mnCurArg == 2) + { + pNewArr->AddOpCode( ocSep ); + pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true() + } + break; + case ocPoissonDist: + if (mnCurArg == 1) + { + pNewArr->AddOpCode( ocSep ); + pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true() + } + break; + case ocNormDist: + if ( mnCurArg == 2 ) + { + pNewArr->AddOpCode( ocSep ); + pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true() + } + break; + case ocLogNormDist: + if ( mnCurArg == 0 ) + { + pNewArr->AddOpCode( ocSep ); + pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0 + } + if ( mnCurArg <= 1 ) + { + pNewArr->AddOpCode( ocSep ); + pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0 + } + break; + case ocLog: + if ( rConv.isPODF() && mnCurArg == 0 ) + { + pNewArr->AddOpCode( ocSep ); + pNewArr->AddDouble( 10.0 ); // 2nd, basis 10 + } + break; + default: + break; + } } break; - case ocLog: - if ( !rConv.isODFF() && mnCurArg == 0 ) + case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML: { - pNewArr->AddOpCode( ocSep ); - pNewArr->AddDouble( 10.0 ); // 2nd, basis 10 + switch (mpFunc->GetOpCode()) + { + case ocIf: + if( mnCurArg == 0 ) + { + // Excel needs at least two parameters in IF function + pNewArr->AddOpCode( ocSep ); + pNewArr->AddOpCode( ocTrue ); // 2nd, true() as function + pNewArr->AddOpCode( ocOpen ); // so the result is of logical type + pNewArr->AddOpCode( ocClose ); // and survives roundtrip + } + break; + + case ocEuroConvert: + if ( mnCurArg == 2 ) + { + pNewArr->AddOpCode( ocSep ); + pNewArr->AddDouble( 0.0 ); // 4th, FullPrecision = false() + } + break; + + case ocPoissonDist: + if (mnCurArg == 1) + { + pNewArr->AddOpCode( ocSep ); + pNewArr->AddDouble( 1.0 ); // 3rd, Cumulative=true() + } + break; + + case ocGammaDist: + case ocNormDist: + if (mnCurArg == 2) + { + pNewArr->AddOpCode( ocSep ); + pNewArr->AddDouble( 1.0 ); // 4th, Cumulative=true() + } + break; + + case ocLogNormDist: + if ( mnCurArg == 0 ) + { + pNewArr->AddOpCode( ocSep ); + pNewArr->AddDouble( 0.0 ); // 2nd, mean = 0.0 + } + if ( mnCurArg <= 1 ) + { + pNewArr->AddOpCode( ocSep ); + pNewArr->AddDouble( 1.0 ); // 3rd, standard deviation = 1.0 + } + break; + + case ocRound: + case ocRoundUp: + case ocRoundDown: + if( mnCurArg == 0 ) + { + // ROUND, ROUNDUP, ROUNDDOWN functions are fixed to 2 parameters in Excel + pNewArr->AddOpCode( ocSep ); + pNewArr->AddDouble( 0.0 ); // 2nd, 0.0 + } + break; + + default: + break; + } } break; - default: - break; } + } inline bool FormulaMissingContext::AddDefaultArg( FormulaTokenArray* pNewArr, int nArg, double f ) const @@ -1124,61 +1255,87 @@ bool FormulaMissingContext::AddMissing( FormulaTokenArray *pNewArr, const Missin bool bRet = false; const OpCode eOp = mpFunc->GetOpCode(); - // Add for both, PODF and ODFF - switch (eOp) + switch (rConv.getConvention()) { - case ocAddress: - return AddDefaultArg( pNewArr, 2, 1.0 ); // abs - default: + case MissingConvention::FORMULA_MISSING_CONVENTION_ODFF: + { + // Add for ODFF + switch (eOp) + { + case ocAddress: + return AddDefaultArg( pNewArr, 2, 1.0 ); // abs + default: + break; + } + } + break; + case MissingConvention::FORMULA_MISSING_CONVENTION_PODF: + { + // Add for PODF + switch (eOp) + { + case ocAddress: + return AddDefaultArg( pNewArr, 2, 1.0 ); // abs + case ocFixed: + return AddDefaultArg( pNewArr, 1, 2.0 ); + case ocBetaDist: + case ocBetaInv: + case ocRMZ: // PMT + return AddDefaultArg( pNewArr, 3, 0.0 ); + case ocZinsZ: // IPMT + case ocKapz: // PPMT + return AddDefaultArg( pNewArr, 4, 0.0 ); + case ocBW: // PV + case ocZW: // FV + bRet |= AddDefaultArg( pNewArr, 2, 0.0 ); // pmt + bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // [fp]v + break; + case ocZins: // RATE + bRet |= AddDefaultArg( pNewArr, 1, 0.0 ); // pmt + bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // fv + bRet |= AddDefaultArg( pNewArr, 4, 0.0 ); // type + break; + case ocExternal: + return AddMissingExternal( pNewArr ); + + // --- more complex cases --- + + case ocOffset: + // FIXME: rather tough. + // if arg 3 (height) omitted, export arg1 (rows) + break; + default: + break; + } + } + break; + case MissingConvention::FORMULA_MISSING_CONVENTION_OOXML: + { + switch (eOp) + { + case ocExternal: + return AddMissingExternal( pNewArr ); + default: + break; + } + } break; } - if (rConv.isODFF()) - { - // Add for ODFF - } - else - { - // Add for PODF - switch (eOp) - { - case ocFixed: - return AddDefaultArg( pNewArr, 1, 2.0 ); - case ocBetaDist: - case ocBetaInv: - case ocRMZ: // PMT - return AddDefaultArg( pNewArr, 3, 0.0 ); - case ocZinsZ: // IPMT - case ocKapz: // PPMT - return AddDefaultArg( pNewArr, 4, 0.0 ); - case ocBW: // PV - case ocZW: // FV - bRet |= AddDefaultArg( pNewArr, 2, 0.0 ); // pmt - bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // [fp]v - break; - case ocZins: // RATE - bRet |= AddDefaultArg( pNewArr, 1, 0.0 ); // pmt - bRet |= AddDefaultArg( pNewArr, 3, 0.0 ); // fv - bRet |= AddDefaultArg( pNewArr, 4, 0.0 ); // type - break; - case ocExternal: - return AddMissingExternal( pNewArr ); - - // --- more complex cases --- + return bRet; +} - case ocOffset: - // FIXME: rather tough. - // if arg 3 (height) omitted, export arg1 (rows) - break; - default: - break; - } +bool FormulaTokenArray::NeedsPodfRewrite( const MissingConventionODF & rConv ) +{ + for ( FormulaToken *pCur = First(); pCur; pCur = Next() ) + { + if ( rConv.isRewriteNeeded( pCur->GetOpCode())) + return true; } - - return bRet; + return false; } -bool FormulaTokenArray::NeedsPofRewrite( const MissingConvention & rConv ) +bool FormulaTokenArray::NeedsOoxmlRewrite( const MissingConventionOOXML & rConv ) { for ( FormulaToken *pCur = First(); pCur; pCur = Next() ) { @@ -1189,7 +1346,7 @@ bool FormulaTokenArray::NeedsPofRewrite( const MissingConvention & rConv ) } -FormulaTokenArray * FormulaTokenArray::RewriteMissingToPof( const MissingConvention & rConv ) +FormulaTokenArray * FormulaTokenArray::RewriteMissing( const MissingConvention & rConv ) { const size_t nAlloc = 256; FormulaMissingContext aCtx[ nAlloc ]; @@ -1232,12 +1389,12 @@ FormulaTokenArray * FormulaTokenArray::RewriteMissingToPof( const MissingConvent ++nFn; // all following operations on _that_ function pCtx[ nFn ].mpFunc = PeekPrevNoSpaces(); pCtx[ nFn ].mnCurArg = 0; - if (pCtx[ nFn ].mpFunc && pCtx[ nFn ].mpFunc->GetOpCode() == ocAddress && !rConv.isODFF()) + if (rConv.isPODF() && pCtx[ nFn ].mpFunc && pCtx[ nFn ].mpFunc->GetOpCode() == ocAddress) pOcas[ nOcas++ ] = nFn; // entering ADDRESS() if PODF break; case ocClose: pCtx[ nFn ].AddMoreArgs( pNewArr, rConv ); - DBG_ASSERT( nFn > 0, "FormulaTokenArray::RewriteMissingToPof: underflow"); + DBG_ASSERT( nFn > 0, "FormulaTokenArray::RewriteMissing: underflow"); if (nOcas > 0 && pOcas[ nOcas-1 ] == nFn) --nOcas; // leaving ADDRESS() if (nFn > 0) @@ -1252,7 +1409,7 @@ FormulaTokenArray * FormulaTokenArray::RewriteMissingToPof( const MissingConvent } break; case ocMissing: - if (bAdd) + if ( bAdd ) bAdd = !pCtx[ nFn ].AddMissing( pNewArr, rConv ); break; default: diff --git a/include/formula/tokenarray.hxx b/include/formula/tokenarray.hxx index c6433aa43b07..ceb84253f246 100644 --- a/include/formula/tokenarray.hxx +++ b/include/formula/tokenarray.hxx @@ -55,12 +55,39 @@ class FormulaMissingContext; class FORMULA_DLLPUBLIC MissingConvention { - bool mbODFF; /// TRUE: ODFF, FALSE: PODF public: - explicit MissingConvention( bool bODFF ) : mbODFF(bODFF) {} + enum Convention + { + FORMULA_MISSING_CONVENTION_PODF, + FORMULA_MISSING_CONVENTION_ODFF, + FORMULA_MISSING_CONVENTION_OOXML + }; + explicit MissingConvention( Convention eConvention ) : meConvention(eConvention) {} + inline bool isPODF() const { return meConvention == FORMULA_MISSING_CONVENTION_PODF; } + inline Convention getConvention() const { return meConvention; } +private: + Convention meConvention; +}; + +class FORMULA_DLLPUBLIC MissingConventionODF : public MissingConvention +{ +public: + explicit MissingConventionODF( bool bODFF ) : + MissingConvention( bODFF ? + MissingConvention::FORMULA_MISSING_CONVENTION_ODFF : + MissingConvention::FORMULA_MISSING_CONVENTION_PODF) + { + } + // Implementation and usage only in token.cxx + inline bool isRewriteNeeded( OpCode eOp ) const; +}; + +class FORMULA_DLLPUBLIC MissingConventionOOXML : public MissingConvention +{ +public: + explicit MissingConventionOOXML() : MissingConvention( MissingConvention::FORMULA_MISSING_CONVENTION_OOXML) {} // Implementation and usage only in token.cxx inline bool isRewriteNeeded( OpCode eOp ) const; - inline bool isODFF() const { return mbODFF; } }; class FORMULA_DLLPUBLIC FormulaTokenArray @@ -238,15 +265,19 @@ public: FormulaTokenArray& operator=( const FormulaTokenArray& ); /** Determines if this formula needs any changes to convert it to something - previous versions of OOo could consume (Plain Old Formula). */ - bool NeedsPofRewrite(const MissingConvention & rConv); + previous versions of OOo could consume (Plain Old Formula, pre-ODFF, or + also ODFF) */ + bool NeedsPodfRewrite( const MissingConventionODF & rConv ); + + /** Determines if this formula needs any changes to convert it to OOXML. */ + bool NeedsOoxmlRewrite( const MissingConventionOOXML & rConv ); - /** Rewrites to Plain Old Formula, substituting missing parameters. The + /** Rewrites to Plain Old Formula or OOXML, substituting missing parameters. The FormulaTokenArray* returned is new'ed. */ - FormulaTokenArray* RewriteMissingToPof(const MissingConvention & rConv); + FormulaTokenArray* RewriteMissing( const MissingConvention & rConv ); /** Determines if this formula may be followed by a reference. */ - bool MayReferenceFollow(); + bool MayReferenceFollow(); }; inline OpCode FormulaTokenArray::GetOuterFuncOpCode() -- cgit