profile use unique_ptr to manage dive handler objects

Instead of manually deleting them (and the gases). Currently
there is only one point where these are deleted, but if
we implement proper Qt model/view semantics, this makes things
less headachy.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2021-01-24 09:13:56 +01:00 committed by Dirk Hohndel
parent 1b14a211f0
commit 396758d489
3 changed files with 31 additions and 26 deletions

View file

@ -22,7 +22,7 @@ DiveHandler::DiveHandler(const struct dive *d) : dive(d)
int DiveHandler::parentIndex() int DiveHandler::parentIndex()
{ {
ProfileWidget2 *view = qobject_cast<ProfileWidget2 *>(scene()->views().first()); ProfileWidget2 *view = qobject_cast<ProfileWidget2 *>(scene()->views().first());
return view->handles.indexOf(this); return view->handleIndex(this);
} }
void DiveHandler::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) void DiveHandler::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)

View file

@ -1062,7 +1062,7 @@ bool ProfileWidget2::eventFilter(QObject *object, QEvent *event)
template <typename T> template <typename T>
static void hideAll(const T &container) static void hideAll(const T &container)
{ {
for (auto *item: container) for (auto &item: container)
item->setVisible(false); item->setVisible(false);
} }
@ -1693,12 +1693,20 @@ void ProfileWidget2::disconnectTemporaryConnections()
} }
} }
int ProfileWidget2::handleIndex(const DiveHandler *h) const
{
auto it = std::find_if(handles.begin(), handles.end(),
[h] (const std::unique_ptr<DiveHandler> &h2)
{ return h == h2.get(); });
return it != handles.end() ? it - handles.begin() : -1;
}
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
void ProfileWidget2::pointInserted(const QModelIndex&, int, int) void ProfileWidget2::pointInserted(const QModelIndex&, int, int)
{ {
DiveHandler *item = new DiveHandler(&displayed_dive); DiveHandler *item = new DiveHandler(&displayed_dive);
scene()->addItem(item); scene()->addItem(item);
handles << 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);
@ -1707,21 +1715,17 @@ void ProfileWidget2::pointInserted(const QModelIndex&, int, int)
scene()->addItem(gasChooseBtn); scene()->addItem(gasChooseBtn);
gasChooseBtn->setZValue(10); gasChooseBtn->setZValue(10);
gasChooseBtn->setFlag(QGraphicsItem::ItemIgnoresTransformations); gasChooseBtn->setFlag(QGraphicsItem::ItemIgnoresTransformations);
gases << gasChooseBtn; gases.emplace_back(gasChooseBtn);
DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance(); DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
if (plannerModel->recalcQ()) if (plannerModel->recalcQ())
replot(); replot();
} }
void ProfileWidget2::pointsRemoved(const QModelIndex &, int start, int end) void ProfileWidget2::pointsRemoved(const QModelIndex &, int start, int end)
{ // start and end are inclusive. {
int num = (end - start) + 1; // Qt's model/view API is mad. The end-point is inclusive, which means that the empty range is [0,-1]!
for (int i = num; i != 0; i--) { handles.erase(handles.begin() + start, handles.begin() + end + 1);
delete handles.back(); gases.erase(gases.begin() + start, gases.begin() + end + 1);
handles.pop_back();
delete gases.back();
gases.pop_back();
}
scene()->clearSelection(); scene()->clearSelection();
replot(); replot();
} }
@ -1735,7 +1739,7 @@ void ProfileWidget2::repositionDiveHandlers()
struct divedatapoint datapoint = plannerModel->at(i); struct divedatapoint datapoint = plannerModel->at(i);
if (datapoint.time == 0) // those are the magic entries for tanks if (datapoint.time == 0) // those are the magic entries for tanks
continue; continue;
DiveHandler *h = handles.at(i); DiveHandler *h = handles[i].get();
h->setVisible(datapoint.entered); h->setVisible(datapoint.entered);
h->setPos(timeAxis->posAtValue(datapoint.time), profileYAxis->posAtValue(datapoint.depth.mm)); h->setPos(timeAxis->posAtValue(datapoint.time), profileYAxis->posAtValue(datapoint.depth.mm));
QPointF p1; QPointF p1;
@ -1763,14 +1767,14 @@ void ProfileWidget2::repositionDiveHandlers()
int ProfileWidget2::fixHandlerIndex(DiveHandler *activeHandler) int ProfileWidget2::fixHandlerIndex(DiveHandler *activeHandler)
{ {
int index = handles.indexOf(activeHandler); int index = handleIndex(activeHandler);
if (index > 0 && index < handles.count() - 1) { if (index > 0 && index < (int)handles.size() - 1) {
DiveHandler *before = handles[index - 1]; DiveHandler *before = handles[index - 1].get();
if (before->pos().x() > activeHandler->pos().x()) { if (before->pos().x() > activeHandler->pos().x()) {
std::swap(handles[index], handles[index - 1]); std::swap(handles[index], handles[index - 1]);
return index - 1; return index - 1;
} }
DiveHandler *after = handles[index + 1]; DiveHandler *after = handles[index + 1].get();
if (after->pos().x() < activeHandler->pos().x()) { if (after->pos().x() < activeHandler->pos().x()) {
std::swap(handles[index], handles[index + 1]); std::swap(handles[index], handles[index + 1]);
return index + 1; return index + 1;
@ -1817,7 +1821,7 @@ void ProfileWidget2::keyDownAction()
Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) { Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) {
if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) {
int row = handles.indexOf(handler); int row = handleIndex(handler);
divedatapoint dp = plannerModel->at(row); divedatapoint dp = plannerModel->at(row);
if (dp.depth.mm >= profileYAxis->maximum()) if (dp.depth.mm >= profileYAxis->maximum())
continue; continue;
@ -1839,7 +1843,7 @@ void ProfileWidget2::keyUpAction()
bool oldRecalc = plannerModel->setRecalc(false); bool oldRecalc = plannerModel->setRecalc(false);
Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) { Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) {
if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) {
int row = handles.indexOf(handler); int row = handleIndex(handler);
divedatapoint dp = plannerModel->at(row); divedatapoint dp = plannerModel->at(row);
if (dp.depth.mm <= 0) if (dp.depth.mm <= 0)
@ -1862,7 +1866,7 @@ void ProfileWidget2::keyLeftAction()
bool oldRecalc = plannerModel->setRecalc(false); bool oldRecalc = plannerModel->setRecalc(false);
Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) { Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) {
if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) {
int row = handles.indexOf(handler); int row = handleIndex(handler);
divedatapoint dp = plannerModel->at(row); divedatapoint dp = plannerModel->at(row);
if (dp.time / 60 <= 0) if (dp.time / 60 <= 0)
@ -1872,7 +1876,7 @@ void ProfileWidget2::keyLeftAction()
// maybe this is a good place for a 'goto'? // maybe this is a good place for a 'goto'?
double xpos = timeAxis->posAtValue((dp.time - 60) / 60); double xpos = timeAxis->posAtValue((dp.time - 60) / 60);
bool nextStep = false; bool nextStep = false;
Q_FOREACH (DiveHandler *h, handles) { for (const auto &h: handles) {
if (IS_FP_SAME(h->pos().x(), xpos)) { if (IS_FP_SAME(h->pos().x(), xpos)) {
nextStep = true; nextStep = true;
break; break;
@ -1898,7 +1902,7 @@ void ProfileWidget2::keyRightAction()
bool oldRecalc = plannerModel->setRecalc(false); bool oldRecalc = plannerModel->setRecalc(false);
Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) { Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) {
if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) {
int row = handles.indexOf(handler); int row = handleIndex(handler);
divedatapoint dp = plannerModel->at(row); divedatapoint dp = plannerModel->at(row);
if (dp.time / 60.0 >= timeAxis->maximum()) if (dp.time / 60.0 >= timeAxis->maximum())
continue; continue;
@ -1907,7 +1911,7 @@ void ProfileWidget2::keyRightAction()
// maybe this is a good place for a 'goto'? // maybe this is a good place for a 'goto'?
double xpos = timeAxis->posAtValue((dp.time + 60) / 60); double xpos = timeAxis->posAtValue((dp.time + 60) / 60);
bool nextStep = false; bool nextStep = false;
Q_FOREACH (DiveHandler *h, handles) { for (const auto &h: handles) {
if (IS_FP_SAME(h->pos().x(), xpos)) { if (IS_FP_SAME(h->pos().x(), xpos)) {
nextStep = true; nextStep = true;
break; break;
@ -1935,7 +1939,7 @@ void ProfileWidget2::keyDeleteAction()
QVector<int> selectedIndices; QVector<int> selectedIndices;
Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) { Q_FOREACH (QGraphicsItem *i, scene()->selectedItems()) {
if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) { if (DiveHandler *handler = qgraphicsitem_cast<DiveHandler *>(i)) {
selectedIndices.push_back(handles.indexOf(handler)); selectedIndices.push_back(handleIndex(handler));
handler->hide(); handler->hide();
} }
} }

View file

@ -227,7 +227,7 @@ private:
#endif #endif
TankItem *tankItem; TankItem *tankItem;
QList<QGraphicsSimpleTextItem *> gases; std::vector<std::unique_ptr<QGraphicsSimpleTextItem>> gases;
//specifics for ADD and PLAN //specifics for ADD and PLAN
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
@ -251,7 +251,8 @@ private:
void updateThumbnailPaintOrder(); void updateThumbnailPaintOrder();
#endif #endif
QList<DiveHandler *> handles; std::vector<std::unique_ptr<DiveHandler>> handles;
int handleIndex(const DiveHandler *h) const;
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
void repositionDiveHandlers(); void repositionDiveHandlers();
int fixHandlerIndex(DiveHandler *activeHandler); int fixHandlerIndex(DiveHandler *activeHandler);