Kaydet (Commit) ff5aad0a authored tarafından Kohei Yoshida's avatar Kohei Yoshida

Speed up pasting of single row onto multiple destination rows.

This is an extension of the earlier paste optimization of a single cell
across multiple destination cells.

Change-Id: I3a60300d3d0e11420d997bea8f7f540e948f56cc
üst 136eed0f
...@@ -54,10 +54,12 @@ class CopyFromClipContext : public ClipContextBase ...@@ -54,10 +54,12 @@ class CopyFromClipContext : public ClipContextBase
ScDocument* mpClipDoc; ScDocument* mpClipDoc;
InsertDeleteFlags mnInsertFlag; InsertDeleteFlags mnInsertFlag;
InsertDeleteFlags mnDeleteFlag; InsertDeleteFlags mnDeleteFlag;
ScCellValue maSingleCell;
std::vector<ScCellValue> maSingleCells;
std::vector<const ScPatternAttr*> maSinglePatterns;
std::vector<const ScPostIt*> maSingleNotes;
ScConditionalFormatList* mpCondFormatList; ScConditionalFormatList* mpCondFormatList;
const ScPatternAttr* mpSinglePattern;
const ScPostIt* mpSingleNote;
bool mbAsLink:1; bool mbAsLink:1;
bool mbSkipAttrForEmptyCells:1; bool mbSkipAttrForEmptyCells:1;
bool mbCloneNotes:1; bool mbCloneNotes:1;
...@@ -96,16 +98,23 @@ public: ...@@ -96,16 +98,23 @@ public:
void setDeleteFlag( InsertDeleteFlags nFlag ); void setDeleteFlag( InsertDeleteFlags nFlag );
InsertDeleteFlags getDeleteFlag() const; InsertDeleteFlags getDeleteFlag() const;
ScCellValue& getSingleCell(); /**
* Set the column size of a "single cell" row, which is used when copying
* a single row of cells in a clip doc and pasting it into multiple
* rows by replicating it.
*/
void setSingleCellColumnSize( size_t nSize );
void setCondFormatList( ScConditionalFormatList* pCondFormatList ); ScCellValue& getSingleCell( size_t nColOffset );
ScConditionalFormatList* getCondFormatList();
const ScPatternAttr* getSingleCellPattern() const; const ScPatternAttr* getSingleCellPattern( size_t nColOffset ) const;
void setSingleCellPattern( const ScPatternAttr* pAttr ); void setSingleCellPattern( size_t nColOffset, const ScPatternAttr* pAttr );
const ScPostIt* getSingleCellNote() const; const ScPostIt* getSingleCellNote( size_t nColOffset ) const;
void setSingleCellNote( const ScPostIt* pNote ); void setSingleCellNote( size_t nColOffset, const ScPostIt* pNote );
void setCondFormatList( ScConditionalFormatList* pCondFormatList );
ScConditionalFormatList* getCondFormatList();
void setTableProtected( bool b ); void setTableProtected( bool b );
bool isTableProtected() const; bool isTableProtected() const;
......
...@@ -245,7 +245,7 @@ public: ...@@ -245,7 +245,7 @@ public:
bool InitBlockPosition( sc::ColumnBlockConstPosition& rBlockPos ) const; bool InitBlockPosition( sc::ColumnBlockConstPosition& rBlockPos ) const;
void DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const ScColumn& rClipCol ); void DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const ScColumn& rClipCol );
void CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2 ); void CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, size_t nColOffset );
void CopyFromClip( void CopyFromClip(
sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, long nDy, ScColumn& rColumn ); sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, long nDy, ScColumn& rColumn );
......
...@@ -36,7 +36,7 @@ CopyFromClipContext::CopyFromClipContext(ScDocument& rDoc, ...@@ -36,7 +36,7 @@ CopyFromClipContext::CopyFromClipContext(ScDocument& rDoc,
mnTabStart(-1), mnTabEnd(-1), mnTabStart(-1), mnTabEnd(-1),
mpRefUndoDoc(pRefUndoDoc), mpClipDoc(pClipDoc), mpRefUndoDoc(pRefUndoDoc), mpClipDoc(pClipDoc),
mnInsertFlag(nInsertFlag), mnDeleteFlag(IDF_NONE), mnInsertFlag(nInsertFlag), mnDeleteFlag(IDF_NONE),
mpCondFormatList(NULL), mpSinglePattern(NULL), mpSingleNote(NULL), mpCondFormatList(NULL),
mbAsLink(bAsLink), mbSkipAttrForEmptyCells(bSkipAttrForEmptyCells), mbAsLink(bAsLink), mbSkipAttrForEmptyCells(bSkipAttrForEmptyCells),
mbCloneNotes (mnInsertFlag & (IDF_NOTE|IDF_ADDNOTES)), mbCloneNotes (mnInsertFlag & (IDF_NOTE|IDF_ADDNOTES)),
mbTableProtected(false) mbTableProtected(false)
...@@ -106,39 +106,51 @@ InsertDeleteFlags CopyFromClipContext::getDeleteFlag() const ...@@ -106,39 +106,51 @@ InsertDeleteFlags CopyFromClipContext::getDeleteFlag() const
return mnDeleteFlag; return mnDeleteFlag;
} }
ScCellValue& CopyFromClipContext::getSingleCell() void CopyFromClipContext::setSingleCellColumnSize( size_t nSize )
{ {
return maSingleCell; maSingleCells.resize(nSize);
maSinglePatterns.resize(nSize, NULL);
maSingleNotes.resize(nSize, NULL);
} }
void CopyFromClipContext::setCondFormatList( ScConditionalFormatList* pCondFormatList ) ScCellValue& CopyFromClipContext::getSingleCell( size_t nColOffset )
{ {
mpCondFormatList = pCondFormatList; assert(nColOffset < maSingleCells.size());
return maSingleCells[nColOffset];
} }
ScConditionalFormatList* CopyFromClipContext::getCondFormatList() const ScPatternAttr* CopyFromClipContext::getSingleCellPattern( size_t nColOffset ) const
{ {
return mpCondFormatList; assert(nColOffset < maSinglePatterns.size());
return maSinglePatterns[nColOffset];
} }
const ScPatternAttr* CopyFromClipContext::getSingleCellPattern() const void CopyFromClipContext::setSingleCellPattern( size_t nColOffset, const ScPatternAttr* pAttr )
{ {
return mpSinglePattern; assert(nColOffset < maSinglePatterns.size());
maSinglePatterns[nColOffset] = pAttr;
} }
void CopyFromClipContext::setSingleCellPattern( const ScPatternAttr* pAttr ) const ScPostIt* CopyFromClipContext::getSingleCellNote( size_t nColOffset ) const
{ {
mpSinglePattern = pAttr; assert(nColOffset < maSingleNotes.size());
return maSingleNotes[nColOffset];
} }
const ScPostIt* CopyFromClipContext::getSingleCellNote() const void CopyFromClipContext::setSingleCellNote( size_t nColOffset, const ScPostIt* pNote )
{ {
return mpSingleNote; assert(nColOffset < maSingleNotes.size());
maSingleNotes[nColOffset] = pNote;
} }
void CopyFromClipContext::setSingleCellNote( const ScPostIt* pNote ) void CopyFromClipContext::setCondFormatList( ScConditionalFormatList* pCondFormatList )
{ {
mpSingleNote = pNote; mpCondFormatList = pCondFormatList;
}
ScConditionalFormatList* CopyFromClipContext::getCondFormatList()
{
return mpCondFormatList;
} }
void CopyFromClipContext::setTableProtected( bool b ) void CopyFromClipContext::setTableProtected( bool b )
......
...@@ -138,7 +138,7 @@ void ScColumn::DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const Sc ...@@ -138,7 +138,7 @@ void ScColumn::DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const Sc
BroadcastCells(aDeletedRows, SC_HINT_DATACHANGED); BroadcastCells(aDeletedRows, SC_HINT_DATACHANGED);
} }
void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2 ) void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, size_t nColOffset )
{ {
assert(nRow1 <= nRow2); assert(nRow1 <= nRow2);
...@@ -147,7 +147,7 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, ...@@ -147,7 +147,7 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
if (!pBlockPos) if (!pBlockPos)
return; return;
ScCellValue& rSrcCell = rCxt.getSingleCell(); ScCellValue& rSrcCell = rCxt.getSingleCell(nColOffset);
InsertDeleteFlags nFlags = rCxt.getInsertFlag(); InsertDeleteFlags nFlags = rCxt.getInsertFlag();
...@@ -155,7 +155,7 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, ...@@ -155,7 +155,7 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
{ {
if (!rCxt.isSkipAttrForEmptyCells() || rSrcCell.meType != CELLTYPE_NONE) if (!rCxt.isSkipAttrForEmptyCells() || rSrcCell.meType != CELLTYPE_NONE)
{ {
const ScPatternAttr* pAttr = rCxt.getSingleCellPattern(); const ScPatternAttr* pAttr = rCxt.getSingleCellPattern(nColOffset);
pAttrArray->SetPatternArea(nRow1, nRow2, pAttr, true); pAttrArray->SetPatternArea(nRow1, nRow2, pAttr, true);
} }
} }
...@@ -221,7 +221,7 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, ...@@ -221,7 +221,7 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1,
} }
} }
const ScPostIt* pNote = rCxt.getSingleCellNote(); const ScPostIt* pNote = rCxt.getSingleCellNote(nColOffset);
if (pNote && (nFlags & (IDF_NOTE | IDF_ADDNOTES)) != IDF_NONE) if (pNote && (nFlags & (IDF_NOTE | IDF_ADDNOTES)) != IDF_NONE)
{ {
// Duplicate the cell note over the whole pasted range. // Duplicate the cell note over the whole pasted range.
......
...@@ -70,142 +70,159 @@ bool ScDocument::CopyOneCellFromClip( ...@@ -70,142 +70,159 @@ bool ScDocument::CopyOneCellFromClip(
return false; return false;
ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange(); ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
if (aClipRange.aStart != aClipRange.aEnd) if (aClipRange.aStart.Row() != aClipRange.aEnd.Row())
// The source is not really a single cell. Bail out. // The source is not really a single row. Bail out.
return false; return false;
ScAddress aSrcPos = aClipRange.aStart; SCCOL nSrcColSize = aClipRange.aEnd.Col() - aClipRange.aStart.Col() + 1;
if (pClipDoc->IsMerged(aSrcPos)) SCCOL nDestColSize = nCol2 - nCol1 + 1;
// We don't handle merged source cell for this. if (nDestColSize < nSrcColSize)
return false; return false;
ScAddress aSrcPos = aClipRange.aStart;
for (SCCOL nCol = aClipRange.aStart.Col(); nCol <= aClipRange.aEnd.Col(); ++nCol)
{
ScAddress aTestPos = aSrcPos;
aTestPos.SetCol(nCol);
if (pClipDoc->IsMerged(aTestPos))
// We don't handle merged source cell for this.
return false;
}
ScTable* pSrcTab = pClipDoc->FetchTable(aSrcPos.Tab()); ScTable* pSrcTab = pClipDoc->FetchTable(aSrcPos.Tab());
if (!pSrcTab) if (!pSrcTab)
return false; return false;
ScCellValue& rSrcCell = rCxt.getSingleCell(); rCxt.setSingleCellColumnSize(nSrcColSize);
const ScPatternAttr* pAttr = pClipDoc->GetPattern(aSrcPos);
rCxt.setSingleCellPattern(pAttr);
if (rCxt.isAsLink())
{
ScSingleRefData aRef;
aRef.InitAddress(aSrcPos);
aRef.SetFlag3D(true);
ScTokenArray aArr; for (SCCOL nColOffset = 0; nColOffset < nSrcColSize; ++nColOffset, aSrcPos.IncCol())
aArr.AddSingleReference(aRef);
rSrcCell.set(new ScFormulaCell(pClipDoc, aSrcPos, aArr));
}
else
{ {
rSrcCell.set(pClipDoc->GetRefCellValue(aSrcPos)); const ScPatternAttr* pAttr = pClipDoc->GetPattern(aSrcPos);
rCxt.setSingleCellPattern(nColOffset, pAttr);
// 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. if ((rCxt.getInsertFlag() & (IDF_NOTE | IDF_ADDNOTES)) != IDF_NONE)
InsertDeleteFlags nFlags = rCxt.getInsertFlag(); rCxt.setSingleCellNote(nColOffset, pClipDoc->GetNote(aSrcPos));
bool bNumeric = (nFlags & IDF_VALUE) != IDF_NONE;
bool bDateTime = (nFlags & IDF_DATETIME) != IDF_NONE; ScCellValue& rSrcCell = rCxt.getSingleCell(nColOffset);
bool bString = (nFlags & IDF_STRING) != IDF_NONE; if (rCxt.isAsLink())
bool bBoolean = (nFlags & IDF_SPECIAL_BOOLEAN) != IDF_NONE;
bool bFormula = (nFlags & IDF_FORMULA) != IDF_NONE;
switch (rSrcCell.meType)
{ {
case CELLTYPE_VALUE: ScSingleRefData aRef;
{ aRef.InitAddress(aSrcPos);
bool bPaste = rCxt.isDateCell(pSrcTab->aCol[aSrcPos.Col()], aSrcPos.Row()) ? bDateTime : bNumeric; aRef.SetFlag3D(true);
if (!bPaste)
// Don't paste this. ScTokenArray aArr;
rSrcCell.clear(); aArr.AddSingleReference(aRef);
} rSrcCell.set(new ScFormulaCell(pClipDoc, aSrcPos, aArr));
break; }
case CELLTYPE_STRING: else
case CELLTYPE_EDIT: {
{ rSrcCell.assign(*pClipDoc, aSrcPos);
if (!bString)
// Skip pasting. // Check the paste flag to see whether we want to paste this cell. If the
rSrcCell.clear(); // flag says we don't want to paste this cell, we'll return with true.
} InsertDeleteFlags nFlags = rCxt.getInsertFlag();
break; bool bNumeric = (nFlags & IDF_VALUE) != IDF_NONE;
case CELLTYPE_FORMULA: bool bDateTime = (nFlags & IDF_DATETIME) != IDF_NONE;
bool bString = (nFlags & IDF_STRING) != IDF_NONE;
bool bBoolean = (nFlags & IDF_SPECIAL_BOOLEAN) != IDF_NONE;
bool bFormula = (nFlags & IDF_FORMULA) != IDF_NONE;
switch (rSrcCell.meType)
{ {
if (bBoolean) case CELLTYPE_VALUE:
{ {
// Check if this formula cell is a boolean cell, and if so, go ahead and paste it. bool bPaste = rCxt.isDateCell(pSrcTab->aCol[aSrcPos.Col()], aSrcPos.Row()) ? bDateTime : bNumeric;
ScTokenArray* pCode = rSrcCell.mpFormula->GetCode(); if (!bPaste)
if (pCode && pCode->GetLen() == 1) // Don't paste this.
{ rSrcCell.clear();
const formula::FormulaToken* p = pCode->First();
if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
// This is a boolean formula. Good.
break;
}
} }
break;
if (bFormula) case CELLTYPE_STRING:
// Good. case CELLTYPE_EDIT:
break;
sal_uInt16 nErr = rSrcCell.mpFormula->GetErrCode();
if (nErr)
{ {
// error codes are cloned with values if (!bString)
if (!bNumeric) // Skip pasting.
// Error code is treated as numeric value. Don't paste it.
rSrcCell.clear(); rSrcCell.clear();
} }
else if (rSrcCell.mpFormula->IsValue()) break;
case CELLTYPE_FORMULA:
{ {
bool bPaste = rCxt.isDateCell(pSrcTab->aCol[aSrcPos.Col()], aSrcPos.Row()) ? bDateTime : bNumeric; if (bBoolean)
if (!bPaste)
{ {
// Don't paste this. // Check if this formula cell is a boolean cell, and if so, go ahead and paste it.
rSrcCell.clear(); ScTokenArray* pCode = rSrcCell.mpFormula->GetCode();
break; if (pCode && pCode->GetLen() == 1)
{
const formula::FormulaToken* p = pCode->First();
if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
// This is a boolean formula. Good.
break;
}
} }
// Turn this into a numeric cell. if (bFormula)
rSrcCell.set(rSrcCell.mpFormula->GetValue()); // Good.
}
else if (bString)
{
svl::SharedString aStr = rSrcCell.mpFormula->GetString();
if (aStr.isEmpty())
{
// do not clone empty string
rSrcCell.clear();
break; break;
sal_uInt16 nErr = rSrcCell.mpFormula->GetErrCode();
if (nErr)
{
// error codes are cloned with values
if (!bNumeric)
// Error code is treated as numeric value. Don't paste it.
rSrcCell.clear();
} }
else if (rSrcCell.mpFormula->IsValue())
{
bool bPaste = rCxt.isDateCell(pSrcTab->aCol[aSrcPos.Col()], aSrcPos.Row()) ? bDateTime : bNumeric;
if (!bPaste)
{
// Don't paste this.
rSrcCell.clear();
break;
}
// Turn this into a string or edit cell. // Turn this into a numeric cell.
if (rSrcCell.mpFormula->IsMultilineResult()) rSrcCell.set(rSrcCell.mpFormula->GetValue());
}
else if (bString)
{ {
// TODO : Add shared string support to the edit engine to svl::SharedString aStr = rSrcCell.mpFormula->GetString();
// make this process simpler. if (aStr.isEmpty())
ScFieldEditEngine& rEngine = GetEditEngine(); {
rEngine.SetText(rSrcCell.mpFormula->GetString().getString()); // do not clone empty string
boost::scoped_ptr<EditTextObject> pObj(rEngine.CreateTextObject()); rSrcCell.clear();
pObj->NormalizeString(GetSharedStringPool()); break;
rSrcCell.set(*pObj); }
// 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 = GetEditEngine();
rEngine.SetText(rSrcCell.mpFormula->GetString().getString());
boost::scoped_ptr<EditTextObject> pObj(rEngine.CreateTextObject());
pObj->NormalizeString(GetSharedStringPool());
rSrcCell.set(*pObj);
}
else
rSrcCell.set(rSrcCell.mpFormula->GetString());
} }
else else
rSrcCell.set(rSrcCell.mpFormula->GetString()); // We don't want to paste this.
rSrcCell.clear();
} }
else break;
// We don't want to paste this. case CELLTYPE_NONE:
default:
// There is nothing to paste.
rSrcCell.clear(); rSrcCell.clear();
} }
break;
case CELLTYPE_NONE:
default:
// There is nothing to paste.
rSrcCell.clear();
} }
} }
if ((rCxt.getInsertFlag() & (IDF_NOTE | IDF_ADDNOTES)) != IDF_NONE)
rCxt.setSingleCellNote(pClipDoc->GetNote(aSrcPos));
// All good. Proceed with the pasting. // All good. Proceed with the pasting.
SCTAB nTabEnd = rCxt.getTabEnd(); SCTAB nTabEnd = rCxt.getTabEnd();
......
...@@ -55,8 +55,16 @@ void ScTable::DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const ScT ...@@ -55,8 +55,16 @@ void ScTable::DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const ScT
void ScTable::CopyOneCellFromClip( void ScTable::CopyOneCellFromClip(
sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
{ {
ScRange aSrcRange = rCxt.getClipDoc()->GetClipParam().getWholeRange();
SCCOL nSrcColSize = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
aCol[nCol].CopyOneCellFromClip(rCxt, nRow1, nRow2); {
SCCOL nColOffset = nCol - nCol1;
nColOffset = nColOffset % nSrcColSize;
assert(nColOffset >= 0);
aCol[nCol].CopyOneCellFromClip(rCxt, nRow1, nRow2, nColOffset);
}
} }
void ScTable::SetValues( SCCOL nCol, SCROW nRow, const std::vector<double>& rVals ) void ScTable::SetValues( SCCOL nCol, SCROW nRow, const std::vector<double>& rVals )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment