summaryrefslogtreecommitdiff
path: root/sc/source
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2014-02-18 16:45:02 -0500
committerKohei Yoshida <kohei.yoshida@collabora.com>2014-02-18 16:51:18 -0500
commitcdc8ebf9646e773351c91039a62f2414c7b02105 (patch)
treeed0cedf4dc04dd347293d4e40a04bb997c218fdb /sc/source
parent3c7b65c171eeade3272cc766b813b99a35a6ef7d (diff)
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
Diffstat (limited to 'sc/source')
-rw-r--r--sc/source/core/data/clipcontext.cxx58
-rw-r--r--sc/source/core/data/column3.cxx52
-rw-r--r--sc/source/core/data/column4.cxx98
-rw-r--r--sc/source/core/data/document.cxx14
-rw-r--r--sc/source/core/data/document10.cxx24
-rw-r--r--sc/source/core/data/table7.cxx32
6 files changed, 246 insertions, 32 deletions
diff --git a/sc/source/core/data/clipcontext.cxx b/sc/source/core/data/clipcontext.cxx
index 35cde4e18161..c70d9d48de2b 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 5bc149b29dbc..1445848df0a5 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 5848183442a7..fa188180f272 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 f825a794c663..92d1f7e03428 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 d36df55ee60b..3e1a69bd43e6 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 8a7391c6e48e..a5936cbeeef9 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 )
{