Merge lp:~osomon/webbrowser-app/touch-selection-controller into lp:webbrowser-app

Proposed by Olivier Tilloy
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 1347
Merged at revision: 1380
Proposed branch: lp:~osomon/webbrowser-app/touch-selection-controller
Merge into: lp:webbrowser-app
Diff against target: 348 lines (+222/-12)
7 files modified
debian/control (+2/-2)
src/Ubuntu/Web/CMakeLists.txt (+4/-4)
src/Ubuntu/Web/UbuntuWebView02.qml (+101/-1)
tests/autopilot/webapp_container/tests/test_context_menu.py (+4/-4)
tests/autopilot/webbrowser_app/tests/http_server.py (+6/-0)
tests/autopilot/webbrowser_app/tests/test_contextmenu.py (+2/-1)
tests/autopilot/webbrowser_app/tests/test_touchselection.py (+103/-0)
To merge this branch: bzr merge lp:~osomon/webbrowser-app/touch-selection-controller
Reviewer Review Type Date Requested Status
Alexandre Abreu (community) Approve
PS Jenkins bot continuous-integration Needs Fixing
Review via email: mp+285165@code.launchpad.net

Commit message

Add a touch selection controller.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

branch is OK, although I found a few bugs (weird behaviors rather) in the underlying api impl,

review: Approve
Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

> branch is OK, although I found a few bugs (weird behaviors rather) in the
> underlying api impl,

