Profile: On dataChanged() only update pictures that actually changed

Only update those pictures of the DivePictureModel that actually changed.
This will be useful once pictures are loaded incrementally.

To do so, replace the pictures array by an array with stable ids. Before
this commit, not-shown pictures are left out of the pictures array, which
makes the mapping from DivePictureModel-ids to the picture array index
non-trivial.

Replace the QList<DivePictureItem *> by a std::vector<std::unique_ptr<DivePictureItem>>
to ease memory management. Sadly, owing to COW semantics, QVector is incompatible
with QScopedPointer.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2018-04-06 17:58:16 +02:00 committed by Dirk Hohndel
parent f633cb81ae
commit f1830cd44e
2 changed files with 45 additions and 17 deletions

View file

@ -778,7 +778,10 @@ void ProfileWidget2::plotDive(struct dive *d, bool force)
DivePlannerPointsModel *model = DivePlannerPointsModel::instance(); DivePlannerPointsModel *model = DivePlannerPointsModel::instance();
model->deleteTemporaryPlan(); model->deleteTemporaryPlan();
} }
plotPictures(); if (printMode)
clearPictures();
else
plotPictures();
#endif #endif
// OK, how long did this take us? Anything above the second is way too long, // OK, how long did this take us? Anything above the second is way too long,
@ -1103,7 +1106,7 @@ void ProfileWidget2::setProfileState()
disconnectTemporaryConnections(); disconnectTemporaryConnections();
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
connect(DivePictureModel::instance(), SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(plotPictures())); connect(DivePictureModel::instance(), &DivePictureModel::dataChanged, this, &ProfileWidget2::updatePictures);
connect(DivePictureModel::instance(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(plotPictures())); connect(DivePictureModel::instance(), SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(plotPictures()));
connect(DivePictureModel::instance(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SLOT(plotPictures())); connect(DivePictureModel::instance(), SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SLOT(plotPictures()));
#endif #endif
@ -1974,26 +1977,47 @@ void ProfileWidget2::keyEscAction()
plannerModel->cancelPlan(); plannerModel->cancelPlan();
} }
void ProfileWidget2::clearPictures()
{
pictures.clear();
}
void ProfileWidget2::updatePictures(const QModelIndex &from, const QModelIndex &to)
{
DivePictureModel *m = DivePictureModel::instance();
for (int picNr = from.row(); picNr <= to.row(); ++picNr) {
int picItemNr = picNr - m->rowDDStart;
if (picItemNr < 0 || (size_t)picItemNr >= pictures.size())
return;
if (!pictures[picItemNr])
return;
pictures[picItemNr]->setPixmap(m->index(picNr, 0).data(Qt::UserRole).value<QPixmap>());
}
}
void ProfileWidget2::plotPictures() void ProfileWidget2::plotPictures()
{ {
Q_FOREACH (DivePictureItem *item, pictures) { DivePictureModel *m = DivePictureModel::instance();
item->hide(); pictures.resize(m->rowDDEnd - m->rowDDStart);
item->deleteLater();
}
pictures.clear();
if (printMode)
return;
double x, y, lastX = -1.0, lastY = -1.0; double x, y, lastX = -1.0, lastY = -1.0;
DivePictureModel *m = DivePictureModel::instance();
for (int i = m->rowDDStart; i < m->rowDDEnd; i++) { for (int i = m->rowDDStart; i < m->rowDDEnd; i++) {
int picItemNr = i - m->rowDDStart;
int offsetSeconds = m->index(i, 1).data(Qt::UserRole).value<int>(); int offsetSeconds = m->index(i, 1).data(Qt::UserRole).value<int>();
// it's a correct picture, but doesn't have a timestamp: only show on the widget near the // it's a correct picture, but doesn't have a timestamp: only show on the widget near the
// information area. // information area. A null pointer in the pictures array indicates that this picture is not
if (!offsetSeconds) // shown.
if (!offsetSeconds) {
pictures[picItemNr].reset();
continue; continue;
DivePictureItem *item = new DivePictureItem(); }
DivePictureItem *item = pictures[picItemNr].get();
if (!item) {
item = new DivePictureItem;
pictures[picItemNr].reset(item);
scene()->addItem(item);
}
item->setPixmap(m->index(i, 0).data(Qt::UserRole).value<QPixmap>()); item->setPixmap(m->index(i, 0).data(Qt::UserRole).value<QPixmap>());
item->setFileUrl(m->index(i, 1).data().toString()); item->setFileUrl(m->index(i, 1).data().toString());
// let's put the picture at the correct time, but at a fixed "depth" on the profile // let's put the picture at the correct time, but at a fixed "depth" on the profile
@ -2008,8 +2032,6 @@ void ProfileWidget2::plotPictures()
lastX = x; lastX = x;
lastY = y; lastY = y;
item->setPos(x, y); item->setPos(x, y);
scene()->addItem(item);
pictures.push_back(item);
} }
} }
#endif #endif

View file

@ -3,6 +3,8 @@
#define PROFILEWIDGET2_H #define PROFILEWIDGET2_H
#include <QGraphicsView> #include <QGraphicsView>
#include <vector>
#include <memory>
// /* The idea of this widget is to display and edit the profile. // /* The idea of this widget is to display and edit the profile.
// * It has: // * It has:
@ -121,6 +123,7 @@ slots: // Necessary to call from QAction's signals.
void deleteCurrentDC(); void deleteCurrentDC();
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 updatePictures(const QModelIndex &from, const QModelIndex &to);
/* this is called for every move on the handlers. maybe we can speed up this a bit? */ /* this is called for every move on the handlers. maybe we can speed up this a bit? */
void recreatePlannedDive(); void recreatePlannedDive();
@ -164,6 +167,7 @@ private: /*methods*/
void addActionShortcut(const Qt::Key shortcut, void (ProfileWidget2::*slot)()); void addActionShortcut(const Qt::Key shortcut, void (ProfileWidget2::*slot)());
void createPPGas(PartialPressureGasItem *item, int verticalColumn, color_index_t color, color_index_t colorAlert, void createPPGas(PartialPressureGasItem *item, int verticalColumn, color_index_t color, color_index_t colorAlert,
double *thresholdSettingsMin, double *thresholdSettingsMax); double *thresholdSettingsMin, double *thresholdSettingsMax);
void clearPictures();
private: private:
DivePlotDataModel *dataModel; DivePlotDataModel *dataModel;
int zoomLevel; int zoomLevel;
@ -217,7 +221,9 @@ private:
bool printMode; bool printMode;
QList<QGraphicsSimpleTextItem *> gases; QList<QGraphicsSimpleTextItem *> gases;
QList<DivePictureItem *> pictures;
// Use std::vector<> and std::unique_ptr<>, because QVector<QScopedPointer<...>> is unsupported.
std::vector<std::unique_ptr<DivePictureItem>> pictures;
//specifics for ADD and PLAN //specifics for ADD and PLAN
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE