Move the aliases before other content of cells

When a user performs insert rows, remove rows, insert columns, or
remove rows, we need to move multiple cells as a batch. The cells are
moved sequentially. For each cell, its dependent alias positions are
looked up and dependencies are added.  However, those cells with
aliases may be moved later in the batch. Thus the earlier dependencies
become wrong. This commit fixes this bug by moving all the aliases
before moving the cells. Unit tests are added to for this bug.

fixes issue #4429
This commit is contained in:
Cheuksan Wang
2020-09-12 17:38:03 -07:00
committed by wmayer
parent 1a7fd88bc3
commit 0aa759b5c5
3 changed files with 119 additions and 23 deletions

View File

@@ -588,7 +588,17 @@ void PropertySheet::setSpans(CellAddress address, int rows, int columns)
nonNullCellAt(address)->setSpans(rows, columns);
}
void PropertySheet::clear(CellAddress address)
void PropertySheet::clearAlias(CellAddress address)
{
// Remove alias if it exists
std::map<CellAddress, std::string>::iterator j = aliasProp.find(address);
if (j != aliasProp.end()) {
revAliasProp.erase(j->second);
aliasProp.erase(j);
}
}
void PropertySheet::clear(CellAddress address, bool toClearAlias)
{
std::map<CellAddress, Cell*>::iterator i = data.find(address);
@@ -607,18 +617,24 @@ void PropertySheet::clear(CellAddress address)
// Mark as dirty
dirty.insert(i->first);
// Remove alias if it exists
std::map<CellAddress, std::string>::iterator j = aliasProp.find(address);
if (j != aliasProp.end()) {
revAliasProp.erase(j->second);
aliasProp.erase(j);
}
if (toClearAlias)
clearAlias(address);
// Erase from internal struct
data.erase(i);
signaller.tryInvoke();
}
void PropertySheet::moveAlias(CellAddress currPos, CellAddress newPos)
{
std::map<CellAddress, std::string>::iterator j = aliasProp.find(currPos);
if (j != aliasProp.end()) {
aliasProp[newPos] = j->second;
revAliasProp[j->second] = newPos;
aliasProp.erase(currPos);
}
}
void PropertySheet::moveCell(CellAddress currPos, CellAddress newPos, std::map<App::ObjectIdentifier, App::ObjectIdentifier> & renames)
{
std::map<CellAddress, Cell*>::const_iterator i = data.find(currPos);
@@ -626,8 +642,10 @@ void PropertySheet::moveCell(CellAddress currPos, CellAddress newPos, std::map<A
AtomicPropertyChange signaller(*this);
if (j != data.end())
clear(newPos);
if (j != data.end()) {
// do not clear alias because we have moved them already
clear(newPos, false);
}
if (i != data.end()) {
Cell * cell = i->second;
@@ -639,12 +657,6 @@ void PropertySheet::moveCell(CellAddress currPos, CellAddress newPos, std::map<A
// Remove merged cell data
splitCell(currPos);
std::string alias;
if(cell->getAlias(alias)) {
owner->aliasRemoved(currPos, alias);
cell->setAlias("");
}
// Remove from old
removeDependencies(currPos);
data.erase(currPos);
@@ -664,9 +676,6 @@ void PropertySheet::moveCell(CellAddress currPos, CellAddress newPos, std::map<A
addDependencies(newPos);
if(alias.size())
cell->setAlias(alias);
setDirty(newPos);
renames[ObjectIdentifier(owner, currPos.toString())] = ObjectIdentifier(owner, newPos.toString());
@@ -689,6 +698,13 @@ void PropertySheet::insertRows(int row, int count)
CellAddress(row, CellAddress::MAX_COLUMNS), count, 0);
AtomicPropertyChange signaller(*this);
// move all the aliases first so dependencies can be calculated correctly
for (std::vector<CellAddress>::const_reverse_iterator i = keys.rbegin(); i != keys.rend(); ++i) {
if (i->row() >= row)
moveAlias(*i, CellAddress(i->row() + count, i->col()));
}
for (std::vector<CellAddress>::const_reverse_iterator i = keys.rbegin(); i != keys.rend(); ++i) {
std::map<CellAddress, Cell*>::iterator j = data.find(*i);
@@ -740,6 +756,15 @@ void PropertySheet::removeRows(int row, int count)
CellAddress(row + count - 1, CellAddress::MAX_COLUMNS), -count, 0);
AtomicPropertyChange signaller(*this);
// move all the aliases first so dependencies can be calculated correctly
for (std::vector<CellAddress>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
if (i->row() >= row && i->row() < row + count)
clearAlias(*i);
else if (i->row() >= row + count)
moveAlias(*i, CellAddress(i->row() - count, i->col()));
}
for (std::vector<CellAddress>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
std::map<CellAddress, Cell*>::iterator j = data.find(*i);
@@ -756,7 +781,7 @@ void PropertySheet::removeRows(int row, int count)
}
if (i->row() >= row && i->row() < row + count)
clear(*i);
clear(*i, false); // aliases were cleared earlier
else if (i->row() >= row + count)
moveCell(*i, CellAddress(i->row() - count, i->col()), renames);
}
@@ -781,6 +806,13 @@ void PropertySheet::insertColumns(int col, int count)
CellAddress(CellAddress::MAX_ROWS, col), 0, count);
AtomicPropertyChange signaller(*this);
// move all the aliases first so dependencies can be calculated correctly
for (std::vector<CellAddress>::const_reverse_iterator i = keys.rbegin(); i != keys.rend(); ++i) {
if (i->col() >= col)
moveAlias(*i, CellAddress(i->row(), i->col() + count));
}
for (std::vector<CellAddress>::const_reverse_iterator i = keys.rbegin(); i != keys.rend(); ++i) {
std::map<CellAddress, Cell*>::iterator j = data.find(*i);
@@ -832,6 +864,15 @@ void PropertySheet::removeColumns(int col, int count)
CellAddress(CellAddress::MAX_ROWS, col + count - 1), 0, -count);
AtomicPropertyChange signaller(*this);
// move all the aliases first so dependencies can be calculated correctly
for (std::vector<CellAddress>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
if (i->col() >= col && i->col() < col + count)
clearAlias(*i);
else if (i->col() >= col + count)
moveAlias(*i, CellAddress(i->row(), i->col() - count));
}
for (std::vector<CellAddress>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
std::map<CellAddress, Cell*>::iterator j = data.find(*i);
@@ -848,7 +889,7 @@ void PropertySheet::removeColumns(int col, int count)
}
if (i->col() >= col && i->col() < col + count)
clear(*i);
clear(*i, false); // aliases were cleared earlier
else if (i->col() >= col + count)
moveCell(*i, CellAddress(i->row(), i->col() - count), renames);
}