diff options
author | hg <hg@oosvn01.> | 2009-10-08 16:03:52 +0000 |
---|---|---|
committer | hg <hg@oosvn01.> | 2009-10-08 16:03:52 +0000 |
commit | 90631ceb76c032e182db62df387688a97cf94f12 (patch) | |
tree | cae70f92ba9197c61a5e81ae21004fb4f385a124 /sc | |
parent | b88253921c6b484acb2d6f893341e953dcae1cba (diff) | |
parent | bebc983ea6df34dbc310d1dfbb3ca74ea62db830 (diff) |
merge with m55
Diffstat (limited to 'sc')
84 files changed, 3214 insertions, 1030 deletions
diff --git a/sc/inc/address.hxx b/sc/inc/address.hxx index 7ba5aa9c1f32..f1859be15fcf 100644 --- a/sc/inc/address.hxx +++ b/sc/inc/address.hxx @@ -791,12 +791,14 @@ template< typename T > void PutInOrder( T& nStart, T& nEnd ) bool ConvertSingleRef( ScDocument* pDoc, const String& rRefString, SCTAB nDefTab, ScRefAddress& rRefAddress, - const ScAddress::Details& rDetails = ScAddress::detailsOOOa1); + const ScAddress::Details& rDetails = ScAddress::detailsOOOa1, + ScAddress::ExternalInfo* pExtInfo = NULL ); bool ConvertDoubleRef(ScDocument* pDoc, const String& rRefString, SCTAB nDefTab, ScRefAddress& rStartRefAddress, ScRefAddress& rEndRefAddress, - const ScAddress::Details& rDetails = ScAddress::detailsOOOa1); + const ScAddress::Details& rDetails = ScAddress::detailsOOOa1, + ScAddress::ExternalInfo* pExtInfo = NULL ); /// append alpha representation of column to buffer SC_DLLPUBLIC void ScColToAlpha( rtl::OUStringBuffer& rBuffer, SCCOL nCol); diff --git a/sc/inc/cell.hxx b/sc/inc/cell.hxx index e04ec9af50ab..10de035abf7c 100644 --- a/sc/inc/cell.hxx +++ b/sc/inc/cell.hxx @@ -387,6 +387,15 @@ public: inline USHORT GetSeenInIteration() const { return nSeenInIteration; } BOOL HasOneReference( ScRange& r ) const; + /* Checks if the formula contains reference list that can be + expressed by one reference (like A1;A2;A3:A5 -> A1:A5). The + reference list is not required to be sorted (i.e. A3;A1;A2 is + still recognized as A1:A3), but no overlapping is allowed. + If one reference is recognized, the rRange is filled. + + It is similar to HasOneReference(), but more general. + */ + bool HasRefListExpressibleAsOneReference(ScRange& rRange) const; BOOL HasRelNameReference() const; BOOL HasColRowName() const; 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 155630a97ac2..76293479660c 100644 --- a/sc/inc/compiler.hxx +++ b/sc/inc/compiler.hxx @@ -311,9 +311,11 @@ private: const CharClass* pCharClass; // which character classification is used for parseAnyToken USHORT mnPredetectedReference; // reference when reading ODF, 0 (none), 1 (single) or 2 (double) SCsTAB nMaxTab; // last sheet in document + sal_Int32 mnRangeOpPosInSymbol; // if and where a range operator is in symbol const Convention *pConv; bool mbCloseBrackets; // whether to close open brackets automatically, default TRUE bool mbExtendedErrorDetection; + bool mbRewind; // whether symbol is to be rewound to some step during lexical analysis BOOL NextNewToken(bool bInArray = false); @@ -352,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 ); @@ -394,6 +396,8 @@ public: maExternalLinks = rLinks; } + void CreateStringFromXMLTokenArray( String& rFormula, String& rFormulaNmsp ); + void SetExtendedErrorDetection( bool bVal ) { mbExtendedErrorDetection = bVal; } BOOL IsCorrected() { return bCorrected; } @@ -401,12 +405,13 @@ 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; } - void MoveRelWrap(); - static void MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, - const ScAddress& rPos ); + void MoveRelWrap( SCCOL nMaxCol, SCROW nMaxRow ); + static void MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, const ScAddress& rPos, + SCCOL nMaxCol, SCROW nMaxRow ); BOOL UpdateNameReference( UpdateRefMode eUpdateRefMode, const ScRange&, 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/datauno.hxx b/sc/inc/datauno.hxx index 405d49e2a6b2..a93bfc341573 100644 --- a/sc/inc/datauno.hxx +++ b/sc/inc/datauno.hxx @@ -50,6 +50,7 @@ #include <com/sun/star/lang/XUnoTunnel.hpp> #include <com/sun/star/container/XNamed.hpp> #include <com/sun/star/util/XRefreshable.hpp> +#include <com/sun/star/sheet/XSheetFilterDescriptor2.hpp> #include <cppuhelper/implbase2.hxx> #include <cppuhelper/implbase3.hxx> #include <cppuhelper/implbase4.hxx> @@ -340,8 +341,9 @@ public: // to uno, all three look the same -class ScFilterDescriptorBase : public cppu::WeakImplHelper3< +class ScFilterDescriptorBase : public cppu::WeakImplHelper4< com::sun::star::sheet::XSheetFilterDescriptor, + com::sun::star::sheet::XSheetFilterDescriptor2, com::sun::star::beans::XPropertySet, com::sun::star::lang::XServiceInfo >, public SfxListener @@ -368,6 +370,13 @@ public: ::com::sun::star::sheet::TableFilterField >& aFilterFields ) throw(::com::sun::star::uno::RuntimeException); + // XSheetFilterDescriptor2 + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::sheet::TableFilterField2 > SAL_CALL + getFilterFields2() throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setFilterFields2( const ::com::sun::star::uno::Sequence< + ::com::sun::star::sheet::TableFilterField2 >& aFilterFields ) + throw(::com::sun::star::uno::RuntimeException); + // XPropertySet virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() 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/externalrefmgr.hxx b/sc/inc/externalrefmgr.hxx index 07c8a6a6697f..9b12dba52f1f 100644 --- a/sc/inc/externalrefmgr.hxx +++ b/sc/inc/externalrefmgr.hxx @@ -132,15 +132,27 @@ public: class Table { public: + + enum ReferencedFlag + { + UNREFERENCED, + REFERENCED_MARKED, // marked as referenced during store to file + REFERENCED_PERMANENT // permanently marked, e.g. from within interpreter + }; + Table(); ~Table(); SC_DLLPUBLIC void setCell(SCCOL nCol, SCROW nRow, TokenRef pToken, sal_uInt32 nFmtIndex = 0); TokenRef getCell(SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex = NULL) const; bool hasRow( SCROW nRow ) const; - /// A temporary state used only during store to file. - bool isReferenced() const; + /** Set/clear referenced status flag only if current status is not + REFERENCED_PERMANENT. */ void setReferenced( bool bReferenced ); + /// Unconditionally set the reference status flag. + void setReferencedFlag( ReferencedFlag eFlag ); + ReferencedFlag getReferencedFlag() const; + bool isReferenced() const; /// Obtain a sorted vector of rows. void getAllRows(::std::vector<SCROW>& rRows) const; /// Obtain a sorted vector of columns. @@ -148,8 +160,8 @@ public: void getAllNumberFormats(::std::vector<sal_uInt32>& rNumFmts) const; private: - RowsDataType maRows; - bool mbReferenced; + RowsDataType maRows; + ReferencedFlag meReferenced; }; typedef ::boost::shared_ptr<Table> TableTypeRef; @@ -219,9 +231,16 @@ public: * Set a table as referenced, used only during store-to-file. * @returns <TRUE/> if ALL tables of ALL documents are marked. */ - bool setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName ); + bool setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName, size_t nSheets, bool bPermanent ); void setAllCacheTableReferencedStati( bool bReferenced ); bool areAllCacheTablesReferenced() const; + + /** + * Set a table as permanently referenced, to be called if not in + * mark-during-store-to-file cycle. + */ + void setCacheTableReferencedPermanently( sal_uInt16 nFileId, const String& rTabName, size_t nSheets ); + private: struct ReferencedStatus { @@ -497,10 +516,16 @@ public: * Set a table as referenced, used only during store-to-file. * @returns <TRUE/> if ALL tables of ALL external documents are marked. */ - bool setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName ); + bool setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName, size_t nSheets ); void setAllCacheTableReferencedStati( bool bReferenced ); /** + * Set a table as permanently referenced, to be called if not in + * mark-during-store-to-file cycle. + */ + void setCacheTableReferencedPermanently( sal_uInt16 nFileId, const String& rTabName, size_t nSheets ); + + /** * @returns <TRUE/> if setAllCacheTableReferencedStati(false) was called, * <FALSE/> if setAllCacheTableReferencedStati(true) was called. */ 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/global.hxx b/sc/inc/global.hxx index 76f5fd665033..e329f477d824 100644 --- a/sc/inc/global.hxx +++ b/sc/inc/global.hxx @@ -728,7 +728,13 @@ enum ScQueryOp SC_TOPVAL, SC_BOTVAL, SC_TOPPERC, - SC_BOTPERC + SC_BOTPERC, + SC_CONTAINS, + SC_DOES_NOT_CONTAIN, + SC_BEGINS_WITH, + SC_DOES_NOT_BEGIN_WITH, + SC_ENDS_WITH, + SC_DOES_NOT_END_WITH }; // ----------------------------------------------------------------------- diff --git a/sc/inc/pch/precompiled_sc.hxx b/sc/inc/pch/precompiled_sc.hxx index 1b0f7150c022..956bdaf6994d 100644 --- a/sc/inc/pch/precompiled_sc.hxx +++ b/sc/inc/pch/precompiled_sc.hxx @@ -36,6 +36,7 @@ #include <algorithm> #include <assert.h> +#include <deque> #include <stdarg.h> #include <stddef.h> #include <stdio.h> @@ -49,6 +50,8 @@ #include <new> #include <cfloat> +#include <boost/bind.hpp> + #include <basegfx/polygon/b2dpolygon.hxx> #include <basegfx/polygon/b3dpolygon.hxx> #include <basegfx/polygon/b3dpolypolygon.hxx> diff --git a/sc/inc/progress.hxx b/sc/inc/progress.hxx index b30cf6d9dc70..c7706c2bc26b 100644 --- a/sc/inc/progress.hxx +++ b/sc/inc/progress.hxx @@ -36,6 +36,17 @@ class ScDocument; +/* + * #i102566 + * Drawing a progress bar update is not cheap, so if we draw it on every + * percentage change of 200 calculations we get one progress draw per 2 + * calculations which is slower than doing the calculations themselves. So as a + * rough guide only do an update per MIN_NO_CODES_PER_PROGRESS_UPDATE + * calculations + */ +#define MIN_NO_CODES_PER_PROGRESS_UPDATE 100 + + class SC_DLLPUBLIC ScProgress { private: diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx index 962aff918e7b..002adf9b77ce 100644 --- a/sc/inc/rangenam.hxx +++ b/sc/inc/rangenam.hxx @@ -81,6 +81,11 @@ private: USHORT nIndex; BOOL bModified; // wird bei UpdateReference gesetzt/geloescht + // max row and column to use for wrapping of references. If -1 use the + // application's default. + SCROW mnMaxRow; + SCCOL mnMaxCol; + friend class ScRangeName; ScRangeData( USHORT nIndex ); public: @@ -153,6 +158,11 @@ public: static void MakeValidName( String& rName ); SC_DLLPUBLIC static BOOL IsNameValid( const String& rName, ScDocument* pDoc ); + + SC_DLLPUBLIC void SetMaxRow(SCROW nRow); + SCROW GetMaxRow() const; + SC_DLLPUBLIC void SetMaxCol(SCCOL nCol); + SCCOL GetMaxCol() const; }; inline BOOL ScRangeData::HasType( RangeType nType ) const diff --git a/sc/inc/refdata.hxx b/sc/inc/refdata.hxx index 6a51d66fdc07..12f29943fce0 100644 --- a/sc/inc/refdata.hxx +++ b/sc/inc/refdata.hxx @@ -109,6 +109,8 @@ struct SC_DLLPUBLIC ScSingleRefData // Single reference (one address) int inline BOOL IsRelName() const { return Flags.bRelName; } inline BOOL Valid() const; + /// In external references nTab is -1 + inline bool ValidExternal() const; void SmartRelAbs( const ScAddress& rPos ); void CalcRelFromAbs( const ScAddress& rPos ); @@ -147,6 +149,13 @@ inline BOOL ScSingleRefData::Valid() const nTab >= 0 && nTab <= MAXTAB; } +inline bool ScSingleRefData::ValidExternal() const +{ + return nCol >= 0 && nCol <= MAXCOL && + nRow >= 0 && nRow <= MAXROW && + nTab == -1; +} + struct ScComplexRefData // Complex reference (a range) into the sheet { @@ -181,6 +190,10 @@ struct ScComplexRefData // Complex reference (a range) into the sheet { return Ref1.IsDeleted() || Ref2.IsDeleted(); } inline BOOL Valid() const { return Ref1.Valid() && Ref2.Valid(); } + /** In external references nTab is -1 for the start tab and -1 for the end + tab if one sheet, or >=0 if more than one sheets. */ + inline bool ValidExternal() const; + /// Absolute references have to be up-to-date when calling this! void PutInOrder(); inline BOOL operator==( const ScComplexRefData& r ) const @@ -192,4 +205,12 @@ struct ScComplexRefData // Complex reference (a range) into the sheet ScComplexRefData& Extend( const ScComplexRefData & rRef, const ScAddress & rPos ); }; +inline bool ScComplexRefData::ValidExternal() const +{ + return Ref1.ValidExternal() && + Ref2.nCol >= 0 && Ref2.nCol <= MAXCOL && + Ref2.nRow >= 0 && Ref2.nRow <= MAXROW && + Ref2.nTab >= Ref1.nTab; +} + #endif diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 7d9bf90a3d81..8b2227d48dbb 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -267,16 +267,28 @@ public: void GetString( SCCOL nCol, SCROW nRow, String& rString ); void GetInputString( SCCOL nCol, SCROW nRow, String& rString ); double GetValue( const ScAddress& rPos ) const - { return aCol[rPos.Col()].GetValue( rPos.Row() ); } + { + return ValidColRow(rPos.Col(),rPos.Row()) ? + aCol[rPos.Col()].GetValue( rPos.Row() ) : + 0.0; + } double GetValue( SCCOL nCol, SCROW nRow ); void GetFormula( SCCOL nCol, SCROW nRow, String& rFormula, BOOL bAsciiExport = FALSE ); CellType GetCellType( const ScAddress& rPos ) const - { return aCol[rPos.Col()].GetCellType( rPos.Row() ); } + { + return ValidColRow(rPos.Col(),rPos.Row()) ? + aCol[rPos.Col()].GetCellType( rPos.Row() ) : + CELLTYPE_NONE; + } CellType GetCellType( SCCOL nCol, SCROW nRow ) const; ScBaseCell* GetCell( const ScAddress& rPos ) const - { return aCol[rPos.Col()].GetCell( rPos.Row() ); } + { + return ValidColRow(rPos.Col(),rPos.Row()) ? + aCol[rPos.Col()].GetCell( rPos.Row() ) : + NULL; + } ScBaseCell* GetCell( SCCOL nCol, SCROW nRow ) const; void GetLastDataPos(SCCOL& rCol, SCROW& rRow) const; @@ -378,7 +390,11 @@ public: SCCOL nEndCol, SCROW nEndRow ) const; USHORT GetErrCode( const ScAddress& rPos ) const - { return aCol[rPos.Col()].GetErrCode( rPos.Row() ); } + { + return ValidColRow(rPos.Col(),rPos.Row()) ? + aCol[rPos.Col()].GetErrCode( rPos.Row() ) : + 0; + } //UNUSED2008-05 USHORT GetErrCode( SCCOL nCol, SCROW nRow ) const; void ResetChanged( const ScRange& rRange ); @@ -454,7 +470,11 @@ public: const ScPatternAttr* GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const; ULONG GetNumberFormat( const ScAddress& rPos ) const - { return aCol[rPos.Col()].GetNumberFormat( rPos.Row() ); } + { + return ValidColRow(rPos.Col(),rPos.Row()) ? + aCol[rPos.Col()].GetNumberFormat( rPos.Row() ) : + 0; + } ULONG GetNumberFormat( SCCOL nCol, SCROW nRow ) const; void MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, BOOL bDeep ) const; @@ -473,7 +493,10 @@ public: void ApplyPattern( SCCOL nCol, SCROW nRow, const ScPatternAttr& rAttr ); void ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScPatternAttr& rAttr ); void SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr, BOOL bPutToPool = FALSE ) - { aCol[rPos.Col()].SetPattern( rPos.Row(), rAttr, bPutToPool ); } + { + if (ValidColRow(rPos.Col(),rPos.Row())) + aCol[rPos.Col()].SetPattern( rPos.Row(), rAttr, bPutToPool ); + } void SetPattern( SCCOL nCol, SCROW nRow, const ScPatternAttr& rAttr, BOOL bPutToPool = FALSE ); void ApplyPatternIfNumberformatIncompatible( const ScRange& rRange, const ScPatternAttr& rPattern, short nNewType ); 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 fe34d185b898..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() ) { @@ -1701,7 +1701,7 @@ void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam ) // Reschedule verlangsamt das ganze erheblich, nur bei Prozentaenderung ausfuehren ScProgress::GetInterpretProgress()->SetStateCountDownOnPercent( - pDocument->GetFormulaCodeInTree() ); + pDocument->GetFormulaCodeInTree()/MIN_NO_CODES_PER_PROGRESS_UPDATE ); } else { diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx index 7ef182660656..a0e776458ca2 100644 --- a/sc/source/core/data/cell2.cxx +++ b/sc/source/core/data/cell2.cxx @@ -34,6 +34,11 @@ // INCLUDE --------------------------------------------------------------- +#include <algorithm> +#include <deque> + +#include <boost/bind.hpp> + #include <vcl/mapmod.hxx> #include <svx/editobj.hxx> #include <svx/editstat.hxx> @@ -175,6 +180,223 @@ void ScEditCell::SetTextObject( const EditTextObject* pObject, // ============================================================================ +namespace +{ + +using std::deque; + +typedef SCCOLROW(*DimensionSelector)(const ScSingleRefData&); + + +static SCCOLROW lcl_GetCol(const ScSingleRefData& rData) +{ + return rData.nCol; +} + + +static SCCOLROW lcl_GetRow(const ScSingleRefData& rData) +{ + return rData.nRow; +} + + +static SCCOLROW lcl_GetTab(const ScSingleRefData& rData) +{ + return rData.nTab; +} + + +/** Check if both references span the same range in selected dimension. + */ +static bool +lcl_checkRangeDimension( + const SingleDoubleRefProvider& rRef1, + const SingleDoubleRefProvider& rRef2, + const DimensionSelector aWhich) +{ + return + aWhich(rRef1.Ref1) == aWhich(rRef2.Ref1) + && aWhich(rRef1.Ref2) == aWhich(rRef2.Ref2); +} + + +static bool +lcl_checkRangeDimensions( + const SingleDoubleRefProvider& rRef1, + const SingleDoubleRefProvider& rRef2, + bool& bCol, bool& bRow, bool& bTab) +{ + const bool bSameCols(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetCol)); + const bool bSameRows(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetRow)); + const bool bSameTabs(lcl_checkRangeDimension(rRef1, rRef2, lcl_GetTab)); + + // Test if exactly two dimensions are equal + if (!(bSameCols ^ bSameRows ^ bSameTabs) + && (bSameCols || bSameRows || bSameTabs)) + { + bCol = !bSameCols; + bRow = !bSameRows; + bTab = !bSameTabs; + return true; + } + return false; +} + + +/** Check if references in given reference list can possibly + form a range. To do that, two of their dimensions must be the same. + */ +static bool +lcl_checkRangeDimensions( + const deque<ScToken*>::const_iterator aBegin, + const deque<ScToken*>::const_iterator aEnd, + bool& bCol, bool& bRow, bool& bTab) +{ + deque<ScToken*>::const_iterator aCur(aBegin); + ++aCur; + const SingleDoubleRefProvider aRef(**aBegin); + bool bOk(false); + { + const SingleDoubleRefProvider aRefCur(**aCur); + bOk = lcl_checkRangeDimensions(aRef, aRefCur, bCol, bRow, bTab); + } + while (bOk && aCur != aEnd) + { + const SingleDoubleRefProvider aRefCur(**aCur); + bool bColTmp(false); + bool bRowTmp(false); + bool bTabTmp(false); + bOk = lcl_checkRangeDimensions(aRef, aRefCur, bColTmp, bRowTmp, bTabTmp); + bOk = bOk && (bCol == bColTmp && bRow == bRowTmp && bTab == bTabTmp); + ++aCur; + } + + if (bOk && aCur == aEnd) + { + bCol = bCol; + bRow = bRow; + bTab = bTab; + return true; + } + return false; +} + + +bool +lcl_lessReferenceBy( + const ScToken* const pRef1, const ScToken* const pRef2, + const DimensionSelector aWhich) +{ + const SingleDoubleRefProvider rRef1(*pRef1); + const SingleDoubleRefProvider rRef2(*pRef2); + return aWhich(rRef1.Ref1) < aWhich(rRef2.Ref1); +} + + +/** Returns true if range denoted by token pRef2 starts immediately after + range denoted by token pRef1. Dimension, in which the comparison takes + place, is given by aWhich. + */ +bool +lcl_isImmediatelyFollowing( + const ScToken* const pRef1, const ScToken* const pRef2, + const DimensionSelector aWhich) +{ + const SingleDoubleRefProvider rRef1(*pRef1); + const SingleDoubleRefProvider rRef2(*pRef2); + return aWhich(rRef2.Ref1) - aWhich(rRef1.Ref2) == 1; +} + + +static bool +lcl_checkIfAdjacent( + const deque<ScToken*>& rReferences, + const DimensionSelector aWhich) +{ + typedef deque<ScToken*>::const_iterator Iter; + Iter aBegin(rReferences.begin()); + Iter aEnd(rReferences.end()); + Iter aBegin1(aBegin); + ++aBegin1, --aEnd; + return std::equal( + aBegin, aEnd, aBegin1, + boost::bind(lcl_isImmediatelyFollowing, _1, _2, aWhich)); +} + + +static void +lcl_fillRangeFromRefList( + const deque<ScToken*>& rReferences, ScRange& rRange) +{ + const ScSingleRefData aStart( + SingleDoubleRefProvider(*rReferences.front()).Ref1); + rRange.aStart.Set(aStart.nCol, aStart.nRow, aStart.nTab); + const ScSingleRefData aEnd( + SingleDoubleRefProvider(*rReferences.back()).Ref2); + rRange.aEnd.Set(aEnd.nCol, aEnd.nRow, aEnd.nTab); +} + + +static bool +lcl_refListFormsOneRange( + const ScAddress& aPos, deque<ScToken*>& rReferences, + ScRange& rRange) +{ + std::for_each( + rReferences.begin(), rReferences.end(), + bind(&ScToken::CalcAbsIfRel, _1, aPos)) + ; + if (rReferences.size() == 1) { + lcl_fillRangeFromRefList(rReferences, rRange); + return true; + } + + bool bCell(false); + bool bRow(false); + bool bTab(false); + if (lcl_checkRangeDimensions(rReferences.begin(), rReferences.end(), + bCell, bRow, bTab)) + { + DimensionSelector aWhich; + if (bCell) + { + aWhich = lcl_GetCol; + } + else if (bRow) + { + aWhich = lcl_GetRow; + } + else if (bTab) + { + aWhich = lcl_GetTab; + } + else + { + OSL_ENSURE(false, "lcl_checkRangeDimensions shouldn't allow that!"); + aWhich = lcl_GetRow; // initialize to avoid warning + } + // Sort the references by start of range + std::sort(rReferences.begin(), rReferences.end(), + boost::bind(lcl_lessReferenceBy, _1, _2, aWhich)); + if (lcl_checkIfAdjacent(rReferences, aWhich)) + { + lcl_fillRangeFromRefList(rReferences, rRange); + return true; + } + } + return false; +} + + +bool lcl_isReference(const FormulaToken& rToken) +{ + return + rToken.GetType() == svSingleRef || + rToken.GetType() == svDoubleRef; +} + +} + BOOL ScFormulaCell::IsEmpty() { if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc()) @@ -449,6 +671,52 @@ BOOL ScFormulaCell::HasOneReference( ScRange& r ) const return FALSE; } +bool +ScFormulaCell::HasRefListExpressibleAsOneReference(ScRange& rRange) const +{ + /* If there appears just one reference in the formula, it's the same + as HasOneReference(). If there are more of them, they can denote + one range if they are (sole) arguments of one function. + Union of these references must form one range and their + intersection must be empty set. + */ + pCode->Reset(); + // Get first reference, if any + ScToken* const pFirstReference( + dynamic_cast<ScToken*>(pCode->GetNextReferenceRPN())); + if (pFirstReference) + { + // Collect all consecutive references, starting by the one + // already found + std::deque<ScToken*> aReferences; + aReferences.push_back(pFirstReference); + FormulaToken* pToken(pCode->NextRPN()); + FormulaToken* pFunction(0); + while (pToken) + { + if (lcl_isReference(*pToken)) + { + aReferences.push_back(dynamic_cast<ScToken*>(pToken)); + pToken = pCode->NextRPN(); + } + else + { + if (pToken->IsFunction()) + { + pFunction = pToken; + } + break; + } + } + if (pFunction && !pCode->GetNextReferenceRPN() + && (pFunction->GetParamCount() == aReferences.size())) + { + return lcl_refListFormsOneRange(aPos, aReferences, rRange); + } + } + return false; +} + BOOL ScFormulaCell::HasRelNameReference() const { pCode->Reset(); @@ -799,7 +1067,7 @@ void ScFormulaCell::UpdateInsertTab(SCTAB nTable) pCode = new ScTokenArray( *pRangeData->GetCode() ); ScCompiler aComp2(pDocument, aPos, *pCode); aComp2.SetGrammar(pDocument->GetGrammar()); - aComp2.MoveRelWrap(); + aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); aComp2.UpdateInsertTab( nTable, FALSE ); // If the shared formula contained a named range/formula containing // an absolute reference to a sheet, those have to be readjusted. @@ -835,7 +1103,7 @@ BOOL ScFormulaCell::UpdateDeleteTab(SCTAB nTable, BOOL bIsMove) ScCompiler aComp2(pDocument, aPos, *pCode); aComp2.SetGrammar(pDocument->GetGrammar()); aComp2.CompileTokenArray(); - aComp2.MoveRelWrap(); + aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); aComp2.UpdateDeleteTab( nTable, FALSE, FALSE, bRefChanged ); // If the shared formula contained a named range/formula containing // an absolute reference to a sheet, those have to be readjusted. @@ -872,7 +1140,7 @@ void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo ) ScCompiler aComp2(pDocument, aPos, *pCode); aComp2.SetGrammar(pDocument->GetGrammar()); aComp2.CompileTokenArray(); - aComp2.MoveRelWrap(); + aComp2.MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); aComp2.UpdateMoveTab( nOldPos, nNewPos, TRUE ); bCompile = TRUE; } 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/documen4.cxx b/sc/source/core/data/documen4.cxx index 3c72baff5ba4..7313ebbf83f5 100644 --- a/sc/source/core/data/documen4.cxx +++ b/sc/source/core/data/documen4.cxx @@ -311,9 +311,16 @@ bool ScDocument::MarkUsedExternalReferences( ScTokenArray & rArr ) switch (t->GetType()) { case svExternalSingleRef: - case svExternalDoubleRef: bAllMarked = pRefMgr->setCacheTableReferenced( - t->GetIndex(), t->GetString()); + t->GetIndex(), t->GetString(), 1); + break; + case svExternalDoubleRef: + { + const ScComplexRefData& rRef = t->GetDoubleRef(); + size_t nSheets = rRef.Ref2.nTab - rRef.Ref1.nTab + 1; + bAllMarked = pRefMgr->setCacheTableReferenced( + t->GetIndex(), t->GetString(), nSheets); + } break; case svExternalName: /* TODO: external names aren't supported yet, but would diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 90eb1597023d..61cf3ab94b35 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -2484,7 +2484,7 @@ void ScDocument::GetCell( SCCOL nCol, SCROW nRow, SCTAB nTab, ScBaseCell* ScDocument::GetCell( const ScAddress& rPos ) const { SCTAB nTab = rPos.Tab(); - if ( pTab[nTab] ) + if (ValidTab(nTab) && pTab[nTab]) return pTab[nTab]->GetCell( rPos ); DBG_ERROR("GetCell ohne Tabelle"); diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx index 09e26c731eb8..38aabaa51a55 100644 --- a/sc/source/core/data/table1.cxx +++ b/sc/source/core/data/table1.cxx @@ -870,6 +870,10 @@ BOOL ScTable::ValidNextPos( SCCOL nCol, SCROW nRow, const ScMarkData& rMark, if (!ValidCol(nCol) || !ValidRow(nRow)) return FALSE; + if (pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) + // Skip an overlapped cell. + return false; + if (bMarked && !rMark.IsCellMarked(nCol,nRow)) return FALSE; @@ -912,7 +916,8 @@ void ScTable::GetNextPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY, { BOOL bUp = ( nMovY < 0 ); nRow = rMark.GetNextMarked( nCol, nRow, bUp ); - while ( VALIDROW(nRow) && pRowFlags && (pRowFlags->GetValue(nRow) & CR_HIDDEN) ) + while ( VALIDROW(nRow) && ((pRowFlags && (pRowFlags->GetValue(nRow) & CR_HIDDEN)) || + pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) ) { // #53697# ausgeblendete ueberspringen (s.o.) nRow += nMovY; @@ -941,7 +946,8 @@ void ScTable::GetNextPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY, else if (nRow > MAXROW) nRow = 0; nRow = rMark.GetNextMarked( nCol, nRow, bUp ); - while ( VALIDROW(nRow) && pRowFlags && (pRowFlags->GetValue(nRow) & CR_HIDDEN) ) + while ( VALIDROW(nRow) && ((pRowFlags && (pRowFlags->GetValue(nRow) & CR_HIDDEN)) || + pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) ) { // #53697# ausgeblendete ueberspringen (s.o.) nRow += nMovY; diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index cf204765b3b0..59858796078c 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -2701,7 +2701,7 @@ void ScTable::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SC pCell = aCol[nCol].GetCell( nRow ); if (pCell) if ( pCell->GetCellType() == CELLTYPE_FORMULA ) - if (((ScFormulaCell*)pCell)->HasOneReference( aRef )) + if (((ScFormulaCell*)pCell)->HasRefListExpressibleAsOneReference( aRef )) if ( aRef.aStart.Col() == nCol && aRef.aEnd.Col() == nCol && aRef.aStart.Tab() == nTab && aRef.aEnd.Tab() == nTab && DiffSign( aRef.aStart.Row(), nRow ) == @@ -2732,7 +2732,7 @@ void ScTable::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SC while ( aIter.Next( nRow, pCell ) && !bFound ) { if ( pCell->GetCellType() == CELLTYPE_FORMULA ) - if (((ScFormulaCell*)pCell)->HasOneReference( aRef )) + if (((ScFormulaCell*)pCell)->HasRefListExpressibleAsOneReference( aRef )) if ( aRef.aStart.Row() == nRow && aRef.aEnd.Row() == nRow && aRef.aStart.Tab() == nTab && aRef.aEnd.Tab() == nTab && DiffSign( aRef.aStart.Col(), nCol ) == diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx index 74f2a97e9c2e..ae299fdf5fca 100644 --- a/sc/source/core/data/table3.cxx +++ b/sc/source/core/data/table3.cxx @@ -1022,12 +1022,19 @@ BOOL ScTable::ValidQuery(SCROW nRow, const ScQueryParam& rParam, } } else if ( (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL) || + (rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN || + rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_ENDS_WITH || + rEntry.eOp == SC_DOES_NOT_BEGIN_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH) || (rEntry.bQueryByString && (pCell ? pCell->HasStringData() : HasStringData( static_cast<SCCOL>(rEntry.nField), nRow)))) { // by String String aCellStr; + if( rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN + || rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_ENDS_WITH + || rEntry.eOp == SC_DOES_NOT_BEGIN_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH ) + bMatchWholeCell = FALSE; if ( pCell ) { if (pCell->GetCellType() != CELLTYPE_NOTE) @@ -1040,7 +1047,10 @@ BOOL ScTable::ValidQuery(SCROW nRow, const ScQueryParam& rParam, GetInputString( static_cast<SCCOL>(rEntry.nField), nRow, aCellStr ); BOOL bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL) - || (rEntry.eOp == SC_NOT_EQUAL))); + || (rEntry.eOp == SC_NOT_EQUAL) || (rEntry.eOp == SC_CONTAINS) + || (rEntry.eOp == SC_DOES_NOT_CONTAIN) || (rEntry.eOp == SC_BEGINS_WITH) + || (rEntry.eOp == SC_ENDS_WITH) || (rEntry.eOp == SC_DOES_NOT_BEGIN_WITH) + || (rEntry.eOp == SC_DOES_NOT_END_WITH))); BOOL bTestRegExp = (pbTestEqualCondition && rParam.bRegExp && ((rEntry.eOp == SC_LESS_EQUAL) || (rEntry.eOp == SC_GREATER_EQUAL))); @@ -1048,20 +1058,61 @@ BOOL ScTable::ValidQuery(SCROW nRow, const ScQueryParam& rParam, { xub_StrLen nStart = 0; xub_StrLen nEnd = aCellStr.Len(); - BOOL bMatch = (BOOL) rEntry.GetSearchTextPtr( rParam.bCaseSens ) - ->SearchFrwrd( aCellStr, &nStart, &nEnd ); + // from 614 on, nEnd is behind the found text + BOOL bMatch = FALSE; + if ( rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH ) + { + nEnd = 0; + nStart = aCellStr.Len(); + bMatch = (BOOL) rEntry.GetSearchTextPtr( rParam.bCaseSens ) + ->SearchBkwrd( aCellStr, &nStart, &nEnd ); + } + else + { + bMatch = (BOOL) rEntry.GetSearchTextPtr( rParam.bCaseSens ) + ->SearchFrwrd( aCellStr, &nStart, &nEnd ); + } if ( bMatch && bMatchWholeCell && (nStart != 0 || nEnd != aCellStr.Len()) ) bMatch = FALSE; // RegExp must match entire cell string if ( bRealRegExp ) - bOk = ((rEntry.eOp == SC_NOT_EQUAL) ? !bMatch : bMatch); + switch (rEntry.eOp) + { + case SC_EQUAL: + case SC_CONTAINS: + bOk = bMatch; + break; + case SC_NOT_EQUAL: + case SC_DOES_NOT_CONTAIN: + bOk = !bMatch; + break; + case SC_BEGINS_WITH: + bOk = ( bMatch && (nStart == 0) ); + break; + case SC_DOES_NOT_BEGIN_WITH: + bOk = !( bMatch && (nStart == 0) ); + break; + case SC_ENDS_WITH: + bOk = ( bMatch && (nEnd == aCellStr.Len()) ); + break; + case SC_DOES_NOT_END_WITH: + bOk = !( bMatch && (nEnd == aCellStr.Len()) ); + break; + default: + { + // added to avoid warnings + } + } else bTestEqual = bMatch; } if ( !bRealRegExp ) { - if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL ) + if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL + || rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN + || rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_ENDS_WITH + || rEntry.eOp == SC_DOES_NOT_BEGIN_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH ) { if ( !rEntry.bQueryByString && rEntry.pStr->Len() == 0 ) { @@ -1069,22 +1120,54 @@ BOOL ScTable::ValidQuery(SCROW nRow, const ScQueryParam& rParam, // the query value is assigned directly, and the string is empty. In that case, // don't find any string (isEqual would find empty string results in formula cells). bOk = FALSE; + if ( rEntry.eOp == SC_NOT_EQUAL ) + bOk = !bOk; } else if ( bMatchWholeCell ) + { bOk = pTransliteration->isEqual( aCellStr, *rEntry.pStr ); + if ( rEntry.eOp == SC_NOT_EQUAL ) + bOk = !bOk; + } else { - ::com::sun::star::uno::Sequence< sal_Int32 > xOff; String aCell( pTransliteration->transliterate( aCellStr, ScGlobal::eLnge, 0, aCellStr.Len(), - &xOff ) ); + NULL ) ); String aQuer( pTransliteration->transliterate( *rEntry.pStr, ScGlobal::eLnge, 0, rEntry.pStr->Len(), - &xOff ) ); - bOk = (aCell.Search( aQuer ) != STRING_NOTFOUND); + NULL ) ); + xub_StrLen nIndex = (rEntry.eOp == SC_ENDS_WITH + || rEntry.eOp == SC_DOES_NOT_END_WITH)? (aCell.Len()-aQuer.Len()):0; + xub_StrLen nStrPos = aCell.Search( aQuer, nIndex ); + switch (rEntry.eOp) + { + case SC_EQUAL: + case SC_CONTAINS: + bOk = ( nStrPos != STRING_NOTFOUND ); + break; + case SC_NOT_EQUAL: + case SC_DOES_NOT_CONTAIN: + bOk = ( nStrPos == STRING_NOTFOUND ); + break; + case SC_BEGINS_WITH: + bOk = ( nStrPos == 0 ); + break; + case SC_DOES_NOT_BEGIN_WITH: + bOk = ( nStrPos != 0 ); + break; + case SC_ENDS_WITH: + bOk = ( nStrPos + aQuer.Len() == aCell.Len() ); + break; + case SC_DOES_NOT_END_WITH: + bOk = ( nStrPos + aQuer.Len() != aCell.Len() ); + break; + default: + { + // added to avoid warnings + } + } } - if ( rEntry.eOp == SC_NOT_EQUAL ) - bOk = !bOk; } else { // use collator here because data was probably sorted 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/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx index 3d783e74c03d..9fcf743c1e85 100644 --- a/sc/source/core/inc/interpre.hxx +++ b/sc/source/core/inc/interpre.hxx @@ -70,6 +70,21 @@ struct ScCompare } }; +struct ScCompareOptions +{ + ScQueryEntry aQueryEntry; + bool bRegEx; + bool bMatchWholeCell; + bool bIgnoreCase; + + ScCompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry, bool bReg ); +private: + // Not implemented, prevent usage. + ScCompareOptions(); + ScCompareOptions( const ScCompareOptions & ); + ScCompareOptions& operator=( const ScCompareOptions & ); +}; + class ScToken; #define MAXSTACK (4096 / sizeof(formula::FormulaToken*)) @@ -356,9 +371,16 @@ void ScChoseJump(); // Returns true if last jump was executed and result matrix pushed. bool JumpMatrix( short nStackLevel ); -double CompareFunc( const ScCompare& rComp ); +/** @param pOptions + NULL means case sensitivity document option is to be used! + */ +double CompareFunc( const ScCompare& rComp, ScCompareOptions* pOptions = NULL ); double Compare(); -ScMatrixRef CompareMat(); +/** @param pOptions + NULL means case sensitivity document option is to be used! + */ +ScMatrixRef CompareMat( ScCompareOptions* pOptions = NULL ); +ScMatrixRef QueryMat( ScMatrix* pMat, ScCompareOptions& rOptions ); void ScEqual(); void ScNotEqual(); void ScLess(); diff --git a/sc/source/core/inc/refupdat.hxx b/sc/source/core/inc/refupdat.hxx index 0461578db0a6..2a8b17335fbf 100644 --- a/sc/source/core/inc/refupdat.hxx +++ b/sc/source/core/inc/refupdat.hxx @@ -82,7 +82,7 @@ public: ScComplexRefData& rRef, BOOL bWrap, BOOL bAbsolute ); static void MoveRelWrap( ScDocument* pDoc, const ScAddress& rPos, - ScComplexRefData& rRef ); + SCCOL nMaxCol, SCROW nMaxRow, ScComplexRefData& rRef ); /// Before calling, the absolute references must be up-to-date! static ScRefUpdateRes UpdateTranspose( ScDocument* pDoc, diff --git a/sc/source/core/tool/address.cxx b/sc/source/core/tool/address.cxx index 8b13374fe501..b38d5b52e4f5 100644 --- a/sc/source/core/tool/address.cxx +++ b/sc/source/core/tool/address.cxx @@ -1126,39 +1126,48 @@ lcl_ScAddress_Parse ( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr, bool ConvertSingleRef( ScDocument* pDoc, const String& rRefString, SCTAB nDefTab, ScRefAddress& rRefAddress, - const ScAddress::Details& rDetails ) + const ScAddress::Details& rDetails, + ScAddress::ExternalInfo* pExtInfo /* = NULL */ ) { - ScAddress aAddr( 0, 0, nDefTab ); - USHORT nRes = lcl_ScAddress_Parse( rRefString.GetBuffer(), pDoc, aAddr, rDetails, NULL ); - if( nRes & SCA_VALID ) + bool bRet = false; + if (pExtInfo || (ScGlobal::FindUnquoted( rRefString, SC_COMPILER_FILE_TAB_SEP) == STRING_NOTFOUND)) { - rRefAddress.Set( aAddr, - ((nRes & SCA_COL_ABSOLUTE) == 0), - ((nRes & SCA_ROW_ABSOLUTE) == 0), - ((nRes & SCA_TAB_ABSOLUTE) == 0)); - return TRUE; + ScAddress aAddr( 0, 0, nDefTab ); + USHORT nRes = aAddr.Parse( rRefString, pDoc, rDetails, pExtInfo); + if ( nRes & SCA_VALID ) + { + rRefAddress.Set( aAddr, + ((nRes & SCA_COL_ABSOLUTE) == 0), + ((nRes & SCA_ROW_ABSOLUTE) == 0), + ((nRes & SCA_TAB_ABSOLUTE) == 0)); + bRet = true; + } } - else - return FALSE; + return bRet; } bool ConvertDoubleRef( ScDocument* pDoc, const String& rRefString, SCTAB nDefTab, ScRefAddress& rStartRefAddress, ScRefAddress& rEndRefAddress, - const ScAddress::Details& rDetails ) + const ScAddress::Details& rDetails, + ScAddress::ExternalInfo* pExtInfo /* = NULL */ ) { - BOOL bRet = FALSE; - // FIXME : This will break for Lotus - xub_StrLen nPos = rRefString.Search(':'); - if (nPos != STRING_NOTFOUND) + bool bRet = false; + if (pExtInfo || (ScGlobal::FindUnquoted( rRefString, SC_COMPILER_FILE_TAB_SEP) == STRING_NOTFOUND)) { - String aTmp( rRefString ); - sal_Unicode* p = aTmp.GetBufferAccess(); - p[ nPos ] = 0; - if( ConvertSingleRef( pDoc, p, nDefTab, rStartRefAddress, rDetails ) ) + ScRange aRange( ScAddress( 0, 0, nDefTab)); + USHORT nRes = aRange.Parse( rRefString, pDoc, rDetails, pExtInfo); + if ( nRes & SCA_VALID ) { - nDefTab = rStartRefAddress.Tab(); - bRet = ConvertSingleRef( pDoc, p + nPos + 1, nDefTab, rEndRefAddress, rDetails ); + rStartRefAddress.Set( aRange.aStart, + ((nRes & SCA_COL_ABSOLUTE) == 0), + ((nRes & SCA_ROW_ABSOLUTE) == 0), + ((nRes & SCA_TAB_ABSOLUTE) == 0)); + rEndRefAddress.Set( aRange.aEnd, + ((nRes & SCA_COL2_ABSOLUTE) == 0), + ((nRes & SCA_ROW2_ABSOLUTE) == 0), + ((nRes & SCA_TAB2_ABSOLUTE) == 0)); + bRet = true; } } return bRet; diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index b0e1dac5062d..bc2266cbd3c8 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); + } } @@ -1811,9 +1822,11 @@ ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos,ScTokenArra aPos( rPos ), pCharClass( ScGlobal::pCharClass ), mnPredetectedReference(0), + mnRangeOpPosInSymbol(-1), pConv( pConvOOO_A1 ), mbCloseBrackets( true ), - mbExtendedErrorDetection( false ) + mbExtendedErrorDetection( false ), + mbRewind( false ) { nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0; } @@ -1824,9 +1837,11 @@ ScCompiler::ScCompiler( ScDocument* pDocument, const ScAddress& rPos) aPos( rPos ), pCharClass( ScGlobal::pCharClass ), mnPredetectedReference(0), + mnRangeOpPosInSymbol(-1), pConv( pConvOOO_A1 ), mbCloseBrackets( true ), - mbExtendedErrorDetection( false ) + mbExtendedErrorDetection( false ), + mbRewind( false ) { nMaxTab = pDoc ? pDoc->GetTableCount() - 1 : 0; } @@ -1962,7 +1977,7 @@ xub_StrLen ScCompiler::NextSymbol(bool bInArray) sal_Unicode c = *pSrc; sal_Unicode cLast = 0; bool bQuote = false; - bool bRangeOp = false; + mnRangeOpPosInSymbol = -1; ScanState eState = ssGetChar; xub_StrLen nSpaces = 0; sal_Unicode cSep = mxSymbols->getSymbol( ocSep).GetChar(0); @@ -2110,11 +2125,11 @@ Label_MaskStateMachine: else *pSym++ = c; } - else if (c == ':' && !bRangeOp) + else if (c == ':' && mnRangeOpPosInSymbol < 0) { // One range operator may form Sheet1.A:A, which we need to // pass as one entity to IsReference(). - bRangeOp = true; + mnRangeOpPosInSymbol = pSym - &cSymbol[0]; if( pSym == &cSymbol[ MAXSTRLEN-1 ] ) { SetError(errStringOverflow); @@ -2409,7 +2424,7 @@ Label_MaskStateMachine: { nSrcPos = sal::static_int_cast<xub_StrLen>( nSrcPos + nSpaces ); String aSymbol; - bRangeOp = false; + mnRangeOpPosInSymbol = -1; USHORT nErr = 0; do { @@ -2438,9 +2453,9 @@ Label_MaskStateMachine: bi18n = (c == cSheetSep || c == SC_COMPILER_FILE_TAB_SEP); } // One range operator restarts parsing for second reference. - if (c == ':' && !bRangeOp) + if (c == ':' && mnRangeOpPosInSymbol < 0) { - bRangeOp = true; + mnRangeOpPosInSymbol = aSymbol.Len(); bi18n = true; } if ( bi18n ) @@ -2460,6 +2475,14 @@ Label_MaskStateMachine: nSrcPos = sal::static_int_cast<xub_StrLen>( pSrc - pStart ); *pSym = 0; } + if (mnRangeOpPosInSymbol >= 0 && mnRangeOpPosInSymbol == (pSym-1) - &cSymbol[0]) + { + // This is a trailing range operator, which is nonsense. Will be caught + // in next round. + mnRangeOpPosInSymbol = -1; + *--pSym = 0; + --nSrcPos; + } if ( bAutoCorrect ) aCorrectedSymbol = cSymbol; if (bAutoIntersection && nSpaces > 1) @@ -2835,8 +2858,21 @@ BOOL ScCompiler::IsReference( const String& rName ) // Though the range operator is handled explicitly, when encountering // something like Sheet1.A:A we will have to treat it as one entity if it // doesn't pass as single cell reference. - if (ScGlobal::FindUnquoted( rName, ':') != STRING_NOTFOUND) - return IsDoubleReference( rName); + if (mnRangeOpPosInSymbol > 0) // ":foo" would be nonsense + { + if (IsDoubleReference( rName)) + return true; + // Now try with a symbol up to the range operator, rewind source + // position. + sal_Int32 nLen = mnRangeOpPosInSymbol; + while (cSymbol[++nLen]) + ; + cSymbol[mnRangeOpPosInSymbol] = 0; + nSrcPos -= static_cast<xub_StrLen>(nLen - mnRangeOpPosInSymbol); + mnRangeOpPosInSymbol = -1; + mbRewind = true; + return true; // end all checks + } return false; } @@ -3551,54 +3587,65 @@ BOOL ScCompiler::NextNewToken( bool bInArray ) // #42016# Italian ARCTAN.2 resulted in #REF! => IsOpcode() before // IsReference(). - const String aOrg( cSymbol ); - - if (bAsciiNonAlnum && IsOpCode( aOrg, bInArray )) - return true; - String aUpper; - bool bAsciiUpper = false; - if (bMayBeFuncName) + + do { - bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); - if (IsOpCode( aUpper, bInArray )) + mbRewind = false; + const String aOrg( cSymbol ); + + if (bAsciiNonAlnum && IsOpCode( aOrg, bInArray )) return true; - } - // Column 'DM' ("Deutsche Mark", German currency) couldn't be - // referred => IsReference() before IsValue(). - // Preserve case of file names in external references. - if (IsReference( aOrg )) - return true; + aUpper.Erase(); + bool bAsciiUpper = false; + if (bMayBeFuncName) + { + bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); + if (IsOpCode( aUpper, bInArray )) + return true; + } - if (!aUpper.Len()) - bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); + // Column 'DM' ("Deutsche Mark", German currency) couldn't be + // referred => IsReference() before IsValue(). + // Preserve case of file names in external references. + if (IsReference( aOrg )) + { + if (mbRewind) // Range operator, but no direct reference. + continue; // do; up to range operator. + return true; + } - // IsBoolean() before IsValue() to catch inline bools without the kludge - // for inline arrays. - if (bAllowBooleans && IsBoolean( aUpper )) - return true; + if (!aUpper.Len()) + bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); - if (IsValue( aUpper )) - return true; + // IsBoolean() before IsValue() to catch inline bools without the kludge + // for inline arrays. + if (bAllowBooleans && IsBoolean( aUpper )) + return true; - // User defined names and such do need i18n upper also in ODF. - if (bAsciiUpper) - aUpper = ScGlobal::pCharClass->upper( aOrg ); + if (IsValue( aUpper )) + return true; - if (IsNamedRange( aUpper )) - return true; - // Preserve case of file names in external references. - if (IsExternalNamedRange( aOrg )) - return true; - if (IsDBRange( aUpper )) - return true; - if (IsColRowName( aUpper )) - return true; - if (bMayBeFuncName && IsMacro( aUpper )) - return true; - if (bMayBeFuncName && IsOpCode2( aUpper )) - return true; + // User defined names and such do need i18n upper also in ODF. + if (bAsciiUpper) + aUpper = ScGlobal::pCharClass->upper( aOrg ); + + if (IsNamedRange( aUpper )) + return true; + // Preserve case of file names in external references. + if (IsExternalNamedRange( aOrg )) + return true; + if (IsDBRange( aUpper )) + return true; + if (IsColRowName( aUpper )) + return true; + if (bMayBeFuncName && IsMacro( aUpper )) + return true; + if (bMayBeFuncName && IsOpCode2( aUpper )) + return true; + + } while (mbRewind); if ( mbExtendedErrorDetection ) { @@ -3620,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 @@ -3627,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; @@ -3829,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() ); @@ -3865,7 +3959,7 @@ BOOL ScCompiler::HandleRange() if( pRangeData->HasReferences() ) { SetRelNameReference(); - MoveRelWrap(); + MoveRelWrap(pRangeData->GetMaxCol(), pRangeData->GetMaxRow()); } pNew->Reset(); if ( bAddPair ) @@ -3917,7 +4011,7 @@ BOOL ScCompiler::HandleExternalReference(const FormulaToken& _aToken) if (pNew->GetNextReference() != NULL) { SetRelNameReference(); - MoveRelWrap(); + MoveRelWrap(MAXCOL, MAXROW); } pNew->Reset(); return GetToken(); @@ -4012,33 +4106,33 @@ void ScCompiler::SetRelNameReference() // Wrap-adjust relative references of a RangeName to current position, // don't call for other token arrays! -void ScCompiler::MoveRelWrap() +void ScCompiler::MoveRelWrap( SCCOL nMaxCol, SCROW nMaxRow ) { pArr->Reset(); for( ScToken* t = static_cast<ScToken*>(pArr->GetNextReference()); t; t = static_cast<ScToken*>(pArr->GetNextReference()) ) { if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef ) - ScRefUpdate::MoveRelWrap( pDoc, aPos, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() ); + ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() ); else - ScRefUpdate::MoveRelWrap( pDoc, aPos, t->GetDoubleRef() ); + ScRefUpdate::MoveRelWrap( pDoc, aPos, nMaxCol, nMaxRow, t->GetDoubleRef() ); } } // static // Wrap-adjust relative references of a RangeName to current position, // don't call for other token arrays! -void ScCompiler::MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, - const ScAddress& rPos ) +void ScCompiler::MoveRelWrap( ScTokenArray& rArr, ScDocument* pDoc, const ScAddress& rPos, + SCCOL nMaxCol, SCROW nMaxRow ) { rArr.Reset(); for( ScToken* t = static_cast<ScToken*>(rArr.GetNextReference()); t; t = static_cast<ScToken*>(rArr.GetNextReference()) ) { if ( t->GetType() == svSingleRef || t->GetType() == svExternalSingleRef ) - ScRefUpdate::MoveRelWrap( pDoc, rPos, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() ); + ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, SingleDoubleRefModifier( t->GetSingleRef() ).Ref() ); else - ScRefUpdate::MoveRelWrap( pDoc, rPos, t->GetDoubleRef() ); + ScRefUpdate::MoveRelWrap( pDoc, rPos, nMaxCol, nMaxRow, t->GetDoubleRef() ); } } @@ -4213,7 +4307,7 @@ ScRangeData* ScCompiler::UpdateReference(UpdateRefMode eUpdateRefMode, SingleDoubleRefModifier aMod( rRef ); if ( rRef.IsRelName() ) { - ScRefUpdate::MoveRelWrap( pDoc, aPos, aMod.Ref() ); + ScRefUpdate::MoveRelWrap( pDoc, aPos, MAXCOL, MAXROW, aMod.Ref() ); rChanged = TRUE; } else @@ -4243,7 +4337,7 @@ ScRangeData* ScCompiler::UpdateReference(UpdateRefMode eUpdateRefMode, SCTAB nTabs = rRef.Ref2.nTab - rRef.Ref1.nTab; if ( rRef.Ref1.IsRelName() || rRef.Ref2.IsRelName() ) { - ScRefUpdate::MoveRelWrap( pDoc, aPos, rRef ); + ScRefUpdate::MoveRelWrap( pDoc, aPos, MAXCOL, MAXROW, rRef ); rChanged = TRUE; } else 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/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index ec4c4c293839..195366271f0d 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -71,6 +71,7 @@ #include "lookupcache.hxx" #include "rangenam.hxx" #include "compiler.hxx" +#include "externalrefmgr.hxx" #define SC_DOUBLE_MAXVALUE 1.7e307 @@ -626,7 +627,20 @@ bool ScInterpreter::JumpMatrix( short nStackLevel ) } -double ScInterpreter::CompareFunc( const ScCompare& rComp ) +ScCompareOptions::ScCompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry, bool bReg ) : + aQueryEntry(rEntry), + bRegEx(bReg), + bMatchWholeCell(pDoc->GetDocOptions().IsMatchWholeCell()), + bIgnoreCase(true) +{ + bRegEx = (bRegEx && (aQueryEntry.eOp == SC_EQUAL || aQueryEntry.eOp == SC_NOT_EQUAL)); + // Interpreter functions usually are case insensitive, except the simple + // comparison operators, for which these options aren't used. Override in + // struct if needed. +} + + +double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOptions ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CompareFunc" ); // Keep DoubleError if encountered @@ -698,7 +712,53 @@ double ScInterpreter::CompareFunc( const ScCompare& rComp ) fRes = 1; // number is less than string else { - if (pDok->GetDocOptions().IsIgnoreCase()) + // Both strings. + if (pOptions) + { + // All similar to Sctable::ValidQuery(), *rComp.pVal[1] actually + // is/must be identical to *rEntry.pStr, which is essential for + // regex to work through GetSearchTextPtr(). + ScQueryEntry& rEntry = pOptions->aQueryEntry; + DBG_ASSERT( *rComp.pVal[1] == *rEntry.pStr, "ScInterpreter::CompareFunc: broken options"); + if (pOptions->bRegEx) + { + xub_StrLen nStart = 0; + xub_StrLen nStop = rComp.pVal[0]->Len(); + bool bMatch = rEntry.GetSearchTextPtr( + !pOptions->bIgnoreCase)->SearchFrwrd( *rComp.pVal[0], + &nStart, &nStop); + if (bMatch && pOptions->bMatchWholeCell && (nStart != 0 || nStop != rComp.pVal[0]->Len())) + bMatch = false; // RegEx must match entire string. + fRes = (bMatch ? 0 : 1); + } + else if (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL) + { + ::utl::TransliterationWrapper* pTransliteration = + (pOptions->bIgnoreCase ? ScGlobal::pTransliteration : + ScGlobal::pCaseTransliteration); + bool bMatch; + if (pOptions->bMatchWholeCell) + bMatch = pTransliteration->isEqual( *rComp.pVal[0], *rComp.pVal[1]); + else + { + String aCell( pTransliteration->transliterate( + *rComp.pVal[0], ScGlobal::eLnge, 0, + rComp.pVal[0]->Len(), NULL)); + String aQuer( pTransliteration->transliterate( + *rComp.pVal[1], ScGlobal::eLnge, 0, + rComp.pVal[1]->Len(), NULL)); + bMatch = (aCell.Search( aQuer ) != STRING_NOTFOUND); + } + fRes = (bMatch ? 0 : 1); + } + else if (pOptions->bIgnoreCase) + fRes = (double) ScGlobal::pCollator->compareString( + *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] ); + else + fRes = (double) ScGlobal::pCaseCollator->compareString( + *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] ); + } + else if (pDok->GetDocOptions().IsIgnoreCase()) fRes = (double) ScGlobal::pCollator->compareString( *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] ); else @@ -763,7 +823,7 @@ double ScInterpreter::Compare() } -ScMatrixRef ScInterpreter::CompareMat() +ScMatrixRef ScInterpreter::CompareMat( ScCompareOptions* pOptions ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CompareMat" ); String aVal1, aVal2; @@ -855,7 +915,7 @@ ScMatrixRef ScInterpreter::CompareMat() aComp.bEmpty[i] = FALSE; } } - pResMat->PutDouble( CompareFunc( aComp ), j,k ); + pResMat->PutDouble( CompareFunc( aComp, pOptions ), j,k ); } else pResMat->PutString( ScGlobal::GetRscString(STR_NO_VALUE), j,k ); @@ -885,7 +945,7 @@ ScMatrixRef ScInterpreter::CompareMat() *aComp.pVal[i] = pMat[i]->GetString(j); aComp.bEmpty[i] = pMat[i]->IsEmpty(j); } - pResMat->PutDouble( CompareFunc( aComp ), j ); + pResMat->PutDouble( CompareFunc( aComp, pOptions ), j ); } } } @@ -894,6 +954,52 @@ ScMatrixRef ScInterpreter::CompareMat() } +ScMatrixRef ScInterpreter::QueryMat( ScMatrix* pMat, ScCompareOptions& rOptions ) +{ + short nSaveCurFmtType = nCurFmtType; + short nSaveFuncFmtType = nFuncFmtType; + PushMatrix( pMat); + if (rOptions.aQueryEntry.bQueryByString) + PushString( *rOptions.aQueryEntry.pStr); + else + PushDouble( rOptions.aQueryEntry.nVal); + ScMatrixRef pResultMatrix = CompareMat( &rOptions); + nCurFmtType = nSaveCurFmtType; + nFuncFmtType = nSaveFuncFmtType; + if (nGlobalError || !pResultMatrix) + { + SetError( errIllegalParameter); + return pResultMatrix; + } + + switch (rOptions.aQueryEntry.eOp) + { + case SC_EQUAL: + pResultMatrix->CompareEqual(); + break; + case SC_LESS: + pResultMatrix->CompareLess(); + break; + case SC_GREATER: + pResultMatrix->CompareGreater(); + break; + case SC_LESS_EQUAL: + pResultMatrix->CompareLessEqual(); + break; + case SC_GREATER_EQUAL: + pResultMatrix->CompareGreaterEqual(); + break; + case SC_NOT_EQUAL: + pResultMatrix->CompareNotEqual(); + break; + default: + SetError( errIllegalArgument); + DBG_ERROR1( "ScInterpreter::QueryMat: unhandled comparison operator: %d", (int)rOptions.aQueryEntry.eOp); + } + return pResultMatrix; +} + + void ScInterpreter::ScEqual() { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScEqual" ); @@ -4310,6 +4416,7 @@ void ScInterpreter::ScCountIf() SCCOL nCol2; SCROW nRow2; SCTAB nTab2; + ScMatrixRef pQueryMatrix; switch ( GetStackType() ) { case svDoubleRef : @@ -4326,6 +4433,24 @@ void ScInterpreter::ScCountIf() nRow2 = nRow1; nTab2 = nTab1; break; + case svMatrix: + { + pQueryMatrix = PopMatrix(); + if (!pQueryMatrix) + { + PushIllegalParameter(); + return; + } + nCol1 = 0; + nRow1 = 0; + nTab1 = 0; + SCSIZE nC, nR; + pQueryMatrix->GetDimensions( nC, nR); + nCol2 = static_cast<SCCOL>(nC - 1); + nRow2 = static_cast<SCROW>(nR - 1); + nTab2 = 0; + } + break; default: PushIllegalParameter(); return ; @@ -4367,15 +4492,37 @@ void ScInterpreter::ScCountIf() rParam.nCol1 = nCol1; rParam.nCol2 = nCol2; rEntry.nField = nCol1; - ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE); - // Entry.nField im Iterator bei Spaltenwechsel weiterschalten - aCellIter.SetAdvanceQueryParamEntryField( TRUE ); - if ( aCellIter.GetFirst() ) + if (pQueryMatrix) { - do + // Never case-sensitive. + ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp); + ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions); + if (nGlobalError || !pResultMatrix) { - fSum++; - } while ( aCellIter.GetNext() ); + PushIllegalParameter(); + return; + } + + SCSIZE nSize = pResultMatrix->GetElementCount(); + for (SCSIZE nIndex = 0; nIndex < nSize; ++nIndex) + { + if (pResultMatrix->IsValue( nIndex) && + pResultMatrix->GetDouble( nIndex)) + ++fSum; + } + } + else + { + ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE); + // Entry.nField im Iterator bei Spaltenwechsel weiterschalten + aCellIter.SetAdvanceQueryParamEntryField( TRUE ); + if ( aCellIter.GetFirst() ) + { + do + { + fSum++; + } while ( aCellIter.GetNext() ); + } } } else @@ -4399,6 +4546,7 @@ void ScInterpreter::ScSumIf() SCROW nRow3 = 0; SCTAB nTab3 = 0; + ScMatrixRef pSumExtraMatrix; bool bSumExtraRange = (nParamCount == 3); if (bSumExtraRange) { @@ -4423,6 +4571,10 @@ void ScInterpreter::ScSumIf() case svSingleRef : PopSingleRef( nCol3, nRow3, nTab3 ); break; + case svMatrix: + pSumExtraMatrix = PopMatrix(); + //! nCol3, nRow3, nTab3 remain 0 + break; default: PushIllegalParameter(); return ; @@ -4498,6 +4650,7 @@ void ScInterpreter::ScSumIf() SCCOL nCol2; SCROW nRow2; SCTAB nTab2; + ScMatrixRef pQueryMatrix; switch ( GetStackType() ) { case svRefList : @@ -4522,13 +4675,31 @@ void ScInterpreter::ScSumIf() nRow2 = nRow1; nTab2 = nTab1; break; + case svMatrix: + { + pQueryMatrix = PopMatrix(); + if (!pQueryMatrix) + { + PushIllegalParameter(); + return; + } + nCol1 = 0; + nRow1 = 0; + nTab1 = 0; + SCSIZE nC, nR; + pQueryMatrix->GetDimensions( nC, nR); + nCol2 = static_cast<SCCOL>(nC - 1); + nRow2 = static_cast<SCROW>(nR - 1); + nTab2 = 0; + } + break; default: PushIllegalParameter(); return ; } if ( nTab1 != nTab2 ) { - PushIllegalParameter(); + PushIllegalArgument(); return; } @@ -4544,15 +4715,29 @@ void ScInterpreter::ScSumIf() // instead of the result range. SCCOL nColDelta = nCol2 - nCol1; SCROW nRowDelta = nRow2 - nRow1; - if (nCol3 + nColDelta > MAXCOL) + SCCOL nMaxCol; + SCROW nMaxRow; + if (pSumExtraMatrix) { - SCCOL nNewDelta = MAXCOL - nCol3; + SCSIZE nC, nR; + pSumExtraMatrix->GetDimensions( nC, nR); + nMaxCol = static_cast<SCCOL>(nC - 1); + nMaxRow = static_cast<SCROW>(nR - 1); + } + else + { + nMaxCol = MAXCOL; + nMaxRow = MAXROW; + } + if (nCol3 + nColDelta > nMaxCol) + { + SCCOL nNewDelta = nMaxCol - nCol3; nCol2 = nCol1 + nNewDelta; } - if (nRow3 + nRowDelta > MAXROW) + if (nRow3 + nRowDelta > nMaxRow) { - SCROW nNewDelta = MAXROW - nRow3; + SCROW nNewDelta = nMaxRow - nRow3; nRow2 = nRow1 + nNewDelta; } } @@ -4592,30 +4777,119 @@ void ScInterpreter::ScSumIf() rParam.nCol1 = nCol1; rParam.nCol2 = nCol2; rEntry.nField = nCol1; - SCCOL nColDiff = nCol3 - nCol1; - SCROW nRowDiff = nRow3 - nRow1; - ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE); - // Increment Entry.nField in iterator when switching to next column. - aCellIter.SetAdvanceQueryParamEntryField( TRUE ); - if ( aCellIter.GetFirst() ) + SCsCOL nColDiff = nCol3 - nCol1; + SCsROW nRowDiff = nRow3 - nRow1; + if (pQueryMatrix) { - do + // Never case-sensitive. + ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp); + ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions); + if (nGlobalError || !pResultMatrix) { - aAdr.SetCol( aCellIter.GetCol() + nColDiff); - aAdr.SetRow( aCellIter.GetRow() + nRowDiff); - ScBaseCell* pCell = GetCell( aAdr ); - if ( HasCellValueData(pCell) ) + PushIllegalParameter(); + return; + } + + if (pSumExtraMatrix) + { + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) { - fVal = GetCellValue( aAdr, pCell ); - if ( bNull && fVal != 0.0 ) + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) { - bNull = FALSE; - fMem = fVal; + if (pResultMatrix->IsValue( nCol, nRow) && + pResultMatrix->GetDouble( nCol, nRow)) + { + SCSIZE nC = nCol + nColDiff; + SCSIZE nR = nRow + nRowDiff; + if (pSumExtraMatrix->IsValue( nC, nR)) + { + fVal = pSumExtraMatrix->GetDouble( nC, nR); + if ( bNull && fVal != 0.0 ) + { + bNull = FALSE; + fMem = fVal; + } + else + fSum += fVal; + } + } } - else - fSum += fVal; } - } while ( aCellIter.GetNext() ); + } + else + { + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + { + for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) + { + if (pResultMatrix->GetDouble( nCol, nRow)) + { + aAdr.SetCol( nCol + nColDiff); + aAdr.SetRow( nRow + nRowDiff); + ScBaseCell* pCell = GetCell( aAdr ); + if ( HasCellValueData(pCell) ) + { + fVal = GetCellValue( aAdr, pCell ); + if ( bNull && fVal != 0.0 ) + { + bNull = FALSE; + fMem = fVal; + } + else + fSum += fVal; + } + } + } + } + } + } + else + { + ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE); + // Increment Entry.nField in iterator when switching to next column. + aCellIter.SetAdvanceQueryParamEntryField( TRUE ); + if ( aCellIter.GetFirst() ) + { + if (pSumExtraMatrix) + { + do + { + SCSIZE nC = aCellIter.GetCol() + nColDiff; + SCSIZE nR = aCellIter.GetRow() + nRowDiff; + if (pSumExtraMatrix->IsValue( nC, nR)) + { + fVal = pSumExtraMatrix->GetDouble( nC, nR); + if ( bNull && fVal != 0.0 ) + { + bNull = FALSE; + fMem = fVal; + } + else + fSum += fVal; + } + } while ( aCellIter.GetNext() ); + } + else + { + do + { + aAdr.SetCol( aCellIter.GetCol() + nColDiff); + aAdr.SetRow( aCellIter.GetRow() + nRowDiff); + ScBaseCell* pCell = GetCell( aAdr ); + if ( HasCellValueData(pCell) ) + { + fVal = GetCellValue( aAdr, pCell ); + if ( bNull && fVal != 0.0 ) + { + bNull = FALSE; + fMem = fVal; + } + else + fSum += fVal; + } + } while ( aCellIter.GetNext() ); + } + } } } else @@ -5762,6 +6036,52 @@ void ScInterpreter::ScDBVarP() } +ScTokenArray* lcl_CreateExternalRefTokenArray( const ScAddress& rPos, ScDocument* pDoc, + const ScAddress::ExternalInfo& rExtInfo, const ScRefAddress& rRefAd1, + const ScRefAddress* pRefAd2 ) +{ + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + size_t nSheets = 1; + const String* pRealTab = pRefMgr->getRealTableName( rExtInfo.mnFileId, rExtInfo.maTabName); + ScTokenArray* pTokenArray = new ScTokenArray; + if (pRefAd2) + { + ScComplexRefData aRef; + aRef.InitRangeRel( ScRange( rRefAd1.GetAddress(), pRefAd2->GetAddress()), rPos); + aRef.Ref1.SetColRel( rRefAd1.IsRelCol()); + aRef.Ref1.SetRowRel( rRefAd1.IsRelRow()); + aRef.Ref1.SetTabRel( rRefAd1.IsRelTab()); + aRef.Ref1.SetFlag3D( true); + aRef.Ref2.SetColRel( pRefAd2->IsRelCol()); + aRef.Ref2.SetRowRel( pRefAd2->IsRelRow()); + aRef.Ref2.SetTabRel( pRefAd2->IsRelTab()); + nSheets = aRef.Ref2.nTab - aRef.Ref1.nTab + 1; + aRef.Ref2.SetFlag3D( nSheets > 1 ); + pTokenArray->AddExternalDoubleReference( rExtInfo.mnFileId, + (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef); + } + else + { + ScSingleRefData aRef; + aRef.InitAddressRel( rRefAd1.GetAddress(), rPos); + aRef.SetColRel( rRefAd1.IsRelCol()); + aRef.SetRowRel( rRefAd1.IsRelRow()); + aRef.SetTabRel( rRefAd1.IsRelTab()); + aRef.SetFlag3D( true); + pTokenArray->AddExternalSingleReference( rExtInfo.mnFileId, + (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef); + } + // The indirect usage of the external table can't be detected during the + // store-to-file cycle, mark it as permanently referenced so it gets stored + // even if not directly referenced anywhere. + pRefMgr->setCacheTableReferencedPermanently( rExtInfo.mnFileId, + rExtInfo.maTabName, nSheets); + ScCompiler aComp( pDoc, rPos, *pTokenArray); + aComp.CompileTokenArray(); + return pTokenArray; +} + + void ScInterpreter::ScIndirect() { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIndirect" ); @@ -5780,15 +6100,46 @@ void ScInterpreter::ScIndirect() SCTAB nTab = aPos.Tab(); String sRefStr( GetString() ); ScRefAddress aRefAd, aRefAd2; - if ( ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd, aRefAd2, aDetails) || + ScAddress::ExternalInfo aExtInfo; + if ( ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd, aRefAd2, aDetails, &aExtInfo) || (bTryXlA1 && ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd, - aRefAd2, aDetailsXlA1))) - PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(), - aRefAd2.Col(), aRefAd2.Row(), aRefAd2.Tab() ); - else if ( ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd, aDetails) || + aRefAd2, aDetailsXlA1, &aExtInfo))) + { + if (aExtInfo.mbExternal) + { + /* TODO: future versions should implement a proper subroutine + * token. This procedure here is a minimally invasive fix for + * #i101645# in OOo3.1.1 */ + // Push a subroutine on the instruction code stack that + // resolves the external reference as the next instruction. + aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok, + aExtInfo, aRefAd, &aRefAd2)); + // Signal subroutine call to interpreter. + PushTempToken( new FormulaUnknownToken( ocCall)); + } + else + PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(), + aRefAd2.Col(), aRefAd2.Row(), aRefAd2.Tab() ); + } + else if ( ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd, aDetails, &aExtInfo) || (bTryXlA1 && ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd, - aDetailsXlA1))) - PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() ); + aDetailsXlA1, &aExtInfo))) + { + if (aExtInfo.mbExternal) + { + /* TODO: future versions should implement a proper subroutine + * token. This procedure here is a minimally invasive fix for + * #i101645# in OOo3.1.1 */ + // Push a subroutine on the instruction code stack that + // resolves the external reference as the next instruction. + aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok, + aExtInfo, aRefAd, NULL)); + // Signal subroutine call to interpreter. + PushTempToken( new FormulaUnknownToken( ocCall)); + } + else + PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() ); + } else { do diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index 2722925fc56d..a73fe62998a6 100644 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -3812,6 +3812,15 @@ StackVar ScInterpreter::Interpret() default : PushError( errUnknownOpCode); break; } + // If the function signalled that it pushed a subroutine on the + // instruction code stack instead of a result, continue with + // execution of the subroutine. + if (sp > nStackBase && pStack[sp-1]->GetOpCode() == ocCall) + { + Pop(); + continue; // while( ( pCur = aCode.Next() ) != NULL ... + } + // Remember result matrix in case it could be reused. if (pTokenMatrixMap && sp && GetStackType() == svMatrix) pTokenMatrixMap->insert( ScTokenMatrixMap::value_type( pCur, 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/core/tool/progress.cxx b/sc/source/core/tool/progress.cxx index fc7a7088d2a9..450736997c2d 100644 --- a/sc/source/core/tool/progress.cxx +++ b/sc/source/core/tool/progress.cxx @@ -162,7 +162,7 @@ void ScProgress::CreateInterpretProgress( ScDocument* pDoc, BOOL bWait ) if ( !pGlobalProgress ) pInterpretProgress = new ScProgress( pDoc->GetDocumentShell(), ScGlobal::GetRscString( STR_PROGRESS_CALCULATING ), - pDoc->GetFormulaCodeInTree(), FALSE, bWait ); + pDoc->GetFormulaCodeInTree()/MIN_NO_CODES_PER_PROGRESS_UPDATE, FALSE, bWait ); pInterpretDoc = pDoc; } } diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx index 704c3255486e..4a4683935e99 100644 --- a/sc/source/core/tool/rangenam.cxx +++ b/sc/source/core/tool/rangenam.cxx @@ -60,7 +60,7 @@ using namespace formula; // Interner ctor fuer das Suchen nach einem Index ScRangeData::ScRangeData( USHORT n ) - : pCode( NULL ), nIndex( n ), bModified( FALSE ) + : pCode( NULL ), nIndex( n ), bModified( FALSE ), mnMaxRow(-1), mnMaxCol(-1) {} ScRangeData::ScRangeData( ScDocument* pDok, @@ -76,7 +76,9 @@ ScRangeData::ScRangeData( ScDocument* pDok, eType ( nType ), pDoc ( pDok ), nIndex ( 0 ), - bModified ( FALSE ) + bModified ( FALSE ), + mnMaxRow (-1), + mnMaxCol (-1) { if (rSymbol.Len() > 0) { @@ -122,7 +124,9 @@ ScRangeData::ScRangeData( ScDocument* pDok, eType ( nType ), pDoc ( pDok ), nIndex ( 0 ), - bModified ( FALSE ) + bModified ( FALSE ), + mnMaxRow (-1), + mnMaxCol (-1) { if( !pCode->GetCodeError() ) { @@ -157,7 +161,9 @@ ScRangeData::ScRangeData( ScDocument* pDok, eType ( RT_NAME ), pDoc ( pDok ), nIndex ( 0 ), - bModified ( FALSE ) + bModified ( FALSE ), + mnMaxRow (-1), + mnMaxCol (-1) { ScSingleRefData aRefData; aRefData.InitAddress( rTarget ); @@ -179,7 +185,9 @@ ScRangeData::ScRangeData(const ScRangeData& rScRangeData) : eType (rScRangeData.eType), pDoc (rScRangeData.pDoc), nIndex (rScRangeData.nIndex), - bModified (rScRangeData.bModified) + bModified (rScRangeData.bModified), + mnMaxRow (rScRangeData.mnMaxRow), + mnMaxCol (rScRangeData.mnMaxCol) {} ScRangeData::~ScRangeData() @@ -247,7 +255,7 @@ void ScRangeData::UpdateSymbol( rtl::OUStringBuffer& rBuffer, const ScAddress& r ::std::auto_ptr<ScTokenArray> pTemp( pCode->Clone() ); ScCompiler aComp( pDoc, rPos, *pTemp.get()); aComp.SetGrammar(eGrammar); - aComp.MoveRelWrap(); + aComp.MoveRelWrap(GetMaxCol(), GetMaxRow()); aComp.CreateStringFromTokenArray( rBuffer ); } @@ -393,7 +401,7 @@ BOOL ScRangeData::IsReference( ScRange& rRange, const ScAddress& rPos ) const ::std::auto_ptr<ScTokenArray> pTemp( pCode->Clone() ); ScCompiler aComp( pDoc, rPos, *pTemp); aComp.SetGrammar(pDoc->GetGrammar()); - aComp.MoveRelWrap(); + aComp.MoveRelWrap(MAXCOL, MAXROW); return pTemp->IsReference( rRange ); } @@ -520,6 +528,26 @@ BOOL ScRangeData::IsNameValid( const String& rName, ScDocument* pDoc ) return TRUE; } +void ScRangeData::SetMaxRow(SCROW nRow) +{ + mnMaxRow = nRow; +} + +SCROW ScRangeData::GetMaxRow() const +{ + return mnMaxRow >= 0 ? mnMaxRow : MAXROW; +} + +void ScRangeData::SetMaxCol(SCCOL nCol) +{ + mnMaxCol = nCol; +} + +SCCOL ScRangeData::GetMaxCol() const +{ + return mnMaxCol >= 0 ? mnMaxCol : MAXCOL; +} + USHORT ScRangeData::GetErrCode() { diff --git a/sc/source/core/tool/reftokenhelper.cxx b/sc/source/core/tool/reftokenhelper.cxx index 1e80700b40ec..e129abdcf97f 100644 --- a/sc/source/core/tool/reftokenhelper.cxx +++ b/sc/source/core/tool/reftokenhelper.cxx @@ -54,8 +54,9 @@ void ScRefTokenHelper::compileRangeRepresentation( const sal_Unicode cSep = ';'; const sal_Unicode cQuote = '\''; + bool bFailure = false; sal_Int32 nOffset = 0; - while (nOffset >= 0) + while (nOffset >= 0 && !bFailure) { OUString aToken; ScRangeStringConverter::GetTokenByOffset(aToken, rRangeStr, nOffset, cSep, cQuote); @@ -66,14 +67,49 @@ void ScRefTokenHelper::compileRangeRepresentation( aCompiler.SetGrammar(eGrammar); auto_ptr<ScTokenArray> pArray(aCompiler.CompileString(aToken)); - // There should only be one reference per range token. - pArray->Reset(); - FormulaToken* p = pArray->GetNextReference(); - if (!p) - continue; + // There MUST be exactly one reference per range token and nothing + // else, and it MUST be a valid reference, not some #REF! + USHORT nLen = pArray->GetLen(); + if (!nLen) + continue; // Should a missing range really be allowed? + if (nLen != 1) + bFailure = true; + else + { + pArray->Reset(); + const FormulaToken* p = pArray->GetNextReference(); + if (!p) + bFailure = true; + else + { + const ScToken* pT = static_cast<const ScToken*>(p); + switch (pT->GetType()) + { + case svSingleRef: + if (!pT->GetSingleRef().Valid()) + bFailure = true; + break; + case svDoubleRef: + if (!pT->GetDoubleRef().Valid()) + bFailure = true; + break; + case svExternalSingleRef: + if (!pT->GetSingleRef().ValidExternal()) + bFailure = true; + break; + case svExternalDoubleRef: + if (!pT->GetDoubleRef().ValidExternal()) + bFailure = true; + break; + default: + ; + } + if (!bFailure) + rRefTokens.push_back( + ScSharedTokenRef(static_cast<ScToken*>(p->Clone()))); + } + } - rRefTokens.push_back( - ScSharedTokenRef(static_cast<ScToken*>(p->Clone()))); #if 0 switch (p->GetType()) { @@ -93,7 +129,10 @@ void ScRefTokenHelper::compileRangeRepresentation( ; } #endif + } + if (bFailure) + rRefTokens.clear(); } bool ScRefTokenHelper::getRangeFromToken(ScRange& rRange, const ScSharedTokenRef& pToken, bool bExternal) diff --git a/sc/source/core/tool/refupdat.cxx b/sc/source/core/tool/refupdat.cxx index d019a6082583..ddb5f3dc0a5c 100644 --- a/sc/source/core/tool/refupdat.cxx +++ b/sc/source/core/tool/refupdat.cxx @@ -821,27 +821,27 @@ ScRefUpdateRes ScRefUpdate::Move( ScDocument* pDoc, const ScAddress& rPos, } void ScRefUpdate::MoveRelWrap( ScDocument* pDoc, const ScAddress& rPos, - ScComplexRefData& rRef ) + SCCOL nMaxCol, SCROW nMaxRow, ScComplexRefData& rRef ) { if( rRef.Ref1.IsColRel() ) { rRef.Ref1.nCol = rRef.Ref1.nRelCol + rPos.Col(); - lcl_MoveItWrap( rRef.Ref1.nCol, static_cast<SCsCOL>(0), MAXCOL ); + lcl_MoveItWrap( rRef.Ref1.nCol, static_cast<SCsCOL>(0), nMaxCol ); } if( rRef.Ref2.IsColRel() ) { rRef.Ref2.nCol = rRef.Ref2.nRelCol + rPos.Col(); - lcl_MoveItWrap( rRef.Ref2.nCol, static_cast<SCsCOL>(0), MAXCOL ); + lcl_MoveItWrap( rRef.Ref2.nCol, static_cast<SCsCOL>(0), nMaxCol ); } if( rRef.Ref1.IsRowRel() ) { rRef.Ref1.nRow = rRef.Ref1.nRelRow + rPos.Row(); - lcl_MoveItWrap( rRef.Ref1.nRow, static_cast<SCsROW>(0), MAXROW ); + lcl_MoveItWrap( rRef.Ref1.nRow, static_cast<SCsROW>(0), nMaxRow ); } if( rRef.Ref2.IsRowRel() ) { rRef.Ref2.nRow = rRef.Ref2.nRelRow + rPos.Row(); - lcl_MoveItWrap( rRef.Ref2.nRow, static_cast<SCsROW>(0), MAXROW ); + lcl_MoveItWrap( rRef.Ref2.nRow, static_cast<SCsROW>(0), nMaxRow ); } SCsTAB nMaxTab = (SCsTAB) pDoc->GetTableCount() - 1; if( rRef.Ref1.IsTabRel() ) diff --git a/sc/source/filter/excel/excimp8.cxx b/sc/source/filter/excel/excimp8.cxx index c4063c74add6..1d209b91bc68 100644 --- a/sc/source/filter/excel/excimp8.cxx +++ b/sc/source/filter/excel/excimp8.cxx @@ -427,6 +427,38 @@ void XclImpAutoFilterData::InsertQueryParam() } } +static void ExcelQueryToOooQuery( ScQueryEntry& rEntry ) +{ + if( ( rEntry.eOp != SC_EQUAL && rEntry.eOp != SC_NOT_EQUAL ) || rEntry.pStr == NULL ) + return; + else + { + xub_StrLen nLen = rEntry.pStr->Len(); + sal_Unicode nStart = rEntry.pStr->GetChar( 0 ); + sal_Unicode nEnd = rEntry.pStr->GetChar( nLen-1 ); + if( nLen >2 && nStart == '*' && nEnd == '*' ) + { + rEntry.pStr->Erase( nLen-1, 1 ); + rEntry.pStr->Erase( 0, 1 ); + rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_CONTAINS : SC_DOES_NOT_CONTAIN; + } + else if( nLen > 1 && nStart == '*' && nEnd != '*' ) + { + rEntry.pStr->Erase( 0, 1 ); + rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_ENDS_WITH : SC_DOES_NOT_END_WITH; + } + else if( nLen > 1 && nStart != '*' && nEnd == '*' ) + { + rEntry.pStr->Erase( nLen-1, 1 ); + rEntry.eOp = ( rEntry.eOp == SC_EQUAL ) ? SC_BEGINS_WITH : SC_DOES_NOT_BEGIN_WITH; + } + else if( nLen == 2 && nStart == '*' && nEnd == '*' ) + { + rEntry.pStr->Erase( 0, 1 ); + } + } +} + void XclImpAutoFilterData::ReadAutoFilter( XclImpStream& rStrm ) { UINT16 nCol, nFlags; @@ -464,14 +496,14 @@ void XclImpAutoFilterData::ReadAutoFilter( XclImpStream& rStrm ) BOOL bIgnore; UINT8 nStrLen[ 2 ] = { 0, 0 }; - String* pEntryStr[ 2 ] = { NULL, NULL }; + ScQueryEntry *pQueryEntries[ 2 ] = { NULL, NULL }; for( nE = 0; nE < 2; nE++ ) { if( nFirstEmpty < nCount ) { ScQueryEntry& aEntry = aParam.GetEntry( nFirstEmpty ); - pEntryStr[ nE ] = aEntry.pStr; + pQueryEntries[ nE ] = &aEntry; bIgnore = FALSE; rStrm >> nType >> nOper; @@ -559,8 +591,12 @@ void XclImpAutoFilterData::ReadAutoFilter( XclImpStream& rStrm ) } for( nE = 0; nE < 2; nE++ ) - if( nStrLen[ nE ] && pEntryStr[ nE ] ) - pEntryStr[ nE ]->Assign( rStrm.ReadUniString( nStrLen[ nE ] ) ); + if( nStrLen[ nE ] && pQueryEntries[ nE ] ) + { + pQueryEntries[ nE ]->pStr->Assign ( rStrm.ReadUniString( nStrLen[ nE ] ) ); + ExcelQueryToOooQuery( *pQueryEntries[ nE ] ); + } + } } diff --git a/sc/source/filter/excel/excrecds.cxx b/sc/source/filter/excel/excrecds.cxx index 89a814c8f3c3..0f51bb8f2f1b 100644 --- a/sc/source/filter/excel/excrecds.cxx +++ b/sc/source/filter/excel/excrecds.cxx @@ -724,7 +724,31 @@ BOOL XclExpAutofilter::AddEntry( const ScQueryEntry& rEntry ) String sText; if( rEntry.pStr ) + { sText.Assign( *rEntry.pStr ); + switch( rEntry.eOp ) + { + case SC_CONTAINS: + case SC_DOES_NOT_CONTAIN: + { + sText.InsertAscii( "*" , 0 ); + sText.AppendAscii( "*" ); + } + break; + case SC_BEGINS_WITH: + case SC_DOES_NOT_BEGIN_WITH: + sText.AppendAscii( "*" ); + break; + case SC_ENDS_WITH: + case SC_DOES_NOT_END_WITH: + sText.InsertAscii( "*" , 0 ); + break; + default: + { + //nothing + } + } + } BOOL bLen = sText.Len() > 0; @@ -784,6 +808,14 @@ BOOL XclExpAutofilter::AddEntry( const ScQueryEntry& rEntry ) case SC_LESS_EQUAL: nOper = EXC_AFOPER_LESSEQUAL; break; case SC_GREATER_EQUAL: nOper = EXC_AFOPER_GREATEREQUAL; break; case SC_NOT_EQUAL: nOper = EXC_AFOPER_NOTEQUAL; break; + case SC_CONTAINS: + case SC_BEGINS_WITH: + case SC_ENDS_WITH: + nOper = EXC_AFOPER_EQUAL; break; + case SC_DOES_NOT_CONTAIN: + case SC_DOES_NOT_BEGIN_WITH: + case SC_DOES_NOT_END_WITH: + nOper = EXC_AFOPER_NOTEQUAL; break; default:; } bConflict = !AddCondition( rEntry.eConnect, nType, nOper, fVal, pText ); diff --git a/sc/source/filter/excel/namebuff.cxx b/sc/source/filter/excel/namebuff.cxx index df53c3edcd3c..b01f5a728263 100644 --- a/sc/source/filter/excel/namebuff.cxx +++ b/sc/source/filter/excel/namebuff.cxx @@ -127,6 +127,9 @@ void ShrfmlaBuffer::Store( const ScRange& rRange, const ScTokenArray& rToken ) DBG_ASSERT( mnCurrIdx <= 0xFFFF, "*ShrfmlaBuffer::Store(): Gleich wird mir schlecht...!" ); ScRangeData* pData = new ScRangeData( pExcRoot->pIR->GetDocPtr(), aName, rToken, rRange.aStart, RT_SHARED ); + const ScAddress& rMaxPos = pExcRoot->pIR->GetMaxPos(); + pData->SetMaxCol(rMaxPos.Col()); + pData->SetMaxRow(rMaxPos.Row()); pData->SetIndex( static_cast< USHORT >( mnCurrIdx ) ); pExcRoot->pIR->GetNamedRanges().Insert( pData ); index_hash[rRange.aStart] = static_cast< USHORT >( mnCurrIdx ); diff --git a/sc/source/filter/excel/xeformula.cxx b/sc/source/filter/excel/xeformula.cxx index e065099b2824..457c31d4ab04 100644 --- a/sc/source/filter/excel/xeformula.cxx +++ b/sc/source/filter/excel/xeformula.cxx @@ -619,7 +619,7 @@ void XclExpFmlaCompImpl::Init( XclFormulaType eType, const ScTokenArray& rScTokA DBG_ASSERT( mbOk, "XclExpFmlaCompImpl::Init - missing cell address" ); // clone the passed token array, convert references relative to current cell position mxOwnScTokArr.reset( rScTokArr.Clone() ); - ScCompiler::MoveRelWrap( *mxOwnScTokArr, GetDocPtr(), *pScBasePos ); + ScCompiler::MoveRelWrap( *mxOwnScTokArr, GetDocPtr(), *pScBasePos, MAXCOL, MAXROW ); // don't remember pScBasePos in mpScBasePos, shared formulas use real relative refs break; default:; 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/XMLExportDatabaseRanges.cxx b/sc/source/filter/xml/XMLExportDatabaseRanges.cxx index 4ca83809843d..b9d9b4936961 100644 --- a/sc/source/filter/xml/XMLExportDatabaseRanges.cxx +++ b/sc/source/filter/xml/XMLExportDatabaseRanges.cxx @@ -203,44 +203,56 @@ void ScXMLExportDatabaseRanges::WriteImportDescriptor(const uno::Sequence <beans } } -rtl::OUString ScXMLExportDatabaseRanges::getOperatorXML(const sheet::FilterOperator aFilterOperator, const sal_Bool bUseRegularExpressions) const +rtl::OUString ScXMLExportDatabaseRanges::getOperatorXML(const long aFilterOperator, const sal_Bool bUseRegularExpressions) const { switch (aFilterOperator) { - case sheet::FilterOperator_EQUAL : + case sheet::FilterOperator2::EQUAL : { if (bUseRegularExpressions) return GetXMLToken(XML_MATCH); else return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("=")); } - case sheet::FilterOperator_NOT_EQUAL : + case sheet::FilterOperator2::NOT_EQUAL : { if (bUseRegularExpressions) return GetXMLToken(XML_NOMATCH); else return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("!=")); } - case sheet::FilterOperator_BOTTOM_PERCENT : + case sheet::FilterOperator2::BOTTOM_PERCENT : return GetXMLToken(XML_BOTTOM_PERCENT); - case sheet::FilterOperator_BOTTOM_VALUES : + case sheet::FilterOperator2::BOTTOM_VALUES : return GetXMLToken(XML_BOTTOM_VALUES); - case sheet::FilterOperator_EMPTY : + case sheet::FilterOperator2::EMPTY : return GetXMLToken(XML_EMPTY); - case sheet::FilterOperator_GREATER : + case sheet::FilterOperator2::GREATER : return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(">")); - case sheet::FilterOperator_GREATER_EQUAL : + case sheet::FilterOperator2::GREATER_EQUAL : return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(">=")); - case sheet::FilterOperator_LESS : + case sheet::FilterOperator2::LESS : return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("<")); - case sheet::FilterOperator_LESS_EQUAL : + case sheet::FilterOperator2::LESS_EQUAL : return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("<=")); - case sheet::FilterOperator_NOT_EMPTY : + case sheet::FilterOperator2::NOT_EMPTY : return GetXMLToken(XML_NOEMPTY); - case sheet::FilterOperator_TOP_PERCENT : + case sheet::FilterOperator2::TOP_PERCENT : return GetXMLToken(XML_TOP_PERCENT); - case sheet::FilterOperator_TOP_VALUES : + case sheet::FilterOperator2::TOP_VALUES : return GetXMLToken(XML_TOP_VALUES); + case sheet::FilterOperator2::CONTAINS : + return GetXMLToken(XML_CONTAINS); + case sheet::FilterOperator2::DOES_NOT_CONTAIN : + return GetXMLToken(XML_DOES_NOT_CONTAIN); + case sheet::FilterOperator2::BEGINS_WITH : + return GetXMLToken(XML_BEGINS_WITH); + case sheet::FilterOperator2::DOES_NOT_BEGIN_WITH : + return GetXMLToken(XML_DOES_NOT_BEGIN_WITH); + case sheet::FilterOperator2::ENDS_WITH : + return GetXMLToken(XML_ENDS_WITH); + case sheet::FilterOperator2::DOES_NOT_END_WITH : + return GetXMLToken(XML_DOES_NOT_END_WITH); default: { // added to avoid warnings @@ -249,7 +261,7 @@ rtl::OUString ScXMLExportDatabaseRanges::getOperatorXML(const sheet::FilterOpera return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("=")); } -void ScXMLExportDatabaseRanges::WriteCondition(const sheet::TableFilterField& aFilterField, sal_Bool bIsCaseSensitive, sal_Bool bUseRegularExpressions) +void ScXMLExportDatabaseRanges::WriteCondition(const sheet::TableFilterField2& aFilterField, sal_Bool bIsCaseSensitive, sal_Bool bUseRegularExpressions) { rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_FIELD_NUMBER, rtl::OUString::valueOf(aFilterField.Field)); if (bIsCaseSensitive) @@ -267,9 +279,9 @@ void ScXMLExportDatabaseRanges::WriteCondition(const sheet::TableFilterField& aF SvXMLElementExport aElemC(rExport, XML_NAMESPACE_TABLE, XML_FILTER_CONDITION, sal_True, sal_True); } -void ScXMLExportDatabaseRanges::WriteFilterDescriptor(const uno::Reference <sheet::XSheetFilterDescriptor>& xSheetFilterDescriptor, const rtl::OUString sDatabaseRangeName) +void ScXMLExportDatabaseRanges::WriteFilterDescriptor(const uno::Reference <sheet::XSheetFilterDescriptor2>& xSheetFilterDescriptor, const rtl::OUString sDatabaseRangeName) { - uno::Sequence <sheet::TableFilterField> aTableFilterFields(xSheetFilterDescriptor->getFilterFields()); + uno::Sequence< sheet::TableFilterField2 > aTableFilterFields( xSheetFilterDescriptor->getFilterFields2() ); sal_Int32 nTableFilterFields = aTableFilterFields.getLength(); if (nTableFilterFields > 0) { @@ -336,7 +348,7 @@ void ScXMLExportDatabaseRanges::WriteFilterDescriptor(const uno::Reference <shee else { SvXMLElementExport aElemC(rExport, XML_NAMESPACE_TABLE, XML_FILTER_OR, sal_True, sal_True); - sheet::TableFilterField aPrevFilterField = aTableFilterFields[0]; + sheet::TableFilterField2 aPrevFilterField = aTableFilterFields[0]; sheet::FilterConnection aConnection = aTableFilterFields[1].Connection; sal_Bool bOpenAndElement; rtl::OUString aName = rExport.GetNamespaceMap().GetQNameByKey(XML_NAMESPACE_TABLE, GetXMLToken(XML_FILTER_AND)); @@ -632,7 +644,9 @@ void ScXMLExportDatabaseRanges::WriteDatabaseRanges(const com::sun::star::uno::R if (::cppu::any2bool(xPropertySetDatabaseRange->getPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_STRIPDAT))))) rExport.AddAttribute(XML_NAMESPACE_TABLE, XML_HAS_PERSISTENT_DATA, XML_FALSE); } - uno::Reference <sheet::XSheetFilterDescriptor> xSheetFilterDescriptor(xDatabaseRange->getFilterDescriptor()); + + uno::Reference< sheet::XSheetFilterDescriptor2 > xSheetFilterDescriptor( + xDatabaseRange->getFilterDescriptor(), uno::UNO_QUERY ); uno::Sequence <beans::PropertyValue> aSortProperties(xDatabaseRange->getSortDescriptor()); if (xSheetFilterDescriptor.is()) { diff --git a/sc/source/filter/xml/XMLExportDatabaseRanges.hxx b/sc/source/filter/xml/XMLExportDatabaseRanges.hxx index c4829ffd3fdd..81d1399e16b3 100644 --- a/sc/source/filter/xml/XMLExportDatabaseRanges.hxx +++ b/sc/source/filter/xml/XMLExportDatabaseRanges.hxx @@ -33,9 +33,9 @@ #include <com/sun/star/uno/Sequence.h> #include <com/sun/star/beans/PropertyValue.hpp> -#include <com/sun/star/sheet/FilterOperator.hpp> -#include <com/sun/star/sheet/TableFilterField.hpp> -#include <com/sun/star/sheet/XSheetFilterDescriptor.hpp> +#include <com/sun/star/sheet/FilterOperator2.hpp> +#include <com/sun/star/sheet/TableFilterField2.hpp> +#include <com/sun/star/sheet/XSheetFilterDescriptor2.hpp> #include <com/sun/star/sheet/XSubTotalDescriptor.hpp> #include <com/sun/star/sheet/XSpreadsheetDocument.hpp> @@ -49,9 +49,9 @@ class ScXMLExportDatabaseRanges ScDocument* pDoc; void WriteImportDescriptor(const com::sun::star::uno::Sequence <com::sun::star::beans::PropertyValue> aImportDescriptor); - rtl::OUString getOperatorXML(const com::sun::star::sheet::FilterOperator aFilterOperator, const sal_Bool bUseRegularExpressions) const; - void WriteCondition(const com::sun::star::sheet::TableFilterField& aFilterField, sal_Bool bIsCaseSensitive, sal_Bool bUseRegularExpressions); - void WriteFilterDescriptor(const com::sun::star::uno::Reference <com::sun::star::sheet::XSheetFilterDescriptor>& xSheetFilterDescriptor, const rtl::OUString sDatabaseRangeName); + rtl::OUString getOperatorXML(const long aFilterOperator, const sal_Bool bUseRegularExpressions) const; + void WriteCondition(const com::sun::star::sheet::TableFilterField2& aFilterField, sal_Bool bIsCaseSensitive, sal_Bool bUseRegularExpressions); + void WriteFilterDescriptor(const com::sun::star::uno::Reference <com::sun::star::sheet::XSheetFilterDescriptor2>& xSheetFilterDescriptor, const rtl::OUString sDatabaseRangeName); void WriteSortDescriptor(const com::sun::star::uno::Sequence <com::sun::star::beans::PropertyValue> aSortProperties); void WriteSubTotalDescriptor(const com::sun::star::uno::Reference <com::sun::star::sheet::XSubTotalDescriptor> xSubTotalDescriptor, const rtl::OUString sDatabaseRangeName); public: 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/xmldrani.cxx b/sc/source/filter/xml/xmldrani.cxx index e2aa6fcd7504..55a1859211d0 100644 --- a/sc/source/filter/xml/xmldrani.cxx +++ b/sc/source/filter/xml/xmldrani.cxx @@ -381,7 +381,8 @@ void ScXMLDatabaseRangeContext::EndElement() pDBData->SetSortParam(aSortParam); } - uno::Reference <sheet::XSheetFilterDescriptor> xSheetFilterDescriptor(xDatabaseRange->getFilterDescriptor()); + uno::Reference< sheet::XSheetFilterDescriptor2 > xSheetFilterDescriptor( + xDatabaseRange->getFilterDescriptor(), uno::UNO_QUERY ); if (xSheetFilterDescriptor.is()) { uno::Reference <beans::XPropertySet> xFilterPropertySet (xSheetFilterDescriptor, uno::UNO_QUERY); @@ -396,7 +397,7 @@ void ScXMLDatabaseRangeContext::EndElement() xFilterPropertySet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_USEREGEX)), uno::makeAny(bFilterUseRegularExpressions)); xFilterPropertySet->setPropertyValue(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_OUTPOS)), uno::makeAny(aFilterOutputPosition)); } - xSheetFilterDescriptor->setFilterFields(aFilterFields); + xSheetFilterDescriptor->setFilterFields2(aFilterFields); if (bFilterConditionSourceRange) { ScRange aAdvSource; diff --git a/sc/source/filter/xml/xmldrani.hxx b/sc/source/filter/xml/xmldrani.hxx index 36c668b0f77f..be55e5b143cc 100644 --- a/sc/source/filter/xml/xmldrani.hxx +++ b/sc/source/filter/xml/xmldrani.hxx @@ -36,7 +36,7 @@ #include <com/sun/star/sheet/SubTotalColumn.hpp> #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/beans/PropertyValue.hpp> -#include <com/sun/star/sheet/TableFilterField.hpp> +#include <com/sun/star/sheet/TableFilterField2.hpp> #include <com/sun/star/table/CellAddress.hpp> #include <com/sun/star/table/CellRangeAddress.hpp> #include <com/sun/star/table/TableOrientation.hpp> @@ -79,7 +79,7 @@ class ScXMLDatabaseRangeContext : public SvXMLImportContext rtl::OUString sDatabaseName; rtl::OUString sSourceObject; com::sun::star::uno::Sequence <com::sun::star::beans::PropertyValue> aSortSequence; - com::sun::star::uno::Sequence <com::sun::star::sheet::TableFilterField> aFilterFields; + com::sun::star::uno::Sequence <com::sun::star::sheet::TableFilterField2> aFilterFields; std::vector < ScSubTotalRule > aSubTotalRules; com::sun::star::table::CellAddress aFilterOutputPosition; com::sun::star::table::CellRangeAddress aFilterConditionSourceRangeAddress; @@ -146,7 +146,7 @@ public: void SetFilterIsCaseSensitive(const sal_Bool bTemp) { bFilterIsCaseSensitive = bTemp; } void SetFilterSkipDuplicates(const sal_Bool bTemp) { bFilterSkipDuplicates = bTemp; } void SetFilterUseRegularExpressions(const sal_Bool bTemp) { bFilterUseRegularExpressions = bTemp; } - void SetFilterFields(const com::sun::star::uno::Sequence <com::sun::star::sheet::TableFilterField>& aTemp) { aFilterFields = aTemp; } + void SetFilterFields(const com::sun::star::uno::Sequence <com::sun::star::sheet::TableFilterField2>& aTemp) { aFilterFields = aTemp; } void SetFilterOutputPosition(const com::sun::star::table::CellAddress& aTemp) { aFilterOutputPosition = aTemp; } void SetFilterConditionSourceRangeAddress(const com::sun::star::table::CellRangeAddress& aTemp) { aFilterConditionSourceRangeAddress = aTemp; bFilterConditionSourceRange = sal_True; } diff --git a/sc/source/filter/xml/xmlfilti.cxx b/sc/source/filter/xml/xmlfilti.cxx index 59d53542535a..87bdc748906c 100644 --- a/sc/source/filter/xml/xmlfilti.cxx +++ b/sc/source/filter/xml/xmlfilti.cxx @@ -335,48 +335,60 @@ SvXMLImportContext *ScXMLConditionContext::CreateChildContext( USHORT nPrefix, return new SvXMLImportContext( GetImport(), nPrefix, rLName ); } -void ScXMLConditionContext::getOperatorXML(const rtl::OUString sTempOperator, sheet::FilterOperator& aFilterOperator, sal_Bool& bUseRegularExpressions) const +void ScXMLConditionContext::getOperatorXML(const rtl::OUString sTempOperator, sal_Int32& aFilterOperator, sal_Bool& bUseRegularExpressions) const { bUseRegularExpressions = sal_False; if (IsXMLToken(sTempOperator, XML_MATCH)) { bUseRegularExpressions = sal_True; - aFilterOperator = sheet::FilterOperator_EQUAL; + aFilterOperator = sheet::FilterOperator2::EQUAL; } else if (IsXMLToken(sTempOperator, XML_NOMATCH)) { bUseRegularExpressions = sal_True; - aFilterOperator = sheet::FilterOperator_NOT_EQUAL; + aFilterOperator = sheet::FilterOperator2::NOT_EQUAL; } else if (sTempOperator.compareToAscii("=") == 0) - aFilterOperator = sheet::FilterOperator_EQUAL; + aFilterOperator = sheet::FilterOperator2::EQUAL; else if (sTempOperator.compareToAscii("!=") == 0) - aFilterOperator = sheet::FilterOperator_NOT_EQUAL; + aFilterOperator = sheet::FilterOperator2::NOT_EQUAL; else if (IsXMLToken(sTempOperator, XML_BOTTOM_PERCENT)) - aFilterOperator = sheet::FilterOperator_BOTTOM_PERCENT; + aFilterOperator = sheet::FilterOperator2::BOTTOM_PERCENT; else if (IsXMLToken(sTempOperator, XML_BOTTOM_VALUES)) - aFilterOperator = sheet::FilterOperator_BOTTOM_VALUES; + aFilterOperator = sheet::FilterOperator2::BOTTOM_VALUES; else if (IsXMLToken(sTempOperator, XML_EMPTY)) - aFilterOperator = sheet::FilterOperator_EMPTY; + aFilterOperator = sheet::FilterOperator2::EMPTY; else if (sTempOperator.compareToAscii(">") == 0) - aFilterOperator = sheet::FilterOperator_GREATER; + aFilterOperator = sheet::FilterOperator2::GREATER; else if (sTempOperator.compareToAscii(">=") == 0) - aFilterOperator = sheet::FilterOperator_GREATER_EQUAL; + aFilterOperator = sheet::FilterOperator2::GREATER_EQUAL; else if (sTempOperator.compareToAscii("<") == 0) - aFilterOperator = sheet::FilterOperator_LESS; + aFilterOperator = sheet::FilterOperator2::LESS; else if (sTempOperator.compareToAscii("<=") == 0) - aFilterOperator = sheet::FilterOperator_LESS_EQUAL; + aFilterOperator = sheet::FilterOperator2::LESS_EQUAL; else if (IsXMLToken(sTempOperator, XML_NOEMPTY)) - aFilterOperator = sheet::FilterOperator_NOT_EMPTY; + aFilterOperator = sheet::FilterOperator2::NOT_EMPTY; else if (IsXMLToken(sTempOperator, XML_TOP_PERCENT)) - aFilterOperator = sheet::FilterOperator_TOP_PERCENT; + aFilterOperator = sheet::FilterOperator2::TOP_PERCENT; else if (IsXMLToken(sTempOperator, XML_TOP_VALUES)) - aFilterOperator = sheet::FilterOperator_TOP_VALUES; + aFilterOperator = sheet::FilterOperator2::TOP_VALUES; + else if (IsXMLToken(sTempOperator, XML_CONTAINS)) + aFilterOperator = sheet::FilterOperator2::CONTAINS; + else if (IsXMLToken(sTempOperator, XML_DOES_NOT_CONTAIN)) + aFilterOperator = sheet::FilterOperator2::DOES_NOT_CONTAIN; + else if (IsXMLToken(sTempOperator, XML_BEGINS_WITH)) + aFilterOperator = sheet::FilterOperator2::BEGINS_WITH; + else if (IsXMLToken(sTempOperator, XML_DOES_NOT_BEGIN_WITH)) + aFilterOperator = sheet::FilterOperator2::DOES_NOT_BEGIN_WITH; + else if (IsXMLToken(sTempOperator, XML_ENDS_WITH)) + aFilterOperator = sheet::FilterOperator2::ENDS_WITH; + else if (IsXMLToken(sTempOperator, XML_DOES_NOT_END_WITH)) + aFilterOperator = sheet::FilterOperator2::DOES_NOT_END_WITH; } void ScXMLConditionContext::EndElement() { - sheet::TableFilterField aFilterField; + sheet::TableFilterField2 aFilterField; if (pFilterContext->GetConnection()) aFilterField.Connection = sheet::FilterConnection_OR; else diff --git a/sc/source/filter/xml/xmlfilti.hxx b/sc/source/filter/xml/xmlfilti.hxx index f0021e9dda1b..b2b45175c138 100644 --- a/sc/source/filter/xml/xmlfilti.hxx +++ b/sc/source/filter/xml/xmlfilti.hxx @@ -36,7 +36,8 @@ #include <com/sun/star/table/CellAddress.hpp> #include <com/sun/star/table/CellRangeAddress.hpp> #include <com/sun/star/sheet/FilterOperator.hpp> -#include <com/sun/star/sheet/TableFilterField.hpp> +#include <com/sun/star/sheet/FilterOperator2.hpp> +#include <com/sun/star/sheet/TableFilterField2.hpp> #include <tools/stack.hxx> #include "xmldrani.hxx" @@ -48,7 +49,7 @@ class ScXMLFilterContext : public SvXMLImportContext { ScXMLDatabaseRangeContext* pDatabaseRangeContext; - com::sun::star::uno::Sequence <com::sun::star::sheet::TableFilterField> aFilterFields; + com::sun::star::uno::Sequence <com::sun::star::sheet::TableFilterField2> aFilterFields; com::sun::star::table::CellAddress aOutputPosition; com::sun::star::table::CellRangeAddress aConditionSourceRangeAddress; sal_Int16 nUserListIndex; @@ -89,7 +90,7 @@ public: aConnectionOrStack.Push(pTemp);} void CloseConnection() { sal_Bool* pTemp = static_cast <sal_Bool*> (aConnectionOrStack.Pop()); bConnectionOr = *pTemp; bNextConnectionOr = *pTemp; delete pTemp;} sal_Bool GetConnection() { sal_Bool bTemp = bConnectionOr; bConnectionOr = bNextConnectionOr; return bTemp; } - void AddFilterField (const com::sun::star::sheet::TableFilterField aFilterField) { aFilterFields.realloc(aFilterFields.getLength() + 1); + void AddFilterField(const com::sun::star::sheet::TableFilterField2 aFilterField) { aFilterFields.realloc(aFilterFields.getLength() + 1); aFilterFields[aFilterFields.getLength() - 1] = aFilterField; } }; @@ -171,7 +172,7 @@ public: const ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XAttributeList>& xAttrList ); - void getOperatorXML(const rtl::OUString sTempOperator, com::sun::star::sheet::FilterOperator& aFilterOperator, sal_Bool& bUseRegularExpressions) const; + void getOperatorXML(const rtl::OUString sTempOperator, sal_Int32& aFilterOperator, sal_Bool& bUseRegularExpressions) const; virtual void EndElement(); }; 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/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx index 6914d5abfaf3..46987c88636f 100644 --- a/sc/source/ui/app/inputhdl.cxx +++ b/sc/source/ui/app/inputhdl.cxx @@ -741,7 +741,7 @@ void ScInputHandler::ShowTipCursor() nLeftParentPos = lcl_MatchParenthesis( aSelText, aSelText.Len()-1 ); if( nLeftParentPos != STRING_NOTFOUND ) { - sal_Unicode c = aSelText.GetChar( nLeftParentPos-1 ); + sal_Unicode c = ( nLeftParentPos > 0 ) ? aSelText.GetChar( nLeftParentPos-1 ) : 0; if( !((c >= 'A' && c<= 'Z') || (c>= 'a' && c<= 'z' )) ) continue; nNextFStart = aHelper.GetFunctionStart( aSelText, nLeftParentPos, TRUE); @@ -983,7 +983,8 @@ void ScInputHandler::UseFormulaData() if( nLeftParentPos == STRING_NOTFOUND ) break; - sal_Unicode c = aFormula.GetChar( nLeftParentPos-1 ); + // #160063# nLeftParentPos can be 0 if a parenthesis is inserted before the formula + sal_Unicode c = ( nLeftParentPos > 0 ) ? aFormula.GetChar( nLeftParentPos-1 ) : 0; if( !((c >= 'A' && c<= 'Z') || (c>= 'a' && c<= 'z') ) ) continue; nNextFStart = aHelper.GetFunctionStart( aFormula, nLeftParentPos, TRUE); diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx index 9820e4a5515e..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 ); @@ -1446,8 +1451,8 @@ BOOL ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark, pDoc->ExtendMerge( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, i ); pDoc->ExtendOverlapped( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, i ); - if(( eCmd == INS_CELLSDOWN && ( nMergeStartX != nMergeTestStartX || nMergeEndX != nMergeTestEndX ))|| - eCmd == INS_CELLSRIGHT && ( nMergeStartY != nMergeTestStartY || nMergeEndY != nMergeTestEndY ) ) + if(( eCmd == INS_CELLSDOWN && ( nMergeStartX != nMergeTestStartX || nMergeEndX != nMergeTestEndX )) || + (eCmd == INS_CELLSRIGHT && ( nMergeStartY != nMergeTestStartY || nMergeEndY != nMergeTestEndY )) ) { if (!bApi) rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); @@ -2073,6 +2078,12 @@ BOOL ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, nUndoPos ++; } } + + if( !bDeletingMerge ) + { + rDocShell.GetUndoManager()->LeaveListAction(); + } + rDocShell.GetUndoManager()->AddUndoAction( new ScUndoDeleteCells( &rDocShell, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ),nUndoPos, pTabs, pScenarios, eCmd, pUndoDoc, pUndoData ) ); @@ -3510,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 ); @@ -3559,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; @@ -4489,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/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx index ea9f02dcaa4b..9cc0b274028e 100644 --- a/sc/source/ui/docshell/externalrefmgr.cxx +++ b/sc/source/ui/docshell/externalrefmgr.cxx @@ -143,7 +143,8 @@ private: // ============================================================================ ScExternalRefCache::Table::Table() - : mbReferenced( true) // Prevent accidental data loss due to lack of knowledge. + : meReferenced( REFERENCED_MARKED ) + // Prevent accidental data loss due to lack of knowledge. { } @@ -151,14 +152,25 @@ ScExternalRefCache::Table::~Table() { } +void ScExternalRefCache::Table::setReferencedFlag( ScExternalRefCache::Table::ReferencedFlag eFlag ) +{ + meReferenced = eFlag; +} + void ScExternalRefCache::Table::setReferenced( bool bReferenced ) { - mbReferenced = bReferenced; + if (meReferenced != REFERENCED_PERMANENT) + meReferenced = (bReferenced ? REFERENCED_MARKED : UNREFERENCED); +} + +ScExternalRefCache::Table::ReferencedFlag ScExternalRefCache::Table::getReferencedFlag() const +{ + return meReferenced; } bool ScExternalRefCache::Table::isReferenced() const { - return mbReferenced; + return meReferenced != UNREFERENCED; } void ScExternalRefCache::Table::setCell(SCCOL nCol, SCROW nRow, TokenRef pToken, sal_uInt32 nFmtIndex) @@ -737,21 +749,57 @@ bool ScExternalRefCache::setCacheDocReferenced( sal_uInt16 nFileId ) return areAllCacheTablesReferenced(); } -bool ScExternalRefCache::setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName ) +bool ScExternalRefCache::setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName, size_t nSheets, bool bPermanent ) { - size_t nIndex = 0; - TableTypeRef pTab = getCacheTable( nFileId, rTabName, false, &nIndex); - if (pTab.get()) + DocItem* pDoc = getDocItem(nFileId); + if (pDoc) { - if (!pTab->isReferenced()) + size_t nIndex = 0; + String aTabNameUpper = ScGlobal::pCharClass->upper( rTabName); + if (lcl_getTableDataIndex( pDoc->maTableNameIndex, aTabNameUpper, nIndex)) { - pTab->setReferenced( true); - addCacheTableToReferenced( nFileId, nIndex); + size_t nStop = ::std::min( nIndex + nSheets, pDoc->maTables.size()); + for (size_t i = nIndex; i < nStop; ++i) + { + TableTypeRef pTab = pDoc->maTables[i]; + if (pTab.get()) + { + Table::ReferencedFlag eNewFlag = (bPermanent ? + Table::REFERENCED_PERMANENT : + Table::REFERENCED_MARKED); + Table::ReferencedFlag eOldFlag = pTab->getReferencedFlag(); + if (eOldFlag != Table::REFERENCED_PERMANENT && eNewFlag != eOldFlag) + { + pTab->setReferencedFlag( eNewFlag); + addCacheTableToReferenced( nFileId, i); + } + } + } } } return areAllCacheTablesReferenced(); } +void ScExternalRefCache::setCacheTableReferencedPermanently( sal_uInt16 nFileId, const String& rTabName, size_t nSheets ) +{ + DocItem* pDoc = getDocItem(nFileId); + if (pDoc) + { + size_t nIndex = 0; + String aTabNameUpper = ScGlobal::pCharClass->upper( rTabName); + if (lcl_getTableDataIndex( pDoc->maTableNameIndex, aTabNameUpper, nIndex)) + { + size_t nStop = ::std::min( nIndex + nSheets, pDoc->maTables.size()); + for (size_t i = nIndex; i < nStop; ++i) + { + TableTypeRef pTab = pDoc->maTables[i]; + if (pTab.get()) + pTab->setReferencedFlag( Table::REFERENCED_PERMANENT); + } + } + } +} + void ScExternalRefCache::setAllCacheTableReferencedStati( bool bReferenced ) { if (bReferenced) @@ -791,9 +839,17 @@ void ScExternalRefCache::setAllCacheTableReferencedStati( bool bReferenced ) TableTypeRef & xTab = rDocItem.maTables[i]; if (xTab.get()) { - xTab->setReferenced( false); - rDocReferenced.maTables[i] = false; - rDocReferenced.mbAllTablesReferenced = false; + if (xTab->getReferencedFlag() == Table::REFERENCED_PERMANENT) + addCacheTableToReferenced( nFileId, i); + else + { + xTab->setReferencedFlag( Table::UNREFERENCED); + rDocReferenced.maTables[i] = false; + rDocReferenced.mbAllTablesReferenced = false; + // An addCacheTableToReferenced() actually may have + // resulted in mbAllReferenced been set. Clear it. + maReferenced.mbAllReferenced = false; + } } } } @@ -1481,9 +1537,19 @@ bool ScExternalRefManager::setCacheDocReferenced( sal_uInt16 nFileId ) return maRefCache.setCacheDocReferenced( nFileId); } -bool ScExternalRefManager::setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName ) +bool ScExternalRefManager::setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName, size_t nSheets ) { - return maRefCache.setCacheTableReferenced( nFileId, rTabName); + return maRefCache.setCacheTableReferenced( nFileId, rTabName, nSheets, false); +} + +void ScExternalRefManager::setCacheTableReferencedPermanently( sal_uInt16 nFileId, const String& rTabName, size_t nSheets ) +{ + if (isInReferenceMarking()) + // Do all maintenance work. + maRefCache.setCacheTableReferenced( nFileId, rTabName, nSheets, true); + else + // Set only the permanent flag. + maRefCache.setCacheTableReferencedPermanently( nFileId, rTabName, nSheets); } void ScExternalRefManager::setAllCacheTableReferencedStati( bool bReferenced ) 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/inc/undoblk.hxx b/sc/source/ui/inc/undoblk.hxx index d357461d0f5e..281f44f4fe82 100644 --- a/sc/source/ui/inc/undoblk.hxx +++ b/sc/source/ui/inc/undoblk.hxx @@ -36,6 +36,7 @@ #include "spellparam.hxx" class ScDocShell; +class ScBaseCell; class ScDocument; class ScOutlineTable; class ScRangeName; @@ -592,6 +593,35 @@ private: void SetChangeTrack(); }; +class ScUndoRefConversion: public ScSimpleUndo +{ +public: + TYPEINFO(); + ScUndoRefConversion( ScDocShell* pNewDocShell, + const ScRange& aMarkRange, const ScMarkData& rMark, + ScDocument* pNewUndoDoc, ScDocument* pNewRedoDoc, BOOL bNewMulti, USHORT nNewFlag); + virtual ~ScUndoRefConversion(); + + virtual void Undo(); + virtual void Redo(); + virtual void Repeat(SfxRepeatTarget& rTarget); + virtual BOOL CanRepeat(SfxRepeatTarget& rTarget) const; + + virtual String GetComment() const; + +private: + ScMarkData aMarkData; + ScDocument* pUndoDoc; + ScDocument* pRedoDoc; + ScRange aRange; + BOOL bMulti; + USHORT nFlags; + ULONG nStartChangeAction; + ULONG nEndChangeAction; + + void DoChange( ScDocument* pRefDoc); + void SetChangeTrack(); +}; class ScUndoListNames: public ScBlockUndo { diff --git a/sc/source/ui/inc/viewfunc.hxx b/sc/source/ui/inc/viewfunc.hxx index a5b044ce4f32..228c4b4c1489 100644 --- a/sc/source/ui/inc/viewfunc.hxx +++ b/sc/source/ui/inc/viewfunc.hxx @@ -303,6 +303,7 @@ public: void SetNoteText( const ScAddress& rPos, const String& rNoteText ); void ReplaceNote( const ScAddress& rPos, const String& rNoteText, const String* pAuthor, const String* pDate ); + void DoRefConversion( BOOL bRecord = TRUE ); //UNUSED2008-05 void DoSpellingChecker( BOOL bRecord = TRUE ); void DoHangulHanjaConversion( BOOL bRecord = TRUE ); diff --git a/sc/source/ui/src/filter.src b/sc/source/ui/src/filter.src index 73108b984ebe..2e6a1c330671 100644 --- a/sc/source/ui/src/filter.src +++ b/sc/source/ui/src/filter.src @@ -34,7 +34,7 @@ ModelessDialog RID_SCDLG_FILTER HelpId = SID_FILTER ; Hide = TRUE ; SVLook = TRUE ; - Size = MAP_APPFONT ( 251 , 121 ) ; + Size = MAP_APPFONT ( 279 , 121 ) ; Text [ en-US ] = "Standard Filter" ; Moveable = TRUE ; Closeable = FALSE ; @@ -58,7 +58,7 @@ ModelessDialog RID_SCDLG_FILTER }; FixedText FT_VAL { - Pos = MAP_APPFONT ( 173 , 14 ) ; + Pos = MAP_APPFONT ( 201 , 14 ) ; Size = MAP_APPFONT ( 60 , 8 ) ; Text [ en-US ] = "Value" ; }; @@ -150,7 +150,7 @@ ModelessDialog RID_SCDLG_FILTER { Border = TRUE ; Pos = MAP_APPFONT ( 122 , 25 ) ; - Size = MAP_APPFONT ( 47 , 145 ) ; + Size = MAP_APPFONT ( 75 , 145 ) ; TabStop = TRUE ; DropDown = TRUE ; stringlist [ en-US ] = @@ -165,13 +165,19 @@ ModelessDialog RID_SCDLG_FILTER < "Smallest" ; Default ; > ; < "Largest %" ; Default ; > ; < "Smallest %" ; Default ; > ; + < "Contains" ; Default ; > ; + < "Does not contain" ; Default ; > ; + < "Begins with" ; Default ; > ; + < "Does not begin with" ; Default ; > ; + < "Ends with" ; Default ; > ; + < "Does not end with" ; Default ; > ; }; }; ListBox LB_COND2 { Border = TRUE ; Pos = MAP_APPFONT ( 122 , 41 ) ; - Size = MAP_APPFONT ( 47 , 145 ) ; + Size = MAP_APPFONT ( 75 , 145 ) ; TabStop = TRUE ; DropDown = TRUE ; stringlist [ en-US ] = @@ -186,13 +192,19 @@ ModelessDialog RID_SCDLG_FILTER < "Smallest" ; Default ; > ; < "Largest %" ; Default ; > ; < "Smallest %" ; Default ; > ; + < "Contains" ; Default ; > ; + < "Does not contain" ; Default ; > ; + < "Begins with" ; Default ; > ; + < "Does not begin with" ; Default ; > ; + < "Ends with" ; Default ; > ; + < "Does not end with" ; Default ; > ; }; }; ListBox LB_COND3 { Border = TRUE ; Pos = MAP_APPFONT ( 122 , 57 ) ; - Size = MAP_APPFONT ( 47 , 145 ) ; + Size = MAP_APPFONT ( 75 , 145 ) ; TabStop = TRUE ; DropDown = TRUE ; stringlist [ en-US ] = @@ -207,13 +219,19 @@ ModelessDialog RID_SCDLG_FILTER < "Smallest" ; Default ; > ; < "Largest %" ; Default ; > ; < "Smallest %" ; Default ; > ; + < "Contains" ; Default ; > ; + < "Does not contain" ; Default ; > ; + < "Begins with" ; Default ; > ; + < "Does not begin with" ; Default ; > ; + < "Ends with" ; Default ; > ; + < "Does not end with" ; Default ; > ; }; }; ListBox LB_COND4 { Border = TRUE ; Pos = MAP_APPFONT ( 122 , 73 ) ; - Size = MAP_APPFONT ( 47 , 145 ) ; + Size = MAP_APPFONT ( 75 , 145 ) ; TabStop = TRUE ; DropDown = TRUE ; stringlist [ en-US ] = @@ -228,39 +246,45 @@ ModelessDialog RID_SCDLG_FILTER < "Smallest" ; Default ; > ; < "Largest %" ; Default ; > ; < "Smallest %" ; Default ; > ; + < "Contains" ; Default ; > ; + < "Does not contain" ; Default ; > ; + < "Begins with" ; Default ; > ; + < "Does not begin with" ; Default ; > ; + < "Ends with" ; Default ; > ; + < "Does not end with" ; Default ; > ; }; }; ComboBox ED_VAL1 { - Pos = MAP_APPFONT ( 173 , 25 ) ; + Pos = MAP_APPFONT ( 201 , 25 ) ; Size = MAP_APPFONT ( 60 , 90 ) ; TabStop = TRUE ; DropDown = TRUE ; }; ComboBox ED_VAL2 { - Pos = MAP_APPFONT ( 173 , 41 ) ; + Pos = MAP_APPFONT ( 201 , 41 ) ; Size = MAP_APPFONT ( 60 , 90 ) ; TabStop = TRUE ; DropDown = TRUE ; }; ComboBox ED_VAL3 { - Pos = MAP_APPFONT ( 173 , 57 ) ; + Pos = MAP_APPFONT ( 201 , 57 ) ; Size = MAP_APPFONT ( 60 , 90 ) ; TabStop = TRUE ; DropDown = TRUE ; }; ComboBox ED_VAL4 { - Pos = MAP_APPFONT ( 173 , 73 ) ; + Pos = MAP_APPFONT ( 201 , 73 ) ; Size = MAP_APPFONT ( 60 , 90 ) ; TabStop = TRUE ; DropDown = TRUE ; }; ScrollBar LB_SCROLL { - Pos = MAP_APPFONT ( 237, 25 ) ; + Pos = MAP_APPFONT ( 265, 25 ) ; Size = MAP_APPFONT ( 8 , 60 ) ; TabStop = TRUE ; VScroll = TRUE ; @@ -269,7 +293,7 @@ ModelessDialog RID_SCDLG_FILTER FixedLine FL_CRITERIA { Pos = MAP_APPFONT ( 6 , 3 ) ; - Size = MAP_APPFONT ( 275 , 8 ) ; + Size = MAP_APPFONT ( 267 , 8 ) ; Text [ en-US ] = "Filter criteria"; }; CheckBox BTN_CASE @@ -325,7 +349,7 @@ ModelessDialog RID_SCDLG_FILTER Border = TRUE ; Hide = TRUE ; Pos = MAP_APPFONT ( 21 , 170 ) ; - Size = MAP_APPFONT ( 90 , 90 ) ; + Size = MAP_APPFONT ( 110 , 90 ) ; TabStop = TRUE ; DropDown = TRUE ; }; @@ -333,13 +357,13 @@ ModelessDialog RID_SCDLG_FILTER { Border = TRUE ; Hide = TRUE ; - Pos = MAP_APPFONT ( 115 , 170 ) ; - Size = MAP_APPFONT ( 104 , 12 ) ; + Pos = MAP_APPFONT ( 136 , 170 ) ; + Size = MAP_APPFONT ( 110 , 12 ) ; TabStop = TRUE ; }; ImageButton RB_COPY_AREA { - Pos = MAP_APPFONT ( 221 , 169 ) ; + Pos = MAP_APPFONT ( 248 , 169 ) ; Size = MAP_APPFONT ( 13 , 15 ) ; TabStop = FALSE ; QuickHelpText [ en-US ] = "Shrink" ; @@ -348,7 +372,7 @@ ModelessDialog RID_SCDLG_FILTER { Hide = TRUE ; Pos = MAP_APPFONT ( 6 , 118 ) ; - Size = MAP_APPFONT ( 239 , 8 ) ; + Size = MAP_APPFONT ( 267 , 8 ) ; }; FixedText FT_DBAREA { @@ -367,14 +391,14 @@ ModelessDialog RID_SCDLG_FILTER }; OKButton BTN_OK { - Pos = MAP_APPFONT ( 141 , 101 ) ; + Pos = MAP_APPFONT ( 169 , 101 ) ; Size = MAP_APPFONT ( 50 , 14 ) ; TabStop = TRUE ; DefButton = TRUE ; }; CancelButton BTN_CANCEL { - Pos = MAP_APPFONT ( 195 , 101 ) ; + Pos = MAP_APPFONT ( 223 , 101 ) ; Size = MAP_APPFONT ( 50 , 14 ) ; TabStop = TRUE ; }; @@ -395,7 +419,7 @@ ModelessDialog RID_SCDLG_FILTER FixedLine FL_SEPARATOR { Pos = MAP_APPFONT ( 0 , 91 ) ; - Size = MAP_APPFONT ( 251 , 6 ) ; + Size = MAP_APPFONT ( 279 , 6 ) ; }; }; //============================================================================ diff --git a/sc/source/ui/undo/undoblk3.cxx b/sc/source/ui/undo/undoblk3.cxx index 335bdf6720ee..ea1e303d6ae3 100644 --- a/sc/source/ui/undo/undoblk3.cxx +++ b/sc/source/ui/undo/undoblk3.cxx @@ -74,6 +74,7 @@ TYPEINIT1(ScUndoAutoFormat, SfxUndoAction); TYPEINIT1(ScUndoReplace, SfxUndoAction); TYPEINIT1(ScUndoTabOp, SfxUndoAction); TYPEINIT1(ScUndoConversion, SfxUndoAction); +TYPEINIT1(ScUndoRefConversion, SfxUndoAction); TYPEINIT1(ScUndoRefreshLink, SfxUndoAction); TYPEINIT1(ScUndoInsertAreaLink, SfxUndoAction); TYPEINIT1(ScUndoRemoveAreaLink, SfxUndoAction); @@ -1527,6 +1528,98 @@ BOOL ScUndoConversion::CanRepeat(SfxRepeatTarget& rTarget) const //============================================================================ +// class ScUndoRefConversion +// +// cell reference conversion + +//---------------------------------------------------------------------------- + +ScUndoRefConversion::ScUndoRefConversion( ScDocShell* pNewDocShell, + const ScRange& aMarkRange, const ScMarkData& rMark, + ScDocument* pNewUndoDoc, ScDocument* pNewRedoDoc, BOOL bNewMulti, USHORT nNewFlag) : +ScSimpleUndo( pNewDocShell ), +aMarkData ( rMark ), +pUndoDoc ( pNewUndoDoc ), +pRedoDoc ( pNewRedoDoc ), +aRange ( aMarkRange ), +bMulti ( bNewMulti ), +nFlags ( nNewFlag ) +{ + SetChangeTrack(); +} + +__EXPORT ScUndoRefConversion::~ScUndoRefConversion() +{ + delete pUndoDoc; + delete pRedoDoc; +} + +String __EXPORT ScUndoRefConversion::GetComment() const +{ + return ScGlobal::GetRscString( STR_UNDO_ENTERDATA ); // "Eingabe" +} + +void ScUndoRefConversion::SetChangeTrack() +{ + ScChangeTrack* pChangeTrack = pDocShell->GetDocument()->GetChangeTrack(); + if ( pChangeTrack && (nFlags & IDF_FORMULA) ) + pChangeTrack->AppendContentsIfInRefDoc( pUndoDoc, + nStartChangeAction, nEndChangeAction ); + else + nStartChangeAction = nEndChangeAction = 0; +} + +void ScUndoRefConversion::DoChange( ScDocument* pRefDoc) +{ + ScDocument* pDoc = pDocShell->GetDocument(); + + ShowTable(aRange); + + ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); + if (pViewShell) + pViewShell->SetMarkData( aMarkData ); + + ScRange aCopyRange = aRange; + SCTAB nTabCount = pDoc->GetTableCount(); + aCopyRange.aStart.SetTab(0); + aCopyRange.aEnd.SetTab(nTabCount-1); + pRefDoc->CopyToDocument( aCopyRange, nFlags, bMulti, pDoc, &aMarkData ); + pDocShell->PostPaint( aRange, PAINT_GRID); + pDocShell->PostDataChanged(); + if (pViewShell) + pViewShell->CellContentChanged(); +} +void __EXPORT ScUndoRefConversion::Undo() +{ + BeginUndo(); + if (pUndoDoc) + DoChange(pUndoDoc); + ScChangeTrack* pChangeTrack = pDocShell->GetDocument()->GetChangeTrack(); + if ( pChangeTrack ) + pChangeTrack->Undo( nStartChangeAction, nEndChangeAction ); + EndUndo(); +} + +void __EXPORT ScUndoRefConversion::Redo() +{ + BeginRedo(); + if (pRedoDoc) + DoChange(pRedoDoc); + SetChangeTrack(); + EndRedo(); +} + +void __EXPORT ScUndoRefConversion::Repeat(SfxRepeatTarget& rTarget) +{ + if (rTarget.ISA(ScTabViewTarget)) + ((ScTabViewTarget&)rTarget).GetViewShell()->DoRefConversion(); +} + +BOOL __EXPORT ScUndoRefConversion::CanRepeat(SfxRepeatTarget& rTarget) const +{ + return (rTarget.ISA(ScTabViewTarget)); +} +//============================================================================ // class ScUndoRefreshLink // // Link aktualisieren / aendern diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx index 7bdb9c7718d2..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) @@ -5633,7 +5632,15 @@ void SAL_CALL ScCellRangeObj::filter( const uno::Reference<sheet::XSheetFilterDe ScDocShell* pDocSh = GetDocShell(); ScFilterDescriptor aImpl(pDocSh); - aImpl.setFilterFields( xDescriptor->getFilterFields() ); + uno::Reference< sheet::XSheetFilterDescriptor2 > xDescriptor2( xDescriptor, uno::UNO_QUERY ); + if ( xDescriptor2.is() ) + { + aImpl.setFilterFields2( xDescriptor2->getFilterFields2() ); + } + else + { + aImpl.setFilterFields( xDescriptor->getFilterFields() ); + } // Rest sind jetzt Properties... uno::Reference<beans::XPropertySet> xPropSet( xDescriptor, uno::UNO_QUERY ); @@ -6198,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 ); } } @@ -6246,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/datauno.cxx b/sc/source/ui/unoobj/datauno.cxx index 98a8a8551d6c..13f2c26c6e47 100644 --- a/sc/source/ui/unoobj/datauno.cxx +++ b/sc/source/ui/unoobj/datauno.cxx @@ -45,6 +45,8 @@ #include <com/sun/star/table/TableOrientation.hpp> #include <com/sun/star/table/CellRangeAddress.hpp> #include <com/sun/star/sheet/DataImportMode.hpp> +#include <com/sun/star/sheet/FilterOperator2.hpp> +#include <com/sun/star/sheet/TableFilterField2.hpp> #include "datauno.hxx" #include "dapiuno.hxx" @@ -1106,7 +1108,7 @@ void ScFilterDescriptorBase::Notify( SfxBroadcaster&, const SfxHint& rHint ) } } -// XSheetFilterDescriptor +// XSheetFilterDescriptor and XSheetFilterDescriptor2 uno::Sequence<sheet::TableFilterField> SAL_CALL ScFilterDescriptorBase::getFilterFields() throw(uno::RuntimeException) @@ -1177,6 +1179,80 @@ uno::Sequence<sheet::TableFilterField> SAL_CALL ScFilterDescriptorBase::getFilte return aSeq; } +uno::Sequence<sheet::TableFilterField2> SAL_CALL ScFilterDescriptorBase::getFilterFields2() +throw(uno::RuntimeException) +{ + ScUnoGuard aGuard; + ScQueryParam aParam; + GetData(aParam); + + SCSIZE nEntries = aParam.GetEntryCount(); // allozierte Eintraege im Param + SCSIZE nCount = 0; // aktive + while ( nCount < nEntries && + aParam.GetEntry(nCount).bDoQuery ) + ++nCount; + + sheet::TableFilterField2 aField; + uno::Sequence<sheet::TableFilterField2> aSeq(static_cast<sal_Int32>(nCount)); + sheet::TableFilterField2* pAry = aSeq.getArray(); + for (SCSIZE i=0; i<nCount; i++) + { + const ScQueryEntry& rEntry = aParam.GetEntry(i); + + rtl::OUString aStringValue; + if (rEntry.pStr) + aStringValue = *rEntry.pStr; + + aField.Connection = (rEntry.eConnect == SC_AND) ? sheet::FilterConnection_AND : sheet::FilterConnection_OR; + aField.Field = rEntry.nField; + aField.IsNumeric = !rEntry.bQueryByString; + aField.StringValue = aStringValue; + aField.NumericValue = rEntry.nVal; + + switch (rEntry.eOp) // ScQueryOp + { + case SC_EQUAL: + { + aField.Operator = sheet::FilterOperator2::EQUAL; + if (!rEntry.bQueryByString && *rEntry.pStr == EMPTY_STRING) + { + if (rEntry.nVal == SC_EMPTYFIELDS) + { + aField.Operator = sheet::FilterOperator2::EMPTY; + aField.NumericValue = 0; + } + else if (rEntry.nVal == SC_NONEMPTYFIELDS) + { + aField.Operator = sheet::FilterOperator2::NOT_EMPTY; + aField.NumericValue = 0; + } + } + } + break; + case SC_LESS: aField.Operator = sheet::FilterOperator2::LESS; break; + case SC_GREATER: aField.Operator = sheet::FilterOperator2::GREATER; break; + case SC_LESS_EQUAL: aField.Operator = sheet::FilterOperator2::LESS_EQUAL; break; + case SC_GREATER_EQUAL: aField.Operator = sheet::FilterOperator2::GREATER_EQUAL; break; + case SC_NOT_EQUAL: aField.Operator = sheet::FilterOperator2::NOT_EQUAL; break; + case SC_TOPVAL: aField.Operator = sheet::FilterOperator2::TOP_VALUES; break; + case SC_BOTVAL: aField.Operator = sheet::FilterOperator2::BOTTOM_VALUES; break; + case SC_TOPPERC: aField.Operator = sheet::FilterOperator2::TOP_PERCENT; break; + case SC_BOTPERC: aField.Operator = sheet::FilterOperator2::BOTTOM_PERCENT; break; + case SC_CONTAINS: aField.Operator = sheet::FilterOperator2::CONTAINS; break; + case SC_DOES_NOT_CONTAIN: aField.Operator = sheet::FilterOperator2::DOES_NOT_CONTAIN; break; + case SC_BEGINS_WITH: aField.Operator = sheet::FilterOperator2::BEGINS_WITH; break; + case SC_DOES_NOT_BEGIN_WITH: aField.Operator = sheet::FilterOperator2::DOES_NOT_BEGIN_WITH; break; + case SC_ENDS_WITH: aField.Operator = sheet::FilterOperator2::ENDS_WITH; break; + case SC_DOES_NOT_END_WITH: aField.Operator = sheet::FilterOperator2::DOES_NOT_END_WITH; break; + default: + DBG_ERROR("Falscher Filter-enum"); + aField.Operator = sheet::FilterOperator2::EMPTY; + } + pAry[i] = aField; + } + return aSeq; +} + void SAL_CALL ScFilterDescriptorBase::setFilterFields( const uno::Sequence<sheet::TableFilterField>& aFilterFields ) throw(uno::RuntimeException) @@ -1251,6 +1327,86 @@ void SAL_CALL ScFilterDescriptorBase::setFilterFields( PutData(aParam); } +void SAL_CALL ScFilterDescriptorBase::setFilterFields2( + const uno::Sequence<sheet::TableFilterField2>& aFilterFields ) + throw(uno::RuntimeException) +{ + ScUnoGuard aGuard; + ScQueryParam aParam; + GetData(aParam); + + SCSIZE nCount = static_cast<SCSIZE>(aFilterFields.getLength()); + DBG_ASSERT( nCount <= MAXQUERY, "setFilterFields: zu viele" ); + + aParam.Resize( nCount ); + + const sheet::TableFilterField2* pAry = aFilterFields.getConstArray(); + SCSIZE i; + for (i=0; i<nCount; i++) + { + ScQueryEntry& rEntry = aParam.GetEntry(i); + if (!rEntry.pStr) + rEntry.pStr = new String; // sollte nicht sein (soll immer initialisiert sein) + + rEntry.bDoQuery = TRUE; + rEntry.eConnect = (pAry[i].Connection == sheet::FilterConnection_AND) ? SC_AND : SC_OR; + rEntry.nField = pAry[i].Field; + rEntry.bQueryByString = !pAry[i].IsNumeric; + *rEntry.pStr = String( pAry[i].StringValue ); + rEntry.nVal = pAry[i].NumericValue; + + if (!rEntry.bQueryByString && pDocSh) + { + pDocSh->GetDocument()->GetFormatTable()->GetInputLineString(rEntry.nVal, 0, *rEntry.pStr); + } + + switch (pAry[i].Operator) // FilterOperator + { + case sheet::FilterOperator2::EQUAL: rEntry.eOp = SC_EQUAL; break; + case sheet::FilterOperator2::LESS: rEntry.eOp = SC_LESS; break; + case sheet::FilterOperator2::GREATER: rEntry.eOp = SC_GREATER; break; + case sheet::FilterOperator2::LESS_EQUAL: rEntry.eOp = SC_LESS_EQUAL; break; + case sheet::FilterOperator2::GREATER_EQUAL: rEntry.eOp = SC_GREATER_EQUAL; break; + case sheet::FilterOperator2::NOT_EQUAL: rEntry.eOp = SC_NOT_EQUAL; break; + case sheet::FilterOperator2::TOP_VALUES: rEntry.eOp = SC_TOPVAL; break; + case sheet::FilterOperator2::BOTTOM_VALUES: rEntry.eOp = SC_BOTVAL; break; + case sheet::FilterOperator2::TOP_PERCENT: rEntry.eOp = SC_TOPPERC; break; + case sheet::FilterOperator2::BOTTOM_PERCENT: rEntry.eOp = SC_BOTPERC; break; + case sheet::FilterOperator2::CONTAINS: rEntry.eOp = SC_CONTAINS; break; + case sheet::FilterOperator2::DOES_NOT_CONTAIN: rEntry.eOp = SC_DOES_NOT_CONTAIN; break; + case sheet::FilterOperator2::BEGINS_WITH: rEntry.eOp = SC_BEGINS_WITH; break; + case sheet::FilterOperator2::DOES_NOT_BEGIN_WITH: rEntry.eOp = SC_DOES_NOT_BEGIN_WITH;break; + case sheet::FilterOperator2::ENDS_WITH: rEntry.eOp = SC_ENDS_WITH; break; + case sheet::FilterOperator2::DOES_NOT_END_WITH: rEntry.eOp = SC_DOES_NOT_END_WITH; break; + case sheet::FilterOperator2::EMPTY: + { + rEntry.eOp = SC_EQUAL; + rEntry.nVal = SC_EMPTYFIELDS; + rEntry.bQueryByString = FALSE; + *rEntry.pStr = EMPTY_STRING; + } + break; + case sheet::FilterOperator2::NOT_EMPTY: + { + rEntry.eOp = SC_EQUAL; + rEntry.nVal = SC_NONEMPTYFIELDS; + rEntry.bQueryByString = FALSE; + *rEntry.pStr = EMPTY_STRING; + } + break; + default: + DBG_ERROR("Falscher Query-enum"); + rEntry.eOp = SC_EQUAL; + } + } + + SCSIZE nParamCount = aParam.GetEntryCount(); // Param wird nicht unter 8 resized + for (i=nCount; i<nParamCount; i++) + aParam.GetEntry(i).bDoQuery = FALSE; // ueberzaehlige Felder zuruecksetzen + + PutData(aParam); +} + // Rest sind Properties // XPropertySet 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/vba/vbarange.cxx b/sc/source/ui/vba/vbarange.cxx index 5019167b4374..d1ac4504ce96 100644 --- a/sc/source/ui/vba/vbarange.cxx +++ b/sc/source/ui/vba/vbarange.cxx @@ -77,7 +77,10 @@ #include <com/sun/star/sheet/XCellRangeMovement.hpp> #include <com/sun/star/sheet/XCellRangeData.hpp> #include <com/sun/star/sheet/FormulaResult.hpp> +#include <com/sun/star/sheet/FilterOperator2.hpp> #include <com/sun/star/sheet/TableFilterField.hpp> +#include <com/sun/star/sheet/TableFilterField2.hpp> +#include <com/sun/star/sheet/XSheetFilterDescriptor2.hpp> #include <com/sun/star/sheet/XSheetFilterable.hpp> #include <com/sun/star/sheet/FilterConnection.hpp> #include <com/sun/star/util/CellProtection.hpp> @@ -4027,7 +4030,7 @@ void lcl_SetAllQueryForField( ScDocShell* pDocShell, SCCOLROW nField, sal_Int16 } // Modifies sCriteria, and nOp depending on the value of sCriteria -void lcl_setTableFieldsFromCriteria( rtl::OUString& sCriteria1, uno::Reference< beans::XPropertySet >& xDescProps, sheet::TableFilterField& rFilterField ) +void lcl_setTableFieldsFromCriteria( rtl::OUString& sCriteria1, uno::Reference< beans::XPropertySet >& xDescProps, sheet::TableFilterField2& rFilterField ) { // #TODO make this more efficient and cycle through // sCriteria1 character by character to pick up <,<>,=, * etc. @@ -4047,10 +4050,10 @@ void lcl_setTableFieldsFromCriteria( rtl::OUString& sCriteria1, uno::Reference< if ( ( nPos = sCriteria1.indexOf( EQUALS ) ) == 0 ) { if ( sCriteria1.getLength() == EQUALS.getLength() ) - rFilterField.Operator = sheet::FilterOperator_EMPTY; + rFilterField.Operator = sheet::FilterOperator2::EMPTY; else { - rFilterField.Operator = sheet::FilterOperator_EQUAL; + rFilterField.Operator = sheet::FilterOperator2::EQUAL; sCriteria1 = sCriteria1.copy( EQUALS.getLength() ); sCriteria1 = VBAToRegexp( sCriteria1 ); // UseRegularExpressions @@ -4062,10 +4065,10 @@ void lcl_setTableFieldsFromCriteria( rtl::OUString& sCriteria1, uno::Reference< else if ( ( nPos = sCriteria1.indexOf( NOTEQUALS ) ) == 0 ) { if ( sCriteria1.getLength() == NOTEQUALS.getLength() ) - rFilterField.Operator = sheet::FilterOperator_NOT_EMPTY; + rFilterField.Operator = sheet::FilterOperator2::NOT_EMPTY; else { - rFilterField.Operator = sheet::FilterOperator_NOT_EQUAL; + rFilterField.Operator = sheet::FilterOperator2::NOT_EQUAL; sCriteria1 = sCriteria1.copy( NOTEQUALS.getLength() ); sCriteria1 = VBAToRegexp( sCriteria1 ); // UseRegularExpressions @@ -4079,12 +4082,12 @@ void lcl_setTableFieldsFromCriteria( rtl::OUString& sCriteria1, uno::Reference< if ( ( nPos = sCriteria1.indexOf( GREATERTHANEQUALS ) ) == 0 ) { sCriteria1 = sCriteria1.copy( GREATERTHANEQUALS.getLength() ); - rFilterField.Operator = sheet::FilterOperator_GREATER_EQUAL; + rFilterField.Operator = sheet::FilterOperator2::GREATER_EQUAL; } else { sCriteria1 = sCriteria1.copy( GREATERTHAN.getLength() ); - rFilterField.Operator = sheet::FilterOperator_GREATER; + rFilterField.Operator = sheet::FilterOperator2::GREATER; } } @@ -4094,17 +4097,17 @@ void lcl_setTableFieldsFromCriteria( rtl::OUString& sCriteria1, uno::Reference< if ( ( nPos = sCriteria1.indexOf( LESSTHANEQUALS ) ) == 0 ) { sCriteria1 = sCriteria1.copy( LESSTHANEQUALS.getLength() ); - rFilterField.Operator = sheet::FilterOperator_LESS_EQUAL; + rFilterField.Operator = sheet::FilterOperator2::LESS_EQUAL; } else { sCriteria1 = sCriteria1.copy( LESSTHAN.getLength() ); - rFilterField.Operator = sheet::FilterOperator_LESS; + rFilterField.Operator = sheet::FilterOperator2::LESS; } } else - rFilterField.Operator = sheet::FilterOperator_EQUAL; + rFilterField.Operator = sheet::FilterOperator2::EQUAL; if ( bIsNumeric ) { @@ -4213,13 +4216,16 @@ ScVbaRange::AutoFilter( const uno::Any& Field, const uno::Any& Criteria1, const bool bAll = false;; if ( ( Field >>= nField ) ) { - uno::Sequence< sheet::TableFilterField > sTabFilts; - uno::Reference< sheet::XSheetFilterDescriptor > xDesc = xDataBaseRange->getFilterDescriptor(); - uno::Reference< beans::XPropertySet > xDescProps( xDesc, uno::UNO_QUERY_THROW ); + uno::Reference< sheet::XSheetFilterDescriptor2 > xDesc( + xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY ); + if ( xDesc.is() ) + { + uno::Sequence< sheet::TableFilterField2 > sTabFilts; + uno::Reference< beans::XPropertySet > xDescProps( xDesc, uno::UNO_QUERY_THROW ); if ( Criteria1.hasValue() ) { sTabFilts.realloc( 1 ); - sTabFilts[0].Operator = sheet::FilterOperator_EQUAL;// sensible default + sTabFilts[0].Operator = sheet::FilterOperator2::EQUAL;// sensible default if ( !bCritHasNumericValue ) { Criteria1 >>= sCriteria1; @@ -4252,16 +4258,16 @@ ScVbaRange::AutoFilter( const uno::Any& Field, const uno::Any& Criteria1, const switch ( nOperator ) { case excel::XlAutoFilterOperator::xlBottom10Items: - sTabFilts[0].Operator = sheet::FilterOperator_BOTTOM_VALUES; + sTabFilts[0].Operator = sheet::FilterOperator2::BOTTOM_VALUES; break; case excel::XlAutoFilterOperator::xlBottom10Percent: - sTabFilts[0].Operator = sheet::FilterOperator_BOTTOM_PERCENT; + sTabFilts[0].Operator = sheet::FilterOperator2::BOTTOM_PERCENT; break; case excel::XlAutoFilterOperator::xlTop10Items: - sTabFilts[0].Operator = sheet::FilterOperator_TOP_VALUES; + sTabFilts[0].Operator = sheet::FilterOperator2::TOP_VALUES; break; case excel::XlAutoFilterOperator::xlTop10Percent: - sTabFilts[0].Operator = sheet::FilterOperator_TOP_PERCENT; + sTabFilts[0].Operator = sheet::FilterOperator2::TOP_PERCENT; break; case excel::XlAutoFilterOperator::xlOr: nConn = sheet::FilterConnection_OR; @@ -4300,12 +4306,12 @@ ScVbaRange::AutoFilter( const uno::Any& Field, const uno::Any& Criteria1, const { Criteria2 >>= sTabFilts[1].NumericValue; sTabFilts[1].IsNumeric = sal_True; - sTabFilts[1].Operator = sheet::FilterOperator_EQUAL; + sTabFilts[1].Operator = sheet::FilterOperator2::EQUAL; } } } - xDesc->setFilterFields( sTabFilts ); + xDesc->setFilterFields2( sTabFilts ); if ( !bAll ) { xDataBaseRange->refresh(); @@ -4313,6 +4319,7 @@ ScVbaRange::AutoFilter( const uno::Any& Field, const uno::Any& Criteria1, const else // was 0 based now seems to be 1 lcl_SetAllQueryForField( pShell, nField, nSheet ); + } } else { @@ -4333,7 +4340,10 @@ ScVbaRange::AutoFilter( const uno::Any& Field, const uno::Any& Criteria1, const lcl_SetAllQueryForField( pShell, rEntry.nField, nSheet ); } // remove exising filters - xDataBaseRange->getFilterDescriptor()->setFilterFields( uno::Sequence< sheet::TableFilterField >() ); + uno::Reference< sheet::XSheetFilterDescriptor2 > xSheetFilterDescriptor( + xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY ); + if( xSheetFilterDescriptor.is() ) + xSheetFilterDescriptor->setFilterFields2( uno::Sequence< sheet::TableFilterField2 >() ); } xDBRangeProps->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("AutoFilter") ), uno::Any(!bHasAuto) ); diff --git a/sc/source/ui/view/cellsh1.cxx b/sc/source/ui/view/cellsh1.cxx index 94184ad63c7c..e5bb702402d8 100644 --- a/sc/source/ui/view/cellsh1.cxx +++ b/sc/source/ui/view/cellsh1.cxx @@ -1709,32 +1709,7 @@ void ScCellShell::ExecuteEdit( SfxRequest& rReq ) break; case SID_TOGGLE_REL: - { - BOOL bOk = FALSE; - SCCOL nCol = GetViewData()->GetCurX(); - SCROW nRow = GetViewData()->GetCurY(); - SCTAB nTab = GetViewData()->GetTabNo(); - ScDocument* pDoc = GetViewData()->GetDocument(); - CellType eType; - pDoc->GetCellType( nCol, nRow, nTab, eType ); - if (eType == CELLTYPE_FORMULA) - { - String aOld; - pDoc->GetFormula( nCol, nRow, nTab, aOld ); - xub_StrLen nLen = aOld.Len(); - ScRefFinder aFinder( aOld, pDoc ); - aFinder.ToggleRel( 0, nLen ); - if (aFinder.GetFound()) - { - String aNew = aFinder.GetText(); - pTabViewShell->EnterData( nCol, nRow, nTab, aNew ); - pTabViewShell->UpdateInputHandler(); - bOk = TRUE; - } - } - if (!bOk) - pTabViewShell->ErrorMessage(STR_ERR_NOREF); - } + pTabViewShell->DoRefConversion(); break; case SID_DEC_INDENT: diff --git a/sc/source/ui/view/viewfun4.cxx b/sc/source/ui/view/viewfun4.cxx index 57fef68c5f83..0f3a1c812802 100644 --- a/sc/source/ui/view/viewfun4.cxx +++ b/sc/source/ui/view/viewfun4.cxx @@ -81,6 +81,9 @@ #include "impex.hxx" #include "editutil.hxx" #include "editable.hxx" +#include "dociter.hxx" +#include "reffind.hxx" +#include "compiler.hxx" using namespace com::sun::star; @@ -187,7 +190,128 @@ void ScViewFunc::PasteRTF( SCCOL nStartCol, SCROW nStartRow, ShowAllCursors(); } } +void ScViewFunc::DoRefConversion( BOOL bRecord ) +{ + ScDocument* pDoc = GetViewData()->GetDocument(); + ScMarkData& rMark = GetViewData()->GetMarkData(); + SCTAB nTabCount = pDoc->GetTableCount(); + if (bRecord && !pDoc->IsUndoEnabled()) + bRecord = FALSE; + ScRange aMarkRange; + rMark.MarkToSimple(); + BOOL bMulti = rMark.IsMultiMarked(); + if (bMulti) + rMark.GetMultiMarkArea( aMarkRange ); + else if (rMark.IsMarked()) + rMark.GetMarkArea( aMarkRange ); + else + { + aMarkRange = ScRange( GetViewData()->GetCurX(), + GetViewData()->GetCurY(), GetViewData()->GetTabNo() ); + } + ScEditableTester aTester( pDoc, aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), + aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(),rMark ); + if (!aTester.IsEditable()) + { + ErrorMessage(aTester.GetMessageId()); + return; + } + + ScDocShell* pDocSh = GetViewData()->GetDocShell(); + BOOL bOk = FALSE; + + ScDocument* pUndoDoc = NULL; + if (bRecord) + { + pUndoDoc = new ScDocument( SCDOCMODE_UNDO ); + SCTAB nTab = aMarkRange.aStart.Tab(); + pUndoDoc->InitUndo( pDoc, nTab, nTab ); + + if ( rMark.GetSelectCount() > 1 ) + { + for (SCTAB i=0; i<nTabCount; i++) + if ( rMark.GetTableSelect(i) && i != nTab ) + pUndoDoc->AddUndoTab( i, i ); + } + ScRange aCopyRange = aMarkRange; + aCopyRange.aStart.SetTab(0); + aCopyRange.aEnd.SetTab(nTabCount-1); + pDoc->CopyToDocument( aCopyRange, IDF_ALL, bMulti, pUndoDoc, &rMark ); + } + + ScRangeListRef xRanges; + GetViewData()->GetMultiArea( xRanges ); + ULONG nCount = xRanges->Count(); + + for (SCTAB i=0; i<nTabCount; i++) + { + if (rMark.GetTableSelect(i)) + { + for (ULONG j=0; j<nCount; j++) + { + ScRange aRange = *xRanges->GetObject(j); + aRange.aStart.SetTab(i); + aRange.aEnd.SetTab(i); + ScCellIterator aIter( pDoc, aRange ); + ScBaseCell* pCell = aIter.GetFirst(); + while ( pCell ) + { + if (pCell->GetCellType() == CELLTYPE_FORMULA) + { + String aOld; + ((ScFormulaCell*)pCell)->GetFormula(aOld); + xub_StrLen nLen = aOld.Len(); + ScRefFinder aFinder( aOld, pDoc ); + aFinder.ToggleRel( 0, nLen ); + if (aFinder.GetFound()) + { + ScAddress aPos = ((ScFormulaCell*)pCell)->aPos; + String aNew = aFinder.GetText(); + ScCompiler aComp( pDoc, aPos); + aComp.SetGrammar(pDoc->GetGrammar()); + ScTokenArray* pArr = aComp.CompileString( aNew ); + ScFormulaCell* pNewCell = new ScFormulaCell( pDoc, aPos, + pArr,formula::FormulaGrammar::GRAM_DEFAULT, MM_NONE ); + pDoc->PutCell( aPos, pNewCell ); + bOk = TRUE; + } + } + pCell = aIter.GetNext(); + } + } + } + } + if (bRecord) + { + ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO ); + SCTAB nTab = aMarkRange.aStart.Tab(); + pRedoDoc->InitUndo( pDoc, nTab, nTab ); + + if ( rMark.GetSelectCount() > 1 ) + { + for (SCTAB i=0; i<nTabCount; i++) + if ( rMark.GetTableSelect(i) && i != nTab ) + pRedoDoc->AddUndoTab( i, i ); + } + ScRange aCopyRange = aMarkRange; + aCopyRange.aStart.SetTab(0); + aCopyRange.aEnd.SetTab(nTabCount-1); + pDoc->CopyToDocument( aCopyRange, IDF_ALL, bMulti, pRedoDoc, &rMark ); + + pDocSh->GetUndoManager()->AddUndoAction( + new ScUndoRefConversion( pDocSh, + aMarkRange, rMark, pUndoDoc, pRedoDoc, bMulti, IDF_ALL) ); + } + + pDocSh->PostPaint( aMarkRange, PAINT_GRID ); + pDocSh->UpdateOle(GetViewData()); + pDocSh->SetDocumentModified(); + CellContentChanged(); + + if (!bOk) + ErrorMessage(STR_ERR_NOREF); +} // Thesaurus - Undo ok void ScViewFunc::DoThesaurus( BOOL bRecord ) { @@ -537,11 +661,13 @@ BOOL ScViewFunc::PasteFile( const Point& rPos, const String& rFile, BOOL bLink ) SfxDispatcher &rDispatcher = GetViewData()->GetDispatcher(); SfxStringItem aFileNameItem( SID_FILE_NAME, aStrURL ); SfxStringItem aFilterItem( SID_FILTER_NAME, pFlt->GetName() ); + // #i69524# add target, as in SfxApplication when the Open dialog is used + SfxStringItem aTargetItem( SID_TARGETNAME, String::CreateFromAscii("_default") ); // Asynchron oeffnen, kann naemlich auch aus D&D heraus passieren // und das bekommt dem MAC nicht so gut ... return BOOL( 0 != rDispatcher.Execute( SID_OPENDOC, - SFX_CALLMODE_ASYNCHRON, &aFileNameItem, &aFilterItem, 0L) ); + SFX_CALLMODE_ASYNCHRON, &aFileNameItem, &aFilterItem, &aTargetItem, 0L) ); } } diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx index fe52636c4e37..79343c31f85b 100644 --- a/sc/source/ui/view/viewfunc.cxx +++ b/sc/source/ui/view/viewfunc.cxx @@ -599,6 +599,7 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rS } else { + DELETEZ(pUndoData); ScFormulaCell* pCell = new ScFormulaCell( aCell, *pDoc, aPos ); if ( nError ) { @@ -751,12 +752,13 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, const EditTextOb ScPatternAttr* pCellAttrs = NULL; EditTextObject* pNewData = NULL; String aString; + + const ScPatternAttr* pOldPattern = pDoc->GetPattern( nCol, nRow, nTab ); + ScTabEditEngine aEngine( *pOldPattern, pDoc->GetEnginePool() ); + aEngine.SetText(*pData); + if (bTestSimple) // Testen, ob einfacher String ohne Attribute { - const ScPatternAttr* pOldPattern = pDoc->GetPattern( nCol, nRow, nTab ); - ScTabEditEngine aEngine( *pOldPattern, pDoc->GetEnginePool() ); - aEngine.SetText(*pData); - ScEditAttrTester aAttrTester( &aEngine ); bSimple = !aAttrTester.NeedsObject(); bCommon = aAttrTester.NeedsCellAttr(); @@ -777,11 +779,11 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, const EditTextOb pCellAttrs->GetFromEditItemSet( &aAttrTester.GetAttribs() ); //! remove common attributes from EditEngine? } - - if (bSimple) - aString = aEngine.GetText(); } + // #i97726# always get text for "repeat" of undo action + aString = ScEditUtil::GetSpaceDelimitedString(aEngine); + // // Undo // @@ -838,7 +840,7 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, const EditTextOb { // wg. ChangeTrack erst jetzt pDocSh->GetUndoManager()->AddUndoAction( new ScUndoEnterData( pDocSh, nCol, nRow, nTab, nPos, pTabs, - ppOldCells, NULL, NULL, String(), + ppOldCells, NULL, NULL, aString, pUndoData ) ); } @@ -924,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()); } |