on xenial help sign in
Removed TimeFormatter in favor of sdk LiveTimer+i18n.relativeDateTime
6d916f1Nick Dedekind
plugins/Utils/CMakeLists.txt−2
@@ -13,8 +13,6 @@ set(QMLPLUGIN_SRC
13 inputwatcher.cpp
13 inputwatcher.cpp
14 qlimitproxymodelqml.cpp
14 qlimitproxymodelqml.cpp
15 unitysortfilterproxymodelqml.cpp
15 unitysortfilterproxymodelqml.cpp
16− relativetimeformatter.cpp
17− timeformatter.cpp
18 Timer.cpp
16 Timer.cpp
19 unitymenumodelpaths.cpp
17 unitymenumodelpaths.cpp
20 windowkeysfilter.cpp
18 windowkeysfilter.cpp
plugins/Utils/plugin.cpp−5
@@ -28,8 +28,6 @@
28#include "inputwatcher.h"
28#include "inputwatcher.h"
29#include "qlimitproxymodelqml.h"
29#include "qlimitproxymodelqml.h"
30#include "unitysortfilterproxymodelqml.h"
30#include "unitysortfilterproxymodelqml.h"
31−#include "relativetimeformatter.h"
32−#include "timeformatter.h"
33#include "unitymenumodelpaths.h"
31#include "unitymenumodelpaths.h"
34#include "windowkeysfilter.h"
32#include "windowkeysfilter.h"
35#include "windowscreenshotprovider.h"
33#include "windowscreenshotprovider.h"
@@ -58,11 +56,8 @@ void UtilsPlugin::registerTypes(const char *uri)
58 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
56 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
59 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
57 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
60 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
58 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
61− qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
62 qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
59 qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
63− qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
64 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
60 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
65− qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter");
66 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
61 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
67 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
62 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
68 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
63 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
plugins/Utils/relativetimeformatter.cppdeleted−260
@@ -1,260 +0,0 @@
1−/*
2− * Copyright 2014 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− */
17−
18−// Local
19−#include "relativetimeformatter.h"
20−
21−// Qt
22−#include <QDateTime>
23−
24−// Other
25−#include <glib.h>
26−#include <glib/gi18n.h>
27−#include <locale.h>
28−#include <langinfo.h>
29−#include <string.h>
30−
31−RelativeTimeFormatter::RelativeTimeFormatter(QObject *parent)
32− : GDateTimeFormatter(parent)
33−{
34−}
35−
36− /* Check the system locale setting to see if the format is 24-hour
37− time or 12-hour time */
38−gboolean
39−is_locale_12h(void)
40−{
41− int i;
42− static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", nullptr};
43− const char* t_fmt = nl_langinfo(T_FMT);
44−
45− for (i=0; formats_24h[i]!=nullptr; i++)
46− if (strstr(t_fmt, formats_24h[i]) != nullptr)
47− return FALSE;
48−
49− return TRUE;
50−}
51−
52−typedef enum
53−{
54− DATE_PROXIMITY_YESTERDAY,
55− DATE_PROXIMITY_TODAY,
56− DATE_PROXIMITY_TOMORROW,
57− DATE_PROXIMITY_LAST_WEEK,
58− DATE_PROXIMITY_NEXT_WEEK,
59− DATE_PROXIMITY_FAR
60−} date_proximity_t;
61−
62−static date_proximity_t
63−getDateProximity(GDateTime* now, GDateTime* time)
64−{
65− date_proximity_t prox = DATE_PROXIMITY_FAR;
66− gint now_year, now_month, now_day;
67− gint time_year, time_month, time_day;
68−
69− // does it happen today?
70− g_date_time_get_ymd(now, &now_year, &now_month, &now_day);
71− g_date_time_get_ymd(time, &time_year, &time_month, &time_day);
72− if ((now_year == time_year) && (now_month == time_month) && (now_day == time_day)) {
73− return DATE_PROXIMITY_TODAY;
74− }
75−
76− // did it happen yesterday?
77− GDateTime* yesterday = g_date_time_add_days(now, -1);
78− gint tom_year, tom_month, tom_day;
79− g_date_time_get_ymd(yesterday, &tom_year, &tom_month, &tom_day);
80− g_date_time_unref(yesterday);
81− if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) {
82− return DATE_PROXIMITY_YESTERDAY;
83− }
84−
85− // does it happen tomorrow?
86− GDateTime* tomorrow = g_date_time_add_days(now, 1);
87− g_date_time_get_ymd(tomorrow, &tom_year, &tom_month, &tom_day);
88− g_date_time_unref(tomorrow);
89− if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) {
90− return DATE_PROXIMITY_TOMORROW;
91− }
92−
93− // does it happen this week?
94− if (g_date_time_compare(time, now) < 0) {
95− GDateTime* last_week = g_date_time_add_days(now, -6);
96− GDateTime* last_week_bound = g_date_time_new_local(g_date_time_get_year(last_week),
97− g_date_time_get_month(last_week),
98− g_date_time_get_day_of_month(last_week),
99− 0, 0, 0);
100− if (g_date_time_compare(time, last_week_bound) >= 0)
101− prox = DATE_PROXIMITY_LAST_WEEK;
102−
103− g_date_time_unref(last_week);
104− g_date_time_unref(last_week_bound);
105− } else {
106− GDateTime* next_week = g_date_time_add_days(now, 6);
107− GDateTime* next_week_bound = g_date_time_new_local(g_date_time_get_year(next_week),
108− g_date_time_get_month(next_week),
109− g_date_time_get_day_of_month(next_week),
110− 23, 59, 59.9);
111− if (g_date_time_compare(time, next_week_bound) <= 0)
112− prox = DATE_PROXIMITY_NEXT_WEEK;
113−
114− g_date_time_unref(next_week);
115− g_date_time_unref(next_week_bound);
116− }
117−
118− return prox;
119−}
120−
121−const char*
122−dgettext_datetime(const char *text)
123−{
124− return dgettext("unity8", text);
125−}
126−
127−/**
128− * _ a time yesterday should be shown as (e.g. “Yesterday 3:55 PM”)
129− * _ a time today should be shown as just the time (e.g. “3:55 PM”)
130− * _ a time tomorrow should be shown as(e.g. “Tomorrow 3:55 PM”)
131− * _ a time any other day this week should be shown as the short version of the
132− * day and time (e.g. “Wed 3:55 PM”)
133− * weekday (e.g. “Friday”)
134− * _ a time after this week should be shown as the short version of the day,
135− * date, and time (e.g. “Wed 21 Apr 3:55 PM”)
136− * _ in addition, when presenting the times of upcoming events, the time should
137− * be followed by the timezone if it is different from the one the computer
138− * is currently set to. For example, “Wed 3:55 PM UTC−5”.
139− *
140− * TODO - keep inline with indicator-datetime
141− */
142−char* generate_full_format_string_at_time (GDateTime* now,
143− GDateTime* then)
144−{
145− GString* ret = g_string_new (nullptr);
146−
147− if (then != nullptr) {
148− const date_proximity_t prox = getDateProximity(now, then);
149−
150− if (is_locale_12h()) {
151− switch (prox) {
152− case DATE_PROXIMITY_YESTERDAY:
153− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
154− This format string is used for showing, on a 12-hour clock, times that happen yesterday.
155− (\u2003 is a unicode em space which is slightly wider than a normal space.)
156− en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 1:00 PM" */
157− g_string_assign (ret, dgettext_datetime("Yesterday\u2003%l:%M %p"));
158− break;
159−
160− case DATE_PROXIMITY_TODAY:
161− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
162− This format string is used for showing, on a 12-hour clock, times that happened today.
163− en_US example: "%l:%M %p" --> "1:00 PM" */
164− g_string_assign (ret, dgettext_datetime("%l:%M %p"));
165− break;
166−
167− case DATE_PROXIMITY_TOMORROW:
168− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
169− This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow.
170− (\u2003 is a unicode em space which is slightly wider than a normal space.)
171− en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 1:00 PM" */
172− g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%l:%M %p"));
173− break;
174−
175− case DATE_PROXIMITY_LAST_WEEK:
176− case DATE_PROXIMITY_NEXT_WEEK:
177− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
178− This format string is used for showing, on a 12-hour clock, times that happened in the last week.
179− (\u2003 is a unicode em space which is slightly wider than a normal space.)
180− en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM" */
181− g_string_assign (ret, dgettext_datetime("%a\u2003%l:%M %p"));
182− break;
183−
184− case DATE_PROXIMITY_FAR:
185− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
186− This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
187− (\u2003 is a unicode em space which is slightly wider than a normal space.)
188− en_US example: "%a %d %b\u2003%l:%M %p" --> "Fri Oct 31 1:00 PM"
189− en_GB example: "%a %b %d\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM" */
190− g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%l:%M %p"));
191− break;
192− }
193− } else {
194− switch (prox) {
195−
196− case DATE_PROXIMITY_YESTERDAY:
197− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
198− This format string is used for showing, on a 24-hour clock, times that happen yesterday.
199− (\u2003 is a unicode em space which is slightly wider than a normal space.)
200− en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 13:00" */
201− g_string_assign (ret, dgettext_datetime("Yesterday\u2003%H:%M"));
202− break;
203−
204− case DATE_PROXIMITY_TODAY:
205− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
206− This format string is used for showing, on a 24-hour clock, times that happened today.
207− en_US example: "%H:%M" --> "13:00" */
208− g_string_assign (ret, dgettext_datetime("%H:%M"));
209− break;
210−
211− case DATE_PROXIMITY_TOMORROW:
212− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
213− This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow.
214− (\u2003 is a unicode em space which is slightly wider than a normal space.)
215− en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 13:00" */
216− g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%H:%M"));
217− break;
218−
219− case DATE_PROXIMITY_LAST_WEEK:
220− case DATE_PROXIMITY_NEXT_WEEK:
221− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
222− This format string is used for showing, on a 24-hour clock, times that happened in the last week.
223− (\u2003 is a unicode em space which is slightly wider than a normal space.)
224− en_US example: "%a\u2003%H:%M" --> "Fri 13:00" */
225− g_string_assign (ret, dgettext_datetime("%a\u2003%H:%M"));
226− break;
227−
228− case DATE_PROXIMITY_FAR:
229− /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
230− This format string is used for showing, on a 24-hour clock, times that happened before a week from now.
231− (\u2003 is a unicode em space which is slightly wider than a normal space.)
232− en_US example: "%a %d %b\u2003%H:%M" --> "Fri Oct 31 13:00"
233− en_GB example: "%a %b %d\u2003%H:%M" --> "Fri 31 Oct 13:00" */
234− g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%H:%M"));
235− break;
236− }
237− }
238− }
239−
240− return g_string_free (ret, FALSE);
241−}
242−
243−QString RelativeTimeFormatter::format() const
244−{
245− GDateTime* now = g_date_time_new_now_local();
246− if (!now) { return QString(); }
247−
248− GDateTime* then = g_date_time_new_from_unix_local(time());
249− if (!then) { return QString(); }
250−
251− char* time_format = generate_full_format_string_at_time(now, then);
252−
253− QString str(QString::fromUtf8(time_format));
254− g_free(time_format);
255−
256− g_date_time_unref(now);
257− g_date_time_unref(then);
258−
259− return str;
260−}
plugins/Utils/relativetimeformatter.hdeleted−34
@@ -1,34 +0,0 @@
1−/*
2− * Copyright 2014 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− */
17−
18−#ifndef RELATIVETIMEFORMATTER_H
19−#define RELATIVETIMEFORMATTER_H
20−
21−#include "timeformatter.h"
22−
23−// TODO - move this to the sdk
24−// https://blueprints.launchpad.net/ubuntu-ui-toolkit/+spec/time-formatter
25−class RelativeTimeFormatter : public GDateTimeFormatter
26−{
27− Q_OBJECT
28−public:
29− RelativeTimeFormatter(QObject *parent = 0);
30−
31− QString format() const override;
32−};
33−
34−#endif // RELATIVETIMEFORMATTER_H
plugins/Utils/timeformatter.cppdeleted−206
@@ -1,206 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Lars Uebernickel <lars.uebernickel@canonical.com>
17− */
18−
19−#include "timeformatter.h"
20−
21−#include <gio/gio.h>
22−#include <QDateTime>
23−
24−struct TimeFormatterPrivate
25−{
26− TimeFormatter *formatter;
27−
28− QString format;
29− QString timeString;
30− qint64 time;
31−
32− GDBusConnection *system_bus;
33− guint subscription_id;
34− GCancellable *cancellable;
35−};
36−
37−static void
38−timedate1_properties_changed (GDBusConnection *connection,
39− const gchar *sender_name,
40− const gchar *object_path,
41− const gchar *interface_name,
42− const gchar *signal_name,
43− GVariant *parameters,
44− gpointer user_data)
45−{
46− Q_UNUSED(connection);
47− Q_UNUSED(sender_name);
48− Q_UNUSED(object_path);
49− Q_UNUSED(interface_name);
50− Q_UNUSED(signal_name);
51−
52− TimeFormatterPrivate *priv = (TimeFormatterPrivate *)user_data;
53− GVariant *changed;
54− GVariantIter *iter;
55− const gchar *name;
56−
57− if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
58− return;
59−
60− g_variant_get (parameters, "(s@a{sv}as)", nullptr, &changed, &iter);
61−
62− if (g_variant_lookup (changed, "Timezone", "s", nullptr)) {
63− priv->formatter->update();
64− }
65− else {
66− while (g_variant_iter_next (iter, "&s", &name)) {
67− if (g_str_equal (name, "Timezone")) {
68− priv->formatter->update();
69− break;
70− }
71− }
72− }
73−
74− g_variant_unref (changed);
75− g_variant_iter_free (iter);
76−}
77−
78−static void
79−got_bus(GObject *object, GAsyncResult *result, gpointer user_data)
80−{
81− Q_UNUSED(object);
82−
83− TimeFormatterPrivate *priv = (TimeFormatterPrivate *)user_data;
84− GError *error = nullptr;
85−
86− priv->system_bus = g_bus_get_finish (result, &error);
87− if (priv->system_bus == nullptr) {
88− if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
89− qWarning("TimeFormatter: cannot connect to the system bus: %s", error->message);
90− g_error_free (error);
91− return;
92− }
93−
94− /* Listen to the PropertiesChanged on the org.freedesktop.timedate1
95− * interface from any sender. In practice, this signal will only be sent
96− * from timedated (we can trust other processes on the system bus to behave
97− * nicely). That way, we don't have to watch timedated's well-known name
98− * and keep the process alive.
99− */
100− priv->subscription_id = g_dbus_connection_signal_subscribe (priv->system_bus,
101− nullptr, /* sender */
102− "org.freedesktop.DBus.Properties",
103− "PropertiesChanged",
104− nullptr,
105− "org.freedesktop.timedate1",
106− G_DBUS_SIGNAL_FLAGS_NONE,
107− timedate1_properties_changed,
108− priv, nullptr);
109−}
110−
111−TimeFormatter::TimeFormatter(QObject *parent): QObject(parent)
112−{
113− priv = new TimeFormatterPrivate;
114− priv->formatter = this;
115− priv->time = 0;
116− priv->format = "yyyy-MM-dd hh:mm";
117− priv->system_bus = nullptr;
118− priv->subscription_id = 0;
119− priv->cancellable = g_cancellable_new ();
120−
121− g_bus_get (G_BUS_TYPE_SYSTEM, priv->cancellable, got_bus, priv);
122−}
123−
124−TimeFormatter::TimeFormatter(const QString &initialFormat, QObject *parent): TimeFormatter(parent)
125−{
126− priv->format = initialFormat;
127−}
128−
129−TimeFormatter::~TimeFormatter()
130−{
131− if (priv->system_bus) {
132− g_dbus_connection_signal_unsubscribe (priv->system_bus, priv->subscription_id);
133− g_object_unref (priv->system_bus);
134− }
135−
136− g_cancellable_cancel (priv->cancellable);
137− g_object_unref (priv->cancellable);
138−}
139−
140−QString TimeFormatter::format() const
141−{
142− return priv->format;
143−}
144−
145−QString TimeFormatter::timeString() const
146−{
147− return priv->timeString;
148−}
149−
150−qint64 TimeFormatter::time() const
151−{
152− return priv->time;
153−}
154−
155−void TimeFormatter::setFormat(const QString &format)
156−{
157− if (priv->format != format) {
158− priv->format = format;
159− Q_EMIT formatChanged(priv->format);
160− update();
161− }
162−}
163−
164−void TimeFormatter::setTime(qint64 time)
165−{
166− if (priv->time != time) {
167− priv->time = time;
168− Q_EMIT timeChanged(priv->time);
169− update();
170− }
171−}
172−
173−void TimeFormatter::update()
174−{
175− priv->timeString = formatTime();
176− Q_EMIT timeStringChanged(priv->timeString);
177−}
178−
179−QString TimeFormatter::formatTime() const
180−{
181− return QDateTime::fromMSecsSinceEpoch(time() / 1000).toString(format());
182−}
183−
184−GDateTimeFormatter::GDateTimeFormatter(QObject* parent)
185−: TimeFormatter("%d-%m-%Y %I:%M%p", parent)
186−{
187−}
188−
189−QString GDateTimeFormatter::formatTime() const
190−{
191− gchar* time_string;
192− GDateTime* datetime;
193− QByteArray formatBytes = format().toUtf8();
194−
195− datetime = g_date_time_new_from_unix_local(time());
196− if (!datetime) {
197− return "";
198− }
199−
200− time_string = g_date_time_format(datetime, formatBytes.constData());
201− QString formattedTime(QString::fromUtf8(time_string));
202−
203− g_free(time_string);
204− g_date_time_unref(datetime);
205− return formattedTime;
206−}
plugins/Utils/timeformatter.hdeleted−68
@@ -1,68 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Lars Uebernickel <lars.uebernickel@canonical.com>
17− */
18−
19−#ifndef TIME_FORMATTER_H
20−#define TIME_FORMATTER_H
21−
22−#include <QObject>
23−
24−// TODO - bug #1260728
25−class TimeFormatter : public QObject
26−{
27− Q_OBJECT
28− Q_PROPERTY(QString format READ format WRITE setFormat NOTIFY formatChanged)
29− Q_PROPERTY(QString timeString READ timeString NOTIFY timeStringChanged)
30− Q_PROPERTY(qint64 time READ time WRITE setTime NOTIFY timeChanged)
31−
32−public:
33− TimeFormatter(QObject *parent = 0);
34− virtual ~TimeFormatter();
35−
36− virtual QString format() const;
37− QString timeString() const;
38− qint64 time() const;
39−
40− void setFormat(const QString &format);
41− void setTime(qint64 time);
42−
43− void update();
44−
45−Q_SIGNALS:
46− void formatChanged(const QString &format);
47− void timeStringChanged(const QString &timeString);
48− void timeChanged(qint64 time);
49−
50−protected:
51− TimeFormatter(const QString &initialFormat, QObject *parent = 0);
52−
53− virtual QString formatTime() const;
54−
55−private:
56− struct TimeFormatterPrivate *priv;
57−};
58−
59−class GDateTimeFormatter : public TimeFormatter
60−{
61−public:
62− GDateTimeFormatter(QObject *parent = 0);
63−
64−protected:
65− QString formatTime() const override;
66−};
67−
68−#endif
qml/Panel/Indicators/MenuItemFactory.qml+18−14
@@ -346,20 +346,23 @@ Item {
346 id: alarmMenu;
346 id: alarmMenu;
347
347
348 Menus.EventMenu {
348 Menus.EventMenu {
349+ id: alarmItem
349 objectName: "alarmMenu"
350 objectName: "alarmMenu"
350 property QtObject menuData: null
351 property QtObject menuData: null
351 property var menuModel: menuFactory.menuModel
352 property var menuModel: menuFactory.menuModel
352 property int menuIndex: -1
353 property int menuIndex: -1
353 property var extendedData: menuData && menuData.ext || undefined
354 property var extendedData: menuData && menuData.ext || undefined
354− // TODO - bug #1260728
355+
355− property var timeFormatter: Utils.GDateTimeFormatter {
356+ property string serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000)
356− time: getExtendedProperty(extendedData, "xCanonicalTime", 0)
357+ LiveTimer {
358+ frequency: LiveTimer.Relative
359+ relativeTime: alarmItem.serverTime
357− format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "")
360+ onTrigger: alarmItem.serverTime = new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000)
358 }
361 }
359
362
360 text: menuData && menuData.label || ""
363 text: menuData && menuData.label || ""
361 iconSource: menuData && menuData.icon || "image://theme/alarm-clock"
364 iconSource: menuData && menuData.icon || "image://theme/alarm-clock"
362− time: timeFormatter.timeString
365+ time: i18n.relativeDateTime(serverTime)
363 enabled: menuData && menuData.sensitive || false
366 enabled: menuData && menuData.sensitive || false
364 highlightWhenPressed: false
367 highlightWhenPressed: false
365
368
@@ -375,8 +378,7 @@ Item {
375
378
376 function loadAttributes() {
379 function loadAttributes() {
377 if (!menuModel || menuIndex == -1) return;
380 if (!menuModel || menuIndex == -1) return;
378− menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64',
381+ menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64'});
379− 'x-canonical-time-format': 'string'});
380 }
382 }
381 }
383 }
382 }
384 }
@@ -385,20 +387,23 @@ Item {
385 id: appointmentMenu;
387 id: appointmentMenu;
386
388
387 Menus.EventMenu {
389 Menus.EventMenu {
390+ id: appointmentItem
388 objectName: "appointmentMenu"
391 objectName: "appointmentMenu"
389 property QtObject menuData: null
392 property QtObject menuData: null
390 property var menuModel: menuFactory.menuModel
393 property var menuModel: menuFactory.menuModel
391 property int menuIndex: -1
394 property int menuIndex: -1
392 property var extendedData: menuData && menuData.ext || undefined
395 property var extendedData: menuData && menuData.ext || undefined
393− // TODO - bug #1260728
396+
394− property var timeFormatter: Utils.GDateTimeFormatter {
397+ property string serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000)
395− time: getExtendedProperty(extendedData, "xCanonicalTime", 0)
398+ LiveTimer {
399+ frequency: LiveTimer.Relative
400+ relativeTime: appointmentItem.serverTime
396− format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "")
401+ onTrigger: appointmentItem.serverTime = new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000)
397 }
402 }
398
403
399 text: menuData && menuData.label || ""
404 text: menuData && menuData.label || ""
400 iconSource: menuData && menuData.icon || "image://theme/calendar"
405 iconSource: menuData && menuData.icon || "image://theme/calendar"
401− time: timeFormatter.timeString
406+ time: i18n.relativeDateTime(serverTime)
402 eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0))
407 eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0))
403 enabled: menuData && menuData.sensitive || false
408 enabled: menuData && menuData.sensitive || false
404 highlightWhenPressed: false
409 highlightWhenPressed: false
@@ -416,8 +421,7 @@ Item {
416 function loadAttributes() {
421 function loadAttributes() {
417 if (!menuModel || menuIndex == -1) return;
422 if (!menuModel || menuIndex == -1) return;
418 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-color': 'string',
423 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-color': 'string',
419− 'x-canonical-time': 'int64',
424+ 'x-canonical-time': 'int64'});
420− 'x-canonical-time-format': 'string'});
421 }
425 }
422 }
426 }
423 }
427 }
qml/Panel/Indicators/MessageMenuItemFactory.qml+30−22
@@ -35,12 +35,16 @@ Loader {
35 signal menuSelected
35 signal menuSelected
36 signal menuDeselected
36 signal menuDeselected
37
37
38+ QtObject {
39+ id: priv
38− property var extendedData: menuData && menuData.ext || undefined
40+ property var extendedData: menuData && menuData.ext || undefined
39− property var actionsDescription: getExtendedProperty(extendedData, "xCanonicalMessageActions", undefined)
41+ property var actionsDescription: getExtendedProperty(extendedData, "xCanonicalMessageActions", undefined)
40−
42+ property string time: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000000)
41− // TODO - bug #1260728
43+ }
42− property var timeFormatter: Utils.RelativeTimeFormatter {
44+ LiveTimer {
45+ frequency: LiveTimer.Relative
46+ relativeTime: priv.time
43− time: getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000000
47+ onTrigger: priv.time = new Date(getExtendedProperty(priv.extendedData, "xCanonicalTime", 0) / 1000000)
44 }
48 }
45
49
46 onMenuModelChanged: {
50 onMenuModelChanged: {
@@ -50,7 +54,7 @@ Loader {
50 loadAttributes();
54 loadAttributes();
51 }
55 }
52
56
53− sourceComponent: loadMessage(actionsDescription)
57+ sourceComponent: loadMessage(priv.actionsDescription)
54
58
55 function loadMessage(actions)
59 function loadMessage(actions)
56 {
60 {
@@ -100,11 +104,11 @@ Loader {
100 objectName: "simpleTextMessage"
104 objectName: "simpleTextMessage"
101 // text
105 // text
102 title: menuData && menuData.label || ""
106 title: menuData && menuData.label || ""
103− time: timeFormatter.timeString
107+ time: i18n.relativeDateTime(priv.time)
104− body: getExtendedProperty(extendedData, "xCanonicalText", "")
108+ body: getExtendedProperty(priv.extendedData, "xCanonicalText", "")
105 // icons
109 // icons
106− avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact")
110+ avatar: getExtendedProperty(priv.extendedData, "icon", "image://theme/contact")
107− icon: getExtendedProperty(extendedData, "xCanonicalAppIcon", "image://theme/message")
111+ icon: getExtendedProperty(priv.extendedData, "xCanonicalAppIcon", "image://theme/message")
108 // actions
112 // actions
109 enabled: menuData && menuData.sensitive || false
113 enabled: menuData && menuData.sensitive || false
110 removable: !selected
114 removable: !selected
@@ -133,7 +137,9 @@ Loader {
133 Menus.TextMessageMenu {
137 Menus.TextMessageMenu {
134 id: message
138 id: message
135 objectName: "textMessage"
139 objectName: "textMessage"
136− property var replyActionDescription: actionsDescription && actionsDescription.length > 0 ? actionsDescription[0] : undefined
140+ property var replyActionDescription: priv.actionsDescription && priv.actionsDescription.length > 0 ?
141+ priv.actionsDescription[0] :
142+ undefined
137
143
138 property var replyAction: QMenuModel.UnityMenuAction {
144 property var replyAction: QMenuModel.UnityMenuAction {
139 model: menuModel
145 model: menuModel
@@ -143,13 +149,13 @@ Loader {
143
149
144 // text
150 // text
145 title: menuData && menuData.label || ""
151 title: menuData && menuData.label || ""
146− time: timeFormatter.timeString
152+ time: i18n.relativeDateTime(priv.time)
147− body: getExtendedProperty(extendedData, "xCanonicalText", "")
153+ body: getExtendedProperty(priv.extendedData, "xCanonicalText", "")
148 replyButtonText: getExtendedProperty(replyActionDescription, "label", "Send")
154 replyButtonText: getExtendedProperty(replyActionDescription, "label", "Send")
149 replyHintText: i18n.ctr("Label: Hint in message indicator line edit", "Reply")
155 replyHintText: i18n.ctr("Label: Hint in message indicator line edit", "Reply")
150 // icons
156 // icons
151− avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact")
157+ avatar: getExtendedProperty(priv.extendedData, "icon", "image://theme/contact")
152− icon: getExtendedProperty(extendedData, "xCanonicalAppIcon", "image://theme/message")
158+ icon: getExtendedProperty(priv.extendedData, "xCanonicalAppIcon", "image://theme/message")
153 // actions
159 // actions
154 replyEnabled: replyAction.valid && replyAction.enabled
160 replyEnabled: replyAction.valid && replyAction.enabled
155 enabled: menuData && menuData.sensitive || false
161 enabled: menuData && menuData.sensitive || false
@@ -183,8 +189,10 @@ Loader {
183 Menus.SnapDecisionMenu {
189 Menus.SnapDecisionMenu {
184 id: message
190 id: message
185 objectName: "snapDecision"
191 objectName: "snapDecision"
186− property var activateActionDescription: actionsDescription && actionsDescription.length > 0 ? actionsDescription[0] : undefined
192+ property var activateActionDescription: priv.actionsDescription && priv.actionsDescription.length > 0 ?
193+ priv.actionsDescription[0] : undefined
187− property var replyActionDescription: actionsDescription && actionsDescription.length > 1 ? actionsDescription[1] : undefined
194+ property var replyActionDescription: priv.actionsDescription && priv.actionsDescription.length > 1 ?
195+ priv.actionsDescription[1] : undefined
188
196
189 property var activateAction: QMenuModel.UnityMenuAction {
197 property var activateAction: QMenuModel.UnityMenuAction {
190 model: menuModel
198 model: menuModel
@@ -199,13 +207,13 @@ Loader {
199
207
200 // text
208 // text
201 title: menuData && menuData.label || ""
209 title: menuData && menuData.label || ""
202− time: timeFormatter.timeString
210+ time: i18n.relativeDateTime(priv.time)
203− body: getExtendedProperty(extendedData, "xCanonicalText", "")
211+ body: getExtendedProperty(priv.extendedData, "xCanonicalText", "")
204 actionButtonText: getExtendedProperty(activateActionDescription, "label", "Call back")
212 actionButtonText: getExtendedProperty(activateActionDescription, "label", "Call back")
205 replyButtonText: getExtendedProperty(replyActionDescription, "label", "Send")
213 replyButtonText: getExtendedProperty(replyActionDescription, "label", "Send")
206 // icons
214 // icons
207− avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact")
215+ avatar: getExtendedProperty(priv.extendedData, "icon", "image://theme/contact")
208− icon: getExtendedProperty(extendedData, "xCanonicalAppIcon", "image://theme/missed-call")
216+ icon: getExtendedProperty(priv.extendedData, "xCanonicalAppIcon", "image://theme/missed-call")
209 // actions
217 // actions
210 actionEnabled: activateAction.valid && activateAction.enabled
218 actionEnabled: activateAction.valid && activateAction.enabled
211 replyEnabled: replyAction.valid && replyAction.enabled
219 replyEnabled: replyAction.valid && replyAction.enabled
tests/mocks/Utils/CMakeLists.txt−2
@@ -12,8 +12,6 @@ set(QMLPLUGIN_SRC
12 ${CMAKE_SOURCE_DIR}/plugins/Utils/inputwatcher.cpp
12 ${CMAKE_SOURCE_DIR}/plugins/Utils/inputwatcher.cpp
13 ${CMAKE_SOURCE_DIR}/plugins/Utils/qlimitproxymodelqml.cpp
13 ${CMAKE_SOURCE_DIR}/plugins/Utils/qlimitproxymodelqml.cpp
14 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
14 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
15− ${CMAKE_SOURCE_DIR}/plugins/Utils/relativetimeformatter.cpp
16− ${CMAKE_SOURCE_DIR}/plugins/Utils/timeformatter.cpp
17 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitymenumodelpaths.cpp
15 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitymenumodelpaths.cpp
18 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowkeysfilter.cpp
16 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowkeysfilter.cpp
19 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp
17 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp
tests/mocks/Utils/Utils.qmltypes+31−28
@@ -4,9 +4,18 @@ import QtQuick.tooling 1.1
4// It is used for QML tooling purposes only.
4// It is used for QML tooling purposes only.
5//
5//
6// This file was auto-generated by:
6// This file was auto-generated by:
7−// 'qmlplugindump -notrelocatable Utils 0.1 plugins'
7+// 'qmlplugindump -notrelocatable Utils 0.1 tests/mocks'
8
8
9Module {
9Module {
10+ Component {
11+ name: "Constants"
12+ prototype: "QObject"
13+ exports: ["Utils/Constants 0.1"]
14+ isCreatable: false
15+ isSingleton: true
16+ exportMetaObjectRevisions: [0]
17+ Property { name: "indicatorValueTimeout"; type: "int"; isReadonly: true }
18+ }
10 Component {
19 Component {
11 name: "EasingCurve"
20 name: "EasingCurve"
12 prototype: "QObject"
21 prototype: "QObject"
@@ -17,6 +26,22 @@ Module {
17 Property { name: "progress"; type: "double" }
26 Property { name: "progress"; type: "double" }
18 Property { name: "value"; type: "double"; isReadonly: true }
27 Property { name: "value"; type: "double"; isReadonly: true }
19 }
28 }
29+ Component {
30+ name: "InputWatcher"
31+ prototype: "QObject"
32+ exports: ["Utils/InputWatcher 0.1"]
33+ exportMetaObjectRevisions: [0]
34+ Property { name: "target"; type: "QObject"; isPointer: true }
35+ Property { name: "targetPressed"; type: "bool"; isReadonly: true }
36+ Signal {
37+ name: "targetChanged"
38+ Parameter { name: "value"; type: "QObject"; isPointer: true }
39+ }
40+ Signal {
41+ name: "targetPressedChanged"
42+ Parameter { name: "value"; type: "bool" }
43+ }
44+ }
20 Component {
45 Component {
21 name: "QAbstractProxyModel"
46 name: "QAbstractProxyModel"
22 prototype: "QAbstractItemModel"
47 prototype: "QAbstractItemModel"
@@ -59,33 +84,6 @@ Module {
59 Method { name: "clear" }
84 Method { name: "clear" }
60 Method { name: "invalidate" }
85 Method { name: "invalidate" }
61 }
86 }
62− Component {
63− name: "RelativeTimeFormatter"
64− prototype: "TimeFormatter"
65− exports: ["Utils/RelativeTimeFormatter 0.1"]
66− exportMetaObjectRevisions: [0]
67− }
68− Component {
69− name: "TimeFormatter"
70− prototype: "QObject"
71− exports: ["Utils/GDateTimeFormatter 0.1", "Utils/TimeFormatter 0.1"]
72− exportMetaObjectRevisions: [0, 0]
73− Property { name: "format"; type: "string" }
74− Property { name: "timeString"; type: "string"; isReadonly: true }
75− Property { name: "time"; type: "qlonglong" }
76− Signal {
77− name: "formatChanged"
78− Parameter { name: "format"; type: "string" }
79− }
80− Signal {
81− name: "timeStringChanged"
82− Parameter { name: "timeString"; type: "string" }
83− }
84− Signal {
85− name: "timeChanged"
86− Parameter { name: "time"; type: "qlonglong" }
87− }
88− }
89 Component {
87 Component {
90 name: "UnityMenuModelPaths"
88 name: "UnityMenuModelPaths"
91 prototype: "QObject"
89 prototype: "QObject"
@@ -160,6 +158,11 @@ Module {
160 isCreatable: false
158 isCreatable: false
161 isSingleton: true
159 isSingleton: true
162 exportMetaObjectRevisions: [0]
160 exportMetaObjectRevisions: [0]
161+ Property { name: "geometry"; type: "QVariantMap" }
162+ Signal {
163+ name: "geometryChanged"
164+ Parameter { name: "geometry"; type: "QVariantMap" }
165+ }
163 Method {
166 Method {
164 name: "saveGeometry"
167 name: "saveGeometry"
165 Parameter { name: "windowId"; type: "string" }
168 Parameter { name: "windowId"; type: "string" }
tests/mocks/Utils/plugin.cpp−5
@@ -30,8 +30,6 @@
30#include <inputwatcher.h>
30#include <inputwatcher.h>
31#include <qlimitproxymodelqml.h>
31#include <qlimitproxymodelqml.h>
32#include <unitysortfilterproxymodelqml.h>
32#include <unitysortfilterproxymodelqml.h>
33−#include <relativetimeformatter.h>
34−#include <timeformatter.h>
35#include <unitymenumodelpaths.h>
33#include <unitymenumodelpaths.h>
36#include <windowkeysfilter.h>
34#include <windowkeysfilter.h>
37#include <windowscreenshotprovider.h>
35#include <windowscreenshotprovider.h>
@@ -58,11 +56,8 @@ void FakeUtilsPlugin::registerTypes(const char *uri)
58 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
56 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
59 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
57 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
60 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
58 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
61− qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
62 qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
59 qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
63− qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
64 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
60 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
65− qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter");
66 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
61 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
67 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
62 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
68 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
63 qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants);
tests/plugins/Utils/CMakeLists.txt−1
@@ -7,7 +7,6 @@ include_directories(
7foreach(util_test
7foreach(util_test
8 QLimitProxyModel
8 QLimitProxyModel
9 UnitySortFilterProxyModel
9 UnitySortFilterProxyModel
10− TimeFormatter
11 HomeKeyWatcher
10 HomeKeyWatcher
12)
11)
13 add_executable(${util_test}TestExec ${util_test}Test.cpp ModelTest.cpp)
12 add_executable(${util_test}TestExec ${util_test}Test.cpp ModelTest.cpp)
tests/plugins/Utils/TimeFormatterTest.cppdeleted−155
@@ -1,155 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU Lesser General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU Lesser General Public License for more details.
12− *
13− * You should have received a copy of the GNU Lesser General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Lars Uebernickel <lars.uebernickel@canonical.com>
17− */
18−
19−#include "timeformatter.h"
20−#include "relativetimeformatter.h"
21−
22−#include <locale.h>
23−
24−#include <QtTest>
25−#include <QDebug>
26−
27−class TimeFormatterTest : public QObject
28−{
29− Q_OBJECT
30−private:
31− void addTestData(QList<int> daysToAdd = QList<int>()) {
32− QTest::addColumn<QDateTime>("time");
33−
34− Q_FOREACH(int dayToAdd, daysToAdd) {
35− QDateTime time = QDateTime::currentDateTime().addDays(dayToAdd);
36− QDateTime am(time); am.setTime(QTime(1, 1, 1));
37− QDateTime midday(time); midday.setTime(QTime(12, 0, 0));
38− QDateTime pm(time); pm.setTime(QTime(17, 59, 59));
39−
40− QTest::newRow(QString("%1day-am").arg(dayToAdd).toLatin1()) << am;
41− QTest::newRow(QString("%1day-midday").arg(dayToAdd).toLatin1()) << midday;
42− QTest::newRow(QString("%1day-pm").arg(dayToAdd).toLatin1()) << pm;
43− }
44−
45− }
46−
47−private Q_SLOTS:
48− void testTimeFormatter_Format_data() { addTestData(QList<int>() << 0); }
49− void testTimeFormatter_Format()
50− {
51− QFETCH(QDateTime, time);
52− const QString format = "hh:mm dd.MM.yy";
53−
54− TimeFormatter formatter;
55− formatter.setTime(time.toMSecsSinceEpoch() * 1000);
56− formatter.setFormat(format);
57−
58− QCOMPARE(formatter.timeString(), time.toString(format));
59− }
60−
61− void tesGDatetTimeFormatter_Format_data() { addTestData(QList<int>() << 0); }
62− void tesGDatetTimeFormatter_Format()
63− {
64− QFETCH(QDateTime, time);
65− const QString format = "%d-%m-%Y %I:%M%p";
66−
67− GDateTimeFormatter formatter;
68− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
69− formatter.setFormat(format);
70−
71− QCOMPARE(formatter.timeString(), time.toString("dd-MM-yyyy hh:mmAP"));
72− }
73−
74− void tesRelativeTimeFormatter_FarBack_data() { addTestData(QList<int>() << -200 << -20 << -7); }
75− void tesRelativeTimeFormatter_FarBack()
76− {
77− QFETCH(QDateTime, time);
78−
79− RelativeTimeFormatter formatter;
80− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
81−
82− QCOMPARE(formatter.timeString(), time.toString("ddd dd MMM\u2003HH:mm"));
83− }
84−
85− void tesRelativeTimeFormatter_WeekBack_data() { addTestData(QList<int>() << -6 << -2); }
86− void tesRelativeTimeFormatter_WeekBack()
87− {
88− QFETCH(QDateTime, time);
89−
90− RelativeTimeFormatter formatter;
91− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
92−
93− QCOMPARE(formatter.timeString(), time.toString("ddd\u2003HH:mm"));
94− }
95−
96− void tesRelativeTimeFormatter_Yesterday_data() { addTestData(QList<int>() << -1); }
97− void tesRelativeTimeFormatter_Yesterday()
98− {
99− QFETCH(QDateTime, time);
100−
101− RelativeTimeFormatter formatter;
102− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
103−
104− QCOMPARE(formatter.timeString(), QString("Yesterday\u2003%1").arg(time.toString("HH:mm")));
105− }
106−
107− void tesRelativeTimeFormatter_Today_data() { addTestData(QList<int>() << 0); }
108− void tesRelativeTimeFormatter_Today()
109− {
110− QFETCH(QDateTime, time);
111−
112− RelativeTimeFormatter formatter;
113− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
114−
115− QCOMPARE(formatter.timeString(), time.toString("HH:mm"));
116− }
117−
118− void tesRelativeTimeFormatter_Tomorrow_data() { addTestData(QList<int>() << 1); }
119− void tesRelativeTimeFormatter_Tomorrow()
120− {
121− QFETCH(QDateTime, time);
122−
123− RelativeTimeFormatter formatter;
124− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
125−
126− QCOMPARE(formatter.timeString(), QString("Tomorrow\u2003%1").arg(time.toString("HH:mm")));
127− }
128−
129−
130− void tesRelativeTimeFormatter_WeekForward_data() { addTestData(QList<int>() << 2 << 6); }
131− void tesRelativeTimeFormatter_WeekForward()
132− {
133− QFETCH(QDateTime, time);
134−
135− RelativeTimeFormatter formatter;
136− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
137−
138− QCOMPARE(formatter.timeString(), time.toString("ddd\u2003HH:mm"));
139− }
140−
141− void tesRelativeTimeFormatter_FarForward_data() { addTestData(QList<int>() << 7 << 20 << 200); }
142− void tesRelativeTimeFormatter_FarForward()
143− {
144− QFETCH(QDateTime, time);
145−
146− RelativeTimeFormatter formatter;
147− formatter.setTime(time.toMSecsSinceEpoch() / 1000); // strftime in seconds since epoc
148−
149− QCOMPARE(formatter.timeString(), time.toString("ddd dd MMM\u2003HH:mm"));
150− }
151−};
152−
153−QTEST_GUILESS_MAIN(TimeFormatterTest)
154−
155−#include "TimeFormatterTest.moc"
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+6−16
@@ -50,10 +50,6 @@ Item {
50 }
50 }
51 }
51 }
52
52
53− Utils.GDateTimeFormatter {
54− id: timeFormatter
55− }
56−
57 UT.UnityTestCase {
53 UT.UnityTestCase {
58 name: "MenuItemFactory"
54 name: "MenuItemFactory"
59 when: windowShown
55 when: windowShown
@@ -374,9 +370,9 @@ Item {
374 function test_create_alarmMenu_data() {
370 function test_create_alarmMenu_data() {
375 return [
371 return [
376 {label: "testLabel1", enabled: true, icon: "file:///testIcon1", color: Qt.rgba(0, 0, 0, 0),
372 {label: "testLabel1", enabled: true, icon: "file:///testIcon1", color: Qt.rgba(0, 0, 0, 0),
377− time: new Date(2014, 04, 14), timeFormat: "%a %d %b %l:%M %p"},
373+ time: new Date(2014, 04, 14)},
378 {label: "testLabel2", enabled: false, icon: "file:///testIcon2", color: Qt.rgba(1, 0, 0, 0),
374 {label: "testLabel2", enabled: false, icon: "file:///testIcon2", color: Qt.rgba(1, 0, 0, 0),
379− time: new Date(2015, 11, 31), timeFormat: "%A" },
375+ time: new Date(2015, 11, 31) },
380 ];
376 ];
381 }
377 }
382
378
@@ -386,11 +382,8 @@ Item {
386 menuData.sensitive = data.enabled;
382 menuData.sensitive = data.enabled;
387 menuData.icon = data.icon;
383 menuData.icon = data.icon;
388 menuData.ext = {
384 menuData.ext = {
389− 'xCanonicalTime': data.time.getTime() / 1000,
385+ 'xCanonicalTime': data.time.getTime() * 1000
390− 'xCanonicalTimeFormat': data.timeFormat
391 };
386 };
392− timeFormatter.format = data.timeFormat;
393− timeFormatter.time = data.time.getTime() / 1000;
394
387
395 loader.data = menuData;
388 loader.data = menuData;
396 loader.sourceComponent = factory.load(menuData);
389 loader.sourceComponent = factory.load(menuData);
@@ -399,7 +392,7 @@ Item {
399
392
400 compare(loader.item.text, data.label, "Label does not match data");
393 compare(loader.item.text, data.label, "Label does not match data");
401 compare(loader.item.iconSource, data.icon, "Icon does not match data");
394 compare(loader.item.iconSource, data.icon, "Icon does not match data");
402− compare(loader.item.time, timeFormatter.timeString, "Time does not match data");
395+ compare(loader.item.time, i18n.relativeDateTime(data.time), "Time does not match data");
403 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
396 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
404 }
397 }
405
398
@@ -419,11 +412,8 @@ Item {
419 menuData.icon = data.icon;
412 menuData.icon = data.icon;
420 menuData.ext = {
413 menuData.ext = {
421 'xCanonicalColor': data.colour,
414 'xCanonicalColor': data.colour,
422− 'xCanonicalTime': data.time.getTime() / 1000,
415+ 'xCanonicalTime': data.time.getTime() * 1000
423− 'xCanonicalTimeFormat': data.timeFormat
424 };
416 };
425− timeFormatter.format = data.timeFormat;
426− timeFormatter.time = data.time.getTime() / 1000;
427
417
428 loader.data = menuData;
418 loader.data = menuData;
429 loader.sourceComponent = factory.load(menuData);
419 loader.sourceComponent = factory.load(menuData);
@@ -432,7 +422,7 @@ Item {
432
422
433 compare(loader.item.text, data.label, "Label does not match data");
423 compare(loader.item.text, data.label, "Label does not match data");
434 compare(loader.item.iconSource, data.icon, "Icon does not match data");
424 compare(loader.item.iconSource, data.icon, "Icon does not match data");
435− compare(loader.item.time, timeFormatter.timeString, "Time does not match data");
425+ compare(loader.item.time, i18n.relativeDateTime(data.time), "Time does not match data");
436 compare(loader.item.eventColor, data.color, "Colour does not match data");
426 compare(loader.item.eventColor, data.color, "Colour does not match data");
437 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
427 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
438 }
428 }
tests/qmltests/Panel/Indicators/tst_MessageMenuItemFactory.qml+6−13
@@ -32,10 +32,6 @@ Item {
32 menuIndex: 0
32 menuIndex: 0
33 }
33 }
34
34
35− Utils.RelativeTimeFormatter {
36− id: timeFormatter
37− }
38−
39 UT.UnityTestCase {
35 UT.UnityTestCase {
40 name: "MessageMenuItemFactory"
36 name: "MessageMenuItemFactory"
41 when: windowShown
37 when: windowShown
@@ -82,17 +78,16 @@ Item {
82 menuData.label = data.title;
78 menuData.label = data.title;
83 menuData.sensitive = data.enabled;
79 menuData.sensitive = data.enabled;
84 menuData.ext = {
80 menuData.ext = {
85− 'xCanonicalTime': data.time.getTime()*1000,
81+ 'xCanonicalTime': data.time.getTime()*1000000,
86 'xCanonicalText': data.body,
82 'xCanonicalText': data.body,
87 'icon': data.avatar,
83 'icon': data.avatar,
88 'xCanonicalAppIcon': data.icon,
84 'xCanonicalAppIcon': data.icon,
89 };
85 };
90 factory.menuData = menuData;
86 factory.menuData = menuData;
91− timeFormatter.time = data.time.getTime()/1000;
92
87
93 tryCompare(factory.item, "objectName", "simpleTextMessage");
88 tryCompare(factory.item, "objectName", "simpleTextMessage");
94 compare(factory.item.title, data.title, "Title does not match data");
89 compare(factory.item.title, data.title, "Title does not match data");
95− compare(factory.item.time, timeFormatter.timeString, "Time does not match data");
90+ compare(factory.item.time, i18n.relativeDateTime(data.time), "Time does not match data");
96 compare(factory.item.body, data.body, "Message does not match data");
91 compare(factory.item.body, data.body, "Message does not match data");
97 compare(factory.item.avatar, data.avatar, "Avatar does not match data");
92 compare(factory.item.avatar, data.avatar, "Avatar does not match data");
98 compare(factory.item.icon, data.icon, "App icon does not match data");
93 compare(factory.item.icon, data.icon, "App icon does not match data");
@@ -111,7 +106,7 @@ Item {
111 menuData.label = data.title;
106 menuData.label = data.title;
112 menuData.sensitive = data.enabled;
107 menuData.sensitive = data.enabled;
113 menuData.ext = {
108 menuData.ext = {
114− 'xCanonicalTime': data.time.getTime()*1000,
109+ 'xCanonicalTime': data.time.getTime()*1000000,
115 'xCanonicalText': data.body,
110 'xCanonicalText': data.body,
116 'icon': data.avatar,
111 'icon': data.avatar,
117 'xCanonicalAppIcon': data.icon,
112 'xCanonicalAppIcon': data.icon,
@@ -123,11 +118,10 @@ Item {
123 ]
118 ]
124 };
119 };
125 factory.menuData = menuData;
120 factory.menuData = menuData;
126− timeFormatter.time = data.time.getTime()/1000;
127
121
128 tryCompare(factory.item, "objectName", "textMessage");
122 tryCompare(factory.item, "objectName", "textMessage");
129 compare(factory.item.title, data.title, "Title does not match data");
123 compare(factory.item.title, data.title, "Title does not match data");
130− compare(factory.item.time, timeFormatter.timeString, "Time does not match data");
124+ compare(factory.item.time, i18n.relativeDateTime(data.time), "Time does not match data");
131 compare(factory.item.body, data.body, "Message does not match data");
125 compare(factory.item.body, data.body, "Message does not match data");
132 compare(factory.item.avatar, data.avatar, "Avatar does not match data");
126 compare(factory.item.avatar, data.avatar, "Avatar does not match data");
133 compare(factory.item.icon, data.icon, "App icon does not match data");
127 compare(factory.item.icon, data.icon, "App icon does not match data");
@@ -147,7 +141,7 @@ Item {
147 menuData.label = data.title;
141 menuData.label = data.title;
148 menuData.sensitive = data.enabled;
142 menuData.sensitive = data.enabled;
149 menuData.ext = {
143 menuData.ext = {
150− 'xCanonicalTime': data.time.getTime()*1000,
144+ 'xCanonicalTime': data.time.getTime()*1000000,
151 'xCanonicalText': data.body,
145 'xCanonicalText': data.body,
152 'icon': data.avatar,
146 'icon': data.avatar,
153 'xCanonicalAppIcon': data.icon,
147 'xCanonicalAppIcon': data.icon,
@@ -162,11 +156,10 @@ Item {
162 ]
156 ]
163 };
157 };
164 factory.menuData = menuData;
158 factory.menuData = menuData;
165− timeFormatter.time = data.time.getTime()/1000;
166
159
167 tryCompare(factory.item, "objectName", "snapDecision");
160 tryCompare(factory.item, "objectName", "snapDecision");
168 compare(factory.item.title, data.title, "Title does not match data");
161 compare(factory.item.title, data.title, "Title does not match data");
169− compare(factory.item.time, timeFormatter.timeString, "Time does not match data");
162+ compare(factory.item.time, i18n.relativeDateTime(data.time), "Time does not match data");
170 compare(factory.item.body, data.body, "Message does not match data");
163 compare(factory.item.body, data.body, "Message does not match data");
171 compare(factory.item.avatar, data.avatar, "Avatar does not match data");
164 compare(factory.item.avatar, data.avatar, "Avatar does not match data");
172 compare(factory.item.icon, data.icon, "App icon does not match data");
165 compare(factory.item.icon, data.icon, "App icon does not match data");