diff options
author | Kohei Yoshida <kohei.yoshida@gmail.com> | 2012-03-07 22:07:09 -0500 |
---|---|---|
committer | Kohei Yoshida <kohei.yoshida@gmail.com> | 2012-03-09 11:13:34 -0500 |
commit | 57c0ff6602dfbd0b7622a643e179923bf632cd87 (patch) | |
tree | 2d9f91bd3d2c3054ed3bdb56be7cb022ecd68800 | |
parent | e3ebacf3fdbafeafe02e2976c25c9299b1fd6bbd (diff) |
Properly display grouped range values for range-based grouping.
-rw-r--r-- | sc/inc/dpgroup.hxx | 7 | ||||
-rw-r--r-- | sc/inc/dpitemdata.hxx | 7 | ||||
-rw-r--r-- | sc/inc/dpnumgroupinfo.hxx | 2 | ||||
-rw-r--r-- | sc/inc/dptablecache.hxx | 4 | ||||
-rw-r--r-- | sc/inc/dputil.hxx | 6 | ||||
-rw-r--r-- | sc/source/core/data/dpgroup.cxx | 188 | ||||
-rw-r--r-- | sc/source/core/data/dpitemdata.cxx | 66 | ||||
-rw-r--r-- | sc/source/core/data/dpnumgroupinfo.cxx | 15 | ||||
-rw-r--r-- | sc/source/core/data/dptablecache.cxx | 24 | ||||
-rw-r--r-- | sc/source/core/data/dputil.cxx | 142 |
10 files changed, 264 insertions, 197 deletions
diff --git a/sc/inc/dpgroup.hxx b/sc/inc/dpgroup.hxx index cff5c4bed390..b90c667b7387 100644 --- a/sc/inc/dpgroup.hxx +++ b/sc/inc/dpgroup.hxx @@ -130,8 +130,6 @@ class SC_DLLPUBLIC ScDPNumGroupDimension mutable ScDPNumGroupInfo aGroupInfo; // settings ScDPDateGroupHelper* pDateHelper; mutable std::vector<SCROW> maMemberEntries; - mutable bool bHasNonInteger; // initialized in GetNumEntries - mutable sal_Unicode cDecSeparator; // initialized in GetNumEntries public: ScDPNumGroupDimension(); @@ -142,8 +140,6 @@ public: ScDPNumGroupDimension& operator=( const ScDPNumGroupDimension& rOther ); const ScDPNumGroupInfo& GetInfo() const { return aGroupInfo; } - bool HasNonInteger() const { return bHasNonInteger; } - sal_Unicode GetDecSeparator() const { return cDecSeparator; } const ScDPDateGroupHelper* GetDateHelper() const { return pDateHelper; } @@ -174,8 +170,7 @@ class ScDPGroupTableData : public ScDPTableData virtual long GetSourceDim( long nDim ); bool IsNumGroupDimension( long nDimension ) const; - void GetNumGroupInfo( long nDimension, ScDPNumGroupInfo& rInfo, - bool& rNonInteger, sal_Unicode& rDecimal ); + void GetNumGroupInfo(long nDimension, ScDPNumGroupInfo& rInfo); void ModifyFilterCriteria(::std::vector<ScDPCacheTable::Criterion>& rCriteria); diff --git a/sc/inc/dpitemdata.hxx b/sc/inc/dpitemdata.hxx index 00b7cd4d6650..926ce7a986d8 100644 --- a/sc/inc/dpitemdata.hxx +++ b/sc/inc/dpitemdata.hxx @@ -49,7 +49,7 @@ class SC_DLLPUBLIC ScDPItemData friend class ScDPCache; public: - enum Type { GroupValue = 0, Value = 1, String = 2, Error = 3, Empty = 4 }; + enum Type { GroupValue = 0, RangeStart, Value, String, Error, Empty }; static const sal_Int32 DateFirst; static const sal_Int32 DateLast; @@ -70,6 +70,8 @@ private: Type meType; + void DisposeString(); + public: // case insensitive equality static sal_Int32 Compare(const ScDPItemData& rA, const ScDPItemData& rB); @@ -84,6 +86,9 @@ public: Type GetType() const; void SetString(const rtl::OUString& rS); void SetValue(double fVal); + void SetRangeStart(double fVal); + void SetRangeFirst(); + void SetRangeLast(); void SetGroupValue(sal_Int32 nGroupType, sal_Int32 nValue); void SetErrorString(const rtl::OUString& rS); bool IsCaseInsEqual(const ScDPItemData& r) const; diff --git a/sc/inc/dpnumgroupinfo.hxx b/sc/inc/dpnumgroupinfo.hxx index 1d5d05d066c6..2e0196d5deaf 100644 --- a/sc/inc/dpnumgroupinfo.hxx +++ b/sc/inc/dpnumgroupinfo.hxx @@ -37,11 +37,13 @@ struct ScDPNumGroupInfo bool mbDateValues:1; bool mbAutoStart:1; bool mbAutoEnd:1; + bool mbIntegerOnly:1; double mfStart; double mfEnd; double mfStep; SC_DLLPUBLIC ScDPNumGroupInfo(); + ScDPNumGroupInfo(const ScDPNumGroupInfo& r); }; #endif diff --git a/sc/inc/dptablecache.hxx b/sc/inc/dptablecache.hxx index cb2b9dfa8c58..b87713028543 100644 --- a/sc/inc/dptablecache.hxx +++ b/sc/inc/dptablecache.hxx @@ -30,6 +30,7 @@ #define SC_DPTABLECACHE_HXX #include "global.hxx" +#include "dpnumgroupinfo.hxx" #include <svl/zforlist.hxx> @@ -63,8 +64,7 @@ public: struct GroupItems : boost::noncopyable { DataListType maItems; - double mfStart; - double mfEnd; + ScDPNumGroupInfo maInfo; GroupItems(); GroupItems(const ScDPNumGroupInfo& rInfo); diff --git a/sc/inc/dputil.hxx b/sc/inc/dputil.hxx index 0aff4b273b2e..68414f3a45bf 100644 --- a/sc/inc/dputil.hxx +++ b/sc/inc/dputil.hxx @@ -33,6 +33,7 @@ #include "scdllapi.h" class SvNumberFormatter; +struct ScDPNumGroupInfo; class ScDPUtil { @@ -46,6 +47,11 @@ public: static rtl::OUString getDateGroupName( sal_Int32 nDatePart, sal_Int32 nValue, SvNumberFormatter* pFormatter, double fStart, double fEnd); + + static double getNumGroupStartValue(double fValue, const ScDPNumGroupInfo& rInfo); + + static rtl::OUString getNumGroupName( + double fValue, const ScDPNumGroupInfo& rInfo, sal_Unicode cDecSep, SvNumberFormatter* pFormatter); }; #endif diff --git a/sc/source/core/data/dpgroup.cxx b/sc/source/core/data/dpgroup.cxx index 2e986ce8f572..2d175dae8e0e 100644 --- a/sc/source/core/data/dpgroup.cxx +++ b/sc/source/core/data/dpgroup.cxx @@ -151,127 +151,11 @@ void lcl_Insert( SCCOL nSourceDim, const ScDPCache* pCache , std::vector< SCROW vIdx.insert( vIdx.begin()+nIndex, nNew ); } -void lcl_AppendDateStr( rtl::OUStringBuffer& rBuffer, double fValue, SvNumberFormatter* pFormatter ) -{ - sal_uLong nFormat = pFormatter->GetStandardFormat( NUMBERFORMAT_DATE, ScGlobal::eLnge ); - String aString; - pFormatter->GetInputLineString( fValue, nFormat, aString ); - rBuffer.append( aString ); -} - -String lcl_GetNumGroupName( double fStartValue, const ScDPNumGroupInfo& rInfo, - bool bHasNonInteger, sal_Unicode cDecSeparator, SvNumberFormatter* pFormatter ) -{ - OSL_ENSURE( cDecSeparator != 0, "cDecSeparator not initialized" ); - - double fStep = rInfo.mfStep; - double fEndValue = fStartValue + fStep; - if ( !bHasNonInteger && ( rInfo.mbDateValues || !rtl::math::approxEqual( fEndValue, rInfo.mfEnd ) ) ) - { - // The second number of the group label is - // (first number + size - 1) if there are only integer numbers, - // (first number + size) if any non-integer numbers are involved. - // Exception: The last group (containing the end value) is always - // shown as including the end value (but not for dates). - - fEndValue -= 1.0; - } - - if ( fEndValue > rInfo.mfEnd && !rInfo.mbAutoEnd ) - { - // limit the last group to the end value - - fEndValue = rInfo.mfEnd; - } - - rtl::OUStringBuffer aBuffer; - if ( rInfo.mbDateValues ) - { - lcl_AppendDateStr( aBuffer, fStartValue, pFormatter ); - aBuffer.appendAscii( " - " ); // with spaces - lcl_AppendDateStr( aBuffer, fEndValue, pFormatter ); - } - else - { - rtl::math::doubleToUStringBuffer( aBuffer, fStartValue, rtl_math_StringFormat_Automatic, - rtl_math_DecimalPlaces_Max, cDecSeparator, true ); - aBuffer.append( (sal_Unicode) '-' ); - rtl::math::doubleToUStringBuffer( aBuffer, fEndValue, rtl_math_StringFormat_Automatic, - rtl_math_DecimalPlaces_Max, cDecSeparator, true ); - } - - return aBuffer.makeStringAndClear(); -} - -String lcl_GetSpecialNumGroupName( double fValue, bool bFirst, sal_Unicode cDecSeparator, - bool bDateValues, SvNumberFormatter* pFormatter ) -{ - OSL_ENSURE( cDecSeparator != 0, "cDecSeparator not initialized" ); - - rtl::OUStringBuffer aBuffer; - aBuffer.append((sal_Unicode)( bFirst ? '<' : '>' )); - if ( bDateValues ) - lcl_AppendDateStr( aBuffer, fValue, pFormatter ); - else - rtl::math::doubleToUStringBuffer( aBuffer, fValue, rtl_math_StringFormat_Automatic, - rtl_math_DecimalPlaces_Max, cDecSeparator, true ); - return aBuffer.makeStringAndClear(); -} - inline bool IsInteger( double fValue ) { return rtl::math::approxEqual( fValue, rtl::math::approxFloor(fValue) ); } -String lcl_GetNumGroupForValue( double fValue, const ScDPNumGroupInfo& rInfo, bool bHasNonInteger, - sal_Unicode cDecSeparator, double& rGroupValue, ScDocument* pDoc ) -{ - SvNumberFormatter* pFormatter = pDoc->GetFormatTable(); - - if ( fValue < rInfo.mfStart && !rtl::math::approxEqual( fValue, rInfo.mfStart ) ) - { - rGroupValue = rInfo.mfStart - rInfo.mfStep; - return lcl_GetSpecialNumGroupName( rInfo.mfStart, true, cDecSeparator, rInfo.mbDateValues, pFormatter ); - } - - if ( fValue > rInfo.mfEnd && !rtl::math::approxEqual( fValue, rInfo.mfEnd ) ) - { - rGroupValue = rInfo.mfEnd + rInfo.mfStep; - return lcl_GetSpecialNumGroupName( rInfo.mfEnd, false, cDecSeparator, rInfo.mbDateValues, pFormatter ); - } - - double fDiff = fValue - rInfo.mfStart; - double fDiv = rtl::math::approxFloor( fDiff / rInfo.mfStep ); - double fGroupStart = rInfo.mfStart + fDiv * rInfo.mfStep; - - if ( rtl::math::approxEqual( fGroupStart, rInfo.mfEnd ) && - !rtl::math::approxEqual( fGroupStart, rInfo.mfStart ) ) - { - if ( !rInfo.mbDateValues ) - { - // A group that would consist only of the end value is not created, - // instead the value is included in the last group before. So the - // previous group is used if the calculated group start value is the - // selected end value. - - fDiv -= 1.0; - fGroupStart = rInfo.mfStart + fDiv * rInfo.mfStep; - } - else - { - // For date values, the end value is instead treated as above the limit - // if it would be a group of its own. - - rGroupValue = rInfo.mfEnd + rInfo.mfStep; - return lcl_GetSpecialNumGroupName( rInfo.mfEnd, false, cDecSeparator, rInfo.mbDateValues, pFormatter ); - } - } - - rGroupValue = fGroupStart; - - return lcl_GetNumGroupName( fGroupStart, rInfo, bHasNonInteger, cDecSeparator, pFormatter ); -} - } class ScDPGroupDateFilter : public ScDPCacheTable::FilterBase @@ -301,8 +185,8 @@ ScDPGroupDateFilter::ScDPGroupDateFilter(double fMatchValue, sal_Int32 nDatePart mfMatchValue(fMatchValue), mnDatePart(nDatePart) { - } + bool ScDPGroupDateFilter::match( const ScDPItemData & rCellData ) const { using namespace ::com::sun::star::sheet; @@ -783,25 +667,14 @@ void ScDPGroupDimension::DisposeData() // ----------------------------------------------------------------------- ScDPNumGroupDimension::ScDPNumGroupDimension() : - pDateHelper( NULL ), - bHasNonInteger( false ), - cDecSeparator( 0 ) -{ -} + pDateHelper(NULL) {} ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupInfo& rInfo ) : - aGroupInfo( rInfo ), - pDateHelper( NULL ), - bHasNonInteger( false ), - cDecSeparator( 0 ) -{ -} + aGroupInfo(rInfo), pDateHelper(NULL) {} ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupDimension& rOther ) : aGroupInfo( rOther.aGroupInfo ), - pDateHelper( NULL ), - bHasNonInteger( false ), - cDecSeparator( 0 ) + pDateHelper(NULL) { if ( rOther.pDateHelper ) pDateHelper = new ScDPDateGroupHelper( *rOther.pDateHelper ); @@ -817,13 +690,12 @@ ScDPNumGroupDimension& ScDPNumGroupDimension::operator=( const ScDPNumGroupDimen else pDateHelper = NULL; - bHasNonInteger = false; return *this; } void ScDPNumGroupDimension::DisposeData() { - bHasNonInteger = false; + aGroupInfo = ScDPNumGroupInfo(); maMemberEntries.clear(); } @@ -860,12 +732,11 @@ const std::vector<SCROW>& ScDPNumGroupDimension::GetNumEntries( // (this in ensured by calling ScDPLevel::GetMembersObject for all column/row/page // dimensions before iterating over the values). - cDecSeparator = ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0); - // non-integer GroupInfo values count, too - bHasNonInteger = ( !aGroupInfo.mbAutoStart && !IsInteger( aGroupInfo.mfStart ) ) || + 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; @@ -889,18 +760,18 @@ const std::vector<SCROW>& ScDPNumGroupDimension::GetNumEntries( if (fSourceValue > fSourceMax) fSourceMax = fSourceValue; - if (!bHasNonInteger && !IsInteger(fSourceValue)) + if (aGroupInfo.mbIntegerOnly && !IsInteger(fSourceValue)) { // if any non-integer numbers are involved, the group labels are // shown including their upper limit - bHasNonInteger = true; + aGroupInfo.mbIntegerOnly = false; } } if (aGroupInfo.mbDateValues) { // special handling for dates: always integer, round down limits - bHasNonInteger = false; + aGroupInfo.mbIntegerOnly = true; fSourceMin = rtl::math::approxFloor( fSourceMin ); fSourceMax = rtl::math::approxFloor( fSourceMax ) + 1; } @@ -924,13 +795,11 @@ const std::vector<SCROW>& ScDPNumGroupDimension::GetNumEntries( // The first group has to be created nonetheless. GetNumGroupForValue has corresponding logic. bool bFirstGroup = true; - SvNumberFormatter* pFormatter = pCache->GetDoc()->GetFormatTable(); while (bFirstGroup || (fLoop < aGroupInfo.mfEnd && !rtl::math::approxEqual(fLoop, aGroupInfo.mfEnd))) { - rtl::OUString aName = lcl_GetNumGroupName( - fLoop, aGroupInfo, bHasNonInteger, cDecSeparator, pFormatter); - // TODO: create a numerical entry to ensure proper sorting - SCROW nId = pCache->SetGroupItem(nSourceDim, ScDPItemData(aName)); + ScDPItemData aItem; + aItem.SetRangeStart(fLoop); + SCROW nId = pCache->SetGroupItem(nSourceDim, aItem); maMemberEntries.push_back(nId); ++nLoopCount; fLoop = aGroupInfo.mfStart + nLoopCount * aGroupInfo.mfStep; @@ -939,14 +808,13 @@ const std::vector<SCROW>& ScDPNumGroupDimension::GetNumEntries( // ScDPItemData values are compared with approxEqual } - rtl::OUString aFirstName = lcl_GetSpecialNumGroupName( - aGroupInfo.mfStart, true, cDecSeparator, aGroupInfo.mbDateValues, pFormatter); - SCROW nId = pCache->SetGroupItem(nSourceDim, ScDPItemData(aFirstName)); + ScDPItemData aItem; + aItem.SetRangeFirst(); + SCROW nId = pCache->SetGroupItem(nSourceDim, aItem); maMemberEntries.push_back(nId); - rtl::OUString aLastName = lcl_GetSpecialNumGroupName( - aGroupInfo.mfEnd, false, cDecSeparator, aGroupInfo.mbDateValues, pFormatter); - nId = pCache->SetGroupItem(nSourceDim, ScDPItemData(aLastName)); + aItem.SetRangeLast(); + nId = pCache->SetGroupItem(nSourceDim, aItem); maMemberEntries.push_back(nId); return maMemberEntries; @@ -1007,15 +875,10 @@ bool ScDPGroupTableData::IsNumGroupDimension( long nDimension ) const return ( nDimension < nSourceCount && pNumGroups[nDimension].GetInfo().mbEnable ); } -void ScDPGroupTableData::GetNumGroupInfo( long nDimension, ScDPNumGroupInfo& rInfo, - bool& rNonInteger, sal_Unicode& rDecimal ) +void ScDPGroupTableData::GetNumGroupInfo(long nDimension, ScDPNumGroupInfo& rInfo) { if ( nDimension < nSourceCount ) - { - rInfo = pNumGroups[nDimension].GetInfo(); - rNonInteger = pNumGroups[nDimension].HasNonInteger(); - rDecimal = pNumGroups[nDimension].GetDecSeparator(); - } + rInfo = pNumGroups[nDimension].GetInfo(); } long ScDPGroupTableData::GetMembersCount( long nDim ) { @@ -1311,13 +1174,10 @@ void ScDPGroupTableData::FillGroupValues(SCROW* pItemDataIndex, long nCount, con if (pData->GetType() == ScDPItemData::Value) { ScDPNumGroupInfo aNumInfo; - bool bHasNonInteger = false; - sal_Unicode cDecSeparator = 0; - GetNumGroupInfo( nColumn, aNumInfo, bHasNonInteger, cDecSeparator ); - double fGroupValue; - rtl::OUString aGroupName = lcl_GetNumGroupForValue( - pData->GetValue(), aNumInfo, bHasNonInteger, cDecSeparator, fGroupValue, pDoc); - ScDPItemData aItemData(aGroupName); + GetNumGroupInfo(nColumn, aNumInfo); + double fGroupValue = ScDPUtil::getNumGroupStartValue(pData->GetValue(), aNumInfo); + ScDPItemData aItemData; + aItemData.SetRangeStart(fGroupValue); pItemDataIndex[nDim] = pCache->GetIdByItemData(nSourceDim, aItemData); } // else (textual) keep original value diff --git a/sc/source/core/data/dpitemdata.cxx b/sc/source/core/data/dpitemdata.cxx index 01538a8ddba8..8f16a335908a 100644 --- a/sc/source/core/data/dpitemdata.cxx +++ b/sc/source/core/data/dpitemdata.cxx @@ -33,6 +33,7 @@ #include "cell.hxx" #include "globstr.hrc" #include "dptabdat.hxx" +#include "rtl/math.hxx" const sal_Int32 ScDPItemData::DateFirst = -1; const sal_Int32 ScDPItemData::DateLast = 10000; @@ -60,6 +61,7 @@ sal_Int32 ScDPItemData::Compare(const ScDPItemData& rA, const ScDPItemData& rB) return rA.maGroupValue.mnGroupType < rB.maGroupValue.mnGroupType ? -1 : 1; } case Value: + case RangeStart: { if (rA.mfValue == rB.mfValue) return 0; @@ -88,6 +90,7 @@ ScDPItemData::ScDPItemData(const ScDPItemData& r) : mpString = new rtl::OUString(*r.mpString); break; case Value: + case RangeStart: mfValue = r.mfValue; break; case GroupValue: @@ -100,6 +103,12 @@ ScDPItemData::ScDPItemData(const ScDPItemData& r) : } } +void ScDPItemData::DisposeString() +{ + if (meType == String || meType == Error) + delete mpString; +} + ScDPItemData::ScDPItemData(const rtl::OUString& rStr) : mpString(new rtl::OUString(rStr)), meType(String) {} @@ -115,8 +124,7 @@ ScDPItemData::ScDPItemData(sal_Int32 nGroupType, sal_Int32 nValue) : ScDPItemData::~ScDPItemData() { - if (meType == String) - delete mpString; + DisposeString(); } ScDPItemData::Type ScDPItemData::GetType() const @@ -126,25 +134,42 @@ ScDPItemData::Type ScDPItemData::GetType() const void ScDPItemData::SetString(const rtl::OUString& rS) { - if (meType == String) - delete mpString; + DisposeString(); mpString = new rtl::OUString(rS); meType = String; } void ScDPItemData::SetValue(double fVal) { - if (meType == String) - delete mpString; + DisposeString(); mfValue = fVal; meType = Value; } -void ScDPItemData::SetGroupValue(sal_Int32 nGroupType, sal_Int32 nValue) +void ScDPItemData::SetRangeStart(double fVal) { - if (meType == String) - delete mpString; + DisposeString(); + mfValue = fVal; + meType = RangeStart; +} + +void ScDPItemData::SetRangeFirst() +{ + DisposeString(); + rtl::math::setInf(&mfValue, true); + meType = RangeStart; +} + +void ScDPItemData::SetRangeLast() +{ + DisposeString(); + rtl::math::setInf(&mfValue, false); + meType = RangeStart; +} +void ScDPItemData::SetGroupValue(sal_Int32 nGroupType, sal_Int32 nValue) +{ + DisposeString(); maGroupValue.mnGroupType = nGroupType; maGroupValue.mnValue = nValue; meType = GroupValue; @@ -186,12 +211,17 @@ bool ScDPItemData::operator== (const ScDPItemData& r) const if (meType != r.meType) return false; - if (meType == Value) - return (r.meType == Value) ? rtl::math::approxEqual(mfValue, r.mfValue) : false; - - if (meType == GroupValue) - return maGroupValue.mnGroupType == r.maGroupValue.mnGroupType && - maGroupValue.mnValue == r.maGroupValue.mnValue; + switch (meType) + { + case Value: + case RangeStart: + return rtl::math::approxEqual(mfValue, r.mfValue); + case GroupValue: + return maGroupValue.mnGroupType == r.maGroupValue.mnGroupType && + maGroupValue.mnValue == r.maGroupValue.mnValue; + default: + ; + } // need exact equality until we have a safe case insensitive string hash return GetString() == r.GetString(); @@ -207,6 +237,7 @@ ScDPItemData& ScDPItemData::operator= (const ScDPItemData& r) mpString = new rtl::OUString(*r.mpString); break; case Value: + case RangeStart: mfValue = r.mfValue; break; case GroupValue: @@ -256,6 +287,8 @@ void ScDPItemData::Dump(const char* msg) const case Value: printf("value: %g\n", mfValue); break; + case RangeStart: + printf("range start: %g\n", mfValue); default: printf("unknown type\n"); } @@ -283,6 +316,7 @@ rtl::OUString ScDPItemData::GetString() const case Value: return rtl::OUString::valueOf(mfValue); case GroupValue: + case RangeStart: return rtl::OUString::createFromAscii("fail"); case Empty: default: @@ -294,7 +328,7 @@ rtl::OUString ScDPItemData::GetString() const double ScDPItemData::GetValue() const { - if (meType == Value) + if (meType == Value || meType == RangeStart) return mfValue; return 0.0; diff --git a/sc/source/core/data/dpnumgroupinfo.cxx b/sc/source/core/data/dpnumgroupinfo.cxx index 6d4e4fa250ce..0b93bf48c2ea 100644 --- a/sc/source/core/data/dpnumgroupinfo.cxx +++ b/sc/source/core/data/dpnumgroupinfo.cxx @@ -29,7 +29,20 @@ #include "dpnumgroupinfo.hxx" ScDPNumGroupInfo::ScDPNumGroupInfo() : - mbEnable(false), mbDateValues(false), mbAutoStart(false), mbAutoEnd(false), + mbEnable(false), + mbDateValues(false), + mbAutoStart(false), + mbAutoEnd(false), + mbIntegerOnly(true), mfStart(0.0), mfEnd(0.0), mfStep(0.0) {} +ScDPNumGroupInfo::ScDPNumGroupInfo(const ScDPNumGroupInfo& r) : + mbEnable(r.mbEnable), + mbDateValues(r.mbDateValues), + mbAutoStart(r.mbAutoStart), + mbAutoEnd(r.mbAutoEnd), + mbIntegerOnly(r.mbIntegerOnly), + mfStart(r.mfStart), + mfEnd(r.mfEnd), mfStep(r.mfStep) {} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/dptablecache.cxx b/sc/source/core/data/dptablecache.cxx index 78c66cee4523..730114672561 100644 --- a/sc/source/core/data/dptablecache.cxx +++ b/sc/source/core/data/dptablecache.cxx @@ -42,6 +42,7 @@ #include <rtl/math.hxx> #include <unotools/textsearch.hxx> +#include <unotools/localedatawrapper.hxx> #include <com/sun/star/sdbc/DataType.hpp> #include <com/sun/star/sdbc/XRow.hpp> @@ -221,11 +222,10 @@ ScDPItemData* lcl_GetItemValue( } -ScDPCache::GroupItems::GroupItems() : - mfStart(0.0), mfEnd(0.0) {} +ScDPCache::GroupItems::GroupItems() {} ScDPCache::GroupItems::GroupItems(const ScDPNumGroupInfo& rInfo) : - mfStart(rInfo.mfStart), mfEnd(rInfo.mfEnd) {} + maInfo(rInfo) {} bool ScDPCache::operator== ( const ScDPCache& r ) const { @@ -1034,13 +1034,24 @@ rtl::OUString ScDPCache::GetFormattedString(long nDim, const ScDPItemData& rItem const GroupItems* p = GetGroupItems(nDim); if (p) { - fStart = p->mfStart; - fEnd = p->mfEnd; + fStart = p->maInfo.mfStart; + fEnd = p->maInfo.mfEnd; } return ScDPUtil::getDateGroupName( aAttr.mnGroupType, aAttr.mnValue, mpDoc->GetFormatTable(), fStart, fEnd); } + if (eType == ScDPItemData::RangeStart) + { + double fVal = rItem.GetValue(); + const GroupItems* p = GetGroupItems(nDim); + if (!p) + return rItem.GetString(); + + sal_Unicode cDecSep = ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0); + return ScDPUtil::getNumGroupName(fVal, p->maInfo, cDecSep, mpDoc->GetFormatTable()); + } + return rItem.GetString(); } @@ -1066,8 +1077,7 @@ void ScDPCache::ResetGroupItems(long nDim, const ScDPNumGroupInfo& rNumInfo) { GroupItems& rGI = maGroupFields[nDim]; rGI.maItems.clear(); - rGI.mfStart = rNumInfo.mfStart; - rGI.mfEnd = rNumInfo.mfEnd; + rGI.maInfo = rNumInfo; } } diff --git a/sc/source/core/data/dputil.cxx b/sc/source/core/data/dputil.cxx index eb816d8ece5d..e12da8c7f32c 100644 --- a/sc/source/core/data/dputil.cxx +++ b/sc/source/core/data/dputil.cxx @@ -29,11 +29,13 @@ #include "dputil.hxx" #include "global.hxx" #include "dpitemdata.hxx" +#include "dpnumgroupinfo.hxx" #include "comphelper/string.hxx" #include "unotools/localedatawrapper.hxx" #include "unotools/calendarwrapper.hxx" #include "svl/zforlist.hxx" +#include "rtl/math.hxx" #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> #include <com/sun/star/i18n/CalendarDisplayIndex.hpp> @@ -148,4 +150,144 @@ rtl::OUString ScDPUtil::getDateGroupName( return rtl::OUString::createFromAscii("FIXME: unhandled value"); } +double ScDPUtil::getNumGroupStartValue(double fValue, const ScDPNumGroupInfo& rInfo) +{ + if (fValue < rInfo.mfStart && !rtl::math::approxEqual(fValue, rInfo.mfStart)) + { + rtl::math::setInf(&fValue, true); + return fValue; + } + + if (fValue > rInfo.mfEnd && !rtl::math::approxEqual(fValue, rInfo.mfEnd)) + { + rtl::math::setInf(&fValue, false); + return fValue; + } + + double fDiff = fValue - rInfo.mfStart; + double fDiv = rtl::math::approxFloor( fDiff / rInfo.mfStep ); + double fGroupStart = rInfo.mfStart + fDiv * rInfo.mfStep; + + if (rtl::math::approxEqual(fGroupStart, rInfo.mfEnd) && + !rtl::math::approxEqual(fGroupStart, rInfo.mfStart)) + { + if (!rInfo.mbDateValues) + { + // A group that would consist only of the end value is not + // created, instead the value is included in the last group + // before. So the previous group is used if the calculated group + // start value is the selected end value. + + fDiv -= 1.0; + return rInfo.mfStart + fDiv * rInfo.mfStep; + } + + // For date values, the end value is instead treated as above the + // limit if it would be a group of its own. + + return rInfo.mfEnd + rInfo.mfStep; + } + + return fGroupStart; +} + +namespace { + +void lcl_AppendDateStr( rtl::OUStringBuffer& rBuffer, double fValue, SvNumberFormatter* pFormatter ) +{ + sal_uLong nFormat = pFormatter->GetStandardFormat( NUMBERFORMAT_DATE, ScGlobal::eLnge ); + rtl::OUString aString; + pFormatter->GetInputLineString( fValue, nFormat, aString ); + rBuffer.append( aString ); +} + +rtl::OUString lcl_GetSpecialNumGroupName( double fValue, bool bFirst, sal_Unicode cDecSeparator, + bool bDateValues, SvNumberFormatter* pFormatter ) +{ + OSL_ENSURE( cDecSeparator != 0, "cDecSeparator not initialized" ); + + rtl::OUStringBuffer aBuffer; + aBuffer.append((sal_Unicode)( bFirst ? '<' : '>' )); + if ( bDateValues ) + lcl_AppendDateStr( aBuffer, fValue, pFormatter ); + else + rtl::math::doubleToUStringBuffer( aBuffer, fValue, rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, cDecSeparator, true ); + return aBuffer.makeStringAndClear(); +} + +rtl::OUString lcl_GetNumGroupName( + double fStartValue, const ScDPNumGroupInfo& rInfo, sal_Unicode cDecSep, + SvNumberFormatter* pFormatter) +{ + OSL_ENSURE( cDecSep != 0, "cDecSeparator not initialized" ); + + double fStep = rInfo.mfStep; + double fEndValue = fStartValue + fStep; + if (rInfo.mbIntegerOnly && (rInfo.mbDateValues || !rtl::math::approxEqual(fEndValue, rInfo.mfEnd))) + { + // The second number of the group label is + // (first number + size - 1) if there are only integer numbers, + // (first number + size) if any non-integer numbers are involved. + // Exception: The last group (containing the end value) is always + // shown as including the end value (but not for dates). + + fEndValue -= 1.0; + } + + if ( fEndValue > rInfo.mfEnd && !rInfo.mbAutoEnd ) + { + // limit the last group to the end value + + fEndValue = rInfo.mfEnd; + } + + rtl::OUStringBuffer aBuffer; + if ( rInfo.mbDateValues ) + { + lcl_AppendDateStr( aBuffer, fStartValue, pFormatter ); + aBuffer.appendAscii( " - " ); // with spaces + lcl_AppendDateStr( aBuffer, fEndValue, pFormatter ); + } + else + { + rtl::math::doubleToUStringBuffer( aBuffer, fStartValue, rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, cDecSep, true ); + aBuffer.append( (sal_Unicode) '-' ); + rtl::math::doubleToUStringBuffer( aBuffer, fEndValue, rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, cDecSep, true ); + } + + return aBuffer.makeStringAndClear(); +} + +} + +rtl::OUString ScDPUtil::getNumGroupName( + double fValue, const ScDPNumGroupInfo& rInfo, sal_Unicode cDecSep, SvNumberFormatter* pFormatter) +{ + if ( fValue < rInfo.mfStart && !rtl::math::approxEqual( fValue, rInfo.mfStart ) ) + return lcl_GetSpecialNumGroupName( rInfo.mfStart, true, cDecSep, rInfo.mbDateValues, pFormatter ); + + if ( fValue > rInfo.mfEnd && !rtl::math::approxEqual( fValue, rInfo.mfEnd ) ) + return lcl_GetSpecialNumGroupName( rInfo.mfEnd, false, cDecSep, rInfo.mbDateValues, pFormatter ); + + double fDiff = fValue - rInfo.mfStart; + double fDiv = rtl::math::approxFloor( fDiff / rInfo.mfStep ); + double fGroupStart = rInfo.mfStart + fDiv * rInfo.mfStep; + + if ( rtl::math::approxEqual( fGroupStart, rInfo.mfEnd ) && + !rtl::math::approxEqual( fGroupStart, rInfo.mfStart ) ) + { + if (rInfo.mbDateValues) + { + // For date values, the end value is instead treated as above the limit + // if it would be a group of its own. + return lcl_GetSpecialNumGroupName( rInfo.mfEnd, false, cDecSep, rInfo.mbDateValues, pFormatter ); + } + } + + return lcl_GetNumGroupName(fGroupStart, rInfo, cDecSep, pFormatter); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |