sc/inc/clipcontext.hxx | 31 +++++++++++ sc/inc/column.hxx | 4 + sc/inc/document.hxx | 2 sc/inc/table.hxx | 2 sc/qa/unit/ucalc.hxx | 2 sc/source/core/data/clipcontext.cxx | 58 ++++++++++++++++++++- sc/source/core/data/column3.cxx | 52 +++++++++---------- sc/source/core/data/column4.cxx | 98 ++++++++++++++++++++++++++++++++++++ sc/source/core/data/document.cxx | 14 +++-- sc/source/core/data/document10.cxx | 24 ++++++++ sc/source/core/data/table7.cxx | 32 +++++++++++ 11 files changed, 285 insertions(+), 34 deletions(-)
New commits: commit b3043662f41b605242784d56802a44e3856187b7 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Tue Feb 18 16:49:43 2014 -0500 This test now passes. Re-enable it. Change-Id: I04a499666d1704277c24524f9e7cb827600a47db diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx index 242d2c1..01cb908 100644 --- a/sc/qa/unit/ucalc.hxx +++ b/sc/qa/unit/ucalc.hxx @@ -411,7 +411,7 @@ public: CPPUNIT_TEST(testCopyPaste); CPPUNIT_TEST(testCopyPasteAsLink); CPPUNIT_TEST(testCopyPasteTranspose); -// CPPUNIT_TEST(testCopyPasteSkipEmpty); TODO : fix this later + CPPUNIT_TEST(testCopyPasteSkipEmpty); //CPPUNIT_TEST(testCopyPasteSkipEmptyConditionalFormatting); CPPUNIT_TEST(testUndoCut); CPPUNIT_TEST(testMoveBlock); commit cdc8ebf9646e773351c91039a62f2414c7b02105 Author: Kohei Yoshida <kohei.yosh...@collabora.com> Date: Tue Feb 18 16:45:02 2014 -0500 fdo#74573: Delete ranges that are non-empty before pasting from clipboard. The conditional formatting part is still not working. But other bits appear to be working now. Change-Id: Ia8a2cbe57cd2fa9ca9ad46635a91a1d8b99b0e7d diff --git a/sc/inc/clipcontext.hxx b/sc/inc/clipcontext.hxx index 77abcf8..d016410 100644 --- a/sc/inc/clipcontext.hxx +++ b/sc/inc/clipcontext.hxx @@ -22,6 +22,7 @@ class ScDocument; class ScColumn; class ScPatternAttr; class ScPostIt; +class ScConditionalFormatList; namespace sc { @@ -43,21 +44,37 @@ public: class CopyFromClipContext : public ClipContextBase { + SCCOL mnDestCol1; + SCCOL mnDestCol2; + SCROW mnDestRow1; + SCROW mnDestRow2; SCTAB mnTabStart; SCTAB mnTabEnd; ScDocument* mpRefUndoDoc; ScDocument* mpClipDoc; - sal_uInt16 mnInsertFlag; + sal_uInt16 mnInsertFlag; + sal_uInt16 mnDeleteFlag; ScCellValue maSingleCell; + ScConditionalFormatList* mpCondFormatList; const ScPatternAttr* mpSinglePattern; const ScPostIt* mpSingleNote; bool mbAsLink:1; bool mbSkipAttrForEmptyCells:1; bool mbCloneNotes:1; + bool mbTableProtected:1; CopyFromClipContext(); // disabled public: + + struct Range + { + SCCOL mnCol1; + SCCOL mnCol2; + SCROW mnRow1; + SCROW mnRow2; + }; + CopyFromClipContext(ScDocument& rDoc, ScDocument* pRefUndoDoc, ScDocument* pClipDoc, sal_uInt16 nInsertFlag, bool bAsLink, bool bSkipAttrForEmptyCells); @@ -69,18 +86,30 @@ public: SCTAB getTabStart() const; SCTAB getTabEnd() const; + void setDestRange( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); + Range getDestRange() const; + ScDocument* getUndoDoc(); ScDocument* getClipDoc(); sal_uInt16 getInsertFlag() const; + void setDeleteFlag( sal_uInt16 nFlag ); + sal_uInt16 getDeleteFlag() const; + ScCellValue& getSingleCell(); + void setCondFormatList( ScConditionalFormatList* pCondFormatList ); + ScConditionalFormatList* getCondFormatList(); + const ScPatternAttr* getSingleCellPattern() const; void setSingleCellPattern( const ScPatternAttr* pAttr ); const ScPostIt* getSingleCellNote() const; void setSingleCellNote( const ScPostIt* pNote ); + void setTableProtected( bool b ); + bool isTableProtected() const; + bool isAsLink() const; bool isSkipAttrForEmptyCells() const; bool isCloneNotes() const; diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 9b36270..7f0c365 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -232,6 +232,7 @@ public: bool InitBlockPosition( sc::ColumnBlockPosition& rBlockPos ); bool InitBlockPosition( sc::ColumnBlockConstPosition& rBlockPos ) const; + void DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const ScColumn& rClipCol ); void CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2 ); void CopyFromClip( @@ -592,6 +593,9 @@ private: // cell notes void SwapCellNotes( SCROW nRow1, SCROW nRow2 ); + void DeleteCells( + sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, sal_uInt16 nDelFlag, + std::vector<SCROW>& rDeleted ); }; #endif diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 1294503..12b2bee 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -1207,6 +1207,8 @@ public: bool InitColumnBlockPosition( sc::ColumnBlockPosition& rBlokPos, SCTAB nTab, SCCOL nCol ); + void DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const ScMarkData& rMark ); + bool CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); void CopyBlockFromClip( diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 1e8764b..563f17d 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -418,6 +418,8 @@ public: bool InitColumnBlockPosition( sc::ColumnBlockPosition& rBlockPos, SCCOL nCol ); + void DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const ScTable& rClipTab ); + void CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); diff --git a/sc/source/core/data/clipcontext.cxx b/sc/source/core/data/clipcontext.cxx index 35cde4e..c70d9d4 100644 --- a/sc/source/core/data/clipcontext.cxx +++ b/sc/source/core/data/clipcontext.cxx @@ -31,11 +31,15 @@ CopyFromClipContext::CopyFromClipContext(ScDocument& rDoc, ScDocument* pRefUndoDoc, ScDocument* pClipDoc, sal_uInt16 nInsertFlag, bool bAsLink, bool bSkipAttrForEmptyCells) : ClipContextBase(rDoc), + mnDestCol1(-1), mnDestCol2(-1), + mnDestRow1(-1), mnDestRow2(-1), mnTabStart(-1), mnTabEnd(-1), - mpRefUndoDoc(pRefUndoDoc), mpClipDoc(pClipDoc), mnInsertFlag(nInsertFlag), - mpSinglePattern(NULL), mpSingleNote(NULL), + mpRefUndoDoc(pRefUndoDoc), mpClipDoc(pClipDoc), + mnInsertFlag(nInsertFlag), mnDeleteFlag(IDF_NONE), + mpCondFormatList(NULL), mpSinglePattern(NULL), mpSingleNote(NULL), mbAsLink(bAsLink), mbSkipAttrForEmptyCells(bSkipAttrForEmptyCells), - mbCloneNotes (mnInsertFlag & (IDF_NOTE|IDF_ADDNOTES)) + mbCloneNotes (mnInsertFlag & (IDF_NOTE|IDF_ADDNOTES)), + mbTableProtected(false) { } @@ -59,6 +63,24 @@ 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; @@ -74,11 +96,31 @@ sal_uInt16 CopyFromClipContext::getInsertFlag() const return mnInsertFlag; } +void CopyFromClipContext::setDeleteFlag( sal_uInt16 nFlag ) +{ + mnDeleteFlag = nFlag; +} + +sal_uInt16 CopyFromClipContext::getDeleteFlag() const +{ + return mnDeleteFlag; +} + ScCellValue& CopyFromClipContext::getSingleCell() { return maSingleCell; } +void CopyFromClipContext::setCondFormatList( ScConditionalFormatList* pCondFormatList ) +{ + mpCondFormatList = pCondFormatList; +} + +ScConditionalFormatList* CopyFromClipContext::getCondFormatList() +{ + return mpCondFormatList; +} + const ScPatternAttr* CopyFromClipContext::getSingleCellPattern() const { return mpSinglePattern; @@ -99,6 +141,16 @@ void CopyFromClipContext::setSingleCellNote( const ScPostIt* pNote ) mpSingleNote = pNote; } +void CopyFromClipContext::setTableProtected( bool b ) +{ + mbTableProtected = b; +} + +bool CopyFromClipContext::isTableProtected() const +{ + return mbTableProtected; +} + bool CopyFromClipContext::isAsLink() const { return mbAsLink; diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index 5bc149b..1445848 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -570,6 +570,29 @@ public: } +void ScColumn::DeleteCells( + sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, sal_uInt16 nDelFlag, + std::vector<SCROW>& rDeleted ) +{ + // Determine which cells to delete based on the deletion flags. + DeleteAreaHandler aFunc(*pDocument, nDelFlag); + sc::CellStoreType::iterator itPos = maCells.position(rBlockPos.miCellPos, nRow1).first; + sc::ProcessBlock(itPos, maCells, aFunc, nRow1, nRow2); + aFunc.endFormulas(); // Have the formula cells stop listening. + + std::vector<SCROW> aDeletedRows; + aFunc.getSpans().getRows(aDeletedRows); + std::copy(aDeletedRows.begin(), aDeletedRows.end(), std::back_inserter(rDeleted)); + + // Get the deletion spans. + sc::SingleColumnSpanSet::SpansType aSpans; + aFunc.getSpans().getSpans(aSpans); + + // Delete the cells for real. + std::for_each(aSpans.begin(), aSpans.end(), EmptyCells(rBlockPos, *this)); + CellStorageModified(); +} + void ScColumn::DeleteArea( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nDelFlag, bool bBroadcast ) { @@ -581,35 +604,14 @@ void ScColumn::DeleteArea( std::vector<SCROW> aDeletedRows; - if (!IsEmptyData() && nContFlag) - { - // There are cells to delete. Determine which cells to delete based on the deletion flags. - DeleteAreaHandler aFunc(*pDocument, nDelFlag); - sc::CellStoreType::iterator itPos = maCells.position(nStartRow).first; - sc::ProcessBlock(itPos, maCells, aFunc, nStartRow, nEndRow); - aFunc.endFormulas(); // Have the formula cells stop listening. - aFunc.getSpans().getRows(aDeletedRows); - - // Get the deletion spans. - sc::SingleColumnSpanSet::SpansType aSpans; - aFunc.getSpans().getSpans(aSpans); + sc::ColumnBlockPosition aBlockPos; + InitBlockPosition(aBlockPos); - sc::ColumnBlockPosition aBlockPos; - aBlockPos.miCellPos = itPos; - aBlockPos.miCellTextAttrPos = maCellTextAttrs.begin(); - aBlockPos.miCellNotePos = maCellNotes.begin(); - - // Delete the cells for real. - std::for_each(aSpans.begin(), aSpans.end(), EmptyCells(aBlockPos, *this)); - CellStorageModified(); - } + if (!IsEmptyData() && nContFlag) + DeleteCells(aBlockPos, nStartRow, nEndRow, nDelFlag, aDeletedRows); if (nDelFlag & IDF_NOTE) - { - sc::ColumnBlockPosition aBlockPos; - aBlockPos.miCellNotePos = maCellNotes.begin(); DeleteCellNotes(aBlockPos, nStartRow, nEndRow); - } if ( nDelFlag & IDF_EDITATTR ) { diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx index 5848183..fa18818 100644 --- a/sc/source/core/data/column4.cxx +++ b/sc/source/core/data/column4.cxx @@ -17,6 +17,11 @@ #include <columnspanset.hxx> #include <listenercontext.hxx> #include <mtvcellfunc.hxx> +#include <clipcontext.hxx> +#include <attrib.hxx> +#include <patattr.hxx> +#include <docpool.hxx> +#include <conditio.hxx> #include <svl/sharedstringpool.hxx> @@ -28,6 +33,99 @@ bool ScColumn::IsMerged( SCROW nRow ) const return pAttrArray->IsMerged(nRow); } +void ScColumn::DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const ScColumn& rClipCol ) +{ + sc::CopyFromClipContext::Range aRange = rCxt.getDestRange(); + if (!ValidRow(aRange.mnRow1) || !ValidRow(aRange.mnRow2)) + return; + + ScRange aClipRange = rCxt.getClipDoc()->GetClipParam().getWholeRange(); + SCROW nClipRow1 = aClipRange.aStart.Row(); + SCROW nClipRow2 = aClipRange.aEnd.Row(); + SCROW nClipRowLen = nClipRow2 - nClipRow1 + 1; + + // Check for non-empty cell ranges in the clip column. + sc::SingleColumnSpanSet aSpanSet; + aSpanSet.scan(rClipCol, nClipRow1, nClipRow2); + sc::SingleColumnSpanSet::SpansType aSpans; + aSpanSet.getSpans(aSpans); + + // Translate the clip column spans into the destination column, and repeat as needed. + std::vector<sc::RowSpan> aDestSpans; + SCROW nDestOffset = aRange.mnRow1 - nClipRow1; + bool bContinue = true; + while (bContinue) + { + sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end(); + for (; it != itEnd && bContinue; ++it) + { + const sc::RowSpan& r = *it; + SCROW nDestRow1 = r.mnRow1 + nDestOffset; + SCROW nDestRow2 = r.mnRow2 + nDestOffset; + + if (nDestRow1 > aRange.mnRow2) + { + // We're done. + bContinue = false; + continue; + } + + if (nDestRow2 > aRange.mnRow2) + { + // Truncate this range, and set it as the last span. + nDestRow2 = aRange.mnRow2; + bContinue = false; + } + + aDestSpans.push_back(sc::RowSpan(nDestRow1, nDestRow2)); + } + + nDestOffset += nClipRowLen; + } + + std::vector<SCROW> aDeletedRows; + sal_uInt16 nDelFlag = rCxt.getDeleteFlag(); + sc::ColumnBlockPosition aBlockPos; + InitBlockPosition(aBlockPos); + + std::vector<sc::RowSpan>::const_iterator it = aDestSpans.begin(), itEnd = aDestSpans.end(); + for (; it != itEnd; ++it) + { + SCROW nRow1 = it->mnRow1; + SCROW nRow2 = it->mnRow2; + + if (nDelFlag & IDF_CONTENTS) + DeleteCells(aBlockPos, nRow1, nRow2, nDelFlag, aDeletedRows); + + if (nDelFlag & IDF_NOTE) + DeleteCellNotes(aBlockPos, nRow1, nRow2); + + if (nDelFlag & IDF_EDITATTR) + RemoveEditAttribs(nRow1, nRow2); + + // Delete attributes just now + if (nDelFlag & IDF_ATTRIB) + { + pAttrArray->DeleteArea(nRow1, nRow2); + + if (rCxt.isTableProtected()) + { + ScPatternAttr aPattern(pDocument->GetPool()); + aPattern.GetItemSet().Put(ScProtectionAttr(false)); + ApplyPatternArea(nRow1, nRow2, aPattern); + } + + ScConditionalFormatList* pCondList = rCxt.getCondFormatList(); + if (pCondList) + pCondList->DeleteArea(nCol, nRow1, nCol, nRow2); + } + else if ((nDelFlag & IDF_HARDATTR) == IDF_HARDATTR) + pAttrArray->DeleteHardAttr(nRow1, nRow2); + } + + BroadcastCells(aDeletedRows, SC_HINT_DATACHANGED); +} + void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2 ) { assert(nRow1 <= nRow2); diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index f825a79..92d1f7e 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -2661,14 +2661,14 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar nDelFlag |= IDF_NOTE; else if ( nInsFlag & IDF_CONTENTS ) nDelFlag |= IDF_CONTENTS; - // With bSkipAttrForEmpty, don't remove attributes, copy - // on top of existing attributes instead. - if ( ( nInsFlag & IDF_ATTRIB ) && !bSkipAttrForEmpty ) + + if (nInsFlag & IDF_ATTRIB) nDelFlag |= IDF_ATTRIB; sc::CopyFromClipContext aCxt(*this, pRefUndoDoc, pClipDoc, nInsFlag, bAsLink, bSkipAttrForEmpty); std::pair<SCTAB,SCTAB> aTabRanges = getMarkedTableRange(maTabs, rMark); aCxt.setTabRange(aTabRanges.first, aTabRanges.second); + aCxt.setDeleteFlag(nDelFlag); ScRangeList aLocalRangeList; if (!pDestRanges) @@ -2690,7 +2690,13 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar SCCOL nCol2 = pRange->aEnd.Col(); SCROW nRow2 = pRange->aEnd.Row(); - if (!bSkipAttrForEmpty) + if (bSkipAttrForEmpty) + { + // Delete cells in the destination only if their corresponding clip cells are not empty. + aCxt.setDestRange(nCol1, nRow1, nCol2, nRow2); + DeleteBeforeCopyFromClip(aCxt, rMark); + } + else DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag); if (CopyOneCellFromClip(aCxt, nCol1, nRow1, nCol2, nRow2)) diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx index d36df55..3e1a69b 100644 --- a/sc/source/core/data/document10.cxx +++ b/sc/source/core/data/document10.cxx @@ -26,6 +26,30 @@ bool ScDocument::IsMerged( const ScAddress& rPos ) const return pTab->IsMerged(rPos.Col(), rPos.Row()); } +void ScDocument::DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const ScMarkData& rMark ) +{ + SCTAB nClipTab = 0; + const TableContainer& rClipTabs = rCxt.getClipDoc()->maTabs; + SCTAB nClipTabCount = rClipTabs.size(); + + for (SCTAB nTab = rCxt.getTabStart(); nTab <= rCxt.getTabEnd(); ++nTab) + { + ScTable* pTab = FetchTable(nTab); + if (!pTab) + continue; + + if (!rMark.GetTableSelect(nTab)) + continue; + + while (!rClipTabs[nClipTab]) + nClipTab = (nClipTab+1) % nClipTabCount; + + pTab->DeleteBeforeCopyFromClip(rCxt, *rClipTabs[nClipTab]); + + nClipTab = (nClipTab+1) % nClipTabCount; + } +} + bool ScDocument::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) { diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx index 8a7391c..a5936cb 100644 --- a/sc/source/core/data/table7.cxx +++ b/sc/source/core/data/table7.cxx @@ -8,6 +8,10 @@ */ #include <table.hxx> +#include <clipcontext.hxx> +#include <document.hxx> +#include <clipparam.hxx> +#include <bcaslot.hxx> bool ScTable::IsMerged( SCCOL nCol, SCROW nRow ) const { @@ -17,6 +21,34 @@ bool ScTable::IsMerged( SCCOL nCol, SCROW nRow ) const return aCol[nCol].IsMerged(nRow); } +void ScTable::DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const ScTable& rClipTab ) +{ + sc::CopyFromClipContext::Range aRange = rCxt.getDestRange(); + if (!ValidCol(aRange.mnCol1) || !ValidCol(aRange.mnCol2)) + return; + + // Pass some stuff to the columns via context. + rCxt.setTableProtected(IsProtected()); + rCxt.setCondFormatList(mpCondFormatList.get()); + + ScRange aClipRange = rCxt.getClipDoc()->GetClipParam().getWholeRange(); + SCCOL nClipCol = aClipRange.aStart.Col(); + { + ScBulkBroadcast aBulkBroadcast(pDocument->GetBASM()); + + for (SCCOL nCol = aRange.mnCol1; nCol <= aRange.mnCol2; ++nCol, ++nClipCol) + { + if (nClipCol > aClipRange.aEnd.Col()) + nClipCol = aClipRange.aStart.Col(); // loop through columns. + + const ScColumn& rClipCol = rClipTab.aCol[nClipCol]; + aCol[nCol].DeleteBeforeCopyFromClip(rCxt, rClipCol); + } + } + + SetStreamValid(false); +} + void ScTable::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) { _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits