diff options
50 files changed, 2177 insertions, 601 deletions
diff --git a/chart2/source/view/charttypes/PieChart.cxx b/chart2/source/view/charttypes/PieChart.cxx index 80f856e94..3596d1758 100644 --- a/chart2/source/view/charttypes/PieChart.cxx +++ b/chart2/source/view/charttypes/PieChart.cxx @@ -129,6 +129,8 @@ PieChart::PieChart( const uno::Reference<XChartType>& xChartTypeModel , m_pPosHelper( new PiePositionHelper( NormalAxis_Z, (m_nDimension==3)?0.0:90.0 ) ) , m_bUseRings(false) { + ::rtl::math::setNan(&m_fMaxOffset); + PlotterBase::m_pPosHelper = m_pPosHelper; VSeriesPlotter::m_pMainPosHelper = m_pPosHelper; m_pPosHelper->m_fRadiusOffset = 0.0; @@ -248,27 +250,31 @@ double PieChart::getMinimumX() { return 0.5; } -double PieChart::getMaxOffset() const +double PieChart::getMaxOffset() { - double fRet = 0.0; + if (!::rtl::math::isNan(m_fMaxOffset)) + // Value already cached. Use it. + return m_fMaxOffset; + + m_fMaxOffset = 0.0; if( m_aZSlots.size()<=0 ) - return fRet; + return m_fMaxOffset; if( m_aZSlots[0].size()<=0 ) - return fRet; + return m_fMaxOffset; const ::std::vector< VDataSeries* >& rSeriesList( m_aZSlots[0][0].m_aSeriesVector ); if( rSeriesList.size()<=0 ) - return fRet; + return m_fMaxOffset; VDataSeries* pSeries = rSeriesList[0]; uno::Reference< beans::XPropertySet > xSeriesProp( pSeries->getPropertiesOfSeries() ); if( !xSeriesProp.is() ) - return fRet; + return m_fMaxOffset; double fExplodePercentage=0.0; xSeriesProp->getPropertyValue( C2U( "Offset" )) >>= fExplodePercentage; - if(fExplodePercentage>fRet) - fRet=fExplodePercentage; + if(fExplodePercentage>m_fMaxOffset) + m_fMaxOffset=fExplodePercentage; uno::Sequence< sal_Int32 > aAttributedDataPointIndexList; if( xSeriesProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList ) @@ -280,12 +286,12 @@ double PieChart::getMaxOffset() const { fExplodePercentage=0.0; xPointProp->getPropertyValue( C2U( "Offset" )) >>= fExplodePercentage; - if(fExplodePercentage>fRet) - fRet=fExplodePercentage; + if(fExplodePercentage>m_fMaxOffset) + m_fMaxOffset=fExplodePercentage; } } } - return fRet; + return m_fMaxOffset; } double PieChart::getMaximumX() { @@ -357,6 +363,7 @@ void PieChart::createShapes() nExplodeableSlot = m_aZSlots[0].size()-1; m_aLabelInfoList.clear(); + ::rtl::math::setNan(&m_fMaxOffset); //============================================================================= for( double fSlotX=0; aXSlotIter != aXSlotEnd && (m_bUseRings||fSlotX<0.5 ); aXSlotIter++, fSlotX+=1.0 ) diff --git a/chart2/source/view/charttypes/PieChart.hxx b/chart2/source/view/charttypes/PieChart.hxx index e32a9e8b7..644751511 100644 --- a/chart2/source/view/charttypes/PieChart.hxx +++ b/chart2/source/view/charttypes/PieChart.hxx @@ -105,7 +105,7 @@ private: //methods , double fLogicZ, double fDepth, double fExplodePercentage , tPropertyNameValueMap* pOverWritePropertiesMap ); - double getMaxOffset() const; + double getMaxOffset(); bool detectLabelOverlapsAndMove(const ::com::sun::star::awt::Size& rPageSize);//returns true when there might be more to do void resetLabelPositionsToPreviousState(); struct PieLabelInfo; @@ -137,6 +137,8 @@ private: //member }; ::std::vector< PieLabelInfo > m_aLabelInfoList; + + double m_fMaxOffset; /// cached max offset value (init'ed to NaN) }; //............................................................................. } //namespace chart diff --git a/sc/inc/chart2uno.hxx b/sc/inc/chart2uno.hxx index bb865288b..dc3228ec5 100644 --- a/sc/inc/chart2uno.hxx +++ b/sc/inc/chart2uno.hxx @@ -533,6 +533,14 @@ private: }; ::std::list<Item> m_aDataArray; + + /** + * Cached data for getData. We may also need to cache data for the + * numerical and textural data series if they turn out to be bottlenecks + * under certain scenarios. + */ + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > m_aMixedDataCache; + ::com::sun::star::uno::Sequence<sal_Int32> m_aHiddenValues; // properties diff --git a/sc/inc/chartlis.hxx b/sc/inc/chartlis.hxx index ae3f70cf3..016158386 100644 --- a/sc/inc/chartlis.hxx +++ b/sc/inc/chartlis.hxx @@ -49,7 +49,7 @@ class ScChartUnoData; #include <com/sun/star/chart/XChartData.hpp> #include <com/sun/star/chart/XChartDataChangeEventListener.hpp> -class ScChartListener : public StrData, public SvtListener +class SC_DLLPUBLIC ScChartListener : public StrData, public SvtListener { public: class ExternalRefListener : public ScExternalRefManager::LinkListener @@ -186,7 +186,7 @@ public: const com::sun::star::uno::Reference< com::sun::star::chart::XChartData >& rSource ); void StartTimer(); void UpdateDirtyCharts(); - void SetDirty(); + void SC_DLLPUBLIC SetDirty(); void SetDiffDirty( const ScChartListenerCollection&, BOOL bSetChartRangeLists = FALSE ); diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 14ad931f9..f48a86b2b 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -114,7 +114,7 @@ private: friend class ScDocument; // fuer FillInfo friend class ScDocumentIterator; friend class ScValueIterator; -friend class ScQueryValueIterator; +friend class ScDBQueryDataIterator; friend class ScColumnIterator; friend class ScQueryCellIterator; friend class ScMarkedDataIter; diff --git a/sc/inc/datauno.hxx b/sc/inc/datauno.hxx index 10e2e2257..8e0d18d88 100644 --- a/sc/inc/datauno.hxx +++ b/sc/inc/datauno.hxx @@ -32,8 +32,8 @@ #define SC_DATAUNO_HXX #include "global.hxx" -#include <svl/itemprop.hxx> -#include <svl/lstner.hxx> +#include "queryparam.hxx" + #include <com/sun/star/sheet/TableFilterField.hpp> #include <com/sun/star/sheet/GeneralFunction.hpp> #include <com/sun/star/sheet/XCellRangeReferrer.hpp> @@ -56,6 +56,8 @@ #include <cppuhelper/implbase4.hxx> #include <cppuhelper/implbase5.hxx> #include <cppuhelper/implbase6.hxx> +#include "svl/itemprop.hxx" +#include "svl/lstner.hxx" class ScDBData; class ScDocShell; diff --git a/sc/inc/dociter.hxx b/sc/inc/dociter.hxx index d5d42354d..495c57d10 100644 --- a/sc/inc/dociter.hxx +++ b/sc/inc/dociter.hxx @@ -35,6 +35,9 @@ #include <tools/solar.h> #include "global.hxx" #include "scdllapi.h" +#include "queryparam.hxx" + +#include <memory> class ScDocument; class ScBaseCell; @@ -127,34 +130,97 @@ public: } }; -class ScQueryValueIterator // alle Zahlenwerte in einem Bereich durchgehen +// ============================================================================ + +class ScDBQueryDataIterator { +public: + struct Value + { + ::rtl::OUString maString; + double mfValue; + sal_uInt16 mnError; + bool mbIsNumber; + + Value(); + }; + private: - ScQueryParam aParam; - ScDocument* pDoc; - const ScAttrArray* pAttrArray; - ULONG nNumFormat; // fuer CalcAsShown - ULONG nNumFmtIndex; - SCCOL nCol; - SCROW nRow; - SCSIZE nColRow; - SCROW nAttrEndRow; - SCTAB nTab; - short nNumFmtType; - BOOL bCalcAsShown; + static SCROW GetRowByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow); + static ScBaseCell* GetCellByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow); + static ScAttrArray* GetAttrArrayByCol(ScDocument& rDoc, SCTAB nTab, SCCOL nCol); + static bool IsQueryValid(ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, ScBaseCell* pCell); + static SCSIZE SearchColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCROW nRow, SCCOL nCol); + + class DataAccess + { + public: + DataAccess(const ScDBQueryDataIterator* pParent); + virtual ~DataAccess() = 0; + virtual bool getCurrent(Value& rValue) = 0; + virtual bool getFirst(Value& rValue) = 0; + virtual bool getNext(Value& rValue) = 0; + protected: + const ScDBQueryDataIterator* mpParent; + }; + + class DataAccessInternal : public DataAccess + { + public: + DataAccessInternal(const ScDBQueryDataIterator* pParent, ScDBQueryParamInternal* pParam, ScDocument* pDoc); + virtual ~DataAccessInternal(); + virtual bool getCurrent(Value& rValue); + virtual bool getFirst(Value& rValue); + virtual bool getNext(Value& rValue); + + private: + ScDBQueryParamInternal* mpParam; + ScDocument* mpDoc; + const ScAttrArray* pAttrArray; + ULONG nNumFormat; // for CalcAsShown + ULONG nNumFmtIndex; + SCCOL nCol; + SCROW nRow; + SCSIZE nColRow; + SCROW nAttrEndRow; + SCTAB nTab; + short nNumFmtType; + bool bCalcAsShown; + }; + + class DataAccessMatrix : public DataAccess + { + public: + DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam); + virtual ~DataAccessMatrix(); + virtual bool getCurrent(Value& rValue); + virtual bool getFirst(Value& rValue); + virtual bool getNext(Value& rValue); + + private: + bool isValidQuery(SCROW mnRow, const ScMatrix& rMat) const; + + ScDBQueryParamMatrix* mpParam; + SCROW mnCurRow; + SCROW mnRows; + SCCOL mnCols; + }; + + ::std::auto_ptr<ScDBQueryParamBase> mpParam; + ::std::auto_ptr<DataAccess> mpData; + + bool GetThis(Value& rValue); - BOOL GetThis(double& rValue, USHORT& rErr); public: - ScQueryValueIterator(ScDocument* pDocument, SCTAB nTable, - const ScQueryParam& aParam); + ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam); /// Does NOT reset rValue if no value found! - BOOL GetFirst(double& rValue, USHORT& rErr); + bool GetFirst(Value& rValue); /// Does NOT reset rValue if no value found! - BOOL GetNext(double& rValue, USHORT& rErr); - void GetCurNumFmtInfo( short& nType, ULONG& nIndex ) - { nType = nNumFmtType; nIndex = nNumFmtIndex; } + bool GetNext(Value& rValue); }; +// ============================================================================ + class ScCellIterator // alle Zellen in einem Bereich durchgehen { // bei SubTotal aber keine ausgeblendeten und private: // SubTotalZeilen diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 23a383306..fe8a9b6b9 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -229,7 +229,7 @@ class ScDocument { friend class ScDocumentIterator; friend class ScValueIterator; -friend class ScQueryValueIterator; +friend class ScDBQueryDataIterator; friend class ScCellIterator; friend class ScQueryCellIterator; friend class ScHorizontalCellIterator; @@ -423,6 +423,7 @@ private: public: SC_DLLPUBLIC ULONG GetCellCount() const; // alle Zellen + SCSIZE GetCellCount(SCTAB nTab, SCCOL nCol) const; ULONG GetWeightedCount() const; // Formeln und Edit staerker gewichtet ULONG GetCodeCount() const; // RPN-Code in Formeln DECL_LINK( GetUserDefinedColor, USHORT * ); diff --git a/sc/inc/dpcachetable.hxx b/sc/inc/dpcachetable.hxx index 7a605354e..0a22fb06e 100644 --- a/sc/inc/dpcachetable.hxx +++ b/sc/inc/dpcachetable.hxx @@ -60,6 +60,7 @@ class ScDPDimension; class ScDPCollection; struct ScDPCacheCell; struct ScDPItemData; +struct ScQueryParam; class Date; // ---------------------------------------------------------------------------- diff --git a/sc/inc/dpshttab.hxx b/sc/inc/dpshttab.hxx index ede4933cf..8483ca2a5 100644 --- a/sc/inc/dpshttab.hxx +++ b/sc/inc/dpshttab.hxx @@ -35,6 +35,7 @@ #include "global.hxx" #include "address.hxx" #include "scdllapi.h" +#include "queryparam.hxx" #include <vector> diff --git a/sc/inc/global.hxx b/sc/inc/global.hxx index 57a6ff146..b401cb92c 100644 --- a/sc/inc/global.hxx +++ b/sc/inc/global.hxx @@ -817,47 +817,6 @@ struct ScQueryEntry BOOL operator==( const ScQueryEntry& r ) const; }; -struct SC_DLLPUBLIC ScQueryParam -{ - SCCOL nCol1; - SCROW nRow1; - SCCOL nCol2; - SCROW nRow2; - SCTAB nTab; - BOOL bHasHeader; - BOOL bByRow; - BOOL bInplace; - BOOL bCaseSens; - BOOL bRegExp; - BOOL bMixedComparison; // whether numbers are smaller than strings - BOOL bDuplicate; - BOOL bDestPers; // nicht gespeichert - SCTAB nDestTab; - SCCOL nDestCol; - SCROW nDestRow; - -private: - SCSIZE nEntryCount; - ScQueryEntry* pEntries; - -public: - ScQueryParam(); - ScQueryParam( const ScQueryParam& r ); - ~ScQueryParam(); - - SCSIZE GetEntryCount() const { return nEntryCount; } - ScQueryEntry& GetEntry(SCSIZE n) const { return pEntries[n]; } - void Resize(SCSIZE nNew); - - ScQueryParam& operator= ( const ScQueryParam& r ); - BOOL operator== ( const ScQueryParam& rOther ) const; - void Clear (); - void DeleteQuery( SCSIZE nPos ); - - void MoveToDest(); - void FillInExcelSyntax(String& aCellStr, SCSIZE nIndex); -}; - // ----------------------------------------------------------------------- struct SC_DLLPUBLIC ScSubTotalParam diff --git a/sc/inc/queryparam.hxx b/sc/inc/queryparam.hxx new file mode 100644 index 000000000..bc5023728 --- /dev/null +++ b/sc/inc/queryparam.hxx @@ -0,0 +1,142 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: interpre.hxx,v $ + * $Revision: 1.35.44.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_QUERYPARAM_HXX +#define SC_QUERYPARAM_HXX + +#include "global.hxx" +#include "scmatrix.hxx" + +#include <vector> + +struct ScDBQueryParamInternal; + +struct ScQueryParamBase +{ + bool bHasHeader; + bool bByRow; + bool bInplace; + bool bCaseSens; + bool bRegExp; + bool bDuplicate; + bool bMixedComparison; // whether numbers are smaller than strings + + virtual ~ScQueryParamBase(); + + SC_DLLPUBLIC SCSIZE GetEntryCount() const; + SC_DLLPUBLIC ScQueryEntry& GetEntry(SCSIZE n) const; + void Resize(SCSIZE nNew); + SC_DLLPUBLIC void DeleteQuery( SCSIZE nPos ); + void FillInExcelSyntax(String& aCellStr, SCSIZE nIndex); + +protected: + ScQueryParamBase(); + ScQueryParamBase(const ScQueryParamBase& r); + + mutable ::std::vector<ScQueryEntry> maEntries; +}; + +// ============================================================================ + +struct ScQueryParamTable +{ + SCCOL nCol1; + SCROW nRow1; + SCCOL nCol2; + SCROW nRow2; + SCTAB nTab; + + ScQueryParamTable(); + ScQueryParamTable(const ScQueryParamTable& r); + virtual ~ScQueryParamTable(); +}; + +// ============================================================================ + +struct SC_DLLPUBLIC ScQueryParam : public ScQueryParamBase, public ScQueryParamTable +{ + BOOL bDestPers; // nicht gespeichert + SCTAB nDestTab; + SCCOL nDestCol; + SCROW nDestRow; + + ScQueryParam(); + ScQueryParam( const ScQueryParam& r ); + ScQueryParam( const ScDBQueryParamInternal& r ); + virtual ~ScQueryParam(); + + ScQueryParam& operator= ( const ScQueryParam& r ); + BOOL operator== ( const ScQueryParam& rOther ) const; + void Clear(); + void ClearDestParams(); + void MoveToDest(); +}; + +// ============================================================================ + +struct ScDBQueryParamBase : public ScQueryParamBase +{ + enum DataType { INTERNAL, MATRIX }; + + SCCOL mnField; /// the field in which the values are processed during iteration. + bool mbSkipString; + + DataType GetType() const; + + virtual ~ScDBQueryParamBase(); + +protected: + ScDBQueryParamBase(DataType eType); + +private: + ScDBQueryParamBase(); + + DataType meType; +}; + +// ============================================================================ + +struct ScDBQueryParamInternal : public ScDBQueryParamBase, public ScQueryParamTable +{ + ScDBQueryParamInternal(); + virtual ~ScDBQueryParamInternal(); +}; + +// ============================================================================ + +struct ScDBQueryParamMatrix : public ScDBQueryParamBase +{ + ScMatrixRef mpMatrix; + + ScDBQueryParamMatrix(); + virtual ~ScDBQueryParamMatrix(); +}; + +#endif diff --git a/sc/inc/reftokenhelper.hxx b/sc/inc/reftokenhelper.hxx index d7b335f9b..99a59982a 100644 --- a/sc/inc/reftokenhelper.hxx +++ b/sc/inc/reftokenhelper.hxx @@ -70,12 +70,12 @@ public: static void getTokensFromRangeList(::std::vector<ScSharedTokenRef>& pTokens, const ScRangeList& rRanges); - static bool isRef(const ScSharedTokenRef& pToken); - static bool isExternalRef(const ScSharedTokenRef& pToken); + static bool SC_DLLPUBLIC isRef(const ScSharedTokenRef& pToken); + static bool SC_DLLPUBLIC isExternalRef(const ScSharedTokenRef& pToken); - static bool intersects(const ::std::vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken); + static bool SC_DLLPUBLIC intersects(const ::std::vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken); - static void join(::std::vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken); + static void SC_DLLPUBLIC join(::std::vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken); static bool getDoubleRefDataFromToken(ScComplexRefData& rData, const ScSharedTokenRef& pToken); }; diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 3b5532d25..034d5fdca 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -162,7 +162,7 @@ private: friend class ScDocument; // fuer FillInfo friend class ScDocumentIterator; friend class ScValueIterator; -friend class ScQueryValueIterator; +friend class ScDBQueryDataIterator; friend class ScCellIterator; friend class ScQueryCellIterator; friend class ScHorizontalCellIterator; @@ -178,6 +178,7 @@ public: ScOutlineTable* GetOutlineTable() { return pOutlineTable; } + SCSIZE GetCellCount(SCCOL nCol) const; ULONG GetCellCount() const; ULONG GetWeightedCount() const; ULONG GetCodeCount() const; // RPN-Code in Formeln diff --git a/sc/source/core/data/autonamecache.cxx b/sc/source/core/data/autonamecache.cxx index ea41e3e4f..329e7f469 100644 --- a/sc/source/core/data/autonamecache.cxx +++ b/sc/source/core/data/autonamecache.cxx @@ -40,6 +40,7 @@ #include "autonamecache.hxx" #include "dociter.hxx" #include "cell.hxx" +#include "queryparam.hxx" // ----------------------------------------------------------------------- diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx index 6f79316e0..fab5ad92d 100644..100755 --- a/sc/source/core/data/dociter.cxx +++ b/sc/source/core/data/dociter.cxx @@ -47,9 +47,23 @@ #include "docoptio.hxx" #include "cellform.hxx" +#include <vector> + +using ::rtl::math::approxEqual; +using ::std::vector; +using ::rtl::OUString; // STATIC DATA ----------------------------------------------------------- +namespace { + +void lcl_toUpper(OUString& rStr) +{ + rStr = ScGlobal::pCharClass->toUpper(rStr.trim(), 0, static_cast<USHORT>(rStr.getLength())); +} + +} + ScDocumentIterator::ScDocumentIterator( ScDocument* pDocument, SCTAB nStartTable, SCTAB nEndTable ) : pDoc( pDocument ), @@ -482,83 +496,121 @@ BOOL ScValueIterator::GetNext(double& rValue, USHORT& rErr) } */ -//------------------------------------------------------------------------ -//------------------------------------------------------------------------ +// ============================================================================ -ScQueryValueIterator::ScQueryValueIterator(ScDocument* pDocument, SCTAB nTable, const ScQueryParam& rParam) : - aParam (rParam), - pDoc( pDocument ), - nNumFmtIndex(0), - nTab( nTable), - nNumFmtType( NUMBERFORMAT_UNDEFINED ), - bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ) +ScDBQueryDataIterator::DataAccess::DataAccess(const ScDBQueryDataIterator* pParent) : + mpParent(pParent) { - nCol = aParam.nCol1; - nRow = aParam.nRow1; +} + +ScDBQueryDataIterator::DataAccess::~DataAccess() +{ +} + +SCROW ScDBQueryDataIterator::GetRowByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow) +{ + ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol]; + return pCol->pItems[nColRow].nRow; +} + +ScBaseCell* ScDBQueryDataIterator::GetCellByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow) +{ + ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol]; + return pCol->pItems[nColRow].pCell; +} + +ScAttrArray* ScDBQueryDataIterator::GetAttrArrayByCol(ScDocument& rDoc, SCTAB nTab, SCCOL nCol) +{ + ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol]; + return pCol->pAttrArray; +} + +bool ScDBQueryDataIterator::IsQueryValid(ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, ScBaseCell* pCell) +{ + return rDoc.pTab[nTab]->ValidQuery(nRow, rParam, NULL, pCell); +} + +SCSIZE ScDBQueryDataIterator::SearchColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCROW nRow, SCCOL nCol) +{ + ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol]; + SCSIZE nColRow; + pCol->Search(nRow, nColRow); + return nColRow; +} + +// ---------------------------------------------------------------------------- + +ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(const ScDBQueryDataIterator* pParent, ScDBQueryParamInternal* pParam, ScDocument* pDoc) : + DataAccess(pParent), + mpParam(pParam), + mpDoc(pDoc) +{ + nCol = mpParam->mnField; + nRow = mpParam->nRow1; + nTab = mpParam->nTab; + nColRow = 0; // wird bei GetFirst initialisiert SCSIZE i; - SCSIZE nCount = aParam.GetEntryCount(); - for (i=0; (i<nCount) && (aParam.GetEntry(i).bDoQuery); i++) + SCSIZE nCount = mpParam->GetEntryCount(); + for (i=0; (i<nCount) && (mpParam->GetEntry(i).bDoQuery); i++) { - ScQueryEntry& rEntry = aParam.GetEntry(i); + ScQueryEntry& rEntry = mpParam->GetEntry(i); sal_uInt32 nIndex = 0; rEntry.bQueryByString = - !(pDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, nIndex, rEntry.nVal)); + !(mpDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, nIndex, rEntry.nVal)); } nNumFormat = 0; // werden bei GetNumberFormat initialisiert pAttrArray = 0; nAttrEndRow = 0; } -BOOL ScQueryValueIterator::GetThis(double& rValue, USHORT& rErr) +ScDBQueryDataIterator::DataAccessInternal::~DataAccessInternal() { - ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; - SCCOLROW nFirstQueryField = aParam.GetEntry(0).nField; +} + +bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue) +{ + SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField; for ( ;; ) { - if ( nRow > aParam.nRow2 ) + if (nRow > mpParam->nRow2) { - nRow = aParam.nRow1; - if (aParam.bHasHeader) - nRow++; - do - { - nCol++; - if ( nCol > aParam.nCol2 ) - { - // rValue = 0.0; // do not change caller's value! - rErr = 0; - return FALSE; // Ende und Aus - } - pCol = &(pDoc->pTab[nTab])->aCol[nCol]; - } while ( pCol->nCount == 0 ); - pCol->Search( nRow, nColRow ); + // Bottom of the range reached. Bail out. + rValue.mnError = 0; + return false; } - while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) ) - nColRow++; + SCSIZE nCellCount = mpDoc->GetCellCount(nTab, nCol); + SCROW nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, nColRow); + while ( (nColRow < nCellCount) && (nThisRow < nRow) ) + nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, ++nColRow); - if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= aParam.nRow2 ) + if ( nColRow < nCellCount && nThisRow <= mpParam->nRow2 ) { - nRow = pCol->pItems[nColRow].nRow; - ScBaseCell* pCell = pCol->pItems[nColRow].pCell; - if ( (pDoc->pTab[nTab])->ValidQuery( nRow, aParam, NULL, - (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL) ) ) + nRow = nThisRow; + ScBaseCell* pCell = NULL; + if (nCol == static_cast<SCCOL>(nFirstQueryField)) + pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow); + + if (ScDBQueryDataIterator::IsQueryValid(*mpDoc, *mpParam, nTab, nRow, pCell)) { switch (pCell->GetCellType()) { case CELLTYPE_VALUE: { - rValue = ((ScValueCell*)pCell)->GetValue(); + rValue.mfValue = ((ScValueCell*)pCell)->GetValue(); + rValue.mbIsNumber = true; if ( bCalcAsShown ) { + const ScAttrArray* pNewAttrArray = + ScDBQueryDataIterator::GetAttrArrayByCol(*mpDoc, nTab, nCol); lcl_IterGetNumberFormat( nNumFormat, pAttrArray, - nAttrEndRow, pCol->pAttrArray, nRow, pDoc ); - rValue = pDoc->RoundValueAsShown( rValue, nNumFormat ); + nAttrEndRow, pNewAttrArray, nRow, mpDoc ); + rValue.mfValue = mpDoc->RoundValueAsShown( rValue.mfValue, nNumFormat ); } nNumFmtType = NUMBERFORMAT_NUMBER; nNumFmtIndex = 0; - rErr = 0; + rValue.mnError = 0; return TRUE; // gefunden } // break; @@ -566,17 +618,31 @@ BOOL ScQueryValueIterator::GetThis(double& rValue, USHORT& rErr) { if (((ScFormulaCell*)pCell)->IsValue()) { - rValue = ((ScFormulaCell*)pCell)->GetValue(); - pDoc->GetNumberFormatInfo( nNumFmtType, + rValue.mfValue = ((ScFormulaCell*)pCell)->GetValue(); + rValue.mbIsNumber = true; + mpDoc->GetNumberFormatInfo( nNumFmtType, nNumFmtIndex, ScAddress( nCol, nRow, nTab ), pCell ); - rErr = ((ScFormulaCell*)pCell)->GetErrCode(); + rValue.mnError = ((ScFormulaCell*)pCell)->GetErrCode(); return TRUE; // gefunden } else nRow++; } break; + case CELLTYPE_STRING: + case CELLTYPE_EDIT: + if (mpParam->mbSkipString) + ++nRow; + else + { + rValue.maString = pCell->GetStringData(); + rValue.mfValue = 0.0; + rValue.mnError = 0; + rValue.mbIsNumber = false; + return true; + } + break; default: nRow++; break; @@ -586,30 +652,309 @@ BOOL ScQueryValueIterator::GetThis(double& rValue, USHORT& rErr) nRow++; } else - nRow = aParam.nRow2 + 1; // Naechste Spalte + nRow = mpParam->nRow2 + 1; // Naechste Spalte } -// return FALSE; +// statement unreachable +// return false; } -BOOL ScQueryValueIterator::GetFirst(double& rValue, USHORT& rErr) +bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value& rValue) { - nCol = aParam.nCol1; - nRow = aParam.nRow1; - if (aParam.bHasHeader) + if (mpParam->bHasHeader) nRow++; -// nColRow = 0; - ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; - pCol->Search( nRow, nColRow ); - return GetThis(rValue, rErr); + + nColRow = ScDBQueryDataIterator::SearchColEntryIndex(*mpDoc, nTab, nRow, nCol); + return getCurrent(rValue); } -BOOL ScQueryValueIterator::GetNext(double& rValue, USHORT& rErr) +bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value& rValue) { ++nRow; - return GetThis(rValue, rErr); + return getCurrent(rValue); } -//------------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam) : + DataAccess(pParent), + mpParam(pParam) +{ + SCSIZE nC, nR; + mpParam->mpMatrix->GetDimensions(nC, nR); + mnRows = static_cast<SCROW>(nR); + mnCols = static_cast<SCCOL>(nC); +} + +ScDBQueryDataIterator::DataAccessMatrix::~DataAccessMatrix() +{ +} + +bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value& rValue) +{ + // Starting from row == mnCurRow, get the first row that satisfies all the + // query parameters. + for ( ;mnCurRow < mnRows; ++mnCurRow) + { + const ScMatrix& rMat = *mpParam->mpMatrix; + if (rMat.IsEmpty(mpParam->mnField, mnCurRow)) + // Don't take empty values into account. + continue; + + bool bIsStrVal = rMat.IsString(mpParam->mnField, mnCurRow); + if (bIsStrVal && mpParam->mbSkipString) + continue; + + if (isValidQuery(mnCurRow, rMat)) + { + rValue.maString = rMat.GetString(mpParam->mnField, mnCurRow); + rValue.mfValue = rMat.GetDouble(mpParam->mnField, mnCurRow); + rValue.mbIsNumber = !bIsStrVal; + rValue.mnError = 0; + return true; + } + } + return false; +} + +bool ScDBQueryDataIterator::DataAccessMatrix::getFirst(Value& rValue) +{ + mnCurRow = mpParam->bHasHeader ? 1 : 0; + return getCurrent(rValue); +} + +bool ScDBQueryDataIterator::DataAccessMatrix::getNext(Value& rValue) +{ + ++mnCurRow; + return getCurrent(rValue); +} + +namespace { + +bool lcl_isQueryByValue(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow) +{ + if (rEntry.bQueryByString) + return false; + + if (!rMat.IsValueOrEmpty(nCol, nRow)) + return false; + + return true; +} + +bool lcl_isQueryByString(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow) +{ + switch (rEntry.eOp) + { + case SC_EQUAL: + case SC_NOT_EQUAL: + case SC_CONTAINS: + case SC_DOES_NOT_CONTAIN: + case SC_BEGINS_WITH: + case SC_ENDS_WITH: + case SC_DOES_NOT_BEGIN_WITH: + case SC_DOES_NOT_END_WITH: + return true; + default: + ; + } + + if (rEntry.bQueryByString && rMat.IsString(nCol, nRow)) + return true; + + return false; +} + +} + +bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScMatrix& rMat) const +{ + SCSIZE nEntryCount = mpParam->GetEntryCount(); + vector<bool> aResults; + aResults.reserve(nEntryCount); + + const CollatorWrapper& rCollator = + mpParam->bCaseSens ? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator(); + + for (SCSIZE i = 0; i < nEntryCount; ++i) + { + const ScQueryEntry& rEntry = mpParam->GetEntry(i); + if (!rEntry.bDoQuery) + continue; + + switch (rEntry.eOp) + { + case SC_EQUAL: + case SC_LESS: + case SC_GREATER: + case SC_LESS_EQUAL: + case SC_GREATER_EQUAL: + case SC_NOT_EQUAL: + break; + default: + // Only the above operators are supported. + continue; + } + + bool bValid = false; + + SCSIZE nField = static_cast<SCSIZE>(rEntry.nField); + if (lcl_isQueryByValue(rEntry, rMat, nField, nRow)) + { + // By value + double fMatVal = rMat.GetDouble(nField, nRow); + bool bEqual = approxEqual(fMatVal, rEntry.nVal); + switch (rEntry.eOp) + { + case SC_EQUAL: + bValid = bEqual; + break; + case SC_LESS: + bValid = (fMatVal < rEntry.nVal) && !bEqual; + break; + case SC_GREATER: + bValid = (fMatVal > rEntry.nVal) && !bEqual; + break; + case SC_LESS_EQUAL: + bValid = (fMatVal < rEntry.nVal) || bEqual; + break; + case SC_GREATER_EQUAL: + bValid = (fMatVal > rEntry.nVal) || bEqual; + break; + case SC_NOT_EQUAL: + bValid = !bEqual; + break; + default: + ; + } + } + else if (lcl_isQueryByString(rEntry, rMat, nField, nRow)) + { + // By string + do + { + if (!rEntry.pStr) + break; + + // Equality check first. + + OUString aMatStr = rMat.GetString(nField, nRow); + lcl_toUpper(aMatStr); + OUString aQueryStr = *rEntry.pStr; + lcl_toUpper(aQueryStr); + bool bDone = false; + switch (rEntry.eOp) + { + case SC_EQUAL: + bValid = aMatStr.equals(aQueryStr); + bDone = true; + break; + case SC_NOT_EQUAL: + bValid = !aMatStr.equals(aQueryStr); + bDone = true; + break; + default: + ; + } + + if (bDone) + break; + + // Unequality check using collator. + + sal_Int32 nCompare = rCollator.compareString(aMatStr, aQueryStr); + switch (rEntry.eOp) + { + case SC_LESS : + bValid = (nCompare < 0); + break; + case SC_GREATER : + bValid = (nCompare > 0); + break; + case SC_LESS_EQUAL : + bValid = (nCompare <= 0); + break; + case SC_GREATER_EQUAL : + bValid = (nCompare >= 0); + break; + default: + ; + } + } + while (false); + } + else if (mpParam->bMixedComparison) + { + // Not used at the moment. + } + + if (aResults.empty()) + // First query entry. + aResults.push_back(bValid); + else if (rEntry.eConnect == SC_AND) + { + // For AND op, tuck the result into the last result value. + size_t n = aResults.size(); + aResults[n-1] = aResults[n-1] && bValid; + } + else + // For OR op, store its own result. + aResults.push_back(bValid); + } + + // Row is valid as long as there is at least one result being true. + vector<bool>::const_iterator itr = aResults.begin(), itrEnd = aResults.end(); + for (; itr != itrEnd; ++itr) + if (*itr) + return true; + + return false; +} + +// ---------------------------------------------------------------------------- + +ScDBQueryDataIterator::Value::Value() : + mnError(0), mbIsNumber(true) +{ + ::rtl::math::setNan(&mfValue); +} + +// ---------------------------------------------------------------------------- + +ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) : + mpParam (pParam) +{ + switch (mpParam->GetType()) + { + case ScDBQueryParamBase::INTERNAL: + { + ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam); + mpData.reset(new DataAccessInternal(this, p, pDocument)); + } + break; + case ScDBQueryParamBase::MATRIX: + { + ScDBQueryParamMatrix* p = static_cast<ScDBQueryParamMatrix*>(pParam); + mpData.reset(new DataAccessMatrix(this, p)); + } + } +} + +bool ScDBQueryDataIterator::GetThis(Value& rValue) +{ + return mpData->getCurrent(rValue); +} + +bool ScDBQueryDataIterator::GetFirst(Value& rValue) +{ + return mpData->getFirst(rValue); +} + +bool ScDBQueryDataIterator::GetNext(Value& rValue) +{ + return mpData->getNext(rValue); +} + +// ============================================================================ ScCellIterator::ScCellIterator( ScDocument* pDocument, SCCOL nSCol, SCROW nSRow, SCTAB nSTab, diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index bf2ec7102..b78d11539 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -4703,6 +4703,13 @@ ULONG ScDocument::GetCellCount() const return nCellCount; } +SCSIZE ScDocument::GetCellCount(SCTAB nTab, SCCOL nCol) const +{ + if (!ValidTab(nTab) || !pTab[nTab]) + return 0; + + return pTab[nTab]->GetCellCount(nCol); +} ULONG ScDocument::GetCodeCount() const { diff --git a/sc/source/core/data/dpcachetable.cxx b/sc/source/core/data/dpcachetable.cxx index 015c6512d..e4fac9ee1 100644 --- a/sc/source/core/data/dpcachetable.cxx +++ b/sc/source/core/data/dpcachetable.cxx @@ -38,6 +38,7 @@ #include "dptabdat.hxx" #include "dptabsrc.hxx" #include "dpobject.hxx" +#include "queryparam.hxx" #include <com/sun/star/i18n/LocaleDataItem.hpp> #include <com/sun/star/sdbc/DataType.hpp> @@ -209,9 +210,39 @@ sal_Int32 ScDPCacheTable::getColSize() const return maTable.empty() ? 0 : maTable[0].size(); } +namespace { + +/** + * While the macro interpret level is incremented, the formula cells are + * (semi-)guaranteed to be interpreted. + */ +class MacroInterpretIncrementer +{ +public: + MacroInterpretIncrementer(ScDocument* pDoc) : + mpDoc(pDoc) + { + mpDoc->IncMacroInterpretLevel(); + } + ~MacroInterpretIncrementer() + { + mpDoc->DecMacroInterpretLevel(); + } +private: + ScDocument* mpDoc; +}; + +} + void ScDPCacheTable::fillTable(ScDocument* pDoc, const ScRange& rRange, const ScQueryParam& rQuery, BOOL* pSpecial, bool bIgnoreEmptyRows) { + // Make sure the formula cells within the data range are interpreted + // during this call, for this method may be called from the interpretation + // of GETPIVOTDATA, which disables nested formula interpretation without + // increasing the macro level. + MacroInterpretIncrementer aMacroInc(pDoc); + SCTAB nTab = rRange.aStart.Tab(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); diff --git a/sc/source/core/data/global2.cxx b/sc/source/core/data/global2.cxx index bf69367bf..4c2e2d3c0 100644 --- a/sc/source/core/data/global2.cxx +++ b/sc/source/core/data/global2.cxx @@ -243,238 +243,6 @@ utl::TextSearch* ScQueryEntry::GetSearchTextPtr( BOOL bCaseSens ) } //------------------------------------------------------------------------ - -ScQueryParam::ScQueryParam() -{ - nEntryCount = 0; - Clear(); -} - -//------------------------------------------------------------------------ - -ScQueryParam::ScQueryParam( const ScQueryParam& r ) : - nCol1(r.nCol1),nRow1(r.nRow1),nCol2(r.nCol2),nRow2(r.nRow2),nTab(r.nTab), - bHasHeader(r.bHasHeader), bByRow(r.bByRow), bInplace(r.bInplace), bCaseSens(r.bCaseSens), - bRegExp(r.bRegExp), bMixedComparison(r.bMixedComparison), - bDuplicate(r.bDuplicate), bDestPers(r.bDestPers), - nDestTab(r.nDestTab), nDestCol(r.nDestCol), nDestRow(r.nDestRow) -{ - nEntryCount = 0; - - Resize( r.nEntryCount ); - for (USHORT i=0; i<nEntryCount; i++) - pEntries[i] = r.pEntries[i]; -} - -//------------------------------------------------------------------------ - -ScQueryParam::~ScQueryParam() -{ - delete[] pEntries; -} - -//------------------------------------------------------------------------ - -void ScQueryParam::Clear() -{ - nCol1=nCol2=nDestCol = 0; - nRow1=nRow2=nDestRow = 0; - nDestTab = 0; - nTab = SCTAB_MAX; - bHasHeader = bCaseSens = bRegExp = bMixedComparison = FALSE; - bInplace = bByRow = bDuplicate = bDestPers = TRUE; - - Resize( MAXQUERY ); - for (USHORT i=0; i<MAXQUERY; i++) - pEntries[i].Clear(); -} - -//------------------------------------------------------------------------ - -ScQueryParam& ScQueryParam::operator=( const ScQueryParam& r ) -{ - nCol1 = r.nCol1; - nRow1 = r.nRow1; - nCol2 = r.nCol2; - nRow2 = r.nRow2; - nTab = r.nTab; - nDestTab = r.nDestTab; - nDestCol = r.nDestCol; - nDestRow = r.nDestRow; - bHasHeader = r.bHasHeader; - bInplace = r.bInplace; - bCaseSens = r.bCaseSens; - bRegExp = r.bRegExp; - bMixedComparison = r.bMixedComparison; - bDuplicate = r.bDuplicate; - bByRow = r.bByRow; - bDestPers = r.bDestPers; - - Resize( r.nEntryCount ); - for (USHORT i=0; i<nEntryCount; i++) - pEntries[i] = r.pEntries[i]; - - return *this; -} - -//------------------------------------------------------------------------ - -BOOL ScQueryParam::operator==( const ScQueryParam& rOther ) const -{ - BOOL bEqual = FALSE; - - // Anzahl der Queries gleich? - USHORT nUsed = 0; - USHORT nOtherUsed = 0; - while ( nUsed<nEntryCount && pEntries[nUsed].bDoQuery ) ++nUsed; - while ( nOtherUsed<rOther.nEntryCount && rOther.pEntries[nOtherUsed].bDoQuery ) - ++nOtherUsed; - - if ( (nUsed == nOtherUsed) - && (nCol1 == rOther.nCol1) - && (nRow1 == rOther.nRow1) - && (nCol2 == rOther.nCol2) - && (nRow2 == rOther.nRow2) - && (nTab == rOther.nTab) - && (bHasHeader == rOther.bHasHeader) - && (bByRow == rOther.bByRow) - && (bInplace == rOther.bInplace) - && (bCaseSens == rOther.bCaseSens) - && (bRegExp == rOther.bRegExp) - && (bMixedComparison == rOther.bMixedComparison) - && (bDuplicate == rOther.bDuplicate) - && (bDestPers == rOther.bDestPers) - && (nDestTab == rOther.nDestTab) - && (nDestCol == rOther.nDestCol) - && (nDestRow == rOther.nDestRow) ) - { - bEqual = TRUE; - for ( USHORT i=0; i<nUsed && bEqual; i++ ) - bEqual = pEntries[i] == rOther.pEntries[i]; - } - return bEqual; -} - -//------------------------------------------------------------------------ - -void ScQueryParam::DeleteQuery( SCSIZE nPos ) -{ - if (nPos<nEntryCount) - { - for (SCSIZE i=nPos; i+1<nEntryCount; i++) - pEntries[i] = pEntries[i+1]; - - pEntries[nEntryCount-1].Clear(); - } - else - { - DBG_ERROR("Falscher Parameter bei ScQueryParam::DeleteQuery"); - } -} - -//------------------------------------------------------------------------ - -void ScQueryParam::Resize(SCSIZE nNew) -{ - if ( nNew < MAXQUERY ) - nNew = MAXQUERY; // nie weniger als MAXQUERY - - ScQueryEntry* pNewEntries = NULL; - if ( nNew ) - pNewEntries = new ScQueryEntry[nNew]; - - SCSIZE nCopy = Min( nEntryCount, nNew ); - for (SCSIZE i=0; i<nCopy; i++) - pNewEntries[i] = pEntries[i]; - - if ( nEntryCount ) - delete[] pEntries; - nEntryCount = nNew; - pEntries = pNewEntries; -} - -//------------------------------------------------------------------------ - -void ScQueryParam::MoveToDest() -{ - if (!bInplace) - { - SCsCOL nDifX = ((SCsCOL) nDestCol) - ((SCsCOL) nCol1); - SCsROW nDifY = ((SCsROW) nDestRow) - ((SCsROW) nRow1); - SCsTAB nDifZ = ((SCsTAB) nDestTab) - ((SCsTAB) nTab); - - nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nDifX ); - nRow1 = sal::static_int_cast<SCROW>( nRow1 + nDifY ); - nCol2 = sal::static_int_cast<SCCOL>( nCol2 + nDifX ); - nRow2 = sal::static_int_cast<SCROW>( nRow2 + nDifY ); - nTab = sal::static_int_cast<SCTAB>( nTab + nDifZ ); - for (USHORT i=0; i<nEntryCount; i++) - pEntries[i].nField += nDifX; - - bInplace = TRUE; - } - else - { - DBG_ERROR("MoveToDest, bInplace == TRUE"); - } -} - -//------------------------------------------------------------------------ - -void ScQueryParam::FillInExcelSyntax(String& aCellStr, SCSIZE nIndex) -{ - if (aCellStr.Len() > 0) - { - if ( nIndex >= nEntryCount ) - Resize( nIndex+1 ); - - ScQueryEntry& rEntry = pEntries[nIndex]; - - rEntry.bDoQuery = TRUE; - // Operatoren herausfiltern - if (aCellStr.GetChar(0) == '<') - { - if (aCellStr.GetChar(1) == '>') - { - *rEntry.pStr = aCellStr.Copy(2); - rEntry.eOp = SC_NOT_EQUAL; - } - else if (aCellStr.GetChar(1) == '=') - { - *rEntry.pStr = aCellStr.Copy(2); - rEntry.eOp = SC_LESS_EQUAL; - } - else - { - *rEntry.pStr = aCellStr.Copy(1); - rEntry.eOp = SC_LESS; - } - } - else if (aCellStr.GetChar(0) == '>') - { - if (aCellStr.GetChar(1) == '=') - { - *rEntry.pStr = aCellStr.Copy(2); - rEntry.eOp = SC_GREATER_EQUAL; - } - else - { - *rEntry.pStr = aCellStr.Copy(1); - rEntry.eOp = SC_GREATER; - } - } - else - { - if (aCellStr.GetChar(0) == '=') - *rEntry.pStr = aCellStr.Copy(1); - else - *rEntry.pStr = aCellStr; - rEntry.eOp = SC_EQUAL; - } - } -} - -//------------------------------------------------------------------------ // struct ScSubTotalParam: ScSubTotalParam::ScSubTotalParam() diff --git a/sc/source/core/data/sortparam.cxx b/sc/source/core/data/sortparam.cxx index 9531c7175..dfab465d0 100644 --- a/sc/source/core/data/sortparam.cxx +++ b/sc/source/core/data/sortparam.cxx @@ -36,6 +36,7 @@ #include "sortparam.hxx" #include "global.hxx" #include "address.hxx" +#include "queryparam.hxx" #include <tools/debug.hxx> diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx index e5943d721..1525f0c62 100644 --- a/sc/source/core/data/table3.cxx +++ b/sc/source/core/data/table3.cxx @@ -60,6 +60,7 @@ #include "progress.hxx" #include "cellform.hxx" #include "postit.hxx" +#include "queryparam.hxx" #include <vector> @@ -1818,6 +1819,11 @@ BOOL ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, TypedScStrCollection& rStri return aCol[nCol].GetDataEntries( nRow, rStrings, bLimit ); } +SCSIZE ScTable::GetCellCount(SCCOL nCol) const +{ + return aCol[nCol].GetCellCount(); +} + ULONG ScTable::GetCellCount() const { ULONG nCellCount = 0; diff --git a/sc/source/core/inc/doubleref.hxx b/sc/source/core/inc/doubleref.hxx new file mode 100644 index 000000000..d79b90790 --- /dev/null +++ b/sc/source/core/inc/doubleref.hxx @@ -0,0 +1,194 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: interpre.hxx,v $ + * $Revision: 1.35.44.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_DOUBLEREF_HXX +#define SC_DOUBLEREF_HXX + +#include "address.hxx" +#include "scmatrix.hxx" + +class ScDocument; +class ScBaseCell; +struct ScDBQueryParamBase; +struct ScQueryParamBase; + +// ============================================================================ + +/** + * Base class for abstracting range data backends for database functions. + */ +class ScDBRangeBase +{ +public: + enum RefType { INTERNAL, EXTERNAL }; + + virtual ~ScDBRangeBase() = 0; + + RefType getType() const; + bool fillQueryEntries(ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef) const; + + virtual SCCOL getColSize() const = 0; + virtual SCROW getRowSize() const = 0; + virtual SCSIZE getVisibleDataCellCount() const = 0; + + /** + * Get a string value of a specified cell position. Note that the + * position of the upper left cell of the range is always (0, 0) even if + * the reference type is of internal range. + * + * @param nCol column position (0 to column size-1) + * @param nRow row position (0 to row size-1) + */ + virtual ::rtl::OUString getString(SCCOL nCol, SCROW nRow) const = 0; + + virtual SCCOL getFirstFieldColumn() const = 0; + + /** + * Get a <i>0-based</i> column index that corresponds with the passed field + * index. Note that the field index passed as the 1st parameter is + * <i>1-based.</i> + * + * @param nIndex 1-based field index. + * + * @return 0-based column index + */ + virtual SCCOL findFieldColumn(SCCOL nIndex) const = 0; + virtual SCCOL findFieldColumn(const ::rtl::OUString& rStr, sal_uInt16* pErr = NULL) const = 0; + virtual ScDBQueryParamBase* createQueryParam(const ScDBRangeBase* pQueryRef) const = 0; + virtual bool isRangeEqual(const ScRange& rRange) const = 0; + +protected: + ScDBRangeBase(ScDocument* pDoc, RefType eType); + ScDocument* getDoc() const; + + /** + * Populate query options that are always the same for all database + * queries. + */ + static void fillQueryOptions(ScQueryParamBase* pParam); + +private: + ScDBRangeBase(); // disabled + + ScDocument* mpDoc; + RefType meType; +}; + +// ============================================================================ + +class ScDBInternalRange : public ScDBRangeBase +{ +public: + explicit ScDBInternalRange(ScDocument* pDoc, const ScRange& rRange); + virtual ~ScDBInternalRange(); + + const ScRange& getRange() const; + + virtual SCCOL getColSize() const; + virtual SCROW getRowSize() const; + virtual SCSIZE getVisibleDataCellCount() const; + + /** + * Get a string value of a specified cell position. Note that the + * position of the upper left cell of the range is always (0, 0) even if + * the reference type is of internal range. + * + * @param nCol column position (0 to column size-1) + * @param nRow row position (0 to row size-1) + */ + virtual ::rtl::OUString getString(SCCOL nCol, SCROW nRow) const; + + virtual SCCOL getFirstFieldColumn() const; + /** + * Get a <i>0-based</i> column index that corresponds with the passed field + * index. Note that the field index passed as the 1st parameter is + * <i>1-based.</i> + * + * @param nIndex 1-based field index. + * + * @return 0-based column index + */ + virtual SCCOL findFieldColumn(SCCOL nIndex) const; + virtual SCCOL findFieldColumn(const ::rtl::OUString& rStr, sal_uInt16* pErr = NULL) const; + virtual ScDBQueryParamBase* createQueryParam(const ScDBRangeBase* pQueryRef) const; + virtual bool isRangeEqual(const ScRange& rRange) const; + +private: + sal_uInt16 getCellString(::rtl::OUString& rStr, ScBaseCell* pCell) const; + +private: + ScRange maRange; +}; + +// ============================================================================ + +class ScDBExternalRange : public ScDBRangeBase +{ +public: + explicit ScDBExternalRange(ScDocument* pDoc, const ScMatrixRef& pMat); + virtual ~ScDBExternalRange(); + + virtual SCCOL getColSize() const; + virtual SCROW getRowSize() const; + virtual SCSIZE getVisibleDataCellCount() const; + + /** + * Get a string value of a specified cell position. Note that the + * position of the upper left cell of the range is always (0, 0) even if + * the reference type is of internal range. + * + * @param nCol column position (0 to column size-1) + * @param nRow row position (0 to row size-1) + */ + virtual ::rtl::OUString getString(SCCOL nCol, SCROW nRow) const; + + virtual SCCOL getFirstFieldColumn() const; + + /** + * Get a <i>0-based</i> column index that corresponds with the passed field + * index. Note that the field index passed as the 1st parameter is + * <i>1-based.</i> + * + * @param nIndex 1-based field index. + * + * @return 0-based column index + */ + virtual SCCOL findFieldColumn(SCCOL nIndex) const; + virtual SCCOL findFieldColumn(const ::rtl::OUString& rStr, sal_uInt16* pErr = NULL) const; + virtual ScDBQueryParamBase* createQueryParam(const ScDBRangeBase* pQueryRef) const; + virtual bool isRangeEqual(const ScRange& rRange) const; + +private: + const ScMatrixRef mpMatrix; + SCCOL mnCols; + SCROW mnRows; +}; + +#endif diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx index 58bc46fcb..0252f1d88 100644 --- a/sc/source/core/inc/interpre.hxx +++ b/sc/source/core/inc/interpre.hxx @@ -53,7 +53,10 @@ class SbxVariable; class ScBaseCell; class ScFormulaCell; class SvNumberFormatter; +class ScDBRangeBase; struct MatrixDoubleOp; +struct ScQueryParam; +struct ScDBQueryParamBase; struct ScCompare { @@ -302,6 +305,7 @@ void DoubleRefToVars( const ScToken* p, SCCOL& rCol1, SCROW &rRow1, SCTAB& rTab1, SCCOL& rCol2, SCROW &rRow2, SCTAB& rTab2, BOOL bDontCheckForTableOp = FALSE ); +ScDBRangeBase* PopDoubleRef(); void PopDoubleRef(SCCOL& rCol1, SCROW &rRow1, SCTAB& rTab1, SCCOL& rCol2, SCROW &rRow2, SCTAB& rTab2, BOOL bDontCheckForTableOp = FALSE ); @@ -491,7 +495,7 @@ void ScSubTotal(); // compatibility). If this was the case then rMissingField is set to TRUE upon // return. If rMissingField==FALSE upon call all "missing cases" are considered // to be an error. -BOOL GetDBParams( SCTAB& rTab, ScQueryParam& rParam, BOOL& rMissingField ); +ScDBQueryParamBase* GetDBParams( BOOL& rMissingField ); void DBIterator( ScIterFunc ); void ScDBSum(); diff --git a/sc/source/core/tool/dbcolect.cxx b/sc/source/core/tool/dbcolect.cxx index e1e3870b4..a47a669a9 100644 --- a/sc/source/core/tool/dbcolect.cxx +++ b/sc/source/core/tool/dbcolect.cxx @@ -40,6 +40,7 @@ #include "refupdat.hxx" #include "rechead.hxx" #include "document.hxx" +#include "queryparam.hxx" #include "globstr.hrc" diff --git a/sc/source/core/tool/doubleref.cxx b/sc/source/core/tool/doubleref.cxx new file mode 100644 index 000000000..01528db9f --- /dev/null +++ b/sc/source/core/tool/doubleref.cxx @@ -0,0 +1,568 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: interpre.hxx,v $ + * $Revision: 1.35.44.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +// INCLUDE --------------------------------------------------------------- + +#include "doubleref.hxx" +#include "cell.hxx" +#include "global.hxx" +#include "document.hxx" +#include "queryparam.hxx" +#include "globstr.hrc" + +#include <memory> +#include <vector> + +using ::rtl::OUString; +using ::std::auto_ptr; +using ::std::vector; + +namespace { + +void lcl_toUpper(OUString& rStr) +{ + rStr = ScGlobal::pCharClass->toUpper(rStr.trim(), 0, static_cast<xub_StrLen>(rStr.getLength())); +} + +bool lcl_createStarQuery(ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef) +{ + // A valid StarQuery must be at least 4 columns wide. To be precise it + // should be exactly 4 columns ... + // Additionally, if this wasn't checked, a formula pointing to a valid 1-3 + // column Excel style query range immediately left to itself would result + // in a circular reference when the field name or operator or value (first + // to third query range column) is obtained (#i58354#). Furthermore, if the + // range wasn't sufficiently specified data changes wouldn't flag formula + // cells for recalculation. + + if (pQueryRef->getColSize() < 4) + return false; + + BOOL bValid; + BOOL bFound; + OUString aCellStr; + SCSIZE nIndex = 0; + SCROW nRow = 0; + SCROW nRows = pDBRef->getRowSize(); + SCSIZE nNewEntries = static_cast<SCSIZE>(nRows); + pParam->Resize(nNewEntries); + + do + { + ScQueryEntry& rEntry = pParam->GetEntry(nIndex); + + bValid = FALSE; + + if (nIndex > 0) + { + // For all entries after the first one, check the and/or connector in the first column. + aCellStr = pQueryRef->getString(0, nRow); + lcl_toUpper(aCellStr); + if ( aCellStr.equals(ScGlobal::GetRscString(STR_TABLE_UND)) ) + { + rEntry.eConnect = SC_AND; + bValid = TRUE; + } + else if ( aCellStr.equals(ScGlobal::GetRscString(STR_TABLE_ODER)) ) + { + rEntry.eConnect = SC_OR; + bValid = TRUE; + } + } + + if ((nIndex < 1) || bValid) + { + // field name in the 2nd column. + bFound = FALSE; + aCellStr = pQueryRef->getString(1, nRow); + SCCOL nField = pDBRef->findFieldColumn(aCellStr); // TODO: must be case insensitive comparison. + if (ValidCol(nField)) + { + rEntry.nField = nField; + bValid = true; + } + else + bValid = false; + } + + if (bValid) + { + // equality, non-equality operator in the 3rd column. + bFound = FALSE; + aCellStr = pQueryRef->getString(2, nRow); + lcl_toUpper(aCellStr); + const sal_Unicode* p = aCellStr.getStr(); + if (p[0] == sal_Unicode('<')) + { + if (p[1] == sal_Unicode('>')) + rEntry.eOp = SC_NOT_EQUAL; + else if (p[1] == sal_Unicode('=')) + rEntry.eOp = SC_LESS_EQUAL; + else + rEntry.eOp = SC_LESS; + } + else if (p[0] == sal_Unicode('>')) + { + if (p[1] == sal_Unicode('=')) + rEntry.eOp = SC_GREATER_EQUAL; + else + rEntry.eOp = SC_GREATER; + } + else if (p[0] == sal_Unicode('=')) + rEntry.eOp = SC_EQUAL; + + } + + if (bValid) + { + // Finally, the right-hand-side value in the 4th column. + *rEntry.pStr = pQueryRef->getString(3, nRow); + rEntry.bDoQuery = TRUE; + } + nIndex++; + nRow++; + } + while (bValid && (nRow < nRows) /* && (nIndex < MAXQUERY) */ ); + return bValid; +} + +bool lcl_createExcelQuery( + ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef) +{ + bool bValid = true; + SCCOL nCols = pQueryRef->getColSize(); + SCROW nRows = pQueryRef->getRowSize(); + vector<SCCOL> aFields(nCols); + SCCOL nCol = 0; + while (bValid && (nCol < nCols)) + { + OUString aQueryStr = pQueryRef->getString(nCol, 0); + SCCOL nField = pDBRef->findFieldColumn(aQueryStr); + if (ValidCol(nField)) + aFields[nCol] = nField; + else + bValid = false; + ++nCol; + } + + if (bValid) + { +// ULONG nVisible = 0; +// for ( nCol=nCol1; nCol<=nCol2; nCol++ ) +// nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 ); + + // Count the number of visible cells (excluding the header row). Each + // visible cell corresponds with a single query. + SCSIZE nVisible = pQueryRef->getVisibleDataCellCount(); + if ( nVisible > SCSIZE_MAX / sizeof(void*) ) + { + DBG_ERROR("zu viele Filterkritierien"); + nVisible = 0; + } + + SCSIZE nNewEntries = nVisible; + pParam->Resize( nNewEntries ); + + SCSIZE nIndex = 0; + SCROW nRow = 1; + String aCellStr; + while (nRow < nRows) + { + nCol = 0; + while (nCol < nCols) + { + aCellStr = pQueryRef->getString(nCol, nRow); + ScGlobal::pCharClass->toUpper( aCellStr ); + if (aCellStr.Len() > 0) + { + if (nIndex < nNewEntries) + { + pParam->GetEntry(nIndex).nField = aFields[nCol]; + pParam->FillInExcelSyntax(aCellStr, nIndex); + nIndex++; + if (nIndex < nNewEntries) + pParam->GetEntry(nIndex).eConnect = SC_AND; + } + else + bValid = FALSE; + } + nCol++; + } + nRow++; + if (nIndex < nNewEntries) + pParam->GetEntry(nIndex).eConnect = SC_OR; + } + } + return bValid; +} + +bool lcl_fillQueryEntries( + ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef, const ScDBRangeBase* pQueryRef) +{ + SCSIZE nCount = pParam->GetEntryCount(); + for (SCSIZE i = 0; i < nCount; ++i) + pParam->GetEntry(i).Clear(); + + // Standard QueryTabelle + bool bValid = lcl_createStarQuery(pParam, pDBRef, pQueryRef); + // Excel QueryTabelle + if (!bValid) + bValid = lcl_createExcelQuery(pParam, pDBRef, pQueryRef); + + nCount = pParam->GetEntryCount(); + if (bValid) + { + // bQueryByString muss gesetzt sein + for (SCSIZE i = 0; i < nCount; ++i) + pParam->GetEntry(i).bQueryByString = true; + } + else + { + // nix + for (SCSIZE i = 0; i < nCount; ++i) + pParam->GetEntry(i).Clear(); + } + return bValid; +} + +} + +// ============================================================================ + +ScDBRangeBase::ScDBRangeBase(ScDocument* pDoc, RefType eType) : + mpDoc(pDoc), meType(eType) +{ +} + +ScDBRangeBase::~ScDBRangeBase() +{ +} + +ScDBRangeBase::RefType ScDBRangeBase::getType() const +{ + return meType; +} + +bool ScDBRangeBase::fillQueryEntries(ScQueryParamBase* pParam, const ScDBRangeBase* pDBRef) const +{ + if (!pDBRef) + return false; + + return lcl_fillQueryEntries(pParam, pDBRef, this); +} + +void ScDBRangeBase::fillQueryOptions(ScQueryParamBase* pParam) +{ + pParam->bHasHeader = true; + pParam->bByRow = true; + pParam->bInplace = true; + pParam->bCaseSens = false; + pParam->bRegExp = false; + pParam->bDuplicate = true; + pParam->bMixedComparison = false; +} + +ScDocument* ScDBRangeBase::getDoc() const +{ + return mpDoc; +} + +// ============================================================================ + +ScDBInternalRange::ScDBInternalRange(ScDocument* pDoc, const ScRange& rRange) : + ScDBRangeBase(pDoc, INTERNAL), maRange(rRange) +{ +} + +ScDBInternalRange::~ScDBInternalRange() +{ +} + +const ScRange& ScDBInternalRange::getRange() const +{ + return maRange; +} + +SCCOL ScDBInternalRange::getColSize() const +{ + return maRange.aEnd.Col() - maRange.aStart.Col() + 1; +} + +SCROW ScDBInternalRange::getRowSize() const +{ + return maRange.aEnd.Row() - maRange.aStart.Row() + 1; +} + +SCSIZE ScDBInternalRange::getVisibleDataCellCount() const +{ + SCCOL nCols = getColSize(); + SCROW nRows = getRowSize(); + if (nRows <= 1) + return 0; + + return (nRows-1)*nCols; +} + +OUString ScDBInternalRange::getString(SCCOL nCol, SCROW nRow) const +{ + String aStr; + const ScAddress& s = maRange.aStart; + getDoc()->GetString(s.Col() + nCol, s.Row() + nRow, maRange.aStart.Tab(), aStr); + return aStr; +} + +SCCOL ScDBInternalRange::getFirstFieldColumn() const +{ + return getRange().aStart.Col(); +} + +SCCOL ScDBInternalRange::findFieldColumn(SCCOL nIndex) const +{ + const ScRange& rRange = getRange(); + const ScAddress& s = rRange.aStart; + const ScAddress& e = rRange.aEnd; + + SCCOL nDBCol1 = s.Col(); + SCCOL nDBCol2 = e.Col(); + + if ( nIndex <= 0 || nIndex > (nDBCol2 - nDBCol1 + 1) ) + return nDBCol1; + + return Min(nDBCol2, static_cast<SCCOL>(nDBCol1 + nIndex - 1)); +} + +sal_uInt16 ScDBInternalRange::getCellString(OUString& rStr, ScBaseCell* pCell) const +{ + sal_uInt16 nErr = 0; + String aStr; + if (pCell) + { + SvNumberFormatter* pFormatter = getDoc()->GetFormatTable(); + switch (pCell->GetCellType()) + { + case CELLTYPE_STRING: + ((ScStringCell*) pCell)->GetString(aStr); + break; + case CELLTYPE_EDIT: + ((ScEditCell*) pCell)->GetString(aStr); + break; + case CELLTYPE_FORMULA: + { + ScFormulaCell* pFCell = (ScFormulaCell*) pCell; + nErr = pFCell->GetErrCode(); + if (pFCell->IsValue()) + { + double fVal = pFCell->GetValue(); + ULONG nIndex = pFormatter->GetStandardFormat( + NUMBERFORMAT_NUMBER, + ScGlobal::eLnge); + pFormatter->GetInputLineString(fVal, nIndex, aStr); + } + else + pFCell->GetString(aStr); + } + break; + case CELLTYPE_VALUE: + { + double fVal = ((ScValueCell*) pCell)->GetValue(); + ULONG nIndex = pFormatter->GetStandardFormat( + NUMBERFORMAT_NUMBER, + ScGlobal::eLnge); + pFormatter->GetInputLineString(fVal, nIndex, aStr); + } + break; + default: + ; + } + } + rStr = aStr; + return nErr; +} + +SCCOL ScDBInternalRange::findFieldColumn(const OUString& rStr, sal_uInt16* pErr) const +{ + const ScAddress& s = maRange.aStart; + const ScAddress& e = maRange.aEnd; + OUString aUpper = rStr; + lcl_toUpper(aUpper); + + SCCOL nDBCol1 = s.Col(); + SCROW nDBRow1 = s.Row(); + SCTAB nDBTab1 = s.Tab(); + SCCOL nDBCol2 = e.Col(); + + SCCOL nField = nDBCol1; + BOOL bFound = TRUE; + + bFound = FALSE; + OUString aCellStr; + ScAddress aLook( nDBCol1, nDBRow1, nDBTab1 ); + while (!bFound && (aLook.Col() <= nDBCol2)) + { + ScBaseCell* pCell = getDoc()->GetCell( aLook ); + sal_uInt16 nErr = getCellString( aCellStr, pCell ); + if (pErr) + *pErr = nErr; + lcl_toUpper(aCellStr); + bFound = ScGlobal::GetpTransliteration()->isEqual(aCellStr, aUpper); + if (!bFound) + aLook.IncCol(); + } + nField = aLook.Col(); + + return bFound ? nField : -1; +} + +ScDBQueryParamBase* ScDBInternalRange::createQueryParam(const ScDBRangeBase* pQueryRef) const +{ + auto_ptr<ScDBQueryParamInternal> pParam(new ScDBQueryParamInternal); + + // Set the database range first. + const ScAddress& s = maRange.aStart; + const ScAddress& e = maRange.aEnd; + pParam->nCol1 = s.Col(); + pParam->nRow1 = s.Row(); + pParam->nCol2 = e.Col(); + pParam->nRow2 = e.Row(); + pParam->nTab = s.Tab(); + + fillQueryOptions(pParam.get()); + + // Now construct the query entries from the query range. + if (!pQueryRef->fillQueryEntries(pParam.get(), this)) + return NULL; + + return pParam.release(); +} + +bool ScDBInternalRange::isRangeEqual(const ScRange& rRange) const +{ + return maRange == rRange; +} + +// ============================================================================ + +ScDBExternalRange::ScDBExternalRange(ScDocument* pDoc, const ScMatrixRef& pMat) : + ScDBRangeBase(pDoc, EXTERNAL), mpMatrix(pMat) +{ + SCSIZE nC, nR; + mpMatrix->GetDimensions(nC, nR); + mnCols = static_cast<SCCOL>(nC); + mnRows = static_cast<SCROW>(nR); +} + +ScDBExternalRange::~ScDBExternalRange() +{ +} + +SCCOL ScDBExternalRange::getColSize() const +{ + return mnCols; +} + +SCROW ScDBExternalRange::getRowSize() const +{ + return mnRows; +} + +SCSIZE ScDBExternalRange::getVisibleDataCellCount() const +{ + SCCOL nCols = getColSize(); + SCROW nRows = getRowSize(); + if (nRows <= 1) + return 0; + + return (nRows-1)*nCols; +} + +OUString ScDBExternalRange::getString(SCCOL nCol, SCROW nRow) const +{ + if (nCol >= mnCols || nRow >= mnRows) + return OUString(); + + return mpMatrix->GetString(nCol, nRow); +} + +SCCOL ScDBExternalRange::getFirstFieldColumn() const +{ + return 0; +} + +SCCOL ScDBExternalRange::findFieldColumn(SCCOL nIndex) const +{ + if (nIndex < 1) + // 1st field + return 0; + + if (nIndex > mnCols) + // last field + return mnCols - 1; + + return nIndex - 1; +} + +SCCOL ScDBExternalRange::findFieldColumn(const OUString& rStr, sal_uInt16* pErr) const +{ + if (pErr) + pErr = 0; + + OUString aUpper = rStr; + lcl_toUpper(aUpper); + for (SCCOL i = 0; i < mnCols; ++i) + { + OUString aUpperVal = mpMatrix->GetString(i, 0); + lcl_toUpper(aUpperVal); + if (aUpper.equals(aUpperVal)) + return i; + } + return -1; +} + +ScDBQueryParamBase* ScDBExternalRange::createQueryParam(const ScDBRangeBase* pQueryRef) const +{ + auto_ptr<ScDBQueryParamMatrix> pParam(new ScDBQueryParamMatrix); + pParam->mpMatrix = mpMatrix; + fillQueryOptions(pParam.get()); + + // Now construct the query entries from the query range. + if (!pQueryRef->fillQueryEntries(pParam.get(), this)) + return NULL; + + return pParam.release(); +} + +bool ScDBExternalRange::isRangeEqual(const ScRange& /*rRange*/) const +{ + return false; +} + diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index 68fbcccfc..aee4743a0 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -68,11 +68,14 @@ #include <string.h> #include <math.h> #include <vector> +#include <memory> #include "cellkeytranslator.hxx" #include "lookupcache.hxx" #include "rangenam.hxx" #include "compiler.hxx" #include "externalrefmgr.hxx" +#include "doubleref.hxx" +#include "queryparam.hxx" #define SC_DOUBLE_MAXVALUE 1.7e307 @@ -83,6 +86,8 @@ ScTokenStack* ScInterpreter::pGlobalStack = NULL; BOOL ScInterpreter::bGlobalStackInUse = FALSE; using namespace formula; +using ::std::auto_ptr; + //----------------------------------------------------------------------------- // Funktionen //----------------------------------------------------------------------------- @@ -5828,11 +5833,9 @@ void ScInterpreter::ScSubTotal() #endif -BOOL ScInterpreter::GetDBParams(SCTAB& rTab, ScQueryParam& rParam, - BOOL& rMissingField ) +ScDBQueryParamBase* ScInterpreter::GetDBParams( BOOL& rMissingField ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDBParams" ); - BOOL bRet = FALSE; BOOL bAllowMissingField = FALSE; if ( rMissingField ) { @@ -5841,14 +5844,10 @@ BOOL ScInterpreter::GetDBParams(SCTAB& rTab, ScQueryParam& rParam, } if ( GetByte() == 3 ) { - - SCCOL nQCol1; - SCROW nQRow1; - SCTAB nQTab1; - SCCOL nQCol2; - SCROW nQRow2; - SCTAB nQTab2; - PopDoubleRef(nQCol1, nQRow1, nQTab1, nQCol2, nQRow2, nQTab2); + // First, get the query criteria range. + ::std::auto_ptr<ScDBRangeBase> pQueryRef( PopDoubleRef() ); + if (!pQueryRef.get()) + return NULL; BOOL bByVal = TRUE; double nVal = 0.0; @@ -5904,116 +5903,85 @@ BOOL ScInterpreter::GetDBParams(SCTAB& rTab, ScQueryParam& rParam, SetError( errIllegalParameter ); } - SCCOL nDBCol1; - SCROW nDBRow1; - SCTAB nDBTab1; - SCCOL nDBCol2; - SCROW nDBRow2; - SCTAB nDBTab2; - PopDoubleRef(nDBCol1, nDBRow1, nDBTab1, nDBCol2, nDBRow2, nDBTab2); + auto_ptr<ScDBRangeBase> pDBRef( PopDoubleRef() ); - if ( nGlobalError == 0 && bRangeFake ) + if (nGlobalError || !pDBRef.get()) + return NULL; + + if ( bRangeFake ) { // range parameter must match entire database range - if ( aMissingRange == ScRange( nDBCol1, nDBRow1, nDBTab1, nDBCol2, - nDBRow2, nDBTab2) ) + if (pDBRef->isRangeEqual(aMissingRange)) rMissingField = TRUE; else SetError( errIllegalParameter ); } - if (nGlobalError == 0) + if (nGlobalError) + return NULL; + + SCCOL nField = pDBRef->getFirstFieldColumn(); + if (rMissingField) + ; // special case + else if (bByVal) + nField = pDBRef->findFieldColumn(static_cast<SCCOL>(nVal)); + else + { + sal_uInt16 nErr = 0; + nField = pDBRef->findFieldColumn(aStr, &nErr); + SetError(nErr); + } + + if (!ValidCol(nField)) + return NULL; + + auto_ptr<ScDBQueryParamBase> pParam( pDBRef->createQueryParam(pQueryRef.get()) ); + + if (pParam.get()) { - SCCOL nField = nDBCol1; - BOOL bFound = TRUE; + // An allowed missing field parameter sets the result field + // to any of the query fields, just to be able to return + // some cell from the iterator. if ( rMissingField ) - ; // special case - else if ( bByVal ) - { - if ( nVal <= 0 || nVal > (nDBCol2 - nDBCol1 + 1) ) - bFound = FALSE; - else - nField = Min(nDBCol2, (SCCOL)(nDBCol1 + (SCCOL)nVal - 1)); - } - else + nField = static_cast<SCCOL>(pParam->GetEntry(0).nField); + pParam->mnField = nField; + + SCSIZE nCount = pParam->GetEntryCount(); + for ( SCSIZE i=0; i < nCount; i++ ) { - bFound = FALSE; - String aCellStr; - ScAddress aLook( nDBCol1, nDBRow1, nDBTab1 ); - while (!bFound && (aLook.Col() <= nDBCol2)) - { - ScBaseCell* pCell = GetCell( aLook ); - GetCellString( aCellStr, pCell ); - bFound = ScGlobal::GetpTransliteration()->isEqual( aCellStr, aStr ); - if (!bFound) - aLook.IncCol(); - } - nField = aLook.Col(); - } - if (bFound) - { - rParam.nCol1 = nDBCol1; - rParam.nRow1 = nDBRow1; - rParam.nCol2 = nDBCol2; - rParam.nRow2 = nDBRow2; - rParam.nTab = nDBTab1; - rParam.bHasHeader = TRUE; - rParam.bByRow = TRUE; - rParam.bInplace = TRUE; - rParam.bCaseSens = FALSE; - rParam.bRegExp = FALSE; - rParam.bDuplicate = TRUE; - if (pDok->CreateQueryParam(nQCol1, nQRow1, nQCol2, nQRow2, nQTab1, rParam)) - { - // An allowed missing field parameter sets the result field - // to any of the query fields, just to be able to return - // some cell from the iterator. - if ( rMissingField ) - nField = static_cast<SCCOL>(rParam.GetEntry(0).nField); - - rParam.nCol1 = nField; - rParam.nCol2 = nField; - rTab = nDBTab1; - bRet = TRUE; - SCSIZE nCount = rParam.GetEntryCount(); - for ( SCSIZE i=0; i < nCount; i++ ) - { - ScQueryEntry& rEntry = rParam.GetEntry(i); - if ( rEntry.bDoQuery ) - { - sal_uInt32 nIndex = 0; - rEntry.bQueryByString = !pFormatter->IsNumberFormat( - *rEntry.pStr, nIndex, rEntry.nVal ); - if ( rEntry.bQueryByString && !rParam.bRegExp ) - rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok ); - } - else - break; // for - } + ScQueryEntry& rEntry = pParam->GetEntry(i); + if ( rEntry.bDoQuery ) + { + sal_uInt32 nIndex = 0; + rEntry.bQueryByString = !pFormatter->IsNumberFormat( + *rEntry.pStr, nIndex, rEntry.nVal ); + if ( rEntry.bQueryByString && !pParam->bRegExp ) + pParam->bRegExp = MayBeRegExp( *rEntry.pStr, pDok ); } + else + break; // for } + return pParam.release(); } } - return bRet; + return false; } void ScInterpreter::DBIterator( ScIterFunc eFunc ) { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::DBIterator" ); - SCTAB nTab1; double nErg = 0.0; double fMem = 0.0; BOOL bNull = TRUE; ULONG nCount = 0; - ScQueryParam aQueryParam; BOOL bMissingField = FALSE; - if ( GetDBParams( nTab1, aQueryParam, bMissingField) ) + auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) ); + if (pQueryParam.get()) { - double nVal; - USHORT nErr; - ScQueryValueIterator aValIter(pDok, nTab1, aQueryParam); - if ( aValIter.GetFirst(nVal, nErr) && !nErr ) + ScDBQueryDataIterator aValIter(pDok, pQueryParam.release()); + ScDBQueryDataIterator::Value aValue; + if ( aValIter.GetFirst(aValue) && !aValue.mnError ) { switch( eFunc ) { @@ -6029,24 +5997,24 @@ void ScInterpreter::DBIterator( ScIterFunc eFunc ) { case ifAVERAGE: case ifSUM: - if ( bNull && nVal != 0.0 ) + if ( bNull && aValue.mfValue != 0.0 ) { bNull = FALSE; - fMem = nVal; + fMem = aValue.mfValue; } else - nErg += nVal; + nErg += aValue.mfValue; break; - case ifSUMSQ: nErg += nVal * nVal; break; - case ifPRODUCT: nErg *= nVal; break; - case ifMAX: if( nVal > nErg ) nErg = nVal; break; - case ifMIN: if( nVal < nErg ) nErg = nVal; break; + case ifSUMSQ: nErg += aValue.mfValue * aValue.mfValue; break; + case ifPRODUCT: nErg *= aValue.mfValue; break; + case ifMAX: if( aValue.mfValue > nErg ) nErg = aValue.mfValue; break; + case ifMIN: if( aValue.mfValue < nErg ) nErg = aValue.mfValue; break; default: ; // nothing } } - while ( aValIter.GetNext(nVal, nErr) && !nErr ); + while ( aValIter.GetNext(aValue) && !aValue.mnError ); } - SetError(nErr); + SetError(aValue.mnError); } else SetError( errIllegalParameter); @@ -6071,13 +6039,12 @@ void ScInterpreter::ScDBSum() void ScInterpreter::ScDBCount() { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBCount" ); - SCTAB nTab; - ScQueryParam aQueryParam; BOOL bMissingField = TRUE; - if ( GetDBParams( nTab, aQueryParam, bMissingField) ) + auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) ); + if (pQueryParam.get()) { ULONG nCount = 0; - if ( bMissingField ) + if ( bMissingField && pQueryParam->GetType() == ScDBQueryParamBase::INTERNAL ) { // count all matching records // TODO: currently the QueryIterators only return cell pointers of // existing cells, so if a query matches an empty cell there's @@ -6087,7 +6054,9 @@ void ScInterpreter::ScDBCount() // have to live with it until we reimplement the iterators to also // return empty cells, which would mean to adapt all callers of // iterators. - ScQueryCellIterator aCellIter( pDok, nTab, aQueryParam); + ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pQueryParam.get()); + SCTAB nTab = p->nTab; + ScQueryCellIterator aCellIter( pDok, nTab, *p); if ( aCellIter.GetFirst() ) { do @@ -6098,17 +6067,17 @@ void ScInterpreter::ScDBCount() } else { // count only matching records with a value in the "result" field - double nVal; - USHORT nErr = 0; - ScQueryValueIterator aValIter( pDok, nTab, aQueryParam); - if ( aValIter.GetFirst( nVal, nErr) && !nErr ) + ScDBQueryDataIterator aValIter( pDok, pQueryParam.release()); + ScDBQueryDataIterator::Value aValue; + if ( aValIter.GetFirst(aValue) && !aValue.mnError ) { do { nCount++; - } while ( aValIter.GetNext( nVal, nErr) && !nErr ); + } + while ( aValIter.GetNext(aValue) && !aValue.mnError ); } - SetError( nErr ); + SetError(aValue.mnError); } PushDouble( nCount ); } @@ -6120,21 +6089,24 @@ void ScInterpreter::ScDBCount() void ScInterpreter::ScDBCount2() { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBCount2" ); - SCTAB nTab; - ScQueryParam aQueryParam; BOOL bMissingField = TRUE; - if (GetDBParams( nTab, aQueryParam, bMissingField)) + auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) ); + if (pQueryParam.get()) { ULONG nCount = 0; - ScQueryCellIterator aCellIter(pDok, nTab, aQueryParam); - if ( aCellIter.GetFirst() ) + pQueryParam->mbSkipString = false; + ScDBQueryDataIterator aValIter( pDok, pQueryParam.release()); + ScDBQueryDataIterator::Value aValue; + if ( aValIter.GetFirst(aValue) && !aValue.mnError ) { do { nCount++; - } while ( aCellIter.GetNext() ); + } + while ( aValIter.GetNext(aValue) && !aValue.mnError ); } - PushDouble(nCount); + SetError(aValue.mnError); + PushDouble( nCount ); } else PushIllegalParameter(); @@ -6178,25 +6150,23 @@ void ScInterpreter::GetDBStVarParams( double& rVal, double& rValCount ) rValCount = 0.0; double fSum = 0.0; - SCTAB nTab; - ScQueryParam aQueryParam; BOOL bMissingField = FALSE; - if (GetDBParams( nTab, aQueryParam, bMissingField)) + auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) ); + if (pQueryParam.get()) { - double fVal; - USHORT nErr; - ScQueryValueIterator aValIter(pDok, nTab, aQueryParam); - if (aValIter.GetFirst(fVal, nErr) && !nErr) + ScDBQueryDataIterator aValIter(pDok, pQueryParam.release()); + ScDBQueryDataIterator::Value aValue; + if (aValIter.GetFirst(aValue) && !aValue.mnError) { do { rValCount++; - values.push_back(fVal); - fSum += fVal; + values.push_back(aValue.mfValue); + fSum += aValue.mfValue; } - while ((nErr == 0) && aValIter.GetNext(fVal, nErr)); + while ((aValue.mnError == 0) && aValIter.GetNext(aValue)); } - SetError(nErr); + SetError(aValue.mnError); } else SetError( errIllegalParameter); diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index 594e234c1..909ba0413 100755 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -68,15 +68,18 @@ #include "jumpmatrix.hxx" #include "parclass.hxx" #include "externalrefmgr.hxx" +#include "doubleref.hxx" #include <math.h> #include <float.h> #include <map> #include <algorithm> #include <functional> +#include <memory> using namespace com::sun::star; using namespace formula; +using ::std::auto_ptr; #define ADDIN_MAXSTRLEN 256 @@ -1222,6 +1225,42 @@ void ScInterpreter::DoubleRefToVars( const ScToken* p, } } +ScDBRangeBase* ScInterpreter::PopDoubleRef() +{ + if (!sp) + { + SetError(errUnknownStackVariable); + return NULL; + } + + --sp; + FormulaToken* p = pStack[sp]; + switch (p->GetType()) + { + case svError: + nGlobalError = p->GetError(); + break; + case svDoubleRef: + { + SCCOL nCol1, nCol2; + SCROW nRow1, nRow2; + SCTAB nTab1, nTab2; + DoubleRefToVars(static_cast<ScToken*>(p), + nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, false); + + return new ScDBInternalRange(pDok, + ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2)); + } + case svMatrix: + { + ScMatrixRef pMat = static_cast<ScToken*>(p)->GetMatrix(); + return new ScDBExternalRange(pDok, pMat); + } + default: + SetError( errIllegalParameter); + } + return NULL; +} void ScInterpreter::PopDoubleRef(SCCOL& rCol1, SCROW &rRow1, SCTAB& rTab1, SCCOL& rCol2, SCROW &rRow2, SCTAB& rTab2, @@ -2055,78 +2094,37 @@ ScMatValType ScInterpreter::GetDoubleOrStringFromMatrix( double& rDouble, void ScInterpreter::ScDBGet() { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBGet" ); - SCTAB nTab; - ScQueryParam aQueryParam; BOOL bMissingField = FALSE; - if (GetDBParams( nTab, aQueryParam, bMissingField)) + auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) ); + if (!pQueryParam.get()) { - ScBaseCell* pCell; - ScQueryCellIterator aCellIter(pDok, nTab, aQueryParam); - if ( (pCell = aCellIter.GetFirst()) != NULL ) - { - if (aCellIter.GetNext()) - PushIllegalArgument(); - else - { - switch (pCell->GetCellType()) - { - case CELLTYPE_VALUE: - { - double rValue = ((ScValueCell*)pCell)->GetValue(); - if ( bCalcAsShown ) - { - ULONG nFormat; - nFormat = aCellIter.GetNumberFormat(); - rValue = pDok->RoundValueAsShown( rValue, nFormat ); - } - PushDouble(rValue); - } - break; - case CELLTYPE_STRING: - { - String rString; - ((ScStringCell*)pCell)->GetString(rString); - PushString(rString); - } - break; - case CELLTYPE_EDIT: - { - String rString; - ((ScEditCell*)pCell)->GetString(rString); - PushString(rString); - } - break; - case CELLTYPE_FORMULA: - { - USHORT rErr = ((ScFormulaCell*)pCell)->GetErrCode(); - if (rErr) - PushError(rErr); - else if (((ScFormulaCell*)pCell)->IsValue()) - { - double rValue = ((ScFormulaCell*)pCell)->GetValue(); - PushDouble(rValue); - } - else - { - String rString; - ((ScFormulaCell*)pCell)->GetString(rString); - PushString(rString); - } - } - break; - case CELLTYPE_NONE: - case CELLTYPE_NOTE: - default: - PushIllegalArgument(); - break; - } - } - } - else - PushNoValue(); + // Failed to create query param. + PushIllegalParameter(); + return; } + + pQueryParam->mbSkipString = false; + ScDBQueryDataIterator aValIter(pDok, pQueryParam.release()); + ScDBQueryDataIterator::Value aValue; + if (!aValIter.GetFirst(aValue) || aValue.mnError) + { + // No match found. + PushNoValue(); + return; + } + + ScDBQueryDataIterator::Value aValNext; + if (aValIter.GetNext(aValNext) && !aValNext.mnError) + { + // There should be only one unique match. + PushIllegalArgument(); + return; + } + + if (aValue.mbIsNumber) + PushDouble(aValue.mfValue); else - PushIllegalParameter(); + PushString(aValue.maString); } diff --git a/sc/source/core/tool/makefile.mk b/sc/source/core/tool/makefile.mk index 52d9bad7c..f3fe479e3 100644 --- a/sc/source/core/tool/makefile.mk +++ b/sc/source/core/tool/makefile.mk @@ -76,6 +76,7 @@ SLOFILES = \ $(SLO)$/detdata.obj \ $(SLO)$/detfunc.obj \ $(SLO)$/docoptio.obj \ + $(SLO)$/doubleref.obj \ $(SLO)$/editutil.obj \ $(SLO)$/filtopt.obj \ $(SLO)$/formulaparserpool.obj \ @@ -95,6 +96,7 @@ SLOFILES = \ $(SLO)$/printopt.obj \ $(SLO)$/prnsave.obj \ $(SLO)$/progress.obj \ + $(SLO)$/queryparam.obj \ $(SLO)$/rangelst.obj \ $(SLO)$/rangenam.obj \ $(SLO)$/rangeseq.obj \ @@ -122,6 +124,7 @@ EXCEPTIONSFILES= \ $(SLO)$/chartlock.obj \ $(SLO)$/chgtrack.obj \ $(SLO)$/compiler.obj \ + $(SLO)$/doubleref.obj \ $(SLO)$/formulaparserpool.obj \ $(SLO)$/interpr1.obj \ $(SLO)$/interpr2.obj \ @@ -130,6 +133,7 @@ EXCEPTIONSFILES= \ $(SLO)$/interpr5.obj \ $(SLO)$/lookupcache.obj \ $(SLO)$/prnsave.obj \ + $(SLO)$/queryparam.obj \ $(SLO)$/reftokenhelper.obj \ $(SLO)$/token.obj diff --git a/sc/source/core/tool/queryparam.cxx b/sc/source/core/tool/queryparam.cxx new file mode 100644 index 000000000..b97558df1 --- /dev/null +++ b/sc/source/core/tool/queryparam.cxx @@ -0,0 +1,365 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: interpr4.cxx,v $ + * $Revision: 1.57.92.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +// INCLUDE --------------------------------------------------------------- + +#include "queryparam.hxx" + +using ::std::vector; + +// ============================================================================ + +ScQueryParamBase::ScQueryParamBase() +{ + Resize( MAXQUERY ); + for (USHORT i=0; i<MAXQUERY; i++) + maEntries[i].Clear(); +} + +ScQueryParamBase::ScQueryParamBase(const ScQueryParamBase& r) : + bHasHeader(r.bHasHeader), bByRow(r.bByRow), bInplace(r.bInplace), bCaseSens(r.bCaseSens), + bRegExp(r.bRegExp), bDuplicate(r.bDuplicate), bMixedComparison(r.bMixedComparison), + maEntries(r.maEntries) +{ +} + +ScQueryParamBase::~ScQueryParamBase() +{ +} + +SCSIZE ScQueryParamBase::GetEntryCount() const +{ + return maEntries.size(); +} + +ScQueryEntry& ScQueryParamBase::GetEntry(SCSIZE n) const +{ + return maEntries[n]; +} + +void ScQueryParamBase::Resize(SCSIZE nNew) +{ + if ( nNew < MAXQUERY ) + nNew = MAXQUERY; // nie weniger als MAXQUERY + + vector<ScQueryEntry> aNewEntries(nNew); + SCSIZE nCopy = ::std::min(maEntries.size(), nNew); + for (SCSIZE i=0; i<nCopy; i++) + aNewEntries[i] = maEntries[i]; + + maEntries.swap(aNewEntries); +} + +void ScQueryParamBase::DeleteQuery( SCSIZE nPos ) +{ + if (nPos >= maEntries.size()) + return; + + size_t n = maEntries.size(); + vector<ScQueryEntry> aNewEntries; + aNewEntries.reserve(n); + for (size_t i = 0; i < n; ++i) + if (i != nPos) + aNewEntries.push_back(maEntries[i]); + + // Don't forget to append an empty entry to make up for the removed one. + // The size of the entries is not supposed to change. + aNewEntries.push_back(ScQueryEntry()); + + maEntries.swap(aNewEntries); +} + +void ScQueryParamBase::FillInExcelSyntax(String& aCellStr, SCSIZE nIndex) +{ + if (aCellStr.Len() > 0) + { + if ( nIndex >= maEntries.size() ) + Resize( nIndex+1 ); + + ScQueryEntry& rEntry = GetEntry(nIndex); + + rEntry.bDoQuery = TRUE; + // Operatoren herausfiltern + if (aCellStr.GetChar(0) == '<') + { + if (aCellStr.GetChar(1) == '>') + { + *rEntry.pStr = aCellStr.Copy(2); + rEntry.eOp = SC_NOT_EQUAL; + } + else if (aCellStr.GetChar(1) == '=') + { + *rEntry.pStr = aCellStr.Copy(2); + rEntry.eOp = SC_LESS_EQUAL; + } + else + { + *rEntry.pStr = aCellStr.Copy(1); + rEntry.eOp = SC_LESS; + } + } + else if (aCellStr.GetChar(0) == '>') + { + if (aCellStr.GetChar(1) == '=') + { + *rEntry.pStr = aCellStr.Copy(2); + rEntry.eOp = SC_GREATER_EQUAL; + } + else + { + *rEntry.pStr = aCellStr.Copy(1); + rEntry.eOp = SC_GREATER; + } + } + else + { + if (aCellStr.GetChar(0) == '=') + *rEntry.pStr = aCellStr.Copy(1); + else + *rEntry.pStr = aCellStr; + rEntry.eOp = SC_EQUAL; + } + } +} + +// ============================================================================ + +ScQueryParamTable::ScQueryParamTable() +{ +} + +ScQueryParamTable::ScQueryParamTable(const ScQueryParamTable& r) : + nCol1(r.nCol1),nRow1(r.nRow1),nCol2(r.nCol2),nRow2(r.nRow2),nTab(r.nTab) +{ +} + +ScQueryParamTable::~ScQueryParamTable() +{ +} + +// ============================================================================ + +ScQueryParam::ScQueryParam() : + ScQueryParamBase(), + ScQueryParamTable() +{ + Clear(); +} + +//------------------------------------------------------------------------ + +ScQueryParam::ScQueryParam( const ScQueryParam& r ) : + ScQueryParamBase(r), + ScQueryParamTable(r), + bDestPers(r.bDestPers), nDestTab(r.nDestTab), nDestCol(r.nDestCol), nDestRow(r.nDestRow) +{ +} + +ScQueryParam::ScQueryParam( const ScDBQueryParamInternal& r ) : + ScQueryParamBase(r), + ScQueryParamTable(r), + bDestPers(true), + nDestTab(0), + nDestCol(0), + nDestRow(0) +{ +} + + +//------------------------------------------------------------------------ + +ScQueryParam::~ScQueryParam() +{ +} + +//------------------------------------------------------------------------ + +void ScQueryParam::Clear() +{ + nCol1=nCol2 = 0; + nRow1=nRow2 = 0; + nTab = SCTAB_MAX; + bHasHeader = bCaseSens = bRegExp = bMixedComparison = FALSE; + bInplace = bByRow = bDuplicate = TRUE; + + Resize( MAXQUERY ); + for (USHORT i=0; i<MAXQUERY; i++) + maEntries[i].Clear(); + + ClearDestParams(); +} + +void ScQueryParam::ClearDestParams() +{ + bDestPers = true; + nDestTab = 0; + nDestCol = 0; + nDestRow = 0; +} + +//------------------------------------------------------------------------ + +ScQueryParam& ScQueryParam::operator=( const ScQueryParam& r ) +{ + nCol1 = r.nCol1; + nRow1 = r.nRow1; + nCol2 = r.nCol2; + nRow2 = r.nRow2; + nTab = r.nTab; + nDestTab = r.nDestTab; + nDestCol = r.nDestCol; + nDestRow = r.nDestRow; + bHasHeader = r.bHasHeader; + bInplace = r.bInplace; + bCaseSens = r.bCaseSens; + bRegExp = r.bRegExp; + bMixedComparison = r.bMixedComparison; + bDuplicate = r.bDuplicate; + bByRow = r.bByRow; + bDestPers = r.bDestPers; + + maEntries = r.maEntries; + + return *this; +} + +//------------------------------------------------------------------------ + +BOOL ScQueryParam::operator==( const ScQueryParam& rOther ) const +{ + BOOL bEqual = FALSE; + + // Anzahl der Queries gleich? + SCSIZE nUsed = 0; + SCSIZE nOtherUsed = 0; + SCSIZE nEntryCount = GetEntryCount(); + SCSIZE nOtherEntryCount = rOther.GetEntryCount(); + + while ( nUsed<nEntryCount && maEntries[nUsed].bDoQuery ) ++nUsed; + while ( nOtherUsed<nOtherEntryCount && rOther.maEntries[nOtherUsed].bDoQuery ) + ++nOtherUsed; + + if ( (nUsed == nOtherUsed) + && (nCol1 == rOther.nCol1) + && (nRow1 == rOther.nRow1) + && (nCol2 == rOther.nCol2) + && (nRow2 == rOther.nRow2) + && (nTab == rOther.nTab) + && (bHasHeader == rOther.bHasHeader) + && (bByRow == rOther.bByRow) + && (bInplace == rOther.bInplace) + && (bCaseSens == rOther.bCaseSens) + && (bRegExp == rOther.bRegExp) + && (bMixedComparison == rOther.bMixedComparison) + && (bDuplicate == rOther.bDuplicate) + && (bDestPers == rOther.bDestPers) + && (nDestTab == rOther.nDestTab) + && (nDestCol == rOther.nDestCol) + && (nDestRow == rOther.nDestRow) ) + { + bEqual = TRUE; + for ( SCSIZE i=0; i<nUsed && bEqual; i++ ) + bEqual = maEntries[i] == rOther.maEntries[i]; + } + return bEqual; +} + +//------------------------------------------------------------------------ + +void ScQueryParam::MoveToDest() +{ + if (!bInplace) + { + SCsCOL nDifX = ((SCsCOL) nDestCol) - ((SCsCOL) nCol1); + SCsROW nDifY = ((SCsROW) nDestRow) - ((SCsROW) nRow1); + SCsTAB nDifZ = ((SCsTAB) nDestTab) - ((SCsTAB) nTab); + + nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nDifX ); + nRow1 = sal::static_int_cast<SCROW>( nRow1 + nDifY ); + nCol2 = sal::static_int_cast<SCCOL>( nCol2 + nDifX ); + nRow2 = sal::static_int_cast<SCROW>( nRow2 + nDifY ); + nTab = sal::static_int_cast<SCTAB>( nTab + nDifZ ); + size_t n = maEntries.size(); + for (size_t i=0; i<n; i++) + maEntries[i].nField += nDifX; + + bInplace = TRUE; + } + else + { + DBG_ERROR("MoveToDest, bInplace == TRUE"); + } +} + +// ============================================================================ + +ScDBQueryParamBase::ScDBQueryParamBase(DataType eType) : + ScQueryParamBase(), + mnField(-1), + mbSkipString(true), + meType(eType) +{ +} + +ScDBQueryParamBase::~ScDBQueryParamBase() +{ +} + +ScDBQueryParamBase::DataType ScDBQueryParamBase::GetType() const +{ + return meType; +} + +// ============================================================================ + +ScDBQueryParamInternal::ScDBQueryParamInternal() : + ScDBQueryParamBase(ScDBQueryParamBase::INTERNAL), + ScQueryParamTable() +{ +} + +ScDBQueryParamInternal::~ScDBQueryParamInternal() +{ +} + +// ============================================================================ + +ScDBQueryParamMatrix::ScDBQueryParamMatrix() : + ScDBQueryParamBase(ScDBQueryParamBase::MATRIX) +{ +} + +ScDBQueryParamMatrix::~ScDBQueryParamMatrix() +{ +} + diff --git a/sc/source/filter/excel/colrowst.cxx b/sc/source/filter/excel/colrowst.cxx index 174ab2032..199dad8f7 100644 --- a/sc/source/filter/excel/colrowst.cxx +++ b/sc/source/filter/excel/colrowst.cxx @@ -43,6 +43,7 @@ #include "xltable.hxx" #include "xistream.hxx" #include "xistyle.hxx" +#include "queryparam.hxx" // for filter manager #include "excimp8.hxx" diff --git a/sc/source/filter/excel/excdoc.cxx b/sc/source/filter/excel/excdoc.cxx index 2b8a9433e..83287b0ae 100644 --- a/sc/source/filter/excel/excdoc.cxx +++ b/sc/source/filter/excel/excdoc.cxx @@ -235,7 +235,7 @@ void ExcTable::FillAsHeader( ExcBoundsheetList& rBoundsheetList ) Add( new XclExpFilePass( GetRoot() ) ); Add( new XclExpInterfaceHdr( nCodePage ) ); Add( new XclExpUInt16Record( EXC_ID_MMS, 0 ) ); - Add( new XclExpEmptyRecord( EXC_ID_INTERFACEEND ) ); + Add( new XclExpInterfaceEnd ); Add( new XclExpWriteAccess ); } diff --git a/sc/source/filter/excel/xecontent.cxx b/sc/source/filter/excel/xecontent.cxx index e5c97d1a9..3767582c8 100644 --- a/sc/source/filter/excel/xecontent.cxx +++ b/sc/source/filter/excel/xecontent.cxx @@ -748,19 +748,19 @@ void XclExpCFImpl::WriteBody( XclExpStream& rStrm ) // font used flag for underline -> 0 = used, 1 = default sal_uInt32 nFontFlags3 = mbUnderlUsed ? 0 : EXC_CF_FONT_UNDERL; - rStrm.WriteZeroBytes( 64 ); + rStrm.WriteZeroBytesToRecord( 64 ); rStrm << nHeight << nStyle << maFontData.mnWeight << EXC_FONTESC_NONE << maFontData.mnUnderline; - rStrm.WriteZeroBytes( 3 ); + rStrm.WriteZeroBytesToRecord( 3 ); rStrm << nColor << sal_uInt32( 0 ) << nFontFlags1 << EXC_CF_FONT_ESCAPEM // escapement never used -> set the flag << nFontFlags3; - rStrm.WriteZeroBytes( 16 ); + rStrm.WriteZeroBytesToRecord( 16 ); rStrm << sal_uInt16( 1 ); // must be 1 } diff --git a/sc/source/filter/excel/xestream.cxx b/sc/source/filter/excel/xestream.cxx index 1dd1bbc74..6f5b0eb4a 100644 --- a/sc/source/filter/excel/xestream.cxx +++ b/sc/source/filter/excel/xestream.cxx @@ -259,6 +259,17 @@ void XclExpStream::WriteZeroBytes( sal_Size nBytes ) WriteRawZeroBytes( nBytes ); } +void XclExpStream::WriteZeroBytesToRecord( sal_Size nBytes ) +{ + if (!mbInRec) + // not in record. + return; + + sal_uInt8 nZero = 0; + for (sal_Size i = 0; i < nBytes; ++i) + *this << nZero; +} + sal_Size XclExpStream::CopyFromStream( SvStream& rInStrm, sal_Size nBytes ) { sal_Size nStrmPos = rInStrm.Tell(); diff --git a/sc/source/filter/excel/xichart.cxx b/sc/source/filter/excel/xichart.cxx index dc542a1c1..7030bb568 100644 --- a/sc/source/filter/excel/xichart.cxx +++ b/sc/source/filter/excel/xichart.cxx @@ -34,6 +34,7 @@ #include "xichart.hxx" #include <algorithm> +#include <memory> #include <com/sun/star/frame/XModel.hpp> #include <com/sun/star/drawing/Direction3D.hpp> @@ -72,6 +73,8 @@ #include "tokenarray.hxx" #include "token.hxx" #include "compiler.hxx" +#include "reftokenhelper.hxx" +#include "chartlis.hxx" #include "fprogressbar.hxx" #include "xltracer.hxx" #include "xistream.hxx" @@ -123,6 +126,8 @@ using ::com::sun::star::chart2::data::XDataSequence; using ::formula::FormulaToken; using ::formula::StackVar; +using ::std::vector; + // Helpers ==================================================================== namespace { @@ -791,6 +796,22 @@ Sequence< Reference< XFormattedString > > XclImpChSourceLink::CreateStringSequen return ScfApiHelper::VectorToSequence( aStringVec ); } +void XclImpChSourceLink::FillSourceLink(vector<ScSharedTokenRef>& rTokens) const +{ + if (!mxTokenArray.is()) + // no links to fill. + return; + + mxTokenArray->Reset(); + for (FormulaToken* p = mxTokenArray->First(); p; p = mxTokenArray->Next()) + { + ScSharedTokenRef pToken(static_cast<ScToken*>(p->Clone())); + if (ScRefTokenHelper::isRef(pToken)) + // This is a reference token. Store it. + ScRefTokenHelper::join(rTokens, pToken); + } +} + // Text ======================================================================= XclImpChFontBase::~XclImpChFontBase() @@ -1837,6 +1858,18 @@ Reference< XDataSeries > XclImpChSeries::CreateDataSeries() const return xDataSeries; } +void XclImpChSeries::FillAllSourceLinks(vector<ScSharedTokenRef>& rTokens) const +{ + if (mxValueLink.is()) + mxValueLink->FillSourceLink(rTokens); + if (mxCategLink.is()) + mxCategLink->FillSourceLink(rTokens); + if (mxTitleLink.is()) + mxTitleLink->FillSourceLink(rTokens); + if (mxBubbleLink.is()) + mxBubbleLink->FillSourceLink(rTokens); +} + void XclImpChSeries::ReadChSourceLink( XclImpStream& rStrm ) { XclImpChSourceLinkRef xSrcLink( new XclImpChSourceLink( GetChRoot() ) ); @@ -3483,7 +3516,7 @@ XclImpChTextRef XclImpChChart::GetDefaultText( XclChTextType eTextType ) const return maDefTexts.get( nDefTextId ); } -void XclImpChChart::Convert( Reference< XChartDocument > xChartDoc, ScfProgressBar& rProgress ) const +void XclImpChChart::Convert( Reference< XChartDocument > xChartDoc, ScfProgressBar& rProgress, const OUString& rObjName ) const { // initialize conversion (locks the model to suppress any internal updates) InitConversion( xChartDoc ); @@ -3526,6 +3559,28 @@ void XclImpChChart::Convert( Reference< XChartDocument > xChartDoc, ScfProgressB // unlock the model FinishConversion( rProgress ); + + ScDocument* pDoc = &GetRoot().GetDoc(); + ScChartListenerCollection* pChartCollection = pDoc->GetChartListenerCollection(); + if (pChartCollection) + { + // Now, start listening to this chart. + ::std::auto_ptr< vector<ScSharedTokenRef> > pRefTokens(new vector<ScSharedTokenRef>); + for (XclImpChSeriesVec::const_iterator itr = maSeries.begin(), itrEnd = maSeries.end(); itr != itrEnd; ++itr) + { + const XclImpChSeriesRef& rSeries = *itr; + rSeries->FillAllSourceLinks(*pRefTokens); + } + if (!pRefTokens->empty()) + { + ::std::auto_ptr<ScChartListener> pListener( + new ScChartListener(rObjName, pDoc, pRefTokens.release())); + pListener->SetUsed(true); + pListener->StartListeningTo(); + pChartCollection->Insert(pListener.release()); + + } + } } void XclImpChChart::ReadChSeries( XclImpStream& rStrm ) @@ -3751,11 +3806,11 @@ sal_Size XclImpChart::GetProgressSize() const return mxChartData.is() ? mxChartData->GetProgressSize() : 0; } -void XclImpChart::Convert( Reference< XModel > xModel, ScfProgressBar& rProgress ) const +void XclImpChart::Convert( Reference< XModel > xModel, ScfProgressBar& rProgress, const OUString& rObjName ) const { Reference< XChartDocument > xChartDoc( xModel, UNO_QUERY ); if( mxChartData.is() && xChartDoc.is() ) - mxChartData->Convert( xChartDoc, rProgress ); + mxChartData->Convert( xChartDoc, rProgress, rObjName ); } void XclImpChart::ReadChChart( XclImpStream& rStrm ) diff --git a/sc/source/filter/excel/xiescher.cxx b/sc/source/filter/excel/xiescher.cxx index 5f1e8c547..57269a318 100644 --- a/sc/source/filter/excel/xiescher.cxx +++ b/sc/source/filter/excel/xiescher.cxx @@ -105,6 +105,7 @@ #include "convuno.hxx" #include "postit.hxx" #include "globstr.hrc" +#include "chartlis.hxx" #include "fprogressbar.hxx" #include "xltracer.hxx" @@ -1662,7 +1663,7 @@ SdrObject* XclImpChartObj::DoCreateSdrObj( const Rectangle& rAnchorRect, ScfProg if( svt::EmbeddedObjectRef::TryRunningState( xEmbObj ) ) { Reference< XModel > xModel( xEmbObj->getComponent(), UNO_QUERY ); - mxChart->Convert( xModel, rProgress ); + mxChart->Convert( xModel, rProgress, aEmbObjName ); Reference< XEmbedPersist > xPers( xEmbObj, UNO_QUERY ); if( xPers.is() ) @@ -3838,6 +3839,9 @@ void XclImpObjectManager::ConvertObjects() rDffManager.ProcessDrawing( maDffStrm, *aPIt ); } } + ScChartListenerCollection* pChartListeners = GetDoc().GetChartListenerCollection(); + if (pChartListeners && pChartListeners->GetCount()) + pChartListeners->SetDirty(); } String XclImpObjectManager::GetDefaultObjName( const XclImpDrawObjBase& rDrawObj ) const diff --git a/sc/source/filter/inc/excimp8.hxx b/sc/source/filter/inc/excimp8.hxx index c3b369365..3bc83b9cc 100644 --- a/sc/source/filter/inc/excimp8.hxx +++ b/sc/source/filter/inc/excimp8.hxx @@ -37,6 +37,7 @@ #include "excscen.hxx" #include "excdefs.hxx" #include "ftools.hxx" +#include "queryparam.hxx" class SotStorage; diff --git a/sc/source/filter/inc/xcl97rec.hxx b/sc/source/filter/inc/xcl97rec.hxx index b94d26124..f6a73ba2a 100644 --- a/sc/source/filter/inc/xcl97rec.hxx +++ b/sc/source/filter/inc/xcl97rec.hxx @@ -570,6 +570,19 @@ private: // ============================================================================ +/** End of User Interface Records */ +class XclExpInterfaceEnd : public XclExpRecord +{ +public: + explicit XclExpInterfaceEnd(); + virtual ~XclExpInterfaceEnd(); + +private: + virtual void WriteBody( XclExpStream& rStrm ); +}; + +// ============================================================================ + /** Write Access User Name - This record contains the user name, which is the name you type when you install Excel. */ class XclExpWriteAccess : public XclExpRecord diff --git a/sc/source/filter/inc/xestream.hxx b/sc/source/filter/inc/xestream.hxx index 95d172baf..e7a2da370 100644 --- a/sc/source/filter/inc/xestream.hxx +++ b/sc/source/filter/inc/xestream.hxx @@ -126,6 +126,9 @@ public: sal_Size Write( const void* pData, sal_Size nBytes ); /** Writes a sequence of nBytes zero bytes (respects slice setting). */ void WriteZeroBytes( sal_Size nBytes ); + + void WriteZeroBytesToRecord( sal_Size nBytes ); + /** Copies nBytes bytes from current position of the stream rInStrm. @descr Omitting the second parameter means: read to end of stream. */ sal_Size CopyFromStream( SvStream& rInStrm, sal_Size nBytes = STREAM_SEEK_TO_END ); diff --git a/sc/source/filter/inc/xichart.hxx b/sc/source/filter/inc/xichart.hxx index e09530083..34536a0da 100644 --- a/sc/source/filter/inc/xichart.hxx +++ b/sc/source/filter/inc/xichart.hxx @@ -39,6 +39,7 @@ #include <svl/itemset.hxx> #include "rangelst.hxx" +#include "token.hxx" #include "xlchart.hxx" #include "xlstyle.hxx" #include "xistring.hxx" @@ -403,6 +404,8 @@ public: XFormattedStringSeq CreateStringSequence( const XclImpChRoot& rRoot, sal_uInt16 nLeadFontIdx, const Color& rLeadFontColor ) const; + void FillSourceLink(::std::vector<ScSharedTokenRef>& rTokens) const; + private: XclChSourceLink maData; /// Contents of the CHSOURCELINK record. XclImpStringRef mxString; /// Text data (CHSTRING record). @@ -811,6 +814,8 @@ public: /** Creates a data series object with initialized source links. */ XDataSeriesRef CreateDataSeries() const; + void FillAllSourceLinks(::std::vector<ScSharedTokenRef>& rTokens) const; + private: /** Reads a CHSOURCELINK record. */ void ReadChSourceLink( XclImpStream& rStrm ); @@ -1353,7 +1358,7 @@ public: inline sal_Size GetProgressSize() const { return 2 * EXC_CHART_PROGRESS_SIZE; } /** Converts and writes all properties to the passed chart. */ - void Convert( XChartDocRef xChartDoc, ScfProgressBar& rProgress ) const; + void Convert( XChartDocRef xChartDoc, ScfProgressBar& rProgress, const ::rtl::OUString& rObjName ) const; private: /** Reads a CHSERIES group (data series source and formatting). */ @@ -1421,7 +1426,7 @@ public: inline bool IsPivotChart() const { return mbIsPivotChart; } /** Creates the chart object in the passed component. */ - void Convert( XModelRef xModel, ScfProgressBar& rProgress ) const; + void Convert( XModelRef xModel, ScfProgressBar& rProgress, const ::rtl::OUString& rObjName ) const; private: /** Reads the CHCHART group (entire chart data). */ diff --git a/sc/source/filter/xcl97/xcl97rec.cxx b/sc/source/filter/xcl97/xcl97rec.cxx index f15ef9667..722881266 100644 --- a/sc/source/filter/xcl97/xcl97rec.cxx +++ b/sc/source/filter/xcl97/xcl97rec.cxx @@ -1459,6 +1459,19 @@ void XclExpInterfaceHdr::WriteBody( XclExpStream& rStrm ) // ============================================================================ +XclExpInterfaceEnd::XclExpInterfaceEnd() : + XclExpRecord(0x00E2, 0) {} + +XclExpInterfaceEnd::~XclExpInterfaceEnd() {} + +void XclExpInterfaceEnd::WriteBody( XclExpStream& rStrm ) +{ + // Don't forget to re-enable encryption. + rStrm.EnableEncryption(); +} + +// ============================================================================ + XclExpWriteAccess::XclExpWriteAccess() : XclExpRecord(0x005C, 112) { diff --git a/sc/source/filter/xml/XMLExportDataPilot.hxx b/sc/source/filter/xml/XMLExportDataPilot.hxx index a3f6cf8d7..46a2bb0b0 100644 --- a/sc/source/filter/xml/XMLExportDataPilot.hxx +++ b/sc/source/filter/xml/XMLExportDataPilot.hxx @@ -44,6 +44,7 @@ class ScDPDimensionSaveData; class ScDPSaveGroupDimension; class ScDPSaveNumGroupDimension; struct ScDPNumGroupInfo; +struct ScQueryParam; class ScXMLExportDataPilot { diff --git a/sc/source/filter/xml/xmldpimp.hxx b/sc/source/filter/xml/xmldpimp.hxx index 6d3bc6236..665fe80bd 100644 --- a/sc/source/filter/xml/xmldpimp.hxx +++ b/sc/source/filter/xml/xmldpimp.hxx @@ -40,6 +40,7 @@ #include "global.hxx" #include "dpobject.hxx" #include "dpsave.hxx" +#include "queryparam.hxx" #include <hash_set> diff --git a/sc/source/ui/dbgui/foptmgr.cxx b/sc/source/ui/dbgui/foptmgr.cxx index ee5f03954..a425836e7 100644 --- a/sc/source/ui/dbgui/foptmgr.cxx +++ b/sc/source/ui/dbgui/foptmgr.cxx @@ -45,6 +45,7 @@ #include "dbcolect.hxx" #include "viewdata.hxx" #include "document.hxx" +#include "queryparam.hxx" #define _FOPTMGR_CXX #include "foptmgr.hxx" diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx index 8573ef309..6d82bb000 100644 --- a/sc/source/ui/docshell/externalrefmgr.cxx +++ b/sc/source/ui/docshell/externalrefmgr.cxx @@ -1061,8 +1061,11 @@ void ScExternalRefLink::DataChanged(const String& /*rMimeType*/, const Any& /*rV else { // The source document has changed. + ScDocShell* pDocShell = ScDocShell::GetViewData()->GetDocShell(); + ScDocShellModificator aMod(*pDocShell); pMgr->switchSrcFile(mnFileId, aFile, aFilter); maFilterName = aFilter; + aMod.SetDocumentModified(); } } diff --git a/sc/source/ui/inc/pfiltdlg.hxx b/sc/source/ui/inc/pfiltdlg.hxx index a9ba0d10a..b3831737c 100644 --- a/sc/source/ui/inc/pfiltdlg.hxx +++ b/sc/source/ui/inc/pfiltdlg.hxx @@ -53,8 +53,8 @@ #ifndef _COMBOBOX_HXX //autogen #include <vcl/combobox.hxx> #endif -#include "global.hxx" // -> ScQueryParam #include "address.hxx" +#include "queryparam.hxx" //------------------------------------------------------------------ diff --git a/sc/source/ui/inc/uiitems.hxx b/sc/source/ui/inc/uiitems.hxx index 3a9cb91c6..1e73bb235 100644 --- a/sc/source/ui/inc/uiitems.hxx +++ b/sc/source/ui/inc/uiitems.hxx @@ -34,6 +34,7 @@ #include "scdllapi.h" #include "conditio.hxx" #include "sortparam.hxx" +#include "queryparam.hxx" #include "paramisc.hxx" #include <svl/poolitem.hxx> diff --git a/sc/source/ui/inc/undodat.hxx b/sc/source/ui/inc/undodat.hxx index fb42d818a..ad46cb7f3 100644 --- a/sc/source/ui/inc/undodat.hxx +++ b/sc/source/ui/inc/undodat.hxx @@ -36,6 +36,7 @@ #include "rangelst.hxx" // ScRangeListRef #include "markdata.hxx" #include "sortparam.hxx" +#include "queryparam.hxx" #include "pivot.hxx" class ScDocShell; diff --git a/sc/source/ui/undo/undobase.cxx b/sc/source/ui/undo/undobase.cxx index f20abdb07..8b59f801b 100644 --- a/sc/source/ui/undo/undobase.cxx +++ b/sc/source/ui/undo/undobase.cxx @@ -45,6 +45,7 @@ #include "undodraw.hxx" #include "dbcolect.hxx" #include "attrib.hxx" +#include "queryparam.hxx" #include "globstr.hrc" // STATIC DATA ----------------------------------------------------------- diff --git a/sc/source/ui/unoobj/chart2uno.cxx b/sc/source/ui/unoobj/chart2uno.cxx index 51f7b806f..6435a71f8 100644 --- a/sc/source/ui/unoobj/chart2uno.cxx +++ b/sc/source/ui/unoobj/chart2uno.cxx @@ -2935,6 +2935,9 @@ void ScChart2DataSequence::BuildDataCache() ::std::list<sal_Int32>::const_iterator itr = aHiddenValues.begin(), itrEnd = aHiddenValues.end(); for (;itr != itrEnd; ++itr, ++pArr) *pArr = *itr; + + // Clear the data series cache when the array is re-built. + m_aMixedDataCache.realloc(0); } void ScChart2DataSequence::RebuildDataCache() @@ -3127,7 +3130,6 @@ void ScChart2DataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint if ( m_bGotDataChangedHint && m_pDocument ) { m_aDataArray.clear(); - m_aDataArray.clear(); lang::EventObject aEvent; aEvent.Source.set((cppu::OWeakObject*)this); @@ -3302,19 +3304,24 @@ uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData() throw uno::RuntimeException(); BuildDataCache(); - sal_Int32 nCount = m_aDataArray.size(); - uno::Sequence<uno::Any> aSeq(nCount); - uno::Any* pArr = aSeq.getArray(); - ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end(); - for (; itr != itrEnd; ++itr, ++pArr) + + if (!m_aMixedDataCache.getLength()) { - if (itr->mbIsValue) - *pArr <<= itr->mfValue; - else - *pArr <<= itr->maString; - } + // Build a cache for the 1st time... - return aSeq; + sal_Int32 nCount = m_aDataArray.size(); + m_aMixedDataCache.realloc(nCount); + uno::Any* pArr = m_aMixedDataCache.getArray(); + ::std::list<Item>::const_iterator itr = m_aDataArray.begin(), itrEnd = m_aDataArray.end(); + for (; itr != itrEnd; ++itr, ++pArr) + { + if (itr->mbIsValue) + *pArr <<= itr->mfValue; + else + *pArr <<= itr->maString; + } + } + return m_aMixedDataCache; } // XNumericalDataSequence -------------------------------------------------- diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx index 5cf7c27ff..cf7779ead 100644 --- a/sc/source/ui/view/gridwin4.cxx +++ b/sc/source/ui/view/gridwin4.cxx @@ -74,6 +74,7 @@ #include "inputopt.hxx" #include "fillinfo.hxx" #include "dpcontrol.hxx" +#include "queryparam.hxx" #include "sc.hrc" #include <vcl/virdev.hxx> |