Kaydet (Commit) 69adec3e authored tarafından Eike Rathke's avatar Eike Rathke

correct references after sort, fdo#79441

5c6ee091 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
üst 4b8a131d
...@@ -103,7 +103,9 @@ typedef boost::unordered_map<SCCOLROW,SCCOLROW> ColRowReorderMapType; ...@@ -103,7 +103,9 @@ typedef boost::unordered_map<SCCOLROW,SCCOLROW> ColRowReorderMapType;
enum AreaOverlapType enum AreaOverlapType
{ {
AreaInside, AreaInside,
AreaPartialOverlap AreaPartialOverlap,
OneRowInsideArea,
OneColumnInsideArea
}; };
} }
......
...@@ -444,14 +444,31 @@ void ScBroadcastAreaSlot::GetAllListeners( ...@@ -444,14 +444,31 @@ void ScBroadcastAreaSlot::GetAllListeners(
ScBroadcastArea* pArea = (*aIter).mpArea; ScBroadcastArea* pArea = (*aIter).mpArea;
const ScRange& rAreaRange = pArea->GetRange(); const ScRange& rAreaRange = pArea->GetRange();
if (eType == sc::AreaInside && !rRange.In(rAreaRange)) switch (eType)
// The range needs to be fully inside specified range. {
continue; case sc::AreaInside:
if (!rRange.In(rAreaRange))
if (eType == sc::AreaPartialOverlap && // The range needs to be fully inside specified range.
(!rRange.Intersects(rAreaRange) || rRange.In(rAreaRange))) continue;
// The range needs to be only partially overlapping. break;
continue; 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& rLst = pArea->GetBroadcaster().GetAllListeners();
SvtBroadcaster::ListenersType::iterator itLst = rLst.begin(), itLstEnd = rLst.end(); SvtBroadcaster::ListenersType::iterator itLst = rLst.begin(), itLstEnd = rLst.end();
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include <sharedformula.hxx> #include <sharedformula.hxx>
#include <refhint.hxx> #include <refhint.hxx>
#include <listenerquery.hxx> #include <listenerquery.hxx>
#include <bcaslot.hxx>
#include <svl/sharedstringpool.hxx> #include <svl/sharedstringpool.hxx>
...@@ -717,6 +718,21 @@ void ScTable::SortReorderByColumn( ...@@ -717,6 +718,21 @@ void ScTable::SortReorderByColumn(
// Collect all listeners within sorted range ahead of time. // Collect all listeners within sorted range ahead of time.
std::vector<SvtListener*> aListeners; 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) for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
aCol[nCol].CollectListeners(aListeners, nRow1, nRow2); aCol[nCol].CollectListeners(aListeners, nRow1, nRow2);
...@@ -728,6 +744,22 @@ void ScTable::SortReorderByColumn( ...@@ -728,6 +744,22 @@ void ScTable::SortReorderByColumn(
ColReorderNotifier aFunc(aColMap, nTab, nRow1, nRow2); ColReorderNotifier aFunc(aColMap, nTab, nRow1, nRow2);
std::for_each(aListeners.begin(), aListeners.end(), aFunc); 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 // Re-join formulas at row boundaries now that all the references have
// been adjusted for column reordering. // been adjusted for column reordering.
for (SCCOL nCol = nStart; nCol <= nLast; ++nCol) for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
...@@ -803,8 +835,7 @@ void ScTable::SortReorderByRow( ...@@ -803,8 +835,7 @@ void ScTable::SortReorderByRow(
assert(rCell.mpAttr); assert(rCell.mpAttr);
ScAddress aOldPos = rCell.maCell.mpFormula->aPos; ScAddress aOldPos = rCell.maCell.mpFormula->aPos;
ScFormulaCell* pNew = rCell.maCell.mpFormula->Clone( ScFormulaCell* pNew = rCell.maCell.mpFormula->Clone( aCellPos, SC_CLONECELL_DEFAULT);
aCellPos, SC_CLONECELL_DEFAULT | SC_CLONECELL_ADJUST3DREL);
pNew->CopyAllBroadcasters(*rCell.maCell.mpFormula); pNew->CopyAllBroadcasters(*rCell.maCell.mpFormula);
pNew->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, aCellPos); pNew->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, aCellPos);
...@@ -944,6 +975,22 @@ void ScTable::SortReorderByRow( ...@@ -944,6 +975,22 @@ void ScTable::SortReorderByRow(
// Collect all listeners within sorted range ahead of time. // Collect all listeners within sorted range ahead of time.
std::vector<SvtListener*> aListeners; 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) for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
aCol[nCol].CollectListeners(aListeners, nRow1, nRow2); aCol[nCol].CollectListeners(aListeners, nRow1, nRow2);
...@@ -976,6 +1023,22 @@ void ScTable::SortReorderByRow( ...@@ -976,6 +1023,22 @@ void ScTable::SortReorderByRow(
RowReorderNotifier aFunc(aRowMap, nTab, nCol1, nCol2); RowReorderNotifier aFunc(aRowMap, nTab, nCol1, nCol2);
std::for_each(aListeners.begin(), aListeners.end(), aFunc); 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. // Re-group formulas in affected columns.
for (itGroupTab = rGroupTabs.begin(); itGroupTab != itGroupTabEnd; ++itGroupTab) for (itGroupTab = rGroupTabs.begin(); itGroupTab != itGroupTabEnd; ++itGroupTab)
{ {
......
...@@ -3464,6 +3464,7 @@ void ScTokenArray::AdjustReferenceOnMovedOrigin( const ScAddress& rOldPos, const ...@@ -3464,6 +3464,7 @@ void ScTokenArray::AdjustReferenceOnMovedOrigin( const ScAddress& rOldPos, const
switch ((*p)->GetType()) switch ((*p)->GetType())
{ {
case svSingleRef: case svSingleRef:
case svExternalSingleRef:
{ {
ScToken* pToken = static_cast<ScToken*>(*p); ScToken* pToken = static_cast<ScToken*>(*p);
ScSingleRefData& rRef = pToken->GetSingleRef(); ScSingleRefData& rRef = pToken->GetSingleRef();
...@@ -3472,6 +3473,7 @@ void ScTokenArray::AdjustReferenceOnMovedOrigin( const ScAddress& rOldPos, const ...@@ -3472,6 +3473,7 @@ void ScTokenArray::AdjustReferenceOnMovedOrigin( const ScAddress& rOldPos, const
} }
break; break;
case svDoubleRef: case svDoubleRef:
case svExternalDoubleRef:
{ {
ScToken* pToken = static_cast<ScToken*>(*p); ScToken* pToken = static_cast<ScToken*>(*p);
ScComplexRefData& rRef = pToken->GetDoubleRef(); ScComplexRefData& rRef = pToken->GetDoubleRef();
......
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