Merge lp:~nick-dedekind/ubuntu-ui-toolkit/lp1378821.time-translation into lp:ubuntu-ui-toolkit
- lp1378821.time-translation
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~nick-dedekind/ubuntu-ui-toolkit/lp1378821.time-translation |
Merge into: | lp:ubuntu-ui-toolkit |
Diff against target: |
905 lines (+718/-24) 10 files modified
debian/changelog (+7/-0) modules/Ubuntu/Components/plugin/plugin.cpp (+2/-2) modules/Ubuntu/Components/plugin/plugin.pro (+5/-2) modules/Ubuntu/Components/plugin/timeformatter.cpp (+199/-0) modules/Ubuntu/Components/plugin/timeformatter.h (+61/-0) modules/Ubuntu/Components/plugin/timeformatter_p.h (+177/-0) po/ubuntu-ui-toolkit.pot (+133/-19) tests/unit/tst_components/dateExt.js (+67/-0) tests/unit/tst_components/tst_components.pro (+2/-1) tests/unit/tst_components/tst_timeformatter.qml (+65/-0) |
To merge this branch: | bzr merge lp:~nick-dedekind/ubuntu-ui-toolkit/lp1378821.time-translation |
Related bugs: | |
Related blueprints: |
A generic, flexible time formatter
(Undefined)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Cris Dywan | Needs Fixing | ||
Zoltan Balogh | Needs Fixing | ||
PS Jenkins bot | continuous-integration | Needs Fixing | |
Review via email: mp+246191@code.launchpad.net |
Commit message
Move the time formatter to SDK.
Description of the change
Move the time formatter to SDK.
PS Jenkins bot (ps-jenkins) wrote : | # |
Michał Sawicz (saviq) wrote : | # |
You need to update the .api file here.
Zoltan Balogh (bzoltan) wrote : | # |
Please re-target the MR to the rtm or the staging branch.
Cris Dywan (kalikiana) wrote : | # |
First and foremost, let's have an API proposal for this. Adding new API to the UITK means it will stay for a few years and if we just drop code like this we get in trouble (thumbnailer anyone?).
Second, we already have i18n for localization features. It seems to me like we'd want to extend that instead of a whole new component.
Third, how urgent is this? Who's using this aside from Unity? API should only be added to UITK if it's useful for several apps, otherwise there's little benefit and we still pay the cost of maintenance.
Albert Astals Cid (aacid) wrote : | # |
Are you telling me you can't really see the use case for this in multiple apps? Phone? Calendar? Email?
Michał Sawicz (saviq) wrote : | # |
FWIW, see the linked spec for use cases for this:
https:/
Cris Dywan (kalikiana) wrote : | # |
Albert, when I asked in IRC I was told Unity was the only currently known use case. It's not about whether I can envision use cases but we need to know who will use the API so that we know if it actually solves the problem.
Thanks for the blueprint!
The point "Timestamps displayed differently depending on the available space" needs clarification. Is this explicitly to be done by the application or part of the formatter?
Please extend API proposal 1 https:/
A short brainstorming meeting might be helpful, if you're interested we should arrange one in IRC.
- 1120. By Nick Dedekind
-
live timer
- 1121. By Nick Dedekind
-
fixed time translation
- 1122. By Nick Dedekind
-
updated potfile
- 1123. By Nick Dedekind
-
LiveTimer & i18n.relativeDa
teTime tests - 1124. By Nick Dedekind
-
version bumped
- 1125. By Nick Dedekind
-
merged with trunk
- 1126. By Nick Dedekind
-
updated potfile
- 1127. By Nick Dedekind
-
removed old file
- 1128. By Nick Dedekind
-
version bump
- 1129. By Nick Dedekind
-
updated api
- 1130. By Nick Dedekind
-
reverted old changelogs
- 1131. By Nick Dedekind
-
better frequency handling
- 1132. By Nick Dedekind
-
whitespace
- 1133. By Nick Dedekind
-
unsubscribe live timer on destruction
Unmerged revisions
- 1133. By Nick Dedekind
-
unsubscribe live timer on destruction
- 1132. By Nick Dedekind
-
whitespace
- 1131. By Nick Dedekind
-
better frequency handling
- 1130. By Nick Dedekind
-
reverted old changelogs
- 1129. By Nick Dedekind
-
updated api
- 1128. By Nick Dedekind
-
version bump
- 1127. By Nick Dedekind
-
removed old file
- 1126. By Nick Dedekind
-
updated potfile
- 1125. By Nick Dedekind
-
merged with trunk
- 1124. By Nick Dedekind
-
version bumped
Preview Diff
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2014-12-17 09:52:56 +0000 |
3 | +++ debian/changelog 2015-01-12 17:27:26 +0000 |
4 | @@ -348,6 +348,13 @@ |
5 | |
6 | -- Zoltán Balogh <zoltan@bakter.hu> Fri, 10 Oct 2014 11:19:10 +0300 |
7 | |
8 | +ubuntu-ui-toolkit (1.1.1279.2-0ubuntu1) UNRELEASED; urgency=medium |
9 | + |
10 | + [ Nick Dedekind ] |
11 | + * Added time formatter |
12 | + |
13 | + -- Nick Dedekind <nick.dedekind@canonical.com> Mon, 15 Dec 2014 09:57:12 +0000 |
14 | + |
15 | ubuntu-ui-toolkit (1.1.1279.1+14.10.20141014-0ubuntu1) 14.09; urgency=low |
16 | |
17 | [ Ubuntu daily release ] |
18 | |
19 | === modified file 'modules/Ubuntu/Components/plugin/plugin.cpp' |
20 | --- modules/Ubuntu/Components/plugin/plugin.cpp 2014-12-03 14:43:27 +0000 |
21 | +++ modules/Ubuntu/Components/plugin/plugin.cpp 2015-01-12 17:27:26 +0000 |
22 | @@ -35,6 +35,7 @@ |
23 | #include "inversemouseareatype.h" |
24 | #include "qquickclipboard.h" |
25 | #include "qquickmimedata.h" |
26 | +#include "timeformatter.h" |
27 | #include "ucubuntuanimation.h" |
28 | #include "ucfontutils.h" |
29 | #include "ucarguments.h" |
30 | @@ -166,11 +167,10 @@ |
31 | qmlRegisterType<QSortFilterProxyModelQML>(uri, 1, 1, "SortFilterModel"); |
32 | qmlRegisterUncreatableType<FilterBehavior>(uri, 1, 1, "FilterBehavior", "Not instantiable"); |
33 | qmlRegisterUncreatableType<SortBehavior>(uri, 1, 1, "SortBehavior", "Not instantiable"); |
34 | - |
35 | - // ListItem and related types, released to 1.2 |
36 | qmlRegisterType<UCListItem, 2>(uri, 1, 2, "ListItem"); |
37 | qmlRegisterType<UCListItemDivider>(); |
38 | qmlRegisterType<UCListItemActions, 2>(uri, 1, 2, "ListItemActions"); |
39 | + qmlRegisterType<TimeFormatter>(uri, 1, 1, "TimeFormatter"); |
40 | } |
41 | |
42 | void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
43 | |
44 | === modified file 'modules/Ubuntu/Components/plugin/plugin.pro' |
45 | --- modules/Ubuntu/Components/plugin/plugin.pro 2014-12-03 14:43:27 +0000 |
46 | +++ modules/Ubuntu/Components/plugin/plugin.pro 2015-01-12 17:27:26 +0000 |
47 | @@ -72,7 +72,9 @@ |
48 | uclistitemactions.h \ |
49 | uclistitemactions_p.h \ |
50 | propertychange_p.h \ |
51 | - uclistitemstyle.h |
52 | + uclistitemstyle.h \ |
53 | + timeformatter.h \ |
54 | + timeformatter_p.h |
55 | |
56 | SOURCES += plugin.cpp \ |
57 | uctheme.cpp \ |
58 | @@ -114,7 +116,8 @@ |
59 | uclistitemactionsattached.cpp \ |
60 | uclistitemattached.cpp \ |
61 | propertychange_p.cpp \ |
62 | - uclistitemstyle.cpp |
63 | + uclistitemstyle.cpp \ |
64 | + timeformatter.cpp |
65 | |
66 | # adapters |
67 | SOURCES += adapters/alarmsadapter_organizer.cpp |
68 | |
69 | === added file 'modules/Ubuntu/Components/plugin/timeformatter.cpp' |
70 | --- modules/Ubuntu/Components/plugin/timeformatter.cpp 1970-01-01 00:00:00 +0000 |
71 | +++ modules/Ubuntu/Components/plugin/timeformatter.cpp 2015-01-12 17:27:26 +0000 |
72 | @@ -0,0 +1,199 @@ |
73 | +/* |
74 | + * Copyright 2014 Canonical Ltd. |
75 | + * |
76 | + * This program is free software; you can redistribute it and/or modify |
77 | + * it under the terms of the GNU General Public License as published by |
78 | + * the Free Software Foundation; version 3. |
79 | + * |
80 | + * This program is distributed in the hope that it will be useful, |
81 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
82 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
83 | + * GNU General Public License for more details. |
84 | + * |
85 | + * You should have received a copy of the GNU General Public License |
86 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
87 | + */ |
88 | + |
89 | +#include "timeformatter.h" |
90 | +#include "timeformatter_p.h" |
91 | + |
92 | +TimeFormatterShared* TimeFormatterShared::s_timeformatter = NULL; |
93 | + |
94 | +TimeFormatterShared::TimeFormatterShared() |
95 | +{ |
96 | + QDBusConnection::systemBus().connect("org.freedesktop.timedate1", |
97 | + "/org/freedesktop/timedate1", |
98 | + "org.freedesktop.DBus.Properties", |
99 | + "PropertiesChanged", |
100 | + this, |
101 | + SLOT(timedate1PropertiesChanged(QString, QVariantMap, QStringList))); |
102 | +} |
103 | + |
104 | +QString TimeFormatterPrivate::relativeTime(const QDateTime &datetime) |
105 | +{ |
106 | + QDateTime now = m_timeSource ? m_timeSource->property("time").toDateTime() : QDateTime::currentDateTime(); |
107 | + const date_proximity_t prox = getDateProximity(now, datetime); |
108 | + |
109 | + switch (prox) { |
110 | + case DATE_PROXIMITY_NOW: |
111 | + m_proximityTimer.setInterval(1000); |
112 | + if (!m_proximityTimer.isActive()) m_proximityTimer.start(); |
113 | + |
114 | + /* TRANSLATORS: Time based "this is happening/happened now" */ |
115 | + return UbuntuI18n::instance().tr("Now"); |
116 | + |
117 | + case DATE_PROXIMITY_HOUR: |
118 | + { |
119 | + m_proximityTimer.setInterval(1000); |
120 | + if (!m_proximityTimer.isActive()) m_proximityTimer.start(); |
121 | + |
122 | + qint64 diff = datetime.toMSecsSinceEpoch() - now.toMSecsSinceEpoch(); |
123 | + qint64 minutes = qRound(float(diff) / 60000); |
124 | + if (minutes < 0) { |
125 | + if (minutes == -1) return UbuntuI18n::instance().tr("%1 minute ago").arg(qAbs(minutes)); |
126 | + return UbuntuI18n::instance().tr("%1 minutes ago").arg(qAbs(minutes)); |
127 | + } |
128 | + if (minutes == 1) return UbuntuI18n::instance().tr("%1 minute").arg(qAbs(minutes)); |
129 | + return UbuntuI18n::instance().tr("%1 minutes").arg(qAbs(minutes)); |
130 | + } |
131 | + |
132 | + case DATE_PROXIMITY_TODAY: |
133 | + /* en_US example: "1:00 PM" */ |
134 | + m_proximityTimer.stop(); |
135 | + /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
136 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
137 | + return datetime.toString(isLocale12h() ? UbuntuI18n::instance().tr("h:mm ap"): |
138 | + /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
139 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
140 | + UbuntuI18n::instance().tr("HH:mm")); |
141 | + |
142 | + case DATE_PROXIMITY_YESTERDAY: |
143 | + /* en_US example: "Yesterday 13:00" */ |
144 | + m_proximityTimer.stop(); |
145 | + /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
146 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
147 | + return datetime.toString(isLocale12h() ? UbuntuI18n::instance().tr("'Yesterday\u2003'h:mm ap") : |
148 | + /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
149 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
150 | + UbuntuI18n::instance().tr("'Yesterday\u2003'HH:mm")); |
151 | + |
152 | + case DATE_PROXIMITY_TOMORROW: |
153 | + /* en_US example: "Tomorrow 1:00 PM" */ |
154 | + /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
155 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
156 | + return datetime.toString(isLocale12h() ? UbuntuI18n::instance().tr("'Tomorrow\u2003'h:mm ap") : |
157 | + /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
158 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
159 | + UbuntuI18n::instance().tr("'Tomorrow\u2003'HH:mm")); |
160 | + |
161 | + case DATE_PROXIMITY_LAST_WEEK: |
162 | + case DATE_PROXIMITY_NEXT_WEEK: |
163 | + /* en_US example: "Fri 1:00 PM" */ |
164 | + m_proximityTimer.stop(); |
165 | + /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
166 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
167 | + return datetime.toString(isLocale12h() ? UbuntuI18n::instance().tr("ddd'\u2003'h:mm ap") : |
168 | + /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
169 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
170 | + UbuntuI18n::instance().tr("ddd'\u2003'HH:mm")); |
171 | + |
172 | + case DATE_PROXIMITY_FAR: |
173 | + default: |
174 | + m_proximityTimer.stop(); |
175 | + /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
176 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
177 | + return datetime.toString(isLocale12h() ? UbuntuI18n::instance().tr("ddd d MMM'\u2003'h:mm ap") : |
178 | + /* TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
179 | + https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 */ |
180 | + UbuntuI18n::instance().tr("ddd d MMM'\u2003'HH:mm")); |
181 | + } |
182 | + m_proximityTimer.stop(); |
183 | + return datetime.toString(Qt::DefaultLocaleShortDate); |
184 | +} |
185 | + |
186 | +TimeFormatter::TimeFormatter(QObject *parent) |
187 | + : QObject(parent) |
188 | + , d(new TimeFormatterPrivate) |
189 | +{ |
190 | + connect(TimeFormatterShared::s_timeformatter, &TimeFormatterShared::updated, this, &TimeFormatter::update); |
191 | + connect(&d->m_proximityTimer, &QTimer::timeout, this, &TimeFormatter::update); |
192 | +} |
193 | + |
194 | +TimeFormatter::~TimeFormatter() |
195 | +{ |
196 | +} |
197 | + |
198 | +QString TimeFormatter::format() const |
199 | +{ |
200 | + return d->m_format; |
201 | +} |
202 | + |
203 | +QString TimeFormatter::timeString() const |
204 | +{ |
205 | + return d->m_timeString; |
206 | +} |
207 | + |
208 | +qint64 TimeFormatter::millisecondsSinceEpoc() const |
209 | +{ |
210 | + return d->m_millisecondsSinceEpoc; |
211 | +} |
212 | + |
213 | +bool TimeFormatter::relative() const |
214 | +{ |
215 | + return d->m_relative; |
216 | +} |
217 | + |
218 | +QObject* TimeFormatter::timeSource() const |
219 | +{ |
220 | + return d->m_timeSource; |
221 | +} |
222 | + |
223 | +void TimeFormatter::setFormat(const QString &format) |
224 | +{ |
225 | + if (d->m_format != format) { |
226 | + d->m_format = format; |
227 | + Q_EMIT formatChanged(d->m_format); |
228 | + update(); |
229 | + } |
230 | +} |
231 | + |
232 | +void TimeFormatter::setMilliSeccondsSinceEpoc(qint64 millisecondsSinceEpoc) |
233 | +{ |
234 | + if (d->m_millisecondsSinceEpoc != millisecondsSinceEpoc) { |
235 | + d->m_millisecondsSinceEpoc = millisecondsSinceEpoc; |
236 | + Q_EMIT millisecondsSinceEpocChanged(d->m_millisecondsSinceEpoc); |
237 | + update(); |
238 | + } |
239 | +} |
240 | + |
241 | +void TimeFormatter::setRelative(bool relative) |
242 | +{ |
243 | + if (d->m_relative != relative) { |
244 | + if (!relative) d->m_proximityTimer.stop(); |
245 | + d->m_relative = relative; |
246 | + Q_EMIT relativeChanged(d->m_relative); |
247 | + update(); |
248 | + } |
249 | +} |
250 | + |
251 | +void TimeFormatter::setTimeSource(QObject* timeSource) |
252 | +{ |
253 | + if (timeSource != d->m_timeSource) { |
254 | + d->m_timeSource = timeSource; |
255 | + Q_EMIT timeSourceChanged(d->m_timeSource); |
256 | + update(); |
257 | + } |
258 | +} |
259 | + |
260 | +void TimeFormatter::update() |
261 | +{ |
262 | + if (format().isEmpty() && !d->m_relative) return; |
263 | + |
264 | + QDateTime datetime(QDateTime::fromMSecsSinceEpoch(millisecondsSinceEpoc())); |
265 | + QString timeString = d->m_relative ? d->relativeTime(datetime) : datetime.toString(format()); |
266 | + |
267 | + if (d->m_timeString != timeString) { |
268 | + d->m_timeString = timeString; |
269 | + Q_EMIT timeStringChanged(d->m_timeString); |
270 | + } |
271 | +} |
272 | |
273 | === added file 'modules/Ubuntu/Components/plugin/timeformatter.h' |
274 | --- modules/Ubuntu/Components/plugin/timeformatter.h 1970-01-01 00:00:00 +0000 |
275 | +++ modules/Ubuntu/Components/plugin/timeformatter.h 2015-01-12 17:27:26 +0000 |
276 | @@ -0,0 +1,61 @@ |
277 | +/* |
278 | + * Copyright 2014 Canonical Ltd. |
279 | + * |
280 | + * This program is free software; you can redistribute it and/or modify |
281 | + * it under the terms of the GNU General Public License as published by |
282 | + * the Free Software Foundation; version 3. |
283 | + * |
284 | + * This program is distributed in the hope that it will be useful, |
285 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
286 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
287 | + * GNU General Public License for more details. |
288 | + * |
289 | + * You should have received a copy of the GNU General Public License |
290 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
291 | + */ |
292 | + |
293 | +#ifndef TIME_FORMATTER_H |
294 | +#define TIME_FORMATTER_H |
295 | + |
296 | +#include <QObject> |
297 | + |
298 | +// TODO - bug #1260728 |
299 | +class TimeFormatter : public QObject |
300 | +{ |
301 | + Q_OBJECT |
302 | + Q_PROPERTY(QString format READ format WRITE setFormat NOTIFY formatChanged) |
303 | + Q_PROPERTY(QString timeString READ timeString NOTIFY timeStringChanged) |
304 | + Q_PROPERTY(qint64 millisecondsSinceEpoc READ millisecondsSinceEpoc WRITE setMilliSeccondsSinceEpoc NOTIFY millisecondsSinceEpocChanged) |
305 | + Q_PROPERTY(bool relative READ relative WRITE setRelative NOTIFY relativeChanged) |
306 | + |
307 | + /* for testing */ |
308 | + Q_PROPERTY(QObject* timeSource READ timeSource WRITE setTimeSource NOTIFY timeSourceChanged) |
309 | +public: |
310 | + TimeFormatter(QObject *parent = 0); |
311 | + virtual ~TimeFormatter(); |
312 | + |
313 | + virtual QString format() const; |
314 | + QString timeString() const; |
315 | + qint64 millisecondsSinceEpoc() const; |
316 | + bool relative() const; |
317 | + QObject* timeSource() const; |
318 | + |
319 | + void setFormat(const QString &format); |
320 | + void setMilliSeccondsSinceEpoc(qint64 millisecondsSinceEpoc); |
321 | + void setRelative(bool relative); |
322 | + void setTimeSource(QObject* timeSource); |
323 | + |
324 | + void update(); |
325 | + |
326 | +Q_SIGNALS: |
327 | + void formatChanged(const QString &format); |
328 | + void timeStringChanged(const QString &timeString); |
329 | + void millisecondsSinceEpocChanged(qint64 millisecondsSinceEpoc); |
330 | + void relativeChanged(bool relative); |
331 | + void timeSourceChanged(QObject* timeSource); |
332 | + |
333 | +private: |
334 | + class TimeFormatterPrivate *d; |
335 | +}; |
336 | + |
337 | +#endif |
338 | |
339 | === added file 'modules/Ubuntu/Components/plugin/timeformatter_p.h' |
340 | --- modules/Ubuntu/Components/plugin/timeformatter_p.h 1970-01-01 00:00:00 +0000 |
341 | +++ modules/Ubuntu/Components/plugin/timeformatter_p.h 2015-01-12 17:27:26 +0000 |
342 | @@ -0,0 +1,177 @@ |
343 | +/* |
344 | + * Copyright 2014 Canonical Ltd. |
345 | + * |
346 | + * This program is free software; you can redistribute it and/or modify |
347 | + * it under the terms of the GNU General Public License as published by |
348 | + * the Free Software Foundation; version 3. |
349 | + * |
350 | + * This program is distributed in the hope that it will be useful, |
351 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
352 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
353 | + * GNU General Public License for more details. |
354 | + * |
355 | + * You should have received a copy of the GNU General Public License |
356 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
357 | + */ |
358 | + |
359 | +#ifndef TIMEFORMATTER_P_H |
360 | +#define TIMEFORMATTER_P_H |
361 | + |
362 | +#include "i18n.h" |
363 | + |
364 | +#include <QDateTime> |
365 | +#include <QDBusConnection> |
366 | +#include <QLocale> |
367 | +#include <QObject> |
368 | +#include <QTimer> |
369 | + |
370 | +/* Check the system locale setting to see if the format is 24-hour |
371 | + time or 12-hour time */ |
372 | +inline bool isLocale12h(void) |
373 | +{ |
374 | + QString strTimeFormat = QLocale::system().timeFormat(); |
375 | + QStringList includes; includes << "AP"; includes << "ap"; |
376 | + QStringList excludes; excludes << "H"; excludes << "HH"; |
377 | + |
378 | + Q_FOREACH(const QString& exclude, excludes) { |
379 | + if (strTimeFormat.contains(exclude)) { |
380 | + return false; |
381 | + } |
382 | + } |
383 | + |
384 | + Q_FOREACH(const QString& include, includes) { |
385 | + if (strTimeFormat.contains(include)) { |
386 | + return true; |
387 | + } |
388 | + } |
389 | + |
390 | + return false; |
391 | +} |
392 | + |
393 | +typedef enum |
394 | +{ |
395 | + DATE_PROXIMITY_NOW, |
396 | + DATE_PROXIMITY_HOUR, |
397 | + DATE_PROXIMITY_TODAY, |
398 | + DATE_PROXIMITY_YESTERDAY, |
399 | + DATE_PROXIMITY_TOMORROW, |
400 | + DATE_PROXIMITY_LAST_WEEK, |
401 | + DATE_PROXIMITY_NEXT_WEEK, |
402 | + DATE_PROXIMITY_FAR |
403 | +} date_proximity_t; |
404 | + |
405 | +inline date_proximity_t getDateProximity(const QDateTime& now, const QDateTime& time) |
406 | +{ |
407 | + int now_day = now.date().day(); |
408 | + int now_month = now.date().month(); |
409 | + int now_year = now.date().year(); |
410 | + |
411 | + int time_day = time.date().day(); |
412 | + int time_month = time.date().month(); |
413 | + int time_year = time.date().year(); |
414 | + |
415 | + qint64 diff = time.toMSecsSinceEpoch() - now.toMSecsSinceEpoch(); |
416 | + if (qAbs(diff) < 30000) return DATE_PROXIMITY_NOW; |
417 | + else if (qAbs(diff) < 3600000) return DATE_PROXIMITY_HOUR; |
418 | + |
419 | + // does it happen today? |
420 | + if ((now_year == time_year) && (now_month == time_month) && (now_day == time_day)) { |
421 | + return DATE_PROXIMITY_TODAY; |
422 | + } |
423 | + |
424 | + // did it happen yesterday? |
425 | + QDateTime yesterday(now.addDays(-1)); |
426 | + int yesterday_day = yesterday.date().day(); |
427 | + int yesterday_month = yesterday.date().month(); |
428 | + int yesterday_year = yesterday.date().year(); |
429 | + if ((yesterday_year == time_year) && (yesterday_month == time_month) && (yesterday_day == time_day)) { |
430 | + return DATE_PROXIMITY_YESTERDAY; |
431 | + } |
432 | + |
433 | + // does it happen tomorrow? |
434 | + QDateTime tomorrow(now.addDays(1)); |
435 | + int tomorrow_day = tomorrow.date().day(); |
436 | + int tomorrow_month = tomorrow.date().month(); |
437 | + int tomorrow_year = tomorrow.date().year(); |
438 | + if ((tomorrow_year == time_year) && (tomorrow_month == time_month) && (tomorrow_day == time_day)) { |
439 | + return DATE_PROXIMITY_TOMORROW; |
440 | + } |
441 | + |
442 | + if (time < now) { |
443 | + QDateTime lastWeek(now.addDays(-6)); |
444 | + QDateTime lastWeekBound(lastWeek.date(), QTime(0, 0, 0, 0)); |
445 | + |
446 | + // does it happen last week? |
447 | + if (time >= lastWeekBound) { |
448 | + return DATE_PROXIMITY_LAST_WEEK; |
449 | + } |
450 | + } else { |
451 | + |
452 | + QDateTime nextWeek(now.addDays(6)); |
453 | + QDateTime nextWeekBound(nextWeek.date(), QTime(23, 59, 59, 999)); |
454 | + |
455 | + // does it happen this week? |
456 | + if (time <= nextWeekBound) { |
457 | + return DATE_PROXIMITY_NEXT_WEEK; |
458 | + } |
459 | + } |
460 | + |
461 | + return DATE_PROXIMITY_FAR; |
462 | +} |
463 | + |
464 | +class TimeFormatterShared : public QObject |
465 | +{ |
466 | + Q_OBJECT |
467 | +public: |
468 | + TimeFormatterShared(); |
469 | + |
470 | + ~TimeFormatterShared() |
471 | + { |
472 | + s_timeformatter = NULL; |
473 | + } |
474 | + |
475 | +public Q_SLOTS: |
476 | + void timedate1PropertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList&) |
477 | + { |
478 | + if (interface != "org.freedesktop.timedate1") return; |
479 | + if (changed.contains("Timezone")) { |
480 | + Q_EMIT updated(); |
481 | + } |
482 | + } |
483 | + |
484 | +Q_SIGNALS: |
485 | + void updated(); |
486 | + |
487 | +public: |
488 | + static TimeFormatterShared* s_timeformatter; |
489 | +}; |
490 | + |
491 | +class TimeFormatterPrivate |
492 | +{ |
493 | +public: |
494 | + TimeFormatterPrivate() |
495 | + : m_format(QLocale::system().dateTimeFormat()) |
496 | + , m_millisecondsSinceEpoc(0) |
497 | + , m_relative(false) |
498 | + , m_timeSource(NULL) |
499 | + { |
500 | + if (!TimeFormatterShared::s_timeformatter) { TimeFormatterShared::s_timeformatter = new TimeFormatterShared(); } |
501 | + m_shared.reset(TimeFormatterShared::s_timeformatter); |
502 | + |
503 | + m_proximityTimer.setSingleShot(false); |
504 | + } |
505 | + |
506 | + QString relativeTime(const QDateTime &datetime); |
507 | + |
508 | + QString m_format; |
509 | + QString m_timeString; |
510 | + qint64 m_millisecondsSinceEpoc; |
511 | + bool m_relative; |
512 | + date_proximity_t m_lastProximity; |
513 | + QObject* m_timeSource; |
514 | + QTimer m_proximityTimer; |
515 | + |
516 | + QSharedPointer<TimeFormatterShared> m_shared; |
517 | +}; |
518 | + |
519 | +#endif // TIMEFORMATTER_P_H |
520 | |
521 | === modified file 'po/ubuntu-ui-toolkit.pot' |
522 | --- po/ubuntu-ui-toolkit.pot 2014-11-06 15:50:17 +0000 |
523 | +++ po/ubuntu-ui-toolkit.pot 2015-01-12 17:27:26 +0000 |
524 | @@ -8,19 +8,28 @@ |
525 | msgstr "" |
526 | "Project-Id-Version: ubuntu-ui-toolkit\n" |
527 | "Report-Msgid-Bugs-To: \n" |
528 | -"POT-Creation-Date: 2014-11-05 14:29+0100\n" |
529 | +"POT-Creation-Date: 2014-12-17 16:18+0000\n" |
530 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
531 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
532 | "Language-Team: LANGUAGE <LL@li.org>\n" |
533 | "Language: \n" |
534 | "MIME-Version: 1.0\n" |
535 | -"Content-Type: text/plain; charset=CHARSET\n" |
536 | +"Content-Type: text/plain; charset=UTF-8\n" |
537 | "Content-Transfer-Encoding: 8bit\n" |
538 | |
539 | -#: Ubuntu/Components/ListItems/Empty.qml:413 |
540 | +#: Ubuntu/Components/ListItems/Empty.qml:397 |
541 | msgid "Delete" |
542 | msgstr "" |
543 | |
544 | +#: Ubuntu/Components/plugin/adapters/dbuspropertywatcher_p.cpp:51 |
545 | +msgid "No service/path specified" |
546 | +msgstr "" |
547 | + |
548 | +#: Ubuntu/Components/plugin/adapters/dbuspropertywatcher_p.cpp:69 |
549 | +#, qt-format |
550 | +msgid "Invalid bus type: %1." |
551 | +msgstr "" |
552 | + |
553 | #: Ubuntu/Components/plugin/statesaverbackend_p.cpp:176 |
554 | #, qt-format |
555 | msgid "" |
556 | @@ -33,13 +42,98 @@ |
557 | msgid "property \"%1\" does not exist or is not writable for object %2" |
558 | msgstr "" |
559 | |
560 | -#: Ubuntu/Components/plugin/ucalarm.cpp:42 |
561 | -#: Ubuntu/Components/plugin/ucalarm.cpp:136 |
562 | +#. TRANSLATORS: Time based "this is happening/happened now" |
563 | +#: Ubuntu/Components/plugin/timeformatter.cpp:43 |
564 | +msgid "Now" |
565 | +msgstr "" |
566 | + |
567 | +#: Ubuntu/Components/plugin/timeformatter.cpp:53 |
568 | +#, qt-format |
569 | +msgid "%1 minute ago" |
570 | +msgstr "" |
571 | + |
572 | +#: Ubuntu/Components/plugin/timeformatter.cpp:54 |
573 | +#, qt-format |
574 | +msgid "%1 minutes ago" |
575 | +msgstr "" |
576 | + |
577 | +#: Ubuntu/Components/plugin/timeformatter.cpp:56 |
578 | +#, qt-format |
579 | +msgid "%1 minute" |
580 | +msgstr "" |
581 | + |
582 | +#: Ubuntu/Components/plugin/timeformatter.cpp:57 |
583 | +#, qt-format |
584 | +msgid "%1 minutes" |
585 | +msgstr "" |
586 | + |
587 | +#. TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
588 | +#. https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 |
589 | +#: Ubuntu/Components/plugin/timeformatter.cpp:65 |
590 | +msgid "h:mm ap" |
591 | +msgstr "" |
592 | + |
593 | +#. TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
594 | +#. https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 |
595 | +#: Ubuntu/Components/plugin/timeformatter.cpp:68 |
596 | +msgid "HH:mm" |
597 | +msgstr "" |
598 | + |
599 | +#. TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
600 | +#. https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 |
601 | +#: Ubuntu/Components/plugin/timeformatter.cpp:75 |
602 | +msgid "'Yesterday 'h:mm ap" |
603 | +msgstr "" |
604 | + |
605 | +#. TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
606 | +#. https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 |
607 | +#: Ubuntu/Components/plugin/timeformatter.cpp:78 |
608 | +msgid "'Yesterday 'HH:mm" |
609 | +msgstr "" |
610 | + |
611 | +#. TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
612 | +#. https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 |
613 | +#: Ubuntu/Components/plugin/timeformatter.cpp:84 |
614 | +msgid "'Tomorrow 'h:mm ap" |
615 | +msgstr "" |
616 | + |
617 | +#. TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
618 | +#. https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 |
619 | +#: Ubuntu/Components/plugin/timeformatter.cpp:87 |
620 | +msgid "'Tomorrow 'HH:mm" |
621 | +msgstr "" |
622 | + |
623 | +#. TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
624 | +#. https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 |
625 | +#: Ubuntu/Components/plugin/timeformatter.cpp:95 |
626 | +msgid "ddd' 'h:mm ap" |
627 | +msgstr "" |
628 | + |
629 | +#. TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
630 | +#. https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 |
631 | +#: Ubuntu/Components/plugin/timeformatter.cpp:98 |
632 | +msgid "ddd' 'HH:mm" |
633 | +msgstr "" |
634 | + |
635 | +#. TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
636 | +#. https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 |
637 | +#: Ubuntu/Components/plugin/timeformatter.cpp:105 |
638 | +msgid "ddd d MMM' 'h:mm ap" |
639 | +msgstr "" |
640 | + |
641 | +#. TRANSLATORS: Please translated these to your locale datetime format using the format specified by |
642 | +#. https://qt-project.org/doc/qt-5-snapshot/qdatetime.html#fromString-2 |
643 | +#: Ubuntu/Components/plugin/timeformatter.cpp:108 |
644 | +msgid "ddd d MMM' 'HH:mm" |
645 | +msgstr "" |
646 | + |
647 | +#: Ubuntu/Components/plugin/ucalarm.cpp:41 |
648 | +#: Ubuntu/Components/plugin/ucalarm.cpp:641 |
649 | msgid "Alarm" |
650 | msgstr "" |
651 | |
652 | -#: Ubuntu/Components/plugin/ucalarm.cpp:684 |
653 | -#: Ubuntu/Components/plugin/ucalarm.cpp:716 |
654 | +#: Ubuntu/Components/plugin/ucalarm.cpp:633 |
655 | +#: Ubuntu/Components/plugin/ucalarm.cpp:665 |
656 | msgid "Alarm has a pending operation." |
657 | msgstr "" |
658 | |
659 | @@ -66,10 +160,29 @@ |
660 | msgid "%1 is expecting additional arguments: %2" |
661 | msgstr "" |
662 | |
663 | -#: Ubuntu/Components/plugin/ucmousefilters.cpp:1064 |
664 | +#: Ubuntu/Components/plugin/uclistitemactions.cpp:155 |
665 | +msgid "actionsDelegate not set!" |
666 | +msgstr "" |
667 | + |
668 | +#: Ubuntu/Components/plugin/uclistitem.cpp:1040 |
669 | +#: Ubuntu/Components/plugin/uclistitem.cpp:1074 |
670 | +msgid "leadingActions and trailingActions cannot share the same object!" |
671 | +msgstr "" |
672 | + |
673 | +#: Ubuntu/Components/plugin/ucmousefilters.cpp:1065 |
674 | msgid "Ignoring AfterItem priority for InverseMouse filters." |
675 | msgstr "" |
676 | |
677 | +#: Ubuntu/Components/plugin/ucserviceproperties.cpp:62 |
678 | +msgid "Changing connection parameters forbidden." |
679 | +msgstr "" |
680 | + |
681 | +#: Ubuntu/Components/plugin/ucserviceproperties.cpp:145 |
682 | +#, qt-format |
683 | +msgid "" |
684 | +"Binding detected on property '%1' will be removed by the service updates." |
685 | +msgstr "" |
686 | + |
687 | #: Ubuntu/Components/plugin/ucstatesaver.cpp:46 |
688 | msgid "Warning: attachee must have an ID. State will not be saved." |
689 | msgstr "" |
690 | @@ -87,23 +200,24 @@ |
691 | "State saving disabled for %1, class %2" |
692 | msgstr "" |
693 | |
694 | -#: Ubuntu/Components/plugin/uctheme.cpp:233 |
695 | -msgid "Theme not found: " |
696 | +#: Ubuntu/Components/plugin/uctheme.cpp:240 |
697 | +#, qt-format |
698 | +msgid "Theme not found: \"%1\"" |
699 | msgstr "" |
700 | |
701 | -#: Ubuntu/Components/Popups/ComposerSheet.qml:80 |
702 | +#: Ubuntu/Components/Popups/ComposerSheet.qml:78 |
703 | msgid "Cancel" |
704 | msgstr "" |
705 | |
706 | -#: Ubuntu/Components/Popups/ComposerSheet.qml:90 |
707 | +#: Ubuntu/Components/Popups/ComposerSheet.qml:88 |
708 | msgid "Confirm" |
709 | msgstr "" |
710 | |
711 | -#: Ubuntu/Components/Popups/DefaultSheet.qml:89 |
712 | +#: Ubuntu/Components/Popups/DefaultSheet.qml:85 |
713 | msgid "Close" |
714 | msgstr "" |
715 | |
716 | -#: Ubuntu/Components/Popups/DefaultSheet.qml:99 |
717 | +#: Ubuntu/Components/Popups/DefaultSheet.qml:95 |
718 | msgid "Done" |
719 | msgstr "" |
720 | |
721 | @@ -111,19 +225,19 @@ |
722 | msgid "Select All" |
723 | msgstr "" |
724 | |
725 | -#: Ubuntu/Components/TextInputPopover.qml:33 |
726 | +#: Ubuntu/Components/TextInputPopover.qml:34 |
727 | msgid "Cut" |
728 | msgstr "" |
729 | |
730 | -#: Ubuntu/Components/TextInputPopover.qml:42 |
731 | +#: Ubuntu/Components/TextInputPopover.qml:46 |
732 | msgid "Copy" |
733 | msgstr "" |
734 | |
735 | -#: Ubuntu/Components/TextInputPopover.qml:49 |
736 | +#: Ubuntu/Components/TextInputPopover.qml:56 |
737 | msgid "Paste" |
738 | msgstr "" |
739 | |
740 | -#: Ubuntu/Components/Themes/Ambiance/ProgressBarStyle.qml:57 |
741 | +#: Ubuntu/Components/Themes/Ambiance/ProgressBarStyle.qml:62 |
742 | msgid "In Progress" |
743 | msgstr "" |
744 | |
745 | @@ -135,6 +249,6 @@ |
746 | msgid "Pull to refresh..." |
747 | msgstr "" |
748 | |
749 | -#: Ubuntu/Components/ToolbarItems.qml:142 |
750 | +#: Ubuntu/Components/ToolbarItems.qml:145 |
751 | msgid "Back" |
752 | msgstr "" |
753 | |
754 | === added file 'tests/unit/tst_components/dateExt.js' |
755 | --- tests/unit/tst_components/dateExt.js 1970-01-01 00:00:00 +0000 |
756 | +++ tests/unit/tst_components/dateExt.js 2015-01-12 17:27:26 +0000 |
757 | @@ -0,0 +1,67 @@ |
758 | +/* |
759 | + * Copyright 2014 Canonical Ltd. |
760 | + * |
761 | + * This program is free software; you can redistribute it and/or modify |
762 | + * it under the terms of the GNU Lesser General Public License as published by |
763 | + * the Free Software Foundation; version 3. |
764 | + * |
765 | + * This program is distributed in the hope that it will be useful, |
766 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
767 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
768 | + * GNU Lesser General Public License for more details. |
769 | + * |
770 | + * You should have received a copy of the GNU Lesser General Public License |
771 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
772 | + */ |
773 | + |
774 | +.pragma library |
775 | + |
776 | +Date.msPerMinute = 60e3 |
777 | +Date.msPerHour = 3600e3 |
778 | +Date.msPerDay = 86400e3 |
779 | +Date.msPerWeek = Date.msPerDay * 7 |
780 | + |
781 | +Date.leapYear = function(year) { |
782 | + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) |
783 | +} |
784 | + |
785 | +Date.prototype.addMinutes = function(minutes) { |
786 | + var date = new Date(this) |
787 | + date.setTime(date.getTime() + Date.msPerMinute * minutes) |
788 | + return date |
789 | +} |
790 | + |
791 | +Date.prototype.addHours = function(hours) { |
792 | + var date = new Date(this) |
793 | + date.setTime(date.getTime() + Date.msPerHour * hours) |
794 | + return date |
795 | +} |
796 | + |
797 | +Date.prototype.addDays = function(days) { |
798 | + var date = new Date(this) |
799 | + date.setTime(date.getTime() + Date.msPerDay * days) |
800 | + return date |
801 | +} |
802 | + |
803 | +Date.prototype.addMonths = function(months) { |
804 | + var date = new Date(this) |
805 | + date.setMonth(date.getMonth() + months) |
806 | + return date |
807 | +} |
808 | + |
809 | +Date.prototype.weekStart = function(weekStartDay) { |
810 | + var date = this.midnight() |
811 | + var day = date.getDay(), n = 0 |
812 | + while (day != weekStartDay) { |
813 | + if (day == 0) day = 6 |
814 | + else day = day - 1 |
815 | + n = n + 1 |
816 | + } |
817 | + return date.addDays(-n) |
818 | +} |
819 | + |
820 | +Date.prototype.midday = function() { |
821 | + var date = new Date(this) |
822 | + date.setHours(12,0,0,0); |
823 | + return date |
824 | +} |
825 | |
826 | === modified file 'tests/unit/tst_components/tst_components.pro' |
827 | --- tests/unit/tst_components/tst_components.pro 2012-12-04 08:11:38 +0000 |
828 | +++ tests/unit/tst_components/tst_components.pro 2015-01-12 17:27:26 +0000 |
829 | @@ -6,4 +6,5 @@ |
830 | |
831 | SOURCES += tst_components.cpp |
832 | |
833 | -OTHER_FILES += $$system(ls *.qml) |
834 | +OTHER_FILES += $$system(ls *.qml) \ |
835 | + dateExt.js |
836 | |
837 | === added file 'tests/unit/tst_components/tst_timeformatter.qml' |
838 | --- tests/unit/tst_components/tst_timeformatter.qml 1970-01-01 00:00:00 +0000 |
839 | +++ tests/unit/tst_components/tst_timeformatter.qml 2015-01-12 17:27:26 +0000 |
840 | @@ -0,0 +1,65 @@ |
841 | +/* |
842 | + * Copyright 2014 Canonical Ltd. |
843 | + * |
844 | + * This program is free software; you can redistribute it and/or modify |
845 | + * it under the terms of the GNU Lesser General Public License as published by |
846 | + * the Free Software Foundation; version 3. |
847 | + * |
848 | + * This program is distributed in the hope that it will be useful, |
849 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
850 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
851 | + * GNU Lesser General Public License for more details. |
852 | + * |
853 | + * You should have received a copy of the GNU Lesser General Public License |
854 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
855 | + */ |
856 | + |
857 | +import QtQuick 2.0 |
858 | +import QtTest 1.0 |
859 | +import Ubuntu.Components 1.1 |
860 | +import "dateExt.js" as DateExt |
861 | + |
862 | +TestCase { |
863 | + name: "TimeFormatter" |
864 | + |
865 | + function init() { |
866 | + timeFormatter.relative = false; |
867 | + } |
868 | + |
869 | + property date testTime: (new Date(2014, 10, 27, 14, 48, 0, 0)) |
870 | + |
871 | + function test_relative_data() { |
872 | + return [ |
873 | + { tag: "now", datetime: testTime, expected: "Now" }, |
874 | + { tag: "last minute", datetime: testTime.addMinutes(-1), expected: "1 minute ago" }, |
875 | + { tag: "next minute", datetime: testTime.addMinutes(1), expected: "1 minute" }, |
876 | + { tag: "last hour", datetime: testTime.addMinutes(-50), expected: "50 minutes ago" }, |
877 | + { tag: "next hour", datetime: testTime.addMinutes(50), expected: "50 minutes" }, |
878 | + { tag: "today-before", datetime: testTime.addHours(-4), expected: "10:48" }, |
879 | + { tag: "today-after", datetime: testTime.addHours(4), expected: "18:48" }, |
880 | + { tag: "yesterday", datetime: testTime.addDays(-1), expected: "Yesterday\u200314:48" }, |
881 | + { tag: "tomorrow", datetime: testTime.addDays(1), expected: "Tomorrow\u200314:48" }, |
882 | + { tag: "last-week", datetime: testTime.addDays(-6), expected: "Fri\u200314:48" }, |
883 | + { tag: "next-week", datetime: testTime.addDays(6), expected: "Wed\u200314:48" }, |
884 | + { tag: "far-past", datetime: testTime.addDays(-7), expected: "Thu 20 Nov\u200314:48" }, |
885 | + { tag: "far-future", datetime: testTime.addDays(7), expected: "Thu 4 Dec\u200314:48" } |
886 | + ]; |
887 | + } |
888 | + |
889 | + function test_relative(data) { |
890 | + timeFormatter.relative = true; |
891 | + timeFormatter.millisecondsSinceEpoc = data.datetime.getTime(); |
892 | + |
893 | + if (data.expected !== undefined) { |
894 | + compare(timeFormatter.timeString, data.expected); |
895 | + } |
896 | + } |
897 | + |
898 | + TimeFormatter { |
899 | + id: timeFormatter |
900 | + |
901 | + timeSource: QtObject { |
902 | + property date time: testTime |
903 | + } |
904 | + } |
905 | +} |
FAILED: Continuous integration, rev:1119 jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- ci/2183/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 778/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- vivid/384/ console jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- vivid-amd64- ci/7/console jenkins. qa.ubuntu. com/job/ ubuntu- ui-toolkit- vivid-armhf- ci/7/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 776/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-amd64/ 390/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- ui-toolkit- ci/2183/ rebuild
http://