23#include <document.hxx>
27#include <osl/diagnose.h>
28#include <rtl/math.hxx>
31#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
33#include <unordered_map>
34#include <unordered_set>
40using ::com::sun::star::uno::Any;
41using ::com::sun::star::uno::Sequence;
44using ::std::shared_ptr;
53 ScDPGroupNumFilter(std::vector<ScDPItemData>&& rValues,
const ScDPNumGroupInfo& rInfo);
64ScDPGroupNumFilter::ScDPGroupNumFilter( std::vector<ScDPItemData>&& rValues,
const ScDPNumGroupInfo& rInfo) :
67bool ScDPGroupNumFilter::match(
const ScDPItemData& rCellData)
const
72 for (
const auto& rValue : maValues)
74 double fVal = rValue.GetValue();
77 if (std::signbit(fVal))
80 if (rCellData.
GetValue() < maNumInfo.mfStart)
85 if (maNumInfo.mfEnd < rCellData.
GetValue())
92 double high = low + maNumInfo.mfStep;
93 if (maNumInfo.mbIntegerOnly)
103std::vector<ScDPItemData> ScDPGroupNumFilter::getMatchValues()
const
105 return std::vector<ScDPItemData>();
117 virtual std::vector<ScDPItemData>
getMatchValues()
const override;
127ScDPGroupDateFilter::ScDPGroupDateFilter(
130 maNullDate(rNullDate),
135bool ScDPGroupDateFilter::match(
const ScDPItemData & rCellData )
const
138 using ::rtl::math::approxFloor;
139 using ::rtl::math::approxEqual;
149 sal_Int32 nGroupType = rValue.GetGroupValue().mnGroupType;
150 sal_Int32
nValue = rValue.GetGroupValue().mnValue;
155 if (rCellData.
GetValue() < maNumInfo.mfStart && !approxEqual(rCellData.
GetValue(), maNumInfo.mfStart))
162 if (rCellData.
GetValue() > maNumInfo.mfEnd && !approxEqual(rCellData.
GetValue(), maNumInfo.mfEnd))
169 if (nGroupType == DataPilotFieldGroupBy::HOURS || nGroupType == DataPilotFieldGroupBy::MINUTES ||
170 nGroupType == DataPilotFieldGroupBy::SECONDS)
175 sal_uInt16 nHour, nMinute, nSecond;
176 double fFractionOfSecond;
181 case DataPilotFieldGroupBy::HOURS:
187 case DataPilotFieldGroupBy::MINUTES:
189 if (nMinute == nValue)
193 case DataPilotFieldGroupBy::SECONDS:
195 if (nSecond == nValue)
200 OSL_FAIL(
"invalid time part");
206 Date date = maNullDate +
static_cast<sal_Int32
>(approxFloor(rCellData.
GetValue()));
209 case DataPilotFieldGroupBy::YEARS:
211 sal_Int32
year =
static_cast<sal_Int32
>(date.
GetYear());
216 case DataPilotFieldGroupBy::QUARTERS:
218 sal_Int32 qtr = 1 + (
static_cast<sal_Int32
>(date.
GetMonth()) - 1) / 3;
223 case DataPilotFieldGroupBy::MONTHS:
230 case DataPilotFieldGroupBy::DAYS:
233 sal_Int32 days = (date - yearStart) + 1;
244 OSL_FAIL(
"invalid date part");
251std::vector<ScDPItemData> ScDPGroupDateFilter::getMatchValues()
const
253 return std::vector<ScDPItemData>();
272 return nGroupValue == nChildValue;
277 case css::sheet::DataPilotFieldGroupBy::MONTHS:
279 if (nGroupPart == css::sheet::DataPilotFieldGroupBy::QUARTERS)
281 return (nGroupValue - 1 == (nChildValue - 1) / 3);
283 case css::sheet::DataPilotFieldGroupBy::DAYS:
285 if (nGroupPart == css::sheet::DataPilotFieldGroupBy::MONTHS ||
286 nGroupPart == css::sheet::DataPilotFieldGroupBy::QUARTERS)
289 aDate.AddDays(nChildValue - 1);
290 sal_Int32 nCompare = aDate.GetMonth();
291 if (nGroupPart == css::sheet::DataPilotFieldGroupBy::QUARTERS)
292 nCompare = ( ( nCompare - 1 ) / 3 ) + 1;
294 return nGroupValue == nCompare;
319 [&rData](
const ScDPItemData& rElement) { return rElement.IsCaseInsEqual(rData); });
325 [&rOther](
const ScDPItemData& rElement) { return rOther.HasElement(rElement); });
335 nSourceDim( nSource ),
337 aGroupName(
std::move( aNewName )),
338 mbDateDimension(false)
348 nSourceDim( rOther.nSourceDim ),
349 nGroupDim( rOther.nGroupDim ),
350 aGroupName( rOther.aGroupName ),
351 aItems( rOther.aItems ),
352 mbDateDimension(rOther.mbDateDimension)
368 aItems.push_back( rItem );
389 [&rData](
const ScDPGroupItem& rItem) { return rItem.HasElement(rData); });
390 if (aIter !=
aItems.end())
399 [&rName](
const ScDPGroupItem& rItem) { return rItem.GetName().IsCaseInsEqual(rName); });
400 if (aIter !=
aItems.end())
427 aGroupInfo(rInfo), mbDateDimension(false) {}
430 aGroupInfo(rOther.aGroupInfo), mbDateDimension(rOther.mbDateDimension) {}
467 pSourceData( pSource ),
470 OSL_ENSURE( pSource,
"ScDPGroupTableData: pSource can't be NULL" );
485 aGroups.push_back( aNewGroup );
602 rGroup.DisposeData();
612 pSourceData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
627class FindCaseInsensitive
635 return maValue.IsCaseInsEqual(rItem);
644 typedef std::unordered_map<tools::Long, const ScDPGroupDimension*> GroupFieldMapType;
645 GroupFieldMapType aGroupFieldIds;
647 for (
const auto& rGroup :
aGroups)
649 aGroupFieldIds.emplace(rGroup.GetGroupDim(), &rGroup);
652 vector<ScDPFilteredCache::Criterion> aNewCriteria;
653 aNewCriteria.reserve(rCriteria.size() +
aGroups.size());
658 GroupFieldMapType::const_iterator itrGrpEnd = aGroupFieldIds.end();
659 for (
const auto& rCriterion : rCriteria)
661 std::vector<ScDPItemData> aMatchValues = rCriterion.mpFilter->getMatchValues();
663 GroupFieldMapType::const_iterator itrGrp = aGroupFieldIds.find(rCriterion.mnFieldIndex);
664 if (itrGrp == itrGrpEnd)
682 std::make_shared<ScDPGroupDateFilter>(
689 std::make_shared<ScDPGroupNumFilter>(std::move(aMatchValues), *pNumInfo);
692 aNewCriteria.push_back(aCri);
697 aNewCriteria.push_back(rCriterion);
715 std::make_shared<ScDPGroupDateFilter>(
718 aNewCriteria.push_back(aCri);
726 aCri.
mpFilter = std::make_shared<ScDPFilteredCache::GroupFilter>();
731 for (
size_t i = 0;
i < nGroupItemCount; ++
i)
738 if (std::none_of(aMatchValues.begin(), aMatchValues.end(), FindCaseInsensitive(pGrpItem->
GetName())))
744 aNewCriteria.push_back(aCri);
748 rCriteria.swap(aNewCriteria);
754 pSourceData->FilterCacheTable(std::move(rCriteria), std::move(rCatDims));
760 pSourceData->GetDrillDownData(std::move(rCriteria), std::move(rCatDims), rData);
770 sal_Int32 nRowSize = rCacheTable.
getRowSize();
771 for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
806 sal_Int32 nGroupedColumns =
aGroups.size();
812 bool bDateDim =
false;
814 sal_Int32 nSourceDim = nColumn;
835 bDateDim =
pNumGroups[nColumn].IsDateDimension();
854 if (bDateDim && pNumInfo)
863 pData->GetValue(), pNumInfo, nDatePart, pFormatter);
883 [&nGroupDim](
const ScDPGroupDimension& rDim) { return rDim.GetGroupDim() == nGroupDim; });
885 return aIter->GetSourceDim();
896 return pNumGroups[nDimension].GetInfo().mbEnable ||
901 [&nDimension](
const ScDPGroupDimension& rDim) { return rDim.GetGroupDim() == nDimension; });
903 return aIter->IsDateDimension();
909 const ScDPItemData& rBaseData, sal_Int32 nBaseIndex )
const
913 return rDim.GetGroupDim() == nGroupIndex && rDim.GetSourceDim() == nBaseIndex; });
919 return isDateInGroup(rGroupData, rBaseData);
932 OSL_FAIL(
"IsInGroup: no group dimension found");
937 const ScDPItemData& rSecondData, sal_Int32 nSecondIndex )
const
941 for (
const auto& rDim :
aGroups )
949 if ( pFirstDim && pSecondDim )
953 if (bFirstDate || bSecondDate)
956 if (!bFirstDate || !bSecondDate)
958 OSL_FAIL(
"mix of date and non-date groups" );
962 return isDateInGroup(rFirstData, rSecondData);
967 if ( pFirstItem && pSecondItem )
972 else if ( pFirstItem )
977 else if ( pSecondItem )
989 OSL_FAIL(
"HasCommonElement: no group dimension found");
1011 if (rItem1 ==
nullptr || rItem2 ==
nullptr)
1020 cout <<
"--- ScDPGroupTableData" <<
endl;
1023 cout <<
"* dimension: " <<
i <<
endl;
1027 cout <<
"---" <<
endl;
sal_Int16 GetYear() const
sal_uInt16 GetMonth() const
This class represents the cached data part of the datapilot cache table implementation.
sal_Int32 GetGroupType(tools::Long nDim) const
Return a group type identifier.
const ScDPItemData * GetItemDataById(tools::Long nDim, SCROW nId) const
SCROW GetIdByItemData(tools::Long nDim, const ScDPItemData &rItem) const
void GetGroupDimMemberIds(tools::Long nDim, std::vector< SCROW > &rIds) const
const ScDPNumGroupInfo * GetNumGroupInfo(tools::Long nDim) const
interface class used for filtering of rows.
virtual std::vector< ScDPItemData > getMatchValues() const =0
virtual bool match(const ScDPItemData &rCellData) const =0
returns true if the matching condition is met for a single cell value, or false otherwise.
multi-item (group) filter.
void addMatchItem(const ScDPItemData &rItem)
This class is only a wrapper to the actual cache, to provide filtering on the raw data based on the q...
sal_Int32 getRowSize() const
bool isRowActive(sal_Int32 nRow, sal_Int32 *pLastRow=nullptr) const
Check whether a specified row is active or not.
const ScDPCache & getCache() const
tools::Long GetSourceDim() const
ScDPGroupDimension & operator=(const ScDPGroupDimension &rOther)
ScDPGroupDimension(tools::Long nSource, OUString aNewName)
const ScDPGroupItem * GetGroupByIndex(size_t nIndex) const
bool IsDateDimension() const
const ScDPGroupItem * GetGroupForData(const ScDPItemData &rData) const
tools::Long GetGroupDim() const
size_t GetItemCount() const
const ScDPGroupItem * GetGroupForName(const ScDPItemData &rName) const
std::vector< SCROW > maMemberEntries
std::vector< ScDPGroupItem > aItems
const std::vector< SCROW > & GetColumnEntries(const ScDPFilteredCache &rCacheTable) const
void SetGroupDim(tools::Long nDim)
void AddItem(const ScDPGroupItem &rItem)
ScDPItemDataVec aElements
void AddElement(const ScDPItemData &rName)
bool HasElement(const ScDPItemData &rData) const
void FillGroupFilter(ScDPFilteredCache::GroupFilter &rFilter) const
ScDPGroupItem(const ScDPItemData &rName)
const ScDPItemData & GetName() const
bool HasCommonElement(const ScDPGroupItem &rOther) const
virtual sal_Int32 GetSourceDim(sal_Int32 nDim) override
virtual const ScDPItemData * GetMemberById(sal_Int32 nDim, sal_Int32 nId) override
virtual sal_Int32 GetMembersCount(sal_Int32 nDim) override
virtual bool IsNumOrDateGroup(sal_Int32 nDim) const override
virtual bool HasCommonElement(const ScDPItemData &rFirstData, sal_Int32 nFirstIndex, const ScDPItemData &rSecondData, sal_Int32 nSecondIndex) const override
virtual void FilterCacheTable(std::vector< ScDPFilteredCache::Criterion > &&rCriteria, std::unordered_set< sal_Int32 > &&rDataDims) override
sal_Int32 GetDimensionIndex(std::u16string_view rName)
std::shared_ptr< ScDPTableData > pSourceData
virtual void CalcResults(CalcInfo &rInfo, bool bAutoShow) override
virtual void SetEmptyFlags(bool bIgnoreEmptyRows, bool bRepeatIfEmpty) override
virtual void DisposeData() override
virtual void CreateCacheTable() override
virtual bool IsDateDimension(sal_Int32 nDim) override
virtual sal_Int32 GetGroupBase(sal_Int32 nGroupDim) const override
virtual bool getIsDataLayoutDimension(sal_Int32 nColumn) override
void FillGroupValues(std::vector< SCROW > &rItems, const std::vector< sal_Int32 > &rDims)
virtual sal_uInt32 GetNumberFormat(sal_Int32 nDim) override
virtual bool IsRepeatIfEmpty() override
virtual bool IsBaseForGroup(sal_Int32 nDim) const override
void GetNumGroupInfo(tools::Long nDimension, ScDPNumGroupInfo &rInfo)
virtual void Dump() const override
bool IsNumGroupDimension(tools::Long nDimension) const
void SetNumGroupDimension(sal_Int32 nIndex, const ScDPNumGroupDimension &rGroup)
virtual const std::vector< SCROW > & GetColumnEntries(sal_Int32 nColumn) override
virtual const ScDPFilteredCache & GetCacheTable() const override
void AddGroupDimension(const ScDPGroupDimension &rGroup)
virtual ~ScDPGroupTableData() override
std::unique_ptr< ScDPNumGroupDimension[]> pNumGroups
virtual bool IsInGroup(const ScDPItemData &rGroupData, sal_Int32 nGroupIndex, const ScDPItemData &rBaseData, sal_Int32 nBaseIndex) const override
virtual void GetDrillDownData(std::vector< ScDPFilteredCache::Criterion > &&rCriteria, std::unordered_set< sal_Int32 > &&rCatDims, css::uno::Sequence< css::uno::Sequence< css::uno::Any > > &rData) override
void ModifyFilterCriteria(::std::vector< ScDPFilteredCache::Criterion > &rCriteria)
virtual void ReloadCacheTable() override
ScDPGroupTableData(const std::shared_ptr< ScDPTableData > &pSource, ScDocument *pDocument)
std::vector< ScDPGroupDimension > aGroups
virtual OUString getDimensionName(sal_Int32 nColumn) override
virtual sal_Int32 GetColumnCount() override
use (new) typed collection instead of ScStrCollection or separate Str and ValueCollection
virtual sal_Int32 Compare(sal_Int32 nDim, sal_Int32 nDataId1, sal_Int32 nDataId2) override
When assigning a string value, you can also assign an interned string whose life-cycle is managed by ...
void SetRangeStart(double fVal)
static const sal_Int32 DateFirst
static sal_Int32 Compare(const ScDPItemData &rA, const ScDPItemData &rB)
bool IsCaseInsEqual(const ScDPItemData &r) const
static const sal_Int32 DateLast
GroupValueAttr GetGroupValue() const
ScDPNumGroupDimension & operator=(const ScDPNumGroupDimension &rOther)
std::vector< SCROW > maMemberEntries
ScDPNumGroupInfo aGroupInfo
const std::vector< SCROW > & GetNumEntries(SCCOL nSourceDim, const ScDPCache *pCache) const
bool IsDateDimension() const
const ScDPNumGroupInfo & GetInfo() const
Base class that abstracts different data source types of a datapilot table.
static void ProcessRowData(CalcInfo &rInfo, const CalcRowData &rData, bool bAutoShow)
void FillRowDataFromCacheTable(sal_Int32 nRow, const ScDPFilteredCache &rCacheTable, const CalcInfo &rInfo, CalcRowData &rData)
static sal_Int32 getDatePartValue(double fValue, const ScDPNumGroupInfo *pInfo, sal_Int32 nDatePart, const SvNumberFormatter *pFormatter)
static double getNumGroupStartValue(double fValue, const ScDPNumGroupInfo &rInfo)
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
const sal_uInt16 SC_DP_LEAPYEAR
std::unique_ptr< sal_Int32[]> pData
constexpr OUStringLiteral aData
PyObject_HEAD PyUNO_callable_Internals * members
TOOLS_DLLPUBLIC SvStream & endl(SvStream &rStr)
single filtering criterion.
std::shared_ptr< FilterBase > mpFilter
This structure stores dimension information used when calculating results.
::std::vector< sal_Int32 > aPageDims
::std::vector< sal_Int32 > aRowLevelDims
::std::vector< sal_Int32 > aColLevelDims
This structure stores vector arrays that hold intermediate data for each row during cache table itera...