xref: /AOO41X/main/sc/source/core/data/dpgroup.cxx (revision b3f79822e811ac3493b185030a72c3c5a51f32d8)
1*b3f79822SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*b3f79822SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*b3f79822SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*b3f79822SAndrew Rist  * distributed with this work for additional information
6*b3f79822SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*b3f79822SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*b3f79822SAndrew Rist  * "License"); you may not use this file except in compliance
9*b3f79822SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11*b3f79822SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13*b3f79822SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*b3f79822SAndrew Rist  * software distributed under the License is distributed on an
15*b3f79822SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b3f79822SAndrew Rist  * KIND, either express or implied.  See the License for the
17*b3f79822SAndrew Rist  * specific language governing permissions and limitations
18*b3f79822SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20*b3f79822SAndrew Rist  *************************************************************/
21*b3f79822SAndrew Rist 
22*b3f79822SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sc.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir 
28cdf0e10cSrcweir 
29cdf0e10cSrcweir // INCLUDE ---------------------------------------------------------------
30cdf0e10cSrcweir 
31cdf0e10cSrcweir #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
32cdf0e10cSrcweir 
33cdf0e10cSrcweir #include <tools/debug.hxx>
34cdf0e10cSrcweir #include <rtl/math.hxx>
35cdf0e10cSrcweir #include <unotools/localedatawrapper.hxx>
36cdf0e10cSrcweir #include <svl/zforlist.hxx>
37cdf0e10cSrcweir 
38cdf0e10cSrcweir #include "dpgroup.hxx"
39cdf0e10cSrcweir #include "collect.hxx"
40cdf0e10cSrcweir #include "global.hxx"
41cdf0e10cSrcweir #include "document.hxx"
42cdf0e10cSrcweir #include "dpcachetable.hxx"
43cdf0e10cSrcweir #include "dptabsrc.hxx"
44cdf0e10cSrcweir #include "dptabres.hxx"
45cdf0e10cSrcweir #include "dpobject.hxx"
46cdf0e10cSrcweir #include "dpglobal.hxx"
47cdf0e10cSrcweir 
48cdf0e10cSrcweir #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
49cdf0e10cSrcweir #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
50cdf0e10cSrcweir 
51cdf0e10cSrcweir #include <vector>
52cdf0e10cSrcweir #include <hash_set>
53cdf0e10cSrcweir #include <hash_map>
54cdf0e10cSrcweir 
55cdf0e10cSrcweir using namespace ::com::sun::star;
56cdf0e10cSrcweir using ::com::sun::star::uno::Any;
57cdf0e10cSrcweir using ::com::sun::star::uno::Reference;
58cdf0e10cSrcweir using ::com::sun::star::uno::Sequence;
59cdf0e10cSrcweir using ::com::sun::star::uno::UNO_QUERY;
60cdf0e10cSrcweir using ::com::sun::star::uno::UNO_QUERY_THROW;
61cdf0e10cSrcweir using ::rtl::OUString;
62cdf0e10cSrcweir using ::rtl::OUStringHash;
63cdf0e10cSrcweir 
64cdf0e10cSrcweir using ::std::vector;
65cdf0e10cSrcweir using ::std::hash_set;
66cdf0e10cSrcweir using ::std::hash_map;
67cdf0e10cSrcweir using ::boost::shared_ptr;
68cdf0e10cSrcweir 
69cdf0e10cSrcweir #define D_TIMEFACTOR              86400.0
70cdf0e10cSrcweir 
71cdf0e10cSrcweir const sal_uInt16 SC_DP_LEAPYEAR = 1648;     // arbitrary leap year for date calculations
72cdf0e10cSrcweir 
73cdf0e10cSrcweir // part values for the extra "<" and ">" entries (same for all parts)
74cdf0e10cSrcweir const sal_Int32 SC_DP_DATE_FIRST = -1;
75cdf0e10cSrcweir const sal_Int32 SC_DP_DATE_LAST = 10000;
76cdf0e10cSrcweir 
77cdf0e10cSrcweir // ============================================================================
78cdf0e10cSrcweir namespace
79cdf0e10cSrcweir {
lcl_Search(SCCOL nSourceDim,ScDPTableDataCache * pCache,const std::vector<SCROW> & vIdx,SCROW nNew,SCROW & rIndex)80cdf0e10cSrcweir     sal_Bool lcl_Search( SCCOL nSourceDim, ScDPTableDataCache* pCache , const std::vector< SCROW >& vIdx, SCROW nNew , SCROW& rIndex)
81cdf0e10cSrcweir     {
82cdf0e10cSrcweir 	    rIndex = vIdx.size();
83cdf0e10cSrcweir 	    sal_Bool bFound = sal_False;
84cdf0e10cSrcweir 	    SCROW nLo = 0;
85cdf0e10cSrcweir 	    SCROW nHi = vIdx.size() - 1;
86cdf0e10cSrcweir 	    SCROW nIndex;
87cdf0e10cSrcweir 	    long nCompare;
88cdf0e10cSrcweir 	    while (nLo <= nHi)
89cdf0e10cSrcweir 	    {
90cdf0e10cSrcweir 		    nIndex = (nLo + nHi) / 2;
91cdf0e10cSrcweir 
92cdf0e10cSrcweir             const ScDPItemData* pData  = pCache->GetItemDataById( nSourceDim, vIdx[nIndex] );
93cdf0e10cSrcweir             const ScDPItemData* pDataInsert = pCache->GetItemDataById( nSourceDim, nNew );
94cdf0e10cSrcweir 
95cdf0e10cSrcweir 		    nCompare = ScDPItemData::Compare( *pData, *pDataInsert );
96cdf0e10cSrcweir 		    if (nCompare < 0)
97cdf0e10cSrcweir 			    nLo = nIndex + 1;
98cdf0e10cSrcweir 		    else
99cdf0e10cSrcweir 		    {
100cdf0e10cSrcweir 			    nHi = nIndex - 1;
101cdf0e10cSrcweir 			    if (nCompare == 0)
102cdf0e10cSrcweir 			    {
103cdf0e10cSrcweir 				    bFound = sal_True;
104cdf0e10cSrcweir 				    nLo = nIndex;
105cdf0e10cSrcweir 			    }
106cdf0e10cSrcweir 		    }
107cdf0e10cSrcweir 	    }
108cdf0e10cSrcweir 	    rIndex = nLo;
109cdf0e10cSrcweir 	    return bFound;
110cdf0e10cSrcweir     }
111cdf0e10cSrcweir 
lcl_Insert(SCCOL nSourceDim,ScDPTableDataCache * pCache,std::vector<SCROW> & vIdx,SCROW nNew)112cdf0e10cSrcweir     void  lcl_Insert( SCCOL nSourceDim, ScDPTableDataCache* pCache ,  std::vector< SCROW >& vIdx, SCROW nNew )
113cdf0e10cSrcweir     {
114cdf0e10cSrcweir         SCROW nIndex = 0;
115cdf0e10cSrcweir         if ( !lcl_Search( nSourceDim, pCache, vIdx, nNew ,nIndex ) )
116cdf0e10cSrcweir             vIdx.insert( vIdx.begin()+nIndex, nNew  );
117cdf0e10cSrcweir     }
118cdf0e10cSrcweir 
119cdf0e10cSrcweir 	template<bool bUpdateData>
120cdf0e10cSrcweir 	SCROW lcl_InsertValue( SCCOL nSourceDim, ScDPTableDataCache* pCache ,  std::vector< SCROW >& vIdx, const ScDPItemData & rData );
121cdf0e10cSrcweir 
122cdf0e10cSrcweir 	template<>
lcl_InsertValue(SCCOL nSourceDim,ScDPTableDataCache * pCache,std::vector<SCROW> & vIdx,const ScDPItemData & rData)123cdf0e10cSrcweir 	SCROW lcl_InsertValue<false>( SCCOL nSourceDim, ScDPTableDataCache* pCache ,  std::vector< SCROW >& vIdx, const ScDPItemData & rData )
124cdf0e10cSrcweir 	{
125cdf0e10cSrcweir 		SCROW nNewID = pCache->GetAdditionalItemID( rData );
126cdf0e10cSrcweir 		lcl_Insert( nSourceDim, pCache, vIdx, nNewID );
127cdf0e10cSrcweir 		return nNewID;
128cdf0e10cSrcweir 	}
129cdf0e10cSrcweir 
130cdf0e10cSrcweir 	template<>
lcl_InsertValue(SCCOL nSourceDim,ScDPTableDataCache * pCache,std::vector<SCROW> & vIdx,const ScDPItemData & rData)131cdf0e10cSrcweir 	SCROW lcl_InsertValue<true>( SCCOL nSourceDim, ScDPTableDataCache* pCache ,  std::vector< SCROW >& vIdx, const ScDPItemData & rData )
132cdf0e10cSrcweir 	{
133cdf0e10cSrcweir 		SCROW nItemId = lcl_InsertValue<false>( nSourceDim, pCache, vIdx, rData );
134cdf0e10cSrcweir 
135cdf0e10cSrcweir 		if( const ScDPItemData *pData = pCache->GetItemDataById( nSourceDim, nItemId ) )
136cdf0e10cSrcweir 			const_cast<ScDPItemData&>(*pData) = rData;
137cdf0e10cSrcweir 
138cdf0e10cSrcweir 		return nItemId;
139cdf0e10cSrcweir 	}
140cdf0e10cSrcweir 
141cdf0e10cSrcweir 	template<bool bUpdateData>
lcl_InsertValue(SCCOL nSourceDim,ScDPTableDataCache * pCache,std::vector<SCROW> & vIdx,const String & rString,const double & fValue)142cdf0e10cSrcweir     void lcl_InsertValue ( SCCOL nSourceDim, ScDPTableDataCache* pCache ,  std::vector< SCROW >& vIdx, const String&  rString, const double& fValue )
143cdf0e10cSrcweir     {
144cdf0e10cSrcweir         lcl_InsertValue<bUpdateData>( nSourceDim, pCache, vIdx, ScDPItemData( rString, fValue, sal_True ) );
145cdf0e10cSrcweir     }
146cdf0e10cSrcweir 
147cdf0e10cSrcweir 	template<bool bUpdateData>
lcl_InsertValue(SCCOL nSourceDim,ScDPTableDataCache * pCache,std::vector<SCROW> & vIdx,const String & rString,const double & fValue,sal_Int32 nDatePart)148cdf0e10cSrcweir 	void lcl_InsertValue ( SCCOL nSourceDim, ScDPTableDataCache* pCache ,  std::vector< SCROW >& vIdx, const String&  rString, const double& fValue, sal_Int32 nDatePart )
149cdf0e10cSrcweir 	{
150cdf0e10cSrcweir 		lcl_InsertValue<bUpdateData>( nSourceDim, pCache, vIdx, ScDPItemData( nDatePart, rString, fValue, ScDPItemData::MK_DATA|ScDPItemData::MK_VAL|ScDPItemData::MK_DATEPART ) );
151cdf0e10cSrcweir 	}
152cdf0e10cSrcweir 
lcl_AppendDateStr(rtl::OUStringBuffer & rBuffer,double fValue,SvNumberFormatter * pFormatter)153cdf0e10cSrcweir     void lcl_AppendDateStr( rtl::OUStringBuffer& rBuffer, double fValue, SvNumberFormatter* pFormatter )
154cdf0e10cSrcweir     {
155cdf0e10cSrcweir         sal_uLong nFormat = pFormatter->GetStandardFormat( NUMBERFORMAT_DATE, ScGlobal::eLnge );
156cdf0e10cSrcweir         String aString;
157cdf0e10cSrcweir         pFormatter->GetInputLineString( fValue, nFormat, aString );
158cdf0e10cSrcweir         rBuffer.append( aString );
159cdf0e10cSrcweir     }
160cdf0e10cSrcweir 
lcl_GetNumGroupName(double fStartValue,const ScDPNumGroupInfo & rInfo,bool bHasNonInteger,sal_Unicode cDecSeparator,SvNumberFormatter * pFormatter)161cdf0e10cSrcweir     String lcl_GetNumGroupName( double fStartValue, const ScDPNumGroupInfo& rInfo,
162cdf0e10cSrcweir         bool bHasNonInteger, sal_Unicode cDecSeparator, SvNumberFormatter* pFormatter )
163cdf0e10cSrcweir     {
164cdf0e10cSrcweir         DBG_ASSERT( cDecSeparator != 0, "cDecSeparator not initialized" );
165cdf0e10cSrcweir 
166cdf0e10cSrcweir         double fStep = rInfo.Step;
167cdf0e10cSrcweir         double fEndValue = fStartValue + fStep;
168cdf0e10cSrcweir         if ( !bHasNonInteger && ( rInfo.DateValues || !rtl::math::approxEqual( fEndValue, rInfo.End ) ) )
169cdf0e10cSrcweir         {
170cdf0e10cSrcweir             //  The second number of the group label is
171cdf0e10cSrcweir             //  (first number + size - 1) if there are only integer numbers,
172cdf0e10cSrcweir             //  (first number + size) if any non-integer numbers are involved.
173cdf0e10cSrcweir             //  Exception: The last group (containing the end value) is always
174cdf0e10cSrcweir             //  shown as including the end value (but not for dates).
175cdf0e10cSrcweir 
176cdf0e10cSrcweir             fEndValue -= 1.0;
177cdf0e10cSrcweir         }
178cdf0e10cSrcweir 
179cdf0e10cSrcweir         if ( fEndValue > rInfo.End && !rInfo.AutoEnd )
180cdf0e10cSrcweir         {
181cdf0e10cSrcweir             // limit the last group to the end value
182cdf0e10cSrcweir 
183cdf0e10cSrcweir             fEndValue = rInfo.End;
184cdf0e10cSrcweir         }
185cdf0e10cSrcweir 
186cdf0e10cSrcweir         rtl::OUStringBuffer aBuffer;
187cdf0e10cSrcweir         if ( rInfo.DateValues )
188cdf0e10cSrcweir         {
189cdf0e10cSrcweir             lcl_AppendDateStr( aBuffer, fStartValue, pFormatter );
190cdf0e10cSrcweir             aBuffer.appendAscii( " - " );   // with spaces
191cdf0e10cSrcweir             lcl_AppendDateStr( aBuffer, fEndValue, pFormatter );
192cdf0e10cSrcweir         }
193cdf0e10cSrcweir         else
194cdf0e10cSrcweir         {
195cdf0e10cSrcweir             rtl::math::doubleToUStringBuffer( aBuffer, fStartValue, rtl_math_StringFormat_Automatic,
196cdf0e10cSrcweir                 rtl_math_DecimalPlaces_Max, cDecSeparator, true );
197cdf0e10cSrcweir             aBuffer.append( (sal_Unicode) '-' );
198cdf0e10cSrcweir             rtl::math::doubleToUStringBuffer( aBuffer, fEndValue, rtl_math_StringFormat_Automatic,
199cdf0e10cSrcweir                 rtl_math_DecimalPlaces_Max, cDecSeparator, true );
200cdf0e10cSrcweir         }
201cdf0e10cSrcweir 
202cdf0e10cSrcweir         return aBuffer.makeStringAndClear();
203cdf0e10cSrcweir     }
204cdf0e10cSrcweir 
lcl_GetSpecialNumGroupName(double fValue,bool bFirst,sal_Unicode cDecSeparator,bool bDateValues,SvNumberFormatter * pFormatter)205cdf0e10cSrcweir     String lcl_GetSpecialNumGroupName( double fValue, bool bFirst, sal_Unicode cDecSeparator,
206cdf0e10cSrcweir         bool bDateValues, SvNumberFormatter* pFormatter )
207cdf0e10cSrcweir     {
208cdf0e10cSrcweir         DBG_ASSERT( cDecSeparator != 0, "cDecSeparator not initialized" );
209cdf0e10cSrcweir 
210cdf0e10cSrcweir         rtl::OUStringBuffer aBuffer;
211cdf0e10cSrcweir         aBuffer.append((sal_Unicode)( bFirst ? '<' : '>' ));
212cdf0e10cSrcweir         if ( bDateValues )
213cdf0e10cSrcweir             lcl_AppendDateStr( aBuffer, fValue, pFormatter );
214cdf0e10cSrcweir         else
215cdf0e10cSrcweir             rtl::math::doubleToUStringBuffer( aBuffer, fValue, rtl_math_StringFormat_Automatic,
216cdf0e10cSrcweir             rtl_math_DecimalPlaces_Max, cDecSeparator, true );
217cdf0e10cSrcweir         return aBuffer.makeStringAndClear();
218cdf0e10cSrcweir     }
219cdf0e10cSrcweir 
IsInteger(double fValue)220cdf0e10cSrcweir     inline bool IsInteger( double fValue )
221cdf0e10cSrcweir     {
222cdf0e10cSrcweir         return rtl::math::approxEqual( fValue, rtl::math::approxFloor(fValue) );
223cdf0e10cSrcweir     }
224cdf0e10cSrcweir 
lcl_GetNumGroupForValue(double fValue,const ScDPNumGroupInfo & rInfo,bool bHasNonInteger,sal_Unicode cDecSeparator,double & rGroupValue,ScDocument * pDoc)225cdf0e10cSrcweir     String lcl_GetNumGroupForValue( double fValue, const ScDPNumGroupInfo& rInfo, bool bHasNonInteger,
226cdf0e10cSrcweir         sal_Unicode cDecSeparator, double& rGroupValue, ScDocument* pDoc )
227cdf0e10cSrcweir     {
228cdf0e10cSrcweir         SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
229cdf0e10cSrcweir 
230cdf0e10cSrcweir         if ( fValue < rInfo.Start && !rtl::math::approxEqual( fValue, rInfo.Start ) )
231cdf0e10cSrcweir         {
232cdf0e10cSrcweir             rGroupValue = rInfo.Start - rInfo.Step;
233cdf0e10cSrcweir             return lcl_GetSpecialNumGroupName( rInfo.Start, true, cDecSeparator, rInfo.DateValues, pFormatter );
234cdf0e10cSrcweir         }
235cdf0e10cSrcweir 
236cdf0e10cSrcweir         if ( fValue > rInfo.End && !rtl::math::approxEqual( fValue, rInfo.End ) )
237cdf0e10cSrcweir         {
238cdf0e10cSrcweir             rGroupValue = rInfo.End + rInfo.Step;
239cdf0e10cSrcweir             return lcl_GetSpecialNumGroupName( rInfo.End, false, cDecSeparator, rInfo.DateValues, pFormatter );
240cdf0e10cSrcweir         }
241cdf0e10cSrcweir 
242cdf0e10cSrcweir         double fDiff = fValue - rInfo.Start;
243cdf0e10cSrcweir         double fDiv = rtl::math::approxFloor( fDiff / rInfo.Step );
244cdf0e10cSrcweir         double fGroupStart = rInfo.Start + fDiv * rInfo.Step;
245cdf0e10cSrcweir 
246cdf0e10cSrcweir         if ( rtl::math::approxEqual( fGroupStart, rInfo.End ) &&
247cdf0e10cSrcweir             !rtl::math::approxEqual( fGroupStart, rInfo.Start ) )
248cdf0e10cSrcweir         {
249cdf0e10cSrcweir             if ( !rInfo.DateValues )
250cdf0e10cSrcweir             {
251cdf0e10cSrcweir                 //  A group that would consist only of the end value is not created,
252cdf0e10cSrcweir                 //  instead the value is included in the last group before. So the
253cdf0e10cSrcweir                 //  previous group is used if the calculated group start value is the
254cdf0e10cSrcweir                 //  selected end value.
255cdf0e10cSrcweir 
256cdf0e10cSrcweir                 fDiv -= 1.0;
257cdf0e10cSrcweir                 fGroupStart = rInfo.Start + fDiv * rInfo.Step;
258cdf0e10cSrcweir             }
259cdf0e10cSrcweir             else
260cdf0e10cSrcweir             {
261cdf0e10cSrcweir                 //  For date values, the end value is instead treated as above the limit
262cdf0e10cSrcweir                 //  if it would be a group of its own.
263cdf0e10cSrcweir 
264cdf0e10cSrcweir                 rGroupValue = rInfo.End + rInfo.Step;
265cdf0e10cSrcweir                 return lcl_GetSpecialNumGroupName( rInfo.End, false, cDecSeparator, rInfo.DateValues, pFormatter );
266cdf0e10cSrcweir             }
267cdf0e10cSrcweir         }
268cdf0e10cSrcweir 
269cdf0e10cSrcweir         rGroupValue = fGroupStart;
270cdf0e10cSrcweir 
271cdf0e10cSrcweir         return lcl_GetNumGroupName( fGroupStart, rInfo, bHasNonInteger, cDecSeparator, pFormatter );
272cdf0e10cSrcweir     }
273cdf0e10cSrcweir }
274cdf0e10cSrcweir 
275cdf0e10cSrcweir class ScDPGroupDateFilter : public ScDPCacheTable::FilterBase
276cdf0e10cSrcweir {
277cdf0e10cSrcweir public:
278cdf0e10cSrcweir     ScDPGroupDateFilter(double fMatchValue, sal_Int32 nDatePart,
279cdf0e10cSrcweir                         const Date* pNullDate, const ScDPNumGroupInfo* pNumInfo);
280cdf0e10cSrcweir 
281cdf0e10cSrcweir     // Wang Xu Ming -- 2009-8-17
282cdf0e10cSrcweir     // DataPilot Migration - Cache&&Performance
283cdf0e10cSrcweir     virtual bool match(const ScDPItemData & rCellData) const;
284cdf0e10cSrcweir     // End Comments
285cdf0e10cSrcweir 
286cdf0e10cSrcweir private:
287cdf0e10cSrcweir     ScDPGroupDateFilter(); // disabled
288cdf0e10cSrcweir 
289cdf0e10cSrcweir     const Date*             mpNullDate;
290cdf0e10cSrcweir     const ScDPNumGroupInfo* mpNumInfo;
291cdf0e10cSrcweir     double                  mfMatchValue;
292cdf0e10cSrcweir     sal_Int32               mnDatePart;
293cdf0e10cSrcweir };
294cdf0e10cSrcweir 
295cdf0e10cSrcweir // ----------------------------------------------------------------------------
296cdf0e10cSrcweir 
ScDPGroupDateFilter(double fMatchValue,sal_Int32 nDatePart,const Date * pNullDate,const ScDPNumGroupInfo * pNumInfo)297cdf0e10cSrcweir ScDPGroupDateFilter::ScDPGroupDateFilter(double fMatchValue, sal_Int32 nDatePart,
298cdf0e10cSrcweir                                  const Date* pNullDate, const ScDPNumGroupInfo* pNumInfo) :
299cdf0e10cSrcweir     mpNullDate(pNullDate),
300cdf0e10cSrcweir     mpNumInfo(pNumInfo),
301cdf0e10cSrcweir     mfMatchValue(fMatchValue),
302cdf0e10cSrcweir     mnDatePart(nDatePart)
303cdf0e10cSrcweir {
304cdf0e10cSrcweir //  fprintf(stdout, "ScDPCacheTable:DateGroupFilter::DateGroupFilter: match value = %g; date part = %ld\n",
305cdf0e10cSrcweir //          mfMatchValue, mnDatePart);
306cdf0e10cSrcweir }
match(const ScDPItemData & rCellData) const307cdf0e10cSrcweir bool ScDPGroupDateFilter::match( const ScDPItemData & rCellData ) const
308cdf0e10cSrcweir {
309cdf0e10cSrcweir     using namespace ::com::sun::star::sheet;
310cdf0e10cSrcweir     using ::rtl::math::approxFloor;
311cdf0e10cSrcweir     using ::rtl::math::approxEqual;
312cdf0e10cSrcweir 
313cdf0e10cSrcweir 	if ( !rCellData.IsValue() )
314cdf0e10cSrcweir 		return false;
315cdf0e10cSrcweir //	ScDPCacheCell rCell( rCellData.fValue );
316cdf0e10cSrcweir     if (!mpNumInfo)
317cdf0e10cSrcweir         return false;
318cdf0e10cSrcweir 
319cdf0e10cSrcweir     // Start and end dates are inclusive.  (An end date without a time value
320cdf0e10cSrcweir     // is included, while an end date with a time value is not.)
321cdf0e10cSrcweir 
322cdf0e10cSrcweir     if ( rCellData.GetValue() < mpNumInfo->Start && !approxEqual(rCellData.GetValue(), mpNumInfo->Start) )
323cdf0e10cSrcweir         return static_cast<sal_Int32>(mfMatchValue) == SC_DP_DATE_FIRST;
324cdf0e10cSrcweir 
325cdf0e10cSrcweir     if ( rCellData.GetValue() > mpNumInfo->End && !approxEqual(rCellData.GetValue(), mpNumInfo->End) )
326cdf0e10cSrcweir         return static_cast<sal_Int32>(mfMatchValue) == SC_DP_DATE_LAST;
327cdf0e10cSrcweir 
328cdf0e10cSrcweir     if (mnDatePart == DataPilotFieldGroupBy::HOURS || mnDatePart == DataPilotFieldGroupBy::MINUTES ||
329cdf0e10cSrcweir         mnDatePart == DataPilotFieldGroupBy::SECONDS)
330cdf0e10cSrcweir     {
331cdf0e10cSrcweir         // handle time
332cdf0e10cSrcweir         // (as in the cell functions, ScInterpreter::ScGetHour etc.: seconds are rounded)
333cdf0e10cSrcweir 
334cdf0e10cSrcweir         double time = rCellData.GetValue() - approxFloor(rCellData.GetValue());
335cdf0e10cSrcweir         long seconds = static_cast<long>(approxFloor(time*D_TIMEFACTOR + 0.5));
336cdf0e10cSrcweir 
337cdf0e10cSrcweir         switch (mnDatePart)
338cdf0e10cSrcweir         {
339cdf0e10cSrcweir             case DataPilotFieldGroupBy::HOURS:
340cdf0e10cSrcweir             {
341cdf0e10cSrcweir                 sal_Int32 hrs = seconds / 3600;
342cdf0e10cSrcweir                 sal_Int32 matchHrs = static_cast<sal_Int32>(mfMatchValue);
343cdf0e10cSrcweir                 return hrs == matchHrs;
344cdf0e10cSrcweir             }
345cdf0e10cSrcweir             case DataPilotFieldGroupBy::MINUTES:
346cdf0e10cSrcweir             {
347cdf0e10cSrcweir                 sal_Int32 minutes = (seconds % 3600) / 60;
348cdf0e10cSrcweir                 sal_Int32 matchMinutes = static_cast<sal_Int32>(mfMatchValue);
349cdf0e10cSrcweir                 return minutes == matchMinutes;
350cdf0e10cSrcweir             }
351cdf0e10cSrcweir             case DataPilotFieldGroupBy::SECONDS:
352cdf0e10cSrcweir             {
353cdf0e10cSrcweir                 sal_Int32 sec = seconds % 60;
354cdf0e10cSrcweir                 sal_Int32 matchSec = static_cast<sal_Int32>(mfMatchValue);
355cdf0e10cSrcweir                 return sec == matchSec;
356cdf0e10cSrcweir             }
357cdf0e10cSrcweir             default:
358cdf0e10cSrcweir                 DBG_ERROR("invalid time part");
359cdf0e10cSrcweir         }
360cdf0e10cSrcweir         return false;
361cdf0e10cSrcweir     }
362cdf0e10cSrcweir 
363cdf0e10cSrcweir     Date date = *mpNullDate + static_cast<long>(approxFloor(rCellData.GetValue()));
364cdf0e10cSrcweir     switch (mnDatePart)
365cdf0e10cSrcweir     {
366cdf0e10cSrcweir         case DataPilotFieldGroupBy::YEARS:
367cdf0e10cSrcweir         {
368cdf0e10cSrcweir             sal_Int32 year = static_cast<sal_Int32>(date.GetYear());
369cdf0e10cSrcweir             sal_Int32 matchYear = static_cast<sal_Int32>(mfMatchValue);
370cdf0e10cSrcweir             return year == matchYear;
371cdf0e10cSrcweir         }
372cdf0e10cSrcweir         case DataPilotFieldGroupBy::QUARTERS:
373cdf0e10cSrcweir         {
374cdf0e10cSrcweir             sal_Int32 qtr =  1 + (static_cast<sal_Int32>(date.GetMonth()) - 1) / 3;
375cdf0e10cSrcweir             sal_Int32 matchQtr = static_cast<sal_Int32>(mfMatchValue);
376cdf0e10cSrcweir             return qtr == matchQtr;
377cdf0e10cSrcweir         }
378cdf0e10cSrcweir         case DataPilotFieldGroupBy::MONTHS:
379cdf0e10cSrcweir         {
380cdf0e10cSrcweir             sal_Int32 month = static_cast<sal_Int32>(date.GetMonth());
381cdf0e10cSrcweir             sal_Int32 matchMonth = static_cast<sal_Int32>(mfMatchValue);
382cdf0e10cSrcweir             return month == matchMonth;
383cdf0e10cSrcweir         }
384cdf0e10cSrcweir         case DataPilotFieldGroupBy::DAYS:
385cdf0e10cSrcweir         {
386cdf0e10cSrcweir             Date yearStart(1, 1, date.GetYear());
387cdf0e10cSrcweir             sal_Int32 days = (date - yearStart) + 1;       // Jan 01 has value 1
388cdf0e10cSrcweir             if (days >= 60 && !date.IsLeapYear())
389cdf0e10cSrcweir             {
390cdf0e10cSrcweir                 // This is not a leap year.  Adjust the value accordingly.
391cdf0e10cSrcweir                 ++days;
392cdf0e10cSrcweir             }
393cdf0e10cSrcweir             sal_Int32 matchDays = static_cast<sal_Int32>(mfMatchValue);
394cdf0e10cSrcweir             return days == matchDays;
395cdf0e10cSrcweir         }
396cdf0e10cSrcweir         default:
397cdf0e10cSrcweir             DBG_ERROR("invalid date part");
398cdf0e10cSrcweir     }
399cdf0e10cSrcweir 
400cdf0e10cSrcweir     return false;
401cdf0e10cSrcweir }
402cdf0e10cSrcweir // -----------------------------------------------------------------------
403cdf0e10cSrcweir 
ScDPDateGroupHelper(const ScDPNumGroupInfo & rInfo,sal_Int32 nPart)404cdf0e10cSrcweir ScDPDateGroupHelper::ScDPDateGroupHelper( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart ) :
405cdf0e10cSrcweir     aNumInfo( rInfo ),
406cdf0e10cSrcweir     nDatePart( nPart )
407cdf0e10cSrcweir {
408cdf0e10cSrcweir }
409cdf0e10cSrcweir 
~ScDPDateGroupHelper()410cdf0e10cSrcweir ScDPDateGroupHelper::~ScDPDateGroupHelper()
411cdf0e10cSrcweir {
412cdf0e10cSrcweir }
413cdf0e10cSrcweir 
lcl_GetTwoDigitString(sal_Int32 nValue)414cdf0e10cSrcweir String lcl_GetTwoDigitString( sal_Int32 nValue )
415cdf0e10cSrcweir {
416cdf0e10cSrcweir     String aRet = String::CreateFromInt32( nValue );
417cdf0e10cSrcweir     if ( aRet.Len() < 2 )
418cdf0e10cSrcweir         aRet.Insert( (sal_Unicode)'0', 0 );
419cdf0e10cSrcweir     return aRet;
420cdf0e10cSrcweir }
421cdf0e10cSrcweir 
lcl_GetDateGroupName(sal_Int32 nDatePart,sal_Int32 nValue,SvNumberFormatter * pFormatter)422cdf0e10cSrcweir String lcl_GetDateGroupName( sal_Int32 nDatePart, sal_Int32 nValue, SvNumberFormatter* pFormatter )
423cdf0e10cSrcweir {
424cdf0e10cSrcweir     String aRet;
425cdf0e10cSrcweir     switch ( nDatePart )
426cdf0e10cSrcweir     {
427cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::YEARS:
428cdf0e10cSrcweir             aRet = String::CreateFromInt32( nValue );
429cdf0e10cSrcweir             break;
430cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS:
431cdf0e10cSrcweir             aRet = ScGlobal::pLocaleData->getQuarterAbbreviation( (sal_Int16)(nValue - 1) );    // nValue is 1-based
432cdf0e10cSrcweir             break;
433cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS:
434cdf0e10cSrcweir             //! cache getMonths() result?
435cdf0e10cSrcweir             aRet = ScGlobal::GetCalendar()->getDisplayName(
436cdf0e10cSrcweir 						::com::sun::star::i18n::CalendarDisplayIndex::MONTH,
437cdf0e10cSrcweir 						sal_Int16(nValue-1), 0 );    // 0-based, get short name
438cdf0e10cSrcweir             break;
439cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS:
440cdf0e10cSrcweir             {
441cdf0e10cSrcweir                 Date aDate( 1, 1, SC_DP_LEAPYEAR );
442cdf0e10cSrcweir                 aDate += ( nValue - 1 );            // nValue is 1-based
443cdf0e10cSrcweir                 Date aNullDate = *(pFormatter->GetNullDate());
444cdf0e10cSrcweir                 long nDays = aDate - aNullDate;
445cdf0e10cSrcweir 
446cdf0e10cSrcweir                 sal_uLong nFormat = pFormatter->GetFormatIndex( NF_DATE_SYS_DDMMM, ScGlobal::eLnge );
447cdf0e10cSrcweir                 Color* pColor;
448cdf0e10cSrcweir                 pFormatter->GetOutputString( nDays, nFormat, aRet, &pColor );
449cdf0e10cSrcweir             }
450cdf0e10cSrcweir             break;
451cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::HOURS:
452cdf0e10cSrcweir             //! allow am/pm format?
453cdf0e10cSrcweir             aRet = lcl_GetTwoDigitString( nValue );
454cdf0e10cSrcweir             break;
455cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::MINUTES:
456cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::SECONDS:
457cdf0e10cSrcweir             aRet = ScGlobal::pLocaleData->getTimeSep();
458cdf0e10cSrcweir             aRet.Append( lcl_GetTwoDigitString( nValue ) );
459cdf0e10cSrcweir             break;
460cdf0e10cSrcweir         default:
461cdf0e10cSrcweir             DBG_ERROR("invalid date part");
462cdf0e10cSrcweir     }
463cdf0e10cSrcweir     return aRet;
464cdf0e10cSrcweir }
465cdf0e10cSrcweir 
lcl_GetDatePartValue(double fValue,sal_Int32 nDatePart,SvNumberFormatter * pFormatter,const ScDPNumGroupInfo * pNumInfo)466cdf0e10cSrcweir sal_Int32 lcl_GetDatePartValue( double fValue, sal_Int32 nDatePart, SvNumberFormatter* pFormatter,
467cdf0e10cSrcweir                                 const ScDPNumGroupInfo* pNumInfo )
468cdf0e10cSrcweir {
469cdf0e10cSrcweir     // Start and end are inclusive
470cdf0e10cSrcweir     // (End date without a time value is included, with a time value it's not)
471cdf0e10cSrcweir 
472cdf0e10cSrcweir     if ( pNumInfo )
473cdf0e10cSrcweir     {
474cdf0e10cSrcweir         if ( fValue < pNumInfo->Start && !rtl::math::approxEqual( fValue, pNumInfo->Start ) )
475cdf0e10cSrcweir             return SC_DP_DATE_FIRST;
476cdf0e10cSrcweir         if ( fValue > pNumInfo->End && !rtl::math::approxEqual( fValue, pNumInfo->End ) )
477cdf0e10cSrcweir             return SC_DP_DATE_LAST;
478cdf0e10cSrcweir     }
479cdf0e10cSrcweir 
480cdf0e10cSrcweir     sal_Int32 nResult = 0;
481cdf0e10cSrcweir 
482cdf0e10cSrcweir     if ( nDatePart == com::sun::star::sheet::DataPilotFieldGroupBy::HOURS || nDatePart == com::sun::star::sheet::DataPilotFieldGroupBy::MINUTES || nDatePart == com::sun::star::sheet::DataPilotFieldGroupBy::SECONDS )
483cdf0e10cSrcweir     {
484cdf0e10cSrcweir         // handle time
485cdf0e10cSrcweir         // (as in the cell functions, ScInterpreter::ScGetHour etc.: seconds are rounded)
486cdf0e10cSrcweir 
487cdf0e10cSrcweir         double fTime = fValue - ::rtl::math::approxFloor(fValue);
488cdf0e10cSrcweir         long nSeconds = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5);
489cdf0e10cSrcweir 
490cdf0e10cSrcweir         switch ( nDatePart )
491cdf0e10cSrcweir         {
492cdf0e10cSrcweir             case com::sun::star::sheet::DataPilotFieldGroupBy::HOURS:
493cdf0e10cSrcweir                 nResult = nSeconds / 3600;
494cdf0e10cSrcweir                 break;
495cdf0e10cSrcweir             case com::sun::star::sheet::DataPilotFieldGroupBy::MINUTES:
496cdf0e10cSrcweir                 nResult = ( nSeconds % 3600 ) / 60;
497cdf0e10cSrcweir                 break;
498cdf0e10cSrcweir             case com::sun::star::sheet::DataPilotFieldGroupBy::SECONDS:
499cdf0e10cSrcweir                 nResult = nSeconds % 60;
500cdf0e10cSrcweir                 break;
501cdf0e10cSrcweir         }
502cdf0e10cSrcweir     }
503cdf0e10cSrcweir     else
504cdf0e10cSrcweir     {
505cdf0e10cSrcweir         Date aDate = *(pFormatter->GetNullDate());
506cdf0e10cSrcweir         aDate += (long)::rtl::math::approxFloor( fValue );
507cdf0e10cSrcweir 
508cdf0e10cSrcweir         switch ( nDatePart )
509cdf0e10cSrcweir         {
510cdf0e10cSrcweir             case com::sun::star::sheet::DataPilotFieldGroupBy::YEARS:
511cdf0e10cSrcweir                 nResult = aDate.GetYear();
512cdf0e10cSrcweir                 break;
513cdf0e10cSrcweir             case com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS:
514cdf0e10cSrcweir                 nResult = 1 + ( aDate.GetMonth() - 1 ) / 3;     // 1..4
515cdf0e10cSrcweir                 break;
516cdf0e10cSrcweir             case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS:
517cdf0e10cSrcweir                 nResult = aDate.GetMonth();     // 1..12
518cdf0e10cSrcweir                 break;
519cdf0e10cSrcweir             case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS:
520cdf0e10cSrcweir                 {
521cdf0e10cSrcweir                     Date aYearStart( 1, 1, aDate.GetYear() );
522cdf0e10cSrcweir                     nResult = ( aDate - aYearStart ) + 1;       // Jan 01 has value 1
523cdf0e10cSrcweir                     if ( nResult >= 60 && !aDate.IsLeapYear() )
524cdf0e10cSrcweir                     {
525cdf0e10cSrcweir                         // days are counted from 1 to 366 - if not from a leap year, adjust
526cdf0e10cSrcweir                         ++nResult;
527cdf0e10cSrcweir                     }
528cdf0e10cSrcweir                 }
529cdf0e10cSrcweir                 break;
530cdf0e10cSrcweir             default:
531cdf0e10cSrcweir                 DBG_ERROR("invalid date part");
532cdf0e10cSrcweir         }
533cdf0e10cSrcweir     }
534cdf0e10cSrcweir 
535cdf0e10cSrcweir     return nResult;
536cdf0e10cSrcweir }
537cdf0e10cSrcweir 
lcl_DateContained(sal_Int32 nGroupPart,const ScDPItemData & rGroupData,sal_Int32 nBasePart,const ScDPItemData & rBaseData)538cdf0e10cSrcweir sal_Bool lcl_DateContained( sal_Int32 nGroupPart, const ScDPItemData& rGroupData,
539cdf0e10cSrcweir                         sal_Int32 nBasePart, const ScDPItemData& rBaseData )
540cdf0e10cSrcweir {
541cdf0e10cSrcweir     if ( !rGroupData.IsValue() || !rBaseData.IsValue() )
542cdf0e10cSrcweir     {
543cdf0e10cSrcweir         // non-numeric entries involved: only match equal entries
544cdf0e10cSrcweir         return rGroupData.IsCaseInsEqual( rBaseData );
545cdf0e10cSrcweir     }
546cdf0e10cSrcweir 
547cdf0e10cSrcweir     // no approxFloor needed, values were created from integers
548cdf0e10cSrcweir // Wang Xu Ming -- 2009-8-17
549cdf0e10cSrcweir // DataPilot Migration - Cache&&Performance
550cdf0e10cSrcweir     sal_Int32 nGroupValue = (sal_Int32) rGroupData.GetValue();
551cdf0e10cSrcweir     sal_Int32 nBaseValue = (sal_Int32) rBaseData.GetValue();
552cdf0e10cSrcweir // End Comments
553cdf0e10cSrcweir     if ( nBasePart > nGroupPart )
554cdf0e10cSrcweir     {
555cdf0e10cSrcweir         // switch, so the base part is the smaller (inner) part
556cdf0e10cSrcweir 
557cdf0e10cSrcweir         ::std::swap( nGroupPart, nBasePart );
558cdf0e10cSrcweir         ::std::swap( nGroupValue, nBaseValue );
559cdf0e10cSrcweir     }
560cdf0e10cSrcweir 
561cdf0e10cSrcweir     if ( nGroupValue == SC_DP_DATE_FIRST || nGroupValue == SC_DP_DATE_LAST ||
562cdf0e10cSrcweir          nBaseValue == SC_DP_DATE_FIRST || nBaseValue == SC_DP_DATE_LAST )
563cdf0e10cSrcweir     {
564cdf0e10cSrcweir         // first/last entry matches only itself
565cdf0e10cSrcweir         return ( nGroupValue == nBaseValue );
566cdf0e10cSrcweir     }
567cdf0e10cSrcweir 
568cdf0e10cSrcweir     sal_Bool bContained = sal_True;
569cdf0e10cSrcweir     switch ( nBasePart )        // inner part
570cdf0e10cSrcweir     {
571cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS:
572cdf0e10cSrcweir             // a month is only contained in its quarter
573cdf0e10cSrcweir             if ( nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS )
574cdf0e10cSrcweir             {
575cdf0e10cSrcweir                 // months and quarters are both 1-based
576cdf0e10cSrcweir                 bContained = ( nGroupValue - 1 == ( nBaseValue - 1 ) / 3 );
577cdf0e10cSrcweir             }
578cdf0e10cSrcweir             break;
579cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS:
580cdf0e10cSrcweir             // a day is only contained in its quarter or month
581cdf0e10cSrcweir             if ( nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS || nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS )
582cdf0e10cSrcweir             {
583cdf0e10cSrcweir                 Date aDate( 1, 1, SC_DP_LEAPYEAR );
584cdf0e10cSrcweir                 aDate += ( nBaseValue - 1 );            // days are 1-based
585cdf0e10cSrcweir                 sal_Int32 nCompare = aDate.GetMonth();
586cdf0e10cSrcweir                 if ( nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS )
587cdf0e10cSrcweir                     nCompare = ( ( nCompare - 1 ) / 3 ) + 1;    // get quarter from date
588cdf0e10cSrcweir 
589cdf0e10cSrcweir                 bContained = ( nGroupValue == nCompare );
590cdf0e10cSrcweir             }
591cdf0e10cSrcweir             break;
592cdf0e10cSrcweir 
593cdf0e10cSrcweir         // other parts: everything is contained
594cdf0e10cSrcweir     }
595cdf0e10cSrcweir 
596cdf0e10cSrcweir     return bContained;
597cdf0e10cSrcweir }
598cdf0e10cSrcweir 
lcl_GetSpecialDateName(double fValue,bool bFirst,SvNumberFormatter * pFormatter)599cdf0e10cSrcweir String lcl_GetSpecialDateName( double fValue, bool bFirst, SvNumberFormatter* pFormatter )
600cdf0e10cSrcweir {
601cdf0e10cSrcweir     rtl::OUStringBuffer aBuffer;
602cdf0e10cSrcweir     aBuffer.append((sal_Unicode)( bFirst ? '<' : '>' ));
603cdf0e10cSrcweir     lcl_AppendDateStr( aBuffer, fValue, pFormatter );
604cdf0e10cSrcweir     return aBuffer.makeStringAndClear();
605cdf0e10cSrcweir }
606cdf0e10cSrcweir 
FillColumnEntries(SCCOL nSourceDim,ScDPTableDataCache * pCache,std::vector<SCROW> & rEntries,const std::vector<SCROW> & rOriginal) const607cdf0e10cSrcweir void ScDPDateGroupHelper::FillColumnEntries( SCCOL nSourceDim, ScDPTableDataCache* pCache, std::vector< SCROW >& rEntries, const std::vector< SCROW >& rOriginal  ) const
608cdf0e10cSrcweir {
609cdf0e10cSrcweir     // auto min/max is only used for "Years" part, but the loop is always needed
610cdf0e10cSrcweir     double fSourceMin = 0.0;
611cdf0e10cSrcweir     double fSourceMax = 0.0;
612cdf0e10cSrcweir     bool bFirst = true;
613cdf0e10cSrcweir 
614cdf0e10cSrcweir     size_t  nOriginalCount = rOriginal.size();
615cdf0e10cSrcweir     for (size_t nOriginalPos=0; nOriginalPos<nOriginalCount; nOriginalPos++)
616cdf0e10cSrcweir     {
617cdf0e10cSrcweir         const  ScDPItemData* pItemData = pCache->GetItemDataById( nSourceDim, rOriginal[nOriginalPos] );
618cdf0e10cSrcweir         if ( pItemData->HasStringData() )
619cdf0e10cSrcweir         {
620cdf0e10cSrcweir             // string data: just copy
621cdf0e10cSrcweir             lcl_Insert( nSourceDim, pCache , rEntries,  rOriginal[nOriginalPos] );
622cdf0e10cSrcweir         }
623cdf0e10cSrcweir         else
624cdf0e10cSrcweir         {
625cdf0e10cSrcweir             double fSourceValue = pItemData->GetValue();
626cdf0e10cSrcweir             if ( bFirst )
627cdf0e10cSrcweir             {
628cdf0e10cSrcweir                 fSourceMin = fSourceMax = fSourceValue;
629cdf0e10cSrcweir                 bFirst = false;
630cdf0e10cSrcweir             }
631cdf0e10cSrcweir             else
632cdf0e10cSrcweir             {
633cdf0e10cSrcweir                 if ( fSourceValue < fSourceMin )
634cdf0e10cSrcweir                     fSourceMin = fSourceValue;
635cdf0e10cSrcweir                 if ( fSourceValue > fSourceMax )
636cdf0e10cSrcweir                     fSourceMax = fSourceValue;
637cdf0e10cSrcweir             }
638cdf0e10cSrcweir         }
639cdf0e10cSrcweir     }
640cdf0e10cSrcweir 
641cdf0e10cSrcweir     // For the start/end values, use the same date rounding as in ScDPNumGroupDimension::GetNumEntries
642cdf0e10cSrcweir     // (but not for the list of available years):
643cdf0e10cSrcweir     if ( aNumInfo.AutoStart )
644cdf0e10cSrcweir         const_cast<ScDPDateGroupHelper*>(this)->aNumInfo.Start = rtl::math::approxFloor( fSourceMin );
645cdf0e10cSrcweir     if ( aNumInfo.AutoEnd )
646cdf0e10cSrcweir         const_cast<ScDPDateGroupHelper*>(this)->aNumInfo.End = rtl::math::approxFloor( fSourceMax ) + 1;
647cdf0e10cSrcweir 
648cdf0e10cSrcweir     //! if not automatic, limit fSourceMin/fSourceMax for list of year values?
649cdf0e10cSrcweir     SvNumberFormatter* pFormatter = pCache->GetDoc()->GetFormatTable();
650cdf0e10cSrcweir 
651cdf0e10cSrcweir     long nStart = 0;
652cdf0e10cSrcweir     long nEnd = 0;          // including
653cdf0e10cSrcweir 
654cdf0e10cSrcweir     switch ( nDatePart )
655cdf0e10cSrcweir     {
656cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::YEARS:
657cdf0e10cSrcweir             nStart = lcl_GetDatePartValue( fSourceMin, com::sun::star::sheet::DataPilotFieldGroupBy::YEARS, pFormatter, NULL );
658cdf0e10cSrcweir             nEnd = lcl_GetDatePartValue( fSourceMax, com::sun::star::sheet::DataPilotFieldGroupBy::YEARS, pFormatter, NULL );
659cdf0e10cSrcweir             break;
660cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS: nStart = 1; nEnd = 4;   break;
661cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS:   nStart = 1; nEnd = 12;  break;
662cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS:     nStart = 1; nEnd = 366; break;
663cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::HOURS:    nStart = 0; nEnd = 23;  break;
664cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::MINUTES:  nStart = 0; nEnd = 59;  break;
665cdf0e10cSrcweir         case com::sun::star::sheet::DataPilotFieldGroupBy::SECONDS:  nStart = 0; nEnd = 59;  break;
666cdf0e10cSrcweir         default:
667cdf0e10cSrcweir             DBG_ERROR("invalid date part");
668cdf0e10cSrcweir     }
669cdf0e10cSrcweir 
670cdf0e10cSrcweir     for ( sal_Int32 nValue = nStart; nValue <= nEnd; nValue++ )
671cdf0e10cSrcweir     {
672cdf0e10cSrcweir         String aName = lcl_GetDateGroupName( nDatePart, nValue, pFormatter );
673cdf0e10cSrcweir 	  lcl_InsertValue<false>( nSourceDim, pCache, rEntries, aName, nValue, nDatePart );
674cdf0e10cSrcweir     }
675cdf0e10cSrcweir 
676cdf0e10cSrcweir     // add first/last entry (min/max)
677cdf0e10cSrcweir 	String aFirstName = lcl_GetSpecialDateName( aNumInfo.Start, true, pFormatter );
678cdf0e10cSrcweir 	lcl_InsertValue<true>( nSourceDim, pCache, rEntries, aFirstName, SC_DP_DATE_FIRST, nDatePart );
679cdf0e10cSrcweir 
680cdf0e10cSrcweir 	String aLastName = lcl_GetSpecialDateName( aNumInfo.End, false, pFormatter );
681cdf0e10cSrcweir 	lcl_InsertValue<true>( nSourceDim, pCache, rEntries, aLastName, SC_DP_DATE_LAST, nDatePart );
682cdf0e10cSrcweir }
683cdf0e10cSrcweir 
684cdf0e10cSrcweir // -----------------------------------------------------------------------
685cdf0e10cSrcweir 
ScDPGroupItem(const ScDPItemData & rName)686cdf0e10cSrcweir ScDPGroupItem::ScDPGroupItem( const ScDPItemData& rName ) :
687cdf0e10cSrcweir     aGroupName( rName )
688cdf0e10cSrcweir {
689cdf0e10cSrcweir }
690cdf0e10cSrcweir 
~ScDPGroupItem()691cdf0e10cSrcweir ScDPGroupItem::~ScDPGroupItem()
692cdf0e10cSrcweir {
693cdf0e10cSrcweir }
694cdf0e10cSrcweir 
AddElement(const ScDPItemData & rName)695cdf0e10cSrcweir void ScDPGroupItem::AddElement( const ScDPItemData& rName )
696cdf0e10cSrcweir {
697cdf0e10cSrcweir     aElements.push_back( rName );
698cdf0e10cSrcweir }
699cdf0e10cSrcweir 
HasElement(const ScDPItemData & rData) const700cdf0e10cSrcweir bool ScDPGroupItem::HasElement( const ScDPItemData& rData ) const
701cdf0e10cSrcweir {
702cdf0e10cSrcweir     for ( ScDPItemDataVec::const_iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ )
703cdf0e10cSrcweir         if ( aIter->IsCaseInsEqual( rData ) )
704cdf0e10cSrcweir             return true;
705cdf0e10cSrcweir 
706cdf0e10cSrcweir     return false;
707cdf0e10cSrcweir }
708cdf0e10cSrcweir 
HasCommonElement(const ScDPGroupItem & rOther) const709cdf0e10cSrcweir bool ScDPGroupItem::HasCommonElement( const ScDPGroupItem& rOther ) const
710cdf0e10cSrcweir {
711cdf0e10cSrcweir     for ( ScDPItemDataVec::const_iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ )
712cdf0e10cSrcweir         if ( rOther.HasElement( *aIter ) )
713cdf0e10cSrcweir             return true;
714cdf0e10cSrcweir 
715cdf0e10cSrcweir     return false;
716cdf0e10cSrcweir }
717cdf0e10cSrcweir 
FillGroupFilter(ScDPCacheTable::GroupFilter & rFilter) const718cdf0e10cSrcweir void ScDPGroupItem::FillGroupFilter( ScDPCacheTable::GroupFilter& rFilter ) const
719cdf0e10cSrcweir {
720cdf0e10cSrcweir     ScDPItemDataVec::const_iterator itrEnd = aElements.end();
721cdf0e10cSrcweir     for (ScDPItemDataVec::const_iterator itr = aElements.begin(); itr != itrEnd; ++itr)
722cdf0e10cSrcweir // Wang Xu Ming -- 2009-8-17
723cdf0e10cSrcweir // DataPilot Migration - Cache&&Performance
724cdf0e10cSrcweir         rFilter.addMatchItem(itr->GetString(), itr->GetValue(), itr->IsValue());
725cdf0e10cSrcweir // End Comments
726cdf0e10cSrcweir }
727cdf0e10cSrcweir 
728cdf0e10cSrcweir // -----------------------------------------------------------------------
729cdf0e10cSrcweir 
ScDPGroupDimension(long nSource,const String & rNewName)730cdf0e10cSrcweir ScDPGroupDimension::ScDPGroupDimension( long nSource, const String& rNewName ) :
731cdf0e10cSrcweir     nSourceDim( nSource ),
732cdf0e10cSrcweir     nGroupDim( -1 ),
733cdf0e10cSrcweir     aGroupName( rNewName ),
734cdf0e10cSrcweir     pDateHelper( NULL )/*,
735cdf0e10cSrcweir     pCollection( NULL )*/
736cdf0e10cSrcweir {
737cdf0e10cSrcweir }
738cdf0e10cSrcweir 
~ScDPGroupDimension()739cdf0e10cSrcweir ScDPGroupDimension::~ScDPGroupDimension()
740cdf0e10cSrcweir {
741cdf0e10cSrcweir     delete pDateHelper;
742cdf0e10cSrcweir     maMemberEntries.clear();
743cdf0e10cSrcweir }
744cdf0e10cSrcweir 
ScDPGroupDimension(const ScDPGroupDimension & rOther)745cdf0e10cSrcweir ScDPGroupDimension::ScDPGroupDimension( const ScDPGroupDimension& rOther ) :
746cdf0e10cSrcweir     nSourceDim( rOther.nSourceDim ),
747cdf0e10cSrcweir     nGroupDim( rOther.nGroupDim ),
748cdf0e10cSrcweir     aGroupName( rOther.aGroupName ),
749cdf0e10cSrcweir     pDateHelper( NULL ),
750cdf0e10cSrcweir    aItems( rOther.aItems )
751cdf0e10cSrcweir {
752cdf0e10cSrcweir     if ( rOther.pDateHelper )
753cdf0e10cSrcweir         pDateHelper = new ScDPDateGroupHelper( *rOther.pDateHelper );
754cdf0e10cSrcweir }
755cdf0e10cSrcweir 
operator =(const ScDPGroupDimension & rOther)756cdf0e10cSrcweir ScDPGroupDimension&	ScDPGroupDimension::operator=( const ScDPGroupDimension& rOther )
757cdf0e10cSrcweir {
758cdf0e10cSrcweir     nSourceDim = rOther.nSourceDim;
759cdf0e10cSrcweir     nGroupDim  = rOther.nGroupDim;
760cdf0e10cSrcweir     aGroupName = rOther.aGroupName;
761cdf0e10cSrcweir     aItems     = rOther.aItems;
762cdf0e10cSrcweir 
763cdf0e10cSrcweir     delete pDateHelper;
764cdf0e10cSrcweir     if ( rOther.pDateHelper )
765cdf0e10cSrcweir         pDateHelper = new ScDPDateGroupHelper( *rOther.pDateHelper );
766cdf0e10cSrcweir     else
767cdf0e10cSrcweir         pDateHelper = NULL;
768cdf0e10cSrcweir 
769cdf0e10cSrcweir     return *this;
770cdf0e10cSrcweir }
771cdf0e10cSrcweir 
MakeDateHelper(const ScDPNumGroupInfo & rInfo,sal_Int32 nPart)772cdf0e10cSrcweir void ScDPGroupDimension::MakeDateHelper( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
773cdf0e10cSrcweir {
774cdf0e10cSrcweir     delete pDateHelper;
775cdf0e10cSrcweir     pDateHelper = new ScDPDateGroupHelper( rInfo, nPart );
776cdf0e10cSrcweir }
777cdf0e10cSrcweir 
AddItem(const ScDPGroupItem & rItem)778cdf0e10cSrcweir void ScDPGroupDimension::AddItem( const ScDPGroupItem& rItem )
779cdf0e10cSrcweir {
780cdf0e10cSrcweir     aItems.push_back( rItem );
781cdf0e10cSrcweir }
782cdf0e10cSrcweir 
SetGroupDim(long nDim)783cdf0e10cSrcweir void ScDPGroupDimension::SetGroupDim( long nDim )
784cdf0e10cSrcweir {
785cdf0e10cSrcweir     nGroupDim = nDim;
786cdf0e10cSrcweir }
787cdf0e10cSrcweir // Wang Xu Ming -- 2009-9-2
788cdf0e10cSrcweir // DataPilot Migration - Cache&&Performance
GetColumnEntries(const ScDPCacheTable & rCacheTable,const std::vector<SCROW> & rOriginal) const789cdf0e10cSrcweir const std::vector< SCROW >&  ScDPGroupDimension::GetColumnEntries( const ScDPCacheTable&  rCacheTable, const std::vector< SCROW >& rOriginal  )  const
790cdf0e10cSrcweir {
791cdf0e10cSrcweir     if ( maMemberEntries.empty() )
792cdf0e10cSrcweir     {
793cdf0e10cSrcweir         if ( pDateHelper )
794cdf0e10cSrcweir         {
795cdf0e10cSrcweir             pDateHelper->FillColumnEntries(  (SCCOL)GetSourceDim(), rCacheTable.GetCache(), maMemberEntries,  rOriginal  );
796cdf0e10cSrcweir         }
797cdf0e10cSrcweir         else
798cdf0e10cSrcweir         {
799cdf0e10cSrcweir             for (size_t  i =0; i < rOriginal.size( );  i ++)
800cdf0e10cSrcweir             {
801cdf0e10cSrcweir                 const  ScDPItemData* pItemData = rCacheTable.GetCache()->GetItemDataById( (SCCOL)GetSourceDim(), rOriginal[i] );
802cdf0e10cSrcweir                 if ( !pItemData || !GetGroupForData( *pItemData ) )
803cdf0e10cSrcweir                 {
804cdf0e10cSrcweir                     // not in any group -> add as its own group
805cdf0e10cSrcweir                     maMemberEntries.push_back( rOriginal[i] );
806cdf0e10cSrcweir                 }
807cdf0e10cSrcweir             }
808cdf0e10cSrcweir 
809cdf0e10cSrcweir             long nCount = aItems.size();
810cdf0e10cSrcweir             for (long i=0; i<nCount; i++)
811cdf0e10cSrcweir             {
812cdf0e10cSrcweir                 SCROW nNew = rCacheTable.GetCache()->GetAdditionalItemID(  aItems[i].GetName() );
813cdf0e10cSrcweir                 lcl_Insert ( (SCCOL)GetSourceDim(), rCacheTable.GetCache(), maMemberEntries, nNew  );
814cdf0e10cSrcweir             }
815cdf0e10cSrcweir         }
816cdf0e10cSrcweir     }
817cdf0e10cSrcweir     return maMemberEntries;
818cdf0e10cSrcweir }
819cdf0e10cSrcweir 
820cdf0e10cSrcweir // End Comments
821cdf0e10cSrcweir 
822cdf0e10cSrcweir 
GetGroupForData(const ScDPItemData & rData) const823cdf0e10cSrcweir const ScDPGroupItem* ScDPGroupDimension::GetGroupForData( const ScDPItemData& rData ) const
824cdf0e10cSrcweir {
825cdf0e10cSrcweir     for ( ScDPGroupItemVec::const_iterator aIter(aItems.begin()); aIter != aItems.end(); aIter++ )
826cdf0e10cSrcweir         if ( aIter->HasElement( rData ) )
827cdf0e10cSrcweir             return &*aIter;
828cdf0e10cSrcweir 
829cdf0e10cSrcweir     return NULL;
830cdf0e10cSrcweir }
831cdf0e10cSrcweir 
GetGroupForName(const ScDPItemData & rName) const832cdf0e10cSrcweir const ScDPGroupItem* ScDPGroupDimension::GetGroupForName( const ScDPItemData& rName ) const
833cdf0e10cSrcweir {
834cdf0e10cSrcweir     for ( ScDPGroupItemVec::const_iterator aIter(aItems.begin()); aIter != aItems.end(); aIter++ )
835cdf0e10cSrcweir         if ( aIter->GetName().IsCaseInsEqual( rName ) )
836cdf0e10cSrcweir             return &*aIter;
837cdf0e10cSrcweir 
838cdf0e10cSrcweir     return NULL;
839cdf0e10cSrcweir }
840cdf0e10cSrcweir 
GetGroupByIndex(size_t nIndex) const841cdf0e10cSrcweir const ScDPGroupItem* ScDPGroupDimension::GetGroupByIndex( size_t nIndex ) const
842cdf0e10cSrcweir {
843cdf0e10cSrcweir     if (nIndex >= aItems.size())
844cdf0e10cSrcweir         return NULL;
845cdf0e10cSrcweir 
846cdf0e10cSrcweir     return &aItems[nIndex];
847cdf0e10cSrcweir }
848cdf0e10cSrcweir 
DisposeData()849cdf0e10cSrcweir void ScDPGroupDimension::DisposeData()
850cdf0e10cSrcweir {
851cdf0e10cSrcweir     maMemberEntries.clear();
852cdf0e10cSrcweir }
853cdf0e10cSrcweir 
854cdf0e10cSrcweir // -----------------------------------------------------------------------
855cdf0e10cSrcweir 
ScDPNumGroupDimension()856cdf0e10cSrcweir ScDPNumGroupDimension::ScDPNumGroupDimension() :
857cdf0e10cSrcweir     pDateHelper( NULL ),
858cdf0e10cSrcweir     bHasNonInteger( false ),
859cdf0e10cSrcweir     cDecSeparator( 0 )
860cdf0e10cSrcweir {
861cdf0e10cSrcweir }
862cdf0e10cSrcweir 
ScDPNumGroupDimension(const ScDPNumGroupInfo & rInfo)863cdf0e10cSrcweir ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupInfo& rInfo ) :
864cdf0e10cSrcweir     aGroupInfo( rInfo ),
865cdf0e10cSrcweir     pDateHelper( NULL ),
866cdf0e10cSrcweir     bHasNonInteger( false ),
867cdf0e10cSrcweir     cDecSeparator( 0 )
868cdf0e10cSrcweir {
869cdf0e10cSrcweir }
870cdf0e10cSrcweir 
ScDPNumGroupDimension(const ScDPNumGroupDimension & rOther)871cdf0e10cSrcweir ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupDimension& rOther ) :
872cdf0e10cSrcweir     aGroupInfo( rOther.aGroupInfo ),
873cdf0e10cSrcweir     pDateHelper( NULL ),
874cdf0e10cSrcweir     bHasNonInteger( false ),
875cdf0e10cSrcweir     cDecSeparator( 0 )
876cdf0e10cSrcweir {
877cdf0e10cSrcweir     if ( rOther.pDateHelper )
878cdf0e10cSrcweir         pDateHelper = new ScDPDateGroupHelper( *rOther.pDateHelper );
879cdf0e10cSrcweir }
880cdf0e10cSrcweir 
operator =(const ScDPNumGroupDimension & rOther)881cdf0e10cSrcweir ScDPNumGroupDimension& ScDPNumGroupDimension::operator=( const ScDPNumGroupDimension& rOther )
882cdf0e10cSrcweir {
883cdf0e10cSrcweir     aGroupInfo = rOther.aGroupInfo;
884cdf0e10cSrcweir 
885cdf0e10cSrcweir     delete pDateHelper;
886cdf0e10cSrcweir     if ( rOther.pDateHelper )
887cdf0e10cSrcweir         pDateHelper = new ScDPDateGroupHelper( *rOther.pDateHelper );
888cdf0e10cSrcweir     else
889cdf0e10cSrcweir         pDateHelper = NULL;
890cdf0e10cSrcweir 
891cdf0e10cSrcweir     bHasNonInteger = false;
892cdf0e10cSrcweir     return *this;
893cdf0e10cSrcweir }
894cdf0e10cSrcweir 
DisposeData()895cdf0e10cSrcweir void ScDPNumGroupDimension::DisposeData()
896cdf0e10cSrcweir {
897cdf0e10cSrcweir     bHasNonInteger = false;
898cdf0e10cSrcweir     maMemberEntries.clear();
899cdf0e10cSrcweir }
900cdf0e10cSrcweir 
~ScDPNumGroupDimension()901cdf0e10cSrcweir ScDPNumGroupDimension::~ScDPNumGroupDimension()
902cdf0e10cSrcweir {
903cdf0e10cSrcweir     delete pDateHelper;
904cdf0e10cSrcweir }
905cdf0e10cSrcweir 
MakeDateHelper(const ScDPNumGroupInfo & rInfo,sal_Int32 nPart)906cdf0e10cSrcweir void ScDPNumGroupDimension::MakeDateHelper( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
907cdf0e10cSrcweir {
908cdf0e10cSrcweir     delete pDateHelper;
909cdf0e10cSrcweir     pDateHelper = new ScDPDateGroupHelper( rInfo, nPart );
910cdf0e10cSrcweir 
911cdf0e10cSrcweir     aGroupInfo.Enable = sal_True;   //! or query both?
912cdf0e10cSrcweir }
913cdf0e10cSrcweir 
GetNumEntries(SCCOL nSourceDim,ScDPTableDataCache * pCache,const std::vector<SCROW> & rOriginal) const914cdf0e10cSrcweir const std::vector< SCROW >& ScDPNumGroupDimension::GetNumEntries( SCCOL nSourceDim, ScDPTableDataCache* pCache,
915cdf0e10cSrcweir                     const std::vector< SCROW >& rOriginal  ) const
916cdf0e10cSrcweir {
917cdf0e10cSrcweir     if ( maMemberEntries.empty() )
918cdf0e10cSrcweir     {
919cdf0e10cSrcweir         SvNumberFormatter* pFormatter = pCache->GetDoc()->GetFormatTable();
920cdf0e10cSrcweir 
921cdf0e10cSrcweir         if ( pDateHelper )
922cdf0e10cSrcweir             pDateHelper->FillColumnEntries( nSourceDim, pCache, maMemberEntries,rOriginal );
923cdf0e10cSrcweir         else
924cdf0e10cSrcweir         {
925cdf0e10cSrcweir             // Copy textual entries.
926cdf0e10cSrcweir             // Also look through the source entries for non-integer numbers, minimum and maximum.
927cdf0e10cSrcweir             // GetNumEntries (GetColumnEntries) must be called before accessing the groups
928cdf0e10cSrcweir             // (this in ensured by calling ScDPLevel::GetMembersObject for all column/row/page
929cdf0e10cSrcweir             // dimensions before iterating over the values).
930cdf0e10cSrcweir 
931cdf0e10cSrcweir             cDecSeparator = ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0);
932cdf0e10cSrcweir 
933cdf0e10cSrcweir             // non-integer GroupInfo values count, too
934cdf0e10cSrcweir             bHasNonInteger = ( !aGroupInfo.AutoStart && !IsInteger( aGroupInfo.Start ) ) ||
935cdf0e10cSrcweir                              ( !aGroupInfo.AutoEnd   && !IsInteger( aGroupInfo.End   ) ) ||
936cdf0e10cSrcweir                              !IsInteger( aGroupInfo.Step );
937cdf0e10cSrcweir             double fSourceMin = 0.0;
938cdf0e10cSrcweir             double fSourceMax = 0.0;
939cdf0e10cSrcweir             bool bFirst = true;
940cdf0e10cSrcweir 
941cdf0e10cSrcweir             size_t  nOriginalCount = rOriginal.size();
942cdf0e10cSrcweir             for (size_t  nOriginalPos=0; nOriginalPos<nOriginalCount; nOriginalPos++)
943cdf0e10cSrcweir             {
944cdf0e10cSrcweir                const  ScDPItemData* pItemData = pCache->GetItemDataById( nSourceDim , rOriginal[nOriginalPos] );
945cdf0e10cSrcweir 
946cdf0e10cSrcweir                if ( pItemData && pItemData ->HasStringData() )
947cdf0e10cSrcweir                {
948cdf0e10cSrcweir                    lcl_Insert( nSourceDim, pCache, maMemberEntries,  rOriginal[nOriginalPos] );
949cdf0e10cSrcweir                }
950cdf0e10cSrcweir                else
951cdf0e10cSrcweir                {
952cdf0e10cSrcweir                    double fSourceValue = pItemData->GetValue();
953cdf0e10cSrcweir                    if ( bFirst )
954cdf0e10cSrcweir                    {
955cdf0e10cSrcweir                        fSourceMin = fSourceMax = fSourceValue;
956cdf0e10cSrcweir                        bFirst = false;
957cdf0e10cSrcweir                    }
958cdf0e10cSrcweir                    else
959cdf0e10cSrcweir                    {
960cdf0e10cSrcweir                        if ( fSourceValue < fSourceMin )
961cdf0e10cSrcweir                            fSourceMin = fSourceValue;
962cdf0e10cSrcweir                        if ( fSourceValue > fSourceMax )
963cdf0e10cSrcweir                            fSourceMax = fSourceValue;
964cdf0e10cSrcweir                    }
965cdf0e10cSrcweir                    if ( !bHasNonInteger && !IsInteger( fSourceValue ) )
966cdf0e10cSrcweir                    {
967cdf0e10cSrcweir                        // if any non-integer numbers are involved, the group labels are
968cdf0e10cSrcweir                        // shown including their upper limit
969cdf0e10cSrcweir                        bHasNonInteger = true;
970cdf0e10cSrcweir                    }
971cdf0e10cSrcweir                }
972cdf0e10cSrcweir             }
973cdf0e10cSrcweir 
974cdf0e10cSrcweir             if ( aGroupInfo.DateValues )
975cdf0e10cSrcweir             {
976cdf0e10cSrcweir                 // special handling for dates: always integer, round down limits
977cdf0e10cSrcweir                 bHasNonInteger = false;
978cdf0e10cSrcweir                 fSourceMin = rtl::math::approxFloor( fSourceMin );
979cdf0e10cSrcweir                 fSourceMax = rtl::math::approxFloor( fSourceMax ) + 1;
980cdf0e10cSrcweir             }
981cdf0e10cSrcweir 
982cdf0e10cSrcweir             if ( aGroupInfo.AutoStart )
983cdf0e10cSrcweir                 const_cast<ScDPNumGroupDimension*>(this)->aGroupInfo.Start = fSourceMin;
984cdf0e10cSrcweir             if ( aGroupInfo.AutoEnd )
985cdf0e10cSrcweir                 const_cast<ScDPNumGroupDimension*>(this)->aGroupInfo.End = fSourceMax;
986cdf0e10cSrcweir 
987cdf0e10cSrcweir             //! limit number of entries?
988cdf0e10cSrcweir 
989cdf0e10cSrcweir             long nLoopCount = 0;
990cdf0e10cSrcweir             double fLoop = aGroupInfo.Start;
991cdf0e10cSrcweir 
992cdf0e10cSrcweir             // Use "less than" instead of "less or equal" for the loop - don't create a group
993cdf0e10cSrcweir             // that consists only of the end value. Instead, the end value is then included
994cdf0e10cSrcweir             // in the last group (last group is bigger than the others).
995cdf0e10cSrcweir             // The first group has to be created nonetheless. GetNumGroupForValue has corresponding logic.
996cdf0e10cSrcweir 
997cdf0e10cSrcweir             bool bFirstGroup = true;
998cdf0e10cSrcweir             while ( bFirstGroup || ( fLoop < aGroupInfo.End && !rtl::math::approxEqual( fLoop, aGroupInfo.End ) ) )
999cdf0e10cSrcweir             {
1000cdf0e10cSrcweir                 String aName = lcl_GetNumGroupName( fLoop, aGroupInfo, bHasNonInteger, cDecSeparator, pFormatter );
1001cdf0e10cSrcweir                 // create a numerical entry to ensure proper sorting
1002cdf0e10cSrcweir                 // (in FillMemberResults this needs special handling)
1003cdf0e10cSrcweir 		        lcl_InsertValue<true>( nSourceDim,  pCache,  maMemberEntries, aName, fLoop );
1004cdf0e10cSrcweir                 ++nLoopCount;
1005cdf0e10cSrcweir                 fLoop = aGroupInfo.Start + nLoopCount * aGroupInfo.Step;
1006cdf0e10cSrcweir                 bFirstGroup = false;
1007cdf0e10cSrcweir 
1008cdf0e10cSrcweir                 // ScDPItemData values are compared with approxEqual
1009cdf0e10cSrcweir             }
1010cdf0e10cSrcweir 
1011cdf0e10cSrcweir             String aFirstName = lcl_GetSpecialNumGroupName( aGroupInfo.Start, true, cDecSeparator, aGroupInfo.DateValues, pFormatter );
1012cdf0e10cSrcweir             lcl_InsertValue<true>( nSourceDim,  pCache,  maMemberEntries, aFirstName,  aGroupInfo.Start - aGroupInfo.Step );
1013cdf0e10cSrcweir 
1014cdf0e10cSrcweir             String aLastName = lcl_GetSpecialNumGroupName( aGroupInfo.End, false, cDecSeparator, aGroupInfo.DateValues, pFormatter );
1015cdf0e10cSrcweir             lcl_InsertValue<true>( nSourceDim,  pCache,  maMemberEntries, aLastName,  aGroupInfo.End + aGroupInfo.Step );
1016cdf0e10cSrcweir         }
1017cdf0e10cSrcweir     }
1018cdf0e10cSrcweir     return maMemberEntries;
1019cdf0e10cSrcweir }
1020cdf0e10cSrcweir 
ScDPGroupTableData(const shared_ptr<ScDPTableData> & pSource,ScDocument * pDocument)1021cdf0e10cSrcweir ScDPGroupTableData::ScDPGroupTableData( const shared_ptr<ScDPTableData>& pSource, ScDocument* pDocument ) :
1022cdf0e10cSrcweir     ScDPTableData(pDocument, pSource->GetCacheId() ),
1023cdf0e10cSrcweir     pSourceData( pSource ),
1024cdf0e10cSrcweir     pDoc( pDocument )
1025cdf0e10cSrcweir {
1026cdf0e10cSrcweir     DBG_ASSERT( pSource, "ScDPGroupTableData: pSource can't be NULL" );
1027cdf0e10cSrcweir 
1028cdf0e10cSrcweir     CreateCacheTable();
1029cdf0e10cSrcweir     nSourceCount = pSource->GetColumnCount();               // real columns, excluding data layout
1030cdf0e10cSrcweir     pNumGroups = new ScDPNumGroupDimension[nSourceCount];
1031cdf0e10cSrcweir }
1032cdf0e10cSrcweir 
~ScDPGroupTableData()1033cdf0e10cSrcweir ScDPGroupTableData::~ScDPGroupTableData()
1034cdf0e10cSrcweir {
1035cdf0e10cSrcweir     delete[] pNumGroups;
1036cdf0e10cSrcweir }
1037cdf0e10cSrcweir 
AddGroupDimension(const ScDPGroupDimension & rGroup)1038cdf0e10cSrcweir void ScDPGroupTableData::AddGroupDimension( const ScDPGroupDimension& rGroup )
1039cdf0e10cSrcweir {
1040cdf0e10cSrcweir     ScDPGroupDimension aNewGroup( rGroup );
1041cdf0e10cSrcweir     aNewGroup.SetGroupDim( GetColumnCount() );      // new dimension will be at the end
1042cdf0e10cSrcweir     aGroups.push_back( aNewGroup );
1043cdf0e10cSrcweir     aGroupNames.insert( OUString(aNewGroup.GetName()) );
1044cdf0e10cSrcweir }
1045cdf0e10cSrcweir 
SetNumGroupDimension(long nIndex,const ScDPNumGroupDimension & rGroup)1046cdf0e10cSrcweir void ScDPGroupTableData::SetNumGroupDimension( long nIndex, const ScDPNumGroupDimension& rGroup )
1047cdf0e10cSrcweir {
1048cdf0e10cSrcweir     if ( nIndex < nSourceCount )
1049cdf0e10cSrcweir     {
1050cdf0e10cSrcweir         pNumGroups[nIndex] = rGroup;
1051cdf0e10cSrcweir 
1052cdf0e10cSrcweir         // automatic minimum / maximum is handled in GetNumEntries
1053cdf0e10cSrcweir     }
1054cdf0e10cSrcweir }
1055cdf0e10cSrcweir 
GetDimensionIndex(const String & rName)1056cdf0e10cSrcweir long ScDPGroupTableData::GetDimensionIndex( const String& rName )
1057cdf0e10cSrcweir {
1058cdf0e10cSrcweir     for (long i=0; i<nSourceCount; i++)                         // nSourceCount excludes data layout
1059cdf0e10cSrcweir         if ( pSourceData->getDimensionName(i) == rName )        //! ignore case?
1060cdf0e10cSrcweir             return i;
1061cdf0e10cSrcweir     return -1;  // none
1062cdf0e10cSrcweir }
1063cdf0e10cSrcweir 
GetColumnCount()1064cdf0e10cSrcweir long ScDPGroupTableData::GetColumnCount()
1065cdf0e10cSrcweir {
1066cdf0e10cSrcweir     return nSourceCount + aGroups.size();
1067cdf0e10cSrcweir }
1068cdf0e10cSrcweir 
IsNumGroupDimension(long nDimension) const1069cdf0e10cSrcweir bool ScDPGroupTableData::IsNumGroupDimension( long nDimension ) const
1070cdf0e10cSrcweir {
1071cdf0e10cSrcweir     return ( nDimension < nSourceCount && pNumGroups[nDimension].GetInfo().Enable );
1072cdf0e10cSrcweir }
1073cdf0e10cSrcweir 
GetNumGroupInfo(long nDimension,ScDPNumGroupInfo & rInfo,bool & rNonInteger,sal_Unicode & rDecimal)1074cdf0e10cSrcweir void ScDPGroupTableData::GetNumGroupInfo( long nDimension, ScDPNumGroupInfo& rInfo,
1075cdf0e10cSrcweir                                         bool& rNonInteger, sal_Unicode& rDecimal )
1076cdf0e10cSrcweir {
1077cdf0e10cSrcweir     if ( nDimension < nSourceCount )
1078cdf0e10cSrcweir     {
1079cdf0e10cSrcweir         rInfo       = pNumGroups[nDimension].GetInfo();
1080cdf0e10cSrcweir         rNonInteger = pNumGroups[nDimension].HasNonInteger();
1081cdf0e10cSrcweir         rDecimal    = pNumGroups[nDimension].GetDecSeparator();
1082cdf0e10cSrcweir     }
1083cdf0e10cSrcweir }
1084cdf0e10cSrcweir // Wang Xu Ming - DataPilot migration
GetMembersCount(long nDim)1085cdf0e10cSrcweir long  ScDPGroupTableData::GetMembersCount( long nDim )
1086cdf0e10cSrcweir {
1087cdf0e10cSrcweir     const std::vector< SCROW >&  members = GetColumnEntries( nDim );
1088cdf0e10cSrcweir     return members.size();
1089cdf0e10cSrcweir }
GetColumnEntries(long nColumn)1090cdf0e10cSrcweir const std::vector< SCROW >& ScDPGroupTableData::GetColumnEntries( long  nColumn )
1091cdf0e10cSrcweir {
1092cdf0e10cSrcweir     if ( nColumn >= nSourceCount )
1093cdf0e10cSrcweir     {
1094cdf0e10cSrcweir         if ( getIsDataLayoutDimension( nColumn) )     // data layout dimension?
1095cdf0e10cSrcweir             nColumn = nSourceCount;                         // index of data layout in source data
1096cdf0e10cSrcweir         else
1097cdf0e10cSrcweir         {
1098cdf0e10cSrcweir             const ScDPGroupDimension& rGroupDim = aGroups[nColumn - nSourceCount];
1099cdf0e10cSrcweir             long nSourceDim = rGroupDim.GetSourceDim();
1100cdf0e10cSrcweir             // collection is cached at pSourceData, GetColumnEntries can be called every time
1101cdf0e10cSrcweir             const  std::vector< SCROW >& rOriginal = pSourceData->GetColumnEntries( nSourceDim );
1102cdf0e10cSrcweir             return rGroupDim.GetColumnEntries( GetCacheTable(), rOriginal );
1103cdf0e10cSrcweir         }
1104cdf0e10cSrcweir     }
1105cdf0e10cSrcweir 
1106cdf0e10cSrcweir     if ( IsNumGroupDimension( nColumn ) )
1107cdf0e10cSrcweir     {
1108cdf0e10cSrcweir         // dimension number is unchanged for numerical groups
1109cdf0e10cSrcweir         const  std::vector< SCROW >& rOriginal = pSourceData->GetColumnEntries( nColumn );
1110cdf0e10cSrcweir         return pNumGroups[nColumn].GetNumEntries( (SCCOL)nColumn,  GetCacheTable().GetCache(), rOriginal );
1111cdf0e10cSrcweir     }
1112cdf0e10cSrcweir 
1113cdf0e10cSrcweir     return pSourceData->GetColumnEntries( nColumn );
1114cdf0e10cSrcweir }
1115cdf0e10cSrcweir 
GetMemberById(long nDim,long nId)1116cdf0e10cSrcweir const ScDPItemData* ScDPGroupTableData::GetMemberById( long nDim, long nId )
1117cdf0e10cSrcweir {
1118cdf0e10cSrcweir     if ( nDim >= nSourceCount )
1119cdf0e10cSrcweir     {
1120cdf0e10cSrcweir 	    if ( getIsDataLayoutDimension( nDim) )
1121cdf0e10cSrcweir 		    nDim 	= nSourceCount;
1122cdf0e10cSrcweir 	    else
1123cdf0e10cSrcweir 	    {
1124cdf0e10cSrcweir 		    const ScDPGroupDimension& rGroupDim = aGroups[nDim - nSourceCount];
1125cdf0e10cSrcweir 		    nDim = rGroupDim.GetSourceDim();
1126cdf0e10cSrcweir 	    }
1127cdf0e10cSrcweir     }
1128cdf0e10cSrcweir     return pSourceData->GetMemberById( nDim, nId );
1129cdf0e10cSrcweir }
1130cdf0e10cSrcweir 
getDimensionName(long nColumn)1131cdf0e10cSrcweir String ScDPGroupTableData::getDimensionName(long nColumn)
1132cdf0e10cSrcweir {
1133cdf0e10cSrcweir     if ( nColumn >= nSourceCount )
1134cdf0e10cSrcweir     {
1135cdf0e10cSrcweir         if ( nColumn == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) )     // data layout dimension?
1136cdf0e10cSrcweir             nColumn = nSourceCount;                         // index of data layout in source data
1137cdf0e10cSrcweir         else
1138cdf0e10cSrcweir             return aGroups[nColumn - nSourceCount].GetName();
1139cdf0e10cSrcweir     }
1140cdf0e10cSrcweir 
1141cdf0e10cSrcweir     return pSourceData->getDimensionName( nColumn );
1142cdf0e10cSrcweir }
1143cdf0e10cSrcweir 
getIsDataLayoutDimension(long nColumn)1144cdf0e10cSrcweir sal_Bool ScDPGroupTableData::getIsDataLayoutDimension(long nColumn)
1145cdf0e10cSrcweir {
1146cdf0e10cSrcweir     // position of data layout dimension is moved from source data
1147cdf0e10cSrcweir     return ( nColumn == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) );    // data layout dimension?
1148cdf0e10cSrcweir }
1149cdf0e10cSrcweir 
IsDateDimension(long nDim)1150cdf0e10cSrcweir sal_Bool ScDPGroupTableData::IsDateDimension(long nDim)
1151cdf0e10cSrcweir {
1152cdf0e10cSrcweir     if ( nDim >= nSourceCount )
1153cdf0e10cSrcweir     {
1154cdf0e10cSrcweir         if ( nDim == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) )        // data layout dimension?
1155cdf0e10cSrcweir             nDim = nSourceCount;                            // index of data layout in source data
1156cdf0e10cSrcweir         else
1157cdf0e10cSrcweir             nDim = aGroups[nDim - nSourceCount].GetSourceDim();  // look at original dimension
1158cdf0e10cSrcweir     }
1159cdf0e10cSrcweir 
1160cdf0e10cSrcweir     return pSourceData->IsDateDimension( nDim );
1161cdf0e10cSrcweir }
1162cdf0e10cSrcweir 
GetNumberFormat(long nDim)1163cdf0e10cSrcweir sal_uLong ScDPGroupTableData::GetNumberFormat(long nDim)
1164cdf0e10cSrcweir {
1165cdf0e10cSrcweir     if ( nDim >= nSourceCount )
1166cdf0e10cSrcweir     {
1167cdf0e10cSrcweir         if ( nDim == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) )        // data layout dimension?
1168cdf0e10cSrcweir             nDim = nSourceCount;                            // index of data layout in source data
1169cdf0e10cSrcweir         else
1170cdf0e10cSrcweir             nDim = aGroups[nDim - nSourceCount].GetSourceDim();  // look at original dimension
1171cdf0e10cSrcweir     }
1172cdf0e10cSrcweir 
1173cdf0e10cSrcweir     return pSourceData->GetNumberFormat( nDim );
1174cdf0e10cSrcweir }
1175cdf0e10cSrcweir 
DisposeData()1176cdf0e10cSrcweir void ScDPGroupTableData::DisposeData()
1177cdf0e10cSrcweir {
1178cdf0e10cSrcweir     for ( ScDPGroupDimensionVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
1179cdf0e10cSrcweir         aIter->DisposeData();
1180cdf0e10cSrcweir 
1181cdf0e10cSrcweir     for ( long i=0; i<nSourceCount; i++ )
1182cdf0e10cSrcweir         pNumGroups[i].DisposeData();
1183cdf0e10cSrcweir 
1184cdf0e10cSrcweir     pSourceData->DisposeData();
1185cdf0e10cSrcweir }
1186cdf0e10cSrcweir 
SetEmptyFlags(sal_Bool bIgnoreEmptyRows,sal_Bool bRepeatIfEmpty)1187cdf0e10cSrcweir void ScDPGroupTableData::SetEmptyFlags( sal_Bool bIgnoreEmptyRows, sal_Bool bRepeatIfEmpty )
1188cdf0e10cSrcweir {
1189cdf0e10cSrcweir     pSourceData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
1190cdf0e10cSrcweir }
1191cdf0e10cSrcweir 
IsRepeatIfEmpty()1192cdf0e10cSrcweir bool ScDPGroupTableData::IsRepeatIfEmpty()
1193cdf0e10cSrcweir {
1194cdf0e10cSrcweir     return pSourceData->IsRepeatIfEmpty();
1195cdf0e10cSrcweir }
1196cdf0e10cSrcweir 
CreateCacheTable()1197cdf0e10cSrcweir void ScDPGroupTableData::CreateCacheTable()
1198cdf0e10cSrcweir {
1199cdf0e10cSrcweir     pSourceData->CreateCacheTable();
1200cdf0e10cSrcweir }
1201cdf0e10cSrcweir 
ModifyFilterCriteria(vector<ScDPCacheTable::Criterion> & rCriteria)1202cdf0e10cSrcweir void ScDPGroupTableData::ModifyFilterCriteria(vector<ScDPCacheTable::Criterion>& rCriteria)
1203cdf0e10cSrcweir {
1204cdf0e10cSrcweir     typedef hash_map<long, const ScDPGroupDimension*> GroupFieldMapType;
1205cdf0e10cSrcweir     GroupFieldMapType aGroupFieldIds;
1206cdf0e10cSrcweir     {
1207cdf0e10cSrcweir         ScDPGroupDimensionVec::const_iterator itr = aGroups.begin(), itrEnd = aGroups.end();
1208cdf0e10cSrcweir         for (; itr != itrEnd; ++itr)
1209cdf0e10cSrcweir             aGroupFieldIds.insert( hash_map<long, const ScDPGroupDimension*>::value_type(itr->GetGroupDim(), &(*itr)) );
1210cdf0e10cSrcweir     }
1211cdf0e10cSrcweir 
1212cdf0e10cSrcweir     vector<ScDPCacheTable::Criterion> aNewCriteria;
1213cdf0e10cSrcweir     aNewCriteria.reserve(rCriteria.size() + aGroups.size());
1214cdf0e10cSrcweir 
1215cdf0e10cSrcweir     // Go through all the filtered field names and process them appropriately.
1216cdf0e10cSrcweir 
1217cdf0e10cSrcweir     vector<ScDPCacheTable::Criterion>::const_iterator itrEnd = rCriteria.end();
1218cdf0e10cSrcweir     GroupFieldMapType::const_iterator itrGrpEnd = aGroupFieldIds.end();
1219cdf0e10cSrcweir     for (vector<ScDPCacheTable::Criterion>::const_iterator itr = rCriteria.begin(); itr != itrEnd; ++itr)
1220cdf0e10cSrcweir     {
1221cdf0e10cSrcweir         ScDPCacheTable::SingleFilter* pFilter = dynamic_cast<ScDPCacheTable::SingleFilter*>(itr->mpFilter.get());
1222cdf0e10cSrcweir         if (!pFilter)
1223cdf0e10cSrcweir             // We expect this to be a single filter.
1224cdf0e10cSrcweir             continue;
1225cdf0e10cSrcweir 
1226cdf0e10cSrcweir         GroupFieldMapType::const_iterator itrGrp = aGroupFieldIds.find(itr->mnFieldIndex);
1227cdf0e10cSrcweir         if (itrGrp == itrGrpEnd)
1228cdf0e10cSrcweir         {
1229cdf0e10cSrcweir             if (IsNumGroupDimension(itr->mnFieldIndex))
1230cdf0e10cSrcweir             {
1231cdf0e10cSrcweir                 // internal number group field
1232cdf0e10cSrcweir                 const ScDPNumGroupDimension& rNumGrpDim = pNumGroups[itr->mnFieldIndex];
1233cdf0e10cSrcweir                 const ScDPDateGroupHelper* pDateHelper = rNumGrpDim.GetDateHelper();
1234cdf0e10cSrcweir                 if (!pDateHelper)
1235cdf0e10cSrcweir                 {
1236cdf0e10cSrcweir                     // What do we do here !?
1237cdf0e10cSrcweir                     continue;
1238cdf0e10cSrcweir                 }
1239cdf0e10cSrcweir 
1240cdf0e10cSrcweir                 ScDPCacheTable::Criterion aCri;
1241cdf0e10cSrcweir                 aCri.mnFieldIndex = itr->mnFieldIndex;
1242cdf0e10cSrcweir                 aCri.mpFilter.reset(new ScDPGroupDateFilter(
1243cdf0e10cSrcweir                     pFilter->getMatchValue(), pDateHelper->GetDatePart(),
1244cdf0e10cSrcweir                     pDoc->GetFormatTable()->GetNullDate(), &pDateHelper->GetNumInfo()));
1245cdf0e10cSrcweir 
1246cdf0e10cSrcweir                 aNewCriteria.push_back(aCri);
1247cdf0e10cSrcweir             }
1248cdf0e10cSrcweir             else
1249cdf0e10cSrcweir             {
1250cdf0e10cSrcweir                 // This is a regular source field.
1251cdf0e10cSrcweir                 aNewCriteria.push_back(*itr);
1252cdf0e10cSrcweir             }
1253cdf0e10cSrcweir         }
1254cdf0e10cSrcweir         else
1255cdf0e10cSrcweir         {
1256cdf0e10cSrcweir             // This is an ordinary group field or external number group field.
1257cdf0e10cSrcweir 
1258cdf0e10cSrcweir             const ScDPGroupDimension* pGrpDim = itrGrp->second;
1259cdf0e10cSrcweir             long nSrcDim = pGrpDim->GetSourceDim();
1260cdf0e10cSrcweir             const ScDPDateGroupHelper* pDateHelper = pGrpDim->GetDateHelper();
1261cdf0e10cSrcweir 
1262cdf0e10cSrcweir             if (pDateHelper)
1263cdf0e10cSrcweir             {
1264cdf0e10cSrcweir                 // external number group
1265cdf0e10cSrcweir                 ScDPCacheTable::Criterion aCri;
1266cdf0e10cSrcweir                 aCri.mnFieldIndex = nSrcDim;  // use the source dimension, not the group dimension.
1267cdf0e10cSrcweir                 aCri.mpFilter.reset(new ScDPGroupDateFilter(
1268cdf0e10cSrcweir                     pFilter->getMatchValue(), pDateHelper->GetDatePart(),
1269cdf0e10cSrcweir                     pDoc->GetFormatTable()->GetNullDate(), &pDateHelper->GetNumInfo()));
1270cdf0e10cSrcweir 
1271cdf0e10cSrcweir                 aNewCriteria.push_back(aCri);
1272cdf0e10cSrcweir             }
1273cdf0e10cSrcweir             else
1274cdf0e10cSrcweir             {
1275cdf0e10cSrcweir                 // normal group
1276cdf0e10cSrcweir 
1277cdf0e10cSrcweir                 // Note that each group dimension may have multiple group names!
1278cdf0e10cSrcweir                 size_t nGroupItemCount = pGrpDim->GetItemCount();
1279cdf0e10cSrcweir                 for (size_t i = 0; i < nGroupItemCount; ++i)
1280cdf0e10cSrcweir                 {
1281cdf0e10cSrcweir                     const ScDPGroupItem* pGrpItem = pGrpDim->GetGroupByIndex(i);
1282cdf0e10cSrcweir 					// Wang Xu Ming -- 2009-6-9
1283cdf0e10cSrcweir 					// DataPilot Migration
1284cdf0e10cSrcweir 					ScDPItemData aName( pFilter->getMatchString(),pFilter->getMatchValue(),pFilter->hasValue()) ;
1285cdf0e10cSrcweir 					/*aName.aString   = pFilter->getMatchString();
1286cdf0e10cSrcweir 					aName.fValue    = pFilter->getMatchValue();
1287cdf0e10cSrcweir 					aName.bHasValue = pFilter->hasValue();*/
1288cdf0e10cSrcweir 					// End Comments
1289cdf0e10cSrcweir 									   if (!pGrpItem || !pGrpItem->GetName().IsCaseInsEqual(aName))
1290cdf0e10cSrcweir                         continue;
1291cdf0e10cSrcweir 
1292cdf0e10cSrcweir                     ScDPCacheTable::Criterion aCri;
1293cdf0e10cSrcweir                     aCri.mnFieldIndex = nSrcDim;
1294cdf0e10cSrcweir                     aCri.mpFilter.reset(new ScDPCacheTable::GroupFilter());
1295cdf0e10cSrcweir                     ScDPCacheTable::GroupFilter* pGrpFilter =
1296cdf0e10cSrcweir                         static_cast<ScDPCacheTable::GroupFilter*>(aCri.mpFilter.get());
1297cdf0e10cSrcweir 
1298cdf0e10cSrcweir                     pGrpItem->FillGroupFilter(*pGrpFilter);
1299cdf0e10cSrcweir                     aNewCriteria.push_back(aCri);
1300cdf0e10cSrcweir                 }
1301cdf0e10cSrcweir             }
1302cdf0e10cSrcweir         }
1303cdf0e10cSrcweir     }
1304cdf0e10cSrcweir     rCriteria.swap(aNewCriteria);
1305cdf0e10cSrcweir }
1306cdf0e10cSrcweir 
FilterCacheTable(const vector<ScDPCacheTable::Criterion> & rCriteria,const hash_set<sal_Int32> & rCatDims)1307cdf0e10cSrcweir void ScDPGroupTableData::FilterCacheTable(const vector<ScDPCacheTable::Criterion>& rCriteria, const hash_set<sal_Int32>& rCatDims)
1308cdf0e10cSrcweir {
1309cdf0e10cSrcweir     vector<ScDPCacheTable::Criterion> aNewCriteria(rCriteria);
1310cdf0e10cSrcweir     ModifyFilterCriteria(aNewCriteria);
1311cdf0e10cSrcweir     pSourceData->FilterCacheTable(aNewCriteria, rCatDims);
1312cdf0e10cSrcweir }
1313cdf0e10cSrcweir 
GetDrillDownData(const vector<ScDPCacheTable::Criterion> & rCriteria,const hash_set<sal_Int32> & rCatDims,Sequence<Sequence<Any>> & rData)1314cdf0e10cSrcweir void ScDPGroupTableData::GetDrillDownData(const vector<ScDPCacheTable::Criterion>& rCriteria, const hash_set<sal_Int32>& rCatDims, Sequence< Sequence<Any> >& rData)
1315cdf0e10cSrcweir {
1316cdf0e10cSrcweir     vector<ScDPCacheTable::Criterion> aNewCriteria(rCriteria);
1317cdf0e10cSrcweir     ModifyFilterCriteria(aNewCriteria);
1318cdf0e10cSrcweir     pSourceData->GetDrillDownData(aNewCriteria, rCatDims, rData);
1319cdf0e10cSrcweir }
1320cdf0e10cSrcweir 
CalcResults(CalcInfo & rInfo,bool bAutoShow)1321cdf0e10cSrcweir void ScDPGroupTableData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
1322cdf0e10cSrcweir {
1323cdf0e10cSrcweir     // #i111435# Inside FillRowDataFromCacheTable/GetItemData, virtual methods
1324cdf0e10cSrcweir     // getIsDataLayoutDimension and GetSourceDim are used, so it has to be called
1325cdf0e10cSrcweir     // with original rInfo, containing dimension indexes of the grouped data.
1326cdf0e10cSrcweir 
1327cdf0e10cSrcweir     const ScDPCacheTable& rCacheTable = pSourceData->GetCacheTable();
1328cdf0e10cSrcweir     sal_Int32 nRowSize = rCacheTable.getRowSize();
1329cdf0e10cSrcweir     for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
1330cdf0e10cSrcweir     {
1331cdf0e10cSrcweir         if (!rCacheTable.isRowActive(nRow))
1332cdf0e10cSrcweir             continue;
1333cdf0e10cSrcweir 
1334cdf0e10cSrcweir         CalcRowData aData;
1335cdf0e10cSrcweir         FillRowDataFromCacheTable(nRow, rCacheTable, rInfo, aData);
1336cdf0e10cSrcweir 
1337cdf0e10cSrcweir         if ( !rInfo.aColLevelDims.empty() )
1338cdf0e10cSrcweir             FillGroupValues(&aData.aColData[0], rInfo.aColLevelDims.size(), &rInfo.aColLevelDims[0]);
1339cdf0e10cSrcweir         if ( !rInfo.aRowLevelDims.empty() )
1340cdf0e10cSrcweir             FillGroupValues(&aData.aRowData[0], rInfo.aRowLevelDims.size(), &rInfo.aRowLevelDims[0]);
1341cdf0e10cSrcweir         if ( !rInfo.aPageDims.empty() )
1342cdf0e10cSrcweir             FillGroupValues(&aData.aPageData[0], rInfo.aPageDims.size(), &rInfo.aPageDims[0]);
1343cdf0e10cSrcweir 
1344cdf0e10cSrcweir         ProcessRowData(rInfo, aData, bAutoShow);
1345cdf0e10cSrcweir     }
1346cdf0e10cSrcweir }
1347cdf0e10cSrcweir 
GetCacheTable() const1348cdf0e10cSrcweir const ScDPCacheTable& ScDPGroupTableData::GetCacheTable() const
1349cdf0e10cSrcweir {
1350cdf0e10cSrcweir     return pSourceData->GetCacheTable();
1351cdf0e10cSrcweir }
1352cdf0e10cSrcweir 
FillGroupValues(SCROW * pItemDataIndex,long nCount,const long * pDims)1353cdf0e10cSrcweir void ScDPGroupTableData::FillGroupValues( /*ScDPItemData* pItemData*/ SCROW* pItemDataIndex, long nCount, const long* pDims )
1354cdf0e10cSrcweir {
1355cdf0e10cSrcweir     long nGroupedColumns = aGroups.size();
1356cdf0e10cSrcweir 
1357cdf0e10cSrcweir     ScDPTableDataCache* pCache = GetCacheTable().GetCache();
1358cdf0e10cSrcweir     for (long nDim=0; nDim<nCount; nDim++)
1359cdf0e10cSrcweir     {
1360cdf0e10cSrcweir         const ScDPDateGroupHelper* pDateHelper = NULL;
1361cdf0e10cSrcweir 
1362cdf0e10cSrcweir         long nColumn = pDims[nDim];
1363cdf0e10cSrcweir         long nSourceDim = nColumn;
1364cdf0e10cSrcweir         if ( nColumn >= nSourceCount && nColumn < nSourceCount + nGroupedColumns )
1365cdf0e10cSrcweir         {
1366cdf0e10cSrcweir             const ScDPGroupDimension& rGroupDim = aGroups[nColumn - nSourceCount];
1367cdf0e10cSrcweir             nSourceDim= rGroupDim.GetSourceDim();
1368cdf0e10cSrcweir             pDateHelper = rGroupDim.GetDateHelper();
1369cdf0e10cSrcweir             if ( !pDateHelper )                         // date is handled below
1370cdf0e10cSrcweir             {
1371cdf0e10cSrcweir        		  const ScDPGroupItem* pGroupItem = rGroupDim.GetGroupForData( *GetMemberById( nSourceDim, pItemDataIndex[nDim] ));
1372cdf0e10cSrcweir               if ( pGroupItem )
1373cdf0e10cSrcweir 		        	  pItemDataIndex[nDim] = pCache->GetAdditionalItemID(  pGroupItem->GetName() );
1374cdf0e10cSrcweir             }
1375cdf0e10cSrcweir         }
1376cdf0e10cSrcweir         else if ( IsNumGroupDimension( nColumn ) )
1377cdf0e10cSrcweir         {
1378cdf0e10cSrcweir             pDateHelper = pNumGroups[nColumn].GetDateHelper();
1379cdf0e10cSrcweir             if ( !pDateHelper )                         // date is handled below
1380cdf0e10cSrcweir             {
1381cdf0e10cSrcweir             	 const ScDPItemData* pData = pCache->GetItemDataById( (SCCOL)nSourceDim, pItemDataIndex[nDim]);
1382cdf0e10cSrcweir                 if ( pData ->IsValue() )
1383cdf0e10cSrcweir                 {
1384cdf0e10cSrcweir                     ScDPNumGroupInfo aNumInfo;
1385cdf0e10cSrcweir                     bool bHasNonInteger = false;
1386cdf0e10cSrcweir                     sal_Unicode cDecSeparator = 0;
1387cdf0e10cSrcweir                     GetNumGroupInfo( nColumn, aNumInfo, bHasNonInteger, cDecSeparator );
1388cdf0e10cSrcweir                     double fGroupValue;
1389cdf0e10cSrcweir                     String aGroupName = lcl_GetNumGroupForValue( pData->GetValue(),
1390cdf0e10cSrcweir                              aNumInfo, bHasNonInteger, cDecSeparator, fGroupValue, pDoc );
1391cdf0e10cSrcweir                     ScDPItemData  aItemData ( aGroupName, fGroupValue, sal_True ) ;
1392cdf0e10cSrcweir                     pItemDataIndex[nDim] = pCache->GetAdditionalItemID( aItemData  );
1393cdf0e10cSrcweir                 }
1394cdf0e10cSrcweir                 // else (textual) keep original value
1395cdf0e10cSrcweir             }
1396cdf0e10cSrcweir         }
1397cdf0e10cSrcweir 
1398cdf0e10cSrcweir         if ( pDateHelper )
1399cdf0e10cSrcweir         {
1400cdf0e10cSrcweir             const ScDPItemData* pData  = GetCacheTable().GetCache()->GetItemDataById( (SCCOL)nSourceDim, pItemDataIndex[nDim]);
1401cdf0e10cSrcweir               if ( pData ->IsValue() )
1402cdf0e10cSrcweir             {
1403cdf0e10cSrcweir                 sal_Int32 nPartValue = lcl_GetDatePartValue(
1404cdf0e10cSrcweir                     pData->GetValue(), pDateHelper->GetDatePart(), pDoc->GetFormatTable(),
1405cdf0e10cSrcweir                     &pDateHelper->GetNumInfo() );
1406cdf0e10cSrcweir // Wang Xu Ming -- 2009-9-7
1407cdf0e10cSrcweir // DataPilot Migration - Cache&&Performance
1408cdf0e10cSrcweir 				//String aName = lcl_GetDateGroupName( pDateHelper, nPartValue, pDoc->GetFormatTable() );
1409cdf0e10cSrcweir 				ScDPItemData  aItemData( pDateHelper->GetDatePart(), String(), nPartValue, ScDPItemData::MK_DATA|ScDPItemData::MK_VAL|ScDPItemData::MK_DATEPART );
1410cdf0e10cSrcweir                 pItemDataIndex[nDim] = GetCacheTable().GetCache()->GetAdditionalItemID( aItemData );
1411cdf0e10cSrcweir // End Comments
1412cdf0e10cSrcweir             }
1413cdf0e10cSrcweir         }
1414cdf0e10cSrcweir 	}
1415cdf0e10cSrcweir }
1416cdf0e10cSrcweir 
IsBaseForGroup(long nDim) const1417cdf0e10cSrcweir sal_Bool ScDPGroupTableData::IsBaseForGroup(long nDim) const
1418cdf0e10cSrcweir {
1419cdf0e10cSrcweir     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
1420cdf0e10cSrcweir     {
1421cdf0e10cSrcweir         const ScDPGroupDimension& rDim = *aIter;
1422cdf0e10cSrcweir         if ( rDim.GetSourceDim() == nDim )
1423cdf0e10cSrcweir             return sal_True;
1424cdf0e10cSrcweir     }
1425cdf0e10cSrcweir 
1426cdf0e10cSrcweir     return sal_False;
1427cdf0e10cSrcweir }
1428cdf0e10cSrcweir 
GetGroupBase(long nGroupDim) const1429cdf0e10cSrcweir long ScDPGroupTableData::GetGroupBase(long nGroupDim) const
1430cdf0e10cSrcweir {
1431cdf0e10cSrcweir     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
1432cdf0e10cSrcweir     {
1433cdf0e10cSrcweir         const ScDPGroupDimension& rDim = *aIter;
1434cdf0e10cSrcweir         if ( rDim.GetGroupDim() == nGroupDim )
1435cdf0e10cSrcweir             return rDim.GetSourceDim();
1436cdf0e10cSrcweir     }
1437cdf0e10cSrcweir 
1438cdf0e10cSrcweir     return -1;      // none
1439cdf0e10cSrcweir }
1440cdf0e10cSrcweir 
IsNumOrDateGroup(long nDimension) const1441cdf0e10cSrcweir sal_Bool ScDPGroupTableData::IsNumOrDateGroup(long nDimension) const
1442cdf0e10cSrcweir {
1443cdf0e10cSrcweir     // Virtual method from ScDPTableData, used in result data to force text labels.
1444cdf0e10cSrcweir 
1445cdf0e10cSrcweir     if ( nDimension < nSourceCount )
1446cdf0e10cSrcweir     {
1447cdf0e10cSrcweir         return pNumGroups[nDimension].GetInfo().Enable ||
1448cdf0e10cSrcweir                pNumGroups[nDimension].GetDateHelper();
1449cdf0e10cSrcweir     }
1450cdf0e10cSrcweir 
1451cdf0e10cSrcweir     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
1452cdf0e10cSrcweir     {
1453cdf0e10cSrcweir         const ScDPGroupDimension& rDim = *aIter;
1454cdf0e10cSrcweir         if ( rDim.GetGroupDim() == nDimension )
1455cdf0e10cSrcweir             return ( rDim.GetDateHelper() != NULL );
1456cdf0e10cSrcweir     }
1457cdf0e10cSrcweir 
1458cdf0e10cSrcweir     return sal_False;
1459cdf0e10cSrcweir }
1460cdf0e10cSrcweir 
IsInGroup(const ScDPItemData & rGroupData,long nGroupIndex,const ScDPItemData & rBaseData,long nBaseIndex) const1461cdf0e10cSrcweir sal_Bool ScDPGroupTableData::IsInGroup( const ScDPItemData& rGroupData, long nGroupIndex,
1462cdf0e10cSrcweir                                     const ScDPItemData& rBaseData, long nBaseIndex ) const
1463cdf0e10cSrcweir {
1464cdf0e10cSrcweir     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
1465cdf0e10cSrcweir     {
1466cdf0e10cSrcweir         const ScDPGroupDimension& rDim = *aIter;
1467cdf0e10cSrcweir         if ( rDim.GetGroupDim() == nGroupIndex && rDim.GetSourceDim() == nBaseIndex )
1468cdf0e10cSrcweir         {
1469cdf0e10cSrcweir             const ScDPDateGroupHelper* pGroupDateHelper = rDim.GetDateHelper();
1470cdf0e10cSrcweir             if ( pGroupDateHelper )
1471cdf0e10cSrcweir             {
1472cdf0e10cSrcweir                 //! transform rBaseData (innermost date part)
1473cdf0e10cSrcweir                 //! -> always do "HasCommonElement" style comparison
1474cdf0e10cSrcweir                 //! (only Quarter, Month, Day affected)
1475cdf0e10cSrcweir 
1476cdf0e10cSrcweir                 const ScDPDateGroupHelper* pBaseDateHelper = NULL;
1477cdf0e10cSrcweir                 if ( nBaseIndex < nSourceCount )
1478cdf0e10cSrcweir                     pBaseDateHelper = pNumGroups[nBaseIndex].GetDateHelper();
1479cdf0e10cSrcweir 
1480cdf0e10cSrcweir                 // If there's a date group dimension, the base dimension must have
1481cdf0e10cSrcweir                 // date group information, too.
1482cdf0e10cSrcweir                 if ( !pBaseDateHelper )
1483cdf0e10cSrcweir                 {
1484cdf0e10cSrcweir                     DBG_ERROR( "mix of date and non-date groups" );
1485cdf0e10cSrcweir                     return sal_True;
1486cdf0e10cSrcweir                 }
1487cdf0e10cSrcweir 
1488cdf0e10cSrcweir                 sal_Int32 nGroupPart = pGroupDateHelper->GetDatePart();
1489cdf0e10cSrcweir                 sal_Int32 nBasePart = pBaseDateHelper->GetDatePart();
1490cdf0e10cSrcweir                 return lcl_DateContained( nGroupPart, rGroupData, nBasePart, rBaseData );
1491cdf0e10cSrcweir             }
1492cdf0e10cSrcweir             else
1493cdf0e10cSrcweir             {
1494cdf0e10cSrcweir                 // If the item is in a group, only that group is valid.
1495cdf0e10cSrcweir                 // If the item is not in any group, its own name is valid.
1496cdf0e10cSrcweir 
1497cdf0e10cSrcweir                 const ScDPGroupItem* pGroup = rDim.GetGroupForData( rBaseData );
1498cdf0e10cSrcweir                 return pGroup ? pGroup->GetName().IsCaseInsEqual( rGroupData ) :
1499cdf0e10cSrcweir                                 rGroupData.IsCaseInsEqual( rBaseData );
1500cdf0e10cSrcweir             }
1501cdf0e10cSrcweir         }
1502cdf0e10cSrcweir     }
1503cdf0e10cSrcweir 
1504cdf0e10cSrcweir     DBG_ERROR("IsInGroup: no group dimension found");
1505cdf0e10cSrcweir     return sal_True;
1506cdf0e10cSrcweir }
1507cdf0e10cSrcweir 
HasCommonElement(const ScDPItemData & rFirstData,long nFirstIndex,const ScDPItemData & rSecondData,long nSecondIndex) const1508cdf0e10cSrcweir sal_Bool ScDPGroupTableData::HasCommonElement( const ScDPItemData& rFirstData, long nFirstIndex,
1509cdf0e10cSrcweir                                          const ScDPItemData& rSecondData, long nSecondIndex ) const
1510cdf0e10cSrcweir {
1511cdf0e10cSrcweir     const ScDPGroupDimension* pFirstDim = NULL;
1512cdf0e10cSrcweir     const ScDPGroupDimension* pSecondDim = NULL;
1513cdf0e10cSrcweir     for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
1514cdf0e10cSrcweir     {
1515cdf0e10cSrcweir         const ScDPGroupDimension* pDim = &(*aIter);
1516cdf0e10cSrcweir         if ( pDim->GetGroupDim() == nFirstIndex )
1517cdf0e10cSrcweir             pFirstDim = pDim;
1518cdf0e10cSrcweir         else if ( pDim->GetGroupDim() == nSecondIndex )
1519cdf0e10cSrcweir             pSecondDim = pDim;
1520cdf0e10cSrcweir     }
1521cdf0e10cSrcweir     if ( pFirstDim && pSecondDim )
1522cdf0e10cSrcweir     {
1523cdf0e10cSrcweir         const ScDPDateGroupHelper* pFirstDateHelper = pFirstDim->GetDateHelper();
1524cdf0e10cSrcweir         const ScDPDateGroupHelper* pSecondDateHelper = pSecondDim->GetDateHelper();
1525cdf0e10cSrcweir         if ( pFirstDateHelper || pSecondDateHelper )
1526cdf0e10cSrcweir         {
1527cdf0e10cSrcweir             // If one is a date group dimension, the other one must be, too.
1528cdf0e10cSrcweir             if ( !pFirstDateHelper || !pSecondDateHelper )
1529cdf0e10cSrcweir             {
1530cdf0e10cSrcweir                 DBG_ERROR( "mix of date and non-date groups" );
1531cdf0e10cSrcweir                 return sal_True;
1532cdf0e10cSrcweir             }
1533cdf0e10cSrcweir 
1534cdf0e10cSrcweir             sal_Int32 nFirstPart = pFirstDateHelper->GetDatePart();
1535cdf0e10cSrcweir             sal_Int32 nSecondPart = pSecondDateHelper->GetDatePart();
1536cdf0e10cSrcweir             return lcl_DateContained( nFirstPart, rFirstData, nSecondPart, rSecondData );
1537cdf0e10cSrcweir         }
1538cdf0e10cSrcweir 
1539cdf0e10cSrcweir         const ScDPGroupItem* pFirstItem = pFirstDim->GetGroupForName( rFirstData );
1540cdf0e10cSrcweir         const ScDPGroupItem* pSecondItem = pSecondDim->GetGroupForName( rSecondData );
1541cdf0e10cSrcweir         if ( pFirstItem && pSecondItem )
1542cdf0e10cSrcweir         {
1543cdf0e10cSrcweir             // two existing groups -> sal_True if they have a common element
1544cdf0e10cSrcweir             return pFirstItem->HasCommonElement( *pSecondItem );
1545cdf0e10cSrcweir         }
1546cdf0e10cSrcweir         else if ( pFirstItem )
1547cdf0e10cSrcweir         {
1548cdf0e10cSrcweir             // "automatic" group contains only its own name
1549cdf0e10cSrcweir             return pFirstItem->HasElement( rSecondData );
1550cdf0e10cSrcweir         }
1551cdf0e10cSrcweir         else if ( pSecondItem )
1552cdf0e10cSrcweir         {
1553cdf0e10cSrcweir             // "automatic" group contains only its own name
1554cdf0e10cSrcweir             return pSecondItem->HasElement( rFirstData );
1555cdf0e10cSrcweir         }
1556cdf0e10cSrcweir         else
1557cdf0e10cSrcweir         {
1558cdf0e10cSrcweir             // no groups -> sal_True if equal
1559cdf0e10cSrcweir             return rFirstData.IsCaseInsEqual( rSecondData );
1560cdf0e10cSrcweir         }
1561cdf0e10cSrcweir     }
1562cdf0e10cSrcweir 
1563cdf0e10cSrcweir     DBG_ERROR("HasCommonElement: no group dimension found");
1564cdf0e10cSrcweir     return sal_True;
1565cdf0e10cSrcweir }
1566cdf0e10cSrcweir 
GetSourceDim(long nDim)1567cdf0e10cSrcweir long ScDPGroupTableData::GetSourceDim( long nDim )
1568cdf0e10cSrcweir {
1569cdf0e10cSrcweir 	if ( getIsDataLayoutDimension( nDim ) )
1570cdf0e10cSrcweir 		return nSourceCount;
1571cdf0e10cSrcweir 	if (  nDim >= nSourceCount && nDim < nSourceCount +(long) aGroups.size()  )
1572cdf0e10cSrcweir 	{
1573cdf0e10cSrcweir 	     const ScDPGroupDimension& rGroupDim = aGroups[nDim - nSourceCount];
1574cdf0e10cSrcweir             return  rGroupDim.GetSourceDim();
1575cdf0e10cSrcweir 	}
1576cdf0e10cSrcweir 	return nDim;
1577cdf0e10cSrcweir }
Compare(long nDim,long nDataId1,long nDataId2)1578cdf0e10cSrcweir  long ScDPGroupTableData::Compare( long nDim, long nDataId1, long nDataId2)
1579cdf0e10cSrcweir {
1580cdf0e10cSrcweir 	if ( getIsDataLayoutDimension(nDim) )
1581cdf0e10cSrcweir 		return 0;
1582cdf0e10cSrcweir 	return ScDPItemData::Compare( *GetMemberById(nDim,  nDataId1),*GetMemberById(nDim,  nDataId2) );
1583cdf0e10cSrcweir }
1584cdf0e10cSrcweir // -----------------------------------------------------------------------
1585cdf0e10cSrcweir 
1586