diff options
Diffstat (limited to 'sc/source/core/data/clipcontext.cxx')
-rw-r--r-- | sc/source/core/data/clipcontext.cxx | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/sc/source/core/data/clipcontext.cxx b/sc/source/core/data/clipcontext.cxx new file mode 100644 index 000000000..f83ee2c9a --- /dev/null +++ b/sc/source/core/data/clipcontext.cxx @@ -0,0 +1,440 @@ +/* -*- 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 <clipcontext.hxx> +#include <document.hxx> +#include <mtvelements.hxx> +#include <column.hxx> +#include <scitems.hxx> +#include <tokenarray.hxx> +#include <editutil.hxx> +#include <clipparam.hxx> + +#include <svl/intitem.hxx> +#include <svl/numformat.hxx> +#include <formula/errorcodes.hxx> +#include <refdata.hxx> +#include <listenercontext.hxx> + +namespace sc { + +ClipContextBase::ClipContextBase(ScDocument& rDoc) : + mpSet(new ColumnBlockPositionSet(rDoc)) {} + +ClipContextBase::~ClipContextBase() {} + +ColumnBlockPosition* ClipContextBase::getBlockPosition(SCTAB nTab, SCCOL nCol) +{ + return mpSet->getBlockPosition(nTab, nCol); +} + +CopyFromClipContext::CopyFromClipContext(ScDocument& rDoc, + ScDocument* pRefUndoDoc, ScDocument* pClipDoc, InsertDeleteFlags nInsertFlag, + bool bAsLink, bool bSkipEmptyCells) : + ClipContextBase(rDoc), + mnDestCol1(-1), mnDestCol2(-1), + mnDestRow1(-1), mnDestRow2(-1), + mnTabStart(-1), mnTabEnd(-1), + mrDestDoc(rDoc), + mpRefUndoDoc(pRefUndoDoc), mpClipDoc(pClipDoc), + mnInsertFlag(nInsertFlag), mnDeleteFlag(InsertDeleteFlags::NONE), + mpCondFormatList(nullptr), + mbAsLink(bAsLink), mbSkipEmptyCells(bSkipEmptyCells), + mbTableProtected(false) +{ +} + +CopyFromClipContext::~CopyFromClipContext() +{ +} + +void CopyFromClipContext::setTabRange(SCTAB nStart, SCTAB nEnd) +{ + mnTabStart = nStart; + mnTabEnd = nEnd; +} + +SCTAB CopyFromClipContext::getTabStart() const +{ + return mnTabStart; +} + +SCTAB CopyFromClipContext::getTabEnd() const +{ + return mnTabEnd; +} + +void CopyFromClipContext::setDestRange( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) +{ + mnDestCol1 = nCol1; + mnDestRow1 = nRow1; + mnDestCol2 = nCol2; + mnDestRow2 = nRow2; +} + +CopyFromClipContext::Range CopyFromClipContext::getDestRange() const +{ + Range aRet; + aRet.mnCol1 = mnDestCol1; + aRet.mnCol2 = mnDestCol2; + aRet.mnRow1 = mnDestRow1; + aRet.mnRow2 = mnDestRow2; + return aRet; +} + +ScDocument* CopyFromClipContext::getUndoDoc() +{ + return mpRefUndoDoc; +} + +ScDocument* CopyFromClipContext::getClipDoc() +{ + return mpClipDoc; +} + +InsertDeleteFlags CopyFromClipContext::getInsertFlag() const +{ + return mnInsertFlag; +} + +void CopyFromClipContext::setDeleteFlag( InsertDeleteFlags nFlag ) +{ + mnDeleteFlag = nFlag; +} + +InsertDeleteFlags CopyFromClipContext::getDeleteFlag() const +{ + return mnDeleteFlag; +} + +void CopyFromClipContext::setListeningFormulaSpans( + SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) +{ + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + maListeningFormulaSpans.set(mrDestDoc, nTab, nCol, nRow1, nRow2, true); +} + +namespace { + +class StartListeningAction : public sc::ColumnSpanSet::Action +{ + ScDocument& mrDestDoc; + sc::StartListeningContext& mrStartCxt; + sc::EndListeningContext& mrEndCxt; + +public: + StartListeningAction( ScDocument& rDestDoc, sc::StartListeningContext& rStartCxt, sc::EndListeningContext& rEndCxt ) : + mrDestDoc(rDestDoc), mrStartCxt(rStartCxt), mrEndCxt(rEndCxt) + { + } + + virtual void execute( const ScAddress& rPos, SCROW nLength, bool bVal ) override + { + if (!bVal) + return; + + SCROW nRow1 = rPos.Row(); + SCROW nRow2 = nRow1 + nLength - 1; + + mrDestDoc.StartListeningFromClip( + mrStartCxt, mrEndCxt, rPos.Tab(), rPos.Col(), nRow1, rPos.Col(), nRow2); + } +}; + +} + +void CopyFromClipContext::startListeningFormulas() +{ + auto pSet = std::make_shared<sc::ColumnBlockPositionSet>(mrDestDoc); + sc::StartListeningContext aStartCxt(mrDestDoc, pSet); + sc::EndListeningContext aEndCxt(mrDestDoc, pSet, nullptr); + + StartListeningAction aAction(mrDestDoc, aStartCxt, aEndCxt); + maListeningFormulaSpans.executeAction(mrDestDoc, aAction); +} + +void CopyFromClipContext::setSingleCellColumnSize( size_t nSize ) +{ + maSingleCells.resize(nSize); + maSingleCellAttrs.resize(nSize); + maSinglePatterns.resize(nSize, nullptr); + maSingleNotes.resize(nSize, nullptr); + maSingleSparkline.resize(nSize); +} + +ScCellValue& CopyFromClipContext::getSingleCell( size_t nColOffset ) +{ + assert(nColOffset < maSingleCells.size()); + return maSingleCells[nColOffset]; +} + +sc::CellTextAttr& CopyFromClipContext::getSingleCellAttr( size_t nColOffset ) +{ + assert(nColOffset < maSingleCellAttrs.size()); + return maSingleCellAttrs[nColOffset]; +} + +void CopyFromClipContext::setSingleCell( const ScAddress& rSrcPos, const ScColumn& rSrcCol ) +{ + SCCOL nColOffset = rSrcPos.Col() - mpClipDoc->GetClipParam().getWholeRange().aStart.Col(); + ScCellValue& rSrcCell = getSingleCell(nColOffset); + + const sc::CellTextAttr* pAttr = rSrcCol.GetCellTextAttr(rSrcPos.Row()); + + if (pAttr) + { + sc::CellTextAttr& rAttr = getSingleCellAttr(nColOffset); + rAttr = *pAttr; + } + + if (mbAsLink) + { + ScSingleRefData aRef; + aRef.InitAddress(rSrcPos); + aRef.SetFlag3D(true); + + ScTokenArray aArr(*mpClipDoc); + aArr.AddSingleReference(aRef); + rSrcCell.set(new ScFormulaCell(*mpClipDoc, rSrcPos, aArr)); + return; + } + + rSrcCell.assign(*mpClipDoc, rSrcPos); + + // Check the paste flag to see whether we want to paste this cell. If the + // flag says we don't want to paste this cell, we'll return with true. + InsertDeleteFlags nFlags = getInsertFlag(); + bool bNumeric = (nFlags & InsertDeleteFlags::VALUE) != InsertDeleteFlags::NONE; + bool bDateTime = (nFlags & InsertDeleteFlags::DATETIME) != InsertDeleteFlags::NONE; + bool bString = (nFlags & InsertDeleteFlags::STRING) != InsertDeleteFlags::NONE; + bool bBoolean = (nFlags & InsertDeleteFlags::SPECIAL_BOOLEAN) != InsertDeleteFlags::NONE; + bool bFormula = (nFlags & InsertDeleteFlags::FORMULA) != InsertDeleteFlags::NONE; + + switch (rSrcCell.meType) + { + case CELLTYPE_VALUE: + { + bool bPaste = isDateCell(rSrcCol, rSrcPos.Row()) ? bDateTime : bNumeric; + if (!bPaste) + // Don't paste this. + rSrcCell.clear(); + } + break; + case CELLTYPE_STRING: + case CELLTYPE_EDIT: + { + if (!bString) + // Skip pasting. + rSrcCell.clear(); + } + break; + case CELLTYPE_FORMULA: + { + if (bBoolean) + { + // Check if this formula cell is a boolean cell, and if so, go ahead and paste it. + const ScTokenArray* pCode = rSrcCell.mpFormula->GetCode(); + if (pCode && pCode->GetLen() == 1) + { + const formula::FormulaToken* p = pCode->FirstToken(); + if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse) + // This is a boolean formula. Good. + break; + } + } + + if (bFormula) + // Good. + break; + + FormulaError nErr = rSrcCell.mpFormula->GetErrCode(); + if (nErr != FormulaError::NONE) + { + // error codes are cloned with values + if (!bNumeric) + // Error code is treated as numeric value. Don't paste it. + rSrcCell.clear(); + else + { + // Turn this into a formula cell with just the error code. + ScFormulaCell* pErrCell = new ScFormulaCell(*mpClipDoc, rSrcPos); + pErrCell->SetErrCode(nErr); + rSrcCell.set(pErrCell); + } + } + else if (rSrcCell.mpFormula->IsEmptyDisplayedAsString()) + { + // Empty stays empty and doesn't become 0. + rSrcCell.clear(); + } + else if (rSrcCell.mpFormula->IsValue()) + { + bool bPaste = isDateCell(rSrcCol, rSrcPos.Row()) ? bDateTime : bNumeric; + if (!bPaste) + { + // Don't paste this. + rSrcCell.clear(); + break; + } + + // Turn this into a numeric cell. + rSrcCell.set(rSrcCell.mpFormula->GetValue()); + } + else if (bString) + { + svl::SharedString aStr = rSrcCell.mpFormula->GetString(); + if (aStr.isEmpty()) + { + // do not clone empty string + rSrcCell.clear(); + break; + } + + // Turn this into a string or edit cell. + if (rSrcCell.mpFormula->IsMultilineResult()) + { + // TODO : Add shared string support to the edit engine to + // make this process simpler. + ScFieldEditEngine& rEngine = mrDestDoc.GetEditEngine(); + rEngine.SetTextCurrentDefaults(rSrcCell.mpFormula->GetString().getString()); + std::unique_ptr<EditTextObject> pObj(rEngine.CreateTextObject()); + pObj->NormalizeString(mrDestDoc.GetSharedStringPool()); + rSrcCell.set(*pObj); + } + else + rSrcCell.set(rSrcCell.mpFormula->GetString()); + } + else + // We don't want to paste this. + rSrcCell.clear(); + } + break; + case CELLTYPE_NONE: + default: + // There is nothing to paste. + rSrcCell.clear(); + } +} + +const ScPatternAttr* CopyFromClipContext::getSingleCellPattern( size_t nColOffset ) const +{ + assert(nColOffset < maSinglePatterns.size()); + return maSinglePatterns[nColOffset]; +} + +void CopyFromClipContext::setSingleCellPattern( size_t nColOffset, const ScPatternAttr* pAttr ) +{ + assert(nColOffset < maSinglePatterns.size()); + maSinglePatterns[nColOffset] = pAttr; +} + +const ScPostIt* CopyFromClipContext::getSingleCellNote( size_t nColOffset ) const +{ + assert(nColOffset < maSingleNotes.size()); + return maSingleNotes[nColOffset]; +} + +void CopyFromClipContext::setSingleCellNote( size_t nColOffset, const ScPostIt* pNote ) +{ + assert(nColOffset < maSingleNotes.size()); + maSingleNotes[nColOffset] = pNote; +} + +std::shared_ptr<sc::Sparkline> const& CopyFromClipContext::getSingleSparkline(size_t nColOffset) const +{ + assert(nColOffset < maSingleSparkline.size()); + return maSingleSparkline[nColOffset]; +} + +void CopyFromClipContext::setSingleSparkline(size_t nColOffset, std::shared_ptr<sc::Sparkline> const& pSparkline) +{ + assert(nColOffset < maSingleSparkline.size()); + maSingleSparkline[nColOffset] = pSparkline; +} + +void CopyFromClipContext::setCondFormatList( ScConditionalFormatList* pCondFormatList ) +{ + mpCondFormatList = pCondFormatList; +} + +ScConditionalFormatList* CopyFromClipContext::getCondFormatList() +{ + return mpCondFormatList; +} + +void CopyFromClipContext::setTableProtected( bool b ) +{ + mbTableProtected = b; +} + +bool CopyFromClipContext::isTableProtected() const +{ + return mbTableProtected; +} + +bool CopyFromClipContext::isAsLink() const +{ + return mbAsLink; +} + +bool CopyFromClipContext::isSkipEmptyCells() const +{ + return mbSkipEmptyCells; +} + +bool CopyFromClipContext::isCloneNotes() const +{ + return bool(mnInsertFlag & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES)); +} + +bool CopyFromClipContext::isCloneSparklines() const +{ + return bool(mnInsertFlag & InsertDeleteFlags::SPARKLINES); +} + +bool CopyFromClipContext::isDateCell( const ScColumn& rCol, SCROW nRow ) const +{ + sal_uLong nNumIndex = rCol.GetAttr(nRow, ATTR_VALUE_FORMAT).GetValue(); + SvNumFormatType nType = mpClipDoc->GetFormatTable()->GetType(nNumIndex); + return (nType == SvNumFormatType::DATE) || (nType == SvNumFormatType::TIME) || (nType == SvNumFormatType::DATETIME); +} + +CopyToClipContext::CopyToClipContext( + ScDocument& rDoc, bool bKeepScenarioFlags) : + ClipContextBase(rDoc), mbKeepScenarioFlags(bKeepScenarioFlags) {} + +CopyToClipContext::~CopyToClipContext() {} + +bool CopyToClipContext::isKeepScenarioFlags() const +{ + return mbKeepScenarioFlags; +} + +CopyToDocContext::CopyToDocContext(ScDocument& rDoc) : + ClipContextBase(rDoc), mbStartListening(true) {} + +CopyToDocContext::~CopyToDocContext() {} + +void CopyToDocContext::setStartListening( bool b ) +{ + mbStartListening = b; +} + +bool CopyToDocContext::isStartListening() const +{ + return mbStartListening; +} + +MixDocContext::MixDocContext(ScDocument& rDoc) : ClipContextBase(rDoc) {} +MixDocContext::~MixDocContext() {} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |