xref: /trunk/main/sc/source/core/data/dptabsrc.cxx (revision 2722ceddc26af33ca9ed6a22fc3c4dfb805171c3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 
34 // INCLUDE ---------------------------------------------------------------
35 
36 #include <algorithm>
37 #include <vector>
38 #include <set>
39 #include <hash_map>
40 #include <hash_set>
41 
42 #include <tools/debug.hxx>
43 #include <rtl/math.hxx>
44 #include <svl/itemprop.hxx>
45 #include <svl/intitem.hxx>
46 
47 #include "scitems.hxx"
48 #include "document.hxx"
49 #include "docpool.hxx"
50 #include "patattr.hxx"
51 #include "cell.hxx"
52 
53 #include "dptabsrc.hxx"
54 #include "dptabres.hxx"
55 #include "dptabdat.hxx"
56 #include "global.hxx"
57 #include "collect.hxx"
58 #include "datauno.hxx"      // ScDataUnoConversion
59 #include "unoguard.hxx"
60 #include "miscuno.hxx"
61 #include "unonames.hxx"
62 
63 #include <com/sun/star/beans/PropertyAttribute.hpp>
64 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
65 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
66 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
67 #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
68 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
69 #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
70 #include <com/sun/star/table/CellAddress.hpp>
71 
72 #include <unotools/collatorwrapper.hxx>
73 #include <unotools/calendarwrapper.hxx>
74 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
75 
76 using namespace com::sun::star;
77 using ::std::vector;
78 using ::std::set;
79 using ::std::hash_map;
80 using ::std::hash_set;
81 using ::com::sun::star::uno::Reference;
82 using ::com::sun::star::uno::Sequence;
83 using ::com::sun::star::uno::Any;
84 using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
85 using ::rtl::OUString;
86 
87 // -----------------------------------------------------------------------
88 
89 #define SC_MINCOUNT_LIMIT   1000000
90 
91 // -----------------------------------------------------------------------
92 
93 SC_SIMPLE_SERVICE_INFO( ScDPSource,      "ScDPSource",      "com.sun.star.sheet.DataPilotSource" )
94 SC_SIMPLE_SERVICE_INFO( ScDPDimensions,  "ScDPDimensions",  "com.sun.star.sheet.DataPilotSourceDimensions" )
95 SC_SIMPLE_SERVICE_INFO( ScDPDimension,   "ScDPDimension",   "com.sun.star.sheet.DataPilotSourceDimension" )
96 SC_SIMPLE_SERVICE_INFO( ScDPHierarchies, "ScDPHierarchies", "com.sun.star.sheet.DataPilotSourceHierarcies" )
97 SC_SIMPLE_SERVICE_INFO( ScDPHierarchy,   "ScDPHierarchy",   "com.sun.star.sheet.DataPilotSourceHierarcy" )
98 SC_SIMPLE_SERVICE_INFO( ScDPLevels,      "ScDPLevels",      "com.sun.star.sheet.DataPilotSourceLevels" )
99 SC_SIMPLE_SERVICE_INFO( ScDPLevel,       "ScDPLevel",       "com.sun.star.sheet.DataPilotSourceLevel" )
100 SC_SIMPLE_SERVICE_INFO( ScDPMembers,     "ScDPMembers",     "com.sun.star.sheet.DataPilotSourceMembers" )
101 SC_SIMPLE_SERVICE_INFO( ScDPMember,      "ScDPMember",      "com.sun.star.sheet.DataPilotSourceMember" )
102 
103 // -----------------------------------------------------------------------
104 
105 // property maps for PropertySetInfo
106 //  DataDescription / NumberFormat are internal
107 
108 // -----------------------------------------------------------------------
109 
110 //! move to a header?
111 sal_Bool lcl_GetBoolFromAny( const uno::Any& aAny )
112 {
113     if ( aAny.getValueTypeClass() == uno::TypeClass_BOOLEAN )
114         return *(sal_Bool*)aAny.getValue();
115     return sal_False;
116 }
117 
118 void lcl_SetBoolInAny( uno::Any& rAny, sal_Bool bValue )
119 {
120     rAny.setValue( &bValue, getBooleanCppuType() );
121 }
122 
123 // -----------------------------------------------------------------------
124 
125 ScDPSource::ScDPSource( ScDPTableData* pD ) :
126     pData( pD ),
127     pDimensions( NULL ),
128     nColDimCount( 0 ),
129     nRowDimCount( 0 ),
130     nDataDimCount( 0 ),
131     nPageDimCount( 0 ),
132     bColumnGrand( sal_True ),       // default is true
133     bRowGrand( sal_True ),
134     bIgnoreEmptyRows( sal_False ),
135     bRepeatIfEmpty( sal_False ),
136     nDupCount( 0 ),
137     pResData( NULL ),
138     pColResRoot( NULL ),
139     pRowResRoot( NULL ),
140     pColResults( NULL ),
141     pRowResults( NULL ),
142     bResultOverflow( sal_False ),
143     bPageFiltered( false ),
144     mpGrandTotalName(NULL)
145 {
146     pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
147 }
148 
149 ScDPSource::~ScDPSource()
150 {
151     if (pDimensions)
152         pDimensions->release();     // ref-counted
153 
154     //! free lists
155 
156     delete[] pColResults;
157     delete[] pRowResults;
158 
159     delete pColResRoot;
160     delete pRowResRoot;
161     delete pResData;
162 }
163 
164 void ScDPSource::SetGrandTotalName(const ::rtl::OUString& rName)
165 {
166     mpGrandTotalName.reset(new ::rtl::OUString(rName));
167 }
168 
169 const ::rtl::OUString* ScDPSource::GetGrandTotalName() const
170 {
171     return mpGrandTotalName.get();
172 }
173 
174 sal_uInt16 ScDPSource::GetOrientation(long nColumn)
175 {
176     long i;
177     for (i=0; i<nColDimCount; i++)
178         if (nColDims[i] == nColumn)
179             return sheet::DataPilotFieldOrientation_COLUMN;
180     for (i=0; i<nRowDimCount; i++)
181         if (nRowDims[i] == nColumn)
182             return sheet::DataPilotFieldOrientation_ROW;
183     for (i=0; i<nDataDimCount; i++)
184         if (nDataDims[i] == nColumn)
185             return sheet::DataPilotFieldOrientation_DATA;
186     for (i=0; i<nPageDimCount; i++)
187         if (nPageDims[i] == nColumn)
188             return sheet::DataPilotFieldOrientation_PAGE;
189     return sheet::DataPilotFieldOrientation_HIDDEN;
190 }
191 
192 long ScDPSource::GetDataDimensionCount()
193 {
194     return nDataDimCount;
195 }
196 
197 ScDPDimension* ScDPSource::GetDataDimension(long nIndex)
198 {
199     if (nIndex < 0 || nIndex >= nDataDimCount)
200         return NULL;
201 
202     long nDimIndex = nDataDims[nIndex];
203     return GetDimensionsObject()->getByIndex(nDimIndex);
204 }
205 
206 String ScDPSource::GetDataDimName( long nIndex )
207 {
208     String aRet;
209     ScDPDimension* pDim = GetDataDimension(nIndex);
210     if (pDim)
211         aRet = String(pDim->getName());
212     return aRet;
213 }
214 
215 long ScDPSource::GetPosition(long nColumn)
216 {
217     long i;
218     for (i=0; i<nColDimCount; i++)
219         if (nColDims[i] == nColumn)
220             return i;
221     for (i=0; i<nRowDimCount; i++)
222         if (nRowDims[i] == nColumn)
223             return i;
224     for (i=0; i<nDataDimCount; i++)
225         if (nDataDims[i] == nColumn)
226             return i;
227     for (i=0; i<nPageDimCount; i++)
228         if (nPageDims[i] == nColumn)
229             return i;
230     return 0;
231 }
232 
233 sal_Bool lcl_TestSubTotal( sal_Bool& rAllowed, long nColumn, long* pArray, long nCount, ScDPSource* pSource )
234 {
235     for (long i=0; i<nCount; i++)
236         if (pArray[i] == nColumn)
237         {
238             //  no subtotals for data layout dim, no matter where
239             if ( pSource->IsDataLayoutDimension(nColumn) )
240                 rAllowed = sal_False;
241             else
242             {
243                 //  no subtotals if no other dim but data layout follows
244                 long nNextIndex = i+1;
245                 if ( nNextIndex < nCount && pSource->IsDataLayoutDimension(pArray[nNextIndex]) )
246                     ++nNextIndex;
247                 if ( nNextIndex >= nCount )
248                     rAllowed = sal_False;
249             }
250 
251             return sal_True;    // found
252         }
253     return sal_False;
254 }
255 
256 sal_Bool ScDPSource::SubTotalAllowed(long nColumn)
257 {
258     //! cache this at ScDPResultData
259     sal_Bool bAllowed = sal_True;
260     if ( lcl_TestSubTotal( bAllowed, nColumn, nColDims, nColDimCount, this ) )
261         return bAllowed;
262     if ( lcl_TestSubTotal( bAllowed, nColumn, nRowDims, nRowDimCount, this ) )
263         return bAllowed;
264     return bAllowed;
265 }
266 
267 void lcl_RemoveDim( long nRemove, long* pDims, long& rCount )
268 {
269     for (long i=0; i<rCount; i++)
270         if ( pDims[i] == nRemove )
271         {
272             for (long j=i; j+1<rCount; j++)
273                 pDims[j] = pDims[j+1];
274             --rCount;
275             return;
276         }
277 }
278 
279 void ScDPSource::SetOrientation(long nColumn, sal_uInt16 nNew)
280 {
281     //! change to no-op if new orientation is equal to old?
282 
283     // remove from old list
284     lcl_RemoveDim( nColumn, nColDims, nColDimCount );
285     lcl_RemoveDim( nColumn, nRowDims, nRowDimCount );
286     lcl_RemoveDim( nColumn, nDataDims, nDataDimCount );
287     lcl_RemoveDim( nColumn, nPageDims, nPageDimCount );
288 
289     // add to new list
290     switch (nNew)
291     {
292         case sheet::DataPilotFieldOrientation_COLUMN:
293             nColDims[nColDimCount++] = nColumn;
294             break;
295         case sheet::DataPilotFieldOrientation_ROW:
296             nRowDims[nRowDimCount++] = nColumn;
297             break;
298         case sheet::DataPilotFieldOrientation_DATA:
299             nDataDims[nDataDimCount++] = nColumn;
300             break;
301         case sheet::DataPilotFieldOrientation_PAGE:
302             nPageDims[nPageDimCount++] = nColumn;
303             break;
304             // Wang Xu Ming -- 2009-9-1
305             // DataPilot Migration - Cache&&Performance
306         case sheet::DataPilotFieldOrientation_HIDDEN:
307             break;
308             // End Comments
309         default:
310             DBG_ERROR( "ScDPSource::SetOrientation: unexpected orientation" );
311             break;
312     }
313 }
314 
315 sal_Bool ScDPSource::IsDataLayoutDimension(long nDim)
316 {
317     return nDim == pData->GetColumnCount();
318 }
319 
320 sal_uInt16 ScDPSource::GetDataLayoutOrientation()
321 {
322     return GetOrientation(pData->GetColumnCount());
323 }
324 
325 sal_Bool ScDPSource::IsDateDimension(long nDim)
326 {
327     return pData->IsDateDimension(nDim);
328 }
329 
330 sal_uInt32  ScDPSource::GetNumberFormat(long nDim)
331 {
332     return pData->GetNumberFormat( nDim );
333 }
334 
335 ScDPDimensions* ScDPSource::GetDimensionsObject()
336 {
337     if (!pDimensions)
338     {
339         pDimensions = new ScDPDimensions(this);
340         pDimensions->acquire();                     // ref-counted
341     }
342     return pDimensions;
343 }
344 
345 uno::Reference<container::XNameAccess> SAL_CALL ScDPSource::getDimensions() throw(uno::RuntimeException)
346 {
347     return GetDimensionsObject();
348 }
349 
350 void ScDPSource::SetDupCount( long nNew )
351 {
352     nDupCount = nNew;
353 }
354 
355 ScDPDimension* ScDPSource::AddDuplicated(long /* nSource */, const String& rNewName)
356 {
357     DBG_ASSERT( pDimensions, "AddDuplicated without dimensions?" );
358 
359     //  re-use
360 
361     long nOldDimCount = pDimensions->getCount();
362     for (long i=0; i<nOldDimCount; i++)
363     {
364         ScDPDimension* pDim = pDimensions->getByIndex(i);
365         if (pDim && String(pDim->getName()) == rNewName)
366         {
367             //! test if pDim is a duplicate of source
368             return pDim;
369         }
370     }
371 
372     SetDupCount( nDupCount + 1 );
373     pDimensions->CountChanged();        // uses nDupCount
374 
375     return pDimensions->getByIndex( pDimensions->getCount() - 1 );
376 }
377 
378 long ScDPSource::GetSourceDim(long nDim)
379 {
380     //  original source dimension or data layout dimension?
381     if ( nDim <= pData->GetColumnCount() )
382         return nDim;
383 
384     if ( nDim < pDimensions->getCount() )
385     {
386         ScDPDimension* pDimObj = pDimensions->getByIndex( nDim );
387         if ( pDimObj )
388         {
389             long nSource = pDimObj->GetSourceDim();
390             if ( nSource >= 0 )
391                 return nSource;
392         }
393     }
394 
395     DBG_ERROR("GetSourceDim: wrong dim");
396     return nDim;
397 }
398 
399 uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResults()
400                                                             throw(uno::RuntimeException)
401 {
402     CreateRes_Impl();       // create pColResRoot and pRowResRoot
403 
404     if ( bResultOverflow )      // set in CreateRes_Impl
405     {
406         //  no results available
407         throw uno::RuntimeException();
408     }
409 
410     long nColCount = pColResRoot->GetSize(pResData->GetColStartMeasure());
411     long nRowCount = pRowResRoot->GetSize(pResData->GetRowStartMeasure());
412 
413     //  allocate full sequence
414     //! leave out empty rows???
415 
416     uno::Sequence< uno::Sequence<sheet::DataResult> > aSeq( nRowCount );
417     uno::Sequence<sheet::DataResult>* pRowAry = aSeq.getArray();
418     for (long nRow = 0; nRow < nRowCount; nRow++)
419     {
420         uno::Sequence<sheet::DataResult> aColSeq( nColCount );
421         //  use default values of DataResult
422         pRowAry[nRow] = aColSeq;
423     }
424 
425     long nSeqRow = 0;
426     pRowResRoot->FillDataResults( pColResRoot, aSeq, nSeqRow, pResData->GetRowStartMeasure() );
427 
428     return aSeq;
429 }
430 
431 void SAL_CALL ScDPSource::refresh() throw(uno::RuntimeException)
432 {
433     disposeData();
434 }
435 
436 void SAL_CALL ScDPSource::addRefreshListener( const uno::Reference<util::XRefreshListener >& )
437                                                 throw(uno::RuntimeException)
438 {
439     DBG_ERROR("not implemented");   //! exception?
440 }
441 
442 void SAL_CALL ScDPSource::removeRefreshListener( const uno::Reference<util::XRefreshListener >& )
443                                                 throw(uno::RuntimeException)
444 {
445     DBG_ERROR("not implemented");   //! exception?
446 }
447 
448 Sequence< Sequence<Any> > SAL_CALL ScDPSource::getDrillDownData(const Sequence<sheet::DataPilotFieldFilter>& aFilters)
449     throw (uno::RuntimeException)
450 {
451     long nColumnCount = GetData()->GetColumnCount();
452 
453     typedef hash_map<String, long, ScStringHashCode> FieldNameMapType;
454     FieldNameMapType aFieldNames;
455     for (long i = 0; i < nColumnCount; ++i)
456     {
457         aFieldNames.insert(
458             FieldNameMapType::value_type(GetData()->getDimensionName(i), i));
459     }
460 
461     // collect ScDPItemData for each filtered column
462     vector<ScDPCacheTable::Criterion> aFilterCriteria;
463     sal_Int32 nFilterCount = aFilters.getLength();
464     for (sal_Int32 i = 0; i < nFilterCount; ++i)
465     {
466         const sheet::DataPilotFieldFilter& rFilter = aFilters[i];
467         String aFieldName( rFilter.FieldName );
468         for (long nCol = 0; nCol < nColumnCount; ++nCol)
469         {
470             if ( aFieldName == pData->getDimensionName(nCol) )
471             {
472                 ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nCol );
473                 ScDPMembers* pMembers = pDim->GetHierarchiesObject()->getByIndex(0)->
474                                         GetLevelsObject()->getByIndex(0)->GetMembersObject();
475                 sal_Int32 nIndex = pMembers->GetIndexFromName( rFilter.MatchValue );
476                 if ( nIndex >= 0 )
477                 {
478                     ScDPItemData aItem;
479                     pMembers->getByIndex(nIndex)->FillItemData( aItem );
480                     aFilterCriteria.push_back( ScDPCacheTable::Criterion() );
481                     aFilterCriteria.back().mnFieldIndex = nCol;
482                     aFilterCriteria.back().mpFilter.reset(
483                         new ScDPCacheTable::SingleFilter(aItem.GetString()/*rSharedString, nMatchStrId*/, aItem.GetValue(), aItem.IsValue()) );
484                 }
485             }
486         }
487     }
488 
489     // Take into account the visibilities of field members.
490     ScDPResultVisibilityData aResVisData(/*rSharedString, */this);
491     pRowResRoot->FillVisibilityData(aResVisData);
492     pColResRoot->FillVisibilityData(aResVisData);
493     aResVisData.fillFieldFilters(aFilterCriteria);
494 
495     Sequence< Sequence<Any> > aTabData;
496     hash_set<sal_Int32> aCatDims;
497     GetCategoryDimensionIndices(aCatDims);
498     pData->GetDrillDownData(aFilterCriteria, aCatDims, aTabData);
499     return aTabData;
500 }
501 
502 String ScDPSource::getDataDescription()
503 {
504     CreateRes_Impl();       // create pResData
505 
506     String aRet;
507     if ( pResData->GetMeasureCount() == 1 )
508     {
509         bool bTotalResult = false;
510         aRet = pResData->GetMeasureString( 0, sal_True, SUBTOTAL_FUNC_NONE, bTotalResult );
511     }
512 
513     //  empty for more than one measure
514 
515     return aRet;
516 }
517 
518 sal_Bool ScDPSource::getColumnGrand() const
519 {
520     return bColumnGrand;
521 }
522 
523 void ScDPSource::setColumnGrand(sal_Bool bSet)
524 {
525     bColumnGrand = bSet;
526 }
527 
528 sal_Bool ScDPSource::getRowGrand() const
529 {
530     return bRowGrand;
531 }
532 
533 void ScDPSource::setRowGrand(sal_Bool bSet)
534 {
535     bRowGrand = bSet;
536 }
537 
538 sal_Bool ScDPSource::getIgnoreEmptyRows() const
539 {
540     return bIgnoreEmptyRows;
541 }
542 
543 void ScDPSource::setIgnoreEmptyRows(sal_Bool bSet)
544 {
545     bIgnoreEmptyRows = bSet;
546     pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
547 }
548 
549 sal_Bool ScDPSource::getRepeatIfEmpty() const
550 {
551     return bRepeatIfEmpty;
552 }
553 
554 void ScDPSource::setRepeatIfEmpty(sal_Bool bSet)
555 {
556     bRepeatIfEmpty = bSet;
557     pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
558 }
559 
560 void ScDPSource::validate()     //! ???
561 {
562     CreateRes_Impl();
563 }
564 
565 void ScDPSource::disposeData()
566 {
567     if ( pResData )
568     {
569         //  reset all data...
570 
571         DELETEZ(pColResRoot);
572         DELETEZ(pRowResRoot);
573         DELETEZ(pResData);
574         delete[] pColResults;
575         delete[] pRowResults;
576         pColResults = NULL;
577         pRowResults = NULL;
578         aColLevelList.Clear();
579         aRowLevelList.Clear();
580     }
581 
582     if ( pDimensions )
583     {
584         pDimensions->release(); // ref-counted
585         pDimensions = NULL;     //  settings have to be applied (from SaveData) again!
586     }
587     SetDupCount( 0 );
588 
589     //! Test ????
590     nColDimCount = nRowDimCount = nDataDimCount = nPageDimCount = 0;
591 
592     pData->DisposeData();   // cached entries etc.
593     bPageFiltered = false;
594     bResultOverflow = sal_False;
595 }
596 
597 long lcl_CountMinMembers(const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLevel, long nLevels )
598 {
599     //  Calculate the product of the member count for those consecutive levels that
600     //  have the "show all" flag, one following level, and the data layout dimension.
601 
602     long nTotal = 1;
603     long nDataCount = 1;
604     sal_Bool bWasShowAll = sal_True;
605     long nPos = nLevels;
606     while ( nPos > 0 )
607     {
608         --nPos;
609 
610         if ( nPos+1 < nLevels && ppDim[nPos] == ppDim[nPos+1] )
611         {
612             DBG_ERROR("lcl_CountMinMembers: multiple levels from one dimension not implemented");
613             return 0;
614         }
615 
616         sal_Bool bDo = sal_False;
617         if ( ppDim[nPos]->getIsDataLayoutDimension() )
618         {
619             //  data layout dim doesn't interfere with "show all" flags
620             nDataCount = ppLevel[nPos]->GetMembersObject()->getCount();
621             if ( nDataCount == 0 )
622                 nDataCount = 1;
623         }
624         else if ( bWasShowAll )     // "show all" set for all following levels?
625         {
626             bDo = sal_True;
627             if ( !ppLevel[nPos]->getShowEmpty() )
628             {
629                 //  this level is counted, following ones are not
630                 bWasShowAll = sal_False;
631             }
632         }
633         if ( bDo )
634         {
635             long nThisCount = ppLevel[nPos]->GetMembersObject()->getMinMembers();
636             if ( nThisCount == 0 )
637             {
638                 nTotal = 1;         //  empty level -> start counting from here
639                                     //! start with visible elements in this level?
640             }
641             else
642             {
643                 if ( nTotal >= LONG_MAX / nThisCount )
644                     return LONG_MAX;                        //  overflow
645                 nTotal *= nThisCount;
646             }
647         }
648     }
649 
650     //  always include data layout dim, even after restarting
651     if ( nTotal >= LONG_MAX / nDataCount )
652         return LONG_MAX;                        //  overflow
653     nTotal *= nDataCount;
654 
655     return nTotal;
656 }
657 
658 long lcl_GetIndexFromName( const rtl::OUString rName, const uno::Sequence<rtl::OUString>& rElements )
659 {
660     long nCount = rElements.getLength();
661     const rtl::OUString* pArray = rElements.getConstArray();
662     for (long nPos=0; nPos<nCount; nPos++)
663         if (pArray[nPos] == rName)
664             return nPos;
665 
666     return -1;  // not found
667 }
668 
669 void ScDPSource::FillCalcInfo(bool bIsRow, ScDPTableData::CalcInfo& rInfo, bool &rHasAutoShow)
670 {
671     long* nDims = bIsRow ? nRowDims : nColDims;
672     long nDimCount = bIsRow ? nRowDimCount : nColDimCount;
673 
674     for (long i = 0; i < nDimCount; ++i)
675     {
676         ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nDims[i] );
677         long nHierarchy = pDim->getUsedHierarchy();
678         if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() )
679             nHierarchy = 0;
680         ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
681         long nCount = pLevels->getCount();
682 
683         //! Test
684         if ( pDim->getIsDataLayoutDimension() && nDataDimCount < 2 )
685             nCount = 0;
686         //! Test
687 
688         for (long j = 0; j < nCount; ++j)
689         {
690             ScDPLevel* pLevel = pLevels->getByIndex(j);
691             pLevel->EvaluateSortOrder();
692 
693             // no layout flags for column fields, only for row fields
694             pLevel->SetEnableLayout( bIsRow );
695 
696             if ( pLevel->GetAutoShow().IsEnabled )
697                 rHasAutoShow = sal_True;
698 
699             if (bIsRow)
700             {
701                 rInfo.aRowLevelDims.push_back(nDims[i]);
702                 rInfo.aRowDims.push_back(pDim);
703                 rInfo.aRowLevels.push_back(pLevel);
704             }
705             else
706             {
707                 rInfo.aColLevelDims.push_back(nDims[i]);
708                 rInfo.aColDims.push_back(pDim);
709                 rInfo.aColLevels.push_back(pLevel);
710             }
711 
712             pLevel->GetMembersObject();                 // initialize for groups
713         }
714     }
715 }
716 
717 void ScDPSource::GetCategoryDimensionIndices(hash_set<sal_Int32>& rCatDims)
718 {
719     hash_set<sal_Int32> aCatDims;
720     for (long i = 0; i < nColDimCount; ++i)
721     {
722         sal_Int32 nDim = static_cast<sal_Int32>(nColDims[i]);
723         if (!IsDataLayoutDimension(nDim))
724             aCatDims.insert(nDim);
725     }
726 
727     for (long i = 0; i < nRowDimCount; ++i)
728     {
729         sal_Int32 nDim = static_cast<sal_Int32>(nRowDims[i]);
730         if (!IsDataLayoutDimension(nDim))
731             aCatDims.insert(nDim);
732     }
733 
734     for (long i = 0; i < nPageDimCount; ++i)
735     {
736         sal_Int32 nDim = static_cast<sal_Int32>(nPageDims[i]);
737         if (!IsDataLayoutDimension(nDim))
738             aCatDims.insert(nDim);
739     }
740 
741     rCatDims.swap(aCatDims);
742 }
743 
744 void ScDPSource::FilterCacheTableByPageDimensions()
745 {
746     // #i117661# Repeated calls to ScDPCacheTable::filterByPageDimension are invalid because
747     // rows are only hidden, never shown again. If FilterCacheTableByPageDimensions is called
748     // again, the cache table must be re-initialized. Currently, CreateRes_Impl always uses
749     // a fresh cache because ScDBDocFunc::DataPilotUpdate calls InvalidateData.
750 
751     if (bPageFiltered)
752     {
753         DBG_ERRORFILE("tried to apply page field filters several times");
754 
755         pData->DisposeData();
756         pData->CreateCacheTable();  // re-initialize the cache table
757         bPageFiltered = false;
758     }
759 
760     // filter table by page dimensions.
761     vector<ScDPCacheTable::Criterion> aCriteria;
762     for (long i = 0; i < nPageDimCount; ++i)
763     {
764         ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nPageDims[i]);
765         long nField = pDim->GetDimension();
766 
767         ScDPMembers* pMems = pDim->GetHierarchiesObject()->getByIndex(0)->
768             GetLevelsObject()->getByIndex(0)->GetMembersObject();
769 
770         long nMemCount = pMems->getCount();
771         ScDPCacheTable::Criterion aFilter;
772         aFilter.mnFieldIndex = static_cast<sal_Int32>(nField);
773         aFilter.mpFilter.reset(new ScDPCacheTable::GroupFilter(/*rSharedString*/));
774         ScDPCacheTable::GroupFilter* pGrpFilter =
775             static_cast<ScDPCacheTable::GroupFilter*>(aFilter.mpFilter.get());
776         for (long j = 0; j < nMemCount; ++j)
777         {
778             ScDPMember* pMem = pMems->getByIndex(j);
779             if (pMem->getIsVisible())
780             {
781                 ScDPItemData aData;
782                 pMem->FillItemData(aData);
783                 pGrpFilter->addMatchItem(aData.GetString(), aData.GetValue(), aData.IsValue());
784             }
785         }
786         if (pGrpFilter->getMatchItemCount() < static_cast<size_t>(nMemCount))
787             // there is at least one invisible item.  Add this filter criterion to the mix.
788             aCriteria.push_back(aFilter);
789 
790         if (!pDim || !pDim->HasSelectedPage())
791             continue;
792 
793         const ScDPItemData& rData = pDim->GetSelectedData();
794         aCriteria.push_back(ScDPCacheTable::Criterion());
795         ScDPCacheTable::Criterion& r = aCriteria.back();
796         r.mnFieldIndex = static_cast<sal_Int32>(nField);
797         r.mpFilter.reset(
798             new ScDPCacheTable::SingleFilter(rData.GetString()/*rSharedString, nStrId*/, rData.GetValue(), rData.IsValue()));
799     }
800     if (!aCriteria.empty())
801     {
802         hash_set<sal_Int32> aCatDims;
803         GetCategoryDimensionIndices(aCatDims);
804         pData->FilterCacheTable(aCriteria, aCatDims);
805         bPageFiltered = true;
806     }
807 }
808 
809 void ScDPSource::CreateRes_Impl()
810 {
811     if ( !pResData )
812     {
813         sal_uInt16 nDataOrient = GetDataLayoutOrientation();
814         if ( nDataDimCount > 1 && ( nDataOrient != sheet::DataPilotFieldOrientation_COLUMN &&
815                                     nDataOrient != sheet::DataPilotFieldOrientation_ROW ) )
816         {
817             //  if more than one data dimension, data layout orientation must be set
818             SetOrientation( pData->GetColumnCount(), sheet::DataPilotFieldOrientation_ROW );
819             nDataOrient = sheet::DataPilotFieldOrientation_ROW;
820         }
821 
822         // TODO: Aggreate pDataNames, pDataRefValues, nDataRefOrient, and
823         // eDataFunctions into a structure and use vector instead of static
824         // or pointer arrays.
825         String* pDataNames = NULL;
826         sheet::DataPilotFieldReference* pDataRefValues = NULL;
827         ScSubTotalFunc eDataFunctions[SC_DAPI_MAXFIELDS];
828         sal_uInt16 nDataRefOrient[SC_DAPI_MAXFIELDS];
829         if (nDataDimCount)
830         {
831             pDataNames = new String[nDataDimCount];
832             pDataRefValues = new sheet::DataPilotFieldReference[nDataDimCount];
833         }
834 
835         ScDPTableData::CalcInfo aInfo;
836 
837 
838         //  LateInit (initialize only those rows/children that are used) can be used unless
839         //  any data dimension needs reference values from column/row dimensions
840         sal_Bool bLateInit = sal_True;
841 
842         // Go through all data dimensions (i.e. fields) and build their meta data
843         // so that they can be passed on to ScDPResultData instance later.
844         // TODO: aggregate all of data dimension info into a structure.
845         long i;
846         for (i=0; i<nDataDimCount; i++)
847         {
848             // Get function for each data field.
849             long nDimIndex = nDataDims[i];
850             ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nDimIndex);
851             sheet::GeneralFunction eUser = (sheet::GeneralFunction)pDim->getFunction();
852             if (eUser == sheet::GeneralFunction_AUTO)
853             {
854                 //! test for numeric data
855                 eUser = sheet::GeneralFunction_SUM;
856             }
857 
858             // Map UNO's enum to internal enum ScSubTotalFunc.
859             eDataFunctions[i] = ScDataUnoConversion::GeneralToSubTotal( eUser );
860 
861             // Get reference field/item information.
862             pDataRefValues[i] = pDim->GetReferenceValue();
863             nDataRefOrient[i] = sheet::DataPilotFieldOrientation_HIDDEN;    // default if not used
864             sal_Int32 eRefType = pDataRefValues[i].ReferenceType;
865             if ( eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
866                  eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
867                  eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE ||
868                  eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL )
869             {
870                 long nColumn = lcl_GetIndexFromName( pDataRefValues[i].ReferenceField,
871                                         GetDimensionsObject()->getElementNames() );
872                 if ( nColumn >= 0 )
873                 {
874                     nDataRefOrient[i] = GetOrientation( nColumn );
875                     //  need fully initialized results to find reference values
876                     //  (both in column or row dimensions), so updated values or
877                     //  differences to 0 can be displayed even for empty results.
878                     bLateInit = sal_False;
879                 }
880             }
881 
882             pDataNames[i] = String( pDim->getName() );  //! label?
883 
884             //  asterisk is added to duplicated dimension names by ScDPSaveData::WriteToSource
885             //! modify user visible strings as in ScDPResultData::GetMeasureString instead!
886 
887             pDataNames[i].EraseTrailingChars('*');
888 
889             //! if the name is overridden by user, a flag must be set
890             //! so the user defined name replaces the function string and field name.
891 
892             //! the complete name (function and field) must be stored at the dimension
893 
894             long nSource = ((ScDPDimension*)pDim)->GetSourceDim();
895             if (nSource >= 0)
896                 aInfo.aDataSrcCols.push_back(nSource);
897             else
898                 aInfo.aDataSrcCols.push_back(nDimIndex);
899         }
900 
901         pResData = new ScDPResultData( this );
902         pResData->SetMeasureData( nDataDimCount, eDataFunctions, pDataRefValues, nDataRefOrient, pDataNames );
903         pResData->SetDataLayoutOrientation(nDataOrient);
904         pResData->SetLateInit( bLateInit );
905 
906         delete[] pDataNames;
907         delete[] pDataRefValues;
908 
909         bool bHasAutoShow = false;
910 
911         ScDPInitState aInitState;
912 
913         // Page field selections restrict the members shown in related fields
914         // (both in column and row fields). aInitState is filled with the page
915         // field selections, they are kept across the data iterator loop.
916 
917         for (i=0; i<nPageDimCount; i++)
918         {
919             ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nPageDims[i] );
920             if ( pDim->HasSelectedPage() )
921                 aInitState.AddMember( nPageDims[i], GetMemberId( nPageDims[i],  pDim->GetSelectedData() ) );
922         }
923 
924         pColResRoot = new ScDPResultMember( pResData, /*NULL, NULL, NULL, */bColumnGrand );
925         pRowResRoot = new ScDPResultMember( pResData, /*NULL, NULL, NULL, */bRowGrand );
926 
927         FillCalcInfo(false, aInfo, bHasAutoShow);
928         long nColLevelCount = aInfo.aColLevels.size();
929 
930         pColResRoot->InitFrom( aInfo.aColDims, aInfo.aColLevels, 0, aInitState );
931         pColResRoot->SetHasElements();
932 
933         FillCalcInfo(true, aInfo, bHasAutoShow);
934         long nRowLevelCount = aInfo.aRowLevels.size();
935 
936         if ( nRowLevelCount > 0 )
937         {
938             // disable layout flags for the innermost row field (level)
939             aInfo.aRowLevels[nRowLevelCount-1]->SetEnableLayout( sal_False );
940         }
941 
942         pRowResRoot->InitFrom( aInfo.aRowDims, aInfo.aRowLevels, 0, aInitState );
943         pRowResRoot->SetHasElements();
944 
945         // initialize members object also for all page dimensions (needed for numeric groups)
946         for (i=0; i<nPageDimCount; i++)
947         {
948             ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nPageDims[i] );
949             long nHierarchy = pDim->getUsedHierarchy();
950             if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() )
951                 nHierarchy = 0;
952 
953             ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
954             long nCount = pLevels->getCount();
955             for (long j=0; j<nCount; j++)
956                 pLevels->getByIndex(j)->GetMembersObject();             // initialize for groups
957         }
958 
959         //  pre-check: calculate minimum number of result columns / rows from
960         //  levels that have the "show all" flag set
961 
962         long nMinColMembers = lcl_CountMinMembers( aInfo.aColDims, aInfo.aColLevels, nColLevelCount );
963         long nMinRowMembers = lcl_CountMinMembers( aInfo.aRowDims, aInfo.aRowLevels, nRowLevelCount );
964 
965         if ( nMinColMembers > MAXCOLCOUNT/*SC_MINCOUNT_LIMIT*/ || nMinRowMembers > SC_MINCOUNT_LIMIT )
966         {
967             //  resulting table is too big -> abort before calculating
968             //  (this relies on late init, so no members are allocated in InitFrom above)
969 
970             bResultOverflow = sal_True;
971         }
972         else
973         {
974             FilterCacheTableByPageDimensions();
975 
976             aInfo.aPageDims.reserve(nPageDimCount);
977             for (i = 0; i < nPageDimCount; ++i)
978                 aInfo.aPageDims.push_back(nPageDims[i]);
979 
980             aInfo.pInitState = &aInitState;
981             aInfo.pColRoot   = pColResRoot;
982             aInfo.pRowRoot   = pRowResRoot;
983             pData->CalcResults(aInfo, false);
984 
985             pColResRoot->CheckShowEmpty();
986             pRowResRoot->CheckShowEmpty();
987             // ----------------------------------------------------------------
988             //  With all data processed, calculate the final results:
989 
990             //  UpdateDataResults calculates all original results from the collected values,
991             //  and stores them as reference values if needed.
992             pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() );
993 
994             if ( bHasAutoShow )     // do the double calculation only if AutoShow is used
995             {
996                 //  Find the desired members and set bAutoHidden flag for the others
997                 pRowResRoot->DoAutoShow( pColResRoot );
998 
999                 //  Reset all results to empty, so they can be built again with data for the
1000                 //  desired members only.
1001                 pColResRoot->ResetResults( sal_True );
1002                 pRowResRoot->ResetResults( sal_True );
1003                 pData->CalcResults(aInfo, true);
1004 
1005                 //  Call UpdateDataResults again, with the new (limited) values.
1006                 pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() );
1007             }
1008 
1009             //  SortMembers does the sorting by a result dimension, using the orginal results,
1010             //  but not running totals etc.
1011             pRowResRoot->SortMembers( pColResRoot );
1012 
1013             //  UpdateRunningTotals calculates running totals along column/row dimensions,
1014             //  differences from other members (named or relative), and column/row percentages
1015             //  or index values.
1016             //  Running totals and relative differences need to be done using the sorted values.
1017             //  Column/row percentages and index values must be done after sorting, because the
1018             //  results may no longer be in the right order (row total for percentage of row is
1019             //  always 1).
1020             ScDPRunningTotalState aRunning( pColResRoot, pRowResRoot );
1021             ScDPRowTotals aTotals;
1022             pRowResRoot->UpdateRunningTotals( pColResRoot, pResData->GetRowStartMeasure(), aRunning, aTotals );
1023 
1024             // ----------------------------------------------------------------
1025         }
1026     }
1027 }
1028 
1029 //UNUSED2009-05 void ScDPSource::DumpState( ScDocument* pDoc, const ScAddress& rPos )
1030 //UNUSED2009-05 {
1031 //UNUSED2009-05     CreateRes_Impl();
1032 //UNUSED2009-05
1033 //UNUSED2009-05     ScAddress aDocPos( rPos );
1034 //UNUSED2009-05
1035 //UNUSED2009-05     if (pColResRoot->GetChildDimension())
1036 //UNUSED2009-05         pColResRoot->GetChildDimension()->DumpState( NULL, pDoc, aDocPos );
1037 //UNUSED2009-05     pRowResRoot->DumpState( pColResRoot, pDoc, aDocPos );
1038 //UNUSED2009-05 }
1039 
1040 void ScDPSource::FillLevelList( sal_uInt16 nOrientation, List& rList )
1041 {
1042     rList.Clear();
1043 
1044     long nDimCount = 0;
1045     long* pDimIndex = NULL;
1046     switch (nOrientation)
1047     {
1048         case sheet::DataPilotFieldOrientation_COLUMN:
1049             pDimIndex = nColDims;
1050             nDimCount = nColDimCount;
1051             break;
1052         case sheet::DataPilotFieldOrientation_ROW:
1053             pDimIndex = nRowDims;
1054             nDimCount = nRowDimCount;
1055             break;
1056         case sheet::DataPilotFieldOrientation_DATA:
1057             pDimIndex = nDataDims;
1058             nDimCount = nDataDimCount;
1059             break;
1060         case sheet::DataPilotFieldOrientation_PAGE:
1061             pDimIndex = nPageDims;
1062             nDimCount = nPageDimCount;
1063             break;
1064         default:
1065             DBG_ERROR( "ScDPSource::FillLevelList: unexpected orientation" );
1066             break;
1067     }
1068     if (!pDimIndex)
1069     {
1070         DBG_ERROR("invalid orientation");
1071         return;
1072     }
1073 
1074     ScDPDimensions* pDims = GetDimensionsObject();
1075     for (long nDim=0; nDim<nDimCount; nDim++)
1076     {
1077         ScDPDimension* pDim = pDims->getByIndex(pDimIndex[nDim]);
1078         DBG_ASSERT( pDim->getOrientation() == nOrientation, "orientations are wrong" );
1079 
1080         ScDPHierarchies* pHiers = pDim->GetHierarchiesObject();
1081         long nHierarchy = pDim->getUsedHierarchy();
1082         if ( nHierarchy >= pHiers->getCount() )
1083             nHierarchy = 0;
1084         ScDPHierarchy* pHier = pHiers->getByIndex(nHierarchy);
1085         ScDPLevels* pLevels = pHier->GetLevelsObject();
1086         long nLevCount = pLevels->getCount();
1087         for (long nLev=0; nLev<nLevCount; nLev++)
1088         {
1089             ScDPLevel* pLevel = pLevels->getByIndex(nLev);
1090             rList.Insert( pLevel, LIST_APPEND );
1091         }
1092     }
1093 }
1094 
1095 void ScDPSource::FillMemberResults()
1096 {
1097     if ( !pColResults && !pRowResults )
1098     {
1099         CreateRes_Impl();
1100 
1101         if ( bResultOverflow )      // set in CreateRes_Impl
1102         {
1103             //  no results available -> abort (leave empty)
1104             //  exception is thrown in ScDPSource::getResults
1105             return;
1106         }
1107 
1108         FillLevelList( sheet::DataPilotFieldOrientation_COLUMN, aColLevelList );
1109         long nColLevelCount = aColLevelList.Count();
1110         if (nColLevelCount)
1111         {
1112             long nColDimSize = pColResRoot->GetSize(pResData->GetColStartMeasure());
1113             pColResults = new uno::Sequence<sheet::MemberResult>[nColLevelCount];
1114             for (long i=0; i<nColLevelCount; i++)
1115                 pColResults[i].realloc(nColDimSize);
1116 
1117             // ScDPResultDimension* pColResDim = pColResRoot->GetChildDimension();
1118             // pColResDim->FillMemberResults( pColResults, 0, pResData->GetColStartMeasure() );
1119             long nPos = 0;
1120             pColResRoot->FillMemberResults( pColResults, nPos, pResData->GetColStartMeasure(),
1121                                             sal_True, NULL, NULL );
1122         }
1123 
1124         FillLevelList( sheet::DataPilotFieldOrientation_ROW, aRowLevelList );
1125         long nRowLevelCount = aRowLevelList.Count();
1126         if (nRowLevelCount)
1127         {
1128             long nRowDimSize = pRowResRoot->GetSize(pResData->GetRowStartMeasure());
1129             pRowResults = new uno::Sequence<sheet::MemberResult>[nRowLevelCount];
1130             for (long i=0; i<nRowLevelCount; i++)
1131                 pRowResults[i].realloc(nRowDimSize);
1132 
1133             // ScDPResultDimension* pRowResDim = pRowResRoot->GetChildDimension();
1134             // pRowResDim->FillMemberResults( pRowResults, 0, pResData->GetRowStartMeasure() );
1135             long nPos = 0;
1136             pRowResRoot->FillMemberResults( pRowResults, nPos, pResData->GetRowStartMeasure(),
1137                                             sal_True, NULL, NULL );
1138         }
1139     }
1140 }
1141 
1142 const uno::Sequence<sheet::MemberResult>* ScDPSource::GetMemberResults( ScDPLevel* pLevel )
1143 {
1144     FillMemberResults();
1145 
1146     long i;
1147     long nColCount = aColLevelList.Count();
1148     for (i=0; i<nColCount; i++)
1149     {
1150         ScDPLevel* pColLevel = (ScDPLevel*)aColLevelList.GetObject(i);
1151         if ( pColLevel == pLevel )
1152             return pColResults+i;
1153     }
1154     long nRowCount = aRowLevelList.Count();
1155     for (i=0; i<nRowCount; i++)
1156     {
1157         ScDPLevel* pRowLevel = (ScDPLevel*)aRowLevelList.GetObject(i);
1158         if ( pRowLevel == pLevel )
1159             return pRowResults+i;
1160     }
1161     return NULL;
1162 }
1163 
1164 // XPropertySet
1165 
1166 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPSource::getPropertySetInfo()
1167                                                         throw(uno::RuntimeException)
1168 {
1169     ScUnoGuard aGuard;
1170     using beans::PropertyAttribute::READONLY;
1171 
1172     static SfxItemPropertyMapEntry aDPSourceMap_Impl[] =
1173     {
1174         {MAP_CHAR_LEN(SC_UNO_COLGRAND), 0,  &getBooleanCppuType(),              0, 0 },
1175         {MAP_CHAR_LEN(SC_UNO_DATADESC), 0,  &getCppuType((rtl::OUString*)0),    beans::PropertyAttribute::READONLY, 0 },
1176         {MAP_CHAR_LEN(SC_UNO_IGNOREEM), 0,  &getBooleanCppuType(),              0, 0 },     // for sheet data only
1177         {MAP_CHAR_LEN(SC_UNO_REPEATIF), 0,  &getBooleanCppuType(),              0, 0 },     // for sheet data only
1178         {MAP_CHAR_LEN(SC_UNO_ROWGRAND), 0,  &getBooleanCppuType(),              0, 0 },
1179         {MAP_CHAR_LEN(SC_UNO_ROWFIELDCOUNT),    0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 },
1180         {MAP_CHAR_LEN(SC_UNO_COLUMNFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 },
1181         {MAP_CHAR_LEN(SC_UNO_DATAFIELDCOUNT),   0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 },
1182         {MAP_CHAR_LEN(SC_UNO_GRANDTOTAL_NAME),  0, &getCppuType(static_cast<OUString*>(0)), 0, 0 },
1183         {0,0,0,0,0,0}
1184     };
1185     static uno::Reference<beans::XPropertySetInfo> aRef =
1186         new SfxItemPropertySetInfo( aDPSourceMap_Impl );
1187     return aRef;
1188 }
1189 
1190 void SAL_CALL ScDPSource::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue )
1191                 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
1192                         lang::IllegalArgumentException, lang::WrappedTargetException,
1193                         uno::RuntimeException)
1194 {
1195     String aNameStr = aPropertyName;
1196     if ( aNameStr.EqualsAscii( SC_UNO_COLGRAND ) )
1197         setColumnGrand( lcl_GetBoolFromAny( aValue ) );
1198     else if ( aNameStr.EqualsAscii( SC_UNO_ROWGRAND ) )
1199         setRowGrand( lcl_GetBoolFromAny( aValue ) );
1200     else if ( aNameStr.EqualsAscii( SC_UNO_IGNOREEM ) )
1201         setIgnoreEmptyRows( lcl_GetBoolFromAny( aValue ) );
1202     else if ( aNameStr.EqualsAscii( SC_UNO_REPEATIF ) )
1203         setRepeatIfEmpty( lcl_GetBoolFromAny( aValue ) );
1204     else if (aNameStr.EqualsAscii(SC_UNO_GRANDTOTAL_NAME))
1205     {
1206         OUString aName;
1207         if (aValue >>= aName)
1208             mpGrandTotalName.reset(new OUString(aName));
1209     }
1210     else
1211     {
1212         DBG_ERROR("unknown property");
1213         //! THROW( UnknownPropertyException() );
1214     }
1215 }
1216 
1217 uno::Any SAL_CALL ScDPSource::getPropertyValue( const rtl::OUString& aPropertyName )
1218                 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
1219                         uno::RuntimeException)
1220 {
1221     uno::Any aRet;
1222     String aNameStr = aPropertyName;
1223     if ( aNameStr.EqualsAscii( SC_UNO_COLGRAND ) )
1224         lcl_SetBoolInAny( aRet, getColumnGrand() );
1225     else if ( aNameStr.EqualsAscii( SC_UNO_ROWGRAND ) )
1226         lcl_SetBoolInAny( aRet, getRowGrand() );
1227     else if ( aNameStr.EqualsAscii( SC_UNO_IGNOREEM ) )
1228         lcl_SetBoolInAny( aRet, getIgnoreEmptyRows() );
1229     else if ( aNameStr.EqualsAscii( SC_UNO_REPEATIF ) )
1230         lcl_SetBoolInAny( aRet, getRepeatIfEmpty() );
1231     else if ( aNameStr.EqualsAscii( SC_UNO_DATADESC ) )             // read-only
1232         aRet <<= rtl::OUString( getDataDescription() );
1233     else if ( aNameStr.EqualsAscii( SC_UNO_ROWFIELDCOUNT ) )        // read-only
1234         aRet <<= static_cast<sal_Int32>(nRowDimCount);
1235     else if ( aNameStr.EqualsAscii( SC_UNO_COLUMNFIELDCOUNT ) )     // read-only
1236         aRet <<= static_cast<sal_Int32>(nColDimCount);
1237     else if ( aNameStr.EqualsAscii( SC_UNO_DATAFIELDCOUNT ) )       // read-only
1238         aRet <<= static_cast<sal_Int32>(nDataDimCount);
1239     else if (aNameStr.EqualsAscii(SC_UNO_GRANDTOTAL_NAME))
1240     {
1241         if (mpGrandTotalName.get())
1242             aRet <<= *mpGrandTotalName;
1243     }
1244     else
1245     {
1246         DBG_ERROR("unknown property");
1247         //! THROW( UnknownPropertyException() );
1248     }
1249     return aRet;
1250 }
1251 
1252 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPSource )
1253 
1254 // -----------------------------------------------------------------------
1255 
1256 ScDPDimensions::ScDPDimensions( ScDPSource* pSrc ) :
1257     pSource( pSrc ),
1258     ppDims( NULL )
1259 {
1260     //! hold pSource
1261 
1262     // include data layout dimension and duplicated dimensions
1263     nDimCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount();
1264 }
1265 
1266 ScDPDimensions::~ScDPDimensions()
1267 {
1268     //! release pSource
1269 
1270     if (ppDims)
1271     {
1272         for (long i=0; i<nDimCount; i++)
1273             if ( ppDims[i] )
1274                 ppDims[i]->release();           // ref-counted
1275         delete[] ppDims;
1276     }
1277 }
1278 
1279 void ScDPDimensions::CountChanged()
1280 {
1281     // include data layout dimension and duplicated dimensions
1282     long nNewCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount();
1283     if ( ppDims )
1284     {
1285         long i;
1286         long nCopy = Min( nNewCount, nDimCount );
1287         ScDPDimension** ppNew = new ScDPDimension*[nNewCount];
1288 
1289         for (i=0; i<nCopy; i++)             // copy existing dims
1290             ppNew[i] = ppDims[i];
1291         for (i=nCopy; i<nNewCount; i++)     // clear additional pointers
1292             ppNew[i] = NULL;
1293         for (i=nCopy; i<nDimCount; i++)     // delete old dims if count is decreased
1294             if ( ppDims[i] )
1295                 ppDims[i]->release();       // ref-counted
1296 
1297         delete[] ppDims;
1298         ppDims = ppNew;
1299     }
1300     nDimCount = nNewCount;
1301 }
1302 
1303 // very simple XNameAccess implementation using getCount/getByIndex
1304 
1305 uno::Any SAL_CALL ScDPDimensions::getByName( const rtl::OUString& aName )
1306             throw(container::NoSuchElementException,
1307                     lang::WrappedTargetException, uno::RuntimeException)
1308 {
1309     long nCount = getCount();
1310     for (long i=0; i<nCount; i++)
1311         if ( getByIndex(i)->getName() == aName )
1312         {
1313             uno::Reference<container::XNamed> xNamed = getByIndex(i);
1314             uno::Any aRet;
1315             aRet <<= xNamed;
1316             return aRet;
1317         }
1318 
1319     throw container::NoSuchElementException();
1320 //    return uno::Any();
1321 }
1322 
1323 uno::Sequence<rtl::OUString> SAL_CALL ScDPDimensions::getElementNames() throw(uno::RuntimeException)
1324 {
1325     long nCount = getCount();
1326     uno::Sequence<rtl::OUString> aSeq(nCount);
1327     rtl::OUString* pArr = aSeq.getArray();
1328     for (long i=0; i<nCount; i++)
1329         pArr[i] = getByIndex(i)->getName();
1330     return aSeq;
1331 }
1332 
1333 sal_Bool SAL_CALL ScDPDimensions::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
1334 {
1335     long nCount = getCount();
1336     for (long i=0; i<nCount; i++)
1337         if ( getByIndex(i)->getName() == aName )
1338             return sal_True;
1339     return sal_False;
1340 }
1341 
1342 uno::Type SAL_CALL ScDPDimensions::getElementType() throw(uno::RuntimeException)
1343 {
1344     return getCppuType((uno::Reference<container::XNamed>*)0);
1345 }
1346 
1347 sal_Bool SAL_CALL ScDPDimensions::hasElements() throw(uno::RuntimeException)
1348 {
1349     return ( getCount() > 0 );
1350 }
1351 
1352 // end of XNameAccess implementation
1353 
1354 long ScDPDimensions::getCount() const
1355 {
1356     //  in tabular data, every column of source data is a dimension
1357 
1358     return nDimCount;
1359 }
1360 
1361 ScDPDimension* ScDPDimensions::getByIndex(long nIndex) const
1362 {
1363     if ( nIndex >= 0 && nIndex < nDimCount )
1364     {
1365         if ( !ppDims )
1366         {
1367             ((ScDPDimensions*)this)->ppDims = new ScDPDimension*[nDimCount];
1368             for (long i=0; i<nDimCount; i++)
1369                 ppDims[i] = NULL;
1370         }
1371         if ( !ppDims[nIndex] )
1372         {
1373             ppDims[nIndex] = new ScDPDimension( pSource, nIndex );
1374             ppDims[nIndex]->acquire();      // ref-counted
1375         }
1376 
1377         return ppDims[nIndex];
1378     }
1379 
1380     return NULL;    //! exception?
1381 }
1382 
1383 // -----------------------------------------------------------------------
1384 
1385 ScDPDimension::ScDPDimension( ScDPSource* pSrc, long nD ) :
1386     pSource( pSrc ),
1387     nDim( nD ),
1388     pHierarchies( NULL ),
1389     nUsedHier( 0 ),
1390     nFunction( SUBTOTAL_FUNC_SUM ),     // sum is default
1391     mpLayoutName(NULL),
1392     mpSubtotalName(NULL),
1393     nSourceDim( -1 ),
1394     bHasSelectedPage( sal_False ),
1395     pSelectedData( NULL ),
1396     mbHasHiddenMember(false)
1397 {
1398     //! hold pSource
1399 }
1400 
1401 ScDPDimension::~ScDPDimension()
1402 {
1403     //! release pSource
1404 
1405     if ( pHierarchies )
1406         pHierarchies->release();    // ref-counted
1407 
1408     delete pSelectedData;
1409 }
1410 
1411 ScDPHierarchies* ScDPDimension::GetHierarchiesObject()
1412 {
1413     if (!pHierarchies)
1414     {
1415         pHierarchies = new ScDPHierarchies( pSource, nDim );
1416         pHierarchies->acquire();        // ref-counted
1417     }
1418     return pHierarchies;
1419 }
1420 
1421 const rtl::OUString* ScDPDimension::GetLayoutName() const
1422 {
1423     return mpLayoutName.get();
1424 }
1425 
1426 const rtl::OUString* ScDPDimension::GetSubtotalName() const
1427 {
1428     return mpSubtotalName.get();
1429 }
1430 
1431 uno::Reference<container::XNameAccess> SAL_CALL ScDPDimension::getHierarchies()
1432                                                     throw(uno::RuntimeException)
1433 {
1434     return GetHierarchiesObject();
1435 }
1436 
1437 ::rtl::OUString SAL_CALL ScDPDimension::getName() throw(uno::RuntimeException)
1438 {
1439     if (aName.Len())
1440         return aName;
1441     else
1442         return pSource->GetData()->getDimensionName( nDim );
1443 }
1444 
1445 void SAL_CALL ScDPDimension::setName( const ::rtl::OUString& rNewName ) throw(uno::RuntimeException)
1446 {
1447     //  used after cloning
1448     aName = String( rNewName );
1449 }
1450 
1451 sal_uInt16 ScDPDimension::getOrientation() const
1452 {
1453     return pSource->GetOrientation( nDim );
1454 }
1455 
1456 void ScDPDimension::setOrientation(sal_uInt16 nNew)
1457 {
1458     pSource->SetOrientation( nDim, nNew );
1459 }
1460 
1461 long ScDPDimension::getPosition() const
1462 {
1463     return pSource->GetPosition( nDim );
1464 }
1465 
1466 void ScDPDimension::setPosition(long /* nNew */)
1467 {
1468     //! ...
1469 }
1470 
1471 sal_Bool ScDPDimension::getIsDataLayoutDimension() const
1472 {
1473     return pSource->GetData()->getIsDataLayoutDimension( nDim );
1474 }
1475 
1476 sal_uInt16 ScDPDimension::getFunction() const
1477 {
1478     return nFunction;
1479 }
1480 
1481 void ScDPDimension::setFunction(sal_uInt16 nNew)
1482 {
1483     nFunction = nNew;
1484 }
1485 
1486 long ScDPDimension::getUsedHierarchy() const
1487 {
1488     return nUsedHier;
1489 }
1490 
1491 void ScDPDimension::setUsedHierarchy(long /* nNew */)
1492 {
1493     // #i52547# don't use the incomplete date hierarchy implementation - ignore the call
1494     // nUsedHier = nNew;
1495 }
1496 
1497 ScDPDimension* ScDPDimension::CreateCloneObject()
1498 {
1499     DBG_ASSERT( nSourceDim < 0, "recursive duplicate - not implemented" );
1500 
1501     //! set new name here, or temporary name ???
1502     String aNewName = aName;
1503 
1504     ScDPDimension* pNew = pSource->AddDuplicated( nDim, aNewName );
1505 
1506     pNew->aName = aNewName;             //! here or in source?
1507     pNew->nSourceDim = nDim;            //! recursive?
1508 
1509     return pNew;
1510 }
1511 
1512 uno::Reference<util::XCloneable> SAL_CALL ScDPDimension::createClone() throw(uno::RuntimeException)
1513 {
1514     return CreateCloneObject();
1515 }
1516 
1517 sal_Bool ScDPDimension::isDuplicated() const
1518 {
1519     return (nSourceDim >= 0);
1520 }
1521 
1522 const sheet::DataPilotFieldReference& ScDPDimension::GetReferenceValue() const
1523 {
1524     return aReferenceValue;
1525 }
1526 
1527 const ScDPItemData& ScDPDimension::GetSelectedData()
1528 {
1529     if ( !pSelectedData )
1530     {
1531         // find the named member to initialize pSelectedData from it, with name and value
1532 
1533         long nLevel = 0;        // same as in ScDPObject::FillPageList
1534 
1535         long nHierarchy = getUsedHierarchy();
1536         if ( nHierarchy >= GetHierarchiesObject()->getCount() )
1537             nHierarchy = 0;
1538         ScDPLevels* pLevels = GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
1539         long nLevCount = pLevels->getCount();
1540         if ( nLevel < nLevCount )
1541         {
1542             ScDPMembers* pMembers = pLevels->getByIndex(nLevel)->GetMembersObject();
1543 
1544             //! merge with ScDPMembers::getByName
1545             long nCount = pMembers->getCount();
1546             for (long i=0; i<nCount && !pSelectedData; i++)
1547             {
1548                 ScDPMember* pMember = pMembers->getByIndex(i);
1549                 if ( pMember->GetNameStr() == aSelectedPage )
1550                 {
1551                     pSelectedData = new ScDPItemData();
1552                     pMember->FillItemData( *pSelectedData );
1553                 }
1554             }
1555         }
1556 
1557         if ( !pSelectedData )
1558             pSelectedData = new ScDPItemData( aSelectedPage, 0.0, sal_False );      // default - name only
1559     }
1560 
1561     return *pSelectedData;
1562 }
1563 
1564 //UNUSED2009-05 sal_Bool ScDPDimension::IsValidPage( const ScDPItemData& rData )
1565 //UNUSED2009-05 {
1566 //UNUSED2009-05     if ( bHasSelectedPage )
1567 //UNUSED2009-05         return rData.IsCaseInsEqual( GetSelectedData() );
1568 //UNUSED2009-05
1569 //UNUSED2009-05     return sal_True;        // no selection -> all data
1570 //UNUSED2009-05 }
1571 
1572 sal_Bool ScDPDimension::IsVisible( const ScDPItemData& rData )
1573 {
1574     if( ScDPMembers* pMembers = this->GetHierarchiesObject()->getByIndex(0)->
1575         GetLevelsObject()->getByIndex(0)->GetMembersObject() )
1576     {
1577         for( long i = pMembers->getCount()-1; i>=0; i-- )
1578             if( ScDPMember *pDPMbr = pMembers->getByIndex( i ) )
1579                 if( rData.IsCaseInsEqual( pDPMbr->GetItemData() ) && !pDPMbr->getIsVisible() )
1580                     return sal_False;
1581     }
1582 
1583     return sal_True;
1584 }
1585 // XPropertySet
1586 
1587 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPDimension::getPropertySetInfo()
1588                                                         throw(uno::RuntimeException)
1589 {
1590     ScUnoGuard aGuard;
1591 
1592     static SfxItemPropertyMapEntry aDPDimensionMap_Impl[] =
1593     {
1594         {MAP_CHAR_LEN(SC_UNO_FILTER),   0,  &getCppuType((uno::Sequence<sheet::TableFilterField>*)0), 0, 0 },
1595         {MAP_CHAR_LEN(SC_UNO_FLAGS),    0,  &getCppuType((sal_Int32*)0),                beans::PropertyAttribute::READONLY, 0 },
1596         {MAP_CHAR_LEN(SC_UNO_FUNCTION), 0,  &getCppuType((sheet::GeneralFunction*)0),   0, 0 },
1597         {MAP_CHAR_LEN(SC_UNO_ISDATALA), 0,  &getBooleanCppuType(),                      beans::PropertyAttribute::READONLY, 0 },
1598         {MAP_CHAR_LEN(SC_UNO_NUMBERFO), 0,  &getCppuType((sal_Int32*)0),                beans::PropertyAttribute::READONLY, 0 },
1599         {MAP_CHAR_LEN(SC_UNO_ORIENTAT), 0,  &getCppuType((sheet::DataPilotFieldOrientation*)0), 0, 0 },
1600         {MAP_CHAR_LEN(SC_UNO_ORIGINAL), 0,  &getCppuType((uno::Reference<container::XNamed>*)0), beans::PropertyAttribute::READONLY, 0 },
1601         {MAP_CHAR_LEN(SC_UNO_POSITION), 0,  &getCppuType((sal_Int32*)0),                0, 0 },
1602         {MAP_CHAR_LEN(SC_UNO_REFVALUE), 0,  &getCppuType((sheet::DataPilotFieldReference*)0), 0, 0 },
1603         {MAP_CHAR_LEN(SC_UNO_USEDHIER), 0,  &getCppuType((sal_Int32*)0),                0, 0 },
1604         {MAP_CHAR_LEN(SC_UNO_LAYOUTNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 },
1605         {MAP_CHAR_LEN(SC_UNO_FIELD_SUBTOTALNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 },
1606         {MAP_CHAR_LEN(SC_UNO_HAS_HIDDEN_MEMBER), 0, &getBooleanCppuType(), 0, 0 },
1607         {0,0,0,0,0,0}
1608     };
1609     static uno::Reference<beans::XPropertySetInfo> aRef =
1610         new SfxItemPropertySetInfo( aDPDimensionMap_Impl );
1611     return aRef;
1612 }
1613 
1614 void SAL_CALL ScDPDimension::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue )
1615                 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
1616                         lang::IllegalArgumentException, lang::WrappedTargetException,
1617                         uno::RuntimeException)
1618 {
1619     String aNameStr = aPropertyName;
1620     if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) )
1621     {
1622         sal_Int32 nInt = 0;
1623         if (aValue >>= nInt)
1624             setPosition( nInt );
1625     }
1626     else if ( aNameStr.EqualsAscii( SC_UNO_USEDHIER ) )
1627     {
1628         sal_Int32 nInt = 0;
1629         if (aValue >>= nInt)
1630             setUsedHierarchy( nInt );
1631     }
1632     else if ( aNameStr.EqualsAscii( SC_UNO_ORIENTAT ) )
1633     {
1634         sheet::DataPilotFieldOrientation eEnum;
1635         if (aValue >>= eEnum)
1636             setOrientation( sal::static_int_cast<sal_uInt16>(eEnum) );
1637     }
1638     else if ( aNameStr.EqualsAscii( SC_UNO_FUNCTION ) )
1639     {
1640         sheet::GeneralFunction eEnum;
1641         if (aValue >>= eEnum)
1642             setFunction( sal::static_int_cast<sal_uInt16>(eEnum) );
1643     }
1644     else if ( aNameStr.EqualsAscii( SC_UNO_REFVALUE ) )
1645         aValue >>= aReferenceValue;
1646     else if ( aNameStr.EqualsAscii( SC_UNO_FILTER ) )
1647     {
1648         sal_Bool bDone = sal_False;
1649         uno::Sequence<sheet::TableFilterField> aSeq;
1650         if (aValue >>= aSeq)
1651         {
1652             sal_Int32 nLength = aSeq.getLength();
1653             if ( nLength == 0 )
1654             {
1655                 aSelectedPage.Erase();
1656                 bHasSelectedPage = sal_False;
1657                 bDone = sal_True;
1658             }
1659             else if ( nLength == 1 )
1660             {
1661                 const sheet::TableFilterField& rField = aSeq[0];
1662                 if ( rField.Field == 0 && rField.Operator == sheet::FilterOperator_EQUAL && !rField.IsNumeric )
1663                 {
1664                     aSelectedPage = rField.StringValue;
1665                     bHasSelectedPage = sal_True;
1666                     bDone = sal_True;
1667                 }
1668             }
1669         }
1670         if ( !bDone )
1671         {
1672             DBG_ERROR("Filter property is not a single string");
1673             throw lang::IllegalArgumentException();
1674         }
1675         DELETEZ( pSelectedData );       // invalid after changing aSelectedPage
1676     }
1677     else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
1678     {
1679         OUString aTmpName;
1680         if (aValue >>= aTmpName)
1681             mpLayoutName.reset(new OUString(aTmpName));
1682     }
1683     else if (aNameStr.EqualsAscii(SC_UNO_FIELD_SUBTOTALNAME))
1684     {
1685         OUString aTmpName;
1686         if (aValue >>= aTmpName)
1687             mpSubtotalName.reset(new OUString(aTmpName));
1688     }
1689     else if (aNameStr.EqualsAscii(SC_UNO_HAS_HIDDEN_MEMBER))
1690         aValue >>= mbHasHiddenMember;
1691     else
1692     {
1693         DBG_ERROR("unknown property");
1694         //! THROW( UnknownPropertyException() );
1695     }
1696 }
1697 
1698 uno::Any SAL_CALL ScDPDimension::getPropertyValue( const rtl::OUString& aPropertyName )
1699                 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
1700                         uno::RuntimeException)
1701 {
1702     uno::Any aRet;
1703     String aNameStr = aPropertyName;
1704     if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) )
1705         aRet <<= (sal_Int32) getPosition();
1706     else if ( aNameStr.EqualsAscii( SC_UNO_USEDHIER ) )
1707         aRet <<= (sal_Int32) getUsedHierarchy();
1708     else if ( aNameStr.EqualsAscii( SC_UNO_ORIENTAT ) )
1709     {
1710         sheet::DataPilotFieldOrientation eVal = (sheet::DataPilotFieldOrientation)getOrientation();
1711         aRet <<= eVal;
1712     }
1713     else if ( aNameStr.EqualsAscii( SC_UNO_FUNCTION ) )
1714     {
1715         sheet::GeneralFunction eVal = (sheet::GeneralFunction)getFunction();
1716         aRet <<= eVal;
1717     }
1718     else if ( aNameStr.EqualsAscii( SC_UNO_REFVALUE ) )
1719         aRet <<= aReferenceValue;
1720     else if ( aNameStr.EqualsAscii( SC_UNO_ISDATALA ) )                 // read-only properties
1721         lcl_SetBoolInAny( aRet, getIsDataLayoutDimension() );
1722     else if ( aNameStr.EqualsAscii( SC_UNO_NUMBERFO ) )
1723     {
1724         sal_Int32 nFormat = 0;
1725         sheet::GeneralFunction eFunc = (sheet::GeneralFunction)getFunction();
1726         // #i63745# don't use source format for "count"
1727         if ( eFunc != sheet::GeneralFunction_COUNT && eFunc != sheet::GeneralFunction_COUNTNUMS )
1728             nFormat = pSource->GetData()->GetNumberFormat( ( nSourceDim >= 0 ) ? nSourceDim : nDim );
1729 
1730         switch ( aReferenceValue.ReferenceType )
1731         {
1732         case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE:
1733         case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
1734         case sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE:
1735         case sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE:
1736         case sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE:
1737             nFormat = pSource->GetData()->GetNumberFormatByIdx( (NfIndexTableOffset)NF_PERCENT_DEC2 );
1738             break;
1739         case sheet::DataPilotFieldReferenceType::INDEX:
1740             nFormat = pSource->GetData()->GetNumberFormatByIdx( (NfIndexTableOffset)NF_NUMBER_SYSTEM );
1741             break;
1742         default:
1743             break;
1744         }
1745 
1746         aRet <<= nFormat;
1747     }
1748     else if ( aNameStr.EqualsAscii( SC_UNO_ORIGINAL ) )
1749     {
1750         uno::Reference<container::XNamed> xOriginal;
1751         if (nSourceDim >= 0)
1752             xOriginal = pSource->GetDimensionsObject()->getByIndex(nSourceDim);
1753         aRet <<= xOriginal;
1754     }
1755     else if ( aNameStr.EqualsAscii( SC_UNO_FILTER ) )
1756     {
1757         if ( bHasSelectedPage )
1758         {
1759             // single filter field: first field equal to selected string
1760             sheet::TableFilterField aField( sheet::FilterConnection_AND, 0,
1761                     sheet::FilterOperator_EQUAL, sal_False, 0.0, aSelectedPage );
1762             aRet <<= uno::Sequence<sheet::TableFilterField>( &aField, 1 );
1763         }
1764         else
1765             aRet <<= uno::Sequence<sheet::TableFilterField>(0);
1766     }
1767     else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
1768         aRet <<= mpLayoutName.get() ? *mpLayoutName : OUString::createFromAscii("");
1769     else if (aNameStr.EqualsAscii(SC_UNO_FIELD_SUBTOTALNAME))
1770         aRet <<= mpSubtotalName.get() ? *mpSubtotalName : OUString::createFromAscii("");
1771     else if (aNameStr.EqualsAscii(SC_UNO_HAS_HIDDEN_MEMBER))
1772         aRet <<= mbHasHiddenMember;
1773     else if (aNameStr.EqualsAscii(SC_UNO_FLAGS))
1774     {
1775         sal_Int32 nFlags = 0;       // tabular data: all orientations are possible
1776         aRet <<= nFlags;
1777     }
1778     else
1779     {
1780         DBG_ERROR("unknown property");
1781         //! THROW( UnknownPropertyException() );
1782     }
1783     return aRet;
1784 }
1785 
1786 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPDimension )
1787 
1788 // -----------------------------------------------------------------------
1789 
1790 ScDPHierarchies::ScDPHierarchies( ScDPSource* pSrc, long nD ) :
1791     pSource( pSrc ),
1792     nDim( nD ),
1793     ppHiers( NULL )
1794 {
1795     //! hold pSource
1796 
1797 #if 0
1798     //  date columns have 3 hierarchies (flat/quarter/week), other columns only one
1799     long nSrcDim = pSource->GetSourceDim( nDim );
1800     if ( pSource->IsDateDimension( nSrcDim ) )
1801         nHierCount = SC_DAPI_DATE_HIERARCHIES;
1802     else
1803         nHierCount = 1;
1804 #endif
1805 
1806     // #i52547# don't offer the incomplete date hierarchy implementation
1807     nHierCount = 1;
1808 }
1809 
1810 ScDPHierarchies::~ScDPHierarchies()
1811 {
1812     //! release pSource
1813 
1814     if (ppHiers)
1815     {
1816         for (long i=0; i<nHierCount; i++)
1817             if ( ppHiers[i] )
1818                 ppHiers[i]->release();      // ref-counted
1819         delete[] ppHiers;
1820     }
1821 }
1822 
1823 // very simple XNameAccess implementation using getCount/getByIndex
1824 
1825 uno::Any SAL_CALL ScDPHierarchies::getByName( const rtl::OUString& aName )
1826             throw(container::NoSuchElementException,
1827                     lang::WrappedTargetException, uno::RuntimeException)
1828 {
1829     long nCount = getCount();
1830     for (long i=0; i<nCount; i++)
1831         if ( getByIndex(i)->getName() == aName )
1832         {
1833             uno::Reference<container::XNamed> xNamed = getByIndex(i);
1834             uno::Any aRet;
1835             aRet <<= xNamed;
1836             return aRet;
1837         }
1838 
1839     throw container::NoSuchElementException();
1840 //    return uno::Any();
1841 }
1842 
1843 uno::Sequence<rtl::OUString> SAL_CALL ScDPHierarchies::getElementNames() throw(uno::RuntimeException)
1844 {
1845     long nCount = getCount();
1846     uno::Sequence<rtl::OUString> aSeq(nCount);
1847     rtl::OUString* pArr = aSeq.getArray();
1848     for (long i=0; i<nCount; i++)
1849         pArr[i] = getByIndex(i)->getName();
1850     return aSeq;
1851 }
1852 
1853 sal_Bool SAL_CALL ScDPHierarchies::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
1854 {
1855     long nCount = getCount();
1856     for (long i=0; i<nCount; i++)
1857         if ( getByIndex(i)->getName() == aName )
1858             return sal_True;
1859     return sal_False;
1860 }
1861 
1862 uno::Type SAL_CALL ScDPHierarchies::getElementType() throw(uno::RuntimeException)
1863 {
1864     return getCppuType((uno::Reference<container::XNamed>*)0);
1865 }
1866 
1867 sal_Bool SAL_CALL ScDPHierarchies::hasElements() throw(uno::RuntimeException)
1868 {
1869     return ( getCount() > 0 );
1870 }
1871 
1872 // end of XNameAccess implementation
1873 
1874 long ScDPHierarchies::getCount() const
1875 {
1876     return nHierCount;
1877 }
1878 
1879 ScDPHierarchy* ScDPHierarchies::getByIndex(long nIndex) const
1880 {
1881     //  pass hierarchy index to new object in case the implementation
1882     //  will be extended to more than one hierarchy
1883 
1884     if ( nIndex >= 0 && nIndex < nHierCount )
1885     {
1886         if ( !ppHiers )
1887         {
1888             ((ScDPHierarchies*)this)->ppHiers = new ScDPHierarchy*[nHierCount];
1889             for (long i=0; i<nHierCount; i++)
1890                 ppHiers[i] = NULL;
1891         }
1892         if ( !ppHiers[nIndex] )
1893         {
1894             ppHiers[nIndex] = new ScDPHierarchy( pSource, nDim, nIndex );
1895             ppHiers[nIndex]->acquire();         // ref-counted
1896         }
1897 
1898         return ppHiers[nIndex];
1899     }
1900 
1901     return NULL;    //! exception?
1902 }
1903 
1904 // -----------------------------------------------------------------------
1905 
1906 ScDPHierarchy::ScDPHierarchy( ScDPSource* pSrc, long nD, long nH ) :
1907     pSource( pSrc ),
1908     nDim( nD ),
1909     nHier( nH ),
1910     pLevels( NULL )
1911 {
1912     //! hold pSource
1913 }
1914 
1915 ScDPHierarchy::~ScDPHierarchy()
1916 {
1917     //! release pSource
1918 
1919     if (pLevels)
1920         pLevels->release();     // ref-counted
1921 }
1922 
1923 ScDPLevels* ScDPHierarchy::GetLevelsObject()
1924 {
1925     if (!pLevels)
1926     {
1927         pLevels = new ScDPLevels( pSource, nDim, nHier );
1928         pLevels->acquire();     // ref-counted
1929     }
1930     return pLevels;
1931 }
1932 
1933 uno::Reference<container::XNameAccess> SAL_CALL ScDPHierarchy::getLevels()
1934                                                     throw(uno::RuntimeException)
1935 {
1936     return GetLevelsObject();
1937 }
1938 
1939 ::rtl::OUString SAL_CALL ScDPHierarchy::getName() throw(uno::RuntimeException)
1940 {
1941     String aRet;        //! globstr-ID !!!!
1942     switch (nHier)
1943     {
1944         case SC_DAPI_HIERARCHY_FLAT:
1945             aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("flat"));
1946             break;  //! name ???????
1947         case SC_DAPI_HIERARCHY_QUARTER:
1948             aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Quarter"));
1949             break;  //! name ???????
1950         case SC_DAPI_HIERARCHY_WEEK:
1951             aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Week"));
1952             break;  //! name ???????
1953         default:
1954             DBG_ERROR( "ScDPHierarchy::getName: unexpected hierarchy" );
1955             break;
1956     }
1957     return aRet;
1958 }
1959 
1960 void SAL_CALL ScDPHierarchy::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException)
1961 {
1962     DBG_ERROR("not implemented");       //! exception?
1963 }
1964 
1965 // -----------------------------------------------------------------------
1966 
1967 ScDPLevels::ScDPLevels( ScDPSource* pSrc, long nD, long nH ) :
1968     pSource( pSrc ),
1969     nDim( nD ),
1970     nHier( nH ),
1971     ppLevs( NULL )
1972 {
1973     //! hold pSource
1974 
1975     //  text columns have only one level
1976 
1977     long nSrcDim = pSource->GetSourceDim( nDim );
1978     if ( pSource->IsDateDimension( nSrcDim ) )
1979     {
1980         switch ( nHier )
1981         {
1982             case SC_DAPI_HIERARCHY_FLAT:    nLevCount = SC_DAPI_FLAT_LEVELS;    break;
1983             case SC_DAPI_HIERARCHY_QUARTER: nLevCount = SC_DAPI_QUARTER_LEVELS; break;
1984             case SC_DAPI_HIERARCHY_WEEK:    nLevCount = SC_DAPI_WEEK_LEVELS;    break;
1985             default:
1986                 DBG_ERROR("wrong hierarchy");
1987                 nLevCount = 0;
1988         }
1989     }
1990     else
1991         nLevCount = 1;
1992 }
1993 
1994 ScDPLevels::~ScDPLevels()
1995 {
1996     //! release pSource
1997 
1998     if (ppLevs)
1999     {
2000         for (long i=0; i<nLevCount; i++)
2001             if ( ppLevs[i] )
2002                 ppLevs[i]->release();   // ref-counted
2003         delete[] ppLevs;
2004     }
2005 }
2006 
2007 // very simple XNameAccess implementation using getCount/getByIndex
2008 
2009 uno::Any SAL_CALL ScDPLevels::getByName( const rtl::OUString& aName )
2010             throw(container::NoSuchElementException,
2011                     lang::WrappedTargetException, uno::RuntimeException)
2012 {
2013     long nCount = getCount();
2014     for (long i=0; i<nCount; i++)
2015         if ( getByIndex(i)->getName() == aName )
2016         {
2017             uno::Reference<container::XNamed> xNamed = getByIndex(i);
2018             uno::Any aRet;
2019             aRet <<= xNamed;
2020             return aRet;
2021         }
2022 
2023     throw container::NoSuchElementException();
2024 //    return uno::Any();
2025 }
2026 
2027 uno::Sequence<rtl::OUString> SAL_CALL ScDPLevels::getElementNames() throw(uno::RuntimeException)
2028 {
2029     long nCount = getCount();
2030     uno::Sequence<rtl::OUString> aSeq(nCount);
2031     rtl::OUString* pArr = aSeq.getArray();
2032     for (long i=0; i<nCount; i++)
2033         pArr[i] = getByIndex(i)->getName();
2034     return aSeq;
2035 }
2036 
2037 sal_Bool SAL_CALL ScDPLevels::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
2038 {
2039     long nCount = getCount();
2040     for (long i=0; i<nCount; i++)
2041         if ( getByIndex(i)->getName() == aName )
2042             return sal_True;
2043     return sal_False;
2044 }
2045 
2046 uno::Type SAL_CALL ScDPLevels::getElementType() throw(uno::RuntimeException)
2047 {
2048     return getCppuType((uno::Reference<container::XNamed>*)0);
2049 }
2050 
2051 sal_Bool SAL_CALL ScDPLevels::hasElements() throw(uno::RuntimeException)
2052 {
2053     return ( getCount() > 0 );
2054 }
2055 
2056 // end of XNameAccess implementation
2057 
2058 long ScDPLevels::getCount() const
2059 {
2060     return nLevCount;
2061 }
2062 
2063 ScDPLevel* ScDPLevels::getByIndex(long nIndex) const
2064 {
2065     if ( nIndex >= 0 && nIndex < nLevCount )
2066     {
2067         if ( !ppLevs )
2068         {
2069             ((ScDPLevels*)this)->ppLevs = new ScDPLevel*[nLevCount];
2070             for (long i=0; i<nLevCount; i++)
2071                 ppLevs[i] = NULL;
2072         }
2073         if ( !ppLevs[nIndex] )
2074         {
2075             ppLevs[nIndex] = new ScDPLevel( pSource, nDim, nHier, nIndex );
2076             ppLevs[nIndex]->acquire();      // ref-counted
2077         }
2078 
2079         return ppLevs[nIndex];
2080     }
2081 
2082     return NULL;    //! exception?
2083 }
2084 
2085 // -----------------------------------------------------------------------
2086 
2087 class ScDPGlobalMembersOrder
2088 {
2089     ScDPLevel&  rLevel;
2090     sal_Bool        bAscending;
2091 
2092 public:
2093             ScDPGlobalMembersOrder( ScDPLevel& rLev, sal_Bool bAsc ) :
2094                 rLevel(rLev),
2095                 bAscending(bAsc)
2096             {}
2097             ~ScDPGlobalMembersOrder() {}
2098 
2099     sal_Bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
2100 };
2101 
2102 sal_Bool ScDPGlobalMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
2103 {
2104     sal_Int32 nCompare = 0;
2105     // seems that some ::std::sort() implementations pass the same index twice
2106     if( nIndex1 != nIndex2 )
2107     {
2108         ScDPMembers* pMembers = rLevel.GetMembersObject();
2109         ScDPMember* pMember1 = pMembers->getByIndex(nIndex1);
2110         ScDPMember* pMember2 = pMembers->getByIndex(nIndex2);
2111         nCompare = pMember1->Compare( *pMember2 );
2112     }
2113     return bAscending ? (nCompare < 0) : (nCompare > 0);
2114 }
2115 
2116 // -----------------------------------------------------------------------
2117 
2118 ScDPLevel::ScDPLevel( ScDPSource* pSrc, long nD, long nH, long nL ) :
2119     pSource( pSrc ),
2120     nDim( nD ),
2121     nHier( nH ),
2122     nLev( nL ),
2123     pMembers( NULL ),
2124     bShowEmpty( sal_False ),
2125     aSortInfo( EMPTY_STRING, sal_True, sheet::DataPilotFieldSortMode::NAME ),   // default: sort by name
2126     nSortMeasure( 0 ),
2127     nAutoMeasure( 0 ),
2128     bEnableLayout( sal_False )
2129 {
2130     //! hold pSource
2131     //  aSubTotals is empty
2132 }
2133 
2134 ScDPLevel::~ScDPLevel()
2135 {
2136     //! release pSource
2137 
2138     if ( pMembers )
2139         pMembers->release();    // ref-counted
2140 }
2141 
2142 void ScDPLevel::EvaluateSortOrder()
2143 {
2144     switch (aSortInfo.Mode)
2145     {
2146         case sheet::DataPilotFieldSortMode::DATA:
2147             {
2148                 // find index of measure (index among data dimensions)
2149 
2150                 String aDataFieldName = aSortInfo.Field;
2151                 long nMeasureCount = pSource->GetDataDimensionCount();
2152                 for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++)
2153                 {
2154                     if ( pSource->GetDataDimName(nMeasure) == aDataFieldName )
2155                     {
2156                         nSortMeasure = nMeasure;
2157                         break;
2158                     }
2159                 }
2160 
2161                 //! error if not found?
2162             }
2163             break;
2164         case sheet::DataPilotFieldSortMode::MANUAL:
2165         case sheet::DataPilotFieldSortMode::NAME:
2166             {
2167                 ScDPMembers* pLocalMembers = GetMembersObject();
2168                 long nCount = pLocalMembers->getCount();
2169 
2170 //                DBG_ASSERT( aGlobalOrder.empty(), "sort twice?" );
2171                 aGlobalOrder.resize( nCount );
2172                 for (long nPos=0; nPos<nCount; nPos++)
2173                     aGlobalOrder[nPos] = nPos;
2174 
2175                 // allow manual or name (manual is always ascending)
2176                 sal_Bool bAscending = ( aSortInfo.Mode == sheet::DataPilotFieldSortMode::MANUAL || aSortInfo.IsAscending );
2177                 ScDPGlobalMembersOrder aComp( *this, bAscending );
2178                 ::std::sort( aGlobalOrder.begin(), aGlobalOrder.end(), aComp );
2179             }
2180             break;
2181     }
2182 
2183     if ( aAutoShowInfo.IsEnabled )
2184     {
2185         // find index of measure (index among data dimensions)
2186 
2187         String aDataFieldName = aAutoShowInfo.DataField;
2188         long nMeasureCount = pSource->GetDataDimensionCount();
2189         for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++)
2190         {
2191             if ( pSource->GetDataDimName(nMeasure) == aDataFieldName )
2192             {
2193                 nAutoMeasure = nMeasure;
2194                 break;
2195             }
2196         }
2197 
2198         //! error if not found?
2199     }
2200 }
2201 
2202 void ScDPLevel::SetEnableLayout( sal_Bool bSet )
2203 {
2204     bEnableLayout = bSet;
2205 }
2206 
2207 ScDPMembers* ScDPLevel::GetMembersObject()
2208 {
2209     if (!pMembers)
2210     {
2211         pMembers = new ScDPMembers( pSource, nDim, nHier, nLev );
2212         pMembers->acquire();    // ref-counted
2213     }
2214     return pMembers;
2215 }
2216 
2217 uno::Reference<container::XNameAccess> SAL_CALL ScDPLevel::getMembers() throw(uno::RuntimeException)
2218 {
2219     return GetMembersObject();
2220 }
2221 
2222 uno::Sequence<sheet::MemberResult> SAL_CALL ScDPLevel::getResults() throw(uno::RuntimeException)
2223 {
2224     const uno::Sequence<sheet::MemberResult>* pRes = pSource->GetMemberResults( this );
2225     if (pRes)
2226         return *pRes;
2227 
2228     return uno::Sequence<sheet::MemberResult>(0);       //! Error?
2229 }
2230 
2231 ::rtl::OUString SAL_CALL ScDPLevel::getName() throw(uno::RuntimeException)
2232 {
2233     long nSrcDim = pSource->GetSourceDim( nDim );
2234     if ( pSource->IsDateDimension( nSrcDim ) )
2235     {
2236         String aRet;        //! globstr-ID !!!!
2237 
2238         if ( nHier == SC_DAPI_HIERARCHY_QUARTER )
2239         {
2240             switch ( nLev )
2241             {
2242                 case SC_DAPI_LEVEL_YEAR:
2243                     aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Year"));
2244                     break;
2245                 case SC_DAPI_LEVEL_QUARTER:
2246                     aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Quarter"));
2247                     break;
2248                 case SC_DAPI_LEVEL_MONTH:
2249                     aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Month"));
2250                     break;
2251                 case SC_DAPI_LEVEL_DAY:
2252                     aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Day"));
2253                     break;
2254                 default:
2255                     DBG_ERROR( "ScDPLevel::getName: unexpected level" );
2256                     break;
2257             }
2258         }
2259         else if ( nHier == SC_DAPI_HIERARCHY_WEEK )
2260         {
2261             switch ( nLev )
2262             {
2263                 case SC_DAPI_LEVEL_YEAR:
2264                     aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Year"));
2265                     break;
2266                 case SC_DAPI_LEVEL_WEEK:
2267                     aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Week"));
2268                     break;
2269                 case SC_DAPI_LEVEL_WEEKDAY:
2270                     aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Weekday"));
2271                     break;
2272                 default:
2273                     DBG_ERROR( "ScDPLevel::getName: unexpected level" );
2274                     break;
2275             }
2276         }
2277         if (aRet.Len())
2278             return aRet;
2279     }
2280 
2281     ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim);
2282     if (!pDim)
2283         return rtl::OUString();
2284 
2285     return pDim->getName();
2286 }
2287 
2288 void SAL_CALL ScDPLevel::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException)
2289 {
2290     DBG_ERROR("not implemented");       //! exception?
2291 }
2292 
2293 uno::Sequence<sheet::GeneralFunction> ScDPLevel::getSubTotals() const
2294 {
2295     //! separate functions for settings and evaluation?
2296 
2297     long nSrcDim = pSource->GetSourceDim( nDim );
2298     if ( !pSource->SubTotalAllowed( nSrcDim ) )
2299         return uno::Sequence<sheet::GeneralFunction>(0);
2300 
2301     return aSubTotals;
2302 }
2303 
2304 void ScDPLevel::setSubTotals(const uno::Sequence<sheet::GeneralFunction>& rNew)
2305 {
2306     aSubTotals = rNew;
2307     //! set "manual change" flag?
2308 }
2309 
2310 sal_Bool ScDPLevel::getShowEmpty() const
2311 {
2312     return bShowEmpty;
2313 }
2314 
2315 void ScDPLevel::setShowEmpty(sal_Bool bSet)
2316 {
2317     bShowEmpty = bSet;
2318 }
2319 
2320 // XPropertySet
2321 
2322 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPLevel::getPropertySetInfo()
2323                                                         throw(uno::RuntimeException)
2324 {
2325     ScUnoGuard aGuard;
2326 
2327     static SfxItemPropertyMapEntry aDPLevelMap_Impl[] =
2328     {
2329         //! change type of AutoShow/Layout/Sorting to API struct when available
2330         {MAP_CHAR_LEN(SC_UNO_AUTOSHOW), 0,  &getCppuType((sheet::DataPilotFieldAutoShowInfo*)0),     0, 0 },
2331         {MAP_CHAR_LEN(SC_UNO_LAYOUT),   0,  &getCppuType((sheet::DataPilotFieldLayoutInfo*)0),       0, 0 },
2332         {MAP_CHAR_LEN(SC_UNO_SHOWEMPT), 0,  &getBooleanCppuType(),                                   0, 0 },
2333         {MAP_CHAR_LEN(SC_UNO_SORTING),  0,  &getCppuType((sheet::DataPilotFieldSortInfo*)0),         0, 0 },
2334         {MAP_CHAR_LEN(SC_UNO_SUBTOTAL), 0,  &getCppuType((uno::Sequence<sheet::GeneralFunction>*)0), 0, 0 },
2335         {0,0,0,0,0,0}
2336     };
2337     static uno::Reference<beans::XPropertySetInfo> aRef =
2338         new SfxItemPropertySetInfo( aDPLevelMap_Impl );
2339     return aRef;
2340 }
2341 
2342 void SAL_CALL ScDPLevel::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue )
2343                 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
2344                         lang::IllegalArgumentException, lang::WrappedTargetException,
2345                         uno::RuntimeException)
2346 {
2347     String aNameStr = aPropertyName;
2348     if ( aNameStr.EqualsAscii( SC_UNO_SHOWEMPT ) )
2349         setShowEmpty( lcl_GetBoolFromAny( aValue ) );
2350     else if ( aNameStr.EqualsAscii( SC_UNO_SUBTOTAL ) )
2351     {
2352         uno::Sequence<sheet::GeneralFunction> aSeq;
2353         if ( aValue >>= aSeq )
2354             setSubTotals( aSeq );
2355     }
2356     else if ( aNameStr.EqualsAscii( SC_UNO_SORTING ) )
2357         aValue >>= aSortInfo;
2358     else if ( aNameStr.EqualsAscii( SC_UNO_AUTOSHOW ) )
2359         aValue >>= aAutoShowInfo;
2360     else if ( aNameStr.EqualsAscii( SC_UNO_LAYOUT ) )
2361         aValue >>= aLayoutInfo;
2362     else
2363     {
2364         DBG_ERROR("unknown property");
2365         //! THROW( UnknownPropertyException() );
2366     }
2367 }
2368 
2369 uno::Any SAL_CALL ScDPLevel::getPropertyValue( const rtl::OUString& aPropertyName )
2370                 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
2371                         uno::RuntimeException)
2372 {
2373     uno::Any aRet;
2374     String aNameStr = aPropertyName;
2375     if ( aNameStr.EqualsAscii( SC_UNO_SHOWEMPT ) )
2376         lcl_SetBoolInAny( aRet, getShowEmpty() );
2377     else if ( aNameStr.EqualsAscii( SC_UNO_SUBTOTAL ) )
2378     {
2379         uno::Sequence<sheet::GeneralFunction> aSeq = getSubTotals();        //! avoid extra copy?
2380         aRet <<= aSeq;
2381     }
2382     else if ( aNameStr.EqualsAscii( SC_UNO_SORTING ) )
2383         aRet <<= aSortInfo;
2384     else if ( aNameStr.EqualsAscii( SC_UNO_AUTOSHOW ) )
2385         aRet <<= aAutoShowInfo;
2386     else if ( aNameStr.EqualsAscii( SC_UNO_LAYOUT ) )
2387         aRet <<= aLayoutInfo;
2388     else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
2389     {
2390         // read only property
2391         long nSrcDim = pSource->GetSourceDim(nDim);
2392         ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim);
2393         if (!pDim)
2394             return aRet;
2395 
2396         const OUString* pLayoutName = pDim->GetLayoutName();
2397         if (!pLayoutName)
2398             return aRet;
2399 
2400         aRet <<= *pLayoutName;
2401     }
2402     else
2403     {
2404         DBG_ERROR("unknown property");
2405         //! THROW( UnknownPropertyException() );
2406     }
2407     return aRet;
2408 }
2409 
2410 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPLevel )
2411 
2412 // -----------------------------------------------------------------------
2413 
2414 ScDPMembers::ScDPMembers( ScDPSource* pSrc, long nD, long nH, long nL ) :
2415     pSource( pSrc ),
2416     nDim( nD ),
2417     nHier( nH ),
2418     nLev( nL ),
2419     ppMbrs( NULL )
2420 {
2421     //! hold pSource
2422 
2423     long nSrcDim = pSource->GetSourceDim( nDim );
2424     if ( pSource->IsDataLayoutDimension(nSrcDim) )
2425         nMbrCount = pSource->GetDataDimensionCount();
2426     else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
2427     {
2428         nMbrCount = 0;
2429         if ( nHier == SC_DAPI_HIERARCHY_QUARTER )
2430         {
2431             switch (nLev)
2432             {
2433                 case SC_DAPI_LEVEL_YEAR:
2434                     {
2435                         // Wang Xu Ming - DataPilot migration
2436                         const ScDPItemData* pLastNumData = NULL;
2437                         for ( SCROW n = 0 ;n <GetSrcItemsCount() ; n-- )
2438                         {
2439                             const ScDPItemData* pData  = GetSrcItemDataByIndex( n );
2440                             if ( pData && pData->HasStringData() )
2441                                 break;
2442                             else
2443                                 pLastNumData = pData;
2444                         }
2445                         // End Comments
2446 
2447                         if ( pLastNumData )
2448                         {
2449                             const ScDPItemData*  pFirstData = GetSrcItemDataByIndex( 0 );
2450                             double fFirstVal = pFirstData->GetValue();
2451                             double fLastVal = pLastNumData->GetValue();
2452 
2453                             long nFirstYear = pSource->GetData()->GetDatePart(
2454                                         (long)::rtl::math::approxFloor( fFirstVal ),
2455                                         nHier, nLev );
2456                             long nLastYear = pSource->GetData()->GetDatePart(
2457                                         (long)::rtl::math::approxFloor( fLastVal ),
2458                                         nHier, nLev );
2459 
2460                             nMbrCount = nLastYear + 1 - nFirstYear;
2461                         }
2462                         else
2463                             nMbrCount = 0;      // no values
2464                     }
2465                     break;
2466                 case SC_DAPI_LEVEL_QUARTER: nMbrCount = 4;  break;
2467                 case SC_DAPI_LEVEL_MONTH:   nMbrCount = 12; break;
2468                 case SC_DAPI_LEVEL_DAY:     nMbrCount = 31; break;
2469                 default:
2470                     DBG_ERROR( "ScDPMembers::ScDPMembers: unexpected level" );
2471                     break;
2472             }
2473         }
2474         else if ( nHier == SC_DAPI_HIERARCHY_WEEK )
2475         {
2476             switch (nLev)
2477             {
2478                 case SC_DAPI_LEVEL_YEAR:    nMbrCount = 1;  break;      //! get years from source
2479                 case SC_DAPI_LEVEL_WEEK:    nMbrCount = 53; break;
2480                 case SC_DAPI_LEVEL_WEEKDAY: nMbrCount = 7;  break;
2481                 default:
2482                     DBG_ERROR( "ScDPMembers::ScDPMembers: unexpected level" );
2483                     break;
2484             }
2485         }
2486     }
2487     else
2488         nMbrCount = pSource->GetData()->GetMembersCount( nSrcDim );
2489 }
2490 
2491 ScDPMembers::~ScDPMembers()
2492 {
2493     //! release pSource
2494 
2495     if (ppMbrs)
2496     {
2497         for (long i=0; i<nMbrCount; i++)
2498             if ( ppMbrs[i] )
2499                 ppMbrs[i]->release();   // ref-counted
2500         delete[] ppMbrs;
2501     }
2502 }
2503 
2504 // XNameAccess implementation using getCount/getByIndex
2505 
2506 sal_Int32 ScDPMembers::GetIndexFromName( const ::rtl::OUString& rName ) const
2507 {
2508     if ( aHashMap.empty() )
2509     {
2510         // store the index for each name
2511 
2512         sal_Int32 nCount = getCount();
2513         for (sal_Int32 i=0; i<nCount; i++)
2514             aHashMap[ getByIndex(i)->getName() ] = i;
2515     }
2516 
2517     ScDPMembersHashMap::const_iterator aIter = aHashMap.find( rName );
2518     if ( aIter != aHashMap.end() )
2519         return aIter->second;           // found index
2520     else
2521         return -1;                      // not found
2522 }
2523 
2524 uno::Any SAL_CALL ScDPMembers::getByName( const rtl::OUString& aName )
2525             throw(container::NoSuchElementException,
2526                     lang::WrappedTargetException, uno::RuntimeException)
2527 {
2528     sal_Int32 nIndex = GetIndexFromName( aName );
2529     if ( nIndex >= 0 )
2530     {
2531         uno::Reference<container::XNamed> xNamed = getByIndex(nIndex);
2532         uno::Any aRet;
2533         aRet <<= xNamed;
2534         return aRet;
2535     }
2536 
2537     throw container::NoSuchElementException();
2538 //    return uno::Any();
2539 }
2540 
2541 uno::Sequence<rtl::OUString> SAL_CALL ScDPMembers::getElementNames() throw(uno::RuntimeException)
2542 {
2543     // Return list of names in sorted order,
2544     // so it's displayed in that order in the field options dialog.
2545     // Sorting is done at the level object (parent of this).
2546 
2547     ScDPLevel* pLevel = pSource->GetDimensionsObject()->getByIndex(nDim)->
2548         GetHierarchiesObject()->getByIndex(nHier)->GetLevelsObject()->getByIndex(nLev);
2549     pLevel->EvaluateSortOrder();
2550     const std::vector<sal_Int32>& rGlobalOrder = pLevel->GetGlobalOrder();
2551     bool bSort = !rGlobalOrder.empty();
2552 
2553     long nCount = getCount();
2554     uno::Sequence<rtl::OUString> aSeq(nCount);
2555     rtl::OUString* pArr = aSeq.getArray();
2556     for (long i=0; i<nCount; i++)
2557         pArr[i] = getByIndex(bSort ? rGlobalOrder[i] : i)->getName();
2558     return aSeq;
2559 }
2560 
2561 sal_Bool SAL_CALL ScDPMembers::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
2562 {
2563     return ( GetIndexFromName( aName ) >= 0 );
2564 }
2565 
2566 uno::Type SAL_CALL ScDPMembers::getElementType() throw(uno::RuntimeException)
2567 {
2568     return getCppuType((uno::Reference<container::XNamed>*)0);
2569 }
2570 
2571 sal_Bool SAL_CALL ScDPMembers::hasElements() throw(uno::RuntimeException)
2572 {
2573     return ( getCount() > 0 );
2574 }
2575 
2576 // end of XNameAccess implementation
2577 
2578 long ScDPMembers::getCount() const
2579 {
2580     return nMbrCount;
2581 }
2582 
2583 long ScDPMembers::getMinMembers() const
2584 {
2585     // used in lcl_CountMinMembers
2586 
2587     long nVisCount = 0;
2588     if ( ppMbrs )
2589     {
2590         for (long i=0; i<nMbrCount; i++)
2591         {
2592             //  count only visible with details (default is true for both)
2593             const ScDPMember* pMbr = ppMbrs[i];
2594             if ( !pMbr || ( pMbr->getIsVisible() && pMbr->getShowDetails() ) )
2595                 ++nVisCount;
2596         }
2597     }
2598     else
2599         nVisCount = nMbrCount;      // default for all
2600 
2601     return nVisCount;
2602 }
2603 
2604 ScDPMember* ScDPMembers::getByIndex(long nIndex) const
2605 {
2606     //  result of GetColumnEntries must not change between ScDPMembers ctor
2607     //  and all calls to getByIndex
2608 
2609     if ( nIndex >= 0 && nIndex < nMbrCount )
2610     {
2611         if ( !ppMbrs )
2612         {
2613             ((ScDPMembers*)this)->ppMbrs = new ScDPMember*[nMbrCount];
2614             for (long i=0; i<nMbrCount; i++)
2615                 ppMbrs[i] = NULL;
2616         }
2617         if ( !ppMbrs[nIndex] )
2618         {
2619             ScDPMember* pNew;
2620             long nSrcDim = pSource->GetSourceDim( nDim );
2621             if ( pSource->IsDataLayoutDimension(nSrcDim) )
2622             {
2623                 // empty name (never shown, not used for lookup)
2624                 pNew = new ScDPMember( pSource, nDim, nHier, nLev, 0 );
2625             }
2626             else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
2627             {
2628                 long nVal = 0;
2629                 String aName;
2630 
2631                 if ( nLev == SC_DAPI_LEVEL_YEAR )   // YEAR is in both hierarchies
2632                 {
2633                     //! cache year range here!
2634 
2635                     // Wang Xu Ming - DataPilot migration
2636                     double fFirstVal = pSource->GetData()->GetMemberByIndex( nSrcDim, 0 )->GetValue();
2637                     long nFirstYear = pSource->GetData()->GetDatePart(
2638                                         (long)::rtl::math::approxFloor( fFirstVal ),
2639                                         nHier, nLev );
2640 
2641                     // End Comments
2642                     nVal = nFirstYear + nIndex;
2643                 }
2644                 else if ( nHier == SC_DAPI_HIERARCHY_WEEK && nLev == SC_DAPI_LEVEL_WEEKDAY )
2645                 {
2646                     nVal = nIndex;              // DayOfWeek is 0-based
2647                     aName = ScGlobal::GetCalendar()->getDisplayName(
2648                         ::com::sun::star::i18n::CalendarDisplayIndex::DAY,
2649                         sal::static_int_cast<sal_Int16>(nVal), 0 );
2650                 }
2651                 else if ( nHier == SC_DAPI_HIERARCHY_QUARTER && nLev == SC_DAPI_LEVEL_MONTH )
2652                 {
2653                     nVal = nIndex;              // Month is 0-based
2654                     aName = ScGlobal::GetCalendar()->getDisplayName(
2655                         ::com::sun::star::i18n::CalendarDisplayIndex::MONTH,
2656                         sal::static_int_cast<sal_Int16>(nVal), 0 );
2657                 }
2658                 else
2659                     nVal = nIndex + 1;          // Quarter, Day, Week are 1-based
2660 
2661                 if ( !aName.Len() )
2662                     aName = String::CreateFromInt32(nVal);
2663 
2664                             ScDPItemData  rData( aName, nVal, sal_True, 0 ) ;
2665                     pNew = new ScDPMember( pSource, nDim, nHier, nLev, pSource->GetCache()->GetAdditionalItemID(rData));
2666             }
2667             else
2668             {
2669                      const std::vector< SCROW >& memberIndexs = pSource->GetData()->GetColumnEntries( nSrcDim );
2670                     pNew = new ScDPMember( pSource, nDim, nHier, nLev, memberIndexs[nIndex]   );
2671             }
2672             pNew->acquire();            // ref-counted
2673             ppMbrs[nIndex] = pNew;
2674         }
2675 
2676         DBG_ASSERT( ppMbrs[nIndex] ," member is not initialized " );
2677 
2678         return ppMbrs[nIndex];
2679     }
2680 
2681     return NULL;    //! exception?
2682 }
2683 
2684 // -----------------------------------------------------------------------
2685 
2686 ScDPMember::ScDPMember( ScDPSource* pSrc, long nD, long nH, long nL,
2687                         SCROW nIndex /*const String& rN, double fV, sal_Bool bHV*/ ) :
2688     pSource( pSrc ),
2689     nDim( nD ),
2690     nHier( nH ),
2691     nLev( nL ),
2692     mnDataId( nIndex ),
2693     mpLayoutName(NULL),
2694     nPosition( -1 ),
2695     bVisible( sal_True ),
2696     bShowDet( sal_True )
2697 {
2698     //! hold pSource
2699 }
2700 
2701 ScDPMember::~ScDPMember()
2702 {
2703     //! release pSource
2704 }
2705 
2706 sal_Bool ScDPMember::IsNamedItem( const ScDPItemData& r ) const
2707 {
2708     long nSrcDim = pSource->GetSourceDim( nDim );
2709     if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) && r.IsValue() )
2710     {
2711         long nComp = pSource->GetData()->GetDatePart(
2712                                         (long)::rtl::math::approxFloor( r.GetValue() ),
2713                                         nHier, nLev );
2714 
2715         //  fValue is converted from integer, so simple comparison works
2716         return nComp == GetItemData().GetValue();
2717     }
2718 
2719     return r.IsCaseInsEqual( GetItemData() );
2720 }
2721 
2722 sal_Bool ScDPMember::IsNamedItem( SCROW    nIndex ) const
2723 {
2724     long nSrcDim = pSource->GetSourceDim( nDim );
2725     if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
2726     {
2727         const ScDPItemData* pData =  pSource->GetCache()->GetItemDataById( (SCCOL) nSrcDim, nIndex );
2728         if (  pData->IsValue()  )
2729         {
2730             long nComp = pSource->GetData()->GetDatePart(
2731                 (long)::rtl::math::approxFloor( pData->GetValue() ),
2732                 nHier, nLev );
2733             //  fValue is converted from integer, so simple comparison works
2734             return nComp == GetItemData().GetValue();
2735         }
2736     }
2737 
2738     return  nIndex == mnDataId;
2739 }
2740 
2741 sal_Int32 ScDPMember::Compare( const ScDPMember& rOther ) const
2742 {
2743     if ( nPosition >= 0 )
2744     {
2745         if ( rOther.nPosition >= 0 )
2746         {
2747             DBG_ASSERT( nPosition != rOther.nPosition, "same position for two members" );
2748             return ( nPosition < rOther.nPosition ) ? -1 : 1;
2749         }
2750         else
2751         {
2752             // only this has a position - members with specified positions come before those without
2753             return -1;
2754         }
2755     }
2756     else if ( rOther.nPosition >= 0 )
2757     {
2758         // only rOther has a position
2759         return 1;
2760     }
2761 
2762     // no positions set - compare names
2763    return pSource->GetData()->Compare( pSource->GetSourceDim(nDim),mnDataId,rOther.GetItemDataId());
2764 }
2765 
2766 void ScDPMember::FillItemData( ScDPItemData& rData ) const
2767 {
2768     //! handle date hierarchy...
2769 
2770     rData = GetItemData() ;
2771 }
2772 
2773 const OUString* ScDPMember::GetLayoutName() const
2774 {
2775     return mpLayoutName.get();
2776 }
2777 
2778 String ScDPMember::GetNameStr() const
2779 {
2780       return GetItemData().GetString();
2781 }
2782 
2783 ::rtl::OUString SAL_CALL ScDPMember::getName() throw(uno::RuntimeException)
2784 {
2785       return GetItemData().GetString();
2786 }
2787 
2788 void SAL_CALL ScDPMember::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException)
2789 {
2790     DBG_ERROR("not implemented");       //! exception?
2791 }
2792 
2793 sal_Bool ScDPMember::getIsVisible() const
2794 {
2795     return bVisible;
2796 }
2797 
2798 void ScDPMember::setIsVisible(sal_Bool bSet)
2799 {
2800     bVisible = bSet;
2801     //! set "manual change" flag
2802 }
2803 
2804 sal_Bool ScDPMember::getShowDetails() const
2805 {
2806     return bShowDet;
2807 }
2808 
2809 void ScDPMember::setShowDetails(sal_Bool bSet)
2810 {
2811     bShowDet = bSet;
2812     //! set "manual change" flag
2813 }
2814 
2815 sal_Int32 ScDPMember::getPosition() const
2816 {
2817     return nPosition;
2818 }
2819 
2820 void ScDPMember::setPosition(sal_Int32 nNew)
2821 {
2822     nPosition = nNew;
2823 }
2824 
2825 // XPropertySet
2826 
2827 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPMember::getPropertySetInfo()
2828                                                         throw(uno::RuntimeException)
2829 {
2830     ScUnoGuard aGuard;
2831 
2832     static SfxItemPropertyMapEntry aDPMemberMap_Impl[] =
2833     {
2834         {MAP_CHAR_LEN(SC_UNO_ISVISIBL), 0,  &getBooleanCppuType(),              0, 0 },
2835         {MAP_CHAR_LEN(SC_UNO_POSITION), 0,  &getCppuType((sal_Int32*)0),        0, 0 },
2836         {MAP_CHAR_LEN(SC_UNO_SHOWDETA), 0,  &getBooleanCppuType(),              0, 0 },
2837         {MAP_CHAR_LEN(SC_UNO_LAYOUTNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 },
2838         {0,0,0,0,0,0}
2839     };
2840     static uno::Reference<beans::XPropertySetInfo> aRef =
2841         new SfxItemPropertySetInfo( aDPMemberMap_Impl );
2842     return aRef;
2843 }
2844 
2845 void SAL_CALL ScDPMember::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue )
2846                 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
2847                         lang::IllegalArgumentException, lang::WrappedTargetException,
2848                         uno::RuntimeException)
2849 {
2850     String aNameStr = aPropertyName;
2851     if ( aNameStr.EqualsAscii( SC_UNO_ISVISIBL ) )
2852         setIsVisible( lcl_GetBoolFromAny( aValue ) );
2853     else if ( aNameStr.EqualsAscii( SC_UNO_SHOWDETA ) )
2854         setShowDetails( lcl_GetBoolFromAny( aValue ) );
2855     else if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) )
2856     {
2857         sal_Int32 nInt = 0;
2858         if (aValue >>= nInt)
2859             setPosition( nInt );
2860     }
2861     else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
2862     {
2863         rtl::OUString aName;
2864         if (aValue >>= aName)
2865             mpLayoutName.reset(new rtl::OUString(aName));
2866     }
2867     else
2868     {
2869         DBG_ERROR("unknown property");
2870         //! THROW( UnknownPropertyException() );
2871     }
2872 }
2873 
2874 uno::Any SAL_CALL ScDPMember::getPropertyValue( const rtl::OUString& aPropertyName )
2875                 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
2876                         uno::RuntimeException)
2877 {
2878     uno::Any aRet;
2879     String aNameStr = aPropertyName;
2880     if ( aNameStr.EqualsAscii( SC_UNO_ISVISIBL ) )
2881         lcl_SetBoolInAny( aRet, getIsVisible() );
2882     else if ( aNameStr.EqualsAscii( SC_UNO_SHOWDETA ) )
2883         lcl_SetBoolInAny( aRet, getShowDetails() );
2884     else if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) )
2885         aRet <<= (sal_Int32) getPosition();
2886     else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
2887         aRet <<= mpLayoutName.get() ? *mpLayoutName : rtl::OUString();
2888     else
2889     {
2890         DBG_ERROR("unknown property");
2891         //! THROW( UnknownPropertyException() );
2892     }
2893     return aRet;
2894 }
2895 
2896 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPMember )
2897 
2898 
2899 ScDPTableDataCache* ScDPSource::GetCache()
2900 {
2901     DBG_ASSERT( GetData() , "empty ScDPTableData pointer");
2902     return ( GetData()!=NULL) ? GetData()->GetCacheTable().GetCache() : NULL ;
2903 }
2904 
2905 const ScDPItemData& ScDPMember::GetItemData() const
2906 {
2907     return *pSource->GetItemDataById( (SCCOL)nDim, mnDataId );//ms-cache-core
2908 }
2909 
2910 const ScDPItemData* ScDPSource::GetItemDataById(long nDim, long nId)
2911 {
2912     long nSrcDim = GetSourceDim( nDim );
2913     const ScDPItemData* pItemData = GetData()->GetMemberById(  nSrcDim,  nId );
2914     if ( !pItemData )
2915    { //todo:
2916         ScDPItemData item;
2917         nId = GetCache()->GetAdditionalItemID( item );
2918         pItemData = GetData()->GetMemberById(  nSrcDim,  nId );
2919     }
2920    return pItemData;
2921 }
2922 
2923 SCROW  ScDPSource::GetMemberId(  long  nDim, const ScDPItemData& rData )
2924 {
2925     long nSrcDim = GetSourceDim( nDim );
2926        return  GetCache()->GetIdByItemData(  nSrcDim, rData );
2927 }
2928 
2929 const ScDPItemData* ScDPMembers::GetSrcItemDataByIndex( SCROW nIndex)
2930 {
2931     const std::vector< SCROW >& memberIds = pSource->GetData()->GetColumnEntries( nDim );
2932     if ( nIndex >= (long )(memberIds.size()) || nIndex < 0 )
2933         return NULL;
2934     SCROW nId =  memberIds[ nIndex ];
2935     return pSource->GetItemDataById( nDim, nId );
2936 }
2937 
2938  SCROW ScDPMembers::GetSrcItemsCount()
2939  {
2940     return pSource->GetData()->GetColumnEntries( nDim ).size();
2941  }
2942 // End Comments
2943 
2944