/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" // INCLUDE --------------------------------------------------------------- #include #include #include #include #include #include #include #include #include #include #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 "miscuno.hxx" #include "unonames.hxx" #include #include #include #include #include #include #include #include #include #include #include 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= 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; iIsDataLayoutDimension(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; iGetColumnCount(); } 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 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; igetByIndex(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 > 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 > aSeq( nRowCount ); uno::Sequence* pRowAry = aSeq.getArray(); for (long nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence 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& ) throw(uno::RuntimeException) { DBG_ERROR("not implemented"); //! exception? } void SAL_CALL ScDPSource::removeRefreshListener( const uno::Reference& ) throw(uno::RuntimeException) { DBG_ERROR("not implemented"); //! exception? } Sequence< Sequence > SAL_CALL ScDPSource::getDrillDownData(const Sequence& aFilters) throw (uno::RuntimeException) { long nColumnCount = GetData()->GetColumnCount(); typedef hash_map 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 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 > aTabData; hash_set 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& ppDim, const vector& 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& rElements ) { long nCount = rElements.getLength(); const rtl::OUString* pArray = rElements.getConstArray(); for (long nPos=0; nPosgetByIndex( 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& rCatDims) { hash_set aCatDims; for (long i = 0; i < nColDimCount; ++i) { sal_Int32 nDim = static_cast(nColDims[i]); if (!IsDataLayoutDimension(nDim)) aCatDims.insert(nDim); } for (long i = 0; i < nRowDimCount; ++i) { sal_Int32 nDim = static_cast(nRowDims[i]); if (!IsDataLayoutDimension(nDim)) aCatDims.insert(nDim); } for (long i = 0; i < nPageDimCount; ++i) { sal_Int32 nDim = static_cast(nPageDims[i]); if (!IsDataLayoutDimension(nDim)) aCatDims.insert(nDim); } rCatDims.swap(aCatDims); } void ScDPSource::FilterCacheTableByPageDimensions() { // filter table by page dimensions. vector 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(nField); aFilter.mpFilter.reset(new ScDPCacheTable::GroupFilter(/*rSharedString*/)); ScDPCacheTable::GroupFilter* pGrpFilter = static_cast(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(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(nField); r.mpFilter.reset( new ScDPCacheTable::SingleFilter(rData.GetString()/*rSharedString, nStrId*/, rData.GetValue(), rData.IsValue())); } if (!aCriteria.empty()) { hash_set 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; igetByIndex(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; igetByIndex( 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; igetByIndex( 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; jgetByIndex(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 ); // ---------------------------------------------------------------- } } } 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; nDimgetByIndex(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; nLevgetByIndex(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[nColLevelCount]; for (long i=0; iGetChildDimension(); // 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[nRowLevelCount]; for (long i=0; iGetChildDimension(); // pRowResDim->FillMemberResults( pRowResults, 0, pResData->GetRowStartMeasure() ); long nPos = 0; pRowResRoot->FillMemberResults( pRowResults, nPos, pResData->GetRowStartMeasure(), TRUE, NULL, NULL ); } } } const uno::Sequence* ScDPSource::GetMemberResults( ScDPLevel* pLevel ) { FillMemberResults(); long i; long nColCount = aColLevelList.Count(); for (i=0; i SAL_CALL ScDPSource::getPropertySetInfo() throw(uno::RuntimeException) { SolarMutexGuard 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(0)), READONLY, 0 }, {MAP_CHAR_LEN(SC_UNO_COLUMNFIELDCOUNT), 0, &getCppuType(static_cast(0)), READONLY, 0 }, {MAP_CHAR_LEN(SC_UNO_DATAFIELDCOUNT), 0, &getCppuType(static_cast(0)), READONLY, 0 }, {MAP_CHAR_LEN(SC_UNO_GRANDTOTAL_NAME), 0, &getCppuType(static_cast(0)), 0, 0 }, {0,0,0,0,0,0} }; static uno::Reference 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(nRowDimCount); else if ( aNameStr.EqualsAscii( SC_UNO_COLUMNFIELDCOUNT ) ) // read-only aRet <<= static_cast(nColDimCount); else if ( aNameStr.EqualsAscii( SC_UNO_DATAFIELDCOUNT ) ) // read-only aRet <<= static_cast(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; irelease(); // 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; irelease(); // 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; igetName() == aName ) { uno::Reference xNamed = getByIndex(i); uno::Any aRet; aRet <<= xNamed; return aRet; } throw container::NoSuchElementException(); // return uno::Any(); } uno::Sequence SAL_CALL ScDPDimensions::getElementNames() throw(uno::RuntimeException) { long nCount = getCount(); uno::Sequence aSeq(nCount); rtl::OUString* pArr = aSeq.getArray(); for (long i=0; igetName(); return aSeq; } sal_Bool SAL_CALL ScDPDimensions::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException) { long nCount = getCount(); for (long i=0; igetName() == aName ) return TRUE; return FALSE; } uno::Type SAL_CALL ScDPDimensions::getElementType() throw(uno::RuntimeException) { return getCppuType((uno::Reference*)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; iacquire(); // 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 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 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; igetByIndex(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; } 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 SAL_CALL ScDPDimension::getPropertySetInfo() throw(uno::RuntimeException) { SolarMutexGuard aGuard; static SfxItemPropertyMapEntry aDPDimensionMap_Impl[] = { {MAP_CHAR_LEN(SC_UNO_FILTER), 0, &getCppuType((uno::Sequence*)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*)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(0)), 0, 0 }, {MAP_CHAR_LEN(SC_UNO_FIELD_SUBTOTALNAME), 0, &getCppuType(static_cast(0)), 0, 0 }, {MAP_CHAR_LEN(SC_UNO_HAS_HIDDEN_MEMBER), 0, &getBooleanCppuType(), 0, 0 }, {0,0,0,0,0,0} }; static uno::Reference 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(eEnum) ); } else if ( aNameStr.EqualsAscii( SC_UNO_FUNCTION ) ) { sheet::GeneralFunction eEnum; if (aValue >>= eEnum) setFunction( sal::static_int_cast(eEnum) ); } else if ( aNameStr.EqualsAscii( SC_UNO_REFVALUE ) ) aValue >>= aReferenceValue; else if ( aNameStr.EqualsAscii( SC_UNO_FILTER ) ) { BOOL bDone = FALSE; uno::Sequence 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 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( &aField, 1 ); } else aRet <<= uno::Sequence(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; irelease(); // 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; igetName() == aName ) { uno::Reference xNamed = getByIndex(i); uno::Any aRet; aRet <<= xNamed; return aRet; } throw container::NoSuchElementException(); // return uno::Any(); } uno::Sequence SAL_CALL ScDPHierarchies::getElementNames() throw(uno::RuntimeException) { long nCount = getCount(); uno::Sequence aSeq(nCount); rtl::OUString* pArr = aSeq.getArray(); for (long i=0; igetName(); return aSeq; } sal_Bool SAL_CALL ScDPHierarchies::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException) { long nCount = getCount(); for (long i=0; igetName() == aName ) return TRUE; return FALSE; } uno::Type SAL_CALL ScDPHierarchies::getElementType() throw(uno::RuntimeException) { return getCppuType((uno::Reference*)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; iacquire(); // 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 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; irelease(); // 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; igetName() == aName ) { uno::Reference xNamed = getByIndex(i); uno::Any aRet; aRet <<= xNamed; return aRet; } throw container::NoSuchElementException(); // return uno::Any(); } uno::Sequence SAL_CALL ScDPLevels::getElementNames() throw(uno::RuntimeException) { long nCount = getCount(); uno::Sequence aSeq(nCount); rtl::OUString* pArr = aSeq.getArray(); for (long i=0; igetName(); return aSeq; } sal_Bool SAL_CALL ScDPLevels::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException) { long nCount = getCount(); for (long i=0; igetName() == aName ) return TRUE; return FALSE; } uno::Type SAL_CALL ScDPLevels::getElementType() throw(uno::RuntimeException) { return getCppuType((uno::Reference*)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; iacquire(); // 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; nMeasureGetDataDimName(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; nPosGetDataDimensionCount(); for (long nMeasure=0; nMeasureGetDataDimName(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 SAL_CALL ScDPLevel::getMembers() throw(uno::RuntimeException) { return GetMembersObject(); } uno::Sequence SAL_CALL ScDPLevel::getResults() throw(uno::RuntimeException) { const uno::Sequence* pRes = pSource->GetMemberResults( this ); if (pRes) return *pRes; return uno::Sequence(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 ScDPLevel::getSubTotals() const { //! separate functions for settings and evaluation? long nSrcDim = pSource->GetSourceDim( nDim ); if ( !pSource->SubTotalAllowed( nSrcDim ) ) return uno::Sequence(0); return aSubTotals; } void ScDPLevel::setSubTotals(const uno::Sequence& rNew) { aSubTotals = rNew; //! set "manual change" flag? } BOOL ScDPLevel::getShowEmpty() const { return bShowEmpty; } void ScDPLevel::setShowEmpty(BOOL bSet) { bShowEmpty = bSet; } // XPropertySet uno::Reference SAL_CALL ScDPLevel::getPropertySetInfo() throw(uno::RuntimeException) { SolarMutexGuard 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*)0), 0, 0 }, {0,0,0,0,0,0} }; static uno::Reference 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 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 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 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; irelease(); // 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; igetName() ] = 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 xNamed = getByIndex(nIndex); uno::Any aRet; aRet <<= xNamed; return aRet; } throw container::NoSuchElementException(); // return uno::Any(); } uno::Sequence 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& rGlobalOrder = pLevel->GetGlobalOrder(); bool bSort = !rGlobalOrder.empty(); long nCount = getCount(); uno::Sequence aSeq(nCount); rtl::OUString* pArr = aSeq.getArray(); for (long i=0; igetName(); 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*)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; igetIsVisible() && 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; iGetSourceDim( 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(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(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 SAL_CALL ScDPMember::getPropertySetInfo() throw(uno::RuntimeException) { SolarMutexGuard 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(0)), 0, 0 }, {0,0,0,0,0,0} }; static uno::Reference 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 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */