Lomiri
Loading...
Searching...
No Matches
timezonemodel.cpp
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
25TimeZoneLocationModel::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
39int TimeZoneLocationModel::rowCount(const QModelIndex &parent) const
40{
41 if (parent.isValid()) {
42 return 0;
43 } else if (m_filter.isEmpty()) {
44 return m_countryLocations.count();
45 } else {
46 return m_locations.count();
47 }
48}
49
50QVariant TimeZoneLocationModel::data(const QModelIndex &index, int role) const
51{
52 GeonamesCity *city;
53 if (m_filter.isEmpty()) {
54 city = m_countryLocations.value(index.row());
55 } else {
56 city = m_locations.value(index.row());
57 }
58 if (!city)
59 return QVariant();
60
61 switch (role) {
62 case Qt::DisplayRole:
63 return QStringLiteral("%1, %2, %3").arg(geonames_city_get_name(city),
64 geonames_city_get_state(city),
65 geonames_city_get_country(city));
66 case SimpleRole:
67 return QStringLiteral("%1, %2").arg(geonames_city_get_name(city),
68 geonames_city_get_country(city));
69 case TimeZoneRole:
70 return geonames_city_get_timezone(city);
71 case CountryRole:
72 return geonames_city_get_country(city);
73 case CityRole:
74 return geonames_city_get_name(city);
75 case OffsetRole: {
76 QTimeZone tmp(geonames_city_get_timezone(city));
77 return static_cast<double>(tmp.standardTimeOffset(QDateTime::currentDateTime())) / 3600;
78 }
79 case LatitudeRole:
80 return geonames_city_get_latitude(city);
81 case LongitudeRole:
82 return geonames_city_get_longitude(city);
83 default:
84 qWarning() << Q_FUNC_INFO << "Unknown role";
85 return QVariant();
86 }
87}
88
89QHash<int, QByteArray> TimeZoneLocationModel::roleNames() const
90{
91 return m_roleNames;
92}
93
94void TimeZoneLocationModel::setModel(const QList<GeonamesCity *> &locations)
95{
96 beginResetModel();
97
98 Q_FOREACH(GeonamesCity *city, m_locations) {
99 geonames_city_free(city);
100 }
101
102 m_locations = locations;
103 endResetModel();
104}
105
106void TimeZoneLocationModel::filterFinished(GObject *source_object,
107 GAsyncResult *res,
108 gpointer user_data)
109{
110 Q_UNUSED(source_object);
111
112 g_autofree gint *cities = nullptr;
113 guint cities_len = 0;
114 g_autoptr(GError) error = nullptr;
115
116 cities = geonames_query_cities_finish(res, &cities_len, &error);
117 if (error) {
118 if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
119 TimeZoneLocationModel *model = static_cast<TimeZoneLocationModel *>(user_data);
120 g_clear_object(&model->m_cancellable);
121 model->setListUpdating(false);
122 qWarning() << "Could not filter timezones:" << error->message;
123 }
124 return;
125 }
126
127 QList<GeonamesCity *> locations;
128
129 for (guint i = 0; i < cities_len; ++i) {
130 GeonamesCity *city = geonames_get_city(cities[i]);
131 if (city) {
132 locations.append(city);
133 }
134 }
135
136 TimeZoneLocationModel *model = static_cast<TimeZoneLocationModel *>(user_data);
137
138 g_clear_object(&model->m_cancellable);
139
140 model->setModel(locations);
141 model->setListUpdating(false);
142}
143
144bool TimeZoneLocationModel::listUpdating() const
145{
146 return m_listUpdating;
147}
148
149void TimeZoneLocationModel::setListUpdating(bool listUpdating)
150{
151 if (m_listUpdating != listUpdating) {
152 m_listUpdating = listUpdating;
153 Q_EMIT listUpdatingChanged();
154 }
155}
156
157QString TimeZoneLocationModel::filter() const
158{
159 return m_filter;
160}
161
162void TimeZoneLocationModel::setFilter(const QString &filter)
163{
164 if (filter != m_filter) {
165 m_filter = filter;
166 Q_EMIT filterChanged();
167 }
168
169 setListUpdating(true);
170
171 if (m_cancellable) {
172 g_cancellable_cancel(m_cancellable);
173 g_clear_object(&m_cancellable);
174 }
175
176 setModel(QList<GeonamesCity *>());
177
178 if (filter.isEmpty()) {
179 setListUpdating(false);
180 return;
181 }
182
183 m_cancellable = g_cancellable_new();
184 geonames_query_cities(filter.toUtf8().data(),
185 GEONAMES_QUERY_DEFAULT,
186 m_cancellable,
187 filterFinished,
188 this);
189}
190
191QString TimeZoneLocationModel::country() const
192{
193 return m_country;
194}
195
196static bool citycmp(GeonamesCity *a, GeonamesCity *b)
197{
198 return geonames_city_get_population(b) < geonames_city_get_population(a);
199}
200
201void TimeZoneLocationModel::setCountry(const QString &country)
202{
203 if (m_country == country)
204 return;
205
206 beginResetModel();
207
208 m_country = country;
209
210 Q_FOREACH(GeonamesCity *city, m_countryLocations) {
211 geonames_city_free(city);
212 }
213 m_countryLocations.clear();
214
215 gint num_cities = geonames_get_n_cities();
216 for (gint i = 0; i < num_cities; i++) {
217 GeonamesCity *city = geonames_get_city(i);
218 if (city && m_country == geonames_city_get_country_code(city)) {
219 m_countryLocations.append(city);
220 }
221 }
222
223 std::sort(m_countryLocations.begin(), m_countryLocations.end(), citycmp);
224
225 endResetModel();
226
227 Q_EMIT countryChanged(country);
228}
229
230TimeZoneLocationModel::~TimeZoneLocationModel()
231{
232 if (m_cancellable) {
233 g_cancellable_cancel(m_cancellable);
234 g_clear_object(&m_cancellable);
235 }
236
237 Q_FOREACH(GeonamesCity *city, m_countryLocations) {
238 geonames_city_free(city);
239 }
240
241 Q_FOREACH(GeonamesCity *city, m_locations) {
242 geonames_city_free(city);
243 }
244}