diff options
author | Jens-Heiner Rechtien <hr@openoffice.org> | 2009-07-28 10:04:47 +0000 |
---|---|---|
committer | Jens-Heiner Rechtien <hr@openoffice.org> | 2009-07-28 10:04:47 +0000 |
commit | 5099046dccb69af04e2a3adafad8e06c0832bd06 (patch) | |
tree | bf9a7b20c84fec1a18a65c66b6a0a25d6bc7e2f7 /sc | |
parent | 6189b25c86e18ef0021ea2f3ba256be36d0fb4be (diff) |
CWS-TOOLING: integrate CWS calc51
2009-07-17 15:47:46 +0200 er r274098 : #i101544# more thorough reference checking in chart data ranges; also prevent some possible crash if invalid ranges were to be passed to document/cell access.
2009-07-16 14:20:11 +0200 er r274051 : #i101544# let ScRefTokenHelper::compileRangeRepresentation() fail on all possible non-reference occasions
2009-07-07 10:11:40 +0200 nn r273776 : #i35579# don't use long instead of sal_Int32
2009-07-03 16:41:39 +0200 nn r273711 : msvc warnings
2009-07-03 14:18:45 +0200 nn r273698 : msvc warning
2009-07-03 11:30:41 +0200 nn r273685 : #i35579# move new tokens to the end
2009-07-03 10:12:55 +0200 nn r273681 : CWS-TOOLING: rebase CWS calc51 to trunk@273468 (milestone: DEV300:m51)
2009-06-30 17:57:30 +0200 nn r273529 : #i103027# EnterData: if it's a formula, don't pass EditTextObject to undo
2009-06-29 14:31:18 +0200 er r273474 : #i101544# #i101645# #i102388# applied diff from CWS dr68ooo311
2009-06-29 10:30:20 +0200 nn r273457 : #i103161# DeleteCells: always leave list action
2009-06-24 16:16:34 +0200 nn r273353 : gcc warnings
2009-06-17 11:50:28 +0200 tbe r273055 : #i35579# Standard filter requires more options
2009-06-17 11:44:22 +0200 tbe r273054 : #i35579# Standard filter requires more options
2009-06-17 11:22:23 +0200 tbe r273052 : #i35579# Standard filter requires more options
2009-06-15 18:29:32 +0200 nn r273006 : #160063# UseFormulaData: check parenthesis position
2009-06-12 15:41:16 +0200 nn r272923 : #i99250# handle range lists in DoAutoOutline (patch from dtardon)
2009-06-11 15:07:05 +0200 nn r272874 : #i86943# GetNextPos: skip overlapped cells
2009-06-11 11:17:37 +0200 nn r272856 : #i97726# EnterData: get text from EditTextObject for repeat string of undo action
2009-06-10 20:45:07 +0200 nn r272839 : #i102566# minimum amount of code between updates of calculation progress (patch by cmc)
2009-06-10 20:22:02 +0200 nn r272838 : #i69524# PasteFile: specify target for SID_OPENDOC
2009-06-09 17:33:08 +0200 nn r272789 : #i16615# absolute/relative reference conversion for cell ranges (patch by gaojingmei)
Diffstat (limited to 'sc')
45 files changed, 1842 insertions, 307 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/compiler.hxx b/sc/inc/compiler.hxx index 155630a97ac2..9f245322fdb7 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); 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/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/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 db4e87d3cdb7..b905bb19db03 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/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/source/core/data/cell.cxx b/sc/source/core/data/cell.cxx index fe34d185b898..ea758e91da06 100644 --- a/sc/source/core/data/cell.cxx +++ b/sc/source/core/data/cell.cxx @@ -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..2a1525b76401 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(); 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/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/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..0f0844392e76 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -1811,9 +1811,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 +1826,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 +1966,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 +2114,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 +2413,7 @@ Label_MaskStateMachine: { nSrcPos = sal::static_int_cast<xub_StrLen>( nSrcPos + nSpaces ); String aSymbol; - bRangeOp = false; + mnRangeOpPosInSymbol = -1; USHORT nErr = 0; do { @@ -2438,9 +2442,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 +2464,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 +2847,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 +3576,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; + } + + // 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; + } - if (!aUpper.Len()) - bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); + if (!aUpper.Len()) + bAsciiUpper = lcl_UpperAsciiOrI18n( aUpper, aOrg, meGrammar); - // IsBoolean() before IsValue() to catch inline bools without the kludge - // for inline arrays. - if (bAllowBooleans && IsBoolean( aUpper )) - return true; + // IsBoolean() before IsValue() to catch inline bools without the kludge + // for inline arrays. + if (bAllowBooleans && IsBoolean( aUpper )) + return true; - if (IsValue( aUpper )) - return true; + if (IsValue( aUpper )) + return true; - // User defined names and such do need i18n upper also in ODF. - if (bAsciiUpper) - aUpper = ScGlobal::pCharClass->upper( aOrg ); + // 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; + 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 ) { 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/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/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/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/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/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/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 303d344d3594..15f9f751338c 100644 --- a/sc/source/ui/docshell/docfunc.cxx +++ b/sc/source/ui/docshell/docfunc.cxx @@ -2073,6 +2073,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 ) ); 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/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..7674bbbf3042 100644 --- a/sc/source/ui/unoobj/cellsuno.cxx +++ b/sc/source/ui/unoobj/cellsuno.cxx @@ -5633,7 +5633,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 ); 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/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..da7d409c492c 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 ) ); } |