on xenial help sign in
Merged launcher-icon-wobble branch and solved all conflicts.
a63f337Mirco Müller
debian/changelog+34
@@ -1,3 +1,37 @@
1+unity8 (8.10+15.10.20150717-0ubuntu1) wily; urgency=medium
2+
3+ [ Albert Astals ]
4+ * Ensure tutorial doesn't let user drag the launcher past screen edge.
5+ (LP: #1454882)
6+
7+ [ Albert Astals Cid ]
8+ * Fix build with ninja
9+
10+ [ Andrea Cimitan ]
11+ * Add PreviewSocialComment
12+
13+ [ Daniel d'Andrada ]
14+ * Ensure tutorial doesn't let user drag the launcher past screen edge.
15+ (LP: #1454882)
16+ * Update tst_ShellWithPin
17+
18+ [ Josh Arenson ]
19+ * Add a basic autopilot test for the SettingsWizard
20+
21+ [ Lukáš Tinkl ]
22+ * Avoid sync DBUS calls
23+
24+ [ Marcus Tomlinson ]
25+ * Handle TERM, HUP, and INT signals in unity-scope-tool (LP: #1470464)
26+
27+ [ Michael Zanetti ]
28+ * Add PreviewSocialComment
29+
30+ [ Nick Dedekind ]
31+ * Fixed qml warnings in 'make tryShell'
32+
33+ -- CI Train Bot <ci-train-bot@canonical.com> Fri, 17 Jul 2015 15:53:38 +0000
34+
1unity8 (8.10+15.10.20150713-0ubuntu1) wily; urgency=medium
35unity8 (8.10+15.10.20150713-0ubuntu1) wily; urgency=medium
2
36
3 [ Albert Astals Cid ]
37 [ Albert Astals Cid ]
debian/control+5−3
@@ -30,7 +30,7 @@ Build-Depends: cmake,
30 libqt5xmlpatterns5-dev,
30 libqt5xmlpatterns5-dev,
31 libsystemsettings-dev,
31 libsystemsettings-dev,
32 libudev-dev,
32 libudev-dev,
33− libunity-api-dev (>= 7.97),
33+ libunity-api-dev (>= 7.98),
34 libusermetricsoutput1-dev,
34 libusermetricsoutput1-dev,
35 libxcb1-dev,
35 libxcb1-dev,
36 pkg-config,
36 pkg-config,
@@ -101,7 +101,7 @@ Depends: gsettings-desktop-schemas,
101 qtdeclarative5-ubuntu-telephony0.1,
101 qtdeclarative5-ubuntu-telephony0.1,
102 qtdeclarative5-ubuntu-web-plugin,
102 qtdeclarative5-ubuntu-web-plugin,
103 ubuntu-system-settings,
103 ubuntu-system-settings,
104− unity-launcher-impl-4,
104+ unity-launcher-impl-7,
105 unity8-common (= ${source:Version}),
105 unity8-common (= ${source:Version}),
106 unity8-private (= ${binary:Version}),
106 unity8-private (= ${binary:Version}),
107 unity8-private | unity-launcher-impl,
107 unity8-private | unity-launcher-impl,
@@ -148,6 +148,7 @@ Depends: autopilot-qt5 (>= 1.4),
148 gir1.2-notify-0.7,
148 gir1.2-notify-0.7,
149 libqt5test5,
149 libqt5test5,
150 libqt5widgets5,
150 libqt5widgets5,
151+ ofono-phonesim,
151 python3-autopilot,
152 python3-autopilot,
152 python3-evdev,
153 python3-evdev,
153 python3-fixtures,
154 python3-fixtures,
@@ -158,6 +159,7 @@ Depends: autopilot-qt5 (>= 1.4),
158 unity8 (= ${source:Version}),
159 unity8 (= ${source:Version}),
159 unity8-fake-env (= ${source:Version}),
160 unity8-fake-env (= ${source:Version}),
160 url-dispatcher-tools,
161 url-dispatcher-tools,
162+ xvfb,
161 ${misc:Depends},
163 ${misc:Depends},
162 ${python3:Depends},
164 ${python3:Depends},
163 ${shlibs:Depends},
165 ${shlibs:Depends},
@@ -189,7 +191,7 @@ Depends: accountsservice-ubuntu-schemas (>= 0.0.3),
189 ${misc:Depends},
191 ${misc:Depends},
190 ${shlibs:Depends},
192 ${shlibs:Depends},
191Provides: unity-launcher-impl,
193Provides: unity-launcher-impl,
192− unity-launcher-impl-4,
194+ unity-launcher-impl-7,
193Description: Unity 8 private libs
195Description: Unity 8 private libs
194 The Unity 8 shell is the primary user interface for Ubuntu devices.
196 The Unity 8 shell is the primary user interface for Ubuntu devices.
195 .
197 .
plugins/AccountsService/AccountsService.cpp+31−42
@@ -23,10 +23,9 @@
23#include <QStringList>
23#include <QStringList>
24#include <QDebug>
24#include <QDebug>
25
25
26−AccountsService::AccountsService(QObject* parent)
26+AccountsService::AccountsService(QObject* parent, const QString &user)
27− : QObject(parent),
27+ : QObject(parent),
28 m_service(new AccountsServiceDBusAdaptor(this)),
28 m_service(new AccountsServiceDBusAdaptor(this)),
29− m_user(""),
30 m_demoEdges(false),
29 m_demoEdges(false),
31 m_enableLauncherWhileLocked(false),
30 m_enableLauncherWhileLocked(false),
32 m_enableIndicatorsWhileLocked(false),
31 m_enableIndicatorsWhileLocked(false),
@@ -36,12 +35,10 @@ AccountsService::AccountsService(QObject* parent)
36 m_hereEnabled(false),
35 m_hereEnabled(false),
37 m_hereLicensePath() // null means not set yet
36 m_hereLicensePath() // null means not set yet
38{
37{
39− connect(m_service, SIGNAL(propertiesChanged(const QString &, const QString &, const QStringList &)),
38+ connect(m_service, &AccountsServiceDBusAdaptor::propertiesChanged, this, &AccountsService::onPropertiesChanged);
40− this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
41− connect(m_service, SIGNAL(maybeChanged(const QString &)),
39+ connect(m_service, &AccountsServiceDBusAdaptor::maybeChanged, this, &AccountsService::onMaybeChanged);
42− this, SLOT(maybeChanged(const QString &)));
43
40
44− setUser(qgetenv("USER"));
41+ setUser(!user.isEmpty() ? user : QString::fromUtf8(qgetenv("USER")));
45}
42}
46
43
47QString AccountsService::user() const
44QString AccountsService::user() const
@@ -173,19 +170,18 @@ void AccountsService::updateEnableLauncherWhileLocked(bool async)
173 connect(watcher, &QDBusPendingCallWatcher::finished,
170 connect(watcher, &QDBusPendingCallWatcher::finished,
174 this, [this](QDBusPendingCallWatcher* watcher) {
171 this, [this](QDBusPendingCallWatcher* watcher) {
175
172
176− QDBusPendingReply<QDBusVariant> reply = *watcher;
173+ QDBusPendingReply<QVariant> reply = *watcher;
174+ watcher->deleteLater();
177 if (reply.isError()) {
175 if (reply.isError()) {
178 qWarning() << "Failed to get 'EnableLauncherWhileLocked' property - " << reply.error().message();
176 qWarning() << "Failed to get 'EnableLauncherWhileLocked' property - " << reply.error().message();
179− watcher->deleteLater();
180 return;
177 return;
181 }
178 }
182
179
183− auto enableLauncherWhileLocked = reply.value().variant().toBool();
180+ const bool enableLauncherWhileLocked = reply.value().toBool();
184 if (m_enableLauncherWhileLocked != enableLauncherWhileLocked) {
181 if (m_enableLauncherWhileLocked != enableLauncherWhileLocked) {
185 m_enableLauncherWhileLocked = enableLauncherWhileLocked;
182 m_enableLauncherWhileLocked = enableLauncherWhileLocked;
186 Q_EMIT enableLauncherWhileLockedChanged();
183 Q_EMIT enableLauncherWhileLockedChanged();
187 }
184 }
188− watcher->deleteLater();
189 });
185 });
190 if (!async) {
186 if (!async) {
191 watcher->waitForFinished();
187 watcher->waitForFinished();
@@ -203,19 +199,18 @@ void AccountsService::updateEnableIndicatorsWhileLocked(bool async)
203 connect(watcher, &QDBusPendingCallWatcher::finished,
199 connect(watcher, &QDBusPendingCallWatcher::finished,
204 this, [this](QDBusPendingCallWatcher* watcher) {
200 this, [this](QDBusPendingCallWatcher* watcher) {
205
201
206− QDBusPendingReply<QDBusVariant> reply = *watcher;
202+ QDBusPendingReply<QVariant> reply = *watcher;
203+ watcher->deleteLater();
207 if (reply.isError()) {
204 if (reply.isError()) {
208 qWarning() << "Failed to get 'EnableIndicatorsWhileLocked' property - " << reply.error().message();
205 qWarning() << "Failed to get 'EnableIndicatorsWhileLocked' property - " << reply.error().message();
209− watcher->deleteLater();
210 return;
206 return;
211 }
207 }
212
208
213− auto enableIndicatorsWhileLocked = reply.value().variant().toBool();
209+ const bool enableIndicatorsWhileLocked = reply.value().toBool();
214 if (m_enableIndicatorsWhileLocked != enableIndicatorsWhileLocked) {
210 if (m_enableIndicatorsWhileLocked != enableIndicatorsWhileLocked) {
215 m_enableIndicatorsWhileLocked = enableIndicatorsWhileLocked;
211 m_enableIndicatorsWhileLocked = enableIndicatorsWhileLocked;
216 Q_EMIT enableIndicatorsWhileLockedChanged();
212 Q_EMIT enableIndicatorsWhileLockedChanged();
217 }
213 }
218− watcher->deleteLater();
219 });
214 });
220 if (!async) {
215 if (!async) {
221 watcher->waitForFinished();
216 watcher->waitForFinished();
@@ -233,19 +228,18 @@ void AccountsService::updateBackgroundFile(bool async)
233 connect(watcher, &QDBusPendingCallWatcher::finished,
228 connect(watcher, &QDBusPendingCallWatcher::finished,
234 this, [this](QDBusPendingCallWatcher* watcher) {
229 this, [this](QDBusPendingCallWatcher* watcher) {
235
230
236− QDBusPendingReply<QDBusVariant> reply = *watcher;
231+ QDBusPendingReply<QVariant> reply = *watcher;
232+ watcher->deleteLater();
237 if (reply.isError()) {
233 if (reply.isError()) {
238 qWarning() << "Failed to get 'BackgroundFile' property - " << reply.error().message();
234 qWarning() << "Failed to get 'BackgroundFile' property - " << reply.error().message();
239− watcher->deleteLater();
240 return;
235 return;
241 }
236 }
242
237
243− auto backgroundFile = reply.value().variant().toString();
238+ const QString backgroundFile = reply.value().toString();
244 if (m_backgroundFile != backgroundFile) {
239 if (m_backgroundFile != backgroundFile) {
245 m_backgroundFile = backgroundFile;
240 m_backgroundFile = backgroundFile;
246 Q_EMIT backgroundFileChanged();
241 Q_EMIT backgroundFileChanged();
247 }
242 }
248− watcher->deleteLater();
249 });
243 });
250 if (!async) {
244 if (!async) {
251 watcher->waitForFinished();
245 watcher->waitForFinished();
@@ -263,19 +257,18 @@ void AccountsService::updateStatsWelcomeScreen(bool async)
263 connect(watcher, &QDBusPendingCallWatcher::finished,
257 connect(watcher, &QDBusPendingCallWatcher::finished,
264 this, [this](QDBusPendingCallWatcher* watcher) {
258 this, [this](QDBusPendingCallWatcher* watcher) {
265
259
266− QDBusPendingReply<QDBusVariant> reply = *watcher;
260+ QDBusPendingReply<QVariant> reply = *watcher;
261+ watcher->deleteLater();
267 if (reply.isError()) {
262 if (reply.isError()) {
268 qWarning() << "Failed to get 'StatsWelcomeScreen' property - " << reply.error().message();
263 qWarning() << "Failed to get 'StatsWelcomeScreen' property - " << reply.error().message();
269− watcher->deleteLater();
270 return;
264 return;
271 }
265 }
272
266
273− auto statsWelcomeScreen = reply.value().variant().toBool();
267+ const bool statsWelcomeScreen = reply.value().toBool();
274 if (m_statsWelcomeScreen != statsWelcomeScreen) {
268 if (m_statsWelcomeScreen != statsWelcomeScreen) {
275 m_statsWelcomeScreen = statsWelcomeScreen;
269 m_statsWelcomeScreen = statsWelcomeScreen;
276 Q_EMIT statsWelcomeScreenChanged();
270 Q_EMIT statsWelcomeScreenChanged();
277 }
271 }
278− watcher->deleteLater();
279 });
272 });
280 if (!async) {
273 if (!async) {
281 watcher->waitForFinished();
274 watcher->waitForFinished();
@@ -293,19 +286,18 @@ void AccountsService::updatePasswordDisplayHint(bool async)
293 connect(watcher, &QDBusPendingCallWatcher::finished,
286 connect(watcher, &QDBusPendingCallWatcher::finished,
294 this, [this](QDBusPendingCallWatcher* watcher) {
287 this, [this](QDBusPendingCallWatcher* watcher) {
295
288
296− QDBusPendingReply<QDBusVariant> reply = *watcher;
289+ QDBusPendingReply<QVariant> reply = *watcher;
290+ watcher->deleteLater();
297 if (reply.isError()) {
291 if (reply.isError()) {
298 qWarning() << "Failed to get 'PasswordDisplayHint' property - " << reply.error().message();
292 qWarning() << "Failed to get 'PasswordDisplayHint' property - " << reply.error().message();
299− watcher->deleteLater();
300 return;
293 return;
301 }
294 }
302
295
303− PasswordDisplayHint passwordDisplayHint = (PasswordDisplayHint)reply.value().variant().toInt();
296+ const PasswordDisplayHint passwordDisplayHint = (PasswordDisplayHint)reply.value().toInt();
304 if (m_passwordDisplayHint != passwordDisplayHint) {
297 if (m_passwordDisplayHint != passwordDisplayHint) {
305 m_passwordDisplayHint = passwordDisplayHint;
298 m_passwordDisplayHint = passwordDisplayHint;
306 Q_EMIT passwordDisplayHintChanged();
299 Q_EMIT passwordDisplayHintChanged();
307 }
300 }
308− watcher->deleteLater();
309 });
301 });
310 if (!async) {
302 if (!async) {
311 watcher->waitForFinished();
303 watcher->waitForFinished();
@@ -323,19 +315,18 @@ void AccountsService::updateFailedLogins(bool async)
323 connect(watcher, &QDBusPendingCallWatcher::finished,
315 connect(watcher, &QDBusPendingCallWatcher::finished,
324 this, [this](QDBusPendingCallWatcher* watcher) {
316 this, [this](QDBusPendingCallWatcher* watcher) {
325
317
326− QDBusPendingReply<QDBusVariant> reply = *watcher;
318+ QDBusPendingReply<QVariant> reply = *watcher;
319+ watcher->deleteLater();
327 if (reply.isError()) {
320 if (reply.isError()) {
328 qWarning() << "Failed to get 'FailedLogins' property - " << reply.error().message();
321 qWarning() << "Failed to get 'FailedLogins' property - " << reply.error().message();
329− watcher->deleteLater();
330 return;
322 return;
331 }
323 }
332
324
333− uint failedLogins = reply.value().variant().toUInt();
325+ const uint failedLogins = reply.value().toUInt();
334 if (m_failedLogins != failedLogins) {
326 if (m_failedLogins != failedLogins) {
335 m_failedLogins = failedLogins;
327 m_failedLogins = failedLogins;
336 Q_EMIT failedLoginsChanged();
328 Q_EMIT failedLoginsChanged();
337 }
329 }
338− watcher->deleteLater();
339 });
330 });
340 if (!async) {
331 if (!async) {
341 watcher->waitForFinished();
332 watcher->waitForFinished();
@@ -353,19 +344,18 @@ void AccountsService::updateHereEnabled(bool async)
353 connect(watcher, &QDBusPendingCallWatcher::finished,
344 connect(watcher, &QDBusPendingCallWatcher::finished,
354 this, [this](QDBusPendingCallWatcher* watcher) {
345 this, [this](QDBusPendingCallWatcher* watcher) {
355
346
356− QDBusPendingReply<QDBusVariant> reply = *watcher;
347+ QDBusPendingReply<QVariant> reply = *watcher;
348+ watcher->deleteLater();
357 if (reply.isError()) {
349 if (reply.isError()) {
358 qWarning() << "Failed to get 'LicenseAccepted' property - " << reply.error().message();
350 qWarning() << "Failed to get 'LicenseAccepted' property - " << reply.error().message();
359− watcher->deleteLater();
360 return;
351 return;
361 }
352 }
362
353
363− auto hereEnabled = reply.value().variant().toBool();
354+ const bool hereEnabled = reply.value().toBool();
364 if (m_hereEnabled != hereEnabled) {
355 if (m_hereEnabled != hereEnabled) {
365 m_hereEnabled = hereEnabled;
356 m_hereEnabled = hereEnabled;
366 Q_EMIT hereEnabledChanged();
357 Q_EMIT hereEnabledChanged();
367 }
358 }
368− watcher->deleteLater();
369 });
359 });
370 if (!async) {
360 if (!async) {
371 watcher->waitForFinished();
361 watcher->waitForFinished();
@@ -383,14 +373,14 @@ void AccountsService::updateHereLicensePath(bool async)
383 connect(watcher, &QDBusPendingCallWatcher::finished,
373 connect(watcher, &QDBusPendingCallWatcher::finished,
384 this, [this](QDBusPendingCallWatcher* watcher) {
374 this, [this](QDBusPendingCallWatcher* watcher) {
385
375
386− QDBusPendingReply<QDBusVariant> reply = *watcher;
376+ QDBusPendingReply<QVariant> reply = *watcher;
377+ watcher->deleteLater();
387 if (reply.isError()) {
378 if (reply.isError()) {
388 qWarning() << "Failed to get 'LicenseBasePath' property - " << reply.error().message();
379 qWarning() << "Failed to get 'LicenseBasePath' property - " << reply.error().message();
389− watcher->deleteLater();
390 return;
380 return;
391 }
381 }
392
382
393− auto hereLicensePath = reply.value().variant().toString();
383+ QString hereLicensePath = reply.value().toString();
394 if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
384 if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
395 hereLicensePath = "";
385 hereLicensePath = "";
396
386
@@ -398,7 +388,6 @@ void AccountsService::updateHereLicensePath(bool async)
398 m_hereLicensePath = hereLicensePath;
388 m_hereLicensePath = hereLicensePath;
399 Q_EMIT hereLicensePathChanged();
389 Q_EMIT hereLicensePathChanged();
400 }
390 }
401− watcher->deleteLater();
402 });
391 });
403 if (!async) {
392 if (!async) {
404 watcher->waitForFinished();
393 watcher->waitForFinished();
@@ -421,7 +410,7 @@ void AccountsService::setFailedLogins(uint failedLogins)
421 }
410 }
422}
411}
423
412
424−void AccountsService::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
413+void AccountsService::onPropertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
425{
414{
426 if (m_user != user) {
415 if (m_user != user) {
427 return;
416 return;
@@ -459,7 +448,7 @@ void AccountsService::propertiesChanged(const QString &user, const QString &inte
459 }
448 }
460}
449}
461
450
462−void AccountsService::maybeChanged(const QString &user)
451+void AccountsService::onMaybeChanged(const QString &user)
463{
452{
464 if (m_user != user) {
453 if (m_user != user) {
465 return;
454 return;
plugins/AccountsService/AccountsService.h+4−3
@@ -72,7 +72,8 @@ public:
72 Numeric,
72 Numeric,
73 };
73 };
74
74
75− explicit AccountsService(QObject *parent = 0);
75+ explicit AccountsService(QObject *parent = 0, const QString & user = QString());
76+ ~AccountsService() = default;
76
77
77 QString user() const;
78 QString user() const;
78 void setUser(const QString &user);
79 void setUser(const QString &user);
@@ -103,8 +104,8 @@ Q_SIGNALS:
103 void hereLicensePathChanged();
104 void hereLicensePathChanged();
104
105
105private Q_SLOTS:
106private Q_SLOTS:
106− void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
107+ void onPropertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
107− void maybeChanged(const QString &user);
108+ void onMaybeChanged(const QString &user);
108
109
109private:
110private:
110 void updateDemoEdges(bool async = true);
111 void updateDemoEdges(bool async = true);
plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+13−11
@@ -21,35 +21,35 @@
21#include <QDBusConnectionInterface>
21#include <QDBusConnectionInterface>
22#include <QDBusMessage>
22#include <QDBusMessage>
23#include <QDBusVariant>
23#include <QDBusVariant>
24+#include <QDebug>
24
25
25AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
26AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
26 : QObject(parent),
27 : QObject(parent),
27 m_accountsManager(nullptr),
28 m_accountsManager(nullptr),
28− m_users(),
29 m_ignoreNextChanged(false)
29 m_ignoreNextChanged(false)
30{
30{
31 QDBusConnection connection = QDBusConnection::SM_BUSNAME();
31 QDBusConnection connection = QDBusConnection::SM_BUSNAME();
32 QDBusConnectionInterface *interface = connection.interface();
32 QDBusConnectionInterface *interface = connection.interface();
33 interface->startService("org.freedesktop.Accounts");
33 interface->startService("org.freedesktop.Accounts");
34 m_accountsManager = new QDBusInterface("org.freedesktop.Accounts",
34 m_accountsManager = new QDBusInterface("org.freedesktop.Accounts",
35− "/org/freedesktop/Accounts",
35+ "/org/freedesktop/Accounts",
36− "org.freedesktop.Accounts",
36+ "org.freedesktop.Accounts",
37− connection, this);
37+ connection, this);
38}
38}
39
39
40QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const QString &interface, const QString &property)
40QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const QString &interface, const QString &property)
41{
41{
42 QDBusInterface *iface = getUserInterface(user);
42 QDBusInterface *iface = getUserInterface(user);
43 if (iface != nullptr && iface->isValid()) {
43 if (iface != nullptr && iface->isValid()) {
44− QDBusMessage answer = iface->call("Get", interface, property);
44+ QDBusReply<QVariant> answer = iface->call("Get", interface, property);
45− if (answer.type() == QDBusMessage::ReplyMessage) {
45+ if (answer.isValid()) {
46− return answer.arguments()[0].value<QDBusVariant>().variant();
46+ return answer;
47 }
47 }
48 }
48 }
49 return QVariant();
49 return QVariant();
50}
50}
51
51
52−QDBusPendingReply<QDBusVariant> AccountsServiceDBusAdaptor::getUserPropertyAsync(const QString &user, const QString &interface, const QString &property)
52+QDBusPendingReply<QVariant> AccountsServiceDBusAdaptor::getUserPropertyAsync(const QString &user, const QString &interface, const QString &property)
53{
53{
54 QDBusInterface *iface = getUserInterface(user);
54 QDBusInterface *iface = getUserInterface(user);
55 if (iface != nullptr && iface->isValid()) {
55 if (iface != nullptr && iface->isValid()) {
@@ -116,9 +116,9 @@ QDBusInterface *AccountsServiceDBusAdaptor::getUserInterface(const QString &user
116{
116{
117 QDBusInterface *iface = m_users.value(user);
117 QDBusInterface *iface = m_users.value(user);
118 if (iface == nullptr && m_accountsManager->isValid()) {
118 if (iface == nullptr && m_accountsManager->isValid()) {
119− QDBusMessage answer = m_accountsManager->call("FindUserByName", user);
119+ QDBusReply<QDBusObjectPath> answer = m_accountsManager->asyncCall("FindUserByName", user);
120− if (answer.type() == QDBusMessage::ReplyMessage) {
120+ if (answer.isValid()) {
121− QString path = answer.arguments()[0].value<QDBusObjectPath>().path();
121+ const QString path = answer.value().path();
122
122
123 iface = new QDBusInterface("org.freedesktop.Accounts",
123 iface = new QDBusInterface("org.freedesktop.Accounts",
124 path,
124 path,
@@ -148,6 +148,8 @@ QDBusInterface *AccountsServiceDBusAdaptor::getUserInterface(const QString &user
148 SLOT(propertiesChangedSlot(QString, QVariantMap, QStringList)));
148 SLOT(propertiesChangedSlot(QString, QVariantMap, QStringList)));
149
149
150 m_users.insert(user, iface);
150 m_users.insert(user, iface);
151+ } else {
152+ qWarning() << "Couldn't get user interface" << answer.error().name() << answer.error().message();
151 }
153 }
152 }
154 }
153 return iface;
155 return iface;
plugins/AccountsService/AccountsServiceDBusAdaptor.h+3−2
@@ -33,13 +33,14 @@ class AccountsServiceDBusAdaptor: public QObject, public QDBusContext
33
33
34public:
34public:
35 explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
35 explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
36+ ~AccountsServiceDBusAdaptor() = default;
36
37
37 Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
38 Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
38− Q_INVOKABLE QDBusPendingReply<QDBusVariant> getUserPropertyAsync(const QString &user, const QString &interface, const QString &property);
39+ Q_INVOKABLE QDBusPendingReply<QVariant> getUserPropertyAsync(const QString &user, const QString &interface, const QString &property);
39
40
40 template <typename T>
41 template <typename T>
41 inline T getUserProperty(const QString &user, const QString &interface, const QString &property) {
42 inline T getUserProperty(const QString &user, const QString &interface, const QString &property) {
42− QVariant variant = getUserProperty(user, interface, property);
43+ const QVariant variant = getUserProperty(user, interface, property);
43 if (variant.isValid() && variant.canConvert<QDBusArgument>()) {
44 if (variant.isValid() && variant.canConvert<QDBusArgument>()) {
44 return qdbus_cast<T>(variant.value<QDBusArgument>());
45 return qdbus_cast<T>(variant.value<QDBusArgument>());
45 }
46 }
plugins/Greeter/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,4 +1,4 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
4
4
plugins/Greeter/Unity/Launcher/launcheritem.cpp+14
@@ -31,6 +31,7 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
31 m_count(0),
31 m_count(0),
32 m_countVisible(false),
32 m_countVisible(false),
33 m_focused(false),
33 m_focused(false),
34+ m_alerting(false),
34 m_quickList(new QuickListModel(this))
35 m_quickList(new QuickListModel(this))
35{
36{
36 QuickListEntry nameAction;
37 QuickListEntry nameAction;
@@ -165,6 +166,19 @@ void LauncherItem::setFocused(bool focused)
165 }
166 }
166}
167}
167
168
169+bool LauncherItem::alerting() const
170+{
171+ return m_alerting;
172+}
173+
174+void LauncherItem::setAlerting(bool alerting)
175+{
176+ if (m_alerting != alerting) {
177+ m_alerting = alerting;
178+ Q_EMIT alertingChanged(alerting);
179+ }
180+}
181+
168unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
182unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
169{
183{
170 return m_quickList;
184 return m_quickList;
plugins/Greeter/Unity/Launcher/launcheritem.h+4
@@ -41,6 +41,7 @@ public:
41 int count() const override;
41 int count() const override;
42 bool countVisible() const override;
42 bool countVisible() const override;
43 bool focused() const override;
43 bool focused() const override;
44+ bool alerting() const override;
44
45
45 unity::shell::launcher::QuickListModelInterface *quickList() const override;
46 unity::shell::launcher::QuickListModelInterface *quickList() const override;
46
47
@@ -54,6 +55,8 @@ private:
54 void setCount(int count);
55 void setCount(int count);
55 void setCountVisible(bool countVisible);
56 void setCountVisible(bool countVisible);
56 void setFocused(bool focused);
57 void setFocused(bool focused);
58+ void setAlerting(bool alerting);
59+
57
60
58private:
61private:
59 QString m_appId;
62 QString m_appId;
@@ -66,6 +69,7 @@ private:
66 int m_count;
69 int m_count;
67 bool m_countVisible;
70 bool m_countVisible;
68 bool m_focused;
71 bool m_focused;
72+ bool m_alerting;
69 QuickListModel *m_quickList;
73 QuickListModel *m_quickList;
70
74
71 friend class LauncherModel;
75 friend class LauncherModel;
plugins/Greeter/Unity/Launcher/launchermodelas.cpp+7
@@ -72,6 +72,13 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
72 return QVariant();
72 return QVariant();
73}
73}
74
74
75+void LauncherModel::setAlerting(const QString &appId, bool alerting)
76+{
77+ Q_UNUSED(appId)
78+ Q_UNUSED(alerting)
79+ qWarning() << "This is a read only implementation. Cannot set alert-state of items.";
80+}
81+
75unity::shell::launcher::LauncherItemInterface *LauncherModel::get(int index) const
82unity::shell::launcher::LauncherItemInterface *LauncherModel::get(int index) const
76{
83{
77 if (index < 0 || index >= m_list.count()) {
84 if (index < 0 || index >= m_list.count()) {
plugins/Greeter/Unity/Launcher/launchermodelas.h+1
@@ -41,6 +41,7 @@ public:
41
41
42 QVariant data(const QModelIndex &index, int role) const override;
42 QVariant data(const QModelIndex &index, int role) const override;
43
43
44+ Q_INVOKABLE void setAlerting(const QString &appId, bool alerting) override;
44 Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const override;
45 Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const override;
45 Q_INVOKABLE void move(int oldIndex, int newIndex) override;
46 Q_INVOKABLE void move(int oldIndex, int newIndex) override;
46 Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
47 Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
plugins/Lights/Lights.cpp+1−1
@@ -71,7 +71,7 @@ void Lights::setColor(const QColor &color)
71 if (m_color != color) {
71 if (m_color != color) {
72 m_color = color;
72 m_color = color;
73 Q_EMIT colorChanged(m_color);
73 Q_EMIT colorChanged(m_color);
74− // FIXME: update the collor if the light is already on
74+ // FIXME: update the color if the light is already on
75 }
75 }
76}
76}
77
77
plugins/Ubuntu/SystemImage/SystemImage.cpp+7−8
@@ -16,19 +16,18 @@
16
16
17#include "SystemImage.h"
17#include "SystemImage.h"
18#include <QDBusConnection>
18#include <QDBusConnection>
19−#include <QDBusInterface>
19+#include <QDBusPendingCall>
20
20
21SystemImage::SystemImage(QObject *parent)
21SystemImage::SystemImage(QObject *parent)
22− : QObject(parent),
22+ : QObject(parent)
23− m_interface(new QDBusInterface("com.canonical.SystemImage",
24− "/Service",
25− "com.canonical.SystemImage",
26− QDBusConnection::systemBus(),
27− this))
28{
23{
29}
24}
30
25
31void SystemImage::factoryReset()
26void SystemImage::factoryReset()
32{
27{
28+ const QDBusMessage msg = QDBusMessage::createMethodCall("com.canonical.SystemImage",
29+ "/Service",
30+ "com.canonical.SystemImage",
33− m_interface->call("FactoryReset");
31+ "FactoryReset");
32+ QDBusConnection::systemBus().asyncCall(msg);
34}
33}
plugins/Ubuntu/SystemImage/SystemImage.h+1−5
@@ -19,8 +19,6 @@
19
19
20#include <QObject>
20#include <QObject>
21
21
22−class QDBusInterface;
23−
24class SystemImage : public QObject
22class SystemImage : public QObject
25{
23{
26 Q_OBJECT
24 Q_OBJECT
@@ -28,11 +26,9 @@ class SystemImage : public QObject
28
26
29public:
27public:
30 explicit SystemImage(QObject *parent = 0);
28 explicit SystemImage(QObject *parent = 0);
29+ ~SystemImage() = default;
31
30
32 Q_INVOKABLE void factoryReset();
31 Q_INVOKABLE void factoryReset();
33−
34−private:
35− QDBusInterface *m_interface;
36};
32};
37
33
38#endif // SYSTEMIMAGE_H
34#endif // SYSTEMIMAGE_H
plugins/Unity/Connectivity/Connectivity.cpp+5−5
@@ -16,7 +16,6 @@
16
16
17#include "Connectivity.h"
17#include "Connectivity.h"
18#include <QDBusConnection>
18#include <QDBusConnection>
19−#include <QDBusInterface>
20#include <QDBusPendingCall>
19#include <QDBusPendingCall>
21
20
22Connectivity::Connectivity(QObject *parent)
21Connectivity::Connectivity(QObject *parent)
@@ -26,8 +25,9 @@ Connectivity::Connectivity(QObject *parent)
26
25
27void Connectivity::unlockAllModems()
26void Connectivity::unlockAllModems()
28{
27{
29− QDBusInterface iface("com.ubuntu.connectivity1",
28+ const QDBusMessage msg = QDBusMessage::createMethodCall("com.ubuntu.connectivity1",
30− "/com/ubuntu/connectivity1/Private",
29+ "/com/ubuntu/connectivity1/Private",
31− "com.ubuntu.connectivity1.Private");
30+ "com.ubuntu.connectivity1.Private",
32− iface.asyncCall("UnlockAllModems");
31+ "UnlockAllModems");
32+ QDBusConnection::sessionBus().asyncCall(msg);
33}
33}
plugins/Unity/Connectivity/Connectivity.h+1
@@ -26,6 +26,7 @@ class Connectivity : public QObject
26
26
27public:
27public:
28 explicit Connectivity(QObject *parent = 0);
28 explicit Connectivity(QObject *parent = 0);
29+ ~Connectivity() = default;
29
30
30 Q_INVOKABLE void unlockAllModems();
31 Q_INVOKABLE void unlockAllModems();
31};
32};
plugins/Unity/DashCommunicator/dbusdashcommunicatorservice.h+1−1
@@ -36,4 +36,4 @@ public Q_SLOTS:
36
36
37};
37};
38
38
39−#endif // DBUSUNITYSESSIONSERVICE_H
39+#endif // DBUSDASHCOMMUNICATORSERVICE_H
plugins/Unity/DashCommunicator/plugin.cpp+1
@@ -25,6 +25,7 @@
25
25
26void DashCommunicatorPlugin::registerTypes(const char *uri)
26void DashCommunicatorPlugin::registerTypes(const char *uri)
27{
27{
28+ // @uri Unity.DashCommunicator
28 Q_ASSERT(uri == QStringLiteral("Unity.DashCommunicator"));
29 Q_ASSERT(uri == QStringLiteral("Unity.DashCommunicator"));
29 qmlRegisterType<DashCommunicatorService>(uri, 0, 1, "DashCommunicatorService");
30 qmlRegisterType<DashCommunicatorService>(uri, 0, 1, "DashCommunicatorService");
30 qmlRegisterType<DashCommunicator>(uri, 0, 1, "DashCommunicator");
31 qmlRegisterType<DashCommunicator>(uri, 0, 1, "DashCommunicator");
plugins/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,4 +1,4 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
4
4
plugins/Unity/Launcher/dbusinterface.cpp+23−13
@@ -32,10 +32,6 @@ DBusInterface::DBusInterface(LauncherModel *parent):
32{
32{
33}
33}
34
34
35−DBusInterface::~DBusInterface()
36−{
37−}
38−
39QString DBusInterface::introspect(const QString &path) const
35QString DBusInterface::introspect(const QString &path) const
40{
36{
41 /* This case we should just list the nodes */
37 /* This case we should just list the nodes */
@@ -67,6 +63,7 @@ QString DBusInterface::introspect(const QString &path) const
67 "<property name=\"count\" type=\"i\" access=\"readwrite\" />"
63 "<property name=\"count\" type=\"i\" access=\"readwrite\" />"
68 "<property name=\"countVisible\" type=\"b\" access=\"readwrite\" />"
64 "<property name=\"countVisible\" type=\"b\" access=\"readwrite\" />"
69 "<property name=\"progress\" type=\"i\" access=\"readwrite\" />"
65 "<property name=\"progress\" type=\"i\" access=\"readwrite\" />"
66+ "<method name=\"Alert\" />"
70 "</interface>";
67 "</interface>";
71 return nodeiface;
68 return nodeiface;
72}
69}
@@ -127,6 +124,20 @@ bool DBusInterface::handleMessage(const QDBusMessage& message, const QDBusConnec
127 return false;
124 return false;
128 }
125 }
129
126
127+ /* Break down the path to just the app id */
128+ bool validpath = true;
129+ QString pathtemp = message.path();
130+ if (!pathtemp.startsWith("/com/canonical/Unity/Launcher/")) {
131+ validpath = false;
132+ }
133+ pathtemp.remove("/com/canonical/Unity/Launcher/");
134+ if (pathtemp.indexOf('/') >= 0) {
135+ validpath = false;
136+ }
137+
138+ /* Find ourselves an appid */
139+ QString appid = decodeAppId(pathtemp);
140+
130 // First handle methods of the Launcher interface
141 // First handle methods of the Launcher interface
131 if (message.interface() == "com.canonical.Unity.Launcher") {
142 if (message.interface() == "com.canonical.Unity.Launcher") {
132 if (message.member() == "Refresh") {
143 if (message.member() == "Refresh") {
@@ -134,6 +145,13 @@ bool DBusInterface::handleMessage(const QDBusMessage& message, const QDBusConnec
134 Q_EMIT refreshCalled();
145 Q_EMIT refreshCalled();
135 return connection.send(reply);
146 return connection.send(reply);
136 }
147 }
148+ } else if (message.interface() == "com.canonical.Unity.Launcher.Item") {
149+ // Handle methods of the Launcher-Item interface
150+ if (message.member() == "Alert" && validpath) {
151+ QDBusMessage reply = message.createReply();
152+ Q_EMIT alertCalled(appid);
153+ return connection.send(reply);
154+ }
137 }
155 }
138
156
139 // Now handle dynamic properties (for launcher emblems)
157 // Now handle dynamic properties (for launcher emblems)
@@ -145,18 +163,10 @@ bool DBusInterface::handleMessage(const QDBusMessage& message, const QDBusConnec
145 return false;
163 return false;
146 }
164 }
147
165
148− /* Break down the path to just the app id */
166+ if (!validpath) {
149− QString pathtemp = message.path();
150− if (!pathtemp.startsWith("/com/canonical/Unity/Launcher/")) {
151− return false;
152− }
153− pathtemp.remove("/com/canonical/Unity/Launcher/");
154− if (pathtemp.indexOf('/') >= 0) {
155 return false;
167 return false;
156 }
168 }
157
169
158− /* Find ourselves an appid */
159− QString appid = decodeAppId(pathtemp);
160 int index = m_launcherModel->findApplication(appid);
170 int index = m_launcherModel->findApplication(appid);
161 LauncherItem *item = static_cast<LauncherItem*>(m_launcherModel->get(index));
171 LauncherItem *item = static_cast<LauncherItem*>(m_launcherModel->get(index));
162
172
plugins/Unity/Launcher/dbusinterface.h+2−1
@@ -27,7 +27,7 @@ class DBusInterface: public UnityDBusVirtualObject
27 Q_OBJECT
27 Q_OBJECT
28public:
28public:
29 DBusInterface(LauncherModel *parent);
29 DBusInterface(LauncherModel *parent);
30− ~DBusInterface();
30+ ~DBusInterface() = default;
31
31
32 // QDBusVirtualObject implementaition
32 // QDBusVirtualObject implementaition
33 QString introspect (const QString &path) const override;
33 QString introspect (const QString &path) const override;
@@ -38,6 +38,7 @@ Q_SIGNALS:
38 void countVisibleChanged(const QString &appId, bool countVisible);
38 void countVisibleChanged(const QString &appId, bool countVisible);
39 void progressChanged(const QString &appId, int progress);
39 void progressChanged(const QString &appId, int progress);
40 void refreshCalled();
40 void refreshCalled();
41+ void alertCalled(const QString &appId);
41
42
42private:
43private:
43 static QString decodeAppId(const QString& path);
44 static QString decodeAppId(const QString& path);
plugins/Unity/Launcher/launcheritem.cpp+23
@@ -34,6 +34,7 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
34 m_count(0),
34 m_count(0),
35 m_countVisible(false),
35 m_countVisible(false),
36 m_focused(false),
36 m_focused(false),
37+ m_alerting(false),
37 m_quickList(new QuickListModel(this))
38 m_quickList(new QuickListModel(this))
38{
39{
39 QuickListEntry nameAction;
40 QuickListEntry nameAction;
@@ -150,6 +151,9 @@ void LauncherItem::setCount(int count)
150 if (m_count != count) {
151 if (m_count != count) {
151 m_count = count;
152 m_count = count;
152 Q_EMIT countChanged(count);
153 Q_EMIT countChanged(count);
154+ if (m_countVisible) {
155+ setAlerting(true);
156+ }
153 }
157 }
154}
158}
155
159
@@ -163,6 +167,9 @@ void LauncherItem::setCountVisible(bool countVisible)
163 if (m_countVisible != countVisible) {
167 if (m_countVisible != countVisible) {
164 m_countVisible = countVisible;
168 m_countVisible = countVisible;
165 Q_EMIT countVisibleChanged(countVisible);
169 Q_EMIT countVisibleChanged(countVisible);
170+ if (countVisible) {
171+ setAlerting(true);
172+ }
166 }
173 }
167}
174}
168
175
@@ -175,10 +182,26 @@ void LauncherItem::setFocused(bool focused)
175{
182{
176 if (m_focused != focused) {
183 if (m_focused != focused) {
177 m_focused = focused;
184 m_focused = focused;
185+ if (focused) {
186+ setAlerting(false);
187+ }
178 Q_EMIT focusedChanged(focused);
188 Q_EMIT focusedChanged(focused);
179 }
189 }
180}
190}
181
191
192+bool LauncherItem::alerting() const
193+{
194+ return m_alerting;
195+}
196+
197+void LauncherItem::setAlerting(bool alerting)
198+{
199+ if (m_alerting != alerting) {
200+ m_alerting = alerting;
201+ Q_EMIT alertingChanged(alerting);
202+ }
203+}
204+
182unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
205unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
183{
206{
184 return m_quickList;
207 return m_quickList;
plugins/Unity/Launcher/launcheritem.h+3
@@ -44,6 +44,7 @@ public:
44 int count() const override;
44 int count() const override;
45 bool countVisible() const override;
45 bool countVisible() const override;
46 bool focused() const override;
46 bool focused() const override;
47+ bool alerting() const override;
47
48
48 unity::shell::launcher::QuickListModelInterface *quickList() const override;
49 unity::shell::launcher::QuickListModelInterface *quickList() const override;
49
50
@@ -57,6 +58,7 @@ private:
57 void setCount(int count);
58 void setCount(int count);
58 void setCountVisible(bool countVisible);
59 void setCountVisible(bool countVisible);
59 void setFocused(bool focused);
60 void setFocused(bool focused);
61+ void setAlerting(bool alerting);
60
62
61private:
63private:
62 QString m_appId;
64 QString m_appId;
@@ -69,6 +71,7 @@ private:
69 int m_count;
71 int m_count;
70 bool m_countVisible;
72 bool m_countVisible;
71 bool m_focused;
73 bool m_focused;
74+ bool m_alerting;
72 QuickListModel *m_quickList;
75 QuickListModel *m_quickList;
73
76
74 friend class LauncherModel;
77 friend class LauncherModel;
plugins/Unity/Launcher/launchermodel.cpp+31
@@ -42,6 +42,7 @@ LauncherModel::LauncherModel(QObject *parent):
42 connect(m_dbusIface, &DBusInterface::countVisibleChanged, this, &LauncherModel::countVisibleChanged);
42 connect(m_dbusIface, &DBusInterface::countVisibleChanged, this, &LauncherModel::countVisibleChanged);
43 connect(m_dbusIface, &DBusInterface::progressChanged, this, &LauncherModel::progressChanged);
43 connect(m_dbusIface, &DBusInterface::progressChanged, this, &LauncherModel::progressChanged);
44 connect(m_dbusIface, &DBusInterface::refreshCalled, this, &LauncherModel::refresh);
44 connect(m_dbusIface, &DBusInterface::refreshCalled, this, &LauncherModel::refresh);
45+ connect(m_dbusIface, &DBusInterface::alertCalled, this, &LauncherModel::alert);
45
46
46 connect(m_settings, &GSettings::changed, this, &LauncherModel::refresh);
47 connect(m_settings, &GSettings::changed, this, &LauncherModel::refresh);
47
48
@@ -83,11 +84,25 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
83 return item->progress();
84 return item->progress();
84 case RoleFocused:
85 case RoleFocused:
85 return item->focused();
86 return item->focused();
87+ case RoleAlerting:
88+ return item->alerting();
86 }
89 }
87
90
88 return QVariant();
91 return QVariant();
89}
92}
90
93
94+void LauncherModel::setAlerting(const QString &appId, bool alerting) {
95+ int index = findApplication(appId);
96+ if (index >= 0) {
97+ QModelIndex modelIndex = this->index(index);
98+ LauncherItem *item = m_list.at(index);
99+ if (!item->focused()) {
100+ item->setAlerting(alerting);
101+ Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RoleAlerting);
102+ }
103+ }
104+}
105+
91unity::shell::launcher::LauncherItemInterface *LauncherModel::get(int index) const
106unity::shell::launcher::LauncherItemInterface *LauncherModel::get(int index) const
92{
107{
93 if (index < 0 || index >= m_list.count()) {
108 if (index < 0 || index >= m_list.count()) {
@@ -335,6 +350,9 @@ void LauncherModel::countChanged(const QString &appId, int count)
335 if (idx >= 0) {
350 if (idx >= 0) {
336 LauncherItem *item = m_list.at(idx);
351 LauncherItem *item = m_list.at(idx);
337 item->setCount(count);
352 item->setCount(count);
353+ if (item->countVisible()) {
354+ setAlerting(item->appId(), true);
355+ }
338 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
356 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
339 m_asAdapter->syncItems(m_list);
357 m_asAdapter->syncItems(m_list);
340 }
358 }
@@ -346,6 +364,9 @@ void LauncherModel::countVisibleChanged(const QString &appId, int countVisible)
346 if (idx >= 0) {
364 if (idx >= 0) {
347 LauncherItem *item = m_list.at(idx);
365 LauncherItem *item = m_list.at(idx);
348 item->setCountVisible(countVisible);
366 item->setCountVisible(countVisible);
367+ if (countVisible) {
368+ setAlerting(item->appId(), true);
369+ }
349 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCountVisible);
370 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCountVisible);
350
371
351 // If countVisible goes to false, and the item is neither pinned nor recent we can drop it
372 // If countVisible goes to false, and the item is neither pinned nor recent we can drop it
@@ -454,6 +475,16 @@ void LauncherModel::refresh()
454 m_asAdapter->syncItems(m_list);
475 m_asAdapter->syncItems(m_list);
455}
476}
456
477
478+void LauncherModel::alert(const QString &appId)
479+{
480+ int idx = findApplication(appId);
481+ if (idx >= 0) {
482+ LauncherItem *item = m_list.at(idx);
483+ setAlerting(item->appId(), true);
484+ Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleAlerting);
485+ }
486+}
487+
457void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
488void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
458{
489{
459 Q_UNUSED(parent);
490 Q_UNUSED(parent);
plugins/Unity/Launcher/launchermodel.h+2
@@ -45,6 +45,7 @@ public:
45
45
46 QVariant data(const QModelIndex &index, int role) const override;
46 QVariant data(const QModelIndex &index, int role) const override;
47
47
48+ Q_INVOKABLE void setAlerting(const QString &appId, bool alerting) override;
48 Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const override;
49 Q_INVOKABLE unity::shell::launcher::LauncherItemInterface* get(int index) const override;
49 Q_INVOKABLE void move(int oldIndex, int newIndex) override;
50 Q_INVOKABLE void move(int oldIndex, int newIndex) override;
50 Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
51 Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
@@ -63,6 +64,7 @@ public:
63public Q_SLOTS:
64public Q_SLOTS:
64 void requestRemove(const QString &appId) override;
65 void requestRemove(const QString &appId) override;
65 Q_INVOKABLE void refresh();
66 Q_INVOKABLE void refresh();
67+ Q_INVOKABLE void alert(const QString &appId);
66
68
67private:
69private:
68 void storeAppList();
70 void storeAppList();
plugins/Unity/Session/dbusunitysessionservice.cpp+47−55
@@ -18,77 +18,69 @@
18#include "dbusunitysessionservice.h"
18#include "dbusunitysessionservice.h"
19
19
20// Qt
20// Qt
21−#include <QDBusConnection>
21+#include <QDBusPendingCall>
22−#include <QDBusInterface>
23
22
24DBusUnitySessionService::DBusUnitySessionService()
23DBusUnitySessionService::DBusUnitySessionService()
25 : UnityDBusObject("/com/canonical/Unity/Session", "com.canonical.Unity")
24 : UnityDBusObject("/com/canonical/Unity/Session", "com.canonical.Unity")
26{
25{
27}
26}
28
27
29−DBusUnitySessionService::~DBusUnitySessionService()
30−{
31−}
32−
33void DBusUnitySessionService::Logout()
28void DBusUnitySessionService::Logout()
34{
29{
30+ // TODO ask the apps to quit and then emit the signal
35− Q_EMIT logoutReady();
31+ Q_EMIT logoutReady();
36}
32}
37
33
38void DBusUnitySessionService::EndSession()
34void DBusUnitySessionService::EndSession()
39{
35{
40− QDBusConnection connection = QDBusConnection::sessionBus();
36+ const QDBusMessage msg = QDBusMessage::createMethodCall("com.ubuntu.Upstart",
41− QDBusInterface iface1 ("com.ubuntu.Upstart",
42− "/com/ubuntu/Upstart",
37+ "/com/ubuntu/Upstart",
43− "com.ubuntu.Upstart0_6",
38+ "com.ubuntu.Upstart0_6",
44− connection);
45−
46− iface1.call("EndSession");
39+ "EndSession");
40+ QDBusConnection::sessionBus().asyncCall(msg);
47}
41}
48
42
49void DBusUnitySessionService::RequestLogout()
43void DBusUnitySessionService::RequestLogout()
50{
44{
51− Q_EMIT logoutRequested(false);
45+ Q_EMIT logoutRequested(false);
52}
46}
53
47
54void DBusUnitySessionService::Reboot()
48void DBusUnitySessionService::Reboot()
55{
49{
56− QDBusConnection connection = QDBusConnection::systemBus();
50+ QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.login1",
57− QDBusInterface iface1 ("org.freedesktop.login1",
58− "/org/freedesktop/login1",
51+ "/org/freedesktop/login1",
59− "org.freedesktop.login1.Manager",
52+ "org.freedesktop.login1.Manager",
60− connection);
61−
62− iface1.call("Reboot", false);
53+ "Reboot");
54+ msg << false;
55+ QDBusConnection::systemBus().asyncCall(msg);
63}
56}
64
57
65void DBusUnitySessionService::RequestReboot()
58void DBusUnitySessionService::RequestReboot()
66{
59{
67− Q_EMIT rebootRequested(false);
60+ Q_EMIT rebootRequested(false);
68}
61}
69
62
70void DBusUnitySessionService::Shutdown()
63void DBusUnitySessionService::Shutdown()
71{
64{
72− QDBusConnection connection = QDBusConnection::systemBus();
65+ QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.login1",
73− QDBusInterface iface1 ("org.freedesktop.login1",
74− "/org/freedesktop/login1",
66+ "/org/freedesktop/login1",
75− "org.freedesktop.login1.Manager",
67+ "org.freedesktop.login1.Manager",
76− connection);
77−
78− iface1.call("PowerOff", false);
68+ "PowerOff");
69+ msg << false;
70+ QDBusConnection::systemBus().asyncCall(msg);
79}
71}
80
72
81void DBusUnitySessionService::RequestShutdown()
73void DBusUnitySessionService::RequestShutdown()
82{
74{
83− Q_EMIT shutdownRequested(false);
75+ Q_EMIT shutdownRequested(false);
84}
76}
85
77
86enum class Action : unsigned
78enum class Action : unsigned
87{
79{
88− LOGOUT = 0,
80+ LOGOUT = 0,
89− SHUTDOWN,
81+ SHUTDOWN,
90− REBOOT,
82+ REBOOT,
91− NONE
83+ NONE
92};
84};
93
85
94DBusGnomeSessionManagerWrapper::DBusGnomeSessionManagerWrapper()
86DBusGnomeSessionManagerWrapper::DBusGnomeSessionManagerWrapper()
@@ -96,38 +88,38 @@ DBusGnomeSessionManagerWrapper::DBusGnomeSessionManagerWrapper()
96{
88{
97}
89}
98
90
99−DBusGnomeSessionManagerWrapper::~DBusGnomeSessionManagerWrapper()
91+void DBusGnomeSessionManagerWrapper::performAsyncCall(const QString &method)
100{
92{
93+ const QDBusMessage msg = QDBusMessage::createMethodCall("com.canonical.Unity",
94+ "/com/canonical/Unity/Session",
95+ "com.canonical.Unity.Session",
96+ method);
97+ QDBusConnection::sessionBus().asyncCall(msg);
101}
98}
102
99
103void DBusGnomeSessionManagerWrapper::Open(const unsigned type, const unsigned arg_1, const unsigned max_wait, const QList<QDBusObjectPath> &inhibitors)
100void DBusGnomeSessionManagerWrapper::Open(const unsigned type, const unsigned arg_1, const unsigned max_wait, const QList<QDBusObjectPath> &inhibitors)
104{
101{
105− Q_UNUSED(arg_1);
102+ Q_UNUSED(arg_1);
106− Q_UNUSED(max_wait);
103+ Q_UNUSED(max_wait);
107− Q_UNUSED(inhibitors);
104+ Q_UNUSED(inhibitors);
108−
109− QDBusConnection connection = QDBusConnection::sessionBus();
110− QDBusInterface iface1 ("com.canonical.Unity",
111− "/com/canonical/Unity/Session",
112− "com.canonical.Unity.Session",
113− connection);
114
105
115− Action action = (Action)type;
106+ const Action action = (Action)type;
116
107
117− switch (action)
108+ switch (action)
118− {
109+ {
119 case Action::LOGOUT:
110 case Action::LOGOUT:
120− iface1.call("RequestLogout");
111+ performAsyncCall("RequestLogout");
121− break;
112+ break;
122
113
123 case Action::REBOOT:
114 case Action::REBOOT:
124− iface1.call("RequestShutdown");
115+ performAsyncCall("RequestReboot");
125− break;
116+ break;
126
117
127 case Action::SHUTDOWN:
118 case Action::SHUTDOWN:
119+ performAsyncCall("RequestShutdown");
128− break;
120+ break;
129
121
130 default:
122 default:
131− break;
123+ break;
132− }
124+ }
133}
125}
plugins/Unity/Session/dbusunitysessionservice.h+11−8
@@ -38,7 +38,7 @@ class DBusUnitySessionService : public UnityDBusObject
38
38
39public:
39public:
40 DBusUnitySessionService();
40 DBusUnitySessionService();
41− ~DBusUnitySessionService();
41+ ~DBusUnitySessionService() = default;
42
42
43 // For use in QML. Javascript doesn't accept functions beginning with capital letters
43 // For use in QML. Javascript doesn't accept functions beginning with capital letters
44 Q_INVOKABLE void logout() { Logout(); }
44 Q_INVOKABLE void logout() { Logout(); }
@@ -90,7 +90,7 @@ public Q_SLOTS:
90 /**
90 /**
91 * Logout the system.
91 * Logout the system.
92 *
92 *
93− * This method directly logout the system without user's confirmation.
93+ * This method directly logs out the system without user's confirmation.
94 * Ordinary applications should avoid calling this method. Please call
94 * Ordinary applications should avoid calling this method. Please call
95 * RequestLogout() to ask the user to decide logout or not.
95 * RequestLogout() to ask the user to decide logout or not.
96 */
96 */
@@ -99,7 +99,7 @@ public Q_SLOTS:
99 /**
99 /**
100 * Reboot the system.
100 * Reboot the system.
101 *
101 *
102− * This method directly reboot the system without user's confirmation.
102+ * This method directly reboots the system without user's confirmation.
103 * Ordinary applications should avoid calling this method. Please call
103 * Ordinary applications should avoid calling this method. Please call
104 * RequestReboot() to ask the user to decide reboot or not.
104 * RequestReboot() to ask the user to decide reboot or not.
105 */
105 */
@@ -108,7 +108,7 @@ public Q_SLOTS:
108 /**
108 /**
109 * Shutdown the system.
109 * Shutdown the system.
110 *
110 *
111− * This method directly shutdown the system without user's confirmation.
111+ * This method directly shuts down the system without user's confirmation.
112 * Ordinary applications should avoid calling this method. Please call
112 * Ordinary applications should avoid calling this method. Please call
113 * RequestShutdown() to ask the user to decide shutdown or not.
113 * RequestShutdown() to ask the user to decide shutdown or not.
114 */
114 */
@@ -117,7 +117,7 @@ public Q_SLOTS:
117 /**
117 /**
118 * Issue a logout request.
118 * Issue a logout request.
119 *
119 *
120− * This method emit the logoutRequested signal to the shell with a boolean
120+ * This method emits the logoutRequested signal to the shell with a boolean
121 * which indicates if there's any inhibitors. The shell should receive
121 * which indicates if there's any inhibitors. The shell should receive
122 * this signal and display a dialog to ask the user to confirm the logout
122 * this signal and display a dialog to ask the user to confirm the logout
123 * action. If confirmed, shell can call Logout() method to logout.
123 * action. If confirmed, shell can call Logout() method to logout.
@@ -127,7 +127,7 @@ public Q_SLOTS:
127 /**
127 /**
128 * Issue a reboot request.
128 * Issue a reboot request.
129 *
129 *
130− * This method emit the rebootRequested signal to the shell with a boolean
130+ * This method emits the rebootRequested signal to the shell with a boolean
131 * which indicates if there's any inhibitors. The shell should receive
131 * which indicates if there's any inhibitors. The shell should receive
132 * this signal and display a dialog to ask the user to confirm the reboot
132 * this signal and display a dialog to ask the user to confirm the reboot
133 * action. If confirmed, shell can call Reboot() method to reboot
133 * action. If confirmed, shell can call Reboot() method to reboot
@@ -137,7 +137,7 @@ public Q_SLOTS:
137 /**
137 /**
138 * Issue a shutdown request.
138 * Issue a shutdown request.
139 *
139 *
140− * This method emit the shutdownRequested signal to the shell with a
140+ * This method emits the shutdownRequested signal to the shell with a
141 * boolean which indicates if there's any inhibitors.
141 * boolean which indicates if there's any inhibitors.
142 * The shell should receive
142 * The shell should receive
143 * this signal and display a dialog to ask the user to confirm the reboot
143 * this signal and display a dialog to ask the user to confirm the reboot
@@ -161,9 +161,12 @@ class DBusGnomeSessionManagerWrapper : public UnityDBusObject
161
161
162public:
162public:
163 DBusGnomeSessionManagerWrapper();
163 DBusGnomeSessionManagerWrapper();
164− ~DBusGnomeSessionManagerWrapper();
164+ ~DBusGnomeSessionManagerWrapper() = default;
165
165
166public Q_SLOTS:
166public Q_SLOTS:
167 Q_SCRIPTABLE void Open(const unsigned int type, const unsigned int arg_1, const unsigned int max_wait, const QList<QDBusObjectPath> &inhibitors);
167 Q_SCRIPTABLE void Open(const unsigned int type, const unsigned int arg_1, const unsigned int max_wait, const QList<QDBusObjectPath> &inhibitors);
168+
169+private:
170+ void performAsyncCall(const QString &method);
168};
171};
169#endif // DBUSUNITYSESSIONSERVICE_H
172#endif // DBUSUNITYSESSIONSERVICE_H
plugins/Wizard/System.cpp+13−9
@@ -16,7 +16,9 @@
16
16
17#include "System.h"
17#include "System.h"
18
18
19−#include <QDBusInterface>
19+#include <QDBusPendingCall>
20+#include <QDBusMessage>
21+#include <QDBusConnection>
20#include <QDBusMetaType>
22#include <QDBusMetaType>
21#include <QDir>
23#include <QDir>
22#include <QFile>
24#include <QFile>
@@ -65,21 +67,23 @@ void System::setWizardEnabled(bool enabled)
65void System::setSessionVariable(const QString &variable, const QString &value)
67void System::setSessionVariable(const QString &variable, const QString &value)
66{
68{
67 // We need to update both upstart's and DBus's environment
69 // We need to update both upstart's and DBus's environment
68− QProcess::execute(QString("initctl set-env --global %1=%2").arg(variable, value));
70+ QProcess::startDetached(QStringLiteral("initctl set-env --global %1=%2").arg(variable, value));
69−
70− QDBusInterface iface("org.freedesktop.DBus",
71− "/org/freedesktop/DBus",
72− "org.freedesktop.DBus",
73− QDBusConnection::sessionBus());
74
71
75 QMap<QString,QString> valueMap;
72 QMap<QString,QString> valueMap;
76 valueMap.insert(variable, value);
73 valueMap.insert(variable, value);
74+
75+ QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus",
76+ "/org/freedesktop/DBus",
77+ "org.freedesktop.DBus",
77− iface.call("UpdateActivationEnvironment", QVariant::fromValue(valueMap));
78+ "UpdateActivationEnvironment");
79+
80+ msg << QVariant::fromValue(valueMap);
81+ QDBusConnection::sessionBus().asyncCall(msg);
78}
82}
79
83
80void System::updateSessionLanguage(const QString &locale)
84void System::updateSessionLanguage(const QString &locale)
81{
85{
82− QString language = locale.split(".")[0];
86+ const QString language = locale.split(".")[0];
83
87
84 setSessionVariable("LANGUAGE", language);
88 setSessionVariable("LANGUAGE", language);
85 setSessionVariable("LANG", locale);
89 setSessionVariable("LANG", locale);
po/ar.po+76−61
@@ -8,7 +8,7 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2015-06-22 12:00+0200\n"
10"POT-Creation-Date: 2015-06-22 12:00+0200\n"
11−"PO-Revision-Date: 2015-07-14 11:45+0000\n"
11+"PO-Revision-Date: 2015-07-17 12:36+0000\n"
12"Last-Translator: Ibrahim Saed <ibraheem5000@gmail.com>\n"
12"Last-Translator: Ibrahim Saed <ibraheem5000@gmail.com>\n"
13"Language-Team: Arabic <ar@li.org>\n"
13"Language-Team: Arabic <ar@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
@@ -16,7 +16,7 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= "
17"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= "
18"3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n"
18"3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n"
19−"X-Launchpad-Export-Date: 2015-07-16 05:44+0000\n"
19+"X-Launchpad-Export-Date: 2015-07-21 05:35+0000\n"
20"X-Generator: Launchpad (build 17628)\n"
20"X-Generator: Launchpad (build 17628)\n"
21
21
22#: plugins/LightDM/Greeter.cpp:112
22#: plugins/LightDM/Greeter.cpp:112
@@ -364,19 +364,19 @@ msgstr "أدخِل الرمز السرّي"
364#: qml/Greeter/NarrowView.qml:118
364#: qml/Greeter/NarrowView.qml:118
365#, qt-format
365#, qt-format
366msgid "Sorry, incorrect %1"
366msgid "Sorry, incorrect %1"
367−msgstr ""
367+msgstr "نأسف، %1 غير صحيحية"
368
368
369#: qml/Greeter/NarrowView.qml:119
369#: qml/Greeter/NarrowView.qml:119
370msgid "Sorry, incorrect passphrase"
370msgid "Sorry, incorrect passphrase"
371−msgstr ""
371+msgstr "نأسف، عبارة السّر غير صحيحية"
372
372
373#: qml/Greeter/NarrowView.qml:120
373#: qml/Greeter/NarrowView.qml:120
374msgid "Please re-enter"
374msgid "Please re-enter"
375−msgstr ""
375+msgstr "برجاء إعادة إدخالها"
376
376
377#: qml/Greeter/NarrowView.qml:121
377#: qml/Greeter/NarrowView.qml:121
378msgid "Sorry, incorrect passcode"
378msgid "Sorry, incorrect passcode"
379−msgstr ""
379+msgstr "نأسف، الرمز السري غير صحيح"
380
380
381#: qml/Notifications/NotificationMenuItemFactory.qml:128
381#: qml/Notifications/NotificationMenuItemFactory.qml:128
382msgid "Show password"
382msgid "Show password"
@@ -384,7 +384,7 @@ msgstr "عرض كلمة السر"
384
384
385#: qml/Panel/ActiveCallHint.qml:79
385#: qml/Panel/ActiveCallHint.qml:79
386msgid "Tap to return to call..."
386msgid "Tap to return to call..."
387−msgstr ""
387+msgstr "انقر للعودة إلى المكالمة..."
388
388
389#: qml/Panel/ActiveCallHint.qml:92
389#: qml/Panel/ActiveCallHint.qml:92
390msgid "Conference"
390msgid "Conference"
@@ -398,52 +398,64 @@ msgstr ""
398#, qt-format
398#, qt-format
399msgid "%1 hour"
399msgid "%1 hour"
400msgid_plural "%1 hours"
400msgid_plural "%1 hours"
401−msgstr[0] ""
401+msgstr[0] "أقل من ساعة (%1)"
402+msgstr[1] "ساعة واحدة (%1)"
403+msgstr[2] "ساعتان (%1)"
404+msgstr[3] "%1 ساعات"
402−msgstr[1] ""
405+msgstr[4] "%1 ساعة"
406+msgstr[5] "%1 ساعة"
403
407
404#: qml/Panel/Indicators/MenuItemFactory.qml:772
408#: qml/Panel/Indicators/MenuItemFactory.qml:772
405#, qt-format
409#, qt-format
406msgid "%1 minute"
410msgid "%1 minute"
407msgid_plural "%1 minutes"
411msgid_plural "%1 minutes"
408−msgstr[0] ""
412+msgstr[0] "أقل من دقيقة (%1)"
413+msgstr[1] "دقيقة واحدة (%1)"
414+msgstr[2] "دقيقتان (%1)"
415+msgstr[3] "%1 دقائق"
409−msgstr[1] ""
416+msgstr[4] "%1 دقيقة"
417+msgstr[5] "%1 دقيقة"
410
418
411#: qml/Panel/Indicators/MenuItemFactory.qml:777
419#: qml/Panel/Indicators/MenuItemFactory.qml:777
412#, qt-format
420#, qt-format
413msgid "%1 second"
421msgid "%1 second"
414msgid_plural "%1 seconds"
422msgid_plural "%1 seconds"
415−msgstr[0] ""
423+msgstr[0] "أقل من ثانية (%1)"
424+msgstr[1] "ثانية واحدة (%1)"
425+msgstr[2] "ثانيتان (%1)"
426+msgstr[3] "%1 ثوان"
416−msgstr[1] ""
427+msgstr[4] "%1 ثانية"
428+msgstr[5] "%1 ثانية"
417
429
418#: qml/Panel/Indicators/MenuItemFactory.qml:780
430#: qml/Panel/Indicators/MenuItemFactory.qml:780
419msgid "0 seconds"
431msgid "0 seconds"
420−msgstr ""
432+msgstr "أقل من ثانية"
421
433
422#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
434#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
423#: qml/Panel/Indicators/MenuItemFactory.qml:782
435#: qml/Panel/Indicators/MenuItemFactory.qml:782
424#, qt-format
436#, qt-format
425msgid "%1 remaining"
437msgid "%1 remaining"
426−msgstr ""
438+msgstr "باق %1"
427
439
428#: qml/Panel/Indicators/MenuItemFactory.qml:788
440#: qml/Panel/Indicators/MenuItemFactory.qml:788
429msgid "In queue…"
441msgid "In queue…"
430−msgstr ""
442+msgstr "في الانتظار..."
431
443
432#: qml/Panel/Indicators/MenuItemFactory.qml:792
444#: qml/Panel/Indicators/MenuItemFactory.qml:792
433msgid "Downloading"
445msgid "Downloading"
434−msgstr ""
446+msgstr "التنزيل"
435
447
436#: qml/Panel/Indicators/MenuItemFactory.qml:794
448#: qml/Panel/Indicators/MenuItemFactory.qml:794
437msgid "Paused, tap to resume"
449msgid "Paused, tap to resume"
438−msgstr ""
450+msgstr "مُلبث، انقر للاستئناف"
439
451
440#: qml/Panel/Indicators/MenuItemFactory.qml:796
452#: qml/Panel/Indicators/MenuItemFactory.qml:796
441msgid "Canceled"
453msgid "Canceled"
442−msgstr ""
454+msgstr "تم إلغائه"
443
455
444#: qml/Panel/Indicators/MenuItemFactory.qml:798
456#: qml/Panel/Indicators/MenuItemFactory.qml:798
445msgid "Finished"
457msgid "Finished"
446−msgstr ""
458+msgstr "انتهى"
447
459
448#: qml/Panel/Indicators/MenuItemFactory.qml:800
460#: qml/Panel/Indicators/MenuItemFactory.qml:800
449msgid "Failed, tap to retry"
461msgid "Failed, tap to retry"
@@ -460,36 +472,36 @@ msgstr ""
460
472
461#: qml/Panel/Indicators/RoamingIndication.qml:27
473#: qml/Panel/Indicators/RoamingIndication.qml:27
462msgid "Roaming"
474msgid "Roaming"
463−msgstr ""
475+msgstr "التجوال"
464
476
465#: qml/Tutorial/TutorialBottomFinish.qml:24
477#: qml/Tutorial/TutorialBottomFinish.qml:24
466msgid "This action does different things for different apps"
478msgid "This action does different things for different apps"
467−msgstr ""
479+msgstr "هذا الإجراء يقوم بأشياء مختلفة على التطبيقات المختلفة"
468
480
469#: qml/Tutorial/TutorialBottomFinish.qml:25
481#: qml/Tutorial/TutorialBottomFinish.qml:25
470msgid "Tap here to finish."
482msgid "Tap here to finish."
471−msgstr ""
483+msgstr "انقر هنا للإنهاء."
472
484
473#: qml/Tutorial/TutorialBottom.qml:28
485#: qml/Tutorial/TutorialBottom.qml:28
474msgid "Open special menus"
486msgid "Open special menus"
475−msgstr ""
487+msgstr "فتح قوائم خاصة"
476
488
477#: qml/Tutorial/TutorialBottom.qml:29
489#: qml/Tutorial/TutorialBottom.qml:29
478msgid "Swipe up from the bottom edge."
490msgid "Swipe up from the bottom edge."
479−msgstr ""
491+msgstr "اسحب لأعلى من الحافة السفلى."
480
492
481#: qml/Tutorial/TutorialContent.qml:81 qml/Tutorial/TutorialLeftFinish.qml:25
493#: qml/Tutorial/TutorialContent.qml:81 qml/Tutorial/TutorialLeftFinish.qml:25
482#: qml/Tutorial/TutorialRight.qml:144
494#: qml/Tutorial/TutorialRight.qml:144
483msgid "Tap here to continue."
495msgid "Tap here to continue."
484−msgstr ""
496+msgstr "انقر هنا للمتابعة."
485
497
486#: qml/Tutorial/TutorialContent.qml:81
498#: qml/Tutorial/TutorialContent.qml:81
487msgid "Click here to finish."
499msgid "Click here to finish."
488−msgstr ""
500+msgstr "انقر هنا للإنهاء."
489
501
490#: qml/Tutorial/TutorialLeftFinish.qml:24
502#: qml/Tutorial/TutorialLeftFinish.qml:24
491msgid "These are the shortcuts to favorite apps"
503msgid "These are the shortcuts to favorite apps"
492−msgstr ""
504+msgstr "هذه اختصارات للتطبيقات المُفضلة"
493
505
494#: qml/Tutorial/TutorialLeft.qml:26
506#: qml/Tutorial/TutorialLeft.qml:26
495msgid "Open the launcher"
507msgid "Open the launcher"
@@ -497,7 +509,7 @@ msgstr ""
497
509
498#: qml/Tutorial/TutorialLeft.qml:27
510#: qml/Tutorial/TutorialLeft.qml:27
499msgid "Short swipe from the left edge."
511msgid "Short swipe from the left edge."
500−msgstr ""
512+msgstr "اسحب سحبة قصيرة من الحافة اليسرى."
501
513
502#: qml/Tutorial/TutorialPage.qml:178
514#: qml/Tutorial/TutorialPage.qml:178
503msgid "You almost got it!"
515msgid "You almost got it!"
@@ -505,7 +517,7 @@ msgstr ""
505
517
506#: qml/Tutorial/TutorialPage.qml:195
518#: qml/Tutorial/TutorialPage.qml:195
507msgid "Try again."
519msgid "Try again."
508−msgstr ""
520+msgstr "حاول مجددًا."
509
521
510#: qml/Tutorial/TutorialRight.qml:31
522#: qml/Tutorial/TutorialRight.qml:31
511msgid "To view open apps"
523msgid "To view open apps"
@@ -513,138 +525,141 @@ msgstr ""
513
525
514#: qml/Tutorial/TutorialRight.qml:32
526#: qml/Tutorial/TutorialRight.qml:32
515msgid "Long swipe from the right edge."
527msgid "Long swipe from the right edge."
516−msgstr ""
528+msgstr "سحبة طويلة من الحافة اليمنى."
517
529
518#: qml/Tutorial/TutorialRight.qml:122
530#: qml/Tutorial/TutorialRight.qml:122
519msgid "View all your running tasks."
531msgid "View all your running tasks."
520−msgstr ""
532+msgstr "عرض جميع المهام النشطة."
521
533
522#: qml/Wizard/Page.qml:89
534#: qml/Wizard/Page.qml:89
523msgctxt "Button: Go back one page in the Wizard"
535msgctxt "Button: Go back one page in the Wizard"
524msgid "Back"
536msgid "Back"
525−msgstr ""
537+msgstr "عودة"
526
538
527#: qml/Wizard/Pages/here-terms.qml:27
539#: qml/Wizard/Pages/here-terms.qml:27
528msgid "Terms & Conditions"
540msgid "Terms & Conditions"
529−msgstr ""
541+msgstr "الشروط والأحكام"
530
542
531#: qml/Wizard/Pages/passwd-confirm.qml:49
543#: qml/Wizard/Pages/passwd-confirm.qml:49
532msgid "Confirm passphrase"
544msgid "Confirm passphrase"
533−msgstr ""
545+msgstr "تأكيد العبارة السرية"
534
546
535#: qml/Wizard/Pages/passwd-confirm.qml:50
547#: qml/Wizard/Pages/passwd-confirm.qml:50
536msgid "Confirm passcode"
548msgid "Confirm passcode"
537−msgstr ""
549+msgstr "تأكيد الرمز السري"
538
550
539#: qml/Wizard/Pages/passwd-confirm.qml:53
551#: qml/Wizard/Pages/passwd-confirm.qml:53
540#: qml/Wizard/Pages/passwd-confirm.qml:54
552#: qml/Wizard/Pages/passwd-confirm.qml:54
541msgid "Please try again."
553msgid "Please try again."
542−msgstr ""
554+msgstr "حاول مجددا."
543
555
544#: qml/Wizard/Pages/passwd-confirm.qml:82 qml/Wizard/Pages/passwd-set.qml:90
556#: qml/Wizard/Pages/passwd-confirm.qml:82 qml/Wizard/Pages/passwd-set.qml:90
545#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
557#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
546#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
558#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
547#: qml/Wizard/Pages/60-reporting.qml:50
559#: qml/Wizard/Pages/60-reporting.qml:50
548msgid "Continue"
560msgid "Continue"
549−msgstr ""
561+msgstr "متابعة"
550
562
551#: qml/Wizard/Pages/passwd-set.qml:61
563#: qml/Wizard/Pages/passwd-set.qml:61
552msgid "Choose your passcode"
564msgid "Choose your passcode"
553−msgstr ""
565+msgstr "اختر الرمز السري خاصتك"
554
566
555#: qml/Wizard/Pages/passwd-set.qml:68
567#: qml/Wizard/Pages/passwd-set.qml:68
556msgid "Passphrase must be 4 characters long"
568msgid "Passphrase must be 4 characters long"
557−msgstr ""
569+msgstr "يجب أن تحتوي العبارة السرية على 4 أحرف على الأقل"
558
570
559#: qml/Wizard/Pages/10-welcome.qml:27
571#: qml/Wizard/Pages/10-welcome.qml:27
560msgid "Hi!"
572msgid "Hi!"
561−msgstr ""
573+msgstr "أهلا!"
562
574
563#: qml/Wizard/Pages/10-welcome.qml:44
575#: qml/Wizard/Pages/10-welcome.qml:44
564msgid "Welcome to your Ubuntu phone."
576msgid "Welcome to your Ubuntu phone."
565−msgstr ""
577+msgstr "مرحبا بك في أوبونتو للهواتف."
566
578
567#: qml/Wizard/Pages/10-welcome.qml:52
579#: qml/Wizard/Pages/10-welcome.qml:52
568msgid "Let’s get started."
580msgid "Let’s get started."
569−msgstr ""
581+msgstr "هيا بنا نبدأ."
570
582
571#: qml/Wizard/Pages/20-sim.qml:25
583#: qml/Wizard/Pages/20-sim.qml:25
572msgid "Add a SIM card and restart your device"
584msgid "Add a SIM card and restart your device"
573−msgstr ""
585+msgstr "أدخِل شريحة SIM ثم أعِد تشغيل الجهاز"
574
586
575#: qml/Wizard/Pages/20-sim.qml:59
587#: qml/Wizard/Pages/20-sim.qml:59
576msgid "Without it, you won’t be able to make calls or use text messaging."
588msgid "Without it, you won’t be able to make calls or use text messaging."
577msgstr ""
589msgstr ""
590+"بدونها لن تتمكن من إجراء أي مكالمات هاتفية أو استخدام الرسائل النصية."
578
591
579#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
592#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
580msgid "Skip"
593msgid "Skip"
581−msgstr ""
594+msgstr "تخطي"
582
595
583#: qml/Wizard/Pages/30-passwd-type.qml:39
596#: qml/Wizard/Pages/30-passwd-type.qml:39
584msgid "Lock security"
597msgid "Lock security"
585−msgstr ""
598+msgstr "قِفل الأمان"
586
599
587#: qml/Wizard/Pages/30-passwd-type.qml:74
600#: qml/Wizard/Pages/30-passwd-type.qml:74
588msgid "Please select how you’d like to unlock your phone."
601msgid "Please select how you’d like to unlock your phone."
589−msgstr ""
602+msgstr "رجاءً اختر الطريقة التي ترغب بأن توصد هاتفك بها."
590
603
591#: qml/Wizard/Pages/30-passwd-type.qml:97
604#: qml/Wizard/Pages/30-passwd-type.qml:97
592msgctxt "Label: Type of security method"
605msgctxt "Label: Type of security method"
593msgid "Swipe"
606msgid "Swipe"
594−msgstr ""
607+msgstr "سحبة"
595
608
596#: qml/Wizard/Pages/30-passwd-type.qml:98
609#: qml/Wizard/Pages/30-passwd-type.qml:98
597msgctxt "Label: Description of security method"
610msgctxt "Label: Description of security method"
598msgid "No security"
611msgid "No security"
599−msgstr ""
612+msgstr "بدون أمان"
600
613
601#: qml/Wizard/Pages/30-passwd-type.qml:100
614#: qml/Wizard/Pages/30-passwd-type.qml:100
602msgctxt "Label: Type of security method"
615msgctxt "Label: Type of security method"
603msgid "Passcode"
616msgid "Passcode"
604−msgstr ""
617+msgstr "رمز سري"
605
618
606#: qml/Wizard/Pages/30-passwd-type.qml:101
619#: qml/Wizard/Pages/30-passwd-type.qml:101
607msgctxt "Label: Description of security method"
620msgctxt "Label: Description of security method"
608msgid "4 digits only"
621msgid "4 digits only"
609−msgstr ""
622+msgstr "4 أرقام فقط"
610
623
611#: qml/Wizard/Pages/30-passwd-type.qml:103
624#: qml/Wizard/Pages/30-passwd-type.qml:103
612msgctxt "Label: Type of security method"
625msgctxt "Label: Type of security method"
613msgid "Passphrase"
626msgid "Passphrase"
614−msgstr ""
627+msgstr "عبارة سرية"
615
628
616#: qml/Wizard/Pages/30-passwd-type.qml:104
629#: qml/Wizard/Pages/30-passwd-type.qml:104
617msgctxt "Label: Description of security method"
630msgctxt "Label: Description of security method"
618msgid "Numbers and letters"
631msgid "Numbers and letters"
619−msgstr ""
632+msgstr "أرقام وحروف"
620
633
621#: qml/Wizard/Pages/40-wifi.qml:29
634#: qml/Wizard/Pages/40-wifi.qml:29
622msgid "Connect to Wi‑Fi"
635msgid "Connect to Wi‑Fi"
623−msgstr ""
636+msgstr "اتصل بالواي فاي"
624
637
625#: qml/Wizard/Pages/40-wifi.qml:168
638#: qml/Wizard/Pages/40-wifi.qml:168
626msgid "Available networks…"
639msgid "Available networks…"
627−msgstr ""
640+msgstr "الشبكات المتاحة..."
628
641
629#: qml/Wizard/Pages/40-wifi.qml:169
642#: qml/Wizard/Pages/40-wifi.qml:169
630msgid "No available networks."
643msgid "No available networks."
631−msgstr ""
644+msgstr "لا توجد شبكات متاحة."
632
645
633#: qml/Wizard/Pages/50-location.qml:27
646#: qml/Wizard/Pages/50-location.qml:27
634msgid "Location"
647msgid "Location"
635−msgstr ""
648+msgstr "الموقع"
636
649
637#: qml/Wizard/Pages/50-location.qml:62
650#: qml/Wizard/Pages/50-location.qml:62
638msgid "Let the phone detect your location:"
651msgid "Let the phone detect your location:"
639−msgstr ""
652+msgstr "دع هاتفك يحدد موقعك:"
640
653
641#: qml/Wizard/Pages/50-location.qml:69
654#: qml/Wizard/Pages/50-location.qml:69
642msgid "Using GPS only (less accurate)"
655msgid "Using GPS only (less accurate)"
643−msgstr ""
656+msgstr "باستخدام نظام تحديد المواقع (GPS) فقط (أقل دقّة)"
644
657
645#: qml/Wizard/Pages/50-location.qml:86
658#: qml/Wizard/Pages/50-location.qml:86
646msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
659msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
647msgstr ""
660msgstr ""
661+"باستخدام نظام تحديد المواقع (GPS)، والواي فاي، وبيانات الشبكة الخلوية "
662+"(مستحسن)"
648
663
649#. Translators: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
664#. Translators: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
650#: qml/Wizard/Pages/50-location.qml:103
665#: qml/Wizard/Pages/50-location.qml:103
@@ -659,11 +674,11 @@ msgstr ""
659
674
660#: qml/Wizard/Pages/50-location.qml:124
675#: qml/Wizard/Pages/50-location.qml:124
661msgid "You can change your mind later in <b>System Settings</b>."
676msgid "You can change your mind later in <b>System Settings</b>."
662−msgstr ""
677+msgstr "يمكنك تغيير رأيك في وقت لاحق عن طريق <b>إعدادات النظام</b>."
663
678
664#: qml/Wizard/Pages/60-reporting.qml:24
679#: qml/Wizard/Pages/60-reporting.qml:24
665msgid "Improving your experience"
680msgid "Improving your experience"
666−msgstr ""
681+msgstr "تحسين تجربتك"
667
682
668#: qml/Wizard/Pages/60-reporting.qml:36
683#: qml/Wizard/Pages/60-reporting.qml:36
669msgid ""
684msgid ""
po/ga.ponew file+697
@@ -0,0 +1,697 @@
1+# Irish translation for unity8
2+# Copyright (c) 2015 Rosetta Contributors and Canonical Ltd 2015
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2015.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2015-06-22 12:00+0200\n"
11+"PO-Revision-Date: 2015-07-20 16:25+0000\n"
12+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13+"Language-Team: Irish <ga@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;\n"
18+"X-Launchpad-Export-Date: 2015-07-21 05:35+0000\n"
19+"X-Generator: Launchpad (build 17628)\n"
20+
21+#: plugins/LightDM/Greeter.cpp:112
22+msgid "Password: "
23+msgstr "Focal Faire: "
24+
25+#: plugins/Unity/Launcher/launcheritem.cpp:45
26+#: plugins/Unity/Launcher/launcheritem.cpp:100
27+msgid "Pin shortcut"
28+msgstr ""
29+
30+#: plugins/Unity/Launcher/launcheritem.cpp:100
31+msgid "Unpin shortcut"
32+msgstr ""
33+
34+#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
35+#. This format string is used for showing, on a 12-hour clock, times that happen yesterday.
36+#. (\u2003 is a unicode em space which is slightly wider than a normal space.)
37+#. en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 1:00 PM"
38+#: plugins/Utils/relativetimeformatter.cpp:157
39+msgid "Yesterday %l:%M %p"
40+msgstr ""
41+
42+#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
43+#. This format string is used for showing, on a 12-hour clock, times that happened today.
44+#. en_US example: "%l:%M %p" --> "1:00 PM"
45+#: plugins/Utils/relativetimeformatter.cpp:164
46+msgid "%l:%M %p"
47+msgstr ""
48+
49+#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
50+#. This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow.
51+#. (\u2003 is a unicode em space which is slightly wider than a normal space.)
52+#. en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 1:00 PM"
53+#: plugins/Utils/relativetimeformatter.cpp:172
54+msgid "Tomorrow %l:%M %p"
55+msgstr ""
56+
57+#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
58+#. This format string is used for showing, on a 12-hour clock, times that happened in the last week.
59+#. (\u2003 is a unicode em space which is slightly wider than a normal space.)
60+#. en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM"
61+#: plugins/Utils/relativetimeformatter.cpp:181
62+msgid "%a %l:%M %p"
63+msgstr ""
64+
65+#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
66+#. This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
67+#. (\u2003 is a unicode em space which is slightly wider than a normal space.)
68+#. en_US example: "%a %d %b\u2003%l:%M %p" --> "Fri Oct 31 1:00 PM"
69+#. en_GB example: "%a %b %d\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM"
70+#: plugins/Utils/relativetimeformatter.cpp:190
71+msgid "%a %d %b %l:%M %p"
72+msgstr ""
73+
74+#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
75+#. This format string is used for showing, on a 24-hour clock, times that happen yesterday.
76+#. (\u2003 is a unicode em space which is slightly wider than a normal space.)
77+#. en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 13:00"
78+#: plugins/Utils/relativetimeformatter.cpp:201
79+msgid "Yesterday %H:%M"
80+msgstr ""
81+
82+#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
83+#. This format string is used for showing, on a 24-hour clock, times that happened today.
84+#. en_US example: "%H:%M" --> "13:00"
85+#: plugins/Utils/relativetimeformatter.cpp:208
86+msgid "%H:%M"
87+msgstr ""
88+
89+#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
90+#. This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow.
91+#. (\u2003 is a unicode em space which is slightly wider than a normal space.)
92+#. en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 13:00"
93+#: plugins/Utils/relativetimeformatter.cpp:216
94+msgid "Tomorrow %H:%M"
95+msgstr ""
96+
97+#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
98+#. This format string is used for showing, on a 24-hour clock, times that happened in the last week.
99+#. (\u2003 is a unicode em space which is slightly wider than a normal space.)
100+#. en_US example: "%a\u2003%H:%M" --> "Fri 13:00"
101+#: plugins/Utils/relativetimeformatter.cpp:225
102+msgid "%a %H:%M"
103+msgstr ""
104+
105+#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
106+#. This format string is used for showing, on a 24-hour clock, times that happened before a week from now.
107+#. (\u2003 is a unicode em space which is slightly wider than a normal space.)
108+#. en_US example: "%a %d %b\u2003%H:%M" --> "Fri Oct 31 13:00"
109+#. en_GB example: "%a %b %d\u2003%H:%M" --> "Fri 31 Oct 13:00"
110+#: plugins/Utils/relativetimeformatter.cpp:234
111+msgid "%a %d %b %H:%M"
112+msgstr ""
113+
114+#: qml/Components/DelayedLockscreen.qml:49
115+msgid "Device Locked"
116+msgstr ""
117+
118+#: qml/Components/DelayedLockscreen.qml:64
119+msgid "You have been locked out due to too many failed passphrase attempts."
120+msgstr ""
121+
122+#: qml/Components/DelayedLockscreen.qml:65
123+msgid "You have been locked out due to too many failed passcode attempts."
124+msgstr ""
125+
126+#: qml/Components/DelayedLockscreen.qml:74
127+#, qt-format
128+msgid "Please wait %1 minute and then try again…"
129+msgid_plural "Please wait %1 minutes and then try again…"
130+msgstr[0] ""
131+msgstr[1] ""
132+
133+#: qml/Components/Dialogs.qml:69
134+msgctxt "Title: Lock/Log out dialog"
135+msgid "Log out"
136+msgstr ""
137+
138+#: qml/Components/Dialogs.qml:70
139+msgid "Are you sure you want to log out?"
140+msgstr ""
141+
142+#: qml/Components/Dialogs.qml:72
143+msgctxt "Button: Lock the system"
144+msgid "Lock"
145+msgstr ""
146+
147+#: qml/Components/Dialogs.qml:79
148+msgctxt "Button: Log out from the system"
149+msgid "Log Out"
150+msgstr ""
151+
152+#: qml/Components/Dialogs.qml:86 qml/Components/Dialogs.qml:117
153+#: qml/Components/Dialogs.qml:173
154+msgid "Cancel"
155+msgstr ""
156+
157+#: qml/Components/Dialogs.qml:98
158+msgctxt "Title: Reboot/Shut down dialog"
159+msgid "Shut down"
160+msgstr ""
161+
162+#: qml/Components/Dialogs.qml:99
163+msgid "Are you sure you want to shut down?"
164+msgstr ""
165+
166+#: qml/Components/Dialogs.qml:101
167+msgctxt "Button: Reboot the system"
168+msgid "Reboot"
169+msgstr ""
170+
171+#: qml/Components/Dialogs.qml:109
172+msgctxt "Button: Shut down the system"
173+msgid "Shut down"
174+msgstr ""
175+
176+#: qml/Components/Dialogs.qml:129
177+msgctxt "Title: Reboot dialog"
178+msgid "Reboot"
179+msgstr ""
180+
181+#: qml/Components/Dialogs.qml:130
182+msgid "Are you sure you want to reboot?"
183+msgstr ""
184+
185+#: qml/Components/Dialogs.qml:132
186+msgid "No"
187+msgstr ""
188+
189+#: qml/Components/Dialogs.qml:138
190+msgid "Yes"
191+msgstr ""
192+
193+#: qml/Components/Dialogs.qml:152
194+msgctxt "Title: Power off/Restart dialog"
195+msgid "Power"
196+msgstr ""
197+
198+#: qml/Components/Dialogs.qml:153
199+msgid ""
200+"Are you sure you would like\n"
201+"to power off?"
202+msgstr ""
203+
204+#: qml/Components/Dialogs.qml:155
205+msgctxt "Button: Power off the system"
206+msgid "Power off"
207+msgstr ""
208+
209+#: qml/Components/Dialogs.qml:164
210+msgctxt "Button: Restart the system"
211+msgid "Restart"
212+msgstr ""
213+
214+#: qml/Components/Lockscreen.qml:245
215+msgid "Return to Call"
216+msgstr ""
217+
218+#: qml/Components/Lockscreen.qml:245
219+msgid "Emergency Call"
220+msgstr ""
221+
222+#: qml/Components/Lockscreen.qml:277
223+msgid "OK"
224+msgstr ""
225+
226+#: qml/Dash/GenericScopeView.qml:532 qml/Dash/GenericScopeView.qml:690
227+msgid "See less"
228+msgstr ""
229+
230+#: qml/Dash/GenericScopeView.qml:532
231+msgid "See all"
232+msgstr ""
233+
234+#: qml/Dash/GenericScopeView.qml:594
235+msgctxt "Label: Hint for dash search line edit"
236+msgid "Search"
237+msgstr ""
238+
239+#: qml/Dash/PageHeader.qml:269
240+msgctxt "Button: Open the Ubuntu Store"
241+msgid "Store"
242+msgstr ""
243+
244+#: qml/Dash/PageHeader.qml:276
245+msgctxt "Button: Start a search in the current dash scope"
246+msgid "Search"
247+msgstr ""
248+
249+#: qml/Dash/PageHeader.qml:286
250+msgctxt "Button: Show the current dash scope settings"
251+msgid "Settings"
252+msgstr ""
253+
254+#: qml/Dash/PageHeader.qml:293
255+msgid "Remove from Favorites"
256+msgstr ""
257+
258+#: qml/Dash/PageHeader.qml:293
259+msgid "Add to Favorites"
260+msgstr ""
261+
262+#: qml/Dash/Previews/PreviewActionCombo.qml:35
263+msgid "More..."
264+msgstr ""
265+
266+#: qml/Dash/Previews/PreviewActionCombo.qml:35
267+msgid "Less..."
268+msgstr ""
269+
270+#: qml/Dash/Previews/PreviewRatingInput.qml:84
271+msgid "Rate this"
272+msgstr ""
273+
274+#: qml/Dash/Previews/PreviewRatingInput.qml:129
275+msgid "Add a review"
276+msgstr ""
277+
278+#: qml/Dash/Previews/PreviewRatingInput.qml:169
279+msgid "Send"
280+msgstr ""
281+
282+#: qml/Dash/PullToRefreshScopeStyle.qml:55
283+msgid "Pull to refresh…"
284+msgstr ""
285+
286+#: qml/Dash/PullToRefreshScopeStyle.qml:60
287+msgid "Release to refresh…"
288+msgstr ""
289+
290+#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
291+msgid "Enable location data"
292+msgstr ""
293+
294+#: qml/Dash/ScopesList.qml:67
295+msgid "Manage"
296+msgstr ""
297+
298+#: qml/Dash/ScopesList.qml:113
299+msgid "Home"
300+msgstr ""
301+
302+#: qml/Dash/ScopesList.qml:114
303+msgid "Also installed"
304+msgstr ""
305+
306+#: qml/Greeter/CoverPage.qml:107
307+msgid "Unlock"
308+msgstr ""
309+
310+#: qml/Greeter/LoginList.qml:236
311+msgid "Retry"
312+msgstr ""
313+
314+#: qml/Greeter/LoginList.qml:237
315+msgid "Tap to unlock"
316+msgstr ""
317+
318+#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
319+msgid "Sorry, incorrect passphrase."
320+msgstr ""
321+
322+#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:54
323+msgid "Sorry, incorrect passcode."
324+msgstr ""
325+
326+#: qml/Greeter/NarrowView.qml:55
327+msgid "This will be your last attempt."
328+msgstr ""
329+
330+#: qml/Greeter/NarrowView.qml:57
331+msgid ""
332+"If passphrase is entered incorrectly, your phone will conduct a factory "
333+"reset and all personal data will be deleted."
334+msgstr ""
335+
336+#: qml/Greeter/NarrowView.qml:58
337+msgid ""
338+"If passcode is entered incorrectly, your phone will conduct a factory reset "
339+"and all personal data will be deleted."
340+msgstr ""
341+
342+#: qml/Greeter/NarrowView.qml:115
343+#, qt-format
344+msgid "Enter %1"
345+msgstr ""
346+
347+#: qml/Greeter/NarrowView.qml:116 qml/Wizard/Pages/passwd-set.qml:60
348+msgid "Enter passphrase"
349+msgstr ""
350+
351+#: qml/Greeter/NarrowView.qml:117
352+msgid "Enter passcode"
353+msgstr ""
354+
355+#: qml/Greeter/NarrowView.qml:118
356+#, qt-format
357+msgid "Sorry, incorrect %1"
358+msgstr ""
359+
360+#: qml/Greeter/NarrowView.qml:119
361+msgid "Sorry, incorrect passphrase"
362+msgstr ""
363+
364+#: qml/Greeter/NarrowView.qml:120
365+msgid "Please re-enter"
366+msgstr ""
367+
368+#: qml/Greeter/NarrowView.qml:121
369+msgid "Sorry, incorrect passcode"
370+msgstr ""
371+
372+#: qml/Notifications/NotificationMenuItemFactory.qml:128
373+msgid "Show password"
374+msgstr ""
375+
376+#: qml/Panel/ActiveCallHint.qml:79
377+msgid "Tap to return to call..."
378+msgstr ""
379+
380+#: qml/Panel/ActiveCallHint.qml:92
381+msgid "Conference"
382+msgstr ""
383+
384+#: qml/Panel/Indicators/MenuItemFactory.qml:639
385+msgid "Nothing is playing"
386+msgstr ""
387+
388+#: qml/Panel/Indicators/MenuItemFactory.qml:768
389+#, qt-format
390+msgid "%1 hour"
391+msgid_plural "%1 hours"
392+msgstr[0] ""
393+msgstr[1] ""
394+
395+#: qml/Panel/Indicators/MenuItemFactory.qml:772
396+#, qt-format
397+msgid "%1 minute"
398+msgid_plural "%1 minutes"
399+msgstr[0] ""
400+msgstr[1] ""
401+
402+#: qml/Panel/Indicators/MenuItemFactory.qml:777
403+#, qt-format
404+msgid "%1 second"
405+msgid_plural "%1 seconds"
406+msgstr[0] ""
407+msgstr[1] ""
408+
409+#: qml/Panel/Indicators/MenuItemFactory.qml:780
410+msgid "0 seconds"
411+msgstr ""
412+
413+#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
414+#: qml/Panel/Indicators/MenuItemFactory.qml:782
415+#, qt-format
416+msgid "%1 remaining"
417+msgstr ""
418+
419+#: qml/Panel/Indicators/MenuItemFactory.qml:788
420+msgid "In queue…"
421+msgstr ""
422+
423+#: qml/Panel/Indicators/MenuItemFactory.qml:792
424+msgid "Downloading"
425+msgstr ""
426+
427+#: qml/Panel/Indicators/MenuItemFactory.qml:794
428+msgid "Paused, tap to resume"
429+msgstr ""
430+
431+#: qml/Panel/Indicators/MenuItemFactory.qml:796
432+msgid "Canceled"
433+msgstr ""
434+
435+#: qml/Panel/Indicators/MenuItemFactory.qml:798
436+msgid "Finished"
437+msgstr ""
438+
439+#: qml/Panel/Indicators/MenuItemFactory.qml:800
440+msgid "Failed, tap to retry"
441+msgstr ""
442+
443+#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
444+msgctxt "Label: Hint in message indicator line edit"
445+msgid "Reply"
446+msgstr ""
447+
448+#: qml/Panel/Indicators/ModemInfoItem.qml:105
449+msgid "Unlock SIM"
450+msgstr ""
451+
452+#: qml/Panel/Indicators/RoamingIndication.qml:27
453+msgid "Roaming"
454+msgstr ""
455+
456+#: qml/Tutorial/TutorialBottomFinish.qml:24
457+msgid "This action does different things for different apps"
458+msgstr ""
459+
460+#: qml/Tutorial/TutorialBottomFinish.qml:25
461+msgid "Tap here to finish."
462+msgstr ""
463+
464+#: qml/Tutorial/TutorialBottom.qml:28
465+msgid "Open special menus"
466+msgstr ""
467+
468+#: qml/Tutorial/TutorialBottom.qml:29
469+msgid "Swipe up from the bottom edge."
470+msgstr ""
471+
472+#: qml/Tutorial/TutorialContent.qml:81 qml/Tutorial/TutorialLeftFinish.qml:25
473+#: qml/Tutorial/TutorialRight.qml:144
474+msgid "Tap here to continue."
475+msgstr ""
476+
477+#: qml/Tutorial/TutorialContent.qml:81
478+msgid "Click here to finish."
479+msgstr ""
480+
481+#: qml/Tutorial/TutorialLeftFinish.qml:24
482+msgid "These are the shortcuts to favorite apps"
483+msgstr ""
484+
485+#: qml/Tutorial/TutorialLeft.qml:26
486+msgid "Open the launcher"
487+msgstr ""
488+
489+#: qml/Tutorial/TutorialLeft.qml:27
490+msgid "Short swipe from the left edge."
491+msgstr ""
492+
493+#: qml/Tutorial/TutorialPage.qml:178
494+msgid "You almost got it!"
495+msgstr ""
496+
497+#: qml/Tutorial/TutorialPage.qml:195
498+msgid "Try again."
499+msgstr ""
500+
501+#: qml/Tutorial/TutorialRight.qml:31
502+msgid "To view open apps"
503+msgstr ""
504+
505+#: qml/Tutorial/TutorialRight.qml:32
506+msgid "Long swipe from the right edge."
507+msgstr ""
508+
509+#: qml/Tutorial/TutorialRight.qml:122
510+msgid "View all your running tasks."
511+msgstr ""
512+
513+#: qml/Wizard/Page.qml:89
514+msgctxt "Button: Go back one page in the Wizard"
515+msgid "Back"
516+msgstr ""
517+
518+#: qml/Wizard/Pages/here-terms.qml:27
519+msgid "Terms & Conditions"
520+msgstr ""
521+
522+#: qml/Wizard/Pages/passwd-confirm.qml:49
523+msgid "Confirm passphrase"
524+msgstr ""
525+
526+#: qml/Wizard/Pages/passwd-confirm.qml:50
527+msgid "Confirm passcode"
528+msgstr ""
529+
530+#: qml/Wizard/Pages/passwd-confirm.qml:53
531+#: qml/Wizard/Pages/passwd-confirm.qml:54
532+msgid "Please try again."
533+msgstr ""
534+
535+#: qml/Wizard/Pages/passwd-confirm.qml:82 qml/Wizard/Pages/passwd-set.qml:90
536+#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
537+#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
538+#: qml/Wizard/Pages/60-reporting.qml:50
539+msgid "Continue"
540+msgstr ""
541+
542+#: qml/Wizard/Pages/passwd-set.qml:61
543+msgid "Choose your passcode"
544+msgstr ""
545+
546+#: qml/Wizard/Pages/passwd-set.qml:68
547+msgid "Passphrase must be 4 characters long"
548+msgstr ""
549+
550+#: qml/Wizard/Pages/10-welcome.qml:27
551+msgid "Hi!"
552+msgstr ""
553+
554+#: qml/Wizard/Pages/10-welcome.qml:44
555+msgid "Welcome to your Ubuntu phone."
556+msgstr ""
557+
558+#: qml/Wizard/Pages/10-welcome.qml:52
559+msgid "Let’s get started."
560+msgstr ""
561+
562+#: qml/Wizard/Pages/20-sim.qml:25
563+msgid "Add a SIM card and restart your device"
564+msgstr ""
565+
566+#: qml/Wizard/Pages/20-sim.qml:59
567+msgid "Without it, you won’t be able to make calls or use text messaging."
568+msgstr ""
569+
570+#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
571+msgid "Skip"
572+msgstr ""
573+
574+#: qml/Wizard/Pages/30-passwd-type.qml:39
575+msgid "Lock security"
576+msgstr ""
577+
578+#: qml/Wizard/Pages/30-passwd-type.qml:74
579+msgid "Please select how you’d like to unlock your phone."
580+msgstr ""
581+
582+#: qml/Wizard/Pages/30-passwd-type.qml:97
583+msgctxt "Label: Type of security method"
584+msgid "Swipe"
585+msgstr ""
586+
587+#: qml/Wizard/Pages/30-passwd-type.qml:98
588+msgctxt "Label: Description of security method"
589+msgid "No security"
590+msgstr ""
591+
592+#: qml/Wizard/Pages/30-passwd-type.qml:100
593+msgctxt "Label: Type of security method"
594+msgid "Passcode"
595+msgstr ""
596+
597+#: qml/Wizard/Pages/30-passwd-type.qml:101
598+msgctxt "Label: Description of security method"
599+msgid "4 digits only"
600+msgstr ""
601+
602+#: qml/Wizard/Pages/30-passwd-type.qml:103
603+msgctxt "Label: Type of security method"
604+msgid "Passphrase"
605+msgstr ""
606+
607+#: qml/Wizard/Pages/30-passwd-type.qml:104
608+msgctxt "Label: Description of security method"
609+msgid "Numbers and letters"
610+msgstr ""
611+
612+#: qml/Wizard/Pages/40-wifi.qml:29
613+msgid "Connect to Wi‑Fi"
614+msgstr ""
615+
616+#: qml/Wizard/Pages/40-wifi.qml:168
617+msgid "Available networks…"
618+msgstr ""
619+
620+#: qml/Wizard/Pages/40-wifi.qml:169
621+msgid "No available networks."
622+msgstr ""
623+
624+#: qml/Wizard/Pages/50-location.qml:27
625+msgid "Location"
626+msgstr ""
627+
628+#: qml/Wizard/Pages/50-location.qml:62
629+msgid "Let the phone detect your location:"
630+msgstr ""
631+
632+#: qml/Wizard/Pages/50-location.qml:69
633+msgid "Using GPS only (less accurate)"
634+msgstr ""
635+
636+#: qml/Wizard/Pages/50-location.qml:86
637+msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
638+msgstr ""
639+
640+#. Translators: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
641+#: qml/Wizard/Pages/50-location.qml:103
642+msgid ""
643+"By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
644+"conditions</a>."
645+msgstr ""
646+
647+#: qml/Wizard/Pages/50-location.qml:112
648+msgid "Not at all"
649+msgstr ""
650+
651+#: qml/Wizard/Pages/50-location.qml:124
652+msgid "You can change your mind later in <b>System Settings</b>."
653+msgstr ""
654+
655+#: qml/Wizard/Pages/60-reporting.qml:24
656+msgid "Improving your experience"
657+msgstr ""
658+
659+#: qml/Wizard/Pages/60-reporting.qml:36
660+msgid ""
661+"Your phone is set up to automatically report errors to Canonical and its "
662+"partners, the makers of the operating system."
663+msgstr ""
664+
665+#: qml/Wizard/Pages/60-reporting.qml:43
666+msgid ""
667+"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
668+"Privacy</b>"
669+msgstr ""
670+
671+#: qml/Wizard/Pages/80-finished.qml:24
672+msgid "All done"
673+msgstr ""
674+
675+#: qml/Wizard/Pages/80-finished.qml:39
676+msgid "Nice work!"
677+msgstr ""
678+
679+#: qml/Wizard/Pages/80-finished.qml:46
680+msgid "Your phone is now ready to use."
681+msgstr ""
682+
683+#: qml/Wizard/Pages/80-finished.qml:53
684+msgid "Finish"
685+msgstr ""
686+
687+#. Translators: This is the arrow for "Back" buttons
688+#: qml/Wizard/StackButton.qml:39
689+#, qt-format
690+msgid "〈 %1"
691+msgstr ""
692+
693+#. Translators: This is the arrow for "Forward" buttons
694+#: qml/Wizard/StackButton.qml:42
695+#, qt-format
696+msgid "%1 〉"
697+msgstr ""
po/sw.po+86−80
@@ -8,15 +8,15 @@ msgstr ""
8"Project-Id-Version: unity8\n"
8"Project-Id-Version: unity8\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2015-06-22 12:00+0200\n"
10"POT-Creation-Date: 2015-06-22 12:00+0200\n"
11−"PO-Revision-Date: 2015-07-10 20:22+0000\n"
11+"PO-Revision-Date: 2015-07-17 20:02+0000\n"
12"Last-Translator: Valentine <mwangi_valentino@yahoo.com>\n"
12"Last-Translator: Valentine <mwangi_valentino@yahoo.com>\n"
13"Language-Team: Swahili <sw@li.org>\n"
13"Language-Team: Swahili <sw@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2015-07-11 05:33+0000\n"
18+"X-Launchpad-Export-Date: 2015-07-21 05:35+0000\n"
19−"X-Generator: Launchpad (build 17620)\n"
19+"X-Generator: Launchpad (build 17628)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:112
21#: plugins/LightDM/Greeter.cpp:112
22msgid "Password: "
22msgid "Password: "
@@ -25,11 +25,11 @@ msgstr "Neno siri "
25#: plugins/Unity/Launcher/launcheritem.cpp:45
25#: plugins/Unity/Launcher/launcheritem.cpp:45
26#: plugins/Unity/Launcher/launcheritem.cpp:100
26#: plugins/Unity/Launcher/launcheritem.cpp:100
27msgid "Pin shortcut"
27msgid "Pin shortcut"
28−msgstr ""
28+msgstr "Njia ya mkato ya nambari ya siri"
29
29
30#: plugins/Unity/Launcher/launcheritem.cpp:100
30#: plugins/Unity/Launcher/launcheritem.cpp:100
31msgid "Unpin shortcut"
31msgid "Unpin shortcut"
32−msgstr ""
32+msgstr "Toa njia ya mkato ya nambari ya siri"
33
33
34#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
34#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
35#. This format string is used for showing, on a 12-hour clock, times that happen yesterday.
35#. This format string is used for showing, on a 12-hour clock, times that happen yesterday.
@@ -60,7 +60,7 @@ msgstr "Kesho %l:%M %p"
60#. en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM"
60#. en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM"
61#: plugins/Utils/relativetimeformatter.cpp:181
61#: plugins/Utils/relativetimeformatter.cpp:181
62msgid "%a %l:%M %p"
62msgid "%a %l:%M %p"
63−msgstr ""
63+msgstr "%a %l:%M %p"
64
64
65#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
65#. Translators, please edit/rearrange these strftime(3) tokens to suit your locale!
66#. This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
66#. This format string is used for showing, on a 12-hour clock, times that happened before a week from now.
@@ -118,10 +118,12 @@ msgstr "kifaa kimefungwa"
118#: qml/Components/DelayedLockscreen.qml:64
118#: qml/Components/DelayedLockscreen.qml:64
119msgid "You have been locked out due to too many failed passphrase attempts."
119msgid "You have been locked out due to too many failed passphrase attempts."
120msgstr ""
120msgstr ""
121+"Huwezi kulogi kwa sababu umenoa kubonyeza vizuri neno la siri mara nyingi."
121
122
122#: qml/Components/DelayedLockscreen.qml:65
123#: qml/Components/DelayedLockscreen.qml:65
123msgid "You have been locked out due to too many failed passcode attempts."
124msgid "You have been locked out due to too many failed passcode attempts."
124msgstr ""
125msgstr ""
126+"Huwezi kulogi kwa sababu umenoa kubonyeza vizuri neno la siri mara nyingi."
125
127
126#: qml/Components/DelayedLockscreen.qml:74
128#: qml/Components/DelayedLockscreen.qml:74
127#, qt-format
129#, qt-format
@@ -193,7 +195,7 @@ msgstr "Ndio"
193#: qml/Components/Dialogs.qml:152
195#: qml/Components/Dialogs.qml:152
194msgctxt "Title: Power off/Restart dialog"
196msgctxt "Title: Power off/Restart dialog"
195msgid "Power"
197msgid "Power"
196−msgstr ""
198+msgstr "Zima"
197
199
198#: qml/Components/Dialogs.qml:153
200#: qml/Components/Dialogs.qml:153
199msgid ""
201msgid ""
@@ -213,7 +215,7 @@ msgstr "Zima na uwashe"
213
215
214#: qml/Components/Lockscreen.qml:245
216#: qml/Components/Lockscreen.qml:245
215msgid "Return to Call"
217msgid "Return to Call"
216−msgstr ""
218+msgstr "Rudi nyuma upige simu"
217
219
218#: qml/Components/Lockscreen.qml:245
220#: qml/Components/Lockscreen.qml:245
219msgid "Emergency Call"
221msgid "Emergency Call"
@@ -269,11 +271,11 @@ msgstr "Kidogo..."
269
271
270#: qml/Dash/Previews/PreviewRatingInput.qml:84
272#: qml/Dash/Previews/PreviewRatingInput.qml:84
271msgid "Rate this"
273msgid "Rate this"
272−msgstr ""
274+msgstr "Pea kiwango"
273
275
274#: qml/Dash/Previews/PreviewRatingInput.qml:129
276#: qml/Dash/Previews/PreviewRatingInput.qml:129
275msgid "Add a review"
277msgid "Add a review"
276−msgstr ""
278+msgstr "Ongeza pitio"
277
279
278#: qml/Dash/Previews/PreviewRatingInput.qml:169
280#: qml/Dash/Previews/PreviewRatingInput.qml:169
279msgid "Send"
281msgid "Send"
@@ -281,11 +283,11 @@ msgstr "Tuma"
281
283
282#: qml/Dash/PullToRefreshScopeStyle.qml:55
284#: qml/Dash/PullToRefreshScopeStyle.qml:55
283msgid "Pull to refresh…"
285msgid "Pull to refresh…"
284−msgstr ""
286+msgstr "Vuta unawarishe"
285
287
286#: qml/Dash/PullToRefreshScopeStyle.qml:60
288#: qml/Dash/PullToRefreshScopeStyle.qml:60
287msgid "Release to refresh…"
289msgid "Release to refresh…"
288−msgstr ""
290+msgstr "Achilia unawarishe"
289
291
290#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
292#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
291msgid "Enable location data"
293msgid "Enable location data"
@@ -317,27 +319,31 @@ msgstr "Gusa ufungue"
317
319
318#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
320#: qml/Greeter/NarrowView.qml:53 qml/Wizard/Pages/passwd-confirm.qml:53
319msgid "Sorry, incorrect passphrase."
321msgid "Sorry, incorrect passphrase."
320−msgstr ""
322+msgstr "Samahani, neno siri si hilo"
321
323
322#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:54
324#: qml/Greeter/NarrowView.qml:54 qml/Wizard/Pages/passwd-confirm.qml:54
323msgid "Sorry, incorrect passcode."
325msgid "Sorry, incorrect passcode."
324−msgstr ""
326+msgstr "Samahani, neno siri si hilo"
325
327
326#: qml/Greeter/NarrowView.qml:55
328#: qml/Greeter/NarrowView.qml:55
327msgid "This will be your last attempt."
329msgid "This will be your last attempt."
328−msgstr ""
330+msgstr "Hii ndiyo nafasi ya mwisho"
329
331
330#: qml/Greeter/NarrowView.qml:57
332#: qml/Greeter/NarrowView.qml:57
331msgid ""
333msgid ""
332"If passphrase is entered incorrectly, your phone will conduct a factory "
334"If passphrase is entered incorrectly, your phone will conduct a factory "
333"reset and all personal data will be deleted."
335"reset and all personal data will be deleted."
334msgstr ""
336msgstr ""
337+"Kama utabonyeza neno la siri lisilofaa, simu yako itajiweka upya na data "
338+"yako yote itafutwa."
335
339
336#: qml/Greeter/NarrowView.qml:58
340#: qml/Greeter/NarrowView.qml:58
337msgid ""
341msgid ""
338"If passcode is entered incorrectly, your phone will conduct a factory reset "
342"If passcode is entered incorrectly, your phone will conduct a factory reset "
339"and all personal data will be deleted."
343"and all personal data will be deleted."
340msgstr ""
344msgstr ""
345+"Kama utabonyeza neno la siri lisilofaa, simu yako itajiweka upya na data "
346+"yako yote itafutwa."
341
347
342#: qml/Greeter/NarrowView.qml:115
348#: qml/Greeter/NarrowView.qml:115
343#, qt-format
349#, qt-format
@@ -350,75 +356,75 @@ msgstr "Bonyeza neno siri"
350
356
351#: qml/Greeter/NarrowView.qml:117
357#: qml/Greeter/NarrowView.qml:117
352msgid "Enter passcode"
358msgid "Enter passcode"
353−msgstr ""
359+msgstr "Bonyeza neno la siri"
354
360
355#: qml/Greeter/NarrowView.qml:118
361#: qml/Greeter/NarrowView.qml:118
356#, qt-format
362#, qt-format
357msgid "Sorry, incorrect %1"
363msgid "Sorry, incorrect %1"
358−msgstr ""
364+msgstr "Samahani, %1 halidhihirishi"
359
365
360#: qml/Greeter/NarrowView.qml:119
366#: qml/Greeter/NarrowView.qml:119
361msgid "Sorry, incorrect passphrase"
367msgid "Sorry, incorrect passphrase"
362−msgstr ""
368+msgstr "Samahani, neno la siri si hilo"
363
369
364#: qml/Greeter/NarrowView.qml:120
370#: qml/Greeter/NarrowView.qml:120
365msgid "Please re-enter"
371msgid "Please re-enter"
366−msgstr ""
372+msgstr "Tafadhali bonyeza tena"
367
373
368#: qml/Greeter/NarrowView.qml:121
374#: qml/Greeter/NarrowView.qml:121
369msgid "Sorry, incorrect passcode"
375msgid "Sorry, incorrect passcode"
370−msgstr ""
376+msgstr "Samahani, neno la siri si hilo"
371
377
372#: qml/Notifications/NotificationMenuItemFactory.qml:128
378#: qml/Notifications/NotificationMenuItemFactory.qml:128
373msgid "Show password"
379msgid "Show password"
374−msgstr ""
380+msgstr "Onyesha neno la siri"
375
381
376#: qml/Panel/ActiveCallHint.qml:79
382#: qml/Panel/ActiveCallHint.qml:79
377msgid "Tap to return to call..."
383msgid "Tap to return to call..."
378−msgstr ""
384+msgstr "Gusa urudi ili upige simu"
379
385
380#: qml/Panel/ActiveCallHint.qml:92
386#: qml/Panel/ActiveCallHint.qml:92
381msgid "Conference"
387msgid "Conference"
382−msgstr ""
388+msgstr "Mkutano"
383
389
384#: qml/Panel/Indicators/MenuItemFactory.qml:639
390#: qml/Panel/Indicators/MenuItemFactory.qml:639
385msgid "Nothing is playing"
391msgid "Nothing is playing"
386−msgstr ""
392+msgstr "Hakuna linalocheza"
387
393
388#: qml/Panel/Indicators/MenuItemFactory.qml:768
394#: qml/Panel/Indicators/MenuItemFactory.qml:768
389#, qt-format
395#, qt-format
390msgid "%1 hour"
396msgid "%1 hour"
391msgid_plural "%1 hours"
397msgid_plural "%1 hours"
392−msgstr[0] ""
398+msgstr[0] "Saa %1"
393−msgstr[1] ""
399+msgstr[1] "Mass %1"
394
400
395#: qml/Panel/Indicators/MenuItemFactory.qml:772
401#: qml/Panel/Indicators/MenuItemFactory.qml:772
396#, qt-format
402#, qt-format
397msgid "%1 minute"
403msgid "%1 minute"
398msgid_plural "%1 minutes"
404msgid_plural "%1 minutes"
399−msgstr[0] ""
405+msgstr[0] "Dakika %1"
400−msgstr[1] ""
406+msgstr[1] "Dakika %1"
401
407
402#: qml/Panel/Indicators/MenuItemFactory.qml:777
408#: qml/Panel/Indicators/MenuItemFactory.qml:777
403#, qt-format
409#, qt-format
404msgid "%1 second"
410msgid "%1 second"
405msgid_plural "%1 seconds"
411msgid_plural "%1 seconds"
406−msgstr[0] ""
412+msgstr[0] "Sekunde %1"
407−msgstr[1] ""
413+msgstr[1] "Sekunde %1"
408
414
409#: qml/Panel/Indicators/MenuItemFactory.qml:780
415#: qml/Panel/Indicators/MenuItemFactory.qml:780
410msgid "0 seconds"
416msgid "0 seconds"
411−msgstr ""
417+msgstr "sekunde 0"
412
418
413#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
419#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
414#: qml/Panel/Indicators/MenuItemFactory.qml:782
420#: qml/Panel/Indicators/MenuItemFactory.qml:782
415#, qt-format
421#, qt-format
416msgid "%1 remaining"
422msgid "%1 remaining"
417−msgstr ""
423+msgstr "%1 imebaki"
418
424
419#: qml/Panel/Indicators/MenuItemFactory.qml:788
425#: qml/Panel/Indicators/MenuItemFactory.qml:788
420msgid "In queue…"
426msgid "In queue…"
421−msgstr ""
427+msgstr "Kwenye foleni"
422
428
423#: qml/Panel/Indicators/MenuItemFactory.qml:792
429#: qml/Panel/Indicators/MenuItemFactory.qml:792
424msgid "Downloading"
430msgid "Downloading"
@@ -426,204 +432,204 @@ msgstr ""
426
432
427#: qml/Panel/Indicators/MenuItemFactory.qml:794
433#: qml/Panel/Indicators/MenuItemFactory.qml:794
428msgid "Paused, tap to resume"
434msgid "Paused, tap to resume"
429−msgstr ""
435+msgstr "Imepumzishwa, gusa uendelee"
430
436
431#: qml/Panel/Indicators/MenuItemFactory.qml:796
437#: qml/Panel/Indicators/MenuItemFactory.qml:796
432msgid "Canceled"
438msgid "Canceled"
433−msgstr ""
439+msgstr "Imeghairishwa"
434
440
435#: qml/Panel/Indicators/MenuItemFactory.qml:798
441#: qml/Panel/Indicators/MenuItemFactory.qml:798
436msgid "Finished"
442msgid "Finished"
437−msgstr ""
443+msgstr "Imemaliza"
438
444
439#: qml/Panel/Indicators/MenuItemFactory.qml:800
445#: qml/Panel/Indicators/MenuItemFactory.qml:800
440msgid "Failed, tap to retry"
446msgid "Failed, tap to retry"
441−msgstr ""
447+msgstr "Imefeli, gusa urudie"
442
448
443#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
449#: qml/Panel/Indicators/MessageMenuItemFactory.qml:149
444msgctxt "Label: Hint in message indicator line edit"
450msgctxt "Label: Hint in message indicator line edit"
445msgid "Reply"
451msgid "Reply"
446−msgstr ""
452+msgstr "Jibu"
447
453
448#: qml/Panel/Indicators/ModemInfoItem.qml:105
454#: qml/Panel/Indicators/ModemInfoItem.qml:105
449msgid "Unlock SIM"
455msgid "Unlock SIM"
450−msgstr ""
456+msgstr "Fungua SIM"
451
457
452#: qml/Panel/Indicators/RoamingIndication.qml:27
458#: qml/Panel/Indicators/RoamingIndication.qml:27
453msgid "Roaming"
459msgid "Roaming"
454−msgstr ""
460+msgstr "Uzururaji"
455
461
456#: qml/Tutorial/TutorialBottomFinish.qml:24
462#: qml/Tutorial/TutorialBottomFinish.qml:24
457msgid "This action does different things for different apps"
463msgid "This action does different things for different apps"
458−msgstr ""
464+msgstr "Hatua hii inafanya vitu tofauti kwenye programu tofauti"
459
465
460#: qml/Tutorial/TutorialBottomFinish.qml:25
466#: qml/Tutorial/TutorialBottomFinish.qml:25
461msgid "Tap here to finish."
467msgid "Tap here to finish."
462−msgstr ""
468+msgstr "Gusa hapa umalize"
463
469
464#: qml/Tutorial/TutorialBottom.qml:28
470#: qml/Tutorial/TutorialBottom.qml:28
465msgid "Open special menus"
471msgid "Open special menus"
466−msgstr ""
472+msgstr "Fungua orodha maalum"
467
473
468#: qml/Tutorial/TutorialBottom.qml:29
474#: qml/Tutorial/TutorialBottom.qml:29
469msgid "Swipe up from the bottom edge."
475msgid "Swipe up from the bottom edge."
470−msgstr ""
476+msgstr "Vuta juu kutoka chini"
471
477
472#: qml/Tutorial/TutorialContent.qml:81 qml/Tutorial/TutorialLeftFinish.qml:25
478#: qml/Tutorial/TutorialContent.qml:81 qml/Tutorial/TutorialLeftFinish.qml:25
473#: qml/Tutorial/TutorialRight.qml:144
479#: qml/Tutorial/TutorialRight.qml:144
474msgid "Tap here to continue."
480msgid "Tap here to continue."
475−msgstr ""
481+msgstr "Gusa hapa uendelee."
476
482
477#: qml/Tutorial/TutorialContent.qml:81
483#: qml/Tutorial/TutorialContent.qml:81
478msgid "Click here to finish."
484msgid "Click here to finish."
479−msgstr ""
485+msgstr "Click hapa umalize."
480
486
481#: qml/Tutorial/TutorialLeftFinish.qml:24
487#: qml/Tutorial/TutorialLeftFinish.qml:24
482msgid "These are the shortcuts to favorite apps"
488msgid "These are the shortcuts to favorite apps"
483−msgstr ""
489+msgstr "Hizi ni njia za mkato za programu ulizopenda"
484
490
485#: qml/Tutorial/TutorialLeft.qml:26
491#: qml/Tutorial/TutorialLeft.qml:26
486msgid "Open the launcher"
492msgid "Open the launcher"
487−msgstr ""
493+msgstr "Fungua launcher"
488
494
489#: qml/Tutorial/TutorialLeft.qml:27
495#: qml/Tutorial/TutorialLeft.qml:27
490msgid "Short swipe from the left edge."
496msgid "Short swipe from the left edge."
491−msgstr ""
497+msgstr "Vuta kidogo kutoka kushoto."
492
498
493#: qml/Tutorial/TutorialPage.qml:178
499#: qml/Tutorial/TutorialPage.qml:178
494msgid "You almost got it!"
500msgid "You almost got it!"
495−msgstr ""
501+msgstr "Karibu upate!"
496
502
497#: qml/Tutorial/TutorialPage.qml:195
503#: qml/Tutorial/TutorialPage.qml:195
498msgid "Try again."
504msgid "Try again."
499−msgstr ""
505+msgstr "Jaribu tena."
500
506
501#: qml/Tutorial/TutorialRight.qml:31
507#: qml/Tutorial/TutorialRight.qml:31
502msgid "To view open apps"
508msgid "To view open apps"
503−msgstr ""
509+msgstr "Kuona fungua programu"
504
510
505#: qml/Tutorial/TutorialRight.qml:32
511#: qml/Tutorial/TutorialRight.qml:32
506msgid "Long swipe from the right edge."
512msgid "Long swipe from the right edge."
507−msgstr ""
513+msgstr "Vuta kabisa kutoka kulia."
508
514
509#: qml/Tutorial/TutorialRight.qml:122
515#: qml/Tutorial/TutorialRight.qml:122
510msgid "View all your running tasks."
516msgid "View all your running tasks."
511−msgstr ""
517+msgstr "Ona kazi zote zinazoendelea."
512
518
513#: qml/Wizard/Page.qml:89
519#: qml/Wizard/Page.qml:89
514msgctxt "Button: Go back one page in the Wizard"
520msgctxt "Button: Go back one page in the Wizard"
515msgid "Back"
521msgid "Back"
516−msgstr ""
522+msgstr "Nyuma"
517
523
518#: qml/Wizard/Pages/here-terms.qml:27
524#: qml/Wizard/Pages/here-terms.qml:27
519msgid "Terms & Conditions"
525msgid "Terms & Conditions"
520−msgstr ""
526+msgstr "Suala na Masharti"
521
527
522#: qml/Wizard/Pages/passwd-confirm.qml:49
528#: qml/Wizard/Pages/passwd-confirm.qml:49
523msgid "Confirm passphrase"
529msgid "Confirm passphrase"
524−msgstr ""
530+msgstr "Thibitisha neno la siri"
525
531
526#: qml/Wizard/Pages/passwd-confirm.qml:50
532#: qml/Wizard/Pages/passwd-confirm.qml:50
527msgid "Confirm passcode"
533msgid "Confirm passcode"
528−msgstr ""
534+msgstr "Thibitisha neno la siri"
529
535
530#: qml/Wizard/Pages/passwd-confirm.qml:53
536#: qml/Wizard/Pages/passwd-confirm.qml:53
531#: qml/Wizard/Pages/passwd-confirm.qml:54
537#: qml/Wizard/Pages/passwd-confirm.qml:54
532msgid "Please try again."
538msgid "Please try again."
533−msgstr ""
539+msgstr "Jaribu tena."
534
540
535#: qml/Wizard/Pages/passwd-confirm.qml:82 qml/Wizard/Pages/passwd-set.qml:90
541#: qml/Wizard/Pages/passwd-confirm.qml:82 qml/Wizard/Pages/passwd-set.qml:90
536#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
542#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
537#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
543#: qml/Wizard/Pages/40-wifi.qml:215 qml/Wizard/Pages/50-location.qml:131
538#: qml/Wizard/Pages/60-reporting.qml:50
544#: qml/Wizard/Pages/60-reporting.qml:50
539msgid "Continue"
545msgid "Continue"
540−msgstr ""
546+msgstr "Endelea"
541
547
542#: qml/Wizard/Pages/passwd-set.qml:61
548#: qml/Wizard/Pages/passwd-set.qml:61
543msgid "Choose your passcode"
549msgid "Choose your passcode"
544−msgstr ""
550+msgstr "Chagua neno lako la siri"
545
551
546#: qml/Wizard/Pages/passwd-set.qml:68
552#: qml/Wizard/Pages/passwd-set.qml:68
547msgid "Passphrase must be 4 characters long"
553msgid "Passphrase must be 4 characters long"
548−msgstr ""
554+msgstr "Neno la siri ni lazima liwe na urefu wa herufi 4"
549
555
550#: qml/Wizard/Pages/10-welcome.qml:27
556#: qml/Wizard/Pages/10-welcome.qml:27
551msgid "Hi!"
557msgid "Hi!"
552−msgstr ""
558+msgstr "Jambo!"
553
559
554#: qml/Wizard/Pages/10-welcome.qml:44
560#: qml/Wizard/Pages/10-welcome.qml:44
555msgid "Welcome to your Ubuntu phone."
561msgid "Welcome to your Ubuntu phone."
556−msgstr ""
562+msgstr "Karibu kwenye simu yako ya Ubuntu."
557
563
558#: qml/Wizard/Pages/10-welcome.qml:52
564#: qml/Wizard/Pages/10-welcome.qml:52
559msgid "Let’s get started."
565msgid "Let’s get started."
560−msgstr ""
566+msgstr "Tuanze pamoja."
561
567
562#: qml/Wizard/Pages/20-sim.qml:25
568#: qml/Wizard/Pages/20-sim.qml:25
563msgid "Add a SIM card and restart your device"
569msgid "Add a SIM card and restart your device"
564−msgstr ""
570+msgstr "Ongeza kadi ya SIM halafu uanzishe upya kifaa chako"
565
571
566#: qml/Wizard/Pages/20-sim.qml:59
572#: qml/Wizard/Pages/20-sim.qml:59
567msgid "Without it, you won’t be able to make calls or use text messaging."
573msgid "Without it, you won’t be able to make calls or use text messaging."
568−msgstr ""
574+msgstr "Bila hiyo, hutaweza kupiga simu ama kutuma teksti."
569
575
570#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
576#: qml/Wizard/Pages/20-sim.qml:73 qml/Wizard/Pages/40-wifi.qml:215
571msgid "Skip"
577msgid "Skip"
572−msgstr ""
578+msgstr "Ruka"
573
579
574#: qml/Wizard/Pages/30-passwd-type.qml:39
580#: qml/Wizard/Pages/30-passwd-type.qml:39
575msgid "Lock security"
581msgid "Lock security"
576−msgstr ""
582+msgstr "Funga usalama"
577
583
578#: qml/Wizard/Pages/30-passwd-type.qml:74
584#: qml/Wizard/Pages/30-passwd-type.qml:74
579msgid "Please select how you’d like to unlock your phone."
585msgid "Please select how you’d like to unlock your phone."
580−msgstr ""
586+msgstr "Tafadhali chagua vile ungependa kufunga simu."
581
587
582#: qml/Wizard/Pages/30-passwd-type.qml:97
588#: qml/Wizard/Pages/30-passwd-type.qml:97
583msgctxt "Label: Type of security method"
589msgctxt "Label: Type of security method"
584msgid "Swipe"
590msgid "Swipe"
585−msgstr ""
591+msgstr "Vuta"
586
592
587#: qml/Wizard/Pages/30-passwd-type.qml:98
593#: qml/Wizard/Pages/30-passwd-type.qml:98
588msgctxt "Label: Description of security method"
594msgctxt "Label: Description of security method"
589msgid "No security"
595msgid "No security"
590−msgstr ""
596+msgstr "Hakuna usalama"
591
597
592#: qml/Wizard/Pages/30-passwd-type.qml:100
598#: qml/Wizard/Pages/30-passwd-type.qml:100
593msgctxt "Label: Type of security method"
599msgctxt "Label: Type of security method"
594msgid "Passcode"
600msgid "Passcode"
595−msgstr ""
601+msgstr "Neno la siri"
596
602
597#: qml/Wizard/Pages/30-passwd-type.qml:101
603#: qml/Wizard/Pages/30-passwd-type.qml:101
598msgctxt "Label: Description of security method"
604msgctxt "Label: Description of security method"
599msgid "4 digits only"
605msgid "4 digits only"
600−msgstr ""
606+msgstr "Herufi nne peke yake"
601
607
602#: qml/Wizard/Pages/30-passwd-type.qml:103
608#: qml/Wizard/Pages/30-passwd-type.qml:103
603msgctxt "Label: Type of security method"
609msgctxt "Label: Type of security method"
604msgid "Passphrase"
610msgid "Passphrase"
605−msgstr ""
611+msgstr "Kaulisiri"
606
612
607#: qml/Wizard/Pages/30-passwd-type.qml:104
613#: qml/Wizard/Pages/30-passwd-type.qml:104
608msgctxt "Label: Description of security method"
614msgctxt "Label: Description of security method"
609msgid "Numbers and letters"
615msgid "Numbers and letters"
610−msgstr ""
616+msgstr "Nambari na herufi"
611
617
612#: qml/Wizard/Pages/40-wifi.qml:29
618#: qml/Wizard/Pages/40-wifi.qml:29
613msgid "Connect to Wi‑Fi"
619msgid "Connect to Wi‑Fi"
614−msgstr ""
620+msgstr "Tumia Wi-fi"
615
621
616#: qml/Wizard/Pages/40-wifi.qml:168
622#: qml/Wizard/Pages/40-wifi.qml:168
617msgid "Available networks…"
623msgid "Available networks…"
618−msgstr ""
624+msgstr "Mitandao inayopatikana"
619
625
620#: qml/Wizard/Pages/40-wifi.qml:169
626#: qml/Wizard/Pages/40-wifi.qml:169
621msgid "No available networks."
627msgid "No available networks."
622−msgstr ""
628+msgstr "Hakuna mitandao inayopatikana"
623
629
624#: qml/Wizard/Pages/50-location.qml:27
630#: qml/Wizard/Pages/50-location.qml:27
625msgid "Location"
631msgid "Location"
626−msgstr ""
632+msgstr "Mahali"
627
633
628#: qml/Wizard/Pages/50-location.qml:62
634#: qml/Wizard/Pages/50-location.qml:62
629msgid "Let the phone detect your location:"
635msgid "Let the phone detect your location:"
qml/Dash/Previews/PreviewComment.qmlnew file+83
@@ -0,0 +1,83 @@
1+/*
2+ * Copyright (C) 2015 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+import QtQuick 2.0
18+import Ubuntu.Components 1.2
19+
20+/*! \brief Preview widget for comments.
21+
22+ This widget shows an (optional) avatar contained in widgetData["source"]
23+ along with a label that comes from widgetData["author"],
24+ a (optional) subtitle from widgetData["subtitle"] and the comment widgetData["comment"].
25+*/
26+
27+PreviewWidget {
28+ id: root
29+ implicitHeight: Math.max(avatar.height, column.implicitHeight)
30+
31+ UbuntuShape {
32+ id: avatar
33+ objectName: "avatar"
34+ anchors {
35+ left: parent.left
36+ top: parent.top
37+ }
38+ width: units.gu(6)
39+ height: width
40+ source: Image {
41+ source: widgetData["source"]
42+ }
43+ radius: "medium"
44+ opacity: source.status === Image.Ready ? 1 : 0
45+ visible: widgetData["source"] !== ""
46+ }
47+
48+ Column {
49+ id: column
50+ objectName: "column"
51+ anchors {
52+ left: avatar.visible ? avatar.right : parent.left
53+ right: parent.right
54+ top: parent.top
55+ topMargin: units.gu(0.5)
56+ leftMargin: avatar.visible ? units.gu(1) : 0
57+ }
58+ spacing: units.gu(0.24)
59+
60+ Label {
61+ width: parent.width
62+ text: widgetData["author"] || ""
63+ fontSize: "small"
64+ maximumLineCount: 1
65+ elide: Text.ElideRight
66+ }
67+ Label {
68+ objectName: "subtitle"
69+ width: parent.width
70+ visible: text !== ""
71+ text: widgetData["subtitle"] || ""
72+ fontSize: "xx-small"
73+ maximumLineCount: 1
74+ elide: Text.ElideRight
75+ }
76+ Label {
77+ width: parent.width
78+ text: widgetData["comment"] || ""
79+ fontSize: "small"
80+ wrapMode: Text.Wrap
81+ }
82+ }
83+}
qml/Dash/Previews/PreviewCommentInput.qmlnew file+66
@@ -0,0 +1,66 @@
1+/*
2+ * Copyright (C) 2015 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+import QtQuick 2.0
18+import Ubuntu.Components 1.1
19+import "../../Components"
20+
21+/*! \brief Preview widget for commenting.
22+
23+ The widget can show a field to enter a comment.
24+ It is possible to customise the submit button's label by setting widgetData["submit-label"]
25+ The successeful submit emits triggered(widgetId, "commented", data),
26+ with data being {"comment": comment}.
27+*/
28+
29+PreviewWidget {
30+ id: root
31+ implicitHeight: Math.max(commentTextArea.implicitHeight, submitButton.implicitHeight)
32+
33+ function submit() {
34+ var data = { "comment": commentTextArea.text };
35+ triggered(root.widgetId, "commented", data);
36+ }
37+
38+ TextArea {
39+ id: commentTextArea
40+ objectName: "commentTextArea"
41+ anchors {
42+ top: parent.top
43+ left: parent.left
44+ right: submitButton.left
45+ rightMargin: units.gu(1)
46+ }
47+ autoSize: true
48+ }
49+
50+ Button {
51+ id: submitButton
52+ objectName: "submitButton"
53+
54+ readonly property bool readyToSubmit: commentTextArea.text.trim().length > 0
55+
56+ anchors {
57+ top: parent.top
58+ right: parent.right
59+ }
60+ color: readyToSubmit ? Theme.palette.selected.base : Theme.palette.normal.base
61+ text: widgetData["submit-label"] || i18n.tr("Send")
62+ onClicked: {
63+ if (readyToSubmit) root.submit()
64+ }
65+ }
66+}
qml/Dash/Previews/PreviewWidgetFactory.qml+2
@@ -50,6 +50,8 @@ Loader {
50 switch (widgetType) {
50 switch (widgetType) {
51 case "actions": return "PreviewActions.qml";
51 case "actions": return "PreviewActions.qml";
52 case "audio": return "PreviewAudioPlayback.qml";
52 case "audio": return "PreviewAudioPlayback.qml";
53+ case "comment": return "PreviewComment.qml";
54+ case "comment-input": return "PreviewCommentInput.qml";
53 case "expandable": return "PreviewExpandable.qml";
55 case "expandable": return "PreviewExpandable.qml";
54 case "gallery": return "PreviewImageGallery.qml";
56 case "gallery": return "PreviewImageGallery.qml";
55 case "header": return "PreviewHeader.qml";
57 case "header": return "PreviewHeader.qml";
qml/Launcher/LauncherDelegate.qml+86
@@ -27,6 +27,8 @@ Item {
27 property bool itemFocused: false
27 property bool itemFocused: false
28 property real maxAngle: 0
28 property real maxAngle: 0
29 property bool inverted: false
29 property bool inverted: false
30+ property bool alerting: false
31+ readonly property alias wiggling: wiggleAnim.running
30
32
31 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
33 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * itemHeight
32 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
34 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * itemHeight
@@ -39,6 +41,82 @@ Item {
39 property real offset: 0
41 property real offset: 0
40 property real itemOpacity: 1
42 property real itemOpacity: 1
41 property real brightness: 0
43 property real brightness: 0
44+ property double maxWiggleAngle: 5.0
45+
46+ QtObject {
47+ id: priv
48+
49+ readonly property int wiggleDuration: UbuntuAnimation.SnapDuration
50+ property real wiggleAngle: 0
51+ }
52+
53+ SequentialAnimation {
54+ id: wiggleAnim
55+
56+ running: alerting
57+ loops: 1
58+ alwaysRunToEnd: true
59+
60+ NumberAnimation {
61+ target: priv
62+ property: "wiggleAngle"
63+ from: 0
64+ to: maxWiggleAngle
65+ duration: priv.wiggleDuration
66+ easing.type: Easing.InQuad
67+ }
68+
69+ NumberAnimation {
70+ target: priv
71+ property: "wiggleAngle"
72+ from: maxWiggleAngle
73+ to: -maxWiggleAngle
74+ duration: priv.wiggleDuration
75+ easing.type: Easing.InOutQuad
76+ }
77+
78+ NumberAnimation {
79+ target: priv
80+ property: "wiggleAngle"
81+ from: -maxWiggleAngle
82+ to: maxWiggleAngle
83+ duration: priv.wiggleDuration
84+ easing.type: Easing.InOutQuad
85+ }
86+
87+ NumberAnimation {
88+ target: priv
89+ property: "wiggleAngle"
90+ from: maxWiggleAngle
91+ to: -maxWiggleAngle
92+ duration: priv.wiggleDuration
93+ easing.type: Easing.InOutQuad
94+ }
95+
96+ NumberAnimation {
97+ target: priv
98+ property: "wiggleAngle"
99+ from: -maxWiggleAngle
100+ to: maxWiggleAngle
101+ duration: priv.wiggleDuration
102+ easing.type: Easing.InOutQuad
103+ }
104+
105+ NumberAnimation {
106+ target: priv
107+ property: "wiggleAngle"
108+ from: maxWiggleAngle
109+ to: 0
110+ duration: priv.wiggleDuration
111+ easing.type: Easing.OutQuad
112+ }
113+
114+ UbuntuNumberAnimation {
115+ target: root
116+ property: "alerting"
117+ to: 0
118+ }
119+ }
42
120
43 Item {
121 Item {
44 id: iconItem
122 id: iconItem
@@ -167,6 +245,14 @@ Item {
167 }
245 }
168
246
169 transform: [
247 transform: [
248+ // The rotation about the icon's center/z-axis for the wiggle
249+ // needs to happen here too, because there's no other way to
250+ // align the wiggle with the icon-folding otherwise
251+ Rotation {
252+ axis { x: 0; y: 0; z: 1 }
253+ origin { x: iconItem.width / 2; y: iconItem.height / 2; z: 0 }
254+ angle: priv.wiggleAngle
255+ },
170 // Rotating 3 times at top/bottom because that increases the perspective.
256 // Rotating 3 times at top/bottom because that increases the perspective.
171 // This is a hack, but as QML does not support real 3D coordinates
257 // This is a hack, but as QML does not support real 3D coordinates
172 // getting a higher perspective can only be done by a hack. This is the most
258 // getting a higher perspective can only be done by a hack. This is the most
qml/Launcher/LauncherPanel.qml+74−3
@@ -86,6 +86,7 @@ Rectangle {
86 height: parent.height - dashItem.height - parent.spacing*2
86 height: parent.height - dashItem.height - parent.spacing*2
87
87
88 Item {
88 Item {
89+ id: launcherListViewItem
89 anchors.fill: parent
90 anchors.fill: parent
90 clip: true
91 clip: true
91
92
@@ -109,12 +110,21 @@ Rectangle {
109 preferredHighlightBegin: (height - itemHeight) / 2
110 preferredHighlightBegin: (height - itemHeight) / 2
110 preferredHighlightEnd: (height + itemHeight) / 2
111 preferredHighlightEnd: (height + itemHeight) / 2
111
112
113+ // for the single peeking icon, when alert-state is set on delegate
114+ property int peekingIndex: -1
115+
112 // The size of the area the ListView is extended to make sure items are not
116 // The size of the area the ListView is extended to make sure items are not
113 // destroyed when dragging them outside the list. This needs to be at least
117 // destroyed when dragging them outside the list. This needs to be at least
114 // itemHeight to prevent folded items from disappearing and DragArea limits
118 // itemHeight to prevent folded items from disappearing and DragArea limits
115 // need to be smaller than this size to avoid breakage.
119 // need to be smaller than this size to avoid breakage.
116 property int extensionSize: 0
120 property int extensionSize: 0
117
121
122+ // These properties are needed to facilitate implicitly unfolding the
123+ // launcher to the peeking icon, if it is not already fully flat
124+ // and in view for the user
125+ property real moveToIndexYFrom
126+ property real moveToIndexYTo
127+
118 // Setting extensionSize after the list has been populated because it has
128 // Setting extensionSize after the list has been populated because it has
119 // the potential to mess up with the intial positioning in combination
129 // the potential to mess up with the intial positioning in combination
120 // with snapping to the center of the list. This catches all the cases
130 // with snapping to the center of the list. This catches all the cases
@@ -128,6 +138,14 @@ Rectangle {
128 flick(0, clickFlickSpeed)
138 flick(0, clickFlickSpeed)
129 }
139 }
130
140
141+ UbuntuNumberAnimation {
142+ id: moveToIndexAnimation
143+ target: launcherListView
144+ property: "contentY"
145+ from: launcherListView.moveToIndexYFrom
146+ to: launcherListView.moveToIndexYTo
147+ }
148+
131 // The height of the area where icons start getting folded
149 // The height of the area where icons start getting folded
132 property int foldingStartHeight: units.gu(6.5)
150 property int foldingStartHeight: units.gu(6.5)
133 // The height of the area where the items reach the final folding angle
151 // The height of the area where the items reach the final folding angle
@@ -180,10 +198,63 @@ Rectangle {
180 progress: model.progress
198 progress: model.progress
181 itemFocused: model.focused
199 itemFocused: model.focused
182 inverted: root.inverted
200 inverted: root.inverted
201+ alerting: model.alerting
183 z: -Math.abs(offset)
202 z: -Math.abs(offset)
184 maxAngle: 55
203 maxAngle: 55
185 property bool dragging: false
204 property bool dragging: false
186
205
206+ SequentialAnimation {
207+ id: peekingAnimation
208+
209+ // revealing
210+ PropertyAction { target: root; property: "visible"; value: (launcher.visibleWidth === 0) ? 1 : 0 }
211+ PropertyAction { target: launcherListViewItem; property: "clip"; value: 0 }
212+
213+ UbuntuNumberAnimation {
214+ target: launcherDelegate
215+ alwaysRunToEnd: true
216+ loops: 1
217+ properties: "x"
218+ to: (units.gu(.5) + launcherListView.width * .5) * (root.inverted ? -1 : 1)
219+ duration: UbuntuAnimation.BriskDuration
220+ }
221+
222+ // hiding
223+ UbuntuNumberAnimation {
224+ target: launcherDelegate
225+ alwaysRunToEnd: true
226+ loops: 1
227+ properties: "x"
228+ to: 0
229+ duration: UbuntuAnimation.BriskDuration
230+ }
231+
232+ PropertyAction { target: launcherListViewItem; property: "clip"; value: 1 }
233+ PropertyAction { target: root; property: "visible"; value: (launcher.visibleWidth === 0) ? 0 : 1 }
234+ }
235+
236+ onAlertingChanged: {
237+ if(alerting) {
238+ if (!dragging && (launcherListView.peekingIndex === -1 || launcher.visibleWidth > 0)) {
239+ launcherListView.moveToIndexYFrom = launcherListView.contentY
240+ launcherListView.positionViewAtIndex(index, ListView.Center)
241+ launcherListView.moveToIndexYTo = launcherListView.contentY
242+ moveToIndexAnimation.start()
243+ if (!dragging && launcher.state !== "visible") {
244+ peekingAnimation.start()
245+ }
246+ }
247+
248+ if (launcherListView.peekingIndex === -1) {
249+ launcherListView.peekingIndex = index
250+ }
251+ } else {
252+ if (launcherListView.peekingIndex === index) {
253+ launcherListView.peekingIndex = -1
254+ }
255+ }
256+ }
257+
187 ThinDivider {
258 ThinDivider {
188 id: dropIndicator
259 id: dropIndicator
189 objectName: "dropIndicator"
260 objectName: "dropIndicator"
@@ -521,7 +592,7 @@ Rectangle {
521 Image {
592 Image {
522 anchors {
593 anchors {
523 left: parent.left
594 left: parent.left
524− leftMargin: (quickList.item.width - units.gu(1)) / 2 - width / 2
595+ leftMargin: quickList.item !== undefined ? (quickList.item.width - units.gu(1)) / 2 - width / 2 : 0
525 verticalCenter: parent.verticalCenter
596 verticalCenter: parent.verticalCenter
526 verticalCenterOffset: (parent.height / 2 + units.dp(3)) * (quickList.offset > 0 ? 1 : -1) * (root.inverted ? 1 : -1)
597 verticalCenterOffset: (parent.height / 2 + units.dp(3)) * (quickList.offset > 0 ? 1 : -1) * (root.inverted ? 1 : -1)
527 }
598 }
@@ -564,9 +635,9 @@ Rectangle {
564
635
565 // internal
636 // internal
566 property int itemCenter: item ? root.mapFromItem(quickList.item).y + (item.height / 2) : units.gu(1)
637 property int itemCenter: item ? root.mapFromItem(quickList.item).y + (item.height / 2) : units.gu(1)
567− property int offset: itemCenter + (item.height/2) + height + units.gu(1) > parent.height ?
638+ property int offset: item !== undefined ? (itemCenter + (item.height/2) + height + units.gu(1) > parent.height ?
568 -(item.height/2) - height - units.gu(.5) :
639 -(item.height/2) - height - units.gu(.5) :
569− (item.height/2) + units.gu(.5)
640+ (item.height/2) + units.gu(.5)) : 0
570
641
571 Column {
642 Column {
572 id: quickListColumn
643 id: quickListColumn
qml/Notifications/Notifications.qml+1−1
@@ -33,7 +33,7 @@ ListView {
33 id: snapDecisionProxyModel
33 id: snapDecisionProxyModel
34 objectName: "snapDecisionProxyModel"
34 objectName: "snapDecisionProxyModel"
35
35
36− model: notificationList.model
36+ model: notificationList.model ? notificationList.model : null
37 filterRole: UnityNotifications.ModelInterface != undefined ? UnityNotifications.ModelInterface.RoleType : 0
37 filterRole: UnityNotifications.ModelInterface != undefined ? UnityNotifications.ModelInterface.RoleType : 0
38 filterRegExp: RegExp(UnityNotifications.Notification.SnapDecision)
38 filterRegExp: RegExp(UnityNotifications.Notification.SnapDecision)
39 }
39 }
qml/Panel/IndicatorItem.qml+1−1
@@ -234,7 +234,7 @@ IndicatorDelegate {
234 ]
234 ]
235 }
235 }
236
236
237− onRootActionStateChanged: {
237+ rootActionState.onUpdated: {
238 if (rootActionState == undefined) {
238 if (rootActionState == undefined) {
239 title = "";
239 title = "";
240 leftLabel = "";
240 leftLabel = "";
qml/Panel/Indicators/IndicatorBase.qml−1
@@ -43,6 +43,5 @@ Item {
43 ModelActionRootState {
43 ModelActionRootState {
44 id: rootAction
44 id: rootAction
45 menu: menuModel ? menuModel : null
45 menu: menuModel ? menuModel : null
46− onUpdated: indicatorItem.rootActionStateChanged()
47 }
46 }
48}
47}
qml/Tutorial/TutorialLeft.qml+16−6
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014,2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -46,24 +46,34 @@ TutorialPage {
46
46
47 SequentialAnimation {
47 SequentialAnimation {
48 id: teaseAnimation
48 id: teaseAnimation
49+ objectName: "teaseAnimation"
49 paused: running && root.paused
50 paused: running && root.paused
50 running: !slider.active && root.launcher.visibleWidth === 0 && root.shown
51 running: !slider.active && root.launcher.visibleWidth === 0 && root.shown
51 loops: Animation.Infinite
52 loops: Animation.Infinite
53+ property real bounce: 0
54+ readonly property real maxBounce: units.gu(2)
52
55
53 UbuntuNumberAnimation {
56 UbuntuNumberAnimation {
54− target: root.launcher
57+ target: teaseAnimation
55− property: "x"
58+ property: "bounce"
56− to: units.gu(2)
59+ to: teaseAnimation.maxBounce
57 duration: UbuntuAnimation.SleepyDuration
60 duration: UbuntuAnimation.SleepyDuration
58 }
61 }
59 UbuntuNumberAnimation {
62 UbuntuNumberAnimation {
60− target: root.launcher
63+ target: teaseAnimation
61− property: "x"
64+ property: "bounce"
62 to: 0
65 to: 0
63 duration: UbuntuAnimation.SleepyDuration
66 duration: UbuntuAnimation.SleepyDuration
64 }
67 }
65 }
68 }
66
69
70+ Binding {
71+ target: root.launcher
72+ when: root.shown
73+ property: "x"
74+ value: Math.min(root.launcher.panelWidth - root.launcher.visibleWidth, teaseAnimation.bounce)
75+ }
76+
67 Timer {
77 Timer {
68 id: finishTimer
78 id: finishTimer
69 interval: 1
79 interval: 1
tests/autopilot/unity8/settings_wizard/__init__.pynew file+507
@@ -0,0 +1,507 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2015 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+import logging
21+import re
22+
23+import autopilot
24+from autopilot import introspection
25+from ubuntuuitoolkit import UbuntuUIToolkitCustomProxyObjectBase
26+
27+from contextlib import contextmanager
28+
29+
30+logger = logging.getLogger(__name__)
31+
32+
33+@contextmanager
34+def override_proxy_timeout(proxy, timeout_seconds):
35+ original_timeout = proxy._poll_time
36+ try:
37+ proxy._poll_time = timeout_seconds
38+ yield proxy
39+ finally:
40+ proxy._poll_time = original_timeout
41+
42+
43+def get_wizard(current_page):
44+ return current_page.get_root_instance().select_single(Wizard)
45+
46+
47+class Wizard(UbuntuUIToolkitCustomProxyObjectBase):
48+ """High-level helper to navigate through the pages of the wizard"""
49+
50+ def get_language_page(self):
51+ return self.wait_select_single(
52+ objectName='languagePage', visible='True')
53+
54+ def get_current_page(self):
55+ return self.wait_select_single('Page', visible='True')
56+
57+ def get_sim_page(self):
58+ return self.wait_select_single(
59+ objectName='simPage', visible='True')
60+
61+ def get_password_page(self):
62+ return self.wait_select_single(
63+ objectName='passwdPage', visible='True')
64+
65+ def get_password_entry_page(self):
66+ return self.wait_select_single(
67+ objectName='passwdSetPage', visible='True')
68+
69+ def get_confirm_password_page(self):
70+ return self.wait_select_single(
71+ objectName='passwdConfirmPage', visible='True')
72+
73+ def get_wifi_connect_page(self):
74+ return self.wait_select_single(
75+ objectName='wifiPage', visible='True')
76+
77+ def get_reporting_page(self):
78+ return self.wait_select_single(
79+ objectName='reportingPage', visible='True')
80+
81+ def get_finished_page(self):
82+ return self.wait_select_single(
83+ objectName='finishedPage', visible='True')
84+
85+
86+class WizardLanguagePage(UbuntuUIToolkitCustomProxyObjectBase):
87+ """Helper class to interact with the language welcome page"""
88+
89+ # This class was renamed from LanguagePage to WizardLanguagePage because
90+ # there is a class with the same name in the system settings custom proxy
91+ # objects. Reported in http://pad.lv/1422904. --elopio - 2015-02-17
92+
93+ @classmethod
94+ def validate_dbus_object(cls, path, state):
95+ name = introspection.get_classname_from_path(path)
96+ if name == b'Page':
97+ if state['objectName'][1] == 'languagePage':
98+ return True
99+ return False
100+
101+ def _get_language_button(self):
102+ return self.select_single(
103+ 'ComboButton', objectName='languageCombo')
104+
105+ def _get_continue_button(self):
106+ return self.select_single('StackButton', text='Continue')
107+
108+ def _swipe_to_language(self, list, language):
109+ """Swipe to the chosen language in the given list"""
110+ list.swipe_to_top()
111+ while not list.atYEnd:
112+ try:
113+ item = list.select_single(
114+ 'LabelVisual', text=language, visible='True')
115+ item.swipe_into_view()
116+ return item
117+ except introspection.dbus.StateNotFoundError:
118+ list.swipe_to_show_more_below()
119+ # item could not be found
120+ raise introspection.dbus.StateNotFoundError
121+
122+ @autopilot.logging.log_action(logger.info)
123+ def select_language(self, language):
124+ """Select a different language from the list"""
125+ combo_button = self._get_language_button()
126+ self.pointing_device.click_object(combo_button)
127+ language_list = combo_button.wait_select_single(
128+ 'UbuntuListView11', visible='True')
129+ item = self._swipe_to_language(language_list, language)
130+ self.pointing_device.click_object(item)
131+
132+ def get_selected_language(self):
133+ return self._get_language_button().get_properties()['text']
134+
135+ @autopilot.logging.log_action(logger.info)
136+ def continue_(self):
137+ self.pointing_device.click_object(self._get_continue_button())
138+ wizard = get_wizard(self)
139+ next_page = wizard.get_current_page()
140+ sim_inserted = True
141+ if next_page.objectName == 'simPage':
142+ # no sim is inserted
143+ next_page = wizard.get_sim_page()
144+ sim_inserted = False
145+ else:
146+ # sim is inserted
147+ next_page = wizard.get_password_page()
148+ return sim_inserted, next_page
149+
150+
151+class SimPage(UbuntuUIToolkitCustomProxyObjectBase):
152+ """Helper class to interact with the no sim notification page"""
153+
154+ @classmethod
155+ def validate_dbus_object(cls, path, state):
156+ name = introspection.get_classname_from_path(path)
157+ if name == b'Page':
158+ if state['objectName'][1] == 'simPage':
159+ return True
160+ return False
161+
162+ def _get_back_button(self):
163+ return self.select_single('StackButton', text='Back')
164+
165+ def _get_skip_button(self):
166+ return self.select_single('StackButton', text='Skip')
167+
168+ @autopilot.logging.log_action(logger.info)
169+ def back(self):
170+ self.pointing_device.click_object(self._get_back_button())
171+ return get_wizard(self).get_languge_page()
172+
173+ @autopilot.logging.log_action(logger.info)
174+ def skip(self):
175+ self.pointing_device.click_object(self._get_skip_button())
176+ return get_wizard(self).get_password_page()
177+
178+
179+class PasswordPage(UbuntuUIToolkitCustomProxyObjectBase):
180+ """Helper class to interact with the password security page"""
181+
182+ SECURITY_SWIPE = 'Swipe'
183+ SECURITY_PASSCODE = 'Passcode'
184+ SECURITY_PASSPHRASE = 'Passphrase'
185+
186+ @classmethod
187+ def validate_dbus_object(cls, path, state):
188+ name = introspection.get_classname_from_path(path)
189+ if name == b'Page':
190+ if state['objectName'][1] == 'passwdPage':
191+ return True
192+ return False
193+
194+ def _get_option_name(self, formatted_name):
195+ # the option name is formatted as follows:
196+ # need to read the name between bold tags
197+ # '<b>Passcode</b> (4 digits only)'
198+ formatted_pattern = re.compile(r'<b>(.*?)</b>.*',
199+ re.IGNORECASE | re.DOTALL)
200+ name = None
201+ match = formatted_pattern.search(formatted_name)
202+ if match:
203+ name = match.group(1)
204+ return name
205+
206+ def _get_all_options(self):
207+ return self.select_many('OptionSelectorDelegate')
208+
209+ def _get_continue_button(self):
210+ return self.select_single('StackButton', text='Continue')
211+
212+ def _get_back_button(self):
213+ return self.select_single('StackButton', text='Back')
214+
215+ def _get_selected_option(self):
216+ return self.select_single(
217+ 'OptionSelectorDelegate', visible='True', selected='True')
218+
219+ def get_selected_security_option(self):
220+ name_fmt = self._get_selected_option().get_properties()['subText']
221+ return self._get_option_name(name_fmt)
222+
223+ @autopilot.logging.log_action(logger.info)
224+ def select_security_option(self, selected_option):
225+ options = self._get_all_options()
226+ for option in options:
227+ name = self._get_option_name(option.get_properties()['subText'])
228+ if name == selected_option:
229+ self.pointing_device.click_object(option)
230+
231+ @autopilot.logging.log_action(logger.info)
232+ def back(self, sim_inserted):
233+ self.pointing_device.click_object(self._get_back_button())
234+ wizard = get_wizard(self)
235+ if sim_inserted:
236+ page = wizard.get_languge_page()
237+ else:
238+ page = wizard.get_sim_page()
239+ return page
240+
241+ @autopilot.logging.log_action(logger.info)
242+ def continue_(self):
243+ option = self.get_selected_security_option()
244+ self.pointing_device.click_object(self._get_continue_button())
245+ wizard = get_wizard(self)
246+ if option == self.SECURITY_SWIPE:
247+ next_page = wizard.get_wifi_connect_page()
248+ else:
249+ next_page = wizard.get_password_entry_page()
250+ return next_page
251+
252+
253+class PasswordEntryPage(UbuntuUIToolkitCustomProxyObjectBase):
254+ """Helper class to interact with the pin entry page"""
255+
256+ @classmethod
257+ def validate_dbus_object(cls, path, state):
258+ name = introspection.get_classname_from_path(path)
259+ if name == b'Page':
260+ if state['objectName'][1] == 'passwdSetPage':
261+ return True
262+ return False
263+
264+ def _get_pinpad_button(self, char):
265+ return self.select_single('PinPadButton', text=char)
266+
267+ def _get_continue_button(self):
268+ return self.select_single('StackButton', text='Continue')
269+
270+ def _get_back_button(self):
271+ return self.select_single('StackButton', text='Back')
272+
273+ def _get_text_field(self):
274+ return self.select_single('QQuickTextInput')
275+
276+ @autopilot.logging.log_action(logger.info)
277+ def enter_pin(self, pin):
278+ for char in pin:
279+ self.pointing_device.click_object(self._get_pinpad_button(char))
280+ return get_wizard(self).get_confirm_password_page()
281+
282+ @autopilot.logging.log_action(logger.info)
283+ def enter_text(self, text):
284+ self.pointing_device.click_object(self._get_text_field())
285+ autopilot.input.Keyboard.create().type(text)
286+
287+ @autopilot.logging.log_action(logger.info)
288+ def back(self):
289+ self.pointing_device.click_object(self._get_back_button())
290+ return get_wizard(self).get_password_page()
291+
292+ @autopilot.logging.log_action(logger.info)
293+ def continue_(self):
294+ autopilot.input.Keyboard.create().press_and_release('Enter')
295+ return get_wizard(self).get_confirm_password_page()
296+
297+
298+class ConfirmPasswordPage(UbuntuUIToolkitCustomProxyObjectBase):
299+ """Helper class to interact with the pin confirmation page"""
300+
301+ @classmethod
302+ def validate_dbus_object(cls, path, state):
303+ name = introspection.get_classname_from_path(path)
304+ if name == b'Page':
305+ if state['objectName'][1] == 'passwdConfirmPage':
306+ return True
307+ return False
308+
309+ def _get_pinpad_button(self, char):
310+ return self.select_single('PinPadButton', text=char)
311+
312+ def _get_continue_button(self):
313+ return self.select_single('StackButton', text='Continue')
314+
315+ def _get_back_button(self):
316+ return self.select_single('StackButton', text='Back')
317+
318+ def _get_text_field(self):
319+ return self.select_single('QQuickTextInput')
320+
321+ @autopilot.logging.log_action(logger.info)
322+ def enter_pin(self, pin):
323+ for char in pin:
324+ self.pointing_device.click_object(self._get_pinpad_button(char))
325+ return get_wizard(self).get_wifi_connect_page()
326+
327+ @autopilot.logging.log_action(logger.info)
328+ def enter_text(self, text):
329+ self.pointing_device.click_object(self._get_text_field())
330+ autopilot.input.Keyboard.create().type(text)
331+
332+ @autopilot.logging.log_action(logger.info)
333+ def back(self):
334+ self.pointing_device.click_object(self._get_back_button())
335+ return get_wizard(self).get_password_page()
336+
337+ @autopilot.logging.log_action(logger.info)
338+ def continue_(self):
339+ autopilot.input.Keyboard.create().press_and_release('Enter')
340+ return get_wizard(self).get_wifi_connect_page()
341+
342+
343+class WifiConnectPage(UbuntuUIToolkitCustomProxyObjectBase):
344+ """Helper class to interact with the Wi-Fi network list page"""
345+
346+ @classmethod
347+ def validate_dbus_object(cls, path, state):
348+ name = introspection.get_classname_from_path(path)
349+ if name == b'Page':
350+ if state['objectName'][1] == 'wifiPage':
351+ return True
352+ return False
353+
354+ def _get_all_networks(self):
355+ try:
356+ networks = self.select_many('Standard', objectName='accessPoint',
357+ visible='True')
358+ except:
359+ networks = []
360+ return networks
361+
362+ def _get_network(self, ssid):
363+ return self.wait_select_single(
364+ 'Standard', objectName='accessPoint', text=ssid, visible='True')
365+
366+ def _get_network_checkbox(self, ssid):
367+ return self._get_network(ssid).select_single(
368+ 'CheckBox', visible='True')
369+
370+ def _get_notification(self, unity):
371+ logger.info('Waiting longer for notification object')
372+ with override_proxy_timeout(unity, 30):
373+ return unity.wait_select_single(
374+ Notification, objectName='notification1', visible='True')
375+
376+ def _get_back_button(self):
377+ return self.wait_select_single(
378+ 'StackButton', text='Back', visible='True')
379+
380+ def _get_skip_button(self):
381+ return self.wait_select_single(
382+ 'StackButton', text='Skip', visible='True')
383+
384+ def _get_continue_button(self):
385+ return self.wait_select_single(
386+ 'StackButton', text='Continue', visible='True')
387+
388+ def is_any_network_checked(self):
389+ networks = self._get_all_networks()
390+ for network in networks:
391+ checkbox = network.select_single('CheckBox', visible='True')
392+ if checkbox.get_properties()['checked']:
393+ return True
394+ return False
395+
396+ def is_any_network_found(self):
397+ num_neworks = len(self._get_all_networks())
398+ return True if num_neworks > 0 else False
399+
400+ def is_network_checked(self, ssid):
401+ return self._get_network_checkbox(ssid).get_properties()['checked']
402+
403+ @autopilot.logging.log_action(logger.info)
404+ def select_network(self, unity, ssid):
405+ self.pointing_device.click_object(self._get_network_checkbox(ssid))
406+ return PasswordNotification(self._get_notification(unity))
407+
408+ @autopilot.logging.log_action(logger.info)
409+ def back(self):
410+ self.pointing_device.click_object(self._get_back_button())
411+ return get_wizard(self).get_password_page()
412+
413+ @autopilot.logging.log_action(logger.info)
414+ def skip(self):
415+ self.pointing_device.click_object(self._get_skip_button())
416+ return get_wizard(self).get_reporting_page()
417+
418+ @autopilot.logging.log_action(logger.info)
419+ def continue_(self):
420+ self.pointing_device.click_object(self._get_continue_button())
421+ return get_wizard(self).get_reporting_page()
422+
423+
424+class Notification(UbuntuUIToolkitCustomProxyObjectBase):
425+ """Base class for notification objects"""
426+ pass
427+
428+
429+class PasswordNotification(Notification):
430+ """Helper class to interact with the password entry notification"""
431+
432+ def __init__(self, notification):
433+ self.notification = notification
434+
435+ def _get_connect_button(self):
436+ return self.notification.wait_select_single(
437+ 'Button', text='Connect', objectName='notify_button0')
438+
439+ def _get_cancel_buttoon(self):
440+ return self.notification.wait_select_single(
441+ 'Button', text='Cancel', objectName='notify_button1')
442+
443+ def _get_text_field(self):
444+ return self.notification.wait_select_single('TextField')
445+
446+ @autopilot.logging.log_action(logger.info)
447+ def enter_text(self, text):
448+ self._get_text_field().write(text)
449+
450+ @autopilot.logging.log_action(logger.info)
451+ def connect(self):
452+ self.notification.pointing_device.click_object(
453+ self._get_connect_button())
454+
455+ @autopilot.logging.log_action(logger.info)
456+ def cancel(self):
457+ self.notification.pointing_device.click_object(
458+ self._get_cancel_buttoon())
459+
460+
461+class ReportingPage(UbuntuUIToolkitCustomProxyObjectBase):
462+ """Helper class to interact with the reporting page"""
463+
464+ @classmethod
465+ def validate_dbus_object(cls, path, state):
466+ name = introspection.get_classname_from_path(path)
467+ if name == b'Page':
468+ if state['objectName'][1] == 'reportingPage':
469+ return True
470+ return False
471+
472+ def _get_continue_button(self):
473+ return self.select_single('StackButton', text='Continue')
474+
475+ def _get_back_button(self):
476+ return self.select_single('StackButton', text='Back')
477+
478+ @autopilot.logging.log_action(logger.info)
479+ def back(self):
480+ self.pointing_device.click_object(self._get_back_button())
481+ return get_wizard(self).get_wifi_connect_page()
482+
483+ @autopilot.logging.log_action(logger.info)
484+ def continue_(self):
485+ self.pointing_device.click_object(self._get_continue_button())
486+ return get_wizard(self).get_finished_page()
487+
488+
489+class FinishedPage(UbuntuUIToolkitCustomProxyObjectBase):
490+ """Helper class to interact with the finished page"""
491+
492+ @classmethod
493+ def validate_dbus_object(cls, path, state):
494+ name = introspection.get_classname_from_path(path)
495+ if name == b'Page':
496+ if state['objectName'][1] == 'finishedPage':
497+ return True
498+ return False
499+
500+ def _get_finish_button(self):
501+ return self.wait_select_single(
502+ 'StackButton', text='Finish', visible='True')
503+
504+ @autopilot.logging.log_action(logger.info)
505+ def finish(self):
506+ self.pointing_device.click_object(self._get_finish_button())
507+ self.wait_until_destroyed()
tests/autopilot/unity8/settings_wizard/fixture_setup.pynew file+58
@@ -0,0 +1,58 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2015 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""Set up and clean up fixtures for the Unity SettingsWizard tests."""
21+
22+import fixtures
23+import os
24+
25+from os.path import expanduser
26+
27+
28+class SettingsWizard(fixtures.Fixture):
29+ WIZARD_FILE = expanduser("~") + \
30+ '/.config/ubuntu-system-settings/wizard-has-run'
31+
32+ def __init__(self, enable):
33+ super().__init__()
34+ self.enable = enable
35+
36+ def setUp(self):
37+ super().setUp()
38+ original_state = self.is_settings_wizard_enabled()
39+ self.addCleanup(self.set_settings_wizard, original_state)
40+ if self.enable != original_state:
41+ self.set_settings_wizard(self.enable)
42+
43+ def is_settings_wizard_enabled(self):
44+ return not os.path.exists(self.WIZARD_FILE)
45+
46+ def set_settings_wizard(self, enabled):
47+ if enabled:
48+ self.enable_settings_wizard()
49+ else:
50+ self.disable_settings_wizard()
51+
52+ def enable_settings_wizard(self):
53+ if os.path.exists(self.WIZARD_FILE):
54+ os.remove(self.WIZARD_FILE)
55+
56+ def disable_settings_wizard(self):
57+ if not os.path.exists(self.WIZARD_FILE):
58+ open(self.WIZARD_FILE, 'a').close()
tests/autopilot/unity8/settings_wizard/ofono_helper.pynew file+116
@@ -0,0 +1,116 @@
1+#!/usr/bin/python -tt
2+
3+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
4+#
5+# Unity Indicators Autopilot Test Suite
6+# Copyright (C) 2014, 2015 Canonical
7+#
8+# This program is free software: you can redistribute it and/or modify
9+# it under the terms of the GNU General Public License as published by
10+# the Free Software Foundation, either version 3 of the License, or
11+# (at your option) any later version.
12+#
13+# This program is distributed in the hope that it will be useful,
14+# but WITHOUT ANY WARRANTY; without even the implied warranty of
15+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+# GNU General Public License for more details.
17+#
18+# You should have received a copy of the GNU General Public License
19+# along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
21+
22+from __future__ import absolute_import
23+
24+import dbus
25+import subprocess
26+from time import sleep
27+
28+
29+class OfonoManager(object):
30+
31+ def __init__(self):
32+ self.system_bus = dbus.SystemBus()
33+ self.ofono = self.system_bus.get_object('org.ofono', '/')
34+
35+ self.real_manager = dbus.Interface(
36+ self.ofono,
37+ 'org.ofono.Manager'
38+ )
39+
40+ def _get_sim_manager(self):
41+ modems = self.real_manager.GetModems()
42+ path = modems[0][0]
43+ return dbus.Interface(self.system_bus.get_object('org.ofono', path),
44+ 'org.ofono.SimManager')
45+
46+ def physical_sim_is_present(self):
47+ sim_manager = self._get_sim_manager()
48+ properties = sim_manager.GetProperties()
49+ return properties["Present"] == 1
50+
51+
52+class PhonesimManager(object):
53+
54+ def __init__(self, sims, exe=None):
55+ if exe is None:
56+ self.phonesim_exe = '/usr/bin/ofono-phonesim'
57+ else:
58+ self.phonesim_exe = exe
59+ self.sims = sims
60+ self.sim_processes = {}
61+ self.system_bus = dbus.SystemBus()
62+ self.ofono = self.system_bus.get_object('org.ofono', '/')
63+
64+ self.phonesim_manager = dbus.Interface(
65+ self.ofono,
66+ 'org.ofono.phonesim.Manager'
67+ )
68+
69+ def start_phonesim_processes(self):
70+ for simname, simport, conffile in self.sims:
71+ cmd = ['/usr/bin/xvfb-run',
72+ '-a',
73+ self.phonesim_exe,
74+ '-p',
75+ str(simport),
76+ conffile]
77+
78+ p = subprocess.Popen(cmd)
79+ self.sim_processes[simname] = p
80+ # give the processes some time to start
81+ sleep(3)
82+
83+ def shutdown(self):
84+ for p in self.sim_processes.values():
85+ p.kill()
86+ self.sim_processes = {}
87+
88+ def reset_ofono(self):
89+ self.phonesim_manager.Reset()
90+
91+ def remove_all_ofono(self):
92+ self.phonesim_manager.RemoveAll()
93+
94+ def add_ofono(self, name):
95+ for simname, simport, _ in self.sims:
96+ if name == simname:
97+ self.phonesim_manager.Add(simname, '127.0.0.1', str(simport))
98+ return
99+ raise RuntimeError('Tried to add unknown modem %s.' % name)
100+
101+ def power_on(self, sim_name):
102+ sim = self.system_bus.get_object('org.ofono', '/'+sim_name)
103+ modem = dbus.Interface(sim, dbus_interface='org.ofono.Modem')
104+ modem.SetProperty('Powered', True)
105+ sleep(1)
106+
107+ def power_off(self, sim_name):
108+ sim = self.system_bus.get_object('org.ofono', '/'+sim_name)
109+ modem = dbus.Interface(sim, dbus_interface='org.ofono.Modem')
110+ modem.SetProperty('Powered', False)
111+ sleep(1)
112+
113+ def get_required_pin(self, sim_name):
114+ sim = self.system_bus.get_object('org.ofono', '/'+sim_name)
115+ interface = dbus.Interface(sim, dbus_interface='org.ofono.SimManager')
116+ return str(interface.GetProperties()['PinRequired'])
tests/autopilot/unity8/settings_wizard/tests/__init__.pynew file

No changes to the content.

tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.pynew file+79
@@ -0,0 +1,79 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2015 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+from unity8.settings_wizard import fixture_setup, Wizard
21+from unity8.shell import tests
22+
23+DEFAULT_LANGUAGE = 'English (United States)'
24+DEFAULT_PHONESIM_CONFIG_FILE = '/usr/share/phonesim/default.xml'
25+DEFAULT_SECURITY_METHOD = 'Passcode'
26+
27+
28+class SkipThroughSettingsWizardTestCase(tests.UnityTestCase):
29+ """ Autopilot test for completing settings wizard """
30+
31+ def setUp(self):
32+ super().setUp()
33+ self.wizard_helper = self.useFixture(
34+ fixture_setup.SettingsWizard(True))
35+ self.unity = self.launch_unity()
36+ self.wizard = self._get_settings_wizard()
37+
38+ def _get_settings_wizard(self):
39+ return self.unity.wait_select_single(Wizard)
40+
41+ def _test_language_page(self):
42+ """ Get the language page, check the default language and continue """
43+ language_page = self.wizard.get_language_page()
44+ default_selection = language_page.get_selected_language()
45+ self.assertEqual(default_selection, DEFAULT_LANGUAGE)
46+ return language_page.continue_()
47+
48+ def _test_password_page(self, password_page):
49+ """ Check default selection for password type and change
50+ password type to swipe to keep this test as uncomplicated
51+ as possible """
52+ default_selection = password_page.get_selected_security_option()
53+ self.assertEqual(default_selection, DEFAULT_SECURITY_METHOD)
54+ password_page.select_security_option('Swipe')
55+ return password_page.continue_()
56+
57+ def _test_reporting_page(self, reporting_page):
58+ return reporting_page.continue_()
59+
60+ def _test_wifi_connect_page(self, wifi_connect_page):
61+ if wifi_connect_page.is_any_network_checked() or not \
62+ wifi_connect_page.is_any_network_found():
63+ return wifi_connect_page.continue_()
64+ else:
65+ return wifi_connect_page.skip()
66+
67+ def test_skipping_through_wizard(self):
68+ """ Most basic test of the settings wizard. Skip all skipable pages """
69+ sim_inserted, next_page = self._test_language_page()
70+ if sim_inserted:
71+ password_page = next_page
72+ else:
73+ password_page = next_page.skip()
74+ wifi_connect_page = self._test_password_page(password_page)
75+ reporting_page = self._test_wifi_connect_page(wifi_connect_page)
76+ finish_page = self._test_reporting_page(reporting_page)
77+ finish_page.finish()
78+ self.assertFalse(
79+ self.wizard_helper.is_settings_wizard_enabled())
tests/mocks/QMenuModel/QDBusActionGroup.qml+2−2
@@ -41,8 +41,8 @@ QtObject {
41 signal activated
41 signal activated
42
42
43 property string actionName: \"" + actionName + "\"
43 property string actionName: \"" + actionName + "\"
44− property bool valid: ActionData.data[actionName] != undefined ? ActionData.data[actionName].valid : false
44+ property bool valid: ActionData.data.hasOwnProperty(actionName) ? ActionData.data[actionName].valid : false
45− property var state: ActionData.data[actionName] != undefined ? ActionData.data[actionName].state : undefined
45+ property var state: ActionData.data.hasOwnProperty(actionName) ? ActionData.data[actionName].state : undefined
46
46
47 function activate() {
47 function activate() {
48 activated();
48 activated();
tests/mocks/QMenuModel/actiondata.h+3−1
@@ -31,7 +31,9 @@ class Q_DECL_EXPORT ActionData : public QObject
31public:
31public:
32 ActionData(QObject* parent = 0)
32 ActionData(QObject* parent = 0)
33 : QObject(parent)
33 : QObject(parent)
34+ , m_data(QVariantMap())
34− {}
35+ {
36+ }
35
37
36 QVariant data() const { return m_data; }
38 QVariant data() const { return m_data; }
37 void setData(const QVariant& data)
39 void setData(const QVariant& data)
tests/mocks/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,4 +1,4 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
2
2
3include_directories(
3include_directories(
4 ${CMAKE_CURRENT_SOURCE_DIR}
4 ${CMAKE_CURRENT_SOURCE_DIR}
tests/mocks/Unity/Launcher/MockLauncherItem.cpp+19
@@ -37,6 +37,7 @@ MockLauncherItem::MockLauncherItem(const QString &appId, const QString& desktopF
37 m_count(0),
37 m_count(0),
38 m_countVisible(false),
38 m_countVisible(false),
39 m_focused(false),
39 m_focused(false),
40+ m_alerting(false),
40 m_quickList(new MockQuickListModel(this))
41 m_quickList(new MockQuickListModel(this))
41{
42{
42
43
@@ -129,6 +130,9 @@ void MockLauncherItem::setCount(int count)
129 {
130 {
130 m_count = count;
131 m_count = count;
131 Q_EMIT countChanged(count);
132 Q_EMIT countChanged(count);
133+ if (m_countVisible) {
134+ setAlerting(true);
135+ }
132 }
136 }
133}
137}
134
138
@@ -142,6 +146,9 @@ void MockLauncherItem::setCountVisible(bool countVisible)
142 if (m_countVisible != countVisible) {
146 if (m_countVisible != countVisible) {
143 m_countVisible = countVisible;
147 m_countVisible = countVisible;
144 Q_EMIT countVisibleChanged(countVisible);
148 Q_EMIT countVisibleChanged(countVisible);
149+ if (countVisible) {
150+ setAlerting(true);
151+ }
145 }
152 }
146}
153}
147
154
@@ -159,6 +166,18 @@ void MockLauncherItem::setFocused(bool focused)
159 }
166 }
160}
167}
161
168
169+bool MockLauncherItem::alerting() const
170+{
171+ return m_alerting;
172+}
173+
174+void MockLauncherItem::setAlerting(bool alerting)
175+{
176+ if (m_alerting != alerting) {
177+ m_alerting = alerting;
178+ Q_EMIT alertingChanged(alerting);
179+ }
180+}
162
181
163unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
182unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
164{
183{
tests/mocks/Unity/Launcher/MockLauncherItem.h+3
@@ -44,6 +44,7 @@ public:
44 int count() const override;
44 int count() const override;
45 bool countVisible() const override;
45 bool countVisible() const override;
46 bool focused() const override;
46 bool focused() const override;
47+ bool alerting() const override;
47
48
48 unity::shell::launcher::QuickListModelInterface *quickList() const override;
49 unity::shell::launcher::QuickListModelInterface *quickList() const override;
49
50
@@ -55,6 +56,7 @@ private:
55 void setCount(int count);
56 void setCount(int count);
56 void setCountVisible(bool countVisible);
57 void setCountVisible(bool countVisible);
57 void setFocused(bool focused);
58 void setFocused(bool focused);
59+ void setAlerting(bool alerting);
58
60
59 QString m_appId;
61 QString m_appId;
60 QString m_desktopFile;
62 QString m_desktopFile;
@@ -67,6 +69,7 @@ private:
67 int m_count;
69 int m_count;
68 bool m_countVisible;
70 bool m_countVisible;
69 bool m_focused;
71 bool m_focused;
72+ bool m_alerting;
70 MockQuickListModel *m_quickList;
73 MockQuickListModel *m_quickList;
71
74
72 friend class MockLauncherModel;
75 friend class MockLauncherModel;
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+40
@@ -34,6 +34,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
34 item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
34 item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
35 item->setProgress(50);
35 item->setProgress(50);
36 item->setCountVisible(true);
36 item->setCountVisible(true);
37+ item->setAlerting(false);
37 m_list.append(item);
38 m_list.append(item);
38 item = new MockLauncherItem("music-app", "/usr/share/applications/music-app.desktop", "Music", "soundcloud", this);
39 item = new MockLauncherItem("music-app", "/usr/share/applications/music-app.desktop", "Music", "soundcloud", this);
39 m_list.append(item);
40 m_list.append(item);
@@ -43,25 +44,30 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
43 item = new MockLauncherItem("webbrowser-app", "/usr/share/applications/webbrowser-app.desktop", "Browser", "browser", this);
44 item = new MockLauncherItem("webbrowser-app", "/usr/share/applications/webbrowser-app.desktop", "Browser", "browser", this);
44 item->setCount(1);
45 item->setCount(1);
45 item->setCountVisible(true);
46 item->setCountVisible(true);
47+ item->setAlerting(false);
46 m_list.append(item);
48 m_list.append(item);
47 item = new MockLauncherItem("twitter-webapp", "/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter", this);
49 item = new MockLauncherItem("twitter-webapp", "/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter", this);
48 item->setCount(12);
50 item->setCount(12);
49 item->setCountVisible(true);
51 item->setCountVisible(true);
52+ item->setAlerting(false);
50 item->setPinned(true);
53 item->setPinned(true);
51 m_list.append(item);
54 m_list.append(item);
52 item = new MockLauncherItem("gmail-webapp", "/usr/share/applications/gmail-webapp.desktop", "GMail", "gmail", this);
55 item = new MockLauncherItem("gmail-webapp", "/usr/share/applications/gmail-webapp.desktop", "GMail", "gmail", this);
53 item->setCount(123);
56 item->setCount(123);
54 item->setCountVisible(true);
57 item->setCountVisible(true);
58+ item->setAlerting(false);
55 m_list.append(item);
59 m_list.append(item);
56 item = new MockLauncherItem("ubuntu-weather-app", "/usr/share/applications/ubuntu-weather-app.desktop", "Weather", "weather", this);
60 item = new MockLauncherItem("ubuntu-weather-app", "/usr/share/applications/ubuntu-weather-app.desktop", "Weather", "weather", this);
57 item->setCount(1234567890);
61 item->setCount(1234567890);
58 item->setCountVisible(true);
62 item->setCountVisible(true);
63+ item->setAlerting(false);
59 item->setPinned(true);
64 item->setPinned(true);
60 m_list.append(item);
65 m_list.append(item);
61 item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this);
66 item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this);
62 item->setProgress(50);
67 item->setProgress(50);
63 item->setCount(5);
68 item->setCount(5);
64 item->setCountVisible(true);
69 item->setCountVisible(true);
70+ item->setAlerting(false);
65 item->setFocused(true);
71 item->setFocused(true);
66 item->setPinned(true);
72 item->setPinned(true);
67 m_list.append(item);
73 m_list.append(item);
@@ -105,6 +111,8 @@ QVariant MockLauncherModel::data(const QModelIndex& index, int role) const
105 return item->countVisible();
111 return item->countVisible();
106 case RoleFocused:
112 case RoleFocused:
107 return item->focused();
113 return item->focused();
114+ case RoleAlerting:
115+ return item->alerting();
108 }
116 }
109
117
110 return QVariant();
118 return QVariant();
@@ -119,6 +127,18 @@ unity::shell::launcher::LauncherItemInterface *MockLauncherModel::get(int index)
119 return m_list.at(index);
127 return m_list.at(index);
120}
128}
121
129
130+void MockLauncherModel::setAlerting(const QString &appId, bool alerting) {
131+ int index = findApp(appId);
132+ if (index >= 0) {
133+ QModelIndex modelIndex = this->index(index);
134+ MockLauncherItem *item = m_list.at(index);
135+ if (!item->focused()) {
136+ item->setAlerting(alerting);
137+ Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RoleAlerting);
138+ }
139+ }
140+}
141+
122void MockLauncherModel::move(int oldIndex, int newIndex)
142void MockLauncherModel::move(int oldIndex, int newIndex)
123{
143{
124 // Make sure its not moved outside the lists
144 // Make sure its not moved outside the lists
@@ -236,6 +256,26 @@ void MockLauncherModel::emitHint()
236 Q_EMIT hint();
256 Q_EMIT hint();
237}
257}
238
258
259+void MockLauncherModel::setCount(const QString &appId, int count)
260+{
261+ int index = findApp(appId);
262+ if (index >= 0) {
263+ m_list.at(index)->setCount(count);
264+ QModelIndex modelIndex = this->index(index);
265+ Q_EMIT dataChanged(modelIndex, modelIndex);
266+ }
267+}
268+
269+void MockLauncherModel::setCountVisible(const QString &appId, bool countVisible)
270+{
271+ int index = findApp(appId);
272+ if (index >= 0) {
273+ m_list.at(index)->setCountVisible(countVisible);
274+ QModelIndex modelIndex = this->index(index);
275+ Q_EMIT dataChanged(modelIndex, modelIndex);
276+ }
277+}
278+
239unity::shell::application::ApplicationManagerInterface *MockLauncherModel::applicationManager() const
279unity::shell::application::ApplicationManagerInterface *MockLauncherModel::applicationManager() const
240{
280{
241 return nullptr;
281 return nullptr;
tests/mocks/Unity/Launcher/MockLauncherModel.h+3
@@ -38,6 +38,7 @@ public:
38
38
39 QVariant data(const QModelIndex& index, int role) const override;
39 QVariant data(const QModelIndex& index, int role) const override;
40
40
41+ Q_INVOKABLE void setAlerting(const QString &appId, bool alerting) override;
41 Q_INVOKABLE unity::shell::launcher::LauncherItemInterface *get(int index) const override;
42 Q_INVOKABLE unity::shell::launcher::LauncherItemInterface *get(int index) const override;
42 Q_INVOKABLE void move(int oldIndex, int newIndex) override;
43 Q_INVOKABLE void move(int oldIndex, int newIndex) override;
43 Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
44 Q_INVOKABLE void pin(const QString &appId, int index = -1) override;
@@ -55,6 +56,8 @@ public:
55 // For testing
56 // For testing
56 Q_INVOKABLE void emitHint();
57 Q_INVOKABLE void emitHint();
57 Q_INVOKABLE void setProgress(const QString &appId, int progress);
58 Q_INVOKABLE void setProgress(const QString &appId, int progress);
59+ Q_INVOKABLE void setCount(const QString &appId, int count);
60+ Q_INVOKABLE void setCountVisible(const QString &appId, bool countVisible);
58
61
59Q_SIGNALS:
62Q_SIGNALS:
60 void quickListTriggered(const QString &appId, int index);
63 void quickListTriggered(const QString &appId, int index);
tests/plugins/AccountsService/client.cpp+10−20
@@ -94,8 +94,7 @@ private Q_SLOTS:
94
94
95 void testGetSetService()
95 void testGetSetService()
96 {
96 {
97− AccountsService session;
97+ AccountsService session(this, QTest::currentTestFunction());
98− session.setUser(QTest::currentTestFunction());
99
98
100 QCOMPARE(session.demoEdges(), false);
99 QCOMPARE(session.demoEdges(), false);
101 session.setDemoEdges(true);
100 session.setDemoEdges(true);
@@ -112,8 +111,7 @@ private Q_SLOTS:
112
111
113 void testAsynchornousChangeForDemoEdges()
112 void testAsynchornousChangeForDemoEdges()
114 {
113 {
115− AccountsService session;
114+ AccountsService session(this, QTest::currentTestFunction());
116− session.setUser(QTest::currentTestFunction());
117
115
118 QCOMPARE(session.demoEdges(), false);
116 QCOMPARE(session.demoEdges(), false);
119 ASSERT_DBUS_CALL(m_userInterface->call("Set",
117 ASSERT_DBUS_CALL(m_userInterface->call("Set",
@@ -125,8 +123,7 @@ private Q_SLOTS:
125
123
126 void testAsynchornousChangeForFailedLogins()
124 void testAsynchornousChangeForFailedLogins()
127 {
125 {
128− AccountsService session;
126+ AccountsService session(this, QTest::currentTestFunction());
129− session.setUser(QTest::currentTestFunction());
130
127
131 QCOMPARE(session.failedLogins(), (uint)0);
128 QCOMPARE(session.failedLogins(), (uint)0);
132 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
129 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
@@ -138,8 +135,7 @@ private Q_SLOTS:
138
135
139 void testAsynchornousChangeForStatsWelcomeScreen()
136 void testAsynchornousChangeForStatsWelcomeScreen()
140 {
137 {
141− AccountsService session;
138+ AccountsService session(this, QTest::currentTestFunction());
142− session.setUser(QTest::currentTestFunction());
143
139
144 QCOMPARE(session.statsWelcomeScreen(), true);
140 QCOMPARE(session.statsWelcomeScreen(), true);
145 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
141 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
@@ -151,8 +147,7 @@ private Q_SLOTS:
151
147
152 void testAsynchornousChangeForStatsEnableLauncherWhileLocked()
148 void testAsynchornousChangeForStatsEnableLauncherWhileLocked()
153 {
149 {
154− AccountsService session;
150+ AccountsService session(this, QTest::currentTestFunction());
155− session.setUser(QTest::currentTestFunction());
156
151
157 QCOMPARE(session.enableLauncherWhileLocked(), true);
152 QCOMPARE(session.enableLauncherWhileLocked(), true);
158 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
153 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
@@ -164,8 +159,7 @@ private Q_SLOTS:
164
159
165 void testAsynchornousChangeForStatsEnableIndicatorsWhileLocked()
160 void testAsynchornousChangeForStatsEnableIndicatorsWhileLocked()
166 {
161 {
167− AccountsService session;
162+ AccountsService session(this, QTest::currentTestFunction());
168− session.setUser(QTest::currentTestFunction());
169
163
170 QCOMPARE(session.enableIndicatorsWhileLocked(), true);
164 QCOMPARE(session.enableIndicatorsWhileLocked(), true);
171 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
165 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
@@ -177,8 +171,7 @@ private Q_SLOTS:
177
171
178 void testAsynchornousChangeForStatsPasswordDisplayHint()
172 void testAsynchornousChangeForStatsPasswordDisplayHint()
179 {
173 {
180− AccountsService session;
174+ AccountsService session(this, QTest::currentTestFunction());
181− session.setUser(QTest::currentTestFunction());
182
175
183 QCOMPARE(session.passwordDisplayHint(), AccountsService::Keyboard);
176 QCOMPARE(session.passwordDisplayHint(), AccountsService::Keyboard);
184 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
177 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
@@ -190,8 +183,7 @@ private Q_SLOTS:
190
183
191 void testAsynchornousChangeForStatsLicenseAccepted()
184 void testAsynchornousChangeForStatsLicenseAccepted()
192 {
185 {
193− AccountsService session;
186+ AccountsService session(this, QTest::currentTestFunction());
194− session.setUser(QTest::currentTestFunction());
195
187
196 QCOMPARE(session.hereEnabled(), false);
188 QCOMPARE(session.hereEnabled(), false);
197 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
189 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
@@ -203,8 +195,7 @@ private Q_SLOTS:
203
195
204 void testAsynchornousChangeForLicenseBasePath()
196 void testAsynchornousChangeForLicenseBasePath()
205 {
197 {
206− AccountsService session;
198+ AccountsService session(this, QTest::currentTestFunction());
207− session.setUser(QTest::currentTestFunction());
208
199
209 QCOMPARE(session.hereLicensePath(), QString());
200 QCOMPARE(session.hereLicensePath(), QString());
210 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
201 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
@@ -216,8 +207,7 @@ private Q_SLOTS:
216
207
217 void testAsynchornousChangeForStatsBackgroundFile()
208 void testAsynchornousChangeForStatsBackgroundFile()
218 {
209 {
219− AccountsService session;
210+ AccountsService session(this, QTest::currentTestFunction());
220− session.setUser(QTest::currentTestFunction());
221
211
222 QCOMPARE(session.backgroundFile(), QString());
212 QCOMPARE(session.backgroundFile(), QString());
223 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
213 ASSERT_DBUS_CALL(m_userInterface->asyncCall("Set",
tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,4 +1,4 @@
1−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
1+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
2pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
3
3
4include_directories(
4include_directories(
tests/plugins/LightDM/CMakeLists.txt+6
@@ -9,6 +9,9 @@ add_executable(GreeterDBusTestExec
9 dbus.cpp
9 dbus.cpp
10 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
10 ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp
11 )
11 )
12+# This add_dependencies is needed since we're linking with with -L and -l below
13+# make seems to work but ninja breaks without it
14+add_dependencies(GreeterDBusTestExec MockLightDM)
12qt5_use_modules(GreeterDBusTestExec Core DBus Quick Test)
15qt5_use_modules(GreeterDBusTestExec Core DBus Quick Test)
13target_link_libraries(GreeterDBusTestExec
16target_link_libraries(GreeterDBusTestExec
14 -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm
17 -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm
@@ -44,6 +47,9 @@ add_executable(GreeterUsersModelTestExec
44 ${CMAKE_SOURCE_DIR}/plugins/LightDM/UsersModel.cpp
47 ${CMAKE_SOURCE_DIR}/plugins/LightDM/UsersModel.cpp
45 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
48 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
46 )
49 )
50+# This add_dependencies is needed since we're linking with with -L and -l below
51+# make seems to work but ninja breaks without it
52+add_dependencies(GreeterUsersModelTestExec MockLightDM)
47qt5_use_modules(GreeterUsersModelTestExec Core Test)
53qt5_use_modules(GreeterUsersModelTestExec Core Test)
48target_link_libraries(GreeterUsersModelTestExec
54target_link_libraries(GreeterUsersModelTestExec
49 -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm
55 -L${CMAKE_BINARY_DIR}/tests/mocks/LightDM/liblightdm
tests/plugins/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,5 +1,5 @@
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=6)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=7)
3
3
4include_directories(
4include_directories(
5 ${CMAKE_CURRENT_SOURCE_DIR}
5 ${CMAKE_CURRENT_SOURCE_DIR}
tests/plugins/Unity/Launcher/launchermodeltest.cpp+23−7
@@ -368,11 +368,18 @@ private Q_SLOTS:
368 }
368 }
369
369
370 void testCountEmblems() {
370 void testCountEmblems() {
371+ QSignalSpy spy(launcherModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)));
372+
371 // Call GetAll on abs-icon
373 // Call GetAll on abs-icon
372 QDBusInterface interface("com.canonical.Unity.Launcher", "/com/canonical/Unity/Launcher/abs_2Dicon", "org.freedesktop.DBus.Properties");
374 QDBusInterface interface("com.canonical.Unity.Launcher", "/com/canonical/Unity/Launcher/abs_2Dicon", "org.freedesktop.DBus.Properties");
373 QDBusReply<QVariantMap> reply = interface.call("GetAll");
375 QDBusReply<QVariantMap> reply = interface.call("GetAll");
374 QVariantMap map = reply.value();
376 QVariantMap map = reply.value();
375
377
378+ // Check that the alerting-status is still false, and the item on the upper side of the API
379+ int index = launcherModel->findApplication("abs-icon");
380+ QCOMPARE(index >= 0, true);
381+ QVERIFY(launcherModel->get(index)->alerting() == false);
382+
376 // Make sure GetAll returns a map with count and countVisible props
383 // Make sure GetAll returns a map with count and countVisible props
377 QCOMPARE(map.contains("count"), true);
384 QCOMPARE(map.contains("count"), true);
378 QCOMPARE(map.contains("countVisible"), true);
385 QCOMPARE(map.contains("countVisible"), true);
@@ -393,13 +400,8 @@ private Q_SLOTS:
393 QCOMPARE(map.value("count").toInt(), 55);
400 QCOMPARE(map.value("count").toInt(), 55);
394 QCOMPARE(map.value("countVisible").toBool(), true);
401 QCOMPARE(map.value("countVisible").toBool(), true);
395
402
396− // Now the item on the upper side of the API
403+ // Finally check, that the change to "count" implicitly also set the alerting-state to true
397− int index = launcherModel->findApplication("abs-icon");
398− QCOMPARE(index >= 0, true);
399−
400− // And make sure values have changed there as well
401− QCOMPARE(launcherModel->get(index)->countVisible(), true);
404+ QVERIFY(launcherModel->get(index)->alerting() == true);
402− QCOMPARE(launcherModel->get(index)->count(), 55);
403 }
405 }
404
406
405 void testCountEmblemAddsRemovesItem_data() {
407 void testCountEmblemAddsRemovesItem_data() {
@@ -459,6 +461,20 @@ private Q_SLOTS:
459 QCOMPARE(index == -1, !isRunning && !isPinned && !startWhenVisible);
461 QCOMPARE(index == -1, !isRunning && !isPinned && !startWhenVisible);
460 }
462 }
461
463
464+ void testAlert() {
465+ // Check that the alerting-status is still false
466+ int index = launcherModel->findApplication("abs-icon");
467+ QCOMPARE(index >= 0, true);
468+ QVERIFY(launcherModel->get(index)->alerting() == false);
469+
470+ // Call Alert() on "abs-icon"
471+ QDBusInterface interface("com.canonical.Unity.Launcher", "/com/canonical/Unity/Launcher/abs_2Dicon", "com.canonical.Unity.Launcher.Item");
472+ interface.call("Alert");
473+
474+ // Check that the alerting-status is now true
475+ QVERIFY(launcherModel->get(index)->alerting() == true);
476+ }
477+
462 void testRefreshAfterDeletedDesktopFiles_data() {
478 void testRefreshAfterDeletedDesktopFiles_data() {
463 QTest::addColumn<bool>("deleted");
479 QTest::addColumn<bool>("deleted");
464 QTest::newRow("have .desktop files") << false;
480 QTest::newRow("have .desktop files") << false;
tests/plugins/Unity/Session/sessionbackendtest.cpp+27−40
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright 2013 Canonical Ltd.
2+ * Copyright 2013-2015 Canonical Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU Lesser General Public License as published by
@@ -15,6 +15,7 @@
15 *
15 *
16 * Authors:
16 * Authors:
17 * Ying-Chun Liu (PaulLiu) <paul.liu@canonical.com>
17 * Ying-Chun Liu (PaulLiu) <paul.liu@canonical.com>
18+ * Lukáš Tinkl <lukas.tinkl@canonical.com>
18 */
19 */
19
20
20#include <QtTest>
21#include <QtTest>
@@ -49,17 +50,22 @@ private Q_SLOTS:
49
50
50 void testUnitySessionLogoutRequested_data() {
51 void testUnitySessionLogoutRequested_data() {
51 QTest::addColumn<QString>("method");
52 QTest::addColumn<QString>("method");
53+ QTest::addColumn<QString>("signal");
52
54
53− QTest::newRow("Logout") << "RequestLogout";
55+ QTest::newRow("Logout") << "RequestLogout" << "logoutRequested(bool)";
56+ QTest::newRow("Reboot") << "RequestReboot" << "rebootRequested(bool)";
57+ QTest::newRow("Shutdown") << "RequestShutdown" << "shutdownRequested(bool)";
54 }
58 }
55
59
56 void testUnitySessionLogoutRequested() {
60 void testUnitySessionLogoutRequested() {
57 QFETCH(QString, method);
61 QFETCH(QString, method);
62+ QFETCH(QString, signal);
58
63
59 DBusUnitySessionService dbusUnitySessionService;
64 DBusUnitySessionService dbusUnitySessionService;
60 QCoreApplication::processEvents(); // to let the service register on DBus
65 QCoreApplication::processEvents(); // to let the service register on DBus
61
66
67+ // .. because QSignalSpy checks the signal signature like this: "if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE)"
62− QSignalSpy spy(&dbusUnitySessionService, SIGNAL(logoutRequested(bool)));
68+ QSignalSpy spy(&dbusUnitySessionService, signal.prepend(QSIGNAL_CODE).toLocal8Bit().constData());
63
69
64 QDBusReply<void> reply = dbusUnitySession->call(method);
70 QDBusReply<void> reply = dbusUnitySession->call(method);
65 QCOMPARE(reply.isValid(), true);
71 QCOMPARE(reply.isValid(), true);
@@ -67,51 +73,34 @@ private Q_SLOTS:
67 QCOMPARE(spy.count(), 1);
73 QCOMPARE(spy.count(), 1);
68 }
74 }
69
75
70− void testGnomeSessionWrapperLogoutRequested() {
76+ void testGnomeSessionWrapper_data() {
71− DBusUnitySessionService dbusUnitySessionService;
77+ QTest::addColumn<uint>("method");
72− QCoreApplication::processEvents(); // to let the service register on DBus
78+ QTest::addColumn<QString>("signal");
73−
74− // Spy on the logoutRequested signal on the /com/canonical/Unity/Session object
75− // as proof we are actually calling the actual method.
76− QSignalSpy spy(&dbusUnitySessionService, SIGNAL(logoutRequested(bool)));
77
79
78− DBusGnomeSessionManagerWrapper dbusGnomeSessionManagerWrapper;
80+ QTest::newRow("Logout") << (uint)Action::LOGOUT << "logoutRequested(bool)";
79− QCoreApplication::processEvents(); // to let the service register on DBus
81+ QTest::newRow("Shutdown") << (unsigned)Action::SHUTDOWN << "shutdownRequested(bool)";
80−
82+ QTest::newRow("Reboot") << (unsigned)Action::REBOOT << "rebootRequested(bool)";
81− QDBusInterface dbusGnomeSessionWrapper ("com.canonical.Unity",
82− "/org/gnome/SessionManager/EndSessionDialog",
83− "org.gnome.SessionManager.EndSessionDialog",
84− QDBusConnection::sessionBus());
85−
86− QCOMPARE(dbusGnomeSessionWrapper.isValid(), true);
87−
88− // Set the QVariant as a QList<QDBusObjectPath> type
89− QDbusList var;
90− QVariant inhibitors;
91− inhibitors.setValue(var);
92−
93− QDBusReply<void> reply = dbusGnomeSessionWrapper.call("Open", (unsigned)Action::LOGOUT, (unsigned)0, (unsigned)0, inhibitors);
94− QCOMPARE(reply.isValid(), true);
95−
96− // Make sure we see the signal being emitted.
97− QCOMPARE(spy.count(), 1);
98 }
83 }
99
84
100− void testGnomeSessionWrapperShutdownRequested() {
85+ void testGnomeSessionWrapper() {
86+ QFETCH(uint, method);
87+ QFETCH(QString, signal);
88+
101 DBusUnitySessionService dbusUnitySessionService;
89 DBusUnitySessionService dbusUnitySessionService;
102 QCoreApplication::processEvents(); // to let the service register on DBus
90 QCoreApplication::processEvents(); // to let the service register on DBus
103
91
104− // Spy on the shutdownRequested signal on the /com/canonical/Unity/Session object
92+ // Spy on the given signal on the /com/canonical/Unity/Session object
105 // as proof we are actually calling the actual method.
93 // as proof we are actually calling the actual method.
94+ // .. because QSignalSpy checks the signal signature like this: "if (((aSignal[0] - '0') & 0x03) != QSIGNAL_CODE)"
106− QSignalSpy spy(&dbusUnitySessionService, SIGNAL(shutdownRequested(bool)));
95+ QSignalSpy spy(&dbusUnitySessionService, signal.prepend(QSIGNAL_CODE).toLocal8Bit().constData());
107
96
108 DBusGnomeSessionManagerWrapper dbusGnomeSessionManagerWrapper;
97 DBusGnomeSessionManagerWrapper dbusGnomeSessionManagerWrapper;
109 QCoreApplication::processEvents(); // to let the service register on DBus
98 QCoreApplication::processEvents(); // to let the service register on DBus
110
99
111− QDBusInterface dbusGnomeSessionWrapper ("com.canonical.Unity",
100+ QDBusInterface dbusGnomeSessionWrapper("com.canonical.Unity",
112− "/org/gnome/SessionManager/EndSessionDialog",
101+ "/org/gnome/SessionManager/EndSessionDialog",
113− "org.gnome.SessionManager.EndSessionDialog",
102+ "org.gnome.SessionManager.EndSessionDialog",
114− QDBusConnection::sessionBus());
103+ QDBusConnection::sessionBus());
115
104
116 QCOMPARE(dbusGnomeSessionWrapper.isValid(), true);
105 QCOMPARE(dbusGnomeSessionWrapper.isValid(), true);
117
106
@@ -120,9 +109,7 @@ private Q_SLOTS:
120 QVariant inhibitors;
109 QVariant inhibitors;
121 inhibitors.setValue(var);
110 inhibitors.setValue(var);
122
111
123− // * Reboot action translates to the shutdown signal due to some weird idiosyncracy
124− // in the indicator-session/Unity interaction. *
125− QDBusReply<void> reply = dbusGnomeSessionWrapper.call("Open", (unsigned)Action::REBOOT, (unsigned)0, (unsigned)0, inhibitors);
112+ QDBusReply<void> reply = dbusGnomeSessionWrapper.call("Open", method, (unsigned)0, (unsigned)0, inhibitors);
126 QCOMPARE(reply.isValid(), true);
113 QCOMPARE(reply.isValid(), true);
127
114
128 // Make sure we see the signal being emitted.
115 // Make sure we see the signal being emitted.
tests/qmltests/CMakeLists.txt+2
@@ -27,6 +27,8 @@ add_unity8_qmltest(Dash PreviewListView)
27add_unity8_qmltest(Dash/Previews Preview)
27add_unity8_qmltest(Dash/Previews Preview)
28add_unity8_qmltest(Dash/Previews PreviewActions)
28add_unity8_qmltest(Dash/Previews PreviewActions)
29add_unity8_qmltest(Dash/Previews PreviewAudioPlayback)
29add_unity8_qmltest(Dash/Previews PreviewAudioPlayback)
30+add_unity8_qmltest(Dash/Previews PreviewComment)
31+add_unity8_qmltest(Dash/Previews PreviewCommentInput)
30add_unity8_qmltest(Dash/Previews PreviewExpandable)
32add_unity8_qmltest(Dash/Previews PreviewExpandable)
31add_unity8_qmltest(Dash/Previews PreviewHeader)
33add_unity8_qmltest(Dash/Previews PreviewHeader)
32add_unity8_qmltest(Dash/Previews PreviewImageGallery)
34add_unity8_qmltest(Dash/Previews PreviewImageGallery)
tests/qmltests/Dash/Previews/tst_PreviewComment.qmlnew file+84
@@ -0,0 +1,84 @@
1+/*
2+ * Copyright 2015 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+import QtQuick 2.0
18+import QtTest 1.0
19+import Ubuntu.Components 1.1
20+import "../../../../qml/Dash/Previews"
21+import Unity.Test 0.1 as UT
22+
23+Rectangle {
24+ id: root
25+ width: units.gu(40)
26+ height: units.gu(80)
27+ color: Theme.palette.selected.background
28+
29+ property var comment: {
30+ "author": "Claire Thompson",
31+ "subtitle": "28/04/2015 3:48pm",
32+ "comment": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
33+ "source": "../../graphics/avatars/amanda@12.png"
34+ }
35+
36+ property var commentNoImage: {
37+ "author": "Claire Thompson",
38+ "subtitle": "28/04/2015 3:48pm",
39+ "comment": "Been quite a while since I really liked one.",
40+ "source": ""
41+ }
42+
43+ property var commentNoSubtitle: {
44+ "author": "Claire Thompson",
45+ "comment": "Been quite a while since I really liked one.",
46+ "source": "../../graphics/avatars/amanda@12.png"
47+ }
48+
49+ PreviewComment {
50+ id: previewComment
51+ anchors.left: parent.left
52+ anchors.right: parent.right
53+ widgetData: comment
54+ widgetId: "previewComment"
55+ }
56+
57+ UT.UnityTestCase {
58+ name: "PreviewCommentTest"
59+ when: windowShown
60+
61+ function init() {
62+ previewComment.widgetData = comment;
63+ }
64+
65+ function test_AnchorsNoAvatar() {
66+ var column = findChild(previewComment, "column");
67+ var avatar = findChild(previewComment, "avatar");
68+
69+ compare(previewComment.widgetData, comment);
70+ compare(avatar.visible, true);
71+ compare(column.anchors.left, avatar.anchors.right);
72+
73+ previewComment.widgetData = commentNoImage;
74+ tryCompare(avatar, "visible", false);
75+ compare(column.anchors.left, previewComment.anchors.left);
76+ }
77+
78+ function test_OptionalSubtitle() {
79+ var subtitle = findChild(previewComment, "subtitle");
80+ previewComment.widgetData = commentNoSubtitle;
81+ tryCompare(subtitle, "visible", false);
82+ }
83+ }
84+}
tests/qmltests/Dash/Previews/tst_PreviewCommentInput.qmlnew file+85
@@ -0,0 +1,85 @@
1+/*
2+ * Copyright 2015 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+import QtQuick 2.0
18+import QtTest 1.0
19+import Ubuntu.Components 1.1
20+import "../../../../qml/Dash/Previews"
21+import Unity.Test 0.1 as UT
22+
23+Rectangle {
24+ id: root
25+ width: units.gu(40)
26+ height: units.gu(80)
27+ color: Theme.palette.selected.background
28+
29+ property string validInputText: "Great!"
30+ property string invalidInputText: ""
31+
32+ property var widgetDataNewLabels: { "submit-label": "TestSubmitLabel" }
33+
34+ PreviewCommentInput {
35+ id: previewCommentInput
36+ anchors.left: parent.left
37+ anchors.right: parent.right
38+ widgetData: widgetDataNewLabels
39+ widgetId: "previewCommentInput"
40+ }
41+
42+ SignalSpy {
43+ id: spy
44+ signalName: "triggered"
45+ }
46+
47+ UT.UnityTestCase {
48+ name: "PreviewCommentInputTest"
49+ when: windowShown
50+
51+ property var commentTextArea: findChild(previewCommentInput, "commentTextArea")
52+ property var submitButton: findChild(previewCommentInput, "submitButton")
53+
54+ function init() {
55+ commentTextArea.text = "";
56+ }
57+
58+ function test_labels() {
59+ previewCommentInput.widgetData = widgetDataNewLabels;
60+ compare(submitButton.text, widgetDataNewLabels["submit-label"]);
61+ }
62+
63+ function test_submit_data() {
64+ return [
65+ {tag: "empty review", inputText: invalidInputText, emitted: false},
66+ {tag: "filled review", inputText: validInputText, emitted: true},
67+ ];
68+ }
69+
70+ function test_submit(data) {
71+ spy.clear();
72+ spy.target = previewCommentInput;
73+
74+ commentTextArea.text = data.inputText;
75+ mouseClick(submitButton);
76+ if (!data.emitted) {
77+ compare(spy.count, 0);
78+ } else {
79+ compare(spy.count, 1);
80+ var args = spy.signalArguments[0];
81+ compare(args[2]["comment"], data.inputText);
82+ }
83+ }
84+ }
85+}
tests/qmltests/Dash/Previews/tst_PreviewWidgetFactory.qml+2
@@ -77,6 +77,8 @@ Rectangle {
77 return [
77 return [
78 { tag: "Actions", type: "actions", source: "PreviewActions.qml" },
78 { tag: "Actions", type: "actions", source: "PreviewActions.qml" },
79 { tag: "Audio", type: "audio", source: "PreviewAudioPlayback.qml" },
79 { tag: "Audio", type: "audio", source: "PreviewAudioPlayback.qml" },
80+ { tag: "Comment", type: "comment", source: "PreviewComment.qml" },
81+ { tag: "Comment Input", type: "comment-input", source: "PreviewCommentInput.qml" },
80 { tag: "Expandable", type: "expandable", source: "PreviewExpandable.qml" },
82 { tag: "Expandable", type: "expandable", source: "PreviewExpandable.qml" },
81 { tag: "Gallery", type: "gallery", source: "PreviewImageGallery.qml" },
83 { tag: "Gallery", type: "gallery", source: "PreviewImageGallery.qml" },
82 { tag: "Header", type: "header", source: "PreviewHeader.qml" },
84 { tag: "Header", type: "header", source: "PreviewHeader.qml" },
tests/qmltests/Launcher/tst_Launcher.qml+168−24
@@ -95,30 +95,55 @@ Item {
95 }
95 }
96
96
97 Row {
97 Row {
98− spacing: units.gu(1)
98+ spacing: units.gu(1)
99−
99+
100− Button {
100+ Button {
101− text: "35% bar"
101+ text: "35% bar"
102− onClicked: LauncherModel.setProgress(LauncherModel.get(parseInt(appIdEntry.displayText)).appId, 35)
102+ onClicked: LauncherModel.setProgress(LauncherModel.get(parseInt(appIdEntryBar.displayText)).appId, 35)
103− Layout.fillWidth: true
103+ Layout.fillWidth: true
104− }
104+ }
105−
105+
106− TextArea {
106+ TextArea {
107− id: appIdEntry
107+ id: appIdEntryBar
108− anchors.verticalCenter: parent.verticalCenter
108+ anchors.verticalCenter: parent.verticalCenter
109− width: units.gu(4)
109+ width: units.gu(4)
110− height: units.gu(4)
110+ height: units.gu(4)
111− autoSize: true
111+ autoSize: true
112− text: "2"
112+ text: "2"
113− maximumLineCount: 1
113+ maximumLineCount: 1
114− }
114+ }
115−
115+
116− Button {
116+ Button {
117− text: "no bar"
117+ text: "no bar"
118− onClicked: LauncherModel.setProgress(LauncherModel.get(parseInt(appIdEntry.displayText)).appId, -1)
118+ onClicked: LauncherModel.setProgress(LauncherModel.get(parseInt(appIdEntryBar.displayText)).appId, -1)
119− Layout.fillWidth: true
119+ Layout.fillWidth: true
120+ }
121+ }
122+
123+ Row {
124+ spacing: units.gu(1)
125+
126+ Button {
127+ text: "set alert"
128+ onClicked: LauncherModel.setAlerting(LauncherModel.get(parseInt(appIdEntryAlert.displayText)).appId, true)
120− }
129+ }
130+
131+ TextArea {
132+ id: appIdEntryAlert
133+ anchors.verticalCenter: parent.verticalCenter
134+ width: units.gu(5)
135+ height: units.gu(4)
136+ autoSize: true
137+ text: "2"
138+ maximumLineCount: 1
139+ Layout.fillWidth: true
140+ }
141+
142+ Button {
143+ text: "unset alert"
144+ onClicked: LauncherModel.setAlerting(LauncherModel.get(parseInt(appIdEntryAlert.displayText)).appId, false)
145+ }
121− }
146+ }
122 }
147 }
123
148
124 SignalSpy {
149 SignalSpy {
@@ -195,6 +220,16 @@ Item {
195 tryCompare(panel, "x", -panel.width, 1000);
220 tryCompare(panel, "x", -panel.width, 1000);
196 }
221 }
197
222
223+ function waitForWiggleToStart(appIcon) {
224+ verify(appIcon != undefined)
225+ tryCompare(appIcon, "wiggling", true, 1000, "wiggle-anim should not be in stopped state")
226+ }
227+
228+ function waitForWiggleToStop(appIcon) {
229+ verify(appIcon != undefined)
230+ tryCompare(appIcon, "wiggling", false, 1000, "wiggle-anim should not be in running state")
231+ }
232+
198 function positionLauncherListAtBeginning() {
233 function positionLauncherListAtBeginning() {
199 var listView = testCase.findChild(launcherLoader.item, "launcherListView");
234 var listView = testCase.findChild(launcherLoader.item, "launcherListView");
200 listView.contentY = -listView.topMargin;
235 listView.contentY = -listView.topMargin;
@@ -673,5 +708,114 @@ Item {
673 compare(findChild(item, "progressOverlay").visible, true)
708 compare(findChild(item, "progressOverlay").visible, true)
674 LauncherModel.setProgress(LauncherModel.get(0).appId, 0)
709 LauncherModel.setProgress(LauncherModel.get(0).appId, 0)
675 }
710 }
711+
712+ function test_alertPeekingIcon() {
713+ var listView = findChild(launcher, "launcherListView")
714+ verify(listView != undefined)
715+ LauncherModel.setAlerting(LauncherModel.get(5).appId, true)
716+ tryCompare(listView, "peekingIndex", 5, 1000, "Wrong appId set as peeking-index")
717+ LauncherModel.setAlerting(LauncherModel.get(5).appId, false)
718+ tryCompare(listView, "peekingIndex", -1, 1000, "peeking-index should be -1")
719+ }
720+
721+ function test_alertHidingIcon() {
722+ var listView = findChild(launcher, "launcherListView")
723+ verify(listView != undefined)
724+ var appIcon6 = findChild(launcher, "launcherDelegate6")
725+ verify(appIcon6 != undefined)
726+ LauncherModel.setAlerting(LauncherModel.get(6).appId, true)
727+ waitForWiggleToStart(appIcon6)
728+ LauncherModel.setAlerting(LauncherModel.get(6).appId, false)
729+ waitForWiggleToStop(appIcon6)
730+ tryCompare(appIcon6, "x", 0, 1000, "x-value of appId #6 should not be non-zero")
731+ waitForRendering(listView)
732+ }
733+
734+ function test_alertIgnoreFocusedApp() {
735+ LauncherModel.setAlerting(LauncherModel.get(0).appId, true)
736+ compare(LauncherModel.get(0).alerting, false, "Focused app should not have the alert-state set")
737+ }
738+
739+ function test_alertOnlyOnePeekingIcon() {
740+ var listView = findChild(launcher, "launcherListView")
741+ verify(listView != undefined)
742+ LauncherModel.setAlerting(LauncherModel.get(3).appId, true)
743+ LauncherModel.setAlerting(LauncherModel.get(1).appId, true)
744+ LauncherModel.setAlerting(LauncherModel.get(5).appId, true)
745+ tryCompare(listView, "peekingIndex", 3, 1000, "Wrong appId set as peeking-index")
746+ LauncherModel.setAlerting(LauncherModel.get(1).appId, false)
747+ LauncherModel.setAlerting(LauncherModel.get(3).appId, false)
748+ LauncherModel.setAlerting(LauncherModel.get(5).appId, false)
749+ tryCompare(listView, "peekingIndex", -1, 1000, "peeking-index should be -1")
750+ waitForRendering(listView)
751+ }
752+
753+ function test_alertMultipleApps() {
754+ LauncherModel.setAlerting(LauncherModel.get(1).appId, true)
755+ LauncherModel.setAlerting(LauncherModel.get(3).appId, true)
756+ LauncherModel.setAlerting(LauncherModel.get(5).appId, true)
757+ LauncherModel.setAlerting(LauncherModel.get(7).appId, true)
758+ compare(LauncherModel.get(1).alerting, true, "Alert-state of appId #1 should not be false")
759+ compare(LauncherModel.get(3).alerting, true, "Alert-state of appId #3 should not be false")
760+ compare(LauncherModel.get(5).alerting, true, "Alert-state of appId #5 should not be false")
761+ compare(LauncherModel.get(7).alerting, true, "Alert-state of appId #7 should not be false")
762+ LauncherModel.setAlerting(LauncherModel.get(1).appId, false)
763+ LauncherModel.setAlerting(LauncherModel.get(3).appId, false)
764+ LauncherModel.setAlerting(LauncherModel.get(5).appId, false)
765+ LauncherModel.setAlerting(LauncherModel.get(7).appId, false)
766+ compare(LauncherModel.get(1).alerting, false, "Alert-state of appId #1 should not be true")
767+ compare(LauncherModel.get(3).alerting, false, "Alert-state of appId #1 should not be true")
768+ compare(LauncherModel.get(5).alerting, false, "Alert-state of appId #1 should not be true")
769+ compare(LauncherModel.get(7).alerting, false, "Alert-state of appId #1 should not be true")
770+ }
771+
772+ function test_alertMoveIconIntoView() {
773+ dragLauncherIntoView();
774+ var appIcon1 = findChild(launcher, "launcherDelegate1");
775+ var appIcon7 = findChild(launcher, "launcherDelegate7");
776+ LauncherModel.setAlerting(LauncherModel.get(1).appId, true)
777+ tryCompare(appIcon1, "angle", 0, 1000, "angle of appId #1 should not be non-zero")
778+ waitForWiggleToStart(appIcon1)
779+ LauncherModel.setAlerting(LauncherModel.get(7).appId, true)
780+ tryCompare(appIcon7, "angle", 0, 1000, "angle of appId #7 should not be non-zero")
781+ waitForWiggleToStart(appIcon7)
782+ LauncherModel.setAlerting(LauncherModel.get(1).appId, false)
783+ waitForWiggleToStop(appIcon1)
784+ LauncherModel.setAlerting(LauncherModel.get(7).appId, false)
785+ waitForWiggleToStop(appIcon7)
786+ }
787+
788+ function test_alertWigglePeekDrag() {
789+ var appIcon5 = findChild(launcher, "launcherDelegate5");
790+ var listView = findChild(launcher, "launcherListView")
791+ verify(listView != undefined)
792+ LauncherModel.setAlerting(LauncherModel.get(5).appId, true)
793+ tryCompare(listView, "peekingIndex", 5, 1000, "Wrong appId set as peeking-index")
794+ waitForWiggleToStart(appIcon5)
795+ tryCompare(appIcon5, "wiggling", true, 1000, "appId #6 should not be still")
796+ dragLauncherIntoView();
797+ tryCompare(listView, "peekingIndex", -1, 1000, "peeking-index should be -1")
798+ LauncherModel.setAlerting(LauncherModel.get(5).appId, false)
799+ waitForWiggleToStop(appIcon5)
800+ tryCompare(appIcon5, "wiggling", false, 1000, "appId #1 should not be wiggling")
801+ }
802+
803+ function test_alertViaCountAndCountVisible() {
804+ dragLauncherIntoView();
805+ var appIcon1 = findChild(launcher, "launcherDelegate1")
806+ var oldCount = LauncherModel.get(1).count
807+ LauncherModel.setCount(LauncherModel.get(1).appId, 42)
808+ tryCompare(appIcon1, "wiggling", false, 1000, "appId #1 should be still")
809+ LauncherModel.setCountVisible(LauncherModel.get(1).appId, 1)
810+ tryCompare(appIcon1, "wiggling", true, 1000, "appId #1 should not be still")
811+ LauncherModel.setAlerting(LauncherModel.get(1).appId, false)
812+ waitForWiggleToStop(appIcon1)
813+ LauncherModel.setCount(LauncherModel.get(1).appId, 4711)
814+ tryCompare(appIcon1, "wiggling", true, 1000, "appId #1 should not be still")
815+ LauncherModel.setAlerting(LauncherModel.get(1).appId, false)
816+ waitForWiggleToStop(appIcon1)
817+ LauncherModel.setCountVisible(LauncherModel.get(1).appId, 0)
818+ LauncherModel.setCount(LauncherModel.get(1).appId, oldCount)
819+ }
676 }
820 }
677}
821}
tests/qmltests/Tutorial/tst_Tutorial.qml+31−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013,2014 Canonical, Ltd.
2+ * Copyright (C) 2013,2014,2015 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -319,6 +319,36 @@ Item {
319 tryCompare(left, "shown", true); // and we should still be on left
319 tryCompare(left, "shown", true); // and we should still be on left
320 }
320 }
321
321
322+ function test_launcherNoDragGap() {
323+ // See bug 1454882, where if you dragged the launcher while it was
324+ // visible, you could pull it further than the edge of the screen.
325+
326+ var left = goToPage("tutorialLeft");
327+ var launcher = findChild(shell, "launcher");
328+ var teaseAnimation = findInvisibleChild(left, "teaseAnimation");
329+
330+ // Wait for launcher to be really out there
331+ tryCompareFunction(function() {return launcher.x > teaseAnimation.maxBounce/2}, true);
332+ verify(teaseAnimation.running);
333+
334+ // Start a drag, make sure animation stops
335+ touchFlick(shell, 0, halfHeight, units.gu(4), halfHeight, true, false);
336+ verify(!teaseAnimation.running);
337+ verify(launcher.visibleWidth > 0);
338+ verify(launcher.x > 0);
339+ compare(launcher.x, teaseAnimation.bounce);
340+
341+ // Continue drag, make sure we don't create a gap on the left hand side
342+ touchFlick(shell, units.gu(4), halfHeight, shell.width, halfHeight, false, false);
343+ verify(!teaseAnimation.running);
344+ compare(launcher.visibleWidth, launcher.panelWidth);
345+ compare(launcher.x, 0);
346+
347+ // Finish and make sure we continue animation
348+ touchFlick(shell, shell.width, halfHeight, shell.width, halfHeight, false, true);
349+ tryCompare(teaseAnimation, "running", true);
350+ }
351+
322 function test_spread() {
352 function test_spread() {
323 // Unfortunately, most of what we want to test of the spread is
353 // Unfortunately, most of what we want to test of the spread is
324 // "did it render correctly?" but that's hard to test. So instead,
354 // "did it render correctly?" but that's hard to test. So instead,
tests/qmltests/tst_ShellWithPin.qml+1−1
@@ -313,7 +313,7 @@ Item {
313 tryCompare(panel, "fullscreenMode", false)
313 tryCompare(panel, "fullscreenMode", false)
314 tryCompare(indicators, "available", true)
314 tryCompare(indicators, "available", true)
315 tryCompare(launcher, "available", true)
315 tryCompare(launcher, "available", true)
316− tryCompare(stage, "spreadEnabled", true)
316+ tryCompare(stage, "spreadEnabled", false)
317 }
317 }
318
318
319 function test_emergencyCallCrash() {
319 function test_emergencyCallCrash() {
tests/scripts/README+1
@@ -2,6 +2,7 @@ This directory holds a few handy shell-scripts to simplify runtime-testing of DB
2
2
3launcher-icon related:
3launcher-icon related:
4 * list-launcher-icons.sh - get all icons of unity8-launcher
4 * list-launcher-icons.sh - get all icons of unity8-launcher
5+ * alert-launcher-icon.sh - trigger alert/wiggle of unfocused launcher-icon
5 * get-progress.sh - get progress-value of a launcher-icon
6 * get-progress.sh - get progress-value of a launcher-icon
6 * set-progress.sh - set progress-value of a launcher-icon
7 * set-progress.sh - set progress-value of a launcher-icon
7 * set-count.sh - set the count of a launcher-icon
8 * set-count.sh - set the count of a launcher-icon
tests/scripts/alert-launcher-icon.shnew file+3
@@ -0,0 +1,3 @@
1+#!/bin/sh
2+
3+qdbus com.canonical.Unity.Launcher /com/canonical/Unity/Launcher/$1 com.canonical.Unity.Launcher.Item.Alert
tools/CMakeLists.txt+1
@@ -1,6 +1,7 @@
1add_executable(${SCOPE_TOOL}
1add_executable(${SCOPE_TOOL}
2 scopetool.cpp
2 scopetool.cpp
3 registry-tracker.cpp
3 registry-tracker.cpp
4+ unix-signal-handler.cpp
4 )
5 )
5
6
6qt5_use_modules(${SCOPE_TOOL} Qml Quick)
7qt5_use_modules(${SCOPE_TOOL} Qml Quick)
tools/scopetool.cpp+6
@@ -32,6 +32,7 @@
32// local
32// local
33#include <paths.h>
33#include <paths.h>
34#include "registry-tracker.h"
34#include "registry-tracker.h"
35+#include "unix-signal-handler.h"
35
36
36
37
37int main(int argc, char *argv[])
38int main(int argc, char *argv[])
@@ -96,6 +97,11 @@ int main(int argc, char *argv[])
96
97
97 view->show();
98 view->show();
98
99
100+ UnixSignalHandler signal_handler([]{
101+ QGuiApplication::exit(0);
102+ });
103+ signal_handler.setupUnixSignalHandlers();
104+
99 int result = application->exec();
105 int result = application->exec();
100
106
101 delete view;
107 delete view;
tools/unix-signal-handler.cppnew file+141
@@ -0,0 +1,141 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Marcus Tomlinson <marcus.tomlinson@canonical.com>
17+ */
18+
19+#include "unix-signal-handler.h"
20+
21+#include <QDebug>
22+
23+#include <csignal>
24+#include <sys/socket.h>
25+#include <unistd.h>
26+
27+int UnixSignalHandler::sighupFd[2];
28+int UnixSignalHandler::sigintFd[2];
29+int UnixSignalHandler::sigtermFd[2];
30+
31+UnixSignalHandler::UnixSignalHandler(const std::function<void()>& f, QObject *parent)
32+ : QObject(parent),
33+ m_func(f)
34+{
35+ if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd))
36+ {
37+ qFatal("Couldn't create HUP socketpair");
38+ }
39+ if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd))
40+ {
41+ qFatal("Couldn't create INT socketpair");
42+ }
43+ if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd))
44+ {
45+ qFatal("Couldn't create TERM socketpair");
46+ }
47+
48+ m_socketNotifierHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this);
49+ connect(m_socketNotifierHup, &QSocketNotifier::activated, this, &UnixSignalHandler::handleSigHup);
50+ m_socketNotifierInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this);
51+ connect(m_socketNotifierInt, &QSocketNotifier::activated, this, &UnixSignalHandler::handleSigInt);
52+ m_socketNotifierTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
53+ connect(m_socketNotifierTerm, &QSocketNotifier::activated, this, &UnixSignalHandler::handleSigTerm);
54+}
55+
56+void UnixSignalHandler::hupSignalHandler(int)
57+{
58+ char a = 1;
59+ ::write(sighupFd[0], &a, sizeof(a));
60+}
61+
62+void UnixSignalHandler::intSignalHandler(int)
63+{
64+ char a = 1;
65+ ::write(sigintFd[0], &a, sizeof(a));
66+}
67+
68+void UnixSignalHandler::termSignalHandler(int)
69+{
70+ char a = 1;
71+ ::write(sigtermFd[0], &a, sizeof(a));
72+}
73+
74+int UnixSignalHandler::setupUnixSignalHandlers()
75+{
76+ struct sigaction sighup, sigint, sigterm;
77+
78+ sighup.sa_handler = UnixSignalHandler::hupSignalHandler;
79+ sigemptyset(&sighup.sa_mask);
80+ sighup.sa_flags = 0;
81+ sighup.sa_flags |= SA_RESTART;
82+
83+ if (sigaction(SIGHUP, &sighup, 0) > 0)
84+ {
85+ return 1;
86+ }
87+
88+ sigint.sa_handler = UnixSignalHandler::intSignalHandler;
89+ sigemptyset(&sigint.sa_mask);
90+ sigint.sa_flags = 0;
91+ sigint.sa_flags |= SA_RESTART;
92+
93+ if (sigaction(SIGINT, &sigint, 0) > 0)
94+ {
95+ return 2;
96+ }
97+
98+ sigterm.sa_handler = UnixSignalHandler::termSignalHandler;
99+ sigemptyset(&sigterm.sa_mask);
100+ sigterm.sa_flags |= SA_RESTART;
101+
102+ if (sigaction(SIGTERM, &sigterm, 0) > 0)
103+ {
104+ return 3;
105+ }
106+
107+ return 0;
108+}
109+
110+void UnixSignalHandler::handleSigHup()
111+{
112+ m_socketNotifierHup->setEnabled(false);
113+ char tmp;
114+ ::read(sighupFd[1], &tmp, sizeof(tmp));
115+
116+ m_func();
117+
118+ m_socketNotifierHup->setEnabled(true);
119+}
120+
121+void UnixSignalHandler::handleSigInt()
122+{
123+ m_socketNotifierInt->setEnabled(false);
124+ char tmp;
125+ ::read(sigintFd[1], &tmp, sizeof(tmp));
126+
127+ m_func();
128+
129+ m_socketNotifierInt->setEnabled(true);
130+}
131+
132+void UnixSignalHandler::handleSigTerm()
133+{
134+ m_socketNotifierTerm->setEnabled(false);
135+ char tmp;
136+ ::read(sigtermFd[1], &tmp, sizeof(tmp));
137+
138+ m_func();
139+
140+ m_socketNotifierTerm->setEnabled(true);
141+}
tools/unix-signal-handler.hnew file+54
@@ -0,0 +1,54 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Marcus Tomlinson <marcus.tomlinson@canonical.com>
17+ */
18+
19+#pragma once
20+
21+#include <QObject>
22+#include <QSocketNotifier>
23+
24+#include <functional>
25+
26+class UnixSignalHandler: public QObject {
27+Q_OBJECT
28+
29+public:
30+ UnixSignalHandler(const std::function<void()>& f, QObject *parent = 0);
31+ ~UnixSignalHandler() = default;
32+
33+ static int setupUnixSignalHandlers();
34+
35+protected Q_SLOTS:
36+ void handleSigHup();
37+ void handleSigInt();
38+ void handleSigTerm();
39+
40+protected:
41+ static void hupSignalHandler(int unused);
42+ static void intSignalHandler(int unused);
43+ static void termSignalHandler(int unused);
44+
45+ static int sighupFd[2];
46+ static int sigintFd[2];
47+ static int sigtermFd[2];
48+
49+ std::function<void()> m_func;
50+
51+ QSocketNotifier *m_socketNotifierHup;
52+ QSocketNotifier *m_socketNotifierInt;
53+ QSocketNotifier *m_socketNotifierTerm;
54+};