/* -*- 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 .
*/
// <= so 1 extra pass after last item for ( size_t i = 1, nRanges = aRangeListRef->size(); i <= nRanges; ++i )
{ // detect spanning/surrounding area etc.
SCCOLROW nTmp, n1, n2; if ( (n1 = pR->aStart.Col()) < nStartCol ) nStartCol = static_cast<SCCOL>(n1 ); if ( (n2 = pR->aEnd.Col() ) > nEndCol ) nEndCol = static_cast<SCCOL>(n2 ); if ( (nTmp = n2 - n1 + 1 ) > nMaxCols ) nMaxCols = static_cast<SCCOL>(nTmp); if ( (n1 = pR->aStart.Row()) < nStartRow ) nStartRow = static_cast<SCROW>(n1 ); if ( (n2 = pR->aEnd.Row() ) > nEndRow ) nEndRow = static_cast<SCROW>(n2 ); if ( (nTmp = n2 - n1 + 1 ) > nMaxRows ) nMaxRows = static_cast<SCROW>(nTmp);
// in last pass; i = nRanges so don't use at() if ( i < nRanges )
pR = &(*aRangeListRef)[i];
}
SCCOL nC = nEndCol - nStartCol + 1;
assert(nC > 0 && "coverity 2023.12.2"); if ( nC == 1 )
{
eGlue = ScChartGlue::Rows; return;
}
SCROW nR = nEndRow - nStartRow + 1; if ( nR == 1 )
{
eGlue = ScChartGlue::Cols; return;
}
sal_uLong nCR = static_cast<sal_uLong>(nC) * nR;
/* TODO: First do it simple without bit masking. A maximum of 8MB could be allocated this way (256 Cols x 32000 Rows). That could be reduced to 2MB by using 2 Bits per entry, but it is faster this way. Another optimization would be to store only used rows/columns in the array, but
would mean another iteration of the RangeList indirect access to the array. */
SCCOL nCol, nCol1, nCol2;
SCROW nRow, nRow1, nRow2; for ( size_t i = 0, nRanges = aRangeListRef->size(); i < nRanges; ++i )
{ // mark selections as used in 2D
pR = &(*aRangeListRef)[i];
nCol1 = pR->aStart.Col() - nStartCol;
nCol2 = pR->aEnd.Col() - nStartCol;
nRow1 = pR->aStart.Row() - nStartRow;
nRow2 = pR->aEnd.Row() - nStartRow; for ( nCol = nCol1; nCol <= nCol2; nCol++ )
{
p = pA.get() + static_cast<sal_uLong>(nCol) * nR + nRow1; for ( nRow = nRow1; nRow <= nRow2; nRow++, p++ )
*p = CellState::Occupied;
}
} bool bGlue = true;
bool bGlueCols = false; for ( nCol = 0; bGlue && nCol < nC; nCol++ )
{ // iterate columns and try to mark as unused
p = pA.get() + static_cast<sal_uLong>(nCol) * nR; for ( nRow = 0; bGlue && nRow < nR; nRow++, p++ )
{ if ( *p == CellState::Occupied )
{ // If there's one right in the middle, we can't combine. // If it were at the edge, we could combine, if in this Column // in every set line, one is set. if ( nRow > 0 && nCol > 0 )
bGlue = false; // nCol==0 can be DummyUpperLeft else
nRow = nR;
} else
*p = CellState::Free;
} if ( bGlue )
{
p = pA.get() + (((static_cast<sal_uLong>(nCol)+1) * nR) - 1); if (*p == CellState::Free)
{ // mark column as totally unused
*p = CellState::Glue;
bGlueCols = true; // one unused column at least
}
}
}
bool bGlueRows = false; for ( nRow = 0; bGlue && nRow < nR; nRow++ )
{ // iterate rows and try to mark as unused
p = pA.get() + nRow; for ( nCol = 0; bGlue && nCol < nC; nCol++, p+=nR )
{ if ( *p == CellState::Occupied )
{ if ( nCol > 0 && nRow > 0 )
bGlue = false; // nRow==0 can be DummyUpperLeft else
nCol = nC;
} else
*p = CellState::Free;
} if ( bGlue )
{
p = pA.get() + (((static_cast<sal_uLong>(nC)-1) * nR) + nRow); if (*p == CellState::Free )
{ // mark row as totally unused
*p = CellState::Glue;
bGlueRows = true; // one unused row at least
}
}
}
// If n=1: The upper left corner could be automagically pulled in for labeling
p = pA.get() + 1; for ( sal_uLong n = 1; bGlue && n < nCR; n++, p++ )
{ // An untouched field means we could neither reach it through rows nor columns, // thus we can't combine anything if ( *p == CellState::Hole )
bGlue = false;
} if ( bGlue )
{ if ( bGlueCols && bGlueRows )
eGlue = ScChartGlue::Both; elseif ( bGlueRows )
eGlue = ScChartGlue::Rows; else
eGlue = ScChartGlue::Cols; if ( pA[0] != CellState::Occupied )
bDummyUpperLeft = true;
} else
{
eGlue = ScChartGlue::NONE;
}
}
constbool bNoGlue = (eGlue == ScChartGlue::NONE);
ColumnMap aColMap;
SCROW nNoGlueRow = 0; for ( size_t i = 0, nRanges = aRangeListRef->size(); i < nRanges; ++i )
{ const ScRange & rR = (*aRangeListRef)[i];
rR.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); for ( nTab = nTab1; nTab <= nTab2; nTab++ )
{ // nTab in ColKey to allow to have the same col/row in another table
sal_uLong nInsCol = (static_cast<sal_uLong>(nTab) << 16) | (bNoGlue ? 0 : static_cast<sal_uLong>(nCol1)); for ( nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol )
{
RowMap* pCol = &aColMap[nInsCol];
// in other table a new ColKey already was created, // the rows must be equal to be filled with Dummy
sal_uLong nInsRow = (bNoGlue ? nNoGlueRow : nRow1); for ( nRow = nRow1; nRow <= nRow2; nRow++, nInsRow++ )
{ if ( pCol->find( nInsRow ) == pCol->end() )
{
pCol->emplace( nInsRow, std::make_unique<ScAddress>( nCol, nRow, nTab ) );
}
}
}
} // For NoGlue: associated tables will be rendered as ColGlue
nNoGlueRow += nRow2 - nRow1 + 1;
}
// count of data
nColCount = static_cast< SCSIZE >( aColMap.size()); if ( !aColMap.empty() )
{
RowMap& rCol = aColMap.begin()->second; if ( bDummyUpperLeft )
rCol[ 0 ] = nullptr; // Dummy for labeling
nRowCount = static_cast< SCSIZE >( rCol.size());
} else
nRowCount = 0; if ( nColCount > 0 )
nColCount -= nColAdd; if ( nRowCount > 0 )
nRowCount -= nRowAdd;
if ( nColCount==0 || nRowCount==0 )
{ // create an entry without data
RowMap& rCol = aColMap[0];
nColCount = 1;
rCol[ 0 ] = nullptr;
nRowCount = 1;
nColAdd = 0;
nRowAdd = 0;
} else
{ if ( bNoGlue )
{ // fill gaps with Dummies, first column is master
RowMap& rFirstCol = aColMap.begin()->second;
for ( constauto& it1 : rFirstCol )
{
sal_uLong nKey = it1.first; for (ColumnMap::iterator it2 = ++aColMap.begin(); it2 != aColMap.end(); ++it2 )
it2->second.emplace( nKey, nullptr ); // no data
}
}
}
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.