diff options
Diffstat (limited to 'sc/source/core/data/cellvalues.cxx')
-rw-r--r-- | sc/source/core/data/cellvalues.cxx | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/sc/source/core/data/cellvalues.cxx b/sc/source/core/data/cellvalues.cxx new file mode 100644 index 000000000..290dc0d09 --- /dev/null +++ b/sc/source/core/data/cellvalues.cxx @@ -0,0 +1,357 @@ +/* -*- 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 <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::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: */ |