File indexing completed on 2024-05-05 05:36:41
0001 /* 0002 SPDX-FileCopyrightText: 2014 Kai Uwe Broulik <kde@privat.broulik.de> 0003 SPDX-FileCopyrightText: 2014 Martin Klapetek <mklapetek@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "timezonemodel.h" 0009 #include "timezonesi18n.h" 0010 0011 #include <KLocalizedString> 0012 #include <QStringMatcher> 0013 #include <QTimeZone> 0014 0015 TimeZoneFilterProxy::TimeZoneFilterProxy(QObject *parent) 0016 : QSortFilterProxyModel(parent) 0017 { 0018 m_stringMatcher.setCaseSensitivity(Qt::CaseInsensitive); 0019 } 0020 0021 bool TimeZoneFilterProxy::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const 0022 { 0023 if (!sourceModel() || m_filterString.isEmpty()) { 0024 return true; 0025 } 0026 0027 const QString city = sourceModel()->index(source_row, 0, source_parent).data(TimeZoneModel::CityRole).toString(); 0028 const QString region = sourceModel()->index(source_row, 0, source_parent).data(TimeZoneModel::RegionRole).toString(); 0029 const QString comment = sourceModel()->index(source_row, 0, source_parent).data(TimeZoneModel::CommentRole).toString(); 0030 0031 if (m_stringMatcher.indexIn(city) != -1 || m_stringMatcher.indexIn(region) != -1 || m_stringMatcher.indexIn(comment) != -1) { 0032 return true; 0033 } 0034 0035 return false; 0036 } 0037 0038 void TimeZoneFilterProxy::setFilterString(const QString &filterString) 0039 { 0040 m_filterString = filterString; 0041 m_stringMatcher.setPattern(filterString); 0042 emit filterStringChanged(); 0043 invalidateFilter(); 0044 } 0045 0046 //============================================================================= 0047 0048 TimeZoneModel::TimeZoneModel(QObject *parent) 0049 : QAbstractListModel(parent) 0050 , m_timezonesI18n(new TimezonesI18n(this)) 0051 { 0052 update(); 0053 } 0054 0055 TimeZoneModel::~TimeZoneModel() 0056 { 0057 } 0058 0059 int TimeZoneModel::rowCount(const QModelIndex &parent) const 0060 { 0061 return parent.isValid() ? 0 : m_data.count(); 0062 } 0063 0064 QVariant TimeZoneModel::data(const QModelIndex &index, int role) const 0065 { 0066 Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)); 0067 0068 const TimeZoneData ¤tData = m_data.at(index.row()); 0069 0070 switch (role) { 0071 case TimeZoneIdRole: 0072 return currentData.id; 0073 case RegionRole: { 0074 return currentData.region; 0075 case CityRole: 0076 if (currentData.city.isEmpty()) 0077 return currentData.id; 0078 } 0079 return currentData.city; 0080 case CommentRole: 0081 return currentData.comment; 0082 case CheckedRole: 0083 return currentData.checked; 0084 } 0085 0086 return {}; 0087 } 0088 0089 bool TimeZoneModel::setData(const QModelIndex &index, const QVariant &value, int role) 0090 { 0091 if (!index.isValid() || value.isNull()) { 0092 return false; 0093 } 0094 0095 if (role == CheckedRole) { 0096 m_data[index.row()].checked = value.toBool(); 0097 emit dataChanged(index, index); 0098 0099 if (m_data[index.row()].checked) { 0100 m_selectedTimeZones.append(m_data[index.row()].id); 0101 m_offsetData.insert(m_data[index.row()].id, m_data[index.row()].offsetFromUtc); 0102 } else { 0103 m_selectedTimeZones.removeAll(m_data[index.row()].id); 0104 m_offsetData.remove(m_data[index.row()].id); 0105 } 0106 0107 sortTimeZones(); 0108 0109 emit selectedTimeZonesChanged(); 0110 return true; 0111 } 0112 0113 return false; 0114 } 0115 0116 void TimeZoneModel::update() 0117 { 0118 beginResetModel(); 0119 m_data.clear(); 0120 0121 QTimeZone localZone = QTimeZone(QTimeZone::systemTimeZoneId()); 0122 const QStringList data = QString::fromUtf8(localZone.id()).split(QLatin1Char('/')); 0123 0124 TimeZoneData local; 0125 local.id = "Local"; 0126 local.region = i18nc("This means \"Local Timezone\"", "Local"); 0127 local.city = m_timezonesI18n->i18nCity(data.last()); 0128 local.comment = i18n("Your system time zone"); 0129 local.checked = false; 0130 0131 m_data.append(local); 0132 0133 QStringList cities; 0134 QHash<QString, QTimeZone> zonesByCity; 0135 0136 const auto systemTimeZones = QTimeZone::availableTimeZoneIds(); 0137 0138 for (const auto &id : systemTimeZones) { 0139 const QTimeZone zone(id); 0140 0141 const QStringList splitted = QString::fromUtf8(id).split(QStringLiteral("/")); 0142 0143 // CITY | COUNTRY | CONTINENT 0144 const QString key = QStringLiteral("%1|%2|%3").arg(splitted.last(), QLocale::territoryToString(zone.territory()), splitted.first()); 0145 0146 cities.append(key); 0147 zonesByCity.insert(key, zone); 0148 } 0149 cities.sort(Qt::CaseInsensitive); 0150 0151 for (const QString &key : std::as_const(cities)) { 0152 const QTimeZone timeZone = zonesByCity.value(key); 0153 QString comment = timeZone.comment(); 0154 0155 // FIXME - this was in the old code but makes no sense 0156 // if (!comment.isEmpty()) { 0157 // comment = i18n(comment.toUtf8()); 0158 // } 0159 0160 const QStringList cityCountryContinent = key.split(QLatin1Char('|')); 0161 0162 TimeZoneData newData; 0163 newData.id = timeZone.id(); 0164 newData.region = timeZone.territory() == QLocale::AnyCountry 0165 ? QString() 0166 : m_timezonesI18n->i18nContinents(cityCountryContinent.at(2)) + QLatin1Char('/') + m_timezonesI18n->i18nCountry(timeZone.territory()); 0167 newData.city = m_timezonesI18n->i18nCity(cityCountryContinent.at(0)); 0168 newData.comment = comment; 0169 newData.checked = false; 0170 newData.offsetFromUtc = timeZone.offsetFromUtc(QDateTime::currentDateTimeUtc()); 0171 m_data.append(newData); 0172 } 0173 0174 endResetModel(); 0175 } 0176 0177 void TimeZoneModel::setSelectedTimeZones(const QStringList &selectedTimeZones) 0178 { 0179 m_selectedTimeZones = selectedTimeZones; 0180 for (int i = 0; i < m_data.size(); i++) { 0181 if (m_selectedTimeZones.contains(m_data.at(i).id)) { 0182 m_data[i].checked = true; 0183 m_offsetData.insert(m_data[i].id, m_data[i].offsetFromUtc); 0184 0185 QModelIndex index = createIndex(i, 0); 0186 emit dataChanged(index, index); 0187 } 0188 } 0189 0190 sortTimeZones(); 0191 } 0192 0193 void TimeZoneModel::selectLocalTimeZone() 0194 { 0195 m_data[0].checked = true; 0196 0197 QModelIndex index = createIndex(0, 0); 0198 emit dataChanged(index, index); 0199 0200 m_selectedTimeZones << m_data[0].id; 0201 emit selectedTimeZonesChanged(); 0202 } 0203 0204 QHash<int, QByteArray> TimeZoneModel::roleNames() const 0205 { 0206 return QHash<int, QByteArray>({ 0207 {TimeZoneIdRole, "timeZoneId"}, 0208 {RegionRole, "region"}, 0209 {CityRole, "city"}, 0210 {CommentRole, "comment"}, 0211 {CheckedRole, "checked"}, 0212 }); 0213 } 0214 0215 void TimeZoneModel::sortTimeZones() 0216 { 0217 std::sort(m_selectedTimeZones.begin(), m_selectedTimeZones.end(), [this](const QString &a, const QString &b) { 0218 return m_offsetData.value(a) < m_offsetData.value(b); 0219 }); 0220 }