File indexing completed on 2024-04-21 14:55:49
0001 /* 0002 Copyright (C) 2005, S.R.Haque <srhaque@iee.org>. 0003 Copyright (C) 2009, David Faure <faure@kde.org> 0004 This file is part of the KDE project 0005 0006 This library is free software; you can redistribute it and/or 0007 modify it under the terms of the GNU Library General Public 0008 License version 2, as published by the Free Software Foundation. 0009 0010 This library is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 Library General Public License for more details. 0014 0015 You should have received a copy of the GNU Library General Public License 0016 along with this library; see the file COPYING.LIB. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "k4timezonewidget.h" 0022 0023 #include <QDebug> 0024 #include <QFile> 0025 #include <QPixmap> 0026 0027 #include <klocale.h> 0028 #include <klocalizedstring.h> 0029 #include <ksystemtimezone.h> 0030 #include <ktimezone.h> 0031 0032 class Q_DECL_HIDDEN K4TimeZoneWidget::Private 0033 { 0034 public: 0035 Private() : itemsCheckable(false), singleSelection(true) {} 0036 0037 enum Columns { 0038 CityColumn = 0, 0039 RegionColumn, 0040 CommentColumn 0041 }; 0042 0043 enum Roles { 0044 ZoneRole = Qt::UserRole + 0xF3A3CB1 0045 }; 0046 0047 bool itemsCheckable; 0048 bool singleSelection; 0049 }; 0050 0051 static bool localeLessThan(const QString &a, const QString &b) 0052 { 0053 return QString::localeAwareCompare(a, b) < 0; 0054 } 0055 0056 K4TimeZoneWidget::K4TimeZoneWidget(QWidget *parent, KTimeZones *db) 0057 : QTreeWidget(parent), 0058 d(new K4TimeZoneWidget::Private) 0059 { 0060 // If the user did not provide a timezone database, we'll use the system default. 0061 setRootIsDecorated(false); 0062 setHeaderLabels(QStringList() << i18nc("Define an area in the time zone, like a town area", "Area") << i18nc("Time zone", "Region") << i18n("Comment")); 0063 0064 // Collect zones by localized city names, so that they can be sorted properly. 0065 QStringList cities; 0066 QHash<QString, KTimeZone> zonesByCity; 0067 0068 if (!db) { 0069 db = KSystemTimeZones::timeZones(); 0070 0071 // add UTC to the defaults default 0072 KTimeZone utc = KTimeZone::utc(); 0073 cities.append(utc.name()); 0074 zonesByCity.insert(utc.name(), utc); 0075 } 0076 0077 const KTimeZones::ZoneMap zones = db->zones(); 0078 for (KTimeZones::ZoneMap::ConstIterator it = zones.begin(); it != zones.end(); ++it) { 0079 const KTimeZone zone = it.value(); 0080 const QString continentCity = displayName(zone); 0081 const int separator = continentCity.lastIndexOf('/'); 0082 // Make up the localized key that will be used for sorting. 0083 // Example: i18n(Asia/Tokyo) -> key = "i18n(Tokyo)|i18n(Asia)|Asia/Tokyo" 0084 // The zone name is appended to ensure unicity even with equal translations (#174918) 0085 const QString key = continentCity.mid(separator + 1) + '|' 0086 + continentCity.left(separator) + '|' + zone.name(); 0087 cities.append(key); 0088 zonesByCity.insert(key, zone); 0089 } 0090 std::sort(cities.begin(), cities.end(), localeLessThan); 0091 0092 foreach (const QString &key, cities) { 0093 const KTimeZone zone = zonesByCity.value(key); 0094 const QString tzName = zone.name(); 0095 QString comment = zone.comment(); 0096 0097 if (!comment.isEmpty()) { 0098 comment = i18n(comment.toUtf8()); 0099 } 0100 0101 // Convert: 0102 // 0103 // "Europe/London", "GB" -> "London", "Europe/GB". 0104 // "UTC", "" -> "UTC", "". 0105 QStringList continentCity = displayName(zone).split('/'); 0106 0107 QTreeWidgetItem *listItem = new QTreeWidgetItem(this); 0108 listItem->setText(Private::CityColumn, continentCity[ continentCity.count() - 1 ]); 0109 QString countryName = KLocale::global()->countryCodeToName(zone.countryCode()); 0110 if (countryName.isEmpty()) { 0111 continentCity[ continentCity.count() - 1 ] = zone.countryCode(); 0112 } else { 0113 continentCity[ continentCity.count() - 1 ] = countryName; 0114 } 0115 0116 listItem->setText(Private::RegionColumn, continentCity.join(QChar('/'))); 0117 listItem->setText(Private::CommentColumn, comment); 0118 listItem->setData(Private::CityColumn, Private::ZoneRole, tzName); // store complete path in custom role 0119 0120 // Locate the flag from share/kf5/locale/countries/%1/flag.png 0121 QString flag = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString("kf5/locale/countries/%1/flag.png").arg(zone.countryCode().toLower())); 0122 if (QFile::exists(flag)) { 0123 listItem->setIcon(Private::RegionColumn, QPixmap(flag)); 0124 } 0125 } 0126 } 0127 0128 K4TimeZoneWidget::~K4TimeZoneWidget() 0129 { 0130 delete d; 0131 } 0132 0133 void K4TimeZoneWidget::setItemsCheckable(bool enable) 0134 { 0135 d->itemsCheckable = enable; 0136 const int count = topLevelItemCount(); 0137 for (int row = 0; row < count; ++row) { 0138 QTreeWidgetItem *listItem = topLevelItem(row); 0139 listItem->setCheckState(Private::CityColumn, Qt::Unchecked); 0140 } 0141 QTreeWidget::setSelectionMode(QAbstractItemView::NoSelection); 0142 } 0143 0144 bool K4TimeZoneWidget::itemsCheckable() const 0145 { 0146 return d->itemsCheckable; 0147 } 0148 0149 QString K4TimeZoneWidget::displayName(const KTimeZone &zone) 0150 { 0151 return i18n(zone.name().toUtf8()).replace('_', ' '); 0152 } 0153 0154 QStringList K4TimeZoneWidget::selection() const 0155 { 0156 QStringList selection; 0157 0158 // Loop through all entries. 0159 // Do not use selectedItems() because it skips hidden items, making it 0160 // impossible to use a KTreeWidgetSearchLine. 0161 // There is no QTreeWidgetItemConstIterator, hence the const_cast :/ 0162 QTreeWidgetItemIterator it(const_cast<K4TimeZoneWidget *>(this), d->itemsCheckable ? QTreeWidgetItemIterator::Checked : QTreeWidgetItemIterator::Selected); 0163 for (; *it; ++it) { 0164 selection.append((*it)->data(Private::CityColumn, Private::ZoneRole).toString()); 0165 } 0166 0167 return selection; 0168 } 0169 0170 void K4TimeZoneWidget::setSelected(const QString &zone, bool selected) 0171 { 0172 bool found = false; 0173 0174 // The code was using findItems( zone, Qt::MatchExactly, Private::ZoneColumn ) 0175 // previously, but the underlying model only has 3 columns, the "hidden" column 0176 // wasn't available in there. 0177 0178 if (!d->itemsCheckable) { 0179 // Runtime compatibility for < 4.3 apps, which don't call the setMultiSelection reimplementation. 0180 d->singleSelection = (QTreeWidget::selectionMode() == QAbstractItemView::SingleSelection); 0181 } 0182 0183 // Loop through all entries. 0184 const int rowCount = model()->rowCount(QModelIndex()); 0185 for (int row = 0; row < rowCount; ++row) { 0186 const QModelIndex index = model()->index(row, Private::CityColumn); 0187 const QString tzName = index.data(Private::ZoneRole).toString(); 0188 if (tzName == zone) { 0189 0190 if (d->singleSelection && selected) { 0191 clearSelection(); 0192 } 0193 0194 if (d->itemsCheckable) { 0195 QTreeWidgetItem *listItem = itemFromIndex(index); 0196 listItem->setCheckState(Private::CityColumn, selected ? Qt::Checked : Qt::Unchecked); 0197 } else { 0198 selectionModel()->select(index, selected ? (QItemSelectionModel::Select | QItemSelectionModel::Rows) : (QItemSelectionModel::Deselect | QItemSelectionModel::Rows)); 0199 } 0200 0201 // Ensure the selected item is visible as appropriate. 0202 scrollTo(index); 0203 0204 found = true; 0205 0206 if (d->singleSelection && selected) { 0207 break; 0208 } 0209 } 0210 } 0211 0212 if (!found) { 0213 qDebug() << "No such zone: " << zone; 0214 } 0215 } 0216 0217 void K4TimeZoneWidget::clearSelection() 0218 { 0219 if (d->itemsCheckable) { 0220 // Un-select all items 0221 const int rowCount = model()->rowCount(QModelIndex()); 0222 for (int row = 0; row < rowCount; ++row) { 0223 const QModelIndex index = model()->index(row, 0); 0224 QTreeWidgetItem *listItem = itemFromIndex(index); 0225 listItem->setCheckState(Private::CityColumn, Qt::Unchecked); 0226 } 0227 } else { 0228 QTreeWidget::clearSelection(); 0229 } 0230 } 0231 0232 void K4TimeZoneWidget::setSelectionMode(QAbstractItemView::SelectionMode mode) 0233 { 0234 d->singleSelection = (mode == QAbstractItemView::SingleSelection); 0235 if (!d->itemsCheckable) { 0236 QTreeWidget::setSelectionMode(mode); 0237 } 0238 } 0239 0240 QAbstractItemView::SelectionMode K4TimeZoneWidget::selectionMode() const 0241 { 0242 if (d->itemsCheckable) { 0243 return d->singleSelection ? QTreeWidget::SingleSelection : QTreeWidget::MultiSelection; 0244 } else { 0245 return QTreeWidget::selectionMode(); 0246 } 0247 } 0248 0249 #include "moc_k4timezonewidget.cpp"