summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2014-08-14 23:36:47 +0200
committerEike Rathke <erack@redhat.com>2014-08-14 23:50:58 +0200
commit69adec3ec051ff94f600ab899506ca9d645a8b56 (patch)
treeb59a4a2076b540925cbdec296b8ca60fd1b8cd91
parent4b8a131d3897a3fda8d4e8fe635f19cc41bed36a (diff)
correct references after sort, fdo#79441
5c6ee09126631342939ae8766fe36083d8c011e3 introduced a different algorithm for reference handling during sort. Unfortunately that clashed with the SC_CLONECELL_ADJUST3DREL introduced a little earlier resulting in relative 3D references effectively being "adjusted" twice. Furthermore, in-sort-range range references to one row (or column) were not adapted to the move at all if the formula within the range listened only to ranges and not a single cell. Added collecting and adjusting area listeners for this. Last but not least, external (relative) references need to be treated the same as internal 3D references, making them point to the same location after the sort. Change-Id: I492768b525f95f1c43d1c6e7a63a36cce093fa5a
-rw-r--r--sc/inc/types.hxx4
-rw-r--r--sc/source/core/data/bcaslot.cxx33
-rw-r--r--sc/source/core/data/table3.cxx67
-rw-r--r--sc/source/core/tool/token.cxx2
4 files changed, 95 insertions, 11 deletions
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 8dc8f181f28d..d40b2a5e110e 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -103,7 +103,9 @@ typedef boost::unordered_map<SCCOLROW,SCCOLROW> ColRowReorderMapType;
enum AreaOverlapType
{
AreaInside,
- AreaPartialOverlap
+ AreaPartialOverlap,
+ OneRowInsideArea,
+ OneColumnInsideArea
};
}
diff --git a/sc/source/core/data/bcaslot.cxx b/sc/source/core/data/bcaslot.cxx
index ea70ffbd3615..2192706c0416 100644
--- a/sc/source/core/data/bcaslot.cxx
+++ b/sc/source/core/data/bcaslot.cxx
@@ -444,14 +444,31 @@ void ScBroadcastAreaSlot::GetAllListeners(
ScBroadcastArea* pArea = (*aIter).mpArea;
const ScRange& rAreaRange = pArea->GetRange();
- if (eType == sc::AreaInside && !rRange.In(rAreaRange))
- // The range needs to be fully inside specified range.
- continue;
-
- if (eType == sc::AreaPartialOverlap &&
- (!rRange.Intersects(rAreaRange) || rRange.In(rAreaRange)))
- // The range needs to be only partially overlapping.
- continue;
+ switch (eType)
+ {
+ case sc::AreaInside:
+ if (!rRange.In(rAreaRange))
+ // The range needs to be fully inside specified range.
+ continue;
+ break;
+ case sc::AreaPartialOverlap:
+ if (!rRange.Intersects(rAreaRange) || rRange.In(rAreaRange))
+ // The range needs to be only partially overlapping.
+ continue;
+ break;
+ case sc::OneRowInsideArea:
+ if (rAreaRange.aStart.Row() != rAreaRange.aEnd.Row() || !rRange.In(rAreaRange))
+ // The range needs to be one single row and fully inside
+ // specified range.
+ continue;
+ break;
+ case sc::OneColumnInsideArea:
+ if (rAreaRange.aStart.Col() != rAreaRange.aEnd.Col() || !rRange.In(rAreaRange))
+ // The range needs to be one single column and fully inside
+ // specified range.
+ continue;
+ break;
+ }
SvtBroadcaster::ListenersType& rLst = pArea->GetBroadcaster().GetAllListeners();
SvtBroadcaster::ListenersType::iterator itLst = rLst.begin(), itLstEnd = rLst.end();
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index 25e088fcc231..0409f14e3e07 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -60,6 +60,7 @@
#include <sharedformula.hxx>
#include <refhint.hxx>
#include <listenerquery.hxx>
+#include <bcaslot.hxx>
#include <svl/sharedstringpool.hxx>
@@ -717,6 +718,21 @@ void ScTable::SortReorderByColumn(
// Collect all listeners within sorted range ahead of time.
std::vector<SvtListener*> aListeners;
+
+ // Get all area listeners that listen on one column within the range and
+ // end their listening.
+ ScRange aMoveRange( nStart, nRow1, nTab, nLast, nRow2, nTab);
+ std::vector<sc::AreaListener> aAreaListeners = pDocument->GetBASM()->GetAllListeners(
+ aMoveRange, sc::OneColumnInsideArea);
+ {
+ std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
+ for (; it != itEnd; ++it)
+ {
+ pDocument->EndListeningArea(it->maArea, it->mpListener);
+ aListeners.push_back( it->mpListener);
+ }
+ }
+
for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
aCol[nCol].CollectListeners(aListeners, nRow1, nRow2);
@@ -728,6 +744,22 @@ void ScTable::SortReorderByColumn(
ColReorderNotifier aFunc(aColMap, nTab, nRow1, nRow2);
std::for_each(aListeners.begin(), aListeners.end(), aFunc);
+ // Re-start area listeners on the reordered columns.
+ {
+ std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
+ for (; it != itEnd; ++it)
+ {
+ ScRange aNewRange = it->maArea;
+ sc::ColRowReorderMapType::const_iterator itCol = aColMap.find( aNewRange.aStart.Col());
+ if (itCol != aColMap.end())
+ {
+ aNewRange.aStart.SetCol( itCol->second);
+ aNewRange.aEnd.SetCol( itCol->second);
+ }
+ pDocument->StartListeningArea(aNewRange, it->mpListener);
+ }
+ }
+
// Re-join formulas at row boundaries now that all the references have
// been adjusted for column reordering.
for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
@@ -803,8 +835,7 @@ void ScTable::SortReorderByRow(
assert(rCell.mpAttr);
ScAddress aOldPos = rCell.maCell.mpFormula->aPos;
- ScFormulaCell* pNew = rCell.maCell.mpFormula->Clone(
- aCellPos, SC_CLONECELL_DEFAULT | SC_CLONECELL_ADJUST3DREL);
+ ScFormulaCell* pNew = rCell.maCell.mpFormula->Clone( aCellPos, SC_CLONECELL_DEFAULT);
pNew->CopyAllBroadcasters(*rCell.maCell.mpFormula);
pNew->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, aCellPos);
@@ -944,6 +975,22 @@ void ScTable::SortReorderByRow(
// Collect all listeners within sorted range ahead of time.
std::vector<SvtListener*> aListeners;
+
+ // Get all area listeners that listen on one row within the range and end
+ // their listening.
+ ScRange aMoveRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab);
+ std::vector<sc::AreaListener> aAreaListeners = pDocument->GetBASM()->GetAllListeners(
+ aMoveRange, sc::OneRowInsideArea);
+ {
+ std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
+ for (; it != itEnd; ++it)
+ {
+ pDocument->EndListeningArea(it->maArea, it->mpListener);
+ aListeners.push_back( it->mpListener);
+ }
+ }
+
+ // Collect listeners of cell broadcasters.
for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
aCol[nCol].CollectListeners(aListeners, nRow1, nRow2);
@@ -976,6 +1023,22 @@ void ScTable::SortReorderByRow(
RowReorderNotifier aFunc(aRowMap, nTab, nCol1, nCol2);
std::for_each(aListeners.begin(), aListeners.end(), aFunc);
+ // Re-start area listeners on the reordered rows.
+ {
+ std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
+ for (; it != itEnd; ++it)
+ {
+ ScRange aNewRange = it->maArea;
+ sc::ColRowReorderMapType::const_iterator itRow = aRowMap.find( aNewRange.aStart.Row());
+ if (itRow != aRowMap.end())
+ {
+ aNewRange.aStart.SetRow( itRow->second);
+ aNewRange.aEnd.SetRow( itRow->second);
+ }
+ pDocument->StartListeningArea(aNewRange, it->mpListener);
+ }
+ }
+
// Re-group formulas in affected columns.
for (itGroupTab = rGroupTabs.begin(); itGroupTab != itGroupTabEnd; ++itGroupTab)
{
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 34f9a16fdae1..0b7df591c1a7 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -3464,6 +3464,7 @@ void ScTokenArray::AdjustReferenceOnMovedOrigin( const ScAddress& rOldPos, const
switch ((*p)->GetType())
{
case svSingleRef:
+ case svExternalSingleRef:
{
ScToken* pToken = static_cast<ScToken*>(*p);
ScSingleRefData& rRef = pToken->GetSingleRef();
@@ -3472,6 +3473,7 @@ void ScTokenArray::AdjustReferenceOnMovedOrigin( const ScAddress& rOldPos, const
}
break;
case svDoubleRef:
+ case svExternalDoubleRef:
{
ScToken* pToken = static_cast<ScToken*>(*p);
ScComplexRefData& rRef = pToken->GetDoubleRef();