/* -*- 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 .
*/
for (constauto& rValue : maValues)
{ double fVal = rValue.GetValue(); if (std::isinf(fVal))
{ if (std::signbit(fVal))
{ // Less than the min value. if (rCellData.GetValue() < maNumInfo.mfStart) returntrue;
}
// Greater than the max value. if (maNumInfo.mfEnd < rCellData.GetValue()) returntrue;
continue;
}
double low = fVal; double high = low + maNumInfo.mfStep; if (maNumInfo.mbIntegerOnly)
high += 1.0;
if (low <= rCellData.GetValue() && rCellData.GetValue() < high) returntrue;
}
// Start and end dates are inclusive. (An end date without a time value // is included, while an end date with a time value is not.)
if (rCellData.GetValue() < maNumInfo.mfStart && !approxEqual(rCellData.GetValue(), maNumInfo.mfStart))
{ if (nValue == ScDPItemData::DateFirst) returntrue; continue;
}
if (rCellData.GetValue() > maNumInfo.mfEnd && !approxEqual(rCellData.GetValue(), maNumInfo.mfEnd))
{ if (nValue == ScDPItemData::DateLast) returntrue; continue;
}
if (nGroupType == DataPilotFieldGroupBy::HOURS || nGroupType == DataPilotFieldGroupBy::MINUTES ||
nGroupType == DataPilotFieldGroupBy::SECONDS)
{ // handle time // (do as in the cell functions, ScInterpreter::ScGetHour() etc.)
switch (nGroupType)
{ case DataPilotFieldGroupBy::HOURS:
{ if (nHour == nValue) returntrue;
} break; case DataPilotFieldGroupBy::MINUTES:
{ if (nMinute == nValue) returntrue;
} break; case DataPilotFieldGroupBy::SECONDS:
{ if (nSecond == nValue) returntrue;
} break; default:
OSL_FAIL("invalid time part");
}
continue;
}
Date date = maNullDate + static_cast<sal_Int32>(approxFloor(rCellData.GetValue())); switch (nGroupType)
{ case DataPilotFieldGroupBy::YEARS:
{
sal_Int32 year = static_cast<sal_Int32>(date.GetYear()); if (year == nValue) returntrue;
} break; case DataPilotFieldGroupBy::QUARTERS:
{
sal_Int32 qtr = 1 + (static_cast<sal_Int32>(date.GetMonth()) - 1) / 3; if (qtr == nValue) returntrue;
} break; case DataPilotFieldGroupBy::MONTHS:
{
sal_Int32 month = static_cast<sal_Int32>(date.GetMonth()); if (month == nValue) returntrue;
} break; case DataPilotFieldGroupBy::DAYS:
{
Date yearStart(1, 1, date.GetYear());
sal_Int32 days = (date - yearStart) + 1; // Jan 01 has value 1 if (days >= 60 && !date.IsLeapYear())
{ // This is not a leap year. Adjust the value accordingly.
++days;
} if (days == nValue) returntrue;
} break; default:
OSL_FAIL("invalid date part");
}
}
switch (nChildPart) // inner part
{ case css::sheet::DataPilotFieldGroupBy::MONTHS: // a month is only contained in its quarter if (nGroupPart == css::sheet::DataPilotFieldGroupBy::QUARTERS) // months and quarters are both 1-based return (nGroupValue - 1 == (nChildValue - 1) / 3); break; case css::sheet::DataPilotFieldGroupBy::DAYS: // a day is only contained in its quarter or month if (nGroupPart == css::sheet::DataPilotFieldGroupBy::MONTHS ||
nGroupPart == css::sheet::DataPilotFieldGroupBy::QUARTERS)
{
Date aDate(1, 1, SC_DP_LEAPYEAR);
aDate.AddDays(nChildValue - 1); // days are 1-based
sal_Int32 nCompare = aDate.GetMonth(); if (nGroupPart == css::sheet::DataPilotFieldGroupBy::QUARTERS)
nCompare = ( ( nCompare - 1 ) / 3 ) + 1; // get quarter from date
CreateCacheTable();
nSourceCount = pSource->GetColumnCount(); // real columns, excluding data layout
pNumGroups.reset( new ScDPNumGroupDimension[nSourceCount] );
}
ScDPGroupTableData::~ScDPGroupTableData()
{
}
void ScDPGroupTableData::AddGroupDimension( const ScDPGroupDimension& rGroup )
{
ScDPGroupDimension aNewGroup( rGroup );
aNewGroup.SetGroupDim( GetColumnCount() ); // new dimension will be at the end
aGroups.push_back( aNewGroup );
}
void ScDPGroupTableData::GetNumGroupInfo(tools::Long nDimension, ScDPNumGroupInfo& rInfo)
{ if ( nDimension < nSourceCount )
rInfo = pNumGroups[nDimension].GetInfo();
}
sal_Int32 ScDPGroupTableData::GetMembersCount( sal_Int32 nDim )
{ const std::vector< SCROW >& members = GetColumnEntries( nDim ); return members.size();
} const std::vector< SCROW >& ScDPGroupTableData::GetColumnEntries( sal_Int32 nColumn )
{ if ( nColumn >= nSourceCount )
{ if ( getIsDataLayoutDimension( nColumn) ) // data layout dimension?
nColumn = nSourceCount; // index of data layout in source data else
{ const ScDPGroupDimension& rGroupDim = aGroups[nColumn - nSourceCount]; return rGroupDim.GetColumnEntries( GetCacheTable() );
}
}
if ( IsNumGroupDimension( nColumn ) )
{ // dimension number is unchanged for numerical groups return pNumGroups[nColumn].GetNumEntries( static_cast<SCCOL>(nColumn), &GetCacheTable().getCache());
}
bool ScDPGroupTableData::getIsDataLayoutDimension(sal_Int32 nColumn)
{ // position of data layout dimension is moved from source data return ( nColumn == sal::static_int_cast<tools::Long>( nSourceCount + aGroups.size() ) ); // data layout dimension?
}
bool ScDPGroupTableData::IsDateDimension(sal_Int32 nDim)
{ if ( nDim >= nSourceCount )
{ if ( nDim == sal::static_int_cast<tools::Long>( nSourceCount + aGroups.size() ) ) // data layout dimension?
nDim = nSourceCount; // index of data layout in source data else
nDim = aGroups[nDim - nSourceCount].GetSourceDim(); // look at original dimension
}
return pSourceData->IsDateDimension( nDim );
}
sal_uInt32 ScDPGroupTableData::GetNumberFormat(sal_Int32 nDim)
{ if ( nDim >= nSourceCount )
{ if ( nDim == sal::static_int_cast<tools::Long>( nSourceCount + aGroups.size() ) ) // data layout dimension?
nDim = nSourceCount; // index of data layout in source data else
nDim = aGroups[nDim - nSourceCount].GetSourceDim(); // look at original dimension
}
void ScDPGroupTableData::ModifyFilterCriteria(vector<ScDPFilteredCache::Criterion>& rCriteria)
{ // Build dimension ID to object map for group dimensions. typedef std::unordered_map<tools::Long, const ScDPGroupDimension*> GroupFieldMapType;
GroupFieldMapType aGroupFieldIds;
for (constauto& rGroup : aGroups)
{
aGroupFieldIds.emplace(rGroup.GetGroupDim(), &rGroup);
}
GroupFieldMapType::const_iterator itrGrp = aGroupFieldIds.find(rCriterion.mnFieldIndex); if (itrGrp == itrGrpEnd)
{ if (IsNumGroupDimension(rCriterion.mnFieldIndex))
{ // internal number group field const ScDPNumGroupInfo* pNumInfo = rCache.GetNumGroupInfo(rCriterion.mnFieldIndex); if (!pNumInfo) // Number group dimension without num info? Something is wrong... continue;
if (rNumGrpDim.IsDateDimension())
{ // grouped by dates.
aCri.mpFilter =
std::make_shared<ScDPGroupDateFilter>(
std::move(aMatchValues), pDoc->GetFormatTable()->GetNullDate(), *pNumInfo);
} else
{ // This dimension is grouped by numeric ranges.
aCri.mpFilter =
std::make_shared<ScDPGroupNumFilter>(std::move(aMatchValues), *pNumInfo);
}
aNewCriteria.push_back(aCri);
} else
{ // This is a regular source field.
aNewCriteria.push_back(rCriterion);
}
} else
{ // This is an ordinary group field or external number group field.
if (pGrpDim->IsDateDimension() && pNumInfo)
{ // external number group
ScDPFilteredCache::Criterion aCri;
aCri.mnFieldIndex = nSrcDim; // use the source dimension, not the group dimension.
aCri.mpFilter =
std::make_shared<ScDPGroupDateFilter>(
std::move(aMatchValues), pDoc->GetFormatTable()->GetNullDate(), *pNumInfo);
aNewCriteria.push_back(aCri);
} else
{ // normal group
size_t nGroupItemCount = pGrpDim->GetItemCount(); for (size_t i = 0; i < nGroupItemCount; ++i)
{ const ScDPGroupItem* pGrpItem = pGrpDim->GetGroupByIndex(i); if (!pGrpItem) continue;
// Make sure this group name equals one of the match values. if (std::none_of(aMatchValues.begin(), aMatchValues.end(), FindCaseInsensitive(pGrpItem->GetName()))) continue;
void ScDPGroupTableData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
{ // #i111435# Inside FillRowDataFromCacheTable/GetItemData, virtual methods // getIsDataLayoutDimension and GetSourceDim are used, so it has to be called // with original rInfo, containing dimension indexes of the grouped data.
bool ScDPGroupTableData::IsNumOrDateGroup(sal_Int32 nDimension) const
{ // Virtual method from ScDPTableData, used in result data to force text labels.
auto aIter = std::find_if(aGroups.begin(), aGroups.end(),
[&nDimension](const ScDPGroupDimension& rDim) { return rDim.GetGroupDim() == nDimension; }); if (aIter != aGroups.end()) return aIter->IsDateDimension();
returnfalse;
}
bool ScDPGroupTableData::IsInGroup( const ScDPItemData& rGroupData, sal_Int32 nGroupIndex, const ScDPItemData& rBaseData, sal_Int32 nBaseIndex ) const
{ auto aIter = std::find_if(aGroups.begin(), aGroups.end(),
[&nGroupIndex, &nBaseIndex](const ScDPGroupDimension& rDim) { return rDim.GetGroupDim() == nGroupIndex && rDim.GetSourceDim() == nBaseIndex; }); if (aIter != aGroups.end())
{ const ScDPGroupDimension& rDim = *aIter; if (rDim.IsDateDimension())
{ return isDateInGroup(rGroupData, rBaseData);
} else
{ // If the item is in a group, only that group is valid. // If the item is not in any group, its own name is valid.
OSL_FAIL("IsInGroup: no group dimension found"); returntrue;
}
bool ScDPGroupTableData::HasCommonElement( const ScDPItemData& rFirstData, sal_Int32 nFirstIndex, const ScDPItemData& rSecondData, sal_Int32 nSecondIndex ) const
{ const ScDPGroupDimension* pFirstDim = nullptr; const ScDPGroupDimension* pSecondDim = nullptr; for ( constauto& rDim : aGroups )
{ const ScDPGroupDimension* pDim = &rDim; if ( pDim->GetGroupDim() == nFirstIndex )
pFirstDim = pDim; elseif ( pDim->GetGroupDim() == nSecondIndex )
pSecondDim = pDim;
} if ( pFirstDim && pSecondDim )
{ bool bFirstDate = pFirstDim->IsDateDimension(); bool bSecondDate = pSecondDim->IsDateDimension(); if (bFirstDate || bSecondDate)
{ // If one is a date group dimension, the other one must be, too. if (!bFirstDate || !bSecondDate)
{
OSL_FAIL( "mix of date and non-date groups" ); returntrue;
}
return isDateInGroup(rFirstData, rSecondData);
}
const ScDPGroupItem* pFirstItem = pFirstDim->GetGroupForName( rFirstData ); const ScDPGroupItem* pSecondItem = pSecondDim->GetGroupForName( rSecondData ); if ( pFirstItem && pSecondItem )
{ // two existing groups -> sal_True if they have a common element return pFirstItem->HasCommonElement( *pSecondItem );
} elseif ( pFirstItem )
{ // "automatic" group contains only its own name return pFirstItem->HasElement( rSecondData );
} elseif ( pSecondItem )
{ // "automatic" group contains only its own name return pSecondItem->HasElement( rFirstData );
} else
{ // no groups -> sal_True if equal return rFirstData.IsCaseInsEqual( rSecondData );
}
}
OSL_FAIL("HasCommonElement: no group dimension found"); returntrue;
}
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.