1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "dpgroup.hxx"
23 #include "document.hxx"
24 #include "dpfilteredcache.hxx"
25 #include "dptabsrc.hxx"
26 #include "dptabres.hxx"
27 #include "dpobject.hxx"
28 #include "dpglobal.hxx"
30 #include "globalnames.hxx"
32 #include <rtl/math.hxx>
34 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
35 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
36 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
39 #include <boost/unordered_map.hpp>
40 #include <boost/unordered_set.hpp>
42 using namespace ::com::sun::star
;
43 using ::com::sun::star::uno::Any
;
44 using ::com::sun::star::uno::Reference
;
45 using ::com::sun::star::uno::Sequence
;
46 using ::com::sun::star::uno::UNO_QUERY
;
47 using ::com::sun::star::uno::UNO_QUERY_THROW
;
50 using ::boost::shared_ptr
;
52 const sal_uInt16 SC_DP_LEAPYEAR
= 1648; // arbitrary leap year for date calculations
54 class ScDPGroupNumFilter
: public ScDPFilteredCache::FilterBase
57 ScDPGroupNumFilter(const std::vector
<ScDPItemData
>& rValues
, const ScDPNumGroupInfo
& rInfo
);
58 virtual ~ScDPGroupNumFilter() {}
59 virtual bool match(const ScDPItemData
&rCellData
) const;
60 virtual std::vector
<ScDPItemData
> getMatchValues() const;
62 std::vector
<ScDPItemData
> maValues
;
63 ScDPNumGroupInfo maNumInfo
;
66 ScDPGroupNumFilter::ScDPGroupNumFilter(const std::vector
<ScDPItemData
>& rValues
, const ScDPNumGroupInfo
& rInfo
) :
67 maValues(rValues
), maNumInfo(rInfo
) {}
69 bool ScDPGroupNumFilter::match(const ScDPItemData
& rCellData
) const
71 if (rCellData
.GetType() != ScDPItemData::Value
)
74 std::vector
<ScDPItemData
>::const_iterator it
= maValues
.begin(), itEnd
= maValues
.end();
75 for (; it
!= itEnd
; ++it
)
77 double fVal
= it
->GetValue();
78 if (rtl::math::isInf(fVal
))
80 if (rtl::math::isSignBitSet(fVal
))
82 // Less than the min value.
83 if (rCellData
.GetValue() < maNumInfo
.mfStart
)
87 // Greater than the max value.
88 if (maNumInfo
.mfEnd
< rCellData
.GetValue())
95 double high
= low
+ maNumInfo
.mfStep
;
96 if (maNumInfo
.mbIntegerOnly
)
99 if (low
<= rCellData
.GetValue() && rCellData
.GetValue() < high
)
106 std::vector
<ScDPItemData
> ScDPGroupNumFilter::getMatchValues() const
108 return std::vector
<ScDPItemData
>();
111 class ScDPGroupDateFilter
: public ScDPFilteredCache::FilterBase
114 virtual ~ScDPGroupDateFilter() {}
116 const std::vector
<ScDPItemData
>& rValues
, const Date
& rNullDate
, const ScDPNumGroupInfo
& rNumInfo
);
118 virtual bool match(const ScDPItemData
& rCellData
) const;
119 virtual std::vector
<ScDPItemData
> getMatchValues() const;
122 ScDPGroupDateFilter(); // disabled
124 std::vector
<ScDPItemData
> maValues
;
126 ScDPNumGroupInfo maNumInfo
;
129 // ----------------------------------------------------------------------------
131 ScDPGroupDateFilter::ScDPGroupDateFilter(
132 const std::vector
<ScDPItemData
>& rValues
, const Date
& rNullDate
, const ScDPNumGroupInfo
& rNumInfo
) :
134 maNullDate(rNullDate
),
139 bool ScDPGroupDateFilter::match( const ScDPItemData
& rCellData
) const
141 using namespace ::com::sun::star::sheet
;
142 using ::rtl::math::approxFloor
;
143 using ::rtl::math::approxEqual
;
145 if ( !rCellData
.IsValue() )
148 std::vector
<ScDPItemData
>::const_iterator it
= maValues
.begin(), itEnd
= maValues
.end();
149 for (; it
!= itEnd
; ++it
)
151 const ScDPItemData
& rValue
= *it
;
152 if (rValue
.GetType() != ScDPItemData::GroupValue
)
155 sal_Int32 nGroupType
= rValue
.GetGroupValue().mnGroupType
;
156 sal_Int32 nValue
= rValue
.GetGroupValue().mnValue
;
158 // Start and end dates are inclusive. (An end date without a time value
159 // is included, while an end date with a time value is not.)
161 if (rCellData
.GetValue() < maNumInfo
.mfStart
&& !approxEqual(rCellData
.GetValue(), maNumInfo
.mfStart
))
163 if (nValue
== ScDPItemData::DateFirst
)
168 if (rCellData
.GetValue() > maNumInfo
.mfEnd
&& !approxEqual(rCellData
.GetValue(), maNumInfo
.mfEnd
))
170 if (nValue
== ScDPItemData::DateLast
)
175 if (nGroupType
== DataPilotFieldGroupBy::HOURS
|| nGroupType
== DataPilotFieldGroupBy::MINUTES
||
176 nGroupType
== DataPilotFieldGroupBy::SECONDS
)
179 // (as in the cell functions, ScInterpreter::ScGetHour etc.: seconds are rounded)
181 double time
= rCellData
.GetValue() - approxFloor(rCellData
.GetValue());
182 long seconds
= static_cast<long>(approxFloor(time
*DATE_TIME_FACTOR
+ 0.5));
186 case DataPilotFieldGroupBy::HOURS
:
188 sal_Int32 hrs
= seconds
/ 3600;
193 case DataPilotFieldGroupBy::MINUTES
:
195 sal_Int32 minutes
= (seconds
% 3600) / 60;
196 if (minutes
== nValue
)
200 case DataPilotFieldGroupBy::SECONDS
:
202 sal_Int32 sec
= seconds
% 60;
208 OSL_FAIL("invalid time part");
214 Date date
= maNullDate
+ static_cast<long>(approxFloor(rCellData
.GetValue()));
217 case DataPilotFieldGroupBy::YEARS
:
219 sal_Int32 year
= static_cast<sal_Int32
>(date
.GetYear());
224 case DataPilotFieldGroupBy::QUARTERS
:
226 sal_Int32 qtr
= 1 + (static_cast<sal_Int32
>(date
.GetMonth()) - 1) / 3;
231 case DataPilotFieldGroupBy::MONTHS
:
233 sal_Int32 month
= static_cast<sal_Int32
>(date
.GetMonth());
238 case DataPilotFieldGroupBy::DAYS
:
240 Date
yearStart(1, 1, date
.GetYear());
241 sal_Int32 days
= (date
- yearStart
) + 1; // Jan 01 has value 1
242 if (days
>= 60 && !date
.IsLeapYear())
244 // This is not a leap year. Adjust the value accordingly.
252 OSL_FAIL("invalid date part");
259 std::vector
<ScDPItemData
> ScDPGroupDateFilter::getMatchValues() const
261 return std::vector
<ScDPItemData
>();
266 bool isDateInGroup(const ScDPItemData
& rGroupItem
, const ScDPItemData
& rChildItem
)
268 if (rGroupItem
.GetType() != ScDPItemData::GroupValue
|| rChildItem
.GetType() != ScDPItemData::GroupValue
)
271 sal_Int32 nGroupPart
= rGroupItem
.GetGroupValue().mnGroupType
;
272 sal_Int32 nGroupValue
= rGroupItem
.GetGroupValue().mnValue
;
273 sal_Int32 nChildPart
= rChildItem
.GetGroupValue().mnGroupType
;
274 sal_Int32 nChildValue
= rChildItem
.GetGroupValue().mnValue
;
276 if (nGroupValue
== ScDPItemData::DateFirst
|| nGroupValue
== ScDPItemData::DateLast
||
277 nChildValue
== ScDPItemData::DateFirst
|| nChildValue
== ScDPItemData::DateLast
)
279 // first/last entry matches only itself
280 return nGroupValue
== nChildValue
;
283 switch (nChildPart
) // inner part
285 case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS
:
286 // a month is only contained in its quarter
287 if (nGroupPart
== com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS
)
288 // months and quarters are both 1-based
289 return (nGroupValue
- 1 == (nChildValue
- 1) / 3);
291 case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS
:
292 // a day is only contained in its quarter or month
293 if (nGroupPart
== com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS
||
294 nGroupPart
== com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS
)
296 Date
aDate(1, 1, SC_DP_LEAPYEAR
);
297 aDate
+= (nChildValue
- 1); // days are 1-based
298 sal_Int32 nCompare
= aDate
.GetMonth();
299 if (nGroupPart
== com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS
)
300 nCompare
= ( ( nCompare
- 1 ) / 3 ) + 1; // get quarter from date
302 return nGroupValue
== nCompare
;
314 ScDPGroupItem::ScDPGroupItem( const ScDPItemData
& rName
) :
319 ScDPGroupItem::~ScDPGroupItem()
323 void ScDPGroupItem::AddElement( const ScDPItemData
& rName
)
325 aElements
.push_back( rName
);
328 bool ScDPGroupItem::HasElement( const ScDPItemData
& rData
) const
330 for ( ScDPItemDataVec::const_iterator
aIter(aElements
.begin()); aIter
!= aElements
.end(); ++aIter
)
331 if ( aIter
->IsCaseInsEqual( rData
) )
337 bool ScDPGroupItem::HasCommonElement( const ScDPGroupItem
& rOther
) const
339 for ( ScDPItemDataVec::const_iterator
aIter(aElements
.begin()); aIter
!= aElements
.end(); ++aIter
)
340 if ( rOther
.HasElement( *aIter
) )
346 void ScDPGroupItem::FillGroupFilter( ScDPFilteredCache::GroupFilter
& rFilter
) const
348 ScDPItemDataVec::const_iterator itrEnd
= aElements
.end();
349 for (ScDPItemDataVec::const_iterator itr
= aElements
.begin(); itr
!= itrEnd
; ++itr
)
350 rFilter
.addMatchItem(*itr
);
353 // -----------------------------------------------------------------------
355 ScDPGroupDimension::ScDPGroupDimension( long nSource
, const OUString
& rNewName
) :
356 nSourceDim( nSource
),
358 aGroupName( rNewName
),
359 mbDateDimension(false)
363 ScDPGroupDimension::~ScDPGroupDimension()
365 maMemberEntries
.clear();
368 ScDPGroupDimension::ScDPGroupDimension( const ScDPGroupDimension
& rOther
) :
369 nSourceDim( rOther
.nSourceDim
),
370 nGroupDim( rOther
.nGroupDim
),
371 aGroupName( rOther
.aGroupName
),
372 aItems( rOther
.aItems
),
373 mbDateDimension(rOther
.mbDateDimension
)
377 ScDPGroupDimension
& ScDPGroupDimension::operator=( const ScDPGroupDimension
& rOther
)
379 nSourceDim
= rOther
.nSourceDim
;
380 nGroupDim
= rOther
.nGroupDim
;
381 aGroupName
= rOther
.aGroupName
;
382 aItems
= rOther
.aItems
;
383 mbDateDimension
= rOther
.mbDateDimension
;
387 void ScDPGroupDimension::AddItem( const ScDPGroupItem
& rItem
)
389 aItems
.push_back( rItem
);
392 void ScDPGroupDimension::SetGroupDim( long nDim
)
397 const std::vector
<SCROW
>& ScDPGroupDimension::GetColumnEntries(
398 const ScDPFilteredCache
& rCacheTable
) const
400 if (!maMemberEntries
.empty())
401 return maMemberEntries
;
403 rCacheTable
.getCache()->GetGroupDimMemberIds(nGroupDim
, maMemberEntries
);
404 return maMemberEntries
;
409 const ScDPGroupItem
* ScDPGroupDimension::GetGroupForData( const ScDPItemData
& rData
) const
411 for (ScDPGroupItemVec::const_iterator aIter
= aItems
.begin(); aIter
!= aItems
.end(); ++aIter
)
412 if (aIter
->HasElement(rData
))
418 const ScDPGroupItem
* ScDPGroupDimension::GetGroupForName( const ScDPItemData
& rName
) const
420 for ( ScDPGroupItemVec::const_iterator
aIter(aItems
.begin()); aIter
!= aItems
.end(); ++aIter
)
421 if ( aIter
->GetName().IsCaseInsEqual( rName
) )
427 const ScDPGroupItem
* ScDPGroupDimension::GetGroupByIndex( size_t nIndex
) const
429 if (nIndex
>= aItems
.size())
432 return &aItems
[nIndex
];
435 void ScDPGroupDimension::DisposeData()
437 maMemberEntries
.clear();
440 void ScDPGroupDimension::SetDateDimension()
442 mbDateDimension
= true;
445 bool ScDPGroupDimension::IsDateDimension() const
447 return mbDateDimension
;
450 // -----------------------------------------------------------------------
452 ScDPNumGroupDimension::ScDPNumGroupDimension() : mbDateDimension(false) {}
454 ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupInfo
& rInfo
) :
455 aGroupInfo(rInfo
), mbDateDimension(false) {}
457 ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupDimension
& rOther
) :
458 aGroupInfo(rOther
.aGroupInfo
), mbDateDimension(rOther
.mbDateDimension
) {}
460 ScDPNumGroupDimension
& ScDPNumGroupDimension::operator=( const ScDPNumGroupDimension
& rOther
)
462 aGroupInfo
= rOther
.aGroupInfo
;
463 mbDateDimension
= rOther
.mbDateDimension
;
467 void ScDPNumGroupDimension::DisposeData()
469 aGroupInfo
= ScDPNumGroupInfo();
470 maMemberEntries
.clear();
473 bool ScDPNumGroupDimension::IsDateDimension() const
475 return mbDateDimension
;
478 ScDPNumGroupDimension::~ScDPNumGroupDimension()
482 void ScDPNumGroupDimension::SetDateDimension()
484 aGroupInfo
.mbEnable
= true; //! or query both?
485 mbDateDimension
= true;
488 const std::vector
<SCROW
>& ScDPNumGroupDimension::GetNumEntries(
489 SCCOL nSourceDim
, const ScDPCache
* pCache
) const
491 if (!maMemberEntries
.empty())
492 return maMemberEntries
;
494 pCache
->GetGroupDimMemberIds(nSourceDim
, maMemberEntries
);
495 return maMemberEntries
;
498 ScDPGroupTableData::ScDPGroupTableData( const shared_ptr
<ScDPTableData
>& pSource
, ScDocument
* pDocument
) :
499 ScDPTableData(pDocument
),
500 pSourceData( pSource
),
503 OSL_ENSURE( pSource
, "ScDPGroupTableData: pSource can't be NULL" );
506 nSourceCount
= pSource
->GetColumnCount(); // real columns, excluding data layout
507 pNumGroups
= new ScDPNumGroupDimension
[nSourceCount
];
510 ScDPGroupTableData::~ScDPGroupTableData()
515 boost::shared_ptr
<ScDPTableData
> ScDPGroupTableData::GetSourceTableData()
520 void ScDPGroupTableData::AddGroupDimension( const ScDPGroupDimension
& rGroup
)
522 ScDPGroupDimension
aNewGroup( rGroup
);
523 aNewGroup
.SetGroupDim( GetColumnCount() ); // new dimension will be at the end
524 aGroups
.push_back( aNewGroup
);
525 aGroupNames
.insert(aNewGroup
.GetName());
528 void ScDPGroupTableData::SetNumGroupDimension( long nIndex
, const ScDPNumGroupDimension
& rGroup
)
530 if ( nIndex
< nSourceCount
)
532 pNumGroups
[nIndex
] = rGroup
;
534 // automatic minimum / maximum is handled in GetNumEntries
538 long ScDPGroupTableData::GetDimensionIndex( const OUString
& rName
)
540 for (long i
= 0; i
< nSourceCount
; ++i
) // nSourceCount excludes data layout
541 if (pSourceData
->getDimensionName(i
).equals(rName
)) //! ignore case?
546 long ScDPGroupTableData::GetColumnCount()
548 return nSourceCount
+ aGroups
.size();
551 bool ScDPGroupTableData::IsNumGroupDimension( long nDimension
) const
553 return ( nDimension
< nSourceCount
&& pNumGroups
[nDimension
].GetInfo().mbEnable
);
556 void ScDPGroupTableData::GetNumGroupInfo(long nDimension
, ScDPNumGroupInfo
& rInfo
)
558 if ( nDimension
< nSourceCount
)
559 rInfo
= pNumGroups
[nDimension
].GetInfo();
561 long ScDPGroupTableData::GetMembersCount( long nDim
)
563 const std::vector
< SCROW
>& members
= GetColumnEntries( nDim
);
564 return members
.size();
566 const std::vector
< SCROW
>& ScDPGroupTableData::GetColumnEntries( long nColumn
)
568 if ( nColumn
>= nSourceCount
)
570 if ( getIsDataLayoutDimension( nColumn
) ) // data layout dimension?
571 nColumn
= nSourceCount
; // index of data layout in source data
574 const ScDPGroupDimension
& rGroupDim
= aGroups
[nColumn
- nSourceCount
];
575 return rGroupDim
.GetColumnEntries( GetCacheTable() );
579 if ( IsNumGroupDimension( nColumn
) )
581 // dimension number is unchanged for numerical groups
582 return pNumGroups
[nColumn
].GetNumEntries(
583 static_cast<SCCOL
>(nColumn
), GetCacheTable().getCache());
586 return pSourceData
->GetColumnEntries( nColumn
);
589 const ScDPItemData
* ScDPGroupTableData::GetMemberById( long nDim
, long nId
)
591 return pSourceData
->GetMemberById( nDim
, nId
);
594 OUString
ScDPGroupTableData::getDimensionName(long nColumn
)
596 if ( nColumn
>= nSourceCount
)
598 if ( nColumn
== sal::static_int_cast
<long>( nSourceCount
+ aGroups
.size() ) ) // data layout dimension?
599 nColumn
= nSourceCount
; // index of data layout in source data
601 return aGroups
[nColumn
- nSourceCount
].GetName();
604 return pSourceData
->getDimensionName( nColumn
);
607 sal_Bool
ScDPGroupTableData::getIsDataLayoutDimension(long nColumn
)
609 // position of data layout dimension is moved from source data
610 return ( nColumn
== sal::static_int_cast
<long>( nSourceCount
+ aGroups
.size() ) ); // data layout dimension?
613 sal_Bool
ScDPGroupTableData::IsDateDimension(long nDim
)
615 if ( nDim
>= nSourceCount
)
617 if ( nDim
== sal::static_int_cast
<long>( nSourceCount
+ aGroups
.size() ) ) // data layout dimension?
618 nDim
= nSourceCount
; // index of data layout in source data
620 nDim
= aGroups
[nDim
- nSourceCount
].GetSourceDim(); // look at original dimension
623 return pSourceData
->IsDateDimension( nDim
);
626 sal_uLong
ScDPGroupTableData::GetNumberFormat(long nDim
)
628 if ( nDim
>= nSourceCount
)
630 if ( nDim
== sal::static_int_cast
<long>( nSourceCount
+ aGroups
.size() ) ) // data layout dimension?
631 nDim
= nSourceCount
; // index of data layout in source data
633 nDim
= aGroups
[nDim
- nSourceCount
].GetSourceDim(); // look at original dimension
636 return pSourceData
->GetNumberFormat( nDim
);
639 void ScDPGroupTableData::DisposeData()
641 for ( ScDPGroupDimensionVec::iterator
aIter(aGroups
.begin()); aIter
!= aGroups
.end(); ++aIter
)
642 aIter
->DisposeData();
644 for ( long i
=0; i
<nSourceCount
; i
++ )
645 pNumGroups
[i
].DisposeData();
647 pSourceData
->DisposeData();
650 void ScDPGroupTableData::SetEmptyFlags( sal_Bool bIgnoreEmptyRows
, sal_Bool bRepeatIfEmpty
)
652 pSourceData
->SetEmptyFlags( bIgnoreEmptyRows
, bRepeatIfEmpty
);
655 bool ScDPGroupTableData::IsRepeatIfEmpty()
657 return pSourceData
->IsRepeatIfEmpty();
660 void ScDPGroupTableData::CreateCacheTable()
662 pSourceData
->CreateCacheTable();
667 class FindCaseInsensitive
: std::unary_function
<ScDPItemData
, bool>
669 ScDPItemData maValue
;
671 FindCaseInsensitive(const ScDPItemData
& rVal
) : maValue(rVal
) {}
673 bool operator() (const ScDPItemData
& rItem
) const
675 return maValue
.IsCaseInsEqual(rItem
);
681 void ScDPGroupTableData::ModifyFilterCriteria(vector
<ScDPFilteredCache::Criterion
>& rCriteria
)
683 // Build dimension ID to object map for group dimensions.
684 typedef boost::unordered_map
<long, const ScDPGroupDimension
*> GroupFieldMapType
;
685 GroupFieldMapType aGroupFieldIds
;
687 ScDPGroupDimensionVec::const_iterator itr
= aGroups
.begin(), itrEnd
= aGroups
.end();
688 for (; itr
!= itrEnd
; ++itr
)
690 aGroupFieldIds
.insert(
691 GroupFieldMapType::value_type(itr
->GetGroupDim(), &(*itr
)));
695 vector
<ScDPFilteredCache::Criterion
> aNewCriteria
;
696 aNewCriteria
.reserve(rCriteria
.size() + aGroups
.size());
698 // Go through all the filtered field names and process them appropriately.
700 const ScDPCache
* pCache
= GetCacheTable().getCache();
701 vector
<ScDPFilteredCache::Criterion
>::const_iterator itrEnd
= rCriteria
.end();
702 GroupFieldMapType::const_iterator itrGrpEnd
= aGroupFieldIds
.end();
703 for (vector
<ScDPFilteredCache::Criterion
>::const_iterator itr
= rCriteria
.begin(); itr
!= itrEnd
; ++itr
)
705 std::vector
<ScDPItemData
> aMatchValues
= itr
->mpFilter
->getMatchValues();
707 GroupFieldMapType::const_iterator itrGrp
= aGroupFieldIds
.find(itr
->mnFieldIndex
);
708 if (itrGrp
== itrGrpEnd
)
710 if (IsNumGroupDimension(itr
->mnFieldIndex
))
712 // internal number group field
713 const ScDPNumGroupInfo
* pNumInfo
= pCache
->GetNumGroupInfo(itr
->mnFieldIndex
);
715 // Number group dimension without num info? Something is wrong...
718 ScDPFilteredCache::Criterion aCri
;
719 aCri
.mnFieldIndex
= itr
->mnFieldIndex
;
720 const ScDPNumGroupDimension
& rNumGrpDim
= pNumGroups
[itr
->mnFieldIndex
];
722 if (rNumGrpDim
.IsDateDimension())
726 new ScDPGroupDateFilter(
727 aMatchValues
, *pDoc
->GetFormatTable()->GetNullDate(), *pNumInfo
));
731 // This dimension is grouped by numeric ranges.
733 new ScDPGroupNumFilter(aMatchValues
, *pNumInfo
));
736 aNewCriteria
.push_back(aCri
);
740 // This is a regular source field.
741 aNewCriteria
.push_back(*itr
);
746 // This is an ordinary group field or external number group field.
748 const ScDPGroupDimension
* pGrpDim
= itrGrp
->second
;
749 long nSrcDim
= pGrpDim
->GetSourceDim();
750 long nGrpDim
= pGrpDim
->GetGroupDim();
751 const ScDPNumGroupInfo
* pNumInfo
= pCache
->GetNumGroupInfo(nGrpDim
);
753 if (pGrpDim
->IsDateDimension() && pNumInfo
)
755 // external number group
756 ScDPFilteredCache::Criterion aCri
;
757 aCri
.mnFieldIndex
= nSrcDim
; // use the source dimension, not the group dimension.
759 new ScDPGroupDateFilter(
760 aMatchValues
, *pDoc
->GetFormatTable()->GetNullDate(), *pNumInfo
));
762 aNewCriteria
.push_back(aCri
);
768 ScDPFilteredCache::Criterion aCri
;
769 aCri
.mnFieldIndex
= nSrcDim
;
770 aCri
.mpFilter
.reset(new ScDPFilteredCache::GroupFilter());
771 ScDPFilteredCache::GroupFilter
* pGrpFilter
=
772 static_cast<ScDPFilteredCache::GroupFilter
*>(aCri
.mpFilter
.get());
774 size_t nGroupItemCount
= pGrpDim
->GetItemCount();
775 for (size_t i
= 0; i
< nGroupItemCount
; ++i
)
777 const ScDPGroupItem
* pGrpItem
= pGrpDim
->GetGroupByIndex(i
);
781 // Make sure this group name equals one of the match values.
782 std::vector
<ScDPItemData
>::iterator it
=
784 aMatchValues
.begin(), aMatchValues
.end(), FindCaseInsensitive(pGrpItem
->GetName()));
786 if (it
== aMatchValues
.end())
789 pGrpItem
->FillGroupFilter(*pGrpFilter
);
792 aNewCriteria
.push_back(aCri
);
796 rCriteria
.swap(aNewCriteria
);
799 void ScDPGroupTableData::FilterCacheTable(const vector
<ScDPFilteredCache::Criterion
>& rCriteria
, const boost::unordered_set
<sal_Int32
>& rCatDims
)
801 vector
<ScDPFilteredCache::Criterion
> aNewCriteria(rCriteria
);
802 ModifyFilterCriteria(aNewCriteria
);
803 pSourceData
->FilterCacheTable(aNewCriteria
, rCatDims
);
806 void ScDPGroupTableData::GetDrillDownData(const vector
<ScDPFilteredCache::Criterion
>& rCriteria
, const boost::unordered_set
<sal_Int32
>& rCatDims
, Sequence
< Sequence
<Any
> >& rData
)
808 vector
<ScDPFilteredCache::Criterion
> aNewCriteria(rCriteria
);
809 ModifyFilterCriteria(aNewCriteria
);
810 pSourceData
->GetDrillDownData(aNewCriteria
, rCatDims
, rData
);
813 void ScDPGroupTableData::CalcResults(CalcInfo
& rInfo
, bool bAutoShow
)
815 // #i111435# Inside FillRowDataFromCacheTable/GetItemData, virtual methods
816 // getIsDataLayoutDimension and GetSourceDim are used, so it has to be called
817 // with original rInfo, containing dimension indexes of the grouped data.
819 const ScDPFilteredCache
& rCacheTable
= pSourceData
->GetCacheTable();
820 sal_Int32 nRowSize
= rCacheTable
.getRowSize();
821 for (sal_Int32 nRow
= 0; nRow
< nRowSize
; ++nRow
)
824 if (!rCacheTable
.isRowActive(nRow
, &nLastRow
))
831 FillRowDataFromCacheTable(nRow
, rCacheTable
, rInfo
, aData
);
833 if ( !rInfo
.aColLevelDims
.empty() )
834 FillGroupValues(aData
.aColData
, rInfo
.aColLevelDims
);
835 if ( !rInfo
.aRowLevelDims
.empty() )
836 FillGroupValues(aData
.aRowData
, rInfo
.aRowLevelDims
);
837 if ( !rInfo
.aPageDims
.empty() )
838 FillGroupValues(aData
.aPageData
, rInfo
.aPageDims
);
840 ProcessRowData(rInfo
, aData
, bAutoShow
);
844 const ScDPFilteredCache
& ScDPGroupTableData::GetCacheTable() const
846 return pSourceData
->GetCacheTable();
849 void ScDPGroupTableData::ReloadCacheTable()
851 pSourceData
->ReloadCacheTable();
854 void ScDPGroupTableData::FillGroupValues(vector
<SCROW
>& rItems
, const vector
<long>& rDims
)
856 long nGroupedColumns
= aGroups
.size();
858 const ScDPCache
* pCache
= GetCacheTable().getCache();
859 vector
<long>::const_iterator it
= rDims
.begin(), itEnd
= rDims
.end();
860 for (size_t i
= 0; it
!= itEnd
; ++it
, ++i
)
863 bool bDateDim
= false;
865 long nSourceDim
= nColumn
;
866 if ( nColumn
>= nSourceCount
&& nColumn
< nSourceCount
+ nGroupedColumns
)
868 const ScDPGroupDimension
& rGroupDim
= aGroups
[nColumn
- nSourceCount
];
869 nSourceDim
= rGroupDim
.GetSourceDim();
870 bDateDim
= rGroupDim
.IsDateDimension();
871 if (!bDateDim
) // date is handled below
873 const ScDPItemData
& rItem
= *GetMemberById(nSourceDim
, rItems
[i
]);
874 const ScDPGroupItem
* pGroupItem
= rGroupDim
.GetGroupForData(rItem
);
878 pCache
->GetIdByItemData(nColumn
, pGroupItem
->GetName());
881 rItems
[i
] = pCache
->GetIdByItemData(nColumn
, rItem
);
884 else if ( IsNumGroupDimension( nColumn
) )
886 bDateDim
= pNumGroups
[nColumn
].IsDateDimension();
887 if (!bDateDim
) // date is handled below
889 const ScDPItemData
* pData
= pCache
->GetItemDataById(nSourceDim
, rItems
[i
]);
890 if (pData
->GetType() == ScDPItemData::Value
)
892 ScDPNumGroupInfo aNumInfo
;
893 GetNumGroupInfo(nColumn
, aNumInfo
);
894 double fGroupValue
= ScDPUtil::getNumGroupStartValue(pData
->GetValue(), aNumInfo
);
895 ScDPItemData aItemData
;
896 aItemData
.SetRangeStart(fGroupValue
);
897 rItems
[i
] = pCache
->GetIdByItemData(nSourceDim
, aItemData
);
899 // else (textual) keep original value
903 const ScDPNumGroupInfo
* pNumInfo
= pCache
->GetNumGroupInfo(nColumn
);
905 if (bDateDim
&& pNumInfo
)
907 // This is a date group dimension.
908 sal_Int32 nDatePart
= pCache
->GetGroupType(nColumn
);
909 const ScDPItemData
* pData
= pCache
->GetItemDataById(nSourceDim
, rItems
[i
]);
910 if (pData
->GetType() == ScDPItemData::Value
)
912 SvNumberFormatter
* pFormatter
= pDoc
->GetFormatTable();
913 sal_Int32 nPartValue
= ScDPUtil::getDatePartValue(
914 pData
->GetValue(), *pNumInfo
, nDatePart
, pFormatter
);
916 ScDPItemData
aItem(nDatePart
, nPartValue
);
917 rItems
[i
] = pCache
->GetIdByItemData(nColumn
, aItem
);
923 sal_Bool
ScDPGroupTableData::IsBaseForGroup(long nDim
) const
925 for ( ScDPGroupDimensionVec::const_iterator
aIter(aGroups
.begin()); aIter
!= aGroups
.end(); ++aIter
)
927 const ScDPGroupDimension
& rDim
= *aIter
;
928 if ( rDim
.GetSourceDim() == nDim
)
935 long ScDPGroupTableData::GetGroupBase(long nGroupDim
) const
937 for ( ScDPGroupDimensionVec::const_iterator
aIter(aGroups
.begin()); aIter
!= aGroups
.end(); ++aIter
)
939 const ScDPGroupDimension
& rDim
= *aIter
;
940 if ( rDim
.GetGroupDim() == nGroupDim
)
941 return rDim
.GetSourceDim();
947 sal_Bool
ScDPGroupTableData::IsNumOrDateGroup(long nDimension
) const
949 // Virtual method from ScDPTableData, used in result data to force text labels.
951 if ( nDimension
< nSourceCount
)
953 return pNumGroups
[nDimension
].GetInfo().mbEnable
||
954 pNumGroups
[nDimension
].IsDateDimension();
957 for ( ScDPGroupDimensionVec::const_iterator
aIter(aGroups
.begin()); aIter
!= aGroups
.end(); ++aIter
)
959 const ScDPGroupDimension
& rDim
= *aIter
;
960 if ( rDim
.GetGroupDim() == nDimension
)
961 return rDim
.IsDateDimension();
967 sal_Bool
ScDPGroupTableData::IsInGroup( const ScDPItemData
& rGroupData
, long nGroupIndex
,
968 const ScDPItemData
& rBaseData
, long nBaseIndex
) const
970 for ( ScDPGroupDimensionVec::const_iterator
aIter(aGroups
.begin()); aIter
!= aGroups
.end(); ++aIter
)
972 const ScDPGroupDimension
& rDim
= *aIter
;
973 if ( rDim
.GetGroupDim() == nGroupIndex
&& rDim
.GetSourceDim() == nBaseIndex
)
975 if (rDim
.IsDateDimension())
977 return isDateInGroup(rGroupData
, rBaseData
);
981 // If the item is in a group, only that group is valid.
982 // If the item is not in any group, its own name is valid.
984 const ScDPGroupItem
* pGroup
= rDim
.GetGroupForData( rBaseData
);
985 return pGroup
? pGroup
->GetName().IsCaseInsEqual( rGroupData
) :
986 rGroupData
.IsCaseInsEqual( rBaseData
);
991 OSL_FAIL("IsInGroup: no group dimension found");
995 sal_Bool
ScDPGroupTableData::HasCommonElement( const ScDPItemData
& rFirstData
, long nFirstIndex
,
996 const ScDPItemData
& rSecondData
, long nSecondIndex
) const
998 const ScDPGroupDimension
* pFirstDim
= NULL
;
999 const ScDPGroupDimension
* pSecondDim
= NULL
;
1000 for ( ScDPGroupDimensionVec::const_iterator
aIter(aGroups
.begin()); aIter
!= aGroups
.end(); ++aIter
)
1002 const ScDPGroupDimension
* pDim
= &(*aIter
);
1003 if ( pDim
->GetGroupDim() == nFirstIndex
)
1005 else if ( pDim
->GetGroupDim() == nSecondIndex
)
1008 if ( pFirstDim
&& pSecondDim
)
1010 bool bFirstDate
= pFirstDim
->IsDateDimension();
1011 bool bSecondDate
= pSecondDim
->IsDateDimension();
1012 if (bFirstDate
|| bSecondDate
)
1014 // If one is a date group dimension, the other one must be, too.
1015 if (!bFirstDate
|| !bSecondDate
)
1017 OSL_FAIL( "mix of date and non-date groups" );
1021 return isDateInGroup(rFirstData
, rSecondData
);
1024 const ScDPGroupItem
* pFirstItem
= pFirstDim
->GetGroupForName( rFirstData
);
1025 const ScDPGroupItem
* pSecondItem
= pSecondDim
->GetGroupForName( rSecondData
);
1026 if ( pFirstItem
&& pSecondItem
)
1028 // two existing groups -> sal_True if they have a common element
1029 return pFirstItem
->HasCommonElement( *pSecondItem
);
1031 else if ( pFirstItem
)
1033 // "automatic" group contains only its own name
1034 return pFirstItem
->HasElement( rSecondData
);
1036 else if ( pSecondItem
)
1038 // "automatic" group contains only its own name
1039 return pSecondItem
->HasElement( rFirstData
);
1043 // no groups -> sal_True if equal
1044 return rFirstData
.IsCaseInsEqual( rSecondData
);
1048 OSL_FAIL("HasCommonElement: no group dimension found");
1052 long ScDPGroupTableData::GetSourceDim( long nDim
)
1054 if ( getIsDataLayoutDimension( nDim
) )
1055 return nSourceCount
;
1056 if ( nDim
>= nSourceCount
&& nDim
< nSourceCount
+(long) aGroups
.size() )
1058 const ScDPGroupDimension
& rGroupDim
= aGroups
[nDim
- nSourceCount
];
1059 return rGroupDim
.GetSourceDim();
1064 long ScDPGroupTableData::Compare(long nDim
, long nDataId1
, long nDataId2
)
1066 if ( getIsDataLayoutDimension(nDim
) )
1068 return ScDPItemData::Compare( *GetMemberById(nDim
, nDataId1
),*GetMemberById(nDim
, nDataId2
) );
1071 #if DEBUG_PIVOT_TABLE
1075 void ScDPGroupTableData::Dump() const
1077 cout
<< "--- ScDPGroupTableData" << endl
;
1078 for (long i
= 0; i
< nSourceCount
; ++i
)
1080 cout
<< "* dimension: " << i
<< endl
;
1081 const ScDPNumGroupDimension
& rGrp
= pNumGroups
[i
];
1082 rGrp
.GetInfo().Dump();
1084 cout
<< "---" << endl
;
1088 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */