diff options
author | Kohei Yoshida <kohei.yoshida@gmail.com> | 2012-03-09 10:15:52 -0500 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@gmail.com> | 2012-03-09 11:13:35 -0500 |
commit | 0637ca0aefed73b55154c15c8738c100f329a3a8 (patch) | |
tree | 551eca27ec05ddb5a6185115126d3c8bd8c9871b /sc | |
parent | Added hook to create group field data at cache creation time. (diff) | |
download | core-0637ca0aefed73b55154c15c8738c100f329a3a8.tar.gz core-0637ca0aefed73b55154c15c8738c100f329a3a8.zip |
Populate group dimensions directly to the cache.
This is to avoid populating them twice in case the same cache is
referenced by multiple pivot tables.
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/dpdimsave.hxx | 22 | ||||
-rw-r--r-- | sc/inc/dpgroup.hxx | 7 | ||||
-rw-r--r-- | sc/inc/dptablecache.hxx | 9 | ||||
-rw-r--r-- | sc/inc/dputil.hxx | 7 | ||||
-rw-r--r-- | sc/source/core/data/dpdimsave.cxx | 295 | ||||
-rw-r--r-- | sc/source/core/data/dpgroup.cxx | 203 | ||||
-rw-r--r-- | sc/source/core/data/dptablecache.cxx | 76 | ||||
-rw-r--r-- | sc/source/core/data/dputil.cxx | 74 | ||||
-rw-r--r-- | sc/source/filter/excel/xepivot.cxx | 3 |
9 files changed, 449 insertions, 247 deletions
diff --git a/sc/inc/dpdimsave.hxx b/sc/inc/dpdimsave.hxx index 6858e8bf0f78..925cb9425918 100644 --- a/sc/inc/dpdimsave.hxx +++ b/sc/inc/dpdimsave.hxx @@ -52,13 +52,14 @@ class ScDPSaveGroupDimension; class SC_DLLPUBLIC ScDPSaveGroupItem { rtl::OUString aGroupName; // name of group - ::std::vector<rtl::OUString> aElements; // names of items in original dimension + std::vector<rtl::OUString> aElements; // names of items in original dimension + mutable std::vector<ScDPItemData> maItems; // items converted from the strings. public: ScDPSaveGroupItem( const rtl::OUString& rName ); ~ScDPSaveGroupItem(); - void AddToData( ScDPGroupDimension& rDataDim, SvNumberFormatter* pFormatter ) const; + void AddToData(ScDPGroupDimension& rDataDim) const; void AddElement( const rtl::OUString& rName ); void AddElementsFromGroup( const ScDPSaveGroupItem& rGroup ); @@ -74,6 +75,9 @@ public: // remove this group's elements from their groups in rDimension // (rDimension must be a different dimension from the one which contains this) void RemoveElementsFromGroups( ScDPSaveGroupDimension& rDimension ) const; + + void ConvertElementsToItems(SvNumberFormatter* pFormatter) const; + bool HasInGroup(const ScDPItemData& rItem) const; }; typedef ::std::vector<ScDPSaveGroupItem> ScDPSaveGroupItemVec; @@ -87,7 +91,7 @@ class SC_DLLPUBLIC ScDPSaveGroupDimension rtl::OUString aSourceDim; // always the real source from the original data rtl::OUString aGroupDimName; ScDPSaveGroupItemVec aGroups; - ScDPNumGroupInfo aDateInfo; + mutable ScDPNumGroupInfo aDateInfo; sal_Int32 nDatePart; public: @@ -96,7 +100,7 @@ public: ~ScDPSaveGroupDimension(); void AddToData( ScDPGroupTableData& rData ) const; - + void AddToCache(ScDPCache& rCache) const; void SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart ); void AddGroupItem( const ScDPSaveGroupItem& rItem ); @@ -119,18 +123,21 @@ public: ScDPSaveGroupItem* GetGroupAccByIndex( long nIndex ); void Rename( const rtl::OUString& rNewName ); + +private: + bool IsInGroup(const ScDPItemData& rItem) const; }; /** * Represents a group dimension that introduces a new hierarchy for an * existing dimension. Unlike the ScDPSaveGroupDimension counterpart, it - * re-uses the source dimension. + * re-uses the source dimension name and ID. */ class SC_DLLPUBLIC ScDPSaveNumGroupDimension { rtl::OUString aDimensionName; - ScDPNumGroupInfo aGroupInfo; - ScDPNumGroupInfo aDateInfo; + mutable ScDPNumGroupInfo aGroupInfo; + mutable ScDPNumGroupInfo aDateInfo; sal_Int32 nDatePart; public: @@ -139,6 +146,7 @@ public: ~ScDPSaveNumGroupDimension(); void AddToData( ScDPGroupTableData& rData ) const; + void AddToCache(ScDPCache& rCache) const; const rtl::OUString& GetDimensionName() const { return aDimensionName; } const ScDPNumGroupInfo& GetInfo() const { return aGroupInfo; } diff --git a/sc/inc/dpgroup.hxx b/sc/inc/dpgroup.hxx index b90c667b7387..5340b70d392b 100644 --- a/sc/inc/dpgroup.hxx +++ b/sc/inc/dpgroup.hxx @@ -60,9 +60,7 @@ public: sal_Int32 GetDatePart() const { return nDatePart; } const ScDPNumGroupInfo& GetNumInfo() const { return aNumInfo; } - void FillColumnEntries( - SCCOL nSourceDim, ScDPCache* pCahe , std::vector<SCROW>& rEntries, - const std::vector<SCROW>& rOriginal) const; + void FillColumnEntries(const ScDPCache* pCache, std::vector<SCROW>& rEntries) const; }; typedef ::std::vector<ScDPItemData> ScDPItemDataVec; @@ -143,8 +141,7 @@ public: const ScDPDateGroupHelper* GetDateHelper() const { return pDateHelper; } - const std::vector<SCROW>& GetNumEntries( - SCCOL nSourceDim, ScDPCache* pCache, const std::vector<SCROW>& rOriginal) const; + const std::vector<SCROW>& GetNumEntries(SCCOL nSourceDim, const ScDPCache* pCache) const; void MakeDateHelper( const ScDPNumGroupInfo& rInfo, long nDim, sal_Int32 nPart ); diff --git a/sc/inc/dptablecache.hxx b/sc/inc/dptablecache.hxx index b87713028543..8a322843dd92 100644 --- a/sc/inc/dptablecache.hxx +++ b/sc/inc/dptablecache.hxx @@ -131,15 +131,16 @@ public: SCROW GetIdByItemData(long nDim, const rtl::OUString& sItemData) const; SCROW GetIdByItemData(long nDim, const ScDPItemData& rItem) const; rtl::OUString GetFormattedString(long nDim, const ScDPItemData& rItem) const; - void AppendGroupField(); + long AppendGroupField(); void ResetGroupItems(long nDim, const ScDPNumGroupInfo& rNumInfo); SCROW SetGroupItem(long nDim, const ScDPItemData& rData); + const DataListType* GetGroupDimMemberValues(long nDim) const; + void GetGroupDimMemberIds(long nDim, std::vector<SCROW>& rIds) const; void ClearGroupFields(); SCROW GetAdditionalItemID( const ScDPItemData& rData ) const; SCCOL GetDimensionIndex(const rtl::OUString& sName) const; - sal_uLong GetNumType ( sal_uLong nFormat ) const; sal_uLong GetNumberFormat( long nDim ) const; bool IsDateDimension( long nDim ) const ; SCROW GetDimMemberCount( SCCOL nDim ) const; @@ -151,12 +152,12 @@ public: SCROW GetRowCount() const; SCROW GetItemDataId( sal_uInt16 nDim, SCROW nRow, bool bRepeatIfEmpty ) const; - rtl::OUString GetDimensionName( sal_uInt16 nColumn ) const; + rtl::OUString GetDimensionName(long nDim) const; bool IsRowEmpty( SCROW nRow ) const; bool IsValid() const; bool ValidQuery(SCROW nRow, const ScQueryParam& rQueryParam) const; - ScDocument* GetDoc() const;//ms-cache-core + ScDocument* GetDoc() const; long GetColumnCount() const; long GetGroupFieldCount() const; diff --git a/sc/inc/dputil.hxx b/sc/inc/dputil.hxx index 68414f3a45bf..4ed4e5c679ea 100644 --- a/sc/inc/dputil.hxx +++ b/sc/inc/dputil.hxx @@ -51,7 +51,12 @@ public: static double getNumGroupStartValue(double fValue, const ScDPNumGroupInfo& rInfo); static rtl::OUString getNumGroupName( - double fValue, const ScDPNumGroupInfo& rInfo, sal_Unicode cDecSep, SvNumberFormatter* pFormatter); + double fValue, const ScDPNumGroupInfo& rInfo, sal_Unicode cDecSep, + SvNumberFormatter* pFormatter); + + static sal_Int32 getDatePartValue( + double fValue, const ScDPNumGroupInfo& rInfo, sal_Int32 nDatePart, + SvNumberFormatter* pFormatter); }; #endif diff --git a/sc/source/core/data/dpdimsave.cxx b/sc/source/core/data/dpdimsave.cxx index 34e87d5ee9c9..234f6676af1f 100644 --- a/sc/source/core/data/dpdimsave.cxx +++ b/sc/source/core/data/dpdimsave.cxx @@ -30,6 +30,7 @@ #include "dpdimsave.hxx" #include "dpgroup.hxx" #include "dpobject.hxx" +#include "dputil.hxx" #include "document.hxx" #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> @@ -38,6 +39,8 @@ #include <rtl/math.hxx> #include <algorithm> +using namespace com::sun::star; + #include <stdio.h> #include <string> #include <sys/time.h> @@ -142,25 +145,37 @@ void ScDPSaveGroupItem::RemoveElementsFromGroups( ScDPSaveGroupDimension& rDimen rDimension.RemoveFromGroups( *aIter ); } -void ScDPSaveGroupItem::AddToData( ScDPGroupDimension& rDataDim, SvNumberFormatter* pFormatter ) const +void ScDPSaveGroupItem::ConvertElementsToItems(SvNumberFormatter* pFormatter) const { - ScDPGroupItem aGroup(aGroupName); - ScDPItemData aData; - - for ( std::vector<rtl::OUString>::const_iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ ) + maItems.reserve(aElements.size()); + std::vector<rtl::OUString>::const_iterator it = aElements.begin(), itEnd = aElements.end(); + for (; it != itEnd; ++it) { - sal_uInt32 nFormat = 0; //! ... + sal_uInt32 nFormat = 0; double fValue; - if ( pFormatter->IsNumberFormat( *aIter, nFormat, fValue ) ) + ScDPItemData aData; + if (pFormatter->IsNumberFormat(*it, nFormat, fValue)) aData.SetValue(fValue); else - aData.SetString( *aIter ); + aData.SetString(*it); - aGroup.AddElement( aData ); - //! for numeric data, look at source members? + maItems.push_back(aData); } +} + +bool ScDPSaveGroupItem::HasInGroup(const ScDPItemData& rItem) const +{ + return std::find(maItems.begin(), maItems.end(), rItem) != maItems.end(); +} + +void ScDPSaveGroupItem::AddToData(ScDPGroupDimension& rDataDim) const +{ + ScDPGroupItem aGroup(aGroupName); + std::vector<ScDPItemData>::const_iterator it = maItems.begin(), itEnd = maItems.end(); + for (; it != itEnd; ++it) + aGroup.AddElement(*it); - rDataDim.AddItem( aGroup ); + rDataDim.AddItem(aGroup); } // ============================================================================ @@ -303,6 +318,99 @@ void ScDPSaveGroupDimension::Rename( const rtl::OUString& rNewName ) aGroupDimName = rNewName; } +bool ScDPSaveGroupDimension::IsInGroup(const ScDPItemData& rItem) const +{ + ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end(); + for (; it != itEnd; ++it) + { + if (it->HasInGroup(rItem)) + return true; + } + return false; +} + +namespace { + +inline bool isInteger(double fValue) +{ + return rtl::math::approxEqual(fValue, rtl::math::approxFloor(fValue)); +} + +void fillDateGroupDimension( + ScDPCache& rCache, ScDPNumGroupInfo& rDateInfo, long nSourceDim, long nGroupDim, + sal_Int32 nDatePart, SvNumberFormatter* pFormatter) +{ + // Auto min/max is only used for "Years" part, but the loop is always + // needed. + double fSourceMin = 0.0; + double fSourceMax = 0.0; + bool bFirst = true; + + const ScDPCache::DataListType& rItems = rCache.GetDimMemberValues(nSourceDim); + ScDPCache::DataListType::const_iterator it = rItems.begin(), itEnd = rItems.end(); + for (; it != itEnd; ++it) + { + const ScDPItemData& rItem = *it; + if (rItem.GetType() != ScDPItemData::Value) + continue; + + double fVal = rItem.GetValue(); + if (bFirst) + { + fSourceMin = fSourceMax = fVal; + bFirst = false; + } + else + { + if (fVal < fSourceMin) + fSourceMin = fVal; + if ( fVal > fSourceMax ) + fSourceMax = fVal; + } + } + + // For the start/end values, use the same date rounding as in + // ScDPNumGroupDimension::GetNumEntries (but not for the list of + // available years). + if (rDateInfo.mbAutoStart) + rDateInfo.mfStart = rtl::math::approxFloor(fSourceMin); + if (rDateInfo.mbAutoEnd) + rDateInfo.mfEnd = rtl::math::approxFloor(fSourceMax) + 1; + + //! if not automatic, limit fSourceMin/fSourceMax for list of year values? + + long nStart = 0, nEnd = 0; // end is inclusive + + switch (nDatePart) + { + case sheet::DataPilotFieldGroupBy::YEARS: + nStart = ScDPUtil::getDatePartValue( + fSourceMin, rDateInfo, sheet::DataPilotFieldGroupBy::YEARS, pFormatter); + nEnd = ScDPUtil::getDatePartValue(fSourceMax, rDateInfo, sheet::DataPilotFieldGroupBy::YEARS, pFormatter); + break; + case sheet::DataPilotFieldGroupBy::QUARTERS: nStart = 1; nEnd = 4; break; + case sheet::DataPilotFieldGroupBy::MONTHS: nStart = 1; nEnd = 12; break; + case sheet::DataPilotFieldGroupBy::DAYS: nStart = 1; nEnd = 366; break; + case sheet::DataPilotFieldGroupBy::HOURS: nStart = 0; nEnd = 23; break; + case sheet::DataPilotFieldGroupBy::MINUTES: nStart = 0; nEnd = 59; break; + case sheet::DataPilotFieldGroupBy::SECONDS: nStart = 0; nEnd = 59; break; + default: + OSL_FAIL("invalid date part"); + } + + // Now, populate the group items in the cache. + rCache.ResetGroupItems(nGroupDim, rDateInfo); + + for (sal_Int32 nValue = nStart; nValue <= nEnd; ++nValue) + rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, nValue)); + + // add first/last entry (min/max) + rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateFirst)); + rCache.SetGroupItem(nGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateLast)); +} + +} + void ScDPSaveGroupDimension::AddToData( ScDPGroupTableData& rData ) const { long nSourceIndex = rData.GetDimensionIndex( aSourceDim ); @@ -319,16 +427,51 @@ void ScDPSaveGroupDimension::AddToData( ScDPGroupTableData& rData ) const { // normal (manual) grouping - SvNumberFormatter* pFormatter = rData.GetDocument()->GetFormatTable(); - - for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ ) - aIter->AddToData( aDim, pFormatter ); + for (ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); ++aIter) + aIter->AddToData(aDim); } rData.AddGroupDimension( aDim ); } } +void ScDPSaveGroupDimension::AddToCache(ScDPCache& rCache) const +{ + long nDim = rCache.AppendGroupField(); + SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable(); + + if (nDatePart) + { + long nSourceDim = rCache.GetDimensionIndex(aSourceDim); + fillDateGroupDimension(rCache, aDateInfo, nSourceDim, nDim, nDatePart, pFormatter); + return; + } + + rCache.ResetGroupItems(nDim, aDateInfo); + { + ScDPSaveGroupItemVec::const_iterator it = aGroups.begin(), itEnd = aGroups.end(); + for (; it != itEnd; ++it) + { + const ScDPSaveGroupItem& rGI = *it; + rGI.ConvertElementsToItems(pFormatter); + rCache.SetGroupItem(nDim, ScDPItemData(rGI.GetGroupName())); + } + } + + long nSourceDim = rCache.GetDimensionIndex(aSourceDim); + const ScDPCache::DataListType& rItems = rCache.GetDimMemberValues(nSourceDim); + { + ScDPCache::DataListType::const_iterator it = rItems.begin(), itEnd = rItems.end(); + for (; it != itEnd; ++it) + { + const ScDPItemData& rItem = *it; + if (!IsInGroup(rItem)) + // Not in any group. Add as its own group. + rCache.SetGroupItem(nDim, rItem); + } + } +} + // ============================================================================ ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const rtl::OUString& rName, const ScDPNumGroupInfo& rInfo ) : @@ -362,6 +505,109 @@ void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData& rData ) const } } +void ScDPSaveNumGroupDimension::AddToCache(ScDPCache& rCache) const +{ + long nDim = rCache.GetDimensionIndex(aDimensionName); + if (aGroupInfo.mbEnable) + { + // Number-range grouping + + // Look through the source entries for non-integer numbers, minimum + // and maximum. + + // non-integer GroupInfo values count, too + aGroupInfo.mbIntegerOnly = + (aGroupInfo.mbAutoStart || isInteger(aGroupInfo.mfStart)) && + (aGroupInfo.mbAutoEnd || isInteger(aGroupInfo.mfEnd)) && + isInteger(aGroupInfo.mfStep); + + double fSourceMin = 0.0; + double fSourceMax = 0.0; + bool bFirst = true; + + const ScDPCache::DataListType& rItems = rCache.GetDimMemberValues(nDim); + ScDPCache::DataListType::const_iterator it = rItems.begin(), itEnd = rItems.end(); + for (; it != itEnd; ++it) + { + const ScDPItemData& rItem = *it; + if (rItem.GetType() != ScDPItemData::Value) + continue; + + double fValue = rItem.GetValue(); + if (bFirst) + { + fSourceMin = fSourceMax = fValue; + bFirst = false; + continue; + } + + if (fValue < fSourceMin) + fSourceMin = fValue; + if (fValue > fSourceMax) + fSourceMax = fValue; + + if (aGroupInfo.mbIntegerOnly && !isInteger(fValue)) + { + // If any non-integer numbers are involved, the group labels + // are shown including their upper limit. + aGroupInfo.mbIntegerOnly = false; + } + } + + if (aGroupInfo.mbDateValues) + { + // special handling for dates: always integer, round down limits + aGroupInfo.mbIntegerOnly = true; + fSourceMin = rtl::math::approxFloor(fSourceMin); + fSourceMax = rtl::math::approxFloor(fSourceMax) + 1; + } + + if (aGroupInfo.mbAutoStart) + aGroupInfo.mfStart = fSourceMin; + if (aGroupInfo.mbAutoEnd) + aGroupInfo.mfEnd = fSourceMax; + + //! limit number of entries? + + long nLoopCount = 0; + double fLoop = aGroupInfo.mfStart; + + rCache.ResetGroupItems(nDim, aGroupInfo); + + // Use "less than" instead of "less or equal" for the loop - don't + // create a group that consists only of the end value. Instead, the + // end value is then included in the last group (last group is bigger + // than the others). The first group has to be created nonetheless. + // GetNumGroupForValue has corresponding logic. + + bool bFirstGroup = true; + while (bFirstGroup || (fLoop < aGroupInfo.mfEnd && !rtl::math::approxEqual(fLoop, aGroupInfo.mfEnd))) + { + ScDPItemData aItem; + aItem.SetRangeStart(fLoop); + rCache.SetGroupItem(nDim, aItem); + ++nLoopCount; + fLoop = aGroupInfo.mfStart + nLoopCount * aGroupInfo.mfStep; + bFirstGroup = false; + + // ScDPItemData values are compared with approxEqual + } + + ScDPItemData aItem; + aItem.SetRangeFirst(); + rCache.SetGroupItem(nDim, aItem); + + aItem.SetRangeLast(); + rCache.SetGroupItem(nDim, aItem); + } + else if (aDateInfo.mbEnable) + { + // Date grouping + SvNumberFormatter* pFormatter = rCache.GetDoc()->GetFormatTable(); + fillDateGroupDimension(rCache, aDateInfo, nDim, nDim, nDatePart, pFormatter); + } +} + void ScDPSaveNumGroupDimension::SetGroupInfo( const ScDPNumGroupInfo& rNew ) { aGroupInfo = rNew; @@ -468,8 +714,27 @@ void ScDPDimensionSaveData::WriteToData( ScDPGroupTableData& rData ) const aIt->second.AddToData( rData ); } +namespace { + +class AddGroupDimToCache : std::unary_function<ScDPSaveGroupDimension, void> +{ + ScDPCache& mrCache; +public: + AddGroupDimToCache(ScDPCache& rCache) : mrCache(rCache) {} + void operator() (const ScDPSaveGroupDimension& rDim) + { + rDim.AddToCache(mrCache); + } +}; + +} + void ScDPDimensionSaveData::WriteToCache(ScDPCache& rCache) const { + std::for_each(maGroupDims.begin(), maGroupDims.end(), AddGroupDimToCache(rCache)); + ScDPSaveNumGroupDimMap::const_iterator it = maNumGroupDims.begin(), itEnd = maNumGroupDims.end(); + for (; it != itEnd; ++it) + it->second.AddToCache(rCache); } const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimForBase( const rtl::OUString& rBaseDimName ) const diff --git a/sc/source/core/data/dpgroup.cxx b/sc/source/core/data/dpgroup.cxx index ffe04309fc20..93c5cbb84a61 100644 --- a/sc/source/core/data/dpgroup.cxx +++ b/sc/source/core/data/dpgroup.cxx @@ -384,79 +384,9 @@ void ScDPDateGroupHelper::SetGroupDim(long nDim) mnGroupDim = nDim; } -void ScDPDateGroupHelper::FillColumnEntries( - SCCOL nSourceDim, ScDPCache* pCache, std::vector<SCROW>& rEntries, const std::vector<SCROW>& rOriginal) const +void ScDPDateGroupHelper::FillColumnEntries(const ScDPCache* pCache, std::vector<SCROW>& rEntries) const { - // auto min/max is only used for "Years" part, but the loop is always needed - double fSourceMin = 0.0; - double fSourceMax = 0.0; - bool bFirst = true; - - size_t nOriginalCount = rOriginal.size(); - for (size_t nOriginalPos=0; nOriginalPos<nOriginalCount; nOriginalPos++) - { - const ScDPItemData* pItemData = pCache->GetItemDataById( nSourceDim, rOriginal[nOriginalPos] ); - if (pItemData->GetType() == ScDPItemData::Value) - { - double fSourceValue = pItemData->GetValue(); - if ( bFirst ) - { - fSourceMin = fSourceMax = fSourceValue; - bFirst = false; - } - else - { - if ( fSourceValue < fSourceMin ) - fSourceMin = fSourceValue; - if ( fSourceValue > fSourceMax ) - fSourceMax = fSourceValue; - } - } - } - - // For the start/end values, use the same date rounding as in ScDPNumGroupDimension::GetNumEntries - // (but not for the list of available years): - if ( aNumInfo.mbAutoStart ) - const_cast<ScDPDateGroupHelper*>(this)->aNumInfo.mfStart = rtl::math::approxFloor( fSourceMin ); - if ( aNumInfo.mbAutoEnd ) - const_cast<ScDPDateGroupHelper*>(this)->aNumInfo.mfEnd = rtl::math::approxFloor( fSourceMax ) + 1; - - //! if not automatic, limit fSourceMin/fSourceMax for list of year values? - SvNumberFormatter* pFormatter = pCache->GetDoc()->GetFormatTable(); - - long nStart = 0; - long nEnd = 0; // including - - switch ( nDatePart ) - { - case com::sun::star::sheet::DataPilotFieldGroupBy::YEARS: - nStart = lcl_GetDatePartValue( fSourceMin, com::sun::star::sheet::DataPilotFieldGroupBy::YEARS, pFormatter, NULL ); - nEnd = lcl_GetDatePartValue( fSourceMax, com::sun::star::sheet::DataPilotFieldGroupBy::YEARS, pFormatter, NULL ); - break; - case com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS: nStart = 1; nEnd = 4; break; - case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS: nStart = 1; nEnd = 12; break; - case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS: nStart = 1; nEnd = 366; break; - case com::sun::star::sheet::DataPilotFieldGroupBy::HOURS: nStart = 0; nEnd = 23; break; - case com::sun::star::sheet::DataPilotFieldGroupBy::MINUTES: nStart = 0; nEnd = 59; break; - case com::sun::star::sheet::DataPilotFieldGroupBy::SECONDS: nStart = 0; nEnd = 59; break; - default: - OSL_FAIL("invalid date part"); - } - - pCache->ResetGroupItems(mnGroupDim, aNumInfo); - - for ( sal_Int32 nValue = nStart; nValue <= nEnd; nValue++ ) - { - SCROW nId = pCache->SetGroupItem(mnGroupDim, ScDPItemData(nDatePart, nValue)); - rEntries.push_back(nId); - } - - // add first/last entry (min/max) - SCROW nId = pCache->SetGroupItem(mnGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateFirst)); - rEntries.push_back(nId); - - nId = pCache->SetGroupItem(mnGroupDim, ScDPItemData(nDatePart, ScDPItemData::DateLast)); - rEntries.push_back(nId); + pCache->GetGroupDimMemberIds(mnGroupDim, rEntries); } // ----------------------------------------------------------------------- @@ -569,33 +499,11 @@ const std::vector<SCROW>& ScDPGroupDimension::GetColumnEntries( if (pDateHelper) { - pDateHelper->FillColumnEntries( - GetSourceDim(), const_cast<ScDPCache*>(rCacheTable.getCache()), maMemberEntries, rOriginal); + pDateHelper->FillColumnEntries(rCacheTable.getCache(), maMemberEntries); return maMemberEntries; } - ScDPCache* pCache = const_cast<ScDPCache*>(rCacheTable.getCache()); - for (size_t i = 0, n = rOriginal.size(); i < n; ++i) - { - const ScDPItemData* pItemData = pCache->GetItemDataById(nSourceDim, rOriginal[i]); - if (!pItemData) - // This shouldn't happen. Something is terribly wrong. - continue; - - if (!GetGroupForData(*pItemData)) - { - // not in any group -> add as its own group - SCROW nId = pCache->SetGroupItem(nGroupDim, *pItemData); - maMemberEntries.push_back(nId); - } - } - - for (size_t i = 0, n = aItems.size(); i < n; ++i) - { - SCROW nId = pCache->SetGroupItem(nGroupDim, aItems[i].GetName()); - maMemberEntries.push_back(nId); - } - + rCacheTable.getCache()->GetGroupDimMemberIds(nGroupDim, maMemberEntries); return maMemberEntries; } @@ -681,7 +589,7 @@ void ScDPNumGroupDimension::MakeDateHelper( const ScDPNumGroupInfo& rInfo, long } const std::vector<SCROW>& ScDPNumGroupDimension::GetNumEntries( - SCCOL nSourceDim, ScDPCache* pCache, const std::vector<SCROW>& rOriginal) const + SCCOL nSourceDim, const ScDPCache* pCache) const { if (!maMemberEntries.empty()) return maMemberEntries; @@ -689,102 +597,11 @@ const std::vector<SCROW>& ScDPNumGroupDimension::GetNumEntries( if (pDateHelper) { // Grouped by dates. - pDateHelper->FillColumnEntries( - nSourceDim, const_cast<ScDPCache*>(pCache), maMemberEntries, rOriginal); + pDateHelper->FillColumnEntries(pCache, maMemberEntries); return maMemberEntries; } - // Copy textual entries. - // Also look through the source entries for non-integer numbers, minimum and maximum. - // GetNumEntries (GetColumnEntries) must be called before accessing the groups - // (this in ensured by calling ScDPLevel::GetMembersObject for all column/row/page - // dimensions before iterating over the values). - - // non-integer GroupInfo values count, too - bool bHasNonInteger = ( !aGroupInfo.mbAutoStart && !IsInteger( aGroupInfo.mfStart ) ) || - ( !aGroupInfo.mbAutoEnd && !IsInteger( aGroupInfo.mfEnd ) ) || - !IsInteger( aGroupInfo.mfStep ); - aGroupInfo.mbIntegerOnly = !bHasNonInteger; - double fSourceMin = 0.0; - double fSourceMax = 0.0; - bool bFirst = true; - - for (size_t i = 0, n = rOriginal.size(); i < n; ++i) - { - const ScDPItemData* pItemData = pCache->GetItemDataById(nSourceDim, rOriginal[i]); - if (pItemData->GetType() != ScDPItemData::Value) - continue; - - double fSourceValue = pItemData->GetValue(); - if (bFirst) - { - fSourceMin = fSourceMax = fSourceValue; - bFirst = false; - continue; - } - - if (fSourceValue < fSourceMin) - fSourceMin = fSourceValue; - if (fSourceValue > fSourceMax) - fSourceMax = fSourceValue; - - if (aGroupInfo.mbIntegerOnly && !IsInteger(fSourceValue)) - { - // if any non-integer numbers are involved, the group labels are - // shown including their upper limit - aGroupInfo.mbIntegerOnly = false; - } - } - - if (aGroupInfo.mbDateValues) - { - // special handling for dates: always integer, round down limits - aGroupInfo.mbIntegerOnly = true; - fSourceMin = rtl::math::approxFloor( fSourceMin ); - fSourceMax = rtl::math::approxFloor( fSourceMax ) + 1; - } - - if (aGroupInfo.mbAutoStart) - aGroupInfo.mfStart = fSourceMin; - if (aGroupInfo.mbAutoEnd) - aGroupInfo.mfEnd = fSourceMax; - - //! limit number of entries? - - long nLoopCount = 0; - double fLoop = aGroupInfo.mfStart; - - // Num group always share the same dimension ID as the source dimension. - pCache->ResetGroupItems(nSourceDim, aGroupInfo); - - // Use "less than" instead of "less or equal" for the loop - don't create a group - // that consists only of the end value. Instead, the end value is then included - // in the last group (last group is bigger than the others). - // The first group has to be created nonetheless. GetNumGroupForValue has corresponding logic. - - bool bFirstGroup = true; - while (bFirstGroup || (fLoop < aGroupInfo.mfEnd && !rtl::math::approxEqual(fLoop, aGroupInfo.mfEnd))) - { - ScDPItemData aItem; - aItem.SetRangeStart(fLoop); - SCROW nId = pCache->SetGroupItem(nSourceDim, aItem); - maMemberEntries.push_back(nId); - ++nLoopCount; - fLoop = aGroupInfo.mfStart + nLoopCount * aGroupInfo.mfStep; - bFirstGroup = false; - - // ScDPItemData values are compared with approxEqual - } - - ScDPItemData aItem; - aItem.SetRangeFirst(); - SCROW nId = pCache->SetGroupItem(nSourceDim, aItem); - maMemberEntries.push_back(nId); - - aItem.SetRangeLast(); - nId = pCache->SetGroupItem(nSourceDim, aItem); - maMemberEntries.push_back(nId); - + pCache->GetGroupDimMemberIds(nSourceDim, maMemberEntries); return maMemberEntries; } @@ -811,8 +628,6 @@ void ScDPGroupTableData::AddGroupDimension( const ScDPGroupDimension& rGroup ) aNewGroup.SetGroupDim( GetColumnCount() ); // new dimension will be at the end aGroups.push_back( aNewGroup ); aGroupNames.insert(aNewGroup.GetName()); - ScDPCache* pCache = const_cast<ScDPCache*>(GetCacheTable().getCache()); - pCache->AppendGroupField(); } void ScDPGroupTableData::SetNumGroupDimension( long nIndex, const ScDPNumGroupDimension& rGroup ) @@ -872,10 +687,8 @@ const std::vector< SCROW >& ScDPGroupTableData::GetColumnEntries( long nColumn if ( IsNumGroupDimension( nColumn ) ) { // dimension number is unchanged for numerical groups - const std::vector< SCROW >& rOriginal = pSourceData->GetColumnEntries( nColumn ); return pNumGroups[nColumn].GetNumEntries( - static_cast<SCCOL>(nColumn), - const_cast<ScDPCache*>(GetCacheTable().getCache()), rOriginal); + static_cast<SCCOL>(nColumn), GetCacheTable().getCache()); } return pSourceData->GetColumnEntries( nColumn ); diff --git a/sc/source/core/data/dptablecache.cxx b/sc/source/core/data/dptablecache.cxx index 1c7f3a2a4db4..a58916406ebf 100644 --- a/sc/source/core/data/dptablecache.cxx +++ b/sc/source/core/data/dptablecache.cxx @@ -386,7 +386,7 @@ bool ScDPCache::InitFromDoc(ScDocument* pDoc, const ScRange& rRange) for (size_t i = 0; i < static_cast<size_t>(mnColumnCount); ++i) maFields.push_back(new Field); - maLabelNames.reserve(mnColumnCount); + maLabelNames.reserve(mnColumnCount+1); for (sal_uInt16 nCol = nStartCol; nCol <= nEndCol; ++nCol) { @@ -423,7 +423,7 @@ bool ScDPCache::InitFromDataBase (const Reference<sdbc::XRowSet>& xRowSet, const // Get column titles and types. maLabelNames.clear(); - maLabelNames.reserve(mnColumnCount); + maLabelNames.reserve(mnColumnCount+1); std::vector<sal_Int32> aColTypes(mnColumnCount); @@ -713,14 +713,14 @@ const ScDPCache::GroupItems* ScDPCache::GetGroupItems(long nDim) const return NULL; } -rtl::OUString ScDPCache::GetDimensionName( sal_uInt16 nColumn ) const +rtl::OUString ScDPCache::GetDimensionName(long nDim) const { - OSL_ENSURE(nColumn < maLabelNames.size()-1 , "ScDPTableDataCache::GetDimensionName"); + OSL_ENSURE(nDim < maLabelNames.size()-1 , "ScDPTableDataCache::GetDimensionName"); OSL_ENSURE(maLabelNames.size() == static_cast <sal_uInt16> (mnColumnCount+1), "ScDPTableDataCache::GetDimensionName"); - if ( static_cast<size_t>(nColumn+1) < maLabelNames.size() ) + if ( static_cast<size_t>(nDim+1) < maLabelNames.size() ) { - return maLabelNames[nColumn+1]; + return maLabelNames[nDim+1]; } else return rtl::OUString(); @@ -844,15 +844,6 @@ const ScDPCache::DataListType& ScDPCache::GetDimMemberValues(SCCOL nDim) const return maFields[nDim].maItems; } -sal_uLong ScDPCache::GetNumType(sal_uLong nFormat) const -{ - SvNumberFormatter* pFormatter = mpDoc->GetFormatTable(); - sal_uLong nType = NUMBERFORMAT_NUMBER; - if ( pFormatter ) - nType = pFormatter->GetType( nFormat ); - return nType; -} - sal_uLong ScDPCache::GetNumberFormat( long nDim ) const { if ( nDim >= mnColumnCount ) @@ -895,7 +886,7 @@ SCCOL ScDPCache::GetDimensionIndex(const rtl::OUString& sName) const for (size_t i = 1; i < maLabelNames.size(); ++i) { if (maLabelNames[i].equals(sName)) - return (SCCOL)(i-1); + return static_cast<SCCOL>(i-1); } return -1; } @@ -1055,10 +1046,10 @@ rtl::OUString ScDPCache::GetFormattedString(long nDim, const ScDPItemData& rItem return rItem.GetString(); } -void ScDPCache::AppendGroupField() +long ScDPCache::AppendGroupField() { maGroupFields.push_back(new GroupItems); - fprintf(stdout, "ScDPCache::AppendGroupField: added; new count = %d\n", maGroupFields.size()); + return static_cast<long>(maFields.size() + maGroupFields.size() - 1); } void ScDPCache::ResetGroupItems(long nDim, const ScDPNumGroupInfo& rNumInfo) @@ -1107,6 +1098,55 @@ SCROW ScDPCache::SetGroupItem(long nDim, const ScDPItemData& rData) return -1; } +const ScDPCache::DataListType* ScDPCache::GetGroupDimMemberValues(long nDim) const +{ + if (nDim < 0) + return NULL; + + long nSourceCount = static_cast<long>(maFields.size()); + if (nDim < nSourceCount) + { + if (!maFields.at(nDim).mpGroup) + return NULL; + + return &maFields[nDim].mpGroup->maItems; + } + + nDim -= nSourceCount; + if (nDim < static_cast<long>(maGroupFields.size())) + return &maGroupFields.at(nDim).maItems; + + return NULL; +} + +void ScDPCache::GetGroupDimMemberIds(long nDim, std::vector<SCROW>& rIds) const +{ + if (nDim < 0) + return; + + long nSourceCount = static_cast<long>(maFields.size()); + if (nDim < nSourceCount) + { + if (!maFields.at(nDim).mpGroup) + return; + + size_t nOffset = maFields[nDim].maItems.size(); + const DataListType& rGI = maFields[nDim].mpGroup->maItems; + for (size_t i = 0, n = rGI.size(); i < n; ++i) + rIds.push_back(static_cast<SCROW>(i + nOffset)); + + return; + } + + nDim -= nSourceCount; + if (nDim < static_cast<long>(maGroupFields.size())) + { + const DataListType& rGI = maGroupFields.at(nDim).maItems; + for (size_t i = 0, n = rGI.size(); i < n; ++i) + rIds.push_back(static_cast<SCROW>(i)); + } +} + namespace { struct ClearGroupItems : std::unary_function<ScDPCache::Field, void> diff --git a/sc/source/core/data/dputil.cxx b/sc/source/core/data/dputil.cxx index e12da8c7f32c..0e1803d64bc2 100644 --- a/sc/source/core/data/dputil.cxx +++ b/sc/source/core/data/dputil.cxx @@ -40,6 +40,8 @@ #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> #include <com/sun/star/i18n/CalendarDisplayIndex.hpp> +#define D_TIMEFACTOR 86400.0 + using namespace com::sun::star; namespace { @@ -290,4 +292,76 @@ rtl::OUString ScDPUtil::getNumGroupName( return lcl_GetNumGroupName(fGroupStart, rInfo, cDecSep, pFormatter); } +sal_Int32 ScDPUtil::getDatePartValue( + double fValue, const ScDPNumGroupInfo& rInfo, sal_Int32 nDatePart, + SvNumberFormatter* pFormatter) +{ + // Start and end are inclusive + // (End date without a time value is included, with a time value it's not) + + if (fValue < rInfo.mfStart && !rtl::math::approxEqual(fValue, rInfo.mfStart)) + return ScDPItemData::DateFirst; + if (fValue > rInfo.mfEnd && !rtl::math::approxEqual(fValue, rInfo.mfEnd)) + return ScDPItemData::DateLast; + + sal_Int32 nResult = 0; + + if (nDatePart == sheet::DataPilotFieldGroupBy::HOURS || + nDatePart == sheet::DataPilotFieldGroupBy::MINUTES || + nDatePart == sheet::DataPilotFieldGroupBy::SECONDS) + { + // handle time + // (as in the cell functions, ScInterpreter::ScGetHour etc.: seconds are rounded) + + double fTime = fValue - rtl::math::approxFloor(fValue); + long nSeconds = (long)rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5); + + switch (nDatePart) + { + case sheet::DataPilotFieldGroupBy::HOURS: + nResult = nSeconds / 3600; + break; + case sheet::DataPilotFieldGroupBy::MINUTES: + nResult = ( nSeconds % 3600 ) / 60; + break; + case sheet::DataPilotFieldGroupBy::SECONDS: + nResult = nSeconds % 60; + break; + } + } + else + { + Date aDate = *(pFormatter->GetNullDate()); + aDate += (long)::rtl::math::approxFloor(fValue); + + switch ( nDatePart ) + { + case com::sun::star::sheet::DataPilotFieldGroupBy::YEARS: + nResult = aDate.GetYear(); + break; + case com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS: + nResult = 1 + (aDate.GetMonth() - 1) / 3; // 1..4 + break; + case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS: + nResult = aDate.GetMonth(); // 1..12 + break; + case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS: + { + Date aYearStart(1, 1, aDate.GetYear()); + nResult = (aDate - aYearStart) + 1; // Jan 01 has value 1 + if (nResult >= 60 && !aDate.IsLeapYear()) + { + // days are counted from 1 to 366 - if not from a leap year, adjust + ++nResult; + } + } + break; + default: + OSL_FAIL("invalid date part"); + } + } + + return nResult; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/filter/excel/xepivot.cxx b/sc/source/filter/excel/xepivot.cxx index d1d5764744bf..324f802a2e4c 100644 --- a/sc/source/filter/excel/xepivot.cxx +++ b/sc/source/filter/excel/xepivot.cxx @@ -554,8 +554,7 @@ void XclExpPCField::InsertNumDateGroupItems( const ScDPObject& rDPObj, const ScD if( nDatePart != 0 ) aTmpDim.MakeDateHelper( rNumInfo, mnFieldIdx, nDatePart ); const std::vector<SCROW>& aMemberIds = aTmpDim.GetNumEntries( - static_cast<SCCOL>(GetBaseFieldIndex()), - const_cast<ScDPCache*>(aDPData.GetCacheTable().getCache()), aOrignial); + static_cast<SCCOL>(GetBaseFieldIndex()), aDPData.GetCacheTable().getCache()); for ( size_t nIdx = 0 ; nIdx < aMemberIds.size(); nIdx++ ) { const ScDPItemData* pData = aDPData.GetMemberById( static_cast< long >( GetBaseFieldIndex() ) , aMemberIds[ nIdx] ); |