on xenial help sign in
merge trunk
14c9978Michael Zanetti
Bottombar/Bottombar.qml+4−4
@@ -16,10 +16,10 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import "../Components"
18import "../Components"
19−import "../Components/Math.js" as MathLocal
19+import Utils 0.1
20−import Unity 0.1
21import Unity.Application 0.1
20import Unity.Application 0.1
22import Ubuntu.Gestures 0.1
21import Ubuntu.Gestures 0.1
22+import Ubuntu.Components 0.1
23
23
24Item {
24Item {
25 id: bottombar
25 id: bottombar
@@ -82,7 +82,7 @@ Item {
82
82
83 readonly property bool centeredHud: parent.width < units.gu(68) // Nexus 7 has 67 gu width
83 readonly property bool centeredHud: parent.width < units.gu(68) // Nexus 7 has 67 gu width
84
84
85− x: centeredHud ? parent.width / 2 - width / 2 : MathLocal.clamp(dragArea.touchStartX - (width / 2), 0, bottombar.width - width)
85+ x: centeredHud ? parent.width / 2 - width / 2 : MathUtils.clamp(dragArea.touchStartX - (width / 2), 0, bottombar.width - width)
86 y: bottombar.height - bottomEdgeButtonCenterDistance - (height / 2) - bottomMargin
86 y: bottombar.height - bottomEdgeButtonCenterDistance - (height / 2) - bottomMargin
87 z: 1
87 z: 1
88 visible: opacity != 0
88 visible: opacity != 0
@@ -136,7 +136,7 @@ Item {
136 readonly property real distanceFromThreshold: (-distance) - distanceThreshold // distance is negative
136 readonly property real distanceFromThreshold: (-distance) - distanceThreshold // distance is negative
137 readonly property real revealDistance: units.gu(2)
137 readonly property real revealDistance: units.gu(2)
138 readonly property real commitDistance: units.gu(6)
138 readonly property real commitDistance: units.gu(6)
139− readonly property real commitProgress: MathLocal.clamp(distanceFromThreshold / commitDistance, 0, 1)
139+ readonly property real commitProgress: MathUtils.clamp(distanceFromThreshold / commitDistance, 0, 1)
140
140
141 onStatusChanged: {
141 onStatusChanged: {
142 if (status === DirectionalDragArea.WaitingForTouch) {
142 if (status === DirectionalDragArea.WaitingForTouch) {
Components/Carousel.qml+26−10
@@ -45,18 +45,22 @@ Item {
45 property int drawBuffer: width / pathItemCount // an "ok" value - but values used from the listView cause loops
45 property int drawBuffer: width / pathItemCount // an "ok" value - but values used from the listView cause loops
46 /// The selected item can be shown in a different size controlled by selectedItemScaleFactor
46 /// The selected item can be shown in a different size controlled by selectedItemScaleFactor
47 property real selectedItemScaleFactor: 1.1
47 property real selectedItemScaleFactor: 1.1
48+ /// The index of the item that should be highlighted
49+ property alias highlightIndex: listView.highlightIndex
50+ /// exposes the delegate of the currentItem
51+ readonly property alias currentItem: listView.currentItem
52+ /// exposes the distance to the next row (only one row in carousel, so it's the topMargins)
53+ readonly property alias verticalSpacing: listView.verticalMargin
48
54
49 /// Emitted when the user clicked on an item
55 /// Emitted when the user clicked on an item
50 /// @param index is the index of the clicked item
56 /// @param index is the index of the clicked item
51− /// @param delegateItem is the clicked component/delegate itself
52 /// @param itemY is y of the clicked delegate
57 /// @param itemY is y of the clicked delegate
53− signal clicked(int index, var delegateItem, real itemY)
58+ signal clicked(int index, real itemY)
54
59
55 /// Emitted when the user pressed and held on an item
60 /// Emitted when the user pressed and held on an item
56 /// @param index is the index of the held item
61 /// @param index is the index of the held item
57− /// @param delegateItem is the held component/delegate itself
58 /// @param itemY is y of the held delegate
62 /// @param itemY is y of the held delegate
59− signal pressAndHold(int index, var delegateItem, real itemY)
63+ signal pressAndHold(int index, real itemY)
60
64
61 implicitHeight: listView.tileHeight * selectedItemScaleFactor
65 implicitHeight: listView.tileHeight * selectedItemScaleFactor
62
66
@@ -75,6 +79,7 @@ Item {
75 property real newContentX: disabledNewContentX
79 property real newContentX: disabledNewContentX
76 property real pathItemCount: referenceWidth / referenceTileWidth
80 property real pathItemCount: referenceWidth / referenceTileWidth
77 property real tileAspectRatio: 1
81 property real tileAspectRatio: 1
82+ property int highlightIndex: -1
78
83
79 /* The positioning and scaling of the items in the carousel is based on the variable
84 /* The positioning and scaling of the items in the carousel is based on the variable
80 'continuousIndex', a continuous real variable between [0, 'carousel.model.count'],
85 'continuousIndex', a continuous real variable between [0, 'carousel.model.count'],
@@ -136,13 +141,14 @@ Item {
136 height: listView.tileHeight
141 height: listView.tileHeight
137 }
142 }
138
143
139− boundsBehavior: Flickable.StopAtBounds
144+ boundsBehavior: Flickable.DragOverBounds
140 cacheBuffer: carousel.cacheBuffer
145 cacheBuffer: carousel.cacheBuffer
141 flickDeceleration: Math.max(1500 * Math.pow(realWidth / referenceWidth, 1.5), 1500) // 1500 is platform default
146 flickDeceleration: Math.max(1500 * Math.pow(realWidth / referenceWidth, 1.5), 1500) // 1500 is platform default
142 maximumFlickVelocity: Math.max(2500 * Math.pow(realWidth / referenceWidth, 1.5), 2500) // 2500 is platform default
147 maximumFlickVelocity: Math.max(2500 * Math.pow(realWidth / referenceWidth, 1.5), 2500) // 2500 is platform default
143 orientation: ListView.Horizontal
148 orientation: ListView.Horizontal
144
149
145 function itemClicked(index, delegateItem) {
150 function itemClicked(index, delegateItem) {
151+ listView.currentIndex = index
146 var x = CarouselJS.getXFromContinuousIndex(index,
152 var x = CarouselJS.getXFromContinuousIndex(index,
147 realWidth,
153 realWidth,
148 realContentWidth,
154 realContentWidth,
@@ -151,11 +157,11 @@ Item {
151 gapToEndPhase,
157 gapToEndPhase,
152 carousel.drawBuffer)
158 carousel.drawBuffer)
153
159
154− if (Math.abs(x - contentX) < 1) {
160+ if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
155 /* We're clicking the selected item and
161 /* We're clicking the selected item and
156 we're in the neighbourhood of radius 1 pixel from it.
162 we're in the neighbourhood of radius 1 pixel from it.
157 Let's emit the clicked signal. */
163 Let's emit the clicked signal. */
158− carousel.clicked(index, delegateItem, delegateItem.y)
164+ carousel.clicked(index, delegateItem.y)
159 return
165 return
160 }
166 }
161
167
@@ -175,11 +181,11 @@ Item {
175 gapToEndPhase,
181 gapToEndPhase,
176 carousel.drawBuffer);
182 carousel.drawBuffer);
177
183
178− if (Math.abs(x - contentX) < 1) {
184+ if (Math.abs(x - contentX) < 1 && delegateItem !== undefined) {
179 /* We're pressAndHold the selected item and
185 /* We're pressAndHold the selected item and
180 we're in the neighbourhood of radius 1 pixel from it.
186 we're in the neighbourhood of radius 1 pixel from it.
181 Let's emit the pressAndHold signal. */
187 Let's emit the pressAndHold signal. */
182− carousel.pressAndHold(index, delegateItem, delegateItem.y);
188+ carousel.pressAndHold(index, delegateItem.y);
183 return;
189 return;
184 }
190 }
185
191
@@ -190,6 +196,12 @@ Item {
190 newContentXAnimation.start();
196 newContentXAnimation.start();
191 }
197 }
192
198
199+ onHighlightIndexChanged: {
200+ if (highlightIndex != -1) {
201+ itemClicked(highlightIndex)
202+ }
203+ }
204+
193 onMovementStarted: {
205 onMovementStarted: {
194 stepAnimation.stop()
206 stepAnimation.stop()
195 newContentXAnimation.stop()
207 newContentXAnimation.stop()
@@ -273,14 +285,18 @@ Item {
273 itemTranslationScale,
285 itemTranslationScale,
274 listView.maximumItemTranslation)
286 listView.maximumItemTranslation)
275
287
288+ readonly property real xTransform: listView.viewTranslation + translationX * listView.scaleFactor
289+ readonly property real center: x - listView.contentX + xTransform - drawBuffer + (width/2)
290+
276 width: listView.tileWidth
291 width: listView.tileWidth
277 height: listView.tileHeight
292 height: listView.tileHeight
278 scale: itemScale * explicitScaleFactor
293 scale: itemScale * explicitScaleFactor
279 sourceComponent: itemComponent
294 sourceComponent: itemComponent
280 z: cachedTiles - Math.abs(index - listView.selectedIndex)
295 z: cachedTiles - Math.abs(index - listView.selectedIndex)
296+ opacity: highlightIndex == -1 ? 1 : (highlightIndex == index ? 0.6 : 0.2)
281
297
282 transform: Translate {
298 transform: Translate {
283− x: listView.viewTranslation + translationX * listView.scaleFactor
299+ x: xTransform
284 }
300 }
285
301
286 Behavior on explicitScaleFactor {
302 Behavior on explicitScaleFactor {
Components/DragHandle.qml+22−24
@@ -17,7 +17,6 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import Ubuntu.Gestures 0.1
19import Ubuntu.Gestures 0.1
20−import "Math.js" as MathLocal
21
20
22/*
21/*
23 Put a DragHandle inside a Showable to enable the user to drag it from that handle.
22 Put a DragHandle inside a Showable to enable the user to drag it from that handle.
@@ -48,9 +47,12 @@ EdgeDragArea {
48 id: dragArea
47 id: dragArea
49 objectName: "dragHandle"
48 objectName: "dragHandle"
50
49
51− // Disable gesture detection by default when hinting is used.
50+ // Disable most of the gesture recognition parameters by default when hinting is used as
52− // It doesn't make sense to have both.
51+ // it conflicts with the hinting idea.
52+ // The only part we keep in this situation is that it must be a single-finger gesture.
53− distanceThreshold: hintDisplacement > 0 ? 0 : units.gu(1.5)
53+ distanceThreshold: hintDisplacement > 0 ? 0 : defaultDistanceThreshold
54+ maxSilenceTime: hintDisplacement > 0 ? 60*60*1000 : defaultMaxSilenceTime
55+ maxDeviation: hintDisplacement > 0 ? 999999 : defaultMaxDeviation
54
56
55 property bool stretch: false
57 property bool stretch: false
56
58
@@ -113,8 +115,8 @@ EdgeDragArea {
113 }
115 }
114 }
116 }
115
117
116− function limitMovement(step) {
118+ function limitMovement(inputStep) {
117− var targetValue = MathLocal.clamp(dragParent[targetProp] + step, minValue, maxValue);
119+ var targetValue = MathUtils.clamp(dragParent[targetProp] + inputStep, minValue, maxValue);
118 var step = targetValue - dragParent[targetProp];
120 var step = targetValue - dragParent[targetProp];
119
121
120 if (hintDisplacement == 0) {
122 if (hintDisplacement == 0) {
@@ -181,29 +183,25 @@ EdgeDragArea {
181 }
183 }
182 }
184 }
183
185
184− onDraggingChanged: {
185− if (dragging) {
186− if (hintDisplacement > 0) {
187− hintingAnimation.targetValue = d.startValue;
188− hintingAnimation.start();
189− }
190− } else {
191− hintingAnimation.stop();
192− }
193− }
194−
195 onStatusChanged: {
186 onStatusChanged: {
196 if (status === DirectionalDragArea.WaitingForTouch) {
187 if (status === DirectionalDragArea.WaitingForTouch) {
188+ hintingAnimation.stop();
197 if (d.previousStatus === DirectionalDragArea.Recognized) {
189 if (d.previousStatus === DirectionalDragArea.Recognized) {
198 d.onFinishedRecognizedGesture();
190 d.onFinishedRecognizedGesture();
191+ } else /* d.previousStatus === DirectionalDragArea.Undecided */ {
192+ // Gesture was rejected.
193+ d.rollbackDrag();
194+ }
195+ } else /* Undecided || Recognized */ {
196+ if (d.previousStatus === DirectionalDragArea.WaitingForTouch ||
197+ d.previousStatus === undefined) {
198+ dragEvaluator.reset();
199+ d.startValue = parent[d.targetProp];
200+ }
201+ if (hintDisplacement > 0) {
202+ hintingAnimation.targetValue = d.startValue;
203+ hintingAnimation.start();
199 }
204 }
200− d.startValue = parent[d.targetProp];
201− }
202−
203− if (d.previousStatus === DirectionalDragArea.WaitingForTouch ||
204− d.previousStatus === undefined) {
205− dragEvaluator.reset();
206− d.startValue = parent[d.targetProp];
207 }
205 }
208
206
209 d.previousStatus = status;
207 d.previousStatus = status;
Components/DraggingArea.qml+1−2
@@ -16,7 +16,6 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19−import "Math.js" as MathLocal
20
19
21MouseArea {
20MouseArea {
22 id: draggingArea
21 id: draggingArea
@@ -26,7 +25,7 @@ MouseArea {
26 property real dragVelocity: 0
25 property real dragVelocity: 0
27 property real dragValue: (orientation == Qt.Vertical ? (mouseY - __pressedPosition.y)
26 property real dragValue: (orientation == Qt.Vertical ? (mouseY - __pressedPosition.y)
28 : (mouseX - __pressedPosition.x))
27 : (mouseX - __pressedPosition.x))
29− property real lateralPosition: orientation == Qt.Horizontal ? MathLocal.clamp(mouseY, 0, height) : MathLocal.clamp(mouseX, 0, width)
28+ property real lateralPosition: orientation == Qt.Horizontal ? MathUtils.clamp(mouseY, 0, height) : MathUtils.clamp(mouseX, 0, width)
30 property point __pressedPosition: Qt.point(0, 0)
29 property point __pressedPosition: Qt.point(0, 0)
31 property var __dragEvents: []
30 property var __dragEvents: []
32 property bool clickValidated: true
31 property bool clickValidated: true
Components/EdgeDemoOverlay.qml+2
@@ -105,6 +105,8 @@ Showable {
105 visible: overlay.active
105 visible: overlay.active
106
106
107 MouseArea {
107 MouseArea {
108+ objectName: "backgroundShadeMouseArea"
109+
108 anchors.fill: parent
110 anchors.fill: parent
109 enabled: overlay.edge == "none" && overlay.opacity == 1.0
111 enabled: overlay.edge == "none" && overlay.opacity == 1.0
110 onClicked: overlay.doSkip()
112 onClicked: overlay.doSkip()
Components/EdgeDragArea.qml+12−4
@@ -29,8 +29,16 @@ DirectionalDragArea {
29 //
29 //
30 // The idea here is that it's better having lax rules than false negatives.
30 // The idea here is that it's better having lax rules than false negatives.
31 // False negatives are very frustrating to the user.
31 // False negatives are very frustrating to the user.
32− maxDeviation: units.gu(3)
32+ maxDeviation: defaultMaxDeviation
33− wideningAngle: 50
33+ wideningAngle: defaultWideningAngle
34− distanceThreshold: units.gu(1.5)
34+ distanceThreshold: defaultDistanceThreshold
35+ minSpeed: defaultMinSpeed
36+ maxSilenceTime: defaultMaxSilenceTime
37+
38+ readonly property real defaultMaxDeviation: units.gu(3)
39+ readonly property real defaultWideningAngle: 50
40+ readonly property real defaultDistanceThreshold: units.gu(1.5)
35− minSpeed: units.gu(0) // some people were getting false negatives with it enabled.
41+ // some people were getting false negatives with it enabled.
42+ readonly property real defaultMinSpeed: units.gu(0)
43+ readonly property int defaultMaxSilenceTime: 200
36}
44}
Components/FilterGrid.qml+3
@@ -54,6 +54,7 @@ Item {
54 property alias delegateWidth: iconTileGrid.delegateWidth
54 property alias delegateWidth: iconTileGrid.delegateWidth
55 property alias delegateHeight: iconTileGrid.delegateHeight
55 property alias delegateHeight: iconTileGrid.delegateHeight
56 property alias verticalSpacing: iconTileGrid.verticalSpacing
56 property alias verticalSpacing: iconTileGrid.verticalSpacing
57+ readonly property alias margins: iconTileGrid.margins
57 property alias delegate: iconTileGrid.delegate
58 property alias delegate: iconTileGrid.delegate
58 property alias cellWidth: iconTileGrid.cellWidth
59 property alias cellWidth: iconTileGrid.cellWidth
59 property alias cellHeight: iconTileGrid.cellHeight
60 property alias cellHeight: iconTileGrid.cellHeight
@@ -62,6 +63,8 @@ Item {
62 readonly property alias flicking: iconTileGrid.flicking
63 readonly property alias flicking: iconTileGrid.flicking
63 readonly property alias moving: iconTileGrid.moving
64 readonly property alias moving: iconTileGrid.moving
64 readonly property alias pressDelay: iconTileGrid.pressDelay
65 readonly property alias pressDelay: iconTileGrid.pressDelay
66+ property alias highlightIndex: iconTileGrid.highlightIndex
67+ readonly property alias currentItem: iconTileGrid.currentItem
65
68
66 height: !filterAnimation.running ? childrenRect.height : height
69 height: !filterAnimation.running ? childrenRect.height : height
67 clip: filterAnimation.running
70 clip: filterAnimation.running
Components/LazyImage.qml+2−2
@@ -100,10 +100,10 @@ Item {
100 verticalAlignment: Image.AlignVCenter
100 verticalAlignment: Image.AlignVCenter
101 sourceSize.width: root.scaleTo == "width" ? root.width
101 sourceSize.width: root.scaleTo == "width" ? root.width
102 : root.scaleTo == "fit" && root.width < root.height ? root.width
102 : root.scaleTo == "fit" && root.width < root.height ? root.width
103− : undefined
103+ : 0
104 sourceSize.height: root.scaleTo == "height" ? root.height
104 sourceSize.height: root.scaleTo == "height" ? root.height
105 : root.scale == "fit" && root.height < root.width ? root.height
105 : root.scale == "fit" && root.height < root.width ? root.height
106− : undefined
106+ : 0
107 }
107 }
108 }
108 }
109
109
Components/PageHeader.qml+4
@@ -48,6 +48,10 @@ Item {
48 searchField.focus = false;
48 searchField.focus = false;
49 }
49 }
50
50
51+ function unfocus() {
52+ searchField.focus = false;
53+ }
54+
51 Connections {
55 Connections {
52 target: greeter
56 target: greeter
53 onShownChanged: if (shown) resetSearch()
57 onShownChanged: if (shown) resetSearch()
Components/PinPadButton.qml+40−13
@@ -21,24 +21,51 @@ Item {
21 id: root
21 id: root
22
22
23 property alias text: label.text
23 property alias text: label.text
24− property alias iconName: icon.name
24+ property alias subText: subTextLabel.text
25+ property string iconName
25
26
26 signal clicked()
27 signal clicked()
27
28
28− Label {
29+ Column {
29− id: label
30 anchors.centerIn: parent
30 anchors.centerIn: parent
31− color: "#f3f3e7"
31+ width: parent.width
32− fontSize: "large"
32+ height: childrenRect.height
33− font.weight: Font.DemiBold
34− }
35
33
34+ Item {
35+ anchors {
36+ left: parent.left
37+ right: parent.right
38+ }
39+ height: label.visible || icon.visible ? Math.max(label.height, icon.height) : 0
40+
41+ Label {
42+ id: label
43+ anchors.centerIn: parent
44+ width: parent.width
45+ horizontalAlignment: Text.AlignHCenter
46+ color: "#f3f3e7"
47+ fontSize: "large"
48+ font.weight: Font.DemiBold
49+ visible: text.length > 0
50+ }
51+
36− Icon {
52+ Icon {
37− id: icon
53+ id: icon
38− height: units.gu(3)
54+ height: units.gu(3)
39− width: height
55+ width: height
40− anchors.centerIn: parent
56+ anchors.centerIn: parent
57+ name: root.iconName
41− color: "#f3f3e7"
58+ color: "#f3f3e7"
59+ visible: name.length > 0
60+ }
61+ }
62+ Label {
63+ id: subTextLabel
64+ fontSize: "small"
65+ color: "grey"
66+ anchors.horizontalCenter: parent.horizontalCenter
67+ visible: text.length > 0
68+ }
42 }
69 }
43
70
44 MouseArea {
71 MouseArea {
Components/ResponsiveGridView.qml+10
@@ -26,6 +26,7 @@ Item {
26 property int maximumNumberOfColumns: 6
26 property int maximumNumberOfColumns: 6
27 readonly property int columns: gridView.columns
27 readonly property int columns: gridView.columns
28 property alias verticalSpacing: gridView.verticalSpacing
28 property alias verticalSpacing: gridView.verticalSpacing
29+ readonly property alias margins: gridView.margin
29 property int delegateWidth
30 property int delegateWidth
30 property int delegateHeight
31 property int delegateHeight
31 property alias model: gridView.model
32 property alias model: gridView.model
@@ -41,6 +42,8 @@ Item {
41 readonly property alias pressDelay: gridView.pressDelay
42 readonly property alias pressDelay: gridView.pressDelay
42 property alias delegateCreationBegin: gridView.delegateCreationBegin
43 property alias delegateCreationBegin: gridView.delegateCreationBegin
43 property alias delegateCreationEnd: gridView.delegateCreationEnd
44 property alias delegateCreationEnd: gridView.delegateCreationEnd
45+ property alias highlightIndex: gridView.highlightIndex
46+ readonly property alias currentItem: gridView.currentItem
44
47
45 function contentHeightForRows(rows) {
48 function contentHeightForRows(rows) {
46 return rows * cellHeight + verticalSpacing
49 return rows * cellHeight + verticalSpacing
@@ -77,8 +80,15 @@ Item {
77 property real horizontalSpacing: spacingForColumns(columns)
80 property real horizontalSpacing: spacingForColumns(columns)
78 property real verticalSpacing: horizontalSpacing
81 property real verticalSpacing: horizontalSpacing
79 property int margin: allocatableHorizontalSpace - columns * horizontalSpacing
82 property int margin: allocatableHorizontalSpace - columns * horizontalSpacing
83+ property int highlightIndex: -1
80
84
81 cellWidth: delegateWidth + horizontalSpacing
85 cellWidth: delegateWidth + horizontalSpacing
82 cellHeight: delegateHeight + verticalSpacing
86 cellHeight: delegateHeight + verticalSpacing
87+
88+ onHighlightIndexChanged: {
89+ if (highlightIndex != -1) {
90+ currentIndex = highlightIndex
91+ }
92+ }
83 }
93 }
84}
94}
Components/Revealer.qml+1−2
@@ -16,7 +16,6 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19−import "Math.js" as MathLocal
20
19
21Item {
20Item {
22 id: revealer
21 id: revealer
@@ -95,7 +94,7 @@ Item {
95 onClosedValueChanged: if (!__opened && !dragging) target[boundProperty] = closedValue
94 onClosedValueChanged: if (!__opened && !dragging) target[boundProperty] = closedValue
96
95
97 function __computeValue(dragPosition) {
96 function __computeValue(dragPosition) {
98− return MathLocal.clamp(dragToValue(dragPosition), __hintValue, openedValue)
97+ return MathUtils.clamp(dragToValue(dragPosition), __hintValue, openedValue)
99 }
98 }
100
99
101 function __open() {
100 function __open() {
Components/Stage.qml+8−7
@@ -482,19 +482,20 @@ Showable {
482 switchToApplicationAnimationController.progress += 0.4 * delta
482 switchToApplicationAnimationController.progress += 0.4 * delta
483 }
483 }
484
484
485− property bool gotRejected: false
485+ property int lastStatus: -1
486
486
487 onStatusChanged: {
487 onStatusChanged: {
488 if (status == DirectionalDragArea.Undecided) {
488 if (status == DirectionalDragArea.Undecided) {
489− gotRejected = false
490 onUndecided();
489 onUndecided();
491− } else if (status == DirectionalDragArea.Rejected) {
492− switchToApplicationAnimationController.completeToBeginningWithSignal();
493− gotRejected = true;
494 } else if (status == DirectionalDragArea.WaitingForTouch) {
490 } else if (status == DirectionalDragArea.WaitingForTouch) {
495− if (!gotRejected)
491+ if (lastStatus == DirectionalDragArea.Undecided) {
492+ // got rejected
493+ switchToApplicationAnimationController.completeToBeginningWithSignal();
494+ } else {
496− onGestureEnded()
495+ onGestureEnded();
496+ }
497 }
497 }
498+ lastStatus = status;
498 }
499 }
499
500
500 function onUndecided() {
501 function onUndecided() {
Components/Tile.qml+9
@@ -26,5 +26,14 @@ AbstractButton {
26 property int imageHeight
26 property int imageHeight
27 property int maximumLineCount: 1
27 property int maximumLineCount: 1
28
28
29+ readonly property int center: (index % GridView.view.columns * width) + (width / 2)
30+
31+ opacity: GridView.view.highlightIndex === -1 ? 1 :
32+ GridView.view.highlightIndex === index ? 0.6 : 0.2
33+
34+ Behavior on opacity {
35+ UbuntuNumberAnimation {}
36+ }
37+
29 style: TileStyle {}
38 style: TileStyle {}
30}
39}
Components/Time.js+9−9
@@ -16,15 +16,15 @@
16
16
17.pragma library
17.pragma library
18
18
19−var factors = {
19+var factors = [
20− "second": [ 1000, "a second ago", "in a second", "%1 seconds ago", "in %1 seconds" ],
20+ [ 1000, "a second ago", "in a second", "%1 seconds ago", "in %1 seconds" ],
21− "minute": [ 60, "a minute ago", "in a minute", "%1 minutes ago", "in %1 minutes" ],
21+ [ 60, "a minute ago", "in a minute", "%1 minutes ago", "in %1 minutes" ],
22− "hour": [ 60, "an hour ago", "in an hour", "%1 hours ago", "in %1 hours" ],
22+ [ 60, "an hour ago", "in an hour", "%1 hours ago", "in %1 hours" ],
23− "day": [ 24, "yesterday", "tomorrow", "%1 days ago", "in %1 days" ],
23+ [ 24, "yesterday", "tomorrow", "%1 days ago", "in %1 days" ],
24− "week": [ 7, "a week ago", "in a week", "about %1 weeks ago", "in about %1 weeks" ],
24+ [ 7, "a week ago", "in a week", "about %1 weeks ago", "in about %1 weeks" ],
25− "month": [ 4.35, "a month ago", "in a month", "%1 months ago", "in %1 months" ], // == 365.25 days / 12 months / 7 days
25+ [ 4.35, "a month ago", "in a month", "%1 months ago", "in %1 months" ], // == 365.25 days / 12 months / 7 days
26− "year": [ 12, "a year ago", "in a year", "%1 years ago", "in %1 years" ]
26+ [ 12, "a year ago", "in a year", "%1 years ago", "in %1 years" ]
27−}
27+]
28
28
29function readableFromNow(date, now) {
29function readableFromNow(date, now) {
30 var then = new Date(date);
30 var then = new Date(date);
Components/UbuntuShapeForItem.qml+1
@@ -31,6 +31,7 @@ Item {
31
31
32 ShaderEffectSource {
32 ShaderEffectSource {
33 id: source
33 id: source
34+ anchors.centerIn: parent // Placed under shape, so it's hidden
34 width: 1
35 width: 1
35 height: 1
36 height: 1
36 hideSource: true
37 hideSource: true
Dash/Apps/AppPreview.qml+9
@@ -44,6 +44,15 @@ GenericPreview {
44 model: previewData.infoMap["more-screenshots"] != null ? previewData.infoMap["more-screenshots"].value : [previewData.image]
44 model: previewData.infoMap["more-screenshots"] != null ? previewData.infoMap["more-screenshots"].value : [previewData.image]
45 cacheBuffer: width * 3
45 cacheBuffer: width * 3
46
46
47+ // FIXME: Because of ListViews inside ListViews inside Flickables inside ListViews (and some more)
48+ // we finally reached the point where this ListView doesn't correctly get swipe input any more but
49+ // instead the parent ListView is the one that is swiped. This MouseArea sort of creates a blocking
50+ // layer to make sure this ListView can be swiped, regardless of what's behind it.
51+ MouseArea {
52+ anchors.fill: parent
53+ enabled: parent.contentWidth > parent.width
54+ }
55+
47 LazyImage {
56 LazyImage {
48 objectName: "placeholderScreenshot"
57 objectName: "placeholderScreenshot"
49 anchors {
58 anchors {
Dash/Apps/ApplicationsFilterGrid.qml+14−5
@@ -19,7 +19,7 @@ import "../../Components"
19import "../../Applications"
19import "../../Applications"
20
20
21FilterGrid {
21FilterGrid {
22− id: filterGrid
22+ id: filtergrid
23
23
24 filter: false
24 filter: false
25 minimumHorizontalSpacing: units.gu(0.5)
25 minimumHorizontalSpacing: units.gu(0.5)
@@ -28,9 +28,11 @@ FilterGrid {
28 delegateHeight: units.gu(9.5)
28 delegateHeight: units.gu(9.5)
29 verticalSpacing: units.gu(2)
29 verticalSpacing: units.gu(2)
30
30
31− signal clicked(int index, variant data)
31+ signal clicked(int index, real itemY)
32+ signal pressAndHold(int index, real itemY)
32
33
33 delegate: Tile {
34 delegate: Tile {
35+ id: tile
34 objectName: "delegate" + index
36 objectName: "delegate" + index
35 Application {
37 Application {
36 id: application
38 id: application
@@ -44,12 +46,19 @@ FilterGrid {
44
46
45 property string icon: model.icon ? model.icon : "../../graphics/applicationIcons/" + application.icon + ".png" // FIXME: this is temporary
47 property string icon: model.icon ? model.icon : "../../graphics/applicationIcons/" + application.icon + ".png" // FIXME: this is temporary
46
48
47− width: filterGrid.cellWidth
49+ width: filtergrid.cellWidth
48− height: filterGrid.cellHeight
50+ height: filtergrid.cellHeight
49 text: model.title ? model.title : application.name // FIXME: this is temporary
51 text: model.title ? model.title : application.name // FIXME: this is temporary
50 imageWidth: units.gu(8)
52 imageWidth: units.gu(8)
51 imageHeight: units.gu(7.5)
53 imageHeight: units.gu(7.5)
52 source: icon
54 source: icon
53− onClicked: filterGrid.clicked(index, application.desktopFile);
55+
56+ onClicked: {
57+ filtergrid.clicked(index, tile.y)
58+ }
59+
60+ onPressAndHold: {
61+ filtergrid.pressAndHold(index, tile.y)
62+ }
54 }
63 }
55}
64}
Dash/Apps/DashPluginFilterGrid.qml+2−4
@@ -37,13 +37,11 @@ GenericFilterGrid {
37 }
37 }
38
38
39 onClicked: {
39 onClicked: {
40− var data = { model: model }
41− filtergrid.clicked(index, data, tile.y)
40+ filtergrid.clicked(index, tile.y)
42 }
41 }
43
42
44 onPressAndHold: {
43 onPressAndHold: {
45− var data = { model: model }
46− filtergrid.pressAndHold(index, data, tile.y)
44+ filtergrid.pressAndHold(index, tile.y)
47 }
45 }
48 }
46 }
49}
47}
Dash/Apps/RunningApplicationTile.qml−2
@@ -105,8 +105,6 @@ AbstractButton {
105 baseline: parent.bottom
105 baseline: parent.bottom
106 left: parent.left
106 left: parent.left
107 right: parent.right
107 right: parent.right
108− leftMargin: units.gu(1)
109− rightMargin: units.gu(1)
110 }
108 }
111 text: (application) ? application.name : ""
109 text: (application) ? application.name : ""
112
110
Dash/DashBar.qml+2−2
@@ -35,7 +35,7 @@ Item {
35
35
36 function startNavigation() {
36 function startNavigation() {
37 timeout.stop()
37 timeout.stop()
38− panel.opened = true
38+ panel.open()
39 }
39 }
40
40
41 function stopNavigation() {
41 function stopNavigation() {
@@ -43,7 +43,7 @@ Item {
43 }
43 }
44
44
45 function finishNavigation() {
45 function finishNavigation() {
46− panel.opened = false
46+ panel.close()
47 }
47 }
48
48
49 Timer {
49 Timer {
Dash/DashContent.qml+2−2
@@ -116,8 +116,8 @@ Item {
116 source: scopeMapper.map(scope.id)
116 source: scopeMapper.map(scope.id)
117 objectName: scope.id + " loader"
117 objectName: scope.id + " loader"
118
118
119− readonly property bool previewShown: item.previewShown
119+ readonly property bool previewShown: item ? item.previewShown : false
120− readonly property bool moving: item.moving
120+ readonly property bool moving: item ? item.moving : false
121
121
122 // these are needed for autopilot tests
122 // these are needed for autopilot tests
123 readonly property string scopeId: scope.id
123 readonly property string scopeId: scope.id
Dash/DashPreview.qml+1−3
@@ -17,7 +17,7 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19
19
20−Rectangle {
20+Item {
21 id: root
21 id: root
22
22
23 property int keyboardSize: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0
23 property int keyboardSize: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0
@@ -36,7 +36,6 @@ Rectangle {
36 readonly property int columnWidth: narrowMode ? contentRow.width : (contentRow.width / 3) - contentRow.spacing
36 readonly property int columnWidth: narrowMode ? contentRow.width : (contentRow.width / 3) - contentRow.spacing
37 readonly property int contentSpacing: units.gu(3)
37 readonly property int contentSpacing: units.gu(3)
38
38
39− color: Qt.rgba(0, 0, 0, .3)
40 clip: true
39 clip: true
41
40
42 function ensureVisible(item) {
41 function ensureVisible(item) {
@@ -61,7 +60,6 @@ Rectangle {
61 anchors.fill: parent
60 anchors.fill: parent
62 }
61 }
63
62
64−
65 Row {
63 Row {
66 id: contentRow
64 id: contentRow
67 anchors {
65 anchors {
tests/mocks/QMenuModel/UnityMenuModel.qml → Dash/DashPreviewPlaceholder.qmlrenamed+6−7
@@ -1,9 +1,6 @@
1/*
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
3 *
4− * Authors:
5− * Mirco Müller <mirco.mueller@canonical.com>
6− *
7 * 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
8 * 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
9 * the Free Software Foundation; version 3.
6 * the Free Software Foundation; version 3.
@@ -18,9 +15,11 @@
18 */
15 */
19
16
20import QtQuick 2.0
17import QtQuick 2.0
18+import Ubuntu.Components 0.1
21
19
22−QtObject {
20+DashPreview {
23− property variant busName
21+ ActivityIndicator {
24− property variant actions
22+ anchors.centerIn: parent
25− property variant menuObjectPath
23+ running: true
24+ }
26}
25}
Dash/Generic/GenericCarouselLoader.qmlnew file+30
@@ -0,0 +1,30 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+
20+Loader {
21+ property var model: null
22+ property url carouselUrl: "GenericCarousel.qml"
23+ property url filtergridUrl: "GenericFilterGrid.qml"
24+
25+ source: model.count > 6 ? carouselUrl : filtergridUrl // FIXME do not hardcode 6, but retrieve correct minimum required count
26+
27+ onLoaded: {
28+ item.model = Qt.binding(function() { return model; })
29+ }
30+}
Dash/Generic/GenericFilterGrid.qml+4−6
@@ -28,8 +28,8 @@ FilterGrid {
28 property int iconWidth: units.gu(8)
28 property int iconWidth: units.gu(8)
29 property int iconHeight: units.gu(7.5)
29 property int iconHeight: units.gu(7.5)
30
30
31− signal clicked(int index, var delegateItem, real itemY)
31+ signal clicked(int index, real itemY)
32− signal pressAndHold(int index, var delegateItem, real itemY)
32+ signal pressAndHold(int index, real itemY)
33
33
34 delegate: Tile {
34 delegate: Tile {
35 id: tile
35 id: tile
@@ -42,13 +42,11 @@ FilterGrid {
42 source: model.icon
42 source: model.icon
43
43
44 onClicked: {
44 onClicked: {
45− var data = { model: model }
46− filtergrid.clicked(index, data, tile.y)
45+ filtergrid.clicked(index, tile.y)
47 }
46 }
48
47
49 onPressAndHold: {
48 onPressAndHold: {
50− var data = { model: model }
51− filtergrid.pressAndHold(index, data, tile.y)
49+ filtergrid.pressAndHold(index, tile.y)
52 }
50 }
53 }
51 }
54}
52}
Dash/Generic/WeatherFilterGrid.qml+2−4
@@ -37,13 +37,11 @@ GenericFilterGrid {
37 style: FlatTileStyle {}
37 style: FlatTileStyle {}
38
38
39 onClicked: {
39 onClicked: {
40− var data = { model: model }
41− filtergrid.clicked(index, data, tile.y)
40+ filtergrid.clicked(index, tile.y)
42 }
41 }
43
42
44 onPressAndHold: {
43 onPressAndHold: {
45− var data = { model: model }
46− filtergrid.pressAndHold(index, data, tile.y)
44+ filtergrid.pressAndHold(index, tile.y)
47 }
45 }
48 }
46 }
49}
47}
Dash/GenericScopeView.qml+229−67
@@ -21,14 +21,14 @@ import "../Components/ListItems" as ListItems
21
21
22ScopeView {
22ScopeView {
23 id: scopeView
23 id: scopeView
24− readonly property alias previewShown: previewLoader.onScreen
24+ readonly property alias previewShown: previewListView.onScreen
25 property bool enableHeightBehaviorOnNextCreation: false
25 property bool enableHeightBehaviorOnNextCreation: false
26
26
27 moving: categoryView.moving
27 moving: categoryView.moving
28
28
29 onIsCurrentChanged: {
29 onIsCurrentChanged: {
30 pageHeader.resetSearch();
30 pageHeader.resetSearch();
31− previewLoader.open = false;
31+ previewListView.open = false;
32 }
32 }
33
33
34 onMovementStarted: categoryView.showHeader()
34 onMovementStarted: categoryView.showHeader()
@@ -57,9 +57,8 @@ ScopeView {
57
57
58 Connections {
58 Connections {
59 target: scopeView.scope
59 target: scopeView.scope
60− onShowDash: previewLoader.open = false;
60+ onShowDash: previewListView.open = false;
61− onHideDash: previewLoader.open = false;
61+ onHideDash: previewListView.open = false;
62− onActivated: previewLoader.closePreviewSpinner();
63 }
62 }
64
63
65 ScopeListView {
64 ScopeListView {
@@ -67,12 +66,18 @@ ScopeView {
67 objectName: "categoryListView"
66 objectName: "categoryListView"
68 anchors.fill: parent
67 anchors.fill: parent
69 model: scopeView.categories
68 model: scopeView.categories
70− forceNoClip: previewLoader.onScreen
69+ forceNoClip: previewListView.onScreen
71
70
72 onAtYEndChanged: if (atYEnd) endReached()
71 onAtYEndChanged: if (atYEnd) endReached()
73 onMovingChanged: if (moving && atYEnd) endReached()
72 onMovingChanged: if (moving && atYEnd) endReached()
74
73
75 property string expandedCategoryId: ""
74 property string expandedCategoryId: ""
75+ signal correctExpandedCategory();
76+
77+ Behavior on contentY {
78+ enabled: previewListView.open
79+ UbuntuNumberAnimation {}
80+ }
76
81
77 delegate: ListItems.Base {
82 delegate: ListItems.Base {
78 id: baseItem
83 id: baseItem
@@ -124,33 +129,50 @@ ScopeView {
124 Connections {
129 Connections {
125 target: rendererLoader.item
130 target: rendererLoader.item
126 onClicked: {
131 onClicked: {
132+ // Prepare the preview in case activate() triggers a preview only
127 effect.positionPx = mapToItem(categoryView, 0, itemY).y
133 effect.positionPx = mapToItem(categoryView, 0, itemY).y
134+ previewListView.categoryId = categoryId
135+ previewListView.categoryDelegate = rendererLoader.item
136+ previewListView.model = target.model;
137+ previewListView.init = true;
138+ previewListView.currentIndex = index;
139+
140+ var item = target.model.get(index);
141+
142+ if ((scopeView.scope.id == "applications.scope" && categoryId == "installed")
143+ || (scopeView.scope.id == "home.scope" && categoryId == "applications.scope")) {
128− scopeView.scope.activate(delegateItem.model.uri,
144+ scopeView.scope.activate(item.uri, item.icon, item.category, 0, item.mimetype, item.title,
129− delegateItem.model.icon,
145+ item.comment, item.dndUri, item.metadata)
130− delegateItem.model.category,
146+ } else {
131− 0,
147+ previewListView.open = true
132− delegateItem.model.mimetype,
148+
133− delegateItem.model.title,
149+ scopeView.scope.preview( item.uri, item.icon, item.category, 0, item.mimetype, item.title,
134− delegateItem.model.comment,
150+ item.comment, item.dndUri, item.metadata)
135− delegateItem.model.dndUri,
151+ }
136− delegateItem.model.metadata)
137 }
152 }
138 onPressAndHold: {
153 onPressAndHold: {
139 effect.positionPx = mapToItem(categoryView, 0, itemY).y
154 effect.positionPx = mapToItem(categoryView, 0, itemY).y
155+ previewListView.categoryId = categoryId
156+ previewListView.categoryDelegate = rendererLoader.item
157+ previewListView.model = target.model;
158+ previewListView.init = true;
159+ previewListView.currentIndex = index;
160+ previewListView.open = true
161+
162+ var item = target.model.get(index)
140− scopeView.scope.preview( delegateItem.model.uri,
163+ scopeView.scope.preview( item.uri, item.icon, item.category, 0, item.mimetype, item.title,
141− delegateItem.model.icon,
164+ item.comment, item.dndUri, item.metadata)
142− delegateItem.model.category,
143− 0,
144− delegateItem.model.mimetype,
145− delegateItem.model.title,
146− delegateItem.model.comment,
147− delegateItem.model.dndUri,
148− delegateItem.model.metadata)
149 }
165 }
150 }
166 }
151 Connections {
167 Connections {
152 target: categoryView
168 target: categoryView
153 onExpandedCategoryIdChanged: {
169 onExpandedCategoryIdChanged: {
170+ collapseAllButExpandedCategory();
171+ }
172+ onCorrectExpandedCategory: {
173+ collapseAllButExpandedCategory();
174+ }
175+ function collapseAllButExpandedCategory() {
154 var item = rendererLoader.item;
176 var item = rendererLoader.item;
155 if (item.expandable) {
177 if (item.expandable) {
156 var shouldFilter = categoryId != categoryView.expandedCategoryId;
178 var shouldFilter = categoryId != categoryView.expandedCategoryId;
@@ -158,13 +180,15 @@ ScopeView {
158 // If the filter animation will be seen start it, otherwise, just flip the switch
180 // If the filter animation will be seen start it, otherwise, just flip the switch
159 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
181 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
160 var growingVisible = !shouldFilter && y + height < categoryView.height;
182 var growingVisible = !shouldFilter && y + height < categoryView.height;
183+ if (!previewListView.open || !shouldFilter) {
161− if (shrinkingVisible || growingVisible) {
184+ if (shrinkingVisible || growingVisible) {
162− item.startFilterAnimation(shouldFilter)
185+ item.startFilterAnimation(shouldFilter)
163− } else {
186+ } else {
164− item.filter = shouldFilter;
187+ item.filter = shouldFilter;
165− }
188+ }
166− if (!shouldFilter) {
189+ if (!shouldFilter && !previewListView.open) {
167− categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
190+ categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
191+ }
168 }
192 }
169 }
193 }
170 }
194 }
@@ -238,26 +262,27 @@ ScopeView {
238 rendererId = getDefaultRendererId(contentType);
262 rendererId = getDefaultRendererId(contentType);
239 }
263 }
240 switch (rendererId) {
264 switch (rendererId) {
265+ case "carousel": {
266+ switch (contentType) {
267+ case "music": return "Music/MusicCarouselLoader.qml";
268+ case "video": return "Video/VideoCarouselLoader.qml";
269+ default: return "Generic/GenericCarouselLoader.qml";
270+ }
271+ }
241 case "grid": {
272 case "grid": {
242 switch (contentType) {
273 switch (contentType) {
243− case "video": return "Video/VideoFilterGrid.qml";
244− case "music": return "Music/MusicFilterGrid.qml";
245 case "apps": {
274 case "apps": {
246 if (rendererHint == "toggled")
275 if (rendererHint == "toggled")
247 return "Apps/DashPluginFilterGrid.qml";
276 return "Apps/DashPluginFilterGrid.qml";
248 else
277 else
249 return "Generic/GenericFilterGrid.qml";
278 return "Generic/GenericFilterGrid.qml";
250 }
279 }
280+ case "music": return "Music/MusicFilterGrid.qml";
281+ case "video": return "Video/VideoFilterGrid.qml";
251 case "weather": return "Generic/WeatherFilterGrid.qml";
282 case "weather": return "Generic/WeatherFilterGrid.qml";
252 default: return "Generic/GenericFilterGrid.qml";
283 default: return "Generic/GenericFilterGrid.qml";
253 }
284 }
254 }
285 }
255− case "carousel": {
256− switch (contentType) {
257− case "music": return "Music/MusicCarousel.qml";
258− default: return "Generic/GenericCarousel.qml";
259− }
260− }
261 case "special": {
286 case "special": {
262 switch (contentType) {
287 switch (contentType) {
263 case "apps": return "Apps/RunningApplicationsGrid.qml";
288 case "apps": return "Apps/RunningApplicationsGrid.qml";
@@ -270,6 +295,7 @@ ScopeView {
270
295
271 OpenEffect {
296 OpenEffect {
272 id: effect
297 id: effect
298+ objectName: "openEffect"
273 anchors {
299 anchors {
274 fill: parent
300 fill: parent
275 bottomMargin: -bottomOverflow
301 bottomMargin: -bottomOverflow
@@ -282,29 +308,44 @@ ScopeView {
282 topOpacity: (1 - gap * 1.2)
308 topOpacity: (1 - gap * 1.2)
283 bottomGapPx: positionPx + gap * (targetBottomGapPx - positionPx)
309 bottomGapPx: positionPx + gap * (targetBottomGapPx - positionPx)
284 bottomOverflow: units.gu(20)
310 bottomOverflow: units.gu(20)
285− bottomOpacity: 1 - (gap * 0.8)
311+ live: !expansionAnimation.running
286
312
287 property int targetBottomGapPx: height - units.gu(8) - bottomOverflow
313 property int targetBottomGapPx: height - units.gu(8) - bottomOverflow
288− property real gap: previewLoader.open ? 1.0 : 0.0
314+ property real gap: previewListView.open ? 1.0 : 0.0
289
315
290 Behavior on gap {
316 Behavior on gap {
291 NumberAnimation {
317 NumberAnimation {
318+ id: expansionAnimation
292 duration: 200
319 duration: 200
293 easing.type: Easing.InOutQuad
320 easing.type: Easing.InOutQuad
294 onRunningChanged: {
321 onRunningChanged: {
295− if (!previewLoader.open && !running) {
322+ if (!previewListView.open && !running) {
296− previewLoader.onScreen = false
323+ previewListView.onScreen = false
297 }
324 }
298 }
325 }
299 }
326 }
300 }
327 }
328+ Behavior on positionPx {
329+ enabled: previewListView.open
330+ UbuntuNumberAnimation {}
331+ }
301 }
332 }
302
333
303 Connections {
334 Connections {
304 target: scopeView.scope
335 target: scopeView.scope
305 onPreviewReady: {
336 onPreviewReady: {
337+ if (previewListView.init) {
338+ // Preview was triggered because of a click on the item. Need to expand now.
339+ if (!previewListView.open) {
340+ previewListView.open = true
341+ }
342+
343+ var index = previewListView.currentIndex
344+ previewListView.currentIndex = -1
345+ previewListView.currentIndex = index
346+ previewListView.init = false
347+ }
306− previewLoader.previewData = preview
348+ previewListView.currentItem.previewData = preview
307− previewLoader.open = true
308 }
349 }
309 }
350 }
310
351
@@ -312,18 +353,9 @@ ScopeView {
312 id: previewDelegateMapper
353 id: previewDelegateMapper
313 }
354 }
314
355
315− Connections {
356+ ListView {
316− ignoreUnknownSignals: true
357+ id: previewListView
317− target: previewLoader.valid ? previewLoader.item : null
358+ objectName: "previewListView"
318− onClose: {
319− previewLoader.open = false
320− }
321− }
322−
323− Loader {
324− objectName: "previewLoader"
325− id: previewLoader
326− property var previewData
327 height: effect.bottomGapPx - effect.topGapPx
359 height: effect.bottomGapPx - effect.topGapPx
328 anchors {
360 anchors {
329 top: parent.top
361 top: parent.top
@@ -331,38 +363,168 @@ ScopeView {
331 left: parent.left
363 left: parent.left
332 right: parent.right
364 right: parent.right
333 }
365 }
334− source: onScreen ? previewDelegateMapper.map(previewLoader.previewData.rendererName) : ""
366+ orientation: ListView.Horizontal
367+ highlightRangeMode: ListView.StrictlyEnforceRange
368+ snapMode: ListView.SnapOneItem
369+ boundsBehavior: Flickable.DragAndOvershootBounds
370+ highlightMoveDuration: 250
371+ flickDeceleration: units.gu(625)
372+ maximumFlickVelocity: width * 5
373+ cacheBuffer: 0
374+
375+ // To be set before opening the preview
376+ property string categoryId: ""
377+ property var categoryDelegate
378+
379+ // because the ListView is built asynchronous, setting the
380+ // currentIndex directly won't work. We need to refresh it
381+ // when the first preview is ready to be displayed.
382+ property bool init: true
383+
384+ onCurrentIndexChanged: {
385+ var row = Math.floor(currentIndex / categoryDelegate.columns);
386+ if (categoryDelegate.collapsedRowCount <= row) {
387+ categoryView.expandedCategoryId = categoryId
388+ }
389+
390+ if (open) {
391+ categoryDelegate.highlightIndex = currentIndex
392+ }
393+
394+ if (!init && model !== undefined) {
395+ var item = model.get(currentIndex)
396+ scopeView.scope.preview( item.uri, item.icon, item.category, 0, item.mimetype, item.title, item.comment, item.dndUri, item.metadata)
397+ }
398+
399+ var itemY = categoryView.contentItem.mapFromItem(categoryDelegate.currentItem).y;
400+ var newContentY = itemY - effect.positionPx - categoryDelegate.verticalSpacing;
401+ var effectAdjust = effect.positionPx;
402+ if (newContentY < 0) {
403+ effectAdjust += newContentY;
404+ newContentY = 0;
405+ }
406+ if (newContentY > Math.max(0, categoryView.contentHeight - categoryView.height)) {
407+ effectAdjust += -(categoryView.contentHeight - categoryView.height) + newContentY
408+ newContentY = categoryView.contentHeight - categoryView.height;
409+ }
410+
411+ effect.positionPx = effectAdjust;
412+ categoryView.contentY = newContentY - categoryView.originY;
413+ }
335
414
336 property bool open: false
415 property bool open: false
337 property bool onScreen: false
416 property bool onScreen: false
338− property bool valid: item !== null
339
417
340 onOpenChanged: {
418 onOpenChanged: {
341 if (open) {
419 if (open) {
342− onScreen = true
420+ onScreen = true;
421+ categoryDelegate.highlightIndex = currentIndex;
422+ pageHeader.unfocus();
423+ } else {
424+ // Cancel any pending preview requests or actions
425+ if (previewListView.currentItem.previewData !== undefined) {
426+ previewListView.currentItem.previewData.cancelAction();
427+ }
428+ scopeView.scope.cancelActivation();
429+ model = undefined;
430+ categoryView.correctExpandedCategory();
431+ categoryDelegate.highlightIndex = -1;
343 }
432 }
344 }
433 }
345
434
435+ Rectangle {
436+ anchors.fill: parent
437+ color: Qt.rgba(0, 0, 0, .3)
438+ z: -1
439+ }
440+
441+ delegate: Loader {
442+ id: previewLoader
443+ objectName: "previewLoader" + index
444+ height: previewListView.height
445+ width: previewListView.width
446+ asynchronous: true
447+ source: previewListView.onScreen ?
448+ (previewData !== undefined ? previewDelegateMapper.map(previewData.rendererName) : "DashPreviewPlaceholder.qml") : ""
449+
450+ onPreviewDataChanged: {
451+ if (previewData !== undefined && source.toString().indexOf("DashPreviewPlaceholder.qml") != -1) {
452+ previewLoader.opacity = 0;
453+ }
454+ }
455+
456+ onSourceChanged: {
457+ if (previewData !== undefined) {
458+ fadeIn.start()
459+ }
460+ }
461+
462+ PropertyAnimation {
463+ id: fadeIn
464+ target: previewLoader
465+ property: "opacity"
466+ from: 0.0
467+ to: 1.0
468+ duration: UbuntuAnimation.BriskDuration
469+ }
470+
471+ property var previewData
472+ property bool valid: item !== null
473+
346− onLoaded: {
474+ onLoaded: {
475+ if (previewListView.onScreen && previewData !== undefined) {
347− item.previewData = Qt.binding(function() { return previewLoader.previewData })
476+ item.previewData = Qt.binding(function() { return previewData })
477+ }
478+ }
479+
480+ Connections {
481+ ignoreUnknownSignals: true
482+ target: item
483+ onClose: {
484+ previewListView.open = false
485+ }
486+ }
487+
488+ function closePreviewSpinner() {
489+ if(item) {
490+ item.showProcessingAction = false;
491+ }
492+ }
348 }
493 }
494+ }
495+
496+ Image {
497+ objectName: "pointerArrow"
498+ anchors {
499+ top: previewListView.bottom
500+ left: parent.left
501+ leftMargin: previewListView.categoryDelegate !== undefined && previewListView.categoryDelegate.currentItem ?
502+ previewListView.categoryDelegate.currentItem.center + (-width + margins) / 2 : 0
349
503
350− function closePreviewSpinner() {
504+ Behavior on leftMargin {
351− if(item) {
505+ SmoothedAnimation {
352− item.showProcessingAction = false;
506+ duration: UbuntuAnimation.FastDuration
507+ }
353 }
508 }
354 }
509 }
510+ height: units.gu(1)
511+ width: units.gu(2)
512+ property int margins: previewListView.categoryDelegate ? previewListView.categoryDelegate.margins : 0
513+ opacity: previewListView.open ? .5 : 0
514+
515+ source: "graphics/tooltip_arrow.png"
355 }
516 }
356
517
357 // TODO: Move as InverseMouseArea to DashPreview
518 // TODO: Move as InverseMouseArea to DashPreview
358 MouseArea {
519 MouseArea {
520+ objectName: "closePreviewMouseArea"
359− enabled: previewLoader.onScreen
521+ enabled: previewListView.onScreen
360 anchors {
522 anchors {
361 fill: parent
523 fill: parent
362 topMargin: effect.bottomGapPx
524 topMargin: effect.bottomGapPx
363 }
525 }
364 onClicked: {
526 onClicked: {
365− previewLoader.open = false;
527+ previewListView.open = false;
366 }
528 }
367 }
529 }
368}
530}
Dash/Music/AlbumTile.qmldeleted−116
@@ -1,116 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−AbstractButton {
21− id: root
22− property url source
23− property alias album: albumLabel.text
24− property alias artist: artistLabel.text
25− property alias iconWidth: icon.width
26− property alias iconHeight: icon.height
27−
28− UbuntuShape {
29− id: icon
30− anchors {
31− top: parent.top
32− horizontalCenter: parent.horizontalCenter
33− }
34− radius: "medium"
35− image: Image {
36− source: root.source
37− sourceSize { width: icon.width; height: icon.height }
38− asynchronous: true
39− cache: false
40− }
41− }
42−
43− UbuntuShape {
44− id: borderPressed
45−
46− anchors.fill: icon
47− radius: "medium"
48− borderSource: "radius_pressed.sci"
49− opacity: root.pressed ? 1.0 : 0.0
50− Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.OutQuint } }
51− }
52−
53− Item {
54− id: artistContainer
55− anchors {
56− left: parent.left
57− right: parent.right
58− top: icon.bottom
59− }
60− height: units.gu(2)
61−
62− Label {
63− id: artistLabel
64− anchors {
65− baseline: parent.bottom
66− left: parent.left
67− right: parent.right
68− leftMargin: units.gu(1)
69− rightMargin: units.gu(1)
70− }
71−
72− color: Theme.palette.selected.backgroundText
73− opacity: 0.9
74− style: Text.Raised
75− styleColor: "black"
76− fontSize: "small"
77− elide: Text.ElideMiddle
78− horizontalAlignment: Text.AlignHCenter
79− }
80− }
81−
82− Item {
83− anchors {
84− left: parent.left
85− right: parent.right
86− top: artistContainer.bottom
87− }
88− height: units.gu(1.5)
89−
90− Label {
91− id: albumLabel
92− anchors {
93− baseline: parent.bottom
94− left: parent.left
95− right: parent.right
96− leftMargin: units.gu(1)
97− rightMargin: units.gu(1)
98− }
99−
100− color: Theme.palette.selected.backgroundText
101− opacity: 0.9
102− style: Text.Raised
103− styleColor: "black"
104− fontSize: "small"
105− font.weight: Font.Light
106− elide: Text.ElideMiddle
107− horizontalAlignment: Text.AlignHCenter
108− }
109− }
110−
111− GridView.onRemove: SequentialAnimation {
112− PropertyAction { target: root; property: "GridView.delayRemove"; value: true }
113− NumberAnimation { target: root; property: "opacity"; from: 1; to: 0; duration: 200; easing.type: Easing.InOutQuad }
114− PropertyAction { target: root; property: "GridView.delayRemove"; value: false }
115− }
116−}
Launcher/QuicklistForegroundStyle.qml → Dash/Music/MusicCarouselLoader.qmlrenamed+6−5
@@ -14,10 +14,11 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17+import QtQuick 2.0
17−import Ubuntu.Components.Themes.Ambiance 0.1
18+import Ubuntu.Components 0.1
19+import "../Generic"
18
20
19−PopoverForegroundStyle {
21+GenericCarouselLoader {
20− bubbleColor: "#221e1c"
22+ carouselUrl: "MusicCarousel.qml"
21− bubbleOpacity: 0.9
23+ filtergridUrl: "MusicFilterGrid.qml"
22− arrowSource: "graphics/quicklist_tooltip.png"
23}
24}
Dash/Music/MusicFilterGrid.qml+2−4
@@ -44,13 +44,11 @@ GenericFilterGrid {
44 }
44 }
45
45
46 onClicked: {
46 onClicked: {
47− var data = { model: model }
48− filtergrid.clicked(index, data, tile.y)
47+ filtergrid.clicked(index, tile.y)
49 }
48 }
50
49
51 onPressAndHold: {
50 onPressAndHold: {
52− var data = { model: model }
53− filtergrid.pressAndHold(index, data, tile.y)
51+ filtergrid.pressAndHold(index, tile.y)
54 }
52 }
55 }
53 }
56}
54}
Dash/SearchableResultModel.qml+4
@@ -25,6 +25,10 @@ SortFilterProxyModel {
25
25
26 filterRole: CategoryResults.RoleTitle
26 filterRole: CategoryResults.RoleTitle
27
27
28+ function get(index) {
29+ return model.get(mapToSource(index))
30+ }
31+
28 onSearchQueryChanged: {
32 onSearchQueryChanged: {
29 if (searchQuery.length == 0) {
33 if (searchQuery.length == 0) {
30 filterRegExp = RegExp("");
34 filterRegExp = RegExp("");
Dash/Video/VideosCarousel.qml → Dash/Video/VideoCarousel.qmlrenamed

The content is the same.

Components/Math.js → Dash/Video/VideoCarouselLoader.qmlrenamed+6−8
@@ -14,13 +14,11 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−.pragma library
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import "../Generic"
18
20
19−function clamp(value, min, max) {
21+GenericCarouselLoader {
20− if (min <= max) {
22+ carouselUrl: "VideoCarousel.qml"
21− return Math.max(min, Math.min(max, value))
23+ filtergridUrl: "VideoFilterGrid.qml"
22− } else {
23− // swap min/max if min > max
24− return clamp(value, max, min)
25− }
26}
24}
Dash/Video/VideoFilterGrid.qml+2−4
@@ -42,13 +42,11 @@ GenericFilterGrid {
42 style: VideoTileStyle {}
42 style: VideoTileStyle {}
43
43
44 onClicked: {
44 onClicked: {
45− var data = { model: model }
46− filtergrid.clicked(index, data, tile.y)
45+ filtergrid.clicked(index, tile.y)
47 }
46 }
48
47
49 onPressAndHold: {
48 onPressAndHold: {
50− var data = { model: model }
51− filtergrid.pressAndHold(index, data, tile.y)
49+ filtergrid.pressAndHold(index, tile.y)
52 }
50 }
53 }
51 }
54}
52}
Dash/graphics/tooltip_arrow@27.pngnew file

Binary file not shown.

Greeter/Greeter.qml+3−3
@@ -19,7 +19,6 @@ import Ubuntu.Components 0.1
19import Ubuntu.Gestures 0.1
19import Ubuntu.Gestures 0.1
20import LightDM 0.1 as LightDM
20import LightDM 0.1 as LightDM
21import "../Components"
21import "../Components"
22−import "../Components/Math.js" as MathLocal
23
22
24Showable {
23Showable {
25 id: greeter
24 id: greeter
@@ -29,7 +28,7 @@ Showable {
29 property url defaultBackground
28 property url defaultBackground
30
29
31 // 1 when fully shown and 0 when fully hidden
30 // 1 when fully shown and 0 when fully hidden
32− property real showProgress: MathLocal.clamp((width + x) / width, 0, 1)
31+ property real showProgress: MathUtils.clamp((width + x) / width, 0, 1)
33
32
34 showAnimation: StandardAnimation { property: "x"; to: 0 }
33 showAnimation: StandardAnimation { property: "x"; to: 0 }
35 hideAnimation: StandardAnimation { property: "x"; to: -width }
34 hideAnimation: StandardAnimation { property: "x"; to: -width }
@@ -52,7 +51,7 @@ Showable {
52 signal unlocked(int uid)
51 signal unlocked(int uid)
53
52
54 onRightTeaserPressedChanged: {
53 onRightTeaserPressedChanged: {
55− if (rightTeaserPressed && !locked) {
54+ if (rightTeaserPressed && !locked && x == 0) {
56 teasingTimer.start();
55 teasingTimer.start();
57 }
56 }
58 }
57 }
@@ -64,6 +63,7 @@ Showable {
64 property var model: LightDM.Users
63 property var model: LightDM.Users
65 property int currentIndex: 0
64 property int currentIndex: 0
66 property var infographicModel: LightDM.Infographic
65 property var infographicModel: LightDM.Infographic
66+ readonly property int backgroundTopMargin: -greeter.y
67
67
68 source: required ? "GreeterContent.qml" : ""
68 source: required ? "GreeterContent.qml" : ""
69
69
Greeter/GreeterContent.qml+23−20
@@ -24,7 +24,7 @@ MouseArea {
24 id: root
24 id: root
25 anchors.fill: parent
25 anchors.fill: parent
26
26
27− property bool ready: wallpaper.source == "" || wallpaper.status == Image.Ready || wallpaper.status == Image.Error
27+ property bool ready: background.source == "" || background.status == Image.Ready || background.status == Image.Error
28 property bool leftTeaserPressed: teasingMouseArea.pressed &&
28 property bool leftTeaserPressed: teasingMouseArea.pressed &&
29 teasingMouseArea.mouseX < teasingMouseArea.width / 2
29 teasingMouseArea.mouseX < teasingMouseArea.width / 2
30 property bool rightTeaserPressed: teasingMouseArea.pressed &&
30 property bool rightTeaserPressed: teasingMouseArea.pressed &&
@@ -34,33 +34,36 @@ MouseArea {
34 signal unlocked(int uid)
34 signal unlocked(int uid)
35
35
36 Rectangle {
36 Rectangle {
37− // In case wallpaper fails to load
37+ // In case background fails to load
38− id: wallpaperBackup
38+ id: backgroundBackup
39 anchors.fill: parent
39 anchors.fill: parent
40 color: "black"
40 color: "black"
41 }
41 }
42
42
43 property url backgroundValue: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : greeter.defaultBackground
43 property url backgroundValue: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : greeter.defaultBackground
44− onBackgroundValueChanged: wallpaper.source = backgroundValue
44+ onBackgroundValueChanged: background.source = backgroundValue
45
45
46 CrossFadeImage {
46 CrossFadeImage {
47− id: wallpaper
47+ id: background
48− objectName: "wallpaper"
48+ objectName: "greeterBackground"
49+ anchors {
49− anchors.fill: parent
50+ fill: parent
51+ topMargin: backgroundTopMargin
52+ }
50 fillMode: Image.PreserveAspectCrop
53 fillMode: Image.PreserveAspectCrop
51 }
54 }
52
55
53 // See Shell.qml's backgroundSettings treatment for why we need a separate
56 // See Shell.qml's backgroundSettings treatment for why we need a separate
54 // Image, but it boils down to avoiding binding loop detection.
57 // Image, but it boils down to avoiding binding loop detection.
55 Image {
58 Image {
56− source: wallpaper.source
59+ source: background.source
57 height: 0
60 height: 0
58 width: 0
61 width: 0
59 sourceSize.height: 0
62 sourceSize.height: 0
60 sourceSize.width: 0
63 sourceSize.width: 0
61 onStatusChanged: {
64 onStatusChanged: {
62 if (status == Image.Error && source != greeter.defaultBackground) {
65 if (status == Image.Error && source != greeter.defaultBackground) {
63− wallpaper.source = greeter.defaultBackground
66+ background.source = greeter.defaultBackground
64 }
67 }
65 }
68 }
66 }
69 }
@@ -71,17 +74,6 @@ MouseArea {
71 opacity: 0.4
74 opacity: 0.4
72 }
75 }
73
76
74− Clock {
75− id: clock
76− visible: narrowMode
77−
78− anchors {
79− top: parent.top
80− topMargin: units.gu(2)
81− horizontalCenter: parent.horizontalCenter
82− }
83− }
84−
85 MouseArea {
77 MouseArea {
86 id: teasingMouseArea
78 id: teasingMouseArea
87 anchors.fill: parent
79 anchors.fill: parent
@@ -160,4 +152,15 @@ MouseArea {
160 right: root.right
152 right: root.right
161 }
153 }
162 }
154 }
155+
156+ Clock {
157+ id: clock
158+ visible: narrowMode
159+
160+ anchors {
161+ top: parent.top
162+ topMargin: units.gu(2)
163+ horizontalCenter: parent.horizontalCenter
164+ }
165+ }
163}
166}
Greeter/Lockscreen.qml+8−4
@@ -57,15 +57,19 @@ Showable {
57 }
57 }
58
58
59 Rectangle {
59 Rectangle {
60− // In case wallpaper fails to load or is undefined
60+ // In case background fails to load or is undefined
61− id: wallpaperBackup
61+ id: backgroundBackup
62 anchors.fill: parent
62 anchors.fill: parent
63 color: "black"
63 color: "black"
64 }
64 }
65
65
66 Image {
66 Image {
67− id: wallpaper
67+ id: backgroundImage
68+ objectName: "lockscreenBackground"
69+ anchors {
68− anchors.fill: parent
70+ fill: parent
71+ topMargin: backgroundTopMargin
72+ }
69 source: root.required ? root.background : ""
73 source: root.required ? root.background : ""
70 fillMode: Image.PreserveAspectCrop
74 fillMode: Image.PreserveAspectCrop
71 }
75 }
Greeter/PinLockscreen.qml+34−4
@@ -27,7 +27,7 @@ Column {
27 property alias placeholderText: pinentryField.placeholderText
27 property alias placeholderText: pinentryField.placeholderText
28 property int padWidth: units.gu(34)
28 property int padWidth: units.gu(34)
29 property int padHeight: units.gu(28)
29 property int padHeight: units.gu(28)
30− property int pinLength: 4
30+ property int pinLength: -1
31
31
32 signal entered(string passphrase)
32 signal entered(string passphrase)
33 signal cancel()
33 signal cancel()
@@ -65,6 +65,9 @@ Column {
65 Label {
65 Label {
66 id: pinentryFieldLabel
66 id: pinentryFieldLabel
67 anchors.centerIn: parent
67 anchors.centerIn: parent
68+ width: parent.width - (backspaceIcon.width + backspaceIcon.anchors.rightMargin) * 2
69+ elide: Text.ElideMiddle
70+ horizontalAlignment: Text.AlignHCenter
68 font.pixelSize: units.dp(44)
71 font.pixelSize: units.dp(44)
69 color: "#f3f3e7"
72 color: "#f3f3e7"
70 opacity: 0.6
73 opacity: 0.6
@@ -76,6 +79,26 @@ Column {
76 text: parent.placeholderText
79 text: parent.placeholderText
77 visible: pinentryFieldLabel.text.length == 0
80 visible: pinentryFieldLabel.text.length == 0
78 }
81 }
82+
83+ Icon {
84+ id: backspaceIcon
85+ objectName: "backspaceIcon"
86+ anchors {
87+ top: parent.top
88+ topMargin: units.gu(1)
89+ right: parent.right
90+ rightMargin: units.gu(2)
91+ bottom: parent.bottom
92+ bottomMargin: units.gu(1)
93+ }
94+ visible: root.pinLength == -1
95+ width: height
96+ name: "erase"
97+ MouseArea {
98+ anchors.fill: parent
99+ onClicked: pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1);
100+ }
101+ }
79 }
102 }
80
103
81 UbuntuShape {
104 UbuntuShape {
@@ -154,7 +177,7 @@ Column {
154 objectName: "pinPadButtonBack"
177 objectName: "pinPadButtonBack"
155 width: root.padWidth / 3
178 width: root.padWidth / 3
156 height: root.padHeight / 4
179 height: root.padHeight / 4
157− iconName: "back"
180+ subText: "CANCEL"
158 onClicked: root.cancel();
181 onClicked: root.cancel();
159 }
182 }
160
183
@@ -171,8 +194,15 @@ Column {
171 objectName: "pinPadButtonErase"
194 objectName: "pinPadButtonErase"
172 width: root.padWidth / 3
195 width: root.padWidth / 3
173 height: root.padHeight / 4
196 height: root.padHeight / 4
174− iconName: "erase"
197+ iconName: root.pinLength == -1 ? "" : "erase"
198+ subText: root.pinLength == -1 ? "DONE" : ""
199+ onClicked: {
200+ if (root.pinLength !== -1) {
175− onClicked: pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1)
201+ pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1);
202+ } else {
203+ root.entered(pinentryField.text);
204+ }
205+ }
176 enabled: entryEnabled
206 enabled: entryEnabled
177 }
207 }
178 }
208 }
Launcher/Launcher.qml+2−2
@@ -28,8 +28,8 @@ Item {
28
28
29 property int panelWidth: units.gu(8)
29 property int panelWidth: units.gu(8)
30 property int dragAreaWidth: units.gu(1)
30 property int dragAreaWidth: units.gu(1)
31− property int minimizeDistance: panelWidth * 2.5
31+ property int minimizeDistance: units.gu(26)
32− property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
32+ property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
33 (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0
33 (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0
34
34
35 readonly property bool shown: panel.x > -panel.width
35 readonly property bool shown: panel.x > -panel.width
Launcher/LauncherPanel.qml+87−46
@@ -21,6 +21,7 @@ import Unity 0.1
21import Unity.Launcher 0.1
21import Unity.Launcher 0.1
22import Ubuntu.Components.Popups 0.1
22import Ubuntu.Components.Popups 0.1
23import "../Components/ListItems"
23import "../Components/ListItems"
24+import "../Components/"
24
25
25Item {
26Item {
26 id: root
27 id: root
@@ -31,7 +32,7 @@ Item {
31 property bool inverted: true
32 property bool inverted: true
32 property bool dragging: false
33 property bool dragging: false
33 property bool moving: launcherListView.moving || launcherListView.flicking
34 property bool moving: launcherListView.moving || launcherListView.flicking
34− property bool preventHiding: moving || dndArea.draggedIndex >= 0 || dndArea.quickListPopover !== null || dndArea.pressed
35+ property bool preventHiding: moving || dndArea.draggedIndex >= 0 || quickList.state === "open" || dndArea.pressed
35 property int highlightIndex: -1
36 property int highlightIndex: -1
36
37
37 signal applicationSelected(string appId)
38 signal applicationSelected(string appId)
@@ -278,7 +279,6 @@ Item {
278 property bool postDragging: false
279 property bool postDragging: false
279 property int startX
280 property int startX
280 property int startY
281 property int startY
281− property var quickListPopover: null
282
282
283 onPressed: {
283 onPressed: {
284 selectedItem = launcherListView.itemAt(mouseX, mouseY + launcherListView.realContentY)
284 selectedItem = launcherListView.itemAt(mouseX, mouseY + launcherListView.realContentY)
@@ -357,11 +357,10 @@ Item {
357 draggedIndex = Math.floor((mouseY + launcherListView.realContentY) / launcherListView.realItemHeight);
357 draggedIndex = Math.floor((mouseY + launcherListView.realContentY) / launcherListView.realItemHeight);
358
358
359 // Opening QuickList
359 // Opening QuickList
360− var quickListModel = launcherListView.model.get(draggedIndex).quickList
360+ quickList.item = selectedItem;
361− var quickListAppId = launcherListView.model.get(draggedIndex).appId
361+ quickList.model = launcherListView.model.get(draggedIndex).quickList;
362−
362+ quickList.appId = launcherListView.model.get(draggedIndex).appId;
363− quickListPopover = PopupUtils.open(popoverComponent, selectedItem,
363+ quickList.state = "open";
364− {model: quickListModel, appId: quickListAppId})
365
364
366 launcherListView.interactive = false
365 launcherListView.interactive = false
367
366
@@ -387,7 +386,7 @@ Item {
387 var distance = Math.max(Math.abs(mouseX - startX), Math.abs(mouseY - startY))
386 var distance = Math.max(Math.abs(mouseX - startX), Math.abs(mouseY - startY))
388 if (!preDragging && distance > units.gu(1.5)) {
387 if (!preDragging && distance > units.gu(1.5)) {
389 preDragging = true;
388 preDragging = true;
390− PopupUtils.close(quickListPopover)
389+ quickList.state = "";
391 }
390 }
392 if (distance > launcherListView.itemHeight) {
391 if (distance > launcherListView.itemHeight) {
393 selectedItem.dragging = true
392 selectedItem.dragging = true
@@ -482,53 +481,95 @@ Item {
482 }
481 }
483 }
482 }
484
483
485− Component {
484+ UbuntuShapeForItem {
486− id: popoverComponent
485+ id: quickListShape
486+ objectName: "quickListShape"
487+ anchors.fill: quickList
488+ opacity: quickList.state === "open" ? 0.8 : 0
489+ visible: opacity > 0
490+ rotation: root.rotation
491+
492+ Behavior on opacity {
493+ UbuntuNumberAnimation {}
494+ }
495+
496+ image: quickList
497+
498+ Image {
499+ anchors {
500+ right: parent.left
501+ rightMargin: -units.dp(4)
502+ verticalCenter: parent.verticalCenter
503+ verticalCenterOffset: -quickList.offset
504+ }
505+ height: units.gu(1)
506+ width: units.gu(2)
507+ source: "graphics/quicklist_tooltip.png"
508+ rotation: 90
509+ }
510+
511+ InverseMouseArea {
512+ anchors.fill: parent
513+ enabled: quickList.state == "open"
514+ onClicked: {
515+ quickList.state = ""
516+ }
517+ }
518+
519+ }
520+
521+ Rectangle {
522+ id: quickList
523+ objectName: "quickList"
524+ color: "#221e1c"
525+ width: units.gu(30)
526+ height: quickListColumn.height
527+ anchors {
528+ left: root.inverted ? undefined : parent.right
529+ right: root.inverted ? parent.left : undefined
530+ margins: units.gu(1)
487
531
488− Popover {
532+ }
489− id: popover
533+ y: itemCenter - (height / 2) + offset
490− property var model
534+ rotation: root.rotation
491− property string appId
492− contentWidth: quickListColumn.width
493− foregroundStyle: QuicklistForegroundStyle {}
494
535
495− // FIXME: There's a bug in the Popover positioning that it covers the item in case it is rotated.
536+ property var model
496− // https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1204470
537+ property string appId
497− // For now, let's move the Popover around with callerMargin.
538+ property var item
498− // Remove popupMargin once the bug is fixed.
499− property int popupMargin: root.inverted ? launcherListView.itemHeight : 0;
500
539
501− callerMargin: units.gu(1) + popupMargin
540+ // internal
541+ property int itemCenter: item ? root.mapFromItem(quickList.item).y + (item.height / 2) : units.gu(1)
542+ property int offset: itemCenter + (height/2) + units.gu(1) > parent.height ? -itemCenter - (height/2) - units.gu(1) + parent.height :
543+ itemCenter - (height/2) < units.gu(1) ? (height/2) - itemCenter + units.gu(1) : 0
502
544
503− Column {
545+ Column {
504− id: quickListColumn
546+ id: quickListColumn
505− width: units.gu(30)
547+ width: parent.width
506− height: childrenRect.height
548+ height: childrenRect.height
507
549
508− Repeater {
550+ Repeater {
509− id: popoverRepeater
551+ id: popoverRepeater
510− model: popover.model
552+ model: quickList.model
511
553
512− ListItems.Standard {
554+ ListItems.Standard {
513− objectName: "quickListEntry" + index
555+ objectName: "quickListEntry" + index
514− text: (model.clickable ? "" : "<b>") + model.label + (model.clickable ? "" : "</b>")
556+ text: (model.clickable ? "" : "<b>") + model.label + (model.clickable ? "" : "</b>")
515− highlightWhenPressed: model.clickable
557+ highlightWhenPressed: model.clickable
516
558
517− // FIXME: This is a workaround for the theme not being context sensitive. I.e. the
559+ // FIXME: This is a workaround for the theme not being context sensitive. I.e. the
518− // ListItems don't know that they are sitting in a themed Popover where the color
560+ // ListItems don't know that they are sitting in a themed Popover where the color
519− // needs to be inverted.
561+ // needs to be inverted.
520− __foregroundColor: Theme.palette.selected.backgroundText
562+ __foregroundColor: Theme.palette.selected.backgroundText
521
563
522− onClicked: {
564+ onClicked: {
523− if (!model.clickable) {
565+ if (!model.clickable) {
524− return;
566+ return;
525− }
526− PopupUtils.close(popover);
527− // Unsetting model to prevent showing changing entries during fading out
528− // that may happen because of triggering an action.
529− LauncherModel.quickListActionInvoked(appId, index);
530− popoverRepeater.model = undefined;
531 }
567 }
568+ quickList.state = "";
569+ // Unsetting model to prevent showing changing entries during fading out
570+ // that may happen because of triggering an action.
571+ LauncherModel.quickListActionInvoked(quickList.appId, index);
572+ quickList.model = undefined;
532 }
573 }
533 }
574 }
534 }
575 }
Notifications/NotificationMenuItemFactory.qml+20−6
@@ -54,7 +54,8 @@ Loader {
54
54
55 Component.onCompleted: {
55 Component.onCompleted: {
56 menuModel.loadExtendedAttributes(menuIndex, {"x-echo-mode-password": "bool"});
56 menuModel.loadExtendedAttributes(menuIndex, {"x-echo-mode-password": "bool"});
57− textfield.echoMode = menuData.ext.xEchoModePassword ? TextInput.Password : TextInput.Normal
57+ checkBox.checked = menuData.ext.xEchoModePassword ? false : true
58+ checkBoxRow.visible = menuData.ext.xEchoModePassword
58 }
59 }
59
60
60 Label {
61 Label {
@@ -65,11 +66,29 @@ Loader {
65 id: textfield
66 id: textfield
66
67
67 anchors.left: parent.left; anchors.right: parent.right
68 anchors.left: parent.left; anchors.right: parent.right
69+ echoMode: checkBox.checked ? TextInput.Normal : TextInput.Password
68 height: units.gu(5)
70 height: units.gu(5)
69 onTextChanged: {
71 onTextChanged: {
70 menuModel.changeState(menuIndex, text);
72 menuModel.changeState(menuIndex, text);
71 }
73 }
72 }
74 }
75+
76+ Row {
77+ id: checkBoxRow
78+
79+ spacing: units.gu(.5)
80+
81+ CheckBox {
82+ id: checkBox
83+
84+ checked: false
85+ }
86+
87+ Label {
88+ anchors.verticalCenter: checkBox.verticalCenter
89+ text: i18n.tr("Show password")
90+ }
91+ }
73 }
92 }
74 }
93 }
75
94
@@ -78,11 +97,6 @@ Loader {
78 PinLockscreen {
97 PinLockscreen {
79 anchors.left: parent.left; anchors.right: parent.right
98 anchors.left: parent.left; anchors.right: parent.right
80
99
81− Component.onCompleted: {
82− menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-pin-length': 'int'});
83− pinLength = menuData.ext.xCanonicalPinLength;
84− }
85−
86 onEntered: {
100 onEntered: {
87 menuModel.changeState(menuIndex, passphrase);
101 menuModel.changeState(menuIndex, passphrase);
88 entryEnabled = false;
102 entryEnabled = false;
Panel/Indicators.qml+1−2
@@ -21,7 +21,6 @@ import Unity.Indicators 0.1 as Indicators
21
21
22import "../Components"
22import "../Components"
23import "../Components/ListItems"
23import "../Components/ListItems"
24−import "../Components/Math.js" as MathLocal
25
24
26Showable {
25Showable {
27 id: indicators
26 id: indicators
@@ -100,7 +99,7 @@ Showable {
100 Otherwise it contains the bar's location as a fraction of the distance between hintValue (is 0) and lockThreshold (is 1).
99 Otherwise it contains the bar's location as a fraction of the distance between hintValue (is 0) and lockThreshold (is 1).
101 */
100 */
102 var verticalProgress =
101 var verticalProgress =
103− MathLocal.clamp((indicators.height - handle.height - hintValue) /
102+ MathUtils.clamp((indicators.height - handle.height - hintValue) /
104 (lockThreshold - hintValue), 0, 1);
103 (lockThreshold - hintValue), 0, 1);
105
104
106 /*
105 /*
Panel/Indicators/DefaultIndicatorWidget.qml+32−10
@@ -24,7 +24,7 @@ import Unity.Indicators 0.1 as Indicators
24Indicators.IndicatorWidget {
24Indicators.IndicatorWidget {
25 id: indicatorWidget
25 id: indicatorWidget
26
26
27− width: itemRow.width + units.gu(0.5)
27+ width: itemRow.width
28
28
29 property alias leftLabel: itemLeftLabel.text
29 property alias leftLabel: itemLeftLabel.text
30 property alias rightLabel: itemRightLabel.text
30 property alias rightLabel: itemRightLabel.text
@@ -32,16 +32,17 @@ Indicators.IndicatorWidget {
32
32
33 Row {
33 Row {
34 id: itemRow
34 id: itemRow
35+ width: childrenRect.width
35 objectName: "itemRow"
36 objectName: "itemRow"
36 anchors {
37 anchors {
37 top: parent.top
38 top: parent.top
38 bottom: parent.bottom
39 bottom: parent.bottom
39 horizontalCenter: parent.horizontalCenter
40 horizontalCenter: parent.horizontalCenter
40 }
41 }
41− spacing: units.gu(0.5)
42
42
43 Label {
43 Label {
44 id: itemLeftLabel
44 id: itemLeftLabel
45+ width: guRoundUp(implicitWidth)
45 objectName: "leftLabel"
46 objectName: "leftLabel"
46 color: Theme.palette.selected.backgroundText
47 color: Theme.palette.selected.backgroundText
47 opacity: 0.8
48 opacity: 0.8
@@ -57,25 +58,35 @@ Indicators.IndicatorWidget {
57 top: parent.top
58 top: parent.top
58 bottom: parent.bottom
59 bottom: parent.bottom
59 }
60 }
60− spacing: units.gu(0.5)
61
61
62 Repeater {
62 Repeater {
63 model: indicatorWidget.icons
63 model: indicatorWidget.icons
64
64
65− Image {
65+ Item {
66− id: itemImage
66+ width: guRoundUp(itemImage.width)
67− objectName: "itemImage"
68− visible: source != ""
69− source: modelData
70 height: indicatorWidget.iconSize
67 height: indicatorWidget.iconSize
68+
69+ Image {
70+ id: itemImage
71+ objectName: "itemImage"
72+ visible: source != ""
73+ source: modelData
74+ height: parent.height
75+ anchors.horizontalCenter: parent.horizontalCenter
76+ fillMode: Image.PreserveAspectFit
77+
78+ sourceSize {
71− width: indicatorWidget.iconSize
79+ width: indicatorWidget.iconSize
72− anchors.verticalCenter: parent.verticalCenter
80+ height: indicatorWidget.iconSize
81+ }
82+ }
73 }
83 }
74 }
84 }
75 }
85 }
76
86
77 Label {
87 Label {
78 id: itemRightLabel
88 id: itemRightLabel
89+ width: guRoundUp(implicitWidth)
79 objectName: "rightLabel"
90 objectName: "rightLabel"
80 color: Theme.palette.selected.backgroundText
91 color: Theme.palette.selected.backgroundText
81 opacity: 0.8
92 opacity: 0.8
@@ -86,6 +97,17 @@ Indicators.IndicatorWidget {
86 }
97 }
87 }
98 }
88
99
100+ // TODO: Use toolkit function https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1242575
101+ function guRoundUp(width) {
102+ if (width == 0) {
103+ return 0;
104+ }
105+ var gu1 = units.gu(1.0);
106+ var mod = (width % gu1);
107+
108+ return mod == 0 ? width : width + (gu1 - mod);
109+ }
110+
89 onRootActionStateChanged: {
111 onRootActionStateChanged: {
90 if (rootActionState == undefined) {
112 if (rootActionState == undefined) {
91 leftLabel = "";
113 leftLabel = "";
Shell.qml+9−3
@@ -30,7 +30,6 @@ import "Launcher"
30import "Panel"
30import "Panel"
31import "Hud"
31import "Hud"
32import "Components"
32import "Components"
33−import "Components/Math.js" as MathLocal
34import "Bottombar"
33import "Bottombar"
35import "SideStage"
34import "SideStage"
36import "Notifications"
35import "Notifications"
@@ -237,7 +236,7 @@ FocusScope {
237 Behavior on x {SmoothedAnimation{velocity: 600}}
236 Behavior on x {SmoothedAnimation{velocity: 600}}
238
237
239 property real showProgress:
238 property real showProgress:
240− MathLocal.clamp(1 - (x + stages.x) / shell.width, 0, 1)
239+ MathUtils.clamp(1 - (x + stages.x) / shell.width, 0, 1)
241
240
242 Showable {
241 Showable {
243 id: stages
242 id: stages
@@ -402,6 +401,10 @@ FocusScope {
402
401
403 Lockscreen {
402 Lockscreen {
404 id: lockscreen
403 id: lockscreen
404+ objectName: "lockscreen"
405+
406+ readonly property int backgroundTopMargin: -panel.panelHeight
407+
405 hides: [launcher, panel.indicators, hud]
408 hides: [launcher, panel.indicators, hud]
406 shown: false
409 shown: false
407 enabled: true
410 enabled: true
@@ -658,19 +661,22 @@ FocusScope {
658 Launcher {
661 Launcher {
659 id: launcher
662 id: launcher
660
663
664+ readonly property bool dashSwipe: progress > 0
665+
661 anchors.top: parent.top
666 anchors.top: parent.top
662 anchors.bottom: parent.bottom
667 anchors.bottom: parent.bottom
663 width: parent.width
668 width: parent.width
664 dragAreaWidth: shell.edgeSize
669 dragAreaWidth: shell.edgeSize
665 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
670 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
671+
666 onDashItemSelected: showHome()
672 onDashItemSelected: showHome()
667 onDash: {
673 onDash: {
668 if (stages.shown) {
674 if (stages.shown) {
669− dash.setCurrentScope("applications.scope", true /* animate */, true /* reset */)
670 stages.hide();
675 stages.hide();
671 launcher.hide();
676 launcher.hide();
672 }
677 }
673 }
678 }
679+ onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("applications.scope", false, true)
674 onLauncherApplicationSelected:{
680 onLauncherApplicationSelected:{
675 greeter.hide()
681 greeter.hide()
676 shell.activateApplication(appId)
682 shell.activateApplication(appId)
data/unity8.conf+20
@@ -6,4 +6,24 @@ stop on desktop-end
6
6
7respawn
7respawn
8
8
9+pre-start script
10+ if [ -n "$MIR_SOCKET" ]; then
11+ if [ -z "$UNITY_MIR_SOCKET" ]; then
12+ # Save original value of MIR_SOCKET in case we are restarted,
13+ # as we modify the variable for future jobs, including ourself.
14+ UNITY_MIR_SOCKET=$MIR_SOCKET
15+ initctl set-env --global UNITY_MIR_SOCKET=$UNITY_MIR_SOCKET
16+ fi
17+
18+ # Point unity8 at unity-system-compositor
19+ MIR_SERVER_FILE=$XDG_RUNTIME_DIR/mir_socket
20+ initctl set-env MIR_SERVER_FILE=$MIR_SERVER_FILE
21+ initctl set-env MIR_SERVER_HOST_SOCKET=$UNITY_MIR_SOCKET
22+
23+ # Point all future jobs in this session to our Mir socket instead of
24+ # unity-system-compositor's socket.
25+ initctl set-env --global MIR_SOCKET=$MIR_SERVER_FILE
26+ fi
27+end script
28+
9exec ${BINARY:-unity8} $ARGS
29exec ${BINARY:-unity8} $ARGS
debian/changelog+102
@@ -1,3 +1,105 @@
1+unity8 (7.83+14.04.20131106-0ubuntu1) trusty; urgency=low
2+
3+ [ Andrea Cimitan ]
4+ * Place ShaderEffectSource of UbuntuShapeForItem under the Shape Item.
5+ (LP: #1239317)
6+
7+ [ Omer Akram ]
8+ * test: make sure the search indicator hides when an app has focus.
9+
10+ [ Nick Dedekind ]
11+ * Fixed indicator slider menu item alignment to label field and icon.
12+ (LP: #1240756)
13+
14+ [ chris.gagnon ]
15+ * Update to autopilot 1.4.
16+
17+ [ Ubuntu daily release ]
18+ * Automatic snapshot from revision 500
19+
20+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 06 Nov 2013 03:37:02 +0000
21+
22+unity8 (7.83+14.04.20131105.1-0ubuntu1) trusty; urgency=low
23+
24+ [ Michał Sawicz ]
25+ * Implement switching between previews by swiping. (LP: #1220651,
26+ #1088572)
27+
28+ [ Nick Dedekind ]
29+ * Faster loading of indicator menus. (LP: #1226650)
30+
31+ [ Albert Astals ]
32+ * Make sure we have ssh started when we need it .
33+ * Fix a few warnings in DashContent.qml on shutdown
34+ Dash/DashContent.qml:119: TypeError: Cannot read property
35+ 'previewShown' of null Dash/DashContent.qml:120: TypeError: Cannot
36+ read property 'moving' of null .
37+ * Don't use deprecated Panel methods.
38+
39+ [ Christopher Lee ]
40+ * Adds an easy to consume function that attempts to unlock the unity
41+ greeter. (LP: #1240261)
42+
43+ [ Lars Uebernickel ]
44+ * Indicators: add TimeFormatter and use it in the messaging menu This
45+ component can be used to turn a timestamp and a format string into a
46+ string with the corresponding time and format. The string will
47+ change whenever the timezone changes. (LP: #1236413)
48+
49+ [ Andrea Cimitan ]
50+ * Allow drag over bounds, but not overshoot. (LP: #1204300)
51+ * Threshold to activate the left edge swipe to reveal dash is now 26
52+ GU. (LP: #1236286)
53+
54+ [ Michael Zanetti ]
55+ * replace the launcher quicklist's Popover with an own quicklist
56+ implementation The Popover probably won't ever support what the
57+ launcher needs.
58+ * Implement switching between previews by swiping. (LP: #1220651,
59+ #1088572)
60+ * don't trigger the greeter teasing during a movement of the greeter.
61+
62+ [ Ubuntu daily release ]
63+ * Automatic snapshot from revision 495
64+
65+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 05 Nov 2013 12:22:04 +0000
66+
67+unity8 (7.83+14.04.20131031-0ubuntu1) trusty; urgency=low
68+
69+ [ Michał Sawicz ]
70+ * Use setenv as early as possible to avoid setenv and getenv clashing
71+ in multi-threaded situations. (LP: #1240866)
72+
73+ [ Ubuntu daily release ]
74+ * Automatic snapshot from revision 482
75+
76+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 31 Oct 2013 20:10:56 +0000
77+
78+unity8 (7.83+14.04.20131028.1-0ubuntu1) trusty; urgency=low
79+
80+ * New rebuild forced
81+ * Automatic snapshot from revision 480
82+
83+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 28 Oct 2013 22:42:07 +0000
84+
85+unity8 (7.83+14.04.20131028-0ubuntu1) trusty; urgency=low
86+
87+ [ Andrea Cimitan ]
88+ * Fix 1195349 by counting drawbuffer on the newContentX logic of the
89+ carousel When we changed carousel from repeater to listview, we
90+ added drawbuffer. this breaks the logic of newContentX, which was
91+ considered disabled and set to -1. The correct disabled value now
92+ has to take into account the drawbuffer. (LP: #1195349)
93+
94+ [ Christopher Lee ]
95+ * Checks both then env and upstart env for the currently set
96+ XDG_DATA_DIRS so they can be set correctly for the test.
97+
98+ [ Ubuntu daily release ]
99+ * Automatic snapshot from revision 479
100+
101+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 28 Oct 2013 03:08:59 +0000
102+
1unity8 (7.83+13.10.20131016.2-0ubuntu1) saucy; urgency=low
103unity8 (7.83+13.10.20131016.2-0ubuntu1) saucy; urgency=low
2
104
3 [ Loïc Minier ]
105 [ Loïc Minier ]
debian/control+1−1
@@ -91,7 +91,7 @@ Description: Unity 8 shell
91Package: unity8-autopilot
91Package: unity8-autopilot
92Architecture: all
92Architecture: all
93Depends: gir1.2-glib-2.0,
93Depends: gir1.2-glib-2.0,
94− libautopilot-qt,
94+ libautopilot-qt (>= 1.4),
95 libqt5test5,
95 libqt5test5,
96 libqt5widgets5,
96 libqt5widgets5,
97 python-evdev,
97 python-evdev,
main.cpp+8−8
@@ -78,14 +78,6 @@ void resolveIconTheme() {
78
78
79int startShell(int argc, const char** argv, void* server)
79int startShell(int argc, const char** argv, void* server)
80{
80{
81− /* Workaround Qt platform integration plugin not advertising itself
82− as having the following capabilities:
83− - QPlatformIntegration::ThreadedOpenGL
84− - QPlatformIntegration::BufferQueueingOpenGL
85− */
86− setenv("QML_FORCE_THREADED_RENDERER", "1", 1);
87− setenv("QML_FIXED_ANIMATION_STEP", "1", 1);
88−
89 const bool isUbuntuMirServer = qgetenv("QT_QPA_PLATFORM") == "ubuntumirserver";
81 const bool isUbuntuMirServer = qgetenv("QT_QPA_PLATFORM") == "ubuntumirserver";
90
82
91 QGuiApplication::setApplicationName("Unity 8");
83 QGuiApplication::setApplicationName("Unity 8");
@@ -186,6 +178,14 @@ int startShell(int argc, const char** argv, void* server)
186
178
187int main(int argc, const char *argv[])
179int main(int argc, const char *argv[])
188{
180{
181+ /* Workaround Qt platform integration plugin not advertising itself
182+ as having the following capabilities:
183+ - QPlatformIntegration::ThreadedOpenGL
184+ - QPlatformIntegration::BufferQueueingOpenGL
185+ */
186+ setenv("QML_FORCE_THREADED_RENDERER", "1", 1);
187+ setenv("QML_FIXED_ANIMATION_STEP", "1", 1);
188+
189 // For ubuntumirserver/ubuntumirclient
189 // For ubuntumirserver/ubuntumirclient
190 if (qgetenv("QT_QPA_PLATFORM").startsWith("ubuntumir")) {
190 if (qgetenv("QT_QPA_PLATFORM").startsWith("ubuntumir")) {
191 setenv("QT_QPA_PLATFORM", "ubuntumirserver", 1);
191 setenv("QT_QPA_PLATFORM", "ubuntumirserver", 1);
plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+4−1
@@ -155,6 +155,7 @@ ListViewWithPageHeader::ListViewWithPageHeader()
155 , m_topSectionItem(nullptr)
155 , m_topSectionItem(nullptr)
156 , m_forceNoClip(false)
156 , m_forceNoClip(false)
157 , m_inLayout(false)
157 , m_inLayout(false)
158+ , m_inContentHeightKeepHeaderShown(false)
158{
159{
159 m_clipItem = new QQuickItem(contentItem());
160 m_clipItem = new QQuickItem(contentItem());
160// m_clipItem = new QQuickRectangle(contentItem());
161// m_clipItem = new QQuickRectangle(contentItem());
@@ -494,7 +495,7 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
494 if (!scrolledUp && contentY() == -m_minYExtent) {
495 if (!scrolledUp && contentY() == -m_minYExtent) {
495 m_headerItemShownHeight = 0;
496 m_headerItemShownHeight = 0;
496 m_headerItem->setY(contentY());
497 m_headerItem->setY(contentY());
497− } else if ((scrolledUp && notRebounding && notShownByItsOwn && !maximizeVisibleAreaRunning) || (m_headerItemShownHeight > 0)) {
498+ } else if ((scrolledUp && notRebounding && notShownByItsOwn && !maximizeVisibleAreaRunning) || (m_headerItemShownHeight > 0) || m_inContentHeightKeepHeaderShown) {
498 if (maximizeVisibleAreaRunning && diff > 0) // If we are maximizing and the header was shown, make sure we hide it
499 if (maximizeVisibleAreaRunning && diff > 0) // If we are maximizing and the header was shown, make sure we hide it
499 m_headerItemShownHeight -= diff;
500 m_headerItemShownHeight -= diff;
500 else
501 else
@@ -1267,7 +1268,9 @@ void ListViewWithPageHeader::updatePolish()
1267
1268
1268 m_contentHeightDirty = false;
1269 m_contentHeightDirty = false;
1269 adjustMinYExtent();
1270 adjustMinYExtent();
1271+ m_inContentHeightKeepHeaderShown = m_headerItem && m_headerItem->y() == contentY();
1270 setContentHeight(contentHeight);
1272 setContentHeight(contentHeight);
1273+ m_inContentHeightKeepHeaderShown = false;
1271 }
1274 }
1272}
1275}
1273
1276
plugins/ListViewWithPageHeader/listviewwithpageheader.h+1
@@ -202,6 +202,7 @@ private:
202
202
203 bool m_forceNoClip;
203 bool m_forceNoClip;
204 bool m_inLayout;
204 bool m_inLayout;
205+ bool m_inContentHeightKeepHeaderShown;
205
206
206 // Qt 5.0 doesn't like releasing the items just after itemCreated
207 // Qt 5.0 doesn't like releasing the items just after itemCreated
207 // so we delay the releasing until the next updatePolish
208 // so we delay the releasing until the next updatePolish
plugins/Ubuntu/Gestures/AxisVelocityCalculator.cpp+9−18
@@ -21,25 +21,19 @@
21#include "AxisVelocityCalculator.h"
21#include "AxisVelocityCalculator.h"
22#include <QtCore/QElapsedTimer>
22#include <QtCore/QElapsedTimer>
23
23
24−class RealTimeSource : public UbuntuGestures::TimeSource {
25−public:
26− RealTimeSource()
27− : UbuntuGestures::TimeSource() {
24+using namespace UbuntuGestures;
28− m_timer.start();
29− }
30− virtual qint64 msecsSinceReference() {
31− return m_timer.elapsed();
32− }
33−private:
34− QElapsedTimer m_timer;
35−};
36
25
37AxisVelocityCalculator::AxisVelocityCalculator(QObject *parent)
26AxisVelocityCalculator::AxisVelocityCalculator(QObject *parent)
27+ : AxisVelocityCalculator(SharedTimeSource(new RealTimeSource), parent)
28+{
29+}
30+
31+AxisVelocityCalculator::AxisVelocityCalculator(const SharedTimeSource &timeSource,
32+ QObject *parent)
38 : QObject(parent)
33 : QObject(parent)
39− , m_timeSource(new RealTimeSource)
34+ , m_timeSource(timeSource)
40 , m_trackedPosition(0.0)
35 , m_trackedPosition(0.0)
41{
36{
42− m_timeSource->setParent(this);
43 reset();
37 reset();
44}
38}
45
39
@@ -142,11 +136,8 @@ int AxisVelocityCalculator::numSamples() const
142 }
136 }
143}
137}
144
138
145−void AxisVelocityCalculator::setTimeSource(UbuntuGestures::TimeSource *timeSource)
139+void AxisVelocityCalculator::setTimeSource(const SharedTimeSource &timeSource)
146{
140{
147− if (m_timeSource && m_timeSource->parent() == this)
148− delete m_timeSource;
149−
150 m_timeSource = timeSource;
141 m_timeSource = timeSource;
151
142
152 if (numSamples() > 0) {
143 if (numSamples() > 0) {
plugins/Ubuntu/Gestures/AxisVelocityCalculator.h+9−16
@@ -24,19 +24,7 @@
24#include "UbuntuGesturesGlobal.h"
24#include "UbuntuGesturesGlobal.h"
25#include <stdint.h>
25#include <stdint.h>
26#include <QtCore/QObject>
26#include <QtCore/QObject>
27−
27+#include "TimeSource.h"
28−namespace UbuntuGestures {
29−/*
30− Interface for a time source.
31− */
32−class UBUNTUGESTURES_EXPORT TimeSource : public QObject {
33− Q_OBJECT
34−public:
35− virtual ~TimeSource() {}
36− /* Returns the current time in milliseconds since some reference time in the past. */
37− virtual qint64 msecsSinceReference() = 0;
38−};
39−}
40
28
41/*
29/*
42 Estimates the current velocity of a finger based on recent movement along an axis
30 Estimates the current velocity of a finger based on recent movement along an axis
@@ -73,10 +61,15 @@ class UBUNTUGESTURES_EXPORT AxisVelocityCalculator : public QObject
73public:
61public:
74
62
75 /*
63 /*
76− Regular constructor
64+ Regular, simple, constructor
77 */
65 */
78 AxisVelocityCalculator(QObject *parent = 0);
66 AxisVelocityCalculator(QObject *parent = 0);
79
67
68+ /*
69+ Constructor that takes a TimeSource
70+ */
71+ AxisVelocityCalculator(const UbuntuGestures::SharedTimeSource &timeSource, QObject *parent = 0);
72+
80 virtual ~AxisVelocityCalculator();
73 virtual ~AxisVelocityCalculator();
81
74
82 qreal trackedPosition() const;
75 qreal trackedPosition() const;
@@ -97,7 +90,7 @@ public:
97 /*
90 /*
98 Replaces the TimeSource with the given one. Useful for testing purposes.
91 Replaces the TimeSource with the given one. Useful for testing purposes.
99 */
92 */
100− void setTimeSource(UbuntuGestures::TimeSource *timeSource);
93+ void setTimeSource(const UbuntuGestures::SharedTimeSource &timeSource);
101
94
102 /*
95 /*
103 The minimum amount of samples needed for a velocity calculation.
96 The minimum amount of samples needed for a velocity calculation.
@@ -145,7 +138,7 @@ private:
145 int m_samplesRead; /* index of the oldest sample available. -1 if buffer is empty */
138 int m_samplesRead; /* index of the oldest sample available. -1 if buffer is empty */
146 int m_samplesWrite; /* index where the next sample will be written */
139 int m_samplesWrite; /* index where the next sample will be written */
147
140
148− UbuntuGestures::TimeSource *m_timeSource;
141+ UbuntuGestures::SharedTimeSource m_timeSource;
149
142
150 qreal m_trackedPosition;
143 qreal m_trackedPosition;
151};
144};
plugins/Ubuntu/Gestures/CMakeLists.txt+1
@@ -6,6 +6,7 @@ set(UbuntuGestureQml_SOURCES
6 AxisVelocityCalculator.cpp
6 AxisVelocityCalculator.cpp
7 Direction.cpp
7 Direction.cpp
8 DirectionalDragArea.cpp
8 DirectionalDragArea.cpp
9+ TimeSource.cpp
9)
10)
10
11
11add_definitions(-DUBUNTUGESTURES_LIBRARY)
12add_definitions(-DUBUNTUGESTURES_LIBRARY)
plugins/Ubuntu/Gestures/DirectionalDragArea.cpp+307−71
@@ -18,6 +18,75 @@
18
18
19#include <QtCore/qmath.h>
19#include <QtCore/qmath.h>
20#include <QtCore/QTimer>
20#include <QtCore/QTimer>
21+#include <QDebug>
22+
23+using namespace UbuntuGestures;
24+
25+#define DIRECTIONALDRAGAREA_DEBUG 0
26+
27+#if DIRECTIONALDRAGAREA_DEBUG
28+#define DDA_DEBUG(msg) qDebug("[DDA] " msg)
29+namespace {
30+QString touchPointStateToString(Qt::TouchPointState state) {
31+ switch (state) {
32+ case Qt::TouchPointPressed:
33+ return QString("pressed");
34+ case Qt::TouchPointMoved:
35+ return QString("moved");
36+ case Qt::TouchPointStationary:
37+ return QString("stationary");
38+ default: // Qt::TouchPointReleased:
39+ return QString("released");
40+ }
41+}
42+QString touchEventToString(QTouchEvent *ev)
43+{
44+ QString message;
45+
46+ switch (ev->type()) {
47+ case QEvent::TouchBegin:
48+ message.append("TouchBegin ");
49+ break;
50+ case QEvent::TouchUpdate:
51+ message.append("TouchUpdate ");
52+ break;
53+ case QEvent::TouchEnd:
54+ message.append("TouchEnd ");
55+ break;
56+ default: //QEvent::TouchCancel
57+ message.append("TouchCancel ");
58+ }
59+
60+ for (int i=0; i < ev->touchPoints().size(); ++i) {
61+
62+ const QTouchEvent::TouchPoint& touchPoint = ev->touchPoints().at(i);
63+ message.append(
64+ QString("(id:%1, state:%2, scenePos:(%3,%4)) ")
65+ .arg(touchPoint.id())
66+ .arg(touchPointStateToString(touchPoint.state()))
67+ .arg(touchPoint.scenePos().x())
68+ .arg(touchPoint.scenePos().y())
69+ );
70+ }
71+
72+ return message;
73+}
74+
75+const char *statusToString(DirectionalDragArea::Status status)
76+{
77+ if (status == DirectionalDragArea::WaitingForTouch) {
78+ return "WaitingForTouch";
79+ } else if (status == DirectionalDragArea::Undecided) {
80+ return "Undecided";
81+ } else {
82+ return "Recognized";
83+ }
84+}
85+
86+} // namespace {
87+#else // DIRECTIONALDRAGAREA_DEBUG
88+#define DDA_DEBUG(msg) do{}while(0)
89+#endif // DIRECTIONALDRAGAREA_DEBUG
21
90
22// Essentially a QTimer wrapper
91// Essentially a QTimer wrapper
23class RecognitionTimer : public UbuntuGestures::AbstractTimer
92class RecognitionTimer : public UbuntuGestures::AbstractTimer
@@ -48,9 +117,12 @@ DirectionalDragArea::DirectionalDragArea(QQuickItem *parent)
48 , m_minSpeed(0)
117 , m_minSpeed(0)
49 , m_maxSilenceTime(200)
118 , m_maxSilenceTime(200)
50 , m_silenceTime(0)
119 , m_silenceTime(0)
120+ , m_compositionTime(60)
51 , m_numSamplesOnLastSpeedCheck(0)
121 , m_numSamplesOnLastSpeedCheck(0)
52 , m_recognitionTimer(0)
122 , m_recognitionTimer(0)
53 , m_velocityCalculator(0)
123 , m_velocityCalculator(0)
124+ , m_timeSource(new RealTimeSource)
125+ , m_activeTouches(m_timeSource)
54{
126{
55 setRecognitionTimer(new RecognitionTimer(this));
127 setRecognitionTimer(new RecognitionTimer(this));
56 m_recognitionTimer->setInterval(60);
128 m_recognitionTimer->setInterval(60);
@@ -73,8 +145,8 @@ void DirectionalDragArea::setDirection(Direction::Type direction)
73
145
74void DirectionalDragArea::setMaxDeviation(qreal value)
146void DirectionalDragArea::setMaxDeviation(qreal value)
75{
147{
76− if (m_dampedPos.maxDelta() != value) {
148+ if (m_dampedScenePos.maxDelta() != value) {
77− m_dampedPos.setMaxDelta(value);
149+ m_dampedScenePos.setMaxDelta(value);
78 Q_EMIT maxDeviationChanged(value);
150 Q_EMIT maxDeviationChanged(value);
79 }
151 }
80}
152}
@@ -118,6 +190,14 @@ void DirectionalDragArea::setMaxSilenceTime(int value)
118 }
190 }
119}
191}
120
192
193+void DirectionalDragArea::setCompositionTime(int value)
194+{
195+ if (m_compositionTime != value) {
196+ m_compositionTime = value;
197+ Q_EMIT compositionTimeChanged(value);
198+ }
199+}
200+
121void DirectionalDragArea::setRecognitionTimer(UbuntuGestures::AbstractTimer *timer)
201void DirectionalDragArea::setRecognitionTimer(UbuntuGestures::AbstractTimer *timer)
122{
202{
123 int interval = 0;
203 int interval = 0;
@@ -141,9 +221,11 @@ void DirectionalDragArea::setRecognitionTimer(UbuntuGestures::AbstractTimer *tim
141 }
221 }
142}
222}
143
223
144−void DirectionalDragArea::setTimeSource(UbuntuGestures::TimeSource *timeSource)
224+void DirectionalDragArea::setTimeSource(const SharedTimeSource &timeSource)
145{
225{
226+ m_timeSource = timeSource;
146 m_velocityCalculator->setTimeSource(timeSource);
227 m_velocityCalculator->setTimeSource(timeSource);
228+ m_activeTouches.m_timeSource = timeSource;
147}
229}
148
230
149qreal DirectionalDragArea::distance() const
231qreal DirectionalDragArea::distance() const
@@ -186,6 +268,12 @@ qreal DirectionalDragArea::touchSceneY() const
186
268
187void DirectionalDragArea::touchEvent(QTouchEvent *event)
269void DirectionalDragArea::touchEvent(QTouchEvent *event)
188{
270{
271+ #if DIRECTIONALDRAGAREA_DEBUG
272+ // TODO Consider using qCDebug() when available (Qt 5.2)
273+ qDebug() << "[DDA]" << m_timeSource->msecsSinceReference()
274+ << qPrintable(touchEventToString(event));
275+ #endif
276+
189 if (!isEnabled() || !isVisible()) {
277 if (!isEnabled() || !isVisible()) {
190 QQuickItem::touchEvent(event);
278 QQuickItem::touchEvent(event);
191 return;
279 return;
@@ -198,76 +286,124 @@ void DirectionalDragArea::touchEvent(QTouchEvent *event)
198 case Undecided:
286 case Undecided:
199 touchEvent_undecided(event);
287 touchEvent_undecided(event);
200 break;
288 break;
201− case Recognized:
289+ default: // Recognized:
202 touchEvent_recognized(event);
290 touchEvent_recognized(event);
203 break;
291 break;
204− default: // Rejected
205− touchEvent_rejected(event);
206− break;
207 }
292 }
293+
294+ m_activeTouches.update(event);
208}
295}
209
296
210void DirectionalDragArea::touchEvent_absent(QTouchEvent *event)
297void DirectionalDragArea::touchEvent_absent(QTouchEvent *event)
211{
298{
212− if ((event->touchPointStates() && (Qt::TouchPointPressed || Qt::TouchPointMoved))
299+ if (!event->touchPointStates().testFlag(Qt::TouchPointPressed)) {
213− && event->touchPoints().count() == 1) {
300+ // Nothing to see here. No touch starting in this event.
214− const QTouchEvent::TouchPoint &touchPoint = event->touchPoints()[0];
301+ return;
215− m_startPos = touchPoint.pos();
302+ }
216− m_startScenePos = touchPoint.scenePos();
217− m_touchId = touchPoint.id();
218− m_dampedPos.reset(m_startPos);
219− updateVelocityCalculator(m_startPos);
220− m_velocityCalculator->reset();
221− m_numSamplesOnLastSpeedCheck = 0;
222− m_silenceTime = 0;
223− setPreviousPos(m_startPos);
224− setPreviousScenePos(m_startScenePos);
225
303
226− if (m_distanceThreshold > 0)
304+ if (isWithinTouchCompositionWindow()) {
227− setStatus(Undecided);
305+ // too close to the last touch start. So we consider them as starting roughly at the same time.
228− else
306+ // Can't be a single-touch gesture.
229− setStatus(Recognized);
307+ #if DIRECTIONALDRAGAREA_DEBUG
308+ qDebug("[DDA] A new touch point came in but we're still within time composition window. Ignoring it.");
309+ #endif
310+ return;
230 }
311 }
312+
313+ const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
314+
315+ const QTouchEvent::TouchPoint *newTouchPoint = nullptr;
316+ for (int i = 0; i < touchPoints.count(); ++i) {
317+ const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
318+ if (touchPoint.state() == Qt::TouchPointPressed) {
319+ if (newTouchPoint) {
320+ // more than one touch starting in this QTouchEvent. Can't be a single-touch gesture
321+ return;
322+ } else {
323+ // that's our candidate
324+ m_touchId = touchPoint.id();
325+ newTouchPoint = &touchPoint;
326+ }
327+ }
328+ }
329+
330+ Q_ASSERT(newTouchPoint);
331+
332+ // If we have made this far, we are good to go to the next status.
333+
334+ m_startPos = newTouchPoint->pos();
335+ m_startScenePos = newTouchPoint->scenePos();
336+ m_touchId = newTouchPoint->id();
337+ m_dampedScenePos.reset(m_startScenePos);
338+ updateVelocityCalculator(m_startScenePos);
339+ m_velocityCalculator->reset();
340+ m_numSamplesOnLastSpeedCheck = 0;
341+ m_silenceTime = 0;
342+ setPreviousPos(m_startPos);
343+ setPreviousScenePos(m_startScenePos);
344+
345+ setStatus(Undecided);
231}
346}
232
347
233void DirectionalDragArea::touchEvent_undecided(QTouchEvent *event)
348void DirectionalDragArea::touchEvent_undecided(QTouchEvent *event)
234{
349{
235 const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event);
350 const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event);
351+
352+ if (!touchPoint) {
353+ qCritical() << "DirectionalDragArea[status=Undecided]: touch " << m_touchId
354+ << "missing from QTouchEvent without first reaching state Qt::TouchPointReleased. "
355+ "Considering it as released.";
356+ setStatus(WaitingForTouch);
357+ return;
358+ }
359+
236− const QPointF &touchPos = touchPoint->pos();
360+ const QPointF &touchScenePos = touchPoint->scenePos();
237
361
238 if (touchPoint->state() == Qt::TouchPointReleased) {
362 if (touchPoint->state() == Qt::TouchPointReleased) {
239 // touch has ended before recognition concluded
363 // touch has ended before recognition concluded
364+ DDA_DEBUG("Touch has ended before recognition concluded");
240 setStatus(WaitingForTouch);
365 setStatus(WaitingForTouch);
241 return;
366 return;
242 }
367 }
243
368
244− if (event->touchPointStates().testFlag(Qt::TouchPointPressed)
369+ if (event->touchPointStates().testFlag(Qt::TouchPointPressed) && isWithinTouchCompositionWindow()) {
245− || event->touchPoints().count() > 1) {
246 // multi-finger drags are not accepted
370 // multi-finger drags are not accepted
371+ DDA_DEBUG("Multi-finger drags are not accepted");
247− setStatus(Rejected);
372+ setStatus(WaitingForTouch);
248 return;
373 return;
249 }
374 }
250
375
251− m_previousDampedPos.setX(m_dampedPos.x());
376+ m_previousDampedScenePos.setX(m_dampedScenePos.x());
252− m_previousDampedPos.setY(m_dampedPos.y());
377+ m_previousDampedScenePos.setY(m_dampedScenePos.y());
253− m_dampedPos.update(touchPos);
378+ m_dampedScenePos.update(touchScenePos);
254− updateVelocityCalculator(touchPos);
379+ updateVelocityCalculator(touchScenePos);
255
380
256 if (!pointInsideAllowedArea()) {
381 if (!pointInsideAllowedArea()) {
382+ DDA_DEBUG("Rejecting gesture because touch point is outside allowed area.");
257− setStatus(Rejected);
383+ setStatus(WaitingForTouch);
258 return;
384 return;
259 }
385 }
260
386
261 if (!movingInRightDirection()) {
387 if (!movingInRightDirection()) {
388+ DDA_DEBUG("Rejecting gesture becauuse touch point is moving in the wrong direction.");
262− setStatus(Rejected);
389+ setStatus(WaitingForTouch);
263 return;
390 return;
264 }
391 }
265
392
266− setPreviousPos(touchPos);
393+ setPreviousPos(touchPoint->pos());
267− setPreviousScenePos(touchPoint->scenePos());
394+ setPreviousScenePos(touchScenePos);
268
395
396+ if (isWithinTouchCompositionWindow()) {
397+ // There's still time for some new touch to appear and ruin our party as it would be combined
398+ // with our m_touchId one and therefore deny the possibility of a single-finger gesture.
399+ DDA_DEBUG("Sill within composition window. Let's wait more.");
400+ return;
401+ }
402+
269− if (movedFarEnough(touchPos)) {
403+ if (movedFarEnough(touchScenePos)) {
270 setStatus(Recognized);
404 setStatus(Recognized);
405+ } else {
406+ DDA_DEBUG("Didn't move far enough yet. Let's wait more.");
271 }
407 }
272}
408}
273
409
@@ -275,20 +411,18 @@ void DirectionalDragArea::touchEvent_recognized(QTouchEvent *event)
275{
411{
276 const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event);
412 const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event);
277
413
278− setPreviousPos(touchPoint->pos());
279− setPreviousScenePos(touchPoint->scenePos());
280−
281− if (touchPoint->state() == Qt::TouchPointReleased) {
414+ if (!touchPoint) {
415+ qCritical() << "DirectionalDragArea[status=Recognized]: touch " << m_touchId
416+ << "missing from QTouchEvent without first reaching state Qt::TouchPointReleased. "
417+ "Considering it as released.";
282 setStatus(WaitingForTouch);
418 setStatus(WaitingForTouch);
283− }
419+ } else {
284−}
420+ setPreviousPos(touchPoint->pos());
285−
421+ setPreviousScenePos(touchPoint->scenePos());
286−void DirectionalDragArea::touchEvent_rejected(QTouchEvent *event)
287−{
288− const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event);
289
422
290− if (!touchPoint || touchPoint->state() == Qt::TouchPointReleased) {
423+ if (touchPoint->state() == Qt::TouchPointReleased) {
291− setStatus(WaitingForTouch);
424+ setStatus(WaitingForTouch);
425+ }
292 }
426 }
293}
427}
294
428
@@ -307,8 +441,8 @@ const QTouchEvent::TouchPoint *DirectionalDragArea::fetchTargetTouchPoint(QTouch
307
441
308bool DirectionalDragArea::pointInsideAllowedArea() const
442bool DirectionalDragArea::pointInsideAllowedArea() const
309{
443{
310− qreal dX = m_dampedPos.x() - m_startPos.x();
444+ qreal dX = m_dampedScenePos.x() - m_startScenePos.x();
311− qreal dY = m_dampedPos.y() - m_startPos.y();
445+ qreal dY = m_dampedScenePos.y() - m_startScenePos.y();
312
446
313 switch (m_direction) {
447 switch (m_direction) {
314 case Direction::Upwards:
448 case Direction::Upwards:
@@ -326,22 +460,26 @@ bool DirectionalDragArea::movingInRightDirection() const
326{
460{
327 switch (m_direction) {
461 switch (m_direction) {
328 case Direction::Upwards:
462 case Direction::Upwards:
329− return m_dampedPos.y() <= m_previousDampedPos.y();
463+ return m_dampedScenePos.y() <= m_previousDampedScenePos.y();
330 case Direction::Downwards:
464 case Direction::Downwards:
331− return m_dampedPos.y() >= m_previousDampedPos.y();
465+ return m_dampedScenePos.y() >= m_previousDampedScenePos.y();
332 case Direction::Leftwards:
466 case Direction::Leftwards:
333− return m_dampedPos.x() <= m_previousDampedPos.x();
467+ return m_dampedScenePos.x() <= m_previousDampedScenePos.x();
334 default: // Direction::Rightwards:
468 default: // Direction::Rightwards:
335− return m_dampedPos.x() >= m_previousDampedPos.x();
469+ return m_dampedScenePos.x() >= m_previousDampedScenePos.x();
336 }
470 }
337}
471}
338
472
339bool DirectionalDragArea::movedFarEnough(const QPointF &point) const
473bool DirectionalDragArea::movedFarEnough(const QPointF &point) const
340{
474{
475+ if (m_distanceThreshold > 0) {
341− if (Direction::isHorizontal(m_direction))
476+ if (Direction::isHorizontal(m_direction))
342− return qFabs(point.x() - m_startPos.x()) > m_distanceThreshold;
477+ return qFabs(point.x() - m_startScenePos.x()) > m_distanceThreshold;
343− else
478+ else
344− return qFabs(point.y() - m_startPos.y()) > m_distanceThreshold;
479+ return qFabs(point.y() - m_startScenePos.y()) > m_distanceThreshold;
480+ } else {
481+ return true;
482+ }
345}
483}
346
484
347void DirectionalDragArea::checkSpeed()
485void DirectionalDragArea::checkSpeed()
@@ -351,7 +489,8 @@ void DirectionalDragArea::checkSpeed()
351 qreal minSpeedMsecs = m_minSpeed / 1000.0;
489 qreal minSpeedMsecs = m_minSpeed / 1000.0;
352
490
353 if (speed < minSpeedMsecs) {
491 if (speed < minSpeedMsecs) {
492+ DDA_DEBUG("Rejecting gesture because it's below minimum speed.");
354− setStatus(Rejected);
493+ setStatus(WaitingForTouch);
355 }
494 }
356 }
495 }
357
496
@@ -359,7 +498,8 @@ void DirectionalDragArea::checkSpeed()
359 m_silenceTime += m_recognitionTimer->interval();
498 m_silenceTime += m_recognitionTimer->interval();
360
499
361 if (m_silenceTime > m_maxSilenceTime) {
500 if (m_silenceTime > m_maxSilenceTime) {
501+ DDA_DEBUG("Rejecting gesture because it's silence time has been exceeded.");
362− setStatus(Rejected);
502+ setStatus(WaitingForTouch);
363 }
503 }
364 } else {
504 } else {
365 m_silenceTime = 0;
505 m_silenceTime = 0;
@@ -381,11 +521,13 @@ void DirectionalDragArea::setStatus(DirectionalDragArea::Status newStatus)
381 m_status = newStatus;
521 m_status = newStatus;
382 Q_EMIT statusChanged(m_status);
522 Q_EMIT statusChanged(m_status);
383
523
524+ #if DIRECTIONALDRAGAREA_DEBUG
525+ qDebug() << "[DDA]" << statusToString(oldStatus) << "->" << statusToString(newStatus);
526+ #endif
527+
384 switch (newStatus) {
528 switch (newStatus) {
385 case WaitingForTouch:
529 case WaitingForTouch:
386− if (oldStatus != DirectionalDragArea::Rejected) {
387− Q_EMIT draggingChanged(false);
530+ Q_EMIT draggingChanged(false);
388− }
389 break;
531 break;
390 case Undecided:
532 case Undecided:
391 m_recognitionTimer->start();
533 m_recognitionTimer->start();
@@ -395,9 +537,6 @@ void DirectionalDragArea::setStatus(DirectionalDragArea::Status newStatus)
395 if (oldStatus == WaitingForTouch)
537 if (oldStatus == WaitingForTouch)
396 Q_EMIT draggingChanged(true);
538 Q_EMIT draggingChanged(true);
397 break;
539 break;
398− case Rejected:
399− Q_EMIT draggingChanged(false);
400− break;
401 default:
540 default:
402 // no-op
541 // no-op
403 break;
542 break;
@@ -406,8 +545,6 @@ void DirectionalDragArea::setStatus(DirectionalDragArea::Status newStatus)
406
545
407void DirectionalDragArea::setPreviousPos(const QPointF &point)
546void DirectionalDragArea::setPreviousPos(const QPointF &point)
408{
547{
409− Q_ASSERT(m_status != Rejected);
410−
411 bool xChanged = m_previousPos.x() != point.x();
548 bool xChanged = m_previousPos.x() != point.x();
412 bool yChanged = m_previousPos.y() != point.y();
549 bool yChanged = m_previousPos.y() != point.y();
413
550
@@ -428,8 +565,6 @@ void DirectionalDragArea::setPreviousPos(const QPointF &point)
428
565
429void DirectionalDragArea::setPreviousScenePos(const QPointF &point)
566void DirectionalDragArea::setPreviousScenePos(const QPointF &point)
430{
567{
431− Q_ASSERT(m_status != Rejected);
432−
433 bool xChanged = m_previousScenePos.x() != point.x();
568 bool xChanged = m_previousScenePos.x() != point.x();
434 bool yChanged = m_previousScenePos.y() != point.y();
569 bool yChanged = m_previousScenePos.y() != point.y();
435
570
@@ -457,5 +592,106 @@ void DirectionalDragArea::updateVelocityCalculator(const QPointF &point)
457 }
592 }
458}
593}
459
594
595+bool DirectionalDragArea::isWithinTouchCompositionWindow()
596+{
597+ return !m_activeTouches.isEmpty() &&
598+ m_timeSource->msecsSinceReference() <=
599+ m_activeTouches.mostRecentStartTime() + (qint64)compositionTime();
600+}
601+
602+//************************** ActiveTouchesInfo **************************
603+
604+DirectionalDragArea::ActiveTouchesInfo::ActiveTouchesInfo(const SharedTimeSource &timeSource)
605+ : m_timeSource(timeSource), m_lastUsedIndex(-1)
606+{
607+ // Estimate of the maximum number of active touches we might reach.
608+ // Not a problem if it ends up being an underestimate as this is just
609+ // an optimization.
610+ m_vector.resize(3);
611+}
612+
613+void DirectionalDragArea::ActiveTouchesInfo::update(QTouchEvent *event)
614+{
615+ if (!(event->touchPointStates() & (Qt::TouchPointPressed | Qt::TouchPointReleased))) {
616+ // nothing to update
617+ return;
618+ }
619+
620+ const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
621+ for (int i = 0; i < touchPoints.count(); ++i) {
622+ const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
623+ if (touchPoint.state() == Qt::TouchPointPressed) {
624+ addTouchPoint(touchPoint);
625+ } else if (touchPoint.state() == Qt::TouchPointReleased) {
626+ removeTouchPoint(touchPoint);
627+ }
628+ }
629+}
630+
631+void DirectionalDragArea::ActiveTouchesInfo::addTouchPoint(const QTouchEvent::TouchPoint &touchPoint)
632+{
633+ ActiveTouchInfo &activeTouchInfo = getEmptySlot();
634+ activeTouchInfo.id = touchPoint.id();
635+ activeTouchInfo.startTime = m_timeSource->msecsSinceReference();
636+}
637+
638+void DirectionalDragArea::ActiveTouchesInfo::removeTouchPoint(const QTouchEvent::TouchPoint &touchPoint)
639+{
640+ for (int i = 0; i <= m_lastUsedIndex; ++i) {
641+ if (touchPoint.id() == m_vector.at(i).id) {
642+ freeSlot(i);
643+ return;
644+ }
645+ }
646+ Q_ASSERT(false); // shouldn't reach this point
647+}
648+
649+DirectionalDragArea::ActiveTouchInfo &DirectionalDragArea::ActiveTouchesInfo::getEmptySlot()
650+{
651+ Q_ASSERT(m_lastUsedIndex < m_vector.size());
652+
653+ // Look for an in-between vacancy first
654+ for (int i = 0; i < m_lastUsedIndex; ++i) {
655+ ActiveTouchInfo &activeTouchInfo = m_vector[i];
656+ if (!activeTouchInfo.isValid()) {
657+ return activeTouchInfo;
658+ }
659+ }
660+
661+ ++m_lastUsedIndex;
662+ if (m_lastUsedIndex >= m_vector.size()) {
663+ m_vector.resize(m_lastUsedIndex + 1);
664+ }
665+
666+ return m_vector[m_lastUsedIndex];
667+}
668+
669+void DirectionalDragArea::ActiveTouchesInfo::freeSlot(int index)
670+{
671+ m_vector[index].reset();
672+ if (index == m_lastUsedIndex) {
673+ do {
674+ --m_lastUsedIndex;
675+ } while (m_lastUsedIndex >= 0 && !m_vector.at(m_lastUsedIndex).isValid());
676+ }
677+}
678+
679+qint64 DirectionalDragArea::ActiveTouchesInfo::mostRecentStartTime()
680+{
681+ Q_ASSERT(m_lastUsedIndex >= 0);
682+
683+ qint64 highestStartTime = m_vector.at(0).startTime;
684+ int i = 1;
685+ do {
686+ const ActiveTouchInfo &activeTouchInfo = m_vector.at(i);
687+ if (activeTouchInfo.isValid() && activeTouchInfo.startTime > highestStartTime) {
688+ highestStartTime = activeTouchInfo.startTime;
689+ }
690+ ++i;
691+ } while (i < m_lastUsedIndex);
692+
693+ return highestStartTime;
694+}
695+
460// Because we are defining a new QObject-based class (RecognitionTimer) here.
696// Because we are defining a new QObject-based class (RecognitionTimer) here.
461#include "DirectionalDragArea.moc"
697#include "DirectionalDragArea.moc"
plugins/Ubuntu/Gestures/DirectionalDragArea.h+50−13
@@ -117,9 +117,17 @@ class UBUNTUGESTURES_EXPORT DirectionalDragArea : public QQuickItem {
117 Q_PROPERTY(int maxSilenceTime READ maxSilenceTime
117 Q_PROPERTY(int maxSilenceTime READ maxSilenceTime
118 WRITE setMaxSilenceTime
118 WRITE setMaxSilenceTime
119 NOTIFY maxSilenceTimeChanged)
119 NOTIFY maxSilenceTimeChanged)
120+
120 //
121 //
121 /////
122 /////
122
123
124+ // Maximum time (in milliseconds) after the start of a given touch point where
125+ // subsequent touch starts are grouped with the first one into an N-touches gesture
126+ // (e.g. a two-fingers tap or drag).
127+ Q_PROPERTY(int compositionTime READ compositionTime
128+ WRITE setCompositionTime
129+ NOTIFY compositionTimeChanged)
130+
123 Q_ENUMS(Direction)
131 Q_ENUMS(Direction)
124 Q_ENUMS(Status)
132 Q_ENUMS(Status)
125public:
133public:
@@ -130,26 +138,23 @@ public:
130
138
131 // Describes the state of the directional drag gesture.
139 // Describes the state of the directional drag gesture.
132 enum Status {
140 enum Status {
133− // There's no touch point over this area.
141+ // Waiting for a new touch point to land on this area. No gesture is being processed
142+ // or tracked.
134 WaitingForTouch,
143 WaitingForTouch,
135
144
136 // A touch point has landed on this area but it's not know yet whether it is
145 // A touch point has landed on this area but it's not know yet whether it is
137 // performing a drag in the correct direction.
146 // performing a drag in the correct direction.
147+ // If it's decided that the touch point is not performing a directional drag gesture,
148+ // it will be rejected/ignored and status will return to WaitingForTouch.
138 Undecided, //Recognizing,
149 Undecided, //Recognizing,
139
150
140 // There's a touch point in this area and it performed a drag in the correct
151 // There's a touch point in this area and it performed a drag in the correct
141 // direction.
152 // direction.
142 //
153 //
143− // Once recognized, the gesture state will move back to Absent only once
154+ // Once recognized, the gesture state will move back to WaitingForTouch only once
144 // that touch point ends. The gesture will remain in the Recognized state even if
155 // that touch point ends. The gesture will remain in the Recognized state even if
145 // the touch point starts moving in other directions or halts.
156 // the touch point starts moving in other directions or halts.
146 Recognized,
157 Recognized,
147−
148− // A gesture was performed but it wasn't a single-touch drag in the correct
149− // direction.
150− // It will remain in this state until there are no more touch points over this
151− // area, at which point it will move to Absent state.
152− Rejected
153 };
158 };
154 Status status() const { return m_status; }
159 Status status() const { return m_status; }
155
160
@@ -164,7 +169,7 @@ public:
164
169
165 bool dragging() const { return (m_status == Undecided) || (m_status == Recognized); }
170 bool dragging() const { return (m_status == Undecided) || (m_status == Recognized); }
166
171
167− qreal maxDeviation() const { return m_dampedPos.maxDelta(); }
172+ qreal maxDeviation() const { return m_dampedScenePos.maxDelta(); }
168 void setMaxDeviation(qreal value);
173 void setMaxDeviation(qreal value);
169
174
170 qreal wideningAngle() const;
175 qreal wideningAngle() const;
@@ -179,13 +184,16 @@ public:
179 int maxSilenceTime() const { return m_maxSilenceTime; }
184 int maxSilenceTime() const { return m_maxSilenceTime; }
180 void setMaxSilenceTime(int value);
185 void setMaxSilenceTime(int value);
181
186
187+ int compositionTime() const { return m_compositionTime; }
188+ void setCompositionTime(int value);
189+
182 // Replaces the existing Timer with the given one.
190 // Replaces the existing Timer with the given one.
183 //
191 //
184 // Useful for providing a fake timer when testing.
192 // Useful for providing a fake timer when testing.
185 void setRecognitionTimer(UbuntuGestures::AbstractTimer *timer);
193 void setRecognitionTimer(UbuntuGestures::AbstractTimer *timer);
186
194
187 // Useful for testing, where a fake time source can be supplied
195 // Useful for testing, where a fake time source can be supplied
188− void setTimeSource(UbuntuGestures::TimeSource *timeSource);
196+ void setTimeSource(const UbuntuGestures::SharedTimeSource &timeSource);
189
197
190Q_SIGNALS:
198Q_SIGNALS:
191 void directionChanged(Direction::Type direction);
199 void directionChanged(Direction::Type direction);
@@ -198,6 +206,7 @@ Q_SIGNALS:
198 void distanceThresholdChanged(qreal value);
206 void distanceThresholdChanged(qreal value);
199 void minSpeedChanged(qreal value);
207 void minSpeedChanged(qreal value);
200 void maxSilenceTimeChanged(int value);
208 void maxSilenceTimeChanged(int value);
209+ void compositionTimeChanged(int value);
201 void touchXChanged(qreal value);
210 void touchXChanged(qreal value);
202 void touchYChanged(qreal value);
211 void touchYChanged(qreal value);
203 void touchSceneXChanged(qreal value);
212 void touchSceneXChanged(qreal value);
@@ -213,7 +222,6 @@ private:
213 void touchEvent_absent(QTouchEvent *event);
222 void touchEvent_absent(QTouchEvent *event);
214 void touchEvent_undecided(QTouchEvent *event);
223 void touchEvent_undecided(QTouchEvent *event);
215 void touchEvent_recognized(QTouchEvent *event);
224 void touchEvent_recognized(QTouchEvent *event);
216− void touchEvent_rejected(QTouchEvent *event);
217 bool pointInsideAllowedArea() const;
225 bool pointInsideAllowedArea() const;
218 bool movingInRightDirection() const;
226 bool movingInRightDirection() const;
219 bool movedFarEnough(const QPointF &point) const;
227 bool movedFarEnough(const QPointF &point) const;
@@ -222,6 +230,7 @@ private:
222 void setPreviousPos(const QPointF &point);
230 void setPreviousPos(const QPointF &point);
223 void setPreviousScenePos(const QPointF &point);
231 void setPreviousScenePos(const QPointF &point);
224 void updateVelocityCalculator(const QPointF &point);
232 void updateVelocityCalculator(const QPointF &point);
233+ bool isWithinTouchCompositionWindow();
225
234
226 Status m_status;
235 Status m_status;
227
236
@@ -233,8 +242,8 @@ private:
233
242
234 // A movement damper is used in some of the gesture recognition calculations
243 // A movement damper is used in some of the gesture recognition calculations
235 // to get rid of noise or small oscillations in the touch position.
244 // to get rid of noise or small oscillations in the touch position.
236− DampedPointF m_dampedPos;
245+ DampedPointF m_dampedScenePos;
237− QPointF m_previousDampedPos;
246+ QPointF m_previousDampedScenePos;
238
247
239 Direction::Type m_direction;
248 Direction::Type m_direction;
240 qreal m_wideningAngle; // in degrees
249 qreal m_wideningAngle; // in degrees
@@ -243,9 +252,37 @@ private:
243 qreal m_minSpeed;
252 qreal m_minSpeed;
244 int m_maxSilenceTime; // in milliseconds
253 int m_maxSilenceTime; // in milliseconds
245 int m_silenceTime; // in milliseconds
254 int m_silenceTime; // in milliseconds
255+ int m_compositionTime; // in milliseconds
246 int m_numSamplesOnLastSpeedCheck;
256 int m_numSamplesOnLastSpeedCheck;
247 UbuntuGestures::AbstractTimer *m_recognitionTimer;
257 UbuntuGestures::AbstractTimer *m_recognitionTimer;
248 AxisVelocityCalculator *m_velocityCalculator;
258 AxisVelocityCalculator *m_velocityCalculator;
259+
260+ UbuntuGestures::SharedTimeSource m_timeSource;
261+
262+ // Information about an active touch point
263+ struct ActiveTouchInfo {
264+ ActiveTouchInfo() : id(-1), startTime(-1) {}
265+ bool isValid() const { return id != -1; }
266+ void reset() { id = -1; }
267+ int id;
268+ qint64 startTime;
269+ };
270+ class ActiveTouchesInfo {
271+ public:
272+ ActiveTouchesInfo(const UbuntuGestures::SharedTimeSource &timeSource);
273+ void update(QTouchEvent *event);
274+ ActiveTouchInfo &touchInfo(int id);
275+ qint64 mostRecentStartTime();
276+ UbuntuGestures::SharedTimeSource m_timeSource;
277+ bool isEmpty() const { return m_lastUsedIndex == -1; }
278+ private:
279+ void addTouchPoint(const QTouchEvent::TouchPoint &touchPoint);
280+ ActiveTouchInfo &getEmptySlot();
281+ void freeSlot(int index);
282+ void removeTouchPoint(const QTouchEvent::TouchPoint &touchPoint);
283+ QVector<struct ActiveTouchInfo> m_vector;
284+ int m_lastUsedIndex;
285+ } m_activeTouches;
249};
286};
250
287
251#endif // DIRECTIONAL_DRAG_AREA_H
288#endif // DIRECTIONAL_DRAG_AREA_H
plugins/Ubuntu/Gestures/TimeSource.cppnew file+49
@@ -0,0 +1,49 @@
1+/*
2+ * Copyright (C) 2013 - Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License, as
6+ * published by the Free Software Foundation; either version 2.1 or 3.0
7+ * of the License.
8+ *
9+ * This program is distributed in the hope that it will be useful, but
10+ * WITHOUT ANY WARRANTY; without even the implied warranties of
11+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12+ * PURPOSE. See the applicable version of the GNU Lesser General Public
13+ * License for more details.
14+ *
15+ * You should have received a copy of both the GNU Lesser General Public
16+ * License along with this program. If not, see <http://www.gnu.org/licenses/>
17+ *
18+ * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
19+ */
20+
21+#include "TimeSource.h"
22+
23+#include <QElapsedTimer>
24+
25+namespace UbuntuGestures {
26+class RealTimeSourcePrivate {
27+public:
28+ QElapsedTimer timer;
29+};
30+}
31+
32+using namespace UbuntuGestures;
33+
34+RealTimeSource::RealTimeSource()
35+ : UbuntuGestures::TimeSource()
36+ , d(new RealTimeSourcePrivate)
37+{
38+ d->timer.start();
39+}
40+
41+RealTimeSource::~RealTimeSource()
42+{
43+ delete d;
44+}
45+
46+qint64 RealTimeSource::msecsSinceReference()
47+{
48+ return d->timer.elapsed();
49+}
plugins/Ubuntu/Gestures/TimeSource.hnew file+54
@@ -0,0 +1,54 @@
1+/*
2+ * Copyright (C) 2013 - Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU Lesser General Public License, as
6+ * published by the Free Software Foundation; either version 2.1 or 3.0
7+ * of the License.
8+ *
9+ * This program is distributed in the hope that it will be useful, but
10+ * WITHOUT ANY WARRANTY; without even the implied warranties of
11+ * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12+ * PURPOSE. See the applicable version of the GNU Lesser General Public
13+ * License for more details.
14+ *
15+ * You should have received a copy of both the GNU Lesser General Public
16+ * License along with this program. If not, see <http://www.gnu.org/licenses/>
17+ *
18+ * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
19+ */
20+
21+#ifndef UBUNTUGESTURES_TIMESOURCE_H
22+#define UBUNTUGESTURES_TIMESOURCE_H
23+
24+#include "UbuntuGesturesGlobal.h"
25+#include <QSharedPointer>
26+
27+namespace UbuntuGestures {
28+/*
29+ Interface for a time source.
30+ */
31+class UBUNTUGESTURES_EXPORT TimeSource {
32+public:
33+ virtual ~TimeSource() {}
34+ /* Returns the current time in milliseconds since some reference time in the past. */
35+ virtual qint64 msecsSinceReference() = 0;
36+};
37+typedef QSharedPointer<TimeSource> SharedTimeSource;
38+
39+/*
40+ Implementation of a time source
41+ */
42+class RealTimeSourcePrivate;
43+class RealTimeSource : public TimeSource {
44+public:
45+ RealTimeSource();
46+ virtual ~RealTimeSource();
47+ qint64 msecsSinceReference() override;
48+private:
49+ RealTimeSourcePrivate *d;
50+};
51+
52+} // namespace UbuntuGestures
53+
54+#endif // UBUNTUGESTURES_TIMESOURCE_H
plugins/Unity/CMakeLists.txt−1
@@ -34,7 +34,6 @@ set(QMLPLUGIN_SRC
34 radiooptionfilter.cpp
34 radiooptionfilter.cpp
35 ratingsfilter.cpp
35 ratingsfilter.cpp
36 ratingfilteroption.cpp
36 ratingfilteroption.cpp
37− bottombarvisibilitycommunicatorshell.cpp
38 applicationpreview.cpp
37 applicationpreview.cpp
39 genericpreview.cpp
38 genericpreview.cpp
40 moviepreview.cpp
39 moviepreview.cpp
plugins/Unity/Indicators/CMakeLists.txt+1
@@ -36,6 +36,7 @@ set(IndicatorsQML_SOURCES
36 unitymenumodelcache.cpp
36 unitymenumodelcache.cpp
37 unitymenumodelstack.cpp
37 unitymenumodelstack.cpp
38 visibleindicatorsmodel.cpp
38 visibleindicatorsmodel.cpp
39+ timeformatter.cpp
39)
40)
40add_definitions(-DUNITYINDICATORS_LIBRARY)
41add_definitions(-DUNITYINDICATORS_LIBRARY)
41
42
plugins/Unity/Indicators/Messaging/qml/MessageMenuItemFactory.qml+3−4
@@ -22,7 +22,6 @@ import QtQuick 2.0
22import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
23import Unity.Indicators 0.1 as Indicators
23import Unity.Indicators 0.1 as Indicators
24import QMenuModel 0.1 as QMenuModel
24import QMenuModel 0.1 as QMenuModel
25−import "utils.js" as Utils
26
25
27Indicators.BaseMenuItem {
26Indicators.BaseMenuItem {
28 id: menuItem
27 id: menuItem
@@ -65,7 +64,7 @@ Indicators.BaseMenuItem {
65 SimpleTextMessage {
64 SimpleTextMessage {
66 // text
65 // text
67 title: menu && menu.label ? menu.label : ""
66 title: menu && menu.label ? menu.label : ""
68− time: menu ? Utils.formatDate(menu.ext.xCanonicalTime) : ""
67+ time: menu ? menu.ext.xCanonicalTime : 0
69 message: menu && menu.ext.xCanonicalText ? menu.ext.xCanonicalText : ""
68 message: menu && menu.ext.xCanonicalText ? menu.ext.xCanonicalText : ""
70 // icons
69 // icons
71 avatar: menu && menu.ext.icon !== undefined ? menu.ext.icon : "qrc:/indicators/artwork/messaging/default_contact.png"
70 avatar: menu && menu.ext.icon !== undefined ? menu.ext.icon : "qrc:/indicators/artwork/messaging/default_contact.png"
@@ -90,7 +89,7 @@ Indicators.BaseMenuItem {
90
89
91 // text
90 // text
92 title: menu && menu.label ? menu.label : ""
91 title: menu && menu.label ? menu.label : ""
93− time: menu ? Utils.formatDate(menu.ext.xCanonicalTime) : ""
92+ time: menu ? menu.ext.xCanonicalTime : 0
94 message: menu && menu.ext.xCanonicalText ? menu.ext.xCanonicalText : ""
93 message: menu && menu.ext.xCanonicalText ? menu.ext.xCanonicalText : ""
95 replyButtonText: actionsDescription && actionsDescription[0].label ? actionsDescription[0].label : "Send"
94 replyButtonText: actionsDescription && actionsDescription[0].label ? actionsDescription[0].label : "Send"
96 // icons
95 // icons
@@ -126,7 +125,7 @@ Indicators.BaseMenuItem {
126
125
127 // text
126 // text
128 title: menu && menu.label ? menu.label : ""
127 title: menu && menu.label ? menu.label : ""
129− time: menu ? Utils.formatDate(menu.ext.xCanonicalTime) : ""
128+ time: menu ? menu.ext.xCanonicalTime : ""
130 message: menu && menu.ext.xCanonicalText ? menu.ext.xCanonicalText : ""
129 message: menu && menu.ext.xCanonicalText ? menu.ext.xCanonicalText : ""
131 actionButtonText: actionsDescription && actionsDescription[0].label ? actionsDescription[0].label : "Call back"
130 actionButtonText: actionsDescription && actionsDescription[0].label ? actionsDescription[0].label : "Call back"
132 replyButtonText: actionsDescription && actionsDescription[1].label ? actionsDescription[1].label : "Send"
131 replyButtonText: actionsDescription && actionsDescription[1].label ? actionsDescription[1].label : "Send"
plugins/Unity/Indicators/Messaging/qml/SimpleTextMessage.qml+9−2
@@ -20,19 +20,20 @@
20
20
21import QtQuick 2.0
21import QtQuick 2.0
22import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
23+import Unity.Indicators 0.1
23
24
24HeroMessage {
25HeroMessage {
25 id: __heroMessage
26 id: __heroMessage
26
27
27 property string title: ""
28 property string title: ""
28− property string time: ""
29+ property var time
29 property string message: ""
30 property string message: ""
30
31
31 property alias footer: footerLoader.sourceComponent
32 property alias footer: footerLoader.sourceComponent
32
33
33 expandedHeight: fullMessage.y + fullMessage.height + units.gu(2)
34 expandedHeight: fullMessage.y + fullMessage.height + units.gu(2)
34 heroMessageHeader.titleText.text: title
35 heroMessageHeader.titleText.text: title
35− heroMessageHeader.subtitleText.text: time
36+ heroMessageHeader.subtitleText.text: timeFormatter.timeString
36 heroMessageHeader.bodyText.text: message
37 heroMessageHeader.bodyText.text: message
37
38
38 Item {
39 Item {
@@ -49,6 +50,12 @@ HeroMessage {
49 opacity: 0.0
50 opacity: 0.0
50 enabled: false
51 enabled: false
51
52
53+ TimeFormatter {
54+ id: timeFormatter
55+ time: __heroMessage.time
56+ format: "hh:mm - MMM dd"
57+ }
58+
52 Label {
59 Label {
53 id: bodyText
60 id: bodyText
54 anchors {
61 anchors {
plugins/Unity/Indicators/Messaging/qml/SnapDecision.qml+9−3
@@ -21,13 +21,13 @@
21import QtQuick 2.0
21import QtQuick 2.0
22import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
23import Unity.Indicators 0.1 as Indicators
23import Unity.Indicators 0.1 as Indicators
24−import "utils.js" as Utils
24+import Unity.Indicators 0.1
25
25
26HeroMessage {
26HeroMessage {
27 id: snapDecision
27 id: snapDecision
28
28
29 property string title: ""
29 property string title: ""
30− property string time: ""
30+ property var time
31 property string message: ""
31 property string message: ""
32
32
33 property bool activateEnabled: true
33 property bool activateEnabled: true
@@ -41,7 +41,7 @@ HeroMessage {
41 heroMessageHeader.titleText.text: title
41 heroMessageHeader.titleText.text: title
42 heroMessageHeader.subtitleText.text: message
42 heroMessageHeader.subtitleText.text: message
43 heroMessageHeader.subtitleText.color: "#e8e1d0"
43 heroMessageHeader.subtitleText.color: "#e8e1d0"
44− heroMessageHeader.bodyText.text: time
44+ heroMessageHeader.bodyText.text: timeFormatter.timeString
45 heroMessageHeader.bodyText.color: "#8f8f88"
45 heroMessageHeader.bodyText.color: "#8f8f88"
46
46
47 signal activate
47 signal activate
@@ -59,6 +59,12 @@ HeroMessage {
59 height: units.gu(4)
59 height: units.gu(4)
60 opacity: 0.0
60 opacity: 0.0
61
61
62+ TimeFormatter {
63+ id: timeFormatter
64+ time: snapDecision.time
65+ format: "hh:mm - MMM dd"
66+ }
67+
62 Button {
68 Button {
63 text: "Message"
69 text: "Message"
64 color: "#bababa"
70 color: "#bababa"
plugins/Unity/Indicators/plugin.cpp+2
@@ -33,6 +33,7 @@
33#include "unitymenumodelcache.h"
33#include "unitymenumodelcache.h"
34#include "unitymenumodelstack.h"
34#include "unitymenumodelstack.h"
35#include "visibleindicatorsmodel.h"
35#include "visibleindicatorsmodel.h"
36+#include "timeformatter.h"
36
37
37static QObject* menuModelCacheSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
38static QObject* menuModelCacheSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
38 Q_UNUSED(engine);
39 Q_UNUSED(engine);
@@ -51,6 +52,7 @@ void Indicators2Plugin::registerTypes(const char *uri)
51 qmlRegisterType<RootActionState>(uri, 0, 1, "RootActionState");
52 qmlRegisterType<RootActionState>(uri, 0, 1, "RootActionState");
52 qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
53 qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
53 qmlRegisterType<VisibleIndicatorsModel>(uri, 0, 1, "VisibleIndicatorsModel");
54 qmlRegisterType<VisibleIndicatorsModel>(uri, 0, 1, "VisibleIndicatorsModel");
55+ qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter");
54
56
55 qmlRegisterSingletonType<UnityMenuModelCache>(uri, 0, 1, "UnityMenuModelCache", menuModelCacheSingleton);
57 qmlRegisterSingletonType<UnityMenuModelCache>(uri, 0, 1, "UnityMenuModelCache", menuModelCacheSingleton);
56
58
plugins/Unity/Indicators/qml/IndicatorPage.qml+27−6
@@ -34,11 +34,36 @@ IndicatorBase {
34 Indicators.UnityMenuModelStack {
34 Indicators.UnityMenuModelStack {
35 id: menuStack
35 id: menuStack
36 head: contentActive ? main.menuModel : null
36 head: contentActive ? main.menuModel : null
37+
38+ property var rootMenu: null
39+
40+ onTailChanged: {
41+ if (!tail) {
42+ rootMenu = null;
43+ } else if (rootMenu != tail) {
44+ if (tail.get(0, "type") === rootMenuType) {
45+ rootMenu = menuStack.tail.submenu(0);
46+ push(rootMenu, 0);
47+ } else {
48+ rootMenu = null;
49+ }
50+ }
51+ }
52+ }
53+
54+ Connections {
55+ target: menuStack.tail
56+ onRowsInserted: {
57+ if (menuStack.rootMenu !== menuStack.tail && menuStack.tail.get(0, "type") === rootMenuType) {
58+ menuStack.rootMenu = menuStack.tail.submenu(0);
59+ menuStack.push(menuStack.rootMenu, 0);
60+ }
61+ }
37 }
62 }
38
63
39 ListView {
64 ListView {
40 id: mainMenu
65 id: mainMenu
41− model: menuStack.tail ? menuStack.tail : null
66+ model: menuStack.rootMenu
42
67
43 anchors {
68 anchors {
44 fill: parent
69 fill: parent
@@ -102,7 +127,7 @@ IndicatorBase {
102
127
103 Loader {
128 Loader {
104 id: loader
129 id: loader
105− asynchronous: true
130+ asynchronous: false
106
131
107 property int modelIndex: index
132 property int modelIndex: index
108
133
@@ -114,10 +139,6 @@ IndicatorBase {
114 sourceComponent: factory.load(model)
139 sourceComponent: factory.load(model)
115
140
116 onLoaded: {
141 onLoaded: {
117− if (model.type === rootMenuType) {
118− menuStack.push(mainMenu.model.submenu(index));
119− }
120−
121 if (item.hasOwnProperty("menuSelected")) {
142 if (item.hasOwnProperty("menuSelected")) {
122 item.menuSelected = Qt.binding(function() { return mainMenu.selectedIndex == index; });
143 item.menuSelected = Qt.binding(function() { return mainMenu.selectedIndex == index; });
123 item.selectMenu.connect(function() { mainMenu.selectedIndex = index; });
144 item.selectMenu.connect(function() { mainMenu.selectedIndex = index; });
plugins/Unity/Indicators/qml/IndicatorWidget.qml+1−1
@@ -24,5 +24,5 @@ IndicatorBase {
24 id: indicatorWidget
24 id: indicatorWidget
25
25
26 enabled: false
26 enabled: false
27− property int iconSize: height - units.gu(0.5)
27+ property int iconSize: height
28}
28}
plugins/Unity/Indicators/qml/SliderMenuItem.qml+3−2
@@ -51,12 +51,12 @@ FramedMenuItem {
51
51
52 control: Item {
52 control: Item {
53 id: row
53 id: row
54− width: sliderMenu.text ? units.gu(20) : menuItem.width - (2 * menuItem.__contentsMargins)
54+ width: menuItem.text ? units.gu(20) : menuItem.width - (2 * menuItem.__contentsMargins)
55 height: slider.height
55 height: slider.height
56
56
57 Image {
57 Image {
58 id: leftImage
58 id: leftImage
59− visible: source != ""
59+ visible: status === Image.Ready
60 anchors.left: row.left
60 anchors.left: row.left
61 anchors.verticalCenter: row.verticalCenter
61 anchors.verticalCenter: row.verticalCenter
62 height: units.gu(4)
62 height: units.gu(4)
@@ -96,6 +96,7 @@ FramedMenuItem {
96
96
97 Image {
97 Image {
98 id: rightImage
98 id: rightImage
99+ visible: status === Image.Ready
99 anchors.right: row.right
100 anchors.right: row.right
100 anchors.verticalCenter: row.verticalCenter
101 anchors.verticalCenter: row.verticalCenter
101 height: units.gu(4)
102 height: units.gu(4)
plugins/Unity/Indicators/timeformatter.cppnew file+172
@@ -0,0 +1,172 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Lars Uebernickel <lars.uebernickel@canonical.com>
17+ */
18+
19+#include "timeformatter.h"
20+
21+#include <gio/gio.h>
22+#include <QDateTime>
23+
24+struct TimeFormatterPrivate
25+{
26+ TimeFormatter *formatter;
27+
28+ QString format;
29+ QString timeString;
30+ qint64 time;
31+
32+ GDBusConnection *system_bus;
33+ guint subscription_id;
34+ GCancellable *cancellable;
35+};
36+
37+static void
38+timedate1_properties_changed (GDBusConnection *connection,
39+ const gchar *sender_name,
40+ const gchar *object_path,
41+ const gchar *interface_name,
42+ const gchar *signal_name,
43+ GVariant *parameters,
44+ gpointer user_data)
45+{
46+ Q_UNUSED(connection);
47+ Q_UNUSED(sender_name);
48+ Q_UNUSED(object_path);
49+ Q_UNUSED(interface_name);
50+ Q_UNUSED(signal_name);
51+
52+ TimeFormatterPrivate *priv = (TimeFormatterPrivate *)user_data;
53+ GVariant *changed;
54+ GVariantIter *iter;
55+ const gchar *name;
56+
57+ if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
58+ return;
59+
60+ g_variant_get (parameters, "(s@a{sv}as)", NULL, &changed, &iter);
61+
62+ if (g_variant_lookup (changed, "Timezone", "s", NULL)) {
63+ priv->formatter->update();
64+ }
65+ else {
66+ while (g_variant_iter_next (iter, "&s", &name)) {
67+ if (g_str_equal (name, "Timezone")) {
68+ priv->formatter->update();
69+ break;
70+ }
71+ }
72+ }
73+
74+ g_variant_unref (changed);
75+ g_variant_iter_free (iter);
76+}
77+
78+static void
79+got_bus(GObject *object, GAsyncResult *result, gpointer user_data)
80+{
81+ Q_UNUSED(object);
82+
83+ TimeFormatterPrivate *priv = (TimeFormatterPrivate *)user_data;
84+ GError *error = NULL;
85+
86+ priv->system_bus = g_bus_get_finish (result, &error);
87+ if (priv->system_bus == NULL) {
88+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
89+ qWarning("TimeFormatter: cannot connect to the system bus: %s", error->message);
90+ g_error_free (error);
91+ return;
92+ }
93+
94+ /* Listen to the PropertiesChanged on the org.freedesktop.timedate1
95+ * interface from any sender. In practice, this signal will only be sent
96+ * from timedated (we can trust other processes on the system bus to behave
97+ * nicely). That way, we don't have to watch timedated's well-known name
98+ * and keep the process alive.
99+ */
100+ priv->subscription_id = g_dbus_connection_signal_subscribe (priv->system_bus,
101+ NULL, /* sender */
102+ "org.freedesktop.DBus.Properties",
103+ "PropertiesChanged",
104+ NULL,
105+ "org.freedesktop.timedate1",
106+ G_DBUS_SIGNAL_FLAGS_NONE,
107+ timedate1_properties_changed,
108+ priv, NULL);
109+}
110+
111+TimeFormatter::TimeFormatter(QObject *parent): QObject(parent)
112+{
113+ priv = new TimeFormatterPrivate;
114+ priv->formatter = this;
115+ priv->time = 0;
116+ priv->format = "yyyy-MM-dd hh:mm";
117+ priv->system_bus = NULL;
118+ priv->subscription_id = 0;
119+ priv->cancellable = g_cancellable_new ();
120+
121+ g_bus_get (G_BUS_TYPE_SYSTEM, priv->cancellable, got_bus, priv);
122+}
123+
124+TimeFormatter::~TimeFormatter()
125+{
126+ if (priv->system_bus) {
127+ g_dbus_connection_signal_unsubscribe (priv->system_bus, priv->subscription_id);
128+ g_object_unref (priv->system_bus);
129+ }
130+
131+ g_cancellable_cancel (priv->cancellable);
132+ g_object_unref (priv->cancellable);
133+}
134+
135+QString TimeFormatter::format() const
136+{
137+ return priv->format;
138+}
139+
140+QString TimeFormatter::timeString() const
141+{
142+ return priv->timeString;
143+}
144+
145+qint64 TimeFormatter::time() const
146+{
147+ return priv->time;
148+}
149+
150+void TimeFormatter::setFormat(const QString &format)
151+{
152+ if (priv->format != format) {
153+ priv->format = format;
154+ Q_EMIT formatChanged(priv->format);
155+ update();
156+ }
157+}
158+
159+void TimeFormatter::setTime(qint64 time)
160+{
161+ if (priv->time != time) {
162+ priv->time = time;
163+ Q_EMIT timeChanged(priv->time);
164+ update();
165+ }
166+}
167+
168+void TimeFormatter::update()
169+{
170+ priv->timeString = QDateTime::fromMSecsSinceEpoch(priv->time / 1000).toString(priv->format);
171+ Q_EMIT timeStringChanged(priv->timeString);
172+}
plugins/Unity/Indicators/timeformatter.hnew file+54
@@ -0,0 +1,54 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Lars Uebernickel <lars.uebernickel@canonical.com>
17+ */
18+
19+#ifndef TIME_FORMATTER_H
20+#define TIME_FORMATTER_H
21+
22+#include "unityindicatorsglobal.h"
23+#include <QObject>
24+
25+class UNITYINDICATORS_EXPORT TimeFormatter : public QObject
26+{
27+ Q_OBJECT
28+ Q_PROPERTY(QString format READ format WRITE setFormat NOTIFY formatChanged)
29+ Q_PROPERTY(QString timeString READ timeString NOTIFY timeStringChanged)
30+ Q_PROPERTY(qint64 time READ time WRITE setTime NOTIFY timeChanged)
31+
32+public:
33+ TimeFormatter(QObject *parent = 0);
34+ ~TimeFormatter();
35+
36+ QString format() const;
37+ QString timeString() const;
38+ qint64 time() const;
39+
40+ void setFormat(const QString &format);
41+ void setTime(qint64 time);
42+
43+ void update();
44+
45+Q_SIGNALS:
46+ void formatChanged(const QString &format);
47+ void timeStringChanged(const QString &timeString);
48+ void timeChanged(qint64 time);
49+
50+private:
51+ struct TimeFormatterPrivate *priv;
52+};
53+
54+#endif
plugins/Unity/Indicators/unitymenumodelstack.cpp+98−7
@@ -19,6 +19,64 @@
19
19
20#include "unitymenumodelstack.h"
20#include "unitymenumodelstack.h"
21
21
22+#include <QDebug>
23+#include <unitymenumodel.h>
24+
25+class UnityMenuModelEntry : public QObject {
26+ Q_OBJECT
27+public:
28+ UnityMenuModelEntry(UnityMenuModel* model, UnityMenuModel* parentModel, int index)
29+ : m_model(model),
30+ m_parentModel(parentModel),
31+ m_index(index)
32+ {
33+ if (m_parentModel) {
34+ QObject::connect(m_parentModel, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(onRowsInserted(QModelIndex, int, int)));
35+ QObject::connect(m_parentModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(onRowsRemoved(QModelIndex, int, int)));
36+ QObject::connect(m_parentModel, SIGNAL(modelReset()), this, SLOT(onModelReset()));
37+ }
38+ }
39+
40+ UnityMenuModel* model() const { return m_model; }
41+
42+private Q_SLOTS:
43+ void onRowsInserted(const QModelIndex&, int start, int end)
44+ {
45+ int delta = end-start + 1;
46+ if (start <= m_index) {
47+ m_index += delta;
48+ }
49+ }
50+
51+ void onRowsRemoved(const QModelIndex&, int start, int end)
52+ {
53+ int delta = end-start + 1;
54+ if (start <= m_index) {
55+ if (start + delta > m_index) {
56+ // in the range removed
57+ Q_EMIT remove();
58+ disconnect(m_parentModel, 0, this, 0);
59+ } else {
60+ m_index -= delta;
61+ }
62+ }
63+ }
64+
65+ void onModelReset()
66+ {
67+ Q_EMIT remove();
68+ disconnect(m_parentModel, 0, this, 0);
69+ }
70+
71+Q_SIGNALS:
72+ void remove();
73+
74+private:
75+ UnityMenuModel* m_model;
76+ UnityMenuModel* m_parentModel;
77+ int m_index;
78+};
79+
22UnityMenuModelStack::UnityMenuModelStack(QObject* parent)
80UnityMenuModelStack::UnityMenuModelStack(QObject* parent)
23 : QObject(parent)
81 : QObject(parent)
24{
82{
@@ -26,31 +84,44 @@ UnityMenuModelStack::UnityMenuModelStack(QObject* parent)
26
84
27UnityMenuModelStack::~UnityMenuModelStack()
85UnityMenuModelStack::~UnityMenuModelStack()
28{
86{
87+ qDeleteAll(m_menuModels);
88+ m_menuModels.clear();
29}
89}
30
90
31UnityMenuModel* UnityMenuModelStack::head() const
91UnityMenuModel* UnityMenuModelStack::head() const
32{
92{
33− return !m_menuModels.isEmpty() ? m_menuModels.first() : NULL;
93+ return !m_menuModels.isEmpty() ? m_menuModels.first()->model() : NULL;
34}
94}
35
95
36void UnityMenuModelStack::setHead(UnityMenuModel* model)
96void UnityMenuModelStack::setHead(UnityMenuModel* model)
37{
97{
38 if (head() != model) {
98 if (head() != model) {
99+ qDeleteAll(m_menuModels);
39 m_menuModels.clear();
100 m_menuModels.clear();
101+
40− push(model);
102+ push(model, 0);
41 Q_EMIT headChanged(model);
103 Q_EMIT headChanged(model);
42 }
104 }
43}
105}
44
106
45UnityMenuModel* UnityMenuModelStack::tail() const
107UnityMenuModel* UnityMenuModelStack::tail() const
46{
108{
47− return !m_menuModels.isEmpty() ? m_menuModels.last() : NULL;
109+ return !m_menuModels.isEmpty() ? m_menuModels.last()->model() : NULL;
110+}
111+
112+int UnityMenuModelStack::count() const
113+{
114+ return m_menuModels.count();
48}
115}
49
116
50−void UnityMenuModelStack::push(UnityMenuModel* model)
117+void UnityMenuModelStack::push(UnityMenuModel* model, int index)
51{
118{
119+ UnityMenuModelEntry* entry = new UnityMenuModelEntry(model, tail(), index);
120+ QObject::connect(entry, SIGNAL(remove()), SLOT(onRemove()));
121+
52− m_menuModels << model;
122+ m_menuModels << entry;
53 Q_EMIT tailChanged(model);
123 Q_EMIT tailChanged(model);
124+ Q_EMIT countChanged(m_menuModels.count());
54}
125}
55
126
56UnityMenuModel* UnityMenuModelStack::pop()
127UnityMenuModel* UnityMenuModelStack::pop()
@@ -58,12 +129,32 @@ UnityMenuModel* UnityMenuModelStack::pop()
58 if (m_menuModels.isEmpty()) {
129 if (m_menuModels.isEmpty()) {
59 return NULL;
130 return NULL;
60 }
131 }
61− UnityMenuModel* model = m_menuModels.takeLast();
132+ UnityMenuModelEntry* entry = m_menuModels.takeLast();
133+ UnityMenuModel* model = entry->model();
134+ entry->deleteLater();
62
135
63 Q_EMIT tailChanged(tail());
136 Q_EMIT tailChanged(tail());
64 if (m_menuModels.isEmpty()) {
137 if (m_menuModels.isEmpty()) {
65 Q_EMIT headChanged(NULL);
138 Q_EMIT headChanged(NULL);
66 }
139 }
140+ Q_EMIT countChanged(m_menuModels.count());
67
141
68 return model;
142 return model;
69−}
143+}
144+
145+void UnityMenuModelStack::onRemove()
146+{
147+ UnityMenuModelEntry* removed = qobject_cast<UnityMenuModelEntry*>(sender());
148+ if (!m_menuModels.contains(removed))
149+ return;
150+
151+ for (int i = m_menuModels.count() -1; i >= 0; i--) {
152+ UnityMenuModelEntry* entry = m_menuModels[i];
153+ pop();
154+ if (entry == removed) {
155+ break;
156+ }
157+ }
158+}
159+
160+#include "unitymenumodelstack.moc"
plugins/Unity/Indicators/unitymenumodelstack.h+10−2
@@ -25,6 +25,7 @@
25#include <QObject>
25#include <QObject>
26#include <QList>
26#include <QList>
27
27
28+class UnityMenuModelEntry;
28class UnityMenuModel;
29class UnityMenuModel;
29
30
30// A LIFO queue for storing the current submenu of a UnityMenuModel.
31// A LIFO queue for storing the current submenu of a UnityMenuModel.
@@ -37,6 +38,7 @@ class UNITYINDICATORS_EXPORT UnityMenuModelStack : public QObject
37 Q_OBJECT
38 Q_OBJECT
38 Q_PROPERTY(UnityMenuModel* head READ head WRITE setHead NOTIFY headChanged)
39 Q_PROPERTY(UnityMenuModel* head READ head WRITE setHead NOTIFY headChanged)
39 Q_PROPERTY(UnityMenuModel* tail READ tail NOTIFY tailChanged)
40 Q_PROPERTY(UnityMenuModel* tail READ tail NOTIFY tailChanged)
41+ Q_PROPERTY(int count READ count NOTIFY countChanged)
40public:
42public:
41 UnityMenuModelStack(QObject*parent=NULL);
43 UnityMenuModelStack(QObject*parent=NULL);
42 ~UnityMenuModelStack();
44 ~UnityMenuModelStack();
@@ -46,15 +48,21 @@ public:
46
48
47 UnityMenuModel* tail() const;
49 UnityMenuModel* tail() const;
48
50
51+ int count() const;
52+
49− Q_INVOKABLE void push(UnityMenuModel* model);
53+ Q_INVOKABLE void push(UnityMenuModel* model, int menuIndex);
50 Q_INVOKABLE UnityMenuModel* pop();
54 Q_INVOKABLE UnityMenuModel* pop();
51
55
52Q_SIGNALS:
56Q_SIGNALS:
53 void headChanged(UnityMenuModel* head);
57 void headChanged(UnityMenuModel* head);
54 void tailChanged(UnityMenuModel* tail);
58 void tailChanged(UnityMenuModel* tail);
59+ void countChanged(int count);
60+
61+private Q_SLOTS:
62+ void onRemove();
55
63
56private:
64private:
57− QList<UnityMenuModel*> m_menuModels;
65+ QList<UnityMenuModelEntry*> m_menuModels;
58};
66};
59
67
60#endif // UNITYMENUMODELSTACK_H
68#endif // UNITYMENUMODELSTACK_H
plugins/Unity/Launcher/launcheritem.cpp+4−2
@@ -20,6 +20,8 @@
20#include "launcheritem.h"
20#include "launcheritem.h"
21#include "quicklistmodel.h"
21#include "quicklistmodel.h"
22
22
23+#include <libintl.h>
24+
23LauncherItem::LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent) :
25LauncherItem::LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent) :
24 LauncherItemInterface(parent),
26 LauncherItemInterface(parent),
25 m_appId(appId),
27 m_appId(appId),
@@ -38,7 +40,7 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
38 m_quickList->appendAction(nameAction);
40 m_quickList->appendAction(nameAction);
39 QuickListEntry pinningAction;
41 QuickListEntry pinningAction;
40 pinningAction.setActionId("pin_item");
42 pinningAction.setActionId("pin_item");
41− pinningAction.setText("Pin to Launcher");
43+ pinningAction.setText(gettext("Lock to Launcher"));
42 m_quickList->appendAction(pinningAction);
44 m_quickList->appendAction(pinningAction);
43}
45}
44
46
@@ -68,7 +70,7 @@ void LauncherItem::setPinned(bool pinned)
68 m_pinned = pinned;
70 m_pinned = pinned;
69 QuickListEntry entry;
71 QuickListEntry entry;
70 entry.setActionId("pin_item");
72 entry.setActionId("pin_item");
71− entry.setText(pinned ? "Remove from Launcher": "Pin to Launcher");
73+ entry.setText(pinned ? gettext("Unlock from Launcher") : gettext("Lock to Launcher"));
72 m_quickList->updateAction(entry);
74 m_quickList->updateAction(entry);
73 Q_EMIT pinnedChanged(pinned);
75 Q_EMIT pinnedChanged(pinned);
74 }
76 }
plugins/Unity/plugin.cpp−12
@@ -17,8 +17,6 @@
17 */
17 */
18
18
19// Qt
19// Qt
20−#include <QDBusConnection>
21−#include <QQmlContext>
22#include <qqml.h>
20#include <qqml.h>
23
21
24// self
22// self
@@ -33,16 +31,12 @@
33#include "scopes.h"
31#include "scopes.h"
34#include "categories.h"
32#include "categories.h"
35#include "categoryresults.h"
33#include "categoryresults.h"
36−#include "bottombarvisibilitycommunicatorshell.h"
37#include "genericoptionsmodel.h"
34#include "genericoptionsmodel.h"
38#include "result.h"
35#include "result.h"
39
36
40// libqtdee
37// libqtdee
41#include "deelistmodel.h"
38#include "deelistmodel.h"
42
39
43−static const char* BOTTOM_BAR_VISIBILITY_COMMUNICATOR_DBUS_PATH = "/BottomBarVisibilityCommunicator";
44−static const char* DBUS_SERVICE = "com.canonical.Shell.BottomBarVisibilityCommunicator";
45−
46void UnityPlugin::registerTypes(const char *uri)
40void UnityPlugin::registerTypes(const char *uri)
47{
41{
48 Q_ASSERT(uri == QLatin1String("Unity"));
42 Q_ASSERT(uri == QLatin1String("Unity"));
@@ -57,7 +51,6 @@ void UnityPlugin::registerTypes(const char *uri)
57 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
51 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
58 qmlRegisterUncreatableType<CategoryResults>(uri, 0, 1, "CategoryResults", "Can't create new Category Results in QML. Get them from Categories instance.");
52 qmlRegisterUncreatableType<CategoryResults>(uri, 0, 1, "CategoryResults", "Can't create new Category Results in QML. Get them from Categories instance.");
59 qmlRegisterType<DeeListModel>(uri, 0, 1, "DeeListModel");
53 qmlRegisterType<DeeListModel>(uri, 0, 1, "DeeListModel");
60− qmlRegisterUncreatableType<BottomBarVisibilityCommunicatorShell>(uri, 0, 1, "BottomBarVisibilityCommunicatorShell", "Can't create BottomBarVisibilityCommunicatorShell");
61}
54}
62
55
63void UnityPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
56void UnityPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
@@ -66,9 +59,4 @@ void UnityPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
66#ifndef GLIB_VERSION_2_36
59#ifndef GLIB_VERSION_2_36
67 g_type_init();
60 g_type_init();
68#endif
61#endif
69−
70− QDBusConnection::sessionBus().registerService(DBUS_SERVICE);
71− BottomBarVisibilityCommunicatorShell *bottomBarVisibilityCommunicator = &BottomBarVisibilityCommunicatorShell::instance();
72− QDBusConnection::sessionBus().registerObject(BOTTOM_BAR_VISIBILITY_COMMUNICATOR_DBUS_PATH, bottomBarVisibilityCommunicator, QDBusConnection::ExportAllContents);
73− engine->rootContext()->setContextProperty("bottomBarVisibilityCommunicatorShell", bottomBarVisibilityCommunicator);
74}
62}
plugins/Utils/CMakeLists.txt+1
@@ -13,6 +13,7 @@ include_directories(
13set(QMLPLUGIN_SRC
13set(QMLPLUGIN_SRC
14 albumartprovider.cpp
14 albumartprovider.cpp
15 applicationpaths.h
15 applicationpaths.h
16+ bottombarvisibilitycommunicatorshell.cpp
16 mediaartcache.cpp
17 mediaartcache.cpp
17 qlimitproxymodelqml.cpp
18 qlimitproxymodelqml.cpp
18 qsortfilterproxymodelqml.cpp
19 qsortfilterproxymodelqml.cpp
plugins/Unity/bottombarvisibilitycommunicatorshell.cpp → plugins/Utils/bottombarvisibilitycommunicatorshell.cpprenamed

The content is the same.

plugins/Unity/bottombarvisibilitycommunicatorshell.h → plugins/Utils/bottombarvisibilitycommunicatorshell.hrenamed

The content is the same.

plugins/Utils/plugin.cpp+12
@@ -18,6 +18,8 @@
18
18
19// Qt
19// Qt
20#include <QtQml/qqml.h>
20#include <QtQml/qqml.h>
21+#include <QDBusConnection>
22+#include <QQmlContext>
21#include <QtQuick/QQuickWindow>
23#include <QtQuick/QQuickWindow>
22#include <QDebug>
24#include <QDebug>
23// self
25// self
@@ -26,11 +28,15 @@
26// local
28// local
27#include "albumartprovider.h"
29#include "albumartprovider.h"
28#include "applicationpaths.h"
30#include "applicationpaths.h"
31+#include "bottombarvisibilitycommunicatorshell.h"
29#include "qlimitproxymodelqml.h"
32#include "qlimitproxymodelqml.h"
30#include "qsortfilterproxymodelqml.h"
33#include "qsortfilterproxymodelqml.h"
31#include "ubuntuwindow.h"
34#include "ubuntuwindow.h"
32#include "unitymenumodelpaths.h"
35#include "unitymenumodelpaths.h"
33
36
37+static const char* BOTTOM_BAR_VISIBILITY_COMMUNICATOR_DBUS_PATH = "/BottomBarVisibilityCommunicator";
38+static const char* DBUS_SERVICE = "com.canonical.Shell.BottomBarVisibilityCommunicator";
39+
34static QObject* applicationsPathsSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
40static QObject* applicationsPathsSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
35 Q_UNUSED(engine);
41 Q_UNUSED(engine);
36 Q_UNUSED(scriptEngine);
42 Q_UNUSED(scriptEngine);
@@ -46,6 +52,7 @@ void UtilsPlugin::registerTypes(const char *uri)
46 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
52 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
47 qmlRegisterExtendedType<QQuickWindow, UbuntuWindow>(uri, 0, 1, "Window");
53 qmlRegisterExtendedType<QQuickWindow, UbuntuWindow>(uri, 0, 1, "Window");
48 qmlRegisterSingletonType<ApplicationPaths>(uri, 0, 1, "ApplicationPaths", applicationsPathsSingleton);
54 qmlRegisterSingletonType<ApplicationPaths>(uri, 0, 1, "ApplicationPaths", applicationsPathsSingleton);
55+ qmlRegisterUncreatableType<BottomBarVisibilityCommunicatorShell>(uri, 0, 1, "BottomBarVisibilityCommunicatorShell", "Can't create BottomBarVisibilityCommunicatorShell");
49}
56}
50
57
51void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
58void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
@@ -64,4 +71,9 @@ void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
64 {
71 {
65 qWarning() << "Failed to register image provider for albumart (unknown error)";
72 qWarning() << "Failed to register image provider for albumart (unknown error)";
66 }
73 }
74+
75+ QDBusConnection::sessionBus().registerService(DBUS_SERVICE);
76+ BottomBarVisibilityCommunicatorShell *bottomBarVisibilityCommunicator = &BottomBarVisibilityCommunicatorShell::instance();
77+ QDBusConnection::sessionBus().registerObject(BOTTOM_BAR_VISIBILITY_COMMUNICATOR_DBUS_PATH, bottomBarVisibilityCommunicator, QDBusConnection::ExportAllContents);
78+ engine->rootContext()->setContextProperty("bottomBarVisibilityCommunicatorShell", bottomBarVisibilityCommunicator);
67}
79}
po/ar.po+9−5
@@ -7,8 +7,8 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11−"PO-Revision-Date: 2013-10-20 19:41+0000\n"
11+"PO-Revision-Date: 2013-11-15 12:29+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,8 +16,8 @@ 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: 2013-10-21 05:04+0000\n"
19+"X-Launchpad-Export-Date: 2013-11-16 06:27+0000\n"
20−"X-Generator: Launchpad (build 16807)\n"
20+"X-Generator: Launchpad (build 16831)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -213,11 +213,15 @@ msgstr "تكلم الآن..."
213msgid "Speaking..."
213msgid "Speaking..."
214msgstr "تتكلم الآن..."
214msgstr "تتكلم الآن..."
215
215
216+#: Notifications/NotificationMenuItemFactory.qml:89
217+msgid "Show password"
218+msgstr "عرض كلمة السر"
219+
216#: Panel/SearchIndicator.qml:27
220#: Panel/SearchIndicator.qml:27
217msgid "Search"
221msgid "Search"
218msgstr "ابحث"
222msgstr "ابحث"
219
223
220−#: plugins/Unity/scope.cpp:398
224+#: plugins/Unity/scope.cpp:408
221msgid "Sorry, there is nothing that matches your search."
225msgid "Sorry, there is nothing that matches your search."
222msgstr "عذراً، لا يوجد ما يطابق بحثك."
226msgstr "عذراً، لا يوجد ما يطابق بحثك."
223
227
po/ast.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-03 14:02+0000\n"
11"PO-Revision-Date: 2013-10-03 14:02+0000\n"
12"Last-Translator: ivarela <ivarela@ubuntu.com>\n"
12"Last-Translator: ivarela <ivarela@ubuntu.com>\n"
13"Language-Team: Asturian <ast@li.org>\n"
13"Language-Team: Asturian <ast@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -209,11 +209,15 @@ msgstr "Fala agora…"
209msgid "Speaking..."
209msgid "Speaking..."
210msgstr "Falando…"
210msgstr "Falando…"
211
211
212+#: Notifications/NotificationMenuItemFactory.qml:89
213+msgid "Show password"
214+msgstr ""
215+
212#: Panel/SearchIndicator.qml:27
216#: Panel/SearchIndicator.qml:27
213msgid "Search"
217msgid "Search"
214msgstr "Guetar"
218msgstr "Guetar"
215
219
216−#: plugins/Unity/scope.cpp:398
220+#: plugins/Unity/scope.cpp:408
217msgid "Sorry, there is nothing that matches your search."
221msgid "Sorry, there is nothing that matches your search."
218msgstr "Sentímoslo, nun hai res que concase cola gueta"
222msgstr "Sentímoslo, nun hai res que concase cola gueta"
219
223
@@ -225,24 +229,3 @@ msgstr "Too"
225#, qt-format
229#, qt-format
226msgid "Please enter %1"
230msgid "Please enter %1"
227msgstr "Introduz %1"
231msgstr "Introduz %1"
228−
229−#~ msgid "New Releases"
230−#~ msgstr "Llanzamientos nuevos"
231−
232−#~ msgid "Featured"
233−#~ msgstr "Destacaos"
234−
235−#~ msgid "Top Charting"
236−#~ msgstr "Meyor posicionaes"
237−
238−#~ msgid "Recent"
239−#~ msgstr "Recientes"
240−
241−#~ msgid "Videos"
242−#~ msgstr "Vídeos"
243−
244−#~ msgid "Music"
245−#~ msgstr "Música"
246−
247−#~ msgid "Popular Online"
248−#~ msgstr "Populares en llinia"
po/az.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-26 23:48+0000\n"
11"PO-Revision-Date: 2013-06-26 23:48+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: Azerbaijani <az@li.org>\n"
13"Language-Team: Azerbaijani <az@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "Söyləyin..."
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "Söylənilir..."
206msgstr "Söylənilir..."
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "Axtar"
214msgstr "Axtar"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "Bağışlayın, amma axtarışınıza heç bir nəticə uyğun gəlmir."
218msgstr "Bağışlayın, amma axtarışınıza heç bir nəticə uyğun gəlmir."
215
219
@@ -221,9 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "Musiqi"
227−
228−#~ msgid "Videos"
229−#~ msgstr "Videolar"
po/bg.po+8−16
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 00:06+0000\n"
11"PO-Revision-Date: 2013-06-27 00:06+0000\n"
12"Last-Translator: Miroslav E. Hadzhiev (Хаджиев) "
12"Last-Translator: Miroslav E. Hadzhiev (Хаджиев) "
13"<miroslav.hadzhiev@gmail.com>\n"
13"<miroslav.hadzhiev@gmail.com>\n"
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Type: text/plain; charset=UTF-8\n"
17"Content-Transfer-Encoding: 8bit\n"
17"Content-Transfer-Encoding: 8bit\n"
18"Plural-Forms: nplurals=2; plural=n != 1;\n"
18"Plural-Forms: nplurals=2; plural=n != 1;\n"
19−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
20−"X-Generator: Launchpad (build 16799)\n"
20+"X-Generator: Launchpad (build 16820)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -206,11 +206,15 @@ msgstr ""
206msgid "Speaking..."
206msgid "Speaking..."
207msgstr ""
207msgstr ""
208
208
209+#: Notifications/NotificationMenuItemFactory.qml:89
210+msgid "Show password"
211+msgstr ""
212+
209#: Panel/SearchIndicator.qml:27
213#: Panel/SearchIndicator.qml:27
210msgid "Search"
214msgid "Search"
211msgstr "Търсене"
215msgstr "Търсене"
212
216
213−#: plugins/Unity/scope.cpp:398
217+#: plugins/Unity/scope.cpp:408
214msgid "Sorry, there is nothing that matches your search."
218msgid "Sorry, there is nothing that matches your search."
215msgstr "Съжаляваме, няма нищо, което да отговаря на вашето търсене."
219msgstr "Съжаляваме, няма нищо, което да отговаря на вашето търсене."
216
220
@@ -222,15 +226,3 @@ msgstr ""
222#, qt-format
226#, qt-format
223msgid "Please enter %1"
227msgid "Please enter %1"
224msgstr ""
228msgstr ""
225−
226−#~ msgid "Featured"
227−#~ msgstr "Най-отличени"
228−
229−#~ msgid "Recent"
230−#~ msgstr "Най-нови"
231−
232−#~ msgid "Music"
233−#~ msgstr "Музика"
234−
235−#~ msgid "Videos"
236−#~ msgstr "Видеоклипове"
po/ca.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-09-28 07:38+0000\n"
11"PO-Revision-Date: 2013-09-28 07:38+0000\n"
12"Last-Translator: David Planella <david.planella@ubuntu.com>\n"
12"Last-Translator: David Planella <david.planella@ubuntu.com>\n"
13"Language-Team: Catalan <ca@li.org>\n"
13"Language-Team: Catalan <ca@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -211,11 +211,15 @@ msgstr "Parleu..."
211msgid "Speaking..."
211msgid "Speaking..."
212msgstr "S'està parlant..."
212msgstr "S'està parlant..."
213
213
214+#: Notifications/NotificationMenuItemFactory.qml:89
215+msgid "Show password"
216+msgstr ""
217+
214#: Panel/SearchIndicator.qml:27
218#: Panel/SearchIndicator.qml:27
215msgid "Search"
219msgid "Search"
216msgstr "Cerca"
220msgstr "Cerca"
217
221
218−#: plugins/Unity/scope.cpp:398
222+#: plugins/Unity/scope.cpp:408
219msgid "Sorry, there is nothing that matches your search."
223msgid "Sorry, there is nothing that matches your search."
220msgstr "No hi ha res que coincideixi amb la cerca"
224msgstr "No hi ha res que coincideixi amb la cerca"
221
225
@@ -227,24 +231,3 @@ msgstr ""
227#, qt-format
231#, qt-format
228msgid "Please enter %1"
232msgid "Please enter %1"
229msgstr "Introduïu %1"
233msgstr "Introduïu %1"
230−
231−#~ msgid "Music"
232−#~ msgstr "Música"
233−
234−#~ msgid "Videos"
235−#~ msgstr "Vídeos"
236−
237−#~ msgid "Recent"
238−#~ msgstr "Recents"
239−
240−#~ msgid "Featured"
241−#~ msgstr "Destacats"
242−
243−#~ msgid "New Releases"
244−#~ msgstr "Novetats"
245−
246−#~ msgid "Top Charting"
247−#~ msgstr "El millor de les llistes"
248−
249−#~ msgid "Popular Online"
250−#~ msgstr "Popular a la xarxa"
po/cs.po+8−19
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-08 08:09+0000\n"
11"PO-Revision-Date: 2013-10-08 08:09+0000\n"
12"Last-Translator: Tadeáš Pařík <tadeas.parik@gmail.com>\n"
12"Last-Translator: Tadeáš Pařík <tadeas.parik@gmail.com>\n"
13"Language-Team: Czech <cs@li.org>\n"
13"Language-Team: Czech <cs@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
17"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -206,11 +206,15 @@ msgstr "Mluvte..."
206msgid "Speaking..."
206msgid "Speaking..."
207msgstr "Mluvte..."
207msgstr "Mluvte..."
208
208
209+#: Notifications/NotificationMenuItemFactory.qml:89
210+msgid "Show password"
211+msgstr ""
212+
209#: Panel/SearchIndicator.qml:27
213#: Panel/SearchIndicator.qml:27
210msgid "Search"
214msgid "Search"
211msgstr "Hledat"
215msgstr "Hledat"
212
216
213−#: plugins/Unity/scope.cpp:398
217+#: plugins/Unity/scope.cpp:408
214msgid "Sorry, there is nothing that matches your search."
218msgid "Sorry, there is nothing that matches your search."
215msgstr "Je nám líto, ale nic neodpovídá zadání"
219msgstr "Je nám líto, ale nic neodpovídá zadání"
216
220
@@ -222,18 +226,3 @@ msgstr "Vše"
222#, qt-format
226#, qt-format
223msgid "Please enter %1"
227msgid "Please enter %1"
224msgstr "Zadejte prosím %1"
228msgstr "Zadejte prosím %1"
225−
226−#~ msgid "Featured"
227−#~ msgstr "Oblíbené"
228−
229−#~ msgid "Recent"
230−#~ msgstr "Nedávné"
231−
232−#~ msgid "Videos"
233−#~ msgstr "Videa"
234−
235−#~ msgid "Music"
236−#~ msgstr "Hudba"
237−
238−#~ msgid "Popular Online"
239−#~ msgstr "Oblíbené on-line"
po/de.po+8−4
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-18 12:26+0000\n"
11"PO-Revision-Date: 2013-10-18 12:26+0000\n"
12"Last-Translator: Phillip Sz <Unknown>\n"
12"Last-Translator: Phillip Sz <Unknown>\n"
13"Language-Team: German <de@li.org>\n"
13"Language-Team: German <de@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-19 05:30+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16807)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -209,11 +209,15 @@ msgstr "Sprechen Sie jetzt …"
209msgid "Speaking..."
209msgid "Speaking..."
210msgstr "Sie sprechen …"
210msgstr "Sie sprechen …"
211
211
212+#: Notifications/NotificationMenuItemFactory.qml:89
213+msgid "Show password"
214+msgstr ""
215+
212#: Panel/SearchIndicator.qml:27
216#: Panel/SearchIndicator.qml:27
213msgid "Search"
217msgid "Search"
214msgstr "Suchen"
218msgstr "Suchen"
215
219
216−#: plugins/Unity/scope.cpp:398
220+#: plugins/Unity/scope.cpp:408
217msgid "Sorry, there is nothing that matches your search."
221msgid "Sorry, there is nothing that matches your search."
218msgstr "Entschuldigung, es wurden keine Treffer erzielt."
222msgstr "Entschuldigung, es wurden keine Treffer erzielt."
219
223
po/el.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 00:53+0000\n"
11"PO-Revision-Date: 2013-06-27 00:53+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: Greek <el@li.org>\n"
13"Language-Team: Greek <el@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "Μιλήστε τώρα..."
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "Ομιλία..."
206msgstr "Ομιλία..."
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "Αναζήτηση"
214msgstr "Αναζήτηση"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "Λυπούμαστε, δεν υπάρχει τίποτα που να ταιριάζει στην αναζήτησή σας."
218msgstr "Λυπούμαστε, δεν υπάρχει τίποτα που να ταιριάζει στην αναζήτησή σας."
215
219
@@ -221,9 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "Μουσική"
227−
228−#~ msgid "Videos"
229−#~ msgstr "Βίντεο"
po/en_AU.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-09-28 07:46+0000\n"
11"PO-Revision-Date: 2013-09-28 07:46+0000\n"
12"Last-Translator: Jared Norris <jarednorris@ubuntu.com>\n"
12"Last-Translator: Jared Norris <jarednorris@ubuntu.com>\n"
13"Language-Team: English (Australia) <en_AU@li.org>\n"
13"Language-Team: English (Australia) <en_AU@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "Speak Now..."
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "Speaking..."
206msgstr "Speaking..."
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "Search"
214msgstr "Search"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "Sorry, there is nothing that matches your search."
218msgstr "Sorry, there is nothing that matches your search."
215
219
@@ -221,24 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr "Please enter %1"
227msgstr "Please enter %1"
224−
225−#~ msgid "Featured"
226−#~ msgstr "Featured"
227−
228−#~ msgid "Recent"
229−#~ msgstr "Recent"
230−
231−#~ msgid "New Releases"
232−#~ msgstr "New Releases"
233−
234−#~ msgid "Top Charting"
235−#~ msgstr "Top Charting"
236−
237−#~ msgid "Music"
238−#~ msgstr "Music"
239−
240−#~ msgid "Popular Online"
241−#~ msgstr "Popular Online"
242−
243−#~ msgid "Videos"
244−#~ msgstr "Videos"
po/en_GB.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 08:53+0000\n"
11"PO-Revision-Date: 2013-06-27 08:53+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: English (United Kingdom) <en_GB@li.org>\n"
13"Language-Team: English (United Kingdom) <en_GB@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "Speak Now..."
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "Speaking..."
206msgstr "Speaking..."
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "Search"
214msgstr "Search"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "Sorry, there is nothing that matches your search."
218msgstr "Sorry, there is nothing that matches your search."
215
219
@@ -221,24 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr "Please enter %1"
227msgstr "Please enter %1"
224−
225−#~ msgid "Featured"
226−#~ msgstr "Featured"
227−
228−#~ msgid "Recent"
229−#~ msgstr "Recent"
230−
231−#~ msgid "New Releases"
232−#~ msgstr "New Releases"
233−
234−#~ msgid "Top Charting"
235−#~ msgstr "Top Charting"
236−
237−#~ msgid "Music"
238−#~ msgstr "Music"
239−
240−#~ msgid "Popular Online"
241−#~ msgstr "Popular Online"
242−
243−#~ msgid "Videos"
244−#~ msgstr "Videos"
po/eo.po+8−4
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-26 22:35+0000\n"
11"PO-Revision-Date: 2013-06-26 22:35+0000\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Language-Team: Esperanto <eo@li.org>\n"
13"Language-Team: Esperanto <eo@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr ""
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr ""
206msgstr ""
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr ""
214msgstr ""
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr ""
218msgstr ""
215
219
po/es.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-02 04:59+0000\n"
11"PO-Revision-Date: 2013-10-02 04:59+0000\n"
12"Last-Translator: Adolfo Jayme Barrientos <fitoschido@gmail.com>\n"
12"Last-Translator: Adolfo Jayme Barrientos <fitoschido@gmail.com>\n"
13"Language-Team: Spanish <es@li.org>\n"
13"Language-Team: Spanish <es@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -209,11 +209,15 @@ msgstr "Hable ahora…"
209msgid "Speaking..."
209msgid "Speaking..."
210msgstr "Hablando…"
210msgstr "Hablando…"
211
211
212+#: Notifications/NotificationMenuItemFactory.qml:89
213+msgid "Show password"
214+msgstr ""
215+
212#: Panel/SearchIndicator.qml:27
216#: Panel/SearchIndicator.qml:27
213msgid "Search"
217msgid "Search"
214msgstr "Buscar"
218msgstr "Buscar"
215
219
216−#: plugins/Unity/scope.cpp:398
220+#: plugins/Unity/scope.cpp:408
217msgid "Sorry, there is nothing that matches your search."
221msgid "Sorry, there is nothing that matches your search."
218msgstr "No hay nada que coincida con su búsqueda."
222msgstr "No hay nada que coincida con su búsqueda."
219
223
@@ -225,24 +229,3 @@ msgstr "Todo"
225#, qt-format
229#, qt-format
226msgid "Please enter %1"
230msgid "Please enter %1"
227msgstr "Introduzca %1"
231msgstr "Introduzca %1"
228−
229−#~ msgid "Featured"
230−#~ msgstr "Destacados"
231−
232−#~ msgid "Recent"
233−#~ msgstr "Recientes"
234−
235−#~ msgid "New Releases"
236−#~ msgstr "Lanzamientos nuevos"
237−
238−#~ msgid "Top Charting"
239−#~ msgstr "Mejor posicionadas"
240−
241−#~ msgid "Music"
242−#~ msgstr "Música"
243−
244−#~ msgid "Popular Online"
245−#~ msgstr "Populares en línea"
246−
247−#~ msgid "Videos"
248−#~ msgstr "Vídeos"
po/fa.ponew file+227
@@ -0,0 +1,227 @@
1+# Persian translation for unity8
2+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
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: 2013-11-05 17:53+0100\n"
11+"PO-Revision-Date: 2013-10-31 19:02+0000\n"
12+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13+"Language-Team: Persian <fa@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=1; plural=0;\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19+"X-Generator: Launchpad (build 16820)\n"
20+
21+#: Applications/applications.js:23
22+msgid "Phone"
23+msgstr ""
24+
25+#: Applications/applications.js:29
26+msgid "Camera"
27+msgstr ""
28+
29+#: Applications/applications.js:35
30+msgid "Gallery"
31+msgstr ""
32+
33+#: Applications/applications.js:40
34+msgid "Facebook"
35+msgstr ""
36+
37+#: Applications/applications.js:46
38+msgid "Browser"
39+msgstr ""
40+
41+#: Applications/applications.js:51
42+msgid "Twitter"
43+msgstr ""
44+
45+#: Applications/applications.js:57
46+msgid "GMail"
47+msgstr ""
48+
49+#: Applications/applications.js:62
50+msgid "Weather"
51+msgstr ""
52+
53+#: Applications/applications.js:68
54+msgid "Notepad"
55+msgstr ""
56+
57+#: Applications/applications.js:74
58+msgid "Calendar"
59+msgstr ""
60+
61+#: Applications/applications.js:80
62+msgid "Media Player"
63+msgstr ""
64+
65+#: Applications/applications.js:86
66+msgid "Evernote"
67+msgstr ""
68+
69+#: Applications/applications.js:91
70+msgid "Map"
71+msgstr ""
72+
73+#: Applications/applications.js:96
74+msgid "Pinterest"
75+msgstr ""
76+
77+#: Applications/applications.js:101
78+msgid "SoundCloud"
79+msgstr ""
80+
81+#: Applications/applications.js:106
82+msgid "Wikipedia"
83+msgstr ""
84+
85+#: Applications/applications.js:111
86+msgid "YouTube"
87+msgstr ""
88+
89+#: Components/EdgeDemoOverlay.qml:149
90+msgid "Skip intro"
91+msgstr ""
92+
93+#: Components/EdgeDemo.qml:112
94+msgid "Right edge"
95+msgstr ""
96+
97+#: Components/EdgeDemo.qml:113
98+msgid "Try swiping from the right edge to unlock the phone"
99+msgstr ""
100+
101+#: Components/EdgeDemo.qml:144
102+msgid "Top edge"
103+msgstr ""
104+
105+#: Components/EdgeDemo.qml:145
106+msgid "Try swiping from the top edge to access the indicators"
107+msgstr ""
108+
109+#: Components/EdgeDemo.qml:170
110+msgid "Close"
111+msgstr ""
112+
113+#: Components/EdgeDemo.qml:171
114+msgid "Swipe up again to close the settings screen"
115+msgstr ""
116+
117+#: Components/EdgeDemo.qml:198
118+msgid "Left edge"
119+msgstr ""
120+
121+#: Components/EdgeDemo.qml:199
122+msgid "Swipe from the left to reveal the launcher for quick access to apps"
123+msgstr ""
124+
125+#: Components/EdgeDemo.qml:226
126+msgid "Well done"
127+msgstr ""
128+
129+#: Components/EdgeDemo.qml:227
130+msgid ""
131+"You have now mastered the edge gestures and can start using the "
132+"phone<br><br>Tap anywhere to start"
133+msgstr ""
134+
135+#: Components/PageHeader.qml:341
136+msgid "Recent searches"
137+msgstr ""
138+
139+#. TRANSLATORS: Number of persons who rated this app
140+#. TRANSLATORS: Number of persons who rated this app/video/whatever
141+#: Dash/Apps/AppInfo.qml:73 Dash/Previews/Header.qml:93
142+#, qt-format
143+msgid "(%1)"
144+msgstr ""
145+
146+#. TRANSLATORS: Number of persons who wrote reviews for this app
147+#. TRANSLATORS: Number of persons who wrote reviews for this app/video/whatever
148+#: Dash/Apps/AppInfo.qml:85 Dash/Previews/Header.qml:105
149+#, qt-format
150+msgid "%1 review"
151+msgid_plural "%1 reviews"
152+msgstr[0] ""
153+msgstr[1] ""
154+
155+#: Dash/Apps/AppPreview.qml:126
156+msgid "Rate this"
157+msgstr ""
158+
159+#: Dash/Previews/Reviews.qml:74
160+msgid "Add a review"
161+msgstr ""
162+
163+#: Dash/Previews/Reviews.qml:86
164+msgid "Review"
165+msgstr ""
166+
167+#: Dash/Previews/Reviews.qml:121
168+msgid "Send"
169+msgstr ""
170+
171+#: Dash/Previews/Reviews.qml:139
172+msgid "Comments:"
173+msgstr ""
174+
175+#: Greeter/Lockscreen.qml:142
176+msgid "Emergency Call"
177+msgstr ""
178+
179+#: Greeter/PassphraseLockscreen.qml:59
180+#, qt-format
181+msgid "Hello %1"
182+msgstr ""
183+
184+#: Greeter/PassphraseLockscreen.qml:59
185+msgid "Hello"
186+msgstr ""
187+
188+#: Hud/HudParametrizedActionsPage.qml:132
189+msgid "Confirm"
190+msgstr ""
191+
192+#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
193+msgid "Type or say a command"
194+msgstr ""
195+
196+#: Hud/Hud.qml:84
197+msgid "Loading. Please Wait..."
198+msgstr ""
199+
200+#: Hud/Hud.qml:89
201+msgid "Speak Now..."
202+msgstr ""
203+
204+#: Hud/Hud.qml:94
205+msgid "Speaking..."
206+msgstr ""
207+
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
212+#: Panel/SearchIndicator.qml:27
213+msgid "Search"
214+msgstr ""
215+
216+#: plugins/Unity/scope.cpp:408
217+msgid "Sorry, there is nothing that matches your search."
218+msgstr ""
219+
220+#: plugins/Unity/showallfilteroption.cpp:41
221+msgid "All"
222+msgstr ""
223+
224+#: Shell.qml:438
225+#, qt-format
226+msgid "Please enter %1"
227+msgstr ""
po/fi.po+9−26
@@ -7,16 +7,16 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11−"PO-Revision-Date: 2013-10-03 09:21+0000\n"
11+"PO-Revision-Date: 2013-11-11 14:07+0000\n"
12"Last-Translator: Jiri Grönroos <Unknown>\n"
12"Last-Translator: Jiri Grönroos <Unknown>\n"
13"Language-Team: Finnish <fi@li.org>\n"
13"Language-Team: Finnish <fi@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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-12 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -207,11 +207,15 @@ msgstr "Puhu nyt..."
207msgid "Speaking..."
207msgid "Speaking..."
208msgstr "Puhutaan..."
208msgstr "Puhutaan..."
209
209
210+#: Notifications/NotificationMenuItemFactory.qml:89
211+msgid "Show password"
212+msgstr "Näytä salasana"
213+
210#: Panel/SearchIndicator.qml:27
214#: Panel/SearchIndicator.qml:27
211msgid "Search"
215msgid "Search"
212msgstr "Hae"
216msgstr "Hae"
213
217
214−#: plugins/Unity/scope.cpp:398
218+#: plugins/Unity/scope.cpp:408
215msgid "Sorry, there is nothing that matches your search."
219msgid "Sorry, there is nothing that matches your search."
216msgstr "Hakuun täsmääviä tuloksia ei löydy."
220msgstr "Hakuun täsmääviä tuloksia ei löydy."
217
221
@@ -223,24 +227,3 @@ msgstr "Kaikki"
223#, qt-format
227#, qt-format
224msgid "Please enter %1"
228msgid "Please enter %1"
225msgstr "Kirjoita %1"
229msgstr "Kirjoita %1"
226−
227−#~ msgid "Featured"
228−#~ msgstr "Suositellut"
229−
230−#~ msgid "Recent"
231−#~ msgstr "Viimeisimmät"
232−
233−#~ msgid "New Releases"
234−#~ msgstr "Uudet julkaisut"
235−
236−#~ msgid "Top Charting"
237−#~ msgstr "Nousukiidossa"
238−
239−#~ msgid "Music"
240−#~ msgstr "Musiikki"
241−
242−#~ msgid "Popular Online"
243−#~ msgstr "Suosittua verkossa"
244−
245−#~ msgid "Videos"
246−#~ msgstr "Videot"
po/fo.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-01 15:13+0000\n"
11"PO-Revision-Date: 2013-10-01 15:13+0000\n"
12"Last-Translator: Jógvan Olsen <jeggy@jebster.net>\n"
12"Last-Translator: Jógvan Olsen <jeggy@jebster.net>\n"
13"Language-Team: Faroese <fo@li.org>\n"
13"Language-Team: Faroese <fo@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "Snakka nú..."
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "Snakkar..."
206msgstr "Snakkar..."
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "Leita"
214msgstr "Leita"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "Tíanverri er tað einki sum hóskar til tína leiting."
218msgstr "Tíanverri er tað einki sum hóskar til tína leiting."
215
219
@@ -221,9 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "Tónleikur"
227−
228−#~ msgid "Videos"
229−#~ msgstr "Sjónbond"
po/fr.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 03:21+0000\n"
11"PO-Revision-Date: 2013-06-27 03:21+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: French <fr@li.org>\n"
13"Language-Team: French <fr@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr ""
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr ""
206msgstr ""
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr ""
214msgstr ""
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr ""
218msgstr ""
215
219
@@ -221,9 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "Musique"
227−
228−#~ msgid "Videos"
229−#~ msgstr "Vidéos"
po/gd.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-09-30 10:34+0000\n"
11"PO-Revision-Date: 2013-09-30 10:34+0000\n"
12"Last-Translator: Akerbeltz <fios@akerbeltz.org>\n"
12"Last-Translator: Akerbeltz <fios@akerbeltz.org>\n"
13"Language-Team: Gaelic; Scottish <gd@li.org>\n"
13"Language-Team: Gaelic; Scottish <gd@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=4; plural=(n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : "
17"Plural-Forms: nplurals=4; plural=(n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : "
18"(n > 2 && n < 20) ? 2 : 3;\n"
18"(n > 2 && n < 20) ? 2 : 3;\n"
19−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
20−"X-Generator: Launchpad (build 16799)\n"
20+"X-Generator: Launchpad (build 16820)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -214,11 +214,15 @@ msgstr "Can rud a-nis..."
214msgid "Speaking..."
214msgid "Speaking..."
215msgstr "A' bruidhinn..."
215msgstr "A' bruidhinn..."
216
216
217+#: Notifications/NotificationMenuItemFactory.qml:89
218+msgid "Show password"
219+msgstr ""
220+
217#: Panel/SearchIndicator.qml:27
221#: Panel/SearchIndicator.qml:27
218msgid "Search"
222msgid "Search"
219msgstr "Lorg"
223msgstr "Lorg"
220
224
221−#: plugins/Unity/scope.cpp:398
225+#: plugins/Unity/scope.cpp:408
222msgid "Sorry, there is nothing that matches your search."
226msgid "Sorry, there is nothing that matches your search."
223msgstr "Tha sinn duilich ach chan eil dad a' freagairt ris na lorg thu."
227msgstr "Tha sinn duilich ach chan eil dad a' freagairt ris na lorg thu."
224
228
@@ -230,24 +234,3 @@ msgstr ""
230#, qt-format
234#, qt-format
231msgid "Please enter %1"
235msgid "Please enter %1"
232msgstr "Cuir a-steach %1"
236msgstr "Cuir a-steach %1"
233−
234−#~ msgid "Top Charting"
235−#~ msgstr "Gràinnean-mullaich nan cairt"
236−
237−#~ msgid "Featured"
238−#~ msgstr "Brosnaichte"
239−
240−#~ msgid "Recent"
241−#~ msgstr "O chionn goirid"
242−
243−#~ msgid "New Releases"
244−#~ msgstr "Air ùr-sgaoileadh"
245−
246−#~ msgid "Videos"
247−#~ msgstr "Videothan"
248−
249−#~ msgid "Music"
250−#~ msgstr "Ceòl"
251−
252−#~ msgid "Popular Online"
253−#~ msgstr "Fèill mhòr air air loidhne"
po/gl.po+8−22
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-03 18:49+0000\n"
11"PO-Revision-Date: 2013-10-03 18:49+0000\n"
12"Last-Translator: Marcos Lans <Unknown>\n"
12"Last-Translator: Marcos Lans <Unknown>\n"
13"Language-Team: Galician <gl@li.org>\n"
13"Language-Team: Galician <gl@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -207,11 +207,15 @@ msgstr "Fale agora…"
207msgid "Speaking..."
207msgid "Speaking..."
208msgstr "Falando…"
208msgstr "Falando…"
209
209
210+#: Notifications/NotificationMenuItemFactory.qml:89
211+msgid "Show password"
212+msgstr ""
213+
210#: Panel/SearchIndicator.qml:27
214#: Panel/SearchIndicator.qml:27
211msgid "Search"
215msgid "Search"
212msgstr "Buscar"
216msgstr "Buscar"
213
217
214−#: plugins/Unity/scope.cpp:398
218+#: plugins/Unity/scope.cpp:408
215msgid "Sorry, there is nothing that matches your search."
219msgid "Sorry, there is nothing that matches your search."
216msgstr "Sentímolo, non hai nada que coincida con esta busca."
220msgstr "Sentímolo, non hai nada que coincida con esta busca."
217
221
@@ -223,21 +227,3 @@ msgstr "Todo"
223#, qt-format
227#, qt-format
224msgid "Please enter %1"
228msgid "Please enter %1"
225msgstr "Introduza %1"
229msgstr "Introduza %1"
226−
227−#~ msgid "Music"
228−#~ msgstr "Música"
229−
230−#~ msgid "Videos"
231−#~ msgstr "Vídeos"
232−
233−#~ msgid "Featured"
234−#~ msgstr "Destacado"
235−
236−#~ msgid "Recent"
237−#~ msgstr "Recentes"
238−
239−#~ msgid "New Releases"
240−#~ msgstr "Novas versións"
241−
242−#~ msgid "Popular Online"
243−#~ msgstr "Populares en liña"
po/he.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-01 09:19+0000\n"
11"PO-Revision-Date: 2013-10-01 09:19+0000\n"
12"Last-Translator: Yaron <sh.yaron@gmail.com>\n"
12"Last-Translator: Yaron <sh.yaron@gmail.com>\n"
13"Language-Team: Hebrew <he@li.org>\n"
13"Language-Team: Hebrew <he@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "יש לדבר כעת..."
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "הדיבור מושמע…"
206msgstr "הדיבור מושמע…"
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "חיפוש"
214msgstr "חיפוש"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "שום דבר אינו תואם לחיפוש שלך, עמך הסליחה."
218msgstr "שום דבר אינו תואם לחיפוש שלך, עמך הסליחה."
215
219
@@ -221,24 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr "נא להזין %1"
227msgstr "נא להזין %1"
224−
225−#~ msgid "Music"
226−#~ msgstr "מוזיקה"
227−
228−#~ msgid "Videos"
229−#~ msgstr "סרטונים"
230−
231−#~ msgid "Top Charting"
232−#~ msgstr "בראש הטבלה"
233−
234−#~ msgid "Featured"
235−#~ msgstr "מומלצים"
236−
237−#~ msgid "Recent"
238−#~ msgstr "אחרונים"
239−
240−#~ msgid "New Releases"
241−#~ msgstr "מהדורות חדשות"
242−
243−#~ msgid "Popular Online"
244−#~ msgstr "פופולריים ברחבי הרשת"
po/hr.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 04:14+0000\n"
11"PO-Revision-Date: 2013-06-27 04:14+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: Croatian <hr@li.org>\n"
13"Language-Team: Croatian <hr@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
20−"X-Generator: Launchpad (build 16799)\n"
20+"X-Generator: Launchpad (build 16820)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -206,11 +206,15 @@ msgstr "Recite..."
206msgid "Speaking..."
206msgid "Speaking..."
207msgstr "Govor..."
207msgstr "Govor..."
208
208
209+#: Notifications/NotificationMenuItemFactory.qml:89
210+msgid "Show password"
211+msgstr ""
212+
209#: Panel/SearchIndicator.qml:27
213#: Panel/SearchIndicator.qml:27
210msgid "Search"
214msgid "Search"
211msgstr "Pretraživanje"
215msgstr "Pretraživanje"
212
216
213−#: plugins/Unity/scope.cpp:398
217+#: plugins/Unity/scope.cpp:408
214msgid "Sorry, there is nothing that matches your search."
218msgid "Sorry, there is nothing that matches your search."
215msgstr "Nažalost, ne postoji ništa što odgovara vašoj pretrazi."
219msgstr "Nažalost, ne postoji ništa što odgovara vašoj pretrazi."
216
220
@@ -222,9 +226,3 @@ msgstr ""
222#, qt-format
226#, qt-format
223msgid "Please enter %1"
227msgid "Please enter %1"
224msgstr ""
228msgstr ""
225−
226−#~ msgid "Music"
227−#~ msgstr "Glazba"
228−
229−#~ msgid "Videos"
230−#~ msgstr "Video"
po/hu.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 04:28+0000\n"
11"PO-Revision-Date: 2013-06-27 04:28+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: Hungarian <hu@li.org>\n"
13"Language-Team: Hungarian <hu@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "Beszéljen most…"
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "Beszéd…"
206msgstr "Beszéd…"
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "Keresés"
214msgstr "Keresés"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "Elnézést, nincs találat a keresésre."
218msgstr "Elnézést, nincs találat a keresésre."
215
219
@@ -221,9 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "Zene"
227−
228−#~ msgid "Videos"
229−#~ msgstr "Videók"
po/hy.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 04:43+0000\n"
11"PO-Revision-Date: 2013-06-27 04:43+0000\n"
12"Last-Translator: iAbaS <sosabazyan@yandex.ru>\n"
12"Last-Translator: iAbaS <sosabazyan@yandex.ru>\n"
13"Language-Team: Armenian <hy@li.org>\n"
13"Language-Team: Armenian <hy@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "Խոսի՛ր"
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "Խոսում եմ..."
206msgstr "Խոսում եմ..."
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "Որոնում"
214msgstr "Որոնում"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "Կներերք, բայց Ձեր հարցումով ոչինչ չկար"
218msgstr "Կներերք, բայց Ձեր հարցումով ոչինչ չկար"
215
219
@@ -221,9 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "Երգեր"
227−
228−#~ msgid "Videos"
229−#~ msgstr "Վիդեոներ"
po/id.po+8−4
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-26 22:35+0000\n"
11"PO-Revision-Date: 2013-06-26 22:35+0000\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Language-Team: Indonesian <id@li.org>\n"
13"Language-Team: Indonesian <id@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr ""
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr ""
206msgstr ""
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr ""
214msgstr ""
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr ""
218msgstr ""
215
219
po/is.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-09-18 16:22+0000\n"
11"PO-Revision-Date: 2013-09-18 16:22+0000\n"
12"Last-Translator: Andri Thorlacius <Unknown>\n"
12"Last-Translator: Andri Thorlacius <Unknown>\n"
13"Language-Team: Icelandic <is@li.org>\n"
13"Language-Team: Icelandic <is@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -206,11 +206,15 @@ msgstr "Talaðu Núna..."
206msgid "Speaking..."
206msgid "Speaking..."
207msgstr "Tala..."
207msgstr "Tala..."
208
208
209+#: Notifications/NotificationMenuItemFactory.qml:89
210+msgid "Show password"
211+msgstr ""
212+
209#: Panel/SearchIndicator.qml:27
213#: Panel/SearchIndicator.qml:27
210msgid "Search"
214msgid "Search"
211msgstr "Leita"
215msgstr "Leita"
212
216
213−#: plugins/Unity/scope.cpp:398
217+#: plugins/Unity/scope.cpp:408
214msgid "Sorry, there is nothing that matches your search."
218msgid "Sorry, there is nothing that matches your search."
215msgstr "Því miður, það var ekkert sem passaði við leitarorðið þitt."
219msgstr "Því miður, það var ekkert sem passaði við leitarorðið þitt."
216
220
@@ -222,24 +226,3 @@ msgstr ""
222#, qt-format
226#, qt-format
223msgid "Please enter %1"
227msgid "Please enter %1"
224msgstr ""
228msgstr ""
225−
226−#~ msgid "Top Charting"
227−#~ msgstr "Topp Listi"
228−
229−#~ msgid "Featured"
230−#~ msgstr "Efst á baugi"
231−
232−#~ msgid "Recent"
233−#~ msgstr "Nýlegt"
234−
235−#~ msgid "New Releases"
236−#~ msgstr "Nýjar Útgáfur"
237−
238−#~ msgid "Videos"
239−#~ msgstr "Myndbönd"
240−
241−#~ msgid "Music"
242−#~ msgstr "Tónlist"
243−
244−#~ msgid "Popular Online"
245−#~ msgstr "Vinsælt á Netinu"
po/it.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-07 09:34+0000\n"
11"PO-Revision-Date: 2013-10-07 09:34+0000\n"
12"Last-Translator: Claudio Arseni <claudio.arseni@gmail.com>\n"
12"Last-Translator: Claudio Arseni <claudio.arseni@gmail.com>\n"
13"Language-Team: Italian <it@li.org>\n"
13"Language-Team: Italian <it@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -212,11 +212,15 @@ msgstr "Parla ora..."
212msgid "Speaking..."
212msgid "Speaking..."
213msgstr "Sto parlando..."
213msgstr "Sto parlando..."
214
214
215+#: Notifications/NotificationMenuItemFactory.qml:89
216+msgid "Show password"
217+msgstr ""
218+
215#: Panel/SearchIndicator.qml:27
219#: Panel/SearchIndicator.qml:27
216msgid "Search"
220msgid "Search"
217msgstr "Cerca"
221msgstr "Cerca"
218
222
219−#: plugins/Unity/scope.cpp:398
223+#: plugins/Unity/scope.cpp:408
220msgid "Sorry, there is nothing that matches your search."
224msgid "Sorry, there is nothing that matches your search."
221msgstr "Nessun risultato corrispondente alla ricerca."
225msgstr "Nessun risultato corrispondente alla ricerca."
222
226
@@ -228,24 +232,3 @@ msgstr "Tutto"
228#, qt-format
232#, qt-format
229msgid "Please enter %1"
233msgid "Please enter %1"
230msgstr "Inserire %1"
234msgstr "Inserire %1"
231−
232−#~ msgid "Music"
233−#~ msgstr "Musica"
234−
235−#~ msgid "Videos"
236−#~ msgstr "Video"
237−
238−#~ msgid "Recent"
239−#~ msgstr "Recenti"
240−
241−#~ msgid "New Releases"
242−#~ msgstr "Nuovi rilasci"
243−
244−#~ msgid "Featured"
245−#~ msgstr "In evidenza"
246−
247−#~ msgid "Popular Online"
248−#~ msgstr "Popolari online"
249−
250−#~ msgid "Top Charting"
251−#~ msgstr "Più votate"
po/ja.po+8−4
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-26 22:36+0000\n"
11"PO-Revision-Date: 2013-06-26 22:36+0000\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Language-Team: Japanese <ja@li.org>\n"
13"Language-Team: Japanese <ja@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr ""
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr ""
206msgstr ""
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr ""
214msgstr ""
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr ""
218msgstr ""
215
219
po/km.po+10−27
@@ -7,16 +7,16 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11−"PO-Revision-Date: 2013-10-11 08:49+0000\n"
11+"PO-Revision-Date: 2013-11-14 03:02+0000\n"
12−"Last-Translator: Khoem Sokhem <khoemsokhem@khmeros.info>\n"
12+"Last-Translator: Seng Sutha <sutha@khmeros.info>\n"
13"Language-Team: Khmer <km@li.org>\n"
13"Language-Team: Khmer <km@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=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-15 06:44+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16831)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -209,11 +209,15 @@ msgstr "និយាយ​ឥឡូវ..."
209msgid "Speaking..."
209msgid "Speaking..."
210msgstr "កំពុង​និយាយ..."
210msgstr "កំពុង​និយាយ..."
211
211
212+#: Notifications/NotificationMenuItemFactory.qml:89
213+msgid "Show password"
214+msgstr "បង្ហាញ​ពាក្យ​សម្ងាត់"
215+
212#: Panel/SearchIndicator.qml:27
216#: Panel/SearchIndicator.qml:27
213msgid "Search"
217msgid "Search"
214msgstr "ស្វែង​រក"
218msgstr "ស្វែង​រក"
215
219
216−#: plugins/Unity/scope.cpp:398
220+#: plugins/Unity/scope.cpp:408
217msgid "Sorry, there is nothing that matches your search."
221msgid "Sorry, there is nothing that matches your search."
218msgstr "សូម​ទោស មិនមាន​ពាក្យ​ដែល​អ្នក​ស្វែងរក​ទេ​។"
222msgstr "សូម​ទោស មិនមាន​ពាក្យ​ដែល​អ្នក​ស្វែងរក​ទេ​។"
219
223
@@ -225,24 +229,3 @@ msgstr "ទាំង​អស់"
225#, qt-format
229#, qt-format
226msgid "Please enter %1"
230msgid "Please enter %1"
227msgstr "សូម​បញ្ចូល %1"
231msgstr "សូម​បញ្ចូល %1"
228−
229−#~ msgid "Popular Online"
230−#~ msgstr "លើ​បណ្ដាញ​ប្រជាប្រិយ"
231−
232−#~ msgid "Music"
233−#~ msgstr "តន្ត្រី"
234−
235−#~ msgid "New Releases"
236−#~ msgstr "ការ​ចេញ​ផ្សាយ​ថ្មី"
237−
238−#~ msgid "Top Charting"
239−#~ msgstr "តារាង​ខាង​លើ"
240−
241−#~ msgid "Featured"
242−#~ msgstr "ដែល​ល្បី"
243−
244−#~ msgid "Recent"
245−#~ msgstr "ថ្មីៗ"
246−
247−#~ msgid "Videos"
248−#~ msgstr "វីដេអូ"
po/kn.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 05:43+0000\n"
11"PO-Revision-Date: 2013-06-27 05:43+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: Kannada <kn@li.org>\n"
13"Language-Team: Kannada <kn@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "ಈಗ ಮಾತನಾಡಿ ..."
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "ಮಾತನಾಡುತಿದ್ದೀರಿ"
206msgstr "ಮಾತನಾಡುತಿದ್ದೀರಿ"
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "ಹುಡುಕು"
214msgstr "ಹುಡುಕು"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "ಕ್ಷಮಿಸಿ ನಿಮ್ಮ ಶೋಧನೆಗೆ ಸರಿಯಾದ ಹೊಂದಾಣಿಕೆಗಳು ದೊರಕುತ್ತಿಲ್ಲ"
218msgstr "ಕ್ಷಮಿಸಿ ನಿಮ್ಮ ಶೋಧನೆಗೆ ಸರಿಯಾದ ಹೊಂದಾಣಿಕೆಗಳು ದೊರಕುತ್ತಿಲ್ಲ"
215
219
@@ -221,9 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "ಸಂಗೀತ"
227−
228−#~ msgid "Videos"
229−#~ msgstr "ವೀಡಿಯೋಗಳು"
po/ko.po+8−7
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-10 07:04+0000\n"
11"PO-Revision-Date: 2013-10-10 07:04+0000\n"
12"Last-Translator: Kim Boram <boramism@gmail.com>\n"
12"Last-Translator: Kim Boram <boramism@gmail.com>\n"
13"Language-Team: Korean <ko@li.org>\n"
13"Language-Team: Korean <ko@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr ""
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr ""
206msgstr ""
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "검색"
214msgstr "검색"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr ""
218msgstr ""
215
219
@@ -221,6 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "음악"
po/ky.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 06:17+0000\n"
11"PO-Revision-Date: 2013-06-27 06:17+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: Kirghiz <ky@li.org>\n"
13"Language-Team: Kirghiz <ky@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "Азыр сүйлөңүз..."
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "Сүйлөнүүдө..."
206msgstr "Сүйлөнүүдө..."
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "Издөө"
214msgstr "Издөө"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "Тилекке каршы, сиздин издөөңүзгө эч нерсе дал келген жок."
218msgstr "Тилекке каршы, сиздин издөөңүзгө эч нерсе дал келген жок."
215
219
@@ -221,9 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "Музыка"
227−
228−#~ msgid "Videos"
229−#~ msgstr "Видеолор"
po/lo.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-02 10:00+0000\n"
11"PO-Revision-Date: 2013-10-02 10:00+0000\n"
12"Last-Translator: Anousak <anousak@gmail.com>\n"
12"Last-Translator: Anousak <anousak@gmail.com>\n"
13"Language-Team: Lao <lo@li.org>\n"
13"Language-Team: Lao <lo@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "ເວົ້າໂລດ"
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "ກໍາລັງເວົ້າ"
206msgstr "ກໍາລັງເວົ້າ"
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "ຊອກຫາ"
214msgstr "ຊອກຫາ"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr ""
218msgstr ""
215
219
@@ -221,9 +225,3 @@ msgstr "ທັງໝົດ"
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr "ກະລູນາປ້ອນ %1"
227msgstr "ກະລູນາປ້ອນ %1"
224−
225−#~ msgid "Videos"
226−#~ msgstr "ວິດີໂອ"
227−
228−#~ msgid "Music"
229−#~ msgstr "ດົນຕີ"
po/lv.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-09-28 16:29+0000\n"
11"PO-Revision-Date: 2013-09-28 16:29+0000\n"
12"Last-Translator: Jānis-Marks Gailis <jeanmarc.gailis@gmail.com>\n"
12"Last-Translator: Jānis-Marks Gailis <jeanmarc.gailis@gmail.com>\n"
13"Language-Team: Latvian <lv@li.org>\n"
13"Language-Team: Latvian <lv@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "Runajiet Tagad"
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "Runa..."
206msgstr "Runa..."
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "Meklēt"
214msgstr "Meklēt"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "Diemžēl nekas neatbilst jūsu meklētajam."
218msgstr "Diemžēl nekas neatbilst jūsu meklētajam."
215
219
@@ -221,9 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "Mūzika"
227−
228−#~ msgid "Videos"
229−#~ msgstr "Video"
po/my.po+8−19
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-09 11:35+0000\n"
11"PO-Revision-Date: 2013-10-09 11:35+0000\n"
12"Last-Translator: Pyae Sone <Unknown>\n"
12"Last-Translator: Pyae Sone <Unknown>\n"
13"Language-Team: Burmese <my@li.org>\n"
13"Language-Team: Burmese <my@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "ယခုပြောပါ"
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "ပြောနေသည်"
206msgstr "ပြောနေသည်"
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "ရှာဖွေ"
214msgstr "ရှာဖွေ"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "ဆောရီး၊ သင်၏ရှာဖွေမူနှင့်တူညီတာဘာမှမရှိပါ။"
218msgstr "ဆောရီး၊ သင်၏ရှာဖွေမူနှင့်တူညီတာဘာမှမရှိပါ။"
215
219
@@ -221,18 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "တေးဂီတ"
227−
228−#~ msgid "Videos"
229−#~ msgstr "ဗီဒီယိုများ"
230−
231−#~ msgid "New Releases"
232−#~ msgstr "အသစ်ထွက်ရှိသော"
233−
234−#~ msgid "Recent"
235−#~ msgstr "မကြာသေးခင်က"
236−
237−#~ msgid "Popular Online"
238−#~ msgstr "အွန်လိုင်းတွင်ပေါ်ပြူလာဖြစ်သော"
po/nb.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 07:02+0000\n"
11"PO-Revision-Date: 2013-06-27 07:02+0000\n"
12"Last-Translator: Joakim Langvand <jlangvand@gmail.com>\n"
12"Last-Translator: Joakim Langvand <jlangvand@gmail.com>\n"
13"Language-Team: Norwegian Bokmal <nb@li.org>\n"
13"Language-Team: Norwegian Bokmal <nb@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "Snakk nå …"
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "Snakker …"
206msgstr "Snakker …"
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "Søk"
214msgstr "Søk"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "Søket ga ingen treff."
218msgstr "Søket ga ingen treff."
215
219
@@ -221,9 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "Musikk"
227−
228−#~ msgid "Videos"
229−#~ msgstr "Videoer"
po/nl.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 07:19+0000\n"
11"PO-Revision-Date: 2013-06-27 07:19+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: Dutch <nl@li.org>\n"
13"Language-Team: Dutch <nl@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:37+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "Nu inspreken…"
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "Inspreken…"
206msgstr "Inspreken…"
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "Zoeken"
214msgstr "Zoeken"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "Er is helaas niets dat met uw zoekopdracht overeenkomt."
218msgstr "Er is helaas niets dat met uw zoekopdracht overeenkomt."
215
219
@@ -221,9 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "Muziek"
227−
228−#~ msgid "Videos"
229−#~ msgstr "Video's"
po/pl.po+8−4
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-13 13:44+0000\n"
11"PO-Revision-Date: 2013-10-13 13:44+0000\n"
12"Last-Translator: GTriderXC <gtriderxc@yahoo.com>\n"
12"Last-Translator: GTriderXC <gtriderxc@yahoo.com>\n"
13"Language-Team: Polish <pl@li.org>\n"
13"Language-Team: Polish <pl@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
17"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
18"|| n%100>=20) ? 1 : 2;\n"
18"|| n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-10-14 05:47+0000\n"
19+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
20−"X-Generator: Launchpad (build 16799)\n"
20+"X-Generator: Launchpad (build 16820)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -211,11 +211,15 @@ msgstr "Mów teraz..."
211msgid "Speaking..."
211msgid "Speaking..."
212msgstr "Rozpoznanie..."
212msgstr "Rozpoznanie..."
213
213
214+#: Notifications/NotificationMenuItemFactory.qml:89
215+msgid "Show password"
216+msgstr ""
217+
214#: Panel/SearchIndicator.qml:27
218#: Panel/SearchIndicator.qml:27
215msgid "Search"
219msgid "Search"
216msgstr "Szukaj"
220msgstr "Szukaj"
217
221
218−#: plugins/Unity/scope.cpp:398
222+#: plugins/Unity/scope.cpp:408
219msgid "Sorry, there is nothing that matches your search."
223msgid "Sorry, there is nothing that matches your search."
220msgstr "Nie znaleziono pasujących wyników."
224msgstr "Nie znaleziono pasujących wyników."
221
225
po/pt_BR.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-01 13:05+0000\n"
11"PO-Revision-Date: 2013-10-01 13:05+0000\n"
12"Last-Translator: Rafael Neri <Unknown>\n"
12"Last-Translator: Rafael Neri <Unknown>\n"
13"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
13"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -207,11 +207,15 @@ msgstr "Fale agora..."
207msgid "Speaking..."
207msgid "Speaking..."
208msgstr "Falando..."
208msgstr "Falando..."
209
209
210+#: Notifications/NotificationMenuItemFactory.qml:89
211+msgid "Show password"
212+msgstr ""
213+
210#: Panel/SearchIndicator.qml:27
214#: Panel/SearchIndicator.qml:27
211msgid "Search"
215msgid "Search"
212msgstr "Pesquisar"
216msgstr "Pesquisar"
213
217
214−#: plugins/Unity/scope.cpp:398
218+#: plugins/Unity/scope.cpp:408
215msgid "Sorry, there is nothing that matches your search."
219msgid "Sorry, there is nothing that matches your search."
216msgstr "Desculpe, não há nada que corresponda à sua pesquisa."
220msgstr "Desculpe, não há nada que corresponda à sua pesquisa."
217
221
@@ -223,24 +227,3 @@ msgstr ""
223#, qt-format
227#, qt-format
224msgid "Please enter %1"
228msgid "Please enter %1"
225msgstr "Por favor, digite %1"
229msgstr "Por favor, digite %1"
226−
227−#~ msgid "Music"
228−#~ msgstr "Músicas"
229−
230−#~ msgid "Videos"
231−#~ msgstr "Vídeos"
232−
233−#~ msgid "New Releases"
234−#~ msgstr "Lançamentos"
235−
236−#~ msgid "Recent"
237−#~ msgstr "Recente"
238−
239−#~ msgid "Featured"
240−#~ msgstr "Em destaque"
241−
242−#~ msgid "Top Charting"
243−#~ msgstr "Top gráficos"
244−
245−#~ msgid "Popular Online"
246−#~ msgstr "Popular Online"
po/ro.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 07:53+0000\n"
11"PO-Revision-Date: 2013-06-27 07:53+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: Romanian <ro@li.org>\n"
13"Language-Team: Romanian <ro@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 "
17"Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 "
18"== 0) && (n != 0))) ? 2: 1));\n"
18"== 0) && (n != 0))) ? 2: 1));\n"
19−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
20−"X-Generator: Launchpad (build 16799)\n"
20+"X-Generator: Launchpad (build 16820)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -206,11 +206,15 @@ msgstr "Vorbiți acum..."
206msgid "Speaking..."
206msgid "Speaking..."
207msgstr "Vorbire..."
207msgstr "Vorbire..."
208
208
209+#: Notifications/NotificationMenuItemFactory.qml:89
210+msgid "Show password"
211+msgstr ""
212+
209#: Panel/SearchIndicator.qml:27
213#: Panel/SearchIndicator.qml:27
210msgid "Search"
214msgid "Search"
211msgstr "Căutare"
215msgstr "Căutare"
212
216
213−#: plugins/Unity/scope.cpp:398
217+#: plugins/Unity/scope.cpp:408
214msgid "Sorry, there is nothing that matches your search."
218msgid "Sorry, there is nothing that matches your search."
215msgstr ""
219msgstr ""
216"Ne pare rău, nu este nimic care se potrivește căutării dumneavoastră."
220"Ne pare rău, nu este nimic care se potrivește căutării dumneavoastră."
@@ -223,9 +227,3 @@ msgstr ""
223#, qt-format
227#, qt-format
224msgid "Please enter %1"
228msgid "Please enter %1"
225msgstr ""
229msgstr ""
226−
227−#~ msgid "Music"
228−#~ msgstr "Muzică"
229−
230−#~ msgid "Videos"
231−#~ msgstr "Video"
po/ru.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-01 05:55+0000\n"
11"PO-Revision-Date: 2013-10-01 05:55+0000\n"
12"Last-Translator: Zonov Roman <Unknown>\n"
12"Last-Translator: Zonov Roman <Unknown>\n"
13"Language-Team: Russian <ru@li.org>\n"
13"Language-Team: Russian <ru@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
20−"X-Generator: Launchpad (build 16799)\n"
20+"X-Generator: Launchpad (build 16820)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -210,11 +210,15 @@ msgstr "Говорите..."
210msgid "Speaking..."
210msgid "Speaking..."
211msgstr "Говорите..."
211msgstr "Говорите..."
212
212
213+#: Notifications/NotificationMenuItemFactory.qml:89
214+msgid "Show password"
215+msgstr ""
216+
213#: Panel/SearchIndicator.qml:27
217#: Panel/SearchIndicator.qml:27
214msgid "Search"
218msgid "Search"
215msgstr "Поиск"
219msgstr "Поиск"
216
220
217−#: plugins/Unity/scope.cpp:398
221+#: plugins/Unity/scope.cpp:408
218msgid "Sorry, there is nothing that matches your search."
222msgid "Sorry, there is nothing that matches your search."
219msgstr "Извините, поиск не дал результатов."
223msgstr "Извините, поиск не дал результатов."
220
224
@@ -226,24 +230,3 @@ msgstr ""
226#, qt-format
230#, qt-format
227msgid "Please enter %1"
231msgid "Please enter %1"
228msgstr "Пожалуйста, введите %1"
232msgstr "Пожалуйста, введите %1"
229−
230−#~ msgid "New Releases"
231−#~ msgstr "Новые релизы"
232−
233−#~ msgid "Music"
234−#~ msgstr "Музыка"
235−
236−#~ msgid "Videos"
237−#~ msgstr "Видео"
238−
239−#~ msgid "Recent"
240−#~ msgstr "Недавние"
241−
242−#~ msgid "Top Charting"
243−#~ msgstr "Наиболее популярное"
244−
245−#~ msgid "Popular Online"
246−#~ msgstr "Популярное в Интернете"
247−
248−#~ msgid "Featured"
249−#~ msgstr "Рекомендованное"
po/shn.po+8−4
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-07 11:46+0000\n"
11"PO-Revision-Date: 2013-10-07 11:46+0000\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Language-Team: Shan <shn@li.org>\n"
13"Language-Team: Shan <shn@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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) ? 0 : 1;\n"
17"Plural-Forms: nplurals=2; plural=(n == 1) ? 0 : 1;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr ""
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr ""
206msgstr ""
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr ""
214msgstr ""
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr ""
218msgstr ""
215
219
po/si.po+8−4
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-26 22:36+0000\n"
11"PO-Revision-Date: 2013-06-26 22:36+0000\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Language-Team: Sinhalese <si@li.org>\n"
13"Language-Team: Sinhalese <si@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr ""
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr ""
206msgstr ""
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr ""
214msgstr ""
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr ""
218msgstr ""
215
219
po/sl.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-02 10:55+0000\n"
11"PO-Revision-Date: 2013-10-02 10:55+0000\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
17"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
18"n%100==4 ? 3 : 0);\n"
18"n%100==4 ? 3 : 0);\n"
19−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
20−"X-Generator: Launchpad (build 16799)\n"
20+"X-Generator: Launchpad (build 16820)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -212,11 +212,15 @@ msgstr "Govorite zdaj ..."
212msgid "Speaking..."
212msgid "Speaking..."
213msgstr "Govorjenje ..."
213msgstr "Govorjenje ..."
214
214
215+#: Notifications/NotificationMenuItemFactory.qml:89
216+msgid "Show password"
217+msgstr ""
218+
215#: Panel/SearchIndicator.qml:27
219#: Panel/SearchIndicator.qml:27
216msgid "Search"
220msgid "Search"
217msgstr "Iskanje"
221msgstr "Iskanje"
218
222
219−#: plugins/Unity/scope.cpp:398
223+#: plugins/Unity/scope.cpp:408
220msgid "Sorry, there is nothing that matches your search."
224msgid "Sorry, there is nothing that matches your search."
221msgstr "Nič se ne ujema z vašim iskalnim nizom."
225msgstr "Nič se ne ujema z vašim iskalnim nizom."
222
226
@@ -228,24 +232,3 @@ msgstr "Vse"
228#, qt-format
232#, qt-format
229msgid "Please enter %1"
233msgid "Please enter %1"
230msgstr "Vnesite %1"
234msgstr "Vnesite %1"
231−
232−#~ msgid "Music"
233−#~ msgstr "Glasba"
234−
235−#~ msgid "Videos"
236−#~ msgstr "Videi"
237−
238−#~ msgid "New Releases"
239−#~ msgstr "Nove izdaje"
240−
241−#~ msgid "Top Charting"
242−#~ msgstr "Najvišje na lestvici"
243−
244−#~ msgid "Featured"
245−#~ msgstr "Predstavljeno"
246−
247−#~ msgid "Recent"
248−#~ msgstr "Nedavno"
249−
250−#~ msgid "Popular Online"
251−#~ msgstr "Priljubljeno na spletu"
po/sr.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 09:19+0000\n"
11"PO-Revision-Date: 2013-06-27 09:19+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: Serbian <sr@li.org>\n"
13"Language-Team: Serbian <sr@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
19+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
20−"X-Generator: Launchpad (build 16799)\n"
20+"X-Generator: Launchpad (build 16820)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -206,11 +206,15 @@ msgstr "Изговорите сада..."
206msgid "Speaking..."
206msgid "Speaking..."
207msgstr "Говор..."
207msgstr "Говор..."
208
208
209+#: Notifications/NotificationMenuItemFactory.qml:89
210+msgid "Show password"
211+msgstr ""
212+
209#: Panel/SearchIndicator.qml:27
213#: Panel/SearchIndicator.qml:27
210msgid "Search"
214msgid "Search"
211msgstr "Претрага"
215msgstr "Претрага"
212
216
213−#: plugins/Unity/scope.cpp:398
217+#: plugins/Unity/scope.cpp:408
214msgid "Sorry, there is nothing that matches your search."
218msgid "Sorry, there is nothing that matches your search."
215msgstr "Нажалост, претрага није наишла на икакво подударање."
219msgstr "Нажалост, претрага није наишла на икакво подударање."
216
220
@@ -222,9 +226,3 @@ msgstr ""
222#, qt-format
226#, qt-format
223msgid "Please enter %1"
227msgid "Please enter %1"
224msgstr ""
228msgstr ""
225−
226−#~ msgid "Music"
227−#~ msgstr "Музика"
228−
229−#~ msgid "Videos"
230−#~ msgstr "Видео"
po/sv.po+8−4
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-26 22:36+0000\n"
11"PO-Revision-Date: 2013-06-26 22:36+0000\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Language-Team: Swedish <sv@li.org>\n"
13"Language-Team: Swedish <sv@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr ""
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr ""
206msgstr ""
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr ""
214msgstr ""
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr ""
218msgstr ""
215
219
po/ta.ponew file+233
@@ -0,0 +1,233 @@
1+# Tamil translation for unity8
2+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
5+# துளசி <Thangamani Arun<thangam.arunx@gmail.com>>, 2013.
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11+"PO-Revision-Date: 2013-10-24 11:36+0000\n"
12+"Last-Translator: Thangamani Arun - தங்கமணி அருண் <thangam.arunx@gmail.com>\n"
13+"Language-Team: Ubuntu Tamil Team/Free Tamil Computing/Thamizha\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=2; plural=n != 1;\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19+"X-Generator: Launchpad (build 16820)\n"
20+"Language: ta\n"
21+
22+#: Applications/applications.js:23
23+msgid "Phone"
24+msgstr "தொலைபேசி"
25+
26+#: Applications/applications.js:29
27+msgid "Camera"
28+msgstr "புகைப்பட கருவி"
29+
30+#: Applications/applications.js:35
31+msgid "Gallery"
32+msgstr "படத்தொகுப்பு"
33+
34+#: Applications/applications.js:40
35+msgid "Facebook"
36+msgstr "முகநுல்"
37+
38+#: Applications/applications.js:46
39+msgid "Browser"
40+msgstr "உலாவி"
41+
42+#: Applications/applications.js:51
43+msgid "Twitter"
44+msgstr "ட்விட்டர்"
45+
46+#: Applications/applications.js:57
47+msgid "GMail"
48+msgstr "ஜிமெயில்"
49+
50+#: Applications/applications.js:62
51+msgid "Weather"
52+msgstr "வானிலை"
53+
54+#: Applications/applications.js:68
55+msgid "Notepad"
56+msgstr "குறிப்புபலகை"
57+
58+#: Applications/applications.js:74
59+msgid "Calendar"
60+msgstr "நாள்காட்டி"
61+
62+#: Applications/applications.js:80
63+msgid "Media Player"
64+msgstr "ஊடக இயக்கி"
65+
66+#: Applications/applications.js:86
67+msgid "Evernote"
68+msgstr "எப்போதும்குறிப்பெடு"
69+
70+#: Applications/applications.js:91
71+msgid "Map"
72+msgstr "வரைபடம்"
73+
74+#: Applications/applications.js:96
75+msgid "Pinterest"
76+msgstr "விசைத்தட்டு"
77+
78+#: Applications/applications.js:101
79+msgid "SoundCloud"
80+msgstr "ஒலி கிளவுட்"
81+
82+#: Applications/applications.js:106
83+msgid "Wikipedia"
84+msgstr "விக்கிப்பீடியா"
85+
86+#: Applications/applications.js:111
87+msgid "YouTube"
88+msgstr "யூட்யுப்"
89+
90+#: Components/EdgeDemoOverlay.qml:149
91+msgid "Skip intro"
92+msgstr "அறிமுகத்தை தவிர்"
93+
94+#: Components/EdgeDemo.qml:112
95+msgid "Right edge"
96+msgstr "வலது விளிம்பு"
97+
98+#: Components/EdgeDemo.qml:113
99+msgid "Try swiping from the right edge to unlock the phone"
100+msgstr "தொலைபேசியை திறக்க வலது முனையிலிருந்து தேய்த்து முயற்சி செய்"
101+
102+#: Components/EdgeDemo.qml:144
103+msgid "Top edge"
104+msgstr "மேல் விளிம்பு"
105+
106+#: Components/EdgeDemo.qml:145
107+msgid "Try swiping from the top edge to access the indicators"
108+msgstr "காட்டிகளை அனுக மேல் விளிம்பிலிருந்து தேய்த்து முயற்சி செய்"
109+
110+#: Components/EdgeDemo.qml:170
111+msgid "Close"
112+msgstr "மூடு"
113+
114+#: Components/EdgeDemo.qml:171
115+msgid "Swipe up again to close the settings screen"
116+msgstr "அமைவுகளின் திரையை மூட மறுபடியும் மேலே தேய்க்கவும்"
117+
118+#: Components/EdgeDemo.qml:198
119+msgid "Left edge"
120+msgstr "இடது விளிம்பு"
121+
122+#: Components/EdgeDemo.qml:199
123+msgid "Swipe from the left to reveal the launcher for quick access to apps"
124+msgstr ""
125+"பயன்பாடுகளின் விரைவான அணுகலை பெறத்தேவையான தொடக்கியை இடமிருந்து தேய்த்தால் "
126+"வெளிப்படும்"
127+
128+#: Components/EdgeDemo.qml:226
129+msgid "Well done"
130+msgstr "நன்றாக செய்தீர்கள்"
131+
132+#: Components/EdgeDemo.qml:227
133+msgid ""
134+"You have now mastered the edge gestures and can start using the "
135+"phone<br><br>Tap anywhere to start"
136+msgstr ""
137+"நீங்கள் இப்போது விளிம்பு சைகைகளில் கைதேர்ந்தவர் மற்றும் தொலைபேசி "
138+"பயன்படுத்த தொடங்கவும் <br> <br>தட்டுவதன் மூலம் எங்க வேண்டுமானாலும் "
139+"தொடங்கலாம்."
140+
141+#: Components/PageHeader.qml:341
142+msgid "Recent searches"
143+msgstr "கடையாக தேடப்பட்டவைகள்"
144+
145+#. TRANSLATORS: Number of persons who rated this app
146+#. TRANSLATORS: Number of persons who rated this app/video/whatever
147+#: Dash/Apps/AppInfo.qml:73 Dash/Previews/Header.qml:93
148+#, qt-format
149+msgid "(%1)"
150+msgstr "(%1)"
151+
152+#. TRANSLATORS: Number of persons who wrote reviews for this app
153+#. TRANSLATORS: Number of persons who wrote reviews for this app/video/whatever
154+#: Dash/Apps/AppInfo.qml:85 Dash/Previews/Header.qml:105
155+#, qt-format
156+msgid "%1 review"
157+msgid_plural "%1 reviews"
158+msgstr[0] "%1 பரிசீலனை"
159+msgstr[1] "%1 பரிசீலனைகள்"
160+
161+#: Dash/Apps/AppPreview.qml:126
162+msgid "Rate this"
163+msgstr "இதை மதிப்பிடு"
164+
165+#: Dash/Previews/Reviews.qml:74
166+msgid "Add a review"
167+msgstr "ஒரு பரிசீலனையை சேர்"
168+
169+#: Dash/Previews/Reviews.qml:86
170+msgid "Review"
171+msgstr "மறுஆய்வு"
172+
173+#: Dash/Previews/Reviews.qml:121
174+msgid "Send"
175+msgstr "அனுப்பு"
176+
177+#: Dash/Previews/Reviews.qml:139
178+msgid "Comments:"
179+msgstr "கருத்துகள்:"
180+
181+#: Greeter/Lockscreen.qml:142
182+msgid "Emergency Call"
183+msgstr "அவசர அழைப்பு"
184+
185+#: Greeter/PassphraseLockscreen.qml:59
186+#, qt-format
187+msgid "Hello %1"
188+msgstr "வணக்கம் %1"
189+
190+#: Greeter/PassphraseLockscreen.qml:59
191+msgid "Hello"
192+msgstr "வணக்கம்"
193+
194+#: Hud/HudParametrizedActionsPage.qml:132
195+msgid "Confirm"
196+msgstr "உறுதிப்படுத்து"
197+
198+#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
199+msgid "Type or say a command"
200+msgstr "ஒரு கட்டளையை உச்சரி அல்லது தட்டச்சுசெய்"
201+
202+#: Hud/Hud.qml:84
203+msgid "Loading. Please Wait..."
204+msgstr "ஏற்றுகிறது. தயைசெய்து காத்திருக்கவும்..."
205+
206+#: Hud/Hud.qml:89
207+msgid "Speak Now..."
208+msgstr "இப்பொது பேசு..."
209+
210+#: Hud/Hud.qml:94
211+msgid "Speaking..."
212+msgstr "பேசுகிறது..."
213+
214+#: Notifications/NotificationMenuItemFactory.qml:89
215+msgid "Show password"
216+msgstr ""
217+
218+#: Panel/SearchIndicator.qml:27
219+msgid "Search"
220+msgstr "தெடு"
221+
222+#: plugins/Unity/scope.cpp:408
223+msgid "Sorry, there is nothing that matches your search."
224+msgstr "மன்னிக்கவும், உங்களுடைய தேடலுக்கு தகுந்த பொருத்தம் கிடைக்கவில்லை."
225+
226+#: plugins/Unity/showallfilteroption.cpp:41
227+msgid "All"
228+msgstr "அனைத்தும்"
229+
230+#: Shell.qml:438
231+#, qt-format
232+msgid "Please enter %1"
233+msgstr "தயவுச்செய்து %1 உள்ளிடு"
po/te.po+8−7
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 09:57+0000\n"
11"PO-Revision-Date: 2013-06-27 09:57+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: Telugu <te@li.org>\n"
13"Language-Team: Telugu <te@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr ""
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr ""
206msgstr ""
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr ""
214msgstr ""
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr ""
218msgstr ""
215
219
@@ -221,6 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "సంగీతం"
po/tr.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-01 13:21+0000\n"
11"PO-Revision-Date: 2013-10-01 13:21+0000\n"
12"Last-Translator: Volkan Gezer <Unknown>\n"
12"Last-Translator: Volkan Gezer <Unknown>\n"
13"Language-Team: Turkish <tr@li.org>\n"
13"Language-Team: Turkish <tr@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -206,11 +206,15 @@ msgstr "Şimdi Konuşun..."
206msgid "Speaking..."
206msgid "Speaking..."
207msgstr "Konuşuyor..."
207msgstr "Konuşuyor..."
208
208
209+#: Notifications/NotificationMenuItemFactory.qml:89
210+msgid "Show password"
211+msgstr ""
212+
209#: Panel/SearchIndicator.qml:27
213#: Panel/SearchIndicator.qml:27
210msgid "Search"
214msgid "Search"
211msgstr "Ara"
215msgstr "Ara"
212
216
213−#: plugins/Unity/scope.cpp:398
217+#: plugins/Unity/scope.cpp:408
214msgid "Sorry, there is nothing that matches your search."
218msgid "Sorry, there is nothing that matches your search."
215msgstr "Üzgünüz, aramanızla eşleşen hiçbir şey yok."
219msgstr "Üzgünüz, aramanızla eşleşen hiçbir şey yok."
216
220
@@ -222,24 +226,3 @@ msgstr ""
222#, qt-format
226#, qt-format
223msgid "Please enter %1"
227msgid "Please enter %1"
224msgstr "Lütfen %1 girin"
228msgstr "Lütfen %1 girin"
225−
226−#~ msgid "Featured"
227−#~ msgstr "Öne Çıkanlar"
228−
229−#~ msgid "Recent"
230−#~ msgstr "En Son"
231−
232−#~ msgid "Music"
233−#~ msgstr "Müzik"
234−
235−#~ msgid "Popular Online"
236−#~ msgstr "Genellikle Çevrimiçi"
237−
238−#~ msgid "Videos"
239−#~ msgstr "Videolar"
240−
241−#~ msgid "Top Charting"
242−#~ msgstr "En Çok Beğenilenler"
243−
244−#~ msgid "New Releases"
245−#~ msgstr "Yeni Sürümler"
po/ug.po+8−19
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-09 22:38+0000\n"
11"PO-Revision-Date: 2013-10-09 22:38+0000\n"
12"Last-Translator: Gheyret T.Kenji <Unknown>\n"
12"Last-Translator: Gheyret T.Kenji <Unknown>\n"
13"Language-Team: Uyghur <ug@li.org>\n"
13"Language-Team: Uyghur <ug@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -204,11 +204,15 @@ msgstr "ئەمدى سۆزلەڭ…"
204msgid "Speaking..."
204msgid "Speaking..."
205msgstr "سۆزلەۋاتىسىز…"
205msgstr "سۆزلەۋاتىسىز…"
206
206
207+#: Notifications/NotificationMenuItemFactory.qml:89
208+msgid "Show password"
209+msgstr ""
210+
207#: Panel/SearchIndicator.qml:27
211#: Panel/SearchIndicator.qml:27
208msgid "Search"
212msgid "Search"
209msgstr "ئىزدە"
213msgstr "ئىزدە"
210
214
211−#: plugins/Unity/scope.cpp:398
215+#: plugins/Unity/scope.cpp:408
212msgid "Sorry, there is nothing that matches your search."
216msgid "Sorry, there is nothing that matches your search."
213msgstr "كەچۈرۈڭ، ئىزدىگىنىڭىزگە ماس نەتىجە تېپىلمىدى."
217msgstr "كەچۈرۈڭ، ئىزدىگىنىڭىزگە ماس نەتىجە تېپىلمىدى."
214
218
@@ -220,18 +224,3 @@ msgstr "ھەممىسى"
220#, qt-format
224#, qt-format
221msgid "Please enter %1"
225msgid "Please enter %1"
222msgstr "%1 نى كىرگۈزۈڭ"
226msgstr "%1 نى كىرگۈزۈڭ"
223−
224−#~ msgid "Featured"
225−#~ msgstr "داڭلىق"
226−
227−#~ msgid "Recent"
228−#~ msgstr "يېقىنقى"
229−
230−#~ msgid "New Releases"
231−#~ msgstr "يېڭى ئېلان قىلىنغانلىرى"
232−
233−#~ msgid "Music"
234−#~ msgstr "مۇزىكا"
235−
236−#~ msgid "Videos"
237−#~ msgstr "سىنلار"
po/uk.po+8−4
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-19 16:44+0000\n"
11"PO-Revision-Date: 2013-10-19 16:44+0000\n"
12"Last-Translator: Yuri Chornoivan <yurchor@gmail.com>\n"
12"Last-Translator: Yuri Chornoivan <yurchor@gmail.com>\n"
13"Language-Team: Ukrainian <uk@li.org>\n"
13"Language-Team: Ukrainian <uk@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-10-20 05:20+0000\n"
19+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
20−"X-Generator: Launchpad (build 16807)\n"
20+"X-Generator: Launchpad (build 16820)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -212,11 +212,15 @@ msgstr "Можна говорити…"
212msgid "Speaking..."
212msgid "Speaking..."
213msgstr "Мовлення…"
213msgstr "Мовлення…"
214
214
215+#: Notifications/NotificationMenuItemFactory.qml:89
216+msgid "Show password"
217+msgstr ""
218+
215#: Panel/SearchIndicator.qml:27
219#: Panel/SearchIndicator.qml:27
216msgid "Search"
220msgid "Search"
217msgstr "Пошук"
221msgstr "Пошук"
218
222
219−#: plugins/Unity/scope.cpp:398
223+#: plugins/Unity/scope.cpp:408
220msgid "Sorry, there is nothing that matches your search."
224msgid "Sorry, there is nothing that matches your search."
221msgstr "Вибачте, для вказаних вами ключових слів нічого не знайдено."
225msgstr "Вибачте, для вказаних вами ключових слів нічого не знайдено."
222
226
po/unity8.pot+20−7
@@ -8,7 +8,7 @@ msgid ""
8msgstr ""
8msgstr ""
9"Project-Id-Version: unity8\n"
9"Project-Id-Version: unity8\n"
10"Report-Msgid-Bugs-To: \n"
10"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2013-10-11 12:12+0200\n"
11+"POT-Creation-Date: 2013-11-12 16:10+0100\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -86,7 +86,7 @@ msgstr ""
86msgid "YouTube"
86msgid "YouTube"
87msgstr ""
87msgstr ""
88
88
89−#: Components/EdgeDemoOverlay.qml:149
89+#: Components/EdgeDemoOverlay.qml:151
90msgid "Skip intro"
90msgid "Skip intro"
91msgstr ""
91msgstr ""
92
92
@@ -132,7 +132,7 @@ msgid ""
132"phone<br><br>Tap anywhere to start"
132"phone<br><br>Tap anywhere to start"
133msgstr ""
133msgstr ""
134
134
135−#: Components/PageHeader.qml:341
135+#: Components/PageHeader.qml:345
136msgid "Recent searches"
136msgid "Recent searches"
137msgstr ""
137msgstr ""
138
138
@@ -152,7 +152,7 @@ msgid_plural "%1 reviews"
152msgstr[0] ""
152msgstr[0] ""
153msgstr[1] ""
153msgstr[1] ""
154
154
155−#: Dash/Apps/AppPreview.qml:126
155+#: Dash/Apps/AppPreview.qml:135
156msgid "Rate this"
156msgid "Rate this"
157msgstr ""
157msgstr ""
158
158
@@ -172,7 +172,7 @@ msgstr ""
172msgid "Comments:"
172msgid "Comments:"
173msgstr ""
173msgstr ""
174
174
175−#: Greeter/Lockscreen.qml:142
175+#: Greeter/Lockscreen.qml:146
176msgid "Emergency Call"
176msgid "Emergency Call"
177msgstr ""
177msgstr ""
178
178
@@ -205,11 +205,24 @@ msgstr ""
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr ""
206msgstr ""
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr ""
214msgstr ""
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/Launcher/launcheritem.cpp:43
217+#: plugins/Unity/Launcher/launcheritem.cpp:73
218+msgid "Lock to Launcher"
219+msgstr ""
220+
221+#: plugins/Unity/Launcher/launcheritem.cpp:73
222+msgid "Unlock from Launcher"
223+msgstr ""
224+
225+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
226msgid "Sorry, there is nothing that matches your search."
214msgstr ""
227msgstr ""
215
228
@@ -217,7 +230,7 @@ msgstr ""
217msgid "All"
230msgid "All"
218msgstr ""
231msgstr ""
219
232
220−#: Shell.qml:438
233+#: Shell.qml:441
221#, qt-format
234#, qt-format
222msgid "Please enter %1"
235msgid "Please enter %1"
223msgstr ""
236msgstr ""
po/xh.po+8−4
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-09-28 13:20+0000\n"
11"PO-Revision-Date: 2013-09-28 13:20+0000\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Language-Team: Xhosa <xh@li.org>\n"
13"Language-Team: Xhosa <xh@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr ""
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr ""
206msgstr ""
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr ""
214msgstr ""
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr ""
218msgstr ""
215
219
po/zh_CN.po+8−25
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-10-09 13:51+0000\n"
11"PO-Revision-Date: 2013-10-09 13:51+0000\n"
12"Last-Translator: Aron Xu <Unknown>\n"
12"Last-Translator: Aron Xu <Unknown>\n"
13"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
13"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "现在请讲..."
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "讲话中..."
206msgstr "讲话中..."
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "搜索"
214msgstr "搜索"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "对不起,没有找到您想要的结果。"
218msgstr "对不起,没有找到您想要的结果。"
215
219
@@ -221,24 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Featured"
226−#~ msgstr "推荐"
227−
228−#~ msgid "New Releases"
229−#~ msgstr "新版本"
230−
231−#~ msgid "Top Charting"
232−#~ msgstr "排行榜图"
233−
234−#~ msgid "Music"
235−#~ msgstr "音乐"
236−
237−#~ msgid "Popular Online"
238−#~ msgstr "经常在线"
239−
240−#~ msgid "Videos"
241−#~ msgstr "视频"
242−
243−#~ msgid "Recent"
244−#~ msgstr "最近使用"
po/zh_TW.po+8−10
@@ -7,7 +7,7 @@ msgid ""
7msgstr ""
7msgstr ""
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: 2013-10-11 12:12+0200\n"
10+"POT-Creation-Date: 2013-11-05 17:53+0100\n"
11"PO-Revision-Date: 2013-06-27 10:24+0000\n"
11"PO-Revision-Date: 2013-06-27 10:24+0000\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
13"Language-Team: Chinese (Traditional) <zh_TW@li.org>\n"
13"Language-Team: Chinese (Traditional) <zh_TW@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
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=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-10-13 05:43+0000\n"
18+"X-Launchpad-Export-Date: 2013-11-08 06:38+0000\n"
19−"X-Generator: Launchpad (build 16799)\n"
19+"X-Generator: Launchpad (build 16820)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -205,11 +205,15 @@ msgstr "請說..."
205msgid "Speaking..."
205msgid "Speaking..."
206msgstr "說話中..."
206msgstr "說話中..."
207
207
208+#: Notifications/NotificationMenuItemFactory.qml:89
209+msgid "Show password"
210+msgstr ""
211+
208#: Panel/SearchIndicator.qml:27
212#: Panel/SearchIndicator.qml:27
209msgid "Search"
213msgid "Search"
210msgstr "搜尋"
214msgstr "搜尋"
211
215
212−#: plugins/Unity/scope.cpp:398
216+#: plugins/Unity/scope.cpp:408
213msgid "Sorry, there is nothing that matches your search."
217msgid "Sorry, there is nothing that matches your search."
214msgstr "很抱歉,找不到符合您想搜尋的結果。"
218msgstr "很抱歉,找不到符合您想搜尋的結果。"
215
219
@@ -221,9 +225,3 @@ msgstr ""
221#, qt-format
225#, qt-format
222msgid "Please enter %1"
226msgid "Please enter %1"
223msgstr ""
227msgstr ""
224−
225−#~ msgid "Music"
226−#~ msgstr "音樂"
227−
228−#~ msgid "Videos"
229−#~ msgstr "影片"
run_on_device+24−4
@@ -1,4 +1,4 @@
1−#!/bin/sh
1+#!/bin/bash
2CODE_DIR=shell
2CODE_DIR=shell
3USER=phablet
3USER=phablet
4USER_ID=32011
4USER_ID=32011
@@ -17,6 +17,8 @@ SUDO="echo $PASSWORD | sudo -S"
17NUM_JOBS='$(( `grep -c ^processor /proc/cpuinfo` + 1 ))'
17NUM_JOBS='$(( `grep -c ^processor /proc/cpuinfo` + 1 ))'
18FLIPPED=false
18FLIPPED=false
19CHROOT_PREFIX="/data/ubuntu"
19CHROOT_PREFIX="/data/ubuntu"
20+SSH_WAS_STARTED=0
21+SSH_STARTED=0
20
22
21usage() {
23usage() {
22 echo "usage: run_on_device [OPTIONS]\n"
24 echo "usage: run_on_device [OPTIONS]\n"
@@ -32,7 +34,15 @@ usage() {
32 exit 1
34 exit 1
33}
35}
34
36
37+start_ssh() {
38+ if [ $SSH_STARTED -eq 0 ]; then
39+ exec_with_adb initctl start ssh
40+ SSH_STARTED=1
41+ fi
42+}
43+
35exec_with_ssh() {
44exec_with_ssh() {
45+ start_ssh
36 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -t $USER@$TARGET_IP -p $TARGET_SSH_PORT sudo -u $USER -i bash -ic \"$@\"
46 ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -t $USER@$TARGET_IP -p $TARGET_SSH_PORT sudo -u $USER -i bash -ic \"$@\"
37}
47}
38
48
@@ -52,7 +62,7 @@ adb_root() {
52install_ssh_key() {
62install_ssh_key() {
53 ssh-keygen -R $TARGET_IP
63 ssh-keygen -R $TARGET_IP
54 HOME_DIR="${CHROOT_PREFIX}/home/phablet"
64 HOME_DIR="${CHROOT_PREFIX}/home/phablet"
55− adb push ~/.ssh/phone_rsa.pub $HOME_DIR/.ssh/authorized_keys
65+ adb push ~/.ssh/id_rsa.pub $HOME_DIR/.ssh/authorized_keys
56 adb shell chown $USER_ID:$USER_ID $HOME_DIR/.ssh
66 adb shell chown $USER_ID:$USER_ID $HOME_DIR/.ssh
57 adb shell chown $USER_ID:$USER_ID $HOME_DIR/.ssh/authorized_keys
67 adb shell chown $USER_ID:$USER_ID $HOME_DIR/.ssh/authorized_keys
58 adb shell chmod 700 $HOME_DIR/.ssh
68 adb shell chmod 700 $HOME_DIR/.ssh
@@ -65,8 +75,6 @@ setup_adb_forwarding() {
65}
75}
66
76
67install_dependencies() {
77install_dependencies() {
68− exec_with_adb rm /etc/init/ssh.override
69− exec_with_adb service ssh start
70 exec_with_adb apt-get update
78 exec_with_adb apt-get update
71 exec_with_ssh $SUDO apt-get -y install build-essential rsync bzr ccache gdb ninja-build devscripts equivs
79 exec_with_ssh $SUDO apt-get -y install build-essential rsync bzr ccache gdb ninja-build devscripts equivs
72}
80}
@@ -74,6 +82,7 @@ install_dependencies() {
74sync_code() {
82sync_code() {
75 [ -e .bzr ] && bzr export --uncommitted --format=dir /tmp/$CODE_DIR
83 [ -e .bzr ] && bzr export --uncommitted --format=dir /tmp/$CODE_DIR
76 [ -e .git ] && git checkout-index -a -f --prefix=/tmp/$CODE_DIR/
84 [ -e .git ] && git checkout-index -a -f --prefix=/tmp/$CODE_DIR/
85+ start_ssh
77 rsync -crlOzv --delete --exclude builddir -e "ssh -p $TARGET_SSH_PORT -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" /tmp/$CODE_DIR/ $USER@$TARGET_IP:$CODE_DIR/
86 rsync -crlOzv --delete --exclude builddir -e "ssh -p $TARGET_SSH_PORT -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" /tmp/$CODE_DIR/ $USER@$TARGET_IP:$CODE_DIR/
78 rm -rf /tmp/$CODE_DIR
87 rm -rf /tmp/$CODE_DIR
79}
88}
@@ -96,7 +105,9 @@ run() {
96 fi
105 fi
97
106
98 exec_with_ssh "stop unity8"
107 exec_with_ssh "stop unity8"
108+ exec_with_ssh "start maliit-server"
99 exec_with_ssh "cd $CODE_DIR/ && ./run $ARGS -- $RUN_OPTIONS"
109 exec_with_ssh "cd $CODE_DIR/ && ./run $ARGS -- $RUN_OPTIONS"
110+ exec_with_ssh "stop maliit-server"
100 exec_with_ssh "start unity8"
111 exec_with_ssh "start unity8"
101}
112}
102
113
@@ -130,6 +141,12 @@ if [ "`adb shell 'grep -q Ubuntu /etc/lsb-release 2> /dev/null && echo -n FLIPPE
130 fi
141 fi
131fi
142fi
132
143
144+status_output=$(exec_with_adb initctl status ssh)
145+if [[ $status_output == "ssh start/running, process "* ]]; then
146+ SSH_WAS_STARTED=1
147+fi
148+SSH_STARTED=$SSH_WAS_STARTED
149+
133if $SETUP; then
150if $SETUP; then
134 echo "Setting up environment for building shell.."
151 echo "Setting up environment for building shell.."
135 install_ssh_key
152 install_ssh_key
@@ -144,3 +161,6 @@ else
144 run
161 run
145fi
162fi
146
163
164+if [ $SSH_WAS_STARTED -eq 0 ]; then
165+ exec_with_adb initctl stop ssh
166+fi
tests/autopilot/unity8/process_helpers.pynew file+116
@@ -0,0 +1,116 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Utilities
4+# Copyright (C) 2013 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 autopilot.introspection import (
21+ get_proxy_object_for_existing_process,
22+ ProcessSearchError,
23+)
24+import subprocess
25+from unity8.shell.emulators import UnityEmulatorBase
26+from unity8.shell.emulators.main_window import MainWindow
27+
28+
29+class CannotAccessUnity(Exception):
30+ pass
31+
32+
33+def unlock_unity():
34+ """Helper function that attempts to unlock the unity greeter.
35+
36+ :raises RuntimeError: if the greeter attempts and fails to be unlocked.
37+
38+ :raises RuntimeWarning: when the greeter cannot be found because it is
39+ already unlocked.
40+ :raises CannotAccessUnity: if unity is not introspectable or cannot be
41+ found on dbus.
42+ :raises CannotAccessUnity: if unity's upstart status is not "start" or the
43+ upstart job cannot be found at all.
44+
45+ """
46+ pid = _get_unity_pid()
47+ try:
48+ unity = get_proxy_object_for_existing_process(
49+ pid=pid,
50+ emulator_base=UnityEmulatorBase,
51+ )
52+ main_window = MainWindow(unity)
53+
54+ greeter = main_window.get_greeter()
55+ if greeter is None:
56+ raise RuntimeWarning("Greeter appears to be already unlocked.")
57+ greeter.swipe()
58+ except ProcessSearchError as e:
59+ raise CannotAccessUnity(
60+ "Cannot introspect unity, make sure that it has been started "
61+ "with testability. Perhaps use the function "
62+ "'restart_unity_with_testability' this module provides."
63+ "(%s)"
64+ % str(e)
65+ )
66+
67+
68+def restart_unity_with_testability():
69+ """Restarts (or just starts) unity8 with the testability driver loaded
70+
71+ :raises subprocess.CalledProcessError: if unable to stop or start the
72+ unity8 upstart job.
73+
74+ """
75+ status = _get_unity_status()
76+ if "start/" in status:
77+ try:
78+ print("Stopping unity.")
79+ subprocess.check_call([
80+ 'initctl',
81+ 'stop',
82+ 'unity8',
83+ ])
84+ except subprocess.CalledProcessError as e:
85+ e.args += ("Failed to stop running instance of unity8", )
86+ raise
87+
88+ try:
89+ print("Starting unity with testability.")
90+ subprocess.check_call([
91+ 'initctl',
92+ 'start',
93+ 'unity8',
94+ 'QT_LOAD_TESTABILITY=1',
95+ ])
96+ except subprocess.CalledProcessError as e:
97+ e.args += ("Failed to start unity8 with testability ", )
98+ raise
99+
100+
101+def _get_unity_status():
102+ try:
103+ return subprocess.check_output([
104+ 'initctl',
105+ 'status',
106+ 'unity8'
107+ ])
108+ except subprocess.CalledProcessError as e:
109+ raise CannotAccessUnity("Unable to get unity's status: %s" % str(e))
110+
111+
112+def _get_unity_pid():
113+ status = _get_unity_status()
114+ if not "start/" in status:
115+ raise CannotAccessUnity("Unity is not in the running state.")
116+ return int(status.split()[-1])
tests/autopilot/unity8/shell/emulators/create_interactive_notification.pymode 100755 → 100644

Only the mode changed.

tests/autopilot/unity8/shell/emulators/dash.py+7−17
@@ -18,42 +18,32 @@
18#
18#
19
19
20from unity8.shell.emulators import UnityEmulatorBase
20from unity8.shell.emulators import UnityEmulatorBase
21−from time import sleep
21+
22
22
23class Dash(UnityEmulatorBase):
23class Dash(UnityEmulatorBase):
24
24
25 """An emulator that understands the Dash."""
25 """An emulator that understands the Dash."""
26
26
27 def get_home_applications_grid(self):
27 def get_home_applications_grid(self):
28− for i in range(1,10):
29− get_grid = self.get_scope('home').select_single(
28+ get_grid = self.get_scope('home').wait_select_single(
30− "GenericFilterGrid",
29+ "GenericFilterGrid",
31− objectName="applications.scope"
30+ objectName="applications.scope"
32− )
31+ )
33− if get_grid != None:
34− break
35− sleep(1)
36 return get_grid
32 return get_grid
37
33
38 def get_application_icon(self, text):
34 def get_application_icon(self, text):
39 """Returns a 'Tile' icon that has the text 'text' from the application
35 """Returns a 'Tile' icon that has the text 'text' from the application
40 grid.
36 grid.
41
37
42− Will return None if the icon isn't found.
43−
44 :param text: String containing the text of the icon to search for.
38 :param text: String containing the text of the icon to search for.
45
39
46 """
40 """
47 app_grid = self.get_home_applications_grid()
41 app_grid = self.get_home_applications_grid()
48− for i in range(1,10):
49− resp_grid = app_grid.select_single('ResponsiveGridView')
42+ resp_grid = app_grid.wait_select_single('ResponsiveGridView')
50− if resp_grid != None:
51− break
52− sleep(1)
53 return resp_grid.select_single('Tile', text=text)
43 return resp_grid.select_single('Tile', text=text)
54
44
55 def get_scope(self, scope_name='home'):
45 def get_scope(self, scope_name='home'):
56− dash_content = self.select_single(
46+ dash_content = self.wait_select_single(
57 'QQuickListView',
47 'QQuickListView',
58 objectName='dashContentList'
48 objectName='dashContentList'
59 )
49 )
tests/autopilot/unity8/shell/emulators/hud.py+12−4
@@ -26,6 +26,7 @@ from autopilot.input import Touch
26
26
27SwipeCoords = namedtuple('SwipeCoords', 'start_x end_x start_y end_y')
27SwipeCoords = namedtuple('SwipeCoords', 'start_x end_x start_y end_y')
28
28
29+
29class Hud(UnityEmulatorBase, DragMixin):
30class Hud(UnityEmulatorBase, DragMixin):
30
31
31 """An emulator that understands the Hud."""
32 """An emulator that understands the Hud."""
@@ -34,13 +35,18 @@ class Hud(UnityEmulatorBase, DragMixin):
34 """Swipes open the Hud."""
35 """Swipes open the Hud."""
35 self.touch = Touch.create()
36 self.touch = Touch.create()
36
37
37− window = self.get_root_instance().select_single('QQuickView')
38+ window = self.get_root_instance().wait_select_single('QQuickView')
38− hud_show_button = window.select_single("HudButton")
39+ hud_show_button = window.wait_select_single("HudButton")
39
40
40 swipe_coords = self.get_button_swipe_coords(window, hud_show_button)
41 swipe_coords = self.get_button_swipe_coords(window, hud_show_button)
41
42
42 self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
43 self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
43− self._drag(swipe_coords.start_x, swipe_coords.start_y, swipe_coords.start_x, swipe_coords.end_y)
44+ self._drag(
45+ swipe_coords.start_x,
46+ swipe_coords.start_y,
47+ swipe_coords.start_x,
48+ swipe_coords.end_y
49+ )
44 try:
50 try:
45 hud_show_button.opacity.wait_for(1.0)
51 hud_show_button.opacity.wait_for(1.0)
46 self.touch.release()
52 self.touch.release()
@@ -74,6 +80,8 @@ class Hud(UnityEmulatorBase, DragMixin):
74 start_x = int(main_view.x + (main_view.width / 2))
80 start_x = int(main_view.x + (main_view.width / 2))
75 end_x = start_x
81 end_x = start_x
76 start_y = main_view.y + (main_view.height - 3)
82 start_y = main_view.y + (main_view.height - 3)
83+ end_y = main_view.y + int(
77− end_y = main_view.y + int(hud_show_button.y + (hud_show_button.height/2))
84+ hud_show_button.y + (hud_show_button.height/2)
85+ )
78
86
79 return SwipeCoords(start_x, end_x, start_y, end_y)
87 return SwipeCoords(start_x, end_x, start_y, end_y)
tests/autopilot/unity8/shell/emulators/main_window.py+7−1
@@ -38,11 +38,14 @@ class MainWindow(object):
38 return self.app.select_single(Greeter)
38 return self.app.select_single(Greeter)
39
39
40 def get_greeter_content_loader(self):
40 def get_greeter_content_loader(self):
41− return self.app.select_single(
41+ return self.app.wait_select_single(
42 "QQuickLoader",
42 "QQuickLoader",
43 objectName="greeterContentLoader"
43 objectName="greeterContentLoader"
44 )
44 )
45
45
46+ def get_greeter_background(self):
47+ return self.app.select_single("CrossFadeImage", objectName="greeterBackground")
48+
46 def get_login_loader(self):
49 def get_login_loader(self):
47 return self.app.select_single("QQuickLoader", objectName="loginLoader")
50 return self.app.select_single("QQuickLoader", objectName="loginLoader")
48
51
@@ -93,3 +96,6 @@ class MainWindow(object):
93
96
94 def get_pinentryField(self):
97 def get_pinentryField(self):
95 return self.app.select_single(objectName="pinentryField")
98 return self.app.select_single(objectName="pinentryField")
99+
100+ def get_shell_background(self):
101+ return self.app.select_single("CrossFadeImage", objectName="backgroundImage")
tests/autopilot/unity8/shell/tests/__init__.py+58−27
@@ -34,7 +34,7 @@ import logging
34import os.path
34import os.path
35import subprocess
35import subprocess
36import sys
36import sys
37−from testtools.matchers import Equals, NotEquals
37+from testtools.matchers import Equals
38
38
39from unity8 import (
39from unity8 import (
40 get_lib_path,
40 get_lib_path,
@@ -53,7 +53,7 @@ logger = logging.getLogger(__name__)
53UNITYSHELL_GSETTINGS_SCHEMA = "org.compiz.unityshell"
53UNITYSHELL_GSETTINGS_SCHEMA = "org.compiz.unityshell"
54UNITYSHELL_GSETTINGS_PATH = "/org/compiz/profiles/unity/plugins/unityshell/"
54UNITYSHELL_GSETTINGS_PATH = "/org/compiz/profiles/unity/plugins/unityshell/"
55UNITYSHELL_LAUNCHER_KEY = "launcher-hide-mode"
55UNITYSHELL_LAUNCHER_KEY = "launcher-hide-mode"
56−UNITYSHELL_LAUNCHER_MODE = 1 # launcher hidden
56+UNITYSHELL_LAUNCHER_MODE = 1 # launcher hidden
57
57
58
58
59def _get_device_emulation_scenarios(devices='All'):
59def _get_device_emulation_scenarios(devices='All'):
@@ -93,17 +93,25 @@ class UnityTestCase(AutopilotTestCase):
93 ], stderr=subprocess.STDOUT)
93 ], stderr=subprocess.STDOUT)
94 except subprocess.CalledProcessError, e:
94 except subprocess.CalledProcessError, e:
95 sys.stderr.write(
95 sys.stderr.write(
96− "Error: `initctl status unity8` failed, most probably the unity8 session could not be found:\n\n"
96+ "Error: `initctl status unity8` failed, most probably the "
97+ "unity8 session could not be found:\n\n"
97 "{0}\n"
98 "{0}\n"
98− "Please install unity8 or copy data/unity8.conf to {1}\n".format(
99+ "Please install unity8 or copy data/unity8.conf to "
100+ "{1}\n".format(
99 e.output,
101 e.output,
100− os.path.join(os.getenv("XDG_CONFIG_HOME", os.path.join(os.getenv("HOME"), ".config")), "upstart")
102+ os.path.join(os.getenv("XDG_CONFIG_HOME",
103+ os.path.join(os.getenv("HOME"),
104+ ".config")
105+ ),
106+ "upstart")
101− ))
107+ )
108+ )
102 sys.exit(1)
109 sys.exit(1)
103
110
104 if "start/" in output:
111 if "start/" in output:
105 sys.stderr.write(
112 sys.stderr.write(
106− "Error: Unity is currently running, these tests require it to be 'stopped'.\n"
113+ "Error: Unity is currently running, these tests require it to "
114+ "be 'stopped'.\n"
107 "Please run this command before running these tests: \n"
115 "Please run this command before running these tests: \n"
108 "initctl stop unity8\n"
116 "initctl stop unity8\n"
109 )
117 )
@@ -111,11 +119,22 @@ class UnityTestCase(AutopilotTestCase):
111
119
112 def setUp(self):
120 def setUp(self):
113 super(UnityTestCase, self).setUp()
121 super(UnityTestCase, self).setUp()
122+ if (Gio is not None and
123+ UNITYSHELL_GSETTINGS_SCHEMA in
114− if Gio is not None and UNITYSHELL_GSETTINGS_SCHEMA in Gio.Settings.list_relocatable_schemas():
124+ Gio.Settings.list_relocatable_schemas()):
125+
115 # Hide Unity launcher
126 # Hide Unity launcher
116− self._unityshell_schema = Gio.Settings.new_with_path(UNITYSHELL_GSETTINGS_SCHEMA, UNITYSHELL_GSETTINGS_PATH)
127+ self._unityshell_schema = Gio.Settings.new_with_path(
128+ UNITYSHELL_GSETTINGS_SCHEMA,
129+ UNITYSHELL_GSETTINGS_PATH,
130+ )
117− self._launcher_hide_mode = self._unityshell_schema.get_int(UNITYSHELL_LAUNCHER_KEY)
131+ self._launcher_hide_mode = self._unityshell_schema.get_int(
132+ UNITYSHELL_LAUNCHER_KEY,
133+ )
118− self._unityshell_schema.set_int(UNITYSHELL_LAUNCHER_KEY, UNITYSHELL_LAUNCHER_MODE)
134+ self._unityshell_schema.set_int(
135+ UNITYSHELL_LAUNCHER_KEY,
136+ UNITYSHELL_LAUNCHER_MODE,
137+ )
119 self.addCleanup(self._reset_launcher)
138 self.addCleanup(self._reset_launcher)
120
139
121 self._proxy = None
140 self._proxy = None
@@ -136,7 +155,10 @@ class UnityTestCase(AutopilotTestCase):
136
155
137 def _reset_launcher(self):
156 def _reset_launcher(self):
138 """Reset Unity launcher hide mode"""
157 """Reset Unity launcher hide mode"""
139− self._unityshell_schema.set_int(UNITYSHELL_LAUNCHER_KEY, self._launcher_hide_mode)
158+ self._unityshell_schema.set_int(
159+ UNITYSHELL_LAUNCHER_KEY,
160+ self._launcher_hide_mode,
161+ )
140
162
141 def _setup_display_details(self):
163 def _setup_display_details(self):
142 scale_divisor = self._determine_geometry()
164 scale_divisor = self._determine_geometry()
@@ -217,7 +239,10 @@ class UnityTestCase(AutopilotTestCase):
217 def _upstart_reset_env(self, key, value):
239 def _upstart_reset_env(self, key, value):
218 logger.info("Resetting upstart env %s to %s", key, value)
240 logger.info("Resetting upstart env %s to %s", key, value)
219 if value is None:
241 if value is None:
242+ subprocess.call(
220− subprocess.call(["/sbin/initctl", "unset-env", key], stderr=subprocess.STDOUT)
243+ ["/sbin/initctl", "unset-env", key],
244+ stderr=subprocess.STDOUT,
245+ )
221 else:
246 else:
222 subprocess.call([
247 subprocess.call([
223 "/sbin/initctl",
248 "/sbin/initctl",
@@ -244,9 +269,13 @@ class UnityTestCase(AutopilotTestCase):
244 self._setup_extra_mock_environment_patch()
269 self._setup_extra_mock_environment_patch()
245
270
246 # FIXME: we shouldn't be doing this
271 # FIXME: we shouldn't be doing this
247− # $MIR_SOCKET, fallback to $XDG_RUNTIME_DIR/mir_socket and /tmp/mir_socket as last resort
272+ # $MIR_SOCKET, fallback to $XDG_RUNTIME_DIR/mir_socket and
273+ # /tmp/mir_socket as last resort
248 try:
274 try:
275+ os.unlink(
276+ os.getenv('MIR_SOCKET',
249− os.unlink(os.getenv('MIR_SOCKET', os.path.join(os.getenv('XDG_RUNTIME_DIR', "/tmp"), "mir_socket")))
277+ os.path.join(os.getenv('XDG_RUNTIME_DIR', "/tmp"),
278+ "mir_socket")))
250 except OSError:
279 except OSError:
251 pass
280 pass
252 try:
281 try:
@@ -256,7 +285,7 @@ class UnityTestCase(AutopilotTestCase):
256
285
257 app_proxy = self._launch_unity_with_upstart(
286 app_proxy = self._launch_unity_with_upstart(
258 binary_path,
287 binary_path,
259− self.unity_geometry_args
288+ self.unity_geometry_args,
260 )
289 )
261
290
262 self._set_proxy(app_proxy)
291 self._set_proxy(app_proxy)
@@ -275,14 +304,16 @@ class UnityTestCase(AutopilotTestCase):
275 binary_arg = "BINARY=%s" % binary_path
304 binary_arg = "BINARY=%s" % binary_path
276 extra_args = "ARGS=%s" % " ".join(args)
305 extra_args = "ARGS=%s" % " ".join(args)
277
306
278− output = subprocess.check_output([
307+ output = subprocess.check_output(
308+ [
279− "/sbin/initctl",
309+ "/sbin/initctl",
280− "start",
310+ "start",
281− "unity8",
311+ "unity8",
282− binary_arg,
312+ binary_arg,
283− extra_args
313+ extra_args,
284− ] + ["%s=%s" % (k,v) for k,v in self._environment.iteritems()],
314+ ] + ["%s=%s" % (k, v) for k, v in self._environment.iteritems()],
285− stderr=subprocess.STDOUT)
315+ stderr=subprocess.STDOUT,
316+ )
286
317
287 self.addCleanup(self._cleanup_launching_upstart_unity)
318 self.addCleanup(self._cleanup_launching_upstart_unity)
288
319
@@ -296,7 +327,8 @@ class UnityTestCase(AutopilotTestCase):
296 def _cleanup_launching_upstart_unity(self):
327 def _cleanup_launching_upstart_unity(self):
297 logger.info("Stopping unity")
328 logger.info("Stopping unity")
298 try:
329 try:
330+ subprocess.check_output(
299− subprocess.check_output(["/sbin/initctl", "stop", "unity8"], stderr=subprocess.STDOUT)
331+ ["/sbin/initctl", "stop", "unity8"], stderr=subprocess.STDOUT)
300 except subprocess.CalledProcessError:
332 except subprocess.CalledProcessError:
301 logger.warning("Appears unity was already stopped!")
333 logger.warning("Appears unity was already stopped!")
302
334
@@ -366,8 +398,7 @@ class UnityTestCase(AutopilotTestCase):
366 self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
398 self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
367
399
368 def get_dash(self):
400 def get_dash(self):
369− dash = self._proxy.select_single(Dash)
401+ dash = self._proxy.wait_select_single(Dash)
370− self.assertThat(dash, NotEquals(None))
371 return dash
402 return dash
372
403
373 @property
404 @property
tests/autopilot/unity8/shell/tests/test_greeter.pynew file+38
@@ -0,0 +1,38 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 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.shell.tests import UnityTestCase, _get_device_emulation_scenarios
21+
22+from testtools.matchers import Equals
23+
24+class TestGreeter(UnityTestCase):
25+
26+ """Tests the Shell Greeter."""
27+
28+ scenarios = _get_device_emulation_scenarios()
29+
30+ def test_greeter_background(self):
31+ """Test that the background of the greeter and the background of the shell are placed correctly
32+
33+ """
34+ self.launch_unity()
35+ self.main_window.get_greeter()
36+ greeter_background = self.main_window.get_greeter_background()
37+ shell_background = self.main_window.get_shell_background()
38+ self.assertThat(greeter_background.globalRect, Equals(shell_background.globalRect))
tests/autopilot/unity8/shell/tests/test_notifications.py+49−42
@@ -45,7 +45,7 @@ class NotificationsBase(UnityTestCase):
45 """Given an icons file name returns the full path (either system or
45 """Given an icons file name returns the full path (either system or
46 source tree.
46 source tree.
47
47
48− Consider the graphics directory as root so for example (runnign tests
48+ Consider the graphics directory as root so for example (running tests
49 from installed unity8-autopilot package):
49 from installed unity8-autopilot package):
50 >>> self.get_icon_path('clock.png')
50 >>> self.get_icon_path('clock.png')
51 /usr/share/unity8/graphics/clock.png
51 /usr/share/unity8/graphics/clock.png
@@ -145,8 +145,8 @@ class InteractiveNotificationBase(NotificationsBase):
145 hints,
145 hints,
146 )
146 )
147
147
148+ get_notification = lambda: notify_list.wait_select_single(
148− get_notification = lambda: notify_list.select_single('Notification', objectName='notification1')
149+ 'Notification', objectName='notification1')
149− self.assertThat(get_notification, Eventually(NotEquals(None)))
150 notification = get_notification()
150 notification = get_notification()
151
151
152 self.touch.tap_object(
152 self.touch.tap_object(
@@ -156,7 +156,8 @@ class InteractiveNotificationBase(NotificationsBase):
156 self.assert_notification_action_id_was_called('action_id')
156 self.assert_notification_action_id_was_called('action_id')
157
157
158 def test_sd_incoming_call(self):
158 def test_sd_incoming_call(self):
159− """Rejecting a call should make notification expand and offer more options."""
159+ """Rejecting a call should make notification expand and
160+ offer more options."""
160 self.launch_unity()
161 self.launch_unity()
161 greeter = self.main_window.get_greeter()
162 greeter = self.main_window.get_greeter()
162 greeter.swipe()
163 greeter.swipe()
@@ -191,8 +192,8 @@ class InteractiveNotificationBase(NotificationsBase):
191 hints
192 hints
192 )
193 )
193
194
195+ get_notification = lambda: notify_list.wait_select_single(
194− get_notification = lambda: notify_list.select_single('Notification', objectName='notification1')
196+ 'Notification', objectName='notification1')
195− self.assertThat(get_notification, Eventually(NotEquals(None)))
196 notification = get_notification()
197 notification = get_notification()
197 self._assert_notification(notification, None, None, True, True, 1.0)
198 self._assert_notification(notification, None, None, True, True, 1.0)
198 initial_height = notification.height
199 initial_height = notification.height
@@ -200,8 +201,10 @@ class InteractiveNotificationBase(NotificationsBase):
200 self.assertThat(
201 self.assertThat(
201 notification.height,
202 notification.height,
202 Eventually(Equals(initial_height +
203 Eventually(Equals(initial_height +
204+ 3 * notification.select_single(
203− 3 * notification.select_single(objectName="buttonColumn").spacing +
205+ objectName="buttonColumn").spacing +
204− 3 * notification.select_single(objectName="button4").height)))
206+ 3 * notification.select_single(
207+ objectName="button4").height)))
205 self.touch.tap_object(notification.select_single(objectName="button4"))
208 self.touch.tap_object(notification.select_single(objectName="button4"))
206 self.assert_notification_action_id_was_called("action_decline_4")
209 self.assert_notification_action_id_was_called("action_decline_4")
207
210
@@ -360,13 +363,20 @@ class EphemeralNotificationsTests(NotificationsBase):
360
363
361 notification.show()
364 notification.show()
362
365
366+ notification = lambda: notify_list.wait_select_single(
363− get_notification = lambda: notify_list.select_single('Notification', objectName='notification1')
367+ 'Notification', objectName='notification1')
364− self.assertThat(get_notification, Eventually(NotEquals(None)))
365− notification = get_notification()
366− self._assert_notification(notification, summary, body, True, True, 1.0)
368+ self._assert_notification(
369+ notification(),
370+ summary,
371+ body,
372+ True,
373+ True,
374+ 1.0,
375+ )
367
376
368 def test_icon_summary(self):
377 def test_icon_summary(self):
369− """Notification must display the expected summary and secondary icon."""
378+ """Notification must display the expected summary and secondary
379+ icon."""
370 self.launch_unity()
380 self.launch_unity()
371 greeter = self.main_window.get_greeter()
381 greeter = self.main_window.get_greeter()
372 greeter.swipe()
382 greeter.swipe()
@@ -391,11 +401,11 @@ class EphemeralNotificationsTests(NotificationsBase):
391
401
392 notification.show()
402 notification.show()
393
403
404+ notification = lambda: notify_list.wait_select_single(
394− get_notification = lambda: notify_list.select_single('Notification', objectName='notification1')
405+ 'Notification', objectName='notification1')
395− self.assertThat(get_notification, Eventually(NotEquals(None)))
406+
396− notification = get_notification()
397 self._assert_notification(
407 self._assert_notification(
398− notification,
408+ notification(),
399 summary,
409 summary,
400 None,
410 None,
401 False,
411 False,
@@ -404,7 +414,8 @@ class EphemeralNotificationsTests(NotificationsBase):
404 )
414 )
405
415
406 def test_urgency_order(self):
416 def test_urgency_order(self):
407− """Notifications must be displayed in order according to their urgency."""
417+ """Notifications must be displayed in order according to their
418+ urgency."""
408 self.launch_unity()
419 self.launch_unity()
409 greeter = self.main_window.get_greeter()
420 greeter = self.main_window.get_greeter()
410 greeter.swipe()
421 greeter.swipe()
@@ -448,11 +459,10 @@ class EphemeralNotificationsTests(NotificationsBase):
448 )
459 )
449 notification_critical.show()
460 notification_critical.show()
450
461
451− get_notification = lambda: notify_list.select_single(
462+ get_notification = lambda: notify_list.wait_select_single(
452 'Notification',
463 'Notification',
453 summary=summary_critical
464 summary=summary_critical
454 )
465 )
455− self.assertThat(get_notification, Eventually(NotEquals(None)))
456
466
457 notification = get_notification()
467 notification = get_notification()
458 self._assert_notification(
468 self._assert_notification(
@@ -464,11 +474,10 @@ class EphemeralNotificationsTests(NotificationsBase):
464 1.0
474 1.0
465 )
475 )
466
476
467− get_normal_notification = lambda: notify_list.select_single(
477+ get_normal_notification = lambda: notify_list.wait_select_single(
468 'Notification',
478 'Notification',
469 summary=summary_normal
479 summary=summary_normal
470 )
480 )
471− self.assertThat(get_normal_notification, Eventually(NotEquals(None)))
472 notification = get_normal_notification()
481 notification = get_normal_notification()
473 self._assert_notification(
482 self._assert_notification(
474 notification,
483 notification,
@@ -479,11 +488,10 @@ class EphemeralNotificationsTests(NotificationsBase):
479 1.0
488 1.0
480 )
489 )
481
490
482− get_low_notification = lambda: notify_list.select_single(
491+ get_low_notification = lambda: notify_list.wait_select_single(
483 'Notification',
492 'Notification',
484 summary=summary_low
493 summary=summary_low
485 )
494 )
486− self.assertThat(get_low_notification, Eventually(NotEquals(None)))
487 notification = get_low_notification()
495 notification = get_low_notification()
488 self._assert_notification(
496 self._assert_notification(
489 notification,
497 notification,
@@ -508,9 +516,8 @@ class EphemeralNotificationsTests(NotificationsBase):
508 notification = self._create_ephemeral_notification(summary, body)
516 notification = self._create_ephemeral_notification(summary, body)
509 notification.show()
517 notification.show()
510
518
519+ notification = notify_list.wait_select_single(
511− get_notification = lambda: notify_list.select_single('Notification', objectName='notification1')
520+ 'Notification', objectName='notification1')
512− self.assertThat(get_notification, Eventually(NotEquals(None)))
513− notification = get_notification()
514 self._assert_notification(
521 self._assert_notification(
515 notification,
522 notification,
516 summary,
523 summary,
@@ -533,14 +540,14 @@ class EphemeralNotificationsTests(NotificationsBase):
533 notification = self._create_ephemeral_notification(summary)
540 notification = self._create_ephemeral_notification(summary)
534 notification.show()
541 notification.show()
535
542
543+ notification = notify_list.wait_select_single(
536− get_notification = lambda: notify_list.select_single('Notification', objectName='notification1')
544+ 'Notification', objectName='notification1')
537− self.assertThat(get_notification, Eventually(NotEquals(None)))
538− notification = get_notification()
539
545
540 self._assert_notification(notification, summary, '', False, False, 1.0)
546 self._assert_notification(notification, summary, '', False, False, 1.0)
541
547
542 def test_update_notification_same_layout(self):
548 def test_update_notification_same_layout(self):
543− """Notification must allow updating its contents while being displayed."""
549+ """Notification must allow updating its contents while being
550+ displayed."""
544 self.launch_unity()
551 self.launch_unity()
545 greeter = self.main_window.get_greeter()
552 greeter = self.main_window.get_greeter()
546 greeter.swipe()
553 greeter.swipe()
@@ -558,8 +565,8 @@ class EphemeralNotificationsTests(NotificationsBase):
558 )
565 )
559 notification.show()
566 notification.show()
560
567
561− get_notification = lambda: notify_list.select_single('Notification', summary=summary)
568+ get_notification = lambda: notify_list.wait_select_single(
562− self.assertThat(get_notification, Eventually(NotEquals(None)))
569+ 'Notification', summary=summary)
563 self._assert_notification(
570 self._assert_notification(
564 get_notification(),
571 get_notification(),
565 summary,
572 summary,
@@ -575,11 +582,11 @@ class EphemeralNotificationsTests(NotificationsBase):
575 icon_path = self._get_icon_path('avatars/amanda.png')
582 icon_path = self._get_icon_path('avatars/amanda.png')
576 notification.update(summary, body, icon_path)
583 notification.update(summary, body, icon_path)
577 notification.show()
584 notification.show()
578− self.assertThat(get_notification, Eventually(NotEquals(None)))
579 self._assert_notification(get_notification(), summary, body)
585 self._assert_notification(get_notification(), summary, body)
580
586
581 def test_update_notification_layout_change(self):
587 def test_update_notification_layout_change(self):
582− """Notification must allow updating its contents and layout while being displayed."""
588+ """Notification must allow updating its contents and layout while
589+ being displayed."""
583 self.launch_unity()
590 self.launch_unity()
584 greeter = self.main_window.get_greeter()
591 greeter = self.main_window.get_greeter()
585 greeter.swipe()
592 greeter.swipe()
@@ -603,8 +610,8 @@ class EphemeralNotificationsTests(NotificationsBase):
603 )
610 )
604 notification.show()
611 notification.show()
605
612
613+ get_notification = lambda: notify_list.wait_select_single(
606− get_notification = lambda: notify_list.select_single('Notification', objectName='notification1')
614+ 'Notification', objectName='notification1')
607− self.assertThat(get_notification, Eventually(NotEquals(None)))
608 self._assert_notification(
615 self._assert_notification(
609 get_notification(),
616 get_notification(),
610 summary,
617 summary,
@@ -645,8 +652,8 @@ class EphemeralNotificationsTests(NotificationsBase):
645
652
646 notification.show()
653 notification.show()
647
654
655+ get_notification = lambda: notify_list.wait_select_single(
648− get_notification = lambda: notify_list.select_single('Notification', objectName='notification1')
656+ 'Notification', objectName='notification1')
649− self.assertThat(get_notification, Eventually(NotEquals(None)))
650 notification = get_notification()
657 notification = get_notification()
651 self._assert_notification(
658 self._assert_notification(
652 notification,
659 notification,
@@ -662,7 +669,8 @@ class EphemeralNotificationsTests(NotificationsBase):
662 'Did you watch the air-race in Oshkosh last week?',
669 'Did you watch the air-race in Oshkosh last week?',
663 'Phil owned the place like no one before him!',
670 'Phil owned the place like no one before him!',
664 'Did really everything in the race work according to regulations?',
671 'Did really everything in the race work according to regulations?',
665− 'Somehow I think to remember Burt Williams did cut corners and was not punished for this.',
672+ 'Somehow I think to remember Burt Williams did cut corners and '
673+ 'was not punished for this.',
666 'Hopefully the referees will watch the videos of the race.',
674 'Hopefully the referees will watch the videos of the race.',
667 'Burt could get fined with US$ 50000 for that rule-violation :)'
675 'Burt could get fined with US$ 50000 for that rule-violation :)'
668 ]
676 ]
@@ -677,11 +685,10 @@ class EphemeralNotificationsTests(NotificationsBase):
677 hints=[('x-canonical-append', 'true')]
685 hints=[('x-canonical-append', 'true')]
678 )
686 )
679 notification.show()
687 notification.show()
680− get_notification = lambda: notify_list.select_single(
688+ get_notification = lambda: notify_list.wait_select_single(
681 'Notification',
689 'Notification',
682 objectName='notification1'
690 objectName='notification1'
683 )
691 )
684− self.assertThat(get_notification, Eventually(NotEquals(None)))
685 notification = get_notification()
692 notification = get_notification()
686 self._assert_notification(
693 self._assert_notification(
687 notification,
694 notification,
tests/mocks/QMenuModel/CMakeLists.txt+23
@@ -9,3 +9,26 @@ add_custom_target(QMenuModelQmlFiles ALL
9 COMMAND cp ${QMLFILES} ${CMAKE_CURRENT_BINARY_DIR}
9 COMMAND cp ${QMLFILES} ${CMAKE_CURRENT_BINARY_DIR}
10 DEPENDS ${QMLFILES}
10 DEPENDS ${QMLFILES}
11)
11)
12+
13+include_directories(
14+ ${Qt5Core_INCLUDE_DIRS}
15+ ${Qt5Quick_INCLUDE_DIRS}
16+)
17+
18+set(QMenuModelQml_SOURCES
19+ actionstateparser.cpp
20+ plugin.cpp
21+ unitymenumodel.cpp
22+)
23+
24+add_library(QMenuModelQml SHARED ${QMenuModelQml_SOURCES})
25+target_link_libraries(QMenuModelQml
26+ ${Qt5Core_LIBRARIES}
27+ ${Qt5Quick_LIBRARIES}
28+)
29+
30+qt5_use_modules(QMenuModelQml Core Quick)
31+
32+set_target_properties(QMenuModelQml PROPERTIES
33+ OUTPUT_NAME qmenumodel
34+ VERSION 0)
tests/mocks/QMenuModel/UnityMenuAction.qmlnew file+30
@@ -0,0 +1,30 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import QMenuModel 0.1
22+
23+QtObject {
24+ property string name
25+ property UnityMenuModel model
26+ property int index
27+
28+ readonly property var state: undefined
29+ readonly property bool valid: false
30+}
tests/mocks/QMenuModel/actionstateparser.cppnew file+19
@@ -0,0 +1,19 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+#include "actionstateparser.h"
tests/mocks/QMenuModel/actionstateparser.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+#ifndef MOCK_ACTIONSTATEPARSER_H
20+#define MOCK_ACTIONSTATEPARSER_H
21+
22+#include <QObject>
23+#include <QVariant>
24+
25+typedef struct _GVariant GVariant;
26+
27+class Q_DECL_EXPORT ActionStateParser : public QObject
28+{
29+ Q_OBJECT
30+public:
31+ ActionStateParser(QObject* parent = 0):QObject(parent) {}
32+ virtual QVariant toQVariant(GVariant*) const { return QVariant(); }
33+};
34+
35+#endif // MOCK_ACTIONSTATEPARSER_H
tests/mocks/QMenuModel/plugin.cppnew file+30
@@ -0,0 +1,30 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+#include "plugin.h"
20+#include "unitymenumodel.h"
21+#include "actionstateparser.h"
22+
23+#include <QtQml>
24+
25+void QMenuModelPlugin::registerTypes(const char *uri)
26+{
27+ Q_ASSERT(uri == QLatin1String("QMenuModel"));
28+ qmlRegisterType<UnityMenuModel>(uri, 0, 1, "UnityMenuModel");
29+ qmlRegisterType<ActionStateParser>(uri, 0, 1, "ActionStateParser");
30+}
tests/mocks/QMenuModel/plugin.hnew file+34
@@ -0,0 +1,34 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+#ifndef MOCK_QMENUMODEL_PLUGIN_H
20+#define MOCK_QMENUMODEL_PLUGIN_H
21+
22+#include <QQmlEngine>
23+#include <QQmlExtensionPlugin>
24+
25+class QMenuModelPlugin : public QQmlExtensionPlugin
26+{
27+ Q_OBJECT
28+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
29+
30+public:
31+ void registerTypes(const char *uri);
32+};
33+
34+#endif
tests/mocks/QMenuModel/qmldir+3−1
@@ -1,3 +1,5 @@
1module QMenuModel
1module QMenuModel
2+plugin qmenumodel
3+
2QDBusActionGroup 0.1 QDBusActionGroup.qml
4QDBusActionGroup 0.1 QDBusActionGroup.qml
3−UnityMenuModel 0.1 UnityMenuModel.qml
5+UnityMenuAction 0.1 UnityMenuAction.qml
tests/mocks/QMenuModel/unitymenumodel.cppnew file+239
@@ -0,0 +1,239 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+#include "unitymenumodel.h"
20+#include <QDebug>
21+
22+enum MenuRoles {
23+ LabelRole = Qt::DisplayRole + 1,
24+ SensitiveRole,
25+ IsSeparatorRole,
26+ IconRole,
27+ TypeRole,
28+ ExtendedAttributesRole,
29+ ActionRole,
30+ ActionStateRole,
31+ IsCheckRole,
32+ IsRadioRole,
33+ IsToggledRole
34+};
35+
36+UnityMenuModel::UnityMenuModel(QObject *parent)
37+: QAbstractListModel(parent)
38+{
39+}
40+
41+QVariant UnityMenuModel::modelData() const
42+{
43+ return m_modelData;
44+}
45+
46+void UnityMenuModel::setModelData(const QVariant& data)
47+{
48+ beginResetModel();
49+
50+ m_modelData.clear();
51+ m_modelData = data.toList();
52+
53+ endResetModel();
54+}
55+
56+
57+void UnityMenuModel::insertRow(int row, const QVariant& data)
58+{
59+ row = qMin(row, rowCount());
60+
61+ beginInsertRows(QModelIndex(), row, row);
62+
63+ m_modelData.insert(row, data);
64+
65+ endInsertRows();
66+}
67+
68+void UnityMenuModel::appendRow(const QVariant& data)
69+{
70+ insertRow(rowCount(), data);
71+}
72+
73+void UnityMenuModel::removeRow(int row)
74+{
75+ if (row < 0 || rowCount() <= row) {
76+ return;
77+ }
78+
79+ beginRemoveRows(QModelIndex(), row, row);
80+
81+ m_modelData.removeAt(row);
82+
83+ endRemoveRows();
84+}
85+
86+UnityMenuModel::~UnityMenuModel()
87+{
88+}
89+
90+QByteArray UnityMenuModel::busName() const
91+{
92+ return m_busName;
93+}
94+
95+void UnityMenuModel::setBusName(const QByteArray &busName)
96+{
97+ this->m_busName = busName;
98+}
99+
100+QVariantMap UnityMenuModel::actions() const
101+{
102+ return m_actions;
103+}
104+
105+void UnityMenuModel::setActions(const QVariantMap &actions)
106+{
107+ this->m_actions = actions;
108+}
109+
110+QByteArray UnityMenuModel::menuObjectPath() const
111+{
112+ return m_menuObjectPath;
113+}
114+
115+void UnityMenuModel::setMenuObjectPath(const QByteArray &path)
116+{
117+ this->m_menuObjectPath = path;
118+}
119+
120+ActionStateParser* UnityMenuModel::actionStateParser() const
121+{
122+ return NULL;
123+}
124+
125+void UnityMenuModel::setActionStateParser(ActionStateParser*)
126+{
127+}
128+
129+int UnityMenuModel::rowCount(const QModelIndex&) const
130+{
131+ return m_modelData.count();
132+}
133+
134+int UnityMenuModel::columnCount(const QModelIndex&) const
135+{
136+ return 1;
137+}
138+
139+QVariant UnityMenuModel::data(const QModelIndex &index, int role) const
140+{
141+ return rowData(index.row())[roleNames()[role]];
142+}
143+
144+QVariantMap UnityMenuModel::rowData(int row) const
145+{
146+ return m_modelData[row].toMap()["rowData"].toMap();
147+}
148+
149+QVariant UnityMenuModel::subMenuData(int row) const
150+{
151+ return m_modelData[row].toMap()["submenu"];
152+}
153+
154+QModelIndex UnityMenuModel::index(int row, int column, const QModelIndex&) const
155+{
156+ return createIndex(row, column);
157+}
158+
159+QModelIndex UnityMenuModel::parent(const QModelIndex &) const
160+{
161+ return QModelIndex();
162+}
163+
164+QHash<int, QByteArray> UnityMenuModel::roleNames() const
165+{
166+ QHash<int, QByteArray> names;
167+
168+ names[LabelRole] = "label";
169+ names[SensitiveRole] = "sensitive";
170+ names[IsSeparatorRole] = "isSeparator";
171+ names[IconRole] = "icon";
172+ names[TypeRole] = "type";
173+ names[ExtendedAttributesRole] = "ext";
174+ names[ActionRole] = "action";
175+ names[ActionStateRole] = "actionState";
176+ names[IsCheckRole] = "isCheck";
177+ names[IsRadioRole] = "isRadio";
178+ names[IsToggledRole] = "isToggled";
179+
180+ return names;
181+}
182+
183+QObject * UnityMenuModel::submenu(int position, QQmlComponent*)
184+{
185+ if (position < 0 || m_modelData.count() < position) {
186+ return NULL;
187+ }
188+
189+ while (submenus.count() <= position) {
190+ submenus.append(NULL);
191+ }
192+
193+ QVariant submenuData = subMenuData(position);
194+ if (submenuData.type() == (int)QMetaType::QVariantList) {
195+ UnityMenuModel*& model = submenus[position];
196+ if (!model) {
197+ model = new UnityMenuModel(this);
198+ }
199+ if (model->modelData() != submenuData) {
200+ model->setModelData(submenuData);
201+ }
202+ return model;
203+ }
204+
205+ return NULL;
206+}
207+
208+bool UnityMenuModel::loadExtendedAttributes(int, const QVariantMap &)
209+{
210+ return false;
211+}
212+
213+QVariant UnityMenuModel::get(int row, const QByteArray &role)
214+{
215+ static QHash<QByteArray, int> roles;
216+ if (roles.isEmpty()) {
217+ QHash<int, QByteArray> names = roleNames();
218+ Q_FOREACH (int role, names.keys())
219+ roles.insert(names[role], role);
220+ }
221+
222+ return this->data(this->index(row, 0), roles[role]);
223+}
224+
225+void UnityMenuModel::activate(int, const QVariant&)
226+{
227+}
228+
229+void UnityMenuModel::changeState(int, const QVariant&)
230+{
231+}
232+
233+void UnityMenuModel::registerAction(UnityMenuAction*)
234+{
235+}
236+
237+void UnityMenuModel::unregisterAction(UnityMenuAction*)
238+{
239+}
tests/mocks/QMenuModel/unitymenumodel.hnew file+96
@@ -0,0 +1,96 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+#ifndef MOCK_UNITYMENUMODEL_H
20+#define MOCK_UNITYMENUMODEL_H
21+
22+#include <QAbstractListModel>
23+class QQmlComponent;
24+class UnityMenuAction;
25+class ActionStateParser;
26+
27+class Q_DECL_EXPORT UnityMenuModel : public QAbstractListModel
28+{
29+ Q_OBJECT
30+ Q_PROPERTY(QVariant modelData READ modelData WRITE setModelData NOTIFY modelDataChanged)
31+ Q_PROPERTY(QByteArray busName READ busName WRITE setBusName NOTIFY busNameChanged)
32+ Q_PROPERTY(QVariantMap actions READ actions WRITE setActions NOTIFY actionsChanged)
33+ Q_PROPERTY(QByteArray menuObjectPath READ menuObjectPath WRITE setMenuObjectPath NOTIFY menuObjectPathChanged)
34+ Q_PROPERTY(ActionStateParser* actionStateParser READ actionStateParser WRITE setActionStateParser NOTIFY actionStateParserChanged)
35+
36+public:
37+ UnityMenuModel(QObject *parent = NULL);
38+ virtual ~UnityMenuModel();
39+
40+ Q_INVOKABLE void insertRow(int row, const QVariant& data);
41+ Q_INVOKABLE void appendRow(const QVariant& data);
42+ Q_INVOKABLE void removeRow(int row);
43+
44+ QVariant modelData() const;
45+ void setModelData(const QVariant& data);
46+
47+ QByteArray busName() const;
48+ void setBusName(const QByteArray &busName);
49+
50+ QVariantMap actions() const;
51+ void setActions(const QVariantMap &actions);
52+
53+ QByteArray menuObjectPath() const;
54+ void setMenuObjectPath(const QByteArray &path);
55+
56+ ActionStateParser* actionStateParser() const;
57+ void setActionStateParser(ActionStateParser* actionStateParser);
58+
59+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
60+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
61+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
62+ QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const;
63+ QModelIndex parent(const QModelIndex &index) const;
64+ QHash<int, QByteArray> roleNames() const;
65+
66+ Q_INVOKABLE QObject * submenu(int position, QQmlComponent* actionStateParser = NULL);
67+ Q_INVOKABLE bool loadExtendedAttributes(int position, const QVariantMap &schema);
68+ Q_INVOKABLE QVariant get(int row, const QByteArray &role);
69+
70+ Q_INVOKABLE void activate(int index, const QVariant& parameter = QVariant());
71+ Q_INVOKABLE void changeState(int index, const QVariant& parameter);
72+
73+ void registerAction(UnityMenuAction* action);
74+ void unregisterAction(UnityMenuAction* action);
75+
76+Q_SIGNALS:
77+ void busNameChanged();
78+ void actionsChanged();
79+ void menuObjectPathChanged();
80+ void actionStateParserChanged();
81+ void modelDataChanged();
82+
83+private:
84+ QVariantMap rowData(int row) const;
85+ QVariant subMenuData(int row) const;
86+
87+ class Row;
88+ QVariantList m_modelData;
89+ QList<UnityMenuModel*> submenus;
90+
91+ QByteArray m_busName;
92+ QVariantMap m_actions;
93+ QByteArray m_menuObjectPath;
94+};
95+
96+#endif // MOCK_UNITYMENUMODEL_H
tests/mocks/Unity/Indicators/IndicatorBase.qmlnew file+37
@@ -0,0 +1,37 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import QMenuModel 0.1
22+
23+Item {
24+ id: indicatorBase
25+
26+ //const
27+ property string busName
28+ property string actionsObjectPath
29+ property string rootMenuType: "com.canonical.indicator.root"
30+ property string deviceMenuObjectPath
31+
32+ property var menuModel: UnityMenuModel {}
33+
34+ property RootActionState rootActionState: RootActionState {
35+ onUpdated: indicatorBase.rootActionStateChanged()
36+ }
37+}
plugins/Unity/Indicators/Messaging/qml/utils.js → tests/mocks/Unity/Indicators/IndicatorWidget.qmlrenamed+8−7
@@ -14,14 +14,15 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
15 *
16 * Authors:
16 * Authors:
17− * Renato Araujo Oliveira Filho <renato@canonical.com>
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18− * Olivier Tilloy <olivier.tilloy@canonical.com>
19 */
18 */
20
19
21−.pragma library
20+import QtQuick 2.0
21+import Unity.Indicators 0.1 as Indicators
22
22
23−function formatDate(timestamp) {
23+IndicatorBase {
24− // timestamp is in microseconds since epoch
24+ id: indicatorWidget
25− var date = new Date(timestamp / 1000);
25+
26− return Qt.formatDateTime(date, "hh:mm - MMM dd");
26+ enabled: false
27+ property int iconSize: height
27}
28}
tests/mocks/Unity/Indicators/RootActionState.qml+17−9
@@ -20,14 +20,22 @@
20import QtQuick 2.0
20import QtQuick 2.0
21
21
22QtObject {
22QtObject {
23− property var menu
23+ property var menu
24− property bool valid: false
24+ property bool valid: false
25− property string title
25+ property string title
26− property string leftLabel
26+ property string leftLabel
27− property string rightLabel
27+ property string rightLabel
28− property var icons
28+ property var icons
29− property string accessibleName
29+ property string accessibleName
30− property bool visible: true
30+ property bool visible: true
31
31
32− signal updated
32+ signal updated
33+
34+ onValidChanged: updated()
35+ onTitleChanged: updated()
36+ onLeftLabelChanged: updated()
37+ onRightLabelChanged: updated()
38+ onIconsChanged: updated()
39+ onAccessibleNameChanged: updated()
40+ onVisibleChanged: updated()
33}
41}
tests/mocks/Unity/Indicators/qmldir+2
@@ -2,6 +2,8 @@ module Unity.Indicators
2plugin IndicatorsFakeQml
2plugin IndicatorsFakeQml
3
3
4CachedUnityMenuModel 0.1 CachedUnityMenuModel.qml
4CachedUnityMenuModel 0.1 CachedUnityMenuModel.qml
5+IndicatorBase 0.1 IndicatorBase.qml
6+IndicatorWidget 0.1 IndicatorWidget.qml
5IndicatorsModel 0.1 IndicatorsModel.qml
7IndicatorsModel 0.1 IndicatorsModel.qml
6FakeMenuPage 0.1 FakeMenuPage.qml
8FakeMenuPage 0.1 FakeMenuPage.qml
7RootActionState 0.1 RootActionState.qml
9RootActionState 0.1 RootActionState.qml
tests/mocks/Unity/fake_preview.cpp+9−1
@@ -16,9 +16,13 @@
16
16
17#include "fake_preview.h"
17#include "fake_preview.h"
18
18
19+Preview::Preview(QObject *parent): QObject(parent)
20+{
21+}
22+
19QString Preview::rendererName() const
23QString Preview::rendererName() const
20{
24{
21− return "foo";
25+ return "generic-preview";
22}
26}
23
27
24QString Preview::title() const
28QString Preview::title() const
@@ -61,3 +65,7 @@ void Preview::execute(const QString& actionId, const QHash<QString, QVariant>& h
61 Q_UNUSED(actionId);
65 Q_UNUSED(actionId);
62 Q_UNUSED(hints);
66 Q_UNUSED(hints);
63}
67}
68+
69+void Preview::cancelAction()
70+{
71+}
tests/mocks/Unity/fake_preview.h+2
@@ -51,6 +51,8 @@ public:
51
51
52 Q_INVOKABLE void execute(const QString& actionId, const QHash<QString, QVariant>& hints);
52 Q_INVOKABLE void execute(const QString& actionId, const QHash<QString, QVariant>& hints);
53
53
54+ Q_INVOKABLE void cancelAction();
55+
54Q_SIGNALS:
56Q_SIGNALS:
55 void previewChanged();
57 void previewChanged();
56};
58};
tests/mocks/Unity/fake_scope.cpp+21−17
@@ -14,31 +14,19 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17−// Self
18#include "fake_scope.h"
17#include "fake_scope.h"
19−
20−#include <dee.h>
18+#include "fake_preview.h"
21#include "paths.h"
19#include "paths.h"
22
20
23−#include "fake_preview.h"
21+#include <dee.h>
24
22
25static DeeModel* create_categories_model(unsigned category_count);
23static DeeModel* create_categories_model(unsigned category_count);
26static DeeModel* create_results_model(unsigned category_count, unsigned result_count);
24static DeeModel* create_results_model(unsigned category_count, unsigned result_count);
27
25
28// TODO: Implement remaining pieces
26// TODO: Implement remaining pieces
29
27
30−Scope::Scope(QObject* parent)
28+Scope::Scope(QObject* parent) : Scope(QString(), QString(), false, parent)
31− : QObject(parent)
32− , m_visible(false)
33− , m_searching(false)
34− , m_isActive(false)
35− , m_categories(new Categories(this))
36− , m_results(new DeeListModel(this))
37{
29{
38− DeeModel* results_model = create_results_model(4, 30);
39− m_categories->setResultModel(results_model);
40− m_categories->setModel(create_categories_model(4));
41− m_results->setModel(results_model);
42}
30}
43
31
44Scope::Scope(QString const& id, QString const& name, bool visible, QObject* parent)
32Scope::Scope(QString const& id, QString const& name, bool visible, QObject* parent)
@@ -51,10 +39,17 @@ Scope::Scope(QString const& id, QString const& name, bool visible, QObject* pare
51 , m_categories(new Categories(this))
39 , m_categories(new Categories(this))
52 , m_results(new DeeListModel(this))
40 , m_results(new DeeListModel(this))
53{
41{
54− DeeModel* results_model = create_results_model(4, 30);
42+ DeeModel* results_model = create_results_model(20, 300);
55 m_categories->setResultModel(results_model);
43 m_categories->setResultModel(results_model);
56− m_categories->setModel(create_categories_model(4));
44+ m_categories->setModel(create_categories_model(20));
57 m_results->setModel(results_model);
45 m_results->setModel(results_model);
46+
47+ m_timer.setInterval(1000);
48+ m_timer.setSingleShot(true);
49+ connect(&m_timer, &QTimer::timeout, [this]() {
50+ Preview *p = new Preview(this);
51+ Q_EMIT previewReady(p);
52+ });
58}
53}
59
54
60QString Scope::id() const {
55QString Scope::id() const {
@@ -168,6 +163,8 @@ void Scope::activate(const QVariant &uri, const QVariant &icon_hint, const QVari
168 Q_UNUSED(comment);
163 Q_UNUSED(comment);
169 Q_UNUSED(dnd_uri);
164 Q_UNUSED(dnd_uri);
170 Q_UNUSED(metadata);
165 Q_UNUSED(metadata);
166+
167+ m_timer.start();
171}
168}
172
169
173void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
170void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
@@ -183,6 +180,8 @@ void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVaria
183 Q_UNUSED(comment);
180 Q_UNUSED(comment);
184 Q_UNUSED(dnd_uri);
181 Q_UNUSED(dnd_uri);
185 Q_UNUSED(metadata);
182 Q_UNUSED(metadata);
183+
184+ m_timer.start();
186}
185}
187
186
188static const gchar * categories_model_schema[] = {
187static const gchar * categories_model_schema[] = {
@@ -248,3 +247,8 @@ DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
248 }
247 }
249 return results_model;
248 return results_model;
250}
249}
250+
251+void Scope::cancelActivation()
252+{
253+ m_timer.stop();
254+}
tests/mocks/Unity/fake_scope.h+7−2
@@ -17,10 +17,11 @@
17#ifndef FAKE_SCOPE_H
17#ifndef FAKE_SCOPE_H
18#define FAKE_SCOPE_H
18#define FAKE_SCOPE_H
19
19
20−// Qt
21−#include <QObject>
22#include "fake_categories.h"
20#include "fake_categories.h"
23
21
22+#include <QObject>
23+#include <QDebug>
24+
24class Preview;
25class Preview;
25
26
26class Scope : public QObject
27class Scope : public QObject
@@ -78,6 +79,8 @@ public:
78 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
79 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
79 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
80 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
80
81
82+ Q_INVOKABLE void cancelActivation();
83+
81Q_SIGNALS:
84Q_SIGNALS:
82 void idChanged(const QString&);
85 void idChanged(const QString&);
83 void nameChanged(const QString&);
86 void nameChanged(const QString&);
@@ -115,6 +118,8 @@ protected:
115
118
116 Categories* m_categories;
119 Categories* m_categories;
117 DeeListModel* m_results;
120 DeeListModel* m_results;
121+
122+ QTimer m_timer;
118};
123};
119
124
120#endif // FAKE_SCOPE_H
125#endif // FAKE_SCOPE_H
tests/mocks/Unity/fake_unity_plugin.cpp+3
@@ -22,6 +22,7 @@
22// local
22// local
23#include "fake_scopes.h"
23#include "fake_scopes.h"
24#include "fake_categories.h"
24#include "fake_categories.h"
25+#include "fake_preview.h"
25#include "categoryresults.h"
26#include "categoryresults.h"
26
27
27// External
28// External
@@ -37,8 +38,10 @@ void FakeUnityPlugin::registerTypes(const char *uri)
37
38
38 Q_ASSERT(uri == QLatin1String("Unity"));
39 Q_ASSERT(uri == QLatin1String("Unity"));
39
40
41+ qmlRegisterUncreatableType<Preview>(uri, 0, 1, "Preview", "Can't create Preview object in QML.");
40 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
42 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
41 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
43 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
42 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
44 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
43 qmlRegisterUncreatableType<CategoryResults>(uri, 0, 1, "CategoryResults", "Can't create");
45 qmlRegisterUncreatableType<CategoryResults>(uri, 0, 1, "CategoryResults", "Can't create");
46+ qmlRegisterType<DeeListModel>(uri, 0, 1, "DeeListModel");
44}
47}
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cpp+20
@@ -1724,6 +1724,9 @@ private Q_SLOTS:
1724
1724
1725 void testMaximizeVisibleAreaMoveUpAndShowHeader()
1725 void testMaximizeVisibleAreaMoveUpAndShowHeader()
1726 {
1726 {
1727+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
1728+ QSKIP("This test is extremely unstable in 5.0.x");
1729+#endif
1727 model->setProperty(0, "size", 800);
1730 model->setProperty(0, "size", 800);
1728 verifyItem(0, 50., 800., false);
1731 verifyItem(0, 50., 800., false);
1729
1732
@@ -1824,6 +1827,23 @@ private Q_SLOTS:
1824 lvwph->positionAtBeginning();
1827 lvwph->positionAtBeginning();
1825 }
1828 }
1826
1829
1830+ void testHeaderPositionBug1240118()
1831+ {
1832+ scrollToBottom();
1833+ lvwph->showHeader();
1834+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1835+ QTest::qWait(100); // Make sure stuff is stable
1836+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 100));
1837+ model->setProperty(3, "size", 10);
1838+ model->setProperty(4, "size", 10);
1839+ model->setProperty(5, "size", 10);
1840+ model->setProperty(6, "size", 10);
1841+#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 3))
1842+ QTRY_COMPARE(lvwph->m_minYExtent, 210.);
1843+#endif
1844+ QTRY_COMPARE(lvwph->m_headerItem->y(), -lvwph->m_minYExtent);
1845+ }
1846+
1827private:
1847private:
1828 QQuickView *view;
1848 QQuickView *view;
1829 ListViewWithPageHeader *lvwph;
1849 ListViewWithPageHeader *lvwph;
tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml+2−10
@@ -31,10 +31,7 @@ Item {
31 y: followDragArea()
31 y: followDragArea()
32
32
33 function followDragArea() {
33 function followDragArea() {
34− if (dragArea.status === DirectionalDragArea.Rejected)
35− return -height
36− else
37− return dragArea.distance < height ? -height + dragArea.distance : 0
34+ return dragArea.distance < height ? -height + dragArea.distance : 0
38 }
35 }
39 }
36 }
40
37
@@ -66,15 +63,10 @@ Item {
66 dragAreaRect.opacity = 0.3
63 dragAreaRect.opacity = 0.3
67 launcher.y = Qt.binding(launcher.followDragArea)
64 launcher.y = Qt.binding(launcher.followDragArea)
68 break;
65 break;
69− case DirectionalDragArea.Recognized:
66+ defaut: // DirectionalDragArea.Recognized:
70 dragAreaRect.color = "green"
67 dragAreaRect.color = "green"
71 dragAreaRect.opacity = 0.5
68 dragAreaRect.opacity = 0.5
72 break;
69 break;
73− default: //case DirectionalDragArea.Rejected:
74− dragAreaRect.color = "red"
75− dragAreaRect.opacity = 0.5
76− launcher.y = -launcher.height
77− break;
78 }
70 }
79 }
71 }
80
72
tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml+5−13
@@ -32,13 +32,10 @@ Item {
32 y: 0
32 y: 0
33
33
34 function followDragArea() {
34 function followDragArea() {
35− if (dragArea.status === DirectionalDragArea.Rejected)
36− return root.width
37− else
38− return dragArea.distance > -width ?
35+ return dragArea.distance > -width ?
39− root.width + dragArea.distance
36+ root.width + dragArea.distance
40− :
37+ :
41− root.width - width
38+ root.width - width
42 }
39 }
43 }
40 }
44
41
@@ -69,15 +66,10 @@ Item {
69 dragAreaRect.opacity = 0.3
66 dragAreaRect.opacity = 0.3
70 launcher.x = Qt.binding(launcher.followDragArea)
67 launcher.x = Qt.binding(launcher.followDragArea)
71 break;
68 break;
72− case DirectionalDragArea.Recognized:
69+ default: //case DirectionalDragArea.Recognized:
73 dragAreaRect.color = "green"
70 dragAreaRect.color = "green"
74 dragAreaRect.opacity = 0.5
71 dragAreaRect.opacity = 0.5
75 break;
72 break;
76− default: //case DirectionalDragArea.Rejected:
77− dragAreaRect.color = "red"
78− dragAreaRect.opacity = 0.5
79− launcher.x = -launcher.height
80− break;
81 }
73 }
82 }
74 }
83
75
tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml+3−10
@@ -19,6 +19,7 @@ import Ubuntu.Gestures 0.1
19import Ubuntu.Components 0.1
19import Ubuntu.Components 0.1
20
20
21Item {
21Item {
22+ objectName: "rightwardsLauncher"
22
23
23 function reset() { launcher.x = -launcher.width }
24 function reset() { launcher.x = -launcher.width }
24
25
@@ -31,10 +32,7 @@ Item {
31 y: 0
32 y: 0
32
33
33 function followDragArea() {
34 function followDragArea() {
34− if (dragArea.status === DirectionalDragArea.Rejected)
35− return -width
36− else
37− return dragArea.distance < width ? -width + dragArea.distance : 0
35+ return dragArea.distance < width ? -width + dragArea.distance : 0
38 }
36 }
39 }
37 }
40
38
@@ -66,15 +64,10 @@ Item {
66 dragAreaRect.opacity = 0.3
64 dragAreaRect.opacity = 0.3
67 launcher.x = Qt.binding(launcher.followDragArea)
65 launcher.x = Qt.binding(launcher.followDragArea)
68 break;
66 break;
69− case DirectionalDragArea.Recognized:
67+ default: //case DirectionalDragArea.Recognized:
70 dragAreaRect.color = "green"
68 dragAreaRect.color = "green"
71 dragAreaRect.opacity = 0.5
69 dragAreaRect.opacity = 0.5
72 break;
70 break;
73− default: //case DirectionalDragArea.Rejected:
74− dragAreaRect.color = "red"
75− dragAreaRect.opacity = 0.5
76− launcher.x = -launcher.height
77− break;
78 }
71 }
79 }
72 }
80
73
tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml+5−13
@@ -32,13 +32,10 @@ Item {
32 y: root.height
32 y: root.height
33
33
34 function followDragArea() {
34 function followDragArea() {
35− if (dragArea.status === DirectionalDragArea.Rejected)
36− return root.height
37− else
38− return dragArea.distance > -height ?
35+ return dragArea.distance > -height ?
39− root.height + dragArea.distance
36+ root.height + dragArea.distance
40− :
37+ :
41− root.height - height
38+ root.height - height
42 }
39 }
43 }
40 }
44
41
@@ -69,15 +66,10 @@ Item {
69 dragAreaRect.opacity = 0.3
66 dragAreaRect.opacity = 0.3
70 launcher.y = Qt.binding(launcher.followDragArea)
67 launcher.y = Qt.binding(launcher.followDragArea)
71 break;
68 break;
72− case DirectionalDragArea.Recognized:
69+ default: //case DirectionalDragArea.Recognized:
73 dragAreaRect.color = "green"
70 dragAreaRect.color = "green"
74 dragAreaRect.opacity = 0.5
71 dragAreaRect.opacity = 0.5
75 break;
72 break;
76− default: //case DirectionalDragArea.Rejected:
77− dragAreaRect.color = "red"
78− dragAreaRect.opacity = 0.5
79− launcher.y = -launcher.height
80− break;
81 }
73 }
82 }
74 }
83
75
tests/plugins/Ubuntu/Gestures/edgeDragExample.qml+7−1
@@ -33,7 +33,13 @@ Rectangle {
33 }
33 }
34 }
34 }
35
35
36+ // NB: Do not anchor it as we will move it programmatically from the test
36− RightwardsLauncher { id: hpLauncher; anchors.fill: parent }
37+ RightwardsLauncher {
38+ id: hpLauncher;
39+ width: parent.width
40+ height: parent.height
41+ }
42+
37 LeftwardsLauncher { id: hnLauncher; anchors.fill: parent }
43 LeftwardsLauncher { id: hnLauncher; anchors.fill: parent }
38 DownwardsLauncher { id: vpLauncher; anchors.fill: parent }
44 DownwardsLauncher { id: vpLauncher; anchors.fill: parent }
39 UpwardsLauncher { id: vnLauncher; anchors.fill: parent }
45 UpwardsLauncher { id: vnLauncher; anchors.fill: parent }
tests/plugins/Ubuntu/Gestures/tst_AxisVelocityCalculator.cpp+3−3
@@ -54,12 +54,12 @@ private Q_SLOTS:
54
54
55private:
55private:
56 AxisVelocityCalculator *velCalc;
56 AxisVelocityCalculator *velCalc;
57− FakeTimeSource *fakeTimeSource;
57+ QSharedPointer<FakeTimeSource> fakeTimeSource;
58};
58};
59
59
60void tst_AxisVelocityCalculator::init()
60void tst_AxisVelocityCalculator::init()
61{
61{
62− fakeTimeSource = new FakeTimeSource;
62+ fakeTimeSource.reset(new FakeTimeSource);
63
63
64 velCalc = new AxisVelocityCalculator;
64 velCalc = new AxisVelocityCalculator;
65 velCalc->setTimeSource(fakeTimeSource);
65 velCalc->setTimeSource(fakeTimeSource);
@@ -68,7 +68,7 @@ void tst_AxisVelocityCalculator::init()
68void tst_AxisVelocityCalculator::cleanup()
68void tst_AxisVelocityCalculator::cleanup()
69{
69{
70 delete velCalc;
70 delete velCalc;
71− delete fakeTimeSource;
71+ fakeTimeSource.reset();
72}
72}
73
73
74void tst_AxisVelocityCalculator::simpleSamples()
74void tst_AxisVelocityCalculator::simpleSamples()
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp+285−96
@@ -19,23 +19,38 @@
19#include <qpa/qwindowsysteminterface.h>
19#include <qpa/qwindowsysteminterface.h>
20#include <QtQuick/QQuickView>
20#include <QtQuick/QQuickView>
21#include <QtQml/QQmlEngine>
21#include <QtQml/QQmlEngine>
22+#include <QPointer>
22
23
23#include <DirectionalDragArea.h>
24#include <DirectionalDragArea.h>
24
25
26+using namespace UbuntuGestures;
27+
25−class FakeTimer : public UbuntuGestures::AbstractTimer
28+class FakeTimer : public AbstractTimer
26{
29{
27 Q_OBJECT
30 Q_OBJECT
28public:
31public:
29− FakeTimer(QObject *parent = 0)
32+ FakeTimer(const SharedTimeSource &timeSource, QObject *parent = 0)
30− : UbuntuGestures::AbstractTimer(parent)
33+ : UbuntuGestures::AbstractTimer(parent),
34+ m_timeSource(timeSource)
31 {}
35 {}
32
36
33− virtual int interval() const { return m_duration; }
37+ int interval() const override { return m_interval; }
34− virtual void setInterval(int msecs) { m_duration = msecs; }
38+ void setInterval(int msecs) override { m_interval = msecs; }
39+ void start() override {
40+ AbstractTimer::start();
41+ m_nextTimeoutTime = m_timeSource->msecsSinceReference() + (qint64)m_interval;
42+ }
43+
44+ void emitTimeout() {
45+ m_nextTimeoutTime += m_interval;
46+ Q_EMIT timeout();
47+ }
35
48
36− void emitTimeout() {Q_EMIT timeout();}
49+ qint64 nextTimeoutTime() const { return m_nextTimeoutTime; }
37private:
50private:
38− int m_duration;
51+ int m_interval;
52+ SharedTimeSource m_timeSource;
53+ qint64 m_nextTimeoutTime;
39};
54};
40
55
41class FakeTimeSource : public UbuntuGestures::TimeSource
56class FakeTimeSource : public UbuntuGestures::TimeSource
@@ -67,14 +82,17 @@ private Q_SLOTS:
67 void maxSilenceTime();
82 void maxSilenceTime();
68 void sceneXAndX();
83 void sceneXAndX();
69 void sceneYAndY();
84 void sceneYAndY();
70− void emitDraggingChangedOnDirectRecognition();
85+ void twoFingerTap();
86+ void movingDDA();
87+ void ignoreOldFinger();
71
88
72private:
89private:
73 QQuickView *createView();
90 QQuickView *createView();
91+ void passTime(qint64 timeSpan);
74 QQuickView *view;
92 QQuickView *view;
75 QTouchDevice *device;
93 QTouchDevice *device;
76 FakeTimer *fakeTimer;
94 FakeTimer *fakeTimer;
77− FakeTimeSource *fakeTimeSource;
95+ QSharedPointer<FakeTimeSource> fakeTimeSource;
78};
96};
79
97
80void tst_DirectionalDragArea::initTestCase()
98void tst_DirectionalDragArea::initTestCase()
@@ -101,8 +119,8 @@ void tst_DirectionalDragArea::init()
101 QVERIFY(view->rootObject() != 0);
119 QVERIFY(view->rootObject() != 0);
102 qApp->processEvents();
120 qApp->processEvents();
103
121
122+ fakeTimeSource.reset(new FakeTimeSource);
104− fakeTimer = new FakeTimer;
123+ fakeTimer = new FakeTimer(fakeTimeSource);
105− fakeTimeSource = new FakeTimeSource;
106}
124}
107
125
108void tst_DirectionalDragArea::cleanup()
126void tst_DirectionalDragArea::cleanup()
@@ -113,8 +131,7 @@ void tst_DirectionalDragArea::cleanup()
113 delete fakeTimer;
131 delete fakeTimer;
114 fakeTimer = 0;
132 fakeTimer = 0;
115
133
116− delete fakeTimeSource;
134+ fakeTimeSource.reset();
117− fakeTimeSource = 0;
118}
135}
119
136
120QQuickView *tst_DirectionalDragArea::createView()
137QQuickView *tst_DirectionalDragArea::createView()
@@ -127,6 +144,23 @@ QQuickView *tst_DirectionalDragArea::createView()
127 return window;
144 return window;
128}
145}
129
146
147+void tst_DirectionalDragArea::passTime(qint64 timeSpan)
148+{
149+ qint64 finalTime = fakeTimeSource->m_msecsSinceReference + timeSpan;
150+
151+ if (fakeTimer->isRunning() && finalTime >= fakeTimer->nextTimeoutTime()) {
152+ fakeTimeSource->m_msecsSinceReference = fakeTimer->nextTimeoutTime();
153+ fakeTimer->emitTimeout();
154+
155+ qint64 timeSpanRemainder = finalTime - fakeTimeSource->m_msecsSinceReference;
156+ if (timeSpanRemainder > 0) {
157+ passTime(timeSpanRemainder);
158+ }
159+ } else {
160+ fakeTimeSource->m_msecsSinceReference = finalTime;
161+ }
162+}
163+
130namespace {
164namespace {
131QPointF calculateInitialTouchPos(DirectionalDragArea *edgeDragArea, QQuickView *view)
165QPointF calculateInitialTouchPos(DirectionalDragArea *edgeDragArea, QQuickView *view)
132{
166{
@@ -180,7 +214,7 @@ void tst_DirectionalDragArea::edgeDrag()
180 QFETCH(QString, dragAreaObjectName);
214 QFETCH(QString, dragAreaObjectName);
181 QFETCH(qreal, wideningAngleMultiplier);
215 QFETCH(qreal, wideningAngleMultiplier);
182 QFETCH(qreal, dragDistanceFactor);
216 QFETCH(qreal, dragDistanceFactor);
183− QFETCH(int, expectedGestureRecognition);
217+ QFETCH(bool, expectGestureRecognition);
184
218
185 DirectionalDragArea *edgeDragArea =
219 DirectionalDragArea *edgeDragArea =
186 view->rootObject()->findChild<DirectionalDragArea*>(dragAreaObjectName);
220 view->rootObject()->findChild<DirectionalDragArea*>(dragAreaObjectName);
@@ -196,7 +230,10 @@ void tst_DirectionalDragArea::edgeDrag()
196 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*dragDistanceFactor;
230 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*dragDistanceFactor;
197 QPointF dragDirectionVector = calculateDirectionVector(edgeDragArea,
231 QPointF dragDirectionVector = calculateDirectionVector(edgeDragArea,
198 wideningAngleMultiplier);
232 wideningAngleMultiplier);
199− QPointF touchMovement = dragDirectionVector * (edgeDragArea->distanceThreshold() * 0.1f);
233+ qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
234+ QPointF touchMovement = dragDirectionVector * movementStepDistance;
235+ int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
236+ int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
200
237
201 QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
238 QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
202
239
@@ -211,15 +248,16 @@ void tst_DirectionalDragArea::edgeDrag()
211 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
248 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
212 }
249 }
213
250
214− do {
251+ for (int i = 0; i < totalMovementSteps; ++i) {
215 touchPoint += touchMovement;
252 touchPoint += touchMovement;
253+ passTime(movementTimeStepMs);
216 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
254 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
217− } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance);
255+ }
218
256
219− if (expectedGestureRecognition)
257+ if (expectGestureRecognition)
220 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
258 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
221
259
222− if (edgeDragArea->status() == DirectionalDragArea::Rejected) {
260+ if (edgeDragArea->status() == DirectionalDragArea::WaitingForTouch) {
223 QCOMPARE(edgeDragArea->dragging(), false);
261 QCOMPARE(edgeDragArea->dragging(), false);
224 QCOMPARE(draggingSpy.count(), 2);
262 QCOMPARE(draggingSpy.count(), 2);
225 }
263 }
@@ -235,49 +273,49 @@ void tst_DirectionalDragArea::edgeDrag_data()
235 QTest::addColumn<QString>("dragAreaObjectName");
273 QTest::addColumn<QString>("dragAreaObjectName");
236 QTest::addColumn<qreal>("wideningAngleMultiplier");
274 QTest::addColumn<qreal>("wideningAngleMultiplier");
237 QTest::addColumn<qreal>("dragDistanceFactor");
275 QTest::addColumn<qreal>("dragDistanceFactor");
238− QTest::addColumn<int>("expectedGestureRecognition");
276+ QTest::addColumn<bool>("expectGestureRecognition");
239
277
240 QTest::newRow("rightwards, tiny drag")
278 QTest::newRow("rightwards, tiny drag")
241− << "hpDragArea" << 0.0 << 0.2 << 0;
279+ << "hpDragArea" << 0.0 << 0.2 << false;
242
280
243 QTest::newRow("rightwards, straight drag")
281 QTest::newRow("rightwards, straight drag")
244− << "hpDragArea" << 0.0 << 3.0 << 1;
282+ << "hpDragArea" << 0.0 << 3.0 << true;
245
283
246 QTest::newRow("rightwards, diagonal drag")
284 QTest::newRow("rightwards, diagonal drag")
247− << "hpDragArea" << 0.9 << 3.0 << 1;
285+ << "hpDragArea" << 0.9 << 3.0 << true;
248
286
249 QTest::newRow("rightwards, overly diagonal drag")
287 QTest::newRow("rightwards, overly diagonal drag")
250− << "hpDragArea" << 2.0 << 3.0 << 0;
288+ << "hpDragArea" << 2.0 << 3.0 << false;
251
289
252 QTest::newRow("leftwards, tiny drag")
290 QTest::newRow("leftwards, tiny drag")
253− << "hnDragArea" << 0.0 << 0.2 << 0;
291+ << "hnDragArea" << 0.0 << 0.2 << false;
254
292
255 QTest::newRow("leftwards, straight drag")
293 QTest::newRow("leftwards, straight drag")
256− << "hnDragArea" << 0.0 << 3.0 << 1;
294+ << "hnDragArea" << 0.0 << 3.0 << true;
257
295
258 QTest::newRow("leftwards, diagonal drag")
296 QTest::newRow("leftwards, diagonal drag")
259− << "hnDragArea" << 0.9 << 3.0 << 1;
297+ << "hnDragArea" << 0.9 << 3.0 << true;
260
298
261 QTest::newRow("downwards, tiny drag")
299 QTest::newRow("downwards, tiny drag")
262− << "vpDragArea" << 0.0 << 0.2 << 0;
300+ << "vpDragArea" << 0.0 << 0.2 << false;
263
301
264 QTest::newRow("downwards, straight drag")
302 QTest::newRow("downwards, straight drag")
265− << "vpDragArea" << 0.0 << 3.0 << 1;
303+ << "vpDragArea" << 0.0 << 3.0 << true;
266
304
267 QTest::newRow("downwards, diagonal drag")
305 QTest::newRow("downwards, diagonal drag")
268− << "vpDragArea" << 0.9 << 3.0 << 1;
306+ << "vpDragArea" << 0.9 << 3.0 << true;
269
307
270 QTest::newRow("upwards, tiny drag")
308 QTest::newRow("upwards, tiny drag")
271− << "vnDragArea" << 0.0 << 0.2 << 0;
309+ << "vnDragArea" << 0.0 << 0.2 << false;
272
310
273 QTest::newRow("upwards, straight drag")
311 QTest::newRow("upwards, straight drag")
274− << "vnDragArea" << 0.0 << 3.0 << 1;
312+ << "vnDragArea" << 0.0 << 3.0 << true;
275
313
276 QTest::newRow("upwards, diagonal drag")
314 QTest::newRow("upwards, diagonal drag")
277− << "vnDragArea" << 0.9 << 3.0 << 1;
315+ << "vnDragArea" << 0.9 << 3.0 << true;
278
316
279 QTest::newRow("upwards, overly diagonal drag")
317 QTest::newRow("upwards, overly diagonal drag")
280− << "vnDragArea" << 2.0 << 3.0 << 0;
318+ << "vnDragArea" << 2.0 << 3.0 << false;
281}
319}
282
320
283/*
321/*
@@ -298,25 +336,33 @@ void tst_DirectionalDragArea::dragWithShortDirectionChange()
298
336
299 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0;
337 qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0;
300 QPointF dragDirectionVector(1.0, 0.0);
338 QPointF dragDirectionVector(1.0, 0.0);
301− QPointF touchMovement = dragDirectionVector * (edgeDragArea->distanceThreshold() * 0.1f);
339+ qreal touchStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
340+ // make sure we are above minimum speed
341+ int touchStepTimeMs = (touchStepDistance / (edgeDragArea->minSpeed() * 5.0f)) * 1000.0f;
342+ QPointF touchMovement = dragDirectionVector * touchStepDistance;
302
343
303 QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
344 QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
304
345
305 // Move a bit in the proper direction
346 // Move a bit in the proper direction
306 for (int i=0; i < 3; ++i) {
347 for (int i=0; i < 3; ++i) {
307 touchPoint += touchMovement;
348 touchPoint += touchMovement;
349+ passTime(touchStepTimeMs);
308 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
350 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
309 }
351 }
310
352
311 // Then a sudden and small movement to the opposite direction
353 // Then a sudden and small movement to the opposite direction
312− touchPoint -= dragDirectionVector * (edgeDragArea->maxDeviation() * 0.7);
354+ touchPoint -= touchMovement*0.2;
355+ passTime(touchStepTimeMs*0.2);
313 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
356 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
314
357
315− // And then resume movment in the correct direction until it crosses the distance threshold.
358+ // And then resume movment in the correct direction until it crosses the distance and time
359+ // thresholds.
316 do {
360 do {
317 touchPoint += touchMovement;
361 touchPoint += touchMovement;
362+ passTime(touchStepTimeMs);
318 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
363 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
319− } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance);
364+ } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance
365+ || fakeTimeSource->m_msecsSinceReference < (edgeDragArea->compositionTime() * 1.5f));
320
366
321 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
367 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
322
368
@@ -329,7 +375,8 @@ void tst_DirectionalDragArea::dragWithShortDirectionChange()
329 */
375 */
330void tst_DirectionalDragArea::minSpeed()
376void tst_DirectionalDragArea::minSpeed()
331{
377{
332− QFETCH(int, minSpeedMsecsDeviation);
378+ QFETCH(qreal, minSpeed);
379+ QFETCH(qreal, speed);
333 QFETCH(int, expectedStatusAfterSpeedCheck);
380 QFETCH(int, expectedStatusAfterSpeedCheck);
334
381
335 DirectionalDragArea *edgeDragArea =
382 DirectionalDragArea *edgeDragArea =
@@ -338,44 +385,40 @@ void tst_DirectionalDragArea::minSpeed()
338 edgeDragArea->setRecognitionTimer(fakeTimer);
385 edgeDragArea->setRecognitionTimer(fakeTimer);
339 edgeDragArea->setTimeSource(fakeTimeSource);
386 edgeDragArea->setTimeSource(fakeTimeSource);
340
387
388+ // A really long, unattainable, number. We don't want it getting recognized before
389+ // the speed checks we want have been performed
390+ edgeDragArea->setDistanceThreshold(500000);
391+
392+ edgeDragArea->setMinSpeed(minSpeed);
393+
341 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
394 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
342 QPointF touchPoint = initialTouchPos;
395 QPointF touchPoint = initialTouchPos;
343
396
344 QPointF dragDirectionVector(1.0, 0.0);
397 QPointF dragDirectionVector(1.0, 0.0);
345− qreal distanceStep = edgeDragArea->distanceThreshold() * 0.1f;
398+ qint64 timeStepMsecs = 10;
399+ qreal distanceStep = (speed / 1000.0f) * timeStepMsecs;
346 QPointF touchMovement = dragDirectionVector * distanceStep;
400 QPointF touchMovement = dragDirectionVector * distanceStep;
347− qreal minSpeedMsecs = edgeDragArea->minSpeed() / 1000.0;
348− qint64 timeStepMsecs = qFloor(distanceStep / minSpeedMsecs) + minSpeedMsecsDeviation;
349
401
350− // if it fails it means the params set in the QML file are not in harmony with the values
351− // used in this test
352− Q_ASSERT(timeStepMsecs > 0);
353−
354− fakeTimeSource->m_msecsSinceReference = 0;
355 QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
402 QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
356
403
357− // Move a bit in the proper direction
404+ // Move for a while to ensure our speed check is performed a couple of times
358− for (int i=0; i < 4; ++i) {
405+ for (int i=0; i < 20; ++i) {
359 touchPoint += touchMovement;
406 touchPoint += touchMovement;
360− fakeTimeSource->m_msecsSinceReference += timeStepMsecs;
407+ passTime(timeStepMsecs);
361 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
408 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
362 }
409 }
363
410
364− QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
365−
366− // Force the periodic speed check.
367− fakeTimer->emitTimeout();
368−
369 QCOMPARE((int)edgeDragArea->status(), expectedStatusAfterSpeedCheck);
411 QCOMPARE((int)edgeDragArea->status(), expectedStatusAfterSpeedCheck);
370}
412}
371
413
372void tst_DirectionalDragArea::minSpeed_data()
414void tst_DirectionalDragArea::minSpeed_data()
373{
415{
374− QTest::addColumn<int>("minSpeedMsecsDeviation");
416+ QTest::addColumn<qreal>("minSpeed");
417+ QTest::addColumn<qreal>("speed");
375 QTest::addColumn<int>("expectedStatusAfterSpeedCheck");
418 QTest::addColumn<int>("expectedStatusAfterSpeedCheck");
376
419
377− QTest::newRow("slower than minSpeed") << 20 << (int)DirectionalDragArea::Rejected;
420+ QTest::newRow("slower than minSpeed") << 100.0 << 50.0 << (int)DirectionalDragArea::WaitingForTouch;
378− QTest::newRow("faster than minSpeed") << -20 << (int)DirectionalDragArea::Undecided;
421+ QTest::newRow("faster than minSpeed") << 100.0 << 150.0 << (int)DirectionalDragArea::Undecided;
379}
422}
380
423
381/*
424/*
@@ -391,32 +434,37 @@ void tst_DirectionalDragArea::recognitionTimerUsage()
391 edgeDragArea->setRecognitionTimer(fakeTimer);
434 edgeDragArea->setRecognitionTimer(fakeTimer);
392 edgeDragArea->setTimeSource(fakeTimeSource);
435 edgeDragArea->setTimeSource(fakeTimeSource);
393
436
437+ // don't let it interfere with our test
438+ edgeDragArea->setMinSpeed(0.0);
439+
440+ int timeStepMs = 5; // some arbitrary small value.
441+
394 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
442 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
395 QPointF touchPoint = initialTouchPos;
443 QPointF touchPoint = initialTouchPos;
396
444
397 QPointF dragDirectionVector(1.0, 0.0);
445 QPointF dragDirectionVector(1.0, 0.0);
398 QPointF touchMovement = dragDirectionVector * (edgeDragArea->distanceThreshold() * 0.2f);
446 QPointF touchMovement = dragDirectionVector * (edgeDragArea->distanceThreshold() * 0.2f);
399
447
448+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
400 QVERIFY(!fakeTimer->isRunning());
449 QVERIFY(!fakeTimer->isRunning());
401
450
402 QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
451 QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
403
452
453+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
404 QVERIFY(fakeTimer->isRunning());
454 QVERIFY(fakeTimer->isRunning());
405
455
406− // Move a bit in the proper direction
456+ // Move beyond distance threshold and composition time to ensure recognition
407− for (int i=0; i < 3; ++i) {
457+ while (fakeTimeSource->m_msecsSinceReference <= edgeDragArea->compositionTime() ||
458+ (touchPoint - initialTouchPos).manhattanLength() <= edgeDragArea->distanceThreshold()) {
459+
460+ QCOMPARE(edgeDragArea->status() == DirectionalDragArea::Undecided, fakeTimer->isRunning());
461+
408 touchPoint += touchMovement;
462 touchPoint += touchMovement;
463+ passTime(timeStepMs);
409 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
464 QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
410 }
465 }
411
466
412− QVERIFY(fakeTimer->isRunning());
413−
414− // Move beyond distance threshold
415− touchPoint += 3*touchMovement;
416− QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
417−
418 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
467 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
419−
420 QVERIFY(!fakeTimer->isRunning());
468 QVERIFY(!fakeTimer->isRunning());
421}
469}
422
470
@@ -432,29 +480,23 @@ void tst_DirectionalDragArea::maxSilenceTime()
432 edgeDragArea->setRecognitionTimer(fakeTimer);
480 edgeDragArea->setRecognitionTimer(fakeTimer);
433 edgeDragArea->setTimeSource(fakeTimeSource);
481 edgeDragArea->setTimeSource(fakeTimeSource);
434
482
483+ // Make sure this property is not disabled
484+ edgeDragArea->setMaxSilenceTime(100);
485+
435 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
486 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
436 QPointF touchPoint = initialTouchPos;
487 QPointF touchPoint = initialTouchPos;
437
488
438− fakeTimeSource->m_msecsSinceReference = 0;
439 QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
489 QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
440
490
441 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
491 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
492+ QVERIFY(fakeTimer->isRunning());
442
493
443− int neededTimeouts = qCeil((qreal)edgeDragArea->maxSilenceTime() / (qreal)fakeTimer->interval());
494+ // Force timer to timeout until after maxSilenceTime has been reached
444− if ((edgeDragArea->maxSilenceTime() % fakeTimer->interval()) == 0) {
495+ while (fakeTimeSource->m_msecsSinceReference < edgeDragArea->maxSilenceTime()) {
445− ++neededTimeouts;
496+ passTime(fakeTimer->interval());
446− }
447−
448− // Force the periodic speed check.
449− for (int i = 0; i < neededTimeouts; ++i) {
450− fakeTimer->emitTimeout();
451−
452− if (i < neededTimeouts - 1) {
453− QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
454− }
455 }
497 }
456
498
457− QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Rejected);
499+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
458}
500}
459
501
460/*
502/*
@@ -471,7 +513,6 @@ void tst_DirectionalDragArea::sceneXAndX()
471
513
472 QPointF touchScenePos(view->width() - (edgeDragArea->width()/2.0f), view->height()/2.0f);
514 QPointF touchScenePos(view->width() - (edgeDragArea->width()/2.0f), view->height()/2.0f);
473
515
474− fakeTimeSource->m_msecsSinceReference = 0;
475 QTest::touchEvent(view, device).press(0, touchScenePos.toPoint());
516 QTest::touchEvent(view, device).press(0, touchScenePos.toPoint());
476
517
477 QSignalSpy touchXSpy(edgeDragArea, SIGNAL(touchXChanged(qreal)));
518 QSignalSpy touchXSpy(edgeDragArea, SIGNAL(touchXChanged(qreal)));
@@ -500,7 +541,6 @@ void tst_DirectionalDragArea::sceneYAndY()
500
541
501 QPointF touchScenePos(view->width()/2.0f, view->height() - (edgeDragArea->height()/2.0f));
542 QPointF touchScenePos(view->width()/2.0f, view->height() - (edgeDragArea->height()/2.0f));
502
543
503− fakeTimeSource->m_msecsSinceReference = 0;
504 QTest::touchEvent(view, device).press(0, touchScenePos.toPoint());
544 QTest::touchEvent(view, device).press(0, touchScenePos.toPoint());
505
545
506 QSignalSpy touchYSpy(edgeDragArea, SIGNAL(touchYChanged(qreal)));
546 QSignalSpy touchYSpy(edgeDragArea, SIGNAL(touchYChanged(qreal)));
@@ -516,11 +556,12 @@ void tst_DirectionalDragArea::sceneYAndY()
516}
556}
517
557
518/*
558/*
519− Emit draggingChanged() when status change from WaitingForTouch directly to Recognized.
559+ Regression test for https://bugs.launchpad.net/bugs/1228336
520− This happens when the gesture recognition is effectively disabled (e.g. by setting a
560+
521− distanceThreshold of zero)
561+ Perform a quick two-finger double-tap and check that DirectionalDragArea properly
562+ rejects those touch points. In the bug above it got confused and crashed.
522 */
563 */
523−void tst_DirectionalDragArea::emitDraggingChangedOnDirectRecognition()
564+void tst_DirectionalDragArea::twoFingerTap()
524{
565{
525 DirectionalDragArea *edgeDragArea =
566 DirectionalDragArea *edgeDragArea =
526 view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
567 view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
@@ -528,22 +569,170 @@ void tst_DirectionalDragArea::emitDraggingChangedOnDirectRecognition()
528 edgeDragArea->setRecognitionTimer(fakeTimer);
569 edgeDragArea->setRecognitionTimer(fakeTimer);
529 edgeDragArea->setTimeSource(fakeTimeSource);
570 edgeDragArea->setTimeSource(fakeTimeSource);
530
571
531− QPointF touchPos = calculateInitialTouchPos(edgeDragArea, view);
572+ // Make touches evenly spaced along the edgeDragArea
573+ QPoint touchAPos(edgeDragArea->width()/2.0f, view->height()*0.33f);
574+ QPoint touchBPos(edgeDragArea->width()/2.0f, view->height()*0.66f);
532
575
533− QSignalSpy draggingSpy(edgeDragArea, SIGNAL(draggingChanged(bool)));
576+ qint64 timeStepMsecs = 5; // some arbitrary, small value
534
577
535− // That will make it completetly skip the recognition phase ("Undecided" status).
578+ // Perform the first two-finger tap
536− edgeDragArea->setDistanceThreshold(0.0);
579+ // NB: using move() instead of stationary() becasue in the latter you cannot provide
580+ // the touch position and therefore it's left with some garbage numbers.
581+ QTest::touchEvent(view, device)
582+ .press(0, touchAPos);
537
583
584+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
585+
586+ passTime(timeStepMsecs);
587+ QTest::touchEvent(view, device)
588+ .move(0, touchAPos)
589+ .press(1, touchBPos);
590+
591+ // A second touch point appeared during recognition, reject immediately as this
592+ // can't be a single-touch gesture anymore.
538 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
593 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
539− QCOMPARE(edgeDragArea->dragging(), false);
540
594
541− fakeTimeSource->m_msecsSinceReference = 0;
595+ passTime(timeStepMsecs);
596+ QTest::touchEvent(view, device)
597+ .release(0, touchAPos)
598+ .move(1, touchBPos);
599+
600+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
601+
602+ passTime(timeStepMsecs);
603+ QTest::touchEvent(view, device)
604+ .release(1, touchBPos);
605+
606+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
607+
608+ // Perform the second two-finger tap
609+
610+ passTime(timeStepMsecs);
611+ QTest::touchEvent(view, device)
612+ .press(0, touchAPos);
613+
614+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
615+
616+ passTime(timeStepMsecs);
617+ QTest::touchEvent(view, device)
618+ .move(0, touchAPos)
619+ .press(1, touchBPos);
620+
621+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
622+
623+ passTime(timeStepMsecs);
624+ QTest::touchEvent(view, device)
625+ .release(0, touchAPos)
626+ .move(1, touchBPos);
627+
628+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
629+
630+ passTime(timeStepMsecs);
631+ QTest::touchEvent(view, device)
632+ .release(1, touchBPos);
633+
634+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
635+}
636+
637+/*
638+ Tests that gesture recognition works normally even if the DirectionalDragArea moves
639+ during recognition.
640+ This effectively means that we have to do gesture recognition with scene coordinates
641+ instead of local item coordinates.
642+ */
643+void tst_DirectionalDragArea::movingDDA()
644+{
645+ QQuickItem *rightwardsLauncher = view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
646+ Q_ASSERT(rightwardsLauncher != 0);
647+
648+ DirectionalDragArea *edgeDragArea =
649+ rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
650+ Q_ASSERT(edgeDragArea != 0);
651+ edgeDragArea->setRecognitionTimer(fakeTimer);
652+ edgeDragArea->setTimeSource(fakeTimeSource);
653+
654+ QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
655+ QPointF touchPoint = initialTouchPos;
656+
657+ qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f;
658+ QPointF dragDirectionVector(1.0f, 0.0f);
659+
660+ qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
661+ QPointF touchMovement = dragDirectionVector * movementStepDistance;
662+ int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
663+ int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
664+
542− QTest::touchEvent(view, device).press(0, touchPos.toPoint());
665+ QTest::touchEvent(view, device).press(0, touchPoint.toPoint());
666+
667+ // Move it far ahead along the direction of the gesture
668+ // rightwardsLauncher is a parent of our DirectionalDragArea. So moving it will move our DDA
669+ rightwardsLauncher->setX(rightwardsLauncher->x() + edgeDragArea->distanceThreshold() * 5.0f);
670+
671+ for (int i = 0; i < totalMovementSteps; ++i) {
672+ touchPoint += touchMovement;
673+ passTime(movementTimeStepMs);
674+ QTest::touchEvent(view, device).move(0, touchPoint.toPoint());
675+ }
543
676
544 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
677 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
545− QCOMPARE(draggingSpy.count(), 1);
678+
679+ QTest::touchEvent(view, device).release(0, touchPoint.toPoint());
680+}
681+
682+/*
683+ The presence of and old, rejected, touch point lying on the DirectionalDragArea
684+ shouldn't impede the recognition of a gesture from a new touch point.
685+ */
686+void tst_DirectionalDragArea::ignoreOldFinger()
687+{
688+ DirectionalDragArea *edgeDragArea =
689+ view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
690+ Q_ASSERT(edgeDragArea != 0);
691+ edgeDragArea->setRecognitionTimer(fakeTimer);
692+ edgeDragArea->setTimeSource(fakeTimeSource);
693+
694+ // Make touches evenly spaced along the edgeDragArea
695+ QPoint touch0Pos(edgeDragArea->width()/2.0f, view->height()*0.33f);
696+ QPoint touch1Pos(edgeDragArea->width()/2.0f, view->height()*0.66f);
697+
698+ QTest::touchEvent(view, device).press(0, touch0Pos);
699+
700+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
701+
702+ // leave it lying around for some time
703+ passTime(qMax(edgeDragArea->maxSilenceTime(), edgeDragArea->compositionTime()) * 10);
704+
705+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
706+
707+ qreal desiredDragDistance = edgeDragArea->distanceThreshold()*2.0f;
708+ QPointF dragDirectionVector(1.0f, 0.0f);
709+
710+ qreal movementStepDistance = edgeDragArea->distanceThreshold() * 0.1f;
711+ QPointF touchMovement = dragDirectionVector * movementStepDistance;
712+ int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
713+ int movementTimeStepMs = (edgeDragArea->compositionTime() * 1.5f) / totalMovementSteps;
714+
715+ QTest::touchEvent(view, device)
716+ .move(0, touch0Pos)
717+ .press(1, touch1Pos);
718+
546− QCOMPARE(edgeDragArea->dragging(), true);
719+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Undecided);
720+
721+ for (int i = 0; i < totalMovementSteps; ++i) {
722+ touch1Pos += touchMovement.toPoint();
723+ passTime(movementTimeStepMs);
724+ QTest::touchEvent(view, device)
725+ .move(0, touch0Pos)
726+ .move(1, touch1Pos);
727+ }
728+
729+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
730+
731+ QTest::touchEvent(view, device)
732+ .move(0, touch0Pos)
733+ .release(1, touch1Pos);
734+
735+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
547}
736}
548
737
549QTEST_MAIN(tst_DirectionalDragArea)
738QTEST_MAIN(tst_DirectionalDragArea)
tests/plugins/Unity/Indicators/CMakeLists.txt+36−26
@@ -1,33 +1,43 @@
1+pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
2+pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
1pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
3pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
2
4
5+set(INDICATORS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../plugins/Unity/Indicators)
6+set(TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
7+
3include_directories(
8include_directories(
4 ${CMAKE_CURRENT_BINARY_DIR}
9 ${CMAKE_CURRENT_BINARY_DIR}
5− ${CMAKE_CURRENT_SOURCE_DIR}/../../../../plugins/Unity/Indicators
10+ ${INDICATORS_DIR}
6− ${QMENUMODEL_INCLUDE_DIRS}
11+ ${TEST_DIR}/mocks/QMenuModel
12+ ${GLIB_INCLUDE_DIRS}
13+ ${GIO_INCLUDE_DIRS}
7 )
14 )
8
15
9−macro(run_tests)
16+macro(indicator_test TEST)
10− set(_test_list "")
17+ set(multi_value_keywords ADDITIONAL_CPPS ADDITIONAL_LIBS)
11− foreach(_test ${ARGN})
18+ cmake_parse_arguments(test "" "" "${multi_value_keywords}" ${ARGN})
12− set(testCommand ${CMAKE_CURRENT_BINARY_DIR}/${_test}Exec
13− -o ${CMAKE_BINARY_DIR}/${_test}.xml,xunitxml
14− -o -,txt)
15− add_test(NAME ${_test} COMMAND ${testCommand})
16− add_custom_target(${_test} ${testCommand})
17− add_executable(${_test}Exec ${_test}.cpp
18− )
19− qt5_use_modules(${_test}Exec Test Core Qml)
20− target_link_libraries(${_test}Exec
21− IndicatorsQml
22− ${QMENUMODEL_LDFLAGS}
23− )
24− set(_test_list "${_test_list};${_test}")
25− endforeach()
26−endmacro(run_tests)
27
19
28−run_tests(
20+ set(testCommand ${CMAKE_CURRENT_BINARY_DIR}/${TEST}Exec
21+ -o ${CMAKE_BINARY_DIR}/${TEST}.xml,xunitxml
22+ -o -,txt)
23+ add_test(NAME ${TEST} COMMAND ${testCommand})
24+ add_custom_target(${TEST} ${testCommand})
25+ add_executable(${TEST}Exec
26+ ${TEST}.cpp
27+ ${test_ADDITIONAL_CPPS}
28+ )
29+ qt5_use_modules(${TEST}Exec Test Core Qml)
30+ target_link_libraries(${TEST}Exec
31+ ${test_ADDITIONAL_LIBS}
32+ ${GLIB_LIBRARIES}
33+ ${GIO_LIBRARIES}
34+ ${QMENUMODEL_LDFLAGS}
35+ )
36+endmacro(indicator_test)
37+
29− indicatorsmanagertest
38+indicator_test(indicatorsmanagertest ADDITIONAL_LIBS IndicatorsQml)
30− indicatorsmodeltest
39+indicator_test(indicatorsmodeltest ADDITIONAL_LIBS IndicatorsQml)
31− menucontentactivatortest
40+indicator_test(menucontentactivatortest ADDITIONAL_CPPS ${INDICATORS_DIR}/menucontentactivator.cpp)
41+indicator_test(unitymenumodelstacktest ADDITIONAL_CPPS ${TEST_DIR}/mocks/QMenuModel/unitymenumodel.cpp ${INDICATORS_DIR}/unitymenumodelstack.cpp)
32− rootactionstatetest
42+indicator_test(rootactionstatetest ADDITIONAL_LIBS IndicatorsQml)
33− )
43+indicator_test(timeformattertest ADDITIONAL_LIBS IndicatorsQml)
tests/plugins/Unity/Indicators/timeformattertest.cppnew file+55
@@ -0,0 +1,55 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Lars Uebernickel <lars.uebernickel@canonical.com>
17+ */
18+
19+#include "timeformatter.h"
20+
21+#include <QtTest>
22+#include <QDebug>
23+
24+class TimeFormatterTest : public QObject
25+{
26+ Q_OBJECT
27+private Q_SLOTS:
28+
29+ void initTestCase()
30+ {
31+ setenv("UNITY_TEST_ENV", "1", 1);
32+ }
33+
34+ void cleanupTestCase()
35+ {
36+ unsetenv("UNITY_TEST_ENV");
37+ }
38+
39+ void testFormat()
40+ {
41+ const QString format = "hh:mm dd.MM.yy";
42+
43+ QDateTime time = QDateTime::currentDateTime();
44+
45+ TimeFormatter formatter;
46+ formatter.setTime(time.toMSecsSinceEpoch() * 1000);
47+ formatter.setFormat(format);
48+
49+ QCOMPARE(formatter.timeString(), time.toString(format));
50+ }
51+};
52+
53+QTEST_GUILESS_MAIN(TimeFormatterTest)
54+
55+#include "timeformattertest.moc"
tests/plugins/Unity/Indicators/unitymenumodelstacktest.cppnew file+206
@@ -0,0 +1,206 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+#include "indicatorsmanager.h"
21+#include "paths.h"
22+#include "unitymenumodelstack.h"
23+
24+#include <QtTest>
25+#include <QDebug>
26+#include <unitymenumodel.h>
27+
28+class UnityMenuModelStackTest : public QObject
29+{
30+ Q_OBJECT
31+private Q_SLOTS:
32+
33+ void init()
34+ {
35+ m_model = new UnityMenuModel();
36+ m_headChanged = false;
37+ m_tailChanged = false;
38+ }
39+
40+ void cleanup()
41+ {
42+ delete m_model;
43+ m_model = NULL;
44+ }
45+
46+ void testHeadOnSetHead()
47+ {
48+ UnityMenuModelStack stack;
49+ connect(&stack, SIGNAL(headChanged(UnityMenuModel*)), this, SLOT(onHeadChanged()));
50+ stack.setHead(m_model);
51+
52+ QCOMPARE(stack.head(), m_model);
53+ QCOMPARE(m_headChanged, true);
54+ }
55+
56+ void testTailOnSetHead()
57+ {
58+ UnityMenuModelStack stack;
59+ connect(&stack, SIGNAL(tailChanged(UnityMenuModel*)), this, SLOT(onTailChanged()));
60+ stack.setHead(m_model);
61+
62+ QCOMPARE(stack.tail(), m_model);
63+ QCOMPARE(m_tailChanged, true);
64+ }
65+
66+ void testPushPop_data() {
67+ QTest::addColumn<int>("menuDepth");
68+ QTest::addColumn<int>("subMenuCount");
69+ QTest::addColumn<int>("subMenuIndex");
70+
71+ QTest::newRow("depth=0") << 0 << 1 << 0;
72+ QTest::newRow("depth=1") << 1 << 1 << 0;
73+ QTest::newRow("depth=8") << 8 << 2 << 1;
74+ }
75+
76+ void testPushPop()
77+ {
78+ QFETCH(int, menuDepth);
79+ QFETCH(int, subMenuCount);
80+ QFETCH(int, subMenuIndex);
81+
82+ m_model->setModelData(recuseAddMenu(subMenuCount, menuDepth));
83+
84+ UnityMenuModelStack stack;
85+ connect(&stack, SIGNAL(tailChanged(UnityMenuModel*)), this, SLOT(onTailChanged()));
86+
87+ QList<UnityMenuModel*> models;
88+
89+ int count = 0;
90+ auto foreachChild = [&](UnityMenuModel* child, int childIndex) {
91+ stack.push(child, childIndex);
92+ QCOMPARE(stack.count(), count+1);
93+
94+ count++;
95+ models << child;
96+ };
97+ recuseSubmenus(m_model, subMenuIndex, foreachChild);
98+
99+ QCOMPARE(stack.count(), models.count());
100+ QCOMPARE(stack.count(), menuDepth+1);
101+ while(stack.count() > 0) {
102+ m_tailChanged = false;
103+
104+ QCOMPARE(stack.pop(), models.takeLast());
105+
106+ QCOMPARE(m_tailChanged, true);
107+ if (stack.count()) {
108+ QCOMPARE(stack.tail(), models.last());
109+ }
110+ }
111+ QCOMPARE(m_tailChanged, true);
112+ }
113+
114+ void testPopOnRemove_data() {
115+ QTest::addColumn<int>("menuDepth");
116+ QTest::addColumn<int>("subMenuCount");
117+ QTest::addColumn<int>("subMenuIndex");
118+ QTest::addColumn<int>("removeIndex");
119+ QTest::addColumn<int>("resultCount");
120+
121+ QTest::newRow("removeIndexBefore") << 4 << 2 << 1 << 0 << 5;
122+ QTest::newRow("removeCurrentIndex") << 4 << 2 << 0 << 0 << 1;
123+ QTest::newRow("removeIndexAfter") << 4 << 2 << 0 << 1 << 5;
124+ }
125+
126+ void testPopOnRemove()
127+ {
128+ QFETCH(int, menuDepth);
129+ QFETCH(int, subMenuCount);
130+ QFETCH(int, subMenuIndex);
131+ QFETCH(int, removeIndex);
132+ QFETCH(int, resultCount);
133+
134+ m_model->setModelData(recuseAddMenu(subMenuCount, menuDepth));
135+
136+ UnityMenuModelStack stack;
137+
138+ auto foreachChild = [&](UnityMenuModel* child, int childIndex) {
139+ stack.push(child, childIndex);
140+ };
141+ recuseSubmenus(m_model, subMenuIndex, foreachChild);
142+
143+ QCOMPARE(stack.count(), menuDepth+1);
144+
145+ m_model->removeRow(removeIndex);
146+
147+ waitFor([&stack, resultCount]() { return stack.count() == resultCount; }, 1000);
148+ QCOMPARE(stack.count(), resultCount);
149+ }
150+
151+private:
152+ bool waitFor(std::function<bool()> functor, int ms) {
153+
154+ QElapsedTimer timer;
155+ timer.start();
156+ while(!functor() && timer.elapsed() < ms) { QTest::qWait(10); }
157+ return functor();
158+ }
159+
160+ QVariant recuseAddMenu(int subMenuCount, int depth_remaining)
161+ {
162+ QVariantList rows;
163+
164+ for (int i = 0; i < subMenuCount; i ++) {
165+ QVariantMap row;
166+ QVariantMap rowData;
167+
168+ if (depth_remaining > 0) {
169+ row["submenu"] = recuseAddMenu(subMenuCount, depth_remaining-1);
170+ }
171+
172+ row["rowData"] = rowData;
173+
174+ rows << row;
175+ }
176+
177+ return rows;
178+ }
179+
180+ void recuseSubmenus(UnityMenuModel* model, int childIndex, std::function<void(UnityMenuModel*, int)> func) {
181+ UnityMenuModel* parent = model;
182+ UnityMenuModel* child = model;
183+
184+ while(child) {
185+ if (func) {
186+ func(child, childIndex);
187+ }
188+
189+ parent = child;
190+ child = qobject_cast<UnityMenuModel*>(parent->submenu(childIndex));
191+ }
192+
193+ }
194+
195+private Q_SLOTS:
196+ void onHeadChanged() { m_headChanged = true; }
197+ void onTailChanged() { m_tailChanged = true; }
198+
199+public:
200+ UnityMenuModel* m_model;
201+ bool m_headChanged;
202+ bool m_tailChanged;
203+};
204+
205+QTEST_GUILESS_MAIN(UnityMenuModelStackTest)
206+#include "unitymenumodelstacktest.moc"
tests/qmltests/CMakeLists.txt+5−3
@@ -13,11 +13,9 @@ set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
13set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
13set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
14add_qml_test(Components AnimationControllerWithSignals)
14add_qml_test(Components AnimationControllerWithSignals)
15add_qml_test(Components Carousel)
15add_qml_test(Components Carousel)
16−add_qml_test(Components MathLocal)
17add_qml_test(Components OpenEffect)
16add_qml_test(Components OpenEffect)
18add_qml_test(Components RatingStars)
17add_qml_test(Components RatingStars)
19add_qml_test(Components TimeLocal)
18add_qml_test(Components TimeLocal)
20−add_qml_test(Greeter Clock IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
21add_qml_test(Panel IndicatorItem)
19add_qml_test(Panel IndicatorItem)
22add_qml_test(utils/Unity/Test UnityTest)
20add_qml_test(utils/Unity/Test UnityTest)
23
21
@@ -61,15 +59,19 @@ add_qml_test(Greeter Phone IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DE
61 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
59 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
62add_qml_test(Greeter Infographics IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
60add_qml_test(Greeter Infographics IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
63 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
61 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
62+add_qml_test(Greeter Clock IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
63+ ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
64add_qml_test(Hud Hud)
64add_qml_test(Hud Hud)
65add_qml_test(Hud Result)
65add_qml_test(Hud Result)
66add_qml_test(Launcher Launcher IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
66add_qml_test(Launcher Launcher IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
67−add_qml_test(Notifications Notifications IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_SOURCE_DIR}/tests/mocks)
67+add_qml_test(Notifications Notifications IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
68add_qml_test(Panel IndicatorRow)
68add_qml_test(Panel IndicatorRow)
69add_qml_test(Panel Indicators IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
69add_qml_test(Panel Indicators IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
70add_qml_test(Panel MenuContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
70add_qml_test(Panel MenuContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
71add_qml_test(Panel Panel IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
71add_qml_test(Panel Panel IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
72add_qml_test(Panel SearchIndicator)
72add_qml_test(Panel SearchIndicator)
73+add_qml_test(Panel/Indicators DefaultIndicatorWidget IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
74+ ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
73add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
75add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
74 ${CMAKE_BINARY_DIR}/tests/mocks
76 ${CMAKE_BINARY_DIR}/tests/mocks
75 ${CMAKE_BINARY_DIR}/plugins)
77 ${CMAKE_BINARY_DIR}/plugins)
tests/qmltests/Components/tst_DragHandle.cpp+4−5
@@ -41,7 +41,7 @@ class FakeTimeSource : public UbuntuGestures::TimeSource
41{
41{
42public:
42public:
43 FakeTimeSource() { m_msecsSinceReference = 0; }
43 FakeTimeSource() { m_msecsSinceReference = 0; }
44− virtual qint64 msecsSinceReference() {return m_msecsSinceReference;}
44+ qint64 msecsSinceReference() override {return m_msecsSinceReference;}
45 qint64 m_msecsSinceReference;
45 qint64 m_msecsSinceReference;
46};
46};
47
47
@@ -73,7 +73,7 @@ private:
73 QQuickView *m_view;
73 QQuickView *m_view;
74 QTouchDevice *m_device;
74 QTouchDevice *m_device;
75 FakeTimer *m_fakeTimer;
75 FakeTimer *m_fakeTimer;
76− FakeTimeSource *m_fakeTimeSource;
76+ QSharedPointer<FakeTimeSource> m_fakeTimeSource;
77};
77};
78
78
79
79
@@ -102,7 +102,7 @@ void tst_DragHandle::init()
102 qApp->processEvents();
102 qApp->processEvents();
103
103
104 m_fakeTimer = new FakeTimer;
104 m_fakeTimer = new FakeTimer;
105− m_fakeTimeSource = new FakeTimeSource;
105+ m_fakeTimeSource.reset(new FakeTimeSource);
106}
106}
107
107
108void tst_DragHandle::cleanup()
108void tst_DragHandle::cleanup()
@@ -113,8 +113,7 @@ void tst_DragHandle::cleanup()
113 delete m_fakeTimer;
113 delete m_fakeTimer;
114 m_fakeTimer = 0;
114 m_fakeTimer = 0;
115
115
116− delete m_fakeTimeSource;
116+ m_fakeTimeSource.reset();
117− m_fakeTimeSource = 0;
118}
117}
119
118
120QQuickView *tst_DragHandle::createView()
119QQuickView *tst_DragHandle::createView()
tests/qmltests/Components/tst_EdgeDemoOverlay.qml+2−2
@@ -112,8 +112,8 @@ Item {
112 // Test that the 'none' edge skips anywhere
112 // Test that the 'none' edge skips anywhere
113 signalSpy.target = none
113 signalSpy.target = none
114 signalSpy.clear()
114 signalSpy.clear()
115− var backgroundShade = findChild(none, "backgroundShade")
115+ var backgroundShade = findChild(none, "backgroundShadeMouseArea")
116− tryCompare(none, "opacity", 1)
116+ tryCompare(backgroundShade, "enabled", true)
117 mousePress(backgroundShade, 1, 1)
117 mousePress(backgroundShade, 1, 1)
118 mouseRelease(backgroundShade, 1, 1)
118 mouseRelease(backgroundShade, 1, 1)
119 signalSpy.wait()
119 signalSpy.wait()
tests/qmltests/Components/tst_MathLocal.qmldeleted−91
@@ -1,91 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../Components/Math.js" as MathLocal
20−
21−TestCase {
22− name: "MathLocal"
23−
24− property int minValue
25− property int maxValue
26− property int clampValue
27− property int clamped
28−
29− function test_clamp_positive_lower() {
30− minValue = 9
31− maxValue = 42
32− clampValue = -7
33−
34− clamped = MathLocal.clamp(clampValue, minValue, maxValue)
35− compare(clamped, minValue, "clamped value not within range")
36− }
37−
38− function test_clamp_positive_greater() {
39− minValue = 9
40− maxValue = 42
41− clampValue = 111
42−
43− clamped = MathLocal.clamp(clampValue, minValue, maxValue)
44− compare(clamped, maxValue, "clamped value not within range")
45− }
46−
47− function test_clamp_positive_within() {
48− minValue = 9
49− maxValue = 53
50− clampValue = 42
51−
52− clamped = MathLocal.clamp(clampValue, minValue, maxValue)
53− compare(clamped, clampValue, "clamped value changed even though it shouldn't have")
54− }
55−
56− function test_clamp_positive_on_border() {
57− minValue = 9
58− maxValue = 42
59− clampValue = 9
60−
61− clamped = MathLocal.clamp(clampValue, minValue, maxValue)
62− compare(clamped, clampValue, "clamped value changed even though it shouldn't have")
63− }
64−
65− function test_clamp_negative_lower() {
66− minValue = -42
67− maxValue = -9
68− clampValue = -50
69−
70− clamped = MathLocal.clamp(clampValue, minValue, maxValue)
71− compare(clamped, minValue, "clamped value not within range")
72− }
73−
74− function test_clamp_negative_greater() {
75− minValue = -42
76− maxValue = -9
77− clampValue = 50
78−
79− clamped = MathLocal.clamp(clampValue, minValue, maxValue)
80− compare(clamped, maxValue, "clamped value not within range")
81− }
82−
83− function test_clamp_postive_and_negative_greater() {
84− minValue = -42
85− maxValue = 9
86− clampValue = 50
87−
88− clamped = MathLocal.clamp(clampValue, minValue, maxValue)
89− compare(clamped, maxValue, "clamped value not within range")
90− }
91−}
tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml+1
@@ -226,6 +226,7 @@ Item {
226 verify(fakeRunningAppsModel.contains("calendar"))
226 verify(fakeRunningAppsModel.contains("calendar"))
227
227
228 mouseClick(calendarTileCloseButton, calendarTileCloseButton.width/2, calendarTileCloseButton.height/2)
228 mouseClick(calendarTileCloseButton, calendarTileCloseButton.width/2, calendarTileCloseButton.height/2)
229+ wait(0) // spin event loop to start any pending animation
229
230
230 verify(!fakeRunningAppsModel.contains("calendar"))
231 verify(!fakeRunningAppsModel.contains("calendar"))
231
232
tests/qmltests/Dash/qml/FakeScopeView.qml+1
@@ -23,6 +23,7 @@ ScopeView {
23 id: fakeScopeView
23 id: fakeScopeView
24
24
25 property alias backColor : back.color
25 property alias backColor : back.color
26+ moving: listView.moving
26
27
27 onEndReached: {
28 onEndReached: {
28 if (shell != undefined && shell.scopeStatus != undefined) {
29 if (shell != undefined && shell.scopeStatus != undefined) {
tests/qmltests/Dash/tst_Dash.qml+2
@@ -103,6 +103,8 @@ Item {
103 return;
103 return;
104 }
104 }
105 dash.showScopeOnLoaded = data.tag
105 dash.showScopeOnLoaded = data.tag
106+ scopes.clear();
107+ scopes.load();
106
108
107 var dashContentList = findChild(dash, "dashContentList");
109 var dashContentList = findChild(dash, "dashContentList");
108 verify(dashContentList != undefined);
110 verify(dashContentList != undefined);
tests/qmltests/Dash/tst_DashContent.qml+14
@@ -229,5 +229,19 @@ Item {
229 tryCompare(scopesModel.get(1), "isActive", data.active1);
229 tryCompare(scopesModel.get(1), "isActive", data.active1);
230 tryCompare(scopesModel.get(2), "isActive", data.active2);
230 tryCompare(scopesModel.get(2), "isActive", data.active2);
231 }
231 }
232+
233+ function test_hswipe_disabled_vswipe() {
234+ var dashContentList = findChild(dashContent, "dashContentList");
235+
236+ tryCompare(dashContentList, "interactive", true);
237+
238+ var startX = dashContentList.width/2;
239+ var startY = dashContentList.height/2;
240+ touchFlick(dashContentList, startX, startY, startX, startY - units.gu(800));
241+
242+ tryCompare(dashContentList.currentItem, "moving", true);
243+
244+ compare(dashContentList.interactive, false);
245+ }
232 }
246 }
233}
247}
tests/qmltests/Dash/tst_GenericScopeView.qml+126−13
@@ -23,11 +23,21 @@ import Ubuntu.Components 0.1
23import Unity.Test 0.1 as UT
23import Unity.Test 0.1 as UT
24
24
25Item {
25Item {
26+ id: shell
26 width: units.gu(120)
27 width: units.gu(120)
27 height: units.gu(80)
28 height: units.gu(80)
28
29
29 Scopes {
30 Scopes {
30 id: scopes
31 id: scopes
32+
33+ onLoadedChanged: {
34+ genericScopeView.scope = scopes.get(0)
35+ }
36+ }
37+
38+ property Item applicationManager: Item {
39+ signal sideStageFocusedApplicationChanged()
40+ signal mainStageFocusedApplicationChanged()
31 }
41 }
32
42
33 GenericScopeView {
43 GenericScopeView {
@@ -38,44 +48,147 @@ Item {
38 name: "GenericScopeView"
48 name: "GenericScopeView"
39 when: scopes.loaded
49 when: scopes.loaded
40
50
41− function init() {
42− genericScopeView.scope = scopes.get(0)
43− }
44−
45 function test_isCurrent() {
51 function test_isCurrent() {
46 var pageHeader = findChild(genericScopeView, "pageHeader");
52 var pageHeader = findChild(genericScopeView, "pageHeader");
47− var previewLoader = findChild(genericScopeView, "previewLoader");
53+ var previewListView = findChild(genericScopeView, "previewListView");
48 genericScopeView.isCurrent = true
54 genericScopeView.isCurrent = true
49 pageHeader.searchQuery = "test"
55 pageHeader.searchQuery = "test"
50− previewLoader.open = true
56+ previewListView.open = true
51 genericScopeView.isCurrent = false
57 genericScopeView.isCurrent = false
52 tryCompare(pageHeader, "searchQuery", "")
58 tryCompare(pageHeader, "searchQuery", "")
53 tryCompare(genericScopeView, "previewShown", false);
59 tryCompare(genericScopeView, "previewShown", false);
54 }
60 }
55
61
56 function test_showDash() {
62 function test_showDash() {
57− var previewLoader = findChild(genericScopeView, "previewLoader");
63+ var previewListView = findChild(genericScopeView, "previewListView");
58− previewLoader.open = true;
64+ previewListView.open = true;
59 scopes.get(0).showDash();
65 scopes.get(0).showDash();
60 tryCompare(genericScopeView, "previewShown", false);
66 tryCompare(genericScopeView, "previewShown", false);
61 }
67 }
62
68
63 function test_hideDash() {
69 function test_hideDash() {
64− var previewLoader = findChild(genericScopeView, "previewLoader");
70+ var previewListView = findChild(genericScopeView, "previewListView");
65− previewLoader.open = true;
71+ previewListView.open = true;
66 scopes.get(0).hideDash();
72 scopes.get(0).hideDash();
67 tryCompare(genericScopeView, "previewShown", false);
73 tryCompare(genericScopeView, "previewShown", false);
68 }
74 }
69
75
76+ function openPreview() {
77+ var categoryListView = findChild(genericScopeView, "categoryListView");
78+ categoryListView.positionAtBeginning();
79+
80+ var tile = findChild(genericScopeView, "delegate0");
81+ mouseClick(tile, tile.width / 2, tile.height / 2);
82+ var openEffect = findChild(genericScopeView, "openEffect");
83+ tryCompare(openEffect, "gap", 1);
84+ }
85+
86+ function checkArrowPosition(index) {
87+ var tile = findChild(genericScopeView, "delegate" + index);
88+ var tileCenter = tile.x + tile.width/2;
89+ var pointerArrow = findChild(genericScopeView, "pointerArrow");
90+ var pointerArrowCenter = pointerArrow.x + pointerArrow.width/2;
91+ compare(pointerArrowCenter, tileCenter, "Pointer did not move to tile");
92+ }
93+
94+ function closePreview() {
95+ var closePreviewMouseArea = findChild(genericScopeView, "closePreviewMouseArea");
96+ mouseClick(closePreviewMouseArea, closePreviewMouseArea.width / 2, closePreviewMouseArea.height / 2);
97+
98+ var previewListView = findChild(genericScopeView, "previewListView");
99+ tryCompare(previewListView, "open", false);
100+ var openEffect = findChild(genericScopeView, "openEffect");
101+ tryCompare(openEffect, "gap", 0);
102+
103+ var categoryListView = findChild(genericScopeView, "categoryListView");
104+ categoryListView.flick(0, units.gu(200));
105+ tryCompare(categoryListView, "flicking", false);
106+ }
107+
108+ function test_previewOpenClose() {
109+ var previewListView = findChild(genericScopeView, "previewListView");
110+ tryCompare(previewListView, "open", false);
111+
112+ openPreview();
113+
114+ // check for it opening successfully
115+ var currentPreviewItem = findChild(genericScopeView, "previewLoader0");
116+ tryCompareFunction(function() {
117+ var parts = currentPreviewItem.source.toString().split("/");
118+ var name = parts[parts.length - 1];
119+ return name == "DashPreviewPlaceholder.qml";
120+ },
121+ true);
122+ tryCompareFunction(function() {
123+ var parts = currentPreviewItem.source.toString().split("/");
124+ var name = parts[parts.length - 1];
125+ return name == "GenericPreview.qml";
126+ },
127+ true);
128+ tryCompare(currentPreviewItem, "progress", 1);
129+ tryCompare(previewListView, "open", true);
130+
131+ closePreview();
132+ tryCompare(previewListView, "open", false);
133+ }
134+
135+ function test_previewCycleOne() {
136+ var previewListView = findChild(genericScopeView, "previewListView");
137+ tryCompare(previewListView, "open", false);
138+
139+ openPreview();
140+
141+ // wait for it to be loaded
142+ var currentPreviewItem = findChild(genericScopeView, "previewLoader0");
143+ tryCompareFunction(function() {
144+ var parts = currentPreviewItem.source.toString().split("/");
145+ var name = parts[parts.length - 1];
146+ return name == "GenericPreview.qml";
147+ },
148+ true);
149+ tryCompare(currentPreviewItem, "progress", 1);
150+ waitForRendering(currentPreviewItem);
151+
152+ checkArrowPosition(0);
153+
154+ // flick to the next previews
155+
156+ for (var i = 1; i < previewListView.count; ++i) {
157+
158+ mouseFlick(previewListView, previewListView.width - units.gu(1),
159+ previewListView.height / 2,
160+ units.gu(2),
161+ previewListView.height / 2);
162+
163+ // wait for it to be loaded
164+ var nextPreviewItem = findChild(genericScopeView, "previewLoader" + i);
165+ tryCompareFunction(function() {
166+ var parts = nextPreviewItem.source.toString().split("/");
167+ var name = parts[parts.length - 1];
168+ return name == "GenericPreview.qml";
169+ },
170+ true);
171+ tryCompare(nextPreviewItem, "progress", 1);
172+ waitForRendering(nextPreviewItem);
173+
174+ checkArrowPosition(i);
175+ }
176+
177+ closePreview();
178+ }
179+
70 function test_show_spinner() {
180 function test_show_spinner() {
181+ openPreview();
71− var previewLoader = findChild(genericScopeView, "previewLoader");
182+ var previewListView = findChild(genericScopeView, "previewListView");
72− previewLoader.open = true;
183+ var previewLoader = findChild(genericScopeView, "previewLoader0");
73− previewLoader.source = "../../../Dash/Generic/GenericPreview.qml";
184+
74 previewLoader.item.showProcessingAction = true;
185 previewLoader.item.showProcessingAction = true;
75 var waitingForAction = findChild(genericScopeView, "waitingForActionMouseArea");
186 var waitingForAction = findChild(genericScopeView, "waitingForActionMouseArea");
76 tryCompare(waitingForAction, "enabled", true);
187 tryCompare(waitingForAction, "enabled", true);
77 previewLoader.closePreviewSpinner();
188 previewLoader.closePreviewSpinner();
78 tryCompare(waitingForAction, "enabled", false);
189 tryCompare(waitingForAction, "enabled", false);
190+
191+ closePreview();
79 }
192 }
80 }
193 }
81 }
194 }
tests/qmltests/Greeter/tst_Clock.qml+16
@@ -19,6 +19,7 @@ import QtTest 1.0
19import ".."
19import ".."
20import "../../../Greeter"
20import "../../../Greeter"
21import Ubuntu.Components 0.1
21import Ubuntu.Components 0.1
22+import QMenuModel 0.1
22import Unity.Test 0.1 as UT
23import Unity.Test 0.1 as UT
23
24
24Rectangle {
25Rectangle {
@@ -35,9 +36,24 @@ Rectangle {
35 }
36 }
36 }
37 }
37
38
39+ UnityMenuModel {
40+ id: menuModel
41+ modelData: [{
42+ "rowData": {
43+ "actionState": { "label": Qt.formatTime(new Date("October 13, 1975 11:13:00")) }
44+ }
45+ }]
46+ }
47+
38 UT.UnityTestCase {
48 UT.UnityTestCase {
39 name: "Clock"
49 name: "Clock"
40
50
51+ function init() {
52+ var cachedModel = findChild(clock, "timeModel");
53+ verify(cachedModel !== undefined);
54+ cachedModel.model = menuModel;
55+ }
56+
41 function test_customDate() {
57 function test_customDate() {
42 var dateObj = new Date("October 13, 1975 11:13:00")
58 var dateObj = new Date("October 13, 1975 11:13:00")
43 var dateString = Qt.formatDate(dateObj, Qt.DefaultLocaleLongDate)
59 var dateString = Qt.formatDate(dateObj, Qt.DefaultLocaleLongDate)
tests/qmltests/Greeter/tst_Lockscreen.qml+41−4
@@ -175,15 +175,17 @@ Rectangle {
175
175
176 function test_unlock_data() {
176 function test_unlock_data() {
177 return [
177 return [
178− {tag: "numeric", alphanumeric: false, username: "has-pin", password: "1234"},
178+ {tag: "numeric", alphanumeric: false, username: "has-pin", password: "1234", pinLength: 4},
179− {tag: "alphanumeric", alphanumeric: true, username: "has-password", password: "password"},
179+ {tag: "alphanumeric", alphanumeric: true, username: "has-password", password: "password", pinLength: -1},
180− {tag: "numeric (wrong)", alphanumeric: false, username: "has-pin", password: "4321"},
180+ {tag: "numeric (wrong)", alphanumeric: false, username: "has-pin", password: "4321", pinLength: 4},
181− {tag: "alphanumeric (wrong)", alphanumeric: true, username: "has-password", password: "drowssap"},
181+ {tag: "alphanumeric (wrong)", alphanumeric: true, username: "has-password", password: "drowssap", pinLength: -1},
182+ {tag: "flexible length", alphanumeric: false, username: "has-pin", password: "1234", pinLength: -1},
182 ]
183 ]
183 }
184 }
184
185
185 function test_unlock(data) {
186 function test_unlock(data) {
186 enteredLabel.text = ""
187 enteredLabel.text = ""
188+ pinLengthTextField.text = data.pinLength
187 LightDM.Greeter.authenticate(data.username)
189 LightDM.Greeter.authenticate(data.username)
188 waitForRendering(lockscreen)
190 waitForRendering(lockscreen)
189
191
@@ -198,6 +200,10 @@ Rectangle {
198 var button = findChild(lockscreen, "pinPadButton" + character)
200 var button = findChild(lockscreen, "pinPadButton" + character)
199 mouseClick(button, units.gu(1), units.gu(1))
201 mouseClick(button, units.gu(1), units.gu(1))
200 }
202 }
203+ if (data.pinLength == -1) {
204+ var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
205+ mouseClick(pinPadButtonErase, units.gu(1), units.gu(1));
206+ }
201 }
207 }
202 tryCompare(enteredLabel, "text", data.password)
208 tryCompare(enteredLabel, "text", data.password)
203 }
209 }
@@ -237,5 +243,36 @@ Rectangle {
237 // wait for animation to finish to not disturb other tests
243 // wait for animation to finish to not disturb other tests
238 tryCompare(animation, "running", false)
244 tryCompare(animation, "running", false)
239 }
245 }
246+
247+ function test_backspace_data() {
248+ return [
249+ {tag: "fixed length", pinLength: 4},
250+ {tag: "variable length", pinLength: -1}
251+ ];
252+ }
253+
254+ function test_backspace(data) {
255+ pinPadCheckBox.checked = false
256+ pinLengthTextField.text = data.pinLength
257+ waitForRendering(lockscreen);
258+
259+ var pinPadButtonErase = findChild(lockscreen, "pinPadButtonErase");
260+ var backspaceIcon = findChild(lockscreen, "backspaceIcon");
261+ var pinEntryField = findChild(lockscreen, "pinentryField");
262+
263+ compare(pinPadButtonErase.iconName, data.pinLength == -1 ? "" : "erase");
264+ compare(backspaceIcon.visible, data.pinLength == -1);
265+
266+ var pinPadButton5 = findChild(lockscreen, "pinPadButton5");
267+ mouseClick(pinPadButton5, units.gu(1), units.gu(1));
268+ compare(pinEntryField.text, "5");
269+
270+ if (data.pinLength == -1) {
271+ mouseClick(backspaceIcon, units.gu(1), units.gu(1));
272+ } else {
273+ mouseClick(pinPadButtonErase, units.gu(1), units.gu(1));
274+ }
275+ compare(pinEntryField.text, "");
276+ }
240 }
277 }
241}
278}
tests/qmltests/Greeter/tst_Phone.qml+23−10
@@ -83,8 +83,9 @@ Item {
83
83
84 function test_teaseLockedUnlocked_data() {
84 function test_teaseLockedUnlocked_data() {
85 return [
85 return [
86− {tag: "unlocked", locked: false},
86+ {tag: "unlocked", locked: false, moved: false},
87− {tag: "locked", locked: true}
87+ {tag: "locked", locked: true, moved: false},
88+ {tag: "moved", locked: false, moved: true}
88 ];
89 ];
89 }
90 }
90
91
@@ -93,10 +94,16 @@ Item {
93 tryCompare(greeter, "x", 0);
94 tryCompare(greeter, "x", 0);
94 greeter.locked = data.locked;
95 greeter.locked = data.locked;
95
96
97+ // simulate greeter being in the middle of a swipe
98+ if (data.moved) {
99+ greeter.x = -units.gu(4);
100+ tryCompare(greeter, "x", -units.gu(4));
101+ }
102+
96 mouseClick(greeter, greeter.width - units.gu(5), greeter.height - units.gu(1));
103 mouseClick(greeter, greeter.width - units.gu(5), greeter.height - units.gu(1));
97 greeter.minX = 0; // This is needed because the transition actually makes x jump once before animating
104 greeter.minX = 0; // This is needed because the transition actually makes x jump once before animating
98
105
99− if (!data.locked) {
106+ if (!data.locked && !data.moved) {
100 // Check if it has been moved over by 2 GUs. Give it a 2 pixel grace area
107 // Check if it has been moved over by 2 GUs. Give it a 2 pixel grace area
101 // because animation duration and teaseTimer are the same duration and
108 // because animation duration and teaseTimer are the same duration and
102 // might cause slight offsets
109 // might cause slight offsets
@@ -104,10 +111,16 @@ Item {
104 } else {
111 } else {
105 // waiting 100ms to make sure nothing moves
112 // waiting 100ms to make sure nothing moves
106 wait(100);
113 wait(100);
107− compare(greeter.minX, 0, "Greeter moved even tho its locked");
114+ compare(greeter.minX, 0, "Greeter teasing not disabled even though it's locked or moving.");
108 }
115 }
116+
117+ // Restore position in case we moved it for the test
118+ if (data.moved) {
119+ greeter.x = 0;
120+ }
121+
109 // Wait until we're back to 0
122 // Wait until we're back to 0
110− tryCompareFunction(function() { return greeter.x;}, 0);
123+ tryCompareFunction(function() { return greeter.x;}, 0);
111 }
124 }
112
125
113 function test_statsWelcomeScreen() {
126 function test_statsWelcomeScreen() {
@@ -120,7 +133,7 @@ Item {
120 tryCompare(LightDM.Infographic, "username", "single")
133 tryCompare(LightDM.Infographic, "username", "single")
121 }
134 }
122
135
123− function test_wallpaper_data() {
136+ function test_background_data() {
124 return [
137 return [
125 {tag: "set", accounts: "../tests/data/unity/backgrounds/blue.png", expected: "blue.png"},
138 {tag: "set", accounts: "../tests/data/unity/backgrounds/blue.png", expected: "blue.png"},
126 {tag: "unset", accounts: "", expected: "background.jpg"},
139 {tag: "unset", accounts: "", expected: "background.jpg"},
@@ -128,12 +141,12 @@ Item {
128 ]
141 ]
129 }
142 }
130
143
131− function test_wallpaper(data) {
144+ function test_background(data) {
132 var loader = findChild(greeter, "greeterContentLoader")
145 var loader = findChild(greeter, "greeterContentLoader")
133− var wallpaper = findChild(loader.item, "wallpaper")
146+ var background = findChild(loader.item, "greeterBackground")
134 AccountsService.backgroundFile = data.accounts
147 AccountsService.backgroundFile = data.accounts
135− tryCompareFunction(function() { return wallpaper.source.toString().indexOf(data.expected) !== -1; }, true)
148+ tryCompareFunction(function() { return background.source.toString().indexOf(data.expected) !== -1; }, true)
136− tryCompare(wallpaper, "status", Image.Ready)
149+ tryCompare(background, "status", Image.Ready)
137 }
150 }
138 }
151 }
139}
152}
tests/qmltests/Launcher/tst_Launcher.qml+47−11
@@ -363,25 +363,60 @@ Item {
363 var draggedItem = findChild(launcher, "launcherDelegate5")
363 var draggedItem = findChild(launcher, "launcherDelegate5")
364 var item0 = findChild(launcher, "launcherDelegate0")
364 var item0 = findChild(launcher, "launcherDelegate0")
365 var fakeDragItem = findChild(launcher, "fakeDragItem")
365 var fakeDragItem = findChild(launcher, "fakeDragItem")
366− var dndArea = findChild(launcher, "dndArea")
366+ var quickListShape = findChild(launcher, "quickListShape")
367
367
368 // Initial state
368 // Initial state
369− compare(dndArea.quickListPopover, null)
369+ compare(quickListShape.visible, false)
370
370
371 // Doing longpress
371 // Doing longpress
372 mousePress(draggedItem, draggedItem.width / 2, draggedItem.height / 2)
372 mousePress(draggedItem, draggedItem.width / 2, draggedItem.height / 2)
373 tryCompare(fakeDragItem, "visible", true) // Wait longpress happening
373 tryCompare(fakeDragItem, "visible", true) // Wait longpress happening
374− verify(dndArea.quickListPopover != null)
374+ tryCompare(quickListShape, "visible", true)
375
375
376 // Dragging a bit (> 1.5 gu)
376 // Dragging a bit (> 1.5 gu)
377 mouseMove(draggedItem, -units.gu(2), draggedItem.height / 2)
377 mouseMove(draggedItem, -units.gu(2), draggedItem.height / 2)
378
378
379 // QuickList needs to be closed when a drag operation starts
379 // QuickList needs to be closed when a drag operation starts
380− tryCompare(dndArea, "quickListPopover", null)
380+ tryCompare(quickListShape, "visible", false)
381
381
382 mouseRelease(draggedItem);
382 mouseRelease(draggedItem);
383 }
383 }
384
384
385+ function test_quicklist_positioning_data() {
386+ return [
387+ {tag: "top", flickTo: "top", itemIndex: 0},
388+ {tag: "bottom", flickTo: "bottom", itemIndex: 9}
389+ ];
390+ }
391+
392+ function test_quicklist_positioning(data) {
393+ revealer.dragLauncherIntoView();
394+ var quickList = findChild(launcher, "quickList")
395+ var draggedItem = findChild(launcher, "launcherDelegate" + data.itemIndex)
396+ var quickListShape = findChild(launcher, "quickListShape")
397+
398+ // Position launcher to where we need it
399+ var listView = findChild(launcher, "launcherListView");
400+ listView.flick(0, units.gu(200) * (data.flickTo === "top" ? 1 : -1));
401+ tryCompare(listView, "flicking", false);
402+
403+ // Doing longpress
404+ mousePress(draggedItem, draggedItem.width / 2, draggedItem.height / 2)
405+ tryCompare(quickListShape, "opacity", 0.8)
406+ mouseRelease(draggedItem);
407+
408+ verify(quickList.y >= units.gu(1))
409+ verify(quickList.y + quickList.height + units.gu(1) <= launcher.height)
410+
411+ // Click somewhere in the empty space to dismiss the quicklist
412+ mouseClick(launcher, launcher.width - units.gu(1), units.gu(1));
413+ tryCompare(quickListShape, "visible", false)
414+
415+ // Click somewhere in the empty space to dismiss the launcher
416+ mouseClick(launcher, launcher.width - units.gu(1), units.gu(1));
417+ revealer.waitUntilLauncherDisappears()
418+ }
419+
385 function test_quicklist_click_data() {
420 function test_quicklist_click_data() {
386 return [
421 return [
387 {tag: "non-clickable", index: 1, clickable: false },
422 {tag: "non-clickable", index: 1, clickable: false },
@@ -392,19 +427,20 @@ Item {
392 function test_quicklist_click(data) {
427 function test_quicklist_click(data) {
393 revealer.dragLauncherIntoView();
428 revealer.dragLauncherIntoView();
394 var clickedItem = findChild(launcher, "launcherDelegate5")
429 var clickedItem = findChild(launcher, "launcherDelegate5")
395− var dndArea = findChild(launcher, "dndArea")
430+ var quickList = findChild(launcher, "quickList")
431+ var quickListShape = findChild(launcher, "quickListShape")
396
432
397 // Initial state
433 // Initial state
398− compare(dndArea.quickListPopover, null)
434+ tryCompare(quickListShape, "visible", false)
399
435
400 // Doing longpress
436 // Doing longpress
401 mousePress(clickedItem, clickedItem.width / 2, clickedItem.height / 2)
437 mousePress(clickedItem, clickedItem.width / 2, clickedItem.height / 2)
402 tryCompare(clickedItem, "itemOpacity", 0) // Wait for longpress to happen
438 tryCompare(clickedItem, "itemOpacity", 0) // Wait for longpress to happen
403− verify(dndArea.quickListPopover != null)
439+ verify(quickListShape.visible, "QuickList must be visible")
404
440
405 mouseRelease(clickedItem);
441 mouseRelease(clickedItem);
406
442
407− var quickListEntry = findChild(dndArea.quickListPopover, "quickListEntry" + data.index)
443+ var quickListEntry = findChild(quickList, "quickListEntry" + data.index)
408
444
409 signalSpy.clear();
445 signalSpy.clear();
410 signalSpy.signalName = "quickListTriggered"
446 signalSpy.signalName = "quickListTriggered"
@@ -413,7 +449,7 @@ Item {
413
449
414 if (data.clickable) {
450 if (data.clickable) {
415 // QuickList needs to be closed when some clickable item is clicked
451 // QuickList needs to be closed when some clickable item is clicked
416− tryCompare(dndArea, "quickListPopover", null)
452+ tryCompare(quickListShape, "visible", false)
417
453
418 compare(signalSpy.count, 1, "Quicklist signal wasn't triggered")
454 compare(signalSpy.count, 1, "Quicklist signal wasn't triggered")
419 compare(signalSpy.signalArguments[0][0], LauncherModel.get(5).appId)
455 compare(signalSpy.signalArguments[0][0], LauncherModel.get(5).appId)
@@ -422,13 +458,13 @@ Item {
422 } else {
458 } else {
423
459
424 // QuickList must not be closed when a non-clickable item is clicked
460 // QuickList must not be closed when a non-clickable item is clicked
425− verify(dndArea.quickListPopover != null)
461+ verify(quickListShape.visible, "QuickList must be visible")
426
462
427 compare(signalSpy.count, 0, "Quicklist signal must NOT be triggered when clicking a non-clickable item")
463 compare(signalSpy.count, 0, "Quicklist signal must NOT be triggered when clicking a non-clickable item")
428
464
429 // Click somewhere in the empty space to dismiss the quicklist
465 // Click somewhere in the empty space to dismiss the quicklist
430 mouseClick(launcher, launcher.width - units.gu(1), units.gu(1));
466 mouseClick(launcher, launcher.width - units.gu(1), units.gu(1));
431− tryCompare(dndArea, "quickListPopover", null)
467+ tryCompare(quickListShape, "visible", false)
432 }
468 }
433 }
469 }
434 }
470 }
tests/qmltests/Panel/Indicators/tst_DefaultIndicatorWidget.qmlnew file+97
@@ -0,0 +1,97 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtTest 1.0
19+import Unity.Test 0.1 as UT
20+import QMenuModel 0.1
21+import "../../../../Panel/Indicators"
22+
23+Item {
24+ id: testView
25+ width: units.gu(40)
26+ height: units.gu(70)
27+
28+ DefaultIndicatorWidget {
29+ id: widget
30+
31+ anchors {
32+ left: parent.left
33+ top: parent.top
34+ }
35+
36+ busName: "test"
37+ actionsObjectPath: "test"
38+ deviceMenuObjectPath: "test"
39+
40+ rootMenuType: ""
41+
42+ iconSize: units.gu(3.2)
43+ height: units.gu(3)
44+
45+ rootActionState {
46+ icons: [ "image://theme/audio-volume-high", "image://theme/audio-volume-low" ]
47+ leftLabel: "left"
48+ rightLabel: "right"
49+ }
50+ }
51+
52+ UT.UnityTestCase {
53+ name: "DefaultIndicatorWidget"
54+ when: windowShown
55+
56+ function init() {
57+ widget.rootActionState.icons = [];
58+ widget.rootActionState.leftLabel = "";
59+ widget.rootActionState.rightLabel = "";
60+ wait(50);
61+ }
62+
63+ function test_guRoundedWidth_data() {
64+ return [
65+ { tag: "empty", icons: [], leftLabel: "", rightLabel: "" },
66+ { tag: "1-icon-no-label", icons: [ "image://theme/audio-volume-high" ], leftLabel: "", rightLabel: "" },
67+ { tag: "2-icon-no-label", icons: [ "image://theme/audio-volume-high", "image://theme/audio-volume-low" ], leftLabel: "", rightLabel: "" },
68+ { tag: "no-icon-l-label", icons: [], leftLabel: "left", rightLabel: "" },
69+ { tag: "no-icon-lr-label", icons: [], leftLabel: "left", rightLabel: "right" },
70+ { tag: "1-icon-l-label", icons: [ "image://theme/audio-volume-high" ], leftLabel: "left", rightLabel: "" },
71+ { tag: "1-icon-lr-label", icons: [ "image://theme/audio-volume-high" ], leftLabel: "left", rightLabel: "right" },
72+ { tag: "2-icon-l-label", icons: [ "image://theme/audio-volume-high", "image://theme/audio-volume-low" ], leftLabel: "left", rightLabel: "" },
73+ { tag: "2-icon-lr-label", icons: [ "image://theme/audio-volume-high", "image://theme/audio-volume-low" ], leftLabel: "left", rightLabel: "right" }
74+ ];
75+ }
76+
77+ function test_guRoundedWidth(data) {
78+ widget.rootActionState.icons = data.icons
79+ widget.rootActionState.leftLabel = data.leftLabel;
80+ widget.rootActionState.rightLabel = data.rightLabel;
81+ wait(50);
82+
83+ compare(widget.width, guRoundUp(widget.width));
84+ }
85+ }
86+
87+ // TODO: Use toolkit function https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1242575
88+ function guRoundUp(width) {
89+ if (width == 0) {
90+ return 0;
91+ }
92+ var gu1 = units.gu(1.0);
93+ var mod = (width % gu1);
94+
95+ return mod == 0 ? width : width + (gu1 - mod);
96+ }
97+}
tests/qmltests/Panel/tst_Panel.qml−1
@@ -52,7 +52,6 @@ Item {
52 {tag: "fullscreen", fullscreenFlag: true }
52 {tag: "fullscreen", fullscreenFlag: true }
53 ]}
53 ]}
54
54
55−
56 function init() {
55 function init() {
57 searchClicked = false;
56 searchClicked = false;
58 panel.indicators.hide();
57 panel.indicators.hide();
tests/qmltests/tst_Shell.qml+85−22
@@ -55,19 +55,42 @@ Item {
55 when: windowShown
55 when: windowShown
56
56
57 function initTestCase() {
57 function initTestCase() {
58− swipeAwayGreeter();
58+ var ok = false;
59+ var attempts = 0;
60+ var maxAttempts = 1000;
61+
62+ // Qt loads a qml scene asynchronously. So early on, some findChild() calls made in
63+ // tests may fail because the desired child item wasn't loaded yet.
64+ // Thus here we try to ensure the scene has been fully loaded before proceeding with the tests.
65+ // As I couldn't find an API in QQuickView & friends to tell me that the scene is 100% loaded
66+ // (all items instantiated, etc), I resort to checking the existence of some key items until
67+ // repeatedly until they're all there.
68+ do {
69+ var dashContentList = findChild(shell, "dashContentList");
70+ waitForRendering(dashContentList);
71+ var homeLoader = findChild(dashContentList, "home.scope loader");
72+ ok = homeLoader !== undefined
73+ && homeLoader.item !== undefined;
59
74
60− // Ensure DashHome is loaded before continuing
75+ var greeter = findChild(shell, "greeter");
61− var dashContentList = findChild(shell, "dashContentList");
76+ ok &= greeter !== undefined;
62− waitForRendering(dashContentList);
77+
63− var homeLoader = findChild(dashContentList, "home.scope loader");
78+ var launcherPanel = findChild(shell, "launcherPanel");
64− verify(homeLoader);
79+ ok &= launcherPanel !== undefined;
65− tryCompareFunction(function() {return homeLoader.item !== undefined;}, true);
80+
81+ attempts++;
82+ if (!ok) {
83+ console.log("Attempt " + attempts + " failed. Waiting a bit before trying again.");
84+ // wait a bit before retrying
85+ wait(100);
86+ } else {
87+ console.log("All seem fine after " + attempts + " attempts.");
88+ }
89+ } while (!ok && attempts <= maxAttempts);
66
90
67− // FIXME: Desperate measure to ensure Jenkins has the scene graph fully loaded
91+ verify(ok);
68− // before it calls the test functions (otherwise findChild calls will fail).
92+
69− // The code above just didn't solve it.
93+ swipeAwayGreeter();
70− wait(2000);
71 }
94 }
72
95
73 function cleanup() {
96 function cleanup() {
@@ -111,14 +134,14 @@ Item {
111 waitUntilApplicationWindowIsFullyVisible();
134 waitUntilApplicationWindowIsFullyVisible();
112
135
113 // Minimize the application we just launched
136 // Minimize the application we just launched
114− swipeFromLeftEdge();
137+ swipeFromLeftEdge(units.gu(27));
115
138
116 waitForUIToSettle();
139 waitForUIToSettle();
117
140
118 checkRightEdgeDragWithMinimizedApp();
141 checkRightEdgeDragWithMinimizedApp();
119
142
120 // Minimize that application once again
143 // Minimize that application once again
121− swipeFromLeftEdge();
144+ swipeFromLeftEdge(units.gu(27));
122
145
123 // Right edge behavior should now be the same as before that app,
146 // Right edge behavior should now be the same as before that app,
124 // was launched. Manually cleanup beforehand to get to initial
147 // was launched. Manually cleanup beforehand to get to initial
@@ -130,8 +153,10 @@ Item {
130
153
131 function test_leftEdgeDrag_data() {
154 function test_leftEdgeDrag_data() {
132 return [
155 return [
133− {tag: "without launcher", revealLauncher: false},
156+ {tag: "without launcher", revealLauncher: false, swipeLength: units.gu(27), appHides: true},
134− {tag: "with launcher", revealLauncher: true},
157+ {tag: "with launcher", revealLauncher: true, swipeLength: units.gu(27), appHides: true},
158+ {tag: "small swipe", revealLauncher: false, swipeLength: units.gu(25), appHides: false},
159+ {tag: "long swipe", revealLauncher: false, swipeLength: units.gu(27), appHides: true}
135 ];
160 ];
136 }
161 }
137
162
@@ -144,8 +169,11 @@ Item {
144 dragLauncherIntoView();
169 dragLauncherIntoView();
145 }
170 }
146
171
147− swipeFromLeftEdge();
172+ swipeFromLeftEdge(data.swipeLength);
173+ if (data.appHides)
148− waitUntilApplicationWindowIsFullyHidden();
174+ waitUntilApplicationWindowIsFullyHidden();
175+ else
176+ waitUntilApplicationWindowIsFullyVisible();
149 }
177 }
150
178
151 function test_suspend() {
179 function test_suspend() {
@@ -292,8 +320,12 @@ Item {
292
320
293 waitUntilApplicationWindowIsFullyVisible();
321 waitUntilApplicationWindowIsFullyVisible();
294
322
323+ // Dragging launcher into view with a little bit of gap (units.gu(1)) should switch to Apps scope
324+ dragLauncherIntoView();
325+ verify(itemIsOnScreen(dashApps));
326+
295 // Minimize the application we just launched
327 // Minimize the application we just launched
296− swipeFromLeftEdge();
328+ swipeFromLeftEdge(units.gu(27));
297
329
298 // Wait for the whole UI to settle down
330 // Wait for the whole UI to settle down
299 waitUntilApplicationWindowIsFullyHidden();
331 waitUntilApplicationWindowIsFullyHidden();
@@ -376,10 +408,10 @@ Item {
376 }
408 }
377 }
409 }
378
410
379− function swipeFromLeftEdge() {
411+ function swipeFromLeftEdge(swipeLength) {
380 var touchStartX = 2;
412 var touchStartX = 2;
381 var touchStartY = shell.height / 2;
413 var touchStartY = shell.height / 2;
382− touchFlick(shell, touchStartX, touchStartY, shell.width * 0.75, touchStartY);
414+ touchFlick(shell, touchStartX, touchStartY, swipeLength, touchStartY);
383 }
415 }
384
416
385 function swipeLeftFromCenter() {
417 function swipeLeftFromCenter() {
@@ -432,7 +464,7 @@ Item {
432 } while (!isStill);
464 } while (!isStill);
433 }
465 }
434
466
435− function test_wallpaper_data() {
467+ function test_background_data() {
436 return [
468 return [
437 {tag: "red", url: "tests/data/unity/backgrounds/red.png", expectedUrl: "tests/data/unity/backgrounds/red.png"},
469 {tag: "red", url: "tests/data/unity/backgrounds/red.png", expectedUrl: "tests/data/unity/backgrounds/red.png"},
438 {tag: "blue", url: "tests/data/unity/backgrounds/blue.png", expectedUrl: "tests/data/unity/backgrounds/blue.png"},
470 {tag: "blue", url: "tests/data/unity/backgrounds/blue.png", expectedUrl: "tests/data/unity/backgrounds/blue.png"},
@@ -441,13 +473,21 @@ Item {
441 ]
473 ]
442 }
474 }
443
475
444− function test_wallpaper(data) {
476+ function test_background(data) {
445 var backgroundImage = findChild(shell, "backgroundImage")
477 var backgroundImage = findChild(shell, "backgroundImage")
446 GSettingsController.setPictureUri(data.url)
478 GSettingsController.setPictureUri(data.url)
447 tryCompareFunction(function() { return backgroundImage.source.toString().indexOf(data.expectedUrl) !== -1; }, true)
479 tryCompareFunction(function() { return backgroundImage.source.toString().indexOf(data.expectedUrl) !== -1; }, true)
448 tryCompare(backgroundImage, "status", Image.Ready)
480 tryCompare(backgroundImage, "status", Image.Ready)
449 }
481 }
450
482
483+ function test_lockscreen_background() {
484+ var backgroundImage = findChild(shell, "backgroundImage")
485+ var lockscreen = findChild(shell, "lockscreen")
486+ var lockscreenBackground = findChild(lockscreen, "lockscreenBackground")
487+ var lockscreenBackgroundMapped = lockscreenBackground.mapToItem(shell, 0, 0)
488+ compare(backgroundImage.y, lockscreenBackgroundMapped.y)
489+ }
490+
451 function test_DashShown_data() {
491 function test_DashShown_data() {
452 return [
492 return [
453 {tag: "in focus", greeter: false, app: false, launcher: false, indicators: false, expectedShown: true},
493 {tag: "in focus", greeter: false, app: false, launcher: false, indicators: false, expectedShown: true},
@@ -483,5 +523,28 @@ Item {
483 var dash = findChild(shell, "dash");
523 var dash = findChild(shell, "dash");
484 tryCompare(dash, "shown", data.expectedShown);
524 tryCompare(dash, "shown", data.expectedShown);
485 }
525 }
526+
527+ function test_searchIndicatorHidesOnAppFocus() {
528+ var searchIndicator = findChild(shell, "container")
529+ tryCompare(searchIndicator, "opacity", 1)
530+ dragLauncherIntoView();
531+
532+ // Launch an app from the launcher
533+ tapOnAppIconInLauncher();
534+ waitUntilApplicationWindowIsFullyVisible();
535+
536+ tryCompare(searchIndicator, "opacity", 0);
537+ }
538+
539+ function test_searchIndicatorHidesOnGreeterShown() {
540+ var searchIndicator = findChild(shell, "container")
541+ var greeter = findChild(shell, "greeter");
542+
543+ tryCompare(searchIndicator, "opacity", 1)
544+
545+ greeter.show()
546+ tryCompare(greeter, "shown", true)
547+ tryCompare(searchIndicator, "opacity", 0)
548+ }
486 }
549 }
487}
550}
tests/utils/modules/Unity/Test/UnityTestCase.qml+34
@@ -14,6 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17+import QtQuick 2.0
17import QtTest 1.0
18import QtTest 1.0
18import Ubuntu.Components 0.1
19import Ubuntu.Components 0.1
19import Unity.Test 0.1 as UT
20import Unity.Test 0.1 as UT
@@ -297,4 +298,37 @@ TestCase {
297 event.release(0 /* touchId */, x, y)
298 event.release(0 /* touchId */, x, y)
298 event.commit()
299 event.commit()
299 }
300 }
301+
302+ Component.onCompleted: {
303+ var rootItem = parent;
304+ while (rootItem.parent != undefined) {
305+ rootItem = rootItem.parent;
306+ }
307+ removeTimeConstraintsFromDirectionalDragAreas(rootItem);
308+ }
309+
310+ /*
311+ In qmltests, sequences of touch events are sent all at once, unlike in "real life".
312+ Also qmltests might run really slowly, e.g. when run from inside virtual machines.
313+ Thus to remove a variable that qmltests cannot really control, namely time, this
314+ function removes all constraints from DirectionalDragAreas that are sensible to
315+ elapsed time.
316+
317+ This effectively makes DirectionalDragAreas easier to fool.
318+ */
319+ function removeTimeConstraintsFromDirectionalDragAreas(item) {
320+
321+ // use duck-typing to identify a DirectionalDragArea
322+ if (item.minSpeed != undefined
323+ && item.maxSilenceTime != undefined
324+ && item.compositionTime != undefined) {
325+ item.minSpeed = 0;
326+ item.maxSilenceTime = 60 * 60 * 1000;
327+ item.compositionTime = 0;
328+ } else {
329+ for (var i in item.children) {
330+ removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);
331+ }
332+ }
333+ }
300}
334}