diff options
Diffstat (limited to 'sc/source/core/data/dptabsrc.cxx')
-rw-r--r-- | sc/source/core/data/dptabsrc.cxx | 2927 |
1 files changed, 2927 insertions, 0 deletions
diff --git a/sc/source/core/data/dptabsrc.cxx b/sc/source/core/data/dptabsrc.cxx new file mode 100644 index 000000000000..b4ca5dbc7330 --- /dev/null +++ b/sc/source/core/data/dptabsrc.cxx @@ -0,0 +1,2927 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + + + + +// INCLUDE --------------------------------------------------------------- + +#include <algorithm> +#include <vector> +#include <set> +#include <hash_map> +#include <hash_set> + +#include <tools/debug.hxx> +#include <rtl/math.hxx> +#include <svl/itemprop.hxx> +#include <svl/intitem.hxx> + +#include "scitems.hxx" +#include "document.hxx" +#include "docpool.hxx" +#include "patattr.hxx" +#include "cell.hxx" + +#include "dptabsrc.hxx" +#include "dptabres.hxx" +#include "dptabdat.hxx" +#include "global.hxx" +#include "collect.hxx" +#include "datauno.hxx" // ScDataUnoConversion +#include "unoguard.hxx" +#include "miscuno.hxx" +#include "unonames.hxx" + +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/sheet/DataPilotFieldFilter.hpp> +#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> +#include <com/sun/star/sheet/DataPilotFieldFilter.hpp> +#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp> +#include <com/sun/star/sheet/DataPilotFieldSortMode.hpp> +#include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp> +#include <com/sun/star/table/CellAddress.hpp> + +#include <unotools/collatorwrapper.hxx> +#include <unotools/calendarwrapper.hxx> +#include <com/sun/star/i18n/CalendarDisplayIndex.hpp> + +using namespace com::sun::star; +using ::std::vector; +using ::std::set; +using ::std::hash_map; +using ::std::hash_set; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; +using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo; +using ::rtl::OUString; + +// ----------------------------------------------------------------------- + +#define SC_MINCOUNT_LIMIT 1000000 + +// ----------------------------------------------------------------------- + +SC_SIMPLE_SERVICE_INFO( ScDPSource, "ScDPSource", "com.sun.star.sheet.DataPilotSource" ) +SC_SIMPLE_SERVICE_INFO( ScDPDimensions, "ScDPDimensions", "com.sun.star.sheet.DataPilotSourceDimensions" ) +SC_SIMPLE_SERVICE_INFO( ScDPDimension, "ScDPDimension", "com.sun.star.sheet.DataPilotSourceDimension" ) +SC_SIMPLE_SERVICE_INFO( ScDPHierarchies, "ScDPHierarchies", "com.sun.star.sheet.DataPilotSourceHierarcies" ) +SC_SIMPLE_SERVICE_INFO( ScDPHierarchy, "ScDPHierarchy", "com.sun.star.sheet.DataPilotSourceHierarcy" ) +SC_SIMPLE_SERVICE_INFO( ScDPLevels, "ScDPLevels", "com.sun.star.sheet.DataPilotSourceLevels" ) +SC_SIMPLE_SERVICE_INFO( ScDPLevel, "ScDPLevel", "com.sun.star.sheet.DataPilotSourceLevel" ) +SC_SIMPLE_SERVICE_INFO( ScDPMembers, "ScDPMembers", "com.sun.star.sheet.DataPilotSourceMembers" ) +SC_SIMPLE_SERVICE_INFO( ScDPMember, "ScDPMember", "com.sun.star.sheet.DataPilotSourceMember" ) + +// ----------------------------------------------------------------------- + +// property maps for PropertySetInfo +// DataDescription / NumberFormat are internal + +// ----------------------------------------------------------------------- + +//! move to a header? +BOOL lcl_GetBoolFromAny( const uno::Any& aAny ) +{ + if ( aAny.getValueTypeClass() == uno::TypeClass_BOOLEAN ) + return *(sal_Bool*)aAny.getValue(); + return FALSE; +} + +void lcl_SetBoolInAny( uno::Any& rAny, BOOL bValue ) +{ + rAny.setValue( &bValue, getBooleanCppuType() ); +} + +// ----------------------------------------------------------------------- + +ScDPSource::ScDPSource( ScDPTableData* pD ) : + pData( pD ), + pDimensions( NULL ), + nColDimCount( 0 ), + nRowDimCount( 0 ), + nDataDimCount( 0 ), + nPageDimCount( 0 ), + bColumnGrand( TRUE ), // default is true + bRowGrand( TRUE ), + bIgnoreEmptyRows( FALSE ), + bRepeatIfEmpty( FALSE ), + nDupCount( 0 ), + pResData( NULL ), + pColResRoot( NULL ), + pRowResRoot( NULL ), + pColResults( NULL ), + pRowResults( NULL ), + bResultOverflow( FALSE ), + mpGrandTotalName(NULL) +{ + pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty ); +} + +ScDPSource::~ScDPSource() +{ + if (pDimensions) + pDimensions->release(); // ref-counted + + //! free lists + + delete[] pColResults; + delete[] pRowResults; + + delete pColResRoot; + delete pRowResRoot; + delete pResData; +} + +void ScDPSource::SetGrandTotalName(const ::rtl::OUString& rName) +{ + mpGrandTotalName.reset(new ::rtl::OUString(rName)); +} + +const ::rtl::OUString* ScDPSource::GetGrandTotalName() const +{ + return mpGrandTotalName.get(); +} + +USHORT ScDPSource::GetOrientation(long nColumn) +{ + long i; + for (i=0; i<nColDimCount; i++) + if (nColDims[i] == nColumn) + return sheet::DataPilotFieldOrientation_COLUMN; + for (i=0; i<nRowDimCount; i++) + if (nRowDims[i] == nColumn) + return sheet::DataPilotFieldOrientation_ROW; + for (i=0; i<nDataDimCount; i++) + if (nDataDims[i] == nColumn) + return sheet::DataPilotFieldOrientation_DATA; + for (i=0; i<nPageDimCount; i++) + if (nPageDims[i] == nColumn) + return sheet::DataPilotFieldOrientation_PAGE; + return sheet::DataPilotFieldOrientation_HIDDEN; +} + +long ScDPSource::GetDataDimensionCount() +{ + return nDataDimCount; +} + +ScDPDimension* ScDPSource::GetDataDimension(long nIndex) +{ + if (nIndex < 0 || nIndex >= nDataDimCount) + return NULL; + + long nDimIndex = nDataDims[nIndex]; + return GetDimensionsObject()->getByIndex(nDimIndex); +} + +String ScDPSource::GetDataDimName( long nIndex ) +{ + String aRet; + ScDPDimension* pDim = GetDataDimension(nIndex); + if (pDim) + aRet = String(pDim->getName()); + return aRet; +} + +long ScDPSource::GetPosition(long nColumn) +{ + long i; + for (i=0; i<nColDimCount; i++) + if (nColDims[i] == nColumn) + return i; + for (i=0; i<nRowDimCount; i++) + if (nRowDims[i] == nColumn) + return i; + for (i=0; i<nDataDimCount; i++) + if (nDataDims[i] == nColumn) + return i; + for (i=0; i<nPageDimCount; i++) + if (nPageDims[i] == nColumn) + return i; + return 0; +} + +BOOL lcl_TestSubTotal( BOOL& rAllowed, long nColumn, long* pArray, long nCount, ScDPSource* pSource ) +{ + for (long i=0; i<nCount; i++) + if (pArray[i] == nColumn) + { + // no subtotals for data layout dim, no matter where + if ( pSource->IsDataLayoutDimension(nColumn) ) + rAllowed = FALSE; + else + { + // no subtotals if no other dim but data layout follows + long nNextIndex = i+1; + if ( nNextIndex < nCount && pSource->IsDataLayoutDimension(pArray[nNextIndex]) ) + ++nNextIndex; + if ( nNextIndex >= nCount ) + rAllowed = FALSE; + } + + return TRUE; // found + } + return FALSE; +} + +BOOL ScDPSource::SubTotalAllowed(long nColumn) +{ + //! cache this at ScDPResultData + BOOL bAllowed = TRUE; + if ( lcl_TestSubTotal( bAllowed, nColumn, nColDims, nColDimCount, this ) ) + return bAllowed; + if ( lcl_TestSubTotal( bAllowed, nColumn, nRowDims, nRowDimCount, this ) ) + return bAllowed; + return bAllowed; +} + +void lcl_RemoveDim( long nRemove, long* pDims, long& rCount ) +{ + for (long i=0; i<rCount; i++) + if ( pDims[i] == nRemove ) + { + for (long j=i; j+1<rCount; j++) + pDims[j] = pDims[j+1]; + --rCount; + return; + } +} + +void ScDPSource::SetOrientation(long nColumn, USHORT nNew) +{ + //! change to no-op if new orientation is equal to old? + + // remove from old list + lcl_RemoveDim( nColumn, nColDims, nColDimCount ); + lcl_RemoveDim( nColumn, nRowDims, nRowDimCount ); + lcl_RemoveDim( nColumn, nDataDims, nDataDimCount ); + lcl_RemoveDim( nColumn, nPageDims, nPageDimCount ); + + // add to new list + switch (nNew) + { + case sheet::DataPilotFieldOrientation_COLUMN: + nColDims[nColDimCount++] = nColumn; + break; + case sheet::DataPilotFieldOrientation_ROW: + nRowDims[nRowDimCount++] = nColumn; + break; + case sheet::DataPilotFieldOrientation_DATA: + nDataDims[nDataDimCount++] = nColumn; + break; + case sheet::DataPilotFieldOrientation_PAGE: + nPageDims[nPageDimCount++] = nColumn; + break; + // Wang Xu Ming -- 2009-9-1 + // DataPilot Migration - Cache&&Performance + case sheet::DataPilotFieldOrientation_HIDDEN: + break; + // End Comments + default: + DBG_ERROR( "ScDPSource::SetOrientation: unexpected orientation" ); + break; + } +} + +BOOL ScDPSource::IsDataLayoutDimension(long nDim) +{ + return nDim == pData->GetColumnCount(); +} + +USHORT ScDPSource::GetDataLayoutOrientation() +{ + return GetOrientation(pData->GetColumnCount()); +} + +BOOL ScDPSource::IsDateDimension(long nDim) +{ + return pData->IsDateDimension(nDim); +} + +UINT32 ScDPSource::GetNumberFormat(long nDim) +{ + return pData->GetNumberFormat( nDim ); +} + +ScDPDimensions* ScDPSource::GetDimensionsObject() +{ + if (!pDimensions) + { + pDimensions = new ScDPDimensions(this); + pDimensions->acquire(); // ref-counted + } + return pDimensions; +} + +uno::Reference<container::XNameAccess> SAL_CALL ScDPSource::getDimensions() throw(uno::RuntimeException) +{ + return GetDimensionsObject(); +} + +void ScDPSource::SetDupCount( long nNew ) +{ + nDupCount = nNew; +} + +ScDPDimension* ScDPSource::AddDuplicated(long /* nSource */, const String& rNewName) +{ + DBG_ASSERT( pDimensions, "AddDuplicated without dimensions?" ); + + // re-use + + long nOldDimCount = pDimensions->getCount(); + for (long i=0; i<nOldDimCount; i++) + { + ScDPDimension* pDim = pDimensions->getByIndex(i); + if (pDim && String(pDim->getName()) == rNewName) + { + //! test if pDim is a duplicate of source + return pDim; + } + } + + SetDupCount( nDupCount + 1 ); + pDimensions->CountChanged(); // uses nDupCount + + return pDimensions->getByIndex( pDimensions->getCount() - 1 ); +} + +long ScDPSource::GetSourceDim(long nDim) +{ + // original source dimension or data layout dimension? + if ( nDim <= pData->GetColumnCount() ) + return nDim; + + if ( nDim < pDimensions->getCount() ) + { + ScDPDimension* pDimObj = pDimensions->getByIndex( nDim ); + if ( pDimObj ) + { + long nSource = pDimObj->GetSourceDim(); + if ( nSource >= 0 ) + return nSource; + } + } + + DBG_ERROR("GetSourceDim: wrong dim"); + return nDim; +} + +uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResults() + throw(uno::RuntimeException) +{ + CreateRes_Impl(); // create pColResRoot and pRowResRoot + + if ( bResultOverflow ) // set in CreateRes_Impl + { + // no results available + throw uno::RuntimeException(); + } + + long nColCount = pColResRoot->GetSize(pResData->GetColStartMeasure()); + long nRowCount = pRowResRoot->GetSize(pResData->GetRowStartMeasure()); + + // allocate full sequence + //! leave out empty rows??? + + uno::Sequence< uno::Sequence<sheet::DataResult> > aSeq( nRowCount ); + uno::Sequence<sheet::DataResult>* pRowAry = aSeq.getArray(); + for (long nRow = 0; nRow < nRowCount; nRow++) + { + uno::Sequence<sheet::DataResult> aColSeq( nColCount ); + // use default values of DataResult + pRowAry[nRow] = aColSeq; + } + + long nSeqRow = 0; + pRowResRoot->FillDataResults( pColResRoot, aSeq, nSeqRow, pResData->GetRowStartMeasure() ); + + return aSeq; +} + +void SAL_CALL ScDPSource::refresh() throw(uno::RuntimeException) +{ + disposeData(); +} + +void SAL_CALL ScDPSource::addRefreshListener( const uno::Reference<util::XRefreshListener >& ) + throw(uno::RuntimeException) +{ + DBG_ERROR("not implemented"); //! exception? +} + +void SAL_CALL ScDPSource::removeRefreshListener( const uno::Reference<util::XRefreshListener >& ) + throw(uno::RuntimeException) +{ + DBG_ERROR("not implemented"); //! exception? +} + +Sequence< Sequence<Any> > SAL_CALL ScDPSource::getDrillDownData(const Sequence<sheet::DataPilotFieldFilter>& aFilters) + throw (uno::RuntimeException) +{ + long nColumnCount = GetData()->GetColumnCount(); + + typedef hash_map<String, long, ScStringHashCode> FieldNameMapType; + FieldNameMapType aFieldNames; + for (long i = 0; i < nColumnCount; ++i) + { + aFieldNames.insert( + FieldNameMapType::value_type(GetData()->getDimensionName(i), i)); + } + + // collect ScDPItemData for each filtered column + vector<ScDPCacheTable::Criterion> aFilterCriteria; + sal_Int32 nFilterCount = aFilters.getLength(); + for (sal_Int32 i = 0; i < nFilterCount; ++i) + { + const sheet::DataPilotFieldFilter& rFilter = aFilters[i]; + String aFieldName( rFilter.FieldName ); + for (long nCol = 0; nCol < nColumnCount; ++nCol) + { + if ( aFieldName == pData->getDimensionName(nCol) ) + { + ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nCol ); + ScDPMembers* pMembers = pDim->GetHierarchiesObject()->getByIndex(0)-> + GetLevelsObject()->getByIndex(0)->GetMembersObject(); + sal_Int32 nIndex = pMembers->GetIndexFromName( rFilter.MatchValue ); + if ( nIndex >= 0 ) + { + ScDPItemData aItem; + pMembers->getByIndex(nIndex)->FillItemData( aItem ); + aFilterCriteria.push_back( ScDPCacheTable::Criterion() ); + aFilterCriteria.back().mnFieldIndex = nCol; + aFilterCriteria.back().mpFilter.reset( + new ScDPCacheTable::SingleFilter(aItem.GetString()/*rSharedString, nMatchStrId*/, aItem.GetValue(), aItem.IsValue()) ); + } + } + } + } + + // Take into account the visibilities of field members. + ScDPResultVisibilityData aResVisData(/*rSharedString, */this); + pRowResRoot->FillVisibilityData(aResVisData); + pColResRoot->FillVisibilityData(aResVisData); + aResVisData.fillFieldFilters(aFilterCriteria); + + Sequence< Sequence<Any> > aTabData; + hash_set<sal_Int32> aCatDims; + GetCategoryDimensionIndices(aCatDims); + pData->GetDrillDownData(aFilterCriteria, aCatDims, aTabData); + return aTabData; +} + +String ScDPSource::getDataDescription() +{ + CreateRes_Impl(); // create pResData + + String aRet; + if ( pResData->GetMeasureCount() == 1 ) + { + bool bTotalResult = false; + aRet = pResData->GetMeasureString( 0, TRUE, SUBTOTAL_FUNC_NONE, bTotalResult ); + } + + // empty for more than one measure + + return aRet; +} + +BOOL ScDPSource::getColumnGrand() const +{ + return bColumnGrand; +} + +void ScDPSource::setColumnGrand(BOOL bSet) +{ + bColumnGrand = bSet; +} + +BOOL ScDPSource::getRowGrand() const +{ + return bRowGrand; +} + +void ScDPSource::setRowGrand(BOOL bSet) +{ + bRowGrand = bSet; +} + +BOOL ScDPSource::getIgnoreEmptyRows() const +{ + return bIgnoreEmptyRows; +} + +void ScDPSource::setIgnoreEmptyRows(BOOL bSet) +{ + bIgnoreEmptyRows = bSet; + pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty ); +} + +BOOL ScDPSource::getRepeatIfEmpty() const +{ + return bRepeatIfEmpty; +} + +void ScDPSource::setRepeatIfEmpty(BOOL bSet) +{ + bRepeatIfEmpty = bSet; + pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty ); +} + +void ScDPSource::validate() //! ??? +{ + CreateRes_Impl(); +} + +void ScDPSource::disposeData() +{ + if ( pResData ) + { + // reset all data... + + DELETEZ(pColResRoot); + DELETEZ(pRowResRoot); + DELETEZ(pResData); + delete[] pColResults; + delete[] pRowResults; + pColResults = NULL; + pRowResults = NULL; + aColLevelList.Clear(); + aRowLevelList.Clear(); + } + + if ( pDimensions ) + { + pDimensions->release(); // ref-counted + pDimensions = NULL; // settings have to be applied (from SaveData) again! + } + SetDupCount( 0 ); + + //! Test ???? + nColDimCount = nRowDimCount = nDataDimCount = nPageDimCount = 0; + + pData->DisposeData(); // cached entries etc. + bResultOverflow = FALSE; +} + +long lcl_CountMinMembers(const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLevel, long nLevels ) +{ + // Calculate the product of the member count for those consecutive levels that + // have the "show all" flag, one following level, and the data layout dimension. + + long nTotal = 1; + long nDataCount = 1; + BOOL bWasShowAll = TRUE; + long nPos = nLevels; + while ( nPos > 0 ) + { + --nPos; + + if ( nPos+1 < nLevels && ppDim[nPos] == ppDim[nPos+1] ) + { + DBG_ERROR("lcl_CountMinMembers: multiple levels from one dimension not implemented"); + return 0; + } + + BOOL bDo = FALSE; + if ( ppDim[nPos]->getIsDataLayoutDimension() ) + { + // data layout dim doesn't interfere with "show all" flags + nDataCount = ppLevel[nPos]->GetMembersObject()->getCount(); + if ( nDataCount == 0 ) + nDataCount = 1; + } + else if ( bWasShowAll ) // "show all" set for all following levels? + { + bDo = TRUE; + if ( !ppLevel[nPos]->getShowEmpty() ) + { + // this level is counted, following ones are not + bWasShowAll = FALSE; + } + } + if ( bDo ) + { + long nThisCount = ppLevel[nPos]->GetMembersObject()->getMinMembers(); + if ( nThisCount == 0 ) + { + nTotal = 1; // empty level -> start counting from here + //! start with visible elements in this level? + } + else + { + if ( nTotal >= LONG_MAX / nThisCount ) + return LONG_MAX; // overflow + nTotal *= nThisCount; + } + } + } + + // always include data layout dim, even after restarting + if ( nTotal >= LONG_MAX / nDataCount ) + return LONG_MAX; // overflow + nTotal *= nDataCount; + + return nTotal; +} + +long lcl_GetIndexFromName( const rtl::OUString rName, const uno::Sequence<rtl::OUString>& rElements ) +{ + long nCount = rElements.getLength(); + const rtl::OUString* pArray = rElements.getConstArray(); + for (long nPos=0; nPos<nCount; nPos++) + if (pArray[nPos] == rName) + return nPos; + + return -1; // not found +} + +void ScDPSource::FillCalcInfo(bool bIsRow, ScDPTableData::CalcInfo& rInfo, bool &rHasAutoShow) +{ + long* nDims = bIsRow ? nRowDims : nColDims; + long nDimCount = bIsRow ? nRowDimCount : nColDimCount; + + for (long i = 0; i < nDimCount; ++i) + { + ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nDims[i] ); + long nHierarchy = pDim->getUsedHierarchy(); + if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() ) + nHierarchy = 0; + ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject(); + long nCount = pLevels->getCount(); + + //! Test + if ( pDim->getIsDataLayoutDimension() && nDataDimCount < 2 ) + nCount = 0; + //! Test + + for (long j = 0; j < nCount; ++j) + { + ScDPLevel* pLevel = pLevels->getByIndex(j); + pLevel->EvaluateSortOrder(); + + // no layout flags for column fields, only for row fields + pLevel->SetEnableLayout( bIsRow ); + + if ( pLevel->GetAutoShow().IsEnabled ) + rHasAutoShow = TRUE; + + if (bIsRow) + { + rInfo.aRowLevelDims.push_back(nDims[i]); + rInfo.aRowDims.push_back(pDim); + rInfo.aRowLevels.push_back(pLevel); + } + else + { + rInfo.aColLevelDims.push_back(nDims[i]); + rInfo.aColDims.push_back(pDim); + rInfo.aColLevels.push_back(pLevel); + } + + pLevel->GetMembersObject(); // initialize for groups + } + } +} + +void ScDPSource::GetCategoryDimensionIndices(hash_set<sal_Int32>& rCatDims) +{ + hash_set<sal_Int32> aCatDims; + for (long i = 0; i < nColDimCount; ++i) + { + sal_Int32 nDim = static_cast<sal_Int32>(nColDims[i]); + if (!IsDataLayoutDimension(nDim)) + aCatDims.insert(nDim); + } + + for (long i = 0; i < nRowDimCount; ++i) + { + sal_Int32 nDim = static_cast<sal_Int32>(nRowDims[i]); + if (!IsDataLayoutDimension(nDim)) + aCatDims.insert(nDim); + } + + for (long i = 0; i < nPageDimCount; ++i) + { + sal_Int32 nDim = static_cast<sal_Int32>(nPageDims[i]); + if (!IsDataLayoutDimension(nDim)) + aCatDims.insert(nDim); + } + + rCatDims.swap(aCatDims); +} + +void ScDPSource::FilterCacheTableByPageDimensions() +{ + + // filter table by page dimensions. + vector<ScDPCacheTable::Criterion> aCriteria; + for (long i = 0; i < nPageDimCount; ++i) + { + ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nPageDims[i]); + long nField = pDim->GetDimension(); + + ScDPMembers* pMems = pDim->GetHierarchiesObject()->getByIndex(0)-> + GetLevelsObject()->getByIndex(0)->GetMembersObject(); + + long nMemCount = pMems->getCount(); + ScDPCacheTable::Criterion aFilter; + aFilter.mnFieldIndex = static_cast<sal_Int32>(nField); + aFilter.mpFilter.reset(new ScDPCacheTable::GroupFilter(/*rSharedString*/)); + ScDPCacheTable::GroupFilter* pGrpFilter = + static_cast<ScDPCacheTable::GroupFilter*>(aFilter.mpFilter.get()); + for (long j = 0; j < nMemCount; ++j) + { + ScDPMember* pMem = pMems->getByIndex(j); + if (pMem->getIsVisible()) + { + ScDPItemData aData; + pMem->FillItemData(aData); + pGrpFilter->addMatchItem(aData.GetString(), aData.GetValue(), aData.IsValue()); + } + } + if (pGrpFilter->getMatchItemCount() < static_cast<size_t>(nMemCount)) + // there is at least one invisible item. Add this filter criterion to the mix. + aCriteria.push_back(aFilter); + + if (!pDim || !pDim->HasSelectedPage()) + continue; + + const ScDPItemData& rData = pDim->GetSelectedData(); + aCriteria.push_back(ScDPCacheTable::Criterion()); + ScDPCacheTable::Criterion& r = aCriteria.back(); + r.mnFieldIndex = static_cast<sal_Int32>(nField); + r.mpFilter.reset( + new ScDPCacheTable::SingleFilter(rData.GetString()/*rSharedString, nStrId*/, rData.GetValue(), rData.IsValue())); + } + if (!aCriteria.empty()) + { + hash_set<sal_Int32> aCatDims; + GetCategoryDimensionIndices(aCatDims); + pData->FilterCacheTable(aCriteria, aCatDims); + } +} + +void ScDPSource::CreateRes_Impl() +{ + if ( !pResData ) + { + USHORT nDataOrient = GetDataLayoutOrientation(); + if ( nDataDimCount > 1 && ( nDataOrient != sheet::DataPilotFieldOrientation_COLUMN && + nDataOrient != sheet::DataPilotFieldOrientation_ROW ) ) + { + // if more than one data dimension, data layout orientation must be set + SetOrientation( pData->GetColumnCount(), sheet::DataPilotFieldOrientation_ROW ); + nDataOrient = sheet::DataPilotFieldOrientation_ROW; + } + + // TODO: Aggreate pDataNames, pDataRefValues, nDataRefOrient, and + // eDataFunctions into a structure and use vector instead of static + // or pointer arrays. + String* pDataNames = NULL; + sheet::DataPilotFieldReference* pDataRefValues = NULL; + ScSubTotalFunc eDataFunctions[SC_DAPI_MAXFIELDS]; + USHORT nDataRefOrient[SC_DAPI_MAXFIELDS]; + if (nDataDimCount) + { + pDataNames = new String[nDataDimCount]; + pDataRefValues = new sheet::DataPilotFieldReference[nDataDimCount]; + } + + ScDPTableData::CalcInfo aInfo; + + + // LateInit (initialize only those rows/children that are used) can be used unless + // any data dimension needs reference values from column/row dimensions + BOOL bLateInit = TRUE; + + // Go through all data dimensions (i.e. fields) and build their meta data + // so that they can be passed on to ScDPResultData instance later. + // TODO: aggregate all of data dimension info into a structure. + long i; + for (i=0; i<nDataDimCount; i++) + { + // Get function for each data field. + long nDimIndex = nDataDims[i]; + ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nDimIndex); + sheet::GeneralFunction eUser = (sheet::GeneralFunction)pDim->getFunction(); + if (eUser == sheet::GeneralFunction_AUTO) + { + //! test for numeric data + eUser = sheet::GeneralFunction_SUM; + } + + // Map UNO's enum to internal enum ScSubTotalFunc. + eDataFunctions[i] = ScDataUnoConversion::GeneralToSubTotal( eUser ); + + // Get reference field/item information. + pDataRefValues[i] = pDim->GetReferenceValue(); + nDataRefOrient[i] = sheet::DataPilotFieldOrientation_HIDDEN; // default if not used + sal_Int32 eRefType = pDataRefValues[i].ReferenceType; + if ( eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE || + eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE || + eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE || + eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL ) + { + long nColumn = lcl_GetIndexFromName( pDataRefValues[i].ReferenceField, + GetDimensionsObject()->getElementNames() ); + if ( nColumn >= 0 ) + { + nDataRefOrient[i] = GetOrientation( nColumn ); + // need fully initialized results to find reference values + // (both in column or row dimensions), so updated values or + // differences to 0 can be displayed even for empty results. + bLateInit = FALSE; + } + } + + pDataNames[i] = String( pDim->getName() ); //! label? + + // asterisk is added to duplicated dimension names by ScDPSaveData::WriteToSource + //! modify user visible strings as in ScDPResultData::GetMeasureString instead! + + pDataNames[i].EraseTrailingChars('*'); + + //! if the name is overridden by user, a flag must be set + //! so the user defined name replaces the function string and field name. + + //! the complete name (function and field) must be stored at the dimension + + long nSource = ((ScDPDimension*)pDim)->GetSourceDim(); + if (nSource >= 0) + aInfo.aDataSrcCols.push_back(nSource); + else + aInfo.aDataSrcCols.push_back(nDimIndex); + } + + pResData = new ScDPResultData( this ); + pResData->SetMeasureData( nDataDimCount, eDataFunctions, pDataRefValues, nDataRefOrient, pDataNames ); + pResData->SetDataLayoutOrientation(nDataOrient); + pResData->SetLateInit( bLateInit ); + + delete[] pDataNames; + delete[] pDataRefValues; + + bool bHasAutoShow = false; + + ScDPInitState aInitState; + + // Page field selections restrict the members shown in related fields + // (both in column and row fields). aInitState is filled with the page + // field selections, they are kept across the data iterator loop. + + for (i=0; i<nPageDimCount; i++) + { + ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nPageDims[i] ); + if ( pDim->HasSelectedPage() ) + aInitState.AddMember( nPageDims[i], GetMemberId( nPageDims[i], pDim->GetSelectedData() ) ); + } + + pColResRoot = new ScDPResultMember( pResData, /*NULL, NULL, NULL, */bColumnGrand ); + pRowResRoot = new ScDPResultMember( pResData, /*NULL, NULL, NULL, */bRowGrand ); + + FillCalcInfo(false, aInfo, bHasAutoShow); + long nColLevelCount = aInfo.aColLevels.size(); + + pColResRoot->InitFrom( aInfo.aColDims, aInfo.aColLevels, 0, aInitState ); + pColResRoot->SetHasElements(); + + FillCalcInfo(true, aInfo, bHasAutoShow); + long nRowLevelCount = aInfo.aRowLevels.size(); + + if ( nRowLevelCount > 0 ) + { + // disable layout flags for the innermost row field (level) + aInfo.aRowLevels[nRowLevelCount-1]->SetEnableLayout( FALSE ); + } + + pRowResRoot->InitFrom( aInfo.aRowDims, aInfo.aRowLevels, 0, aInitState ); + pRowResRoot->SetHasElements(); + + // initialize members object also for all page dimensions (needed for numeric groups) + for (i=0; i<nPageDimCount; i++) + { + ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nPageDims[i] ); + long nHierarchy = pDim->getUsedHierarchy(); + if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() ) + nHierarchy = 0; + + ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject(); + long nCount = pLevels->getCount(); + for (long j=0; j<nCount; j++) + pLevels->getByIndex(j)->GetMembersObject(); // initialize for groups + } + + // pre-check: calculate minimum number of result columns / rows from + // levels that have the "show all" flag set + + long nMinColMembers = lcl_CountMinMembers( aInfo.aColDims, aInfo.aColLevels, nColLevelCount ); + long nMinRowMembers = lcl_CountMinMembers( aInfo.aRowDims, aInfo.aRowLevels, nRowLevelCount ); + + if ( nMinColMembers > MAXCOLCOUNT/*SC_MINCOUNT_LIMIT*/ || nMinRowMembers > SC_MINCOUNT_LIMIT ) + { + // resulting table is too big -> abort before calculating + // (this relies on late init, so no members are allocated in InitFrom above) + + bResultOverflow = TRUE; + } + else + { + FilterCacheTableByPageDimensions(); + + aInfo.aPageDims.reserve(nPageDimCount); + for (i = 0; i < nPageDimCount; ++i) + aInfo.aPageDims.push_back(nPageDims[i]); + + aInfo.pInitState = &aInitState; + aInfo.pColRoot = pColResRoot; + aInfo.pRowRoot = pRowResRoot; + pData->CalcResults(aInfo, false); + + pColResRoot->CheckShowEmpty(); + pRowResRoot->CheckShowEmpty(); + // ---------------------------------------------------------------- + // With all data processed, calculate the final results: + + // UpdateDataResults calculates all original results from the collected values, + // and stores them as reference values if needed. + pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() ); + + if ( bHasAutoShow ) // do the double calculation only if AutoShow is used + { + // Find the desired members and set bAutoHidden flag for the others + pRowResRoot->DoAutoShow( pColResRoot ); + + // Reset all results to empty, so they can be built again with data for the + // desired members only. + pColResRoot->ResetResults( TRUE ); + pRowResRoot->ResetResults( TRUE ); + pData->CalcResults(aInfo, true); + + // Call UpdateDataResults again, with the new (limited) values. + pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() ); + } + + // SortMembers does the sorting by a result dimension, using the orginal results, + // but not running totals etc. + pRowResRoot->SortMembers( pColResRoot ); + + // UpdateRunningTotals calculates running totals along column/row dimensions, + // differences from other members (named or relative), and column/row percentages + // or index values. + // Running totals and relative differences need to be done using the sorted values. + // Column/row percentages and index values must be done after sorting, because the + // results may no longer be in the right order (row total for percentage of row is + // always 1). + ScDPRunningTotalState aRunning( pColResRoot, pRowResRoot ); + ScDPRowTotals aTotals; + pRowResRoot->UpdateRunningTotals( pColResRoot, pResData->GetRowStartMeasure(), aRunning, aTotals ); + + // ---------------------------------------------------------------- + } + } +} + +//UNUSED2009-05 void ScDPSource::DumpState( ScDocument* pDoc, const ScAddress& rPos ) +//UNUSED2009-05 { +//UNUSED2009-05 CreateRes_Impl(); +//UNUSED2009-05 +//UNUSED2009-05 ScAddress aDocPos( rPos ); +//UNUSED2009-05 +//UNUSED2009-05 if (pColResRoot->GetChildDimension()) +//UNUSED2009-05 pColResRoot->GetChildDimension()->DumpState( NULL, pDoc, aDocPos ); +//UNUSED2009-05 pRowResRoot->DumpState( pColResRoot, pDoc, aDocPos ); +//UNUSED2009-05 } + +void ScDPSource::FillLevelList( USHORT nOrientation, List& rList ) +{ + rList.Clear(); + + long nDimCount = 0; + long* pDimIndex = NULL; + switch (nOrientation) + { + case sheet::DataPilotFieldOrientation_COLUMN: + pDimIndex = nColDims; + nDimCount = nColDimCount; + break; + case sheet::DataPilotFieldOrientation_ROW: + pDimIndex = nRowDims; + nDimCount = nRowDimCount; + break; + case sheet::DataPilotFieldOrientation_DATA: + pDimIndex = nDataDims; + nDimCount = nDataDimCount; + break; + case sheet::DataPilotFieldOrientation_PAGE: + pDimIndex = nPageDims; + nDimCount = nPageDimCount; + break; + default: + DBG_ERROR( "ScDPSource::FillLevelList: unexpected orientation" ); + break; + } + if (!pDimIndex) + { + DBG_ERROR("invalid orientation"); + return; + } + + ScDPDimensions* pDims = GetDimensionsObject(); + for (long nDim=0; nDim<nDimCount; nDim++) + { + ScDPDimension* pDim = pDims->getByIndex(pDimIndex[nDim]); + DBG_ASSERT( pDim->getOrientation() == nOrientation, "orientations are wrong" ); + + ScDPHierarchies* pHiers = pDim->GetHierarchiesObject(); + long nHierarchy = pDim->getUsedHierarchy(); + if ( nHierarchy >= pHiers->getCount() ) + nHierarchy = 0; + ScDPHierarchy* pHier = pHiers->getByIndex(nHierarchy); + ScDPLevels* pLevels = pHier->GetLevelsObject(); + long nLevCount = pLevels->getCount(); + for (long nLev=0; nLev<nLevCount; nLev++) + { + ScDPLevel* pLevel = pLevels->getByIndex(nLev); + rList.Insert( pLevel, LIST_APPEND ); + } + } +} + +void ScDPSource::FillMemberResults() +{ + if ( !pColResults && !pRowResults ) + { + CreateRes_Impl(); + + if ( bResultOverflow ) // set in CreateRes_Impl + { + // no results available -> abort (leave empty) + // exception is thrown in ScDPSource::getResults + return; + } + + FillLevelList( sheet::DataPilotFieldOrientation_COLUMN, aColLevelList ); + long nColLevelCount = aColLevelList.Count(); + if (nColLevelCount) + { + long nColDimSize = pColResRoot->GetSize(pResData->GetColStartMeasure()); + pColResults = new uno::Sequence<sheet::MemberResult>[nColLevelCount]; + for (long i=0; i<nColLevelCount; i++) + pColResults[i].realloc(nColDimSize); + + // ScDPResultDimension* pColResDim = pColResRoot->GetChildDimension(); + // pColResDim->FillMemberResults( pColResults, 0, pResData->GetColStartMeasure() ); + long nPos = 0; + pColResRoot->FillMemberResults( pColResults, nPos, pResData->GetColStartMeasure(), + TRUE, NULL, NULL ); + } + + FillLevelList( sheet::DataPilotFieldOrientation_ROW, aRowLevelList ); + long nRowLevelCount = aRowLevelList.Count(); + if (nRowLevelCount) + { + long nRowDimSize = pRowResRoot->GetSize(pResData->GetRowStartMeasure()); + pRowResults = new uno::Sequence<sheet::MemberResult>[nRowLevelCount]; + for (long i=0; i<nRowLevelCount; i++) + pRowResults[i].realloc(nRowDimSize); + + // ScDPResultDimension* pRowResDim = pRowResRoot->GetChildDimension(); + // pRowResDim->FillMemberResults( pRowResults, 0, pResData->GetRowStartMeasure() ); + long nPos = 0; + pRowResRoot->FillMemberResults( pRowResults, nPos, pResData->GetRowStartMeasure(), + TRUE, NULL, NULL ); + } + } +} + +const uno::Sequence<sheet::MemberResult>* ScDPSource::GetMemberResults( ScDPLevel* pLevel ) +{ + FillMemberResults(); + + long i; + long nColCount = aColLevelList.Count(); + for (i=0; i<nColCount; i++) + { + ScDPLevel* pColLevel = (ScDPLevel*)aColLevelList.GetObject(i); + if ( pColLevel == pLevel ) + return pColResults+i; + } + long nRowCount = aRowLevelList.Count(); + for (i=0; i<nRowCount; i++) + { + ScDPLevel* pRowLevel = (ScDPLevel*)aRowLevelList.GetObject(i); + if ( pRowLevel == pLevel ) + return pRowResults+i; + } + return NULL; +} + +// XPropertySet + +uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPSource::getPropertySetInfo() + throw(uno::RuntimeException) +{ + ScUnoGuard aGuard; + using beans::PropertyAttribute::READONLY; + + static SfxItemPropertyMapEntry aDPSourceMap_Impl[] = + { + {MAP_CHAR_LEN(SC_UNO_COLGRAND), 0, &getBooleanCppuType(), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_DATADESC), 0, &getCppuType((rtl::OUString*)0), beans::PropertyAttribute::READONLY, 0 }, + {MAP_CHAR_LEN(SC_UNO_IGNOREEM), 0, &getBooleanCppuType(), 0, 0 }, // for sheet data only + {MAP_CHAR_LEN(SC_UNO_REPEATIF), 0, &getBooleanCppuType(), 0, 0 }, // for sheet data only + {MAP_CHAR_LEN(SC_UNO_ROWGRAND), 0, &getBooleanCppuType(), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_ROWFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 }, + {MAP_CHAR_LEN(SC_UNO_COLUMNFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 }, + {MAP_CHAR_LEN(SC_UNO_DATAFIELDCOUNT), 0, &getCppuType(static_cast<sal_Int32*>(0)), READONLY, 0 }, + {MAP_CHAR_LEN(SC_UNO_GRANDTOTAL_NAME), 0, &getCppuType(static_cast<OUString*>(0)), 0, 0 }, + {0,0,0,0,0,0} + }; + static uno::Reference<beans::XPropertySetInfo> aRef = + new SfxItemPropertySetInfo( aDPSourceMap_Impl ); + return aRef; +} + +void SAL_CALL ScDPSource::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue ) + throw(beans::UnknownPropertyException, beans::PropertyVetoException, + lang::IllegalArgumentException, lang::WrappedTargetException, + uno::RuntimeException) +{ + String aNameStr = aPropertyName; + if ( aNameStr.EqualsAscii( SC_UNO_COLGRAND ) ) + setColumnGrand( lcl_GetBoolFromAny( aValue ) ); + else if ( aNameStr.EqualsAscii( SC_UNO_ROWGRAND ) ) + setRowGrand( lcl_GetBoolFromAny( aValue ) ); + else if ( aNameStr.EqualsAscii( SC_UNO_IGNOREEM ) ) + setIgnoreEmptyRows( lcl_GetBoolFromAny( aValue ) ); + else if ( aNameStr.EqualsAscii( SC_UNO_REPEATIF ) ) + setRepeatIfEmpty( lcl_GetBoolFromAny( aValue ) ); + else if (aNameStr.EqualsAscii(SC_UNO_GRANDTOTAL_NAME)) + { + OUString aName; + if (aValue >>= aName) + mpGrandTotalName.reset(new OUString(aName)); + } + else + { + DBG_ERROR("unknown property"); + //! THROW( UnknownPropertyException() ); + } +} + +uno::Any SAL_CALL ScDPSource::getPropertyValue( const rtl::OUString& aPropertyName ) + throw(beans::UnknownPropertyException, lang::WrappedTargetException, + uno::RuntimeException) +{ + uno::Any aRet; + String aNameStr = aPropertyName; + if ( aNameStr.EqualsAscii( SC_UNO_COLGRAND ) ) + lcl_SetBoolInAny( aRet, getColumnGrand() ); + else if ( aNameStr.EqualsAscii( SC_UNO_ROWGRAND ) ) + lcl_SetBoolInAny( aRet, getRowGrand() ); + else if ( aNameStr.EqualsAscii( SC_UNO_IGNOREEM ) ) + lcl_SetBoolInAny( aRet, getIgnoreEmptyRows() ); + else if ( aNameStr.EqualsAscii( SC_UNO_REPEATIF ) ) + lcl_SetBoolInAny( aRet, getRepeatIfEmpty() ); + else if ( aNameStr.EqualsAscii( SC_UNO_DATADESC ) ) // read-only + aRet <<= rtl::OUString( getDataDescription() ); + else if ( aNameStr.EqualsAscii( SC_UNO_ROWFIELDCOUNT ) ) // read-only + aRet <<= static_cast<sal_Int32>(nRowDimCount); + else if ( aNameStr.EqualsAscii( SC_UNO_COLUMNFIELDCOUNT ) ) // read-only + aRet <<= static_cast<sal_Int32>(nColDimCount); + else if ( aNameStr.EqualsAscii( SC_UNO_DATAFIELDCOUNT ) ) // read-only + aRet <<= static_cast<sal_Int32>(nDataDimCount); + else if (aNameStr.EqualsAscii(SC_UNO_GRANDTOTAL_NAME)) + { + if (mpGrandTotalName.get()) + aRet <<= *mpGrandTotalName; + } + else + { + DBG_ERROR("unknown property"); + //! THROW( UnknownPropertyException() ); + } + return aRet; +} + +SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPSource ) + +// ----------------------------------------------------------------------- + +ScDPDimensions::ScDPDimensions( ScDPSource* pSrc ) : + pSource( pSrc ), + ppDims( NULL ) +{ + //! hold pSource + + // include data layout dimension and duplicated dimensions + nDimCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount(); +} + +ScDPDimensions::~ScDPDimensions() +{ + //! release pSource + + if (ppDims) + { + for (long i=0; i<nDimCount; i++) + if ( ppDims[i] ) + ppDims[i]->release(); // ref-counted + delete[] ppDims; + } +} + +void ScDPDimensions::CountChanged() +{ + // include data layout dimension and duplicated dimensions + long nNewCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount(); + if ( ppDims ) + { + long i; + long nCopy = Min( nNewCount, nDimCount ); + ScDPDimension** ppNew = new ScDPDimension*[nNewCount]; + + for (i=0; i<nCopy; i++) // copy existing dims + ppNew[i] = ppDims[i]; + for (i=nCopy; i<nNewCount; i++) // clear additional pointers + ppNew[i] = NULL; + for (i=nCopy; i<nDimCount; i++) // delete old dims if count is decreased + if ( ppDims[i] ) + ppDims[i]->release(); // ref-counted + + delete[] ppDims; + ppDims = ppNew; + } + nDimCount = nNewCount; +} + +// very simple XNameAccess implementation using getCount/getByIndex + +uno::Any SAL_CALL ScDPDimensions::getByName( const rtl::OUString& aName ) + throw(container::NoSuchElementException, + lang::WrappedTargetException, uno::RuntimeException) +{ + long nCount = getCount(); + for (long i=0; i<nCount; i++) + if ( getByIndex(i)->getName() == aName ) + { + uno::Reference<container::XNamed> xNamed = getByIndex(i); + uno::Any aRet; + aRet <<= xNamed; + return aRet; + } + + throw container::NoSuchElementException(); +// return uno::Any(); +} + +uno::Sequence<rtl::OUString> SAL_CALL ScDPDimensions::getElementNames() throw(uno::RuntimeException) +{ + long nCount = getCount(); + uno::Sequence<rtl::OUString> aSeq(nCount); + rtl::OUString* pArr = aSeq.getArray(); + for (long i=0; i<nCount; i++) + pArr[i] = getByIndex(i)->getName(); + return aSeq; +} + +sal_Bool SAL_CALL ScDPDimensions::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException) +{ + long nCount = getCount(); + for (long i=0; i<nCount; i++) + if ( getByIndex(i)->getName() == aName ) + return TRUE; + return FALSE; +} + +uno::Type SAL_CALL ScDPDimensions::getElementType() throw(uno::RuntimeException) +{ + return getCppuType((uno::Reference<container::XNamed>*)0); +} + +sal_Bool SAL_CALL ScDPDimensions::hasElements() throw(uno::RuntimeException) +{ + return ( getCount() > 0 ); +} + +// end of XNameAccess implementation + +long ScDPDimensions::getCount() const +{ + // in tabular data, every column of source data is a dimension + + return nDimCount; +} + +ScDPDimension* ScDPDimensions::getByIndex(long nIndex) const +{ + if ( nIndex >= 0 && nIndex < nDimCount ) + { + if ( !ppDims ) + { + ((ScDPDimensions*)this)->ppDims = new ScDPDimension*[nDimCount]; + for (long i=0; i<nDimCount; i++) + ppDims[i] = NULL; + } + if ( !ppDims[nIndex] ) + { + ppDims[nIndex] = new ScDPDimension( pSource, nIndex ); + ppDims[nIndex]->acquire(); // ref-counted + } + + return ppDims[nIndex]; + } + + return NULL; //! exception? +} + +// ----------------------------------------------------------------------- + +ScDPDimension::ScDPDimension( ScDPSource* pSrc, long nD ) : + pSource( pSrc ), + nDim( nD ), + pHierarchies( NULL ), + nUsedHier( 0 ), + nFunction( SUBTOTAL_FUNC_SUM ), // sum is default + mpLayoutName(NULL), + mpSubtotalName(NULL), + nSourceDim( -1 ), + bHasSelectedPage( FALSE ), + pSelectedData( NULL ), + mbHasHiddenMember(false) +{ + //! hold pSource +} + +ScDPDimension::~ScDPDimension() +{ + //! release pSource + + if ( pHierarchies ) + pHierarchies->release(); // ref-counted + + delete pSelectedData; +} + +ScDPHierarchies* ScDPDimension::GetHierarchiesObject() +{ + if (!pHierarchies) + { + pHierarchies = new ScDPHierarchies( pSource, nDim ); + pHierarchies->acquire(); // ref-counted + } + return pHierarchies; +} + +const rtl::OUString* ScDPDimension::GetLayoutName() const +{ + return mpLayoutName.get(); +} + +const rtl::OUString* ScDPDimension::GetSubtotalName() const +{ + return mpSubtotalName.get(); +} + +uno::Reference<container::XNameAccess> SAL_CALL ScDPDimension::getHierarchies() + throw(uno::RuntimeException) +{ + return GetHierarchiesObject(); +} + +::rtl::OUString SAL_CALL ScDPDimension::getName() throw(uno::RuntimeException) +{ + if (aName.Len()) + return aName; + else + return pSource->GetData()->getDimensionName( nDim ); +} + +void SAL_CALL ScDPDimension::setName( const ::rtl::OUString& rNewName ) throw(uno::RuntimeException) +{ + // used after cloning + aName = String( rNewName ); +} + +USHORT ScDPDimension::getOrientation() const +{ + return pSource->GetOrientation( nDim ); +} + +void ScDPDimension::setOrientation(USHORT nNew) +{ + pSource->SetOrientation( nDim, nNew ); +} + +long ScDPDimension::getPosition() const +{ + return pSource->GetPosition( nDim ); +} + +void ScDPDimension::setPosition(long /* nNew */) +{ + //! ... +} + +BOOL ScDPDimension::getIsDataLayoutDimension() const +{ + return pSource->GetData()->getIsDataLayoutDimension( nDim ); +} + +USHORT ScDPDimension::getFunction() const +{ + return nFunction; +} + +void ScDPDimension::setFunction(USHORT nNew) +{ + nFunction = nNew; +} + +long ScDPDimension::getUsedHierarchy() const +{ + return nUsedHier; +} + +void ScDPDimension::setUsedHierarchy(long /* nNew */) +{ + // #i52547# don't use the incomplete date hierarchy implementation - ignore the call + // nUsedHier = nNew; +} + +ScDPDimension* ScDPDimension::CreateCloneObject() +{ + DBG_ASSERT( nSourceDim < 0, "recursive duplicate - not implemented" ); + + //! set new name here, or temporary name ??? + String aNewName = aName; + + ScDPDimension* pNew = pSource->AddDuplicated( nDim, aNewName ); + + pNew->aName = aNewName; //! here or in source? + pNew->nSourceDim = nDim; //! recursive? + + return pNew; +} + +uno::Reference<util::XCloneable> SAL_CALL ScDPDimension::createClone() throw(uno::RuntimeException) +{ + return CreateCloneObject(); +} + +BOOL ScDPDimension::isDuplicated() const +{ + return (nSourceDim >= 0); +} + +const sheet::DataPilotFieldReference& ScDPDimension::GetReferenceValue() const +{ + return aReferenceValue; +} + +const ScDPItemData& ScDPDimension::GetSelectedData() +{ + if ( !pSelectedData ) + { + // find the named member to initialize pSelectedData from it, with name and value + + long nLevel = 0; // same as in ScDPObject::FillPageList + + long nHierarchy = getUsedHierarchy(); + if ( nHierarchy >= GetHierarchiesObject()->getCount() ) + nHierarchy = 0; + ScDPLevels* pLevels = GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject(); + long nLevCount = pLevels->getCount(); + if ( nLevel < nLevCount ) + { + ScDPMembers* pMembers = pLevels->getByIndex(nLevel)->GetMembersObject(); + + //! merge with ScDPMembers::getByName + long nCount = pMembers->getCount(); + for (long i=0; i<nCount && !pSelectedData; i++) + { + ScDPMember* pMember = pMembers->getByIndex(i); + if ( pMember->GetNameStr() == aSelectedPage ) + { + pSelectedData = new ScDPItemData(); + pMember->FillItemData( *pSelectedData ); + } + } + } + + if ( !pSelectedData ) + pSelectedData = new ScDPItemData( aSelectedPage, 0.0, FALSE ); // default - name only + } + + return *pSelectedData; +} + +//UNUSED2009-05 BOOL ScDPDimension::IsValidPage( const ScDPItemData& rData ) +//UNUSED2009-05 { +//UNUSED2009-05 if ( bHasSelectedPage ) +//UNUSED2009-05 return rData.IsCaseInsEqual( GetSelectedData() ); +//UNUSED2009-05 +//UNUSED2009-05 return TRUE; // no selection -> all data +//UNUSED2009-05 } + +BOOL ScDPDimension::IsVisible( const ScDPItemData& rData ) +{ + if( ScDPMembers* pMembers = this->GetHierarchiesObject()->getByIndex(0)-> + GetLevelsObject()->getByIndex(0)->GetMembersObject() ) + { + for( long i = pMembers->getCount()-1; i>=0; i-- ) + if( ScDPMember *pDPMbr = pMembers->getByIndex( i ) ) + if( rData.IsCaseInsEqual( pDPMbr->GetItemData() ) && !pDPMbr->getIsVisible() ) + return FALSE; + } + + return TRUE; +} +// XPropertySet + +uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPDimension::getPropertySetInfo() + throw(uno::RuntimeException) +{ + ScUnoGuard aGuard; + + static SfxItemPropertyMapEntry aDPDimensionMap_Impl[] = + { + {MAP_CHAR_LEN(SC_UNO_FILTER), 0, &getCppuType((uno::Sequence<sheet::TableFilterField>*)0), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_FLAGS), 0, &getCppuType((sal_Int32*)0), beans::PropertyAttribute::READONLY, 0 }, + {MAP_CHAR_LEN(SC_UNO_FUNCTION), 0, &getCppuType((sheet::GeneralFunction*)0), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_ISDATALA), 0, &getBooleanCppuType(), beans::PropertyAttribute::READONLY, 0 }, + {MAP_CHAR_LEN(SC_UNO_NUMBERFO), 0, &getCppuType((sal_Int32*)0), beans::PropertyAttribute::READONLY, 0 }, + {MAP_CHAR_LEN(SC_UNO_ORIENTAT), 0, &getCppuType((sheet::DataPilotFieldOrientation*)0), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_ORIGINAL), 0, &getCppuType((uno::Reference<container::XNamed>*)0), beans::PropertyAttribute::READONLY, 0 }, + {MAP_CHAR_LEN(SC_UNO_POSITION), 0, &getCppuType((sal_Int32*)0), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_REFVALUE), 0, &getCppuType((sheet::DataPilotFieldReference*)0), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_USEDHIER), 0, &getCppuType((sal_Int32*)0), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_LAYOUTNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_FIELD_SUBTOTALNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_HAS_HIDDEN_MEMBER), 0, &getBooleanCppuType(), 0, 0 }, + {0,0,0,0,0,0} + }; + static uno::Reference<beans::XPropertySetInfo> aRef = + new SfxItemPropertySetInfo( aDPDimensionMap_Impl ); + return aRef; +} + +void SAL_CALL ScDPDimension::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue ) + throw(beans::UnknownPropertyException, beans::PropertyVetoException, + lang::IllegalArgumentException, lang::WrappedTargetException, + uno::RuntimeException) +{ + String aNameStr = aPropertyName; + if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) ) + { + INT32 nInt = 0; + if (aValue >>= nInt) + setPosition( nInt ); + } + else if ( aNameStr.EqualsAscii( SC_UNO_USEDHIER ) ) + { + INT32 nInt = 0; + if (aValue >>= nInt) + setUsedHierarchy( nInt ); + } + else if ( aNameStr.EqualsAscii( SC_UNO_ORIENTAT ) ) + { + sheet::DataPilotFieldOrientation eEnum; + if (aValue >>= eEnum) + setOrientation( sal::static_int_cast<USHORT>(eEnum) ); + } + else if ( aNameStr.EqualsAscii( SC_UNO_FUNCTION ) ) + { + sheet::GeneralFunction eEnum; + if (aValue >>= eEnum) + setFunction( sal::static_int_cast<USHORT>(eEnum) ); + } + else if ( aNameStr.EqualsAscii( SC_UNO_REFVALUE ) ) + aValue >>= aReferenceValue; + else if ( aNameStr.EqualsAscii( SC_UNO_FILTER ) ) + { + BOOL bDone = FALSE; + uno::Sequence<sheet::TableFilterField> aSeq; + if (aValue >>= aSeq) + { + sal_Int32 nLength = aSeq.getLength(); + if ( nLength == 0 ) + { + aSelectedPage.Erase(); + bHasSelectedPage = FALSE; + bDone = TRUE; + } + else if ( nLength == 1 ) + { + const sheet::TableFilterField& rField = aSeq[0]; + if ( rField.Field == 0 && rField.Operator == sheet::FilterOperator_EQUAL && !rField.IsNumeric ) + { + aSelectedPage = rField.StringValue; + bHasSelectedPage = TRUE; + bDone = TRUE; + } + } + } + if ( !bDone ) + { + DBG_ERROR("Filter property is not a single string"); + throw lang::IllegalArgumentException(); + } + DELETEZ( pSelectedData ); // invalid after changing aSelectedPage + } + else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) + { + OUString aTmpName; + if (aValue >>= aTmpName) + mpLayoutName.reset(new OUString(aTmpName)); + } + else if (aNameStr.EqualsAscii(SC_UNO_FIELD_SUBTOTALNAME)) + { + OUString aTmpName; + if (aValue >>= aTmpName) + mpSubtotalName.reset(new OUString(aTmpName)); + } + else if (aNameStr.EqualsAscii(SC_UNO_HAS_HIDDEN_MEMBER)) + aValue >>= mbHasHiddenMember; + else + { + DBG_ERROR("unknown property"); + //! THROW( UnknownPropertyException() ); + } +} + +uno::Any SAL_CALL ScDPDimension::getPropertyValue( const rtl::OUString& aPropertyName ) + throw(beans::UnknownPropertyException, lang::WrappedTargetException, + uno::RuntimeException) +{ + uno::Any aRet; + String aNameStr = aPropertyName; + if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) ) + aRet <<= (sal_Int32) getPosition(); + else if ( aNameStr.EqualsAscii( SC_UNO_USEDHIER ) ) + aRet <<= (sal_Int32) getUsedHierarchy(); + else if ( aNameStr.EqualsAscii( SC_UNO_ORIENTAT ) ) + { + sheet::DataPilotFieldOrientation eVal = (sheet::DataPilotFieldOrientation)getOrientation(); + aRet <<= eVal; + } + else if ( aNameStr.EqualsAscii( SC_UNO_FUNCTION ) ) + { + sheet::GeneralFunction eVal = (sheet::GeneralFunction)getFunction(); + aRet <<= eVal; + } + else if ( aNameStr.EqualsAscii( SC_UNO_REFVALUE ) ) + aRet <<= aReferenceValue; + else if ( aNameStr.EqualsAscii( SC_UNO_ISDATALA ) ) // read-only properties + lcl_SetBoolInAny( aRet, getIsDataLayoutDimension() ); + else if ( aNameStr.EqualsAscii( SC_UNO_NUMBERFO ) ) + { + sal_Int32 nFormat = 0; + sheet::GeneralFunction eFunc = (sheet::GeneralFunction)getFunction(); + // #i63745# don't use source format for "count" + if ( eFunc != sheet::GeneralFunction_COUNT && eFunc != sheet::GeneralFunction_COUNTNUMS ) + nFormat = pSource->GetData()->GetNumberFormat( ( nSourceDim >= 0 ) ? nSourceDim : nDim ); + + switch ( aReferenceValue.ReferenceType ) + { + case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE: + case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE: + case sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE: + case sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE: + case sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE: + nFormat = pSource->GetData()->GetNumberFormatByIdx( (NfIndexTableOffset)NF_PERCENT_DEC2 ); + break; + case sheet::DataPilotFieldReferenceType::INDEX: + nFormat = pSource->GetData()->GetNumberFormatByIdx( (NfIndexTableOffset)NF_NUMBER_SYSTEM ); + break; + default: + break; + } + + aRet <<= nFormat; + } + else if ( aNameStr.EqualsAscii( SC_UNO_ORIGINAL ) ) + { + uno::Reference<container::XNamed> xOriginal; + if (nSourceDim >= 0) + xOriginal = pSource->GetDimensionsObject()->getByIndex(nSourceDim); + aRet <<= xOriginal; + } + else if ( aNameStr.EqualsAscii( SC_UNO_FILTER ) ) + { + if ( bHasSelectedPage ) + { + // single filter field: first field equal to selected string + sheet::TableFilterField aField( sheet::FilterConnection_AND, 0, + sheet::FilterOperator_EQUAL, sal_False, 0.0, aSelectedPage ); + aRet <<= uno::Sequence<sheet::TableFilterField>( &aField, 1 ); + } + else + aRet <<= uno::Sequence<sheet::TableFilterField>(0); + } + else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) + aRet <<= mpLayoutName.get() ? *mpLayoutName : OUString::createFromAscii(""); + else if (aNameStr.EqualsAscii(SC_UNO_FIELD_SUBTOTALNAME)) + aRet <<= mpSubtotalName.get() ? *mpSubtotalName : OUString::createFromAscii(""); + else if (aNameStr.EqualsAscii(SC_UNO_HAS_HIDDEN_MEMBER)) + aRet <<= mbHasHiddenMember; + else if (aNameStr.EqualsAscii(SC_UNO_FLAGS)) + { + sal_Int32 nFlags = 0; // tabular data: all orientations are possible + aRet <<= nFlags; + } + else + { + DBG_ERROR("unknown property"); + //! THROW( UnknownPropertyException() ); + } + return aRet; +} + +SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPDimension ) + +// ----------------------------------------------------------------------- + +ScDPHierarchies::ScDPHierarchies( ScDPSource* pSrc, long nD ) : + pSource( pSrc ), + nDim( nD ), + ppHiers( NULL ) +{ + //! hold pSource + +#if 0 + // date columns have 3 hierarchies (flat/quarter/week), other columns only one + long nSrcDim = pSource->GetSourceDim( nDim ); + if ( pSource->IsDateDimension( nSrcDim ) ) + nHierCount = SC_DAPI_DATE_HIERARCHIES; + else + nHierCount = 1; +#endif + + // #i52547# don't offer the incomplete date hierarchy implementation + nHierCount = 1; +} + +ScDPHierarchies::~ScDPHierarchies() +{ + //! release pSource + + if (ppHiers) + { + for (long i=0; i<nHierCount; i++) + if ( ppHiers[i] ) + ppHiers[i]->release(); // ref-counted + delete[] ppHiers; + } +} + +// very simple XNameAccess implementation using getCount/getByIndex + +uno::Any SAL_CALL ScDPHierarchies::getByName( const rtl::OUString& aName ) + throw(container::NoSuchElementException, + lang::WrappedTargetException, uno::RuntimeException) +{ + long nCount = getCount(); + for (long i=0; i<nCount; i++) + if ( getByIndex(i)->getName() == aName ) + { + uno::Reference<container::XNamed> xNamed = getByIndex(i); + uno::Any aRet; + aRet <<= xNamed; + return aRet; + } + + throw container::NoSuchElementException(); +// return uno::Any(); +} + +uno::Sequence<rtl::OUString> SAL_CALL ScDPHierarchies::getElementNames() throw(uno::RuntimeException) +{ + long nCount = getCount(); + uno::Sequence<rtl::OUString> aSeq(nCount); + rtl::OUString* pArr = aSeq.getArray(); + for (long i=0; i<nCount; i++) + pArr[i] = getByIndex(i)->getName(); + return aSeq; +} + +sal_Bool SAL_CALL ScDPHierarchies::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException) +{ + long nCount = getCount(); + for (long i=0; i<nCount; i++) + if ( getByIndex(i)->getName() == aName ) + return TRUE; + return FALSE; +} + +uno::Type SAL_CALL ScDPHierarchies::getElementType() throw(uno::RuntimeException) +{ + return getCppuType((uno::Reference<container::XNamed>*)0); +} + +sal_Bool SAL_CALL ScDPHierarchies::hasElements() throw(uno::RuntimeException) +{ + return ( getCount() > 0 ); +} + +// end of XNameAccess implementation + +long ScDPHierarchies::getCount() const +{ + return nHierCount; +} + +ScDPHierarchy* ScDPHierarchies::getByIndex(long nIndex) const +{ + // pass hierarchy index to new object in case the implementation + // will be extended to more than one hierarchy + + if ( nIndex >= 0 && nIndex < nHierCount ) + { + if ( !ppHiers ) + { + ((ScDPHierarchies*)this)->ppHiers = new ScDPHierarchy*[nHierCount]; + for (long i=0; i<nHierCount; i++) + ppHiers[i] = NULL; + } + if ( !ppHiers[nIndex] ) + { + ppHiers[nIndex] = new ScDPHierarchy( pSource, nDim, nIndex ); + ppHiers[nIndex]->acquire(); // ref-counted + } + + return ppHiers[nIndex]; + } + + return NULL; //! exception? +} + +// ----------------------------------------------------------------------- + +ScDPHierarchy::ScDPHierarchy( ScDPSource* pSrc, long nD, long nH ) : + pSource( pSrc ), + nDim( nD ), + nHier( nH ), + pLevels( NULL ) +{ + //! hold pSource +} + +ScDPHierarchy::~ScDPHierarchy() +{ + //! release pSource + + if (pLevels) + pLevels->release(); // ref-counted +} + +ScDPLevels* ScDPHierarchy::GetLevelsObject() +{ + if (!pLevels) + { + pLevels = new ScDPLevels( pSource, nDim, nHier ); + pLevels->acquire(); // ref-counted + } + return pLevels; +} + +uno::Reference<container::XNameAccess> SAL_CALL ScDPHierarchy::getLevels() + throw(uno::RuntimeException) +{ + return GetLevelsObject(); +} + +::rtl::OUString SAL_CALL ScDPHierarchy::getName() throw(uno::RuntimeException) +{ + String aRet; //! globstr-ID !!!! + switch (nHier) + { + case SC_DAPI_HIERARCHY_FLAT: + aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("flat")); + break; //! name ??????? + case SC_DAPI_HIERARCHY_QUARTER: + aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Quarter")); + break; //! name ??????? + case SC_DAPI_HIERARCHY_WEEK: + aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Week")); + break; //! name ??????? + default: + DBG_ERROR( "ScDPHierarchy::getName: unexpected hierarchy" ); + break; + } + return aRet; +} + +void SAL_CALL ScDPHierarchy::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException) +{ + DBG_ERROR("not implemented"); //! exception? +} + +// ----------------------------------------------------------------------- + +ScDPLevels::ScDPLevels( ScDPSource* pSrc, long nD, long nH ) : + pSource( pSrc ), + nDim( nD ), + nHier( nH ), + ppLevs( NULL ) +{ + //! hold pSource + + // text columns have only one level + + long nSrcDim = pSource->GetSourceDim( nDim ); + if ( pSource->IsDateDimension( nSrcDim ) ) + { + switch ( nHier ) + { + case SC_DAPI_HIERARCHY_FLAT: nLevCount = SC_DAPI_FLAT_LEVELS; break; + case SC_DAPI_HIERARCHY_QUARTER: nLevCount = SC_DAPI_QUARTER_LEVELS; break; + case SC_DAPI_HIERARCHY_WEEK: nLevCount = SC_DAPI_WEEK_LEVELS; break; + default: + DBG_ERROR("wrong hierarchy"); + nLevCount = 0; + } + } + else + nLevCount = 1; +} + +ScDPLevels::~ScDPLevels() +{ + //! release pSource + + if (ppLevs) + { + for (long i=0; i<nLevCount; i++) + if ( ppLevs[i] ) + ppLevs[i]->release(); // ref-counted + delete[] ppLevs; + } +} + +// very simple XNameAccess implementation using getCount/getByIndex + +uno::Any SAL_CALL ScDPLevels::getByName( const rtl::OUString& aName ) + throw(container::NoSuchElementException, + lang::WrappedTargetException, uno::RuntimeException) +{ + long nCount = getCount(); + for (long i=0; i<nCount; i++) + if ( getByIndex(i)->getName() == aName ) + { + uno::Reference<container::XNamed> xNamed = getByIndex(i); + uno::Any aRet; + aRet <<= xNamed; + return aRet; + } + + throw container::NoSuchElementException(); +// return uno::Any(); +} + +uno::Sequence<rtl::OUString> SAL_CALL ScDPLevels::getElementNames() throw(uno::RuntimeException) +{ + long nCount = getCount(); + uno::Sequence<rtl::OUString> aSeq(nCount); + rtl::OUString* pArr = aSeq.getArray(); + for (long i=0; i<nCount; i++) + pArr[i] = getByIndex(i)->getName(); + return aSeq; +} + +sal_Bool SAL_CALL ScDPLevels::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException) +{ + long nCount = getCount(); + for (long i=0; i<nCount; i++) + if ( getByIndex(i)->getName() == aName ) + return TRUE; + return FALSE; +} + +uno::Type SAL_CALL ScDPLevels::getElementType() throw(uno::RuntimeException) +{ + return getCppuType((uno::Reference<container::XNamed>*)0); +} + +sal_Bool SAL_CALL ScDPLevels::hasElements() throw(uno::RuntimeException) +{ + return ( getCount() > 0 ); +} + +// end of XNameAccess implementation + +long ScDPLevels::getCount() const +{ + return nLevCount; +} + +ScDPLevel* ScDPLevels::getByIndex(long nIndex) const +{ + if ( nIndex >= 0 && nIndex < nLevCount ) + { + if ( !ppLevs ) + { + ((ScDPLevels*)this)->ppLevs = new ScDPLevel*[nLevCount]; + for (long i=0; i<nLevCount; i++) + ppLevs[i] = NULL; + } + if ( !ppLevs[nIndex] ) + { + ppLevs[nIndex] = new ScDPLevel( pSource, nDim, nHier, nIndex ); + ppLevs[nIndex]->acquire(); // ref-counted + } + + return ppLevs[nIndex]; + } + + return NULL; //! exception? +} + +// ----------------------------------------------------------------------- + +class ScDPGlobalMembersOrder +{ + ScDPLevel& rLevel; + BOOL bAscending; + +public: + ScDPGlobalMembersOrder( ScDPLevel& rLev, BOOL bAsc ) : + rLevel(rLev), + bAscending(bAsc) + {} + ~ScDPGlobalMembersOrder() {} + + BOOL operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const; +}; + +BOOL ScDPGlobalMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const +{ + sal_Int32 nCompare = 0; + // seems that some ::std::sort() implementations pass the same index twice + if( nIndex1 != nIndex2 ) + { + ScDPMembers* pMembers = rLevel.GetMembersObject(); + ScDPMember* pMember1 = pMembers->getByIndex(nIndex1); + ScDPMember* pMember2 = pMembers->getByIndex(nIndex2); + nCompare = pMember1->Compare( *pMember2 ); + } + return bAscending ? (nCompare < 0) : (nCompare > 0); +} + +// ----------------------------------------------------------------------- + +ScDPLevel::ScDPLevel( ScDPSource* pSrc, long nD, long nH, long nL ) : + pSource( pSrc ), + nDim( nD ), + nHier( nH ), + nLev( nL ), + pMembers( NULL ), + bShowEmpty( FALSE ), + aSortInfo( EMPTY_STRING, sal_True, sheet::DataPilotFieldSortMode::NAME ), // default: sort by name + nSortMeasure( 0 ), + nAutoMeasure( 0 ), + bEnableLayout( FALSE ) +{ + //! hold pSource + // aSubTotals is empty +} + +ScDPLevel::~ScDPLevel() +{ + //! release pSource + + if ( pMembers ) + pMembers->release(); // ref-counted +} + +void ScDPLevel::EvaluateSortOrder() +{ + switch (aSortInfo.Mode) + { + case sheet::DataPilotFieldSortMode::DATA: + { + // find index of measure (index among data dimensions) + + String aDataFieldName = aSortInfo.Field; + long nMeasureCount = pSource->GetDataDimensionCount(); + for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++) + { + if ( pSource->GetDataDimName(nMeasure) == aDataFieldName ) + { + nSortMeasure = nMeasure; + break; + } + } + + //! error if not found? + } + break; + case sheet::DataPilotFieldSortMode::MANUAL: + case sheet::DataPilotFieldSortMode::NAME: + { + ScDPMembers* pLocalMembers = GetMembersObject(); + long nCount = pLocalMembers->getCount(); + +// DBG_ASSERT( aGlobalOrder.empty(), "sort twice?" ); + aGlobalOrder.resize( nCount ); + for (long nPos=0; nPos<nCount; nPos++) + aGlobalOrder[nPos] = nPos; + + // allow manual or name (manual is always ascending) + BOOL bAscending = ( aSortInfo.Mode == sheet::DataPilotFieldSortMode::MANUAL || aSortInfo.IsAscending ); + ScDPGlobalMembersOrder aComp( *this, bAscending ); + ::std::sort( aGlobalOrder.begin(), aGlobalOrder.end(), aComp ); + } + break; + } + + if ( aAutoShowInfo.IsEnabled ) + { + // find index of measure (index among data dimensions) + + String aDataFieldName = aAutoShowInfo.DataField; + long nMeasureCount = pSource->GetDataDimensionCount(); + for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++) + { + if ( pSource->GetDataDimName(nMeasure) == aDataFieldName ) + { + nAutoMeasure = nMeasure; + break; + } + } + + //! error if not found? + } +} + +void ScDPLevel::SetEnableLayout( BOOL bSet ) +{ + bEnableLayout = bSet; +} + +ScDPMembers* ScDPLevel::GetMembersObject() +{ + if (!pMembers) + { + pMembers = new ScDPMembers( pSource, nDim, nHier, nLev ); + pMembers->acquire(); // ref-counted + } + return pMembers; +} + +uno::Reference<container::XNameAccess> SAL_CALL ScDPLevel::getMembers() throw(uno::RuntimeException) +{ + return GetMembersObject(); +} + +uno::Sequence<sheet::MemberResult> SAL_CALL ScDPLevel::getResults() throw(uno::RuntimeException) +{ + const uno::Sequence<sheet::MemberResult>* pRes = pSource->GetMemberResults( this ); + if (pRes) + return *pRes; + + return uno::Sequence<sheet::MemberResult>(0); //! Error? +} + +::rtl::OUString SAL_CALL ScDPLevel::getName() throw(uno::RuntimeException) +{ + long nSrcDim = pSource->GetSourceDim( nDim ); + if ( pSource->IsDateDimension( nSrcDim ) ) + { + String aRet; //! globstr-ID !!!! + + if ( nHier == SC_DAPI_HIERARCHY_QUARTER ) + { + switch ( nLev ) + { + case SC_DAPI_LEVEL_YEAR: + aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Year")); + break; + case SC_DAPI_LEVEL_QUARTER: + aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Quarter")); + break; + case SC_DAPI_LEVEL_MONTH: + aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Month")); + break; + case SC_DAPI_LEVEL_DAY: + aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Day")); + break; + default: + DBG_ERROR( "ScDPLevel::getName: unexpected level" ); + break; + } + } + else if ( nHier == SC_DAPI_HIERARCHY_WEEK ) + { + switch ( nLev ) + { + case SC_DAPI_LEVEL_YEAR: + aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Year")); + break; + case SC_DAPI_LEVEL_WEEK: + aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Week")); + break; + case SC_DAPI_LEVEL_WEEKDAY: + aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Weekday")); + break; + default: + DBG_ERROR( "ScDPLevel::getName: unexpected level" ); + break; + } + } + if (aRet.Len()) + return aRet; + } + + ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim); + if (!pDim) + return rtl::OUString(); + + return pDim->getName(); +} + +void SAL_CALL ScDPLevel::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException) +{ + DBG_ERROR("not implemented"); //! exception? +} + +uno::Sequence<sheet::GeneralFunction> ScDPLevel::getSubTotals() const +{ + //! separate functions for settings and evaluation? + + long nSrcDim = pSource->GetSourceDim( nDim ); + if ( !pSource->SubTotalAllowed( nSrcDim ) ) + return uno::Sequence<sheet::GeneralFunction>(0); + + return aSubTotals; +} + +void ScDPLevel::setSubTotals(const uno::Sequence<sheet::GeneralFunction>& rNew) +{ + aSubTotals = rNew; + //! set "manual change" flag? +} + +BOOL ScDPLevel::getShowEmpty() const +{ + return bShowEmpty; +} + +void ScDPLevel::setShowEmpty(BOOL bSet) +{ + bShowEmpty = bSet; +} + +// XPropertySet + +uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPLevel::getPropertySetInfo() + throw(uno::RuntimeException) +{ + ScUnoGuard aGuard; + + static SfxItemPropertyMapEntry aDPLevelMap_Impl[] = + { + //! change type of AutoShow/Layout/Sorting to API struct when available + {MAP_CHAR_LEN(SC_UNO_AUTOSHOW), 0, &getCppuType((sheet::DataPilotFieldAutoShowInfo*)0), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_LAYOUT), 0, &getCppuType((sheet::DataPilotFieldLayoutInfo*)0), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_SHOWEMPT), 0, &getBooleanCppuType(), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_SORTING), 0, &getCppuType((sheet::DataPilotFieldSortInfo*)0), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_SUBTOTAL), 0, &getCppuType((uno::Sequence<sheet::GeneralFunction>*)0), 0, 0 }, + {0,0,0,0,0,0} + }; + static uno::Reference<beans::XPropertySetInfo> aRef = + new SfxItemPropertySetInfo( aDPLevelMap_Impl ); + return aRef; +} + +void SAL_CALL ScDPLevel::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue ) + throw(beans::UnknownPropertyException, beans::PropertyVetoException, + lang::IllegalArgumentException, lang::WrappedTargetException, + uno::RuntimeException) +{ + String aNameStr = aPropertyName; + if ( aNameStr.EqualsAscii( SC_UNO_SHOWEMPT ) ) + setShowEmpty( lcl_GetBoolFromAny( aValue ) ); + else if ( aNameStr.EqualsAscii( SC_UNO_SUBTOTAL ) ) + { + uno::Sequence<sheet::GeneralFunction> aSeq; + if ( aValue >>= aSeq ) + setSubTotals( aSeq ); + } + else if ( aNameStr.EqualsAscii( SC_UNO_SORTING ) ) + aValue >>= aSortInfo; + else if ( aNameStr.EqualsAscii( SC_UNO_AUTOSHOW ) ) + aValue >>= aAutoShowInfo; + else if ( aNameStr.EqualsAscii( SC_UNO_LAYOUT ) ) + aValue >>= aLayoutInfo; + else + { + DBG_ERROR("unknown property"); + //! THROW( UnknownPropertyException() ); + } +} + +uno::Any SAL_CALL ScDPLevel::getPropertyValue( const rtl::OUString& aPropertyName ) + throw(beans::UnknownPropertyException, lang::WrappedTargetException, + uno::RuntimeException) +{ + uno::Any aRet; + String aNameStr = aPropertyName; + if ( aNameStr.EqualsAscii( SC_UNO_SHOWEMPT ) ) + lcl_SetBoolInAny( aRet, getShowEmpty() ); + else if ( aNameStr.EqualsAscii( SC_UNO_SUBTOTAL ) ) + { + uno::Sequence<sheet::GeneralFunction> aSeq = getSubTotals(); //! avoid extra copy? + aRet <<= aSeq; + } + else if ( aNameStr.EqualsAscii( SC_UNO_SORTING ) ) + aRet <<= aSortInfo; + else if ( aNameStr.EqualsAscii( SC_UNO_AUTOSHOW ) ) + aRet <<= aAutoShowInfo; + else if ( aNameStr.EqualsAscii( SC_UNO_LAYOUT ) ) + aRet <<= aLayoutInfo; + else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) + { + // read only property + long nSrcDim = pSource->GetSourceDim(nDim); + ScDPDimension* pDim = pSource->GetDimensionsObject()->getByIndex(nSrcDim); + if (!pDim) + return aRet; + + const OUString* pLayoutName = pDim->GetLayoutName(); + if (!pLayoutName) + return aRet; + + aRet <<= *pLayoutName; + } + else + { + DBG_ERROR("unknown property"); + //! THROW( UnknownPropertyException() ); + } + return aRet; +} + +SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPLevel ) + +// ----------------------------------------------------------------------- + +ScDPMembers::ScDPMembers( ScDPSource* pSrc, long nD, long nH, long nL ) : + pSource( pSrc ), + nDim( nD ), + nHier( nH ), + nLev( nL ), + ppMbrs( NULL ) +{ + //! hold pSource + + long nSrcDim = pSource->GetSourceDim( nDim ); + if ( pSource->IsDataLayoutDimension(nSrcDim) ) + nMbrCount = pSource->GetDataDimensionCount(); + else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) ) + { + nMbrCount = 0; + if ( nHier == SC_DAPI_HIERARCHY_QUARTER ) + { + switch (nLev) + { + case SC_DAPI_LEVEL_YEAR: + { + // Wang Xu Ming - DataPilot migration + const ScDPItemData* pLastNumData = NULL; + for ( SCROW n = 0 ;n <GetSrcItemsCount() ; n-- ) + { + const ScDPItemData* pData = GetSrcItemDataByIndex( n ); + if ( pData && pData->HasStringData() ) + break; + else + pLastNumData = pData; + } + // End Comments + + if ( pLastNumData ) + { + const ScDPItemData* pFirstData = GetSrcItemDataByIndex( 0 ); + double fFirstVal = pFirstData->GetValue(); + double fLastVal = pLastNumData->GetValue(); + + long nFirstYear = pSource->GetData()->GetDatePart( + (long)::rtl::math::approxFloor( fFirstVal ), + nHier, nLev ); + long nLastYear = pSource->GetData()->GetDatePart( + (long)::rtl::math::approxFloor( fLastVal ), + nHier, nLev ); + + nMbrCount = nLastYear + 1 - nFirstYear; + } + else + nMbrCount = 0; // no values + } + break; + case SC_DAPI_LEVEL_QUARTER: nMbrCount = 4; break; + case SC_DAPI_LEVEL_MONTH: nMbrCount = 12; break; + case SC_DAPI_LEVEL_DAY: nMbrCount = 31; break; + default: + DBG_ERROR( "ScDPMembers::ScDPMembers: unexpected level" ); + break; + } + } + else if ( nHier == SC_DAPI_HIERARCHY_WEEK ) + { + switch (nLev) + { + case SC_DAPI_LEVEL_YEAR: nMbrCount = 1; break; //! get years from source + case SC_DAPI_LEVEL_WEEK: nMbrCount = 53; break; + case SC_DAPI_LEVEL_WEEKDAY: nMbrCount = 7; break; + default: + DBG_ERROR( "ScDPMembers::ScDPMembers: unexpected level" ); + break; + } + } + } + else + nMbrCount = pSource->GetData()->GetMembersCount( nSrcDim ); +} + +ScDPMembers::~ScDPMembers() +{ + //! release pSource + + if (ppMbrs) + { + for (long i=0; i<nMbrCount; i++) + if ( ppMbrs[i] ) + ppMbrs[i]->release(); // ref-counted + delete[] ppMbrs; + } +} + +// XNameAccess implementation using getCount/getByIndex + +sal_Int32 ScDPMembers::GetIndexFromName( const ::rtl::OUString& rName ) const +{ + if ( aHashMap.empty() ) + { + // store the index for each name + + sal_Int32 nCount = getCount(); + for (sal_Int32 i=0; i<nCount; i++) + aHashMap[ getByIndex(i)->getName() ] = i; + } + + ScDPMembersHashMap::const_iterator aIter = aHashMap.find( rName ); + if ( aIter != aHashMap.end() ) + return aIter->second; // found index + else + return -1; // not found +} + +uno::Any SAL_CALL ScDPMembers::getByName( const rtl::OUString& aName ) + throw(container::NoSuchElementException, + lang::WrappedTargetException, uno::RuntimeException) +{ + sal_Int32 nIndex = GetIndexFromName( aName ); + if ( nIndex >= 0 ) + { + uno::Reference<container::XNamed> xNamed = getByIndex(nIndex); + uno::Any aRet; + aRet <<= xNamed; + return aRet; + } + + throw container::NoSuchElementException(); +// return uno::Any(); +} + +uno::Sequence<rtl::OUString> SAL_CALL ScDPMembers::getElementNames() throw(uno::RuntimeException) +{ + // Return list of names in sorted order, + // so it's displayed in that order in the field options dialog. + // Sorting is done at the level object (parent of this). + + ScDPLevel* pLevel = pSource->GetDimensionsObject()->getByIndex(nDim)-> + GetHierarchiesObject()->getByIndex(nHier)->GetLevelsObject()->getByIndex(nLev); + pLevel->EvaluateSortOrder(); + const std::vector<sal_Int32>& rGlobalOrder = pLevel->GetGlobalOrder(); + bool bSort = !rGlobalOrder.empty(); + + long nCount = getCount(); + uno::Sequence<rtl::OUString> aSeq(nCount); + rtl::OUString* pArr = aSeq.getArray(); + for (long i=0; i<nCount; i++) + pArr[i] = getByIndex(bSort ? rGlobalOrder[i] : i)->getName(); + return aSeq; +} + +sal_Bool SAL_CALL ScDPMembers::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException) +{ + return ( GetIndexFromName( aName ) >= 0 ); +} + +uno::Type SAL_CALL ScDPMembers::getElementType() throw(uno::RuntimeException) +{ + return getCppuType((uno::Reference<container::XNamed>*)0); +} + +sal_Bool SAL_CALL ScDPMembers::hasElements() throw(uno::RuntimeException) +{ + return ( getCount() > 0 ); +} + +// end of XNameAccess implementation + +long ScDPMembers::getCount() const +{ + return nMbrCount; +} + +long ScDPMembers::getMinMembers() const +{ + // used in lcl_CountMinMembers + + long nVisCount = 0; + if ( ppMbrs ) + { + for (long i=0; i<nMbrCount; i++) + { + // count only visible with details (default is true for both) + const ScDPMember* pMbr = ppMbrs[i]; + if ( !pMbr || ( pMbr->getIsVisible() && pMbr->getShowDetails() ) ) + ++nVisCount; + } + } + else + nVisCount = nMbrCount; // default for all + + return nVisCount; +} + +ScDPMember* ScDPMembers::getByIndex(long nIndex) const +{ + // result of GetColumnEntries must not change between ScDPMembers ctor + // and all calls to getByIndex + + if ( nIndex >= 0 && nIndex < nMbrCount ) + { + if ( !ppMbrs ) + { + ((ScDPMembers*)this)->ppMbrs = new ScDPMember*[nMbrCount]; + for (long i=0; i<nMbrCount; i++) + ppMbrs[i] = NULL; + } + if ( !ppMbrs[nIndex] ) + { + ScDPMember* pNew; + long nSrcDim = pSource->GetSourceDim( nDim ); + if ( pSource->IsDataLayoutDimension(nSrcDim) ) + { + // empty name (never shown, not used for lookup) + pNew = new ScDPMember( pSource, nDim, nHier, nLev, 0 ); + } + else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) ) + { + long nVal = 0; + String aName; + + if ( nLev == SC_DAPI_LEVEL_YEAR ) // YEAR is in both hierarchies + { + //! cache year range here! + + // Wang Xu Ming - DataPilot migration + double fFirstVal = pSource->GetData()->GetMemberByIndex( nSrcDim, 0 )->GetValue(); + long nFirstYear = pSource->GetData()->GetDatePart( + (long)::rtl::math::approxFloor( fFirstVal ), + nHier, nLev ); + + // End Comments + nVal = nFirstYear + nIndex; + } + else if ( nHier == SC_DAPI_HIERARCHY_WEEK && nLev == SC_DAPI_LEVEL_WEEKDAY ) + { + nVal = nIndex; // DayOfWeek is 0-based + aName = ScGlobal::GetCalendar()->getDisplayName( + ::com::sun::star::i18n::CalendarDisplayIndex::DAY, + sal::static_int_cast<sal_Int16>(nVal), 0 ); + } + else if ( nHier == SC_DAPI_HIERARCHY_QUARTER && nLev == SC_DAPI_LEVEL_MONTH ) + { + nVal = nIndex; // Month is 0-based + aName = ScGlobal::GetCalendar()->getDisplayName( + ::com::sun::star::i18n::CalendarDisplayIndex::MONTH, + sal::static_int_cast<sal_Int16>(nVal), 0 ); + } + else + nVal = nIndex + 1; // Quarter, Day, Week are 1-based + + if ( !aName.Len() ) + aName = String::CreateFromInt32(nVal); + + ScDPItemData rData( aName, nVal, TRUE, 0 ) ; + pNew = new ScDPMember( pSource, nDim, nHier, nLev, pSource->GetCache()->GetAdditionalItemID(rData)); + } + else + { + const std::vector< SCROW >& memberIndexs = pSource->GetData()->GetColumnEntries( nSrcDim ); + pNew = new ScDPMember( pSource, nDim, nHier, nLev, memberIndexs[nIndex] ); + } + pNew->acquire(); // ref-counted + ppMbrs[nIndex] = pNew; + } + + DBG_ASSERT( ppMbrs[nIndex] ," member is not initialized " ); + + return ppMbrs[nIndex]; + } + + return NULL; //! exception? +} + +// ----------------------------------------------------------------------- + +ScDPMember::ScDPMember( ScDPSource* pSrc, long nD, long nH, long nL, + SCROW nIndex /*const String& rN, double fV, BOOL bHV*/ ) : + pSource( pSrc ), + nDim( nD ), + nHier( nH ), + nLev( nL ), + mnDataId( nIndex ), + mpLayoutName(NULL), + nPosition( -1 ), + bVisible( TRUE ), + bShowDet( TRUE ) +{ + //! hold pSource +} + +ScDPMember::~ScDPMember() +{ + //! release pSource +} + +BOOL ScDPMember::IsNamedItem( const ScDPItemData& r ) const +{ + long nSrcDim = pSource->GetSourceDim( nDim ); + if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) && r.IsValue() ) + { + long nComp = pSource->GetData()->GetDatePart( + (long)::rtl::math::approxFloor( r.GetValue() ), + nHier, nLev ); + + // fValue is converted from integer, so simple comparison works + return nComp == GetItemData().GetValue(); + } + + return r.IsCaseInsEqual( GetItemData() ); +} + +BOOL ScDPMember::IsNamedItem( SCROW nIndex ) const +{ + long nSrcDim = pSource->GetSourceDim( nDim ); + if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) ) + { + const ScDPItemData* pData = pSource->GetCache()->GetItemDataById( (SCCOL) nSrcDim, nIndex ); + if ( pData->IsValue() ) + { + long nComp = pSource->GetData()->GetDatePart( + (long)::rtl::math::approxFloor( pData->GetValue() ), + nHier, nLev ); + // fValue is converted from integer, so simple comparison works + return nComp == GetItemData().GetValue(); + } + } + + return nIndex == mnDataId; +} + +sal_Int32 ScDPMember::Compare( const ScDPMember& rOther ) const +{ + if ( nPosition >= 0 ) + { + if ( rOther.nPosition >= 0 ) + { + DBG_ASSERT( nPosition != rOther.nPosition, "same position for two members" ); + return ( nPosition < rOther.nPosition ) ? -1 : 1; + } + else + { + // only this has a position - members with specified positions come before those without + return -1; + } + } + else if ( rOther.nPosition >= 0 ) + { + // only rOther has a position + return 1; + } + + // no positions set - compare names + return pSource->GetData()->Compare( pSource->GetSourceDim(nDim),mnDataId,rOther.GetItemDataId()); +} + +void ScDPMember::FillItemData( ScDPItemData& rData ) const +{ + //! handle date hierarchy... + + rData = GetItemData() ; +} + +const OUString* ScDPMember::GetLayoutName() const +{ + return mpLayoutName.get(); +} + +String ScDPMember::GetNameStr() const +{ + return GetItemData().GetString(); +} + +::rtl::OUString SAL_CALL ScDPMember::getName() throw(uno::RuntimeException) +{ + return GetItemData().GetString(); +} + +void SAL_CALL ScDPMember::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException) +{ + DBG_ERROR("not implemented"); //! exception? +} + +BOOL ScDPMember::getIsVisible() const +{ + return bVisible; +} + +void ScDPMember::setIsVisible(BOOL bSet) +{ + bVisible = bSet; + //! set "manual change" flag +} + +BOOL ScDPMember::getShowDetails() const +{ + return bShowDet; +} + +void ScDPMember::setShowDetails(BOOL bSet) +{ + bShowDet = bSet; + //! set "manual change" flag +} + +sal_Int32 ScDPMember::getPosition() const +{ + return nPosition; +} + +void ScDPMember::setPosition(sal_Int32 nNew) +{ + nPosition = nNew; +} + +// XPropertySet + +uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPMember::getPropertySetInfo() + throw(uno::RuntimeException) +{ + ScUnoGuard aGuard; + + static SfxItemPropertyMapEntry aDPMemberMap_Impl[] = + { + {MAP_CHAR_LEN(SC_UNO_ISVISIBL), 0, &getBooleanCppuType(), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_POSITION), 0, &getCppuType((sal_Int32*)0), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_SHOWDETA), 0, &getBooleanCppuType(), 0, 0 }, + {MAP_CHAR_LEN(SC_UNO_LAYOUTNAME), 0, &getCppuType(static_cast<rtl::OUString*>(0)), 0, 0 }, + {0,0,0,0,0,0} + }; + static uno::Reference<beans::XPropertySetInfo> aRef = + new SfxItemPropertySetInfo( aDPMemberMap_Impl ); + return aRef; +} + +void SAL_CALL ScDPMember::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue ) + throw(beans::UnknownPropertyException, beans::PropertyVetoException, + lang::IllegalArgumentException, lang::WrappedTargetException, + uno::RuntimeException) +{ + String aNameStr = aPropertyName; + if ( aNameStr.EqualsAscii( SC_UNO_ISVISIBL ) ) + setIsVisible( lcl_GetBoolFromAny( aValue ) ); + else if ( aNameStr.EqualsAscii( SC_UNO_SHOWDETA ) ) + setShowDetails( lcl_GetBoolFromAny( aValue ) ); + else if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) ) + { + sal_Int32 nInt = 0; + if (aValue >>= nInt) + setPosition( nInt ); + } + else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) + { + rtl::OUString aName; + if (aValue >>= aName) + mpLayoutName.reset(new rtl::OUString(aName)); + } + else + { + DBG_ERROR("unknown property"); + //! THROW( UnknownPropertyException() ); + } +} + +uno::Any SAL_CALL ScDPMember::getPropertyValue( const rtl::OUString& aPropertyName ) + throw(beans::UnknownPropertyException, lang::WrappedTargetException, + uno::RuntimeException) +{ + uno::Any aRet; + String aNameStr = aPropertyName; + if ( aNameStr.EqualsAscii( SC_UNO_ISVISIBL ) ) + lcl_SetBoolInAny( aRet, getIsVisible() ); + else if ( aNameStr.EqualsAscii( SC_UNO_SHOWDETA ) ) + lcl_SetBoolInAny( aRet, getShowDetails() ); + else if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) ) + aRet <<= (sal_Int32) getPosition(); + else if (aNameStr.EqualsAscii(SC_UNO_LAYOUTNAME)) + aRet <<= mpLayoutName.get() ? *mpLayoutName : rtl::OUString(); + else + { + DBG_ERROR("unknown property"); + //! THROW( UnknownPropertyException() ); + } + return aRet; +} + +SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPMember ) + + +ScDPTableDataCache* ScDPSource::GetCache() +{ + DBG_ASSERT( GetData() , "empty ScDPTableData pointer"); + return ( GetData()!=NULL) ? GetData()->GetCacheTable().GetCache() : NULL ; +} + +const ScDPItemData& ScDPMember::GetItemData() const +{ + return *pSource->GetItemDataById( (SCCOL)nDim, mnDataId );//ms-cache-core +} + +const ScDPItemData* ScDPSource::GetItemDataById(long nDim, long nId) +{ + long nSrcDim = GetSourceDim( nDim ); + const ScDPItemData* pItemData = GetData()->GetMemberById( nSrcDim, nId ); + if ( !pItemData ) + { //todo: + ScDPItemData item; + nId = GetCache()->GetAdditionalItemID( item ); + pItemData = GetData()->GetMemberById( nSrcDim, nId ); + } + return pItemData; +} + +SCROW ScDPSource::GetMemberId( long nDim, const ScDPItemData& rData ) +{ + long nSrcDim = GetSourceDim( nDim ); + return GetCache()->GetIdByItemData( nSrcDim, rData ); +} + +const ScDPItemData* ScDPMembers::GetSrcItemDataByIndex( SCROW nIndex) +{ + const std::vector< SCROW >& memberIds = pSource->GetData()->GetColumnEntries( nDim ); + if ( nIndex >= (long )(memberIds.size()) || nIndex < 0 ) + return NULL; + SCROW nId = memberIds[ nIndex ]; + return pSource->GetItemDataById( nDim, nId ); +} + + SCROW ScDPMembers::GetSrcItemsCount() + { + return pSource->GetData()->GetColumnEntries( nDim ).size(); + } +// End Comments + |