34
36
m_roleNames[OffsetRole] = "offset";
35
37
m_roleNames[LatitudeRole] = "latitude";
36
38
m_roleNames[LongitudeRole] = "longitude";
40
QObject::connect(m_workerThread,
41
&TimeZonePopulateWorker::resultReady,
43
&TimeZoneLocationModel::processModelResult);
44
QObject::connect(m_workerThread,
45
&TimeZonePopulateWorker::finished,
47
&TimeZoneLocationModel::store);
48
QObject::connect(m_workerThread,
49
&TimeZonePopulateWorker::finished,
51
&QObject::deleteLater);
56
void TimeZoneLocationModel::init()
59
m_workerThread->start();
62
void TimeZoneLocationModel::store()
64
m_workerThread = nullptr;
68
void TimeZoneLocationModel::processModelResult(const TzLocationWizard &location)
70
m_locations.append(location);
39
73
int TimeZoneLocationModel::rowCount(const QModelIndex &parent) const
41
if (parent.isValid()) {
43
} else if (m_filter.isEmpty()) {
44
return m_countryLocations.count();
46
return m_locations.count();
77
return m_locations.count();
50
80
QVariant TimeZoneLocationModel::data(const QModelIndex &index, int role) const
53
if (m_filter.isEmpty()) {
54
city = m_countryLocations.value(index.row());
56
city = m_locations.value(index.row());
82
if (index.row() >= m_locations.count() || index.row() < 0)
85
const TzLocationWizard tz = m_locations.at(index.row());
87
const QString country(tz.full_country.isEmpty() ? tz.country : tz.full_country);
62
90
case Qt::DisplayRole:
63
return QStringLiteral("%1, %2, %3").arg(geonames_city_get_name(city))
64
.arg(geonames_city_get_state(city))
65
.arg(geonames_city_get_country(city));
91
if (!tz.state.isEmpty())
92
return QStringLiteral("%1, %2, %3").arg(tz.city).arg(tz.state).arg(country);
94
return QStringLiteral("%1, %2").arg(tz.city).arg(country);
67
return QStringLiteral("%1, %2").arg(geonames_city_get_name(city))
68
.arg(geonames_city_get_country(city));
96
return QStringLiteral("%1, %2").arg(tz.city).arg(country);
70
return geonames_city_get_timezone(city);
72
return geonames_city_get_country(city);
74
return geonames_city_get_name(city);
75
103
case OffsetRole: {
76
QTimeZone tmp(geonames_city_get_timezone(city));
104
QTimeZone tmp(tz.timezone.toLatin1());
77
105
return static_cast<double>(tmp.standardTimeOffset(QDateTime::currentDateTime())) / 3600;
79
107
case LatitudeRole:
80
return geonames_city_get_latitude(city);
81
109
case LongitudeRole:
82
return geonames_city_get_longitude(city);
84
112
qWarning() << Q_FUNC_INFO << "Unknown role";
85
113
return QVariant();
91
119
return m_roleNames;
94
void TimeZoneLocationModel::setModel(const QList<GeonamesCity *> &locations)
98
Q_FOREACH(GeonamesCity *city, m_locations) {
99
geonames_city_free(city);
102
m_locations = locations;
106
void TimeZoneLocationModel::filterFinished(GObject *source_object,
110
Q_UNUSED(source_object);
112
g_autofree gint *cities = nullptr;
113
guint cities_len = 0;
114
g_autoptr(GError) error = nullptr;
116
cities = geonames_query_cities_finish(res, &cities_len, &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;
127
QList<GeonamesCity *> locations;
129
for (guint i = 0; i < cities_len; ++i) {
130
GeonamesCity *city = geonames_get_city(cities[i]);
132
locations.append(city);
136
TimeZoneLocationModel *model = static_cast<TimeZoneLocationModel *>(user_data);
138
g_clear_object(&model->m_cancellable);
140
model->setModel(locations);
141
model->setListUpdating(false);
144
bool TimeZoneLocationModel::listUpdating() const
146
return m_listUpdating;
149
void TimeZoneLocationModel::setListUpdating(bool listUpdating)
151
if (m_listUpdating != listUpdating) {
152
m_listUpdating = listUpdating;
153
Q_EMIT listUpdatingChanged();
157
QString TimeZoneLocationModel::filter() const
122
void TimeZonePopulateWorker::run()
127
void TimeZonePopulateWorker::buildCityMap()
129
TzDB *tzdb = tz_load_db();
130
GPtrArray *tz_locations = tz_get_locations(tzdb);
132
TimeZoneLocationModel::TzLocationWizard tmpTz;
134
for (guint i = 0; i < tz_locations->len; ++i) {
135
auto tmp = static_cast<CcTimezoneLocation *>(g_ptr_array_index(tz_locations, i));
136
gchar *en_name, *country, *zone, *state, *full_country;
139
g_object_get (tmp, "en_name", &en_name,
143
"full_country", &full_country,
144
"latitude", &latitude,
145
"longitude", &longitude,
147
// There are empty entries in the DB
148
if (g_strcmp0(en_name, "") != 0) {
149
tmpTz.city = en_name;
150
tmpTz.country = country;
151
tmpTz.timezone = zone;
153
tmpTz.full_country = full_country;
154
tmpTz.latitude = latitude;
155
tmpTz.longitude = longitude;
157
Q_EMIT (resultReady(tmpTz));
163
g_free (full_country);
166
g_ptr_array_free (tz_locations, TRUE);
171
TimeZoneFilterModel::TimeZoneFilterModel(QObject *parent)
172
: QSortFilterProxyModel(parent)
174
setDynamicSortFilter(false);
175
setSortLocaleAware(true);
176
setSortRole(TimeZoneLocationModel::CityRole);
177
m_stringMatcher.setCaseSensitivity(Qt::CaseInsensitive);
181
bool TimeZoneFilterModel::filterAcceptsRow(int row, const QModelIndex &parentIndex) const
183
if (!sourceModel()) {
187
if (!m_filter.isEmpty()) { // filtering by freeform text input, cf setFilter(QString)
188
const QString city = sourceModel()->index(row, 0, parentIndex).data(TimeZoneLocationModel::CityRole).toString();
190
if (m_stringMatcher.indexIn(city) == 0) { // match at the beginning of the city name
193
} else if (!m_country.isEmpty()) { // filter by country code
194
const QString countryCode = sourceModel()->index(row, 0, parentIndex).data(TimeZoneLocationModel::CountryRole).toString();
195
return m_country.compare(countryCode, Qt::CaseInsensitive) == 0;
201
QString TimeZoneFilterModel::filter() const
162
void TimeZoneLocationModel::setFilter(const QString &filter)
206
void TimeZoneFilterModel::setFilter(const QString &filter)
164
208
if (filter != m_filter) {
165
209
m_filter = filter;
210
m_stringMatcher.setPattern(m_filter);
166
211
Q_EMIT filterChanged();
169
setListUpdating(true);
172
g_cancellable_cancel(m_cancellable);
173
g_clear_object(&m_cancellable);
176
setModel(QList<GeonamesCity *>());
178
if (filter.isEmpty()) {
179
setListUpdating(false);
183
m_cancellable = g_cancellable_new();
184
geonames_query_cities(filter.toUtf8().data(),
185
GEONAMES_QUERY_DEFAULT,
191
QString TimeZoneLocationModel::country() const
216
QString TimeZoneFilterModel::country() const
193
218
return m_country;
196
static bool citycmp(GeonamesCity *a, GeonamesCity *b)
198
return geonames_city_get_population(b) < geonames_city_get_population(a);
201
void TimeZoneLocationModel::setCountry(const QString &country)
221
void TimeZoneFilterModel::setCountry(const QString &country)
203
223
if (m_country == country)
208
226
m_country = country;
210
Q_FOREACH(GeonamesCity *city, m_countryLocations) {
211
geonames_city_free(city);
213
m_countryLocations.clear();
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);
223
std::sort(m_countryLocations.begin(), m_countryLocations.end(), citycmp);
227
227
Q_EMIT countryChanged(country);
230
TimeZoneLocationModel::~TimeZoneLocationModel()
233
g_cancellable_cancel(m_cancellable);
234
g_clear_object(&m_cancellable);
237
Q_FOREACH(GeonamesCity *city, m_countryLocations) {
238
geonames_city_free(city);
241
Q_FOREACH(GeonamesCity *city, m_locations) {
242
geonames_city_free(city);