From 613a3112d27e2d40c3a4eeb7fb061f4739279157 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Sat, 19 Oct 2019 22:12:50 -0400 Subject: [PATCH] Mobile: get dive details directly from the model By getting a DiveObjectHelper and then dereferencing that we ended up creating hundres and hundreds of these objects, only to immediately destroy them after using a tiny part of the data. Instead make those data available directly from the model, without having to create a DiveObjectHelper forst. Signed-off-by: Dirk Hohndel --- mobile-widgets/qml/DiveDetails.qml | 61 +++++++++++++------------- mobile-widgets/qml/DiveDetailsView.qml | 58 ++++++++++++------------ qt-models/divelistmodel.cpp | 45 ++++++++++++++++++- qt-models/divelistmodel.h | 30 +++++++++++++ 4 files changed, 134 insertions(+), 60 deletions(-) diff --git a/mobile-widgets/qml/DiveDetails.qml b/mobile-widgets/qml/DiveDetails.qml index d766970ff..4d9f7fc63 100644 --- a/mobile-widgets/qml/DiveDetails.qml +++ b/mobile-widgets/qml/DiveDetails.qml @@ -52,7 +52,7 @@ Kirigami.Page { property alias cylinderModel3: detailsEdit.cylinderModel3 property alias cylinderModel4: detailsEdit.cylinderModel4 - title: currentItem && currentItem.modelData ? currentItem.modelData.dive.location : qsTr("Dive details") + title: currentItem && currentItem.modelData ? currentItem.modelData.location : qsTr("Dive details") state: "view" leftPadding: 0 topPadding: Kirigami.Units.gridUnit / 2 @@ -68,7 +68,7 @@ Kirigami.Page { target: diveDetailsPage; actions { right: deleteAction - left: currentItem ? (currentItem.modelData && currentItem.modelData.dive.gps !== "" ? mapAction : null) : null + left: currentItem ? (currentItem.modelData && currentItem.modelData.gps !== "" ? mapAction : null) : null } } }, @@ -153,7 +153,7 @@ Kirigami.Page { name: ":/icons/trash-empty.svg" } onTriggered: { - var deletedId = currentItem.modelData.dive.id + var deletedId = currentItem.modelData.id var deletedIndex = diveDetailsListView.currentIndex manager.deleteDive(deletedId) pageStack.pop() @@ -181,7 +181,7 @@ Kirigami.Page { } onTriggered: { showMap() - mapPage.centerOnDiveSite(currentItem.modelData.dive.dive_site) + mapPage.centerOnDiveSite(currentItem.modelData.diveSite) } } @@ -218,11 +218,11 @@ Kirigami.Page { // why do we do this? What consumes this? manager.selectedDiveTimestamp = currentItem.modelData.dive.timestamp // make sure the core data structures reflect that this dive is selected - manager.selectDive(currentItem.modelData.dive.id) + manager.selectDive(currentItem.modelData.id) // update the map to show the highlighted flag and center on it if (rootItem.pageIndex(mapPage) !== -1) { mapPage.reloadMap() - mapPage.centerOnDiveSite(currentItem.modelData.dive.dive_site) + mapPage.centerOnDiveSite(currentItem.modelData.diveSite) } } @@ -251,34 +251,35 @@ Kirigami.Page { // set things up for editing - so make sure that the detailsEdit has // all the right data (using the property aliases set up above) var dive = currentItem.modelData.dive - dive_id = dive.id - number = dive.number - date = dive.date + " " + dive.time - location = dive.location - locationIndex = manager.locationList.indexOf(dive.location) - gps = dive.gps + var modelData = currentItem.modelData + dive_id = modelData.id + number = modelData.number + date = modelData.dateTime + location = modelData.location + locationIndex = manager.locationList.indexOf(modelData.location) + gps = modelData.gps gpsCheckbox = false - duration = dive.duration - depth = dive.depth - airtemp = dive.airTemp - watertemp = dive.waterTemp - suitIndex = manager.suitList.indexOf(dive.suit) - if (dive.buddy.indexOf(",") > 0) { - buddyIndex = manager.buddyList.indexOf(dive.buddy.split(",", 1).toString()) + duration = modelData.duration + depth = modelData.depth + airtemp = modelData.airTemp + watertemp = modelData.waterTemp + suitIndex = manager.suitList.indexOf(modelData.suit) + if (modelData.buddy.indexOf(",") > 0) { + buddyIndex = manager.buddyList.indexOf(modelData.buddy.split(",", 1).toString()) } else { - buddyIndex = manager.buddyList.indexOf(dive.buddy) + buddyIndex = manager.buddyList.indexOf(modelData.buddy) } - buddyText = dive.buddy; - if (dive.divemaster.indexOf(",") > 0) { - divemasterIndex = manager.divemasterList.indexOf(dive.divemaster.split(",", 1).toString()) + buddyText = modelData.buddy; + if (modelData.diveMaster.indexOf(",") > 0) { + divemasterIndex = manager.divemasterList.indexOf(modelData.diveMaster.split(",", 1).toString()) } else { - divemasterIndex = manager.divemasterList.indexOf(dive.divemaster) + divemasterIndex = manager.divemasterList.indexOf(modelData.diveMaster) } - divemasterText = dive.divemaster - notes = dive.notes - if (dive.singleWeight) { + divemasterText = modelData.diveMaster + notes = modelData.notes + if (modelData.singleWeight) { // we have only one weight, go ahead, have fun and edit it - weight = dive.sumWeight + weight = modelData.sumWeight } else { // careful when translating, this text is "magic" in DiveDetailsEdit.qml weight = "cannot edit multiple weight systems" @@ -292,8 +293,8 @@ Kirigami.Page { cylinderIndex2 = dive.cylinderList.indexOf(usedCyl[2]) cylinderIndex3 = dive.cylinderList.indexOf(usedCyl[3]) cylinderIndex4 = dive.cylinderList.indexOf(usedCyl[4]) - rating = dive.rating - visibility = dive.visibility + rating = modelData.rating + visibility = modelData.viz diveDetailsPage.state = "edit" } diff --git a/mobile-widgets/qml/DiveDetailsView.qml b/mobile-widgets/qml/DiveDetailsView.qml index 846a817a4..e46d6c45e 100644 --- a/mobile-widgets/qml/DiveDetailsView.qml +++ b/mobile-widgets/qml/DiveDetailsView.qml @@ -36,7 +36,7 @@ Item { anchors.left: parent.left Controls.Label { id: locationText - text: dive.location + text: location font.weight: Font.Bold font.pointSize: subsurfaceTheme.titlePointSize wrapMode: Text.WrapAtWordBoundaryOrAnywhere @@ -49,21 +49,21 @@ Item { } MouseArea { anchors.fill: parent - enabled: dive.gps_decimal !== "" + enabled: gpsDecimal !== "" onClicked: { showMap() - mapPage.centerOnDiveSite(dive.dive_site) + mapPage.centerOnDiveSite(dive_site) } } } SsrfButton { id: gpsButton anchors.right: parent.right - enabled: dive.gps !== "" + enabled: gps !== "" text: qsTr("Map it") onClicked: { showMap() - mapPage.centerOnDiveSite(dive.dive_site) + mapPage.centerOnDiveSite(dive_site) } } Row { @@ -77,14 +77,14 @@ Item { } Controls.Label { - text: dive.date + " " + dive.time + text: dateTime width: Math.max(locationText.width * 0.45, paintedWidth) font.pointSize: subsurfaceTheme.smallPointSize color: subsurfaceTheme.textColor } // let's try to show the depth / duration very compact Controls.Label { - text: dive.depth + ' / ' + dive.duration + text: depthDuration width: Math.max(Kirigami.Units.gridUnit * 3, paintedWidth) font.pointSize: subsurfaceTheme.smallPointSize color: subsurfaceTheme.textColor @@ -92,7 +92,7 @@ Item { } Controls.Label { id: numberText - text: "#" + dive.number + text: "#" + number font.pointSize: subsurfaceTheme.smallPointSize color: subsurfaceTheme.textColor anchors { @@ -117,35 +117,35 @@ Item { width: height height: subsurfaceTheme.regularPointSize anchors.verticalCenter: ratingText.verticalCenter - source: (dive.rating >= 1) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" + source: (rating >= 1) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" color: subsurfaceTheme.textColor } Kirigami.Icon { width: height height: subsurfaceTheme.regularPointSize anchors.verticalCenter: ratingText.verticalCenter - source: (dive.rating >= 2) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" + source: (rating >= 2) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" color: subsurfaceTheme.textColor } Kirigami.Icon { width: height height: subsurfaceTheme.regularPointSize anchors.verticalCenter: ratingText.verticalCenter - source: (dive.rating >= 3) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" + source: (rating >= 3) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" color: subsurfaceTheme.textColor } Kirigami.Icon { width: height height: subsurfaceTheme.regularPointSize anchors.verticalCenter: ratingText.verticalCenter - source: (dive.rating >= 4) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" + source: (rating >= 4) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" color: subsurfaceTheme.textColor } Kirigami.Icon { width: height height: subsurfaceTheme.regularPointSize anchors.verticalCenter: ratingText.verticalCenter - source: (dive.rating === 5) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" + source: (rating === 5) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" color: subsurfaceTheme.textColor } } @@ -165,35 +165,35 @@ Item { width: height height: subsurfaceTheme.regularPointSize anchors.verticalCenter: visibilityText.verticalCenter - source: (dive.visibility >= 1) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" + source: (viz >= 1) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" color: subsurfaceTheme.textColor } Kirigami.Icon { width: height height: subsurfaceTheme.regularPointSize anchors.verticalCenter: visibilityText.verticalCenter - source: (dive.visibility >= 2) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" + source: (viz >= 2) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" color: subsurfaceTheme.textColor } Kirigami.Icon { width: height height: subsurfaceTheme.regularPointSize anchors.verticalCenter: visibilityText.verticalCenter - source: (dive.visibility >= 3) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" + source: (viz >= 3) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" color: subsurfaceTheme.textColor } Kirigami.Icon { width: height height: subsurfaceTheme.regularPointSize anchors.verticalCenter: visibilityText.verticalCenter - source: (dive.visibility >= 4) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" + source: (viz >= 4) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" color: subsurfaceTheme.textColor } Kirigami.Icon { width: height height: subsurfaceTheme.regularPointSize anchors.verticalCenter: visibilityText.verticalCenter - source: (dive.visibility === 5) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" + source: (viz === 5) ? ":/icons/ic_star.svg" : ":/icons/ic_star_border.svg" color: subsurfaceTheme.textColor } } @@ -214,7 +214,7 @@ Item { QMLProfile { id: qmlProfile - visible: !dive.noDive + visible: !noDive Layout.fillWidth: true Layout.preferredHeight: Layout.minimumHeight Layout.minimumHeight: width * 0.75 @@ -230,7 +230,7 @@ Item { } Controls.Label { id: noProfile - visible: dive.noDive + visible: noDive Layout.fillWidth: true Layout.columnSpan: 3 Layout.margins: Kirigami.Units.gridUnit @@ -266,21 +266,21 @@ Item { //------------ Controls.Label { id: txtSuit - text: dive.suit + text: suit wrapMode: TextEdit.WrapAtWordBoundaryOrAnywhere Layout.maximumWidth: detailsView.col1Width color: subsurfaceTheme.textColor } Controls.Label { id: txtAirTemp - text: dive.airTemp + text: airTemp wrapMode: Text.WrapAtWordBoundaryOrAnywhere Layout.maximumWidth: detailsView.col2Width color: subsurfaceTheme.textColor } Controls.Label { id: txtWaterTemp - text: dive.waterTemp + text: waterTemp wrapMode: Text.WrapAtWordBoundaryOrAnywhere Layout.maximumWidth: detailsView.col3Width color: subsurfaceTheme.textColor @@ -325,21 +325,21 @@ Item { //------------ Controls.Label { id: txtCylinder - text: dive.getCylinder.join(', ') + text: cylinder wrapMode: Text.WrapAtWordBoundaryOrAnywhere Layout.maximumWidth: detailsView.col1Width color: subsurfaceTheme.textColor } Controls.Label { id: txtWeight - text: dive.sumWeight + text: sumWeight wrapMode: Text.WrapAtWordBoundaryOrAnywhere Layout.maximumWidth: detailsView.col2Width color: subsurfaceTheme.textColor } Controls.Label { id: txtSAC - text: dive.sac + text: sac wrapMode: Text.WrapAtWordBoundaryOrAnywhere Layout.maximumWidth: detailsView.col3Width color: subsurfaceTheme.textColor @@ -377,14 +377,14 @@ Item { //----------- Controls.Label { id: txtDiveMaster - text: dive.divemaster + text: diveMaster wrapMode: TextEdit.WrapAtWordBoundaryOrAnywhere Layout.maximumWidth: detailsView.col1Width color: subsurfaceTheme.textColor } Controls.Label { id: txtBuddy - text: dive.buddy + text: buddy wrapMode: Text.WrapAtWordBoundaryOrAnywhere Layout.columnSpan: 2 Layout.maximumWidth: detailsView.col2Width + detailsView.col3Width @@ -411,7 +411,7 @@ Item { Controls.Label { id: txtNotes - text: dive.notes + text: notes focus: true Layout.columnSpan: 3 Layout.fillWidth: true diff --git a/qt-models/divelistmodel.cpp b/qt-models/divelistmodel.cpp index d3c4e3ce2..d0a309330 100644 --- a/qt-models/divelistmodel.cpp +++ b/qt-models/divelistmodel.cpp @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "qt-models/divelistmodel.h" +#include "core/divesite.h" #include "core/qthelper.h" #include "core/trip.h" #include "core/settings/qPrefGeneral.h" @@ -97,7 +98,7 @@ static dive_trip *tripIdToObject(const QString &s) return nullptr; int id = s.toInt(); dive_trip **trip = std::find_if(&trip_table.trips[0], &trip_table.trips[trip_table.nr], - [id] (const dive_trip *t) { return t->id == id; }); + [id] (const dive_trip *t) { return t->id == id; }); if (trip == &trip_table.trips[trip_table.nr]) { fprintf(stderr, "Warning: unknown trip id passed through QML: %d\n", id); return nullptr; @@ -256,8 +257,29 @@ QVariant DiveListModel::data(const QModelIndex &index, int role) const case IdRole: return d->id; case NumberRole: return d->number; case LocationRole: return get_dive_location(d); + case DepthRole: return get_depth_string(d->dc.maxdepth.mm, true, true); + case DurationRole: return get_dive_duration_string(d->duration.seconds, gettextFromC::tr("h"), gettextFromC::tr("min")); case DepthDurationRole: return QStringLiteral("%1 / %2").arg(get_depth_string(d->dc.maxdepth.mm, true, true), get_dive_duration_string(d->duration.seconds, gettextFromC::tr("h"), gettextFromC::tr("min"))); + case RatingRole: return d->rating; + case VizRole: return d->visibility; + case SuitRole: return d->suit; + case AirTempRole: return get_temperature_string(d->airtemp, true); + case WaterTempRole: return get_temperature_string(d->watertemp, true); + case SacRole: return formatSac(d); + case SumWeightRole: return get_weight_string(weight_t { total_weight(d) }, true); + case DiveMasterRole: return d->divemaster ? d->divemaster : QString(); + case BuddyRole: return d->buddy ? d->buddy : QString(); + case NotesRole: return formatNotes(d); + case GpsRole: return d->dive_site ? printGPSCoords(&d->dive_site->location) : QString(); + case GpsDecimalRole: return format_gps_decimal(d); + case NoDiveRole: return d->duration.seconds == 0 && d->dc.duration.seconds == 0; + case DiveSiteRole: return QVariant::fromValue(d->dive_site); + case CylinderRole: return formatGetCylinder(d).join(", "); + case SingleWeightRole: return d->weightsystems.nr <= 1; + case StartPressureRole: return getStartPressure(d); + case EndPressureRole: return getEndPressure(d); + case FirstGasRole: return getFirstGas(d); } return QVariant(); } @@ -273,7 +295,28 @@ QHash DiveListModel::roleNames() const roles[IdRole] = "id"; roles[NumberRole] = "number"; roles[LocationRole] = "location"; + roles[DepthRole] = "depth"; + roles[DurationRole] = "duration"; roles[DepthDurationRole] = "depthDuration"; + roles[RatingRole] = "rating"; + roles[VizRole] = "viz"; + roles[SuitRole] = "suit"; + roles[AirTempRole] = "airTemp"; + roles[WaterTempRole] = "waterTemp"; + roles[SacRole] = "sac"; + roles[SumWeightRole] = "sumWeight"; + roles[DiveMasterRole] = "diveMaster"; + roles[BuddyRole] = "buddy"; + roles[NotesRole]= "notes"; + roles[GpsRole] = "gps"; + roles[GpsDecimalRole] = "gpsDecimal"; + roles[NoDiveRole] = "noDive"; + roles[DiveSiteRole] = "diveSite"; + roles[CylinderRole] = "cylinder"; + roles[SingleWeightRole] = "singleWeight"; + roles[StartPressureRole] = "startPressure"; + roles[EndPressureRole] = "endPressure"; + roles[FirstGasRole] = "firstGas"; return roles; } diff --git a/qt-models/divelistmodel.h b/qt-models/divelistmodel.h index 90cc51966..2f8985235 100644 --- a/qt-models/divelistmodel.h +++ b/qt-models/divelistmodel.h @@ -29,6 +29,15 @@ private: void updateFilterState(); }; +QString formatSac(const dive *d); +QString formatNotes(const dive *d); +QString format_gps_decimal(const dive *d); +QStringList formatGetCylinder(const dive *d); +QStringList getStartPressure(const dive *d); +QStringList getEndPressure(const dive *d); +QStringList getFirstGas(const dive *d); + + class DiveListModel : public QAbstractListModel { Q_OBJECT @@ -42,7 +51,28 @@ public: IdRole, NumberRole, LocationRole, + DepthRole, + DurationRole, DepthDurationRole, + RatingRole, + VizRole, + SuitRole, + AirTempRole, + WaterTempRole, + SacRole, + SumWeightRole, + DiveMasterRole, + BuddyRole, + NotesRole, + GpsDecimalRole, + GpsRole, + NoDiveRole, + DiveSiteRole, + CylinderRole, + SingleWeightRole, + StartPressureRole, + EndPressureRole, + FirstGasRole, }; static DiveListModel *instance();