summaryrefslogtreecommitdiffstats
path: root/sc/source/core/data/cellvalues.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/data/cellvalues.cxx')
-rw-r--r--sc/source/core/data/cellvalues.cxx357
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: */