/* * Copyright (C) 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include #include #include #include "LocalePlugin.h" #include "timezonemodel.h" TimeZoneLocationModel::TimeZoneLocationModel(QObject *parent): QAbstractListModel(parent), m_listUpdating(false), m_cancellable(nullptr) { m_roleNames[Qt::DisplayRole] = "displayName"; m_roleNames[TimeZoneRole] = "timeZone"; m_roleNames[CityRole] = "city"; m_roleNames[CountryRole] = "country"; m_roleNames[OffsetRole] = "offset"; m_roleNames[LatitudeRole] = "latitude"; m_roleNames[LongitudeRole] = "longitude"; } int TimeZoneLocationModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } else if (m_filter.isEmpty()) { return m_countryLocations.count(); } else { return m_locations.count(); } } QVariant TimeZoneLocationModel::data(const QModelIndex &index, int role) const { GeonamesCity *city; if (m_filter.isEmpty()) { city = m_countryLocations.value(index.row()); } else { city = m_locations.value(index.row()); } if (!city) return QVariant(); switch (role) { case Qt::DisplayRole: return QStringLiteral("%1, %2, %3").arg(geonames_city_get_name(city), geonames_city_get_state(city), geonames_city_get_country(city)); case SimpleRole: return QStringLiteral("%1, %2").arg(geonames_city_get_name(city), geonames_city_get_country(city)); case TimeZoneRole: return geonames_city_get_timezone(city); case CountryRole: return geonames_city_get_country(city); case CityRole: return geonames_city_get_name(city); case OffsetRole: { QTimeZone tmp(geonames_city_get_timezone(city)); return static_cast(tmp.standardTimeOffset(QDateTime::currentDateTime())) / 3600; } case LatitudeRole: return geonames_city_get_latitude(city); case LongitudeRole: return geonames_city_get_longitude(city); default: qWarning() << Q_FUNC_INFO << "Unknown role"; return QVariant(); } } QHash TimeZoneLocationModel::roleNames() const { return m_roleNames; } void TimeZoneLocationModel::setModel(const QList &locations) { beginResetModel(); Q_FOREACH(GeonamesCity *city, m_locations) { geonames_city_free(city); } m_locations = locations; endResetModel(); } void TimeZoneLocationModel::filterFinished(GObject *source_object, GAsyncResult *res, gpointer user_data) { Q_UNUSED(source_object); g_autofree gint *cities = nullptr; guint cities_len = 0; g_autoptr(GError) error = nullptr; cities = geonames_query_cities_finish(res, &cities_len, &error); if (error) { if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { TimeZoneLocationModel *model = static_cast(user_data); g_clear_object(&model->m_cancellable); model->setListUpdating(false); qWarning() << "Could not filter timezones:" << error->message; } return; } QList locations; for (guint i = 0; i < cities_len; ++i) { GeonamesCity *city = geonames_get_city(cities[i]); if (city) { locations.append(city); } } TimeZoneLocationModel *model = static_cast(user_data); g_clear_object(&model->m_cancellable); model->setModel(locations); model->setListUpdating(false); } bool TimeZoneLocationModel::listUpdating() const { return m_listUpdating; } void TimeZoneLocationModel::setListUpdating(bool listUpdating) { if (m_listUpdating != listUpdating) { m_listUpdating = listUpdating; Q_EMIT listUpdatingChanged(); } } QString TimeZoneLocationModel::filter() const { return m_filter; } void TimeZoneLocationModel::setFilter(const QString &filter) { if (filter != m_filter) { m_filter = filter; Q_EMIT filterChanged(); } setListUpdating(true); if (m_cancellable) { g_cancellable_cancel(m_cancellable); g_clear_object(&m_cancellable); } setModel(QList()); if (filter.isEmpty()) { setListUpdating(false); return; } m_cancellable = g_cancellable_new(); geonames_query_cities(filter.toUtf8().data(), GEONAMES_QUERY_DEFAULT, m_cancellable, filterFinished, this); } QString TimeZoneLocationModel::country() const { return m_country; } static bool citycmp(GeonamesCity *a, GeonamesCity *b) { return geonames_city_get_population(b) < geonames_city_get_population(a); } void TimeZoneLocationModel::setCountry(const QString &country) { if (m_country == country) return; beginResetModel(); m_country = country; Q_FOREACH(GeonamesCity *city, m_countryLocations) { geonames_city_free(city); } m_countryLocations.clear(); gint num_cities = geonames_get_n_cities(); for (gint i = 0; i < num_cities; i++) { GeonamesCity *city = geonames_get_city(i); if (city && m_country == geonames_city_get_country_code(city)) { m_countryLocations.append(city); } } std::sort(m_countryLocations.begin(), m_countryLocations.end(), citycmp); endResetModel(); Q_EMIT countryChanged(country); } TimeZoneLocationModel::~TimeZoneLocationModel() { if (m_cancellable) { g_cancellable_cancel(m_cancellable); g_clear_object(&m_cancellable); } Q_FOREACH(GeonamesCity *city, m_countryLocations) { geonames_city_free(city); } Q_FOREACH(GeonamesCity *city, m_locations) { geonames_city_free(city); } }