KDELibs4Support

k4timezonewidget.cpp
1 /*
2  Copyright (C) 2005, S.R.Haque <[email protected]>.
3  Copyright (C) 2009, David Faure <[email protected]>
4  This file is part of the KDE project
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License version 2, as published by the Free Software Foundation.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "k4timezonewidget.h"
22 
23 #include <QDebug>
24 #include <QFile>
25 #include <QPixmap>
26 
27 #include <klocale.h>
28 #include <klocalizedstring.h>
29 #include <ksystemtimezone.h>
30 #include <ktimezone.h>
31 
32 class Q_DECL_HIDDEN K4TimeZoneWidget::Private
33 {
34 public:
35  Private() : itemsCheckable(false), singleSelection(true) {}
36 
37  enum Columns {
38  CityColumn = 0,
39  RegionColumn,
40  CommentColumn
41  };
42 
43  enum Roles {
44  ZoneRole = Qt::UserRole + 0xF3A3CB1
45  };
46 
47  bool itemsCheckable;
48  bool singleSelection;
49 };
50 
51 static bool localeLessThan(const QString &a, const QString &b)
52 {
53  return QString::localeAwareCompare(a, b) < 0;
54 }
55 
57  : QTreeWidget(parent),
58  d(new K4TimeZoneWidget::Private)
59 {
60  // If the user did not provide a timezone database, we'll use the system default.
61  setRootIsDecorated(false);
62  setHeaderLabels(QStringList() << i18nc("Define an area in the time zone, like a town area", "Area") << i18nc("Time zone", "Region") << i18n("Comment"));
63 
64  // Collect zones by localized city names, so that they can be sorted properly.
65  QStringList cities;
66  QHash<QString, KTimeZone> zonesByCity;
67 
68  if (!db) {
70 
71  // add UTC to the defaults default
72  KTimeZone utc = KTimeZone::utc();
73  cities.append(utc.name());
74  zonesByCity.insert(utc.name(), utc);
75  }
76 
77  const KTimeZones::ZoneMap zones = db->zones();
78  for (KTimeZones::ZoneMap::ConstIterator it = zones.begin(); it != zones.end(); ++it) {
79  const KTimeZone zone = it.value();
80  const QString continentCity = displayName(zone);
81  const int separator = continentCity.lastIndexOf('/');
82  // Make up the localized key that will be used for sorting.
83  // Example: i18n(Asia/Tokyo) -> key = "i18n(Tokyo)|i18n(Asia)|Asia/Tokyo"
84  // The zone name is appended to ensure unicity even with equal translations (#174918)
85  const QString key = continentCity.mid(separator + 1) + '|'
86  + continentCity.left(separator) + '|' + zone.name();
87  cities.append(key);
88  zonesByCity.insert(key, zone);
89  }
90  std::sort(cities.begin(), cities.end(), localeLessThan);
91 
92  foreach (const QString &key, cities) {
93  const KTimeZone zone = zonesByCity.value(key);
94  const QString tzName = zone.name();
95  QString comment = zone.comment();
96 
97  if (!comment.isEmpty()) {
98  comment = i18n(comment.toUtf8());
99  }
100 
101  // Convert:
102  //
103  // "Europe/London", "GB" -> "London", "Europe/GB".
104  // "UTC", "" -> "UTC", "".
105  QStringList continentCity = displayName(zone).split('/');
106 
107  QTreeWidgetItem *listItem = new QTreeWidgetItem(this);
108  listItem->setText(Private::CityColumn, continentCity[ continentCity.count() - 1 ]);
109  QString countryName = KLocale::global()->countryCodeToName(zone.countryCode());
110  if (countryName.isEmpty()) {
111  continentCity[ continentCity.count() - 1 ] = zone.countryCode();
112  } else {
113  continentCity[ continentCity.count() - 1 ] = countryName;
114  }
115 
116  listItem->setText(Private::RegionColumn, continentCity.join(QChar('/')));
117  listItem->setText(Private::CommentColumn, comment);
118  listItem->setData(Private::CityColumn, Private::ZoneRole, tzName); // store complete path in custom role
119 
120  // Locate the flag from share/kf5/locale/countries/%1/flag.png
121  QString flag = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString("kf5/locale/countries/%1/flag.png").arg(zone.countryCode().toLower()));
122  if (QFile::exists(flag)) {
123  listItem->setIcon(Private::RegionColumn, QPixmap(flag));
124  }
125  }
126 }
127 
129 {
130  delete d;
131 }
132 
134 {
135  d->itemsCheckable = enable;
136  const int count = topLevelItemCount();
137  for (int row = 0; row < count; ++row) {
138  QTreeWidgetItem *listItem = topLevelItem(row);
139  listItem->setCheckState(Private::CityColumn, Qt::Unchecked);
140  }
142 }
143 
145 {
146  return d->itemsCheckable;
147 }
148 
150 {
151  return i18n(zone.name().toUtf8()).replace('_', ' ');
152 }
153 
155 {
157 
158  // Loop through all entries.
159  // Do not use selectedItems() because it skips hidden items, making it
160  // impossible to use a KTreeWidgetSearchLine.
161  // There is no QTreeWidgetItemConstIterator, hence the const_cast :/
162  QTreeWidgetItemIterator it(const_cast<K4TimeZoneWidget *>(this), d->itemsCheckable ? QTreeWidgetItemIterator::Checked : QTreeWidgetItemIterator::Selected);
163  for (; *it; ++it) {
164  selection.append((*it)->data(Private::CityColumn, Private::ZoneRole).toString());
165  }
166 
167  return selection;
168 }
169 
170 void K4TimeZoneWidget::setSelected(const QString &zone, bool selected)
171 {
172  bool found = false;
173 
174  // The code was using findItems( zone, Qt::MatchExactly, Private::ZoneColumn )
175  // previously, but the underlying model only has 3 columns, the "hidden" column
176  // wasn't available in there.
177 
178  if (!d->itemsCheckable) {
179  // Runtime compatibility for < 4.3 apps, which don't call the setMultiSelection reimplementation.
181  }
182 
183  // Loop through all entries.
184  const int rowCount = model()->rowCount(QModelIndex());
185  for (int row = 0; row < rowCount; ++row) {
186  const QModelIndex index = model()->index(row, Private::CityColumn);
187  const QString tzName = index.data(Private::ZoneRole).toString();
188  if (tzName == zone) {
189 
190  if (d->singleSelection && selected) {
191  clearSelection();
192  }
193 
194  if (d->itemsCheckable) {
195  QTreeWidgetItem *listItem = itemFromIndex(index);
196  listItem->setCheckState(Private::CityColumn, selected ? Qt::Checked : Qt::Unchecked);
197  } else {
199  }
200 
201  // Ensure the selected item is visible as appropriate.
202  scrollTo(index);
203 
204  found = true;
205 
206  if (d->singleSelection && selected) {
207  break;
208  }
209  }
210  }
211 
212  if (!found) {
213  qDebug() << "No such zone: " << zone;
214  }
215 }
216 
218 {
219  if (d->itemsCheckable) {
220  // Un-select all items
221  const int rowCount = model()->rowCount(QModelIndex());
222  for (int row = 0; row < rowCount; ++row) {
223  const QModelIndex index = model()->index(row, 0);
224  QTreeWidgetItem *listItem = itemFromIndex(index);
225  listItem->setCheckState(Private::CityColumn, Qt::Unchecked);
226  }
227  } else {
229  }
230 }
231 
233 {
234  d->singleSelection = (mode == QAbstractItemView::SingleSelection);
235  if (!d->itemsCheckable) {
237  }
238 }
239 
241 {
242  if (d->itemsCheckable) {
243  return d->singleSelection ? QTreeWidget::SingleSelection : QTreeWidget::MultiSelection;
244  } else {
246  }
247 }
248 
virtual int rowCount(const QModelIndex &parent) const const =0
QHash::iterator insert(const Key &key, const T &value)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const =0
int localeAwareCompare(const QString &other) const const
void setSelectionMode(QAbstractItemView::SelectionMode mode)
QItemSelectionModel * selectionModel() const const
void setSelected(const QString &zone, bool selected)
Select/deselect the named time zone.
void setIcon(int column, const QIcon &icon)
virtual void setData(int column, int role, const QVariant &value)
QString countryCodeToName(const QString &country) const
Convert a known country code to a human readable, localized form.
Definition: klocale.cpp:601
bool exists() const const
void clearSelection()
Unselect all timezones.
The KTimeZones class represents a time zone database which consists of a collection of individual tim...
Definition: ktimezone.h:308
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
static KTimeZones * timeZones()
Returns the unique KTimeZones instance containing the system time zones collection.
bool itemsCheckable() const
System time zone functions.
QString countryCode() const
Returns the two-letter country code of the time zone.
Definition: ktimezone.cpp:643
static QString displayName(const KTimeZone &zone)
Format a time zone name in a standardised manner.
void append(const T &value)
QStringList selection() const
Returns the currently selected time zones.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
UserRole
virtual void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command)
bool isEmpty() const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
Time zone functions.
QMap::iterator end()
virtual ~K4TimeZoneWidget()
Destroys the time zone selection widget.
QMap::iterator begin()
static KLocale * global()
Return the global KLocale instance.
Definition: klocale.cpp:309
QTreeWidgetItem * itemFromIndex(const QModelIndex &index) const const
QList::iterator end()
QString toLower() const const
const T value(const Key &key) const const
K4TimeZoneWidget(QWidget *parent=nullptr, KTimeZones *timeZones=nullptr)
Constructs a time zone selection widget.
virtual void scrollTo(const QModelIndex &index, QAbstractItemView::ScrollHint hint) override
Base class representing a time zone.
Definition: ktimezone.h:415
QString i18n(const char *text, const TYPE &arg...)
void setHeaderLabels(const QStringList &labels)
QAbstractItemView::SelectionMode selectionMode() const
void setCheckState(int column, Qt::CheckState state)
QString mid(int position, int n) const const
QVariant data(int role) const const
void setItemsCheckable(bool enable)
Makes all items show a checkbox, so that the user can select multiple timezones by means of checking ...
void setText(int column, const QString &text)
Unchecked
QString left(int n) const const
QString name() const
Returns the name of the time zone.
Definition: ktimezone.cpp:663
QTreeWidgetItem * topLevelItem(int index) const const
const ZoneMap zones() const
Returns all the time zones defined in this collection.
Definition: ktimezone.cpp:62
QAbstractItemModel * model() const const
void setRootIsDecorated(bool show)
int topLevelItemCount() const const
QString comment() const
Returns any comment for the time zone.
Definition: ktimezone.cpp:658
QString toString() const const
QList::iterator begin()
void setSelectionMode(QAbstractItemView::SelectionMode mode)
Allows to select multiple timezones.
static KTimeZone utc()
Returns a standard UTC time zone, with name "UTC".
Definition: ktimezone.cpp:916
A time zone selection widget.
QString locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat Jul 4 2020 22:58:56 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.