(just to complement on that, I'll test a bit more & add oxide bugs for those)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alexandre Abreu (abreu-alexandre) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2016-03-01 10:42:32 +0000
3+++ debian/control 2016-03-10 05:58:20 +0000
4@@ -12,7 +12,7 @@
5 hardening-wrapper,
6 libapparmor-dev,
7 libevdev-dev,
8- liboxideqt-qmlplugin (>= 1.9),
9+ liboxideqt-qmlplugin (>= 1.12),
10 libqt5sql5-sqlite,
11 libudev-dev,
12 pkg-config,
13@@ -106,7 +106,7 @@
14 Pre-Depends: ${misc:Pre-Depends}
15 Depends: ${misc:Depends},
16 ${shlibs:Depends},
17- liboxideqt-qmlplugin (>= 1.9),
18+ liboxideqt-qmlplugin (>= 1.12),
19 qml-module-qtquick2 (>= 5.4),
20 qml-module-qtquick-window2 (>= 5.3),
21 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3),
22
23=== modified file 'src/Ubuntu/Web/CMakeLists.txt'
24--- src/Ubuntu/Web/CMakeLists.txt 2015-08-25 13:56:58 +0000
25+++ src/Ubuntu/Web/CMakeLists.txt 2016-03-10 05:58:20 +0000
26@@ -17,17 +17,17 @@
27 Qt5::Qml
28 )
29
30-file(GLOB QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml qmldir *.js)
31+file(GLOB PLUGIN_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml qmldir *.js *.png)
32 install(TARGETS ${PLUGIN} DESTINATION ${UBUNTU_WEB_IMPORTS_DIR})
33-install(FILES ${QML_FILES} DESTINATION ${UBUNTU_WEB_IMPORTS_DIR})
34+install(FILES ${PLUGIN_FILES} DESTINATION ${UBUNTU_WEB_IMPORTS_DIR})
35
36 if(NOT ${CMAKE_CURRENT_BINARY_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
37 # copy qml files over to build dir to be able to import them uninstalled
38- foreach(_file ${QML_FILES})
39+ foreach(_file ${PLUGIN_FILES})
40 add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${_file}
41 DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_file}
42 COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/${_file} ${CMAKE_CURRENT_BINARY_DIR}/${_file})
43 endforeach(_file)
44- add_custom_target(copy_files_to_build_dir DEPENDS ${QML_FILES})
45+ add_custom_target(copy_files_to_build_dir DEPENDS ${PLUGIN_FILES})
46 add_dependencies(${PLUGIN} copy_files_to_build_dir)
47 endif()
48
49=== modified file 'src/Ubuntu/Web/UbuntuWebView02.qml'
50--- src/Ubuntu/Web/UbuntuWebView02.qml 2016-02-09 15:34:24 +0000
51+++ src/Ubuntu/Web/UbuntuWebView02.qml 2016-03-10 05:58:20 +0000
52@@ -18,7 +18,7 @@
53
54 import QtQuick 2.4
55 import QtQuick.Window 2.2
56-import com.canonical.Oxide 1.9 as Oxide
57+import com.canonical.Oxide 1.12 as Oxide
58 import Ubuntu.Components 1.3
59 import Ubuntu.Components.Popups 1.3
60 import "." // QTBUG-34418
61@@ -138,6 +138,106 @@
62 console.warn("WARNING: the copy() function is deprecated and does nothing.")
63 }
64
65+ touchSelectionController.handle: Image {
66+ objectName: "touchSelectionHandle"
67+ readonly property int handleOrientation: orientation
68+ width: units.gu(1.5)
69+ height: units.gu(1.5)
70+ source: "handle.png"
71+ Component.onCompleted: horizontalPaddingRatio = 0.5
72+ }
73+
74+ UbuntuShape {
75+ objectName: "touchSelectionActions"
76+ // FIXME: hide contextual actions while resizing the
77+ // selection (needs an additional API in oxide?)
78+ visible: _webview.activeFocus && _webview.touchSelectionController.active && !selectionOutOfSight
79+ aspect: UbuntuShape.DropShadow
80+ backgroundColor: "white"
81+ readonly property int padding: units.gu(1)
82+ width: touchSelectionActionsRow.width + padding * 2
83+ height: childrenRect.height + padding * 2
84+
85+ readonly property rect bounds: _webview.touchSelectionController.bounds
86+ readonly property bool selectionOutOfSight: (bounds.x > _webview.width) || ((bounds.x + bounds.width) < 0) || (bounds.y > _webview.height) || ((bounds.y + bounds.height) < 0)
87+ readonly property real handleHeight: units.gu(1.5)
88+ readonly property real spacing: units.gu(1)
89+ readonly property bool fitsBelow: (bounds.y + bounds.height + handleHeight + spacing + height) <= _webview.height
90+ readonly property bool fitsAbove: (bounds.y - spacing - height) >= (_webview.locationBarController.height + _webview.locationBarController.offset)
91+ readonly property real xCentered: bounds.x + (bounds.width - width) / 2
92+ x: ((xCentered >= 0) && ((xCentered + width) <= _webview.width))
93+ ? xCentered : (xCentered < 0) ? 0 : _webview.width - width
94+ y: fitsBelow ? (bounds.y + bounds.height + handleHeight + spacing)
95+ : fitsAbove ? (bounds.y - spacing - height)
96+ : (_webview.height + _webview.locationBarController.height + _webview.locationBarController.offset - height) / 2
97+
98+ ActionList {
99+ id: touchSelectionActions
100+ Action {
101+ name: "selectall"
102+ text: i18n.dtr('ubuntu-ui-toolkit', "Select All")
103+ iconName: "edit-select-all"
104+ enabled: _webview.editingCapabilities & Oxide.WebView.SelectAllCapability
105+ visible: enabled
106+ onTriggered: _webview.executeEditingCommand(Oxide.WebView.EditingCommandSelectAll)
107+ }
108+ Action {
109+ name: "cut"
110+ text: i18n.dtr('ubuntu-ui-toolkit', "Cut")
111+ iconName: "edit-cut"
112+ enabled: _webview.editingCapabilities & Oxide.WebView.CutCapability
113+ visible: enabled
114+ onTriggered: _webview.executeEditingCommand(Oxide.WebView.EditingCommandCut)
115+ }
116+ Action {
117+ name: "copy"
118+ text: i18n.dtr('ubuntu-ui-toolkit', "Copy")
119+ iconName: "edit-copy"
120+ enabled: _webview.editingCapabilities & Oxide.WebView.CopyCapability
121+ visible: enabled
122+ onTriggered: _webview.executeEditingCommand(Oxide.WebView.EditingCommandCopy)
123+ }
124+ Action {
125+ name: "paste"
126+ text: i18n.dtr('ubuntu-ui-toolkit', "Paste")
127+ iconName: "edit-paste"
128+ enabled: _webview.editingCapabilities & Oxide.WebView.PasteCapability
129+ visible: enabled
130+ onTriggered: _webview.executeEditingCommand(Oxide.WebView.EditingCommandPaste)
131+ }
132+ }
133+
134+ Row {
135+ id: touchSelectionActionsRow
136+ x: parent.padding
137+ y: parent.padding
138+ width: {
139+ // work around what seems to be a bug in Row’s childrenRect.width
140+ var w = 0
141+ for (var i in visibleChildren) {
142+ w += visibleChildren[i].width
143+ }
144+ return w
145+ }
146+ height: units.gu(6)
147+
148+ Repeater {
149+ model: touchSelectionActions.actions.length
150+ AbstractButton {
151+ objectName: "touchSelectionAction_" + action.name
152+ anchors {
153+ top: parent.top
154+ bottom: parent.bottom
155+ }
156+ width: Math.max(units.gu(5), implicitWidth) + units.gu(2)
157+ action: touchSelectionActions.actions[modelData]
158+ styleName: "ToolbarButtonStyle"
159+ activeFocusOnPress: false
160+ }
161+ }
162+ }
163+ }
164+
165 QtObject {
166 id: internal
167 property int lastLoadRequestStatus: -1
168
169=== added file 'src/Ubuntu/Web/handle@27.png'
170Binary files src/Ubuntu/Web/handle@27.png 1970-01-01 00:00:00 +0000 and src/Ubuntu/Web/handle@27.png 2016-03-10 05:58:20 +0000 differ
171=== modified file 'tests/autopilot/webapp_container/tests/test_context_menu.py'
172--- tests/autopilot/webapp_container/tests/test_context_menu.py 2016-03-07 18:10:35 +0000
173+++ tests/autopilot/webapp_container/tests/test_context_menu.py 2016-03-10 05:58:20 +0000
174@@ -1,6 +1,6 @@
175 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
176 #
177-# Copyright 2015 Canonical
178+# Copyright 2015-2016 Canonical
179 #
180 # This program is free software: you can redistribute it and/or modify it
181 # under the terms of the GNU General Public License version 3, as published
182@@ -16,11 +16,10 @@
183
184 import time
185
186-import testtools
187-
188 from autopilot.platform import model
189 from autopilot.matchers import Eventually
190-from testtools.matchers import Equals, StartsWith, GreaterThan
191+import testtools
192+from testtools.matchers import Equals, GreaterThan, StartsWith
193
194 from webapp_container.tests import WebappContainerTestCaseWithLocalContentBase
195
196@@ -299,6 +298,7 @@
197 self._test_copy_image()
198
199
200+@testtools.skipIf(model() != "Desktop", "on desktop only")
201 class TestContextMenuTextArea(TestContextMenuBase):
202
203 def _test_actions(self):
204
205=== modified file 'tests/autopilot/webbrowser_app/tests/http_server.py'
206--- tests/autopilot/webbrowser_app/tests/http_server.py 2016-02-29 20:42:13 +0000
207+++ tests/autopilot/webbrowser_app/tests/http_server.py 2016-03-10 05:58:20 +0000
208@@ -246,6 +246,12 @@
209 html += 'history.pushState(null, null, "/statepushed"); });'
210 html += '</script></body></html>'
211 self.send_html(html)
212+ elif self.path == "/super":
213+ self.send_response(200)
214+ html = '<html><body><div style="position: fixed; top: 50%; left: '
215+ html += '50%; transform: translate(-50%, -50%); font-size: 500%">'
216+ html += 'Supercalifragilisticexpialidocious</div></body></html>'
217+ self.send_html(html)
218 else:
219 self.send_error(404)
220
221
222=== modified file 'tests/autopilot/webbrowser_app/tests/test_contextmenu.py'
223--- tests/autopilot/webbrowser_app/tests/test_contextmenu.py 2016-01-05 08:35:58 +0000
224+++ tests/autopilot/webbrowser_app/tests/test_contextmenu.py 2016-03-10 05:58:20 +0000
225@@ -1,6 +1,6 @@
226 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
227 #
228-# Copyright 2015 Canonical
229+# Copyright 2015-2016 Canonical
230 #
231 # This program is free software: you can redistribute it and/or modify it
232 # under the terms of the GNU General Public License version 3, as published
233@@ -137,6 +137,7 @@
234 self.menu.click_action("CopyImageContextualAction")
235
236
237+@testtools.skipIf(model() != "Desktop", "on desktop only")
238 class TestContextMenuTextArea(TestContextMenuBase):
239
240 def setUp(self):
241
242=== added file 'tests/autopilot/webbrowser_app/tests/test_touchselection.py'
243--- tests/autopilot/webbrowser_app/tests/test_touchselection.py 1970-01-01 00:00:00 +0000
244+++ tests/autopilot/webbrowser_app/tests/test_touchselection.py 2016-03-10 05:58:20 +0000
245@@ -0,0 +1,103 @@
246+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
247+#
248+# Copyright 2016 Canonical
249+#
250+# This program is free software: you can redistribute it and/or modify it
251+# under the terms of the GNU General Public License version 3, as published
252+# by the Free Software Foundation.
253+#
254+# This program is distributed in the hope that it will be useful,
255+# but WITHOUT ANY WARRANTY; without even the implied warranty of
256+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
257+# GNU General Public License for more details.
258+#
259+# You should have received a copy of the GNU General Public License
260+# along with this program. If not, see <http://www.gnu.org/licenses/>.
261+
262+from autopilot.platform import model
263+import testtools
264+from testtools.matchers import Equals, MatchesAny
265+import time
266+
267+from webbrowser_app.tests import StartOpenRemotePageTestCaseBase
268+
269+
270+class TestTouchSelectionBase(StartOpenRemotePageTestCaseBase):
271+
272+ def get_actions(self):
273+ webview = self.main_window.get_current_webview()
274+ return webview.wait_select_single(objectName="touchSelectionActions",
275+ visible=True)
276+
277+ def long_press_webview(self):
278+ webview = self.main_window.get_current_webview()
279+ chrome = self.main_window.chrome
280+ x = webview.globalRect.x + webview.globalRect.width // 2
281+ y = webview.globalRect.y + \
282+ (webview.globalRect.height + chrome.height) // 2
283+ self.pointing_device.move(x, y)
284+ self.pointing_device.press()
285+ time.sleep(1.5)
286+ self.pointing_device.release()
287+ return self.get_actions()
288+
289+ def get_visible_actions(self, actions):
290+ return actions.select_many(styleName="ToolbarButtonStyle",
291+ visible=True)
292+
293+ def get_handles(self):
294+ webview = self.main_window.get_current_webview()
295+ handles = webview.select_many(objectName="touchSelectionHandle",
296+ visible=True)
297+ handles.sort(key=lambda handle: handle.globalRect.x)
298+ return handles
299+
300+
301+@testtools.skipIf(model() == "Desktop", "on devices only")
302+class TestTouchSelection(TestTouchSelectionBase):
303+
304+ def setUp(self):
305+ super(TestTouchSelection, self).setUp(path="/super")
306+
307+ def test_touch_selection(self):
308+ actions = self.long_press_webview()
309+ self.assertThat(len(self.get_visible_actions(actions)), Equals(2))
310+ actions.select_single(objectName="touchSelectionAction_selectall",
311+ visible=True)
312+ actions.select_single(objectName="touchSelectionAction_copy",
313+ visible=True)
314+
315+ handles = self.get_handles()
316+ self.assertThat(len(handles), Equals(2))
317+ left = 0 # Oxide.TouchSelectionController.HandleOrientationLeft
318+ self.assertThat(handles[0].handleOrientation, Equals(left))
319+ right = 2 # Oxide.TouchSelectionController.HandleOrientationRight
320+ self.assertThat(handles[1].handleOrientation, Equals(right))
321+
322+
323+@testtools.skipIf(model() == "Desktop", "on devices only")
324+class TestTouchInsertion(TestTouchSelectionBase):
325+
326+ def setUp(self):
327+ super(TestTouchInsertion, self).setUp(path="/textarea")
328+
329+ def test_touch_insertion(self):
330+ webview = self.main_window.get_current_webview()
331+ self.pointing_device.click_object(webview)
332+ actions = self.get_actions()
333+ self.assertThat(len(self.get_visible_actions(actions)),
334+ MatchesAny(Equals(1), Equals(2)))
335+ actions.select_single(objectName="touchSelectionAction_selectall",
336+ visible=True)
337+ if len(self.get_visible_actions(actions)) == 2:
338+ actions.select_single(objectName="touchSelectionAction_paste",
339+ visible=True)
340+
341+ handles = self.get_handles()
342+ self.assertThat(len(handles), Equals(1))
343+ center = 1 # Oxide.TouchSelectionController.HandleOrientationCenter
344+ self.assertThat(handles[0].handleOrientation, Equals(center))
345+
346+
347+# TODO: add tests for selection resizing, and activation of the contextual
348+# actions (verifying the contents of the clipboard is a complex task).

Subscribers

People subscribed via source and target branches

to status/vote changes: