/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include namespace { CellType adjustCellType( CellType eOrig ) { switch (eOrig) { case CELLTYPE_EDIT: return CELLTYPE_STRING; default: ; } return eOrig; } template OUString getString( const T& rVal ) { if (rVal.getType() == CELLTYPE_STRING) return rVal.getSharedString()->getString(); if (rVal.getType() == CELLTYPE_EDIT) { OUStringBuffer aRet; sal_Int32 n = rVal.getEditText()->GetParagraphCount(); for (sal_Int32 i = 0; i < n; ++i) { if (i > 0) aRet.append('\n'); aRet.append(rVal.getEditText()->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 bool equalsWithoutFormatImpl( const T& left, const T& right ) { CellType eType1 = adjustCellType(left.getType()); CellType eType2 = adjustCellType(right.getType()); if (eType1 != eType2) return false; switch (eType1) { case CELLTYPE_NONE: return true; case CELLTYPE_VALUE: return left.getDouble() == right.getDouble(); case CELLTYPE_STRING: { OUString aStr1 = getString(left); OUString aStr2 = getString(right); return aStr1 == aStr2; } case CELLTYPE_FORMULA: return equalsFormulaCells(left.getFormula(), right.getFormula()); default: ; } return false; } bool equalsWithoutFormatImpl( const ScCellValue& left, const ScCellValue& right ) { CellType eType1 = adjustCellType(left.getType()); CellType eType2 = adjustCellType(right.getType()); if (eType1 != eType2) return false; switch (eType1) { case CELLTYPE_NONE: return true; case CELLTYPE_VALUE: return left.getDouble() == right.getDouble(); case CELLTYPE_STRING: { OUString aStr1 = getString(left); OUString aStr2 = getString(right); return aStr1 == aStr2; } case CELLTYPE_FORMULA: return equalsFormulaCells(left.getFormula(), right.getFormula()); default: ; } return false; } void commitToColumn( const ScCellValue& rCell, ScColumn& rColumn, SCROW nRow ) { switch (rCell.getType()) { case CELLTYPE_STRING: rColumn.SetRawString(nRow, *rCell.getSharedString()); break; case CELLTYPE_EDIT: rColumn.SetEditText(nRow, ScEditUtil::Clone(*rCell.getEditText(), rColumn.GetDoc())); break; case CELLTYPE_VALUE: rColumn.SetValue(nRow, rCell.getDouble()); break; case CELLTYPE_FORMULA: { ScAddress aDestPos(rColumn.GetCol(), nRow, rColumn.GetTab()); rColumn.SetFormulaCell(nRow, new ScFormulaCell(*rCell.getFormula(), 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 OUString getStringImpl( const T& rCell, const ScDocument* pDoc ) { switch (rCell.getType()) { case CELLTYPE_VALUE: return OUString::number(rCell.getDouble()); case CELLTYPE_STRING: return rCell.getSharedString()->getString(); case CELLTYPE_EDIT: if (rCell.getEditText()) return ScEditUtil::GetString(*rCell.getEditText(), pDoc); break; case CELLTYPE_FORMULA: return rCell.getFormula()->GetString().getString(); default: ; } return OUString(); } template OUString getRawStringImpl( const CellT& rCell, const ScDocument& rDoc ) { switch (rCell.getType()) { case CELLTYPE_VALUE: return OUString::number(rCell.getDouble()); case CELLTYPE_STRING: return rCell.getSharedString()->getString(); case CELLTYPE_EDIT: if (rCell.getEditText()) return ScEditUtil::GetString(*rCell.getEditText(), &rDoc); break; case CELLTYPE_FORMULA: return rCell.getFormula()->GetRawString().getString(); default: ; } return OUString(); } } ScCellValue::ScCellValue() {} ScCellValue::ScCellValue( const ScRefCellValue& rCell ) { switch (rCell.getType()) { case CELLTYPE_STRING: maData = *rCell.getSharedString(); break; case CELLTYPE_EDIT: maData = rCell.getEditText()->Clone().release(); break; case CELLTYPE_FORMULA: maData = rCell.getFormula()->Clone(); break; case CELLTYPE_VALUE: maData = rCell.getDouble(); break; default: ; } } ScCellValue::ScCellValue( double fValue ) : maData(fValue) {} ScCellValue::ScCellValue( const svl::SharedString& rString ) : maData(rString) {} ScCellValue::ScCellValue( std::unique_ptr xEdit ) : maData(xEdit.release()) {} ScCellValue::ScCellValue( const ScCellValue& r ) { switch (r.getType()) { case CELLTYPE_STRING: maData = *r.getSharedString(); break; case CELLTYPE_EDIT: maData = r.getEditText()->Clone().release(); break; case CELLTYPE_FORMULA: maData = r.getFormula()->Clone(); break; case CELLTYPE_VALUE: maData = r.getDouble(); break; default: ; } } void ScCellValue::reset_to_empty() { suppress_fun_call_w_exception(maData = std::monostate()); // reset to empty; } ScCellValue::ScCellValue(ScCellValue&& r) noexcept : maData(std::move(r.maData)) { r.reset_to_empty(); } ScCellValue::~ScCellValue() { clear(); } CellType ScCellValue::getType() const { switch (maData.index()) { case 0: return CELLTYPE_NONE; case 1: return CELLTYPE_VALUE; case 2: return CELLTYPE_STRING; case 3: return CELLTYPE_EDIT; case 4: return CELLTYPE_FORMULA; default: assert(false); return CELLTYPE_NONE; } } void ScCellValue::clear() noexcept { switch (getType()) { case CELLTYPE_EDIT: suppress_fun_call_w_exception(delete getEditText()); break; case CELLTYPE_FORMULA: suppress_fun_call_w_exception(delete getFormula()); break; default: ; } // Reset to empty value. reset_to_empty(); } void ScCellValue::set( double fValue ) { clear(); maData = fValue; } void ScCellValue::set( const svl::SharedString& rStr ) { clear(); maData = rStr; } void ScCellValue::set( const EditTextObject& rEditText ) { clear(); maData = rEditText.Clone().release(); } void ScCellValue::set( std::unique_ptr xEditText ) { clear(); maData = xEditText.release(); } void ScCellValue::set( ScFormulaCell* pFormula ) { clear(); maData = pFormula; } void ScCellValue::assign( const ScDocument& rDoc, const ScAddress& rPos ) { clear(); ScRefCellValue aRefVal(const_cast(rDoc), rPos); switch (aRefVal.getType()) { case CELLTYPE_STRING: maData = *aRefVal.getSharedString(); break; case CELLTYPE_EDIT: maData = aRefVal.getEditText() ? aRefVal.getEditText()->Clone().release() : static_cast(nullptr); break; case CELLTYPE_VALUE: maData = aRefVal.getDouble(); break; case CELLTYPE_FORMULA: maData = aRefVal.getFormula()->Clone(); break; default: ; // leave empty } } void ScCellValue::assign(const ScCellValue& rOther, ScDocument& rDestDoc, ScCloneFlags nCloneFlags) { clear(); switch (rOther.getType()) { case CELLTYPE_STRING: maData = rOther.maData; break; case CELLTYPE_EDIT: { // Switch to the pool of the destination document. ScFieldEditEngine& rEngine = rDestDoc.GetEditEngine(); if (rOther.getEditText()->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.getEditText()); maData = rEngine.CreateTextObject().release(); if (bNewControl) rEngine.SetControlWord(nControl); } else { rEngine.SetTextCurrentDefaults(*rOther.getEditText()); maData = rEngine.CreateTextObject().release(); } } break; case CELLTYPE_VALUE: maData = rOther.maData; break; case CELLTYPE_FORMULA: // Switch to the destination document. maData = new ScFormulaCell(*rOther.getFormula(), rDestDoc, rOther.getFormula()->aPos, nCloneFlags); break; default: ; // leave empty } } void ScCellValue::commit( ScDocument& rDoc, const ScAddress& rPos ) const { switch (getType()) { case CELLTYPE_STRING: { ScSetStringParam aParam; aParam.setTextInput(); rDoc.SetString(rPos, getSharedString()->getString(), &aParam); } break; case CELLTYPE_EDIT: rDoc.SetEditText(rPos, getEditText()->Clone()); break; case CELLTYPE_VALUE: rDoc.SetValue(rPos, getDouble()); break; case CELLTYPE_FORMULA: rDoc.SetFormulaCell(rPos, getFormula()->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 (getType()) { case CELLTYPE_STRING: { // Currently, string cannot be placed without copying. ScSetStringParam aParam; aParam.setTextInput(); rDoc.SetString(rPos, getSharedString()->getString(), &aParam); } break; case CELLTYPE_EDIT: // Cell takes the ownership of the text object. rDoc.SetEditText(rPos, std::unique_ptr(getEditText())); break; case CELLTYPE_VALUE: rDoc.SetValue(rPos, getDouble()); break; case CELLTYPE_FORMULA: // This formula cell instance is directly placed in the document without copying. rDoc.SetFormulaCell(rPos, getFormula()); break; default: rDoc.SetEmptyCell(rPos); } reset_to_empty(); // reset to empty } void ScCellValue::release( ScColumn& rColumn, SCROW nRow, sc::StartListeningType eListenType ) { switch (getType()) { case CELLTYPE_STRING: { // Currently, string cannot be placed without copying. rColumn.SetRawString(nRow, *getSharedString()); } break; case CELLTYPE_EDIT: // Cell takes the ownership of the text object. rColumn.SetEditText(nRow, std::unique_ptr(getEditText())); break; case CELLTYPE_VALUE: rColumn.SetValue(nRow, getDouble()); break; case CELLTYPE_FORMULA: // This formula cell instance is directly placed in the document without copying. rColumn.SetFormulaCell(nRow, getFormula(), eListenType); break; default: rColumn.DeleteContent(nRow); } reset_to_empty(); // reset to empty } OUString ScCellValue::getString( const ScDocument& rDoc ) const { return getStringImpl(*this, &rDoc); } bool ScCellValue::isEmpty() const { return getType() == 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(); maData = std::move(rCell.maData); rCell.reset_to_empty(); // reset to empty; return *this; } ScCellValue& ScCellValue::operator= ( const ScRefCellValue& r ) { ScCellValue aTmp(r); swap(aTmp); return *this; } void ScCellValue::swap( ScCellValue& r ) { std::swap(maData, r.maData); } 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: */