summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2014-05-03 00:50:46 -0400
committerMarkus Mohrhard <markus.mohrhard@googlemail.com>2014-05-08 13:18:54 +0000
commit23e43dfd8a4b26a9adee87e5274b82a6d1d84a57 (patch)
tree67669984d799aa59e009cf205cccdf1d8ba23044
parent610a6a4e262868381677838fdd3571e22adee12e (diff)
fdo#78062: Broadcast only on non-empty cells within deleted range.
We don't want to broadcast over the whole selected range, which may be the whole sheet which is well over 1 billion cells ! (cherry picked from commit af7df25bcc8bc95462e2b3bf8c003d035111a479) Conflicts: sc/source/ui/inc/undobase.hxx sc/source/ui/undo/undobase.cxx Change-Id: I7c139ce5efe09312cf824e35f0efe551184032eb Reviewed-on: https://gerrit.libreoffice.org/9240 Tested-by: Markus Mohrhard <markus.mohrhard@googlemail.com> Reviewed-by: Markus Mohrhard <markus.mohrhard@googlemail.com>
-rw-r--r--sc/inc/columnspanset.hxx8
-rw-r--r--sc/source/core/data/columnspanset.cxx47
-rw-r--r--sc/source/ui/inc/undobase.hxx13
-rw-r--r--sc/source/ui/inc/undoblk.hxx4
-rw-r--r--sc/source/ui/undo/undobase.cxx45
-rw-r--r--sc/source/ui/undo/undoblk3.cxx12
-rw-r--r--sc/source/ui/view/viewfunc.cxx32
7 files changed, 155 insertions, 6 deletions
diff --git a/sc/inc/columnspanset.hxx b/sc/inc/columnspanset.hxx
index 62e96a8a41bd..c12f13e9b2d9 100644
--- a/sc/inc/columnspanset.hxx
+++ b/sc/inc/columnspanset.hxx
@@ -39,8 +39,10 @@ struct RowSpan
*/
class ColumnSpanSet : boost::noncopyable
{
+public:
typedef mdds::flat_segment_tree<SCROW, bool> ColumnSpansType;
+private:
struct ColumnType
{
ColumnSpansType maSpans;
@@ -81,6 +83,12 @@ public:
void set(SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, bool bVal);
void set(const ScRange& rRange, bool bVal);
+ /**
+ * Scan specified range in a specified sheet and mark all non-empty cells
+ * with specified boolean value.
+ */
+ void scan(const ScDocument& rDoc, SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bVal);
+
void executeAction(Action& ac) const;
void executeColumnAction(ScDocument& rDoc, ColumnAction& ac) const;
};
diff --git a/sc/source/core/data/columnspanset.cxx b/sc/source/core/data/columnspanset.cxx
index efa51b5a2707..7bc517b61331 100644
--- a/sc/source/core/data/columnspanset.cxx
+++ b/sc/source/core/data/columnspanset.cxx
@@ -20,6 +20,29 @@
namespace sc {
+namespace {
+
+class ColumnScanner
+{
+ ColumnSpanSet::ColumnSpansType& mrRanges;
+ bool mbVal;
+public:
+ ColumnScanner(ColumnSpanSet::ColumnSpansType& rRanges, bool bVal) :
+ mrRanges(rRanges), mbVal(bVal) {}
+
+ void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
+ {
+ if (node.type == sc::element_type_empty)
+ return;
+
+ size_t nRow = node.position + nOffset;
+ size_t nEndRow = nRow + nDataSize; // Last row of current block plus 1
+ mrRanges.insert_back(nRow, nEndRow, mbVal);
+ }
+};
+
+}
+
RowSpan::RowSpan(SCROW nRow1, SCROW nRow2) : mnRow1(nRow1), mnRow2(nRow2) {}
ColumnSpanSet::ColumnType::ColumnType(SCROW nStart, SCROW nEnd, bool bInit) :
@@ -94,6 +117,30 @@ void ColumnSpanSet::set(const ScRange& rRange, bool bVal)
}
}
+void ColumnSpanSet::scan(
+ const ScDocument& rDoc, SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bVal)
+{
+ if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2))
+ return;
+
+ if (nCol1 > nCol2 || nRow1 > nRow2)
+ return;
+
+ const ScTable* pTab = rDoc.FetchTable(nTab);
+ if (!pTab)
+ return;
+
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ {
+ ColumnType& rCol = getColumn(nTab, nCol);
+
+ const CellStoreType& rSrcCells = pTab->aCol[nCol].maCells;
+
+ ColumnScanner aScanner(rCol.maSpans, bVal);
+ ParseBlock(rSrcCells.begin(), rSrcCells, aScanner, nRow1, nRow2);
+ }
+}
+
void ColumnSpanSet::executeAction(Action& ac) const
{
for (size_t nTab = 0; nTab < maDoc.size(); ++nTab)
diff --git a/sc/source/ui/inc/undobase.hxx b/sc/source/ui/inc/undobase.hxx
index 5c9df4bf9f62..fd8430356b30 100644
--- a/sc/source/ui/inc/undobase.hxx
+++ b/sc/source/ui/inc/undobase.hxx
@@ -24,6 +24,9 @@
#include "global.hxx"
#include "address.hxx"
#include "docsh.hxx"
+#include <columnspanset.hxx>
+
+#include <boost/ptr_container/ptr_map.hpp>
class ScDocument;
class ScDocShell;
@@ -39,6 +42,8 @@ class ScSimpleUndo: public SfxUndoAction
public:
TYPEINFO();
+ typedef boost::ptr_map<SCTAB,sc::ColumnSpanSet> DataSpansType;
+
ScSimpleUndo( ScDocShell* pDocSh );
virtual ~ScSimpleUndo();
@@ -59,6 +64,14 @@ protected:
void BroadcastChanges( const ScRange& rRange );
+ /**
+ * Broadcast changes on specified spans.
+ *
+ * @param rSpans container that specifies all spans whose changes need to
+ * be broadcasted.
+ */
+ void BroadcastChanges( const DataSpansType& rSpans );
+
static void ShowTable( SCTAB nTab );
static void ShowTable( const ScRange& rRange );
};
diff --git a/sc/source/ui/inc/undoblk.hxx b/sc/source/ui/inc/undoblk.hxx
index 758e5bb91357..007c6e1e39b6 100644
--- a/sc/source/ui/inc/undoblk.hxx
+++ b/sc/source/ui/inc/undoblk.hxx
@@ -274,7 +274,11 @@ public:
virtual OUString GetComment() const;
+ void SetDataSpans( const boost::shared_ptr<DataSpansType>& pSpans );
+
private:
+ boost::shared_ptr<DataSpansType> mpDataSpans; // Spans of non-empty cells.
+
ScRange aRange;
ScMarkData aMarkData;
ScDocument* pUndoDoc; // Block mark and deleted data
diff --git a/sc/source/ui/undo/undobase.cxx b/sc/source/ui/undo/undobase.cxx
index 77f83456e684..609b6febf893 100644
--- a/sc/source/ui/undo/undobase.cxx
+++ b/sc/source/ui/undo/undobase.cxx
@@ -30,8 +30,7 @@
#include "queryparam.hxx"
#include "subtotalparam.hxx"
#include "globstr.hrc"
-
-// STATIC DATA -----------------------------------------------------------
+#include <column.hxx>
TYPEINIT1(ScSimpleUndo, SfxUndoAction);
TYPEINIT1(ScBlockUndo, ScSimpleUndo);
@@ -148,6 +147,48 @@ void ScSimpleUndo::BroadcastChanges( const ScRange& rRange )
pDoc->BroadcastCells(rRange, SC_HINT_DATACHANGED);
}
+namespace {
+
+class SpanBroadcaster : public sc::ColumnSpanSet::ColumnAction
+{
+ ScDocument& mrDoc;
+ SCTAB mnCurTab;
+ SCCOL mnCurCol;
+
+public:
+ SpanBroadcaster( ScDocument& rDoc ) : mrDoc(rDoc), mnCurTab(-1), mnCurCol(-1) {}
+
+ virtual void startColumn( ScColumn* pCol )
+ {
+ mnCurTab = pCol->GetTab();
+ mnCurCol = pCol->GetCol();
+ }
+
+ virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal )
+ {
+ if (!bVal)
+ return;
+
+ ScRange aRange(mnCurTab, mnCurCol, nRow1, mnCurTab, mnCurCol, nRow2);
+ mrDoc.BroadcastCells(aRange, SC_HINT_DATACHANGED);
+ };
+};
+
+}
+
+void ScSimpleUndo::BroadcastChanges( const DataSpansType& rSpans )
+{
+ ScDocument* pDoc = pDocShell->GetDocument();
+ SpanBroadcaster aBroadcaster(*pDoc);
+
+ DataSpansType::const_iterator it = rSpans.begin(), itEnd = rSpans.end();
+ for (; it != itEnd; ++it)
+ {
+ const sc::ColumnSpanSet& rSet = *it->second;
+ rSet.executeColumnAction(*pDoc, aBroadcaster);
+ }
+}
+
void ScSimpleUndo::ShowTable( SCTAB nTab )
{
ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
diff --git a/sc/source/ui/undo/undoblk3.cxx b/sc/source/ui/undo/undoblk3.cxx
index a06a07627ebf..6c258e064c9a 100644
--- a/sc/source/ui/undo/undoblk3.cxx
+++ b/sc/source/ui/undo/undoblk3.cxx
@@ -105,6 +105,11 @@ OUString ScUndoDeleteContents::GetComment() const
return ScGlobal::GetRscString( STR_UNDO_DELETECONTENTS ); // "Delete"
}
+void ScUndoDeleteContents::SetDataSpans( const boost::shared_ptr<DataSpansType>& pSpans )
+{
+ mpDataSpans = pSpans;
+}
+
void ScUndoDeleteContents::SetChangeTrack()
{
ScChangeTrack* pChangeTrack = pDocShell->GetDocument()->GetChangeTrack();
@@ -183,8 +188,13 @@ void ScUndoDeleteContents::Undo()
EndUndo();
if (nFlags & IDF_CONTENTS)
+ {
// Broadcast only when the content changes. fdo#74687
- BroadcastChanges(aRange);
+ if (mpDataSpans)
+ BroadcastChanges(*mpDataSpans);
+ else
+ BroadcastChanges(aRange);
+ }
HelperNotifyChanges::NotifyIfChangesListeners(*pDocShell, aRange);
}
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index dd4e56234885..e308caddf3ad 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -1854,6 +1854,9 @@ void ScViewFunc::DeleteContents( sal_uInt16 nFlags, bool bRecord )
aFuncMark );
}
+ // To keep track of all non-empty cells within the deleted area.
+ boost::shared_ptr<ScSimpleUndo::DataSpansType> pDataSpans;
+
if ( bRecord )
{
pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
@@ -1880,6 +1883,26 @@ void ScViewFunc::DeleteContents( sal_uInt16 nFlags, bool bRecord )
// do not copy note captions to undo document
nUndoDocFlags |= IDF_NOCAPTIONS;
pDoc->CopyToDocument( aCopyRange, nUndoDocFlags, bMulti, pUndoDoc, &aFuncMark );
+
+ pDataSpans.reset(new ScSimpleUndo::DataSpansType);
+
+ for (itr = aFuncMark.begin(); itr != itrEnd; ++itr)
+ {
+ nTab = *itr;
+
+ SCCOL nCol1 = aCopyRange.aStart.Col(), nCol2 = aCopyRange.aEnd.Col();
+ SCROW nRow1 = aCopyRange.aStart.Row(), nRow2 = aCopyRange.aEnd.Row();
+
+ std::pair<ScSimpleUndo::DataSpansType::iterator,bool> r =
+ pDataSpans->insert(nTab, new sc::ColumnSpanSet(false));
+
+ if (r.second)
+ {
+ ScSimpleUndo::DataSpansType::iterator it = r.first;
+ sc::ColumnSpanSet* pSet = it->second;
+ pSet->scan(*pDoc, nTab, nCol1, nRow1, nCol2, nRow2, true);
+ }
+ }
}
HideAllCursors(); // for if summary is cancelled
@@ -1894,9 +1917,12 @@ void ScViewFunc::DeleteContents( sal_uInt16 nFlags, bool bRecord )
if ( bRecord )
{
- pDocSh->GetUndoManager()->AddUndoAction(
- new ScUndoDeleteContents( pDocSh, aFuncMark, aExtendedRange,
- pUndoDoc, bMulti, nFlags, bDrawUndo ) );
+ ScUndoDeleteContents* pUndo =
+ new ScUndoDeleteContents(
+ pDocSh, aFuncMark, aExtendedRange, pUndoDoc, bMulti, nFlags, bDrawUndo);
+ pUndo->SetDataSpans(pDataSpans);
+
+ pDocSh->GetUndoManager()->AddUndoAction(pUndo);
}
if (!AdjustRowHeight( aExtendedRange.aStart.Row(), aExtendedRange.aEnd.Row() ))