summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@gmail.com>2013-03-11 17:16:54 -0400
committerKohei Yoshida <kohei.yoshida@gmail.com>2013-04-19 00:30:10 -0400
commitac569ed4cf5064248b9952f182f6572f20dc9bcb (patch)
tree44789fb45958b6cc8ce21f1742a04a407d5f6c75
parent687a821e3b4ac872fd7eb1010ea87c3d81e71991 (diff)
fdo#60300: Work-in-progress change to rework pivot table core.
The idea is to avoid parsing the pivot table sheet output in order to calculate GETPIVOTDATA. The table outout is configurable, and it will only be more configurable in the future. The gist of my rework is to calcualte the result of GETPIVOTDATA with the internl result tree alone. Also, the same result tree can be used for drill down too, which also currently parses the table output, therefore subject to the same limitation & fragility. Change-Id: Ib0147e2aa2b710dfd627df7f535a685301214a52
-rw-r--r--offapi/com/sun/star/sheet/XDataPilotResults.idl3
-rw-r--r--sc/Library_sc.mk1
-rw-r--r--sc/inc/dpitemdata.hxx5
-rw-r--r--sc/inc/dpmacros.hxx2
-rw-r--r--sc/inc/dpobject.hxx5
-rw-r--r--sc/inc/dpresfilter.hxx115
-rw-r--r--sc/inc/dptabres.hxx43
-rw-r--r--sc/inc/dptabsrc.hxx7
-rw-r--r--sc/source/core/data/dpitemdata.cxx31
-rw-r--r--sc/source/core/data/dpobject.cxx51
-rw-r--r--sc/source/core/data/dpresfilter.cxx157
-rw-r--r--sc/source/core/data/dptabres.cxx265
-rw-r--r--sc/source/core/data/dptabsrc.cxx68
-rw-r--r--sc/source/core/tool/interpr2.cxx80
14 files changed, 734 insertions, 99 deletions
diff --git a/offapi/com/sun/star/sheet/XDataPilotResults.idl b/offapi/com/sun/star/sheet/XDataPilotResults.idl
index e5b2c3c23afa..0e4486b91537 100644
--- a/offapi/com/sun/star/sheet/XDataPilotResults.idl
+++ b/offapi/com/sun/star/sheet/XDataPilotResults.idl
@@ -22,6 +22,7 @@
#include <com/sun/star/uno/XInterface.idl>
#include <com/sun/star/sheet/DataResult.idl>
+#include <com/sun/star/sheet/DataPilotFieldFilter.idl>
module com { module sun { module star { module sheet {
@@ -44,6 +45,8 @@ interface XDataPilotResults: com::sun::star::uno::XInterface
*/
sequence< sequence< DataResult > > getResults();
+ sequence<any> getFilteredResults(
+ [in] sequence<com::sun::star::sheet::DataPilotFieldFilter> aFilters );
};
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 5631f5578229..77e3e355a068 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -135,6 +135,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
sc/source/core/data/dpobject \
sc/source/core/data/dpoutput \
sc/source/core/data/dpoutputgeometry \
+ sc/source/core/data/dpresfilter \
sc/source/core/data/dpsave \
sc/source/core/data/dpsdbtab \
sc/source/core/data/dpshttab \
diff --git a/sc/inc/dpitemdata.hxx b/sc/inc/dpitemdata.hxx
index eeb79b7d4a74..84a5f922b657 100644
--- a/sc/inc/dpitemdata.hxx
+++ b/sc/inc/dpitemdata.hxx
@@ -62,6 +62,11 @@ public:
sal_Int32 mnValue;
};
+ struct Hash
+ {
+ size_t operator() (const ScDPItemData& rVal) const;
+ };
+
private:
union {
diff --git a/sc/inc/dpmacros.hxx b/sc/inc/dpmacros.hxx
index 79aafafe0f6d..ce91b06b63b0 100644
--- a/sc/inc/dpmacros.hxx
+++ b/sc/inc/dpmacros.hxx
@@ -29,7 +29,7 @@
#ifndef __SC_DPMACROS_HXX__
#define __SC_DPMACROS_HXX__
-#define DEBUG_PIVOT_TABLE 0
+#define DEBUG_PIVOT_TABLE 1
#if DEBUG_PIVOT_TABLE
#include <iostream>
diff --git a/sc/inc/dpobject.hxx b/sc/inc/dpobject.hxx
index c2c07f5b8741..fd7c59822fcf 100644
--- a/sc/inc/dpobject.hxx
+++ b/sc/inc/dpobject.hxx
@@ -179,6 +179,11 @@ public:
Rectangle& rPosRect, sal_uInt16& rOrient, long& rDimPos );
bool IsFilterButton( const ScAddress& rPos );
+ double GetPivotData(
+ const OUString& rDataFieldName,
+ const com::sun::star::uno::Sequence<
+ com::sun::star::sheet::DataPilotFieldFilter>& rFilters);
+
bool GetPivotData( ScDPGetPivotDataField& rTarget, /* returns result */
const std::vector< ScDPGetPivotDataField >& rFilters );
bool ParseFilters( ScDPGetPivotDataField& rTarget,
diff --git a/sc/inc/dpresfilter.hxx b/sc/inc/dpresfilter.hxx
new file mode 100644
index 000000000000..db32f6e16d90
--- /dev/null
+++ b/sc/inc/dpresfilter.hxx
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef __SC_DPRESFILTER_HXX__
+#define __SC_DPRESFILTER_HXX__
+
+#include "dpitemdata.hxx"
+
+#include <vector>
+#include <boost/noncopyable.hpp>
+
+#if DEBUG_PIVOT_TABLE
+#include <map>
+#else
+#include <boost/unordered_map.hpp>
+#endif
+
+struct ScDPResultFilter
+{
+ OUString maDimName;
+ ScDPItemData maValue;
+
+ bool mbHasValue:1;
+ bool mbDataLayout:1;
+
+ ScDPResultFilter(const OUString& rDimName, bool bDataLayout);
+};
+
+class ScDPResultFilterSet : boost::noncopyable
+{
+ struct MemberNode;
+ struct DimensionNode;
+#if DEBUG_PIVOT_TABLE
+ // To keep the entries sorted in the tree dump.
+ typedef std::map<ScDPItemData, MemberNode*> MembersType;
+ typedef std::map<OUString, DimensionNode*> DimensionsType;
+#else
+ typedef boost::unordered_map<ScDPItemData, MemberNode*, ScDPItemData::Hash> MembersType;
+ typedef boost::unordered_map<OUString, DimensionNode*, OUStringHash> DimensionsType;
+#endif
+ typedef std::vector<double> ValuesType;
+
+ struct DimensionNode : boost::noncopyable
+ {
+ const MemberNode* mpParent;
+ MembersType maChildMembers;
+
+ DimensionNode(const MemberNode* pParent);
+ ~DimensionNode();
+
+#if DEBUG_PIVOT_TABLE
+ void dump(int nLevel) const;
+#endif
+ };
+
+ struct MemberNode : boost::noncopyable
+ {
+ const DimensionNode* mpParent;
+ double mfValue;
+ ValuesType maValues;
+ DimensionsType maChildDimensions;
+
+ MemberNode(const DimensionNode* pParent);
+ ~MemberNode();
+
+#if DEBUG_PIVOT_TABLE
+ void dump(int nLevel) const;
+#endif
+ };
+
+ MemberNode* mpRoot;
+
+public:
+ ScDPResultFilterSet();
+ ~ScDPResultFilterSet();
+
+ /**
+ * Add a single value filter path. The filters are expected to be sorted
+ * by row dimension order then by column dimension order.
+ *
+ * @param rFilter set of filters.
+ * @param nCol column position relative to the top-left cell within the
+ * data field range.
+ * @param nRow row position relative to the top-left cell within the data
+ * field range.
+ * @param fVal result value, as displayed in the table output.
+ */
+ void add(const std::vector<ScDPResultFilter>& rFilter, long nCol, long nRow, double fVal);
+
+ void swap(ScDPResultFilterSet& rOther);
+
+#if DEBUG_PIVOT_TABLE
+ void dump() const;
+#endif
+};
+
+struct ScDPResultFilterContext
+{
+ ScDPResultFilterSet maFilterSet;
+ std::vector<ScDPResultFilter> maFilters;
+ long mnCol;
+ long mnRow;
+
+ ScDPResultFilterContext();
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/dptabres.hxx b/sc/inc/dptabres.hxx
index 96ebe53c2e0f..e6289be227d8 100644
--- a/sc/inc/dptabres.hxx
+++ b/sc/inc/dptabres.hxx
@@ -52,6 +52,7 @@ class ScDPResultVisibilityData;
struct ScDPValue;
class ScDPItemData;
+struct ScDPResultFilterContext;
/**
* Member names that are being processed for InitFrom/LateInitFrom (needed
@@ -403,11 +404,12 @@ public:
com::sun::star::sheet::MemberResult>* pSequences,
long& rPos, long nMeasure, bool bRoot, const OUString* pMemberName, const OUString* pMemberCaption );
- void FillDataResults( const ScDPResultMember* pRefMember,
- com::sun::star::uno::Sequence<
- com::sun::star::uno::Sequence<
- com::sun::star::sheet::DataResult> >& rSequence,
- long& rRow, long nMeasure ) const;
+ void FillDataResults(
+ const ScDPResultMember* pRefMember, ScDPResultFilterContext& rFilterCxt,
+ com::sun::star::uno::Sequence<
+ com::sun::star::uno::Sequence<
+ com::sun::star::sheet::DataResult> >& rSequence,
+ long nMeasure) const;
void UpdateDataResults( const ScDPResultMember* pRefMember, long nMeasure ) const;
void UpdateRunningTotals( const ScDPResultMember* pRefMember, long nMeasure,
@@ -471,10 +473,12 @@ public:
const ScDPAggData* GetConstAggData( long nMeasure, const ScDPSubTotalState& rSubState ) const;
ScDPAggData* GetAggData( long nMeasure, const ScDPSubTotalState& rSubState );
- void FillDataRow( const ScDPResultMember* pRefMember,
- com::sun::star::uno::Sequence<com::sun::star::sheet::DataResult>& rSequence,
- long& rCol, long nMeasure, bool bIsSubTotalRow,
- const ScDPSubTotalState& rSubState ) const;
+ void FillDataRow(
+ const ScDPResultMember* pRefMember,
+ ScDPResultFilterContext& rFilterCxt,
+ com::sun::star::uno::Sequence<com::sun::star::sheet::DataResult>& rSequence,
+ long nMeasure, bool bIsSubTotalRow,
+ const ScDPSubTotalState& rSubState) const;
void UpdateDataRow( const ScDPResultMember* pRefMember, long nMeasure, bool bIsSubTotalRow,
const ScDPSubTotalState& rSubState );
@@ -557,11 +561,13 @@ public:
com::sun::star::sheet::MemberResult>* pSequences,
long nStart, long nMeasure );
- void FillDataResults( const ScDPResultMember* pRefMember,
- com::sun::star::uno::Sequence<
- com::sun::star::uno::Sequence<
- com::sun::star::sheet::DataResult> >& rSequence,
- long nRow, long nMeasure ) const;
+ void FillDataResults(
+ const ScDPResultMember* pRefMember,
+ ScDPResultFilterContext& rFilterCxt,
+ com::sun::star::uno::Sequence<
+ com::sun::star::uno::Sequence<
+ com::sun::star::sheet::DataResult> >& rSequence,
+ long nMeasure) const;
void UpdateDataResults( const ScDPResultMember* pRefMember, long nMeasure ) const;
void UpdateRunningTotals( const ScDPResultMember* pRefMember, long nMeasure,
@@ -629,10 +635,11 @@ public:
void InitFrom( const ScDPResultDimension* pDim ); // recursive
void ProcessData( const ::std::vector< SCROW >& aDataMembers, const ::std::vector<ScDPValue>& aValues,
const ScDPSubTotalState& rSubState );
- void FillDataRow( const ScDPResultDimension* pRefDim,
- com::sun::star::uno::Sequence<com::sun::star::sheet::DataResult>& rSequence,
- long nCol, long nMeasure, bool bIsSubTotalRow,
- const ScDPSubTotalState& rSubState ) const;
+ void FillDataRow(
+ const ScDPResultDimension* pRefDim,
+ ScDPResultFilterContext& rFilterCxt,
+ com::sun::star::uno::Sequence<com::sun::star::sheet::DataResult>& rSequence,
+ long nMeasure, bool bIsSubTotalRow, const ScDPSubTotalState& rSubState) const;
void UpdateDataRow( const ScDPResultDimension* pRefDim, long nMeasure, bool bIsSubTotalRow,
const ScDPSubTotalState& rSubState ) const;
diff --git a/sc/inc/dptabsrc.hxx b/sc/inc/dptabsrc.hxx
index e98b6516f6bb..a51dd478e30f 100644
--- a/sc/inc/dptabsrc.hxx
+++ b/sc/inc/dptabsrc.hxx
@@ -49,6 +49,7 @@
#include "dptabdat.hxx"
#include "dpglobal.hxx"
+#include "dpresfilter.hxx"
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
@@ -103,6 +104,7 @@ private:
std::vector<long> maRowDims;
std::vector<long> maDataDims;
std::vector<long> maPageDims;
+ ScDPResultFilterSet maResFilterSet;
bool bColumnGrand;
bool bRowGrand;
@@ -199,6 +201,11 @@ public:
::com::sun::star::sheet::DataResult > > SAL_CALL getResults( )
throw(::com::sun::star::uno::RuntimeException);
+ virtual com::sun::star::uno::Sequence<com::sun::star::uno::Any> SAL_CALL
+ getFilteredResults(
+ const com::sun::star::uno::Sequence<com::sun::star::sheet::DataPilotFieldFilter>& aFilters )
+ throw (com::sun::star::uno::RuntimeException);
+
// XRefreshable
virtual void SAL_CALL refresh() throw(::com::sun::star::uno::RuntimeException);
virtual void SAL_CALL addRefreshListener( const ::com::sun::star::uno::Reference<
diff --git a/sc/source/core/data/dpitemdata.cxx b/sc/source/core/data/dpitemdata.cxx
index a91476522699..c417317ff1fd 100644
--- a/sc/source/core/data/dpitemdata.cxx
+++ b/sc/source/core/data/dpitemdata.cxx
@@ -29,6 +29,33 @@
const sal_Int32 ScDPItemData::DateFirst = -1;
const sal_Int32 ScDPItemData::DateLast = 10000;
+size_t ScDPItemData::Hash::operator() (const ScDPItemData& rVal) const
+{
+ switch (rVal.GetType())
+ {
+ case GroupValue:
+ case Value:
+ case RangeStart:
+ return (size_t)(rVal.mfValue);
+ case String:
+ case Error:
+ {
+ if (!rVal.mpString)
+ return 0;
+
+ if (rVal.mbStringInterned)
+ return reinterpret_cast<size_t>(rVal.mpString);
+
+ OUStringHash aStrHasher;
+ return aStrHasher(*rVal.mpString);
+ }
+ default:
+ ;
+ }
+
+ return 0;
+}
+
sal_Int32 ScDPItemData::Compare(const ScDPItemData& rA, const ScDPItemData& rB)
{
if (rA.meType != rB.meType)
@@ -337,10 +364,10 @@ OUString ScDPItemData::GetString() const
case Error:
return *mpString;
case Value:
+ case RangeStart:
return OUString::valueOf(mfValue);
case GroupValue:
- case RangeStart:
- return OUString::createFromAscii("fail");
+ return OUString::valueOf(maGroupValue.mnValue);
case Empty:
default:
;
diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx
index 703317003fd3..d04197ef69d8 100644
--- a/sc/source/core/data/dpobject.cxx
+++ b/sc/source/core/data/dpobject.cxx
@@ -1278,6 +1278,57 @@ void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHead
aPosData.PositionData >>= rData;
}
+namespace {
+
+class FindByName : std::unary_function<const ScDPSaveDimension*, bool>
+{
+ OUString maName;
+public:
+ FindByName(const OUString& rName) : maName(rName) {}
+ bool operator() (const ScDPSaveDimension* pDim) const
+ {
+ const OUString* pLayoutName = pDim->GetLayoutName();
+ if (pLayoutName)
+ return *pLayoutName == maName;
+
+ return maName == pDim->GetName();
+ }
+};
+
+}
+
+double ScDPObject::GetPivotData(const OUString& rDataFieldName, const uno::Sequence<sheet::DataPilotFieldFilter>& rFilters)
+{
+ double fRet;
+ rtl::math::setNan(&fRet);
+ if (!mbEnableGetPivotData)
+ return fRet;
+
+ CreateObjects();
+
+ std::vector<const ScDPSaveDimension*> aDims;
+ pSaveData->GetAllDimensionsByOrientation(sheet::DataPilotFieldOrientation_DATA, aDims);
+ if (aDims.empty())
+ return fRet;
+
+ std::vector<const ScDPSaveDimension*>::iterator it = std::find_if(
+ aDims.begin(), aDims.end(), FindByName(rDataFieldName));
+ if (it == aDims.end())
+ return fRet;
+
+ sal_Int32 nDataIndex = std::distance(aDims.begin(), it);
+
+ uno::Reference<sheet::XDataPilotResults> xDPResults(xSource, uno::UNO_QUERY);
+ if (!xDPResults.is())
+ return fRet;
+
+ uno::Sequence<uno::Any> aRes = xDPResults->getFilteredResults(rFilters);
+
+ fRet = 54.0;
+
+ return fRet;
+}
+
// Returns sal_True on success and stores the result in rTarget
bool ScDPObject::GetPivotData( ScDPGetPivotDataField& rTarget,
const std::vector< ScDPGetPivotDataField >& rFilters )
diff --git a/sc/source/core/data/dpresfilter.cxx b/sc/source/core/data/dpresfilter.cxx
new file mode 100644
index 000000000000..b08cc4ac7674
--- /dev/null
+++ b/sc/source/core/data/dpresfilter.cxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "dpresfilter.hxx"
+
+using namespace std;
+
+ScDPResultFilter::ScDPResultFilter(const OUString& rDimName, bool bDataLayout) :
+ maDimName(rDimName), mbHasValue(false), mbDataLayout(bDataLayout) {}
+
+ScDPResultFilterContext::ScDPResultFilterContext() :
+ mnCol(0), mnRow(0) {}
+
+ScDPResultFilterSet::DimensionNode::DimensionNode(const MemberNode* pParent) :
+ mpParent(pParent) {}
+
+ScDPResultFilterSet::DimensionNode::~DimensionNode()
+{
+ MembersType::iterator it = maChildMembers.begin(), itEnd = maChildMembers.end();
+ for (; it != itEnd; ++it)
+ delete it->second;
+}
+
+#if DEBUG_PIVOT_TABLE
+void ScDPResultFilterSet::DimensionNode::dump(int nLevel) const
+{
+ string aIndent(nLevel*2, ' ');
+ MembersType::const_iterator it = maChildMembers.begin(), itEnd = maChildMembers.end();
+ for (; it != itEnd; ++it)
+ {
+ cout << aIndent << "member: ";
+ const ScDPItemData& rVal = it->first;
+ if (rVal.IsValue())
+ cout << rVal.GetValue();
+ else
+ cout << rVal.GetString();
+ cout << endl;
+
+ it->second->dump(nLevel+1);
+ }
+}
+#endif
+
+ScDPResultFilterSet::MemberNode::MemberNode(const DimensionNode* pParent) :
+ mpParent(pParent) {}
+
+ScDPResultFilterSet::MemberNode::~MemberNode()
+{
+ DimensionsType::iterator it = maChildDimensions.begin(), itEnd = maChildDimensions.end();
+ for (; it != itEnd; ++it)
+ delete it->second;
+}
+
+#if DEBUG_PIVOT_TABLE
+void ScDPResultFilterSet::MemberNode::dump(int nLevel) const
+{
+ string aIndent(nLevel*2, ' ');
+ ValuesType::const_iterator itVal = maValues.begin(), itValEnd = maValues.end();
+ for (; itVal != itValEnd; ++itVal)
+ cout << aIndent << "value: " << *itVal << endl;
+
+ DimensionsType::const_iterator it = maChildDimensions.begin(), itEnd = maChildDimensions.end();
+ for (; it != itEnd; ++it)
+ {
+ cout << aIndent << "dimension: " << it->first << endl;
+ it->second->dump(nLevel+1);
+ }
+}
+#endif
+
+ScDPResultFilterSet::ScDPResultFilterSet() : mpRoot(new MemberNode(NULL)) {}
+ScDPResultFilterSet::~ScDPResultFilterSet()
+{
+ delete mpRoot;
+}
+
+void ScDPResultFilterSet::add(
+ const std::vector<ScDPResultFilter>& rFilters, long nCol, long nRow, double fVal)
+{
+ // TODO: I'll work on the col / row to value node mapping later.
+
+ MemberNode* pMemNode = mpRoot;
+
+ fprintf(stdout, "(row=%ld; col=%ld; value=%g) : ", nRow, nCol, fVal);
+ std::vector<ScDPResultFilter>::const_iterator itFilter = rFilters.begin(), itFilterEnd = rFilters.end();
+ for (; itFilter != itFilterEnd; ++itFilter)
+ {
+ const ScDPResultFilter& filter = *itFilter;
+ if (filter.mbDataLayout)
+ continue;
+
+ printf("%s: ", rtl::OUStringToOString(filter.maDimName, RTL_TEXTENCODING_UTF8).getStr());
+ if (filter.maValue.IsValue())
+ printf("%g ", filter.maValue.GetValue());
+ else
+ printf("'%s' ", rtl::OUStringToOString(filter.maValue.GetString(), RTL_TEXTENCODING_UTF8).getStr());
+
+ // See if this dimension exists.
+ DimensionsType& rDims = pMemNode->maChildDimensions;
+ DimensionsType::iterator itDim = rDims.find(filter.maDimName);
+ if (itDim == rDims.end())
+ {
+ // New dimenison. Insert it.
+ std::pair<DimensionsType::iterator, bool> r =
+ rDims.insert(DimensionsType::value_type(filter.maDimName, new DimensionNode(pMemNode)));
+
+ if (!r.second)
+ // Insertion failed!
+ return;
+
+ itDim = r.first;
+ }
+
+ // Now, see if this dimension member exists.
+ DimensionNode* pDim = itDim->second;
+ MembersType& rMembers = pDim->maChildMembers;
+ MembersType::iterator itMem = rMembers.find(filter.maValue);
+ if (itMem == rMembers.end())
+ {
+ // New member. Insert it.
+ std::pair<MembersType::iterator, bool> r =
+ rMembers.insert(
+ MembersType::value_type(filter.maValue, new MemberNode(pDim)));
+
+ if (!r.second)
+ // Insertion failed!
+ return;
+
+ itMem = r.first;
+ }
+
+ pMemNode = itMem->second;
+ }
+
+ pMemNode->maValues.push_back(fVal);
+ printf("\n");
+}
+
+void ScDPResultFilterSet::swap(ScDPResultFilterSet& rOther)
+{
+ std::swap<MemberNode*>(mpRoot, rOther.mpRoot);
+}
+
+#if DEBUG_PIVOT_TABLE
+void ScDPResultFilterSet::dump() const
+{
+ mpRoot->dump(0);
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/dptabres.cxx b/sc/source/core/data/dptabres.cxx
index 322dc5ff450d..379f5c1a7d4c 100644
--- a/sc/source/core/data/dptabres.cxx
+++ b/sc/source/core/data/dptabres.cxx
@@ -29,6 +29,7 @@
#include "document.hxx" // for DumpState only!
#include "stlalgorithm.hxx"
+#include "dpresfilter.hxx"
#include <osl/diagnose.h>
#include <rtl/math.hxx>
@@ -38,6 +39,7 @@
#include <float.h> //! Test !!!
#include <algorithm>
#include <boost/unordered_map.hpp>
+#include <boost/scoped_ptr.hpp>
#include <com/sun/star/sheet/DataResultFlags.hpp>
#include <com/sun/star/sheet/MemberResultFlags.hpp>
@@ -53,9 +55,51 @@ using ::std::vector;
using ::std::pair;
using ::com::sun::star::uno::Sequence;
-// -----------------------------------------------------------------------
+#include <stdio.h>
+#include <string>
+#include <sys/time.h>
+
+namespace {
-static sal_uInt16 nFuncStrIds[12] = // passend zum enum ScSubTotalFunc
+class stack_printer
+{
+public:
+ explicit stack_printer(const char* msg) :
+ msMsg(msg)
+ {
+ fprintf(stdout, "%s: --begin\n", msMsg.c_str());
+ mfStartTime = getTime();
+ }
+
+ ~stack_printer()
+ {
+ double fEndTime = getTime();
+ fprintf(stdout, "%s: --end (duration: %g sec)\n", msMsg.c_str(), (fEndTime - mfStartTime));
+ }
+
+ void printTime(int line) const
+ {
+ double fEndTime = getTime();
+ fprintf(stdout, "%s: --(%d) (duration: %g sec)\n", msMsg.c_str(), line, (fEndTime - mfStartTime));
+ }
+
+private:
+ double getTime() const
+ {
+ timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec + tv.tv_usec / 1000000.0;
+ }
+
+ ::std::string msMsg;
+ double mfStartTime;
+};
+
+}
+
+namespace {
+
+sal_uInt16 nFuncStrIds[12] = // passend zum enum ScSubTotalFunc
{
0, // SUBTOTAL_FUNC_NONE
STR_FUN_TEXT_AVG, // SUBTOTAL_FUNC_AVE
@@ -70,35 +114,62 @@ static sal_uInt16 nFuncStrIds[12] = // passend zum enum ScSubTotalFunc
STR_FUN_TEXT_VAR, // SUBTOTAL_FUNC_VAR
STR_FUN_TEXT_VAR // SUBTOTAL_FUNC_VARP
};
-namespace {
- bool lcl_SearchMember( const std::vector <ScDPResultMember *>& list, SCROW nOrder, SCROW& rIndex)
+bool lcl_SearchMember( const std::vector <ScDPResultMember *>& list, SCROW nOrder, SCROW& rIndex)
+{
+ rIndex = list.size();
+ bool bFound = false;
+ SCROW nLo = 0;
+ SCROW nHi = list.size() - 1;
+ SCROW nIndex;
+ while (nLo <= nHi)
{
- rIndex = list.size();
- bool bFound = false;
- SCROW nLo = 0;
- SCROW nHi = list.size() - 1;
- SCROW nIndex;
- while (nLo <= nHi)
+ nIndex = (nLo + nHi) / 2;
+ if ( list[nIndex]->GetOrder() < nOrder )
+ nLo = nIndex + 1;
+ else
{
- nIndex = (nLo + nHi) / 2;
- if ( list[nIndex]->GetOrder() < nOrder )
- nLo = nIndex + 1;
- else
+ nHi = nIndex - 1;
+ if ( list[nIndex]->GetOrder() == nOrder )
{
- nHi = nIndex - 1;
- if ( list[nIndex]->GetOrder() == nOrder )
- {
- bFound = true;
- nLo = nIndex;
- }
+ bFound = true;
+ nLo = nIndex;
}
}
- rIndex = nLo;
- return bFound;
}
+ rIndex = nLo;
+ return bFound;
+}
+
+class FilterStack
+{
+ std::vector<ScDPResultFilter>& mrFilters;
+public:
+ FilterStack(std::vector<ScDPResultFilter>& rFilters) : mrFilters(rFilters) {}
+
+ void pushDimName(const OUString& rName, bool bDataLayout)
+ {
+ mrFilters.push_back(ScDPResultFilter(rName, bDataLayout));
+ }
+
+ void pushDimValue(const ScDPItemData& rValue)
+ {
+ ScDPResultFilter& rFilter = mrFilters.back();
+ rFilter.maValue = rValue;
+ rFilter.mbHasValue = true;
+ }
+
+ ~FilterStack()
+ {
+ ScDPResultFilter& rFilter = mrFilters.back();
+ if (rFilter.mbHasValue)
+ rFilter.mbHasValue = false;
+ else
+ mrFilters.pop_back();
+ }
+};
+
}
-// -----------------------------------------------------------------------
//
// function objects for sorting of the column and row members:
@@ -1497,14 +1568,26 @@ void ScDPResultMember::FillMemberResults(
}
}
-void ScDPResultMember::FillDataResults( const ScDPResultMember* pRefMember,
- uno::Sequence< uno::Sequence<sheet::DataResult> >& rSequence,
- long& rRow, long nMeasure ) const
+void ScDPResultMember::FillDataResults(
+ const ScDPResultMember* pRefMember,
+ ScDPResultFilterContext& rFilterCxt, uno::Sequence<uno::Sequence<sheet::DataResult> >& rSequence,
+ long nMeasure) const
{
+ boost::scoped_ptr<FilterStack> pFilterStack;
+ const ScDPMember* pDPMember = GetDPMember();
+ if (pDPMember)
+ {
+ // Root result has no corresponding DP member. Only take the non-root results.
+ ScDPItemData aItem;
+ pDPMember->FillItemData(aItem);
+ pFilterStack.reset(new FilterStack(rFilterCxt.maFilters));
+ pFilterStack->pushDimValue(aItem);
+ }
+
// IsVisible() test is in ScDPResultDimension::FillDataResults
// (not on data layout dimension)
const ScDPLevel* pParentLevel = GetParentLevel();
- long nStartRow = rRow;
+ long nStartRow = rFilterCxt.mnRow;
long nExtraSpace = 0;
if ( pParentLevel && pParentLevel->IsAddEmpty() )
@@ -1520,13 +1603,16 @@ void ScDPResultMember::FillDataResults( const ScDPResultMember* pRefMember,
if (bHasChild)
{
if ( bTitleLine ) // in tabular layout the title is on a separate row
- ++rRow; // -> fill child dimension one row below
+ ++rFilterCxt.mnRow; // -> fill child dimension one row below
- pChildDimension->FillDataResults( pRefMember, rSequence, rRow, nMeasure ); // doesn't modify rRow
- rRow += GetSize( nMeasure );
+ long nOldRow = rFilterCxt.mnRow;
+ pChildDimension->FillDataResults(pRefMember, rFilterCxt, rSequence, nMeasure);
+ rFilterCxt.mnRow = nOldRow; // Revert to the original row before the call.
+
+ rFilterCxt.mnRow += GetSize( nMeasure );
if ( bTitleLine ) // title row is included in GetSize, so the following
- --rRow; // positions are calculated with the normal values
+ --rFilterCxt.mnRow; // positions are calculated with the normal values
}
long nUserSubStart;
@@ -1545,15 +1631,15 @@ void ScDPResultMember::FillDataResults( const ScDPResultMember* pRefMember,
long nSubSize = pResultData->GetCountForMeasure(nMeasure);
if (bHasChild)
{
- rRow -= nSubSize * ( nUserSubCount - nUserSubStart ); // GetSize includes space for SubTotal
- rRow -= nExtraSpace; // GetSize includes the empty line
+ rFilterCxt.mnRow -= nSubSize * ( nUserSubCount - nUserSubStart ); // GetSize includes space for SubTotal
+ rFilterCxt.mnRow -= nExtraSpace; // GetSize includes the empty line
}
long nMoveSubTotal = 0;
if ( bSubTotalInTitle )
{
- nMoveSubTotal = rRow - nStartRow; // force to first (title) row
- rRow = nStartRow;
+ nMoveSubTotal = rFilterCxt.mnRow - nStartRow; // force to first (title) row
+ rFilterCxt.mnRow = nStartRow;
}
if ( pDataRoot )
@@ -1575,24 +1661,23 @@ void ScDPResultMember::FillDataResults( const ScDPResultMember* pRefMember,
else if ( pResultData->GetColStartMeasure() == SC_DPMEASURE_ALL )
nMemberMeasure = SC_DPMEASURE_ALL;
- OSL_ENSURE( rRow < rSequence.getLength(), "bumm" );
- uno::Sequence<sheet::DataResult>& rSubSeq = rSequence.getArray()[rRow];
- long nSeqCol = 0;
+ OSL_ENSURE( rFilterCxt.mnRow < rSequence.getLength(), "bumm" );
+ uno::Sequence<sheet::DataResult>& rSubSeq = rSequence.getArray()[rFilterCxt.mnRow];
+ rFilterCxt.mnCol = 0;
if (pRefMember->IsVisible())
- pDataRoot->FillDataRow(pRefMember, rSubSeq, nSeqCol, nMemberMeasure, bHasChild, aSubState);
+ pDataRoot->FillDataRow(pRefMember, rFilterCxt, rSubSeq, nMemberMeasure, bHasChild, aSubState);
- rRow += 1;
+ rFilterCxt.mnRow += 1;
}
}
}
else
- rRow += nSubSize * ( nUserSubCount - nUserSubStart ); // empty rows occur when ShowEmpty is true
+ rFilterCxt.mnRow += nSubSize * ( nUserSubCount - nUserSubStart ); // empty rows occur when ShowEmpty is true
// add extra space again if subtracted from GetSize above,
// add to own size if no children
- rRow += nExtraSpace;
-
- rRow += nMoveSubTotal;
+ rFilterCxt.mnRow += nExtraSpace;
+ rFilterCxt.mnRow += nMoveSubTotal;
}
}
@@ -1990,14 +2075,28 @@ const ScDPAggData* ScDPDataMember::GetConstAggData( long nMeasure, const ScDPSub
return pAgg;
}
-void ScDPDataMember::FillDataRow( const ScDPResultMember* pRefMember,
- uno::Sequence<sheet::DataResult>& rSequence,
- long& rCol, long nMeasure, bool bIsSubTotalRow,
- const ScDPSubTotalState& rSubState ) const
+void ScDPDataMember::FillDataRow(
+ const ScDPResultMember* pRefMember, ScDPResultFilterContext& rFilterCxt,
+ uno::Sequence<sheet::DataResult>& rSequence, long nMeasure, bool bIsSubTotalRow,
+ const ScDPSubTotalState& rSubState) const
{
+ boost::scoped_ptr<FilterStack> pFilterStack;
+ if (pResultMember)
+ {
+ // Topmost data member (pResultMember=NULL) doesn't need to be handled
+ // since its immediate parent result member is linked to the same
+ // dimension member.
+ ScDPItemData aItem;
+ const ScDPMember* pDPMember = pResultMember->GetDPMember();
+ if (pDPMember)
+ pDPMember->FillItemData(aItem);
+ pFilterStack.reset(new FilterStack(rFilterCxt.maFilters));
+ pFilterStack->pushDimValue(aItem);
+ }
+
OSL_ENSURE( pRefMember == pResultMember || !pResultMember, "bla" );
- long nStartCol = rCol;
+ long nStartCol = rFilterCxt.mnCol;
const ScDPDataDimension* pDataChild = GetChildDimension();
const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
@@ -2021,14 +2120,18 @@ void ScDPDataMember::FillDataRow( const ScDPResultMember* pRefMember,
if ( bHasChild )
{
if ( bTitleLine ) // in tabular layout the title is on a separate column
- ++rCol; // -> fill child dimension one column below
+ ++rFilterCxt.mnCol; // -> fill child dimension one column below
if ( pDataChild )
- pDataChild->FillDataRow( pRefChild, rSequence, rCol, nMeasure, bIsSubTotalRow, rSubState );
- rCol += (sal_uInt16)pRefMember->GetSize( nMeasure );
+ {
+ long nOldCol = rFilterCxt.mnCol;
+ pDataChild->FillDataRow(pRefChild, rFilterCxt, rSequence, nMeasure, bIsSubTotalRow, rSubState);
+ rFilterCxt.mnCol = nOldCol; // Revert to the old column value before the call.
+ }
+ rFilterCxt.mnCol += (sal_uInt16)pRefMember->GetSize( nMeasure );
if ( bTitleLine ) // title column is included in GetSize, so the following
- --rCol; // positions are calculated with the normal values
+ --rFilterCxt.mnCol; // positions are calculated with the normal values
}
long nUserSubStart;
@@ -2049,15 +2152,15 @@ void ScDPDataMember::FillDataRow( const ScDPResultMember* pRefMember,
long nSubSize = pResultData->GetCountForMeasure(nMeasure);
if (bHasChild)
{
- rCol -= nSubSize * ( nUserSubCount - nUserSubStart ); // GetSize includes space for SubTotal
- rCol -= nExtraSpace; // GetSize includes the empty line
+ rFilterCxt.mnCol -= nSubSize * ( nUserSubCount - nUserSubStart ); // GetSize includes space for SubTotal
+ rFilterCxt.mnCol -= nExtraSpace; // GetSize includes the empty line
}
long nMoveSubTotal = 0;
if ( bSubTotalInTitle )
{
- nMoveSubTotal = rCol - nStartCol; // force to first (title) column
- rCol = nStartCol;
+ nMoveSubTotal = rFilterCxt.mnCol - nStartCol; // force to first (title) column
+ rFilterCxt.mnCol = nStartCol;
}
for (long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
@@ -2074,8 +2177,8 @@ void ScDPDataMember::FillDataRow( const ScDPResultMember* pRefMember,
if ( nMeasure == SC_DPMEASURE_ALL )
nMemberMeasure = nSubCount;
- OSL_ENSURE( rCol < rSequence.getLength(), "bumm" );
- sheet::DataResult& rRes = rSequence.getArray()[rCol];
+ OSL_ENSURE( rFilterCxt.mnCol < rSequence.getLength(), "bumm" );
+ sheet::DataResult& rRes = rSequence.getArray()[rFilterCxt.mnCol];
if ( HasData( nMemberMeasure, aLocalSubState ) )
{
@@ -2094,15 +2197,15 @@ void ScDPDataMember::FillDataRow( const ScDPResultMember* pRefMember,
if ( bHasChild || bIsSubTotalRow )
rRes.Flags |= sheet::DataResultFlags::SUBTOTAL;
- rCol += 1;
+ rFilterCxt.maFilterSet.add(rFilterCxt.maFilters, rFilterCxt.mnCol, rFilterCxt.mnRow, rRes.Value);
+ rFilterCxt.mnCol += 1;
}
}
// add extra space again if subtracted from GetSize above,
// add to own size if no children
- rCol += nExtraSpace;
-
- rCol += nMoveSubTotal;
+ rFilterCxt.mnCol += nExtraSpace;
+ rFilterCxt.mnCol += nMoveSubTotal;
}
}
@@ -3022,11 +3125,13 @@ void ScDPResultDimension::FillMemberResults( uno::Sequence<sheet::MemberResult>*
}
}
-void ScDPResultDimension::FillDataResults( const ScDPResultMember* pRefMember,
- uno::Sequence< uno::Sequence<sheet::DataResult> >& rSequence,
- long nRow, long nMeasure ) const
+void ScDPResultDimension::FillDataResults(
+ const ScDPResultMember* pRefMember, ScDPResultFilterContext& rFilterCxt,
+ uno::Sequence< uno::Sequence<sheet::DataResult> >& rSequence, long nMeasure) const
{
- long nMemberRow = nRow;
+ FilterStack aFilterStack(rFilterCxt.maFilters);
+ aFilterStack.pushDimName(GetName(), bIsDataLayout);
+
long nMemberMeasure = nMeasure;
long nCount = maMemberArray.size();
for (long i=0; i<nCount; i++)
@@ -3045,8 +3150,7 @@ void ScDPResultDimension::FillDataResults( const ScDPResultMember* pRefMember,
pMember = maMemberArray[nSorted];
if ( pMember->IsVisible() )
- pMember->FillDataResults( pRefMember, rSequence, nMemberRow, nMemberMeasure );
- // nMemberRow is modified
+ pMember->FillDataResults(pRefMember, rFilterCxt, rSequence, nMemberMeasure);
}
}
@@ -3564,18 +3668,28 @@ void ScDPDataDimension::ProcessData( const vector< SCROW >& aDataMembers, const
OSL_FAIL("ProcessData: Member not found");
}
-void ScDPDataDimension::FillDataRow( const ScDPResultDimension* pRefDim,
- uno::Sequence<sheet::DataResult>& rSequence,
- long nCol, long nMeasure, bool bIsSubTotalRow,
- const ScDPSubTotalState& rSubState ) const
+void ScDPDataDimension::FillDataRow(
+ const ScDPResultDimension* pRefDim, ScDPResultFilterContext& rFilterCxt,
+ uno::Sequence<sheet::DataResult>& rSequence, long nMeasure, bool bIsSubTotalRow,
+ const ScDPSubTotalState& rSubState) const
{
+ OUString aDimName;
+ bool bDataLayout = false;
+ if (pResultDimension)
+ {
+ aDimName = pResultDimension->GetName();
+ bDataLayout = pResultDimension->IsDataLayout();
+ }
+
+ FilterStack aFilterStack(rFilterCxt.maFilters);
+ aFilterStack.pushDimName(aDimName, bDataLayout);
+
OSL_ENSURE( pRefDim && static_cast<size_t>(pRefDim->GetMemberCount()) == maMembers.size(), "dimensions don't match" );
OSL_ENSURE( pRefDim == pResultDimension, "wrong dim" );
const ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();
long nMemberMeasure = nMeasure;
- long nMemberCol = nCol;
long nCount = maMembers.size();
for (long i=0; i<nCount; i++)
{
@@ -3594,8 +3708,7 @@ void ScDPDataDimension::FillDataRow( const ScDPResultDimension* pRefDim,
if ( pRefMember->IsVisible() ) //! here or in ScDPDataMember::FillDataRow ???
{
const ScDPDataMember* pDataMember = maMembers[(sal_uInt16)nMemberPos];
- pDataMember->FillDataRow( pRefMember, rSequence, nMemberCol, nMemberMeasure, bIsSubTotalRow, rSubState );
- // nMemberCol is modified
+ pDataMember->FillDataRow(pRefMember, rFilterCxt, rSequence, nMemberMeasure, bIsSubTotalRow, rSubState);
}
}
}
diff --git a/sc/source/core/data/dptabsrc.cxx b/sc/source/core/data/dptabsrc.cxx
index dddbeabf6663..058a0296502c 100644
--- a/sc/source/core/data/dptabsrc.cxx
+++ b/sc/source/core/data/dptabsrc.cxx
@@ -44,6 +44,7 @@
#include "unonames.hxx"
#include "dpitemdata.hxx"
#include "dputil.hxx"
+#include "dpresfilter.hxx"
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
@@ -67,6 +68,48 @@ using ::com::sun::star::uno::Sequence;
using ::com::sun::star::uno::Any;
using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
+#include <stdio.h>
+#include <string>
+#include <sys/time.h>
+
+namespace {
+
+class stack_printer
+{
+public:
+ explicit stack_printer(const char* msg) :
+ msMsg(msg)
+ {
+ fprintf(stdout, "%s: --begin\n", msMsg.c_str());
+ mfStartTime = getTime();
+ }
+
+ ~stack_printer()
+ {
+ double fEndTime = getTime();
+ fprintf(stdout, "%s: --end (duration: %g sec)\n", msMsg.c_str(), (fEndTime - mfStartTime));
+ }
+
+ void printTime(int line) const
+ {
+ double fEndTime = getTime();
+ fprintf(stdout, "%s: --(%d) (duration: %g sec)\n", msMsg.c_str(), line, (fEndTime - mfStartTime));
+ }
+
+private:
+ double getTime() const
+ {
+ timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec + tv.tv_usec / 1000000.0;
+ }
+
+ ::std::string msMsg;
+ double mfStartTime;
+};
+
+}
+
// -----------------------------------------------------------------------
#define SC_MINCOUNT_LIMIT 1000000
@@ -380,6 +423,7 @@ long ScDPSource::GetSourceDim(long nDim)
uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResults()
throw(uno::RuntimeException)
{
+ stack_printer __stack_printer__("ScDPSource::getResults");
CreateRes_Impl(); // create pColResRoot and pRowResRoot
if ( bResultOverflow ) // set in CreateRes_Impl
@@ -403,12 +447,32 @@ uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResult
pRowAry[nRow] = aColSeq;
}
- long nSeqRow = 0;
- pRowResRoot->FillDataResults( pColResRoot, aSeq, nSeqRow, pResData->GetRowStartMeasure() );
+ ScDPResultFilterContext aFilterCxt;
+ pRowResRoot->FillDataResults(
+ pColResRoot, aFilterCxt, aSeq, pResData->GetRowStartMeasure());
+
+ maResFilterSet.swap(aFilterCxt.maFilterSet); // Keep this data for GETPIVOTDATA.
+ maResFilterSet.dump();
return aSeq;
}
+uno::Sequence<uno::Any> ScDPSource::getFilteredResults(
+ const uno::Sequence<sheet::DataPilotFieldFilter>& aFilters )
+ throw (uno::RuntimeException)
+{
+ sal_Int32 n = aFilters.getLength();
+ std::vector<sheet::DataPilotFieldFilter> aSorted;
+ aSorted.reserve(n);
+ for (sal_Int32 i = 0; i < n; ++i)
+ aSorted.push_back(aFilters[i]);
+
+ // Sort filters by order of appearance. Row fields come before column fields.
+
+
+ return uno::Sequence<uno::Any>();
+}
+
void SAL_CALL ScDPSource::refresh() throw(uno::RuntimeException)
{
disposeData();
diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx
index a5588afd84d7..a5a8d8330a49 100644
--- a/sc/source/core/tool/interpr2.cxx
+++ b/sc/source/core/tool/interpr2.cxx
@@ -45,9 +45,13 @@
#include "tokenarray.hxx"
#include "globalnames.hxx"
+
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+
#include <string.h>
#include <math.h>
+using namespace com::sun::star;
using namespace formula;
#define SCdEpsilon 1.0E-7
@@ -3078,6 +3082,81 @@ void ScInterpreter::ScGetPivotData()
RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetPivotData" );
sal_uInt8 nParamCount = GetByte();
+#if 1
+ if (!MustHaveParamCount(nParamCount, 2, 30) || (nParamCount % 2) == 1)
+ {
+ PushError(errNoRef);
+ return;
+ }
+
+ bool bOldSyntax = false;
+ if (nParamCount == 2)
+ {
+ // if the first parameter is a ref, assume old syntax
+ StackVar eFirstType = GetStackType(2);
+ if (eFirstType == svSingleRef || eFirstType == svDoubleRef)
+ bOldSyntax = true;
+ }
+
+ if (bOldSyntax)
+ {
+ // TODO: I'll handle this later.
+ PushError(errNoRef);
+ return;
+ }
+
+ // Standard syntax: separate name/value pairs
+
+ sal_uInt16 nFilterCount = nParamCount / 2 - 1;
+ uno::Sequence<sheet::DataPilotFieldFilter> aFilters(nFilterCount);
+
+ sal_uInt16 i = nFilterCount;
+ while (i-- > 0)
+ {
+ //! should allow numeric constraint values
+ aFilters[i].MatchValue = GetString();
+ aFilters[i].FieldName = GetString();
+ }
+
+ ScRange aBlock;
+ switch (GetStackType())
+ {
+ case svDoubleRef :
+ PopDoubleRef(aBlock);
+ break;
+ case svSingleRef :
+ {
+ ScAddress aAddr;
+ PopSingleRef(aAddr);
+ aBlock = aAddr;
+ }
+ break;
+ default:
+ PushError(errNoRef);
+ return;
+ }
+
+ // NOTE : MS Excel docs claim to use the 'most recent' which is not
+ // exactly the same as what we do in ScDocument::GetDPAtBlock
+ // However we do need to use GetDPABlock
+ ScDPObject* pDPObj = pDok->GetDPAtBlock(aBlock);
+ if (!pDPObj)
+ {
+ PushError(errNoRef);
+ return;
+ }
+
+ OUString aDataFieldName = GetString(); // First parameter is data field name.
+
+ double fVal = pDPObj->GetPivotData(aDataFieldName, aFilters);
+ if (rtl::math::isNan(fVal))
+ {
+ PushError(errNoRef);
+ return;
+ }
+ PushDouble(fVal);
+
+#else
if ( MustHaveParamCount( nParamCount, 2, 30 ) )
{
// there must be an even number of args
@@ -3164,6 +3243,7 @@ void ScInterpreter::ScGetPivotData()
failed :
PushError( errNoRef );
+#endif
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */