profile: display arbitrary dive

So far the profile operated on the global displayed_dive. Instead,
take the dive to be displayed as a parameter to the plotDive()
functions.

This is necessary if we want to have multiple concurrent
profile objects. Think for example for printing or for mobile
where multiple dive objects are active at the same time.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2021-01-28 14:24:38 +01:00 committed by Dirk Hohndel
parent 36f0ba9abe
commit 2789bb05b1
9 changed files with 121 additions and 131 deletions

View file

@ -229,7 +229,7 @@ void exportProfile(const struct dive *dive, const QString filename)
profile->setPrintMode(true); profile->setPrintMode(true);
double scale = profile->getFontPrintScale(); double scale = profile->getFontPrintScale();
profile->setFontPrintScale(4 * scale); profile->setFontPrintScale(4 * scale);
profile->plotDive(dive, true, false, true); profile->plotDive(dive, 0, true, false, true);
QImage image = QImage(profile->size() * 4, QImage::Format_RGB32); QImage image = QImage(profile->size() * 4, QImage::Format_RGB32);
QPainter paint; QPainter paint;
paint.begin(&image); paint.begin(&image);
@ -238,5 +238,5 @@ void exportProfile(const struct dive *dive, const QString filename)
profile->setToolTipVisibile(true); profile->setToolTipVisibile(true);
profile->setFontPrintScale(scale); profile->setFontPrintScale(scale);
profile->setPrintMode(false); profile->setPrintMode(false);
profile->plotDive(dive, true); profile->plotDive(dive, 0, true); // TODO: Shouldn't this plot the current dive?
} }

View file

@ -541,7 +541,7 @@ void PlannerWidgets::planDive()
{ {
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN); DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN);
MainWindow::instance()->graphics->setPlanState(); MainWindow::instance()->graphics->setPlanState(&displayed_dive, 0);
dc_number = 0; dc_number = 0;
// create a simple starting dive, using the first gas from the just copied cylinders // create a simple starting dive, using the first gas from the just copied cylinders
@ -569,7 +569,7 @@ void PlannerWidgets::replanDive()
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN); DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::PLAN);
DivePlannerPointsModel::instance()->loadFromDive(&displayed_dive); DivePlannerPointsModel::instance()->loadFromDive(&displayed_dive);
MainWindow::instance()->graphics->setPlanState(); MainWindow::instance()->graphics->setPlanState(&displayed_dive, 0);
plannerWidget.setReplanButton(true); plannerWidget.setReplanButton(true);
plannerWidget.setupStartTime(timestampToDateTime(displayed_dive.when)); plannerWidget.setupStartTime(timestampToDateTime(displayed_dive.when));

View file

@ -434,7 +434,7 @@ void MainWindow::selectionChanged()
configureToolbar(); configureToolbar();
enableDisableOtherDCsActions(); enableDisableOtherDCsActions();
} }
graphics->plotDive(current_dive, false); graphics->plotDive(current_dive, dc_number, false);
MapWidget::instance()->selectionChanged(); MapWidget::instance()->selectionChanged();
} }
@ -685,7 +685,7 @@ void MainWindow::enableShortcuts()
void MainWindow::showProfile() void MainWindow::showProfile()
{ {
enableShortcuts(); enableShortcuts();
graphics->setProfileState(); graphics->setProfileState(current_dive, dc_number);
setApplicationState(ApplicationState::Default); setApplicationState(ApplicationState::Default);
} }
@ -738,7 +738,7 @@ void MainWindow::refreshProfile()
{ {
showProfile(); showProfile();
configureToolbar(); configureToolbar();
graphics->plotDive(current_dive, true); graphics->plotDive(current_dive, dc_number, true);
} }
void MainWindow::planCanceled() void MainWindow::planCanceled()
@ -919,7 +919,7 @@ void MainWindow::on_actionPreviousDC_triggered()
unsigned nrdc = number_of_computers(current_dive); unsigned nrdc = number_of_computers(current_dive);
dc_number = (dc_number + nrdc - 1) % nrdc; dc_number = (dc_number + nrdc - 1) % nrdc;
configureToolbar(); configureToolbar();
graphics->plotDive(current_dive, false); graphics->plotDive(current_dive, dc_number, false);
mainTab->updateDiveInfo(); mainTab->updateDiveInfo();
} }
@ -928,7 +928,7 @@ void MainWindow::on_actionNextDC_triggered()
unsigned nrdc = number_of_computers(current_dive); unsigned nrdc = number_of_computers(current_dive);
dc_number = (dc_number + 1) % nrdc; dc_number = (dc_number + 1) % nrdc;
configureToolbar(); configureToolbar();
graphics->plotDive(current_dive, false); graphics->plotDive(current_dive, dc_number, false);
mainTab->updateDiveInfo(); mainTab->updateDiveInfo();
} }
@ -1516,7 +1516,7 @@ void MainWindow::editCurrentDive()
disableShortcuts(); disableShortcuts();
copy_dive(current_dive, &displayed_dive); // Work on a copy of the dive copy_dive(current_dive, &displayed_dive); // Work on a copy of the dive
DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::ADD); DivePlannerPointsModel::instance()->setPlanMode(DivePlannerPointsModel::ADD);
graphics->setAddState(); graphics->setAddState(&displayed_dive, 0);
setApplicationState(ApplicationState::EditDive); setApplicationState(ApplicationState::EditDive);
DivePlannerPointsModel::instance()->loadFromDive(&displayed_dive); DivePlannerPointsModel::instance()->loadFromDive(&displayed_dive);
mainTab->enableEdition(); mainTab->enableEdition();

View file

@ -38,7 +38,7 @@ void Printer::putProfileImage(const QRect &profilePlaceholder, const QRect &view
int y = profilePlaceholder.y() - viewPort.y(); int y = profilePlaceholder.y() - viewPort.y();
// use the placeHolder and the viewPort position to calculate the relative position of the dive profile. // use the placeHolder and the viewPort position to calculate the relative position of the dive profile.
QRect pos(x, y, profilePlaceholder.width(), profilePlaceholder.height()); QRect pos(x, y, profilePlaceholder.width(), profilePlaceholder.height());
profile->plotDive(dive, true, true); profile->plotDive(dive, 0, true, true);
if (!printOptions.color_selected) { if (!printOptions.color_selected) {
QImage image(pos.width(), pos.height(), QImage::Format_ARGB32); QImage image(pos.width(), pos.height(), QImage::Format_ARGB32);
@ -193,7 +193,7 @@ void Printer::render(int pages)
qPrefDisplay::set_animation_speed(animationOriginal); qPrefDisplay::set_animation_speed(animationOriginal);
//replot the dive after returning the settings //replot the dive after returning the settings
profile->plotDive(current_dive, true, true); profile->plotDive(current_dive, dc_number, true, true);
} }
//value: ranges from 0 : 100 and shows the progress of the templating engine //value: ranges from 0 : 100 and shows the progress of the templating engine

View file

@ -541,11 +541,6 @@ void MainTab::rejectChanges()
// no harm done to call cancelPlan even if we were not PLAN mode... // no harm done to call cancelPlan even if we were not PLAN mode...
DivePlannerPointsModel::instance()->cancelPlan(); DivePlannerPointsModel::instance()->cancelPlan();
// now make sure that the correct dive is displayed
if (current_dive)
copy_dive(current_dive, &displayed_dive);
else
clear_dive(&displayed_dive);
updateDiveInfo(); updateDiveInfo();
// show the profile and dive info // show the profile and dive info

View file

@ -360,7 +360,7 @@ void ProfileWidget2::setupItemOnScene()
void ProfileWidget2::replot() void ProfileWidget2::replot()
{ {
plotDive(current_dive, true, false); plotDive(d, dc, true, false);
} }
PartialPressureGasItem *ProfileWidget2::createPPGas(int column, color_index_t color, color_index_t colorAlert, PartialPressureGasItem *ProfileWidget2::createPPGas(int column, color_index_t color, color_index_t colorAlert,
@ -521,29 +521,21 @@ void ProfileWidget2::resetZoom()
} }
// Currently just one dive, but the plan is to enable All of the selected dives. // Currently just one dive, but the plan is to enable All of the selected dives.
void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPictures, bool instant) void ProfileWidget2::plotDive(const struct dive *dIn, int dcIn, bool force, bool doClearPictures, bool instant)
{ {
d = dIn;
dc = dcIn;
if (!d) {
setEmptyState();
return;
}
QElapsedTimer measureDuration; // let's measure how long this takes us (maybe we'll turn of TTL calculation later QElapsedTimer measureDuration; // let's measure how long this takes us (maybe we'll turn of TTL calculation later
measureDuration.start(); measureDuration.start();
#ifdef SUBSURFACE_MOBILE #ifdef SUBSURFACE_MOBILE
Q_UNUSED(doClearPictures); Q_UNUSED(doClearPictures);
#endif #endif
if ((currentState != ADD && currentState != PLAN) || !plannerModel) { if ((currentState != ADD && currentState != PLAN) || !plannerModel) {
if (!d) {
setEmptyState();
return;
}
// No need to do this again if we are already showing the same dive
// computer of the same dive, so we check the unique id of the dive
// and the selected dive computer number against the ones we are
// showing (can't compare the dive pointers as those might change).
if (d->id == displayed_dive.id && dc_number == dataModel->dcShown() && !force)
return;
// this copies the dive and makes copies of all the relevant additional data
copy_dive(d, &displayed_dive);
if (decoMode(false) == VPMB) if (decoMode(false) == VPMB)
decoModelParameters->setText(QString("VPM-B +%1").arg(prefs.vpmb_conservatism)); decoModelParameters->setText(QString("VPM-B +%1").arg(prefs.vpmb_conservatism));
else else
@ -563,7 +555,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
#endif #endif
} }
struct divecomputer *currentdc = select_dc(&displayed_dive); const struct divecomputer *currentdc = get_dive_dc_const(d, dc);
if (!currentdc || !currentdc->samples) if (!currentdc || !currentdc->samples)
return setEmptyState(); return setEmptyState();
@ -581,7 +573,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
if (currentState == EMPTY) if (currentState == EMPTY)
setProfileState(); setProfileState();
bool setpointflag = (currentdc->divemode == CCR) && prefs.pp_graphs.po2 && current_dive; bool setpointflag = (currentdc->divemode == CCR) && prefs.pp_graphs.po2;
bool sensorflag = setpointflag && prefs.show_ccr_sensors; bool sensorflag = setpointflag && prefs.show_ccr_sensors;
o2SetpointGasItem->setVisible(setpointflag && prefs.show_ccr_setpoint); o2SetpointGasItem->setVisible(setpointflag && prefs.show_ccr_setpoint);
ccrsensor1GasItem->setVisible(sensorflag); ccrsensor1GasItem->setVisible(sensorflag);
@ -602,9 +594,9 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
// A non-null planner_ds signals to create_plot_info_new that the dive is currently planned. // A non-null planner_ds signals to create_plot_info_new that the dive is currently planned.
struct deco_state *planner_ds = currentState == PLAN && plannerModel ? &plannerModel->final_deco_state : nullptr; struct deco_state *planner_ds = currentState == PLAN && plannerModel ? &plannerModel->final_deco_state : nullptr;
create_plot_info_new(&displayed_dive, currentdc, &plotInfo, !shouldCalculateMaxDepth, planner_ds); create_plot_info_new(d, get_dive_dc_const(d, dc), &plotInfo, !shouldCalculateMaxDepth, planner_ds);
#else #else
create_plot_info_new(&displayed_dive, currentdc, &plotInfo, !shouldCalculateMaxDepth, nullptr); create_plot_info_new(d, get_dive_dc_const(d, dc), &plotInfo, !shouldCalculateMaxDepth, nullptr);
#endif #endif
int newMaxtime = get_maxtime(&plotInfo); int newMaxtime = get_maxtime(&plotInfo);
if (shouldCalculateMaxTime || newMaxtime > maxtime) if (shouldCalculateMaxTime || newMaxtime > maxtime)
@ -682,7 +674,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
cylinderPressureAxis->setMinimum(plotInfo.minpressure); cylinderPressureAxis->setMinimum(plotInfo.minpressure);
cylinderPressureAxis->setMaximum(plotInfo.maxpressure); cylinderPressureAxis->setMaximum(plotInfo.maxpressure);
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
rulerItem->setPlotInfo(&displayed_dive, plotInfo); rulerItem->setPlotInfo(d, plotInfo);
#endif #endif
#ifdef SUBSURFACE_MOBILE #ifdef SUBSURFACE_MOBILE
@ -722,13 +714,13 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
ocpo2GasItem->setVisible(false); ocpo2GasItem->setVisible(false);
} }
#endif #endif
tankItem->setData(&plotInfo, &displayed_dive); tankItem->setData(&plotInfo, d);
gasYAxis->update(); gasYAxis->update();
// Replot dive items // Replot dive items
for (AbstractProfilePolygonItem *item: profileItems) for (AbstractProfilePolygonItem *item: profileItems)
item->replot(&displayed_dive, currentState == PLAN); item->replot(d, currentState == PLAN);
// The event items are a bit special since we don't know how many events are going to // The event items are a bit special since we don't know how many events are going to
// exist on a dive, so I cant create cache items for that. that's why they are here // exist on a dive, so I cant create cache items for that. that's why they are here
@ -736,7 +728,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
qDeleteAll(eventItems); qDeleteAll(eventItems);
eventItems.clear(); eventItems.clear();
struct event *event = currentdc->events; struct event *event = currentdc->events;
struct gasmix lastgasmix = get_gasmix_at_time(&displayed_dive, current_dc, duration_t{1}); struct gasmix lastgasmix = get_gasmix_at_time(d, get_dive_dc_const(d, dc), duration_t{1});
while (event) { while (event) {
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
@ -759,7 +751,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
item->setHorizontalAxis(timeAxis); item->setHorizontalAxis(timeAxis);
item->setVerticalAxis(profileYAxis, qPrefDisplay::animation_speed()); item->setVerticalAxis(profileYAxis, qPrefDisplay::animation_speed());
item->setModel(dataModel); item->setModel(dataModel);
item->setEvent(&displayed_dive, event, lastgasmix); item->setEvent(d, event, lastgasmix);
item->setZValue(2); item->setZValue(2);
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
item->setScale(printMode ? 4 :1); item->setScale(printMode ? 4 :1);
@ -767,7 +759,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
scene()->addItem(item); scene()->addItem(item);
eventItems.push_back(item); eventItems.push_back(item);
if (event_is_gaschange(event)) if (event_is_gaschange(event))
lastgasmix = get_gasmix_from_event(&displayed_dive, event); lastgasmix = get_gasmix_from_event(d, event);
event = event->next; event = event->next;
} }
@ -784,8 +776,8 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
dcText = tr("Unknown dive computer"); dcText = tr("Unknown dive computer");
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
int nr; int nr;
if ((nr = number_of_computers(&displayed_dive)) > 1) if ((nr = number_of_computers(d)) > 1)
dcText += tr(" (#%1 of %2)").arg(dc_number + 1).arg(nr); dcText += tr(" (#%1 of %2)").arg(dc + 1).arg(nr);
#endif #endif
diveComputerText->setText(dcText); diveComputerText->setText(dcText);
@ -799,7 +791,7 @@ void ProfileWidget2::plotDive(const struct dive *d, bool force, bool doClearPict
else else
plotPicturesInternal(d, instant); plotPicturesInternal(d, instant);
toolTipItem->refresh(&displayed_dive, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN); toolTipItem->refresh(d, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN);
#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,
@ -1025,7 +1017,7 @@ void ProfileWidget2::scrollViewTo(const QPoint &pos)
void ProfileWidget2::mouseMoveEvent(QMouseEvent *event) void ProfileWidget2::mouseMoveEvent(QMouseEvent *event)
{ {
QPointF pos = mapToScene(event->pos()); QPointF pos = mapToScene(event->pos());
toolTipItem->refresh(&displayed_dive, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN); toolTipItem->refresh(d, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN);
if (zoomLevel == 0) { if (zoomLevel == 0) {
QGraphicsView::mouseMoveEvent(event); QGraphicsView::mouseMoveEvent(event);
@ -1123,6 +1115,14 @@ void ProfileWidget2::setEmptyState()
hideAll(gases); hideAll(gases);
} }
void ProfileWidget2::setProfileState(const dive *dIn, int dcIn)
{
d = dIn;
dc = dcIn;
setProfileState();
}
void ProfileWidget2::setProfileState() void ProfileWidget2::setProfileState()
{ {
// Then starting Empty State, move the background up. // Then starting Empty State, move the background up.
@ -1207,13 +1207,14 @@ void ProfileWidget2::setProfileState()
po2GasItem->setVisible(prefs.pp_graphs.po2); po2GasItem->setVisible(prefs.pp_graphs.po2);
pheGasItem->setVisible(prefs.pp_graphs.phe); pheGasItem->setVisible(prefs.pp_graphs.phe);
bool setpointflag = current_dive && (current_dc->divemode == CCR) && prefs.pp_graphs.po2; const struct divecomputer *currentdc = d ? get_dive_dc_const(d, dc) : nullptr;
bool setpointflag = currentdc && currentdc->divemode == CCR && prefs.pp_graphs.po2;
bool sensorflag = setpointflag && prefs.show_ccr_sensors; bool sensorflag = setpointflag && prefs.show_ccr_sensors;
o2SetpointGasItem->setVisible(setpointflag && prefs.show_ccr_setpoint); o2SetpointGasItem->setVisible(setpointflag && prefs.show_ccr_setpoint);
ccrsensor1GasItem->setVisible(sensorflag); ccrsensor1GasItem->setVisible(sensorflag);
ccrsensor2GasItem->setVisible(sensorflag && (current_dc->no_o2sensors > 1)); ccrsensor2GasItem->setVisible(currentdc && sensorflag && currentdc->no_o2sensors > 1);
ccrsensor3GasItem->setVisible(sensorflag && (current_dc->no_o2sensors > 2)); ccrsensor3GasItem->setVisible(currentdc && sensorflag && currentdc->no_o2sensors > 2);
ocpo2GasItem->setVisible(current_dive && (current_dc->divemode == PSCR) && prefs.show_scr_ocpo2); ocpo2GasItem->setVisible(currentdc && currentdc->divemode == PSCR && prefs.show_scr_ocpo2);
heartBeatItem->setVisible(prefs.hrgraph); heartBeatItem->setVisible(prefs.hrgraph);
#endif #endif
@ -1272,12 +1273,12 @@ void ProfileWidget2::connectPlannerModel()
connect(plannerModel, &DivePlannerPointsModel::rowsMoved, this, &ProfileWidget2::pointsMoved); connect(plannerModel, &DivePlannerPointsModel::rowsMoved, this, &ProfileWidget2::pointsMoved);
} }
void ProfileWidget2::setAddState() void ProfileWidget2::setAddState(const dive *d, int dc)
{ {
if (currentState == ADD) if (currentState == ADD)
return; return;
setProfileState(); setProfileState(d, dc);
mouseFollowerHorizontal->setVisible(true); mouseFollowerHorizontal->setVisible(true);
mouseFollowerVertical->setVisible(true); mouseFollowerVertical->setVisible(true);
mouseFollowerHorizontal->setLine(timeAxis->line()); mouseFollowerHorizontal->setLine(timeAxis->line());
@ -1300,12 +1301,12 @@ void ProfileWidget2::setAddState()
setBackgroundBrush(QColor("#A7DCFF")); setBackgroundBrush(QColor("#A7DCFF"));
} }
void ProfileWidget2::setPlanState() void ProfileWidget2::setPlanState(const dive *d, int dc)
{ {
if (currentState == PLAN) if (currentState == PLAN)
return; return;
setProfileState(); setProfileState(d, dc);
mouseFollowerHorizontal->setVisible(true); mouseFollowerHorizontal->setVisible(true);
mouseFollowerVertical->setVisible(true); mouseFollowerVertical->setVisible(true);
mouseFollowerHorizontal->setLine(timeAxis->line()); mouseFollowerHorizontal->setLine(timeAxis->line());
@ -1369,7 +1370,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
} }
QMenu m; QMenu m;
bool isDCName = false; bool isDCName = false;
if (!current_dive) if (!d)
return; return;
// figure out if we are ontop of the dive computer name in the profile // figure out if we are ontop of the dive computer name in the profile
QGraphicsItem *sceneItem = itemAt(mapFromGlobal(event->globalPos())); QGraphicsItem *sceneItem = itemAt(mapFromGlobal(event->globalPos()));
@ -1383,13 +1384,13 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
parentItem = parentItem->parentItem(); parentItem = parentItem->parentItem();
} }
if (isDCName) { if (isDCName) {
if (dc_number == 0 && number_of_computers(current_dive) == 1) if (dc == 0 && number_of_computers(d) == 1)
// nothing to do, can't delete or reorder // nothing to do, can't delete or reorder
return; return;
// create menu to show when right clicking on dive computer name // create menu to show when right clicking on dive computer name
if (dc_number > 0) if (dc > 0)
m.addAction(tr("Make first dive computer"), this, &ProfileWidget2::makeFirstDC); m.addAction(tr("Make first dive computer"), this, &ProfileWidget2::makeFirstDC);
if (number_of_computers(current_dive) > 1) { if (number_of_computers(d) > 1) {
m.addAction(tr("Delete this dive computer"), this, &ProfileWidget2::deleteCurrentDC); m.addAction(tr("Delete this dive computer"), this, &ProfileWidget2::deleteCurrentDC);
m.addAction(tr("Split this dive computer into own dive"), this, &ProfileWidget2::splitCurrentDC); m.addAction(tr("Split this dive computer into own dive"), this, &ProfileWidget2::splitCurrentDC);
} }
@ -1405,19 +1406,19 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
DiveEventItem *item = dynamic_cast<DiveEventItem *>(sceneItem); DiveEventItem *item = dynamic_cast<DiveEventItem *>(sceneItem);
// Add or edit Gas Change // Add or edit Gas Change
if (current_dive && item && event_is_gaschange(item->getEvent())) { if (d && item && event_is_gaschange(item->getEvent())) {
int eventTime = item->getEvent()->time.seconds; int eventTime = item->getEvent()->time.seconds;
QMenu *gasChange = m.addMenu(tr("Edit Gas Change")); QMenu *gasChange = m.addMenu(tr("Edit Gas Change"));
for (int i = 0; i < current_dive->cylinders.nr; i++) { for (int i = 0; i < d->cylinders.nr; i++) {
const cylinder_t *cylinder = get_cylinder(current_dive, i); const cylinder_t *cylinder = get_cylinder(d, i);
QString label = printCylinderDescription(i, cylinder); QString label = printCylinderDescription(i, cylinder);
gasChange->addAction(label, [this, i, eventTime] { changeGas(i, eventTime); }); gasChange->addAction(label, [this, i, eventTime] { changeGas(i, eventTime); });
} }
} else if (current_dive && current_dive->cylinders.nr > 1) { } else if (d && d->cylinders.nr > 1) {
// if we have more than one gas, offer to switch to another one // if we have more than one gas, offer to switch to another one
QMenu *gasChange = m.addMenu(tr("Add gas change")); QMenu *gasChange = m.addMenu(tr("Add gas change"));
for (int i = 0; i < current_dive->cylinders.nr; i++) { for (int i = 0; i < d->cylinders.nr; i++) {
const cylinder_t *cylinder = get_cylinder(current_dive, i); const cylinder_t *cylinder = get_cylinder(d, i);
QString label = printCylinderDescription(i, cylinder); QString label = printCylinderDescription(i, cylinder);
gasChange->addAction(label, [this, i, seconds] { changeGas(i, seconds); }); gasChange->addAction(label, [this, i, seconds] { changeGas(i, seconds); });
} }
@ -1428,7 +1429,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
const struct event *ev = NULL; const struct event *ev = NULL;
enum divemode_t divemode = UNDEF_COMP_TYPE; enum divemode_t divemode = UNDEF_COMP_TYPE;
get_current_divemode(current_dc, seconds, &ev, &divemode); get_current_divemode(get_dive_dc_const(d, dc), seconds, &ev, &divemode);
QMenu *changeMode = m.addMenu(tr("Change divemode")); QMenu *changeMode = m.addMenu(tr("Change divemode"));
if (divemode != OC) if (divemode != OC)
changeMode->addAction(gettextFromC::tr(divemode_text_ui[OC]), changeMode->addAction(gettextFromC::tr(divemode_text_ui[OC]),
@ -1440,7 +1441,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
changeMode->addAction(gettextFromC::tr(divemode_text_ui[PSCR]), changeMode->addAction(gettextFromC::tr(divemode_text_ui[PSCR]),
[this, seconds](){ addDivemodeSwitch(seconds, PSCR); }); [this, seconds](){ addDivemodeSwitch(seconds, PSCR); });
if (same_string(current_dc->model, "manually added dive")) if (same_string(get_dive_dc_const(d, dc)->model, "manually added dive"))
m.addAction(tr("Edit the profile"), this, &ProfileWidget2::editCurrentDive); m.addAction(tr("Edit the profile"), this, &ProfileWidget2::editCurrentDive);
if (DiveEventItem *item = dynamic_cast<DiveEventItem *>(sceneItem)) { if (DiveEventItem *item = dynamic_cast<DiveEventItem *>(sceneItem)) {
@ -1471,7 +1472,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
int newGasIdx = gasChangeIdx + 1; int newGasIdx = gasChangeIdx + 1;
const struct plot_data &newGasEntry = plotInfo.entry[newGasIdx]; const struct plot_data &newGasEntry = plotInfo.entry[newGasIdx];
qDebug() << "after gas change at " << newGasEntry->sec << ": sensor pressure" << newGasEntry->pressure[0] << "interpolated" << newGasEntry->pressure[1]; qDebug() << "after gas change at " << newGasEntry->sec << ": sensor pressure" << newGasEntry->pressure[0] << "interpolated" << newGasEntry->pressure[1];
if (get_plot_sensor_pressure(&plotInfo, gasChangeIdx) == 0 || get_cylinder(&displayed_dive, gasChangeEntry->sensor[0])->sample_start.mbar == 0) { if (get_plot_sensor_pressure(&plotInfo, gasChangeIdx) == 0 || get_cylinder(d, gasChangeEntry->sensor[0])->sample_start.mbar == 0) {
// if we have no sensorpressure or if we have no pressure from samples we can assume that // if we have no sensorpressure or if we have no pressure from samples we can assume that
// we only have interpolated pressure (the pressure in the entry may be stored in the sensor // we only have interpolated pressure (the pressure in the entry may be stored in the sensor
// pressure field if this is the first or last entry for this tank... see details in gaspressures.c // pressure field if this is the first or last entry for this tank... see details in gaspressures.c
@ -1480,7 +1481,7 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
QAction *adjustOldPressure = m.addAction(tr("Adjust pressure of cyl. %1 (currently interpolated as %2)") QAction *adjustOldPressure = m.addAction(tr("Adjust pressure of cyl. %1 (currently interpolated as %2)")
.arg(gasChangeEntry->sensor[0] + 1).arg(get_pressure_string(pressure))); .arg(gasChangeEntry->sensor[0] + 1).arg(get_pressure_string(pressure)));
} }
if (get_plot_sensor_pressure(&plotInfo, newGasIdx) == 0 || get_cylinder(&displayed_dive, newGasEntry->sensor[0])->sample_start.mbar == 0) { if (get_plot_sensor_pressure(&plotInfo, newGasIdx) == 0 || get_cylinder(d, newGasEntry->sensor[0])->sample_start.mbar == 0) {
// we only have interpolated press -- see commend above // we only have interpolated press -- see commend above
pressure_t pressure; pressure_t pressure;
pressure.mbar = get_plot_interpolated_pressure(&plotInfo, newGasIdx) ? : get_plot_sensor_pressure(&plotInfo, newGasIdx); pressure.mbar = get_plot_interpolated_pressure(&plotInfo, newGasIdx) ? : get_plot_sensor_pressure(&plotInfo, newGasIdx);
@ -1505,17 +1506,20 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event)
void ProfileWidget2::deleteCurrentDC() void ProfileWidget2::deleteCurrentDC()
{ {
Command::deleteDiveComputer(current_dive, dc_number); if (d)
Command::deleteDiveComputer(mutable_dive(), dc);
} }
void ProfileWidget2::splitCurrentDC() void ProfileWidget2::splitCurrentDC()
{ {
Command::splitDiveComputer(current_dive, dc_number); if (d)
Command::splitDiveComputer(mutable_dive(), dc);
} }
void ProfileWidget2::makeFirstDC() void ProfileWidget2::makeFirstDC()
{ {
Command::moveDiveComputerToFront(current_dive, dc_number); if (d)
Command::moveDiveComputerToFront(mutable_dive(), dc);
} }
void ProfileWidget2::hideEvents(DiveEventItem *item) void ProfileWidget2::hideEvents(DiveEventItem *item)
@ -1551,68 +1555,54 @@ void ProfileWidget2::unhideEvents()
item->show(); item->show();
} }
// The profile displays a copy of the current_dive, namely displayed_dive.
// Therefore, the events we get are likewise copies. This function finds
// the original event. TODO: Remove function once the profile can display
// arbitrary dives.
static event *find_event(const struct event *ev)
{
struct divecomputer *dc = current_dc;
if (!dc)
return nullptr;
for (struct event *act = current_dc->events; act; act = act->next) {
if (same_event(act, ev))
return act;
}
return nullptr;
}
void ProfileWidget2::removeEvent(DiveEventItem *item) void ProfileWidget2::removeEvent(DiveEventItem *item)
{ {
struct event *event = find_event(item->getEvent()); struct event *event = item->getEvent();
if (!event) if (!event || !d)
return; return;
if (QMessageBox::question(this, TITLE_OR_TEXT( if (QMessageBox::question(this, TITLE_OR_TEXT(
tr("Remove the selected event?"), tr("Remove the selected event?"),
tr("%1 @ %2:%3").arg(event->name).arg(event->time.seconds / 60).arg(event->time.seconds % 60, 2, 10, QChar('0'))), tr("%1 @ %2:%3").arg(event->name).arg(event->time.seconds / 60).arg(event->time.seconds % 60, 2, 10, QChar('0'))),
QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok)
Command::removeEvent(current_dive, dc_number, event); Command::removeEvent(mutable_dive(), dc, event);
} }
void ProfileWidget2::addBookmark(int seconds) void ProfileWidget2::addBookmark(int seconds)
{ {
Command::addEventBookmark(current_dive, dc_number, seconds); if (d)
Command::addEventBookmark(mutable_dive(), dc, seconds);
} }
void ProfileWidget2::addDivemodeSwitch(int seconds, int divemode) void ProfileWidget2::addDivemodeSwitch(int seconds, int divemode)
{ {
Command::addEventDivemodeSwitch(current_dive, dc_number, seconds, divemode); if (d)
Command::addEventDivemodeSwitch(mutable_dive(), dc, seconds, divemode);
} }
void ProfileWidget2::addSetpointChange(int seconds) void ProfileWidget2::addSetpointChange(int seconds)
{ {
SetpointDialog dialog(current_dive, dc_number, seconds); if (!d)
return;
SetpointDialog dialog(mutable_dive(), dc, seconds);
dialog.exec(); dialog.exec();
} }
void ProfileWidget2::splitDive(int seconds) void ProfileWidget2::splitDive(int seconds)
{ {
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
// Make sure that this is an actual dive and we're not in add mode
dive *d = get_dive_by_uniq_id(displayed_dive.id);
if (!d) if (!d)
return; return;
Command::splitDives(d, duration_t{ seconds }); Command::splitDives(mutable_dive(), duration_t{ seconds });
#endif #endif
} }
void ProfileWidget2::changeGas(int tank, int seconds) void ProfileWidget2::changeGas(int tank, int seconds)
{ {
if (!current_dive || tank < 0 || tank >= current_dive->cylinders.nr) if (!d || tank < 0 || tank >= d->cylinders.nr)
return; return;
Command::addGasSwitch(current_dive, dc_number, seconds, tank); Command::addGasSwitch(mutable_dive(), dc, seconds, tank);
} }
#endif #endif
@ -1660,8 +1650,8 @@ double ProfileWidget2::getFontPrintScale() const
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
void ProfileWidget2::editName(DiveEventItem *item) void ProfileWidget2::editName(DiveEventItem *item)
{ {
struct event *event = find_event(item->getEvent()); struct event *event = item->getEvent();
if (!event) if (!event || !d)
return; return;
bool ok; bool ok;
QString newName = QInputDialog::getText(this, tr("Edit name of bookmark"), QString newName = QInputDialog::getText(this, tr("Edit name of bookmark"),
@ -1674,7 +1664,7 @@ void ProfileWidget2::editName(DiveEventItem *item)
lengthWarning.exec(); lengthWarning.exec();
return; return;
} }
Command::renameEvent(current_dive, dc_number, event, qPrintable(newName)); Command::renameEvent(mutable_dive(), dc, event, qPrintable(newName));
} }
} }
#endif #endif
@ -1710,7 +1700,7 @@ int ProfileWidget2::handleIndex(const DiveHandler *h) const
DiveHandler *ProfileWidget2::createHandle() DiveHandler *ProfileWidget2::createHandle()
{ {
DiveHandler *item = new DiveHandler(&displayed_dive); DiveHandler *item = new DiveHandler(d);
scene()->addItem(item); scene()->addItem(item);
connect(item, &DiveHandler::moved, this, &ProfileWidget2::divePlannerHandlerMoved); connect(item, &DiveHandler::moved, this, &ProfileWidget2::divePlannerHandlerMoved);
connect(item, &DiveHandler::clicked, this, &ProfileWidget2::divePlannerHandlerClicked); connect(item, &DiveHandler::clicked, this, &ProfileWidget2::divePlannerHandlerClicked);
@ -1792,8 +1782,8 @@ void ProfileWidget2::repositionDiveHandlers()
QLineF line(p1, p2); QLineF line(p1, p2);
QPointF pos = line.pointAt(0.5); QPointF pos = line.pointAt(0.5);
gases[i]->setPos(pos); gases[i]->setPos(pos);
if (datapoint.cylinderid >= 0 && datapoint.cylinderid < displayed_dive.cylinders.nr) if (datapoint.cylinderid >= 0 && datapoint.cylinderid < d->cylinders.nr)
gases[i]->setText(get_gas_string(get_cylinder(&displayed_dive, datapoint.cylinderid)->gasmix)); gases[i]->setText(get_gas_string(get_cylinder(d, datapoint.cylinderid)->gasmix));
else else
gases[i]->setText(QString()); gases[i]->setText(QString());
gases[i]->setVisible(datapoint.entered && gases[i]->setVisible(datapoint.entered &&
@ -2067,7 +2057,7 @@ void ProfileWidget2::updateThumbnailXPos(PictureEntry &e)
// This function resets the picture thumbnails of the current dive. // This function resets the picture thumbnails of the current dive.
void ProfileWidget2::plotPictures() void ProfileWidget2::plotPictures()
{ {
plotPicturesInternal(current_dive, false); plotPicturesInternal(d, false);
} }
void ProfileWidget2::plotPicturesInternal(const struct dive *d, bool synchronous) void ProfileWidget2::plotPicturesInternal(const struct dive *d, bool synchronous)
@ -2099,8 +2089,6 @@ void ProfileWidget2::plotPicturesInternal(const struct dive *d, bool synchronous
// Remove the pictures with the given filenames from the profile plot. // Remove the pictures with the given filenames from the profile plot.
void ProfileWidget2::picturesRemoved(dive *d, QVector<QString> fileUrls) void ProfileWidget2::picturesRemoved(dive *d, QVector<QString> fileUrls)
{ {
if (d->id != displayed_dive.id)
return;
// To remove the pictures, we use the std::remove_if() algorithm. // To remove the pictures, we use the std::remove_if() algorithm.
// std::remove_if() does not actually delete the elements, but moves // std::remove_if() does not actually delete the elements, but moves
// them to the end of the given range. It returns an iterator to the // them to the end of the given range. It returns an iterator to the
@ -2116,9 +2104,6 @@ void ProfileWidget2::picturesRemoved(dive *d, QVector<QString> fileUrls)
void ProfileWidget2::picturesAdded(dive *d, QVector<PictureObj> pics) void ProfileWidget2::picturesAdded(dive *d, QVector<PictureObj> pics)
{ {
if (d->id != displayed_dive.id)
return;
for (const PictureObj &pic: pics) { for (const PictureObj &pic: pics) {
if (pic.offset.seconds > 0 && pic.offset.seconds <= d->duration.seconds) { if (pic.offset.seconds > 0 && pic.offset.seconds <= d->duration.seconds) {
pictures.emplace_back(pic.offset, QString::fromStdString(pic.filename), this, false); pictures.emplace_back(pic.offset, QString::fromStdString(pic.filename), this, false);
@ -2135,14 +2120,13 @@ void ProfileWidget2::picturesAdded(dive *d, QVector<PictureObj> pics)
void ProfileWidget2::removePicture(const QString &fileUrl) void ProfileWidget2::removePicture(const QString &fileUrl)
{ {
struct dive *d = get_dive_by_uniq_id(displayed_dive.id);
if (d) if (d)
Command::removePictures({ { d, { fileUrl.toStdString() } } }); Command::removePictures({ { mutable_dive(), { fileUrl.toStdString() } } });
} }
void ProfileWidget2::profileChanged(dive *d) void ProfileWidget2::profileChanged(dive *dive)
{ {
if (!d || d->id != displayed_dive.id) if (dive != d)
return; // Cylinders of a differnt dive than the shown one changed. return; // Cylinders of a differnt dive than the shown one changed.
replot(); replot();
} }
@ -2152,7 +2136,7 @@ void ProfileWidget2::profileChanged(dive *d)
void ProfileWidget2::dropEvent(QDropEvent *event) void ProfileWidget2::dropEvent(QDropEvent *event)
{ {
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
if (event->mimeData()->hasFormat("application/x-subsurfaceimagedrop")) { if (event->mimeData()->hasFormat("application/x-subsurfaceimagedrop") && d) {
QByteArray itemData = event->mimeData()->data("application/x-subsurfaceimagedrop"); QByteArray itemData = event->mimeData()->data("application/x-subsurfaceimagedrop");
QDataStream dataStream(&itemData, QIODevice::ReadOnly); QDataStream dataStream(&itemData, QIODevice::ReadOnly);
@ -2160,7 +2144,7 @@ void ProfileWidget2::dropEvent(QDropEvent *event)
dataStream >> filename; dataStream >> filename;
QPointF mappedPos = mapToScene(event->pos()); QPointF mappedPos = mapToScene(event->pos());
offset_t offset { (int32_t)lrint(timeAxis->valueAt(mappedPos)) }; offset_t offset { (int32_t)lrint(timeAxis->valueAt(mappedPos)) };
Command::setPictureOffset(current_dive, filename, offset); Command::setPictureOffset(mutable_dive(), filename, offset);
if (event->source() == this) { if (event->source() == this) {
event->setDropAction(Qt::MoveAction); event->setDropAction(Qt::MoveAction);
@ -2175,13 +2159,13 @@ void ProfileWidget2::dropEvent(QDropEvent *event)
} }
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
void ProfileWidget2::pictureOffsetChanged(dive *d, QString filename, offset_t offset) void ProfileWidget2::pictureOffsetChanged(dive *dIn, QString filename, offset_t offset)
{ {
if (d->id != displayed_dive.id) if (dIn != d)
return; // Picture of a different dive than the one shown changed. return; // Picture of a different dive than the one shown changed.
// Calculate time in dive where picture was dropped and whether the new position is during the dive. // Calculate time in dive where picture was dropped and whether the new position is during the dive.
bool duringDive = current_dive && offset.seconds > 0 && offset.seconds < current_dive->duration.seconds; bool duringDive = d && offset.seconds > 0 && offset.seconds < d->duration.seconds;
// A picture was drag&dropped onto the profile: We have four cases to consider: // A picture was drag&dropped onto the profile: We have four cases to consider:
// 1a) The image was already shown on the profile and is moved to a different position on the profile. // 1a) The image was already shown on the profile and is moved to a different position on the profile.
@ -2266,3 +2250,8 @@ void ProfileWidget2::dragMoveEvent(QDragMoveEvent *event)
event->ignore(); event->ignore();
} }
} }
struct dive *ProfileWidget2::mutable_dive() const
{
return const_cast<dive *>(d);
}

View file

@ -80,7 +80,10 @@ public:
~ProfileWidget2(); ~ProfileWidget2();
void resetZoom(); void resetZoom();
void scale(qreal sx, qreal sy); void scale(qreal sx, qreal sy);
void plotDive(const struct dive *d, bool force = false, bool clearPictures = false, bool instant = false); void plotDive(const struct dive *d, int dc, bool force = false, bool clearPictures = false, bool instant = false);
void setProfileState(const struct dive *d, int dc);
void setPlanState(const struct dive *d, int dc);
void setAddState(const struct dive *d, int dc);
void setPrintMode(bool mode, bool grayscale = false); void setPrintMode(bool mode, bool grayscale = false);
bool getPrintMode() const; bool getPrintMode() const;
bool isPointOutOfBoundaries(const QPointF &point) const; bool isPointOutOfBoundaries(const QPointF &point) const;
@ -107,13 +110,10 @@ slots: // Necessary to call from QAction's signals.
void actionRequestedReplot(bool triggered); void actionRequestedReplot(bool triggered);
void divesChanged(const QVector<dive *> &dives, DiveField field); void divesChanged(const QVector<dive *> &dives, DiveField field);
void setEmptyState(); void setEmptyState();
void setProfileState();
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
void plotPictures(); void plotPictures();
void picturesRemoved(dive *d, QVector<QString> filenames); void picturesRemoved(dive *d, QVector<QString> filenames);
void picturesAdded(dive *d, QVector<PictureObj> pics); void picturesAdded(dive *d, QVector<PictureObj> pics);
void setPlanState();
void setAddState();
void pointsReset(); 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);
@ -139,6 +139,7 @@ slots: // Necessary to call from QAction's signals.
#endif #endif
private: private:
void setProfileState(); // keep currently displayed dive
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
#ifndef SUBSURFACE_MOBILE #ifndef SUBSURFACE_MOBILE
void wheelEvent(QWheelEvent *event) override; void wheelEvent(QWheelEvent *event) override;
@ -194,6 +195,8 @@ private:
// All those here should probably be merged into one structure, // All those here should probably be merged into one structure,
// So it's esyer to replicate for more dives later. // So it's esyer to replicate for more dives later.
// In the meantime, keep it here. // In the meantime, keep it here.
const struct dive *d;
int dc;
struct plot_info plotInfo; struct plot_info plotInfo;
DepthAxis *profileYAxis; DepthAxis *profileYAxis;
PartialGasPressureAxis *gasYAxis; PartialGasPressureAxis *gasYAxis;
@ -272,6 +275,12 @@ private:
int maxtime; int maxtime;
int maxdepth; int maxdepth;
double fontPrintScale; double fontPrintScale;
// We store a const pointer to the shown dive. However, the undo commands want
// (understandably) a non-const pointer. Since the profile has a context-menu
// with actions, it needs such a non-const pointer. This function turns the
// currently shown dive into such a pointer. Ugly, yes.
struct dive *mutable_dive() const;
}; };
#endif // PROFILEWIDGET2_H #endif // PROFILEWIDGET2_H

View file

@ -20,7 +20,7 @@ QMLProfile::QMLProfile(QQuickItem *parent) :
{ {
setAntialiasing(true); setAntialiasing(true);
setFlags(QQuickItem::ItemClipsChildrenToShape | QQuickItem::ItemHasContents ); setFlags(QQuickItem::ItemClipsChildrenToShape | QQuickItem::ItemHasContents );
m_profileWidget->setProfileState(); m_profileWidget->setProfileState(nullptr, 0);
m_profileWidget->setPrintMode(true); m_profileWidget->setPrintMode(true);
m_profileWidget->setFontPrintScale(fontScale); m_profileWidget->setFontPrintScale(fontScale);
connect(QMLManager::instance(), &QMLManager::sendScreenChanged, this, &QMLProfile::screenChanged); connect(QMLManager::instance(), &QMLManager::sendScreenChanged, this, &QMLProfile::screenChanged);
@ -135,7 +135,7 @@ void QMLProfile::updateProfile()
return; return;
if (verbose) if (verbose)
qDebug() << "update profile for dive #" << d->number << "offeset" << QString::number(m_xOffset, 'f', 1) << "/" << QString::number(m_yOffset, 'f', 1); qDebug() << "update profile for dive #" << d->number << "offeset" << QString::number(m_xOffset, 'f', 1) << "/" << QString::number(m_yOffset, 'f', 1);
m_profileWidget->plotDive(d, true); m_profileWidget->plotDive(d, dc_number, true);
} }
void QMLProfile::setDiveId(int diveId) void QMLProfile::setDiveId(int diveId)
@ -189,10 +189,9 @@ void QMLProfile::divesChanged(const QVector<dive *> &dives, DiveField)
for (struct dive *d: dives) { for (struct dive *d: dives) {
if (d->id == m_diveId) { if (d->id == m_diveId) {
qDebug() << "dive #" << d->number << "changed, trigger profile update"; qDebug() << "dive #" << d->number << "changed, trigger profile update";
m_profileWidget->plotDive(d, true); m_profileWidget->plotDive(d, dc_number, true);
triggerUpdate(); triggerUpdate();
return; return;
} }
} }
} }

View file

@ -193,7 +193,6 @@ void DivePictureModel::picturesRemoved(dive *d, QVector<QString> filenamesIn)
endRemoveRows(); endRemoveRows();
toIdx -= j - i; toIdx -= j - i;
} }
copy_dive(current_dive, &displayed_dive); // TODO: Remove once displayed_dive is moved to the planner
} }
// Assumes that pics is sorted! // Assumes that pics is sorted!
@ -306,7 +305,6 @@ void DivePictureModel::pictureOffsetChanged(dive *d, const QString filenameIn, o
// Update the offset here and in the backend // Update the offset here and in the backend
oldPos->offsetSeconds = offset.seconds; oldPos->offsetSeconds = offset.seconds;
copy_dive(current_dive, &displayed_dive); // TODO: remove once profile can display arbitrary dives
// Henceforth we will work with indices instead of iterators // Henceforth we will work with indices instead of iterators
int oldIndex = oldPos - pictures.begin(); int oldIndex = oldPos - pictures.begin();