364 lines
11 KiB
C++
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: */
|