/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
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;
/** * Database connection implementation for UNO database API. Note that in * the UNO database API, column index is 1-based, whereas the interface * requires that column index be 0-based.
*/ class DBConnector : public ScDPCache::DBConnector
{
ScDPCache& mrCache;
uno::Reference<sdbc::XRowSet> mxRowSet;
uno::Reference<sdbc::XRow> mxRow;
uno::Reference<sdbc::XResultSetMetaData> mxMetaData;
Date maNullDate;
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? */
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.24 Sekunden
(vorverarbeitet)
¤
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.