Update ooo320-m1
[ooovba.git] / sc / source / core / data / dptabsrc.cxx
blobe99c2bc2302bbde3e347693de2a38ca6964ceb1f
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dptabsrc.cxx,v $
10 * $Revision: 1.27 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
37 // INCLUDE ---------------------------------------------------------------
39 #include <algorithm>
40 #include <vector>
41 #include <set>
42 #include <hash_map>
43 #include <hash_set>
45 #include <tools/debug.hxx>
46 #include <rtl/math.hxx>
47 #include <svtools/itemprop.hxx>
48 #include <svtools/intitem.hxx>
50 #include "scitems.hxx"
51 #include "document.hxx"
52 #include "docpool.hxx"
53 #include "patattr.hxx"
54 #include "cell.hxx"
56 #include "dptabsrc.hxx"
57 #include "dptabres.hxx"
58 #include "dptabdat.hxx"
59 #include "global.hxx"
60 #include "collect.hxx"
61 #include "datauno.hxx" // ScDataUnoConversion
62 #include "unoguard.hxx"
63 #include "miscuno.hxx"
64 #include "unonames.hxx"
66 #include <com/sun/star/beans/PropertyAttribute.hpp>
67 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
68 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
69 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
70 #include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
71 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
72 #include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
73 #include <com/sun/star/table/CellAddress.hpp>
75 #include <unotools/collatorwrapper.hxx>
76 #include <unotools/calendarwrapper.hxx>
77 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
79 using namespace com::sun::star;
80 using ::std::vector;
81 using ::std::set;
82 using ::std::hash_map;
83 using ::std::hash_set;
84 using ::com::sun::star::uno::Reference;
85 using ::com::sun::star::uno::Sequence;
86 using ::com::sun::star::uno::Any;
87 using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
88 using ::rtl::OUString;
90 // -----------------------------------------------------------------------
92 #define SC_MINCOUNT_LIMIT 1000000
94 // -----------------------------------------------------------------------
96 SC_SIMPLE_SERVICE_INFO( ScDPSource, "ScDPSource", "com.sun.star.sheet.DataPilotSource" )
97 SC_SIMPLE_SERVICE_INFO( ScDPDimensions, "ScDPDimensions", "com.sun.star.sheet.DataPilotSourceDimensions" )
98 SC_SIMPLE_SERVICE_INFO( ScDPDimension, "ScDPDimension", "com.sun.star.sheet.DataPilotSourceDimension" )
99 SC_SIMPLE_SERVICE_INFO( ScDPHierarchies, "ScDPHierarchies", "com.sun.star.sheet.DataPilotSourceHierarcies" )
100 SC_SIMPLE_SERVICE_INFO( ScDPHierarchy, "ScDPHierarchy", "com.sun.star.sheet.DataPilotSourceHierarcy" )
101 SC_SIMPLE_SERVICE_INFO( ScDPLevels, "ScDPLevels", "com.sun.star.sheet.DataPilotSourceLevels" )
102 SC_SIMPLE_SERVICE_INFO( ScDPLevel, "ScDPLevel", "com.sun.star.sheet.DataPilotSourceLevel" )
103 SC_SIMPLE_SERVICE_INFO( ScDPMembers, "ScDPMembers", "com.sun.star.sheet.DataPilotSourceMembers" )
104 SC_SIMPLE_SERVICE_INFO( ScDPMember, "ScDPMember", "com.sun.star.sheet.DataPilotSourceMember" )
106 // -----------------------------------------------------------------------
108 // property maps for PropertySetInfo
109 // DataDescription / NumberFormat are internal
111 // -----------------------------------------------------------------------
113 //! move to a header?
114 BOOL lcl_GetBoolFromAny( const uno::Any& aAny )
116 if ( aAny.getValueTypeClass() == uno::TypeClass_BOOLEAN )
117 return *(sal_Bool*)aAny.getValue();
118 return FALSE;
121 void lcl_SetBoolInAny( uno::Any& rAny, BOOL bValue )
123 rAny.setValue( &bValue, getBooleanCppuType() );
126 // -----------------------------------------------------------------------
128 ScDPSource::ScDPSource( ScDPTableData* pD ) :
129 pData( pD ),
130 pDimensions( NULL ),
131 nColDimCount( 0 ),
132 nRowDimCount( 0 ),
133 nDataDimCount( 0 ),
134 nPageDimCount( 0 ),
135 bColumnGrand( TRUE ), // default is true
136 bRowGrand( TRUE ),
137 bIgnoreEmptyRows( FALSE ),
138 bRepeatIfEmpty( FALSE ),
139 nDupCount( 0 ),
140 pResData( NULL ),
141 pColResRoot( NULL ),
142 pRowResRoot( NULL ),
143 pColResults( NULL ),
144 pRowResults( NULL ),
145 bResultOverflow( FALSE ),
146 mpGrandTotalName(NULL)
148 pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
151 ScDPSource::~ScDPSource()
153 if (pDimensions)
154 pDimensions->release(); // ref-counted
156 //! free lists
158 delete[] pColResults;
159 delete[] pRowResults;
161 delete pColResRoot;
162 delete pRowResRoot;
163 delete pResData;
166 void ScDPSource::SetGrandTotalName(const ::rtl::OUString& rName)
168 mpGrandTotalName.reset(new ::rtl::OUString(rName));
171 const ::rtl::OUString* ScDPSource::GetGrandTotalName() const
173 return mpGrandTotalName.get();
176 USHORT ScDPSource::GetOrientation(long nColumn)
178 long i;
179 for (i=0; i<nColDimCount; i++)
180 if (nColDims[i] == nColumn)
181 return sheet::DataPilotFieldOrientation_COLUMN;
182 for (i=0; i<nRowDimCount; i++)
183 if (nRowDims[i] == nColumn)
184 return sheet::DataPilotFieldOrientation_ROW;
185 for (i=0; i<nDataDimCount; i++)
186 if (nDataDims[i] == nColumn)
187 return sheet::DataPilotFieldOrientation_DATA;
188 for (i=0; i<nPageDimCount; i++)
189 if (nPageDims[i] == nColumn)
190 return sheet::DataPilotFieldOrientation_PAGE;
191 return sheet::DataPilotFieldOrientation_HIDDEN;
194 long ScDPSource::GetDataDimensionCount()
196 return nDataDimCount;
199 ScDPDimension* ScDPSource::GetDataDimension(long nIndex)
201 if (nIndex < 0 || nIndex >= nDataDimCount)
202 return NULL;
204 long nDimIndex = nDataDims[nIndex];
205 return GetDimensionsObject()->getByIndex(nDimIndex);
208 String ScDPSource::GetDataDimName( long nIndex )
210 String aRet;
211 ScDPDimension* pDim = GetDataDimension(nIndex);
212 if (pDim)
213 aRet = String(pDim->getName());
214 return aRet;
217 long ScDPSource::GetPosition(long nColumn)
219 long i;
220 for (i=0; i<nColDimCount; i++)
221 if (nColDims[i] == nColumn)
222 return i;
223 for (i=0; i<nRowDimCount; i++)
224 if (nRowDims[i] == nColumn)
225 return i;
226 for (i=0; i<nDataDimCount; i++)
227 if (nDataDims[i] == nColumn)
228 return i;
229 for (i=0; i<nPageDimCount; i++)
230 if (nPageDims[i] == nColumn)
231 return i;
232 return 0;
235 BOOL lcl_TestSubTotal( BOOL& rAllowed, long nColumn, long* pArray, long nCount, ScDPSource* pSource )
237 for (long i=0; i<nCount; i++)
238 if (pArray[i] == nColumn)
240 // no subtotals for data layout dim, no matter where
241 if ( pSource->IsDataLayoutDimension(nColumn) )
242 rAllowed = FALSE;
243 else
245 // no subtotals if no other dim but data layout follows
246 long nNextIndex = i+1;
247 if ( nNextIndex < nCount && pSource->IsDataLayoutDimension(pArray[nNextIndex]) )
248 ++nNextIndex;
249 if ( nNextIndex >= nCount )
250 rAllowed = FALSE;
253 return TRUE; // found
255 return FALSE;
258 BOOL ScDPSource::SubTotalAllowed(long nColumn)
260 //! cache this at ScDPResultData
261 BOOL bAllowed = TRUE;
262 if ( lcl_TestSubTotal( bAllowed, nColumn, nColDims, nColDimCount, this ) )
263 return bAllowed;
264 if ( lcl_TestSubTotal( bAllowed, nColumn, nRowDims, nRowDimCount, this ) )
265 return bAllowed;
266 return bAllowed;
269 void lcl_RemoveDim( long nRemove, long* pDims, long& rCount )
271 for (long i=0; i<rCount; i++)
272 if ( pDims[i] == nRemove )
274 for (long j=i; j+1<rCount; j++)
275 pDims[j] = pDims[j+1];
276 --rCount;
277 return;
281 void ScDPSource::SetOrientation(long nColumn, USHORT nNew)
283 //! change to no-op if new orientation is equal to old?
285 // remove from old list
286 lcl_RemoveDim( nColumn, nColDims, nColDimCount );
287 lcl_RemoveDim( nColumn, nRowDims, nRowDimCount );
288 lcl_RemoveDim( nColumn, nDataDims, nDataDimCount );
289 lcl_RemoveDim( nColumn, nPageDims, nPageDimCount );
291 // add to new list
292 switch (nNew)
294 case sheet::DataPilotFieldOrientation_COLUMN:
295 nColDims[nColDimCount++] = nColumn;
296 break;
297 case sheet::DataPilotFieldOrientation_ROW:
298 nRowDims[nRowDimCount++] = nColumn;
299 break;
300 case sheet::DataPilotFieldOrientation_DATA:
301 nDataDims[nDataDimCount++] = nColumn;
302 break;
303 case sheet::DataPilotFieldOrientation_PAGE:
304 nPageDims[nPageDimCount++] = nColumn;
305 break;
306 case sheet::DataPilotFieldOrientation_HIDDEN:
307 /* Do not assert HIDDEN as it occurs e.g. while using the
308 csss.XDataPilotTables.createDataPilotDescriptor() function. */
309 break;
310 default:
311 DBG_ERROR( "ScDPSource::SetOrientation: unexpected orientation" );
312 break;
316 BOOL ScDPSource::IsDataLayoutDimension(long nDim)
318 return nDim == pData->GetColumnCount();
321 USHORT ScDPSource::GetDataLayoutOrientation()
323 return GetOrientation(pData->GetColumnCount());
326 BOOL ScDPSource::IsDateDimension(long nDim)
328 return pData->IsDateDimension(nDim);
331 ScDPDimensions* ScDPSource::GetDimensionsObject()
333 if (!pDimensions)
335 pDimensions = new ScDPDimensions(this);
336 pDimensions->acquire(); // ref-counted
338 return pDimensions;
341 uno::Reference<container::XNameAccess> SAL_CALL ScDPSource::getDimensions() throw(uno::RuntimeException)
343 return GetDimensionsObject();
346 void ScDPSource::SetDupCount( long nNew )
348 nDupCount = nNew;
351 ScDPDimension* ScDPSource::AddDuplicated(long /* nSource */, const String& rNewName)
353 DBG_ASSERT( pDimensions, "AddDuplicated without dimensions?" );
355 // re-use
357 long nOldDimCount = pDimensions->getCount();
358 for (long i=0; i<nOldDimCount; i++)
360 ScDPDimension* pDim = pDimensions->getByIndex(i);
361 if (pDim && String(pDim->getName()) == rNewName)
363 //! test if pDim is a duplicate of source
364 return pDim;
368 SetDupCount( nDupCount + 1 );
369 pDimensions->CountChanged(); // uses nDupCount
371 return pDimensions->getByIndex( pDimensions->getCount() - 1 );
374 long ScDPSource::GetSourceDim(long nDim)
376 // original source dimension or data layout dimension?
377 if ( nDim <= pData->GetColumnCount() )
378 return nDim;
380 if ( nDim < pDimensions->getCount() )
382 ScDPDimension* pDimObj = pDimensions->getByIndex( nDim );
383 if ( pDimObj )
385 long nSource = pDimObj->GetSourceDim();
386 if ( nSource >= 0 )
387 return nSource;
391 DBG_ERROR("GetSourceDim: wrong dim");
392 return nDim;
395 uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResults()
396 throw(uno::RuntimeException)
398 CreateRes_Impl(); // create pColResRoot and pRowResRoot
400 if ( bResultOverflow ) // set in CreateRes_Impl
402 // no results available
403 throw uno::RuntimeException();
406 long nColCount = pColResRoot->GetSize(pResData->GetColStartMeasure());
407 long nRowCount = pRowResRoot->GetSize(pResData->GetRowStartMeasure());
409 // allocate full sequence
410 //! leave out empty rows???
412 uno::Sequence< uno::Sequence<sheet::DataResult> > aSeq( nRowCount );
413 uno::Sequence<sheet::DataResult>* pRowAry = aSeq.getArray();
414 for (long nRow = 0; nRow < nRowCount; nRow++)
416 uno::Sequence<sheet::DataResult> aColSeq( nColCount );
417 // use default values of DataResult
418 pRowAry[nRow] = aColSeq;
421 long nSeqRow = 0;
422 pRowResRoot->FillDataResults( pColResRoot, aSeq, nSeqRow, pResData->GetRowStartMeasure() );
424 return aSeq;
427 void SAL_CALL ScDPSource::refresh() throw(uno::RuntimeException)
429 disposeData();
432 void SAL_CALL ScDPSource::addRefreshListener( const uno::Reference<util::XRefreshListener >& )
433 throw(uno::RuntimeException)
435 DBG_ERROR("not implemented"); //! exception?
438 void SAL_CALL ScDPSource::removeRefreshListener( const uno::Reference<util::XRefreshListener >& )
439 throw(uno::RuntimeException)
441 DBG_ERROR("not implemented"); //! exception?
444 Sequence< Sequence<Any> > SAL_CALL ScDPSource::getDrillDownData(const Sequence<sheet::DataPilotFieldFilter>& aFilters)
445 throw (uno::RuntimeException)
447 long nColumnCount = GetData()->GetColumnCount();
448 ScSimpleSharedString& rSharedString = GetData()->GetSharedString();
450 typedef hash_map<String, long, ScStringHashCode> FieldNameMapType;
451 FieldNameMapType aFieldNames;
452 for (long i = 0; i < nColumnCount; ++i)
454 aFieldNames.insert(
455 FieldNameMapType::value_type(GetData()->getDimensionName(i), i));
458 // collect ScDPItemData for each filtered column
459 vector<ScDPCacheTable::Criterion> aFilterCriteria;
460 sal_Int32 nFilterCount = aFilters.getLength();
461 for (sal_Int32 i = 0; i < nFilterCount; ++i)
463 const sheet::DataPilotFieldFilter& rFilter = aFilters[i];
464 String aFieldName( rFilter.FieldName );
465 for (long nCol = 0; nCol < nColumnCount; ++nCol)
467 if ( aFieldName == pData->getDimensionName(nCol) )
469 ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nCol );
470 ScDPMembers* pMembers = pDim->GetHierarchiesObject()->getByIndex(0)->
471 GetLevelsObject()->getByIndex(0)->GetMembersObject();
472 sal_Int32 nIndex = pMembers->GetIndexFromName( rFilter.MatchValue );
473 if ( nIndex >= 0 )
475 ScDPItemData aItem;
476 pMembers->getByIndex(nIndex)->FillItemData( aItem );
477 aFilterCriteria.push_back( ScDPCacheTable::Criterion() );
478 sal_Int32 nMatchStrId = rSharedString.getStringId(aItem.aString);
479 aFilterCriteria.back().mnFieldIndex = nCol;
480 aFilterCriteria.back().mpFilter.reset(
481 new ScDPCacheTable::SingleFilter(rSharedString, nMatchStrId, aItem.fValue, aItem.bHasValue) );
487 // Take into account the visibilities of field members.
488 ScDPResultVisibilityData aResVisData(rSharedString, this);
489 pRowResRoot->FillVisibilityData(aResVisData);
490 pColResRoot->FillVisibilityData(aResVisData);
491 aResVisData.fillFieldFilters(aFilterCriteria);
493 Sequence< Sequence<Any> > aTabData;
494 hash_set<sal_Int32> aCatDims;
495 GetCategoryDimensionIndices(aCatDims);
496 pData->GetDrillDownData(aFilterCriteria, aCatDims, aTabData);
497 return aTabData;
500 String ScDPSource::getDataDescription()
502 CreateRes_Impl(); // create pResData
504 String aRet;
505 if ( pResData->GetMeasureCount() == 1 )
507 bool bTotalResult = false;
508 aRet = pResData->GetMeasureString( 0, TRUE, SUBTOTAL_FUNC_NONE, bTotalResult );
511 // empty for more than one measure
513 return aRet;
516 BOOL ScDPSource::getColumnGrand() const
518 return bColumnGrand;
521 void ScDPSource::setColumnGrand(BOOL bSet)
523 bColumnGrand = bSet;
526 BOOL ScDPSource::getRowGrand() const
528 return bRowGrand;
531 void ScDPSource::setRowGrand(BOOL bSet)
533 bRowGrand = bSet;
536 BOOL ScDPSource::getIgnoreEmptyRows() const
538 return bIgnoreEmptyRows;
541 void ScDPSource::setIgnoreEmptyRows(BOOL bSet)
543 bIgnoreEmptyRows = bSet;
544 pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
547 BOOL ScDPSource::getRepeatIfEmpty() const
549 return bRepeatIfEmpty;
552 void ScDPSource::setRepeatIfEmpty(BOOL bSet)
554 bRepeatIfEmpty = bSet;
555 pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
558 void ScDPSource::validate() //! ???
560 CreateRes_Impl();
563 void ScDPSource::disposeData()
565 if ( pResData )
567 // reset all data...
569 DELETEZ(pColResRoot);
570 DELETEZ(pRowResRoot);
571 DELETEZ(pResData);
572 delete[] pColResults;
573 delete[] pRowResults;
574 pColResults = NULL;
575 pRowResults = NULL;
576 aColLevelList.Clear();
577 aRowLevelList.Clear();
580 if ( pDimensions )
582 pDimensions->release(); // ref-counted
583 pDimensions = NULL; // settings have to be applied (from SaveData) again!
585 SetDupCount( 0 );
587 //! Test ????
588 nColDimCount = nRowDimCount = nDataDimCount = nPageDimCount = 0;
590 pData->DisposeData(); // cached entries etc.
591 bResultOverflow = FALSE;
594 long lcl_CountMinMembers(const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLevel, long nLevels )
596 // Calculate the product of the member count for those consecutive levels that
597 // have the "show all" flag, one following level, and the data layout dimension.
599 long nTotal = 1;
600 long nDataCount = 1;
601 BOOL bWasShowAll = TRUE;
602 long nPos = nLevels;
603 while ( nPos > 0 )
605 --nPos;
607 if ( nPos+1 < nLevels && ppDim[nPos] == ppDim[nPos+1] )
609 DBG_ERROR("lcl_CountMinMembers: multiple levels from one dimension not implemented");
610 return 0;
613 BOOL bDo = FALSE;
614 if ( ppDim[nPos]->getIsDataLayoutDimension() )
616 // data layout dim doesn't interfere with "show all" flags
617 nDataCount = ppLevel[nPos]->GetMembersObject()->getCount();
618 if ( nDataCount == 0 )
619 nDataCount = 1;
621 else if ( bWasShowAll ) // "show all" set for all following levels?
623 bDo = TRUE;
624 if ( !ppLevel[nPos]->getShowEmpty() )
626 // this level is counted, following ones are not
627 bWasShowAll = FALSE;
630 if ( bDo )
632 long nThisCount = ppLevel[nPos]->GetMembersObject()->getMinMembers();
633 if ( nThisCount == 0 )
635 nTotal = 1; // empty level -> start counting from here
636 //! start with visible elements in this level?
638 else
640 if ( nTotal >= LONG_MAX / nThisCount )
641 return LONG_MAX; // overflow
642 nTotal *= nThisCount;
647 // always include data layout dim, even after restarting
648 if ( nTotal >= LONG_MAX / nDataCount )
649 return LONG_MAX; // overflow
650 nTotal *= nDataCount;
652 return nTotal;
655 long lcl_GetIndexFromName( const rtl::OUString rName, const uno::Sequence<rtl::OUString>& rElements )
657 long nCount = rElements.getLength();
658 const rtl::OUString* pArray = rElements.getConstArray();
659 for (long nPos=0; nPos<nCount; nPos++)
660 if (pArray[nPos] == rName)
661 return nPos;
663 return -1; // not found
666 void ScDPSource::FillCalcInfo(bool bIsRow, ScDPTableData::CalcInfo& rInfo, bool &rHasAutoShow)
668 long* nDims = bIsRow ? nRowDims : nColDims;
669 long nDimCount = bIsRow ? nRowDimCount : nColDimCount;
671 for (long i = 0; i < nDimCount; ++i)
673 ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nDims[i] );
674 long nHierarchy = pDim->getUsedHierarchy();
675 if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() )
676 nHierarchy = 0;
677 ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
678 long nCount = pLevels->getCount();
680 //! Test
681 if ( pDim->getIsDataLayoutDimension() && nDataDimCount < 2 )
682 nCount = 0;
683 //! Test
685 for (long j = 0; j < nCount; ++j)
687 ScDPLevel* pLevel = pLevels->getByIndex(j);
688 pLevel->EvaluateSortOrder();
690 // no layout flags for column fields, only for row fields
691 pLevel->SetEnableLayout( bIsRow );
693 if ( pLevel->GetAutoShow().IsEnabled )
694 rHasAutoShow = TRUE;
696 if (bIsRow)
698 rInfo.aRowLevelDims.push_back(nDims[i]);
699 rInfo.aRowDims.push_back(pDim);
700 rInfo.aRowLevels.push_back(pLevel);
702 else
704 rInfo.aColLevelDims.push_back(nDims[i]);
705 rInfo.aColDims.push_back(pDim);
706 rInfo.aColLevels.push_back(pLevel);
709 pLevel->GetMembersObject(); // initialize for groups
714 void ScDPSource::GetCategoryDimensionIndices(hash_set<sal_Int32>& rCatDims)
716 hash_set<sal_Int32> aCatDims;
717 for (long i = 0; i < nColDimCount; ++i)
719 sal_Int32 nDim = static_cast<sal_Int32>(nColDims[i]);
720 if (!IsDataLayoutDimension(nDim))
721 aCatDims.insert(nDim);
724 for (long i = 0; i < nRowDimCount; ++i)
726 sal_Int32 nDim = static_cast<sal_Int32>(nRowDims[i]);
727 if (!IsDataLayoutDimension(nDim))
728 aCatDims.insert(nDim);
731 for (long i = 0; i < nPageDimCount; ++i)
733 sal_Int32 nDim = static_cast<sal_Int32>(nPageDims[i]);
734 if (!IsDataLayoutDimension(nDim))
735 aCatDims.insert(nDim);
738 rCatDims.swap(aCatDims);
741 void ScDPSource::FilterCacheTableByPageDimensions()
743 ScSimpleSharedString& rSharedString = GetData()->GetSharedString();
745 // filter table by page dimensions.
746 vector<ScDPCacheTable::Criterion> aCriteria;
747 for (long i = 0; i < nPageDimCount; ++i)
749 ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nPageDims[i]);
750 long nField = pDim->GetDimension();
752 ScDPMembers* pMems = pDim->GetHierarchiesObject()->getByIndex(0)->
753 GetLevelsObject()->getByIndex(0)->GetMembersObject();
755 long nMemCount = pMems->getCount();
756 ScDPCacheTable::Criterion aFilter;
757 aFilter.mnFieldIndex = static_cast<sal_Int32>(nField);
758 aFilter.mpFilter.reset(new ScDPCacheTable::GroupFilter(rSharedString));
759 ScDPCacheTable::GroupFilter* pGrpFilter =
760 static_cast<ScDPCacheTable::GroupFilter*>(aFilter.mpFilter.get());
761 for (long j = 0; j < nMemCount; ++j)
763 ScDPMember* pMem = pMems->getByIndex(j);
764 if (pMem->getIsVisible())
766 ScDPItemData aData;
767 pMem->FillItemData(aData);
768 pGrpFilter->addMatchItem(aData.aString, aData.fValue, aData.bHasValue);
771 if (pGrpFilter->getMatchItemCount() < static_cast<size_t>(nMemCount))
772 // there is at least one invisible item. Add this filter criterion to the mix.
773 aCriteria.push_back(aFilter);
775 if (!pDim || !pDim->HasSelectedPage())
776 continue;
778 const ScDPItemData& rData = pDim->GetSelectedData();
779 aCriteria.push_back(ScDPCacheTable::Criterion());
780 ScDPCacheTable::Criterion& r = aCriteria.back();
781 r.mnFieldIndex = static_cast<sal_Int32>(nField);
782 sal_Int32 nStrId = rSharedString.getStringId(rData.aString);
783 r.mpFilter.reset(
784 new ScDPCacheTable::SingleFilter(rSharedString, nStrId, rData.fValue, rData.bHasValue));
786 if (!aCriteria.empty())
788 hash_set<sal_Int32> aCatDims;
789 GetCategoryDimensionIndices(aCatDims);
790 pData->FilterCacheTable(aCriteria, aCatDims);
794 void ScDPSource::CreateRes_Impl()
796 if ( !pResData )
798 USHORT nDataOrient = GetDataLayoutOrientation();
799 if ( nDataDimCount > 1 && ( nDataOrient != sheet::DataPilotFieldOrientation_COLUMN &&
800 nDataOrient != sheet::DataPilotFieldOrientation_ROW ) )
802 // if more than one data dimension, data layout orientation must be set
803 SetOrientation( pData->GetColumnCount(), sheet::DataPilotFieldOrientation_ROW );
804 nDataOrient = sheet::DataPilotFieldOrientation_ROW;
807 // TODO: Aggreate pDataNames, pDataRefValues, nDataRefOrient, and
808 // eDataFunctions into a structure and use vector instead of static
809 // or pointer arrays.
810 String* pDataNames = NULL;
811 sheet::DataPilotFieldReference* pDataRefValues = NULL;
812 ScSubTotalFunc eDataFunctions[SC_DAPI_MAXFIELDS];
813 USHORT nDataRefOrient[SC_DAPI_MAXFIELDS];
814 if (nDataDimCount)
816 pDataNames = new String[nDataDimCount];
817 pDataRefValues = new sheet::DataPilotFieldReference[nDataDimCount];
820 ScDPTableData::CalcInfo aInfo;
823 // LateInit (initialize only those rows/children that are used) can be used unless
824 // any data dimension needs reference values from column/row dimensions
825 BOOL bLateInit = TRUE;
827 // Go through all data dimensions (i.e. fields) and build their meta data
828 // so that they can be passed on to ScDPResultData instance later.
829 // TODO: aggregate all of data dimension info into a structure.
830 long i;
831 for (i=0; i<nDataDimCount; i++)
833 // Get function for each data field.
834 long nDimIndex = nDataDims[i];
835 ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nDimIndex);
836 sheet::GeneralFunction eUser = (sheet::GeneralFunction)pDim->getFunction();
837 if (eUser == sheet::GeneralFunction_AUTO)
839 //! test for numeric data
840 eUser = sheet::GeneralFunction_SUM;
843 // Map UNO's enum to internal enum ScSubTotalFunc.
844 eDataFunctions[i] = ScDataUnoConversion::GeneralToSubTotal( eUser );
846 // Get reference field/item information.
847 pDataRefValues[i] = pDim->GetReferenceValue();
848 nDataRefOrient[i] = sheet::DataPilotFieldOrientation_HIDDEN; // default if not used
849 sal_Int32 eRefType = pDataRefValues[i].ReferenceType;
850 if ( eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
851 eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
852 eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE ||
853 eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL )
855 long nColumn = lcl_GetIndexFromName( pDataRefValues[i].ReferenceField,
856 GetDimensionsObject()->getElementNames() );
857 if ( nColumn >= 0 )
859 nDataRefOrient[i] = GetOrientation( nColumn );
860 // need fully initialized results to find reference values
861 // (both in column or row dimensions), so updated values or
862 // differences to 0 can be displayed even for empty results.
863 bLateInit = FALSE;
867 pDataNames[i] = String( pDim->getName() ); //! label?
869 // asterisk is added to duplicated dimension names by ScDPSaveData::WriteToSource
870 //! modify user visible strings as in ScDPResultData::GetMeasureString instead!
872 pDataNames[i].EraseTrailingChars('*');
874 //! if the name is overridden by user, a flag must be set
875 //! so the user defined name replaces the function string and field name.
877 //! the complete name (function and field) must be stored at the dimension
879 long nSource = ((ScDPDimension*)pDim)->GetSourceDim();
880 if (nSource >= 0)
881 aInfo.aDataSrcCols.push_back(nSource);
882 else
883 aInfo.aDataSrcCols.push_back(nDimIndex);
886 pResData = new ScDPResultData( this );
887 pResData->SetMeasureData( nDataDimCount, eDataFunctions, pDataRefValues, nDataRefOrient, pDataNames );
888 pResData->SetDataLayoutOrientation(nDataOrient);
889 pResData->SetLateInit( bLateInit );
891 delete[] pDataNames;
892 delete[] pDataRefValues;
894 bool bHasAutoShow = false;
896 ScDPInitState aInitState;
898 // Page field selections restrict the members shown in related fields
899 // (both in column and row fields). aInitState is filled with the page
900 // field selections, they are kept across the data iterator loop.
902 for (i=0; i<nPageDimCount; i++)
904 ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nPageDims[i] );
905 if ( pDim->HasSelectedPage() )
906 aInitState.AddMember( nPageDims[i], pDim->GetSelectedData() );
909 pColResRoot = new ScDPResultMember( pResData, NULL, NULL, NULL, bColumnGrand );
910 pRowResRoot = new ScDPResultMember( pResData, NULL, NULL, NULL, bRowGrand );
912 FillCalcInfo(false, aInfo, bHasAutoShow);
913 long nColLevelCount = aInfo.aColLevels.size();
915 pColResRoot->InitFrom( aInfo.aColDims, aInfo.aColLevels, 0, aInitState );
916 pColResRoot->SetHasElements();
918 FillCalcInfo(true, aInfo, bHasAutoShow);
919 long nRowLevelCount = aInfo.aRowLevels.size();
921 if ( nRowLevelCount > 0 )
923 // disable layout flags for the innermost row field (level)
924 aInfo.aRowLevels[nRowLevelCount-1]->SetEnableLayout( FALSE );
927 pRowResRoot->InitFrom( aInfo.aRowDims, aInfo.aRowLevels, 0, aInitState );
928 pRowResRoot->SetHasElements();
930 // initialize members object also for all page dimensions (needed for numeric groups)
931 for (i=0; i<nPageDimCount; i++)
933 ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nPageDims[i] );
934 long nHierarchy = pDim->getUsedHierarchy();
935 if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() )
936 nHierarchy = 0;
938 ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
939 long nCount = pLevels->getCount();
940 for (long j=0; j<nCount; j++)
941 pLevels->getByIndex(j)->GetMembersObject(); // initialize for groups
944 // pre-check: calculate minimum number of result columns / rows from
945 // levels that have the "show all" flag set
947 long nMinColMembers = lcl_CountMinMembers( aInfo.aColDims, aInfo.aColLevels, nColLevelCount );
948 long nMinRowMembers = lcl_CountMinMembers( aInfo.aRowDims, aInfo.aRowLevels, nRowLevelCount );
950 if ( nMinColMembers > SC_MINCOUNT_LIMIT || nMinRowMembers > SC_MINCOUNT_LIMIT )
952 // resulting table is too big -> abort before calculating
953 // (this relies on late init, so no members are allocated in InitFrom above)
955 bResultOverflow = TRUE;
957 else
959 FilterCacheTableByPageDimensions();
961 aInfo.aPageDims.reserve(nPageDimCount);
962 for (i = 0; i < nPageDimCount; ++i)
963 aInfo.aPageDims.push_back(nPageDims[i]);
965 aInfo.pInitState = &aInitState;
966 aInfo.pColRoot = pColResRoot;
967 aInfo.pRowRoot = pRowResRoot;
968 pData->CalcResults(aInfo, false);
970 // ----------------------------------------------------------------
971 // With all data processed, calculate the final results:
973 // UpdateDataResults calculates all original results from the collected values,
974 // and stores them as reference values if needed.
975 pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() );
977 if ( bHasAutoShow ) // do the double calculation only if AutoShow is used
979 // Find the desired members and set bAutoHidden flag for the others
980 pRowResRoot->DoAutoShow( pColResRoot );
982 // Reset all results to empty, so they can be built again with data for the
983 // desired members only.
984 pColResRoot->ResetResults( TRUE );
985 pRowResRoot->ResetResults( TRUE );
986 pData->CalcResults(aInfo, true);
988 // Call UpdateDataResults again, with the new (limited) values.
989 pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() );
992 // SortMembers does the sorting by a result dimension, using the orginal results,
993 // but not running totals etc.
994 pRowResRoot->SortMembers( pColResRoot );
996 // UpdateRunningTotals calculates running totals along column/row dimensions,
997 // differences from other members (named or relative), and column/row percentages
998 // or index values.
999 // Running totals and relative differences need to be done using the sorted values.
1000 // Column/row percentages and index values must be done after sorting, because the
1001 // results may no longer be in the right order (row total for percentage of row is
1002 // always 1).
1003 ScDPRunningTotalState aRunning( pColResRoot, pRowResRoot );
1004 ScDPRowTotals aTotals;
1005 pRowResRoot->UpdateRunningTotals( pColResRoot, pResData->GetRowStartMeasure(), aRunning, aTotals );
1007 // ----------------------------------------------------------------
1012 //UNUSED2009-05 void ScDPSource::DumpState( ScDocument* pDoc, const ScAddress& rPos )
1013 //UNUSED2009-05 {
1014 //UNUSED2009-05 CreateRes_Impl();
1015 //UNUSED2009-05
1016 //UNUSED2009-05 ScAddress aDocPos( rPos );
1017 //UNUSED2009-05
1018 //UNUSED2009-05 if (pColResRoot->GetChildDimension())
1019 //UNUSED2009-05 pColResRoot->GetChildDimension()->DumpState( NULL, pDoc, aDocPos );
1020 //UNUSED2009-05 pRowResRoot->DumpState( pColResRoot, pDoc, aDocPos );
1021 //UNUSED2009-05 }
1023 void ScDPSource::FillLevelList( USHORT nOrientation, List& rList )
1025 rList.Clear();
1027 long nDimCount = 0;
1028 long* pDimIndex = NULL;
1029 switch (nOrientation)
1031 case sheet::DataPilotFieldOrientation_COLUMN:
1032 pDimIndex = nColDims;
1033 nDimCount = nColDimCount;
1034 break;
1035 case sheet::DataPilotFieldOrientation_ROW:
1036 pDimIndex = nRowDims;
1037 nDimCount = nRowDimCount;
1038 break;
1039 case sheet::DataPilotFieldOrientation_DATA:
1040 pDimIndex = nDataDims;
1041 nDimCount = nDataDimCount;
1042 break;
1043 case sheet::DataPilotFieldOrientation_PAGE:
1044 pDimIndex = nPageDims;
1045 nDimCount = nPageDimCount;
1046 break;
1047 default:
1048 DBG_ERROR( "ScDPSource::FillLevelList: unexpected orientation" );
1049 break;
1051 if (!pDimIndex)
1053 DBG_ERROR("invalid orientation");
1054 return;
1057 ScDPDimensions* pDims = GetDimensionsObject();
1058 for (long nDim=0; nDim<nDimCount; nDim++)
1060 ScDPDimension* pDim = pDims->getByIndex(pDimIndex[nDim]);
1061 DBG_ASSERT( pDim->getOrientation() == nOrientation, "orientations are wrong" );
1063 ScDPHierarchies* pHiers = pDim->GetHierarchiesObject();
1064 long nHierarchy = pDim->getUsedHierarchy();
1065 if ( nHierarchy >= pHiers->getCount() )
1066 nHierarchy = 0;
1067 ScDPHierarchy* pHier = pHiers->getByIndex(nHierarchy);
1068 ScDPLevels* pLevels = pHier->GetLevelsObject();
1069 long nLevCount = pLevels->getCount();
1070 for (long nLev=0; nLev<nLevCount; nLev++)
1072 ScDPLevel* pLevel = pLevels->getByIndex(nLev);
1073 rList.Insert( pLevel, LIST_APPEND );
1078 void ScDPSource::FillMemberResults()
1080 if ( !pColResults && !pRowResults )
1082 CreateRes_Impl();
1084 if ( bResultOverflow ) // set in CreateRes_Impl
1086 // no results available -> abort (leave empty)
1087 // exception is thrown in ScDPSource::getResults
1088 return;
1091 FillLevelList( sheet::DataPilotFieldOrientation_COLUMN, aColLevelList );
1092 long nColLevelCount = aColLevelList.Count();
1093 if (nColLevelCount)
1095 long nColDimSize = pColResRoot->GetSize(pResData->GetColStartMeasure());
1096 pColResults = new uno::Sequence<sheet::MemberResult>[nColLevelCount];
1097 for (long i=0; i<nColLevelCount; i++)
1098 pColResults[i].realloc(nColDimSize);
1100 // ScDPResultDimension* pColResDim = pColResRoot->GetChildDimension();
1101 // pColResDim->FillMemberResults( pColResults, 0, pResData->GetColStartMeasure() );
1102 long nPos = 0;
1103 pColResRoot->FillMemberResults( pColResults, nPos, pResData->GetColStartMeasure(),
1104 TRUE, NULL, NULL );
1107 FillLevelList( sheet::DataPilotFieldOrientation_ROW, aRowLevelList );
1108 long nRowLevelCount = aRowLevelList.Count();
1109 if (nRowLevelCount)
1111 long nRowDimSize = pRowResRoot->GetSize(pResData->GetRowStartMeasure());
1112 pRowResults = new uno::Sequence<sheet::MemberResult>[nRowLevelCount];
1113 for (long i=0; i<nRowLevelCount; i++)
1114 pRowResults[i].realloc(nRowDimSize);
1116 // ScDPResultDimension* pRowResDim = pRowResRoot->GetChildDimension();
1117 // pRowResDim->FillMemberResults( pRowResults, 0, pResData->GetRowStartMeasure() );
1118 long nPos = 0;
1119 pRowResRoot->FillMemberResults( pRowResults, nPos, pResData->GetRowStartMeasure(),
1120 TRUE, NULL, NULL );
1125 const uno::Sequence<sheet::MemberResult>* ScDPSource::GetMemberResults( ScDPLevel* pLevel )
1127 FillMemberResults();
1129 long i;
1130 long nColCount = aColLevelList.Count();
1131 for (i=0; i<nColCount; i++)
1133 ScDPLevel* pColLevel = (ScDPLevel*)aColLevelList.GetObject(i);
1134 if ( pColLevel == pLevel )
1135 return pColResults+i;
1137 long nRowCount = aRowLevelList.Count();
1138 for (i=0; i<nRowCount; i++)
1140 ScDPLevel* pRowLevel = (ScDPLevel*)aRowLevelList.GetObject(i);
1141 if ( pRowLevel == pLevel )
1142 return pRowResults+i;
1144 return NULL;
1147 // XPropertySet
1149 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPSource::getPropertySetInfo()
1150 throw(uno::RuntimeException)
1152 ScUnoGuard aGuard;
1153 using beans::PropertyAttribute::READONLY;
1155 static SfxItemPropertyMapEntry aDPSourceMap_Impl[] =
1157 {MAP_CHAR_LEN(SC_UNO_COLGRAND), 0, &getBooleanCppuType(), 0, 0 },
1158 {MAP_CHAR_LEN(SC_UNO_DATADESC), 0, &getCppuType((rtl::OUString*)0), beans::PropertyAttribute::READONLY, 0 },
1159 {MAP_CHAR_LEN(SC_UNO_IGNOREEM), 0, &getBooleanCppuType(), 0, 0 }, // for sheet data only
1160 {MAP_CHAR_LEN(SC_UNO_REPEATIF), 0, &getBooleanCppuType(), 0, 0 }, // for sheet data only
1161 {MAP_CHAR_LEN(SC_UNO_ROWGRAND), 0, &getBooleanCppuType(), 0, 0 },
1162 {MAP_CHAR_LEN(SC_UNO_ROWFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 },
1163 {MAP_CHAR_LEN(SC_UNO_COLUMNFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 },
1164 {MAP_CHAR_LEN(SC_UNO_DATAFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 },
1165 {MAP_CHAR_LEN(SC_UNO_GRANDTOTAL_NAME), 0, &getCppuType(static_cast<OUString*>(0)), 0, 0 },
1166 {0,0,0,0,0,0}
1168 static uno::Reference<beans::XPropertySetInfo> aRef =
1169 new SfxItemPropertySetInfo( aDPSourceMap_Impl );
1170 return aRef;
1173 void SAL_CALL ScDPSource::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue )
1174 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
1175 lang::IllegalArgumentException, lang::WrappedTargetException,
1176 uno::RuntimeException)
1178 String aNameStr = aPropertyName;
1179 if ( aNameStr.EqualsAscii( SC_UNO_COLGRAND ) )
1180 setColumnGrand( lcl_GetBoolFromAny( aValue ) );
1181 else if ( aNameStr.EqualsAscii( SC_UNO_ROWGRAND ) )
1182 setRowGrand( lcl_GetBoolFromAny( aValue ) );
1183 else if ( aNameStr.EqualsAscii( SC_UNO_IGNOREEM ) )
1184 setIgnoreEmptyRows( lcl_GetBoolFromAny( aValue ) );
1185 else if ( aNameStr.EqualsAscii( SC_UNO_REPEATIF ) )
1186 setRepeatIfEmpty( lcl_GetBoolFromAny( aValue ) );
1187 else if (aNameStr.EqualsAscii(SC_UNO_GRANDTOTAL_NAME))
1189 OUString aName;
1190 if (aValue >>= aName)
1191 mpGrandTotalName.reset(new OUString(aName));
1193 else
1195 DBG_ERROR("unknown property");
1196 //! THROW( UnknownPropertyException() );
1200 uno::Any SAL_CALL ScDPSource::getPropertyValue( const rtl::OUString& aPropertyName )
1201 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
1202 uno::RuntimeException)
1204 uno::Any aRet;
1205 String aNameStr = aPropertyName;
1206 if ( aNameStr.EqualsAscii( SC_UNO_COLGRAND ) )
1207 lcl_SetBoolInAny( aRet, getColumnGrand() );
1208 else if ( aNameStr.EqualsAscii( SC_UNO_ROWGRAND ) )
1209 lcl_SetBoolInAny( aRet, getRowGrand() );
1210 else if ( aNameStr.EqualsAscii( SC_UNO_IGNOREEM ) )
1211 lcl_SetBoolInAny( aRet, getIgnoreEmptyRows() );
1212 else if ( aNameStr.EqualsAscii( SC_UNO_REPEATIF ) )
1213 lcl_SetBoolInAny( aRet, getRepeatIfEmpty() );
1214 else if ( aNameStr.EqualsAscii( SC_UNO_DATADESC ) ) // read-only
1215 aRet <<= rtl::OUString( getDataDescription() );
1216 else if ( aNameStr.EqualsAscii( SC_UNO_ROWFIELDCOUNT ) ) // read-only
1217 aRet <<= static_cast<sal_Int32>(nRowDimCount);
1218 else if ( aNameStr.EqualsAscii( SC_UNO_COLUMNFIELDCOUNT ) ) // read-only
1219 aRet <<= static_cast<sal_Int32>(nColDimCount);
1220 else if ( aNameStr.EqualsAscii( SC_UNO_DATAFIELDCOUNT ) ) // read-only
1221 aRet <<= static_cast<sal_Int32>(nDataDimCount);
1222 else if (aNameStr.EqualsAscii(SC_UNO_GRANDTOTAL_NAME))
1224 if (mpGrandTotalName.get())
1225 aRet <<= *mpGrandTotalName;
1227 else
1229 DBG_ERROR("unknown property");
1230 //! THROW( UnknownPropertyException() );
1232 return aRet;
1235 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPSource )
1237 // -----------------------------------------------------------------------
1239 ScDPDimensions::ScDPDimensions( ScDPSource* pSrc ) :
1240 pSource( pSrc ),
1241 ppDims( NULL )
1243 //! hold pSource
1245 // include data layout dimension and duplicated dimensions
1246 nDimCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount();
1249 ScDPDimensions::~ScDPDimensions()
1251 //! release pSource
1253 if (ppDims)
1255 for (long i=0; i<nDimCount; i++)
1256 if ( ppDims[i] )
1257 ppDims[i]->release(); // ref-counted
1258 delete[] ppDims;
1262 void ScDPDimensions::CountChanged()
1264 // include data layout dimension and duplicated dimensions
1265 long nNewCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount();
1266 if ( ppDims )
1268 long i;
1269 long nCopy = Min( nNewCount, nDimCount );
1270 ScDPDimension** ppNew = new ScDPDimension*[nNewCount];
1272 for (i=0; i<nCopy; i++) // copy existing dims
1273 ppNew[i] = ppDims[i];
1274 for (i=nCopy; i<nNewCount; i++) // clear additional pointers
1275 ppNew[i] = NULL;
1276 for (i=nCopy; i<nDimCount; i++) // delete old dims if count is decreased
1277 if ( ppDims[i] )
1278 ppDims[i]->release(); // ref-counted
1280 delete[] ppDims;
1281 ppDims = ppNew;
1283 nDimCount = nNewCount;
1286 // very simple XNameAccess implementation using getCount/getByIndex
1288 uno::Any SAL_CALL ScDPDimensions::getByName( const rtl::OUString& aName )
1289 throw(container::NoSuchElementException,
1290 lang::WrappedTargetException, uno::RuntimeException)
1292 long nCount = getCount();
1293 for (long i=0; i<nCount; i++)
1294 if ( getByIndex(i)->getName() == aName )
1296 uno::Reference<container::XNamed> xNamed = getByIndex(i);
1297 uno::Any aRet;
1298 aRet <<= xNamed;
1299 return aRet;
1302 throw container::NoSuchElementException();
1303 // return uno::Any();
1306 uno::Sequence<rtl::OUString> SAL_CALL ScDPDimensions::getElementNames() throw(uno::RuntimeException)
1308 long nCount = getCount();
1309 uno::Sequence<rtl::OUString> aSeq(nCount);
1310 rtl::OUString* pArr = aSeq.getArray();
1311 for (long i=0; i<nCount; i++)
1312 pArr[i] = getByIndex(i)->getName();
1313 return aSeq;
1316 sal_Bool SAL_CALL ScDPDimensions::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
1318 long nCount = getCount();
1319 for (long i=0; i<nCount; i++)
1320 if ( getByIndex(i)->getName() == aName )
1321 return TRUE;
1322 return FALSE;
1325 uno::Type SAL_CALL ScDPDimensions::getElementType() throw(uno::RuntimeException)
1327 return getCppuType((uno::Reference<container::XNamed>*)0);
1330 sal_Bool SAL_CALL ScDPDimensions::hasElements() throw(uno::RuntimeException)
1332 return ( getCount() > 0 );
1335 // end of XNameAccess implementation
1337 long ScDPDimensions::getCount() const
1339 // in tabular data, every column of source data is a dimension
1341 return nDimCount;
1344 ScDPDimension* ScDPDimensions::getByIndex(long nIndex) const
1346 if ( nIndex >= 0 && nIndex < nDimCount )
1348 if ( !ppDims )
1350 ((ScDPDimensions*)this)->ppDims = new ScDPDimension*[nDimCount];
1351 for (long i=0; i<nDimCount; i++)
1352 ppDims[i] = NULL;
1354 if ( !ppDims[nIndex] )
1356 ppDims[nIndex] = new ScDPDimension( pSource, nIndex );
1357 ppDims[nIndex]->acquire(); // ref-counted
1360 return ppDims[nIndex];
1363 return NULL; //! exception?
1366 // -----------------------------------------------------------------------
1368 ScDPDimension::ScDPDimension( ScDPSource* pSrc, long nD ) :
1369 pSource( pSrc ),
1370 nDim( nD ),
1371 pHierarchies( NULL ),
1372 nUsedHier( 0 ),
1373 nFunction( SUBTOTAL_FUNC_SUM ), // sum is default
1374 mpLayoutName(NULL),
1375 mpSubtotalName(NULL),
1376 nSourceDim( -1 ),
1377 bHasSelectedPage( FALSE ),
1378 pSelectedData( NULL ),
1379 mbHasHiddenMember(false)
1381 //! hold pSource
1384 ScDPDimension::~ScDPDimension()
1386 //! release pSource
1388 if ( pHierarchies )
1389 pHierarchies->release(); // ref-counted
1391 delete pSelectedData;
1394 ScDPHierarchies* ScDPDimension::GetHierarchiesObject()
1396 if (!pHierarchies)
1398 pHierarchies = new ScDPHierarchies( pSource, nDim );
1399 pHierarchies->acquire(); // ref-counted
1401 return pHierarchies;
1404 const rtl::OUString* ScDPDimension::GetLayoutName() const
1406 return mpLayoutName.get();
1409 const rtl::OUString* ScDPDimension::GetSubtotalName() const
1411 return mpSubtotalName.get();
1414 uno::Reference<container::XNameAccess> SAL_CALL ScDPDimension::getHierarchies()
1415 throw(uno::RuntimeException)
1417 return GetHierarchiesObject();
1420 ::rtl::OUString SAL_CALL ScDPDimension::getName() throw(uno::RuntimeException)
1422 if (aName.Len())
1423 return aName;
1424 else
1425 return pSource->GetData()->getDimensionName( nDim );
1428 void SAL_CALL ScDPDimension::setName( const ::rtl::OUString& rNewName ) throw(uno::RuntimeException)
1430 // used after cloning
1431 aName = String( rNewName );
1434 USHORT ScDPDimension::getOrientation() const
1436 return pSource->GetOrientation( nDim );
1439 void ScDPDimension::setOrientation(USHORT nNew)
1441 pSource->SetOrientation( nDim, nNew );
1444 long ScDPDimension::getPosition() const
1446 return pSource->GetPosition( nDim );
1449 void ScDPDimension::setPosition(long /* nNew */)
1451 //! ...
1454 BOOL ScDPDimension::getIsDataLayoutDimension() const
1456 return pSource->GetData()->getIsDataLayoutDimension( nDim );
1459 USHORT ScDPDimension::getFunction() const
1461 return nFunction;
1464 void ScDPDimension::setFunction(USHORT nNew)
1466 nFunction = nNew;
1469 long ScDPDimension::getUsedHierarchy() const
1471 return nUsedHier;
1474 void ScDPDimension::setUsedHierarchy(long /* nNew */)
1476 // #i52547# don't use the incomplete date hierarchy implementation - ignore the call
1477 // nUsedHier = nNew;
1480 ScDPDimension* ScDPDimension::CreateCloneObject()
1482 DBG_ASSERT( nSourceDim < 0, "recursive duplicate - not implemented" );
1484 //! set new name here, or temporary name ???
1485 String aNewName = aName;
1487 ScDPDimension* pNew = pSource->AddDuplicated( nDim, aNewName );
1489 pNew->aName = aNewName; //! here or in source?
1490 pNew->nSourceDim = nDim; //! recursive?
1492 return pNew;
1495 uno::Reference<util::XCloneable> SAL_CALL ScDPDimension::createClone() throw(uno::RuntimeException)
1497 return CreateCloneObject();
1500 BOOL ScDPDimension::isDuplicated() const
1502 return (nSourceDim >= 0);
1505 const sheet::DataPilotFieldReference& ScDPDimension::GetReferenceValue() const
1507 return aReferenceValue;
1510 const ScDPItemData& ScDPDimension::GetSelectedData()
1512 if ( !pSelectedData )
1514 // find the named member to initialize pSelectedData from it, with name and value
1516 long nLevel = 0; // same as in ScDPObject::FillPageList
1518 long nHierarchy = getUsedHierarchy();
1519 if ( nHierarchy >= GetHierarchiesObject()->getCount() )
1520 nHierarchy = 0;
1521 ScDPLevels* pLevels = GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
1522 long nLevCount = pLevels->getCount();
1523 if ( nLevel < nLevCount )
1525 ScDPMembers* pMembers = pLevels->getByIndex(nLevel)->GetMembersObject();
1527 //! merge with ScDPMembers::getByName
1528 long nCount = pMembers->getCount();
1529 for (long i=0; i<nCount && !pSelectedData; i++)
1531 ScDPMember* pMember = pMembers->getByIndex(i);
1532 if ( pMember->GetNameStr() == aSelectedPage )
1534 pSelectedData = new ScDPItemData();
1535 pMember->FillItemData( *pSelectedData );
1540 if ( !pSelectedData )
1541 pSelectedData = new ScDPItemData( aSelectedPage, 0.0, FALSE ); // default - name only
1544 return *pSelectedData;
1547 //UNUSED2009-05 BOOL ScDPDimension::IsValidPage( const ScDPItemData& rData )
1548 //UNUSED2009-05 {
1549 //UNUSED2009-05 if ( bHasSelectedPage )
1550 //UNUSED2009-05 return rData.IsCaseInsEqual( GetSelectedData() );
1551 //UNUSED2009-05
1552 //UNUSED2009-05 return TRUE; // no selection -> all data
1553 //UNUSED2009-05 }
1555 // XPropertySet
1557 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPDimension::getPropertySetInfo()
1558 throw(uno::RuntimeException)
1560 ScUnoGuard aGuard;
1562 static SfxItemPropertyMapEntry aDPDimensionMap_Impl[] =
1564 {MAP_CHAR_LEN(SC_UNO_FILTER), 0, &getCppuType((uno::Sequence<sheet::TableFilterField>*)0), 0, 0 },
1565 {MAP_CHAR_LEN(SC_UNO_FUNCTION), 0, &getCppuType((sheet::GeneralFunction*)0), 0, 0 },
1566 {MAP_CHAR_LEN(SC_UNO_ISDATALA), 0, &getBooleanCppuType(), beans::PropertyAttribute::READONLY, 0 },
1567 {MAP_CHAR_LEN(SC_UNO_NUMBERFO), 0, &getCppuType((sal_Int32*)0), beans::PropertyAttribute::READONLY, 0 },
1568 {MAP_CHAR_LEN(SC_UNO_ORIENTAT), 0, &getCppuType((sheet::DataPilotFieldOrientation*)0), 0, 0 },
1569 {MAP_CHAR_LEN(SC_UNO_ORIGINAL), 0, &getCppuType((uno::Reference<container::XNamed>*)0), beans::PropertyAttribute::READONLY, 0 },
1570 {MAP_CHAR_LEN(SC_UNO_POSITION), 0, &getCppuType((sal_Int32*)0), 0, 0 },
1571 {MAP_CHAR_LEN(SC_UNO_REFVALUE), 0, &getCppuType((sheet::DataPilotFieldReference*)0), 0, 0 },
1572 {MAP_CHAR_LEN(SC_UNO_USEDHIER), 0, &getCppuType((sal_Int32*)0), 0, 0 },
1573 {MAP_CHAR_LEN(SC_UNO_LAYOUTNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 },
1574 {MAP_CHAR_LEN(SC_UNO_FIELD_SUBTOTALNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 },
1575 {MAP_CHAR_LEN(SC_UNO_HAS_HIDDEN_MEMBER), 0, &getBooleanCppuType(), 0, 0 },
1576 {0,0,0,0,0,0}
1578 static uno::Reference<beans::XPropertySetInfo> aRef =
1579 new SfxItemPropertySetInfo( aDPDimensionMap_Impl );
1580 return aRef;
1583 void SAL_CALL ScDPDimension::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue )
1584 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
1585 lang::IllegalArgumentException, lang::WrappedTargetException,
1586 uno::RuntimeException)
1588 String aNameStr = aPropertyName;
1589 if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) )
1591 INT32 nInt = 0;
1592 if (aValue >>= nInt)
1593 setPosition( nInt );
1595 else if ( aNameStr.EqualsAscii( SC_UNO_USEDHIER ) )
1597 INT32 nInt = 0;
1598 if (aValue >>= nInt)
1599 setUsedHierarchy( nInt );
1601 else if ( aNameStr.EqualsAscii( SC_UNO_ORIENTAT ) )
1603 sheet::DataPilotFieldOrientation eEnum;
1604 if (aValue >>= eEnum)
1605 setOrientation( sal::static_int_cast<USHORT>(eEnum) );
1607 else if ( aNameStr.EqualsAscii( SC_UNO_FUNCTION ) )
1609 sheet::GeneralFunction eEnum;
1610 if (aValue >>= eEnum)
1611 setFunction( sal::static_int_cast<USHORT>(eEnum) );
1613 else if ( aNameStr.EqualsAscii( SC_UNO_REFVALUE ) )
1614 aValue >>= aReferenceValue;
1615 else if ( aNameStr.EqualsAscii( SC_UNO_FILTER ) )
1617 BOOL bDone = FALSE;
1618 uno::Sequence<sheet::TableFilterField> aSeq;
1619 if (aValue >>= aSeq)
1621 sal_Int32 nLength = aSeq.getLength();
1622 if ( nLength == 0 )
1624 aSelectedPage.Erase();
1625 bHasSelectedPage = FALSE;
1626 bDone = TRUE;
1628 else if ( nLength == 1 )
1630 const sheet::TableFilterField& rField = aSeq[0];
1631 if ( rField.Field == 0 && rField.Operator == sheet::FilterOperator_EQUAL && !rField.IsNumeric )
1633 aSelectedPage = rField.StringValue;
1634 bHasSelectedPage = TRUE;
1635 bDone = TRUE;
1639 if ( !bDone )
1641 DBG_ERROR("Filter property is not a single string");
1642 throw lang::IllegalArgumentException();
1644 DELETEZ( pSelectedData ); // invalid after changing aSelectedPage
1646 else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
1648 OUString aTmpName;
1649 if (aValue >>= aTmpName)
1650 mpLayoutName.reset(new OUString(aTmpName));
1652 else if (aNameStr.EqualsAscii(SC_UNO_FIELD_SUBTOTALNAME))
1654 OUString aTmpName;
1655 if (aValue >>= aTmpName)
1656 mpSubtotalName.reset(new OUString(aTmpName));
1658 else if (aNameStr.EqualsAscii(SC_UNO_HAS_HIDDEN_MEMBER))
1659 aValue >>= mbHasHiddenMember;
1660 else
1662 DBG_ERROR("unknown property");
1663 //! THROW( UnknownPropertyException() );
1667 uno::Any SAL_CALL ScDPDimension::getPropertyValue( const rtl::OUString& aPropertyName )
1668 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
1669 uno::RuntimeException)
1671 uno::Any aRet;
1672 String aNameStr = aPropertyName;
1673 if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) )
1674 aRet <<= (sal_Int32) getPosition();
1675 else if ( aNameStr.EqualsAscii( SC_UNO_USEDHIER ) )
1676 aRet <<= (sal_Int32) getUsedHierarchy();
1677 else if ( aNameStr.EqualsAscii( SC_UNO_ORIENTAT ) )
1679 sheet::DataPilotFieldOrientation eVal = (sheet::DataPilotFieldOrientation)getOrientation();
1680 aRet <<= eVal;
1682 else if ( aNameStr.EqualsAscii( SC_UNO_FUNCTION ) )
1684 sheet::GeneralFunction eVal = (sheet::GeneralFunction)getFunction();
1685 aRet <<= eVal;
1687 else if ( aNameStr.EqualsAscii( SC_UNO_REFVALUE ) )
1688 aRet <<= aReferenceValue;
1689 else if ( aNameStr.EqualsAscii( SC_UNO_ISDATALA ) ) // read-only properties
1690 lcl_SetBoolInAny( aRet, getIsDataLayoutDimension() );
1691 else if ( aNameStr.EqualsAscii( SC_UNO_NUMBERFO ) )
1693 sal_Int32 nFormat = 0;
1694 sheet::GeneralFunction eFunc = (sheet::GeneralFunction)getFunction();
1695 // #i63745# don't use source format for "count"
1696 if ( eFunc != sheet::GeneralFunction_COUNT && eFunc != sheet::GeneralFunction_COUNTNUMS )
1697 nFormat = pSource->GetData()->GetNumberFormat( ( nSourceDim >= 0 ) ? nSourceDim : nDim );
1698 aRet <<= nFormat;
1700 else if ( aNameStr.EqualsAscii( SC_UNO_ORIGINAL ) )
1702 uno::Reference<container::XNamed> xOriginal;
1703 if (nSourceDim >= 0)
1704 xOriginal = pSource->GetDimensionsObject()->getByIndex(nSourceDim);
1705 aRet <<= xOriginal;
1707 else if ( aNameStr.EqualsAscii( SC_UNO_FILTER ) )
1709 if ( bHasSelectedPage )
1711 // single filter field: first field equal to selected string
1712 sheet::TableFilterField aField( sheet::FilterConnection_AND, 0,
1713 sheet::FilterOperator_EQUAL, sal_False, 0.0, aSelectedPage );
1714 aRet <<= uno::Sequence<sheet::TableFilterField>( &aField, 1 );
1716 else
1717 aRet <<= uno::Sequence<sheet::TableFilterField>(0);
1719 else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
1720 aRet <<= mpLayoutName.get() ? *mpLayoutName : OUString::createFromAscii("");
1721 else if (aNameStr.EqualsAscii(SC_UNO_FIELD_SUBTOTALNAME))
1722 aRet <<= mpSubtotalName.get() ? *mpSubtotalName : OUString::createFromAscii("");
1723 else if (aNameStr.EqualsAscii(SC_UNO_HAS_HIDDEN_MEMBER))
1724 aRet <<= mbHasHiddenMember;
1725 else
1727 DBG_ERROR("unknown property");
1728 //! THROW( UnknownPropertyException() );
1730 return aRet;
1733 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPDimension )
1735 // -----------------------------------------------------------------------
1737 ScDPHierarchies::ScDPHierarchies( ScDPSource* pSrc, long nD ) :
1738 pSource( pSrc ),
1739 nDim( nD ),
1740 ppHiers( NULL )
1742 //! hold pSource
1744 #if 0
1745 // date columns have 3 hierarchies (flat/quarter/week), other columns only one
1746 long nSrcDim = pSource->GetSourceDim( nDim );
1747 if ( pSource->IsDateDimension( nSrcDim ) )
1748 nHierCount = SC_DAPI_DATE_HIERARCHIES;
1749 else
1750 nHierCount = 1;
1751 #endif
1753 // #i52547# don't offer the incomplete date hierarchy implementation
1754 nHierCount = 1;
1757 ScDPHierarchies::~ScDPHierarchies()
1759 //! release pSource
1761 if (ppHiers)
1763 for (long i=0; i<nHierCount; i++)
1764 if ( ppHiers[i] )
1765 ppHiers[i]->release(); // ref-counted
1766 delete[] ppHiers;
1770 // very simple XNameAccess implementation using getCount/getByIndex
1772 uno::Any SAL_CALL ScDPHierarchies::getByName( const rtl::OUString& aName )
1773 throw(container::NoSuchElementException,
1774 lang::WrappedTargetException, uno::RuntimeException)
1776 long nCount = getCount();
1777 for (long i=0; i<nCount; i++)
1778 if ( getByIndex(i)->getName() == aName )
1780 uno::Reference<container::XNamed> xNamed = getByIndex(i);
1781 uno::Any aRet;
1782 aRet <<= xNamed;
1783 return aRet;
1786 throw container::NoSuchElementException();
1787 // return uno::Any();
1790 uno::Sequence<rtl::OUString> SAL_CALL ScDPHierarchies::getElementNames() throw(uno::RuntimeException)
1792 long nCount = getCount();
1793 uno::Sequence<rtl::OUString> aSeq(nCount);
1794 rtl::OUString* pArr = aSeq.getArray();
1795 for (long i=0; i<nCount; i++)
1796 pArr[i] = getByIndex(i)->getName();
1797 return aSeq;
1800 sal_Bool SAL_CALL ScDPHierarchies::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
1802 long nCount = getCount();
1803 for (long i=0; i<nCount; i++)
1804 if ( getByIndex(i)->getName() == aName )
1805 return TRUE;
1806 return FALSE;
1809 uno::Type SAL_CALL ScDPHierarchies::getElementType() throw(uno::RuntimeException)
1811 return getCppuType((uno::Reference<container::XNamed>*)0);
1814 sal_Bool SAL_CALL ScDPHierarchies::hasElements() throw(uno::RuntimeException)
1816 return ( getCount() > 0 );
1819 // end of XNameAccess implementation
1821 long ScDPHierarchies::getCount() const
1823 return nHierCount;
1826 ScDPHierarchy* ScDPHierarchies::getByIndex(long nIndex) const
1828 // pass hierarchy index to new object in case the implementation
1829 // will be extended to more than one hierarchy
1831 if ( nIndex >= 0 && nIndex < nHierCount )
1833 if ( !ppHiers )
1835 ((ScDPHierarchies*)this)->ppHiers = new ScDPHierarchy*[nHierCount];
1836 for (long i=0; i<nHierCount; i++)
1837 ppHiers[i] = NULL;
1839 if ( !ppHiers[nIndex] )
1841 ppHiers[nIndex] = new ScDPHierarchy( pSource, nDim, nIndex );
1842 ppHiers[nIndex]->acquire(); // ref-counted
1845 return ppHiers[nIndex];
1848 return NULL; //! exception?
1851 // -----------------------------------------------------------------------
1853 ScDPHierarchy::ScDPHierarchy( ScDPSource* pSrc, long nD, long nH ) :
1854 pSource( pSrc ),
1855 nDim( nD ),
1856 nHier( nH ),
1857 pLevels( NULL )
1859 //! hold pSource
1862 ScDPHierarchy::~ScDPHierarchy()
1864 //! release pSource
1866 if (pLevels)
1867 pLevels->release(); // ref-counted
1870 ScDPLevels* ScDPHierarchy::GetLevelsObject()
1872 if (!pLevels)
1874 pLevels = new ScDPLevels( pSource, nDim, nHier );
1875 pLevels->acquire(); // ref-counted
1877 return pLevels;
1880 uno::Reference<container::XNameAccess> SAL_CALL ScDPHierarchy::getLevels()
1881 throw(uno::RuntimeException)
1883 return GetLevelsObject();
1886 ::rtl::OUString SAL_CALL ScDPHierarchy::getName() throw(uno::RuntimeException)
1888 String aRet; //! globstr-ID !!!!
1889 switch (nHier)
1891 case SC_DAPI_HIERARCHY_FLAT:
1892 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("flat"));
1893 break; //! name ???????
1894 case SC_DAPI_HIERARCHY_QUARTER:
1895 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Quarter"));
1896 break; //! name ???????
1897 case SC_DAPI_HIERARCHY_WEEK:
1898 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Week"));
1899 break; //! name ???????
1900 default:
1901 DBG_ERROR( "ScDPHierarchy::getName: unexpected hierarchy" );
1902 break;
1904 return aRet;
1907 void SAL_CALL ScDPHierarchy::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException)
1909 DBG_ERROR("not implemented"); //! exception?
1912 // -----------------------------------------------------------------------
1914 ScDPLevels::ScDPLevels( ScDPSource* pSrc, long nD, long nH ) :
1915 pSource( pSrc ),
1916 nDim( nD ),
1917 nHier( nH ),
1918 ppLevs( NULL )
1920 //! hold pSource
1922 // text columns have only one level
1924 long nSrcDim = pSource->GetSourceDim( nDim );
1925 if ( pSource->IsDateDimension( nSrcDim ) )
1927 switch ( nHier )
1929 case SC_DAPI_HIERARCHY_FLAT: nLevCount = SC_DAPI_FLAT_LEVELS; break;
1930 case SC_DAPI_HIERARCHY_QUARTER: nLevCount = SC_DAPI_QUARTER_LEVELS; break;
1931 case SC_DAPI_HIERARCHY_WEEK: nLevCount = SC_DAPI_WEEK_LEVELS; break;
1932 default:
1933 DBG_ERROR("wrong hierarchy");
1934 nLevCount = 0;
1937 else
1938 nLevCount = 1;
1941 ScDPLevels::~ScDPLevels()
1943 //! release pSource
1945 if (ppLevs)
1947 for (long i=0; i<nLevCount; i++)
1948 if ( ppLevs[i] )
1949 ppLevs[i]->release(); // ref-counted
1950 delete[] ppLevs;
1954 // very simple XNameAccess implementation using getCount/getByIndex
1956 uno::Any SAL_CALL ScDPLevels::getByName( const rtl::OUString& aName )
1957 throw(container::NoSuchElementException,
1958 lang::WrappedTargetException, uno::RuntimeException)
1960 long nCount = getCount();
1961 for (long i=0; i<nCount; i++)
1962 if ( getByIndex(i)->getName() == aName )
1964 uno::Reference<container::XNamed> xNamed = getByIndex(i);
1965 uno::Any aRet;
1966 aRet <<= xNamed;
1967 return aRet;
1970 throw container::NoSuchElementException();
1971 // return uno::Any();
1974 uno::Sequence<rtl::OUString> SAL_CALL ScDPLevels::getElementNames() throw(uno::RuntimeException)
1976 long nCount = getCount();
1977 uno::Sequence<rtl::OUString> aSeq(nCount);
1978 rtl::OUString* pArr = aSeq.getArray();
1979 for (long i=0; i<nCount; i++)
1980 pArr[i] = getByIndex(i)->getName();
1981 return aSeq;
1984 sal_Bool SAL_CALL ScDPLevels::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
1986 long nCount = getCount();
1987 for (long i=0; i<nCount; i++)
1988 if ( getByIndex(i)->getName() == aName )
1989 return TRUE;
1990 return FALSE;
1993 uno::Type SAL_CALL ScDPLevels::getElementType() throw(uno::RuntimeException)
1995 return getCppuType((uno::Reference<container::XNamed>*)0);
1998 sal_Bool SAL_CALL ScDPLevels::hasElements() throw(uno::RuntimeException)
2000 return ( getCount() > 0 );
2003 // end of XNameAccess implementation
2005 long ScDPLevels::getCount() const
2007 return nLevCount;
2010 ScDPLevel* ScDPLevels::getByIndex(long nIndex) const
2012 if ( nIndex >= 0 && nIndex < nLevCount )
2014 if ( !ppLevs )
2016 ((ScDPLevels*)this)->ppLevs = new ScDPLevel*[nLevCount];
2017 for (long i=0; i<nLevCount; i++)
2018 ppLevs[i] = NULL;
2020 if ( !ppLevs[nIndex] )
2022 ppLevs[nIndex] = new ScDPLevel( pSource, nDim, nHier, nIndex );
2023 ppLevs[nIndex]->acquire(); // ref-counted
2026 return ppLevs[nIndex];
2029 return NULL; //! exception?
2032 // -----------------------------------------------------------------------
2034 class ScDPGlobalMembersOrder
2036 ScDPLevel& rLevel;
2037 BOOL bAscending;
2039 public:
2040 ScDPGlobalMembersOrder( ScDPLevel& rLev, BOOL bAsc ) :
2041 rLevel(rLev),
2042 bAscending(bAsc)
2044 ~ScDPGlobalMembersOrder() {}
2046 BOOL operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
2049 BOOL ScDPGlobalMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
2051 sal_Int32 nCompare = 0;
2052 // seems that some ::std::sort() implementations pass the same index twice
2053 if( nIndex1 != nIndex2 )
2055 ScDPMembers* pMembers = rLevel.GetMembersObject();
2056 ScDPMember* pMember1 = pMembers->getByIndex(nIndex1);
2057 ScDPMember* pMember2 = pMembers->getByIndex(nIndex2);
2058 nCompare = pMember1->Compare( *pMember2 );
2060 return bAscending ? (nCompare < 0) : (nCompare > 0);
2063 // -----------------------------------------------------------------------
2065 ScDPLevel::ScDPLevel( ScDPSource* pSrc, long nD, long nH, long nL ) :
2066 pSource( pSrc ),
2067 nDim( nD ),
2068 nHier( nH ),
2069 nLev( nL ),
2070 pMembers( NULL ),
2071 bShowEmpty( FALSE ),
2072 aSortInfo( EMPTY_STRING, sal_True, sheet::DataPilotFieldSortMode::NAME ), // default: sort by name
2073 nSortMeasure( 0 ),
2074 nAutoMeasure( 0 ),
2075 bEnableLayout( FALSE )
2077 //! hold pSource
2078 // aSubTotals is empty
2081 ScDPLevel::~ScDPLevel()
2083 //! release pSource
2085 if ( pMembers )
2086 pMembers->release(); // ref-counted
2089 void ScDPLevel::EvaluateSortOrder()
2091 switch (aSortInfo.Mode)
2093 case sheet::DataPilotFieldSortMode::DATA:
2095 // find index of measure (index among data dimensions)
2097 String aDataFieldName = aSortInfo.Field;
2098 long nMeasureCount = pSource->GetDataDimensionCount();
2099 for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++)
2101 if ( pSource->GetDataDimName(nMeasure) == aDataFieldName )
2103 nSortMeasure = nMeasure;
2104 break;
2108 //! error if not found?
2110 break;
2111 case sheet::DataPilotFieldSortMode::MANUAL:
2112 case sheet::DataPilotFieldSortMode::NAME:
2114 ScDPMembers* pLocalMembers = GetMembersObject();
2115 long nCount = pLocalMembers->getCount();
2117 // DBG_ASSERT( aGlobalOrder.empty(), "sort twice?" );
2118 aGlobalOrder.resize( nCount );
2119 for (long nPos=0; nPos<nCount; nPos++)
2120 aGlobalOrder[nPos] = nPos;
2122 // allow manual or name (manual is always ascending)
2123 BOOL bAscending = ( aSortInfo.Mode == sheet::DataPilotFieldSortMode::MANUAL || aSortInfo.IsAscending );
2124 ScDPGlobalMembersOrder aComp( *this, bAscending );
2125 ::std::sort( aGlobalOrder.begin(), aGlobalOrder.end(), aComp );
2127 break;
2130 if ( aAutoShowInfo.IsEnabled )
2132 // find index of measure (index among data dimensions)
2134 String aDataFieldName = aAutoShowInfo.DataField;
2135 long nMeasureCount = pSource->GetDataDimensionCount();
2136 for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++)
2138 if ( pSource->GetDataDimName(nMeasure) == aDataFieldName )
2140 nAutoMeasure = nMeasure;
2141 break;
2145 //! error if not found?
2149 void ScDPLevel::SetEnableLayout( BOOL bSet )
2151 bEnableLayout = bSet;
2154 ScDPMembers* ScDPLevel::GetMembersObject()
2156 if (!pMembers)
2158 pMembers = new ScDPMembers( pSource, nDim, nHier, nLev );
2159 pMembers->acquire(); // ref-counted
2161 return pMembers;
2164 uno::Reference<container::XNameAccess> SAL_CALL ScDPLevel::getMembers() throw(uno::RuntimeException)
2166 return GetMembersObject();
2169 uno::Sequence<sheet::MemberResult> SAL_CALL ScDPLevel::getResults() throw(uno::RuntimeException)
2171 const uno::Sequence<sheet::MemberResult>* pRes = pSource->GetMemberResults( this );
2172 if (pRes)
2173 return *pRes;
2175 return uno::Sequence<sheet::MemberResult>(0); //! Error?
2178 ::rtl::OUString SAL_CALL ScDPLevel::getName() throw(uno::RuntimeException)
2180 long nSrcDim = pSource->GetSourceDim( nDim );
2181 if ( pSource->IsDateDimension( nSrcDim ) )
2183 String aRet; //! globstr-ID !!!!
2185 if ( nHier == SC_DAPI_HIERARCHY_QUARTER )
2187 switch ( nLev )
2189 case SC_DAPI_LEVEL_YEAR:
2190 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Year"));
2191 break;
2192 case SC_DAPI_LEVEL_QUARTER:
2193 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Quarter"));
2194 break;
2195 case SC_DAPI_LEVEL_MONTH:
2196 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Month"));
2197 break;
2198 case SC_DAPI_LEVEL_DAY:
2199 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Day"));
2200 break;
2201 default:
2202 DBG_ERROR( "ScDPLevel::getName: unexpected level" );
2203 break;
2206 else if ( nHier == SC_DAPI_HIERARCHY_WEEK )
2208 switch ( nLev )
2210 case SC_DAPI_LEVEL_YEAR:
2211 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Year"));
2212 break;
2213 case SC_DAPI_LEVEL_WEEK:
2214 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Week"));
2215 break;
2216 case SC_DAPI_LEVEL_WEEKDAY:
2217 aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Weekday"));
2218 break;
2219 default:
2220 DBG_ERROR( "ScDPLevel::getName: unexpected level" );
2221 break;
2224 if (aRet.Len())
2225 return aRet;
2228 ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim);
2229 if (!pDim)
2230 return rtl::OUString();
2232 return pDim->getName();
2235 void SAL_CALL ScDPLevel::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException)
2237 DBG_ERROR("not implemented"); //! exception?
2240 uno::Sequence<sheet::GeneralFunction> ScDPLevel::getSubTotals() const
2242 //! separate functions for settings and evaluation?
2244 long nSrcDim = pSource->GetSourceDim( nDim );
2245 if ( !pSource->SubTotalAllowed( nSrcDim ) )
2246 return uno::Sequence<sheet::GeneralFunction>(0);
2248 return aSubTotals;
2251 void ScDPLevel::setSubTotals(const uno::Sequence<sheet::GeneralFunction>& rNew)
2253 aSubTotals = rNew;
2254 //! set "manual change" flag?
2257 BOOL ScDPLevel::getShowEmpty() const
2259 return bShowEmpty;
2262 void ScDPLevel::setShowEmpty(BOOL bSet)
2264 bShowEmpty = bSet;
2267 // XPropertySet
2269 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPLevel::getPropertySetInfo()
2270 throw(uno::RuntimeException)
2272 ScUnoGuard aGuard;
2274 static SfxItemPropertyMapEntry aDPLevelMap_Impl[] =
2276 //! change type of AutoShow/Layout/Sorting to API struct when available
2277 {MAP_CHAR_LEN(SC_UNO_AUTOSHOW), 0, &getCppuType((sheet::DataPilotFieldAutoShowInfo*)0), 0, 0 },
2278 {MAP_CHAR_LEN(SC_UNO_LAYOUT), 0, &getCppuType((sheet::DataPilotFieldLayoutInfo*)0), 0, 0 },
2279 {MAP_CHAR_LEN(SC_UNO_SHOWEMPT), 0, &getBooleanCppuType(), 0, 0 },
2280 {MAP_CHAR_LEN(SC_UNO_SORTING), 0, &getCppuType((sheet::DataPilotFieldSortInfo*)0), 0, 0 },
2281 {MAP_CHAR_LEN(SC_UNO_SUBTOTAL), 0, &getCppuType((uno::Sequence<sheet::GeneralFunction>*)0), 0, 0 },
2282 {0,0,0,0,0,0}
2284 static uno::Reference<beans::XPropertySetInfo> aRef =
2285 new SfxItemPropertySetInfo( aDPLevelMap_Impl );
2286 return aRef;
2289 void SAL_CALL ScDPLevel::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue )
2290 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
2291 lang::IllegalArgumentException, lang::WrappedTargetException,
2292 uno::RuntimeException)
2294 String aNameStr = aPropertyName;
2295 if ( aNameStr.EqualsAscii( SC_UNO_SHOWEMPT ) )
2296 setShowEmpty( lcl_GetBoolFromAny( aValue ) );
2297 else if ( aNameStr.EqualsAscii( SC_UNO_SUBTOTAL ) )
2299 uno::Sequence<sheet::GeneralFunction> aSeq;
2300 if ( aValue >>= aSeq )
2301 setSubTotals( aSeq );
2303 else if ( aNameStr.EqualsAscii( SC_UNO_SORTING ) )
2304 aValue >>= aSortInfo;
2305 else if ( aNameStr.EqualsAscii( SC_UNO_AUTOSHOW ) )
2306 aValue >>= aAutoShowInfo;
2307 else if ( aNameStr.EqualsAscii( SC_UNO_LAYOUT ) )
2308 aValue >>= aLayoutInfo;
2309 else
2311 DBG_ERROR("unknown property");
2312 //! THROW( UnknownPropertyException() );
2316 uno::Any SAL_CALL ScDPLevel::getPropertyValue( const rtl::OUString& aPropertyName )
2317 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
2318 uno::RuntimeException)
2320 uno::Any aRet;
2321 String aNameStr = aPropertyName;
2322 if ( aNameStr.EqualsAscii( SC_UNO_SHOWEMPT ) )
2323 lcl_SetBoolInAny( aRet, getShowEmpty() );
2324 else if ( aNameStr.EqualsAscii( SC_UNO_SUBTOTAL ) )
2326 uno::Sequence<sheet::GeneralFunction> aSeq = getSubTotals(); //! avoid extra copy?
2327 aRet <<= aSeq;
2329 else if ( aNameStr.EqualsAscii( SC_UNO_SORTING ) )
2330 aRet <<= aSortInfo;
2331 else if ( aNameStr.EqualsAscii( SC_UNO_AUTOSHOW ) )
2332 aRet <<= aAutoShowInfo;
2333 else if ( aNameStr.EqualsAscii( SC_UNO_LAYOUT ) )
2334 aRet <<= aLayoutInfo;
2335 else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
2337 // read only property
2338 long nSrcDim = pSource->GetSourceDim(nDim);
2339 ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim);
2340 if (!pDim)
2341 return aRet;
2343 const OUString* pLayoutName = pDim->GetLayoutName();
2344 if (!pLayoutName)
2345 return aRet;
2347 aRet <<= *pLayoutName;
2349 else
2351 DBG_ERROR("unknown property");
2352 //! THROW( UnknownPropertyException() );
2354 return aRet;
2357 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPLevel )
2359 // -----------------------------------------------------------------------
2361 USHORT lcl_GetFirstStringPos( const TypedScStrCollection& rColl )
2363 USHORT nPos = 0;
2364 USHORT nCount = rColl.GetCount();
2365 while ( nPos < nCount && !rColl[nPos]->IsStrData() )
2366 ++nPos;
2367 return nPos;
2370 ScDPMembers::ScDPMembers( ScDPSource* pSrc, long nD, long nH, long nL ) :
2371 pSource( pSrc ),
2372 nDim( nD ),
2373 nHier( nH ),
2374 nLev( nL ),
2375 ppMbrs( NULL )
2377 //! hold pSource
2379 long nSrcDim = pSource->GetSourceDim( nDim );
2380 if ( pSource->IsDataLayoutDimension(nSrcDim) )
2381 nMbrCount = pSource->GetDataDimensionCount();
2382 else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
2384 nMbrCount = 0;
2385 if ( nHier == SC_DAPI_HIERARCHY_QUARTER )
2387 switch (nLev)
2389 case SC_DAPI_LEVEL_YEAR:
2391 const TypedScStrCollection& rStrings = pSource->GetData()->GetColumnEntries(nSrcDim);
2392 USHORT nFirstString = lcl_GetFirstStringPos( rStrings );
2393 if ( nFirstString > 0 )
2395 double fFirstVal = rStrings[0]->GetValue();
2396 double fLastVal = rStrings[nFirstString-1]->GetValue();
2398 long nFirstYear = pSource->GetData()->GetDatePart(
2399 (long)::rtl::math::approxFloor( fFirstVal ),
2400 nHier, nLev );
2401 long nLastYear = pSource->GetData()->GetDatePart(
2402 (long)::rtl::math::approxFloor( fLastVal ),
2403 nHier, nLev );
2405 nMbrCount = nLastYear + 1 - nFirstYear;
2407 else
2408 nMbrCount = 0; // no values
2410 break;
2411 case SC_DAPI_LEVEL_QUARTER: nMbrCount = 4; break;
2412 case SC_DAPI_LEVEL_MONTH: nMbrCount = 12; break;
2413 case SC_DAPI_LEVEL_DAY: nMbrCount = 31; break;
2414 default:
2415 DBG_ERROR( "ScDPMembers::ScDPMembers: unexpected level" );
2416 break;
2419 else if ( nHier == SC_DAPI_HIERARCHY_WEEK )
2421 switch (nLev)
2423 case SC_DAPI_LEVEL_YEAR: nMbrCount = 1; break; //! get years from source
2424 case SC_DAPI_LEVEL_WEEK: nMbrCount = 53; break;
2425 case SC_DAPI_LEVEL_WEEKDAY: nMbrCount = 7; break;
2426 default:
2427 DBG_ERROR( "ScDPMembers::ScDPMembers: unexpected level" );
2428 break;
2432 else
2434 // StringCollection is cached at TableData
2435 const TypedScStrCollection& rStrings = pSource->GetData()->GetColumnEntries(nSrcDim);
2436 nMbrCount = rStrings.GetCount();
2440 ScDPMembers::~ScDPMembers()
2442 //! release pSource
2444 if (ppMbrs)
2446 for (long i=0; i<nMbrCount; i++)
2447 if ( ppMbrs[i] )
2448 ppMbrs[i]->release(); // ref-counted
2449 delete[] ppMbrs;
2453 // XNameAccess implementation using getCount/getByIndex
2455 sal_Int32 ScDPMembers::GetIndexFromName( const ::rtl::OUString& rName ) const
2457 if ( aHashMap.empty() )
2459 // store the index for each name
2461 sal_Int32 nCount = getCount();
2462 for (sal_Int32 i=0; i<nCount; i++)
2463 aHashMap[ getByIndex(i)->getName() ] = i;
2466 ScDPMembersHashMap::const_iterator aIter = aHashMap.find( rName );
2467 if ( aIter != aHashMap.end() )
2468 return aIter->second; // found index
2469 else
2470 return -1; // not found
2473 uno::Any SAL_CALL ScDPMembers::getByName( const rtl::OUString& aName )
2474 throw(container::NoSuchElementException,
2475 lang::WrappedTargetException, uno::RuntimeException)
2477 sal_Int32 nIndex = GetIndexFromName( aName );
2478 if ( nIndex >= 0 )
2480 uno::Reference<container::XNamed> xNamed = getByIndex(nIndex);
2481 uno::Any aRet;
2482 aRet <<= xNamed;
2483 return aRet;
2486 throw container::NoSuchElementException();
2487 // return uno::Any();
2490 uno::Sequence<rtl::OUString> SAL_CALL ScDPMembers::getElementNames() throw(uno::RuntimeException)
2492 // Return list of names in sorted order,
2493 // so it's displayed in that order in the field options dialog.
2494 // Sorting is done at the level object (parent of this).
2496 ScDPLevel* pLevel = pSource->GetDimensionsObject()->getByIndex(nDim)->
2497 GetHierarchiesObject()->getByIndex(nHier)->GetLevelsObject()->getByIndex(nLev);
2498 pLevel->EvaluateSortOrder();
2499 const std::vector<sal_Int32>& rGlobalOrder = pLevel->GetGlobalOrder();
2500 bool bSort = !rGlobalOrder.empty();
2502 long nCount = getCount();
2503 uno::Sequence<rtl::OUString> aSeq(nCount);
2504 rtl::OUString* pArr = aSeq.getArray();
2505 for (long i=0; i<nCount; i++)
2506 pArr[i] = getByIndex(bSort ? rGlobalOrder[i] : i)->getName();
2507 return aSeq;
2510 sal_Bool SAL_CALL ScDPMembers::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
2512 return ( GetIndexFromName( aName ) >= 0 );
2515 uno::Type SAL_CALL ScDPMembers::getElementType() throw(uno::RuntimeException)
2517 return getCppuType((uno::Reference<container::XNamed>*)0);
2520 sal_Bool SAL_CALL ScDPMembers::hasElements() throw(uno::RuntimeException)
2522 return ( getCount() > 0 );
2525 // end of XNameAccess implementation
2527 long ScDPMembers::getCount() const
2529 return nMbrCount;
2532 long ScDPMembers::getMinMembers() const
2534 // used in lcl_CountMinMembers
2536 long nVisCount = 0;
2537 if ( ppMbrs )
2539 for (long i=0; i<nMbrCount; i++)
2541 // count only visible with details (default is true for both)
2542 const ScDPMember* pMbr = ppMbrs[i];
2543 if ( !pMbr || ( pMbr->getIsVisible() && pMbr->getShowDetails() ) )
2544 ++nVisCount;
2547 else
2548 nVisCount = nMbrCount; // default for all
2550 return nVisCount;
2553 ScDPMember* ScDPMembers::getByIndex(long nIndex) const
2555 // result of GetColumnEntries must not change between ScDPMembers ctor
2556 // and all calls to getByIndex
2558 if ( nIndex >= 0 && nIndex < nMbrCount )
2560 if ( !ppMbrs )
2562 ((ScDPMembers*)this)->ppMbrs = new ScDPMember*[nMbrCount];
2563 for (long i=0; i<nMbrCount; i++)
2564 ppMbrs[i] = NULL;
2566 if ( !ppMbrs[nIndex] )
2568 ScDPMember* pNew;
2569 long nSrcDim = pSource->GetSourceDim( nDim );
2570 if ( pSource->IsDataLayoutDimension(nSrcDim) )
2572 // empty name (never shown, not used for lookup)
2573 pNew = new ScDPMember( pSource, nDim, nHier, nLev,
2574 String(), 0.0, FALSE );
2576 else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
2578 long nVal = 0;
2579 String aName;
2581 if ( nLev == SC_DAPI_LEVEL_YEAR ) // YEAR is in both hierarchies
2583 //! cache year range here!
2585 const TypedScStrCollection& rStrings = pSource->GetData()->GetColumnEntries(nSrcDim);
2586 double fFirstVal = rStrings[0]->GetValue();
2587 long nFirstYear = pSource->GetData()->GetDatePart(
2588 (long)::rtl::math::approxFloor( fFirstVal ),
2589 nHier, nLev );
2591 nVal = nFirstYear + nIndex;
2593 else if ( nHier == SC_DAPI_HIERARCHY_WEEK && nLev == SC_DAPI_LEVEL_WEEKDAY )
2595 nVal = nIndex; // DayOfWeek is 0-based
2596 aName = ScGlobal::GetCalendar()->getDisplayName(
2597 ::com::sun::star::i18n::CalendarDisplayIndex::DAY,
2598 sal::static_int_cast<sal_Int16>(nVal), 0 );
2600 else if ( nHier == SC_DAPI_HIERARCHY_QUARTER && nLev == SC_DAPI_LEVEL_MONTH )
2602 nVal = nIndex; // Month is 0-based
2603 aName = ScGlobal::GetCalendar()->getDisplayName(
2604 ::com::sun::star::i18n::CalendarDisplayIndex::MONTH,
2605 sal::static_int_cast<sal_Int16>(nVal), 0 );
2607 else
2608 nVal = nIndex + 1; // Quarter, Day, Week are 1-based
2610 if ( !aName.Len() )
2611 aName = String::CreateFromInt32(nVal);
2613 pNew = new ScDPMember( pSource, nDim, nHier, nLev, aName, nVal, TRUE );
2615 else
2617 const TypedScStrCollection& rStrings = pSource->GetData()->GetColumnEntries(nSrcDim);
2618 const TypedStrData* pData = rStrings[(USHORT)nIndex];
2619 pNew = new ScDPMember( pSource, nDim, nHier, nLev,
2620 pData->GetString(), pData->GetValue(), !pData->IsStrData() );
2622 pNew->acquire(); // ref-counted
2623 ppMbrs[nIndex] = pNew;
2626 return ppMbrs[nIndex];
2629 return NULL; //! exception?
2632 // -----------------------------------------------------------------------
2634 ScDPMember::ScDPMember( ScDPSource* pSrc, long nD, long nH, long nL,
2635 const String& rN, double fV, BOOL bHV ) :
2636 pSource( pSrc ),
2637 nDim( nD ),
2638 nHier( nH ),
2639 nLev( nL ),
2640 maData( rN, fV, bHV ),
2641 mpLayoutName(NULL),
2642 nPosition( -1 ),
2643 bVisible( TRUE ),
2644 bShowDet( TRUE )
2646 //! hold pSource
2649 ScDPMember::~ScDPMember()
2651 //! release pSource
2654 BOOL ScDPMember::IsNamedItem( const ScDPItemData& r ) const
2656 long nSrcDim = pSource->GetSourceDim( nDim );
2657 if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) && r.bHasValue )
2659 long nComp = pSource->GetData()->GetDatePart(
2660 (long)::rtl::math::approxFloor( r.fValue ),
2661 nHier, nLev );
2663 // fValue is converted from integer, so simple comparison works
2664 return nComp == maData.fValue;
2667 return r.IsCaseInsEqual( maData );
2670 sal_Int32 ScDPMember::Compare( const ScDPMember& rOther ) const
2672 if ( nPosition >= 0 )
2674 if ( rOther.nPosition >= 0 )
2676 DBG_ASSERT( nPosition != rOther.nPosition, "same position for two members" );
2677 return ( nPosition < rOther.nPosition ) ? -1 : 1;
2679 else
2681 // only this has a position - members with specified positions come before those without
2682 return -1;
2685 else if ( rOther.nPosition >= 0 )
2687 // only rOther has a position
2688 return 1;
2691 // no positions set - compare names
2692 return ScDPItemData::Compare( maData, rOther.maData );
2695 void ScDPMember::FillItemData( ScDPItemData& rData ) const
2697 //! handle date hierarchy...
2699 rData = maData;
2702 const OUString* ScDPMember::GetLayoutName() const
2704 return mpLayoutName.get();
2707 String ScDPMember::GetNameStr() const
2709 return maData.aString;
2712 ::rtl::OUString SAL_CALL ScDPMember::getName() throw(uno::RuntimeException)
2714 return maData.aString;
2717 void SAL_CALL ScDPMember::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException)
2719 DBG_ERROR("not implemented"); //! exception?
2722 BOOL ScDPMember::getIsVisible() const
2724 return bVisible;
2727 void ScDPMember::setIsVisible(BOOL bSet)
2729 bVisible = bSet;
2730 //! set "manual change" flag
2733 BOOL ScDPMember::getShowDetails() const
2735 return bShowDet;
2738 void ScDPMember::setShowDetails(BOOL bSet)
2740 bShowDet = bSet;
2741 //! set "manual change" flag
2744 sal_Int32 ScDPMember::getPosition() const
2746 return nPosition;
2749 void ScDPMember::setPosition(sal_Int32 nNew)
2751 nPosition = nNew;
2754 // XPropertySet
2756 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPMember::getPropertySetInfo()
2757 throw(uno::RuntimeException)
2759 ScUnoGuard aGuard;
2761 static SfxItemPropertyMapEntry aDPMemberMap_Impl[] =
2763 {MAP_CHAR_LEN(SC_UNO_ISVISIBL), 0, &getBooleanCppuType(), 0, 0 },
2764 {MAP_CHAR_LEN(SC_UNO_POSITION), 0, &getCppuType((sal_Int32*)0), 0, 0 },
2765 {MAP_CHAR_LEN(SC_UNO_SHOWDETA), 0, &getBooleanCppuType(), 0, 0 },
2766 {MAP_CHAR_LEN(SC_UNO_LAYOUTNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 },
2767 {0,0,0,0,0,0}
2769 static uno::Reference<beans::XPropertySetInfo> aRef =
2770 new SfxItemPropertySetInfo( aDPMemberMap_Impl );
2771 return aRef;
2774 void SAL_CALL ScDPMember::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue )
2775 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
2776 lang::IllegalArgumentException, lang::WrappedTargetException,
2777 uno::RuntimeException)
2779 String aNameStr = aPropertyName;
2780 if ( aNameStr.EqualsAscii( SC_UNO_ISVISIBL ) )
2781 setIsVisible( lcl_GetBoolFromAny( aValue ) );
2782 else if ( aNameStr.EqualsAscii( SC_UNO_SHOWDETA ) )
2783 setShowDetails( lcl_GetBoolFromAny( aValue ) );
2784 else if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) )
2786 sal_Int32 nInt = 0;
2787 if (aValue >>= nInt)
2788 setPosition( nInt );
2790 else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
2792 rtl::OUString aName;
2793 if (aValue >>= aName)
2794 mpLayoutName.reset(new rtl::OUString(aName));
2796 else
2798 DBG_ERROR("unknown property");
2799 //! THROW( UnknownPropertyException() );
2803 uno::Any SAL_CALL ScDPMember::getPropertyValue( const rtl::OUString& aPropertyName )
2804 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
2805 uno::RuntimeException)
2807 uno::Any aRet;
2808 String aNameStr = aPropertyName;
2809 if ( aNameStr.EqualsAscii( SC_UNO_ISVISIBL ) )
2810 lcl_SetBoolInAny( aRet, getIsVisible() );
2811 else if ( aNameStr.EqualsAscii( SC_UNO_SHOWDETA ) )
2812 lcl_SetBoolInAny( aRet, getShowDetails() );
2813 else if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) )
2814 aRet <<= (sal_Int32) getPosition();
2815 else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME))
2816 aRet <<= mpLayoutName.get() ? *mpLayoutName : rtl::OUString();
2817 else
2819 DBG_ERROR("unknown property");
2820 //! THROW( UnknownPropertyException() );
2822 return aRet;
2825 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPMember )