6#include <QtCore/QCoreApplication>
7#include <QtCore/QStringList>
8#include <QtCore/qnumeric.h>
12 static constexpr QByteArrayView terminator(
"ENDSOURCETABLE");
14 const qsizetype from = (std::max) (qsizetype(0), checkedSize - terminator.size());
15 for (qsizetype offset = body.indexOf(terminator, from); offset >= 0;
16 offset = body.indexOf(terminator, offset + 1)) {
17 const qsizetype end = offset + terminator.size();
18 if ((offset == 0 || body.at(offset - 1) ==
'\n') &&
19 (end == body.size() || body.at(end) ==
'\r' || body.at(end) ==
'\n')) {
30 const QStringList fields = line.split(
';');
31 if (fields.size() < 18 || fields.at(0).trimmed().toUpper() != QStringLiteral(
"STR")) {
37 mp.
format = fields.at(3).trimmed();
39 mp.
country = fields.at(8).trimmed();
40 const auto parseCoord = [](
const QString& s,
double limit) ->
double {
42 const double v = s.trimmed().toDouble(&ok);
43 return (ok && qIsFinite(v) && qAbs(v) <= limit) ? v : qQNaN();
45 mp.
latitude = parseCoord(fields.at(9), 90.0);
46 mp.
longitude = parseCoord(fields.at(10), 180.0);
47 mp.
bitrate = fields.at(17).trimmed().toInt();
54 if (!from.isValid() || !mountCoord.isValid() || (
latitude == 0.0 &&
longitude == 0.0)) {
58 distanceKm = from.distanceTo(mountCoord) / 1000.0;
65 if (!part.isEmpty()) {
71 parts.append(QCoreApplication::translate(
"NTRIPMountpoint",
"%1 bps").arg(
bitrate));
75 parts.append(QCoreApplication::translate(
"NTRIPMountpoint",
"%1 km").arg(
distanceKm, 0,
'f', 1));
78 return parts.join(QCoreApplication::translate(
"NTRIPMountpoint",
" ยท "));
87 : QRangeModel(&std::as_const(_mountpoints), parent)
92 QList<NTRIPMountpoint> mountpoints;
93 const QStringList lines = raw.split(
'\n');
94 for (
const QString& line : lines) {
96 mp->updateDistance(from);
97 mountpoints.append(*mp);
101 _mountpoints = std::move(mountpoints);
108 qsizetype firstChanged = -1;
109 qsizetype lastChanged = -1;
110 for (qsizetype row = 0; row < _mountpoints.size(); ++row) {
112 const double previous = mountpoint.
distanceKm;
115 firstChanged = firstChanged < 0 ? row : firstChanged;
119 if (firstChanged >= 0) {
120 emit dataChanged(index(
static_cast<int>(firstChanged), 0), index(
static_cast<int>(lastChanged), 0),
127 if (_mountpoints.isEmpty()) {
131 _mountpoints.clear();
141 : QSortFilterProxyModel(parent)
143 setSourceModel(source);
152 const double leftKm = left.data(sortRole()).toDouble();
153 const double rightKm = right.data(sortRole()).toDouble();
154 if ((leftKm < 0) != (rightKm < 0)) {
157 if (leftKm >= 0 && leftKm != rightKm) {
158 return leftKm < rightKm;
161 return left.row() < right.row();
bool ntripSourceTableComplete(QByteArrayView body, qsizetype checkedSize)
void updateDistances(const QGeoCoordinate &from)
Recompute distances; one dataChanged for DistanceKmRole spans the rows whose distance changed.
void parseSourceTable(const QString &raw, const QGeoCoordinate &from={})
Publish the parsed rows and their distances in a single reset.
NTRIPSourceTableModel(QObject *parent=nullptr)
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
NTRIPSourceTableSortModel(NTRIPSourceTableModel *source, QObject *parent=nullptr)
void updateDistance(const QGeoCoordinate &from)
Recompute distanceKm, or mark it unknown for invalid reference/mountpoint coordinates.
static std::optional< NTRIPMountpoint > fromSourceTableLine(const QString &line)
Parses one source-table line ("STR;..."); none unless it is a valid STR row.
QString mountpoint
The format, navigation systems, country, bitrate and distance that are known, as one line.