1
0
Fork 0
libreoffice/sc/source/core/data/cellvalues.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

364 lines
11 KiB
C++

/* -*- 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/.
*/
#include <memory>
#include <cellvalues.hxx>
#include <column.hxx>
#include <formulacell.hxx>
#include <editeng/editobj.hxx>
#include <cassert>
namespace sc {
namespace {
struct BlockPos
{
size_t mnStart;
size_t mnEnd;
};
}
CellValueSpan::CellValueSpan( SCROW nRow1, SCROW nRow2 ) :
mnRow1(nRow1), mnRow2(nRow2) {}
struct CellValuesImpl
{
CellStoreType maCells;
CellTextAttrStoreType maCellTextAttrs;
CellStoreType::iterator miCellPos;
CellTextAttrStoreType::iterator miAttrPos;
CellValuesImpl() = default;
CellValuesImpl(const CellValuesImpl&) = delete;
const CellValuesImpl& operator=(const CellValuesImpl&) = delete;
};
CellValues::CellValues() :
mpImpl(new CellValuesImpl) {}
CellValues::~CellValues()
{
}
void CellValues::transferFrom( ScColumn& rCol, SCROW nRow, size_t nLen )
{
mpImpl->maCells.resize(nLen);
mpImpl->maCellTextAttrs.resize(nLen);
rCol.maCells.transfer(nRow, nRow+nLen-1, mpImpl->maCells, 0);
rCol.maCellTextAttrs.transfer(nRow, nRow+nLen-1, mpImpl->maCellTextAttrs, 0);
}
void CellValues::copyTo( ScColumn& rCol, SCROW nRow ) const
{
copyCellsTo(rCol, nRow);
copyCellTextAttrsTo(rCol, nRow);
}
void CellValues::swapNonEmpty( ScColumn& rCol )
{
std::vector<BlockPos> aBlocksToSwap;
// Go through static value blocks and record their positions and sizes.
for (const auto& rCell : mpImpl->maCells)
{
if (rCell.type == sc::element_type_empty)
continue;
BlockPos aPos;
aPos.mnStart = rCell.position;
aPos.mnEnd = aPos.mnStart + rCell.size - 1;
aBlocksToSwap.push_back(aPos);
}
// Do the swapping. The undo storage will store the replaced formula cells after this.
for (const auto& rBlock : aBlocksToSwap)
{
rCol.maCells.swap(rBlock.mnStart, rBlock.mnEnd, mpImpl->maCells, rBlock.mnStart);
rCol.maCellTextAttrs.swap(rBlock.mnStart, rBlock.mnEnd, mpImpl->maCellTextAttrs, rBlock.mnStart);
}
}
void CellValues::assign( const std::vector<double>& rVals )
{
mpImpl->maCells.resize(rVals.size());
mpImpl->maCells.set(0, rVals.begin(), rVals.end());
// Set default text attributes.
std::vector<CellTextAttr> aDefaults(rVals.size(), CellTextAttr());
mpImpl->maCellTextAttrs.resize(rVals.size());
mpImpl->maCellTextAttrs.set(0, aDefaults.begin(), aDefaults.end());
}
void CellValues::assign( const std::vector<ScFormulaCell*>& rVals )
{
std::vector<ScFormulaCell*> aCopyVals(rVals.size());
size_t nIdx = 0;
for (const auto* pCell : rVals)
{
aCopyVals[nIdx] = pCell->Clone();
++nIdx;
}
mpImpl->maCells.resize(aCopyVals.size());
mpImpl->maCells.set(0, aCopyVals.begin(), aCopyVals.end());
// Set default text attributes.
std::vector<CellTextAttr> aDefaults(rVals.size(), CellTextAttr());
mpImpl->maCellTextAttrs.resize(rVals.size());
mpImpl->maCellTextAttrs.set(0, aDefaults.begin(), aDefaults.end());
}
size_t CellValues::size() const
{
assert(mpImpl->maCells.size() == mpImpl->maCellTextAttrs.size());
return mpImpl->maCells.size();
}
void CellValues::reset( size_t nSize )
{
mpImpl->maCells.clear();
mpImpl->maCells.resize(nSize);
mpImpl->maCellTextAttrs.clear();
mpImpl->maCellTextAttrs.resize(nSize);
mpImpl->miCellPos = mpImpl->maCells.begin();
mpImpl->miAttrPos = mpImpl->maCellTextAttrs.begin();
}
void CellValues::setValue( size_t nRow, double fVal )
{
mpImpl->miCellPos = mpImpl->maCells.set(mpImpl->miCellPos, nRow, fVal);
mpImpl->miAttrPos = mpImpl->maCellTextAttrs.set(mpImpl->miAttrPos, nRow, sc::CellTextAttr());
}
void CellValues::setValue( size_t nRow, const svl::SharedString& rStr )
{
mpImpl->miCellPos = mpImpl->maCells.set(mpImpl->miCellPos, nRow, rStr);
mpImpl->miAttrPos = mpImpl->maCellTextAttrs.set(mpImpl->miAttrPos, nRow, sc::CellTextAttr());
}
void CellValues::setValue( size_t nRow, std::unique_ptr<EditTextObject> pEditText )
{
mpImpl->miCellPos = mpImpl->maCells.set(mpImpl->miCellPos, nRow, pEditText.release());
mpImpl->miAttrPos = mpImpl->maCellTextAttrs.set(mpImpl->miAttrPos, nRow, sc::CellTextAttr());
}
void CellValues::swap( CellValues& r )
{
std::swap(mpImpl, r.mpImpl);
}
std::vector<CellValueSpan> CellValues::getNonEmptySpans() const
{
std::vector<CellValueSpan> aRet;
for (const auto& rCell : mpImpl->maCells)
{
if (rCell.type != element_type_empty)
{
// Record this span.
size_t nRow1 = rCell.position;
size_t nRow2 = nRow1 + rCell.size - 1;
aRet.emplace_back(nRow1, nRow2);
}
}
return aRet;
}
void CellValues::copyCellsTo( ScColumn& rCol, SCROW nRow ) const
{
CellStoreType& rDest = rCol.maCells;
const CellStoreType& rSrc = mpImpl->maCells;
// Caller must ensure the destination is long enough.
assert(rSrc.size() + static_cast<size_t>(nRow) <= rDest.size());
SCROW nCurRow = nRow;
CellStoreType::iterator itPos = rDest.begin();
for (const auto& rBlk : rSrc)
{
switch (rBlk.type)
{
case element_type_numeric:
{
numeric_block::const_iterator it = numeric_block::begin(*rBlk.data);
numeric_block::const_iterator itEnd = numeric_block::end(*rBlk.data);
itPos = rDest.set(itPos, nCurRow, it, itEnd);
}
break;
case element_type_string:
{
string_block::const_iterator it = string_block::begin(*rBlk.data);
string_block::const_iterator itEnd = string_block::end(*rBlk.data);
itPos = rDest.set(itPos, nCurRow, it, itEnd);
}
break;
case element_type_edittext:
{
edittext_block::const_iterator it = edittext_block::begin(*rBlk.data);
edittext_block::const_iterator itEnd = edittext_block::end(*rBlk.data);
std::vector<EditTextObject*> aVals;
aVals.reserve(rBlk.size);
for (; it != itEnd; ++it)
{
const EditTextObject* p = *it;
aVals.push_back(p->Clone().release());
}
itPos = rDest.set(itPos, nCurRow, aVals.begin(), aVals.end());
}
break;
case element_type_formula:
{
formula_block::const_iterator it = formula_block::begin(*rBlk.data);
formula_block::const_iterator itEnd = formula_block::end(*rBlk.data);
std::vector<ScFormulaCell*> aVals;
aVals.reserve(rBlk.size);
for (; it != itEnd; ++it)
{
const ScFormulaCell* p = *it;
aVals.push_back(p->Clone());
}
itPos = rDest.set(itPos, nCurRow, aVals.begin(), aVals.end());
}
break;
default:
itPos = rDest.set_empty(itPos, nCurRow, nCurRow+rBlk.size-1);
}
nCurRow += rBlk.size;
}
}
void CellValues::copyCellTextAttrsTo( ScColumn& rCol, SCROW nRow ) const
{
CellTextAttrStoreType& rDest = rCol.maCellTextAttrs;
const CellTextAttrStoreType& rSrc = mpImpl->maCellTextAttrs;
// Caller must ensure the destination is long enough.
assert(rSrc.size() + static_cast<size_t>(nRow) <= rDest.size());
SCROW nCurRow = nRow;
CellTextAttrStoreType::iterator itPos = rDest.begin();
for (const auto& rBlk : rSrc)
{
switch (rBlk.type)
{
case element_type_celltextattr:
{
celltextattr_block::const_iterator it = celltextattr_block::begin(*rBlk.data);
celltextattr_block::const_iterator itEnd = celltextattr_block::end(*rBlk.data);
itPos = rDest.set(itPos, nCurRow, it, itEnd);
}
break;
default:
itPos = rDest.set_empty(itPos, nCurRow, nCurRow+rBlk.size-1);
}
nCurRow += rBlk.size;
}
}
typedef std::vector<std::unique_ptr<CellValues>> TableType;
typedef std::vector<std::unique_ptr<TableType>> TablesType;
struct TableValues::Impl
{
ScRange maRange;
TablesType m_Tables;
explicit Impl( const ScRange& rRange ) : maRange(rRange)
{
size_t nTabs = rRange.aEnd.Tab() - rRange.aStart.Tab() + 1;
size_t nCols = rRange.aEnd.Col() - rRange.aStart.Col() + 1;
for (size_t nTab = 0; nTab < nTabs; ++nTab)
{
m_Tables.push_back(std::make_unique<TableType>());
std::unique_ptr<TableType>& rTab2 = m_Tables.back();
for (size_t nCol = 0; nCol < nCols; ++nCol)
rTab2->push_back(std::make_unique<CellValues>());
}
}
CellValues* getCellValues( SCTAB nTab, SCCOL nCol )
{
if (nTab < maRange.aStart.Tab() || maRange.aEnd.Tab() < nTab)
// sheet index out of bound.
return nullptr;
if (nCol < maRange.aStart.Col() || maRange.aEnd.Col() < nCol)
// column index out of bound.
return nullptr;
size_t nTabOffset = nTab - maRange.aStart.Tab();
if (nTabOffset >= m_Tables.size())
return nullptr;
std::unique_ptr<TableType>& rTab2 = m_Tables[nTab-maRange.aStart.Tab()];
size_t nColOffset = nCol - maRange.aStart.Col();
if (nColOffset >= rTab2->size())
return nullptr;
return &rTab2.get()[0][nColOffset].get()[0];
}
};
TableValues::TableValues() :
mpImpl(new Impl(ScRange(ScAddress::INITIALIZE_INVALID))) {}
TableValues::TableValues( const ScRange& rRange ) :
mpImpl(new Impl(rRange)) {}
TableValues::~TableValues()
{
}
const ScRange& TableValues::getRange() const
{
return mpImpl->maRange;
}
void TableValues::swap( SCTAB nTab, SCCOL nCol, CellValues& rColValue )
{
CellValues* pCol = mpImpl->getCellValues(nTab, nCol);
if (!pCol)
return;
pCol->swap(rColValue);
}
void TableValues::swapNonEmpty( SCTAB nTab, SCCOL nCol, ScColumn& rCol )
{
CellValues* pCol = mpImpl->getCellValues(nTab, nCol);
if (!pCol)
return;
pCol->swapNonEmpty(rCol);
}
std::vector<CellValueSpan> TableValues::getNonEmptySpans( SCTAB nTab, SCCOL nCol ) const
{
std::vector<CellValueSpan> aRet;
CellValues* pCol = mpImpl->getCellValues(nTab, nCol);
if (pCol)
aRet = pCol->getNonEmptySpans();
return aRet;
}
void TableValues::swap( TableValues& rOther )
{
std::swap(mpImpl, rOther.mpImpl);
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */