Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / dptabsrc.cxx
blob2809b0e062bbb52e855771a4a05548725ab0c4a5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "dptabsrc.hxx"
22 #include <algorithm>
23 #include <vector>
24 #include <set>
25 #include <boost/unordered_set.hpp>
26 #include <boost/unordered_map.hpp>
28 #include <rtl/math.hxx>
29 #include <svl/itemprop.hxx>
30 #include <svl/intitem.hxx>
31 #include <vcl/svapp.hxx>
33 #include "scitems.hxx"
34 #include "document.hxx"
35 #include "docpool.hxx"
36 #include "patattr.hxx"
37 #include "formulacell.hxx"
39 #include "dptabres.hxx"
40 #include "dptabdat.hxx"
41 #include "global.hxx"
42 #include "datauno.hxx"
43 #include "miscuno.hxx"
44 #include "unonames.hxx"
45 #include "dpitemdata.hxx"
46 #include "dputil.hxx"
47 #include "dpresfilter.hxx"
48 #include "calcmacros.hxx"
50 #include <com/sun/star/beans/PropertyAttribute.hpp>
51 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
52 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
53 #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
54 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
55 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
56 #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
57 #include <com/sun/star/table/CellAddress.hpp>
59 #include "comphelper/string.hxx"
60 #include <unotools/collatorwrapper.hxx>
61 #include <unotools/calendarwrapper.hxx>
62 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
64 using namespace com::sun::star;
65 using ::std::vector;
66 using ::std::set;
67 using ::com::sun::star::uno::Reference;
68 using ::com::sun::star::uno::Sequence;
69 using ::com::sun::star::uno::Any;
70 using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
72 // -----------------------------------------------------------------------
74 #define SC_MINCOUNT_LIMIT 1000000
76 // -----------------------------------------------------------------------
78 SC_SIMPLE_SERVICE_INFO( ScDPSource, "ScDPSource", "com.sun.star.sheet.DataPilotSource" )
79 SC_SIMPLE_SERVICE_INFO( ScDPDimensions, "ScDPDimensions", "com.sun.star.sheet.DataPilotSourceDimensions" )
80 SC_SIMPLE_SERVICE_INFO( ScDPDimension, "ScDPDimension", "com.sun.star.sheet.DataPilotSourceDimension" )
81 SC_SIMPLE_SERVICE_INFO( ScDPHierarchies, "ScDPHierarchies", "com.sun.star.sheet.DataPilotSourceHierarcies" )
82 SC_SIMPLE_SERVICE_INFO( ScDPHierarchy, "ScDPHierarchy", "com.sun.star.sheet.DataPilotSourceHierarcy" )
83 SC_SIMPLE_SERVICE_INFO( ScDPLevels, "ScDPLevels", "com.sun.star.sheet.DataPilotSourceLevels" )
84 SC_SIMPLE_SERVICE_INFO( ScDPLevel, "ScDPLevel", "com.sun.star.sheet.DataPilotSourceLevel" )
85 SC_SIMPLE_SERVICE_INFO( ScDPMembers, "ScDPMembers", "com.sun.star.sheet.DataPilotSourceMembers" )
86 SC_SIMPLE_SERVICE_INFO( ScDPMember, "ScDPMember", "com.sun.star.sheet.DataPilotSourceMember" )
88 // -----------------------------------------------------------------------
90 // property maps for PropertySetInfo
91 // DataDescription / NumberFormat are internal
93 // -----------------------------------------------------------------------
95 //! move to a header?
96 static sal_Bool lcl_GetBoolFromAny( const uno::Any& aAny )
98 if ( aAny.getValueTypeClass() == uno::TypeClass_BOOLEAN )
99 return *(sal_Bool*)aAny.getValue();
100 return false;
103 static void lcl_SetBoolInAny( uno::Any& rAny, sal_Bool bValue )
105 rAny.setValue( &bValue, getBooleanCppuType() );
108 // -----------------------------------------------------------------------
110 ScDPSource::ScDPSource( ScDPTableData* pD ) :
111 pData( pD ),
112 pDimensions( NULL ),
113 bColumnGrand( true ), // default is true
114 bRowGrand( true ),
115 bIgnoreEmptyRows( false ),
116 bRepeatIfEmpty( false ),
117 nDupCount( 0 ),
118 pResData( NULL ),
119 pColResRoot( NULL ),
120 pRowResRoot( NULL ),
121 pColResults( NULL ),
122 pRowResults( NULL ),
123 bResultOverflow( false ),
124 bPageFiltered( false ),
125 mpGrandTotalName(NULL)
127 pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
130 ScDPSource::~ScDPSource()
132 if (pDimensions)
133 pDimensions->release(); // ref-counted
135 //! free lists
137 delete[] pColResults;
138 delete[] pRowResults;
140 delete pColResRoot;
141 delete pRowResRoot;
142 delete pResData;
145 const OUString* ScDPSource::GetGrandTotalName() const
147 return mpGrandTotalName.get();
150 sal_uInt16 ScDPSource::GetOrientation(long nColumn)
152 if (std::find(maColDims.begin(), maColDims.end(), nColumn) != maColDims.end())
153 return sheet::DataPilotFieldOrientation_COLUMN;
155 if (std::find(maRowDims.begin(), maRowDims.end(), nColumn) != maRowDims.end())
156 return sheet::DataPilotFieldOrientation_ROW;
158 if (std::find(maDataDims.begin(), maDataDims.end(), nColumn) != maDataDims.end())
159 return sheet::DataPilotFieldOrientation_DATA;
161 if (std::find(maPageDims.begin(), maPageDims.end(), nColumn) != maPageDims.end())
162 return sheet::DataPilotFieldOrientation_PAGE;
164 return sheet::DataPilotFieldOrientation_HIDDEN;
167 long ScDPSource::GetDataDimensionCount()
169 return maDataDims.size();
172 ScDPDimension* ScDPSource::GetDataDimension(long nIndex)
174 if (nIndex < 0 || static_cast<size_t>(nIndex) >= maDataDims.size())
175 return NULL;
177 long nDimIndex = maDataDims[nIndex];
178 return GetDimensionsObject()->getByIndex(nDimIndex);
181 OUString ScDPSource::GetDataDimName(long nIndex)
183 OUString aRet;
184 ScDPDimension* pDim = GetDataDimension(nIndex);
185 if (pDim)
186 aRet = pDim->getName();
187 return aRet;
190 long ScDPSource::GetPosition(long nColumn)
192 std::vector<long>::const_iterator it, itBeg = maColDims.begin(), itEnd = maColDims.end();
193 it = std::find(itBeg, itEnd, nColumn);
194 if (it != itEnd)
195 return std::distance(itBeg, it);
197 itBeg = maRowDims.begin();
198 itEnd = maRowDims.end();
199 it = std::find(itBeg, itEnd, nColumn);
200 if (it != itEnd)
201 return std::distance(itBeg, it);
203 itBeg = maDataDims.begin();
204 itEnd = maDataDims.end();
205 it = std::find(itBeg, itEnd, nColumn);
206 if (it != itEnd)
207 return std::distance(itBeg, it);
209 itBeg = maPageDims.begin();
210 itEnd = maPageDims.end();
211 it = std::find(itBeg, itEnd, nColumn);
212 if (it != itEnd)
213 return std::distance(itBeg, it);
215 return 0;
218 namespace {
220 bool testSubTotal( bool& rAllowed, long nColumn, const std::vector<long>& rDims, ScDPSource* pSource )
222 rAllowed = true;
223 std::vector<long>::const_iterator it = rDims.begin(), itEnd = rDims.end();
224 for (; it != itEnd; ++it)
226 if (*it != nColumn)
227 continue;
229 if ( pSource->IsDataLayoutDimension(nColumn) )
231 // no subtotals for data layout dim, no matter where
232 rAllowed = false;
233 return true;
236 // no subtotals if no other dim but data layout follows
237 ++it;
238 if (it != itEnd && pSource->IsDataLayoutDimension(*it))
239 ++it;
240 if (it == itEnd)
241 rAllowed = false;
243 return true; // found
246 return false;
249 void removeDim( long nRemove, std::vector<long>& rDims )
251 std::vector<long>::iterator it = std::find(rDims.begin(), rDims.end(), nRemove);
252 if (it != rDims.end())
253 rDims.erase(it);
258 sal_Bool ScDPSource::SubTotalAllowed(long nColumn)
260 //! cache this at ScDPResultData
261 bool bAllowed = true;
262 if ( testSubTotal(bAllowed, nColumn, maColDims, this) )
263 return bAllowed;
264 if ( testSubTotal(bAllowed, nColumn, maRowDims, this) )
265 return bAllowed;
266 return bAllowed;
269 void ScDPSource::SetOrientation(long nColumn, sal_uInt16 nNew)
271 //! change to no-op if new orientation is equal to old?
273 // remove from old list
274 removeDim(nColumn, maColDims);
275 removeDim(nColumn, maRowDims);
276 removeDim(nColumn, maDataDims);
277 removeDim(nColumn, maPageDims);
279 // add to new list
280 switch (nNew)
282 case sheet::DataPilotFieldOrientation_COLUMN:
283 maColDims.push_back(nColumn);
284 break;
285 case sheet::DataPilotFieldOrientation_ROW:
286 maRowDims.push_back(nColumn);
287 break;
288 case sheet::DataPilotFieldOrientation_DATA:
289 maDataDims.push_back(nColumn);
290 break;
291 case sheet::DataPilotFieldOrientation_PAGE:
292 maPageDims.push_back(nColumn);
293 break;
294 // DataPilot Migration - Cache&&Performance
295 case sheet::DataPilotFieldOrientation_HIDDEN:
296 break;
297 default:
298 OSL_FAIL( "ScDPSource::SetOrientation: unexpected orientation" );
299 break;
303 sal_Bool ScDPSource::IsDataLayoutDimension(long nDim)
305 return nDim == pData->GetColumnCount();
308 sal_uInt16 ScDPSource::GetDataLayoutOrientation()
310 return GetOrientation(pData->GetColumnCount());
313 sal_Bool ScDPSource::IsDateDimension(long nDim)
315 return pData->IsDateDimension(nDim);
318 ScDPDimensions* ScDPSource::GetDimensionsObject()
320 if (!pDimensions)
322 pDimensions = new ScDPDimensions(this);
323 pDimensions->acquire(); // ref-counted
325 return pDimensions;
328 uno::Reference<container::XNameAccess> SAL_CALL ScDPSource::getDimensions() throw(uno::RuntimeException)
330 return GetDimensionsObject();
333 void ScDPSource::SetDupCount( long nNew )
335 nDupCount = nNew;
338 ScDPDimension* ScDPSource::AddDuplicated(long /* nSource */, const OUString& rNewName)
340 OSL_ENSURE( pDimensions, "AddDuplicated without dimensions?" );
342 // re-use
344 long nOldDimCount = pDimensions->getCount();
345 for (long i=0; i<nOldDimCount; i++)
347 ScDPDimension* pDim = pDimensions->getByIndex(i);
348 if (pDim && pDim->getName().equals(rNewName))
350 //! test if pDim is a duplicate of source
351 return pDim;
355 SetDupCount( nDupCount + 1 );
356 pDimensions->CountChanged(); // uses nDupCount
358 return pDimensions->getByIndex( pDimensions->getCount() - 1 );
361 long ScDPSource::GetSourceDim(long nDim)
363 // original source dimension or data layout dimension?
364 if ( nDim <= pData->GetColumnCount() )
365 return nDim;
367 if ( nDim < pDimensions->getCount() )
369 ScDPDimension* pDimObj = pDimensions->getByIndex( nDim );
370 if ( pDimObj )
372 long nSource = pDimObj->GetSourceDim();
373 if ( nSource >= 0 )
374 return nSource;
378 OSL_FAIL("GetSourceDim: wrong dim");
379 return nDim;
382 uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResults()
383 throw(uno::RuntimeException)
385 CreateRes_Impl(); // create pColResRoot and pRowResRoot
387 if ( bResultOverflow ) // set in CreateRes_Impl
389 // no results available
390 throw uno::RuntimeException();
393 long nColCount = pColResRoot->GetSize(pResData->GetColStartMeasure());
394 long nRowCount = pRowResRoot->GetSize(pResData->GetRowStartMeasure());
396 // allocate full sequence
397 //! leave out empty rows???
399 uno::Sequence< uno::Sequence<sheet::DataResult> > aSeq( nRowCount );
400 uno::Sequence<sheet::DataResult>* pRowAry = aSeq.getArray();
401 for (long nRow = 0; nRow < nRowCount; nRow++)
403 uno::Sequence<sheet::DataResult> aColSeq( nColCount );
404 // use default values of DataResult
405 pRowAry[nRow] = aColSeq;
408 ScDPResultFilterContext aFilterCxt;
409 pRowResRoot->FillDataResults(
410 pColResRoot, aFilterCxt, aSeq, pResData->GetRowStartMeasure());
412 maResFilterSet.swap(aFilterCxt.maFilterSet); // Keep this data for GETPIVOTDATA.
414 return aSeq;
417 uno::Sequence<double> ScDPSource::getFilteredResults(
418 const uno::Sequence<sheet::DataPilotFieldFilter>& aFilters )
419 throw (uno::RuntimeException)
421 if (maResFilterSet.empty())
422 getResults(); // Build result tree first.
424 // Get result values from the tree.
425 const ScDPResultTree::ValuesType* pVals = maResFilterSet.getResults(aFilters);
426 if (pVals)
428 size_t n = pVals->size();
429 uno::Sequence<double> aRet(n);
430 for (size_t i = 0; i < n; ++i)
431 aRet[i] = (*pVals)[i];
433 return aRet;
436 if (aFilters.getLength() == 1)
438 // Try to get result from the leaf nodes.
439 double fVal = maResFilterSet.getLeafResult(aFilters[0]);
440 if (!rtl::math::isNan(fVal))
442 uno::Sequence<double> aRet(1);
443 aRet[0] = fVal;
444 return aRet;
448 return uno::Sequence<double>();
451 void SAL_CALL ScDPSource::refresh() throw(uno::RuntimeException)
453 disposeData();
456 void SAL_CALL ScDPSource::addRefreshListener( const uno::Reference<util::XRefreshListener >& )
457 throw(uno::RuntimeException)
459 OSL_FAIL("not implemented"); //! exception?
462 void SAL_CALL ScDPSource::removeRefreshListener( const uno::Reference<util::XRefreshListener >& )
463 throw(uno::RuntimeException)
465 OSL_FAIL("not implemented"); //! exception?
468 Sequence< Sequence<Any> > SAL_CALL ScDPSource::getDrillDownData(const Sequence<sheet::DataPilotFieldFilter>& aFilters)
469 throw (uno::RuntimeException)
471 long nColumnCount = GetData()->GetColumnCount();
473 vector<ScDPFilteredCache::Criterion> aFilterCriteria;
474 sal_Int32 nFilterCount = aFilters.getLength();
475 for (sal_Int32 i = 0; i < nFilterCount; ++i)
477 const sheet::DataPilotFieldFilter& rFilter = aFilters[i];
478 const OUString& aFieldName = rFilter.FieldName;
479 for (long nCol = 0; nCol < nColumnCount; ++nCol)
481 if (aFieldName.equals(pData->getDimensionName(nCol)))
483 ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nCol );
484 ScDPMembers* pMembers = pDim->GetHierarchiesObject()->getByIndex(0)->
485 GetLevelsObject()->getByIndex(0)->GetMembersObject();
486 sal_Int32 nIndex = pMembers->GetIndexFromName( rFilter.MatchValue );
487 if ( nIndex >= 0 )
489 ScDPItemData aItem;
490 pMembers->getByIndex(nIndex)->FillItemData( aItem );
491 aFilterCriteria.push_back( ScDPFilteredCache::Criterion() );
492 aFilterCriteria.back().mnFieldIndex = nCol;
493 aFilterCriteria.back().mpFilter.reset(
494 new ScDPFilteredCache::SingleFilter(aItem));
500 // Take into account the visibilities of field members.
501 ScDPResultVisibilityData aResVisData(this);
502 pRowResRoot->FillVisibilityData(aResVisData);
503 pColResRoot->FillVisibilityData(aResVisData);
504 aResVisData.fillFieldFilters(aFilterCriteria);
506 Sequence< Sequence<Any> > aTabData;
507 boost::unordered_set<sal_Int32> aCatDims;
508 GetCategoryDimensionIndices(aCatDims);
509 pData->GetDrillDownData(aFilterCriteria, aCatDims, aTabData);
510 return aTabData;
513 OUString ScDPSource::getDataDescription()
515 CreateRes_Impl(); // create pResData
517 OUString aRet;
518 if ( pResData->GetMeasureCount() == 1 )
520 bool bTotalResult = false;
521 aRet = pResData->GetMeasureString(0, true, SUBTOTAL_FUNC_NONE, bTotalResult);
524 // empty for more than one measure
526 return aRet;
529 void ScDPSource::setIgnoreEmptyRows(bool bSet)
531 bIgnoreEmptyRows = bSet;
532 pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
535 void ScDPSource::setRepeatIfEmpty(bool bSet)
537 bRepeatIfEmpty = bSet;
538 pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
541 void ScDPSource::disposeData()
543 maResFilterSet.clear();
545 if ( pResData )
547 // reset all data...
549 DELETEZ(pColResRoot);
550 DELETEZ(pRowResRoot);
551 DELETEZ(pResData);
552 delete[] pColResults;
553 delete[] pRowResults;
554 pColResults = NULL;
555 pRowResults = NULL;
556 aColLevelList.clear();
557 aRowLevelList.clear();
560 if ( pDimensions )
562 pDimensions->release(); // ref-counted
563 pDimensions = NULL; // settings have to be applied (from SaveData) again!
565 SetDupCount( 0 );
567 maColDims.clear();
568 maRowDims.clear();
569 maDataDims.clear();
570 maPageDims.clear();
572 pData->DisposeData(); // cached entries etc.
573 bPageFiltered = false;
574 bResultOverflow = false;
577 static long lcl_CountMinMembers(const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLevel, long nLevels )
579 // Calculate the product of the member count for those consecutive levels that
580 // have the "show all" flag, one following level, and the data layout dimension.
582 long nTotal = 1;
583 long nDataCount = 1;
584 sal_Bool bWasShowAll = sal_True;
585 long nPos = nLevels;
586 while ( nPos > 0 )
588 --nPos;
590 if ( nPos+1 < nLevels && ppDim[nPos] == ppDim[nPos+1] )
592 OSL_FAIL("lcl_CountMinMembers: multiple levels from one dimension not implemented");
593 return 0;
596 sal_Bool bDo = false;
597 if ( ppDim[nPos]->getIsDataLayoutDimension() )
599 // data layout dim doesn't interfere with "show all" flags
600 nDataCount = ppLevel[nPos]->GetMembersObject()->getCount();
601 if ( nDataCount == 0 )
602 nDataCount = 1;
604 else if ( bWasShowAll ) // "show all" set for all following levels?
606 bDo = sal_True;
607 if ( !ppLevel[nPos]->getShowEmpty() )
609 // this level is counted, following ones are not
610 bWasShowAll = false;
613 if ( bDo )
615 long nThisCount = ppLevel[nPos]->GetMembersObject()->getMinMembers();
616 if ( nThisCount == 0 )
618 nTotal = 1; // empty level -> start counting from here
619 //! start with visible elements in this level?
621 else
623 if ( nTotal >= LONG_MAX / nThisCount )
624 return LONG_MAX; // overflow
625 nTotal *= nThisCount;
630 // always include data layout dim, even after restarting
631 if ( nTotal >= LONG_MAX / nDataCount )
632 return LONG_MAX; // overflow
633 nTotal *= nDataCount;
635 return nTotal;
638 static long lcl_GetIndexFromName( const OUString rName, const uno::Sequence<OUString>& rElements )
640 long nCount = rElements.getLength();
641 const OUString* pArray = rElements.getConstArray();
642 for (long nPos=0; nPos<nCount; nPos++)
643 if (pArray[nPos] == rName)
644 return nPos;
646 return -1; // not found
649 void ScDPSource::FillCalcInfo(bool bIsRow, ScDPTableData::CalcInfo& rInfo, bool &rHasAutoShow)
651 const std::vector<long>& rDims = bIsRow ? maRowDims : maColDims;
652 std::vector<long>::const_iterator it = rDims.begin(), itEnd = rDims.end();
653 for (; it != itEnd; ++it)
655 ScDPDimension* pDim = GetDimensionsObject()->getByIndex(*it);
656 long nHierarchy = pDim->getUsedHierarchy();
657 if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() )
658 nHierarchy = 0;
659 ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
660 long nCount = pLevels->getCount();
662 //! Test
663 if (pDim->getIsDataLayoutDimension() && maDataDims.size() < 2)
664 nCount = 0;
665 //! Test
667 for (long j = 0; j < nCount; ++j)
669 ScDPLevel* pLevel = pLevels->getByIndex(j);
670 pLevel->EvaluateSortOrder();
672 // no layout flags for column fields, only for row fields
673 pLevel->SetEnableLayout( bIsRow );
675 if ( pLevel->GetAutoShow().IsEnabled )
676 rHasAutoShow = true;
678 if (bIsRow)
680 rInfo.aRowLevelDims.push_back(*it);
681 rInfo.aRowDims.push_back(pDim);
682 rInfo.aRowLevels.push_back(pLevel);
684 else
686 rInfo.aColLevelDims.push_back(*it);
687 rInfo.aColDims.push_back(pDim);
688 rInfo.aColLevels.push_back(pLevel);
691 pLevel->GetMembersObject(); // initialize for groups
696 namespace {
698 class CategoryDimInserter : std::unary_function<long, void>
700 ScDPSource& mrSource;
701 boost::unordered_set<sal_Int32>& mrCatDims;
702 public:
703 CategoryDimInserter(ScDPSource& rSource, boost::unordered_set<sal_Int32>& rCatDims) :
704 mrSource(rSource),
705 mrCatDims(rCatDims) {}
707 void operator() (long nDim)
709 if (!mrSource.IsDataLayoutDimension(nDim))
710 mrCatDims.insert(nDim);
716 void ScDPSource::GetCategoryDimensionIndices(boost::unordered_set<sal_Int32>& rCatDims)
718 boost::unordered_set<sal_Int32> aCatDims;
720 CategoryDimInserter aInserter(*this, aCatDims);
721 std::for_each(maColDims.begin(), maColDims.end(), aInserter);
722 std::for_each(maRowDims.begin(), maRowDims.end(), aInserter);
723 std::for_each(maPageDims.begin(), maPageDims.end(), aInserter);
725 rCatDims.swap(aCatDims);
728 void ScDPSource::FilterCacheByPageDimensions()
730 // #i117661# Repeated calls to ScDPFilteredCache::filterByPageDimension
731 // are invalid because rows are only hidden, never shown again. If
732 // FilterCacheByPageDimensions is called again, the cache table must
733 // be re-initialized. Currently, CreateRes_Impl always uses a fresh cache
734 // because ScDBDocFunc::DataPilotUpdate calls InvalidateData.
736 if (bPageFiltered)
738 SAL_WARN( "sc.core","tried to apply page field filters several times");
740 pData->DisposeData();
741 pData->CreateCacheTable(); // re-initialize the cache table
742 bPageFiltered = false;
745 // filter table by page dimensions.
746 vector<ScDPFilteredCache::Criterion> aCriteria;
747 vector<long>::const_iterator it = maPageDims.begin(), itEnd = maPageDims.end();
748 for (; it != itEnd; ++it)
750 ScDPDimension* pDim = GetDimensionsObject()->getByIndex(*it);
751 long nField = pDim->GetDimension();
753 ScDPMembers* pMems = pDim->GetHierarchiesObject()->getByIndex(0)->
754 GetLevelsObject()->getByIndex(0)->GetMembersObject();
756 long nMemCount = pMems->getCount();
757 ScDPFilteredCache::Criterion aFilter;
758 aFilter.mnFieldIndex = static_cast<sal_Int32>(nField);
759 aFilter.mpFilter.reset(new ScDPFilteredCache::GroupFilter);
760 ScDPFilteredCache::GroupFilter* pGrpFilter =
761 static_cast<ScDPFilteredCache::GroupFilter*>(aFilter.mpFilter.get());
762 for (long j = 0; j < nMemCount; ++j)
764 ScDPMember* pMem = pMems->getByIndex(j);
765 if (pMem->isVisible())
767 ScDPItemData aData;
768 pMem->FillItemData(aData);
769 pGrpFilter->addMatchItem(aData);
772 if (pGrpFilter->getMatchItemCount() < static_cast<size_t>(nMemCount))
773 // there is at least one invisible item. Add this filter criterion to the mix.
774 aCriteria.push_back(aFilter);
776 if (!pDim || !pDim->HasSelectedPage())
777 continue;
779 const ScDPItemData& rData = pDim->GetSelectedData();
780 aCriteria.push_back(ScDPFilteredCache::Criterion());
781 ScDPFilteredCache::Criterion& r = aCriteria.back();
782 r.mnFieldIndex = static_cast<sal_Int32>(nField);
783 r.mpFilter.reset(new ScDPFilteredCache::SingleFilter(rData));
785 if (!aCriteria.empty())
787 boost::unordered_set<sal_Int32> aCatDims;
788 GetCategoryDimensionIndices(aCatDims);
789 pData->FilterCacheTable(aCriteria, aCatDims);
790 bPageFiltered = true;
794 void ScDPSource::CreateRes_Impl()
796 if (pResData)
797 return;
799 sal_uInt16 nDataOrient = GetDataLayoutOrientation();
800 if (maDataDims.size() > 1 && ( nDataOrient != sheet::DataPilotFieldOrientation_COLUMN &&
801 nDataOrient != sheet::DataPilotFieldOrientation_ROW ) )
803 // if more than one data dimension, data layout orientation must be set
804 SetOrientation( pData->GetColumnCount(), sheet::DataPilotFieldOrientation_ROW );
805 nDataOrient = sheet::DataPilotFieldOrientation_ROW;
808 // TODO: Aggreate pDataNames, pDataRefValues, nDataRefOrient, and
809 // eDataFunctions into a structure and use vector instead of static
810 // or pointer arrays.
811 vector<OUString> aDataNames;
812 vector<sheet::DataPilotFieldReference> aDataRefValues;
813 vector<ScSubTotalFunc> aDataFunctions;
814 vector<sal_uInt16> aDataRefOrient;
816 ScDPTableData::CalcInfo aInfo;
819 // LateInit (initialize only those rows/children that are used) can be used unless
820 // any data dimension needs reference values from column/row dimensions
821 bool bLateInit = true;
823 // Go through all data dimensions (i.e. fields) and build their meta data
824 // so that they can be passed on to ScDPResultData instance later.
825 // TODO: aggregate all of data dimension info into a structure.
826 vector<long>::const_iterator it = maDataDims.begin(), itEnd = maDataDims.end();
827 for (; it != itEnd; ++it)
829 // Get function for each data field.
830 long nDimIndex = *it;
831 ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nDimIndex);
832 sheet::GeneralFunction eUser = (sheet::GeneralFunction)pDim->getFunction();
833 if (eUser == sheet::GeneralFunction_AUTO)
835 //! test for numeric data
836 eUser = sheet::GeneralFunction_SUM;
839 // Map UNO's enum to internal enum ScSubTotalFunc.
840 aDataFunctions.push_back(ScDPUtil::toSubTotalFunc(eUser));
842 // Get reference field/item information.
843 aDataRefValues.push_back(pDim->GetReferenceValue());
844 sal_uInt16 nDataRefOrient = sheet::DataPilotFieldOrientation_HIDDEN; // default if not used
845 sal_Int32 eRefType = aDataRefValues.back().ReferenceType;
846 if ( eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
847 eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
848 eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE ||
849 eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL )
851 long nColumn = lcl_GetIndexFromName(
852 aDataRefValues.back().ReferenceField, GetDimensionsObject()->getElementNames());
853 if ( nColumn >= 0 )
855 nDataRefOrient = GetOrientation(nColumn);
856 // need fully initialized results to find reference values
857 // (both in column or row dimensions), so updated values or
858 // differences to 0 can be displayed even for empty results.
859 bLateInit = false;
863 aDataRefOrient.push_back(nDataRefOrient);
865 aDataNames.push_back(pDim->getName());
867 //! modify user visible strings as in ScDPResultData::GetMeasureString instead!
869 aDataNames.back() = ScDPUtil::getSourceDimensionName(aDataNames.back());
871 //! if the name is overridden by user, a flag must be set
872 //! so the user defined name replaces the function string and field name.
874 //! the complete name (function and field) must be stored at the dimension
876 long nSource = pDim->GetSourceDim();
877 if (nSource >= 0)
878 aInfo.aDataSrcCols.push_back(nSource);
879 else
880 aInfo.aDataSrcCols.push_back(nDimIndex);
883 pResData = new ScDPResultData(*this);
884 pResData->SetMeasureData(aDataFunctions, aDataRefValues, aDataRefOrient, aDataNames);
885 pResData->SetDataLayoutOrientation(nDataOrient);
886 pResData->SetLateInit( bLateInit );
888 bool bHasAutoShow = false;
890 ScDPInitState aInitState;
892 // Page field selections restrict the members shown in related fields
893 // (both in column and row fields). aInitState is filled with the page
894 // field selections, they are kept across the data iterator loop.
896 for (it = maPageDims.begin(), itEnd = maPageDims.end(); it != itEnd; ++it)
898 ScDPDimension* pDim = GetDimensionsObject()->getByIndex(*it);
899 if ( pDim->HasSelectedPage() )
900 aInitState.AddMember(*it, GetMemberId(*it, pDim->GetSelectedData()));
903 // Show grand total columns only when the option is set *and* there is at
904 // least one column field. Same for the grand total rows.
905 sal_uInt16 nDataLayoutOrient = GetDataLayoutOrientation();
906 long nColDimCount2 = maColDims.size() - (nDataLayoutOrient == sheet::DataPilotFieldOrientation_COLUMN ? 1 : 0);
907 long nRowDimCount2 = maRowDims.size() - (nDataLayoutOrient == sheet::DataPilotFieldOrientation_ROW ? 1 : 0);
908 bool bShowColGrand = bColumnGrand && nColDimCount2 > 0;
909 bool bShowRowGrand = bRowGrand && nRowDimCount2 > 0;
910 pColResRoot = new ScDPResultMember(pResData, bShowColGrand);
911 pRowResRoot = new ScDPResultMember(pResData, bShowRowGrand);
913 FillCalcInfo(false, aInfo, bHasAutoShow);
914 long nColLevelCount = aInfo.aColLevels.size();
916 pColResRoot->InitFrom( aInfo.aColDims, aInfo.aColLevels, 0, aInitState );
917 pColResRoot->SetHasElements();
919 FillCalcInfo(true, aInfo, bHasAutoShow);
920 long nRowLevelCount = aInfo.aRowLevels.size();
922 if ( nRowLevelCount > 0 )
924 // disable layout flags for the innermost row field (level)
925 aInfo.aRowLevels[nRowLevelCount-1]->SetEnableLayout( false );
928 pRowResRoot->InitFrom( aInfo.aRowDims, aInfo.aRowLevels, 0, aInitState );
929 pRowResRoot->SetHasElements();
931 // initialize members object also for all page dimensions (needed for numeric groups)
932 for (it = maPageDims.begin(), itEnd = maPageDims.end(); it != itEnd; ++it)
934 ScDPDimension* pDim = GetDimensionsObject()->getByIndex(*it);
935 long nHierarchy = pDim->getUsedHierarchy();
936 if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() )
937 nHierarchy = 0;
939 ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
940 long nCount = pLevels->getCount();
941 for (long j=0; j<nCount; j++)
942 pLevels->getByIndex(j)->GetMembersObject(); // initialize for groups
945 // pre-check: calculate minimum number of result columns / rows from
946 // levels that have the "show all" flag set
948 long nMinColMembers = lcl_CountMinMembers( aInfo.aColDims, aInfo.aColLevels, nColLevelCount );
949 long nMinRowMembers = lcl_CountMinMembers( aInfo.aRowDims, aInfo.aRowLevels, nRowLevelCount );
951 if ( nMinColMembers > MAXCOLCOUNT/*SC_MINCOUNT_LIMIT*/ || nMinRowMembers > SC_MINCOUNT_LIMIT )
953 // resulting table is too big -> abort before calculating
954 // (this relies on late init, so no members are allocated in InitFrom above)
956 bResultOverflow = true;
957 return;
960 FilterCacheByPageDimensions();
962 aInfo.aPageDims.reserve(maPageDims.size());
963 for (it = maPageDims.begin(), itEnd = maPageDims.end(); it != itEnd; ++it)
964 aInfo.aPageDims.push_back(*it);
966 aInfo.pInitState = &aInitState;
967 aInfo.pColRoot = pColResRoot;
968 aInfo.pRowRoot = pRowResRoot;
969 pData->CalcResults(aInfo, false);
971 pColResRoot->CheckShowEmpty();
972 pRowResRoot->CheckShowEmpty();
973 // ----------------------------------------------------------------
974 // With all data processed, calculate the final results:
976 // UpdateDataResults calculates all original results from the collected values,
977 // and stores them as reference values if needed.
978 pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() );
980 if ( bHasAutoShow ) // do the double calculation only if AutoShow is used
982 // Find the desired members and set bAutoHidden flag for the others
983 pRowResRoot->DoAutoShow( pColResRoot );
985 // Reset all results to empty, so they can be built again with data for the
986 // desired members only.
987 pColResRoot->ResetResults();
988 pRowResRoot->ResetResults();
989 pData->CalcResults(aInfo, true);
991 // Call UpdateDataResults again, with the new (limited) values.
992 pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() );
995 // SortMembers does the sorting by a result dimension, using the orginal results,
996 // but not running totals etc.
997 pRowResRoot->SortMembers( pColResRoot );
999 // UpdateRunningTotals calculates running totals along column/row dimensions,
1000 // differences from other members (named or relative), and column/row percentages
1001 // or index values.
1002 // Running totals and relative differences need to be done using the sorted values.
1003 // Column/row percentages and index values must be done after sorting, because the
1004 // results may no longer be in the right order (row total for percentage of row is
1005 // always 1).
1006 ScDPRunningTotalState aRunning( pColResRoot, pRowResRoot );
1007 ScDPRowTotals aTotals;
1008 pRowResRoot->UpdateRunningTotals( pColResRoot, pResData->GetRowStartMeasure(), aRunning, aTotals );
1012 void ScDPSource::FillLevelList( sal_uInt16 nOrientation, std::vector<ScDPLevel*> &rList )
1014 rList.clear();
1016 std::vector<long>* pDimIndex = NULL;
1017 switch (nOrientation)
1019 case sheet::DataPilotFieldOrientation_COLUMN:
1020 pDimIndex = &maColDims;
1021 break;
1022 case sheet::DataPilotFieldOrientation_ROW:
1023 pDimIndex = &maRowDims;
1024 break;
1025 case sheet::DataPilotFieldOrientation_DATA:
1026 pDimIndex = &maDataDims;
1027 break;
1028 case sheet::DataPilotFieldOrientation_PAGE:
1029 pDimIndex = &maPageDims;
1030 break;
1031 default:
1032 OSL_FAIL( "ScDPSource::FillLevelList: unexpected orientation" );
1033 break;
1035 if (!pDimIndex)
1037 OSL_FAIL("invalid orientation");
1038 return;
1041 ScDPDimensions* pDims = GetDimensionsObject();
1042 std::vector<long>::const_iterator it = pDimIndex->begin(), itEnd = pDimIndex->end();
1043 for (; it != itEnd; ++it)
1045 ScDPDimension* pDim = pDims->getByIndex(*it);
1046 OSL_ENSURE( pDim->getOrientation() == nOrientation, "orientations are wrong" );
1048 ScDPHierarchies* pHiers = pDim->GetHierarchiesObject();
1049 long nHierarchy = pDim->getUsedHierarchy();
1050 if ( nHierarchy >= pHiers->getCount() )
1051 nHierarchy = 0;
1052 ScDPHierarchy* pHier = pHiers->getByIndex(nHierarchy);
1053 ScDPLevels* pLevels = pHier->GetLevelsObject();
1054 long nLevCount = pLevels->getCount();
1055 for (long nLev=0; nLev<nLevCount; nLev++)
1057 ScDPLevel* pLevel = pLevels->getByIndex(nLev);
1058 rList.push_back(pLevel);
1063 void ScDPSource::FillMemberResults()
1065 if ( !pColResults && !pRowResults )
1067 CreateRes_Impl();
1069 if ( bResultOverflow ) // set in CreateRes_Impl
1071 // no results available -> abort (leave empty)
1072 // exception is thrown in ScDPSource::getResults
1073 return;
1076 FillLevelList( sheet::DataPilotFieldOrientation_COLUMN, aColLevelList );
1077 long nColLevelCount = aColLevelList.size();
1078 if (nColLevelCount)
1080 long nColDimSize = pColResRoot->GetSize(pResData->GetColStartMeasure());
1081 pColResults = new uno::Sequence<sheet::MemberResult>[nColLevelCount];
1082 for (long i=0; i<nColLevelCount; i++)
1083 pColResults[i].realloc(nColDimSize);
1085 long nPos = 0;
1086 pColResRoot->FillMemberResults( pColResults, nPos, pResData->GetColStartMeasure(),
1087 sal_True, NULL, NULL );
1090 FillLevelList( sheet::DataPilotFieldOrientation_ROW, aRowLevelList );
1091 long nRowLevelCount = aRowLevelList.size();
1092 if (nRowLevelCount)
1094 long nRowDimSize = pRowResRoot->GetSize(pResData->GetRowStartMeasure());
1095 pRowResults = new uno::Sequence<sheet::MemberResult>[nRowLevelCount];
1096 for (long i=0; i<nRowLevelCount; i++)
1097 pRowResults[i].realloc(nRowDimSize);
1099 long nPos = 0;
1100 pRowResRoot->FillMemberResults( pRowResults, nPos, pResData->GetRowStartMeasure(),
1101 sal_True, NULL, NULL );
1106 const uno::Sequence<sheet::MemberResult>* ScDPSource::GetMemberResults( ScDPLevel* pLevel )
1108 FillMemberResults();
1110 long i = 0;
1111 long nColCount = aColLevelList.size();
1112 for (i=0; i<nColCount; i++)
1114 ScDPLevel* pColLevel = aColLevelList[i];
1115 if ( pColLevel == pLevel )
1116 return pColResults+i;
1118 long nRowCount = aRowLevelList.size();
1119 for (i=0; i<nRowCount; i++)
1121 ScDPLevel* pRowLevel = aRowLevelList[i];
1122 if ( pRowLevel == pLevel )
1123 return pRowResults+i;
1125 return NULL;
1128 // XPropertySet
1130 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPSource::getPropertySetInfo()
1131 throw(uno::RuntimeException)
1133 SolarMutexGuard aGuard;
1134 using beans::PropertyAttribute::READONLY;
1136 static const SfxItemPropertyMapEntry aDPSourceMap_Impl[] =
1138 {MAP_CHAR_LEN(SC_UNO_DP_COLGRAND), 0, &getBooleanCppuType(), 0, 0 },
1139 {MAP_CHAR_LEN(SC_UNO_DP_DATADESC), 0, &getCppuType((OUString*)0), beans::PropertyAttribute::READONLY, 0 },
1140 {MAP_CHAR_LEN(SC_UNO_DP_IGNOREEMPTY), 0, &getBooleanCppuType(), 0, 0 }, // for sheet data only
1141 {MAP_CHAR_LEN(SC_UNO_DP_REPEATEMPTY), 0, &getBooleanCppuType(), 0, 0 }, // for sheet data only
1142 {MAP_CHAR_LEN(SC_UNO_DP_ROWGRAND), 0, &getBooleanCppuType(), 0, 0 },
1143 {MAP_CHAR_LEN(SC_UNO_DP_ROWFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 },
1144 {MAP_CHAR_LEN(SC_UNO_DP_COLUMNFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 },
1145 {MAP_CHAR_LEN(SC_UNO_DP_DATAFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 },
1146 {MAP_CHAR_LEN(SC_UNO_DP_GRANDTOTAL_NAME), 0, &getCppuType(static_cast<OUString*>(0)), 0, 0 },
1147 {0,0,0,0,0,0}
1149 static uno::Reference<beans::XPropertySetInfo> aRef =
1150 new SfxItemPropertySetInfo( aDPSourceMap_Impl );
1151 return aRef;
1154 void SAL_CALL ScDPSource::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
1155 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
1156 lang::IllegalArgumentException, lang::WrappedTargetException,
1157 uno::RuntimeException)
1159 if (aPropertyName.equalsAscii(SC_UNO_DP_COLGRAND))
1160 bColumnGrand = lcl_GetBoolFromAny(aValue);
1161 else if (aPropertyName.equalsAscii(SC_UNO_DP_ROWGRAND))
1162 bRowGrand = lcl_GetBoolFromAny(aValue);
1163 else if (aPropertyName.equalsAscii(SC_UNO_DP_IGNOREEMPTY))
1164 setIgnoreEmptyRows( lcl_GetBoolFromAny( aValue ) );
1165 else if (aPropertyName.equalsAscii(SC_UNO_DP_REPEATEMPTY))
1166 setRepeatIfEmpty( lcl_GetBoolFromAny( aValue ) );
1167 else if (aPropertyName.equalsAscii(SC_UNO_DP_GRANDTOTAL_NAME))
1169 OUString aName;
1170 if (aValue >>= aName)
1171 mpGrandTotalName.reset(new OUString(aName));
1173 else
1175 OSL_FAIL("unknown property");
1176 //! THROW( UnknownPropertyException() );
1180 uno::Any SAL_CALL ScDPSource::getPropertyValue( const OUString& aPropertyName )
1181 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
1182 uno::RuntimeException)
1184 uno::Any aRet;
1185 if ( aPropertyName.equalsAscii( SC_UNO_DP_COLGRAND ) )
1186 lcl_SetBoolInAny(aRet, bColumnGrand);
1187 else if ( aPropertyName.equalsAscii( SC_UNO_DP_ROWGRAND ) )
1188 lcl_SetBoolInAny(aRet, bRowGrand);
1189 else if ( aPropertyName.equalsAscii( SC_UNO_DP_IGNOREEMPTY ) )
1190 lcl_SetBoolInAny(aRet, bIgnoreEmptyRows);
1191 else if ( aPropertyName.equalsAscii( SC_UNO_DP_REPEATEMPTY ) )
1192 lcl_SetBoolInAny(aRet, bRepeatIfEmpty);
1193 else if ( aPropertyName.equalsAscii( SC_UNO_DP_DATADESC ) ) // read-only
1194 aRet <<= getDataDescription();
1195 else if ( aPropertyName.equalsAscii( SC_UNO_DP_ROWFIELDCOUNT ) ) // read-only
1196 aRet <<= static_cast<sal_Int32>(maRowDims.size());
1197 else if ( aPropertyName.equalsAscii( SC_UNO_DP_COLUMNFIELDCOUNT ) ) // read-only
1198 aRet <<= static_cast<sal_Int32>(maColDims.size());
1199 else if ( aPropertyName.equalsAscii( SC_UNO_DP_DATAFIELDCOUNT ) ) // read-only
1200 aRet <<= static_cast<sal_Int32>(maDataDims.size());
1201 else if (aPropertyName.equalsAscii(SC_UNO_DP_GRANDTOTAL_NAME))
1203 if (mpGrandTotalName.get())
1204 aRet <<= *mpGrandTotalName;
1206 else
1208 OSL_FAIL("unknown property");
1209 //! THROW( UnknownPropertyException() );
1211 return aRet;
1214 #if DEBUG_PIVOT_TABLE
1215 void ScDPSource::DumpResults() const
1217 std::cout << "+++++ column root" << std::endl;
1218 pColResRoot->Dump(1);
1219 std::cout << "+++++ row root" << std::endl;
1220 pRowResRoot->Dump(1);
1222 #endif
1224 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPSource )
1226 // -----------------------------------------------------------------------
1228 ScDPDimensions::ScDPDimensions( ScDPSource* pSrc ) :
1229 pSource( pSrc ),
1230 ppDims( NULL )
1232 //! hold pSource
1234 // include data layout dimension and duplicated dimensions
1235 nDimCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount();
1238 ScDPDimensions::~ScDPDimensions()
1240 //! release pSource
1242 if (ppDims)
1244 for (long i=0; i<nDimCount; i++)
1245 if ( ppDims[i] )
1246 ppDims[i]->release(); // ref-counted
1247 delete[] ppDims;
1251 void ScDPDimensions::CountChanged()
1253 // include data layout dimension and duplicated dimensions
1254 long nNewCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount();
1255 if ( ppDims )
1257 long i;
1258 long nCopy = std::min( nNewCount, nDimCount );
1259 ScDPDimension** ppNew = new ScDPDimension*[nNewCount];
1261 for (i=0; i<nCopy; i++) // copy existing dims
1262 ppNew[i] = ppDims[i];
1263 for (i=nCopy; i<nNewCount; i++) // clear additional pointers
1264 ppNew[i] = NULL;
1265 for (i=nCopy; i<nDimCount; i++) // delete old dims if count is decreased
1266 if ( ppDims[i] )
1267 ppDims[i]->release(); // ref-counted
1269 delete[] ppDims;
1270 ppDims = ppNew;
1272 nDimCount = nNewCount;
1275 // very simple XNameAccess implementation using getCount/getByIndex
1277 uno::Any SAL_CALL ScDPDimensions::getByName( const OUString& aName )
1278 throw(container::NoSuchElementException,
1279 lang::WrappedTargetException, uno::RuntimeException)
1281 long nCount = getCount();
1282 for (long i=0; i<nCount; i++)
1283 if ( getByIndex(i)->getName() == aName )
1285 uno::Reference<container::XNamed> xNamed = getByIndex(i);
1286 uno::Any aRet;
1287 aRet <<= xNamed;
1288 return aRet;
1291 throw container::NoSuchElementException();
1292 // return uno::Any();
1295 uno::Sequence<OUString> SAL_CALL ScDPDimensions::getElementNames() throw(uno::RuntimeException)
1297 long nCount = getCount();
1298 uno::Sequence<OUString> aSeq(nCount);
1299 OUString* pArr = aSeq.getArray();
1300 for (long i=0; i<nCount; i++)
1301 pArr[i] = getByIndex(i)->getName();
1302 return aSeq;
1305 sal_Bool SAL_CALL ScDPDimensions::hasByName( const OUString& aName ) throw(uno::RuntimeException)
1307 long nCount = getCount();
1308 for (long i=0; i<nCount; i++)
1309 if ( getByIndex(i)->getName() == aName )
1310 return sal_True;
1311 return false;
1314 uno::Type SAL_CALL ScDPDimensions::getElementType() throw(uno::RuntimeException)
1316 return getCppuType((uno::Reference<container::XNamed>*)0);
1319 sal_Bool SAL_CALL ScDPDimensions::hasElements() throw(uno::RuntimeException)
1321 return ( getCount() > 0 );
1324 // end of XNameAccess implementation
1326 long ScDPDimensions::getCount() const
1328 // in tabular data, every column of source data is a dimension
1330 return nDimCount;
1333 ScDPDimension* ScDPDimensions::getByIndex(long nIndex) const
1335 if ( nIndex >= 0 && nIndex < nDimCount )
1337 if ( !ppDims )
1339 ((ScDPDimensions*)this)->ppDims = new ScDPDimension*[nDimCount];
1340 for (long i=0; i<nDimCount; i++)
1341 ppDims[i] = NULL;
1343 if ( !ppDims[nIndex] )
1345 ppDims[nIndex] = new ScDPDimension( pSource, nIndex );
1346 ppDims[nIndex]->acquire(); // ref-counted
1349 return ppDims[nIndex];
1352 return NULL; //! exception?
1355 // -----------------------------------------------------------------------
1357 ScDPDimension::ScDPDimension( ScDPSource* pSrc, long nD ) :
1358 pSource( pSrc ),
1359 nDim( nD ),
1360 pHierarchies( NULL ),
1361 nUsedHier( 0 ),
1362 nFunction( SUBTOTAL_FUNC_SUM ), // sum is default
1363 mpLayoutName(NULL),
1364 mpSubtotalName(NULL),
1365 nSourceDim( -1 ),
1366 bHasSelectedPage( false ),
1367 pSelectedData( NULL ),
1368 mbHasHiddenMember(false)
1370 //! hold pSource
1373 ScDPDimension::~ScDPDimension()
1375 //! release pSource
1377 if ( pHierarchies )
1378 pHierarchies->release(); // ref-counted
1380 delete pSelectedData;
1383 ScDPHierarchies* ScDPDimension::GetHierarchiesObject()
1385 if (!pHierarchies)
1387 pHierarchies = new ScDPHierarchies( pSource, nDim );
1388 pHierarchies->acquire(); // ref-counted
1390 return pHierarchies;
1393 const OUString* ScDPDimension::GetLayoutName() const
1395 return mpLayoutName.get();
1398 const OUString* ScDPDimension::GetSubtotalName() const
1400 return mpSubtotalName.get();
1403 uno::Reference<container::XNameAccess> SAL_CALL ScDPDimension::getHierarchies()
1404 throw(uno::RuntimeException)
1406 return GetHierarchiesObject();
1409 OUString SAL_CALL ScDPDimension::getName() throw(uno::RuntimeException)
1411 if (!aName.isEmpty())
1412 return aName;
1413 else
1414 return pSource->GetData()->getDimensionName( nDim );
1417 void SAL_CALL ScDPDimension::setName( const OUString& rNewName ) throw(uno::RuntimeException)
1419 // used after cloning
1420 aName = rNewName;
1423 sal_uInt16 ScDPDimension::getOrientation() const
1425 return pSource->GetOrientation( nDim );
1428 void ScDPDimension::setOrientation(sal_uInt16 nNew)
1430 pSource->SetOrientation( nDim, nNew );
1433 long ScDPDimension::getPosition() const
1435 return pSource->GetPosition( nDim );
1438 bool ScDPDimension::getIsDataLayoutDimension() const
1440 return pSource->GetData()->getIsDataLayoutDimension( nDim );
1443 sal_uInt16 ScDPDimension::getFunction() const
1445 return nFunction;
1448 void ScDPDimension::setFunction(sal_uInt16 nNew)
1450 nFunction = nNew;
1453 long ScDPDimension::getUsedHierarchy() const
1455 return nUsedHier;
1458 void ScDPDimension::setUsedHierarchy(long /* nNew */)
1460 // #i52547# don't use the incomplete date hierarchy implementation - ignore the call
1463 ScDPDimension* ScDPDimension::CreateCloneObject()
1465 OSL_ENSURE( nSourceDim < 0, "recursive duplicate - not implemented" );
1467 //! set new name here, or temporary name ???
1468 OUString aNewName = aName;
1470 ScDPDimension* pNew = pSource->AddDuplicated( nDim, aNewName );
1472 pNew->aName = aNewName; //! here or in source?
1473 pNew->nSourceDim = nDim; //! recursive?
1475 return pNew;
1478 uno::Reference<util::XCloneable> SAL_CALL ScDPDimension::createClone() throw(uno::RuntimeException)
1480 return CreateCloneObject();
1483 const sheet::DataPilotFieldReference& ScDPDimension::GetReferenceValue() const
1485 return aReferenceValue;
1488 const ScDPItemData& ScDPDimension::GetSelectedData()
1490 if ( !pSelectedData )
1492 // find the named member to initialize pSelectedData from it, with name and value
1494 long nLevel = 0;
1496 long nHierarchy = getUsedHierarchy();
1497 if ( nHierarchy >= GetHierarchiesObject()->getCount() )
1498 nHierarchy = 0;
1499 ScDPLevels* pLevels = GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
1500 long nLevCount = pLevels->getCount();
1501 if ( nLevel < nLevCount )
1503 ScDPMembers* pMembers = pLevels->getByIndex(nLevel)->GetMembersObject();
1505 //! merge with ScDPMembers::getByName
1506 long nCount = pMembers->getCount();
1507 for (long i=0; i<nCount && !pSelectedData; i++)
1509 ScDPMember* pMember = pMembers->getByIndex(i);
1510 if (aSelectedPage.equals(pMember->GetNameStr()))
1512 pSelectedData = new ScDPItemData();
1513 pMember->FillItemData( *pSelectedData );
1518 if ( !pSelectedData )
1519 pSelectedData = new ScDPItemData(aSelectedPage); // default - name only
1522 return *pSelectedData;
1525 // XPropertySet
1527 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPDimension::getPropertySetInfo()
1528 throw(uno::RuntimeException)
1530 SolarMutexGuard aGuard;
1532 static const SfxItemPropertyMapEntry aDPDimensionMap_Impl[] =
1534 {MAP_CHAR_LEN(SC_UNO_DP_FILTER), 0, &getCppuType((uno::Sequence<sheet::TableFilterField>*)0), 0, 0 },
1535 {MAP_CHAR_LEN(SC_UNO_DP_FLAGS), 0, &getCppuType((sal_Int32*)0), beans::PropertyAttribute::READONLY, 0 },
1536 {MAP_CHAR_LEN(SC_UNO_DP_FUNCTION), 0, &getCppuType((sheet::GeneralFunction*)0), 0, 0 },
1537 {MAP_CHAR_LEN(SC_UNO_DP_ISDATALAYOUT), 0, &getBooleanCppuType(), beans::PropertyAttribute::READONLY, 0 },
1538 {MAP_CHAR_LEN(SC_UNO_DP_NUMBERFO), 0, &getCppuType((sal_Int32*)0), beans::PropertyAttribute::READONLY, 0 },
1539 {MAP_CHAR_LEN(SC_UNO_DP_ORIENTATION), 0, &getCppuType((sheet::DataPilotFieldOrientation*)0), 0, 0 },
1540 {MAP_CHAR_LEN(SC_UNO_DP_ORIGINAL), 0, &getCppuType((uno::Reference<container::XNamed>*)0), beans::PropertyAttribute::READONLY, 0 },
1541 {MAP_CHAR_LEN(SC_UNO_DP_ORIGINAL_POS), 0, &getCppuType((sal_Int32*)0), 0, 0 },
1542 {MAP_CHAR_LEN(SC_UNO_DP_POSITION), 0, &getCppuType((sal_Int32*)0), 0, 0 },
1543 {MAP_CHAR_LEN(SC_UNO_DP_REFVALUE), 0, &getCppuType((sheet::DataPilotFieldReference*)0), 0, 0 },
1544 {MAP_CHAR_LEN(SC_UNO_DP_USEDHIERARCHY), 0, &getCppuType((sal_Int32*)0), 0, 0 },
1545 {MAP_CHAR_LEN(SC_UNO_DP_LAYOUTNAME), 0, &getCppuType(static_cast<OUString*>(0)), 0, 0 },
1546 {MAP_CHAR_LEN(SC_UNO_DP_FIELD_SUBTOTALNAME), 0, &getCppuType(static_cast<OUString*>(0)), 0, 0 },
1547 {MAP_CHAR_LEN(SC_UNO_DP_HAS_HIDDEN_MEMBER), 0, &getBooleanCppuType(), 0, 0 },
1548 {0,0,0,0,0,0}
1550 static uno::Reference<beans::XPropertySetInfo> aRef =
1551 new SfxItemPropertySetInfo( aDPDimensionMap_Impl );
1552 return aRef;
1555 void SAL_CALL ScDPDimension::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
1556 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
1557 lang::IllegalArgumentException, lang::WrappedTargetException,
1558 uno::RuntimeException)
1560 if ( aPropertyName.equalsAscii( SC_UNO_DP_USEDHIERARCHY ) )
1562 sal_Int32 nInt = 0;
1563 if (aValue >>= nInt)
1564 setUsedHierarchy( nInt );
1566 else if ( aPropertyName.equalsAscii( SC_UNO_DP_ORIENTATION ) )
1568 sheet::DataPilotFieldOrientation eEnum;
1569 if (aValue >>= eEnum)
1570 setOrientation( sal::static_int_cast<sal_uInt16>(eEnum) );
1572 else if ( aPropertyName.equalsAscii( SC_UNO_DP_FUNCTION ) )
1574 sheet::GeneralFunction eEnum;
1575 if (aValue >>= eEnum)
1576 setFunction( sal::static_int_cast<sal_uInt16>(eEnum) );
1578 else if ( aPropertyName.equalsAscii( SC_UNO_DP_REFVALUE ) )
1579 aValue >>= aReferenceValue;
1580 else if ( aPropertyName.equalsAscii( SC_UNO_DP_FILTER ) )
1582 sal_Bool bDone = false;
1583 uno::Sequence<sheet::TableFilterField> aSeq;
1584 if (aValue >>= aSeq)
1586 sal_Int32 nLength = aSeq.getLength();
1587 if ( nLength == 0 )
1589 aSelectedPage = "";
1590 bHasSelectedPage = false;
1591 bDone = sal_True;
1593 else if ( nLength == 1 )
1595 const sheet::TableFilterField& rField = aSeq[0];
1596 if ( rField.Field == 0 && rField.Operator == sheet::FilterOperator_EQUAL && !rField.IsNumeric )
1598 aSelectedPage = rField.StringValue;
1599 bHasSelectedPage = true;
1600 bDone = sal_True;
1604 if ( !bDone )
1606 OSL_FAIL("Filter property is not a single string");
1607 throw lang::IllegalArgumentException();
1609 DELETEZ( pSelectedData ); // invalid after changing aSelectedPage
1611 else if (aPropertyName.equalsAscii(SC_UNO_DP_LAYOUTNAME))
1613 OUString aTmpName;
1614 if (aValue >>= aTmpName)
1615 mpLayoutName.reset(new OUString(aTmpName));
1617 else if (aPropertyName.equalsAscii(SC_UNO_DP_FIELD_SUBTOTALNAME))
1619 OUString aTmpName;
1620 if (aValue >>= aTmpName)
1621 mpSubtotalName.reset(new OUString(aTmpName));
1623 else if (aPropertyName.equalsAscii(SC_UNO_DP_HAS_HIDDEN_MEMBER))
1625 sal_Bool b = false;
1626 aValue >>= b;
1627 mbHasHiddenMember = b;
1629 else
1631 OSL_FAIL("unknown property");
1632 //! THROW( UnknownPropertyException() );
1636 uno::Any SAL_CALL ScDPDimension::getPropertyValue( const OUString& aPropertyName )
1637 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
1638 uno::RuntimeException)
1640 uno::Any aRet;
1641 if ( aPropertyName.equalsAscii( SC_UNO_DP_POSITION ) )
1642 aRet <<= (sal_Int32) getPosition();
1643 else if ( aPropertyName.equalsAscii( SC_UNO_DP_USEDHIERARCHY ) )
1644 aRet <<= (sal_Int32) getUsedHierarchy();
1645 else if ( aPropertyName.equalsAscii( SC_UNO_DP_ORIENTATION ) )
1647 sheet::DataPilotFieldOrientation eVal = (sheet::DataPilotFieldOrientation)getOrientation();
1648 aRet <<= eVal;
1650 else if ( aPropertyName.equalsAscii( SC_UNO_DP_FUNCTION ) )
1652 sheet::GeneralFunction eVal = (sheet::GeneralFunction)getFunction();
1653 aRet <<= eVal;
1655 else if ( aPropertyName.equalsAscii( SC_UNO_DP_REFVALUE ) )
1656 aRet <<= aReferenceValue;
1657 else if ( aPropertyName.equalsAscii( SC_UNO_DP_ISDATALAYOUT ) ) // read-only properties
1658 lcl_SetBoolInAny( aRet, getIsDataLayoutDimension() );
1659 else if ( aPropertyName.equalsAscii( SC_UNO_DP_NUMBERFO ) )
1661 sal_Int32 nFormat = 0;
1662 sheet::GeneralFunction eFunc = (sheet::GeneralFunction)getFunction();
1663 // #i63745# don't use source format for "count"
1664 if ( eFunc != sheet::GeneralFunction_COUNT && eFunc != sheet::GeneralFunction_COUNTNUMS )
1665 nFormat = pSource->GetData()->GetNumberFormat( ( nSourceDim >= 0 ) ? nSourceDim : nDim );
1667 switch ( aReferenceValue.ReferenceType )
1669 case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE:
1670 case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
1671 case sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE:
1672 case sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE:
1673 case sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE:
1674 nFormat = pSource->GetData()->GetNumberFormatByIdx( (NfIndexTableOffset)NF_PERCENT_DEC2 );
1675 break;
1676 case sheet::DataPilotFieldReferenceType::INDEX:
1677 nFormat = pSource->GetData()->GetNumberFormatByIdx( (NfIndexTableOffset)NF_NUMBER_SYSTEM );
1678 break;
1679 default:
1680 break;
1683 aRet <<= nFormat;
1685 else if ( aPropertyName.equalsAscii( SC_UNO_DP_ORIGINAL ) )
1687 uno::Reference<container::XNamed> xOriginal;
1688 if (nSourceDim >= 0)
1689 xOriginal = pSource->GetDimensionsObject()->getByIndex(nSourceDim);
1690 aRet <<= xOriginal;
1692 else if (aPropertyName.equalsAscii(SC_UNO_DP_ORIGINAL_POS))
1694 sal_Int32 nPos = static_cast<sal_Int32>(nSourceDim);
1695 aRet <<= nPos;
1697 else if ( aPropertyName.equalsAscii( SC_UNO_DP_FILTER ) )
1699 if ( bHasSelectedPage )
1701 // single filter field: first field equal to selected string
1702 sheet::TableFilterField aField( sheet::FilterConnection_AND, 0,
1703 sheet::FilterOperator_EQUAL, false, 0.0, aSelectedPage );
1704 aRet <<= uno::Sequence<sheet::TableFilterField>( &aField, 1 );
1706 else
1707 aRet <<= uno::Sequence<sheet::TableFilterField>(0);
1709 else if (aPropertyName.equalsAscii(SC_UNO_DP_LAYOUTNAME))
1710 aRet <<= mpLayoutName.get() ? *mpLayoutName : OUString("");
1711 else if (aPropertyName.equalsAscii(SC_UNO_DP_FIELD_SUBTOTALNAME))
1712 aRet <<= mpSubtotalName.get() ? *mpSubtotalName : OUString("");
1713 else if (aPropertyName.equalsAscii(SC_UNO_DP_HAS_HIDDEN_MEMBER))
1714 aRet <<= static_cast<sal_Bool>(mbHasHiddenMember);
1715 else if (aPropertyName.equalsAscii(SC_UNO_DP_FLAGS))
1717 sal_Int32 nFlags = 0; // tabular data: all orientations are possible
1718 aRet <<= nFlags;
1720 else
1722 OSL_FAIL("unknown property");
1723 //! THROW( UnknownPropertyException() );
1725 return aRet;
1728 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPDimension )
1730 // -----------------------------------------------------------------------
1732 ScDPHierarchies::ScDPHierarchies( ScDPSource* pSrc, long nD ) :
1733 pSource( pSrc ),
1734 nDim( nD ),
1735 ppHiers( NULL )
1737 //! hold pSource
1739 // date columns have 3 hierarchies (flat/quarter/week), other columns only one
1741 // #i52547# don't offer the incomplete date hierarchy implementation
1742 nHierCount = 1;
1745 ScDPHierarchies::~ScDPHierarchies()
1747 //! release pSource
1749 if (ppHiers)
1751 for (long i=0; i<nHierCount; i++)
1752 if ( ppHiers[i] )
1753 ppHiers[i]->release(); // ref-counted
1754 delete[] ppHiers;
1758 // very simple XNameAccess implementation using getCount/getByIndex
1760 uno::Any SAL_CALL ScDPHierarchies::getByName( const OUString& aName )
1761 throw(container::NoSuchElementException,
1762 lang::WrappedTargetException, uno::RuntimeException)
1764 long nCount = getCount();
1765 for (long i=0; i<nCount; i++)
1766 if ( getByIndex(i)->getName() == aName )
1768 uno::Reference<container::XNamed> xNamed = getByIndex(i);
1769 uno::Any aRet;
1770 aRet <<= xNamed;
1771 return aRet;
1774 throw container::NoSuchElementException();
1777 uno::Sequence<OUString> SAL_CALL ScDPHierarchies::getElementNames() throw(uno::RuntimeException)
1779 long nCount = getCount();
1780 uno::Sequence<OUString> aSeq(nCount);
1781 OUString* pArr = aSeq.getArray();
1782 for (long i=0; i<nCount; i++)
1783 pArr[i] = getByIndex(i)->getName();
1784 return aSeq;
1787 sal_Bool SAL_CALL ScDPHierarchies::hasByName( const OUString& aName ) throw(uno::RuntimeException)
1789 long nCount = getCount();
1790 for (long i=0; i<nCount; i++)
1791 if ( getByIndex(i)->getName() == aName )
1792 return sal_True;
1793 return false;
1796 uno::Type SAL_CALL ScDPHierarchies::getElementType() throw(uno::RuntimeException)
1798 return getCppuType((uno::Reference<container::XNamed>*)0);
1801 sal_Bool SAL_CALL ScDPHierarchies::hasElements() throw(uno::RuntimeException)
1803 return ( getCount() > 0 );
1806 // end of XNameAccess implementation
1808 long ScDPHierarchies::getCount() const
1810 return nHierCount;
1813 ScDPHierarchy* ScDPHierarchies::getByIndex(long nIndex) const
1815 // pass hierarchy index to new object in case the implementation
1816 // will be extended to more than one hierarchy
1818 if ( nIndex >= 0 && nIndex < nHierCount )
1820 if ( !ppHiers )
1822 ((ScDPHierarchies*)this)->ppHiers = new ScDPHierarchy*[nHierCount];
1823 for (long i=0; i<nHierCount; i++)
1824 ppHiers[i] = NULL;
1826 if ( !ppHiers[nIndex] )
1828 ppHiers[nIndex] = new ScDPHierarchy( pSource, nDim, nIndex );
1829 ppHiers[nIndex]->acquire(); // ref-counted
1832 return ppHiers[nIndex];
1835 return NULL; //! exception?
1838 // -----------------------------------------------------------------------
1840 ScDPHierarchy::ScDPHierarchy( ScDPSource* pSrc, long nD, long nH ) :
1841 pSource( pSrc ),
1842 nDim( nD ),
1843 nHier( nH ),
1844 pLevels( NULL )
1846 //! hold pSource
1849 ScDPHierarchy::~ScDPHierarchy()
1851 //! release pSource
1853 if (pLevels)
1854 pLevels->release(); // ref-counted
1857 ScDPLevels* ScDPHierarchy::GetLevelsObject()
1859 if (!pLevels)
1861 pLevels = new ScDPLevels( pSource, nDim, nHier );
1862 pLevels->acquire(); // ref-counted
1864 return pLevels;
1867 uno::Reference<container::XNameAccess> SAL_CALL ScDPHierarchy::getLevels()
1868 throw(uno::RuntimeException)
1870 return GetLevelsObject();
1873 OUString SAL_CALL ScDPHierarchy::getName() throw(uno::RuntimeException)
1875 OUString aRet; //! globstr-ID !!!!
1876 switch (nHier)
1878 case SC_DAPI_HIERARCHY_FLAT:
1879 aRet = "flat";
1880 break; //! name ???????
1881 case SC_DAPI_HIERARCHY_QUARTER:
1882 aRet = "Quarter";
1883 break; //! name ???????
1884 case SC_DAPI_HIERARCHY_WEEK:
1885 aRet = "Week";
1886 break; //! name ???????
1887 default:
1888 OSL_FAIL( "ScDPHierarchy::getName: unexpected hierarchy" );
1889 break;
1891 return aRet;
1894 void SAL_CALL ScDPHierarchy::setName( const OUString& /* rNewName */ ) throw(uno::RuntimeException)
1896 OSL_FAIL("not implemented"); //! exception?
1899 // -----------------------------------------------------------------------
1901 ScDPLevels::ScDPLevels( ScDPSource* pSrc, long nD, long nH ) :
1902 pSource( pSrc ),
1903 nDim( nD ),
1904 nHier( nH ),
1905 ppLevs( NULL )
1907 //! hold pSource
1909 // text columns have only one level
1911 long nSrcDim = pSource->GetSourceDim( nDim );
1912 if ( pSource->IsDateDimension( nSrcDim ) )
1914 switch ( nHier )
1916 case SC_DAPI_HIERARCHY_FLAT: nLevCount = SC_DAPI_FLAT_LEVELS; break;
1917 case SC_DAPI_HIERARCHY_QUARTER: nLevCount = SC_DAPI_QUARTER_LEVELS; break;
1918 case SC_DAPI_HIERARCHY_WEEK: nLevCount = SC_DAPI_WEEK_LEVELS; break;
1919 default:
1920 OSL_FAIL("wrong hierarchy");
1921 nLevCount = 0;
1924 else
1925 nLevCount = 1;
1928 ScDPLevels::~ScDPLevels()
1930 //! release pSource
1932 if (ppLevs)
1934 for (long i=0; i<nLevCount; i++)
1935 if ( ppLevs[i] )
1936 ppLevs[i]->release(); // ref-counted
1937 delete[] ppLevs;
1941 // very simple XNameAccess implementation using getCount/getByIndex
1943 uno::Any SAL_CALL ScDPLevels::getByName( const OUString& aName )
1944 throw(container::NoSuchElementException,
1945 lang::WrappedTargetException, uno::RuntimeException)
1947 long nCount = getCount();
1948 for (long i=0; i<nCount; i++)
1949 if ( getByIndex(i)->getName() == aName )
1951 uno::Reference<container::XNamed> xNamed = getByIndex(i);
1952 uno::Any aRet;
1953 aRet <<= xNamed;
1954 return aRet;
1957 throw container::NoSuchElementException();
1960 uno::Sequence<OUString> SAL_CALL ScDPLevels::getElementNames() throw(uno::RuntimeException)
1962 long nCount = getCount();
1963 uno::Sequence<OUString> aSeq(nCount);
1964 OUString* pArr = aSeq.getArray();
1965 for (long i=0; i<nCount; i++)
1966 pArr[i] = getByIndex(i)->getName();
1967 return aSeq;
1970 sal_Bool SAL_CALL ScDPLevels::hasByName( const OUString& aName ) throw(uno::RuntimeException)
1972 long nCount = getCount();
1973 for (long i=0; i<nCount; i++)
1974 if ( getByIndex(i)->getName() == aName )
1975 return sal_True;
1976 return false;
1979 uno::Type SAL_CALL ScDPLevels::getElementType() throw(uno::RuntimeException)
1981 return getCppuType((uno::Reference<container::XNamed>*)0);
1984 sal_Bool SAL_CALL ScDPLevels::hasElements() throw(uno::RuntimeException)
1986 return ( getCount() > 0 );
1989 // end of XNameAccess implementation
1991 long ScDPLevels::getCount() const
1993 return nLevCount;
1996 ScDPLevel* ScDPLevels::getByIndex(long nIndex) const
1998 if ( nIndex >= 0 && nIndex < nLevCount )
2000 if ( !ppLevs )
2002 ((ScDPLevels*)this)->ppLevs = new ScDPLevel*[nLevCount];
2003 for (long i=0; i<nLevCount; i++)
2004 ppLevs[i] = NULL;
2006 if ( !ppLevs[nIndex] )
2008 ppLevs[nIndex] = new ScDPLevel( pSource, nDim, nHier, nIndex );
2009 ppLevs[nIndex]->acquire(); // ref-counted
2012 return ppLevs[nIndex];
2015 return NULL; //! exception?
2018 // -----------------------------------------------------------------------
2020 class ScDPGlobalMembersOrder
2022 ScDPLevel& rLevel;
2023 sal_Bool bAscending;
2025 public:
2026 ScDPGlobalMembersOrder( ScDPLevel& rLev, sal_Bool bAsc ) :
2027 rLevel(rLev),
2028 bAscending(bAsc)
2030 ~ScDPGlobalMembersOrder() {}
2032 sal_Bool operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
2035 sal_Bool ScDPGlobalMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
2037 sal_Int32 nCompare = 0;
2038 // seems that some ::std::sort() implementations pass the same index twice
2039 if( nIndex1 != nIndex2 )
2041 ScDPMembers* pMembers = rLevel.GetMembersObject();
2042 ScDPMember* pMember1 = pMembers->getByIndex(nIndex1);
2043 ScDPMember* pMember2 = pMembers->getByIndex(nIndex2);
2044 nCompare = pMember1->Compare( *pMember2 );
2046 return bAscending ? (nCompare < 0) : (nCompare > 0);
2049 // -----------------------------------------------------------------------
2051 ScDPLevel::ScDPLevel( ScDPSource* pSrc, long nD, long nH, long nL ) :
2052 pSource( pSrc ),
2053 nDim( nD ),
2054 nHier( nH ),
2055 nLev( nL ),
2056 pMembers( NULL ),
2057 aSortInfo( EMPTY_OUSTRING, sal_True, sheet::DataPilotFieldSortMode::NAME ), // default: sort by name
2058 nSortMeasure( 0 ),
2059 nAutoMeasure( 0 ),
2060 bShowEmpty( false ),
2061 bEnableLayout( false )
2063 //! hold pSource
2064 // aSubTotals is empty
2067 ScDPLevel::~ScDPLevel()
2069 //! release pSource
2071 if ( pMembers )
2072 pMembers->release(); // ref-counted
2075 void ScDPLevel::EvaluateSortOrder()
2077 switch (aSortInfo.Mode)
2079 case sheet::DataPilotFieldSortMode::DATA:
2081 // find index of measure (index among data dimensions)
2083 long nMeasureCount = pSource->GetDataDimensionCount();
2084 for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++)
2086 if (pSource->GetDataDimName(nMeasure).equals(aSortInfo.Field))
2088 nSortMeasure = nMeasure;
2089 break;
2093 //! error if not found?
2095 break;
2096 case sheet::DataPilotFieldSortMode::MANUAL:
2097 case sheet::DataPilotFieldSortMode::NAME:
2099 ScDPMembers* pLocalMembers = GetMembersObject();
2100 long nCount = pLocalMembers->getCount();
2102 aGlobalOrder.resize( nCount );
2103 for (long nPos=0; nPos<nCount; nPos++)
2104 aGlobalOrder[nPos] = nPos;
2106 // allow manual or name (manual is always ascending)
2107 sal_Bool bAscending = ( aSortInfo.Mode == sheet::DataPilotFieldSortMode::MANUAL || aSortInfo.IsAscending );
2108 ScDPGlobalMembersOrder aComp( *this, bAscending );
2109 ::std::sort( aGlobalOrder.begin(), aGlobalOrder.end(), aComp );
2111 break;
2114 if ( aAutoShowInfo.IsEnabled )
2116 // find index of measure (index among data dimensions)
2118 long nMeasureCount = pSource->GetDataDimensionCount();
2119 for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++)
2121 if (pSource->GetDataDimName(nMeasure).equals(aAutoShowInfo.DataField))
2123 nAutoMeasure = nMeasure;
2124 break;
2128 //! error if not found?
2132 void ScDPLevel::SetEnableLayout(bool bSet)
2134 bEnableLayout = bSet;
2137 ScDPMembers* ScDPLevel::GetMembersObject()
2139 if (!pMembers)
2141 pMembers = new ScDPMembers( pSource, nDim, nHier, nLev );
2142 pMembers->acquire(); // ref-counted
2144 return pMembers;
2147 uno::Reference<container::XNameAccess> SAL_CALL ScDPLevel::getMembers() throw(uno::RuntimeException)
2149 return GetMembersObject();
2152 uno::Sequence<sheet::MemberResult> SAL_CALL ScDPLevel::getResults() throw(uno::RuntimeException)
2154 const uno::Sequence<sheet::MemberResult>* pRes = pSource->GetMemberResults( this );
2155 if (pRes)
2156 return *pRes;
2158 return uno::Sequence<sheet::MemberResult>(0); //! Error?
2161 OUString SAL_CALL ScDPLevel::getName() throw(uno::RuntimeException)
2163 long nSrcDim = pSource->GetSourceDim( nDim );
2164 if ( pSource->IsDateDimension( nSrcDim ) )
2166 OUString aRet; //! globstr-ID !!!!
2168 if ( nHier == SC_DAPI_HIERARCHY_QUARTER )
2170 switch ( nLev )
2172 case SC_DAPI_LEVEL_YEAR:
2173 aRet = "Year";
2174 break;
2175 case SC_DAPI_LEVEL_QUARTER:
2176 aRet = "Quarter";
2177 break;
2178 case SC_DAPI_LEVEL_MONTH:
2179 aRet = "Month";
2180 break;
2181 case SC_DAPI_LEVEL_DAY:
2182 aRet = "Day";
2183 break;
2184 default:
2185 OSL_FAIL( "ScDPLevel::getName: unexpected level" );
2186 break;
2189 else if ( nHier == SC_DAPI_HIERARCHY_WEEK )
2191 switch ( nLev )
2193 case SC_DAPI_LEVEL_YEAR:
2194 aRet = "Year";
2195 break;
2196 case SC_DAPI_LEVEL_WEEK:
2197 aRet = "Week";
2198 break;
2199 case SC_DAPI_LEVEL_WEEKDAY:
2200 aRet = "Weekday";
2201 break;
2202 default:
2203 OSL_FAIL( "ScDPLevel::getName: unexpected level" );
2204 break;
2207 if (!aRet.isEmpty())
2208 return aRet;
2211 ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim);
2212 if (!pDim)
2213 return OUString();
2215 return pDim->getName();
2218 void SAL_CALL ScDPLevel::setName( const OUString& /* rNewName */ ) throw(uno::RuntimeException)
2220 OSL_FAIL("not implemented"); //! exception?
2223 uno::Sequence<sheet::GeneralFunction> ScDPLevel::getSubTotals() const
2225 //! separate functions for settings and evaluation?
2227 long nSrcDim = pSource->GetSourceDim( nDim );
2228 if ( !pSource->SubTotalAllowed( nSrcDim ) )
2229 return uno::Sequence<sheet::GeneralFunction>(0);
2231 return aSubTotals;
2234 bool ScDPLevel::getShowEmpty() const
2236 return bShowEmpty;
2239 // XPropertySet
2241 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPLevel::getPropertySetInfo()
2242 throw(uno::RuntimeException)
2244 SolarMutexGuard aGuard;
2246 static const SfxItemPropertyMapEntry aDPLevelMap_Impl[] =
2248 //! change type of AutoShow/Layout/Sorting to API struct when available
2249 {MAP_CHAR_LEN(SC_UNO_DP_AUTOSHOW), 0, &getCppuType((sheet::DataPilotFieldAutoShowInfo*)0), 0, 0 },
2250 {MAP_CHAR_LEN(SC_UNO_DP_LAYOUT), 0, &getCppuType((sheet::DataPilotFieldLayoutInfo*)0), 0, 0 },
2251 {MAP_CHAR_LEN(SC_UNO_DP_SHOWEMPTY), 0, &getBooleanCppuType(), 0, 0 },
2252 {MAP_CHAR_LEN(SC_UNO_DP_SORTING), 0, &getCppuType((sheet::DataPilotFieldSortInfo*)0), 0, 0 },
2253 {MAP_CHAR_LEN(SC_UNO_DP_SUBTOTAL), 0, &getCppuType((uno::Sequence<sheet::GeneralFunction>*)0), 0, 0 },
2254 {0,0,0,0,0,0}
2256 static uno::Reference<beans::XPropertySetInfo> aRef =
2257 new SfxItemPropertySetInfo( aDPLevelMap_Impl );
2258 return aRef;
2261 void SAL_CALL ScDPLevel::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
2262 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
2263 lang::IllegalArgumentException, lang::WrappedTargetException,
2264 uno::RuntimeException)
2266 if ( aPropertyName.equalsAscii( SC_UNO_DP_SHOWEMPTY ) )
2267 bShowEmpty = lcl_GetBoolFromAny(aValue);
2268 else if ( aPropertyName.equalsAscii( SC_UNO_DP_SUBTOTAL ) )
2269 aValue >>= aSubTotals;
2270 else if ( aPropertyName.equalsAscii( SC_UNO_DP_SORTING ) )
2271 aValue >>= aSortInfo;
2272 else if ( aPropertyName.equalsAscii( SC_UNO_DP_AUTOSHOW ) )
2273 aValue >>= aAutoShowInfo;
2274 else if ( aPropertyName.equalsAscii( SC_UNO_DP_LAYOUT ) )
2275 aValue >>= aLayoutInfo;
2276 else
2278 OSL_FAIL("unknown property");
2282 uno::Any SAL_CALL ScDPLevel::getPropertyValue( const OUString& aPropertyName )
2283 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
2284 uno::RuntimeException)
2286 uno::Any aRet;
2287 if ( aPropertyName.equalsAscii( SC_UNO_DP_SHOWEMPTY ) )
2288 lcl_SetBoolInAny(aRet, bShowEmpty);
2289 else if ( aPropertyName.equalsAscii( SC_UNO_DP_SUBTOTAL ) )
2291 uno::Sequence<sheet::GeneralFunction> aSeq = getSubTotals(); //! avoid extra copy?
2292 aRet <<= aSeq;
2294 else if ( aPropertyName.equalsAscii( SC_UNO_DP_SORTING ) )
2295 aRet <<= aSortInfo;
2296 else if ( aPropertyName.equalsAscii( SC_UNO_DP_AUTOSHOW ) )
2297 aRet <<= aAutoShowInfo;
2298 else if ( aPropertyName.equalsAscii( SC_UNO_DP_LAYOUT ) )
2299 aRet <<= aLayoutInfo;
2300 else if (aPropertyName.equalsAscii(SC_UNO_DP_LAYOUTNAME))
2302 // read only property
2303 long nSrcDim = pSource->GetSourceDim(nDim);
2304 ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim);
2305 if (!pDim)
2306 return aRet;
2308 const OUString* pLayoutName = pDim->GetLayoutName();
2309 if (!pLayoutName)
2310 return aRet;
2312 aRet <<= *pLayoutName;
2314 else
2316 OSL_FAIL("unknown property");
2318 return aRet;
2321 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPLevel )
2323 // -----------------------------------------------------------------------
2325 ScDPMembers::ScDPMembers( ScDPSource* pSrc, long nD, long nH, long nL ) :
2326 pSource( pSrc ),
2327 nDim( nD ),
2328 nHier( nH ),
2329 nLev( nL )
2331 //! hold pSource
2333 long nSrcDim = pSource->GetSourceDim( nDim );
2334 if ( pSource->IsDataLayoutDimension(nSrcDim) )
2335 nMbrCount = pSource->GetDataDimensionCount();
2336 else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
2338 nMbrCount = 0;
2339 if ( nHier == SC_DAPI_HIERARCHY_QUARTER )
2341 switch (nLev)
2343 case SC_DAPI_LEVEL_YEAR:
2345 const ScDPItemData* pLastNumData = NULL;
2346 for ( SCROW n = 0 ;n <GetSrcItemsCount() ; n-- )
2348 const ScDPItemData* pData = GetSrcItemDataByIndex( n );
2349 if ( pData && pData->HasStringData() )
2350 break;
2351 else
2352 pLastNumData = pData;
2355 if ( pLastNumData )
2357 const ScDPItemData* pFirstData = GetSrcItemDataByIndex( 0 );
2358 double fFirstVal = pFirstData->GetValue();
2359 double fLastVal = pLastNumData->GetValue();
2361 long nFirstYear = pSource->GetData()->GetDatePart(
2362 (long)::rtl::math::approxFloor( fFirstVal ),
2363 nHier, nLev );
2364 long nLastYear = pSource->GetData()->GetDatePart(
2365 (long)::rtl::math::approxFloor( fLastVal ),
2366 nHier, nLev );
2368 nMbrCount = nLastYear + 1 - nFirstYear;
2370 else
2371 nMbrCount = 0; // no values
2373 break;
2374 case SC_DAPI_LEVEL_QUARTER: nMbrCount = 4; break;
2375 case SC_DAPI_LEVEL_MONTH: nMbrCount = 12; break;
2376 case SC_DAPI_LEVEL_DAY: nMbrCount = 31; break;
2377 default:
2378 OSL_FAIL( "ScDPMembers::ScDPMembers: unexpected level" );
2379 break;
2382 else if ( nHier == SC_DAPI_HIERARCHY_WEEK )
2384 switch (nLev)
2386 case SC_DAPI_LEVEL_YEAR: nMbrCount = 1; break; //! get years from source
2387 case SC_DAPI_LEVEL_WEEK: nMbrCount = 53; break;
2388 case SC_DAPI_LEVEL_WEEKDAY: nMbrCount = 7; break;
2389 default:
2390 OSL_FAIL( "ScDPMembers::ScDPMembers: unexpected level" );
2391 break;
2395 else
2396 nMbrCount = pSource->GetData()->GetMembersCount( nSrcDim );
2399 ScDPMembers::~ScDPMembers()
2403 // XNameAccess implementation using getCount/getByIndex
2405 sal_Int32 ScDPMembers::GetIndexFromName( const OUString& rName ) const
2407 if ( aHashMap.empty() )
2409 // store the index for each name
2411 sal_Int32 nCount = getCount();
2412 for (sal_Int32 i=0; i<nCount; i++)
2413 aHashMap[ getByIndex(i)->getName() ] = i;
2416 ScDPMembersHashMap::const_iterator aIter = aHashMap.find( rName );
2417 if ( aIter != aHashMap.end() )
2418 return aIter->second; // found index
2419 else
2420 return -1; // not found
2423 uno::Any SAL_CALL ScDPMembers::getByName( const OUString& aName )
2424 throw(container::NoSuchElementException,
2425 lang::WrappedTargetException, uno::RuntimeException)
2427 sal_Int32 nIndex = GetIndexFromName( aName );
2428 if ( nIndex >= 0 )
2430 uno::Reference<container::XNamed> xNamed = getByIndex(nIndex);
2431 uno::Any aRet;
2432 aRet <<= xNamed;
2433 return aRet;
2436 throw container::NoSuchElementException();
2439 uno::Sequence<OUString> SAL_CALL ScDPMembers::getElementNames() throw(uno::RuntimeException)
2441 // Return list of names in sorted order,
2442 // so it's displayed in that order in the field options dialog.
2443 // Sorting is done at the level object (parent of this).
2445 ScDPLevel* pLevel = pSource->GetDimensionsObject()->getByIndex(nDim)->
2446 GetHierarchiesObject()->getByIndex(nHier)->GetLevelsObject()->getByIndex(nLev);
2447 pLevel->EvaluateSortOrder();
2448 const std::vector<sal_Int32>& rGlobalOrder = pLevel->GetGlobalOrder();
2449 bool bSort = !rGlobalOrder.empty();
2451 long nCount = getCount();
2452 uno::Sequence<OUString> aSeq(nCount);
2453 OUString* pArr = aSeq.getArray();
2454 for (long i=0; i<nCount; i++)
2455 pArr[i] = getByIndex(bSort ? rGlobalOrder[i] : i)->getName();
2456 return aSeq;
2459 sal_Bool SAL_CALL ScDPMembers::hasByName( const OUString& aName ) throw(uno::RuntimeException)
2461 return ( GetIndexFromName( aName ) >= 0 );
2464 uno::Type SAL_CALL ScDPMembers::getElementType() throw(uno::RuntimeException)
2466 return getCppuType((uno::Reference<container::XNamed>*)0);
2469 sal_Bool SAL_CALL ScDPMembers::hasElements() throw(uno::RuntimeException)
2471 return ( getCount() > 0 );
2474 // end of XNameAccess implementation
2476 long ScDPMembers::getCount() const
2478 return nMbrCount;
2481 long ScDPMembers::getMinMembers() const
2483 // used in lcl_CountMinMembers
2485 long nVisCount = 0;
2486 if (!maMembers.empty())
2488 MembersType::const_iterator it = maMembers.begin(), itEnd = maMembers.end();
2489 for (; it != itEnd; ++it)
2491 // count only visible with details (default is true for both)
2492 const rtl::Reference<ScDPMember>& pMbr = *it;
2493 if (!pMbr.get() || (pMbr->isVisible() && pMbr->getShowDetails()))
2494 ++nVisCount;
2497 else
2498 nVisCount = nMbrCount; // default for all
2500 return nVisCount;
2503 ScDPMember* ScDPMembers::getByIndex(long nIndex) const
2505 // result of GetColumnEntries must not change between ScDPMembers ctor
2506 // and all calls to getByIndex
2508 if ( nIndex >= 0 && nIndex < nMbrCount )
2510 if (maMembers.empty())
2511 maMembers.resize(nMbrCount);
2513 if (!maMembers[nIndex].get())
2515 rtl::Reference<ScDPMember> pNew;
2516 long nSrcDim = pSource->GetSourceDim( nDim );
2517 if ( pSource->IsDataLayoutDimension(nSrcDim) )
2519 // empty name (never shown, not used for lookup)
2520 pNew.set(new ScDPMember(pSource, nDim, nHier, nLev, 0));
2522 else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
2524 sal_Int32 nGroupBy = 0;
2525 sal_Int32 nVal = 0;
2526 OUString aName;
2528 if ( nLev == SC_DAPI_LEVEL_YEAR ) // YEAR is in both hierarchies
2530 //! cache year range here!
2532 double fFirstVal = pSource->GetData()->GetMemberByIndex( nSrcDim, 0 )->GetValue();
2533 long nFirstYear = pSource->GetData()->GetDatePart(
2534 (long)::rtl::math::approxFloor( fFirstVal ),
2535 nHier, nLev );
2537 nVal = nFirstYear + nIndex;
2539 else if ( nHier == SC_DAPI_HIERARCHY_WEEK && nLev == SC_DAPI_LEVEL_WEEKDAY )
2541 nVal = nIndex; // DayOfWeek is 0-based
2542 aName = ScGlobal::GetCalendar()->getDisplayName(
2543 ::com::sun::star::i18n::CalendarDisplayIndex::DAY,
2544 sal::static_int_cast<sal_Int16>(nVal), 0 );
2546 else if ( nHier == SC_DAPI_HIERARCHY_QUARTER && nLev == SC_DAPI_LEVEL_MONTH )
2548 nVal = nIndex; // Month is 0-based
2549 aName = ScGlobal::GetCalendar()->getDisplayName(
2550 ::com::sun::star::i18n::CalendarDisplayIndex::MONTH,
2551 sal::static_int_cast<sal_Int16>(nVal), 0 );
2553 else
2554 nVal = nIndex + 1; // Quarter, Day, Week are 1-based
2556 switch (nLev)
2558 case SC_DAPI_LEVEL_YEAR:
2559 nGroupBy = sheet::DataPilotFieldGroupBy::YEARS;
2560 break;
2561 case SC_DAPI_LEVEL_QUARTER:
2562 case SC_DAPI_LEVEL_WEEK:
2563 nGroupBy = sheet::DataPilotFieldGroupBy::QUARTERS;
2564 break;
2565 case SC_DAPI_LEVEL_MONTH:
2566 case SC_DAPI_LEVEL_WEEKDAY:
2567 nGroupBy = sheet::DataPilotFieldGroupBy::MONTHS;
2568 break;
2569 case SC_DAPI_LEVEL_DAY:
2570 nGroupBy = sheet::DataPilotFieldGroupBy::DAYS;
2571 break;
2572 default:
2575 if (aName.isEmpty())
2576 aName = OUString::number(nVal);
2578 ScDPItemData aData(nGroupBy, nVal);
2579 SCROW nId = pSource->GetCache()->GetIdByItemData(nDim, aData);
2580 pNew.set(new ScDPMember(pSource, nDim, nHier, nLev, nId));
2582 else
2584 const std::vector<SCROW>& memberIndexs = pSource->GetData()->GetColumnEntries(nSrcDim);
2585 pNew.set(new ScDPMember(pSource, nDim, nHier, nLev, memberIndexs[nIndex]));
2587 maMembers[nIndex] = pNew;
2590 return maMembers[nIndex].get();
2593 return NULL; //! exception?
2596 // -----------------------------------------------------------------------
2598 ScDPMember::ScDPMember(
2599 ScDPSource* pSrc, long nD, long nH, long nL, SCROW nIndex) :
2600 pSource( pSrc ),
2601 nDim( nD ),
2602 nHier( nH ),
2603 nLev( nL ),
2604 mnDataId( nIndex ),
2605 mpLayoutName(NULL),
2606 nPosition( -1 ),
2607 bVisible( true ),
2608 bShowDet( true )
2610 //! hold pSource
2613 ScDPMember::~ScDPMember()
2615 //! release pSource
2618 bool ScDPMember::IsNamedItem(SCROW nIndex) const
2620 long nSrcDim = pSource->GetSourceDim( nDim );
2621 if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
2623 const ScDPItemData* pData = pSource->GetCache()->GetItemDataById(nDim, nIndex);
2624 if (pData->IsValue())
2626 long nComp = pSource->GetData()->GetDatePart(
2627 (long)::rtl::math::approxFloor( pData->GetValue() ),
2628 nHier, nLev );
2629 // fValue is converted from integer, so simple comparison works
2630 const ScDPItemData* pData2 = GetItemData();
2631 return pData2 && nComp == pData2->GetValue();
2635 return nIndex == mnDataId;
2638 sal_Int32 ScDPMember::Compare( const ScDPMember& rOther ) const
2640 if ( nPosition >= 0 )
2642 if ( rOther.nPosition >= 0 )
2644 OSL_ENSURE( nPosition != rOther.nPosition, "same position for two members" );
2645 return ( nPosition < rOther.nPosition ) ? -1 : 1;
2647 else
2649 // only this has a position - members with specified positions come before those without
2650 return -1;
2653 else if ( rOther.nPosition >= 0 )
2655 // only rOther has a position
2656 return 1;
2659 // no positions set - compare names
2660 return pSource->GetData()->Compare( pSource->GetSourceDim(nDim),mnDataId,rOther.GetItemDataId());
2663 void ScDPMember::FillItemData( ScDPItemData& rData ) const
2665 //! handle date hierarchy...
2667 const ScDPItemData* pData = GetItemData();
2668 rData = (pData ? *pData : ScDPItemData());
2671 const OUString* ScDPMember::GetLayoutName() const
2673 return mpLayoutName.get();
2676 long ScDPMember::GetDim() const
2678 return nDim;
2681 OUString ScDPMember::GetNameStr() const
2683 const ScDPItemData* pData = GetItemData();
2684 if (pData)
2685 return pSource->GetData()->GetFormattedString(nDim, *pData);
2686 return OUString();
2689 OUString SAL_CALL ScDPMember::getName() throw(uno::RuntimeException)
2691 return GetNameStr();
2694 void SAL_CALL ScDPMember::setName( const OUString& /* rNewName */ ) throw(uno::RuntimeException)
2696 OSL_FAIL("not implemented"); //! exception?
2699 bool ScDPMember::isVisible() const
2701 return bVisible;
2704 bool ScDPMember::getShowDetails() const
2706 return bShowDet;
2709 // XPropertySet
2711 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPMember::getPropertySetInfo()
2712 throw(uno::RuntimeException)
2714 SolarMutexGuard aGuard;
2716 static const SfxItemPropertyMapEntry aDPMemberMap_Impl[] =
2718 {MAP_CHAR_LEN(SC_UNO_DP_ISVISIBLE), 0, &getBooleanCppuType(), 0, 0 },
2719 {MAP_CHAR_LEN(SC_UNO_DP_POSITION), 0, &getCppuType((sal_Int32*)0), 0, 0 },
2720 {MAP_CHAR_LEN(SC_UNO_DP_SHOWDETAILS), 0, &getBooleanCppuType(), 0, 0 },
2721 {MAP_CHAR_LEN(SC_UNO_DP_LAYOUTNAME), 0, &getCppuType(static_cast<OUString*>(0)), 0, 0 },
2722 {0,0,0,0,0,0}
2724 static uno::Reference<beans::XPropertySetInfo> aRef =
2725 new SfxItemPropertySetInfo( aDPMemberMap_Impl );
2726 return aRef;
2729 void SAL_CALL ScDPMember::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
2730 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
2731 lang::IllegalArgumentException, lang::WrappedTargetException,
2732 uno::RuntimeException)
2734 if ( aPropertyName.equalsAscii( SC_UNO_DP_ISVISIBLE ) )
2735 bVisible = lcl_GetBoolFromAny(aValue);
2736 else if ( aPropertyName.equalsAscii( SC_UNO_DP_SHOWDETAILS ) )
2737 bShowDet = lcl_GetBoolFromAny(aValue);
2738 else if ( aPropertyName.equalsAscii( SC_UNO_DP_POSITION ) )
2739 aValue >>= nPosition;
2740 else if (aPropertyName.equalsAscii(SC_UNO_DP_LAYOUTNAME))
2742 OUString aName;
2743 if (aValue >>= aName)
2744 mpLayoutName.reset(new OUString(aName));
2746 else
2748 OSL_FAIL("unknown property");
2752 uno::Any SAL_CALL ScDPMember::getPropertyValue( const OUString& aPropertyName )
2753 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
2754 uno::RuntimeException)
2756 uno::Any aRet;
2757 if ( aPropertyName.equalsAscii( SC_UNO_DP_ISVISIBLE ) )
2758 lcl_SetBoolInAny(aRet, bVisible);
2759 else if ( aPropertyName.equalsAscii( SC_UNO_DP_SHOWDETAILS ) )
2760 lcl_SetBoolInAny(aRet, bShowDet);
2761 else if ( aPropertyName.equalsAscii( SC_UNO_DP_POSITION ) )
2762 aRet <<= nPosition;
2763 else if (aPropertyName.equalsAscii(SC_UNO_DP_LAYOUTNAME))
2764 aRet <<= mpLayoutName.get() ? *mpLayoutName : OUString();
2765 else
2767 OSL_FAIL("unknown property");
2769 return aRet;
2772 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPMember )
2775 const ScDPCache* ScDPSource::GetCache()
2777 OSL_ENSURE( GetData() , "empty ScDPTableData pointer");
2778 return ( GetData()!=NULL) ? GetData()->GetCacheTable().getCache() : NULL ;
2781 const ScDPItemData* ScDPMember::GetItemData() const
2783 const ScDPItemData* pData = pSource->GetItemDataById(nDim, mnDataId);
2784 SAL_WARN_IF( !pData, "sc", "ScDPMember::GetItemData: what data? nDim " << nDim << ", mnDataId " << mnDataId);
2785 return pData;
2788 const ScDPItemData* ScDPSource::GetItemDataById(long nDim, long nId)
2790 return GetData()->GetMemberById(nDim, nId);
2793 SCROW ScDPSource::GetMemberId(long nDim, const ScDPItemData& rData)
2795 return GetCache()->GetIdByItemData(nDim, rData);
2798 const ScDPItemData* ScDPMembers::GetSrcItemDataByIndex(SCROW nIndex)
2800 const std::vector< SCROW >& memberIds = pSource->GetData()->GetColumnEntries( nDim );
2801 if ( nIndex >= (long )(memberIds.size()) || nIndex < 0 )
2802 return NULL;
2803 SCROW nId = memberIds[ nIndex ];
2804 return pSource->GetItemDataById( nDim, nId );
2807 SCROW ScDPMembers::GetSrcItemsCount()
2809 return pSource->GetData()->GetColumnEntries(nDim).size();
2812 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */