summaryrefslogtreecommitdiffstats
path: root/sc/source/core/data/cellvalue.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/data/cellvalue.cxx')
-rw-r--r--sc/source/core/data/cellvalue.cxx691
1 files changed, 691 insertions, 0 deletions
diff --git a/sc/source/core/data/cellvalue.cxx b/sc/source/core/data/cellvalue.cxx
new file mode 100644
index 000000000..64cd34e32
--- /dev/null
+++ b/sc/source/core/data/cellvalue.cxx
@@ -0,0 +1,691 @@
+/* -*- 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 <cellvalue.hxx>
+#include <document.hxx>
+#include <column.hxx>
+#include <formulacell.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+#include <stringutil.hxx>
+#include <editutil.hxx>
+#include <tokenarray.hxx>
+#include <formula/token.hxx>
+#include <formula/errorcodes.hxx>
+#include <svl/sharedstring.hxx>
+
+namespace {
+
+CellType adjustCellType( CellType eOrig )
+{
+ switch (eOrig)
+ {
+ case CELLTYPE_EDIT:
+ return CELLTYPE_STRING;
+ default:
+ ;
+ }
+ return eOrig;
+}
+
+template<typename T>
+OUString getString( const T& rVal )
+{
+ if (rVal.meType == CELLTYPE_STRING)
+ return rVal.mpString->getString();
+
+ if (rVal.meType == CELLTYPE_EDIT)
+ {
+ OUStringBuffer aRet;
+ sal_Int32 n = rVal.mpEditText->GetParagraphCount();
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ if (i > 0)
+ aRet.append('\n');
+ aRet.append(rVal.mpEditText->GetText(i));
+ }
+ return aRet.makeStringAndClear();
+ }
+
+ return OUString();
+}
+
+bool equalsFormulaCells( const ScFormulaCell* p1, const ScFormulaCell* p2 )
+{
+ const ScTokenArray* pCode1 = p1->GetCode();
+ const ScTokenArray* pCode2 = p2->GetCode();
+
+ if (pCode1->GetLen() != pCode2->GetLen())
+ return false;
+
+ if (pCode1->GetCodeError() != pCode2->GetCodeError())
+ return false;
+
+ sal_uInt16 n = pCode1->GetLen();
+ formula::FormulaToken** ppToken1 = pCode1->GetArray();
+ formula::FormulaToken** ppToken2 = pCode2->GetArray();
+ for (sal_uInt16 i = 0; i < n; ++i)
+ {
+ if (!ppToken1[i]->TextEqual(*(ppToken2[i])))
+ return false;
+ }
+
+ return true;
+}
+
+template<typename T>
+bool equalsWithoutFormatImpl( const T& left, const T& right )
+{
+ CellType eType1 = adjustCellType(left.meType);
+ CellType eType2 = adjustCellType(right.meType);
+ if (eType1 != eType2)
+ return false;
+
+ switch (eType1)
+ {
+ case CELLTYPE_NONE:
+ return true;
+ case CELLTYPE_VALUE:
+ return left.mfValue == right.mfValue;
+ case CELLTYPE_STRING:
+ {
+ OUString aStr1 = getString(left);
+ OUString aStr2 = getString(right);
+ return aStr1 == aStr2;
+ }
+ case CELLTYPE_FORMULA:
+ return equalsFormulaCells(left.mpFormula, right.mpFormula);
+ default:
+ ;
+ }
+ return false;
+}
+
+void commitToColumn( const ScCellValue& rCell, ScColumn& rColumn, SCROW nRow )
+{
+ switch (rCell.meType)
+ {
+ case CELLTYPE_STRING:
+ rColumn.SetRawString(nRow, *rCell.mpString);
+ break;
+ case CELLTYPE_EDIT:
+ rColumn.SetEditText(nRow, ScEditUtil::Clone(*rCell.mpEditText, rColumn.GetDoc()));
+ break;
+ case CELLTYPE_VALUE:
+ rColumn.SetValue(nRow, rCell.mfValue);
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScAddress aDestPos(rColumn.GetCol(), nRow, rColumn.GetTab());
+ rColumn.SetFormulaCell(nRow, new ScFormulaCell(*rCell.mpFormula, rColumn.GetDoc(), aDestPos));
+ }
+ break;
+ default:
+ rColumn.DeleteContent(nRow);
+ }
+}
+
+bool hasStringImpl( CellType eType, ScFormulaCell* pFormula )
+{
+ switch (eType)
+ {
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ return true;
+ case CELLTYPE_FORMULA:
+ return !pFormula->IsValue();
+ default:
+ return false;
+ }
+}
+
+bool hasNumericImpl( CellType eType, ScFormulaCell* pFormula )
+{
+ switch (eType)
+ {
+ case CELLTYPE_VALUE:
+ return true;
+ case CELLTYPE_FORMULA:
+ return pFormula->IsValue();
+ default:
+ return false;
+ }
+}
+
+template<typename CellT>
+OUString getStringImpl( const CellT& rCell, const ScDocument* pDoc )
+{
+ switch (rCell.meType)
+ {
+ case CELLTYPE_VALUE:
+ return OUString::number(rCell.mfValue);
+ case CELLTYPE_STRING:
+ return rCell.mpString->getString();
+ case CELLTYPE_EDIT:
+ if (rCell.mpEditText)
+ return ScEditUtil::GetString(*rCell.mpEditText, pDoc);
+ break;
+ case CELLTYPE_FORMULA:
+ return rCell.mpFormula->GetString().getString();
+ default:
+ ;
+ }
+ return OUString();
+}
+
+template<typename CellT>
+OUString getRawStringImpl( const CellT& rCell, const ScDocument& rDoc )
+{
+ switch (rCell.meType)
+ {
+ case CELLTYPE_VALUE:
+ return OUString::number(rCell.mfValue);
+ case CELLTYPE_STRING:
+ return rCell.mpString->getString();
+ case CELLTYPE_EDIT:
+ if (rCell.mpEditText)
+ return ScEditUtil::GetString(*rCell.mpEditText, &rDoc);
+ break;
+ case CELLTYPE_FORMULA:
+ return rCell.mpFormula->GetRawString().getString();
+ default:
+ ;
+ }
+ return OUString();
+}
+
+}
+
+ScCellValue::ScCellValue() : meType(CELLTYPE_NONE), mfValue(0.0) {}
+
+ScCellValue::ScCellValue( const ScRefCellValue& rCell ) : meType(rCell.meType), mfValue(rCell.mfValue)
+{
+ switch (rCell.meType)
+ {
+ case CELLTYPE_STRING:
+ mpString = new svl::SharedString(*rCell.mpString);
+ break;
+ case CELLTYPE_EDIT:
+ mpEditText = rCell.mpEditText->Clone().release();
+ break;
+ case CELLTYPE_FORMULA:
+ mpFormula = rCell.mpFormula->Clone();
+ break;
+ default:
+ ;
+ }
+}
+
+ScCellValue::ScCellValue( double fValue ) : meType(CELLTYPE_VALUE), mfValue(fValue) {}
+
+ScCellValue::ScCellValue( const svl::SharedString& rString ) : meType(CELLTYPE_STRING), mpString(new svl::SharedString(rString)) {}
+
+ScCellValue::ScCellValue( const ScCellValue& r ) : meType(r.meType), mfValue(r.mfValue)
+{
+ switch (r.meType)
+ {
+ case CELLTYPE_STRING:
+ mpString = new svl::SharedString(*r.mpString);
+ break;
+ case CELLTYPE_EDIT:
+ mpEditText = r.mpEditText->Clone().release();
+ break;
+ case CELLTYPE_FORMULA:
+ mpFormula = r.mpFormula->Clone();
+ break;
+ default:
+ ;
+ }
+}
+
+ScCellValue::ScCellValue(ScCellValue&& r) noexcept
+ : meType(r.meType)
+ , mfValue(r.mfValue)
+{
+ switch (r.meType)
+ {
+ case CELLTYPE_STRING:
+ mpString = r.mpString;
+ break;
+ case CELLTYPE_EDIT:
+ mpEditText = r.mpEditText;
+ break;
+ case CELLTYPE_FORMULA:
+ mpFormula = r.mpFormula;
+ break;
+ default:
+ ;
+ }
+ r.meType = CELLTYPE_NONE;
+}
+
+ScCellValue::~ScCellValue()
+{
+ clear();
+}
+
+void ScCellValue::clear() noexcept
+{
+ switch (meType)
+ {
+ case CELLTYPE_STRING:
+ delete mpString;
+ break;
+ case CELLTYPE_EDIT:
+ delete mpEditText;
+ break;
+ case CELLTYPE_FORMULA:
+ delete mpFormula;
+ break;
+ default:
+ ;
+ }
+
+ // Reset to empty value.
+ meType = CELLTYPE_NONE;
+ mfValue = 0.0;
+}
+
+void ScCellValue::set( double fValue )
+{
+ clear();
+ meType = CELLTYPE_VALUE;
+ mfValue = fValue;
+}
+
+void ScCellValue::set( const svl::SharedString& rStr )
+{
+ clear();
+ meType = CELLTYPE_STRING;
+ mpString = new svl::SharedString(rStr);
+}
+
+void ScCellValue::set( const EditTextObject& rEditText )
+{
+ clear();
+ meType = CELLTYPE_EDIT;
+ mpEditText = rEditText.Clone().release();
+}
+
+void ScCellValue::set( EditTextObject* pEditText )
+{
+ clear();
+ meType = CELLTYPE_EDIT;
+ mpEditText = pEditText;
+}
+
+void ScCellValue::set( ScFormulaCell* pFormula )
+{
+ clear();
+ meType = CELLTYPE_FORMULA;
+ mpFormula = pFormula;
+}
+
+void ScCellValue::assign( const ScDocument& rDoc, const ScAddress& rPos )
+{
+ clear();
+
+ ScRefCellValue aRefVal(const_cast<ScDocument&>(rDoc), rPos);
+
+ meType = aRefVal.meType;
+ switch (meType)
+ {
+ case CELLTYPE_STRING:
+ mpString = new svl::SharedString(*aRefVal.mpString);
+ break;
+ case CELLTYPE_EDIT:
+ if (aRefVal.mpEditText)
+ mpEditText = aRefVal.mpEditText->Clone().release();
+ break;
+ case CELLTYPE_VALUE:
+ mfValue = aRefVal.mfValue;
+ break;
+ case CELLTYPE_FORMULA:
+ mpFormula = aRefVal.mpFormula->Clone();
+ break;
+ default:
+ meType = CELLTYPE_NONE; // reset to empty.
+ }
+}
+
+void ScCellValue::assign(const ScCellValue& rOther, ScDocument& rDestDoc, ScCloneFlags nCloneFlags)
+{
+ clear();
+
+ meType = rOther.meType;
+ switch (meType)
+ {
+ case CELLTYPE_STRING:
+ mpString = new svl::SharedString(*rOther.mpString);
+ break;
+ case CELLTYPE_EDIT:
+ {
+ // Switch to the pool of the destination document.
+ ScFieldEditEngine& rEngine = rDestDoc.GetEditEngine();
+ if (rOther.mpEditText->HasOnlineSpellErrors())
+ {
+ EEControlBits nControl = rEngine.GetControlWord();
+ const EEControlBits nSpellControl = EEControlBits::ONLINESPELLING | EEControlBits::ALLOWBIGOBJS;
+ bool bNewControl = ((nControl & nSpellControl) != nSpellControl);
+ if (bNewControl)
+ rEngine.SetControlWord(nControl | nSpellControl);
+ rEngine.SetTextCurrentDefaults(*rOther.mpEditText);
+ mpEditText = rEngine.CreateTextObject().release();
+ if (bNewControl)
+ rEngine.SetControlWord(nControl);
+ }
+ else
+ {
+ rEngine.SetTextCurrentDefaults(*rOther.mpEditText);
+ mpEditText = rEngine.CreateTextObject().release();
+ }
+ }
+ break;
+ case CELLTYPE_VALUE:
+ mfValue = rOther.mfValue;
+ break;
+ case CELLTYPE_FORMULA:
+ // Switch to the destination document.
+ mpFormula = new ScFormulaCell(*rOther.mpFormula, rDestDoc, rOther.mpFormula->aPos, nCloneFlags);
+ break;
+ default:
+ meType = CELLTYPE_NONE; // reset to empty.
+ }
+}
+
+void ScCellValue::commit( ScDocument& rDoc, const ScAddress& rPos ) const
+{
+ switch (meType)
+ {
+ case CELLTYPE_STRING:
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(rPos, mpString->getString(), &aParam);
+ }
+ break;
+ case CELLTYPE_EDIT:
+ rDoc.SetEditText(rPos, mpEditText->Clone());
+ break;
+ case CELLTYPE_VALUE:
+ rDoc.SetValue(rPos, mfValue);
+ break;
+ case CELLTYPE_FORMULA:
+ rDoc.SetFormulaCell(rPos, mpFormula->Clone());
+ break;
+ default:
+ rDoc.SetEmptyCell(rPos);
+ }
+}
+
+void ScCellValue::commit( ScColumn& rColumn, SCROW nRow ) const
+{
+ commitToColumn(*this, rColumn, nRow);
+}
+
+void ScCellValue::release( ScDocument& rDoc, const ScAddress& rPos )
+{
+ switch (meType)
+ {
+ case CELLTYPE_STRING:
+ {
+ // Currently, string cannot be placed without copying.
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(rPos, mpString->getString(), &aParam);
+ delete mpString;
+ }
+ break;
+ case CELLTYPE_EDIT:
+ // Cell takes the ownership of the text object.
+ rDoc.SetEditText(rPos, std::unique_ptr<EditTextObject>(mpEditText));
+ break;
+ case CELLTYPE_VALUE:
+ rDoc.SetValue(rPos, mfValue);
+ break;
+ case CELLTYPE_FORMULA:
+ // This formula cell instance is directly placed in the document without copying.
+ rDoc.SetFormulaCell(rPos, mpFormula);
+ break;
+ default:
+ rDoc.SetEmptyCell(rPos);
+ }
+
+ meType = CELLTYPE_NONE;
+ mfValue = 0.0;
+}
+
+void ScCellValue::release( ScColumn& rColumn, SCROW nRow, sc::StartListeningType eListenType )
+{
+ switch (meType)
+ {
+ case CELLTYPE_STRING:
+ {
+ // Currently, string cannot be placed without copying.
+ rColumn.SetRawString(nRow, *mpString);
+ delete mpString;
+ }
+ break;
+ case CELLTYPE_EDIT:
+ // Cell takes the ownership of the text object.
+ rColumn.SetEditText(nRow, std::unique_ptr<EditTextObject>(mpEditText));
+ break;
+ case CELLTYPE_VALUE:
+ rColumn.SetValue(nRow, mfValue);
+ break;
+ case CELLTYPE_FORMULA:
+ // This formula cell instance is directly placed in the document without copying.
+ rColumn.SetFormulaCell(nRow, mpFormula, eListenType);
+ break;
+ default:
+ rColumn.DeleteContent(nRow);
+ }
+
+ meType = CELLTYPE_NONE;
+ mfValue = 0.0;
+}
+
+OUString ScCellValue::getString( const ScDocument& rDoc ) const
+{
+ return getStringImpl(*this, &rDoc);
+}
+
+bool ScCellValue::isEmpty() const
+{
+ return meType == CELLTYPE_NONE;
+}
+
+bool ScCellValue::equalsWithoutFormat( const ScCellValue& r ) const
+{
+ return equalsWithoutFormatImpl(*this, r);
+}
+
+ScCellValue& ScCellValue::operator= ( const ScCellValue& r )
+{
+ ScCellValue aTmp(r);
+ swap(aTmp);
+ return *this;
+}
+
+ScCellValue& ScCellValue::operator=(ScCellValue&& rCell) noexcept
+{
+ clear();
+
+ meType = rCell.meType;
+ mfValue = rCell.mfValue;
+ switch (rCell.meType)
+ {
+ case CELLTYPE_STRING:
+ mpString = rCell.mpString;
+ break;
+ case CELLTYPE_EDIT:
+ mpEditText = rCell.mpEditText;
+ break;
+ case CELLTYPE_FORMULA:
+ mpFormula = rCell.mpFormula;
+ break;
+ default:
+ ;
+ }
+ //we don't need to reset mpString/mpEditText/mpFormula if we
+ //set meType to NONE as the ScCellValue dtor keys off the meType
+ rCell.meType = CELLTYPE_NONE;
+
+ return *this;
+}
+
+ScCellValue& ScCellValue::operator= ( const ScRefCellValue& r )
+{
+ ScCellValue aTmp(r);
+ swap(aTmp);
+ return *this;
+}
+
+void ScCellValue::swap( ScCellValue& r )
+{
+ std::swap(meType, r.meType);
+
+ // double is 8 bytes, whereas a pointer may be 4 or 8 bytes depending on
+ // the platform. Swap by double values.
+ std::swap(mfValue, r.mfValue);
+}
+
+ScRefCellValue::ScRefCellValue() : meType(CELLTYPE_NONE), mfValue(0.0) {}
+ScRefCellValue::ScRefCellValue( double fValue ) : meType(CELLTYPE_VALUE), mfValue(fValue) {}
+ScRefCellValue::ScRefCellValue( const svl::SharedString* pString ) : meType(CELLTYPE_STRING), mpString(pString) {}
+ScRefCellValue::ScRefCellValue( const EditTextObject* pEditText ) : meType(CELLTYPE_EDIT), mpEditText(pEditText) {}
+ScRefCellValue::ScRefCellValue( ScFormulaCell* pFormula ) : meType(CELLTYPE_FORMULA), mpFormula(pFormula) {}
+
+ScRefCellValue::ScRefCellValue( ScDocument& rDoc, const ScAddress& rPos )
+{
+ assign( rDoc, rPos);
+}
+
+ScRefCellValue::ScRefCellValue( ScDocument& rDoc, const ScAddress& rPos, sc::ColumnBlockPosition& rBlockPos )
+{
+ assign( rDoc, rPos, rBlockPos );
+}
+
+void ScRefCellValue::clear()
+{
+ // Reset to empty value.
+ meType = CELLTYPE_NONE;
+ mfValue = 0.0;
+}
+
+void ScRefCellValue::assign( ScDocument& rDoc, const ScAddress& rPos )
+{
+ *this = rDoc.GetRefCellValue(rPos);
+}
+
+void ScRefCellValue::assign( ScDocument& rDoc, const ScAddress& rPos, sc::ColumnBlockPosition& rBlockPos )
+{
+ *this = rDoc.GetRefCellValue(rPos, rBlockPos);
+}
+
+void ScRefCellValue::commit( ScDocument& rDoc, const ScAddress& rPos ) const
+{
+ switch (meType)
+ {
+ case CELLTYPE_STRING:
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(rPos, mpString->getString(), &aParam);
+ }
+ break;
+ case CELLTYPE_EDIT:
+ rDoc.SetEditText(rPos, ScEditUtil::Clone(*mpEditText, rDoc));
+ break;
+ case CELLTYPE_VALUE:
+ rDoc.SetValue(rPos, mfValue);
+ break;
+ case CELLTYPE_FORMULA:
+ rDoc.SetFormulaCell(rPos, new ScFormulaCell(*mpFormula, rDoc, rPos));
+ break;
+ default:
+ rDoc.SetEmptyCell(rPos);
+ }
+}
+
+bool ScRefCellValue::hasString() const
+{
+ return hasStringImpl(meType, mpFormula);
+}
+
+bool ScRefCellValue::hasNumeric() const
+{
+ return hasNumericImpl(meType, mpFormula);
+}
+
+bool ScRefCellValue::hasError() const
+{
+ return meType == CELLTYPE_FORMULA && mpFormula->GetErrCode() != FormulaError::NONE;
+}
+
+double ScRefCellValue::getValue()
+{
+ switch (meType)
+ {
+ case CELLTYPE_VALUE:
+ return mfValue;
+ case CELLTYPE_FORMULA:
+ return mpFormula->GetValue();
+ default:
+ ;
+ }
+ return 0.0;
+}
+
+double ScRefCellValue::getRawValue() const
+{
+ switch (meType)
+ {
+ case CELLTYPE_VALUE:
+ return mfValue;
+ case CELLTYPE_FORMULA:
+ return mpFormula->GetRawValue();
+ default:
+ ;
+ }
+ return 0.0;
+}
+
+OUString ScRefCellValue::getString( const ScDocument* pDoc ) const
+{
+ return getStringImpl(*this, pDoc);
+}
+
+OUString ScRefCellValue::getRawString( const ScDocument& rDoc ) const
+{
+ return getRawStringImpl(*this, rDoc);
+}
+
+bool ScRefCellValue::isEmpty() const
+{
+ return meType == CELLTYPE_NONE;
+}
+
+bool ScRefCellValue::hasEmptyValue()
+{
+ if (isEmpty())
+ return true;
+
+ if (meType == CELLTYPE_FORMULA)
+ return mpFormula->IsEmpty();
+
+ return false;
+}
+
+bool ScRefCellValue::equalsWithoutFormat( const ScRefCellValue& r ) const
+{
+ return equalsWithoutFormatImpl(*this, r);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */