summaryrefslogtreecommitdiffstats
path: root/examples/positioning/satelliteinfo/satellitemodel.cpp
blob: e37b48b23fd1f14aa34aa824cc03608520c95fa9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

#include "roles.h"
#include "satellitemodel.h"

using namespace Qt::StringLiterals;

static QString systemString(QGeoSatelliteInfo::SatelliteSystem system)
{
    switch (system) {
    case QGeoSatelliteInfo::Undefined:
        return u"Undefined"_s;
    case QGeoSatelliteInfo::GPS:
        return u"GPS"_s;
    case QGeoSatelliteInfo::GLONASS:
        return u"GLONASS"_s;
    case QGeoSatelliteInfo::GALILEO:
        return u"GALILEO"_s;
    case QGeoSatelliteInfo::BEIDOU:
        return u"BEIDOU"_s;
    case QGeoSatelliteInfo::QZSS:
        return u"QZSS"_s;
    case QGeoSatelliteInfo::Multiple:
        return u"Multiple"_s;
    case QGeoSatelliteInfo::CustomType:
        return u"CustomType"_s;
    }
    return u"Undefined"_s;
}

SatelliteModel::SatelliteModel(QObject *parent)
    : QAbstractListModel{parent}
{
}

int SatelliteModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return static_cast<int>(m_satellites.size());
}

QVariant SatelliteModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || index.row() >= rowCount())
        return QVariant();

    const QGeoSatelliteInfo &info = m_satellites.at(index.row());
    switch (role) {
    case Roles::IdRole:
        return info.satelliteIdentifier();
    case Roles::RssiRole:
        return info.signalStrength();
    case Roles::AzimuthRole:
        return info.attribute(QGeoSatelliteInfo::Azimuth);
    case Roles::ElevationRole:
        return info.attribute(QGeoSatelliteInfo::Elevation);
    case Roles::SystemRole:
        return systemString(info.satelliteSystem());
    case Roles::SystemIdRole:
        return info.satelliteSystem();
    case Roles::InUseRole:
        return m_inUseIds.contains(getUid(info));
    case Roles::VisibleNameRole:
        return u"%1-%2"_s.arg(systemString(info.satelliteSystem()),
                              QString::number(info.satelliteIdentifier()));
    }

    return QVariant();
}

//! [0]
QHash<int, QByteArray> SatelliteModel::roleNames() const
{
    return {
        {Roles::IdRole, "id"},
        {Roles::RssiRole, "rssi"},
        {Roles::AzimuthRole, "azimuth"},
        {Roles::ElevationRole, "elevation"},
        {Roles::SystemRole, "system"},
        {Roles::SystemIdRole, "systemId"},
        {Roles::InUseRole, "inUse"},
        {Roles::VisibleNameRole, "name"}
    };
}
//! [0]

void SatelliteModel::updateSatellitesInView(const QList<QGeoSatelliteInfo> &inView)
{
    const bool emitSizeChanged = inView.size() != m_satellites.size();

    QSet<UniqueId> idsInUpdate;
    for (const QGeoSatelliteInfo &info : inView)
        idsInUpdate.insert(getUid(info));

    // 1. Get the ids of all satellites to be removed.
    const auto toBeRemoved = m_allIds - idsInUpdate;
    // 2. Remove them and call {begin,end}RemoveRows() for each of them
    qsizetype idx = 0;
    while (idx < m_satellites.size()) {
        const auto &sat = m_satellites.at(idx);
        if (toBeRemoved.contains(getUid(sat))) {
            beginRemoveRows(QModelIndex(), idx, idx);
            m_satellites.removeAt(idx);
            endRemoveRows();
        } else {
            ++idx;
        }
    }
    // 3. Get ids of all new elements.
    const auto toBeAdded = idsInUpdate - m_allIds;
    // 4. Sort the input items, so that we always have the same order of
    //    elements during comparison
    auto inViewCopy = inView;
    std::sort(inViewCopy.begin(), inViewCopy.end(),
              [](const auto &lhs, const auto &rhs) {
                  if (lhs.satelliteIdentifier() == rhs.satelliteIdentifier())
                      return lhs.satelliteSystem() < rhs.satelliteSystem();
                  return lhs.satelliteIdentifier() < rhs.satelliteIdentifier();
              });
    // 5. Iterate through the list:
    //    * if the id of the satellite is new, use {begin,end}InsertRows()
    //    * otherwise use dataChanged()
    for (idx = 0; idx < inViewCopy.size(); ++idx) {
        const auto &sat = inViewCopy.at(idx);
        if (toBeAdded.contains(getUid(sat))) {
            beginInsertRows(QModelIndex(), idx, idx);
            m_satellites.insert(idx, inViewCopy.at(idx));
            endInsertRows();
        } else {
            m_satellites[idx] = inViewCopy.at(idx);
            emit dataChanged(index(idx), index(idx),
                             {Roles::RssiRole, Roles::AzimuthRole, Roles::ElevationRole});
        }
    }
    m_allIds = idsInUpdate;
    if (emitSizeChanged)
        emit sizeChanged();
}

void SatelliteModel::updateSatellitesInUse(const QList<QGeoSatelliteInfo> &inUse)
{
    m_inUseIds.clear();
    for (const QGeoSatelliteInfo &info : inUse)
        m_inUseIds.insert(getUid(info));
    emit dataChanged(index(0), index(m_satellites.size() - 1), {Roles::InUseRole});
}

SatelliteModel::UniqueId SatelliteModel::getUid(const QGeoSatelliteInfo &info)
{
    return std::make_pair(static_cast<int>(info.satelliteSystem()), info.satelliteIdentifier());
}