2022-03-05 22:41:29 +05:00

236 lines
6.9 KiB
C++

/*
SPDX-FileCopyrightText: 2014 Kai Uwe Broulik <kde@privat.broulik.de>
SPDX-FileCopyrightText: 2014 Martin Klapetek <mklapetek@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "timezonemodel.h"
#include "timezonesi18n.h"
#include <KLocalizedString>
#include <QStringMatcher>
#include <QTimeZone>
TimeZoneFilterProxy::TimeZoneFilterProxy(QObject *parent)
: QSortFilterProxyModel(parent)
{
m_stringMatcher.setCaseSensitivity(Qt::CaseInsensitive);
}
bool TimeZoneFilterProxy::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (!sourceModel() || (m_filterString.isEmpty() && !m_onlyShowChecked)) {
return true;
}
const bool checked = sourceModel()->index(source_row, 0, source_parent).data(TimeZoneModel::CheckedRole).toBool();
if (m_onlyShowChecked && !checked) {
return false;
}
const QString city = sourceModel()->index(source_row, 0, source_parent).data(TimeZoneModel::CityRole).toString();
const QString region = sourceModel()->index(source_row, 0, source_parent).data(TimeZoneModel::RegionRole).toString();
const QString comment = sourceModel()->index(source_row, 0, source_parent).data(TimeZoneModel::CommentRole).toString();
if (m_stringMatcher.indexIn(city) != -1 || m_stringMatcher.indexIn(region) != -1 || m_stringMatcher.indexIn(comment) != -1) {
return true;
}
return false;
}
void TimeZoneFilterProxy::setFilterString(const QString &filterString)
{
m_filterString = filterString;
m_stringMatcher.setPattern(filterString);
Q_EMIT filterStringChanged();
invalidateFilter();
}
void TimeZoneFilterProxy::setOnlyShowChecked(const bool show)
{
if (m_onlyShowChecked == show) {
return;
}
m_onlyShowChecked = show;
Q_EMIT onlyShowCheckedChanged();
}
//=============================================================================
TimeZoneModel::TimeZoneModel(QObject *parent)
: QAbstractListModel(parent)
, m_timezonesI18n(new TimezonesI18n(this))
{
update();
}
TimeZoneModel::~TimeZoneModel()
{
}
int TimeZoneModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return m_data.count();
}
QVariant TimeZoneModel::data(const QModelIndex &index, int role) const
{
if (index.isValid()) {
TimeZoneData currentData = m_data.at(index.row());
switch (role) {
case TimeZoneIdRole:
return currentData.id;
case RegionRole:
return currentData.region;
case CityRole:
return currentData.city;
case CommentRole:
return currentData.comment;
case CheckedRole:
return currentData.checked;
case IsLocalTimeZoneRole:
return currentData.isLocalTimeZone;
}
}
return QVariant();
}
bool TimeZoneModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() || value.isNull()) {
return false;
}
if (role == CheckedRole) {
m_data[index.row()].checked = value.toBool();
Q_EMIT dataChanged(index, index);
if (m_data[index.row()].checked) {
m_selectedTimeZones.append(m_data[index.row()].id);
m_offsetData.insert(m_data[index.row()].id, m_data[index.row()].offsetFromUtc);
} else {
m_selectedTimeZones.removeAll(m_data[index.row()].id);
m_offsetData.remove(m_data[index.row()].id);
}
sortTimeZones();
Q_EMIT selectedTimeZonesChanged();
return true;
}
return false;
}
void TimeZoneModel::update()
{
beginResetModel();
m_data.clear();
QTimeZone localZone = QTimeZone(QTimeZone::systemTimeZoneId());
const QStringList data = QString::fromUtf8(localZone.id()).split(QLatin1Char('/'));
TimeZoneData local;
local.isLocalTimeZone = true;
local.id = QStringLiteral("Local");
local.region = i18nc("This means \"Local Timezone\"", "Local");
local.city = m_timezonesI18n->i18nCity(data.last());
local.comment = i18n("System's local time zone");
local.checked = false;
m_data.append(local);
QStringList cities;
QHash<QString, QTimeZone> zonesByCity;
const QList<QByteArray> systemTimeZones = QTimeZone::availableTimeZoneIds();
for (auto it = systemTimeZones.constBegin(); it != systemTimeZones.constEnd(); ++it) {
const QTimeZone zone(*it);
const QStringList splitted = QString::fromUtf8(zone.id()).split(QStringLiteral("/"));
// CITY | COUNTRY | CONTINENT
const QString key = QStringLiteral("%1|%2|%3").arg(splitted.last(), QLocale::countryToString(zone.country()), splitted.first());
cities.append(key);
zonesByCity.insert(key, zone);
}
cities.sort(Qt::CaseInsensitive);
for (const QString &key : qAsConst(cities)) {
const QTimeZone timeZone = zonesByCity.value(key);
QString comment = timeZone.comment();
if (!comment.isEmpty()) {
comment = i18n(comment.toUtf8());
}
const QStringList cityCountryContinent = key.split(QLatin1Char('|'));
TimeZoneData newData;
newData.isLocalTimeZone = false;
newData.id = timeZone.id();
newData.region = timeZone.country() == QLocale::AnyCountry
? QString()
: m_timezonesI18n->i18nContinents(cityCountryContinent.at(2)) + QLatin1Char('/') + m_timezonesI18n->i18nCountry(timeZone.country());
newData.city = m_timezonesI18n->i18nCity(cityCountryContinent.at(0));
newData.comment = comment;
newData.checked = false;
newData.offsetFromUtc = timeZone.offsetFromUtc(QDateTime::currentDateTimeUtc());
m_data.append(newData);
}
endResetModel();
}
void TimeZoneModel::setSelectedTimeZones(const QStringList &selectedTimeZones)
{
m_selectedTimeZones = selectedTimeZones;
for (int i = 0; i < m_data.size(); i++) {
if (m_selectedTimeZones.contains(m_data.at(i).id)) {
m_data[i].checked = true;
m_offsetData.insert(m_data[i].id, m_data[i].offsetFromUtc);
QModelIndex index = createIndex(i, 0);
Q_EMIT dataChanged(index, index);
}
}
sortTimeZones();
}
void TimeZoneModel::selectLocalTimeZone()
{
m_data[0].checked = true;
QModelIndex index = createIndex(0, 0);
Q_EMIT dataChanged(index, index);
m_selectedTimeZones << m_data[0].id;
Q_EMIT selectedTimeZonesChanged();
}
QHash<int, QByteArray> TimeZoneModel::roleNames() const
{
return QHash<int, QByteArray>({
{TimeZoneIdRole, "timeZoneId"},
{RegionRole, "region"},
{CityRole, "city"},
{CommentRole, "comment"},
{CheckedRole, "checked"},
{IsLocalTimeZoneRole, "isLocalTimeZone"},
});
}
void TimeZoneModel::sortTimeZones()
{
std::sort(m_selectedTimeZones.begin(), m_selectedTimeZones.end(), [this](const QString &a, const QString &b) {
return m_offsetData.value(a) < m_offsetData.value(b);
});
}