Merge lp:~mzanetti/unity/phablet-folding-launcher into lp:unity/phablet
- phablet-folding-launcher
- Merge into phablet
Status: | Merged |
---|---|
Approved by: | Daniel d'Andrada |
Approved revision: | no longer in the source branch. |
Merged at revision: | 732 |
Proposed branch: | lp:~mzanetti/unity/phablet-folding-launcher |
Merge into: | lp:unity/phablet |
Diff against target: |
1923 lines (+902/-677) 18 files modified
Launcher/Launcher.qml (+161/-337) Launcher/LauncherDelegate.qml (+127/-0) Launcher/LauncherPanel.qml (+82/-279) Shell.qml (+13/-21) plugins/Ubuntu/Gestures/DirectionalDragArea.cpp (+11/-4) plugins/Ubuntu/Gestures/DirectionalDragArea.h (+3/-2) plugins/Unity/CMakeLists.txt (+1/-0) plugins/Unity/launchermodel.cpp (+153/-0) plugins/Unity/launchermodel.h (+86/-0) plugins/Unity/plugin.cpp (+3/-0) tests/autopilot/qml_phone_shell/tests/helpers.py (+1/-1) tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp (+3/-1) tests/qmltests/CMakeLists.txt (+1/-1) tests/qmltests/Launcher/tst_Launcher.qml (+17/-31) tests/qmltests/plugins/Unity/CMakeLists.txt (+1/-0) tests/qmltests/plugins/Unity/fake_launchermodel.cpp (+150/-0) tests/qmltests/plugins/Unity/fake_launchermodel.h (+86/-0) tests/qmltests/plugins/Unity/fake_unity_plugin.cpp (+3/-0) |
To merge this branch: | bzr merge lp:~mzanetti/unity/phablet-folding-launcher |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Daniel d'Andrada (community) | Approve | ||
Michał Sawicz | Needs Information | ||
Review via email: mp+166000@code.launchpad.net |
Commit message
refactored launcher
- moved dummy data one level towards real implementation
- throw away all unused demo experiments from the launcher
- add folding effect
- preliminary (and disabled) drag'n'drop feature for icons
Description of the change
Ugly dummy data will of course be removed again when switching to real API.
preliminary drag and drop support in there is disabled as its not really working anyways. This will be fixed/completed in next steps.
This also fixes a signal in the DirectionalDrag
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:630
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:632
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:635
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:636
http://
Executed test runs:
ABORTED: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:636
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:637
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:637
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
My 2¢ here:
* feels like the long-drag-
* when (un)folding, the icons change in distance from the adjacent, unfolded icon - that's not necessarily bad, just noting to make sure that's ok with design
Daniel d'Andrada (dandrader) wrote : | # |
Good refactoring and clean up. Looks way better now!
=======
Icons are not getting highlighted when pressed. The only way I could get an icon highlighted was by long-pressing it.
=======
The branch alone works fine, but if I merge it with latest trunk it get the following wrong behavior:
I have an application on foreground. Right from the beginning of a left-edge drag the application window slides rightwards instead of only after the launcher is fully revealed.
=======
+ MouseArea {
+ id: closeMouseArea
+ enabled: root.state == "visible"
+ anchors.fill: panel
+ anchors.
+ drag {
+ axis: Drag.XAxis
+ maximumX: 0
+ target: panel
+ }
+
+ onReleased: {
+ if (panel.x < -panel.width/3) {
+ root.switchToNe
+ } else {
+ root.switchToNe
}
}
- }
- function hide() {
- launcher.state = ""
+ }
+ MouseArea {
+ anchors {
+ left: closeMouseArea.
+ top: parent.top
+ right: parent.right
+ bottom: parent.bottom
+ }
+ enabled: root.state == "visible"
+ onPressed: {
+ root.state = ""
+ }
}
I think second MouseArea should be the one named "closeMouseArea" (as it closes the launcher when clicked), not the first one.
=======
+ if (distance > root.width / 2){
Coding style: spacing between ')' and '{'
=======
- default: // Rejected
+ case Rejected:
+ Q_EMIT draggingChanged
+ break;
+ default:
// no-op
break;
Since the default case now deals specifically with invalid states, we could make it issue a qFatal().
=======
You can remove this line from Launcher.qml:
import "../Application
And this one from tst_Launcher.qml:
import "../../
=======
In Shell.qml:
"""
+ InputFilterArea {
+ blockInput: launcher.shown
+ anchors {
+ top: parent.top
+ bottom: parent.bottom
+ left: parent.left
+ }
+ width: launcher.shown ? launcher.width : launcher.panelWidth
+ }
"""
Why not make width just:
+ width: launcher.width
Afterall it only works when launcher.shown is true anyway.
=======
tst_Launcher fails to run due to missing symbols, related to "import Unity 0.1".
Michael Zanetti (mzanetti) wrote : | # |
> My 2¢ here:
> * feels like the long-drag-
> (behavior?) between the finger and the app edge
Hmm... might be this:
Behavior on x {SmoothedAnimat
However, I did not touch this and the current launcher has the same. If it would be just some NumberAnimation I would disable it while dragging, but as it is a SmoothedAnimation with some velocity it seems kinda intentional. I'll have a chat with Vesa about it.
> * when (un)folding, the icons change in distance from the adjacent, unfolded
> icon - that's not necessarily bad, just noting to make sure that's ok with
> design
Hmm... this seems to be pretty much the same distance as it is on the desktop. However, next steps in the design work is to figure how many folded items should be visible. Depending on how the others will fade out, this most likely will still change by design.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:639
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
> Icons are not getting highlighted when pressed. The only way I could get an
> icon highlighted was by long-pressing it.
fixed.
> =======
>
> The branch alone works fine, but if I merge it with latest trunk it get the
> following wrong behavior:
> I have an application on foreground. Right from the beginning of a left-edge
> drag the application window slides rightwards instead of only after the
> launcher is fully revealed.
Hmm... Can't reproduce. After merging it still seems to be the same for me.
> =======
>
> + MouseArea {
> + id: closeMouseArea
> + enabled: root.state == "visible"
> + anchors.fill: panel
> + anchors.
> + drag {
> + axis: Drag.XAxis
> + maximumX: 0
> + target: panel
> + }
> +
> + onReleased: {
> + if (panel.x < -panel.width/3) {
> + root.switchToNe
> + } else {
> + root.switchToNe
> }
> }
> - }
>
> - function hide() {
> - launcher.state = ""
> + }
> + MouseArea {
> + anchors {
> + left: closeMouseArea.
> + top: parent.top
> + right: parent.right
> + bottom: parent.bottom
> + }
> + enabled: root.state == "visible"
> + onPressed: {
> + root.state = ""
> + }
> }
>
> I think second MouseArea should be the one named "closeMouseArea" (as it
> closes the launcher when clicked), not the first one.
Fixed.
> =======
>
> + if (distance > root.width / 2){
>
> Coding style: spacing between ')' and '{'
Fixed.
> =======
>
> - default: // Rejected
> + case Rejected:
> + Q_EMIT draggingChanged
> + break;
> + default:
> // no-op
> break;
>
> Since the default case now deals specifically with invalid states, we could
> make it issue a qFatal().
How I read it, the default case is still valid for the Recognized state.
> =======
>
> You can remove this line from Launcher.qml:
>
> import "../Application
>
> And this one from tst_Launcher.qml:
>
> import "../../
fixed.
> =======
>
> In Shell.qml:
>
> """
> + InputFilterArea {
> + blockInput: launcher.shown
> + anchors {
> + top: parent.top
> + bottom: parent.bottom
> + left: parent.left
> + }
> + width: launcher.shown ? launcher.width : launcher.panelWidth
> + }
>
> """
>
> Why not make width just:
>
> + width: launcher.width
>
> Afterall it only works when launcher.shown is true anyway.
Fixed.
> =======
Daniel d'Andrada (dandrader) wrote : | # |
> >
> > The branch alone works fine, but if I merge it with latest trunk it get the
> > following wrong behavior:
> > I have an application on foreground. Right from the beginning of a left-edge
> > drag the application window slides rightwards instead of only after the
> > launcher is fully revealed.
>
> Hmm... Can't reproduce. After merging it still seems to be the same for me.
Well, it's also working fine for me now. Let's forget about it then. :)
> >
> > - default: // Rejected
> > + case Rejected:
> > + Q_EMIT draggingChanged
> > + break;
> > + default:
> > // no-op
> > break;
> >
> > Since the default case now deals specifically with invalid states, we could
> > make it issue a qFatal().
>
> How I read it, the default case is still valid for the Recognized state.
Right!
Daniel d'Andrada (dandrader) wrote : | # |
One last detail I just spotted:
plugins/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:643
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
> plugins/
> [-Wunused-
fixed
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:645
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:646
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
All good.
Do you think it makes sense to fix those warnings that are output when tst_Launcher.qml is run?
Michael Zanetti (mzanetti) wrote : | # |
> Do you think it makes sense to fix those warnings that are output when
> tst_Launcher.qml is run?
Done.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:647
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'Launcher/Launcher.qml' |
2 | --- Launcher/Launcher.qml 2013-05-27 15:12:07 +0000 |
3 | +++ Launcher/Launcher.qml 2013-06-04 12:32:22 +0000 |
4 | @@ -18,401 +18,225 @@ |
5 | import "../Components" |
6 | import Ubuntu.Components 0.1 |
7 | import Ubuntu.Gestures 0.1 |
8 | -import "../Applications/applications.js" as ApplicationsModel |
9 | +import Unity 0.1 |
10 | |
11 | Item { |
12 | - id: launcher |
13 | - |
14 | - property var favourites: ["/usr/share/applications/phone-app.desktop", |
15 | - "/usr/share/applications/camera-app.desktop", |
16 | - "/usr/share/applications/gallery-app.desktop", |
17 | - "/usr/share/applications/facebook-webapp.desktop", |
18 | - "/usr/share/applications/webbrowser-app.desktop", |
19 | - "/usr/share/applications/twitter-webapp.desktop", |
20 | - "/usr/share/applications/gmail-webapp.desktop", |
21 | - "/usr/share/applications/ubuntu-weather-app.desktop", |
22 | - "/usr/share/applications/notes-app.desktop", |
23 | - "/usr/share/applications/ubuntu-calendar-app.desktop"] |
24 | - property ListModel model: ListModel {} |
25 | - property ListModel applicationsRunning: ListModel {} |
26 | - property int lastFavouriteIndex: -1 |
27 | + id: root |
28 | |
29 | property bool available: true // can be used to disable all interactions |
30 | - property bool applicationFocused: false |
31 | - |
32 | - property bool shown: launcher.state != "" |
33 | - property int progress |
34 | - progress: { |
35 | - if (launcher.state == "spreadMoving") |
36 | - return dragArea.distance |
37 | - else if (launcher.state == "spread") |
38 | - return launcher.width |
39 | - else |
40 | - return 0 |
41 | - } |
42 | - |
43 | - // Thresholds and dimensions |
44 | - property int shortcutsHintWidth: units.gu(3) |
45 | - property int shortcutsWidth: units.gu(6) |
46 | - property int shortcutsThreshold: units.dp(2) |
47 | - property int shortcutsCloseThreshold: units.gu(1) |
48 | - property int spreadHintThreshold: shortcutsWidth |
49 | - property int spreadOutThreshold: units.gu(18) |
50 | - |
51 | - // For how long (in milliseconds) the launcher will stay up without being |
52 | - // interacted with, before it finally hides itself. |
53 | - property int inactivityTimeout: 8000 |
54 | - |
55 | - property string iconPath: "." |
56 | - |
57 | - property int launcherProgressValue |
58 | - launcherProgressValue: { |
59 | - if (launcher.state == "" |
60 | - || launcher.state == "hint" |
61 | - || launcher.state == "moving" |
62 | - || launcher.state == "shortcuts") { |
63 | - return 0 |
64 | - } else if (launcher.state == "spreadHint") { |
65 | - return units.gu(17) |
66 | - } else if (launcher.state == "spreadMoving") { |
67 | - return units.gu(22) |
68 | - } else if (launcher.state == "spread") { |
69 | - return units.gu(28) |
70 | - } |
71 | - } |
72 | |
73 | property bool teasing: false |
74 | - |
75 | - signal launcherApplicationSelected(string name) |
76 | - signal dashItemSelected(int itemIndex) |
77 | - |
78 | + property int panelWidth: units.gu(8.5) |
79 | + property int dragAreaWidth: units.gu(1) |
80 | + property real progress: dragArea.dragging && dragArea.touchX > panel.width ? dragArea.touchX : 0 |
81 | + |
82 | + readonly property bool shown: panel.x > -panel.width |
83 | + |
84 | + // emitted when an application is selected |
85 | + signal launcherApplicationSelected(string desktopFile) |
86 | + |
87 | + // emitted when the apps dash should be shown because of a swipe gesture |
88 | signal dash() |
89 | |
90 | + // emitted when the dash icon in the launcher has been tapped |
91 | + signal dashItemSelected() |
92 | + |
93 | + onStateChanged: { |
94 | + if (state == "") { |
95 | + dismissTimer.stop() |
96 | + } else { |
97 | + dismissTimer.restart() |
98 | + } |
99 | + } |
100 | + |
101 | + function hide() { |
102 | + state = "" |
103 | + } |
104 | + |
105 | + function switchToNextState(state) { |
106 | + animateTimer.nextState = state |
107 | + animateTimer.start(); |
108 | + } |
109 | + |
110 | onTeasingChanged: { |
111 | if (teasing) { |
112 | - hintTimer.restart(); |
113 | + teaseTimer.start(); |
114 | } |
115 | } |
116 | |
117 | Timer { |
118 | - id: hintTimer |
119 | + id: teaseTimer |
120 | interval: 200 |
121 | } |
122 | |
123 | - // internal properties hidden from public api |
124 | - QtObject { |
125 | - id: priv |
126 | - |
127 | - property bool shortcutAnimationOngoing |
128 | - property string previousStateHelp |
129 | - property string previousState: "" |
130 | - property string teasing: launcher.teasing || hintTimer.running |
131 | - } |
132 | - |
133 | - onStateChanged: { |
134 | - priv.previousState = priv.previousStateHelp |
135 | - priv.previousStateHelp = state |
136 | - if (launcher.state != "shorcuts") { |
137 | - dismissTimer.stop() |
138 | - } |
139 | - |
140 | - if (launcher.state == "spread") { |
141 | - dragArea.visible = false |
142 | - hideTimer.restart() |
143 | - dragArea.visible = true |
144 | - } |
145 | - //console.log("Launcher state: " + state) |
146 | - } |
147 | - |
148 | - Component.onCompleted: { |
149 | - __populateWithFavouriteApplications(); |
150 | - } |
151 | - |
152 | - function __populateWithFavouriteApplications() { |
153 | - for (var i=0; i<launcher.favourites.length; i++) { |
154 | - var desktopFile = launcher.favourites[i]; |
155 | - var application = ApplicationsModel.__availableApplications[desktopFile]; |
156 | - if (application) { |
157 | - application["desktopFile"] = desktopFile; |
158 | - launcher.model.append(application); |
159 | - } |
160 | - } |
161 | - } |
162 | - |
163 | - function hide() { |
164 | - launcher.state = "" |
165 | + Timer { |
166 | + id: dismissTimer |
167 | + interval: 5000 |
168 | + onTriggered: { |
169 | + if (!panel.moving) { |
170 | + root.state = "" |
171 | + } else { |
172 | + dismissTimer.restart() |
173 | + } |
174 | + } |
175 | + } |
176 | + |
177 | + // Because the animation on x is disabled while dragging |
178 | + // switching state directly in the drag handlers would not animate |
179 | + // the completion of the hide/reveal gesture. Lets update the state |
180 | + // machine and switch to the final state in the next event loop run |
181 | + Timer { |
182 | + id: animateTimer |
183 | + interval: 1 |
184 | + property string nextState: "" |
185 | + onTriggered: { |
186 | + // switching to an intermediate state here to make sure all the |
187 | + // values are restored, even if we were already in the target state |
188 | + root.state = "tmp" |
189 | + root.state = nextState |
190 | + } |
191 | + } |
192 | + |
193 | + LauncherModel { |
194 | + id: launcherModel |
195 | + } |
196 | + |
197 | + MouseArea { |
198 | + id: launcherDragArea |
199 | + enabled: root.state == "visible" |
200 | + anchors.fill: panel |
201 | + anchors.rightMargin: -units.gu(2) |
202 | + drag { |
203 | + axis: Drag.XAxis |
204 | + maximumX: 0 |
205 | + target: panel |
206 | + } |
207 | + |
208 | + onReleased: { |
209 | + if (panel.x < -panel.width/3) { |
210 | + root.switchToNextState("") |
211 | + } else { |
212 | + root.switchToNextState("visible") |
213 | + } |
214 | + } |
215 | + |
216 | + } |
217 | + MouseArea { |
218 | + id: closeMouseArea |
219 | + anchors { |
220 | + left: launcherDragArea.right |
221 | + top: parent.top |
222 | + right: parent.right |
223 | + bottom: parent.bottom |
224 | + } |
225 | + enabled: root.state == "visible" |
226 | + onPressed: { |
227 | + root.state = "" |
228 | + } |
229 | } |
230 | |
231 | Rectangle { |
232 | id: backgroundShade |
233 | anchors.fill: parent |
234 | color: "black" |
235 | - opacity: { |
236 | - if (launcher.state == "" || launcher.state == "hint" || launcher.state == "moving") { |
237 | - return 0 |
238 | - } else return 0.4 |
239 | - } |
240 | - visible: opacity != 0 |
241 | + opacity: root.state == "visible" ? 0.4 : 0 |
242 | |
243 | Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.OutQuad} } |
244 | - |
245 | - MouseArea { |
246 | - anchors.fill: parent |
247 | - onClicked: { |
248 | - launcher.state = "" |
249 | - } |
250 | - visible: launcher.state != "spread" |
251 | - } |
252 | } |
253 | |
254 | - LauncherShortcuts { |
255 | - id: shortcuts |
256 | - objectName: "shortcuts" |
257 | - width: shortcutsWidth |
258 | + LauncherPanel { |
259 | + id: panel |
260 | + objectName: "launcherPanel" |
261 | + width: root.panelWidth |
262 | anchors { |
263 | top: parent.top |
264 | bottom: parent.bottom |
265 | } |
266 | x: -width |
267 | - model: launcher.model |
268 | + model: launcherModel |
269 | + |
270 | + property bool animate: true |
271 | + |
272 | onApplicationSelected: { |
273 | - launcher.state = "" |
274 | + root.state = "" |
275 | launcherApplicationSelected(desktopFile) |
276 | } |
277 | onDashItemSelected: { |
278 | - launcher.state = "" |
279 | - launcher.dashItemSelected(index) |
280 | - } |
281 | - iconPath: launcher.iconPath |
282 | - |
283 | - Behavior on x { NumberAnimation {duration: launcher.state == "hint" ? 70 : launcher.state == "moving" ? 0 : 300; easing.type: Easing.OutCubic } } |
284 | + root.state = "" |
285 | + root.dashItemSelected(index) |
286 | + } |
287 | + |
288 | + onMovingChanged: { |
289 | + if (dismissTimer.running) { |
290 | + dismissTimer.restart(); |
291 | + } |
292 | + } |
293 | + |
294 | + Behavior on x { |
295 | + NumberAnimation { |
296 | + // Disabling animation when dragging |
297 | + duration: dragArea.dragging || launcherDragArea.drag.active ? 0 : 300; |
298 | + easing.type: Easing.OutCubic |
299 | + } |
300 | + } |
301 | } |
302 | |
303 | DirectionalDragArea { |
304 | id: dragArea |
305 | - enabled: launcher.state != "shortcuts" || dragging |
306 | |
307 | direction: DirectionalDragArea.Rightwards |
308 | |
309 | // values to be tweaked and later removed from here and set in stone as defaults |
310 | // once we are confident it's all good. |
311 | maxDeviation: units.gu(1.5) |
312 | - wideningAngle: 10 |
313 | + wideningAngle: 30 |
314 | distanceThreshold: units.gu(4) |
315 | |
316 | - visible: launcher.available |
317 | - width: { |
318 | - if (launcher.state == "") { |
319 | - return shortcutsThreshold |
320 | - } else { |
321 | - return shortcutsWidth |
322 | + enabled: root.available && root.state !== "visible" |
323 | + width: root.dragAreaWidth |
324 | + height: root.height |
325 | + |
326 | + onTouchXChanged: { |
327 | + if (dragging) { |
328 | + panel.x = Math.min(0, touchX - panel.width); |
329 | } |
330 | } |
331 | - height: launcher.height |
332 | |
333 | onDraggingChanged: { |
334 | - if (dragging) |
335 | - onDragStarted() |
336 | - else |
337 | - onDragEnded() |
338 | - } |
339 | - |
340 | - function onDragStarted() { |
341 | - if (launcher.state == "") launcher.state = "hint" |
342 | - dismissTimer.stop() |
343 | - } |
344 | - |
345 | - onDistanceChanged: { |
346 | - if (launcher.state == "shortcuts" && distance < shortcutsCloseThreshold) { |
347 | - launcher.state = "" |
348 | - } else if (launcher.state == "hint" && distance > 0 ) { |
349 | - launcher.state = "moving" |
350 | - } else if (distance > shortcutsThreshold && distance < spreadHintThreshold) { |
351 | - launcher.state = "shortcuts" |
352 | - } else if (distance >= spreadHintThreshold && distance < shortcutsWidth) { |
353 | - if (launcher.applicationFocused){ |
354 | - launcher.state = "spreadHint" |
355 | - } |
356 | - } else if (distance >= shortcutsWidth && distance < spreadOutThreshold) { |
357 | - if (launcher.applicationFocused) { |
358 | - launcher.state = "spreadMoving" |
359 | + if (!dragging) { |
360 | + if (distance > root.width / 2) { |
361 | + root.dash() |
362 | + root.switchToNextState("") |
363 | + } else if (distance > panel.width/2) { |
364 | + root.switchToNextState("visible") |
365 | } else { |
366 | - dismissTimer.restart() |
367 | - } |
368 | - } else if (distance >= spreadOutThreshold && launcher.applicationFocused) { |
369 | - launcher.state = "spread" |
370 | - } |
371 | - } |
372 | - |
373 | - function onDragEnded() { |
374 | - var currentApplicationIndex |
375 | - if (launcher.state == "shortcuts" && !priv.shortcutAnimationOngoing) { |
376 | - // launch app |
377 | - currentApplicationIndex = shortcuts.selectCurrentApplication() |
378 | - if (currentApplicationIndex === 0) { |
379 | - launcher.dashItemSelected(0) |
380 | - launcher.state = "" |
381 | - } else if (currentApplicationIndex === -1) { |
382 | - launcher.state = "shortcuts" |
383 | - } |
384 | - } |
385 | - |
386 | - if (launcher.state == "hint" || launcher.state == "moving") { |
387 | - launcher.state = "" |
388 | - } else if (launcher.state == "spreadMoving" || launcher.state == "spreadHint") { |
389 | - launcher.state = "shortcuts" |
390 | - } |
391 | - |
392 | - shortcuts.stopScroll() |
393 | - |
394 | - if (launcher.state == "shortcuts") { |
395 | - dismissTimer.restart() |
396 | - } |
397 | - |
398 | - } |
399 | - } |
400 | - |
401 | - Timer { |
402 | - id: dismissTimer |
403 | - interval: launcher.inactivityTimeout; |
404 | - running: false; |
405 | - repeat: false |
406 | - onTriggered: { |
407 | - launcher.state = "" |
408 | - } |
409 | - } |
410 | - |
411 | - Timer { |
412 | - id: hideTimer |
413 | - interval: 50; |
414 | - running: false; |
415 | - repeat: false |
416 | - onTriggered: { |
417 | - launcher.state = "" |
418 | + root.switchToNextState("") |
419 | + } |
420 | + } |
421 | } |
422 | } |
423 | |
424 | states: [ |
425 | State { |
426 | - name: "hint" |
427 | - when: priv.teasing |
428 | - PropertyChanges { |
429 | - target: shortcuts |
430 | - x: -shortcuts.width + launcher.shortcutsHintWidth |
431 | - } |
432 | - }, |
433 | - State { |
434 | - name: "moving" |
435 | - PropertyChanges { |
436 | - target: shortcuts |
437 | - x: -shortcuts.width + dragArea.distance + launcher.shortcutsHintWidth |
438 | - } |
439 | - }, |
440 | - State { |
441 | - name: "shortcuts" |
442 | - PropertyChanges { |
443 | - target: shortcuts |
444 | - x: 0 |
445 | - } |
446 | - }, |
447 | - State { |
448 | - name: "spreadHint" |
449 | - extend: "shortcuts" |
450 | - }, |
451 | - State { |
452 | - name: "spreadMoving" |
453 | - PropertyChanges { |
454 | - target: launcher |
455 | - launcherProgressValue: dragArea.distance |
456 | - } |
457 | - PropertyChanges { |
458 | - target: shortcuts |
459 | - x: 0 |
460 | - } |
461 | - }, |
462 | - State { |
463 | - name: "spread" |
464 | - extend: "shortcuts" |
465 | - } |
466 | - |
467 | - ] |
468 | - |
469 | - transitions: [ |
470 | - Transition { |
471 | - to: "" |
472 | - SequentialAnimation { |
473 | - PropertyAnimation { |
474 | - target: shortcuts |
475 | - properties: "x" |
476 | - duration: 400 |
477 | - easing.type: Easing.OutCubic |
478 | - } |
479 | - ScriptAction { |
480 | - script: { |
481 | - shortcuts.resetScrollPosition() |
482 | - } |
483 | - } |
484 | - } |
485 | - }, |
486 | - Transition { |
487 | - to: "hint" |
488 | - PropertyAnimation { |
489 | - target: shortcuts |
490 | - properties: "x" |
491 | - duration: 400 |
492 | - easing.type: Easing.OutCubic |
493 | - } |
494 | - }, |
495 | - Transition { |
496 | - to: "shortcuts" |
497 | - SequentialAnimation { |
498 | - ScriptAction { |
499 | - script: { |
500 | - if (priv.previousState == "moving") { |
501 | - priv.shortcutAnimationOngoing = true |
502 | - } |
503 | - } |
504 | - } |
505 | - ParallelAnimation { |
506 | - SequentialAnimation { |
507 | - PropertyAnimation { |
508 | - target: shortcuts |
509 | - properties: "x" |
510 | - duration: 300 |
511 | - easing.type: Easing.OutCubic |
512 | - } |
513 | - ScriptAction { |
514 | - script: { |
515 | - priv.shortcutAnimationOngoing = false |
516 | - } |
517 | - } |
518 | - } |
519 | - } |
520 | - } |
521 | - }, |
522 | - Transition { |
523 | - to: "spreadHint" |
524 | - PropertyAnimation { |
525 | - target: shortcuts |
526 | - properties: "x" |
527 | - duration: 300 |
528 | - easing.type: Easing.OutCubic |
529 | - } |
530 | - }, |
531 | - Transition { |
532 | - to: "spreadMoving" |
533 | - ScriptAction { |
534 | - script: { |
535 | - priv.shortcutAnimationOngoing = false |
536 | - } |
537 | - } |
538 | - }, |
539 | - Transition { |
540 | - to: "spread" |
541 | - ScriptAction { |
542 | - script: { |
543 | - launcher.dash() |
544 | - } |
545 | + name: "" // hidden state. Must be the default state ("") because "when:" falls back to this. |
546 | + PropertyChanges { |
547 | + target: panel |
548 | + x: -root.panelWidth |
549 | + } |
550 | + }, |
551 | + State { |
552 | + name: "visible" |
553 | + PropertyChanges { |
554 | + target: panel |
555 | + x: 0 |
556 | + } |
557 | + }, |
558 | + State { |
559 | + name: "teasing" |
560 | + when: root.teasing || teaseTimer.running |
561 | + PropertyChanges { |
562 | + target: panel |
563 | + x: -root.panelWidth + units.gu(2) |
564 | } |
565 | } |
566 | ] |
567 | |
568 | === added file 'Launcher/LauncherDelegate.qml' |
569 | --- Launcher/LauncherDelegate.qml 1970-01-01 00:00:00 +0000 |
570 | +++ Launcher/LauncherDelegate.qml 2013-06-04 12:32:22 +0000 |
571 | @@ -0,0 +1,127 @@ |
572 | +/* |
573 | + * Copyright (C) 2013 Canonical, Ltd. |
574 | + * |
575 | + * This program is free software; you can redistribute it and/or modify |
576 | + * it under the terms of the GNU General Public License as published by |
577 | + * the Free Software Foundation; version 3. |
578 | + * |
579 | + * This program is distributed in the hope that it will be useful, |
580 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
581 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
582 | + * GNU General Public License for more details. |
583 | + * |
584 | + * You should have received a copy of the GNU General Public License |
585 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
586 | + */ |
587 | + |
588 | +import QtQuick 2.0 |
589 | +import Ubuntu.Components 0.1 |
590 | + |
591 | +Item { |
592 | + id: root |
593 | + |
594 | + property string iconName |
595 | + |
596 | + property real angle: 0 |
597 | + property bool highlighted: false |
598 | + property real offset: 0 |
599 | + |
600 | + property real maxAngle: 0 |
601 | + property bool inverted: false |
602 | + |
603 | + readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * height |
604 | + readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * height |
605 | + |
606 | + property int itemsBeforeThis: 0 |
607 | + property int itemsAfterThis: 0 |
608 | + |
609 | + property bool dragging:false |
610 | + |
611 | + signal clicked() |
612 | + signal longtap() |
613 | + signal released() |
614 | + |
615 | + UbuntuShape { |
616 | + id: iconItem |
617 | + color: Qt.rgba(0, 0, 1, 0.5) |
618 | + width: parent.width |
619 | + height: parent.height |
620 | + anchors.centerIn: parent |
621 | + anchors.verticalCenterOffset: root.offset + (height - root.effectiveHeight)/2 * (angle < 0 ? -1 : 1) |
622 | + rotation: root.inverted ? 180 : 0 |
623 | + radius: "medium" |
624 | + |
625 | + transform: Rotation { |
626 | + axis { x: 1; y: 0; z: 0 } |
627 | + origin { x: iconItem.width / 2; y: iconItem.height / 2; z: 0 } |
628 | + angle: root.angle |
629 | + } |
630 | + |
631 | + image: Image { |
632 | + source: "../graphics/applicationIcons/" + root.iconName + ".png" |
633 | + } |
634 | + |
635 | + MouseArea { |
636 | + id: mouseArea |
637 | + anchors.fill: parent |
638 | + onClicked: root.clicked() |
639 | + onCanceled: root.released() |
640 | + preventStealing: false |
641 | + |
642 | + onPressAndHold: { |
643 | + root.state = "moving" |
644 | + } |
645 | + onReleased: { |
646 | + root.state = "docked" |
647 | + } |
648 | + } |
649 | + |
650 | + BorderImage { |
651 | + id: overlayHighlight |
652 | + anchors.centerIn: iconItem |
653 | + rotation: inverted ? 180 : 0 |
654 | + source: root.highlighted || mouseArea.pressed ? "graphics/selected.sci" : "graphics/non-selected.sci" |
655 | + width: iconItem.width + units.gu(1.5) |
656 | + height: width |
657 | + } |
658 | + } |
659 | + |
660 | + states: [ |
661 | + State { |
662 | + name: "docked" |
663 | + PropertyChanges { |
664 | + target: root |
665 | + offset: if (launcherFlickable.contentY > itemsBeforeThis * (foldedHeight + launcherColumn.spacing*2)) { |
666 | + return launcherFlickable.contentY - (index * (foldedHeight + launcherColumn.spacing*2)); |
667 | + } else if (y + height - launcherFlickable.contentY > launcherFlickable.height - (itemsAfterThis*(foldedHeight - launcherColumn.spacing))) { |
668 | + return launcherFlickable.height - (y+height) + launcherFlickable.contentY - (itemsAfterThis*(foldedHeight - launcherColumn.spacing)); |
669 | + } else { |
670 | + return 0; |
671 | + } |
672 | + angle: -Math.min(Math.max(offset * maxAngle / foldedHeight, -maxAngle), maxAngle) |
673 | + |
674 | + } |
675 | + }, |
676 | + |
677 | + State { |
678 | + name: "moving" |
679 | + PropertyChanges { |
680 | + target: launcherDelegate; |
681 | + offset: 0 |
682 | + angle: 0 |
683 | + } |
684 | + PropertyChanges { |
685 | + target: root |
686 | + highlighted: true |
687 | + dragging: true |
688 | + } |
689 | + PropertyChanges { |
690 | + target: mouseArea |
691 | + preventStealing: true |
692 | + drag.target: root |
693 | + } |
694 | + } |
695 | + |
696 | + ] |
697 | + |
698 | +} |
699 | |
700 | === renamed file 'Launcher/LauncherShortcuts.qml' => 'Launcher/LauncherPanel.qml' |
701 | --- Launcher/LauncherShortcuts.qml 2013-05-27 15:13:11 +0000 |
702 | +++ Launcher/LauncherPanel.qml 2013-06-04 12:32:22 +0000 |
703 | @@ -16,301 +16,104 @@ |
704 | |
705 | import QtQuick 2.0 |
706 | import Ubuntu.Components 0.1 |
707 | +import Unity 0.1 |
708 | |
709 | Item { |
710 | - id: shortcuts |
711 | - |
712 | - property ListModel model |
713 | - property ListModel shortcutsModel: model |
714 | - property ListModel openModel: ListModel{} |
715 | - property ListModel semiFoldedModel: ListModel{} |
716 | - property ListModel foldedModel: ListModel{} |
717 | - |
718 | - property bool enabled: true |
719 | - property string iconPath: "." |
720 | - |
721 | - property bool animating: openShortcuts.animating || semiFoldedShortcut.animating || foldedShortcuts.animating // read only |
722 | - property int currentIndex: -1 |
723 | - |
724 | - property int scrollValue: 0 |
725 | - property bool scrolling: scrollTimer.running |
726 | - |
727 | - property int itemWidth: units.gu(9) |
728 | - property int itemHeight: units.gu(7.5) |
729 | - property int iconWidth: units.gu(7) |
730 | - property int iconHeight: units.gu(6.5) |
731 | - |
732 | - property int iconCount: shortcutsModel.count |
733 | - |
734 | - property int foldedSize: itemWidth - foldedShortcuts.initialFoldedOffset |
735 | - |
736 | - property int openItemsCount |
737 | - property int foldedItemsCount: iconCount - openItemsCount |
738 | - property int fillItemHeight: height - openItemsCount * itemHeight - foldedItemsCount * foldedSize |
739 | - property bool open: false |
740 | + id: root |
741 | + |
742 | + rotation: inverted ? 180 : 0 |
743 | + |
744 | + property var model |
745 | property bool inverted: true |
746 | - property int labelPosition |
747 | - labelPosition: { |
748 | - if (!inverted) { |
749 | - return currentIndex*shortcuts.itemHeight + shortcuts.itemHeight/2 + shortcutsContainer.targetY |
750 | - } else { |
751 | - return shortcuts.height - (currentIndex*shortcuts.itemHeight + shortcuts.itemHeight/2 + shortcutsContainer.targetY) |
752 | - } |
753 | - } |
754 | - |
755 | - rotation: inverted ? 180 : 0 |
756 | - |
757 | - QtObject { |
758 | - id: priv |
759 | - |
760 | - property int modelCount: shortcuts.model ? shortcuts.model.count : 0 |
761 | - } |
762 | + property bool dragging: false |
763 | + property bool moving: launcherFlickable.moving |
764 | + property int dragPosition: 0 |
765 | + property int highlightIndex: -1 |
766 | |
767 | signal applicationSelected(string desktopFile) |
768 | signal dashItemSelected(int index) |
769 | |
770 | - Component.onCompleted: init() |
771 | - |
772 | - function resetScrollPosition() { |
773 | - flickable.contentY = 0 |
774 | - } |
775 | - |
776 | - function init() { |
777 | - clearModels() |
778 | - addDashIcon() |
779 | - calculateOpenIcons() |
780 | - createModels() |
781 | - } |
782 | - |
783 | - function clearModels() { |
784 | - openModel.clear() |
785 | - semiFoldedModel.clear() |
786 | - foldedModel.clear() |
787 | - } |
788 | - |
789 | - function addDashIcon() { |
790 | - shortcutsModel.insert(0, {"desktopFile": "dash.desktop", |
791 | - "name": "Home", |
792 | - "icon": "dash", |
793 | - "exec": "" |
794 | - }); |
795 | - } |
796 | - |
797 | - function calculateOpenIcons() { |
798 | - var foldedSize = (shortcuts.itemHeight - foldedShortcuts.initialFoldedOffset) |
799 | - var maxopenItemsCount = Math.floor(shortcuts.height / shortcuts.itemHeight) |
800 | - var leftOverIcons = shortcuts.iconCount - maxopenItemsCount |
801 | - var leftOverSpace |
802 | - if (leftOverIcons > 0) { |
803 | - leftOverSpace = shortcuts.height - shortcuts.itemHeight * maxopenItemsCount |
804 | - leftOverIcons = leftOverIcons - Math.floor(leftOverSpace / foldedSize) |
805 | - while (leftOverIcons > 0) { |
806 | - maxopenItemsCount-- |
807 | - leftOverIcons = shortcuts.iconCount - maxopenItemsCount |
808 | - if (leftOverIcons > 0) { |
809 | - leftOverSpace = shortcuts.height - shortcuts.itemHeight * maxopenItemsCount |
810 | - leftOverIcons = leftOverIcons - Math.floor(leftOverSpace / foldedSize) |
811 | - } |
812 | - } |
813 | - } |
814 | - shortcuts.openItemsCount = Math.min(maxopenItemsCount, shortcuts.iconCount) |
815 | - shortcuts.visible = true |
816 | - } |
817 | - |
818 | - function createModels() { |
819 | - for (var i = 0; i < shortcutsModel.count; i++) { |
820 | - if (i < shortcuts.openItemsCount) { |
821 | - shortcuts.openModel.append(shortcutsModel.get(i)) |
822 | - } else if (i == shortcuts.openItemsCount) { |
823 | - shortcuts.semiFoldedModel.append(shortcutsModel.get(i)) |
824 | - } else { |
825 | - shortcuts.foldedModel.append(shortcutsModel.get(i)) |
826 | - } |
827 | - } |
828 | - } |
829 | - |
830 | - function scroll() { |
831 | - if (!scrolling && shortcutsContainer.height > shortcuts.height) { |
832 | - var scrollingAtStart = shortcutsContainer.targetY == 0 |
833 | - var scrollingAtEnd = shortcutsContainer.targetY == shortcuts.height - shortcutsContainer.height |
834 | - var scrollingInTheMiddle = shortcutsContainer.targetY > (shortcuts.height - shortcutsContainer.height) && shortcutsContainer.targetY < 0 |
835 | - var scrollValue = inverted ? -shortcuts.scrollValue : shortcuts.scrollValue |
836 | - |
837 | - shortcutsContainer.animateY = false |
838 | - |
839 | - if (scrollingInTheMiddle || (scrollingAtEnd && scrollValue > 0) || (scrollingAtStart && scrollValue < 0)) { |
840 | - scrollTimer.start() |
841 | - } |
842 | - } |
843 | - } |
844 | - |
845 | - function stopScroll() { |
846 | - scrollTimer.stop() |
847 | - shortcutsContainer.animateY = true |
848 | - } |
849 | - |
850 | - function selectCurrentApplication() { |
851 | - if (currentIndex < shortcuts.openItemsCount || foldedShortcuts.foldedAngle == 0) { |
852 | - return currentIndex |
853 | - } else { |
854 | - return -1 |
855 | - } |
856 | + onDragPositionChanged: { |
857 | + var effectiveDragPosition = root.inverted ? launcherFlickable.height - dragPosition : dragPosition - mainColumn.anchors.margins |
858 | + |
859 | + var hiddenContentHeight = launcherFlickable.contentHeight - launcherFlickable.height |
860 | + // Shortening scrollable height because the first/last item needs to be fully expanded before reaching the top/bottom |
861 | + var scrollableHeight = launcherFlickable.height - (launcherFlickable.itemSize + launcherColumn.spacing) *2 |
862 | + // As we shortened the scrollableHeight, lets move everything down by the itemSize |
863 | + var shortenedEffectiveDragPosition = effectiveDragPosition - launcherFlickable.itemSize - launcherColumn.spacing |
864 | + var newContentY = shortenedEffectiveDragPosition * hiddenContentHeight / scrollableHeight |
865 | + |
866 | + // limit top/bottom to prevent overshooting |
867 | + launcherFlickable.contentY = Math.min(hiddenContentHeight, Math.max(0, newContentY)); |
868 | + |
869 | + // Now calculate the current index: |
870 | + // > the current mouse position + the hidden/scolled content on top is the mouse position in the averall view |
871 | + // > adjust that removing all the margins |
872 | + // > divide by itemSize to get index |
873 | + highlightIndex = (effectiveDragPosition + launcherFlickable.contentY - mainColumn.anchors.margins*3 - launcherColumn.spacing/2) / (launcherFlickable.itemSize + launcherColumn.spacing) |
874 | } |
875 | |
876 | BorderImage { |
877 | id: background |
878 | source: "graphics/launcher_bg.sci" |
879 | - width: parent.width |
880 | - x: 0 |
881 | - rotation: inverted ? 180 : 0 |
882 | - height: parent.height |
883 | + anchors.fill: parent |
884 | } |
885 | |
886 | - Component { |
887 | - id: shortcutsItemDelegate |
888 | - Item { |
889 | - id: delegateItem |
890 | - property int ownIndex: parent ? index + parent.initialIndex : -1 |
891 | - property bool isCurrentItem: ownIndex == shortcuts.currentIndex |
892 | - property bool ribbonModeHighlight: itemMouseArea.pressed |
893 | - |
894 | - z: -index |
895 | - anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined |
896 | - width: shortcuts.itemWidth |
897 | - height: shortcuts.itemHeight |
898 | - |
899 | - Item { |
900 | - width: shortcuts.iconWidth |
901 | - height: shortcuts.iconHeight |
902 | - anchors.centerIn: parent |
903 | - transform: Rotation { origin.x: width/2; origin.y: height; axis { x: 1; y: 0; z: 0 } angle: parent ? parent.foldedAngle : 0 } |
904 | - smooth: true |
905 | - UbuntuShape { |
906 | - id: icon |
907 | - objectName: "delegate " + model.desktopFile |
908 | - anchors.centerIn: parent |
909 | - rotation: inverted ? 180 : 0 |
910 | - width: shortcuts.iconWidth |
911 | - height: width * units.gu(7.5) / units.gu(8) |
912 | - radius: "medium" |
913 | - borderSource: "" |
914 | - image: Image { |
915 | - id: iconImage |
916 | - source: '../' + shortcuts.iconPath + "/" + model.icon + '.png' |
917 | - sourceSize { width: icon.width; height: icon.height } |
918 | + Column { |
919 | + id: mainColumn |
920 | + anchors.fill: parent |
921 | + anchors.margins: units.gu(1) |
922 | + spacing: units.gu(1) |
923 | + |
924 | + LauncherDelegate { |
925 | + id: dashItem |
926 | + objectName: "dashItem" |
927 | + width: launcherFlickable.itemSize |
928 | + height: launcherFlickable.itemSize |
929 | + anchors.horizontalCenter: parent.horizontalCenter |
930 | + iconName: "dash" |
931 | + onClicked: root.dashItemSelected(0) |
932 | + } |
933 | + Flickable { |
934 | + id: launcherFlickable |
935 | + anchors.left: parent.left |
936 | + anchors.right: parent.right |
937 | + height: parent.height - dashItem.height - parent.spacing |
938 | + contentHeight: launcherColumn.height |
939 | + |
940 | + property int itemSize: width |
941 | + |
942 | + Column { |
943 | + id: launcherColumn |
944 | + width: parent.width |
945 | + spacing: units.gu(1) |
946 | + anchors.horizontalCenter: parent.horizontalCenter |
947 | + |
948 | + Repeater { |
949 | + id: iconRepeater |
950 | + model: root.model |
951 | + |
952 | + LauncherDelegate { |
953 | + id: launcherDelegate |
954 | + objectName: "launcherDelegate" + index |
955 | + width: launcherFlickable.itemSize |
956 | + height: launcherFlickable.itemSize |
957 | + iconName: model.icon |
958 | + inverted: root.inverted |
959 | + highlighted: root.dragging && index === root.highlightIndex |
960 | + z: -Math.abs(offset) |
961 | + state: "docked" |
962 | + |
963 | + maxAngle: 60 |
964 | + |
965 | + itemsBeforeThis: index |
966 | + itemsAfterThis: iconRepeater.count - (index+1) |
967 | + |
968 | + onClicked: { |
969 | + root.applicationSelected(launcherModel.get(index).desktopFile); |
970 | + } |
971 | } |
972 | } |
973 | - |
974 | - BorderImage { |
975 | - id: overlayHighlight |
976 | - anchors.centerIn: icon |
977 | - rotation: inverted ? 180 : 0 |
978 | - source: isCurrentItem && (ribbonModeHighlight) ? "graphics/selected.sci" : "graphics/non-selected.sci" |
979 | - width: icon.width + units.gu(1.5) |
980 | - height: width * units.gu(7.5) / units.gu(8) |
981 | - } |
982 | - } |
983 | - MouseArea { |
984 | - id: itemMouseArea |
985 | - anchors.fill: parent |
986 | - onPressed: shortcuts.currentIndex = ownIndex |
987 | - onClicked: { |
988 | - if (model.desktopFile === "dash.desktop") shortcuts.dashItemSelected(ownIndex) |
989 | - else shortcuts.applicationSelected(model.desktopFile) |
990 | - } |
991 | - } |
992 | - } |
993 | - } |
994 | - |
995 | - Flickable { |
996 | - id: flickable |
997 | - width: parent.width |
998 | - height: parent.height |
999 | - contentWidth: width |
1000 | - contentHeight: shortcutsContainer.height |
1001 | - Item { |
1002 | - id: shortcutsContainer |
1003 | - |
1004 | - property bool animateY: true |
1005 | - property real targetY |
1006 | - |
1007 | - x: ( parent.width - background.width) / 2 |
1008 | - y: targetY |
1009 | - width: shortcuts.width |
1010 | - height: openShortcuts.height + semiFoldedShortcut.height + foldedShortcuts.height |
1011 | - |
1012 | - Behavior on y { NumberAnimation{duration: shortcutsContainer.animateY ? 200 : 0; } } |
1013 | - |
1014 | - ShortcutsContainer { |
1015 | - id: openShortcuts |
1016 | - objectName: "openShortcuts" |
1017 | - |
1018 | - width: shortcuts.width |
1019 | - height: childrenRect.height |
1020 | - z: 3 |
1021 | - model: shortcuts.openModel |
1022 | - delegate: shortcutsItemDelegate |
1023 | - initialIndex: 0 |
1024 | - } |
1025 | - |
1026 | - ShortcutsContainer { |
1027 | - id: semiFoldedShortcut |
1028 | - objectName: "semiFoldedShortcut" |
1029 | - |
1030 | - foldedAngle: 0 // FIXME: folding disabled // shortcuts.open ? 0 : 90 * (height - initialFoldedOffset)/height - 80 // todo: better algorithm here |
1031 | - initialFoldedOffset: -2 * shortcuts.itemHeight / 3 + shortcuts.fillItemHeight |
1032 | - foldedOffset: 0 // FIXME: folding disabled //shortcuts.open ? 0 : initialFoldedOffset |
1033 | - visible: shortcuts.iconCount > shortcuts.openItemsCount |
1034 | - width: shortcuts.itemWidth |
1035 | - height: childrenRect.height |
1036 | - anchors.top: openShortcuts.bottom |
1037 | - z: 2 |
1038 | - anchors.horizontalCenter: parent.horizontalCenter |
1039 | - anchors.topMargin: foldedOffset |
1040 | - model: shortcuts.semiFoldedModel |
1041 | - delegate: shortcutsItemDelegate |
1042 | - initialIndex: shortcuts.openModel.count |
1043 | - } |
1044 | - |
1045 | - ShortcutsContainer { |
1046 | - id: foldedShortcuts |
1047 | - objectName: "foldedShortcuts" |
1048 | - |
1049 | - foldedAngle: 0 // FIXME: folding disabled //shortcuts.open ? 0 : 68 |
1050 | - initialFoldedOffset: 2 * shortcuts.itemHeight / 3 |
1051 | - foldedOffset: 0 // FIXME: folding disabled // shortcuts.open ? 0 : initialFoldedOffset |
1052 | - width: shortcuts.width |
1053 | - height: childrenRect.height |
1054 | - spacing: -foldedOffset |
1055 | - anchors.top: semiFoldedShortcut.bottom |
1056 | - anchors.topMargin: -foldedOffset |
1057 | - z: 1 |
1058 | - model: shortcuts.foldedModel |
1059 | - delegate: shortcutsItemDelegate |
1060 | - initialIndex: shortcuts.openModel.count + shortcuts.semiFoldedModel.count |
1061 | - } |
1062 | - } |
1063 | - } |
1064 | - |
1065 | - Timer { |
1066 | - id: scrollTimer |
1067 | - |
1068 | - repeat: true |
1069 | - running: false |
1070 | - interval: 16 |
1071 | - onTriggered:{ |
1072 | - if (shortcutsContainer.height > shortcuts.height) { |
1073 | - var scrollValue = inverted ? -shortcuts.scrollValue : shortcuts.scrollValue |
1074 | - var newValue = shortcutsContainer.targetY + scrollValue |
1075 | - |
1076 | - if (newValue > 0) { |
1077 | - newValue = 0 |
1078 | - stop() |
1079 | - } else if (newValue < shortcuts.height - shortcutsContainer.height) { |
1080 | - newValue = shortcuts.height - shortcutsContainer.height |
1081 | - stop() |
1082 | - } |
1083 | - shortcutsContainer.targetY = newValue |
1084 | } |
1085 | } |
1086 | } |
1087 | |
1088 | === modified file 'Shell.qml' |
1089 | --- Shell.qml 2013-06-03 08:29:01 +0000 |
1090 | +++ Shell.qml 2013-06-04 12:32:22 +0000 |
1091 | @@ -479,16 +479,23 @@ |
1092 | enabled: !panel.indicators.shown |
1093 | } |
1094 | |
1095 | + InputFilterArea { |
1096 | + blockInput: launcher.shown |
1097 | + anchors { |
1098 | + top: parent.top |
1099 | + bottom: parent.bottom |
1100 | + left: parent.left |
1101 | + } |
1102 | + width: launcher.width |
1103 | + } |
1104 | + |
1105 | Launcher { |
1106 | id: launcher |
1107 | |
1108 | anchors.top: parent.top |
1109 | anchors.bottom: parent.bottom |
1110 | width: parent.width |
1111 | - applicationFocused: stages.shown |
1112 | - shortcutsWidth: units.gu(9) |
1113 | - shortcutsThreshold: shell.edgeSize |
1114 | - iconPath: "graphics/applicationIcons" |
1115 | + dragAreaWidth: shell.edgeSize |
1116 | available: !greeter.locked |
1117 | teasing: available && greeter.leftTeaserPressed |
1118 | onDashItemSelected: { |
1119 | @@ -502,17 +509,12 @@ |
1120 | stages.hide(); |
1121 | } |
1122 | onDash: { |
1123 | - greeter.hide() |
1124 | + dash.setCurrentLens("applications.lens", true, false) |
1125 | stages.hide(); |
1126 | } |
1127 | onLauncherApplicationSelected:{ |
1128 | greeter.hide() |
1129 | - shell.activateApplication(name) |
1130 | - } |
1131 | - onStateChanged: { |
1132 | - if (state == "spreadMoving") { |
1133 | - dash.setCurrentLens("applications.lens", false, true) |
1134 | - } |
1135 | + shell.activateApplication(desktopFile) |
1136 | } |
1137 | onShownChanged: { |
1138 | if (shown) { |
1139 | @@ -521,16 +523,6 @@ |
1140 | } |
1141 | } |
1142 | } |
1143 | - |
1144 | - InputFilterArea { |
1145 | - blockInput: launcher.shown |
1146 | - anchors { |
1147 | - top: parent.top |
1148 | - bottom: parent.bottom |
1149 | - left: parent.left |
1150 | - } |
1151 | - width: launcher.shortcutsWidth |
1152 | - } |
1153 | } |
1154 | |
1155 | focus: true |
1156 | |
1157 | === modified file 'plugins/Ubuntu/Gestures/DirectionalDragArea.cpp' |
1158 | --- plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2013-05-20 11:12:09 +0000 |
1159 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2013-06-04 12:32:22 +0000 |
1160 | @@ -243,17 +243,24 @@ |
1161 | if (newStatus == m_status) |
1162 | return; |
1163 | |
1164 | + DirectionalDragArea::Status oldStatus = m_status; |
1165 | + |
1166 | m_status = newStatus; |
1167 | Q_EMIT statusChanged(m_status); |
1168 | |
1169 | switch (newStatus) { |
1170 | case WaitingForTouch: |
1171 | + if (oldStatus != DirectionalDragArea::Rejected) { |
1172 | + Q_EMIT draggingChanged(false); |
1173 | + } |
1174 | + break; |
1175 | + case Undecided: |
1176 | + Q_EMIT draggingChanged(true); |
1177 | + break; |
1178 | + case Rejected: |
1179 | Q_EMIT draggingChanged(false); |
1180 | break; |
1181 | - case Undecided: |
1182 | - Q_EMIT draggingChanged(true); |
1183 | - break; |
1184 | - default: // Rejected |
1185 | + default: |
1186 | // no-op |
1187 | break; |
1188 | } |
1189 | |
1190 | === modified file 'plugins/Ubuntu/Gestures/DirectionalDragArea.h' |
1191 | --- plugins/Ubuntu/Gestures/DirectionalDragArea.h 2013-05-20 13:12:51 +0000 |
1192 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea.h 2013-06-04 12:32:22 +0000 |
1193 | @@ -47,8 +47,9 @@ |
1194 | // The current status of the directional drag gesture area. |
1195 | Q_PROPERTY(Status status READ status NOTIFY statusChanged) |
1196 | |
1197 | - // Whether a drag gesture is taking place (regardless of whether it's a correct |
1198 | - // single-finger directional drag or not) |
1199 | + // Whether a drag gesture is taking place |
1200 | + // This will be true as long as status is Undecided or Recognized |
1201 | + // When a gesture gets rejected, dragging turns to false. |
1202 | Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged) |
1203 | |
1204 | ///// |
1205 | |
1206 | === modified file 'plugins/Unity/CMakeLists.txt' |
1207 | --- plugins/Unity/CMakeLists.txt 2013-05-08 09:51:55 +0000 |
1208 | +++ plugins/Unity/CMakeLists.txt 2013-06-04 12:32:22 +0000 |
1209 | @@ -20,6 +20,7 @@ |
1210 | peoplepreviewdata.cpp |
1211 | plugin.cpp |
1212 | bottombarvisibilitycommunicatorshell.cpp |
1213 | + launchermodel.cpp |
1214 | ) |
1215 | |
1216 | add_library(Unity-qml MODULE |
1217 | |
1218 | === added file 'plugins/Unity/launchermodel.cpp' |
1219 | --- plugins/Unity/launchermodel.cpp 1970-01-01 00:00:00 +0000 |
1220 | +++ plugins/Unity/launchermodel.cpp 2013-06-04 12:32:22 +0000 |
1221 | @@ -0,0 +1,153 @@ |
1222 | +/* |
1223 | + * Copyright (C) 2011 Canonical, Ltd. |
1224 | + * |
1225 | + * Authors: |
1226 | + * Michael Zanetti <michael.zanetti@canonical.com> |
1227 | + * |
1228 | + * This program is free software; you can redistribute it and/or modify |
1229 | + * it under the terms of the GNU General Public License as published by |
1230 | + * the Free Software Foundation; version 3. |
1231 | + * |
1232 | + * This program is distributed in the hope that it will be useful, |
1233 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1234 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1235 | + * GNU General Public License for more details. |
1236 | + * |
1237 | + * You should have received a copy of the GNU General Public License |
1238 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1239 | + */ |
1240 | + |
1241 | +#include "launchermodel.h" |
1242 | + |
1243 | +LauncherModel::LauncherModel(QObject *parent): QAbstractListModel(parent) |
1244 | +{ |
1245 | + // FIXME: Dummy data... Aggregate real data from backends |
1246 | + |
1247 | + // Fake favorites |
1248 | + LauncherItem *item = new LauncherItem("/usr/share/applications/phone-app.desktop", "Phone", "phone-app"); |
1249 | + m_list.append(item); |
1250 | + item = new LauncherItem("/usr/share/applications/camera-app.desktop", "Camera", "camera"); |
1251 | + m_list.append(item); |
1252 | + item = new LauncherItem("/usr/share/applications/gallery-app.desktop", "Gallery", "gallery"); |
1253 | + m_list.append(item); |
1254 | + item = new LauncherItem("/usr/share/applications/facebook-webapp.desktop", "Facebook", "facebook"); |
1255 | + m_list.append(item); |
1256 | + item = new LauncherItem("/usr/share/applications/webbrowser-app.desktop", "Browser", "browser"); |
1257 | + m_list.append(item); |
1258 | + item = new LauncherItem("/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter"); |
1259 | + m_list.append(item); |
1260 | + item = new LauncherItem("/usr/share/applications/gmail-webapp.desktop", "GMail", "gmail"); |
1261 | + m_list.append(item); |
1262 | + item = new LauncherItem("/usr/share/applications/ubuntu-weather-app.desktop", "Weather", "weather"); |
1263 | + m_list.append(item); |
1264 | + item = new LauncherItem("/usr/share/applications/notes-app.desktop", "Notepad", "notepad"); |
1265 | + m_list.append(item); |
1266 | + item = new LauncherItem("/usr/share/applications/ubuntu-calendar-app.desktop","Calendar", "calendar"); |
1267 | + m_list.append(item); |
1268 | +} |
1269 | + |
1270 | +LauncherModel::~LauncherModel() |
1271 | +{ |
1272 | + while (!m_list.empty()) { |
1273 | + m_list.takeFirst()->deleteLater(); |
1274 | + } |
1275 | +} |
1276 | + |
1277 | +int LauncherModel::rowCount(const QModelIndex &parent) const |
1278 | +{ |
1279 | + Q_UNUSED(parent) |
1280 | + return m_list.count(); |
1281 | +} |
1282 | + |
1283 | +QVariant LauncherModel::data(const QModelIndex &index, int role) const |
1284 | +{ |
1285 | + LauncherItem *item = m_list.at(index.row()); |
1286 | + switch(role) { |
1287 | + case RoleName: |
1288 | + return item->name(); |
1289 | + case RoleIcon: |
1290 | + return item->icon(); |
1291 | + case RoleFavorite: |
1292 | + return item->favorite(); |
1293 | + } |
1294 | + |
1295 | + return QVariant(); |
1296 | +} |
1297 | + |
1298 | +LauncherItem *LauncherModel::get(int index) const |
1299 | +{ |
1300 | + if (index < 0 || index >= m_list.count()) { |
1301 | + return 0; |
1302 | + } |
1303 | + return m_list.at(index); |
1304 | +} |
1305 | + |
1306 | +void LauncherModel::move(int oldIndex, int newIndex) |
1307 | +{ |
1308 | + beginMoveRows(QModelIndex(), oldIndex, oldIndex, QModelIndex(), newIndex); |
1309 | + m_list.move(oldIndex, newIndex); |
1310 | + endMoveRows(); |
1311 | +} |
1312 | + |
1313 | +QHash<int, QByteArray> LauncherModel::roleNames() const |
1314 | +{ |
1315 | + QHash<int, QByteArray> roles; |
1316 | + roles.insert(RoleDesktopFile, "desktopFile"); |
1317 | + roles.insert(RoleName, "name"); |
1318 | + roles.insert(RoleIcon, "icon"); |
1319 | + roles.insert(RoleFavorite, "favorite"); |
1320 | + roles.insert(RoleRunning, "runnng"); |
1321 | + return roles; |
1322 | +} |
1323 | + |
1324 | + |
1325 | +LauncherItem::LauncherItem(const QString &desktopFile, const QString &name, const QString &icon, QObject *parent): |
1326 | + QObject(parent), |
1327 | + m_desktopFile(desktopFile), |
1328 | + m_name(name), |
1329 | + m_icon(icon), |
1330 | + m_favorite(false) |
1331 | +{ |
1332 | + |
1333 | +} |
1334 | + |
1335 | +QString LauncherItem::desktopFile() const |
1336 | +{ |
1337 | + return m_desktopFile; |
1338 | +} |
1339 | + |
1340 | +QString LauncherItem::name() const |
1341 | +{ |
1342 | + return m_name; |
1343 | +} |
1344 | + |
1345 | +QString LauncherItem::icon() const |
1346 | +{ |
1347 | + return m_icon; |
1348 | +} |
1349 | + |
1350 | +bool LauncherItem::favorite() const |
1351 | +{ |
1352 | + return m_favorite; |
1353 | +} |
1354 | + |
1355 | +void LauncherItem::setFavorite(bool favorite) |
1356 | +{ |
1357 | + if (m_favorite != favorite) { |
1358 | + m_favorite = favorite; |
1359 | + Q_EMIT favoriteChanged(m_favorite); |
1360 | + } |
1361 | +} |
1362 | + |
1363 | +bool LauncherItem::running() const |
1364 | +{ |
1365 | + return m_running; |
1366 | +} |
1367 | + |
1368 | +void LauncherItem::setRunning(bool running) |
1369 | +{ |
1370 | + if (m_running != running) { |
1371 | + m_running = running; |
1372 | + Q_EMIT runningChanged(running); |
1373 | + } |
1374 | +} |
1375 | |
1376 | === added file 'plugins/Unity/launchermodel.h' |
1377 | --- plugins/Unity/launchermodel.h 1970-01-01 00:00:00 +0000 |
1378 | +++ plugins/Unity/launchermodel.h 2013-06-04 12:32:22 +0000 |
1379 | @@ -0,0 +1,86 @@ |
1380 | +/* |
1381 | + * Copyright (C) 2011 Canonical, Ltd. |
1382 | + * |
1383 | + * Authors: |
1384 | + * Michael Zanetti <michael.zanetti@canonical.com> |
1385 | + * |
1386 | + * This program is free software; you can redistribute it and/or modify |
1387 | + * it under the terms of the GNU General Public License as published by |
1388 | + * the Free Software Foundation; version 3. |
1389 | + * |
1390 | + * This program is distributed in the hope that it will be useful, |
1391 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1392 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1393 | + * GNU General Public License for more details. |
1394 | + * |
1395 | + * You should have received a copy of the GNU General Public License |
1396 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1397 | + */ |
1398 | + |
1399 | +#include <QAbstractListModel> |
1400 | + |
1401 | +class LauncherItem; |
1402 | + |
1403 | +class LauncherModel: public QAbstractListModel |
1404 | +{ |
1405 | + Q_OBJECT |
1406 | + |
1407 | +public: |
1408 | + enum Roles { |
1409 | + RoleDesktopFile = Qt::UserRole, |
1410 | + RoleName, |
1411 | + RoleIcon, |
1412 | + RoleFavorite, |
1413 | + RoleRunning |
1414 | + }; |
1415 | + |
1416 | + LauncherModel(QObject *parent = 0); |
1417 | + ~LauncherModel(); |
1418 | + |
1419 | + int rowCount(const QModelIndex &parent) const; |
1420 | + |
1421 | + QVariant data(const QModelIndex &index, int role) const; |
1422 | + |
1423 | + Q_INVOKABLE LauncherItem* get(int index) const; |
1424 | + Q_INVOKABLE void move(int oldIndex, int newIndex); |
1425 | + |
1426 | + QHash<int, QByteArray> roleNames() const; |
1427 | + |
1428 | +private: |
1429 | + QList<LauncherItem*> m_list; |
1430 | +}; |
1431 | + |
1432 | +class LauncherItem: public QObject |
1433 | +{ |
1434 | + Q_OBJECT |
1435 | + Q_PROPERTY(QString desktopFile READ desktopFile CONSTANT) |
1436 | + Q_PROPERTY(QString name READ name CONSTANT) |
1437 | + Q_PROPERTY(QString icon READ icon CONSTANT) |
1438 | + Q_PROPERTY(bool favorite READ favorite WRITE setFavorite NOTIFY favoriteChanged) |
1439 | + Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged) |
1440 | + |
1441 | +public: |
1442 | + LauncherItem(const QString &desktopFile, const QString &name, const QString &icon, QObject *parent = 0); |
1443 | + |
1444 | + QString desktopFile() const; |
1445 | + |
1446 | + QString name() const; |
1447 | + QString icon() const; |
1448 | + |
1449 | + bool favorite() const; |
1450 | + void setFavorite(bool favorite); |
1451 | + |
1452 | + bool running() const; |
1453 | + void setRunning(bool running); |
1454 | + |
1455 | +Q_SIGNALS: |
1456 | + void favoriteChanged(bool favorite); |
1457 | + void runningChanged(bool running); |
1458 | + |
1459 | +private: |
1460 | + QString m_desktopFile; |
1461 | + QString m_name; |
1462 | + QString m_icon; |
1463 | + bool m_favorite; |
1464 | + bool m_running; |
1465 | +}; |
1466 | |
1467 | === modified file 'plugins/Unity/plugin.cpp' |
1468 | --- plugins/Unity/plugin.cpp 2013-04-05 22:03:12 +0000 |
1469 | +++ plugins/Unity/plugin.cpp 2013-06-04 12:32:22 +0000 |
1470 | @@ -30,6 +30,7 @@ |
1471 | #include "categoryfilter.h" |
1472 | #include "peoplepreviewdata.h" |
1473 | #include "bottombarvisibilitycommunicatorshell.h" |
1474 | +#include "launchermodel.h" |
1475 | |
1476 | // libqtdee |
1477 | #include "deelistmodel.h" |
1478 | @@ -49,6 +50,8 @@ |
1479 | qmlRegisterType<PeoplePhoneData>(uri, 0, 1, "PeoplePhoneData"); |
1480 | qmlRegisterType<PeopleAddressData>(uri, 0, 1, "PeopleAddressData"); |
1481 | qmlRegisterType<PeopleIMData>(uri, 0, 1, "PeopleIMData"); |
1482 | + qmlRegisterType<LauncherModel>(uri, 0, 1, "LauncherModel"); |
1483 | + qmlRegisterUncreatableType<LauncherItem>(uri, 0, 1, "LauncherItem", "Can't create new Launcher Items in QML. Get them from the LauncherModel."); |
1484 | qmlRegisterUncreatableType<BottomBarVisibilityCommunicatorShell>(uri, 0, 1, "BottomBarVisibilityCommunicatorShell", "Can't create BottomBarVisibilityCommunicatorShell"); |
1485 | } |
1486 | |
1487 | |
1488 | === modified file 'tests/autopilot/qml_phone_shell/tests/helpers.py' |
1489 | --- tests/autopilot/qml_phone_shell/tests/helpers.py 2013-05-30 20:17:20 +0000 |
1490 | +++ tests/autopilot/qml_phone_shell/tests/helpers.py 2013-06-04 12:32:22 +0000 |
1491 | @@ -154,7 +154,7 @@ |
1492 | view = self.main_window.get_qml_view() |
1493 | start_x = view.x + 1 |
1494 | start_y = view.y + view.height / 2 |
1495 | - stop_x = start_x + launcher.shortcutsWidth + 1 |
1496 | + stop_x = start_x + launcher.panelWidth + 1 |
1497 | stop_y = start_y |
1498 | self.touch.drag(start_x, start_y, stop_x, stop_y) |
1499 | self.assertThat(launcher.shown, Eventually(Equals(True))) |
1500 | |
1501 | === modified file 'tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp' |
1502 | --- tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp 2013-05-20 13:12:51 +0000 |
1503 | +++ tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp 2013-06-04 12:32:22 +0000 |
1504 | @@ -162,8 +162,10 @@ |
1505 | if (expectedGestureRecognition) |
1506 | QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized); |
1507 | |
1508 | - if (edgeDragArea->status() == DirectionalDragArea::Rejected) |
1509 | + if (edgeDragArea->status() == DirectionalDragArea::Rejected) { |
1510 | QCOMPARE(edgeDragArea->dragging(), false); |
1511 | + QCOMPARE(draggingSpy.count(), 2); |
1512 | + } |
1513 | |
1514 | QTest::touchEvent(view, device).release(0, touchPoint.toPoint()); |
1515 | |
1516 | |
1517 | === modified file 'tests/qmltests/CMakeLists.txt' |
1518 | --- tests/qmltests/CMakeLists.txt 2013-06-03 20:18:44 +0000 |
1519 | +++ tests/qmltests/CMakeLists.txt 2013-06-04 12:32:22 +0000 |
1520 | @@ -53,7 +53,7 @@ |
1521 | ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full") |
1522 | add_qml_test(Hud Hud) |
1523 | add_qml_test(Hud Result) |
1524 | -add_qml_test(Launcher Launcher IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins) |
1525 | +add_qml_test(Launcher Launcher IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}) |
1526 | add_qml_test(Notifications Notifications) |
1527 | add_qml_test(Panel IndicatorRow) |
1528 | add_qml_test(Panel Indicators) |
1529 | |
1530 | === modified file 'tests/qmltests/Launcher/tst_Launcher.qml' |
1531 | --- tests/qmltests/Launcher/tst_Launcher.qml 2013-05-21 11:32:49 +0000 |
1532 | +++ tests/qmltests/Launcher/tst_Launcher.qml 2013-06-04 12:32:22 +0000 |
1533 | @@ -19,7 +19,6 @@ |
1534 | import Unity.Test 0.1 as UT |
1535 | import ".." |
1536 | import "../../../Launcher" |
1537 | -import "../../../Applications/applications.js" as ApplicationsModel |
1538 | |
1539 | /* Nothing is shown at first. If you drag from left edge you will bring up the |
1540 | launcher. */ |
1541 | @@ -32,20 +31,12 @@ |
1542 | x: 0 |
1543 | y: 0 |
1544 | width: units.gu(40) |
1545 | - height: units.gu(71) |
1546 | - |
1547 | - favourites: ["/usr/share/applications/phone-app.desktop", |
1548 | - "/usr/share/applications/camera-app.desktop", |
1549 | - "/usr/share/applications/gallery-app.desktop"] |
1550 | - |
1551 | - shortcutsWidth: units.gu(9) |
1552 | - shortcutsThreshold: units.gu(2) |
1553 | - iconPath: "graphics/applicationIcons" |
1554 | + height: units.gu(81) |
1555 | |
1556 | property string latestApplicationSelected |
1557 | |
1558 | onLauncherApplicationSelected: { |
1559 | - latestApplicationSelected = name |
1560 | + latestApplicationSelected = desktopFile |
1561 | } |
1562 | |
1563 | property int dashItemSelected_count: 0 |
1564 | @@ -62,13 +53,11 @@ |
1565 | // Drag from the left edge of the screen rightwards and check that the launcher |
1566 | // appears (as if being dragged by the finger/pointer) |
1567 | function test_dragLeftEdgeToRevealLauncherAndTapCenterToDismiss() { |
1568 | - // "shortcuts" is the vertical stripe of icons the user see. |
1569 | - // i.e., the launcher graphical element itself. |
1570 | - var shortcuts = findChild(launcher, "shortcuts") |
1571 | - verify(shortcuts != undefined) |
1572 | + var panel = findChild(launcher, "launcherPanel") |
1573 | + verify(panel != undefined) |
1574 | |
1575 | // it starts out hidden just left of the left launcher edge |
1576 | - compare(shortcuts.x, -shortcuts.width) |
1577 | + compare(panel.x, -panel.width) |
1578 | |
1579 | dragLauncherIntoView() |
1580 | |
1581 | @@ -76,7 +65,7 @@ |
1582 | mouseClick(launcher, launcher.width/2, launcher.height/2) |
1583 | |
1584 | // should eventually get fully retracted (hidden) |
1585 | - tryCompare(shortcuts, "x", -shortcuts.width, 1000) |
1586 | + tryCompare(panel, "x", -launcher.panelWidth, 1000) |
1587 | } |
1588 | |
1589 | /* If I click on the icon of an application on the launcher |
1590 | @@ -88,11 +77,10 @@ |
1591 | |
1592 | dragLauncherIntoView() |
1593 | |
1594 | - var phoneIcon = findChild(launcher, |
1595 | - "delegate /usr/share/applications/phone-app.desktop") |
1596 | - verify(phoneIcon != undefined) |
1597 | + var appIcon = findChild(launcher, "launcherDelegate0") |
1598 | + verify(appIcon != undefined) |
1599 | |
1600 | - mouseClick(phoneIcon, phoneIcon.width/2, phoneIcon.height/2) |
1601 | + mouseClick(appIcon, appIcon.width/2, appIcon.height/2) |
1602 | |
1603 | tryCompare(launcher, "latestApplicationSelected", |
1604 | "/usr/share/applications/phone-app.desktop") |
1605 | @@ -108,8 +96,7 @@ |
1606 | |
1607 | dragLauncherIntoView() |
1608 | |
1609 | - var dashIcon = findChild(launcher, |
1610 | - "delegate dash.desktop") |
1611 | + var dashIcon = findChild(launcher, "dashItem") |
1612 | verify(dashIcon != undefined) |
1613 | |
1614 | mouseClick(dashIcon, dashIcon.width/2, dashIcon.height/2) |
1615 | @@ -121,24 +108,23 @@ |
1616 | } |
1617 | |
1618 | function dragLauncherIntoView() { |
1619 | - var startX = launcher.shortcutsThreshold/2 |
1620 | + var startX = launcher.dragAreaWidth/2 |
1621 | var startY = launcher.height/2 |
1622 | touchFlick(launcher, |
1623 | startX, startY, |
1624 | startX+units.gu(8), startY) |
1625 | |
1626 | - // "shortcuts" is the vertical stripe of icons the user see. |
1627 | - // i.e., the launcher graphical element itself. |
1628 | - var shortcuts = findChild(launcher, "shortcuts") |
1629 | - verify(shortcuts != undefined) |
1630 | + var panel = findChild(launcher, "launcherPanel") |
1631 | + verify(panel != undefined) |
1632 | |
1633 | // wait until it gets fully extended |
1634 | - tryCompare(shortcuts, "x", 0) |
1635 | + tryCompare(panel, "x", 0) |
1636 | + tryCompare(launcher, "state", "visible") |
1637 | } |
1638 | |
1639 | function waitUntilLauncherDisappears() { |
1640 | - var shortcuts = findChild(launcher, "shortcuts") |
1641 | - tryCompare(shortcuts, "x", -shortcuts.width, 1000) |
1642 | + var panel = findChild(launcher, "launcherPanel") |
1643 | + tryCompare(panel, "x", -panel.width, 1000) |
1644 | } |
1645 | } |
1646 | } |
1647 | |
1648 | === modified file 'tests/qmltests/plugins/Unity/CMakeLists.txt' |
1649 | --- tests/qmltests/plugins/Unity/CMakeLists.txt 2013-05-02 16:38:00 +0000 |
1650 | +++ tests/qmltests/plugins/Unity/CMakeLists.txt 2013-06-04 12:32:22 +0000 |
1651 | @@ -25,6 +25,7 @@ |
1652 | fake_lens.cpp |
1653 | fake_lenses.cpp |
1654 | fake_unity_plugin.cpp |
1655 | + fake_launchermodel.cpp |
1656 | ) |
1657 | |
1658 | add_library(FakeUnityQml MODULE ${UnityQML_SOURCES}) |
1659 | |
1660 | === added file 'tests/qmltests/plugins/Unity/fake_launchermodel.cpp' |
1661 | --- tests/qmltests/plugins/Unity/fake_launchermodel.cpp 1970-01-01 00:00:00 +0000 |
1662 | +++ tests/qmltests/plugins/Unity/fake_launchermodel.cpp 2013-06-04 12:32:22 +0000 |
1663 | @@ -0,0 +1,150 @@ |
1664 | +/* |
1665 | + * Copyright (C) 2011 Canonical, Ltd. |
1666 | + * |
1667 | + * Authors: |
1668 | + * Michael Zanetti <michael.zanetti@canonical.com> |
1669 | + * |
1670 | + * This program is free software; you can redistribute it and/or modify |
1671 | + * it under the terms of the GNU General Public License as published by |
1672 | + * the Free Software Foundation; version 3. |
1673 | + * |
1674 | + * This program is distributed in the hope that it will be useful, |
1675 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1676 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1677 | + * GNU General Public License for more details. |
1678 | + * |
1679 | + * You should have received a copy of the GNU General Public License |
1680 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1681 | + */ |
1682 | + |
1683 | +#include "launchermodel.h" |
1684 | + |
1685 | +LauncherModel::LauncherModel(QObject *parent): QAbstractListModel(parent) |
1686 | +{ |
1687 | + LauncherItem *item = new LauncherItem("/usr/share/applications/phone-app.desktop", "Phone", "phone-app"); |
1688 | + m_list.append(item); |
1689 | + item = new LauncherItem("/usr/share/applications/camera-app.desktop", "Camera", "camera"); |
1690 | + m_list.append(item); |
1691 | + item = new LauncherItem("/usr/share/applications/gallery-app.desktop", "Gallery", "gallery"); |
1692 | + m_list.append(item); |
1693 | + item = new LauncherItem("/usr/share/applications/facebook-webapp.desktop", "Facebook", "facebook"); |
1694 | + m_list.append(item); |
1695 | + item = new LauncherItem("/usr/share/applications/webbrowser-app.desktop", "Browser", "browser"); |
1696 | + m_list.append(item); |
1697 | + item = new LauncherItem("/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter"); |
1698 | + m_list.append(item); |
1699 | + item = new LauncherItem("/usr/share/applications/gmail-webapp.desktop", "GMail", "gmail"); |
1700 | + m_list.append(item); |
1701 | + item = new LauncherItem("/usr/share/applications/ubuntu-weather-app.desktop", "Weather", "weather"); |
1702 | + m_list.append(item); |
1703 | + item = new LauncherItem("/usr/share/applications/notes-app.desktop", "Notepad", "notepad"); |
1704 | + m_list.append(item); |
1705 | + item = new LauncherItem("/usr/share/applications/ubuntu-calendar-app.desktop","Calendar", "calendar"); |
1706 | + m_list.append(item); |
1707 | +} |
1708 | + |
1709 | +LauncherModel::~LauncherModel() |
1710 | +{ |
1711 | + while (!m_list.empty()) { |
1712 | + m_list.takeFirst()->deleteLater(); |
1713 | + } |
1714 | +} |
1715 | + |
1716 | +int LauncherModel::rowCount(const QModelIndex &parent) const |
1717 | +{ |
1718 | + Q_UNUSED(parent) |
1719 | + return m_list.count(); |
1720 | +} |
1721 | + |
1722 | +QVariant LauncherModel::data(const QModelIndex &index, int role) const |
1723 | +{ |
1724 | + LauncherItem *item = m_list.at(index.row()); |
1725 | + switch(role) { |
1726 | + case RoleName: |
1727 | + return item->name(); |
1728 | + case RoleIcon: |
1729 | + return item->icon(); |
1730 | + case RoleFavorite: |
1731 | + return item->favorite(); |
1732 | + } |
1733 | + |
1734 | + return QVariant(); |
1735 | +} |
1736 | + |
1737 | +LauncherItem *LauncherModel::get(int index) const |
1738 | +{ |
1739 | + if (index < 0 || index >= m_list.count()) { |
1740 | + return 0; |
1741 | + } |
1742 | + return m_list.at(index); |
1743 | +} |
1744 | + |
1745 | +void LauncherModel::move(int oldIndex, int newIndex) |
1746 | +{ |
1747 | + beginMoveRows(QModelIndex(), oldIndex, oldIndex, QModelIndex(), newIndex); |
1748 | + m_list.move(oldIndex, newIndex); |
1749 | + endMoveRows(); |
1750 | +} |
1751 | + |
1752 | +QHash<int, QByteArray> LauncherModel::roleNames() const |
1753 | +{ |
1754 | + QHash<int, QByteArray> roles; |
1755 | + roles.insert(RoleDesktopFile, "desktopFile"); |
1756 | + roles.insert(RoleName, "name"); |
1757 | + roles.insert(RoleIcon, "icon"); |
1758 | + roles.insert(RoleFavorite, "favorite"); |
1759 | + roles.insert(RoleRunning, "runnng"); |
1760 | + return roles; |
1761 | +} |
1762 | + |
1763 | + |
1764 | +LauncherItem::LauncherItem(const QString &desktopFile, const QString &name, const QString &icon, QObject *parent): |
1765 | + QObject(parent), |
1766 | + m_desktopFile(desktopFile), |
1767 | + m_name(name), |
1768 | + m_icon(icon), |
1769 | + m_favorite(false) |
1770 | +{ |
1771 | + |
1772 | +} |
1773 | + |
1774 | +QString LauncherItem::desktopFile() const |
1775 | +{ |
1776 | + return m_desktopFile; |
1777 | +} |
1778 | + |
1779 | +QString LauncherItem::name() const |
1780 | +{ |
1781 | + return m_name; |
1782 | +} |
1783 | + |
1784 | +QString LauncherItem::icon() const |
1785 | +{ |
1786 | + return m_icon; |
1787 | +} |
1788 | + |
1789 | +bool LauncherItem::favorite() const |
1790 | +{ |
1791 | + return m_favorite; |
1792 | +} |
1793 | + |
1794 | +void LauncherItem::setFavorite(bool favorite) |
1795 | +{ |
1796 | + if (m_favorite != favorite) { |
1797 | + m_favorite = favorite; |
1798 | + Q_EMIT favoriteChanged(m_favorite); |
1799 | + } |
1800 | +} |
1801 | + |
1802 | +bool LauncherItem::running() const |
1803 | +{ |
1804 | + return m_running; |
1805 | +} |
1806 | + |
1807 | +void LauncherItem::setRunning(bool running) |
1808 | +{ |
1809 | + if (m_running != running) { |
1810 | + m_running = running; |
1811 | + Q_EMIT runningChanged(running); |
1812 | + } |
1813 | +} |
1814 | |
1815 | === added file 'tests/qmltests/plugins/Unity/fake_launchermodel.h' |
1816 | --- tests/qmltests/plugins/Unity/fake_launchermodel.h 1970-01-01 00:00:00 +0000 |
1817 | +++ tests/qmltests/plugins/Unity/fake_launchermodel.h 2013-06-04 12:32:22 +0000 |
1818 | @@ -0,0 +1,86 @@ |
1819 | +/* |
1820 | + * Copyright (C) 2011 Canonical, Ltd. |
1821 | + * |
1822 | + * Authors: |
1823 | + * Michael Zanetti <michael.zanetti@canonical.com> |
1824 | + * |
1825 | + * This program is free software; you can redistribute it and/or modify |
1826 | + * it under the terms of the GNU General Public License as published by |
1827 | + * the Free Software Foundation; version 3. |
1828 | + * |
1829 | + * This program is distributed in the hope that it will be useful, |
1830 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1831 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1832 | + * GNU General Public License for more details. |
1833 | + * |
1834 | + * You should have received a copy of the GNU General Public License |
1835 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1836 | + */ |
1837 | + |
1838 | +#include <QAbstractListModel> |
1839 | + |
1840 | +class LauncherItem; |
1841 | + |
1842 | +class LauncherModel: public QAbstractListModel |
1843 | +{ |
1844 | + Q_OBJECT |
1845 | + |
1846 | +public: |
1847 | + enum Roles { |
1848 | + RoleDesktopFile = Qt::UserRole, |
1849 | + RoleName, |
1850 | + RoleIcon, |
1851 | + RoleFavorite, |
1852 | + RoleRunning |
1853 | + }; |
1854 | + |
1855 | + LauncherModel(QObject *parent = 0); |
1856 | + ~LauncherModel(); |
1857 | + |
1858 | + int rowCount(const QModelIndex &parent) const; |
1859 | + |
1860 | + QVariant data(const QModelIndex &index, int role) const; |
1861 | + |
1862 | + Q_INVOKABLE LauncherItem* get(int index) const; |
1863 | + Q_INVOKABLE void move(int oldIndex, int newIndex); |
1864 | + |
1865 | + QHash<int, QByteArray> roleNames() const; |
1866 | + |
1867 | +private: |
1868 | + QList<LauncherItem*> m_list; |
1869 | +}; |
1870 | + |
1871 | +class LauncherItem: public QObject |
1872 | +{ |
1873 | + Q_OBJECT |
1874 | + Q_PROPERTY(QString desktopFile READ desktopFile CONSTANT) |
1875 | + Q_PROPERTY(QString name READ name CONSTANT) |
1876 | + Q_PROPERTY(QString icon READ icon CONSTANT) |
1877 | + Q_PROPERTY(bool favorite READ favorite WRITE setFavorite NOTIFY favoriteChanged) |
1878 | + Q_PROPERTY(bool running READ running WRITE setRunning NOTIFY runningChanged) |
1879 | + |
1880 | +public: |
1881 | + LauncherItem(const QString &desktopFile, const QString &name, const QString &icon, QObject *parent = 0); |
1882 | + |
1883 | + QString desktopFile() const; |
1884 | + |
1885 | + QString name() const; |
1886 | + QString icon() const; |
1887 | + |
1888 | + bool favorite() const; |
1889 | + void setFavorite(bool favorite); |
1890 | + |
1891 | + bool running() const; |
1892 | + void setRunning(bool running); |
1893 | + |
1894 | +Q_SIGNALS: |
1895 | + void favoriteChanged(bool favorite); |
1896 | + void runningChanged(bool running); |
1897 | + |
1898 | +private: |
1899 | + QString m_desktopFile; |
1900 | + QString m_name; |
1901 | + QString m_icon; |
1902 | + bool m_favorite; |
1903 | + bool m_running; |
1904 | +}; |
1905 | |
1906 | === modified file 'tests/qmltests/plugins/Unity/fake_unity_plugin.cpp' |
1907 | --- tests/qmltests/plugins/Unity/fake_unity_plugin.cpp 2013-05-02 23:05:09 +0000 |
1908 | +++ tests/qmltests/plugins/Unity/fake_unity_plugin.cpp 2013-06-04 12:32:22 +0000 |
1909 | @@ -23,6 +23,7 @@ |
1910 | #include "fake_lenses.h" |
1911 | #include "categories.h" |
1912 | #include "categoryfilter.h" |
1913 | +#include "fake_launchermodel.h" |
1914 | |
1915 | // External |
1916 | #include <glib-object.h> |
1917 | @@ -40,4 +41,6 @@ |
1918 | qmlRegisterType<Lens>(uri, 0, 1, "Lens"); |
1919 | qmlRegisterType<Categories>(uri, 0, 1, "Categories"); |
1920 | qmlRegisterType<CategoryFilter>(uri, 0, 1, "CategoryFilter"); |
1921 | + qmlRegisterType<LauncherModel>(uri, 0, 1, "LauncherModel"); |
1922 | + qmlRegisterUncreatableType<LauncherItem>(uri, 0, 1, "LauncherItem", "Can't create"); |
1923 | } |
FAILED: Continuous integration, rev:629 jenkins. qa.ubuntu. com/job/ unity-phablet- ci/1070/ s-jenkins: 8080/job/ unity-phablet- qmluitests/ 1076 jenkins. qa.ubuntu. com/job/ unity-phablet- raring- armhf-ci/ 945/console jenkins. qa.ubuntu. com/job/ unity-phablet- raring- i386-ci/ 949/console
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ unity-phablet- ci/1070/ rebuild
http://