Changeset View
Changeset View
Standalone View
Standalone View
runners/datetime/datetimerunner.cpp
1 | /* | 1 | /* | ||
---|---|---|---|---|---|
2 | * Copyright (C) 2006 Aaron Seigo <aseigo@kde.org> | 2 | * Copyright (C) 2006 Aaron Seigo <aseigo@kde.org> | ||
3 | * Copyright (C) 2010 Marco Martin <notmart@gmail.com> | 3 | * Copyright (C) 2010 Marco Martin <notmart@gmail.com> | ||
4 | * Copyright (C) 2015 Vishesh Handa <vhanda@kde.org> | 4 | * Copyright (C) 2015 Vishesh Handa <vhanda@kde.org> | ||
5 | * Copyright (C) 2018 James D. Smith <smithjd15@gmail.com> | ||||
5 | * | 6 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU Library General Public License version 2 as | 8 | * it under the terms of the GNU Library General Public License version 2 as | ||
8 | * published by the Free Software Foundation | 9 | * published by the Free Software Foundation | ||
9 | * | 10 | * | ||
10 | * This program is distributed in the hope that it will be useful, | 11 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
Show All 19 Lines | |||||
32 | DateTimeRunner::DateTimeRunner(QObject *parent, const QVariantList &args) | 33 | DateTimeRunner::DateTimeRunner(QObject *parent, const QVariantList &args) | ||
33 | : Plasma::AbstractRunner(parent, args) | 34 | : Plasma::AbstractRunner(parent, args) | ||
34 | { | 35 | { | ||
35 | setObjectName(QLatin1String( "DataTimeRunner" )); | 36 | setObjectName(QLatin1String( "DataTimeRunner" )); | ||
36 | 37 | | |||
37 | addSyntax(Plasma::RunnerSyntax(dateWord, i18n("Displays the current date"))); | 38 | addSyntax(Plasma::RunnerSyntax(dateWord, i18n("Displays the current date"))); | ||
38 | addSyntax(Plasma::RunnerSyntax(dateWord + QLatin1String( " :q:" ), i18n("Displays the current date in a given timezone"))); | 39 | addSyntax(Plasma::RunnerSyntax(dateWord + QLatin1String( " :q:" ), i18n("Displays the current date in a given timezone"))); | ||
39 | addSyntax(Plasma::RunnerSyntax(timeWord, i18n("Displays the current time"))); | 40 | addSyntax(Plasma::RunnerSyntax(timeWord, i18n("Displays the current time"))); | ||
41 | addSyntax(Plasma::RunnerSyntax(timeWord + QLatin1String( " 24" ), i18n("Displays the current time, in 24 hour time"))); | ||||
40 | addSyntax(Plasma::RunnerSyntax(timeWord + QLatin1String( " :q:" ), i18n("Displays the current time in a given timezone"))); | 42 | addSyntax(Plasma::RunnerSyntax(timeWord + QLatin1String( " :q:" ), i18n("Displays the current time in a given timezone"))); | ||
43 | addSyntax(Plasma::RunnerSyntax(timeWord + QLatin1String( " :q:" ) + QLatin1String( " 24" ), i18n("Displays the local time from the given time of the form hh:mm [am/pm] or HH:mm, in 24 hour time"))); | ||||
44 | addSyntax(Plasma::RunnerSyntax(timeWord + QLatin1String( " :q:" ) + QLatin1String( " 24" ), i18n("Displays the current time in a given timezone, in 24 hour time"))); | ||||
45 | addSyntax(Plasma::RunnerSyntax(timeWord + QLatin1String( " :q:" ), i18n("Displays the local time from the given time of the form hh:mm [am/pm] or HH:mm"))); | ||||
46 | addSyntax(Plasma::RunnerSyntax(timeWord + QLatin1String( " :q:" ) + QLatin1String( " :q:" ), i18n("Displays the time in the given timezone converted from the given local time of the form hh:mm [am/pm] or HH:mm"))); | ||||
47 | addSyntax(Plasma::RunnerSyntax(timeWord + QLatin1String( " :q:" ) + QLatin1String( " :q:" ), i18n("Displays the given time of the form hh:mm [am/pm] or HH:mm converted from the given timezone to the local time"))); | ||||
48 | addSyntax(Plasma::RunnerSyntax(timeWord + QLatin1String( " :q:" ) + QLatin1String( " :q:" ) + QLatin1String( " 24" ), i18n("Displays the time in the given timezone converted from the given local time of the form hh:mm [am/pm] or HH:mm, in 24 hour time"))); | ||||
49 | addSyntax(Plasma::RunnerSyntax(timeWord + QLatin1String( " :q:" ) + QLatin1String( " :q:" ) + QLatin1String( " 24" ), i18n("Displays the given time of the form hh:mm [am/pm] or HH:mm converted from the given timezone to the local time, in 24 hour time"))); | ||||
41 | } | 50 | } | ||
42 | 51 | | |||
43 | DateTimeRunner::~DateTimeRunner() | 52 | DateTimeRunner::~DateTimeRunner() | ||
44 | { | 53 | { | ||
45 | } | 54 | } | ||
46 | 55 | | |||
47 | void DateTimeRunner::match(Plasma::RunnerContext &context) | 56 | void DateTimeRunner::match(Plasma::RunnerContext &context) | ||
48 | { | 57 | { | ||
49 | const QString term = context.query(); | 58 | const QStringList terms = context.query().split(QChar::Space, QString::SkipEmptyParts); | ||
50 | if (term.compare(dateWord, Qt::CaseInsensitive) == 0) { | 59 | bool is24Hr = terms.contains(QStringLiteral("24")); | ||
51 | const QString date = QLocale().toString(QDate::currentDate()); | 60 | bool toLocalTime = QChar(terms.value(1).at(0)).isNumber() && (terms.value(1) != QStringLiteral("24")); | ||
52 | addMatch(i18n("Today's date is %1", date), date, context, QStringLiteral("view-calendar-day")); | 61 | | ||
53 | } else if (term.startsWith(dateWord + QLatin1Char( ' ' ), Qt::CaseInsensitive)) { | 62 | QMultiHash<QString, QTimeZone> zoneMatches; | ||
54 | const auto tz = term.rightRef(term.length() - dateWord.length() - 1); | 63 | QMultiHash<QString, QDateTime> dTMatches; | ||
55 | const auto dates = datetime(tz); | 64 | QString time; | ||
56 | for(auto it = dates.constBegin(), itEnd = dates.constEnd(); it != itEnd; ++it) { | 65 | QTime t; | ||
57 | const QString date = QLocale().toString(*it); | 66 | | ||
58 | addMatch(QStringLiteral("%1 - %2").arg(it.key(), date), date, context, QStringLiteral("view-calendar-day")); | 67 | for (const QString &term : terms) { | ||
59 | } | 68 | if (term.contains(QStringLiteral(":"))) { | ||
60 | } else if (term.compare(timeWord, Qt::CaseInsensitive) == 0) { | 69 | time = term; | ||
61 | const QString time = QLocale().toString(QTime::currentTime()); | 70 | } else if (term.compare(QStringLiteral("am"), Qt::CaseInsensitive) == 0) { | ||
62 | addMatch(i18n("Current time is %1", time), time, context, QStringLiteral("clock")); | 71 | time += QChar::Space + term; | ||
63 | } else if (term.startsWith(timeWord + QLatin1Char( ' ' ), Qt::CaseInsensitive)) { | 72 | } else if (term.compare(QStringLiteral("pm"), Qt::CaseInsensitive) == 0) { | ||
64 | const auto tz = term.rightRef(term.length() - timeWord.length() - 1); | 73 | time += QChar::Space + term; | ||
65 | const auto times = datetime(tz); | 74 | } else if (!QChar(term.at(0)).isNumber()) { | ||
66 | for(auto it = times.constBegin(), itEnd = times.constEnd(); it != itEnd; ++it) { | 75 | zoneMatches = timeZoneMatches(term); | ||
67 | const QString time = QLocale().toString(*it, QLocale::ShortFormat); | 76 | } | ||
68 | addMatch(QStringLiteral("%1 - %2").arg(it.key(), time), time, context, QStringLiteral("clock")); | | |||
69 | } | 77 | } | ||
78 | | ||||
79 | // Possible time formats. | ||||
80 | QTime hmmapTime = QTime::fromString(time, QStringLiteral("h:mm ap")); | ||||
81 | QTime hhmmapTime = QTime::fromString(time, QStringLiteral("hh:mm ap")); | ||||
82 | QTime hmmTime = QTime::fromString(time, QStringLiteral("h:mm")); | ||||
83 | QTime hhmmTime = QTime::fromString(time, QStringLiteral("hh:mm")); | ||||
84 | | ||||
85 | if (hmmapTime.isValid()) { | ||||
86 | t = hmmapTime; | ||||
87 | } else if (hhmmapTime.isValid()) { | ||||
88 | t = hhmmapTime; | ||||
89 | } else if (hmmTime.isValid()) { | ||||
90 | t = hmmTime; | ||||
91 | } else if (hhmmTime.isValid()) { | ||||
92 | t = hhmmTime; | ||||
70 | } | 93 | } | ||
94 | | ||||
95 | // If there are no zone matches the time is localtime. | ||||
96 | if (!zoneMatches.isEmpty()) { | ||||
97 | for (auto it = zoneMatches.begin(); it != zoneMatches.end(); ++it) { | ||||
98 | if (toLocalTime && t.isValid()) { | ||||
99 | dTMatches.insert(it.key(), QDateTime(QDateTime::currentDateTime().date(), t, it.value()).toLocalTime()); | ||||
100 | } else if (!toLocalTime && t.isValid()) { | ||||
101 | dTMatches.insert(it.key(), QDateTime(QDateTime::currentDateTime().date(), t).toTimeZone(it.value())); | ||||
102 | } else if (!toLocalTime && !t.isValid()) { | ||||
103 | dTMatches.insert(it.key(), QDateTime::currentDateTime().toTimeZone(it.value())); | ||||
104 | } | ||||
105 | } | ||||
106 | } else if ((terms.size() == 1) || ((terms.size() == 2) && is24Hr)) { | ||||
107 | dTMatches.insert(QTimeZone::systemTimeZone().displayName(QTimeZone::GenericTime, QTimeZone::ShortName), QDateTime::currentDateTime()); | ||||
108 | } else { | ||||
109 | return; | ||||
110 | } | ||||
111 | | ||||
112 | if (terms.value(0).compare(dateWord, Qt::CaseInsensitive) == 0) { | ||||
113 | for (auto it = dTMatches.begin(); it != dTMatches.end(); ++it) { | ||||
114 | const QDateTime &dt = it.value(); | ||||
115 | const QString &tzName = it.key(); | ||||
116 | QString date = QLocale().toString(dt.date()); | ||||
117 | | ||||
118 | addMatch(QStringLiteral("%1 - %2").arg(tzName, date), date, context, QStringLiteral("view-calendar-day")); | ||||
71 | } | 119 | } | ||
120 | } else if (terms.value(0).compare(timeWord, Qt::CaseInsensitive) == 0) { | ||||
121 | for (auto it = dTMatches.begin(); it != dTMatches.end(); ++it) { | ||||
122 | const QDateTime &dt = it.value(); | ||||
123 | const QString &tzName = it.key(); | ||||
124 | QString dateTime; | ||||
72 | 125 | | |||
73 | QHash<QString, QDateTime> DateTimeRunner::datetime(const QStringRef& tz) | 126 | if (is24Hr) { | ||
127 | QString timeFormat24hr = QLocale().timeFormat(QLocale::ShortFormat); | ||||
128 | timeFormat24hr.remove(QStringLiteral("a"), Qt::CaseInsensitive); | ||||
129 | timeFormat24hr.remove(QStringLiteral("p"), Qt::CaseInsensitive); | ||||
130 | | ||||
131 | dateTime = QLocale().toString(dt.time(), timeFormat24hr.simplified()); | ||||
132 | } else { | ||||
133 | dateTime = QLocale().toString(dt.time(), QLocale::ShortFormat); | ||||
134 | } | ||||
135 | | ||||
136 | // When converting time append a date string. | ||||
137 | if (!zoneMatches.isEmpty()) { | ||||
138 | dateTime += QStringLiteral(" - ") + QLocale().toString(dt.date(), QLocale::ShortFormat); | ||||
139 | } | ||||
140 | | ||||
141 | addMatch(QStringLiteral("%1 - %2").arg(tzName, dateTime), dateTime, context, QStringLiteral("clock")); | ||||
142 | } | ||||
143 | } | ||||
144 | } | ||||
145 | | ||||
146 | QMultiHash<QString, QTimeZone> DateTimeRunner::timeZoneMatches(QString tz) | ||||
74 | { | 147 | { | ||
75 | QHash<QString, QDateTime> ret; | 148 | QMultiHash<QString, QTimeZone> ret; | ||
76 | // | 149 | | ||
77 | // KTimeZone gives us the actual timezone names such as "Asia/Kolkatta" and does | 150 | QList<QByteArray> timeZoneIds = QTimeZone::availableTimeZoneIds(); | ||
78 | // not give us country info. QTimeZone does not give us the actual timezone name | | |||
79 | // This is why we are using both for now. | | |||
80 | // | | |||
81 | const QList<QByteArray> timeZoneIds = QTimeZone::availableTimeZoneIds(); | | |||
82 | for (const QByteArray& zoneId : timeZoneIds) { | 151 | for (const QByteArray& zoneId : timeZoneIds) { | ||
83 | QTimeZone timeZone(zoneId); | 152 | QTimeZone timeZone(zoneId); | ||
153 | const QString zone = timeZone.displayName(QTimeZone::GenericTime); | ||||
84 | 154 | | |||
85 | const QString zoneName = QString::fromUtf8(zoneId); | 155 | const QString zoneName = QString::fromUtf8(zoneId); | ||
86 | if (zoneName.contains(tz, Qt::CaseInsensitive)) { | 156 | if (zoneName.contains(tz, Qt::CaseInsensitive) && !ret.contains(zone)) { | ||
87 | ret[zoneName] = QDateTime::currentDateTimeUtc().toTimeZone(timeZone); | 157 | ret.insert(zone, timeZone); | ||
88 | continue; | | |||
89 | } | 158 | } | ||
90 | 159 | | |||
91 | const QString country = QLocale::countryToString(timeZone.country()); | 160 | const QString country = QLocale::countryToString(timeZone.country()); | ||
92 | if (country.contains(tz, Qt::CaseInsensitive)) { | 161 | if (country.contains(tz, Qt::CaseInsensitive) && !ret.contains(zone)) { | ||
93 | ret[country] = QDateTime::currentDateTimeUtc().toTimeZone(timeZone); | 162 | ret.insert(zone, timeZone); | ||
94 | continue; | | |||
95 | } | 163 | } | ||
96 | 164 | | |||
97 | // FIXME: This only includes the current abbreviation and not old abbreviation or | 165 | // FIXME: This only includes the current abbreviation and not old abbreviation or | ||
98 | // other possible names. | 166 | // other possible names. | ||
99 | // Eg - depending on the current date, only CET or CEST will work | 167 | // Eg - depending on the current date, only CET or CEST will work | ||
100 | const QString abbr = timeZone.abbreviation(QDateTime::currentDateTime()); | 168 | const QString abbr = timeZone.abbreviation(QDateTime::currentDateTime()); | ||
101 | if (abbr.contains(tz, Qt::CaseInsensitive)) { | 169 | if (abbr.contains(tz, Qt::CaseInsensitive) && !ret.contains(zone)) { | ||
102 | ret[abbr] = QDateTime::currentDateTimeUtc().toTimeZone(timeZone); | 170 | ret.insert(zone, timeZone); | ||
103 | continue; | | |||
104 | } | 171 | } | ||
105 | } | 172 | } | ||
106 | 173 | | |||
107 | return ret; | 174 | return ret; | ||
108 | } | 175 | } | ||
109 | 176 | | |||
110 | void DateTimeRunner::addMatch(const QString &text, const QString &clipboardText, | 177 | void DateTimeRunner::addMatch(const QString &text, const QString &clipboardText, | ||
111 | Plasma::RunnerContext &context, const QString& iconName) | 178 | Plasma::RunnerContext &context, const QString& iconName) | ||
Show All 14 Lines |