diff --git a/mobile-widgets/qmlmanager.cpp b/mobile-widgets/qmlmanager.cpp index dc4961cef..f9fdb3a87 100644 --- a/mobile-widgets/qmlmanager.cpp +++ b/mobile-widgets/qmlmanager.cpp @@ -19,7 +19,6 @@ #include -#include "qt-models/divelistmodel.h" #include "qt-models/gpslistmodel.h" #include "qt-models/completionmodels.h" #include "qt-models/messagehandlermodel.h" @@ -28,6 +27,7 @@ #include "core/device.h" #include "core/errorhelper.h" #include "core/file.h" +#include "core/divefilter.h" #include "core/qthelper.h" #include "core/qt-gui.h" #include "core/git-access.h" @@ -44,6 +44,7 @@ #include "core/settings/qPrefTechnicalDetails.h" #include "core/settings/qPrefPartialPressureGas.h" #include "core/settings/qPrefUnit.h" +#include "core/subsurface-qt/diveobjecthelper.h" #include "core/trip.h" #include "backend-shared/exportfuncs.h" #include "core/worldmap-save.h" @@ -1409,8 +1410,6 @@ void QMLManager::selectDive(int id) } if (amount_selected == 0) qWarning("QManager::selectDive() called with unknown id"); - // else - // FIXME: CollapsedDiveListSortModel::instance()->updateSelectionState(); } void QMLManager::deleteDive(int id) diff --git a/mobile-widgets/qmlmanager.h b/mobile-widgets/qmlmanager.h index 3919eec35..0ab1ff981 100644 --- a/mobile-widgets/qmlmanager.h +++ b/mobile-widgets/qmlmanager.h @@ -13,7 +13,6 @@ #include "core/btdiscovery.h" #include "core/gpslocation.h" #include "core/downloadfromdcthread.h" -#include "qt-models/divelistmodel.h" #include "qt-models/completionmodels.h" #include "qt-models/divelocationmodel.h" #include "core/settings/qPrefCloudStorage.h" @@ -143,8 +142,6 @@ public: void setShowNonDiveComputers(bool show); - DiveListSortModel *dlSortModel; - QStringList suitList() const; QStringList buddyList() const; QStringList divemasterList() const; diff --git a/packaging/ios/Subsurface-mobile.pro b/packaging/ios/Subsurface-mobile.pro index b7bd121be..b837b471a 100644 --- a/packaging/ios/Subsurface-mobile.pro +++ b/packaging/ios/Subsurface-mobile.pro @@ -124,7 +124,6 @@ SOURCES += ../../subsurface-mobile-main.cpp \ ../../mobile-widgets/qmlinterface.cpp \ ../../mobile-widgets/qmlmanager.cpp \ ../../mobile-widgets/themeinterface.cpp \ - ../../qt-models/divelistmodel.cpp \ ../../qt-models/divesummarymodel.cpp \ ../../qt-models/diveplotdatamodel.cpp \ ../../qt-models/gpslistmodel.cpp \ @@ -271,7 +270,6 @@ HEADERS += \ ../../mobile-widgets/qmlmanager.h \ ../../mobile-widgets/themeinterface.h \ ../../map-widget/qmlmapwidgethelper.h \ - ../../qt-models/divelistmodel.h \ ../../qt-models/divesummarymodel.h \ ../../qt-models/diveplotdatamodel.h \ ../../qt-models/gpslistmodel.h \ diff --git a/qt-models/CMakeLists.txt b/qt-models/CMakeLists.txt index 45c303888..f3eb89373 100644 --- a/qt-models/CMakeLists.txt +++ b/qt-models/CMakeLists.txt @@ -57,8 +57,6 @@ set(SUBSURFACE_DESKTOP_MODELS_LIB_SRCS # models exclusively used in mobile builds set(SUBSURFACE_MOBILE_MODELS_LIB_SRCS - divelistmodel.cpp - divelistmodel.h divesummarymodel.cpp divesummarymodel.h gpslistmodel.cpp diff --git a/qt-models/divelistmodel.cpp b/qt-models/divelistmodel.cpp deleted file mode 100644 index f3e56cce9..000000000 --- a/qt-models/divelistmodel.cpp +++ /dev/null @@ -1,313 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include "qt-models/divelistmodel.h" -#include "core/divefilter.h" -#include "core/divesite.h" -#include "core/qthelper.h" -#include "core/trip.h" -#include "core/settings/qPrefGeneral.h" -#include "core/errorhelper.h" // for verbose -#include -#include -#include - -// the DiveListSortModel creates the sorted, filtered list of dives that the user -// can flip through horizontally -DiveListSortModel::DiveListSortModel() -{ - setSourceModel(DiveListModel::instance()); -} - -DiveListSortModel *DiveListSortModel::instance() -{ - static DiveListSortModel self; - return &self; -} - -void DiveListSortModel::updateFilterState() -{ - DiveFilter::instance()->updateAll(); - emit shownChanged(); -} - -void DiveListSortModel::setSourceModel(QAbstractItemModel *sourceModel) -{ - QSortFilterProxyModel::setSourceModel(sourceModel); - // make sure we sort descending and have the filters correct - setDynamicSortFilter(true); - setSortRole(DiveListModel::DiveDateRole); - sort(0, Qt::DescendingOrder); - updateFilterState(); -} - -void DiveListSortModel::setFilter(QString f, FilterData::Mode mode) -{ - f = f.trimmed(); - FilterData data; - if (!f.isEmpty()) { - data.mode = mode; - if (mode == FilterData::Mode::FULLTEXT) - data.fullText = f; - else - data.tags = f.split(",", QString::SkipEmptyParts); - } - DiveFilter::instance()->setFilter(data); - invalidateFilter(); -} - -void DiveListSortModel::resetFilter() -{ - int i; - struct dive *d; - for_each_dive(i, d) - d->hidden_by_filter = false; - invalidateFilter(); -} - -// filtering is way too slow on mobile. Maybe we should roll our own? -bool DiveListSortModel::filterAcceptsRow(int source_row, const QModelIndex &) const -{ - DiveListModel *mySourceModel = qobject_cast(sourceModel()); - const dive *d = mySourceModel->getDive(source_row); - return d && !d->hidden_by_filter; -} - -int DiveListSortModel::shown() -{ - return rowCount(); -} - -int DiveListSortModel::getIdxForId(int id) -{ - DiveListModel *mySourceModel = qobject_cast(sourceModel()); - QModelIndex sourceIdx = mySourceModel->getDiveQIdx(id); - if (!sourceIdx.isValid()) - return -1; - QModelIndex localIdx = mapFromSource(sourceIdx); - return localIdx.row(); -} - -void DiveListSortModel::reload() -{ - DiveListModel *mySourceModel = qobject_cast(sourceModel()); - mySourceModel->resetInternalData(); -} - -DiveListModel::DiveListModel() -{ -} - -void DiveListModel::insertDive(int i) -{ - beginInsertRows(QModelIndex(), i, i); - endInsertRows(); -} - -void DiveListModel::removeDive(int i) -{ - beginRemoveRows(QModelIndex(), i, i); - endRemoveRows(); -} - -void DiveListModel::removeDiveById(int id) -{ - for (int i = 0; i < dive_table.nr; i++) { - if (dive_table.dives[i]->id == id) { - removeDive(i); - return; - } - } -} - -void DiveListModel::updateDive(int i, dive *d) -{ - // we need to make sure that QML knows that this dive has changed - - // the only reliable way I've found is to remove and re-insert it - removeDive(i); - insertDive(i); -} - -void DiveListModel::clear() -{ - beginResetModel(); - clear_dive_file_data(); - endResetModel(); -} - -void DiveListModel::reload() -{ - // Note: instead of doing a (logical) beginResetModel()/endResetModel(), - // we add the rows (if any). The reason is that a beginResetModel()/endResetModel() - // pair resulted in the DiveDetailsPage being renedered for *every* dive in - // the list. It is unclear whether this is a Qt-bug or intended insanity. - // Therefore, this function must only be called after having called clear(). - // Otherwise the model will become inconsistent! - if (dive_table.nr > 0) { - beginInsertRows(QModelIndex(), 0, dive_table.nr - 1); - endInsertRows(); - } -} - -void DiveListModel::resetInternalData() -{ - // this is a hack. There is a long standing issue, that seems related to a - // sync problem between QML engine and underlying model data. It causes delete - // from divelist (on mobile) to crash. But not always. This function is part of - // an attempt to fix this. See commit. - beginResetModel(); - endResetModel(); -} - -int DiveListModel::rowCount(const QModelIndex &) const -{ - return dive_table.nr; -} - -// Get the index of a dive in the global dive list by the dive's unique id. Returns an integer [0..nrdives). -int DiveListModel::getDiveIdx(int id) const -{ - return get_idx_by_uniq_id(id); -} - -// Get an index of a dive. In contrast to getDiveIdx, this returns a Qt model-index, -// which can be used to access data of a Qt model. -QModelIndex DiveListModel::getDiveQIdx(int id) -{ - int idx = getDiveIdx(id); - return idx >= 0 ? createIndex(idx, 0) : QModelIndex(); -} - -QVariant DiveListModel::data(const QModelIndex &index, int role) const -{ - if(index.row() < 0 || index.row() >= dive_table.nr) - return QVariant(); - - dive *d = dive_table.dives[index.row()]; - if (!d) - return QVariant(); - switch(role) { - case DiveDateRole: return (qlonglong)d->when; - // We have to return a QString as trip-id, because that will be used as section - // variable in the QtQuick list view. That has to be a string because it will try - // to do locale-aware sorting. And amazingly this can't be changed. - case TripIdRole: return d->divetrip ? QString::number(d->divetrip->id) : QString(); - case TripNrDivesRole: return d->divetrip ? d->divetrip->dives.nr : 0; - case DateTimeRole: { - QDateTime localTime = QDateTime::fromMSecsSinceEpoch(1000 * d->when, Qt::UTC); - localTime.setTimeSpec(Qt::UTC); - return QStringLiteral("%1 %2").arg(localTime.date().toString(prefs.date_format_short), - localTime.time().toString(prefs.time_format)); - } - 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 GetCylinderRole: return formatGetCylinder(d); - case CylinderListRole: return getFullCylinderList(); - case SingleWeightRole: return d->weightsystems.nr <= 1; - case StartPressureRole: return getStartPressure(d); - case EndPressureRole: return getEndPressure(d); - case FirstGasRole: return getFirstGas(d); - case SelectedRole: return d->selected; - } - return QVariant(); -} - -QHash DiveListModel::roleNames() const -{ - QHash roles; - roles[DiveDateRole] = "date"; - roles[TripIdRole] = "tripId"; - roles[TripNrDivesRole] = "tripNrDives"; - roles[DateTimeRole] = "dateTime"; - 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[GetCylinderRole] = "getCylinder"; - roles[CylinderListRole] = "cylinderList"; - roles[SingleWeightRole] = "singleWeight"; - roles[StartPressureRole] = "startPressure"; - roles[EndPressureRole] = "endPressure"; - roles[FirstGasRole] = "firstGas"; - roles[SelectedRole] = "selected"; - return roles; -} - -// create a new dive. set the current time and add it to the end of the dive list -QString DiveListModel::startAddDive() -{ - struct dive *d; - d = alloc_dive(); - d->when = QDateTime::currentMSecsSinceEpoch() / 1000L + gettimezoneoffset(); - - // find the highest dive nr we have and pick the next one - struct dive *pd; - int i, nr = 0; - for_each_dive(i, pd) { - if (pd->number > nr) - nr = pd->number; - } - nr++; - d->number = nr; - d->dc.model = strdup("manually added dive"); - append_dive(d); - insertDive(get_idx_by_uniq_id(d->id)); - return QString::number(d->id); -} - -DiveListModel *DiveListModel::instance() -{ - static DiveListModel self; - return &self; -} - -struct dive *DiveListModel::getDive(int i) -{ - if (i < 0 || i >= dive_table.nr) { - qWarning("DiveListModel::getDive(): accessing invalid dive with id %d", i); - return nullptr; - } - return dive_table.dives[i]; -} - -DiveObjectHelper DiveListModel::at(int i) -{ - // For an invalid id, returns an invalid DiveObjectHelper that will crash on access. - dive *d = getDive(i); - return d ? DiveObjectHelper(d) : DiveObjectHelper(); -} diff --git a/qt-models/divelistmodel.h b/qt-models/divelistmodel.h deleted file mode 100644 index c2722f924..000000000 --- a/qt-models/divelistmodel.h +++ /dev/null @@ -1,104 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#ifndef DIVELISTMODEL_H -#define DIVELISTMODEL_H - -#include -#include - -#include "core/divefilter.h" -#include "core/subsurface-qt/diveobjecthelper.h" - -class DiveListSortModel : public QSortFilterProxyModel -{ - Q_OBJECT -public: - static DiveListSortModel *instance(); - void setSourceModel(QAbstractItemModel *sourceModel); - Q_INVOKABLE void reload(); - QString filterString; - void updateFilterState(); - Q_PROPERTY(int shown READ shown NOTIFY shownChanged); - int shown(); -public slots: - int getIdxForId(int id); - void setFilter(QString f, FilterData::Mode mode); - void resetFilter(); -signals: - void shownChanged(); -protected: - bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; -private: - DiveListSortModel(); -}; - -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); -QStringList getFullCylinderList(); - -class DiveListModel : public QAbstractListModel -{ - Q_OBJECT -public: - enum DiveListRoles { - DiveDateRole = Qt::UserRole + 1, - TripIdRole, - TripNrDivesRole, - DateTimeRole, - IdRole, - NumberRole, - LocationRole, - DepthRole, - DurationRole, - DepthDurationRole, - RatingRole, - VizRole, - SuitRole, - AirTempRole, - WaterTempRole, - SacRole, - SumWeightRole, - DiveMasterRole, - BuddyRole, - NotesRole, - GpsDecimalRole, - GpsRole, - NoDiveRole, - DiveSiteRole, - CylinderRole, - GetCylinderRole, - CylinderListRole, - SingleWeightRole, - StartPressureRole, - EndPressureRole, - FirstGasRole, - SelectedRole, - }; - - static DiveListModel *instance(); - void addDive(const QList &listOfDives); - void addAllDives(); - void insertDive(int i); - void removeDive(int i); - void removeDiveById(int id); - void updateDive(int i, dive *d); - void reload(); // Only call after clearing the model! - struct dive *getDive(int i); - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int getDiveIdx(int id) const; - QModelIndex getDiveQIdx(int id); - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - QHash roleNames() const; - QString startAddDive(); - void resetInternalData(); - void clear(); // Clear all dives in core - Q_INVOKABLE DiveObjectHelper at(int i); -private: - DiveListModel(); -}; - -#endif // DIVELISTMODEL_H diff --git a/subsurface-helper.cpp b/subsurface-helper.cpp index d76e4b52c..013cfb125 100644 --- a/subsurface-helper.cpp +++ b/subsurface-helper.cpp @@ -16,7 +16,6 @@ #include "mobile-widgets/themeinterface.h" #include "mobile-widgets/qmlmanager.h" #include "mobile-widgets/qmlinterface.h" -#include "qt-models/divelistmodel.h" #include "qt-models/divesummarymodel.h" #include "qt-models/gpslistmodel.h" #include "qt-models/messagehandlermodel.h"