/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" // INCLUDE --------------------------------------------------------------- #include "dptablecache.hxx" #include "dptabdat.hxx" #include "document.hxx" #include "cell.hxx" #include "globstr.hrc" #include #include "queryparam.hxx" #include "dpglobal.hxx" #include "docoptio.hxx" //for ValidQuery #include //for ValidQuery #include #include #include #include #include const double D_TIMEFACTOR = 86400.0; using namespace ::com::sun::star; using ::com::sun::star::uno::Exception; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::uno::UNO_QUERY_THROW; // ----------------------------------------------------------------------- namespace { sal_Bool lcl_isDate( sal_uLong nNumType ) { return ( (nNumType & NUMBERFORMAT_DATE) != 0 )? 1:0 ; } sal_Bool lcl_Search( const std::vector& list, const ::std::vector& rOrder, const ScDPItemData& item, SCROW& rIndex) { rIndex = list.size(); sal_Bool bFound = sal_False; SCROW nLo = 0; SCROW nHi = list.size() - 1; SCROW nIndex; long nCompare; while (nLo <= nHi) { nIndex = (nLo + nHi) / 2; nCompare = ScDPItemData::Compare( *list[rOrder[nIndex]], item ); if (nCompare < 0) nLo = nIndex + 1; else { nHi = nIndex - 1; if (nCompare == 0) { bFound = sal_True; nLo = nIndex; } } } rIndex = nLo; return bFound; } ScDPItemData* lcl_GetItemValue(const Reference& xRow, sal_Int32 nType, long nCol, const Date& rNullDate ) { short nNumType = NUMBERFORMAT_NUMBER; try { String rStr = xRow->getString(nCol); double fValue = 0.0; switch (nType) { case sdbc::DataType::BIT: case sdbc::DataType::BOOLEAN: { nNumType = NUMBERFORMAT_LOGICAL; fValue = xRow->getBoolean(nCol) ? 1 : 0; return new ScDPItemData( rStr, fValue,sal_True,nNumType); } //break; case sdbc::DataType::TINYINT: case sdbc::DataType::SMALLINT: case sdbc::DataType::INTEGER: case sdbc::DataType::BIGINT: case sdbc::DataType::FLOAT: case sdbc::DataType::REAL: case sdbc::DataType::DOUBLE: case sdbc::DataType::NUMERIC: case sdbc::DataType::DECIMAL: { //! do the conversion here? fValue = xRow->getDouble(nCol); return new ScDPItemData( rStr, fValue,sal_True); } //break; case sdbc::DataType::DATE: { nNumType = NUMBERFORMAT_DATE; util::Date aDate = xRow->getDate(nCol); fValue = Date(aDate.Day, aDate.Month, aDate.Year) - rNullDate; return new ScDPItemData( rStr, fValue, sal_True, nNumType ); } //break; case sdbc::DataType::TIME: { nNumType = NUMBERFORMAT_TIME; util::Time aTime = xRow->getTime(nCol); fValue = ( aTime.Hours * 3600 + aTime.Minutes * 60 + aTime.Seconds + aTime.HundredthSeconds / 100.0 ) / D_TIMEFACTOR; return new ScDPItemData( rStr,fValue, sal_True, nNumType ); } //break; case sdbc::DataType::TIMESTAMP: { nNumType = NUMBERFORMAT_DATETIME; util::DateTime aStamp = xRow->getTimestamp(nCol); fValue = ( Date( aStamp.Day, aStamp.Month, aStamp.Year ) - rNullDate ) + ( aStamp.Hours * 3600 + aStamp.Minutes * 60 + aStamp.Seconds + aStamp.HundredthSeconds / 100.0 ) / D_TIMEFACTOR; return new ScDPItemData( rStr,fValue, sal_True, nNumType ); } //break; case sdbc::DataType::CHAR: case sdbc::DataType::VARCHAR: case sdbc::DataType::LONGVARCHAR: case sdbc::DataType::SQLNULL: case sdbc::DataType::BINARY: case sdbc::DataType::VARBINARY: case sdbc::DataType::LONGVARBINARY: default: return new ScDPItemData ( rStr ); //break; } } catch (uno::Exception&) { } catch ( ... ) { } return NULL; } } // Wang Xu Ming -- 12/23/2008 //Refactor cache data ScDPItemData::ScDPItemData( const String& rS, double fV/* = 0.0*/, sal_Bool bHV/* = sal_False*/, const sal_uLong nNumFormatP /*= 0*/ , sal_Bool bData/* = sal_True*/) : nNumFormat( nNumFormatP ), aString(rS), fValue(fV), mbFlag( (MK_VAL*!!bHV) | (MK_DATA*!!bData) | (MK_ERR*!!sal_False) | (MK_DATE*!!lcl_isDate( nNumFormat ) ) ) { } ScDPItemData::ScDPItemData( ScDocument* pDoc, SCROW nRow, sal_uInt16 nCol, sal_uInt16 nDocTab ): nNumFormat( 0 ), fValue(0.0), mbFlag( 0 ) { String aDocStr; pDoc->GetString( nCol, nRow, nDocTab, aDocStr ); SvNumberFormatter* pFormatter = pDoc->GetFormatTable(); ScAddress aPos( nCol, nRow, nDocTab ); ScBaseCell* pCell = pDoc->GetCell( aPos ); if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell)->GetErrCode() ) { SetString ( aDocStr ); //bErr = sal_True; mbFlag |= MK_ERR; } else if ( pDoc->HasValueData( nCol, nRow, nDocTab ) ) { double fVal = pDoc->GetValue(ScAddress(nCol, nRow, nDocTab)); nNumFormat = pDoc->GetNumberFormat( ScAddress( nCol, nRow, nDocTab ) ); sal_uLong nFormat = NUMBERFORMAT_NUMBER; if ( pFormatter ) nFormat = pFormatter->GetType( nNumFormat ); aString = aDocStr; fValue = fVal; mbFlag |= MK_VAL|MK_DATA; lcl_isDate( nFormat ) ? ( mbFlag |= MK_DATE ) : (mbFlag &= ~MK_DATE); } else if ( pDoc->HasData( nCol,nRow, nDocTab ) ) SetString ( aDocStr ); } // End Comments sal_Bool ScDPItemData::IsCaseInsEqual( const ScDPItemData& r ) const { //TODO: indified Date? //! pass Transliteration? //! inline? return IsValue() ? ( r.IsValue() && rtl::math::approxEqual( fValue, r.fValue ) ) : ( !r.IsValue() && ScGlobal::GetpTransliteration()->isEqual( aString, r.aString ) ); } size_t ScDPItemData::Hash() const { if ( IsValue() ) return (size_t) rtl::math::approxFloor( fValue ); else // If we do unicode safe case insensitive hash we can drop // ScDPItemData::operator== and use ::IsCasInsEqual return rtl_ustr_hashCode_WithLength( aString.GetBuffer(), aString.Len() ); } sal_Bool ScDPItemData::operator==( const ScDPItemData& r ) const { if ( IsValue() ) { if( (HasDatePart() != r.HasDatePart()) || (HasDatePart() && mnDatePart != r.mnDatePart) ) return sal_False; // Wang Xu Ming -- 1/9/2009 // Add Data Cache Support. // Identify date if ( IsDate() != r.IsDate() ) return sal_False; else if ( r.IsValue() ) return rtl::math::approxEqual( fValue, r.fValue ); else return sal_False; // End Comments } else if ( r.IsValue() ) return sal_False; else // need exact equality until we have a safe case insensitive string hash return aString == r.aString; } sal_Int32 ScDPItemData::Compare( const ScDPItemData& rA, const ScDPItemData& rB ) { if ( rA.IsValue() ) { if ( rB.IsValue() ) { if ( rtl::math::approxEqual( rA.fValue, rB.fValue ) ) { // Wang Xu Ming -- 1/9/2009 // Add Data Cache Support. // Date > number if ( rA.IsDate() == rB.IsDate() ) return 0; else return rA.IsDate() ? 1: -1; // End Comments } else if ( rA.fValue < rB.fValue ) return -1; else return 1; } else return -1; // values first } else if ( rB.IsValue() ) return 1; // values first else return ScGlobal::GetCollator()->compareString( rA.aString, rB.aString ); } #ifdef DEBUG void ScDPItemData::dump() const { DBG_TRACE1( "Numberformat= %o", nNumFormat ); DBG_TRACESTR(aString ); DBG_TRACE1( "fValue= %f", fValue ); DBG_TRACE1( "mbFlag= %d", mbFlag); } #endif TypedStrData* ScDPItemData::CreateTypeString( ) { if ( IsValue() ) return new TypedStrData( aString, fValue, SC_STRTYPE_VALUE ); else return new TypedStrData( aString ); } sal_uInt8 ScDPItemData::GetType() const { if ( IsHasErr() ) return SC_VALTYPE_ERROR; else if ( !IsHasData() ) return SC_VALTYPE_EMPTY; else if ( IsValue()) return SC_VALTYPE_VALUE; else return SC_VALTYPE_STRING; } sal_Bool ScDPItemData::IsHasData() const { return !!(mbFlag&MK_DATA); } sal_Bool ScDPItemData::IsHasErr() const { return !!(mbFlag&MK_ERR); } sal_Bool ScDPItemData::IsValue() const { return !!(mbFlag&MK_VAL); } String ScDPItemData::GetString() const { return aString; } double ScDPItemData::GetValue() const { return fValue; } sal_uLong ScDPItemData::GetNumFormat() const { return nNumFormat; } sal_Bool ScDPItemData::HasStringData() const { return IsHasData()&&!IsHasErr()&&!IsValue(); } sal_Bool ScDPItemData::IsDate() const { return !!(mbFlag&MK_DATE); } sal_Bool ScDPItemData::HasDatePart() const { return !!(mbFlag&MK_DATEPART); } void ScDPItemData::SetDate( sal_Bool b ) { b ? ( mbFlag |= MK_DATE ) : ( mbFlag &= ~MK_DATE ); } // ----------------------------------------------------------------------- //class ScDPTableDataCache //To cache the pivot table data source sal_Bool ScDPTableDataCache::operator== ( const ScDPTableDataCache& r ) const { if ( GetColumnCount() == r.GetColumnCount() ) { for ( SCCOL i = 0 ; i < GetColumnCount(); i++ ) { //check dim names if ( GetDimensionName( i ) != r.GetDimensionName( i ) ) return sal_False; //check rows count if ( GetRowCount() != r.GetRowCount() ) return sal_False; //check dim member values size_t nMembersCount = GetDimMemberValues( i ).size(); if ( GetDimMemberValues( i ).size() == r. GetDimMemberValues( i ).size() ) { for ( size_t j = 0; j < nMembersCount; j++ ) { if ( *( GetDimMemberValues( i )[j] ) == *( r.GetDimMemberValues( i )[j] ) ) continue; else return sal_False; } } else return sal_False; //check source table index for ( SCROW k=0 ; k < GetRowCount(); k ++ ) { if ( GetItemDataId( i, k, sal_False ) == r.GetItemDataId( i,k,sal_False) ) continue; else return sal_False; } } } return sal_True; } ScDPTableDataCache::ScDPTableDataCache( ScDocument* pDoc ) : mpDoc( pDoc ), mnColumnCount ( 0 ), mpTableDataValues ( NULL ), mpSourceData ( NULL ), mpGlobalOrder( NULL ), mpIndexOrder( NULL) { mnID = -1; } ScDPTableDataCache::~ScDPTableDataCache() { if ( IsValid() ) { // Wang Xu Ming -- 2/17/2009 // Performance issue sal_uInt16 nCol; for ( nCol=0; nCol < GetColumnCount() ; nCol++ ) { for ( sal_uLong row = 0 ; row < mpTableDataValues[nCol].size(); row++ ) delete mpTableDataValues[nCol][row]; } for ( nCol =0; nCol < mrLabelNames.size(); nCol++ ) delete mrLabelNames[nCol]; // End Comments mnColumnCount = 0; delete [] mpTableDataValues; mpTableDataValues = NULL; delete [] mpSourceData; mpSourceData = NULL; delete [] mpGlobalOrder; mpGlobalOrder = NULL; delete [] mpIndexOrder; mpIndexOrder = NULL; } } // ----------------------------------------------------------------------- void ScDPTableDataCache::AddRow( ScDPItemData* pRow, sal_uInt16 nCount ) { DBG_ASSERT( pRow , " empty pointer" ); if ( !mrLabelNames.size() ) { mnColumnCount= nCount; mpTableDataValues = new std::vector[ mnColumnCount ]; mpSourceData = new std::vector[ mnColumnCount ]; mpGlobalOrder = new std::vector[ mnColumnCount ]; mpIndexOrder = new std::vector[ mnColumnCount ]; for ( sal_uInt16 i = 0; i < nCount ; i ++ ) AddLabel( new ScDPItemData( pRow[i] ) ); } else { for ( sal_uInt16 i = 0; i < nCount && i < mnColumnCount; i ++ ) AddData( i, new ScDPItemData( pRow[i] ) ); } } // ----------------------------------------------------------------------- bool ScDPTableDataCache::IsValid() const { //TODO: continue check valid return mpTableDataValues!=NULL && mpSourceData!= NULL && mnColumnCount>0; } // ----------------------------------------------------------------------- namespace { /** * While the macro interpret level is incremented, the formula cells are * (semi-)guaranteed to be interpreted. */ class MacroInterpretIncrementer { public: MacroInterpretIncrementer(ScDocument* pDoc) : mpDoc(pDoc) { mpDoc->IncMacroInterpretLevel(); } ~MacroInterpretIncrementer() { mpDoc->DecMacroInterpretLevel(); } private: ScDocument* mpDoc; }; } // ----------------------------------------------------------------------- bool ScDPTableDataCache::InitFromDoc( ScDocument* pDoc, const ScRange& rRange ) { // Make sure the formula cells within the data range are interpreted // during this call, for this method may be called from the interpretation // of GETPIVOTDATA, which disables nested formula interpretation without // increasing the macro level. MacroInterpretIncrementer aMacroInc(pDoc); // SCROW nStartRow = rRange.aStart.Row(); // start of data SCROW nEndRow = rRange.aEnd.Row(); sal_uInt16 nStartCol = rRange.aStart.Col(); sal_uInt16 nEndCol = rRange.aEnd.Col(); sal_uInt16 nDocTab = rRange.aStart.Tab(); //init long nOldColumCount = mnColumnCount; mnColumnCount = nEndCol - nStartCol + 1; if ( IsValid() ) { for ( sal_uInt16 nCol=0; nCol < nOldColumCount ; nCol++ ) { for ( sal_uLong row = 0 ; row < mpTableDataValues[nCol].size(); row++ ) delete mpTableDataValues[nCol][row]; delete mrLabelNames[nCol]; } delete [] mpTableDataValues; delete [] mpSourceData; delete [] mpGlobalOrder; delete [] mpIndexOrder; mrLabelNames.clear(); } mpTableDataValues = new std::vector[ mnColumnCount ]; mpSourceData = new std::vector[ mnColumnCount ]; mpGlobalOrder = new std::vector[ mnColumnCount ]; mpIndexOrder = new std::vector[ mnColumnCount ]; pDoc->FillDPCache( this, nDocTab, nStartCol, nEndCol, nStartRow, nEndRow ); return sal_True; } // ----------------------------------------------------------------------- bool ScDPTableDataCache::InitFromDataBase (const Reference& xRowSet, const Date& rNullDate) { if (!xRowSet.is()) // Dont' even waste time to go any further. return false; try { Reference xMetaSupp(xRowSet, UNO_QUERY_THROW); Reference xMeta = xMetaSupp->getMetaData(); if (!xMeta.is()) return false; long nOldColumCount = mnColumnCount; mnColumnCount = xMeta->getColumnCount(); if ( IsValid() ) { for ( sal_uInt16 nCol=0; nCol < nOldColumCount ; nCol++ ) { for ( sal_uLong row = 0 ; row < mpTableDataValues[nCol].size(); row++ ) delete mpTableDataValues[nCol][row]; delete mrLabelNames[nCol]; } delete [] mpTableDataValues; delete [] mpSourceData; delete [] mpGlobalOrder; delete [] mpIndexOrder; mrLabelNames.clear(); } // Get column titles and types. mrLabelNames.reserve(mnColumnCount); mpTableDataValues = new std::vector[ mnColumnCount ]; mpSourceData = new std::vector[ mnColumnCount ]; mpGlobalOrder = new std::vector[ mnColumnCount ]; mpIndexOrder = new std::vector[ mnColumnCount ]; std::vector aColTypes(mnColumnCount); for (sal_Int32 nCol = 0; nCol < mnColumnCount; ++nCol) { String aColTitle = xMeta->getColumnLabel(nCol+1); aColTypes[nCol] = xMeta->getColumnType(nCol+1); AddLabel( new ScDPItemData( aColTitle) ); } // Now get the data rows. Reference xRow(xRowSet, UNO_QUERY_THROW); xRowSet->first(); do { for (sal_Int32 nCol = 0; nCol < mnColumnCount; ++nCol) { ScDPItemData * pNew = lcl_GetItemValue( xRow, aColTypes[nCol], nCol+1, rNullDate ); if ( pNew ) AddData( nCol , pNew ); } } while (xRowSet->next()); xRowSet->beforeFirst(); return true; } catch (const Exception&) { return false; } } // ----------------------------------------------------------------------- sal_uLong ScDPTableDataCache::GetDimNumType( SCCOL nDim) const { DBG_ASSERT( IsValid(), " IsValid() == false " ); DBG_ASSERT( nDim < mnColumnCount && nDim >=0, " dimension out of bound " ); if ( mpTableDataValues[nDim].size()==0 ) return NUMBERFORMAT_UNDEFINED; else return GetNumType(mpTableDataValues[nDim][0]->nNumFormat); } // ----------------------------------------------------------------------- bool ScDPTableDataCache::ValidQuery( SCROW nRow, const ScQueryParam &rParam, sal_Bool *pSpecial) { //Copied and modified from ScTable::ValidQuery if (!rParam.GetEntry(0).bDoQuery) return sal_True; sal_Bool bMatchWholeCell = mpDoc->GetDocOptions().IsMatchWholeCell(); //--------------------------------------------------------------- const SCSIZE nFixedBools = 32; sal_Bool aBool[nFixedBools]; sal_Bool aTest[nFixedBools]; SCSIZE nEntryCount = rParam.GetEntryCount(); sal_Bool* pPasst = ( nEntryCount <= nFixedBools ? &aBool[0] : new sal_Bool[nEntryCount] ); sal_Bool* pTest = ( nEntryCount <= nFixedBools ? &aTest[0] : new sal_Bool[nEntryCount] ); long nPos = -1; SCSIZE i = 0; CollatorWrapper* pCollator = (rParam.bCaseSens ? ScGlobal::GetCaseCollator() : ScGlobal::GetCollator() ); ::utl::TransliterationWrapper* pTransliteration = (rParam.bCaseSens ? ScGlobal::GetCaseTransliteration() : ScGlobal::GetpTransliteration()); while ( (i < nEntryCount) && rParam.GetEntry(i).bDoQuery ) { ScQueryEntry& rEntry = rParam.GetEntry(i); // we can only handle one single direct query // #i115431# nField in QueryParam is the sheet column, not the field within the source range SCCOL nQueryCol = (SCCOL)rEntry.nField; if ( nQueryCol < rParam.nCol1 ) nQueryCol = rParam.nCol1; if ( nQueryCol > rParam.nCol2 ) nQueryCol = rParam.nCol2; SCCOL nSourceField = nQueryCol - rParam.nCol1; SCROW nId = GetItemDataId( nSourceField, nRow, sal_False ); const ScDPItemData* pCellData = GetItemDataById( nSourceField, nId ); sal_Bool bOk = sal_False; sal_Bool bTestEqual = sal_False; if ( pSpecial && pSpecial[i] ) { if (rEntry.nVal == SC_EMPTYFIELDS) bOk = ! pCellData->IsHasData(); else // if (rEntry.nVal == SC_NONEMPTYFIELDS) bOk = pCellData->IsHasData(); } else if ( !rEntry.bQueryByString && pCellData->IsValue() ) { // by Value double nCellVal = pCellData->GetValue(); switch (rEntry.eOp) { case SC_EQUAL : bOk = ::rtl::math::approxEqual( nCellVal, rEntry.nVal ); break; case SC_LESS : bOk = (nCellVal < rEntry.nVal) && !::rtl::math::approxEqual( nCellVal, rEntry.nVal ); break; case SC_GREATER : bOk = (nCellVal > rEntry.nVal) && !::rtl::math::approxEqual( nCellVal, rEntry.nVal ); break; case SC_LESS_EQUAL : bOk = (nCellVal < rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal ); break; case SC_GREATER_EQUAL : bOk = (nCellVal > rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal ); break; case SC_NOT_EQUAL : bOk = !::rtl::math::approxEqual( nCellVal, rEntry.nVal ); break; default: bOk= sal_False; break; } } else if ( (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL) || (rEntry.bQueryByString && pCellData->HasStringData() ) ) { // by String String aCellStr = pCellData->GetString(); sal_Bool bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL) || (rEntry.eOp == SC_NOT_EQUAL))); sal_Bool bTestRegExp = sal_False; if ( bRealRegExp || bTestRegExp ) { xub_StrLen nStart = 0; xub_StrLen nEnd = aCellStr.Len(); sal_Bool bMatch = (sal_Bool) rEntry.GetSearchTextPtr( rParam.bCaseSens ) ->SearchFrwrd( aCellStr, &nStart, &nEnd ); // from 614 on, nEnd is behind the found text if ( bMatch && bMatchWholeCell && (nStart != 0 || nEnd != aCellStr.Len()) ) bMatch = sal_False; // RegExp must match entire cell string if ( bRealRegExp ) bOk = ((rEntry.eOp == SC_NOT_EQUAL) ? !bMatch : bMatch); else bTestEqual = bMatch; } if ( !bRealRegExp ) { if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL ) { if ( bMatchWholeCell ) { bOk = pTransliteration->isEqual( aCellStr, *rEntry.pStr ); String aStr = *rEntry.pStr;//"f*" //use another way to find "*" in aStr sal_Bool bHasStar = sal_False; xub_StrLen nIndex; if( ( nIndex = aStr.Search('*') ) != STRING_NOTFOUND ) bHasStar = sal_True; if(bHasStar && (nIndex>0)) { for(i=0;(i xOff; String aCell( pTransliteration->transliterate( aCellStr, ScGlobal::eLnge, 0, aCellStr.Len(), &xOff ) ); String aQuer( pTransliteration->transliterate( *rEntry.pStr, ScGlobal::eLnge, 0, rEntry.pStr->Len(), &xOff ) ); bOk = (aCell.Search( aQuer ) != STRING_NOTFOUND); } if ( rEntry.eOp == SC_NOT_EQUAL ) bOk = !bOk; } else { // use collator here because data was probably sorted sal_Int32 nCompare = pCollator->compareString( aCellStr, *rEntry.pStr ); switch (rEntry.eOp) { case SC_LESS : bOk = (nCompare < 0); break; case SC_GREATER : bOk = (nCompare > 0); break; case SC_LESS_EQUAL : bOk = (nCompare <= 0); break; case SC_GREATER_EQUAL : bOk = (nCompare >= 0); break; case SC_NOT_EQUAL: DBG_ASSERT( false , "SC_NOT_EQUAL"); break; case SC_TOPVAL: case SC_BOTVAL: case SC_TOPPERC: case SC_BOTPERC: default: break; } } } } if (nPos == -1) { nPos++; pPasst[nPos] = bOk; pTest[nPos] = bTestEqual; } else { if (rEntry.eConnect == SC_AND) { pPasst[nPos] = pPasst[nPos] && bOk; pTest[nPos] = pTest[nPos] && bTestEqual; } else { nPos++; pPasst[nPos] = bOk; pTest[nPos] = bTestEqual; } } i++; } for ( long j=1; j <= nPos; j++ ) { pPasst[0] = pPasst[0] || pPasst[j]; pTest[0] = pTest[0] || pTest[j]; } sal_Bool bRet = pPasst[0]; if ( pPasst != &aBool[0] ) delete [] pPasst; if ( pTest != &aTest[0] ) delete [] pTest; return bRet; } // ----------------------------------------------------------------------- bool ScDPTableDataCache::IsRowEmpty( SCROW nRow ) const { return mbEmptyRow[ nRow ]; } // ----------------------------------------------------------------------- bool ScDPTableDataCache::IsEmptyMember( SCROW nRow, sal_uInt16 nColumn ) const { return !GetItemDataById( nColumn, GetItemDataId( nColumn, nRow, sal_False ) )->IsHasData(); } sal_Bool ScDPTableDataCache::AddData(long nDim, ScDPItemData* pitemData, bool bCheckDate ) { DBG_ASSERT( IsValid(), " IsValid() == false " ); DBG_ASSERT( nDim < mnColumnCount && nDim >=0 , "dimension out of bound" ); SCROW nIndex = 0; sal_Bool bInserted = sal_False; if( true == bCheckDate) pitemData->SetDate( lcl_isDate( GetNumType( pitemData->nNumFormat ) ) ); if ( !lcl_Search( mpTableDataValues[nDim], mpGlobalOrder[nDim], *pitemData, nIndex ) ) { mpTableDataValues[nDim].push_back( pitemData ); mpGlobalOrder[nDim].insert( mpGlobalOrder[nDim].begin()+nIndex, mpTableDataValues[nDim].size()-1 ); DBG_ASSERT( (size_t) mpGlobalOrder[nDim][nIndex] == mpTableDataValues[nDim].size()-1 ,"ScDPTableDataCache::AddData "); mpSourceData[nDim].push_back( mpTableDataValues[nDim].size()-1 ); bInserted = sal_True; } else mpSourceData[nDim].push_back( mpGlobalOrder[nDim][nIndex] ); //init empty row tag size_t nCurRow = mpSourceData[nDim].size() -1 ; while ( mbEmptyRow.size() <= nCurRow ) mbEmptyRow.push_back( sal_True ); if ( pitemData->IsHasData() ) mbEmptyRow[ nCurRow ] = sal_False; if ( !bInserted ) delete pitemData; return sal_True; } String ScDPTableDataCache::GetDimensionName( sal_uInt16 nColumn ) const { DBG_ASSERT( /* nColumn>=0 && */ nColumn < mrLabelNames.size()-1 , "ScDPTableDataCache::GetDimensionName"); DBG_ASSERT( mrLabelNames.size() == static_cast (mnColumnCount+1), "ScDPTableDataCache::GetDimensionName"); if ( static_cast(nColumn+1) < mrLabelNames.size() ) { return mrLabelNames[nColumn+1]->aString; } else return String(); } void ScDPTableDataCache::AddLabel(ScDPItemData *pData) { DBG_ASSERT( IsValid(), " IsValid() == false " ); if ( mrLabelNames.size() == 0 ) mrLabelNames.push_back( new ScDPItemData( ScGlobal::GetRscString(STR_PIVOT_DATA) ) ); //reset name if needed String strNewName = pData->aString; // #i116457# don't modify empty column titles if ( strNewName.Len() ) { sal_Bool bFound = sal_False; long nIndex = 1; do { for ( long i= mrLabelNames.size()-1; i>=0; i-- ) { if( mrLabelNames[i]->aString == strNewName ) { strNewName = pData->aString; strNewName += String::CreateFromInt32( nIndex ); nIndex ++ ; bFound = sal_True; } } bFound = !bFound; } while ( !bFound ); } pData->aString = strNewName; mrLabelNames.push_back( pData ); } SCROW ScDPTableDataCache::GetItemDataId(sal_uInt16 nDim, SCROW nRow, sal_Bool bRepeatIfEmpty) const { // DBG_ASSERT( IsValid(), " IsValid() == false " ); DBG_ASSERT( /* nDim >= 0 && */ nDim < mnColumnCount, "ScDPTableDataCache::GetItemDataId " ); if ( bRepeatIfEmpty ) { while ( nRow >0 && !mpTableDataValues[nDim][ mpSourceData[nDim][nRow] ]->IsHasData() ) --nRow; } return mpSourceData[nDim][nRow]; } const ScDPItemData* ScDPTableDataCache::GetItemDataById(long nDim, SCROW nId) const { if ( nId >= GetRowCount() ) return maAdditionalDatas.getData( nId - GetRowCount() ); if ( (size_t)nId >= mpTableDataValues[nDim].size() || nDim >= mnColumnCount || nId < 0 ) return NULL; else return mpTableDataValues[nDim][nId]; } SCROW ScDPTableDataCache::GetRowCount() const { if ( IsValid() ) return mpSourceData[0].size(); else return 0; } const std::vector& ScDPTableDataCache::GetDimMemberValues(SCCOL nDim) const { DBG_ASSERT( nDim>=0 && nDim < mnColumnCount ," nDim < mnColumnCount "); return mpTableDataValues[nDim]; } SCROW ScDPTableDataCache::GetSortedItemDataId(SCCOL nDim, SCROW nOrder) const { DBG_ASSERT ( IsValid(), "IsValid"); DBG_ASSERT( nDim>=0 && nDim < mnColumnCount, "nDim < mnColumnCount"); DBG_ASSERT( nOrder >= 0 && (size_t) nOrder < mpGlobalOrder[nDim].size(), "nOrder < mpGlobalOrder[nDim].size()" ); return mpGlobalOrder[nDim][nOrder]; } sal_uLong ScDPTableDataCache::GetNumType(sal_uLong nFormat) const { SvNumberFormatter* pFormatter = mpDoc->GetFormatTable(); sal_uLong nType = NUMBERFORMAT_NUMBER; if ( pFormatter ) nType = pFormatter->GetType( nFormat ); return nType; } sal_uLong ScDPTableDataCache::GetNumberFormat( long nDim ) const { if ( nDim >= mnColumnCount ) return 0; // #i113411# take the number format from the first value entry size_t nSize = mpTableDataValues[nDim].size(); size_t nPos = 0; while ( nPos < nSize && mpTableDataValues[nDim][nPos]->GetType() != SC_VALTYPE_VALUE ) ++nPos; if ( nPos < nSize ) return mpTableDataValues[nDim][nPos]->nNumFormat; return 0; } sal_Bool ScDPTableDataCache::IsDateDimension( long nDim ) const { if ( nDim >= mnColumnCount ) return false; else if ( mpTableDataValues[nDim].size()==0 ) return false; else return mpTableDataValues[nDim][0]->IsDate(); } SCROW ScDPTableDataCache::GetDimMemberCount( SCCOL nDim ) const { DBG_ASSERT( nDim>=0 && nDim < mnColumnCount ," ScDPTableDataCache::GetDimMemberCount : out of bound "); return mpTableDataValues[nDim].size(); } const ScDPItemData* ScDPTableDataCache::GetSortedItemData(SCCOL nDim, SCROW nOrder) const { SCROW n = GetSortedItemDataId( nDim, nOrder ); return GetItemDataById( nDim, n ); } SCCOL ScDPTableDataCache::GetDimensionIndex(String sName) const { for ( size_t n = 1; n < mrLabelNames.size(); n ++ ) //defects, label name map wrong { if ( mrLabelNames[n]->GetString() == sName ) return (SCCOL)(n-1); } return -1; } SCROW ScDPTableDataCache::GetIdByItemData(long nDim, String sItemData ) const { if ( nDim < mnColumnCount && nDim >=0 ) { for ( size_t n = 0; n< mpTableDataValues[nDim].size(); n++ ) { if ( mpTableDataValues[nDim][n]->GetString() == sItemData ) return n; } } ScDPItemData rData ( sItemData ); return GetRowCount() +maAdditionalDatas.getDataId(rData); } SCROW ScDPTableDataCache::GetIdByItemData( long nDim, const ScDPItemData& rData ) const { if ( nDim < mnColumnCount && nDim >=0 ) { for ( size_t n = 0; n< mpTableDataValues[nDim].size(); n++ ) { if ( *mpTableDataValues[nDim][n] == rData ) return n; } } return GetRowCount() + maAdditionalDatas.getDataId(rData); } SCROW ScDPTableDataCache::GetAdditionalItemID ( String sItemData ) { ScDPItemData rData ( sItemData ); return GetAdditionalItemID( rData ); } SCROW ScDPTableDataCache::GetAdditionalItemID( const ScDPItemData& rData ) { return GetRowCount() + maAdditionalDatas.insertData( rData ); } SCROW ScDPTableDataCache::GetOrder(long nDim, SCROW nIndex) const { DBG_ASSERT( IsValid(), " IsValid() == false " ); DBG_ASSERT( nDim >=0 && nDim < mnColumnCount, "ScDPTableDataCache::GetOrder : out of bound" ); if ( mpIndexOrder[nDim].size() != mpGlobalOrder[nDim].size() ) { //not inited SCROW i = 0; mpIndexOrder[nDim].resize( mpGlobalOrder[nDim].size(), 0 ); for ( size_t n = 0 ; n< mpGlobalOrder[nDim].size(); n++ ) { i = mpGlobalOrder[nDim][n]; mpIndexOrder[nDim][ i ] = n; } } DBG_ASSERT( nIndex>=0 && (size_t)nIndex < mpIndexOrder[nDim].size() , "ScDPTableDataCache::GetOrder"); return mpIndexOrder[nDim][nIndex]; } ScDocument* ScDPTableDataCache::GetDoc() const { return mpDoc; }; long ScDPTableDataCache::GetColumnCount() const { return mnColumnCount; } long ScDPTableDataCache::GetId() const { return mnID; }