/* -*- 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 .
*/
if (!mrDoc.ValidCol(maStartPos.Col())) maStartPos.SetCol(mrDoc.MaxCol()); if (!mrDoc.ValidCol(maEndPos.Col())) maEndPos.SetCol(mrDoc.MaxCol()); if (!mrDoc.ValidRow(maStartPos.Row())) maStartPos.SetRow(mrDoc.MaxRow()); if (!mrDoc.ValidRow(maEndPos.Row())) maEndPos.SetRow(mrDoc.MaxRow()); if (!ValidTab(maStartPos.Tab()) || maStartPos.Tab() > nDocMaxTab) maStartPos.SetTab(nDocMaxTab); if (!ValidTab(maEndPos.Tab()) || maEndPos.Tab() > nDocMaxTab) maEndPos.SetTab(nDocMaxTab);
}
SCROW ScValueIterator::GetRow() const
{ // Position of the head of the current block + offset within the block // equals the logical element position. return maCurPos.first->position + maCurPos.second;
}
void ScValueIterator::IncPos()
{ if (maCurPos.second + 1 < maCurPos.first->size) // Move within the same block.
++maCurPos.second; else // Move to the next block.
IncBlock();
}
bool ScValueIterator::GetThis(double& rValue, FormulaError& rErr)
{ while (true)
{ bool bNextColumn = !mpCells || maCurPos.first == mpCells->end(); if (!bNextColumn)
{ if (GetRow() > maEndPos.Row())
bNextColumn = true;
}
ScColumn* pCol; if (!bNextColumn)
pCol = &(mrDoc.maTabs[mnTab])->aCol[mnCol]; else
{ // Find the next available column. do
{
++mnCol; while (mnCol > maEndPos.Col() || mnCol >= mrDoc.maTabs[mnTab]->GetAllocatedColumnsCount())
{
mnCol = maStartPos.Col();
++mnTab; if (mnTab > maEndPos.Tab())
{
rErr = FormulaError::NONE; returnfalse;
}
}
pCol = &(mrDoc.maTabs[mnTab])->aCol[mnCol];
} while (pCol->IsEmptyData());
bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue)
{ // Start with the current row position, and find the first row position // that satisfies the query.
// If the query starts in the same column as the result vector we can // prefetch the cell which saves us one fetch in the success case.
SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField;
ScRefCellValue aCell;
while (true)
{ if (maCurPos.first == mpCells->end() || nRow > mpParam->nRow2)
{ // Bottom of the range reached. Bail out.
rValue.mnError = FormulaError::NONE; returnfalse;
}
if (maCurPos.first->type == sc::element_type_empty)
{ // Skip the whole empty block.
incBlock(); continue;
}
void ScDBQueryDataIterator::DataAccessInternal::incPos()
{ if (maCurPos.second + 1 < maCurPos.first->size)
{ // Move within the same block.
++maCurPos.second;
++nRow;
} else // Move to the next block.
incBlock();
}
bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value& rValue)
{ // Starting from row == mnCurRow, get the first row that satisfies all the // query parameters. for ( ;mnCurRow < mnRows; ++mnCurRow)
{ const ScMatrix& rMat = *mpParam->mpMatrix; if (rMat.IsEmpty(mpParam->mnField, mnCurRow)) // Don't take empty values into account. continue;
bool bIsStrVal = rMat.IsStringOrEmpty(mpParam->mnField, mnCurRow); if (bIsStrVal && mpParam->mbSkipString) continue;
if (!rMat.IsValueOrEmpty(nCol, nRow)) returnfalse;
returntrue;
}
bool isQueryByString(const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
{ switch (rEntry.eOp)
{ case SC_EQUAL: case SC_NOT_EQUAL: case SC_CONTAINS: case SC_DOES_NOT_CONTAIN: case SC_BEGINS_WITH: case SC_ENDS_WITH: case SC_DOES_NOT_BEGIN_WITH: case SC_DOES_NOT_END_WITH: returntrue; default:
;
}
for (SCSIZE i = 0; i < nEntryCount; ++i)
{ const ScQueryEntry& rEntry = mpParam->GetEntry(i); const ScQueryEntry::Item& rItem = rEntry.GetQueryItem(); if (!rEntry.bDoQuery) continue;
switch (rEntry.eOp)
{ case SC_EQUAL: case SC_LESS: case SC_GREATER: case SC_LESS_EQUAL: case SC_GREATER_EQUAL: case SC_NOT_EQUAL: break; default: // Only the above operators are supported.
SAL_WARN("sc.core", "Unsupported operator " << rEntry.eOp
<< " in ScDBQueryDataIterator::DataAccessMatrix::isValidQuery()"); continue;
}
// Unequality check using collator.
sal_Int32 nCompare = rCollator.compareString(aMatStr.getString(), aQueryStr.getString()); switch (rEntry.eOp)
{ case SC_LESS :
bValid = (nCompare < 0); break; case SC_GREATER :
bValid = (nCompare > 0); break; case SC_LESS_EQUAL :
bValid = (nCompare <= 0); break; case SC_GREATER_EQUAL :
bValid = (nCompare >= 0); break; default:
;
}
} while (false);
}
if (aResults.empty()) // First query entry.
aResults.push_back(bValid); elseif (rEntry.eConnect == SC_AND)
{ // For AND op, tuck the result into the last result value.
size_t n = aResults.size();
aResults[n-1] = aResults[n-1] && bValid;
} else // For OR op, store its own result.
aResults.push_back(bValid);
}
// Row is valid as long as there is at least one result being true. return std::find(aResults.begin(), aResults.end(), true) != aResults.end();
}
void ScCellIterator::incPos()
{ if (maCurColPos.second + 1 < maCurColPos.first->size)
{ // Move within the same block.
++maCurColPos.second;
maCurPos.IncRow();
} else // Move to the next block.
incBlock();
}
if (!mrDoc.ValidCol(maStartPos.Col())) maStartPos.SetCol(mrDoc.MaxCol()); if (!mrDoc.ValidCol(maEndPos.Col())) maEndPos.SetCol(mrDoc.MaxCol()); if (!mrDoc.ValidRow(maStartPos.Row())) maStartPos.SetRow(mrDoc.MaxRow()); if (!mrDoc.ValidRow(maEndPos.Row())) maEndPos.SetRow(mrDoc.MaxRow()); if (!ValidTab(maStartPos.Tab(), nDocMaxTab)) maStartPos.SetTab(nDocMaxTab); if (!ValidTab(maEndPos.Tab(), nDocMaxTab)) maEndPos.SetTab(nDocMaxTab);
while (maEndPos.Tab() > 0 && !mrDoc.maTabs[maEndPos.Tab()])
maEndPos.IncTab(-1); // Only the tables in use
if (maStartPos.Tab() > maEndPos.Tab() || !mrDoc.maTabs[maStartPos.Tab()])
{
assert(!"Table not found");
maStartPos = ScAddress(mrDoc.MaxCol()+1, mrDoc.MaxRow()+1, MAXTAB+1); // -> Abort on first().
} else
{ for (auto tabNo = maStartPos.Tab();; ++tabNo)
{ constauto& pTab = mrDoc.maTabs[tabNo]; if (pTab && maStartPos.Col() < pTab->GetAllocatedColumnsCount())
{ // Found the first table with allocated columns in range
maStartPos.SetTab(tabNo); break;
} if (tabNo == maEndPos.Tab())
{ // No allocated columns found in the range -> return false from first().
maStartPos = ScAddress(mrDoc.MaxCol() + 1, mrDoc.MaxRow() + 1, MAXTAB + 1); break;
}
}
}
while (true)
{ bool bNextColumn = maCurColPos.first == pCol->maCells.end(); if (!bNextColumn)
{ if (maCurPos.Row() > maEndPos.Row())
bNextColumn = true;
}
if (bNextColumn)
{ // Move to the next column.
maCurPos.SetRow(maStartPos.Row()); do
{
maCurPos.IncCol(); while (maCurPos.Col() >= mrDoc.GetAllocatedColumnsCount(maCurPos.Tab())
|| maCurPos.Col() > maEndPos.Col())
{
maCurPos.SetCol(maStartPos.Col());
maCurPos.IncTab(); if (maCurPos.Tab() > maEndPos.Tab())
{
maCurCell.clear(); returnfalse;
}
}
pCol = getColumn();
} while (pCol->IsEmptyData());
// Set the start position in each column. for (SCCOL i = nStartCol; i <= nEndCol; ++i)
{
ScColumn* pCol = &rDoc.maTabs[mnTab]->aCol[i];
ColParam aParam;
aParam.maPos = pCol->maCells.position(nStartRow).first;
aParam.maEnd = pCol->maCells.end();
aParam.mnCol = i;
// find first non-empty element. while (aParam.maPos != aParam.maEnd) { if (aParam.maPos->type == sc::element_type_empty)
++aParam.maPos; else
{
maColPositions.push_back( aParam ); break;
}
}
}
// Skip any invalid / empty cells across the current row, // we only advance the cursor if the current entry is invalid. // if we return true we have a valid cursor (or hit the end) bool ScHorizontalCellIterator::SkipInvalidInRow()
{
assert (mbMore);
assert (maColPos != maColPositions.end());
// Find the next non-empty cell in the current row. while( maColPos != maColPositions.end() )
{
ColParam& r = *maColPos;
assert (r.maPos != r.maEnd);
size_t nRow = static_cast<size_t>(mnRow);
if (nRow >= r.maPos->position)
{ if (nRow < r.maPos->position + r.maPos->size)
{
mnCol = maColPos->mnCol;
debugiter("found valid cell at column %d, row %d\n",
(int)mnCol, (int)mnRow);
assert(r.maPos->type != sc::element_type_empty); returntrue;
} else
{ bool bMoreBlocksInColumn = false; // This block is behind the current row position. Advance the block. for (++r.maPos; r.maPos != r.maEnd; ++r.maPos)
{ if (nRow < r.maPos->position + r.maPos->size &&
r.maPos->type != sc::element_type_empty)
{
bMoreBlocksInColumn = true; break;
}
} if (!bMoreBlocksInColumn)
{
debugiter("remove column %d at row %d\n",
(int)maColPos->mnCol, (int)nRow);
maColPos = maColPositions.erase(maColPos); if (maColPositions.empty())
{
debugiter("no more columns\n");
mbMore = false;
}
} else
{
debugiter("advanced column %d to block starting row %d, retrying\n",
(int)maColPos->mnCol, r.maPos->position);
}
}
} else
{
debugiter("skip empty cells at column %d, row %d\n",
(int)maColPos->mnCol, (int)nRow);
++maColPos;
}
}
// No more columns with anything interesting in them ? if (maColPositions.empty())
{
debugiter("no more live columns left - done\n");
mbMore = false; returntrue;
}
returnfalse;
}
/// Find the next row that has some real content in one of its columns.
SCROW ScHorizontalCellIterator::FindNextNonEmptyRow()
{
size_t nNextRow = rDoc.MaxRow()+1;
for (const ColParam& r : maColPositions)
{
assert(o3tl::make_unsigned(mnRow) <= r.maPos->position);
nNextRow = std::min (nNextRow, static_cast<size_t>(r.maPos->position));
}
SCROW nRow = std::max(static_cast<SCROW>(nNextRow), mnRow);
debugiter("Next non empty row is %d\n", (int) nRow); return nRow;
}
maColPos = maColPositions.begin();
debugiter("moving to next row\n"); if (SkipInvalidInRow())
{
debugiter("moved to valid cell in next row (or end)\n"); return;
}
if (!rDoc.ValidCol(nStartCol)) nStartCol = rDoc.MaxCol(); if (!rDoc.ValidCol(nEndCol)) nEndCol = rDoc.MaxCol(); if (!rDoc.ValidRow(nStartRow)) nStartRow = rDoc.MaxRow(); if (!rDoc.ValidRow(nEndRow)) nEndRow = rDoc.MaxRow(); if (!ValidTab(nStartTab)) nStartTab = MAXTAB; if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
for (SCCOL i=nStartCol; i<=nEndCol; i++)
{
SCCOL nPos = i - nStartCol; if ( bInitialization || pNextEnd[nPos] < nRow )
{ const ScAttrArray& pArray = rDoc.maTabs[nTab]->GetColumnData(i).AttrArray();
SCSIZE nIndex; if (bInitialization)
{ if ( pArray.Count() )
pArray.Search( nStartRow, nIndex ); else
nIndex = 0;
pIndices[nPos] = nIndex;
pHorizEnd[nPos] = rDoc.MaxCol()+1; // only for assert()
} else
nIndex = ++pIndices[nPos];
if ( !nIndex && !pArray.Count() )
{
pNextEnd[nPos] = rDoc.MaxRow();
assert( pNextEnd[nPos] >= nRow && "Sequence out of order" );
ppPatterns[nPos] = &rDoc.getCellAttributeHelper().getDefaultCellAttribute();
} elseif ( nIndex < pArray.Count() )
{ const ScPatternAttr* pPattern = pArray.mvData[nIndex].getScPatternAttr();
SCROW nThisEnd = pArray.mvData[nIndex].nEndRow;
pNextEnd[nPos] = nThisEnd;
assert( pNextEnd[nPos] >= nRow && "Sequence out of order" );
ppPatterns[nPos] = pPattern;
} else
{
assert(!"AttrArray does not range to MAXROW");
pNextEnd[nPos] = rDoc.MaxRow();
ppPatterns[nPos] = nullptr;
}
}
if ( nMinNextEnd > pNextEnd[nPos] )
nMinNextEnd = pNextEnd[nPos];
// store positions of ScHorizontalAttrIterator elements (minimizing expensive ScPatternAttr comparisons) if (i > nStartCol && !ScPatternAttr::areSame(ppPatterns[nThisHead], ppPatterns[nPos]))
{
pHorizEnd[nThisHead] = i - 1;
nThisHead = nPos; // start position of the next horizontal group
}
}
pHorizEnd[nThisHead] = nEndCol; // set the end position of the last horizontal group, too
}
const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow )
{
assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT"); for (;;)
{ if ( nCol <= nEndCol )
{ const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol];
rRow = nRow;
rCol1 = nCol;
assert( pHorizEnd[nCol-nStartCol] < rDoc.MaxCol()+1 && "missing stored data" );
nCol = pHorizEnd[nCol-nStartCol];
rCol2 = nCol;
++nCol; // Count up for next call return pPat; // Found it!
}
// Next row
++nRow; if ( nRow > nEndRow ) // Already at the end? return nullptr; // Found nothing
nCol = nStartCol; // Start at the left again
if ( nRow > nMinNextEnd )
InitForNextRow(false);
}
}
void ScDocRowHeightUpdater::update(constbool bOnlyUsedRows)
{ if (!mpTabRangesArray || mpTabRangesArray->empty())
{ // No ranges defined. Update all rows in all tables.
updateAll(bOnlyUsedRows); return;
}
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.