diff options
Diffstat (limited to 'sc/source/core')
-rw-r--r-- | sc/source/core/data/cell2.cxx | 4 | ||||
-rw-r--r-- | sc/source/core/data/column2.cxx | 17 | ||||
-rw-r--r-- | sc/source/core/data/documen2.cxx | 7 | ||||
-rw-r--r-- | sc/source/core/data/documen3.cxx | 29 | ||||
-rwxr-xr-x | sc/source/core/data/documen9.cxx | 22 | ||||
-rw-r--r-- | sc/source/core/data/dpobject.cxx | 52 | ||||
-rw-r--r-- | sc/source/core/data/dpsave.cxx | 63 | ||||
-rw-r--r-- | sc/source/core/data/dpsdbtab.cxx | 2 | ||||
-rw-r--r-- | sc/source/core/data/dpshttab.cxx | 12 | ||||
-rw-r--r-- | sc/source/core/data/dptablecache.cxx | 44 | ||||
-rw-r--r-- | sc/source/core/data/drwlayer.cxx | 24 | ||||
-rw-r--r-- | sc/source/core/data/table2.cxx | 34 | ||||
-rw-r--r-- | sc/source/core/data/table4.cxx | 261 | ||||
-rw-r--r-- | sc/source/core/inc/interpre.hxx | 1 | ||||
-rw-r--r-- | sc/source/core/tool/address.cxx | 8 | ||||
-rw-r--r-- | sc/source/core/tool/compiler.cxx | 47 | ||||
-rw-r--r-- | sc/source/core/tool/dbcolect.cxx | 23 | ||||
-rw-r--r-- | sc/source/core/tool/interpr1.cxx | 260 | ||||
-rw-r--r-- | sc/source/core/tool/interpr3.cxx | 252 | ||||
-rwxr-xr-x | sc/source/core/tool/interpr4.cxx | 48 | ||||
-rw-r--r-- | sc/source/core/tool/token.cxx | 25 |
21 files changed, 814 insertions, 421 deletions
diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx index e4631dde2d9a..23b9934564b9 100644 --- a/sc/source/core/data/cell2.cxx +++ b/sc/source/core/data/cell2.cxx @@ -990,6 +990,10 @@ void ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode, pUndoDoc->PutCell( aUndoPos, pFCell ); } } + // #i116833# If the formula is changed, always invalidate the stream (even if the result is the same). + // If the formula is moved, the change is recognized separately. + if (bValChanged && pDocument->IsStreamValid(aPos.Tab())) + pDocument->SetStreamValid(aPos.Tab(), sal_False); bValChanged = sal_False; if ( pRangeData ) { // Replace shared formula with own formula diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index abc82c005408..db48b58a169a 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -244,9 +244,16 @@ long ScColumn::GetNeededSize( SCROW nRow, OutputDevice* pDev, else bBreak = ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue(); - if (pCell->HasValueData()) - // Cell has a value. Disable line break. - bBreak = false; + SvNumberFormatter* pFormatter = pDocument->GetFormatTable(); + sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet ); + // #i111387# #o11817313# disable automatic line breaks only for "General" number format + if ( bBreak && pCell->HasValueData() && ( nFormat % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 ) + { + // also take formula result type into account for number format + if ( pCell->GetCellType() != CELLTYPE_FORMULA || + ( static_cast<ScFormulaCell*>(pCell)->GetStandardFormat(*pFormatter, nFormat) % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 ) + bBreak = false; + } // get other attributes from pattern and conditional formatting @@ -332,8 +339,6 @@ long ScColumn::GetNeededSize( SCROW nRow, OutputDevice* pDev, { String aValStr; Color* pColor; - SvNumberFormatter* pFormatter = pDocument->GetFormatTable(); - sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet ); ScCellFormat::GetString( pCell, nFormat, aValStr, &pColor, *pFormatter, sal_True, rOptions.bFormula, ftCheck ); @@ -497,8 +502,6 @@ long ScColumn::GetNeededSize( SCROW nRow, OutputDevice* pDev, else { Color* pColor; - SvNumberFormatter* pFormatter = pDocument->GetFormatTable(); - sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet ); String aString; ScCellFormat::GetString( pCell, nFormat, aString, &pColor, *pFormatter, diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx index 44f7e6722d69..e0242ab90305 100644 --- a/sc/source/core/data/documen2.cxx +++ b/sc/source/core/data/documen2.cxx @@ -447,7 +447,12 @@ ScDocument::~ScDocument() delete pChangeViewSettings; // und weg damit delete pVirtualDevice_100th_mm; - delete pDPCollection; + if (pDPCollection) + { + pDPCollection->FreeAll(); + RemoveUnusedDPObjectCaches(); + delete pDPCollection; + } // delete the EditEngine before destroying the xPoolHelper delete pCacheFieldEditEngine; diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx index e249d7f3bf47..3f8742ee1d56 100644 --- a/sc/source/core/data/documen3.cxx +++ b/sc/source/core/data/documen3.cxx @@ -2,7 +2,7 @@ * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright 2000, 2010 Oracle and/or its affiliates. + * Copyright 2000, 2011 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * @@ -197,6 +197,14 @@ ScDBData* ScDocument::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nC return NULL; } +ScDBData* ScDocument::GetFilterDBAtTable(SCTAB nTab) const +{ + if (pDBCollection) + return pDBCollection->GetFilterDBAtTable(nTab); + else + return NULL; +} + ScDPCollection* ScDocument::GetDPCollection() { if (!pDPCollection) @@ -1359,6 +1367,20 @@ sal_Bool ScDocument::GetFilterEntries( SCCOL nEndCol; SCROW nEndRow; pDBData->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow ); + + //Add for i85305 + SCCOL nTmpStartCol = nCol; + SCROW nTmpStartRow = nRow; + SCCOL nTmpEndCol = nCol; + SCROW nTmpEndRow = nRow; + GetDataArea( nTab, nTmpStartCol, nTmpStartRow, nTmpEndCol, nTmpEndRow, sal_False, false); + if (nTmpEndRow > nEndRow) + { + nEndRow = nTmpEndRow; + pDBData->SetArea(nAreaTab, nStartCol,nStartRow, nEndCol,nEndRow); + } + //End of i85305 + if (pDBData->HasHeader()) ++nStartRow; @@ -2098,7 +2120,7 @@ void ScDocument::RemoveDPObjectCache( long nID ) void ScDocument::RemoveUnusedDPObjectCaches() { - for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); iter++ ) + for ( std::list<ScDPTableDataCache*>::iterator iter = m_listDPObjectsCaches.begin(); iter!=m_listDPObjectsCaches.end(); ) { long nID = (*iter)->GetId(); sal_uInt16 nCount = GetDPCollection()->GetCount(); @@ -2111,10 +2133,11 @@ void ScDocument::RemoveUnusedDPObjectCaches() if ( i == nCount ) { ScDPTableDataCache* pCache = *iter; - m_listDPObjectsCaches.erase( iter ); + iter = m_listDPObjectsCaches.erase( iter ); delete pCache; continue; } + ++iter; } } diff --git a/sc/source/core/data/documen9.cxx b/sc/source/core/data/documen9.cxx index 7d66ece8c570..4ca9b14d8f5d 100755 --- a/sc/source/core/data/documen9.cxx +++ b/sc/source/core/data/documen9.cxx @@ -111,17 +111,21 @@ void ScDocument::TransferDrawPage(ScDocument* pSrcDoc, SCTAB nSrcPos, SCTAB nDes SdrObject* pOldObject = aIter.Next(); while (pOldObject) { - // #116235# - SdrObject* pNewObject = pOldObject->Clone(); - // SdrObject* pNewObject = pOldObject->Clone( pNewPage, pDrawLayer ); - pNewObject->SetModel(pDrawLayer); - pNewObject->SetPage(pNewPage); + // #i112034# do not copy internal objects (detective) and note captions + if ( pOldObject->GetLayer() != SC_LAYER_INTERN && !ScDrawLayer::IsNoteCaption( pOldObject ) ) + { + // #116235# + SdrObject* pNewObject = pOldObject->Clone(); + // SdrObject* pNewObject = pOldObject->Clone( pNewPage, pDrawLayer ); + pNewObject->SetModel(pDrawLayer); + pNewObject->SetPage(pNewPage); - pNewObject->NbcMove(Size(0,0)); - pNewPage->InsertObject( pNewObject ); + pNewObject->NbcMove(Size(0,0)); + pNewPage->InsertObject( pNewObject ); - if (pDrawLayer->IsRecording()) - pDrawLayer->AddCalcUndo( new SdrUndoInsertObj( *pNewObject ) ); + if (pDrawLayer->IsRecording()) + pDrawLayer->AddCalcUndo( new SdrUndoInsertObj( *pNewObject ) ); + } pOldObject = aIter.Next(); } diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx index c4a256b48f54..431b86d328a0 100644 --- a/sc/source/core/data/dpobject.cxx +++ b/sc/source/core/data/dpobject.cxx @@ -175,7 +175,8 @@ ScDPObject::ScDPObject( ScDocument* pD ) : nHeaderRows( 0 ), mbHeaderLayout(false), bRefresh( sal_False ), // Wang Xu Ming - DataPilot migration - mnCacheId( -1) // Wang Xu Ming - DataPilot migration + mnCacheId( -1 ), // Wang Xu Ming - DataPilot migration + mbCreatingTableData( false ) { } @@ -197,7 +198,8 @@ ScDPObject::ScDPObject(const ScDPObject& r) : nHeaderRows( r.nHeaderRows ), mbHeaderLayout( r.mbHeaderLayout ), bRefresh( r.bRefresh ), // Wang Xu Ming - DataPilot migration - mnCacheId ( r.mnCacheId ) // Wang Xu Ming - DataPilot migration + mnCacheId ( r.mnCacheId ), // Wang Xu Ming - DataPilot migration + mbCreatingTableData( false ) { if (r.pSaveData) pSaveData = new ScDPSaveData(*r.pSaveData); @@ -272,7 +274,7 @@ void ScDPObject::SetOutRange(const ScRange& rRange) pOutput->SetPosition( rRange.aStart ); } -void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc) +void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc, bool bFromRefUpdate) { if ( pSheetDesc && rDesc == *pSheetDesc ) return; // nothing to do @@ -280,7 +282,7 @@ void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc) DELETEZ( pImpDesc ); DELETEZ( pServDesc ); - delete pImpDesc; + delete pSheetDesc; pSheetDesc = new ScSheetSourceDesc(rDesc); // make valid QueryParam @@ -292,6 +294,8 @@ void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc) pSheetDesc->aQueryParam.bHasHeader = sal_True; InvalidateSource(); // new source must be created + if (!bFromRefUpdate) + SetCacheId( -1 ); // #i116504# don't use the same cache ID for a different range (except reference update) } void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc) @@ -306,6 +310,7 @@ void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc) pImpDesc = new ScImportSourceDesc(rDesc); InvalidateSource(); // new source must be created + SetCacheId( -1 ); } void ScDPObject::SetServiceData(const ScDPServiceDesc& rDesc) @@ -416,8 +421,12 @@ void ScDPObject::CreateOutput() ScDPTableData* ScDPObject::GetTableData() { - if (!mpTableData) + if (!mpTableData && !mbCreatingTableData) { + // #i117239# While filling the cache, mpTableData is still null. + // Prevent nested calls from GetPivotData and similar functions. + mbCreatingTableData = true; + shared_ptr<ScDPTableData> pData; if ( pImpDesc ) { @@ -453,6 +462,8 @@ ScDPTableData* ScDPObject::GetTableData() // End Comments mpTableData = pData; // after SetCacheId + + mbCreatingTableData = false; } return mpTableData.get(); @@ -482,16 +493,19 @@ void ScDPObject::CreateObjects() DBG_ASSERT( !pServDesc, "DPSource could not be created" ); ScDPTableData* pData = GetTableData(); - ScDPSource* pSource = new ScDPSource( pData ); - xSource = pSource; - - if ( pSaveData && bRefresh ) + if ( pData ) // nested GetTableData calls may return NULL { - pSaveData->Refresh( xSource ); - bRefresh = sal_False; + ScDPSource* pSource = new ScDPSource( pData ); + xSource = pSource; + + if ( pSaveData && bRefresh ) + { + pSaveData->Refresh( xSource ); + bRefresh = sal_False; + } } } - if (pSaveData ) + if ( xSource.is() && pSaveData ) pSaveData->WriteToSource( xSource ); } else if (bSettingsChanged) @@ -630,9 +644,12 @@ void ScDPObject::BuildAllDimensionMembers() return; // #i111857# don't always create empty mpTableData for external service. - // Ideally, xSource should be used instead of mpTableData. + // #163781# Initialize all members from xSource instead. if (pServDesc) + { + pSaveData->BuildAllDimensionMembersFromSource( this ); return; + } pSaveData->BuildAllDimensionMembers(GetTableData()); } @@ -739,7 +756,7 @@ void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode, if (aNewDesc.aQueryParam.GetEntry(i).bDoQuery) aNewDesc.aQueryParam.GetEntry(i).nField += nDiffX; - SetSheetDesc( aNewDesc ); // allocates new pSheetDesc + SetSheetDesc( aNewDesc, true ); // allocates new pSheetDesc } } } @@ -767,7 +784,7 @@ void ScDPObject::WriteRefsTo( ScDPObject& r ) const { r.SetOutRange( aOutRange ); if ( pSheetDesc ) - r.SetSheetDesc( *pSheetDesc ); + r.SetSheetDesc( *pSheetDesc, true ); } void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData) @@ -1043,6 +1060,11 @@ void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHead sal_Bool ScDPObject::GetPivotData( ScDPGetPivotDataField& rTarget, const std::vector< ScDPGetPivotDataField >& rFilters ) { + // #i117239# Exit with an error if called from creating the cache for this object + // (don't create an empty pOutput object) + if (mbCreatingTableData) + return sal_False; + CreateOutput(); // create xSource and pOutput if not already done return pOutput->GetPivotData( rTarget, rFilters ); diff --git a/sc/source/core/data/dpsave.cxx b/sc/source/core/data/dpsave.cxx index 100db65df4b7..24df9f90b31f 100644 --- a/sc/source/core/data/dpsave.cxx +++ b/sc/source/core/data/dpsave.cxx @@ -34,6 +34,7 @@ #include "dpsave.hxx" #include "dpdimsave.hxx" +#include "dpobject.hxx" // GetMemberNames used in BuildAllDimensionMembersFromSource #include "miscuno.hxx" #include "scerrors.hxx" #include "unonames.hxx" @@ -874,6 +875,7 @@ ScDPSaveDimension* ScDPSaveData::GetDimensionByName(const String& rName) } ScDPSaveDimension* pNew = new ScDPSaveDimension( rName, sal_False ); aDimList.Insert( pNew, LIST_APPEND ); + mbDimensionMembersBuilt = false; // BuildAllDimensionMembers only handles existing entries in aDimList return pNew; } @@ -900,6 +902,7 @@ ScDPSaveDimension* ScDPSaveData::GetNewDimensionByName(const String& rName) } ScDPSaveDimension* pNew = new ScDPSaveDimension( rName, sal_False ); aDimList.Insert( pNew, LIST_APPEND ); + mbDimensionMembersBuilt = false; // BuildAllDimensionMembers only handles existing entries in aDimList return pNew; } @@ -911,6 +914,7 @@ ScDPSaveDimension* ScDPSaveData::GetDataLayoutDimension() ScDPSaveDimension* pNew = new ScDPSaveDimension( String(), sal_True ); aDimList.Insert( pNew, LIST_APPEND ); + mbDimensionMembersBuilt = false; // BuildAllDimensionMembers only handles existing entries in aDimList return pNew; } @@ -935,6 +939,7 @@ ScDPSaveDimension* ScDPSaveData::DuplicateDimension(const String& rName) ScDPSaveDimension* pNew = new ScDPSaveDimension( *pOld ); pNew->SetDupFlag( sal_True ); aDimList.Insert( pNew, LIST_APPEND ); + mbDimensionMembersBuilt = false; // BuildAllDimensionMembers only handles existing entries in aDimList return pNew; } @@ -958,6 +963,7 @@ ScDPSaveDimension& ScDPSaveData::DuplicateDimension( const ScDPSaveDimension& rD ScDPSaveDimension* pNew = new ScDPSaveDimension( rDim ); pNew->SetDupFlag( sal_True ); aDimList.Insert( pNew, LIST_APPEND ); + mbDimensionMembersBuilt = false; // BuildAllDimensionMembers only handles existing entries in aDimList return *pNew; } @@ -1275,6 +1281,63 @@ void ScDPSaveData::BuildAllDimensionMembers(ScDPTableData* pData) mbDimensionMembersBuilt = true; } +void ScDPSaveData::BuildAllDimensionMembersFromSource( ScDPObject* pDPObj ) +{ + // Initialize all members like BuildAllDimensionMembers, but access only the DataPilotSource, not the table data. + // This could also replace BuildAllDimensionMembers, but the performance implications still have to be checked. + // ScDPObject is used for the helper method GetMemberNames. + + if (mbDimensionMembersBuilt) + return; + + uno::Reference<sheet::XDimensionsSupplier> xSource = pDPObj->GetSource(); + uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions(); + // GetMemberNames uses the dimension index from getElementNames + uno::Sequence<OUString> aDimNames = xDimsName->getElementNames(); + + // First, build a dimension name-to-index map. + typedef hash_map<OUString, long, ::rtl::OUStringHash> NameIndexMap; + NameIndexMap aMap; + long nColCount = aDimNames.getLength(); + for (long i = 0; i < nColCount; ++i) + aMap.insert( NameIndexMap::value_type(aDimNames[i], i) ); + + NameIndexMap::const_iterator itrEnd = aMap.end(); + + sal_uInt32 n = aDimList.Count(); + for (sal_uInt32 i = 0; i < n; ++i) + { + ScDPSaveDimension* pDim = static_cast<ScDPSaveDimension*>(aDimList.GetObject(i)); + const String& rDimName = pDim->GetName(); + if (!rDimName.Len()) + // empty dimension name. It must be data layout. + continue; + + NameIndexMap::const_iterator itr = aMap.find(rDimName); + if (itr == itrEnd) + // dimension name not in the data. This should never happen! + continue; + + long nDimIndex = itr->second; + uno::Sequence<OUString> aMemberNames; + pDPObj->GetMemberNames( nDimIndex, aMemberNames ); + sal_Int32 nMemberCount = aMemberNames.getLength(); + for (sal_Int32 j = 0; j < nMemberCount; ++j) + { + String aMemName = aMemberNames[j]; + if (pDim->GetExistingMemberByName(aMemName)) + // this member instance already exists. nothing to do. + continue; + + auto_ptr<ScDPSaveMember> pNewMember(new ScDPSaveMember(aMemName)); + pNewMember->SetIsVisible(true); + pDim->AddMember(pNewMember.release()); + } + } + + mbDimensionMembersBuilt = true; +} + bool ScDPSaveData::HasInvisibleMember(const OUString& rDimName) const { ScDPSaveDimension* pDim = GetExistingDimensionByName(rDimName); diff --git a/sc/source/core/data/dpsdbtab.cxx b/sc/source/core/data/dpsdbtab.cxx index f0e060e8cc7d..977be2e182a9 100644 --- a/sc/source/core/data/dpsdbtab.cxx +++ b/sc/source/core/data/dpsdbtab.cxx @@ -214,7 +214,7 @@ ScDatabaseDPData::ScDatabaseDPData( ScDocument* pDoc, const ScImportSourceDesc& rImport, long nCacheId /*=-1 */ ) : ScDPTableData(pDoc, rImport.GetCacheId( pDoc, nCacheId) ), - aCacheTable( pDoc, rImport.GetCacheId( pDoc, nCacheId)) + aCacheTable( pDoc, GetCacheId() ) // base class ID is initialized with the GetCacheId call above { } diff --git a/sc/source/core/data/dpshttab.cxx b/sc/source/core/data/dpshttab.cxx index 33ce84cc94c2..6c376209e035 100644 --- a/sc/source/core/data/dpshttab.cxx +++ b/sc/source/core/data/dpshttab.cxx @@ -67,7 +67,7 @@ ScSheetDPData::ScSheetDPData( ScDocument* pD, const ScSheetSourceDesc& rDesc , l pSpecial(NULL), bIgnoreEmptyRows( sal_False ), bRepeatIfEmpty(sal_False), - aCacheTable( pD, rDesc.GetCacheId( pD, nCacheId)) + aCacheTable( pD, GetCacheId() ) // base class ID is initialized with the GetCacheId call above { SCSIZE nEntryCount( aQuery.GetEntryCount()); pSpecial = new sal_Bool[nEntryCount]; @@ -291,12 +291,10 @@ sal_uLong ScSheetSourceDesc::CheckValidate( ScDocument* pDoc ) const ScRange aSrcRange( aSourceRange); if ( !pDoc ) return STR_ERR_DATAPILOTSOURCE; - for(sal_uInt16 i= aSrcRange.aStart.Col();i <= aSrcRange.aEnd.Col();i++) - { - if ( pDoc->IsBlockEmpty( aSrcRange.aStart.Tab(), - i, aSrcRange.aStart.Row(),i, aSrcRange.aStart.Row())) - return STR_PIVOT_FIRSTROWEMPTYERR; - } + + // #i116457# Empty column titles were allowed before 3.3, and might be useful for hidden columns with annotations. + // Be compatible with 3.2: Allow empty titles, create columns with empty names, hide them in the dialogs. + if( pDoc->IsBlockEmpty( aSrcRange.aStart.Tab(), aSrcRange.aStart.Col(), aSrcRange.aStart.Row()+1, aSrcRange.aEnd.Col(), aSrcRange.aEnd.Row() ) ) { return STR_PIVOT_ONLYONEROWERR; diff --git a/sc/source/core/data/dptablecache.cxx b/sc/source/core/data/dptablecache.cxx index 3cf40a7ab6dc..4a80f742769b 100644 --- a/sc/source/core/data/dptablecache.cxx +++ b/sc/source/core/data/dptablecache.cxx @@ -210,13 +210,13 @@ ScDPItemData::ScDPItemData( ScDocument* pDoc, SCROW nRow, sal_uInt16 nCol, sal_u 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( pDoc->GetNumberFormat( ScAddress( nCol, nRow, nDocTab ) ) ); + nFormat = pFormatter->GetType( nNumFormat ); aString = aDocStr; fValue = fVal; mbFlag |= MK_VAL|MK_DATA; - nNumFormat = pDoc->GetNumberFormat( ScAddress( nCol, nRow, nDocTab ) ); lcl_isDate( nFormat ) ? ( mbFlag |= MK_DATE ) : (mbFlag &= ~MK_DATE); } else if ( pDoc->HasData( nCol,nRow, nDocTab ) ) @@ -938,23 +938,28 @@ void ScDPTableDataCache::AddLabel(ScDPItemData *pData) //reset name if needed String strNewName = pData->aString; - sal_Bool bFound = sal_False; - long nIndex = 1; - do + + // #i116457# don't modify empty column titles + if ( strNewName.Len() ) { - for ( long i= mrLabelNames.size()-1; i>=0; i-- ) + sal_Bool bFound = sal_False; + long nIndex = 1; + do { - if( mrLabelNames[i]->aString == strNewName ) + for ( long i= mrLabelNames.size()-1; i>=0; i-- ) { - strNewName = pData->aString; - strNewName += String::CreateFromInt32( nIndex ); - nIndex ++ ; - bFound = sal_True; + if( mrLabelNames[i]->aString == strNewName ) + { + strNewName = pData->aString; + strNewName += String::CreateFromInt32( nIndex ); + nIndex ++ ; + bFound = sal_True; + } } + bFound = !bFound; } - bFound = !bFound; + while ( !bFound ); } - while ( !bFound ); pData->aString = strNewName; mrLabelNames.push_back( pData ); @@ -1021,10 +1026,15 @@ sal_uLong ScDPTableDataCache::GetNumberFormat( long nDim ) const { if ( nDim >= mnColumnCount ) return 0; - if ( mpTableDataValues[nDim].size()==0 ) - return 0; - else - return mpTableDataValues[nDim][0]->nNumFormat; + + // #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 diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx index 59abdcfd6b60..c3f8edbbc265 100644 --- a/sc/source/core/data/drwlayer.cxx +++ b/sc/source/core/data/drwlayer.cxx @@ -430,16 +430,20 @@ void ScDrawLayer::ScCopyPage( sal_uInt16 nOldPos, sal_uInt16 nNewPos, sal_Bool b SdrObject* pOldObject = aIter.Next(); while (pOldObject) { - // #116235# - SdrObject* pNewObject = pOldObject->Clone(); - //SdrObject* pNewObject = pOldObject->Clone( pNewPage, this ); - pNewObject->SetModel(this); - pNewObject->SetPage(pNewPage); - - pNewObject->NbcMove(Size(0,0)); - pNewPage->InsertObject( pNewObject ); - if (bRecording) - AddCalcUndo( new SdrUndoInsertObj( *pNewObject ) ); + // #i112034# do not copy internal objects (detective) and note captions + if ( pOldObject->GetLayer() != SC_LAYER_INTERN && !IsNoteCaption( pOldObject ) ) + { + // #116235# + SdrObject* pNewObject = pOldObject->Clone(); + //SdrObject* pNewObject = pOldObject->Clone( pNewPage, this ); + pNewObject->SetModel(this); + pNewObject->SetPage(pNewPage); + + pNewObject->NbcMove(Size(0,0)); + pNewPage->InsertObject( pNewObject ); + if (bRecording) + AddCalcUndo( new SdrUndoInsertObj( *pNewObject ) ); + } pOldObject = aIter.Next(); } diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 3b10e51355e8..83c5412d08c3 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -2,7 +2,7 @@ * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright 2000, 2010 Oracle and/or its affiliates. + * Copyright 2000, 2011 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * @@ -59,6 +59,7 @@ #include "sheetevents.hxx" #include "globstr.hrc" #include "segmenttree.hxx" +#include "dbcolect.hxx" #include <math.h> @@ -2487,8 +2488,22 @@ sal_uLong ScTable::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, double fS { if (nLastRow > nEndRow) nLastRow = nEndRow; - sal_uInt32 nThisHeight = mpRowHeights->getSumValue(nRow, nLastRow); - nHeight += static_cast<sal_uLong>(nThisHeight * fScale); + + // #i117315# can't use getSumValue, because individual values must be rounded + while (nRow <= nLastRow) + { + ScFlatUInt16RowSegments::RangeData aData; + if (!mpRowHeights->getRangeData(nRow, aData)) + return nHeight; // shouldn't happen + + SCROW nSegmentEnd = std::min( nLastRow, aData.mnRow2 ); + + // round-down a single height value, multiply resulting (pixel) values + sal_uLong nOneHeight = static_cast<sal_uLong>( aData.mnValue * fScale ); + nHeight += nOneHeight * ( nSegmentEnd + 1 - nRow ); + + nRow = nSegmentEnd + 1; + } } nRow = nLastRow + 1; } @@ -2772,6 +2787,19 @@ void ScTable::ShowRows(SCROW nRow1, SCROW nRow2, bool bShow) DecRecalcLevel(); } +sal_Bool ScTable::IsDataFiltered() const +{ + sal_Bool bAnyQuery = sal_False; + ScDBData* pDBData = pDocument->GetFilterDBAtTable(nTab); + if ( pDBData ) + { + ScQueryParam aParam; + pDBData->GetQueryParam( aParam ); + if ( aParam.GetEntry(0).bDoQuery ) + bAnyQuery = sal_True; + } + return bAnyQuery; +} void ScTable::SetColFlags( SCCOL nCol, sal_uInt8 nNewFlags ) { diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx index 5c7c872f6c64..ba68fa53b13f 100644 --- a/sc/source/core/data/table4.cxx +++ b/sc/source/core/data/table4.cxx @@ -2,7 +2,7 @@ * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright 2000, 2010 Oracle and/or its affiliates. + * Copyright 2000, 2011 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * @@ -78,6 +78,7 @@ #include "rangenam.hxx" #include "docpool.hxx" #include "progress.hxx" +#include "segmenttree.hxx" #include <math.h> @@ -198,7 +199,7 @@ void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, rMinDigits = 0; rListData = NULL; rCmd = FILL_SIMPLE; - if ( nScFillModeMouseModifier & KEY_MOD1 ) + if (( nScFillModeMouseModifier & KEY_MOD1 )||IsDataFiltered()) //i89232 return ; // Ctrl-Taste: Copy SCCOL nAddX; @@ -567,11 +568,14 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uLong nIMin = nIStart; sal_uLong nIMax = nIEnd; PutInOrder(nIMin,nIMax); - if (bVertical) - DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), IDF_AUTOFILL); - else - DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, IDF_AUTOFILL); - + sal_Bool bHasFiltered = IsDataFiltered(); + if (!bHasFiltered) //modify for i89232 + { + if (bVertical) + DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), IDF_AUTOFILL); + else + DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, IDF_AUTOFILL); + } sal_uLong nProgress = rProgress.GetState(); // @@ -617,7 +621,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, pNewPattern = NULL; } - if ( bVertical && nISrcStart == nISrcEnd ) + if ( bVertical && nISrcStart == nISrcEnd && !bHasFiltered ) { // Attribute komplett am Stueck setzen if (pNewPattern || pSrcPattern != pDocument->GetDefPattern()) @@ -635,37 +639,44 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, break; // Schleife abbrechen } - if ( pSrcPattern != aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) ) + if ( !RowFiltered(nRow) ) { - // Vorlage auch uebernehmen - //! am AttrArray mit ApplyPattern zusammenfassen ?? - if ( pStyleSheet ) - aCol[nCol].ApplyStyle( static_cast<SCROW>(nRow), *pStyleSheet ); + if ( bHasFiltered ) + DeleteArea(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), + static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), IDF_AUTOFILL); - // ApplyPattern statt SetPattern um alte MergeFlags stehenzulassen - if ( pNewPattern ) - aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pNewPattern ); - else - aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pSrcPattern ); - } + if ( pSrcPattern != aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) ) + { + // Vorlage auch uebernehmen + //! am AttrArray mit ApplyPattern zusammenfassen ?? + if ( pStyleSheet ) + aCol[nCol].ApplyStyle( static_cast<SCROW>(nRow), *pStyleSheet ); - if (nAtSrc==nISrcEnd) - { - if ( nAtSrc != nISrcStart ) - { // mehr als eine Source-Zelle - nAtSrc = nISrcStart; + // ApplyPattern statt SetPattern um alte MergeFlags stehenzulassen + if ( pNewPattern ) + aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pNewPattern ); + else + aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pSrcPattern ); + } + + if (nAtSrc==nISrcEnd) + { + if ( nAtSrc != nISrcStart ) + { // mehr als eine Source-Zelle + nAtSrc = nISrcStart; + bGetPattern = sal_True; + } + } + else if (bPositive) + { + ++nAtSrc; + bGetPattern = sal_True; + } + else + { + --nAtSrc; bGetPattern = sal_True; } - } - else if (bPositive) - { - ++nAtSrc; - bGetPattern = sal_True; - } - else - { - --nAtSrc; - bGetPattern = sal_True; } if (rInner == nIEnd) break; @@ -733,7 +744,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, { sal_uLong nSource = nISrcStart; double nDelta; - if ( nScFillModeMouseModifier & KEY_MOD1 ) + if (( nScFillModeMouseModifier & KEY_MOD1 )||bHasFiltered) //i89232 nDelta = 0.0; else if ( bPositive ) nDelta = 1.0; @@ -750,6 +761,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScBaseCell* pSrcCell = NULL; CellType eCellType = CELLTYPE_NONE; sal_Bool bIsOrdinalSuffix = sal_False; + sal_Bool bRowFiltered = sal_False; //i89232 rInner = nIStart; while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes @@ -775,7 +787,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ((ScStringCell*)pSrcCell)->GetString( aValue ); else ((ScEditCell*)pSrcCell)->GetString( aValue ); - if ( !(nScFillModeMouseModifier & KEY_MOD1) ) + if ( !(nScFillModeMouseModifier & KEY_MOD1) && !bHasFiltered) //i89232 { nCellDigits = 0; // look at each source cell individually nHeadNoneTail = lcl_DecompValueString( @@ -794,92 +806,101 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, else eCellType = CELLTYPE_NONE; } - switch (eCellType) + + //Modify for i89232 + bRowFiltered = mpFilteredRows->getValue(nRow); + + if (!bRowFiltered) { - case CELLTYPE_VALUE: - aCol[nCol].Insert(static_cast<SCROW>(nRow), new ScValueCell(nVal + nDelta)); - break; - case CELLTYPE_STRING: - case CELLTYPE_EDIT: - if ( nHeadNoneTail ) - { - // #i48009# with the "nStringValue+(long)nDelta" expression within the - // lcl_ValueString calls, gcc 3.4.1 makes wrong optimizations (ok in 3.4.3), - // so nNextValue is now calculated ahead. - sal_Int32 nNextValue = nStringValue+(sal_Int32)nDelta; + //End of i89232 - String aStr; - if ( nHeadNoneTail < 0 ) + switch (eCellType) + { + case CELLTYPE_VALUE: + aCol[nCol].Insert(static_cast<SCROW>(nRow), new ScValueCell(nVal + nDelta)); + break; + case CELLTYPE_STRING: + case CELLTYPE_EDIT: + if ( nHeadNoneTail ) { - aCol[nCol].Insert( static_cast<SCROW>(nRow), - lcl_getSuffixCell( pDocument, - nNextValue, nCellDigits, aValue, - eCellType, bIsOrdinalSuffix)); + // #i48009# with the "nStringValue+(long)nDelta" expression within the + // lcl_ValueString calls, gcc 3.4.1 makes wrong optimizations (ok in 3.4.3), + // so nNextValue is now calculated ahead. + sal_Int32 nNextValue = nStringValue+(sal_Int32)nDelta; + + String aStr; + if ( nHeadNoneTail < 0 ) + { + aCol[nCol].Insert( static_cast<SCROW>(nRow), + lcl_getSuffixCell( pDocument, + nNextValue, nCellDigits, aValue, + eCellType, bIsOrdinalSuffix)); + } + else + { + aStr = aValue; + aStr += lcl_ValueString( nNextValue, nCellDigits ); + aCol[nCol].Insert( static_cast<SCROW>(nRow), + new ScStringCell( aStr)); + } } else { - aStr = aValue; - aStr += lcl_ValueString( nNextValue, nCellDigits ); - aCol[nCol].Insert( static_cast<SCROW>(nRow), - new ScStringCell( aStr)); - } - } - else - { - ScAddress aDestPos( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), nTab ); - switch ( eCellType ) - { - case CELLTYPE_STRING: - case CELLTYPE_EDIT: - aCol[nCol].Insert( aDestPos.Row(), pSrcCell->CloneWithoutNote( *pDocument ) ); - break; - default: + ScAddress aDestPos( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), nTab ); + switch ( eCellType ) { - // added to avoid warnings + case CELLTYPE_STRING: + case CELLTYPE_EDIT: + aCol[nCol].Insert( aDestPos.Row(), pSrcCell->CloneWithoutNote( *pDocument ) ); + break; + default: + { + // added to avoid warnings + } } } + break; + case CELLTYPE_FORMULA : + FillFormula( nFormulaCounter, bFirst, + (ScFormulaCell*) pSrcCell, + static_cast<SCCOL>(nCol), + static_cast<SCROW>(nRow), (rInner == nIEnd) ); + if (nFormulaCounter - nActFormCnt > nMaxFormCnt) + nMaxFormCnt = nFormulaCounter - nActFormCnt; + break; + default: + { + // added to avoid warnings } - break; - case CELLTYPE_FORMULA : - FillFormula( nFormulaCounter, bFirst, - (ScFormulaCell*) pSrcCell, - static_cast<SCCOL>(nCol), - static_cast<SCROW>(nRow), (rInner == nIEnd) ); - if (nFormulaCounter - nActFormCnt > nMaxFormCnt) - nMaxFormCnt = nFormulaCounter - nActFormCnt; - break; - default: - { - // added to avoid warnings } - } - if (nSource==nISrcEnd) - { - if ( nSource != nISrcStart ) - { // mehr als eine Source-Zelle - nSource = nISrcStart; + if (nSource==nISrcEnd) + { + if ( nSource != nISrcStart ) + { // mehr als eine Source-Zelle + nSource = nISrcStart; + bGetCell = sal_True; + } + if ( !(nScFillModeMouseModifier & KEY_MOD1) && !bHasFiltered ) //i89232 + { + if ( bPositive ) + nDelta += 1.0; + else + nDelta -= 1.0; + } + nFormulaCounter = nActFormCnt; + bFirst = sal_False; + } + else if (bPositive) + { + ++nSource; bGetCell = sal_True; } - if ( !(nScFillModeMouseModifier & KEY_MOD1) ) + else { - if ( bPositive ) - nDelta += 1.0; - else - nDelta -= 1.0; + --nSource; + bGetCell = sal_True; } - nFormulaCounter = nActFormCnt; - bFirst = sal_False; - } - else if (bPositive) - { - ++nSource; - bGetCell = sal_True; - } - else - { - --nSource; - bGetCell = sal_True; } // Progress in der inneren Schleife nur bei teuren Zellen, @@ -978,6 +999,30 @@ String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW n } else if ( eFillCmd == FILL_SIMPLE ) // Auffuellen mit Muster { + //Add for i89232 + if ((eFillDir == FILL_TO_BOTTOM)||(eFillDir == FILL_TO_TOP)) + { + long nBegin = 0; + long nEnd = 0; + if (nEndY > nRow1) + { + nBegin = nRow2+1; + nEnd = nEndY; + } + else + { + nBegin = nEndY; + nEnd = nRow1 -1; + } + long nNonFiltered = CountNonFilteredRows(nBegin, nEnd); + long nFiltered = nEnd + 1 - nBegin - nNonFiltered; + if (nIndex >0) + nIndex = nIndex - nFiltered; + else + nIndex = nIndex + nFiltered; + } + //End of i89232 + long nPosIndex = nIndex; while ( nPosIndex < 0 ) nPosIndex += nSrcCount; @@ -1008,7 +1053,7 @@ String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW n ((ScStringCell*)pCell)->GetString( aValue ); else ((ScEditCell*)pCell)->GetString( aValue ); - if ( !(nScFillModeMouseModifier & KEY_MOD1) ) + if ( !(nScFillModeMouseModifier & KEY_MOD1) && !IsDataFiltered() ) //i89232 { sal_Int32 nVal; sal_uInt16 nCellDigits = 0; // look at each source cell individually @@ -1029,7 +1074,7 @@ String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW n { // dabei kann's keinen Ueberlauf geben... double nVal = ((ScValueCell*)pCell)->GetValue(); - if ( !(nScFillModeMouseModifier & KEY_MOD1) ) + if ( !(nScFillModeMouseModifier & KEY_MOD1) && !IsDataFiltered() ) //i89232 nVal += (double) nDelta; Color* pColor; diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx index 0ab37d167b01..0adef9f88348 100644 --- a/sc/source/core/inc/interpre.hxx +++ b/sc/source/core/inc/interpre.hxx @@ -696,6 +696,7 @@ double GetGamma(double x); double GetLogGamma(double x); double GetBeta(double fAlpha, double fBeta); double GetLogBeta(double fAlpha, double fBeta); +double GetBinomDistPMF(double x, double n, double p); //probability mass function void ScLogGamma(); void ScGamma(); void ScPhi(); diff --git a/sc/source/core/tool/address.cxx b/sc/source/core/tool/address.cxx index 26a194b731ef..e24a4ff4158e 100644 --- a/sc/source/core/tool/address.cxx +++ b/sc/source/core/tool/address.cxx @@ -1648,8 +1648,8 @@ void ScAddress::Format( String& r, sal_uInt16 nFlags, ScDocument* pDoc, // External Reference, same as in ScCompiler::MakeTabStr() if( aTabName.GetChar(0) == '\'' ) { // "'Doc'#Tab" - xub_StrLen nPos = ScGlobal::FindUnquoted( aTabName, SC_COMPILER_FILE_TAB_SEP); - if (nPos != STRING_NOTFOUND && nPos > 0 && aTabName.GetChar(nPos-1) == '\'') + xub_StrLen nPos = ScCompiler::GetDocTabPos( aTabName); + if (nPos != STRING_NOTFOUND) { aDocName = aTabName.Copy( 0, nPos + 1 ); aTabName.Erase( 0, nPos + 1 ); @@ -1731,8 +1731,8 @@ lcl_Split_DocTab( const ScDocument* pDoc, SCTAB nTab, // External reference, same as in ScCompiler::MakeTabStr() if ( rTabName.GetChar(0) == '\'' ) { // "'Doc'#Tab" - xub_StrLen nPos = ScGlobal::FindUnquoted( rTabName, SC_COMPILER_FILE_TAB_SEP); - if (nPos != STRING_NOTFOUND && nPos > 0 && rTabName.GetChar(nPos-1) == '\'') + xub_StrLen nPos = ScCompiler::GetDocTabPos( rTabName); + if (nPos != STRING_NOTFOUND) { rDocName = rTabName.Copy( 0, nPos + 1 ); rTabName.Erase( 0, nPos + 1 ); diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx index 3dd25801532f..31964eff34be 100644 --- a/sc/source/core/tool/compiler.cxx +++ b/sc/source/core/tool/compiler.cxx @@ -855,18 +855,14 @@ struct ConventionOOO_A1 : public Convention_A1 aString = ScGlobal::GetRscString(STR_NO_REF_TABLE); else { - if ( aString.GetChar(0) == '\'' ) - { // "'Doc'#Tab" - xub_StrLen nPos = ScGlobal::FindUnquoted( aString, SC_COMPILER_FILE_TAB_SEP); - if (nPos != STRING_NOTFOUND && nPos > 0 && aString.GetChar(nPos-1) == '\'') - { - aDoc = aString.Copy( 0, nPos + 1 ); - aString.Erase( 0, nPos + 1 ); - aDoc = INetURLObject::decode( aDoc, INET_HEX_ESCAPE, + // "'Doc'#Tab" + xub_StrLen nPos = ScCompiler::GetDocTabPos( aString); + if (nPos != STRING_NOTFOUND) + { + aDoc = aString.Copy( 0, nPos + 1 ); + aString.Erase( 0, nPos + 1 ); + aDoc = INetURLObject::decode( aDoc, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS ); - } - else - aDoc.Erase(); } else aDoc.Erase(); @@ -1203,18 +1199,15 @@ struct ConventionXL } // Cheesy hack to unparse the OOO style "'Doc'#Tab" - if ( rTabName.GetChar(0) == '\'' ) + xub_StrLen nPos = ScCompiler::GetDocTabPos( rTabName); + if (nPos != STRING_NOTFOUND) { - xub_StrLen nPos = ScGlobal::FindUnquoted( rTabName, SC_COMPILER_FILE_TAB_SEP); - if (nPos != STRING_NOTFOUND && nPos > 0 && rTabName.GetChar(nPos-1) == '\'') - { - rDocName = rTabName.Copy( 0, nPos ); - // TODO : More research into how XL escapes the doc path - rDocName = INetURLObject::decode( rDocName, INET_HEX_ESCAPE, + rDocName = rTabName.Copy( 0, nPos ); + // TODO : More research into how XL escapes the doc path + rDocName = INetURLObject::decode( rDocName, INET_HEX_ESCAPE, INetURLObject::DECODE_UNAMBIGUOUS ); - rTabName.Erase( 0, nPos + 1 ); - bHasDoc = true; - } + rTabName.Erase( 0, nPos + 1 ); + bHasDoc = true; } // XL uses the same sheet name quoting conventions in both modes @@ -1872,6 +1865,18 @@ void ScCompiler::CheckTabQuotes( String& rString, } } + +xub_StrLen ScCompiler::GetDocTabPos( const String& rString ) +{ + if (rString.GetChar(0) != '\'') + return STRING_NOTFOUND; + xub_StrLen nPos = ScGlobal::FindUnquoted( rString, SC_COMPILER_FILE_TAB_SEP); + // it must be 'Doc'# + if (nPos != STRING_NOTFOUND && rString.GetChar(nPos-1) != '\'') + nPos = STRING_NOTFOUND; + return nPos; +} + //--------------------------------------------------------------------------- void ScCompiler::SetRefConvention( FormulaGrammar::AddressConvention eConv ) diff --git a/sc/source/core/tool/dbcolect.cxx b/sc/source/core/tool/dbcolect.cxx index 800716bef3b6..baf2c3de8c2a 100644 --- a/sc/source/core/tool/dbcolect.cxx +++ b/sc/source/core/tool/dbcolect.cxx @@ -2,7 +2,7 @@ * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * - * Copyright 2000, 2010 Oracle and/or its affiliates. + * Copyright 2000, 2011 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * @@ -753,6 +753,27 @@ ScDBData* ScDBCollection::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCO return pNoNameData; // "unbenannt" nur zurueck, wenn sonst nichts gefunden } +ScDBData* ScDBCollection::GetFilterDBAtTable(SCTAB nTab) const +{ + ScDBData* pDataEmpty = NULL; + if (pItems) + { + for (sal_uInt16 i = 0; i < nCount; i++) + { + ScDBData* pDBTemp = (ScDBData*)pItems[i]; + if ( pDBTemp->nTable == nTab ) + { + sal_Bool bFilter = pDBTemp->HasAutoFilter() || pDBTemp->HasQueryParam(); + + if ( bFilter ) + return pDBTemp; + } + } + } + + return pDataEmpty; +} + sal_Bool ScDBCollection::SearchName( const String& rName, sal_uInt16& rIndex ) const { ScDBData aDataObj( rName, 0,0,0,0,0 ); diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index 7e015e12d16e..c507c3970bb1 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -653,6 +653,7 @@ double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOp if ( !rComp.bEmpty[1] && rComp.bVal[1] && !::rtl::math::isFinite( rComp.nVal[1])) return rComp.nVal[1]; + size_t nStringQuery = 0; // 0:=no, 1:=0, 2:=1 double fRes = 0; if ( rComp.bEmpty[ 0 ] ) { @@ -709,16 +710,22 @@ double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOp } } else - fRes = -1; // number is less than string + { + fRes = -1; // number is less than string + nStringQuery = 2; // 1+1 + } } else if( rComp.bVal[ 1 ] ) - fRes = 1; // number is less than string + { + fRes = 1; // string is greater than number + nStringQuery = 1; // 0+1 + } else { // Both strings. if (pOptions) { - // All similar to Sctable::ValidQuery(), *rComp.pVal[1] actually + // All similar to ScTable::ValidQuery(), *rComp.pVal[1] actually // is/must be identical to *rEntry.pStr, which is essential for // regex to work through GetSearchTextPtr(). ScQueryEntry& rEntry = pOptions->aQueryEntry; @@ -768,6 +775,20 @@ double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOp fRes = (double) ScGlobal::GetCaseCollator()->compareString( *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] ); } + if (nStringQuery && pOptions) + { + const ScQueryEntry& rEntry = pOptions->aQueryEntry; + if (!rEntry.bQueryByString && rEntry.pStr->Len() && + (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)) + { + // As in ScTable::ValidQuery() match a numeric string for a + // number query that originated from a string, e.g. in SUMIF + // and COUNTIF. Transliteration is not needed here. + bool bEqual = rComp.pVal[nStringQuery-1]->Equals( *rEntry.pStr); + // match => fRes=0, else fRes=1 + fRes = (rEntry.eOp == SC_NOT_EQUAL) ? bEqual : !bEqual; + } + } return fRes; } @@ -6223,7 +6244,7 @@ void ScInterpreter::ScDBVarP() } -ScTokenArray* lcl_CreateExternalRefTokenArray( const ScAddress& rPos, ScDocument* pDoc, +FormulaSubroutineToken* lcl_CreateExternalRefSubroutine( const ScAddress& rPos, ScDocument* pDoc, const ScAddress::ExternalInfo& rExtInfo, const ScRefAddress& rRefAd1, const ScRefAddress* pRefAd2 ) { @@ -6265,7 +6286,7 @@ ScTokenArray* lcl_CreateExternalRefTokenArray( const ScAddress& rPos, ScDocument rExtInfo.maTabName, nSheets); ScCompiler aComp( pDoc, rPos, *pTokenArray); aComp.CompileTokenArray(); - return pTokenArray; + return new FormulaSubroutineToken( pTokenArray); } @@ -6294,15 +6315,10 @@ void ScInterpreter::ScIndirect() { if (aExtInfo.mbExternal) { - /* TODO: future versions should implement a proper subroutine - * token. This procedure here is a minimally invasive fix for - * #i101645# in OOo3.1.1 */ - // Push a subroutine on the instruction code stack that - // resolves the external reference as the next instruction. - aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok, + // Push a subroutine that resolves the external reference as + // the next instruction. + PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, aExtInfo, aRefAd, &aRefAd2)); - // Signal subroutine call to interpreter. - PushTempToken( new FormulaUnknownToken( ocCall)); } else PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(), @@ -6314,15 +6330,10 @@ void ScInterpreter::ScIndirect() { if (aExtInfo.mbExternal) { - /* TODO: future versions should implement a proper subroutine - * token. This procedure here is a minimally invasive fix for - * #i101645# in OOo3.1.1 */ - // Push a subroutine on the instruction code stack that - // resolves the external reference as the next instruction. - aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok, + // Push a subroutine that resolves the external reference as + // the next instruction. + PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, aExtInfo, aRefAd, NULL)); - // Signal subroutine call to interpreter. - PushTempToken( new FormulaUnknownToken( ocCall)); } else PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() ); @@ -6441,9 +6452,27 @@ void ScInterpreter::ScAddressFunc() const ScAddress aAdr( nCol, nRow, 0); aAdr.Format( aRefStr, nFlags, pDok, aDetails ); - if( nParamCount >= 5 ) + if( nParamCount >= 5 && sTabStr.Len() ) { - ScCompiler::CheckTabQuotes( sTabStr, eConv); + String aDoc; + if (eConv == FormulaGrammar::CONV_OOO) + { + // Isolate Tab from 'Doc'#Tab + xub_StrLen nPos = ScCompiler::GetDocTabPos( sTabStr); + if (nPos != STRING_NOTFOUND) + { + if (sTabStr.GetChar(nPos+1) == '$') + ++nPos; // also split 'Doc'#$Tab + aDoc = sTabStr.Copy( 0, nPos+1); + sTabStr.Erase( 0, nPos+1); + } + } + /* TODO: yet unsupported external reference in CONV_XL_R1C1 syntax may + * need some extra handling to isolate Tab from Doc. */ + if (sTabStr.GetChar(0) != '\'' || sTabStr.GetChar(sTabStr.Len()-1) != '\'') + ScCompiler::CheckTabQuotes( sTabStr, eConv); + if (aDoc.Len()) + sTabStr.Insert( aDoc, 0); sTabStr += static_cast<sal_Unicode>(eConv == FormulaGrammar::CONV_XL_R1C1 ? '!' : '.'); sTabStr += aRefStr; PushString( sTabStr ); @@ -6453,6 +6482,24 @@ void ScInterpreter::ScAddressFunc() } +FormulaSubroutineToken* lcl_CreateExternalRefSubroutine( const ScAddress& rPos, + ScDocument* pDoc, const FormulaTokenRef& xExtRef ) +{ + // The exact usage (which cell range) of the external table can't be + // detected during the store-to-file cycle, mark it as permanently + // referenced so it gets stored even if not directly referenced anywhere. + ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); + pRefMgr->setCacheTableReferencedPermanently( + static_cast<const ScToken*>(xExtRef.get())->GetIndex(), + static_cast<const ScToken*>(xExtRef.get())->GetString(), 1); + ScTokenArray* pTokenArray = new ScTokenArray; + pTokenArray->AddToken( *xExtRef); + ScCompiler aComp( pDoc, rPos, *pTokenArray); + aComp.CompileTokenArray(); + return new FormulaSubroutineToken( pTokenArray); +} + + void ScInterpreter::ScOffset() { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOffset" ); @@ -6477,54 +6524,129 @@ void ScInterpreter::ScOffset() PushIllegalArgument(); return; } - if (GetStackType() == svSingleRef) - { - PopSingleRef(nCol1, nRow1, nTab1); - if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0)) - { - nCol1 = (SCCOL)((long) nCol1 + nColPlus); - nRow1 = (SCROW)((long) nRow1 + nRowPlus); - if (!ValidCol(nCol1) || !ValidRow(nRow1)) - PushIllegalArgument(); - else - PushSingleRef(nCol1, nRow1, nTab1); - } - else - { - if (nColNew < 0) - nColNew = 1; - if (nRowNew < 0) - nRowNew = 1; - nCol1 = (SCCOL)((long)nCol1+nColPlus); // ! nCol1 wird veraendert! - nRow1 = (SCROW)((long)nRow1+nRowPlus); - nCol2 = (SCCOL)((long)nCol1+nColNew-1); - nRow2 = (SCROW)((long)nRow1+nRowNew-1); - if (!ValidCol(nCol1) || !ValidRow(nRow1) || - !ValidCol(nCol2) || !ValidRow(nRow2)) - PushIllegalArgument(); - else - PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1); - } - } - else if (GetStackType() == svDoubleRef) + FormulaTokenRef xExtRef; + switch (GetStackType()) { - PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); - if (nColNew < 0) - nColNew = nCol2 - nCol1 + 1; - if (nRowNew < 0) - nRowNew = nRow2 - nRow1 + 1; - nCol1 = (SCCOL)((long)nCol1+nColPlus); - nRow1 = (SCROW)((long)nRow1+nRowPlus); - nCol2 = (SCCOL)((long)nCol1+nColNew-1); - nRow2 = (SCROW)((long)nRow1+nRowNew-1); - if (!ValidCol(nCol1) || !ValidRow(nRow1) || - !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2) - PushIllegalArgument(); - else - PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1); + case svExternalSingleRef: + xExtRef = PopToken()->Clone(); + // fallthru + case svSingleRef: + { + if (xExtRef) + { + ScSingleRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetSingleRef(); + rData.CalcAbsIfRel( aPos); + nCol1 = rData.nCol; + nRow1 = rData.nRow; + nTab1 = rData.nTab; + } + else + PopSingleRef( nCol1, nRow1, nTab1); + if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0)) + { + nCol1 = (SCCOL)((long) nCol1 + nColPlus); + nRow1 = (SCROW)((long) nRow1 + nRowPlus); + if (!ValidCol(nCol1) || !ValidRow(nRow1)) + PushIllegalArgument(); + else if (xExtRef) + { + ScSingleRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetSingleRef(); + rData.nCol = nCol1; + rData.nRow = nRow1; + rData.nTab = nTab1; + rData.CalcRelFromAbs( aPos); + // Push a subroutine that resolves the external + // reference as the next instruction. + PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef)); + } + else + PushSingleRef(nCol1, nRow1, nTab1); + } + else + { + if (nColNew < 0) + nColNew = 1; + if (nRowNew < 0) + nRowNew = 1; + nCol1 = (SCCOL)((long)nCol1+nColPlus); // ! nCol1 is modified + nRow1 = (SCROW)((long)nRow1+nRowPlus); + nCol2 = (SCCOL)((long)nCol1+nColNew-1); + nRow2 = (SCROW)((long)nRow1+nRowNew-1); + if (!ValidCol(nCol1) || !ValidRow(nRow1) || + !ValidCol(nCol2) || !ValidRow(nRow2)) + PushIllegalArgument(); + else if (xExtRef) + { + // Convert SingleRef to DoubleRef. + xExtRef = new ScExternalDoubleRefToken( + *static_cast<const ScExternalSingleRefToken*>(xExtRef.get())); + ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef(); + rData.Ref1.nCol = nCol1; + rData.Ref1.nRow = nRow1; + rData.Ref1.nTab = nTab1; + rData.Ref2.nCol = nCol2; + rData.Ref2.nRow = nRow2; + rData.Ref2.nTab = nTab1; + rData.CalcRelFromAbs( aPos); + // Push a subroutine that resolves the external + // reference as the next instruction. + PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef)); + } + else + PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1); + } + } + break; + case svExternalDoubleRef: + xExtRef = PopToken()->Clone(); + // fallthru + case svDoubleRef: + { + if (xExtRef) + { + ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef(); + rData.CalcAbsIfRel( aPos); + nCol1 = rData.Ref1.nCol; + nRow1 = rData.Ref1.nRow; + nTab1 = rData.Ref1.nTab; + nCol2 = rData.Ref2.nCol; + nRow2 = rData.Ref2.nRow; + nTab2 = rData.Ref2.nTab; + } + else + PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); + if (nColNew < 0) + nColNew = nCol2 - nCol1 + 1; + if (nRowNew < 0) + nRowNew = nRow2 - nRow1 + 1; + nCol1 = (SCCOL)((long)nCol1+nColPlus); + nRow1 = (SCROW)((long)nRow1+nRowPlus); + nCol2 = (SCCOL)((long)nCol1+nColNew-1); + nRow2 = (SCROW)((long)nRow1+nRowNew-1); + if (!ValidCol(nCol1) || !ValidRow(nRow1) || + !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2) + PushIllegalArgument(); + else if (xExtRef) + { + ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef(); + rData.Ref1.nCol = nCol1; + rData.Ref1.nRow = nRow1; + rData.Ref1.nTab = nTab1; + rData.Ref2.nCol = nCol2; + rData.Ref2.nRow = nRow2; + rData.Ref2.nTab = nTab1; + rData.CalcRelFromAbs( aPos); + // Push a subroutine that resolves the external + // reference as the next instruction. + PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef)); + } + else + PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1); + } + break; + default: + PushIllegalParameter(); } - else - PushIllegalParameter(); } } diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx index dfcce4c06c3f..ef1a18b65def 100644 --- a/sc/source/core/tool/interpr3.cxx +++ b/sc/source/core/tool/interpr3.cxx @@ -949,17 +949,18 @@ double ScInterpreter::GetBetaDistPDF(double fX, double fA, double fB) const double fLogDblMin = log( ::std::numeric_limits<double>::min()); double fLogY = (fX < 0.1) ? ::rtl::math::log1p(-fX) : log(0.5-fX+0.5); double fLogX = log(fX); - double fAm1 = fA-1.0; - double fBm1 = fB-1.0; + double fAm1LogX = (fA-1.0) * fLogX; + double fBm1LogY = (fB-1.0) * fLogY; double fLogBeta = GetLogBeta(fA,fB); // check whether parts over- or underflow - if ( fAm1 * fLogX < fLogDblMax && fAm1 * fLogX > fLogDblMin - && fBm1 * fLogY < fLogDblMax && fBm1* fLogY > fLogDblMin - && fLogBeta < fLogDblMax && fLogBeta > fLogDblMin ) + if ( fAm1LogX < fLogDblMax && fAm1LogX > fLogDblMin + && fBm1LogY < fLogDblMax && fBm1LogY > fLogDblMin + && fLogBeta < fLogDblMax && fLogBeta > fLogDblMin + && fAm1LogX + fBm1LogY < fLogDblMax && fAm1LogX + fBm1LogY > fLogDblMin) return pow(fX,fA-1.0) * pow(0.5-fX+0.5,fB-1.0) / GetBeta(fA,fB); else // need logarithm; // might overflow as a whole, but seldom, not worth to pre-detect it - return exp((fA-1.0)*fLogX + (fB-1.0)* fLogY - fLogBeta); + return exp( fAm1LogX + fBm1LogY - fLogBeta); } @@ -1226,121 +1227,106 @@ void ScInterpreter::ScVariationen2() } } -void ScInterpreter::ScB() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScB" ); - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 4 ) ) - return ; - if (nParamCount == 3) - { - double x = ::rtl::math::approxFloor(GetDouble()); - double p = GetDouble(); - double n = ::rtl::math::approxFloor(GetDouble()); - if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0) - PushIllegalArgument(); - else + +double ScInterpreter::GetBinomDistPMF(double x, double n, double p) +// used in ScB and ScBinomDist +// preconditions: 0.0 <= x <= n, 0.0 < p < 1.0; x,n integral although double { - double q = 1.0 - p; + double q = (0.5 - p) + 0.5; double fFactor = pow(q, n); - if (fFactor == 0.0) + if (fFactor <=::std::numeric_limits<double>::min()) { fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); + if (fFactor <= ::std::numeric_limits<double>::min()) + return GetBetaDistPDF(p, x+1.0, n-x+1.0)/(n+1.0); else { - sal_uLong max = (sal_uLong) (n - x); - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) + sal_uInt32 max = static_cast<sal_uInt32>(n - x); + for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++) fFactor *= (n-i)/(i+1)*q/p; - PushDouble(fFactor); + return fFactor; } } else { - sal_uLong max = (sal_uLong) x; - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) + sal_uInt32 max = static_cast<sal_uInt32>(x); + for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++) fFactor *= (n-i)/(i+1)*p/q; - PushDouble(fFactor); - } + return fFactor; } } - else if (nParamCount == 4) - { - double xe = GetDouble(); - double xs = GetDouble(); - double p = GetDouble(); - double n = GetDouble(); -// alter Stand 300-SC -// if ((xs < n) && (xe < n) && (p < 1.0)) -// { -// double Varianz = sqrt(n * p * (1.0 - p)); -// xs = fabs(xs - (n * p /* / 2.0 STE */ )); -// xe = fabs(xe - (n * p /* / 2.0 STE */ )); -//// STE double nVal = gauss((xs + 0.5) / Varianz) + gauss((xe + 0.5) / Varianz); -// double nVal = fabs(gauss(xs / Varianz) - gauss(xe / Varianz)); -// PushDouble(nVal); -// } - bool bIsValidX = ( 0.0 <= xs && xs <= xe && xe <= n); - if ( bIsValidX && 0.0 < p && p < 1.0 ) - { - double q = 1.0 - p; - double fFactor = pow(q, n); - if (fFactor == 0.0) - { - fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); - else + +double lcl_GetBinomDistRange(double n, double xs,double xe, + double fFactor /* q^n */, double p, double q) +//preconditions: 0.0 <= xs < xe <= n; xs,xe,n integral although double { - double fSum = 0.0; - sal_uLong max; - if (xe < (sal_uLong) n) - max = (sal_uLong) (n-xe)-1; - else - max = 0; - sal_uLong i; - for (i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*q/p; - if (xs < (sal_uLong) n) - max = (sal_uLong) (n-xs); - else - fSum = fFactor; - for (; i < max && fFactor > 0.0; i++) + sal_uInt32 i; + double fSum; + // skip summands index 0 to xs-1, start sum with index xs + sal_uInt32 nXs = static_cast<sal_uInt32>( xs ); + for (i = 1; i <= nXs && fFactor > 0.0; i++) + fFactor *= (n-i+1)/i * p/q; + fSum = fFactor; // Summand xs + sal_uInt32 nXe = static_cast<sal_uInt32>(xe); + for (i = nXs+1; i <= nXe && fFactor > 0.0; i++) { - fFactor *= (n-i)/(i+1)*q/p; + fFactor *= (n-i+1)/i * p/q; fSum += fFactor; } - PushDouble(fSum); + return (fSum>1.0) ? 1.0 : fSum; } + +void ScInterpreter::ScB() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScB" ); + sal_uInt8 nParamCount = GetByte(); + if ( !MustHaveParamCount( nParamCount, 3, 4 ) ) + return ; + if (nParamCount == 3) // mass function + { + double x = ::rtl::math::approxFloor(GetDouble()); + double p = GetDouble(); + double n = ::rtl::math::approxFloor(GetDouble()); + if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0) + PushIllegalArgument(); + else + if (p == 0.0) + PushDouble( (x == 0.0) ? 1.0 : 0.0 ); + else + if ( p == 1.0) + PushDouble( (x == n) ? 1.0 : 0.0); + else + PushDouble(GetBinomDistPMF(x,n,p)); } else + { // nParamCount == 4 + double xe = ::rtl::math::approxFloor(GetDouble()); + double xs = ::rtl::math::approxFloor(GetDouble()); + double p = GetDouble(); + double n = ::rtl::math::approxFloor(GetDouble()); + double q = (0.5 - p) + 0.5; + bool bIsValidX = ( 0.0 <= xs && xs <= xe && xe <= n); + if ( bIsValidX && 0.0 < p && p < 1.0) { - sal_uLong max; - double fSum; - if ( (sal_uLong) xs == 0) + if (xs == xe) // mass function + PushDouble(GetBinomDistPMF(xs,n,p)); + else { - fSum = fFactor; - max = 0; - } + double fFactor = pow(q, n); + if (fFactor > ::std::numeric_limits<double>::min()) + PushDouble(lcl_GetBinomDistRange(n,xs,xe,fFactor,p,q)); else { - max = (sal_uLong) xs-1; - fSum = 0.0; + fFactor = pow(p, n); + if (fFactor > ::std::numeric_limits<double>::min()) + { + // sum from j=xs to xe {(n choose j) * p^j * q^(n-j)} + // = sum from i = n-xe to n-xs { (n choose i) * q^i * p^(n-i)} + PushDouble(lcl_GetBinomDistRange(n,n-xe,n-xs,fFactor,q,p)); } - sal_uLong i; - for (i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*p/q; - if ((sal_uLong)xe == 0) // beide 0 - fSum = fFactor; else - max = (sal_uLong) xe; - for (; i < max && fFactor > 0.0; i++) - { - fFactor *= (n-i)/(i+1)*p/q; - fSum += fFactor; + PushDouble(GetBetaDist(q,n-xe,xe+1.0)-GetBetaDist(q,n-xs+1,xs) ); } - PushDouble(fSum); } } else @@ -1365,77 +1351,63 @@ void ScInterpreter::ScBinomDist() RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBinomDist" ); if ( MustHaveParamCount( GetByte(), 4 ) ) { - double kum = GetDouble(); // 0 oder 1 - double p = GetDouble(); // p - double n = ::rtl::math::approxFloor(GetDouble()); // n - double x = ::rtl::math::approxFloor(GetDouble()); // x - double fFactor, q, fSum; + bool bIsCum = GetBool(); // false=mass function; true=cumulative + double p = GetDouble(); + double n = ::rtl::math::approxFloor(GetDouble()); + double x = ::rtl::math::approxFloor(GetDouble()); + double q = (0.5 - p) + 0.5; // get one bit more for p near 1.0 + double fFactor, fSum; if (n < 0.0 || x < 0.0 || x > n || p < 0.0 || p > 1.0) - PushIllegalArgument(); - else if (kum == 0.0) // Dichte { - q = 1.0 - p; - fFactor = pow(q, n); - if (fFactor == 0.0) - { - fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); - else - { - sal_uLong max = (sal_uLong) (n - x); - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*q/p; - PushDouble(fFactor); - } + PushIllegalArgument(); + return; } - else + if ( p == 0.0) { - sal_uLong max = (sal_uLong) x; - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) - fFactor *= (n-i)/(i+1)*p/q; - PushDouble(fFactor); + PushDouble( (x==0.0 || bIsCum) ? 1.0 : 0.0 ); + return; } + if ( p == 1.0) + { + PushDouble( (x==n) ? 1.0 : 0.0); + return; } - else // Verteilung + if (!bIsCum) + PushDouble( GetBinomDistPMF(x,n,p)); + else { - if (n == x) + if (x == n) PushDouble(1.0); else { - q = 1.0 - p; fFactor = pow(q, n); - if (fFactor == 0.0) + if (x == 0.0) + PushDouble(fFactor); + else + if (fFactor <= ::std::numeric_limits<double>::min()) { fFactor = pow(p, n); - if (fFactor == 0.0) - PushNoValue(); + if (fFactor <= ::std::numeric_limits<double>::min()) + PushDouble(GetBetaDist(q,n-x,x+1.0)); else { + if (fFactor > fMachEps) + { fSum = 1.0 - fFactor; - sal_uLong max = (sal_uLong) (n - x) - 1; - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) + sal_uInt32 max = static_cast<sal_uInt32> (n - x) - 1; + for (sal_uInt32 i = 0; i < max && fFactor > 0.0; i++) { fFactor *= (n-i)/(i+1)*q/p; fSum -= fFactor; } - if (fSum < 0.0) - PushDouble(0.0); - else - PushDouble(fSum); - } + PushDouble( (fSum < 0.0) ? 0.0 : fSum ); } else - { - fSum = fFactor; - sal_uLong max = (sal_uLong) x; - for (sal_uLong i = 0; i < max && fFactor > 0.0; i++) - { - fFactor *= (n-i)/(i+1)*p/q; - fSum += fFactor; + PushDouble(lcl_GetBinomDistRange(n,n-x,n,fFactor,q,p)); } - PushDouble(fSum); } + else + PushDouble( lcl_GetBinomDistRange(n,0.0,x,fFactor,p,q)) ; } } } diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx index e3cd6239191e..439e0375a8b9 100755 --- a/sc/source/core/tool/interpr4.cxx +++ b/sc/source/core/tool/interpr4.cxx @@ -3181,6 +3181,14 @@ void ScInterpreter::ScColRowNameAuto() void ScInterpreter::ScExternalRef() { + const FormulaToken* pNextOp = aCode.PeekNextOperator(); + if (pNextOp && pNextOp->GetOpCode() == ocOffset) + { + // Handled by OFFSET function. + PushTempToken( *pCur); + return; + } + ScExternalRefManager* pRefMgr = pDok->GetExternalRefManager(); const String* pFile = pRefMgr->getExternalFileName(pCur->GetIndex()); if (!pFile) @@ -3324,6 +3332,21 @@ void ScInterpreter::GlobalExit() // static } +// A ::std::vector<FormulaTokenRef> is not possible, a push_back() attempts to +// use a FormulaToken(const FormulaTokenRef&) ctor. Reinvent wheel.. +struct FormulaTokenRefPtr +{ + FormulaToken* mp; + FormulaTokenRefPtr() : mp(0) {} + FormulaTokenRefPtr( FormulaToken* p ) : mp(p) { if (mp) mp->IncRef(); } + FormulaTokenRefPtr( const FormulaTokenRefPtr & r ) : mp(r.mp) { if (mp) mp->IncRef(); } + ~FormulaTokenRefPtr() { if (mp) mp->DecRef(); } + FormulaTokenRefPtr& operator=( const FormulaTokenRefPtr & r ) + { if (r.mp) r.mp->IncRef(); if (mp) mp->DecRef(); mp = r.mp; return *this; } +}; +typedef ::std::vector< FormulaTokenRefPtr > FormulaTokenDtor; + + StackVar ScInterpreter::Interpret() { RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Interpret" ); @@ -3342,6 +3365,7 @@ StackVar ScInterpreter::Interpret() pJumpMatrix = NULL; glSubTotal = sal_False; ScTokenMatrixMap::const_iterator aTokenMatrixMapIter; + ::boost::scoped_ptr< FormulaTokenDtor > pTokenDtor; // Once upon a time we used to have FP exceptions on, and there was a // Windows printer driver that kept switching off exceptions, so we had to @@ -3724,13 +3748,27 @@ StackVar ScInterpreter::Interpret() default : PushError( errUnknownOpCode); break; } - // If the function signalled that it pushed a subroutine on the - // instruction code stack instead of a result, continue with + // If the function pushed a subroutine as result, continue with // execution of the subroutine. - if (sp > nStackBase && pStack[sp-1]->GetOpCode() == ocCall) + if (sp > nStackBase && pStack[sp-1]->GetOpCode() == ocCall && pStack[sp-1]->GetType() == svSubroutine) { - Pop(); - continue; // while( ( pCur = aCode.Next() ) != NULL ... + FormulaTokenRef xTok = PopToken(); + const FormulaSubroutineToken* pSub = dynamic_cast<FormulaSubroutineToken*>(xTok.get()); + if (pSub) + { + // Remember token for late destruction. + if (!pTokenDtor) + pTokenDtor.reset( new FormulaTokenDtor); + pTokenDtor->push_back( FormulaTokenDtor::value_type( xTok)); + // Continue with execution of subroutine. + aCode.Push( pSub->GetTokenArray()); + continue; // while( ( pCur = aCode.Next() ) != NULL ... + } + else + { + DBG_ERRORFILE( "ScInterpreter::Interpret: ocCall svSubroutine, but no FormulaSubroutineToken?!?"); + PushError( errNoCode); + } } // Remember result matrix in case it could be reused. diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index a270969e100c..83ee5d365e63 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -561,6 +561,9 @@ sal_Bool ScToken::Is3DRef() const if ( GetSingleRef().IsFlag3D() ) return sal_True; break; + case svExternalSingleRef: + case svExternalDoubleRef: + return sal_True; default: { // added to avoid warnings @@ -922,6 +925,14 @@ ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalDoubleRefTok { } +ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalSingleRefToken& r ) : + ScToken( svExternalDoubleRef, ocExternalRef), + mnFileId( r.GetIndex()), + maTabName( r.GetString()) +{ + maDoubleRef.Ref1 = maDoubleRef.Ref2 = r.GetSingleRef(); +} + ScExternalDoubleRefToken::~ScExternalDoubleRefToken() { } @@ -1825,6 +1836,20 @@ void ScTokenArray::ReadjustRelative3DReferences( const ScAddress& rOldPos, } } break; + case svExternalDoubleRef: + { + ScSingleRefData& rRef2 = static_cast<ScToken*>(pCode[j])->GetSingleRef2(); + rRef2.CalcAbsIfRel( rOldPos ); + rRef2.CalcRelFromAbs( rNewPos ); + } + //! fallthru + case svExternalSingleRef: + { + ScSingleRefData& rRef1 = static_cast<ScToken*>(pCode[j])->GetSingleRef(); + rRef1.CalcAbsIfRel( rOldPos ); + rRef1.CalcRelFromAbs( rNewPos ); + } + break; default: { // added to avoid warnings |