MailJDTourDownloadDocsQualityTestsCoverage

Which source lines and branches the tests execute. Lines 91.5 %, branches 75.0 % (minimum 85 % and 72 %). main @ 399ffe3d · 21 October 2026 · pipeline 7238.

GCC Code Coverage Report


Directory: src/
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 97.3% 363 / 0 / 373
Functions: 100.0% 35 / 0 / 35
Branches: 82.1% 492 / 0 / 599

presentation/QuickContactMap.cpp
Line Branch Exec Source
1 #include "QuickContactMap.h"
2
3 #include "data/ContactIndex.h"
4 #include "data/ContactPlaceIndexer.h"
5 #include "data/ContactQueries.h"
6 #include "data/ContactStore.h"
7 #include "data/GeoData.h"
8 #include "data/PlaceGazetteer.h"
9 #include "presentation/MapMarkerModel.h"
10 #include "presentation/MapTileSource.h"
11
12 #include <QElapsedTimer>
13 #include <QHash>
14 #include <QLocale>
15 #include <QMap>
16 #include <QLoggingCategory>
17 #include <QPointer>
18 #include <QRegularExpression>
19 #include <QSet>
20 #include <QSettings>
21 #include <QSqlQuery>
22 #include <QStandardPaths>
23 #include <QTimer>
24 #include <QUrl>
25 #include <algorithm>
26 #include <cmath>
27
28 Q_DECLARE_LOGGING_CATEGORY(lcMapTiles)
29
30 812 QuickContactMap::QuickContactMap(QString databasePath, QObject *parent)
31 812 : QObject(parent), m_databasePath(std::move(databasePath)),
32
1/3
✓ Branch 42 → 43 taken 812 times.
✗ Branch 196 → 197 not taken.
✗ Branch 196 → 199 not taken.
1624 m_tileSource(new MapTileSource(QDir(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) +
33
3/4
✓ Branch 43 → 44 taken 812 times.
✓ Branch 44 → 45 taken 812 times.
✗ Branch 51 → 52 not taken.
✓ Branch 51 → 54 taken 812 times.
2436 QStringLiteral("/maptiles")),
34
6/12
✓ Branch 5 → 6 taken 812 times.
✓ Branch 27 → 28 taken 812 times.
✓ Branch 29 → 30 taken 4060 times.
✓ Branch 29 → 31 taken 812 times.
✓ Branch 38 → 39 taken 812 times.
✓ Branch 45 → 46 taken 812 times.
✗ Branch 157 → 158 not taken.
✗ Branch 157 → 159 not taken.
✗ Branch 175 → 176 not taken.
✗ Branch 175 → 179 not taken.
✗ Branch 177 → 178 not taken.
✗ Branch 177 → 179 not taken.
11368 this)) {
35
1/1
✓ Branch 63 → 64 taken 812 times.
812 m_pool.setMaxThreadCount(1);
36 812 m_viewport.zoom = 1.5;
37
4/7
✓ Branch 64 → 65 taken 812 times.
✓ Branch 65 → 66 taken 812 times.
✓ Branch 66 → 67 taken 812 times.
✗ Branch 68 → 69 not taken.
✓ Branch 68 → 70 taken 812 times.
✗ Branch 203 → 204 not taken.
✗ Branch 203 → 205 not taken.
812 m_markerModel = new MapMarkerModel("cluster", this);
38
4/7
✓ Branch 70 → 71 taken 812 times.
✓ Branch 71 → 72 taken 812 times.
✓ Branch 72 → 73 taken 812 times.
✗ Branch 74 → 75 not taken.
✓ Branch 74 → 76 taken 812 times.
✗ Branch 209 → 210 not taken.
✗ Branch 209 → 211 not taken.
812 m_tileModel = new MapMarkerModel("tile", this);
39
4/7
✓ Branch 76 → 77 taken 812 times.
✓ Branch 77 → 78 taken 812 times.
✓ Branch 78 → 79 taken 812 times.
✗ Branch 80 → 81 not taken.
✓ Branch 80 → 82 taken 812 times.
✗ Branch 215 → 216 not taken.
✗ Branch 215 → 217 not taken.
812 m_onlineTileModel = new MapMarkerModel("tile", this);
40
3/6
✓ Branch 82 → 83 taken 812 times.
✓ Branch 83 → 84 taken 812 times.
✗ Branch 84 → 85 not taken.
✓ Branch 84 → 86 taken 812 times.
✗ Branch 218 → 219 not taken.
✗ Branch 218 → 220 not taken.
812 m_wantTimer = new QTimer(this);
41
1/1
✓ Branch 86 → 87 taken 812 times.
812 m_wantTimer->setSingleShot(true);
42
1/1
✓ Branch 87 → 88 taken 812 times.
812 m_wantTimer->setInterval(WantDelayMs);
43
1/1
✓ Branch 88 → 89 taken 812 times.
812 connect(m_wantTimer, &QTimer::timeout, this, &QuickContactMap::requestTiles);
44
1/1
✓ Branch 90 → 91 taken 812 times.
812 const QSettings settings;
45 // F103-24: a server set before the styles existed is the custom style.
46
2/2
✓ Branch 95 → 96 taken 812 times.
✓ Branch 96 → 97 taken 812 times.
812 const QString custom = settings.value(QStringLiteral("contacts/mapTileServer")).toString();
47
3/5
✓ Branch 101 → 102 taken 810 times.
✓ Branch 101 → 105 taken 2 times.
✓ Branch 113 → 114 taken 812 times.
✗ Branch 250 → 251 not taken.
✗ Branch 250 → 252 not taken.
4058 m_tileStyle = settings.value(QStringLiteral("contacts/mapTileStyle"), custom.isEmpty() ? QStringLiteral("osm")
48
4/6
✓ Branch 122 → 123 taken 2 times.
✓ Branch 122 → 124 taken 810 times.
✓ Branch 124 → 125 taken 810 times.
✓ Branch 124 → 126 taken 2 times.
✗ Branch 246 → 247 not taken.
✗ Branch 246 → 248 not taken.
812 : QStringLiteral("custom"))
49
1/1
✓ Branch 114 → 115 taken 812 times.
812 .toString();
50
1/1
✓ Branch 126 → 127 taken 812 times.
812 applyTileStyle();
51
2/2
✓ Branch 132 → 133 taken 812 times.
✓ Branch 133 → 134 taken 812 times.
1624 m_onlineTiles = settings.value(QStringLiteral("contacts/mapTiles"), false).toBool();
52
5/6
✓ Branch 138 → 139 taken 1 time.
✓ Branch 138 → 142 taken 811 times.
✓ Branch 139 → 140 taken 1 time.
✓ Branch 140 → 141 taken 1 time.
✗ Branch 140 → 142 not taken.
✓ Branch 143 → 144 taken 812 times.
812 m_tileSource->setEnabled(m_onlineTiles && !tileKeyMissing());
53
3/3
✓ Branch 144 → 145 taken 1 time.
✓ Branch 144 → 147 taken 811 times.
✓ Branch 145 → 146 taken 1 time.
812 m_viewport.maxZoom = m_onlineTiles ? onlineMaxZoom() : MapProjection::MaxZoom;
54 // Arriving tiles are shown in one pass per event loop turn (two requests run at a time).
55
1/1
✓ Branch 148 → 149 taken 812 times.
812 connect(m_tileSource, &MapTileSource::tileReady, this, [this] {
56
2/2
✓ Branch 2 → 3 taken 31 times.
✓ Branch 2 → 4 taken 33 times.
64 if (m_tileRefreshQueued)
57 31 return;
58 33 m_tileRefreshQueued = true;
59
1/1
✓ Branch 4 → 5 taken 33 times.
33 QTimer::singleShot(0, this, [this] {
60 32 m_tileRefreshQueued = false;
61 32 updateOnlineTiles();
62 32 emit viewportChanged();
63 32 });
64 });
65
1/1
✓ Branch 150 → 151 taken 812 times.
812 connect(m_tileSource, &MapTileSource::unavailableChanged, this, [this](bool unavailable) {
66 1 m_tilesUnavailable = unavailable;
67 1 emit tilesUnavailableChanged();
68 1 });
69
1/1
✓ Branch 152 → 153 taken 812 times.
812 initLookup();
70 812 }
71
72 812 QuickContactMap::~QuickContactMap() { m_pool.waitForDone(); }
73
74 22 QObject *QuickContactMap::markerModel() const { return m_markerModel; }
75
76 // The first fit waits for the worker: fitted to the few places known
77 // before it (pinned ones), the map would stay zoomed in on them.
78 49 void QuickContactMap::activate() {
79 49 m_active = true;
80 49 placeOnWorker();
81 49 readPlaces();
82 49 }
83
84 42 void QuickContactMap::deactivate() {
85
2/2
✓ Branch 2 → 3 taken 19 times.
✓ Branch 2 → 4 taken 23 times.
42 if (!m_active)
86 19 return;
87 23 m_active = false;
88 23 stopBackgroundLookups();
89
5/5
✓ Branch 5 → 6 taken 23 times.
✓ Branch 9 → 10 taken 23 times.
✓ Branch 10 → 11 taken 23 times.
✓ Branch 14 → 7 taken 23 times.
✓ Branch 14 → 15 taken 23 times.
46 qCInfo(lcMapTiles) << "Map inactive: background address lookups stopped";
90 }
91
92 45 void QuickContactMap::reload() {
93
2/2
✓ Branch 2 → 3 taken 41 times.
✓ Branch 2 → 4 taken 4 times.
45 if (!m_active)
94 41 return;
95 4 placeOnWorker();
96 4 readPlaces();
97 }
98
99 // Pending rows are placed in slices of 200 on the worker; the GUI reads the
100 // places again when a slice placed something and once at the end.
101 53 void QuickContactMap::placeOnWorker() {
102
10/13
✓ Branch 2 → 3 taken 42 times.
✓ Branch 2 → 8 taken 11 times.
✓ Branch 4 → 5 taken 42 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 42 times.
✓ Branch 7 → 8 taken 20 times.
✓ Branch 7 → 9 taken 22 times.
✓ Branch 10 → 11 taken 42 times.
✓ Branch 10 → 12 taken 11 times.
✓ Branch 12 → 13 taken 31 times.
✓ Branch 12 → 14 taken 22 times.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 33 not taken.
53 if (m_placing || m_databasePath.isEmpty() || !GeoData::builtIn())
103 31 return;
104 22 m_placing = true;
105
1/1
✓ Branch 14 → 15 taken 22 times.
22 emit placingChanged();
106 22 const QString path = m_databasePath;
107
3/3
✓ Branch 16 → 17 taken 22 times.
✓ Branch 17 → 18 taken 22 times.
✓ Branch 18 → 19 taken 22 times.
22 const QString country = QLocale::territoryToCode(QLocale::system().territory());
108
1/1
✓ Branch 20 → 21 taken 22 times.
22 QPointer<QuickContactMap> self(this);
109
1/5
✓ Branch 24 → 25 taken 22 times.
✗ Branch 40 → 41 not taken.
✗ Branch 40 → 42 not taken.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 45 not taken.
22 m_pool.start([self, path, country] {
110 22 QElapsedTimer timer;
111 22 timer.start();
112 22 int placed = 0;
113
1/1
✓ Branch 3 → 4 taken 22 times.
22 ContactStore store;
114
2/3
✓ Branch 4 → 5 taken 22 times.
✓ Branch 5 → 6 taken 22 times.
✗ Branch 5 → 19 not taken.
22 if (store.open(path)) {
115
1/1
✓ Branch 6 → 7 taken 22 times.
22 QSqlDatabase db = store.database();
116
1/2
✓ Branch 16 → 8 taken 22 times.
✗ Branch 16 → 17 not taken.
22 for (int slice = 0; slice < 500; ++slice) {
117
2/2
✓ Branch 8 → 9 taken 22 times.
✓ Branch 10 → 11 taken 22 times.
22 const ContactPlaceIndexer::Result result = ContactPlaceIndexer::run(db, *GeoData::builtIn(), country, 200);
118 22 placed += result.placed;
119
1/4
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 15 taken 22 times.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 15 not taken.
22 if (result.remaining == 0 || result.processed == 0)
120 break;
121 }
122 22 }
123
9/9
✓ Branch 19 → 20 taken 22 times.
✓ Branch 23 → 24 taken 22 times.
✓ Branch 24 → 25 taken 22 times.
✓ Branch 25 → 26 taken 22 times.
✓ Branch 26 → 27 taken 22 times.
✓ Branch 28 → 29 taken 22 times.
✓ Branch 29 → 30 taken 22 times.
✓ Branch 33 → 21 taken 22 times.
✓ Branch 33 → 34 taken 22 times.
44 qCInfo(lcMapTiles) << "Places placed on the worker:" << placed << "in" << timer.elapsed() << "ms";
124
1/1
✓ Branch 36 → 37 taken 22 times.
22 QMetaObject::invokeMethod(
125 22 self.data(),
126
0/2
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 56 not taken.
44 [self, placed] {
127
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 19 times.
19 if (!self)
128 ✗ return;
129 19 self->m_placing = false;
130 19 emit self->placingChanged();
131
6/6
✓ Branch 8 → 9 taken 8 times.
✓ Branch 8 → 11 taken 11 times.
✓ Branch 10 → 11 taken 5 times.
✓ Branch 10 → 12 taken 3 times.
✓ Branch 13 → 14 taken 16 times.
✓ Branch 13 → 16 taken 3 times.
19 if (placed > 0 || !self->m_fitted)
132 16 self->readPlaces();
133 19 self->queueLookups(); // S103.1.9: only with the setting on
134 },
135 Qt::QueuedConnection);
136 22 });
137 22 }
138
139 73 void QuickContactMap::readPlaces() {
140 73 QElapsedTimer timer;
141 73 timer.start();
142
1/1
✓ Branch 3 → 4 taken 73 times.
73 m_places.clear();
143 // S106-278: the clusters index into m_places, so they go with it; the
144 // next updateMarkers re-forms them even when the new set has the same size.
145
1/1
✓ Branch 4 → 5 taken 73 times.
73 m_clusterInput.clear();
146
1/1
✓ Branch 5 → 6 taken 73 times.
73 m_clusters.clear();
147 73 m_clusterKeys.clear();
148 73 m_clusterZoom = -1;
149 73 QHash<QString, int> personOf;
150 73 QSet<QString> placed;
151 73 QSet<QString> withPlaceText;
152
1/1
✓ Branch 9 → 10 taken 73 times.
73 ContactStore store;
153
4/7
✓ Branch 11 → 12 taken 73 times.
✗ Branch 11 → 15 not taken.
✓ Branch 12 → 13 taken 73 times.
✓ Branch 13 → 14 taken 73 times.
✗ Branch 13 → 15 not taken.
✓ Branch 16 → 17 taken 73 times.
✗ Branch 16 → 148 not taken.
73 if (!m_databasePath.isEmpty() && store.open(m_databasePath)) {
154
2/2
✓ Branch 17 → 18 taken 73 times.
✓ Branch 18 → 19 taken 73 times.
73 QSqlQuery q(store.database());
155
1/1
✓ Branch 20 → 21 taken 73 times.
73 q.setForwardOnly(true);
156
2/3
✓ Branch 24 → 25 taken 73 times.
✓ Branch 27 → 28 taken 73 times.
✗ Branch 27 → 146 not taken.
73 if (q.exec(QStringLiteral("SELECT c.book_id, c.uid, c.display_name, c.has_photo, p.kind, p.lat, p.lon,"
157 " CASE WHEN p.locality <> '' THEN p.locality WHEN p.place_name <> '' THEN p.place_name"
158 " ELSE p.text END, p.country, p.source, p.precision"
159 " FROM card_places p JOIN cards c ON c.id = p.card_id"
160 " JOIN address_books b ON b.id = c.book_id WHERE b.show_in_all = 1 AND c.kind <> 'group'"))) {
161
3/3
✓ Branch 144 → 145 taken 3566 times.
✓ Branch 145 → 29 taken 3493 times.
✓ Branch 145 → 146 taken 73 times.
3566 while (q.next()) {
162
5/5
✓ Branch 29 → 30 taken 3493 times.
✓ Branch 30 → 31 taken 3493 times.
✓ Branch 31 → 32 taken 3493 times.
✓ Branch 32 → 33 taken 3493 times.
✓ Branch 33 → 34 taken 3493 times.
3493 const QString key = ContactQueries::cardKey(q.value(0).toLongLong(), q.value(1).toString());
163
2/2
✓ Branch 37 → 38 taken 3493 times.
✓ Branch 38 → 39 taken 3493 times.
3493 const QString kind = q.value(4).toString();
164
2/2
✓ Branch 41 → 42 taken 6 times.
✓ Branch 41 → 43 taken 3487 times.
3493 if (!m_kinds.contains(kind))
165 6 continue;
166
1/1
✓ Branch 43 → 44 taken 3487 times.
3487 withPlaceText.insert(key);
167
12/18
✓ Branch 44 → 45 taken 3487 times.
✓ Branch 45 → 46 taken 3487 times.
✓ Branch 46 → 47 taken 1881 times.
✓ Branch 46 → 50 taken 1606 times.
✓ Branch 47 → 48 taken 1881 times.
✓ Branch 48 → 49 taken 1881 times.
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 51 taken 1881 times.
✓ Branch 52 → 53 taken 1881 times.
✓ Branch 52 → 54 taken 1606 times.
✓ Branch 54 → 55 taken 3487 times.
✗ Branch 54 → 56 not taken.
✓ Branch 56 → 57 taken 1606 times.
✓ Branch 56 → 58 taken 1881 times.
✗ Branch 211 → 212 not taken.
✗ Branch 211 → 213 not taken.
✗ Branch 215 → 216 not taken.
✗ Branch 215 → 217 not taken.
3487 if (q.value(5).isNull() || q.value(6).isNull())
168 1606 continue;
169 1881 Place place;
170 1881 place.key = key;
171
2/2
✓ Branch 59 → 60 taken 1881 times.
✓ Branch 60 → 61 taken 1881 times.
1881 place.name = q.value(2).toString();
172
1/1
✓ Branch 64 → 65 taken 1881 times.
1881 ContactCard named;
173 1881 named.formattedName = place.name;
174
1/1
✓ Branch 66 → 67 taken 1881 times.
1881 place.initials = ContactIndex::initials(named);
175
3/3
✓ Branch 69 → 70 taken 1881 times.
✓ Branch 70 → 71 taken 1881 times.
✓ Branch 71 → 72 taken 1881 times.
1881 place.avatarColor = ContactIndex::avatarColorIndex(q.value(1).toString());
176
2/2
✓ Branch 74 → 75 taken 1881 times.
✓ Branch 75 → 76 taken 1881 times.
1881 place.hasPhoto = q.value(3).toBool();
177 1881 place.kind = kind;
178
2/2
✓ Branch 78 → 79 taken 1881 times.
✓ Branch 79 → 80 taken 1881 times.
1881 place.label = q.value(7).toString();
179
2/2
✓ Branch 83 → 84 taken 1881 times.
✓ Branch 84 → 85 taken 1881 times.
1881 place.country = q.value(8).toString();
180
2/2
✓ Branch 88 → 89 taken 1881 times.
✓ Branch 89 → 90 taken 1881 times.
1881 const QString source = q.value(9).toString();
181 // S103.1.9: a street-level answer of the online lookup is no estimate.
182
9/14
✓ Branch 93 → 94 taken 4 times.
✓ Branch 93 → 100 taken 1877 times.
✓ Branch 95 → 96 taken 4 times.
✓ Branch 96 → 97 taken 4 times.
✓ Branch 98 → 99 taken 4 times.
✗ Branch 98 → 100 not taken.
✓ Branch 101 → 102 taken 4 times.
✓ Branch 101 → 103 taken 1877 times.
✓ Branch 103 → 104 taken 4 times.
✓ Branch 103 → 105 taken 1877 times.
✗ Branch 244 → 245 not taken.
✗ Branch 244 → 246 not taken.
✗ Branch 248 → 249 not taken.
✗ Branch 248 → 250 not taken.
1881 const bool exactOnline = source == QLatin1String("online") && q.value(10).toString() == QLatin1String("exact");
183
5/6
✓ Branch 107 → 108 taken 1861 times.
✓ Branch 107 → 113 taken 20 times.
✓ Branch 110 → 111 taken 1861 times.
✗ Branch 110 → 113 not taken.
✓ Branch 111 → 112 taken 1857 times.
✓ Branch 111 → 113 taken 4 times.
1881 place.approximate = source != QLatin1String("pinned") && source != QLatin1String("card") && !exactOnline;
184 1881 place.person = int(personOf.size());
185
2/2
✓ Branch 118 → 119 taken 96 times.
✓ Branch 118 → 121 taken 1785 times.
1881 if (const auto known = personOf.constFind(key); known != personOf.cend())
186 96 place.person = *known;
187 else
188
1/1
✓ Branch 121 → 122 taken 1785 times.
1785 personOf.insert(key, place.person);
189
5/5
✓ Branch 122 → 123 taken 1881 times.
✓ Branch 123 → 124 taken 1881 times.
✓ Branch 124 → 125 taken 1881 times.
✓ Branch 125 → 126 taken 1881 times.
✓ Branch 126 → 127 taken 1881 times.
1881 place.world = MapProjection::project(q.value(5).toDouble(), q.value(6).toDouble());
190
1/1
✓ Branch 129 → 130 taken 1881 times.
1881 m_places.append(place);
191
1/1
✓ Branch 130 → 131 taken 1881 times.
1881 placed.insert(key);
192 5105 }
193 }
194 73 }
195 73 m_personCount = int(personOf.size());
196
1/1
✓ Branch 149 → 150 taken 73 times.
73 m_seenAt.assign(size_t(m_personCount), -1);
197 73 m_placedPeople = int(placed.size());
198
1/1
✓ Branch 151 → 152 taken 73 times.
73 m_unplacedPeople = int((withPlaceText - placed).size());
199
9/9
✓ Branch 154 → 155 taken 73 times.
✓ Branch 158 → 159 taken 73 times.
✓ Branch 159 → 160 taken 73 times.
✓ Branch 161 → 162 taken 73 times.
✓ Branch 162 → 163 taken 73 times.
✓ Branch 163 → 164 taken 73 times.
✓ Branch 164 → 165 taken 73 times.
✓ Branch 171 → 156 taken 73 times.
✓ Branch 171 → 172 taken 73 times.
146 qCInfo(lcMapTiles) << "Map places read:" << m_places.size() << "places of" << m_placedPeople << "people in"
200
2/2
✓ Branch 166 → 167 taken 73 times.
✓ Branch 167 → 168 taken 73 times.
73 << timer.elapsed() << "ms";
201
1/1
✓ Branch 172 → 173 taken 73 times.
73 emit placesChanged();
202
9/10
✓ Branch 173 → 174 taken 61 times.
✓ Branch 173 → 180 taken 12 times.
✓ Branch 174 → 175 taken 36 times.
✓ Branch 174 → 180 taken 25 times.
✓ Branch 176 → 177 taken 13 times.
✓ Branch 176 → 180 taken 23 times.
✓ Branch 178 → 179 taken 13 times.
✗ Branch 178 → 180 not taken.
✓ Branch 181 → 182 taken 13 times.
✓ Branch 181 → 183 taken 60 times.
73 if (!m_fitted && !m_placing && !m_places.isEmpty() && !m_viewport.size.isEmpty()) {
203 13 m_fitted = true;
204
1/1
✓ Branch 182 → 184 taken 13 times.
13 fitAll();
205 } else {
206
1/1
✓ Branch 183 → 184 taken 60 times.
60 updateMarkers();
207 }
208 73 }
209
210 158 QString QuickContactMap::viewMode() const {
211
3/3
✓ Branch 2 → 3 taken 158 times.
✓ Branch 7 → 8 taken 158 times.
✓ Branch 8 → 9 taken 158 times.
316 const QString mode = QSettings().value(QStringLiteral("contacts/viewMode")).toString();
212
6/6
✓ Branch 15 → 16 taken 120 times.
✓ Branch 15 → 19 taken 38 times.
✓ Branch 18 → 19 taken 30 times.
✓ Branch 18 → 20 taken 90 times.
✓ Branch 24 → 25 taken 90 times.
✓ Branch 24 → 26 taken 68 times.
564 return mode == QLatin1String("map") || mode == QLatin1String("graph") ? mode : QStringLiteral("list");
213 158 }
214
215 36 void QuickContactMap::setViewMode(const QString &mode) {
216
5/7
✓ Branch 2 → 3 taken 36 times.
✓ Branch 4 → 5 taken 22 times.
✓ Branch 4 → 14 taken 14 times.
✓ Branch 18 → 19 taken 15 times.
✓ Branch 18 → 20 taken 21 times.
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 49 not taken.
94 if (mode == viewMode() ||
217
7/8
✓ Branch 7 → 8 taken 18 times.
✓ Branch 7 → 15 taken 4 times.
✓ Branch 10 → 11 taken 9 times.
✓ Branch 10 → 15 taken 9 times.
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 15 taken 8 times.
✓ Branch 16 → 17 taken 36 times.
✗ Branch 16 → 18 not taken.
58 (mode != QLatin1String("list") && mode != QLatin1String("map") && mode != QLatin1String("graph")))
218 15 return;
219
2/2
✓ Branch 20 → 21 taken 21 times.
✓ Branch 26 → 27 taken 21 times.
42 QSettings().setValue(QStringLiteral("contacts/viewMode"), mode);
220
6/6
✓ Branch 31 → 32 taken 21 times.
✓ Branch 35 → 36 taken 21 times.
✓ Branch 36 → 37 taken 21 times.
✓ Branch 37 → 38 taken 21 times.
✓ Branch 41 → 33 taken 21 times.
✓ Branch 41 → 42 taken 21 times.
42 qCInfo(lcMapTiles) << "Contact view:" << mode;
221 21 emit viewModeChanged();
222 }
223
224 2 void QuickContactMap::setPlacesList(bool on) {
225
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2 times.
2 if (on == m_placesList)
226 ✗ return;
227 2 m_placesList = on;
228 2 emit viewModeChanged();
229 }
230
231 2 QVariantList QuickContactMap::placesTree() const {
232 struct City {
233 QList<const Place *> people;
234 };
235 2 QMap<QString, QMap<QString, City>> countries;
236
2/2
✓ Branch 20 → 4 taken 165 times.
✓ Branch 20 → 21 taken 2 times.
167 for (const Place &place : m_places) {
237
3/3
✓ Branch 6 → 7 taken 119 times.
✓ Branch 6 → 8 taken 46 times.
✓ Branch 7 → 9 taken 119 times.
165 const QString country = place.country.isEmpty() ? tr("Other places") : place.country;
238
4/6
✓ Branch 9 → 10 taken 165 times.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 165 times.
✗ Branch 12 → 14 not taken.
✓ Branch 14 → 15 taken 165 times.
✓ Branch 15 → 16 taken 165 times.
165 countries[country][place.label.isEmpty() ? tr("Unnamed place") : place.label].people.append(&place);
239 165 }
240 2 QVariantList out;
241
4/4
✓ Branch 21 → 22 taken 2 times.
✓ Branch 129 → 130 taken 26 times.
✓ Branch 131 → 23 taken 24 times.
✓ Branch 131 → 132 taken 2 times.
26 for (auto country = countries.cbegin(); country != countries.cend(); ++country) {
242 24 QVariantList cities;
243 24 int total = 0;
244
4/4
✓ Branch 24 → 25 taken 24 times.
✓ Branch 94 → 95 taken 94 times.
✓ Branch 96 → 26 taken 70 times.
✓ Branch 96 → 97 taken 24 times.
94 for (auto city = country->cbegin(); city != country->cend(); ++city) {
245 70 QVariantList people;
246
2/2
✓ Branch 58 → 29 taken 165 times.
✓ Branch 58 → 59 taken 70 times.
235 for (const Place *place : city->people)
247
1/1
✓ Branch 44 → 45 taken 165 times.
495 people.append(QVariantMap{{QStringLiteral("key"), place->key},
248 330 {QStringLiteral("name"), place->name},
249
2/4
✓ Branch 48 → 49 taken 495 times.
✓ Branch 48 → 50 taken 165 times.
✗ Branch 150 → 151 not taken.
✗ Branch 150 → 152 not taken.
990 {QStringLiteral("kind"), place->kind}});
250
3/3
✓ Branch 59 → 60 taken 70 times.
✓ Branch 60 → 61 taken 70 times.
✓ Branch 61 → 62 taken 70 times.
70 std::sort(people.begin(), people.end(), [](const QVariant &a, const QVariant &b) {
251
4/4
✓ Branch 2 → 3 taken 317 times.
✓ Branch 7 → 8 taken 317 times.
✓ Branch 8 → 9 taken 317 times.
✓ Branch 16 → 17 taken 317 times.
1268 return a.toMap().value(QStringLiteral("name")).toString().localeAwareCompare(
252
3/3
✓ Branch 9 → 10 taken 317 times.
✓ Branch 14 → 15 taken 317 times.
✓ Branch 15 → 16 taken 317 times.
1268 b.toMap().value(QStringLiteral("name")).toString()) < 0;
253 });
254 70 total += int(people.size());
255
1/1
✓ Branch 79 → 80 taken 70 times.
210 cities.append(QVariantMap{{QStringLiteral("city"), city.key()},
256 140 {QStringLiteral("count"), int(people.size())},
257
2/4
✓ Branch 83 → 84 taken 210 times.
✓ Branch 83 → 85 taken 70 times.
✗ Branch 185 → 186 not taken.
✗ Branch 185 → 187 not taken.
350 {QStringLiteral("people"), people}});
258 70 }
259 157 const auto byCount = [](const QVariant &a, const QVariant &b) {
260
3/3
✓ Branch 2 → 3 taken 157 times.
✓ Branch 7 → 8 taken 157 times.
✓ Branch 8 → 9 taken 157 times.
314 const int ca = a.toMap().value(QStringLiteral("count")).toInt();
261
3/3
✓ Branch 14 → 15 taken 157 times.
✓ Branch 19 → 20 taken 157 times.
✓ Branch 20 → 21 taken 157 times.
314 const int cb = b.toMap().value(QStringLiteral("count")).toInt();
262
4/4
✓ Branch 26 → 27 taken 80 times.
✓ Branch 26 → 29 taken 77 times.
✓ Branch 27 → 28 taken 41 times.
✓ Branch 27 → 29 taken 39 times.
157 return ca != cb ? ca > cb : false;
263 };
264
3/3
✓ Branch 97 → 98 taken 24 times.
✓ Branch 98 → 99 taken 24 times.
✓ Branch 99 → 100 taken 24 times.
24 std::stable_sort(cities.begin(), cities.end(), byCount);
265
1/1
✓ Branch 115 → 116 taken 24 times.
72 out.append(QVariantMap{{QStringLiteral("country"), country.key()},
266 48 {QStringLiteral("count"), total},
267
2/4
✓ Branch 119 → 120 taken 72 times.
✓ Branch 119 → 121 taken 24 times.
✗ Branch 225 → 226 not taken.
✗ Branch 225 → 227 not taken.
120 {QStringLiteral("cities"), cities}});
268 24 }
269
3/3
✓ Branch 132 → 133 taken 2 times.
✓ Branch 133 → 134 taken 2 times.
✓ Branch 134 → 135 taken 2 times.
2 std::stable_sort(out.begin(), out.end(), [](const QVariant &a, const QVariant &b) {
270
6/6
✓ Branch 2 → 3 taken 71 times.
✓ Branch 7 → 8 taken 71 times.
✓ Branch 8 → 9 taken 71 times.
✓ Branch 9 → 10 taken 71 times.
✓ Branch 14 → 15 taken 71 times.
✓ Branch 15 → 16 taken 71 times.
213 return a.toMap().value(QStringLiteral("count")).toInt() > b.toMap().value(QStringLiteral("count")).toInt();
271 });
272 2 return out;
273 1038 }
274
275 2 void QuickContactMap::setKinds(const QStringList &kinds) {
276
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 2 times.
2 if (kinds == m_kinds)
277 ✗ return;
278 2 m_kinds = kinds;
279 2 readPlaces();
280 }
281
282 84 void QuickContactMap::setSize(double width, double height) {
283
4/4
✓ Branch 2 → 3 taken 65 times.
✓ Branch 2 → 4 taken 19 times.
✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 5 taken 63 times.
84 if (width <= 0 || height <= 0)
284 21 return;
285 63 MapProjection::Viewport next = m_viewport;
286 63 next.size = QSizeF(width, height);
287
1/1
✓ Branch 6 → 7 taken 63 times.
63 next.zoom = qMax(next.zoom, MapProjection::minZoomFor(next.size));
288
1/1
✓ Branch 8 → 9 taken 63 times.
63 setViewport(next);
289
6/8
✓ Branch 9 → 10 taken 50 times.
✓ Branch 9 → 14 taken 13 times.
✓ Branch 10 → 11 taken 44 times.
✓ Branch 10 → 14 taken 6 times.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 44 times.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 63 times.
63 if (!m_fitted && !m_placing && !m_places.isEmpty()) {
290 ✗ m_fitted = true;
291 ✗ fitAll();
292 }
293 }
294
295
2/2
✓ Branch 3 → 4 taken 5 times.
✓ Branch 4 → 5 taken 5 times.
5 void QuickContactMap::panBy(double dx, double dy) { setViewport(m_viewport.panned(QPointF(dx, dy))); }
296
297
2/2
✓ Branch 3 → 4 taken 21 times.
✓ Branch 4 → 5 taken 21 times.
21 void QuickContactMap::zoomAt(double steps, double x, double y) { setViewport(m_viewport.zoomed(steps, QPointF(x, y))); }
298
299 14 void QuickContactMap::fitAll() {
300 14 QList<QPointF> points;
301
2/2
✓ Branch 9 → 5 taken 888 times.
✓ Branch 9 → 10 taken 14 times.
902 for (const Place &place : std::as_const(m_places))
302
1/1
✓ Branch 6 → 7 taken 888 times.
888 points.append(place.world);
303
1/1
✓ Branch 10 → 11 taken 14 times.
14 MapProjection::Viewport next = MapProjection::fit(points, m_viewport.size);
304
1/1
✓ Branch 11 → 12 taken 14 times.
14 next.zoom = qMax(next.zoom, MapProjection::minZoomFor(next.size));
305
1/1
✓ Branch 13 → 14 taken 14 times.
14 setViewport(next);
306 14 }
307
308 // §6.5: pan (never zoom) to the person's first place when none is in view.
309 5 void QuickContactMap::showKey(const QString &key) {
310 5 QList<QPointF> points;
311
2/2
✓ Branch 11 → 5 taken 330 times.
✓ Branch 11 → 12 taken 5 times.
335 for (const Place &place : std::as_const(m_places))
312
2/2
✓ Branch 7 → 8 taken 4 times.
✓ Branch 7 → 9 taken 326 times.
330 if (place.key == key)
313
1/1
✓ Branch 8 → 9 taken 4 times.
4 points.append(place.world);
314
5/6
✓ Branch 13 → 14 taken 4 times.
✓ Branch 13 → 16 taken 1 time.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 17 taken 4 times.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 20 taken 4 times.
5 if (points.isEmpty() || m_viewport.size.isEmpty())
315 1 return;
316 4 const QRectF canvas(QPointF(0, 0), m_viewport.size);
317
4/4
✓ Branch 22 → 23 taken 4 times.
✓ Branch 23 → 24 taken 4 times.
✓ Branch 32 → 25 taken 4 times.
✓ Branch 32 → 33 taken 1 time.
5 for (const QPointF &point : points)
318
3/3
✓ Branch 26 → 27 taken 4 times.
✓ Branch 28 → 29 taken 3 times.
✓ Branch 28 → 30 taken 1 time.
4 if (canvas.contains(m_viewport.toScreen(point)))
319 3 return;
320 1 MapProjection::Viewport next = m_viewport;
321
1/1
✓ Branch 33 → 34 taken 1 time.
1 next.center = points.first();
322
1/1
✓ Branch 34 → 35 taken 1 time.
1 setViewport(next);
323 5 }
324
325 7 QVariantMap QuickContactMap::toLatLon(double x, double y) const {
326
2/2
✓ Branch 3 → 4 taken 7 times.
✓ Branch 4 → 5 taken 7 times.
7 const QPointF lonLat = MapProjection::unproject(m_viewport.toWorld(QPointF(x, y)));
327
2/4
✓ Branch 17 → 18 taken 14 times.
✓ Branch 17 → 19 taken 7 times.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 30 not taken.
35 return {{QStringLiteral("latitude"), lonLat.y()}, {QStringLiteral("longitude"), lonLat.x()}};
328 21 }
329
330 8 void QuickContactMap::centerOn(double latitude, double longitude, double zoom) {
331 8 MapProjection::Viewport next = m_viewport;
332
1/1
✓ Branch 2 → 3 taken 8 times.
8 next.center = MapProjection::project(latitude, longitude);
333
1/2
✓ Branch 3 → 4 taken 8 times.
✗ Branch 3 → 7 not taken.
8 if (zoom > 0)
334
1/1
✓ Branch 4 → 5 taken 8 times.
8 next.zoom = qBound(MapProjection::minZoomFor(next.size), zoom, next.maxZoom);
335
1/1
✓ Branch 7 → 8 taken 8 times.
8 setViewport(next);
336 8 }
337
338 2 QVariantMap QuickContactMap::toScreen(double latitude, double longitude) const {
339
2/2
✓ Branch 2 → 3 taken 2 times.
✓ Branch 3 → 4 taken 2 times.
2 const QPointF point = m_viewport.toScreen(MapProjection::project(latitude, longitude));
340
2/4
✓ Branch 16 → 17 taken 4 times.
✓ Branch 16 → 18 taken 2 times.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 28 not taken.
10 return {{QStringLiteral("x"), point.x()}, {QStringLiteral("y"), point.y()}};
341 6 }
342
343 2 bool QuickContactMap::showPlace(const QString &text) {
344
1/1
✓ Branch 2 → 3 taken 2 times.
2 const std::shared_ptr<const GeoData> data = GeoData::builtIn();
345
5/11
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 2 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 2 times.
✓ Branch 10 → 11 taken 2 times.
✗ Branch 10 → 12 not taken.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 2 times.
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 52 not taken.
2 if (!data || text.trimmed().isEmpty())
346 ✗ return false;
347
2/2
✓ Branch 15 → 16 taken 2 times.
✓ Branch 17 → 18 taken 2 times.
2 const PlaceGazetteer::Place place = PlaceGazetteer::locateText(*data, text.trimmed());
348
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 2 times.
2 if (!place.isValid())
349 ✗ return false;
350
2/4
✗ Branch 25 → 26 not taken.
✓ Branch 25 → 27 taken 2 times.
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 2 times.
2 const double zoom = place.precision == QLatin1String("country") ? 4 : place.precision == QLatin1String("region") ? 6 : 9;
351
1/1
✓ Branch 33 → 34 taken 2 times.
2 centerOn(place.position.latitude, place.position.longitude, zoom);
352
6/6
✓ Branch 34 → 35 taken 2 times.
✓ Branch 38 → 39 taken 2 times.
✓ Branch 39 → 40 taken 2 times.
✓ Branch 40 → 41 taken 2 times.
✓ Branch 44 → 36 taken 2 times.
✓ Branch 44 → 45 taken 2 times.
4 qCInfo(lcMapTiles) << "Map shows a place of precision" << place.precision;
353 2 return true;
354 2 }
355
356 20 QVariantMap QuickContactMap::nearby(const QString &text) const {
357
1/1
✓ Branch 2 → 3 taken 20 times.
20 const std::shared_ptr<const GeoData> data = GeoData::builtIn();
358
9/13
✓ Branch 4 → 5 taken 10 times.
✓ Branch 4 → 10 taken 10 times.
✓ Branch 5 → 6 taken 10 times.
✓ Branch 7 → 8 taken 10 times.
✗ Branch 7 → 10 not taken.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 10 times.
✓ Branch 12 → 13 taken 10 times.
✓ Branch 12 → 14 taken 10 times.
✓ Branch 14 → 15 taken 10 times.
✓ Branch 14 → 16 taken 10 times.
✗ Branch 114 → 115 not taken.
✗ Branch 114 → 116 not taken.
20 if (!data || text.trimmed().isEmpty() || m_databasePath.isEmpty())
359 10 return {};
360
2/2
✓ Branch 17 → 18 taken 10 times.
✓ Branch 19 → 20 taken 10 times.
10 const PlaceGazetteer::Place place = PlaceGazetteer::locateText(*data, text.trimmed());
361
6/6
✓ Branch 23 → 24 taken 9 times.
✓ Branch 23 → 27 taken 1 time.
✓ Branch 26 → 27 taken 1 time.
✓ Branch 26 → 28 taken 8 times.
✓ Branch 29 → 30 taken 2 times.
✓ Branch 29 → 31 taken 8 times.
10 if (!place.isValid() || place.precision == QLatin1String("country"))
362 2 return {};
363
1/1
✓ Branch 31 → 32 taken 8 times.
8 ContactStore store;
364
2/3
✓ Branch 32 → 33 taken 8 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 8 times.
8 if (!store.open(m_databasePath))
365 ✗ return {};
366 // About 50 km: the box of the contact search's near: (ContactPeopleFilter).
367 8 const double lat = place.position.latitude, lon = place.position.longitude;
368 8 const double dLon = 0.45 / qMax(0.1, std::cos(lat * M_PI / 180.0));
369
2/2
✓ Branch 36 → 37 taken 8 times.
✓ Branch 37 → 38 taken 8 times.
8 QSqlQuery q(store.database());
370
1/1
✓ Branch 42 → 43 taken 8 times.
8 q.prepare(QStringLiteral("SELECT DISTINCT c.book_id, c.uid FROM card_places p JOIN cards c ON c.id = p.card_id"
371 " JOIN address_books b ON b.id = c.book_id WHERE b.show_in_all = 1 AND c.kind <> 'group'"
372 " AND p.precision <> 'country' AND p.lat BETWEEN ? AND ? AND p.lon BETWEEN ? AND ?"));
373
1/1
✓ Branch 47 → 48 taken 8 times.
8 q.addBindValue(lat - 0.45);
374
1/1
✓ Branch 51 → 52 taken 8 times.
8 q.addBindValue(lat + 0.45);
375
1/1
✓ Branch 55 → 56 taken 8 times.
8 q.addBindValue(lon - dLon);
376
1/1
✓ Branch 59 → 60 taken 8 times.
8 q.addBindValue(lon + dLon);
377
3/3
✓ Branch 61 → 62 taken 8 times.
✓ Branch 66 → 67 taken 8 times.
✓ Branch 67 → 68 taken 8 times.
16 const QString me = QSettings().value(QStringLiteral("contacts/meCard")).toString();
378 8 int count = 0;
379
2/3
✓ Branch 72 → 73 taken 8 times.
✓ Branch 73 → 74 taken 8 times.
✗ Branch 73 → 91 not taken.
8 if (q.exec())
380
3/3
✓ Branch 89 → 90 taken 33 times.
✓ Branch 90 → 75 taken 25 times.
✓ Branch 90 → 91 taken 8 times.
33 while (q.next())
381
6/7
✓ Branch 75 → 76 taken 25 times.
✓ Branch 76 → 77 taken 25 times.
✓ Branch 77 → 78 taken 25 times.
✓ Branch 78 → 79 taken 25 times.
✓ Branch 79 → 80 taken 25 times.
✓ Branch 81 → 82 taken 25 times.
✗ Branch 81 → 83 not taken.
25 count += ContactQueries::cardKey(q.value(0).toLongLong(), q.value(1).toString()) != me ? 1 : 0;
382
2/4
✓ Branch 101 → 102 taken 16 times.
✓ Branch 101 → 103 taken 8 times.
✗ Branch 173 → 174 not taken.
✗ Branch 173 → 175 not taken.
40 return {{QStringLiteral("place"), place.placeName}, {QStringLiteral("count"), count}};
383 44 }
384
385 112 void QuickContactMap::setViewport(const MapProjection::Viewport &requested) {
386 112 MapProjection::Viewport viewport = requested; // fit() knows nothing of the online tiles
387
3/3
✓ Branch 2 → 3 taken 11 times.
✓ Branch 2 → 5 taken 101 times.
✓ Branch 3 → 4 taken 11 times.
112 viewport.maxZoom = m_onlineTiles ? onlineMaxZoom() : MapProjection::MaxZoom;
388
5/6
✓ Branch 7 → 8 taken 18 times.
✓ Branch 7 → 11 taken 94 times.
✓ Branch 9 → 10 taken 18 times.
✗ Branch 9 → 11 not taken.
✓ Branch 12 → 13 taken 18 times.
✓ Branch 12 → 14 taken 94 times.
112 if (viewport == m_viewport && !m_tiles.isEmpty())
389 18 return;
390 94 m_viewport = viewport;
391
1/1
✓ Branch 14 → 15 taken 94 times.
94 updateTiles();
392
1/1
✓ Branch 15 → 16 taken 94 times.
94 updateMarkers();
393
1/1
✓ Branch 16 → 17 taken 94 times.
94 emit viewportChanged();
394 }
395
396 31 void QuickContactMap::rebuildClusterInput() {
397 31 m_clusterInput.clear();
398 31 m_clusterInput.reserve(m_places.size());
399
2/2
✓ Branch 12 → 6 taken 1881 times.
✓ Branch 12 → 13 taken 31 times.
1912 for (int i = 0; i < m_places.size(); ++i)
400 1881 m_clusterInput.append({QString::number(i), m_places.at(i).world});
401 31 m_clusterZoom = -1;
402 1912 }
403
404 // The people of a cluster, computed when it first becomes visible at a zoom.
405 296 const QStringList &QuickContactMap::clusterKeys(int cluster) {
406
1/1
✓ Branch 2 → 3 taken 296 times.
296 auto found = m_clusterKeys.find(cluster);
407
2/2
✓ Branch 5 → 6 taken 103 times.
✓ Branch 5 → 7 taken 193 times.
296 if (found != m_clusterKeys.end())
408 103 return *found;
409 193 QStringList keys;
410
2/2
✓ Branch 19 → 10 taken 1587 times.
✓ Branch 19 → 20 taken 193 times.
1780 for (const QString &member : m_clusters.at(cluster).members) {
411
1/1
✓ Branch 11 → 12 taken 1587 times.
1587 const Place &place = m_places.at(member.toInt());
412
2/2
✓ Branch 14 → 15 taken 1538 times.
✓ Branch 14 → 17 taken 49 times.
1587 if (m_seenAt[size_t(place.person)] != cluster) {
413 1538 m_seenAt[size_t(place.person)] = cluster;
414
1/1
✓ Branch 16 → 17 taken 1538 times.
1538 keys.append(place.key);
415 }
416 }
417
1/1
✓ Branch 20 → 21 taken 193 times.
193 return *m_clusterKeys.insert(cluster, keys);
418 193 }
419
420 195 void QuickContactMap::updateMarkers() {
421 195 QElapsedTimer timer;
422 195 timer.start();
423
2/2
✓ Branch 5 → 6 taken 31 times.
✓ Branch 5 → 7 taken 164 times.
195 if (m_clusterInput.size() != m_places.size())
424
1/1
✓ Branch 6 → 7 taken 31 times.
31 rebuildClusterInput();
425 // F103-14: clusters are made per whole zoom level; between levels the
426 // same clusters only move (each fractional step re-formed them, so the
427 // bubbles jumped while zooming). 88 px cells at the level are 62–124 px
428 // on screen, still apart for markers up to 44 px.
429 195 const double level = std::round(m_viewport.zoom);
430
2/2
✓ Branch 7 → 8 taken 112 times.
✓ Branch 7 → 16 taken 83 times.
195 if (level != m_clusterZoom) {
431
1/1
✓ Branch 8 → 9 taken 112 times.
112 m_clusters = MapClusterer::cluster(m_clusterInput, level, 88.0);
432 112 m_clusterZoom = level;
433 112 m_clusterKeys.clear();
434
1/1
✓ Branch 14 → 15 taken 112 times.
112 std::fill(m_seenAt.begin(), m_seenAt.end(), -1);
435 }
436 195 QVariantList markers;
437
1/1
✓ Branch 16 → 17 taken 195 times.
195 const double worldPixels = m_viewport.worldPixels();
438
2/2
✓ Branch 174 → 18 taken 664 times.
✓ Branch 174 → 175 taken 195 times.
859 for (int c = 0; c < m_clusters.size(); ++c) {
439 664 const MapClusterer::Cluster &cluster = m_clusters.at(c);
440
1/1
✓ Branch 19 → 20 taken 664 times.
664 QPointF point = m_viewport.toScreen(cluster.world);
441 // The world repeats east–west: take the copy inside the canvas.
442
5/6
✓ Branch 24 → 25 taken 37 times.
✓ Branch 24 → 27 taken 664 times.
✓ Branch 25 → 26 taken 37 times.
✗ Branch 25 → 27 not taken.
✓ Branch 28 → 21 taken 37 times.
✓ Branch 28 → 29 taken 664 times.
701 while (point.x() < -32 && worldPixels > 0)
443 37 point.rx() += worldPixels;
444
5/6
✓ Branch 34 → 35 taken 344 times.
✓ Branch 34 → 37 taken 664 times.
✓ Branch 35 → 36 taken 344 times.
✗ Branch 35 → 37 not taken.
✓ Branch 38 → 30 taken 344 times.
✓ Branch 38 → 39 taken 664 times.
1008 while (point.x() > m_viewport.size.width() + 32 && worldPixels > 0)
445 344 point.rx() -= worldPixels;
446
7/8
✓ Branch 40 → 41 taken 320 times.
✓ Branch 40 → 49 taken 344 times.
✓ Branch 42 → 43 taken 306 times.
✓ Branch 42 → 49 taken 14 times.
✓ Branch 45 → 46 taken 306 times.
✗ Branch 45 → 49 not taken.
✓ Branch 51 → 52 taken 368 times.
✓ Branch 51 → 53 taken 296 times.
970 if (point.x() < -32 || point.y() < -32 || point.x() > m_viewport.size.width() + 32 ||
447
2/2
✓ Branch 48 → 49 taken 10 times.
✓ Branch 48 → 50 taken 296 times.
306 point.y() > m_viewport.size.height() + 32)
448 368 continue;
449
1/2
✗ Branch 54 → 55 not taken.
✓ Branch 54 → 56 taken 296 times.
296 if (cluster.members.isEmpty())
450 ✗ continue;
451
1/1
✓ Branch 56 → 57 taken 296 times.
296 const QStringList &keys = clusterKeys(c);
452
1/1
✓ Branch 58 → 59 taken 296 times.
296 const Place *first = &m_places.at(cluster.members.first().toInt());
453 592 QVariantMap marker{{QStringLiteral("id"), cluster.id},
454 592 {QStringLiteral("x"), point.x()},
455 592 {QStringLiteral("y"), point.y()},
456 592 {QStringLiteral("count"), int(keys.size())},
457 592 {QStringLiteral("keys"), keys},
458 592 {QStringLiteral("sameSpot"), cluster.sameSpot},
459
2/4
✓ Branch 93 → 94 taken 2072 times.
✓ Branch 93 → 95 taken 296 times.
✗ Branch 202 → 203 not taken.
✗ Branch 202 → 204 not taken.
2664 {QStringLiteral("place"), first->label}};
460
2/2
✓ Branch 110 → 111 taken 148 times.
✓ Branch 110 → 166 taken 148 times.
296 if (keys.size() == 1)
461
3/5
✓ Branch 144 → 145 taken 148 times.
✓ Branch 147 → 148 taken 1184 times.
✓ Branch 147 → 149 taken 148 times.
✗ Branch 259 → 260 not taken.
✗ Branch 259 → 261 not taken.
1628 marker.insert({{QStringLiteral("key"), first->key},
462 296 {QStringLiteral("name"), first->name},
463 296 {QStringLiteral("initials"), first->initials},
464 296 {QStringLiteral("avatarColor"), first->avatarColor},
465 296 {QStringLiteral("hasPhoto"), first->hasPhoto},
466 296 {QStringLiteral("kind"), first->kind},
467 296 {QStringLiteral("country"), first->country},
468 296 {QStringLiteral("approximate"), first->approximate}});
469
1/1
✓ Branch 167 → 168 taken 296 times.
296 markers.append(marker);
470 296 }
471 195 m_markers = markers;
472
1/1
✓ Branch 176 → 177 taken 195 times.
195 m_markerModel->setMarkers(markers);
473
9/9
✓ Branch 177 → 178 taken 195 times.
✓ Branch 181 → 182 taken 195 times.
✓ Branch 182 → 183 taken 195 times.
✓ Branch 184 → 185 taken 195 times.
✓ Branch 185 → 186 taken 195 times.
✓ Branch 187 → 188 taken 195 times.
✓ Branch 188 → 189 taken 195 times.
✓ Branch 195 → 179 taken 195 times.
✓ Branch 195 → 196 taken 195 times.
390 qCDebug(lcMapTiles) << "Markers:" << markers.size() << "from" << m_places.size() << "places in"
474
2/2
✓ Branch 190 → 191 taken 195 times.
✓ Branch 191 → 192 taken 195 times.
195 << timer.nsecsElapsed() / 1000 << "µs";
475
1/1
✓ Branch 196 → 197 taken 195 times.
195 emit markersChanged();
476 3895 }
477