Kaydet (Commit) ac569ed4 authored tarafından Kohei Yoshida's avatar Kohei Yoshida

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
üst 687a821e
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <com/sun/star/uno/XInterface.idl> #include <com/sun/star/uno/XInterface.idl>
#include <com/sun/star/sheet/DataResult.idl> #include <com/sun/star/sheet/DataResult.idl>
#include <com/sun/star/sheet/DataPilotFieldFilter.idl>
module com { module sun { module star { module sheet { module com { module sun { module star { module sheet {
...@@ -44,6 +45,8 @@ interface XDataPilotResults: com::sun::star::uno::XInterface ...@@ -44,6 +45,8 @@ interface XDataPilotResults: com::sun::star::uno::XInterface
*/ */
sequence< sequence< DataResult > > getResults(); sequence< sequence< DataResult > > getResults();
sequence<any> getFilteredResults(
[in] sequence<com::sun::star::sheet::DataPilotFieldFilter> aFilters );
}; };
......
...@@ -135,6 +135,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\ ...@@ -135,6 +135,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
sc/source/core/data/dpobject \ sc/source/core/data/dpobject \
sc/source/core/data/dpoutput \ sc/source/core/data/dpoutput \
sc/source/core/data/dpoutputgeometry \ sc/source/core/data/dpoutputgeometry \
sc/source/core/data/dpresfilter \
sc/source/core/data/dpsave \ sc/source/core/data/dpsave \
sc/source/core/data/dpsdbtab \ sc/source/core/data/dpsdbtab \
sc/source/core/data/dpshttab \ sc/source/core/data/dpshttab \
......
...@@ -62,6 +62,11 @@ public: ...@@ -62,6 +62,11 @@ public:
sal_Int32 mnValue; sal_Int32 mnValue;
}; };
struct Hash
{
size_t operator() (const ScDPItemData& rVal) const;
};
private: private:
union { union {
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#ifndef __SC_DPMACROS_HXX__ #ifndef __SC_DPMACROS_HXX__
#define __SC_DPMACROS_HXX__ #define __SC_DPMACROS_HXX__
#define DEBUG_PIVOT_TABLE 0 #define DEBUG_PIVOT_TABLE 1
#if DEBUG_PIVOT_TABLE #if DEBUG_PIVOT_TABLE
#include <iostream> #include <iostream>
......
...@@ -179,6 +179,11 @@ public: ...@@ -179,6 +179,11 @@ public:
Rectangle& rPosRect, sal_uInt16& rOrient, long& rDimPos ); Rectangle& rPosRect, sal_uInt16& rOrient, long& rDimPos );
bool IsFilterButton( const ScAddress& rPos ); 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 */ bool GetPivotData( ScDPGetPivotDataField& rTarget, /* returns result */
const std::vector< ScDPGetPivotDataField >& rFilters ); const std::vector< ScDPGetPivotDataField >& rFilters );
bool ParseFilters( ScDPGetPivotDataField& rTarget, bool ParseFilters( ScDPGetPivotDataField& rTarget,
......
/* -*- 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: */
...@@ -52,6 +52,7 @@ class ScDPResultVisibilityData; ...@@ -52,6 +52,7 @@ class ScDPResultVisibilityData;
struct ScDPValue; struct ScDPValue;
class ScDPItemData; class ScDPItemData;
struct ScDPResultFilterContext;
/** /**
* Member names that are being processed for InitFrom/LateInitFrom (needed * Member names that are being processed for InitFrom/LateInitFrom (needed
...@@ -403,11 +404,12 @@ public: ...@@ -403,11 +404,12 @@ public:
com::sun::star::sheet::MemberResult>* pSequences, com::sun::star::sheet::MemberResult>* pSequences,
long& rPos, long nMeasure, bool bRoot, const OUString* pMemberName, const OUString* pMemberCaption ); long& rPos, long nMeasure, bool bRoot, const OUString* pMemberName, const OUString* pMemberCaption );
void FillDataResults( const ScDPResultMember* pRefMember, void FillDataResults(
com::sun::star::uno::Sequence< const ScDPResultMember* pRefMember, ScDPResultFilterContext& rFilterCxt,
com::sun::star::uno::Sequence< com::sun::star::uno::Sequence<
com::sun::star::sheet::DataResult> >& rSequence, com::sun::star::uno::Sequence<
long& rRow, long nMeasure ) const; com::sun::star::sheet::DataResult> >& rSequence,
long nMeasure) const;
void UpdateDataResults( const ScDPResultMember* pRefMember, long nMeasure ) const; void UpdateDataResults( const ScDPResultMember* pRefMember, long nMeasure ) const;
void UpdateRunningTotals( const ScDPResultMember* pRefMember, long nMeasure, void UpdateRunningTotals( const ScDPResultMember* pRefMember, long nMeasure,
...@@ -471,10 +473,12 @@ public: ...@@ -471,10 +473,12 @@ public:
const ScDPAggData* GetConstAggData( long nMeasure, const ScDPSubTotalState& rSubState ) const; const ScDPAggData* GetConstAggData( long nMeasure, const ScDPSubTotalState& rSubState ) const;
ScDPAggData* GetAggData( long nMeasure, const ScDPSubTotalState& rSubState ); ScDPAggData* GetAggData( long nMeasure, const ScDPSubTotalState& rSubState );
void FillDataRow( const ScDPResultMember* pRefMember, void FillDataRow(
com::sun::star::uno::Sequence<com::sun::star::sheet::DataResult>& rSequence, const ScDPResultMember* pRefMember,
long& rCol, long nMeasure, bool bIsSubTotalRow, ScDPResultFilterContext& rFilterCxt,
const ScDPSubTotalState& rSubState ) const; 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, void UpdateDataRow( const ScDPResultMember* pRefMember, long nMeasure, bool bIsSubTotalRow,
const ScDPSubTotalState& rSubState ); const ScDPSubTotalState& rSubState );
...@@ -557,11 +561,13 @@ public: ...@@ -557,11 +561,13 @@ public:
com::sun::star::sheet::MemberResult>* pSequences, com::sun::star::sheet::MemberResult>* pSequences,
long nStart, long nMeasure ); long nStart, long nMeasure );
void FillDataResults( const ScDPResultMember* pRefMember, void FillDataResults(
com::sun::star::uno::Sequence< const ScDPResultMember* pRefMember,
com::sun::star::uno::Sequence< ScDPResultFilterContext& rFilterCxt,
com::sun::star::sheet::DataResult> >& rSequence, com::sun::star::uno::Sequence<
long nRow, long nMeasure ) const; com::sun::star::uno::Sequence<
com::sun::star::sheet::DataResult> >& rSequence,
long nMeasure) const;
void UpdateDataResults( const ScDPResultMember* pRefMember, long nMeasure ) const; void UpdateDataResults( const ScDPResultMember* pRefMember, long nMeasure ) const;
void UpdateRunningTotals( const ScDPResultMember* pRefMember, long nMeasure, void UpdateRunningTotals( const ScDPResultMember* pRefMember, long nMeasure,
...@@ -629,10 +635,11 @@ public: ...@@ -629,10 +635,11 @@ public:
void InitFrom( const ScDPResultDimension* pDim ); // recursive void InitFrom( const ScDPResultDimension* pDim ); // recursive
void ProcessData( const ::std::vector< SCROW >& aDataMembers, const ::std::vector<ScDPValue>& aValues, void ProcessData( const ::std::vector< SCROW >& aDataMembers, const ::std::vector<ScDPValue>& aValues,
const ScDPSubTotalState& rSubState ); const ScDPSubTotalState& rSubState );
void FillDataRow( const ScDPResultDimension* pRefDim, void FillDataRow(
com::sun::star::uno::Sequence<com::sun::star::sheet::DataResult>& rSequence, const ScDPResultDimension* pRefDim,
long nCol, long nMeasure, bool bIsSubTotalRow, ScDPResultFilterContext& rFilterCxt,
const ScDPSubTotalState& rSubState ) const; 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, void UpdateDataRow( const ScDPResultDimension* pRefDim, long nMeasure, bool bIsSubTotalRow,
const ScDPSubTotalState& rSubState ) const; const ScDPSubTotalState& rSubState ) const;
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "dptabdat.hxx" #include "dptabdat.hxx"
#include "dpglobal.hxx" #include "dpglobal.hxx"
#include "dpresfilter.hxx"
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp> #include <boost/unordered_set.hpp>
...@@ -103,6 +104,7 @@ private: ...@@ -103,6 +104,7 @@ private:
std::vector<long> maRowDims; std::vector<long> maRowDims;
std::vector<long> maDataDims; std::vector<long> maDataDims;
std::vector<long> maPageDims; std::vector<long> maPageDims;
ScDPResultFilterSet maResFilterSet;
bool bColumnGrand; bool bColumnGrand;
bool bRowGrand; bool bRowGrand;
...@@ -199,6 +201,11 @@ public: ...@@ -199,6 +201,11 @@ public:
::com::sun::star::sheet::DataResult > > SAL_CALL getResults( ) ::com::sun::star::sheet::DataResult > > SAL_CALL getResults( )
throw(::com::sun::star::uno::RuntimeException); 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 // XRefreshable
virtual void SAL_CALL refresh() throw(::com::sun::star::uno::RuntimeException); virtual void SAL_CALL refresh() throw(::com::sun::star::uno::RuntimeException);
virtual void SAL_CALL addRefreshListener( const ::com::sun::star::uno::Reference< virtual void SAL_CALL addRefreshListener( const ::com::sun::star::uno::Reference<
......
...@@ -29,6 +29,33 @@ ...@@ -29,6 +29,33 @@
const sal_Int32 ScDPItemData::DateFirst = -1; const sal_Int32 ScDPItemData::DateFirst = -1;
const sal_Int32 ScDPItemData::DateLast = 10000; 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) sal_Int32 ScDPItemData::Compare(const ScDPItemData& rA, const ScDPItemData& rB)
{ {
if (rA.meType != rB.meType) if (rA.meType != rB.meType)
...@@ -337,10 +364,10 @@ OUString ScDPItemData::GetString() const ...@@ -337,10 +364,10 @@ OUString ScDPItemData::GetString() const
case Error: case Error:
return *mpString; return *mpString;
case Value: case Value:
case RangeStart:
return OUString::valueOf(mfValue); return OUString::valueOf(mfValue);
case GroupValue: case GroupValue:
case RangeStart: return OUString::valueOf(maGroupValue.mnValue);
return OUString::createFromAscii("fail");
case Empty: case Empty:
default: default:
; ;
......
...@@ -1278,6 +1278,57 @@ void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHead ...@@ -1278,6 +1278,57 @@ void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHead
aPosData.PositionData >>= rData; 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 // Returns sal_True on success and stores the result in rTarget
bool ScDPObject::GetPivotData( ScDPGetPivotDataField& rTarget, bool ScDPObject::GetPivotData( ScDPGetPivotDataField& rTarget,
const std::vector< ScDPGetPivotDataField >& rFilters ) const std::vector< ScDPGetPivotDataField >& rFilters )
......
/* -*- 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: */
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "unonames.hxx" #include "unonames.hxx"
#include "dpitemdata.hxx" #include "dpitemdata.hxx"
#include "dputil.hxx" #include "dputil.hxx"
#include "dpresfilter.hxx"
#include <com/sun/star/beans/PropertyAttribute.hpp> #include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/sheet/DataPilotFieldFilter.hpp> #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
...@@ -67,6 +68,48 @@ using ::com::sun::star::uno::Sequence; ...@@ -67,6 +68,48 @@ using ::com::sun::star::uno::Sequence;
using ::com::sun::star::uno::Any; using ::com::sun::star::uno::Any;
using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo; 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 #define SC_MINCOUNT_LIMIT 1000000
...@@ -380,6 +423,7 @@ long ScDPSource::GetSourceDim(long nDim) ...@@ -380,6 +423,7 @@ long ScDPSource::GetSourceDim(long nDim)
uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResults() uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResults()
throw(uno::RuntimeException) throw(uno::RuntimeException)
{ {
stack_printer __stack_printer__("ScDPSource::getResults");
CreateRes_Impl(); // create pColResRoot and pRowResRoot CreateRes_Impl(); // create pColResRoot and pRowResRoot
if ( bResultOverflow ) // set in CreateRes_Impl if ( bResultOverflow ) // set in CreateRes_Impl
...@@ -403,12 +447,32 @@ uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResult ...@@ -403,12 +447,32 @@ uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResult
pRowAry[nRow] = aColSeq; pRowAry[nRow] = aColSeq;
} }
long nSeqRow = 0; ScDPResultFilterContext aFilterCxt;
pRowResRoot->FillDataResults( pColResRoot, aSeq, nSeqRow, pResData->GetRowStartMeasure() ); pRowResRoot->FillDataResults(
pColResRoot, aFilterCxt, aSeq, pResData->GetRowStartMeasure());
maResFilterSet.swap(aFilterCxt.maFilterSet); // Keep this data for GETPIVOTDATA.
maResFilterSet.dump();
return aSeq; 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) void SAL_CALL ScDPSource::refresh() throw(uno::RuntimeException)
{ {
disposeData(); disposeData();
......
...@@ -45,9 +45,13 @@ ...@@ -45,9 +45,13 @@
#include "tokenarray.hxx" #include "tokenarray.hxx"
#include "globalnames.hxx" #include "globalnames.hxx"
#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
using namespace com::sun::star;
using namespace formula; using namespace formula;
#define SCdEpsilon 1.0E-7 #define SCdEpsilon 1.0E-7
...@@ -3078,6 +3082,81 @@ void ScInterpreter::ScGetPivotData() ...@@ -3078,6 +3082,81 @@ void ScInterpreter::ScGetPivotData()
RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetPivotData" ); RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetPivotData" );
sal_uInt8 nParamCount = GetByte(); 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 ) ) if ( MustHaveParamCount( nParamCount, 2, 30 ) )
{ {
// there must be an even number of args // there must be an even number of args
...@@ -3164,6 +3243,7 @@ void ScInterpreter::ScGetPivotData() ...@@ -3164,6 +3243,7 @@ void ScInterpreter::ScGetPivotData()
failed : failed :
PushError( errNoRef ); PushError( errNoRef );
#endif
} }
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment