planner: implement move semantics in DivePlannerPointsModel

When reordering the points, the DivePlannerPointsModel would
not emit the appropriate move signals, but simply a data-changed
signal over all elements. This obviously violates Qt's
model/view API, though it is probably harmless. Let's do
the right thing so that the frontend knows that the selected
item changed place.

Also, emit dataChanged only on the actually changed element,
not all elements.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2021-01-25 14:29:47 +01:00 committed by Dirk Hohndel
parent 79ddb23edf
commit dee1fea683
2 changed files with 35 additions and 4 deletions

View file

@ -1289,6 +1289,7 @@ void ProfileWidget2::setAddState()
connect(plannerModel, &DivePlannerPointsModel::modelReset, this, &ProfileWidget2::pointsReset); connect(plannerModel, &DivePlannerPointsModel::modelReset, this, &ProfileWidget2::pointsReset);
connect(plannerModel, &DivePlannerPointsModel::rowsInserted, this, &ProfileWidget2::pointInserted); connect(plannerModel, &DivePlannerPointsModel::rowsInserted, this, &ProfileWidget2::pointInserted);
connect(plannerModel, &DivePlannerPointsModel::rowsRemoved, this, &ProfileWidget2::pointsRemoved); connect(plannerModel, &DivePlannerPointsModel::rowsRemoved, this, &ProfileWidget2::pointsRemoved);
connect(plannerModel, &DivePlannerPointsModel::rowsMoved, this, &ProfileWidget2::pointsMoved);
/* show the same stuff that the profile shows. */ /* show the same stuff that the profile shows. */
currentState = ADD; /* enable the add state. */ currentState = ADD; /* enable the add state. */
diveCeiling->setVisible(true); diveCeiling->setVisible(true);
@ -1321,6 +1322,7 @@ void ProfileWidget2::setPlanState()
connect(plannerModel, &DivePlannerPointsModel::modelReset, this, &ProfileWidget2::pointsReset); connect(plannerModel, &DivePlannerPointsModel::modelReset, this, &ProfileWidget2::pointsReset);
connect(plannerModel, &DivePlannerPointsModel::rowsInserted, this, &ProfileWidget2::pointInserted); connect(plannerModel, &DivePlannerPointsModel::rowsInserted, this, &ProfileWidget2::pointInserted);
connect(plannerModel, &DivePlannerPointsModel::rowsRemoved, this, &ProfileWidget2::pointsRemoved); connect(plannerModel, &DivePlannerPointsModel::rowsRemoved, this, &ProfileWidget2::pointsRemoved);
connect(plannerModel, &DivePlannerPointsModel::rowsMoved, this, &ProfileWidget2::pointsMoved);
/* show the same stuff that the profile shows. */ /* show the same stuff that the profile shows. */
currentState = PLAN; /* enable the add state. */ currentState = PLAN; /* enable the add state. */
diveCeiling->setVisible(true); diveCeiling->setVisible(true);

View file

@ -831,20 +831,49 @@ int DivePlannerPointsModel::addStop(int milimeters, int seconds, int cylinderid_
void DivePlannerPointsModel::editStop(int row, divedatapoint newData) void DivePlannerPointsModel::editStop(int row, divedatapoint newData)
{ {
if (row < 0 || row >= divepoints.count())
return;
// Refuse to move to 0, since that has special meaning.
if (newData.time <= 0)
return;
/* /*
* When moving divepoints rigorously, we might end up with index * When moving divepoints rigorously, we might end up with index
* out of range, thus returning the last one instead. * out of range, thus returning the last one instead.
*/ */
int old_first_cylid = divepoints[0].cylinderid; int old_first_cylid = divepoints[0].cylinderid;
if (row >= divepoints.count())
return; // Is it ok to change data first and then move the rows?
divepoints[row] = newData; divepoints[row] = newData;
std::sort(divepoints.begin(), divepoints.end(), divePointsLessThan);
// If the time changed, the item might have to be moved. Oh joy.
int newRow = row;
while (newRow + 1 < divepoints.count() && divepoints[newRow + 1].time < divepoints[row].time)
++newRow;
if (newRow != row) {
++newRow; // Move one past item with smaller time stamp
} else {
// If we didn't move forward, try moving backwards
while (newRow > 0 && divepoints[newRow - 1].time > divepoints[row].time)
--newRow;
}
if (newRow != row && newRow != row + 1) {
beginMoveRows(QModelIndex(), row, row, QModelIndex(), newRow);
moveInVector(divepoints, row, row + 1, newRow);
endMoveRows();
// Account for moving the row backwards in the array.
row = newRow > row ? newRow - 1 : newRow;
}
if (updateMaxDepth()) if (updateMaxDepth())
cylinders.updateBestMixes(); cylinders.updateBestMixes();
if (divepoints[0].cylinderid != old_first_cylid) if (divepoints[0].cylinderid != old_first_cylid)
cylinders.moveAtFirst(divepoints[0].cylinderid); cylinders.moveAtFirst(divepoints[0].cylinderid);
emitDataChanged();
emit dataChanged(createIndex(row, 0), createIndex(row, COLUMNS - 1));
} }
int DivePlannerPointsModel::size() const int DivePlannerPointsModel::size() const