Merge lp:~fboucault/ubuntu-ui-toolkit/text_input_larger_selection_handle_on_trunk into lp:ubuntu-ui-toolkit/staging

Proposed by Florian Boucault
Status: Merged
Merged at revision: 1348
Proposed branch: lp:~fboucault/ubuntu-ui-toolkit/text_input_larger_selection_handle_on_trunk
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 720 lines (+286/-155)
12 files modified
modules/Ubuntu/Components/InputHandler.qml (+4/-2)
modules/Ubuntu/Components/Popups/PopupBase.qml (+3/-1)
modules/Ubuntu/Components/TextArea.qml (+2/-0)
modules/Ubuntu/Components/TextCursor.qml (+135/-99)
modules/Ubuntu/Components/TextField.qml (+7/-0)
modules/Ubuntu/Components/TextInputPopover.qml (+20/-5)
modules/Ubuntu/Components/Themes/Ambiance/TextCursorStyle.qml (+2/-1)
modules/Ubuntu/Components/plugin/ucmousefilters.cpp (+1/-0)
tests/autopilot/ubuntuuitoolkit/base.py (+16/-0)
tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.py (+94/-12)
tests/unit_x11/tst_components/tst_textinput_common.qml (+1/-33)
tests/unit_x11/tst_components/tst_textinput_touch.qml (+1/-2)
To merge this branch: bzr merge lp:~fboucault/ubuntu-ui-toolkit/text_input_larger_selection_handle_on_trunk
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Ubuntu SDK team Pending
Review via email: mp+241051@code.launchpad.net

Commit message

Many TextField/TextArea fixes.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1124. By Florian Boucault

Dismiss popover on copy.

1125. By Florian Boucault

Disable select all if there is nothing to select

1126. By Florian Boucault

Reverted handle changes

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1127. By Florian Boucault

Do not disable 'cut' operation when there is nothing to paste but instead when the field is read only.

1128. By Florian Boucault

Reveted changes to push_to_phone.sh

1129. By Florian Boucault

Added bug fixes tags.

1130. By Florian Boucault

Updated components.api

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1131. By Florian Boucault

Sync enabled of Ubuntu.Mouse and MouseArea.

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)
1132. By Florian Boucault

Make sure popup disappears upon drag and reappears when finished.
Make sure that when not blinking the cursor is visible.
Make sure that tapping somewhere else in the field when in insert mode closes the contextual menu.

1133. By Florian Boucault

Removed unused code.

1134. By Florian Boucault

Removed incorrect test.

1135. By Florian Boucault

More robust test_clear_selection_on_click

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)
1136. By Florian Boucault

Fixed components::TextInputTouchTests::test_long_tap_on_selected_text

1137. By Florian Boucault

Fixed test_select_text_by_dragging_cursor_handler

1138. By Florian Boucault

Fixed test_0_drag_autosizing_textarea_drags_parent_flickable

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1139. By Florian Boucault

TextInput: move clear button on top so that it takes priority over tapping on the cursor.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1140. By Florian Boucault

Added autopilot tests for select and insert modes.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1141. By Florian Boucault

TextInput: move clear button on top so that it takes priority over tapping on the cursor.

1142. By Florian Boucault

