subsurface/qt-models/mobilelistmodel.h
Dirk Hohndel 4db79c8db9 mobile/models: add access to tags string
We already allow filtering by tags, but don't even show them on mobile.
That seems rather inconsistent.
First step is to make the tags available to the QML layer.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-05-14 12:57:08 -07:00

199 lines
6.9 KiB
C++

// SPDX-License-Identifier: GPL-2.0
// This header files declares two linear models used by the mobile UI.
//
// MobileListModel presents a list of trips and optionally the dives of
// one expanded trip. It is used for quick navigation through trips.
//
// MobileSwipeModel gives a linearized view of all dives, sorted by
// trip. Even if there is temporal overlap of trips, all dives of
// a trip are listed in a contiguous block. This model is used for
// swiping through dives.
#ifndef MOBILELISTMODEL_H
#define MOBILELISTMODEL_H
#include "divetripmodel.h"
// This is the base class of the mobile-list model. All it does
// is exporting the various dive fields as roles.
class MobileListModelBase : public QAbstractItemModel {
Q_OBJECT
public:
enum Roles {
IsTopLevelRole = DiveTripModelBase::LAST_ROLE + 1,
DiveDateRole,
TripIdRole,
TripNrDivesRole,
TripShortDateRole,
TripTitleRole,
DateTimeRole,
IdRole,
NumberRole,
LocationRole,
DepthRole,
DurationRole,
DepthDurationRole,
RatingRole,
VizRole,
SuitRole,
AirTempRole,
WaterTempRole,
SacRole,
SumWeightRole,
DiveMasterRole,
BuddyRole,
TagsRole,
NotesRole,
GpsDecimalRole,
GpsRole,
NoDiveRole,
DiveSiteRole,
CylinderRole,
GetCylinderRole,
CylinderListRole,
SingleWeightRole,
StartPressureRole,
EndPressureRole,
FirstGasRole,
SelectedRole,
DiveInTripRole,
TripAbove,
TripBelow,
TripLocationRole,
TripNotesRole,
IsInvalidRole
};
QHash<int, QByteArray> roleNames() const override;
protected:
DiveTripModelBase *source;
MobileListModelBase(DiveTripModelBase *source);
private:
int columnCount(const QModelIndex &parent) const override;
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
QModelIndex parent(const QModelIndex &index) const override;
};
class MobileListModel : public MobileListModelBase {
Q_OBJECT
public:
MobileListModel(DiveTripModelBase *source);
void expand(int row);
void unexpand();
void invalidate();
Q_INVOKABLE void toggle(int row);
Q_PROPERTY(int shown READ shown NOTIFY shownChanged);
signals:
void shownChanged();
private:
struct IndexRange {
bool visible;
int first, last;
};
std::vector<IndexRange> rangeStack;
QModelIndex sourceIndex(int row, int col, int parentRow = -1) const;
int numSubItems() const;
int mapRowFromSourceTopLevel(int row) const;
int mapRowFromSourceTopLevelForInsert(int row) const;
int mapRowFromSourceTrip(const QModelIndex &parent, int parentRow, int row) const;
int mapRowFromSource(const QModelIndex &parent, int row) const;
int invertRow(const QModelIndex &parent, int row) const;
IndexRange mapRangeFromSource(const QModelIndex &parent, int first, int last) const;
IndexRange mapRangeFromSourceForInsert(const QModelIndex &parent, int first, int last) const;
QModelIndex mapFromSource(const QModelIndex &idx) const;
QModelIndex mapToSource(const QModelIndex &idx) const;
static void updateRowAfterRemove(const IndexRange &range, int &row);
static void updateRowAfterMove(const IndexRange &range, const IndexRange &dest, int &row);
QVariant data(const QModelIndex &index, int role) const override;
int rowCount(const QModelIndex &parent) const override;
int shown() const;
int expandedRow;
private slots:
void prepareRemove(const QModelIndex &parent, int first, int last);
void doneRemove(const QModelIndex &parent, int first, int last);
void prepareInsert(const QModelIndex &parent, int first, int last);
void doneInsert(const QModelIndex &parent, int first, int last);
void prepareMove(const QModelIndex &parent, int first, int last, const QModelIndex &dest, int destRow);
void doneMove(const QModelIndex &parent, int first, int last, const QModelIndex &dest, int destRow);
void changed(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
};
class MobileSwipeModel : public MobileListModelBase {
Q_OBJECT
public:
MobileSwipeModel(DiveTripModelBase *source);
static MobileSwipeModel *instance();
void resetModel(DiveTripModelBase::Layout layout); // Switch between tree and list view
void invalidate();
private:
struct IndexRange {
int first, last;
};
std::vector<IndexRange> rangeStack;
std::vector<int> firstElement; // First element of top level item.
int rows;
QVariant data(const QModelIndex &index, int role) const override;
int rowCount(const QModelIndex &parent) const override;
// Since accesses to data come in bursts, we cache map-to-source lookup.
// Note that this is not thread safe. We suppose that the model is only ever accessed from the UI thread.
mutable int cachedRow = -1;
mutable QModelIndex cacheSourceParent;
mutable int cacheSourceRow = -1;
// Translate indices from/to source
int topLevelRowCountInSource(int sourceRow) const;
QModelIndex mapToSource(const QModelIndex &index) const;
int mapTopLevelFromSource(int row) const;
int mapTopLevelFromSourceForInsert(int row) const;
int elementCountInTopLevel(int row) const;
int mapRowFromSource(const QModelIndex &parent, int row) const;
int mapRowFromSource(const QModelIndex &parent) const;
int mapRowFromSourceForInsert(const QModelIndex &parent, int row) const;
IndexRange mapRangeFromSource(const QModelIndex &parent, int first, int last) const;
void invalidateSourceRowCache() const;
void updateSourceRowCache(int row) const;
// Update elements
void initData();
int removeTopLevel(int begin, int end);
void addTopLevel(int row, std::vector<int> items);
void updateTopLevel(int row, int delta);
signals:
void currentDiveChanged(QModelIndex index);
private slots:
void doneReset();
void prepareRemove(const QModelIndex &parent, int first, int last);
void doneRemove(const QModelIndex &parent, int first, int last);
void prepareInsert(const QModelIndex &parent, int first, int last);
void doneInsert(const QModelIndex &parent, int first, int last);
void prepareMove(const QModelIndex &parent, int first, int last, const QModelIndex &dest, int destRow);
void doneMove(const QModelIndex &parent, int first, int last, const QModelIndex &dest, int destRow);
void changed(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles);
};
// This convenience class provides access to the two mobile models.
// Moreover, it provides an interface to the source trip-model.
class MobileModels {
public:
static MobileModels *instance();
MobileListModel *listModel();
MobileSwipeModel *swipeModel();
void invalidate(); // Invalidate all entries to force a re-render.
private:
MobileModels();
DiveTripModelTree source;
MobileListModel lm;
MobileSwipeModel sm;
};
// Helper functions - these are actually defined in DiveObjectHelper.cpp. Why declare them here?
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();
#endif