@@ -0,0 +1,194 @@
1+/*
2+ * Copyright (C) 2016 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QDebug>
18+
19+#include <glib.h>
20+#include <glib-object.h>
21+
22+#include "LocalePlugin.h"
23+#include "timezonemodel.h"
24+
25+TimeZoneLocationModel::TimeZoneLocationModel(QObject *parent):
26+ QAbstractListModel(parent),
27+ m_listUpdating(false),
28+ m_cancellable(nullptr)
29+{
30+ m_roleNames[Qt::DisplayRole] = "displayName";
31+ m_roleNames[TimeZoneRole] = "timeZone";
32+ m_roleNames[CityRole] = "city";
33+ m_roleNames[CountryRole] = "country";
34+ m_roleNames[OffsetRole] = "offset";
35+ m_roleNames[LatitudeRole] = "latitude";
36+ m_roleNames[LongitudeRole] = "longitude";
37+}
38+
39+int TimeZoneLocationModel::rowCount(const QModelIndex &parent) const
40+{
41+ if (parent.isValid())
42+ return 0;
43+ return m_locations.count();
44+}
45+
46+QVariant TimeZoneLocationModel::data(const QModelIndex &index, int role) const
47+{
48+ if (index.row() >= m_locations.count() || index.row() < 0)
49+ return QVariant();
50+
51+ GeonamesCity *city = m_locations[index.row()];
52+
53+ switch (role) {
54+ case Qt::DisplayRole:
55+ return QVariant(QString("%1, %2, %3").arg(geonames_city_get_name(city))
56+ .arg(geonames_city_get_state(city))
57+ .arg(geonames_city_get_country(city)));
58+ case SimpleRole:
59+ return QVariant(QString("%1, %2").arg(geonames_city_get_name(city))
60+ .arg(geonames_city_get_country(city)));
61+ case TimeZoneRole:
62+ return geonames_city_get_timezone(city);
63+ case CountryRole:
64+ return geonames_city_get_country(city);
65+ case CityRole:
66+ return geonames_city_get_name(city);
67+ case OffsetRole: {
68+ QTimeZone tmp(geonames_city_get_timezone(city));
69+ return static_cast<double>(tmp.standardTimeOffset(QDateTime::currentDateTime())) / 3600;
70+ }
71+ case LatitudeRole:
72+ return geonames_city_get_latitude(city);
73+ case LongitudeRole:
74+ return geonames_city_get_longitude(city);
75+ default:
76+ qWarning() << Q_FUNC_INFO << "Unknown role";
77+ return QVariant();
78+ }
79+}
80+
81+QHash<int, QByteArray> TimeZoneLocationModel::roleNames() const
82+{
83+ return m_roleNames;
84+}
85+
86+void TimeZoneLocationModel::filterFinished(GObject *source_object,
87+ GAsyncResult *res,
88+ gpointer user_data)
89+{
90+ Q_UNUSED(source_object);
91+
92+ g_autofree gint *cities = nullptr;
93+ guint cities_len = 0;
94+ g_autoptr(GError) error = nullptr;
95+
96+ cities = geonames_query_cities_finish(res, &cities_len, &error);
97+ if (error) {
98+ if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
99+ TimeZoneLocationModel *model = static_cast<TimeZoneLocationModel *>(user_data);
100+ g_clear_object(&model->m_cancellable);
101+ qWarning() << "Could not filter timezones:" << error->message;
102+ }
103+ return;
104+ }
105+
106+ QList<GeonamesCity *> locations;
107+
108+ for (guint i = 0; i < cities_len; ++i) {
109+ GeonamesCity *city = geonames_get_city(cities[i]);
110+ if (city) {
111+ locations.append(city);
112+ }
113+ }
114+
115+ TimeZoneLocationModel *model = static_cast<TimeZoneLocationModel *>(user_data);
116+
117+ g_clear_object(&model->m_cancellable);
118+
119+ model->setModel(locations);
120+ model->setListUpdating(false);
121+}
122+
123+bool TimeZoneLocationModel::listUpdating() const
124+{
125+ return m_listUpdating;
126+}
127+
128+void TimeZoneLocationModel::setListUpdating(bool listUpdating)
129+{
130+ if (m_listUpdating != listUpdating) {
131+ m_listUpdating = listUpdating;
132+ Q_EMIT listUpdatingChanged();
133+ }
134+}
135+
136+QString TimeZoneLocationModel::filter() const
137+{
138+ return m_filter;
139+}
140+
141+void TimeZoneLocationModel::setFilter(const QString &filter)
142+{
143+ if (filter != m_filter) {
144+ m_filter = filter;
145+ Q_EMIT filterChanged();
146+ }
147+
148+ setListUpdating(true);
149+
150+ if (m_cancellable) {
151+ g_cancellable_cancel(m_cancellable);
152+ g_clear_object(&m_cancellable);
153+ }
154+
155+ setModel(QList<GeonamesCity *>());
156+
157+ if (filter.isEmpty()) {
158+ setListUpdating(false);
159+ return;
160+ }
161+
162+ m_cancellable = g_cancellable_new();
163+ geonames_query_cities(filter.toUtf8().data(),
164+ GEONAMES_QUERY_DEFAULT,
165+ m_cancellable,
166+ filterFinished,
167+ this);
168+}
169+
170+QString TimeZoneLocationModel::country() const
171+{
172+ return m_country;
173+}
174+
175+void TimeZoneLocationModel::setCountry(const QString &country)
176+{
177+ if (m_country == country)
178+ return;
179+
180+ m_country = country;
181+ Q_EMIT countryChanged(country);
182+}
183+
184+TimeZoneLocationModel::~TimeZoneLocationModel()
185+{
186+ if (m_cancellable) {
187+ g_cancellable_cancel(m_cancellable);
188+ g_clear_object(&m_cancellable);
189+ }
190+
191+ Q_FOREACH(GeonamesCity *city, m_locations) {
192+ geonames_city_free(city);
193+ }
194+}