profile: implement proper model/view semantics in ProfileWidget2

The ProfileWidget2 slots, which reacted to model changes were
broken. They did not add / remove items at the changed positions,
but arbitrarily at the end. Moreover, they assumed that only
a single item was added / removed and thus violated the model/view
API.

This worked because the handles are completely reset after each
operation and the model only ever touched single items.
Nevertheless, this has to be fixed if we ever want finer grained
undo.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2021-01-24 23:29:28 +01:00 committed by Dirk Hohndel
parent 396758d489
commit 79ddb23edf
2 changed files with 43 additions and 6 deletions

View file

@ -1286,6 +1286,7 @@ void ProfileWidget2::setAddState()
DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
connect(plannerModel, &DivePlannerPointsModel::dataChanged, this, &ProfileWidget2::replot); connect(plannerModel, &DivePlannerPointsModel::dataChanged, this, &ProfileWidget2::replot);
connect(plannerModel, &DivePlannerPointsModel::cylinderModelEdited, this, &ProfileWidget2::replot); connect(plannerModel, &DivePlannerPointsModel::cylinderModelEdited, this, &ProfileWidget2::replot);
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);
/* show the same stuff that the profile shows. */ /* show the same stuff that the profile shows. */
@ -1317,6 +1318,7 @@ void ProfileWidget2::setPlanState()
DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
connect(plannerModel, &DivePlannerPointsModel::dataChanged, this, &ProfileWidget2::replot); connect(plannerModel, &DivePlannerPointsModel::dataChanged, this, &ProfileWidget2::replot);
connect(plannerModel, &DivePlannerPointsModel::cylinderModelEdited, this, &ProfileWidget2::replot); connect(plannerModel, &DivePlannerPointsModel::cylinderModelEdited, this, &ProfileWidget2::replot);
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);
/* show the same stuff that the profile shows. */ /* show the same stuff that the profile shows. */
@ -1684,8 +1686,10 @@ void ProfileWidget2::disconnectTemporaryConnections()
disconnect(plannerModel, &DivePlannerPointsModel::dataChanged, this, &ProfileWidget2::replot); disconnect(plannerModel, &DivePlannerPointsModel::dataChanged, this, &ProfileWidget2::replot);
disconnect(plannerModel, &DivePlannerPointsModel::cylinderModelEdited, this, &ProfileWidget2::replot); disconnect(plannerModel, &DivePlannerPointsModel::cylinderModelEdited, this, &ProfileWidget2::replot);
disconnect(plannerModel, &DivePlannerPointsModel::modelReset, this, &ProfileWidget2::pointsReset);
disconnect(plannerModel, &DivePlannerPointsModel::rowsInserted, this, &ProfileWidget2::pointInserted); disconnect(plannerModel, &DivePlannerPointsModel::rowsInserted, this, &ProfileWidget2::pointInserted);
disconnect(plannerModel, &DivePlannerPointsModel::rowsRemoved, this, &ProfileWidget2::pointsRemoved); disconnect(plannerModel, &DivePlannerPointsModel::rowsRemoved, this, &ProfileWidget2::pointsRemoved);
disconnect(plannerModel, &DivePlannerPointsModel::rowsMoved, this, &ProfileWidget2::pointsMoved);
#endif #endif
Q_FOREACH (QAction *action, actionsForKeys.values()) { Q_FOREACH (QAction *action, actionsForKeys.values()) {
action->setShortcut(QKeySequence()); action->setShortcut(QKeySequence());
@ -1702,22 +1706,45 @@ int ProfileWidget2::handleIndex(const DiveHandler *h) const
} }
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
void ProfileWidget2::pointInserted(const QModelIndex&, int, int)
DiveHandler *ProfileWidget2::createHandle()
{ {
DiveHandler *item = new DiveHandler(&displayed_dive); DiveHandler *item = new DiveHandler(&displayed_dive);
scene()->addItem(item); scene()->addItem(item);
handles.emplace_back(item);
connect(item, &DiveHandler::moved, this, &ProfileWidget2::recreatePlannedDive); connect(item, &DiveHandler::moved, this, &ProfileWidget2::recreatePlannedDive);
connect(item, &DiveHandler::clicked, this, &ProfileWidget2::divePlannerHandlerClicked); connect(item, &DiveHandler::clicked, this, &ProfileWidget2::divePlannerHandlerClicked);
connect(item, &DiveHandler::released, this, &ProfileWidget2::divePlannerHandlerReleased); connect(item, &DiveHandler::released, this, &ProfileWidget2::divePlannerHandlerReleased);
return item;
}
QGraphicsSimpleTextItem *ProfileWidget2::createGas()
{
QGraphicsSimpleTextItem *gasChooseBtn = new QGraphicsSimpleTextItem(); QGraphicsSimpleTextItem *gasChooseBtn = new QGraphicsSimpleTextItem();
scene()->addItem(gasChooseBtn); scene()->addItem(gasChooseBtn);
gasChooseBtn->setZValue(10); gasChooseBtn->setZValue(10);
gasChooseBtn->setFlag(QGraphicsItem::ItemIgnoresTransformations); gasChooseBtn->setFlag(QGraphicsItem::ItemIgnoresTransformations);
gases.emplace_back(gasChooseBtn); return gasChooseBtn;
DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); }
if (plannerModel->recalcQ())
void ProfileWidget2::pointsReset()
{
handles.clear();
gases.clear();
int count = DivePlannerPointsModel::instance()->rowCount();
for (int i = 0; i < count; ++i) {
handles.emplace_back(createHandle());
gases.emplace_back(createGas());
}
}
void ProfileWidget2::pointInserted(const QModelIndex &, int from, int to)
{
for (int i = from; i <= to; ++i) {
handles.emplace(handles.begin() + i, createHandle());
gases.emplace(gases.begin() + i, createGas());
}
if (DivePlannerPointsModel::instance()->recalcQ())
replot(); replot();
} }
@ -1730,6 +1757,12 @@ void ProfileWidget2::pointsRemoved(const QModelIndex &, int start, int end)
replot(); replot();
} }
void ProfileWidget2::pointsMoved(const QModelIndex &, int start, int end, const QModelIndex &, int row)
{
moveInVector(handles, start, end + 1, row);
moveInVector(gases, start, end + 1, row);
}
void ProfileWidget2::repositionDiveHandlers() void ProfileWidget2::repositionDiveHandlers()
{ {
DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();

View file

@ -112,8 +112,10 @@ slots: // Necessary to call from QAction's signals.
void picturesAdded(dive *d, QVector<PictureObj> pics); void picturesAdded(dive *d, QVector<PictureObj> pics);
void setPlanState(); void setPlanState();
void setAddState(); void setAddState();
void pointsReset();
void pointInserted(const QModelIndex &parent, int start, int end); void pointInserted(const QModelIndex &parent, int start, int end);
void pointsRemoved(const QModelIndex &, int start, int end); void pointsRemoved(const QModelIndex &, int start, int end);
void pointsMoved(const QModelIndex &, int start, int end, const QModelIndex &destination, int row);
void updateThumbnail(QString filename, QImage thumbnail, duration_t duration); void updateThumbnail(QString filename, QImage thumbnail, duration_t duration);
void profileChanged(dive *d); void profileChanged(dive *d);
void pictureOffsetChanged(dive *d, QString filename, offset_t offset); void pictureOffsetChanged(dive *d, QString filename, offset_t offset);
@ -256,6 +258,8 @@ private:
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
void repositionDiveHandlers(); void repositionDiveHandlers();
int fixHandlerIndex(DiveHandler *activeHandler); int fixHandlerIndex(DiveHandler *activeHandler);
DiveHandler *createHandle();
QGraphicsSimpleTextItem *createGas();
#endif #endif
friend class DiveHandler; friend class DiveHandler;
QHash<Qt::Key, QAction *> actionsForKeys; QHash<Qt::Key, QAction *> actionsForKeys;