Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / dpgroup.cxx
blobf79a7403e5f04bb7a2e4fdcc22b5be1985328b4b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
22 #include "global.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"
29 #include "dputil.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>
38 #include <vector>
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;
49 using ::std::vector;
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
56 public:
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;
61 private:
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)
72 return false;
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)
84 return true;
87 // Greater than the max value.
88 if (maNumInfo.mfEnd < rCellData.GetValue())
89 return true;
91 continue;
94 double low = fVal;
95 double high = low + maNumInfo.mfStep;
96 if (maNumInfo.mbIntegerOnly)
97 high += 1.0;
99 if (low <= rCellData.GetValue() && rCellData.GetValue() < high)
100 return true;
103 return false;
106 std::vector<ScDPItemData> ScDPGroupNumFilter::getMatchValues() const
108 return std::vector<ScDPItemData>();
111 class ScDPGroupDateFilter : public ScDPFilteredCache::FilterBase
113 public:
114 virtual ~ScDPGroupDateFilter() {}
115 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;
121 private:
122 ScDPGroupDateFilter(); // disabled
124 std::vector<ScDPItemData> maValues;
125 Date maNullDate;
126 ScDPNumGroupInfo maNumInfo;
129 // ----------------------------------------------------------------------------
131 ScDPGroupDateFilter::ScDPGroupDateFilter(
132 const std::vector<ScDPItemData>& rValues, const Date& rNullDate, const ScDPNumGroupInfo& rNumInfo) :
133 maValues(rValues),
134 maNullDate(rNullDate),
135 maNumInfo(rNumInfo)
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() )
146 return false;
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)
153 continue;
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)
164 return true;
165 continue;
168 if (rCellData.GetValue() > maNumInfo.mfEnd && !approxEqual(rCellData.GetValue(), maNumInfo.mfEnd))
170 if (nValue == ScDPItemData::DateLast)
171 return true;
172 continue;
175 if (nGroupType == DataPilotFieldGroupBy::HOURS || nGroupType == DataPilotFieldGroupBy::MINUTES ||
176 nGroupType == DataPilotFieldGroupBy::SECONDS)
178 // handle time
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));
184 switch (nGroupType)
186 case DataPilotFieldGroupBy::HOURS:
188 sal_Int32 hrs = seconds / 3600;
189 if (hrs == nValue)
190 return true;
192 break;
193 case DataPilotFieldGroupBy::MINUTES:
195 sal_Int32 minutes = (seconds % 3600) / 60;
196 if (minutes == nValue)
197 return true;
199 break;
200 case DataPilotFieldGroupBy::SECONDS:
202 sal_Int32 sec = seconds % 60;
203 if (sec == nValue)
204 return true;
206 break;
207 default:
208 OSL_FAIL("invalid time part");
211 continue;
214 Date date = maNullDate + static_cast<long>(approxFloor(rCellData.GetValue()));
215 switch (nGroupType)
217 case DataPilotFieldGroupBy::YEARS:
219 sal_Int32 year = static_cast<sal_Int32>(date.GetYear());
220 if (year == nValue)
221 return true;
223 break;
224 case DataPilotFieldGroupBy::QUARTERS:
226 sal_Int32 qtr = 1 + (static_cast<sal_Int32>(date.GetMonth()) - 1) / 3;
227 if (qtr == nValue)
228 return true;
230 break;
231 case DataPilotFieldGroupBy::MONTHS:
233 sal_Int32 month = static_cast<sal_Int32>(date.GetMonth());
234 if (month == nValue)
235 return true;
237 break;
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.
245 ++days;
247 if (days == nValue)
248 return true;
250 break;
251 default:
252 OSL_FAIL("invalid date part");
256 return false;
259 std::vector<ScDPItemData> ScDPGroupDateFilter::getMatchValues() const
261 return std::vector<ScDPItemData>();
264 namespace {
266 bool isDateInGroup(const ScDPItemData& rGroupItem, const ScDPItemData& rChildItem)
268 if (rGroupItem.GetType() != ScDPItemData::GroupValue || rChildItem.GetType() != ScDPItemData::GroupValue)
269 return false;
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;
304 break;
305 default:
309 return true;
314 ScDPGroupItem::ScDPGroupItem( const ScDPItemData& rName ) :
315 aGroupName( 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 ) )
332 return true;
334 return false;
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 ) )
341 return true;
343 return false;
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 ),
357 nGroupDim( -1 ),
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;
384 return *this;
387 void ScDPGroupDimension::AddItem( const ScDPGroupItem& rItem )
389 aItems.push_back( rItem );
392 void ScDPGroupDimension::SetGroupDim( long nDim )
394 nGroupDim = 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))
413 return &*aIter;
415 return NULL;
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 ) )
422 return &*aIter;
424 return NULL;
427 const ScDPGroupItem* ScDPGroupDimension::GetGroupByIndex( size_t nIndex ) const
429 if (nIndex >= aItems.size())
430 return NULL;
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;
464 return *this;
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 ),
501 pDoc( pDocument )
503 OSL_ENSURE( pSource, "ScDPGroupTableData: pSource can't be NULL" );
505 CreateCacheTable();
506 nSourceCount = pSource->GetColumnCount(); // real columns, excluding data layout
507 pNumGroups = new ScDPNumGroupDimension[nSourceCount];
510 ScDPGroupTableData::~ScDPGroupTableData()
512 delete[] pNumGroups;
515 boost::shared_ptr<ScDPTableData> ScDPGroupTableData::GetSourceTableData()
517 return pSourceData;
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?
542 return i;
543 return -1; // none
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
572 else
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
600 else
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
619 else
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
632 else
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();
665 namespace {
667 class FindCaseInsensitive : std::unary_function<ScDPItemData, bool>
669 ScDPItemData maValue;
670 public:
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);
714 if (!pNumInfo)
715 // Number group dimension without num info? Something is wrong...
716 continue;
718 ScDPFilteredCache::Criterion aCri;
719 aCri.mnFieldIndex = itr->mnFieldIndex;
720 const ScDPNumGroupDimension& rNumGrpDim = pNumGroups[itr->mnFieldIndex];
722 if (rNumGrpDim.IsDateDimension())
724 // grouped by dates.
725 aCri.mpFilter.reset(
726 new ScDPGroupDateFilter(
727 aMatchValues, *pDoc->GetFormatTable()->GetNullDate(), *pNumInfo));
729 else
731 // This dimension is grouped by numeric ranges.
732 aCri.mpFilter.reset(
733 new ScDPGroupNumFilter(aMatchValues, *pNumInfo));
736 aNewCriteria.push_back(aCri);
738 else
740 // This is a regular source field.
741 aNewCriteria.push_back(*itr);
744 else
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.
758 aCri.mpFilter.reset(
759 new ScDPGroupDateFilter(
760 aMatchValues, *pDoc->GetFormatTable()->GetNullDate(), *pNumInfo));
762 aNewCriteria.push_back(aCri);
764 else
766 // normal group
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);
778 if (!pGrpItem)
779 continue;
781 // Make sure this group name equals one of the match values.
782 std::vector<ScDPItemData>::iterator it =
783 std::find_if(
784 aMatchValues.begin(), aMatchValues.end(), FindCaseInsensitive(pGrpItem->GetName()));
786 if (it == aMatchValues.end())
787 continue;
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)
823 sal_Int32 nLastRow;
824 if (!rCacheTable.isRowActive(nRow, &nLastRow))
826 nRow = nLastRow;
827 continue;
830 CalcRowData aData;
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)
862 long nColumn = *it;
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);
875 if (pGroupItem)
877 rItems[i] =
878 pCache->GetIdByItemData(nColumn, pGroupItem->GetName());
880 else
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 )
929 return sal_True;
932 return false;
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();
944 return -1; // none
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();
964 return false;
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);
979 else
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");
992 return true;
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 )
1004 pFirstDim = pDim;
1005 else if ( pDim->GetGroupDim() == nSecondIndex )
1006 pSecondDim = pDim;
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" );
1018 return true;
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 );
1041 else
1043 // no groups -> sal_True if equal
1044 return rFirstData.IsCaseInsEqual( rSecondData );
1048 OSL_FAIL("HasCommonElement: no group dimension found");
1049 return true;
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();
1061 return nDim;
1064 long ScDPGroupTableData::Compare(long nDim, long nDataId1, long nDataId2)
1066 if ( getIsDataLayoutDimension(nDim) )
1067 return 0;
1068 return ScDPItemData::Compare( *GetMemberById(nDim, nDataId1),*GetMemberById(nDim, nDataId2) );
1071 #if DEBUG_PIVOT_TABLE
1072 using std::cout;
1073 using std::endl;
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;
1086 #endif
1088 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */