on xenial help sign in
Merge
commit7f3c4171e15838d052b53417b3b2b5859e0031e1 authorAlbert Astals <albert.astals@canonical.com> dateTue 16 Dec 2014, 09:16 (12 years ago) parent071d208f0a4ab9
46 files changed+996−389
debian/changelog+23 plugins/Dash/abstractdashview.cpp+24−5 plugins/Dash/abstractdashview.h+6 plugins/Dash/listviewwithpageheader.cpp+7−2 plugins/Dash/listviewwithpageheader.h+4−4 plugins/Ubuntu/Gestures/Direction.cpp+6−2 plugins/Ubuntu/Gestures/Direction.h+2−1 plugins/Ubuntu/Gestures/DirectionalDragArea.cpp+27−37 plugins/Unity/Session/dbusunitysessionservice.h+5 po/br.po+45−37 po/hu.po+47−39 qml/Components/Dialogs.qml+61−67 qml/Components/DragHandle.qml+10−2 qml/Components/EdgeDragEvaluator.qml+11−5 qml/Components/ResponsiveVerticalJournal.qml+1 qml/Components/ShellDialog.qml+37 qml/Components/Showable.qml+13 qml/Dash/CardGrid.qml+1−2 qml/Dash/CardVerticalJournal.qml+1 qml/Dash/Dash.qml+1 qml/Dash/DashContent.qml+2 qml/Dash/DashRenderer.qml+2 qml/Dash/GenericScopeView.qml+46−20 qml/Dash/ScopeListView.qml+4−2 qml/Dash/ScopesList.qml+5−1 qml/Dash/ScopesListCategory.qml+2−2 qml/Dash/ScopesListCategoryItem.qml+3−1 qml/Greeter/Greeter.qml+91−82 qml/Greeter/Infographics.qml−3 qml/Shell.qml+12−4 tests/autopilot/unity8/shell/emulators/dash.py+22−8 tests/mocks/Unity/Application/ApplicationManager.cpp+7 tests/plugins/Dash/horizontaljournaltest.qml+1 tests/plugins/Dash/listviewwithpageheadertest.cpp+1−1 tests/plugins/Dash/organicgridtest.qml+1 tests/plugins/Dash/verticaljournaltest.qml+1 tests/qmltests/CMakeLists.txt+1 tests/qmltests/Components/tst_Dialogs.qml+104 tests/qmltests/Components/tst_DragHandle.cpp+4 tests/qmltests/Components/tst_DragHandle.qml+43−8 tests/qmltests/Components/tst_DragHandle/BidirectionalShowable.qml+69 tests/qmltests/Dash/tst_Dash.qml+107−11 tests/qmltests/Dash/tst_GenericScopeView.qml+2 tests/qmltests/Greeter/tst_MultiGreeter.qml+15−15 tests/qmltests/Greeter/tst_SingleGreeter.qml+104−16 tests/qmltests/tst_TabletShell.qml+15−12
debian/changelog+23
@@ -1,3 +1,26 @@
1+unity8 (8.02+15.04.20141215.3-0ubuntu1) vivid; urgency=low
2+
3+ [ Albert Astals Cid ]
4+ * ScopesList: Use the default scope style for the header
5+
6+ [ Daniel d'Andrada ]
7+ * Refactor Dialogs.qml to use proper in-scene dialogs
8+ * Make Greeter nicely handle being resized
9+
10+ [ Albert Astals ]
11+ * Rework how we set the ranges so we get some more asynchronousity
12+ from item views (LP: #1384374)
13+ * clickscope is back to being unfavoritable (LP: #1400762)
14+ * Fix clicking on the manage dash list after having moved the current
15+ scope
16+ * Make the drag range be a multiple of the drag "rate" value.
17+ Workarounds https://bugs.launchpad.net/mir/+bug/1399690
18+
19+ [ Gerry Boland ]
20+ * MockAppMan: emit SIGSTOP so AP test apps are run (LP: #1394208)
21+
22+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 15 Dec 2014 22:43:16 +0000
23+
124unity8 (8.02+15.04.20141212.1-0ubuntu1) vivid; urgency=low
225
326 [ Ubuntu daily release ]
plugins/Dash/abstractdashview.cpp+24−5
@@ -16,13 +16,12 @@
1616
1717#include "abstractdashview.h"
1818
19−static const qreal bufferRatio = 0.5;
20−
2119AbstractDashView::AbstractDashView()
2220 : m_delegateModel(nullptr)
2321 , m_asyncRequestedIndex(-1)
2422 , m_columnSpacing(0)
2523 , m_rowSpacing(0)
24+ , m_buffer(320) // Same value used in qquickitemview.cpp in Qt 5.4
2625 , m_displayMarginBeginning(0)
2726 , m_displayMarginEnd(0)
2827 , m_needsRelayout(false)
@@ -112,6 +111,27 @@ void AbstractDashView::setRowSpacing(qreal rowSpacing)
112111 }
113112}
114113
114+int AbstractDashView::cacheBuffer() const
115+{
116+ return m_buffer;
117+}
118+
119+void AbstractDashView::setCacheBuffer(int buffer)
120+{
121+ if (buffer < 0) {
122+ qmlInfo(this) << "Cannot set a negative cache buffer";
123+ return;
124+ }
125+
126+ if (m_buffer != buffer) {
127+ m_buffer = buffer;
128+ if (isComponentComplete()) {
129+ polish();
130+ }
131+ emit cacheBufferChanged();
132+ }
133+}
134+
115135qreal AbstractDashView::displayMarginBeginning() const
116136{
117137 return m_displayMarginBeginning;
@@ -160,9 +180,8 @@ void AbstractDashView::refill()
160180
161181 const qreal from = -m_displayMarginBeginning;
162182 const qreal to = height() + m_displayMarginEnd;
163− const qreal buffer = (to - from) * bufferRatio;
164− const qreal bufferFrom = from - buffer;
165− const qreal bufferTo = to + buffer;
183+ const qreal bufferFrom = from - m_buffer;
184+ const qreal bufferTo = to + m_buffer;
166185
167186 bool added = addVisibleItems(from, to, false);
168187 bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
plugins/Dash/abstractdashview.h+6
@@ -35,6 +35,7 @@ class AbstractDashView : public QQuickItem
3535 Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
3636 Q_PROPERTY(qreal columnSpacing READ columnSpacing WRITE setColumnSpacing NOTIFY columnSpacingChanged)
3737 Q_PROPERTY(qreal rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged)
38+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
3839 Q_PROPERTY(qreal displayMarginBeginning READ displayMarginBeginning
3940 WRITE setDisplayMarginBeginning
4041 NOTIFY displayMarginBeginningChanged)
@@ -61,6 +62,9 @@ public:
6162 qreal rowSpacing() const;
6263 void setRowSpacing(qreal rowSpacing);
6364
65+ int cacheBuffer() const;
66+ void setCacheBuffer(int);
67+
6468 qreal displayMarginBeginning() const;
6569 void setDisplayMarginBeginning(qreal);
6670
@@ -72,6 +76,7 @@ Q_SIGNALS:
7276 void delegateChanged();
7377 void columnSpacingChanged();
7478 void rowSpacingChanged();
79+ void cacheBufferChanged();
7580 void displayMarginBeginningChanged();
7681 void displayMarginEndChanged();
7782
@@ -117,6 +122,7 @@ private:
117122
118123 int m_columnSpacing;
119124 int m_rowSpacing;
125+ int m_buffer;
120126 qreal m_displayMarginBeginning;
121127 qreal m_displayMarginEnd;
122128 bool m_needsRelayout;
plugins/Dash/listviewwithpageheader.cpp+7−2
@@ -334,13 +334,18 @@ qreal ListViewWithPageHeader::headerItemShownHeight() const
334334 return m_headerItemShownHeight;
335335}
336336
337−qreal ListViewWithPageHeader::cacheBuffer() const
337+int ListViewWithPageHeader::cacheBuffer() const
338338{
339339 return m_cacheBuffer;
340340}
341341
342−void ListViewWithPageHeader::setCacheBuffer(qreal cacheBuffer)
342+void ListViewWithPageHeader::setCacheBuffer(int cacheBuffer)
343343{
344+ if (cacheBuffer < 0) {
345+ qmlInfo(this) << "Cannot set a negative cache buffer";
346+ return;
347+ }
348+
344349 if (cacheBuffer != m_cacheBuffer) {
345350 m_cacheBuffer = cacheBuffer;
346351 Q_EMIT cacheBufferChanged();
plugins/Dash/listviewwithpageheader.h+4−4
@@ -54,7 +54,7 @@ class ListViewWithPageHeader : public QQuickFlickable, public QQuickItemChangeLi
5454 Q_PROPERTY(bool forceNoClip READ forceNoClip WRITE setForceNoClip NOTIFY forceNoClipChanged)
5555 Q_PROPERTY(int stickyHeaderHeight READ stickyHeaderHeight NOTIFY stickyHeaderHeightChanged)
5656 Q_PROPERTY(qreal headerItemShownHeight READ headerItemShownHeight NOTIFY headerItemShownHeightChanged)
57− Q_PROPERTY(qreal cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
57+ Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged)
5858
5959 friend class ListViewWithPageHeaderTest;
6060 friend class ListViewWithPageHeaderTestSection;
@@ -85,8 +85,8 @@ public:
8585 int stickyHeaderHeight() const;
8686 qreal headerItemShownHeight() const;
8787
88− qreal cacheBuffer() const;
89− void setCacheBuffer(qreal cacheBuffer);
88+ int cacheBuffer() const;
89+ void setCacheBuffer(int cacheBuffer);
9090
9191 Q_INVOKABLE void positionAtBeginning();
9292 Q_INVOKABLE void showHeader();
@@ -204,7 +204,7 @@ private:
204204 bool m_forceNoClip;
205205 bool m_inLayout;
206206 bool m_inContentHeightKeepHeaderShown;
207− qreal m_cacheBuffer;
207+ int m_cacheBuffer;
208208
209209 // Qt 5.0 doesn't like releasing the items just after itemCreated
210210 // so we delay the releasing until the next updatePolish
plugins/Ubuntu/Gestures/Direction.cpp+6−2
@@ -18,7 +18,9 @@
1818
1919bool Direction::isHorizontal(Direction::Type type)
2020{
21− return type == Direction::Leftwards || type == Direction::Rightwards;
21+ return type == Direction::Leftwards
22+ || type == Direction::Rightwards
23+ || type == Direction::Horizontal;
2224}
2325
2426bool Direction::isVertical(Direction::Type type)
@@ -28,5 +30,7 @@ bool Direction::isVertical(Direction::Type type)
2830
2931bool Direction::isPositive(Direction::Type type)
3032{
31− return type == Rightwards || type == Downwards;
33+ return type == Rightwards
34+ || type == Downwards
35+ || type == Horizontal;
3236}
plugins/Ubuntu/Gestures/Direction.h+2−1
@@ -33,7 +33,8 @@ public:
3333 Rightwards, // Along the positive direction of the X axis
3434 Leftwards, // Along the negative direction of the X axis
3535 Downwards, // Along the positive direction of the Y axis
36− Upwards // Along the negative direction of the Y axis
36+ Upwards, // Along the negative direction of the Y axis
37+ Horizontal // Along the X axis, in any direction
3738 };
3839
3940 Q_INVOKABLE static bool isHorizontal(Direction::Type type);
plugins/Ubuntu/Gestures/DirectionalDragArea.cpp+27−37
@@ -36,7 +36,7 @@
3636using namespace UbuntuGestures;
3737
3838#if DIRECTIONALDRAGAREA_DEBUG
39−#define DDA_DEBUG(msg) qDebug("[DDA] " msg)
39+#define ddaDebug(params) qDebug().nospace() << "[DDA(" << qPrintable(objectName()) << ")] " << params
4040#include "DebugHelpers.h"
4141
4242namespace {
@@ -53,7 +53,7 @@ const char *statusToString(DirectionalDragArea::Status status)
5353
5454} // namespace {
5555#else // DIRECTIONALDRAGAREA_DEBUG
56−#define DDA_DEBUG(msg) do{}while(0)
56+#define ddaDebug(params) ((void)0)
5757#endif // DIRECTIONALDRAGAREA_DEBUG
5858
5959
@@ -253,7 +253,7 @@ void DirectionalDragArea::touchOwnershipEvent(TouchOwnershipEvent *event)
253253 if (event->gained()) {
254254 QVector<int> ids;
255255 ids.append(event->touchId());
256− DDA_DEBUG("grabbing touch");
256+ ddaDebug("grabbing touch");
257257 grabTouchPoints(ids);
258258
259259 // Work around for Qt bug. If we grab a touch that is being used for mouse pointer
@@ -265,7 +265,7 @@ void DirectionalDragArea::touchOwnershipEvent(TouchOwnershipEvent *event)
265265 if (window()) {
266266 QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(window());
267267 if (windowPrivate->touchMouseId == event->touchId() && window()->mouseGrabberItem()) {
268− DDA_DEBUG("removing mouse grabber");
268+ ddaDebug("removing mouse grabber");
269269 window()->mouseGrabberItem()->ungrabMouse();
270270 }
271271 }
@@ -283,11 +283,7 @@ void DirectionalDragArea::unownedTouchEvent(UnownedTouchEvent *unownedTouchEvent
283283
284284 Q_ASSERT(!event->touchPointStates().testFlag(Qt::TouchPointPressed));
285285
286− #if DIRECTIONALDRAGAREA_DEBUG
287− // TODO Consider using qCDebug() when available (Qt 5.2)
288− qDebug() << "[DDA] Unowned" << m_timeSource->msecsSinceReference()
289− << qPrintable(touchEventToString(event));
290− #endif
286+ ddaDebug("Unowned " << m_timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event)));
291287
292288 switch (m_status) {
293289 case WaitingForTouch:
@@ -322,7 +318,7 @@ void DirectionalDragArea::unownedTouchEvent_undecided(UnownedTouchEvent *unowned
322318
323319 if (touchPoint->state() == Qt::TouchPointReleased) {
324320 // touch has ended before recognition concluded
325− DDA_DEBUG("Touch has ended before recognition concluded");
321+ ddaDebug("Touch has ended before recognition concluded");
326322 TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this);
327323 emitSignalIfTapped();
328324 setStatus(WaitingForTouch);
@@ -335,7 +331,7 @@ void DirectionalDragArea::unownedTouchEvent_undecided(UnownedTouchEvent *unowned
335331 updateVelocityCalculator(touchScenePos);
336332
337333 if (!pointInsideAllowedArea()) {
338− DDA_DEBUG("Rejecting gesture because touch point is outside allowed area.");
334+ ddaDebug("Rejecting gesture because touch point is outside allowed area.");
339335 TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this);
340336 // We still wanna know when it ends for keeping the composition time window up-to-date
341337 TouchRegistry::instance()->addTouchWatcher(m_touchId, this);
@@ -344,7 +340,7 @@ void DirectionalDragArea::unownedTouchEvent_undecided(UnownedTouchEvent *unowned
344340 }
345341
346342 if (!movingInRightDirection()) {
347− DDA_DEBUG("Rejecting gesture because touch point is moving in the wrong direction.");
343+ ddaDebug("Rejecting gesture because touch point is moving in the wrong direction.");
348344 TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this);
349345 // We still wanna know when it ends for keeping the composition time window up-to-date
350346 TouchRegistry::instance()->addTouchWatcher(m_touchId, this);
@@ -358,7 +354,7 @@ void DirectionalDragArea::unownedTouchEvent_undecided(UnownedTouchEvent *unowned
358354 if (isWithinTouchCompositionWindow()) {
359355 // There's still time for some new touch to appear and ruin our party as it would be combined
360356 // with our m_touchId one and therefore deny the possibility of a single-finger gesture.
361− DDA_DEBUG("Sill within composition window. Let's wait more.");
357+ ddaDebug("Sill within composition window. Let's wait more.");
362358 return;
363359 }
364360
@@ -366,7 +362,7 @@ void DirectionalDragArea::unownedTouchEvent_undecided(UnownedTouchEvent *unowned
366362 TouchRegistry::instance()->requestTouchOwnership(m_touchId, this);
367363 setStatus(Recognized);
368364 } else {
369− DDA_DEBUG("Didn't move far enough yet. Let's wait more.");
365+ ddaDebug("Didn't move far enough yet. Let's wait more.");
370366 }
371367}
372368
@@ -375,11 +371,7 @@ void DirectionalDragArea::touchEvent(QTouchEvent *event)
375371 // TODO: Consider when more than one touch starts in the same event (although it's not possible
376372 // with Mir's android-input). Have to track them all. Consider it a plus/bonus.
377373
378− #if DIRECTIONALDRAGAREA_DEBUG
379− // TODO Consider using qCDebug() when available (Qt 5.2)
380− qDebug() << "[DDA]" << m_timeSource->msecsSinceReference()
381− << qPrintable(touchEventToString(event));
382− #endif
374+ ddaDebug(m_timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event)));
383375
384376 if (!isEnabled() || !isVisible()) {
385377 QQuickItem::touchEvent(event);
@@ -416,9 +408,7 @@ void DirectionalDragArea::touchEvent_absent(QTouchEvent *event)
416408 if (isWithinTouchCompositionWindow()) {
417409 // too close to the last touch start. So we consider them as starting roughly at the same time.
418410 // Can't be a single-touch gesture.
419− #if DIRECTIONALDRAGAREA_DEBUG
420− qDebug("[DDA] A new touch point came in but we're still within time composition window. Ignoring it.");
421− #endif
411+ ddaDebug("A new touch point came in but we're still within time composition window. Ignoring it.");
422412 allGood = false;
423413 }
424414
@@ -456,6 +446,7 @@ void DirectionalDragArea::touchEvent_absent(QTouchEvent *event)
456446
457447 if (recognitionIsDisabled()) {
458448 // Behave like a dumb TouchArea
449+ ddaDebug("Gesture recognition is disabled. Requesting touch ownership immediately.");
459450 TouchRegistry::instance()->requestTouchOwnership(m_touchId, this);
460451 setStatus(Recognized);
461452 event->accept();
@@ -487,7 +478,7 @@ void DirectionalDragArea::touchEvent_undecided(QTouchEvent *event)
487478
488479 if (event->touchPointStates().testFlag(Qt::TouchPointPressed) && isWithinTouchCompositionWindow()) {
489480 // multi-finger drags are not accepted
490− DDA_DEBUG("Multi-finger drags are not accepted");
481+ ddaDebug("Multi-finger drags are not accepted");
491482
492483 TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this);
493484 // We still wanna know when it ends for keeping the composition time window up-to-date
@@ -581,12 +572,16 @@ bool DirectionalDragArea::pointInsideAllowedArea() const
581572
582573bool DirectionalDragArea::movingInRightDirection() const
583574{
584− QPointF movementVector(m_dampedScenePos.x() - m_previousDampedScenePos.x(),
585− m_dampedScenePos.y() - m_previousDampedScenePos.y());
575+ if (m_direction == Direction::Horizontal) {
576+ return true;
577+ } else {
578+ QPointF movementVector(m_dampedScenePos.x() - m_previousDampedScenePos.x(),
579+ m_dampedScenePos.y() - m_previousDampedScenePos.y());
586580
587− qreal scalarProjection = projectOntoDirectionVector(movementVector);
581+ qreal scalarProjection = projectOntoDirectionVector(movementVector);
588582
589− return scalarProjection >= 0.;
583+ return scalarProjection >= 0.;
584+ }
590585}
591586
592587bool DirectionalDragArea::movedFarEnough(const QPointF &point) const
@@ -614,7 +609,7 @@ void DirectionalDragArea::checkSpeed()
614609 qreal minSpeedMsecs = m_minSpeed / 1000.0;
615610
616611 if (speed < minSpeedMsecs) {
617− DDA_DEBUG("Rejecting gesture because it's below minimum speed.");
612+ ddaDebug("Rejecting gesture because it's below minimum speed.");
618613 TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this);
619614 TouchRegistry::instance()->addTouchWatcher(m_touchId, this);
620615 setStatus(WaitingForTouch);
@@ -625,7 +620,7 @@ void DirectionalDragArea::checkSpeed()
625620 m_silenceTime += m_recognitionTimer->interval();
626621
627622 if (m_silenceTime > m_maxSilenceTime) {
628− DDA_DEBUG("Rejecting gesture because its silence time has been exceeded.");
623+ ddaDebug("Rejecting gesture because its silence time has been exceeded.");
629624 TouchRegistry::instance()->removeCandidateOwnerForTouch(m_touchId, this);
630625 TouchRegistry::instance()->addTouchWatcher(m_touchId, this);
631626 setStatus(WaitingForTouch);
@@ -646,7 +641,7 @@ void DirectionalDragArea::giveUpIfDisabledOrInvisible()
646641 }
647642
648643 if (m_status != WaitingForTouch) {
649− DDA_DEBUG("Resetting status because got disabled or made invisible");
644+ ddaDebug("Resetting status because got disabled or made invisible");
650645 setStatus(WaitingForTouch);
651646 }
652647 }
@@ -666,9 +661,7 @@ void DirectionalDragArea::setStatus(DirectionalDragArea::Status newStatus)
666661 m_status = newStatus;
667662 Q_EMIT statusChanged(m_status);
668663
669− #if DIRECTIONALDRAGAREA_DEBUG
670− qDebug() << "[DDA]" << statusToString(oldStatus) << "->" << statusToString(newStatus);
671− #endif
664+ ddaDebug(statusToString(oldStatus) << " -> " << statusToString(newStatus));
672665
673666 switch (newStatus) {
674667 case WaitingForTouch:
@@ -875,7 +868,7 @@ void DirectionalDragArea::updateSceneDirectionVector()
875868 localDirection.rx() = -1.;
876869 localDirection.ry() = 0.;
877870 break;
878− default: // Direction::Rightwards:
871+ default: // Direction::Rightwards || Direction.Horizontal
879872 localDirection.rx() = 1.;
880873 localDirection.ry() = 0.;
881874 break;
@@ -891,6 +884,3 @@ qreal DirectionalDragArea::projectOntoDirectionVector(const QPointF &sceneVector
891884 return sceneVector.x() * m_sceneDirectionVector.x() +
892885 sceneVector.y() * m_sceneDirectionVector.y();
893886}
894−
895−// Because we are defining a new QObject-based class (RecognitionTimer) here.
896−#include "DirectionalDragArea.moc"
plugins/Unity/Session/dbusunitysessionservice.h+5
@@ -35,6 +35,11 @@ public:
3535 DBusUnitySessionService();
3636 ~DBusUnitySessionService();
3737
38+ // For use in QML. Javascript doesn't accept functions beginning with capital letters
39+ Q_INVOKABLE void logout() { Logout(); }
40+ Q_INVOKABLE void reboot() { Reboot(); }
41+ Q_INVOKABLE void shutdown() { Shutdown(); }
42+
3843Q_SIGNALS:
3944 /**
4045 * logoutRequested signal
po/br.po+45−37
@@ -8,14 +8,14 @@ msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2014-12-10 10:55+0100\n"
11−"PO-Revision-Date: 2014-12-10 07:14+0000\n"
11+"PO-Revision-Date: 2014-12-16 07:27+0000\n"
1212"Last-Translator: Fohanno Thierry <thierry.fohanno@ofis-bzh.org>\n"
1313"Language-Team: Breton <br@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2014-12-13 07:11+0000\n"
18+"X-Launchpad-Export-Date: 2014-12-16 07:34+0000\n"
1919"X-Generator: Launchpad (build 17286)\n"
2020
2121#: plugins/LightDM/Greeter.cpp:130
@@ -358,98 +358,100 @@ msgstr ""
358358
359359#: qml/Wizard/Page.qml:89
360360msgid "Back"
361−msgstr ""
361+msgstr "Distreiñ"
362362
363363#: qml/Wizard/Pages/10-welcome.qml:27
364364msgid "Hi!"
365−msgstr ""
365+msgstr "Salud deoc'h !"
366366
367367#: qml/Wizard/Pages/10-welcome.qml:44
368368msgid "Welcome to your Ubuntu phone."
369−msgstr ""
369+msgstr "Deuet-mat oc'h en ho pellgomzer Ubuntu."
370370
371371#: qml/Wizard/Pages/10-welcome.qml:52
372372msgid "Let’s get started."
373−msgstr ""
373+msgstr "Krogomp ganti."
374374
375375#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
376376#: qml/Wizard/Pages/40-wifi.qml:197 qml/Wizard/Pages/50-location.qml:131
377377#: qml/Wizard/Pages/60-reporting.qml:50 qml/Wizard/Pages/passwd-confirm.qml:82
378378#: qml/Wizard/Pages/passwd-set.qml:90
379379msgid "Continue"
380−msgstr ""
380+msgstr "Kenderc'hel"
381381
382382#: qml/Wizard/Pages/20-sim.qml:25
383383msgid "Add a SIM card and restart your device"
384−msgstr ""
384+msgstr "Lakait ur gartenn SIM hag adloc'hit ho penveg"
385385
386386#: qml/Wizard/Pages/20-sim.qml:55
387387msgid "Without it, you won’t be able to make calls or use text messaging."
388−msgstr ""
388+msgstr "Ne vioc'h ket evit pellgomz pe kas kemennadennoù hepti."
389389
390390#: qml/Wizard/Pages/20-sim.qml:69 qml/Wizard/Pages/40-wifi.qml:197
391391msgid "Skip"
392−msgstr ""
392+msgstr "Tremen hebiou"
393393
394394#: qml/Wizard/Pages/30-passwd-type.qml:39
395395msgid "Lock security"
396−msgstr ""
396+msgstr "Surentez ar prennañ"
397397
398398#: qml/Wizard/Pages/30-passwd-type.qml:74
399399msgid "Please select how you’d like to unlock your phone."
400400msgstr ""
401+"Diuzit e peseurt mod e fell deoc'h dibrennañ ho pellgomzer, mar plij."
401402
402403#: qml/Wizard/Pages/30-passwd-type.qml:97
403404msgid "Swipe"
404−msgstr ""
405+msgstr "Riklañ"
405406
406407#: qml/Wizard/Pages/30-passwd-type.qml:98
407408msgid "No security"
408−msgstr ""
409+msgstr "Tamm surentez ebet"
409410
410411#: qml/Wizard/Pages/30-passwd-type.qml:100
411412msgid "Passcode"
412−msgstr ""
413+msgstr "Kod-tremen"
413414
414415#: qml/Wizard/Pages/30-passwd-type.qml:101
415416msgid "4 digits only"
416−msgstr ""
417+msgstr "4 sifr hepken"
417418
418419#: qml/Wizard/Pages/30-passwd-type.qml:103
419420msgid "Passphrase"
420−msgstr ""
421+msgstr "Frazenn-dremen"
421422
422423#: qml/Wizard/Pages/30-passwd-type.qml:104
423424msgid "Numbers and letters"
424−msgstr ""
425+msgstr "Sifroù ha lizherennoù"
425426
426427#: qml/Wizard/Pages/40-wifi.qml:28
427428msgid "Connect to Wi‑Fi"
428−msgstr ""
429+msgstr "Kevreañ ouzh ar Wi-Fi"
429430
430431#: qml/Wizard/Pages/40-wifi.qml:147
431432msgid "Available networks…"
432−msgstr ""
433+msgstr "Rouedadoù a c'haller kaout..."
433434
434435#: qml/Wizard/Pages/40-wifi.qml:148
435436msgid "No available networks."
436−msgstr ""
437+msgstr "N'eus rouedad ebet da gaout."
437438
438439#: qml/Wizard/Pages/50-location.qml:27
439440msgid "Location"
440−msgstr ""
441+msgstr "Lec'h"
441442
442443#: qml/Wizard/Pages/50-location.qml:62
443444msgid "Let the phone detect your location:"
444−msgstr ""
445+msgstr "Lezel ar pellgomzer da gavout pelec'h emaoc'h :"
445446
446447#: qml/Wizard/Pages/50-location.qml:69
447448msgid "Using GPS only (less accurate)"
448−msgstr ""
449+msgstr "Implijout ar GPS hepken (n'eo ket ken resis)"
449450
450451#: qml/Wizard/Pages/50-location.qml:86
451452msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
452453msgstr ""
454+"Implijout ar GPS, Wi-Fi dizanv pe titouroù ar rouedad kelligel (aliet)"
453455
454456#. TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
455457#: qml/Wizard/Pages/50-location.qml:103
@@ -457,81 +459,87 @@ msgid ""
457459"By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
458460"conditions</a>."
459461msgstr ""
462+"Pa ziuzit an dibarzh-mañ ez asantit da <a href='#'>zivizoù implij</a> Nokia."
460463
461464#: qml/Wizard/Pages/50-location.qml:112
462465msgid "Not at all"
463−msgstr ""
466+msgstr "Tamm ebet"
464467
465468#: qml/Wizard/Pages/50-location.qml:124
466469msgid "You can change your mind later in <b>System Settings</b>."
467470msgstr ""
471+"Gallout a rit cheñch soñj diwezhatoc'h en <b>Arventennoù ar reizhad</b>."
468472
469473#: qml/Wizard/Pages/60-reporting.qml:24
470474msgid "Improving your experience"
471−msgstr ""
475+msgstr "Gwellaat ho skiant-prenet"
472476
473477#: qml/Wizard/Pages/60-reporting.qml:36
474478msgid ""
475479"Your phone is set up to automatically report errors to Canonical and its "
476480"partners, the makers of the operating system."
477481msgstr ""
482+"Arventennet eo ho pellgomzer evit titourañ ent emgefre ar fazioù da "
483+"gCanonical ha d'e gevelerien, ar re o deus savet ar reizhiad korvoiñ."
478484
479485#: qml/Wizard/Pages/60-reporting.qml:43
480486msgid ""
481487"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
482488"Privacy</b>"
483489msgstr ""
490+"Gallout a ra bezañ diweredekaet e-barzh <b>Arventennoù ar reizhiad</b> "
491+"dindan <b>Surentez &amp; Prevezded</b>"
484492
485493#: qml/Wizard/Pages/80-finished.qml:24
486494msgid "All done"
487−msgstr ""
495+msgstr "Echu penn-da-benn"
488496
489497#: qml/Wizard/Pages/80-finished.qml:39
490498msgid "Nice work!"
491−msgstr ""
499+msgstr "Gwellat labour !"
492500
493501#: qml/Wizard/Pages/80-finished.qml:46
494502msgid "Your phone is now ready to use."
495−msgstr ""
503+msgstr "Prest eo ho pellgomzer da vezañ implijet bremañ."
496504
497505#: qml/Wizard/Pages/80-finished.qml:53
498506msgid "Finish"
499−msgstr ""
507+msgstr "Echuiñ"
500508
501509#: qml/Wizard/Pages/here-terms.qml:27
502510msgid "Terms & Conditions"
503−msgstr ""
511+msgstr "Penndivizoù implij"
504512
505513#: qml/Wizard/Pages/passwd-confirm.qml:49
506514msgid "Confirm passphrase"
507−msgstr ""
515+msgstr "Kadarnaat ar frazenn-dremen"
508516
509517#: qml/Wizard/Pages/passwd-confirm.qml:50
510518msgid "Confirm passcode"
511−msgstr ""
519+msgstr "Kadarnaat ar c'hod-tremen"
512520
513521#: qml/Wizard/Pages/passwd-confirm.qml:53
514522#: qml/Wizard/Pages/passwd-confirm.qml:54
515523msgid "Please try again."
516−msgstr ""
524+msgstr "Esaeit en-dro, mar plij."
517525
518526#: qml/Wizard/Pages/passwd-set.qml:61
519527msgid "Choose your passcode"
520−msgstr ""
528+msgstr "Choaz ho kod-tremen"
521529
522530#: qml/Wizard/Pages/passwd-set.qml:68
523531msgid "Passphrase must be 4 characters long"
524−msgstr ""
532+msgstr "4 arouezenn a rank bezañ er frazenn-dremen"
525533
526534#: qml/Wizard/StackButton.qml:39
527535#, qt-format
528536msgid "〈 %1"
529−msgstr ""
537+msgstr "〈 %1"
530538
531539#: qml/Wizard/StackButton.qml:42
532540#, qt-format
533541msgid "%1 〉"
534−msgstr ""
542+msgstr "%1 〉"
535543
536544#~ msgid "Loading. Please Wait..."
537545#~ msgstr "O kargañ. Gortozit, mar plij..."
po/hu.po+47−39
@@ -8,14 +8,14 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2014-12-10 10:55+0100\n"
11−"PO-Revision-Date: 2014-11-05 15:45+0000\n"
11+"PO-Revision-Date: 2014-12-15 15:26+0000\n"
1212"Last-Translator: Richard Somlói <ricsipontaz@gmail.com>\n"
1313"Language-Team: Hungarian <hu@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-12-13 07:11+0000\n"
18+"X-Launchpad-Export-Date: 2014-12-16 07:34+0000\n"
1919"X-Generator: Launchpad (build 17286)\n"
2020
2121#: plugins/LightDM/Greeter.cpp:130
@@ -237,7 +237,7 @@ msgstr ""
237237
238238#: qml/Dash/ScopesList.qml:108
239239msgid "Also installed"
240−msgstr ""
240+msgstr "Szintén telepítve"
241241
242242#: qml/Greeter/Greeter.qml:174
243243msgid "Unlock"
@@ -351,98 +351,100 @@ msgstr ""
351351
352352#: qml/Wizard/Page.qml:89
353353msgid "Back"
354−msgstr ""
354+msgstr "Vissza"
355355
356356#: qml/Wizard/Pages/10-welcome.qml:27
357357msgid "Hi!"
358−msgstr ""
358+msgstr "Üdv!"
359359
360360#: qml/Wizard/Pages/10-welcome.qml:44
361361msgid "Welcome to your Ubuntu phone."
362−msgstr ""
362+msgstr "Üdvözöljük az Ubuntu telefonos változatában."
363363
364364#: qml/Wizard/Pages/10-welcome.qml:52
365365msgid "Let’s get started."
366−msgstr ""
366+msgstr "Kezdjünk is bele."
367367
368368#: qml/Wizard/Pages/10-welcome.qml:88 qml/Wizard/Pages/30-passwd-type.qml:128
369369#: qml/Wizard/Pages/40-wifi.qml:197 qml/Wizard/Pages/50-location.qml:131
370370#: qml/Wizard/Pages/60-reporting.qml:50 qml/Wizard/Pages/passwd-confirm.qml:82
371371#: qml/Wizard/Pages/passwd-set.qml:90
372372msgid "Continue"
373−msgstr ""
373+msgstr "Folytatás"
374374
375375#: qml/Wizard/Pages/20-sim.qml:25
376376msgid "Add a SIM card and restart your device"
377−msgstr ""
377+msgstr "Helyezzen be egy SIM kártyát és indítsa újra az eszközét"
378378
379379#: qml/Wizard/Pages/20-sim.qml:55
380380msgid "Without it, you won’t be able to make calls or use text messaging."
381381msgstr ""
382+"Anélkül nem indíthat vagy fogadhat hívásokat és nem küldhet vagy fogadhat "
383+"üzeneteket."
382384
383385#: qml/Wizard/Pages/20-sim.qml:69 qml/Wizard/Pages/40-wifi.qml:197
384386msgid "Skip"
385−msgstr ""
387+msgstr "Kihagyás"
386388
387389#: qml/Wizard/Pages/30-passwd-type.qml:39
388390msgid "Lock security"
389−msgstr ""
391+msgstr "Képernyőzárolás"
390392
391393#: qml/Wizard/Pages/30-passwd-type.qml:74
392394msgid "Please select how you’d like to unlock your phone."
393−msgstr ""
395+msgstr "Válassza ki, hogy milyen módon kívánja feloldani a telefonját."
394396
395397#: qml/Wizard/Pages/30-passwd-type.qml:97
396398msgid "Swipe"
397−msgstr ""
399+msgstr "Csúsztatás"
398400
399401#: qml/Wizard/Pages/30-passwd-type.qml:98
400402msgid "No security"
401−msgstr ""
403+msgstr "Nem biztonságos"
402404
403405#: qml/Wizard/Pages/30-passwd-type.qml:100
404406msgid "Passcode"
405−msgstr ""
407+msgstr "Jelkód"
406408
407409#: qml/Wizard/Pages/30-passwd-type.qml:101
408410msgid "4 digits only"
409−msgstr ""
411+msgstr "4 számjegy"
410412
411413#: qml/Wizard/Pages/30-passwd-type.qml:103
412414msgid "Passphrase"
413−msgstr ""
415+msgstr "Jelmondat"
414416
415417#: qml/Wizard/Pages/30-passwd-type.qml:104
416418msgid "Numbers and letters"
417−msgstr ""
419+msgstr "Betűk és számok"
418420
419421#: qml/Wizard/Pages/40-wifi.qml:28
420422msgid "Connect to Wi‑Fi"
421−msgstr ""
423+msgstr "Csatlakozás Wi-Fi hálózathoz"
422424
423425#: qml/Wizard/Pages/40-wifi.qml:147
424426msgid "Available networks…"
425−msgstr ""
427+msgstr "Elérhető hálózatok…"
426428
427429#: qml/Wizard/Pages/40-wifi.qml:148
428430msgid "No available networks."
429−msgstr ""
431+msgstr "Nincsenek elérhető hálózatok."
430432
431433#: qml/Wizard/Pages/50-location.qml:27
432434msgid "Location"
433−msgstr ""
435+msgstr "Tartózkodási hely"
434436
435437#: qml/Wizard/Pages/50-location.qml:62
436438msgid "Let the phone detect your location:"
437−msgstr ""
439+msgstr "A telefon megpróbálja megállapítani az Ön tartózkodási helyét:"
438440
439441#: qml/Wizard/Pages/50-location.qml:69
440442msgid "Using GPS only (less accurate)"
441−msgstr ""
443+msgstr "Csak GPS használata (kevésbé pontos)"
442444
443445#: qml/Wizard/Pages/50-location.qml:86
444446msgid "Using GPS, anonymized Wi-Fi and cellular network info (recommended)"
445−msgstr ""
447+msgstr "GPS és névtelen Wi-Fi és mobilhálózati adatok (ajánlott)"
446448
447449#. TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
448450#: qml/Wizard/Pages/50-location.qml:103
@@ -450,6 +452,8 @@ msgid ""
450452"By selecting this option you agree to the Nokia HERE <a href='#'>terms and "
451453"conditions</a>."
452454msgstr ""
455+"A lehetőség kiválasztásával elfogadja a Nokia HERE <a href='#'>felhasználási "
456+"feltételeit</a>."
453457
454458#: qml/Wizard/Pages/50-location.qml:112
455459msgid "Not at all"
@@ -457,74 +461,78 @@ msgstr ""
457461
458462#: qml/Wizard/Pages/50-location.qml:124
459463msgid "You can change your mind later in <b>System Settings</b>."
460−msgstr ""
464+msgstr "Ezt később a <b>Rendszerbeállítások</b> alatt módosíthatja."
461465
462466#: qml/Wizard/Pages/60-reporting.qml:24
463467msgid "Improving your experience"
464−msgstr ""
468+msgstr "Javítson az élményen"
465469
466470#: qml/Wizard/Pages/60-reporting.qml:36
467471msgid ""
468472"Your phone is set up to automatically report errors to Canonical and its "
469473"partners, the makers of the operating system."
470474msgstr ""
475+"A telefonja automatikus hibajelentéseket küld az operációs rendszert készítő "
476+"Canonical, és annak partnerei felé."
471477
472478#: qml/Wizard/Pages/60-reporting.qml:43
473479msgid ""
474480"This can be disabled in <b>System Settings</b> under <b>Security &amp; "
475481"Privacy</b>"
476482msgstr ""
483+"Ezt kikapcsolhatja a <b>Rendszerbeállítások</b> alatt található <b>Biztonság "
484+"és adatvédelem</b> alatt"
477485
478486#: qml/Wizard/Pages/80-finished.qml:24
479487msgid "All done"
480−msgstr ""
488+msgstr "Készen van"
481489
482490#: qml/Wizard/Pages/80-finished.qml:39
483491msgid "Nice work!"
484−msgstr ""
492+msgstr "Szép munka!"
485493
486494#: qml/Wizard/Pages/80-finished.qml:46
487495msgid "Your phone is now ready to use."
488−msgstr ""
496+msgstr "A telefonja készen áll a használatra."
489497
490498#: qml/Wizard/Pages/80-finished.qml:53
491499msgid "Finish"
492−msgstr ""
500+msgstr "Befejezés"
493501
494502#: qml/Wizard/Pages/here-terms.qml:27
495503msgid "Terms & Conditions"
496−msgstr ""
504+msgstr "Felhasználási feltételek"
497505
498506#: qml/Wizard/Pages/passwd-confirm.qml:49
499507msgid "Confirm passphrase"
500−msgstr ""
508+msgstr "Jelmondat megerősítése"
501509
502510#: qml/Wizard/Pages/passwd-confirm.qml:50
503511msgid "Confirm passcode"
504−msgstr ""
512+msgstr "Jelkód megerősítése"
505513
506514#: qml/Wizard/Pages/passwd-confirm.qml:53
507515#: qml/Wizard/Pages/passwd-confirm.qml:54
508516msgid "Please try again."
509−msgstr ""
517+msgstr "Próbálja újra."
510518
511519#: qml/Wizard/Pages/passwd-set.qml:61
512520msgid "Choose your passcode"
513−msgstr ""
521+msgstr "Jelkód kiválasztása"
514522
515523#: qml/Wizard/Pages/passwd-set.qml:68
516524msgid "Passphrase must be 4 characters long"
517−msgstr ""
525+msgstr "A jelmondat legalább 4 karakter hosszú legyen"
518526
519527#: qml/Wizard/StackButton.qml:39
520528#, qt-format
521529msgid "〈 %1"
522−msgstr ""
530+msgstr "〈 %1"
523531
524532#: qml/Wizard/StackButton.qml:42
525533#, qt-format
526534msgid "%1 〉"
527−msgstr ""
535+msgstr "%1 〉"
528536
529537#~ msgid "Confirm"
530538#~ msgstr "Megerősítés"
qml/Components/Dialogs.qml+61−67
@@ -19,11 +19,22 @@ import QtQuick 2.0
1919import Unity.Application 0.1
2020import Unity.Session 0.1
2121import Ubuntu.Components 1.1
22−import Ubuntu.Components.Popups 0.1
2322
2423Item {
2524 id: root
2625
26+ // to be set from outside, useful mostly for testing purposes
27+ property var unitySessionService: DBusUnitySessionService
28+ property var closeAllApps: function() {
29+ while (true) {
30+ var app = ApplicationManager.get(0);
31+ if (app === null) {
32+ break;
33+ }
34+ ApplicationManager.stopApplication(app.appId);
35+ }
36+ }
37+
2738 function onPowerKeyPressed() {
2839 // FIXME: event.isAutoRepeat is always false on Nexus 4.
2940 // So we use powerKeyTimer.running to avoid the PowerOff key repeat
@@ -41,16 +52,21 @@ Item {
4152
4253 QtObject {
4354 id: d // private stuff
55+ objectName: "dialogsPrivate"
4456
45− property bool dialogShown: false
4657
4758 function showPowerDialog() {
48− if (!d.dialogShown) {
49− d.dialogShown = true;
50− PopupUtils.open(powerDialog, root, {"z": root.z});
59+ if (!dialogLoader.active) {
60+ dialogLoader.sourceComponent = powerDialogComponent;
61+ dialogLoader.active = true;
5162 }
5263 }
5364 }
65+ Loader {
66+ id: dialogLoader
67+ anchors.fill: parent
68+ active: false
69+ }
5470
5571 Timer {
5672 id: powerKeyTimer
@@ -64,91 +80,84 @@ Item {
6480 }
6581
6682 Component {
67− id: logoutDialog
68− Dialog {
69− id: dialogueLogout
83+ id: logoutDialogComponent
84+ ShellDialog {
85+ id: logoutDialog
7086 title: i18n.tr("Log out")
7187 text: i18n.tr("Are you sure you want to log out?")
7288 Button {
7389 text: i18n.tr("No")
7490 onClicked: {
75− PopupUtils.close(dialogueLogout);
76− d.dialogShown = false;
91+ logoutDialog.hide();
7792 }
7893 }
7994 Button {
8095 text: i18n.tr("Yes")
8196 onClicked: {
82− DBusUnitySessionService.Logout();
83− PopupUtils.close(dialogueLogout);
84− d.dialogShown = false;
97+ unitySessionService.logout();
98+ logoutDialog.hide();
8599 }
86100 }
87101 }
88102 }
89103
90104 Component {
91− id: shutdownDialog
92− Dialog {
93− id: dialogueShutdown
105+ id: shutdownDialogComponent
106+ ShellDialog {
107+ id: shutdownDialog
94108 title: i18n.tr("Shut down")
95109 text: i18n.tr("Are you sure you want to shut down?")
96110 Button {
97111 text: i18n.tr("No")
98112 onClicked: {
99− PopupUtils.close(dialogueShutdown);
100− d.dialogShown = false;
113+ shutdownDialog.hide();
101114 }
102115 }
103116 Button {
104117 text: i18n.tr("Yes")
105118 onClicked: {
106− dBusUnitySessionServiceConnection.closeAllApps();
107− DBusUnitySessionService.Shutdown();
108− PopupUtils.close(dialogueShutdown);
109− d.dialogShown = false;
119+ root.closeAllApps();
120+ unitySessionService.shutdown();
121+ shutdownDialog.hide();
110122 }
111123 }
112124 }
113125 }
114126
115127 Component {
116− id: rebootDialog
117− Dialog {
118− id: dialogueReboot
128+ id: rebootDialogComponent
129+ ShellDialog {
130+ id: rebootDialog
119131 title: i18n.tr("Reboot")
120132 text: i18n.tr("Are you sure you want to reboot?")
121133 Button {
122134 text: i18n.tr("No")
123135 onClicked: {
124− PopupUtils.close(dialogueReboot)
125− d.dialogShown = false;
136+ rebootDialog.hide();
126137 }
127138 }
128139 Button {
129140 text: i18n.tr("Yes")
130141 onClicked: {
131− dBusUnitySessionServiceConnection.closeAllApps();
132− DBusUnitySessionService.Reboot();
133− PopupUtils.close(dialogueReboot);
134− d.dialogShown = false;
142+ root.closeAllApps();
143+ unitySessionService.reboot();
144+ rebootDialog.hide();
135145 }
136146 }
137147 }
138148 }
139149
140150 Component {
141− id: powerDialog
142− Dialog {
143− id: dialoguePower
151+ id: powerDialogComponent
152+ ShellDialog {
153+ id: powerDialog
144154 title: i18n.tr("Power")
145155 text: i18n.tr("Are you sure you would like\nto power off?")
146156 Button {
147157 text: i18n.tr("Power off")
148158 onClicked: {
149− dBusUnitySessionServiceConnection.closeAllApps();
150− PopupUtils.close(dialoguePower);
151− d.dialogShown = false;
159+ root.closeAllApps();
160+ powerDialog.hide();
152161 root.powerOffClicked();
153162 }
154163 color: UbuntuColors.red
@@ -156,66 +165,51 @@ Item {
156165 Button {
157166 text: i18n.tr("Restart")
158167 onClicked: {
159− dBusUnitySessionServiceConnection.closeAllApps();
160− DBusUnitySessionService.Reboot();
161− PopupUtils.close(dialoguePower);
162− d.dialogShown = false;
168+ root.closeAllApps();
169+ unitySessionService.reboot();
170+ powerDialog.hide();
163171 }
164172 color: UbuntuColors.green
165173 }
166174 Button {
167175 text: i18n.tr("Cancel")
168176 onClicked: {
169− PopupUtils.close(dialoguePower);
170− d.dialogShown = false;
177+ powerDialog.hide();
171178 }
172179 color: UbuntuColors.coolGrey
173180 }
174181 }
175182 }
176183
177−
178184 Connections {
179− id: dBusUnitySessionServiceConnection
180− objectName: "dBusUnitySessionServiceConnection"
181− target: DBusUnitySessionService
182−
183− function closeAllApps() {
184− while (true) {
185− var app = ApplicationManager.get(0);
186− if (app === null) {
187− break;
188− }
189− ApplicationManager.stopApplication(app.appId);
190− }
191− }
185+ target: root.unitySessionService
192186
193187 onLogoutRequested: {
194188 // Display a dialog to ask the user to confirm.
195− if (!d.dialogShown) {
196− d.dialogShown = true;
197− PopupUtils.open(logoutDialog, root, {"z": root.z});
189+ if (!dialogLoader.active) {
190+ dialogLoader.sourceComponent = logoutDialogComponent;
191+ dialogLoader.active = true;
198192 }
199193 }
200194
201195 onShutdownRequested: {
202196 // Display a dialog to ask the user to confirm.
203− if (!d.dialogShown) {
204− d.dialogShown = true;
205− PopupUtils.open(shutdownDialog, root, {"z": root.z});
197+ if (!dialogLoader.active) {
198+ dialogLoader.sourceComponent = shutdownDialogComponent;
199+ dialogLoader.active = true;
206200 }
207201 }
208202
209203 onRebootRequested: {
210204 // Display a dialog to ask the user to confirm.
211− if (!d.dialogShown) {
212− d.dialogShown = true;
213− PopupUtils.open(rebootDialog, root, {"z": root.z});
205+ if (!dialogLoader.active) {
206+ dialogLoader.sourceComponent = rebootDialogComponent;
207+ dialogLoader.active = true;
214208 }
215209 }
216210
217211 onLogoutReady: {
218− closeAllApps();
212+ root.closeAllApps();
219213 Qt.quit();
220214 }
221215 }
qml/Components/DragHandle.qml+10−2
@@ -100,8 +100,16 @@ EdgeDragArea {
100100 id: d
101101 property var previousStatus: DirectionalDragArea.WaitingForTouch
102102 property real startValue
103− property real minValue: Direction.isPositive(direction) ? startValue
104− : startValue - maxTotalDragDistance
103+ property real minValue: {
104+ if (direction == Direction.Horizontal) {
105+ return startValue - maxTotalDragDistance;
106+ } else if (Direction.isPositive(direction)) {
107+ return startValue;
108+ } else {
109+ return startValue - maxTotalDragDistance;
110+ }
111+ }
112+
105113 property real maxValue: Direction.isPositive(direction) ? startValue + maxTotalDragDistance
106114 : startValue
107115
qml/Components/EdgeDragEvaluator.qml+11−5
@@ -53,20 +53,26 @@ AxisVelocityCalculator {
5353 // Returns whether the drag should continue by itself until completed.
5454 function shouldAutoComplete() {
5555 var deltaPos = trackedPosition - __startPosition;
56+
5657 if (Math.abs(deltaPos) < minDragDistance) {
5758 velocity = 0;
5859 minVelocity = 0;
5960 return false;
6061 }
6162
62− minVelocity = __calculateMinimumVelocityForAutoCompletion(deltaPos);
6363 velocity = calculate();
6464
65− if (Direction.isPositive(direction) && (velocity >= minVelocity)
66− || !Direction.isPositive(direction) && (velocity <= minVelocity)) {
67− return true;
65+ if (direction == Direction.Horizontal) {
66+ minVelocity = __calculateMinimumVelocityForAutoCompletion(Math.abs(deltaPos));
67+ return Math.abs(velocity) >= minVelocity;
6868 } else {
69− return false;
69+ minVelocity = __calculateMinimumVelocityForAutoCompletion(deltaPos);
70+ if (Direction.isPositive(direction) && (velocity >= minVelocity)
71+ || !Direction.isPositive(direction) && (velocity <= minVelocity)) {
72+ return true;
73+ } else {
74+ return false;
75+ }
7076 }
7177 }
7278
qml/Components/ResponsiveVerticalJournal.qml+1
@@ -45,6 +45,7 @@ Item {
4545 property alias rowSpacing: verticalJournalView.rowSpacing
4646 property alias model: verticalJournalView.model
4747 property alias delegate: verticalJournalView.delegate
48+ property alias cacheBuffer: verticalJournalView.cacheBuffer
4849 property alias displayMarginBeginning: verticalJournalView.displayMarginBeginning
4950 property alias displayMarginEnd: verticalJournalView.displayMarginEnd
5051
qml/Components/ShellDialog.qmlnew file+37
@@ -0,0 +1,37 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+
19+import Ubuntu.Components 1.1
20+import Ubuntu.Components.Popups 0.1
21+
22+/*
23+ A Dialog configured for use as a proper in-scene Dialog
24+
25+ This is a helper component for Dialogs.qml, thus some assumptions
26+ on context are (or will be) made here.
27+ */
28+Dialog {
29+ automaticOrientation: false
30+
31+ // NB: PopupBase, Dialog's superclass, will check for the existence of this property
32+ property bool reparentToRootItem: false
33+
34+ onVisibleChanged: { if (!visible) { dialogLoader.active = false; } }
35+
36+ Component.onCompleted: show()
37+}
qml/Components/Showable.qml+13
@@ -99,10 +99,23 @@ Item {
9999 return true;
100100 }
101101
102+ /*
103+ Will be called right before starting the hideAnimation.
104+ */
105+ property var prepareToHide: function(){}
106+
102107 function hide() {
103108 if (showAnimation != undefined && showAnimation.running) {
104109 showAnimation.stop()
105110 }
111+
112+ if (typeof prepareToHide === "function") {
113+ prepareToHide();
114+ } else {
115+ console.warn("Showable.prepareToHide should be a function, but it's a " +
116+ (typeof prepareToHide) + " instead");
117+ }
118+
106119 if (hideAnimation != undefined) {
107120 if (!hideAnimation.running) {
108121 hideAnimation.restart()
qml/Dash/CardGrid.qml+1−2
@@ -50,7 +50,7 @@ DashRenderer {
5050 model: root.model
5151 displayMarginBeginning: root.displayMarginBeginning
5252 displayMarginEnd: root.displayMarginEnd
53− cacheBuffer: 0
53+ cacheBuffer: root.cacheBuffer
5454 interactive: false
5555 delegate: Item {
5656 width: grid.cellWidth
@@ -59,7 +59,6 @@ DashRenderer {
5959 id: loader
6060 sourceComponent: cardTool.cardComponent
6161 anchors.horizontalCenter: parent.horizontalCenter
62− asynchronous: true
6362 onLoaded: {
6463 item.objectName = "delegate" + index;
6564 item.width = Qt.binding(function() { return cardTool.cardWidth; });
qml/Dash/CardVerticalJournal.qml+1
@@ -59,6 +59,7 @@ DashRenderer {
5959 rowSpacing: minimumColumnSpacing
6060 columnWidth: cardTool.cardWidth
6161
62+ cacheBuffer: root.cacheBuffer
6263 displayMarginBeginning: root.displayMarginBeginning
6364 displayMarginEnd: root.displayMarginEnd
6465
qml/Dash/Dash.qml+1
@@ -75,6 +75,7 @@ Showable {
7575 return
7676 }
7777
78+ dashContent.workaroundRestoreIndex = -1;
7879 dashContent.setCurrentScopeAtIndex(scopeIndex, animate, reset)
7980 }
8081
qml/Dash/DashContent.qml+2
@@ -163,6 +163,7 @@ Item {
163163
164164 delegate:
165165 Loader {
166+ id: loader
166167 width: ListView.view.width
167168 height: ListView.view.height
168169 opacity: { // hide delegate if offscreen
@@ -191,6 +192,7 @@ Item {
191192 dashContent.scopeLoaded(item.scope.id)
192193 item.paginationCount = Qt.binding(function() { return dashContentList.count } )
193194 item.paginationIndex = Qt.binding(function() { return dashContentList.currentIndex } )
195+ item.visibleToParent = Qt.binding(function() { return loader.opacity != 0 });
194196 item.holdingList = dashContentList;
195197 item.forceNonInteractive = Qt.binding(function() { return dashContent.forceNonInteractive } )
196198 }
qml/Dash/DashRenderer.qml+2
@@ -23,6 +23,8 @@ Item {
2323
2424 property int collapsedItemCount: -1
2525
26+ property int cacheBuffer: 0
27+
2628 property int displayMarginBeginning: 0
2729
2830 property int displayMarginEnd: 0
qml/Dash/GenericScopeView.qml+46−20
@@ -38,6 +38,7 @@ FocusScope {
3838 readonly property alias subPageShown: subPageLoader.subPageShown
3939 property int paginationCount: 0
4040 property int paginationIndex: 0
41+ property bool visibleToParent: false
4142 property alias pageHeaderTotallyVisible: categoryView.pageHeaderTotallyVisible
4243 property var holdingList: null
4344
@@ -357,6 +358,7 @@ FocusScope {
357358 Connections {
358359 target: scopeView
359360 onIsCurrentChanged: rendererLoader.updateRanges();
361+ onVisibleToParentChanged: rendererLoader.updateRanges();
360362 }
361363 Connections {
362364 target: holdingList
@@ -364,7 +366,9 @@ FocusScope {
364366 }
365367
366368 function updateRanges() {
367− if (holdingList && holdingList.moving) {
369+ // Don't want to create stress by requesting more items during scope
370+ // changes so unless you're not part of the visible scopes just return
371+ if (holdingList && holdingList.moving && !scopeView.visibleToParent) {
368372 return;
369373 }
370374
@@ -380,28 +384,50 @@ FocusScope {
380384 }
381385
382386 if (item && item.hasOwnProperty("displayMarginBeginning")) {
383− // A item view is considered visible from
387+ // A item view creates its delegates synchronously from
384388 // -displayMarginBeginning
385389 // to
386− // height + item.displayMarginEnd
390+ // height + displayMarginEnd
391+ // Around that area it adds the cacheBuffer area where delegates are created async
392+ //
387393 // We adjust displayMarginBeginning and displayMarginEnd so
388− // * In non visible scopes only the viewport is considered visible
389− // that way when you switch to it the visible items are there
390− // * For visible scopes we increase the visible range by categoryView.height * 1.5
391− // in both directions to make scrolling nicer by mantaining a higher number of
394+ // * In non visible scopes nothing is considered visible and we set cacheBuffer
395+ // so that creates the items that would be in the viewport asynchronously
396+ // * For the current scope set the visible range to the viewport and then
397+ // use cacheBuffer to create extra items for categoryView.height * 1.5
398+ // to make scrolling nicer by mantaining a higher number of
392399 // cached items
393− // TODO Improvements
394− // - For non visible scopes we should always have a visible range of 0 and
395− // make sure the items in the viewport are created with the cache buffer feature
396− // - For visible scopes we should always the have a visible range be exactly the
397− // viewport and make sure the rest of items are created with the cache buffer feature
398− // To be able to implement that feature VerticalJournal/AbstractDashView needs to
399− // make the cache buffer value setable externally
400− var extraMargins = scopeView.isCurrent ? categoryView.height * 1.5 : 0;
401−
402− item.displayMarginBeginning = Math.round(-Math.max(-baseItem.y - extraMargins, 0));
403− item.displayMarginEnd = -Math.round(Math.max(baseItem.height - extraMargins - seeAll.height -
404− categoryView.height + baseItem.y, 0));
400+ // * For non current but visible scopes (i.e. when the user changes from one scope
401+ // to the next, we set the visible range to the viewport so
402+ // items are not culled (invisible) but still use no cacheBuffer
403+ // (it will be set once the scope is the current one)
404+ var displayMarginBeginning = baseItem.y;
405+ displayMarginBeginning = -Math.max(-displayMarginBeginning, 0);
406+ displayMarginBeginning = -Math.min(-displayMarginBeginning, baseItem.height);
407+ displayMarginBeginning = Math.round(displayMarginBeginning);
408+ var displayMarginEnd = -baseItem.height + seeAll.height + categoryView.height - baseItem.y;
409+ displayMarginEnd = -Math.max(-displayMarginEnd, 0);
410+ displayMarginEnd = -Math.min(-displayMarginEnd, baseItem.height);
411+ displayMarginEnd = Math.round(displayMarginEnd);
412+ if (scopeView.isCurrent || scopeView.visibleToParent) {
413+ item.displayMarginBeginning = displayMarginBeginning;
414+ item.displayMarginEnd = displayMarginEnd;
415+ item.cacheBuffer = scopeView.isCurrent ? categoryView.height * 1.5 : 0;
416+ } else {
417+ var visibleRange = baseItem.height + displayMarginEnd + displayMarginBeginning;
418+ if (visibleRange < 0) {
419+ item.displayMarginBeginning = displayMarginBeginning;
420+ item.displayMarginEnd = displayMarginEnd;
421+ item.cacheBuffer = 0;
422+ } else {
423+ // This should be visibleRange/2 in each of the properties
424+ // but some item views still (like GridView) like creating sync delegates even if
425+ // the visible range is 0 so let's make sure the visible range is negative
426+ item.displayMarginBeginning = displayMarginBeginning - visibleRange;
427+ item.displayMarginEnd = displayMarginEnd - visibleRange;
428+ item.cacheBuffer = visibleRange;
429+ }
430+ }
405431 }
406432 }
407433 }
@@ -494,7 +520,7 @@ FocusScope {
494520 showBackButton: scopeView.hasBackAction
495521 searchEntryEnabled: true
496522 settingsEnabled: scopeView.scope && scopeView.scope.settings && scopeView.scope.settings.count > 0 || false
497− favoriteEnabled: scopeView.scope
523+ favoriteEnabled: scopeView.scope && scopeView.scope.id !== "clickscope"
498524 favorite: scopeView.scope && scopeView.scope.favorite
499525 scopeStyle: scopeView.scopeStyle
500526 paginationCount: scopeView.paginationCount
qml/Dash/ScopeListView.qml+4−2
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2014 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -20,5 +20,7 @@ import Dash 0.1
2020ListViewWithPageHeader {
2121 maximumFlickVelocity: height * 10
2222 flickDeceleration: height * 2
23− cacheBuffer: Number.MAX_VALUE
23+ // 1073741823 is s^30 -1. A quite big number so that you have "infinite" cache, but not so
24+ // big so that if you add if with itself you're outside the 2^31 int range
25+ cacheBuffer: 1073741823
2426}
qml/Dash/ScopesList.qml+5−1
@@ -34,6 +34,9 @@ Item {
3434
3535 state: "browse"
3636
37+ property var scopeStyle: ScopeStyle {
38+ }
39+
3740 onStateChanged: {
3841 if (state == "edit") {
3942 // As per design entering edit mode clears the possible existing search
@@ -66,6 +69,7 @@ Item {
6669 backIsClose: root.state == "edit"
6770 storeEntryEnabled: root.state == "browse"
6871 searchEntryEnabled: false // Disable search for now
72+ scopeStyle: root.scopeStyle
6973 onBackClicked: {
7074 if (backIsClose) {
7175 root.state = "browse"
@@ -111,7 +115,7 @@ Item {
111115
112116 editMode: root.state == "edit"
113117
114− scopeStyle: root.scope.scopeStyle
118+ scopeStyle: root.scopeStyle
115119 isFavoritesFeed: categoryId == "favorites"
116120 isAlsoInstalled: categoryId == "other"
117121
qml/Dash/ScopesListCategory.qml+2−2
@@ -78,7 +78,7 @@ Item {
7878 clip: height < listItemHeight
7979 Behavior on height { enabled: visible; UbuntuNumberAnimation { } }
8080 sourceComponent: ScopesListCategoryItem {
81− objectName: "delegate" + index
81+ objectName: "delegate" + model.scopeId
8282
8383 width: root.width
8484 topMargin: height > listItemHeight ? height - listItemHeight : 0
@@ -86,7 +86,7 @@ Item {
8686 icon: model.art || model.mascot || ""
8787 text: model.title || ""
8888 subtext: model.subtitle || ""
89− showStar: root.isFavoritesFeed || root.isAlsoInstalled
89+ showStar: model.scopeId !== "clickscope" && (root.isFavoritesFeed || root.isAlsoInstalled)
9090 isFavorite: root.isFavoritesFeed
9191
9292 hideChildren: dragItem.loaderToShrink == loader
qml/Dash/ScopesListCategoryItem.qml+3−1
@@ -29,8 +29,8 @@ MouseArea {
2929 property alias icon: shapeImage.source
3030 property alias text: titleLabel.text
3131 property alias subtext: subtitleLabel.text
32− property alias showStar: star.visible
3332
33+ property bool showStar: false
3434 property bool isFavorite: false
3535 property bool hideChildren: false
3636
@@ -84,12 +84,14 @@ MouseArea {
8484 }
8585 MouseArea {
8686 id: starArea
87+ objectName: "starArea"
8788 height: parent.height
8889 width: height
8990 anchors.right: parent.right
9091 onClicked: if (!editMode) root.requestFavorite(model.scopeId, !isFavorite);
9192 onPressed: if (editMode) root.handlePressed(starArea);
9293 onReleased: if (editMode) root.handleReleased(starArea);
94+ visible: editMode || showStar
9395 Icon {
9496 id: star
9597 anchors.centerIn: parent
qml/Greeter/Greeter.qml+91−82
@@ -25,16 +25,26 @@ Showable {
2525 enabled: shown
2626 created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready
2727
28+ property real dragHandleLeftMargin: 0
29+ property alias dragging: dragHandle.dragging
30+
2831 property url background
32+
33+ prepareToHide: function () {
34+ hideTranslation.to = greeter.x > 0 || d.forceRightOnNextHideAnimation ? greeter.width : -greeter.width;
35+ d.forceRightOnNextHideAnimation = false;
36+ }
37+
38+ QtObject {
39+ id: d
40+ property bool forceRightOnNextHideAnimation: false
41+ }
42+
2943 property bool loadContent: required
3044
3145 // 1 when fully shown and 0 when fully hidden
32− property real showProgress: MathUtils.clamp((width - Math.abs(x)) / width, 0, 1)
33−
34− showAnimation: StandardAnimation { property: "x"; to: 0; duration: UbuntuAnimation.FastDuration }
35− hideAnimation: __leftHideAnimation
46+ property real showProgress: visible ? MathUtils.clamp((width - Math.abs(x)) / width, 0, 1) : 0
3647
37− property alias dragHandleWidth: dragHandle.width
3848 property alias model: greeterContentLoader.model
3949 property bool locked: true
4050
@@ -43,18 +53,13 @@ Showable {
4353
4454 readonly property int currentIndex: greeterContentLoader.currentIndex
4555
46− property var __leftHideAnimation: StandardAnimation { property: "x"; to: -width }
47− property var __rightHideAnimation: StandardAnimation { property: "x"; to: width }
48−
4956 signal selected(int uid)
5057 signal unlocked(int uid)
51− signal tease()
58+ signal tapped()
5259
5360 function hideRight() {
54− if (shown) {
55− hideAnimation = __rightHideAnimation
56− hide()
57− }
61+ d.forceRightOnNextHideAnimation = true;
62+ hide();
5863 }
5964
6065 function tryToUnlock() {
@@ -69,71 +74,9 @@ Showable {
6974 }
7075 }
7176
72− onRequiredChanged: {
73− // Reset hide animation to default once we're finished with it
74− if (required) {
75− // Reset hide animation so that a hide() call is reliably left
76− hideAnimation = __leftHideAnimation
77− }
78− }
79−
80− // Bi-directional revealer
81− DraggingArea {
82− id: dragHandle
83− anchors.fill: parent
84− enabled: (greeter.narrowMode || !greeter.locked) && greeter.enabled && greeter.shown
85− orientation: Qt.Horizontal
86− propagateComposedEvents: true
87−
88− Component.onCompleted: {
89− // set evaluators to baseline of dragValue == 0
90− leftEvaluator.reset()
91− rightEvaluator.reset()
92− }
93−
94− function maybeTease() {
95− if (!greeter.locked || greeter.narrowMode)
96− greeter.tease();
97− }
98−
99− onClicked: maybeTease()
100− onDragStart: maybeTease()
101− onPressAndHold: {} // eat event, but no need to tease, as drag will cover it
102−
103− onDragEnd: {
104− if (greeter.x > 0 && rightEvaluator.shouldAutoComplete()) {
105− greeter.hideRight()
106− } else if (greeter.x < 0 && leftEvaluator.shouldAutoComplete()) {
107− greeter.hide();
108− } else {
109− greeter.show(); // undo drag
110− }
111− }
112−
113− onDragValueChanged: {
114− // dragValue is kept as a "step" value since we do this x adjusting on the fly
115− greeter.x += dragValue
116− }
117−
118− EdgeDragEvaluator {
119− id: rightEvaluator
120− trackedPosition: dragHandle.dragValue + greeter.x
121− maxDragDistance: parent.width
122− direction: Direction.Rightwards
123− }
124−
125− EdgeDragEvaluator {
126− id: leftEvaluator
127− trackedPosition: dragHandle.dragValue + greeter.x
128− maxDragDistance: parent.width
129− direction: Direction.Leftwards
130− }
131− }
132− TouchGate {
133− targetItem: dragHandle
134− anchors.fill: targetItem
135− enabled: targetItem.enabled
136− }
77+ // event eater
78+ // Nothing should leak to items behind the greeter
79+ MouseArea { anchors.fill: parent }
13780
13881 Loader {
13982 id: greeterContentLoader
@@ -161,11 +104,27 @@ Showable {
161104 }
162105 }
163106
164− onTease: showLabelAnimation.start()
107+ DragHandle {
108+ id: dragHandle
109+ anchors.fill: parent
110+ anchors.leftMargin: greeter.dragHandleLeftMargin
111+ enabled: (greeter.narrowMode || !greeter.locked) && greeter.enabled && greeter.shown
112+ direction: Direction.Horizontal
113+
114+ onTapped: {
115+ greeter.tapped();
116+ showLabelAnimation.start();
117+ }
118+
119+ onDraggingChanged: {
120+ if (dragging) {
121+ showLabelAnimation.start();
122+ }
123+ }
124+ }
165125
166126 Label {
167127 id: swipeHint
168− visible: greeter.shown
169128 property real baseOpacity: 0.5
170129 opacity: 0.0
171130 anchors.horizontalCenter: parent.horizontalCenter
@@ -199,7 +158,6 @@ Showable {
199158 anchors.left: parent.right
200159 anchors.top: parent.top
201160 anchors.bottom: parent.bottom
202− visible: parent.required
203161 fillMode: Image.Tile
204162 source: "../graphics/dropshadow_right.png"
205163 }
@@ -209,8 +167,59 @@ Showable {
209167 anchors.right: parent.left
210168 anchors.top: parent.top
211169 anchors.bottom: parent.bottom
212− visible: parent.required
213170 fillMode: Image.Tile
214171 source: "../graphics/dropshadow_left.png"
215172 }
173+
174+ Binding {
175+ id: positionLock
176+
177+ property bool enabled: false
178+ onEnabledChanged: {
179+ if (enabled === __enabled) {
180+ return;
181+ }
182+
183+ if (enabled) {
184+ if (greeter.x > 0) {
185+ value = Qt.binding(function() { return greeter.width; })
186+ } else {
187+ value = Qt.binding(function() { return -greeter.width; })
188+ }
189+ }
190+
191+ __enabled = enabled;
192+ }
193+
194+ property bool __enabled: false
195+
196+ target: greeter
197+ when: __enabled
198+ property: "x"
199+ }
200+
201+ hideAnimation: SequentialAnimation {
202+ id: hideAnimation
203+ objectName: "hideAnimation"
204+ StandardAnimation {
205+ id: hideTranslation
206+ property: "x"
207+ target: greeter
208+ }
209+ PropertyAction { target: greeter; property: "visible"; value: false }
210+ PropertyAction { target: positionLock; property: "enabled"; value: true }
211+ }
212+
213+ showAnimation: SequentialAnimation {
214+ id: showAnimation
215+ objectName: "showAnimation"
216+ PropertyAction { target: greeter; property: "visible"; value: true }
217+ PropertyAction { target: positionLock; property: "enabled"; value: false }
218+ StandardAnimation {
219+ property: "x"
220+ target: greeter
221+ to: 0
222+ duration: UbuntuAnimation.FastDuration
223+ }
224+ }
216225}
qml/Greeter/Infographics.qml−3
@@ -406,8 +406,5 @@ Item {
406406 infographic.model.nextDataSource()
407407 }
408408 }
409−
410− onClicked: mouse.accepted = false
411− onPressed: mouse.accepted = false
412409 }
413410}
qml/Shell.qml+12−4
@@ -554,9 +554,7 @@ Item {
554554 property string lockedApp: ""
555555 property bool hasLockedApp: lockedApp !== ""
556556
557− available: true
558557 hides: [launcher, panel.indicators]
559− shown: true
560558 loadContent: required || lockscreen.required // keeps content in memory for quick show()
561559
562560 locked: shell.locked
@@ -566,7 +564,12 @@ Item {
566564 width: parent.width
567565 height: parent.height
568566
569− dragHandleWidth: shell.edgeSize
567+
568+ // avoid overlapping with Launcher's edge drag area
569+ // FIXME: Fix TouchRegistry & friends and remove this workaround
570+ // Issue involves launcher's DDA getting disabled on a long
571+ // left-edge drag
572+ dragHandleLeftMargin: launcher.available ? launcher.dragAreaWidth + 1 : 0
570573
571574 function startUnlock() {
572575 if (narrowMode) {
@@ -620,7 +623,12 @@ Item {
620623 LauncherModel.setUser(user);
621624 }
622625
623− onTease: launcher.tease()
626+ onTapped: launcher.tease()
627+ onDraggingChanged: {
628+ if (dragging) {
629+ launcher.tease();
630+ }
631+ }
624632
625633 Binding {
626634 target: ApplicationManager
tests/autopilot/unity8/shell/emulators/dash.py+22−8
@@ -90,8 +90,12 @@ class Dash(emulators.UnityEmulatorBase):
9090
9191 def _get_scope_loader(self, scope_id):
9292 try:
93− return self.dash_content_list.wait_select_single(
94− 'QQuickLoader', scopeId=scope_id)
93+ aux = self.dash_content_list.get_children_by_type('QQuickItem')[0]
94+ for l in aux.get_children_by_type('QQuickLoader'):
95+ if (l.scopeId == scope_id):
96+ return l;
97+ raise emulators.UnityEmulatorException(
98+ 'No scope found with id {0}'.format(scope_id))
9599 except dbus.StateNotFoundError:
96100 raise emulators.UnityEmulatorException(
97101 'No scope found with id {0}'.format(scope_id))
@@ -125,10 +129,15 @@ class Dash(emulators.UnityEmulatorBase):
125129 original_index = self.dash_content_list.currentIndex
126130 dash_content = self.select_single(objectName="dashContent")
127131 x, y, width, height = dash_content.globalRect
128− start_x = x + width / 3
129− stop_x = x + width / 3 * 2
132+ # Make the drag range be a multiple of the drag "rate" value.
133+ # Workarounds https://bugs.launchpad.net/mir/+bug/1399690
134+ rate = 10
135+ divisions = 5
136+ jump = ( width / divisions ) // rate * rate
137+ start_x = x + jump
138+ stop_x = x + jump * (divisions - 1)
130139 start_y = stop_y = y + 1
131− self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
140+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y, rate)
132141 self.dash_content_list.currentIndex.wait_for(original_index - 1)
133142
134143 @autopilot_logging.log_action(logger.info)
@@ -136,10 +145,15 @@ class Dash(emulators.UnityEmulatorBase):
136145 original_index = self.dash_content_list.currentIndex
137146 dash_content = self.select_single(objectName="dashContent")
138147 x, y, width, height = dash_content.globalRect
139− start_x = x + width / 3 * 2
140− stop_x = x + width / 3
148+ # Make the drag range be a multiple of the drag "rate" value.
149+ # Workarounds https://bugs.launchpad.net/mir/+bug/1399690
150+ rate = 10
151+ divisions = 5
152+ jump = ( width / divisions ) // rate * rate
153+ start_x = x + jump * (divisions - 1)
154+ stop_x = x + jump
141155 start_y = stop_y = y + 1
142− self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
156+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y, rate)
143157 self.dash_content_list.currentIndex.wait_for(original_index + 1)
144158
145159 def enter_search_query(self, query):
tests/mocks/Unity/Application/ApplicationManager.cpp+7
@@ -20,6 +20,7 @@
2020#include "ApplicationTestInterface.h"
2121
2222#include <paths.h>
23+#include <csignal>
2324
2425#include <QDir>
2526#include <QGuiApplication>
@@ -36,6 +37,12 @@ ApplicationManager *ApplicationManager::singleton()
3637{
3738 if (!the_application_manager) {
3839 the_application_manager = new ApplicationManager();
40+
41+ // Emit signal to notify Upstart that Mir is ready to receive client connections
42+ // see http://upstart.ubuntu.com/cookbook/#expect-stop
43+ if (qgetenv("UNITY_MIR_EMITS_SIGSTOP") == "1") {
44+ raise(SIGSTOP);
45+ }
3946 }
4047 return the_application_manager;
4148}
tests/plugins/Dash/horizontaljournaltest.qml+1
@@ -25,6 +25,7 @@ Item {
2525 rowHeight: 150
2626 columnSpacing: 10
2727 rowSpacing: 10
28+ cacheBuffer: Math.max(0, (height + displayMarginEnd + displayMarginBeginning) / 2)
2829
2930 delegate: Rectangle {
3031 property real randomValue: Math.random()
tests/plugins/Dash/listviewwithpageheadertest.cpp+1−1
@@ -1920,7 +1920,7 @@ private Q_SLOTS:
19201920
19211921 void testAllCacheBuffer()
19221922 {
1923− lvwph->setCacheBuffer(std::numeric_limits<qreal>::max());
1923+ lvwph->setCacheBuffer(std::numeric_limits<int>::max());
19241924 QTRY_COMPARE(lvwph->m_visibleItems.count(), 6);
19251925 QCOMPARE(lvwph->m_firstVisibleIndex, 0);
19261926 verifyItem(0, 50., 150., false);
tests/plugins/Dash/organicgridtest.qml+1
@@ -27,6 +27,7 @@ Item {
2727 rowSpacing: 10
2828 smallDelegateSize: Qt.size(90, 90)
2929 bigDelegateSize: Qt.size(180, 180)
30+ cacheBuffer: Math.max(0, (height + displayMarginEnd + displayMarginBeginning) / 2)
3031
3132 delegate: Rectangle {
3233 property real randomValue: Math.random()
tests/plugins/Dash/verticaljournaltest.qml+1
@@ -26,6 +26,7 @@ Item {
2626 columnWidth: 150
2727 columnSpacing: 10
2828 rowSpacing: 10
29+ cacheBuffer: Math.max(0, (height + displayMarginEnd + displayMarginBeginning) / 2)
2930
3031 delegate: Rectangle {
3132 property real randomValue: Math.random()
tests/qmltests/CMakeLists.txt+1
@@ -23,6 +23,7 @@ add_qml_test(. ShellWithPin ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tes
2323add_qml_test(. TabletShell ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full:${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
2424add_qml_test(Components Background)
2525add_qml_test(Components Carousel)
26+add_qml_test(Components Dialogs)
2627add_qml_test(Components DraggingArea)
2728add_qml_test(Components EdgeDemoOverlay)
2829add_qml_test(Components LazyImage)
tests/qmltests/Components/tst_Dialogs.qmlnew file+104
@@ -0,0 +1,104 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.2
18+import QtTest 1.0
19+import Ubuntu.Components 1.1
20+import Unity.Test 0.1
21+
22+import "../../../qml/Components"
23+
24+Rectangle {
25+ id: root
26+ color: "black"
27+ width: units.gu(70)
28+ height: fakeShell.longestDimension
29+
30+ QtObject {
31+ id: fakeUnitySession
32+ signal logoutRequested
33+ signal shutdownRequested
34+ signal rebootRequested
35+ function logout() {}
36+ function shutdown() {}
37+ function reboot() {}
38+ }
39+
40+ Rectangle {
41+ id: fakeShell
42+ color: "green"
43+ readonly property real longestDimension: units.gu(71)
44+ readonly property real shortestDimension: units.gu(40)
45+ readonly property bool landscape: rotation === 90 || rotation === 270
46+ x: (shortestDimension - width) / 2
47+ y: (longestDimension - height) / 2
48+ width: landscape ? longestDimension : shortestDimension
49+ height: landscape ? shortestDimension : longestDimension
50+
51+ Text {
52+ text: "Shell"
53+ color: "black"
54+ anchors.fill: parent
55+ fontSizeMode: Text.Fit
56+ minimumPixelSize: 10
57+ font.pixelSize: 200
58+ verticalAlignment: Text.AlignVCenter
59+ horizontalAlignment: Text.AlignHCenter
60+ }
61+
62+ Dialogs {
63+ id: dialogs
64+ anchors.fill: parent
65+ unitySessionService: fakeUnitySession
66+ closeAllApps: function() {}
67+ }
68+ }
69+
70+ Rectangle {
71+ color: "white"
72+ x: fakeShell.shortestDimension
73+ width: root.width - x
74+ anchors {
75+ top: parent.top
76+ bottom: parent.bottom
77+ }
78+
79+ Column {
80+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
81+ spacing: units.gu(1)
82+ Button { text: "Power dialog"; onClicked: { testCase.showPowerDialog(); } }
83+ Button { text: "Logout Requested"; onClicked: { fakeUnitySession.logoutRequested(); } }
84+ Button { text: "Shutdown Requested"; onClicked: { fakeUnitySession.shutdownRequested(); } }
85+ Button { text: "Reboot Requested"; onClicked: { fakeUnitySession.rebootRequested(); } }
86+ Label { text: "Rotation:" }
87+ Button { text: "0"; onClicked: {fakeShell.rotation = 0;} }
88+ Button { text: "90"; onClicked: {fakeShell.rotation = 90;} }
89+ Button { text: "180"; onClicked: {fakeShell.rotation = 180;} }
90+ Button { text: "270"; onClicked: {fakeShell.rotation = 270;} }
91+ }
92+ }
93+
94+ UnityTestCase {
95+ id: testCase
96+ name: "Dialogs"
97+ when: windowShown
98+
99+ function showPowerDialog() {
100+ var dialogsPrivate = findInvisibleChild(dialogs, "dialogsPrivate");
101+ dialogsPrivate.showPowerDialog();
102+ }
103+ }
104+}
tests/qmltests/Components/tst_DragHandle.cpp+4
@@ -101,6 +101,10 @@ void tst_DragHandle::init()
101101 QVERIFY(m_view->rootObject() != 0);
102102 qApp->processEvents();
103103
104+ // Hide the controls to ensure we don't hit them accidentally
105+ QQuickItem *controls = m_view->rootObject()->findChild<QQuickItem*>("controls");
106+ controls->setVisible(false);
107+
104108 m_fakeTimer = new FakeTimer;
105109 m_fakeTimeSource.reset(new FakeTimeSource);
106110}
tests/qmltests/Components/tst_DragHandle.qml+43−8
@@ -27,8 +27,9 @@ import Ubuntu.Gestures 0.1
2727 A black vertical line marks the point where a drag needs no forward velocity to
2828 achieve auto-completion (i.e., get Showable.show() called after touch release).
2929 */
30−Item {
30+Rectangle {
3131 id: root
32+ color: "darkblue"
3233 width: units.gu(70)
3334 height: units.gu(70)
3435
@@ -36,19 +37,35 @@ Item {
3637
3738 property bool stretch: false
3839 property real hintDisplacement: 0
40+ property bool bidirectional: false
3941
4042 Item {
4143 id: baseItem
4244 objectName: "baseItem"
4345 anchors.fill: parent
4446
47+ Button {
48+ visible: root.bidirectional && bidirectionalShowable.fullyHidden
49+ text: "bidirectionalShowable.show()"
50+ anchors.centerIn: parent
51+ onClicked: { bidirectionalShowable.show(); }
52+ }
53+
54+ BidirectionalShowable {
55+ id: bidirectionalShowable
56+ visible: root.bidirectional
57+ onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
58+ }
59+
4560 VerticalShowable {
61+ visible: !root.bidirectional
4662 onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
4763 stretch: root.stretch
4864 hintDisplacement: root.hintDisplacement
4965 }
5066
5167 HorizontalShowable {
68+ visible: !root.bidirectional
5269 onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
5370 stretch: root.stretch
5471 hintDisplacement: root.hintDisplacement
@@ -60,15 +77,28 @@ Item {
6077 width: 2
6178 height: parent.height
6279
63− visible: dragHandle !== undefined && Direction.isHorizontal(dragHandle.direction)
80+ visible: dragHandle !== undefined
81+ && (dragHandle.direction === Direction.Horizontal || dragHandle.direction === Direction.Rightwards)
6482
6583 x: {
6684 if (dragHandle) {
67− if (dragHandle.direction === Direction.Rightwards) {
68− dragHandle.edgeDragEvaluator.dragThreshold;
69− } else {
70− parent.width - dragHandle.edgeDragEvaluator.dragThreshold;
71− }
85+ dragHandle.edgeDragEvaluator.dragThreshold;
86+ } else {
87+ 0
88+ }
89+ }
90+ }
91+ Rectangle {
92+ color: "black"
93+ width: 2
94+ height: parent.height
95+
96+ visible: dragHandle !== undefined
97+ && (dragHandle.direction === Direction.Horizontal || dragHandle.direction === Direction.Leftwards)
98+
99+ x: {
100+ if (dragHandle) {
101+ parent.width - dragHandle.edgeDragEvaluator.dragThreshold;
72102 } else {
73103 0
74104 }
@@ -126,13 +156,13 @@ Item {
126156 }
127157
128158 Row {
159+ objectName: "controls"
129160 anchors.bottom: parent.bottom
130161 anchors.left: parent.left
131162 anchors.margins: units.gu(1)
132163 spacing: units.gu(1)
133164
134165 Button {
135− id: stretchButton
136166 text: root.stretch ? "stretch" : "move"
137167 onClicked: { root.stretch = !root.stretch; }
138168 }
@@ -158,5 +188,10 @@ Item {
158188 }
159189 }
160190 }
191+
192+ Button {
193+ text: root.bidirectional ? "bidirectional" : "directional"
194+ onClicked: { root.bidirectional = !root.bidirectional; }
195+ }
161196 }
162197}
tests/qmltests/Components/tst_DragHandle/BidirectionalShowable.qmlnew file+69
@@ -0,0 +1,69 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import "../../../../qml/Components"
19+import Ubuntu.Components 0.1
20+import Ubuntu.Gestures 0.1
21+
22+Item {
23+ id: root
24+ x: 0
25+ width: parent.width
26+ height: parent.height
27+
28+ property bool shown: true
29+
30+ signal dragHandleRecognizedGesture(var dragHandle)
31+
32+ property bool fullyHidden: x == -width || x == width
33+
34+ function show() {
35+ shown = true;
36+ animation.stop();
37+ animation.to = 0;
38+ animation.start();
39+ }
40+
41+ function hide() {
42+ shown = false;
43+ animation.stop();
44+ animation.to = x > 0 ? width : -width;
45+ animation.start();
46+ }
47+
48+ StandardAnimation {
49+ id: animation
50+ target: root
51+ property: "x"
52+ }
53+
54+ Image { source: "../../UnityLogo.png"; anchors.fill: parent }
55+
56+ DragHandle {
57+ id: dragHandle
58+ anchors.fill: parent
59+ direction: Direction.Horizontal
60+ maxTotalDragDistance: root.parent.width
61+ autoCompleteDragThreshold: parent.width / 3
62+
63+ onStatusChanged: {
64+ if (status === DirectionalDragArea.Recognized) {
65+ dragHandleRecognizedGesture(dragHandle);
66+ }
67+ }
68+ }
69+}
tests/qmltests/Dash/tst_Dash.qml+107−11
@@ -70,17 +70,28 @@ Item {
7070 waitForRendering(findChild(dash, "scopeLoader0").item);
7171 }
7272
73− function get_scope_data() {
74− return [
75− { tag: "MockScope1", visualIndex: 0 },
76− { tag: "MockScope2", visualIndex: -1 },
77− { tag: "clickscope", visualIndex: 1 },
78− { tag: "MockScope5", visualIndex: 2 },
79− ]
80− }
73+ function test_manage_dash_clickscope_unfavoritable() {
74+ // Show the manage dash
75+ touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, units.gu(2));
76+ var bottomEdgeController = findInvisibleChild(dash, "bottomEdgeController");
77+ tryCompare(bottomEdgeController, "progress", 1);
78+
79+ // Make sure stuff is loaded
80+ var favScopesListCategory = findChild(dash, "scopesListCategoryfavorites");
81+ var favScopesListCategoryList = findChild(favScopesListCategory, "scopesListCategoryInnerList");
82+ tryCompare(favScopesListCategoryList, "currentIndex", 0);
83+
84+ // Click scope star area is not visible (i.e. can't be unfavorited)
85+ var clickScope = findChild(favScopesListCategoryList, "delegateclickscope");
86+ var starArea = findChild(clickScope, "starArea");
87+ compare(starArea.visible, false);
8188
82− function test_show_scope_on_load_data() {
83− return get_scope_data()
89+ // Go back
90+ var scopesList = findChild(dash, "scopesList");
91+ var scopesListPageHeader = findChild(scopesList, "pageHeader");
92+ var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "backButton");
93+ mouseClick(backButton, 0, 0);
94+ tryCompare(bottomEdgeController, "progress", 0);
8495 }
8596
8697 function test_manage_dash_select_same_favorite() {
@@ -306,7 +317,7 @@ Item {
306317 spy.target = scopesList.scope;
307318 spy.signalName = "performQuery";
308319
309− // Do a search
320+ // Click on the store
310321 var scopesListPageHeader = findChild(scopesList, "pageHeader");
311322 var searchButton = findChild(scopesListPageHeader, "store_header_button");
312323 mouseClick(searchButton, 0, 0);
@@ -315,5 +326,90 @@ Item {
315326 compare(spy.signalArguments[0][0], "scope://com.canonical.scopes.clickstore");
316327 tryCompare(bottomEdgeController, "progress", 0);
317328 }
329+
330+ function test_manage_dash_move_current() {
331+ var dashContentList = findChild(dash, "dashContentList");
332+ compare(dashContentList.currentIndex, 0);
333+ compare(dashContentList.currentItem.scopeId, "MockScope1");
334+
335+ // Show the manage dash
336+ touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, units.gu(2));
337+ var bottomEdgeController = findInvisibleChild(dash, "bottomEdgeController");
338+ tryCompare(bottomEdgeController, "progress", 1);
339+
340+ // Make sure stuff is loaded
341+ var favScopesListCategory = findChild(dash, "scopesListCategoryfavorites");
342+ var favScopesListCategoryList = findChild(favScopesListCategory, "scopesListCategoryInnerList");
343+ tryCompare(favScopesListCategoryList, "currentIndex", 0);
344+
345+ // Enter edit mode
346+ var scopesList = findChild(dash, "scopesList");
347+ var clickScope = findChild(favScopesListCategoryList, "delegateclickscope");
348+ mousePress(clickScope, 0, 0);
349+ tryCompare(scopesList, "state", "edit");
350+ mouseRelease(clickScope, 0, 0);
351+
352+ var starArea = findChild(clickScope, "starArea");
353+ touchFlick(starArea, 0, 0, 0, -units.gu(10));
354+
355+ // Exit edit mode and go back
356+ var scopesList = findChild(dash, "scopesList");
357+ var scopesListPageHeader = findChild(scopesList, "pageHeader");
358+ var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "backButton");
359+ mouseClick(backButton, 0, 0);
360+ mouseClick(backButton, 0, 0);
361+ tryCompare(bottomEdgeController, "progress", 0);
362+
363+ tryCompare(dashContentList, "currentIndex", 0);
364+ compare(dashContentList.currentItem.scopeId, "clickscope");
365+
366+ // Move to second scope
367+ touchFlick(dash, dash.width / 2, units.gu(2), dash.width / 5, units.gu(2));
368+ tryCompare(dashContentList, "currentIndex", 1);
369+ compare(dashContentList.currentItem.scopeId, "MockScope1");
370+ }
371+
372+ function test_manage_dash_move_current_click_other() {
373+ var dashContentList = findChild(dash, "dashContentList");
374+ compare(dashContentList.currentIndex, 0);
375+ compare(dashContentList.currentItem.scopeId, "MockScope1");
376+
377+ // Show the manage dash
378+ touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, units.gu(2));
379+ var bottomEdgeController = findInvisibleChild(dash, "bottomEdgeController");
380+ tryCompare(bottomEdgeController, "progress", 1);
381+
382+ // Make sure stuff is loaded
383+ var favScopesListCategory = findChild(dash, "scopesListCategoryfavorites");
384+ var favScopesListCategoryList = findChild(favScopesListCategory, "scopesListCategoryInnerList");
385+ tryCompare(favScopesListCategoryList, "currentIndex", 0);
386+
387+ // Enter edit mode
388+ var scopesList = findChild(dash, "scopesList");
389+ var clickScope = findChild(favScopesListCategoryList, "delegateclickscope");
390+ mousePress(clickScope, 0, 0);
391+ tryCompare(scopesList, "state", "edit");
392+ mouseRelease(clickScope, 0, 0);
393+
394+ var starArea = findChild(clickScope, "starArea");
395+ touchFlick(starArea, 0, 0, 0, -units.gu(10));
396+
397+ // wait for the animation to settle
398+ tryCompare(clickScope, "height", units.gu(6));
399+
400+ // Exit edit mode
401+ var scopesList = findChild(dash, "scopesList");
402+ var scopesListPageHeader = findChild(scopesList, "pageHeader");
403+ var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "backButton");
404+ mouseClick(backButton, 0, 0);
405+
406+ // Click on third scope
407+ var mockScope5 = findChild(favScopesListCategoryList, "delegateMockScope5");
408+ waitForRendering(mockScope5)
409+ mouseClick(mockScope5, 0, 0);
410+ tryCompare(bottomEdgeController, "progress", 0);
411+ tryCompare(dashContentList, "currentIndex", 2);
412+ compare(dashContentList.currentItem.scopeId, "MockScope5");
413+ }
318414 }
319415}
tests/qmltests/Dash/tst_GenericScopeView.qml+2
@@ -59,6 +59,7 @@ Item {
5959 GenericScopeView {
6060 id: genericScopeView
6161 anchors.fill: parent
62+ visibleToParent: true
6263
6364 UT.UnityTestCase {
6465 id: testCase
@@ -574,6 +575,7 @@ Item {
574575 var innerHeader = findChild(header, "innerPageHeader");
575576 verify(innerHeader, "Could not find the inner header");
576577
578+ expectFail("Apps", "Click scope should not have a favorite button");
577579 var favoriteAction = findChild(innerHeader, "favorite_header_button");
578580 verify(favoriteAction, "Could not find the favorite action.");
579581 mouseClick(favoriteAction, favoriteAction.width / 2, favoriteAction.height / 2);
tests/qmltests/Greeter/tst_MultiGreeter.qml+15−15
@@ -56,9 +56,9 @@ Item {
5656 }
5757
5858 SignalSpy {
59− id: teaseSpy
59+ id: tappedSpy
6060 target: greeter
61− signalName: "tease"
61+ signalName: "tapped"
6262 }
6363
6464 UT.UnityTestCase {
@@ -323,18 +323,18 @@ Item {
323323 compare(greeter.model.data(index, LightDM.UserRoles.BackgroundPathRole), "")
324324 }
325325
326− function test_teasingArea_data() {
326+ function test_tappedSignal_data() {
327327 return [
328− {tag: "left", posX: units.gu(2), leftPressed: true, rightPressed: false},
329− {tag: "right", posX: greeter.width - units.gu(2), leftPressed: false, rightPressed: true}
328+ {tag: "left", posX: units.gu(2)},
329+ {tag: "right", posX: greeter.width - units.gu(2)}
330330 ]
331331 }
332332
333− function test_teasingArea(data) {
334− teaseSpy.clear()
335− mouseClick(greeter, data.posX, greeter.height - units.gu(1))
336− teaseSpy.wait()
337− tryCompare(teaseSpy, "count", 1)
333+ function test_tappedSignal(data) {
334+ select_user("no-password");
335+ tappedSpy.clear();
336+ tap(greeter, data.posX, greeter.height - units.gu(1))
337+ tryCompare(tappedSpy, "count", 1)
338338 }
339339
340340 function test_teaseLockedUnlocked_data() {
@@ -345,18 +345,18 @@ Item {
345345 }
346346
347347 function test_teaseLockedUnlocked(data) {
348− teaseSpy.clear()
348+ tappedSpy.clear()
349349 greeter.locked = data.locked;
350350
351− mouseClick(greeter, greeter.width - units.gu(5), greeter.height - units.gu(1));
351+ tap(greeter, greeter.width - units.gu(5), greeter.height - units.gu(1));
352352
353353 if (!data.locked || data.narrow) {
354− teaseSpy.wait()
355− tryCompare(teaseSpy, "count", 1);
354+ tappedSpy.wait()
355+ tryCompare(tappedSpy, "count", 1);
356356 } else {
357357 // waiting 100ms to make sure nothing happens
358358 wait(100);
359− compare(teaseSpy.count, 0, "Greeter teasing not disabled even though it's locked.");
359+ compare(tappedSpy.count, 0, "Greeter teasing not disabled even though it's locked.");
360360 }
361361
362362 // Reset value
tests/qmltests/Greeter/tst_SingleGreeter.qml+104−16
@@ -23,10 +23,20 @@ import LightDM 0.1 as LightDM
2323import Ubuntu.Components 0.1
2424import Unity.Test 0.1 as UT
2525
26−Item {
26+Rectangle {
27+ color: "darkblue"
2728 width: units.gu(60)
2829 height: units.gu(80)
2930
31+ Button {
32+ anchors.centerIn: parent
33+ text: "Show Greeter"
34+ onClicked: {
35+ if (greeterLoader.item)
36+ greeterLoader.item.show();
37+ }
38+ }
39+
3040 Loader {
3141 id: greeterLoader
3242 anchors.fill: parent
@@ -35,15 +45,8 @@ Item {
3545
3646 sourceComponent: Component {
3747 Greeter {
38− anchors.fill: greeterLoader
39−
40− property int minX: 0
41−
42− onXChanged: {
43− if (x < minX) {
44− minX = x;
45− }
46− }
48+ width: greeterLoader.width
49+ height: greeterLoader.height
4750
4851 Component.onDestruction: {
4952 greeterLoader.itemDestroyed = true;
@@ -64,9 +67,9 @@ Item {
6467 }
6568
6669 SignalSpy {
67− id: teaseSpy
70+ id: tappedSpy
6871 target: greeterLoader.item
69− signalName: "tease"
72+ signalName: "tapped"
7073 }
7174
7275 SignalSpy {
@@ -90,9 +93,11 @@ Item {
9093 tryCompare(greeterLoader, "itemDestroyed", true);
9194
9295 unlockSpy.clear();
93− teaseSpy.clear();
96+ tappedSpy.clear();
9497
9598 greeterLoader.active = true;
99+ tryCompare(greeterLoader, "status", Loader.Ready);
100+ removeTimeConstraintsFromDirectionalDragAreas(greeterLoader.item);
96101 }
97102
98103 function test_properties() {
@@ -108,10 +113,10 @@ Item {
108113 }
109114
110115 function test_teasingArea(data) {
111− teaseSpy.clear()
116+ tappedSpy.clear()
112117 tap(greeter, data.posX, greeter.height - units.gu(1))
113− teaseSpy.wait()
114− tryCompare(teaseSpy, "count", 1)
118+ tappedSpy.wait()
119+ tryCompare(tappedSpy, "count", 1)
115120 }
116121
117122 function test_statsWelcomeScreen() {
@@ -152,5 +157,88 @@ Item {
152157
153158 tryCompare(infographicDataChangedSpy, "count", 1);
154159 }
160+
161+ function test_movesBackIntoPlaceWhenNotDraggedFarEnough() {
162+
163+ var dragEvaluator = findInvisibleChild(greeter, "edgeDragEvaluator");
164+ verify(dragEvaluator);
165+
166+ // Make it easier to get a rejection/rollback. Otherwise would have to inject
167+ // a fake timer into dragEvaluator.
168+ // Afterall, we are testing if the Greeter indeed moves back on a
169+ // rollback decision, not the drag evaluation itself.
170+ dragEvaluator.minDragDistance = dragEvaluator.maxDragDistance / 2;
171+
172+ // it starts as fully shown
173+ compare(greeter.x, 0);
174+
175+ // then we drag it a bit
176+ var startX = greeter.width - 1;
177+ var touchY = greeter.height / 2;
178+ var dragXDelta = -(dragEvaluator.minDragDistance * 0.3);
179+ touchFlick(greeter,
180+ startX , touchY, // start pos
181+ startX + dragXDelta, touchY, // end pos
182+ true /* beginTouch */, false /* endTouch */);
183+
184+ // which should make it move a bit
185+ tryCompareFunction(function(){return greeter.x < 0;}, true);
186+
187+ // then we release it
188+ touchRelease(greeter, startX + dragXDelta, touchY);
189+
190+ // which should make it move back into its original position as it didn't move
191+ // far enough to have it hidden
192+ tryCompare(greeter, "x", 0);
193+ }
194+
195+ function test_dragToHide_data() {
196+ return [
197+ {tag: "left", startX: greeter.width * 0.95, endX: greeter.width * 0.1, hiddenX: -greeter.width},
198+ {tag: "right", startX: greeter.width * 0.1, endX: greeter.width * 0.95, hiddenX: greeter.width},
199+ ];
200+ }
201+ function test_dragToHide(data) {
202+ compare(greeter.x, 0);
203+ compare(greeter.visible, true);
204+ compare(greeter.shown, true);
205+ compare(greeter.showProgress, 1);
206+
207+ touchFlick(greeter,
208+ data.startX, greeter.height / 2, // start pos
209+ data.endX, greeter.height / 2); // end pos
210+
211+ tryCompare(greeter, "x", data.hiddenX);
212+ tryCompare(greeter, "visible", false);
213+ tryCompare(greeter, "shown", false);
214+ tryCompare(greeter, "showProgress", 0);
215+ }
216+
217+ function test_hiddenGreeterRemainsHiddenAfterResize_data() {
218+ return [
219+ {tag: "left", startX: greeter.width * 0.95, endX: greeter.width * 0.1},
220+ {tag: "right", startX: greeter.width * 0.1, endX: greeter.width * 0.95},
221+ ];
222+ }
223+ function test_hiddenGreeterRemainsHiddenAfterResize(data) {
224+ touchFlick(greeter,
225+ data.startX, greeter.height / 2, // start pos
226+ data.endX, greeter.height / 2); // end pos
227+
228+ tryCompare(greeter, "x", data.tag == "left" ? -greeter.width : greeter.width);
229+ tryCompare(greeter, "visible", false);
230+ tryCompare(greeter, "shown", false);
231+ tryCompare(greeter, "showProgress", 0);
232+
233+ // flip dimensions to simulate an orientation change
234+ greeter.width = greeterLoader.height;
235+ greeter.height = greeterLoader.width;
236+
237+ // All properties should remain consistent
238+ tryCompare(greeter, "x", data.tag == "left" ? -greeter.width : greeter.width);
239+ tryCompare(greeter, "visible", false);
240+ tryCompare(greeter, "shown", false);
241+ tryCompare(greeter, "showProgress", 0);
242+ }
155243 }
156244}
tests/qmltests/tst_TabletShell.qml+15−12
@@ -74,21 +74,24 @@ Row {
7474 Column {
7575 anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
7676 spacing: units.gu(1)
77− Row {
78− anchors { left: parent.left; right: parent.right }
79− Button {
80− text: "Show Greeter"
81− onClicked: {
82− if (shellLoader.status !== Loader.Ready)
83− return
84−
85− var greeter = testCase.findChild(shellLoader.item, "greeter")
86− if (!greeter.shown) {
87− greeter.show()
88− }
77+ Button {
78+ text: "Show Greeter"
79+ onClicked: {
80+ if (shellLoader.status !== Loader.Ready)
81+ return
82+
83+ var greeter = testCase.findChild(shellLoader.item, "greeter")
84+ if (!greeter.shown) {
85+ greeter.show()
8986 }
9087 }
9188 }
89+ Button {
90+ text: "Demo edges"
91+ onClicked: {
92+ AccountsService.demoEdges = true
93+ }
94+ }
9295 }
9396 }
9497