Merge lp:~mterry/unity8/oobe-timezone into lp:~lukas-kde/unity8/oobe
- oobe-timezone
- Merge into oobe
Status: | Merged |
---|---|
Merged at revision: | 2118 |
Proposed branch: | lp:~mterry/unity8/oobe-timezone |
Merge into: | lp:~lukas-kde/unity8/oobe |
Diff against target: |
665 lines (+193/-222) 11 files modified
CMakeLists.txt (+1/-0) debian/control (+1/-1) plugins/Wizard/CMakeLists.txt (+2/-4) plugins/Wizard/plugin.cpp (+0/-1) plugins/Wizard/timezonemodel.cpp (+152/-141) plugins/Wizard/timezonemodel.h (+22/-55) qml/Wizard/Pages.qml (+0/-11) qml/Wizard/Pages/10-welcome.qml (+0/-1) qml/Wizard/Pages/50-timezone.qml (+13/-3) tests/mocks/Wizard/CMakeLists.txt (+2/-4) tests/mocks/Wizard/mockplugin.cpp (+0/-1) |
To merge this branch: | bzr merge lp:~mterry/unity8/oobe-timezone |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Lukáš Tinkl | Approve | ||
Review via email: mp+287520@code.launchpad.net |
Commit message
Description of the change
Switch to libgeonames and add an ActivityIndicator.
Needs https:/
Lukáš Tinkl (lukas-kde) wrote : | # |
Michael Terry (mterry) wrote : | # |
The model itself is now the filter model, basically. The backing model is internal to libgeonames. And we just query it for filtered results. So our model now just stores the query results.
You say "filter on both at the same time". What do you mean by that?
I don't think your inline comments survived LP.
Lukáš Tinkl (lukas-kde) wrote : | # |
Inline comments (re)added
- 2119. By Michael Terry
-
Sort default cities by name, not population
- 2120. By Michael Terry
-
Fix some review comments
Michael Terry (mterry) wrote : | # |
> No need to cast the result to QVariant explicitely, also it should be sth like:
>
> QStringLiteral("%1, %2, %3).arg(
Fixed this (don't cast to QVariant, and use QStringLiteral). But I didn't use ::fromUtf8, because the QString constructor assumes Utf8 already.
> const QList<GeonamesCity *> &locations
Fixed.
> The default country should be the one from root.country (set in the first page).
In this MP, I've removed root.countryCode. I can add it back if you insist, but I didn't understand why it existed in the first place. The language page already saves the chosen language in the shared value i18n.language. We don't need to store country separately, right?
The less special cross-page variables, the better, in my book.
Lukáš Tinkl (lukas-kde) wrote : | # |
> > No need to cast the result to QVariant explicitely, also it should be sth
> like:
> >
> > QStringLiteral("%1, %2, %3).arg(
>
> Fixed this (don't cast to QVariant, and use QStringLiteral). But I didn't use
> ::fromUtf8, because the QString constructor assumes Utf8 already.
>
> > const QList<GeonamesCity *> &locations
>
> Fixed.
>
> > The default country should be the one from root.country (set in the first
> page).
>
> In this MP, I've removed root.countryCode. I can add it back if you insist,
> but I didn't understand why it existed in the first place. The language page
> already saves the chosen language in the shared value i18n.language. We don't
> need to store country separately, right?
>
> The less special cross-page variables, the better, in my book.
Yup, looks good now
- 2121. By Michael Terry
-
Go back to sorting cities (when no search pattern entered) by population; Paty liked it
Lukáš Tinkl (lukas-kde) wrote : | # |
Worked great with my testing, thanks!
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2016-02-12 00:12:30 +0000 |
3 | +++ CMakeLists.txt 2016-03-02 16:19:54 +0000 |
4 | @@ -58,6 +58,7 @@ |
5 | find_package(Qt5Sql 5.4 REQUIRED) |
6 | |
7 | pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=13) |
8 | +pkg_check_modules(GEONAMES REQUIRED geonames) |
9 | pkg_check_modules(GIO REQUIRED gio-2.0>=2.32) |
10 | pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32) |
11 | pkg_check_modules(QMENUMODEL REQUIRED qmenumodel) |
12 | |
13 | === modified file 'debian/control' |
14 | --- debian/control 2016-02-16 04:28:15 +0000 |
15 | +++ debian/control 2016-03-02 16:19:54 +0000 |
16 | @@ -15,6 +15,7 @@ |
17 | gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815), |
18 | libconnectivity-qt1-dev, |
19 | libevdev-dev, |
20 | + libgeonames-dev (>= 0.2), |
21 | libgl1-mesa-dev[!armhf] | libgl-dev[!armhf], |
22 | libgl1-mesa-dri, |
23 | libgles2-mesa-dev[armhf], |
24 | @@ -28,7 +29,6 @@ |
25 | libqt5svg5-dev, |
26 | libqt5xmlpatterns5-dev, |
27 | libsystemsettings-dev, |
28 | - libtimezonemap1-dev, |
29 | libudev-dev, |
30 | libunity-api-dev (>= 7.106), |
31 | libusermetricsoutput1-dev, |
32 | |
33 | === modified file 'plugins/Wizard/CMakeLists.txt' |
34 | --- plugins/Wizard/CMakeLists.txt 2016-02-16 13:10:24 +0000 |
35 | +++ plugins/Wizard/CMakeLists.txt 2016-03-02 16:19:54 +0000 |
36 | @@ -1,6 +1,4 @@ |
37 | -pkg_search_module(TIMEZONEMAP REQUIRED timezonemap) |
38 | - |
39 | -include_directories(${GLIB_INCLUDE_DIRS} ${TIMEZONEMAP_INCLUDE_DIRS}) |
40 | +include_directories(${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS}) |
41 | |
42 | add_library(Wizard-qml MODULE |
43 | plugin.cpp |
44 | @@ -12,7 +10,7 @@ |
45 | ) |
46 | |
47 | qt5_use_modules(Wizard-qml DBus Qml Concurrent) |
48 | -target_link_libraries(Wizard-qml ${GLIB_LDFLAGS} ${TIMEZONEMAP_LDFLAGS}) |
49 | +target_link_libraries(Wizard-qml ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS}) |
50 | add_unity8_plugin(Wizard 0.1 Wizard TARGETS Wizard-qml) |
51 | |
52 | set(POLKIT_LIB_DIR "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1") |
53 | |
54 | === modified file 'plugins/Wizard/plugin.cpp' |
55 | --- plugins/Wizard/plugin.cpp 2016-02-16 13:10:24 +0000 |
56 | +++ plugins/Wizard/plugin.cpp 2016-03-02 16:19:54 +0000 |
57 | @@ -30,6 +30,5 @@ |
58 | qmlRegisterSingletonType<System>(uri, 0, 1, "System", [](QQmlEngine*, QJSEngine*) -> QObject* { return new System; }); |
59 | qmlRegisterSingletonType<Status>(uri, 0, 1, "Status", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Status; }); |
60 | qmlRegisterType<TimeZoneLocationModel>(uri, 0, 1, "TimeZoneModel"); |
61 | - qmlRegisterType<TimeZoneFilterModel>(uri, 0, 1, "TimeZoneFilterModel"); |
62 | qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin"); |
63 | } |
64 | |
65 | === modified file 'plugins/Wizard/timezonemodel.cpp' |
66 | --- plugins/Wizard/timezonemodel.cpp 2016-02-16 13:10:24 +0000 |
67 | +++ plugins/Wizard/timezonemodel.cpp 2016-03-02 16:19:54 +0000 |
68 | @@ -1,5 +1,5 @@ |
69 | /* |
70 | - * Copyright (C) 2015 Canonical Ltd. |
71 | + * Copyright (C) 2016 Canonical Ltd. |
72 | * |
73 | * This program is free software: you can redistribute it and/or modify it |
74 | * under the terms of the GNU General Public License version 3, as published |
75 | @@ -18,17 +18,15 @@ |
76 | |
77 | #include <glib.h> |
78 | #include <glib-object.h> |
79 | -#include <timezonemap/tz.h> |
80 | |
81 | #include "LocalePlugin.h" |
82 | #include "timezonemodel.h" |
83 | |
84 | TimeZoneLocationModel::TimeZoneLocationModel(QObject *parent): |
85 | QAbstractListModel(parent), |
86 | - m_workerThread(new TimeZonePopulateWorker()) |
87 | + m_listUpdating(false), |
88 | + m_cancellable(nullptr) |
89 | { |
90 | - qRegisterMetaType<TzLocationWizard>(); |
91 | - |
92 | m_roleNames[Qt::DisplayRole] = "displayName"; |
93 | m_roleNames[TimeZoneRole] = "timeZone"; |
94 | m_roleNames[CityRole] = "city"; |
95 | @@ -36,78 +34,52 @@ |
96 | m_roleNames[OffsetRole] = "offset"; |
97 | m_roleNames[LatitudeRole] = "latitude"; |
98 | m_roleNames[LongitudeRole] = "longitude"; |
99 | - |
100 | - QObject::connect(m_workerThread, |
101 | - &TimeZonePopulateWorker::resultReady, |
102 | - this, |
103 | - &TimeZoneLocationModel::processModelResult); |
104 | - QObject::connect(m_workerThread, |
105 | - &TimeZonePopulateWorker::finished, |
106 | - this, |
107 | - &TimeZoneLocationModel::store); |
108 | - QObject::connect(m_workerThread, |
109 | - &TimeZonePopulateWorker::finished, |
110 | - m_workerThread, |
111 | - &QObject::deleteLater); |
112 | - |
113 | - init(); |
114 | -} |
115 | - |
116 | -void TimeZoneLocationModel::init() |
117 | -{ |
118 | - beginResetModel(); |
119 | - m_workerThread->start(); |
120 | -} |
121 | - |
122 | -void TimeZoneLocationModel::store() |
123 | -{ |
124 | - m_workerThread = nullptr; |
125 | - endResetModel(); |
126 | -} |
127 | - |
128 | -void TimeZoneLocationModel::processModelResult(const TzLocationWizard &location) |
129 | -{ |
130 | - m_locations.append(location); |
131 | } |
132 | |
133 | int TimeZoneLocationModel::rowCount(const QModelIndex &parent) const |
134 | { |
135 | - if (parent.isValid()) |
136 | + if (parent.isValid()) { |
137 | return 0; |
138 | - return m_locations.count(); |
139 | + } else if (m_filter.isEmpty()) { |
140 | + return m_countryLocations.count(); |
141 | + } else { |
142 | + return m_locations.count(); |
143 | + } |
144 | } |
145 | |
146 | QVariant TimeZoneLocationModel::data(const QModelIndex &index, int role) const |
147 | { |
148 | - if (index.row() >= m_locations.count() || index.row() < 0) |
149 | + GeonamesCity *city; |
150 | + if (m_filter.isEmpty()) { |
151 | + city = m_countryLocations.value(index.row()); |
152 | + } else { |
153 | + city = m_locations.value(index.row()); |
154 | + } |
155 | + if (!city) |
156 | return QVariant(); |
157 | |
158 | - const TzLocationWizard tz = m_locations.at(index.row()); |
159 | - |
160 | - const QString country(tz.full_country.isEmpty() ? tz.country : tz.full_country); |
161 | - |
162 | switch (role) { |
163 | case Qt::DisplayRole: |
164 | - if (!tz.state.isEmpty()) |
165 | - return QStringLiteral("%1, %2, %3").arg(tz.city).arg(tz.state).arg(country); |
166 | - else |
167 | - return QStringLiteral("%1, %2").arg(tz.city).arg(country); |
168 | + return QStringLiteral("%1, %2, %3").arg(geonames_city_get_name(city)) |
169 | + .arg(geonames_city_get_state(city)) |
170 | + .arg(geonames_city_get_country(city)); |
171 | case SimpleRole: |
172 | - return QStringLiteral("%1, %2").arg(tz.city).arg(country); |
173 | + return QStringLiteral("%1, %2").arg(geonames_city_get_name(city)) |
174 | + .arg(geonames_city_get_country(city)); |
175 | case TimeZoneRole: |
176 | - return tz.timezone; |
177 | + return geonames_city_get_timezone(city); |
178 | case CountryRole: |
179 | - return tz.country; |
180 | + return geonames_city_get_country(city); |
181 | case CityRole: |
182 | - return tz.city; |
183 | + return geonames_city_get_name(city); |
184 | case OffsetRole: { |
185 | - QTimeZone tmp(tz.timezone.toLatin1()); |
186 | + QTimeZone tmp(geonames_city_get_timezone(city)); |
187 | return static_cast<double>(tmp.standardTimeOffset(QDateTime::currentDateTime())) / 3600; |
188 | } |
189 | case LatitudeRole: |
190 | - return tz.latitude; |
191 | + return geonames_city_get_latitude(city); |
192 | case LongitudeRole: |
193 | - return tz.longitude; |
194 | + return geonames_city_get_longitude(city); |
195 | default: |
196 | qWarning() << Q_FUNC_INFO << "Unknown role"; |
197 | return QVariant(); |
198 | @@ -119,110 +91,149 @@ |
199 | return m_roleNames; |
200 | } |
201 | |
202 | -void TimeZonePopulateWorker::run() |
203 | -{ |
204 | - buildCityMap(); |
205 | -} |
206 | - |
207 | -void TimeZonePopulateWorker::buildCityMap() |
208 | -{ |
209 | - TzDB *tzdb = tz_load_db(); |
210 | - GPtrArray *tz_locations = tz_get_locations(tzdb); |
211 | - |
212 | - TimeZoneLocationModel::TzLocationWizard tmpTz; |
213 | - |
214 | - for (guint i = 0; i < tz_locations->len; ++i) { |
215 | - auto tmp = static_cast<CcTimezoneLocation *>(g_ptr_array_index(tz_locations, i)); |
216 | - gchar *en_name, *country, *zone, *state, *full_country; |
217 | - gdouble latitude; |
218 | - gdouble longitude; |
219 | - g_object_get (tmp, "en_name", &en_name, |
220 | - "country", &country, |
221 | - "zone", &zone, |
222 | - "state", &state, |
223 | - "full_country", &full_country, |
224 | - "latitude", &latitude, |
225 | - "longitude", &longitude, |
226 | - nullptr); |
227 | - // There are empty entries in the DB |
228 | - if (g_strcmp0(en_name, "") != 0) { |
229 | - tmpTz.city = en_name; |
230 | - tmpTz.country = country; |
231 | - tmpTz.timezone = zone; |
232 | - tmpTz.state = state; |
233 | - tmpTz.full_country = full_country; |
234 | - tmpTz.latitude = latitude; |
235 | - tmpTz.longitude = longitude; |
236 | - |
237 | - Q_EMIT (resultReady(tmpTz)); |
238 | - } |
239 | - g_free (en_name); |
240 | - g_free (country); |
241 | - g_free (zone); |
242 | - g_free (state); |
243 | - g_free (full_country); |
244 | - } |
245 | - |
246 | - g_ptr_array_free (tz_locations, TRUE); |
247 | - tz_db_free(tzdb); |
248 | -} |
249 | - |
250 | - |
251 | -TimeZoneFilterModel::TimeZoneFilterModel(QObject *parent) |
252 | - : QSortFilterProxyModel(parent) |
253 | -{ |
254 | - setDynamicSortFilter(false); |
255 | - setSortLocaleAware(true); |
256 | - setSortRole(TimeZoneLocationModel::CityRole); |
257 | - m_stringMatcher.setCaseSensitivity(Qt::CaseInsensitive); |
258 | - sort(0); |
259 | -} |
260 | - |
261 | -bool TimeZoneFilterModel::filterAcceptsRow(int row, const QModelIndex &parentIndex) const |
262 | -{ |
263 | - if (!sourceModel()) { |
264 | - return true; |
265 | - } |
266 | - |
267 | - if (!m_filter.isEmpty()) { // filtering by freeform text input, cf setFilter(QString) |
268 | - const QString city = sourceModel()->index(row, 0, parentIndex).data(TimeZoneLocationModel::CityRole).toString(); |
269 | - |
270 | - if (m_stringMatcher.indexIn(city) == 0) { // match at the beginning of the city name |
271 | - return true; |
272 | - } |
273 | - } else if (!m_country.isEmpty()) { // filter by country code |
274 | - const QString countryCode = sourceModel()->index(row, 0, parentIndex).data(TimeZoneLocationModel::CountryRole).toString(); |
275 | - return m_country.compare(countryCode, Qt::CaseInsensitive) == 0; |
276 | - } |
277 | - |
278 | - return false; |
279 | -} |
280 | - |
281 | -QString TimeZoneFilterModel::filter() const |
282 | +void TimeZoneLocationModel::setModel(const QList<GeonamesCity *> &locations) |
283 | +{ |
284 | + beginResetModel(); |
285 | + |
286 | + Q_FOREACH(GeonamesCity *city, m_locations) { |
287 | + geonames_city_free(city); |
288 | + } |
289 | + |
290 | + m_locations = locations; |
291 | + endResetModel(); |
292 | +} |
293 | + |
294 | +void TimeZoneLocationModel::filterFinished(GObject *source_object, |
295 | + GAsyncResult *res, |
296 | + gpointer user_data) |
297 | +{ |
298 | + Q_UNUSED(source_object); |
299 | + |
300 | + g_autofree gint *cities = nullptr; |
301 | + guint cities_len = 0; |
302 | + g_autoptr(GError) error = nullptr; |
303 | + |
304 | + cities = geonames_query_cities_finish(res, &cities_len, &error); |
305 | + if (error) { |
306 | + if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { |
307 | + TimeZoneLocationModel *model = static_cast<TimeZoneLocationModel *>(user_data); |
308 | + g_clear_object(&model->m_cancellable); |
309 | + model->setListUpdating(false); |
310 | + qWarning() << "Could not filter timezones:" << error->message; |
311 | + } |
312 | + return; |
313 | + } |
314 | + |
315 | + QList<GeonamesCity *> locations; |
316 | + |
317 | + for (guint i = 0; i < cities_len; ++i) { |
318 | + GeonamesCity *city = geonames_get_city(cities[i]); |
319 | + if (city) { |
320 | + locations.append(city); |
321 | + } |
322 | + } |
323 | + |
324 | + TimeZoneLocationModel *model = static_cast<TimeZoneLocationModel *>(user_data); |
325 | + |
326 | + g_clear_object(&model->m_cancellable); |
327 | + |
328 | + model->setModel(locations); |
329 | + model->setListUpdating(false); |
330 | +} |
331 | + |
332 | +bool TimeZoneLocationModel::listUpdating() const |
333 | +{ |
334 | + return m_listUpdating; |
335 | +} |
336 | + |
337 | +void TimeZoneLocationModel::setListUpdating(bool listUpdating) |
338 | +{ |
339 | + if (m_listUpdating != listUpdating) { |
340 | + m_listUpdating = listUpdating; |
341 | + Q_EMIT listUpdatingChanged(); |
342 | + } |
343 | +} |
344 | + |
345 | +QString TimeZoneLocationModel::filter() const |
346 | { |
347 | return m_filter; |
348 | } |
349 | |
350 | -void TimeZoneFilterModel::setFilter(const QString &filter) |
351 | +void TimeZoneLocationModel::setFilter(const QString &filter) |
352 | { |
353 | if (filter != m_filter) { |
354 | m_filter = filter; |
355 | - m_stringMatcher.setPattern(m_filter); |
356 | Q_EMIT filterChanged(); |
357 | - invalidate(); |
358 | - } |
359 | + } |
360 | + |
361 | + setListUpdating(true); |
362 | + |
363 | + if (m_cancellable) { |
364 | + g_cancellable_cancel(m_cancellable); |
365 | + g_clear_object(&m_cancellable); |
366 | + } |
367 | + |
368 | + setModel(QList<GeonamesCity *>()); |
369 | + |
370 | + if (filter.isEmpty()) { |
371 | + setListUpdating(false); |
372 | + return; |
373 | + } |
374 | + |
375 | + m_cancellable = g_cancellable_new(); |
376 | + geonames_query_cities(filter.toUtf8().data(), |
377 | + GEONAMES_QUERY_DEFAULT, |
378 | + m_cancellable, |
379 | + filterFinished, |
380 | + this); |
381 | } |
382 | |
383 | -QString TimeZoneFilterModel::country() const |
384 | +QString TimeZoneLocationModel::country() const |
385 | { |
386 | return m_country; |
387 | } |
388 | |
389 | -void TimeZoneFilterModel::setCountry(const QString &country) |
390 | +static bool citycmp(GeonamesCity *a, GeonamesCity *b) |
391 | +{ |
392 | + return geonames_city_get_population(b) < geonames_city_get_population(a); |
393 | +} |
394 | + |
395 | +void TimeZoneLocationModel::setCountry(const QString &country) |
396 | { |
397 | if (m_country == country) |
398 | return; |
399 | |
400 | m_country = country; |
401 | + |
402 | + Q_FOREACH(GeonamesCity *city, m_countryLocations) { |
403 | + geonames_city_free(city); |
404 | + } |
405 | + |
406 | + gint num_cities = geonames_get_n_cities(); |
407 | + for (gint i = 0; i < num_cities; i++) { |
408 | + GeonamesCity *city = geonames_get_city(i); |
409 | + if (city && m_country == geonames_city_get_country_code(city)) { |
410 | + m_countryLocations.append(city); |
411 | + } |
412 | + } |
413 | + |
414 | + std::sort(m_countryLocations.begin(), m_countryLocations.end(), citycmp); |
415 | + |
416 | Q_EMIT countryChanged(country); |
417 | } |
418 | + |
419 | +TimeZoneLocationModel::~TimeZoneLocationModel() |
420 | +{ |
421 | + if (m_cancellable) { |
422 | + g_cancellable_cancel(m_cancellable); |
423 | + g_clear_object(&m_cancellable); |
424 | + } |
425 | + |
426 | + Q_FOREACH(GeonamesCity *city, m_countryLocations) { |
427 | + geonames_city_free(city); |
428 | + } |
429 | + |
430 | + Q_FOREACH(GeonamesCity *city, m_locations) { |
431 | + geonames_city_free(city); |
432 | + } |
433 | +} |
434 | |
435 | === modified file 'plugins/Wizard/timezonemodel.h' |
436 | --- plugins/Wizard/timezonemodel.h 2016-02-16 13:10:24 +0000 |
437 | +++ plugins/Wizard/timezonemodel.h 2016-03-02 16:19:54 +0000 |
438 | @@ -1,5 +1,5 @@ |
439 | /* |
440 | - * Copyright (C) 2015 Canonical Ltd. |
441 | + * Copyright (C) 2016 Canonical Ltd. |
442 | * |
443 | * This program is free software: you can redistribute it and/or modify it |
444 | * under the terms of the GNU General Public License version 3, as published |
445 | @@ -17,21 +17,21 @@ |
446 | #ifndef TIMEZONEMODEL_H |
447 | #define TIMEZONEMODEL_H |
448 | |
449 | +#include <geonames.h> |
450 | +#include <glib.h> |
451 | #include <QAbstractListModel> |
452 | -#include <QSortFilterProxyModel> |
453 | -#include <QThread> |
454 | -#include <QtConcurrent> |
455 | -#include <QtGui/QImage> |
456 | - |
457 | -class TimeZonePopulateWorker; |
458 | |
459 | class TimeZoneLocationModel: public QAbstractListModel |
460 | { |
461 | Q_OBJECT |
462 | + Q_PROPERTY(bool listUpdating READ listUpdating NOTIFY listUpdatingChanged) |
463 | + Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged) |
464 | + Q_PROPERTY(QString country READ country WRITE setCountry NOTIFY countryChanged) |
465 | Q_ENUMS(Roles) |
466 | + |
467 | public: |
468 | explicit TimeZoneLocationModel(QObject *parent = nullptr); |
469 | - ~TimeZoneLocationModel() = default; |
470 | + ~TimeZoneLocationModel(); |
471 | |
472 | enum Roles { |
473 | TimeZoneRole = Qt::UserRole + 1, |
474 | @@ -43,56 +43,11 @@ |
475 | LongitudeRole |
476 | }; |
477 | |
478 | - struct TzLocationWizard { |
479 | - QString city; |
480 | - QString country; |
481 | - QString timezone; |
482 | - QString state; |
483 | - QString full_country; |
484 | - double latitude; |
485 | - double longitude; |
486 | - }; |
487 | - |
488 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
489 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; |
490 | QHash<int, QByteArray> roleNames() const override; |
491 | |
492 | -private Q_SLOTS: |
493 | - void processModelResult(const TzLocationWizard &location); |
494 | - void store(); |
495 | - |
496 | -private: |
497 | - void init(); |
498 | - QHash<int, QByteArray> m_roleNames; |
499 | - QList<TzLocationWizard> m_locations; |
500 | - TimeZonePopulateWorker *m_workerThread; |
501 | -}; |
502 | - |
503 | -Q_DECLARE_METATYPE (TimeZoneLocationModel::TzLocationWizard) |
504 | - |
505 | -class TimeZonePopulateWorker: public QThread |
506 | -{ |
507 | - Q_OBJECT |
508 | -public: |
509 | - void run() override; |
510 | - |
511 | -Q_SIGNALS: |
512 | - void resultReady(const TimeZoneLocationModel::TzLocationWizard &tz); |
513 | - |
514 | -private: |
515 | - void buildCityMap(); |
516 | -}; |
517 | - |
518 | -class TimeZoneFilterModel: public QSortFilterProxyModel |
519 | -{ |
520 | - Q_OBJECT |
521 | - Q_PROPERTY(QString filter READ filter WRITE setFilter NOTIFY filterChanged) |
522 | - Q_PROPERTY(QString country READ country WRITE setCountry NOTIFY countryChanged) |
523 | - |
524 | -public: |
525 | - explicit TimeZoneFilterModel(QObject *parent = nullptr); |
526 | - ~TimeZoneFilterModel() = default; |
527 | - bool filterAcceptsRow(int row, const QModelIndex &parentIndex) const override; |
528 | + bool listUpdating() const; |
529 | |
530 | QString filter() const; |
531 | void setFilter(const QString &filter); |
532 | @@ -101,13 +56,25 @@ |
533 | void setCountry(const QString &country); |
534 | |
535 | Q_SIGNALS: |
536 | + void listUpdatingChanged(); |
537 | void filterChanged(); |
538 | void countryChanged(const QString &country); |
539 | |
540 | private: |
541 | + void setModel(const QList<GeonamesCity *> &locations); |
542 | + void setListUpdating(bool listUpdating); |
543 | + static void filterFinished(GObject *source_object, |
544 | + GAsyncResult *res, |
545 | + gpointer user_data); |
546 | + |
547 | + |
548 | + bool m_listUpdating; |
549 | QString m_filter; |
550 | - QStringMatcher m_stringMatcher; |
551 | QString m_country; |
552 | + GCancellable *m_cancellable; |
553 | + QHash<int, QByteArray> m_roleNames; |
554 | + QList<GeonamesCity *> m_locations; |
555 | + QList<GeonamesCity *> m_countryLocations; |
556 | }; |
557 | |
558 | #endif |
559 | |
560 | === modified file 'qml/Wizard/Pages.qml' |
561 | --- qml/Wizard/Pages.qml 2016-02-18 14:05:12 +0000 |
562 | +++ qml/Wizard/Pages.qml 2016-03-02 16:19:54 +0000 |
563 | @@ -34,23 +34,12 @@ |
564 | property int passwordMethod: UbuntuSecurityPrivacyPanel.Passphrase |
565 | property string password: "" |
566 | |
567 | - property string countryCode: "US" // default country (for the timezone page) |
568 | property bool seenSIMPage: false // we want to see the SIM page at most once |
569 | |
570 | property alias modemManager: modemManager |
571 | property alias simManager0: simManager0 |
572 | property alias simManager1: simManager1 |
573 | |
574 | - TimeZoneModel { // preload the heavy models |
575 | - id: tzModel |
576 | - } |
577 | - |
578 | - TimeZoneFilterModel { |
579 | - id: tzFilterModel |
580 | - sourceModel: tzModel |
581 | - country: countryCode |
582 | - } |
583 | - |
584 | UbuntuSecurityPrivacyPanel { |
585 | id: securityPrivacy |
586 | objectName: "securityPrivacy" |
587 | |
588 | === modified file 'qml/Wizard/Pages/10-welcome.qml' |
589 | --- qml/Wizard/Pages/10-welcome.qml 2016-02-16 04:28:15 +0000 |
590 | +++ qml/Wizard/Pages/10-welcome.qml 2016-03-02 16:19:54 +0000 |
591 | @@ -155,7 +155,6 @@ |
592 | System.updateSessionLocale(plugin.languageCodes[plugin.currentLanguage]); |
593 | } |
594 | i18n.language = plugin.languageCodes[plugin.currentLanguage]; // re-notify of change after above call (for qlocale change) |
595 | - root.countryCode = plugin.languageCodes[plugin.currentLanguage].split('_')[1].split('.')[0]; // extract the country code, save it for the timezone page |
596 | |
597 | if (!root.modemManager.available || !root.modemManager.ready || root.modemManager.modems.length === 0 || |
598 | (root.simManager0.present && root.simManager0.ready) || (root.simManager1.present && root.simManager1.ready) || |
599 | |
600 | === modified file 'qml/Wizard/Pages/50-timezone.qml' |
601 | --- qml/Wizard/Pages/50-timezone.qml 2016-03-01 19:00:13 +0000 |
602 | +++ qml/Wizard/Pages/50-timezone.qml 2016-03-02 16:19:54 +0000 |
603 | @@ -87,8 +87,6 @@ |
604 | } |
605 | |
606 | resetViews(); |
607 | - tzFilterModel.filter = Qt.binding(function() { return searchField.text; }); |
608 | - tzFilterModel.invalidate(); |
609 | theme.palette.normal.backgroundText = "#cdcdcd"; |
610 | searchField.forceActiveFocus(); |
611 | } |
612 | @@ -192,9 +190,21 @@ |
613 | objectName: "tzList" |
614 | clip: true |
615 | currentIndex: -1 |
616 | - model: tzFilterModel |
617 | + model: TimeZoneModel { |
618 | + id: timeZoneModel |
619 | + filter: searchField.text |
620 | + country: i18n.language.split('_')[1].split('.')[0] |
621 | + } |
622 | delegate: tzComponent |
623 | } |
624 | + |
625 | + ActivityIndicator { |
626 | + anchors.centerIn: tzList |
627 | + running: tzList.count == 0 && |
628 | + searchField.length > 0 && |
629 | + timeZoneModel.listUpdating |
630 | + visible: running |
631 | + } |
632 | } |
633 | |
634 | Item { |
635 | |
636 | === modified file 'tests/mocks/Wizard/CMakeLists.txt' |
637 | --- tests/mocks/Wizard/CMakeLists.txt 2016-02-16 13:10:24 +0000 |
638 | +++ tests/mocks/Wizard/CMakeLists.txt 2016-03-02 16:19:54 +0000 |
639 | @@ -1,7 +1,5 @@ |
640 | -pkg_search_module(TIMEZONEMAP REQUIRED timezonemap) |
641 | - |
642 | include_directories( |
643 | - ${GLIB_INCLUDE_DIRS} ${TIMEZONEMAP_INCLUDE_DIRS} |
644 | + ${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS} |
645 | ${CMAKE_SOURCE_DIR}/plugins/Wizard |
646 | ) |
647 | |
648 | @@ -15,5 +13,5 @@ |
649 | ) |
650 | |
651 | qt5_use_modules(MockWizard-qml DBus Qml Concurrent) |
652 | -target_link_libraries(MockWizard-qml ${GLIB_LDFLAGS} ${TIMEZONEMAP_LDFLAGS}) |
653 | +target_link_libraries(MockWizard-qml ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS}) |
654 | add_unity8_mock(Wizard 0.1 Wizard TARGETS MockWizard-qml) |
655 | |
656 | === modified file 'tests/mocks/Wizard/mockplugin.cpp' |
657 | --- tests/mocks/Wizard/mockplugin.cpp 2016-02-16 13:10:24 +0000 |
658 | +++ tests/mocks/Wizard/mockplugin.cpp 2016-03-02 16:19:54 +0000 |
659 | @@ -30,6 +30,5 @@ |
660 | qmlRegisterSingletonType<MockSystem>(uri, 0, 1, "System", [](QQmlEngine*, QJSEngine*) -> QObject* { return new MockSystem; }); |
661 | qmlRegisterSingletonType<Status>(uri, 0, 1, "Status", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Status; }); |
662 | qmlRegisterType<TimeZoneLocationModel>(uri, 0, 1, "TimeZoneModel"); |
663 | - qmlRegisterType<TimeZoneFilterModel>(uri, 0, 1, "TimeZoneFilterModel"); |
664 | qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin"); |
665 | } |
Nice work, one remark tho - why did you remove the filter model? We need to filter on both at the same time.
Otherwise a few small comments inline