diff options
39 files changed, 1298 insertions, 690 deletions
diff --git a/sc/inc/cellsuno.hxx b/sc/inc/cellsuno.hxx index e73869489ebc..2dd0bd6cc16e 100644 --- a/sc/inc/cellsuno.hxx +++ b/sc/inc/cellsuno.hxx @@ -629,9 +629,10 @@ protected: throw(::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); - void SetArrayFormula_Impl( const rtl::OUString& aFormula, - const formula::FormulaGrammar::Grammar eGrammar ) - throw(::com::sun::star::uno::RuntimeException); + void SetArrayFormula_Impl( const rtl::OUString& rFormula, + const rtl::OUString& rFormulaNmsp, + const formula::FormulaGrammar::Grammar eGrammar ) + throw(::com::sun::star::uno::RuntimeException); public: ScCellRangeObj(ScDocShell* pDocSh, const ScRange& rR); @@ -650,7 +651,8 @@ public: virtual void RefChanged(); // via getImplementation() - virtual void SetArrayFormulaWithGrammar( const ::rtl::OUString& aFormula, + virtual void SetArrayFormulaWithGrammar( const ::rtl::OUString& rFormula, + const ::rtl::OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar ) throw(::com::sun::star::uno::RuntimeException); @@ -869,7 +871,7 @@ public: void SetFormulaResultString( const ::rtl::OUString& rResult ); void SetFormulaResultDouble( double fResult ); void SetFormulaWithGrammar( const ::rtl::OUString& rFormula, - const formula::FormulaGrammar::Grammar ); + const ::rtl::OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar ); const ScAddress& GetPosition() const { return aCellPos; } // XText diff --git a/sc/inc/compiler.hxx b/sc/inc/compiler.hxx index 9f245322fdb7..058b3b30f30a 100644 --- a/sc/inc/compiler.hxx +++ b/sc/inc/compiler.hxx @@ -354,9 +354,9 @@ public: const formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_OOO ); static BOOL EnQuote( String& rStr ); - sal_Unicode GetNativeAddressSymbol( Convention::SpecialSymbolType eType ) const; + // Check if it is a valid english function name bool IsEnglishSymbol( const String& rName ); @@ -396,6 +396,8 @@ public: maExternalLinks = rLinks; } + void CreateStringFromXMLTokenArray( String& rFormula, String& rFormulaNmsp ); + void SetExtendedErrorDetection( bool bVal ) { mbExtendedErrorDetection = bVal; } BOOL IsCorrected() { return bCorrected; } @@ -403,6 +405,7 @@ public: // Use convention from this->aPos by default ScTokenArray* CompileString( const String& rFormula ); + ScTokenArray* CompileString( const String& rFormula, const String& rFormulaNmsp ); const ScDocument* GetDoc() const { return pDoc; } const ScAddress& GetPos() const { return aPos; } diff --git a/sc/inc/conditio.hxx b/sc/inc/conditio.hxx index 42a030b8e809..edb0f9371788 100644 --- a/sc/inc/conditio.hxx +++ b/sc/inc/conditio.hxx @@ -84,7 +84,10 @@ class SC_DLLPUBLIC ScConditionEntry double nVal2; String aStrVal1; // eingegeben oder berechnet String aStrVal2; - formula::FormulaGrammar::Grammar eTempGrammar; // grammar to be used on (re)compilation, e.g. in XML import + String aStrNmsp1; // namespace to be used on (re)compilation, e.g. in XML import + String aStrNmsp2; // namespace to be used on (re)compilation, e.g. in XML import + formula::FormulaGrammar::Grammar eTempGrammar1; // grammar to be used on (re)compilation, e.g. in XML import + formula::FormulaGrammar::Grammar eTempGrammar2; // grammar to be used on (re)compilation, e.g. in XML import BOOL bIsStr1; // um auch leere Strings zu erkennen BOOL bIsStr2; ScTokenArray* pFormula1; // eingegebene Formel @@ -101,7 +104,10 @@ class SC_DLLPUBLIC ScConditionEntry void MakeCells( const ScAddress& rPos ); void Compile( const String& rExpr1, const String& rExpr2, - const formula::FormulaGrammar::Grammar eGrammar, BOOL bTextToReal ); + const String& rExprNmsp1, const String& rExprNmsp2, + formula::FormulaGrammar::Grammar eGrammar1, + formula::FormulaGrammar::Grammar eGrammar2, + BOOL bTextToReal ); void Interpret( const ScAddress& rPos ); BOOL IsValid( double nArg ) const; @@ -111,7 +117,9 @@ public: ScConditionEntry( ScConditionMode eOper, const String& rExpr1, const String& rExpr2, ScDocument* pDocument, const ScAddress& rPos, - const formula::FormulaGrammar::Grammar eGrammar ); + const String& rExprNmsp1, const String& rExprNmsp2, + formula::FormulaGrammar::Grammar eGrammar1, + formula::FormulaGrammar::Grammar eGrammar2 ); ScConditionEntry( ScConditionMode eOper, const ScTokenArray* pArr1, const ScTokenArray* pArr2, ScDocument* pDocument, const ScAddress& rPos ); @@ -174,7 +182,10 @@ public: const String& rExpr1, const String& rExpr2, ScDocument* pDocument, const ScAddress& rPos, const String& rStyle, - const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT ); + const String& rExprNmsp1 = EMPTY_STRING, + const String& rExprNmsp2 = EMPTY_STRING, + formula::FormulaGrammar::Grammar eGrammar1 = formula::FormulaGrammar::GRAM_DEFAULT, + formula::FormulaGrammar::Grammar eGrammar2 = formula::FormulaGrammar::GRAM_DEFAULT ); ScCondFormatEntry( ScConditionMode eOper, const ScTokenArray* pArr1, const ScTokenArray* pArr2, ScDocument* pDocument, const ScAddress& rPos, diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 17c3234a7723..c8d3751a7aaf 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -139,6 +139,7 @@ class ScTemporaryChartLock; class ScLookupCache; struct ScLookupCacheMapImpl; class SfxUndoManager; +class ScFormulaParserPool; namespace com { namespace sun { namespace star { namespace lang { @@ -291,6 +292,11 @@ private: ::std::auto_ptr<ScDocProtection> pDocProtection; ::std::auto_ptr<ScExternalRefManager> pExternalRefMgr; + + // mutable for lazy construction + mutable ::std::auto_ptr< ScFormulaParserPool > + mxFormulaParserPool; /// Pool for all external formula parsers used by this document. + String aDocName; // opt: Dokumentname ScRangePairListRef xColNameRanges; ScRangePairListRef xRowNameRanges; @@ -619,6 +625,10 @@ public: void MarkUsedExternalReferences(); bool MarkUsedExternalReferences( ScTokenArray & rArr ); + /** Returns the pool containing external formula parsers. Creates the pool + on first call. */ + ScFormulaParserPool& GetFormulaParserPool() const; + BOOL HasDdeLinks() const; BOOL HasAreaLinks() const; void UpdateExternalRefLinks(); diff --git a/sc/inc/fmtuno.hxx b/sc/inc/fmtuno.hxx index ba4e02041faa..6005a849fb0f 100644 --- a/sc/inc/fmtuno.hxx +++ b/sc/inc/fmtuno.hxx @@ -32,7 +32,8 @@ #define SC_FMTUNO_HXX #include "address.hxx" -#include "formula/grammar.hxx" +#include "conditio.hxx" +#include <formula/grammar.hxx> #include <tools/list.hxx> #include <svtools/itemprop.hxx> #include <com/sun/star/sheet/XSheetConditionalEntries.hpp> @@ -61,16 +62,19 @@ struct ScCondFormatEntryItem { ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaToken > maTokens1; ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaToken > maTokens2; - String maExpr1; - String maExpr2; - String maPosStr; // formula position as text - String maStyle; // display name as stored in ScStyleSheet - ScAddress maPos; - formula::FormulaGrammar::Grammar meGrammar; // grammar used with maExpr1 and maExpr2 - USHORT mnMode; // stores enum ScConditionMode + String maExpr1; + String maExpr2; + String maExprNmsp1; + String maExprNmsp2; + String maPosStr; // formula position as text + String maStyle; // display name as stored in ScStyleSheet + ScAddress maPos; + formula::FormulaGrammar::Grammar meGrammar1; // grammar used with maExpr1 + formula::FormulaGrammar::Grammar meGrammar2; // grammar used with maExpr2 + ScConditionMode meMode; // Make sure the grammar is initialized for API calls. - ScCondFormatEntryItem() : meGrammar( formula::FormulaGrammar::GRAM_UNSPECIFIED ) {} + ScCondFormatEntryItem(); }; class ScTableConditionalFormat : public cppu::WeakImplHelper5< @@ -89,11 +93,11 @@ private: ScTableConditionalFormat(); // disable public: ScTableConditionalFormat(ScDocument* pDoc, ULONG nKey, - const formula::FormulaGrammar::Grammar eGrammar); + formula::FormulaGrammar::Grammar eGrammar); virtual ~ScTableConditionalFormat(); - void FillFormat( ScConditionalFormat& rFormat, - ScDocument* pDoc, formula::FormulaGrammar::Grammar eGrammar ) const; + void FillFormat( ScConditionalFormat& rFormat, ScDocument* pDoc, + formula::FormulaGrammar::Grammar eGrammar) const; void DataChanged(); // XSheetConditionalEntries @@ -211,7 +215,10 @@ private: USHORT nMode; // enum ScConditionMode String aExpr1; String aExpr2; - formula::FormulaGrammar::Grammar meGrammar; // grammar used with aExpr1 and aExpr2 + String maExprNmsp1; + String maExprNmsp2; + formula::FormulaGrammar::Grammar meGrammar1; // grammar used with aExpr1 and aExpr2 + formula::FormulaGrammar::Grammar meGrammar2; // grammar used with aExpr1 and aExpr2 ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaToken > aTokens1; ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaToken > aTokens2; ScAddress aSrcPos; diff --git a/sc/inc/formulaparserpool.hxx b/sc/inc/formulaparserpool.hxx new file mode 100644 index 000000000000..af6b0ed3ebf1 --- /dev/null +++ b/sc/inc/formulaparserpool.hxx @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: formulaparserpool.hxx,v $ + * $Revision: 1.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_FORMULAPARSERPOOL_HXX +#define SC_FORMULAPARSERPOOL_HXX + +#include <hash_map> +#include <com/sun/star/sheet/XFormulaParser.hpp> + +class ScDocument; + +// ============================================================================ + +/** Stores the used instances of the FilterFormulaParser service + implementations, mapped by the formula namespace they support. */ +class ScFormulaParserPool +{ +public: + explicit ScFormulaParserPool( const ScDocument& rDoc ); + ~ScFormulaParserPool(); + + /** Returns true, if a formula parser is registered for the passed namespace. */ + bool hasFormulaParser( const ::rtl::OUString& rNamespace ); + + /** Returns the formula parser that is registered for the passed namespace. */ + ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XFormulaParser > + getFormulaParser( const ::rtl::OUString& rNamespace ); + +private: + typedef ::std::hash_map< + ::rtl::OUString, + ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XFormulaParser >, + ::rtl::OUStringHash, + ::std::equal_to< ::rtl::OUString > > ParserMap; + + const ScDocument& mrDoc; + ParserMap maParsers; +}; + +// ============================================================================ + +#endif + diff --git a/sc/inc/tokenuno.hxx b/sc/inc/tokenuno.hxx index abb9d1d06a22..bcd3435668be 100644 --- a/sc/inc/tokenuno.hxx +++ b/sc/inc/tokenuno.hxx @@ -31,15 +31,14 @@ #ifndef SC_TOKENUNO_HXX #define SC_TOKENUNO_HXX -#include <svtools/lstner.hxx> -#include <com/sun/star/sheet/FormulaToken.hpp> #include <com/sun/star/uno/Sequence.hxx> #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/beans/XPropertySet.hpp> -#include <com/sun/star/sheet/XFormulaParser.hpp> -#include <com/sun/star/sheet/XFormulaOpCodeMapper.hpp> #include <com/sun/star/sheet/FormulaOpCodeMapEntry.hpp> +#include <com/sun/star/sheet/FormulaToken.hpp> +#include <com/sun/star/sheet/XFormulaParser.hpp> #include <cppuhelper/implbase3.hxx> +#include <svtools/lstner.hxx> #include <formula/FormulaOpCodeMapperObj.hxx> #include "address.hxx" #include "compiler.hxx" @@ -47,6 +46,7 @@ class ScTokenArray; class ScDocShell; +// ============================================================================ class ScTokenConversion { @@ -61,6 +61,7 @@ public: const ScTokenArray& rTokenArray ); }; +// ============================================================================ class ScFormulaParserObj : public ::cppu::WeakImplHelper3< ::com::sun::star::sheet::XFormulaParser, @@ -73,7 +74,6 @@ private: ::com::sun::star::uno::Sequence< const ::com::sun::star::sheet::ExternalLinkInfo > maExternalLinks; ScCompiler::OpCodeMapPtr mxOpCodeMap; ScDocShell* mpDocShell; - ScAddress maRefPos; sal_Int16 mnConv; bool mbEnglish; bool mbIgnoreSpaces; @@ -89,10 +89,12 @@ public: // XFormulaParser virtual ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaToken > SAL_CALL parseFormula( - const ::rtl::OUString& aFormula ) + const ::rtl::OUString& aFormula, + const ::com::sun::star::table::CellAddress& rReferencePos ) throw (::com::sun::star::uno::RuntimeException); virtual ::rtl::OUString SAL_CALL printFormula( const ::com::sun::star::uno::Sequence< - ::com::sun::star::sheet::FormulaToken >& aTokens ) + ::com::sun::star::sheet::FormulaToken >& aTokens, + const ::com::sun::star::table::CellAddress& rReferencePos ) throw (::com::sun::star::uno::RuntimeException); // XPropertySet @@ -145,11 +147,15 @@ public: throw(::com::sun::star::uno::RuntimeException); }; +// ============================================================================ + class ScFormulaOpCodeMapperObj : public formula::FormulaOpCodeMapperObj { public: ScFormulaOpCodeMapperObj(::std::auto_ptr<formula::FormulaCompiler> _pCompiler); }; +// ============================================================================ + #endif diff --git a/sc/inc/unonames.hxx b/sc/inc/unonames.hxx index 367e7d7cfe35..010e420feb42 100644 --- a/sc/inc/unonames.hxx +++ b/sc/inc/unonames.hxx @@ -318,7 +318,10 @@ #define SC_UNONAME_FORMULA2 "Formula2" #define SC_UNONAME_SOURCEPOS "SourcePosition" #define SC_UNONAME_SOURCESTR "SourcePositionAsString" // only for use in XML filter -#define SC_UNONAME_GRAMMAR "Grammar" // only for use in XML filter +#define SC_UNONAME_FORMULANMSP1 "FormulaNamespace1" // only for use in XML filter +#define SC_UNONAME_FORMULANMSP2 "FormulaNamespace2" // only for use in XML filter +#define SC_UNONAME_GRAMMAR1 "Grammar1" // only for use in XML filter +#define SC_UNONAME_GRAMMAR2 "Grammar2" // only for use in XML filter #define SC_UNONAME_STYLENAME "StyleName" // validation @@ -599,7 +602,6 @@ // <-- // FormulaParser -#define SC_UNO_REFERENCEPOS "ReferencePosition" #define SC_UNO_COMPILEENGLISH "CompileEnglish" #define SC_UNO_FORMULACONVENTION "FormulaConvention" #define SC_UNO_IGNORELEADING "IgnoreLeadingSpaces" diff --git a/sc/inc/validat.hxx b/sc/inc/validat.hxx index d3588c366a7c..cea9c154f04a 100644 --- a/sc/inc/validat.hxx +++ b/sc/inc/validat.hxx @@ -93,7 +93,9 @@ public: ScValidationData( ScValidationMode eMode, ScConditionMode eOper, const String& rExpr1, const String& rExpr2, ScDocument* pDocument, const ScAddress& rPos, - const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT ); + const String& rExprNmsp1 = EMPTY_STRING, const String& rExprNmsp2 = EMPTY_STRING, + formula::FormulaGrammar::Grammar eGrammar1 = formula::FormulaGrammar::GRAM_DEFAULT, + formula::FormulaGrammar::Grammar eGrammar2 = formula::FormulaGrammar::GRAM_DEFAULT ); ScValidationData( ScValidationMode eMode, ScConditionMode eOper, const ScTokenArray* pArr1, const ScTokenArray* pArr2, ScDocument* pDocument, const ScAddress& rPos ); diff --git a/sc/source/core/data/cell.cxx b/sc/source/core/data/cell.cxx index ea758e91da06..da2de0b68099 100644 --- a/sc/source/core/data/cell.cxx +++ b/sc/source/core/data/cell.cxx @@ -1016,15 +1016,15 @@ void ScFormulaCell::CompileXML( ScProgress& rProgress ) ScCompiler aComp( pDocument, aPos, *pCode); aComp.SetGrammar(eTempGrammar); - String aFormula; - aComp.CreateStringFromTokenArray( aFormula ); + String aFormula, aFormulaNmsp; + aComp.CreateStringFromXMLTokenArray( aFormula, aFormulaNmsp ); pDocument->DecXMLImportedFormulaCount( aFormula.Len() ); rProgress.SetStateCountDownOnPercent( pDocument->GetXMLImportedFormulaCount() ); // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein if ( pCode ) pCode->Clear(); ScTokenArray* pCodeOld = pCode; - pCode = aComp.CompileString( aFormula ); + pCode = aComp.CompileString( aFormula, aFormulaNmsp ); delete pCodeOld; if( !pCode->GetCodeError() ) { diff --git a/sc/source/core/data/conditio.cxx b/sc/source/core/data/conditio.cxx index 12dbf77e88e6..3c636d9049d4 100644 --- a/sc/source/core/data/conditio.cxx +++ b/sc/source/core/data/conditio.cxx @@ -130,7 +130,10 @@ ScConditionEntry::ScConditionEntry( const ScConditionEntry& r ) : nVal2(r.nVal2), aStrVal1(r.aStrVal1), aStrVal2(r.aStrVal2), - eTempGrammar(r.eTempGrammar), + aStrNmsp1(r.aStrNmsp1), + aStrNmsp2(r.aStrNmsp2), + eTempGrammar1(r.eTempGrammar1), + eTempGrammar2(r.eTempGrammar2), bIsStr1(r.bIsStr1), bIsStr2(r.bIsStr2), pFormula1(NULL), @@ -161,7 +164,10 @@ ScConditionEntry::ScConditionEntry( ScDocument* pDocument, const ScConditionEntr nVal2(r.nVal2), aStrVal1(r.aStrVal1), aStrVal2(r.aStrVal2), - eTempGrammar(r.eTempGrammar), + aStrNmsp1(r.aStrNmsp1), + aStrNmsp2(r.aStrNmsp2), + eTempGrammar1(r.eTempGrammar1), + eTempGrammar2(r.eTempGrammar2), bIsStr1(r.bIsStr1), bIsStr2(r.bIsStr2), pFormula1(NULL), @@ -187,14 +193,17 @@ ScConditionEntry::ScConditionEntry( ScDocument* pDocument, const ScConditionEntr } ScConditionEntry::ScConditionEntry( ScConditionMode eOper, - const String& rExpr1, const String& rExpr2, - ScDocument* pDocument, const ScAddress& rPos, - const FormulaGrammar::Grammar eGrammar ) : + const String& rExpr1, const String& rExpr2, ScDocument* pDocument, const ScAddress& rPos, + const String& rExprNmsp1, const String& rExprNmsp2, + FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2 ) : eOp(eOper), nOptions(0), // spaeter... nVal1(0.0), nVal2(0.0), - eTempGrammar(eGrammar), + aStrNmsp1(rExprNmsp1), + aStrNmsp2(rExprNmsp2), + eTempGrammar1(eGrammar1), + eTempGrammar2(eGrammar2), bIsStr1(FALSE), bIsStr2(FALSE), pFormula1(NULL), @@ -207,7 +216,7 @@ ScConditionEntry::ScConditionEntry( ScConditionMode eOper, bRelRef2(FALSE), bFirstRun(TRUE) { - Compile( rExpr1, rExpr2, eGrammar, FALSE ); + Compile( rExpr1, rExpr2, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2, FALSE ); // Formelzellen werden erst bei IsValid angelegt } @@ -219,7 +228,8 @@ ScConditionEntry::ScConditionEntry( ScConditionMode eOper, nOptions(0), // spaeter... nVal1(0.0), nVal2(0.0), - eTempGrammar(FormulaGrammar::GRAM_DEFAULT), + eTempGrammar1(FormulaGrammar::GRAM_DEFAULT), + eTempGrammar2(FormulaGrammar::GRAM_DEFAULT), bIsStr1(FALSE), bIsStr2(FALSE), pFormula1(NULL), @@ -294,15 +304,16 @@ ScConditionEntry::~ScConditionEntry() } void ScConditionEntry::Compile( const String& rExpr1, const String& rExpr2, - const FormulaGrammar::Grammar eGrammar, BOOL bTextToReal ) + const String& rExprNmsp1, const String& rExprNmsp2, + FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2, BOOL bTextToReal ) { if ( rExpr1.Len() || rExpr2.Len() ) { ScCompiler aComp( pDoc, aSrcPos ); - aComp.SetGrammar(eGrammar); if ( rExpr1.Len() ) { + aComp.SetGrammar( eGrammar1 ); if ( pDoc->IsImportingXML() && !bTextToReal ) { // temporary formula string as string tokens @@ -313,7 +324,7 @@ void ScConditionEntry::Compile( const String& rExpr1, const String& rExpr2, } else { - pFormula1 = aComp.CompileString( rExpr1 ); + pFormula1 = aComp.CompileString( rExpr1, rExprNmsp1 ); if ( pFormula1->GetLen() == 1 ) { // einzelne (konstante Zahl) ? @@ -339,6 +350,7 @@ void ScConditionEntry::Compile( const String& rExpr1, const String& rExpr2, if ( rExpr2.Len() ) { + aComp.SetGrammar( eGrammar2 ); if ( pDoc->IsImportingXML() && !bTextToReal ) { // temporary formula string as string tokens @@ -349,7 +361,7 @@ void ScConditionEntry::Compile( const String& rExpr1, const String& rExpr2, } else { - pFormula2 = aComp.CompileString( rExpr2 ); + pFormula2 = aComp.CompileString( rExpr2, rExprNmsp2 ); if ( pFormula2->GetLen() == 1 ) { // einzelne (konstante Zahl) ? @@ -429,9 +441,9 @@ void ScConditionEntry::CompileXML() // Convert the text tokens that were created during XML import into real tokens. - Compile( GetExpression(aSrcPos, 0, 0, eTempGrammar), - GetExpression(aSrcPos, 1, 0, eTempGrammar), - eTempGrammar, TRUE ); + Compile( GetExpression(aSrcPos, 0, 0, eTempGrammar1), + GetExpression(aSrcPos, 1, 0, eTempGrammar2), + aStrNmsp1, aStrNmsp2, eTempGrammar1, eTempGrammar2, TRUE ); } void ScConditionEntry::SetSrcString( const String& rNew ) @@ -1129,8 +1141,10 @@ ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper, const String& rExpr1, const String& rExpr2, ScDocument* pDocument, const ScAddress& rPos, const String& rStyle, - const FormulaGrammar::Grammar eGrammar ) : - ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, eGrammar ), + const String& rExprNmsp1, const String& rExprNmsp2, + FormulaGrammar::Grammar eGrammar1, + FormulaGrammar::Grammar eGrammar2 ) : + ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2 ), aStyleName( rStyle ), pParent( NULL ) { diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx index 120ecb20ade4..16613fbcbab4 100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -95,6 +95,7 @@ #include "lookupcache.hxx" #include "externalrefmgr.hxx" #include "tabprotection.hxx" +#include "formulaparserpool.hxx" // pImpl because including lookupcache.hxx in document.hxx isn't wanted, and // dtor plus helpers are convenient. @@ -154,7 +155,6 @@ ScDocument::ScDocument( ScDocumentMode eMode, pScriptTypeData( NULL ), pCacheFieldEditEngine( NULL ), pDocProtection( NULL ), - pExternalRefMgr( NULL ), pViewOptions( NULL ), pDocOptions( NULL ), pExtDocOptions( NULL ), @@ -384,15 +384,14 @@ ScDocument::~ScDocument() pLinkManager->Remove( 0, pLinkManager->GetLinks().Count() ); } - if (pExternalRefMgr.get()) - // Destroy the external ref mgr instance here because it has a timer - // which needs to be stopped before the app closes. - pExternalRefMgr.reset(NULL); + mxFormulaParserPool.reset(); + // Destroy the external ref mgr instance here because it has a timer + // which needs to be stopped before the app closes. + pExternalRefMgr.reset(); ScAddInAsync::RemoveDocument( this ); ScAddInListener::RemoveDocument( this ); - delete pChartListenerCollection; // vor pBASM wg. evtl. Listener! - pChartListenerCollection = NULL; + DELETEZ( pChartListenerCollection); // vor pBASM wg. evtl. Listener! DELETEZ( pLookupCacheMapImpl); // before pBASM because of listeners // BroadcastAreas vor allen Zellen zerstoeren um unnoetige // Einzel-EndListenings der Formelzellen zu vermeiden diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index b194ecc4aa73..08170fd6cdc9 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -40,6 +40,7 @@ #include <sfx2/bindings.hxx> #include <sfx2/objsh.hxx> #include <svtools/zforlist.hxx> +#include <svtools/PasswordHelper.hxx> #include <vcl/svapp.hxx> #include "document.hxx" #include "attrib.hxx" @@ -77,8 +78,8 @@ #include "drwlayer.hxx" #include "unoreflist.hxx" #include "listenercalls.hxx" -#include "svtools/PasswordHelper.hxx" #include "tabprotection.hxx" +#include "formulaparserpool.hxx" #include <memory> @@ -509,6 +510,13 @@ void ScDocument::MarkUsedExternalReferences() * collecting them during export. */ } +ScFormulaParserPool& ScDocument::GetFormulaParserPool() const +{ + if( !mxFormulaParserPool.get() ) + mxFormulaParserPool.reset( new ScFormulaParserPool( *this ) ); + return *mxFormulaParserPool; +} + ScOutlineTable* ScDocument::GetOutlineTable( SCTAB nTab, BOOL bCreate ) { ScOutlineTable* pVal = NULL; diff --git a/sc/source/core/data/validat.cxx b/sc/source/core/data/validat.cxx index 0a33ab111f50..9bb8bff1081f 100644 --- a/sc/source/core/data/validat.cxx +++ b/sc/source/core/data/validat.cxx @@ -76,8 +76,9 @@ SV_IMPL_OP_PTRARR_SORT( ScValidationEntries_Impl, ScValidationDataPtr ); ScValidationData::ScValidationData( ScValidationMode eMode, ScConditionMode eOper, const String& rExpr1, const String& rExpr2, ScDocument* pDocument, const ScAddress& rPos, - const formula::FormulaGrammar::Grammar eGrammar ) : - ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, eGrammar ), + const String& rExprNmsp1, const String& rExprNmsp2, + FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2 ) : + ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2 ), nKey( 0 ), eDataMode( eMode ), eErrorStyle( SC_VALERR_STOP ), diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index 0f0844392e76..2b66663f3ee9 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -68,11 +68,14 @@ #include "cell.hxx" #include "dociter.hxx" #include "docoptio.hxx" -#include "formula/errorcodes.hxx" +#include <formula/errorcodes.hxx> #include "parclass.hxx" #include "autonamecache.hxx" #include "externalrefmgr.hxx" #include "rangeutl.hxx" +#include "convuno.hxx" +#include "tokenuno.hxx" +#include "formulaparserpool.hxx" using namespace formula; using namespace ::com::sun::star; @@ -408,28 +411,36 @@ void ScCompiler::InitCharClassEnglish() void ScCompiler::SetGrammar( const FormulaGrammar::Grammar eGrammar ) { - DBG_ASSERT( eGrammar != FormulaGrammar::GRAM_UNSPECIFIED, "ScCompiler::SetGrammar: don't passFormulaGrammar::GRAM_UNSPECIFIED"); + DBG_ASSERT( eGrammar != FormulaGrammar::GRAM_UNSPECIFIED, "ScCompiler::SetGrammar: don't pass FormulaGrammar::GRAM_UNSPECIFIED"); if (eGrammar == GetGrammar()) return; // nothing to be done - FormulaGrammar::Grammar eMyGrammar = eGrammar; - const sal_Int32 nFormulaLanguage = FormulaGrammar::extractFormulaLanguage( eMyGrammar); - OpCodeMapPtr xMap( GetOpCodeMap( nFormulaLanguage)); - DBG_ASSERT( xMap, "ScCompiler::SetGrammar: unknown formula language"); - if (!xMap) + if( eGrammar == FormulaGrammar::GRAM_EXTERNAL ) { - xMap = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE); - eMyGrammar = xMap->getGrammar(); + meGrammar = eGrammar; + mxSymbols = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE); } + else + { + FormulaGrammar::Grammar eMyGrammar = eGrammar; + const sal_Int32 nFormulaLanguage = FormulaGrammar::extractFormulaLanguage( eMyGrammar); + OpCodeMapPtr xMap = GetOpCodeMap( nFormulaLanguage); + DBG_ASSERT( xMap, "ScCompiler::SetGrammar: unknown formula language"); + if (!xMap) + { + xMap = GetOpCodeMap( ::com::sun::star::sheet::FormulaLanguage::NATIVE); + eMyGrammar = xMap->getGrammar(); + } - // Save old grammar for call to SetGrammarAndRefConvention(). - FormulaGrammar::Grammar eOldGrammar = GetGrammar(); - // This also sets the grammar associated with the map! - SetFormulaLanguage( xMap); + // Save old grammar for call to SetGrammarAndRefConvention(). + FormulaGrammar::Grammar eOldGrammar = GetGrammar(); + // This also sets the grammar associated with the map! + SetFormulaLanguage( xMap); - // Override if necessary. - if (eMyGrammar != GetGrammar()) - SetGrammarAndRefConvention( eMyGrammar, eOldGrammar); + // Override if necessary. + if (eMyGrammar != GetGrammar()) + SetGrammarAndRefConvention( eMyGrammar, eOldGrammar); + } } @@ -3656,6 +3667,21 @@ BOOL ScCompiler::NextNewToken( bool bInArray ) return true; } +void ScCompiler::CreateStringFromXMLTokenArray( String& rFormula, String& rFormulaNmsp ) +{ + bool bExternal = GetGrammar() == FormulaGrammar::GRAM_EXTERNAL; + USHORT nExpectedCount = bExternal ? 2 : 1; + DBG_ASSERT( pArr->GetLen() == nExpectedCount, "ScCompiler::CreateStringFromXMLTokenArray - wrong number of tokens" ); + if( pArr->GetLen() == nExpectedCount ) + { + FormulaToken** ppTokens = pArr->GetArray(); + // string tokens expected, GetString() will assert if token type is wrong + rFormula = ppTokens[ 0 ]->GetString(); + if( bExternal ) + rFormulaNmsp = ppTokens[ 1 ]->GetString(); + } +} + ScTokenArray* ScCompiler::CompileString( const String& rFormula ) { #if 0 @@ -3663,6 +3689,10 @@ ScTokenArray* ScCompiler::CompileString( const String& rFormula ) rtl::OUStringToOString( rFormula, RTL_TEXTENCODING_UTF8 ).getStr() ); #endif + OSL_ENSURE( meGrammar != FormulaGrammar::GRAM_EXTERNAL, "ScCompiler::CompileString - unexpected grammar GRAM_EXTERNAL" ); + if( meGrammar == FormulaGrammar::GRAM_EXTERNAL ) + SetGrammar( FormulaGrammar::GRAM_PODF ); + ScTokenArray aArr; pArr = &aArr; aFormula = rFormula; @@ -3865,6 +3895,34 @@ ScTokenArray* ScCompiler::CompileString( const String& rFormula ) } +ScTokenArray* ScCompiler::CompileString( const String& rFormula, const String& rFormulaNmsp ) +{ + DBG_ASSERT( (GetGrammar() == FormulaGrammar::GRAM_EXTERNAL) || (rFormulaNmsp.Len() == 0), + "ScCompiler::CompileString - unexpected formula namespace for internal grammar" ); + if( GetGrammar() == FormulaGrammar::GRAM_EXTERNAL ) try + { + ScFormulaParserPool& rParserPool = pDoc->GetFormulaParserPool(); + uno::Reference< sheet::XFormulaParser > xParser( rParserPool.getFormulaParser( rFormulaNmsp ), uno::UNO_SET_THROW ); + table::CellAddress aReferencePos; + ScUnoConversion::FillApiAddress( aReferencePos, aPos ); + uno::Sequence< sheet::FormulaToken > aTokenSeq = xParser->parseFormula( rFormula, aReferencePos ); + ScTokenArray aTokenArray; + if( ScTokenConversion::ConvertToTokenArray( *pDoc, aTokenArray, aTokenSeq ) ) + { + // remember pArr, in case a subsequent CompileTokenArray() is executed. + ScTokenArray* pNew = new ScTokenArray( aTokenArray ); + pArr = pNew; + return pNew; + } + } + catch( uno::Exception& ) + { + } + // no success - fallback to some internal grammar and hope the best + return CompileString( rFormula ); +} + + BOOL ScCompiler::HandleRange() { ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( pToken->GetIndex() ); diff --git a/sc/source/core/tool/formulaparserpool.cxx b/sc/source/core/tool/formulaparserpool.cxx new file mode 100644 index 000000000000..94259a56d6e2 --- /dev/null +++ b/sc/source/core/tool/formulaparserpool.cxx @@ -0,0 +1,171 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: formulaparserpool.cxx,v $ + * $Revision: 1.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +#include "formulaparserpool.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XContentEnumerationAccess.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/sheet/XFilterFormulaParser.hpp> +#include <rtl/instance.hxx> +#include <comphelper/processfactory.hxx> +#include <sfx2/objsh.hxx> +#include "document.hxx" + +using ::rtl::OUString; +using ::rtl::OUStringHash; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sheet; +using namespace ::com::sun::star::uno; + +// ============================================================================ + +namespace { + +class ScParserFactoryMap +{ +public: + explicit ScParserFactoryMap(); + + Reference< XFormulaParser > createFormulaParser( + const Reference< XComponent >& rxComponent, + const OUString& rNamespace ); + +private: + typedef ::std::hash_map< + OUString, + Reference< XSingleComponentFactory >, + OUStringHash, + ::std::equal_to< OUString > > FactoryMap; + + Reference< XComponentContext > mxContext; /// Default context of global process factory. + FactoryMap maFactories; /// All parser factories, mapped by formula namespace. +}; + +ScParserFactoryMap::ScParserFactoryMap() +{ + try + { + // get process factory and default component context + Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory(), UNO_SET_THROW ); + Reference< XPropertySet > xPropSet( xFactory, UNO_QUERY_THROW ); + mxContext.set( xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ), UNO_QUERY_THROW ); + + // enumerate all implementations of the FormulaParser service + Reference< XContentEnumerationAccess > xFactoryEA( xFactory, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnum( xFactoryEA->createContentEnumeration( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sheet.FilterFormulaParser" ) ) ), UNO_SET_THROW ); + while( xEnum->hasMoreElements() ) try // single try/catch for every element + { + // create an instance of the formula parser implementation + Reference< XSingleComponentFactory > xCompFactory( xEnum->nextElement(), UNO_QUERY_THROW ); + Reference< XFilterFormulaParser > xParser( xCompFactory->createInstanceWithContext( mxContext ), UNO_QUERY_THROW ); + + // store factory in the map + OUString aNamespace = xParser->getSupportedNamespace(); + if( aNamespace.getLength() > 0 ) + maFactories[ aNamespace ] = xCompFactory; + } + catch( Exception& ) + { + } + } + catch( Exception& ) + { + } +} + +Reference< XFormulaParser > ScParserFactoryMap::createFormulaParser( + const Reference< XComponent >& rxComponent, const OUString& rNamespace ) +{ + Reference< XFormulaParser > xParser; + FactoryMap::const_iterator aIt = maFactories.find( rNamespace ); + if( aIt != maFactories.end() ) try + { + Sequence< Any > aArgs( 1 ); + aArgs[ 0 ] <<= rxComponent; + xParser.set( aIt->second->createInstanceWithArgumentsAndContext( aArgs, mxContext ), UNO_QUERY_THROW ); + } + catch( Exception& ) + { + } + return xParser; +} + +struct ScParserFactorySingleton : public ::rtl::Static< ScParserFactoryMap, ScParserFactorySingleton > {}; + +} // namespace + +// ============================================================================ + +ScFormulaParserPool::ScFormulaParserPool( const ScDocument& rDoc ) : + mrDoc( rDoc ) +{ +} + +ScFormulaParserPool::~ScFormulaParserPool() +{ +} + +bool ScFormulaParserPool::hasFormulaParser( const OUString& rNamespace ) +{ + return getFormulaParser( rNamespace ).is(); +} + +Reference< XFormulaParser > ScFormulaParserPool::getFormulaParser( const OUString& rNamespace ) +{ + // try to find an existing parser entry + ParserMap::iterator aIt = maParsers.find( rNamespace ); + if( aIt != maParsers.end() ) + return aIt->second; + + // always create a new entry in the map (even if the following initialization fails) + Reference< XFormulaParser >& rxParser = maParsers[ rNamespace ]; + + // try to create a new parser object + if( SfxObjectShell* pDocShell = mrDoc.GetDocumentShell() ) try + { + Reference< XComponent > xComponent( pDocShell->GetModel(), UNO_QUERY_THROW ); + ScParserFactoryMap& rFactoryMap = ScParserFactorySingleton::get(); + rxParser = rFactoryMap.createFormulaParser( xComponent, rNamespace ); + } + catch( Exception& )
+ { + } + return rxParser; +} + +// ============================================================================ + diff --git a/sc/source/core/tool/makefile.mk b/sc/source/core/tool/makefile.mk index 8a4b1b44fd12..ac0aa23fc044 100644 --- a/sc/source/core/tool/makefile.mk +++ b/sc/source/core/tool/makefile.mk @@ -1,7 +1,7 @@ #************************************************************************* # # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# +# # Copyright 2008 by Sun Microsystems, Inc. # # OpenOffice.org - a multi-platform office productivity suite @@ -78,6 +78,7 @@ SLOFILES = \ $(SLO)$/docoptio.obj \ $(SLO)$/editutil.obj \ $(SLO)$/filtopt.obj \ + $(SLO)$/formulaparserpool.obj \ $(SLO)$/hints.obj \ $(SLO)$/indexmap.obj \ $(SLO)$/inputopt.obj \ @@ -122,6 +123,7 @@ EXCEPTIONSFILES= \ $(SLO)$/chartlock.obj \ $(SLO)$/chgtrack.obj \ $(SLO)$/compiler.obj \ + $(SLO)$/formulaparserpool.obj \ $(SLO)$/interpr1.obj \ $(SLO)$/interpr2.obj \ $(SLO)$/interpr3.obj \ diff --git a/sc/source/filter/xml/XMLConverter.cxx b/sc/source/filter/xml/XMLConverter.cxx index e0a20ad4353e..84fdba343630 100644 --- a/sc/source/filter/xml/XMLConverter.cxx +++ b/sc/source/filter/xml/XMLConverter.cxx @@ -31,20 +31,17 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" - - - -//___________________________________________________________________ #include "XMLConverter.hxx" +#include <com/sun/star/util/DateTime.hpp> +#include <tools/datetime.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmluconv.hxx> #include "rangelst.hxx" #include "rangeutl.hxx" #include "docuno.hxx" #include "convuno.hxx" #include "document.hxx" -#include <tools/datetime.hxx> -#include <xmloff/xmltoken.hxx> -#include <xmloff/xmluconv.hxx> -#include <com/sun/star/util/DateTime.hpp> +#include "ftools.hxx" using ::rtl::OUString; using ::rtl::OUStringBuffer; @@ -385,3 +382,292 @@ void ScXMLConverter::ConvertAPIToCoreDateTime(const util::DateTime& aDateTime, D rDateTime = aTempDateTime; } +// ============================================================================ + +namespace { + +/** Enumerates different types of condition tokens. */ +enum ScXMLConditionTokenType +{ + XML_COND_TYPE_KEYWORD, /// Simple keyword without parentheses, e.g. 'and'. + XML_COND_TYPE_COMPARISON, /// Comparison rule, e.g. 'cell-content()<=2'. + XML_COND_TYPE_FUNCTION0, /// Function without parameters, e.g. 'cell-content-is-whole-number()'. + XML_COND_TYPE_FUNCTION1, /// Function with 1 parameter, e.g. 'is-true-formula(1+1=2)'. + XML_COND_TYPE_FUNCTION2 /// Function with 2 parameters, e.g. 'cell-content-is-between(1,2)'. +}; + +struct ScXMLConditionInfo +{ + ScXMLConditionToken meToken; + ScXMLConditionTokenType meType; + sheet::ValidationType meValidation; + sheet::ConditionOperator meOperator; + const sal_Char* mpcIdentifier; + sal_Int32 mnIdentLength; +}; + +static const ScXMLConditionInfo spConditionInfos[] = +{ + { XML_COND_AND, XML_COND_TYPE_KEYWORD, sheet::ValidationType_ANY, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "and" ) }, + { XML_COND_CELLCONTENT, XML_COND_TYPE_COMPARISON, sheet::ValidationType_ANY, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content" ) }, + { XML_COND_ISBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_ANY, sheet::ConditionOperator_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-between" ) }, + { XML_COND_ISNOTBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_ANY, sheet::ConditionOperator_NOT_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-not-between" ) }, + { XML_COND_ISWHOLENUMBER, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_WHOLE, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-whole-number" ) }, + { XML_COND_ISDECIMALNUMBER, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_DECIMAL, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-decimal-number" ) }, + { XML_COND_ISDATE, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_DATE, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-date" ) }, + { XML_COND_ISTIME, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_TIME, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-time" ) }, + { XML_COND_ISINLIST, XML_COND_TYPE_FUNCTION1, sheet::ValidationType_LIST, sheet::ConditionOperator_EQUAL, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-in-list" ) }, + { XML_COND_TEXTLENGTH, XML_COND_TYPE_COMPARISON, sheet::ValidationType_TEXT_LEN, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length" ) }, + { XML_COND_TEXTLENGTH_ISBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_TEXT_LEN, sheet::ConditionOperator_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length-is-between" ) }, + { XML_COND_TEXTLENGTH_ISNOTBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_TEXT_LEN, sheet::ConditionOperator_NOT_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length-is-not-between" ) }, + { XML_COND_ISTRUEFORMULA, XML_COND_TYPE_FUNCTION1, sheet::ValidationType_CUSTOM, sheet::ConditionOperator_FORMULA, RTL_CONSTASCII_STRINGPARAM( "is-true-formula" ) } +}; + +void lclSkipWhitespace( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd ) +{ + while( (rpcString < pcEnd) && (*rpcString <= ' ') ) ++rpcString; +} + +const ScXMLConditionInfo* lclGetConditionInfo( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd ) +{ + lclSkipWhitespace( rpcString, pcEnd ); + /* Search the end of an identifier name; assuming that valid identifiers + consist of [a-z-] only. */ + const sal_Unicode* pcIdStart = rpcString; + while( (rpcString < pcEnd) && (((*rpcString >= 'a') && (*rpcString <= 'z')) || (*rpcString == '-')) ) ++rpcString; + sal_Int32 nLength = static_cast< sal_Int32 >( rpcString - pcIdStart ); + + // search the table for an entry + if( nLength > 0 ) + for( const ScXMLConditionInfo* pInfo = spConditionInfos; pInfo < STATIC_TABLE_END( spConditionInfos ); ++pInfo ) + if( (nLength == pInfo->mnIdentLength) && (::rtl_ustr_ascii_shortenedCompare_WithLength( pcIdStart, nLength, pInfo->mpcIdentifier, nLength ) == 0) ) + return pInfo; + + return 0; +} + +sheet::ConditionOperator lclGetConditionOperator( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd ) +{ + // check for double-char operators + if( (rpcString + 1 < pcEnd) && (rpcString[ 1 ] == '=') ) + { + sheet::ConditionOperator eOperator = sheet::ConditionOperator_NONE; + switch( *rpcString ) + { + case '!': eOperator = sheet::ConditionOperator_NOT_EQUAL; break; + case '<': eOperator = sheet::ConditionOperator_LESS_EQUAL; break; + case '>': eOperator = sheet::ConditionOperator_GREATER_EQUAL; break; + } + if( eOperator != sheet::ConditionOperator_NONE ) + { + rpcString += 2; + return eOperator; + } + } + + // check for single-char operators + if( rpcString < pcEnd ) + { + sheet::ConditionOperator eOperator = sheet::ConditionOperator_NONE; + switch( *rpcString ) + { + case '=': eOperator = sheet::ConditionOperator_EQUAL; break; + case '<': eOperator = sheet::ConditionOperator_LESS; break; + case '>': eOperator = sheet::ConditionOperator_GREATER; break; + } + if( eOperator != sheet::ConditionOperator_NONE ) + { + ++rpcString; + return eOperator; + } + } + + return sheet::ConditionOperator_NONE; +} + +/** Skips a literal string in a formula expression. + + @param rpcString + (in-out) On call, must point to the first character of the string + following the leading string delimiter character. On return, points to + the trailing string delimiter character if existing, otherwise to + pcEnd. + + @param pcEnd + The end of the string to parse. + + @param cQuoteChar + The string delimiter character enclosing the string. + */ +void lclSkipExpressionString( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cQuoteChar ) +{ + if( rpcString < pcEnd ) + { + sal_Int32 nLength = static_cast< sal_Int32 >( pcEnd - rpcString ); + sal_Int32 nNextQuote = ::rtl_ustr_indexOfChar_WithLength( rpcString, nLength, cQuoteChar ); + if( nNextQuote >= 0 ) + rpcString += nNextQuote; + else + rpcString = pcEnd; + } +} + +/** Skips a formula expression. Processes embedded parentheses, braces, and + literal strings. + + @param rpcString + (in-out) On call, must point to the first character of the expression. + On return, points to the passed end character if existing, otherwise to + pcEnd. + + @param pcEnd + The end of the string to parse. + + @param cEndChar + The termination character following the expression. + */ +void lclSkipExpression( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cEndChar ) +{ + while( rpcString < pcEnd ) + { + if( *rpcString == cEndChar ) + return; + switch( *rpcString ) + { + case '(': lclSkipExpression( ++rpcString, pcEnd, ')' ); break; + case '{': lclSkipExpression( ++rpcString, pcEnd, '}' ); break; + case '"': lclSkipExpressionString( ++rpcString, pcEnd, '"' ); break; + case '\'': lclSkipExpressionString( ++rpcString, pcEnd, '\'' ); break; + } + if( rpcString < pcEnd ) ++rpcString; + } +} + +/** Extracts a formula expression. Processes embedded parentheses, braces, and + literal strings. + + @param rpcString + (in-out) On call, must point to the first character of the expression. + On return, points *behind* the passed end character if existing, + otherwise to pcEnd. + + @param pcEnd + The end of the string to parse. + + @param cEndChar + The termination character following the expression. + */ +OUString lclGetExpression( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cEndChar ) +{ + OUString aExp; + const sal_Unicode* pcExpStart = rpcString; + lclSkipExpression( rpcString, pcEnd, cEndChar ); + if( rpcString < pcEnd ) + { + aExp = OUString( pcExpStart, static_cast< sal_Int32 >( rpcString - pcExpStart ) ).trim(); + ++rpcString; + } + return aExp; +} + +/** Tries to skip an empty pair of parentheses (which may contain whitespace + characters). + + @return + True on success, rpcString points behind the closing parentheses then. + */ +bool lclSkipEmptyParentheses( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd ) +{ + if( (rpcString < pcEnd) && (*rpcString == '(') ) + { + lclSkipWhitespace( ++rpcString, pcEnd ); + if( (rpcString < pcEnd) && (*rpcString == ')') ) + { + ++rpcString; + return true; + } + } + return false; +} + +} // namespace + +// ---------------------------------------------------------------------------- + +/*static*/ void ScXMLConditionHelper::parseCondition( + ScXMLConditionParseResult& rParseResult, const OUString& rAttribute, sal_Int32 nStartIndex ) +{ + rParseResult.meToken = XML_COND_INVALID; + if( (nStartIndex < 0) || (nStartIndex >= rAttribute.getLength()) ) return; + + // try to find an identifier + const sal_Unicode* pcBegin = rAttribute.getStr(); + const sal_Unicode* pcString = pcBegin + nStartIndex; + const sal_Unicode* pcEnd = pcBegin + rAttribute.getLength(); + if( const ScXMLConditionInfo* pCondInfo = lclGetConditionInfo( pcString, pcEnd ) ) + { + // insert default values into parse result (may be changed below) + rParseResult.meValidation = pCondInfo->meValidation; + rParseResult.meOperator = pCondInfo->meOperator; + // continue parsing dependent on token type + switch( pCondInfo->meType ) + { + case XML_COND_TYPE_KEYWORD: + // nothing specific has to follow, success + rParseResult.meToken = pCondInfo->meToken; + break; + + case XML_COND_TYPE_COMPARISON: + // format is <condition>()<operator><expression> + if( lclSkipEmptyParentheses( pcString, pcEnd ) ) + { + rParseResult.meOperator = lclGetConditionOperator( pcString, pcEnd ); + if( rParseResult.meOperator != sheet::ConditionOperator_NONE ) + { + lclSkipWhitespace( pcString, pcEnd ); + if( pcString < pcEnd ) + { + rParseResult.meToken = pCondInfo->meToken; + // comparison must be at end of attribute, remaining text is the formula + rParseResult.maOperand1 = OUString( pcString, static_cast< sal_Int32 >( pcEnd - pcString ) ); + } + } + } + break; + + case XML_COND_TYPE_FUNCTION0: + // format is <condition>() + if( lclSkipEmptyParentheses( pcString, pcEnd ) ) + rParseResult.meToken = pCondInfo->meToken; + break; + + case XML_COND_TYPE_FUNCTION1: + // format is <condition>(<expression>) + if( (pcString < pcEnd) && (*pcString == '(') ) + { + rParseResult.maOperand1 = lclGetExpression( ++pcString, pcEnd, ')' ); + if( rParseResult.maOperand1.getLength() > 0 ) + rParseResult.meToken = pCondInfo->meToken; + } + break; + + case XML_COND_TYPE_FUNCTION2: + // format is <condition>(<expression1>,<expression2>) + if( (pcString < pcEnd) && (*pcString == '(') ) + { + rParseResult.maOperand1 = lclGetExpression( ++pcString, pcEnd, ',' ); + if( rParseResult.maOperand1.getLength() > 0 ) + { + rParseResult.maOperand2 = lclGetExpression( pcString, pcEnd, ')' ); + if( rParseResult.maOperand2.getLength() > 0 ) + rParseResult.meToken = pCondInfo->meToken; + } + } + break; + } + rParseResult.mnEndIndex = static_cast< sal_Int32 >( pcString - pcBegin ); + } +} + +// ============================================================================ + diff --git a/sc/source/filter/xml/XMLConverter.hxx b/sc/source/filter/xml/XMLConverter.hxx index 75254a7b3300..090a3553aa91 100644 --- a/sc/source/filter/xml/XMLConverter.hxx +++ b/sc/source/filter/xml/XMLConverter.hxx @@ -36,8 +36,10 @@ #include "detdata.hxx" #include <rtl/ustrbuf.hxx> #include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/sheet/ConditionOperator.hpp> #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> #include <com/sun/star/sheet/GeneralFunction.hpp> +#include <com/sun/star/sheet/ValidationType.hpp> #include <com/sun/star/util/DateTime.hpp> class ScDocument; @@ -117,6 +119,62 @@ public: static void ConvertAPIToCoreDateTime(const com::sun::star::util::DateTime& aDateTime, DateTime& rDateTime); }; +// ============================================================================ + +enum ScXMLConditionToken +{ + XML_COND_INVALID, /// Token not recognized. + XML_COND_AND, /// The 'and' token. + XML_COND_CELLCONTENT, /// The 'cell-content' token. + XML_COND_ISBETWEEN, /// The 'cell-content-is-between' token. + XML_COND_ISNOTBETWEEN, /// The 'cell-content-is-not-between' token. + XML_COND_ISWHOLENUMBER, /// The 'cell-content-is-whole-number' token. + XML_COND_ISDECIMALNUMBER, /// The 'cell-content-is-decimal-number' token. + XML_COND_ISDATE, /// The 'cell-content-is-date' token. + XML_COND_ISTIME, /// The 'cell-content-is-time' token. + XML_COND_ISINLIST, /// The 'cell-content-is-in-list' token. + XML_COND_TEXTLENGTH, /// The 'cell-content-text-length' token. + XML_COND_TEXTLENGTH_ISBETWEEN, /// The 'cell-content-text-length-is-between' token. + XML_COND_TEXTLENGTH_ISNOTBETWEEN, /// The 'cell-content-text-length-is-not-between' token. + XML_COND_ISTRUEFORMULA /// The 'is-true-formula' token. +}; + +// ---------------------------------------------------------------------------- + +/** Result of an attempt to parse a single condition in a 'condition' attribute + value of e.g. conditional formatting or data validation. + */ +struct ScXMLConditionParseResult +{ + ScXMLConditionToken meToken; /// The leading condition token. + ::com::sun::star::sheet::ValidationType + meValidation; /// A data validation type if existing. + ::com::sun::star::sheet::ConditionOperator + meOperator; /// A comparison operator if existing. + ::rtl::OUString maOperand1; /// First operand of the token or comparison value. + ::rtl::OUString maOperand2; /// Second operand of 'between' conditions. + sal_Int32 mnEndIndex; /// Index of first character following the condition. +}; + +// ---------------------------------------------------------------------------- + +class ScXMLConditionHelper +{ +public: + /** Parses the next condition in a 'condition' attribute value of e.g. + conditional formatting or data validation. + */ + static void parseCondition( + ScXMLConditionParseResult& rParseResult, + const ::rtl::OUString& rAttribute, + sal_Int32 nStartIndex ); + +private: + ScXMLConditionHelper(); + ~ScXMLConditionHelper(); +}; + +// ============================================================================ #endif diff --git a/sc/source/filter/xml/XMLTrackedChangesContext.cxx b/sc/source/filter/xml/XMLTrackedChangesContext.cxx index d1320a8c737f..2d8eac1dfc76 100644 --- a/sc/source/filter/xml/XMLTrackedChangesContext.cxx +++ b/sc/source/filter/xml/XMLTrackedChangesContext.cxx @@ -109,6 +109,7 @@ class ScXMLCellContentDeletionContext : public SvXMLImportContext { rtl::OUString sFormulaAddress; rtl::OUString sFormula; + rtl::OUString sFormulaNmsp; rtl::OUString sInputString; ScBigRange aBigRange; double fValue; @@ -298,7 +299,8 @@ public: ScXMLChangeCellContext( ScXMLImport& rImport, USHORT nPrfx, const ::rtl::OUString& rLName, const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList, - ScBaseCell*& rOldCell, rtl::OUString& sAddress, rtl::OUString& sFormula, + ScBaseCell*& rOldCell, rtl::OUString& sAddress, + rtl::OUString& rFormula, rtl::OUString& rFormulaNmsp, formula::FormulaGrammar::Grammar& rGrammar, rtl::OUString& rInputString, double& fValue, sal_uInt16& nType, sal_uInt8& nMatrixFlag, sal_Int32& nMatrixCols, sal_Int32& nMatrixRows); @@ -322,6 +324,7 @@ class ScXMLPreviousContext : public SvXMLImportContext { rtl::OUString sFormulaAddress; rtl::OUString sFormula; + rtl::OUString sFormulaNmsp; rtl::OUString sInputString; double fValue; ScXMLChangeTrackingImportHelper* pChangeTrackingImportHelper; @@ -329,7 +332,7 @@ class ScXMLPreviousContext : public SvXMLImportContext sal_uInt32 nID; sal_Int32 nMatrixCols; sal_Int32 nMatrixRows; - formula::FormulaGrammar::Grammar eGrammar; + formula::FormulaGrammar::Grammar eGrammar; sal_uInt16 nType; sal_uInt8 nMatrixFlag; @@ -831,7 +834,7 @@ SvXMLImportContext *ScXMLCellContentDeletionContext::CreateChildContext( USHORT { bContainsCell = sal_True; pContext = new ScXMLChangeCellContext(GetScImport(), nPrefix, rLocalName, xAttrList, - pCell, sFormulaAddress, sFormula, eGrammar, sInputString, fValue, nType, nMatrixFlag, nMatrixCols, nMatrixRows ); + pCell, sFormulaAddress, sFormula, sFormulaNmsp, eGrammar, sInputString, fValue, nType, nMatrixFlag, nMatrixCols, nMatrixRows ); } else if (IsXMLToken(rLocalName, XML_CELL_ADDRESS)) { @@ -1115,7 +1118,8 @@ ScXMLChangeCellContext::ScXMLChangeCellContext( ScXMLImport& rImport, USHORT nPrfx, const ::rtl::OUString& rLName, const uno::Reference<xml::sax::XAttributeList>& xAttrList, - ScBaseCell*& rTempOldCell, rtl::OUString& rAddress, rtl::OUString& rFormula, + ScBaseCell*& rTempOldCell, rtl::OUString& rAddress, + rtl::OUString& rFormula, rtl::OUString& rFormulaNmsp, formula::FormulaGrammar::Grammar& rGrammar, rtl::OUString& rTempInputString, double& fDateTimeValue, sal_uInt16& nType, sal_uInt8& nMatrixFlag, sal_Int32& nMatrixCols, sal_Int32& nMatrixRows ) : @@ -1130,7 +1134,6 @@ ScXMLChangeCellContext::ScXMLChangeCellContext( ScXMLImport& rImport, bString(sal_True), bFormula(sal_False) { - const formula::FormulaGrammar::Grammar eStorageGrammar = rGrammar = GetScImport().GetDocument()->GetStorageGrammar(); sal_Bool bIsMatrix(sal_False); sal_Bool bIsCoveredMatrix(sal_False); sal_Int16 nAttrCount(xAttrList.is() ? xAttrList->getLength() : 0); @@ -1147,12 +1150,7 @@ ScXMLChangeCellContext::ScXMLChangeCellContext( ScXMLImport& rImport, if (IsXMLToken(aLocalName, XML_FORMULA)) { bEmpty = sal_False; - sal_uInt16 nFormulaPrefix = GetImport().GetNamespaceMap(). - _GetKeyByAttrName( sValue, &rFormula, sal_False ); - - if (!ScXMLImport::IsAcceptedFormulaNamespace( nFormulaPrefix, - sValue, rGrammar, eStorageGrammar)) - rFormula = sValue; + GetScImport().ExtractFormulaNamespaceGrammar( rFormula, rFormulaNmsp, rGrammar, sValue ); bFormula = sal_True; } else if (IsXMLToken(aLocalName, XML_CELL_ADDRESS)) @@ -1339,8 +1337,6 @@ ScXMLPreviousContext::ScXMLPreviousContext( ScXMLImport& rImport, const uno::Reference<xml::sax::XAttributeList>& xAttrList, ScXMLChangeTrackingImportHelper* pTempChangeTrackingImportHelper ) : SvXMLImportContext( rImport, nPrfx, rLName ), - sFormulaAddress(), - sFormula(), pChangeTrackingImportHelper(pTempChangeTrackingImportHelper), pOldCell(NULL), nID(0), @@ -1380,7 +1376,7 @@ SvXMLImportContext *ScXMLPreviousContext::CreateChildContext( USHORT nPrefix, if ((nPrefix == XML_NAMESPACE_TABLE) && (IsXMLToken(rLocalName, XML_CHANGE_TRACK_TABLE_CELL))) pContext = new ScXMLChangeCellContext(GetScImport(), nPrefix, rLocalName, xAttrList, - pOldCell, sFormulaAddress, sFormula, eGrammar, sInputString, fValue, nType, nMatrixFlag, nMatrixCols, nMatrixRows); + pOldCell, sFormulaAddress, sFormula, sFormulaNmsp, eGrammar, sInputString, fValue, nType, nMatrixFlag, nMatrixCols, nMatrixRows); if( !pContext ) pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); diff --git a/sc/source/filter/xml/xmlcelli.cxx b/sc/source/filter/xml/xmlcelli.cxx index 5c190ca272b3..f0a4569cc86e 100644 --- a/sc/source/filter/xml/xmlcelli.cxx +++ b/sc/source/filter/xml/xmlcelli.cxx @@ -129,7 +129,6 @@ ScXMLTableRowCellContext::ScXMLTableRowCellContext( ScXMLImport& rImport, bSolarMutexLocked(sal_False), bFormulaTextResult(sal_False) { - formula::FormulaGrammar::Grammar eStorageGrammar = eGrammar = GetScImport().GetDocument()->GetStorageGrammar(); rXMLImport.SetRemoveLastChar(sal_False); rXMLImport.GetTables().AddColumn(bTempIsCovered); const sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; @@ -232,25 +231,9 @@ ScXMLTableRowCellContext::ScXMLTableRowCellContext( ScXMLImport& rImport, if (sValue.getLength()) { DBG_ASSERT(!pOUFormula, "here should be only one formula"); - rtl::OUString sFormula; - sal_uInt16 nFormulaPrefix = GetImport().GetNamespaceMap(). - _GetKeyByAttrName( sValue, &sFormula, sal_False ); - - if (ScXMLImport::IsAcceptedFormulaNamespace( - nFormulaPrefix, sValue, eGrammar, - eStorageGrammar)) - { - // Namespaces we accept. - pOUFormula.reset( sFormula); - } - else - { - // No namespace => entire string. - // Also unknown namespace included in formula, - // so hopefully will result in string or - // compile error. - pOUFormula.reset( sValue); - } + rtl::OUString aFormula, aFormulaNmsp; + rXMLImport.ExtractFormulaNamespaceGrammar( aFormula, aFormulaNmsp, eGrammar, sValue ); + pOUFormula.reset( FormulaWithNamespace( aFormula, aFormulaNmsp ) ); } } break; @@ -530,7 +513,7 @@ void ScXMLTableRowCellContext::SetContentValidation(com::sun::star::uno::Referen if (pContentValidationName) { ScMyImportValidation aValidation; - aValidation.eGrammar = GetScImport().GetDocument()->GetStorageGrammar(); + aValidation.eGrammar1 = aValidation.eGrammar2 = GetScImport().GetDocument()->GetStorageGrammar(); if (rXMLImport.GetValidation(*pContentValidationName, aValidation)) { uno::Reference<beans::XPropertySet> xPropertySet(xPropSet->getPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_VALIXML))), uno::UNO_QUERY); @@ -559,8 +542,11 @@ void ScXMLTableRowCellContext::SetContentValidation(com::sun::star::uno::Referen // #b4974740# source position must be set as string, because it may // refer to a sheet that hasn't been loaded yet. xPropertySet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_SOURCESTR)), uno::makeAny(aValidation.sBaseCellAddress)); - // Transport grammar. - xPropertySet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_GRAMMAR)), uno::makeAny(static_cast<sal_Int32>(aValidation.eGrammar))); + // Transport grammar and formula namespace + xPropertySet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_FORMULANMSP1)), uno::makeAny(aValidation.sFormulaNmsp1)); + xPropertySet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_FORMULANMSP2)), uno::makeAny(aValidation.sFormulaNmsp2)); + xPropertySet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_GRAMMAR1)), uno::makeAny(static_cast<sal_Int32>(aValidation.eGrammar1))); + xPropertySet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_GRAMMAR2)), uno::makeAny(static_cast<sal_Int32>(aValidation.eGrammar2))); } } xPropSet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_VALIXML)), uno::makeAny(xPropertySet)); @@ -1046,7 +1032,7 @@ void ScXMLTableRowCellContext::EndElement() //SetType(xTempCell); } } - else + else // if ( !pOUFormula ) { if (CellExists(aCellPos)) { @@ -1059,7 +1045,7 @@ void ScXMLTableRowCellContext::EndElement() { DBG_ERRORFILE("It seems here are to many columns or rows"); } - if (xCell.is() && pOUFormula) + if (xCell.is()) { SetCellProperties(xCell); // set now only the validation DBG_ASSERT(((nCellsRepeated == 1) && (nRepeatedRows == 1)), "repeated cells with formula not possible now"); @@ -1072,7 +1058,7 @@ void ScXMLTableRowCellContext::EndElement() xCell)); if (pCellObj) { - pCellObj->SetFormulaWithGrammar( *pOUFormula, eGrammar); + pCellObj->SetFormulaWithGrammar( pOUFormula->first, pOUFormula->second, eGrammar); if (bFormulaTextResult && pOUTextValue && pOUTextValue->getLength()) pCellObj->SetFormulaResultString( *pOUTextValue); else if (fValue != 0.0) @@ -1087,7 +1073,7 @@ void ScXMLTableRowCellContext::EndElement() aCellPos.Column, aCellPos.Row, aCellPos.Column + nMatrixCols - 1, aCellPos.Row + nMatrixRows - 1, - *pOUFormula, eGrammar); + pOUFormula->first, pOUFormula->second, eGrammar); } } SetAnnotation( aCellPos ); @@ -1104,7 +1090,7 @@ void ScXMLTableRowCellContext::EndElement() rXMLImport.SetRangeOverflowType(SCWARN_IMPORT_COLUMN_OVERFLOW); } - } + } // if ( !pOUFormula ) } UnlockSolarMutex(); } diff --git a/sc/source/filter/xml/xmlcelli.hxx b/sc/source/filter/xml/xmlcelli.hxx index 1a4280af36b2..fe2bfd116348 100644 --- a/sc/source/filter/xml/xmlcelli.hxx +++ b/sc/source/filter/xml/xmlcelli.hxx @@ -52,11 +52,12 @@ struct ScXMLAnnotationData; class ScXMLTableRowCellContext : public SvXMLImportContext { + typedef ::std::pair< ::rtl::OUString, ::rtl::OUString > FormulaWithNamespace; com::sun::star::uno::Reference<com::sun::star::table::XCell> xBaseCell; com::sun::star::uno::Reference<com::sun::star::document::XActionLockable> xLockable; ::boost::optional< rtl::OUString > pOUTextValue; ::boost::optional< rtl::OUString > pOUTextContent; - ::boost::optional< rtl::OUString > pOUFormula; + ::boost::optional< FormulaWithNamespace > pOUFormula; rtl::OUString* pContentValidationName; ::std::auto_ptr< ScXMLAnnotationData > mxAnnotationData; ScMyImpDetectiveObjVec* pDetectiveObjVec; diff --git a/sc/source/filter/xml/xmlcvali.cxx b/sc/source/filter/xml/xmlcvali.cxx index d8d8eb0d7cc2..aeff28f3eed6 100644 --- a/sc/source/filter/xml/xmlcvali.cxx +++ b/sc/source/filter/xml/xmlcvali.cxx @@ -51,6 +51,8 @@ using namespace com::sun::star; using namespace xmloff::token; +using namespace ::formula; +using ::rtl::OUString; class ScXMLContentValidationContext : public SvXMLImportContext { @@ -62,7 +64,6 @@ class ScXMLContentValidationContext : public SvXMLImportContext rtl::OUString sErrorMessageType; rtl::OUString sBaseCellAddress; rtl::OUString sCondition; - formula::FormulaGrammar::Grammar eGrammar; sal_Int16 nShowList; sal_Bool bAllowEmptyCell; sal_Bool bDisplayHelp; @@ -73,11 +74,10 @@ class ScXMLContentValidationContext : public SvXMLImportContext const ScXMLImport& GetScImport() const { return (const ScXMLImport&)GetImport(); } ScXMLImport& GetScImport() { return (ScXMLImport&)GetImport(); } - void GetAlertStyle(const rtl::OUString& sMessageType, com::sun::star::sheet::ValidationAlertStyle& aAlertStyle); - void SetFormulas(const rtl::OUString& sFormulas, rtl::OUString& sFormula1, rtl::OUString& sFormula2) const; - void GetCondition(const rtl::OUString& sCondition, rtl::OUString& sFormula1, rtl::OUString& sFormula2, - com::sun::star::sheet::ValidationType& aValidationType, - com::sun::star::sheet::ConditionOperator& aOperator); + com::sun::star::sheet::ValidationAlertStyle GetAlertStyle() const; + void SetFormula( OUString& rFormula, OUString& rFormulaNmsp, FormulaGrammar::Grammar& reGrammar, + const OUString& rCondition, const OUString& rGlobNmsp, FormulaGrammar::Grammar eGlobGrammar, bool bHasNmsp ) const; + void GetCondition( ScMyImportValidation& rValidation ) const; public: @@ -235,20 +235,11 @@ ScXMLContentValidationContext::ScXMLContentValidationContext( ScXMLImport& rImpo const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList) : SvXMLImportContext( rImport, nPrfx, rLName ), - sName(), - sHelpTitle(), - sHelpMessage(), - sErrorTitle(), - sErrorMessage(), - sErrorMessageType(), - sBaseCellAddress(), - sCondition(), nShowList(sheet::TableValidationVisibility::UNSORTED), bAllowEmptyCell(sal_True), bDisplayHelp(sal_False), bDisplayError(sal_False) { - const formula::FormulaGrammar::Grammar eStorageGrammar = eGrammar = GetScImport().GetDocument()->GetStorageGrammar(); sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; const SvXMLTokenMap& rAttrTokenMap = GetScImport().GetContentValidationAttrTokenMap(); for( sal_Int16 i=0; i < nAttrCount; ++i ) @@ -265,14 +256,7 @@ ScXMLContentValidationContext::ScXMLContentValidationContext( ScXMLImport& rImpo sName = sValue; break; case XML_TOK_CONTENT_VALIDATION_CONDITION: - { - sal_uInt16 nCondPrefix = GetImport().GetNamespaceMap(). - _GetKeyByAttrName( sValue, &sCondition, sal_False ); - - if (!ScXMLImport::IsAcceptedFormulaNamespace( nCondPrefix, - sValue, eGrammar, eStorageGrammar)) - sCondition = sValue; - } + sCondition = sValue; break; case XML_TOK_CONTENT_VALIDATION_BASE_CELL_ADDRESS: sBaseCellAddress = sValue; @@ -336,189 +320,116 @@ SvXMLImportContext *ScXMLContentValidationContext::CreateChildContext( USHORT nP return pContext; } -void ScXMLContentValidationContext::GetAlertStyle(const rtl::OUString& sMessageType, com::sun::star::sheet::ValidationAlertStyle& aAlertStyle) +sheet::ValidationAlertStyle ScXMLContentValidationContext::GetAlertStyle() const { - if (IsXMLToken(sMessageType, XML_MACRO)) - aAlertStyle = sheet::ValidationAlertStyle_MACRO; - else if (IsXMLToken(sMessageType, XML_STOP)) - aAlertStyle = sheet::ValidationAlertStyle_STOP; - else if (IsXMLToken(sMessageType, XML_WARNING)) - aAlertStyle = sheet::ValidationAlertStyle_WARNING; - else if (IsXMLToken(sMessageType, XML_INFORMATION)) - aAlertStyle = sheet::ValidationAlertStyle_INFO; - else // don't leave uninitialized - aAlertStyle = sheet::ValidationAlertStyle_STOP; + if (IsXMLToken(sErrorMessageType, XML_MACRO)) + return sheet::ValidationAlertStyle_MACRO; + if (IsXMLToken(sErrorMessageType, XML_STOP)) + return sheet::ValidationAlertStyle_STOP; + if (IsXMLToken(sErrorMessageType, XML_WARNING)) + return sheet::ValidationAlertStyle_WARNING; + if (IsXMLToken(sErrorMessageType, XML_INFORMATION)) + return sheet::ValidationAlertStyle_INFO; + // default for unknown + return sheet::ValidationAlertStyle_STOP; } -void ScXMLContentValidationContext::SetFormulas(const rtl::OUString& sFormulas, rtl::OUString& sFormula1, rtl::OUString& sFormula2) const +void ScXMLContentValidationContext::SetFormula( OUString& rFormula, OUString& rFormulaNmsp, FormulaGrammar::Grammar& reGrammar, + const OUString& rCondition, const OUString& rGlobNmsp, FormulaGrammar::Grammar eGlobGrammar, bool bHasNmsp ) const { - sal_Int32 i = 0; - sal_Bool bString = sal_False; - sal_Int32 nBrakes = 0; - while ((sFormulas[i] != ',' || nBrakes > 0 || bString) && i < sFormulas.getLength()) + reGrammar = FormulaGrammar::GRAM_UNSPECIFIED; + if( bHasNmsp ) { - if (sFormulas[i] == '(') - ++nBrakes; - if (sFormulas[i] == ')') - --nBrakes; - if (sFormulas[i] == '"') - bString = !bString; - ++i; + // the entire attribute contains a namespace: internal namespace not allowed + rFormula = rCondition; + rFormulaNmsp = rGlobNmsp; + reGrammar = eGlobGrammar; } - if (sFormulas[i] == ',') + else { - sFormula1 = sFormulas.copy(0, i); - sFormula2 = sFormulas.copy(i + 1); + // the attribute does not contain a namespace: try to find a namespace of an external grammar + GetScImport().ExtractFormulaNamespaceGrammar( rFormula, rFormulaNmsp, reGrammar, rCondition, true ); + if( reGrammar != FormulaGrammar::GRAM_EXTERNAL ) + reGrammar = eGlobGrammar; } } -void ScXMLContentValidationContext::GetCondition(const rtl::OUString& sTempCondition, rtl::OUString& sFormula1, rtl::OUString& sFormula2, - com::sun::star::sheet::ValidationType& aValidationType, - com::sun::star::sheet::ConditionOperator& aOperator) +void ScXMLContentValidationContext::GetCondition( ScMyImportValidation& rValidation ) const { - aValidationType = sheet::ValidationType_ANY; // #b6343997# default if no condition is given - aOperator = sheet::ConditionOperator_NONE; + rValidation.aValidationType = sheet::ValidationType_ANY; // #b6343997# default if no condition is given + rValidation.aOperator = sheet::ConditionOperator_NONE; - rtl::OUString sLocalCondition(sTempCondition); - if (sLocalCondition.getLength()) + if( sCondition.getLength() > 0 ) { - // ToDo: erase all blanks in the condition, but not in formulas or strings - rtl::OUString scell_content(RTL_CONSTASCII_USTRINGPARAM("cell_content")); - rtl::OUString scell_content_is_date(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-date")); - rtl::OUString scell_content_is_time(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-time")); - rtl::OUString scell_content_is_between(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-between")); - rtl::OUString scell_content_is_in_list(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-in-list")); - rtl::OUString scell_content_text_length(RTL_CONSTASCII_USTRINGPARAM("cell-content-text-length")); - rtl::OUString scell_content_is_not_between(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-not-between")); - rtl::OUString scell_content_is_whole_number(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-whole-number")); - rtl::OUString scell_content_is_decimal_number(RTL_CONSTASCII_USTRINGPARAM("cell-content-is-decimal-number")); - rtl::OUString scell_content_text_length_is_between(RTL_CONSTASCII_USTRINGPARAM("cell-content-text-length-is-between")); - rtl::OUString scell_content_text_length_is_not_between(RTL_CONSTASCII_USTRINGPARAM("cell-content-text-length-is-not-between")); - sal_Int32 i = 0; - sal_Bool bAnd(sal_True); - while (sLocalCondition[i] != '(' && i < sLocalCondition.getLength()) - ++i; - if (sLocalCondition[i] == '(') + // extract leading namespace from condition string + OUString aCondition, aConditionNmsp; + FormulaGrammar::Grammar eGrammar = FormulaGrammar::GRAM_UNSPECIFIED; + GetScImport().ExtractFormulaNamespaceGrammar( aCondition, aConditionNmsp, eGrammar, sCondition ); + bool bHasNmsp = aCondition.getLength() < sCondition.getLength(); + + // parse a condition from the attribute string + ScXMLConditionParseResult aParseResult; + ScXMLConditionHelper::parseCondition( aParseResult, aCondition, 0 ); + + /* Check the result. A valid value in aParseResult.meToken implies + that the other members of aParseResult are filled with valid data + for that token. */ + bool bSecondaryPart = false; + switch( aParseResult.meToken ) { - if (i != scell_content_text_length.getLength() && - i != scell_content_text_length_is_between.getLength() && - i != scell_content_text_length_is_not_between.getLength() && - i != scell_content_is_in_list.getLength()) - { - if (i == scell_content_is_time.getLength()) - { - rtl::OUString sTemp = sLocalCondition.copy(0, i); - if (sTemp == scell_content_is_time) - aValidationType = sheet::ValidationType_TIME; - else - aValidationType = sheet::ValidationType_DATE; - } - else if (i == scell_content_is_whole_number.getLength()) - aValidationType = sheet::ValidationType_WHOLE; - else if (i == scell_content_is_decimal_number.getLength()) - aValidationType = sheet::ValidationType_DECIMAL; - sLocalCondition = sLocalCondition.copy(i + 2); - rtl::OUString sTemp = sLocalCondition.copy(0, 5); - if (sTemp.compareToAscii(" and ") == 0) - sLocalCondition = sLocalCondition.copy(5); - else - bAnd = sal_False; - } - if (sLocalCondition.getLength() && bAnd) + case XML_COND_TEXTLENGTH: // condition is 'cell-content-text-length()<operator><expression>' + case XML_COND_TEXTLENGTH_ISBETWEEN: // condition is 'cell-content-text-length-is-between(<expression1>,<expression2>)' + case XML_COND_TEXTLENGTH_ISNOTBETWEEN: // condition is 'cell-content-text-length-is-not-between(<expression1>,<expression2>)' + case XML_COND_ISINLIST: // condition is 'cell-content-is-in-list(<expression>)' + rValidation.aValidationType = aParseResult.meValidation; + rValidation.aOperator = aParseResult.meOperator; + break; + + case XML_COND_ISWHOLENUMBER: // condition is 'cell-content-is-whole-number() and <condition>' + case XML_COND_ISDECIMALNUMBER: // condition is 'cell-content-is-decimal-number() and <condition>' + case XML_COND_ISDATE: // condition is 'cell-content-is-date() and <condition>' + case XML_COND_ISTIME: // condition is 'cell-content-is-time() and <condition>' + rValidation.aValidationType = aParseResult.meValidation; + bSecondaryPart = true; + break; + + default:; // unacceptable or unknown condition + } + + /* Parse the following 'and <condition>' part of some conditions. This + updates the members of aParseResult that will contain the operands + and comparison operator then. */ + if( bSecondaryPart ) + { + ScXMLConditionHelper::parseCondition( aParseResult, aCondition, aParseResult.mnEndIndex ); + if( aParseResult.meToken == XML_COND_AND ) { - i = 0; - while (sLocalCondition[i] != '(' && i < sLocalCondition.getLength()) - ++i; - if (sLocalCondition[i] == '(') + ScXMLConditionHelper::parseCondition( aParseResult, aCondition, aParseResult.mnEndIndex ); + switch( aParseResult.meToken ) { - rtl::OUString sTemp = sLocalCondition.copy(0, i); - sLocalCondition = sLocalCondition.copy(i + 1); - if (i == scell_content_is_between.getLength() || - i == scell_content_text_length_is_between.getLength()) - { - if (sTemp == scell_content_is_in_list) - { - aValidationType = sheet::ValidationType_LIST; - sFormula1 = sLocalCondition.copy(0, sLocalCondition.getLength() - 1); - aOperator = sheet::ConditionOperator_EQUAL; - } - else - { - if (i == scell_content_text_length_is_between.getLength()) - aValidationType = sheet::ValidationType_TEXT_LEN; - aOperator = sheet::ConditionOperator_BETWEEN; - sLocalCondition = sLocalCondition.copy(0, sLocalCondition.getLength() - 1); - SetFormulas(sLocalCondition, sFormula1, sFormula2); - } - } - else if (i == scell_content_is_not_between.getLength() || - i == scell_content_text_length_is_not_between.getLength()) - { - if (i == scell_content_text_length_is_not_between.getLength()) - aValidationType = sheet::ValidationType_TEXT_LEN; - aOperator = sheet::ConditionOperator_NOT_BETWEEN; - sLocalCondition = sLocalCondition.copy(0, sLocalCondition.getLength() - 1); - SetFormulas(sLocalCondition, sFormula1, sFormula2); - } - else if (i == scell_content.getLength() || - i == scell_content_text_length.getLength()) - { - if (i == scell_content_text_length.getLength()) - aValidationType = sheet::ValidationType_TEXT_LEN; - sLocalCondition = sLocalCondition.copy(1); - switch (sLocalCondition[0]) - { - case '<' : - { - if (sLocalCondition[1] == '=') - { - aOperator = sheet::ConditionOperator_LESS_EQUAL; - sLocalCondition = sLocalCondition.copy(2); - } - else - { - aOperator = sheet::ConditionOperator_LESS; - sLocalCondition = sLocalCondition.copy(1); - } - } - break; - case '>' : - { - if (sLocalCondition[1] == '=') - { - aOperator = sheet::ConditionOperator_GREATER_EQUAL; - sLocalCondition = sLocalCondition.copy(2); - } - else - { - aOperator = sheet::ConditionOperator_GREATER; - sLocalCondition = sLocalCondition.copy(1); - } - } - break; - case '=' : - { - aOperator = sheet::ConditionOperator_EQUAL; - sLocalCondition = sLocalCondition.copy(1); - } - break; - case '!' : - { - aOperator = sheet::ConditionOperator_NOT_EQUAL; - sLocalCondition = sLocalCondition.copy(1); - } - break; - } - sFormula1 = sLocalCondition; - } + case XML_COND_CELLCONTENT: // condition is 'and cell-content()<operator><expression>' + case XML_COND_ISBETWEEN: // condition is 'and cell-content-is-between(<expression1>,<expression2>)' + case XML_COND_ISNOTBETWEEN: // condition is 'and cell-content-is-not-between(<expression1>,<expression2>)' + rValidation.aOperator = aParseResult.meOperator; + break; + default:; // unacceptable or unknown condition } } } - } - // a validation type (date, integer) without a condition isn't possible - if ( aOperator == sheet::ConditionOperator_NONE ) - aValidationType = sheet::ValidationType_ANY; + // a validation type (date, integer) without a condition isn't possible + if( rValidation.aOperator == sheet::ConditionOperator_NONE ) + rValidation.aValidationType = sheet::ValidationType_ANY; + + // parse the formulas + if( rValidation.aValidationType != sheet::ValidationType_ANY ) + { + SetFormula( rValidation.sFormula1, rValidation.sFormulaNmsp1, rValidation.eGrammar1, + aParseResult.maOperand1, aConditionNmsp, eGrammar, bHasNmsp ); + SetFormula( rValidation.sFormula2, rValidation.sFormulaNmsp2, rValidation.eGrammar2, + aParseResult.maOperand2, aConditionNmsp, eGrammar, bHasNmsp ); + } + } } void ScXMLContentValidationContext::EndElement() @@ -546,15 +457,15 @@ void ScXMLContentValidationContext::EndElement() } ScMyImportValidation aValidation; - aValidation.eGrammar = eGrammar; + aValidation.eGrammar1 = aValidation.eGrammar2 = GetScImport().GetDocument()->GetStorageGrammar(); aValidation.sName = sName; aValidation.sBaseCellAddress = sBaseCellAddress; aValidation.sImputTitle = sHelpTitle; aValidation.sImputMessage = sHelpMessage; aValidation.sErrorTitle = sErrorTitle; aValidation.sErrorMessage = sErrorMessage; - GetCondition(sCondition, aValidation.sFormula1, aValidation.sFormula2, aValidation.aValidationType, aValidation.aOperator); - GetAlertStyle(sErrorMessageType, aValidation.aAlertStyle); + GetCondition( aValidation ); + aValidation.aAlertStyle = GetAlertStyle(); aValidation.bShowErrorMessage = bDisplayError; aValidation.bShowImputMessage = bDisplayHelp; aValidation.bIgnoreBlanks = bAllowEmptyCell; diff --git a/sc/source/filter/xml/xmlimprt.cxx b/sc/source/filter/xml/xmlimprt.cxx index b806ef13561d..200e33743020 100644 --- a/sc/source/filter/xml/xmlimprt.cxx +++ b/sc/source/filter/xml/xmlimprt.cxx @@ -74,6 +74,7 @@ #include "unonames.hxx" #include "rangeutl.hxx" #include "postit.hxx" +#include "formulaparserpool.hxx" #include <comphelper/extract.hxx> #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> @@ -2887,36 +2888,62 @@ sal_Int32 ScXMLImport::GetVisibleSheet() return 0; } -// static -bool ScXMLImport::IsAcceptedFormulaNamespace( const sal_uInt16 nFormulaPrefix, - const rtl::OUString & rValue, formula::FormulaGrammar::Grammar& rGrammar, - const formula::FormulaGrammar::Grammar eStorageGrammar ) +void ScXMLImport::ExtractFormulaNamespaceGrammar( + OUString& rFormula, OUString& rFormulaNmsp, FormulaGrammar::Grammar& reGrammar, + const OUString& rAttrValue, bool bRestrictToExternalNmsp ) const { - switch (nFormulaPrefix) + // parse the attribute value, extract namespace ID, literal namespace, and formula string + rFormulaNmsp = OUString(); + sal_uInt16 nNsId = GetNamespaceMap()._GetKeyByAttrName( rAttrValue, 0, &rFormula, &rFormulaNmsp, sal_False ); + + // check if we have an ODF formula namespace + if( !bRestrictToExternalNmsp ) switch( nNsId ) { - case XML_NAMESPACE_OF: - rGrammar = formula::FormulaGrammar::GRAM_ODFF; - return true; - case XML_NAMESPACE_OOOC: - rGrammar = formula::FormulaGrammar::GRAM_PODF; - return true; + case XML_NAMESPACE_OOOC: + rFormulaNmsp = OUString(); // remove namespace string for built-in grammar + reGrammar = FormulaGrammar::GRAM_PODF; + return; + case XML_NAMESPACE_OF: + rFormulaNmsp = OUString(); // remove namespace string for built-in grammar + reGrammar = FormulaGrammar::GRAM_ODFF; + return; } - // An invalid namespace can occur from a colon in the formula text if no - // namespace tag was added. First character in string has to be '=' in that - // case. - bool bNoNamespace = (nFormulaPrefix == XML_NAMESPACE_NONE || - (nFormulaPrefix == XML_NAMESPACE_UNKNOWN && rValue.toChar() == '=')); - - if (bNoNamespace && eStorageGrammar == formula::FormulaGrammar::GRAM_PODF) - // There may be documents in the wild that stored no namespace in ODF 1.x - rGrammar = formula::FormulaGrammar::GRAM_PODF; - else if (bNoNamespace) - // The default for ODF 1.2 and later without namespace is 'of:' ODFF - rGrammar = formula::FormulaGrammar::GRAM_ODFF; - else - // Whatever ... - rGrammar = eStorageGrammar; + /* Find default grammar for formulas without namespace. There may be + documents in the wild that stored no namespace in ODF 1.0/1.1. Use + GRAM_PODF then (old style ODF 1.0/1.1 formulas). The default for ODF + 1.2 and later without namespace is GRAM_ODFF (OpenFormula). */ + FormulaGrammar::Grammar eDefaultGrammar = + (GetDocument()->GetStorageGrammar() == FormulaGrammar::GRAM_PODF) ? + FormulaGrammar::GRAM_PODF : FormulaGrammar::GRAM_ODFF; + + /* Check if we have no namespace at all. The value XML_NAMESPACE_NONE + indicates that there is no colon. If the first character of the + attribute value is the equality sign, the value XML_NAMESPACE_UNKNOWN + indicates that there is a colon somewhere in the formula string. */ + if( (nNsId == XML_NAMESPACE_NONE) || ((nNsId == XML_NAMESPACE_UNKNOWN) && (rAttrValue.toChar() == '=')) ) + { + rFormula = rAttrValue; // return entire string as formula + reGrammar = eDefaultGrammar; + return; + } - return false; + /* Check if a namespace URL could be resolved from the attribute value. + Use that namespace only, if the Calc document knows an associated + external formula parser. This prevents that the range operator in + conjunction with defined names is confused as namespaces prefix, e.g. + in the expression 'table:A1' where 'table' is a named reference. */ + if( ((nNsId & XML_NAMESPACE_UNKNOWN_FLAG) != 0) && (rFormulaNmsp.getLength() > 0) && + GetDocument()->GetFormulaParserPool().hasFormulaParser( rFormulaNmsp ) ) + { + reGrammar = FormulaGrammar::GRAM_EXTERNAL; + return; + } + + /* All attempts failed (e.g. no namespace and no leading equality sign, or + an invalid namespace prefix), continue with the entire attribute value. */ + rFormula = rAttrValue; + rFormulaNmsp = OUString(); // remove any namespace string + reGrammar = eDefaultGrammar; } + diff --git a/sc/source/filter/xml/xmlimprt.hxx b/sc/source/filter/xml/xmlimprt.hxx index 108138c9a016..f96d34c40ca5 100644 --- a/sc/source/filter/xml/xmlimprt.hxx +++ b/sc/source/filter/xml/xmlimprt.hxx @@ -598,6 +598,7 @@ struct ScMyNamedExpression { rtl::OUString sName; rtl::OUString sContent; + rtl::OUString sContentNmsp; rtl::OUString sBaseCellAddress; rtl::OUString sRangeType; formula::FormulaGrammar::Grammar eGrammar; @@ -624,11 +625,14 @@ struct ScMyImportValidation rtl::OUString sErrorMessage; rtl::OUString sFormula1; rtl::OUString sFormula2; + rtl::OUString sFormulaNmsp1; + rtl::OUString sFormulaNmsp2; rtl::OUString sBaseCellAddress; // #b4974740# string is used directly com::sun::star::sheet::ValidationAlertStyle aAlertStyle; com::sun::star::sheet::ValidationType aValidationType; com::sun::star::sheet::ConditionOperator aOperator; - formula::FormulaGrammar::Grammar eGrammar; + formula::FormulaGrammar::Grammar eGrammar1; + formula::FormulaGrammar::Grammar eGrammar2; sal_Int16 nShowList; sal_Bool bShowErrorMessage; sal_Bool bShowImputMessage; @@ -984,46 +988,42 @@ public: void AddDefaultNote( const com::sun::star::table::CellAddress& aCell ); sal_Int32 GetVisibleSheet(); - - /** If namespace prefix is an accepted formula namespace. - - For an accepted namespace (return <TRUE/>), the formula text is the - part without the namespace tag (aFormula of the _GetKeyByAttrName() - example below). - - For an invalid namespace (not defined in the file, - XML_NAMESPACE_UNKNOWN; may also be the result of no namespace with - colon in the formula text, in that case text has to start with - character '=') or no namespace tag (XML_NAMESPACE_NONE) the full text - (rValue) should be used (return <FALSE/>). - - @param nFormulaPrefix - The result of a _GetKeyByAttrName( rValue, aFormula, sal_False) - call. - - @param rValue - The attribute's string (formula text) including the namespace, if - any. - - @param rGrammar - Return value set toformula::FormulaGrammar::GRAM_ODFF orformula::FormulaGrammar::GRAM_PODF or - eStorageGrammar, according to the namespace or absence thereof - encountered. - - @param eStorageGrammar - Default storage grammar of the document,formula::FormulaGrammar::GRAM_ODFF for - ODF 1.2 and later documents,formula::FormulaGrammar::GRAM_PODF for ODF 1.x - documents. - - @return - <TRUE/> if an accepted namespace (XML_NAMESPACE_OF or - XML_NAMESPACE_OOOC), else <FALSE/>. + /** Extracts the formula string, the formula grammar namespace URL, and a + grammar enum value from the passed formula attribute value. + + @param rFormula + (out-parameter) Returns the plain formula string with the leading + equality sign if existing. + + @param rFormulaNmsp + (out-parameter) Returns the URL of the formula grammar namespace if + the attribute value contains the prefix of an unknown namespace. + + @param reGrammar + (out-parameter) Returns the exact formula grammar if the formula + is in a supported ODF format (e.g. FormulaGrammar::GRAM_PODF for + ODF 1.0/1.1 formulas, or FormulaGrammar::GRAM_ODFF for ODF 1.2 + formulas a.k.a. OpenFormula). Returns the default storage grammar, + if the attribute value does not contain a namespace prefix. Returns + the special value FormulaGrammar::GRAM_EXTERNAL, if an unknown + namespace could be extracted from the formula which will be + contained in the parameter rFormulaNmsp then. + + @param rAttrValue + The value of the processed formula attribute. + + @param bRestrictToExternalNmsp + If set to TRUE, only namespaces of external formula grammars will + be recognized. Internal namespace prefixes (e.g. 'oooc:' or 'of:' + will be considered to be part of the formula, e.g. an expression + with range operator. */ - - static bool IsAcceptedFormulaNamespace( const sal_uInt16 nFormulaPrefix, - const rtl::OUString & rValue, formula::FormulaGrammar::Grammar& rGrammar, - const formula::FormulaGrammar::Grammar eStorageGrammar ); - + void ExtractFormulaNamespaceGrammar( + ::rtl::OUString& rFormula, + ::rtl::OUString& rFormulaNmsp, + ::formula::FormulaGrammar::Grammar& reGrammar, + const ::rtl::OUString& rAttrValue, + bool bRestrictToExternalNmsp = false ) const; }; #endif diff --git a/sc/source/filter/xml/xmlnexpi.cxx b/sc/source/filter/xml/xmlnexpi.cxx index 3f822d5274c6..9a2a49f0b021 100644 --- a/sc/source/filter/xml/xmlnexpi.cxx +++ b/sc/source/filter/xml/xmlnexpi.cxx @@ -196,8 +196,6 @@ ScXMLNamedExpressionContext::ScXMLNamedExpressionContext( ScXMLImport& rImport, SvXMLImportContext( rImport, nPrfx, rLName ) { ScMyNamedExpression* pNamedExpression(new ScMyNamedExpression); - const formula::FormulaGrammar::Grammar eStorageGrammar = pNamedExpression->eGrammar = - GetScImport().GetDocument()->GetStorageGrammar(); sal_Int16 nAttrCount(xAttrList.is() ? xAttrList->getLength() : 0); const SvXMLTokenMap& rAttrTokenMap(GetScImport().GetNamedExpressionAttrTokenMap()); for( sal_Int16 i=0; i < nAttrCount; ++i ) @@ -217,16 +215,9 @@ ScXMLNamedExpressionContext::ScXMLNamedExpressionContext( ScXMLImport& rImport, break; case XML_TOK_NAMED_EXPRESSION_ATTR_EXPRESSION : { - rtl::OUString sFormula; - sal_uInt16 nFormulaPrefix = GetImport().GetNamespaceMap(). - _GetKeyByAttrName( sValue, &sFormula, sal_False ); - - if (ScXMLImport::IsAcceptedFormulaNamespace( nFormulaPrefix, - sValue, pNamedExpression->eGrammar, - eStorageGrammar)) - pNamedExpression->sContent = sFormula; - else - pNamedExpression->sContent = sValue; + GetScImport().ExtractFormulaNamespaceGrammar( + pNamedExpression->sContent, pNamedExpression->sContentNmsp, + pNamedExpression->eGrammar, sValue ); } break; case XML_TOK_NAMED_EXPRESSION_ATTR_BASE_CELL_ADDRESS : diff --git a/sc/source/filter/xml/xmlstyli.cxx b/sc/source/filter/xml/xmlstyli.cxx index 3b411df8db08..79ba79f0e689 100644 --- a/sc/source/filter/xml/xmlstyli.cxx +++ b/sc/source/filter/xml/xmlstyli.cxx @@ -73,6 +73,7 @@ using namespace ::com::sun::star::beans; using namespace ::com::sun::star::container; using namespace xmloff::token; //using namespace ::com::sun::star::text; +using namespace ::formula; ScXMLCellImportPropertyMapper::ScXMLCellImportPropertyMapper( const UniReference< XMLPropertySetMapper >& rMapper, @@ -285,10 +286,7 @@ public: ScXMLMapContext::ScXMLMapContext(SvXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName, const uno::Reference< xml::sax::XAttributeList > & xAttrList ) - : SvXMLImportContext( rImport, nPrfx, rLName ), - sApplyStyle(), - sCondition(), - sBaseCell() + : SvXMLImportContext( rImport, nPrfx, rLName ) { sal_Int16 nAttrCount(xAttrList.is() ? xAttrList->getLength() : 0); for( sal_Int16 i=0; i < nAttrCount; ++i ) @@ -315,200 +313,118 @@ ScXMLMapContext::~ScXMLMapContext() { } -void XMLTableStyleContext::SetOperator(com::sun::star::uno::Sequence<beans::PropertyValue>& aProps, - const com::sun::star::sheet::ConditionOperator aOp) const -{ - sal_Int32 nLength(aProps.getLength()); - aProps.realloc(nLength + 1); - aProps[nLength].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_OPERATOR)); - aProps[nLength].Value <<= aOp; -} +namespace { -void XMLTableStyleContext::SetBaseCellAddress(com::sun::star::uno::Sequence<beans::PropertyValue>& aProps, - const rtl::OUString& sBaseCell) const +template< typename Type > +inline void lclAppendProperty( uno::Sequence< beans::PropertyValue >& rProps, const OUString& rPropName, const Type& rValue ) { - sal_Int32 nLength(aProps.getLength()); - aProps.realloc(nLength + 1); - - // #b4974740# source position must be set as string, because it may - // refer to a sheet that hasn't been loaded yet. - - aProps[nLength].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_SOURCESTR)); - aProps[nLength].Value <<= sBaseCell; + sal_Int32 nLength = rProps.getLength(); + rProps.realloc( nLength + 1 ); + rProps[ nLength ].Name = rPropName; + rProps[ nLength ].Value <<= rValue; } -void XMLTableStyleContext::SetStyle(com::sun::star::uno::Sequence<beans::PropertyValue>& aProps, - const rtl::OUString& sApplyStyle) const +} // namespace + +void XMLTableStyleContext::SetOperator( uno::Sequence< beans::PropertyValue >& rProps, sheet::ConditionOperator eOp ) const { - sal_Int32 nLength(aProps.getLength()); - aProps.realloc(nLength + 1); - aProps[nLength].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_STYLENAME)); - aProps[nLength].Value <<= sApplyStyle; + lclAppendProperty( rProps, OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_OPERATOR ) ), eOp ); } -void XMLTableStyleContext::SetFormula1(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& aProps, - const rtl::OUString& sFormula, bool bPreParse) const +void XMLTableStyleContext::SetBaseCellAddress( uno::Sequence< beans::PropertyValue >& rProps, const OUString& rBaseCell ) const { - sal_Int32 nLength(aProps.getLength()); - aProps.realloc(nLength + 1); - aProps[nLength].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_FORMULA1)); - if (bPreParse) - { - rtl::OUString sRealFormula(sFormula); - ScXMLConverter::ParseFormula(sRealFormula); - aProps[nLength].Value <<= sRealFormula; - } - else - aProps[nLength].Value <<= sFormula; + /* #b4974740# Source position must be set as string, because it may refer + to a sheet that hasn't been loaded yet. */ + lclAppendProperty( rProps, OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_SOURCESTR ) ), rBaseCell ); } -void XMLTableStyleContext::SetFormula2(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& aProps, - const rtl::OUString& sFormula) const +void XMLTableStyleContext::SetStyle( uno::Sequence<beans::PropertyValue>& rProps, const OUString& rApplyStyle ) const { - sal_Int32 nLength(aProps.getLength()); - aProps.realloc(nLength + 1); - aProps[nLength].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_FORMULA2)); - rtl::OUString sRealFormula(sFormula); - ScXMLConverter::ParseFormula(sRealFormula); - aProps[nLength].Value <<= sRealFormula; + lclAppendProperty( rProps, OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_STYLENAME ) ), rApplyStyle ); } -void XMLTableStyleContext::SetFormulas(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& aProps, - const rtl::OUString& sFormulas) const +void XMLTableStyleContext::SetFormula( uno::Sequence< beans::PropertyValue >& rProps, + sal_Int32 nFormulaIdx, const OUString& rFormula, const OUString& rFormulaNmsp, + FormulaGrammar::Grammar eGrammar, bool bHasNmsp ) const { - sal_Int32 i(0); - sal_Bool bString(sal_False); - sal_Int32 nBrakes(0); - while ((sFormulas[i] != ',' || nBrakes > 0 || bString) && i < sFormulas.getLength()) + OUString aFormula, aFormulaNmsp; + FormulaGrammar::Grammar eNewGrammar = FormulaGrammar::GRAM_UNSPECIFIED; + if( bHasNmsp ) { - if (sFormulas[i] == '(') - ++nBrakes; - if (sFormulas[i] == ')') - --nBrakes; - if (sFormulas[i] == '"') - bString = !bString; - ++i; + // the entire attribute contains a namespace: internal namespace not allowed + aFormula = rFormula; + aFormulaNmsp = rFormulaNmsp; + eNewGrammar = eGrammar; } - if (sFormulas[i] == ',') + else { - rtl::OUString sFormula1(sFormulas.copy(0, i)); - rtl::OUString sFormula2(sFormulas.copy(i + 1)); - SetFormula1(aProps, sFormula1); - SetFormula2(aProps, sFormula2); + // the attribute does not contain a namespace: try to find a namespace of an external grammar + GetScImport().ExtractFormulaNamespaceGrammar( aFormula, aFormulaNmsp, eNewGrammar, rFormula, true ); + if( eNewGrammar != FormulaGrammar::GRAM_EXTERNAL ) + eNewGrammar = eGrammar; } -} -void XMLTableStyleContext::SetGrammar(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& aProps, - const formula::FormulaGrammar::Grammar eGrammar) const -{ - sal_Int32 nLength(aProps.getLength()); - aProps.realloc(nLength + 1); - aProps[nLength].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_GRAMMAR)); - aProps[nLength].Value <<= static_cast<sal_Int32>(eGrammar); + // add formula, formula namespace, and grammar with appropriate property names + sal_Int32 nGrammar = static_cast< sal_Int32 >( eNewGrammar ); + switch( nFormulaIdx ) + { + case 1: + lclAppendProperty( rProps, OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_FORMULA1 ) ), aFormula ); + lclAppendProperty( rProps, OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_FORMULANMSP1 ) ), aFormulaNmsp ); + lclAppendProperty( rProps, OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_GRAMMAR1 ) ), nGrammar ); + break; + case 2: + lclAppendProperty( rProps, OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_FORMULA2 ) ), aFormula ); + lclAppendProperty( rProps, OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_FORMULANMSP2 ) ), aFormulaNmsp ); + lclAppendProperty( rProps, OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_GRAMMAR2 ) ), nGrammar ); + break; + default: + OSL_ENSURE( false, "XMLTableStyleContext::SetFormula - invalid formula index" ); + } } void XMLTableStyleContext::GetConditionalFormat(uno::Any& aAny, const rtl::OUString& sTempCondition, const rtl::OUString& sApplyStyle, const rtl::OUString& sBaseCell) const { - rtl::OUString sCondition(sTempCondition); - if (sCondition.getLength() && sApplyStyle.getLength()) + if (sTempCondition.getLength() && sApplyStyle.getLength()) { uno::Reference<sheet::XSheetConditionalEntries> xConditionalEntries(aAny, uno::UNO_QUERY); if (xConditionalEntries.is()) { - const formula::FormulaGrammar::Grammar eStorageGrammar = GetScImport().GetDocument()->GetStorageGrammar(); - formula::FormulaGrammar::Grammar eGrammar = eStorageGrammar; - // ToDo: erase all blanks in the condition, but not in formulas or strings - rtl::OUString scell_content(RTL_CONSTASCII_USTRINGPARAM("cell_content")); - rtl::OUString scell_content_is_between(RTL_CONSTASCII_USTRINGPARAM("cell_content_is_between")); - rtl::OUString scell_content_is_not_between(RTL_CONSTASCII_USTRINGPARAM("cell_content_is_not_between")); - rtl::OUString sis_true_formula(RTL_CONSTASCII_USTRINGPARAM("is_true_formula")); uno::Sequence<beans::PropertyValue> aProps; if (sBaseCell.getLength()) SetBaseCellAddress(aProps, sBaseCell); SetStyle(aProps, sApplyStyle); - sal_Int32 i = 0; - while (sCondition[i] != '(' && i < sCondition.getLength()) - ++i; - if (sCondition[i] == '(') + + // extract leading namespace from condition string + OUString aCondition, aConditionNmsp; + FormulaGrammar::Grammar eGrammar = FormulaGrammar::GRAM_UNSPECIFIED; + GetScImport().ExtractFormulaNamespaceGrammar( aCondition, aConditionNmsp, eGrammar, sTempCondition ); + bool bHasNmsp = aCondition.getLength() < sTempCondition.getLength(); + + // parse a condition from the attribute string + ScXMLConditionParseResult aParseResult; + ScXMLConditionHelper::parseCondition( aParseResult, aCondition, 0 ); + + /* Check the result. A valid value in aParseResult.meToken implies + that the other members of aParseResult are filled with valid + data for that token. */ + switch( aParseResult.meToken ) { - sCondition = sCondition.copy(i + 1); - if (i == scell_content.getLength()) - { - sCondition = sCondition.copy(1); - switch (sCondition[0]) - { - case '<' : - { - if (sCondition[1] == '=') - { - SetOperator(aProps, sheet::ConditionOperator_LESS_EQUAL); - sCondition = sCondition.copy(2); - } - else - { - SetOperator(aProps, sheet::ConditionOperator_LESS); - sCondition = sCondition.copy(1); - } - } - break; - case '>' : - { - if (sCondition[1] == '=') - { - SetOperator(aProps, sheet::ConditionOperator_GREATER_EQUAL); - sCondition = sCondition.copy(2); - } - else - { - SetOperator(aProps, sheet::ConditionOperator_GREATER); - sCondition = sCondition.copy(1); - } - } - break; - case '=' : - { - SetOperator(aProps, sheet::ConditionOperator_EQUAL); - sCondition = sCondition.copy(1); - } - break; - case '!' : - { - SetOperator(aProps, sheet::ConditionOperator_NOT_EQUAL); - sCondition = sCondition.copy(1); - } - break; - } - SetFormula1(aProps, sCondition); - } - else if (i == scell_content_is_between.getLength()) - { - SetOperator(aProps, sheet::ConditionOperator_BETWEEN); - sCondition = sCondition.copy(0, sCondition.getLength() - 1); - SetFormulas(aProps, sCondition); - } - else if (i == scell_content_is_not_between.getLength()) - { - SetOperator(aProps, sheet::ConditionOperator_NOT_BETWEEN); - sCondition = sCondition.copy(0, sCondition.getLength() - 1); - SetFormulas(aProps, sCondition); - } - else if (i == sis_true_formula.getLength()) - { - SetOperator(aProps, sheet::ConditionOperator_FORMULA); - sCondition = sCondition.copy(0, sCondition.getLength() - 1); - rtl::OUString sFormula; - sal_uInt16 nFormulaPrefix = GetImport().GetNamespaceMap(). - _GetKeyByAttrName( sCondition, &sFormula, sal_False ); - if (ScXMLImport::IsAcceptedFormulaNamespace( nFormulaPrefix, - sCondition, eGrammar, eStorageGrammar)) - sCondition = sFormula; - SetFormula1(aProps, sCondition, false); - } + case XML_COND_CELLCONTENT: // condition is 'cell-content()<operator><expression>' + case XML_COND_ISTRUEFORMULA: // condition is 'is-true-formula(<expression>)' + case XML_COND_ISBETWEEN: // condition is 'cell-content-is-between(<expression1>,<expression2>)' + case XML_COND_ISNOTBETWEEN: // condition is 'cell-content-is-not-between(<expression1>,<expression2>)' + SetOperator( aProps, aParseResult.meOperator ); + SetFormula( aProps, 1, aParseResult.maOperand1, aConditionNmsp, eGrammar, bHasNmsp ); + SetFormula( aProps, 2, aParseResult.maOperand2, aConditionNmsp, eGrammar, bHasNmsp ); + break; + + default:; // unacceptable or unknown condition } - SetGrammar( aProps, eGrammar); - xConditionalEntries->addNew(aProps); + + xConditionalEntries->addNew( aProps ); aAny <<= xConditionalEntries; } } diff --git a/sc/source/filter/xml/xmlstyli.hxx b/sc/source/filter/xml/xmlstyli.hxx index 4d80f5710ac9..272ec0151134 100644 --- a/sc/source/filter/xml/xmlstyli.hxx +++ b/sc/source/filter/xml/xmlstyli.hxx @@ -107,20 +107,22 @@ class XMLTableStyleContext : public XMLPropStyleContext const ScXMLImport& GetScImport() const { return (const ScXMLImport&)GetImport(); } ScXMLImport& GetScImport() { return (ScXMLImport&)GetImport(); } - void SetOperator(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& aProps, - const com::sun::star::sheet::ConditionOperator aOp) const; - void SetBaseCellAddress(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& aProps, - const rtl::OUString& sBaseCell) const; - void SetStyle(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& aProps, - const rtl::OUString& sApplyStyle) const; - void SetFormula1(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& aProps, - const rtl::OUString& sFormula, bool bPreParse = true) const; - void SetFormula2(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& aProps, - const rtl::OUString& sFormula) const; - void SetFormulas(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& aProps, - const rtl::OUString& sFormulas) const; - void SetGrammar(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue>& aProps, - const formula::FormulaGrammar::Grammar eGrammar) const; + void SetOperator( + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rProps, + ::com::sun::star::sheet::ConditionOperator eOp ) const; + + void SetBaseCellAddress( + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rProps, + const ::rtl::OUString& rBaseCell ) const; + + void SetStyle( + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rProps, + const ::rtl::OUString& rApplyStyle ) const; + + void SetFormula( + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rProps, + sal_Int32 nFormulaIdx, const ::rtl::OUString& rFormula, + const ::rtl::OUString& rFormulaNmsp, ::formula::FormulaGrammar::Grammar eGrammar, bool bHasNmsp ) const; void GetConditionalFormat( ::com::sun::star::uno::Any& aAny, const rtl::OUString& sCondition, diff --git a/sc/source/filter/xml/xmlsubti.cxx b/sc/source/filter/xml/xmlsubti.cxx index 0eb74bf11218..231839b9f946 100644 --- a/sc/source/filter/xml/xmlsubti.cxx +++ b/sc/source/filter/xml/xmlsubti.cxx @@ -641,7 +641,7 @@ void ScMyTables::DeleteTable() ScMyMatrixRangeList::iterator aEndItr = aMatrixRangeList.end(); while(aItr != aEndItr) { - SetMatrix(aItr->aRange, aItr->sFormula, aItr->eGrammar); + SetMatrix(aItr->aRange, aItr->sFormula, aItr->sFormulaNmsp, aItr->eGrammar); ++aItr; } aMatrixRangeList.clear(); @@ -755,7 +755,9 @@ void ScMyTables::AddShape(uno::Reference <drawing::XShape>& rShape, aResizeShapes.AddShape(rShape, pRangeList, rStartAddress, rEndAddress, nEndX, nEndY); } -void ScMyTables::AddMatrixRange(sal_Int32 nStartColumn, sal_Int32 nStartRow, sal_Int32 nEndColumn, sal_Int32 nEndRow, const rtl::OUString& rFormula, const formula::FormulaGrammar::Grammar eGrammar) +void ScMyTables::AddMatrixRange( + sal_Int32 nStartColumn, sal_Int32 nStartRow, sal_Int32 nEndColumn, sal_Int32 nEndRow, + const rtl::OUString& rFormula, const rtl::OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar) { DBG_ASSERT(nEndRow >= nStartRow, "wrong row order"); DBG_ASSERT(nEndColumn >= nStartColumn, "wrong column order"); @@ -765,7 +767,7 @@ void ScMyTables::AddMatrixRange(sal_Int32 nStartColumn, sal_Int32 nStartRow, sal aRange.EndColumn = nEndColumn; aRange.EndRow = nEndRow; aRange.Sheet = sal::static_int_cast<sal_Int16>(nCurrentSheet); - ScMatrixRange aMRange(aRange, rFormula, eGrammar); + ScMatrixRange aMRange(aRange, rFormula, rFormulaNmsp, eGrammar); aMatrixRangeList.push_back(aMRange); } @@ -786,7 +788,7 @@ sal_Bool ScMyTables::IsPartOfMatrix(sal_Int32 nColumn, sal_Int32 nRow) } else if ((nRow > aItr->aRange.EndRow) && (nColumn > aItr->aRange.EndColumn)) { - SetMatrix(aItr->aRange, aItr->sFormula, aItr->eGrammar); + SetMatrix(aItr->aRange, aItr->sFormula, aItr->sFormulaNmsp, aItr->eGrammar); aItr = aMatrixRangeList.erase(aItr); } else if (nColumn < aItr->aRange.StartColumn) @@ -803,7 +805,8 @@ sal_Bool ScMyTables::IsPartOfMatrix(sal_Int32 nColumn, sal_Int32 nRow) return bResult; } -void ScMyTables::SetMatrix(const table::CellRangeAddress& rRange, const rtl::OUString& rFormula, const formula::FormulaGrammar::Grammar eGrammar) +void ScMyTables::SetMatrix(const table::CellRangeAddress& rRange, const rtl::OUString& rFormula, + const rtl::OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar) { uno::Reference <table::XCellRange> xMatrixCellRange( GetCurrentXCellRange()->getCellRangeByPosition(rRange.StartColumn, rRange.StartRow, @@ -817,7 +820,7 @@ void ScMyTables::SetMatrix(const table::CellRangeAddress& rRange, const rtl::OUS static_cast<ScCellRangeObj*>(ScCellRangesBase::getImplementation( xMatrixCellRange)); if (pCellRangeObj) - pCellRangeObj->SetArrayFormulaWithGrammar( rFormula, eGrammar); + pCellRangeObj->SetArrayFormulaWithGrammar( rFormula, rFormulaNmsp, eGrammar); } } } diff --git a/sc/source/filter/xml/xmlsubti.hxx b/sc/source/filter/xml/xmlsubti.hxx index 84a07ff90449..c5a16e2c3ef4 100644 --- a/sc/source/filter/xml/xmlsubti.hxx +++ b/sc/source/filter/xml/xmlsubti.hxx @@ -97,10 +97,12 @@ public: struct ScMatrixRange { rtl::OUString sFormula; + rtl::OUString sFormulaNmsp; formula::FormulaGrammar::Grammar eGrammar; com::sun::star::table::CellRangeAddress aRange; - ScMatrixRange(const com::sun::star::table::CellRangeAddress& rRange, const rtl::OUString& rFormula, const formula::FormulaGrammar::Grammar eGrammarP) : + ScMatrixRange(const com::sun::star::table::CellRangeAddress& rRange, const rtl::OUString& rFormula, const rtl::OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammarP) : sFormula(rFormula), + sFormulaNmsp(rFormulaNmsp), eGrammar(eGrammarP), aRange(rRange) { @@ -181,11 +183,13 @@ public: sal_Int32 nEndColumn, sal_Int32 nEndRow, const rtl::OUString& rFormula, + const rtl::OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar ); sal_Bool IsPartOfMatrix(sal_Int32 nColumn, sal_Int32 nRow); void SetMatrix( const com::sun::star::table::CellRangeAddress& rRange, const rtl::OUString& rFormula, + const rtl::OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar ); }; diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx index 15f9f751338c..ebb080a89cfa 100644 --- a/sc/source/ui/docshell/docfunc.cxx +++ b/sc/source/ui/docshell/docfunc.cxx @@ -960,16 +960,18 @@ BOOL ScDocFunc::PutData( const ScAddress& rPos, ScEditEngineDefaulter& rEngine, } -ScTokenArray* lcl_ScDocFunc_CreateTokenArrayXML( const String& rText ) +ScTokenArray* lcl_ScDocFunc_CreateTokenArrayXML( const String& rText, const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) { ScTokenArray* pCode = new ScTokenArray; pCode->AddString( rText ); + if( (eGrammar == formula::FormulaGrammar::GRAM_EXTERNAL) && (rFormulaNmsp.Len() > 0) ) + pCode->AddString( rFormulaNmsp ); return pCode; } ScBaseCell* ScDocFunc::InterpretEnglishString( const ScAddress& rPos, - const String& rText, const formula::FormulaGrammar::Grammar eGrammar ) + const String& rText, const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) { ScDocument* pDoc = rDocShell.GetDocument(); ScBaseCell* pNewCell = NULL; @@ -979,7 +981,7 @@ ScBaseCell* ScDocFunc::InterpretEnglishString( const ScAddress& rPos, ScTokenArray* pCode; if ( pDoc->IsImportingXML() ) { // temporary formula string as string tokens - pCode = lcl_ScDocFunc_CreateTokenArrayXML( rText ); + pCode = lcl_ScDocFunc_CreateTokenArrayXML( rText, rFormulaNmsp, eGrammar ); pDoc->IncXMLImportedFormulaCount( rText.Len() ); } else @@ -1016,8 +1018,8 @@ ScBaseCell* ScDocFunc::InterpretEnglishString( const ScAddress& rPos, BOOL ScDocFunc::SetCellText( const ScAddress& rPos, const String& rText, - BOOL bInterpret, BOOL bEnglish, BOOL bApi, - const formula::FormulaGrammar::Grammar eGrammar ) + BOOL bInterpret, BOOL bEnglish, BOOL bApi, + const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) { // SetCellText ruft PutCell oder SetNormalString @@ -1030,12 +1032,15 @@ BOOL ScDocFunc::SetCellText( const ScAddress& rPos, const String& rText, // code moved to own method InterpretEnglishString because it is also used in // ScCellRangeObj::setFormulaArray - pNewCell = InterpretEnglishString( rPos, rText, eGrammar ); + pNewCell = InterpretEnglishString( rPos, rText, rFormulaNmsp, eGrammar ); } // sonst Null behalten -> SetString mit lokalen Formeln/Zahlformat } else if ( rText.Len() ) + { + OSL_ENSURE( rFormulaNmsp.Len() == 0, "ScDocFunc::SetCellText - formula namespace, but do not interpret?" ); pNewCell = ScBaseCell::CreateTextCell( rText, pDoc ); // immer Text + } if (pNewCell) return PutCell( rPos, pNewCell, bApi ); @@ -3516,9 +3521,8 @@ BOOL ScDocFunc::AutoFormat( const ScRange& rRange, const ScMarkData* pTabMark, //------------------------------------------------------------------------ BOOL ScDocFunc::EnterMatrix( const ScRange& rRange, const ScMarkData* pTabMark, - const ScTokenArray* pTokenArray, - const String& rString, BOOL bApi, BOOL bEnglish, - const formula::FormulaGrammar::Grammar eGrammar ) + const ScTokenArray* pTokenArray, const String& rString, BOOL bApi, BOOL bEnglish, + const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) { ScDocShellModificator aModificator( rDocShell ); @@ -3565,7 +3569,7 @@ BOOL ScDocFunc::EnterMatrix( const ScRange& rRange, const ScMarkData* pTabMark, } else if ( pDoc->IsImportingXML() ) { - ScTokenArray* pCode = lcl_ScDocFunc_CreateTokenArrayXML( rString ); + ScTokenArray* pCode = lcl_ScDocFunc_CreateTokenArrayXML( rString, rFormulaNmsp, eGrammar ); pDoc->InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow, aMark, EMPTY_STRING, pCode, eGrammar); delete pCode; @@ -4495,11 +4499,11 @@ BOOL ScDocFunc::ResizeMatrix( const ScRange& rOldRange, const ScAddress& rNewEnd if ( DeleteContents( aMark, IDF_CONTENTS, TRUE, bApi ) ) { // GRAM_PODF_A1 for API compatibility. - bRet = EnterMatrix( aNewRange, &aMark, NULL, aFormula, bApi, FALSE,formula::FormulaGrammar::GRAM_PODF_A1 ); + bRet = EnterMatrix( aNewRange, &aMark, NULL, aFormula, bApi, FALSE, EMPTY_STRING, formula::FormulaGrammar::GRAM_PODF_A1 ); if (!bRet) { // versuchen, alten Zustand wiederherzustellen - EnterMatrix( rOldRange, &aMark, NULL, aFormula, bApi, FALSE,formula::FormulaGrammar::GRAM_PODF_A1 ); + EnterMatrix( rOldRange, &aMark, NULL, aFormula, bApi, FALSE, EMPTY_STRING, formula::FormulaGrammar::GRAM_PODF_A1 ); } } diff --git a/sc/source/ui/docshell/docsh3.cxx b/sc/source/ui/docshell/docsh3.cxx index fcdfa8612a02..fcbfb648ae14 100644 --- a/sc/source/ui/docshell/docsh3.cxx +++ b/sc/source/ui/docshell/docsh3.cxx @@ -1051,8 +1051,8 @@ void ScDocShell::MergeDocument( ScDocument& rOtherDoc, bool bShared, bool bCheck aValue.Erase( 0, 1 ); aValue.Erase( aValue.Len()-1, 1 ); GetDocFunc().EnterMatrix( aSourceRange, - NULL, NULL, aValue, FALSE, FALSE, - formula::FormulaGrammar::GRAM_DEFAULT ); + NULL, NULL, aValue, FALSE, FALSE, + EMPTY_STRING, formula::FormulaGrammar::GRAM_DEFAULT ); } break; case MM_REFERENCE : // do nothing diff --git a/sc/source/ui/formdlg/formula.cxx b/sc/source/ui/formdlg/formula.cxx index 4544c1ca0792..8d631a9f0609 100644 --- a/sc/source/ui/formdlg/formula.cxx +++ b/sc/source/ui/formdlg/formula.cxx @@ -126,7 +126,6 @@ ScFormulaDlg::ScFormulaDlg( SfxBindings* pB, SfxChildWindow* pCW, m_xParser.set(ScServiceProvider::MakeInstance(SC_SERVICE_FORMULAPARS,(ScDocShell*)pDoc->GetDocumentShell()),uno::UNO_QUERY); uno::Reference< beans::XPropertySet> xSet(m_xParser,uno::UNO_QUERY); xSet->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNO_COMPILEFAP)),uno::makeAny(sal_True)); - xSet->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNO_REFERENCEPOS)),uno::makeAny(table::CellAddress(aCursorPos.Tab(),aCursorPos.Col(),aCursorPos.Row()))); m_xOpCodeMapper.set(ScServiceProvider::MakeInstance(SC_SERVICE_OPCODEMAPPER,(ScDocShell*)pDoc->GetDocumentShell()),uno::UNO_QUERY); @@ -657,6 +656,12 @@ uno::Reference< sheet::XFormulaOpCodeMapper> ScFormulaDlg::getFormulaOpCodeMappe { return m_xOpCodeMapper; } + +table::CellAddress ScFormulaDlg::getReferencePosition() const +{ + return table::CellAddress(aCursorPos.Tab(),aCursorPos.Col(),aCursorPos.Row()); +} + ::std::auto_ptr<formula::FormulaTokenArray> ScFormulaDlg::convertToTokenArray(const uno::Sequence< sheet::FormulaToken >& _aTokenList) { ::std::auto_ptr<formula::FormulaTokenArray> pArray(new ScTokenArray()); diff --git a/sc/source/ui/inc/docfunc.hxx b/sc/source/ui/inc/docfunc.hxx index 2457dc0611b4..21e295a58fa4 100644 --- a/sc/source/ui/inc/docfunc.hxx +++ b/sc/source/ui/inc/docfunc.hxx @@ -89,11 +89,12 @@ public: BOOL bInterpret, BOOL bApi ); BOOL SetCellText( const ScAddress& rPos, const String& rText, BOOL bInterpret, BOOL bEnglish, BOOL bApi, + const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ); // creates a new cell for use with PutCell ScBaseCell* InterpretEnglishString( const ScAddress& rPos, const String& rText, - const formula::FormulaGrammar::Grammar eGrammar ); + const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ); bool ShowNote( const ScAddress& rPos, bool bShow = true ); inline bool HideNote( const ScAddress& rPos ) { return ShowNote( rPos, false ); } @@ -147,6 +148,7 @@ public: BOOL EnterMatrix( const ScRange& rRange, const ScMarkData* pTabMark, const ScTokenArray* pTokenArray, const String& rString, BOOL bApi, BOOL bEnglish, + const String& rFormulaNmsp, const formula::FormulaGrammar::Grammar ); BOOL TabOp( const ScRange& rRange, const ScMarkData* pTabMark, diff --git a/sc/source/ui/inc/formula.hxx b/sc/source/ui/inc/formula.hxx index a40a6092fe26..b25811eb9220 100644 --- a/sc/source/ui/inc/formula.hxx +++ b/sc/source/ui/inc/formula.hxx @@ -105,6 +105,7 @@ public: virtual ::std::auto_ptr<formula::FormulaTokenArray> convertToTokenArray(const ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::FormulaToken >& _aTokenList); virtual ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XFormulaParser> getFormulaParser() const; virtual ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XFormulaOpCodeMapper> getFormulaOpCodeMapper() const; + virtual ::com::sun::star::table::CellAddress getReferencePosition() const; virtual BOOL Close(); diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx index 7674bbbf3042..cfe51aed6edc 100644 --- a/sc/source/ui/unoobj/cellsuno.cxx +++ b/sc/source/ui/unoobj/cellsuno.cxx @@ -1170,8 +1170,8 @@ BOOL lcl_PutDataArray( ScDocShell& rDocShell, const ScRange& rRange, } BOOL lcl_PutFormulaArray( ScDocShell& rDocShell, const ScRange& rRange, - const uno::Sequence< uno::Sequence<rtl::OUString> >& aData, - const formula::FormulaGrammar::Grammar eGrammar ) + const uno::Sequence< uno::Sequence<rtl::OUString> >& aData, + const ::rtl::OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) { // BOOL bApi = TRUE; @@ -1226,7 +1226,7 @@ BOOL lcl_PutFormulaArray( ScDocShell& rDocShell, const ScRange& rRange, { String aText(pColArr[nCol]); ScAddress aPos( nDocCol, nDocRow, nTab ); - ScBaseCell* pNewCell = aFunc.InterpretEnglishString( aPos, aText, eGrammar ); + ScBaseCell* pNewCell = aFunc.InterpretEnglishString( aPos, aText, rFormulaNmsp, eGrammar ); pDoc->PutCell( aPos, pNewCell ); ++nDocCol; @@ -5052,15 +5052,14 @@ rtl::OUString SAL_CALL ScCellRangeObj::getArrayFormula() throw(uno::RuntimeExcep return aFormula; } -void ScCellRangeObj::SetArrayFormula_Impl( const rtl::OUString& aFormula, - const formula::FormulaGrammar::Grammar eGrammar ) throw(uno::RuntimeException) +void ScCellRangeObj::SetArrayFormula_Impl( const rtl::OUString& rFormula, + const rtl::OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) throw(uno::RuntimeException) { ScDocShell* pDocSh = GetDocShell(); if (pDocSh) { - String aString(aFormula); ScDocFunc aFunc(*pDocSh); - if ( aString.Len() ) + if ( rFormula.getLength() ) { if ( ScTableSheetObj::getImplementation( (cppu::OWeakObject*)this ) ) { @@ -5068,7 +5067,7 @@ void ScCellRangeObj::SetArrayFormula_Impl( const rtl::OUString& aFormula, throw uno::RuntimeException(); } - aFunc.EnterMatrix( aRange, NULL, NULL, aString, TRUE, TRUE, eGrammar ); + aFunc.EnterMatrix( aRange, NULL, NULL, rFormula, TRUE, TRUE, rFormulaNmsp, eGrammar ); } else { @@ -5086,14 +5085,14 @@ void SAL_CALL ScCellRangeObj::setArrayFormula( const rtl::OUString& aFormula ) { ScUnoGuard aGuard; // GRAM_PODF_A1 for API compatibility. - SetArrayFormula_Impl( aFormula,formula::FormulaGrammar::GRAM_PODF_A1); + SetArrayFormula_Impl( aFormula, ::rtl::OUString(), formula::FormulaGrammar::GRAM_PODF_A1); } -void ScCellRangeObj::SetArrayFormulaWithGrammar( const rtl::OUString& aFormula, - const formula::FormulaGrammar::Grammar eGrammar ) throw(uno::RuntimeException) +void ScCellRangeObj::SetArrayFormulaWithGrammar( const rtl::OUString& rFormula, + const rtl::OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) throw(uno::RuntimeException) { ScUnoGuard aGuard; - SetArrayFormula_Impl( aFormula, eGrammar); + SetArrayFormula_Impl( rFormula, rFormulaNmsp, eGrammar); } // XArrayFormulaTokens @@ -5153,7 +5152,7 @@ void SAL_CALL ScCellRangeObj::setArrayTokens( const uno::Sequence<sheet::Formula // Actually GRAM_PODF_A1 is a don't-care here because of the token // array being set, it fits with other API compatibility grammars // though. - aFunc.EnterMatrix( aRange, NULL, &aTokenArray, EMPTY_STRING, TRUE, TRUE,formula::FormulaGrammar::GRAM_PODF_A1 ); + aFunc.EnterMatrix( aRange, NULL, &aTokenArray, EMPTY_STRING, TRUE, TRUE, EMPTY_STRING, formula::FormulaGrammar::GRAM_PODF_A1 ); } else { @@ -5269,7 +5268,7 @@ void SAL_CALL ScCellRangeObj::setFormulaArray( if (pDocSh) { // GRAM_PODF_A1 for API compatibility. - bDone = lcl_PutFormulaArray( *pDocSh, aRange, aArray,formula::FormulaGrammar::GRAM_PODF_A1 ); + bDone = lcl_PutFormulaArray( *pDocSh, aRange, aArray, EMPTY_STRING, formula::FormulaGrammar::GRAM_PODF_A1 ); } if (!bDone) @@ -6206,7 +6205,7 @@ void ScCellObj::SetString_Impl(const String& rString, BOOL bInterpret, BOOL bEng { ScDocFunc aFunc(*pDocSh); // GRAM_PODF_A1 for API compatibility. - (void)aFunc.SetCellText( aCellPos, rString, bInterpret, bEnglish, TRUE,formula::FormulaGrammar::GRAM_PODF_A1 ); + (void)aFunc.SetCellText( aCellPos, rString, bInterpret, bEnglish, TRUE, EMPTY_STRING, formula::FormulaGrammar::GRAM_PODF_A1 ); } } @@ -6254,13 +6253,13 @@ void ScCellObj::SetFormulaResultDouble( double fResult ) } void ScCellObj::SetFormulaWithGrammar( const ::rtl::OUString& rFormula, - const formula::FormulaGrammar::Grammar eGrammar ) + const ::rtl::OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar ) { ScDocShell* pDocSh = GetDocShell(); if ( pDocSh ) { ScDocFunc aFunc(*pDocSh); - aFunc.SetCellText( aCellPos, String( rFormula), TRUE, TRUE, TRUE, eGrammar); + aFunc.SetCellText( aCellPos, rFormula, TRUE, TRUE, TRUE, rFormulaNmsp, eGrammar); } } diff --git a/sc/source/ui/unoobj/fmtuno.cxx b/sc/source/ui/unoobj/fmtuno.cxx index 14fdb958a180..f9407b544f76 100644 --- a/sc/source/ui/unoobj/fmtuno.cxx +++ b/sc/source/ui/unoobj/fmtuno.cxx @@ -42,7 +42,6 @@ #include "fmtuno.hxx" #include "miscuno.hxx" -#include "conditio.hxx" #include "validat.hxx" #include "document.hxx" #include "unoguard.hxx" @@ -51,7 +50,8 @@ #include "tokenarray.hxx" #include "tokenuno.hxx" -using namespace com::sun::star; +using namespace ::com::sun::star; +using namespace ::formula; //------------------------------------------------------------------------ @@ -130,12 +130,17 @@ ScConditionMode lcl_ConditionOperatorToMode( sheet::ConditionOperator eOper ) //------------------------------------------------------------------------ -//UNUSED2008-05 ScTableConditionalFormat::ScTableConditionalFormat() -//UNUSED2008-05 { -//UNUSED2008-05 } +ScCondFormatEntryItem::ScCondFormatEntryItem() : + meGrammar1( FormulaGrammar::GRAM_UNSPECIFIED ), + meGrammar2( FormulaGrammar::GRAM_UNSPECIFIED ), + meMode( SC_COND_NONE ) +{ +} + +//------------------------------------------------------------------------ -ScTableConditionalFormat::ScTableConditionalFormat(ScDocument* pDoc, ULONG nKey, - const formula::FormulaGrammar::Grammar eGrammar) +ScTableConditionalFormat::ScTableConditionalFormat( + ScDocument* pDoc, ULONG nKey, FormulaGrammar::Grammar eGrammar) { // Eintrag aus dem Dokument lesen... @@ -156,11 +161,11 @@ ScTableConditionalFormat::ScTableConditionalFormat(ScDocument* pDoc, ULONG nKey, { ScCondFormatEntryItem aItem; const ScCondFormatEntry* pFormatEntry = pFormat->GetEntry(i); - aItem.mnMode = sal::static_int_cast<USHORT>(pFormatEntry->GetOperation()); + aItem.meMode = pFormatEntry->GetOperation(); aItem.maPos = pFormatEntry->GetValidSrcPos(); aItem.maExpr1 = pFormatEntry->GetExpression(aItem.maPos, 0, 0, eGrammar); aItem.maExpr2 = pFormatEntry->GetExpression(aItem.maPos, 1, 0, eGrammar); - aItem.meGrammar = eGrammar; + aItem.meGrammar1 = aItem.meGrammar2 = eGrammar; aItem.maStyle = pFormatEntry->GetStyle(); AddEntry_Impl(aItem); @@ -170,8 +175,20 @@ ScTableConditionalFormat::ScTableConditionalFormat(ScDocument* pDoc, ULONG nKey, } } +namespace { + +FormulaGrammar::Grammar lclResolveGrammar( FormulaGrammar::Grammar eExtGrammar, FormulaGrammar::Grammar eIntGrammar ) +{ + if( eExtGrammar != FormulaGrammar::GRAM_UNSPECIFIED ) + return eExtGrammar; + OSL_ENSURE( eIntGrammar != FormulaGrammar::GRAM_UNSPECIFIED, "lclResolveGrammar - unspecified grammar, using GRAM_PODF_A1" ); + return (eIntGrammar == FormulaGrammar::GRAM_UNSPECIFIED) ? FormulaGrammar::GRAM_PODF_A1 : eIntGrammar; +} + +} // namespace + void ScTableConditionalFormat::FillFormat( ScConditionalFormat& rFormat, - ScDocument* pDoc, formula::FormulaGrammar::Grammar eGrammar ) const + ScDocument* pDoc, FormulaGrammar::Grammar eGrammar) const { // ScConditionalFormat = Core-Struktur, muss leer sein @@ -185,15 +202,12 @@ void ScTableConditionalFormat::FillFormat( ScConditionalFormat& rFormat, ScCondFormatEntryItem aData; pEntry->GetData(aData); - if (eGrammar == formula::FormulaGrammar::GRAM_UNSPECIFIED) - eGrammar = aData.meGrammar; - if (eGrammar == formula::FormulaGrammar::GRAM_UNSPECIFIED) - { - DBG_ERRORFILE("FillFormat: unspecified grammar, using GRAM_PODF_A1"); - eGrammar = formula::FormulaGrammar::GRAM_PODF_A1; - } - ScCondFormatEntry aCoreEntry( static_cast<ScConditionMode>(aData.mnMode), - aData.maExpr1, aData.maExpr2, pDoc, aData.maPos, aData.maStyle, eGrammar ); + + FormulaGrammar::Grammar eGrammar1 = lclResolveGrammar( eGrammar, aData.meGrammar1 ); + FormulaGrammar::Grammar eGrammar2 = lclResolveGrammar( eGrammar, aData.meGrammar2 ); + + ScCondFormatEntry aCoreEntry( aData.meMode, aData.maExpr1, aData.maExpr2, + pDoc, aData.maPos, aData.maStyle, aData.maExprNmsp1, aData.maExprNmsp2, eGrammar1, eGrammar2 ); if ( aData.maPosStr.Len() ) aCoreEntry.SetSrcString( aData.maPosStr ); @@ -248,69 +262,86 @@ void SAL_CALL ScTableConditionalFormat::addNew( { ScUnoGuard aGuard; ScCondFormatEntryItem aEntry; - aEntry.mnMode = sal::static_int_cast<USHORT>(SC_COND_NONE); + aEntry.meMode = SC_COND_NONE; const beans::PropertyValue* pPropArray = aConditionalEntry.getConstArray(); long nPropCount = aConditionalEntry.getLength(); for (long i = 0; i < nPropCount; i++) { const beans::PropertyValue& rProp = pPropArray[i]; - String aPropName(rProp.Name); - if ( aPropName.EqualsAscii( SC_UNONAME_OPERATOR ) ) + if ( rProp.Name.equalsAscii( SC_UNONAME_OPERATOR ) ) { sheet::ConditionOperator eOper = (sheet::ConditionOperator) ScUnoHelpFunctions::GetEnumFromAny( rProp.Value ); - aEntry.mnMode = sal::static_int_cast<USHORT>(lcl_ConditionOperatorToMode( eOper )); + aEntry.meMode = lcl_ConditionOperatorToMode( eOper ); } - else if ( aPropName.EqualsAscii( SC_UNONAME_FORMULA1 ) ) + else if ( rProp.Name.equalsAscii( SC_UNONAME_FORMULA1 ) ) { rtl::OUString aStrVal; uno::Sequence<sheet::FormulaToken> aTokens; if ( rProp.Value >>= aStrVal ) - aEntry.maExpr1 = String( aStrVal ); + aEntry.maExpr1 = aStrVal; else if ( rProp.Value >>= aTokens ) { aEntry.maExpr1.Erase(); aEntry.maTokens1 = aTokens; } } - else if ( aPropName.EqualsAscii( SC_UNONAME_FORMULA2 ) ) + else if ( rProp.Name.equalsAscii( SC_UNONAME_FORMULA2 ) ) { rtl::OUString aStrVal; uno::Sequence<sheet::FormulaToken> aTokens; if ( rProp.Value >>= aStrVal ) - aEntry.maExpr2 = String( aStrVal ); + aEntry.maExpr2 = aStrVal; else if ( rProp.Value >>= aTokens ) { aEntry.maExpr2.Erase(); aEntry.maTokens2 = aTokens; } } - else if ( aPropName.EqualsAscii( SC_UNONAME_SOURCEPOS ) ) + else if ( rProp.Name.equalsAscii( SC_UNONAME_SOURCEPOS ) ) { table::CellAddress aAddress; if ( rProp.Value >>= aAddress ) aEntry.maPos = ScAddress( (SCCOL)aAddress.Column, (SCROW)aAddress.Row, aAddress.Sheet ); } - else if ( aPropName.EqualsAscii( SC_UNONAME_SOURCESTR ) ) + else if ( rProp.Name.equalsAscii( SC_UNONAME_SOURCESTR ) ) { rtl::OUString aStrVal; if ( rProp.Value >>= aStrVal ) aEntry.maPosStr = String( aStrVal ); } - else if ( aPropName.EqualsAscii( SC_UNONAME_STYLENAME ) ) + else if ( rProp.Name.equalsAscii( SC_UNONAME_STYLENAME ) ) { rtl::OUString aStrVal; if ( rProp.Value >>= aStrVal ) aEntry.maStyle = ScStyleNameConversion::ProgrammaticToDisplayName( aStrVal, SFX_STYLE_FAMILY_PARA ); } - else if ( aPropName.EqualsAscii( SC_UNONAME_GRAMMAR ) ) + else if ( rProp.Name.equalsAscii( SC_UNONAME_FORMULANMSP1 ) ) + { + rtl::OUString aStrVal; + if ( rProp.Value >>= aStrVal ) + aEntry.maExprNmsp1 = aStrVal; + } + else if ( rProp.Name.equalsAscii( SC_UNONAME_FORMULANMSP2 ) ) + { + rtl::OUString aStrVal; + if ( rProp.Value >>= aStrVal ) + aEntry.maExprNmsp2 = aStrVal; + } + else if ( rProp.Name.equalsAscii( SC_UNONAME_GRAMMAR1 ) ) { sal_Int32 nVal = 0; if ( rProp.Value >>= nVal ) - aEntry.meGrammar = static_cast<formula::FormulaGrammar::Grammar>(nVal); + aEntry.meGrammar1 = static_cast< FormulaGrammar::Grammar >( nVal ); + } + else if ( rProp.Name.equalsAscii( SC_UNONAME_GRAMMAR2 ) ) + { + sal_Int32 nVal = 0; + if ( rProp.Value >>= nVal ) + aEntry.meGrammar2 = static_cast< FormulaGrammar::Grammar >( nVal ); } else { @@ -523,14 +554,14 @@ sheet::ConditionOperator SAL_CALL ScTableConditionalEntry::getOperator() throw(uno::RuntimeException) { ScUnoGuard aGuard; - return lcl_ConditionModeToOperator( static_cast<ScConditionMode>(aData.mnMode) ); + return lcl_ConditionModeToOperator( aData.meMode ); } void SAL_CALL ScTableConditionalEntry::setOperator( sheet::ConditionOperator nOperator ) throw(uno::RuntimeException) { ScUnoGuard aGuard; - aData.mnMode = sal::static_int_cast<USHORT>( lcl_ConditionOperatorToMode( nOperator ) ); + aData.meMode = lcl_ConditionOperatorToMode( nOperator ); if (pParent) pParent->DataChanged(); } @@ -619,7 +650,7 @@ ScTableValidationObj::ScTableValidationObj(ScDocument* pDoc, ULONG nKey, aSrcPos = pData->GetValidSrcPos(); // #b4974740# valid pos for expressions aExpr1 = pData->GetExpression( aSrcPos, 0, 0, eGrammar ); aExpr2 = pData->GetExpression( aSrcPos, 1, 0, eGrammar ); - meGrammar = eGrammar; + meGrammar1 = meGrammar2 = eGrammar; nValMode = sal::static_int_cast<USHORT>( pData->GetDataMode() ); bIgnoreBlank = pData->IsIgnoreBlank(); nShowList = pData->GetListType(); @@ -647,18 +678,14 @@ ScValidationData* ScTableValidationObj::CreateValidationData( ScDocument* pDoc, { // ScValidationData = Core-Struktur - if (eGrammar == formula::FormulaGrammar::GRAM_UNSPECIFIED) - eGrammar = meGrammar; - if (eGrammar == formula::FormulaGrammar::GRAM_UNSPECIFIED) - { - DBG_ERRORFILE("CreateValidationData: unspecified grammar, using GRAM_PODF_A1"); - eGrammar = formula::FormulaGrammar::GRAM_PODF_A1; - } + FormulaGrammar::Grammar eGrammar1 = lclResolveGrammar( eGrammar, meGrammar1 ); + FormulaGrammar::Grammar eGrammar2 = lclResolveGrammar( eGrammar, meGrammar2 ); ScValidationData* pRet = new ScValidationData( (ScValidationMode)nValMode, (ScConditionMode)nMode, aExpr1, aExpr2, pDoc, aSrcPos, - eGrammar ); + maExprNmsp1, maExprNmsp2, + eGrammar1, eGrammar2 ); pRet->SetIgnoreBlank(bIgnoreBlank); pRet->SetListType(nShowList); @@ -702,7 +729,9 @@ void ScTableValidationObj::ClearData_Impl() aSrcPos.Set(0,0,0); aExpr1.Erase(); aExpr2.Erase(); - meGrammar = formula::FormulaGrammar::GRAM_UNSPECIFIED; // will be overriden when needed + maExprNmsp1.Erase(); + maExprNmsp2.Erase(); + meGrammar1 = meGrammar2 = FormulaGrammar::GRAM_UNSPECIFIED; // will be overriden when needed aInputTitle.Erase(); aInputMessage.Erase(); aErrorTitle.Erase(); @@ -905,13 +934,37 @@ void SAL_CALL ScTableValidationObj::setPropertyValue( if ( aValue >>= aStrVal ) aPosString = String( aStrVal ); } - else if ( aString.EqualsAscii( SC_UNONAME_GRAMMAR ) ) + else if ( aString.EqualsAscii( SC_UNONAME_FORMULANMSP1 ) ) + { + // internal - only for XML filter, not in PropertySetInfo, only set + + rtl::OUString aStrVal; + if ( aValue >>= aStrVal ) + maExprNmsp1 = aStrVal; + } + else if ( aString.EqualsAscii( SC_UNONAME_FORMULANMSP2 ) ) + { + // internal - only for XML filter, not in PropertySetInfo, only set + + rtl::OUString aStrVal; + if ( aValue >>= aStrVal ) + maExprNmsp2 = aStrVal; + } + else if ( aString.EqualsAscii( SC_UNONAME_GRAMMAR1 ) ) + { + // internal - only for XML filter, not in PropertySetInfo, only set + + sal_Int32 nVal = 0; + if ( aValue >>= nVal ) + meGrammar1 = static_cast< FormulaGrammar::Grammar >(nVal); + } + else if ( aString.EqualsAscii( SC_UNONAME_GRAMMAR2 ) ) { // internal - only for XML filter, not in PropertySetInfo, only set sal_Int32 nVal = 0; if ( aValue >>= nVal ) - meGrammar = static_cast<formula::FormulaGrammar::Grammar>(nVal); + meGrammar2 = static_cast< FormulaGrammar::Grammar >(nVal); } DataChanged(); diff --git a/sc/source/ui/unoobj/tokenuno.cxx b/sc/source/ui/unoobj/tokenuno.cxx index c543b5880fe7..e6e194d7eb75 100644 --- a/sc/source/ui/unoobj/tokenuno.cxx +++ b/sc/source/ui/unoobj/tokenuno.cxx @@ -51,17 +51,16 @@ #include "docsh.hxx" #include "rangeseq.hxx" #include "externalrefmgr.hxx" -using namespace formula; -using namespace com::sun::star; +using namespace ::formula; +using namespace ::com::sun::star; -//------------------------------------------------------------------------ +// ============================================================================ const SfxItemPropertyMapEntry* lcl_GetFormulaParserMap() { static SfxItemPropertyMapEntry aFormulaParserMap_Impl[] = { - {MAP_CHAR_LEN(SC_UNO_REFERENCEPOS), 0, &getCppuType((table::CellAddress*)0), 0, 0 }, {MAP_CHAR_LEN(SC_UNO_COMPILEFAP), 0, &getBooleanCppuType(), 0, 0 }, {MAP_CHAR_LEN(SC_UNO_COMPILEENGLISH), 0, &getBooleanCppuType(), 0, 0 }, {MAP_CHAR_LEN(SC_UNO_IGNORELEADING), 0, &getBooleanCppuType(), 0, 0 }, @@ -74,7 +73,7 @@ const SfxItemPropertyMapEntry* lcl_GetFormulaParserMap() SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS ) -//------------------------------------------------------------------------ +// ============================================================================ ScFormulaParserObj::ScFormulaParserObj(ScDocShell* pDocSh) : mpDocShell( pDocSh ), @@ -135,7 +134,8 @@ void ScFormulaParserObj::SetCompilerFlags( ScCompiler& rCompiler ) const rCompiler.SetExternalLinks( maExternalLinks); } -uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula( const rtl::OUString& aFormula ) +uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula( + const rtl::OUString& aFormula, const table::CellAddress& rReferencePos ) throw (uno::RuntimeException) { ScUnoGuard aGuard; @@ -143,8 +143,10 @@ uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula( co if (mpDocShell) { + ScAddress aRefPos( ScAddress::UNINITIALIZED ); + ScUnoConversion::FillScAddress( aRefPos, rReferencePos ); ScDocument* pDoc = mpDocShell->GetDocument(); - ScCompiler aCompiler( pDoc, maRefPos); + ScCompiler aCompiler( pDoc, aRefPos); aCompiler.SetGrammar(pDoc->GetGrammar()); SetCompilerFlags( aCompiler ); @@ -156,7 +158,8 @@ uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula( co return aRet; } -rtl::OUString SAL_CALL ScFormulaParserObj::printFormula( const uno::Sequence<sheet::FormulaToken>& aTokens ) +rtl::OUString SAL_CALL ScFormulaParserObj::printFormula( + const uno::Sequence<sheet::FormulaToken>& aTokens, const table::CellAddress& rReferencePos ) throw (uno::RuntimeException) { ScUnoGuard aGuard; @@ -167,7 +170,9 @@ rtl::OUString SAL_CALL ScFormulaParserObj::printFormula( const uno::Sequence<she ScDocument* pDoc = mpDocShell->GetDocument(); ScTokenArray aCode; (void)ScTokenConversion::ConvertToTokenArray( *pDoc, aCode, aTokens ); - ScCompiler aCompiler( pDoc, maRefPos, aCode); + ScAddress aRefPos( ScAddress::UNINITIALIZED ); + ScUnoConversion::FillScAddress( aRefPos, rReferencePos ); + ScCompiler aCompiler( pDoc, aRefPos, aCode); aCompiler.SetGrammar(pDoc->GetGrammar()); SetCompilerFlags( aCompiler ); @@ -197,13 +202,7 @@ void SAL_CALL ScFormulaParserObj::setPropertyValue( { ScUnoGuard aGuard; String aString(aPropertyName); - if ( aString.EqualsAscii( SC_UNO_REFERENCEPOS ) ) - { - table::CellAddress aAddress; - aValue >>= aAddress; - ScUnoConversion::FillScAddress( maRefPos, aAddress ); - } // if ( aString.EqualsAscii( SC_UNO_REFERENCEPOS ) ) - else if ( aString.EqualsAscii( SC_UNO_COMPILEFAP ) ) + if ( aString.EqualsAscii( SC_UNO_COMPILEFAP ) ) { aValue >>= mbCompileFAP; } @@ -218,7 +217,7 @@ void SAL_CALL ScFormulaParserObj::setPropertyValue( if (mxOpCodeMap.get() && mbEnglish != bOldEnglish) { ScDocument* pDoc = mpDocShell->GetDocument(); - ScCompiler aCompiler( pDoc, maRefPos); + ScCompiler aCompiler( pDoc, ScAddress()); aCompiler.SetGrammar(pDoc->GetGrammar()); mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish); } @@ -239,7 +238,7 @@ void SAL_CALL ScFormulaParserObj::setPropertyValue( if (aValue >>= maOpCodeMapping) { ScDocument* pDoc = mpDocShell->GetDocument(); - ScCompiler aCompiler( pDoc, maRefPos); + ScCompiler aCompiler( pDoc, ScAddress()); aCompiler.SetGrammar(pDoc->GetGrammar()); mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish); } @@ -262,13 +261,7 @@ uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const rtl::OUString& aPr ScUnoGuard aGuard; uno::Any aRet; String aString(aPropertyName); - if ( aString.EqualsAscii( SC_UNO_REFERENCEPOS ) ) - { - table::CellAddress aAddress; - ScUnoConversion::FillApiAddress( aAddress, maRefPos ); - aRet <<= aAddress; - } - else if ( aString.EqualsAscii( SC_UNO_COMPILEFAP ) ) + if ( aString.EqualsAscii( SC_UNO_COMPILEFAP ) ) { aRet <<= mbCompileFAP; } @@ -299,7 +292,7 @@ uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const rtl::OUString& aPr SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj ) -//------------------------------------------------------------------------ +// ============================================================================ void lcl_ExternalRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef ) { @@ -463,9 +456,13 @@ bool ScTokenConversion::ConvertToTokenSequence( ScDocument& rDoc, return !bError; } -// ----------------------------------------------------------------------------- + +// ============================================================================ + ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::auto_ptr<formula::FormulaCompiler> _pCompiler) : formula::FormulaOpCodeMapperObj(_pCompiler) { } +// ============================================================================ + diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx index da7d409c492c..79343c31f85b 100644 --- a/sc/source/ui/view/viewfunc.cxx +++ b/sc/source/ui/view/viewfunc.cxx @@ -926,7 +926,7 @@ void ScViewFunc::EnterMatrix( const String& rString ) if (pData->GetSimpleArea(aRange) == SC_MARK_SIMPLE) { ScDocShell* pDocSh = pData->GetDocShell(); - BOOL bSuccess = pDocSh->GetDocFunc().EnterMatrix( aRange, &rMark, NULL, rString, FALSE, FALSE,formula::FormulaGrammar::GRAM_DEFAULT ); + BOOL bSuccess = pDocSh->GetDocFunc().EnterMatrix( aRange, &rMark, NULL, rString, FALSE, FALSE, EMPTY_STRING, formula::FormulaGrammar::GRAM_DEFAULT ); if (bSuccess) pDocSh->UpdateOle(GetViewData()); } |