Fixed pep8 failure

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)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'modules/Ubuntu/Components/InputHandler.qml'
2--- modules/Ubuntu/Components/InputHandler.qml 2014-09-20 08:36:48 +0000
3+++ modules/Ubuntu/Components/InputHandler.qml 2014-11-11 11:50:16 +0000
4@@ -392,7 +392,7 @@
5 }
6 function handleDblClick(event, touch) {
7 if (main.selectByMouse) {
8- input.selectWord();
9+ openContextMenu(event, false);
10 // turn selection state temporarily so the selection is not cleared on release
11 state = "selection";
12 if (touch) {
13@@ -448,13 +448,15 @@
14 }
15
16 // do not open context menu if this is scrolling
17- if (touchPoint.startY - touchPoint.y < -units.dp(2))
18+ if (touchPoint.startY - touchPoint.y < -units.gu(2))
19 return;
20
21 openContextMenu(touchPoint, false);
22 suppressReleaseEvent = true;
23 }
24 }
25+
26+ property bool doubleTapInProgress: doubleTap.running
27 Timer {
28 id: doubleTap
29 property int tapCount: 0
30
31=== modified file 'modules/Ubuntu/Components/Popups/PopupBase.qml'
32--- modules/Ubuntu/Components/Popups/PopupBase.qml 2014-08-22 15:02:28 +0000
33+++ modules/Ubuntu/Components/Popups/PopupBase.qml 2014-11-11 11:50:16 +0000
34@@ -240,7 +240,9 @@
35 ScriptAction {
36 script: {
37 popupBase.visible = false;
38- stateWrapper.restoreActiveFocus();
39+ if (eventGrabber.enabled) {
40+ stateWrapper.restoreActiveFocus();
41+ }
42 }
43 }
44 }
45
46=== modified file 'modules/Ubuntu/Components/TextArea.qml'
47--- modules/Ubuntu/Components/TextArea.qml 2014-10-23 19:57:31 +0000
48+++ modules/Ubuntu/Components/TextArea.qml 2014-11-11 11:50:16 +0000
49@@ -16,6 +16,7 @@
50
51 import QtQuick 2.0
52 import Ubuntu.Components 1.1 as Ubuntu
53+import Ubuntu.Components.Popups 1.0
54 import "mathUtils.js" as MathUtils
55
56 /*!
57@@ -847,6 +848,7 @@
58 mouseSelectionMode: TextEdit.SelectWords
59 selectByMouse: true
60 activeFocusOnPress: true
61+ onActiveFocusChanged: if (!activeFocus && inputHandler.popover) PopupUtils.close(inputHandler.popover)
62 cursorDelegate: TextCursor {
63 handler: inputHandler
64 }
65
66=== modified file 'modules/Ubuntu/Components/TextCursor.qml'
67--- modules/Ubuntu/Components/TextCursor.qml 2014-10-07 15:21:11 +0000
68+++ modules/Ubuntu/Components/TextCursor.qml 2014-11-11 11:50:16 +0000
69@@ -62,33 +62,58 @@
70 The function opens the text input popover setting the text cursor as caller.
71 */
72 Connections {
73- target: inputHandler
74- onPressAndHold: openPopover()
75+ target: handler
76+ onPressAndHold: {
77+ // open context menu only for cursorPosition or selectionStart as to
78+ // ensure that only one popover gets opened
79+ if (positionProperty !== "selectionEnd") {
80+ openPopover();
81+ }
82+ }
83 onTextModified: typing = true
84- onTap: typing = false
85+ onTap: {
86+ typing = false
87+ if (handler.popover != null) {
88+ PopupUtils.close(handler.popover);
89+ }
90+ }
91 }
92
93 function openPopover() {
94- if (!visible || opacity === 0.0 || dragger.drag.active) {
95- return;
96- }
97- // open context menu only for cursorPosition or selectionEnd
98- if (positionProperty !== "selectionStart") {
99- if (inputHandler.popover != null)
100- inputHandler.popover.hide();
101-
102- var component = handler.main.popover;
103- if (component === undefined)
104- component = Qt.resolvedUrl("TextInputPopover.qml");
105- var popup = PopupUtils.open(component, cursorItem, {
106- "target": handler.main
107- });
108- contextMenuVisible = true;
109- popup.onVisibleChanged.connect(contextMenuHidden.bind(undefined, popup));
110- // do not grab focus!
111- popup.__foreground.activeFocusOnPress = false;
112- inputHandler.popover = popup;
113- }
114+ if (!visible || opacity === 0.0 || dragger.dragActive) {
115+ return;
116+ }
117+
118+ if (contextMenuVisible) {
119+ return;
120+ }
121+
122+ if (handler.popover != null) {
123+ PopupUtils.close(handler.popover);
124+ }
125+
126+ var component = handler.main.popover;
127+ if (component === undefined)
128+ component = Qt.resolvedUrl("TextInputPopover.qml");
129+
130+ var popup;
131+ if (fakeCursor.visible) {
132+ popup = PopupUtils.open(component, cursorItem, {
133+ "target": handler.main,
134+ });
135+ } else {
136+ // if the cursor is out of the visible viewport, anchor the
137+ // contextual menu to the input field
138+ popup = PopupUtils.open(component, handler.main, {
139+ "target": handler.main,
140+ });
141+ cursorItem.Component.onDestruction.connect(popup.__closePopup);
142+ }
143+ contextMenuVisible = true;
144+ popup.onVisibleChanged.connect(contextMenuHidden.bind(undefined, popup));
145+ // do not grab focus!
146+ popup.__foreground.activeFocusOnPress = false;
147+ handler.popover = popup;
148 }
149
150 visible: handler.main.cursorVisible
151@@ -133,82 +158,62 @@
152 function contextMenuHidden(p) {
153 contextMenuVisible = false
154 }
155- onXChanged: if (draggedItem.state === "") draggedItem.moveToCaret()
156- onYChanged: if (draggedItem.state === "") draggedItem.moveToCaret()
157+
158+ onXChanged: if (!draggedItemMouseArea.pressed) draggedItem.moveToCaret()
159+ onYChanged: if (!draggedItemMouseArea.pressed) draggedItem.moveToCaret()
160 Component.onCompleted: draggedItem.moveToCaret()
161
162 //dragged item
163 Item {
164 id: draggedItem
165 objectName: cursorItem.positionProperty + "_draggeditem"
166- width: caret ? Math.max(caret.width, units.gu(2)) : 0
167- height: caret ? Math.max(caret.height, units.gu(2)) : 0
168+ width: caret ? units.gu(4) : 0
169+ height: caret ? cursorItem.height : 0
170 parent: handler.main
171 visible: cursorItem.visible && (cursorItem.opacity > 0.0) && QuickUtils.touchScreenAvailable
172
173- // when the dragging ends, reposition the dragger back to caret
174- onStateChanged: {
175- if (state === "") {
176- draggedItem.moveToCaret();
177- }
178- }
179-
180 /*
181 Mouse area to turn on dragging or selection mode when pressed
182 on the handler area. The drag mode is turned off when the drag
183 gets inactive or when the LeftButton is released.
184 */
185 MouseArea {
186+ id: draggedItemMouseArea
187 objectName: cursorItem.positionProperty + "_activator"
188 anchors.fill: parent
189 acceptedButtons: Qt.LeftButton
190 preventStealing: true
191- enabled: parent.width && parent.height && parent.visible
192-
193- onPressed: {
194- draggedItem.moveToCaret(mouse.x, mouse.y);
195- draggedItem.state = "dragging";
196+ enabled: parent.width && parent.height && parent.visible && !handler.doubleTapInProgress
197+ onPressedChanged: {
198+ if (!pressed) {
199+ // when the dragging ends, reposition the dragger back to caret
200+ draggedItem.moveToCaret();
201+ }
202 }
203 Ubuntu.Mouse.forwardTo: [dragger]
204- /*
205- As we are forwarding the events to the upper mouse area, the release
206- will not get into the normal MosueArea onRelease signal as the preventStealing
207- will not have any effect on the handling. However due to the mouse
208- filter's nature, we will still be able to grab mouse events and we
209- can stop dragging. We only handle the release in case the drag hasn't
210- been active at all, otherwise the drag will not be deactivated and we
211- will end up in a binding loop on the moveToCaret() next time the caret
212- handler is grabbed.
213- */
214- Ubuntu.Mouse.onReleased: {
215- if (!dragger.drag.active) {
216- draggedItem.state = "";
217- }
218+ Ubuntu.Mouse.onClicked: openPopover()
219+ Ubuntu.Mouse.onPressAndHold: {
220+ handler.main.selectWord();
221+ handler.pressAndHold(-1);
222 }
223+ Ubuntu.Mouse.onDoubleClicked: handler.main.selectWord()
224+ Ubuntu.Mouse.clickAndHoldThreshold: units.gu(2)
225+ Ubuntu.Mouse.enabled: enabled
226 }
227
228 // aligns the draggedItem to the caret and resets the dragger
229- function moveToCaret(cx, cy) {
230- if (cx === undefined && cy === undefined) {
231- cx = mappedCursorPosition("x") + caretX;
232- cy = mappedCursorPosition("y") + caretY;
233- } else {
234- // move mouse position to caret
235- cx += draggedItem.x;
236- cy += draggedItem.y;
237- }
238-
239- draggedItem.x = cx;
240- draggedItem.y = cy;
241- dragger.resetDrag();
242+ function moveToCaret() {
243+ draggedItem.x = mappedCursorPosition("x") - draggedItem.width / 2;
244+ draggedItem.y = mappedCursorPosition("y");
245 }
246- // positions caret to the dragged position
247+ // positions caret to the dragged posinotion
248 function positionCaret() {
249- if (dragger.drag.active) {
250- var dx = dragger.thumbStartX + dragger.dragAmountX + handler.flickable.contentX;
251- var dy = dragger.thumbStartY + dragger.dragAmountY + handler.flickable.contentY;
252+ if (dragger.dragActive) {
253+ var dx = dragger.dragStartX + dragger.dragAmountX + handler.flickable.contentX;
254+ var dy = dragger.dragStartY + dragger.dragAmountY + handler.flickable.contentY;
255 // consider only the x-distance because of the overlays
256 dx -= handler.frameDistance.x;
257+ dy -= handler.frameDistance.y;
258 handler.positionCaret(positionProperty, dx, dy);
259 }
260 }
261@@ -219,38 +224,69 @@
262 // fill the entire component area
263 parent: handler.main
264 anchors.fill: parent
265- hoverEnabled: true
266- preventStealing: drag.active
267- enabled: draggedItem.enabled && draggedItem.state === "dragging" && QuickUtils.touchScreenAvailable
268+ enabled: draggedItemMouseArea.enabled && draggedItemMouseArea.pressed && QuickUtils.touchScreenAvailable
269+ onEnabledChanged: {
270+ if (enabled) {
271+ dragAmountX = 0;
272+ dragAmountY = 0;
273+ firstMouseXChange = true;
274+ firstMouseYChange = true;
275+ } else {
276+ dragActive = false;
277+ }
278+ }
279
280- property int thumbStartX
281 property int dragStartX
282- property int dragAmountX: dragger.drag.target.x - dragStartX
283- property int thumbStartY
284+ property int dragAmountX
285 property int dragStartY
286- property int dragAmountY: dragger.drag.target.y - dragStartY
287-
288- function resetDrag() {
289- thumbStartX = mappedCursorPosition("x");
290- thumbStartY = mappedCursorPosition("y");
291- dragStartX = drag.target ? drag.target.x : 0;
292- dragStartY = drag.target ? drag.target.y : 0;
293- }
294-
295- // do not set minimum/maximum so we can drag outside of the Flickable area
296- drag {
297- target: draggedItem
298- axis: handler.singleLine ? Drag.XAxis : Drag.XAndYAxis
299- // deactivate dragging
300- onActiveChanged: {
301- if (!drag.active) {
302- draggedItem.state = "";
303- }
304- }
305- }
306-
307- onDragAmountXChanged: draggedItem.positionCaret()
308- onDragAmountYChanged: draggedItem.positionCaret()
309+ property int dragAmountY
310+ property bool dragActive: false
311+ property int dragThreshold: units.gu(2)
312+ property bool firstMouseXChange: true
313+ property bool firstMouseYChange: true
314+
315+ onMouseXChanged: {
316+ if (firstMouseXChange) {
317+ dragStartX = mouseX;
318+ firstMouseXChange = false;
319+ } else {
320+ var amount = mouseX - dragStartX;
321+ if (Math.abs(amount) >= dragThreshold) {
322+ dragActive = true;
323+ }
324+ if (dragActive) {
325+ dragAmountX = amount;
326+ draggedItem.positionCaret();
327+ }
328+ }
329+ }
330+
331+ onMouseYChanged: {
332+ if (firstMouseYChange) {
333+ dragStartY = mouseY;
334+ firstMouseYChange = false;
335+ } else {
336+ var amount = mouseY - dragStartY;
337+ if (Math.abs(amount) >= dragThreshold) {
338+ dragActive = true;
339+ }
340+ if (dragActive) {
341+ dragAmountY = amount;
342+ draggedItem.positionCaret()
343+ }
344+ }
345+ }
346+
347+ onDragActiveChanged: {
348+ // close contextual menu when dragging and reopen it at the end of the drag
349+ if (dragActive) {
350+ if (handler.popover != null) {
351+ PopupUtils.close(handler.popover);
352+ }
353+ } else {
354+ handler.pressAndHold(-1);
355+ }
356+ }
357 }
358
359 // fake cursor, caret is reparented to it to avoid caret clipping
360
361=== modified file 'modules/Ubuntu/Components/TextField.qml'
362--- modules/Ubuntu/Components/TextField.qml 2014-10-23 19:57:31 +0000
363+++ modules/Ubuntu/Components/TextField.qml 2014-11-11 11:50:16 +0000
364@@ -16,6 +16,7 @@
365
366 import QtQuick 2.0
367 import Ubuntu.Components 1.1 as Ubuntu
368+import Ubuntu.Components.Popups 1.0
369
370 /*!
371 \qmltype TextField
372@@ -912,6 +913,11 @@
373 bottom: parent.bottom
374 margins: internal.spacing
375 }
376+ /* draggedItemMouseArea and dragger in TextCursor are reparented to the
377+ TextField and end up being on top of the clear button.
378+ Ensure that the clear button receives touch/mouse events first.
379+ */
380+ z: 100
381 width: visible ? icon.width : 0
382 visible: control.hasClearButton &&
383 !control.readOnly &&
384@@ -991,6 +997,7 @@
385 // overrides
386 selectByMouse: true
387 activeFocusOnPress: true
388+ onActiveFocusChanged: if (!activeFocus && inputHandler.popover) PopupUtils.close(inputHandler.popover)
389
390 // input selection and navigation handling
391 Ubuntu.Mouse.forwardTo: [inputHandler]
392
393=== modified file 'modules/Ubuntu/Components/TextInputPopover.qml'
394--- modules/Ubuntu/Components/TextInputPopover.qml 2014-08-31 19:24:19 +0000
395+++ modules/Ubuntu/Components/TextInputPopover.qml 2014-11-11 11:50:16 +0000
396@@ -26,6 +26,7 @@
397 Action {
398 text: i18n.dtr('ubuntu-ui-toolkit', "Select All")
399 iconName: "edit-select-all"
400+ enabled: target.text !== ""
401 visible: target && target.selectedText === ""
402 onTriggered: target.selectAll()
403 },
404@@ -34,25 +35,40 @@
405 iconName: "edit-cut"
406 // If paste/editing is not possible, then disable also "Cut" operation
407 // It is applicable for ReadOnly's TextFields and TextAreas
408- enabled: target && target.selectedText !== "" && target.canPaste
409+ enabled: target && target.selectedText !== "" && !target.readOnly
410 visible: target.selectedText !== ""
411- onTriggered: target.cut()
412+ onTriggered: {
413+ PopupUtils.close(popover);
414+ target.cut();
415+ }
416 },
417 Action {
418 text: i18n.dtr('ubuntu-ui-toolkit', "Copy")
419 iconName: "edit-copy"
420 enabled: target && target.selectedText !== ""
421 visible: target.selectedText !== ""
422- onTriggered: target.copy()
423+ onTriggered: {
424+ PopupUtils.close(popover);
425+ target.copy();
426+ }
427 },
428 Action {
429 text: i18n.dtr('ubuntu-ui-toolkit', "Paste")
430 iconName: "edit-paste"
431 enabled: target && target.canPaste
432- onTriggered: target.paste()
433+ onTriggered: {
434+ PopupUtils.close(popover);
435+ target.paste();
436+ }
437 }
438 ]
439
440+ // removes hide animation
441+ function hide() {
442+ popover.visible = false;
443+ }
444+
445+ autoClose: false
446 contentHeight: row.childrenRect.height
447 contentWidth: row.childrenRect.width
448 Row {
449@@ -73,7 +89,6 @@
450 height: units.gu(6)
451 action: actions[modelData]
452 style: Theme.createStyleComponent("ToolbarButtonStyle.qml", button)
453- onClicked: popover.hide()
454 }
455 }
456 }
457
458=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/TextCursorStyle.qml'
459--- modules/Ubuntu/Components/Themes/Ambiance/TextCursorStyle.qml 2014-10-07 15:21:11 +0000
460+++ modules/Ubuntu/Components/Themes/Ambiance/TextCursorStyle.qml 2014-11-11 11:50:16 +0000
461@@ -53,10 +53,11 @@
462 Component {
463 id: delegate
464 Rectangle {
465+ objectName: "text_cursor_style_" + styledItem.positionProperty
466 width: cursorWidth
467 // FIXME: Extend the palette and use palette values here
468 color: UbuntuColors.blue
469- visible: blinkTimer.timerShowCursor
470+ visible: blinkTimer.timerShowCursor || !blinkTimer.running
471 Timer {
472 id: blinkTimer
473 interval: cursorStyle.cursorVisibleTimeout
474
475=== modified file 'modules/Ubuntu/Components/plugin/ucmousefilters.cpp'
476--- modules/Ubuntu/Components/plugin/ucmousefilters.cpp 2014-04-25 12:53:58 +0000
477+++ modules/Ubuntu/Components/plugin/ucmousefilters.cpp 2014-11-11 11:50:16 +0000
478@@ -784,6 +784,7 @@
479 m_owner->installEventFilter(this);
480 } else {
481 m_owner->removeEventFilter(this);
482+ m_pressAndHoldTimer.stop();
483 }
484 Q_EMIT enabledChanged();
485 }
486
487=== modified file 'tests/autopilot/ubuntuuitoolkit/base.py'
488--- tests/autopilot/ubuntuuitoolkit/base.py 2014-09-17 16:06:35 +0000
489+++ tests/autopilot/ubuntuuitoolkit/base.py 2014-11-11 11:50:16 +0000
490@@ -21,6 +21,9 @@
491 import os
492 import subprocess
493 import ubuntuuitoolkit
494+from autopilot.introspection import dbus
495+from autopilot.matchers import Eventually
496+from testtools.matchers import Equals
497
498 from autopilot import (
499 input,
500@@ -80,3 +83,16 @@
501 return input.Mouse
502 else:
503 return input.Touch
504+
505+ def _assert_not_visible(self, type_name='*', **kwargs):
506+ """Confirm that an object is hidden.
507+
508+ Internally this means asserting that selecting the object fails.
509+ """
510+ try:
511+ object = self.main_view.select_single(type_name, **kwargs)
512+ # object.visible is always True if the select succeeds
513+ self.assertThat(object.visible, Eventually(Equals(False)))
514+ except dbus.StateNotFoundError:
515+ # Caret can't be selected because it's hidden
516+ pass
517
518=== modified file 'tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.py'
519--- tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.py 2014-09-22 07:19:56 +0000
520+++ tests/autopilot/ubuntuuitoolkit/tests/components/test_textinput.py 2014-11-11 11:50:16 +0000
521@@ -17,8 +17,11 @@
522 """Tests for the Ubuntu UI Toolkit Header component."""
523
524 import os
525+import testtools
526+from time import sleep
527
528-from autopilot.introspection import dbus
529+from autopilot.input._common import get_center_point
530+from autopilot import platform
531
532 from ubuntuuitoolkit import tests
533
534@@ -57,19 +60,11 @@
535 self.assertFalse(self.textfield.focus)
536
537 def test_caret_visible_on_focus(self):
538- try:
539- cursor = self.main_view.select_single(
540- objectName='text_cursor_style_caret_cursorPosition')
541- # cursor.visible is always True if the select succeeds
542- self.assertFalse(cursor.visible)
543- except dbus.StateNotFoundError:
544- # Caret can't be selected because it's hidden
545- pass
546-
547+ cursorName = 'text_cursor_style_caret_cursorPosition'
548+ self._assert_not_visible(objectName=cursorName)
549 self.pointing_device.click_object(self.textfield)
550 self.assertTrue(self.textfield.focus)
551- cursor = self.main_view.select_single(
552- objectName='text_cursor_style_caret_cursorPosition')
553+ cursor = self.main_view.select_single(objectName=cursorName)
554 self.assertTrue(cursor.visible)
555
556 def test_caret_hide_while_typing(self):
557@@ -96,3 +91,90 @@
558 cursor = self.main_view.select_single(
559 objectName='text_cursor_style_caret_selectionEnd')
560 self.assertTrue(cursor.visible)
561+
562+
563+class InsertModeTextInputTestCase(tests.QMLFileAppTestCase):
564+
565+ path = os.path.abspath(__file__)
566+ dir_path = os.path.dirname(path)
567+ textfield_qml_file_path = os.path.join(
568+ dir_path, 'test_textinput.textfield.qml')
569+ textarea_qml_file_path = os.path.join(
570+ dir_path, 'test_textinput.textarea.qml')
571+ customfield_qml_file_path = os.path.join(
572+ dir_path, 'test_textinput.textfield_custom.qml')
573+
574+ scenarios = [
575+ ('textfield',
576+ dict(test_qml_file_path=textfield_qml_file_path,
577+ objectName='textfield')),
578+ ('textarea',
579+ dict(test_qml_file_path=textarea_qml_file_path,
580+ objectName='textarea')),
581+ ('customfield',
582+ dict(test_qml_file_path=customfield_qml_file_path,
583+ objectName='textfield')),
584+ ]
585+
586+ def get_command_line(self, command_line):
587+ command_line.append('-touch')
588+ return command_line
589+
590+ def setUp(self):
591+ super(InsertModeTextInputTestCase, self).setUp()
592+ self.textfield = self.main_view.select_single(
593+ objectName=self.objectName)
594+ self.assertFalse(self.textfield.focus)
595+
596+ def assert_buttons(self, texts):
597+ popover = self.main_view.get_text_input_context_menu(
598+ 'text_input_contextmenu')
599+ for text in texts:
600+ button = popover._get_button(text)
601+ self.assertTrue(button.visible)
602+
603+ def assert_discard_popover(self):
604+ # Discard popover by tap
605+ self.pointing_device.move(
606+ self.textfield.globalRect.x + self.textfield.width * 0.7,
607+ self.textfield.globalRect.y + self.textfield.height / 10)
608+ self.pointing_device.click()
609+
610+ self._assert_not_visible(objectName='text_input_contextmenu')
611+
612+ @testtools.skipIf(platform.model() == 'Desktop', 'Touch only')
613+ def test_popover_visible_after_tapping_caret(self):
614+ # Insert Mode
615+ self.pointing_device.click_object(self.textfield)
616+ sleep(1)
617+ cursor = self.main_view.select_single(
618+ objectName='text_cursor_style_cursorPosition')
619+ self.pointing_device.click_object(cursor)
620+ self.assert_buttons(['Select All', 'Paste'])
621+ self.assert_discard_popover()
622+
623+ @testtools.skipIf(platform.model() == 'Desktop', 'Touch only')
624+ def test_popover_visible_after_dragging_caret(self):
625+ # Insert Mode
626+ self.pointing_device.click_object(self.textfield)
627+ self.textfield.keyboard.type('Lorem ipsum')
628+ cursor = self.main_view.select_single(
629+ objectName='text_cursor_style_cursorPosition')
630+ x, y = get_center_point(cursor)
631+ self.pointing_device.drag(x, y, 0, y)
632+ self.assert_buttons(['Select All', 'Paste'])
633+ self.assert_discard_popover()
634+
635+ @testtools.skipIf(platform.model() == 'Desktop', 'Touch only')
636+ def test_popover_visible_after_selecting(self):
637+ # Select Mode
638+ self.pointing_device.click_object(self.textfield)
639+ self.textfield.keyboard.type('Lorem ipsum')
640+ self.pointing_device.move(
641+ self.textfield.globalRect.x + self.textfield.width / 8,
642+ self.textfield.globalRect.y + self.textfield.height / 2)
643+ # Long press to select a word
644+ self.pointing_device.click()
645+ self.pointing_device.click()
646+ self.assert_buttons(['Cut', 'Copy', 'Paste'])
647+ self.assert_discard_popover()
648
649=== modified file 'tests/unit_x11/tst_components/tst_textinput_common.qml'
650--- tests/unit_x11/tst_components/tst_textinput_common.qml 2014-07-13 07:19:15 +0000
651+++ tests/unit_x11/tst_components/tst_textinput_common.qml 2014-11-11 11:50:16 +0000
652@@ -175,38 +175,6 @@
653 cursorRectSpy.target = null;
654 }
655
656- function test_press_and_hold_does_nothing_data() {
657- return [
658- {tag: "TextField", input: textField, withTextSelected: false},
659- {tag: "TextArea", input: textArea, withTextSelected: false},
660- {tag: "TextField", input: textField, withTextSelected: true},
661- {tag: "TextArea", input: textArea, withTextSelected: true},
662- ];
663- }
664-
665- function test_press_and_hold_does_nothing(data) {
666- var handler = findChild(data.input, "input_handler");
667- popupSpy.target = handler;
668-
669- data.input.focus = true;
670- if (data.withTextSelected) {
671- // select the first 20 characters
672- data.input.select(0, 20);
673- }
674-
675- // press and hold over selected text
676- mouseLongPress(data.input, units.gu(7), y);
677- waitForRendering(data.input);
678- expectFailContinue(data.tag, "Should not open popover");
679- popupSpy.wait(400);
680-
681- if (data.withTextSelected) {
682- // text selection must not be cleared
683- verify(data.input.selectedText !== "", "Selected text cleared!");
684- }
685- mouseRelease(data.input, units.gu(7), y);
686- }
687-
688 function test_scroll_when_not_focused_data() {
689 return [
690 // dx and dy are in eights of a degree; see QWheelEvent::angleDelta() for more details.
691@@ -274,7 +242,7 @@
692 {tag: "TextField click on selection", input: textField, selectChars: 10, clickPos: Qt.point(10, textField.height / 2)},
693 {tag: "TextArea click on selection", input: textArea, selectChars: 40, clickPos: Qt.point(20, 20)},
694 {tag: "TextField click beside selection", input: textField, selectChars: 5, clickPos: Qt.point(textField.width / 2, textField.height / 2)},
695- {tag: "TextArea click beside selection", input: textArea, selectChars: 5, clickPos: Qt.point(textArea.width / 2, textArea.height / 2)},
696+ {tag: "TextArea click beside selection", input: textArea, selectChars: 1, clickPos: Qt.point(textArea.width / 2, textArea.height / 2)},
697 ];
698 }
699 function test_clear_selection_on_click(data) {
700
701=== modified file 'tests/unit_x11/tst_components/tst_textinput_touch.qml'
702--- tests/unit_x11/tst_components/tst_textinput_touch.qml 2014-08-26 10:36:07 +0000
703+++ tests/unit_x11/tst_components/tst_textinput_touch.qml 2014-11-11 11:50:16 +0000
704@@ -223,7 +223,7 @@
705 return [
706 {tag: "TextField", input: textField, initialCursorPosition: 0, cursorName: "selectionEnd", delta: guPoint(10, 0)},
707 {tag: "TextArea", input: textArea, initialCursorPosition: 0, cursorName: "selectionEnd", delta: guPoint(10, 5)},
708- {tag: "TextField", input: textField, initialCursorPosition: 50, cursorName: "selectionStart", delta: guPoint(-10, 0)},
709+ {tag: "TextField", input: textField, initialCursorPosition: 48, cursorName: "selectionStart", delta: guPoint(-10, 0)},
710 {tag: "TextArea", input: textArea, initialCursorPosition: 50, cursorName: "selectionStart", delta: guPoint(-20, -5)},
711 ];
712 }
713@@ -268,7 +268,6 @@
714 function test_0_drag_autosizing_textarea_drags_parent_flickable_data() {
715 return [
716 {tag: "when inactive", focused: false },
717- {tag: "when active", focused: true },
718 ];
719 }
720 function test_0_drag_autosizing_textarea_drags_parent_flickable(data) {

Subscribers

People subscribed via source and target branches