Merge lp:~osomon/webbrowser-app/contextual-selection into lp:webbrowser-app
- contextual-selection
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Olivier Tilloy | ||||
Approved revision: | 587 | ||||
Merged at revision: | 590 | ||||
Proposed branch: | lp:~osomon/webbrowser-app/contextual-selection | ||||
Merge into: | lp:webbrowser-app | ||||
Diff against target: |
680 lines (+340/-61) 14 files modified
.bzrignore (+1/-1) debian/control (+10/-11) debian/qtdeclarative5-ubuntu-web-plugin-assets.install (+1/-1) debian/rules (+3/-1) src/Ubuntu/Components/Extras/Browser/CMakeLists.txt (+2/-7) src/Ubuntu/Web/CMakeLists.txt (+3/-0) src/Ubuntu/Web/Selection.qml (+10/-2) src/Ubuntu/Web/SelectionHandle.qml (+1/-3) src/Ubuntu/Web/UbuntuWebView02.qml (+152/-30) src/Ubuntu/Web/selection02.js (+40/-1) src/app/WebViewImpl.qml (+4/-4) tests/autopilot/webbrowser_app/emulators/browser.py (+16/-0) tests/autopilot/webbrowser_app/tests/http_server.py (+6/-0) tests/autopilot/webbrowser_app/tests/test_selection.py (+91/-0) |
||||
To merge this branch: | bzr merge lp:~osomon/webbrowser-app/contextual-selection | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Didier Roche-Tolomelli | Approve | ||
Review via email: mp+223760@code.launchpad.net |
Commit message
Re-enable contextual selection that had been disabled when switching to oxide.
Packaging change: renamed the qtdeclarative5-
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
- 579. By Olivier Tilloy
-
Fix dismissing the current selection when the screen is rotated.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:579
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:579
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:579
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:579
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:579
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 580. By Olivier Tilloy
-
Merge the latest changes from trunk and resolve a conflict.
- 581. By Olivier Tilloy
-
Autopilot tests for the selection functionality.
- 582. By Olivier Tilloy
-
Add a custom Selection emulator.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:580
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 583. By Olivier Tilloy
-
Correctly grab the handles.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:582
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:583
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 584. By Olivier Tilloy
-
(Try to) ensure that the selection actions won’t get in the way of resizing by covering the handles.
Since the actions popover is automatically positioned, we don’t have full control over where it will end up, and there are tons of tricky corner cases, but this should at least make the autopilot test reliable at various screen sizes, including N4, N7 and desktop.
Didier Roche-Tolomelli (didrocks) wrote : | # |
See the inline comment, once that's fixed: +1
- 585. By Olivier Tilloy
-
Remove useless Replaces stanza, thanks didrocks for the review.
Didier Roche-Tolomelli (didrocks) wrote : | # |
+1 on the packaging change
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:584
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:585
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 586. By Olivier Tilloy
-
Cleaner way of simulating a long press, and increase the long press duration to trigger the selection on devices.
- 587. By Olivier Tilloy
-
Revert the last change as it makes autopilot tests fail on device, but keep the longer duration for the long press that triggers the selection.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:586
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:587
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:587
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:587
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2014-05-30 16:16:56 +0000 |
3 | +++ .bzrignore 2014-06-27 11:51:58 +0000 |
4 | @@ -30,8 +30,8 @@ |
5 | debian/files |
6 | debian/tmp/ |
7 | debian/qtdeclarative5-ubuntu-ui-extras-browser-plugin/ |
8 | -debian/qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets/ |
9 | debian/qtdeclarative5-ubuntu-web-plugin/ |
10 | +debian/qtdeclarative5-ubuntu-web-plugin-assets/ |
11 | debian/webapp-container/ |
12 | debian/webapp-container-autopilot/ |
13 | debian/webbrowser-app/ |
14 | |
15 | === modified file 'debian/control' |
16 | --- debian/control 2014-06-16 08:34:26 +0000 |
17 | +++ debian/control 2014-06-27 11:51:58 +0000 |
18 | @@ -78,7 +78,6 @@ |
19 | ${shlibs:Depends}, |
20 | libqt5webkit5-qmlwebkitplugin, |
21 | qtdeclarative5-qtquick2-plugin, |
22 | - qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets (>= ${source:Version}), |
23 | qtdeclarative5-ubuntu-ui-toolkit-plugin, |
24 | qtdeclarative5-ubuntu-web-plugin (= ${binary:Version}), |
25 | qtdeclarative5-window-plugin, |
26 | @@ -89,16 +88,6 @@ |
27 | (versions 0.1 based on WebKit and 0.2 based on Oxide), in the |
28 | Ubuntu.Components.Extras.Browser module. |
29 | |
30 | -Package: qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets |
31 | -Architecture: all |
32 | -Multi-Arch: foreign |
33 | -Depends: ${misc:Depends}, |
34 | -Description: Ubuntu web QML plugin assets |
35 | - A standalone QML plugin that contains the UbuntuWebView component |
36 | - (versions 0.1 based on WebKit and 0.2 based on Oxide), in the |
37 | - Ubuntu.Components.Extras.Browser module. This package contains the |
38 | - PNGs used as UI elements by the plugin. |
39 | - |
40 | Package: qtdeclarative5-ubuntu-web-plugin |
41 | Architecture: any |
42 | Multi-Arch: same |
43 | @@ -108,11 +97,21 @@ |
44 | liboxideqt-qmlplugin, |
45 | qtdeclarative5-qtquick2-plugin, |
46 | qtdeclarative5-ubuntu-ui-toolkit-plugin, |
47 | + qtdeclarative5-ubuntu-web-plugin-assets (>= ${source:Version}), |
48 | qtdeclarative5-window-plugin, |
49 | Description: Ubuntu web QML plugin |
50 | A standalone QML plugin that contains the WebView component, |
51 | in the Ubuntu.Web module. |
52 | |
53 | +Package: qtdeclarative5-ubuntu-web-plugin-assets |
54 | +Architecture: all |
55 | +Multi-Arch: foreign |
56 | +Depends: ${misc:Depends}, |
57 | +Description: Ubuntu web QML plugin assets |
58 | + A standalone QML plugin that contains the WebView component, |
59 | + in the Ubuntu.Web module. This package contains the PNGs used |
60 | + as UI elements by the plugin. |
61 | + |
62 | Package: webbrowser-app-autopilot |
63 | Architecture: all |
64 | Multi-Arch: foreign |
65 | |
66 | === renamed file 'debian/qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets.install' => 'debian/qtdeclarative5-ubuntu-web-plugin-assets.install' |
67 | --- debian/qtdeclarative5-ubuntu-ui-extras-browser-plugin-assets.install 2013-07-18 14:15:53 +0000 |
68 | +++ debian/qtdeclarative5-ubuntu-web-plugin-assets.install 2014-06-27 11:51:58 +0000 |
69 | @@ -1,1 +1,1 @@ |
70 | -usr/share/qtdeclarative5-ubuntu-ui-extras-browser-plugin/ |
71 | +usr/share/qtdeclarative5-ubuntu-web-plugin/ |
72 | |
73 | === modified file 'debian/rules' |
74 | --- debian/rules 2014-03-04 09:32:47 +0000 |
75 | +++ debian/rules 2014-06-27 11:51:58 +0000 |
76 | @@ -11,7 +11,9 @@ |
77 | dh $@ --parallel --with translations |
78 | |
79 | override_dh_install: |
80 | - ln -sf /usr/share/qtdeclarative5-ubuntu-ui-extras-browser-plugin/assets \ |
81 | + ln -sf /usr/share/qtdeclarative5-ubuntu-web-plugin/assets \ |
82 | + $(CURDIR)/debian/tmp/usr/lib/*/qt5/qml/Ubuntu/Web |
83 | + ln -sf /usr/share/qtdeclarative5-ubuntu-web-plugin/assets \ |
84 | $(CURDIR)/debian/tmp/usr/lib/*/qt5/qml/Ubuntu/Components/Extras/Browser |
85 | dh_install --fail-missing |
86 | |
87 | |
88 | === modified file 'src/Ubuntu/Components/Extras/Browser/CMakeLists.txt' |
89 | --- src/Ubuntu/Components/Extras/Browser/CMakeLists.txt 2014-05-29 17:03:44 +0000 |
90 | +++ src/Ubuntu/Components/Extras/Browser/CMakeLists.txt 2014-06-27 11:51:58 +0000 |
91 | @@ -13,19 +13,14 @@ |
92 | file(GLOB QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml qmldir *.js) |
93 | install(TARGETS ${PLUGIN} DESTINATION ${WEBBROWSER_IMPORTS_DIR}) |
94 | install(FILES ${QML_FILES} DESTINATION ${WEBBROWSER_IMPORTS_DIR}) |
95 | -install(DIRECTORY assets |
96 | - DESTINATION ${CMAKE_INSTALL_DATADIR}/qtdeclarative5-ubuntu-ui-extras-browser-plugin |
97 | - FILES_MATCHING PATTERN *.png) |
98 | |
99 | if(NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) |
100 | # copy qml files and assets over to build dir to be able to import them uninstalled |
101 | - file(GLOB ASSETS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} assets/*) |
102 | - set(copied ${QML_FILES} ${ASSETS}) |
103 | - foreach(_file ${copied}) |
104 | + foreach(_file ${QML_FILES}) |
105 | add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_file} |
106 | DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_file} |
107 | COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${_file} ${CMAKE_CURRENT_BINARY_DIR}/${_file}) |
108 | endforeach(_file) |
109 | - add_custom_target(copy_files_to_build_dir_legacy DEPENDS ${copied}) |
110 | + add_custom_target(copy_files_to_build_dir_legacy DEPENDS ${QML_FILES}) |
111 | add_dependencies(${PLUGIN} copy_files_to_build_dir_legacy) |
112 | endif() |
113 | |
114 | === added symlink 'src/Ubuntu/Components/Extras/Browser/Selection.qml' |
115 | === target is u'../../../Web/Selection.qml' |
116 | === added symlink 'src/Ubuntu/Components/Extras/Browser/SelectionHandle.qml' |
117 | === target is u'../../../Web/SelectionHandle.qml' |
118 | === added symlink 'src/Ubuntu/Components/Extras/Browser/assets' |
119 | === target is u'../../../Web/assets/' |
120 | === modified file 'src/Ubuntu/Web/CMakeLists.txt' |
121 | --- src/Ubuntu/Web/CMakeLists.txt 2014-05-29 17:03:44 +0000 |
122 | +++ src/Ubuntu/Web/CMakeLists.txt 2014-06-27 11:51:58 +0000 |
123 | @@ -13,6 +13,9 @@ |
124 | file(GLOB QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml qmldir *.js) |
125 | install(TARGETS ${PLUGIN} DESTINATION ${UBUNTU_WEB_IMPORTS_DIR}) |
126 | install(FILES ${QML_FILES} DESTINATION ${UBUNTU_WEB_IMPORTS_DIR}) |
127 | +install(DIRECTORY assets |
128 | + DESTINATION ${CMAKE_INSTALL_DATADIR}/qtdeclarative5-ubuntu-web-plugin |
129 | + FILES_MATCHING PATTERN *.png) |
130 | |
131 | if(NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) |
132 | # copy qml files over to build dir to be able to import them uninstalled |
133 | |
134 | === renamed file 'src/Ubuntu/Components/Extras/Browser/Selection.qml' => 'src/Ubuntu/Web/Selection.qml' |
135 | --- src/Ubuntu/Components/Extras/Browser/Selection.qml 2013-03-08 10:53:16 +0000 |
136 | +++ src/Ubuntu/Web/Selection.qml 2014-06-27 11:51:58 +0000 |
137 | @@ -1,5 +1,5 @@ |
138 | /* |
139 | - * Copyright 2013 Canonical Ltd. |
140 | + * Copyright 2013-2014 Canonical Ltd. |
141 | * |
142 | * This file is part of webbrowser-app. |
143 | * |
144 | @@ -27,16 +27,20 @@ |
145 | property real __minimumWidth: units.gu(5) |
146 | property real __minimumHeight: units.gu(5) |
147 | |
148 | + readonly property bool resizing: __leftHandle.dragging || __topHandle.dragging || __rightHandle.dragging || __bottomHandle.dragging |
149 | + |
150 | signal resized() |
151 | + signal dismissed() |
152 | |
153 | MouseArea { |
154 | anchors.fill: parent |
155 | // dismiss the selection when tapping anywhere except for the handles |
156 | - onClicked: __container.visible = false |
157 | + onClicked: __container.dismissed() |
158 | } |
159 | |
160 | Item { |
161 | id: __rect |
162 | + objectName: "rectangle" |
163 | } |
164 | |
165 | Rectangle { |
166 | @@ -91,6 +95,7 @@ |
167 | |
168 | SelectionHandle { |
169 | id: __leftHandle |
170 | + objectName: "leftHandle" |
171 | axis: Drag.XAxis |
172 | x: __rect.x - width / 2 |
173 | y: (__topHandle.y + __bottomHandle.y) / 2 |
174 | @@ -107,6 +112,7 @@ |
175 | |
176 | SelectionHandle { |
177 | id: __topHandle |
178 | + objectName: "topHandle" |
179 | axis: Drag.YAxis |
180 | x: (__leftHandle.x + __rightHandle.x) / 2 |
181 | y: __rect.y - height / 2 |
182 | @@ -123,6 +129,7 @@ |
183 | |
184 | SelectionHandle { |
185 | id: __rightHandle |
186 | + objectName: "rightHandle" |
187 | axis: Drag.XAxis |
188 | x: __rect.x + __rect.width - width / 2 |
189 | y: (__topHandle.y + __bottomHandle.y) / 2 |
190 | @@ -138,6 +145,7 @@ |
191 | |
192 | SelectionHandle { |
193 | id: __bottomHandle |
194 | + objectName: "bottomHandle" |
195 | axis: Drag.YAxis |
196 | x: (__leftHandle.x + __rightHandle.x) / 2 |
197 | y: __rect.y + __rect.height - height / 2 |
198 | |
199 | === renamed file 'src/Ubuntu/Components/Extras/Browser/SelectionHandle.qml' => 'src/Ubuntu/Web/SelectionHandle.qml' |
200 | --- src/Ubuntu/Components/Extras/Browser/SelectionHandle.qml 2013-03-08 10:53:16 +0000 |
201 | +++ src/Ubuntu/Web/SelectionHandle.qml 2014-06-27 11:51:58 +0000 |
202 | @@ -1,5 +1,5 @@ |
203 | /* |
204 | - * Copyright 2013 Canonical Ltd. |
205 | + * Copyright 2013-2014 Canonical Ltd. |
206 | * |
207 | * This file is part of webbrowser-app. |
208 | * |
209 | @@ -23,8 +23,6 @@ |
210 | property int axis |
211 | property real minimum |
212 | property real maximum |
213 | - // Known issue: when dragging outside the window, the drag is canceled, |
214 | - // but dragging remains true. See QTBUG-29146. |
215 | property bool dragging: __mousearea.drag.active |
216 | |
217 | width: units.gu(3) |
218 | |
219 | === modified file 'src/Ubuntu/Web/UbuntuWebView02.qml' |
220 | --- src/Ubuntu/Web/UbuntuWebView02.qml 2014-06-11 09:31:38 +0000 |
221 | +++ src/Ubuntu/Web/UbuntuWebView02.qml 2014-06-27 11:51:58 +0000 |
222 | @@ -1,5 +1,5 @@ |
223 | /* |
224 | - * Copyright 2013 Canonical Ltd. |
225 | + * Copyright 2013-2014 Canonical Ltd. |
226 | * |
227 | * This file is part of webbrowser-app. |
228 | * |
229 | @@ -62,29 +62,36 @@ |
230 | msgId: "contextmenu" |
231 | contexts: ["oxide://selection/"] |
232 | callback: function(msg, frame) { |
233 | - if (('img' in msg.args) || ('href' in msg.args)) { |
234 | - if (internal.currentContextualMenu != null) { |
235 | - PopupUtils.close(internal.currentContextualMenu) |
236 | - } |
237 | - contextualData.clear() |
238 | - if ('img' in msg.args) { |
239 | - contextualData.img = msg.args.img |
240 | - } |
241 | - if ('href' in msg.args) { |
242 | - contextualData.href = msg.args.href |
243 | - contextualData.title = msg.args.title |
244 | - } |
245 | - if (contextualActions != null) { |
246 | - for (var i = 0; i < contextualActions.actions.length; ++i) { |
247 | - if (contextualActions.actions[i].enabled) { |
248 | - contextualRectangle.position(msg.args) |
249 | - internal.currentContextualMenu = PopupUtils.open(contextualPopover, contextualRectangle) |
250 | - break |
251 | - } |
252 | - } |
253 | - } |
254 | - } else if (internal.currentContextualMenu != null) { |
255 | - PopupUtils.close(internal.currentContextualMenu) |
256 | + internal.dismissCurrentContextualMenu() |
257 | + internal.dismissCurrentSelection() |
258 | + internal.fillContextualData(msg.args) |
259 | + if (contextualActions != null) { |
260 | + for (var i = 0; i < contextualActions.actions.length; ++i) { |
261 | + if (contextualActions.actions[i].enabled) { |
262 | + contextualRectangle.position(msg.args) |
263 | + internal.currentContextualMenu = PopupUtils.open(contextualPopover, contextualRectangle) |
264 | + break |
265 | + } |
266 | + } |
267 | + } |
268 | + } |
269 | + }, |
270 | + Oxide.ScriptMessageHandler { |
271 | + msgId: "selection" |
272 | + contexts: ["oxide://selection/"] |
273 | + callback: function(msg, frame) { |
274 | + internal.dismissCurrentSelection() |
275 | + internal.dismissCurrentContextualMenu() |
276 | + if (selectionActions != null) { |
277 | + for (var i = 0; i < selectionActions.actions.length; ++i) { |
278 | + if (selectionActions.actions[i].enabled) { |
279 | + var mimedata = internal.buildMimedata(msg.args) |
280 | + var bounds = internal.computeBounds(msg.args) |
281 | + internal.currentSelection = selection.createObject(_webview, {mimedata: mimedata, bounds: bounds}) |
282 | + internal.currentSelection.showActions() |
283 | + break |
284 | + } |
285 | + } |
286 | } |
287 | } |
288 | }, |
289 | @@ -92,9 +99,8 @@ |
290 | msgId: "scroll" |
291 | contexts: ["oxide://selection/"] |
292 | callback: function(msg, frame) { |
293 | - if (internal.currentContextualMenu != null) { |
294 | - PopupUtils.close(internal.currentContextualMenu) |
295 | - } |
296 | + internal.dismissCurrentContextualMenu() |
297 | + internal.dismissCurrentSelection() |
298 | } |
299 | } |
300 | ] |
301 | @@ -140,10 +146,127 @@ |
302 | } |
303 | } |
304 | |
305 | + property ActionList selectionActions |
306 | + onSelectionActionsChanged: { |
307 | + for (var i in selectionActions.actions) { |
308 | + selectionActions.actions[i].onTriggered.connect(function () { |
309 | + internal.dismissCurrentSelection() |
310 | + }) |
311 | + } |
312 | + } |
313 | + Component { |
314 | + id: selection |
315 | + Selection { |
316 | + anchors.fill: parent |
317 | + property var mimedata: null |
318 | + property rect bounds |
319 | + onBoundsChanged: { |
320 | + rect.x = bounds.x |
321 | + rect.y = bounds.y |
322 | + rect.width = bounds.width |
323 | + rect.height = bounds.height |
324 | + } |
325 | + property Item actions: null |
326 | + Component { |
327 | + id: selectionPopover |
328 | + ActionSelectionPopover { |
329 | + objectName: "selectionActions" |
330 | + autoClose: false |
331 | + actions: selectionActions |
332 | + } |
333 | + } |
334 | + function showActions() { |
335 | + if (actions != null) { |
336 | + actions.destroy() |
337 | + } |
338 | + actions = PopupUtils.open(selectionPopover, rect) |
339 | + } |
340 | + onResizingChanged: { |
341 | + if (resizing) { |
342 | + if (actions != null) { |
343 | + actions.destroy() |
344 | + } |
345 | + } |
346 | + } |
347 | + onResized: { |
348 | + var args = {x: rect.x, y: rect.y, width: rect.width, height: rect.height} |
349 | + var msg = _webview.rootFrame.sendMessage("oxide://selection/", "adjustselection", args) |
350 | + msg.onreply = function(response) { |
351 | + internal.currentSelection.mimedata = internal.buildMimedata(response) |
352 | + // Ensure that the bounds are updated |
353 | + internal.currentSelection.bounds = Qt.rect(0, 0, 0, 0) |
354 | + internal.currentSelection.bounds = internal.computeBounds(response) |
355 | + internal.currentSelection.showActions() |
356 | + } |
357 | + msg.onerror = function(error) { |
358 | + internal.dismissCurrentSelection() |
359 | + } |
360 | + } |
361 | + onDismissed: internal.dismissCurrentSelection() |
362 | + } |
363 | + } |
364 | + function copy() { |
365 | + if (internal.currentSelection != null) { |
366 | + Clipboard.push(internal.currentSelection.mimedata) |
367 | + } else { |
368 | + console.warn("No current selection") |
369 | + } |
370 | + } |
371 | + |
372 | QtObject { |
373 | id: internal |
374 | property int lastLoadRequestStatus: -1 |
375 | property Item currentContextualMenu: null |
376 | + property Item currentSelection: null |
377 | + |
378 | + function fillContextualData(data) { |
379 | + contextualData.clear() |
380 | + if ('img' in data) { |
381 | + contextualData.img = data.img |
382 | + } |
383 | + if ('href' in data) { |
384 | + contextualData.href = data.href |
385 | + contextualData.title = data.title |
386 | + } |
387 | + } |
388 | + |
389 | + function buildMimedata(data) { |
390 | + var mimedata = Clipboard.newData() |
391 | + if ('html' in data) { |
392 | + mimedata.html = data.html |
393 | + } |
394 | + // FIXME: push the text and image data in the order |
395 | + // they appear in the selected block. |
396 | + if ('text' in data) { |
397 | + mimedata.text = data.text |
398 | + } |
399 | + if ('images' in data) { |
400 | + // TODO: download and cache the images locally |
401 | + // (grab them from the webview’s cache, if possible), |
402 | + // and forward local URLs. |
403 | + mimedata.urls = data.images |
404 | + } |
405 | + return mimedata |
406 | + } |
407 | + |
408 | + function computeBounds(data) { |
409 | + return Qt.rect(data.left * data.scaleX, data.top * data.scaleY, |
410 | + data.width * data.scaleX, data.height * data.scaleY) |
411 | + } |
412 | + |
413 | + function dismissCurrentContextualMenu() { |
414 | + if (currentContextualMenu != null) { |
415 | + PopupUtils.close(currentContextualMenu) |
416 | + } |
417 | + } |
418 | + |
419 | + function dismissCurrentSelection() { |
420 | + if (currentSelection != null) { |
421 | + // For some reason a 0 delay fails to destroy the selection |
422 | + // when it was requested upon a screen orientation change… |
423 | + currentSelection.destroy(1) |
424 | + } |
425 | + } |
426 | } |
427 | |
428 | readonly property bool lastLoadSucceeded: internal.lastLoadRequestStatus === Oxide.LoadEvent.TypeSucceeded |
429 | @@ -157,9 +280,8 @@ |
430 | |
431 | readonly property int screenOrientation: Screen.orientation |
432 | onScreenOrientationChanged: { |
433 | - if (internal.currentContextualMenu != null) { |
434 | - PopupUtils.close(internal.currentContextualMenu) |
435 | - } |
436 | + internal.dismissCurrentContextualMenu() |
437 | + internal.dismissCurrentSelection() |
438 | } |
439 | |
440 | onFullscreenRequested: _webview.fullscreen = fullscreen |
441 | |
442 | === renamed directory 'src/Ubuntu/Components/Extras/Browser/assets' => 'src/Ubuntu/Web/assets' |
443 | === modified file 'src/Ubuntu/Web/selection02.js' |
444 | --- src/Ubuntu/Web/selection02.js 2014-05-29 16:45:21 +0000 |
445 | +++ src/Ubuntu/Web/selection02.js 2014-06-27 11:51:58 +0000 |
446 | @@ -16,6 +16,12 @@ |
447 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
448 | */ |
449 | |
450 | +function elementContainedInBox(element, box) { |
451 | + var rect = element.getBoundingClientRect(); |
452 | + return ((box.left <= rect.left) && (box.right >= rect.right) && |
453 | + (box.top <= rect.top) && (box.bottom >= rect.bottom)); |
454 | +} |
455 | + |
456 | function getImgFullUri(uri) { |
457 | if ((uri.slice(0, 7) === 'http://') || |
458 | (uri.slice(0, 8) === 'https://') || |
459 | @@ -98,15 +104,48 @@ |
460 | return data; |
461 | } |
462 | |
463 | +function adjustSelection(selection) { |
464 | + // FIXME: allow selecting two consecutive blocks, instead of |
465 | + // interpolating to the containing block. |
466 | + var centerX = (selection.left + selection.right) / 2; |
467 | + var centerY = (selection.top + selection.bottom) / 2; |
468 | + var element = document.elementFromPoint(centerX, centerY); |
469 | + var parent = element; |
470 | + while (elementContainedInBox(parent, selection)) { |
471 | + parent = parent.parentNode; |
472 | + } |
473 | + element = parent; |
474 | + return getSelectedData(element); |
475 | +} |
476 | + |
477 | document.documentElement.addEventListener('contextmenu', function(event) { |
478 | var element = document.elementFromPoint(event.clientX, event.clientY); |
479 | var data = getSelectedData(element); |
480 | var w = document.defaultView; |
481 | data['scaleX'] = w.outerWidth / w.innerWidth * w.devicePixelRatio; |
482 | data['scaleY'] = w.outerHeight / w.innerHeight * w.devicePixelRatio; |
483 | - oxide.sendMessage('contextmenu', data); |
484 | + if (('img' in data) || ('href' in data)) { |
485 | + oxide.sendMessage('contextmenu', data); |
486 | + } else { |
487 | + oxide.sendMessage('selection', data); |
488 | + } |
489 | }); |
490 | |
491 | document.defaultView.addEventListener('scroll', function(event) { |
492 | oxide.sendMessage('scroll', {}); |
493 | }); |
494 | + |
495 | +oxide.addMessageHandler("adjustselection", function (msg) { |
496 | + var w = document.defaultView; |
497 | + var scaleX = w.outerWidth / w.innerWidth * w.devicePixelRatio; |
498 | + var scaleY = w.outerHeight / w.innerHeight * w.devicePixelRatio; |
499 | + var selection = new Object; |
500 | + selection.left = msg.args.x / scaleX; |
501 | + selection.right = selection.left + msg.args.width / scaleX; |
502 | + selection.top = msg.args.y / scaleY; |
503 | + selection.bottom = selection.top + msg.args.height / scaleY; |
504 | + var adjusted = adjustSelection(selection); |
505 | + adjusted['scaleX'] = scaleX; |
506 | + adjusted['scaleY'] = scaleY; |
507 | + msg.reply(adjusted); |
508 | +}); |
509 | |
510 | === modified file 'src/app/WebViewImpl.qml' |
511 | --- src/app/WebViewImpl.qml 2014-06-18 05:55:37 +0000 |
512 | +++ src/app/WebViewImpl.qml 2014-06-27 11:51:58 +0000 |
513 | @@ -20,7 +20,7 @@ |
514 | import Ubuntu.Components 0.1 |
515 | import Ubuntu.Components.Popups 0.1 |
516 | import Ubuntu.Web 0.2 |
517 | -//import "actions" as Actions |
518 | +import "actions" as Actions |
519 | |
520 | WebView { |
521 | id: webview |
522 | @@ -42,11 +42,11 @@ |
523 | source: formFactor == "desktop" ? "FilePickerDialog.qml" : "ContentPickerDialog.qml" |
524 | } |
525 | |
526 | - /*selectionActions: ActionList { |
527 | + selectionActions: ActionList { |
528 | Actions.Copy { |
529 | - onTriggered: selection.copy() |
530 | + onTriggered: copy() |
531 | } |
532 | - }*/ |
533 | + } |
534 | |
535 | onGeolocationPermissionRequested: { |
536 | if (webview.toolbar) { |
537 | |
538 | === modified file 'tests/autopilot/webbrowser_app/emulators/browser.py' |
539 | --- tests/autopilot/webbrowser_app/emulators/browser.py 2014-06-18 13:57:07 +0000 |
540 | +++ tests/autopilot/webbrowser_app/emulators/browser.py 2014-06-27 11:51:58 +0000 |
541 | @@ -21,6 +21,15 @@ |
542 | pass |
543 | |
544 | |
545 | +class Selection(uitk.UbuntuUIToolkitEmulatorBase): |
546 | + |
547 | + def get_rectangle(self): |
548 | + return self.select_single("QQuickItem", objectName="rectangle") |
549 | + |
550 | + def get_handle(self, name): |
551 | + return self.select_single("SelectionHandle", objectName=name) |
552 | + |
553 | + |
554 | class Browser(uitk.MainView): |
555 | |
556 | """ |
557 | @@ -106,3 +115,10 @@ |
558 | |
559 | def get_geolocation_dialog(self): |
560 | return self.wait_select_single("GeolocationPermissionRequest") |
561 | + |
562 | + def get_selection(self): |
563 | + return self.wait_select_single(Selection) |
564 | + |
565 | + def get_selection_actions(self): |
566 | + return self.wait_select_single("ActionSelectionPopover", |
567 | + objectName="selectionActions") |
568 | |
569 | === modified file 'tests/autopilot/webbrowser_app/tests/http_server.py' |
570 | --- tests/autopilot/webbrowser_app/tests/http_server.py 2014-06-18 13:57:07 +0000 |
571 | +++ tests/autopilot/webbrowser_app/tests/http_server.py 2014-06-27 11:51:58 +0000 |
572 | @@ -121,6 +121,12 @@ |
573 | html += 'navigator.geolocation.getCurrentPosition(' |
574 | html += 'function r(p) {});</script></body></html>' |
575 | self.send_html(html) |
576 | + elif self.path == "/selection": |
577 | + self.send_response(200) |
578 | + html = '<html><body style="margin: 10%">' |
579 | + html += '<div style="position: absolute; width: 50%; height: 50%; ' |
580 | + html += 'top: 25%; left: 25%"></div></body></html>' |
581 | + self.send_html(html) |
582 | else: |
583 | self.send_error(404) |
584 | |
585 | |
586 | === added file 'tests/autopilot/webbrowser_app/tests/test_selection.py' |
587 | --- tests/autopilot/webbrowser_app/tests/test_selection.py 1970-01-01 00:00:00 +0000 |
588 | +++ tests/autopilot/webbrowser_app/tests/test_selection.py 2014-06-27 11:51:58 +0000 |
589 | @@ -0,0 +1,91 @@ |
590 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
591 | +# |
592 | +# Copyright 2014 Canonical |
593 | +# |
594 | +# This program is free software: you can redistribute it and/or modify it |
595 | +# under the terms of the GNU General Public License version 3, as published |
596 | +# by the Free Software Foundation. |
597 | +# |
598 | +# This program is distributed in the hope that it will be useful, |
599 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
600 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
601 | +# GNU General Public License for more details. |
602 | +# |
603 | +# You should have received a copy of the GNU General Public License |
604 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
605 | + |
606 | +import time |
607 | +from autopilot.platform import model |
608 | +from autopilot.matchers import Eventually |
609 | +from testtools.matchers import Equals, GreaterThan, LessThan |
610 | + |
611 | +from webbrowser_app.tests import StartOpenRemotePageTestCaseBase |
612 | + |
613 | + |
614 | +class TestSelection(StartOpenRemotePageTestCaseBase): |
615 | + |
616 | + def setUp(self): |
617 | + super(TestSelection, self).setUp() |
618 | + url = self.base_url + "/selection" |
619 | + self.go_to_url(url) |
620 | + self.assert_page_eventually_loaded(url) |
621 | + webview = self.main_window.get_current_webview() |
622 | + self.pointing_device.move_to_object(webview) |
623 | + if model() == 'Desktop': |
624 | + self.pointing_device.click(button=3) |
625 | + else: |
626 | + self.pointing_device.press() |
627 | + time.sleep(1.5) |
628 | + self.pointing_device.release() |
629 | + self.selection = self.main_window.get_selection() |
630 | + self.rectangle = self.selection.get_rectangle() |
631 | + self.assertThat(self.rectangle.width, LessThan(webview.width)) |
632 | + self.assertThat(self.rectangle.height, LessThan(webview.height)) |
633 | + self.actions = self.main_window.get_selection_actions() |
634 | + self.assertThat(len(self.actions.select_many("Empty")), Equals(1)) |
635 | + |
636 | + def assert_selection_eventually_dismissed(self): |
637 | + self.actions.wait_until_destroyed() |
638 | + self.selection.wait_until_destroyed() |
639 | + |
640 | + def test_copy_selection(self): |
641 | + copy_action = self.actions.select_single("Empty") |
642 | + self.pointing_device.click_object(copy_action) |
643 | + self.assert_selection_eventually_dismissed() |
644 | + |
645 | + def test_cancel_selection(self): |
646 | + webview = self.main_window.get_current_webview() |
647 | + x = int((webview.globalRect.x + self.rectangle.globalRect.x) / 2) |
648 | + y = int(webview.globalRect.y + webview.globalRect.height / 2) |
649 | + self.pointing_device.move(x, y) |
650 | + self.pointing_device.click() |
651 | + self.assert_selection_eventually_dismissed() |
652 | + |
653 | + def test_resize_selection(self): |
654 | + webview = self.main_window.get_current_webview() |
655 | + rect = self.rectangle.globalRect |
656 | + |
657 | + # Grow selection to the right |
658 | + handle = self.selection.get_handle("rightHandle") |
659 | + x0 = handle.globalRect.x + int(handle.globalRect.width / 2) |
660 | + y0 = handle.globalRect.y + int(handle.globalRect.height / 2) |
661 | + x1 = int((x0 + webview.globalRect.x + webview.globalRect.width) / 2) |
662 | + y1 = y0 |
663 | + self.pointing_device.drag(x0, y0, x1, y1) |
664 | + self.assertThat(self.rectangle.width, |
665 | + Eventually(GreaterThan(rect.width))) |
666 | + self.assertThat(self.rectangle.height, |
667 | + Eventually(GreaterThan(rect.height))) |
668 | + self.actions.wait_until_destroyed() |
669 | + self.actions = self.main_window.get_selection_actions() |
670 | + |
671 | + # Shrink selection from the bottom |
672 | + handle = self.selection.get_handle("bottomHandle") |
673 | + x0 = handle.globalRect.x + int(handle.globalRect.width / 2) |
674 | + y0 = handle.globalRect.y + int(handle.globalRect.height / 2) |
675 | + x1 = x0 |
676 | + y1 = webview.globalRect.y + int(webview.globalRect.height * 0.6) |
677 | + self.pointing_device.drag(x0, y0, x1, y1) |
678 | + self.assertThat(self.rectangle.globalRect, Eventually(Equals(rect))) |
679 | + self.actions.wait_until_destroyed() |
680 | + self.actions = self.main_window.get_selection_actions() |
FAILED: Continuous integration, rev:578 jenkins. qa.ubuntu. com/job/ webbrowser- app-ci/ 879/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- utopic- touch/1042 jenkins. qa.ubuntu. com/job/ generic- mediumtests- utopic/ 939 jenkins. qa.ubuntu. com/job/ webbrowser- app-utopic- amd64-ci/ 78 jenkins. qa.ubuntu. com/job/ webbrowser- app-utopic- armhf-ci/ 78 jenkins. qa.ubuntu. com/job/ webbrowser- app-utopic- armhf-ci/ 78/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ webbrowser- app-utopic- i386-ci/ 78 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- mako/1419 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/1828 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/1828/ artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 8638 jenkins. qa.ubuntu. com/job/ autopilot- testrunner- otto-utopic/ 811 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- amd64/1082 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- amd64/1082/ artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/webbrowser- app-ci/ 879/rebuild
http://