435 lines
12 KiB
C++
435 lines
12 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 <memory>
|
|
#include <clipcontext.hxx>
|
|
#include <document.hxx>
|
|
#include <mtvelements.hxx>
|
|
#include <column.hxx>
|
|
#include <scitems.hxx>
|
|
#include <tokenarray.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()
|
|
{
|
|
const 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.getType())
|
|
{
|
|
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.getFormula()->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.getFormula()->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.getFormula()->IsEmptyDisplayedAsString())
|
|
{
|
|
// Empty stays empty and doesn't become 0.
|
|
rSrcCell.clear();
|
|
}
|
|
else if (rSrcCell.getFormula()->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.getFormula()->GetValue());
|
|
}
|
|
else if (bString)
|
|
{
|
|
svl::SharedString aStr = rSrcCell.getFormula()->GetString();
|
|
if (aStr.isEmpty())
|
|
{
|
|
// do not clone empty string
|
|
rSrcCell.clear();
|
|
break;
|
|
}
|
|
|
|
// Turn this into a string or edit cell.
|
|
if (rSrcCell.getFormula()->IsMultilineResult())
|
|
{
|
|
std::unique_ptr<EditTextObject> pObj(mrDestDoc.CreateSharedStringTextObject(
|
|
rSrcCell.getFormula()->GetString()));
|
|
rSrcCell.set(*pObj);
|
|
}
|
|
else
|
|
rSrcCell.set(rSrcCell.getFormula()->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_uInt32 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, bool bCopyChartRanges) :
|
|
ClipContextBase(rDoc), mbKeepScenarioFlags(bKeepScenarioFlags), mbCopyChartRanges(bCopyChartRanges) {}
|
|
|
|
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: */
|