Files
loongoffice/sc/source/core/data/cellvalues.cxx
Kohei Yoshida dd617c0bbe New feature to allow converting formula cells to static values.
You used to have to convert formula cells to static values by copying
them and pasting them as values onto the original place.  Why not just
allow converting them in place?

This is something I've always wanted to implement.
2014-10-02 21:32:24 -04:00

375 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 <cellvalues.hxx>
#include <column.hxx>
#include <cellvalue.hxx>
#include <cassert>
#include <boost/noncopyable.hpp>
namespace sc {
namespace {
struct BlockPos
{
size_t mnStart;
size_t mnEnd;
};
CellType toCellType( mdds::mtv::element_t eType )
{
switch (eType)
{
case element_type_numeric:
return CELLTYPE_VALUE;
case element_type_string:
return CELLTYPE_STRING;
case element_type_edittext:
return CELLTYPE_EDIT;
case element_type_formula:
return CELLTYPE_FORMULA;
default:
;
}
return CELLTYPE_NONE;
}
}
CellValueSpan::CellValueSpan( SCROW nRow1, SCROW nRow2, CellType eType ) :
mnRow1(nRow1), mnRow2(nRow2), meType(eType) {}
struct CellValuesImpl : boost::noncopyable
{
CellStoreType maCells;
CellTextAttrStoreType maCellTextAttrs;
CellStoreType::iterator miCellPos;
CellTextAttrStoreType::iterator miAttrPos;
};
CellValues::CellValues() :
mpImpl(new CellValuesImpl) {}
CellValues::~CellValues()
{
delete mpImpl;
}
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::transferTo( ScColumn& rCol, SCROW nRow )
{
assert(mpImpl->maCells.size() == mpImpl->maCellTextAttrs.size());
size_t nLen = mpImpl->maCells.size();
mpImpl->maCells.transfer(0, nLen-1, rCol.maCells, nRow);
mpImpl->maCellTextAttrs.transfer(0, nLen-1, rCol.maCellTextAttrs, nRow);
}
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.
sc::CellStoreType::const_iterator it = mpImpl->maCells.begin(), itEnd = mpImpl->maCells.end();
for (; it != itEnd; ++it)
{
if (it->type == sc::element_type_empty)
continue;
BlockPos aPos;
aPos.mnStart = it->position;
aPos.mnEnd = aPos.mnStart + it->size - 1;
aBlocksToSwap.push_back(aPos);
}
}
// Do the swapping. The undo storage will store the replaced formula cells after this.
std::vector<BlockPos>::const_iterator it = aBlocksToSwap.begin(), itEnd = aBlocksToSwap.end();
for (; it != itEnd; ++it)
{
rCol.maCells.swap(it->mnStart, it->mnEnd, mpImpl->maCells, it->mnStart);
rCol.maCellTextAttrs.swap(it->mnStart, it->mnEnd, mpImpl->maCellTextAttrs, it->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());
}
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;
CellStoreType::const_iterator it = mpImpl->maCells.begin(), itEnd = mpImpl->maCells.end();
for (; it != itEnd; ++it)
{
if (it->type != element_type_empty)
{
// Record this span.
size_t nRow1 = it->position;
size_t nRow2 = nRow1 + it->size - 1;
aRet.push_back(CellValueSpan(nRow1, nRow2, toCellType(it->type)));
}
}
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();
CellStoreType::const_iterator itBlk = rSrc.begin(), itBlkEnd = rSrc.end();
for (; itBlk != itBlkEnd; ++itBlk)
{
switch (itBlk->type)
{
case element_type_numeric:
{
numeric_block::const_iterator it = numeric_block::begin(*itBlk->data);
numeric_block::const_iterator itEnd = numeric_block::end(*itBlk->data);
itPos = rDest.set(itPos, nCurRow, it, itEnd);
}
break;
case element_type_string:
{
string_block::const_iterator it = string_block::begin(*itBlk->data);
string_block::const_iterator itEnd = string_block::end(*itBlk->data);
itPos = rDest.set(itPos, nCurRow, it, itEnd);
}
break;
case element_type_edittext:
{
edittext_block::const_iterator it = edittext_block::begin(*itBlk->data);
edittext_block::const_iterator itEnd = edittext_block::end(*itBlk->data);
std::vector<EditTextObject*> aVals;
aVals.reserve(itBlk->size);
for (; it != itEnd; ++it)
{
const EditTextObject* p = *it;
aVals.push_back(p->Clone());
}
itPos = rDest.set(itPos, nCurRow, aVals.begin(), aVals.end());
}
break;
case element_type_formula:
{
formula_block::const_iterator it = formula_block::begin(*itBlk->data);
formula_block::const_iterator itEnd = formula_block::end(*itBlk->data);
std::vector<ScFormulaCell*> aVals;
aVals.reserve(itBlk->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+itBlk->size-1);
}
nCurRow += itBlk->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();
CellTextAttrStoreType::const_iterator itBlk = rSrc.begin(), itBlkEnd = rSrc.end();
for (; itBlk != itBlkEnd; ++itBlk)
{
switch (itBlk->type)
{
case element_type_celltextattr:
{
celltextattr_block::const_iterator it = celltextattr_block::begin(*itBlk->data);
celltextattr_block::const_iterator itEnd = celltextattr_block::end(*itBlk->data);
itPos = rDest.set(itPos, nCurRow, it, itEnd);
}
break;
default:
itPos = rDest.set_empty(itPos, nCurRow, nCurRow+itBlk->size-1);
}
nCurRow += itBlk->size;
}
}
typedef boost::ptr_vector<CellValues> TableType;
typedef boost::ptr_vector<TableType> TablesType;
struct TableValues::Impl
{
ScRange maRange;
TablesType maTables;
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)
{
maTables.push_back(new TableType);
TableType& rTab = maTables.back();
for (size_t nCol = 0; nCol < nCols; ++nCol)
rTab.push_back(new CellValues);
}
}
CellValues* getCellValues( SCTAB nTab, SCCOL nCol )
{
if (nTab < maRange.aStart.Tab() || maRange.aEnd.Tab() < nTab)
// sheet index out of bound.
return NULL;
if (nCol < maRange.aStart.Col() || maRange.aEnd.Col() < nCol)
// column index out of bound.
return NULL;
size_t nTabOffset = nTab - maRange.aStart.Tab();
if (nTabOffset >= maTables.size())
return NULL;
TableType& rTab = maTables[nTab-maRange.aStart.Tab()];
size_t nColOffset = nCol - maRange.aStart.Col();
if (nColOffset >= rTab.size())
return NULL;
return &rTab[nColOffset];
}
};
TableValues::TableValues() :
mpImpl(new Impl(ScRange(ScAddress::INITIALIZE_INVALID))) {}
TableValues::TableValues( const ScRange& rRange ) :
mpImpl(new Impl(rRange)) {}
TableValues::~TableValues()
{
delete mpImpl;
}
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: */