usingnamespace com::sun::star; using ::std::vector; using ::std::shared_ptr; using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::uno::Any; using ::com::sun::star::uno::Exception; using ::com::sun::star::lang::XComponent; using ::com::sun::star::sheet::DataPilotTableHeaderData; using ::com::sun::star::sheet::DataPilotTablePositionData; using ::com::sun::star::sheet::XDimensionsSupplier; using ::com::sun::star::beans::XPropertySet;
try
{ double fValue = 0.0; switch (nType)
{ case sdbc::DataType::BIT: case sdbc::DataType::BOOLEAN:
{
rNumType = SvNumFormatType::LOGICAL;
fValue = mxRow->getBoolean(nCol+1) ? 1 : 0;
rData.SetValue(fValue); 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:
{ //TODO: do the conversion here?
fValue = mxRow->getDouble(nCol+1);
rData.SetValue(fValue); break;
} case sdbc::DataType::DATE:
{
rNumType = SvNumFormatType::DATE;
if (rOther.mpSaveData)
mpSaveData.reset(new ScDPSaveData(*rOther.mpSaveData)); if (rOther.mpSheetDescription)
mpSheetDescription.reset(new ScSheetSourceDesc(*rOther.mpSheetDescription)); if (rOther.mpImportDescription)
mpImportDescription.reset(new ScImportSourceDesc(*rOther.mpImportDescription)); if (rOther.mpServiceDescription)
mpServiceDescription.reset(new ScDPServiceDesc(*rOther.mpServiceDescription));
} return *this;
}
void ScDPObject::EnableGetPivotData(bool b)
{
mbEnableGetPivotData = b;
}
bool ScDPObject::IsDataDescriptionCell(const ScAddress& rPos)
{ if (!mpSaveData) returnfalse;
tools::Long nDataDimCount = mpSaveData->GetDataDimensionCount(); if (nDataDimCount != 1) // There has to be exactly one data dimension for the description to // appear at top-left corner. returnfalse;
voidoperator() (const std::unique_ptr<ScDPObject>& rObj)
{ const ScRange& rRange = rObj->GetOutRange(); if (mnTab != rRange.aStart.Tab()) // Not on this sheet. return;
if (mpImportDescription)
{ // database data const ScDPCache* pCache = mpImportDescription->CreateCache(pDimData); if (pCache)
{
pCache->AddReference(this);
pData = std::make_shared<ScDatabaseDPData>(mpDocument, *pCache);
}
} else
{ // cell data if (!mpSheetDescription)
{
OSL_FAIL("no source descriptor");
mpSheetDescription.reset(new ScSheetSourceDesc(mpDocument)); // dummy defaults
}
{ // Temporarily disable GETPIVOTDATA to avoid having // GETPIVOTDATA called onto itself from within the source // range.
DisableGetPivotData aSwitch(*this, mbEnableGetPivotData); const ScDPCache* pCache = mpSheetDescription->CreateCache(pDimData); if (pCache)
{
pCache->AddReference(this);
pData = std::make_shared<ScSheetDPData>(mpDocument, *mpSheetDescription, *pCache);
}
}
}
// grouping (for cell or database data) if (pData && pDimData)
{ auto pGroupData = std::make_shared<ScDPGroupTableData>(pData, mpDocument);
pDimData->WriteToData(*pGroupData);
pData = pGroupData;
}
mpTableData = std::move(pData); // after SetCacheId
}
return mpTableData.get();
}
void ScDPObject::CreateObjects()
{ if (!mxSource.is())
{
mpOutput.reset(); // not valid when mxSource is changed
if (mpServiceDescription)
{
mxSource = CreateSource(*mpServiceDescription);
}
if (!mxSource.is()) // database or sheet data, or error in CreateSource
{
OSL_ENSURE(!mpServiceDescription, "DPSource could not be created");
ScDPTableData* pData = GetTableData(); if (pData)
{ if (mpSaveData) // Make sure to transfer these flags to the table data // since they may have changed.
pData->SetEmptyFlags(mpSaveData->GetIgnoreEmptyRows(), mpSaveData->GetRepeatIfEmpty());
pData->ReloadCacheTable();
mxSource = new ScDPSource( pData );
}
}
if (mpSaveData)
mpSaveData->WriteToSource(mxSource);
} elseif (mbSettingsChanged)
{
mpOutput.reset(); // not valid when mxSource is changed
uno::Reference<util::XRefreshable> xRef(mxSource, uno::UNO_QUERY); if (xRef.is())
{ try
{
xRef->refresh();
} catch(uno::Exception&)
{
TOOLS_WARN_EXCEPTION( "sc", "exception in refresh");
}
}
if (mpSaveData)
mpSaveData->WriteToSource(mxSource);
}
mbSettingsChanged = false;
}
if (!mpTableData) // Table data not built yet. No need to reload the group data. return;
if (!mpSaveData) // How could it not have the save data... but whatever. return;
const ScDPDimensionSaveData* pDimData = mpSaveData->GetExistingDimensionData(); if (!pDimData || !pDimData->HasGroupDimensions())
{ // No group dimensions exist. Check if it currently has group // dimensions, and if so, remove all of them.
ScDPGroupTableData* pData = dynamic_cast<ScDPGroupTableData*>(mpTableData.get()); if (pData)
{ // Replace the existing group table data with the source data.
mpTableData = pData->GetSourceTableData();
} return;
}
ScDPGroupTableData* pData = dynamic_cast<ScDPGroupTableData*>(mpTableData.get()); if (pData)
{ // This is already a group table data. Salvage the source data and // re-create a new group data. const shared_ptr<ScDPTableData>& pSource = pData->GetSourceTableData(); auto pGroupData = std::make_shared<ScDPGroupTableData>(pSource, mpDocument);
pDimData->WriteToData(*pGroupData);
mpTableData = pGroupData;
} else
{ // This is a source data. Create a group data based on it. auto pGroupData = std::make_shared<ScDPGroupTableData>(mpTableData, mpDocument);
pDimData->WriteToData(*pGroupData);
mpTableData = pGroupData;
}
ScRange ScDPObject::GetNewOutputRange( bool& rOverflow )
{
CreateOutput(); // create mxSource and mpOutput if not already done
rOverflow = mpOutput->HasError(); // range overflow or exception from source if ( rOverflow ) return ScRange(maOutputRange.aStart); else
{ // don't store the result in maOutputRange, because nothing has been output yet return mpOutput->GetOutputRange();
}
}
CreateOutput(); // create mxSource and mpOutput if not already done
mpOutput->SetPosition( rPos );
mpOutput->Output();
// maOutputRange is always the range that was last output to the document
maOutputRange = mpOutput->GetOutputRange(); const ScAddress& s = maOutputRange.aStart; const ScAddress& e = maOutputRange.aEnd;
mpDocument->ApplyFlagsTab(s.Col(), s.Row(), e.Col(), e.Row(), s.Tab(), ScMF::DpTable);
}
void ScDPObject::RefreshAfterLoad()
{ // apply drop-down attribute, initialize mnHeaderRows, without accessing the source // (button attribute must be present)
// simple test: block of button cells at the top, followed by an empty cell
bool ScDPObject::SyncAllDimensionMembers()
{ if (!mpSaveData) returnfalse;
// #i111857# don't always create empty mpTableData for external service. // Ideally, mxSource should be used instead of mpTableData. if (mpServiceDescription) returnfalse;
ScDPTableData* pData = GetTableData(); if (!pData) // No table data exists. This can happen when refreshing from an // external source which doesn't exist. returnfalse;
// Refresh the cache wrapper since the cache may have changed.
pData->SetEmptyFlags(mpSaveData->GetIgnoreEmptyRows(), mpSaveData->GetRepeatIfEmpty());
pData->ReloadCacheTable();
mpSaveData->SyncAllDimensionMembers(pData); returntrue;
}
const OUString& rRangeName = mpSheetDescription->GetRangeName(); if (!rRangeName.isEmpty()) // Source range is a named range. No need to update. return;
if (mpSheetDescription && rOther.mpSheetDescription)
{ if (mpSheetDescription->GetSourceRange() != rOther.mpSheetDescription->GetSourceRange()) returnfalse;
} elseif (mpSheetDescription || rOther.mpSheetDescription)
{
OSL_FAIL("RefsEqual: SheetDesc set at only one object"); returnfalse;
}
returntrue;
}
void ScDPObject::WriteRefsTo(ScDPObject& rObject) const
{
rObject.SetOutRange(maOutputRange); if (mpSheetDescription)
rObject.SetSheetDesc(*mpSheetDescription);
}
vector<sheet::DataPilotFieldFilter> aFilters; if (!mpOutput->GetDataResultPositionData(aFilters, rPos)) returnfalse;
sal_Int32 n = static_cast<sal_Int32>(aFilters.size());
rFilters.realloc(n); auto pFilters = rFilters.getArray(); for (sal_Int32 i = 0; i < n; ++i)
pFilters[i] = aFilters[i];
uno::Reference<sheet::XDataPilotResults> xDPResults(mxSource, uno::UNO_QUERY); if (!xDPResults.is()) return std::numeric_limits<double>::quiet_NaN();
// Dimensions must be sorted in order of appearance, and row dimensions // must come before column dimensions.
std::sort(rFilters.begin(), rFilters.end(), LessByDimOrder(mpSaveData->GetDimensionSortOrder()));
size_t n = rFilters.size();
uno::Sequence<sheet::DataPilotFieldFilter> aFilters(n); auto aFiltersRange = asNonConstRange(aFilters); for (size_t i = 0; i < n; ++i)
aFiltersRange[i] = rFilters[i];
uno::Sequence<double> aRes = xDPResults->getFilteredResults(aFilters); if (nDataIndex >= o3tl::make_unsigned(aRes.getLength())) return std::numeric_limits<double>::quiet_NaN();
return aRes[nDataIndex];
}
bool ScDPObject::IsFilterButton( const ScAddress& rPos )
{
CreateOutput(); // create mxSource and mpOutput if not already done
return mpOutput->IsFilterButton( rPos );
}
tools::Long ScDPObject::GetHeaderDim( const ScAddress& rPos, sheet::DataPilotFieldOrientation& rOrient )
{
CreateOutput(); // create mxSource and mpOutput if not already done
return mpOutput->GetHeaderDim( rPos, rOrient );
}
bool ScDPObject::GetHeaderDrag( const ScAddress& rPos, bool bMouseLeft, bool bMouseTop, tools::Long nDragDim,
tools::Rectangle& rPosRect, sheet::DataPilotFieldOrientation& rOrient, tools::Long& rDimPos )
{
CreateOutput();// create mxSource and mpOutput if not already done
void ScDPObject::GetMemberResultNames(ScDPUniqueStringSet& rNames, tools::Long nDimension)
{
CreateOutput();// create mxSource and mpOutput if not already done
mpOutput->GetMemberResultNames(rNames, nDimension); // used only with table data -> level not needed
}
if (nStartPos < nListLen && rList[nStartPos] == '\'') // quoted within the brackets?
{ if ( dequote( rList, nStartPos, nQuoteEnd, aDequoted ) )
{ // after the quoted string, there must be the closing bracket, optionally preceded by spaces, // and/or a function name while (nQuoteEnd < nListLen && rList[nQuoteEnd] == ' ')
++nQuoteEnd;
// semicolon separates function name if (nQuoteEnd < nListLen && rList[nQuoteEnd] == ';' && pFunc)
{
sal_Int32 nFuncEnd = 0; if ( parseFunction( rList, nQuoteEnd + 1, nFuncEnd, *pFunc ) )
nQuoteEnd = nFuncEnd;
} if (nQuoteEnd < nListLen && rList[nQuoteEnd] == ']')
{
++nQuoteEnd; // include the closing bracket for the matched length
bParsed = true;
}
}
} else
{ // implicit quoting to the closing bracket
// field name has to be followed by item name in brackets if (aRemaining.startsWith("["))
{
bHasFieldName = true; // bUsed remains false - still need the item
} else
{
bUsed = true;
bError = true;
}
}
}
}
OUString aQueryValue = aQueryValueName; if (mpTableData)
{
ScInterpreterContext& rContext = mpTableData->GetCacheTable().getCache().GetInterpreterContext(); // Parse possible number from aQueryValueName and format // locale independent as aQueryValue.
sal_uInt32 nNumFormat = 0; double fValue; if (rContext.NFIsNumberFormat(aQueryValueName, nNumFormat, fValue))
aQueryValue = ScDPCache::GetLocaleIndependentFormattedString(fValue, rContext, nNumFormat);
}
for ( SCSIZE nField=0; nField<nFieldCount; nField++ )
{ // If a field name is given, look in that field only, otherwise in all fields. // aSpecField is initialized from aFieldNames array, so exact comparison can be used. if ( !bHasFieldName || aFieldNames[nField] == aSpecField )
{ const uno::Sequence<OUString>& rItemNames = aFieldValueNames[nField]; const uno::Sequence<OUString>& rItemValues = aFieldValues[nField];
sal_Int32 nItemCount = rItemNames.getLength();
assert(nItemCount == rItemValues.getLength()); const OUString* pItemNamesArr = rItemNames.getConstArray(); const OUString* pItemValuesArr = rItemValues.getConstArray(); for ( sal_Int32 nItem=0; nItem<nItemCount; nItem++ )
{ bool bThisItemFound; if (bHasQuery)
{ // First check given value name against both.
bThisItemFound = ScGlobal::GetTransliteration().isEqual(
aQueryValueName, pItemNamesArr[nItem]); if (!bThisItemFound && pItemValuesArr[nItem] != pItemNamesArr[nItem])
bThisItemFound = ScGlobal::GetTransliteration().isEqual(
aQueryValueName, pItemValuesArr[nItem]); if (!bThisItemFound && aQueryValueName != aQueryValue)
{ // Second check locale independent value // against both. /* TODO: or check only value string against
* value string, not against the value name? */
bThisItemFound = ScGlobal::GetTransliteration().isEqual(
aQueryValue, pItemNamesArr[nItem]); if (!bThisItemFound && pItemValuesArr[nItem] != pItemNamesArr[nItem])
bThisItemFound = ScGlobal::GetTransliteration().isEqual(
aQueryValue, pItemValuesArr[nItem]);
}
} else
{
bThisItemFound = isAtStart( aRemaining, pItemNamesArr[nItem], nMatched, false, &eFunc ); if (!bThisItemFound && pItemValuesArr[nItem] != pItemNamesArr[nItem])
bThisItemFound = isAtStart( aRemaining, pItemValuesArr[nItem], nMatched, false, &eFunc ); /* TODO: this checks only the given value name, *checkalsolocaleindependentvalue.Butwe'd *havetodothatineachiterationoftheloop *insideisAtStart()sinceaquerycouldnotbe *extractedandamatchcouldbeonthepassed *itemvaluenamestringoritemvaluestring
* starting at aRemaining. */
} if (bThisItemFound)
{ if ( bItemFound )
bError = true; // duplicate (also across fields) else
{
aFoundName = aFieldNames[nField];
aFoundValueName = pItemNamesArr[nItem];
aFoundValue = pItemValuesArr[nItem];
eFoundFunc = eFunc;
bItemFound = true;
bUsed = true;
}
}
}
}
}
// remove any number of spaces between entries
aRemaining = comphelper::string::stripStart(aRemaining, ' ');
}
if ( !bError && !bHasData && aDataNames.size() == 1 )
{ // if there's only one data field, its name need not be specified
rDataFieldName = aDataNames[0];
bHasData = true;
}
return bHasData && !bError;
}
void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPObject* pDestObj)
{
CreateObjects(); // create mxSource if not already done
uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY ); bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
SC_UNO_DP_ISDATALAYOUT ); if (bDataLayout)
{ // the elements of the data layout dimension can't be found by their names // -> don't change anything return;
}
if ( xDimProp.is() && nDimOrient == nOrient )
{ // Let's take this dimension.
// function mask.
PivotFunc nMask = PivotFunc::NONE; if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
{
sal_Int16 eFunc = ScUnoHelpFunctions::GetShortProperty(
xDimProp, SC_UNO_DP_FUNCTION2,
sheet::GeneralFunction2::NONE ); if ( eFunc == sheet::GeneralFunction2::AUTO )
{ //TODO: test for numeric data
eFunc = sheet::GeneralFunction2::SUM;
}
nMask = ScDataPilotConversion::FunctionBit(eFunc);
} else
nMask = lcl_FirstSubTotal( xDimProp ); // from first hierarchy
// is this data layout dimension? bool bDataLayout = ScUnoHelpFunctions::GetBoolProperty(
xDimProp, SC_UNO_DP_ISDATALAYOUT);
// is this dimension cloned?
tools::Long nDupSource = -1; try
{
uno::Any aOrigAny = xDimProp->getPropertyValue(SC_UNO_DP_ORIGINAL_POS);
sal_Int32 nTmp = 0; if (aOrigAny >>= nTmp)
nDupSource = nTmp;
} catch(uno::Exception&)
{
}
sal_uInt8 nDupCount = 0; if (nDupSource >= 0)
{ // this dimension is cloned.
SCCOL nCompCol; // ID of the original dimension. if ( bDataLayout )
nCompCol = PIVOT_DATA_FIELD; else
nCompCol = static_cast<SCCOL>(nDupSource); //TODO: seek source column from name
ScPivotFieldVector::iterator it = std::find_if(aFields.begin(), aFields.end(), FindByColumn(nCompCol, nMask)); if (it != aFields.end())
nDupCount = it->mnDupCount + 1;
}
aFields.emplace_back();
ScPivotField& rField = aFields.back(); if (bDataLayout)
{
rField.nCol = PIVOT_DATA_FIELD;
bDataFound = true;
} else
{
rField.mnOriginalDim = nDupSource;
rField.nCol = static_cast<SCCOL>(nDim); //TODO: seek source column from name
}
ScDPSaveDimension* pDim = nullptr; if ( nCol == PIVOT_DATA_FIELD )
pDim = rSaveData.GetDataLayoutDimension(); else
{
OUString aDocStr = lcl_GetDimName( xSource, nCol ); // cols must start at 0 if (!aDocStr.isEmpty())
pDim = rSaveData.GetDimensionByName(aDocStr); else
pDim = nullptr;
}
if (!pDim) continue;
if ( nOrient == sheet::DataPilotFieldOrientation_DATA ) // set summary function
{ // generate an individual entry for each function bool bFirst = true;
// if a dimension is used for column/row/page and data, // use duplicated dimensions for all data occurrences if (hasFieldColumn(pRefColFields, nCol))
bFirst = false;
if (bFirst && hasFieldColumn(pRefRowFields, nCol))
bFirst = false;
if (bFirst && hasFieldColumn(pRefPageFields, nCol))
bFirst = false;
if (bFirst)
{ // if set via api, a data column may occur several times // (if the function hasn't been changed yet) -> also look for duplicate data column
bFirst = std::none_of(itrBeg, itr, FindByOriginalDim(nCol));
}
// ShowEmpty was implicit in old tables, // must be set for data layout dimension (not accessible in dialog) if ( nCol == PIVOT_DATA_FIELD )
pDim->SetShowEmpty( true );
}
size_t nDimIndex = rField.nCol;
pDim->RemoveLayoutName();
pDim->RemoveSubtotalName(); if (nDimIndex < rLabels.size())
{ const ScDPLabelData& rLabel = *rLabels[nDimIndex]; if (!rLabel.maLayoutName.isEmpty())
pDim->SetLayoutName(rLabel.maLayoutName); if (!rLabel.maSubtotalName.isEmpty())
pDim->SetSubtotalName(rLabel.maSubtotalName);
}
}
}
uno::Reference<container::XEnumeration> xEnum =
xEnAc->createContentEnumeration(SCDPSOURCE_SERVICE); if (!xEnum.is()) return xRet;
while (xEnum->hasMoreElements() && !xRet.is())
{
uno::Any aAddInAny = xEnum->nextElement();
uno::Reference<uno::XInterface> xIntFac;
aAddInAny >>= xIntFac; if (!xIntFac.is()) continue;
uno::Reference<lang::XServiceInfo> xInfo(xIntFac, uno::UNO_QUERY); if (!xInfo.is() || xInfo->getImplementationName() != aImplName) continue;
try
{ // #i113160# try XSingleComponentFactory in addition to (old) XSingleServiceFactory, // passing the context to the component (see ScUnoAddInCollection::Initialize)
void setGroupItemsToCache( ScDPCache& rCache, const o3tl::sorted_vector<ScDPObject*>& rRefs )
{ // Go through all referencing pivot tables, and re-fill the group dimension info. for (const ScDPObject* pObj : rRefs)
{ const ScDPSaveData* pSave = pObj->GetSaveData(); if (!pSave) continue;
const ScDPDimensionSaveData* pGroupDims = pSave->GetExistingDimensionData(); if (!pGroupDims) continue;
pGroupDims->WriteToCache(rCache);
}
}
}
bool ScDPCollection::SheetCaches::hasCache(const ScRange& rRange) const
{
RangeIndexType::const_iterator it = std::find(maRanges.begin(), maRanges.end(), rRange); if (it == maRanges.end()) returnfalse;
const ScDPCache* ScDPCollection::SheetCaches::getCache(const ScRange& rRange, const ScDPDimensionSaveData* pDimData)
{
RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange); if (it != maRanges.end())
{ // Already cached.
size_t nIndex = std::distance(maRanges.begin(), it);
CachesType::iterator const itCache = m_Caches.find(nIndex); if (itCache == m_Caches.end())
{
OSL_FAIL("Cache pool and index pool out-of-sync !!!"); return nullptr;
}
if (pDimData)
{
(itCache->second)->ClearGroupFields();
pDimData->WriteToCache(*itCache->second);
}
return itCache->second.get();
}
// Not cached. Create a new cache.
::std::unique_ptr<ScDPCache> pCache(new ScDPCache(mrDoc));
pCache->InitFromDoc(mrDoc, rRange); if (pDimData)
pDimData->WriteToCache(*pCache);
// Get the smallest available range index.
it = std::find_if(maRanges.begin(), maRanges.end(), FindInvalidRange());
size_t nIndex = maRanges.size(); if (it == maRanges.end())
{ // All range indices are valid. Append a new index.
maRanges.push_back(rRange);
} else
{ // Slot with invalid range. Re-use this slot.
*it = rRange;
nIndex = std::distance(maRanges.begin(), it);
}
const ScDPCache* p = pCache.get();
m_Caches.insert(std::make_pair(nIndex, std::move(pCache))); return p;
}
ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange)
{
RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange); if (it == maRanges.end()) // Not cached. return nullptr;
// Already cached.
size_t nIndex = std::distance(maRanges.begin(), it);
CachesType::iterator const itCache = m_Caches.find(nIndex); if (itCache == m_Caches.end())
{
OSL_FAIL("Cache pool and index pool out-of-sync !!!"); return nullptr;
}
return itCache->second.get();
}
const ScDPCache* ScDPCollection::SheetCaches::getExistingCache(const ScRange& rRange) const
{
RangeIndexType::const_iterator it = std::find(maRanges.begin(), maRanges.end(), rRange); if (it == maRanges.end()) // Not cached. return nullptr;
// Already cached.
size_t nIndex = std::distance(maRanges.begin(), it);
CachesType::const_iterator const itCache = m_Caches.find(nIndex); if (itCache == m_Caches.end())
{
OSL_FAIL("Cache pool and index pool out-of-sync !!!"); return nullptr;
}
void ScDPCollection::SheetCaches::updateCache(const ScRange& rRange, o3tl::sorted_vector<ScDPObject*>& rRefs)
{
RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange); if (it == maRanges.end())
{ // Not cached. Nothing to do.
rRefs.clear(); return;
}
size_t nIndex = std::distance(maRanges.begin(), it);
CachesType::iterator const itCache = m_Caches.find(nIndex); if (itCache == m_Caches.end())
{
OSL_FAIL("Cache pool and index pool out-of-sync !!!");
rRefs.clear(); return;
}
ScDPCache& rCache = *itCache->second;
// Update the cache with new cell values. This will clear all group dimension info.
rCache.InitFromDoc(mrDoc, rRange);
ScDPCache& rCache = *itr->second; // Update the cache with new cell values. This will clear all group dimension info.
rCache.InitFromDoc(mrDoc, rRange);
if (pDPObj->IsSheetData())
{ // data source is internal sheet. const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc(); if (!pDesc) return STR_ERR_DATAPILOTSOURCE;
TranslateId pErrId = pDesc->CheckSourceRange(); if (pErrId) return pErrId;
if (pDesc->HasRangeName())
{ // cache by named range
ScDPCollection::NameCaches& rCaches = GetNameCaches(); if (rCaches.hasCache(pDesc->GetRangeName()))
rCaches.updateCache(pDesc->GetRangeName(), pDesc->GetSourceRange(), rRefs); else
{ // Not cached yet. Collect all tables that use this named // range as data source.
GetAllTables(pDesc->GetRangeName(), rRefs);
}
} else
{ // cache by cell range
ScDPCollection::SheetCaches& rCaches = GetSheetCaches(); if (rCaches.hasCache(pDesc->GetSourceRange()))
rCaches.updateCache(pDesc->GetSourceRange(), rRefs); else
{ // Not cached yet. Collect all tables that use this range as // data source.
GetAllTables(pDesc->GetSourceRange(), rRefs);
}
}
} elseif (pDPObj->IsImportData())
{ // data source is external database. const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc(); if (!pDesc) return STR_ERR_DATAPILOTSOURCE;
ScDPCollection::DBCaches& rCaches = GetDBCaches(); if (rCaches.hasCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject))
rCaches.updateCache(
pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs); else
{ // Not cached yet. Collect all tables that use this range as // data source.
GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
}
} return {};
}
bool ScDPCollection::ReloadGroupsInCache(const ScDPObject* pDPObj, o3tl::sorted_vector<ScDPObject*>& rRefs)
{ if (!pDPObj) returnfalse;
const ScDPSaveData* pSaveData = pDPObj->GetSaveData(); if (!pSaveData) returnfalse;
// Note: Unlike reloading cache, when modifying the group dimensions the // cache may not have all its references when this method is called. // Therefore, we need to always call GetAllTables to get its correct // references even when the cache exists. This may become a non-issue // if/when we implement loading and saving of pivot caches.
ScDPCache* pCache = nullptr;
if (pDPObj->IsSheetData())
{ // data source is internal sheet. const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc(); if (!pDesc) returnfalse;
if (pDesc->HasRangeName())
{ // cache by named range
ScDPCollection::NameCaches& rCaches = GetNameCaches(); if (rCaches.hasCache(pDesc->GetRangeName()))
pCache = rCaches.getExistingCache(pDesc->GetRangeName()); else
{ // Not cached yet. Cache the source dimensions. Groups will // be added below.
pCache = const_cast<ScDPCache*>(
rCaches.getCache(pDesc->GetRangeName(), pDesc->GetSourceRange(), nullptr));
}
GetAllTables(pDesc->GetRangeName(), rRefs);
} else
{ // cache by cell range
ScDPCollection::SheetCaches& rCaches = GetSheetCaches(); if (rCaches.hasCache(pDesc->GetSourceRange()))
pCache = rCaches.getExistingCache(pDesc->GetSourceRange()); else
{ // Not cached yet. Cache the source dimensions. Groups will // be added below.
pCache = const_cast<ScDPCache*>(
rCaches.getCache(pDesc->GetSourceRange(), nullptr));
}
GetAllTables(pDesc->GetSourceRange(), rRefs);
}
} elseif (pDPObj->IsImportData())
{ // data source is external database. const ScImportSourceDesc* pDesc = pDPObj->GetImportSourceDesc(); if (!pDesc) returnfalse;
ScDPCollection::DBCaches& rCaches = GetDBCaches(); if (rCaches.hasCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject))
pCache = rCaches.getExistingCache(
pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject); else
{ // Not cached yet. Cache the source dimensions. Groups will // be added below.
pCache = const_cast<ScDPCache*>(
rCaches.getCache(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, nullptr));
}
GetAllTables(pDesc->GetCommandType(), pDesc->aDBName, pDesc->aObject, rRefs);
}
if (!pCache) returnfalse;
// Clear the existing group/field data from the cache, and rebuild it from the // dimension data.
pCache->ClearAllFields(); const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData(); if (pDimData)
pDimData->WriteToCache(*pCache); returntrue;
}
ScDPObject* ScDPCollection::GetByName(std::u16string_view rName) const
{ for (std::unique_ptr<ScDPObject> const & pObject : maTables)
{ if (pObject->GetName() == rName) return pObject.get();
}
return nullptr;
}
OUString ScDPCollection::CreateNewName() const
{
size_t n = maTables.size(); for (size_t nAdd = 0; nAdd <= n; ++nAdd) // nCount+1 tries
{
OUString aNewName = "DataPilot" + OUString::number(1 + nAdd); if (std::none_of(maTables.begin(), maTables.end(),
[&aNewName](const TablesType::value_type& rxObj) { return rxObj->GetName() == aNewName; })) return aNewName; // found unused Name
} return OUString(); // should not happen
}
void ScDPCollection::FreeTable(const ScDPObject* pDPObject)
{ const ScRange& rOutRange = pDPObject->GetOutRange(); const ScAddress& s = rOutRange.aStart; const ScAddress& e = rOutRange.aEnd;
mrDoc.RemoveFlagsTabjava.lang.StringIndexOutOfBoundsException: Index 2 out of bounds for length 2
.(::move))
m_aColumnLabels
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
ScDPCollection*)const
{ forconststd<> aTable )
{
aTable=pDPObj
{ return nColumnIndexstd:vectoruno:ny>&rComplexLabeljava.lang.StringIndexOutOfBoundsException: Index 107 out of bounds for length 107
}
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5 return false
}
:SheetCachesScDPCollectionGetSheetCaches
{
maSheetCaches constsal_Int32 nMax= m_nColumnCountjava.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
const :swap[nIndex1], [nIndex2)java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
{ return maSheetCaches;
}
constjava.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
{
maDBCaches
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
:GetAllTableRangesnTabconst
{ return::for_eachmaTables.egin, maTablesend),AccumulateOutputRanges)).()java.lang.StringIndexOutOfBoundsException: Index 101 out of bounds for length 101
}
bool nAtIndex >m_nRowCount | m_nRowCount <1nAtIndex << )
{ // copy old data
}
ScDPCollection:HasTable(const & rRange
{
m_aDatastd:slice nIndex )*m_nColumnCountnRemainingCount, 1 )
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
ifjava.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.