on xenial help sign in
use time formatter from sdk
5d642b6Nick Dedekind
debian/control+3−3
@@ -49,7 +49,7 @@ Build-Depends: cmake,
49 qtdeclarative5-private-dev (>= 5.2.1),
49 qtdeclarative5-private-dev (>= 5.2.1),
50 qtdeclarative5-qtmultimedia-plugin,
50 qtdeclarative5-qtmultimedia-plugin,
51 qtdeclarative5-ubuntu-settings-components (>= 0.6),
51 qtdeclarative5-ubuntu-settings-components (>= 0.6),
52− qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
52+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1550) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1550),
53 qtdeclarative5-ubuntu-web-plugin,
53 qtdeclarative5-ubuntu-web-plugin,
54 ttf-ubuntu-font-family,
54 ttf-ubuntu-font-family,
55Standards-Version: 3.9.4
55Standards-Version: 3.9.4
@@ -64,7 +64,7 @@ X-Ubuntu-Use-Langpack: yes
64Package: indicators-client
64Package: indicators-client
65Architecture: amd64 armhf i386
65Architecture: amd64 armhf i386
66Depends: qmenumodel-qml (>= 0.2.9),
66Depends: qmenumodel-qml (>= 0.2.9),
67− qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
67+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1550) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1550),
68 unity8 (= ${binary:Version}),
68 unity8 (= ${binary:Version}),
69 ${misc:Depends},
69 ${misc:Depends},
70 ${shlibs:Depends},
70 ${shlibs:Depends},
@@ -122,7 +122,7 @@ Architecture: all
122Depends: qml-module-qtquick-layouts,
122Depends: qml-module-qtquick-layouts,
123 qtdeclarative5-ubuntu-settings-components (>= 0.6),
123 qtdeclarative5-ubuntu-settings-components (>= 0.6),
124 qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
124 qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
125− qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
125+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1550) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1550),
126 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
126 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
127 ubuntu-thumbnailer-impl-0,
127 ubuntu-thumbnailer-impl-0,
128 unity-application-impl-6,
128 unity-application-impl-6,
plugins/Utils/CMakeLists.txt−2
@@ -14,8 +14,6 @@ set(QMLPLUGIN_SRC
14 inputwatcher.cpp
14 inputwatcher.cpp
15 qlimitproxymodelqml.cpp
15 qlimitproxymodelqml.cpp
16 unitysortfilterproxymodelqml.cpp
16 unitysortfilterproxymodelqml.cpp
17− relativetimeformatter.cpp
18− timeformatter.cpp
19 Timer.cpp
17 Timer.cpp
20 unitymenumodelpaths.cpp
18 unitymenumodelpaths.cpp
21 windowkeysfilter.cpp
19 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+19−15
@@ -23,7 +23,7 @@ import Ubuntu.Settings.Components 0.1
23import QMenuModel 0.1
23import QMenuModel 0.1
24import Utils 0.1 as Utils
24import Utils 0.1 as Utils
25import Ubuntu.Components.ListItems 0.1 as ListItems
25import Ubuntu.Components.ListItems 0.1 as ListItems
26−import Ubuntu.Components 1.1
26+import Ubuntu.Components 1.3
27
27
28Item {
28Item {
29 id: menuFactory
29 id: menuFactory
@@ -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 date 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 date 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+31−23
@@ -19,7 +19,7 @@
19 */
19 */
20
20
21import QtQuick 2.0
21import QtQuick 2.0
22−import Ubuntu.Components 0.1
22+import Ubuntu.Components 1.3
23import Ubuntu.Settings.Menus 0.1 as Menus
23import Ubuntu.Settings.Menus 0.1 as Menus
24import QMenuModel 0.1 as QMenuModel
24import QMenuModel 0.1 as QMenuModel
25import Utils 0.1 as Utils
25import Utils 0.1 as Utils
@@ -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 date time: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000)
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) / 1000)
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", i18n.tr("Call back"))
212 actionButtonText: getExtendedProperty(activateActionDescription, "label", i18n.tr("Call back"))
205 replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.tr("Send"))
213 replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.tr("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 @@ include_directories(
12set(QMLPLUGIN_SRC
12set(QMLPLUGIN_SRC
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−13
@@ -23,14 +23,6 @@
23
23
24// local
24// local
25#include "plugin.h"
25#include "plugin.h"
26−#include "inputwatcher.h"
27−#include "qlimitproxymodelqml.h"
28−#include "unitysortfilterproxymodelqml.h"
29−#include "relativetimeformatter.h"
30−#include "timeformatter.h"
31−#include "unitymenumodelpaths.h"
32−#include "windowkeysfilter.h"
33−#include "easingcurve.h"
34#include "windowstatestorage.h"
26#include "windowstatestorage.h"
35#include "constants.h"
27#include "constants.h"
36
28
@@ -38,8 +30,6 @@
38#include <inputwatcher.h>
30#include <inputwatcher.h>
39#include <qlimitproxymodelqml.h>
31#include <qlimitproxymodelqml.h>
40#include <unitysortfilterproxymodelqml.h>
32#include <unitysortfilterproxymodelqml.h>
41−#include <relativetimeformatter.h>
42−#include <timeformatter.h>
43#include <unitymenumodelpaths.h>
33#include <unitymenumodelpaths.h>
44#include <windowkeysfilter.h>
34#include <windowkeysfilter.h>
45#include <windowscreenshotprovider.h>
35#include <windowscreenshotprovider.h>
@@ -66,11 +56,8 @@ void FakeUtilsPlugin::registerTypes(const char *uri)
66 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
56 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
67 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
57 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
68 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
58 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
69− qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
70 qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
59 qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
71− qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter");
72 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
60 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
73− qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter");
74 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
61 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
75 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
62 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
76 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 // expected in seconds
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 // expected in seconds
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()*1000, // expected in microseconds
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()*1000, // expected in microseconds
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()*1000, // expected in microseconds
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");