aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/quick')
-rw-r--r--tests/auto/quick/.prev_CMakeLists.txt72
-rw-r--r--tests/auto/quick/CMakeLists.txt34
-rw-r--r--tests/auto/quick/doc/CMakeLists.txt7
-rw-r--r--tests/auto/quick/doc/how-tos/CMakeLists.txt6
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-cpp-button/CMakeLists.txt31
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-cpp-button/Main.qml19
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-cpp-button/backend.cpp13
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-cpp-button/backend.h17
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-cpp-button/tst_how-to-cpp-button.cpp53
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/CMakeLists.txt25
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/backend.cpp36
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/backend.h29
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/script.mjs13
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/tst_how-to-cpp-enum-js.cpp47
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-qml/CMakeLists.txt33
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-qml/active-focus-debugging/ActiveFocusDebuggingMain.qml25
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimeComponentLabel.qml29
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePicker.qml325
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePickerDialog.qml88
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePickerLabel.qml126
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePickerMain.qml59
-rw-r--r--tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp368
-rw-r--r--tests/auto/quick/drawingmodes/BLACKLIST11
-rw-r--r--tests/auto/quick/drawingmodes/CMakeLists.txt21
-rw-r--r--tests/auto/quick/drawingmodes/tst_drawingmodes.cpp62
-rw-r--r--tests/auto/quick/examples/CMakeLists.txt15
-rw-r--r--tests/auto/quick/examples/tst_examples.cpp142
-rw-r--r--tests/auto/quick/geometry/CMakeLists.txt11
-rw-r--r--tests/auto/quick/geometry/tst_geometry.cpp29
-rw-r--r--tests/auto/quick/nodes/CMakeLists.txt11
-rw-r--r--tests/auto/quick/nodes/tst_nodestest.cpp46
-rw-r--r--tests/auto/quick/nokeywords/CMakeLists.txt11
-rw-r--r--tests/auto/quick/nokeywords/tst_nokeywords.cpp29
-rw-r--r--tests/auto/quick/pointerhandlers/CMakeLists.txt3
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST22
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/CMakeLists.txt24
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/GrooveDragSlider.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/KnobDragSlider.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnFlickable.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnList.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnTable.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/pinchOnFlickable.qml49
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/pinchOnFlickableWithParentTapHandler.qml24
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnFlickable.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnList.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnTable.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp319
-rw-r--r--tests/auto/quick/pointerhandlers/mousearea_interop/BLACKLIST7
-rw-r--r--tests/auto/quick/pointerhandlers/mousearea_interop/CMakeLists.txt24
-rw-r--r--tests/auto/quick/pointerhandlers/mousearea_interop/data/dragHandlerInMouseAreaGrandparent.qml20
-rw-r--r--tests/auto/quick/pointerhandlers/mousearea_interop/data/dragTakeOverFromSibling.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/mousearea_interop/data/hoverHandlerInGrandparentOfHoverableItem.qml33
-rw-r--r--tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp103
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/BLACKLIST5
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/CMakeLists.txt24
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/dragParentOfMPTA.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml33
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/unloadHandlerOnPress.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp55
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/BLACKLIST9
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/CMakeLists.txt24
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml33
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml33
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragAndWheel.qml32
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragHandlerUnderModalLayer.qml34
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml33
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/draghandler_and_pinchhandler.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml55
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/simpleTapAndDragHandlers.qml37
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/data/snapMode.qml49
-rw-r--r--tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp464
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST5
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/CMakeLists.txt24
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/data/changingCursor.qml37
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverDeviceCursors.qml55
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverHandler.qml17
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml181
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/data/nohandler.qml15
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/data/windowCursorShape.qml13
-rw-r--r--tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp523
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/BLACKLIST3
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/CMakeLists.txt24
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/data/nullTarget.qml33
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchAndDrag.qml37
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchproperties.qml88
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/data/threeFingers.qml36
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/data/transformedPinchHandler.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp743
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointerhandler/CMakeLists.txt24
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointerhandler/data/clip.qml36
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointerhandler/data/grabberSceneChange.qml78
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointerhandler/data/itemOnly.qml24
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointerhandler/data/reparenting.qml40
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp291
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointhandler/BLACKLIST2
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointhandler/CMakeLists.txt24
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointhandler/data/multiPointTracker.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointhandler/data/pointTracker.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp215
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/BLACKLIST3
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/CMakeLists.txt24
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml46
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml41
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/data/dragReleaseMenu.qml64
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/data/nested.qml35
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/data/nestedAndSibling.qml39
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/data/rightTapHandler.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/data/simpleTapHandler.qml14
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/data/tapHandlersOverlapped.qml60
-rw-r--r--tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp814
-rw-r--r--tests/auto/quick/pointerhandlers/qquickwheelhandler/CMakeLists.txt24
-rw-r--r--tests/auto/quick/pointerhandlers/qquickwheelhandler/data/nested.qml29
-rw-r--r--tests/auto/quick/pointerhandlers/qquickwheelhandler/data/rectWheel.qml45
-rw-r--r--tests/auto/quick/pointerhandlers/qquickwheelhandler/tst_qquickwheelhandler.cpp92
-rw-r--r--tests/auto/quick/propertyrequirements/CMakeLists.txt11
-rw-r--r--tests/auto/quick/propertyrequirements/tst_propertyrequirements.cpp44
-rw-r--r--tests/auto/quick/qquickaccessible/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquickaccessible/data/hittest.qml29
-rw-r--r--tests/auto/quick/qquickaccessible/data/ignored.qml29
-rw-r--r--tests/auto/quick/qquickaccessible/data/text.qml10
-rw-r--r--tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp195
-rw-r--r--tests/auto/quick/qquickanchors/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickanchors/data/centerin.qml7
-rw-r--r--tests/auto/quick/qquickanchors/tst_qquickanchors.cpp60
-rw-r--r--tests/auto/quick/qquickanimatedimage/BLACKLIST5
-rw-r--r--tests/auto/quick/qquickanimatedimage/CMakeLists.txt20
-rw-r--r--tests/auto/quick/qquickanimatedimage/data/currentframe.qml1
-rw-r--r--tests/auto/quick/qquickanimatedimage/data/stickmansourcesized.qml (renamed from tests/auto/quick/qquickanimatedimage/data/stickmanerror1.qml)2
-rw-r--r--tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp173
-rw-r--r--tests/auto/quick/qquickanimatedsprite/BLACKLIST4
-rw-r--r--tests/auto/quick/qquickanimatedsprite/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquickanimatedsprite/data/basic.qml29
-rw-r--r--tests/auto/quick/qquickanimatedsprite/data/frameChange.qml29
-rw-r--r--tests/auto/quick/qquickanimatedsprite/data/infiniteLoops.qml29
-rw-r--r--tests/auto/quick/qquickanimatedsprite/data/largeAnimation.qml29
-rw-r--r--tests/auto/quick/qquickanimatedsprite/data/runningChange.qml29
-rw-r--r--tests/auto/quick/qquickanimatedsprite/data/sourceSwitch.qml29
-rw-r--r--tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp94
-rw-r--r--tests/auto/quick/qquickanimationcontroller/CMakeLists.txt11
-rw-r--r--tests/auto/quick/qquickanimationcontroller/tst_qquickanimationcontroller.cpp29
-rw-r--r--tests/auto/quick/qquickanimations/BLACKLIST14
-rw-r--r--tests/auto/quick/qquickanimations/CMakeLists.txt21
-rw-r--r--tests/auto/quick/qquickanimations/data/animationJobSelfDestructionBug.qml40
-rw-r--r--tests/auto/quick/qquickanimations/data/animatorInvalidTargetCrash.qml29
-rw-r--r--tests/auto/quick/qquickanimations/data/changePropertiesDuringAnimation.qml31
-rw-r--r--tests/auto/quick/qquickanimations/data/cleanupWhenRenderThreadStops.qml32
-rw-r--r--tests/auto/quick/qquickanimations/data/fastFlickingBug.qml40
-rw-r--r--tests/auto/quick/qquickanimations/data/finished.qml29
-rw-r--r--tests/auto/quick/qquickanimations/data/frameAnimation.qml22
-rw-r--r--tests/auto/quick/qquickanimations/data/infiniteAnimationWithoutFrom.qml29
-rw-r--r--tests/auto/quick/qquickanimations/data/restartAnimationGroupWhenDirty.qml92
-rw-r--r--tests/auto/quick/qquickanimations/data/restartNestedAnimationGroupWhenDirty.qml96
-rw-r--r--tests/auto/quick/qquickanimations/data/scriptActionCrash.qml29
-rw-r--r--tests/auto/quick/qquickanimations/data/targetsDeletedWithoutRemoval.qml29
-rw-r--r--tests/auto/quick/qquickanimations/tst_qquickanimations.cpp435
-rw-r--r--tests/auto/quick/qquickanimators/BLACKLIST2
-rw-r--r--tests/auto/quick/qquickanimators/CMakeLists.txt25
-rw-r--r--tests/auto/quick/qquickanimators/data/animatorImplicitFrom.qml29
-rw-r--r--tests/auto/quick/qquickanimators/data/positionerWithAnimator.qml29
-rw-r--r--tests/auto/quick/qquickanimators/data/windowWithAnimator.qml29
-rw-r--r--tests/auto/quick/qquickanimators/tst_qquickanimators.cpp44
-rw-r--r--tests/auto/quick/qquickapplication/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickapplication/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquickapplication/tst_qquickapplication.cpp327
-rw-r--r--tests/auto/quick/qquickbehaviors/CMakeLists.txt28
-rw-r--r--tests/auto/quick/qquickbehaviors/bindable.h25
-rw-r--r--tests/auto/quick/qquickbehaviors/data/bindableProperty.qml12
-rw-r--r--tests/auto/quick/qquickbehaviors/data/defaultQProperty.qml14
-rw-r--r--tests/auto/quick/qquickbehaviors/data/duplicated.qml31
-rw-r--r--tests/auto/quick/qquickbehaviors/data/qtbug21549-2.qml51
-rw-r--r--tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp111
-rw-r--r--tests/auto/quick/qquickborderimage/BLACKLIST7
-rw-r--r--tests/auto/quick/qquickborderimage/CMakeLists.txt25
-rw-r--r--tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp124
-rw-r--r--tests/auto/quick/qquickboundaryrule/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp54
-rw-r--r--tests/auto/quick/qquickcanvasitem/BLACKLIST5
-rw-r--r--tests/auto/quick/qquickcanvasitem/CMakeLists.txt11
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_arc.qml22
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_arcto.qml9
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml6
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_colors.qml40
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_composite.qml7
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_contextFontValidation.qml (renamed from tests/auto/quick/qquickcanvasitem/data/tst_context.qml)69
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_contextTypeStored.qml25
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_contextValidWhenTypePredefined.qml64
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_fillStyle.qml8
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_fillrect.qml1
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_gradient.qml6
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_image.qml25
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_imagedata.qml1
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_invalidContext.qml35
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_line.qml43
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_path.qml16
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_pattern.qml6
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_pixel.qml5
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_shadow.qml11
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_state.qml16
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_strokeStyle.qml5
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_svgpath.qml1
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_text.qml6
-rw-r--r--tests/auto/quick/qquickcanvasitem/data/tst_transform.qml6
-rw-r--r--tests/auto/quick/qquickcanvasitem/tst_qquickcanvasitem.cpp29
-rw-r--r--tests/auto/quick/qquickcolorgroup/CMakeLists.txt11
-rw-r--r--tests/auto/quick/qquickcolorgroup/tst_qquickcolorgroup.cpp44
-rw-r--r--tests/auto/quick/qquickdeliveryagent/BLACKLIST7
-rw-r--r--tests/auto/quick/qquickdeliveryagent/CMakeLists.txt44
-rw-r--r--tests/auto/quick/qquickdeliveryagent/data/clearItemsOnHoverLeave.qml32
-rw-r--r--tests/auto/quick/qquickdeliveryagent/data/compoundControl.qml28
-rw-r--r--tests/auto/quick/qquickdeliveryagent/data/flickableTextEdit.qml42
-rw-r--r--tests/auto/quick/qquickdeliveryagent/data/listViewDelegate.qml21
-rw-r--r--tests/auto/quick/qquickdeliveryagent/data/passiveGrabberItem.qml34
-rw-r--r--tests/auto/quick/qquickdeliveryagent/data/pointHandler.qml17
-rw-r--r--tests/auto/quick/qquickdeliveryagent/data/tapHandler.qml14
-rw-r--r--tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp681
-rw-r--r--tests/auto/quick/qquickdesignersupport/CMakeLists.txt25
-rw-r--r--tests/auto/quick/qquickdesignersupport/data/RecursiveProperty.qml8
-rw-r--r--tests/auto/quick/qquickdesignersupport/data/RegTestComponent.qml20
-rw-r--r--tests/auto/quick/qquickdesignersupport/data/propertyNameTest.qml13
-rw-r--r--tests/auto/quick/qquickdesignersupport/data/regTestProperties.qml13
-rw-r--r--tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp150
-rw-r--r--tests/auto/quick/qquickdrag/BLACKLIST25
-rw-r--r--tests/auto/quick/qquickdrag/CMakeLists.txt11
-rw-r--r--tests/auto/quick/qquickdrag/tst_qquickdrag.cpp46
-rw-r--r--tests/auto/quick/qquickdragattached/CMakeLists.txt38
-rw-r--r--tests/auto/quick/qquickdragattached/data/qt_logo.svg26
-rw-r--r--tests/auto/quick/qquickdragattached/tst_qquickdragattached.cpp183
-rw-r--r--tests/auto/quick/qquickdroparea/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickdroparea/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickdroparea/data/ignoreRetriggerEvent.qml15
-rw-r--r--tests/auto/quick/qquickdroparea/data/nested1.qml51
-rw-r--r--tests/auto/quick/qquickdroparea/data/nested2.qml51
-rw-r--r--tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp142
-rw-r--r--tests/auto/quick/qquickdynamicpropertyanimation/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquickdynamicpropertyanimation/tst_qquickdynamicpropertyanimation.cpp35
-rw-r--r--tests/auto/quick/qquickflickable/BLACKLIST9
-rw-r--r--tests/auto/quick/qquickflickable/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickflickable/data/contentPosWhileDragging.qml24
-rw-r--r--tests/auto/quick/qquickflickable/data/dragon.qml15
-rw-r--r--tests/auto/quick/qquickflickable/data/endpoints.qml14
-rw-r--r--tests/auto/quick/qquickflickable/data/flickableWithTapHandler.qml24
-rw-r--r--tests/auto/quick/qquickflickable/data/fractionalExtent.qml14
-rw-r--r--tests/auto/quick/qquickflickable/data/nested.qml29
-rw-r--r--tests/auto/quick/qquickflickable/data/nestedmouseareapce.qml26
-rw-r--r--tests/auto/quick/qquickflickable/data/overshoot.qml29
-rw-r--r--tests/auto/quick/qquickflickable/data/overshoot_reentrant.qml29
-rw-r--r--tests/auto/quick/qquickflickable/data/parallel.qml29
-rw-r--r--tests/auto/quick/qquickflickable/data/pressDelay.qml12
-rw-r--r--tests/auto/quick/qquickflickable/data/ratios.qml29
-rw-r--r--tests/auto/quick/qquickflickable/data/rotatedFlickable.qml32
-rw-r--r--tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml29
-rw-r--r--tests/auto/quick/qquickflickable/tst_qquickflickable.cpp1359
-rw-r--r--tests/auto/quick/qquickflipable/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquickflipable/data/flip-y-axis-flipable.qml32
-rw-r--r--tests/auto/quick/qquickflipable/tst_qquickflipable.cpp65
-rw-r--r--tests/auto/quick/qquickfocusscope/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickfocusscope/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickfocusscope/tst_qquickfocusscope.cpp155
-rw-r--r--tests/auto/quick/qquickfontloader/CMakeLists.txt20
-rw-r--r--tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp54
-rw-r--r--tests/auto/quick/qquickfontloader_static/CMakeLists.txt21
-rw-r--r--tests/auto/quick/qquickfontloader_static/tst_qquickfontloader_static.cpp57
-rw-r--r--tests/auto/quick/qquickfontmetrics/CMakeLists.txt11
-rw-r--r--tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp35
-rw-r--r--tests/auto/quick/qquickframebufferobject/BLACKLIST5
-rw-r--r--tests/auto/quick/qquickframebufferobject/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquickframebufferobject/data/testStuff.qml29
-rw-r--r--tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp55
-rw-r--r--tests/auto/quick/qquickgraphicsinfo/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquickgraphicsinfo/tst_qquickgraphicsinfo.cpp41
-rw-r--r--tests/auto/quick/qquickgridview/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickgridview/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickgridview/data/attachedProperties.qml51
-rw-r--r--tests/auto/quick/qquickgridview/data/displayMargin.qml29
-rw-r--r--tests/auto/quick/qquickgridview/data/margins2.qml51
-rw-r--r--tests/auto/quick/qquickgridview/data/negativeDisplayMargin.qml29
-rw-r--r--tests/auto/quick/qquickgridview/data/qtbug49218.qml51
-rw-r--r--tests/auto/quick/qquickgridview/data/qtbug91461.qml34
-rw-r--r--tests/auto/quick/qquickgridview/data/qtbug92998.qml53
-rw-r--r--tests/auto/quick/qquickgridview/data/removeAccessibleChildrenEvenIfReusingItems.qml48
-rw-r--r--tests/auto/quick/qquickgridview/tst_qquickgridview.cpp659
-rw-r--r--tests/auto/quick/qquickimage/BLACKLIST11
-rw-r--r--tests/auto/quick/qquickimage/CMakeLists.txt25
-rw-r--r--tests/auto/quick/qquickimage/data/hugeImages.qml29
-rw-r--r--tests/auto/quick/qquickimage/data/qtbug_32513.qml29
-rw-r--r--tests/auto/quick/qquickimage/data/statusChanged.qml25
-rw-r--r--tests/auto/quick/qquickimage/tst_qquickimage.cpp199
-rw-r--r--tests/auto/quick/qquickimageprovider/BLACKLIST21
-rw-r--r--tests/auto/quick/qquickimageprovider/CMakeLists.txt29
-rw-r--r--tests/auto/quick/qquickimageprovider/data/forImports.qml5
-rw-r--r--tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp98
-rw-r--r--tests/auto/quick/qquickitem/BLACKLIST4
-rw-r--r--tests/auto/quick/qquickitem/CMakeLists.txt28
-rw-r--r--tests/auto/quick/qquickitem/data/childAtRectangle.qml29
-rw-r--r--tests/auto/quick/qquickitem/data/containsContainmentMask.qml40
-rw-r--r--tests/auto/quick/qquickitem/data/mainWindowQtBug60123.qml29
-rw-r--r--tests/auto/quick/qquickitem/data/objectCastInDestructor.qml23
-rw-r--r--tests/auto/quick/qquickitem/data/shortcutOverride.qml29
-rw-r--r--tests/auto/quick/qquickitem/tst_qquickitem.cpp551
-rw-r--r--tests/auto/quick/qquickitem2/CMakeLists.txt21
-rw-r--r--tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop3.qml13
-rw-r--r--tests/auto/quick/qquickitem2/data/colorgroup.qml34
-rw-r--r--tests/auto/quick/qquickitem2/data/focusInScopeChanges.qml31
-rw-r--r--tests/auto/quick/qquickitem2/data/focusReason.qml85
-rw-r--r--tests/auto/quick/qquickitem2/data/focusableItemReparentedToLoadedComponent.qml51
-rw-r--r--tests/auto/quick/qquickitem2/data/grabToImage.qml29
-rw-r--r--tests/auto/quick/qquickitem2/data/hollowTestItem.qml1
-rw-r--r--tests/auto/quick/qquickitem2/data/keysforward.qml29
-rw-r--r--tests/auto/quick/qquickitem2/data/mapCoordinates.qml29
-rw-r--r--tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml29
-rw-r--r--tests/auto/quick/qquickitem2/data/mapCoordinatesWithWindows.qml51
-rw-r--r--tests/auto/quick/qquickitem2/data/paletteAllocate.qml35
-rw-r--r--tests/auto/quick/qquickitem2/data/standardkeys.qml29
-rw-r--r--tests/auto/quick/qquickitem2/data/undefinedInvalid.qml9
-rw-r--r--tests/auto/quick/qquickitem2/data/viewports.qml54
-rw-r--r--tests/auto/quick/qquickitem2/data/visiblechanged.qml39
-rw-r--r--tests/auto/quick/qquickitem2/tst_qquickitem.cpp1242
-rw-r--r--tests/auto/quick/qquickitemlayer/BLACKLIST23
-rw-r--r--tests/auto/quick/qquickitemlayer/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquickitemlayer/data/itemImageLayer.qml14
-rw-r--r--tests/auto/quick/qquickitemlayer/data/qt-logo.pngbin0 -> 1301 bytes
-rw-r--r--tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp65
-rw-r--r--tests/auto/quick/qquicklayouts/BLACKLIST10
-rw-r--r--tests/auto/quick/qquicklayouts/CMakeLists.txt11
-rw-r--r--tests/auto/quick/qquicklayouts/data/LayoutHelperLibrary.js42
-rw-r--r--tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml51
-rw-r--r--tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml51
-rw-r--r--tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml51
-rw-r--r--tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml51
-rw-r--r--tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml51
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml276
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_layoutproxy.qml687
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml766
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml691
-rw-r--r--tests/auto/quick/qquicklayouts/tst_qquicklayouts.cpp71
-rw-r--r--tests/auto/quick/qquicklistview/BLACKLIST15
-rw-r--r--tests/auto/quick/qquicklistview/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquicklistview/data/addoncompleted.qml51
-rw-r--r--tests/auto/quick/qquicklistview/data/appendDuringScrollDown.qml3
-rw-r--r--tests/auto/quick/qquicklistview/data/attachedProperties.qml51
-rw-r--r--tests/auto/quick/qquicklistview/data/contentHeightWithDelayRemove.qml7
-rw-r--r--tests/auto/quick/qquicklistview/data/displayMargin.qml31
-rw-r--r--tests/auto/quick/qquicklistview/data/flickBothDirections.qml51
-rw-r--r--tests/auto/quick/qquicklistview/data/headerCrash.qml2
-rw-r--r--tests/auto/quick/qquicklistview/data/listview-itematindex.qml3
-rw-r--r--tests/auto/quick/qquicklistview/data/listview-sections_delegate.qml16
-rw-r--r--tests/auto/quick/qquicklistview/data/listview-sections_delegate_required.qml15
-rw-r--r--tests/auto/quick/qquicklistview/data/listviewtest-package.qml20
-rw-r--r--tests/auto/quick/qquicklistview/data/moveObjectModelItemToAnotherObjectModel.qml51
-rw-r--r--tests/auto/quick/qquicklistview/data/negativeDisplayMargin.qml33
-rw-r--r--tests/auto/quick/qquicklistview/data/objectModelCulling.qml1
-rw-r--r--tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml53
-rw-r--r--tests/auto/quick/qquicklistview/data/proxytest.qml29
-rw-r--r--tests/auto/quick/qquicklistview/data/qtbug34576.qml29
-rw-r--r--tests/auto/quick/qquicklistview/data/qtbug48044.qml2
-rw-r--r--tests/auto/quick/qquicklistview/data/qtbug61537_modelChangesAsync.qml51
-rw-r--r--tests/auto/quick/qquicklistview/data/repositionListViewOnPopulateTransition.qml51
-rw-r--r--tests/auto/quick/qquicklistview/data/resizeAfterComponentComplete.qml53
-rw-r--r--tests/auto/quick/qquicklistview/data/reusedelegateitems.qml51
-rw-r--r--tests/auto/quick/qquicklistview/data/roundingErrors.qml53
-rw-r--r--tests/auto/quick/qquicklistview/data/sectionSnapping.qml3
-rw-r--r--tests/auto/quick/qquicklistview/data/setpositiononlayout.qml51
-rw-r--r--tests/auto/quick/qquicklistview/data/sizeTransitions.qml51
-rw-r--r--tests/auto/quick/qquicklistview/data/snapOneItemResize.qml1
-rw-r--r--tests/auto/quick/qquicklistview/data/snapOneItemWrongDirection.qml3
-rw-r--r--tests/auto/quick/qquicklistview/data/stickyPositioning-both.qml51
-rw-r--r--tests/auto/quick/qquicklistview/data/stickyPositioning-footer.qml51
-rw-r--r--tests/auto/quick/qquicklistview/data/stickyPositioning-header.qml51
-rw-r--r--tests/auto/quick/qquicklistview/data/strictlyenforcerange-resize.qml3
-rw-r--r--tests/auto/quick/qquicklistview/data/usechooserwithoutdefault.qml40
-rw-r--r--tests/auto/quick/qquicklistview/incrementalmodel.cpp29
-rw-r--r--tests/auto/quick/qquicklistview/incrementalmodel.h39
-rw-r--r--tests/auto/quick/qquicklistview/proxytestinnermodel.cpp33
-rw-r--r--tests/auto/quick/qquicklistview/proxytestinnermodel.h39
-rw-r--r--tests/auto/quick/qquicklistview/randomsortmodel.cpp37
-rw-r--r--tests/auto/quick/qquicklistview/randomsortmodel.h37
-rw-r--r--tests/auto/quick/qquicklistview/reusemodel.h29
-rw-r--r--tests/auto/quick/qquicklistview/tst_qquicklistview.cpp922
-rw-r--r--tests/auto/quick/qquicklistview2/BLACKLIST5
-rw-r--r--tests/auto/quick/qquicklistview2/CMakeLists.txt46
-rw-r--r--tests/auto/quick/qquicklistview2/data/areaZeroView.qml22
-rw-r--r--tests/auto/quick/qquicklistview2/data/bindOnHeaderAndFooterXPosition.qml29
-rw-r--r--tests/auto/quick/qquicklistview2/data/bindOnHeaderAndFooterYPosition.qml29
-rw-r--r--tests/auto/quick/qquicklistview2/data/boundDelegateComponent.qml64
-rw-r--r--tests/auto/quick/qquicklistview2/data/buttonDelegate.qml27
-rw-r--r--tests/auto/quick/qquicklistview2/data/changingOrientationWithListModel.qml47
-rw-r--r--tests/auto/quick/qquicklistview2/data/changingOrientationWithObjectModel.qml54
-rw-r--r--tests/auto/quick/qquicklistview2/data/delegateChooserEnumRole.qml41
-rw-r--r--tests/auto/quick/qquicklistview2/data/delegateContextHandling.qml75
-rw-r--r--tests/auto/quick/qquicklistview2/data/delegateModelRefresh.qml53
-rw-r--r--tests/auto/quick/qquicklistview2/data/delegateWithMouseArea.qml73
-rw-r--r--tests/auto/quick/qquicklistview2/data/fetchMore.qml21
-rw-r--r--tests/auto/quick/qquicklistview2/data/footerUpdate.qml39
-rw-r--r--tests/auto/quick/qquicklistview2/data/highlightWithBound.qml10
-rw-r--r--tests/auto/quick/qquicklistview2/data/innerRequired.qml35
-rw-r--r--tests/auto/quick/qquicklistview2/data/maxXExtent.qml29
-rw-r--r--tests/auto/quick/qquicklistview2/data/maxYExtent.qml30
-rw-r--r--tests/auto/quick/qquicklistview2/data/metaSequenceAsModel.qml14
-rw-r--r--tests/auto/quick/qquicklistview2/data/mouseAreaDelegate.qml30
-rw-r--r--tests/auto/quick/qquicklistview2/data/noCrashOnIndexChange.qml48
-rw-r--r--tests/auto/quick/qquicklistview2/data/qtbug104679_footer.qml21
-rw-r--r--tests/auto/quick/qquicklistview2/data/qtbug104679_header.qml21
-rw-r--r--tests/auto/quick/qquicklistview2/data/qtbug86744.qml25
-rw-r--r--tests/auto/quick/qquicklistview2/data/qtbug98315.qml98
-rw-r--r--tests/auto/quick/qquicklistview2/data/qtbug_92809.qml71
-rw-r--r--tests/auto/quick/qquicklistview2/data/sectionBoundComponent.qml14
-rw-r--r--tests/auto/quick/qquicklistview2/data/sectionGeometryChange.qml58
-rw-r--r--tests/auto/quick/qquicklistview2/data/sectionsNoOverlap.qml77
-rw-r--r--tests/auto/quick/qquicklistview2/data/singletonModelLifetime.qml32
-rw-r--r--tests/auto/quick/qquicklistview2/data/snapOneItem.qml34
-rw-r--r--tests/auto/quick/qquicklistview2/data/urlListModel.qml22
-rw-r--r--tests/auto/quick/qquicklistview2/data/viewportAvoidUndesiredMovementOnSetCurrentIndex.qml47
-rw-r--r--tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp1255
-rw-r--r--tests/auto/quick/qquicklistview2/typerolemodel.cpp41
-rw-r--r--tests/auto/quick/qquicklistview2/typerolemodel.h30
-rw-r--r--tests/auto/quick/qquickloader/BLACKLIST2
-rw-r--r--tests/auto/quick/qquickloader/CMakeLists.txt25
-rw-r--r--tests/auto/quick/qquickloader/data/Rect120x60.qml8
-rw-r--r--tests/auto/quick/qquickloader/data/bindings.qml29
-rw-r--r--tests/auto/quick/qquickloader/data/boundComponent.qml12
-rw-r--r--tests/auto/quick/qquickloader/data/itemLoaderItemWindow.qml2
-rw-r--r--tests/auto/quick/qquickloader/data/itemLoaderWindow.qml2
-rw-r--r--tests/auto/quick/qquickloader/data/loader-async-race-rect.qml10
-rw-r--r--tests/auto/quick/qquickloader/data/loader-async-race.qml14
-rw-r--r--tests/auto/quick/qquickloader/data/noEngine.qml32
-rw-r--r--tests/auto/quick/qquickloader/data/overflow.qml5
-rw-r--r--tests/auto/quick/qquickloader/data/overflow2.qml7
-rw-r--r--tests/auto/quick/qquickloader/data/parentErrors.qml29
-rw-r--r--tests/auto/quick/qquickloader/data/rootContext.qml29
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp269
-rw-r--r--tests/auto/quick/qquickmousearea/BLACKLIST10
-rw-r--r--tests/auto/quick/qquickmousearea/CMakeLists.txt25
-rw-r--r--tests/auto/quick/qquickmousearea/data/clickThrough2.qml6
-rw-r--r--tests/auto/quick/qquickmousearea/data/containsMouseAndHoverDisabled.qml15
-rw-r--r--tests/auto/quick/qquickmousearea/data/containsMouseMasked.qml24
-rw-r--r--tests/auto/quick/qquickmousearea/data/cursorUpdating.qml71
-rw-r--r--tests/auto/quick/qquickmousearea/data/disableParentOnPress.qml14
-rw-r--r--tests/auto/quick/qquickmousearea/data/doubleClickToHide.qml19
-rw-r--r--tests/auto/quick/qquickmousearea/data/hoverAfterPress.qml2
-rw-r--r--tests/auto/quick/qquickmousearea/data/ignoreBySource.qml2
-rw-r--r--tests/auto/quick/qquickmousearea/data/mask.qml40
-rw-r--r--tests/auto/quick/qquickmousearea/data/moveAndReleaseWithoutPress.qml2
-rw-r--r--tests/auto/quick/qquickmousearea/data/preventStealingListViewChild.qml31
-rw-r--r--tests/auto/quick/qquickmousearea/data/qtbug34368.qml4
-rw-r--r--tests/auto/quick/qquickmousearea/data/qtbug49100.qml2
-rw-r--r--tests/auto/quick/qquickmousearea/data/rejectEvent.qml2
-rw-r--r--tests/auto/quick/qquickmousearea/data/simple.qml3
-rw-r--r--tests/auto/quick/qquickmousearea/data/updateMousePosOnResize.qml6
-rw-r--r--tests/auto/quick/qquickmousearea/data/wheel.qml2
-rw-r--r--tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp600
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/BLACKLIST6
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/cancel.qml12
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/inFlickable.qml6
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/mouse.qml8
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/nested.qml2
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/nestedMouseArea.qml26
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml44
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/nestedTouchPosCheck.qml52
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml4
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/signalTest.qml14
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/touchOverMouseArea.qml21
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/data/transformedMultiPointTouchArea.qml4
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp293
-rw-r--r--tests/auto/quick/qquickpainteditem/BLACKLIST7
-rw-r--r--tests/auto/quick/qquickpainteditem/CMakeLists.txt11
-rw-r--r--tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp85
-rw-r--r--tests/auto/quick/qquickpalette/CMakeLists.txt32
-rw-r--r--tests/auto/quick/qquickpalette/data/palette-item-custom.qml26
-rw-r--r--tests/auto/quick/qquickpalette/data/palette-item-default.qml7
-rw-r--r--tests/auto/quick/qquickpalette/data/palette-window-custom.qml26
-rw-r--r--tests/auto/quick/qquickpalette/data/palette-window-default.qml7
-rw-r--r--tests/auto/quick/qquickpalette/tst_qquickpalette.cpp128
-rw-r--r--tests/auto/quick/qquickpath/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquickpath/tst_qquickpath.cpp33
-rw-r--r--tests/auto/quick/qquickpathview/CMakeLists.txt26
-rw-r--r--tests/auto/quick/qquickpathview/data/flickableDelegate.qml51
-rw-r--r--tests/auto/quick/qquickpathview/data/mousePressAfterFlick.qml61
-rw-r--r--tests/auto/quick/qquickpathview/data/nestedInFlickable.qml51
-rw-r--r--tests/auto/quick/qquickpathview/data/nestedmousearea2.qml51
-rw-r--r--tests/auto/quick/qquickpathview/data/objectModelMove.qml51
-rw-r--r--tests/auto/quick/qquickpathview/data/overcached.qml27
-rw-r--r--tests/auto/quick/qquickpathview/data/qtbug37815.qml51
-rw-r--r--tests/auto/quick/qquickpathview/data/qtbug46487.qml28
-rw-r--r--tests/auto/quick/qquickpathview/data/qtbug53464.qml51
-rw-r--r--tests/auto/quick/qquickpathview/data/qtbug90479.qml25
-rw-r--r--tests/auto/quick/qquickpathview/tst_qquickpathview.cpp668
-rw-r--r--tests/auto/quick/qquickpincharea/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickpincharea/data/draggablePinchArea.qml70
-rw-r--r--tests/auto/quick/qquickpincharea/data/pinchAreaInPathView.qml48
-rw-r--r--tests/auto/quick/qquickpincharea/data/pinchproperties.qml6
-rw-r--r--tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp305
-rw-r--r--tests/auto/quick/qquickpixmapcache/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickpixmapcache/CMakeLists.txt32
-rw-r--r--tests/auto/quick/qquickpixmapcache/data/tableViewWithDeviceLoadingImages.qml45
-rw-r--r--tests/auto/quick/qquickpixmapcache/deviceloadingimage.cpp43
-rw-r--r--tests/auto/quick/qquickpixmapcache/deviceloadingimage.h19
-rw-r--r--tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp126
-rw-r--r--tests/auto/quick/qquickpositioners/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp128
-rw-r--r--tests/auto/quick/qquickrectangle/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickrectangle/data/multi-radius.qml27
-rw-r--r--tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp142
-rw-r--r--tests/auto/quick/qquickrendercontrol/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickrendercontrol/CMakeLists.txt26
-rw-r--r--tests/auto/quick/qquickrendercontrol/data/rect.qml29
-rw-r--r--tests/auto/quick/qquickrendercontrol/data/rect_depth.qml28
-rw-r--r--tests/auto/quick/qquickrendercontrol/tst_qquickrendercontrol.cpp313
-rw-r--r--tests/auto/quick/qquickrepeater/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickrepeater/data/boundDelegateComponent.qml25
-rw-r--r--tests/auto/quick/qquickrepeater/data/innerRequired.qml33
-rw-r--r--tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp375
-rw-r--r--tests/auto/quick/qquickrhiitem/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickrhiitem/CMakeLists.txt52
-rw-r--r--tests/auto/quick/qquickrhiitem/data/test.qml41
-rw-r--r--tests/auto/quick/qquickrhiitem/testrhiitem.cpp157
-rw-r--r--tests/auto/quick/qquickrhiitem/testrhiitem.h61
-rw-r--r--tests/auto/quick/qquickrhiitem/texture.frag18
-rw-r--r--tests/auto/quick/qquickrhiitem/texture.vert19
-rw-r--r--tests/auto/quick/qquickrhiitem/tst_qquickrhiitem.cpp150
-rw-r--r--tests/auto/quick/qquickscreen/CMakeLists.txt26
-rw-r--r--tests/auto/quick/qquickscreen/tst_qquickscreen.cpp44
-rw-r--r--tests/auto/quick/qquickshadereffect/CMakeLists.txt22
-rw-r--r--tests/auto/quick/qquickshadereffect/data/+qsb/testprop.fragbin0 -> 1842 bytes
-rw-r--r--tests/auto/quick/qquickshadereffect/data/MyIcon.qml51
-rw-r--r--tests/auto/quick/qquickshadereffect/data/compile.bat2
-rw-r--r--tests/auto/quick/qquickshadereffect/data/deleteShaderEffectSource.qml29
-rw-r--r--tests/auto/quick/qquickshadereffect/data/deleteSourceItem.qml29
-rw-r--r--tests/auto/quick/qquickshadereffect/data/hideParent.qml29
-rw-r--r--tests/auto/quick/qquickshadereffect/data/testProperties.qml48
-rw-r--r--tests/auto/quick/qquickshadereffect/data/testprop.frag28
-rw-r--r--tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml51
-rw-r--r--tests/auto/quick/qquickshadereffect/resources.qrc18
-rw-r--r--tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp122
-rw-r--r--tests/auto/quick/qquickshape/BLACKLIST19
-rw-r--r--tests/auto/quick/qquickshape/CMakeLists.txt26
-rw-r--r--tests/auto/quick/qquickshape/data/multiline.qml29
-rw-r--r--tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml29
-rw-r--r--tests/auto/quick/qquickshape/data/pathitem7.qml29
-rw-r--r--tests/auto/quick/qquickshape/data/pathitem8.qml29
-rw-r--r--tests/auto/quick/qquickshape/data/polyline.qml29
-rw-r--r--tests/auto/quick/qquickshape/tst_qquickshape.cpp139
-rw-r--r--tests/auto/quick/qquickshortcut/CMakeLists.txt21
-rw-r--r--tests/auto/quick/qquickshortcut/data/embedded.qml20
-rw-r--r--tests/auto/quick/qquickshortcut/data/multiple.qml29
-rw-r--r--tests/auto/quick/qquickshortcut/data/shortcuts.qml29
-rw-r--r--tests/auto/quick/qquickshortcut/data/shortcutsRect.qml29
-rw-r--r--tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp126
-rw-r--r--tests/auto/quick/qquicksmoothedanimation/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp32
-rw-r--r--tests/auto/quick/qquickspringanimation/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp32
-rw-r--r--tests/auto/quick/qquickspritesequence/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquickspritesequence/data/advance.qml29
-rw-r--r--tests/auto/quick/qquickspritesequence/data/basic.qml29
-rw-r--r--tests/auto/quick/qquickspritesequence/data/crashonstart.qml29
-rw-r--r--tests/auto/quick/qquickspritesequence/data/huge.qml29
-rw-r--r--tests/auto/quick/qquickspritesequence/data/spriteaftergoal.qml29
-rw-r--r--tests/auto/quick/qquickspritesequence/data/spritebeforegoal.qml29
-rw-r--r--tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp33
-rw-r--r--tests/auto/quick/qquickstates/CMakeLists.txt44
-rw-r--r--tests/auto/quick/qquickstates/data/anchorRewind.qml31
-rw-r--r--tests/auto/quick/qquickstates/data/anchorRewindSize.qml30
-rw-r--r--tests/auto/quick/qquickstates/data/broken.qml5
-rw-r--r--tests/auto/quick/qquickstates/data/cleanPropertyChange.qml27
-rw-r--r--tests/auto/quick/qquickstates/data/jsValueWhen.qml18
-rw-r--r--tests/auto/quick/qquickstates/data/jsValueWhen2.qml20
-rw-r--r--tests/auto/quick/qquickstates/data/noStateOsciallation.qml22
-rw-r--r--tests/auto/quick/qquickstates/data/parentChangeInvolvingBindings.qml43
-rw-r--r--tests/auto/quick/qquickstates/data/removeBindingWithTransition.qml23
-rw-r--r--tests/auto/quick/qquickstates/tst_qquickstates.cpp396
-rw-r--r--tests/auto/quick/qquickstyledtext/CMakeLists.txt11
-rw-r--r--tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp42
-rw-r--r--tests/auto/quick/qquicksystempalette/CMakeLists.txt31
-rw-r--r--tests/auto/quick/qquicksystempalette/data/systemPalette.qml4
-rw-r--r--tests/auto/quick/qquicksystempalette/data/systemPaletteDisabled.qml5
-rw-r--r--tests/auto/quick/qquicksystempalette/data/systemPaletteInactive.qml5
-rw-r--r--tests/auto/quick/qquicksystempalette/tst_qquicksystempalette.cpp58
-rw-r--r--tests/auto/quick/qquicktableview/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquicktableview/data/alternatingrowheightcolumnwidth.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/asyncloader.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/asyncplain.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/boundDelegateComponent.qml67
-rw-r--r--tests/auto/quick/qquicktableview/data/changemodelfromdelegate.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/changemodelordelegateduringupdate.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/checkalwaysemit.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/checkmodelpropertyrevision.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/checkrowandcolumnnotchanged.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/columnwidthboundtoviewwidth.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/contentwidthheight.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/countingtableview.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/delegateWithRequired.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/delegatewithRequiredUnset.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/delegatewithanchors.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/deletedDelegate.qml25
-rw-r--r--tests/auto/quick/qquicktableview/data/deprecatedapi.qml25
-rw-r--r--tests/auto/quick/qquicktableview/data/editdelegate.qml60
-rw-r--r--tests/auto/quick/qquicktableview/data/editdelegate_combobox.qml67
-rw-r--r--tests/auto/quick/qquicktableview/data/forcelayout.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/hiderowsandcolumns.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/iscolumnloaded.qml67
-rw-r--r--tests/auto/quick/qquicktableview/data/plaintableview.qml44
-rw-r--r--tests/auto/quick/qquicktableview/data/positionlast.qml52
-rw-r--r--tests/auto/quick/qquicktableview/data/qqmllistpropertymodel.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/resetJsModelData.qml19
-rw-r--r--tests/auto/quick/qquicktableview/data/resetModelData.qml25
-rw-r--r--tests/auto/quick/qquicktableview/data/setcontentpos.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/sizefromdelegate.qml38
-rw-r--r--tests/auto/quick/qquicktableview/data/syncviewsimple.qml66
-rw-r--r--tests/auto/quick/qquicktableview/data/tableviewdefaultspacing.qml29
-rw-r--r--tests/auto/quick/qquicktableview/data/tableviewfocus.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml29
-rw-r--r--tests/auto/quick/qquicktableview/data/tableviewinteractive.qml32
-rw-r--r--tests/auto/quick/qquicktableview/data/tableviewwithselected1.qml38
-rw-r--r--tests/auto/quick/qquicktableview/data/tableviewwithselected2.qml39
-rw-r--r--tests/auto/quick/qquicktableview/data/tweakimplicitsize.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/unloadheader.qml43
-rw-r--r--tests/auto/quick/qquicktableview/data/usechooserwithoutdefault.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/usefaultyrowcolumnprovider.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/userowcolumnprovider.qml40
-rw-r--r--tests/auto/quick/qquicktableview/data/zerosizedtableview.qml37
-rw-r--r--tests/auto/quick/qquicktableview/data/zerosizedviewport.qml31
-rw-r--r--tests/auto/quick/qquicktableview/testmodel.h80
-rw-r--r--tests/auto/quick/qquicktableview/tst_qquicktableview.cpp4666
-rw-r--r--tests/auto/quick/qquicktext/BLACKLIST13
-rw-r--r--tests/auto/quick/qquicktext/CMakeLists.txt20
-rw-r--r--tests/auto/quick/qquicktext/data/elideZeroWidthWithMargins.qml27
-rw-r--r--tests/auto/quick/qquicktext/data/lineLayout.qml2
-rw-r--r--tests/auto/quick/qquicktext/data/lineLayoutFontUpdate.qml25
-rw-r--r--tests/auto/quick/qquicktext/data/lineLayoutImplicitWidth.qml53
-rw-r--r--tests/auto/quick/qquicktext/data/lineLayoutRelayout.qml2
-rw-r--r--tests/auto/quick/qquicktext/data/loaderActiveOnVisible.qml24
-rw-r--r--tests/auto/quick/qquicktext/data/long.qml7
-rw-r--r--tests/auto/quick/qquicktext/data/padding.qml26
-rw-r--r--tests/auto/quick/qquicktext/data/paddingInLoader.qml14
-rw-r--r--tests/auto/quick/qquicktext/data/qtbug_106205.qml28
-rw-r--r--tests/auto/quick/qquicktext/data/tarzeau_ocr_a.ttfbin0 -> 24544 bytes
-rw-r--r--tests/auto/quick/qquicktext/data/viewport.qml19
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp1100
-rw-r--r--tests/auto/quick/qquicktextdocument/CMakeLists.txt19
-rw-r--r--tests/auto/quick/qquicktextdocument/data/hello-8857-7.html9
-rw-r--r--tests/auto/quick/qquicktextdocument/data/hello-utf16be.htmlbin0 -> 48 bytes
-rw-r--r--tests/auto/quick/qquicktextdocument/data/hello.html1
-rw-r--r--tests/auto/quick/qquicktextdocument/data/hello.md1
-rw-r--r--tests/auto/quick/qquicktextdocument/data/hello.txt1
-rw-r--r--tests/auto/quick/qquicktextdocument/data/sideBySideIndependent.qml21
-rw-r--r--tests/auto/quick/qquicktextdocument/data/sideBySideIndependentReverse.qml21
-rw-r--r--tests/auto/quick/qquicktextdocument/data/text.qml14
-rw-r--r--tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp562
-rw-r--r--tests/auto/quick/qquicktextedit/BLACKLIST26
-rw-r--r--tests/auto/quick/qquicktextedit/CMakeLists.txt27
-rw-r--r--tests/auto/quick/qquicktextedit/data/embeddedImagesLocalError.qml2
-rw-r--r--tests/auto/quick/qquicktextedit/data/embeddedImagesRemote.qml2
-rw-r--r--tests/auto/quick/qquicktextedit/data/embeddedImagesRemoteError.qml2
-rw-r--r--tests/auto/quick/qquicktextedit/data/focusByDefault.qml7
-rw-r--r--tests/auto/quick/qquicktextedit/data/httpfail/warning.pngbin0 -> 10285 bytes
-rw-r--r--tests/auto/quick/qquicktextedit/data/httpslow/turtle.svg15
-rw-r--r--tests/auto/quick/qquicktextedit/data/inFlickable.qml7
-rw-r--r--tests/auto/quick/qquicktextedit/data/keyEventPropagation.qml31
-rw-r--r--tests/auto/quick/qquicktextedit/data/keys_shortcutoverride.qml4
-rw-r--r--tests/auto/quick/qquicktextedit/data/markdown.qml9
-rw-r--r--tests/auto/quick/qquicktextedit/data/mouseselection_old_default.qml (renamed from tests/auto/quick/qquicktextedit/data/mouseselection_default.qml)3
-rw-r--r--tests/auto/quick/qquicktextedit/data/mouseselectionmode_default.qml3
-rw-r--r--tests/auto/quick/qquicktextedit/data/multipleRemoteImages.md13
-rw-r--r--tests/auto/quick/qquicktextedit/data/qtConfigureHelp.qml186
-rw-r--r--tests/auto/quick/qquicktextedit/data/qtbug-112858.qml12
-rw-r--r--tests/auto/quick/qquicktextedit/data/resizeTextEditPolish.qml42
-rw-r--r--tests/auto/quick/qquicktextedit/data/tarzeau_ocr_a.ttfbin0 -> 24544 bytes
-rw-r--r--tests/auto/quick/qquicktextedit/data/textEdit.qml6
-rw-r--r--tests/auto/quick/qquicktextedit/data/threeLines.qml7
-rw-r--r--tests/auto/quick/qquicktextedit/data/twoInAColumn.qml32
-rw-r--r--tests/auto/quick/qquicktextedit/data/viewport.qml33
-rw-r--r--tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp2065
-rw-r--r--tests/auto/quick/qquicktextinput/BLACKLIST4
-rw-r--r--tests/auto/quick/qquicktextinput/CMakeLists.txt22
-rw-r--r--tests/auto/quick/qquicktextinput/data/checkCursorDelegateWhenPaddingChanged.qml16
-rw-r--r--tests/auto/quick/qquicktextinput/data/cursorTest.qml2
-rw-r--r--tests/auto/quick/qquicktextinput/data/cursorTestExternal.qml2
-rw-r--r--tests/auto/quick/qquicktextinput/data/cursorTestInline.qml2
-rw-r--r--tests/auto/quick/qquicktextinput/data/focusReason.qml39
-rw-r--r--tests/auto/quick/qquicktextinput/data/mouseselection_old_default.qml (renamed from tests/auto/quick/qquicktextinput/data/mouseselection_true.qml)1
-rw-r--r--tests/auto/quick/qquicktextinput/data/mouseselectionmode_default.qml3
-rw-r--r--tests/auto/quick/qquicktextinput/data/twoInAColumn.qml14
-rw-r--r--tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp882
-rw-r--r--tests/auto/quick/qquicktextmetrics/CMakeLists.txt11
-rw-r--r--tests/auto/quick/qquicktextmetrics/tst_qquicktextmetrics.cpp29
-rw-r--r--tests/auto/quick/qquicktimeline/CMakeLists.txt11
-rw-r--r--tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp29
-rw-r--r--tests/auto/quick/qquicktreeview/CMakeLists.txt50
-rw-r--r--tests/auto/quick/qquicktreeview/data/CustomDelegate.qml47
-rw-r--r--tests/auto/quick/qquicktreeview/data/normaltreeview.qml23
-rw-r--r--tests/auto/quick/qquicktreeview/testmodel.cpp160
-rw-r--r--tests/auto/quick/qquicktreeview/testmodel.h51
-rw-r--r--tests/auto/quick/qquicktreeview/tst_qquicktreeview.cpp1311
-rw-r--r--tests/auto/quick/qquickview/CMakeLists.txt34
-rw-r--r--tests/auto/quick/qquickview/data/TestQml.qml3
-rw-r--r--tests/auto/quick/qquickview/data/overlay.qml17
-rw-r--r--tests/auto/quick/qquickview/tst_qquickview.cpp123
-rw-r--r--tests/auto/quick/qquickview_extra/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickview_extra/tst_qquickview_extra.cpp37
-rw-r--r--tests/auto/quick/qquickvisualdatamodel/CMakeLists.txt26
-rw-r--r--tests/auto/quick/qquickvisualdatamodel/data/attachedDeclarativelySet.qml23
-rw-r--r--tests/auto/quick/qquickvisualdatamodel/data/externalManagedModel.qml29
-rw-r--r--tests/auto/quick/qquickvisualdatamodel/data/objectDeletion.qml20
-rw-r--r--tests/auto/quick/qquickvisualdatamodel/data/setDelegateNoDoubleChange.qml43
-rw-r--r--tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp357
-rw-r--r--tests/auto/quick/qquickwindow/BLACKLIST12
-rw-r--r--tests/auto/quick/qquickwindow/CMakeLists.txt24
-rw-r--r--tests/auto/quick/qquickwindow/data/conflictingVisibleFalse.qml6
-rw-r--r--tests/auto/quick/qquickwindow/data/conflictingVisibleTrue.qml6
-rw-r--r--tests/auto/quick/qquickwindow/data/earlyGrab.qml25
-rw-r--r--tests/auto/quick/qquickwindow/data/eventTypes.qml20
-rw-r--r--tests/auto/quick/qquickwindow/data/maximized.qml5
-rw-r--r--tests/auto/quick/qquickwindow/data/shortcut.qml29
-rw-r--r--tests/auto/quick/qquickwindow/data/shortcutOverride.qml30
-rw-r--r--tests/auto/quick/qquickwindow/data/visibilityDoesntClobberWindowState.qml5
-rw-r--r--tests/auto/quick/qquickwindow/data/windowattached.qml4
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp721
-rw-r--r--tests/auto/quick/qquickwindowcontainer/CMakeLists.txt37
-rw-r--r--tests/auto/quick/qquickwindowcontainer/data/basicFunctionality_container.qml15
-rw-r--r--tests/auto/quick/qquickwindowcontainer/data/basicFunctionality_item.qml15
-rw-r--r--tests/auto/quick/qquickwindowcontainer/data/basicFunctionality_window.qml10
-rw-r--r--tests/auto/quick/qquickwindowcontainer/data/deferredVisibilityWithoutWindow.qml11
-rw-r--r--tests/auto/quick/qquickwindowcontainer/data/windowComponent.qml28
-rw-r--r--tests/auto/quick/qquickwindowcontainer/tst_qquickwindowcontainer.cpp192
-rw-r--r--tests/auto/quick/rendernode/CMakeLists.txt27
-rw-r--r--tests/auto/quick/rendernode/color.frag15
-rw-r--r--tests/auto/quick/rendernode/color.vert17
-rw-r--r--tests/auto/quick/rendernode/data/MessUpState.qml33
-rw-r--r--tests/auto/quick/rendernode/data/RenderOrder.qml53
-rw-r--r--tests/auto/quick/rendernode/data/glsimple.qml26
-rw-r--r--tests/auto/quick/rendernode/data/matrix.qml74
-rw-r--r--tests/auto/quick/rendernode/data/simple.qml26
-rw-r--r--tests/auto/quick/rendernode/tst_rendernode.cpp554
-rw-r--r--tests/auto/quick/scenegraph/CMakeLists.txt41
-rw-r--r--tests/auto/quick/scenegraph/data/RenderTestBase.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/manyWindows_dftext.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/manyWindows_image.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/manyWindows_ntext.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/manyWindows_rects.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/renderControl_rect.qml16
-rw-r--r--tests/auto/quick/scenegraph/data/render_AlphaOverlapRebuild.qml90
-rw-r--r--tests/auto/quick/scenegraph/data/render_BreakOpacityBatch.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/render_DrawSets.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/render_ImageFiltering.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/render_Mipmap.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/render_MovingOverlap.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/render_OpacityThroughBatchRoot.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/render_OutOfFloatRange.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/render_Overlap.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/render_StackingOrder.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/render_bug37422.frag.qsbbin686 -> 0 bytes
-rw-r--r--tests/auto/quick/scenegraph/data/render_bug37422.qml31
-rw-r--r--tests/auto/quick/scenegraph/data/simple.qml29
-rw-r--r--tests/auto/quick/scenegraph/data/widebtn1.pngbin0 -> 1969 bytes
-rw-r--r--tests/auto/quick/scenegraph/data/widebtn2.pngbin0 -> 1965 bytes
-rw-r--r--tests/auto/quick/scenegraph/tst_scenegraph.cpp387
-rw-r--r--tests/auto/quick/shared/geometrytestutil.cpp43
-rw-r--r--tests/auto/quick/shared/geometrytestutil.h49
-rw-r--r--tests/auto/quick/shared/viewtestutil.cpp531
-rw-r--r--tests/auto/quick/shared/viewtestutil.h203
-rw-r--r--tests/auto/quick/shared/visualtestutil.cpp104
-rw-r--r--tests/auto/quick/shared/visualtestutil.h103
-rw-r--r--tests/auto/quick/sharedimage/CMakeLists.txt11
-rw-r--r--tests/auto/quick/sharedimage/tst_sharedimage.cpp37
-rw-r--r--tests/auto/quick/softwarerenderer/CMakeLists.txt35
-rw-r--r--tests/auto/quick/softwarerenderer/tst_softwarerenderer.cpp99
-rw-r--r--tests/auto/quick/touchmouse/BLACKLIST4
-rw-r--r--tests/auto/quick/touchmouse/CMakeLists.txt24
-rw-r--r--tests/auto/quick/touchmouse/data/oneMouseArea.qml14
-rw-r--r--tests/auto/quick/touchmouse/tst_touchmouse.cpp243
777 files changed, 38139 insertions, 16403 deletions
diff --git a/tests/auto/quick/.prev_CMakeLists.txt b/tests/auto/quick/.prev_CMakeLists.txt
deleted file mode 100644
index 6714305201..0000000000
--- a/tests/auto/quick/.prev_CMakeLists.txt
+++ /dev/null
@@ -1,72 +0,0 @@
-# Generated from quick.pro.
-
-add_subdirectory(geometry)
-add_subdirectory(qquickpixmapcache)
-if(QT_FEATURE_private_tests)
- add_subdirectory(nokeywords)
- add_subdirectory(propertyrequirements)
- add_subdirectory(qquickanimations)
- add_subdirectory(qquickapplication)
- add_subdirectory(qquickbehaviors)
- add_subdirectory(qquickboundaryrule)
- add_subdirectory(qquickfontloader)
- add_subdirectory(qquickfontloader_static)
- add_subdirectory(qquickfontmetrics)
- add_subdirectory(qquickimageprovider)
- add_subdirectory(qquicklayouts)
- add_subdirectory(qquickpath)
- add_subdirectory(qquicksmoothedanimation)
- add_subdirectory(qquickspringanimation)
- add_subdirectory(qquickanimationcontroller)
- add_subdirectory(qquickstyledtext)
- add_subdirectory(qquickstates)
- add_subdirectory(qquicksystempalette)
- add_subdirectory(qquickcolorgroup)
- add_subdirectory(qquickpalette)
- add_subdirectory(qquicktimeline)
- add_subdirectory(pointerhandlers)
- add_subdirectory(qquickaccessible)
- add_subdirectory(qquickanchors)
- add_subdirectory(qquickanimatedimage)
- add_subdirectory(qquickanimators)
- add_subdirectory(qquickdynamicpropertyanimation)
- add_subdirectory(qquickborderimage)
- add_subdirectory(qquickwindow)
- add_subdirectory(qquickdrag)
- add_subdirectory(qquickdroparea)
- add_subdirectory(qquickflickable)
- add_subdirectory(qquickflipable)
- add_subdirectory(qquickfocusscope)
- add_subdirectory(qquickgraphicsinfo)
- add_subdirectory(qquickgridview)
- add_subdirectory(qquickimage)
- add_subdirectory(qquickitem)
- add_subdirectory(qquickitem2)
- add_subdirectory(qquickitemlayer)
- add_subdirectory(qquicklistview)
- add_subdirectory(qquicktableview)
- add_subdirectory(qquickloader)
- add_subdirectory(qquickmousearea)
- add_subdirectory(qquickmultipointtoucharea)
- add_subdirectory(qquickpainteditem)
- add_subdirectory(qquickshape)
- add_subdirectory(qquickpathview)
- add_subdirectory(qquickpincharea)
- add_subdirectory(qquickpositioners)
- add_subdirectory(qquickrectangle)
- add_subdirectory(qquickrepeater)
- add_subdirectory(qquickshortcut)
- add_subdirectory(qquicktext)
- add_subdirectory(qquicktextdocument)
- add_subdirectory(qquicktextedit)
- add_subdirectory(qquicktextinput)
- add_subdirectory(qquickvisualdatamodel)
- add_subdirectory(qquickview)
- add_subdirectory(qquickview_extra)
- add_subdirectory(qquickcanvasitem)
- add_subdirectory(qquickdesignersupport)
- add_subdirectory(qquickscreen)
- add_subdirectory(touchmouse)
- add_subdirectory(scenegraph)
- add_subdirectory(sharedimage)
-endif()
diff --git a/tests/auto/quick/CMakeLists.txt b/tests/auto/quick/CMakeLists.txt
index 70574110ed..3ecf89f351 100644
--- a/tests/auto/quick/CMakeLists.txt
+++ b/tests/auto/quick/CMakeLists.txt
@@ -1,8 +1,21 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from quick.pro.
add_subdirectory(geometry)
+add_subdirectory(nodes)
add_subdirectory(qquickpixmapcache)
+
+# Limit set of tests to run for static Qt builds.
+if(QT_BUILD_MINIMAL_STATIC_TESTS)
+ return()
+endif()
+add_subdirectory(drawingmodes)
+
if(QT_FEATURE_private_tests)
+ add_subdirectory(doc)
+ add_subdirectory(examples)
add_subdirectory(nokeywords)
add_subdirectory(propertyrequirements)
add_subdirectory(qquickanimations)
@@ -30,7 +43,10 @@ if(QT_FEATURE_private_tests)
add_subdirectory(qquickdynamicpropertyanimation)
add_subdirectory(qquickborderimage)
add_subdirectory(qquickwindow)
+ add_subdirectory(qquickwindowcontainer)
+ add_subdirectory(qquickdeliveryagent)
add_subdirectory(qquickdrag)
+ add_subdirectory(qquickdragattached)
add_subdirectory(qquickdroparea)
add_subdirectory(qquickflickable)
add_subdirectory(qquickflipable)
@@ -42,7 +58,9 @@ if(QT_FEATURE_private_tests)
add_subdirectory(qquickitem2)
add_subdirectory(qquickitemlayer)
add_subdirectory(qquicklistview)
+ add_subdirectory(qquicklistview2)
add_subdirectory(qquicktableview)
+ add_subdirectory(qquicktreeview)
add_subdirectory(qquickloader)
add_subdirectory(qquickmousearea)
add_subdirectory(qquickmultipointtoucharea)
@@ -62,11 +80,25 @@ if(QT_FEATURE_private_tests)
add_subdirectory(qquickview)
add_subdirectory(qquickview_extra)
add_subdirectory(qquickcanvasitem)
- add_subdirectory(qquickdesignersupport)
+ if(QT_FEATURE_quick_designer)
+ add_subdirectory(qquickdesignersupport)
+ endif()
add_subdirectory(qquickscreen)
add_subdirectory(touchmouse)
add_subdirectory(scenegraph)
add_subdirectory(sharedimage)
add_subdirectory(qquickcolorgroup)
add_subdirectory(qquickpalette)
+ add_subdirectory(qquickrendercontrol)
+ add_subdirectory(qquickshadereffect)
+ add_subdirectory(qquickanimatedsprite)
+ add_subdirectory(qquickspritesequence)
+ add_subdirectory(qquickrhiitem)
+ add_subdirectory(rendernode)
+
+ if(QT_FEATURE_opengl)
+ add_subdirectory(qquickframebufferobject)
+ endif()
+
+ add_subdirectory(softwarerenderer)
endif()
diff --git a/tests/auto/quick/doc/CMakeLists.txt b/tests/auto/quick/doc/CMakeLists.txt
new file mode 100644
index 0000000000..1a7e1b834e
--- /dev/null
+++ b/tests/auto/quick/doc/CMakeLists.txt
@@ -0,0 +1,7 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# This directory contains auto tests for documentation examples/snippets.
+
+add_subdirectory(how-tos)
+
diff --git a/tests/auto/quick/doc/how-tos/CMakeLists.txt b/tests/auto/quick/doc/how-tos/CMakeLists.txt
new file mode 100644
index 0000000000..202ff38bb5
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+add_subdirectory(how-to-cpp-button)
+add_subdirectory(how-to-cpp-enum-js)
+add_subdirectory(how-to-qml)
diff --git a/tests/auto/quick/doc/how-tos/how-to-cpp-button/CMakeLists.txt b/tests/auto/quick/doc/how-tos/how-to-cpp-button/CMakeLists.txt
new file mode 100644
index 0000000000..34f370c7b3
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-cpp-button/CMakeLists.txt
@@ -0,0 +1,31 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_how-to-cpp-button LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_how-to-cpp-button
+ SOURCES
+ tst_how-to-cpp-button.cpp
+ LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::Quick
+ Qt::QuickPrivate
+ Qt::QuickControlsTestUtilsPrivate
+ Qt::QuickTemplates2Private
+)
+
+qt_policy(SET QTP0001 NEW)
+
+qt_add_qml_module(tst_how-to-cpp-button
+ URI MyModule
+ QML_FILES
+ Main.qml
+ SOURCES
+ backend.h
+ backend.cpp
+)
diff --git a/tests/auto/quick/doc/how-tos/how-to-cpp-button/Main.qml b/tests/auto/quick/doc/how-tos/how-to-cpp-button/Main.qml
new file mode 100644
index 0000000000..5150f6c6d6
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-cpp-button/Main.qml
@@ -0,0 +1,19 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+//! [file]
+import QtQuick.Controls
+
+import MyModule
+
+ApplicationWindow {
+ width: 400
+ height: 400
+ title: qsTr("C++ Button example")
+
+ Button {
+ text: qsTr("Click me")
+ onClicked: Backend.doStuff()
+ }
+}
+//! [file]
diff --git a/tests/auto/quick/doc/how-tos/how-to-cpp-button/backend.cpp b/tests/auto/quick/doc/how-tos/how-to-cpp-button/backend.cpp
new file mode 100644
index 0000000000..4143aea9e6
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-cpp-button/backend.cpp
@@ -0,0 +1,13 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+//! [file]
+#include "backend.h"
+
+#include <QDebug>
+
+void Backend::doStuff()
+{
+ qDebug() << "Did stuff!";
+}
+//! [file]
diff --git a/tests/auto/quick/doc/how-tos/how-to-cpp-button/backend.h b/tests/auto/quick/doc/how-tos/how-to-cpp-button/backend.h
new file mode 100644
index 0000000000..10249f5416
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-cpp-button/backend.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+//! [file]
+#include <QObject>
+#include <QQmlEngine>
+
+class Backend : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_SINGLETON
+
+public:
+ Q_INVOKABLE void doStuff();
+};
+//! [file]
diff --git a/tests/auto/quick/doc/how-tos/how-to-cpp-button/tst_how-to-cpp-button.cpp b/tests/auto/quick/doc/how-tos/how-to-cpp-button/tst_how-to-cpp-button.cpp
new file mode 100644
index 0000000000..792f84ffc2
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-cpp-button/tst_how-to-cpp-button.cpp
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtCore/qregularexpression.h>
+#include <QtTest/QtTest>
+#include <QtQml/qqmlapplicationengine.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuickTemplates2/private/qquickbutton_p.h>
+#include <QtQuickControlsTestUtils/private/controlstestutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QQuickControlsTestUtils;
+
+class tst_HowToCppButton : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_HowToCppButton();
+
+private slots:
+ void example();
+};
+
+tst_HowToCppButton::tst_HowToCppButton()
+{
+}
+
+void tst_HowToCppButton::example()
+{
+ QTest::failOnWarning(QRegularExpression(QStringLiteral(".?")));
+
+ QQmlApplicationEngine engine;
+ engine.loadFromModule("MyModule", "Main");
+ QCOMPARE(engine.rootObjects().size(), 1);
+
+ auto *window = qobject_cast<QQuickWindow*>(engine.rootObjects().at(0));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *button = window->findChild<QQuickButton*>();
+ QVERIFY(button);
+ QCOMPARE(button->text(), "Click me");
+ QTest::ignoreMessage(QtDebugMsg, "Did stuff!");
+ QVERIFY(clickButton(button));
+}
+
+QT_END_NAMESPACE
+
+QTEST_MAIN(tst_HowToCppButton)
+
+#include "tst_how-to-cpp-button.moc"
diff --git a/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/CMakeLists.txt b/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/CMakeLists.txt
new file mode 100644
index 0000000000..5adc456b4b
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/CMakeLists.txt
@@ -0,0 +1,25 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_how-to-cpp-enum-js LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_how-to-cpp-enum-js
+ SOURCES
+ backend.cpp
+ backend.h
+ tst_how-to-cpp-enum-js.cpp
+ LIBRARIES
+ Qt::Core
+ Qt::Qml
+)
+
+qt_add_resources(tst_how-to-cpp-enum-js "js"
+ PREFIX
+ /
+ FILES
+ script.mjs
+)
diff --git a/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/backend.cpp b/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/backend.cpp
new file mode 100644
index 0000000000..a78678cc18
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/backend.cpp
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+//! [file]
+#include "backend.h"
+
+Backend::Backend(QJSEngine *engine) :
+ mEngine(engine)
+{
+}
+
+bool Backend::load()
+{
+ // Do some loading here...
+
+ const QJSValue module = mEngine->importModule(":/script.mjs");
+ if (module.isError()) {
+ qWarning() << "Error loading script.mjs:" << module.toString();
+ return false;
+ }
+
+ const QJSValue function = module.property("backendStatusUpdate");
+ if (!function.isCallable()) {
+ qWarning() << "backendStatusUpdate script function is not callable!";
+ return false;
+ }
+
+ const QJSValue functionResult = function.call(QJSValueList() << Loaded);
+ if (functionResult.isError()) {
+ qWarning() << "backendStatusUpdate script function had errors:" << functionResult.toString();
+ return false;
+ }
+
+ return true;
+}
+//! [file]
diff --git a/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/backend.h b/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/backend.h
new file mode 100644
index 0000000000..5e723d406e
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/backend.h
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+//! [file]
+#include <QObject>
+#include <QJSEngine>
+
+class Backend : public QObject
+{
+ Q_OBJECT
+
+public:
+ Backend(QJSEngine *engine);
+
+ enum Status {
+ Unknown,
+ Error,
+ Loading,
+ Loaded
+ };
+
+ Q_ENUM(Status)
+
+ bool load();
+
+private:
+ QJSEngine *mEngine = nullptr;
+};
+//! [file]
diff --git a/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/script.mjs b/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/script.mjs
new file mode 100644
index 0000000000..a4f929222a
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/script.mjs
@@ -0,0 +1,13 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+//! [file]
+export function backendStatusUpdate(backendStatus) {
+ if (backendStatus === Backend.Error) {
+ console.warn("Error!")
+ return
+ }
+
+ console.log("Backend loaded successfully")
+}
+//! [file]
diff --git a/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/tst_how-to-cpp-enum-js.cpp b/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/tst_how-to-cpp-enum-js.cpp
new file mode 100644
index 0000000000..933a1cf3e3
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-cpp-enum-js/tst_how-to-cpp-enum-js.cpp
@@ -0,0 +1,47 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtCore/qregularexpression.h>
+#include <QtTest/QtTest>
+#include <QtQml/qjsengine.h>
+
+#include "backend.h"
+
+QT_BEGIN_NAMESPACE
+
+class tst_HowToCppEnumJs : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_HowToCppEnumJs();
+
+private slots:
+ void example();
+};
+
+tst_HowToCppEnumJs::tst_HowToCppEnumJs()
+{
+}
+
+void tst_HowToCppEnumJs::example()
+{
+ QTest::failOnWarning(QRegularExpression(QStringLiteral(".?")));
+
+ QJSEngine engine;
+ engine.installExtensions(QJSEngine::AllExtensions);
+
+ QJSValue backendJsMetaObject = engine.newQMetaObject(&Backend::staticMetaObject);
+ engine.globalObject().setProperty("Backend", backendJsMetaObject);
+
+ QTest::ignoreMessage(QtDebugMsg, "Backend loaded successfully");
+ Backend backend(&engine);
+ const bool loaded = backend.load();
+ QVERIFY(loaded);
+}
+
+QT_END_NAMESPACE
+
+QTEST_MAIN(tst_HowToCppEnumJs)
+
+#include "tst_how-to-cpp-enum-js.moc"
diff --git a/tests/auto/quick/doc/how-tos/how-to-qml/CMakeLists.txt b/tests/auto/quick/doc/how-tos/how-to-qml/CMakeLists.txt
new file mode 100644
index 0000000000..bdf84439c8
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-qml/CMakeLists.txt
@@ -0,0 +1,33 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_how-to-qml LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_how-to-qml
+ SOURCES
+ tst_how-to-qml.cpp
+ LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::Quick
+ Qt::QuickPrivate
+ Qt::QuickControlsTestUtilsPrivate
+ Qt::QuickTemplates2Private
+)
+
+qt_policy(SET QTP0001 NEW)
+
+qt_add_qml_module(tst_how-to-qml
+ URI HowToQml
+ QML_FILES
+ active-focus-debugging/ActiveFocusDebuggingMain.qml
+ time-picker/TimeComponentLabel.qml
+ time-picker/TimePickerDialog.qml
+ time-picker/TimePickerMain.qml
+ time-picker/TimePickerLabel.qml
+ time-picker/TimePicker.qml
+)
diff --git a/tests/auto/quick/doc/how-tos/how-to-qml/active-focus-debugging/ActiveFocusDebuggingMain.qml b/tests/auto/quick/doc/how-tos/how-to-qml/active-focus-debugging/ActiveFocusDebuggingMain.qml
new file mode 100644
index 0000000000..b0f48cdb59
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-qml/active-focus-debugging/ActiveFocusDebuggingMain.qml
@@ -0,0 +1,25 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 400
+ height: 400
+ visible: true
+ title: qsTr("Active focus debugging example")
+
+ onActiveFocusItemChanged: print("activeFocusItem: " + activeFocusItem)
+
+ Row {
+ TextField {
+ objectName: "textField1"
+ }
+ TextField {
+ objectName: "textField2"
+ }
+ }
+}
+//! [file]
diff --git a/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimeComponentLabel.qml b/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimeComponentLabel.qml
new file mode 100644
index 0000000000..6b1653bde5
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimeComponentLabel.qml
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls.Material
+
+Label {
+ id: root
+ fontSizeMode: Label.Fit
+ horizontalAlignment: Label.AlignHCenter
+ verticalAlignment: Label.AlignVCenter
+
+ Material.foreground: Material.theme === Material.Light
+ ? Material.color(Material.Indigo, !dim ? Material.Shade500 : Material.Shade100)
+ : Material.color(Material.Indigo, dim ? Material.Shade300 : Material.Shade100)
+
+ Layout.fillHeight: true
+
+ property bool dim: false
+ property alias interactive: tapHandler.enabled
+
+ signal tapped
+
+ TapHandler {
+ id: tapHandler
+ onTapped: root.tapped()
+ }
+}
diff --git a/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePicker.qml b/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePicker.qml
new file mode 100644
index 0000000000..edcf864784
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePicker.qml
@@ -0,0 +1,325 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+//! [file]
+import QtQuick
+import QtQuick.Controls.Material
+
+Item {
+ id: root
+ implicitWidth: 250
+ implicitHeight: 250
+
+ enum Mode {
+ Hours,
+ Minutes
+ }
+
+ property int mode: TimePicker.Mode.Hours
+ property int hours
+ property int minutes
+ property bool is24Hour
+ property bool interactive: true
+
+ // The mode that the label delegates see, so that we can
+ // animate their opacity before their text changes.
+ property int __effectiveMode: TimePicker.Mode.Hours
+ // For 12 hour pickers, we can use 0 to 60 to represent all values.
+ property int __value: 0
+ // For 24 hour pickers, we need to store this extra flag.
+ property bool __is24HourValueSelected
+ // How many values the arm should snap to at a time.
+ readonly property int __stepSize: __getStepSize(mode)
+ readonly property int __to: 60
+ readonly property int __labelAngleStepSize: 360 / 12
+ property bool __switchingModes
+
+ // This signal could be used if TimePicker is used as a standalone component.
+ // It's emitted when the minute is selected.
+ signal accepted()
+
+ // Convenience for setting each property individually, but also
+ // ensures that the selector arm is properly rotated when there is
+ // a programmatic change in hours or minutes but not mode.
+ function openWith(mode, hours, minutes) {
+ root.mode = mode
+ root.hours = hours
+ root.minutes = minutes
+ __updateAfterModeOrTimeChange()
+ }
+
+ // Until QML gets private properties (QTBUG-11984), use the traditional
+ // double-underscore convention.
+ function __angleForValue(value: int): real {
+ return (value / __to) * 360
+ }
+
+ function __getStepSize(mode) {
+ return mode === TimePicker.Mode.Hours ? 5 : 1
+ }
+
+ function __updateAfterModeOrTimeChange() {
+ // We use a function for this rather than a binding, because we could be called before the
+ // __stepSize binding is evaluated.
+ if (mode === TimePicker.Mode.Hours) {
+ // modulo the hours value by __to because we want 60 (12) to be 0.
+ __value = hours * __getStepSize(mode) % __to
+ } else {
+ __value = minutes
+ }
+
+ __is24HourValueSelected = mode === TimePicker.Mode.Hours && hours >= 13
+ }
+
+ onModeChanged: __updateAfterModeOrTimeChange()
+
+ onIs24HourChanged: {
+ // Don't allow 24-hour values when we're not a 24-hour picker.
+ if (!is24Hour && hours > 12)
+ hours = 12
+ }
+
+ // Center dot.
+ Rectangle {
+ width: 6
+ height: 6
+ radius: width / 2
+ color: Material.primary
+ anchors.centerIn: parent
+ z: 1
+ }
+
+ Rectangle {
+ id: contentContainer
+ objectName: "contentContainer"
+ width: Math.min(parent.width, parent.height)
+ height: width
+ radius: width / 2
+ anchors.centerIn: parent
+ color: Material.theme === Material.Light ? "#eeeeee" : "#626262"
+
+ // Animate this so that we don't need an intermediate parent item for the
+ // labels to animate the opacity of that instead. That item would be required
+ // because we don't want to change the opacity of the contentContainer Rectangle.
+ property real labelOpacity: 1
+
+ function updateValueAfterPressPointChange() {
+ const y1 = height / 2
+ const x1 = width / 2
+ const y2 = tapHandler.point.position.y
+ const x2 = tapHandler.point.position.x
+ const yDistance = y2 - y1
+ const xDistance = x2 - x1
+ const angle = Math.atan2(yDistance, xDistance)
+
+ let angleInDegrees = (angle * (180 / Math.PI)) + 90.0
+ if (angleInDegrees < 0)
+ angleInDegrees = 360 + angleInDegrees
+
+ const normalisedAngle = angleInDegrees / 360.0
+ const rawValue = normalisedAngle * __to
+ // Snap to each step.
+ const steppedValue = Math.round(rawValue / __stepSize) * __stepSize
+ root.__value = steppedValue
+ // Account for the area where the angle wraps around from 360 to 0,
+ // otherwise values from 59.5 to 59.999[...] will register as 60 instead of 0.
+ if (rawValue > __to - __stepSize / 2)
+ root.__value = 0
+
+ const distanceFromCenter = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2))
+ // Only allow selecting 24 hour values when it's in the correct mode.
+ root.__is24HourValueSelected = root.is24Hour && root.__effectiveMode === TimePicker.Mode.Hours
+ && distanceFromCenter < distanceFromCenterForLabels(true) + selectionIndicator.height * 0.5
+ }
+
+ // Returns the distance from our center at which a label should be centered over given is24Hour.
+ function distanceFromCenterForLabels(is24Hour) {
+ return contentContainer.radius - (is24Hour
+ ? selectionIndicator.height * 1.5 : selectionIndicator.height * 0.5)
+ }
+
+ states: [
+ State {
+ name: "hours"
+ when: root.mode === TimePicker.Mode.Hours
+ },
+ State {
+ name: "minutes"
+ when: root.mode === TimePicker.Mode.Minutes
+ }
+ ]
+
+ transitions: [
+ Transition {
+ // When the picker isn't interactive (e.g. when a dialog is opening),
+ // we shouldn't animate the opacity of the labels, as it looks wrong,
+ // and should only happen when switching between modes while the
+ // picker was already visible.
+ enabled: root.interactive
+
+ SequentialAnimation {
+ NumberAnimation {
+ target: contentContainer
+ property: "labelOpacity"
+ from: 1
+ to: 0
+ duration: 100
+ }
+
+ ScriptAction {
+ script: root.__effectiveMode = root.mode
+ }
+
+ NumberAnimation {
+ target: contentContainer
+ property: "labelOpacity"
+ from: 0
+ to: 1
+ duration: 100
+ }
+ }
+ },
+ Transition {
+ enabled: !root.interactive
+
+ // Since the transition above doesn't run when we're not interactive,
+ // we need to do the immediate property change here.
+ // See QTBUG-13268 for why we use a ScriptAction and not PropertyAction.
+ ScriptAction {
+ script: root.__effectiveMode = root.mode
+ }
+ }
+
+ ]
+
+ TapHandler {
+ id: tapHandler
+ gesturePolicy: TapHandler.ReleaseWithinBounds
+ // Don't allow input while switching modes, or a click on an hour could go through to a minute.
+ enabled: root.interactive && root.__effectiveMode === root.mode
+
+ onPointChanged: {
+ if (pressed) {
+ // Don't call this when not pressed, as the position will be invalid.
+ contentContainer.updateValueAfterPressPointChange()
+
+ // Update the value (like a "live" Slider) while the pointer position changes.
+ if (mode === TimePicker.Mode.Hours) {
+ root.hours = root.__value / root.__stepSize
+
+ if (root.hours === 0) {
+ // A value of 0 (when it's not a 24-hour picker) is 12.
+ // When it is a 24-hour picker, it's 0.
+ if (!root.__is24HourValueSelected)
+ root.hours = 12
+ } else if (root.__is24HourValueSelected) {
+ root.hours += 12
+ }
+ } else {
+ root.minutes = root.__value
+ }
+ } else {
+ // Select the value that was chosen in the press code above.
+ if (mode === TimePicker.Mode.Hours) {
+ mode = TimePicker.Mode.Minutes
+ } else {
+ // Does nothing in our example, but could be used to hide the dialog
+ // if it didn't have an OK button to accept it.
+ root.accepted()
+ }
+ }
+ }
+ }
+
+ // The line connecting the center dot to the selection indicator.
+ Rectangle {
+ id: selectionArm
+ objectName: "selectionArm"
+ width: 2
+ height: contentContainer.distanceFromCenterForLabels(root.__is24HourValueSelected)
+ color: Material.primary
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.verticalCenter
+ rotation: root.__angleForValue(root.__value)
+ transformOrigin: Item.Bottom
+ antialiasing: true
+
+ Rectangle {
+ id: selectionIndicator
+ objectName: "selectionIndicator"
+ width: 40
+ height: 40
+ radius: width / 2
+ color: Material.primary
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.top
+
+ Rectangle {
+ width: 4
+ height: 4
+ radius: width / 2
+ color: Material.color(Material.Indigo, Material.Shade100)
+ anchors.centerIn: parent
+ // Only show the circle within the indicator between minute labels.
+ visible: root.__effectiveMode === TimePicker.Mode.Minutes
+ && root.__value % 5 !== 0
+ }
+ }
+ }
+
+ Repeater {
+ id: labelRepeater
+ model: root.mode === TimePicker.Mode.Hours && root.is24Hour ? 24 : 12
+ delegate: Label {
+ id: labelDelegate
+ text: displayValue
+ font.pixelSize: Qt.application.font.pixelSize * (is24HourValue ? 0.85 : 1)
+ rotation: -rotationTransform.angle
+ opacity: contentContainer.labelOpacity
+ anchors.centerIn: parent
+
+ // TODO: remove me - QTBUG-122679
+ Component.onCompleted: print("created", labelDelegate, "at index", index)
+ Component.onDestruction: print("destroyed", labelDelegate, "at index", index)
+
+ required property int index
+ // From 0 to 60.
+ readonly property int value: (index * 5) % root.__to
+ property int displayValue: root.__effectiveMode === TimePicker.Mode.Hours
+ ? index === 0
+ ? 12
+ : index === 12
+ ? 0
+ : index
+ : value
+ // The picker's current value can equal ours but we still might not be current -
+ // it depends on whether it's a 24 hour value or not.
+ readonly property bool current: root.__value === value && root.__is24HourValueSelected == is24HourValue
+ readonly property bool is24HourValue: index >= 12
+
+ Material.foreground: current
+ // When the selection arm is over us, invert our color so it's legible.
+ ? Material.color(Material.Indigo, Material.Shade100)
+ : root.Material.theme === Material.Light
+ ? is24HourValue ? "#686868" : "#484848"
+ : Material.color(Material.Indigo, is24HourValue ? Material.Shade300 : Material.Shade100)
+
+ transform: [
+ Translate {
+ // We're already centered in our parent, so we can use this function
+ // to determine our position, which doesn't need to be aware of our height -
+ // it just needs to tell us where our center position should be.
+ y: -contentContainer.distanceFromCenterForLabels(labelDelegate.is24HourValue)
+ },
+ Rotation {
+ id: rotationTransform
+ angle: root.__angleForValue(labelDelegate.value)
+ origin.x: labelDelegate.width / 2
+ origin.y: labelDelegate.height / 2
+ }
+ ]
+ }
+ }
+ }
+}
+//! [file]
diff --git a/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePickerDialog.qml b/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePickerDialog.qml
new file mode 100644
index 0000000000..fa02234eb8
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePickerDialog.qml
@@ -0,0 +1,88 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+//! [file]
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls.Material
+
+Dialog {
+ id: root
+ standardButtons: Dialog.Ok | Dialog.Cancel
+ closePolicy: Dialog.NoAutoClose
+ // We don't want so much space between the picker and dialog buttons.
+ bottomPadding: 8
+
+ property int hours: 12
+ property int minutes: 0
+ property alias is24Hour: timePicker.is24Hour
+
+ property int __initialHours
+ property int __initialMinutes
+
+ signal timeAccepted
+ signal timeRejected
+
+ function openWithMode(mode) {
+ timePicker.openWith(mode !== undefined ? mode : TimePicker.Mode.Hours, hours, minutes)
+
+ __initialHours = hours
+ __initialMinutes = minutes
+
+ open()
+ }
+
+ onAccepted: {
+ root.hours = timePicker.hours
+ root.minutes = timePicker.minutes
+ root.timeAccepted()
+ }
+ onRejected: {
+ hours = __initialHours
+ minutes = __initialMinutes
+ // Also reset the picker's time so that the onIs24HourChanged handler below works as expected.
+ timePicker.hours = __initialHours
+ timePicker.minutes = __initialMinutes
+ root.timeRejected()
+ }
+
+ // If is24Hour changes programmatically (only while we're not open),
+ // make sure we adapt to any possible clamping it did in the transition from 24 hours to 12.
+ onIs24HourChanged: {
+ if (!opened)
+ root.hours = timePicker.hours
+ }
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 12
+
+ TimePickerLabel {
+ id: timeLabel
+ // Use TimePicker's time, because that is updated live, whereas our values
+ // are only changed once we've been accepted.
+ time: new Date(1970, 1, 1, timePicker.hours, timePicker.minutes)
+ hoursActive: timePicker.mode === TimePicker.Mode.Hours
+ showAmPm: !timePicker.is24Hour
+
+ Layout.fillWidth: true
+ // Push us down a bit so we're not so close to the top of the dialog.
+ Layout.topMargin: 8
+
+ onHoursSelected: timePicker.mode = TimePicker.Mode.Hours
+ onMinutesSelected: timePicker.mode = TimePicker.Mode.Minutes
+ }
+
+ TimePicker {
+ id: timePicker
+ objectName: "timePicker"
+ // Our TapHandler may handle the click event on the Label if we don't do this,
+ // causing an hour to be inadvertently selected.
+ interactive: root.opened
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+}
+//! [file]
diff --git a/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePickerLabel.qml b/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePickerLabel.qml
new file mode 100644
index 0000000000..66b651c0c5
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePickerLabel.qml
@@ -0,0 +1,126 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+//! [file]
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls.Material
+
+Item {
+ id: root
+ // Use TextMetrics' boundingRect.width rather than a RowLayout's implicitWidth
+ // because the latter can cause TimePickerDialog to jump around when the label text changes.
+ implicitWidth: fullTextMetrics.boundingRect.width + amPmLayout.implicitWidth + 80
+ implicitHeight: fullTextMetrics.boundingRect.height
+
+ property var time
+ property bool am: true
+ property bool showAmPm: true
+
+ property bool hoursActive: true
+
+ property int fontPixelSize: Qt.application.font.pixelSize * 4
+
+ signal hoursSelected
+ signal minutesSelected
+ signal amSelected
+ signal pmSelected
+
+ TextMetrics {
+ id: fullTextMetrics
+ font: hoursLabel.font
+ text: "99:99"
+ }
+
+ TextMetrics {
+ id: hourTextMetrics
+ font.family: hoursLabel.font.family
+ font.pixelSize: hoursLabel.fontInfo.pixelSize
+ text: "99"
+ }
+
+ TimeComponentLabel {
+ id: hoursLabel
+ objectName: "hoursLabel"
+ text: Qt.formatTime(root.time, "hh")
+ font.pixelSize: root.fontPixelSize
+ // Avoid any jumping around by using a dedicated TextMetrics object
+ // for our label too, and position ourselves based on its width.
+ x: colonLabel.x - hourTextMetrics.boundingRect.width - 4
+ anchors.verticalCenter: parent.verticalCenter
+ dim: !root.hoursActive
+
+ onTapped: root.hoursSelected()
+ }
+
+ TimeComponentLabel {
+ id: colonLabel
+ text: ":"
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ font.pixelSize: root.fontPixelSize
+ dim: true
+ }
+
+ TimeComponentLabel {
+ id: minutesLabel
+ objectName: "minutesLabel"
+ text: Qt.formatTime(root.time, "mm")
+ font.pixelSize: root.fontPixelSize
+ anchors.left: colonLabel.right
+ anchors.leftMargin: 4
+ anchors.verticalCenter: parent.verticalCenter
+ dim: root.hoursActive
+
+ onTapped: root.minutesSelected()
+ }
+
+ ColumnLayout {
+ id: amPmLayout
+ visible: root.showAmPm
+ // We also need to avoid the AM/PM label jumping around,
+ // so rather than anchor it to the right of the minutes label,
+ // we use colonLabel's horizontal center (which never changes), and fullTextMetrics.
+ anchors.left: colonLabel.horizontalCenter
+ anchors.leftMargin: fullTextMetrics.boundingRect.width / 2 + 12
+ anchors.verticalCenter: minutesLabel.verticalCenter
+
+ spacing: 0
+
+ ToolButton {
+ objectName: "amButton"
+ text: qsTr("AM")
+ autoExclusive: true
+
+ Material.foreground: Material.color(Material.Indigo,
+ root.am ? Material.Shade500 : Material.Shade100)
+
+ // Set the size explicitly to ensure that the buttons aren't too large.
+ // We also add 1 to the width because we want square ripple effects, not round.
+ Layout.preferredWidth: (implicitWidth * 0.7) + 1
+ Layout.preferredHeight: (implicitHeight * 0.7)
+
+ onClicked: {
+ root.am = true
+ root.amSelected()
+ }
+ }
+ ToolButton {
+ objectName: "pmButton"
+ text: qsTr("PM")
+ autoExclusive: true
+
+ Material.foreground: Material.color(Material.Indigo,
+ !root.am ? Material.Shade500 : Material.Shade100)
+
+ Layout.preferredWidth: (implicitWidth * 0.7) + 1
+ Layout.preferredHeight: (implicitHeight * 0.7)
+
+ onClicked: {
+ root.am = false
+ root.pmSelected()
+ }
+ }
+ }
+}
+//! [file]
diff --git a/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePickerMain.qml b/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePickerMain.qml
new file mode 100644
index 0000000000..c7c304613d
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-qml/time-picker/TimePickerMain.qml
@@ -0,0 +1,59 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+//! [file]
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls.Material
+
+ApplicationWindow {
+ id: window
+ width: 600
+ height: 600
+ visible: true
+ title: qsTr("Time Picker Example")
+
+ Material.theme: darkThemeSwitch.checked ? Material.Dark : Material.Light
+
+ // Shows the selected time and opens the dialog.
+ TimeComponentLabel {
+ id: openDialogLabel
+ width: parent.width - 80
+ anchors.centerIn: parent
+ font.pixelSize: Qt.application.font.pixelSize * 8
+ renderTypeQuality: Text.VeryHighRenderTypeQuality
+ interactive: !timePickerDialog.opened
+
+ text: Qt.formatTime(new Date(1970, 1, 1, timePickerDialog.hours, timePickerDialog.minutes), "hh:mm")
+
+ onTapped: timePickerDialog.openWithMode(TimePicker.Mode.Hours)
+ }
+
+ ColumnLayout {
+ // We always want the openDialogLabel to be centered in the window, not us.
+ // For that reason, we use anchors rather than putting the root items into a ColumnLayout.
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: openDialogLabel.bottom
+ anchors.topMargin: 24
+ spacing: 12
+
+ Switch {
+ id: is24HourSwitch
+ text: qsTr("24 Hour")
+ checked: timePickerDialog.is24Hour
+ }
+ Switch {
+ id: darkThemeSwitch
+ text: qsTr("Dark")
+ }
+ }
+
+ TimePickerDialog {
+ id: timePickerDialog
+ anchors.centerIn: parent
+ is24Hour: is24HourSwitch.checked
+
+ onTimeAccepted: print("A time was chosen - do something here!")
+ }
+}
+//! [file]
diff --git a/tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp b/tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp
new file mode 100644
index 0000000000..66dcb208fc
--- /dev/null
+++ b/tests/auto/quick/doc/how-tos/how-to-qml/tst_how-to-qml.cpp
@@ -0,0 +1,368 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtCore/qregularexpression.h>
+#include <QtTest/QtTest>
+#include <QtQml/qqmlapplicationengine.h>
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/private/qquickrepeater_p.h>
+#include <QtQuickTemplates2/private/qquickdialog_p.h>
+#include <QtQuickTemplates2/private/qquickdialogbuttonbox_p.h>
+#include <QtQuickTemplates2/private/qquicklabel_p.h>
+#include <QtQuickTemplates2/private/qquicktextfield_p.h>
+#include <QtQuickControlsTestUtils/private/controlstestutils_p.h>
+#include <QtQuickControlsTestUtils/private/dialogstestutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QQuickVisualTestUtils;
+using namespace QQuickControlsTestUtils;
+using namespace QQuickDialogTestUtils;
+
+// Allows us to use test macros outside of test functions.
+#define RETURN_IF_FAILED(expression) \
+expression; \
+if (QTest::currentTestFailed()) \
+ return
+
+class tst_HowToQml : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_HowToQml();
+
+private slots:
+ void init();
+ void activeFocusDebugging();
+ void timePicker();
+
+private:
+ QScopedPointer<QPointingDevice> touchScreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
+};
+
+tst_HowToQml::tst_HowToQml()
+{
+ qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+}
+
+void tst_HowToQml::init()
+{
+// QTest::failOnWarning(QRegularExpression(QStringLiteral(".?")));
+}
+
+void tst_HowToQml::activeFocusDebugging()
+{
+ QQmlApplicationEngine engine;
+ engine.loadFromModule("HowToQml", "ActiveFocusDebuggingMain");
+ QCOMPARE(engine.rootObjects().size(), 1);
+
+ auto *window = qobject_cast<QQuickWindow*>(engine.rootObjects().at(0));
+ window->show();
+ QTest::ignoreMessage(QtDebugMsg, QRegularExpression("activeFocusItem: .*\"ActiveFocusDebuggingMain\""));
+ QVERIFY(QTest::qWaitForWindowActive(window));
+
+ QTest::ignoreMessage(QtDebugMsg, QRegularExpression("activeFocusItem: .*\"textField1\""));
+ auto *textField1 = window->findChild<QQuickTextField*>("textField1");
+ QVERIFY(textField1);
+ textField1->forceActiveFocus();
+ QVERIFY(textField1->hasActiveFocus());
+
+ QTest::ignoreMessage(QtDebugMsg, QRegularExpression("activeFocusItem: .*\"textField2\""));
+ auto *textField2 = window->findChild<QQuickTextField*>("textField2");
+ QVERIFY(textField2);
+ QTest::keyClick(window, Qt::Key_Tab);
+ QVERIFY(textField2->hasActiveFocus());
+}
+
+void tst_HowToQml::timePicker()
+{
+ QQmlApplicationEngine engine;
+ engine.loadFromModule("HowToQml", "TimePickerMain");
+ QCOMPARE(engine.rootObjects().size(), 1);
+
+ auto *window = qobject_cast<QQuickWindow*>(engine.rootObjects().at(0));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ auto *dialog = window->findChild<QQuickDialog *>();
+ QVERIFY(dialog);
+
+ auto *timePicker = dialog->findChild<QQuickItem *>("timePicker");
+ QVERIFY(timePicker);
+
+ auto *contentContainer = timePicker->findChild<QQuickItem *>("contentContainer");
+ QVERIFY(contentContainer);
+ const int contentRadius = contentContainer->property("radius").toReal();
+
+ auto *labelRepeater = timePicker->findChild<QQuickRepeater *>();
+ QVERIFY(labelRepeater);
+
+ auto *selectionArm = timePicker->findChild<QQuickItem *>("selectionArm");
+ QVERIFY(selectionArm);
+
+ auto *selectionIndicator = selectionArm->findChild<QQuickItem *>("selectionIndicator");
+ QVERIFY(selectionIndicator);
+ const int selectionIndicatorHeight = selectionIndicator->height();
+
+ auto angleForValue = [](int value) -> int {
+ return int((value / 60.0) * 360) % 360;
+ };
+
+ // Note that is24HourValue should be true if "value" is a 24-hour value,
+ // not if the picker's is24Hour property is true.
+ auto labelCenterPosForValue = [&](int value, bool is24HourValue = false) -> QPoint {
+ if (value < 0 || value > 60)
+ return {};
+
+ const qreal angle = angleForValue(value);
+
+ QTransform transform;
+ // Translate to the center.
+ transform.translate(contentRadius, contentRadius);
+ // Rotate to the correct angle.
+ transform.rotate(angle);
+ // Go outward.
+ const int labelDistance = is24HourValue ? selectionIndicatorHeight * 1.5 : selectionIndicatorHeight * 0.5;
+ transform.translate(0, -contentRadius + labelDistance);
+
+ const auto centerPos = transform.map(QPoint(0, 0));
+ return centerPos;
+ };
+
+ enum Mode {
+ Hours,
+ Minutes
+ };
+
+ const int valuesPerLabelStep = 5;
+ const bool TwelveHour = false;
+ const bool TwentyFourHour = true;
+
+ // Checks that all the labels are in their expected positions and that they have the correct text.
+ auto verifyLabels = [&](Mode expectedMode, bool is24Hour, int callerLineNumber) {
+ // When not in 24 hour mode, there are always 12 labels, regardless of whether it's showing hours or minutes.
+ const int expectedLabelCount = expectedMode == Hours && is24Hour ? 24 : 12;
+ QCOMPARE(labelRepeater->count(), expectedLabelCount);
+ for (int i = 0; i < expectedLabelCount; ++i) {
+ auto *labelDelegate = labelRepeater->itemAt(i);
+ QVERIFY2(labelDelegate, qPrintable(QString::fromLatin1("Expected valid label delegate item at index %1 (caller line %2)")
+ .arg(i).arg(callerLineNumber)));
+ // Use the waiting variant of the macro because there are opacity animations.
+ // TODO: is this causing the failure on line 224?
+ QTRY_VERIFY2(qFuzzyCompare(labelDelegate->opacity(), 1.0), qPrintable(QString::fromLatin1(
+ "Expected opacity of label delegate %1 at index %2 to be 1 but it's %3 (caller line %4) - QTBUG-118056: actual label delegate at this index is now %5")
+ .arg(QDebug::toString(labelDelegate)).arg(i).arg(labelDelegate->opacity()).arg(callerLineNumber).arg(QDebug::toString(labelRepeater->itemAt(i)))));
+
+ const int expectedValue = (i * valuesPerLabelStep) % 60;
+ const int actualValue = labelDelegate->property("value").toInt();
+ QVERIFY2(expectedValue == actualValue, qPrintable(QString::fromLatin1(
+ "Expected label's value at index %1 to be %2 but it's %3 (caller line %4)")
+ .arg(i).arg(expectedValue).arg(actualValue).arg(callerLineNumber)));
+
+ const QString expectedText = QString::number(expectedMode == Hours
+ ? (i == 0 ? 12 : (i == 12 ? 0 : i)) : i * valuesPerLabelStep);
+ // Use QTRY_VERIFY2 rather than QVERIFY2, because text changes are animated.
+ QTRY_VERIFY2(expectedText == labelDelegate->property("text").toString(), qPrintable(QString::fromLatin1(
+ "Expected label's text at index %1 to be %2 but it's %3 (caller line %4)").arg(i)
+ .arg(expectedText, labelDelegate->property("text").toString(), QString::number(callerLineNumber))));
+ }
+ };
+
+ auto verifySelectionIndicator = [&](int expectedValue, bool expect24HourValue, int callerLineNumber) {
+ const qreal actualRotation = int(selectionArm->rotation()) % 360;
+ const qreal expectedRotation = angleForValue(expectedValue);
+ QVERIFY2(qFuzzyCompare(actualRotation, expectedRotation), qPrintable(QString::fromLatin1(
+ "Expected selection arm's rotation to be %1 for expectedValue %2 but it's %3 (caller line %4)")
+ .arg(expectedRotation).arg(expectedValue).arg(actualRotation).arg(callerLineNumber)));
+
+ const QPoint expectedIndicatorCenterPos = labelCenterPosForValue(expectedValue, expect24HourValue);
+ const QPoint actualIndicatorCenterPos = selectionIndicator->mapToItem(
+ contentContainer, selectionIndicator->boundingRect().center().toPoint()).toPoint();
+ const QPoint difference = actualIndicatorCenterPos - expectedIndicatorCenterPos;
+ QVERIFY2(difference.x() <= 2 && difference.y() <= 2, qPrintable(QString::fromLatin1(
+ "Expected selection indicator's center position to be %1 (with 2 pixels of tolerance) but it's %2 (caller line %3)")
+ .arg(QDebug::toString(expectedIndicatorCenterPos), QDebug::toString(actualIndicatorCenterPos)).arg(callerLineNumber)));
+ };
+
+ auto valueForHour = [&](int hour) {
+ return (hour * valuesPerLabelStep) % 60;
+ };
+
+ // Open the picker to hours mode by clicking on the label.
+ auto *openDialogLabel = window->findChild<QQuickLabel *>(QString(), Qt::FindDirectChildrenOnly);
+ QVERIFY(openDialogLabel);
+ QCOMPARE(openDialogLabel->text(), "12:00");
+ QTest::touchEvent(window, touchScreen.data()).press(0, mapCenterToWindow(openDialogLabel));
+ QTest::touchEvent(window, touchScreen.data()).release(0, mapCenterToWindow(openDialogLabel));
+ QTRY_COMPARE(dialog->property("opened").toBool(), true);
+ // It should show hours.
+ RETURN_IF_FAILED(verifyLabels(Hours, TwelveHour, __LINE__));
+ RETURN_IF_FAILED(verifySelectionIndicator(0, TwelveHour, __LINE__));
+
+ // Select the 3rd hour.
+ const QPoint thirdHourPos = labelCenterPosForValue(valueForHour(3));
+ QTest::touchEvent(window, touchScreen.data()).press(0, mapToWindow(contentContainer, thirdHourPos));
+ RETURN_IF_FAILED(verifySelectionIndicator(valueForHour(3), TwelveHour, __LINE__));
+ QCOMPARE(timePicker->property("mode").toInt(), Hours);
+ QTest::touchEvent(window, touchScreen.data()).release(0, mapToWindow(contentContainer, thirdHourPos));
+ QCOMPARE(timePicker->property("hours").toInt(), 3);
+ QCOMPARE(timePicker->property("minutes").toInt(), 0);
+ // The dialog's values shouldn't change until the dialog has been accepted.
+ QCOMPARE(dialog->property("hours").toInt(), 12);
+ QCOMPARE(dialog->property("minutes").toInt(), 0);
+ // It should be showing minutes now.
+ QCOMPARE(timePicker->property("mode").toInt(), Minutes);
+ RETURN_IF_FAILED(verifyLabels(Minutes, TwelveHour, __LINE__));
+ RETURN_IF_FAILED(verifySelectionIndicator(0, TwelveHour, __LINE__));
+ auto *minutesLabel = dialog->findChild<QQuickLabel *>("minutesLabel");
+ QVERIFY(minutesLabel);
+ QCOMPARE(minutesLabel->property("dim").toBool(), false);
+
+ // Select the 59th minute.
+ const QPoint fiftyNinthMinutePos = labelCenterPosForValue(59);
+ QTest::touchEvent(window, touchScreen.data()).press(0, mapToWindow(contentContainer, fiftyNinthMinutePos));
+ RETURN_IF_FAILED(verifySelectionIndicator(59, TwelveHour, __LINE__));
+ QTest::touchEvent(window, touchScreen.data()).release(0, mapToWindow(contentContainer, fiftyNinthMinutePos));
+ QCOMPARE(timePicker->property("hours").toInt(), 3);
+ QCOMPARE(timePicker->property("minutes").toInt(), 59);
+ QCOMPARE(dialog->property("hours").toInt(), 12);
+ QCOMPARE(dialog->property("minutes").toInt(), 0);
+ // It shouldn't be closed until the OK or Cancel buttons are clicked.
+ QCOMPARE(dialog->property("opened").toBool(), true);
+
+ // Accept the dialog to make the changes.
+ auto *dialogButtonBox = qobject_cast<QQuickDialogButtonBox *>(dialog->footer());
+ QVERIFY(dialogButtonBox);
+ auto *okButton = findDialogButton(dialogButtonBox, "OK");
+ QTest::ignoreMessage(QtDebugMsg, "A time was chosen - do something here!");
+ QVERIFY(clickButton(okButton));
+ QTRY_COMPARE(dialog->property("visible").toBool(), false);
+ QCOMPARE(dialog->property("hours").toInt(), 3);
+ QCOMPARE(dialog->property("minutes").toInt(), 59);
+ QCOMPARE(openDialogLabel->text(), "03:59");
+
+ // Open it again.
+ QTest::touchEvent(window, touchScreen.data()).press(0, mapCenterToWindow(openDialogLabel));
+ QTest::touchEvent(window, touchScreen.data()).release(0, mapCenterToWindow(openDialogLabel));
+ QTRY_COMPARE(dialog->property("opened"), true);
+ RETURN_IF_FAILED(verifyLabels(Hours, TwelveHour, __LINE__));
+ RETURN_IF_FAILED(verifySelectionIndicator(valueForHour(3), TwelveHour, __LINE__));
+ // The time label should be unchanged.
+ QCOMPARE(openDialogLabel->text(), "03:59");
+
+ // Switch from hours to minutes by clicking on the minutes label.
+ QTest::touchEvent(window, touchScreen.data()).press(0, mapCenterToWindow(minutesLabel));
+ QTest::touchEvent(window, touchScreen.data()).release(0, mapCenterToWindow(minutesLabel));
+ RETURN_IF_FAILED(verifyLabels(Minutes, TwelveHour, __LINE__));
+ RETURN_IF_FAILED(verifySelectionIndicator(59, TwelveHour, __LINE__));
+
+ // Select the 1st minute.
+ const QPoint firstMinutePos = labelCenterPosForValue(1);
+ QTest::touchEvent(window, touchScreen.data()).press(0, mapToWindow(contentContainer, firstMinutePos));
+ RETURN_IF_FAILED(verifySelectionIndicator(1, TwelveHour, __LINE__));
+ QTest::touchEvent(window, touchScreen.data()).release(0, mapToWindow(contentContainer, firstMinutePos));
+ QCOMPARE(timePicker->property("hours").toInt(), 3);
+ QCOMPARE(timePicker->property("minutes").toInt(), 1);
+ // It shouldn't be closed until the OK or Cancel buttons are clicked.
+ QCOMPARE(dialog->property("opened").toBool(), true);
+
+ // Accept the dialog to make the changes.
+ QTest::ignoreMessage(QtDebugMsg, "A time was chosen - do something here!");
+ QVERIFY(clickButton(okButton));
+ QTRY_COMPARE(dialog->property("visible").toBool(), false);
+ QCOMPARE(dialog->property("hours").toInt(), 3);
+ QCOMPARE(dialog->property("minutes").toInt(), 1);
+ QCOMPARE(openDialogLabel->text(), "03:01");
+
+ // Check that hours and minutes set programmatically on the picker and dialog are respected.
+ QVERIFY(dialog->setProperty("hours", QVariant::fromValue(7)));
+ QVERIFY(dialog->setProperty("minutes", QVariant::fromValue(8)));
+ QCOMPARE(openDialogLabel->text(), "07:08");
+ // Open the picker to hours mode by clicking on the label.
+ QTest::touchEvent(window, touchScreen.data()).press(0, mapCenterToWindow(openDialogLabel));
+ QTest::touchEvent(window, touchScreen.data()).release(0, mapCenterToWindow(openDialogLabel));
+ QTRY_COMPARE(dialog->property("opened").toBool(), true);
+ RETURN_IF_FAILED(verifyLabels(Hours, TwelveHour, __LINE__));
+ RETURN_IF_FAILED(verifySelectionIndicator(valueForHour(7), TwelveHour, __LINE__));
+ QCOMPARE(timePicker->property("hours").toInt(), 7);
+ QCOMPARE(timePicker->property("minutes").toInt(), 8);
+
+ // Check that cancelling the dialog cancels any changes.
+ // Select the fourth hour.
+ const QPoint fourthHourPos = labelCenterPosForValue(20);
+ QTest::touchEvent(window, touchScreen.data()).press(0, mapToWindow(contentContainer, fourthHourPos));
+ RETURN_IF_FAILED(verifySelectionIndicator(valueForHour(4), TwelveHour, __LINE__));
+ QTest::touchEvent(window, touchScreen.data()).release(0, mapToWindow(contentContainer, fourthHourPos));
+ QCOMPARE(timePicker->property("hours").toInt(), 4);
+ QCOMPARE(timePicker->property("minutes").toInt(), 8);
+ auto *cancelButton = findDialogButton(dialogButtonBox, "Cancel");
+ QVERIFY(clickButton(cancelButton));
+ QTRY_COMPARE(dialog->property("visible").toBool(), false);
+ QCOMPARE(dialog->property("hours").toInt(), 7);
+ QCOMPARE(dialog->property("minutes").toInt(), 8);
+
+ // Test that the 24 hour mode works.
+ const bool isCi = qgetenv("QTEST_ENVIRONMENT") == "ci"; // QTBUG-122679
+ if (isCi)
+ qDebug() << "about to set is24hour to true";
+ QVERIFY(dialog->setProperty("is24Hour", QVariant::fromValue(true)));
+ if (isCi)
+ qDebug() << "about to open picker";
+ QTest::touchEvent(window, touchScreen.data()).press(0, mapCenterToWindow(openDialogLabel));
+ QTest::touchEvent(window, touchScreen.data()).release(0, mapCenterToWindow(openDialogLabel));
+ QTRY_COMPARE(dialog->property("opened").toBool(), true);
+ QCOMPARE(timePicker->property("mode").toInt(), Hours);
+ if (isCi)
+ qDebug() << "about to verify labels after switching to 24hr";
+ RETURN_IF_FAILED(verifyLabels(Hours, TwentyFourHour, __LINE__));
+ // TwelveHour because the selected value (7) is on the 12 hour "ring".
+ RETURN_IF_FAILED(verifySelectionIndicator(valueForHour(7), TwelveHour, __LINE__));
+ // It should still show the old time.
+ QCOMPARE(timePicker->property("hours").toInt(), 7);
+ QCOMPARE(timePicker->property("minutes").toInt(), 8);
+ QCOMPARE(dialog->property("hours").toInt(), 7);
+ QCOMPARE(dialog->property("minutes").toInt(), 8);
+
+ // Select the 23rd hour.
+ const QPoint twentyThirdHourPos = labelCenterPosForValue(valueForHour(11), TwentyFourHour);
+ QTest::touchEvent(window, touchScreen.data()).press(0, mapToWindow(contentContainer, twentyThirdHourPos));
+ RETURN_IF_FAILED(verifySelectionIndicator(valueForHour(23), TwentyFourHour, __LINE__));
+ QTest::touchEvent(window, touchScreen.data()).release(0, mapToWindow(contentContainer, twentyThirdHourPos));
+ QCOMPARE(timePicker->property("hours").toInt(), 23);
+ QCOMPARE(timePicker->property("minutes").toInt(), 8);
+ QCOMPARE(dialog->property("hours").toInt(), 7);
+ QCOMPARE(dialog->property("minutes").toInt(), 8);
+ RETURN_IF_FAILED(verifyLabels(Minutes, TwentyFourHour, __LINE__));
+ RETURN_IF_FAILED(verifySelectionIndicator(8, TwelveHour, __LINE__));
+
+ // Select the 20th minute.
+ const QPoint twentiethMinutePos = labelCenterPosForValue(20);
+ QTest::touchEvent(window, touchScreen.data()).press(0, mapToWindow(contentContainer, twentiethMinutePos));
+ RETURN_IF_FAILED(verifySelectionIndicator(20, TwelveHour, __LINE__));
+ QTest::touchEvent(window, touchScreen.data()).release(0, mapToWindow(contentContainer, twentiethMinutePos));
+ QCOMPARE(timePicker->property("hours").toInt(), 23);
+ QCOMPARE(timePicker->property("minutes").toInt(), 20);
+
+ // Go back to hours and make sure that the selection indicator is correct.
+ auto *hoursLabel = dialog->findChild<QQuickLabel *>("hoursLabel");
+ QVERIFY(hoursLabel);
+ QTest::touchEvent(window, touchScreen.data()).press(0, mapCenterToWindow(hoursLabel));
+ QTest::touchEvent(window, touchScreen.data()).release(0, mapCenterToWindow(hoursLabel));
+ RETURN_IF_FAILED(verifyLabels(Hours, TwentyFourHour, __LINE__));
+ RETURN_IF_FAILED(verifySelectionIndicator(valueForHour(23), TwentyFourHour, __LINE__));
+
+ // Accept.
+ QTest::ignoreMessage(QtDebugMsg, "A time was chosen - do something here!");
+ QVERIFY(clickButton(okButton));
+ QTRY_COMPARE(dialog->property("visible").toBool(), false);
+ QCOMPARE(dialog->property("hours").toInt(), 23);
+ QCOMPARE(dialog->property("minutes").toInt(), 20);
+}
+
+QT_END_NAMESPACE
+
+QTEST_MAIN(tst_HowToQml)
+
+#include "tst_how-to-qml.moc"
diff --git a/tests/auto/quick/drawingmodes/BLACKLIST b/tests/auto/quick/drawingmodes/BLACKLIST
new file mode 100644
index 0000000000..2a7a12b995
--- /dev/null
+++ b/tests/auto/quick/drawingmodes/BLACKLIST
@@ -0,0 +1,11 @@
+# QTBUG-102447
+[points]
+android
+[lines]
+android
+[lineStrip]
+android
+[triangles]
+android
+[triangleStrip]
+android
diff --git a/tests/auto/quick/drawingmodes/CMakeLists.txt b/tests/auto/quick/drawingmodes/CMakeLists.txt
index f7bf15f49f..09f53f1037 100644
--- a/tests/auto/quick/drawingmodes/CMakeLists.txt
+++ b/tests/auto/quick/drawingmodes/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from drawingmodes.pro.
#####################################################################
## tst_drawingmodes Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_drawingmodes LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,16 +21,12 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_drawingmodes
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_drawingmodes.cpp
- DEFINES
- QT_DISABLE_DEPRECATED_BEFORE=0
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Qml
Qt::Quick
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -33,10 +38,10 @@ qt_internal_add_test(tst_drawingmodes
qt_internal_extend_target(tst_drawingmodes CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_drawingmodes CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp b/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp
index e982410f89..a68be8a745 100644
--- a/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp
+++ b/tests/auto/quick/drawingmodes/tst_drawingmodes.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
@@ -34,9 +9,8 @@
#include <QtQuick/qsggeometry.h>
#include <QtQuick/qsgflatcolormaterial.h>
#include <QtGui/qscreen.h>
-#include <qopenglcontext.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
class tst_drawingmodes : public QQmlDataTest
{
@@ -78,7 +52,7 @@ class DrawingModeItem : public QQuickItem
{
Q_OBJECT
public:
- static GLenum drawingMode;
+ static QSGGeometry::DrawingMode drawingMode;
DrawingModeItem() : first(QSGGeometry::defaultAttributes_Point2D(), 5),
second(QSGGeometry::defaultAttributes_Point2D(), 5)
@@ -92,7 +66,7 @@ protected:
QSGGeometry second;
QSGFlatColorMaterial material;
- virtual QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
+ QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override
{
if (!node) {
QRect bounds(0, 0, 200, 200);
@@ -127,7 +101,7 @@ protected:
}
};
-GLenum DrawingModeItem::drawingMode;
+QSGGeometry::DrawingMode DrawingModeItem::drawingMode;
bool tst_drawingmodes::hasPixelAround(const QImage &fb, int centerX, int centerY) {
for (int x = centerX - 2; x <= centerX + 2; ++x) {
@@ -139,7 +113,10 @@ bool tst_drawingmodes::hasPixelAround(const QImage &fb, int centerX, int centerY
return false;
}
-tst_drawingmodes::tst_drawingmodes() : black(qRgb(0, 0, 0)), red(qRgb(0xff, 0, 0))
+tst_drawingmodes::tst_drawingmodes()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+ , black(qRgb(0, 0, 0))
+ , red(qRgb(0xff, 0, 0))
{
qmlRegisterType<DrawingModeItem>("Test", 1, 0, "DrawingModeItem");
outerWindow.showNormal();
@@ -148,7 +125,7 @@ tst_drawingmodes::tst_drawingmodes() : black(qRgb(0, 0, 0)), red(qRgb(0xff, 0, 0
void tst_drawingmodes::points()
{
- DrawingModeItem::drawingMode = GL_POINTS;
+ DrawingModeItem::drawingMode = QSGGeometry::DrawPoints;
if (QGuiApplication::primaryScreen()->depth() < 24)
QSKIP("This test does not work at display depths < 24");
@@ -156,9 +133,8 @@ void tst_drawingmodes::points()
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
-#ifdef Q_OS_WIN
- if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES)
- QSKIP("ANGLE cannot draw GL_POINTS.");
+#if QT_CONFIG(metal)
+ QSKIP("Skipping points test due to unexpected failures in M1 CI VM");
#endif
QImage fb = runTest("DrawingModes.qml");
@@ -191,7 +167,7 @@ void tst_drawingmodes::points()
void tst_drawingmodes::lines()
{
- DrawingModeItem::drawingMode = GL_LINES;
+ DrawingModeItem::drawingMode = QSGGeometry::DrawLines;
if (QGuiApplication::primaryScreen()->depth() < 24)
QSKIP("This test does not work at display depths < 24");
@@ -222,7 +198,7 @@ void tst_drawingmodes::lines()
void tst_drawingmodes::lineStrip()
{
- DrawingModeItem::drawingMode = GL_LINE_STRIP;
+ DrawingModeItem::drawingMode = QSGGeometry::DrawLineStrip;
if (QGuiApplication::primaryScreen()->depth() < 24)
QSKIP("This test does not work at display depths < 24");
@@ -255,7 +231,7 @@ void tst_drawingmodes::lineStrip()
void tst_drawingmodes::lineLoop()
{
- DrawingModeItem::drawingMode = GL_LINE_LOOP;
+ DrawingModeItem::drawingMode = QSGGeometry::DrawLineLoop;
if (QGuiApplication::primaryScreen()->depth() < 24)
QSKIP("This test does not work at display depths < 24");
@@ -291,7 +267,7 @@ void tst_drawingmodes::lineLoop()
void tst_drawingmodes::triangles()
{
- DrawingModeItem::drawingMode = GL_TRIANGLES;
+ DrawingModeItem::drawingMode = QSGGeometry::DrawTriangles;
if (QGuiApplication::primaryScreen()->depth() < 24)
QSKIP("This test does not work at display depths < 24");
@@ -320,7 +296,7 @@ void tst_drawingmodes::triangles()
void tst_drawingmodes::triangleStrip()
{
- DrawingModeItem::drawingMode = GL_TRIANGLE_STRIP;
+ DrawingModeItem::drawingMode = QSGGeometry::DrawTriangleStrip;
if (QGuiApplication::primaryScreen()->depth() < 24)
QSKIP("This test does not work at display depths < 24");
@@ -348,7 +324,7 @@ void tst_drawingmodes::triangleStrip()
void tst_drawingmodes::triangleFan()
{
- DrawingModeItem::drawingMode = GL_TRIANGLE_FAN;
+ DrawingModeItem::drawingMode = QSGGeometry::DrawTriangleFan;
if (QGuiApplication::primaryScreen()->depth() < 24)
QSKIP("This test does not work at display depths < 24");
diff --git a/tests/auto/quick/examples/CMakeLists.txt b/tests/auto/quick/examples/CMakeLists.txt
index 5bcaa3f93a..74fe0fba51 100644
--- a/tests/auto/quick/examples/CMakeLists.txt
+++ b/tests/auto/quick/examples/CMakeLists.txt
@@ -1,15 +1,24 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
# Generated from examples.pro.
#####################################################################
## tst_examples Test:
#####################################################################
-qt_internal_add_test(tst_examples
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_quick_examples LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_quick_examples
SOURCES
tst_examples.cpp
DEFINES
- SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\"
- PUBLIC_LIBRARIES
+ SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}"
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/quick/examples/tst_examples.cpp b/tests/auto/quick/examples/tst_examples.cpp
index dca5c1c3fd..4962f6b759 100644
--- a/tests/auto/quick/examples/tst_examples.cpp
+++ b/tests/auto/quick/examples/tst_examples.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QLibraryInfo>
@@ -54,10 +29,10 @@ private slots:
void init();
void cleanup();
- void sgexamples_data();
- void sgexamples();
- void sgsnippets_data();
- void sgsnippets();
+ void examples_data();
+ void examples();
+ void snippets_data();
+ void snippets();
void namingConvention();
private:
@@ -79,23 +54,23 @@ tst_examples::tst_examples()
// Add directories you want excluded here
excludedDirs << "shared"; //Not an example
excludedDirs << "snippets/qml/path"; //No root QQuickItem
- excludedDirs << "examples/qml/qmlextensionplugins"; //Requires special import search path
// These snippets are not expected to run on their own.
excludedDirs << "snippets/qml/visualdatamodel_rootindex";
excludedDirs << "snippets/qml/qtbinding";
excludedDirs << "snippets/qml/imports";
+ excludedDirs << "examples/quickcontrols/imagine";
+ excludedDirs << "examples/quickcontrols/texteditor";
+ excludedDirs << "examples/quickcontrols/ios/todolist"; // Must be run via executable.
excludedFiles << "snippets/qml/image-ext.qml";
excludedFiles << "examples/quick/shapes/content/main.qml"; // relies on resources
excludedFiles << "examples/quick/shapes/content/interactive.qml"; // relies on resources
#if !QT_CONFIG(opengl)
//No support for Particles
- excludedFiles << "examples/qml/dynamicscene/dynamicscene.qml";
excludedFiles << "examples/quick/animation/basics/color-animation.qml";
excludedFiles << "examples/quick/particles/affectors/content/age.qml";
- excludedFiles << "examples/quick/touchinteraction/multipointtouch/bearwhack.qml";
- excludedFiles << "examples/quick/touchinteraction/multipointtouch/multiflame.qml";
+ excludedFiles << "examples/quick/pointerhandlers/multiflame.qml";
excludedDirs << "examples/quick/particles";
// No Support for ShaderEffect
excludedFiles << "src/quick/doc/snippets/qml/animators.qml";
@@ -109,13 +84,13 @@ tst_examples::~tst_examples()
void tst_examples::init()
{
- if (!qstrcmp(QTest::currentTestFunction(), "sgsnippets"))
+ if (!qstrcmp(QTest::currentTestFunction(), "snippets"))
testlibMsgHandler = qInstallMessageHandler(msgHandlerFilter);
}
void tst_examples::cleanup()
{
- if (!qstrcmp(QTest::currentTestFunction(), "sgsnippets"))
+ if (!qstrcmp(QTest::currentTestFunction(), "snippets"))
qInstallMessageHandler(testlibMsgHandler);
}
@@ -125,27 +100,25 @@ to have them tested by the examples() test.
*/
void tst_examples::namingConvention(const QDir &d)
{
- for (int ii = 0; ii < excludedDirs.count(); ++ii) {
+ for (int ii = 0; ii < excludedDirs.size(); ++ii) {
QString s = excludedDirs.at(ii);
if (d.absolutePath().endsWith(s))
return;
}
- QStringList files = d.entryList(QStringList() << QLatin1String("*.qml"),
- QDir::Files);
+ const QStringList files = d.entryList(QStringList() << QLatin1String("*.qml"), QDir::Files);
bool seenQml = !files.isEmpty();
bool seenLowercase = false;
- foreach (const QString &file, files) {
+ for (const QString &file : files) {
if (file.at(0).isLower())
seenLowercase = true;
}
if (!seenQml) {
- QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot |
- QDir::NoSymLinks);
- foreach (const QString &dir, dirs) {
+ const QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
+ for (const QString &dir : dirs) {
QDir sub = d;
sub.cd(dir);
namingConvention(sub);
@@ -166,11 +139,12 @@ void tst_examples::namingConvention(const QDir &d)
void tst_examples::namingConvention()
{
- QStringList examplesLocations;
- examplesLocations << QLibraryInfo::path(QLibraryInfo::ExamplesPath) + QLatin1String("/qml");
- examplesLocations << QLibraryInfo::path(QLibraryInfo::ExamplesPath) + QLatin1String("/quick");
+ const QStringList examplesLocations = {
+ QLibraryInfo::path(QLibraryInfo::ExamplesPath) + QLatin1String("/qml"),
+ QLibraryInfo::path(QLibraryInfo::ExamplesPath) + QLatin1String("/quick")
+ };
- foreach(const QString &examples, examplesLocations) {
+ for (const QString &examples : examplesLocations) {
QDir d(examples);
if (d.exists())
namingConvention(d);
@@ -179,7 +153,7 @@ void tst_examples::namingConvention()
QStringList tst_examples::findQmlFiles(const QDir &d)
{
- for (int ii = 0; ii < excludedDirs.count(); ++ii) {
+ for (int ii = 0; ii < excludedDirs.size(); ++ii) {
QString s = excludedDirs.at(ii);
if (d.absolutePath().endsWith(s))
return QStringList();
@@ -189,12 +163,11 @@ QStringList tst_examples::findQmlFiles(const QDir &d)
QStringList cppfiles = d.entryList(QStringList() << QLatin1String("*.cpp"), QDir::Files);
if (cppfiles.isEmpty()) {
- QStringList files = d.entryList(QStringList() << QLatin1String("*.qml"),
- QDir::Files);
- foreach (const QString &file, files) {
+ const QStringList files = d.entryList(QStringList() << QLatin1String("*.qml"), QDir::Files);
+ for (const QString &file : files) {
if (file.at(0).isLower()) {
bool superContinue = false;
- for (int ii = 0; ii < excludedFiles.count(); ++ii) {
+ for (int ii = 0; ii < excludedFiles.size(); ++ii) {
QString e = excludedFiles.at(ii);
if (d.absoluteFilePath(file).endsWith(e)) {
superContinue = true;
@@ -209,9 +182,8 @@ QStringList tst_examples::findQmlFiles(const QDir &d)
}
- QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot |
- QDir::NoSymLinks);
- foreach (const QString &dir, dirs) {
+ const QStringList dirs = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
+ for (const QString &dir : dirs) {
QDir sub = d;
sub.cd(dir);
rv << findQmlFiles(sub);
@@ -227,20 +199,29 @@ that they start and exit cleanly.
Examples are any .qml files under the examples/ directory that start
with a lower case letter.
*/
-void tst_examples::sgexamples_data()
+void tst_examples::examples_data()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("tst_examples::examples_data needs adaptions for Android, QTBUG-102858.");
+#endif
QTest::addColumn<QString>("file");
- QString examples = QLatin1String(SRCDIR) + "/../../../../examples/";
+ const QDir repoSourceDir(QLatin1String(SRCDIR) + "/../../../..");
+ QVERIFY2(repoSourceDir.exists(), qPrintable(
+ QString::fromLatin1("repoSourceDir %1 doesn't exist").arg(repoSourceDir.path())));
+
+ const QDir examplesDir(repoSourceDir.path() + "/examples");
+ QVERIFY2(examplesDir.exists(), qPrintable(
+ QStringLiteral("examplesDir %1 doesn't exist").arg(examplesDir.path())));
QStringList files;
- files << findQmlFiles(QDir(examples));
+ files << findQmlFiles(examplesDir);
- foreach (const QString &file, files)
- QTest::newRow(qPrintable(file)) << file;
+ for (const QString &file : std::as_const(files))
+ QTest::newRow(qPrintable(repoSourceDir.relativeFilePath(file))) << file;
}
-void tst_examples::sgexamples()
+void tst_examples::examples()
{
QFETCH(QString, file);
QQuickWindow window;
@@ -268,24 +249,39 @@ void tst_examples::sgexamples()
qApp->processEvents();
}
-void tst_examples::sgsnippets_data()
+void tst_examples::snippets_data()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("tst_examples::snippets_data needs adaptions for Android, QTBUG-102858.");
+#endif
QTest::addColumn<QString>("file");
- QString snippets = QLatin1String(SRCDIR) + "/../../../../src/qml/doc/snippets/qml";
+ // Add QML snippets.
+ const QDir repoSourceDir(QLatin1String(SRCDIR) + "/../../../..");
+ QVERIFY2(repoSourceDir.exists(), qPrintable(
+ QStringLiteral("repoSourceDir %1 doesn't exist").arg(repoSourceDir.path())));
+
+ QDir snippetsDir(repoSourceDir.path() + "/src/qml/doc/snippets/qml");
+ QVERIFY2(snippetsDir.exists(), qPrintable(
+ QStringLiteral("qml snippetsDir %1 doesn't exist").arg(snippetsDir.path())));
+
QStringList files;
- files << findQmlFiles(QDir(snippets));
- foreach (const QString &file, files)
- QTest::newRow(qPrintable(file)) << file;
+ files << findQmlFiles(snippetsDir);
+ for (const QString &file : std::as_const(files))
+ QTest::newRow(qPrintable(repoSourceDir.relativeFilePath(file))) << file;
+
+ // Add Quick snippets.
+ snippetsDir = QDir(repoSourceDir.path() + "/src/quick/doc/snippets/qml");
+ QVERIFY2(snippetsDir.exists(), qPrintable(
+ QStringLiteral("quick snippetsDir %1 doesn't exist").arg(snippetsDir.path())));
- snippets = QLatin1String(SRCDIR) + "/../../../../src/quick/doc/snippets/qml";
files.clear();
- files << findQmlFiles(QDir(snippets));
- foreach (const QString &file, files)
- QTest::newRow(qPrintable(file)) << file;
+ files << findQmlFiles(snippetsDir);
+ for (const QString &file : std::as_const(files))
+ QTest::newRow(qPrintable(repoSourceDir.relativeFilePath(file))) << file;
}
-void tst_examples::sgsnippets()
+void tst_examples::snippets()
{
QFETCH(QString, file);
@@ -300,7 +296,7 @@ void tst_examples::sgsnippets()
QQuickItem *root = qobject_cast<QQuickItem *>(object.data());
if (!root && !window) {
component.completeCreate();
- QVERIFY(false);
+ QFAIL("No root and no window");
}
if (!window)
window = new QQuickWindow;
diff --git a/tests/auto/quick/geometry/CMakeLists.txt b/tests/auto/quick/geometry/CMakeLists.txt
index 1c729527fe..8231608a7f 100644
--- a/tests/auto/quick/geometry/CMakeLists.txt
+++ b/tests/auto/quick/geometry/CMakeLists.txt
@@ -1,13 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from geometry.pro.
#####################################################################
## tst_geometry Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_geometry LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_geometry
SOURCES
tst_geometry.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/quick/geometry/tst_geometry.cpp b/tests/auto/quick/geometry/tst_geometry.cpp
index 54de46276c..f3034977e5 100644
--- a/tests/auto/quick/geometry/tst_geometry.cpp
+++ b/tests/auto/quick/geometry/tst_geometry.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt scene graph research project.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QString>
#include <QtTest/QtTest>
diff --git a/tests/auto/quick/nodes/CMakeLists.txt b/tests/auto/quick/nodes/CMakeLists.txt
index 9b85a9fb7b..415179b79d 100644
--- a/tests/auto/quick/nodes/CMakeLists.txt
+++ b/tests/auto/quick/nodes/CMakeLists.txt
@@ -1,13 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from nodes.pro.
#####################################################################
## tst_nodestest Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_nodestest LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_nodestest
SOURCES
tst_nodestest.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/quick/nodes/tst_nodestest.cpp b/tests/auto/quick/nodes/tst_nodestest.cpp
index fa53ebfa02..d91654a6f6 100644
--- a/tests/auto/quick/nodes/tst_nodestest.cpp
+++ b/tests/auto/quick/nodes/tst_nodestest.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QString>
#include <QtTest/QtTest>
@@ -43,28 +18,23 @@
#include <QtGui/qpa/qplatformintegration.h>
#include <QtGui/qoffscreensurface.h>
-#include <QtGui/private/qrhi_p.h>
-#include <QtGui/private/qrhinull_p.h>
+#include <rhi/qrhi.h>
#if QT_CONFIG(opengl)
# include <QOpenGLContext>
-# include <QtGui/private/qrhigles2_p.h>
# define TST_GL
#endif
#if QT_CONFIG(vulkan)
# include <QVulkanInstance>
-# include <QtGui/private/qrhivulkan_p.h>
# define TST_VK
#endif
#ifdef Q_OS_WIN
-#include <QtGui/private/qrhid3d11_p.h>
# define TST_D3D11
#endif
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
-# include <QtGui/private/qrhimetal_p.h>
+#if QT_CONFIG(metal)
# define TST_MTL
#endif
@@ -83,7 +53,7 @@ public:
NodesTest();
private Q_SLOTS:
- void initTestCase() override;
+ void initTestCase();
void cleanupTestCase();
// Root nodes
@@ -109,8 +79,6 @@ private Q_SLOTS:
private:
void rhiTestData();
- QOffscreenSurface *surface = nullptr;
- QOpenGLContext *context = nullptr;
QSGDefaultRenderContext *renderContext = nullptr;
struct {
@@ -172,12 +140,12 @@ public:
setRootNode(root);
}
- void render() {
+ void render() override {
++renderCount;
renderingOrder = ++globalRendereringOrder;
}
- void nodeChanged(QSGNode *node, QSGNode::DirtyState state) {
+ void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override {
changedNode = node;
changedState = state;
QSGBatchRenderer::Renderer::nodeChanged(node, state);
diff --git a/tests/auto/quick/nokeywords/CMakeLists.txt b/tests/auto/quick/nokeywords/CMakeLists.txt
index 682ab8aa9c..44e371ab3a 100644
--- a/tests/auto/quick/nokeywords/CMakeLists.txt
+++ b/tests/auto/quick/nokeywords/CMakeLists.txt
@@ -1,13 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from nokeywords.pro.
#####################################################################
## tst_nokeywords Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_nokeywords LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_nokeywords
SOURCES
tst_nokeywords.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/quick/nokeywords/tst_nokeywords.cpp b/tests/auto/quick/nokeywords/tst_nokeywords.cpp
index 79b57c9d1c..190c9fac34 100644
--- a/tests/auto/quick/nokeywords/tst_nokeywords.cpp
+++ b/tests/auto/quick/nokeywords/tst_nokeywords.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#define QT_NO_KEYWORDS
#undef signals
diff --git a/tests/auto/quick/pointerhandlers/CMakeLists.txt b/tests/auto/quick/pointerhandlers/CMakeLists.txt
index f8ac22d531..fcd00cddc6 100644
--- a/tests/auto/quick/pointerhandlers/CMakeLists.txt
+++ b/tests/auto/quick/pointerhandlers/CMakeLists.txt
@@ -1,3 +1,6 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from pointerhandlers.pro.
if(QT_FEATURE_private_tests)
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST b/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST
index 47c11f14d8..f5259a9e64 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/BLACKLIST
@@ -5,7 +5,23 @@ opensuse-leap
windows gcc
[touchDragFlickableBehindButton]
windows gcc
+# QTBUG-95887
+[mouseDragSlider]
+opensuse-leap
+# QTBUG-95887
+[touchDragFlickableBehindButton]
+opensuse-leap
+# QTBUG-95887
+[mouseClickButton]
+opensuse-leap
+# QTBUG-95887
+[mouseDragFlickableBehindSlider]
+opensuse-leap
+# QTBUG-103061
+[touchDragFlickableBehindItemWithHandlers]
+android
+[mouseDragFlickableBehindItemWithHandlers]
+android
[touchAndDragHandlerOnFlickable]
-macos # QTBUG-86729
-[touchDragSliderAndFlickable]
-* # QTBUG-86729
+android
+
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/CMakeLists.txt b/tests/auto/quick/pointerhandlers/flickableinterop/CMakeLists.txt
index f67f9a0a59..3836aefbb2 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/CMakeLists.txt
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from flickableinterop.pro.
#####################################################################
## tst_flickableinterop Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_flickableinterop LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_flickableinterop
SOURCES
- ../../../shared/util.cpp ../../../shared/util.h
- ../../shared/geometrytestutil.cpp ../../shared/geometrytestutil.h
- ../../shared/viewtestutil.cpp ../../shared/viewtestutil.h
- ../../shared/visualtestutil.cpp ../../shared/visualtestutil.h
tst_flickableinterop.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -38,10 +40,10 @@ qt_internal_add_test(tst_flickableinterop
qt_internal_extend_target(tst_flickableinterop CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_flickableinterop CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml
index 4b2935b52e..9483a12d1c 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/FlashAnimation.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the manual tests of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/GrooveDragSlider.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/GrooveDragSlider.qml
index 7a32170bed..ec790c9b99 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/data/GrooveDragSlider.qml
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/GrooveDragSlider.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/KnobDragSlider.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/KnobDragSlider.qml
index b3d621c447..cba135269f 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/data/KnobDragSlider.qml
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/KnobDragSlider.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml
index 2c9fa30a70..99b53e6afb 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/TapHandlerButton.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnFlickable.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnFlickable.qml
index 7bdae0e76b..f6748da19c 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnFlickable.qml
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnFlickable.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnList.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnList.qml
index 00f3d66049..562dc156f9 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnList.qml
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnList.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnTable.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnTable.qml
index ee63c1aa79..bbd5f5b278 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnTable.qml
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/dragOnTable.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml
index 5693a6acd2..740b698fd4 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/flickableWithHandlers.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/pinchOnFlickable.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/pinchOnFlickable.qml
new file mode 100644
index 0000000000..e594f165b2
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/pinchOnFlickable.qml
@@ -0,0 +1,49 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Flickable {
+ id: root
+ width: 800
+ height: 480
+ contentWidth: 1000
+ contentHeight: 600
+
+ Rectangle {
+ id: pinchable
+ objectName: "pinchable"
+ border.color: "black"
+ color: pinch.active ? "salmon" : "peachpuff"
+ x: 100
+ y: 100
+ width: 200
+ height: 200
+ radius: 80
+ PinchHandler {
+ id: pinch
+ }
+ PointHandler {
+ id: p1
+ target: Rectangle {
+ parent: pinchable
+ color: "green"
+ visible: p1.active
+ x: p1.point.position.x - width / 2
+ y: p1.point.position.y - height / 2
+ width: 9; height: width; radius: width / 2
+ }
+ }
+ PointHandler {
+ id: p0
+ target: Rectangle {
+ parent: pinchable
+ color: "red"
+ visible: p0.active
+ x: p0.point.position.x - width / 2
+ y: p0.point.position.y - height / 2
+ width: 9; height: width; radius: width / 2
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/pinchOnFlickableWithParentTapHandler.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/pinchOnFlickableWithParentTapHandler.qml
new file mode 100644
index 0000000000..2660952f16
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/pinchOnFlickableWithParentTapHandler.qml
@@ -0,0 +1,24 @@
+import QtQuick
+
+Rectangle {
+ width: 320
+ height: 320
+
+ TapHandler {
+ onTapped: color = "tomato"
+ }
+
+ Flickable {
+ anchors.fill: parent
+ contentWidth: content.width
+ contentHeight: content.height
+ Rectangle {
+ id: content
+ objectName: "pinchable"
+ width: 150
+ height: 150
+ color: "wheat"
+ PinchHandler {}
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnFlickable.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnFlickable.qml
index 56ae514b96..dc32b1d82c 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnFlickable.qml
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnFlickable.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnList.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnList.qml
index 2ad92e8b71..f4c0e5daaa 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnList.qml
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnList.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnTable.qml b/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnTable.qml
index 46b01ee577..0293ad03b0 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnTable.qml
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/data/tapOnTable.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp
index 869ba80658..790c7c771e 100644
--- a/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp
+++ b/tests/auto/quick/pointerhandlers/flickableinterop/tst_flickableinterop.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -36,6 +11,7 @@
#include <QtQuick/private/qquickitemview_p.h>
#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/private/qquickdraghandler_p.h>
+#include <QtQuick/private/qquickpinchhandler_p.h>
#include <QtQuick/private/qquicktaphandler_p.h>
#include <QtQuick/private/qquicktableview_p.h>
#include <qpa/qwindowsysteminterface.h>
@@ -45,8 +21,8 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlproperty.h>
-#include "../../../shared/util.h"
-#include "../../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests")
@@ -55,7 +31,7 @@ class tst_FlickableInterop : public QQmlDataTest
Q_OBJECT
public:
tst_FlickableInterop()
- :touchDevice(QTest::createTouchDevice())
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{}
private slots:
@@ -79,10 +55,15 @@ private slots:
void touchDragSliderAndFlickable();
void touchAndDragHandlerOnFlickable_data();
void touchAndDragHandlerOnFlickable();
+ void pinchHandlerOnFlickable();
+ void nativeGesturePinchOnFlickableWithParentTapHandler_data();
+ void nativeGesturePinchOnFlickableWithParentTapHandler();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
- QPointingDevice *touchDevice;
+ QScopedPointer<QPointingDevice> touchDevice = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
+ QScopedPointer<QPointingDevice> touchpad = QScopedPointer<QPointingDevice>(
+ QTest::createTouchDevice(QInputDevice::DeviceType::TouchPad));
};
void tst_FlickableInterop::createView(QScopedPointer<QQuickView> &window, const char *fileName)
@@ -90,8 +71,8 @@ void tst_FlickableInterop::createView(QScopedPointer<QQuickView> &window, const
window.reset(new QQuickView);
window->setSource(testFileUrl(fileName));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -121,27 +102,27 @@ void tst_FlickableInterop::touchTapButton()
// Button changes pressed state and emits tapped on release
QPoint p1 = button->mapToScene(QPointF(20, 20)).toPoint();
- QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).press(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(button->property("pressed").toBool());
- QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 1);
+ QCOMPARE(tappedSpy.size(), 1);
// We can drag <= dragThreshold and the button still acts normal, Flickable doesn't grab
p1 = button->mapToScene(QPointF(20, 20)).toPoint();
- QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).press(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(button->property("pressed").toBool());
p1 += QPoint(dragThreshold, 0);
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(button->property("pressed").toBool());
- QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 2);
+ QCOMPARE(tappedSpy.size(), 2);
}
void tst_FlickableInterop::touchDragFlickableBehindButton_data()
@@ -169,11 +150,11 @@ void tst_FlickableInterop::touchDragFlickableBehindButton()
tappedSpy.clear();
QPoint p1 = button->mapToScene(QPointF(20, 20)).toPoint();
- QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).press(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(button->property("pressed").toBool());
p1 += QPoint(dragThreshold, 0);
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(button->property("pressed").toBool());
int i = 0;
@@ -181,17 +162,17 @@ void tst_FlickableInterop::touchDragFlickableBehindButton()
// Button is no longer pressed because Flickable steals the grab
for (; i < 100 && !flickable->isMoving(); ++i) {
p1 += QPoint(1, 0);
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
}
qCDebug(lcPointerTests) << "flickable started moving after" << i << "moves, when we got to" << p1;
QVERIFY(flickable->isMoving());
QCOMPARE(i, 2);
QVERIFY(!button->property("pressed").toBool());
- QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).release(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 0);
+ QCOMPARE(tappedSpy.size(), 0);
}
void tst_FlickableInterop::mouseClickButton_data()
@@ -221,7 +202,7 @@ void tst_FlickableInterop::mouseClickButton()
QTRY_VERIFY(button->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 1);
+ QCOMPARE(tappedSpy.size(), 1);
// We can drag <= dragThreshold and the button still acts normal, Flickable doesn't grab
p1 = button->mapToScene(QPointF(20, 20)).toPoint();
@@ -232,7 +213,7 @@ void tst_FlickableInterop::mouseClickButton()
QVERIFY(button->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 2);
+ QCOMPARE(tappedSpy.size(), 2);
}
void tst_FlickableInterop::mouseDragFlickableBehindButton_data()
@@ -265,7 +246,7 @@ void tst_FlickableInterop::mouseDragFlickableBehindButton()
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(button->property("pressed").toBool());
p1 += QPoint(dragThreshold, 0);
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QVERIFY(button->property("pressed").toBool());
int i = 0;
for (; i < 100 && !flickable->isMoving(); ++i) {
@@ -278,7 +259,7 @@ void tst_FlickableInterop::mouseDragFlickableBehindButton()
QVERIFY(!button->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QVERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 0);
+ QCOMPARE(tappedSpy.size(), 0);
}
void tst_FlickableInterop::touchDragSlider()
@@ -297,24 +278,24 @@ void tst_FlickableInterop::touchDragSlider()
QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>();
QVERIFY(flickable);
QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped()));
- QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy(drag, &QQuickDragHandler::translationChanged);
// Drag the slider in the allowed (vertical) direction
tappedSpy.clear();
QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint() - QPoint(0, 8);
- QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).press(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(slider->property("pressed").toBool());
p1 += QPoint(0, dragThreshold);
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(slider->property("pressed").toBool());
QCOMPARE(slider->property("value").toInt(), 49);
p1 += QPoint(0, 1);
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
p1 += QPoint(0, 10);
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(slider->property("value").toInt() < 49);
QVERIFY(!flickable->isMoving());
@@ -323,15 +304,15 @@ void tst_FlickableInterop::touchDragSlider()
// Now that the DragHandler is active, the Flickable will not steal the grab
// even if we move a large distance horizontally
p1 += QPoint(dragThreshold * 2, 0);
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(!flickable->isMoving());
// Release, and do not expect the tapped signal
- QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).release(1, p1, window);
QQuickTouchUtils::flush(window);
- QCOMPARE(tappedSpy.count(), 0);
- QCOMPARE(translationChangedSpy.count(), 1);
+ QCOMPARE(tappedSpy.size(), 0);
+ QCOMPARE(translationChangedSpy.size(), 1);
}
void tst_FlickableInterop::mouseDragSlider_data()
@@ -377,7 +358,7 @@ void tst_FlickableInterop::mouseDragSlider()
QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>();
QVERIFY(flickable);
QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped()));
- QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy(drag, &QQuickDragHandler::translationChanged);
// Drag the slider
tappedSpy.clear();
@@ -415,8 +396,8 @@ void tst_FlickableInterop::mouseDragSlider()
// Release, and do not expect the tapped signal
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
- QCOMPARE(tappedSpy.count(), 0);
- QCOMPARE(translationChangedSpy.count(), expectedDragHandlerActive ? 1 : 0);
+ QCOMPARE(tappedSpy.size(), 0);
+ QCOMPARE(translationChangedSpy.size(), expectedDragHandlerActive ? 1 : 0);
}
void tst_FlickableInterop::touchDragFlickableBehindSlider()
@@ -435,34 +416,34 @@ void tst_FlickableInterop::touchDragFlickableBehindSlider()
QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>();
QVERIFY(flickable);
QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped()));
- QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy(drag, &QQuickDragHandler::translationChanged);
// Button is no longer pressed if touchpoint goes beyond dragThreshold,
// because Flickable steals the grab
tappedSpy.clear();
QPoint p1 = knob->mapToScene(knob->clipRect().center()).toPoint();
- QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).press(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(slider->property("pressed").toBool());
p1 += QPoint(dragThreshold, 0);
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(slider->property("pressed").toBool());
int i = 0;
for (; i < 100 && !flickable->isMoving(); ++i) {
p1 += QPoint(1, 0);
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
}
qCDebug(lcPointerTests) << "flickable started moving after" << i << "moves, when we got to" << p1;
QVERIFY(flickable->isMoving());
QCOMPARE(i, 2);
QVERIFY(!slider->property("pressed").toBool());
- QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).release(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(!slider->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 0);
- QCOMPARE(translationChangedSpy.count(), 0);
+ QCOMPARE(tappedSpy.size(), 0);
+ QCOMPARE(translationChangedSpy.size(), 0);
}
void tst_FlickableInterop::mouseDragFlickableBehindSlider()
@@ -481,7 +462,7 @@ void tst_FlickableInterop::mouseDragFlickableBehindSlider()
QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>();
QVERIFY(flickable);
QSignalSpy tappedSpy(knob->parent(), SIGNAL(tapped()));
- QSignalSpy translationChangedSpy(drag, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy(drag, &QQuickDragHandler::translationChanged);
// Button is no longer pressed if touchpoint goes beyond dragThreshold,
// because Flickable steals the grab
@@ -503,8 +484,8 @@ void tst_FlickableInterop::mouseDragFlickableBehindSlider()
QCOMPARE(i, 2);
QVERIFY(!slider->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
- QCOMPARE(tappedSpy.count(), 0);
- QCOMPARE(translationChangedSpy.count(), 0);
+ QCOMPARE(tappedSpy.size(), 0);
+ QCOMPARE(translationChangedSpy.size(), 0);
}
void tst_FlickableInterop::touchDragFlickableBehindItemWithHandlers_data()
@@ -532,19 +513,19 @@ void tst_FlickableInterop::touchDragFlickableBehindItemWithHandlers()
QPoint p1 = rect->mapToScene(rect->clipRect().center()).toPoint();
QPoint originP1 = p1;
- QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).press(1, p1, window);
QQuickTouchUtils::flush(window);
for (int i = 0; i < dragThreshold * 3; ++i) {
p1 = originP1;
p1.rx() += i;
- QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).move(1, p1, window);
QQuickTouchUtils::flush(window);
}
QCOMPARE(flickable->isMoving(), expectedFlickableMoving);
if (!expectedFlickableMoving) {
QVERIFY(rect->mapToScene(rect->clipRect().center()).toPoint().x() > originP1.x());
}
- QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QTest::touchEvent(window, touchDevice.get()).release(1, p1, window);
QQuickTouchUtils::flush(window);
}
@@ -609,7 +590,7 @@ void tst_FlickableInterop::touchDragSliderAndFlickable()
QVERIFY(knob);
QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>();
QVERIFY(flickable);
- QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice, false);
+ QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice.get(), false);
// The knob is initially centered over the slider's "groove"
qreal initialXOffset = qAbs(knob->mapToScene(knob->clipRect().center()).x() - slider->mapToScene
@@ -647,7 +628,10 @@ void tst_FlickableInterop::touchDragSliderAndFlickable()
QQuickTouchUtils::flush(window);
qCDebug(lcPointerTests) << "step" << i << ": fingers @" << p1 << p2 << "is Flickable moving yet?" << flickable->isMoving();
}
- QVERIFY(flickable->isMoving());
+ // In Qt 6, Flickable doesn't see the second touchpoint, so it doesn't move.
+ // One way to see this is that Flickable is more immune to stray touches than it otherwise would be.
+ // But time will tell if we are missing out on something useful, which was possible in Qt 5 (QTBUG-123490).
+ QCOMPARE(flickable->isMoving(), false);
qreal knobSliderXOffset = qAbs(knob->mapToScene(knob->clipRect().center()).toPoint().x() -
slider->mapToScene(slider->clipRect().center()).toPoint().x()) - initialXOffset;
if (knobSliderXOffset > 1)
@@ -739,7 +723,7 @@ void tst_FlickableInterop::touchAndDragHandlerOnFlickable()
}
// Drag one finger on the Flickable (between delegates) and make sure it flicks
- QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice, false);
+ QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice.get(), false);
QPoint p1(780, 460);
if (delegate)
p1 = delegate->mapToScene(delegate->clipRect().bottomRight()).toPoint() + QPoint(-1, 1);
@@ -806,6 +790,187 @@ void tst_FlickableInterop::touchAndDragHandlerOnFlickable()
touchSeq.release(1, p1, window).commit();
}
+void tst_FlickableInterop::pinchHandlerOnFlickable()
+{
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("pinchOnFlickable.qml")));
+ QQuickFlickable *flickable = qmlobject_cast<QQuickFlickable*>(window.rootObject());
+ QVERIFY(flickable);
+ QQuickPointerHandler *pinchHandler = flickable->findChild<QQuickPointerHandler*>();
+ QVERIFY(pinchHandler);
+ QQuickItem *pinchable = pinchHandler->target();
+ QVERIFY(pinchable);
+
+ QSignalSpy flickMoveSpy(flickable, &QQuickFlickable::movementStarted);
+ QSignalSpy grabChangedSpy(touchDevice.get(), &QPointingDevice::grabChanged);
+
+ QObject *grabber = nullptr;
+ connect(touchDevice.get(), &QPointingDevice::grabChanged,
+ [&grabber](QObject *g, QPointingDevice::GrabTransition transition, const QPointerEvent *, const QEventPoint &) {
+ if (transition == QPointingDevice::GrabTransition::GrabExclusive)
+ grabber = g;
+ });
+
+ QPoint p0 = pinchable->mapToScene({50, 100}).toPoint();
+ QPoint p1 = pinchable->mapToScene({150, 100}).toPoint();
+ QTest::QTouchEventSequence touch = QTest::touchEvent(&window, touchDevice.get());
+
+ touch.press(0, p0, &window).press(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ int activeStep = -1;
+ int grabTransitionCount = 0;
+ // drag two fingers down: PinchHandler moves the item; Flickable doesn't grab, because there are 2 points
+ for (int i = 0; i < 4; ++i) {
+ p0 += QPoint(0, dragThreshold);
+ p1 += QPoint(0, dragThreshold);
+ touch.move(0, p0, &window).move(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ if (pinchHandler->active() && activeStep < 0) {
+ qCDebug(lcPointerTests) << "pinch began at step" << i;
+ activeStep = i;
+ QCOMPARE(grabber, pinchHandler);
+ grabTransitionCount = grabChangedSpy.count();
+ }
+ }
+ QVERIFY(pinchHandler->active());
+ QCOMPARE(grabChangedSpy.count(), grabTransitionCount);
+ QCOMPARE(grabber, pinchHandler);
+ qreal scale = pinchable->scale();
+ QCOMPARE(scale, 1);
+ qreal rot = pinchable->rotation();
+ QCOMPARE(rot, 0);
+ // start expanding and rotating
+ for (int i = 0; i < 4; ++i) {
+ p0 += QPoint(-5, 10);
+ p1 += QPoint(5, -10);
+ touch.move(0, p0, &window).move(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ QVERIFY(pinchHandler->active());
+ // PinchHandler keeps grab: no more transitions
+ QCOMPARE(grabChangedSpy.count(), grabTransitionCount);
+ QCOMPARE(grabber, pinchHandler);
+ QTRY_COMPARE_GT(pinchable->scale(), scale);
+ scale = pinchable->scale();
+ QCOMPARE_LT(pinchable->rotation(), rot);
+ rot = pinchable->rotation();
+ }
+ touch.release(0, p0, &window).release(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ QTRY_COMPARE(pinchHandler->active(), false);
+ QCOMPARE(flickMoveSpy.count(), 0); // Flickable never moved
+}
+
+void tst_FlickableInterop::nativeGesturePinchOnFlickableWithParentTapHandler_data()
+{
+ QTest::addColumn<const QPointingDevice*>("device");
+ QTest::addColumn<Qt::MouseButton>("button");
+ QTest::addColumn<Qt::NativeGestureType>("gesture");
+ QTest::addColumn<qreal>("value");
+ QTest::addColumn<qreal>("expectedPropertyValue");
+
+ const QPointingDevice *constTouchPad = touchpad.data();
+
+ QTest::newRow("touchpad: left and rotate") << constTouchPad << Qt::LeftButton << Qt::RotateNativeGesture << 5.0 << 10.0;
+ QTest::newRow("touchpad: right and rotate") << constTouchPad << Qt::RightButton << Qt::RotateNativeGesture << 5.0 << 10.0;
+ QTest::newRow("touchpad: left and scale") << constTouchPad << Qt::LeftButton << Qt::ZoomNativeGesture << 0.1 << 1.21;
+ QTest::newRow("touchpad: right and scale") << constTouchPad << Qt::RightButton << Qt::ZoomNativeGesture << 0.1 << 1.21;
+
+ const auto *mouse = QPointingDevice::primaryPointingDevice();
+ if (mouse->type() == QInputDevice::DeviceType::Mouse) {
+ QTest::newRow("mouse: left and rotate") << mouse << Qt::LeftButton << Qt::RotateNativeGesture << 5.0 << 10.0;
+ QTest::newRow("mouse: right and rotate") << mouse << Qt::RightButton << Qt::RotateNativeGesture << 5.0 << 10.0;
+ QTest::newRow("mouse: left and scale") << mouse << Qt::LeftButton << Qt::ZoomNativeGesture << 0.1 << 1.21;
+ QTest::newRow("mouse: right and scale") << mouse << Qt::RightButton << Qt::ZoomNativeGesture << 0.1 << 1.21;
+ } else {
+ qCWarning(lcPointerTests) << "skipping mouse tests: primary device is not a mouse" << mouse;
+ }
+}
+
+void tst_FlickableInterop::nativeGesturePinchOnFlickableWithParentTapHandler()
+{
+ QFETCH(const QPointingDevice*, device);
+ QFETCH(Qt::MouseButton, button);
+ QFETCH(Qt::NativeGestureType, gesture);
+ QFETCH(qreal, value);
+ QFETCH(qreal, expectedPropertyValue);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("pinchOnFlickableWithParentTapHandler.qml")));
+ QQuickFlickable *flickable = window.rootObject()->findChild<QQuickFlickable*>();
+ QVERIFY(flickable);
+ QQuickPointerHandler *pinchHandler = flickable->findChild<QQuickPinchHandler*>();
+ QVERIFY(pinchHandler);
+ QQuickItem *pinchable = pinchHandler->target();
+ QVERIFY(pinchable);
+ QQuickTapHandler *tapHandler = window.rootObject()->findChild<QQuickTapHandler*>();
+ QVERIFY(tapHandler);
+ const bool expectTap = button & tapHandler->acceptedButtons();
+
+ QSignalSpy flickMoveSpy(flickable, &QQuickFlickable::movementStarted);
+ QSignalSpy grabChangedSpy(touchDevice.get(), &QPointingDevice::grabChanged);
+ QSignalSpy tapActiveSpy(tapHandler, &QQuickTapHandler::activeChanged);
+ QSignalSpy tapSpy(tapHandler, &QQuickTapHandler::tapped);
+
+ QObject *grabber = nullptr;
+ connect(device, &QPointingDevice::grabChanged,
+ [&grabber](QObject *g, QPointingDevice::GrabTransition transition, const QPointerEvent *, const QEventPoint &) {
+ if (transition == QPointingDevice::GrabTransition::GrabExclusive)
+ grabber = g;
+ });
+
+ const QPoint pinchPos(75, 75);
+ const QPoint outsidePos(200, 200);
+
+ // move to position
+ QTest::mouseMove(&window, pinchPos);
+
+ // pinch via native gesture
+ ulong ts = 502; // after the mouse move, which is at time 501 in practice
+ QWindowSystemInterface::handleGestureEvent(&window, ts++, touchpad.get(),
+ Qt::BeginNativeGesture, pinchPos, pinchPos);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ for (int i = 0; i < 2; ++i) {
+ QWindowSystemInterface::handleGestureEventWithRealValue(&window, ts++, touchpad.get(),
+ gesture, value, pinchPos, pinchPos);
+ }
+ if (gesture == Qt::RotateNativeGesture)
+ QTRY_COMPARE(pinchHandler->parentItem()->rotation(), expectedPropertyValue);
+ else if (gesture == Qt::ZoomNativeGesture)
+ QTRY_COMPARE(pinchHandler->parentItem()->scale(), expectedPropertyValue);
+ QVERIFY(pinchHandler->active());
+ QCOMPARE(grabChangedSpy.count(), 0);
+ QCOMPARE(grabber, nullptr);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QWindowSystemInterface::handleGestureEvent(&window, ts++, touchpad.get(),
+ Qt::EndNativeGesture, pinchPos, pinchPos);
+
+ // tap in square: TapHandler detects tap iff acceptedButtons permits
+ // TODO delay; unfortunately this also begins at timestamp 502 because we don't have testlib
+ // functions to send gesture events, and QQuickTest::pointerPress() doesn't take a delay value
+ QQuickTest::pointerPress(device, &window, 0, pinchPos, button);
+ QCOMPARE(tapHandler->point().id(), expectTap ? 0 : -1);
+ QQuickTest::pointerRelease(device, &window, 0, pinchPos, button);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QCOMPARE(tapSpy.size() != 0, expectTap);
+ QCOMPARE(tapActiveSpy.size(), 0);
+ QCOMPARE(tapHandler->point().id(), -1); // does not keep tracking after release
+
+ // move outside: nothing should happen;
+ // but QTBUG-108896 happened because TapHandler was setting pointInfo to track this moving point
+ QQuickTest::pointerMove(device, &window, 0, outsidePos);
+ QCOMPARE(tapHandler->point().id(), -1); // does not track after mouse move
+
+ // tap outside: nothing happens
+ tapSpy.clear();
+ tapActiveSpy.clear();
+ QQuickTest::pointerPress(device, &window, 0, outsidePos, button);
+ QQuickTest::pointerRelease(device, &window, 0, outsidePos, button);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QCOMPARE(tapSpy.size(), 0);
+ QCOMPARE(tapActiveSpy.size(), 0);
+}
+
QTEST_MAIN(tst_FlickableInterop)
#include "tst_flickableinterop.moc"
diff --git a/tests/auto/quick/pointerhandlers/mousearea_interop/BLACKLIST b/tests/auto/quick/pointerhandlers/mousearea_interop/BLACKLIST
new file mode 100644
index 0000000000..74d29b4ac3
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/mousearea_interop/BLACKLIST
@@ -0,0 +1,7 @@
+# QTBUG-95938
+[dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch]
+opensuse-leap
+
+# QTBUG-95938
+[dragHandlerInSiblingStealingGrabFromMouseAreaViaMouse]
+opensuse-leap
diff --git a/tests/auto/quick/pointerhandlers/mousearea_interop/CMakeLists.txt b/tests/auto/quick/pointerhandlers/mousearea_interop/CMakeLists.txt
index f799de97b8..22123e6385 100644
--- a/tests/auto/quick/pointerhandlers/mousearea_interop/CMakeLists.txt
+++ b/tests/auto/quick/pointerhandlers/mousearea_interop/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from mousearea_interop.pro.
#####################################################################
## tst_mousearea_interop Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_mousearea_interop LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_mousearea_interop
SOURCES
- ../../../shared/util.cpp ../../../shared/util.h
- ../../shared/geometrytestutil.cpp ../../shared/geometrytestutil.h
- ../../shared/viewtestutil.cpp ../../shared/viewtestutil.h
- ../../shared/visualtestutil.cpp ../../shared/visualtestutil.h
tst_mousearea_interop.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -38,10 +40,10 @@ qt_internal_add_test(tst_mousearea_interop
qt_internal_extend_target(tst_mousearea_interop CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_mousearea_interop CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/pointerhandlers/mousearea_interop/data/dragHandlerInMouseAreaGrandparent.qml b/tests/auto/quick/pointerhandlers/mousearea_interop/data/dragHandlerInMouseAreaGrandparent.qml
new file mode 100644
index 0000000000..7adb205a1f
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/mousearea_interop/data/dragHandlerInMouseAreaGrandparent.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.12
+
+Rectangle {
+ width: 200; height: 200
+
+ DragHandler { }
+
+ Rectangle {
+ objectName: "button"
+ width: 100; height: 40; x: 10; y: 10
+ border.color: "orange"
+ color: ma.pressed ? "lightsteelblue" : "beige"
+
+ MouseArea {
+ id: ma
+ anchors.fill: parent
+ onDoubleClicked: console.log("__")
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/mousearea_interop/data/dragTakeOverFromSibling.qml b/tests/auto/quick/pointerhandlers/mousearea_interop/data/dragTakeOverFromSibling.qml
index 48b1dc86f0..1bde433dba 100644
--- a/tests/auto/quick/pointerhandlers/mousearea_interop/data/dragTakeOverFromSibling.qml
+++ b/tests/auto/quick/pointerhandlers/mousearea_interop/data/dragTakeOverFromSibling.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/mousearea_interop/data/hoverHandlerInGrandparentOfHoverableItem.qml b/tests/auto/quick/pointerhandlers/mousearea_interop/data/hoverHandlerInGrandparentOfHoverableItem.qml
new file mode 100644
index 0000000000..a3b957a1f7
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/mousearea_interop/data/hoverHandlerInGrandparentOfHoverableItem.qml
@@ -0,0 +1,33 @@
+import QtQuick 2.12
+
+Item {
+ width: 320
+ height: 240
+
+ Rectangle {
+ color: hh.hovered ? "orange" : "gray"
+ anchors.fill: container
+ }
+
+ Item {
+ id: container
+ anchors.fill: parent
+ anchors.margins: 40
+
+ Rectangle {
+ width: parent.width
+ height: 40
+ color: ma.pressed ? "blue" : ma.containsMouse ? "aquamarine" : "beige"
+
+ MouseArea {
+ id: ma
+ anchors.fill: parent
+ hoverEnabled: true
+ }
+ }
+
+ HoverHandler {
+ id: hh
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp b/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp
index 4709622245..b1a480b9cf 100644
--- a/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp
+++ b/tests/auto/quick/pointerhandlers/mousearea_interop/tst_mousearea_interop.cpp
@@ -1,43 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
+#include <QtGui/qstylehints.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlproperty.h>
#include <QtQuick/private/qquickdraghandler_p.h>
+#include <QtQuick/private/qquickhoverhandler_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickview.h>
#include <QtGui/private/qpointingdevice_p.h>
-#include "../../../shared/util.h"
-#include "../../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+
+#include <QtCore/qpointer.h>
Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests")
@@ -46,12 +25,15 @@ class tst_MouseAreaInterop : public QQmlDataTest
Q_OBJECT
public:
tst_MouseAreaInterop()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{}
private slots:
void dragHandlerInSiblingStealingGrabFromMouseAreaViaMouse();
void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch_data();
void dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch();
+ void hoverHandlerDoesntHoverOnPress();
+ void doubleClickInMouseAreaWithDragHandlerInGrandparent();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
@@ -63,8 +45,8 @@ void tst_MouseAreaInterop::createView(QScopedPointer<QQuickView> &window, const
window.reset(new QQuickView);
window->setSource(testFileUrl(fileName));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -86,7 +68,7 @@ void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaMouse
QPoint p1(150, 150);
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
QCOMPARE(window->mouseGrabberItem(), ma);
- QCOMPARE(ma->pressed(), true);
+ QCOMPARE(ma->isPressed(), true);
// Start dragging
// DragHandler keeps monitoring, due to its passive grab,
@@ -104,7 +86,7 @@ void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaMouse
qCDebug(lcPointerTests, "DragHandler stole the grab after %d events", dragStoleGrab);
QVERIFY(dragStoleGrab > 1);
QCOMPARE(handler->active(), true);
- QCOMPARE(ma->pressed(), false);
+ QCOMPARE(ma->isPressed(), false);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QCOMPARE(handler->active(), false);
@@ -145,7 +127,7 @@ void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch
QVERIFY(epd);
QVERIFY(epd->passiveGrabbers.contains(handler.data()));
QCOMPARE(epd->exclusiveGrabber, ma);
- QCOMPARE(ma->pressed(), true);
+ QCOMPARE(ma->isPressed(), true);
// Start dragging
// DragHandler keeps monitoring, due to its passive grab,
@@ -163,11 +145,11 @@ void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch
if (preventStealing) {
QCOMPARE(dragStoleGrab, 0);
QCOMPARE(handler->active(), false);
- QCOMPARE(ma->pressed(), true);
+ QCOMPARE(ma->isPressed(), true);
} else {
QVERIFY(dragStoleGrab > 1);
QCOMPARE(handler->active(), true);
- QCOMPARE(ma->pressed(), false);
+ QCOMPARE(ma->isPressed(), false);
}
touch.release(1, p1).commit();
@@ -175,6 +157,55 @@ void tst_MouseAreaInterop::dragHandlerInSiblingStealingGrabFromMouseAreaViaTouch
QCOMPARE(handler->active(), false);
}
+void tst_MouseAreaInterop::hoverHandlerDoesntHoverOnPress() // QTBUG-72843
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("hoverHandlerInGrandparentOfHoverableItem.qml")));
+
+ QPointer<QQuickHoverHandler> handler = window.rootObject()->findChild<QQuickHoverHandler*>();
+ QVERIFY(handler);
+ QQuickMouseArea *ma = window.rootObject()->findChild<QQuickMouseArea*>();
+ QVERIFY(ma);
+ QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint();
+
+ // move the mouse below the "button" but within HoverHandler's region of interest
+ QTest::mouseMove(&window, p + QPoint(0, 50));
+ QTRY_COMPARE(handler->isHovered(), true);
+ // move the mouse into the "button"
+ QTest::mouseMove(&window, p);
+ // both the hoverhandler and the mouse area should now be hovered!
+ QTRY_COMPARE(handler->isHovered(), true);
+ QCOMPARE(ma->hovered(), true);
+
+ QSignalSpy hoveredChangedSpy(handler, SIGNAL(hoveredChanged()));
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p);
+ QTRY_COMPARE(ma->isPressed(), true);
+ QCOMPARE(handler->isHovered(), true);
+ QCOMPARE(hoveredChangedSpy.size(), 0);
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p);
+ QTRY_COMPARE(ma->isPressed(), false);
+ QCOMPARE(handler->isHovered(), true);
+ QCOMPARE(hoveredChangedSpy.size(), 0);
+}
+
+void tst_MouseAreaInterop::doubleClickInMouseAreaWithDragHandlerInGrandparent()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("dragHandlerInMouseAreaGrandparent.qml")));
+
+ QQuickDragHandler *handler = window.rootObject()->findChild<QQuickDragHandler*>();
+ QVERIFY(handler);
+ QSignalSpy dragActiveSpy(handler, &QQuickDragHandler::activeChanged);
+ QQuickMouseArea *ma = window.rootObject()->findChild<QQuickMouseArea*>();
+ QVERIFY(ma);
+ QSignalSpy dClickSpy(ma, &QQuickMouseArea::doubleClicked);
+ QPoint p = ma->mapToScene(ma->boundingRect().center()).toPoint();
+
+ QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p);
+ QCOMPARE(dClickSpy.size(), 1);
+ QCOMPARE(dragActiveSpy.size(), 0);
+}
+
QTEST_MAIN(tst_MouseAreaInterop)
#include "tst_mousearea_interop.moc"
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/BLACKLIST b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/BLACKLIST
index 3f01d3a7d4..80d6dd0ee8 100644
--- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/BLACKLIST
+++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/BLACKLIST
@@ -1,2 +1,3 @@
-[touchesThenPinch]
-* # QTBUG-86729
+# QTBUG-118062
+[touchDrag]
+opensuse-leap
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/CMakeLists.txt b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/CMakeLists.txt
index 4aac9440f9..9f19e8b427 100644
--- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/CMakeLists.txt
+++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from multipointtoucharea_interop.pro.
#####################################################################
## tst_multipointtoucharea_interop Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_multipointtoucharea_interop LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_multipointtoucharea_interop
SOURCES
- ../../../shared/util.cpp ../../../shared/util.h
- ../../shared/geometrytestutil.cpp ../../shared/geometrytestutil.h
- ../../shared/viewtestutil.cpp ../../shared/viewtestutil.h
- ../../shared/visualtestutil.cpp ../../shared/visualtestutil.h
tst_multipointtoucharea_interop.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -38,10 +40,10 @@ qt_internal_add_test(tst_multipointtoucharea_interop
qt_internal_extend_target(tst_multipointtoucharea_interop CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_multipointtoucharea_interop CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/dragParentOfMPTA.qml b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/dragParentOfMPTA.qml
index dc7e5f6411..ad4494eb25 100644
--- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/dragParentOfMPTA.qml
+++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/dragParentOfMPTA.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml
index f1591a412e..199292e015 100644
--- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml
+++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/pinchDragMPTA.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
@@ -60,8 +35,8 @@ Rectangle {
Item {
id: crosshairs
property TouchPoint touchPoint
- x: touchPoint.x - width / 2
- y: touchPoint.y - height / 2
+ x: touchPoint?.x - width / 2
+ y: touchPoint?.y - height / 2
width: 300; height: 300
visible: touchPoint.pressed
rotation: touchPoint.rotation
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/unloadHandlerOnPress.qml b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/unloadHandlerOnPress.qml
index 1bd20c6bcb..868a5265a6 100644
--- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/unloadHandlerOnPress.qml
+++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/data/unloadHandlerOnPress.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
index 0312ed0141..a4cc182422 100644
--- a/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
+++ b/tests/auto/quick/pointerhandlers/multipointtoucharea_interop/tst_multipointtoucharea_interop.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -37,8 +12,10 @@
#include <QtQuick/qquickview.h>
#include <QtGui/private/qpointingdevice_p.h>
-#include "../../../shared/util.h"
-#include "../../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+
+#include <QtCore/qpointer.h>
Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests")
@@ -47,6 +24,7 @@ class tst_MptaInterop : public QQmlDataTest
Q_OBJECT
public:
tst_MptaInterop()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{}
private slots:
@@ -67,8 +45,8 @@ void tst_MptaInterop::createView(QScopedPointer<QQuickView> &window, const char
window.reset(new QQuickView);
window->setSource(testFileUrl(fileName));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -169,7 +147,7 @@ void tst_MptaInterop::touchesThenPinch()
QQuickTouchUtils::flush(window);
QVERIFY(tp.at(0)->property("pressed").toBool());
QTRY_VERIFY(tp.at(1)->property("pressed").toBool());
- QCOMPARE(mptaPressedSpy.count(), 2);
+ QCOMPARE(mptaPressedSpy.size(), 2);
// Press a third touchpoint: MPTA grabs it too
QPoint p3 = mpta->mapToScene(QPointF(110, 200)).toPoint();
@@ -178,8 +156,8 @@ void tst_MptaInterop::touchesThenPinch()
QCOMPARE(tp.at(0)->property("pressed").toBool(), true);
QCOMPARE(tp.at(1)->property("pressed").toBool(), true);
QCOMPARE(tp.at(2)->property("pressed").toBool(), true);
- QCOMPARE(mptaPressedSpy.count(), 3);
- QCOMPARE(mptaCanceledSpy.count(), 0);
+ QCOMPARE(mptaPressedSpy.size(), 3);
+ QCOMPARE(mptaCanceledSpy.size(), 0);
QCOMPARE(devPriv->pointById(1)->exclusiveGrabber, mpta);
QCOMPARE(devPriv->pointById(2)->exclusiveGrabber, mpta);
QCOMPARE(devPriv->pointById(3)->exclusiveGrabber, mpta);
@@ -272,13 +250,14 @@ void tst_MptaInterop::touchesThenPinch()
if (!dragTookGrab && devPriv->pointById(2)->exclusiveGrabber == drag)
dragTookGrab = i;
}
- qCDebug(lcPointerTests) << "drag started after" << dragTookGrab << "moves; ended with translation" << drag->translation();
- QCOMPARE(devPriv->pointById(1)->exclusiveGrabber, drag);
- QTRY_VERIFY(drag->translation().x() > 0);
+ qCDebug(lcPointerTests) << "drag started after" << dragTookGrab
+ << "moves; ended with translation" << drag->activeTranslation();
+ QCOMPARE(devPriv->pointById(2)->exclusiveGrabber, drag);
+ QTRY_VERIFY(drag->activeTranslation().x() > 0);
touch.release(2, p2).commit();
QQuickTouchUtils::flush(window);
- QTRY_COMPARE(mptaReleasedSpy.count(), 1);
+ QTRY_COMPARE(mptaReleasedSpy.size(), 1);
}
void tst_MptaInterop::unloadHandlerWithPassiveGrab()
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/BLACKLIST b/tests/auto/quick/pointerhandlers/qquickdraghandler/BLACKLIST
new file mode 100644
index 0000000000..e555a4bb61
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/BLACKLIST
@@ -0,0 +1,9 @@
+# QTBUG-103064
+[touchDragMulti]
+android
+[touchDrag]
+android
+[touchDragMultiSliders]
+android
+[touchPassiveGrabbers]
+android
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/CMakeLists.txt b/tests/auto/quick/pointerhandlers/qquickdraghandler/CMakeLists.txt
index 85c664f8ca..23087c1d48 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/CMakeLists.txt
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickdraghandler.pro.
#####################################################################
## tst_qquickdraghandler Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickdraghandler LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickdraghandler
SOURCES
- ../../../shared/util.cpp ../../../shared/util.h
- ../../shared/geometrytestutil.cpp ../../shared/geometrytestutil.h
- ../../shared/viewtestutil.cpp ../../shared/viewtestutil.h
- ../../shared/visualtestutil.cpp ../../shared/visualtestutil.h
tst_qquickdraghandler.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -38,10 +40,10 @@ qt_internal_add_test(tst_qquickdraghandler
qt_internal_extend_target(tst_qquickdraghandler CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickdraghandler CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml
index 778a799d70..065b0aaed8 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/DragAnywhereSlider.qml
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-import QtQuick 2.12
+import QtQuick
Item {
id: root
@@ -38,7 +13,7 @@ Item {
property alias pressed: tap.pressed
signal tapped
width: 140
- height: 400
+ height: 260
DragHandler {
id: dragHandler
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml
index 158a02b7a6..9483a12d1c 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/FlashAnimation.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml
index 782750b783..200e846207 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/Slider.qml
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-import QtQuick 2.12
+import QtQuick
Item {
id: root
@@ -38,7 +13,7 @@ Item {
property alias pressed: tap.pressed
signal tapped
width: 140
- height: 400
+ height: 260
Rectangle {
id: slot
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragAndWheel.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragAndWheel.qml
new file mode 100644
index 0000000000..811326aaba
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragAndWheel.qml
@@ -0,0 +1,32 @@
+import QtQuick 2.15
+
+Item {
+ id: root
+
+ property bool gotWheel: false
+ property int changeCount: 0
+ property alias wheelHandlerEnabled: wheelHandler.enabled
+
+ width: 640
+ height: 480
+
+ Rectangle {
+ color: "blue"
+ width: 200
+ height: 200
+
+ DragHandler {
+ id: dragHandler
+ }
+
+ WheelHandler {
+ id: wheelHandler
+
+ enabled: !dragHandler.active
+ onEnabledChanged: root.changeCount++
+ onWheel: root.gotWheel = true
+ }
+
+ }
+
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragHandlerUnderModalLayer.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragHandlerUnderModalLayer.qml
new file mode 100644
index 0000000000..b24812c914
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/dragHandlerUnderModalLayer.qml
@@ -0,0 +1,34 @@
+import QtQuick 2.15
+
+import Test 1.0
+
+Item {
+ width: 640
+ height: 480
+
+ Rectangle {
+ anchors.fill: parent
+ color: "grey"
+
+ Rectangle {
+ x: 200
+ y: 200
+ width: 100
+ height: 100
+ color: "orange"
+ DragHandler {
+ grabPermissions: DragHandler.CanTakeOverFromAnything // but not anything with keepMouseGrab!
+ }
+ }
+ }
+
+ ModalLayer {
+ anchors.fill: parent
+
+ Rectangle {
+ anchors.fill: parent
+ color: "red"
+ opacity: 0.4
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml
index 81fa20f3bb..47be6052ad 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draggables.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the manual tests of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.15
@@ -54,7 +29,9 @@ Item {
color: "white"
anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
- text: ball.objectName + "\n" + dragHandler.centroid.position.x.toFixed(1) + "," + dragHandler.centroid.position.y.toFixed(1)
+ text: ball.objectName + "\n"
+ + dragHandler.centroid.position.x.toFixed(1) + "," + dragHandler.centroid.position.y.toFixed(1) + "\n"
+ + ball.x.toFixed(1) + "," + ball.y.toFixed(1)
}
}
}
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draghandler_and_pinchhandler.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draghandler_and_pinchhandler.qml
index 08b85aef50..5d700cdd08 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draghandler_and_pinchhandler.qml
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/draghandler_and_pinchhandler.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the manual tests of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml
index f6042f4461..ea71da5623 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/multipleSliders.qml
@@ -1,40 +1,35 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-import QtQuick 2.12
+import QtQuick
Rectangle {
id: root
- width: 900
- height: 850
+ width: 600
+ height: 540
objectName: "root"
color: "#222222"
+ Instantiator {
+ model: 3
+ // non-interfering, just for visual monitoring of points
+ delegate: PointHandler {
+ id: ph
+ required property int index
+ objectName: "ph" + index
+ parent: root
+
+ target: Rectangle {
+ parent: root
+ visible: ph.active
+ x: ph.point.position.x - width / 2
+ y: ph.point.position.y - height / 2
+ width: 10; height: width; radius: width / 2
+ color: Qt.rgba(1, 0.33 * ph.index, 1 - 0.3 * ph.index)
+ }
+ }
+ }
+
Grid {
objectName: "grid"
anchors.fill: parent
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/simpleTapAndDragHandlers.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/simpleTapAndDragHandlers.qml
index 6e5574787c..6c7a25c148 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/simpleTapAndDragHandlers.qml
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/simpleTapAndDragHandlers.qml
@@ -1,37 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the manual tests of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-import QtQuick 2.12
+import QtQuick
Rectangle {
id: root
- width: 900
- height: 850
+ width: 320
+ height: 240
objectName: "root"
color: "#222222"
@@ -105,7 +80,5 @@ Rectangle {
}
}
}
-
-
}
}
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/snapMode.qml b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/snapMode.qml
index d6eb791700..30b28ac9e8 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/data/snapMode.qml
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/data/snapMode.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
@@ -34,6 +9,26 @@ Item {
width: 640
height: 480
+ Instantiator {
+ model: 3
+ // non-interfering, just for visual monitoring of points
+ delegate: PointHandler {
+ id: ph
+ required property int index
+ objectName: "ph" + index
+ parent: root
+
+ target: Rectangle {
+ parent: root
+ visible: ph.active
+ x: ph.point.position.x - width / 2
+ y: ph.point.position.y - height / 2
+ width: 10; height: width; radius: width / 2
+ color: Qt.rgba(1, 0.33 * ph.index, 1 - 0.3 * ph.index)
+ }
+ }
+ }
+
Rectangle {
id: rect1
objectName: "rect1"
diff --git a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
index c33c70b9e9..15df656b93 100644
--- a/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickdraghandler/tst_qquickdraghandler.cpp
@@ -1,33 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
+#include <QtGui/qstylehints.h>
+#include <QtQml/private/qqmlglobal_p.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlproperty.h>
#include <QtQuick/private/qquickdraghandler_p.h>
@@ -37,8 +14,10 @@
#include <QtQuick/qquickview.h>
#include <QtGui/private/qpointingdevice_p.h>
-#include "../../../shared/util.h"
-#include "../../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+
+#include <QtCore/qpointer.h>
Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests")
@@ -47,7 +26,8 @@ class tst_DragHandler : public QQmlDataTest
Q_OBJECT
public:
tst_DragHandler()
- :touchDevice(QTest::createTouchDevice())
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+ , touchDevice(QTest::createTouchDevice())
{}
private slots:
@@ -69,8 +49,12 @@ private slots:
void touchPassiveGrabbers_data();
void touchPassiveGrabbers();
void touchPinchAndMouseMove();
+ void unsuitableEventDuringDrag();
+ void underModalLayer();
+ void interruptedByIrrelevantButton();
private:
+ void sendWheelEvent(QQuickView &window, QPoint pos, QPoint angleDelta, QPoint pixelDelta, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase, bool inverted);
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
QSet<QQuickPointerHandler *> passiveGrabbers(QQuickWindow *window, int pointId = 0);
QPointingDevice *touchDevice;
@@ -81,8 +65,8 @@ void tst_DragHandler::createView(QScopedPointer<QQuickView> &window, const char
window.reset(new QQuickView);
window->setSource(testFileUrl(fileName));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -124,7 +108,8 @@ void tst_DragHandler::defaultPropertyValues()
QVERIFY(dragHandler);
QCOMPARE(dragHandler->acceptedButtons(), Qt::LeftButton);
- QCOMPARE(dragHandler->translation(), QVector2D());
+ QCOMPARE(dragHandler->persistentTranslation(), QVector2D());
+ QCOMPARE(dragHandler->activeTranslation(), QVector2D());
QCOMPARE(dragHandler->centroid().position(), QPointF());
QCOMPARE(dragHandler->centroid().scenePosition(), QPointF());
QCOMPARE(dragHandler->centroid().pressPosition(), QPointF());
@@ -159,8 +144,9 @@ void tst_DragHandler::touchDrag()
dragHandler->setDragThreshold(dragThreshold);
}
- QSignalSpy translationChangedSpy(dragHandler, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy(dragHandler, &QQuickDragHandler::translationChanged);
QSignalSpy centroidChangedSpy(dragHandler, SIGNAL(centroidChanged()));
+ QSignalSpy xDeltaSpy(dragHandler->xAxis(), &QQuickDragAxis::activeValueChanged);
QPointF ballCenter = ball->clipRect().center();
QPointF scenePressPos = ball->mapToScene(ballCenter);
@@ -173,22 +159,24 @@ void tst_DragHandler::touchDrag()
QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos);
QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
QCOMPARE(dragHandler->centroid().velocity(), QVector2D());
- QCOMPARE(centroidChangedSpy.count(), 1);
+ QCOMPARE(centroidChangedSpy.size(), 1);
p1 += QPoint(dragThreshold, 0);
QTest::touchEvent(window, touchDevice).move(1, p1, window);
QQuickTouchUtils::flush(window);
qCDebug(lcPointerTests) << "velocity after drag" << dragHandler->centroid().velocity();
if (dragThreshold > 0)
QTRY_VERIFY(!qFuzzyIsNull(dragHandler->centroid().velocity().x()));
- QCOMPARE(centroidChangedSpy.count(), 2);
+ QCOMPARE(centroidChangedSpy.size(), 2);
QVERIFY(!dragHandler->active());
p1 += QPoint(1, 0);
QTest::touchEvent(window, touchDevice).move(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(dragHandler->active());
- QCOMPARE(translationChangedSpy.count(), 0);
- QCOMPARE(centroidChangedSpy.count(), 3);
- QCOMPARE(dragHandler->translation().x(), 0.0);
+ QCOMPARE(translationChangedSpy.size(), 0);
+ QCOMPARE(xDeltaSpy.size(), 0);
+ QCOMPARE(centroidChangedSpy.size(), 3);
+ QCOMPARE(dragHandler->persistentTranslation().x(), 0);
+ QCOMPARE(dragHandler->activeTranslation().x(), 0);
QPointF sceneGrabPos = p1;
QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos);
p1 += QPoint(19, 0);
@@ -200,18 +188,79 @@ void tst_DragHandler::touchDrag()
QCOMPARE(dragHandler->centroid().scenePosition(), ball->mapToScene(ballCenter));
QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos);
- QCOMPARE(dragHandler->translation().x(), dragThreshold + 20.0);
- QCOMPARE(dragHandler->translation().y(), 0.0);
+ QCOMPARE(dragHandler->persistentTranslation().x(), dragThreshold + 20);
+ QCOMPARE(dragHandler->activeTranslation().x(), dragThreshold + 20);
+ QCOMPARE(dragHandler->persistentTranslation().y(), 0);
+ QCOMPARE(dragHandler->activeTranslation().y(), 0);
+ QCOMPARE(translationChangedSpy.size(), 1);
+ QCOMPARE(translationChangedSpy.first().first().value<QVector2D>(), QVector2D(dragThreshold + 20, 0));
QVERIFY(dragHandler->centroid().velocity().x() > 0);
- QCOMPARE(centroidChangedSpy.count(), 4);
+ QCOMPARE(centroidChangedSpy.size(), 4);
QTest::touchEvent(window, touchDevice).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!dragHandler->active());
QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton);
QCOMPARE(dragHandler->centroid().velocity(), QVector2D());
QCOMPARE(ball->mapToScene(ballCenter).toPoint(), p1);
- QCOMPARE(translationChangedSpy.count(), 1);
- QCOMPARE(centroidChangedSpy.count(), 5);
+ QCOMPARE(translationChangedSpy.size(), 1);
+ QCOMPARE(xDeltaSpy.size(), 1);
+ QCOMPARE(xDeltaSpy.first().first().toReal(), dragThreshold + 20);
+ QCOMPARE(centroidChangedSpy.size(), 5);
+ QCOMPARE(dragHandler->persistentTranslation().x(), dragThreshold + 20);
+
+ // Drag again: activeTranslation starts over, while persistentTranslation accumulates
+ p1 = ball->mapToScene(ballCenter).toPoint();
+ QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ QCOMPARE(dragHandler->persistentTranslation().x(), dragThreshold + 20);
+ p1 += QPoint(dragThreshold, 0);
+ QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ p1 += QPoint(1, 0);
+ QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ QTRY_VERIFY(dragHandler->active());
+ p1 += QPoint(9, 0);
+ QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ QCOMPARE(xDeltaSpy.size(), 2);
+ QCOMPARE(xDeltaSpy.last().first().toReal(), dragThreshold + 10);
+ p1 += QPoint(10, 0);
+ QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ QCOMPARE(dragHandler->activeTranslation().x(), dragThreshold + 20);
+ QCOMPARE(dragHandler->persistentTranslation().x(), dragThreshold * 2 + 40);
+ QCOMPARE(xDeltaSpy.size(), 3);
+ QCOMPARE(xDeltaSpy.last().first().toReal(), 10);
+ QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QQuickTouchUtils::flush(window);
+
+ // Call setPersistentTranslation and drag yet again:
+ // activeTranslation starts over, while persistentTranslation adds the drags onto the new basis
+ dragHandler->setPersistentTranslation({10, 10});
+ p1 = ball->mapToScene(ballCenter).toPoint();
+ QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ QCOMPARE(dragHandler->persistentTranslation().x(), 10);
+ p1 += QPoint(dragThreshold, 0);
+ QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ p1 += QPoint(1, 0);
+ QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ QTRY_VERIFY(dragHandler->active());
+ p1 += QPoint(9, 0);
+ QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ p1 += QPoint(10, 0);
+ QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ QCOMPARE(dragHandler->activeTranslation().x(), dragThreshold + 20);
+ QCOMPARE(dragHandler->persistentTranslation().x(), dragThreshold + 30);
+ QCOMPARE(xDeltaSpy.size(), 6);
+ QCOMPARE(xDeltaSpy.last().first().toReal(), 10);
+ QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QQuickTouchUtils::flush(window);
}
void tst_DragHandler::mouseDrag_data()
@@ -241,8 +290,9 @@ void tst_DragHandler::mouseDrag()
QVERIFY(dragHandler);
dragHandler->setAcceptedButtons(acceptedButtons); // QTBUG-76875
- QSignalSpy translationChangedSpy(dragHandler, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy(dragHandler, &QQuickDragHandler::translationChanged);
QSignalSpy centroidChangedSpy(dragHandler, SIGNAL(centroidChanged()));
+ QSignalSpy xDeltaSpy(dragHandler->xAxis(), &QQuickDragAxis::activeValueChanged);
QPointF ballCenter = ball->clipRect().center();
QPointF scenePressPos = ball->mapToScene(ballCenter);
@@ -258,13 +308,13 @@ void tst_DragHandler::mouseDrag()
QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos);
QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
QCOMPARE(dragHandler->centroid().velocity(), QVector2D());
- QCOMPARE(centroidChangedSpy.count(), 1);
+ QCOMPARE(centroidChangedSpy.size(), 1);
}
p1 += QPoint(dragThreshold, 0);
QTest::mouseMove(window, p1);
if (shouldDrag) {
-// QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0); // TODO QTBUG-33891
- QCOMPARE(centroidChangedSpy.count(), 2);
+ QVERIFY(dragHandler->centroid().velocity().x() > 0);
+ QCOMPARE(centroidChangedSpy.size(), 2);
QVERIFY(!dragHandler->active());
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
@@ -276,10 +326,12 @@ void tst_DragHandler::mouseDrag()
QTRY_VERIFY(dragHandler->active());
else
QVERIFY(!dragHandler->active());
- QCOMPARE(translationChangedSpy.count(), 0);
+ QCOMPARE(translationChangedSpy.size(), 0);
+ QCOMPARE(xDeltaSpy.size(), 0);
if (shouldDrag)
- QCOMPARE(centroidChangedSpy.count(), 3);
- QCOMPARE(dragHandler->translation().x(), 0.0);
+ QCOMPARE(centroidChangedSpy.size(), 3);
+ QCOMPARE(dragHandler->persistentTranslation().x(), 0.0);
+ QCOMPARE(dragHandler->activeTranslation().x(), 0.0);
QPointF sceneGrabPos = p1;
if (shouldDrag)
QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos);
@@ -292,10 +344,12 @@ void tst_DragHandler::mouseDrag()
QCOMPARE(dragHandler->centroid().scenePosition(), ball->mapToScene(ballCenter));
QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos);
- QCOMPARE(dragHandler->translation().x(), dragThreshold + 20.0);
- QCOMPARE(dragHandler->translation().y(), 0.0);
-// QVERIFY(dragHandler->centroid().velocity().x() > 0); // TODO QTBUG-33891
- QCOMPARE(centroidChangedSpy.count(), 4);
+ QCOMPARE(dragHandler->persistentTranslation().x(), dragThreshold + 20.0);
+ QCOMPARE(dragHandler->activeTranslation().x(), dragThreshold + 20.0);
+ QCOMPARE(dragHandler->persistentTranslation().y(), 0.0);
+ QCOMPARE(dragHandler->activeTranslation().y(), 0.0);
+ QVERIFY(dragHandler->centroid().velocity().x() > 0);
+ QCOMPARE(centroidChangedSpy.size(), 4);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::ClosedHandCursor);
#endif
@@ -303,10 +357,13 @@ void tst_DragHandler::mouseDrag()
QTest::mouseRelease(window, static_cast<Qt::MouseButton>(int(dragButton)), Qt::NoModifier, p1);
QTRY_VERIFY(!dragHandler->active());
QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton);
- if (shouldDrag)
+ QCOMPARE(translationChangedSpy.size(), shouldDrag ? 1 : 0);
+ if (shouldDrag) {
QCOMPARE(ball->mapToScene(ballCenter).toPoint(), p1);
- QCOMPARE(translationChangedSpy.count(), shouldDrag ? 1 : 0);
- QCOMPARE(centroidChangedSpy.count(), shouldDrag ? 5 : 0);
+ QCOMPARE(translationChangedSpy.first().first().value<QVector2D>(), QVector2D(dragThreshold + 20, 0));
+ }
+ QCOMPARE(xDeltaSpy.size(), shouldDrag ? 1 : 0);
+ QCOMPARE(centroidChangedSpy.size(), shouldDrag ? 5 : 0);
#if QT_CONFIG(cursor)
QTest::mouseMove(window, p1 + QPoint(1, 0)); // TODO after fixing QTBUG-53987, don't send mouseMove
QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
@@ -340,8 +397,9 @@ void tst_DragHandler::mouseDragThreshold()
dragHandler->setDragThreshold(dragThreshold);
}
- QSignalSpy translationChangedSpy(dragHandler, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy(dragHandler, &QQuickDragHandler::translationChanged);
QSignalSpy centroidChangedSpy(dragHandler, SIGNAL(centroidChanged()));
+ QSignalSpy xDeltaSpy(dragHandler->xAxis(), &QQuickDragAxis::activeValueChanged);
QPointF ballCenter = ball->clipRect().center();
QPointF scenePressPos = ball->mapToScene(ballCenter);
@@ -353,20 +411,28 @@ void tst_DragHandler::mouseDragThreshold()
QCOMPARE(dragHandler->centroid().scenePosition(), scenePressPos);
QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
QCOMPARE(dragHandler->centroid().velocity(), QVector2D());
- QCOMPARE(centroidChangedSpy.count(), 1);
+ QCOMPARE(centroidChangedSpy.size(), 1);
p1 += QPoint(qMax(1, dragThreshold), 0); // QTBUG-85431: zero-distance mouse moves are not delivered
QTest::mouseMove(window, p1);
if (dragThreshold > 0)
QTRY_VERIFY(dragHandler->centroid().velocity().x() > 0);
- QCOMPARE(centroidChangedSpy.count(), 2);
+ QCOMPARE(centroidChangedSpy.size(), 2);
// the handler is not yet active, unless the drag threshold was already exceeded
QCOMPARE(dragHandler->active(), dragThreshold == 0);
p1 += QPoint(1, 0);
QTest::mouseMove(window, p1);
QTRY_VERIFY(dragHandler->active());
- QCOMPARE(translationChangedSpy.count(), dragThreshold ? 0 : 1);
- QCOMPARE(centroidChangedSpy.count(), 3);
+ QCOMPARE(translationChangedSpy.size(), dragThreshold ? 0 : 1);
+ if (!dragThreshold)
+ QCOMPARE(translationChangedSpy.first().first().value<QVector2D>(), QVector2D(2, 0));
+ QCOMPARE(xDeltaSpy.size(), dragThreshold ? 0 : 1);
+ QCOMPARE(centroidChangedSpy.size(), 3);
+#if QT_DEPRECATED_SINCE(6, 2)
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
QCOMPARE(dragHandler->translation().x(), dragThreshold ? 0 : 2);
+QT_WARNING_POP
+#endif
+ QCOMPARE(dragHandler->activeTranslation().x(), dragThreshold ? 0 : 2);
QPointF sceneGrabPos = dragThreshold ? p1 : p1 - QPoint(1, 0);
QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos);
p1 += QPoint(19, 0);
@@ -377,16 +443,26 @@ void tst_DragHandler::mouseDragThreshold()
QCOMPARE(dragHandler->centroid().scenePosition(), ball->mapToScene(ballCenter));
QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
QCOMPARE(dragHandler->centroid().sceneGrabPosition(), sceneGrabPos);
+#if QT_DEPRECATED_SINCE(6, 2)
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
QCOMPARE(dragHandler->translation().x(), dragThreshold + (dragThreshold ? 20 : 21));
QCOMPARE(dragHandler->translation().y(), 0.0);
+QT_WARNING_POP
+#endif
+ QCOMPARE(dragHandler->activeTranslation().x(), dragThreshold + (dragThreshold ? 20 : 21));
+ QCOMPARE(dragHandler->activeTranslation().y(), 0.0);
+ QCOMPARE(translationChangedSpy.size(), dragThreshold ? 1 : 2);
+ QCOMPARE(translationChangedSpy.first().first().value<QVector2D>(),
+ QVector2D(dragThreshold ? dragThreshold + 20 : 2, 0));
QVERIFY(dragHandler->centroid().velocity().x() > 0);
- QCOMPARE(centroidChangedSpy.count(), 4);
+ QCOMPARE(centroidChangedSpy.size(), 4);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(!dragHandler->active());
QCOMPARE(dragHandler->centroid().pressedButtons(), Qt::NoButton);
QCOMPARE(ball->mapToScene(ballCenter).toPoint(), p1);
- QCOMPARE(translationChangedSpy.count(), dragThreshold ? 1 : 2);
- QCOMPARE(centroidChangedSpy.count(), 5);
+ QCOMPARE(translationChangedSpy.size(), dragThreshold ? 1 : 2);
+ QCOMPARE(xDeltaSpy.size(), dragThreshold ? 1 : 2);
+ QCOMPARE(centroidChangedSpy.size(), 5);
}
void tst_DragHandler::dragFromMargin() // QTBUG-74966
@@ -416,8 +492,14 @@ void tst_DragHandler::dragFromMargin() // QTBUG-74966
QTRY_VERIFY(dragHandler->active());
QCOMPARE(dragHandler->centroid().scenePressPosition(), scenePressPos);
QCOMPARE(dragHandler->centroid().sceneGrabPosition(), p1);
+#if QT_DEPRECATED_SINCE(6, 2)
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
QCOMPARE(dragHandler->translation().x(), 0.0); // hmm that's odd
QCOMPARE(dragHandler->translation().y(), 0.0);
+QT_WARNING_POP
+#endif
+ QCOMPARE(dragHandler->activeTranslation().x(), 0.0); // hmm that's odd
+ QCOMPARE(dragHandler->activeTranslation().y(), 0.0);
QCOMPARE(draggableItem->position(), originalPos + QPointF(dragThreshold * 2, 0));
#if QT_CONFIG(cursor)
// The cursor doesn't change until the next event after the handler becomes active.
@@ -516,15 +598,17 @@ void tst_DragHandler::touchDragMulti()
QVERIFY(ball1);
QQuickDragHandler *dragHandler1 = ball1->findChild<QQuickDragHandler*>();
QVERIFY(dragHandler1);
- QSignalSpy translationChangedSpy1(dragHandler1, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy1(dragHandler1, &QQuickDragHandler::translationChanged);
QSignalSpy centroidChangedSpy1(dragHandler1, SIGNAL(centroidChanged()));
+ QSignalSpy xDeltaSpy1(dragHandler1->xAxis(), &QQuickDragAxis::activeValueChanged);
QQuickItem *ball2 = window->rootObject()->childItems().at(1);
QVERIFY(ball2);
QQuickDragHandler *dragHandler2 = ball2->findChild<QQuickDragHandler*>();
QVERIFY(dragHandler2);
- QSignalSpy translationChangedSpy2(dragHandler2, SIGNAL(translationChanged()));
+ QSignalSpy translationChangedSpy2(dragHandler2, &QQuickDragHandler::translationChanged);
QSignalSpy centroidChangedSpy2(dragHandler1, SIGNAL(centroidChanged()));
+ QSignalSpy yDeltaSpy2(dragHandler2->yAxis(), &QQuickDragAxis::activeValueChanged);
QPointF ball1Center = ball1->clipRect().center();
QPointF scenePressPos1 = ball1->mapToScene(ball1Center);
@@ -534,16 +618,18 @@ void tst_DragHandler::touchDragMulti()
QPoint p2 = scenePressPos2.toPoint();
QTest::QTouchEventSequence touchSeq = QTest::touchEvent(window, touchDevice, false);
- touchSeq.press(1, p1, window).press(2, p2, window).commit();
+ touchSeq.press(1, p1, window).commit();
+ QQuickTouchUtils::flush(window);
+ touchSeq.stationary(1).press(2, p2, window).commit();
QQuickTouchUtils::flush(window);
QVERIFY(!dragHandler1->active());
- QCOMPARE(centroidChangedSpy1.count(), 1);
+ QCOMPARE(centroidChangedSpy1.size(), 2);
QCOMPARE(dragHandler1->centroid().position(), ball1Center);
QCOMPARE(dragHandler1->centroid().pressPosition(), ball1Center);
QCOMPARE(dragHandler1->centroid().scenePosition(), scenePressPos1);
QCOMPARE(dragHandler1->centroid().scenePressPosition(), scenePressPos1);
QVERIFY(!dragHandler2->active());
- QCOMPARE(centroidChangedSpy2.count(), 1);
+ QCOMPARE(centroidChangedSpy2.size(), 2);
QCOMPARE(dragHandler2->centroid().position(), ball2Center);
QCOMPARE(dragHandler2->centroid().pressPosition(), ball2Center);
QCOMPARE(dragHandler2->centroid().scenePosition(), scenePressPos2);
@@ -553,13 +639,13 @@ void tst_DragHandler::touchDragMulti()
touchSeq.move(1, p1, window).move(2, p2, window).commit();
QQuickTouchUtils::flush(window);
QVERIFY(!dragHandler1->active());
- QCOMPARE(centroidChangedSpy1.count(), 2);
+ QCOMPARE(centroidChangedSpy1.size(), 3);
QCOMPARE(dragHandler1->centroid().position(), ball1Center + QPointF(dragThreshold, 0));
QCOMPARE(dragHandler1->centroid().pressPosition(), ball1Center);
QCOMPARE(dragHandler1->centroid().scenePosition().toPoint(), p1);
QCOMPARE(dragHandler1->centroid().scenePressPosition(), scenePressPos1);
QVERIFY(!dragHandler2->active());
- QCOMPARE(centroidChangedSpy2.count(), 2);
+ QCOMPARE(centroidChangedSpy2.size(), 3);
QCOMPARE(dragHandler2->centroid().position(), ball2Center + QPointF(0, dragThreshold));
QCOMPARE(dragHandler2->centroid().pressPosition(), ball2Center);
QCOMPARE(dragHandler2->centroid().scenePosition().toPoint(), p2);
@@ -570,8 +656,14 @@ void tst_DragHandler::touchDragMulti()
QQuickTouchUtils::flush(window);
QTRY_VERIFY(dragHandler1->active());
QVERIFY(dragHandler2->active());
- QCOMPARE(translationChangedSpy1.count(), 0);
+ QCOMPARE(translationChangedSpy1.size(), 0);
+ QCOMPARE(xDeltaSpy1.size(), 0);
+#if QT_DEPRECATED_SINCE(6, 2)
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
QCOMPARE(dragHandler1->translation().x(), 0.0);
+QT_WARNING_POP
+#endif
+ QCOMPARE(dragHandler1->activeTranslation().x(), 0.0);
QPointF sceneGrabPos1 = p1;
QPointF sceneGrabPos2 = p2;
QCOMPARE(dragHandler1->centroid().sceneGrabPosition(), sceneGrabPos1);
@@ -579,8 +671,14 @@ void tst_DragHandler::touchDragMulti()
p1 += QPoint(19, 0);
p2 += QPoint(0, 19);
QVERIFY(dragHandler2->active());
- QCOMPARE(translationChangedSpy2.count(), 0);
+ QCOMPARE(translationChangedSpy2.size(), 0);
+ QCOMPARE(yDeltaSpy2.size(), 0);
+#if QT_DEPRECATED_SINCE(6, 2)
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
QCOMPARE(dragHandler2->translation().x(), 0.0);
+QT_WARNING_POP
+#endif
+ QCOMPARE(dragHandler2->activeTranslation().x(), 0.0);
QCOMPARE(dragHandler2->centroid().sceneGrabPosition(), sceneGrabPos2);
touchSeq.move(1, p1, window).move(2, p2, window).commit();
QQuickTouchUtils::flush(window);
@@ -591,27 +689,47 @@ void tst_DragHandler::touchDragMulti()
QCOMPARE(dragHandler1->centroid().scenePosition(), ball1->mapToScene(ball1Center));
QCOMPARE(dragHandler1->centroid().scenePressPosition(), scenePressPos1);
QCOMPARE(dragHandler1->centroid().sceneGrabPosition(), sceneGrabPos1);
+#if QT_DEPRECATED_SINCE(6, 2)
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
QCOMPARE(dragHandler1->translation().x(), dragThreshold + 20.0);
QCOMPARE(dragHandler1->translation().y(), 0.0);
+QT_WARNING_POP
+#endif
+ QCOMPARE(dragHandler1->activeTranslation().x(), dragThreshold + 20.0);
+ QCOMPARE(dragHandler1->activeTranslation().y(), 0.0);
QCOMPARE(dragHandler2->centroid().position(), ball2Center);
QCOMPARE(dragHandler2->centroid().pressPosition(), ball2Center);
QCOMPARE(dragHandler2->centroid().scenePosition(), ball2->mapToScene(ball2Center));
QCOMPARE(dragHandler2->centroid().scenePressPosition(), scenePressPos2);
QCOMPARE(dragHandler2->centroid().sceneGrabPosition(), sceneGrabPos2);
+#if QT_DEPRECATED_SINCE(6, 2)
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
QCOMPARE(dragHandler2->translation().x(), 0.0);
QCOMPARE(dragHandler2->translation().y(), dragThreshold + 20.0);
+QT_WARNING_POP
+#endif
+ QCOMPARE(dragHandler2->activeTranslation().x(), 0.0);
+ QCOMPARE(dragHandler2->activeTranslation().y(), dragThreshold + 20.0);
+ QCOMPARE(xDeltaSpy1.size(), 1);
+ QCOMPARE(xDeltaSpy1.first().first().toReal(), dragThreshold + 20);
+ QCOMPARE(yDeltaSpy2.size(), 1);
+ QCOMPARE(yDeltaSpy2.first().first().toReal(), dragThreshold + 20);
+ QCOMPARE(translationChangedSpy1.size(), 1);
+ QCOMPARE(translationChangedSpy1.first().first().value<QVector2D>(), QVector2D(dragThreshold + 20, 0));
+ QCOMPARE(translationChangedSpy2.size(), 1);
+ QCOMPARE(translationChangedSpy2.first().first().value<QVector2D>(), QVector2D(0, dragThreshold + 20));
touchSeq.release(1, p1, window).stationary(2).commit();
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!dragHandler1->active());
QVERIFY(dragHandler2->active());
QCOMPARE(dragHandler1->centroid().pressedButtons(), Qt::NoButton);
QCOMPARE(ball1->mapToScene(ball1Center).toPoint(), p1);
- QCOMPARE(translationChangedSpy1.count(), 1);
+ QCOMPARE(translationChangedSpy1.size(), 1);
touchSeq.release(2, p2, window).commit();
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!dragHandler2->active());
QCOMPARE(ball2->mapToScene(ball2Center).toPoint(), p2);
- QCOMPARE(translationChangedSpy2.count(), 1);
+ QCOMPARE(translationChangedSpy2.size(), 1);
}
void tst_DragHandler::touchDragMultiSliders_data()
@@ -700,7 +818,7 @@ void tst_DragHandler::touchDragMultiSliders()
expectedEndPosition = startPoints[sli].toPoint();
qCDebug(lcPointerTests) << "slider " << knobs[sli]->objectName() << "started @" << startPoints[sli]
<< "tried to move by" << movements[sli] << "ended up @" << endPosition << "expected" << expectedEndPosition;
- QTRY_COMPARE(endPosition, expectedEndPosition);
+ QCOMPARE(endPosition, expectedEndPosition);
}
// Release
@@ -817,10 +935,198 @@ void tst_DragHandler::touchPinchAndMouseMove()
for (int i = 0; i < 10; ++i) {
p1 += delta;
QTest::mouseMove(window, p1);
- QCOMPARE(rectMovedSpy.count(), 0);
+ QCOMPARE(rectMovedSpy.size(), 0);
}
}
+void tst_DragHandler::unsuitableEventDuringDrag()
+{
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "dragAndWheel.qml");
+ QQuickView *window = windowPtr.data();
+ auto root = window->rootObject();
+ QQmlProperty changeCount(root, "changeCount");
+ QQmlProperty wheelHandlerEnabled(root, "wheelHandlerEnabled");
+ bool ok = false;
+ QCOMPARE(changeCount.read().toInt(&ok), 0);
+ QVERIFY(ok);
+ QCOMPARE(wheelHandlerEnabled.read().toBool(), true);
+
+ QPoint p1(100, 100);
+ QPoint p2(150, 150);
+
+ QTest::QTouchEventSequence touch = QTest::touchEvent(window, touchDevice);
+ // When we start dragging...
+ touch.press(3,p1).commit();
+ touch.move(3, p2).commit();
+ QQuickTouchUtils::flush(window);
+ // the DragHandler becomes active
+ ok = false;
+ QCOMPARE(changeCount.read().toInt(&ok), 1);
+ QVERIFY(ok);
+ QCOMPARE(wheelHandlerEnabled.read().toBool(), false);
+
+ // When a scroll event arrives while we are dragging
+ sendWheelEvent(*window, p2, QPoint(160, 120), QPoint(-360, 120), Qt::NoModifier, Qt::ScrollBegin, false);
+ // nothing changes because the DragHandler is still active, and the wheel handler stays disabled
+ ok = false;
+ QCOMPARE(changeCount.read().toInt(&ok), 1);
+ QVERIFY(ok);
+ QCOMPARE(wheelHandlerEnabled.read().toBool(), false);
+
+ // When we stop dragging...
+ touch.release(3, p2).commit();
+ QQuickTouchUtils::flush(window);
+
+ // the wheel handler becomes active again
+ ok = false;
+ QCOMPARE(changeCount.read().toInt(&ok), 2);
+ QVERIFY(ok);
+ QCOMPARE(wheelHandlerEnabled.read().toBool(), true);
+
+ // During the whole sequence the wheel handler never got a wheel event
+ // as it was disabled:
+ QQmlProperty gotWheel(root, "gotWheel");
+ QVERIFY(!gotWheel.read().toBool());
+
+ // If the WheelHandler is unconditionally enabled...
+ wheelHandlerEnabled.write(true);
+ // it receives scroll events during drags.
+ touch.press(4,p2).commit();
+ touch.move(4, p1).commit();
+ QQuickTouchUtils::flush(window);
+ sendWheelEvent(*window, p2, QPoint(160, 120), QPoint(-360, 120), Qt::NoModifier, Qt::ScrollBegin, false);
+ touch.release(4, p2).commit();
+ QQuickTouchUtils::flush(window);
+ QVERIFY(gotWheel.read().toBool());
+}
+
+void tst_DragHandler::sendWheelEvent(QQuickView &window, QPoint pos, QPoint angleDelta, QPoint pixelDelta, Qt::KeyboardModifiers modifiers, Qt::ScrollPhase phase, bool inverted)
+{
+ QWheelEvent wheelEvent(pos, window.mapToGlobal(pos), pixelDelta, angleDelta,
+ Qt::NoButton, modifiers, phase, inverted);
+ QGuiApplication::sendEvent(&window, &wheelEvent);
+ qApp->processEvents();
+ QQuickTouchUtils::flush(&window);
+}
+
+class ModalLayer : public QQuickItem {
+public:
+ explicit ModalLayer(QQuickItem* parent = nullptr) : QQuickItem(parent) {
+ this->setAcceptedMouseButtons(Qt::AllButtons);
+ this->setAcceptTouchEvents(true);
+ this->setKeepMouseGrab(true);
+ this->setKeepTouchGrab(true);
+ }
+
+ bool event(QEvent* event) override {
+ switch (event->type()) {
+ case QEvent::KeyPress:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseTrackingChange:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::Wheel:
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchCancel:
+ case QEvent::TouchEnd: {
+ qCDebug(lcPointerTests) << "BLOCK!" << event->type();
+ return true;
+ }
+ default: break;
+ }
+ return QQuickItem::event(event);
+ }
+};
+
+void tst_DragHandler::underModalLayer() // QTBUG-78258
+{
+ qmlRegisterType<ModalLayer>("Test", 1, 0, "ModalLayer");
+
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "dragHandlerUnderModalLayer.qml");
+ QQuickView * window = windowPtr.data();
+ QPointer<QQuickDragHandler> dragHandler = window->rootObject()->findChild<QQuickDragHandler*>();
+ QVERIFY(dragHandler);
+
+ QPoint p1(250, 250);
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
+ p1 += QPoint(dragThreshold, dragThreshold);
+ QTest::mouseMove(window, p1);
+ QVERIFY(!dragHandler->active());
+ p1 += QPoint(dragThreshold, dragThreshold);
+ QTest::mouseMove(window, p1);
+ QVERIFY(!dragHandler->active());
+ QTest::mouseRelease(window, Qt::LeftButton);
+}
+
+void tst_DragHandler::interruptedByIrrelevantButton() // QTBUG-102201
+{
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("draggables.qml")));
+
+ QQuickItem *ball = window.rootObject()->childItems().first();
+ QVERIFY(ball);
+ QQuickDragHandler *dragHandler = ball->findChild<QQuickDragHandler*>();
+ QVERIFY(dragHandler);
+
+ QCOMPARE(dragHandler->acceptedButtons(), Qt::LeftButton); // the default
+
+ QSignalSpy translationChangedSpy(dragHandler, &QQuickDragHandler::translationChanged);
+ QSignalSpy cancelSpy(dragHandler, &QQuickDragHandler::canceled);
+ QSignalSpy activeSpy(dragHandler, &QQuickDragHandler::activeChanged);
+ QSignalSpy grabSpy(dragHandler, &QQuickDragHandler::grabChanged);
+
+ QPoint p1 = ball->mapToScene(ball->clipRect().center()).toPoint();
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p1);
+ QCOMPARE(grabSpy.size(), 1); // passive grab
+ p1 += QPoint(dragThreshold + 1, 0);
+ QTest::mouseMove(&window, p1);
+ QVERIFY(dragHandler->active());
+ QCOMPARE(activeSpy.size(), 1);
+ QCOMPARE(grabSpy.size(), 2); // exclusive grab
+ QCOMPARE(translationChangedSpy.size(), 0);
+ p1 += QPoint(1, 0);
+ QTest::mouseMove(&window, p1);
+ QCOMPARE(translationChangedSpy.size(), 1);
+
+ // Left button is already held, now press right button too (chording)
+ QTest::mousePress(&window, Qt::RightButton, Qt::NoModifier, p1);
+ // DragHandler will ungrab and deactivate, but not cancel
+ QCOMPARE(dragHandler->active(), false);
+ QCOMPARE(translationChangedSpy.size(), 1);
+ QCOMPARE(cancelSpy.size(), 0);
+ QCOMPARE(activeSpy.size(), 2);
+ QCOMPARE_GT(grabSpy.size(), 2); // lost grabs
+
+ // Release right button: no change in state
+ QTest::mouseRelease(&window, Qt::RightButton, Qt::NoModifier, p1);
+ QCOMPARE(dragHandler->active(), false);
+ QCOMPARE(translationChangedSpy.size(), 1);
+ QCOMPARE(cancelSpy.size(), 0);
+ QCOMPARE(activeSpy.size(), 2);
+ auto grabChangedCount = grabSpy.size();
+
+ // But the left button is still held, and it's possible to resume dragging
+ p1 += QPoint(dragThreshold + 1, 0);
+ QTest::mouseMove(&window, p1);
+ QCOMPARE_GT(grabSpy.size(), grabChangedCount); // re-grabbed
+ p1 += QPoint(1, 0);
+ QTest::mouseMove(&window, p1);
+ QVERIFY(dragHandler->active());
+ QCOMPARE(activeSpy.size(), 3);
+ QCOMPARE(translationChangedSpy.size(), 2);
+
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p1);
+ QVERIFY(!dragHandler->active());
+ QCOMPARE(activeSpy.size(), 4);
+ QCOMPARE(cancelSpy.size(), 0); // none of this caused a canceled() signal
+}
+
QTEST_MAIN(tst_DragHandler)
#include "tst_qquickdraghandler.moc"
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST b/tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST
index 9bb35c4770..c0d73ff05f 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/BLACKLIST
@@ -1,3 +1,8 @@
[movingItemWithHoverHandler]
macos # Can't move cursor (QTBUG-76312)
+# QTBUG-103065
+[movingItemWithHoverHandler]
+android
+[window]
+opensuse-leap # QTBUG-122405
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/CMakeLists.txt b/tests/auto/quick/pointerhandlers/qquickhoverhandler/CMakeLists.txt
index 654bf1c366..a2e7d640d5 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/CMakeLists.txt
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickhoverhandler.pro.
#####################################################################
## tst_qquickhoverhandler Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickhoverhandler LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickhoverhandler
SOURCES
- ../../../shared/util.cpp ../../../shared/util.h
- ../../shared/geometrytestutil.cpp ../../shared/geometrytestutil.h
- ../../shared/viewtestutil.cpp ../../shared/viewtestutil.h
- ../../shared/visualtestutil.cpp ../../shared/visualtestutil.h
tst_qquickhoverhandler.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -38,10 +40,10 @@ qt_internal_add_test(tst_qquickhoverhandler
qt_internal_extend_target(tst_qquickhoverhandler CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickhoverhandler CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/changingCursor.qml b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/changingCursor.qml
new file mode 100644
index 0000000000..42b658a4d4
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/changingCursor.qml
@@ -0,0 +1,37 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.15
+
+
+Rectangle {
+ id: brownRect
+ objectName: "brownRect"
+
+ width: 400
+ height: 400
+
+ HoverHandler {
+ id: hh
+ cursorShape: parent.colorIndex == 0 ?
+ Qt.CrossCursor :
+ Qt.OpenHandCursor
+ }
+
+ property list<color> colors: ["beige", "brown"]
+ property int colorIndex: 0
+
+ color: colors[colorIndex]
+
+ Timer {
+ id: colorTimer
+ interval: 200
+ running: true
+ repeat: true
+
+ onTriggered: {
+ parent.colorIndex = (parent.colorIndex + 1) % parent.colors.length;
+ parent.color = parent.colors[parent.colorIndex];
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverDeviceCursors.qml b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverDeviceCursors.qml
new file mode 100644
index 0000000000..48e130a35e
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverDeviceCursors.qml
@@ -0,0 +1,55 @@
+import QtQuick
+
+Item {
+ width: 200; height: 200
+
+ Rectangle {
+ width: 100; height: 100
+ anchors.centerIn: parent
+ border.color: "black"
+
+ HoverHandler {
+ objectName: "stylus"
+ acceptedDevices: PointerDevice.Stylus
+ acceptedPointerTypes: PointerDevice.Pen
+ cursorShape: Qt.CrossCursor
+ }
+
+ HoverHandler {
+ objectName: "stylus eraser"
+ acceptedDevices: PointerDevice.Stylus
+ acceptedPointerTypes: PointerDevice.Eraser
+ cursorShape: Qt.PointingHandCursor
+ }
+
+ HoverHandler {
+ objectName: "airbrush"
+ acceptedDevices: PointerDevice.Airbrush
+ acceptedPointerTypes: PointerDevice.Pen
+ cursorShape: Qt.BusyCursor
+ }
+
+ HoverHandler {
+ objectName: "airbrush eraser"
+ acceptedDevices: PointerDevice.Airbrush
+ acceptedPointerTypes: PointerDevice.Eraser
+ cursorShape: Qt.OpenHandCursor
+ }
+
+ HoverHandler {
+ objectName: "mouse"
+ acceptedDevices: PointerDevice.Mouse
+ // acceptedPointerTypes can be omitted because Mouse is not ambiguous.
+ // When a genuine mouse move is sent, there's a conflict, and this one should win.
+ cursorShape: Qt.IBeamCursor
+ }
+
+ HoverHandler {
+ objectName: "conflictingMouse"
+ acceptedDevices: PointerDevice.Mouse
+ // acceptedPointerTypes can be omitted because Mouse is not ambiguous.
+ // When a genuine mouse move is sent, there's a conflict, and this one should lose.
+ cursorShape: Qt.ClosedHandCursor
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverHandler.qml b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverHandler.qml
new file mode 100644
index 0000000000..60dfc53c40
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/hoverHandler.qml
@@ -0,0 +1,17 @@
+import QtQuick
+
+Item {
+ width: 320
+ height: 240
+
+ Rectangle {
+ width: 100
+ height: 100
+ anchors.centerIn: parent
+ color: hh.hovered ? "lightsteelblue" : "beige"
+
+ HoverHandler {
+ id: hh
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml
index 38a19c57c5..ca30a7fe99 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/lesHoverables.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.15
@@ -34,59 +9,96 @@ Rectangle {
height: 480
color: "#444"
- Component {
- id: buttonsAndStuff
- Column {
- anchors.fill: parent
- anchors.margins: 8
- spacing: 8
-
- Rectangle {
- objectName: "buttonWithMA"
- width: parent.width
- height: 30
- color: buttonMA.pressed ? "lightsteelblue" : "#999"
- border.color: buttonMA.containsMouse ? "cyan" : "transparent"
-
- MouseArea {
- id: buttonMA
- objectName: "buttonMA"
- hoverEnabled: true
- cursorShape: Qt.UpArrowCursor
- anchors.fill: parent
- onClicked: console.log("clicked MA")
- }
+ component CheckBox: Row {
+ id: cbRoot
+ property bool checked : true
+ property string label : "CheckBox"
+ spacing: 4
+ Rectangle {
+ width: 16; height: 16
+ // comment out this color change to test whether we rely on "dirty" items to
+ // trigger QQuickDeliveryAgentPrivate::flushFrameSynchronousEvents() to update hover state
+ color: cbRoot.checked ? "cadetblue" : "transparent"
+ border.color: "black"
+ TapHandler { onTapped: cbRoot.checked = !cbRoot.checked }
+ }
+ Text { text: cbRoot.label }
+ }
- Text {
- anchors.centerIn: parent
- text: "MouseArea"
- }
+ component ButtonsAndStuff: Column {
+ anchors.fill: parent
+ anchors.margins: 8
+ spacing: 8
+ function toggleMAEnabled() { maButtonCB.checked = !maButtonCB.checked }
+ function toggleMAHover() { maButtonHoverCB.checked = !maButtonHoverCB.checked }
+ function toggleHHEnabled() { hhButtonHoverCB.checked = !hhButtonHoverCB.checked }
+
+ CheckBox {
+ id: maButtonCB
+ label: "enabled"
+ }
+
+ CheckBox {
+ id: maButtonHoverCB
+ label: "hover enabled"
+ }
+
+ Rectangle {
+ objectName: "buttonWithMA"
+ width: parent.width
+ height: 30
+ color: buttonMA.pressed ? "lightsteelblue" : "#999"
+ border.color: buttonMA.containsMouse ? "cyan" : "transparent"
+
+ MouseArea {
+ id: buttonMA
+ objectName: "buttonMA"
+ enabled: maButtonCB.checked
+ hoverEnabled: maButtonHoverCB.checked
+ cursorShape: Qt.UpArrowCursor
+ anchors.fill: parent
}
- Rectangle {
- objectName: "buttonWithHH"
- width: parent.width
- height: 30
- color: flash ? "#999" : "white"
- border.color: buttonHH.hovered ? "cyan" : "transparent"
- property bool flash: true
-
- HoverHandler {
- id: buttonHH
- objectName: "buttonHH"
- acceptedDevices: PointerDevice.AllDevices
- cursorShape: tapHandler.pressed ? Qt.BusyCursor : Qt.PointingHandCursor
- }
+ Text {
+ anchors.centerIn: parent
+ text: "MouseArea"
+ }
+ }
- TapHandler {
- id: tapHandler
- }
+ CheckBox {
+ id: hhButtonHoverCB
+ label: "hover enabled"
+ }
+
+ Rectangle {
+ id: buttonRoot
+ objectName: "buttonWithHH"
+ width: parent.width
+ height: 30
+ color: flash ? "#999" : "white"
+ border.color: buttonHH.hovered ? "cyan" : "transparent"
+ property bool flash: true
+
+ HoverHandler {
+ id: buttonHH
+ objectName: "buttonHH"
+ acceptedDevices: PointerDevice.AllDevices
+ enabled: hhButtonHoverCB.checked
+ cursorShape: tapHandler.pressed ? Qt.BusyCursor : Qt.PointingHandCursor
+ }
- Text {
- anchors.centerIn: parent
- text: "HoverHandler"
+ TapHandler {
+ id: tapHandler
+ onTapped: {
+ console.log("buttonRoot tapped")
+ buttonHH.enabled = !buttonHH.enabled
}
}
+
+ Text {
+ anchors.centerIn: parent
+ text: "HoverHandler"
+ }
}
}
@@ -134,10 +146,22 @@ Rectangle {
cursorShape: Qt.OpenHandCursor
}
- Loader {
- objectName: "topSidebarLoader"
- sourceComponent: buttonsAndStuff
+ ButtonsAndStuff {
+ id: tbs
+ objectName: "topSidebarContents"
anchors.fill: parent
+ Shortcut {
+ sequence: "Ctrl+E"
+ onActivated: tbs.toggleMAEnabled()
+ }
+ Shortcut {
+ sequence: "Ctrl+M"
+ onActivated: tbs.toggleMAHover()
+ }
+ Shortcut {
+ sequence: "Ctrl+H"
+ onActivated: tbs.toggleHHEnabled()
+ }
}
}
@@ -161,9 +185,8 @@ Rectangle {
anchors.fill: parent
}
- Loader {
- objectName: "bottomSidebarLoader"
- sourceComponent: buttonsAndStuff
+ ButtonsAndStuff {
+ objectName: "bottomSidebarContents"
anchors.fill: parent
}
}
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/nohandler.qml b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/nohandler.qml
new file mode 100644
index 0000000000..ed3728e278
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/nohandler.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.15
+import QtQuick.Window 2.15
+
+Window {
+ width: 320
+ height: 240
+ visible: true
+
+ Rectangle {
+ objectName: "childItem"
+ width: 100
+ height: 100
+ color: "lightblue"
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/windowCursorShape.qml b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/windowCursorShape.qml
new file mode 100644
index 0000000000..b5c1f3d2ef
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/data/windowCursorShape.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.15
+import QtQuick.Window 2.15
+
+Window {
+ width: 320
+ height: 240
+ visible: true
+ color: hh.hovered ? "lightsteelblue" : "beige"
+ HoverHandler {
+ id: hh
+ cursorShape: Qt.OpenHandCursor
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
index 11a5393390..0569fed472 100644
--- a/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickhoverhandler/tst_qquickhoverhandler.cpp
@@ -1,36 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/private/qquickhoverhandler_p.h>
+#include <QtQuick/private/qquickpointerhandler_p_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
#include <qpa/qwindowsysteminterface.h>
@@ -38,9 +14,10 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlproperty.h>
+#include <QQmlComponent>
-#include "../../../shared/util.h"
-#include "../../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests")
@@ -54,17 +31,30 @@ class tst_HoverHandler : public QQmlDataTest
Q_OBJECT
public:
tst_HoverHandler()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{}
private slots:
+ void hoverHandlerAndUnderlyingHoverHandler_data();
void hoverHandlerAndUnderlyingHoverHandler();
void mouseAreaAndUnderlyingHoverHandler();
void hoverHandlerAndUnderlyingMouseArea();
+ void disabledHoverHandlerAndUnderlyingMouseArea();
+ void hoverHandlerOnDisabledItem();
void movingItemWithHoverHandler();
void margin();
+ void window();
+ void deviceCursor_data();
+ void deviceCursor();
+ void addHandlerFromCpp();
+ void ensureHoverHandlerWorksWhenItemHasHoverDisabled();
+ void changeCursor();
+ void touchDrag();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
+
+ QScopedPointer<QPointingDevice> touchscreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
};
void tst_HoverHandler::createView(QScopedPointer<QQuickView> &window, const char *fileName)
@@ -72,16 +62,26 @@ void tst_HoverHandler::createView(QScopedPointer<QQuickView> &window, const char
window.reset(new QQuickView);
window->setSource(testFileUrl(fileName));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
}
+void tst_HoverHandler::hoverHandlerAndUnderlyingHoverHandler_data()
+{
+ QTest::addColumn<bool>("blocking");
+
+ QTest::newRow("default: nonblocking") << false;
+ QTest::newRow("blocking") << true;
+}
+
void tst_HoverHandler::hoverHandlerAndUnderlyingHoverHandler()
{
+ QFETCH(bool, blocking);
+
QScopedPointer<QQuickView> windowPtr;
createView(windowPtr, "lesHoverables.qml");
QQuickView * window = windowPtr.data();
@@ -94,6 +94,9 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingHoverHandler()
QQuickHoverHandler *buttonHH = button->findChild<QQuickHoverHandler *>("buttonHH");
QVERIFY(buttonHH);
+ QCOMPARE(buttonHH->isBlocking(), false); // default property value
+ buttonHH->setBlocking(blocking);
+
QPoint buttonCenter(button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint());
QPoint rightOfButton(button->mapToScene(QPointF(button->width() + 2, button->height() / 2)).toPoint());
QPoint outOfSidebar(topSidebar->mapToScene(QPointF(topSidebar->width() + 2, topSidebar->height() / 2)).toPoint());
@@ -102,45 +105,45 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingHoverHandler()
QTest::mouseMove(window, outOfSidebar);
QCOMPARE(topSidebarHH->isHovered(), false);
- QCOMPARE(sidebarHoveredSpy.count(), 0);
+ QCOMPARE(sidebarHoveredSpy.size(), 0);
QCOMPARE(buttonHH->isHovered(), false);
- QCOMPARE(buttonHoveredSpy.count(), 0);
+ QCOMPARE(buttonHoveredSpy.size(), 0);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
#endif
QTest::mouseMove(window, rightOfButton);
QCOMPARE(topSidebarHH->isHovered(), true);
- QCOMPARE(sidebarHoveredSpy.count(), 1);
+ QCOMPARE(sidebarHoveredSpy.size(), 1);
QCOMPARE(buttonHH->isHovered(), false);
- QCOMPARE(buttonHoveredSpy.count(), 0);
+ QCOMPARE(buttonHoveredSpy.size(), 0);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::OpenHandCursor);
#endif
QTest::mouseMove(window, buttonCenter);
- QCOMPARE(topSidebarHH->isHovered(), true);
- QCOMPARE(sidebarHoveredSpy.count(), 1);
+ QCOMPARE(topSidebarHH->isHovered(), !blocking);
+ QCOMPARE(sidebarHoveredSpy.size(), blocking ? 2 : 1);
QCOMPARE(buttonHH->isHovered(), true);
- QCOMPARE(buttonHoveredSpy.count(), 1);
+ QCOMPARE(buttonHoveredSpy.size(), 1);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::PointingHandCursor);
#endif
QTest::mouseMove(window, rightOfButton);
QCOMPARE(topSidebarHH->isHovered(), true);
- QCOMPARE(sidebarHoveredSpy.count(), 1);
+ QCOMPARE(sidebarHoveredSpy.size(), blocking ? 3 : 1);
QCOMPARE(buttonHH->isHovered(), false);
- QCOMPARE(buttonHoveredSpy.count(), 2);
+ QCOMPARE(buttonHoveredSpy.size(), 2);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::OpenHandCursor);
#endif
QTest::mouseMove(window, outOfSidebar);
QCOMPARE(topSidebarHH->isHovered(), false);
- QCOMPARE(sidebarHoveredSpy.count(), 2);
+ QCOMPARE(sidebarHoveredSpy.size(), blocking ? 4 : 2);
QCOMPARE(buttonHH->isHovered(), false);
- QCOMPARE(buttonHoveredSpy.count(), 2);
+ QCOMPARE(buttonHoveredSpy.size(), 2);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
#endif
@@ -158,6 +161,13 @@ void tst_HoverHandler::mouseAreaAndUnderlyingHoverHandler()
QQuickHoverHandler *topSidebarHH = topSidebar->findChild<QQuickHoverHandler *>("topSidebarHH");
QVERIFY(topSidebarHH);
+ // Ensure that we don't get extra hover events delivered on the
+ // side, since it can affect the number of hover move events we receive below.
+ QQuickWindowPrivate::get(window)->deliveryAgentPrivate()->frameSynchronousHoverEnabled = false;
+ // And flush out any mouse events that might be queued up
+ // in QPA, since QTest::mouseMove() calls processEvents.
+ qGuiApp->processEvents();
+
QPoint buttonCenter(buttonMA->mapToScene(QPointF(buttonMA->width() / 2, buttonMA->height() / 2)).toPoint());
QPoint rightOfButton(buttonMA->mapToScene(QPointF(buttonMA->width() + 2, buttonMA->height() / 2)).toPoint());
QPoint outOfSidebar(topSidebar->mapToScene(QPointF(topSidebar->width() + 2, topSidebar->height() / 2)).toPoint());
@@ -166,45 +176,45 @@ void tst_HoverHandler::mouseAreaAndUnderlyingHoverHandler()
QTest::mouseMove(window, outOfSidebar);
QCOMPARE(topSidebarHH->isHovered(), false);
- QCOMPARE(sidebarHoveredSpy.count(), 0);
+ QCOMPARE(sidebarHoveredSpy.size(), 0);
QCOMPARE(buttonMA->hovered(), false);
- QCOMPARE(buttonHoveredSpy.count(), 0);
+ QCOMPARE(buttonHoveredSpy.size(), 0);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
#endif
QTest::mouseMove(window, rightOfButton);
QCOMPARE(topSidebarHH->isHovered(), true);
- QCOMPARE(sidebarHoveredSpy.count(), 1);
+ QCOMPARE(sidebarHoveredSpy.size(), 1);
QCOMPARE(buttonMA->hovered(), false);
- QCOMPARE(buttonHoveredSpy.count(), 0);
+ QCOMPARE(buttonHoveredSpy.size(), 0);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::OpenHandCursor);
#endif
QTest::mouseMove(window, buttonCenter);
QCOMPARE(topSidebarHH->isHovered(), true);
- QCOMPARE(sidebarHoveredSpy.count(), 1);
+ QCOMPARE(sidebarHoveredSpy.size(), 1);
QCOMPARE(buttonMA->hovered(), true);
- QCOMPARE(buttonHoveredSpy.count(), 1);
+ QCOMPARE(buttonHoveredSpy.size(), 1);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::UpArrowCursor);
#endif
QTest::mouseMove(window, rightOfButton);
QCOMPARE(topSidebarHH->isHovered(), true);
- QCOMPARE(sidebarHoveredSpy.count(), 1);
+ QCOMPARE(sidebarHoveredSpy.size(), 1);
QCOMPARE(buttonMA->hovered(), false);
- QCOMPARE(buttonHoveredSpy.count(), 2);
+ QCOMPARE(buttonHoveredSpy.size(), 2);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::OpenHandCursor);
#endif
QTest::mouseMove(window, outOfSidebar);
QCOMPARE(topSidebarHH->isHovered(), false);
- QCOMPARE(sidebarHoveredSpy.count(), 2);
+ QCOMPARE(sidebarHoveredSpy.size(), 2);
QCOMPARE(buttonMA->hovered(), false);
- QCOMPARE(buttonHoveredSpy.count(), 2);
+ QCOMPARE(buttonHoveredSpy.size(), 2);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
#endif
@@ -232,50 +242,131 @@ void tst_HoverHandler::hoverHandlerAndUnderlyingMouseArea()
QTest::mouseMove(window, outOfSidebar);
QCOMPARE(bottomSidebarMA->hovered(), false);
- QCOMPARE(sidebarHoveredSpy.count(), 0);
+ QCOMPARE(sidebarHoveredSpy.size(), 0);
QCOMPARE(buttonHH->isHovered(), false);
- QCOMPARE(buttonHoveredSpy.count(), 0);
+ QCOMPARE(buttonHoveredSpy.size(), 0);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
#endif
QTest::mouseMove(window, rightOfButton);
QCOMPARE(bottomSidebarMA->hovered(), true);
- QCOMPARE(sidebarHoveredSpy.count(), 1);
+ QCOMPARE(sidebarHoveredSpy.size(), 1);
QCOMPARE(buttonHH->isHovered(), false);
- QCOMPARE(buttonHoveredSpy.count(), 0);
+ QCOMPARE(buttonHoveredSpy.size(), 0);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::ClosedHandCursor);
#endif
QTest::mouseMove(window, buttonCenter);
QCOMPARE(bottomSidebarMA->hovered(), false);
- QCOMPARE(sidebarHoveredSpy.count(), 2);
+ QCOMPARE(sidebarHoveredSpy.size(), 2);
QCOMPARE(buttonHH->isHovered(), true);
- QCOMPARE(buttonHoveredSpy.count(), 1);
+ QCOMPARE(buttonHoveredSpy.size(), 1);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::PointingHandCursor);
#endif
QTest::mouseMove(window, rightOfButton);
QCOMPARE(bottomSidebarMA->hovered(), true);
- QCOMPARE(sidebarHoveredSpy.count(), 3);
+ QCOMPARE(sidebarHoveredSpy.size(), 3);
QCOMPARE(buttonHH->isHovered(), false);
- QCOMPARE(buttonHoveredSpy.count(), 2);
+ QCOMPARE(buttonHoveredSpy.size(), 2);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::ClosedHandCursor);
#endif
QTest::mouseMove(window, outOfSidebar);
QCOMPARE(bottomSidebarMA->hovered(), false);
- QCOMPARE(sidebarHoveredSpy.count(), 4);
+ QCOMPARE(sidebarHoveredSpy.size(), 4);
QCOMPARE(buttonHH->isHovered(), false);
- QCOMPARE(buttonHoveredSpy.count(), 2);
+ QCOMPARE(buttonHoveredSpy.size(), 2);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
#endif
}
+void tst_HoverHandler::disabledHoverHandlerAndUnderlyingMouseArea()
+{
+ // Check that if a disabled HoverHandler is installed on an item, it
+ // will not participate in hover event delivery, and as such, also
+ // not block propagation to siblings.
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "lesHoverables.qml");
+ QQuickView * window = windowPtr.data();
+ QQuickItem * bottomSidebar = window->rootObject()->findChild<QQuickItem *>("bottomSidebar");
+ QVERIFY(bottomSidebar);
+ QQuickMouseArea *bottomSidebarMA = bottomSidebar->findChild<QQuickMouseArea *>("bottomSidebarMA");
+ QVERIFY(bottomSidebarMA);
+ QQuickItem * button = bottomSidebar->findChild<QQuickItem *>("buttonWithHH");
+ QVERIFY(button);
+ QQuickHoverHandler *buttonHH = button->findChild<QQuickHoverHandler *>("buttonHH");
+ QVERIFY(buttonHH);
+
+ // By disabling the HoverHandler, it should no longer
+ // block the sibling MouseArea underneath from receiving hover events.
+ buttonHH->setEnabled(false);
+
+ QPoint buttonCenter(button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint());
+ QPoint rightOfButton(button->mapToScene(QPointF(button->width() + 2, button->height() / 2)).toPoint());
+ QPoint outOfSidebar(bottomSidebar->mapToScene(QPointF(bottomSidebar->width() + 2, bottomSidebar->height() / 2)).toPoint());
+ QSignalSpy sidebarHoveredSpy(bottomSidebarMA, SIGNAL(hoveredChanged()));
+ QSignalSpy buttonHoveredSpy(buttonHH, SIGNAL(hoveredChanged()));
+
+ QTest::mouseMove(window, outOfSidebar);
+ QCOMPARE(bottomSidebarMA->hovered(), false);
+ QCOMPARE(sidebarHoveredSpy.size(), 0);
+ QCOMPARE(buttonHH->isHovered(), false);
+ QCOMPARE(buttonHoveredSpy.size(), 0);
+
+ QTest::mouseMove(window, buttonCenter);
+ QCOMPARE(bottomSidebarMA->hovered(), true);
+ QCOMPARE(sidebarHoveredSpy.size(), 1);
+ QCOMPARE(buttonHH->isHovered(), false);
+ QCOMPARE(buttonHoveredSpy.size(), 0);
+
+ QTest::mouseMove(window, rightOfButton);
+ QCOMPARE(bottomSidebarMA->hovered(), true);
+ QCOMPARE(sidebarHoveredSpy.size(), 1);
+ QCOMPARE(buttonHH->isHovered(), false);
+ QCOMPARE(buttonHoveredSpy.size(), 0);
+}
+
+void tst_HoverHandler::hoverHandlerOnDisabledItem()
+{
+ // Check that if HoverHandler on a disabled item will
+ // continue to receive hover events (QTBUG-30801)
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "lesHoverables.qml");
+ QQuickView * window = windowPtr.data();
+ QQuickItem * bottomSidebar = window->rootObject()->findChild<QQuickItem *>("bottomSidebar");
+ QVERIFY(bottomSidebar);
+ QQuickItem * button = bottomSidebar->findChild<QQuickItem *>("buttonWithHH");
+ QVERIFY(button);
+ QQuickHoverHandler *buttonHH = button->findChild<QQuickHoverHandler *>("buttonHH");
+ QVERIFY(buttonHH);
+
+ // Disable the button/rectangle item. This should not
+ // block its HoverHandler from being hovered
+ button->setEnabled(false);
+
+ QPoint buttonCenter(button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint());
+ QPoint rightOfButton(button->mapToScene(QPointF(button->width() + 2, button->height() / 2)).toPoint());
+ QSignalSpy buttonHoveredSpy(buttonHH, SIGNAL(hoveredChanged()));
+
+ QTest::mouseMove(window, rightOfButton);
+ QCOMPARE(buttonHH->isHovered(), false);
+ QCOMPARE(buttonHoveredSpy.size(), 0);
+
+ QTest::mouseMove(window, buttonCenter);
+ QCOMPARE(buttonHH->isHovered(), true);
+ QCOMPARE(buttonHoveredSpy.size(), 1);
+
+ QTest::mouseMove(window, rightOfButton);
+ QCOMPARE(buttonHH->isHovered(), false);
+ QCOMPARE(buttonHoveredSpy.size(), 2);
+}
+
void tst_HoverHandler::movingItemWithHoverHandler()
{
if (isPlatformWayland())
@@ -306,7 +397,7 @@ void tst_HoverHandler::movingItemWithHoverHandler()
paddle->setX(100);
QTRY_COMPARE(paddleHH->isHovered(), false);
- paddle->setX(p.x());
+ paddle->setX(p.x() - paddle->width() / 2);
QTRY_COMPARE(paddleHH->isHovered(), true);
paddle->setX(540);
@@ -329,21 +420,21 @@ void tst_HoverHandler::margin() // QTBUG-85303
QTest::mouseMove(window, {10, 10});
QCOMPARE(hh->isHovered(), false);
- QCOMPARE(hoveredSpy.count(), 0);
+ QCOMPARE(hoveredSpy.size(), 0);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::ArrowCursor);
#endif
QTest::mouseMove(window, leftMargin);
QCOMPARE(hh->isHovered(), true);
- QCOMPARE(hoveredSpy.count(), 1);
+ QCOMPARE(hoveredSpy.size(), 1);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::OpenHandCursor);
#endif
QTest::mouseMove(window, itemCenter);
QCOMPARE(hh->isHovered(), true);
- QCOMPARE(hoveredSpy.count(), 1);
+ QCOMPARE(hoveredSpy.size(), 1);
#if QT_CONFIG(cursor)
QCOMPARE(window->cursor().shape(), Qt::OpenHandCursor);
#endif
@@ -363,6 +454,306 @@ void tst_HoverHandler::margin() // QTBUG-85303
#endif
}
+void tst_HoverHandler::window() // QTBUG-98717
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("windowCursorShape.qml"));
+ QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(component.create()));
+ QVERIFY(!window.isNull());
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+#if QT_CONFIG(cursor)
+ if (isPlatformWayland())
+ QSKIP("Wayland: QCursor::setPos() doesn't work.");
+ auto cursorPos = window->mapToGlobal(QPoint(100, 100));
+ qCDebug(lcPointerTests) << "in window @" << window->position() << "setting cursor pos" << cursorPos;
+ QCursor::setPos(cursorPos);
+ if (!QTest::qWaitFor([cursorPos]{ return QCursor::pos() == cursorPos; }))
+ QSKIP("QCursor::setPos() doesn't work (QTBUG-76312).");
+ QTRY_COMPARE(window->cursor().shape(), Qt::OpenHandCursor);
+#endif
+}
+
+void tst_HoverHandler::deviceCursor_data()
+{
+ QTest::addColumn<bool>("synthMouseForTabletEvents");
+ QTest::addColumn<bool>("earlierTabletBeforeMouse");
+
+ QTest::newRow("nosynth, tablet wins") << false << false;
+ QTest::newRow("synth, tablet wins") << true << false;
+ QTest::newRow("synth, mouse wins") << true << true;
+}
+
+void tst_HoverHandler::deviceCursor()
+{
+#if !QT_CONFIG(tabletevent)
+ QSKIP("This test depends on QTabletEvent delivery.");
+#endif
+ QFETCH(bool, synthMouseForTabletEvents);
+ QFETCH(bool, earlierTabletBeforeMouse);
+ qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents, synthMouseForTabletEvents);
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("hoverDeviceCursors.qml")));
+ // Ensure that we don't get extra hover events delivered on the side
+ QQuickWindowPrivate::get(&window)->deliveryAgentPrivate()->frameSynchronousHoverEnabled = false;
+ // And flush out any mouse events that might be queued up in QPA, since QTest::mouseMove() calls processEvents.
+ qGuiApp->processEvents();
+ const QQuickItem *root = window.rootObject();
+ QQuickHoverHandler *stylusHandler = root->findChild<QQuickHoverHandler *>("stylus");
+ QVERIFY(stylusHandler);
+ QQuickHoverHandler *eraserHandler = root->findChild<QQuickHoverHandler *>("stylus eraser");
+ QVERIFY(eraserHandler);
+ QQuickHoverHandler *aibrushHandler = root->findChild<QQuickHoverHandler *>("airbrush");
+ QVERIFY(aibrushHandler);
+ QQuickHoverHandler *airbrushEraserHandler = root->findChild<QQuickHoverHandler *>("airbrush eraser");
+ QVERIFY(airbrushEraserHandler);
+ QQuickHoverHandler *mouseHandler = root->findChild<QQuickHoverHandler *>("mouse");
+ QVERIFY(mouseHandler);
+
+ QPoint point(100, 100);
+
+ const qint64 stylusId = 1234567890;
+ QElapsedTimer timer;
+ timer.start();
+ auto testStylusDevice = [&](QInputDevice::DeviceType dt, QPointingDevice::PointerType pt,
+ Qt::CursorShape expectedCursor, QQuickHoverHandler* expectedActiveHandler) {
+ // We will follow up with a mouse event afterwards, and we want to simulate that the tablet events occur
+ // either slightly before (earlierTabletBeforeMouse == true) or some time before.
+ // It turns out that the first mouse move happens at timestamp 501 (simulated).
+ const ulong timestamp = (earlierTabletBeforeMouse ? 0 : 400) + timer.elapsed();
+ qCDebug(lcPointerTests) << "@" << timestamp << "sending" << dt << pt << "expecting" << expectedCursor << expectedActiveHandler->objectName();
+ QWindowSystemInterface::handleTabletEvent(&window, timestamp, point, window.mapToGlobal(point),
+ int(dt), int(pt), Qt::NoButton, 0, 0, 0, 0, 0, 0, stylusId, Qt::NoModifier);
+ point += QPoint(1, 0);
+#if QT_CONFIG(cursor)
+ // QQuickItem::setCursor() doesn't get called: we only have HoverHandlers in this test
+ QCOMPARE(root->cursor().shape(), Qt::ArrowCursor);
+ QTRY_COMPARE(window.cursor().shape(), expectedCursor);
+#endif
+ QCOMPARE(stylusHandler->isHovered(), stylusHandler == expectedActiveHandler);
+ QCOMPARE(eraserHandler->isHovered(), eraserHandler == expectedActiveHandler);
+ QCOMPARE(aibrushHandler->isHovered(), aibrushHandler == expectedActiveHandler);
+ QCOMPARE(airbrushEraserHandler->isHovered(), airbrushEraserHandler == expectedActiveHandler);
+ };
+
+ // simulate move events from various tablet stylus types
+ testStylusDevice(QInputDevice::DeviceType::Stylus, QPointingDevice::PointerType::Pen,
+ Qt::CrossCursor, stylusHandler);
+ testStylusDevice(QInputDevice::DeviceType::Stylus, QPointingDevice::PointerType::Eraser,
+ Qt::PointingHandCursor, eraserHandler);
+ testStylusDevice(QInputDevice::DeviceType::Airbrush, QPointingDevice::PointerType::Pen,
+ Qt::BusyCursor, aibrushHandler);
+ testStylusDevice(QInputDevice::DeviceType::Airbrush, QPointingDevice::PointerType::Eraser,
+ Qt::OpenHandCursor, airbrushEraserHandler);
+
+ qCDebug(lcPointerTests) << "---- no more tablet events, now we send a mouse move";
+
+ // move the mouse: the mouse-specific HoverHandler gets to set the cursor only if
+ // more than kCursorOverrideTimeout ms have elapsed (100ms)
+ QTest::mouseMove(&window, point, 100);
+ QTRY_IMPL(mouseHandler->isHovered() == true, 500);
+ const bool afterTimeout =
+ QQuickPointerHandlerPrivate::get(airbrushEraserHandler)->lastEventTime + 100 <
+ QQuickPointerHandlerPrivate::get(mouseHandler)->lastEventTime;
+ qCDebug(lcPointerTests) << "airbrush handler reacted last time:" << QQuickPointerHandlerPrivate::get(airbrushEraserHandler)->lastEventTime
+ << "and the mouse handler reacted at time:" << QQuickPointerHandlerPrivate::get(mouseHandler)->lastEventTime
+ << "so > 100 ms have elapsed?" << afterTimeout;
+ if (afterTimeout)
+ QCOMPARE(mouseHandler->isHovered(), true);
+ else
+ QSKIP("Failed to delay mouse move 100ms after the previous tablet event");
+
+#if QT_CONFIG(cursor)
+ QCOMPARE(window.cursor().shape(), afterTimeout ? Qt::IBeamCursor : Qt::OpenHandCursor);
+#endif
+ QCOMPARE(stylusHandler->isHovered(), false);
+ QCOMPARE(eraserHandler->isHovered(), false);
+ QCOMPARE(aibrushHandler->isHovered(), false);
+ QCOMPARE(airbrushEraserHandler->isHovered(), true); // there was no fresh QTabletEvent to tell it not to be hovered
+
+ // hover with the stylus again, then move the mouse outside the handlers' parent item
+ testStylusDevice(QInputDevice::DeviceType::Stylus, QPointingDevice::PointerType::Pen,
+ Qt::CrossCursor, stylusHandler);
+ QTest::mouseMove(&window, QPoint(180, 180));
+ // the mouse has left the item: all its HoverHandlers should be unhovered (QTBUG-116505)
+ QCOMPARE(stylusHandler->isHovered(), false);
+ QCOMPARE(eraserHandler->isHovered(), false);
+ QCOMPARE(aibrushHandler->isHovered(), false);
+ QCOMPARE(airbrushEraserHandler->isHovered(), false);
+ QCOMPARE(mouseHandler->isHovered(), false);
+}
+
+void tst_HoverHandler::addHandlerFromCpp()
+{
+ // Check that you can create a hover handler from c++, and add it
+ // as a child of an existing item. Continue to check that you can
+ // also change the parent item at runtime.
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("nohandler.qml"));
+ QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(component.create()));
+ QVERIFY(!window.isNull());
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickItem *childItem = window->findChild<QQuickItem *>("childItem");
+ QVERIFY(childItem);
+
+ // Move mouse outside child
+ const QPoint outside(200, 200);
+ const QPoint inside(50, 50);
+ QTest::mouseMove(window.data(), outside);
+
+ QQuickHoverHandler *handler = new QQuickHoverHandler(childItem);
+ QSignalSpy spy(handler, &QQuickHoverHandler::hoveredChanged);
+
+ // Move mouse inside child
+ QTest::mouseMove(window.data(), inside);
+ QVERIFY(handler->isHovered());
+ QCOMPARE(spy.size(), 1);
+
+ // Move mouse outside child
+ QTest::mouseMove(window.data(), outside);
+ QVERIFY(!handler->isHovered());
+ QCOMPARE(spy.size(), 2);
+
+ // Remove the parent item from the handler
+ spy.clear();
+ handler->setParentItem(nullptr);
+
+ // Move mouse inside child
+ QTest::mouseMove(window.data(), inside);
+ QVERIFY(!handler->isHovered());
+ QCOMPARE(spy.size(), 0);
+
+ // Move mouse outside child
+ QTest::mouseMove(window.data(), outside);
+ QVERIFY(!handler->isHovered());
+ QCOMPARE(spy.size(), 0);
+
+ // Reparent back the item to the handler
+ spy.clear();
+ handler->setParentItem(childItem);
+
+ // Move mouse inside child
+ QTest::mouseMove(window.data(), inside);
+ QVERIFY(handler->isHovered());
+ QCOMPARE(spy.size(), 1);
+
+ // Move mouse outside child
+ QTest::mouseMove(window.data(), outside);
+ QVERIFY(!handler->isHovered());
+ QCOMPARE(spy.size(), 2);
+}
+
+void tst_HoverHandler::ensureHoverHandlerWorksWhenItemHasHoverDisabled()
+{
+ // Check that a hover handler with a leaf item as parent, continues to
+ // receive hover, even if the item itself stops listening for hover.
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("nohandler.qml"));
+ QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(component.create()));
+ QVERIFY(!window.isNull());
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickItem *childItem = window->findChild<QQuickItem *>("childItem");
+ QVERIFY(childItem);
+
+ // Move mouse outside child
+ const QPoint outside(200, 200);
+ const QPoint inside(50, 50);
+ QTest::mouseMove(window.data(), outside);
+
+ QQuickHoverHandler *handler = new QQuickHoverHandler(childItem);
+
+ // Toggle hover on the item. This should not clear subtreeHoverEnabled
+ // on the item as a whole, since it still has a hover handler.
+ childItem->setAcceptHoverEvents(true);
+ childItem->setAcceptHoverEvents(false);
+ QSignalSpy spy(handler, &QQuickHoverHandler::hoveredChanged);
+
+ // Move mouse inside child
+ QTest::mouseMove(window.data(), inside);
+ QVERIFY(handler->isHovered());
+ QCOMPARE(spy.size(), 1);
+
+ // Move mouse outside child
+ QTest::mouseMove(window.data(), outside);
+ QVERIFY(!handler->isHovered());
+ QCOMPARE(spy.size(), 2);
+}
+
+void tst_HoverHandler::changeCursor()
+{
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "changingCursor.qml");
+ QQuickView * window = windowPtr.data();
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ QQuickItem *item = window->findChild<QQuickItem *>("brownRect");
+ QVERIFY(item);
+ QQuickHoverHandler *hh = item->findChild<QQuickHoverHandler *>();
+ QVERIFY(hh);
+
+ QPoint itemCenter(item->mapToScene(QPointF(item->width() / 2, item->height() / 2)).toPoint());
+ QSignalSpy hoveredSpy(hh, SIGNAL(hoveredChanged()));
+
+ QTest::mouseMove(window, itemCenter);
+
+ QTRY_COMPARE(hoveredSpy.size(), 1);
+
+#if QT_CONFIG(cursor)
+ QTRY_COMPARE(window->cursor().shape(), Qt::CrossCursor);
+ QTRY_COMPARE(window->cursor().shape(), Qt::OpenHandCursor);
+ QTRY_COMPARE(window->cursor().shape(), Qt::CrossCursor);
+ QTRY_COMPARE(window->cursor().shape(), Qt::OpenHandCursor);
+#endif
+}
+
+void tst_HoverHandler::touchDrag()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("hoverHandler.qml")));
+ const QQuickItem *root = window.rootObject();
+ QQuickHoverHandler *handler = root->findChild<QQuickHoverHandler *>();
+ QVERIFY(handler);
+
+ // polishAndSync() calls flushFrameSynchronousEvents() before emitting afterAnimating()
+ QSignalSpy frameSyncSpy(&window, &QQuickWindow::afterAnimating);
+
+ const QPoint out(root->width() - 1, root->height() / 2);
+ QPoint in(root->width() / 2, root->height() / 2);
+
+ QTest::touchEvent(&window, touchscreen.get()).press(0, out, &window);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(handler->isHovered(), false);
+
+ frameSyncSpy.clear();
+ QTest::touchEvent(&window, touchscreen.get()).move(0, in, &window);
+ QQuickTouchUtils::flush(&window);
+ QTRY_COMPARE(handler->isHovered(), true);
+ QCOMPARE(handler->point().scenePosition(), in);
+
+ in += {10, 10};
+ QTest::touchEvent(&window, touchscreen.get()).move(0, in, &window);
+ QQuickTouchUtils::flush(&window);
+ // ensure that the color change is visible
+ QTRY_COMPARE_GE(frameSyncSpy.size(), 1);
+ QCOMPARE(handler->isHovered(), true);
+ QCOMPARE(handler->point().scenePosition(), in);
+
+ QTest::touchEvent(&window, touchscreen.get()).move(0, out, &window);
+ QQuickTouchUtils::flush(&window);
+ QTRY_COMPARE_GE(frameSyncSpy.size(), 2);
+ QCOMPARE(handler->isHovered(), false);
+
+ QTest::touchEvent(&window, touchscreen.get()).release(0, out, &window);
+}
+
QTEST_MAIN(tst_HoverHandler)
#include "tst_qquickhoverhandler.moc"
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/BLACKLIST b/tests/auto/quick/pointerhandlers/qquickpinchhandler/BLACKLIST
new file mode 100644
index 0000000000..701cdae344
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/BLACKLIST
@@ -0,0 +1,3 @@
+# QTBUG-103066
+[scaleNativeGesture]
+android
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/CMakeLists.txt b/tests/auto/quick/pointerhandlers/qquickpinchhandler/CMakeLists.txt
index 09550b143d..1334607ab2 100644
--- a/tests/auto/quick/pointerhandlers/qquickpinchhandler/CMakeLists.txt
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickpinchhandler.pro.
#####################################################################
## tst_qquickpinchhandler Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickpinchhandler LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickpinchhandler
SOURCES
- ../../../shared/util.cpp ../../../shared/util.h
- ../../shared/geometrytestutil.cpp ../../shared/geometrytestutil.h
- ../../shared/viewtestutil.cpp ../../shared/viewtestutil.h
- ../../shared/visualtestutil.cpp ../../shared/visualtestutil.h
tst_qquickpinchhandler.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -38,10 +40,10 @@ qt_internal_add_test(tst_qquickpinchhandler
qt_internal_extend_target(tst_qquickpinchhandler CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickpinchhandler CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/nullTarget.qml b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/nullTarget.qml
new file mode 100644
index 0000000000..9d9903fc0e
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/nullTarget.qml
@@ -0,0 +1,33 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.15
+
+Item {
+ width: 320; height: 320
+ property alias pinchScale: pinch.scale
+
+ Rectangle {
+ objectName: "blackrect"
+ width: 200; height: 200
+ color: "black"
+ antialiasing: true
+ scale: pinch.scale
+ rotation: pinch.rotation
+ x: pinch.translation.x
+ y: pinch.translation.y
+
+ PinchHandler {
+ id: pinch
+ target: null
+ minimumScale: 0.5
+ maximumScale: 4
+ }
+
+ Text {
+ color: "cyan"
+ anchors.centerIn: parent
+ text: "scale " + pinch.scale.toFixed(2) + " activeScale " + pinch.activeScale.toFixed(2)
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchAndDrag.qml b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchAndDrag.qml
new file mode 100644
index 0000000000..ddd63ec720
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchAndDrag.qml
@@ -0,0 +1,37 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Rectangle {
+ id: whiteRect
+ property real scale: -1.0
+ property int activeCount : 0
+ property int deactiveCount : 0
+ width: 320; height: 320
+ color: "white"
+ Rectangle {
+ id: blackRect
+ objectName: "blackrect"
+ color: "black"
+ y: 50
+ x: 50
+ width: 100
+ height: 100
+ Text { color: "white"; text: "opacity: " + blackRect.opacity + "\nscale: " + blackRect.scale}
+ Rectangle {
+ color: "red"
+ width: 6; height: 6; radius: 3
+ visible: pincharea.active
+ x: pincharea.centroid.position.x - radius
+ y: pincharea.centroid.position.y - radius
+ }
+
+ DragHandler { }
+
+ PinchHandler {
+ id: pincharea
+ objectName: "pinchHandler"
+ }
+ }
+ }
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchproperties.qml b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchproperties.qml
index 3cabde5f59..2b9b3eb156 100644
--- a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchproperties.qml
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/pinchproperties.qml
@@ -1,40 +1,49 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
Rectangle {
id: whiteRect
- property real scale: -1.0
+ property real pinchScale: -1.0
property int activeCount : 0
property int deactiveCount : 0
width: 320; height: 320
color: "white"
+
+ PointHandler {
+ id: ph1
+ acceptedDevices: PointerDevice.TouchScreen
+ target: Rectangle {
+ parent: whiteRect
+ color: "cyan"
+ x: ph1.point.position.x - 3
+ y: ph1.point.position.y - 3
+ width: 6; height: 6; radius: 3
+ }
+ }
+
+ PointHandler {
+ id: ph2
+ acceptedDevices: PointerDevice.TouchScreen
+ target: Rectangle {
+ parent: whiteRect
+ color: "lightgreen"
+ x: ph2.point.position.x - 3
+ y: ph2.point.position.y - 3
+ width: 6; height: 6; radius: 3
+ }
+ }
+
+ Text {
+ color: "magenta"
+ z: 1
+ text: "scale: " + blackRect.scale +
+ "\npos: " + blackRect.x.toFixed(2) + ", " + blackRect.y.toFixed(2) +
+ "\ntranslation: active " + pincharea.activeTranslation.x.toFixed(2) + ", " + pincharea.activeTranslation.y.toFixed(2) +
+ "\n persistent " + pincharea.persistentTranslation.x.toFixed(2) + ", " + pincharea.persistentTranslation.y.toFixed(2)
+ }
+
Rectangle {
id: blackRect
objectName: "blackrect"
@@ -43,8 +52,7 @@ Rectangle {
x: 50
width: 100
height: 100
- opacity: (whiteRect.width-blackRect.x+whiteRect.height-blackRect.y-199)/200
- Text { color: "white"; text: "opacity: " + blackRect.opacity + "\nscale: " + blackRect.scale}
+
Rectangle {
color: "red"
width: 6; height: 6; radius: 3
@@ -56,22 +64,30 @@ Rectangle {
PinchHandler {
id: pincharea
objectName: "pinchHandler"
- minimumScale: 1.0
+ minimumScale: 0.5
maximumScale: 4.0
minimumRotation: 0.0
maximumRotation: 90.0
xAxis.maximum: 140
yAxis.maximum: 170
onActiveChanged: {
- whiteRect.scale = pincharea.scale
+ whiteRect.pinchScale = pincharea.scale
if (active) ++activeCount
else ++deactiveCount;
}
onUpdated: {
- whiteRect.scale = pincharea.scale
+ whiteRect.pinchScale = pincharea.scale
//whiteRect.pointCount = pincharea.pointCount
}
- }
- }
- }
+ }
+ }
+
+ Rectangle {
+ color: "transparent"; border.color: "green"
+ width: 12; height: 12; radius: 6; border.width: 2
+ visible: pincharea.active
+ x: pincharea.centroid.scenePosition.x - radius
+ y: pincharea.centroid.scenePosition.y - radius
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/threeFingers.qml b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/threeFingers.qml
index 4d1a520c01..ed9220f99e 100644
--- a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/threeFingers.qml
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/threeFingers.qml
@@ -1,39 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-import QtQuick 2.12
+import QtQuick
Rectangle {
id: root
- property variant centroid : pinchHandler.centroid
- property real scale: pinchHandler.scale
- property int pointCount: 0
- property bool pinchActive: pinchHandler.active
width: 240; height: 320
Rectangle {
@@ -48,6 +19,7 @@ Rectangle {
PinchHandler {
id: pinchHandler
objectName: "pinchHandler"
+ dragThreshold: 10
minimumScale: 0.5
maximumScale: 2.0
minimumRotation: 0.0
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/transformedPinchHandler.qml b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/transformedPinchHandler.qml
index 46e9ccca87..f25d0e9f38 100644
--- a/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/transformedPinchHandler.qml
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/data/transformedPinchHandler.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp
index cd24d8643e..78483c5bdb 100644
--- a/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickpinchhandler/tst_qquickpinchhandler.cpp
@@ -1,55 +1,41 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtTest/QSignalSpy>
#include <QtGui/QStyleHints>
-#include <QtGui/private/qevent_p.h>
+#include <QtGui/private/qeventpoint_p.h>
#include <qpa/qwindowsysteminterface.h>
#include <QtQuick/private/qquickpinchhandler_p.h>
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/qquickview.h>
#include <QtQml/qqmlcontext.h>
-#include "../../../shared/util.h"
-#include "../../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests")
+class PinchHandler : public QQuickPinchHandler {
+public:
+ const QQuickHandlerPoint &firstPoint() { return currentPoints().first(); }
+ const QQuickHandlerPoint &lastPoint() { return currentPoints().last(); }
+};
+
class tst_QQuickPinchHandler: public QQmlDataTest
{
Q_OBJECT
public:
- tst_QQuickPinchHandler() { }
+ tst_QQuickPinchHandler() : QQmlDataTest(QT_QMLTEST_DATADIR) { }
private slots:
void cleanupTestCase();
void pinchProperties();
+ void scale_data();
void scale();
void scaleThreeFingers();
+ void scaleNativeGesture_data();
+ void scaleNativeGesture();
+ void cumulativeNativeGestures_data();
+ void cumulativeNativeGestures();
void pan();
void dragAxesEnabled_data();
void dragAxesEnabled();
@@ -59,8 +45,8 @@ private slots:
void transformedpinchHandler();
private:
- QQuickView *createView();
- QPointingDevice *device = QTest::createTouchDevice();
+ QScopedPointer<QPointingDevice> touchscreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
+ QScopedPointer<QPointingDevice> touchpad = QScopedPointer<QPointingDevice>(QTest::createTouchDevice(QInputDevice::DeviceType::TouchPad));
};
void tst_QQuickPinchHandler::cleanupTestCase()
@@ -75,7 +61,7 @@ static bool withinBounds(qreal lower, qreal num, qreal upper)
void tst_QQuickPinchHandler::pinchProperties()
{
- QScopedPointer<QQuickView> window(createView());
+ QScopedPointer<QQuickView> window(QQuickViewTestUtils::createView());
window->setSource(testFileUrl("pinchproperties.qml"));
window->show();
QVERIFY(window->rootObject() != nullptr);
@@ -91,193 +77,292 @@ void tst_QQuickPinchHandler::pinchProperties()
QVERIFY(rootItem != nullptr);
QSignalSpy targetSpy(pinchHandler, SIGNAL(targetChanged()));
pinchHandler->setTarget(rootItem);
- QCOMPARE(targetSpy.count(),1);
+ QCOMPARE(targetSpy.size(),1);
pinchHandler->setTarget(rootItem);
- QCOMPARE(targetSpy.count(),1);
-
- // axis
- /*
- QCOMPARE(pinchHandler->axis(), QQuickPinch::XAndYAxis);
- QSignalSpy axisSpy(pinchHandler, SIGNAL(dragAxisChanged()));
- pinchHandler->setAxis(QQuickPinch::XAxis);
- QCOMPARE(pinchHandler->axis(), QQuickPinch::XAxis);
- QCOMPARE(axisSpy.count(),1);
- pinchHandler->setAxis(QQuickPinch::XAxis);
- QCOMPARE(axisSpy.count(),1);
+ QCOMPARE(targetSpy.size(),1);
+
+ // drag axes
+ QCOMPARE(pinchHandler->xAxis()->enabled(), true);
+ QCOMPARE(pinchHandler->yAxis()->enabled(), true);
+ QSignalSpy xEnabledSpy(pinchHandler->xAxis(), &QQuickDragAxis::enabledChanged);
+ QSignalSpy yEnabledSpy(pinchHandler->yAxis(), &QQuickDragAxis::enabledChanged);
+ QSignalSpy scaleEnabledSpy(pinchHandler->scaleAxis(), &QQuickDragAxis::enabledChanged);
+ QSignalSpy rotationEnabledSpy(pinchHandler->rotationAxis(), &QQuickDragAxis::enabledChanged);
+ pinchHandler->xAxis()->setEnabled(false);
+ QCOMPARE(xEnabledSpy.count(), 1);
+ pinchHandler->yAxis()->setEnabled(false);
+ QCOMPARE(yEnabledSpy.count(), 1);
+ pinchHandler->scaleAxis()->setEnabled(false);
+ QCOMPARE(scaleEnabledSpy.count(), 1);
+ pinchHandler->rotationAxis()->setEnabled(false);
+ QCOMPARE(rotationEnabledSpy.count(), 1);
// minimum and maximum drag properties
- QSignalSpy xminSpy(pinchHandler, SIGNAL(minimumXChanged()));
- QSignalSpy xmaxSpy(pinchHandler, SIGNAL(maximumXChanged()));
- QSignalSpy yminSpy(pinchHandler, SIGNAL(minimumYChanged()));
- QSignalSpy ymaxSpy(pinchHandler, SIGNAL(maximumYChanged()));
-
- QCOMPARE(pinchHandler->xmin(), 0.0);
- QCOMPARE(pinchHandler->xmax(), rootItem->width()-blackRect->width());
- QCOMPARE(pinchHandler->ymin(), 0.0);
- QCOMPARE(pinchHandler->ymax(), rootItem->height()-blackRect->height());
-
- pinchHandler->setXmin(10);
- pinchHandler->setXmax(10);
- pinchHandler->setYmin(10);
- pinchHandler->setYmax(10);
-
- QCOMPARE(pinchHandler->xmin(), 10.0);
- QCOMPARE(pinchHandler->xmax(), 10.0);
- QCOMPARE(pinchHandler->ymin(), 10.0);
- QCOMPARE(pinchHandler->ymax(), 10.0);
+ QSignalSpy xminSpy(pinchHandler->xAxis(), &QQuickDragAxis::minimumChanged);
+ QSignalSpy xmaxSpy(pinchHandler->xAxis(), &QQuickDragAxis::maximumChanged);
+ QSignalSpy yminSpy(pinchHandler->yAxis(), &QQuickDragAxis::minimumChanged);
+ QSignalSpy ymaxSpy(pinchHandler->yAxis(), &QQuickDragAxis::maximumChanged);
+
+ QCOMPARE(pinchHandler->xAxis()->minimum(), std::numeric_limits<qreal>::lowest());
+ QCOMPARE(pinchHandler->xAxis()->maximum(), 140);
+ QCOMPARE(pinchHandler->yAxis()->minimum(), std::numeric_limits<qreal>::lowest());
+ QCOMPARE(pinchHandler->yAxis()->maximum(), 170);
+
+ pinchHandler->xAxis()->setMinimum(10);
+ pinchHandler->xAxis()->setMaximum(10);
+ pinchHandler->yAxis()->setMinimum(10);
+ pinchHandler->yAxis()->setMaximum(10);
+
+ QCOMPARE(pinchHandler->xAxis()->minimum(), 10);
+ QCOMPARE(pinchHandler->xAxis()->maximum(), 10);
+ QCOMPARE(pinchHandler->yAxis()->minimum(), 10);
+ QCOMPARE(pinchHandler->yAxis()->maximum(), 10);
QCOMPARE(xminSpy.count(),1);
QCOMPARE(xmaxSpy.count(),1);
QCOMPARE(yminSpy.count(),1);
QCOMPARE(ymaxSpy.count(),1);
- pinchHandler->setXmin(10);
- pinchHandler->setXmax(10);
- pinchHandler->setYmin(10);
- pinchHandler->setYmax(10);
+ pinchHandler->xAxis()->setMinimum(10);
+ pinchHandler->xAxis()->setMaximum(10);
+ pinchHandler->yAxis()->setMinimum(10);
+ pinchHandler->yAxis()->setMaximum(10);
QCOMPARE(xminSpy.count(),1);
QCOMPARE(xmaxSpy.count(),1);
QCOMPARE(yminSpy.count(),1);
QCOMPARE(ymaxSpy.count(),1);
- */
// minimum and maximum scale properties
- QSignalSpy scaleMinSpy(pinchHandler, SIGNAL(minimumScaleChanged()));
- QSignalSpy scaleMaxSpy(pinchHandler, SIGNAL(maximumScaleChanged()));
-
- QCOMPARE(pinchHandler->minimumScale(), 1.0);
- QCOMPARE(pinchHandler->maximumScale(), 4.0);
+ QSignalSpy scaleAxisMinSpy(pinchHandler->scaleAxis(), &QQuickDragAxis::minimumChanged);
+ QSignalSpy scaleAxisMaxSpy(pinchHandler->scaleAxis(), &QQuickDragAxis::maximumChanged);
- pinchHandler->setMinimumScale(0.5);
- pinchHandler->setMaximumScale(1.5);
+ QCOMPARE(pinchHandler->scaleAxis()->minimum(), 0.5);
+ QCOMPARE(pinchHandler->scaleAxis()->maximum(), 4);
+#if QT_DEPRECATED_SINCE(6, 5)
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
QCOMPARE(pinchHandler->minimumScale(), 0.5);
- QCOMPARE(pinchHandler->maximumScale(), 1.5);
-
- QCOMPARE(scaleMinSpy.count(),1);
- QCOMPARE(scaleMaxSpy.count(),1);
+ QCOMPARE(pinchHandler->maximumScale(), 4);
+QT_WARNING_POP
+#endif
- pinchHandler->setMinimumScale(0.5);
- pinchHandler->setMaximumScale(1.5);
+ pinchHandler->scaleAxis()->setMinimum(0.25);
+ pinchHandler->scaleAxis()->setMaximum(1.5);
- QCOMPARE(scaleMinSpy.count(),1);
- QCOMPARE(scaleMaxSpy.count(),1);
+ QCOMPARE(pinchHandler->scaleAxis()->minimum(), 0.25);
+ QCOMPARE(pinchHandler->scaleAxis()->maximum(), 1.5);
- // minimum and maximum rotation properties
- QSignalSpy rotMinSpy(pinchHandler, SIGNAL(minimumRotationChanged()));
- QSignalSpy rotMaxSpy(pinchHandler, SIGNAL(maximumRotationChanged()));
-
- QCOMPARE(pinchHandler->minimumRotation(), 0.0);
- QCOMPARE(pinchHandler->maximumRotation(), 90.0);
-
- pinchHandler->setMinimumRotation(-90.0);
- pinchHandler->setMaximumRotation(45.0);
+#if QT_DEPRECATED_SINCE(6, 5)
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
+ QCOMPARE(pinchHandler->minimumScale(), 0.25);
+ QCOMPARE(pinchHandler->maximumScale(), 1.5);
+QT_WARNING_POP
+#endif
- QCOMPARE(pinchHandler->minimumRotation(), -90.0);
- QCOMPARE(pinchHandler->maximumRotation(), 45.0);
+ QCOMPARE(scaleAxisMinSpy.size(),1);
+ QCOMPARE(scaleAxisMaxSpy.size(),1);
- QCOMPARE(rotMinSpy.count(),1);
- QCOMPARE(rotMaxSpy.count(),1);
+ pinchHandler->scaleAxis()->setMinimum(0.25);
+ pinchHandler->scaleAxis()->setMaximum(1.5);
- pinchHandler->setMinimumRotation(-90.0);
- pinchHandler->setMaximumRotation(45.0);
+ QCOMPARE(scaleAxisMinSpy.size(),1);
+ QCOMPARE(scaleAxisMaxSpy.size(),1);
- QCOMPARE(rotMinSpy.count(),1);
- QCOMPARE(rotMaxSpy.count(),1);
+ // minimum and maximum rotation properties
+ QSignalSpy rotAxisMinSpy(pinchHandler->rotationAxis(), &QQuickDragAxis::minimumChanged);
+ QSignalSpy rotAxisMaxSpy(pinchHandler->rotationAxis(), &QQuickDragAxis::maximumChanged);
+
+#if QT_DEPRECATED_SINCE(6, 5)
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
+ QCOMPARE(pinchHandler->minimumRotation(), 0);
+ QCOMPARE(pinchHandler->maximumRotation(), 90);
+QT_WARNING_POP
+#endif
+ QCOMPARE(pinchHandler->rotationAxis()->minimum(), 0);
+ QCOMPARE(pinchHandler->rotationAxis()->maximum(), 90);
+
+ pinchHandler->rotationAxis()->setMinimum(-90);
+ pinchHandler->rotationAxis()->setMaximum(45);
+
+#if QT_DEPRECATED_SINCE(6, 5)
+QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
+ QCOMPARE(pinchHandler->minimumRotation(), -90);
+ QCOMPARE(pinchHandler->maximumRotation(), 45);
+QT_WARNING_POP
+#endif
+
+ QCOMPARE(rotAxisMinSpy.size(),1);
+ QCOMPARE(rotAxisMaxSpy.size(),1);
+
+ pinchHandler->rotationAxis()->setMinimum(-90);
+ pinchHandler->rotationAxis()->setMaximum(45);
+
+ QCOMPARE(rotAxisMinSpy.size(),1);
+ QCOMPARE(rotAxisMaxSpy.size(),1);
}
-QMutableEventPoint makeTouchPoint(int id, QPoint p, QQuickView *v, QQuickItem *i)
+QEventPoint makeTouchPoint(int id, QPoint p, QQuickView *v, QQuickItem *i)
{
- QMutableEventPoint touchPoint(id);
- touchPoint.setPosition(i->mapFromScene(p));
- touchPoint.setGlobalPosition(v->mapToGlobal(p));
- touchPoint.setScenePosition(p);
+ QEventPoint touchPoint(id);
+ QMutableEventPoint::setPosition(touchPoint, i->mapFromScene(p));
+ QMutableEventPoint::setGlobalPosition(touchPoint, v->mapToGlobal(p));
+ QMutableEventPoint::setScenePosition(touchPoint, p);
return touchPoint;
}
-void tst_QQuickPinchHandler::scale()
+void tst_QQuickPinchHandler::scale_data()
{
- QQuickView *window = createView();
- QScopedPointer<QQuickView> scope(window);
- window->setSource(testFileUrl("pinchproperties.qml"));
- window->show();
- QVERIFY(QTest::qWaitForWindowExposed(window));
- QVERIFY(window->rootObject() != nullptr);
- qApp->processEvents();
+ QTest::addColumn<QUrl>("qmlfile");
+ QTest::addColumn<bool>("hasTarget");
+ QTest::newRow("targetModifying") << testFileUrl("pinchproperties.qml") << true;
+ QTest::newRow("nullTarget") << testFileUrl("nullTarget.qml") << false;
+}
- QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler");
- QVERIFY(pinchHandler != nullptr);
+void tst_QQuickPinchHandler::scale()
+{
+ QFETCH(QUrl, qmlfile);
+ QFETCH(bool, hasTarget);
- QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, qmlfile));
+ QQuickItem *root = qobject_cast<QQuickItem*>(window.rootObject());
QVERIFY(root != nullptr);
-
- // target
- QQuickItem *blackRect = window->rootObject()->findChild<QQuickItem*>("blackrect");
+ auto *pinchHandler = static_cast<PinchHandler *>(root->findChild<QQuickPinchHandler*>());
+ QVERIFY(pinchHandler != nullptr);
+ QQuickItem *blackRect = (hasTarget ? pinchHandler->target() : pinchHandler->parentItem());
QVERIFY(blackRect != nullptr);
+ QSignalSpy grabChangedSpy(pinchHandler, SIGNAL(grabChanged(QPointingDevice::GrabTransition,QEventPoint)));
+ QSignalSpy scaleChangedSpy(pinchHandler, &QQuickPinchHandler::scaleChanged);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
QPoint p0(80, 80);
QPoint p1(100, 100);
- {
- QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
- pinchSequence.press(0, p0, window).commit();
- QQuickTouchUtils::flush(window);
- // In order for the stationary point to remember its previous position,
- // we have to reuse the same pinchSequence object. Otherwise if we let it
- // be destroyed and then start a new sequence, point 0 will default to being
- // stationary at 0, 0, and pinchHandler will filter out that touchpoint because
- // it is outside its bounds.
- pinchSequence.stationary(0).press(1, p1, window).commit();
- QQuickTouchUtils::flush(window);
-
- QPoint pd(10, 10);
- // move one point until PinchHandler activates
- for (int pi = 0; pi < 10 && !pinchHandler->active(); ++pi) {
- p1 += pd;
- pinchSequence.stationary(0).move(1, p1, window).commit();
- QQuickTouchUtils::flush(window);
- }
- QCOMPARE(pinchHandler->active(), true);
- QLineF line(p0, p1);
- const qreal startLength = line.length();
-
- p1+=pd;
- pinchSequence.stationary(0).move(1, p1, window).commit();
- QQuickTouchUtils::flush(window);
- line.setP2(p1);
- qreal scale = line.length() / startLength;
- QVERIFY(qFloatDistance(root->property("scale").toReal(), scale) < 10);
- QVERIFY(qFloatDistance(blackRect->scale(), scale) < 10);
-
- p1+=pd;
- pinchSequence.stationary(0).move(1, p1, window).commit();
- QQuickTouchUtils::flush(window);
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(&window, touchscreen.get());
+ pinchSequence.press(0, p0, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object. Otherwise if we let it
+ // be destroyed and then start a new sequence, point 0 will default to being
+ // stationary at 0, 0, and pinchHandler will filter out that touchpoint because
+ // it is outside its bounds.
+ pinchSequence.stationary(0).press(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QCOMPARE(grabChangedSpy.size(), 1); // passive grab
+
+ QPoint pd(10, 10);
+ // move one point until PinchHandler activates
+ for (int pi = 0; pi < 10 && !pinchHandler->active(); ++pi) {
+ p1 += pd;
+ pinchSequence.stationary(0).move(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ }
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QCOMPARE(pinchHandler->active(), true);
+ // grabs occur when the handler becomes active; at that time, QQuickHandlerPoint.sceneGrabPosition should be correct
+ QVERIFY(pinchHandler->firstPoint().sceneGrabPosition() != QPointF());
+ QVERIFY(pinchHandler->lastPoint().sceneGrabPosition() != QPointF());
+ QCOMPARE(pinchHandler->firstPoint().sceneGrabPosition(), pinchHandler->firstPoint().scenePosition());
+ QCOMPARE(pinchHandler->lastPoint().sceneGrabPosition(), pinchHandler->lastPoint().scenePosition());
+ // first point got a passive grab; both points got exclusive grabs
+ QCOMPARE(grabChangedSpy.size(), 3);
+ QLineF line(p0, p1);
+ const qreal startLength = line.length();
+
+ // move the same point even further and observe the change in scale
+ for (int i = 0; i < 2; ++i) {
+ qreal lastScale = pinchHandler->activeScale();
+ p1 += pd;
+ pinchSequence.stationary(0).move(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
line.setP2(p1);
- scale = line.length() / startLength;
-
- QVERIFY(qFloatDistance(root->property("scale").toReal(), scale) < 10);
- QVERIFY(qFloatDistance(blackRect->scale(), scale) < 10);
-
- QPointF expectedCentroid = p0 + (p1 - p0)/2;
+ qreal expectedScale = line.length() / startLength;
+ qCDebug(lcPointerTests) << "pinchScale" << root->property("pinchScale").toReal()
+ << "expected" << expectedScale << "; target scale" << blackRect->scale()
+ << "increments" << scaleChangedSpy.size()
+ << "multiplier" << scaleChangedSpy.last().first().toReal();
+ QVERIFY(qFloatDistance(root->property("pinchScale").toReal(), expectedScale) < 10);
+ QVERIFY(qFloatDistance(blackRect->scale(), expectedScale) < 10);
+ QCOMPARE(pinchHandler->persistentScale(), root->property("pinchScale").toReal());
+ QCOMPARE(pinchHandler->persistentScale(), pinchHandler->activeScale()); // in sync for the first gesture
+ QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), pinchHandler->activeScale());
+ QCOMPARE(pinchHandler->scaleAxis()->activeValue(), pinchHandler->activeScale());
+ const qreal expectedIncrement = pinchHandler->activeScale() / lastScale;
+ QCOMPARE(scaleChangedSpy.size(), i + 1);
+ QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement);
+ QPointF expectedCentroid = p0 + (p1 - p0) / 2;
QCOMPARE(pinchHandler->centroid().scenePosition(), expectedCentroid);
}
- // scale beyond bound
- p1 += QPoint(20, 20);
- {
- QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
- pinchSequence.stationary(0).move(1, p1, window).commit();
- QQuickTouchUtils::flush(window);
- QCOMPARE(blackRect->scale(), qreal(4)); // qquickpinchhandler does not manipulate scale property
- pinchSequence.release(0, p0, window).release(1, p1, window).commit();
- QQuickTouchUtils::flush(window);
+ qreal lastScale = pinchHandler->persistentScale();
+ pinchSequence.release(0, p0, &window).release(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ // scale property is persistent after release
+ QCOMPARE(pinchHandler->persistentScale(), lastScale);
+ QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), lastScale);
+ QCOMPARE(pinchHandler->scaleAxis()->activeValue(), 1);
+
+ // pinch a second time: scale picks up where we left off
+ p0 = QPoint(80, 80);
+ p1 = QPoint(100, 100);
+ pinchSequence.press(0, p0, &window).press(1, p1, &window).commit();
+ // move one point until PinchHandler activates
+ for (int pi = 0; pi < 10 && !pinchHandler->active(); ++pi) {
+ p1 += pd;
+ pinchSequence.stationary(0).move(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
}
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QCOMPARE(pinchHandler->active(), true);
+ QCOMPARE(pinchHandler->persistentScale(), lastScale); // just activated, not scaling further yet
+ QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), lastScale);
+ QCOMPARE(pinchHandler->scaleAxis()->activeValue(), 1);
+ for (int i = 0; i < 2; ++i) {
+ lastScale = pinchHandler->persistentScale();
+ p1 += pd;
+ pinchSequence.stationary(0).move(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QCOMPARE_GT(pinchHandler->persistentScale(), lastScale);
+ line.setP2(p1);
+ qreal expectedActiveScale = line.length() / startLength;
+ qCDebug(lcPointerTests) << i << "activeScale" << pinchHandler->activeScale()
+ << "expected" << expectedActiveScale << "; scale" << pinchHandler->persistentScale()
+ << "increments" << scaleChangedSpy.size()
+ << "multiplier" << scaleChangedSpy.last().first().toReal();
+ QVERIFY(qFloatDistance(pinchHandler->activeScale(), expectedActiveScale) < 10);
+ QCOMPARE(pinchHandler->persistentScale(), root->property("pinchScale").toReal());
+ QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), root->property("pinchScale").toReal());
+ QCOMPARE_NE(pinchHandler->persistentScale(), pinchHandler->activeScale()); // not in sync anymore
+ QCOMPARE(pinchHandler->scaleAxis()->activeValue(), pinchHandler->activeScale());
+ const qreal expectedIncrement = pinchHandler->persistentScale() / lastScale;
+ QCOMPARE(scaleChangedSpy.size(), i + 3);
+ QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement);
+ }
+
+ // scale beyond maximumScale
+ lastScale = pinchHandler->activeScale();
+ p1 = QPoint(310, 310);
+ pinchSequence.stationary(0).move(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QCOMPARE(blackRect->scale(), qreal(4));
+ QCOMPARE(pinchHandler->persistentScale(), qreal(4)); // limited by maximumScale
+ QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), 4);
+ const qreal expectedIncrement = pinchHandler->activeScale() / lastScale;
+ QCOMPARE(scaleChangedSpy.size(), 5);
+ QCOMPARE(scaleChangedSpy.last().first().toReal(), expectedIncrement);
+ pinchSequence.release(0, p0, &window).release(1, p1, &window).commit();
+ QQuickTouchUtils::flush(&window);
QCOMPARE(pinchHandler->active(), false);
}
void tst_QQuickPinchHandler::scaleThreeFingers()
{
- QQuickView *window = createView();
+ QQuickView *window = QQuickViewTestUtils::createView();
QScopedPointer<QQuickView> scope(window);
window->setSource(testFileUrl("threeFingers.qml"));
window->show();
@@ -300,7 +385,7 @@ void tst_QQuickPinchHandler::scaleThreeFingers()
QPoint p1(220, 80);
QPoint p2(150, 220);
{
- QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, touchscreen.get());
pinchSequence.press(0, p0, window).commit();
QQuickTouchUtils::flush(window);
// In order for the stationary point to remember its previous position,
@@ -322,9 +407,17 @@ void tst_QQuickPinchHandler::scaleThreeFingers()
QCOMPARE(pinchHandler->active(), true);
// scale we got was 1.1729088738267854364, but keep some slack
- QVERIFY(withinBounds(1.163, root->property("scale").toReal(), 1.183));
+ qCDebug(lcPointerTests) << "pinch scale" << pinchHandler->persistentScale() << "expected 1.173";
+ QVERIFY(withinBounds(1.163, pinchHandler->persistentScale(), 1.183));
// should not rotate
- QCOMPARE(root->property("rotation").toReal(), 0.);
+ QCOMPARE(root->rotation(), 0);
+ // rotation should be 0, but could be something tiny
+ qCDebug(lcPointerTests) << "pinch scale expected zero:" << pinchHandler->activeRotation()
+ << pinchHandler->rotationAxis()->activeValue()
+ << pinchHandler->rotationAxis()->persistentValue();
+ QCOMPARE_LE(qAbs(pinchHandler->activeRotation()), 0.001);
+ QCOMPARE(pinchHandler->rotationAxis()->activeValue(), pinchHandler->activeRotation());
+ QCOMPARE(pinchHandler->rotationAxis()->persistentValue(), 0);
for (int i = 0; i < 5;++i) {
p0 += QPoint(-4, -4);
@@ -334,10 +427,10 @@ void tst_QQuickPinchHandler::scaleThreeFingers()
QQuickTouchUtils::flush(window);
}
// scale we got was 1.4613, but keep some slack
- QVERIFY(withinBounds(1.361, root->property("scale").toReal(), 1.561));
+ QVERIFY(withinBounds(1.361, pinchHandler->persistentScale(), 1.561));
// since points were moved symetrically around the y axis, centroid should remain at x:150
- QCOMPARE(root->property("centroid").value<QQuickHandlerPoint>().scenePosition().x(), 150); // blackrect is at 50,50
+ QCOMPARE(pinchHandler->centroid().scenePosition().x(), 150); // blackrect is at 50,50
// scale beyond bound, we should reach the maximumScale
p0 += QPoint(-40, -40);
@@ -346,16 +439,243 @@ void tst_QQuickPinchHandler::scaleThreeFingers()
pinchSequence.move(0, p0,window).move(1, p1,window).move(2, p2,window).commit();
QQuickTouchUtils::flush(window);
- QCOMPARE(root->property("scale").toReal(), 2.);
+ QCOMPARE(pinchHandler->persistentScale(), 2);
+ QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), 2);
+ QCOMPARE(pinchHandler->scaleAxis()->activeValue(), 2);
pinchSequence.release(0, p0, window).release(1, p1, window).release(2, p2, window).commit();
QQuickTouchUtils::flush(window);
}
QCOMPARE(pinchHandler->active(), false);
}
+void tst_QQuickPinchHandler::scaleNativeGesture_data()
+{
+ QTest::addColumn<QString>("qmlfile");
+ QTest::addColumn<qreal>("scale");
+
+ QTest::newRow("just pinch") << "pinchproperties.qml" << 1.1;
+ QTest::newRow("pinch & drag") << "pinchAndDrag.qml" << 1.1;
+ QTest::newRow("bigger than limit") << "pinchproperties.qml" << 5.0;
+ QTest::newRow("smaller than limit") << "pinchproperties.qml" << 0.25;
+}
+
+void tst_QQuickPinchHandler::scaleNativeGesture()
+{
+ QFETCH(QString, qmlfile);
+ QFETCH(qreal, scale);
+
+ QQuickView *window = QQuickViewTestUtils::createView();
+ QScopedPointer<QQuickView> scope(window);
+ window->setSource(testFileUrl(qmlfile));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ QVERIFY(window->rootObject() != nullptr);
+ qApp->processEvents();
+
+ QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler");
+ QVERIFY(pinchHandler != nullptr);
+ QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
+ QVERIFY(root != nullptr);
+ QQuickItem *target = window->rootObject()->findChild<QQuickItem*>("blackrect");
+ QVERIFY(target != nullptr);
+
+ QPointF targetPos = target->position();
+ ulong ts = 1;
+
+ // first pinch: scale it
+ const qreal expectedScale = qBound(qreal(0.5), scale, qreal(4));
+ QPointF pinchPos(75, 75);
+ QPointF pinchLocalPos = target->mapFromScene(pinchPos);
+ // target position is adjusted in QQuickItemPrivate::adjustedPosForTransform()
+ // so as to compensate for the change in size, to hold the centroid in place
+ const QPointF expectedPos = targetPos + QPointF( (pinchPos.x() - target->x()) * (expectedScale - 1),
+ (pinchPos.y() - target->y()) * (expectedScale - 1) );
+ QWindowSystemInterface::handleGestureEvent(window, ts++, touchpad.get(),
+ Qt::BeginNativeGesture, pinchPos, pinchPos);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QWindowSystemInterface::handleGestureEventWithRealValue(window, ts++, touchpad.get(),
+ Qt::ZoomNativeGesture, scale - 1, pinchPos, pinchPos);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QTRY_COMPARE(target->scale(), expectedScale);
+ QCOMPARE(pinchHandler->active(), true);
+ qCDebug(lcPointerTests) << "centroid: local" << pinchHandler->centroid().position()
+ << "scene" << pinchHandler->centroid().scenePosition();
+ QCOMPARE(pinchHandler->centroid().position().toPoint(), pinchLocalPos.toPoint());
+ QCOMPARE(pinchHandler->centroid().scenePosition().toPoint(), pinchPos.toPoint());
+ QVERIFY(qAbs(target->position().x() - expectedPos.x()) < 0.001);
+ QVERIFY(qAbs(target->position().y() - expectedPos.y()) < 0.001);
+ QCOMPARE(pinchHandler->persistentScale(), expectedScale);
+ QCOMPARE(pinchHandler->activeScale(), scale);
+ QCOMPARE(pinchHandler->scaleAxis()->activeValue(), scale);
+ QCOMPARE(pinchHandler->activeTranslation(), QPointF());
+ QCOMPARE(pinchHandler->activeRotation(), 0);
+ QCOMPARE(pinchHandler->rotationAxis()->persistentValue(), 0);
+ QCOMPARE(pinchHandler->rotationAxis()->activeValue(), 0);
+ QWindowSystemInterface::handleGestureEvent(window, ts++, touchpad.get(),
+ Qt::EndNativeGesture, pinchPos, pinchPos);
+ QTRY_COMPARE(pinchHandler->active(), false);
+ QCOMPARE(target->scale(), expectedScale);
+ QCOMPARE(pinchHandler->persistentScale(), expectedScale);
+ QCOMPARE(pinchHandler->activeScale(), 1);
+ QCOMPARE(pinchHandler->scaleAxis()->activeValue(), 1);
+ QCOMPARE(pinchHandler->activeTranslation(), QPointF());
+ QCOMPARE(pinchHandler->activeRotation(), 0);
+ QCOMPARE(pinchHandler->rotationAxis()->persistentValue(), 0);
+ QCOMPARE(pinchHandler->rotationAxis()->activeValue(), 0);
+
+ // second pinch at a different position: scale it back to original size again
+ // but remove the limits first, so that we can scale arbitrarily
+ pinchHandler->scaleAxis()->setMaximum(qInf());
+ pinchHandler->scaleAxis()->setMinimum(-qInf());
+ const qreal reverseScale = (1 / expectedScale);
+ pinchPos = QPointF(110, 110);
+ pinchLocalPos = target->mapFromScene(pinchPos);
+ QWindowSystemInterface::handleGestureEvent(window, ts++, touchpad.get(),
+ Qt::BeginNativeGesture, pinchPos, pinchPos);
+ QWindowSystemInterface::handleGestureEventWithRealValue(window, ts++, touchpad.get(),
+ Qt::ZoomNativeGesture, reverseScale - 1, pinchPos, pinchPos);
+ QTRY_COMPARE(target->scale(), 1);
+ QCOMPARE(pinchHandler->active(), true);
+ qCDebug(lcPointerTests) << "centroid: local" << pinchHandler->centroid().position()
+ << "scene" << pinchHandler->centroid().scenePosition();
+ QCOMPARE(pinchHandler->centroid().position().toPoint(), pinchLocalPos.toPoint());
+ QCOMPARE(pinchHandler->centroid().scenePosition().toPoint(), pinchPos.toPoint());
+ QCOMPARE(pinchHandler->persistentScale(), 1);
+ QCOMPARE(pinchHandler->activeScale(), reverseScale);
+ QCOMPARE(pinchHandler->scaleAxis()->activeValue(), reverseScale);
+ QWindowSystemInterface::handleGestureEvent(window, ts++, touchpad.get(),
+ Qt::EndNativeGesture, pinchPos, pinchPos);
+ QTRY_COMPARE(pinchHandler->active(), false);
+ QCOMPARE(target->scale(), 1);
+ QCOMPARE(pinchHandler->persistentScale(), 1);
+ QCOMPARE(pinchHandler->activeScale(), 1);
+ QCOMPARE(pinchHandler->scaleAxis()->activeValue(), 1);
+}
+
+void tst_QQuickPinchHandler::cumulativeNativeGestures_data()
+{
+ QTest::addColumn<const QPointingDevice*>("device");
+ QTest::addColumn<Qt::NativeGestureType>("gesture");
+ QTest::addColumn<qreal>("value");
+ QTest::addColumn<QList<QPoint>>("expectedTargetTranslations");
+
+ const auto *touchpadDevice = touchpad.get();
+ const auto *mouse = QPointingDevice::primaryPointingDevice();
+
+ QTest::newRow("touchpad: rotate") << touchpadDevice << Qt::RotateNativeGesture << 5.0
+ << QList<QPoint>{{-2, 2}, {-5, 4}, {-7, 6}, {-10, 7}};
+ QTest::newRow("touchpad: scale") << touchpadDevice << Qt::ZoomNativeGesture << 0.1
+ << QList<QPoint>{{3, 3}, {5, 5}, {8, 8}, {12, 12}};
+ if (mouse->type() == QInputDevice::DeviceType::Mouse) {
+ QTest::newRow("mouse: rotate") << mouse << Qt::RotateNativeGesture << 5.0
+ << QList<QPoint>{{-2, 2}, {-5, 4}, {-7, 6}, {-10, 7}};
+ QTest::newRow("mouse: scale") << mouse << Qt::ZoomNativeGesture << 0.1
+ << QList<QPoint>{{3, 3}, {5, 5}, {8, 8}, {12, 12}};
+ } else {
+ qCWarning(lcPointerTests) << "skipping mouse tests: primary device is not a mouse" << mouse;
+ }
+}
+
+void tst_QQuickPinchHandler::cumulativeNativeGestures()
+{
+ QFETCH(const QPointingDevice*, device);
+ QFETCH(Qt::NativeGestureType, gesture);
+ QFETCH(qreal, value);
+ QFETCH(QList<QPoint>, expectedTargetTranslations);
+
+ QCOMPARE(expectedTargetTranslations.size(), 4);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("pinchproperties.qml")));
+ QVERIFY(window.rootObject() != nullptr);
+ qApp->processEvents();
+
+ QQuickItem *root = qobject_cast<QQuickItem*>(window.rootObject());
+ QVERIFY(root != nullptr);
+ QQuickPinchHandler *pinchHandler = root->findChild<QQuickPinchHandler*>("pinchHandler");
+ QVERIFY(pinchHandler != nullptr);
+ QQuickItem *target = root->findChild<QQuickItem*>("blackrect");
+ QVERIFY(target != nullptr);
+ QCOMPARE(pinchHandler->target(), target);
+
+ ulong ts = 1;
+ qreal expectedScale = 1;
+ qreal expectedRotation = 0;
+ QPointF pinchPos(75, 75);
+ const QPointF initialTargetPos(target->position());
+ QWindowSystemInterface::handleGestureEvent(&window, ts++, device,
+ Qt::BeginNativeGesture, pinchPos, pinchPos);
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ for (int i = 1; i <= 4; ++i) {
+ QWindowSystemInterface::handleGestureEventWithRealValue(&window, ts++, device,
+ gesture, value, pinchPos, pinchPos);
+ qApp->processEvents();
+ switch (gesture) {
+ case Qt::ZoomNativeGesture:
+ expectedScale = qBound(qreal(0.5), qPow(1 + value, i), qreal(4));
+ break;
+ case Qt::RotateNativeGesture:
+ expectedRotation = qBound(qreal(0), value * i, qreal(90));
+ break;
+ default:
+ break; // PinchHandler doesn't react to the others
+ }
+
+ qCDebug(lcPointerTests) << i << gesture << "with value" << value
+ << ": scale" << target->scale() << "expected" << expectedScale
+ << ": rotation" << target->rotation() << "expected" << expectedRotation;
+ if (lcPointerTests().isDebugEnabled()) QTest::qWait(500);
+ QCOMPARE(target->scale(), expectedScale);
+ QCOMPARE(target->rotation(), expectedRotation);
+ QCOMPARE(pinchHandler->persistentScale(), expectedScale);
+ QCOMPARE(pinchHandler->activeScale(), expectedScale);
+ QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), expectedScale);
+ QCOMPARE(pinchHandler->scaleAxis()->activeValue(), expectedScale);
+ QCOMPARE(pinchHandler->persistentRotation(), expectedRotation);
+ QCOMPARE(pinchHandler->activeRotation(), expectedRotation);
+ QCOMPARE(pinchHandler->rotationAxis()->persistentValue(), expectedRotation);
+ QCOMPARE(pinchHandler->rotationAxis()->activeValue(), expectedRotation);
+ // The target gets transformed around the gesture position, for which
+ // QQuickItemPrivate::adjustedPosForTransform() computes its new position to compensate.
+ QPointF delta = target->position() - initialTargetPos;
+ qCDebug(lcPointerTests) << "target moved by" << delta << "to" << target->position()
+ << "active trans" << pinchHandler->activeTranslation()
+ << "perst trans" << pinchHandler->persistentTranslation();
+ QCOMPARE_NE(target->position(), initialTargetPos);
+ QCOMPARE(delta.toPoint(), expectedTargetTranslations.at(i - 1));
+ // The native pinch gesture cannot include a translation component (and
+ // the cursor doesn't move while you are performing the gesture on a touchpad).
+ QCOMPARE(pinchHandler->activeTranslation(), QPointF());
+ // The target only moves to compensate for scale and rotation changes, and that's
+ // not reflected in PinchHandler.persistentTranslation.
+ QCOMPARE(pinchHandler->persistentTranslation(), QPointF());
+ }
+ QCOMPARE(pinchHandler->active(), true);
+ qCDebug(lcPointerTests) << "centroid: local" << pinchHandler->centroid().position()
+ << "scene" << pinchHandler->centroid().scenePosition();
+ QCOMPARE(pinchHandler->persistentScale(), expectedScale);
+ QCOMPARE(pinchHandler->activeScale(), expectedScale);
+ QCOMPARE(pinchHandler->scaleAxis()->activeValue(), expectedScale);
+ QWindowSystemInterface::handleGestureEvent(&window, ts++, device,
+ Qt::EndNativeGesture, pinchPos, pinchPos);
+ QTRY_COMPARE(pinchHandler->active(), false);
+ QCOMPARE(target->scale(), expectedScale);
+ QCOMPARE(target->rotation(), expectedRotation);
+ QCOMPARE(pinchHandler->persistentScale(), expectedScale);
+ QCOMPARE(pinchHandler->activeScale(), 1);
+ QCOMPARE(pinchHandler->scaleAxis()->persistentValue(), expectedScale);
+ QCOMPARE(pinchHandler->scaleAxis()->activeValue(), 1);
+ QCOMPARE(pinchHandler->persistentRotation(), expectedRotation);
+ QCOMPARE(pinchHandler->activeRotation(), 0);
+ QCOMPARE(pinchHandler->rotationAxis()->persistentValue(), expectedRotation);
+ QCOMPARE(pinchHandler->rotationAxis()->activeValue(), 0);
+ QCOMPARE(pinchHandler->activeTranslation(), QPointF());
+ QCOMPARE(pinchHandler->persistentTranslation(), QPointF());
+}
+
void tst_QQuickPinchHandler::pan()
{
- QQuickView *window = createView();
+ QQuickView *window = QQuickViewTestUtils::createView();
QScopedPointer<QQuickView> scope(window);
window->setSource(testFileUrl("pinchproperties.qml"));
window->show();
@@ -365,6 +685,7 @@ void tst_QQuickPinchHandler::pan()
QQuickPinchHandler *pinchHandler = window->rootObject()->findChild<QQuickPinchHandler*>("pinchHandler");
QVERIFY(pinchHandler != nullptr);
+ QSignalSpy translationChangedSpy(pinchHandler, &QQuickPinchHandler::translationChanged);
QQuickItem *root = qobject_cast<QQuickItem*>(window->rootObject());
QVERIFY(root != nullptr);
@@ -377,7 +698,7 @@ void tst_QQuickPinchHandler::pan()
QPoint p1(100, 100);
{
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
- QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, touchscreen.get());
pinchSequence.press(0, p0, window).commit();
QQuickTouchUtils::flush(window);
// In order for the stationary point to remember its previous position,
@@ -385,7 +706,7 @@ void tst_QQuickPinchHandler::pan()
pinchSequence.stationary(0).press(1, p1, window).commit();
QQuickTouchUtils::flush(window);
QVERIFY(!root->property("pinchActive").toBool());
- QCOMPARE(root->property("scale").toReal(), -1.0);
+ QCOMPARE(root->property("pinchScale").toReal(), -1.0);
p0 += QPoint(dragThreshold, 0);
p1 += QPoint(dragThreshold, 0);
@@ -393,7 +714,7 @@ void tst_QQuickPinchHandler::pan()
QQuickTouchUtils::flush(window);
// movement < dragThreshold: pinchHandler not yet active
QVERIFY(!root->property("pinchActive").toBool());
- QCOMPARE(root->property("scale").toReal(), -1.0);
+ QCOMPARE(root->property("pinchScale").toReal(), -1.0);
// just above the dragThreshold: pinchHandler starts
p0 += QPoint(1, 0);
@@ -401,7 +722,7 @@ void tst_QQuickPinchHandler::pan()
pinchSequence.move(0, p0, window).move(1, p1, window).commit();
QQuickTouchUtils::flush(window);
QCOMPARE(pinchHandler->active(), true);
- QCOMPARE(root->property("scale").toReal(), 1.0);
+ QCOMPARE(root->property("pinchScale").toReal(), 1.0);
// Calculation of the center point is tricky at first:
// center point of the two touch points in item coordinates:
@@ -413,6 +734,8 @@ void tst_QQuickPinchHandler::pan()
// blackrect starts at 50,50
QCOMPARE(blackRect->x(), 50.0);
QCOMPARE(blackRect->y(), 50.0);
+ QCOMPARE(translationChangedSpy.size(), 1);
+ QCOMPARE(translationChangedSpy.first().first().value<QVector2D>(), QVector2D(0, 0));
p0 += QPoint(10, 0);
p1 += QPoint(10, 0);
@@ -421,6 +744,8 @@ void tst_QQuickPinchHandler::pan()
QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 11, 90));
QCOMPARE(blackRect->x(), 60.0);
QCOMPARE(blackRect->y(), 50.0);
+ QCOMPARE(translationChangedSpy.size(), 2);
+ QCOMPARE(translationChangedSpy.last().first().value<QVector2D>(), QVector2D(10, 0));
p0 += QPoint(0, 10);
p1 += QPoint(0, 10);
@@ -429,6 +754,8 @@ void tst_QQuickPinchHandler::pan()
QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 11, 90 + 10));
QCOMPARE(blackRect->x(), 60.0);
QCOMPARE(blackRect->y(), 60.0);
+ QCOMPARE(translationChangedSpy.size(), 3);
+ QCOMPARE(translationChangedSpy.last().first().value<QVector2D>(), QVector2D(0, 10));
p0 += QPoint(10, 10);
p1 += QPoint(10, 10);
@@ -438,18 +765,22 @@ void tst_QQuickPinchHandler::pan()
QCOMPARE(pinchHandler->centroid().scenePosition(), QPointF(90 + dragThreshold + 21, 90 + 20));
QCOMPARE(blackRect->x(), 70.0);
QCOMPARE(blackRect->y(), 70.0);
+ QCOMPARE(translationChangedSpy.size(), 4);
+ QCOMPARE(translationChangedSpy.last().first().value<QVector2D>(), QVector2D(10, 10));
}
// pan x beyond bound
p0 += QPoint(100,100);
p1 += QPoint(100,100);
- QTest::touchEvent(window, device).move(0, p0, window).move(1, p1, window);
+ QTest::touchEvent(window, touchscreen.get()).move(0, p0, window).move(1, p1, window);
QQuickTouchUtils::flush(window);
QCOMPARE(blackRect->x(), 140.0);
QCOMPARE(blackRect->y(), 170.0);
+ QCOMPARE(translationChangedSpy.size(), 5);
+ QCOMPARE(translationChangedSpy.last().first().value<QVector2D>(), QVector2D(100, 100));
- QTest::touchEvent(window, device).release(0, p0, window).release(1, p1, window);
+ QTest::touchEvent(window, touchscreen.get()).release(0, p0, window).release(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(!root->property("pinchActive").toBool());
}
@@ -467,7 +798,7 @@ void tst_QQuickPinchHandler::dragAxesEnabled_data()
void tst_QQuickPinchHandler::dragAxesEnabled()
{
- QQuickView *window = createView();
+ QQuickView *window = QQuickViewTestUtils::createView();
QScopedPointer<QQuickView> scope(window);
window->setSource(testFileUrl("pinchproperties.qml"));
window->show();
@@ -489,7 +820,7 @@ void tst_QQuickPinchHandler::dragAxesEnabled()
QPoint blackRectPos = blackRect->position().toPoint();
// press two points, one above the rectangle's center and one below
- QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, touchscreen.get());
pinchSequence.press(0, p0, window).press(1, p1, window).commit();
QQuickTouchUtils::flush(window);
@@ -526,7 +857,7 @@ void tst_QQuickPinchHandler::dragAxesEnabled()
QCOMPARE(blackRect->position().toPoint().x(), xEnabled ? 140 : blackRectPos.x()); // because of xAxis.maximum
QCOMPARE(blackRect->position().toPoint().y(), yEnabled ? 170 : blackRectPos.y()); // because of yAxis.maximum
- QTest::touchEvent(window, device).release(0, p0, window).release(1, p1, window);
+ QTest::touchEvent(window, touchscreen.get()).release(0, p0, window).release(1, p1, window);
QQuickTouchUtils::flush(window);
}
@@ -534,7 +865,7 @@ void tst_QQuickPinchHandler::dragAxesEnabled()
void tst_QQuickPinchHandler::retouch()
{
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
- QQuickView *window = createView();
+ QQuickView *window = QQuickViewTestUtils::createView();
QScopedPointer<QQuickView> scope(window);
window->setSource(testFileUrl("pinchproperties.qml"));
window->show();
@@ -555,7 +886,7 @@ void tst_QQuickPinchHandler::retouch()
QPoint p0(80, 80);
QPoint p1(100, 100);
{
- QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, touchscreen.get());
pinchSequence.press(0, p0, window).commit();
QQuickTouchUtils::flush(window);
// In order for the stationary point to remember its previous position,
@@ -568,7 +899,7 @@ void tst_QQuickPinchHandler::retouch()
pinchSequence.move(0, p0,window).move(1, p1,window).commit();
QQuickTouchUtils::flush(window);
- QCOMPARE(root->property("scale").toReal(), 1.0);
+ QCOMPARE(root->property("pinchScale").toReal(), 1.0);
QCOMPARE(pinchHandler->active(), true);
p0 -= delta;
@@ -579,8 +910,8 @@ void tst_QQuickPinchHandler::retouch()
QCOMPARE(pinchHandler->active(), true);
// accept some slack
- QVERIFY(withinBounds(1.4, root->property("scale").toReal(), 1.6));
- QCOMPARE(pinchHandler->centroid().position(), QPointF(40, 40)); // blackrect is at 50,50
+ QVERIFY(withinBounds(1.4, root->property("pinchScale").toReal(), 1.6));
+ QCOMPARE(pinchHandler->centroid().position().toPoint(), QPoint(40, 40)); // blackrect is at 50,50
QVERIFY(withinBounds(1.4, blackRect->scale(), 1.6));
QCOMPARE(root->property("activeCount").toInt(), 1);
@@ -617,7 +948,7 @@ void tst_QQuickPinchHandler::retouch()
void tst_QQuickPinchHandler::cancel()
{
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
- QQuickView *window = createView();
+ QQuickView *window = QQuickViewTestUtils::createView();
QScopedPointer<QQuickView> scope(window);
window->setSource(testFileUrl("pinchproperties.qml"));
window->show();
@@ -638,7 +969,7 @@ void tst_QQuickPinchHandler::cancel()
QPoint p0(80, 80);
QPoint p1(100, 100);
{
- QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, device);
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(window, touchscreen.get());
pinchSequence.press(0, p0, window).commit();
QQuickTouchUtils::flush(window);
// In order for the stationary point to remember its previous position,
@@ -654,7 +985,7 @@ void tst_QQuickPinchHandler::cancel()
pinchSequence.move(0, p0,window).move(1, p1,window).commit();
QQuickTouchUtils::flush(window);
- QCOMPARE(root->property("scale").toReal(), 1.0);
+ QCOMPARE(root->property("pinchScale").toReal(), 1.0);
QCOMPARE(pinchHandler->active(), true);
p0 -= delta;
@@ -662,18 +993,18 @@ void tst_QQuickPinchHandler::cancel()
pinchSequence.move(0, p0,window).move(1, p1,window).commit();
QQuickTouchUtils::flush(window);
- QVERIFY(withinBounds(1.4, root->property("scale").toReal(), 1.6));
- QCOMPARE(pinchHandler->centroid().position(), QPointF(40, 40)); // blackrect is at 50,50
+ QVERIFY(withinBounds(1.4, root->property("pinchScale").toReal(), 1.6));
+ QCOMPARE(pinchHandler->centroid().position().toPoint(), QPoint(40, 40)); // blackrect is at 50,50
QVERIFY(withinBounds(1.4, blackRect->scale(), 1.6));
QSKIP("cancel is not supported atm");
- QTouchEvent cancelEvent(QEvent::TouchCancel, device);
+ QTouchEvent cancelEvent(QEvent::TouchCancel, touchscreen.get());
QCoreApplication::sendEvent(window, &cancelEvent);
QQuickTouchUtils::flush(window);
- QCOMPARE(root->property("scale").toReal(), 1.0);
- QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50
+ QCOMPARE(root->property("pinchScale").toReal(), 1.0);
+ QCOMPARE(root->property("center").toPoint(), QPoint(40, 40)); // blackrect is at 50,50
QCOMPARE(blackRect->scale(), 1.0);
QVERIFY(!root->property("pinchActive").toBool());
}
@@ -710,7 +1041,7 @@ void tst_QQuickPinchHandler::transformedpinchHandler()
QFETCH(QPoint, p1);
QFETCH(bool, shouldPinch);
- QQuickView *view = createView();
+ QQuickView *view = QQuickViewTestUtils::createView();
QScopedPointer<QQuickView> scope(view);
view->setSource(testFileUrl("transformedPinchHandler.qml"));
view->show();
@@ -724,7 +1055,7 @@ void tst_QQuickPinchHandler::transformedpinchHandler()
const int threshold = qApp->styleHints()->startDragDistance();
{
- QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(view, device);
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(view, touchscreen.get());
// start pinchHandler
pinchSequence.press(0, p0, view).commit();
QQuickTouchUtils::flush(view);
@@ -749,14 +1080,6 @@ void tst_QQuickPinchHandler::transformedpinchHandler()
}
}
-QQuickView *tst_QQuickPinchHandler::createView()
-{
- QQuickView *window = new QQuickView(0);
- window->setGeometry(0,0,240,320);
-
- return window;
-}
-
QTEST_MAIN(tst_QQuickPinchHandler)
#include "tst_qquickpinchhandler.moc"
diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/CMakeLists.txt b/tests/auto/quick/pointerhandlers/qquickpointerhandler/CMakeLists.txt
index 9dc541a845..e15b802814 100644
--- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/CMakeLists.txt
+++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickpointerhandler.pro.
#####################################################################
## tst_qquickpointerhandler Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickpointerhandler LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickpointerhandler
SOURCES
- ../../../shared/util.cpp ../../../shared/util.h
- ../../shared/geometrytestutil.cpp ../../shared/geometrytestutil.h
- ../../shared/viewtestutil.cpp ../../shared/viewtestutil.h
- ../../shared/visualtestutil.cpp ../../shared/visualtestutil.h
tst_qquickpointerhandler.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,10 +37,10 @@ qt_internal_add_test(tst_qquickpointerhandler
qt_internal_extend_target(tst_qquickpointerhandler CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickpointerhandler CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/clip.qml b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/clip.qml
new file mode 100644
index 0000000000..7bc3907c8c
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/clip.qml
@@ -0,0 +1,36 @@
+import QtQuick
+import Qt.test 1.0
+
+Item {
+ width: 200
+ height: 200
+
+ Rectangle {
+ id: circle
+ y: 0
+ width: 100
+ height: width
+ radius: width/2
+ color: "#3e1"
+ clip: true
+
+ // Rectangle contains() is not affected by its 'radius' property
+ containmentMask: QtObject {
+ property alias radius: circle.radius
+ function contains(point: point) : bool {
+ return (Math.pow(point.x - radius, 2) + Math.pow(point.y - radius, 2)) < Math.pow(radius, 2)
+ }
+ }
+ EventHandler {
+ objectName: "circle eventHandler"
+ }
+ Rectangle {
+ width: circle.width/2
+ height: width
+ color: "red"
+ EventHandler {
+ objectName: "eventHandler"
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/grabberSceneChange.qml b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/grabberSceneChange.qml
new file mode 100644
index 0000000000..7bc6028bc2
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/grabberSceneChange.qml
@@ -0,0 +1,78 @@
+import QtQuick
+
+Window {
+ id: root
+ visible: true
+ objectName: "root"
+ width: 320
+ height: 480
+
+ property bool useTimer : false
+ property int grabChangedCounter : 0
+
+ Item {
+ id: back
+ anchors.fill: parent
+
+ Rectangle {
+ id: background
+ anchors.fill: parent
+ color: "blue"
+ }
+
+ Rectangle {
+ id: container
+ objectName: "container"
+ anchors.fill: parent
+ anchors.margins: 50
+ z: 2
+
+ Rectangle {
+ id: likeButton
+ color: "gray"
+ anchors.centerIn: parent
+ width: 200
+ height: 200
+
+ DragHandler {
+ id: handler
+ objectName: "dragHandler"
+ grabPermissions: PointerHandler.CanTakeOverFromItems
+ onGrabChanged: {
+ ++grabChangedCounter
+ }
+ }
+ }
+ }
+
+ Timer {
+ id: reparentTimer
+ running: false
+ interval: 100
+ repeat: false
+ onTriggered: {
+ container.parent = null
+ }
+ }
+
+ Rectangle {
+ id: likeButton2
+ color: "yellow"
+ anchors.centerIn: parent
+ width: 100
+ height: 100
+ z: 3
+
+ MultiPointTouchArea {
+ id: press
+ anchors.fill: parent
+ onPressed: {
+ if (useTimer)
+ reparentTimer.running = true
+ else
+ container.parent = null
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/itemOnly.qml b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/itemOnly.qml
new file mode 100644
index 0000000000..70b4655160
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/itemOnly.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.8
+import Qt.test 1.0
+
+Item {
+ id: root
+ objectName: "root Item"
+ width: 320
+ height: 480
+
+ Rectangle {
+ objectName: "eventItem's bounds"
+ anchors.fill: eventItem
+ color: "lightsteelblue"
+ }
+
+ EventItem {
+ id: eventItem
+ objectName: "eventItem1"
+ x: 5
+ y: 5
+ height: 30
+ width: 30
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/reparenting.qml b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/reparenting.qml
new file mode 100644
index 0000000000..7553bc63cc
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/data/reparenting.qml
@@ -0,0 +1,40 @@
+import QtQuick
+import Qt.test
+
+Item {
+ id: root
+ objectName: "root Item"
+ width: 320
+ height: 480
+
+ Rectangle {
+ id: top
+ objectName: "top"
+ width: parent.width - 12
+ height: parent.height / 2 - 9
+ x: 6; y: 6
+ color: "teal"
+ border.width: 3
+ border.color: handler.parent == top ? "brown" : "transparent"
+ EventHandler {
+ id: handler
+ objectName: "eventHandler"
+ }
+ }
+
+ Rectangle {
+ id: bottom
+ objectName: "bottom"
+ width: parent.width - 12
+ height: parent.height / 2 - 9
+ x: 6; y: parent.height / 2 + 3
+ color: "darkolivegreen"
+ border.width: 3
+ border.color: handler.parent == bottom ? "brown" : "transparent"
+ }
+
+ Timer {
+ interval: 1000; running: true; repeat: true
+ onTriggered: handler.parent = (handler.parent == top ? bottom : top)
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp
index 6b0f574178..1120cb54c2 100644
--- a/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickpointerhandler/tst_qquickpointerhandler.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -33,10 +8,13 @@
#include <QtGui/private/qpointingdevice_p.h>
#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/qquickitem.h>
+#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/qquickview.h>
+#include <QtQml/private/qqmlglobal_p.h> // qmlobject_cast
-#include "../../../shared/util.h"
-#include "../../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QQmlComponent>
Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests")
@@ -103,45 +81,45 @@ public:
return (accept && (state != QEventPoint::State::Released)) ? (int)QPointingDevice::GrabExclusive : (int)NoGrab;
}
- void touchEvent(QTouchEvent *event)
+ void touchEvent(QTouchEvent *event) override
{
qCDebug(lcPointerTests) << event << "will accept?" << acceptTouch;
for (auto &tp : event->points())
eventList.append(Event(Event::TouchDestination, event->type(), tp.state(), grabTransition(acceptTouch, tp.state()), tp.position(), tp.scenePosition()));
event->setAccepted(acceptTouch);
}
- void mousePressEvent(QMouseEvent *event)
+ void mousePressEvent(QMouseEvent *event) override
{
qCDebug(lcPointerTests) << event << "will accept?" << acceptMouse;
eventList.append(Event(Event::MouseDestination, event->type(), QEventPoint::State::Pressed, grabTransition(acceptMouse, QEventPoint::State::Pressed), event->position().toPoint(), event->scenePosition()));
event->setAccepted(acceptMouse);
}
- void mouseMoveEvent(QMouseEvent *event)
+ void mouseMoveEvent(QMouseEvent *event) override
{
qCDebug(lcPointerTests) << event << "will accept?" << acceptMouse;
eventList.append(Event(Event::MouseDestination, event->type(), QEventPoint::State::Updated, grabTransition(acceptMouse, QEventPoint::State::Updated), event->position().toPoint(), event->scenePosition()));
event->setAccepted(acceptMouse);
}
- void mouseReleaseEvent(QMouseEvent *event)
+ void mouseReleaseEvent(QMouseEvent *event) override
{
qCDebug(lcPointerTests) << event << "will accept?" << acceptMouse;
eventList.append(Event(Event::MouseDestination, event->type(), QEventPoint::State::Released, grabTransition(acceptMouse, QEventPoint::State::Released), event->position().toPoint(), event->scenePosition()));
event->setAccepted(acceptMouse);
}
- void mouseDoubleClickEvent(QMouseEvent *event)
+ void mouseDoubleClickEvent(QMouseEvent *event) override
{
qCDebug(lcPointerTests) << event << "will accept?" << acceptMouse;
eventList.append(Event(Event::MouseDestination, event->type(), QEventPoint::State::Pressed, grabTransition(acceptMouse, QEventPoint::State::Pressed), event->position().toPoint(), event->scenePosition()));
event->setAccepted(acceptMouse);
}
- void mouseUngrabEvent()
+ void mouseUngrabEvent() override
{
qCDebug(lcPointerTests);
eventList.append(Event(Event::MouseDestination, QEvent::UngrabMouse, QEventPoint::State::Released, QPointingDevice::UngrabExclusive, QPoint(0,0), QPoint(0,0)));
}
- bool event(QEvent *event)
+ bool event(QEvent *event) override
{
qCDebug(lcPointerTests) << event;
return QQuickItem::event(event);
@@ -154,7 +132,7 @@ public:
bool acceptTouch;
bool filterTouch; // when used as event filter
- bool eventFilter(QObject *o, QEvent *event)
+ bool eventFilter(QObject *o, QEvent *event) override
{
qCDebug(lcPointerTests) << event << o;
if (event->type() == QEvent::TouchBegin ||
@@ -184,7 +162,11 @@ public:
class EventHandler : public QQuickPointerHandler
{
+ Q_OBJECT
public:
+ EventHandler(QQuickItem *parent = nullptr) :
+ QQuickPointerHandler(parent) {}
+
void handlePointerEventImpl(QPointerEvent *event) override
{
QQuickPointerHandler::handlePointerEventImpl(event);
@@ -233,7 +215,8 @@ class tst_PointerHandlers : public QQmlDataTest
Q_OBJECT
public:
tst_PointerHandlers()
- : touchDevice(QTest::createTouchDevice())
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+ , touchDevice(QTest::createTouchDevice())
{}
private slots:
@@ -247,9 +230,14 @@ private slots:
void dynamicCreation();
void handlerInWindow();
void dynamicCreationInWindow();
+ void cppConstruction();
+ void reparenting();
+ void grabberSceneChange_data();
+ void grabberSceneChange();
+ void clip();
protected:
- bool eventFilter(QObject *, QEvent *event)
+ bool eventFilter(QObject *, QEvent *event) override
{
QEventPoint::State tpState;
switch (event->type()) {
@@ -284,8 +272,8 @@ void tst_PointerHandlers::createView(QScopedPointer<QQuickView> &window, const c
// window->setGeometry(0,0,240,320);
window->setSource(testFileUrl(fileName));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -335,11 +323,11 @@ void tst_PointerHandlers::touchEventDelivery()
QTest::touchEvent(window, touchDevice).move(0, p1, window);
QQuickTouchUtils::flush(window);
qCDebug(lcPointerTests) << "events after touch move" << eventItem1->eventList;
- QCOMPARE(eventItem1->eventList.size(), 2); // no grabs -> no updates
+ QCOMPARE(eventItem1->eventList.size(), 3); // no grabs -> only the handler gets the update
QTest::touchEvent(window, touchDevice).release(0, p1, window);
QQuickTouchUtils::flush(window);
qCDebug(lcPointerTests) << "events after touch release" << eventItem1->eventList;
- QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE(eventItem1->eventList.size(), 4);
QCOMPARE_EVENT(eventItem1->eventList.size() - 1, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Released, NoGrab);
eventItem1->eventList.clear();
@@ -390,12 +378,12 @@ void tst_PointerHandlers::touchEventDelivery()
QTest::touchEvent(window, touchDevice).move(0, p1, window);
QQuickTouchUtils::flush(window);
qCDebug(lcPointerTests) << "events after touch move" << eventItem1->eventList;
- QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.size(), 3);
QTest::touchEvent(window, touchDevice).release(0, p1, window);
QQuickTouchUtils::flush(window);
qCDebug(lcPointerTests) << "events after touch release" << eventItem1->eventList;
- QCOMPARE(eventItem1->eventList.size(), 3);
- QCOMPARE_EVENT(2, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Released, NoGrab);
+ QCOMPARE(eventItem1->eventList.size(), 4);
+ QCOMPARE_EVENT(3, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Released, NoGrab);
eventItem1->eventList.clear();
// wait to avoid getting a double click event
@@ -417,11 +405,11 @@ void tst_PointerHandlers::touchEventDelivery()
QTest::touchEvent(window, touchDevice).move(0, p1, window);
QQuickTouchUtils::flush(window);
qCDebug(lcPointerTests) << "events after touch move" << eventItem1->eventList;
- QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.size(), 3);
QTest::touchEvent(window, touchDevice).release(0, p1, window);
QQuickTouchUtils::flush(window);
qCDebug(lcPointerTests) << "events after touch release" << eventItem1->eventList;
- QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE(eventItem1->eventList.size(), 4);
eventItem1->eventList.clear();
// wait to avoid getting a double click event
@@ -485,18 +473,24 @@ void tst_PointerHandlers::mouseEventDelivery()
EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1");
QVERIFY(eventItem1);
+ EventHandler *handler = window->rootObject()->findChild<EventHandler*>("eventHandler");
+ QVERIFY(handler);
+ QCOMPARE(handler->parentItem(), eventItem1);
+ QCOMPARE(handler->target(), eventItem1);
+ QVERIFY(QQuickItemPrivate::get(eventItem1)->extra->resourcesList.contains(handler));
+
// Do not accept anything
QPoint p1 = QPoint(20, 20);
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
qCDebug(lcPointerTests) << "events after mouse press" << eventItem1->eventList;
- QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.size(), 3); // handler: hover; handler: press; item: press
p1 += QPoint(10, 0);
QTest::mouseMove(window, p1);
qCDebug(lcPointerTests) << "events after mouse move" << eventItem1->eventList;
- QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.size(), 4); // handler: hover
QTest::mouseRelease(window, Qt::LeftButton);
qCDebug(lcPointerTests) << "events after mouse release" << eventItem1->eventList;
- QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.size(), 4);
eventItem1->eventList.clear();
// wait to avoid getting a double click event
@@ -509,9 +503,9 @@ void tst_PointerHandlers::mouseEventDelivery()
p1 = QPoint(20, 20);
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
qCDebug(lcPointerTests) << "events after mouse press" << eventItem1->eventList;
- QCOMPARE(eventItem1->eventList.size(), 2);
- QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, NoGrab);
- QCOMPARE_EVENT(1, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, QPointingDevice::GrabExclusive);
+ QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, NoGrab);
+ QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, QPointingDevice::GrabExclusive);
QCOMPARE(window->mouseGrabberItem(), eventItem1);
QPointF localPos = eventItem1->mapFromScene(p1);
@@ -524,11 +518,11 @@ void tst_PointerHandlers::mouseEventDelivery()
p1 += QPoint(10, 0);
QTest::mouseMove(window, p1);
qCDebug(lcPointerTests) << "events after mouse move" << eventItem1->eventList;
- QCOMPARE(eventItem1->eventList.size(), 4);
- QCOMPARE_EVENT(3, Event::MouseDestination, QEvent::MouseMove, QEventPoint::State::Updated, QPointingDevice::GrabExclusive);
+ QCOMPARE(eventItem1->eventList.size(), 5);
+ QCOMPARE_EVENT(4, Event::MouseDestination, QEvent::MouseMove, QEventPoint::State::Updated, QPointingDevice::GrabExclusive);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
qCDebug(lcPointerTests) << "events after mouse release" << eventItem1->eventList;
- QCOMPARE(eventItem1->eventList.size(), 7);
+ QCOMPARE(eventItem1->eventList.size(), 8);
QCOMPARE_EVENT(eventItem1->eventList.size() - 2, Event::MouseDestination, QEvent::MouseButtonRelease, QEventPoint::State::Released, NoGrab);
QCOMPARE_EVENT(eventItem1->eventList.size() - 1, Event::MouseDestination, QEvent::UngrabMouse, QEventPoint::State::Released, QPointingDevice::UngrabExclusive);
eventItem1->eventList.clear();
@@ -631,12 +625,14 @@ void tst_PointerHandlers::dynamicCreation()
QCOMPARE(handler->parentItem(), eventItem1);
QCOMPARE(handler->target(), eventItem1);
+ QVERIFY(QQuickItemPrivate::get(eventItem1)->extra->resourcesList.contains(handler));
QPoint p1(20, 20);
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
- QTRY_COMPARE(eventItem1->eventList.size(), 2);
- QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, NoGrab);
- QCOMPARE_EVENT(1, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, NoGrab);
+ QTRY_COMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE_EVENT(0, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Updated, NoGrab);
+ QCOMPARE_EVENT(1, Event::HandlerDestination, QEvent::Pointer, QEventPoint::State::Pressed, NoGrab);
+ QCOMPARE_EVENT(2, Event::MouseDestination, QEvent::MouseButtonPress, QEventPoint::State::Pressed, NoGrab);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
}
@@ -688,6 +684,181 @@ void tst_PointerHandlers::dynamicCreationInWindow()
QTRY_COMPARE(handler->releaseEventCount, 1);
}
+void tst_PointerHandlers::cppConstruction()
+{
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "itemOnly.qml");
+ QQuickView * window = windowPtr.data();
+
+ EventItem *eventItem1 = window->rootObject()->findChild<EventItem*>("eventItem1");
+ QVERIFY(eventItem1);
+ QQuickItemPrivate *eventItemPriv = QQuickItemPrivate::get(eventItem1);
+ // tell the handler to grab on press
+ eventItem1->grabPointer = true;
+
+ EventHandler handler(eventItem1);
+ QCOMPARE(handler.parentItem(), eventItem1);
+ QCOMPARE(handler.target(), eventItem1);
+ QCOMPARE(eventItemPriv->extra->pointerHandlers.first(), &handler);
+ QVERIFY(eventItemPriv->extra->resourcesList.contains(&handler));
+
+ // the handler and then eventItem1 sees each event
+ QPoint p1 = QPoint(20, 20);
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
+ QCOMPARE(handler.pressEventCount, 1);
+ qCDebug(lcPointerTests) << "events after mouse press" << eventItem1->eventList;
+ QCOMPARE(eventItem1->eventList.size(), 3);
+ QTest::mouseRelease(window, Qt::LeftButton);
+ QCOMPARE(handler.releaseEventCount, 1);
+ qCDebug(lcPointerTests) << "events after mouse release" << eventItem1->eventList;
+ QCOMPARE(eventItem1->eventList.size(), 7);
+
+ // wait to avoid getting a double click event
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
+}
+
+void tst_PointerHandlers::reparenting()
+{
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "reparenting.qml");
+ QQuickView * window = windowPtr.data();
+
+ QQuickItem *topItem = window->rootObject()->findChild<QQuickItem*>("top");
+ QVERIFY(topItem);
+ QQuickItem *bottomItem = window->rootObject()->findChild<QQuickItem*>("bottom");
+ QVERIFY(bottomItem);
+ EventHandler *handler = window->rootObject()->findChild<EventHandler*>("eventHandler");
+ QVERIFY(handler);
+ topItem->setAcceptedMouseButtons(Qt::RightButton);
+
+ for (int i = 1; i < 5; ++i) {
+ QQuickItem *expectedParentItem = (i % 2 ? topItem : bottomItem);
+ QQuickItem *unexpectedParentItem = (i % 2 ? bottomItem : topItem);
+ qCDebug(lcPointerTests) << "initial parent" << handler->parentItem() << "waiting for" << expectedParentItem;
+ QTRY_COMPARE(handler->parentItem(), expectedParentItem);
+ QCOMPARE(handler->target(), expectedParentItem);
+ QVERIFY(QQuickItemPrivate::get(expectedParentItem)->extra.isAllocated());
+ QVERIFY(QQuickItemPrivate::get(expectedParentItem)->extra->resourcesList.contains(handler));
+ if (QQuickItemPrivate::get(unexpectedParentItem)->extra.isAllocated())
+ QVERIFY(!QQuickItemPrivate::get(unexpectedParentItem)->extra->resourcesList.contains(handler));
+ QCOMPARE(expectedParentItem->acceptedMouseButtons(), Qt::AllButtons);
+ QCOMPARE(unexpectedParentItem->acceptedMouseButtons(), unexpectedParentItem == topItem ? Qt::RightButton : Qt::NoButton);
+
+ QPoint pt = expectedParentItem->mapToScene(expectedParentItem->boundingRect().center()).toPoint();
+ qCDebug(lcPointerTests) << "click @" << pt;
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, pt);
+ QTRY_COMPARE(handler->pressEventCount, i);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, pt);
+ QTRY_COMPARE(handler->releaseEventCount, i);
+ }
+}
+
+/*!
+ Verify that removing an item that has a grabbing handler from the scene
+ does not result in crashes in our event dispatching code. The item's window()
+ pointer will be nullptr, so the handler must have released the grab, or never
+ gotten the grab, depending on when the item gets removed.
+
+ See QTBUG-114475.
+*/
+void tst_PointerHandlers::grabberSceneChange_data()
+{
+ QTest::addColumn<bool>("useTimer");
+ QTest::addColumn<int>("grabChangedCount");
+
+ QTest::addRow("Immediately") << false << 0;
+ QTest::addRow("Delayed") << true << 2;
+}
+
+void tst_PointerHandlers::grabberSceneChange()
+{
+ QFETCH(const bool, useTimer);
+ QFETCH(const int, grabChangedCount);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("grabberSceneChange.qml"));
+ QQuickWindow *window = qobject_cast<QQuickWindow*>(component.create());
+ QScopedPointer<QQuickWindow> cleanup(window);
+ QVERIFY(window);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ window->setProperty("useTimer", useTimer);
+
+ QQuickItem *container = window->findChild<QQuickItem *>("container");
+
+ QPoint p1 = QPoint(window->width() / 2, window->height() / 2);
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
+ // The container gets removed from this window, either immediately on
+ // press, or through a timer.
+ QTRY_COMPARE(container->parentItem(), nullptr);
+
+ QEXPECT_FAIL("Delayed",
+ "PointerHandlers don't release their grab when item is removed", Continue);
+ QCOMPARE(window->property("grabChangedCounter").toInt(), grabChangedCount);
+
+ // this should not crash
+ QTest::mouseMove(window, p1 + QPoint(5, 5));
+}
+
+void tst_PointerHandlers::clip()
+{
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "clip.qml");
+ QQuickView * window = windowPtr.data();
+ QVERIFY(window);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+
+ EventHandler *handler = window->contentItem()->findChild<EventHandler*>("eventHandler");
+ EventHandler *circleHandler = window->contentItem()->findChild<EventHandler*>("circle eventHandler");
+
+ QCOMPARE(handler->pressEventCount, 0);
+ QCOMPARE(circleHandler->pressEventCount, 0);
+ QCOMPARE(handler->releaseEventCount, 0);
+ QCOMPARE(circleHandler->releaseEventCount, 0);
+
+ const QPoint rectPt = QPoint(1, 1);
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, rectPt);
+ QCOMPARE(handler->pressEventCount, 1);
+ QCOMPARE(circleHandler->pressEventCount, 0);
+
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, rectPt);
+ QCOMPARE(handler->releaseEventCount, 1);
+ QCOMPARE(circleHandler->releaseEventCount, 0);
+
+
+ handler->pressEventCount = 0;
+ circleHandler->pressEventCount = 0;
+ handler->releaseEventCount = 0;
+ circleHandler->releaseEventCount = 0;
+
+ const QPoint rectAndCirclePt = QPoint(49 ,49);
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, rectAndCirclePt);
+ QCOMPARE(handler->pressEventCount, 1);
+ QCOMPARE(circleHandler->pressEventCount, 1);
+
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, rectAndCirclePt);
+ QCOMPARE(handler->releaseEventCount, 1);
+ QCOMPARE(circleHandler->releaseEventCount, 1);
+
+
+ handler->pressEventCount = 0;
+ circleHandler->pressEventCount = 0;
+ handler->releaseEventCount = 0;
+ circleHandler->releaseEventCount = 0;
+
+ const QPoint circlePt = QPoint(51 ,51);
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, circlePt);
+ QCOMPARE(handler->pressEventCount, 0);
+ QCOMPARE(circleHandler->pressEventCount, 1);
+
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, circlePt);
+ QCOMPARE(handler->releaseEventCount, 0);
+ QCOMPARE(circleHandler->releaseEventCount, 1);
+}
+
QTEST_MAIN(tst_PointerHandlers)
#include "tst_qquickpointerhandler.moc"
diff --git a/tests/auto/quick/pointerhandlers/qquickpointhandler/BLACKLIST b/tests/auto/quick/pointerhandlers/qquickpointhandler/BLACKLIST
index f4d271c230..5d6a59e1dd 100644
--- a/tests/auto/quick/pointerhandlers/qquickpointhandler/BLACKLIST
+++ b/tests/auto/quick/pointerhandlers/qquickpointhandler/BLACKLIST
@@ -1,2 +1,4 @@
[tabletStylus]
macos ci
+qnx
+android # QTBUG-103068
diff --git a/tests/auto/quick/pointerhandlers/qquickpointhandler/CMakeLists.txt b/tests/auto/quick/pointerhandlers/qquickpointhandler/CMakeLists.txt
index 507bc7549b..aa73218361 100644
--- a/tests/auto/quick/pointerhandlers/qquickpointhandler/CMakeLists.txt
+++ b/tests/auto/quick/pointerhandlers/qquickpointhandler/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickpointhandler.pro.
#####################################################################
## tst_qquickpointhandler Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickpointhandler LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickpointhandler
SOURCES
- ../../../shared/util.cpp ../../../shared/util.h
- ../../shared/geometrytestutil.cpp ../../shared/geometrytestutil.h
- ../../shared/viewtestutil.cpp ../../shared/viewtestutil.h
- ../../shared/visualtestutil.cpp ../../shared/visualtestutil.h
tst_qquickpointhandler.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -38,10 +40,10 @@ qt_internal_add_test(tst_qquickpointhandler
qt_internal_extend_target(tst_qquickpointhandler CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickpointhandler CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/pointerhandlers/qquickpointhandler/data/multiPointTracker.qml b/tests/auto/quick/pointerhandlers/qquickpointhandler/data/multiPointTracker.qml
index 3f50d7c761..616d526592 100644
--- a/tests/auto/quick/pointerhandlers/qquickpointhandler/data/multiPointTracker.qml
+++ b/tests/auto/quick/pointerhandlers/qquickpointhandler/data/multiPointTracker.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/qquickpointhandler/data/pointTracker.qml b/tests/auto/quick/pointerhandlers/qquickpointhandler/data/pointTracker.qml
index 674bbda850..2de03703e8 100644
--- a/tests/auto/quick/pointerhandlers/qquickpointhandler/data/pointTracker.qml
+++ b/tests/auto/quick/pointerhandlers/qquickpointhandler/data/pointTracker.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp b/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp
index a2415fedd7..e1641c282e 100644
--- a/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickpointhandler/tst_qquickpointhandler.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -33,13 +8,17 @@
#include <QtQuick/private/qquickpointhandler_p.h>
#include <qpa/qwindowsysteminterface.h>
+#include <private/qhighdpiscaling_p.h>
#include <private/qquickwindow_p.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlproperty.h>
-#include "../../../shared/util.h"
-#include "../../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+
+#include <QtCore/qpointer.h>
Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests")
@@ -48,7 +27,8 @@ class tst_PointHandler : public QQmlDataTest
Q_OBJECT
public:
tst_PointHandler()
- : touchDevice(QTest::createTouchDevice())
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+ , touchDevice(QTest::createTouchDevice())
{}
private slots:
@@ -59,6 +39,7 @@ private slots:
void simultaneousMultiTouch();
void pressedMultipleButtons_data();
void pressedMultipleButtons();
+ void ignoreSystemSynthMouse();
private:
void createView(QScopedPointer<QQuickView> &window, const char *fileName);
@@ -70,8 +51,8 @@ void tst_PointHandler::createView(QScopedPointer<QQuickView> &window, const char
window.reset(new QQuickView);
window->setSource(testFileUrl(fileName));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::centerOnScreen(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -104,20 +85,20 @@ void tst_PointHandler::singleTouch()
QTest::touchEvent(window, touchDevice).press(1, point, window);
QQuickTouchUtils::flush(window);
QTRY_COMPARE(handler->active(), true);
- QCOMPARE(activeSpy.count(), 1);
- QCOMPARE(pointSpy.count(), 1);
+ QCOMPARE(activeSpy.size(), 1);
+ QCOMPARE(pointSpy.size(), 1);
QCOMPARE(handler->point().position().toPoint(), point);
QCOMPARE(handler->point().scenePosition().toPoint(), point);
QCOMPARE(handler->point().pressedButtons(), Qt::NoButton);
QCOMPARE(handler->translation(), QVector2D());
- QCOMPARE(translationSpy.count(), 1);
+ QCOMPARE(translationSpy.size(), 1);
point += QPoint(10, 10);
QTest::touchEvent(window, touchDevice).move(1, point, window);
QQuickTouchUtils::flush(window);
QCOMPARE(handler->active(), true);
- QCOMPARE(activeSpy.count(), 1);
- QCOMPARE(pointSpy.count(), 2);
+ QCOMPARE(activeSpy.size(), 1);
+ QCOMPARE(pointSpy.size(), 2);
QCOMPARE(handler->point().position().toPoint(), point);
QCOMPARE(handler->point().scenePosition().toPoint(), point);
QCOMPARE(handler->point().pressPosition().toPoint(), QPoint(100, 100));
@@ -126,15 +107,15 @@ void tst_PointHandler::singleTouch()
QVERIFY(handler->point().velocity().x() > 0);
QVERIFY(handler->point().velocity().y() > 0);
QCOMPARE(handler->translation(), QVector2D(10, 10));
- QCOMPARE(translationSpy.count(), 2);
+ QCOMPARE(translationSpy.size(), 2);
QTest::touchEvent(window, touchDevice).release(1, point, window);
QQuickTouchUtils::flush(window);
QTRY_COMPARE(handler->active(), false);
- QCOMPARE(activeSpy.count(), 2);
- QCOMPARE(pointSpy.count(), 3);
+ QCOMPARE(activeSpy.size(), 2);
+ QCOMPARE(pointSpy.size(), 3);
QCOMPARE(handler->translation(), QVector2D());
- QCOMPARE(translationSpy.count(), 3);
+ QCOMPARE(translationSpy.size(), 3);
}
void tst_PointHandler::tabletStylus()
@@ -146,54 +127,59 @@ void tst_PointHandler::tabletStylus()
QQuickPointHandler *handler = window->rootObject()->findChild<QQuickPointHandler *>("pointHandler");
QVERIFY(handler);
handler->setAcceptedDevices(QInputDevice::DeviceType::Stylus);
+ // avoid generating a double click
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
QSignalSpy activeSpy(handler, SIGNAL(activeChanged()));
QSignalSpy pointSpy(handler, SIGNAL(pointChanged()));
QSignalSpy translationSpy(handler, SIGNAL(translationChanged()));
QPoint point(100,100);
+ QPoint pointLocalDPI = QHighDpi::fromNativeLocalPosition(point, window);
const qint64 stylusId = 1234567890;
QWindowSystemInterface::handleTabletEvent(window, point, window->mapToGlobal(point),
int(QInputDevice::DeviceType::Stylus), int(QPointingDevice::PointerType::Pen), Qt::LeftButton, 0.5, 25, 35, 0.6, 12.3, 3, stylusId, Qt::NoModifier);
QTRY_COMPARE(handler->active(), true);
- QCOMPARE(activeSpy.count(), 1);
- QCOMPARE(pointSpy.count(), 1);
- QCOMPARE(handler->point().position().toPoint(), point);
- QCOMPARE(handler->point().scenePosition().toPoint(), point);
+ QCOMPARE(activeSpy.size(), 1);
+ QCOMPARE(pointSpy.size(), 1);
+ QCOMPARE(handler->point().position().toPoint(), pointLocalDPI);
+ QCOMPARE(handler->point().scenePosition().toPoint(), pointLocalDPI);
QCOMPARE(handler->point().pressedButtons(), Qt::LeftButton);
QCOMPARE(handler->point().pressure(), 0.5);
QCOMPARE(handler->point().rotation(), 12.3);
QCOMPARE(handler->point().uniqueId().numericId(), stylusId);
QCOMPARE(handler->translation(), QVector2D());
- QCOMPARE(translationSpy.count(), 1);
+ QCOMPARE(translationSpy.size(), 1);
- point += QPoint(10, 10);
+ QPoint delta(10, 10);
+ QPoint deltaLocalDPI = QHighDpi::fromNativeLocalPosition(delta, window);
+ point += delta;
QWindowSystemInterface::handleTabletEvent(window, point, window->mapToGlobal(point),
int(QInputDevice::DeviceType::Stylus), int(QPointingDevice::PointerType::Pen), Qt::LeftButton, 0.45, 23, 33, 0.57, 15.6, 3, stylusId, Qt::NoModifier);
- QTRY_COMPARE(pointSpy.count(), 2);
+ QTRY_COMPARE(pointSpy.size(), 2);
QCOMPARE(handler->active(), true);
- QCOMPARE(activeSpy.count(), 1);
- QCOMPARE(handler->point().position().toPoint(), point);
- QCOMPARE(handler->point().scenePosition().toPoint(), point);
- QCOMPARE(handler->point().pressPosition().toPoint(), QPoint(100, 100));
- QCOMPARE(handler->point().scenePressPosition().toPoint(), QPoint(100, 100));
+ QCOMPARE(activeSpy.size(), 1);
+ QCOMPARE(handler->point().position().toPoint(), pointLocalDPI + deltaLocalDPI);
+ QCOMPARE(handler->point().scenePosition().toPoint(), pointLocalDPI + deltaLocalDPI);
+ QCOMPARE(handler->point().pressPosition().toPoint(), pointLocalDPI);
+ QCOMPARE(handler->point().scenePressPosition().toPoint(), pointLocalDPI);
QCOMPARE(handler->point().pressedButtons(), Qt::LeftButton);
QCOMPARE(handler->point().pressure(), 0.45);
QCOMPARE(handler->point().rotation(), 15.6);
QCOMPARE(handler->point().uniqueId().numericId(), stylusId);
- QVERIFY(handler->point().velocity().x() > 0);
- QVERIFY(handler->point().velocity().y() > 0);
- QCOMPARE(handler->translation(), QVector2D(10, 10));
- QCOMPARE(translationSpy.count(), 2);
+ QCOMPARE_GT(handler->point().velocity().x(), 0);
+ QCOMPARE_GT(handler->point().velocity().y(), 0);
+ QCOMPARE(handler->translation(), QVector2D(deltaLocalDPI));
+ QCOMPARE(translationSpy.size(), 2);
QWindowSystemInterface::handleTabletEvent(window, point, window->mapToGlobal(point),
int(QInputDevice::DeviceType::Stylus), int(QPointingDevice::PointerType::Pen), Qt::NoButton, 0, 0, 0, 0, 0, 0, stylusId, Qt::NoModifier);
QTRY_COMPARE(handler->active(), false);
- QCOMPARE(activeSpy.count(), 2);
- QCOMPARE(pointSpy.count(), 3);
+ QCOMPARE(activeSpy.size(), 2);
+ QCOMPARE(pointSpy.size(), 3);
QCOMPARE(handler->translation(), QVector2D());
- QCOMPARE(translationSpy.count(), 3);
+ QCOMPARE(translationSpy.size(), 3);
}
void tst_PointHandler::simultaneousMultiTouch()
@@ -202,7 +188,7 @@ void tst_PointHandler::simultaneousMultiTouch()
createView(windowPtr, "multiPointTracker.qml");
QQuickView * window = windowPtr.data();
QList<QQuickPointHandler *> handlers = window->rootObject()->findChildren<QQuickPointHandler *>();
- QCOMPARE(handlers.count(), 3);
+ QCOMPARE(handlers.size(), 3);
QVector<QSignalSpy*> activeSpies;
QVector<QSignalSpy*> pointSpies;
@@ -221,8 +207,8 @@ void tst_PointHandler::simultaneousMultiTouch()
int i = 0;
for (auto h : handlers) {
QTRY_COMPARE(h->active(), true);
- QCOMPARE(activeSpies[i]->count(), 1);
- QCOMPARE(pointSpies[i]->count(), 1);
+ QCOMPARE(activeSpies[i]->size(), 1);
+ QCOMPARE(pointSpies[i]->size(), 1);
int chosenPointIndex = points.indexOf(h->point().position().toPoint());
QVERIFY(chosenPointIndex != -1);
// Verify that each handler chose a unique point
@@ -232,7 +218,7 @@ void tst_PointHandler::simultaneousMultiTouch()
QCOMPARE(h->point().scenePosition().toPoint(), point);
QCOMPARE(h->point().pressedButtons(), Qt::NoButton);
QCOMPARE(h->translation(), QVector2D());
- QCOMPARE(translationSpies[i]->count(), 1);
+ QCOMPARE(translationSpies[i]->size(), 1);
++i;
}
@@ -243,8 +229,8 @@ void tst_PointHandler::simultaneousMultiTouch()
i = 0;
for (auto h : handlers) {
QCOMPARE(h->active(), true);
- QCOMPARE(activeSpies[i]->count(), 1);
- QCOMPARE(pointSpies[i]->count(), 2);
+ QCOMPARE(activeSpies[i]->size(), 1);
+ QCOMPARE(pointSpies[i]->size(), 2);
QCOMPARE(h->point().position().toPoint(), points[pointIndexPerHandler[i]]);
QCOMPARE(h->point().scenePosition().toPoint(), points[pointIndexPerHandler[i]]);
QCOMPARE(h->point().pressPosition().toPoint(), pressPoints[pointIndexPerHandler[i]]);
@@ -253,7 +239,7 @@ void tst_PointHandler::simultaneousMultiTouch()
QVERIFY(h->point().velocity().x() > 0);
QVERIFY(h->point().velocity().y() > 0);
QCOMPARE(h->translation(), QVector2D(10 + 10 * pointIndexPerHandler[i], 10 + 10 * pointIndexPerHandler[i] % 2));
- QCOMPARE(translationSpies[i]->count(), 2);
+ QCOMPARE(translationSpies[i]->size(), 2);
++i;
}
@@ -262,10 +248,10 @@ void tst_PointHandler::simultaneousMultiTouch()
i = 0;
for (auto h : handlers) {
QTRY_COMPARE(h->active(), false);
- QCOMPARE(activeSpies[i]->count(), 2);
- QCOMPARE(pointSpies[i]->count(), 3);
+ QCOMPARE(activeSpies[i]->size(), 2);
+ QCOMPARE(pointSpies[i]->size(), 3);
QCOMPARE(h->translation(), QVector2D());
- QCOMPARE(translationSpies[i]->count(), 3);
+ QCOMPARE(translationSpies[i]->size(), 3);
++i;
}
@@ -379,7 +365,7 @@ void tst_PointHandler::pressedMultipleButtons()
QPoint point(100,100);
- for (int i = 0; i < buttons.count(); ++i) {
+ for (int i = 0; i < buttons.size(); ++i) {
int btns = int(buttons.at(i));
int release = 0;
if (i > 0) {
@@ -399,8 +385,91 @@ void tst_PointHandler::pressedMultipleButtons()
QTest::mousePress(windowPtr.data(), Qt::NoButton, Qt::NoModifier, point);
QCOMPARE(handler->active(), false);
- QCOMPARE(activeSpy.count(), activeChangeCount);
- QCOMPARE(pointSpy.count(), changeCount);
+ QCOMPARE(activeSpy.size(), activeChangeCount);
+ QCOMPARE(pointSpy.size(), changeCount);
+}
+
+void tst_PointHandler::ignoreSystemSynthMouse() // QTBUG-104890
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("pointTracker.qml")));
+ QQuickPointHandler *handler = window.rootObject()->findChild<QQuickPointHandler *>();
+ QVERIFY(handler);
+ auto devPriv = QPointingDevicePrivate::get(touchDevice);
+ QSignalSpy activeSpy(handler, SIGNAL(activeChanged()));
+ QSignalSpy pointSpy(handler, SIGNAL(pointChanged()));
+
+ // touch press
+ QPoint point(100,100);
+ QTest::touchEvent(&window, touchDevice).press(0, point, &window);
+ QQuickTouchUtils::flush(&window);
+
+ // touch move
+ point += QPoint(10, 10);
+ QTest::touchEvent(&window, touchDevice).move(0, point, &window);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(handler->active(), true);
+ QCOMPARE(activeSpy.size(), 1);
+ QCOMPARE(pointSpy.size(), 2);
+ QVERIFY(devPriv->queryPointById(0)->passiveGrabbers.contains(handler));
+
+ // Windows begins to synthesize mouse events in parallel with the touch event stream: move to touchpoint position, then press
+ {
+ QMouseEvent move(QEvent::MouseMove, point, point, window.mapToGlobal(point),
+ Qt::NoButton, Qt::NoButton, Qt::NoModifier, Qt::MouseEventSynthesizedBySystem, touchDevice);
+ move.setTimestamp(235); // slightly after the last touch event
+ QGuiApplication::sendEvent(&window, &move);
+ }
+ QCOMPARE(handler->active(), true);
+ QCOMPARE(activeSpy.size(), 1);
+ QCOMPARE(pointSpy.size(), 2);
+ QVERIFY(devPriv->queryPointById(0)->passiveGrabbers.contains(handler));
+ {
+ QMouseEvent press(QEvent::MouseButtonPress, point, point, window.mapToGlobal(point),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier, Qt::MouseEventSynthesizedBySystem, touchDevice);
+ press.setTimestamp(235);
+ QGuiApplication::sendEvent(&window, &press);
+ }
+ QCOMPARE(handler->active(), true);
+ QCOMPARE(activeSpy.size(), 1);
+ QCOMPARE(pointSpy.size(), 2);
+ QVERIFY(devPriv->queryPointById(0)->passiveGrabbers.contains(handler));
+
+ // another touch move
+ point += QPoint(10, 10);
+ QTest::touchEvent(&window, touchDevice).move(0, point, &window);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(handler->active(), true);
+ QCOMPARE(activeSpy.size(), 1);
+ QCOMPARE(pointSpy.size(), 3);
+ QCOMPARE(handler->point().position().toPoint(), point);
+ QCOMPARE(handler->point().scenePosition().toPoint(), point);
+ QCOMPARE(handler->point().pressPosition().toPoint(), QPoint(100, 100));
+ QCOMPARE(handler->point().scenePressPosition().toPoint(), QPoint(100, 100));
+ QVERIFY(devPriv->queryPointById(0)->passiveGrabbers.contains(handler));
+
+ // another fake mouse move
+ {
+ QMouseEvent move(QEvent::MouseMove, point, point, window.mapToGlobal(point),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier, Qt::MouseEventSynthesizedBySystem, touchDevice);
+ move.setTimestamp(240);
+ QGuiApplication::sendEvent(&window, &move);
+ }
+ QCOMPARE(handler->active(), true);
+ QCOMPARE(activeSpy.size(), 1);
+ QCOMPARE(pointSpy.size(), 3);
+ QCOMPARE(handler->point().position().toPoint(), point);
+ QCOMPARE(handler->point().scenePosition().toPoint(), point);
+ QCOMPARE(handler->point().pressPosition().toPoint(), QPoint(100, 100));
+ QCOMPARE(handler->point().scenePressPosition().toPoint(), QPoint(100, 100));
+ QVERIFY(devPriv->queryPointById(0)->passiveGrabbers.contains(handler));
+
+ // end with released state
+ QTest::touchEvent(&window, touchDevice).release(0, point, &window);
+ QMouseEvent release(QEvent::MouseButtonRelease, point, point, window.mapToGlobal(point),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier, Qt::MouseEventSynthesizedBySystem);
+ release.setTimestamp(280);
+ QGuiApplication::sendEvent(&window, &release);
}
QTEST_MAIN(tst_PointHandler)
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/BLACKLIST b/tests/auto/quick/pointerhandlers/qquicktaphandler/BLACKLIST
new file mode 100644
index 0000000000..1559014480
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/BLACKLIST
@@ -0,0 +1,3 @@
+# QTBUG-103072
+[gesturePolicyDragWithinBounds]
+android
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/CMakeLists.txt b/tests/auto/quick/pointerhandlers/qquicktaphandler/CMakeLists.txt
index babe276519..94834e04c6 100644
--- a/tests/auto/quick/pointerhandlers/qquicktaphandler/CMakeLists.txt
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquicktaphandler.pro.
#####################################################################
## tst_qquicktaphandler Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicktaphandler LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquicktaphandler
SOURCES
- ../../../shared/util.cpp ../../../shared/util.h
- ../../shared/geometrytestutil.cpp ../../shared/geometrytestutil.h
- ../../shared/viewtestutil.cpp ../../shared/viewtestutil.h
- ../../shared/visualtestutil.cpp ../../shared/visualtestutil.h
tst_qquicktaphandler.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,10 +37,10 @@ qt_internal_add_test(tst_qquicktaphandler
qt_internal_extend_target(tst_qquicktaphandler CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquicktaphandler CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml
index 800c25c77d..fc1e623902 100644
--- a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/Button.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
@@ -35,13 +10,20 @@ Rectangle {
property alias pressed: tap.pressed
property bool checked: false
property alias gesturePolicy: tap.gesturePolicy
+ property alias longPressThreshold: tap.longPressThreshold
property point tappedPosition: Qt.point(0, 0)
+ property real timeHeldWhenTapped: 0
+ property real timeHeldWhenLongPressed: 0
signal tapped
signal canceled
width: label.implicitWidth * 1.5; height: label.implicitHeight * 2.0
border.color: "#9f9d9a"; border.width: 1; radius: height / 4; antialiasing: true
+ function assignUndefinedLongPressThreshold() {
+ tap.longPressThreshold = undefined
+ }
+
gradient: Gradient {
GradientStop { position: 0.0; color: tap.pressed ? "#b8b5b2" : "#efebe7" }
GradientStop { position: 1.0; color: "#b8b5b2" }
@@ -50,11 +32,17 @@ Rectangle {
TapHandler {
id: tap
objectName: label.text
- longPressThreshold: 100 // CI can be insanely slow, so don't demand a timely release to generate onTapped
- onTapped: {
+ onSingleTapped: console.log("Single tap")
+ onDoubleTapped: console.log("Double tap")
+ onTapped: (eventPoint, button) => {
+ console.log("Tapped", button, eventPoint)
tapFlash.start()
root.tappedPosition = point.scenePosition
root.tapped()
+ root.timeHeldWhenTapped = tap.timeHeld // eventPoint.timeHeld is already 0
+ }
+ onLongPressed: {
+ root.timeHeldWhenLongPressed = tap.timeHeld
}
onCanceled: root.canceled()
}
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml
index 158a02b7a6..9483a12d1c 100644
--- a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/FlashAnimation.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml
index 4a8b8e1375..b36fcdef08 100644
--- a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttonOverrideHandler.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml
index 821b8073e9..04fbbc176b 100644
--- a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/buttons.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
@@ -34,19 +9,25 @@ Item {
Button {
objectName: "DragThreshold"
label: "DragThreshold"
- x: 10; y: 10; width: parent.width - 20; height: 40
+ x: 10; y: 10; width: 300; height: 40
gesturePolicy: TapHandler.DragThreshold
}
Button {
objectName: "WithinBounds"
label: "WithinBounds"
- x: 10; y: 60; width: parent.width - 20; height: 40
+ x: 10; y: 60; width: 300; height: 40
gesturePolicy: TapHandler.WithinBounds
}
Button {
objectName: "ReleaseWithinBounds"
label: "ReleaseWithinBounds"
- x: 10; y: 110; width: parent.width - 20; height: 40
+ x: 10; y: 110; width: 300; height: 40
gesturePolicy: TapHandler.ReleaseWithinBounds
}
+ Button {
+ objectName: "DragWithinBounds"
+ label: "DragWithinBounds"
+ x: 10; y: 160; width: 300; height: 40
+ gesturePolicy: TapHandler.DragWithinBounds
+ }
}
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/dragReleaseMenu.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/dragReleaseMenu.qml
new file mode 100644
index 0000000000..5f60ef879e
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/dragReleaseMenu.qml
@@ -0,0 +1,64 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Item {
+ width: 480
+ height: 480
+ property alias feedbackText: feedback.text
+
+ Rectangle {
+ id: rect
+ anchors.fill: parent; anchors.margins: 40
+ color: tapHandler.active ? "lightgrey" : "darkgrey"
+
+ TapHandler {
+ id: tapHandler
+ gesturePolicy: TapHandler.DragWithinBounds
+ onPressedChanged: if (pressed) {
+ menu.x = point.position.x - menu.width / 2
+ menu.y = point.position.y - menu.height / 2
+ } else {
+ if (menu.highlightedMenuItem !== "")
+ feedback.text = menu.highlightedMenuItem
+ }
+ onCanceled: feedback.text = "canceled"
+ }
+
+ Column {
+ id: menu
+ visible: tapHandler.pressed
+ opacity: Math.min(1, tapHandler.timeHeld)
+ property string highlightedMenuItem: ""
+ Repeater {
+ model: [ "top", "middle", "bottom" ]
+ delegate: Rectangle {
+ property bool highlighted: tapHandler.pressed &&
+ contains(mapFromItem(rect, tapHandler.point.position))
+ onHighlightedChanged: {
+ if (highlighted)
+ menu.highlightedMenuItem = menuItemText.text
+ else if (menu.highlightedMenuItem === menuItemText.text)
+ menu.highlightedMenuItem = ""
+ }
+ width: 100
+ height: 20
+ color: highlighted ? "lightsteelblue" : "aliceblue"
+ Text {
+ id: menuItemText
+ anchors.centerIn: parent
+ text: modelData
+ }
+ }
+ }
+ }
+
+ Text {
+ id: feedback
+ x: 6; y: 6
+ textFormat: Text.MarkdownText
+ text: "hold for context menu"
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/nested.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/nested.qml
new file mode 100644
index 0000000000..c0f0b10bf4
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/nested.qml
@@ -0,0 +1,35 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+import QtQuick 2.12
+
+Item {
+ width: 300
+ height: 200
+ property var taps: []
+
+ Rectangle {
+ x: 25
+ y: 25
+ width: 200
+ height: 100
+ color: "salmon"
+
+ TapHandler {
+ objectName: "parentTapHandler"
+ onTapped: taps.push(objectName)
+ }
+
+ Rectangle {
+ x: 25
+ y: 25
+ width: 200
+ height: 100
+ color: "lightsteelblue"
+
+ TapHandler {
+ objectName: "childTapHandler"
+ onTapped: taps.push(objectName)
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/nestedAndSibling.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/nestedAndSibling.qml
new file mode 100644
index 0000000000..7732c42082
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/nestedAndSibling.qml
@@ -0,0 +1,39 @@
+import QtQuick 2.15
+import QtQuick.Window 2.15
+import QtQuick.Controls 2.15
+
+Item {
+ width: 360
+ height: 280
+
+ Rectangle {
+ width: 200; height: 200; x: 100; y: 10
+ color: th1.pressed ? "blue" : "lightblue"
+
+ TapHandler {
+ id: th1
+ objectName: "th1"
+ }
+
+ Rectangle {
+ width: 200; height: 200; x: 50; y: 50
+ color: th2.pressed ? "steelblue" : "lightsteelblue"
+
+ TapHandler {
+ id: th2
+ objectName: "th2"
+ }
+ }
+ }
+
+ Rectangle {
+ width: 200; height: 200; x: 10; y: 50
+ color: th3.pressed ? "goldenrod" : "beige"
+
+ TapHandler {
+ id: th3
+ objectName: "th3"
+ }
+ }
+}
+
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/rightTapHandler.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/rightTapHandler.qml
index aea01c154c..85f5c87b39 100644
--- a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/rightTapHandler.qml
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/rightTapHandler.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/simpleTapHandler.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/simpleTapHandler.qml
new file mode 100644
index 0000000000..026be48f83
--- /dev/null
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/simpleTapHandler.qml
@@ -0,0 +1,14 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.12
+
+Item {
+ id: root
+ width: 100
+ height: 100
+ property int tapCount: 0
+ TapHandler {
+ onTapped: { ++root.tapCount }
+ }
+}
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/tapHandlersOverlapped.qml b/tests/auto/quick/pointerhandlers/qquicktaphandler/data/tapHandlersOverlapped.qml
deleted file mode 100644
index 8d2e36d921..0000000000
--- a/tests/auto/quick/pointerhandlers/qquicktaphandler/data/tapHandlersOverlapped.qml
+++ /dev/null
@@ -1,60 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-import QtQuick 2.12
-
-Item {
- width: 300
- height: 200
- property var taps: []
-
- Rectangle {
- x: 25
- y: 25
- width: 200
- height: 100
- color: "salmon"
-
- TapHandler {
- objectName: "parentTapHandler"
- onTapped: taps.push(objectName)
- }
-
- Rectangle {
- x: 25
- y: 25
- width: 200
- height: 100
- color: "lightsteelblue"
-
- TapHandler {
- objectName: "childTapHandler"
- onTapped: taps.push(objectName)
- }
- }
- }
-}
diff --git a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp
index 8457488cd9..1dab0836cd 100644
--- a/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquicktaphandler/tst_qquicktaphandler.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -41,8 +16,8 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlproperty.h>
-#include "../../../shared/util.h"
-#include "../../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests")
@@ -51,6 +26,7 @@ class tst_TapHandler : public QQmlDataTest
Q_OBJECT
public:
tst_TapHandler()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{}
private slots:
@@ -63,33 +39,68 @@ private slots:
void mouseGesturePolicyWithinBounds();
void touchGesturePolicyReleaseWithinBounds();
void mouseGesturePolicyReleaseWithinBounds();
+ void gesturePolicyDragWithinBounds_data();
+ void gesturePolicyDragWithinBounds();
void touchMultiTap();
+ void mouseMultiTap_data();
void mouseMultiTap();
- void touchLongPress();
- void mouseLongPress();
+ void mouseMultiTapLeftRight_data();
+ void mouseMultiTapLeftRight();
+ void singleTapDoubleTap_data();
+ void singleTapDoubleTap();
+ void longPress_data();
+ void longPress();
void buttonsMultiTouch();
void componentUserBehavioralOverride();
void rightLongPressIgnoreWheel();
void negativeZStackingOrder();
+ void nonTopLevelParentWindow();
+ void nestedDoubleTap_data();
+ void nestedDoubleTap();
+ void nestedAndSiblingPropagation_data();
+ void nestedAndSiblingPropagation();
private:
- void createView(QScopedPointer<QQuickView> &window, const char *fileName);
- QPointingDevice *touchDevice = QTest::createTouchDevice();
+ void createView(QScopedPointer<QQuickView> &window, const char *fileName,
+ QWindow *parent = nullptr);
+ QPointingDevice *touchDevice = QTest::createTouchDevice(); // TODO const after fixing QTBUG-107864
+ void mouseEvent(QEvent::Type type, Qt::MouseButton button, const QPoint &point,
+ QWindow *targetWindow, QWindow *mapToWindow);
};
-void tst_TapHandler::createView(QScopedPointer<QQuickView> &window, const char *fileName)
+void tst_TapHandler::createView(QScopedPointer<QQuickView> &window, const char *fileName,
+ QWindow *parent)
{
- window.reset(new QQuickView);
+ window.reset(new QQuickView(parent));
+ if (parent) {
+ parent->show();
+ QVERIFY(QTest::qWaitForWindowActive(parent));
+ }
+
window->setSource(testFileUrl(fileName));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
}
+void tst_TapHandler::mouseEvent(QEvent::Type type, Qt::MouseButton button, const QPoint &point,
+ QWindow *targetWindow, QWindow *mapToWindow)
+{
+ QVERIFY(targetWindow);
+ QVERIFY(mapToWindow);
+ auto buttons = button;
+ if (type == QEvent::MouseButtonRelease) {
+ buttons = Qt::NoButton;
+ }
+ QMouseEvent me(type, point, mapToWindow->mapToGlobal(point), button, buttons,
+ Qt::KeyboardModifiers(), QPointingDevice::primaryPointingDevice());
+ QVERIFY(qApp->notify(targetWindow, &me));
+}
+
void tst_TapHandler::initTestCase()
{
// This test assumes that we don't get synthesized mouse events from QGuiApplication
@@ -123,7 +134,7 @@ void tst_TapHandler::touchGesturePolicyDragThreshold()
QTest::touchEvent(window, touchDevice).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool());
- QCOMPARE(dragThresholdTappedSpy.count(), 1);
+ QCOMPARE(dragThresholdTappedSpy.size(), 1);
QCOMPARE(buttonDragThreshold->property("tappedPosition").toPoint(), p1);
QCOMPARE(tapHandler->point().position(), QPointF());
@@ -144,7 +155,7 @@ void tst_TapHandler::touchGesturePolicyDragThreshold()
QTest::touchEvent(window, touchDevice).release(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(!buttonDragThreshold->property("pressed").toBool());
- QCOMPARE(dragThresholdTappedSpy.count(), 0);
+ QCOMPARE(dragThresholdTappedSpy.size(), 0);
}
void tst_TapHandler::mouseGesturePolicyDragThreshold()
@@ -169,7 +180,7 @@ void tst_TapHandler::mouseGesturePolicyDragThreshold()
QVERIFY(buttonDragThreshold->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool());
- QTRY_COMPARE(dragThresholdTappedSpy.count(), 1);
+ QTRY_COMPARE(dragThresholdTappedSpy.size(), 1);
QCOMPARE(buttonDragThreshold->property("tappedPosition").toPoint(), p1);
QCOMPARE(tapHandler->point().position(), QPointF());
@@ -186,7 +197,7 @@ void tst_TapHandler::mouseGesturePolicyDragThreshold()
QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QVERIFY(!buttonDragThreshold->property("pressed").toBool());
- QCOMPARE(dragThresholdTappedSpy.count(), 0);
+ QCOMPARE(dragThresholdTappedSpy.size(), 0);
}
void tst_TapHandler::touchMouseGesturePolicyDragThreshold()
@@ -206,8 +217,8 @@ void tst_TapHandler::touchMouseGesturePolicyDragThreshold()
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool());
QTest::mouseMove(window, p2);
- QTRY_COMPARE(canceledSpy.count(), 1);
- QCOMPARE(tappedSpy.count(), 0);
+ QTRY_COMPARE(canceledSpy.size(), 1);
+ QCOMPARE(tappedSpy.size(), 0);
QCOMPARE(buttonDragThreshold->property("pressed").toBool(), false);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p2);
@@ -218,7 +229,7 @@ void tst_TapHandler::touchMouseGesturePolicyDragThreshold()
QTest::touchEvent(window, touchDevice).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 1);
+ QCOMPARE(tappedSpy.size(), 1);
// Press touch, drag it outside the button, release
QTest::touchEvent(window, touchDevice).press(1, p1, window);
@@ -229,16 +240,16 @@ void tst_TapHandler::touchMouseGesturePolicyDragThreshold()
QTRY_COMPARE(buttonDragThreshold->property("pressed").toBool(), false);
QTest::touchEvent(window, touchDevice).release(1, p2, window);
QQuickTouchUtils::flush(window);
- QTRY_COMPARE(canceledSpy.count(), 2);
- QCOMPARE(tappedSpy.count(), 1); // didn't increase
+ QTRY_COMPARE(canceledSpy.size(), 2);
+ QCOMPARE(tappedSpy.size(), 1); // didn't increase
QCOMPARE(buttonDragThreshold->property("pressed").toBool(), false);
// Press and release mouse, verify that it still works
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
- QTRY_COMPARE(tappedSpy.count(), 2);
- QCOMPARE(canceledSpy.count(), 2); // didn't increase
+ QTRY_COMPARE(tappedSpy.size(), 2);
+ QCOMPARE(canceledSpy.size(), 2); // didn't increase
QCOMPARE(buttonDragThreshold->property("pressed").toBool(), false);
}
@@ -264,7 +275,7 @@ void tst_TapHandler::touchGesturePolicyWithinBounds()
QTest::touchEvent(window, touchDevice).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool());
- QCOMPARE(withinBoundsTappedSpy.count(), 1);
+ QCOMPARE(withinBoundsTappedSpy.size(), 1);
// WithinBounds button is no longer pressed if touchpoint leaves bounds
withinBoundsTappedSpy.clear();
@@ -279,7 +290,7 @@ void tst_TapHandler::touchGesturePolicyWithinBounds()
QTest::touchEvent(window, touchDevice).release(1, p1, window);
QQuickTouchUtils::flush(window);
QVERIFY(!buttonWithinBounds->property("pressed").toBool());
- QCOMPARE(withinBoundsTappedSpy.count(), 0);
+ QCOMPARE(withinBoundsTappedSpy.size(), 0);
}
void tst_TapHandler::mouseGesturePolicyWithinBounds()
@@ -301,7 +312,7 @@ void tst_TapHandler::mouseGesturePolicyWithinBounds()
QVERIFY(buttonWithinBounds->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool());
- QCOMPARE(withinBoundsTappedSpy.count(), 1);
+ QCOMPARE(withinBoundsTappedSpy.size(), 1);
// WithinBounds button is no longer pressed if touchpoint leaves bounds
withinBoundsTappedSpy.clear();
@@ -313,7 +324,7 @@ void tst_TapHandler::mouseGesturePolicyWithinBounds()
QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QVERIFY(!buttonWithinBounds->property("pressed").toBool());
- QCOMPARE(withinBoundsTappedSpy.count(), 0);
+ QCOMPARE(withinBoundsTappedSpy.size(), 0);
}
void tst_TapHandler::touchGesturePolicyReleaseWithinBounds()
@@ -347,7 +358,7 @@ void tst_TapHandler::touchGesturePolicyReleaseWithinBounds()
QTest::touchEvent(window, touchDevice).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool());
- QCOMPARE(releaseWithinBoundsTappedSpy.count(), 1);
+ QCOMPARE(releaseWithinBoundsTappedSpy.size(), 1);
// ReleaseWithinBounds button does not emit tapped if released out of bounds
releaseWithinBoundsTappedSpy.clear();
@@ -362,7 +373,7 @@ void tst_TapHandler::touchGesturePolicyReleaseWithinBounds()
QTest::touchEvent(window, touchDevice).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool());
- QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0);
+ QCOMPARE(releaseWithinBoundsTappedSpy.size(), 0);
}
void tst_TapHandler::mouseGesturePolicyReleaseWithinBounds()
@@ -391,7 +402,7 @@ void tst_TapHandler::mouseGesturePolicyReleaseWithinBounds()
QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool());
- QCOMPARE(releaseWithinBoundsTappedSpy.count(), 1);
+ QCOMPARE(releaseWithinBoundsTappedSpy.size(), 1);
// ReleaseWithinBounds button does not emit tapped if released out of bounds
releaseWithinBoundsTappedSpy.clear();
@@ -403,7 +414,52 @@ void tst_TapHandler::mouseGesturePolicyReleaseWithinBounds()
QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool());
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_VERIFY(!buttonReleaseWithinBounds->property("pressed").toBool());
- QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0);
+ QCOMPARE(releaseWithinBoundsTappedSpy.size(), 0);
+}
+
+void tst_TapHandler::gesturePolicyDragWithinBounds_data()
+{
+ QTest::addColumn<const QPointingDevice *>("device");
+ QTest::addColumn<QPoint>("dragStart");
+ QTest::addColumn<QPoint>("dragDistance");
+ QTest::addColumn<QString>("expectedFeedback");
+
+ const QPointingDevice *constTouchDevice = touchDevice;
+
+ QTest::newRow("mouse: click") << QPointingDevice::primaryPointingDevice() << QPoint(200, 200) << QPoint(0, 0) << "middle";
+ QTest::newRow("touch: tap") << constTouchDevice << QPoint(200, 200) << QPoint(0, 0) << "middle";
+ QTest::newRow("mouse: drag up") << QPointingDevice::primaryPointingDevice() << QPoint(200, 200) << QPoint(0, -20) << "top";
+ QTest::newRow("touch: drag up") << constTouchDevice << QPoint(200, 200) << QPoint(0, -20) << "top";
+ QTest::newRow("mouse: drag out to cancel") << QPointingDevice::primaryPointingDevice() << QPoint(435, 200) << QPoint(10, 0) << "canceled";
+ QTest::newRow("touch: drag out to cancel") << constTouchDevice << QPoint(435, 200) << QPoint(10, 0) << "canceled";
+}
+
+void tst_TapHandler::gesturePolicyDragWithinBounds()
+{
+ QFETCH(const QPointingDevice *, device);
+ QFETCH(QPoint, dragStart);
+ QFETCH(QPoint, dragDistance);
+ QFETCH(QString, expectedFeedback);
+ const bool expectedCanceled = expectedFeedback == "canceled";
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("dragReleaseMenu.qml")));
+ QQuickTapHandler *tapHandler = window.rootObject()->findChild<QQuickTapHandler*>();
+ QVERIFY(tapHandler);
+ QSignalSpy canceledSpy(tapHandler, &QQuickTapHandler::canceled);
+
+ QQuickTest::pointerPress(device, &window, 0, dragStart);
+ QTRY_VERIFY(tapHandler->isPressed());
+ QQuickTest::pointerMove(device, &window, 0, dragStart + dragDistance);
+ if (expectedCanceled)
+ QTRY_COMPARE(tapHandler->timeHeld(), -1);
+ else
+ QTRY_VERIFY(tapHandler->timeHeld() > 0.1);
+ QQuickTest::pointerRelease(device, &window, 0, dragStart + dragDistance);
+
+ QCOMPARE(window.rootObject()->property("feedbackText"), expectedFeedback);
+ if (expectedCanceled)
+ QCOMPARE(canceledSpy.size(), 1);
}
void tst_TapHandler::touchMultiTap()
@@ -425,7 +481,7 @@ void tst_TapHandler::touchMultiTap()
QTest::touchEvent(window, touchDevice).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 1);
+ QCOMPARE(tappedSpy.size(), 1);
// Tap again in exactly the same place (not likely with touch in the real world)
QTest::touchEvent(window, touchDevice).press(1, p1, window);
@@ -434,7 +490,7 @@ void tst_TapHandler::touchMultiTap()
QTest::touchEvent(window, touchDevice).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 2);
+ QCOMPARE(tappedSpy.size(), 2);
// Tap a third time, nearby
p1 += QPoint(dragThreshold, dragThreshold);
@@ -444,7 +500,7 @@ void tst_TapHandler::touchMultiTap()
QTest::touchEvent(window, touchDevice).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 3);
+ QCOMPARE(tappedSpy.size(), 3);
// Tap a fourth time, drifting farther away
p1 += QPoint(dragThreshold, dragThreshold);
@@ -454,11 +510,52 @@ void tst_TapHandler::touchMultiTap()
QTest::touchEvent(window, touchDevice).release(1, p1, window);
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 4);
+ QCOMPARE(tappedSpy.size(), 4);
+
+ // Test a stray touch begin
+ tappedSpy.clear();
+ constexpr int count = 2;
+ for (int i = 0; i < count; ++i) {
+ QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ p1 -= QPoint(dragThreshold, dragThreshold);
+ QTest::touchEvent(window, touchDevice).move(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ QTest::touchEvent(window, touchDevice).release(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ p1 += QPoint(dragThreshold, dragThreshold);
+ QTest::touchEvent(window, touchDevice).press(1, p1, window);
+ QQuickTouchUtils::flush(window);
+ }
+ QCOMPARE(tappedSpy.count(), count);
+}
+
+void tst_TapHandler::mouseMultiTap_data()
+{
+ QTest::addColumn<QQuickTapHandler::ExclusiveSignals>("exclusiveSignals");
+ QTest::addColumn<int>("expectedSingleTaps");
+ QTest::addColumn<int>("expectedSingleTapsAfterMovingAway");
+ QTest::addColumn<int>("expectedSingleTapsAfterWaiting");
+ QTest::addColumn<int>("expectedDoubleTaps");
+
+ QTest::newRow("NotExclusive") << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::NotExclusive)
+ << 1 << 2 << 3 << 1;
+ QTest::newRow("SingleTap") << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::SingleTap)
+ << 1 << 2 << 3 << 0;
+ QTest::newRow("DoubleTap") << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::DoubleTap)
+ << 0 << 0 << 0 << 1;
+ QTest::newRow("SingleTap|DoubleTap") << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::SingleTap | QQuickTapHandler::DoubleTap)
+ << 0 << 0 << 0 << 0;
}
void tst_TapHandler::mouseMultiTap()
{
+ QFETCH(QQuickTapHandler::ExclusiveSignals, exclusiveSignals);
+ QFETCH(int, expectedSingleTaps);
+ QFETCH(int, expectedSingleTapsAfterMovingAway);
+ QFETCH(int, expectedSingleTapsAfterWaiting);
+ QFETCH(int, expectedDoubleTaps);
+
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
QScopedPointer<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
@@ -466,110 +563,409 @@ void tst_TapHandler::mouseMultiTap()
QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold");
QVERIFY(button);
+ QQuickTapHandler *tapHandler = button->findChild<QQuickTapHandler*>();
+ QVERIFY(tapHandler);
+ tapHandler->setExclusiveSignals(exclusiveSignals);
QSignalSpy tappedSpy(button, SIGNAL(tapped()));
+ QSignalSpy singleTapSpy(tapHandler, &QQuickTapHandler::singleTapped);
+ QSignalSpy doubleTapSpy(tapHandler, &QQuickTapHandler::doubleTapped);
- // Tap once
+ // Click once
QPoint p1 = button->mapToScene(QPointF(2, 2)).toPoint();
- QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
- QTRY_VERIFY(button->property("pressed").toBool());
- QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
- QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 1);
-
- // Tap again in exactly the same place (not likely with touch in the real world)
- QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1, 10);
QTRY_VERIFY(button->property("pressed").toBool());
- QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1, 10);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 2);
-
- // Tap a third time, nearby
+ QCOMPARE(tappedSpy.size(), 1);
+ // If exclusiveSignals == SingleTap | DoubleTap:
+ // This would be a single-click if we waited longer than the double-click interval,
+ // but it's too early for the signal at this moment; and we're going to click again.
+ // If exclusiveSignals == DoubleTap: singleTapped() won't happen.
+ // Otherwise: we got singleTapped() immediately.
+ QCOMPARE(singleTapSpy.size(), expectedSingleTaps);
+ QCOMPARE(tapHandler->timeHeld(), -1);
+
+ // Click again in exactly the same place
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, p1, 10);
+ QCOMPARE(tappedSpy.size(), 2);
+ QCOMPARE(singleTapSpy.size(), expectedSingleTaps);
+ QCOMPARE(doubleTapSpy.size(), expectedDoubleTaps);
+
+ // Click a third time, nearby: that'll be a triple-click
+ p1 += QPoint(1, 1);
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, p1, 10);
+ QCOMPARE(tappedSpy.size(), 3);
+ QCOMPARE(singleTapSpy.size(), expectedSingleTaps);
+ QCOMPARE(doubleTapSpy.size(), expectedDoubleTaps);
+ QCOMPARE(tapHandler->tapCount(), 3);
+
+ // Click a fourth time, drifting farther away: treated as a separate click, regardless of timing
p1 += QPoint(dragThreshold, dragThreshold);
- QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
- QTRY_VERIFY(button->property("pressed").toBool());
- QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
- QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 3);
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, p1); // default delay to prevent double-click
+ QCOMPARE(tappedSpy.size(), 4);
+ QCOMPARE(tapHandler->tapCount(), 1);
+ QTRY_COMPARE(singleTapSpy.size(), expectedSingleTapsAfterMovingAway);
+
+ // Click a fifth time later on at the same place: treated as a separate click
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, p1);
+ QCOMPARE(tappedSpy.size(), 5);
+ QCOMPARE(tapHandler->tapCount(), 1);
+ QCOMPARE(singleTapSpy.size(), expectedSingleTapsAfterWaiting);
+}
- // Tap a fourth time, drifting farther away
- p1 += QPoint(dragThreshold, dragThreshold);
- QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
- QTRY_VERIFY(button->property("pressed").toBool());
- QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
- QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 4);
+void tst_TapHandler::mouseMultiTapLeftRight_data()
+{
+ QTest::addColumn<QQuickTapHandler::ExclusiveSignals>("exclusiveSignals");
+ QTest::addColumn<int>("expectedSingleTaps");
+ QTest::addColumn<int>("expectedDoubleTaps");
+ QTest::addColumn<int>("expectedTabCount2");
+ QTest::addColumn<int>("expectedTabCount3");
+
+ QTest::newRow("NotExclusive") << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::NotExclusive)
+ << 3 << 0 << 1 << 1;
+ QTest::newRow("SingleTap") << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::SingleTap)
+ << 3 << 0 << 1 << 1;
+ QTest::newRow("DoubleTap") << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::DoubleTap)
+ << 0 << 0 << 1 << 1;
+ QTest::newRow("SingleTap|DoubleTap") << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::SingleTap | QQuickTapHandler::DoubleTap)
+ << 0 << 0 << 1 << 1;
}
-void tst_TapHandler::touchLongPress()
+void tst_TapHandler::mouseMultiTapLeftRight() //QTBUG-111557
{
+ QFETCH(QQuickTapHandler::ExclusiveSignals, exclusiveSignals);
+ QFETCH(int, expectedSingleTaps);
+ QFETCH(int, expectedDoubleTaps);
+ QFETCH(int, expectedTabCount2);
+ QFETCH(int, expectedTabCount3);
+
QScopedPointer<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold");
QVERIFY(button);
- QQuickTapHandler *tapHandler = button->findChild<QQuickTapHandler*>("DragThreshold");
+ QQuickTapHandler *tapHandler = button->findChild<QQuickTapHandler*>();
QVERIFY(tapHandler);
+ tapHandler->setExclusiveSignals(exclusiveSignals);
+ tapHandler->setAcceptedButtons(Qt::LeftButton | Qt::RightButton);
QSignalSpy tappedSpy(button, SIGNAL(tapped()));
- QSignalSpy longPressThresholdChangedSpy(tapHandler, SIGNAL(longPressThresholdChanged()));
- QSignalSpy timeHeldSpy(tapHandler, SIGNAL(timeHeldChanged()));
- QSignalSpy longPressedSpy(tapHandler, SIGNAL(longPressed()));
+ QSignalSpy singleTapSpy(tapHandler, &QQuickTapHandler::singleTapped);
+ QSignalSpy doubleTapSpy(tapHandler, &QQuickTapHandler::doubleTapped);
- // Reduce the threshold so that we can get a long press quickly
- tapHandler->setLongPressThreshold(0.5);
- QCOMPARE(longPressThresholdChangedSpy.count(), 1);
+ // Click once with the left button
+ QPoint p1 = button->mapToScene(QPointF(2, 2)).toPoint();
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1, 10);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1, 10);
- // Press and hold
- QPoint p1 = button->mapToScene(button->clipRect().center()).toPoint();
- QTest::touchEvent(window, touchDevice).press(1, p1, window);
- QQuickTouchUtils::flush(window);
- QTRY_VERIFY(button->property("pressed").toBool());
- QTRY_COMPARE(longPressedSpy.count(), 1);
- timeHeldSpy.wait(); // the longer we hold it, the more this will occur
- qDebug() << "held" << tapHandler->timeHeld() << "secs; timeHeld updated" << timeHeldSpy.count() << "times";
- QVERIFY(timeHeldSpy.count() > 0);
- QVERIFY(tapHandler->timeHeld() > 0.4); // Should be > 0.5 but slow CI and timer granularity can interfere
+ // Click again with the right button -> should reset tabCount()
+ QTest::mousePress(window, Qt::RightButton, Qt::NoModifier, p1, 10);
+ QTest::mouseRelease(window, Qt::RightButton, Qt::NoModifier, p1, 10);
- // Release and verify that tapped was not emitted
- QTest::touchEvent(window, touchDevice).release(1, p1, window);
- QQuickTouchUtils::flush(window);
- QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 0);
+ QCOMPARE(tapHandler->tapCount(), expectedTabCount2);
+
+ // Click again with the left button -> should reset tabCount()
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1, 10);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1, 10);
+
+ QCOMPARE(tapHandler->tapCount(), expectedTabCount3);
+ QCOMPARE(singleTapSpy.size(), expectedSingleTaps);
+ QCOMPARE(doubleTapSpy.size(), expectedDoubleTaps);
+}
+
+void tst_TapHandler::singleTapDoubleTap_data()
+{
+ QTest::addColumn<QPointingDevice::DeviceType>("deviceType");
+ QTest::addColumn<QQuickTapHandler::ExclusiveSignals>("exclusiveSignals");
+ QTest::addColumn<int>("expectedEndingSingleTapCount");
+ QTest::addColumn<int>("expectedDoubleTapCount");
+
+ QTest::newRow("mouse:NotExclusive")
+ << QPointingDevice::DeviceType::Mouse
+ << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::NotExclusive)
+ << 1 << 1;
+ QTest::newRow("mouse:SingleTap")
+ << QPointingDevice::DeviceType::Mouse
+ << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::SingleTap)
+ << 1 << 0;
+ QTest::newRow("mouse:DoubleTap")
+ << QPointingDevice::DeviceType::Mouse
+ << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::DoubleTap)
+ << 0 << 1;
+ QTest::newRow("mouse:SingleTap|DoubleTap")
+ << QPointingDevice::DeviceType::Mouse
+ << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::SingleTap | QQuickTapHandler::DoubleTap)
+ << 0 << 1;
+ QTest::newRow("touch:NotExclusive")
+ << QPointingDevice::DeviceType::TouchScreen
+ << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::NotExclusive)
+ << 1 << 1;
+ QTest::newRow("touch:SingleTap")
+ << QPointingDevice::DeviceType::TouchScreen
+ << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::SingleTap)
+ << 1 << 0;
+ QTest::newRow("touch:DoubleTap")
+ << QPointingDevice::DeviceType::TouchScreen
+ << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::DoubleTap)
+ << 0 << 1;
+ QTest::newRow("touch:SingleTap|DoubleTap")
+ << QPointingDevice::DeviceType::TouchScreen
+ << QQuickTapHandler::ExclusiveSignals(QQuickTapHandler::SingleTap | QQuickTapHandler::DoubleTap)
+ << 0 << 1;
}
-void tst_TapHandler::mouseLongPress()
+void tst_TapHandler::singleTapDoubleTap()
{
+ QFETCH(QPointingDevice::DeviceType, deviceType);
+ QFETCH(QQuickTapHandler::ExclusiveSignals, exclusiveSignals);
+ QFETCH(int, expectedEndingSingleTapCount);
+ QFETCH(int, expectedDoubleTapCount);
+
QScopedPointer<QQuickView> windowPtr;
createView(windowPtr, "buttons.qml");
QQuickView * window = windowPtr.data();
QQuickItem *button = window->rootObject()->findChild<QQuickItem*>("DragThreshold");
QVERIFY(button);
- QQuickTapHandler *tapHandler = button->findChild<QQuickTapHandler*>("DragThreshold");
+ QQuickTapHandler *tapHandler = button->findChild<QQuickTapHandler*>();
+ QVERIFY(tapHandler);
+ tapHandler->setExclusiveSignals(exclusiveSignals);
+ QSignalSpy tappedSpy(tapHandler, &QQuickTapHandler::tapped);
+ QSignalSpy singleTapSpy(tapHandler, &QQuickTapHandler::singleTapped);
+ QSignalSpy doubleTapSpy(tapHandler, &QQuickTapHandler::doubleTapped);
+
+ auto tap = [window, tapHandler, deviceType, this](const QPoint &p1, int delay = 10) {
+ switch (static_cast<QPointingDevice::DeviceType>(deviceType)) {
+ case QPointingDevice::DeviceType::Mouse:
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, p1, delay);
+ break;
+ case QPointingDevice::DeviceType::TouchScreen:
+ QTest::qWait(delay);
+ QTest::touchEvent(window, touchDevice).press(0, p1, window);
+ QTRY_VERIFY(tapHandler->isPressed());
+ QTest::touchEvent(window, touchDevice).release(0, p1, window);
+ break;
+ default:
+ break;
+ }
+ };
+
+ // tap once
+ const QPoint p1 = button->mapToScene(QPointF(2, 2)).toPoint();
+ tap(p1);
+ QCOMPARE(tappedSpy.size(), 1);
+ QCOMPARE(doubleTapSpy.size(), 0);
+
+ // tap again immediately afterwards
+ tap(p1);
+ QTRY_COMPARE(doubleTapSpy.size(), expectedDoubleTapCount);
+ QCOMPARE(tappedSpy.size(), 2);
+ QCOMPARE(singleTapSpy.size(), expectedEndingSingleTapCount);
+
+ // wait past the double-tap interval, then do it again
+ const auto delay = qApp->styleHints()->mouseDoubleClickInterval() + 10;
+ tappedSpy.clear();
+ singleTapSpy.clear();
+ doubleTapSpy.clear();
+
+ // tap once with delay
+ tap(p1, delay);
+ QCOMPARE(tappedSpy.size(), 1);
+ QCOMPARE(doubleTapSpy.size(), 0);
+
+ // tap again immediately afterwards
+ tap(p1);
+ QTRY_COMPARE(doubleTapSpy.size(), expectedDoubleTapCount);
+ QCOMPARE(tappedSpy.size(), 2);
+ QCOMPARE(singleTapSpy.size(), expectedEndingSingleTapCount);
+}
+
+void tst_TapHandler::longPress_data()
+{
+ QTest::addColumn<const QPointingDevice *>("device");
+ QTest::addColumn<QString>("buttonName");
+ QTest::addColumn<qreal>("longPressThreshold");
+ QTest::addColumn<QPoint>("releaseOffset");
+ QTest::addColumn<bool>("expectLongPress");
+ QTest::addColumn<bool>("expectTapped");
+
+ const QPointingDevice *constTouchDevice = touchDevice;
+
+ // Reduce the threshold so that we can get a long press quickly (faster in CI)
+ const qreal longPressThreshold = 0.3;
+ QTest::newRow("mouse, lpt longPressThreshold: DragThreshold")
+ << QPointingDevice::primaryPointingDevice() << "DragThreshold"
+ << longPressThreshold << QPoint(0, 0) << true << false;
+ QTest::newRow("touch, lpt longPressThreshold: DragThreshold")
+ << constTouchDevice << "DragThreshold" << longPressThreshold
+ << QPoint(0, 0) << true << false;
+ QTest::newRow("mouse, lpt longPressThreshold: DragThreshold, drag")
+ << QPointingDevice::primaryPointingDevice() << "DragThreshold"
+ << longPressThreshold << QPoint(50, 0) << false << false;
+ QTest::newRow("touch, lpt longPressThreshold: DragThreshold, drag")
+ << constTouchDevice << "DragThreshold"
+ << longPressThreshold << QPoint(50, 0) << false << false;
+
+ QTest::newRow("mouse, lpt longPressThreshold: WithinBounds")
+ << QPointingDevice::primaryPointingDevice() << "WithinBounds"
+ << longPressThreshold << QPoint(0, 0) << true << false;
+ QTest::newRow("touch, lpt longPressThreshold: WithinBounds")
+ << constTouchDevice << "WithinBounds"
+ << longPressThreshold << QPoint(0, 0) << true << false;
+ QTest::newRow("mouse, lpt longPressThreshold: WithinBounds, drag")
+ << QPointingDevice::primaryPointingDevice() << "WithinBounds"
+ << longPressThreshold << QPoint(50, 0) << true << false;
+ QTest::newRow("touch, lpt longPressThreshold: WithinBounds, drag")
+ << constTouchDevice << "WithinBounds"
+ << longPressThreshold << QPoint(50, 0) << true << false;
+ QTest::newRow("mouse, lpt longPressThreshold: WithinBounds, drag out")
+ << QPointingDevice::primaryPointingDevice() << "WithinBounds"
+ << longPressThreshold << QPoint(155, 0) << false << false;
+ QTest::newRow("touch, lpt longPressThreshold: WithinBounds, drag out")
+ << constTouchDevice << "WithinBounds"
+ << longPressThreshold << QPoint(155, 0) << false << false;
+
+ QTest::newRow("mouse, lpt longPressThreshold: ReleaseWithinBounds")
+ << QPointingDevice::primaryPointingDevice() << "ReleaseWithinBounds"
+ << longPressThreshold << QPoint(0, 0) << true << false;
+ QTest::newRow("touch, lpt longPressThreshold: ReleaseWithinBounds")
+ << constTouchDevice << "ReleaseWithinBounds"
+ << longPressThreshold << QPoint(0, 0) << true << false;
+ QTest::newRow("mouse, lpt longPressThreshold: ReleaseWithinBounds, drag")
+ << QPointingDevice::primaryPointingDevice() << "ReleaseWithinBounds"
+ << longPressThreshold << QPoint(50, 0) << true << false;
+ QTest::newRow("touch, lpt longPressThreshold: ReleaseWithinBounds, drag")
+ << constTouchDevice << "ReleaseWithinBounds"
+ << longPressThreshold << QPoint(50, 0) << true << false;
+ QTest::newRow("mouse, lpt longPressThreshold: ReleaseWithinBounds, drag out")
+ << QPointingDevice::primaryPointingDevice() << "ReleaseWithinBounds"
+ << longPressThreshold << QPoint(155, 0) << false << false;
+ QTest::newRow("touch, lpt longPressThreshold: ReleaseWithinBounds, drag out")
+ << constTouchDevice << "ReleaseWithinBounds"
+ << longPressThreshold << QPoint(155, 0) << false << false;
+
+ QTest::newRow("mouse, lpt longPressThreshold: DragWithinBounds")
+ << QPointingDevice::primaryPointingDevice() << "DragWithinBounds"
+ << longPressThreshold << QPoint(0, 0) << true << false;
+ QTest::newRow("touch, lpt longPressThreshold: DragWithinBounds")
+ << constTouchDevice << "DragWithinBounds"
+ << longPressThreshold << QPoint(0, 0) << true << false;
+ QTest::newRow("mouse, lpt longPressThreshold: DragWithinBounds, drag")
+ << QPointingDevice::primaryPointingDevice() << "DragWithinBounds"
+ << longPressThreshold << QPoint(50, 0) << true << false;
+ QTest::newRow("touch, lpt longPressThreshold: DragWithinBounds, drag")
+ << constTouchDevice << "DragWithinBounds"
+ << longPressThreshold << QPoint(50, 0) << true << false;
+ QTest::newRow("mouse, lpt longPressThreshold: DragWithinBounds, drag out")
+ << QPointingDevice::primaryPointingDevice() << "DragWithinBounds"
+ << longPressThreshold << QPoint(155, 0) << false << false;
+ QTest::newRow("touch, lpt longPressThreshold: DragWithinBounds, drag out")
+ << constTouchDevice << "DragWithinBounds"
+ << longPressThreshold << QPoint(155, 0) << false << false;
+
+ // Zero or negative threshold means long press is disabled
+ QTest::newRow("mouse, lpt 0: DragThreshold")
+ << QPointingDevice::primaryPointingDevice() << "DragThreshold"
+ << qreal(0) << QPoint(0, 0) << false << true;
+ QTest::newRow("mouse, lpt -1: DragThreshold")
+ << QPointingDevice::primaryPointingDevice() << "DragThreshold"
+ << qreal(-1) << QPoint(0, 0) << true << false;
+ QTest::newRow("touch, lpt 0: DragThreshold")
+ << constTouchDevice << "DragThreshold"
+ << qreal(0) << QPoint(0, 0) << false << true;
+
+ QTest::newRow("mouse, lpt 0: WithinBounds")
+ << QPointingDevice::primaryPointingDevice() << "WithinBounds"
+ << qreal(0) << QPoint(0, 0) << false << true;
+ QTest::newRow("mouse, lpt -1: WithinBounds")
+ << QPointingDevice::primaryPointingDevice() << "WithinBounds"
+ << qreal(-1) << QPoint(0, 0) << true << false;
+ QTest::newRow("touch, lpt 0: WithinBounds")
+ << constTouchDevice << "WithinBounds"
+ << qreal(0) << QPoint(0, 0) << false << true;
+
+ QTest::newRow("mouse, lpt 0: ReleaseWithinBounds")
+ << QPointingDevice::primaryPointingDevice() << "ReleaseWithinBounds"
+ << qreal(0) << QPoint(0, 0) << false << true;
+ QTest::newRow("mouse, lpt -1: ReleaseWithinBounds")
+ << QPointingDevice::primaryPointingDevice() << "ReleaseWithinBounds"
+ << qreal(-1) << QPoint(0, 0) << true << false;
+ QTest::newRow("touch, lpt 0: ReleaseWithinBounds")
+ << constTouchDevice << "ReleaseWithinBounds"
+ << qreal(0) << QPoint(0, 0) << false << true;
+
+ QTest::newRow("mouse, lpt 0: DragWithinBounds")
+ << QPointingDevice::primaryPointingDevice() << "DragWithinBounds"
+ << qreal(0) << QPoint(0, 0) << false << true;
+ QTest::newRow("mouse, lpt -1: DragWithinBounds")
+ << QPointingDevice::primaryPointingDevice() << "DragWithinBounds"
+ << qreal(-1) << QPoint(0, 0) << true << false;
+ QTest::newRow("touch, lpt 0: DragWithinBounds")
+ << constTouchDevice << "DragWithinBounds"
+ << qreal(0) << QPoint(0, 0) << false << true;
+}
+
+void tst_TapHandler::longPress()
+{
+ QFETCH(const QPointingDevice *, device);
+ QFETCH(QString, buttonName);
+ QFETCH(qreal, longPressThreshold);
+ QFETCH(QPoint, releaseOffset);
+ QFETCH(bool, expectLongPress);
+ QFETCH(bool, expectTapped);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("buttons.qml")));
+
+ QQuickItem *button = window.rootObject()->findChild<QQuickItem*>(buttonName);
+ QVERIFY(button);
+ QQuickTapHandler *tapHandler = button->findChild<QQuickTapHandler*>(buttonName);
QVERIFY(tapHandler);
QSignalSpy tappedSpy(button, SIGNAL(tapped()));
QSignalSpy longPressThresholdChangedSpy(tapHandler, SIGNAL(longPressThresholdChanged()));
QSignalSpy timeHeldSpy(tapHandler, SIGNAL(timeHeldChanged()));
QSignalSpy longPressedSpy(tapHandler, SIGNAL(longPressed()));
- // Reduce the threshold so that we can get a long press quickly
- tapHandler->setLongPressThreshold(0.5);
- QCOMPARE(longPressThresholdChangedSpy.count(), 1);
+ const qreal defaultThreshold = tapHandler->longPressThreshold();
+ qsizetype changedCount = 0;
+ QCOMPARE_GT(defaultThreshold, 0);
+ tapHandler->setLongPressThreshold(longPressThreshold);
+ if (longPressThreshold > 0)
+ QCOMPARE(longPressThresholdChangedSpy.size(), ++changedCount);
+ QVERIFY(QMetaObject::invokeMethod(button, "assignUndefinedLongPressThreshold"));
+ if (longPressThreshold > 0)
+ QCOMPARE(longPressThresholdChangedSpy.size(), ++changedCount);
+ QCOMPARE(tapHandler->longPressThreshold(), defaultThreshold);
+ tapHandler->setLongPressThreshold(longPressThreshold);
// Press and hold
QPoint p1 = button->mapToScene(button->clipRect().center()).toPoint();
- QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
+ QQuickTest::pointerPress(device, &window, 1, p1);
QTRY_VERIFY(button->property("pressed").toBool());
- QTRY_COMPARE(longPressedSpy.count(), 1);
+ QTRY_COMPARE(longPressedSpy.size(), expectLongPress ? 1 : 0);
timeHeldSpy.wait(); // the longer we hold it, the more this will occur
- qDebug() << "held" << tapHandler->timeHeld() << "secs; timeHeld updated" << timeHeldSpy.count() << "times";
- QVERIFY(timeHeldSpy.count() > 0);
- QVERIFY(tapHandler->timeHeld() > 0.4); // Should be > 0.5 but slow CI and timer granularity can interfere
+ qDebug() << "held" << tapHandler->timeHeld() << "secs; timeHeld updated" << timeHeldSpy.size() << "times";
+ QCOMPARE_GT(timeHeldSpy.size(), 0);
+ if (expectLongPress) {
+ // Should be > longPressThreshold but slow CI and timer granularity can interfere
+ QCOMPARE_GT(tapHandler->timeHeld(), longPressThreshold - 0.1);
+ } else {
+ // Should be quite small, but event delivery is not instantaneous
+ QCOMPARE_LT(tapHandler->timeHeld(), 0.3);
+ }
+
+ // If we have an offset, we need a move between press and release for realistic simulation
+ if (!releaseOffset.isNull())
+ QQuickTest::pointerMove(device, &window, 1, p1 + releaseOffset);
- // Release and verify that tapped was not emitted
- QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1, 500);
+ // Release (optionally at an offset) and check whether tapped was emitted
+ QQuickTest::pointerRelease(device, &window, 1, p1 + releaseOffset);
QTRY_VERIFY(!button->property("pressed").toBool());
- QCOMPARE(tappedSpy.count(), 0);
+ if (expectLongPress)
+ QCOMPARE_GT(button->property("timeHeldWhenLongPressed").toReal(), longPressThreshold - 0.1);
+ QCOMPARE(tapHandler->timeHeld(), -1);
+ QCOMPARE(tappedSpy.size(), expectTapped ? 1 : 0);
+ QCOMPARE(longPressedSpy.size(), expectLongPress ? 1 : 0);
}
void tst_TapHandler::buttonsMultiTouch()
@@ -631,11 +1027,11 @@ void tst_TapHandler::buttonsMultiTouch()
touchSeq.stationary(2).stationary(3).release(1, p1, window).commit();
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!buttonDragThreshold->property("pressed").toBool());
- QCOMPARE(dragThresholdTappedSpy.count(), 1);
+ QCOMPARE(dragThresholdTappedSpy.size(), 1);
QVERIFY(buttonWithinBounds->property("pressed").toBool());
- QCOMPARE(withinBoundsTappedSpy.count(), 0);
+ QCOMPARE(withinBoundsTappedSpy.size(), 0);
QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool());
- QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0);
+ QCOMPARE(releaseWithinBoundsTappedSpy.size(), 0);
touchSeq.stationary(2).stationary(3).press(1, p1, window).commit();
QQuickTouchUtils::flush(window);
QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool());
@@ -646,11 +1042,11 @@ void tst_TapHandler::buttonsMultiTouch()
touchSeq.stationary(1).stationary(3).release(2, p2, window).commit();
QQuickTouchUtils::flush(window);
QTRY_VERIFY(!buttonWithinBounds->property("pressed").toBool());
- QCOMPARE(withinBoundsTappedSpy.count(), 1);
+ QCOMPARE(withinBoundsTappedSpy.size(), 1);
QVERIFY(buttonDragThreshold->property("pressed").toBool());
- QCOMPARE(dragThresholdTappedSpy.count(), 1);
+ QCOMPARE(dragThresholdTappedSpy.size(), 1);
QVERIFY(buttonReleaseWithinBounds->property("pressed").toBool());
- QCOMPARE(releaseWithinBoundsTappedSpy.count(), 0);
+ QCOMPARE(releaseWithinBoundsTappedSpy.size(), 0);
touchSeq.stationary(1).stationary(3).press(2, p2, window).commit();
QQuickTouchUtils::flush(window);
QVERIFY(buttonDragThreshold->property("pressed").toBool());
@@ -660,11 +1056,11 @@ void tst_TapHandler::buttonsMultiTouch()
// can release bottom button and press again: others stay pressed the whole time
touchSeq.stationary(1).stationary(2).release(3, p3, window).commit();
QQuickTouchUtils::flush(window);
- QCOMPARE(releaseWithinBoundsTappedSpy.count(), 1);
+ QCOMPARE(releaseWithinBoundsTappedSpy.size(), 1);
QVERIFY(buttonWithinBounds->property("pressed").toBool());
- QCOMPARE(withinBoundsTappedSpy.count(), 1);
+ QCOMPARE(withinBoundsTappedSpy.size(), 1);
QVERIFY(!buttonReleaseWithinBounds->property("pressed").toBool());
- QCOMPARE(dragThresholdTappedSpy.count(), 1);
+ QCOMPARE(dragThresholdTappedSpy.size(), 1);
touchSeq.stationary(1).stationary(2).press(3, p3, window).commit();
QQuickTouchUtils::flush(window);
QTRY_VERIFY(buttonDragThreshold->property("pressed").toBool());
@@ -685,26 +1081,26 @@ void tst_TapHandler::componentUserBehavioralOverride()
QQuickTapHandler *userTapHandler = button->findChild<QQuickTapHandler*>("override");
QVERIFY(userTapHandler);
QSignalSpy tappedSpy(button, SIGNAL(tapped()));
- QSignalSpy innerGrabChangedSpy(innerTapHandler, SIGNAL(grabChanged(QPointingDevice::GrabTransition, QEventPoint)));
- QSignalSpy userGrabChangedSpy(userTapHandler, SIGNAL(grabChanged(QPointingDevice::GrabTransition, QEventPoint)));
+ QSignalSpy innerGrabChangedSpy(innerTapHandler, SIGNAL(grabChanged(QPointingDevice::GrabTransition,QEventPoint)));
+ QSignalSpy userGrabChangedSpy(userTapHandler, SIGNAL(grabChanged(QPointingDevice::GrabTransition,QEventPoint)));
QSignalSpy innerPressedChangedSpy(innerTapHandler, SIGNAL(pressedChanged()));
QSignalSpy userPressedChangedSpy(userTapHandler, SIGNAL(pressedChanged()));
// Press
QPoint p1 = button->mapToScene(button->clipRect().center()).toPoint();
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, p1);
- QTRY_COMPARE(userPressedChangedSpy.count(), 1);
- QCOMPARE(innerPressedChangedSpy.count(), 0);
- QCOMPARE(innerGrabChangedSpy.count(), 0);
- QCOMPARE(userGrabChangedSpy.count(), 1);
+ QTRY_COMPARE(userPressedChangedSpy.size(), 1);
+ QCOMPARE(innerPressedChangedSpy.size(), 0);
+ QCOMPARE(innerGrabChangedSpy.size(), 0);
+ QCOMPARE(userGrabChangedSpy.size(), 1);
// Release
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, p1);
- QTRY_COMPARE(userPressedChangedSpy.count(), 2);
- QCOMPARE(innerPressedChangedSpy.count(), 0);
- QCOMPARE(tappedSpy.count(), 1); // only because the override handler makes that happen
- QCOMPARE(innerGrabChangedSpy.count(), 0);
- QCOMPARE(userGrabChangedSpy.count(), 2);
+ QTRY_COMPARE(userPressedChangedSpy.size(), 2);
+ QCOMPARE(innerPressedChangedSpy.size(), 0);
+ QCOMPARE(tappedSpy.size(), 1); // only because the override handler makes that happen
+ QCOMPARE(innerGrabChangedSpy.size(), 0);
+ QCOMPARE(userGrabChangedSpy.size(), 2);
}
void tst_TapHandler::rightLongPressIgnoreWheel()
@@ -715,8 +1111,8 @@ void tst_TapHandler::rightLongPressIgnoreWheel()
QQuickTapHandler *tap = window->rootObject()->findChild<QQuickTapHandler*>();
QVERIFY(tap);
- QSignalSpy tappedSpy(tap, SIGNAL(tapped(QEventPoint *)));
- QSignalSpy longPressedSpy(tap, SIGNAL(longPressed()));
+ QSignalSpy tappedSpy(tap, &QQuickTapHandler::tapped);
+ QSignalSpy longPressedSpy(tap, &QQuickTapHandler::longPressed);
QPoint p1(100, 100);
// Mouse wheel with ScrollBegin phase (because as soon as two fingers are touching
@@ -735,20 +1131,20 @@ void tst_TapHandler::rightLongPressIgnoreWheel()
QWheelEvent wheelEvent(p1, p1, QPoint(0, 0), QPoint(0, 0),
Qt::NoButton, Qt::NoModifier, Qt::ScrollEnd, false, Qt::MouseEventNotSynthesized);
QGuiApplication::sendEvent(window, &wheelEvent);
- QTRY_COMPARE(longPressedSpy.count(), 1);
+ QTRY_COMPARE(longPressedSpy.size(), 1);
QCOMPARE(tap->isPressed(), true);
- QCOMPARE(tappedSpy.count(), 0);
+ QCOMPARE(tappedSpy.size(), 0);
// Release
QTest::mouseRelease(window, Qt::RightButton, Qt::NoModifier, p1, 500);
QTRY_COMPARE(tap->isPressed(), false);
- QCOMPARE(tappedSpy.count(), 0);
+ QCOMPARE(tappedSpy.size(), 0);
}
void tst_TapHandler::negativeZStackingOrder() // QTBUG-83114
{
QScopedPointer<QQuickView> windowPtr;
- createView(windowPtr, "tapHandlersOverlapped.qml");
+ createView(windowPtr, "nested.qml");
QQuickView *window = windowPtr.data();
QQuickItem *root = window->rootObject();
@@ -760,8 +1156,8 @@ void tst_TapHandler::negativeZStackingOrder() // QTBUG-83114
QSignalSpy clickSpyChild(childTapHandler, &QQuickTapHandler::tapped);
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(150, 100));
- QCOMPARE(clickSpyChild.count(), 1);
- QCOMPARE(clickSpyParent.count(), 1);
+ QCOMPARE(clickSpyChild.size(), 1);
+ QCOMPARE(clickSpyParent.size(), 1);
auto order = root->property("taps").toList();
QVERIFY(order.at(0) == "childTapHandler");
QVERIFY(order.at(1) == "parentTapHandler");
@@ -770,13 +1166,129 @@ void tst_TapHandler::negativeZStackingOrder() // QTBUG-83114
childTapHandler->parentItem()->setZ(-1);
root->setProperty("taps", QVariantList());
QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(150, 100));
- QCOMPARE(clickSpyChild.count(), 2);
- QCOMPARE(clickSpyParent.count(), 2);
+ QCOMPARE(clickSpyChild.size(), 2);
+ QCOMPARE(clickSpyParent.size(), 2);
order = root->property("taps").toList();
QVERIFY(order.at(0) == "parentTapHandler");
QVERIFY(order.at(1) == "childTapHandler");
}
+void tst_TapHandler::nonTopLevelParentWindow() // QTBUG-91716
+{
+ QScopedPointer<QQuickWindow> parentWindowPtr(new QQuickWindow);
+ auto parentWindow = parentWindowPtr.get();
+ parentWindow->setGeometry(400, 400, 250, 250);
+
+ QScopedPointer<QQuickView> windowPtr;
+ createView(windowPtr, "simpleTapHandler.qml", parentWindow);
+ auto window = windowPtr.get();
+ window->setGeometry(10, 10, 100, 100);
+
+ QQuickItem *root = window->rootObject();
+
+ auto p1 = QPoint(20, 20);
+ mouseEvent(QEvent::MouseButtonPress, Qt::LeftButton, p1, window, parentWindow);
+ mouseEvent(QEvent::MouseButtonRelease, Qt::LeftButton, p1, window, parentWindow);
+
+ QCOMPARE(root->property("tapCount").toInt(), 1);
+
+ QTest::touchEvent(window, touchDevice).press(0, p1, parentWindow).commit();
+ QTest::touchEvent(window, touchDevice).release(0, p1, parentWindow).commit();
+
+ QCOMPARE(root->property("tapCount").toInt(), 2);
+}
+
+void tst_TapHandler::nestedDoubleTap_data()
+{
+ QTest::addColumn<QQuickTapHandler::GesturePolicy>("childGesturePolicy");
+
+ QTest::newRow("DragThreshold") << QQuickTapHandler::GesturePolicy::DragThreshold;
+ QTest::newRow("WithinBounds") << QQuickTapHandler::GesturePolicy::WithinBounds;
+ QTest::newRow("ReleaseWithinBounds") << QQuickTapHandler::GesturePolicy::ReleaseWithinBounds;
+ QTest::newRow("DragWithinBounds") << QQuickTapHandler::GesturePolicy::DragWithinBounds;
+}
+
+void tst_TapHandler::nestedDoubleTap() // QTBUG-102625
+{
+ QFETCH(QQuickTapHandler::GesturePolicy, childGesturePolicy);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("nested.qml")));
+ QQuickItem *root = window.rootObject();
+ QQuickTapHandler *parentTapHandler = root->findChild<QQuickTapHandler*>("parentTapHandler");
+ QVERIFY(parentTapHandler);
+ QSignalSpy parentSpy(parentTapHandler, &QQuickTapHandler::doubleTapped);
+ QQuickTapHandler *childTapHandler = root->findChild<QQuickTapHandler*>("childTapHandler");
+ QVERIFY(childTapHandler);
+ QSignalSpy childSpy(childTapHandler, &QQuickTapHandler::doubleTapped);
+ childTapHandler->setGesturePolicy(childGesturePolicy);
+
+ QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, QPoint(150, 100));
+
+ QCOMPARE(childSpy.size(), 1);
+ // If the child gets by with a passive grab, both handlers see tap and double-tap.
+ // If the child takes an exclusive grab and stops event propagation, the parent doesn't see them.
+ QCOMPARE(parentSpy.size(),
+ childGesturePolicy == QQuickTapHandler::GesturePolicy::DragThreshold ? 1 : 0);
+ QCOMPARE(root->property("taps").toList().size(),
+ childGesturePolicy == QQuickTapHandler::GesturePolicy::DragThreshold ? 4 : 2);
+}
+
+void tst_TapHandler::nestedAndSiblingPropagation_data()
+{
+ QTest::addColumn<const QPointingDevice *>("device");
+ QTest::addColumn<QQuickTapHandler::GesturePolicy>("gesturePolicy");
+ QTest::addColumn<bool>("expectPropagation");
+
+ const QPointingDevice *constTouchDevice = touchDevice;
+
+ QTest::newRow("primary, DragThreshold") << QPointingDevice::primaryPointingDevice()
+ << QQuickTapHandler::GesturePolicy::DragThreshold << true;
+ QTest::newRow("primary, WithinBounds") << QPointingDevice::primaryPointingDevice()
+ << QQuickTapHandler::GesturePolicy::WithinBounds << false;
+ QTest::newRow("primary, ReleaseWithinBounds") << QPointingDevice::primaryPointingDevice()
+ << QQuickTapHandler::GesturePolicy::ReleaseWithinBounds << false;
+ QTest::newRow("primary, DragWithinBounds") << QPointingDevice::primaryPointingDevice()
+ << QQuickTapHandler::GesturePolicy::DragWithinBounds << false;
+
+ QTest::newRow("touch, DragThreshold") << constTouchDevice
+ << QQuickTapHandler::GesturePolicy::DragThreshold << true;
+ QTest::newRow("touch, WithinBounds") << constTouchDevice
+ << QQuickTapHandler::GesturePolicy::WithinBounds << false;
+ QTest::newRow("touch, ReleaseWithinBounds") << constTouchDevice
+ << QQuickTapHandler::GesturePolicy::ReleaseWithinBounds << false;
+ QTest::newRow("touch, DragWithinBounds") << constTouchDevice
+ << QQuickTapHandler::GesturePolicy::DragWithinBounds << false;
+}
+
+void tst_TapHandler::nestedAndSiblingPropagation() // QTBUG-117387
+{
+ QFETCH(const QPointingDevice *, device);
+ QFETCH(QQuickTapHandler::GesturePolicy, gesturePolicy);
+ QFETCH(bool, expectPropagation);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("nestedAndSibling.qml")));
+ QQuickItem *root = window.rootObject();
+ QQuickTapHandler *th1 = root->findChild<QQuickTapHandler*>("th1");
+ QVERIFY(th1);
+ th1->setGesturePolicy(gesturePolicy);
+ QQuickTapHandler *th2 = root->findChild<QQuickTapHandler*>("th2");
+ QVERIFY(th2);
+ th2->setGesturePolicy(gesturePolicy);
+ QQuickTapHandler *th3 = root->findChild<QQuickTapHandler*>("th3");
+ QVERIFY(th3);
+ th3->setGesturePolicy(gesturePolicy);
+
+ QPoint middle(180, 140);
+ QQuickTest::pointerPress(device, &window, 0, middle);
+ QVERIFY(th3->isPressed()); // it's on top
+ QCOMPARE(th2->isPressed(), expectPropagation);
+ QCOMPARE(th1->isPressed(), expectPropagation);
+
+ QQuickTest::pointerRelease(device, &window, 0, middle);
+}
+
QTEST_MAIN(tst_TapHandler)
#include "tst_qquicktaphandler.moc"
diff --git a/tests/auto/quick/pointerhandlers/qquickwheelhandler/CMakeLists.txt b/tests/auto/quick/pointerhandlers/qquickwheelhandler/CMakeLists.txt
index 588fd8f2e2..d50181dfe4 100644
--- a/tests/auto/quick/pointerhandlers/qquickwheelhandler/CMakeLists.txt
+++ b/tests/auto/quick/pointerhandlers/qquickwheelhandler/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickwheelhandler.pro.
#####################################################################
## tst_qquickwheelhandler Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickwheelhandler LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickwheelhandler
SOURCES
- ../../../shared/util.cpp ../../../shared/util.h
- ../../shared/geometrytestutil.cpp ../../shared/geometrytestutil.h
- ../../shared/viewtestutil.cpp ../../shared/viewtestutil.h
- ../../shared/visualtestutil.cpp ../../shared/visualtestutil.h
tst_qquickwheelhandler.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -38,10 +40,10 @@ qt_internal_add_test(tst_qquickwheelhandler
qt_internal_extend_target(tst_qquickwheelhandler CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickwheelhandler CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/nested.qml b/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/nested.qml
index 49e44f2b1f..9c43df46da 100644
--- a/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/nested.qml
+++ b/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/nested.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.14
diff --git a/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/rectWheel.qml b/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/rectWheel.qml
index d4875d5313..ca6053ebcf 100644
--- a/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/rectWheel.qml
+++ b/tests/auto/quick/pointerhandlers/qquickwheelhandler/data/rectWheel.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.14
@@ -39,7 +14,23 @@ Rectangle {
}
}
+ Rectangle {
+ color: "red"
+ width: 6; height: 6; radius: 3
+ x: wheelHandler.point.position.x - radius
+ y: wheelHandler.point.position.y - radius
+ }
+
+ Text {
+ anchors.centerIn: parent
+ anchors.verticalCenterOffset: 20
+ color: "white"
+ font.pixelSize: 18
+ text: parent.x.toFixed(2) + ", " + parent.y.toFixed(2)
+ }
+
WheelHandler {
+ id: wheelHandler
activeTimeout: 0.5
}
}
diff --git a/tests/auto/quick/pointerhandlers/qquickwheelhandler/tst_qquickwheelhandler.cpp b/tests/auto/quick/pointerhandlers/qquickwheelhandler/tst_qquickwheelhandler.cpp
index 2abf2ea8c3..c88b1af2ea 100644
--- a/tests/auto/quick/pointerhandlers/qquickwheelhandler/tst_qquickwheelhandler.cpp
+++ b/tests/auto/quick/pointerhandlers/qquickwheelhandler/tst_qquickwheelhandler.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtTest/QSignalSpy>
@@ -34,8 +9,8 @@
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/qquickview.h>
#include <QtQml/qqmlcontext.h>
-#include "../../../shared/util.h"
-#include "../../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
Q_LOGGING_CATEGORY(lcPointerTests, "qt.quick.pointer.tests")
@@ -43,13 +18,15 @@ class tst_QQuickWheelHandler: public QQmlDataTest
{
Q_OBJECT
public:
- tst_QQuickWheelHandler() { }
+ tst_QQuickWheelHandler() : QQmlDataTest(QT_QMLTEST_DATADIR) { }
private slots:
void singleHandler_data();
void singleHandler();
void nestedHandler_data();
void nestedHandler();
+ void blocking_data();
+ void blocking();
private:
void sendWheelEvent(QQuickView &window, QPoint pos, QPoint angleDelta,
@@ -188,13 +165,13 @@ void tst_QQuickWheelHandler::singleHandler()
sendWheelEvent(window, eventPos, eventAngleDelta, eventPixelDelta, eventModifiers, Qt::NoScrollPhase, eventInverted);
}
QCOMPARE(rect->position().toPoint(), expectedPosition);
- QCOMPARE(activeChangedSpy.count(), 1);
+ QCOMPARE(activeChangedSpy.size(), 1);
QCOMPARE(handler->active(), true);
QCOMPARE(rect->scale(), expectedScale);
QCOMPARE(rect->rotation(), expectedRotation);
if (!eventPhases) {
QTRY_COMPARE(handler->active(), false);
- QCOMPARE(activeChangedSpy.count(), 2);
+ QCOMPARE(activeChangedSpy.size(), 2);
}
// restore by rotating backwards
@@ -204,7 +181,7 @@ void tst_QQuickWheelHandler::singleHandler()
} else {
sendWheelEvent(window, eventPos, eventAngleDelta * -1, eventPixelDelta * -1, eventModifiers, Qt::NoScrollPhase, eventInverted);
}
- QCOMPARE(activeChangedSpy.count(), eventPhases ? 2 : 3);
+ QCOMPARE(activeChangedSpy.size(), eventPhases ? 2 : 3);
QCOMPARE(handler->active(), !eventPhases);
QCOMPARE(rect->position().toPoint(), QPoint(0, 0));
QCOMPARE(rect->scale(), 1);
@@ -329,16 +306,61 @@ void tst_QQuickWheelHandler::nestedHandler()
QCOMPARE(innerRect->scale(), innerScale);
QCOMPARE(innerRect->rotation(), innerRotation);
QCOMPARE(outerRect->position().toPoint(), outerPosition);
- QCOMPARE(outerActiveChangedSpy.count(), 1);
+ QCOMPARE(outerActiveChangedSpy.size(), 1);
QCOMPARE(outerHandler->active(), true);
QCOMPARE(outerRect->scale(), outerScale);
QCOMPARE(outerRect->rotation(), outerRotation);
if (!eventPhases) {
QTRY_COMPARE(outerHandler->active(), false);
- QCOMPARE(outerActiveChangedSpy.count(), 2);
+ QCOMPARE(outerActiveChangedSpy.size(), 2);
}
}
+void tst_QQuickWheelHandler::blocking_data()
+{
+ // handler properties
+ QTest::addColumn<bool>("blocking");
+
+ // move the item
+ QTest::newRow("default: blocking") << true;
+ QTest::newRow("nonblocking") << false;
+}
+
+void tst_QQuickWheelHandler::blocking()
+{
+ QFETCH(bool, blocking);
+
+ QQuickView window;
+ QByteArray errorMessage;
+ QVERIFY2(QQuickTest::initView(window, testFileUrl("nested.qml"), true, &errorMessage), errorMessage.constData());
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ QQuickItem *outerRect = window.rootObject();
+ QVERIFY(outerRect != nullptr);
+ QQuickWheelHandler *outerHandler = outerRect->findChild<QQuickWheelHandler*>("outerWheelHandler");
+ QVERIFY(outerHandler != nullptr);
+ QQuickWheelHandler *innerHandler = outerRect->findChild<QQuickWheelHandler*>("innerWheelHandler");
+ QVERIFY(innerHandler != nullptr);
+ QQuickItem *innerRect = innerHandler->parentItem();
+ QVERIFY(innerRect != nullptr);
+ QPoint eventPos = innerRect->mapToScene(innerRect->boundingRect().center()).toPoint();
+
+ QCOMPARE(innerHandler->isBlocking(), true); // default property value
+ innerHandler->setBlocking(blocking);
+ QSignalSpy innerActiveChangedSpy(innerHandler, SIGNAL(activeChanged()));
+ QSignalSpy outerActiveChangedSpy(outerHandler, SIGNAL(activeChanged()));
+
+ qreal innerPosWas = innerRect->position().x();
+ qreal outerPosWas = outerRect->position().x();
+
+ sendWheelEvent(window, eventPos, {0, 120}, {0, 0}, Qt::NoModifier, Qt::NoScrollPhase, false);
+ QTRY_COMPARE(innerActiveChangedSpy.size(), 2);
+ QCOMPARE(innerRect->position().x(), innerPosWas + 15);
+ QCOMPARE(outerActiveChangedSpy.size(), blocking ? 0 : 2);
+ QCOMPARE(outerRect->position().x(), outerPosWas + (blocking ? 0 : 15));
+}
+
QTEST_MAIN(tst_QQuickWheelHandler)
#include "tst_qquickwheelhandler.moc"
diff --git a/tests/auto/quick/propertyrequirements/CMakeLists.txt b/tests/auto/quick/propertyrequirements/CMakeLists.txt
index 6b689502ea..cab8e3904c 100644
--- a/tests/auto/quick/propertyrequirements/CMakeLists.txt
+++ b/tests/auto/quick/propertyrequirements/CMakeLists.txt
@@ -1,13 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from propertyrequirements.pro.
#####################################################################
## tst_propertyrequirements Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_propertyrequirements LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_propertyrequirements
SOURCES
tst_propertyrequirements.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::QmlPrivate
)
diff --git a/tests/auto/quick/propertyrequirements/tst_propertyrequirements.cpp b/tests/auto/quick/propertyrequirements/tst_propertyrequirements.cpp
index ca348eea03..c8efaab4b1 100644
--- a/tests/auto/quick/propertyrequirements/tst_propertyrequirements.cpp
+++ b/tests/auto/quick/propertyrequirements/tst_propertyrequirements.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Kevin Krammer <kevin.krammer@kdab.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Kevin Krammer <kevin.krammer@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlengine.h>
@@ -92,8 +67,9 @@ void tst_PropertyRequirements::constantOrNotifyableMain()
}
messages.sort();
- const QString message("\nThe following QML Types have properties which are neither CONSTANT nor NOTIFYable:\n");
- QWARN(qPrintable(message + messages.join("\n")));
+ qWarning() << "\nThe following QML Types have properties which are"
+ << "neither CONSTANT nor NOTIFYable nor BINDABLE:\n"
+ << qPrintable(messages.join("\n"));
// TODO enable once technical debt is fixes
// QCOMPARE(failuresByProperty.count(), 0);
@@ -119,7 +95,9 @@ void tst_PropertyRequirements::constantOrNotifyableFull()
}
- static const QString messagePattern("\nProperty %1 neither CONSTANT nor NOTIFYable. Affected types:\n\t%2");
+ static const QLatin1String messagePattern(
+ "\nProperty %1 neither CONSTANT nor NOTIFYable nor BINDABLE. "
+ "Affected types:\n\t%2");
QStringList occurrencesList = occurrences.values();
occurrencesList.sort();
messages.append(messagePattern.arg(it.key(), occurrencesList.join("\n\t")));
@@ -127,7 +105,7 @@ void tst_PropertyRequirements::constantOrNotifyableFull()
}
messages.sort();
- QWARN(qPrintable(messages.join("\n")));
+ qWarning() << qPrintable(messages.join("\n"));
// TODO enable once technical debt is fixes
// QCOMPARE(failuresByProperty.count(), 0);
@@ -185,12 +163,12 @@ void tst_PropertyRequirements::testQmlType(TestDepth testDepth, const QQmlType &
inheritanceHierarchy.append(qmlType.metaObject());
}
- for (const QMetaObject *metaClass : qAsConst(inheritanceHierarchy)) {
+ for (const QMetaObject *metaClass : std::as_const(inheritanceHierarchy)) {
for (int idx = metaClass->propertyOffset(); idx < metaClass->propertyCount(); ++idx) {
const QMetaProperty property = metaClass->property(idx);
// needs to be either CONSTANT or have a NOTIFY signal
- if (!property.isConstant() && !property.hasNotifySignal()) {
+ if (!property.isConstant() && !property.hasNotifySignal() && !property.isBindable()) {
static const QString fullNamePattern("%1::%2");
const QString fullPropertyName = fullNamePattern.arg(metaClass->className(), property.name());
diff --git a/tests/auto/quick/qquickaccessible/CMakeLists.txt b/tests/auto/quick/qquickaccessible/CMakeLists.txt
index 8d0fcbe406..517e910f73 100644
--- a/tests/auto/quick/qquickaccessible/CMakeLists.txt
+++ b/tests/auto/quick/qquickaccessible/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickaccessible.pro.
#####################################################################
## tst_qquickaccessible Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickaccessible LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,17 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickaccessible
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickaccessible.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -34,10 +41,10 @@ qt_internal_add_test(tst_qquickaccessible
qt_internal_extend_target(tst_qquickaccessible CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickaccessible CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickaccessible/data/hittest.qml b/tests/auto/quick/qquickaccessible/data/hittest.qml
index 7e5412ee64..09d60d8f07 100644
--- a/tests/auto/quick/qquickaccessible/data/hittest.qml
+++ b/tests/auto/quick/qquickaccessible/data/hittest.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickaccessible/data/ignored.qml b/tests/auto/quick/qquickaccessible/data/ignored.qml
index de21b1a801..150a2bd8ef 100644
--- a/tests/auto/quick/qquickaccessible/data/ignored.qml
+++ b/tests/auto/quick/qquickaccessible/data/ignored.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickaccessible/data/text.qml b/tests/auto/quick/qquickaccessible/data/text.qml
index 6daeacfd81..4de461f2e1 100644
--- a/tests/auto/quick/qquickaccessible/data/text.qml
+++ b/tests/auto/quick/qquickaccessible/data/text.qml
@@ -57,4 +57,14 @@ Item {
Accessible.description: "description"
}
+ Text {
+ x: 100
+ y: 200
+ width: 100
+ height: 40
+ text : "<p>Rich text with links:</p><a href=\"https://qt.io\">Website</a> or <a href=\"https://qt.io/blog\">blog</a>"
+ Accessible.name: Accessible.stripHtml(text)
+ Accessible.description: "Rich text with two hyperlinks"
+ }
+
}
diff --git a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
index 4c192374ee..e164d89217 100644
--- a/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
+++ b/tests/auto/quick/qquickaccessible/tst_qquickaccessible.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -44,9 +19,14 @@
#include <QtQuick/private/qquickaccessibleattached_p.h>
#include <QtQuick/private/qquicklistview_p.h>
#include <QtQuick/private/qquicktext_p.h>
+#include <QtQuick/private/qquicktextinput_p.h>
-#include "../../shared/util.h"
-#include "../shared/visualtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+
+#include <QQmlComponent>
+
+using namespace Qt::StringLiterals;
#define EXPECT(cond) \
do { \
@@ -69,7 +49,7 @@ public:
public slots:
void initTestCase() override;
void cleanupTestCase();
- void init();
+ void init() override;
void cleanup();
private slots:
@@ -77,13 +57,16 @@ private slots:
void commonTests();
void quickAttachedProperties();
+ void attachedWins();
void basicPropertiesTest();
void hitTest();
void checkableTest();
void ignoredTest();
+ void passwordTest();
};
tst_QQuickAccessible::tst_QQuickAccessible()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
@@ -110,6 +93,7 @@ void tst_QQuickAccessible::cleanupTestCase()
void tst_QQuickAccessible::init()
{
+ QQmlDataTest::init();
QTestAccessibility::clearEvents();
}
@@ -117,13 +101,17 @@ void tst_QQuickAccessible::cleanup()
{
const EventList list = QTestAccessibility::events();
if (!list.isEmpty()) {
- qWarning().noquote() << list.count()
+ qWarning().noquote() << list.size()
<< "accessibility event(s) were not handled in testfunction '"
<< QTest::currentTestFunction() << "':";
- for (int i = 0; i < list.count(); ++i)
- qWarning().noquote() << " " << (i + 1) << ": Object: " << list.at(i)->object()
+ for (int i = 0; i < list.size(); ++i) {
+ auto object = list.at(i)->object();
+ QString objectInfo = object ? QDebug::toString(object)
+ : u"[deleted object]"_s;
+ qWarning().noquote() << " " << (i + 1) << objectInfo
<< "Event: '" << qAccessibleEventString(list.at(i)->type())
<< "' Child: " << list.at(i)->child();
+ }
}
QTestAccessibility::clearEvents();
}
@@ -142,17 +130,17 @@ void tst_QQuickAccessible::commonTests()
qDebug() << "testing" << accessibleRoleFileName;
- QQuickView *view = new QQuickView();
+ auto view = std::make_unique<QQuickView>();
// view->setFixedSize(240,320);
view->setSource(testFileUrl(accessibleRoleFileName));
view->show();
// view->setFocus();
QVERIFY(view->rootObject() != nullptr);
- QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(view);
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(view.get());
QVERIFY(iface);
- delete view;
+ view.reset();
QTestAccessibility::clearEvents();
}
@@ -163,12 +151,11 @@ void tst_QQuickAccessible::quickAttachedProperties()
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0\nItem {\n"
"}", QUrl());
- QObject *object = component.create();
+ auto object = std::unique_ptr<QObject>(component.create());
QVERIFY(object != nullptr);
- QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object);
+ QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object.get());
QCOMPARE(attachedObject, static_cast<QObject*>(nullptr));
- delete object;
}
// Attaching to non-item
@@ -197,11 +184,11 @@ void tst_QQuickAccessible::quickAttachedProperties()
component.setData("import QtQuick 2.0\nItem {\n"
"Accessible.role: Accessible.Button\n"
"}", QUrl());
- QObject *object = component.create();
+ auto object = std::unique_ptr<QObject>(component.create());
QVERIFY(object != nullptr);
const auto attachedObject = qobject_cast<QQuickAccessibleAttached*>(
- QQuickAccessibleAttached::attachedProperties(object));
+ QQuickAccessibleAttached::attachedProperties(object.get()));
QVERIFY(attachedObject);
if (attachedObject) {
QVariant p = attachedObject->property("role");
@@ -215,7 +202,6 @@ void tst_QQuickAccessible::quickAttachedProperties()
QVERIFY2(p.value<QString>().isEmpty(), QTest::toString(p));
QCOMPARE(attachedObject->wasNameExplicitlySet(), false);
}
- delete object;
}
// Attached property
@@ -227,11 +213,11 @@ void tst_QQuickAccessible::quickAttachedProperties()
"Accessible.name: \"Donald\"\n"
"Accessible.description: \"Duck\"\n"
"}", QUrl());
- QObject *object = component.create();
+ auto object = std::unique_ptr<QObject>(component.create());
QVERIFY(object != nullptr);
const auto attachedObject = qobject_cast<QQuickAccessibleAttached*>(
- QQuickAccessibleAttached::attachedProperties(object));
+ QQuickAccessibleAttached::attachedProperties(object.get()));
QVERIFY(attachedObject);
if (attachedObject) {
QVariant p = attachedObject->property("role");
@@ -245,7 +231,6 @@ void tst_QQuickAccessible::quickAttachedProperties()
QCOMPARE(p.toString(), QLatin1String("Duck"));
QCOMPARE(attachedObject->wasNameExplicitlySet(), true);
}
- delete object;
}
// Check overriding of attached role for Text
@@ -257,10 +242,10 @@ void tst_QQuickAccessible::quickAttachedProperties()
"Accessible.name: \"TextButton\"\n"
"Accessible.description: \"Text Button\"\n"
"}", QUrl());
- QObject *object = component.create();
+ auto object = std::unique_ptr<QObject>(component.create());
QVERIFY(object != nullptr);
- QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object);
+ QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(object.get());
QVERIFY(attachedObject);
if (attachedObject) {
QVariant p = attachedObject->property("role");
@@ -273,7 +258,6 @@ void tst_QQuickAccessible::quickAttachedProperties()
QCOMPARE(p.isNull(), false);
QCOMPARE(p.toString(), QLatin1String("Text Button"));
}
- delete object;
}
// Check overriding of attached role for Text
{
@@ -289,13 +273,13 @@ void tst_QQuickAccessible::quickAttachedProperties()
"Accessible.description: \"Text Button\"\n"
"}\n"
"}", QUrl());
- QObject *object = component.create();
+ auto object = std::unique_ptr<QObject>(component.create());
QVERIFY(object != nullptr);
- QQuickListView *listview = qobject_cast<QQuickListView *>(object);
+ QQuickListView *listview = qobject_cast<QQuickListView *>(object.get());
QVERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
- QQuickText *childItem = QQuickVisualTestUtil::findItem<QQuickText>(contentItem, "acc_text");
+ QQuickText *childItem = QQuickVisualTestUtils::findItem<QQuickText>(contentItem, "acc_text");
QVERIFY(childItem != nullptr);
QObject *attachedObject = QQuickAccessibleAttached::attachedProperties(childItem);
@@ -311,7 +295,6 @@ void tst_QQuickAccessible::quickAttachedProperties()
QCOMPARE(p.isNull(), false);
QCOMPARE(p.toString(), QLatin1String("Text Button"));
}
- delete object;
}
// Check that a name can be implicitly set.
{
@@ -323,11 +306,11 @@ void tst_QQuickAccessible::quickAttachedProperties()
Accessible.role: Accessible.Button
Accessible.description: "Text Button"
})", QUrl());
- QScopedPointer<QObject> object(component.create());
+ auto object = std::unique_ptr<QObject>(component.create());
QVERIFY(object);
const auto attachedObject = qobject_cast<QQuickAccessibleAttached*>(
- QQuickAccessibleAttached::attachedProperties(object.data()));
+ QQuickAccessibleAttached::attachedProperties(object.get()));
QVERIFY(attachedObject);
QVERIFY(!attachedObject->wasNameExplicitlySet());
@@ -342,24 +325,49 @@ void tst_QQuickAccessible::quickAttachedProperties()
QTestAccessibility::clearEvents();
}
+// Verify that a role can be explicitly set, and that the values from the
+// attached object are used even if the item has a default role - QTBUG-110114
+void tst_QQuickAccessible::attachedWins()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(R"(
+ import QtQuick
+ import QtQuick.Controls
+ Button {
+ text: "Button"
+ objectName: "button"
+ Accessible.role: Accessible.RadioButton
+ Accessible.description: "Radio Button"
+ })", QUrl());
+ auto button = std::unique_ptr<QObject>(component.create());
+ QVERIFY(button);
+
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(button.get());
+ QVERIFY(iface);
+
+ QCOMPARE(iface->role(), QAccessible::RadioButton);
+ QTestAccessibility::clearEvents();
+}
+
void tst_QQuickAccessible::basicPropertiesTest()
{
QAccessibleInterface *app = QAccessible::queryAccessibleInterface(qApp);
QCOMPARE(app->childCount(), 0);
- QQuickView *window = new QQuickView();
+ auto window = std::make_unique<QQuickView>();
window->setSource(testFileUrl("text.qml"));
window->show();
QCOMPARE(app->childCount(), 1);
- QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window);
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.get());
QVERIFY(iface);
QCOMPARE(iface->childCount(), 1);
QAccessibleInterface *item = iface->child(0);
QVERIFY(item);
- QCOMPARE(item->childCount(), 5);
+ QCOMPARE(item->childCount(), 6);
QCOMPARE(item->rect().size(), QSize(400, 400));
QCOMPARE(item->role(), QAccessible::Client);
QCOMPARE(iface->indexOfChild(item), 0);
@@ -387,6 +395,7 @@ void tst_QQuickAccessible::basicPropertiesTest()
QCOMPARE(item->indexOfChild(text2), 1);
QVERIFY(!text2->state().editable);
QVERIFY(text2->state().readOnly);
+ QVERIFY(text2->state().focusable);
QCOMPARE(iface->indexOfChild(text2), -1);
QCOMPARE(text2->indexOfChild(item), -1);
@@ -444,6 +453,31 @@ void tst_QQuickAccessible::basicPropertiesTest()
QCOMPARE(text3->role(), QAccessible::StaticText);
QVERIFY(text3->state().readOnly);
+ // Text "Rich text"
+ QAccessibleInterface *richText = item->child(5);
+ QVERIFY(text3);
+ QCOMPARE(richText->childCount(), 2);
+ QCOMPARE(richText->text(QAccessible::Name), QLatin1String("Rich text with links:\nWebsite or blog"));
+ QCOMPARE(richText->role(), QAccessible::StaticText);
+ QCOMPARE(item->indexOfChild(richText), 5);
+ QVERIFY(!richText->state().editable);
+ QVERIFY(!richText->state().readOnly);
+
+ // Check for hyperlink child nodes
+ for (int i = 0; i < richText->childCount(); ++i) {
+ static const char *linkUrls[2][2] = {
+ {"Website", "https://qt.io"},
+ {"blog", "https://qt.io/blog"}
+ };
+ QAccessibleInterface *link1 = richText->child(i);
+ QVERIFY(link1);
+ QCOMPARE(link1->role(), QAccessible::Link);
+ QAccessibleHyperlinkInterface *link = link1->hyperlinkInterface();
+ QVERIFY(link);
+ QCOMPARE(link->anchor(), QLatin1String(linkUrls[i][0]));
+ QCOMPARE(link->anchorTarget(), QLatin1String(linkUrls[i][1]));
+ }
+
// see if implicit changes back
attached->setRole(QAccessible::EditableText);
QEXPECT_FAIL("", "EditableText does not implicitly set readOnly to false", Continue);
@@ -453,7 +487,7 @@ void tst_QQuickAccessible::basicPropertiesTest()
attached->setRole(QAccessible::StaticText);
QVERIFY(!text3->state().readOnly);
- delete window;
+ window.reset();
QTestAccessibility::clearEvents();
}
@@ -472,14 +506,15 @@ QAccessibleInterface *topLevelChildAt(QAccessibleInterface *iface, int x, int y)
void tst_QQuickAccessible::hitTest()
{
- QQuickView *window = new QQuickView;
+ auto window = std::make_unique<QQuickView>();
window->setSource(testFileUrl("hittest.qml"));
window->show();
- QAccessibleInterface *windowIface = QAccessible::queryAccessibleInterface(window);
+ QAccessibleInterface *windowIface = QAccessible::queryAccessibleInterface(window.get());
QVERIFY(windowIface);
QAccessibleInterface *rootItem = windowIface->child(0);
- QRect rootRect = rootItem->rect();
+ // on Android the main window is always shown fullscreen
+ QRect rootRect = QRect(window->x(), window->y(), window->width(), window->height());
// check the root item from app
QAccessibleInterface *appIface = QAccessible::queryAccessibleInterface(qApp);
@@ -525,13 +560,13 @@ void tst_QQuickAccessible::hitTest()
}
}
- delete window;
+ window.reset();
QTestAccessibility::clearEvents();
}
void tst_QQuickAccessible::checkableTest()
{
- QScopedPointer<QQuickView> window(new QQuickView());
+ auto window = std::make_unique<QQuickView>();
window->setSource(testFileUrl("checkbuttons.qml"));
window->show();
@@ -544,7 +579,7 @@ void tst_QQuickAccessible::checkableTest()
QAccessible::State activatedChange;
activatedChange.active = true;
- QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.data());
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.get());
QVERIFY(iface);
QAccessibleInterface *root = iface->child(0);
@@ -608,7 +643,7 @@ void tst_QQuickAccessible::checkableTest()
void tst_QQuickAccessible::ignoredTest()
{
- QScopedPointer<QQuickView> window(new QQuickView());
+ auto window = std::make_unique<QQuickView>();
window->setSource(testFileUrl("ignored.qml"));
window->show();
@@ -621,7 +656,7 @@ void tst_QQuickAccessible::ignoredTest()
QAccessible::State activatedChange;
activatedChange.active = true;
- QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.data());
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.get());
QVERIFY(iface);
QAccessibleInterface *rectangleA = iface->child(0);
@@ -636,6 +671,34 @@ void tst_QQuickAccessible::ignoredTest()
QTestAccessibility::clearEvents();
}
+void tst_QQuickAccessible::passwordTest()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick\nTextInput {\n"
+ "Accessible.role: Accessible.EditableText\n"
+ "Accessible.name: \"Password\"\n"
+ "Accessible.passwordEdit: true\n"
+ "echoMode: TextInput.Password\n"
+ "text: \"Green\"\n"
+ "}", QUrl());
+ auto object = std::unique_ptr<QObject>(component.create());
+ QVERIFY(object != nullptr);
+
+ QQuickTextInput *textInput = qobject_cast<QQuickTextInput *>(object.get());
+ QVERIFY(textInput != nullptr);
+
+ const auto passwordCharacter = textInput->passwordCharacter();
+ const auto passwordLength = textInput->text().length();
+ const auto password = passwordCharacter.repeated(passwordLength);
+
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(object.get());
+ QVERIFY(iface);
+ QCOMPARE(iface->text(QAccessible::Value), password);
+
+ QTestAccessibility::clearEvents();
+}
+
QTEST_MAIN(tst_QQuickAccessible)
#include "tst_qquickaccessible.moc"
diff --git a/tests/auto/quick/qquickanchors/CMakeLists.txt b/tests/auto/quick/qquickanchors/CMakeLists.txt
index 08a4298145..9bc4d5203b 100644
--- a/tests/auto/quick/qquickanchors/CMakeLists.txt
+++ b/tests/auto/quick/qquickanchors/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickanchors.pro.
#####################################################################
## tst_qquickanchors Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickanchors LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickanchors
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickanchors.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,10 +37,10 @@ qt_internal_add_test(tst_qquickanchors
qt_internal_extend_target(tst_qquickanchors CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickanchors CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickanchors/data/centerin.qml b/tests/auto/quick/qquickanchors/data/centerin.qml
index b880219f0f..94c344b4e8 100644
--- a/tests/auto/quick/qquickanchors/data/centerin.qml
+++ b/tests/auto/quick/qquickanchors/data/centerin.qml
@@ -22,4 +22,11 @@ Rectangle {
anchors.centerIn: parent;
anchors.alignWhenCentered: false
}
+
+ Rectangle {
+ objectName: "centered4"
+ width: 0.9; height: 0.9; color: "plum"
+ anchors.centerIn: parent;
+ anchors.alignWhenCentered: false
+ }
}
diff --git a/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp b/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp
index 128a154492..508a3906fc 100644
--- a/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp
+++ b/tests/auto/quick/qquickanchors/tst_qquickanchors.cpp
@@ -1,30 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#include <qtest.h>
#include <QSignalSpy>
#include <private/qquickitem_p.h>
@@ -35,18 +11,18 @@
#include <QtQuick/private/qquicktext_p.h>
#include <QtQuick/private/qquickanchors_p_p.h>
#include <QtQuick/private/qquickitem_p.h>
-#include "../../shared/util.h"
-#include "../shared/visualtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
Q_DECLARE_METATYPE(QQuickAnchors::Anchor)
-using namespace QQuickVisualTestUtil;
+using namespace QQuickVisualTestUtils;
class tst_qquickanchors : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickanchors() {}
+ tst_qquickanchors() : QQmlDataTest(QT_QMLTEST_DATADIR) {}
private slots:
void basicAnchors();
@@ -168,15 +144,16 @@ void tst_qquickanchors::basicAnchorsRTL()
qApp->processEvents();
QQuickItem* rootItem = qobject_cast<QQuickItem*>(view->rootObject());
- foreach (QObject *child, rootItem->children()) {
+ const QObjectList children = rootItem->children();
+ for (QObject *child : children) {
bool mirrored = QQuickItemPrivate::get(qobject_cast<QQuickItem*>(child))->anchors()->mirrored();
QCOMPARE(mirrored, false);
}
- foreach (QObject *child, rootItem->children())
+ for (QObject *child : children)
mirrorAnchors(qobject_cast<QQuickItem*>(child));
- foreach (QObject *child, rootItem->children()) {
+ for (QObject *child : children) {
bool mirrored = QQuickItemPrivate::get(qobject_cast<QQuickItem*>(child))->anchors()->mirrored();
QCOMPARE(mirrored, true);
}
@@ -298,7 +275,8 @@ void tst_qquickanchors::illegalSets_data()
<< "Rectangle { id: rect; Rectangle { anchors.left: rect.left; anchors.right: rect.right; anchors.horizontalCenter: rect.horizontalCenter } }"
<< "<Unknown File>:2:23: QML Rectangle: Cannot specify left, right, and horizontalCenter anchors at the same time.";
- foreach (const QString &side, QStringList() << "left" << "right") {
+ const QStringList leftRight = {"left", "right"};
+ for (const QString &side : leftRight) {
QTest::newRow("H - anchor to V")
<< QString("Rectangle { Rectangle { anchors.%1: parent.top } }").arg(side)
<< "<Unknown File>:2:13: QML Rectangle: Cannot anchor a horizontal edge to a vertical edge.";
@@ -321,7 +299,8 @@ void tst_qquickanchors::illegalSets_data()
<< "Rectangle { Text { id: text1; text: \"Hello\" } Text { anchors.baseline: text1.baseline; anchors.top: text1.top; } }"
<< "<Unknown File>:2:47: QML Text: Baseline anchor cannot be used in conjunction with top, bottom, or verticalCenter anchors.";
- foreach (const QString &side, QStringList() << "top" << "bottom" << "baseline") {
+ const QStringList topBottomBaseline = {"top", "bottom", "baseline"};
+ for (const QString &side : topBottomBaseline) {
QTest::newRow("V - anchor to H")
<< QString("Rectangle { Rectangle { anchors.%1: parent.left } }").arg(side)
@@ -541,6 +520,15 @@ void tst_qquickanchors::centerIn()
QCOMPARE(rect3->x(), 94.5);
QCOMPARE(rect3->y(), 94.5);
+ //QTBUG-95224 (fractional positions are not center-rounded correctly)
+ // The center anchor lines on the parent will be rounded from 41.2 / 2 == 20.6 to 21
+ // rect4 has anchors.alignWhenCentered: false, so no rounding will be done on that items position.
+ // As a result, the expected position of rect4 will be 21 - 0.9/2 = 20.55
+ QQuickRectangle* rect4 = findItem<QQuickRectangle>(view->rootObject(), QLatin1String("centered4"));
+ view->rootObject()->setWidth(41.2);
+ view->rootObject()->setHeight(41.2);
+ QCOMPARE(rect4->x(), 20.55);
+ QCOMPARE(rect4->y(), 20.55);
delete view;
}
diff --git a/tests/auto/quick/qquickanimatedimage/BLACKLIST b/tests/auto/quick/qquickanimatedimage/BLACKLIST
new file mode 100644
index 0000000000..c4778ba8e5
--- /dev/null
+++ b/tests/auto/quick/qquickanimatedimage/BLACKLIST
@@ -0,0 +1,5 @@
+# QTBUG-103076
+[mirror_running]
+android
+[mirror_notRunning]
+android
diff --git a/tests/auto/quick/qquickanimatedimage/CMakeLists.txt b/tests/auto/quick/qquickanimatedimage/CMakeLists.txt
index e7a026a36f..109e84cc14 100644
--- a/tests/auto/quick/qquickanimatedimage/CMakeLists.txt
+++ b/tests/auto/quick/qquickanimatedimage/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickanimatedimage.pro.
#####################################################################
## tst_qquickanimatedimage Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickanimatedimage LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,18 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickanimatedimage
SOURCES
- ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h
- ../../shared/util.cpp ../../shared/util.h
tst_qquickanimatedimage.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -32,10 +38,10 @@ qt_internal_add_test(tst_qquickanimatedimage
qt_internal_extend_target(tst_qquickanimatedimage CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickanimatedimage CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickanimatedimage/data/currentframe.qml b/tests/auto/quick/qquickanimatedimage/data/currentframe.qml
index b679da2a99..3c58bdaa4b 100644
--- a/tests/auto/quick/qquickanimatedimage/data/currentframe.qml
+++ b/tests/auto/quick/qquickanimatedimage/data/currentframe.qml
@@ -4,6 +4,7 @@ AnimatedImage {
property int currentFrameChangeCount: 0
property int frameChangeCount: 0
source: "stickman.gif"
+ paused: true
onCurrentFrameChanged: if (currentFrame > 0) ++currentFrameChangeCount;
onFrameChanged: if (currentFrame > 0) ++frameChangeCount;
function scriptedSetCurrentFrame(frame) {
diff --git a/tests/auto/quick/qquickanimatedimage/data/stickmanerror1.qml b/tests/auto/quick/qquickanimatedimage/data/stickmansourcesized.qml
index 4f823b3d70..76d277df62 100644
--- a/tests/auto/quick/qquickanimatedimage/data/stickmanerror1.qml
+++ b/tests/auto/quick/qquickanimatedimage/data/stickmansourcesized.qml
@@ -1,6 +1,6 @@
import QtQuick 2.0
AnimatedImage {
- sourceSize: "240x180"
+ sourceSize: "80x60"
source: "stickman.gif"
}
diff --git a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
index 31c3fb9946..efea42de34 100644
--- a/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
+++ b/tests/auto/quick/qquickanimatedimage/tst_qquickanimatedimage.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlexpression.h>
@@ -36,8 +11,8 @@
#include <QSignalSpy>
#include <QtQml/qqmlcontext.h>
-#include "../../shared/testhttpserver.h"
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/testhttpserver_p.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
Q_DECLARE_METATYPE(QQuickImageBase::Status)
@@ -62,7 +37,7 @@ class tst_qquickanimatedimage : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickanimatedimage() {}
+ tst_qquickanimatedimage() : QQmlDataTest(QT_QMLTEST_DATADIR) {}
private slots:
void cleanup();
@@ -77,9 +52,9 @@ private slots:
void remote();
void remote_data();
void sourceSize();
+ void setSourceSize();
void sourceSizeChanges();
void sourceSizeChanges_intermediate();
- void sourceSizeReadOnly();
void invalidSource();
void qtbug_16520();
void progressAndStatusChanges();
@@ -87,6 +62,7 @@ private slots:
void noCaching();
void sourceChangesOnFrameChanged();
void currentFrame();
+ void qtbug_120555();
};
void tst_qquickanimatedimage::cleanup()
@@ -157,10 +133,10 @@ void tst_qquickanimatedimage::frameCount()
const QUrl origSource = anim->source();
anim->setSource(QUrl());
QCOMPARE(anim->frameCount(), 0);
- QCOMPARE(frameCountChangedSpy.count(), 1);
+ QCOMPARE(frameCountChangedSpy.size(), 1);
anim->setSource(origSource);
QCOMPARE(anim->frameCount(), 3);
- QCOMPARE(frameCountChangedSpy.count(), 2);
+ QCOMPARE(frameCountChangedSpy.size(), 2);
delete anim;
}
@@ -194,13 +170,13 @@ void tst_qquickanimatedimage::mirror_running()
QVERIFY(spy.isValid());
anim->setPlaying(true);
- QTRY_VERIFY(spy.count() == 1); spy.clear();
+ QTRY_VERIFY(spy.size() == 1); spy.clear();
anim->setMirror(true);
QCOMPARE(anim->currentFrame(), 1);
QImage frame1_flipped = window.grabWindow();
- QTRY_VERIFY(spy.count() == 1); spy.clear();
+ QTRY_VERIFY(spy.size() == 1); spy.clear();
QCOMPARE(anim->currentFrame(), 0); // animation only has 2 frames, should cycle back to first
QImage frame0_flipped = window.grabWindow();
@@ -312,12 +288,19 @@ void tst_qquickanimatedimage::sourceSize()
delete anim;
}
-void tst_qquickanimatedimage::sourceSizeReadOnly()
+void tst_qquickanimatedimage::setSourceSize()
{
QQmlEngine engine;
- QQmlComponent component(&engine, testFileUrl("stickmanerror1.qml"));
- QVERIFY(component.isError());
- QCOMPARE(component.errors().at(0).description(), QString("Invalid property assignment: \"sourceSize\" is a read-only property"));
+ QQmlComponent component(&engine, testFileUrl("stickmansourcesized.qml"));
+ QScopedPointer<QQuickAnimatedImage> anim(qobject_cast<QQuickAnimatedImage *>(component.create()));
+ QVERIFY(anim);
+ QCOMPARE(anim->sourceSize(), QSize(80, 60));
+
+ anim->setSourceSize(QSize(40, 30));
+ QCOMPARE(anim->sourceSize(), QSize(40, 30));
+
+ anim->setSourceSize(QSize());
+ QCOMPARE(anim->sourceSize(), QSize(160, 120));
}
void tst_qquickanimatedimage::invalidSource()
@@ -361,48 +344,48 @@ void tst_qquickanimatedimage::sourceSizeChanges()
// Local
ctxt->setContextProperty("srcImage", QUrl(""));
QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Null);
- QTRY_COMPARE(sourceSizeSpy.count(), 0);
+ QTRY_COMPARE(sourceSizeSpy.size(), 0);
ctxt->setContextProperty("srcImage", testFileUrl("hearts.gif"));
QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 1);
+ QTRY_COMPARE(sourceSizeSpy.size(), 1);
ctxt->setContextProperty("srcImage", testFileUrl("hearts.gif"));
QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 1);
+ QTRY_COMPARE(sourceSizeSpy.size(), 1);
ctxt->setContextProperty("srcImage", testFileUrl("hearts_copy.gif"));
QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 1);
+ QTRY_COMPARE(sourceSizeSpy.size(), 1);
ctxt->setContextProperty("srcImage", testFileUrl("colors.gif"));
QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 2);
+ QTRY_COMPARE(sourceSizeSpy.size(), 2);
ctxt->setContextProperty("srcImage", QUrl(""));
QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Null);
- QTRY_COMPARE(sourceSizeSpy.count(), 3);
+ QTRY_COMPARE(sourceSizeSpy.size(), 3);
// Remote
ctxt->setContextProperty("srcImage", server.url("/hearts.gif"));
QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 4);
+ QTRY_COMPARE(sourceSizeSpy.size(), 4);
ctxt->setContextProperty("srcImage", server.url("/hearts.gif"));
QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 4);
+ QTRY_COMPARE(sourceSizeSpy.size(), 4);
ctxt->setContextProperty("srcImage", server.url("/hearts_copy.gif"));
QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 4);
+ QTRY_COMPARE(sourceSizeSpy.size(), 4);
ctxt->setContextProperty("srcImage", server.url("/colors.gif"));
QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 5);
+ QTRY_COMPARE(sourceSizeSpy.size(), 5);
ctxt->setContextProperty("srcImage", QUrl(""));
QTRY_COMPARE(anim->status(), QQuickAnimatedImage::Null);
- QTRY_COMPARE(sourceSizeSpy.count(), 6);
+ QTRY_COMPARE(sourceSizeSpy.size(), 6);
delete anim;
}
@@ -478,17 +461,17 @@ void tst_qquickanimatedimage::progressAndStatusChanges()
ctxt->setContextProperty("srcImage", testFileUrl("stickman.gif"));
QTRY_COMPARE(obj->status(), QQuickImage::Ready);
QTRY_COMPARE(obj->progress(), 1.0);
- QTRY_COMPARE(sourceSpy.count(), 0);
- QTRY_COMPARE(progressSpy.count(), 0);
- QTRY_COMPARE(statusSpy.count(), 0);
+ QTRY_COMPARE(sourceSpy.size(), 0);
+ QTRY_COMPARE(progressSpy.size(), 0);
+ QTRY_COMPARE(statusSpy.size(), 0);
// Loading local file
ctxt->setContextProperty("srcImage", testFileUrl("colors.gif"));
QTRY_COMPARE(obj->status(), QQuickImage::Ready);
QTRY_COMPARE(obj->progress(), 1.0);
- QTRY_COMPARE(sourceSpy.count(), 1);
- QTRY_COMPARE(progressSpy.count(), 0);
- QTRY_COMPARE(statusSpy.count(), 1);
+ QTRY_COMPARE(sourceSpy.size(), 1);
+ QTRY_COMPARE(progressSpy.size(), 0);
+ QTRY_COMPARE(statusSpy.size(), 1);
// Loading remote file
ctxt->setContextProperty("srcImage", server.url("/stickman.gif"));
@@ -496,16 +479,16 @@ void tst_qquickanimatedimage::progressAndStatusChanges()
QTRY_COMPARE(obj->progress(), 0.0);
QTRY_COMPARE(obj->status(), QQuickImage::Ready);
QTRY_COMPARE(obj->progress(), 1.0);
- QTRY_COMPARE(sourceSpy.count(), 2);
- QTRY_VERIFY(progressSpy.count() > 1);
- QTRY_COMPARE(statusSpy.count(), 3);
+ QTRY_COMPARE(sourceSpy.size(), 2);
+ QTRY_VERIFY(progressSpy.size() > 1);
+ QTRY_COMPARE(statusSpy.size(), 3);
ctxt->setContextProperty("srcImage", "");
QTRY_COMPARE(obj->status(), QQuickImage::Null);
QTRY_COMPARE(obj->progress(), 0.0);
- QTRY_COMPARE(sourceSpy.count(), 3);
- QTRY_VERIFY(progressSpy.count() > 2);
- QTRY_COMPARE(statusSpy.count(), 4);
+ QTRY_COMPARE(sourceSpy.size(), 3);
+ QTRY_VERIFY(progressSpy.size() > 2);
+ QTRY_COMPARE(statusSpy.size(), 4);
delete obj;
}
@@ -531,40 +514,40 @@ void tst_qquickanimatedimage::playingAndPausedChanges()
obj->setProperty("paused", false);
QTRY_VERIFY(obj->isPlaying());
QTRY_VERIFY(!obj->isPaused());
- QTRY_COMPARE(playingSpy.count(), 0);
- QTRY_COMPARE(pausedSpy.count(), 0);
+ QTRY_COMPARE(playingSpy.size(), 0);
+ QTRY_COMPARE(pausedSpy.size(), 0);
obj->setProperty("playing", false);
obj->setProperty("paused", true);
QTRY_VERIFY(!obj->isPlaying());
QTRY_VERIFY(obj->isPaused());
- QTRY_COMPARE(playingSpy.count(), 1);
- QTRY_COMPARE(pausedSpy.count(), 1);
+ QTRY_COMPARE(playingSpy.size(), 1);
+ QTRY_COMPARE(pausedSpy.size(), 1);
obj->setProperty("playing", true);
obj->setProperty("paused", false);
QTRY_VERIFY(obj->isPlaying());
QTRY_VERIFY(!obj->isPaused());
- QTRY_COMPARE(playingSpy.count(), 2);
- QTRY_COMPARE(pausedSpy.count(), 2);
+ QTRY_COMPARE(playingSpy.size(), 2);
+ QTRY_COMPARE(pausedSpy.size(), 2);
ctxt->setContextProperty("srcImage", testFileUrl("stickman.gif"));
QTRY_VERIFY(obj->isPlaying());
QTRY_VERIFY(!obj->isPaused());
- QTRY_COMPARE(playingSpy.count(), 2);
- QTRY_COMPARE(pausedSpy.count(), 2);
+ QTRY_COMPARE(playingSpy.size(), 2);
+ QTRY_COMPARE(pausedSpy.size(), 2);
obj->setProperty("paused", true);
QTRY_VERIFY(obj->isPlaying());
QTRY_VERIFY(obj->isPaused());
- QTRY_COMPARE(playingSpy.count(), 2);
- QTRY_COMPARE(pausedSpy.count(), 3);
+ QTRY_COMPARE(playingSpy.size(), 2);
+ QTRY_COMPARE(pausedSpy.size(), 3);
obj->setProperty("playing", false);
QTRY_VERIFY(!obj->isPlaying());
QTRY_VERIFY(!obj->isPaused());
- QTRY_COMPARE(playingSpy.count(), 3);
- QTRY_COMPARE(pausedSpy.count(), 4);
+ QTRY_COMPARE(playingSpy.size(), 3);
+ QTRY_COMPARE(pausedSpy.size(), 4);
obj->setProperty("playing", true);
@@ -572,8 +555,8 @@ void tst_qquickanimatedimage::playingAndPausedChanges()
ctxt->setContextProperty("srcImage", testFileUrl("green.png"));
QTRY_VERIFY(!obj->isPlaying());
QTRY_VERIFY(!obj->isPaused());
- QTRY_COMPARE(playingSpy.count(), 5);
- QTRY_COMPARE(pausedSpy.count(), 4);
+ QTRY_COMPARE(playingSpy.size(), 5);
+ QTRY_COMPARE(pausedSpy.size(), 4);
delete obj;
}
@@ -651,19 +634,49 @@ void tst_qquickanimatedimage::currentFrame()
anim->setCurrentFrame(1);
QCOMPARE(anim->currentFrame(), 1);
- QCOMPARE(frameChangedSpy.count(), 1);
- QCOMPARE(currentFrameChangedSpy.count(), 1);
+ QCOMPARE(frameChangedSpy.size(), 1);
+ QCOMPARE(currentFrameChangedSpy.size(), 1);
QCOMPARE(anim->property("currentFrameChangeCount"), 1);
QCOMPARE(anim->property("frameChangeCount"), 1);
evaluate<void>(anim, "scriptedSetCurrentFrame(2)");
QCOMPARE(anim->currentFrame(), 2);
- QCOMPARE(frameChangedSpy.count(), 2);
- QCOMPARE(currentFrameChangedSpy.count(), 2);
+ QCOMPARE(frameChangedSpy.size(), 2);
+ QCOMPARE(currentFrameChangedSpy.size(), 2);
QCOMPARE(anim->property("currentFrameChangeCount"), 2);
QCOMPARE(anim->property("frameChangeCount"), 2);
}
+void tst_qquickanimatedimage::qtbug_120555()
+{
+ TestHTTPServer server;
+ QVERIFY2(server.listen(), qPrintable(server.errorString()));
+ server.serveDirectory(dataDirectory());
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick 2.0\nAnimatedImage {}", {});
+
+ QQuickAnimatedImage *anim = qobject_cast<QQuickAnimatedImage*>(component.create());
+ QVERIFY(anim);
+
+ anim->setSource(server.url("/stickman.gif"));
+ QTRY_COMPARE(anim->status(), QQuickImage::Loading);
+
+ anim->setFillMode(QQuickImage::PreserveAspectFit);
+ QCOMPARE(anim->fillMode(), QQuickImage::PreserveAspectFit);
+ anim->setMipmap(true);
+ QCOMPARE(anim->mipmap(), true);
+ anim->setCache(false);
+ QCOMPARE(anim->cache(), false);
+ anim->setSourceSize(QSize(200, 200));
+ QCOMPARE(anim->sourceSize(), QSize(200, 200));
+
+ QTRY_COMPARE(anim->status(), QQuickImage::Ready);
+
+ delete anim;
+}
+
QTEST_MAIN(tst_qquickanimatedimage)
#include "tst_qquickanimatedimage.moc"
diff --git a/tests/auto/quick/qquickanimatedsprite/BLACKLIST b/tests/auto/quick/qquickanimatedsprite/BLACKLIST
index 7eb242876a..720ef7a275 100644
--- a/tests/auto/quick/qquickanimatedsprite/BLACKLIST
+++ b/tests/auto/quick/qquickanimatedsprite/BLACKLIST
@@ -1,3 +1,7 @@
# QTBUG-65613
[test_largeAnimation]
b2qt
+
+# QTBUG-103260
+[test_finishBehavior]
+android
diff --git a/tests/auto/quick/qquickanimatedsprite/CMakeLists.txt b/tests/auto/quick/qquickanimatedsprite/CMakeLists.txt
index 9e20d712e6..36117df988 100644
--- a/tests/auto/quick/qquickanimatedsprite/CMakeLists.txt
+++ b/tests/auto/quick/qquickanimatedsprite/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickanimatedsprite.pro.
#####################################################################
## tst_qquickanimatedsprite Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickanimatedsprite LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,11 +21,8 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickanimatedsprite
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickanimatedsprite.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
@@ -24,6 +30,7 @@ qt_internal_add_test(tst_qquickanimatedsprite
Qt::QmlPrivate
Qt::QuickPrivate
Qt::QuickTest
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,10 +42,10 @@ qt_internal_add_test(tst_qquickanimatedsprite
qt_internal_extend_target(tst_qquickanimatedsprite CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickanimatedsprite CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickanimatedsprite/data/basic.qml b/tests/auto/quick/qquickanimatedsprite/data/basic.qml
index c332fc7bcc..a6564a8983 100644
--- a/tests/auto/quick/qquickanimatedsprite/data/basic.qml
+++ b/tests/auto/quick/qquickanimatedsprite/data/basic.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickanimatedsprite/data/frameChange.qml b/tests/auto/quick/qquickanimatedsprite/data/frameChange.qml
index e97428b172..dbbbc222b3 100644
--- a/tests/auto/quick/qquickanimatedsprite/data/frameChange.qml
+++ b/tests/auto/quick/qquickanimatedsprite/data/frameChange.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickanimatedsprite/data/infiniteLoops.qml b/tests/auto/quick/qquickanimatedsprite/data/infiniteLoops.qml
index 551329a457..2771716774 100644
--- a/tests/auto/quick/qquickanimatedsprite/data/infiniteLoops.qml
+++ b/tests/auto/quick/qquickanimatedsprite/data/infiniteLoops.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickanimatedsprite/data/largeAnimation.qml b/tests/auto/quick/qquickanimatedsprite/data/largeAnimation.qml
index 3b501ae787..bfff9c9d29 100644
--- a/tests/auto/quick/qquickanimatedsprite/data/largeAnimation.qml
+++ b/tests/auto/quick/qquickanimatedsprite/data/largeAnimation.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickanimatedsprite/data/runningChange.qml b/tests/auto/quick/qquickanimatedsprite/data/runningChange.qml
index 74e7d3d191..7c746cae91 100644
--- a/tests/auto/quick/qquickanimatedsprite/data/runningChange.qml
+++ b/tests/auto/quick/qquickanimatedsprite/data/runningChange.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Tasuku Suzuki <stasuku@gmail.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Tasuku Suzuki <stasuku@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickanimatedsprite/data/sourceSwitch.qml b/tests/auto/quick/qquickanimatedsprite/data/sourceSwitch.qml
index c81a765c7e..319579d2e1 100644
--- a/tests/auto/quick/qquickanimatedsprite/data/sourceSwitch.qml
+++ b/tests/auto/quick/qquickanimatedsprite/data/sourceSwitch.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.4
diff --git a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp
index 7a56c370d5..f7ed660f88 100644
--- a/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp
+++ b/tests/auto/quick/qquickanimatedsprite/tst_qquickanimatedsprite.cpp
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtQuick/qquickview.h>
#include <QtQuickTest/QtQuickTest>
#include <private/qabstractanimation_p.h>
@@ -42,7 +17,7 @@ class tst_qquickanimatedsprite : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickanimatedsprite(){}
+ tst_qquickanimatedsprite() : QQmlDataTest(QT_QMLTEST_DATADIR) {}
private slots:
void initTestCase() override;
@@ -88,7 +63,7 @@ void tst_qquickanimatedsprite::test_properties()
sprite->setRunning(false);
QVERIFY(!sprite->running());
// The finished() signal shouldn't be emitted when running is manually set to false.
- QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(finishedSpy.size(), 0);
sprite->setInterpolate(false);
QVERIFY(!sprite->interpolate());
}
@@ -112,11 +87,11 @@ void tst_qquickanimatedsprite::test_runningChangedSignal()
QVERIFY(finishedSpy.isValid());
sprite->setRunning(true);
- QTRY_COMPARE(runningChangedSpy.count(), 1);
- QCOMPARE(finishedSpy.count(), 0);
+ QTRY_COMPARE(runningChangedSpy.size(), 1);
+ QCOMPARE(finishedSpy.size(), 0);
QTRY_VERIFY(!sprite->running());
- QTRY_COMPARE(runningChangedSpy.count(), 2);
- QCOMPARE(finishedSpy.count(), 1);
+ QTRY_COMPARE(runningChangedSpy.size(), 2);
+ QCOMPARE(finishedSpy.size(), 1);
}
void tst_qquickanimatedsprite::test_startStop()
@@ -139,12 +114,12 @@ void tst_qquickanimatedsprite::test_startStop()
sprite->start();
QVERIFY(sprite->running());
- QTRY_COMPARE(runningChangedSpy.count(), 1);
- QCOMPARE(finishedSpy.count(), 0);
+ QTRY_COMPARE(runningChangedSpy.size(), 1);
+ QCOMPARE(finishedSpy.size(), 0);
sprite->stop();
QVERIFY(!sprite->running());
- QTRY_COMPARE(runningChangedSpy.count(), 2);
- QCOMPARE(finishedSpy.count(), 0);
+ QTRY_COMPARE(runningChangedSpy.size(), 2);
+ QCOMPARE(finishedSpy.size(), 0);
sprite->setCurrentFrame(2);
sprite->start();
@@ -179,12 +154,12 @@ void tst_qquickanimatedsprite::test_frameChangedSignal()
QVERIFY(!sprite->paused());
QCOMPARE(sprite->loops(), 3);
QCOMPARE(sprite->frameCount(), 6);
- QCOMPARE(frameChangedSpy.count(), 0);
+ QCOMPARE(frameChangedSpy.size(), 0);
frameChangedSpy.clear();
sprite->setRunning(true);
QTRY_VERIFY(!sprite->running());
- QCOMPARE(frameChangedSpy.count(), 3*6 + 1);
+ QCOMPARE(frameChangedSpy.size(), 3*6 + 1);
int prevFrame = -1;
int loopCounter = 0;
@@ -220,7 +195,7 @@ public:
{
}
- QPixmap requestPixmap(const QString &/*id*/, QSize *size, const QSize &requestedSize)
+ QPixmap requestPixmap(const QString &/*id*/, QSize *size, const QSize &requestedSize) override
{
if (requestedSize.isValid())
qWarning() << "requestPixmap called with requestedSize of" << requestedSize;
@@ -282,7 +257,7 @@ void tst_qquickanimatedsprite::test_largeAnimation()
sprite->setRunning(true);
QTRY_VERIFY_WITH_TIMEOUT(!sprite->running(), 100000 /* make sure we wait until its done*/ );
if (frameSync)
- QVERIFY(isWithinRange(3*40, int(frameChangedSpy.count()), 3*40 + 1));
+ QVERIFY(isWithinRange(3*40, int(frameChangedSpy.size()), 3*40 + 1));
int prevFrame = -1;
int loopCounter = 0;
int maxFrame = 0;
@@ -321,7 +296,7 @@ void tst_qquickanimatedsprite::test_reparenting()
// don't crash (QTBUG-51162)
sprite->polish();
QVERIFY(QQuickTest::qIsPolishScheduled(sprite));
- QVERIFY(QQuickTest::qWaitForItemPolished(sprite));
+ QVERIFY(QQuickTest::qWaitForPolish(sprite));
}
class KillerThread : public QThread
@@ -329,9 +304,26 @@ class KillerThread : public QThread
Q_OBJECT
protected:
void run() override {
- sleep(3);
- qFatal("Either the GUI or the render thread is stuck in an infinite loop.");
+ QMutexLocker lock(&abortMutex);
+ if (!aborted)
+ abortWaitCondition.wait(&abortMutex, 3000);
+
+ if (!aborted)
+ qFatal("Either the GUI or the render thread is stuck in an infinite loop.");
+ }
+
+public:
+ void abort()
+ {
+ QMutexLocker lock(&abortMutex);
+ aborted = true;
+ abortWaitCondition.wakeAll();
}
+
+private:
+ QMutex abortMutex;
+ QWaitCondition abortWaitCondition;
+ bool aborted = false;
};
// Regression test for QTBUG-53937
@@ -356,7 +348,7 @@ void tst_qquickanimatedsprite::test_changeSourceToSmallerImgKeepingBigFrameSize(
// If we reach this point it's because we didn't hit QTBUG-53937
- killer->terminate();
+ killer->abort();
killer->wait();
}
@@ -383,8 +375,8 @@ void tst_qquickanimatedsprite::test_implicitSize()
QVERIFY(frameImplicitWidthChangedSpy.isValid());
sprite->setFrameWidth(20);
- QCOMPARE(frameWidthChangedSpy.count(), 1);
- QCOMPARE(frameImplicitWidthChangedSpy.count(), 1);
+ QCOMPARE(frameWidthChangedSpy.size(), 1);
+ QCOMPARE(frameImplicitWidthChangedSpy.size(), 1);
// Ensure that implicitHeight matches frameHeight.
QSignalSpy frameHeightChangedSpy(sprite, SIGNAL(frameHeightChanged(int)));
@@ -394,8 +386,8 @@ void tst_qquickanimatedsprite::test_implicitSize()
QVERIFY(frameImplicitHeightChangedSpy.isValid());
sprite->setFrameHeight(20);
- QCOMPARE(frameHeightChangedSpy.count(), 1);
- QCOMPARE(frameImplicitHeightChangedSpy.count(), 1);
+ QCOMPARE(frameHeightChangedSpy.size(), 1);
+ QCOMPARE(frameImplicitHeightChangedSpy.size(), 1);
}
void tst_qquickanimatedsprite::test_infiniteLoops()
@@ -417,7 +409,7 @@ void tst_qquickanimatedsprite::test_infiniteLoops()
// The finished() signal shouldn't be emitted for infinite animations.
const int previousFrame = sprite->currentFrame();
QTRY_VERIFY(sprite->currentFrame() != previousFrame);
- QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(finishedSpy.size(), 0);
}
void tst_qquickanimatedsprite::test_finishBehavior()
diff --git a/tests/auto/quick/qquickanimationcontroller/CMakeLists.txt b/tests/auto/quick/qquickanimationcontroller/CMakeLists.txt
index ffe59c805e..44c3e4d797 100644
--- a/tests/auto/quick/qquickanimationcontroller/CMakeLists.txt
+++ b/tests/auto/quick/qquickanimationcontroller/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickanimationcontroller.pro.
#####################################################################
## tst_qquickanimationcontroller Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickanimationcontroller LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -15,7 +24,7 @@ qt_internal_add_test(tst_qquickanimationcontroller
QMLTEST
SOURCES
tst_qquickanimationcontroller.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/quick/qquickanimationcontroller/tst_qquickanimationcontroller.cpp b/tests/auto/quick/qquickanimationcontroller/tst_qquickanimationcontroller.cpp
index 466d6d29d0..41b3ae2ac7 100644
--- a/tests/auto/quick/qquickanimationcontroller/tst_qquickanimationcontroller.cpp
+++ b/tests/auto/quick/qquickanimationcontroller/tst_qquickanimationcontroller.cpp
@@ -1,29 +1,4 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtQuickTest/quicktest.h>
QUICK_TEST_MAIN(qquickanimationcontroller)
diff --git a/tests/auto/quick/qquickanimations/BLACKLIST b/tests/auto/quick/qquickanimations/BLACKLIST
index 53db13385e..3c54790f47 100644
--- a/tests/auto/quick/qquickanimations/BLACKLIST
+++ b/tests/auto/quick/qquickanimations/BLACKLIST
@@ -1,4 +1,18 @@
+# QTBUG-82015
[simplePath]
macos ci
+# QTBUG-85624
[reparent]
macos ci
+
+#QTBUG-98516
+[pathTransition]
+macos ci
+
+#QTBUG-98516
+[opacityAnimationFromZero]
+macos ci
+
+# QTBUG-104107
+[frameAnimation2]
+macos ci
diff --git a/tests/auto/quick/qquickanimations/CMakeLists.txt b/tests/auto/quick/qquickanimations/CMakeLists.txt
index 203fa770fb..1b6b0b84a5 100644
--- a/tests/auto/quick/qquickanimations/CMakeLists.txt
+++ b/tests/auto/quick/qquickanimations/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickanimations.pro.
#####################################################################
## tst_qquickanimations Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickanimations LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,19 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickanimations
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickanimations.cpp
- DEFINES
- QT_DISABLE_DEPRECATED_BEFORE=0
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlModelsPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -36,10 +41,10 @@ qt_internal_add_test(tst_qquickanimations
qt_internal_extend_target(tst_qquickanimations CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickanimations CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickanimations/data/animationJobSelfDestructionBug.qml b/tests/auto/quick/qquickanimations/data/animationJobSelfDestructionBug.qml
index 259871785b..a9123427d5 100644
--- a/tests/auto/quick/qquickanimations/data/animationJobSelfDestructionBug.qml
+++ b/tests/auto/quick/qquickanimations/data/animationJobSelfDestructionBug.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.11
import QtQuick.Window 2.11
diff --git a/tests/auto/quick/qquickanimations/data/animatorInvalidTargetCrash.qml b/tests/auto/quick/qquickanimations/data/animatorInvalidTargetCrash.qml
index b8c237feab..c69dc2a065 100644
--- a/tests/auto/quick/qquickanimations/data/animatorInvalidTargetCrash.qml
+++ b/tests/auto/quick/qquickanimations/data/animatorInvalidTargetCrash.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.3
import QtQuick.Window 2.2
diff --git a/tests/auto/quick/qquickanimations/data/changePropertiesDuringAnimation.qml b/tests/auto/quick/qquickanimations/data/changePropertiesDuringAnimation.qml
new file mode 100644
index 0000000000..322bd9c0e4
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/changePropertiesDuringAnimation.qml
@@ -0,0 +1,31 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Window 2.2
+
+Rectangle {
+ id: root
+ width: 200
+ height: 200
+ visible: true
+
+ property alias rect: rect
+ property alias numberAnimation: numberAnimation
+ property alias loops: numberAnimation.loops
+
+ Rectangle {
+ id: rect
+ width: 100
+ height: 10
+ color: "tomato"
+
+ NumberAnimation on x {
+ id: numberAnimation
+ from: -rect.width
+ to: root.width
+ duration: 60
+ easing.type: Easing.Linear
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickanimations/data/cleanupWhenRenderThreadStops.qml b/tests/auto/quick/qquickanimations/data/cleanupWhenRenderThreadStops.qml
new file mode 100644
index 0000000000..4cfb59aeab
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/cleanupWhenRenderThreadStops.qml
@@ -0,0 +1,32 @@
+//main.qml
+
+import QtQuick 2.12
+import QtQuick.Window 2.12
+
+Item {
+ id: root
+ width: 640
+ height: 480
+ visible: true
+ property bool running : false
+
+ Rectangle {
+ id: rect
+ anchors.fill: parent
+ color: "red"
+
+ Component.onCompleted: {
+ anim.start()
+ running = true
+ }
+ }
+
+ OpacityAnimator {
+ id: anim
+
+ target: rect
+ from: 1
+ to: 0
+ duration: 20000
+ }
+}
diff --git a/tests/auto/quick/qquickanimations/data/fastFlickingBug.qml b/tests/auto/quick/qquickanimations/data/fastFlickingBug.qml
index b2649a801b..1c653f59d2 100644
--- a/tests/auto/quick/qquickanimations/data/fastFlickingBug.qml
+++ b/tests/auto/quick/qquickanimations/data/fastFlickingBug.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtCore module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.11
import QtQuick.Window 2.11
diff --git a/tests/auto/quick/qquickanimations/data/finished.qml b/tests/auto/quick/qquickanimations/data/finished.qml
index a18b321501..ba74a77ce4 100644
--- a/tests/auto/quick/qquickanimations/data/finished.qml
+++ b/tests/auto/quick/qquickanimations/data/finished.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/qquickanimations/data/frameAnimation.qml b/tests/auto/quick/qquickanimations/data/frameAnimation.qml
new file mode 100644
index 0000000000..6ed305db60
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/frameAnimation.qml
@@ -0,0 +1,22 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Rectangle {
+ id: root
+ width: 200
+ height: 200
+ visible: true
+
+ property alias frameAnimation: frameAnimation
+
+ FrameAnimation {
+ id: frameAnimation
+ onTriggered: {
+ // Pause when we reach the frame 3
+ if (currentFrame === 3)
+ pause();
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickanimations/data/infiniteAnimationWithoutFrom.qml b/tests/auto/quick/qquickanimations/data/infiniteAnimationWithoutFrom.qml
new file mode 100644
index 0000000000..21051e030e
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/infiniteAnimationWithoutFrom.qml
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.0
+
+Item {
+ width: 100
+ height: 100
+
+ // note that 'from' property is missing
+ NumberAnimation {
+ objectName: "anim"
+ to: from+360
+ loops: Animation.Infinite
+ target: rect
+ properties: "rotation"
+ duration: 100
+ }
+
+ Rectangle {
+ objectName: "rect"
+ id: rect
+ width: 30
+ height: 10
+ color: "red"
+ anchors.centerIn: parent
+ transformOrigin: Item.Center
+ }
+}
diff --git a/tests/auto/quick/qquickanimations/data/restartAnimationGroupWhenDirty.qml b/tests/auto/quick/qquickanimations/data/restartAnimationGroupWhenDirty.qml
new file mode 100644
index 0000000000..aec1cec432
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/restartAnimationGroupWhenDirty.qml
@@ -0,0 +1,92 @@
+import QtQuick
+
+Rectangle {
+ width: 300
+ height: 300
+
+ // test SequentialAnimation
+ Rectangle {
+ id: line0
+ y: 100
+ width: parent.width
+ height: 2
+ color: "blue"
+ }
+ Rectangle {
+ id: target0
+ objectName: "target0"
+ y: 100
+ anchors.verticalCenter: line0.verticalCenter
+ height: line0.height * 5
+ width: height
+ color: "red"
+ radius: height/2
+
+ property bool onFinishedCalled : false;
+
+ SequentialAnimation {
+ id: seqAnim0
+ objectName: "seqAnim0"
+ loops: 2
+ running: true
+ NumberAnimation {
+ id: anim0
+ target: target0
+ property: "x"
+ from: 0
+ to: 50
+ duration: 500
+ }
+ Component.onCompleted: anim0.to = 290
+ onFinished: target0.onFinishedCalled = true
+ }
+ }
+
+ // test ParallelAnimation
+ Rectangle {
+ id: line1
+ y: 200
+ width: parent.width
+ height: 2
+ color: "blue"
+ }
+ Rectangle {
+ id: target1
+ objectName: "target1"
+ anchors.verticalCenter: line1.verticalCenter
+ height: line1.height * 5
+ width: height
+ color: "yellow"
+ radius: height/2
+
+ property bool onFinishedCalled : false;
+
+ ParallelAnimation {
+ id: parAnim0
+ objectName: "parAnim0"
+ loops: 2
+ running: true
+ NumberAnimation {
+ id: anim1
+ target: target1
+ property: "x"
+ from: 0
+ to: 50
+ duration: 500
+ }
+ Component.onCompleted: anim1.to = 290
+ onFinished: target1.onFinishedCalled = true
+ }
+ }
+
+ Timer {
+ interval: 400
+ running: true
+ onTriggered: {
+ seqAnim0.pause()
+ parAnim0.pause()
+ anim0.to = 140
+ anim1.to = 140
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickanimations/data/restartNestedAnimationGroupWhenDirty.qml b/tests/auto/quick/qquickanimations/data/restartNestedAnimationGroupWhenDirty.qml
new file mode 100644
index 0000000000..da0de96448
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/restartNestedAnimationGroupWhenDirty.qml
@@ -0,0 +1,96 @@
+import QtQuick
+
+Rectangle {
+ width: 300
+ height: 300
+
+ // test ParallelAnimation in SequentialAnimation
+ Rectangle {
+ id: line0
+ y: 100
+ width: parent.width
+ height: 2
+ color: "blue"
+ }
+ Rectangle {
+ id: target0
+ objectName: "target0"
+ y: 100
+ anchors.verticalCenter: line0.verticalCenter
+ height: line0.height * 5
+ width: height
+ color: "red"
+ radius: height/2
+
+ property bool onFinishedCalled : false;
+
+ SequentialAnimation {
+ id: seqAnim0
+ objectName: "seqAnim0"
+ loops: 2
+ running: true
+ ParallelAnimation {
+ NumberAnimation {
+ id: anim0
+ target: target0
+ property: "x"
+ from: 0
+ to: 50
+ duration: 500
+ }
+ }
+ Component.onCompleted: anim0.to = 290
+ onFinished: target0.onFinishedCalled = true
+ }
+ }
+
+ // test SequentialAnimation in ParallelAnimation
+ Rectangle {
+ id: line1
+ y: 200
+ width: parent.width
+ height: 2
+ color: "blue"
+ }
+ Rectangle {
+ id: target1
+ objectName: "target1"
+ anchors.verticalCenter: line1.verticalCenter
+ height: line1.height * 5
+ width: height
+ color: "yellow"
+ radius: height/2
+
+ property bool onFinishedCalled : false;
+
+ ParallelAnimation {
+ id: parAnim0
+ objectName: "parAnim0"
+ loops: 2
+ running: true
+ SequentialAnimation {
+ NumberAnimation {
+ id: anim1
+ target: target1
+ property: "x"
+ from: 0
+ to: 50
+ duration: 500
+ }
+ }
+ Component.onCompleted: anim1.to = 290
+ onFinished: target1.onFinishedCalled = true
+ }
+ }
+
+ Timer {
+ interval: 400
+ running: true
+ onTriggered: {
+ seqAnim0.pause()
+ parAnim0.pause()
+ anim0.to = 140
+ anim1.to = 140
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickanimations/data/scriptActionCrash.qml b/tests/auto/quick/qquickanimations/data/scriptActionCrash.qml
index 8479e76038..ace63918d8 100644
--- a/tests/auto/quick/qquickanimations/data/scriptActionCrash.qml
+++ b/tests/auto/quick/qquickanimations/data/scriptActionCrash.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Jolla Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickanimations/data/targetsDeletedWithoutRemoval.qml b/tests/auto/quick/qquickanimations/data/targetsDeletedWithoutRemoval.qml
new file mode 100644
index 0000000000..e31caa1905
--- /dev/null
+++ b/tests/auto/quick/qquickanimations/data/targetsDeletedWithoutRemoval.qml
@@ -0,0 +1,29 @@
+import QtQuick
+
+Item {
+ id: root
+
+ property list<Translate> targets
+ property alias animTargets: animation.targets
+
+ Component {
+ id: trComponent
+ Translate {}
+ }
+
+ Component.onCompleted: {
+ const target = trComponent.createObject(this);
+ targets.push(target);
+ target.destroy();
+ // give event loop some time to actually stop the animation and destroy the target
+ Qt.callLater(animation.start);
+ }
+
+ NumberAnimation {
+ id: animation
+ targets: root.targets
+ property: "x"
+ running: false
+ to: 100
+ }
+}
diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
index 53216da5b7..25c8559ed3 100644
--- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
+++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
@@ -41,18 +16,19 @@
#include <QtQuick/private/qquickpathinterpolator_p.h>
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquicklistview_p.h>
+#include <QtQuick/private/qquickframeanimation_p.h>
#include <QEasingCurve>
#include <limits.h>
#include <math.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
class tst_qquickanimations : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickanimations() {}
+ tst_qquickanimations() : QQmlDataTest(QT_QMLTEST_DATADIR) {}
private slots:
void initTestCase() override
@@ -116,6 +92,15 @@ private slots:
void fastFlickingBug();
void opacityAnimationFromZero();
void alwaysRunToEndInSequentialAnimationBug();
+ void cleanupWhenRenderThreadStops();
+ void changePropertiesDuringAnimation_data();
+ void changePropertiesDuringAnimation();
+ void infiniteLoopsWithoutFrom();
+ void frameAnimation1();
+ void frameAnimation2();
+ void restartAnimationGroupWhenDirty();
+ void restartNestedAnimationGroupWhenDirty();
+ void targetsDeletedNotRemoved();
};
#define QTIMED_COMPARE(lhs, rhs) do { \
@@ -139,8 +124,8 @@ void tst_qquickanimations::simpleProperty()
QCOMPARE(animation.target(), &rect);
QCOMPARE(animation.property(), QLatin1String("x"));
QCOMPARE(animation.to().toReal(), 200.0);
- QCOMPARE(fromChangedSpy.count(), 0);
- QCOMPARE(toChangedSpy.count(), 1);
+ QCOMPARE(fromChangedSpy.size(), 0);
+ QCOMPARE(toChangedSpy.size(), 1);
animation.start();
QVERIFY(animation.isRunning());
QTest::qWait(animation.duration());
@@ -155,8 +140,8 @@ void tst_qquickanimations::simpleProperty()
QCOMPARE(animation.currentTime(), 125);
QCOMPARE(rect.x(),100.0);
animation.setFrom(100);
- QCOMPARE(fromChangedSpy.count(), 1);
- QCOMPARE(toChangedSpy.count(), 1);
+ QCOMPARE(fromChangedSpy.size(), 1);
+ QCOMPARE(toChangedSpy.size(), 1);
}
void tst_qquickanimations::simpleNumber()
@@ -171,8 +156,8 @@ void tst_qquickanimations::simpleNumber()
QCOMPARE(animation.target(), &rect);
QCOMPARE(animation.property(), QLatin1String("x"));
QCOMPARE(animation.to(), qreal(200));
- QCOMPARE(fromChangedSpy.count(), 0);
- QCOMPARE(toChangedSpy.count(), 1);
+ QCOMPARE(fromChangedSpy.size(), 0);
+ QCOMPARE(toChangedSpy.size(), 1);
animation.start();
QVERIFY(animation.isRunning());
QTest::qWait(animation.duration());
@@ -187,8 +172,8 @@ void tst_qquickanimations::simpleNumber()
QCOMPARE(animation.currentTime(), 125);
QCOMPARE(rect.x(), qreal(100));
animation.setFrom(100);
- QCOMPARE(fromChangedSpy.count(), 1);
- QCOMPARE(toChangedSpy.count(), 1);
+ QCOMPARE(fromChangedSpy.size(), 1);
+ QCOMPARE(toChangedSpy.size(), 1);
}
void tst_qquickanimations::simpleColor()
@@ -203,8 +188,8 @@ void tst_qquickanimations::simpleColor()
QCOMPARE(animation.target(), &rect);
QCOMPARE(animation.property(), QLatin1String("color"));
QCOMPARE(animation.to(), QColor("red"));
- QCOMPARE(fromChangedSpy.count(), 0);
- QCOMPARE(toChangedSpy.count(), 1);
+ QCOMPARE(fromChangedSpy.size(), 0);
+ QCOMPARE(toChangedSpy.size(), 1);
animation.start();
QVERIFY(animation.isRunning());
QTest::qWait(animation.duration());
@@ -217,18 +202,18 @@ void tst_qquickanimations::simpleColor()
QVERIFY(animation.isPaused());
animation.setCurrentTime(125);
QCOMPARE(animation.currentTime(), 125);
- QCOMPARE(rect.color(), QColor::fromRgbF(0.498039, 0, 0.498039, 1));
+ QCOMPARE(rect.color(), QColor::fromRgbF(0.498039f, 0, 0.498039f, 1));
rect.setColor(QColor("green"));
animation.setFrom(QColor("blue"));
QCOMPARE(animation.from(), QColor("blue"));
- QCOMPARE(fromChangedSpy.count(), 1);
- QCOMPARE(toChangedSpy.count(), 1);
+ QCOMPARE(fromChangedSpy.size(), 1);
+ QCOMPARE(toChangedSpy.size(), 1);
animation.restart();
QCOMPARE(rect.color(), QColor("blue"));
QVERIFY(animation.isRunning());
animation.setCurrentTime(125);
- QCOMPARE(rect.color(), QColor::fromRgbF(0.498039, 0, 0.498039, 1));
+ QCOMPARE(rect.color(), QColor::fromRgbF(0.498039f, 0, 0.498039f, 1));
}
void tst_qquickanimations::simpleRotation()
@@ -244,8 +229,8 @@ void tst_qquickanimations::simpleRotation()
QCOMPARE(animation.property(), QLatin1String("rotation"));
QCOMPARE(animation.to(), qreal(270));
QCOMPARE(animation.direction(), QQuickRotationAnimation::Numerical);
- QCOMPARE(fromChangedSpy.count(), 0);
- QCOMPARE(toChangedSpy.count(), 1);
+ QCOMPARE(fromChangedSpy.size(), 0);
+ QCOMPARE(toChangedSpy.size(), 1);
animation.start();
QVERIFY(animation.isRunning());
QTest::qWait(animation.duration());
@@ -260,8 +245,8 @@ void tst_qquickanimations::simpleRotation()
QCOMPARE(animation.currentTime(), 125);
QCOMPARE(rect.rotation(), qreal(135));
animation.setFrom(90);
- QCOMPARE(fromChangedSpy.count(), 1);
- QCOMPARE(toChangedSpy.count(), 1);
+ QCOMPARE(fromChangedSpy.size(), 1);
+ QCOMPARE(toChangedSpy.size(), 1);
}
void tst_qquickanimations::simplePath()
@@ -685,11 +670,11 @@ void tst_qquickanimations::resume()
QSignalSpy spy(&animation, SIGNAL(pausedChanged(bool)));
animation.pause();
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QVERIFY(animation.isPaused());
animation.stop();
QVERIFY(!animation.isPaused());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
// Load QtQuick to ensure that QQuickPropertyAnimation is registered as PropertyAnimation
{
@@ -701,12 +686,12 @@ void tst_qquickanimations::resume()
QByteArray message = "<Unknown File>: QML PropertyAnimation: setPaused() cannot be used when animation isn't running.";
QTest::ignoreMessage(QtWarningMsg, message);
animation.pause();
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
QVERIFY(!animation.isPaused());
animation.resume();
QVERIFY(!animation.isPaused());
QVERIFY(!animation.isRunning());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
void tst_qquickanimations::dotProperty()
@@ -745,7 +730,7 @@ void tst_qquickanimations::badTypes()
QScopedPointer<QObject> obj(c.create());
QVERIFY(obj.isNull());
- QCOMPARE(c.errors().count(), 1);
+ QCOMPARE(c.errors().size(), 1);
QCOMPARE(c.errors().at(0).description(), QLatin1String("Invalid property assignment: number expected"));
}
@@ -757,7 +742,7 @@ void tst_qquickanimations::badTypes()
QScopedPointer<QObject> obj(c.create());
QVERIFY(obj.isNull());
- QCOMPARE(c.errors().count(), 1);
+ QCOMPARE(c.errors().size(), 1);
QCOMPARE(c.errors().at(0).description(), QLatin1String("Invalid property assignment: color expected"));
}
@@ -1065,12 +1050,12 @@ void tst_qquickanimations::disabledTransition()
QSignalSpy runningSpy(trans, SIGNAL(runningChanged()));
QQuickItemPrivate::get(rect)->setState("");
QCOMPARE(myRect->x(),qreal(200));
- QCOMPARE(runningSpy.count(), 1); //stopped -> running
+ QCOMPARE(runningSpy.size(), 1); //stopped -> running
QVERIFY(trans->running());
QTest::qWait(300);
QTIMED_COMPARE(myRect->x(),qreal(100));
QVERIFY(!trans->running());
- QCOMPARE(runningSpy.count(), 2); //running -> stopped
+ QCOMPARE(runningSpy.size(), 2); //running -> stopped
}
void tst_qquickanimations::invalidDuration()
@@ -1244,7 +1229,7 @@ void tst_qquickanimations::easingProperties()
QVERIFY(animObject != nullptr);
QCOMPARE(animObject->easing().type(), QEasingCurve::BezierSpline);
QVector<QPointF> points = animObject->easing().toCubicSpline();
- QCOMPARE(points.count(), 3);
+ QCOMPARE(points.size(), 3);
QCOMPARE(points.at(0), QPointF(0.5, 0.2));
QCOMPARE(points.at(1), QPointF(0.13, 0.65));
QCOMPARE(points.at(2), QPointF(1.0, 1.0));
@@ -1373,7 +1358,7 @@ void tst_qquickanimations::signalOrder()
colorAnimation->setDuration(duration);
animation->start();
- QTRY_VERIFY(finishedSpy.count());
+ QTRY_VERIFY(finishedSpy.size());
QCOMPARE(actualSignalOrder, expectedSignalOrder);
}
@@ -1696,7 +1681,7 @@ void tst_qquickanimations::unsetAnimatorProxyJobWindow()
item.setParentItem(&dummy);
QSignalSpy spy(&window, SIGNAL(sceneGraphInitialized()));
window.show();
- if (spy.count() < 1)
+ if (spy.size() < 1)
spy.wait();
QCOMPARE(proxy.job().data(), job);
}
@@ -1723,8 +1708,8 @@ void tst_qquickanimations::finished()
QVERIFY(finishedSpy.isValid());
QVERIFY(simpleTopLevelAnimation->setProperty("running", QVariant(true)));
- QTRY_COMPARE(stoppedSpy.count(), 1);
- QCOMPARE(finishedSpy.count(), 1);
+ QTRY_COMPARE(stoppedSpy.size(), 1);
+ QCOMPARE(finishedSpy.size(), 1);
// Test that the signal is properly revisioned and hence accessible from QML.
QCOMPARE(root->property("finishedUsableInQml").toBool(), true);
@@ -1751,9 +1736,9 @@ void tst_qquickanimations::finished()
QObject *transitionRect = root->property("transitionRect").value<QObject*>();
QVERIFY(transitionRect);
QVERIFY(transitionRect->setProperty("state", QVariant(QLatin1String("go"))));
- QTRY_COMPARE(runningChangedSpy.count(), 1);
- QCOMPARE(stoppedSpy.count(), 0);
- QCOMPARE(finishedSpy.count(), 0);
+ QTRY_COMPARE(runningChangedSpy.size(), 1);
+ QCOMPARE(stoppedSpy.size(), 0);
+ QCOMPARE(finishedSpy.size(), 0);
}
// Test that finished() is not emitted for animations within a Behavior.
@@ -1770,8 +1755,8 @@ void tst_qquickanimations::finished()
QVERIFY(root->setProperty("bar", QVariant(1.0)));
QTRY_COMPARE(root->property("bar").toReal(), 1.0);
- QCOMPARE(stoppedSpy.count(), 0);
- QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(stoppedSpy.size(), 0);
+ QCOMPARE(finishedSpy.size(), 0);
}
}
@@ -1862,9 +1847,8 @@ void tst_qquickanimations::fastFlickingBug()
void tst_qquickanimations::opacityAnimationFromZero()
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms");
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
// not easy to verify this in threaded render loop
// since it's difficult to capture the first frame when scene graph
@@ -1898,7 +1882,7 @@ void tst_qquickanimations::opacityAnimationFromZero()
void tst_qquickanimations::alwaysRunToEndInSequentialAnimationBug()
{
- QQuickView view(QUrl::fromLocalFile("data/alwaysRunToEndInSequentialAnimationBug.qml"));
+ QQuickView view(testFileUrl("alwaysRunToEndInSequentialAnimationBug.qml"));
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
@@ -1998,6 +1982,319 @@ void tst_qquickanimations::alwaysRunToEndInSequentialAnimationBug()
QCOMPARE(whiteRect->property("opacity").value<qreal>(),1.0);
}
+void tst_qquickanimations::cleanupWhenRenderThreadStops()
+{
+ QQuickView view(testFileUrl("cleanupWhenRenderThreadStops.qml"));
+ view.show();
+ view.setPersistentGraphics(false);
+ view.setPersistentSceneGraph(false);
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+ QTest::qWait(50);
+ view.hide();
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+}
+
+// This will be called each frame and should return true for the test to pass.
+typedef std::function<bool(QQuickItem *, QString &)> PropertyValidatorFunc;
+Q_DECLARE_METATYPE(PropertyValidatorFunc)
+
+void tst_qquickanimations::changePropertiesDuringAnimation_data()
+{
+ QTest::addColumn<int>("loops");
+ QTest::addColumn<QString>("propertyName");
+ QTest::addColumn<qreal>("newValue");
+ QTest::addColumn<PropertyValidatorFunc>("propertyValidatorFunc");
+
+ // Use a value large enough to ensure that the animation is running for the duration of
+ // the test. We test both infinite and non-infinite loop counts.
+ const int largeLoopCount = 100;
+
+ const auto fromValidator = PropertyValidatorFunc([](QQuickItem *rect, QString &failureMessage){
+ if (rect->x() >= 0)
+ return true;
+ QDebug(&failureMessage) << "Expected x of rect to never go below new \"from\" value of 0, but it's" << rect->x();
+ return false;
+ });
+ QTest::newRow("from") << largeLoopCount << "from" << 0.0 << fromValidator;
+ QTest::newRow("from,infinite") << int(QQuickAbstractAnimation::Infinite) << "from" << 0.0 << fromValidator;
+
+ const auto toValidator = PropertyValidatorFunc([](QQuickItem *rect, QString &failureMessage){
+ if (rect->x() <= 100)
+ return true;
+ QDebug(&failureMessage) << "Expected x of rect to never go above new \"to\" value of 100, but it's" << rect->x();
+ return false;
+ });
+ QTest::newRow("to") << largeLoopCount << "to" << 100.0 << toValidator;
+ QTest::newRow("to,infinite") << int(QQuickAbstractAnimation::Infinite) << "to" << 100.0 << toValidator;
+
+ // Duration and easing.type would be difficult/flaky to test in CI so they're left out here.
+}
+
+// Tests that changing a NumberAnimation's properties while it's running will result
+// in those changes being picked up on the next loop. This is new behavior introduced
+// in Qt 6.4.
+void tst_qquickanimations::changePropertiesDuringAnimation()
+{
+ QFETCH(int, loops);
+ QFETCH(QString, propertyName);
+ QFETCH(qreal, newValue);
+ QFETCH(PropertyValidatorFunc, propertyValidatorFunc);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("changePropertiesDuringAnimation.qml"));
+ QScopedPointer<QQuickItem> rootItem(qobject_cast<QQuickItem*>(component.createWithInitialProperties({{ "loops", loops }})));
+ QVERIFY2(!component.isError(), qPrintable(component.errorString()));
+
+ auto numberAnimation = rootItem->property("numberAnimation").value<QQuickNumberAnimation*>();
+ QVERIFY(numberAnimation);
+ QCOMPARE(numberAnimation->from(), -100);
+ QCOMPARE(numberAnimation->to(), rootItem->width());
+
+ // Start the animation.
+ numberAnimation->start();
+ QVERIFY(numberAnimation->isRunning());
+
+ int loopCountBeforeModification = 0;
+ // Ensure that it's past the first loop so that we can check that it resumes
+ // from that loop after "restarting".
+ QTRY_VERIFY(numberAnimation->qtAnimation()->currentLoop() >= 1);
+ loopCountBeforeModification = numberAnimation->qtAnimation()->currentLoop();
+
+ QSignalSpy startedSpy(numberAnimation, SIGNAL(started()));
+ QVERIFY(startedSpy.isValid());
+ QSignalSpy stoppedSpy(numberAnimation, SIGNAL(stopped()));
+ QVERIFY(stoppedSpy.isValid());
+
+ // Modify the property.
+ // QQuickPropertyAnimation has a setProperty function of its own, and we don't want to call it, hence the cast.
+ QVERIFY(static_cast<QObject*>(numberAnimation)->setProperty(propertyName.toLatin1().constData(), QVariant(newValue)));
+
+ // Make sure we've reached the end of the animation.
+ auto rect = rootItem->property("rect").value<QQuickItem*>();
+ QVERIFY(rect);
+ // Ensure that we've passed the loop on which we modified the property, while also checking
+ // that currentLoop never gets reset to 0. We can't just use QTRY_VERIFY
+ // for this, because it could start at 0 and then pass loopCountBeforeModification;
+ // we need to ensure that it never goes below loopCountBeforeModification.
+ while (numberAnimation->qtAnimation()->currentLoop() < loopCountBeforeModification + 1) {
+ QVERIFY2(numberAnimation->qtAnimation()->currentLoop() >= loopCountBeforeModification,
+ qPrintable(QString::fromLatin1("Expected currentLoop to be larger than %1, but it's %2")
+ .arg(loopCountBeforeModification).arg(numberAnimation->qtAnimation()->currentLoop())));
+ QTest::qWait(0);
+ }
+
+ // Now that we know the modification should have been taken into account,
+ // check that the animated property never gets set to a value that we wouldn't expect after the change.
+ const int previousLoop = numberAnimation->qtAnimation()->currentLoop();
+ QString failureMessage;
+ while (numberAnimation->qtAnimation()->currentLoop() < previousLoop + 1) {
+ if (!propertyValidatorFunc(rect, failureMessage))
+ QFAIL(qPrintable(failureMessage));
+ QTest::qWait(0);
+ }
+
+ // The started and stopped signals should not be emitted when adapting to changes
+ // mid-animation.
+ if (loops != QQuickAbstractAnimation::Infinite)
+ QVERIFY(numberAnimation->qtAnimation()->currentLoop() < numberAnimation->loops());
+ QCOMPARE(startedSpy.size(), 0);
+ QCOMPARE(stoppedSpy.size(), 0);
+}
+
+void tst_qquickanimations::infiniteLoopsWithoutFrom()
+{
+ // This test checks QTBUG-84375
+ QQuickView view(testFileUrl("infiniteAnimationWithoutFrom.qml"));
+ view.show();
+
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+ QVERIFY(view.rootObject());
+
+ QObject *root = view.rootObject();
+ QQuickAbstractAnimation *animation = root->findChild<QQuickAbstractAnimation *>("anim");
+ QVERIFY(animation);
+ QQuickRectangle *rectangle = root->findChild<QQuickRectangle *>("rect");
+ QVERIFY(rectangle);
+
+ qreal prevRotation = rectangle->rotation();
+ int numsCrossedZero = 0;
+ connect(rectangle, &QQuickRectangle::rotationChanged, this, [&]() {
+ const auto rotation = rectangle->rotation();
+ // We take a large range of (180; 360] here, because the animation in
+ // the test runs for a short time, and so there can be huge gaps between
+ // rotation values.
+ const bool prevRotationOldLoop = prevRotation > 180.0 && prevRotation <= 360.0;
+ const bool currRotationNewLoop = rotation >= 0.0 && rotation <= 180.0;
+ if (prevRotationOldLoop && currRotationNewLoop)
+ numsCrossedZero++;
+ prevRotation = rotation;
+ });
+
+ // The logic in lamdba function above requires at least two positions in
+ // a rotation animation - one in [0; 180] range, and another in (180; 360]
+ // range
+ animation->start();
+ animation->pause();
+ QCOMPARE(numsCrossedZero, 0);
+ animation->setCurrentTime(40);
+ animation->setCurrentTime(90);
+ QCOMPARE(numsCrossedZero, 0);
+ animation->setCurrentTime(140);
+ animation->setCurrentTime(190);
+ QCOMPARE(numsCrossedZero, 1);
+ animation->setCurrentTime(240);
+ animation->setCurrentTime(290);
+ QCOMPARE(numsCrossedZero, 2);
+
+ animation->stop();
+}
+
+void tst_qquickanimations::frameAnimation1()
+{
+ QQuickFrameAnimation frameAnimation;
+ QVERIFY(!frameAnimation.isRunning());
+ QVERIFY(!frameAnimation.isPaused());
+ QCOMPARE(frameAnimation.currentFrame(), 0);
+ QCOMPARE(frameAnimation.frameTime(), 0);
+ QCOMPARE(frameAnimation.smoothFrameTime(), 0);
+ QCOMPARE(frameAnimation.elapsedTime(), 0);
+
+ frameAnimation.start();
+ QVERIFY(frameAnimation.isRunning());
+ QVERIFY(!frameAnimation.isPaused());
+ frameAnimation.pause();
+ QVERIFY(frameAnimation.isRunning());
+ QVERIFY(frameAnimation.isPaused());
+ frameAnimation.resume();
+ QVERIFY(frameAnimation.isRunning());
+ QVERIFY(!frameAnimation.isPaused());
+ frameAnimation.stop();
+ QVERIFY(!frameAnimation.isRunning());
+ QVERIFY(!frameAnimation.isPaused());
+ frameAnimation.restart();
+ QVERIFY(frameAnimation.isRunning());
+ QVERIFY(!frameAnimation.isPaused());
+}
+
+void tst_qquickanimations::frameAnimation2()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("frameAnimation.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ auto *root = qobject_cast<QQuickRectangle*>(obj.data());
+ QVERIFY(root);
+
+ QQuickFrameAnimation *frameAnimation = root->findChild<QQuickFrameAnimation*>();
+ QVERIFY(frameAnimation);
+ QSignalSpy spy(frameAnimation, SIGNAL(triggered()));
+
+ // Start the animation and wait at least 1 frame
+ frameAnimation->start();
+ QVERIFY(frameAnimation->isRunning());
+ QVERIFY(spy.wait(500));
+ QVERIFY(frameAnimation->currentFrame() > 0);
+ QVERIFY(frameAnimation->frameTime() > 0);
+ QVERIFY(frameAnimation->smoothFrameTime() > 0);
+ QVERIFY(frameAnimation->elapsedTime() > 0);
+
+ // Stopping and reseting should return currentFrame back to 0
+ frameAnimation->stop();
+ frameAnimation->reset();
+ QCOMPARE(frameAnimation->currentFrame(), 0);
+
+ // Start and wait so the animation runs into frame 3 and pauses
+ frameAnimation->start();
+ QTRY_VERIFY(frameAnimation->isPaused());
+ QVERIFY(frameAnimation->currentFrame() >= 3);
+
+ // Then resume the animation
+ frameAnimation->resume();
+ QVERIFY(!frameAnimation->isPaused());
+ QVERIFY(spy.wait(500));
+ QVERIFY(frameAnimation->currentFrame() > 3);
+}
+
+//QTBUG-110589
+void tst_qquickanimations::restartAnimationGroupWhenDirty()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("restartAnimationGroupWhenDirty.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ auto *root = qobject_cast<QQuickRectangle*>(obj.data());
+ QVERIFY2(root, qPrintable(c.errorString()));
+
+ QQuickSequentialAnimation *seqAnim0 = root->findChild<QQuickSequentialAnimation*>("seqAnim0");
+ QVERIFY(seqAnim0);
+ QQuickRectangle *target0 = root->findChild<QQuickRectangle*>("target0");
+ QVERIFY(target0);
+ QQuickParallelAnimation *parAnim0 = root->findChild<QQuickParallelAnimation*>("parAnim0");
+ QVERIFY(parAnim0);
+ QQuickRectangle *target1 = root->findChild<QQuickRectangle*>("target1");
+ QVERIFY(target1);
+
+ QTRY_VERIFY(seqAnim0->isPaused());
+ QTRY_VERIFY(parAnim0->isPaused());
+ QTRY_VERIFY(target0->x() > 140);
+ QTRY_VERIFY(target1->x() > 140);
+ seqAnim0->resume();
+ parAnim0->resume();
+ QTRY_VERIFY(target0->property("onFinishedCalled").value<bool>());
+ QTRY_VERIFY(target1->property("onFinishedCalled").value<bool>());
+ QTRY_COMPARE(target0->x(), 140);
+ QTRY_COMPARE(target1->x(), 140);
+}
+
+//QTBUG-95840
+void tst_qquickanimations::restartNestedAnimationGroupWhenDirty()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("restartNestedAnimationGroupWhenDirty.qml"));
+ QScopedPointer<QObject> obj(c.create());
+ auto *root = qobject_cast<QQuickRectangle*>(obj.data());
+ QVERIFY2(root, qPrintable(c.errorString()));
+
+ QQuickSequentialAnimation *seqAnim0 = root->findChild<QQuickSequentialAnimation*>("seqAnim0");
+ QVERIFY(seqAnim0);
+ QQuickRectangle *target0 = root->findChild<QQuickRectangle*>("target0");
+ QVERIFY(target0);
+ QQuickParallelAnimation *parAnim0 = root->findChild<QQuickParallelAnimation*>("parAnim0");
+ QVERIFY(parAnim0);
+ QQuickRectangle *target1 = root->findChild<QQuickRectangle*>("target1");
+ QVERIFY(target1);
+
+ QTRY_VERIFY(seqAnim0->isPaused());
+ QTRY_VERIFY(parAnim0->isPaused());
+ QTRY_VERIFY(target0->x() > 140);
+ QTRY_VERIFY(target1->x() > 140);
+ seqAnim0->resume();
+ parAnim0->resume();
+ QTRY_VERIFY(target0->property("onFinishedCalled").value<bool>());
+ QTRY_VERIFY(target1->property("onFinishedCalled").value<bool>());
+ QTRY_COMPARE(target0->x(), 140);
+ QTRY_COMPARE(target1->x(), 140);
+}
+
+void tst_qquickanimations::targetsDeletedNotRemoved()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("targetsDeletedWithoutRemoval.qml"));
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY2(obj.get(), qPrintable(component.errorString()));
+ {
+ QQmlListReference ref(obj.get(), "targets");
+ QVERIFY(ref.isValid());
+ QCOMPARE(ref.size(), 1);
+ QTRY_COMPARE(ref.at(0), nullptr);
+ }
+ {
+ QQmlListReference ref(obj.get(), "animTargets");
+ QVERIFY(ref.isValid());
+ QCOMPARE(ref.size(), 1);
+ QCOMPARE(ref.at(0), nullptr);
+ }
+}
+
QTEST_MAIN(tst_qquickanimations)
#include "tst_qquickanimations.moc"
diff --git a/tests/auto/quick/qquickanimators/BLACKLIST b/tests/auto/quick/qquickanimators/BLACKLIST
index 019bf71d5e..f0da331c9f 100644
--- a/tests/auto/quick/qquickanimators/BLACKLIST
+++ b/tests/auto/quick/qquickanimators/BLACKLIST
@@ -1,4 +1,4 @@
# QTBUG-89023
[testTransitionsWithImplicitFrom]
-ubuntu-20.04
+ubuntu-22.04
opensuse-leap
diff --git a/tests/auto/quick/qquickanimators/CMakeLists.txt b/tests/auto/quick/qquickanimators/CMakeLists.txt
index 4ad5624f85..4865baa4cf 100644
--- a/tests/auto/quick/qquickanimators/CMakeLists.txt
+++ b/tests/auto/quick/qquickanimators/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickanimators.pro.
#####################################################################
## tst_qquickanimators Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickanimators LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,22 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickanimators
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickanimators.cpp
- DEFINES
- QT_DISABLE_DEPRECATED_BEFORE=0
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -39,10 +40,10 @@ qt_internal_add_test(tst_qquickanimators
qt_internal_extend_target(tst_qquickanimators CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickanimators CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickanimators/data/animatorImplicitFrom.qml b/tests/auto/quick/qquickanimators/data/animatorImplicitFrom.qml
index 2d2ebe2ff8..c291fcfd95 100644
--- a/tests/auto/quick/qquickanimators/data/animatorImplicitFrom.qml
+++ b/tests/auto/quick/qquickanimators/data/animatorImplicitFrom.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/qquickanimators/data/positionerWithAnimator.qml b/tests/auto/quick/qquickanimators/data/positionerWithAnimator.qml
index bd3b42b397..979d7df1d5 100644
--- a/tests/auto/quick/qquickanimators/data/positionerWithAnimator.qml
+++ b/tests/auto/quick/qquickanimators/data/positionerWithAnimator.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/qquickanimators/data/windowWithAnimator.qml b/tests/auto/quick/qquickanimators/data/windowWithAnimator.qml
index bcebffdc91..95b22c3a20 100644
--- a/tests/auto/quick/qquickanimators/data/windowWithAnimator.qml
+++ b/tests/auto/quick/qquickanimators/data/windowWithAnimator.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
import QtQuick.Window 2.0
diff --git a/tests/auto/quick/qquickanimators/tst_qquickanimators.cpp b/tests/auto/quick/qquickanimators/tst_qquickanimators.cpp
index 30a1d5a560..f6bc136422 100644
--- a/tests/auto/quick/qquickanimators/tst_qquickanimators.cpp
+++ b/tests/auto/quick/qquickanimators/tst_qquickanimators.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtQuickTest/quicktest.h>
@@ -37,10 +12,11 @@
#include <QtQuick/private/qquickanimation_p_p.h>
#include <QtQuick/private/qquickitem_p.h>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QQmlComponent>
-using namespace QQuickViewTestUtil;
+using namespace QQuickViewTestUtils;
QT_BEGIN_NAMESPACE
@@ -48,6 +24,9 @@ class tst_Animators: public QQmlDataTest
{
Q_OBJECT
+public:
+ tst_Animators();
+
private slots:
void testMultiWinAnimator_data();
void testMultiWinAnimator();
@@ -55,6 +34,11 @@ private slots:
void testTransitionsWithImplicitFrom();
};
+tst_Animators::tst_Animators()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
void tst_Animators::testMultiWinAnimator_data()
{
QTest::addColumn<int>("count");
diff --git a/tests/auto/quick/qquickapplication/BLACKLIST b/tests/auto/quick/qquickapplication/BLACKLIST
deleted file mode 100644
index 1b7464e7c4..0000000000
--- a/tests/auto/quick/qquickapplication/BLACKLIST
+++ /dev/null
@@ -1,3 +0,0 @@
-[active]
-opensuse-42.3
-opensuse-leap
diff --git a/tests/auto/quick/qquickapplication/CMakeLists.txt b/tests/auto/quick/qquickapplication/CMakeLists.txt
index 53582b4548..25dd31046a 100644
--- a/tests/auto/quick/qquickapplication/CMakeLists.txt
+++ b/tests/auto/quick/qquickapplication/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickapplication.pro.
#####################################################################
## tst_qquickapplication Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickapplication LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,11 +21,8 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickapplication
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickapplication.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
@@ -24,6 +30,7 @@ qt_internal_add_test(tst_qquickapplication
Qt::QmlPrivate
Qt::Quick
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,10 +42,10 @@ qt_internal_add_test(tst_qquickapplication
qt_internal_extend_target(tst_qquickapplication CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickapplication CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
index f5812f56ee..48b9b833d5 100644
--- a/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
+++ b/tests/auto/quick/qquickapplication/tst_qquickapplication.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtQml/qqmlcomponent.h>
@@ -36,7 +11,10 @@
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformintegration.h>
#include <private/qguiapplication_p.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QFont>
+
+using namespace Qt::StringLiterals;
class tst_qquickapplication : public QQmlDataTest
{
@@ -60,6 +38,7 @@ private:
};
tst_qquickapplication::tst_qquickapplication()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
@@ -73,152 +52,180 @@ void tst_qquickapplication::cleanup()
void tst_qquickapplication::active()
{
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0; "
- "Item { "
- " property bool active: Qt.application.active; "
- " property bool active2: false; "
- " Connections { "
- " target: Qt.application; "
- " onActiveChanged: active2 = Qt.application.active; "
- " } "
- "}", QUrl::fromLocalFile(""));
- QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
- QVERIFY(item);
- QQuickWindow window;
- item->setParentItem(window.contentItem());
-
- // If the platform plugin has the ApplicationState capability, app activation originate from it
- // as a result of a system event. We therefore have to simulate these events here.
- if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) {
-
- // Flush pending events, in case the platform have already queued real application state events
- QWindowSystemInterface::flushWindowSystemEvents();
-
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
- QWindowSystemInterface::flushWindowSystemEvents();
- QVERIFY(item->property("active").toBool());
- QVERIFY(item->property("active2").toBool());
-
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
- QWindowSystemInterface::flushWindowSystemEvents();
- QVERIFY(!item->property("active").toBool());
- QVERIFY(!item->property("active2").toBool());
- } else {
- // Otherwise, app activation is triggered by window activation.
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
- QCOMPARE(QGuiApplication::focusWindow(), &window);
- QVERIFY(item->property("active").toBool());
- QVERIFY(item->property("active2").toBool());
-
- // not active again
- QWindowSystemInterface::handleWindowActivated(nullptr);
- QTRY_VERIFY(QGuiApplication::focusWindow() != &window);
- QVERIFY(!item->property("active").toBool());
- QVERIFY(!item->property("active2").toBool());
+ for (const QString &app : { u"Qt.application"_s, u"Application"_s }) {
+ QQmlComponent component(&engine);
+ component.setData(u"import QtQuick 2.0; "
+ "Item { "
+ " property bool active: %1.active; "
+ " property bool active2: false; "
+ " Connections { "
+ " target: %1; "
+ " function onActiveChanged(active) { active2 = %1.active; }"
+ " } "
+ "}"_s.arg(app)
+ .toUtf8(),
+ QUrl::fromLocalFile(""));
+ QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
+ QVERIFY(item);
+ QQuickWindow window;
+ item->setParentItem(window.contentItem());
+
+ // If the platform plugin has the ApplicationState capability, app activation originate from
+ // it as a result of a system event. We therefore have to simulate these events here.
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(
+ QPlatformIntegration::ApplicationState)) {
+
+ // Flush pending events, in case the platform have already queued real application state
+ // events
+ QWindowSystemInterface::flushWindowSystemEvents();
+
+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
+ QWindowSystemInterface::flushWindowSystemEvents();
+ QVERIFY(item->property("active").toBool());
+ QVERIFY(item->property("active2").toBool());
+
+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
+ QWindowSystemInterface::flushWindowSystemEvents();
+ QVERIFY(!item->property("active").toBool());
+ QVERIFY(!item->property("active2").toBool());
+ } else {
+ // Otherwise, app activation is triggered by window activation.
+ window.show();
+ window.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+ QTRY_COMPARE(QGuiApplication::focusWindow(), &window);
+ QVERIFY(item->property("active").toBool());
+ QVERIFY(item->property("active2").toBool());
+
+ // not active again
+ QWindowSystemInterface::handleFocusWindowChanged(nullptr);
+ QTRY_COMPARE_NE(QGuiApplication::focusWindow(), &window);
+ QVERIFY(!item->property("active").toBool());
+ QVERIFY(!item->property("active2").toBool());
+ }
}
}
void tst_qquickapplication::state()
{
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0; "
- "Item { "
- " property int state: Qt.application.state; "
- " property int state2: Qt.ApplicationInactive; "
- " Connections { "
- " target: Qt.application; "
- " onStateChanged: state2 = Qt.application.state; "
- " } "
- " Component.onCompleted: state2 = Qt.application.state; "
- "}", QUrl::fromLocalFile(""));
- QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
- QVERIFY(item);
- QQuickWindow window;
- item->setParentItem(window.contentItem());
-
- // If the platform plugin has the ApplicationState capability, state changes originate from it
- // as a result of a system event. We therefore have to simulate these events here.
- if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) {
-
- // Flush pending events, in case the platform have already queued real application state events
- QWindowSystemInterface::flushWindowSystemEvents();
-
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
- QWindowSystemInterface::flushWindowSystemEvents();
- QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationActive);
- QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationActive);
-
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
- QWindowSystemInterface::flushWindowSystemEvents();
- QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationInactive);
- QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationInactive);
-
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended);
- QWindowSystemInterface::flushWindowSystemEvents();
- QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationSuspended);
- QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationSuspended);
-
- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationHidden);
- QWindowSystemInterface::flushWindowSystemEvents();
- QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationHidden);
- QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationHidden);
-
- } else {
- // Otherwise, the application can only be in two states, Active and Inactive. These are
- // triggered by window activation.
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
- QCOMPARE(QGuiApplication::focusWindow(), &window);
- QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationActive);
- QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationActive);
-
- // not active again
- QWindowSystemInterface::handleWindowActivated(nullptr);
- QTRY_VERIFY(QGuiApplication::focusWindow() != &window);
- QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationInactive);
- QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationInactive);
+ for (const QString &app : { u"Qt.application"_s, u"Application"_s }) {
+ QQmlComponent component(&engine);
+ component.setData(u"import QtQuick 2.0; "
+ "Item { "
+ " property int state: %1.state; "
+ " property int state2: Qt.ApplicationInactive; "
+ " Connections { "
+ " target: %1; "
+ " function onStateChanged(state) { state2 = %1.state; }"
+ " } "
+ " Component.onCompleted: state2 = %1.state; "
+ "}"_s.arg(app)
+ .toUtf8(),
+ QUrl::fromLocalFile(""));
+ QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
+ QVERIFY(item);
+ QQuickWindow window;
+ item->setParentItem(window.contentItem());
+
+ // If the platform plugin has the ApplicationState capability, state changes originate from
+ // it as a result of a system event. We therefore have to simulate these events here.
+ if (QGuiApplicationPrivate::platformIntegration()->hasCapability(
+ QPlatformIntegration::ApplicationState)) {
+
+ // Flush pending events, in case the platform have already queued real application state
+ // events
+ QWindowSystemInterface::flushWindowSystemEvents();
+
+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
+ QWindowSystemInterface::flushWindowSystemEvents();
+ QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationActive);
+ QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationActive);
+
+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
+ QWindowSystemInterface::flushWindowSystemEvents();
+ QCOMPARE(Qt::ApplicationState(item->property("state").toInt()),
+ Qt::ApplicationInactive);
+ QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()),
+ Qt::ApplicationInactive);
+
+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationSuspended);
+ QWindowSystemInterface::flushWindowSystemEvents();
+ QCOMPARE(Qt::ApplicationState(item->property("state").toInt()),
+ Qt::ApplicationSuspended);
+ QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()),
+ Qt::ApplicationSuspended);
+
+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationHidden);
+ QWindowSystemInterface::flushWindowSystemEvents();
+ QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationHidden);
+ QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationHidden);
+
+ } else {
+ // Otherwise, the application can only be in two states, Active and Inactive. These are
+ // triggered by window activation.
+ window.show();
+ window.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+ QTRY_COMPARE(QGuiApplication::focusWindow(), &window);
+ QCOMPARE(Qt::ApplicationState(item->property("state").toInt()), Qt::ApplicationActive);
+ QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()), Qt::ApplicationActive);
+
+ // not active again
+ QWindowSystemInterface::handleFocusWindowChanged(nullptr);
+ QTRY_COMPARE_NE(QGuiApplication::focusWindow(), &window);
+ QCOMPARE(Qt::ApplicationState(item->property("state").toInt()),
+ Qt::ApplicationInactive);
+ QCOMPARE(Qt::ApplicationState(item->property("state2").toInt()),
+ Qt::ApplicationInactive);
+ }
}
}
void tst_qquickapplication::layoutDirection()
{
-
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0; Item { property bool layoutDirection: Qt.application.layoutDirection }", QUrl::fromLocalFile(""));
- QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
- QVERIFY(item);
- QQuickView view;
- item->setParentItem(view.rootObject());
-
- // not mirrored
- QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::LeftToRight);
-
- // mirrored
- QGuiApplication::setLayoutDirection(Qt::RightToLeft);
- QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::RightToLeft);
-
- // not mirrored again
- QGuiApplication::setLayoutDirection(Qt::LeftToRight);
- QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::LeftToRight);
+ for (const QString &app : { u"Qt.application"_s, u"Application"_s }) {
+ QQmlComponent component(&engine);
+ component.setData(
+ u"import QtQuick 2.0; Item { property bool layoutDirection: %1.layoutDirection }"_s
+ .arg(app)
+ .toUtf8(),
+ QUrl::fromLocalFile(""));
+ QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
+ QVERIFY(item);
+ QQuickView view;
+ item->setParentItem(view.rootObject());
+
+ // not mirrored
+ QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::LeftToRight);
+
+ // mirrored
+ QGuiApplication::setLayoutDirection(Qt::RightToLeft);
+ QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::RightToLeft);
+
+ // not mirrored again
+ QGuiApplication::setLayoutDirection(Qt::LeftToRight);
+ QCOMPARE(Qt::LayoutDirection(item->property("layoutDirection").toInt()), Qt::LeftToRight);
+ }
}
void tst_qquickapplication::font()
{
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0; Item { property font defaultFont: Qt.application.font }", QUrl::fromLocalFile(""));
- QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
- QVERIFY(item);
- QQuickView view;
- item->setParentItem(view.rootObject());
-
- QVariant defaultFontProperty = item->property("defaultFont");
- QVERIFY(defaultFontProperty.isValid());
- QCOMPARE(defaultFontProperty.typeId(), QMetaType::QFont);
- QCOMPARE(defaultFontProperty.value<QFont>(), qApp->font());
+ for (const QString &app : { u"Qt.application"_s, u"Application"_s }) {
+ QQmlComponent component(&engine);
+ component.setData(
+ u"import QtQuick 2.0; Item { property font defaultFont: %1.font }"_s.arg(app)
+ .toUtf8(),
+ QUrl::fromLocalFile(""));
+ QQuickItem *item = qobject_cast<QQuickItem *>(component.create());
+ QVERIFY(item);
+ QQuickView view;
+ item->setParentItem(view.rootObject());
+
+ QVariant defaultFontProperty = item->property("defaultFont");
+ QVERIFY(defaultFontProperty.isValid());
+ QCOMPARE(defaultFontProperty.typeId(), QMetaType::QFont);
+ QCOMPARE(defaultFontProperty.value<QFont>(), qApp->font());
+ }
}
void tst_qquickapplication::inputMethod()
diff --git a/tests/auto/quick/qquickbehaviors/CMakeLists.txt b/tests/auto/quick/qquickbehaviors/CMakeLists.txt
index 330df778b6..4c79b376a8 100644
--- a/tests/auto/quick/qquickbehaviors/CMakeLists.txt
+++ b/tests/auto/quick/qquickbehaviors/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickbehaviors.pro.
#####################################################################
## tst_qquickbehaviors Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickbehaviors LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,19 +21,26 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickbehaviors
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickbehaviors.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ bindable.h
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
+set_target_properties(tst_qquickbehaviors PROPERTIES
+ QT_QML_MODULE_VERSION 1.0
+ QT_QML_MODULE_URI test
+)
+
+_qt_internal_qml_type_registration(tst_qquickbehaviors)
+
+
#### Keys ignored in scope 1:.:.:qquickbehaviors.pro:<TRUE>:
# DISTFILES = "data/*"
@@ -33,10 +49,10 @@ qt_internal_add_test(tst_qquickbehaviors
qt_internal_extend_target(tst_qquickbehaviors CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickbehaviors CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickbehaviors/bindable.h b/tests/auto/quick/qquickbehaviors/bindable.h
new file mode 100644
index 0000000000..0eeed6f87a
--- /dev/null
+++ b/tests/auto/quick/qquickbehaviors/bindable.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#ifndef BINDABLE_H
+#define BINDABLE_H
+
+#include <QObject>
+#include <QQuickItem>
+#include <qqmlregistration.h>
+#include <QBindable>
+#include <qproperty.h>
+
+class TestBindable : public QQuickItem
+{
+ Q_OBJECT
+ QML_ELEMENT
+ Q_PROPERTY(int prop READ prop WRITE setProp BINDABLE bindableProp)
+public:
+ int prop() { return m_prop; }
+ void setProp(int i) { m_prop = i; }
+ QBindable<int> bindableProp() { return &m_prop; }
+
+private:
+ QProperty<int> m_prop;
+};
+#endif
diff --git a/tests/auto/quick/qquickbehaviors/data/bindableProperty.qml b/tests/auto/quick/qquickbehaviors/data/bindableProperty.qml
new file mode 100644
index 0000000000..e4d76036aa
--- /dev/null
+++ b/tests/auto/quick/qquickbehaviors/data/bindableProperty.qml
@@ -0,0 +1,12 @@
+import QtQuick
+import test
+
+TestBindable {
+ property int targetValue: 0
+ prop: targetValue
+ property alias enableBehavior: behavior.enabled
+ Behavior on prop {
+ id: behavior
+ NumberAnimation {duration: 100}
+ }
+}
diff --git a/tests/auto/quick/qquickbehaviors/data/defaultQProperty.qml b/tests/auto/quick/qquickbehaviors/data/defaultQProperty.qml
new file mode 100644
index 0000000000..596efac325
--- /dev/null
+++ b/tests/auto/quick/qquickbehaviors/data/defaultQProperty.qml
@@ -0,0 +1,14 @@
+import QtQuick
+
+Item {
+ property int heightChanges: 0
+ property int widthChanges: 0
+ implicitWidth: 50
+ implicitHeight: 50
+ height: { return 0 }
+ width: { return 10 }
+ Behavior on height { NumberAnimation { duration: 300 } }
+ Behavior on width { NumberAnimation { duration: 300 } }
+ onHeightChanged: ++heightChanges
+ onWidthChanged: ++widthChanges
+}
diff --git a/tests/auto/quick/qquickbehaviors/data/duplicated.qml b/tests/auto/quick/qquickbehaviors/data/duplicated.qml
new file mode 100644
index 0000000000..15518a05cf
--- /dev/null
+++ b/tests/auto/quick/qquickbehaviors/data/duplicated.qml
@@ -0,0 +1,31 @@
+import QtQuick 2.0
+Rectangle {
+ id: main
+
+ width: 400
+ height: 400
+
+ property bool behavior1Triggered
+ property bool behavior2Triggered
+
+ Behavior on x {
+ ScriptAction { script: behavior1Triggered = true }
+ }
+ Behavior on x {
+ ScriptAction { script: behavior2Triggered = true }
+ }
+
+ MouseArea {
+ id: clicker
+ anchors.fill: parent
+ }
+
+ states: State {
+ name: "moved"
+ when: clicker.pressed
+ PropertyChanges {
+ target: main
+ x: 200
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickbehaviors/data/qtbug21549-2.qml b/tests/auto/quick/qquickbehaviors/data/qtbug21549-2.qml
index f87febf958..4c3d4a0d26 100644
--- a/tests/auto/quick/qquickbehaviors/data/qtbug21549-2.qml
+++ b/tests/auto/quick/qquickbehaviors/data/qtbug21549-2.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp
index 3b46019f64..e9720130f2 100644
--- a/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp
+++ b/tests/auto/quick/qquickbehaviors/tst_qquickbehaviors.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <qsignalspy.h>
#include <QtQml/qqmlengine.h>
@@ -36,16 +11,17 @@
#include <QtQuick/private/qquickanimation_p.h>
#include <QtQuick/private/qquicksmoothedanimation_p.h>
#include <private/qquickitem_p.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include "bindable.h"
class tst_qquickbehaviors : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickbehaviors() {}
+ tst_qquickbehaviors() : QQmlDataTest(QT_QMLTEST_DATADIR) {}
private slots:
- void init() { qApp->processEvents(); } //work around animation timer bug (QTBUG-22865)
+ void init() override;
void simpleBehavior();
void scriptTriggered();
void cppTriggered();
@@ -57,6 +33,7 @@ private slots:
void group();
void valueType();
void emptyBehavior();
+ void duplicatedBehavior();
void explicitSelection();
void nonSelectingBehavior();
void reassignedAnimation();
@@ -76,8 +53,17 @@ private slots:
void oneWay();
void safeToDelete();
void targetProperty();
+ void bindableProperty();
+ void defaultQProperty();
};
+void tst_qquickbehaviors::init()
+{
+ QQmlDataTest::init();
+ //work around animation timer bug (QTBUG-22865)
+ qApp->processEvents();
+}
+
void tst_qquickbehaviors::simpleBehavior()
{
QQmlEngine engine;
@@ -238,6 +224,20 @@ void tst_qquickbehaviors::emptyBehavior()
QCOMPARE(x, qreal(200)); //should change immediately
}
+void tst_qquickbehaviors::duplicatedBehavior()
+{
+ QTest::failOnWarning(QRegularExpression(".*"));
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg,
+ QRegularExpression("Attempting to set another interceptor on.*"));
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("duplicated.qml"));
+ QScopedPointer<QQuickRectangle> rect(qobject_cast<QQuickRectangle *>(c.create()));
+ QVERIFY2(!rect.isNull(), qPrintable(c.errorString()));
+
+ // Expecting no crash
+ QQuickItemPrivate::get(rect.data())->setState("moved");
+}
+
void tst_qquickbehaviors::explicitSelection()
{
QQmlEngine engine;
@@ -356,7 +356,7 @@ void tst_qquickbehaviors::runningTrue()
QSignalSpy runningSpy(animation, SIGNAL(runningChanged(bool)));
rect->setProperty("myValue", 180);
- QTRY_VERIFY(runningSpy.count() > 0);
+ QTRY_VERIFY(runningSpy.size() > 0);
}
//QTBUG-12295
@@ -594,7 +594,7 @@ void tst_qquickbehaviors::aliasedProperty()
QSignalSpy targetValueSpy(behavior, SIGNAL(targetValueChanged()));
QQuickItemPrivate::get(rect.data())->setState("moved");
QCOMPARE(behavior->targetValue(), 400);
- QCOMPARE(targetValueSpy.count(), 1);
+ QCOMPARE(targetValueSpy.size(), 1);
QScopedPointer<QQuickRectangle> acc(qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("acc")));
QScopedPointer<QQuickRectangle> range(qobject_cast<QQuickRectangle*>(acc->findChild<QQuickRectangle*>("range")));
QTRY_VERIFY(acc->property("value").toDouble() > 0);
@@ -630,7 +630,7 @@ void tst_qquickbehaviors::oneWay()
QQuickRectangle *myRect = qobject_cast<QQuickRectangle*>(rect->findChild<QQuickRectangle*>("MyRectOneWay"));
myRect->setProperty("x", 100);
QCOMPARE(behavior->targetValue(), 100);
- QCOMPARE(targetValueSpy.count(), 1);
+ QCOMPARE(targetValueSpy.size(), 1);
QCOMPARE(behavior->enabled(), false);
qreal x = myRect->x();
QCOMPARE(x, qreal(100)); //should change immediately
@@ -640,7 +640,7 @@ void tst_qquickbehaviors::oneWay()
myRect->setProperty("x", 0);
QCOMPARE(behavior->targetValue(), 0);
- QCOMPARE(targetValueSpy.count(), 2);
+ QCOMPARE(targetValueSpy.size(), 2);
QCOMPARE(behavior->enabled(), true);
QCOMPARE(myAnimation->isRunning(), true);
QVERIFY(myRect->x() > 0.0);
@@ -654,7 +654,8 @@ void tst_qquickbehaviors::safeToDelete()
{
QQmlEngine engine;
QQmlComponent c(&engine, testFileUrl("delete.qml"));
- QVERIFY(c.create());
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(o.data());
}
Q_DECLARE_METATYPE(QQmlProperty)
@@ -678,6 +679,46 @@ void tst_qquickbehaviors::targetProperty()
QCOMPARE(item->property("emptyBehaviorName").toString(), "");
}
+void tst_qquickbehaviors::bindableProperty()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("bindableProperty.qml"));
+ QScopedPointer<QObject> root(c.create());
+ QVERIFY2(root, qPrintable(c.errorString()));
+ auto testBindable = qobject_cast<TestBindable *>(root.get());
+ QVERIFY(testBindable);
+
+ testBindable->setProperty("targetValue", 100);
+ QVERIFY(testBindable->prop() != 100);
+ QTRY_COMPARE(testBindable->prop(), 100);
+
+ testBindable->setProperty("enableBehavior", false);
+ testBindable->setProperty("targetValue", 200);
+ QCOMPARE(testBindable->prop(), 200);
+
+ testBindable->setProperty("enableBehavior", true);
+ testBindable->setProperty("prop", 300); // write through metaobject system gets intercepted
+ QVERIFY(testBindable->prop() != 300);
+ QTRY_COMPARE(testBindable->prop(), 300);
+}
+
+void tst_qquickbehaviors::defaultQProperty()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("defaultQProperty.qml"));
+ QScopedPointer<QObject> root(c.create());
+ QVERIFY2(root, qPrintable(c.errorString()));
+
+ QQuickItem *item = qobject_cast<QQuickItem *>(root.data());
+ QVERIFY(item);
+
+ QCOMPARE(item->height(), 0.0);
+ QCOMPARE(item->width(), 10.0);
+
+ // Both change only once: No intermediate change to 0 on width.
+ QCOMPARE(root->property("heightChanges").toInt(), 1);
+ QCOMPARE(root->property("widthChanges").toInt(), 1);
+}
QTEST_MAIN(tst_qquickbehaviors)
diff --git a/tests/auto/quick/qquickborderimage/BLACKLIST b/tests/auto/quick/qquickborderimage/BLACKLIST
new file mode 100644
index 0000000000..30b72020a4
--- /dev/null
+++ b/tests/auto/quick/qquickborderimage/BLACKLIST
@@ -0,0 +1,7 @@
+# QTBUG-103077
+[mirror]
+android
+[borderImageMesh]
+android
+[multiFrame]
+android
diff --git a/tests/auto/quick/qquickborderimage/CMakeLists.txt b/tests/auto/quick/qquickborderimage/CMakeLists.txt
index 7316588123..5d88680367 100644
--- a/tests/auto/quick/qquickborderimage/CMakeLists.txt
+++ b/tests/auto/quick/qquickborderimage/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickborderimage.pro.
#####################################################################
## tst_qquickborderimage Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickborderimage LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,23 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickborderimage
SOURCES
- ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickborderimage.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -37,10 +38,10 @@ qt_internal_add_test(tst_qquickborderimage
qt_internal_extend_target(tst_qquickborderimage CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickborderimage CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp
index 32b502c6dc..83396c6944 100644
--- a/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp
+++ b/tests/auto/quick/qquickborderimage/tst_qquickborderimage.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QTextDocument>
#include <QTcpServer>
@@ -42,9 +17,9 @@
#include <QtQuick/qquickview.h>
#include <QtQml/qqmlcontext.h>
-#include "../../shared/testhttpserver.h"
-#include "../../shared/util.h"
-#include "../shared/visualtestutil.h"
+#include <QtQuickTestUtils/private/testhttpserver_p.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
@@ -70,6 +45,7 @@ private slots:
void sciSource();
void sciSource_data();
void invalidSciFile();
+ void nonExistingSciFile();
void validSciFiles_data();
void validSciFiles();
void pendingRemoteRequest();
@@ -96,6 +72,7 @@ void tst_qquickborderimage::cleanup()
}
tst_qquickborderimage::tst_qquickborderimage()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
@@ -135,13 +112,6 @@ void tst_qquickborderimage::imageSource()
QFETCH(bool, remote);
QFETCH(QString, error);
-#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
- if (qstrcmp(QTest::currentDataTag(), "remote") == 0
- || qstrcmp(QTest::currentDataTag(), "remote not found") == 0) {
- QSKIP("Remote tests cause occasional hangs in the CI system -- QTBUG-45655");
- }
-#endif
-
TestHTTPServer server;
if (remote) {
QVERIFY2(server.listen(), qPrintable(server.errorString()));
@@ -366,6 +336,21 @@ void tst_qquickborderimage::invalidSciFile()
delete obj;
}
+void tst_qquickborderimage::nonExistingSciFile()
+{
+ const QString componentStr = "import QtQuick 2.0\nBorderImage { source: \"" + testFileUrl("this_file_does_not_exist.sci").toString() +"\"; width: 300; height: 300 }";
+ QQmlComponent component(&engine);
+ component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ std::unique_ptr<QObject> obj(component.create());
+ auto bimage = qobject_cast<QQuickBorderImage *>(obj.get());
+ QVERIFY(bimage != nullptr);
+ QCOMPARE(bimage->width(), 300.);
+ QCOMPARE(bimage->height(), 300.);
+ QCOMPARE(bimage->status(), QQuickImageBase::Error);
+ QCOMPARE(bimage->horizontalTileMode(), QQuickBorderImage::Stretch);
+ QCOMPARE(bimage->verticalTileMode(), QQuickBorderImage::Stretch);
+}
+
void tst_qquickborderimage::validSciFiles_data()
{
QTest::addColumn<QString>("source");
@@ -459,7 +444,7 @@ void tst_qquickborderimage::statusChanges()
if (remote)
server.sendDelayedItem();
QTRY_COMPARE(obj->status(), finalStatus);
- QCOMPARE(spy.count(), emissions);
+ QCOMPARE(spy.size(), emissions);
delete obj;
}
@@ -484,48 +469,48 @@ void tst_qquickborderimage::sourceSizeChanges()
// Local
ctxt->setContextProperty("srcImage", QUrl(""));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Null);
- QTRY_COMPARE(sourceSizeSpy.count(), 0);
+ QTRY_COMPARE(sourceSizeSpy.size(), 0);
ctxt->setContextProperty("srcImage", testFileUrl("heart200.png"));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 1);
+ QTRY_COMPARE(sourceSizeSpy.size(), 1);
ctxt->setContextProperty("srcImage", testFileUrl("heart200.png"));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 1);
+ QTRY_COMPARE(sourceSizeSpy.size(), 1);
ctxt->setContextProperty("srcImage", testFileUrl("heart200_copy.png"));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 1);
+ QTRY_COMPARE(sourceSizeSpy.size(), 1);
ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 2);
+ QTRY_COMPARE(sourceSizeSpy.size(), 2);
ctxt->setContextProperty("srcImage", QUrl(""));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Null);
- QTRY_COMPARE(sourceSizeSpy.count(), 3);
+ QTRY_COMPARE(sourceSizeSpy.size(), 3);
// Remote
ctxt->setContextProperty("srcImage", server.url("/heart200.png"));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 4);
+ QTRY_COMPARE(sourceSizeSpy.size(), 4);
ctxt->setContextProperty("srcImage", server.url("/heart200.png"));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 4);
+ QTRY_COMPARE(sourceSizeSpy.size(), 4);
ctxt->setContextProperty("srcImage", server.url("/heart200_copy.png"));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 4);
+ QTRY_COMPARE(sourceSizeSpy.size(), 4);
ctxt->setContextProperty("srcImage", server.url("/colors.png"));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 5);
+ QTRY_COMPARE(sourceSizeSpy.size(), 5);
ctxt->setContextProperty("srcImage", QUrl(""));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Null);
- QTRY_COMPARE(sourceSizeSpy.count(), 6);
+ QTRY_COMPARE(sourceSizeSpy.size(), 6);
delete obj;
}
@@ -556,17 +541,17 @@ void tst_qquickborderimage::progressAndStatusChanges()
ctxt->setContextProperty("srcImage", testFileUrl("heart200.png"));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Ready);
QTRY_COMPARE(obj->progress(), 1.0);
- QTRY_COMPARE(sourceSpy.count(), 0);
- QTRY_COMPARE(progressSpy.count(), 0);
- QTRY_COMPARE(statusSpy.count(), 0);
+ QTRY_COMPARE(sourceSpy.size(), 0);
+ QTRY_COMPARE(progressSpy.size(), 0);
+ QTRY_COMPARE(statusSpy.size(), 0);
// Loading local file
ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
QTRY_COMPARE(obj->status(), QQuickBorderImage::Ready);
QTRY_COMPARE(obj->progress(), 1.0);
- QTRY_COMPARE(sourceSpy.count(), 1);
- QTRY_COMPARE(progressSpy.count(), 0);
- QTRY_COMPARE(statusSpy.count(), 1);
+ QTRY_COMPARE(sourceSpy.size(), 1);
+ QTRY_COMPARE(progressSpy.size(), 0);
+ QTRY_COMPARE(statusSpy.size(), 1);
// Loading remote file
ctxt->setContextProperty("srcImage", server.url("/heart200.png"));
@@ -574,34 +559,40 @@ void tst_qquickborderimage::progressAndStatusChanges()
QTRY_COMPARE(obj->progress(), 0.0);
QTRY_COMPARE(obj->status(), QQuickBorderImage::Ready);
QTRY_COMPARE(obj->progress(), 1.0);
- QTRY_COMPARE(sourceSpy.count(), 2);
- QTRY_VERIFY(progressSpy.count() > 1);
- QTRY_COMPARE(statusSpy.count(), 3);
+ QTRY_COMPARE(sourceSpy.size(), 2);
+ QTRY_VERIFY(progressSpy.size() > 1);
+ QTRY_COMPARE(statusSpy.size(), 3);
ctxt->setContextProperty("srcImage", "");
QTRY_COMPARE(obj->status(), QQuickBorderImage::Null);
QTRY_COMPARE(obj->progress(), 0.0);
- QTRY_COMPARE(sourceSpy.count(), 3);
- QTRY_VERIFY(progressSpy.count() > 2);
- QTRY_COMPARE(statusSpy.count(), 4);
+ QTRY_COMPARE(sourceSpy.size(), 3);
+ QTRY_VERIFY(progressSpy.size() > 2);
+ QTRY_COMPARE(statusSpy.size(), 4);
delete obj;
}
#if QT_CONFIG(opengl)
void tst_qquickborderimage::borderImageMesh()
{
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
+
QQuickView *window = new QQuickView;
window->setSource(testFileUrl("nonmesh.qml"));
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window));
+ if (window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software)
+ QSKIP("Software backend has no ShaderEffect supported, skipping test");
+
QImage nonmesh = window->grabWindow();
window->setSource(testFileUrl("mesh.qml"));
QImage mesh = window->grabWindow();
QString errorMessage;
- QVERIFY2(QQuickVisualTestUtil::compareImages(mesh, nonmesh, &errorMessage),
+ QVERIFY2(QQuickVisualTestUtils::compareImages(mesh, nonmesh, &errorMessage),
qPrintable(errorMessage));
}
#endif
@@ -617,9 +608,8 @@ void tst_qquickborderimage::multiFrame_data()
void tst_qquickborderimage::multiFrame()
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QFETCH(QString, qmlfile);
QFETCH(bool, asynchronous);
@@ -633,7 +623,7 @@ void tst_qquickborderimage::multiFrame()
if (asynchronous) {
QCOMPARE(image->frameCount(), 0);
QTRY_COMPARE(image->frameCount(), 4);
- QCOMPARE(countSpy.count(), 1);
+ QCOMPARE(countSpy.size(), 1);
} else {
QCOMPARE(image->frameCount(), 4);
}
@@ -655,7 +645,7 @@ void tst_qquickborderimage::multiFrame()
image->setCurrentFrame(1);
QTRY_COMPARE(image->status(), QQuickImageBase::Ready);
- QCOMPARE(currentSpy.count(), 1);
+ QCOMPARE(currentSpy.size(), 1);
QCOMPARE(image->currentFrame(), 1);
contents = view.grabWindow();
// The middle of the second frame looks green, approximately qRgba(0x3a, 0xd2, 0x31, 0xff)
diff --git a/tests/auto/quick/qquickboundaryrule/CMakeLists.txt b/tests/auto/quick/qquickboundaryrule/CMakeLists.txt
index 96395c9956..c969657c3e 100644
--- a/tests/auto/quick/qquickboundaryrule/CMakeLists.txt
+++ b/tests/auto/quick/qquickboundaryrule/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickboundaryrule.pro.
#####################################################################
## tst_qquickboundaryrule Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickboundaryrule LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,22 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickboundaryrule
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickboundaryrule.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Qml
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -36,10 +38,10 @@ qt_internal_add_test(tst_qquickboundaryrule
qt_internal_extend_target(tst_qquickboundaryrule CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickboundaryrule CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp b/tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp
index 75639dba49..c301848b1e 100644
--- a/tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp
+++ b/tests/auto/quick/qquickboundaryrule/tst_qquickboundaryrule.cpp
@@ -1,50 +1,32 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <qsignalspy.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQuick/qquickview.h>
#include <QtQuick/private/qquickdraghandler_p.h>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
class tst_qquickboundaryrule : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickboundaryrule() {}
+ tst_qquickboundaryrule() : QQmlDataTest(QT_QMLTEST_DATADIR) {}
private slots:
- void init() { qApp->processEvents(); } //work around animation timer bug (QTBUG-22865)
+ void init() override;
void dragHandler();
};
+void tst_qquickboundaryrule::init()
+{
+ QQmlDataTest::init();
+ //work around animation timer bug (QTBUG-22865)
+ qApp->processEvents();
+}
+
void tst_qquickboundaryrule::dragHandler()
{
QQuickView window;
@@ -59,6 +41,7 @@ void tst_qquickboundaryrule::dragHandler()
QObject *boundaryRule = target->findChild<QObject *>(QLatin1String("boundaryRule"));
QVERIFY(boundaryRule);
QSignalSpy overshootChangedSpy(boundaryRule, SIGNAL(currentOvershootChanged()));
+ QSignalSpy returnedSpy(boundaryRule, SIGNAL(returnedToBounds()));
QPoint p1(10, 10);
QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p1);
@@ -72,25 +55,26 @@ void tst_qquickboundaryrule::dragHandler()
QVERIFY(ok);
QCOMPARE(boundaryRule->property("peakOvershoot").toReal(&ok), 0);
QVERIFY(ok);
- QCOMPARE(overshootChangedSpy.count(), 0);
+ QCOMPARE(overshootChangedSpy.size(), 0);
// restricted drag: halfway into overshoot
p1 += QPoint(20, 0);
QTest::mouseMove(&window, p1);
QCOMPARE(target->position().x(), 117.5);
QCOMPARE(boundaryRule->property("currentOvershoot").toReal(), 20);
QCOMPARE(boundaryRule->property("peakOvershoot").toReal(), 20);
- QCOMPARE(overshootChangedSpy.count(), 1);
+ QCOMPARE(overshootChangedSpy.size(), 1);
// restricted drag: maximum overshoot
p1 += QPoint(80, 0);
QTest::mouseMove(&window, p1);
QCOMPARE(target->position().x(), 140);
QCOMPARE(boundaryRule->property("currentOvershoot").toReal(), 100);
QCOMPARE(boundaryRule->property("peakOvershoot").toReal(), 100);
- QCOMPARE(overshootChangedSpy.count(), 2);
+ QCOMPARE(overshootChangedSpy.size(), 2);
// release and let it return to bounds
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p1);
QTRY_COMPARE(dragHandler->active(), false);
- QTRY_COMPARE(overshootChangedSpy.count(), 3);
+ QTRY_COMPARE(returnedSpy.size(), 1);
+ QCOMPARE(overshootChangedSpy.size(), 3);
QCOMPARE(boundaryRule->property("currentOvershoot").toReal(&ok), 0);
QVERIFY(ok);
QCOMPARE(boundaryRule->property("peakOvershoot").toReal(&ok), 0);
diff --git a/tests/auto/quick/qquickcanvasitem/BLACKLIST b/tests/auto/quick/qquickcanvasitem/BLACKLIST
index f88c681630..c7245e7633 100644
--- a/tests/auto/quick/qquickcanvasitem/BLACKLIST
+++ b/tests/auto/quick/qquickcanvasitem/BLACKLIST
@@ -6,6 +6,7 @@ macos
windows
macos
# QTBUG-41043
+android
[canvas::test_toDataURL]
*
[fillRect::test_fillRect]
@@ -19,3 +20,7 @@ opensuse-leap
# QTQAINFRA-4127
[canvas::test_extraArgumentsIgnored:text]
ci b2qt 32bit
+
+# QTBUG-100991
+[line::test_cap]
+android
diff --git a/tests/auto/quick/qquickcanvasitem/CMakeLists.txt b/tests/auto/quick/qquickcanvasitem/CMakeLists.txt
index bd9b7a7265..fdc1416a32 100644
--- a/tests/auto/quick/qquickcanvasitem/CMakeLists.txt
+++ b/tests/auto/quick/qquickcanvasitem/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickcanvasitem.pro.
#####################################################################
## tst_qquickcanvasitem Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickcanvasitem LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -15,7 +24,7 @@ qt_internal_add_test(tst_qquickcanvasitem
QMLTEST
SOURCES
tst_qquickcanvasitem.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_arc.qml b/tests/auto/quick/qquickcanvasitem/data/tst_arc.qml
index 33fffd4cb1..00d13f31f4 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_arc.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_arc.qml
@@ -6,6 +6,7 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_angle_1(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -21,6 +22,7 @@ CanvasTestCase {
}
function test_angle_2(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -36,6 +38,7 @@ CanvasTestCase {
}
function test_angle_3(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#0f0';
@@ -53,6 +56,7 @@ CanvasTestCase {
}
function test_angle_4(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -71,6 +75,7 @@ CanvasTestCase {
}
function test_angle_5(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -90,6 +95,7 @@ CanvasTestCase {
function test_angle_6(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -110,6 +116,7 @@ CanvasTestCase {
function test_empty(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -125,6 +132,7 @@ CanvasTestCase {
}
function test_nonempty(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -141,6 +149,7 @@ CanvasTestCase {
}
function test_nonfinite(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -199,6 +208,7 @@ CanvasTestCase {
}
function test_end(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -216,6 +226,7 @@ CanvasTestCase {
}
function test_negative(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -234,6 +245,7 @@ CanvasTestCase {
function test_scale_1(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -270,6 +282,7 @@ CanvasTestCase {
function test_scale_2(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -296,6 +309,7 @@ CanvasTestCase {
function test_selfintersect_1(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -316,6 +330,7 @@ CanvasTestCase {
function test_selfintersect_2(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -340,6 +355,7 @@ CanvasTestCase {
function test_shape_1(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -361,6 +377,7 @@ CanvasTestCase {
function test_shape_2(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -381,6 +398,7 @@ CanvasTestCase {
}
function test_shape_3(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -401,6 +419,7 @@ CanvasTestCase {
function test_shape_4(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -421,6 +440,7 @@ CanvasTestCase {
function test_shape_5(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -441,6 +461,7 @@ CanvasTestCase {
function test_twopie(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -488,6 +509,7 @@ CanvasTestCase {
function test_zero(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_arcto.qml b/tests/auto/quick/qquickcanvasitem/data/tst_arcto.qml
index ef1b7a7b2a..81412d98c9 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_arcto.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_arcto.qml
@@ -7,6 +7,7 @@ CanvasTestCase {
function test_coincide(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -44,6 +45,7 @@ CanvasTestCase {
}
function test_collinear(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -109,6 +111,7 @@ CanvasTestCase {
}
function test_subpath(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -135,6 +138,7 @@ CanvasTestCase {
function test_negative(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -152,6 +156,7 @@ CanvasTestCase {
function test_nonfinite(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -208,6 +213,7 @@ CanvasTestCase {
}
function test_scale(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -237,6 +243,7 @@ CanvasTestCase {
function test_shape(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -348,6 +355,7 @@ CanvasTestCase {
function test_transform(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -374,6 +382,7 @@ CanvasTestCase {
}
function test_zero(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml
index d74df3daa7..e039806f39 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_canvas.qml
@@ -135,6 +135,10 @@ CanvasTestCase {
tryVerify(function() { return c.isImageLoaded(imagePath) })
verify(!c.isImageLoading(imagePath));
verify(!c.isImageError(imagePath));
+ var sizedImagePath = applicationDirPath + "/c2.png";
+ verify(c.save(sizedImagePath, Qt.size(c.width / 2, c.height / 2)));
+ var img = createTemporaryQmlObject("import QtQuick 2.0; Image { source: \"file://" + sizedImagePath + "\" }", c)
+ tryVerify(function() { return img.width === c.width / 2 && img.height === c.height / 2 })
c.destroy();
}
@@ -673,6 +677,8 @@ CanvasTestCase {
function test_implicitlySizedParent() {
var implicitlySizedItem = implicitlySizedComponent.createObject(container);
verify(implicitlySizedItem);
+ tryVerify(() => implicitlySizedItem.canvas)
+ tryVerify(() => implicitlySizedItem.canvas.context)
var xCenter = implicitlySizedItem.width / 2;
var yCenter = implicitlySizedItem.height / 2;
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_colors.qml b/tests/auto/quick/qquickcanvasitem/data/tst_colors.qml
new file mode 100644
index 0000000000..600ebe6cc5
--- /dev/null
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_colors.qml
@@ -0,0 +1,40 @@
+
+import QtQuick 2.0
+import QtTest 1.1
+
+Canvas {
+ id: canvas
+ width: 1
+ height: 1
+ contextType: "2d"
+
+ property var contextInPaint
+
+ SignalSpy {
+ id: contextSpy
+ target: canvas
+ signalName: "contextChanged"
+ }
+
+ onPaint: {
+ contextInPaint = context;
+ }
+
+ TestCase {
+ name: "Colors"
+ when: canvas.available
+
+ function test_colors() {
+ wait(100);
+ compare(contextSpy.count, 1);
+
+ var ctx = canvas.getContext("2d");
+ // QTBUG-47894
+ ctx.strokeStyle = 'hsl(255, 100%, 50%)';
+ var c1 = ctx.strokeStyle.toString();
+ ctx.strokeStyle = 'hsl(320, 100%, 50%)';
+ var c2 = ctx.strokeStyle.toString();
+ verify(c1 !== c2);
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_composite.qml b/tests/auto/quick/qquickcanvasitem/data/tst_composite.qml
index 8a5a52cf1e..4ee24ad437 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_composite.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_composite.qml
@@ -6,6 +6,7 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_clearRect(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -17,6 +18,7 @@ CanvasTestCase {
function test_clip(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
var composites = [ {compsite:"copy"},
{compsite:"destination-atop"},
@@ -47,6 +49,7 @@ CanvasTestCase {
function test_globalAlpha(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
compare(ctx.globalAlpha, 1.0);
@@ -83,6 +86,7 @@ CanvasTestCase {
function test_operation(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.globalCompositeOperation = 'xor';
@@ -137,6 +141,7 @@ CanvasTestCase {
function test_solid(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = Qt.rgba(0, 1, 1, 1.0);
@@ -233,6 +238,7 @@ CanvasTestCase {
}
function test_transparent(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
@@ -330,6 +336,7 @@ CanvasTestCase {
function test_uncovered(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = 'rgba(0, 255, 0, 0.5)';
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_context.qml b/tests/auto/quick/qquickcanvasitem/data/tst_contextFontValidation.qml
index e78ee773d4..89f7b9d369 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_context.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_contextFontValidation.qml
@@ -11,12 +11,6 @@ Canvas {
property var contextInPaint
SignalSpy {
- id: paintedSpy
- target: canvas
- signalName: "paint"
- }
-
- SignalSpy {
id: contextSpy
target: canvas
signalName: "contextChanged"
@@ -26,51 +20,6 @@ Canvas {
contextInPaint = context;
}
- TestCase {
- name: "ContextTypeStored"
- when: windowShown
-
- function test_contextType() {
- compare(canvas.contextType, "2d");
- }
- }
-
- TestCase {
- name: "ContextValidWhenTypePredefined"
- when: canvas.available
-
- function test_context() {
- // Wait for the context to become active
- wait(100);
- compare(contextSpy.count, 1);
-
- // Context is available
- verify(canvas.context)
- }
-
- function test_contextIsConsistent() {
- // Wait for the context to become active
- wait(100);
- compare(contextSpy.count, 1);
-
- // getContext("2d") is the same as the context property
- compare(canvas.getContext("2d"), canvas.context);
- }
-
- function test_paintHadContext() {
- // Make there was a paint signal
- wait(100);
- verify(paintedSpy.count, 1)
-
- // Paint was called with a valid context when contextType is
- // specified
- verify(canvas.contextInPaint)
-
- // paints context was the correct one
- compare(canvas.contextInPaint, canvas.getContext("2d"));
- }
- }
-
// See: http://www.w3.org/TR/css3-fonts/#font-prop
TestCase {
name: "ContextFontValidation"
@@ -184,22 +133,4 @@ Canvas {
}
}
}
-
- TestCase {
- name: "Colors"
- when: canvas.available
-
- function test_colors() {
- wait(100);
- compare(contextSpy.count, 1);
-
- var ctx = canvas.getContext("2d");
- // QTBUG-47894
- ctx.strokeStyle = 'hsl(255, 100%, 50%)';
- var c1 = ctx.strokeStyle.toString();
- ctx.strokeStyle = 'hsl(320, 100%, 50%)';
- var c2 = ctx.strokeStyle.toString();
- verify(c1 !== c2);
- }
- }
}
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_contextTypeStored.qml b/tests/auto/quick/qquickcanvasitem/data/tst_contextTypeStored.qml
new file mode 100644
index 0000000000..ff859c0d4d
--- /dev/null
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_contextTypeStored.qml
@@ -0,0 +1,25 @@
+
+import QtQuick 2.0
+import QtTest 1.1
+
+Canvas {
+ id: canvas
+ width: 1
+ height: 1
+ contextType: "2d"
+
+ property var contextInPaint
+
+ onPaint: {
+ contextInPaint = context;
+ }
+
+ TestCase {
+ name: "ContextTypeStored"
+ when: windowShown
+
+ function test_contextType() {
+ compare(canvas.contextType, "2d");
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_contextValidWhenTypePredefined.qml b/tests/auto/quick/qquickcanvasitem/data/tst_contextValidWhenTypePredefined.qml
new file mode 100644
index 0000000000..1a4aa2ff09
--- /dev/null
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_contextValidWhenTypePredefined.qml
@@ -0,0 +1,64 @@
+
+import QtQuick 2.0
+import QtTest 1.1
+
+Canvas {
+ id: canvas
+ width: 1
+ height: 1
+ contextType: "2d"
+
+ property var contextInPaint
+
+ SignalSpy {
+ id: paintedSpy
+ target: canvas
+ signalName: "paint"
+ }
+
+ SignalSpy {
+ id: contextSpy
+ target: canvas
+ signalName: "contextChanged"
+ }
+
+ onPaint: {
+ contextInPaint = context;
+ }
+
+ TestCase {
+ name: "ContextValidWhenTypePredefined"
+ when: canvas.available
+
+ function test_context() {
+ // Wait for the context to become active
+ wait(100);
+ compare(contextSpy.count, 1);
+
+ // Context is available
+ verify(canvas.context)
+ }
+
+ function test_contextIsConsistent() {
+ // Wait for the context to become active
+ wait(100);
+ compare(contextSpy.count, 1);
+
+ // getContext("2d") is the same as the context property
+ compare(canvas.getContext("2d"), canvas.context);
+ }
+
+ function test_paintHadContext() {
+ // Make there was a paint signal
+ wait(100);
+ verify(paintedSpy.count, 1)
+
+ // Paint was called with a valid context when contextType is
+ // specified
+ verify(canvas.contextInPaint)
+
+ // paints context was the correct one
+ compare(canvas.contextInPaint, canvas.getContext("2d"));
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_fillStyle.qml b/tests/auto/quick/qquickcanvasitem/data/tst_fillStyle.qml
index 58ea6d7f59..9e8c0785c3 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_fillStyle.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_fillStyle.qml
@@ -6,6 +6,7 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_default(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
verify(ctx.fillStyle, "#000000");
@@ -14,6 +15,7 @@ CanvasTestCase {
}
function test_get(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#fa0';
@@ -23,6 +25,7 @@ CanvasTestCase {
}
function test_hex(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -37,6 +40,7 @@ CanvasTestCase {
}
function test_invalid(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#fa0';
@@ -60,6 +64,7 @@ CanvasTestCase {
}
function test_saverestore(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
var old = ctx.fillStyle;
ctx.save();
@@ -75,6 +80,7 @@ CanvasTestCase {
}
function test_namedColor(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = "red";
@@ -91,6 +97,7 @@ CanvasTestCase {
}
function test_rgba(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = "rgb(-100, 300, 255)";
@@ -108,6 +115,7 @@ CanvasTestCase {
function test_hsla(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = "hsla(120, 100%, 50%, 0.499)";
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_fillrect.qml b/tests/auto/quick/qquickcanvasitem/data/tst_fillrect.qml
index ce1c27c6bc..213abdd622 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_fillrect.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_fillrect.qml
@@ -6,6 +6,7 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_fillRect(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.fillStyle = "red";
ctx.fillRect(0, 0, canvas.width, canvas.height);
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_gradient.qml b/tests/auto/quick/qquickcanvasitem/data/tst_gradient.qml
index 7c87d896fb..70e77c8760 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_gradient.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_gradient.qml
@@ -6,6 +6,7 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_basic(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#0f0';
@@ -18,6 +19,7 @@ CanvasTestCase {
function test_interpolate(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -166,6 +168,7 @@ CanvasTestCase {
}
function test_radial(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#0f0';
@@ -788,6 +791,7 @@ CanvasTestCase {
}
function test_linear(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
try { var err = false;
@@ -907,6 +911,7 @@ CanvasTestCase {
}
function test_object(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
var g1 = ctx.createLinearGradient(0, 0, 100, 0);
@@ -978,6 +983,7 @@ CanvasTestCase {
function test_conical(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
var g = ctx.createConicalGradient(10, 10, 50);
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_image.qml b/tests/auto/quick/qquickcanvasitem/data/tst_image.qml
index 1f695d7080..a1eb272cd0 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_image.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_image.qml
@@ -11,12 +11,12 @@ CanvasTestCase {
canvas.loadImage('rgrg-256x256.png');
canvas.loadImage('ggrr-256x256.png');
canvas.loadImage('broken.png');
- while (!canvas.isImageLoaded('green.png'))
- wait(200);
+ tryVerify(function() { return canvas.isImageLoaded('green.png'); })
}
function test_3args(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
ctx.reset();
@@ -35,6 +35,7 @@ CanvasTestCase {
}
function test_5args(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -54,6 +55,7 @@ CanvasTestCase {
}
function test_9args(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -118,6 +120,7 @@ CanvasTestCase {
}
function test_animated(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -125,6 +128,7 @@ CanvasTestCase {
}
function test_clip(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -139,6 +143,7 @@ CanvasTestCase {
}
function test_self(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -170,6 +175,7 @@ CanvasTestCase {
function test_outsidesource(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -207,6 +213,7 @@ CanvasTestCase {
function test_null(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -220,15 +227,18 @@ CanvasTestCase {
function test_url(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
canvas.loadImage(testCase.green);
+ tryVerify(function() { return canvas.isImageLoaded(testCase.green); })
ctx.drawImage(testCase.green, 0, 0);
comparePixel(ctx, 0,0, 0,255,0,255,2);
}
function test_composite(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -241,12 +251,14 @@ CanvasTestCase {
}
function test_path(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
}
function test_transform(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -260,6 +272,7 @@ CanvasTestCase {
function test_imageitem(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -268,6 +281,7 @@ CanvasTestCase {
function test_imageData(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -276,6 +290,7 @@ CanvasTestCase {
function test_wrongtype(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -293,6 +308,7 @@ CanvasTestCase {
function test_nonfinite(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -606,6 +622,7 @@ CanvasTestCase {
function test_negative(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -661,6 +678,7 @@ CanvasTestCase {
function test_canvas(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -684,6 +702,7 @@ CanvasTestCase {
function test_broken(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -694,6 +713,7 @@ CanvasTestCase {
function test_alpha(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
@@ -706,6 +726,7 @@ CanvasTestCase {
}
function test_multiple_painting(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
loadImages(canvas);
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_imagedata.qml b/tests/auto/quick/qquickcanvasitem/data/tst_imagedata.qml
index 76b99a765e..aab7a95589 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_imagedata.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_imagedata.qml
@@ -11,6 +11,7 @@ CanvasTestCase {
skip("ctx.getImageData crashes on offscreen/minimal platforms");
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
var size = 17
ctx.reset();
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_invalidContext.qml b/tests/auto/quick/qquickcanvasitem/data/tst_invalidContext.qml
index dd14aef433..904b0a3405 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_invalidContext.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_invalidContext.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.4
import QtTest 1.1
@@ -53,16 +28,16 @@ Item {
anchors.fill: parent
property var paintContext: null
- function paint() {
+ function doPaint() {
paintContext.fillStyle = Qt.rgba(1, 0, 0, 1);
paintContext.fillRect(0, 0, width, height);
- requestAnimationFrame(paint);
+ requestAnimationFrame(doPaint);
}
onAvailableChanged: {
if (available) {
paintContext = getContext("2d")
- requestAnimationFrame(paint);
+ requestAnimationFrame(doPaint);
}
}
}
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_line.qml b/tests/auto/quick/qquickcanvasitem/data/tst_line.qml
index dc960a24d0..e5d03e5db7 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_line.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_line.qml
@@ -6,6 +6,7 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_default(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
compare(ctx.lineWidth, 1);
@@ -16,6 +17,7 @@ CanvasTestCase {
function test_cross(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#0f0';
@@ -43,6 +45,7 @@ CanvasTestCase {
function test_join(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -306,6 +309,7 @@ CanvasTestCase {
}
function test_miter(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -481,6 +485,7 @@ CanvasTestCase {
}
function test_width(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#0f0';
@@ -621,7 +626,11 @@ CanvasTestCase {
}
function test_cap(row) {
+ if (Qt.platform.os === "android")
+ skip("line::test_cap crashes on Android, QTBUG-103257")
+
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -838,6 +847,7 @@ CanvasTestCase {
function test_lineDash(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.strokeStyle = "#fff";
@@ -894,8 +904,41 @@ CanvasTestCase {
comparePixel(ctx, 39,0, 0,0,0,0);
}
+ function test_lineDashReset(row) {
+ var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
+ var ctx = canvas.getContext('2d');
+ ctx.reset();
+ ctx.strokeStyle = "#ff0000";
+ ctx.lineWidth = 2;
+ var pattern = [2, 3, 5, 1, 6, 3]
+ ctx.setLineDash(pattern)
+
+ compare(ctx.getLineDash(), pattern);
+
+ pattern = []
+ ctx.setLineDash(pattern)
+ compare(ctx.getLineDash(), pattern);
+
+ ctx.beginPath();
+ ctx.moveTo(0, 0);
+ ctx.lineTo(40, 0);
+ ctx.stroke();
+
+ comparePixel(ctx, 0,0, 255,0,0,255);
+ comparePixel(ctx, 4,0, 255,0,0,255);
+ comparePixel(ctx, 5,0, 255,0,0,255);
+ comparePixel(ctx, 14,0, 255,0,0,255);
+ comparePixel(ctx, 20,0, 255,0,0,255);
+ comparePixel(ctx, 21,0, 255,0,0,255);
+ comparePixel(ctx, 22,0, 255,0,0,255);
+ comparePixel(ctx, 34,0, 255,0,0,255);
+ comparePixel(ctx, 35,0, 255,0,0,255);
+ }
+
function test_lineDashOffset(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.strokeStyle = "#fff";
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_path.qml b/tests/auto/quick/qquickcanvasitem/data/tst_path.qml
index 60c782c8fa..ae08b58519 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_path.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_path.qml
@@ -6,6 +6,7 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_basic(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#0f0';
@@ -36,6 +37,7 @@ CanvasTestCase {
}
function test_beginPath(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#0f0';
ctx.fillRect(0, 0, 100, 50);
@@ -48,6 +50,7 @@ CanvasTestCase {
}
function test_closePath(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#0f0';
@@ -86,6 +89,7 @@ CanvasTestCase {
function test_isPointInPath(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.arc(50, 25, 10, 0, Math.PI, false);
@@ -256,6 +260,7 @@ CanvasTestCase {
function test_fill(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -378,6 +383,7 @@ CanvasTestCase {
}
function test_stroke(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#0f0';
@@ -662,6 +668,7 @@ CanvasTestCase {
}
function test_clip(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -784,6 +791,7 @@ CanvasTestCase {
function test_moveTo(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -839,6 +847,7 @@ CanvasTestCase {
}
function test_lineTo(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -904,6 +913,7 @@ CanvasTestCase {
}
function test_bezierCurveTo(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -1072,6 +1082,7 @@ CanvasTestCase {
}
function test_quadraticCurveTo(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -1173,6 +1184,7 @@ CanvasTestCase {
}
function test_rect(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -1371,6 +1383,7 @@ CanvasTestCase {
function test_clearRect(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#0f0';
@@ -1383,6 +1396,7 @@ CanvasTestCase {
}
function test_fillRect(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.beginPath();
@@ -1397,6 +1411,7 @@ CanvasTestCase {
function test_strokeRect(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.beginPath();
@@ -1412,6 +1427,7 @@ CanvasTestCase {
}
function test_transform(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_pattern.qml b/tests/auto/quick/qquickcanvasitem/data/tst_pattern.qml
index 1d7fd2c12f..e0a4d7ad23 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_pattern.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_pattern.qml
@@ -6,36 +6,42 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_basic(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_animated(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_image(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_modified(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_paint(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_repeat(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_pixel.qml b/tests/auto/quick/qquickcanvasitem/data/tst_pixel.qml
index 281264ba92..ef908db92a 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_pixel.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_pixel.qml
@@ -7,6 +7,7 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_createImageData(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
var imageData = ctx.createImageData(1, 1);
var imageDataValues = imageData.data;
@@ -20,24 +21,28 @@ CanvasTestCase {
}
function test_getImageData(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_object(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_putImageData(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_filters(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_shadow.qml b/tests/auto/quick/qquickcanvasitem/data/tst_shadow.qml
index 2baaa072d0..14318b3f56 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_shadow.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_shadow.qml
@@ -6,12 +6,14 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_basic(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_blur(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
@@ -19,6 +21,7 @@ CanvasTestCase {
function test_clip(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
@@ -26,6 +29,7 @@ CanvasTestCase {
function test_composite(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
@@ -33,6 +37,7 @@ CanvasTestCase {
function test_enable(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
@@ -40,36 +45,42 @@ CanvasTestCase {
function test_gradient(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_image(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_offset(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_pattern(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_stroke(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_tranform(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_state.qml b/tests/auto/quick/qquickcanvasitem/data/tst_state.qml
index 18464def7c..ce02f9d7f7 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_state.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_state.qml
@@ -6,6 +6,7 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_bitmap(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -19,6 +20,7 @@ CanvasTestCase {
}
function test_clip(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -35,6 +37,7 @@ CanvasTestCase {
}
function test_fillStyle(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
// Test that restore() undoes any modifications
@@ -56,6 +59,7 @@ CanvasTestCase {
}
function test_font(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -78,6 +82,7 @@ CanvasTestCase {
}
function test_globalAlpha(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -100,6 +105,7 @@ CanvasTestCase {
}
function test_globalCompositeOperation(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -122,6 +128,7 @@ CanvasTestCase {
}
function test_lineCap(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -144,6 +151,7 @@ CanvasTestCase {
}
function test_lineJoin(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -166,6 +174,7 @@ CanvasTestCase {
}
function test_lineWidth(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -188,6 +197,7 @@ CanvasTestCase {
}
function test_miterLimit(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -210,6 +220,7 @@ CanvasTestCase {
}
function test_path(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -225,6 +236,7 @@ CanvasTestCase {
}
function test_shadow(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -295,6 +307,7 @@ CanvasTestCase {
}
function test_stack(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -330,6 +343,7 @@ CanvasTestCase {
}
function test_strokeStyle(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -353,6 +367,7 @@ CanvasTestCase {
function test_text(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -392,6 +407,7 @@ CanvasTestCase {
function test_transform(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_strokeStyle.qml b/tests/auto/quick/qquickcanvasitem/data/tst_strokeStyle.qml
index a3f1ab0a9b..0dc39b8b4c 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_strokeStyle.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_strokeStyle.qml
@@ -8,6 +8,7 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_default(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
compare(ctx.strokeStyle, "#000000")
@@ -17,6 +18,7 @@ CanvasTestCase {
}
function test_saverestore(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
var old = ctx.strokeStyle;
ctx.save();
@@ -33,6 +35,7 @@ CanvasTestCase {
}
function test_namedColor(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.strokeStyle = "red";
@@ -50,6 +53,7 @@ CanvasTestCase {
}
function test_colorFromObjectToString(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -68,6 +72,7 @@ CanvasTestCase {
}
function test_withInvalidColor(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_svgpath.qml b/tests/auto/quick/qquickcanvasitem/data/tst_svgpath.qml
index 2b39357bed..011fbd497b 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_svgpath.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_svgpath.qml
@@ -6,6 +6,7 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_svgpath(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
var svgs = [
// Absolute coordinates, explicit commands.
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_text.qml b/tests/auto/quick/qquickcanvasitem/data/tst_text.qml
index bfc4067040..f7cd66890b 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_text.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_text.qml
@@ -6,36 +6,42 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_baseLine(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_align(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_stroke(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_fill(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_font(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
}
function test_measure(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
canvas.destroy()
diff --git a/tests/auto/quick/qquickcanvasitem/data/tst_transform.qml b/tests/auto/quick/qquickcanvasitem/data/tst_transform.qml
index b2f5b51fa5..bbfec6a106 100644
--- a/tests/auto/quick/qquickcanvasitem/data/tst_transform.qml
+++ b/tests/auto/quick/qquickcanvasitem/data/tst_transform.qml
@@ -6,6 +6,7 @@ CanvasTestCase {
function init_data() { return testData("2d"); }
function test_order(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -20,6 +21,7 @@ CanvasTestCase {
}
function test_rotate(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -90,6 +92,7 @@ CanvasTestCase {
}
function test_scale(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
@@ -182,6 +185,7 @@ CanvasTestCase {
}
function test_setTransform(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -325,6 +329,7 @@ CanvasTestCase {
}
function test_transform(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
@@ -460,6 +465,7 @@ CanvasTestCase {
}
function test_translate(row) {
var canvas = createCanvasObject(row);
+ tryVerify(function() { return canvas.available; });
var ctx = canvas.getContext('2d');
ctx.reset();
ctx.fillStyle = '#f00';
diff --git a/tests/auto/quick/qquickcanvasitem/tst_qquickcanvasitem.cpp b/tests/auto/quick/qquickcanvasitem/tst_qquickcanvasitem.cpp
index 4a83bd6c0d..7e65b2a9d4 100644
--- a/tests/auto/quick/qquickcanvasitem/tst_qquickcanvasitem.cpp
+++ b/tests/auto/quick/qquickcanvasitem/tst_qquickcanvasitem.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtQuickTest/quicktest.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
diff --git a/tests/auto/quick/qquickcolorgroup/CMakeLists.txt b/tests/auto/quick/qquickcolorgroup/CMakeLists.txt
index 9fde27b06f..0ced7947fd 100644
--- a/tests/auto/quick/qquickcolorgroup/CMakeLists.txt
+++ b/tests/auto/quick/qquickcolorgroup/CMakeLists.txt
@@ -1,13 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickcolorgroup.pro.
#####################################################################
## tst_qquickcolorgroup Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickcolorgroup LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qquickcolorgroup
SOURCES
tst_qquickcolorgroup.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::QmlPrivate
diff --git a/tests/auto/quick/qquickcolorgroup/tst_qquickcolorgroup.cpp b/tests/auto/quick/qquickcolorgroup/tst_qquickcolorgroup.cpp
index 71477c058b..acf2849188 100644
--- a/tests/auto/quick/qquickcolorgroup/tst_qquickcolorgroup.cpp
+++ b/tests/auto/quick/qquickcolorgroup/tst_qquickcolorgroup.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/qtest.h>
#include <QtTest/QSignalSpy>
@@ -82,7 +46,7 @@ void tst_QQuickColorGroup::checkColorProperty()
qvariant_cast<QColor>(property.read(&defaultGroup)));
constexpr int expectedNotificationsCount = 2; // One from write + one from reset
- QCOMPARE(sp.count(), expectedNotificationsCount);
+ QCOMPARE(sp.size(), expectedNotificationsCount);
}
void tst_QQuickColorGroup::checkColorProperty_data()
@@ -109,7 +73,7 @@ void tst_QQuickColorGroup::colorGroupChangedWhenColorChanged()
group.setMid(Qt::blue);
- QCOMPARE(sp.count(), 1);
+ QCOMPARE(sp.size(), 1);
}
QTEST_MAIN(tst_QQuickColorGroup)
diff --git a/tests/auto/quick/qquickdeliveryagent/BLACKLIST b/tests/auto/quick/qquickdeliveryagent/BLACKLIST
new file mode 100644
index 0000000000..f1c1d7fade
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/BLACKLIST
@@ -0,0 +1,7 @@
+# QTBUG-103080
+[passiveGrabberOrder]
+android
+
+# QTBUG-100991
+[touchCompression]
+android
diff --git a/tests/auto/quick/qquickdeliveryagent/CMakeLists.txt b/tests/auto/quick/qquickdeliveryagent/CMakeLists.txt
new file mode 100644
index 0000000000..f893d4372b
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/CMakeLists.txt
@@ -0,0 +1,44 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qquickdeliveryagent Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickdeliveryagent LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_qquickdeliveryagent
+ SOURCES
+ tst_qquickdeliveryagent.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qquickdeliveryagent CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=":/data"
+)
+
+qt_internal_extend_target(tst_qquickdeliveryagent CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+)
diff --git a/tests/auto/quick/qquickdeliveryagent/data/clearItemsOnHoverLeave.qml b/tests/auto/quick/qquickdeliveryagent/data/clearItemsOnHoverLeave.qml
new file mode 100644
index 0000000000..7b37b44050
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/data/clearItemsOnHoverLeave.qml
@@ -0,0 +1,32 @@
+import QtQuick
+
+Rectangle{
+ id: mainWindow
+
+ visible: true
+ width: 800
+ height: 600
+
+ Column {
+ anchors.fill: parent
+ MouseArea {
+ width: parent.width
+ height: parent.height/3
+ hoverEnabled: true
+ }
+ MouseArea {
+ id: mouseArea
+ width: parent.width
+ height: parent.height/3
+ hoverEnabled: true
+ onExited: {
+ Window.window.close();
+ }
+ }
+ MouseArea {
+ width: parent.width
+ height: parent.height / 3
+ hoverEnabled: true
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickdeliveryagent/data/compoundControl.qml b/tests/auto/quick/qquickdeliveryagent/data/compoundControl.qml
new file mode 100644
index 0000000000..8ed05fc8d2
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/data/compoundControl.qml
@@ -0,0 +1,28 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.Basic
+
+Item {
+ id: root
+ objectName: "root"
+ width: 320
+ height: 240
+
+ FocusScope {
+ id: spinboxFocusScope
+ objectName: "spinboxFocusScope"
+ width: spinbox.width
+ height: spinbox.height
+ SpinBox {
+ id: spinbox
+ objectName: "spinbox"
+ editable: true
+ contentItem: TextField {
+ objectName: "spinboxContentItem"
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/auto/quick/qquickdeliveryagent/data/flickableTextEdit.qml b/tests/auto/quick/qquickdeliveryagent/data/flickableTextEdit.qml
new file mode 100644
index 0000000000..79d91a25d4
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/data/flickableTextEdit.qml
@@ -0,0 +1,42 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Rectangle {
+ id: root
+ width: 320
+ height: 240
+ property int tapCount: 0
+
+ Flickable {
+ width: (parent.width / 2) - 20
+ height: parent.height - 20
+ x: 10; y: 10
+ contentWidth: 300
+ contentHeight: 300
+ clip: true
+ Rectangle {
+ width: 140
+ height: 220
+ border.color: "black"
+ color: "aquamarine"
+ TextEdit {
+ id: textEdit
+ objectName: "textEdit"
+ anchors.fill: parent
+ anchors.margins: 2
+ text: "No! those days are gone away,
+And their hours are old and gray,
+And their minutes buried all
+Under the down-trodden pall
+Of the leaves of many years:
+Many times have winter's shears,
+Frozen North, and chilling East,
+Sounded tempests to the feast
+Of the forest's whispering fleeces,
+Since men knew nor rent nor leases."
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickdeliveryagent/data/listViewDelegate.qml b/tests/auto/quick/qquickdeliveryagent/data/listViewDelegate.qml
new file mode 100644
index 0000000000..c5207e2a5d
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/data/listViewDelegate.qml
@@ -0,0 +1,21 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Item {
+ id: root
+ width: 320
+ height: 240
+
+ ListView {
+ id: listView
+ width: 320
+ height: 240
+ delegate: Rectangle {
+ width: ListView.view.width
+ height: ListView.view.height / ListView.view.count
+ color: "tomato"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickdeliveryagent/data/passiveGrabberItem.qml b/tests/auto/quick/qquickdeliveryagent/data/passiveGrabberItem.qml
new file mode 100644
index 0000000000..71e0ac8989
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/data/passiveGrabberItem.qml
@@ -0,0 +1,34 @@
+import QtQuick
+
+import Test
+
+Item {
+ width: 320
+ height: 240
+ property alias exclusiveGrabber: exGrabber
+ property alias passiveGrabber: psGrabber
+ ExclusiveGrabber {
+ id: exGrabber
+ width: parent.width
+ height: 30
+ color: "blue"
+ anchors.verticalCenter: parent.verticalCenter
+ Text {
+ anchors.centerIn: parent
+ text: "Exclusive Grabber"
+ }
+ }
+ PassiveGrabber {
+ id: psGrabber
+ width: parent.width * 0.3
+ height: parent.height
+ color: "yellow"
+ opacity: 0.5
+ Text {
+ anchors.centerIn: parent
+ text: "Passive Grabber"
+ rotation: 90
+ }
+ }
+}
+
diff --git a/tests/auto/quick/qquickdeliveryagent/data/pointHandler.qml b/tests/auto/quick/qquickdeliveryagent/data/pointHandler.qml
new file mode 100644
index 0000000000..a8afa8f78a
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/data/pointHandler.qml
@@ -0,0 +1,17 @@
+import QtQuick
+
+Rectangle {
+ id: root
+ objectName: "root"
+ color: ph.active ? "coral" : "cadetblue"
+ border.color: "black"
+ width: 100; height: 100
+ PointHandler {
+ id: ph
+ objectName: root.objectName + "PointHandler"
+ }
+ Text {
+ anchors.centerIn: parent
+ text: ph.point.position.x.toFixed(1) + ", " + ph.point.position.y.toFixed(1)
+ }
+}
diff --git a/tests/auto/quick/qquickdeliveryagent/data/tapHandler.qml b/tests/auto/quick/qquickdeliveryagent/data/tapHandler.qml
new file mode 100644
index 0000000000..e2ba88dcde
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/data/tapHandler.qml
@@ -0,0 +1,14 @@
+import QtQuick
+
+Rectangle {
+ id: root
+ objectName: "root"
+ color: th.pressed ? "goldenrod" : "khaki"
+ border.color: "black"
+ width: 100; height: 100
+ TapHandler {
+ id: th
+ objectName: root.objectName + "Tap"
+ onTapped: console.log(this, objectName)
+ }
+}
diff --git a/tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp b/tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp
new file mode 100644
index 0000000000..c9bce0c0b4
--- /dev/null
+++ b/tests/auto/quick/qquickdeliveryagent/tst_qquickdeliveryagent.cpp
@@ -0,0 +1,681 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <qtest.h>
+#include <QSignalSpy>
+#include <QDebug>
+#include <QtQml/QQmlEngine>
+#include <QtQml/QQmlComponent>
+#include <QtQuick/QQuickItem>
+#include <QtQuick/QQuickView>
+#include <QtQuick/QQuickWindow>
+#include <QtQuick/private/qquickrectangle_p.h>
+#include <QtQuick/private/qquickflickable_p.h>
+#include <QtQuick/private/qquicklistview_p.h>
+#include <QtQuick/private/qquickpointhandler_p.h>
+#include <QtQuick/private/qquickshadereffectsource_p.h>
+#include <QtQuick/private/qquicktaphandler_p.h>
+#include <QtQuick/private/qquickwindow_p.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuick/private/qquickmousearea_p.h>
+
+#include <QtGui/private/qeventpoint_p.h>
+
+#include <QtCore/qpointer.h>
+
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+
+// On one hand, uncommenting this will make troubleshooting easier (avoid the 60FPS hover events).
+// On the other hand, if anything actually breaks when hover events are enabled, that's also a bug.
+//#define DISABLE_HOVER_IN_IRRELEVANT_TESTS
+
+struct ViewportTransformHelper : public QQuickDeliveryAgent::Transform
+{
+ QPointF offset = QPointF(50, 50);
+
+ // Transforms window coordinates to subscene coordinates.
+ QPointF map(const QPointF &viewportPoint) override {
+ qCDebug(lcTests) << viewportPoint << "->" << viewportPoint - offset;
+ return viewportPoint - offset;
+ }
+};
+
+struct HoverItem : public QQuickItem
+{
+ HoverItem(QQuickItem *parent) : QQuickItem(parent){}
+ void hoverEnterEvent(QHoverEvent *e) override
+ {
+ hoverEnter = true;
+ e->setAccepted(block);
+ }
+
+ void hoverLeaveEvent(QHoverEvent *e) override
+ {
+ hoverLeave = true;
+ e->setAccepted(block);
+ }
+
+ bool hoverEnter = false;
+ bool hoverLeave = false;
+ bool block = false;
+};
+
+// A QQuick3DViewport simulator
+class SubsceneRootItem : public QQuickShaderEffectSource
+{
+public:
+ SubsceneRootItem(QQuickItem *source, QRectF bounds, QQuickItem *parent = nullptr)
+ : QQuickShaderEffectSource(parent),
+ deliveryAgent(QQuickItemPrivate::get(source)->ensureSubsceneDeliveryAgent())
+ {
+ setAcceptedMouseButtons(Qt::AllButtons);
+ setAcceptTouchEvents(true);
+ setAcceptHoverEvents(true);
+ setSourceItem(source);
+ setSize(bounds.size());
+ setPosition(bounds.topLeft());
+ setOpacity(0.5);
+ deliveryAgent->setObjectName("subscene");
+ vxh->offset = position();
+ }
+
+ QQuickDeliveryAgent *deliveryAgent = nullptr;
+
+protected:
+ bool event(QEvent *e) override {
+ if (e->isPointerEvent()) {
+ bool ret = false;
+ auto pe = static_cast<QPointerEvent *>(e);
+
+ QVarLengthArray<QPointF, 16> originalScenePositions;
+ originalScenePositions.resize(pe->pointCount());
+ for (int pointIndex = 0; pointIndex < pe->pointCount(); ++pointIndex)
+ originalScenePositions[pointIndex] = pe->point(pointIndex).scenePosition();
+
+ for (int pointIndex = 0; pointIndex < pe->pointCount(); ++pointIndex) {
+ QEventPoint &p = pe->point(pointIndex);
+ QMutableEventPoint::setScenePosition(p, vxh->map(p.scenePosition()));
+ QMutableEventPoint::setPosition(p, p.position());
+ }
+
+ qCDebug(lcTests) << "forwarding to subscene DA" << pe;
+ if (deliveryAgent->event(pe)) {
+ ret = true;
+ if (QQuickDeliveryAgentPrivate::anyPointGrabbed(pe))
+ deliveryAgent->setSceneTransform(vxh); // takes ownership
+ }
+
+ // restore original scene positions
+ for (int pointIndex = 0; pointIndex < pe->pointCount(); ++pointIndex)
+ QMutableEventPoint::setScenePosition(pe->point(pointIndex), originalScenePositions.at(pointIndex));
+
+ pe->setAccepted(false); // reject implicit grab and let it keep propagating
+ qCDebug(lcTests) << e << "returning" << ret;
+ return ret;
+ } else {
+ return QQuickShaderEffectSource::event(e);
+ }
+ }
+
+ ViewportTransformHelper *vxh = new ViewportTransformHelper;
+};
+
+class tst_qquickdeliveryagent : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_qquickdeliveryagent()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+ {
+ }
+
+private slots:
+ void passiveGrabberOrder();
+ void passiveGrabberItems();
+ void tapHandlerDoesntOverrideSubsceneGrabber_data();
+ void tapHandlerDoesntOverrideSubsceneGrabber();
+ void undoDelegationWhenSubsceneFocusCleared();
+ void touchCompression();
+ void hoverPropagation_nested_data();
+ void hoverPropagation_nested();
+ void hoverPropagation_siblings();
+ void hoverEnterOnItemMove();
+ void hoverEnterOnItemMoveAfterHide();
+ void clearItemsOnHoverLeave();
+ void deleteTargetOnPress();
+ void compoundControlsFocusInSubscene();
+
+private:
+ QScopedPointer<QPointingDevice> touchDevice = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
+};
+
+void tst_qquickdeliveryagent::passiveGrabberOrder()
+{
+ QQuickView view;
+ QQmlComponent component(view.engine());
+ component.loadUrl(testFileUrl("tapHandler.qml"));
+ view.setContent(QUrl(), &component, component.create());
+ view.resize(160, 160);
+ QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject());
+ QVERIFY(root);
+ QQuickTapHandler *rootTap = root->findChild<QQuickTapHandler *>();
+ QVERIFY(rootTap);
+
+ QScopedPointer<QQuickItem> subsceneRect(qobject_cast<QQuickItem *>(component.createWithInitialProperties({{"objectName", "child"}})));
+ QVERIFY(subsceneRect);
+ QQuickTapHandler *subsceneTap = subsceneRect->findChild<QQuickTapHandler *>();
+ QVERIFY(subsceneTap);
+
+ SubsceneRootItem subscene(subsceneRect.data(), {50, 50, 100, 100}, view.rootObject());
+ QCOMPARE(subsceneRect->parentItem(), nullptr);
+ QQuickDeliveryAgent *windowAgent = QQuickWindowPrivate::get(&view)->deliveryAgent;
+ windowAgent->setObjectName("window");
+ QVERIFY(subscene.deliveryAgent);
+ QVERIFY(subscene.deliveryAgent != windowAgent);
+ QQuickVisualTestUtils::SignalMultiSpy spy;
+ QVERIFY(spy.connectToSignal(rootTap, &QQuickTapHandler::tapped));
+ QVERIFY(spy.connectToSignal(subsceneTap, &QQuickTapHandler::tapped));
+
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QPoint pos(75, 75);
+ QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, pos);
+ QTRY_VERIFY(rootTap->isPressed());
+ QTRY_VERIFY(subsceneTap->isPressed());
+ auto devPriv = QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice());
+ const auto &persistentPoint = devPriv->activePoints.values().first();
+ qCDebug(lcTests) << "passive grabbers" << persistentPoint.passiveGrabbers << "contexts" << persistentPoint.passiveGrabbersContext;
+ QCOMPARE(persistentPoint.passiveGrabbers.size(), 2);
+ QCOMPARE(persistentPoint.passiveGrabbers.first(), subsceneTap);
+ QCOMPARE(persistentPoint.passiveGrabbersContext.first(), subscene.deliveryAgent);
+ QCOMPARE(persistentPoint.passiveGrabbers.last(), rootTap);
+
+ QTest::mouseRelease(&view, Qt::LeftButton);
+ QTRY_COMPARE(rootTap->isPressed(), false);
+ QTRY_COMPARE(subsceneTap->isPressed(), false);
+ // QQuickWindow::event() has failsafe: clear all grabbers after release
+ QCOMPARE(persistentPoint.passiveGrabbers.size(), 0);
+
+ qCDebug(lcTests) << "TapHandlers emitted tapped in this order:" << spy.senders;
+ QCOMPARE(spy.senders.size(), 2);
+ // passive grabbers are visited in order, and emit tapped() at that time
+ QCOMPARE(spy.senders.first(), subsceneTap);
+ QCOMPARE(spy.senders.last(), rootTap);
+}
+
+class PassiveGrabberItem : public QQuickRectangle
+{
+public:
+ PassiveGrabberItem(QQuickItem *parent = nullptr) : QQuickRectangle(parent) {
+ setAcceptedMouseButtons(Qt::LeftButton);
+ }
+ void mousePressEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << "Passive grabber pressed";
+ lastPressed = true;
+ event->addPassiveGrabber(event->point(0), this);
+ event->ignore();
+ }
+ void mouseMoveEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << "Mouse move handled by passive grabber";
+ const QPointF pos = event->scenePosition();
+ const int threshold = 20;
+ bool overThreshold = pos.x() >= threshold;
+ if (overThreshold) {
+ event->setExclusiveGrabber(event->point(0), this);
+ this->setKeepMouseGrab(true);
+ event->accept();
+ } else {
+ event->ignore();
+ }
+ }
+ void mouseReleaseEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << "Passive grabber released";
+ lastPressed = false;
+ event->ignore();
+ }
+
+ bool lastPressed = false;
+};
+
+class ExclusiveGrabberItem : public QQuickRectangle
+{
+public:
+ ExclusiveGrabberItem(QQuickItem *parent = nullptr) : QQuickRectangle(parent) {
+ setAcceptedMouseButtons(Qt::LeftButton);
+ }
+ void mousePressEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << "Exclusive grabber pressed";
+ lastPressed = true;
+ event->accept();
+ }
+ void mouseMoveEvent(QMouseEvent *event) override {
+ event->accept();
+ }
+ void mouseReleaseEvent(QMouseEvent *event) override {
+ qCDebug(lcTests) << "Exclusive grabber released";
+ lastPressed = false;
+ event->accept();
+ }
+ void mouseUngrabEvent() override {
+ qCDebug(lcTests) << "Exclusive grab ended";
+ ungrabbed = true;
+ }
+
+ bool lastPressed = false;
+ bool ungrabbed = false;
+};
+
+void tst_qquickdeliveryagent::passiveGrabberItems()
+{
+ QQuickView view;
+ QQmlComponent component(view.engine());
+ qmlRegisterType<PassiveGrabberItem>("Test", 1, 0, "PassiveGrabber");
+ qmlRegisterType<ExclusiveGrabberItem>("Test", 1, 0, "ExclusiveGrabber");
+ component.loadUrl(testFileUrl("passiveGrabberItem.qml"));
+ view.setContent(QUrl(), &component, component.create());
+ QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject());
+ QVERIFY(root);
+ ExclusiveGrabberItem *exclusiveGrabber = root->property("exclusiveGrabber").value<ExclusiveGrabberItem*>();
+ PassiveGrabberItem *passiveGrabber = root->property("passiveGrabber").value<PassiveGrabberItem *>();
+ QVERIFY(exclusiveGrabber);
+ QVERIFY(passiveGrabber);
+
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, QPoint(exclusiveGrabber->x() + 1, exclusiveGrabber->y() + 1));
+ auto devPriv = QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice());
+ const auto &persistentPoint = devPriv->activePoints.values().first();
+ QTRY_COMPARE(persistentPoint.passiveGrabbers.size(), 1);
+ QCOMPARE(persistentPoint.passiveGrabbers.first(), passiveGrabber);
+ QCOMPARE(persistentPoint.exclusiveGrabber, exclusiveGrabber);
+ QVERIFY(exclusiveGrabber->lastPressed);
+ QVERIFY(passiveGrabber->lastPressed);
+
+ // Mouse move bigger than threshold -> passive grabber becomes exclusive grabber
+ QTest::mouseMove(&view);
+ QTRY_COMPARE(persistentPoint.exclusiveGrabber, passiveGrabber);
+ QVERIFY(exclusiveGrabber->ungrabbed);
+
+ QTest::mouseRelease(&view, Qt::LeftButton);
+ // Only the passive grabber got the release event
+ // since it became the exclusive grabber on mouseMove
+ QTRY_VERIFY(!passiveGrabber->lastPressed);
+ QVERIFY(exclusiveGrabber->lastPressed);
+ QCOMPARE(persistentPoint.passiveGrabbers.size(), 0);
+ QCOMPARE(persistentPoint.exclusiveGrabber, nullptr);
+
+ exclusiveGrabber->lastPressed = false;
+ exclusiveGrabber->ungrabbed = false;
+ passiveGrabber->lastPressed = false;
+
+ QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, QPoint(exclusiveGrabber->x() + 1, exclusiveGrabber->y() + 1));
+ const auto &pressedPoint = devPriv->activePoints.values().first();
+ QTRY_COMPARE(pressedPoint.passiveGrabbers.size(), 1);
+ QCOMPARE(pressedPoint.passiveGrabbers.first(), passiveGrabber);
+ QCOMPARE(pressedPoint.exclusiveGrabber, exclusiveGrabber);
+ QVERIFY(exclusiveGrabber->lastPressed);
+ QVERIFY(passiveGrabber->lastPressed);
+
+ // Mouse move smaller than threshold -> grab remains with the exclusive grabber
+ QTest::mouseMove(&view, QPoint(exclusiveGrabber->x(), exclusiveGrabber->y()));
+ QTRY_COMPARE(pressedPoint.exclusiveGrabber, exclusiveGrabber);
+
+ QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, QPoint(exclusiveGrabber->x(), exclusiveGrabber->y()));
+
+ // Both the passive and the exclusive grabber get the mouseRelease event
+ QTRY_VERIFY(!passiveGrabber->lastPressed);
+ QVERIFY(!exclusiveGrabber->lastPressed);
+ QCOMPARE(pressedPoint.passiveGrabbers.size(), 0);
+ QCOMPARE(pressedPoint.exclusiveGrabber, nullptr);
+}
+
+void tst_qquickdeliveryagent::tapHandlerDoesntOverrideSubsceneGrabber_data()
+{
+ QTest::addColumn<QQuickTapHandler::GesturePolicy>("gesturePolicy");
+ QTest::addColumn<int>("expectedTaps");
+ QTest::addColumn<int>("expectedCancels");
+ // TapHandler gets passive grab => "stealth" tap, regardless of other Items
+ QTest::newRow("DragThreshold") << QQuickTapHandler::DragThreshold << 1 << 0;
+ // TapHandler gets exclusive grab => it's cancelled when the TextEdit takes the grab
+ QTest::newRow("WithinBounds") << QQuickTapHandler::WithinBounds << 0 << 2; // 2 because of QTBUG-105865
+ QTest::newRow("ReleaseWithinBounds") << QQuickTapHandler::ReleaseWithinBounds << 0 << 2;
+ QTest::newRow("DragWithinBounds") << QQuickTapHandler::DragWithinBounds << 0 << 2;
+}
+
+void tst_qquickdeliveryagent::tapHandlerDoesntOverrideSubsceneGrabber() // QTBUG-94012
+{
+ QFETCH(QQuickTapHandler::GesturePolicy, gesturePolicy);
+ QFETCH(int, expectedTaps);
+ QFETCH(int, expectedCancels);
+
+ QQuickView window;
+#ifdef DISABLE_HOVER_IN_IRRELEVANT_TESTS
+ QQuickWindowPrivate::get(&window)->deliveryAgentPrivate()->frameSynchronousHoverEnabled = false;
+#endif
+ QVERIFY(QQuickTest::initView(window, testFileUrl("flickableTextEdit.qml")));
+ QQuickItem *textEdit = window.rootObject()->findChild<QQuickItem*>("textEdit");
+ QVERIFY(textEdit);
+ QQuickFlickable *flickable = window.rootObject()->findChild<QQuickFlickable*>();
+ QVERIFY(flickable);
+
+ // put the Flickable into a SubsceneRootItem
+ SubsceneRootItem subscene(flickable, flickable->boundingRect().translated(flickable->width() + 20, 10), window.rootObject());
+ QPoint clickPos = subscene.boundingRect().translated(subscene.width(), 10).center().toPoint();
+
+ // add a TapHandler to it
+ QQuickTapHandler tapHandler(&subscene);
+ tapHandler.setGesturePolicy(gesturePolicy);
+ QSignalSpy clickSpy(&tapHandler, &QQuickTapHandler::tapped);
+ QSignalSpy cancelSpy(&tapHandler, &QQuickTapHandler::canceled);
+
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ int cursorPos = textEdit->property("cursorPosition").toInt();
+
+ // Click on the middle of the subscene to the right (texture cloned from the left).
+ // TapHandler takes whichever type of grab on press; TextEdit takes the exclusive grab;
+ // TapHandler either gets tapped if it has passive grab, or gets its exclusive grab cancelled.
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, clickPos);
+ qCDebug(lcTests) << "clicking subscene TextEdit set cursorPos to" << cursorPos;
+ QVERIFY(textEdit->property("cursorPosition").toInt() > cursorPos); // TextEdit reacts regardless
+ QCOMPARE(clickSpy.size(), expectedTaps);
+ QCOMPARE(cancelSpy.size(), expectedCancels);
+}
+
+void tst_qquickdeliveryagent::undoDelegationWhenSubsceneFocusCleared() // QTBUG-105192
+{
+ QQuickView window;
+#ifdef DISABLE_HOVER_IN_IRRELEVANT_TESTS
+ QQuickWindowPrivate::get(&window)->deliveryAgentPrivate()->frameSynchronousHoverEnabled = false;
+#endif
+ QVERIFY(QQuickTest::initView(window, testFileUrl("listViewDelegate.qml")));
+ QQuickListView *listView = window.rootObject()->findChild<QQuickListView*>();
+ QVERIFY(listView);
+
+ // put the ListView into a SubsceneRootItem
+ SubsceneRootItem subscene(listView, listView->boundingRect(), window.rootObject());
+
+ window.show();
+ QVERIFY(QTest::qWaitForWindowFocused(&window));
+
+ // populate a delegate in ListView
+ listView->setModel(1);
+ QQuickItem *delegate = nullptr;
+ QTRY_VERIFY(QQuickVisualTestUtils::findViewDelegateItem(listView, 0, delegate));
+ QCOMPARE(QQuickWindowPrivate::get(&window)->deliveryAgentPrivate()->activeFocusItem, delegate);
+ delete listView;
+ QCOMPARE_NE(QQuickWindowPrivate::get(&window)->deliveryAgentPrivate()->activeFocusItem, delegate);
+}
+
+void tst_qquickdeliveryagent::touchCompression()
+{
+ QQuickView window;
+ // avoid interference from X11 window managers, so we can look at eventpoint globalPosition
+ window.setFlag(Qt::FramelessWindowHint);
+#ifdef DISABLE_HOVER_IN_IRRELEVANT_TESTS
+ QQuickWindowPrivate::get(&window)->deliveryAgentPrivate()->frameSynchronousHoverEnabled = false;
+#endif
+ QVERIFY(QQuickTest::showView(window, testFileUrl("pointHandler.qml")));
+ QQuickDeliveryAgent *windowAgent = QQuickWindowPrivate::get(&window)->deliveryAgent;
+ QQuickDeliveryAgentPrivate *agentPriv = static_cast<QQuickDeliveryAgentPrivate *>(QQuickDeliveryAgentPrivate::get(windowAgent));
+ QQuickItem *root = qobject_cast<QQuickItem*>(window.rootObject());
+ QVERIFY(root);
+ QQuickPointHandler *rootHandler = root->findChild<QQuickPointHandler *>();
+ QVERIFY(rootHandler);
+ QTest::QTouchEventSequence touch = QTest::touchEvent(&window, touchDevice.data());
+ QPoint pt1(30, 50);
+ QPoint pt2(70, 50);
+ // Press and drag fast, alternating moving and stationary points
+ touch.press(11, pt1).press(12, pt2).commit();
+ QQuickTouchUtils::flush(&window);
+ QTest::qWait(50); // not critical, but let it hopefully render a frame or two
+ QCOMPARE(agentPriv->compressedTouchCount, 0);
+ for (int m = 1; m < 4; ++m) {
+ pt1 += {0, 1};
+ pt2 -= {0, 1};
+ if (m % 2)
+ touch.move(11, pt1).stationary(12).commit();
+ else
+ touch.stationary(11).move(12, pt2).commit();
+ // don't call QQuickTouchUtils::flush() here: we want to see the compression happen
+ if (agentPriv->compressedTouchCount) {
+ if (m % 2) {
+ QCOMPARE(agentPriv->delayedTouch->point(0).position().toPoint(), pt1);
+ QCOMPARE(agentPriv->delayedTouch->point(0).globalPosition().toPoint(), root->mapToGlobal(pt1).toPoint());
+ } else {
+ QCOMPARE(agentPriv->delayedTouch->point(1).position().toPoint(), pt2);
+ QCOMPARE(agentPriv->delayedTouch->point(1).globalPosition().toPoint(), root->mapToGlobal(pt2).toPoint());
+ }
+ }
+ // we can't guarantee that a CI VM is fast enough, but usually compressedTouchCount == m
+ qCDebug(lcTests) << "compressedTouchCount" << agentPriv->compressedTouchCount << "expected" << m;
+ qCDebug(lcTests) << "PointHandler still sees" << rootHandler->point().position() << "while" << pt1 << "was likely not yet delivered";
+ }
+ QTRY_COMPARE(rootHandler->point().position().toPoint(), pt1);
+ touch.release(11, pt1).release(12, pt2).commit();
+ // should be delivered, bypassing compression; when PointHandler gets the release, it will reset its point
+ QTRY_COMPARE(rootHandler->active(), false);
+ QCOMPARE(rootHandler->point().position(), QPointF());
+ QCOMPARE(agentPriv->compressedTouchCount, 0);
+}
+
+void tst_qquickdeliveryagent::hoverPropagation_nested_data()
+{
+ QTest::addColumn<bool>("block");
+ QTest::newRow("block=false") << false;
+ QTest::newRow("block=true") << true;
+}
+
+void tst_qquickdeliveryagent::hoverPropagation_nested()
+{
+ QFETCH(bool, block);
+
+ QQuickWindow window;
+ window.resize(200, 200);
+ window.show();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+
+ HoverItem child(window.contentItem());
+ child.setAcceptHoverEvents(true);
+ child.setWidth(100);
+ child.setHeight(100);
+
+ HoverItem grandChild(&child);
+ grandChild.setAcceptHoverEvents(true);
+ grandChild.block = block;
+ grandChild.setWidth(100);
+ grandChild.setHeight(100);
+
+ // Start by moving the mouse to the window
+ QTest::mouseMove(&window, QPoint(150, 150));
+ QCOMPARE(child.hoverEnter, false);
+ QCOMPARE(grandChild.hoverEnter, false);
+
+ // Move the mouse inside the items. If block is true, only
+ // the grandchild should be hovered. Otherwise both.
+ QTest::mouseMove(&window, QPoint(50, 50));
+ QCOMPARE(child.hoverEnter, !block);
+ QCOMPARE(grandChild.hoverEnter, true);
+}
+
+void tst_qquickdeliveryagent::hoverPropagation_siblings()
+{
+ QQuickWindow window;
+ window.resize(200, 200);
+ window.show();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+
+ HoverItem sibling1(window.contentItem());
+ sibling1.setAcceptHoverEvents(true);
+ sibling1.setWidth(100);
+ sibling1.setHeight(100);
+
+ HoverItem sibling2(window.contentItem());
+ sibling2.setAcceptHoverEvents(true);
+ sibling2.setWidth(100);
+ sibling2.setHeight(100);
+
+ // Start by moving the mouse to the window
+ QTest::mouseMove(&window, QPoint(150, 150));
+ QCOMPARE(sibling1.hoverEnter, false);
+ QCOMPARE(sibling2.hoverEnter, false);
+
+ // Move the mouse inside the items. Only the
+ // sibling on the top should receive hover
+ QTest::mouseMove(&window, QPoint(50, 50));
+ QCOMPARE(sibling1.hoverEnter, false);
+ QCOMPARE(sibling2.hoverEnter, true);
+}
+
+void tst_qquickdeliveryagent::hoverEnterOnItemMove()
+{
+ QQuickWindow window;
+ auto deliveryAgent = QQuickWindowPrivate::get(&window)->deliveryAgentPrivate();
+ window.resize(200, 200);
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ // start with the mouse in the bottom right
+ QTest::mouseMove(&window, QPoint(150, 150));
+
+ HoverItem hoverItem(window.contentItem());
+ hoverItem.setAcceptHoverEvents(true);
+ hoverItem.setWidth(100);
+ hoverItem.setHeight(100);
+
+ deliveryAgent->flushFrameSynchronousEvents(&window);
+
+ QCOMPARE(hoverItem.hoverEnter, false);
+
+ // move the item so the mouse is now inside where the mouse was
+ hoverItem.setX(100);
+ hoverItem.setY(100);
+ deliveryAgent->flushFrameSynchronousEvents(&window);
+ QCOMPARE(hoverItem.hoverEnter, true);
+}
+
+void tst_qquickdeliveryagent::hoverEnterOnItemMoveAfterHide()
+{
+ QQuickWindow window;
+ auto deliveryAgent = QQuickWindowPrivate::get(&window)->deliveryAgentPrivate();
+ window.resize(200, 200);
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ // start with the mouse in the bottom right
+ QTest::mouseMove(&window, QPoint(149, 149));
+
+ HoverItem hoverItem(window.contentItem());
+ hoverItem.setAcceptHoverEvents(true);
+ hoverItem.setWidth(100);
+ hoverItem.setHeight(100);
+
+ deliveryAgent->flushFrameSynchronousEvents(&window);
+ QCOMPARE(hoverItem.hoverEnter, false);
+
+ window.hide();
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ QCOMPARE(hoverItem.hoverEnter, false);
+
+ // move the item so the mouse is now inside where the mouse was
+ hoverItem.setX(100);
+ hoverItem.setY(100);
+ deliveryAgent->flushFrameSynchronousEvents(&window);
+ QCOMPARE(hoverItem.hoverEnter, false);
+}
+
+void tst_qquickdeliveryagent::clearItemsOnHoverLeave()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("clearItemsOnHoverLeave.qml")));
+
+ QTest::mouseMove(&window, QPoint(10, 205)); // Move to MouseArea that triggers close
+ QTest::mouseMove(&window, QPoint(10, 405)); // Exit MouseArea that triggers close.
+}
+
+// QTBUG-91272
+void tst_qquickdeliveryagent::deleteTargetOnPress()
+{
+ QQuickWindow window;
+ auto deliveryAgent = QQuickWindowPrivate::get(&window)->deliveryAgentPrivate();
+ window.resize(200, 200);
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ QQuickMouseArea *lowerArea = new QQuickMouseArea(window.contentItem());
+ lowerArea->setWidth(200);
+ lowerArea->setHeight(200);
+
+ QQuickMouseArea *upperArea = new QQuickMouseArea(window.contentItem());
+ upperArea->setWidth(180);
+ upperArea->setHeight(180);
+ bool pressed = false;
+ connect(upperArea, &QQuickMouseArea::pressed, this, [&]() {
+ pressed = true;
+ delete lowerArea;
+ lowerArea = nullptr;
+ });
+ QTest::mouseMove(&window, QPoint(100, 100));
+ QTest::mousePress(&window, Qt::MouseButton::LeftButton, {}, {100, 100});
+ deliveryAgent->flushFrameSynchronousEvents(&window);
+ QVERIFY(pressed);
+ QVERIFY(upperArea->isPressed());
+ QTest::mouseRelease(&window, Qt::MouseButton::LeftButton, {}, {100, 100});
+ deliveryAgent->flushFrameSynchronousEvents(&window);
+ QVERIFY(!upperArea->isPressed());
+}
+
+void tst_qquickdeliveryagent::compoundControlsFocusInSubscene()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::initView(window, testFileUrl("compoundControl.qml")));
+ QQuickItem *spinboxFocusScope = window.rootObject()->findChild<QQuickItem *>("spinboxFocusScope");
+ QVERIFY(spinboxFocusScope);
+ QQuickItem *spinbox = window.rootObject()->findChild<QQuickItem *>("spinbox");
+ QVERIFY(spinbox);
+ QQuickItem *textField = window.rootObject()->findChild<QQuickItem *>("spinboxContentItem");
+ QVERIFY(textField);
+
+ // put the items into a SubsceneRootItem
+ SubsceneRootItem subscene(spinboxFocusScope, spinboxFocusScope->boundingRect().translated(0, spinboxFocusScope->height() + 20), window.rootObject());
+
+ window.show();
+ QVERIFY(QTest::qWaitForWindowFocused(&window));
+
+ QVERIFY(!textField->hasActiveFocus());
+ QVERIFY(!textField->hasFocus());
+ QVERIFY(!spinbox->hasActiveFocus());
+ QVERIFY(!spinbox->hasFocus());
+ QVERIFY(!spinbox->scopedFocusItem());
+ QVERIFY(!spinboxFocusScope->hasActiveFocus());
+ QVERIFY(!spinboxFocusScope->hasFocus());
+ QVERIFY(!spinbox->scopedFocusItem());
+
+ auto clickPos = spinboxFocusScope->boundingRect().translated(0, spinboxFocusScope->height() + 20).center().toPoint();
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, clickPos);
+
+ QVERIFY(textField->hasActiveFocus());
+ QVERIFY(textField->hasFocus());
+ QTRY_VERIFY(spinbox->hasActiveFocus());
+ QVERIFY(spinbox->hasFocus());
+ QCOMPARE(spinbox->scopedFocusItem(), textField);
+ QVERIFY(spinboxFocusScope->hasActiveFocus());
+ QVERIFY(spinboxFocusScope->hasFocus());
+ QCOMPARE(spinboxFocusScope->scopedFocusItem(), spinbox);
+
+ QQuickDeliveryAgentPrivate *daPriv = static_cast<QQuickDeliveryAgentPrivate *>(QQuickDeliveryAgentPrivate::get(subscene.deliveryAgent));
+ QVERIFY(daPriv->rootItem->hasActiveFocus());
+ QCOMPARE(daPriv->activeFocusItem, textField);
+ QCOMPARE(QQuickWindowPrivate::get(&window)->deliveryAgentPrivate()->activeFocusItem, textField);
+ QCOMPARE(QQuickWindowPrivate::get(&window)->deliveryAgentPrivate()->rootItem->scopedFocusItem(), spinboxFocusScope);
+}
+
+QTEST_MAIN(tst_qquickdeliveryagent)
+
+#include "tst_qquickdeliveryagent.moc"
diff --git a/tests/auto/quick/qquickdesignersupport/CMakeLists.txt b/tests/auto/quick/qquickdesignersupport/CMakeLists.txt
index 2cdb7328ce..985233f5f3 100644
--- a/tests/auto/quick/qquickdesignersupport/CMakeLists.txt
+++ b/tests/auto/quick/qquickdesignersupport/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickdesignersupport.pro.
#####################################################################
## tst_qquickdesignersupport Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickdesignersupport LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,22 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickdesignersupport
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickdesignersupport.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
- Qt::TestPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -39,10 +40,10 @@ qt_internal_add_test(tst_qquickdesignersupport
qt_internal_extend_target(tst_qquickdesignersupport CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickdesignersupport CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickdesignersupport/data/RecursiveProperty.qml b/tests/auto/quick/qquickdesignersupport/data/RecursiveProperty.qml
new file mode 100644
index 0000000000..ec419f8935
--- /dev/null
+++ b/tests/auto/quick/qquickdesignersupport/data/RecursiveProperty.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+
+Item {
+ id: myObject
+ readonly property int testProperty: 0
+ readonly property QtObject myproperty: myObject
+}
+
diff --git a/tests/auto/quick/qquickdesignersupport/data/RegTestComponent.qml b/tests/auto/quick/qquickdesignersupport/data/RegTestComponent.qml
new file mode 100644
index 0000000000..8bb8480daf
--- /dev/null
+++ b/tests/auto/quick/qquickdesignersupport/data/RegTestComponent.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+QtObject {
+ id: root
+
+ property int currentCategory: 0
+
+
+
+ property var materialsNames: [[qsTr("Car Paint"), qsTr("Glittery Car Paint"), qsTr("Aluminium"), qsTr("Chrome"), qsTr("Steel"), qsTr("Brushed Steel"), qsTr("Steel Floor"), qsTr("Copper"), qsTr("Silver"), qsTr("Gold"), qsTr("Mirror")],
+ [qsTr("Asphalt"), qsTr("Brick"), qsTr("Ceramic"), qsTr("Concrete"), qsTr("Glass"), qsTr("Darkened Glass"), qsTr("Wood"), qsTr("Wood - Planks"), qsTr("Wood - Parquet"), qsTr("Stone")],
+ [qsTr("Acrylic Paint"), qsTr("Carbon Fiber"), qsTr("Shiny Plastic"), qsTr("Matte Plastic"), qsTr("Textured Plastic"), qsTr("Rubber"), qsTr("Wax")],
+ [qsTr("Fabric"), qsTr("Fabric: Rough"), qsTr("Fabric: Satin"), qsTr("Leather"), qsTr("Paper")]]
+
+
+
+ property var model: root.materialsNames[root.currentCategory]
+
+} \ No newline at end of file
diff --git a/tests/auto/quick/qquickdesignersupport/data/propertyNameTest.qml b/tests/auto/quick/qquickdesignersupport/data/propertyNameTest.qml
new file mode 100644
index 0000000000..4815709d21
--- /dev/null
+++ b/tests/auto/quick/qquickdesignersupport/data/propertyNameTest.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.11
+
+Rectangle {
+ objectName: "rootItem"
+ color: "white"
+ width: 800
+ height: 600
+
+ RecursiveProperty {
+ objectName: "recursiveProperty"
+
+ }
+}
diff --git a/tests/auto/quick/qquickdesignersupport/data/regTestProperties.qml b/tests/auto/quick/qquickdesignersupport/data/regTestProperties.qml
new file mode 100644
index 0000000000..5ea3f58aff
--- /dev/null
+++ b/tests/auto/quick/qquickdesignersupport/data/regTestProperties.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.11
+
+Rectangle {
+ objectName: "rootItem"
+ color: "white"
+ width: 800
+ height: 600
+
+ RegTestComponent {
+ objectName: "testComponent"
+
+ }
+}
diff --git a/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp b/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp
index 6165e0ee93..bdc8f97d3a 100644
--- a/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp
+++ b/tests/auto/quick/qquickdesignersupport/tst_qquickdesignersupport.cpp
@@ -1,30 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#include <qtest.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
@@ -40,17 +16,16 @@
#include <private/qquickstategroup_p.h>
#include <private/qquickpropertychanges_p.h>
#include <private/qquickrectangle_p.h>
-#include "../../shared/util.h"
-#include "../shared/visualtestutil.h"
-#include <QtTest/private/qemulationdetector_p.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
-using namespace QQuickVisualTestUtil;
+using namespace QQuickVisualTestUtils;
class tst_qquickdesignersupport : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickdesignersupport() {}
+ tst_qquickdesignersupport() : QQmlDataTest(QT_QMLTEST_DATADIR) {}
private slots:
void customData();
@@ -66,6 +41,8 @@ private slots:
void testSimpleBindings();
void testDotProperties();
void testItemReparenting();
+ void testPropertyNames();
+ void regressionTestAllProperties();
};
@@ -106,9 +83,9 @@ void addToNewProperty(QObject *object, QObject *newParent, const QByteArray &new
Q_ASSERT(objectToVariant(object).isValid());
}
-static void removeObjectFromList(const QQmlProperty &property, QObject *objectToBeRemoved, QQmlEngine * engine)
+static void removeObjectFromList(const QQmlProperty &property, QObject *objectToBeRemoved)
{
- QQmlListReference listReference(property.object(), property.name().toUtf8(), engine);
+ QQmlListReference listReference(property.object(), property.name().toUtf8());
int count = listReference.count();
@@ -312,7 +289,7 @@ void tst_qquickdesignersupport::dynamicProperty()
QVERIFY(simpleItem);
QQuickDesignerSupportProperties::registerNodeInstanceMetaObject(simpleItem, view->engine());
- QQuickDesignerSupportProperties::getPropertyCache(simpleItem, view->engine());
+ QQuickDesignerSupportProperties::getPropertyCache(simpleItem);
QQuickDesignerSupportProperties::createNewDynamicProperty(simpleItem, view->engine(), QLatin1String("dynamicProperty"));
@@ -344,10 +321,13 @@ void tst_qquickdesignersupport::createComponent()
QVERIFY(rootItem);
- QObject *testComponentObject = QQuickDesignerSupportItems::createComponent(testFileUrl("TestComponent.qml"), view->rootContext());
+ QScopedPointer<QObject> testComponentObject(
+ QQuickDesignerSupportItems::createComponent(
+ testFileUrl("TestComponent.qml"), view->rootContext()));
QVERIFY(testComponentObject);
- QVERIFY(QQuickDesignerSupportMetaInfo::isSubclassOf(testComponentObject, "QtQuick/Item"));
+ QVERIFY(QQuickDesignerSupportMetaInfo::isSubclassOf(
+ testComponentObject.data(), "QtQuick/Item"));
}
void tst_qquickdesignersupport::basicStates()
@@ -366,7 +346,7 @@ void tst_qquickdesignersupport::basicStates()
QVERIFY(stateGroup);
- QCOMPARE(stateGroup->states().count(), 2 );
+ QCOMPARE(stateGroup->states().size(), 2 );
QQuickState *state01 = stateGroup->states().first();
QQuickState *state02 = stateGroup->states().last();
@@ -412,7 +392,7 @@ void tst_qquickdesignersupport::statesPropertyChanges()
QVERIFY(stateGroup);
- QCOMPARE(stateGroup->states().count(), 2 );
+ QCOMPARE(stateGroup->states().size(), 2 );
QQuickState *state01 = stateGroup->states().first();
QQuickState *state02 = stateGroup->states().last();
@@ -431,7 +411,7 @@ void tst_qquickdesignersupport::statesPropertyChanges()
QCOMPARE(state01->operationCount(), 1);
- QCOMPARE(statePrivate01->operations.count(), 1);
+ QCOMPARE(statePrivate01->operations.size(), 1);
QQuickStateOperation *propertyChange = statePrivate01->operations.at(0).data();
@@ -466,7 +446,7 @@ void tst_qquickdesignersupport::statesPropertyChanges()
QCOMPARE(rootItem, QQuickDesignerSupportPropertyChanges::targetObject(newPropertyChange));
QCOMPARE(state01->operationCount(), 2);
- QCOMPARE(statePrivate01->operations.count(), 2);
+ QCOMPARE(statePrivate01->operations.size(), 2);
QCOMPARE(QQuickDesignerSupportPropertyChanges::stateObject(newPropertyChange), state01);
@@ -579,14 +559,15 @@ void doComponentCompleteRecursive(QObject *object)
QList<QObject*> childList = object->children();
if (item) {
- foreach (QQuickItem *childItem, item->childItems()) {
+ const auto childItems = item->childItems();
+ for (QQuickItem *childItem : childItems) {
if (!childList.contains(childItem))
childList.append(childItem);
}
}
- foreach (QObject *child, childList)
- doComponentCompleteRecursive(child);
+ for (QObject *child : std::as_const(childList))
+ doComponentCompleteRecursive(child);
if (item) {
static_cast<QQmlParserStatus*>(item)->componentComplete();
@@ -664,9 +645,6 @@ void tst_qquickdesignersupport::testComponentOnCompleteSignal()
void tst_qquickdesignersupport::testSimpleBindings()
{
- if (QTestPrivate::isRunningArmOnX86())
- QSKIP("Crashes in QEMU. (QTBUG-90869)");
-
QScopedPointer<QQuickView> view(new QQuickView);
view->engine()->setOutputWarningsToStandardError(false);
view->setSource(testFileUrl("bindingTest.qml"));
@@ -708,9 +686,6 @@ void tst_qquickdesignersupport::testSimpleBindings()
void tst_qquickdesignersupport::testDotProperties()
{
- if (QTestPrivate::isRunningArmOnX86())
- QSKIP("Crashes in QEMU. (QTBUG-90869)");
-
QScopedPointer<QQuickView> view(new QQuickView);
view->engine()->setOutputWarningsToStandardError(false);
view->setSource(testFileUrl("bindingTest.qml"));
@@ -740,8 +715,6 @@ void tst_qquickdesignersupport::testDotProperties()
void tst_qquickdesignersupport::testItemReparenting()
{
- if (QTestPrivate::isRunningArmOnX86())
- QSKIP("Crashes in QEMU. (QTBUG-90869)");
QScopedPointer<QQuickView> view(new QQuickView);
view->engine()->setOutputWarningsToStandardError(false);
@@ -766,11 +739,82 @@ void tst_qquickdesignersupport::testItemReparenting()
QCOMPARE(text->parentItem(), rootItem);
QQmlProperty childrenProperty(rootItem, "children");
- removeObjectFromList(childrenProperty, text, view->engine());
+ removeObjectFromList(childrenProperty, text);
addToNewProperty(text, item, "children");
QCOMPARE(text->parentItem(), item);
}
+void tst_qquickdesignersupport::testPropertyNames()
+{
+ QScopedPointer<QQuickView> view(new QQuickView);
+ view->engine()->setOutputWarningsToStandardError(false);
+ view->setSource(testFileUrl("propertyNameTest.qml"));
+
+ QVERIFY(view->errors().isEmpty());
+ QQuickItem *rootItem = view->rootObject();
+ QVERIFY(rootItem);
+
+ QQuickDesignerSupport::PropertyNameList names = QQuickDesignerSupportProperties::allPropertyNames(rootItem);
+ QVERIFY(!names.isEmpty());
+ QVERIFY(names.contains("width"));
+ QVERIFY(names.contains("height"));
+ QVERIFY(names.contains("clip"));
+ QVERIFY(names.contains("childrenRect"));
+ QVERIFY(names.contains("activeFocus"));
+ QVERIFY(names.contains("border.width"));
+ names = QQuickDesignerSupportProperties::propertyNameListForWritableProperties(rootItem);
+ QVERIFY(!names.isEmpty());
+ QVERIFY(names.contains("width"));
+ QVERIFY(names.contains("height"));
+ QVERIFY(names.contains("opacity"));
+ QVERIFY(!names.contains("childrenRect"));
+ QVERIFY(!names.contains("childrenRect"));
+ QVERIFY(!names.contains("activeFocus"));
+ QVERIFY(names.contains("border.width"));
+
+ QQuickItem *recursiveProperty = findItem<QQuickItem>(rootItem, QLatin1String("recursiveProperty"));
+ QVERIFY(recursiveProperty);
+ names = QQuickDesignerSupportProperties::allPropertyNames(recursiveProperty);
+ QVERIFY(!names.isEmpty());
+ QVERIFY(names.contains("testProperty"));
+ QVERIFY(names.contains("myproperty.testProperty"));
+
+ names = QQuickDesignerSupportProperties::propertyNameListForWritableProperties(recursiveProperty);
+ QVERIFY(!names.isEmpty());
+ QVERIFY(!names.contains("testProperty"));
+}
+
+void tst_qquickdesignersupport::regressionTestAllProperties()
+{
+ QScopedPointer<QQuickView> view(new QQuickView);
+ view->engine()->setOutputWarningsToStandardError(false);
+ view->setSource(testFileUrl("regTestProperties.qml"));
+
+ QVERIFY(view->errors().isEmpty());
+ QQuickItem *rootItem = view->rootObject();
+ QVERIFY(rootItem);
+
+ QObject *component = rootItem->findChild<QObject*>("testComponent");
+
+ QVERIFY(component);
+ QCOMPARE(component->objectName(), QLatin1String("testComponent"));
+
+ QVERIFY(component);
+
+ QQuickDesignerSupport::PropertyNameList names
+ = QQuickDesignerSupportProperties::allPropertyNames(component);
+ QVERIFY(!names.isEmpty());
+
+ const QByteArrayList expectedNames = QByteArrayList {
+ "objectName", "currentCategory", "materialsNames", "model"
+ };
+
+ QCOMPARE(names, expectedNames);
+ names = QQuickDesignerSupportProperties::propertyNameListForWritableProperties(component);
+ QVERIFY(!names.isEmpty());
+ QCOMPARE(names, expectedNames);
+}
+
QTEST_MAIN(tst_qquickdesignersupport)
#include "tst_qquickdesignersupport.moc"
diff --git a/tests/auto/quick/qquickdrag/BLACKLIST b/tests/auto/quick/qquickdrag/BLACKLIST
new file mode 100644
index 0000000000..71cc97fc7a
--- /dev/null
+++ b/tests/auto/quick/qquickdrag/BLACKLIST
@@ -0,0 +1,25 @@
+# QTBUG-103082
+[active]
+android
+[setActive]
+android
+[drop]
+android
+[move]
+android
+[parentChange]
+android
+[hotSpot]
+android
+[supportedActions]
+android
+[proposedAction]
+android
+[keys]
+android
+[source]
+android
+[recursion]
+android
+[noCrashWithImageProvider]
+android
diff --git a/tests/auto/quick/qquickdrag/CMakeLists.txt b/tests/auto/quick/qquickdrag/CMakeLists.txt
index 16da0943e9..73e8c64bb7 100644
--- a/tests/auto/quick/qquickdrag/CMakeLists.txt
+++ b/tests/auto/quick/qquickdrag/CMakeLists.txt
@@ -1,13 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickdrag.pro.
#####################################################################
## tst_qquickdrag Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickdrag LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qquickdrag
SOURCES
tst_qquickdrag.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp b/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp
index dd61fd717d..b17b16b429 100644
--- a/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp
+++ b/tests/auto/quick/qquickdrag/tst_qquickdrag.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtTest/QSignalSpy>
@@ -33,6 +8,7 @@
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlexpression.h>
+#include <QQmlComponent>
template <typename T> static T evaluate(QObject *scope, const QString &expression)
{
@@ -74,7 +50,7 @@ public:
supportedActions = Qt::IgnoreAction;
}
- void dragEnterEvent(QDragEnterEvent *event)
+ void dragEnterEvent(QDragEnterEvent *event) override
{
++enterEvents;
position = event->position().toPoint();
@@ -84,7 +60,7 @@ public:
event->setAccepted(accept);
}
- void dragMoveEvent(QDragMoveEvent *event)
+ void dragMoveEvent(QDragMoveEvent *event) override
{
++moveEvents;
position = event->position().toPoint();
@@ -94,13 +70,13 @@ public:
event->setAccepted(accept);
}
- void dragLeaveEvent(QDragLeaveEvent *event)
+ void dragLeaveEvent(QDragLeaveEvent *event) override
{
++leaveEvents;
event->setAccepted(accept);
}
- void dropEvent(QDropEvent *event)
+ void dropEvent(QDropEvent *event) override
{
++dropEvents;
position = event->position().toPoint();
@@ -1044,28 +1020,28 @@ public:
void setItem(QQuickItem *i) { item = i; }
protected:
- void dragEnterEvent(QDragEnterEvent *event)
+ void dragEnterEvent(QDragEnterEvent *event) override
{
TestDropTarget::dragEnterEvent(event);
if (type == QEvent::DragEnter && enterEvents < 2)
evaluate<void>(item, script);
}
- void dragMoveEvent(QDragMoveEvent *event)
+ void dragMoveEvent(QDragMoveEvent *event) override
{
TestDropTarget::dragMoveEvent(event);
if (type == QEvent::DragMove && moveEvents < 2)
evaluate<void>(item, script);
}
- void dragLeaveEvent(QDragLeaveEvent *event)
+ void dragLeaveEvent(QDragLeaveEvent *event) override
{
TestDropTarget::dragLeaveEvent(event);
if (type == QEvent::DragLeave && leaveEvents < 2)
evaluate<void>(item, script);
}
- void dropEvent(QDropEvent *event)
+ void dropEvent(QDropEvent *event) override
{
TestDropTarget::dropEvent(event);
if (type == QEvent::Drop && dropEvents < 2)
diff --git a/tests/auto/quick/qquickdragattached/CMakeLists.txt b/tests/auto/quick/qquickdragattached/CMakeLists.txt
new file mode 100644
index 0000000000..822e38861e
--- /dev/null
+++ b/tests/auto/quick/qquickdragattached/CMakeLists.txt
@@ -0,0 +1,38 @@
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickdragattached LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_qquickdragattached
+ SOURCES
+ tst_qquickdragattached.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::Network
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qquickdragattached CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=":/data"
+)
+
+qt_internal_extend_target(tst_qquickdragattached CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+)
diff --git a/tests/auto/quick/qquickdragattached/data/qt_logo.svg b/tests/auto/quick/qquickdragattached/data/qt_logo.svg
new file mode 100644
index 0000000000..062daff3e9
--- /dev/null
+++ b/tests/auto/quick/qquickdragattached/data/qt_logo.svg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ width="462pt"
+ height="339pt"
+ viewBox="0 0 462 339"
+ version="1.1"
+ id="svg2"
+>
+ <path
+ fill="#41cd52"
+ d=" M 63.50 0.00 L 462.00 0.00 L 462.00 274.79 C 440.60 296.26 419.13 317.66 397.61 339.00 L 0.00 339.00 L 0.00 63.39 C 21.08 42.18 42.34 21.13 63.50 0.00 Z"
+ id="path6"/>
+ <path
+ d=" M 122.37 71.33 C 137.50 61.32 156.21 58.79 174.00 58.95 C 190.94 59.16 208.72 62.13 222.76 72.24 C 232.96 79.41 239.59 90.48 244.01 101.93 C 251.16 120.73 253.26 141.03 253.50 161.01 C 253.53 181.13 252.62 201.69 245.96 220.86 C 241.50 233.90 233.01 245.48 221.81 253.52 C 229.87 266.58 238.09 279.54 246.15 292.60 C 236.02 297.27 225.92 301.97 215.78 306.62 C 207.15 292.38 198.56 278.11 189.90 263.89 C 178.19 265.81 166.21 265.66 154.44 264.36 C 140.34 262.67 125.97 258.37 115.09 248.88 C 106.73 241.64 101.48 231.51 97.89 221.21 C 92.01 203.79 90.43 185.25 90.16 166.97 C 90.02 147.21 91.28 127.14 97.24 108.18 C 101.85 93.92 109.48 79.69 122.37 71.33 Z"
+ id="path8"
+ fill="#ffffff"/>
+ <path
+ d=" M 294.13 70.69 C 304.73 70.68 315.33 70.68 325.93 70.69 C 325.96 84.71 325.92 98.72 325.95 112.74 C 339.50 112.76 353.05 112.74 366.60 112.75 C 366.37 121.85 366.12 130.95 365.86 140.05 C 352.32 140.08 338.79 140.04 325.25 140.07 C 325.28 163.05 325.18 186.03 325.30 209.01 C 325.56 215.30 325.42 221.94 328.19 227.75 C 330.21 232.23 335.65 233.38 340.08 233.53 C 348.43 233.50 356.77 233.01 365.12 232.86 C 365.63 241.22 366.12 249.59 366.60 257.95 C 349.99 260.74 332.56 264.08 316.06 258.86 C 309.11 256.80 302.63 252.19 299.81 245.32 C 294.76 233.63 294.35 220.62 294.13 208.07 C 294.11 185.40 294.13 162.74 294.12 140.07 C 286.73 140.05 279.34 140.08 271.95 140.05 C 271.93 130.96 271.93 121.86 271.95 112.76 C 279.34 112.73 286.72 112.77 294.11 112.74 C 294.14 98.72 294.10 84.71 294.13 70.69 Z"
+ id="path10"
+ fill="#ffffff"/>
+ <path
+ fill="#41cd52"
+ d=" M 160.51 87.70 C 170.80 86.36 181.60 86.72 191.34 90.61 C 199.23 93.73 205.93 99.84 209.47 107.58 C 214.90 119.31 216.98 132.26 218.03 145.05 C 219.17 162.07 219.01 179.25 216.66 196.17 C 215.01 206.24 212.66 216.85 205.84 224.79 C 198.92 232.76 188.25 236.18 178.01 236.98 C 167.21 237.77 155.82 236.98 146.07 231.87 C 140.38 228.84 135.55 224.09 132.73 218.27 C 129.31 211.30 127.43 203.69 126.11 196.07 C 122.13 171.91 121.17 146.91 126.61 122.89 C 128.85 113.83 132.11 104.53 138.73 97.70 C 144.49 91.85 152.51 88.83 160.51 87.70 Z"
+ id="path12"/>
+</svg>
diff --git a/tests/auto/quick/qquickdragattached/tst_qquickdragattached.cpp b/tests/auto/quick/qquickdragattached/tst_qquickdragattached.cpp
new file mode 100644
index 0000000000..243d767c80
--- /dev/null
+++ b/tests/auto/quick/qquickdragattached/tst_qquickdragattached.cpp
@@ -0,0 +1,183 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+#include <QtTest/QSignalSpy>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/private/qquickdrag_p_p.h>
+
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+
+class tst_QQuickDragAttached: public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_QQuickDragAttached();
+
+private slots:
+ void setMimeData_data();
+ void setMimeData();
+
+ void imageSourceSize_data();
+ void imageSourceSize();
+
+ void startDrag_data();
+ void startDrag();
+};
+
+tst_QQuickDragAttached::tst_QQuickDragAttached()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
+void tst_QQuickDragAttached::setMimeData_data()
+{
+ QTest::addColumn<QVariantMap>("mimeData");
+ QTest::addColumn<QStringList>("formats");
+
+ const QImage image(50, 50, QImage::Format_RGB32);
+
+ QTest::addRow("empty") << QVariantMap{} << QStringList{};
+
+ const auto makeMap = [](const QString &mime, const QVariant &value) {
+ QVariantMap map;
+ map[mime] = value;
+ return map;
+ };
+
+ QTest::addRow("text/plain, string")
+ << makeMap("text/plain", QString("string"))
+ << QStringList{"text/plain"};
+ QTest::addRow("valid charset")
+ << makeMap("text/plain;charset=utf-16", QString("string"))
+ << QStringList{"text/plain;charset=utf-16"};
+ QTest::addRow("image/png, image")
+ << makeMap("image/png", image)
+ << QStringList{"image/png"};
+ QTest::addRow("text/uri-list, string")
+ << makeMap("text/uri-list", QString("https://qt-project.org"))
+ << QStringList{"text/uri-list"};
+ QTest::addRow("text/uri-list, strings")
+ << makeMap("text/uri-list", QStringList{"file://foo", "https://www.test.com"})
+ << QStringList{"text/uri-list"};
+ QTest::addRow("text/uri-list, url")
+ << makeMap("text/uri-list", QVariantList{QVariant(QUrl("file://foo"))})
+ << QStringList{"text/uri-list"};
+ QTest::addRow("text/uri-list, variant")
+ << makeMap("text/uri-list", QVariantList{QVariant("file://foo")})
+ << QStringList{"text/uri-list"};
+ QTest::addRow("application/json")
+ << makeMap("application/json", "{}")
+ << QStringList{"application/json"};
+ QTest::addRow("missing charset")
+ << makeMap("text/plain;charset=", QString("foo"))
+ << QStringList{};
+ QTest::addRow("invalid charset")
+ << makeMap("text/plain;charset=ugh4", QString("ugh4"))
+ << QStringList{};
+ QTest::addRow("mismatch compat")
+ << makeMap("text/plain", image)
+ << QStringList{"text/plain"};
+ QTest::addRow("mismatch list")
+ << makeMap("text/uri-list", QVariantList{image})
+ << QStringList{};
+}
+
+void tst_QQuickDragAttached::setMimeData()
+{
+ QFETCH(QVariantMap, mimeData);
+
+ QQuickDragAttached attached(nullptr);
+ QSignalSpy spy(&attached, &QQuickDragAttached::mimeDataChanged);
+
+ attached.setMimeData(mimeData);
+ int expectedCount = mimeData.isEmpty() ? 0 : 1;
+ QCOMPARE(spy.count(), expectedCount);
+
+ QCOMPARE(attached.mimeData(), mimeData);
+
+ attached.setMimeData(mimeData);
+ QCOMPARE(spy.count(), expectedCount);
+
+ expectedCount += mimeData.isEmpty() ? 0 : 1;
+ attached.setMimeData({});
+ QCOMPARE(spy.count(), expectedCount);
+}
+
+void tst_QQuickDragAttached::imageSourceSize_data()
+{
+ QTest::addColumn<bool>("sizeFirst");
+ QTest::addColumn<QSize>("imageSourceSize");
+ QTest::addColumn<QSize>("expectedSourceSize");
+ QTest::addColumn<QSize>("expectedImageSize");
+
+ QTest::addRow("default size") << false << QSize() << QSize(462, 339) << QSize(462, 339);
+ QTest::addRow("shrunken elongated") << false << QSize(214, 114) << QSize(214, 114) << QSize(214, 114);
+ QTest::addRow("width, neg height") << false << QSize(154, -1) << QSize(154, 339) << QSize(154, 339);
+ QTest::addRow("width, zero height") << false << QSize(154, 0) << QSize(154, 0) << QSize(154, 113);
+
+ QTest::addRow("size first: default size") << true << QSize() << QSize(462, 339) << QSize(462, 339);
+ QTest::addRow("size first: shrunken elongated") << true << QSize(214, 114) << QSize(214, 114) << QSize(214, 114);
+ QTest::addRow("size first: width, neg height") << true << QSize(154, -1) << QSize(154, 113) << QSize(154, 113);
+ QTest::addRow("size first: width, zero height") << true << QSize(154, 0) << QSize(154, 0) << QSize(154, 113);
+}
+
+void tst_QQuickDragAttached::imageSourceSize()
+{
+ QFETCH(bool, sizeFirst);
+ QFETCH(QSize, imageSourceSize);
+ QFETCH(QSize, expectedSourceSize);
+ QFETCH(QSize, expectedImageSize);
+
+ QQuickDragAttached attached(nullptr);
+ QSignalSpy spy(&attached, &QQuickDragAttached::imageSourceSizeChanged);
+
+ if (sizeFirst)
+ attached.setImageSourceSize(imageSourceSize);
+ attached.setImageSource(testFileUrl("qt_logo.svg"));
+ attached.setImageSourceSize(imageSourceSize);
+
+ const int expectedCount = imageSourceSize.width() >= 0 || imageSourceSize.height() >= 0 ? 1 : 0;
+ QCOMPARE(spy.count(), expectedCount);
+ QCOMPARE(attached.imageSourceSize(), expectedSourceSize);
+ QCOMPARE(QQuickDragAttachedPrivate::get(&attached)->pixmapLoader.image().size(), expectedImageSize);
+}
+
+void tst_QQuickDragAttached::startDrag_data()
+{
+ setMimeData_data();
+}
+
+void tst_QQuickDragAttached::startDrag()
+{
+#ifdef QT_BUILD_INTERNAL
+ QFETCH(QVariantMap, mimeData);
+ QFETCH(QStringList, formats);
+
+ QQuickDragAttached attached(nullptr);
+ attached.setMimeData(mimeData);
+
+ auto *d = static_cast<QQuickDragAttachedPrivate *>(QObjectPrivate::get(&attached));
+
+ if (formats.isEmpty()) {
+ if (!mimeData.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*QML QQuickDragAttached:.*"));
+ else
+ QTest::failOnWarning(QRegularExpression(".*"));
+ }
+ std::unique_ptr<QMimeData> data(d->createMimeData());
+ QVERIFY(data);
+
+ auto debugHelper = qScopeGuard([&data]{
+ qWarning() << data->formats();
+ });
+ QCOMPARE(data->formats(), formats);
+ debugHelper.dismiss();
+#else
+ QSKIP("This test relies on private APIs that are only exported in developer-builds");
+#endif
+}
+
+QTEST_MAIN(tst_QQuickDragAttached)
+
+#include "tst_qquickdragattached.moc"
diff --git a/tests/auto/quick/qquickdroparea/BLACKLIST b/tests/auto/quick/qquickdroparea/BLACKLIST
new file mode 100644
index 0000000000..61650f3308
--- /dev/null
+++ b/tests/auto/quick/qquickdroparea/BLACKLIST
@@ -0,0 +1,3 @@
+# QTBUG-103083
+[signalOrder]
+android
diff --git a/tests/auto/quick/qquickdroparea/CMakeLists.txt b/tests/auto/quick/qquickdroparea/CMakeLists.txt
index d66bf23714..32d631f08c 100644
--- a/tests/auto/quick/qquickdroparea/CMakeLists.txt
+++ b/tests/auto/quick/qquickdroparea/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickdroparea.pro.
#####################################################################
## tst_qquickdroparea Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickdroparea LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,22 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickdroparea
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickdroparea.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -39,10 +41,10 @@ qt_internal_add_test(tst_qquickdroparea
qt_internal_extend_target(tst_qquickdroparea CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickdroparea CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickdroparea/data/ignoreRetriggerEvent.qml b/tests/auto/quick/qquickdroparea/data/ignoreRetriggerEvent.qml
new file mode 100644
index 0000000000..af25a04ee7
--- /dev/null
+++ b/tests/auto/quick/qquickdroparea/data/ignoreRetriggerEvent.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.0
+
+DropArea {
+ property int enterEvents: 0
+ property int exitEvents: 0
+ width: 100; height: 100
+ objectName: "dropArea"
+ onEntered: function (drag) { ++enterEvents; drag.accepted = false }
+ onExited: {++exitEvents}
+ Item {
+ objectName: "dragItem"
+ x: 50; y: 50
+ width: 10; height: 10
+ }
+}
diff --git a/tests/auto/quick/qquickdroparea/data/nested1.qml b/tests/auto/quick/qquickdroparea/data/nested1.qml
index de6ac70d08..430421d27b 100644
--- a/tests/auto/quick/qquickdroparea/data/nested1.qml
+++ b/tests/auto/quick/qquickdroparea/data/nested1.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
Item {
diff --git a/tests/auto/quick/qquickdroparea/data/nested2.qml b/tests/auto/quick/qquickdroparea/data/nested2.qml
index 93630c3779..c7261ef1d5 100644
--- a/tests/auto/quick/qquickdroparea/data/nested2.qml
+++ b/tests/auto/quick/qquickdroparea/data/nested2.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
Item {
diff --git a/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp b/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp
index 593f3a0efb..f861eb37f2 100644
--- a/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp
+++ b/tests/auto/quick/qquickdroparea/tst_qquickdroparea.cpp
@@ -1,44 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtTest/QSignalSpy>
#include <QtGui/qstylehints.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickview.h>
+#include <QtQml/QQmlComponent>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlexpression.h>
#include <qpa/qplatformdrag.h>
#include <qpa/qwindowsysteminterface.h>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+
+using namespace Qt::StringLiterals;
template <typename T> static T evaluate(QObject *scope, const QString &expression)
{
@@ -60,9 +38,16 @@ template <> void evaluate<void>(QObject *scope, const QString &expression)
class tst_QQuickDropArea: public QQmlDataTest
{
Q_OBJECT
+
+public:
+ tst_QQuickDropArea();
+
private slots:
void containsDrag_internal();
void containsDrag_external();
+
+ void ignoreRetriggerEvent();
+
void keys_internal();
void keys_external();
void source_internal();
@@ -76,11 +61,17 @@ private slots:
void dropStuff();
void nestedDropAreas_data();
void nestedDropAreas();
+ void signalOrder();
private:
QQmlEngine engine;
};
+tst_QQuickDropArea::tst_QQuickDropArea()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
void tst_QQuickDropArea::containsDrag_internal()
{
QQuickWindow window;
@@ -819,6 +810,32 @@ void tst_QQuickDropArea::competingDrags()
QCOMPARE(evaluate<QString>(dropArea1, "statuslol"), QStringLiteral("parent"));
}
+void tst_QQuickDropArea::ignoreRetriggerEvent()
+{
+ QQuickView window;
+ QByteArray errorMessage;
+ QVERIFY2(QQuickTest::initView(window, testFileUrl("ignoreRetriggerEvent.qml"), true, &errorMessage), errorMessage.constData());
+
+ QQuickItem *dropArea = window.rootObject();
+ QVERIFY(dropArea);
+ QQuickItem *dragItem = dropArea->findChild<QQuickItem *>("dragItem");
+ QVERIFY(dragItem);
+
+ evaluate<void>(dragItem, "Drag.active = true");
+ // Drag the item within the drop area
+ dragItem->setPosition(QPointF(25, 25));
+ QCoreApplication::processEvents();
+ dragItem->setPosition(QPointF(50, 50));
+ QCoreApplication::processEvents();
+ dragItem->setPosition(QPointF(75, 75));
+ QCoreApplication::processEvents();
+
+ QCOMPARE(evaluate<bool>(dropArea, "containsDrag"), false);
+ QCOMPARE(evaluate<int>(dropArea, "enterEvents"), 1);
+ QCOMPARE(evaluate<int>(dropArea, "exitEvents"), 0);
+}
+
+
void tst_QQuickDropArea::simultaneousDrags()
{
QQuickWindow window;
@@ -949,8 +966,8 @@ void tst_QQuickDropArea::simultaneousDrags()
Qt::MouseButtons(), Qt::KeyboardModifiers());
//Same as in the first case, dropArea2 already contains a drag, dropArea1 will get the event
QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true);
- QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1);
- QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 0);
+ QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2);
+ QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1);
QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true);
QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0);
QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0);
@@ -958,8 +975,8 @@ void tst_QQuickDropArea::simultaneousDrags()
QWindowSystemInterface::handleDrag(&alternateWindow, &data, QPoint(50, 50), Qt::CopyAction,
Qt::MouseButtons(), Qt::KeyboardModifiers());
QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), false);
- QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 1);
- QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1);
+ QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2);
+ QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 2);
QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true);
QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0);
QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0);
@@ -967,16 +984,16 @@ void tst_QQuickDropArea::simultaneousDrags()
QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction,
Qt::MouseButtons(), Qt::KeyboardModifiers());
QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true);
- QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2);
- QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1);
+ QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 4);
+ QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 3);
QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), true);
QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0);
QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 0);
evaluate<void>(dragItem1, "Drag.active = false");
QCOMPARE(evaluate<bool>(dropArea1, "containsDrag"), true);
- QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 2);
- QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 1);
+ QCOMPARE(evaluate<int>(dropArea1, "enterEvents"), 4);
+ QCOMPARE(evaluate<int>(dropArea1, "exitEvents"), 3);
QCOMPARE(evaluate<bool>(dropArea2, "containsDrag"), false);
QCOMPARE(evaluate<int>(dropArea2, "enterEvents"), 0);
QCOMPARE(evaluate<int>(dropArea2, "exitEvents"), 1);
@@ -1190,9 +1207,14 @@ void tst_QQuickDropArea::dropStuff()
component.setData(
"import QtQuick 2.3\n"
"DropArea {\n"
+ "id: root\n"
"width: 100; height: 100\n"
"property var array\n"
- "onDropped: { array = drop.getDataAsArrayBuffer('text/x-red'); }\n"
+ "property string text\n"
+ "onDropped: {\n"
+ " root.array = drop.getDataAsArrayBuffer('text/x-red'); \n"
+ " root.text = drop.getDataAsString('text/x-red').arg('no-op'); \n"
+ "}\n"
"}", QUrl());
QScopedPointer<QObject> object(component.create());
@@ -1204,6 +1226,7 @@ void tst_QQuickDropArea::dropStuff()
data.setData("text/x-red", "red");
QCOMPARE(evaluate<QVariant>(dropArea, "array"), QVariant());
+ QCOMPARE(evaluate<QString>(dropArea, "text"), QString());
QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction,
Qt::MouseButtons(), Qt::KeyboardModifiers());
@@ -1211,6 +1234,7 @@ void tst_QQuickDropArea::dropStuff()
Qt::MouseButtons(), Qt::KeyboardModifiers());
QCOMPARE(evaluate<int>(dropArea, "array.byteLength"), 3);
QCOMPARE(evaluate<QByteArray>(dropArea, "array"), QByteArray("red"));
+ QCOMPARE(evaluate<QString>(dropArea, "text"), QString("red"));
}
void tst_QQuickDropArea::nestedDropAreas_data()
@@ -1281,6 +1305,48 @@ void tst_QQuickDropArea::nestedDropAreas()
QCOMPARE(window.rootObject()->property("innerExitEvents"), 2);
}
+void tst_QQuickDropArea::signalOrder()
+{
+ QQuickWindow window;
+ QQmlComponent component(&engine);
+ component.setData("import QtQuick\n"
+ "Item {\n"
+ " id: root\n"
+ " property var eventOrder: []\n"
+ " DropArea {\n"
+ " width: 100; height: 100\n"
+ " x: 0; y: 0\n"
+ " onEntered: eventOrder.push('entered1');\n"
+ " onExited: eventOrder.push('exited1');\n"
+ " }\n"
+ " DropArea {\n"
+ " width: 100; height: 100\n"
+ " x: 0; y: 100\n"
+ " onEntered: eventOrder.push('entered2');\n"
+ " onExited: eventOrder.push('exited2');\n"
+ " }\n"
+ "}",
+ QUrl());
+
+ QScopedPointer<QObject> object(component.create());
+ QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
+ QVERIFY(item);
+ item->setParentItem(window.contentItem());
+
+ QMimeData data;
+
+ QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 50), Qt::CopyAction,
+ Qt::MouseButtons(), Qt::KeyboardModifiers());
+ QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 150), Qt::CopyAction,
+ Qt::MouseButtons(), Qt::KeyboardModifiers());
+ QWindowSystemInterface::handleDrag(&window, &data, QPoint(50, 250), Qt::CopyAction,
+ Qt::MouseButtons(), Qt::KeyboardModifiers());
+
+ const QList<QVariant> eventOrder = item->property("eventOrder").toList();
+ QCOMPARE(eventOrder,
+ QList<QVariant>({ u"entered1"_s, u"exited1"_s, u"entered2"_s, u"exited2"_s }));
+}
+
QTEST_MAIN(tst_QQuickDropArea)
#include "tst_qquickdroparea.moc"
diff --git a/tests/auto/quick/qquickdynamicpropertyanimation/CMakeLists.txt b/tests/auto/quick/qquickdynamicpropertyanimation/CMakeLists.txt
index 78395e4661..b9834a7a72 100644
--- a/tests/auto/quick/qquickdynamicpropertyanimation/CMakeLists.txt
+++ b/tests/auto/quick/qquickdynamicpropertyanimation/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickdynamicpropertyanimation.pro.
#####################################################################
## tst_qquickdynamicpropertyanimation Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickdynamicpropertyanimation LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,14 +21,12 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickdynamicpropertyanimation
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickdynamicpropertyanimation.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Qml
Qt::Quick
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -28,10 +35,10 @@ qt_internal_add_test(tst_qquickdynamicpropertyanimation
qt_internal_extend_target(tst_qquickdynamicpropertyanimation CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickdynamicpropertyanimation CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickdynamicpropertyanimation/tst_qquickdynamicpropertyanimation.cpp b/tests/auto/quick/qquickdynamicpropertyanimation/tst_qquickdynamicpropertyanimation.cpp
index 07658a5418..85ff58fd4d 100644
--- a/tests/auto/quick/qquickdynamicpropertyanimation/tst_qquickdynamicpropertyanimation.cpp
+++ b/tests/auto/quick/qquickdynamicpropertyanimation/tst_qquickdynamicpropertyanimation.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtQml/QQmlEngine>
#include <QtQml/QQmlProperty>
@@ -36,13 +11,13 @@
#include <QtCore/QRect>
#include <QtGui/QColor>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
class tst_qquickdynamicpropertyanimation : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickdynamicpropertyanimation() {}
+ tst_qquickdynamicpropertyanimation() : QQmlDataTest(QT_QMLTEST_DATADIR) {}
private:
template<class T>
@@ -64,7 +39,7 @@ private:
}
private slots:
- void initTestCase()
+ void initTestCase() override
{
QQmlEngine engine; // ensure types are registered
QQmlDataTest::initTestCase();
diff --git a/tests/auto/quick/qquickflickable/BLACKLIST b/tests/auto/quick/qquickflickable/BLACKLIST
index 2430735613..d35ddb9e3f 100644
--- a/tests/auto/quick/qquickflickable/BLACKLIST
+++ b/tests/auto/quick/qquickflickable/BLACKLIST
@@ -1,5 +1,14 @@
[movingAndFlicking]
macos-11
+opensuse-leap # QTBUG-118060
[flickVelocity]
macos-11
+
+# QTBUG-118060
+[ignoreNonLeftMouseButtons]
+opensuse-leap
+
+# QTBUG-118063
+[nativeGesturePinchOnFlickableWithParentTapHandler]
+opensuse-leap
diff --git a/tests/auto/quick/qquickflickable/CMakeLists.txt b/tests/auto/quick/qquickflickable/CMakeLists.txt
index 7c8e802daf..e46378188d 100644
--- a/tests/auto/quick/qquickflickable/CMakeLists.txt
+++ b/tests/auto/quick/qquickflickable/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickflickable.pro.
#####################################################################
## tst_qquickflickable Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickflickable LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickflickable
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickflickable.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,10 +37,10 @@ qt_internal_add_test(tst_qquickflickable
qt_internal_extend_target(tst_qquickflickable CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickflickable CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickflickable/data/contentPosWhileDragging.qml b/tests/auto/quick/qquickflickable/data/contentPosWhileDragging.qml
new file mode 100644
index 0000000000..b42fbc1adb
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/contentPosWhileDragging.qml
@@ -0,0 +1,24 @@
+import QtQuick
+import QtQuick.Shapes
+import QtQuick.Controls
+
+Item {
+ id: root
+ width: 500
+ height: 500
+ Flickable {
+ anchors.centerIn: parent
+ width: 100
+ height: 100
+ clip: true
+ contentWidth: content.width
+ contentHeight: content.height
+ Rectangle {
+ id: content
+ width: 320
+ height: width
+ color: "#41cd52"
+ radius: width/2
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickflickable/data/dragon.qml b/tests/auto/quick/qquickflickable/data/dragon.qml
new file mode 100644
index 0000000000..b82477453b
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/dragon.qml
@@ -0,0 +1,15 @@
+import QtQuick 2.12
+
+Flickable {
+ id: flick
+ width: 320
+ height: 320
+ contentWidth: 500
+ contentHeight: 500
+ Text {
+ anchors.centerIn: parent
+ font.pixelSize: 50
+ text: "ðŸ‰"
+ color: flick.dragging ? "orange" : "grey"
+ }
+}
diff --git a/tests/auto/quick/qquickflickable/data/endpoints.qml b/tests/auto/quick/qquickflickable/data/endpoints.qml
new file mode 100644
index 0000000000..80caa32da5
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/endpoints.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Flickable {
+ width: 100; height: 100
+ contentWidth: row.width; contentHeight: row.height
+
+ Row {
+ id: row
+ Repeater {
+ model: 4
+ Rectangle { width: 200; height: 300; color: "blue" }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickflickable/data/flickableWithTapHandler.qml b/tests/auto/quick/qquickflickable/data/flickableWithTapHandler.qml
new file mode 100644
index 0000000000..91b81059ab
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/flickableWithTapHandler.qml
@@ -0,0 +1,24 @@
+import QtQuick
+
+Item {
+ width: 300
+ height: 300
+
+ Flickable {
+ anchors.fill: parent
+ anchors.topMargin: 100
+ contentWidth: 1000
+ contentHeight: 1000
+
+ Rectangle {
+ objectName: "childItem"
+ x: 20
+ y: 50
+ width: 20
+ height: 20
+ color: "red"
+ TapHandler {
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickflickable/data/fractionalExtent.qml b/tests/auto/quick/qquickflickable/data/fractionalExtent.qml
new file mode 100644
index 0000000000..2675e8c85a
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/fractionalExtent.qml
@@ -0,0 +1,14 @@
+import QtQuick
+
+Flickable {
+ width: 300
+ height: 300
+ contentWidth: content.width; contentHeight: content.height
+ Rectangle {
+ id: content
+ width: 350
+ height: 350
+ color: "darkkhaki"
+ }
+ boundsBehavior: Flickable.StopAtBounds
+}
diff --git a/tests/auto/quick/qquickflickable/data/nested.qml b/tests/auto/quick/qquickflickable/data/nested.qml
index c306bfab23..0cbeb5cef3 100644
--- a/tests/auto/quick/qquickflickable/data/nested.qml
+++ b/tests/auto/quick/qquickflickable/data/nested.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
Flickable {
diff --git a/tests/auto/quick/qquickflickable/data/nestedmouseareapce.qml b/tests/auto/quick/qquickflickable/data/nestedmouseareapce.qml
new file mode 100644
index 0000000000..b36df04d45
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/nestedmouseareapce.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.0
+
+Flickable {
+ id: outer
+ objectName: "flickable"
+ width: 400
+ height: 400
+ contentX: 50
+ contentY: 50
+ contentWidth: 500
+ contentHeight: 500
+
+ Rectangle {
+ objectName: "nested"
+ x: 100
+ y: 100
+ width: 300
+ height: 300
+
+ color: "yellow"
+ MouseArea {
+ anchors.fill: parent
+ propagateComposedEvents: true
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickflickable/data/overshoot.qml b/tests/auto/quick/qquickflickable/data/overshoot.qml
index f08460a413..baa1bfea01 100644
--- a/tests/auto/quick/qquickflickable/data/overshoot.qml
+++ b/tests/auto/quick/qquickflickable/data/overshoot.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.9
diff --git a/tests/auto/quick/qquickflickable/data/overshoot_reentrant.qml b/tests/auto/quick/qquickflickable/data/overshoot_reentrant.qml
index bc7abba25a..7bbe45907c 100644
--- a/tests/auto/quick/qquickflickable/data/overshoot_reentrant.qml
+++ b/tests/auto/quick/qquickflickable/data/overshoot_reentrant.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.9
diff --git a/tests/auto/quick/qquickflickable/data/parallel.qml b/tests/auto/quick/qquickflickable/data/parallel.qml
index 4259173e9f..8e7f64a84e 100644
--- a/tests/auto/quick/qquickflickable/data/parallel.qml
+++ b/tests/auto/quick/qquickflickable/data/parallel.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickflickable/data/pressDelay.qml b/tests/auto/quick/qquickflickable/data/pressDelay.qml
index a69c4af6de..97bc6b794f 100644
--- a/tests/auto/quick/qquickflickable/data/pressDelay.qml
+++ b/tests/auto/quick/qquickflickable/data/pressDelay.qml
@@ -1,4 +1,4 @@
-import QtQuick 2.0
+import QtQuick
Flickable {
flickableDirection: Flickable.VerticalFlick
@@ -15,7 +15,6 @@ Flickable {
MouseArea {
id: ma
- objectName: "mouseArea"
y: 100
anchors.horizontalCenter: parent.horizontalCenter
width: 240
@@ -32,14 +31,7 @@ Flickable {
Rectangle {
anchors.fill: parent
- color: parent.pressed ? 'blue' : 'green'
-
- Text {
- anchors.fill: parent
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignHCenter
- text: 'Hello'
- }
+ color: parent.pressed ? 'blue' : 'lightsteelblue'
}
}
}
diff --git a/tests/auto/quick/qquickflickable/data/ratios.qml b/tests/auto/quick/qquickflickable/data/ratios.qml
index a31ab371cd..7983b797fe 100644
--- a/tests/auto/quick/qquickflickable/data/ratios.qml
+++ b/tests/auto/quick/qquickflickable/data/ratios.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickflickable/data/rotatedFlickable.qml b/tests/auto/quick/qquickflickable/data/rotatedFlickable.qml
new file mode 100644
index 0000000000..04816c178b
--- /dev/null
+++ b/tests/auto/quick/qquickflickable/data/rotatedFlickable.qml
@@ -0,0 +1,32 @@
+import QtQuick 2.0
+
+Item {
+ width: 300
+ height: 300
+
+ Flickable {
+ id: flickable
+ anchors.fill: parent
+ contentHeight: column.height
+ flickDeceleration: 5000 // speed up the test run
+
+ Column {
+ id: column
+ width: parent.width
+
+ Repeater {
+ model: 255
+
+ delegate: Rectangle {
+ width: column.width
+ height: 50
+ color: "gray"
+ Text {
+ anchors.centerIn: parent
+ text: index
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml b/tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml
index 6f7bc89793..a52f612af7 100644
--- a/tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml
+++ b/tests/auto/quick/qquickflickable/data/visibleAreaBinding.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.14
diff --git a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
index b7a1848949..b003511356 100644
--- a/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
+++ b/tests/auto/quick/qquickflickable/tst_qquickflickable.cpp
@@ -1,53 +1,33 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include <qtest.h>
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
#include <QtTest/QSignalSpy>
+#include <QtQuick/qquickview.h>
+#include <QtQuickTest/QtQuickTest>
#include <QtGui/QStyleHints>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
-#include <QtQuick/qquickview.h>
+#include <private/qguiapplication_p.h>
#include <private/qquickflickable_p.h>
#include <private/qquickflickable_p_p.h>
#include <private/qquickmousearea_p.h>
#include <private/qquicktransition_p.h>
#include <private/qqmlvaluetype_p.h>
+#include <private/qquicktaphandler_p.h>
#include <math.h>
-#include "../../shared/util.h"
-#include "../shared/geometrytestutil.h"
-#include "../shared/viewtestutil.h"
-#include "../shared/visualtestutil.h"
+#include <QtGui/qpa/qplatformintegration.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/geometrytestutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <qpa/qwindowsysteminterface.h>
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
-using namespace QQuickViewTestUtil;
-using namespace QQuickVisualTestUtil;
+using namespace QQuickViewTestUtils;
+using namespace QQuickVisualTestUtils;
// an abstract Slider which only handles touch events
class TouchDragArea : public QQuickItem
@@ -95,7 +75,7 @@ public:
protected:
void touchEvent(QTouchEvent *ev) override
{
- QCOMPARE(ev->points().count(), 1);
+ QCOMPARE(ev->points().size(), 1);
auto touchpoint = ev->points().first();
switch (touchpoint.state()) {
case QEventPoint::State::Pressed:
@@ -142,11 +122,38 @@ private:
bool m_active;
};
+class FlickableWithExtents : public QQuickFlickable
+{
+public:
+ qreal extent = 10;
+
+ qreal minXExtent() const override
+ {
+ return QQuickFlickable::minXExtent() + extent;
+ }
+
+ qreal maxXExtent() const override
+ {
+ return QQuickFlickable::maxXExtent() + extent;
+ }
+
+ qreal minYExtent() const override
+ {
+ return QQuickFlickable::minYExtent() + extent;
+ }
+
+ qreal maxYExtent() const override
+ {
+ return QQuickFlickable::maxYExtent() + extent;
+ }
+};
+
class tst_qquickflickable : public QQmlDataTest
{
Q_OBJECT
public:
tst_qquickflickable()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{}
private slots:
@@ -160,6 +167,7 @@ private slots:
void rebound();
void maximumFlickVelocity();
void flickDeceleration();
+ void pressDelay_data();
void pressDelay();
void nestedPressDelay();
void filterReplayedPress();
@@ -169,6 +177,7 @@ private slots:
void returnToBounds();
void returnToBounds_data();
void wheel();
+ void wheelBackwards();
void trackpad();
void nestedTrackpad();
void movingAndFlicking();
@@ -177,6 +186,7 @@ private slots:
void movingAndDragging_data();
void flickOnRelease();
void pressWhileFlicking();
+ void dragWhileFlicking();
void disabled();
void flickVelocity();
void margins();
@@ -189,6 +199,7 @@ private slots:
void stopAtBounds();
void stopAtBounds_data();
void nestedMouseAreaUsingTouch();
+ void nestedMouseAreaPropagateComposedEvents();
void nestedSliderUsingTouch();
void nestedSliderUsingTouch_data();
void pressDelayWithLoader();
@@ -205,16 +216,40 @@ private slots:
void synchronousDrag();
void visibleAreaBinding();
void parallelTouch();
+ void ignoreNonLeftMouseButtons();
+ void ignoreNonLeftMouseButtons_data();
+ void receiveTapOutsideContentItem();
+ void flickWhenRotated_data();
+ void flickWhenRotated();
+ void flickAndReleaseOutsideBounds();
+ void scrollingWithFractionalExtentSize_data();
+ void scrollingWithFractionalExtentSize();
+ void setContentPositionWhileDragging_data();
+ void setContentPositionWhileDragging();
+ void coalescedMove();
+ void onlyOneMove();
+ void proportionalWheelScrolling();
+ void touchCancel();
+ void pixelAlignedEndPoints();
private:
void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to);
QPointingDevice *touchDevice = QTest::createTouchDevice();
+ const QPointingDevice *mouseDevice = new QPointingDevice(
+ "test mouse", 1000, QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic,
+ QInputDevice::Capability::Position | QInputDevice::Capability::Hover | QInputDevice::Capability::Scroll,
+ 1, 5, QString(), QPointingDeviceUniqueId(), this);
};
void tst_qquickflickable::initTestCase()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("test crashes at unknown location in Android");
+#endif
QQmlDataTest::initTestCase();
qmlRegisterType<TouchDragArea>("Test",1,0,"TouchDragArea");
+ touchDevice->setParent(this); // avoid leak
+ QWindowSystemInterface::registerInputDevice(mouseDevice);
}
void tst_qquickflickable::cleanup()
@@ -335,27 +370,27 @@ void tst_qquickflickable::boundsBehavior()
flickable->setBoundsBehavior(QQuickFlickable::DragAndOvershootBounds);
QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::DragAndOvershootBounds);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
flickable->setBoundsBehavior(QQuickFlickable::DragAndOvershootBounds);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
flickable->setBoundsBehavior(QQuickFlickable::DragOverBounds);
QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::DragOverBounds);
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
flickable->setBoundsBehavior(QQuickFlickable::DragOverBounds);
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
flickable->setBoundsBehavior(QQuickFlickable::StopAtBounds);
QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::StopAtBounds);
- QCOMPARE(spy.count(),3);
+ QCOMPARE(spy.size(),3);
flickable->setBoundsBehavior(QQuickFlickable::StopAtBounds);
- QCOMPARE(spy.count(),3);
+ QCOMPARE(spy.size(),3);
flickable->setBoundsBehavior(QQuickFlickable::OvershootBounds);
QCOMPARE(flickable->boundsBehavior(), QQuickFlickable::OvershootBounds);
- QCOMPARE(spy.count(),4);
+ QCOMPARE(spy.size(),4);
flickable->setBoundsBehavior(QQuickFlickable::OvershootBounds);
- QCOMPARE(spy.count(),4);
+ QCOMPARE(spy.size(),4);
delete flickable;
}
@@ -365,8 +400,8 @@ void tst_qquickflickable::rebound()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("rebound.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -388,23 +423,23 @@ void tst_qquickflickable::rebound()
flick(window.data(), QPoint(20,20), QPoint(120,120), 200);
QTRY_COMPARE(window->rootObject()->property("transitionsStarted").toInt(), 2);
- QCOMPARE(hMoveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), 1);
- QCOMPARE(movementStartedSpy.count(), 1);
- QCOMPARE(movementEndedSpy.count(), 0);
+ QCOMPARE(hMoveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), 1);
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 0);
QVERIFY(rebound->running());
QTRY_VERIFY(!flickable->isMoving());
QCOMPARE(flickable->contentX(), 0.0);
QCOMPARE(flickable->contentY(), 0.0);
- QCOMPARE(hMoveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), 2);
- QCOMPARE(movementStartedSpy.count(), 1);
- QCOMPARE(movementEndedSpy.count(), 1);
+ QCOMPARE(hMoveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), 2);
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 1);
QCOMPARE(window->rootObject()->property("transitionsStarted").toInt(), 2);
QVERIFY(!rebound->running());
- QCOMPARE(reboundSpy.count(), 2);
+ QCOMPARE(reboundSpy.size(), 2);
hMoveSpy.clear();
vMoveSpy.clear();
@@ -420,19 +455,19 @@ void tst_qquickflickable::rebound()
QVERIFY(flickable->isMoving());
QTRY_VERIFY(window->rootObject()->property("transitionsStarted").toInt() >= 1);
- QCOMPARE(hMoveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), 1);
- QCOMPARE(movementStartedSpy.count(), 1);
+ QCOMPARE(hMoveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), 1);
+ QCOMPARE(movementStartedSpy.size(), 1);
QTRY_VERIFY(!flickable->isMoving());
QCOMPARE(flickable->contentX(), 0.0);
// moving started/stopped signals should only have been emitted once,
// and when they are, all transitions should have finished
- QCOMPARE(hMoveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), 2);
- QCOMPARE(movementStartedSpy.count(), 1);
- QCOMPARE(movementEndedSpy.count(), 1);
+ QCOMPARE(hMoveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), 2);
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 1);
hMoveSpy.clear();
vMoveSpy.clear();
@@ -447,16 +482,16 @@ void tst_qquickflickable::rebound()
flick(window.data(), QPoint(20,20), QPoint(120,120), 200);
QCOMPARE(window->rootObject()->property("transitionsStarted").toInt(), 0);
- QCOMPARE(hMoveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), 1);
- QCOMPARE(movementStartedSpy.count(), 1);
- QCOMPARE(movementEndedSpy.count(), 0);
+ QCOMPARE(hMoveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), 1);
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 0);
QTRY_VERIFY(!flickable->isMoving());
- QCOMPARE(hMoveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), 2);
- QCOMPARE(movementStartedSpy.count(), 1);
- QCOMPARE(movementEndedSpy.count(), 1);
+ QCOMPARE(hMoveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), 2);
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 1);
QCOMPARE(window->rootObject()->property("transitionsStarted").toInt(), 0);
}
@@ -473,9 +508,9 @@ void tst_qquickflickable::maximumFlickVelocity()
flickable->setMaximumFlickVelocity(2.0);
QCOMPARE(flickable->maximumFlickVelocity(), 2.0);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
flickable->setMaximumFlickVelocity(2.0);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
delete flickable;
}
@@ -493,52 +528,61 @@ void tst_qquickflickable::flickDeceleration()
flickable->setFlickDeceleration(2.0);
QCOMPARE(flickable->flickDeceleration(), 2.0);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
flickable->setFlickDeceleration(2.0);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
delete flickable;
}
+void tst_qquickflickable::pressDelay_data()
+{
+ QTest::addColumn<const QPointingDevice *>("device");
+ const QPointingDevice *constTouchDevice = touchDevice;
+
+ QTest::newRow("mouse") << mouseDevice;
+ QTest::newRow("touch") << constTouchDevice;
+}
+
void tst_qquickflickable::pressDelay()
{
- QScopedPointer<QQuickView> window(new QQuickView);
- window->setSource(testFileUrl("pressDelay.qml"));
- QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
- window->show();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QVERIFY(window->rootObject() != nullptr);
+ QFETCH(const QPointingDevice *, device);
- QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
- QSignalSpy spy(flickable, SIGNAL(pressDelayChanged()));
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("pressDelay.qml")));
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window.rootObject());
QVERIFY(flickable);
- QCOMPARE(flickable->pressDelay(), 100);
+ QQuickMouseArea *mouseArea = flickable->findChild<QQuickMouseArea*>();
+ QSignalSpy clickedSpy(mouseArea, &QQuickMouseArea::clicked);
+ // Test the pressDelay property itself
+ QSignalSpy pressDelayChangedSpy(flickable, &QQuickFlickable::pressDelayChanged);
+ QCOMPARE(flickable->pressDelay(), 100);
flickable->setPressDelay(200);
QCOMPARE(flickable->pressDelay(), 200);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(pressDelayChangedSpy.size(), 1);
flickable->setPressDelay(200);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(pressDelayChangedSpy.size(), 1);
- QQuickItem *mouseArea = window->rootObject()->findChild<QQuickItem*>("mouseArea");
- QSignalSpy clickedSpy(mouseArea, SIGNAL(clicked(QQuickMouseEvent*)));
- moveAndPress(window.data(), QPoint(150, 150));
+ // Test the press delay
+ QPoint p(150, 150);
+ if (device->type() == QInputDevice::DeviceType::Mouse)
+ QQuickTest::pointerMove(device, &window, 0, p);
+ QQuickTest::pointerPress(device, &window, 0, p);
// The press should not occur immediately
- QVERIFY(!mouseArea->property("pressed").toBool());
+ QCOMPARE(mouseArea->isPressed(), false);
// But, it should occur eventually
- QTRY_VERIFY(mouseArea->property("pressed").toBool());
+ QTRY_VERIFY(mouseArea->isPressed());
- QCOMPARE(clickedSpy.count(),0);
+ QCOMPARE(clickedSpy.size(), 0);
// On release the clicked signal should be emitted
- QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 150));
- QCOMPARE(clickedSpy.count(),1);
+ QQuickTest::pointerRelease(device, &window, 0, p);
+ QCOMPARE(clickedSpy.size(), 1);
// Press and release position should match
QCOMPARE(flickable->property("pressX").toReal(), flickable->property("releaseX").toReal());
@@ -546,38 +590,44 @@ void tst_qquickflickable::pressDelay()
// Test a quick tap within the pressDelay timeout
+ p = QPoint(180, 180);
clickedSpy.clear();
- moveAndPress(window.data(), QPoint(180, 180));
+ if (device->type() == QInputDevice::DeviceType::Mouse)
+ QQuickTest::pointerMove(device, &window, 0, p);
+ QQuickTest::pointerPress(device, &window, 0, p);
// The press should not occur immediately
- QVERIFY(!mouseArea->property("pressed").toBool());
+ QCOMPARE(mouseArea->isPressed(), false);
+ QCOMPARE(clickedSpy.size(), 0);
- QCOMPARE(clickedSpy.count(),0);
-
- // On release the press, release and clicked signal should be emitted
- QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(180, 180));
- QCOMPARE(clickedSpy.count(),1);
+ // On release, the press, release and clicked signal should be emitted
+ QQuickTest::pointerRelease(device, &window, 0, p);
+ QCOMPARE(clickedSpy.size(), 1);
// Press and release position should match
QCOMPARE(flickable->property("pressX").toReal(), flickable->property("releaseX").toReal());
QCOMPARE(flickable->property("pressY").toReal(), flickable->property("releaseY").toReal());
- // QTBUG-31168
- moveAndPress(window.data(), QPoint(150, 110));
+ // Test flick after press (QTBUG-31168)
+ QPoint startPosition(150, 110);
+ p = QPoint(150, 190);
+ clickedSpy.clear();
+ if (device->type() == QInputDevice::DeviceType::Mouse)
+ QQuickTest::pointerMove(device, &window, 0, startPosition);
+ QQuickTest::pointerPress(device, &window, 0, startPosition);
// The press should not occur immediately
- QVERIFY(!mouseArea->property("pressed").toBool());
+ QCOMPARE(mouseArea->isPressed(), false);
+ QQuickTest::pointerMove(device, &window, 0, p);
- QTest::mouseMove(window.data(), QPoint(150, 190));
+ // Since we moved past the drag threshold, we should never receive the press
+ QCOMPARE(mouseArea->isPressed(), false);
+ QTRY_COMPARE(mouseArea->isPressed(), false);
- // As we moved pass the drag threshold, we should never receive the press
- QVERIFY(!mouseArea->property("pressed").toBool());
- QTRY_VERIFY(!mouseArea->property("pressed").toBool());
-
- // On release the clicked signal should *not* be emitted
- QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(150, 190));
- QCOMPARE(clickedSpy.count(),1);
+ // On release, the clicked signal should *not* be emitted
+ QQuickTest::pointerRelease(device, &window, 0, p);
+ QCOMPARE(clickedSpy.size(), 0);
}
// QTBUG-17361
@@ -586,8 +636,8 @@ void tst_qquickflickable::nestedPressDelay()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("nestedPressDelay.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -666,8 +716,8 @@ void tst_qquickflickable::filterReplayedPress()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("nestedPressDelay.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -709,8 +759,8 @@ void tst_qquickflickable::nestedClickThenFlick()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("nestedClickThenFlick.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -761,19 +811,19 @@ void tst_qquickflickable::flickableDirection()
flickable->setFlickableDirection(QQuickFlickable::HorizontalAndVerticalFlick);
QCOMPARE(flickable->flickableDirection(), QQuickFlickable::HorizontalAndVerticalFlick);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
flickable->setFlickableDirection(QQuickFlickable::AutoFlickDirection);
QCOMPARE(flickable->flickableDirection(), QQuickFlickable::AutoFlickDirection);
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick);
QCOMPARE(flickable->flickableDirection(), QQuickFlickable::HorizontalFlick);
- QCOMPARE(spy.count(),3);
+ QCOMPARE(spy.size(),3);
flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick);
QCOMPARE(flickable->flickableDirection(), QQuickFlickable::HorizontalFlick);
- QCOMPARE(spy.count(),3);
+ QCOMPARE(spy.size(),3);
delete flickable;
}
@@ -846,7 +896,7 @@ void tst_qquickflickable::returnToBounds()
QTRY_COMPARE(obj->contentY(), 0.);
QVERIFY(!rebound->running());
- QCOMPARE(reboundSpy.count(), setRebound ? 2 : 0);
+ QCOMPARE(reboundSpy.size(), setRebound ? 2 : 0);
}
void tst_qquickflickable::returnToBounds_data()
@@ -869,6 +919,7 @@ void tst_qquickflickable::wheel()
QVERIFY(flick != nullptr);
QQuickFlickablePrivate *fp = QQuickFlickablePrivate::get(flick);
QSignalSpy moveEndSpy(flick, SIGNAL(movementEnded()));
+ quint64 timestamp = 10;
// test a vertical flick
{
@@ -876,16 +927,18 @@ void tst_qquickflickable::wheel()
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(0,-120),
Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
event.setAccepted(false);
+ event.setTimestamp(timestamp);
QGuiApplication::sendEvent(window.data(), &event);
}
QTRY_VERIFY(flick->contentY() > 0);
QCOMPARE(flick->contentX(), qreal(0));
- QTRY_COMPARE(moveEndSpy.count(), 1);
+ QTRY_COMPARE(moveEndSpy.size(), 1);
QCOMPARE(fp->velocityTimeline.isActive(), false);
QCOMPARE(fp->timeline.isActive(), false);
QTest::qWait(50); // make sure that onContentYChanged won't sneak in again
+ timestamp += 50;
QCOMPARE(flick->property("movementsAfterEnd").value<int>(), 0); // QTBUG-55886
// get ready to test horizontal flick
@@ -899,20 +952,61 @@ void tst_qquickflickable::wheel()
QPoint pos(200, 200);
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), QPoint(-120,0),
Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
-
event.setAccepted(false);
+ event.setTimestamp(timestamp);
QGuiApplication::sendEvent(window.data(), &event);
}
QTRY_VERIFY(flick->contentX() > 0);
QCOMPARE(flick->contentY(), qreal(0));
- QTRY_COMPARE(moveEndSpy.count(), 2);
+ QTRY_COMPARE(moveEndSpy.size(), 2);
QCOMPARE(fp->velocityTimeline.isActive(), false);
QCOMPARE(fp->timeline.isActive(), false);
QTest::qWait(50); // make sure that onContentXChanged won't sneak in again
QCOMPARE(flick->property("movementsAfterEnd").value<int>(), 0); // QTBUG-55886
}
+void tst_qquickflickable::wheelBackwards() // (QTBUG-121349)
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("wheel.qml")));
+ QQuickFlickable *flick = window.rootObject()->findChild<QQuickFlickable*>("flick");
+ QVERIFY(flick);
+ QSignalSpy moveEndSpy(flick, SIGNAL(movementEnded()));
+ quint64 timestamp = 10;
+ const QPoint pos(200, 200);
+
+ // attempting to scroll vertically "backwards" beyond extents does not initiate overshoot
+ {
+ QWheelEvent event(pos, window.mapToGlobal(pos), QPoint(), QPoint(0, 120),
+ Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
+ event.setAccepted(false);
+ event.setTimestamp(timestamp++);
+ QGuiApplication::sendEvent(&window, &event);
+ }
+ QCOMPARE(flick->contentY(), qreal(0));
+ QCOMPARE(flick->isMoving(), false);
+ QCOMPARE(moveEndSpy.size(), 0);
+
+ // get ready to test horizontal wheel
+ flick->setContentY(0); // which triggers movementEnded again
+ flick->setProperty("movementsAfterEnd", 0);
+ flick->setProperty("ended", false);
+ QCOMPARE(flick->contentY(), qreal(0));
+
+ // attempting to scroll horizontally "backwards" beyond extents does not initiate overshoot
+ {
+ QWheelEvent event(pos, window.mapToGlobal(pos), QPoint(), QPoint(120, 0),
+ Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
+ event.setAccepted(false);
+ event.setTimestamp(timestamp);
+ QGuiApplication::sendEvent(&window, &event);
+ }
+ QCOMPARE(flick->contentX(), qreal(0));
+ QCOMPARE(flick->isMoving(), false);
+ QCOMPARE(moveEndSpy.size(), 0);
+}
+
void tst_qquickflickable::trackpad()
{
QScopedPointer<QQuickView> window(new QQuickView);
@@ -925,11 +1019,13 @@ void tst_qquickflickable::trackpad()
QVERIFY(flick != nullptr);
QSignalSpy moveEndSpy(flick, SIGNAL(movementEnded()));
QPoint pos(200, 200);
+ quint64 timestamp = 10;
{
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,-100), QPoint(0,-120),
Qt::NoButton, Qt::NoModifier, Qt::ScrollBegin, false);
event.setAccepted(false);
+ event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(window.data(), &event);
}
@@ -943,6 +1039,7 @@ void tst_qquickflickable::trackpad()
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(-100,0), QPoint(-120,0),
Qt::NoButton, Qt::NoModifier, Qt::ScrollUpdate, false);
event.setAccepted(false);
+ event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(window.data(), &event);
}
@@ -953,10 +1050,11 @@ void tst_qquickflickable::trackpad()
QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(0,0), QPoint(0,0),
Qt::NoButton, Qt::NoModifier, Qt::ScrollEnd, false);
event.setAccepted(false);
+ event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(window.data(), &event);
}
- QTRY_COMPARE(moveEndSpy.count(), 1); // QTBUG-55871
+ QTRY_COMPARE(moveEndSpy.size(), 1); // QTBUG-55871
QCOMPARE(flick->property("movementsAfterEnd").value<int>(), 0); // QTBUG-55886
}
@@ -993,7 +1091,7 @@ void tst_qquickflickable::nestedTrackpad()
event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(&window, &event);
}
- QTRY_COMPARE(innerMoveEndSpy.count(), 1);
+ QTRY_COMPARE(innerMoveEndSpy.size(), 1);
innerFlickable->setContentX(0);
QCOMPARE(innerFlickable->contentX(), qreal(0));
@@ -1017,7 +1115,7 @@ void tst_qquickflickable::nestedTrackpad()
event.setTimestamp(timestamp++);
QGuiApplication::sendEvent(&window, &event);
}
- QTRY_COMPARE(outerMoveEndSpy.count(), 1);
+ QTRY_COMPARE(outerMoveEndSpy.size(), 1);
}
void tst_qquickflickable::movingAndFlicking_data()
@@ -1055,8 +1153,8 @@ void tst_qquickflickable::movingAndFlicking()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("flickable03.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -1089,15 +1187,15 @@ void tst_qquickflickable::movingAndFlicking()
QCOMPARE(flickable->property("movingInContentX").value<bool>(), true);
QCOMPARE(flickable->property("movingInContentY").value<bool>(), true);
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
- QCOMPARE(flickSpy.count(), 1);
- QCOMPARE(vFlickSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(moveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(flickSpy.size(), 1);
+ QCOMPARE(vFlickSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hFlickSpy.size(), horizontalEnabled ? 1 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(flickStartSpy.count(), 1);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(flickStartSpy.size(), 1);
// wait for any motion to end
QTRY_VERIFY(!flickable->isMoving());
@@ -1108,17 +1206,17 @@ void tst_qquickflickable::movingAndFlicking()
QVERIFY(!flickable->isFlickingHorizontally());
QVERIFY(!flickable->isFlickingVertically());
- QCOMPARE(moveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0);
- QCOMPARE(flickSpy.count(), 2);
- QCOMPARE(vFlickSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(moveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(flickSpy.size(), 2);
+ QCOMPARE(vFlickSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hFlickSpy.size(), horizontalEnabled ? 2 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 1);
- QCOMPARE(flickStartSpy.count(), 1);
- QCOMPARE(flickEndSpy.count(), 1);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 1);
+ QCOMPARE(flickStartSpy.size(), 1);
+ QCOMPARE(flickEndSpy.size(), 1);
// Stop on a full pixel after user interaction
if (verticalEnabled)
@@ -1145,17 +1243,17 @@ void tst_qquickflickable::movingAndFlicking()
QCOMPARE(flickable->isFlickingHorizontally(), horizontalEnabled);
QCOMPARE(flickable->isFlickingVertically(), verticalEnabled);
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
- QCOMPARE(flickSpy.count(), 1);
- QCOMPARE(vFlickSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(moveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(flickSpy.size(), 1);
+ QCOMPARE(vFlickSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hFlickSpy.size(), horizontalEnabled ? 1 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 0);
- QCOMPARE(flickStartSpy.count(), 1);
- QCOMPARE(flickEndSpy.count(), 0);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 0);
+ QCOMPARE(flickStartSpy.size(), 1);
+ QCOMPARE(flickEndSpy.size(), 0);
// wait for any motion to end
QTRY_VERIFY(!flickable->isMoving());
@@ -1166,17 +1264,17 @@ void tst_qquickflickable::movingAndFlicking()
QVERIFY(!flickable->isFlickingHorizontally());
QVERIFY(!flickable->isFlickingVertically());
- QCOMPARE(moveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0);
- QCOMPARE(flickSpy.count(), 2);
- QCOMPARE(vFlickSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hFlickSpy.count(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(moveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(flickSpy.size(), 2);
+ QCOMPARE(vFlickSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hFlickSpy.size(), horizontalEnabled ? 2 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 1);
- QCOMPARE(flickStartSpy.count(), 1);
- QCOMPARE(flickEndSpy.count(), 1);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 1);
+ QCOMPARE(flickStartSpy.size(), 1);
+ QCOMPARE(flickEndSpy.size(), 1);
QCOMPARE(flickable->contentX(), 0.0);
QCOMPARE(flickable->contentY(), 0.0);
@@ -1218,8 +1316,8 @@ void tst_qquickflickable::movingAndDragging()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("flickable03.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -1257,26 +1355,26 @@ void tst_qquickflickable::movingAndDragging()
QCOMPARE(flickable->property("draggingInContentX").value<bool>(), true);
QCOMPARE(flickable->property("draggingInContentY").value<bool>(), true);
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
- QCOMPARE(dragSpy.count(), 1);
- QCOMPARE(vDragSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hDragSpy.count(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(moveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(dragSpy.size(), 1);
+ QCOMPARE(vDragSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hDragSpy.size(), horizontalEnabled ? 1 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(dragStartSpy.count(), 1);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(dragStartSpy.size(), 1);
QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, moveFrom + moveByWithoutSnapBack*3);
QVERIFY(!flickable->isDragging());
QVERIFY(!flickable->isDraggingHorizontally());
QVERIFY(!flickable->isDraggingVertically());
- QCOMPARE(dragSpy.count(), 2);
- QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0);
- QCOMPARE(dragStartSpy.count(), 1);
- QCOMPARE(dragEndSpy.count(), 1);
+ QCOMPARE(dragSpy.size(), 2);
+ QCOMPARE(vDragSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hDragSpy.size(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(dragStartSpy.size(), 1);
+ QCOMPARE(dragEndSpy.size(), 1);
// Don't test whether moving finished because a flick could occur
// wait for any motion to end
@@ -1288,17 +1386,17 @@ void tst_qquickflickable::movingAndDragging()
QVERIFY(!flickable->isDraggingHorizontally());
QVERIFY(!flickable->isDraggingVertically());
- QCOMPARE(dragSpy.count(), 2);
- QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0);
- QCOMPARE(moveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(dragSpy.size(), 2);
+ QCOMPARE(vDragSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hDragSpy.size(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(moveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 2 : 0);
- QCOMPARE(dragStartSpy.count(), 1);
- QCOMPARE(dragEndSpy.count(), 1);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 1);
+ QCOMPARE(dragStartSpy.size(), 1);
+ QCOMPARE(dragEndSpy.size(), 1);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 1);
// Stop on a full pixel after user interaction
if (verticalEnabled)
@@ -1328,17 +1426,17 @@ void tst_qquickflickable::movingAndDragging()
QCOMPARE(flickable->isDraggingHorizontally(), horizontalEnabled);
QCOMPARE(flickable->isDraggingVertically(), verticalEnabled);
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
- QCOMPARE(dragSpy.count(), 1);
- QCOMPARE(vDragSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hDragSpy.count(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(moveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(dragSpy.size(), 1);
+ QCOMPARE(vDragSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hDragSpy.size(), horizontalEnabled ? 1 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 0);
- QCOMPARE(dragStartSpy.count(), 1);
- QCOMPARE(dragEndSpy.count(), 0);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 0);
+ QCOMPARE(dragStartSpy.size(), 1);
+ QCOMPARE(dragEndSpy.size(), 0);
QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, moveFrom + moveByWithSnapBack*3);
@@ -1350,15 +1448,15 @@ void tst_qquickflickable::movingAndDragging()
QVERIFY(!flickable->isDraggingHorizontally());
QVERIFY(!flickable->isDraggingVertically());
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 1 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 1 : 0);
- QCOMPARE(dragSpy.count(), 2);
- QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(moveSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 1 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 1 : 0);
+ QCOMPARE(dragSpy.size(), 2);
+ QCOMPARE(vDragSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hDragSpy.size(), horizontalEnabled ? 2 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 0);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 0);
// wait for any motion to end
QTRY_VERIFY(!flickable->isMoving());
@@ -1369,17 +1467,17 @@ void tst_qquickflickable::movingAndDragging()
QVERIFY(!flickable->isDraggingHorizontally());
QVERIFY(!flickable->isDraggingVertically());
- QCOMPARE(moveSpy.count(), 2);
- QCOMPARE(vMoveSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hMoveSpy.count(), horizontalEnabled ? 2 : 0);
- QCOMPARE(dragSpy.count(), 2);
- QCOMPARE(vDragSpy.count(), verticalEnabled ? 2 : 0);
- QCOMPARE(hDragSpy.count(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(moveSpy.size(), 2);
+ QCOMPARE(vMoveSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hMoveSpy.size(), horizontalEnabled ? 2 : 0);
+ QCOMPARE(dragSpy.size(), 2);
+ QCOMPARE(vDragSpy.size(), verticalEnabled ? 2 : 0);
+ QCOMPARE(hDragSpy.size(), horizontalEnabled ? 2 : 0);
- QCOMPARE(moveStartSpy.count(), 1);
- QCOMPARE(moveEndSpy.count(), 1);
- QCOMPARE(dragStartSpy.count(), 1);
- QCOMPARE(dragEndSpy.count(), 1);
+ QCOMPARE(moveStartSpy.size(), 1);
+ QCOMPARE(moveEndSpy.size(), 1);
+ QCOMPARE(dragStartSpy.size(), 1);
+ QCOMPARE(dragEndSpy.size(), 1);
QCOMPARE(flickable->contentX(), 0.0);
QCOMPARE(flickable->contentY(), 0.0);
@@ -1407,7 +1505,7 @@ void tst_qquickflickable::flickOnRelease()
QTest::mouseMove(window.data(), QPoint(50, 10), 10);
QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(50, 10), 10);
- QCOMPARE(vFlickSpy.count(), 1);
+ QCOMPARE(vFlickSpy.size(), 1);
// wait for any motion to end
QTRY_VERIFY(!flickable->isMoving());
@@ -1421,8 +1519,8 @@ void tst_qquickflickable::pressWhileFlicking()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("flickable03.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -1436,6 +1534,8 @@ void tst_qquickflickable::pressWhileFlicking()
QSignalSpy hFlickSpy(flickable, SIGNAL(flickingHorizontallyChanged()));
QSignalSpy vFlickSpy(flickable, SIGNAL(flickingVerticallyChanged()));
QSignalSpy flickSpy(flickable, SIGNAL(flickingChanged()));
+ QSignalSpy flickStartSpy(flickable, &QQuickFlickable::flickStarted);
+ QSignalSpy flickEndSpy(flickable, &QQuickFlickable::flickEnded);
// flick then press while it is still moving
// flicking == false, moving == true;
@@ -1447,12 +1547,14 @@ void tst_qquickflickable::pressWhileFlicking()
QVERIFY(flickable->isMoving());
QVERIFY(flickable->isMovingVertically());
QVERIFY(!flickable->isMovingHorizontally());
- QCOMPARE(vMoveSpy.count(), 1);
- QCOMPARE(hMoveSpy.count(), 0);
- QCOMPARE(moveSpy.count(), 1);
- QCOMPARE(vFlickSpy.count(), 1);
- QCOMPARE(hFlickSpy.count(), 0);
- QCOMPARE(flickSpy.count(), 1);
+ QCOMPARE(vMoveSpy.size(), 1);
+ QCOMPARE(hMoveSpy.size(), 0);
+ QCOMPARE(moveSpy.size(), 1);
+ QCOMPARE(vFlickSpy.size(), 1);
+ QCOMPARE(hFlickSpy.size(), 0);
+ QCOMPARE(flickSpy.size(), 1);
+ QCOMPARE(flickStartSpy.size(), 1);
+ QCOMPARE(flickEndSpy.size(), 0);
QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(20, 50));
QTRY_VERIFY(!flickable->isFlicking());
@@ -1465,6 +1567,76 @@ void tst_qquickflickable::pressWhileFlicking()
QVERIFY(!flickable->isFlickingVertically());
QTRY_VERIFY(!flickable->isMoving());
QVERIFY(!flickable->isMovingVertically());
+ QCOMPARE(flickStartSpy.size(), 1);
+ QCOMPARE(flickEndSpy.size(), 1);
+ // Stop on a full pixel after user interaction
+ QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX()));
+}
+
+void tst_qquickflickable::dragWhileFlicking()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("flickable03.qml")));
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window.rootObject());
+ QVERIFY(flickable != nullptr);
+
+ QSignalSpy vMoveSpy(flickable, &QQuickFlickable::movingVerticallyChanged);
+ QSignalSpy hMoveSpy(flickable, &QQuickFlickable::movingHorizontallyChanged);
+ QSignalSpy moveSpy(flickable, &QQuickFlickable::movingChanged);
+ QSignalSpy hFlickSpy(flickable, &QQuickFlickable::flickingHorizontallyChanged);
+ QSignalSpy vFlickSpy(flickable, &QQuickFlickable::flickingVerticallyChanged);
+ QSignalSpy flickSpy(flickable, &QQuickFlickable::flickingChanged);
+ QSignalSpy flickStartSpy(flickable, &QQuickFlickable::flickStarted);
+ QSignalSpy flickEndSpy(flickable, &QQuickFlickable::flickEnded);
+
+ // flick first, let it keep moving
+ flick(&window, QPoint(20,190), QPoint(20, 50), 200);
+ QVERIFY(flickable->verticalVelocity() > 0.0);
+ QTRY_VERIFY(flickable->isFlicking());
+ QVERIFY(flickable->isFlickingVertically());
+ QCOMPARE(flickable->isFlickingHorizontally(), false);
+ QVERIFY(flickable->isMoving());
+ QVERIFY(flickable->isMovingVertically());
+ QCOMPARE(flickable->isMovingHorizontally(), false);
+ QCOMPARE(vMoveSpy.size(), 1);
+ QCOMPARE(hMoveSpy.size(), 0);
+ QCOMPARE(moveSpy.size(), 1);
+ QCOMPARE(vFlickSpy.size(), 1);
+ QCOMPARE(hFlickSpy.size(), 0);
+ QCOMPARE(flickSpy.size(), 1);
+ QCOMPARE(flickStartSpy.size(), 1);
+ QCOMPARE(flickEndSpy.size(), 0);
+
+ // then drag slowly while it's still flicking and moving
+ const int dragStepDelay = 100;
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(20, 70));
+ QTRY_COMPARE(flickable->isFlicking(), false);
+ QCOMPARE(flickable->isFlickingVertically(), false);
+ QVERIFY(flickable->isMoving());
+ QVERIFY(flickable->isMovingVertically());
+
+ for (int y = 70; y > 50; y -= 5) {
+ QTest::mouseMove(&window, QPoint(20, y), dragStepDelay);
+ QVERIFY(flickable->isMoving());
+ QVERIFY(flickable->isMovingVertically());
+ // Flickable's timeline is real-time, so spoofing timestamps isn't enough
+ QTest::qWait(dragStepDelay);
+ }
+
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(20, 50), dragStepDelay);
+
+ QCOMPARE(flickable->isFlicking(), false);
+ QCOMPARE(flickable->isFlickingVertically(), false);
+ QTRY_COMPARE(flickable->isMoving(), false);
+ QCOMPARE(flickable->isMovingVertically(), false);
+ QCOMPARE(flickStartSpy.size(), 1);
+ QCOMPARE(flickEndSpy.size(), 1);
+ QCOMPARE(vMoveSpy.size(), 2);
+ QCOMPARE(hMoveSpy.size(), 0);
+ QCOMPARE(moveSpy.size(), 2);
+ QCOMPARE(vFlickSpy.size(), 2);
+ QCOMPARE(hFlickSpy.size(), 0);
// Stop on a full pixel after user interaction
QCOMPARE(flickable->contentX(), (qreal)qRound(flickable->contentX()));
}
@@ -1502,8 +1674,8 @@ void tst_qquickflickable::flickVelocity()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("flickable03.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -1546,8 +1718,8 @@ void tst_qquickflickable::margins()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("margins.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->setTitle(QTest::currentTestFunction());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -1610,8 +1782,8 @@ void tst_qquickflickable::cancelOnHide()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("hide.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject());
@@ -1629,8 +1801,8 @@ void tst_qquickflickable::cancelOnMouseGrab()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("cancel.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -1653,7 +1825,8 @@ void tst_qquickflickable::cancelOnMouseGrab()
QQuickItem *item = window->rootObject()->findChild<QQuickItem*>("row");
auto mouse = QPointingDevice::primaryPointingDevice();
auto mousePriv = QPointingDevicePrivate::get(const_cast<QPointingDevice *>(mouse));
- QMouseEvent fakeMouseEv(QEvent::MouseMove, QPoint(130, 100), Qt::NoButton, Qt::LeftButton, Qt::NoModifier, mouse);
+ QMouseEvent fakeMouseEv(QEvent::MouseMove, QPoint(130, 100), QPoint(130, 100),
+ Qt::NoButton, Qt::LeftButton, Qt::NoModifier, mouse);
mousePriv->setExclusiveGrabber(&fakeMouseEv, fakeMouseEv.points().first(), item);
QTRY_COMPARE(flickable->contentX(), 0.);
@@ -1669,8 +1842,8 @@ void tst_qquickflickable::clickAndDragWhenTransformed()
QScopedPointer<QQuickView> view(new QQuickView);
view->setSource(testFileUrl("transformedFlickable.qml"));
QTRY_COMPARE(view->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(view.data());
- QQuickViewTestUtil::moveMouseAway(view.data());
+ QQuickVisualTestUtils::centerOnScreen(view.data());
+ QQuickVisualTestUtils::moveMouseAway(view.data());
view->show();
QVERIFY(QTest::qWaitForWindowActive(view.data()));
QVERIFY(view->rootObject() != nullptr);
@@ -1688,7 +1861,8 @@ void tst_qquickflickable::clickAndDragWhenTransformed()
QTRY_COMPARE(flickable->property("itemPressed").toBool(), true);
QTest::mouseRelease(view.data(), Qt::LeftButton, Qt::NoModifier, QPoint(200, 200));
- const int threshold = qApp->styleHints()->startDragDistance();
+ // drag threshold is scaled according to the scene scaling
+ const int threshold = qApp->styleHints()->startDragDistance() * flickable->parentItem()->scale();
// drag outside bounds
moveAndPress(view.data(), QPoint(160, 160));
@@ -1701,10 +1875,18 @@ void tst_qquickflickable::clickAndDragWhenTransformed()
// drag inside bounds
moveAndPress(view.data(), QPoint(200, 140));
+ QCOMPARE(flickable->keepMouseGrab(), false);
QTest::qWait(10);
+ // Flickable should get interested in dragging when the drag is beyond the
+ // threshold distance along the hypoteneuse of the 45° rotation
+ const int deltaPastRotatedThreshold = threshold * 1.414 + 1;
+ QTest::mouseMove(view.data(), QPoint(200 + deltaPastRotatedThreshold, 140));
+ qCDebug(lcTests) << "transformed flickable dragging yet?" << flickable->isDragging() <<
+ "after dragging by" << deltaPastRotatedThreshold << "past scaled threshold" << threshold;
+ QCOMPARE(flickable->isDragging(), false); // Flickable never grabs on the first drag past the threshold
+ QCOMPARE(flickable->keepMouseGrab(), true); // but it plans to do it next time!
QTest::mouseMove(view.data(), QPoint(200 + threshold * 2, 140));
- QTest::mouseMove(view.data(), QPoint(200 + threshold * 3, 140));
- QCOMPARE(flickable->isDragging(), true);
+ QCOMPARE(flickable->isDragging(), true); // it grabs only during the second drag past the threshold
QCOMPARE(flickable->property("itemPressed").toBool(), false);
moveAndRelease(view.data(), QPoint(220, 140));
}
@@ -1714,8 +1896,8 @@ void tst_qquickflickable::flickTwiceUsingTouches()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("longList.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(window->rootObject() != nullptr);
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -1795,8 +1977,8 @@ void tst_qquickflickable::nestedStopAtBounds()
QQuickView view;
view.setSource(testFileUrl("nestedStopAtBounds.qml"));
QTRY_COMPARE(view.status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(&view);
- QQuickViewTestUtil::moveMouseAway(&view);
+ QQuickVisualTestUtils::centerOnScreen(&view);
+ QQuickVisualTestUtils::moveMouseAway(&view);
view.show();
view.requestActivate();
QVERIFY(QTest::qWaitForWindowActive(&view));
@@ -1838,7 +2020,7 @@ void tst_qquickflickable::nestedStopAtBounds()
moveAndPress(&view, position);
if (waitForPressDelay) {
QVERIFY(innerFiltering); // isPressed will never be true if the mouse area isn't enabled.
- QTRY_VERIFY(mouseArea->pressed());
+ QTRY_VERIFY(mouseArea->isPressed());
}
axis += invert ? threshold * 2 : -threshold * 2;
@@ -1949,8 +2131,8 @@ void tst_qquickflickable::stopAtBounds()
QQuickView view;
view.setSource(testFileUrl("stopAtBounds.qml"));
QTRY_COMPARE(view.status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(&view);
- QQuickViewTestUtil::moveMouseAway(&view);
+ QQuickVisualTestUtils::centerOnScreen(&view);
+ QQuickVisualTestUtils::moveMouseAway(&view);
view.show();
view.requestActivate();
QVERIFY(QTest::qWaitForWindowActive(&view));
@@ -1998,10 +2180,10 @@ void tst_qquickflickable::stopAtBounds()
else
QCOMPARE(transpose ? flickable->isAtYBeginning() : flickable->isAtXBeginning(), false);
- QCOMPARE(atXBeginningChangedSpy.count(), (!transpose && !invert) ? 1 : 0);
- QCOMPARE(atYBeginningChangedSpy.count(), ( transpose && !invert) ? 1 : 0);
- QCOMPARE(atXEndChangedSpy.count(), (!transpose && invert) ? 1 : 0);
- QCOMPARE(atYEndChangedSpy.count(), ( transpose && invert) ? 1 : 0);
+ QCOMPARE(atXBeginningChangedSpy.size(), (!transpose && !invert) ? 1 : 0);
+ QCOMPARE(atYBeginningChangedSpy.size(), ( transpose && !invert) ? 1 : 0);
+ QCOMPARE(atXEndChangedSpy.size(), (!transpose && invert) ? 1 : 0);
+ QCOMPARE(atYEndChangedSpy.size(), ( transpose && invert) ? 1 : 0);
// Drag away from the aligned boundary again.
// None of the mouse movements will position the view at the boundary exactly,
@@ -2035,7 +2217,7 @@ void tst_qquickflickable::stopAtBounds()
else
flick(&view, QPoint(120,120), QPoint(20,20), 100);
- QVERIFY(flickSignal.count() > 0);
+ QVERIFY(flickSignal.size() > 0);
if (transpose) {
if (invert)
QTRY_COMPARE(flickable->isAtYBeginning(), true);
@@ -2054,8 +2236,8 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("nestedmousearea.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(window->rootObject() != nullptr);
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -2074,6 +2256,27 @@ void tst_qquickflickable::nestedMouseAreaUsingTouch()
QVERIFY(nested->y() < 100.0);
}
+void tst_qquickflickable::nestedMouseAreaPropagateComposedEvents()
+{
+ QScopedPointer<QQuickView> window(new QQuickView);
+ window->setSource(testFileUrl("nestedmouseareapce.qml"));
+ QTRY_COMPARE(window->status(), QQuickView::Ready);
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
+ window->show();
+ QVERIFY(window->rootObject() != nullptr);
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
+ QVERIFY(flickable != nullptr);
+
+ QCOMPARE(flickable->contentY(), 50.0f);
+ flickWithTouch(window.data(), QPoint(100, 300), QPoint(100, 200));
+
+ // flickable should have moved
+ QVERIFY(!qFuzzyCompare(flickable->contentY(), 50.0));
+}
+
void tst_qquickflickable::nestedSliderUsingTouch_data()
{
QTest::addColumn<bool>("keepMouseGrab");
@@ -2100,8 +2303,8 @@ void tst_qquickflickable::nestedSliderUsingTouch()
QScopedPointer<QQuickView> windowPtr(window);
windowPtr->setSource(testFileUrl("nestedSlider.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window);
- QQuickViewTestUtil::moveMouseAway(window);
+ QQuickVisualTestUtils::centerOnScreen(window);
+ QQuickVisualTestUtils::moveMouseAway(window);
window->show();
QVERIFY(QTest::qWaitForWindowActive(window));
QVERIFY(window->rootObject() != nullptr);
@@ -2124,7 +2327,7 @@ void tst_qquickflickable::nestedSliderUsingTouch()
QTest::touchEvent(window, touchDevice).move(0, p0, window);
QQuickTouchUtils::flush(window);
}
- QCOMPARE(tda->active(), keepMouseGrab | keepTouchGrab);
+ QCOMPARE(tda->active(), keepMouseGrab || keepTouchGrab);
QTest::touchEvent(window, touchDevice).release(0, p0, window);
QQuickTouchUtils::flush(window);
QTRY_COMPARE(tda->touchPointStates.first(), QEventPoint::State::Pressed);
@@ -2139,8 +2342,8 @@ void tst_qquickflickable::pressDelayWithLoader()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("pressDelayWithLoader.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
QVERIFY(window->rootObject() != nullptr);
@@ -2156,8 +2359,8 @@ void tst_qquickflickable::movementFromProgrammaticFlick()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("movementSignals.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -2185,22 +2388,22 @@ void tst_qquickflickable::contentSize()
flickable.setWidth(100);
QCOMPARE(flickable.width(), qreal(100));
QCOMPARE(flickable.contentWidth(), qreal(-1.0));
- QCOMPARE(cwspy.count(), 0);
+ QCOMPARE(cwspy.size(), 0);
flickable.setContentWidth(10);
QCOMPARE(flickable.width(), qreal(100));
QCOMPARE(flickable.contentWidth(), qreal(10));
- QCOMPARE(cwspy.count(), 1);
+ QCOMPARE(cwspy.size(), 1);
flickable.setHeight(100);
QCOMPARE(flickable.height(), qreal(100));
QCOMPARE(flickable.contentHeight(), qreal(-1.0));
- QCOMPARE(chspy.count(), 0);
+ QCOMPARE(chspy.size(), 0);
flickable.setContentHeight(10);
QCOMPARE(flickable.height(), qreal(100));
QCOMPARE(flickable.contentHeight(), qreal(10));
- QCOMPARE(chspy.count(), 1);
+ QCOMPARE(chspy.size(), 1);
}
// QTBUG-53726
@@ -2209,8 +2412,8 @@ void tst_qquickflickable::ratios_smallContent()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("ratios_smallContent.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->setTitle(QTest::currentTestFunction());
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
@@ -2235,8 +2438,8 @@ void tst_qquickflickable::contentXYNotTruncatedToInt()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("contentXY.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -2255,8 +2458,8 @@ void tst_qquickflickable::keepGrab()
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("keepGrab.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window.data());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickViewTestUtils::centerOnScreen(window.data());
+ QQuickViewTestUtils::moveMouseAway(window.data());
window->show();
QVERIFY(QTest::qWaitForWindowActive(window.data()));
@@ -2302,6 +2505,7 @@ void tst_qquickflickable::overshoot()
{
QFETCH(QQuickFlickable::BoundsBehavior, boundsBehavior);
QFETCH(int, boundsMovement);
+ QFETCH(bool, pixelAligned);
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("overshoot.qml"));
@@ -2311,6 +2515,7 @@ void tst_qquickflickable::overshoot()
QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
QVERIFY(flickable);
+ flickable->setPixelAligned(pixelAligned);
QCOMPARE(flickable->width(), 200.0);
QCOMPARE(flickable->height(), 200.0);
@@ -2357,7 +2562,7 @@ void tst_qquickflickable::overshoot()
QMetaObject::invokeMethod(flickable, "reset");
// flick past the beginning
- flick(window.data(), QPoint(10, 10), QPoint(50, 50), 100);
+ flick(window.data(), QPoint(10, 10), QPoint(50, 50), 50);
QTRY_VERIFY(!flickable->property("flicking").toBool());
if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::OvershootBounds)) {
@@ -2426,7 +2631,7 @@ void tst_qquickflickable::overshoot()
QMetaObject::invokeMethod(flickable, "reset");
// flick past the end
- flick(window.data(), QPoint(50, 50), QPoint(10, 10), 100);
+ flick(window.data(), QPoint(50, 50), QPoint(10, 10), 50);
QTRY_VERIFY(!flickable->property("flicking").toBool());
if ((boundsMovement == QQuickFlickable::FollowBoundsBehavior) && (boundsBehavior & QQuickFlickable::OvershootBounds)) {
@@ -2459,29 +2664,53 @@ void tst_qquickflickable::overshoot_data()
{
QTest::addColumn<QQuickFlickable::BoundsBehavior>("boundsBehavior");
QTest::addColumn<int>("boundsMovement");
+ QTest::addColumn<bool>("pixelAligned");
QTest::newRow("StopAtBounds,FollowBoundsBehavior")
<< QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds)
- << int(QQuickFlickable::FollowBoundsBehavior);
+ << int(QQuickFlickable::FollowBoundsBehavior) << false;
QTest::newRow("DragOverBounds,FollowBoundsBehavior")
<< QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds)
- << int(QQuickFlickable::FollowBoundsBehavior);
+ << int(QQuickFlickable::FollowBoundsBehavior) << false;
QTest::newRow("OvershootBounds,FollowBoundsBehavior")
<< QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds)
- << int(QQuickFlickable::FollowBoundsBehavior);
+ << int(QQuickFlickable::FollowBoundsBehavior) << false;
QTest::newRow("DragAndOvershootBounds,FollowBoundsBehavior")
<< QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds)
- << int(QQuickFlickable::FollowBoundsBehavior);
+ << int(QQuickFlickable::FollowBoundsBehavior) << false;
QTest::newRow("DragOverBounds,StopAtBounds")
<< QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds)
- << int(QQuickFlickable::StopAtBounds);
+ << int(QQuickFlickable::StopAtBounds) << false;
QTest::newRow("OvershootBounds,StopAtBounds")
<< QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds)
- << int(QQuickFlickable::StopAtBounds);
+ << int(QQuickFlickable::StopAtBounds) << false;
QTest::newRow("DragAndOvershootBounds,StopAtBounds")
<< QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds)
- << int(QQuickFlickable::StopAtBounds);
+ << int(QQuickFlickable::StopAtBounds) << false;
+
+ QTest::newRow("StopAtBounds,FollowBoundsBehavior,pixelAligned")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds)
+ << int(QQuickFlickable::FollowBoundsBehavior) << true;
+ QTest::newRow("DragOverBounds,FollowBoundsBehavior,pixelAligned")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds)
+ << int(QQuickFlickable::FollowBoundsBehavior) << true;
+ QTest::newRow("OvershootBounds,FollowBoundsBehavior,pixelAligned")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds)
+ << int(QQuickFlickable::FollowBoundsBehavior) << true;
+ QTest::newRow("DragAndOvershootBounds,FollowBoundsBehavior,pixelAligned")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds)
+ << int(QQuickFlickable::FollowBoundsBehavior) << true;
+
+ QTest::newRow("DragOverBounds,StopAtBounds,pixelAligned")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds)
+ << int(QQuickFlickable::StopAtBounds) << true;
+ QTest::newRow("OvershootBounds,StopAtBounds,pixelAligned")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds)
+ << int(QQuickFlickable::StopAtBounds) << true;
+ QTest::newRow("DragAndOvershootBounds,StopAtBounds,pixelAligned")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds)
+ << int(QQuickFlickable::StopAtBounds) << true;
}
void tst_qquickflickable::overshoot_reentrant()
@@ -2550,8 +2779,8 @@ void tst_qquickflickable::synchronousDrag()
QQuickView *window = scopedWindow.data();
window->setSource(testFileUrl("longList.qml"));
QTRY_COMPARE(window->status(), QQuickView::Ready);
- QQuickViewTestUtil::centerOnScreen(window);
- QQuickViewTestUtil::moveMouseAway(window);
+ QQuickVisualTestUtils::centerOnScreen(window);
+ QQuickVisualTestUtils::moveMouseAway(window);
window->show();
QVERIFY(window->rootObject() != nullptr);
QVERIFY(QTest::qWaitForWindowActive(window));
@@ -2649,6 +2878,560 @@ void tst_qquickflickable::parallelTouch() // QTBUG-30840
QTRY_VERIFY(!flickable2->isMoving());
}
+void tst_qquickflickable::ignoreNonLeftMouseButtons() // QTBUG-96909
+{
+ QFETCH(Qt::MouseButton, otherButton);
+ const int threshold = qApp->styleHints()->startDragDistance();
+ QQuickView view;
+ view.setSource(testFileUrl("dragon.qml"));
+ view.show();
+ view.requestActivate();
+ QQuickFlickable *flickable = static_cast<QQuickFlickable *>(view.rootObject());
+ QSignalSpy dragSpy(flickable, &QQuickFlickable::draggingChanged);
+
+ // Drag with left button
+ QPoint p1(100, 100);
+ moveAndPress(&view, p1);
+ for (int i = 0; i < 8; ++i) {
+ p1 -= QPoint(threshold, threshold);
+ QTest::mouseMove(&view, p1, 50);
+ }
+ QVERIFY(flickable->isDragging());
+ QCOMPARE(dragSpy.size(), 1);
+
+ // Press other button too, then release left button: dragging changes to false
+ QTest::mousePress(&view, otherButton);
+ QTest::mouseRelease(&view, Qt::LeftButton);
+ QTRY_COMPARE(flickable->isDragging(), false);
+ QCOMPARE(dragSpy.size(), 2);
+
+ // Drag further with the other button held: Flickable ignores it
+ for (int i = 0; i < 8; ++i) {
+ p1 -= QPoint(threshold, threshold);
+ QTest::mouseMove(&view, p1, 50);
+ }
+ QCOMPARE(flickable->isDragging(), false);
+ QCOMPARE(dragSpy.size(), 2);
+
+ // Release other button: nothing happens
+ QTest::mouseRelease(&view, otherButton);
+ QCOMPARE(dragSpy.size(), 2);
+}
+
+void tst_qquickflickable::ignoreNonLeftMouseButtons_data()
+{
+ QTest::addColumn<Qt::MouseButton>("otherButton");
+
+ QTest::newRow("right") << Qt::RightButton;
+ QTest::newRow("middle") << Qt::MiddleButton;
+}
+
+void tst_qquickflickable::receiveTapOutsideContentItem()
+{
+ // Check that if we add a TapHandler handler to a flickable, we
+ // can tap on the whole flickable area inside it, which includes
+ // the extents in addition to the content item.
+ QQuickView window;
+ window.resize(200, 200);
+ FlickableWithExtents flickable;
+ flickable.setParentItem(window.contentItem());
+ flickable.setWidth(200);
+ flickable.setHeight(200);
+ flickable.setContentWidth(100);
+ flickable.setContentHeight(100);
+
+ window.show();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+
+ QQuickTapHandler tapHandler(&flickable);
+ QSignalSpy clickedSpy(&tapHandler, SIGNAL(tapped(QEventPoint,Qt::MouseButton)));
+
+ // Tap outside the content item in the top-left corner
+ QTest::mouseClick(&window, Qt::LeftButton, {}, QPoint(5, 5));
+ QCOMPARE(clickedSpy.size(), 1);
+
+ // Tap outside the content item in the bottom-right corner
+ const QPoint bottomRight(flickable.contentItem()->width() + 5, flickable.contentItem()->height() + 5);
+ QTest::mouseClick(&window, Qt::LeftButton, {}, bottomRight);
+ QCOMPARE(clickedSpy.size(), 2);
+}
+
+void tst_qquickflickable::flickWhenRotated_data()
+{
+ QTest::addColumn<qreal>("rootRotation");
+ QTest::addColumn<qreal>("flickableRotation");
+ QTest::addColumn<qreal>("scale");
+
+ static constexpr qreal rotations[] = { 0, 30, 90, 180, 270 };
+ static constexpr qreal scales[] = { 0.3, 1, 1.5 };
+
+ for (const auto pr : rotations) {
+ for (const auto fr : rotations) {
+ if (pr <= 90) {
+ for (const auto s : scales)
+ QTest::addRow("parent: %g, flickable: %g, scale: %g", pr, fr, s) << pr << fr << s;
+ } else {
+ // don't bother trying every scale with every set of rotations, to save time
+ QTest::addRow("parent: %g, flickable: %g, scale: 1", pr, fr) << pr << fr << qreal(1);
+ }
+ }
+ }
+}
+
+void tst_qquickflickable::flickWhenRotated() // QTBUG-99639
+{
+ QFETCH(qreal, rootRotation);
+ QFETCH(qreal, flickableRotation);
+ QFETCH(qreal, scale);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("rotatedFlickable.qml")));
+ QQuickItem *rootItem = window.rootObject();
+ QVERIFY(rootItem);
+ QQuickFlickable *flickable = rootItem->findChild<QQuickFlickable*>();
+ QVERIFY(flickable);
+
+ rootItem->setRotation(rootRotation);
+ flickable->setRotation(flickableRotation);
+ rootItem->setScale(scale);
+ QVERIFY(flickable->isAtYBeginning());
+
+ // Flick in Y direction in Flickable's coordinate system and check how much it moved
+ const QPointF startPoint = flickable->mapToGlobal(QPoint(20, 180));
+ const QPointF endPoint = flickable->mapToGlobal(QPoint(20, 40));
+ flick(&window, window.mapFromGlobal(startPoint).toPoint(), window.mapFromGlobal(endPoint).toPoint(), 100);
+ QTRY_VERIFY(flickable->isMoving());
+ QTRY_VERIFY(!flickable->isMoving());
+ qCDebug(lcTests) << "flicking from" << startPoint << "to" << endPoint << ": ended at contentY" << flickable->contentY();
+ // usually flickable->contentY() is at 275 or very close
+ QVERIFY(!flickable->isAtYBeginning());
+}
+
+void tst_qquickflickable::flickAndReleaseOutsideBounds() // QTBUG-104987
+{
+ // Check that flicking works when the mouse release happens
+ // outside the bounds of the flickable (and the flick started on top
+ // of a TapHandler that has a passive grab).
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("flickableWithTapHandler.qml")));
+ QQuickItem *rootItem = window.rootObject();
+ QVERIFY(rootItem);
+ QQuickFlickable *flickable = rootItem->findChild<QQuickFlickable*>();
+ QVERIFY(flickable);
+ QQuickItem *childItem = flickable->findChild<QQuickItem*>("childItem");
+ QVERIFY(childItem);
+
+ QVERIFY(flickable->isAtYBeginning());
+
+ // Startpoint is on top of the tapHandler, while the endpoint is outside the flickable
+ const QPointF startPos = childItem->mapToGlobal(QPoint(10, 10));
+ const QPointF endPos = flickable->mapToGlobal(QPoint(10, -10));
+ const QPoint globalStartPos = window.mapFromGlobal(startPos).toPoint();
+ const QPoint globalEndPos = window.mapFromGlobal(endPos).toPoint();
+ const qreal dragDistance = 20;
+
+ // Note: here we need to initiate a flick using raw events, rather than
+ // flickable.flick(), since we're testing if the mouse events takes the
+ // correct path to starts a flick (among passive and exclusive grabbers, combined
+ // with childMouseEventFilter()).
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, globalStartPos);
+ QTest::mouseMove(&window, globalStartPos - QPoint(0, dragDistance / 2));
+ QTest::mouseMove(&window, globalStartPos - QPoint(0, dragDistance));
+ QTest::mouseMove(&window, globalEndPos);
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, globalEndPos);
+
+ // Ensure that the content item ends up being moved more than what we dragged
+ QTRY_VERIFY(flickable->contentY() > dragDistance * 2);
+}
+
+void tst_qquickflickable::scrollingWithFractionalExtentSize_data()
+{
+ QTest::addColumn<QByteArray>("property");
+ QTest::addColumn<bool>("isYAxis");
+ QTest::addColumn<bool>("atBeginning");
+ QTest::addColumn<QQuickFlickable::BoundsBehaviorFlag>("boundsBehaviour");
+
+ QTest::newRow("minyextent") << QByteArray("topMargin") << true << true << QQuickFlickable::StopAtBounds;
+ QTest::newRow("maxyextent") << QByteArray("bottomMargin") << true << false << QQuickFlickable::StopAtBounds;
+ QTest::newRow("minxextent") << QByteArray("leftMargin") << false << true << QQuickFlickable::StopAtBounds;
+ QTest::newRow("maxxextent") << QByteArray("rightMargin") << false << false << QQuickFlickable::StopAtBounds;
+
+ QTest::newRow("minyextent") << QByteArray("topMargin") << true << true << QQuickFlickable::DragAndOvershootBounds;
+ QTest::newRow("maxyextent") << QByteArray("bottomMargin") << true << false << QQuickFlickable::DragAndOvershootBounds;
+ QTest::newRow("minxextent") << QByteArray("leftMargin") << false << true << QQuickFlickable::DragAndOvershootBounds;
+ QTest::newRow("maxxextent") << QByteArray("rightMargin") << false << false << QQuickFlickable::DragAndOvershootBounds;
+}
+
+void tst_qquickflickable::scrollingWithFractionalExtentSize() // QTBUG-101268
+{
+ QFETCH(QByteArray, property);
+ QFETCH(bool, isYAxis);
+ QFETCH(bool, atBeginning);
+ QFETCH(QQuickFlickable::BoundsBehaviorFlag, boundsBehaviour);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("fractionalExtent.qml")));
+ QQuickItem *rootItem = window.rootObject();
+ QVERIFY(rootItem);
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(rootItem);
+ QVERIFY(flickable);
+ flickable->setBoundsBehavior(boundsBehaviour);
+
+ qreal value = 100.5;
+ flickable->setProperty(property.constData(), 100.5);
+ if (isYAxis)
+ flickable->setContentY(atBeginning ? -value : value + qAbs(flickable->height() - flickable->contentHeight()));
+ else
+ flickable->setContentX(atBeginning ? -value : value + qAbs(flickable->width() - flickable->contentWidth()));
+
+ if (isYAxis) {
+ QVERIFY(atBeginning ? flickable->isAtYBeginning() : flickable->isAtYEnd());
+ QVERIFY(!flickable->isMovingVertically());
+ } else {
+ QVERIFY(atBeginning ? flickable->isAtXBeginning() : flickable->isAtXEnd());
+ QVERIFY(!flickable->isMovingHorizontally());
+ }
+
+ QPointF pos(flickable->x() + flickable->width() / 2, flickable->y() + flickable->height() / 2);
+ QPoint angleDelta(isYAxis ? 0 : (atBeginning ? -50 : 50), isYAxis ? (atBeginning ? -50 : 50) : 0);
+
+ QWheelEvent wheelEvent1(pos, window.mapToGlobal(pos), QPoint(), angleDelta,
+ Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
+
+ QGuiApplication::sendEvent(&window, &wheelEvent1);
+ qApp->processEvents();
+ if (isYAxis) {
+ QVERIFY(flickable->isMovingVertically());
+ QTRY_VERIFY(!flickable->isMovingVertically());
+ QVERIFY(!(atBeginning ? flickable->isAtYBeginning() : flickable->isAtYEnd()));
+ } else {
+ QVERIFY(flickable->isMovingHorizontally());
+ QTRY_VERIFY(!flickable->isMovingHorizontally());
+ QVERIFY(!(atBeginning ? flickable->isAtXBeginning() : flickable->isAtXEnd()));
+ }
+
+ QWheelEvent wheelEvent2(pos, window.mapToGlobal(pos), QPoint(), -angleDelta,
+ Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
+ wheelEvent2.setTimestamp(wheelEvent1.timestamp() + 10);
+
+ QGuiApplication::sendEvent(&window, &wheelEvent2);
+ qApp->processEvents();
+
+ if (isYAxis) {
+ QVERIFY(flickable->isMovingVertically());
+ QTRY_VERIFY(!flickable->isMovingVertically());
+ QVERIFY(atBeginning ? flickable->isAtYBeginning() : flickable->isAtYEnd());
+ } else {
+ QVERIFY(flickable->isMovingHorizontally());
+ QTRY_VERIFY(!flickable->isMovingHorizontally());
+ QVERIFY(atBeginning ? flickable->isAtXBeginning() : flickable->isAtXEnd());
+ }
+}
+
+void tst_qquickflickable::setContentPositionWhileDragging_data()
+{
+ QTest::addColumn<bool>("isHorizontal");
+ QTest::addColumn<int>("newPos");
+ QTest::addColumn<int>("newExtent");
+ QTest::newRow("horizontal, setContentX") << true << 0 << -1;
+ QTest::newRow("vertical, setContentY") << false << 0 << -1;
+ QTest::newRow("horizontal, setContentWidth") << true << -1 << 200;
+ QTest::newRow("vertical, setContentHeight") << false << -1 << 200;
+}
+
+void tst_qquickflickable::setContentPositionWhileDragging() // QTBUG-104966
+{
+ QFETCH(bool, isHorizontal);
+ QFETCH(int, newPos);
+ QFETCH(int, newExtent);
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("contentPosWhileDragging.qml")));
+ QQuickViewTestUtils::centerOnScreen(&window);
+ QVERIFY(window.isVisible());
+ QQuickItem *rootItem = window.rootObject();
+ QVERIFY(rootItem);
+ QQuickFlickable *flickable = rootItem->findChild<QQuickFlickable *>();
+ QVERIFY(flickable);
+
+ const auto contentPos = [flickable]() -> QPoint {
+ return QPoint(flickable->contentX(), flickable->contentY());
+ };
+ const qreal threshold =
+ qApp->styleHints()->startDragDistance() * flickable->parentItem()->scale();
+ const QPoint thresholdPnt(qRound(threshold), qRound(threshold));
+ const auto flickableCenterPos = flickable->mapToScene({flickable->width() / 2, flickable->height() / 2}).toPoint();
+
+ // Drag the mouse until we have surpassed the mouse drag threshold and a drag is initiated
+ // by checking for flickable->isDragging()
+ QPoint pos = flickableCenterPos;
+ QQuickViewTestUtils::moveAndPress(&window, pos);
+ int j = 1;
+ QVERIFY(!flickable->isDragging());
+ while (!flickable->isDragging()) {
+ pos = flickableCenterPos - QPoint(j, j);
+ QTest::mouseMove(&window, pos);
+ j++;
+ }
+
+ // Now we have entered the drag state
+ QVERIFY(flickable->isDragging());
+ QCOMPARE(flickable->contentX(), 0);
+ QCOMPARE(flickable->contentY(), 0);
+ QVERIFY(flickable->width() > 0);
+ QVERIFY(flickable->height() > 0);
+
+
+ const int moveLength = 50;
+ const QPoint unitDelta(isHorizontal ? 1 : 0, isHorizontal ? 0 : 1);
+ const QPoint moveDelta = unitDelta * moveLength;
+
+ pos -= 3*moveDelta;
+ QTest::mouseMove(&window, pos);
+ // Should be positive because we drag in the opposite direction
+ QCOMPARE(contentPos(), 3 * moveDelta);
+ QPoint expectedContentPos;
+
+ // Set the content item position back to zero *while dragging* (!!)
+ if (newPos >= 0) {
+ if (isHorizontal) {
+ flickable->setContentX(newPos);
+ } else {
+ flickable->setContentY(newPos);
+ }
+ // Continue dragging
+ pos -= moveDelta;
+ expectedContentPos = moveDelta;
+ } else if (newExtent >= 0) {
+ // ...or reduce the content size be be less than current (contentX, contentY) position
+ // This forces the content item to move.
+ // contentY: 150
+ // 320 - 150 = 170 pixels down to bottom
+ // Now reduce contentHeight to 200
+ // since we are at the bottom, and the flickable is 100 pixels tall, contentY must land
+ // at newExtent - 100.
+
+ if (isHorizontal) {
+ flickable->setContentWidth(newExtent);
+ } else {
+ flickable->setContentHeight(newExtent);
+ }
+ // Assumption is that the contentItem is aligned to the bottom of the flickable
+ // We therefore cannot scroll/flick it further down. Drag it up towards the top instead
+ // (by moving mouse down).
+ pos += moveDelta;
+ expectedContentPos = unitDelta * (newExtent - (isHorizontal ? flickable->width() : flickable->height()));
+ }
+
+ QTest::mouseMove(&window, pos);
+
+ // Make sure that the contentItem was only dragged the delta in mouse movement since the last
+ // setContentX/Y() call.
+ QCOMPARE(contentPos(), expectedContentPos);
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, pos);
+ QVERIFY(!flickable->isDragging());
+}
+
+void tst_qquickflickable::coalescedMove()
+{
+ QQuickView *window = new QQuickView;
+ QScopedPointer<QQuickView> windowPtr(window);
+ windowPtr->setSource(testFileUrl("flickable03.qml"));
+ QTRY_COMPARE(window->status(), QQuickView::Ready);
+ QQuickVisualTestUtils::centerOnScreen(window);
+ QQuickVisualTestUtils::moveMouseAway(window);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ QVERIFY(window->rootObject() != nullptr);
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
+ QVERIFY(flickable != nullptr);
+
+ QSignalSpy movementStartedSpy(flickable, SIGNAL(movementStarted()));
+ QSignalSpy movementEndedSpy(flickable, SIGNAL(movementEnded()));
+ QSignalSpy flickStartedSpy(flickable, SIGNAL(flickStarted()));
+ QSignalSpy flickEndedSpy(flickable, SIGNAL(flickEnded()));
+
+ QTest::touchEvent(window, touchDevice).press(0, {10, 10}).commit();
+
+ QTest::touchEvent(window, touchDevice).move(0, {10, 40}).commit();
+
+ QTest::touchEvent(window, touchDevice).move(0, {10, 100}).commit();
+
+ QTest::touchEvent(window, touchDevice).release(0, {10, 150}).commit();
+ QQuickTouchUtils::flush(window);
+
+ QTRY_VERIFY(!flickable->isMoving());
+
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(flickStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 1);
+ QCOMPARE(flickEndedSpy.size(), 1);
+}
+
+void tst_qquickflickable::onlyOneMove()
+{
+ QQuickView *window = new QQuickView;
+ QScopedPointer<QQuickView> windowPtr(window);
+ windowPtr->setSource(testFileUrl("flickable03.qml"));
+ QTRY_COMPARE(window->status(), QQuickView::Ready);
+ QQuickVisualTestUtils::centerOnScreen(window);
+ QQuickVisualTestUtils::moveMouseAway(window);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+ QVERIFY(window->rootObject() != nullptr);
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window->rootObject());
+ QVERIFY(flickable != nullptr);
+
+ QSignalSpy movementStartedSpy(flickable, SIGNAL(movementStarted()));
+ QSignalSpy movementEndedSpy(flickable, SIGNAL(movementEnded()));
+ QSignalSpy flickStartedSpy(flickable, SIGNAL(flickStarted()));
+ QSignalSpy flickEndedSpy(flickable, SIGNAL(flickEnded()));
+
+ QTest::touchEvent(window, touchDevice).press(0, {10, 10}).commit();
+ QQuickTouchUtils::flush(window);
+
+ QTest::touchEvent(window, touchDevice).move(0, {10, 100}).commit();
+ QQuickTouchUtils::flush(window);
+
+ QTest::touchEvent(window, touchDevice).release(0, {10, 200}).commit();
+ QQuickTouchUtils::flush(window);
+
+ QTRY_VERIFY(!flickable->isMoving());
+
+ QCOMPARE(movementStartedSpy.size(), 1);
+ QCOMPARE(flickStartedSpy.size(), 1);
+ QCOMPARE(movementEndedSpy.size(), 1);
+ QCOMPARE(flickEndedSpy.size(), 1);
+}
+
+void tst_qquickflickable::proportionalWheelScrolling() // QTBUG-106338 etc.
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("wheel.qml")));
+ QQuickViewTestUtils::centerOnScreen(&window);
+ QVERIFY(window.isVisible());
+ QQuickItem *rootItem = window.rootObject();
+ QVERIFY(rootItem);
+ QQuickFlickable *flickable = rootItem->findChild<QQuickFlickable *>();
+ QVERIFY(flickable);
+
+ QVERIFY(!flickable->property("ended").value<bool>());
+
+ QPointF pos(flickable->x() + flickable->width() / 2, flickable->y() + flickable->height() / 2);
+ QPoint angleDelta(0, -120);
+ QWheelEvent wheelEvent(pos, window.mapToGlobal(pos), QPoint(), angleDelta,
+ Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
+
+ QGuiApplication::sendEvent(&window, &wheelEvent);
+ qApp->processEvents();
+
+ // Verify that scrolling is proportional to the wheel delta
+ QVERIFY(flickable->isMovingVertically());
+ QTRY_VERIFY(!flickable->isMovingVertically());
+
+ // The current movement formula being used is: delta / 120 * wheelScrollLines * 24
+ const int defaultWheelDecel = 15000;
+ bool wheelDecelerationEnvSet = false;
+ const int wheelDecelerationEnv = qEnvironmentVariableIntValue("QT_QUICK_FLICKABLE_WHEEL_DECELERATION", &wheelDecelerationEnvSet);
+ const qreal wheelDecel = wheelDecelerationEnvSet ? wheelDecelerationEnv : defaultWheelDecel;
+ const bool proportionalWheel = wheelDecel >= 15000;
+ qCDebug(lcTests) << "platform wheel decel" << defaultWheelDecel
+ << "env wheel decel" << wheelDecelerationEnv
+ << "expect proportional scrolling?" << proportionalWheel;
+ const qreal expectedMovementFromWheelClick = qAbs(angleDelta.y()) / 120 * qApp->styleHints()->wheelScrollLines() * 24;
+
+ if (proportionalWheel)
+ QCOMPARE(flickable->contentY(), expectedMovementFromWheelClick);
+
+ QVERIFY(flickable->property("ended").value<bool>());
+ QCOMPARE(flickable->property("movementsAfterEnd").value<int>(), 0);
+
+ flickable->setProperty("ended", QVariant::fromValue(false));
+ flickable->setContentY(0);
+
+ // Verify that multiple wheel events in a row won't accumulate the scroll distance, before the timeline completes
+ wheelEvent.setTimestamp(wheelEvent.timestamp() + 2000);
+ QGuiApplication::sendEvent(&window, &wheelEvent);
+
+ wheelEvent.setTimestamp(wheelEvent.timestamp() + 10);
+ QGuiApplication::sendEvent(&window, &wheelEvent);
+
+ wheelEvent.setTimestamp(wheelEvent.timestamp() + 10);
+ QGuiApplication::sendEvent(&window, &wheelEvent);
+
+ qApp->processEvents();
+
+ QVERIFY(flickable->isMovingVertically());
+ QTRY_VERIFY(!flickable->isMovingVertically());
+
+ if (proportionalWheel) {
+ QVERIFY2(flickable->contentY() >= expectedMovementFromWheelClick, "The contentItem moved shorter than expected from a wheelEvent");
+ QCOMPARE_LT(flickable->contentY(), expectedMovementFromWheelClick * 3);
+ }
+
+ QVERIFY(flickable->property("ended").value<bool>());
+ QCOMPARE(flickable->property("movementsAfterEnd").value<int>(), 0);
+}
+
+void tst_qquickflickable::touchCancel()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("flickable03.qml")));
+ QQuickViewTestUtils::centerOnScreen(&window);
+ QVERIFY(window.isVisible());
+
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window.rootObject());
+ QVERIFY(flickable != nullptr);
+
+ QSignalSpy movementStartedSpy(flickable, SIGNAL(movementStarted()));
+ QSignalSpy movementEndedSpy(flickable, SIGNAL(movementEnded()));
+
+ int touchPosY = 10;
+ QTest::touchEvent(&window, touchDevice).press(0, {10, touchPosY}).commit();
+ QQuickTouchUtils::flush(&window);
+
+ for (int i = 0; i < 3; ++i) {
+ touchPosY += qApp->styleHints()->startDragDistance();
+ QTest::touchEvent(&window, touchDevice).move(0, {10, touchPosY}).commit();
+ QQuickTouchUtils::flush(&window);
+ }
+
+ QTRY_COMPARE(movementStartedSpy.size(), 1);
+ QWindowSystemInterface::handleTouchCancelEvent(nullptr, touchDevice);
+ QTRY_COMPARE(movementEndedSpy.size(), 1);
+}
+
+void tst_qquickflickable::pixelAlignedEndPoints()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("endpoints.qml")));
+ QQuickViewTestUtils::centerOnScreen(&window);
+ QVERIFY(window.isVisible());
+ QQuickItem *rootItem = window.rootObject();
+ QVERIFY(rootItem);
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(rootItem);
+ QVERIFY(flickable);
+ flickable->setPixelAligned(true);
+ QVERIFY(flickable->isAtYBeginning());
+
+ QSignalSpy isAtEndSpy(flickable, &QQuickFlickable::atYEndChanged);
+ QSignalSpy isAtBeginningSpy(flickable, &QQuickFlickable::atYBeginningChanged);
+
+ flickable->setContentY(199.99);
+ QCOMPARE(flickable->contentY(), 200);
+ QVERIFY(!flickable->isAtYBeginning());
+ QVERIFY(flickable->isAtYEnd());
+ QCOMPARE(isAtEndSpy.count(), 1);
+ QCOMPARE(isAtBeginningSpy.count(), 1);
+
+ flickable->setContentY(0.01);
+ QCOMPARE(flickable->contentY(), 0);
+ QVERIFY(flickable->isAtYBeginning());
+ QVERIFY(!flickable->isAtYEnd());
+ QCOMPARE(isAtEndSpy.count(), 2);
+ QCOMPARE(isAtBeginningSpy.count(), 2);}
+
QTEST_MAIN(tst_qquickflickable)
#include "tst_qquickflickable.moc"
diff --git a/tests/auto/quick/qquickflipable/CMakeLists.txt b/tests/auto/quick/qquickflipable/CMakeLists.txt
index 95231d7ad9..f73d4f81d1 100644
--- a/tests/auto/quick/qquickflipable/CMakeLists.txt
+++ b/tests/auto/quick/qquickflipable/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickflipable.pro.
#####################################################################
## tst_qquickflipable Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickflipable LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,16 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickflipable
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickflipable.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -30,10 +37,10 @@ qt_internal_add_test(tst_qquickflipable
qt_internal_extend_target(tst_qquickflipable CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickflipable CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickflipable/data/flip-y-axis-flipable.qml b/tests/auto/quick/qquickflipable/data/flip-y-axis-flipable.qml
new file mode 100644
index 0000000000..a52e1fd942
--- /dev/null
+++ b/tests/auto/quick/qquickflipable/data/flip-y-axis-flipable.qml
@@ -0,0 +1,32 @@
+// Copyright (C) 2023 UnionTech Software Technology Co., Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Flipable {
+ id: flipable
+
+ property real angle: 0
+ width: 3840 // wider than 1024 * 2: part of it goes behind the camera while flipping
+ height: 2160
+
+ front: Rectangle {
+ width: parent.width
+ height: parent.height
+ color: "red"
+ anchors.centerIn: parent
+ }
+ back: Rectangle {
+ color: "yellow"
+ anchors.centerIn: parent
+ width: parent.width
+ height: parent.height
+ }
+ transform: Rotation {
+ id: rotation
+ origin.x: flipable.width / 2
+ origin.y: flipable.height / 2
+ axis.x: 0; axis.y: 1; axis.z: 0
+ angle: flipable.angle
+ }
+}
diff --git a/tests/auto/quick/qquickflipable/tst_qquickflipable.cpp b/tests/auto/quick/qquickflipable/tst_qquickflipable.cpp
index b4082b3d34..5941f32832 100644
--- a/tests/auto/quick/qquickflipable/tst_qquickflipable.cpp
+++ b/tests/auto/quick/qquickflipable/tst_qquickflipable.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
@@ -34,12 +9,13 @@
#include <QFontMetrics>
#include <QtQuick/private/qquickrectangle_p.h>
#include <math.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
class tst_qquickflipable : public QQmlDataTest
{
Q_OBJECT
public:
+ tst_qquickflipable();
private slots:
void create();
@@ -51,10 +27,18 @@ private slots:
void QTBUG_9161_crash();
void QTBUG_8474_qgv_abort();
+ void flipRotationAngle_data();
+ void flipRotationAngle();
+
private:
QQmlEngine engine;
};
+tst_qquickflipable::tst_qquickflipable()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
void tst_qquickflipable::create()
{
QQmlEngine engine;
@@ -131,6 +115,31 @@ void tst_qquickflipable::QTBUG_8474_qgv_abort()
delete window;
}
+void tst_qquickflipable::flipRotationAngle_data()
+{
+ QTest::addColumn<int>("angle");
+ QTest::addColumn<QQuickFlipable::Side>("side");
+
+ QTest::newRow("89") << 89 << QQuickFlipable::Front;
+ QTest::newRow("91") << 91 << QQuickFlipable::Back;
+ QTest::newRow("-89") << -89 << QQuickFlipable::Front;
+ QTest::newRow("-91") << -91 << QQuickFlipable::Back;
+}
+
+void tst_qquickflipable::flipRotationAngle() // QTBUG-75954
+{
+ QFETCH(int, angle);
+ QFETCH(QQuickFlipable::Side, side);
+
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("flip-y-axis-flipable.qml"));
+ QQuickFlipable *obj = qobject_cast<QQuickFlipable*>(c.create());
+ QVERIFY(obj != nullptr);
+ obj->setProperty("angle", angle);
+ QCOMPARE(obj->side(), side);
+ delete obj;
+}
+
QTEST_MAIN(tst_qquickflipable)
#include "tst_qquickflipable.moc"
diff --git a/tests/auto/quick/qquickfocusscope/BLACKLIST b/tests/auto/quick/qquickfocusscope/BLACKLIST
new file mode 100644
index 0000000000..7a1e82e98d
--- /dev/null
+++ b/tests/auto/quick/qquickfocusscope/BLACKLIST
@@ -0,0 +1,3 @@
+# QTBUG-103086
+[canvasFocus]
+android
diff --git a/tests/auto/quick/qquickfocusscope/CMakeLists.txt b/tests/auto/quick/qquickfocusscope/CMakeLists.txt
index dac0f78281..755612121e 100644
--- a/tests/auto/quick/qquickfocusscope/CMakeLists.txt
+++ b/tests/auto/quick/qquickfocusscope/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickfocusscope.pro.
#####################################################################
## tst_qquickfocusscope Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickfocusscope LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickfocusscope
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickfocusscope.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,10 +37,10 @@ qt_internal_add_test(tst_qquickfocusscope
qt_internal_extend_target(tst_qquickfocusscope CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickfocusscope CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickfocusscope/tst_qquickfocusscope.cpp b/tests/auto/quick/qquickfocusscope/tst_qquickfocusscope.cpp
index e59bb7266c..70e5f227d3 100644
--- a/tests/auto/quick/qquickfocusscope/tst_qquickfocusscope.cpp
+++ b/tests/auto/quick/qquickfocusscope/tst_qquickfocusscope.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QSignalSpy>
#include <QtQml/qqmlengine.h>
@@ -34,16 +9,16 @@
#include <private/qquicktextedit_p.h>
#include <QtQuick/private/qquicktext_p.h>
#include <QtQuick/private/qquickfocusscope_p.h>
-#include "../../shared/util.h"
-#include "../shared/visualtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
-using namespace QQuickVisualTestUtil;
+using namespace QQuickVisualTestUtils;
class tst_qquickfocusscope : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickfocusscope() {}
+ tst_qquickfocusscope() : QQmlDataTest(QT_QMLTEST_DATADIR) {}
private slots:
void basic();
@@ -404,78 +379,78 @@ void tst_qquickfocusscope::forceActiveFocus()
itemA1->forceActiveFocus();
QVERIFY(itemA1->hasActiveFocus());
QVERIFY(!rootObject->hasActiveFocus());
- QCOMPARE(rootSpy.count(), 0);
- QCOMPARE(scopeSpy.count(), 1);
+ QCOMPARE(rootSpy.size(), 0);
+ QCOMPARE(scopeSpy.size(), 1);
scopeA->forceActiveFocus();
QVERIFY(!itemA1->hasActiveFocus());
QVERIFY(scopeA->hasActiveFocus());
- QCOMPARE(scopeASpy.count(), 1);
- QCOMPARE(rootSpy.count(), 0);
- QCOMPARE(scopeSpy.count(), 1);
+ QCOMPARE(scopeASpy.size(), 1);
+ QCOMPARE(rootSpy.size(), 0);
+ QCOMPARE(scopeSpy.size(), 1);
itemA2->forceActiveFocus();
QVERIFY(!itemA1->hasActiveFocus());
QVERIFY(itemA2->hasActiveFocus());
QVERIFY(scopeA->hasActiveFocus());
- QCOMPARE(scopeASpy.count(), 1);
- QCOMPARE(rootSpy.count(), 0);
- QCOMPARE(scopeSpy.count(), 1);
+ QCOMPARE(scopeASpy.size(), 1);
+ QCOMPARE(rootSpy.size(), 0);
+ QCOMPARE(scopeSpy.size(), 1);
scopeA->forceActiveFocus();
QVERIFY(!itemA1->hasActiveFocus());
QVERIFY(itemA2->hasActiveFocus());
QVERIFY(scopeA->hasActiveFocus());
- QCOMPARE(scopeASpy.count(), 1);
- QCOMPARE(rootSpy.count(), 0);
- QCOMPARE(scopeSpy.count(), 1);
+ QCOMPARE(scopeASpy.size(), 1);
+ QCOMPARE(rootSpy.size(), 0);
+ QCOMPARE(scopeSpy.size(), 1);
itemA1->forceActiveFocus();
QVERIFY(itemA1->hasActiveFocus());
QVERIFY(!scopeA->hasActiveFocus());
QVERIFY(!itemA2->hasActiveFocus());
- QCOMPARE(scopeASpy.count(), 2);
- QCOMPARE(rootSpy.count(), 0);
- QCOMPARE(scopeSpy.count(), 1);
+ QCOMPARE(scopeASpy.size(), 2);
+ QCOMPARE(rootSpy.size(), 0);
+ QCOMPARE(scopeSpy.size(), 1);
// Then jump back and forth between branch 'a' and 'b'
itemB1->forceActiveFocus();
QVERIFY(itemB1->hasActiveFocus());
- QCOMPARE(rootSpy.count(), 0);
- QCOMPARE(scopeSpy.count(), 1);
+ QCOMPARE(rootSpy.size(), 0);
+ QCOMPARE(scopeSpy.size(), 1);
scopeA->forceActiveFocus();
QVERIFY(!itemA1->hasActiveFocus());
QVERIFY(!itemB1->hasActiveFocus());
QVERIFY(scopeA->hasActiveFocus());
- QCOMPARE(scopeASpy.count(), 3);
- QCOMPARE(rootSpy.count(), 0);
- QCOMPARE(scopeSpy.count(), 1);
+ QCOMPARE(scopeASpy.size(), 3);
+ QCOMPARE(rootSpy.size(), 0);
+ QCOMPARE(scopeSpy.size(), 1);
scopeB->forceActiveFocus();
QVERIFY(!scopeA->hasActiveFocus());
QVERIFY(!itemB1->hasActiveFocus());
QVERIFY(scopeB->hasActiveFocus());
- QCOMPARE(scopeASpy.count(), 4);
- QCOMPARE(scopeBSpy.count(), 1);
- QCOMPARE(rootSpy.count(), 0);
- QCOMPARE(scopeSpy.count(), 1);
+ QCOMPARE(scopeASpy.size(), 4);
+ QCOMPARE(scopeBSpy.size(), 1);
+ QCOMPARE(rootSpy.size(), 0);
+ QCOMPARE(scopeSpy.size(), 1);
itemA2->forceActiveFocus();
QVERIFY(!scopeB->hasActiveFocus());
QVERIFY(itemA2->hasActiveFocus());
- QCOMPARE(scopeASpy.count(), 5);
- QCOMPARE(scopeBSpy.count(), 2);
- QCOMPARE(rootSpy.count(), 0);
- QCOMPARE(scopeSpy.count(), 1);
+ QCOMPARE(scopeASpy.size(), 5);
+ QCOMPARE(scopeBSpy.size(), 2);
+ QCOMPARE(rootSpy.size(), 0);
+ QCOMPARE(scopeSpy.size(), 1);
itemB2->forceActiveFocus();
QVERIFY(!itemA2->hasActiveFocus());
QVERIFY(itemB2->hasActiveFocus());
- QCOMPARE(scopeASpy.count(), 6);
- QCOMPARE(scopeBSpy.count(), 3);
- QCOMPARE(rootSpy.count(), 0);
- QCOMPARE(scopeSpy.count(), 1);
+ QCOMPARE(scopeASpy.size(), 6);
+ QCOMPARE(scopeBSpy.size(), 3);
+ QCOMPARE(rootSpy.size(), 0);
+ QCOMPARE(scopeSpy.size(), 1);
delete view;
}
@@ -541,12 +516,12 @@ void tst_qquickfocusscope::canvasFocus()
QCOMPARE(item2->hasFocus(), false);
QCOMPARE(item2->hasActiveFocus(), false);
- QCOMPARE(rootFocusSpy.count(), 1);
- QCOMPARE(rootActiveFocusSpy.count(), 1);
- QCOMPARE(scope1FocusSpy.count(), 0);
- QCOMPARE(scope1ActiveFocusSpy.count(), 1);
- QCOMPARE(item1FocusSpy.count(), 0);
- QCOMPARE(item1ActiveFocusSpy.count(), 1);
+ QCOMPARE(rootFocusSpy.size(), 1);
+ QCOMPARE(rootActiveFocusSpy.size(), 1);
+ QCOMPARE(scope1FocusSpy.size(), 0);
+ QCOMPARE(scope1ActiveFocusSpy.size(), 1);
+ QCOMPARE(item1FocusSpy.size(), 0);
+ QCOMPARE(item1ActiveFocusSpy.size(), 1);
// view->hide(); // seemingly doesn't remove focus, so have an another view steal it.
@@ -562,12 +537,12 @@ void tst_qquickfocusscope::canvasFocus()
QCOMPARE(item1->hasFocus(), true);
QCOMPARE(item1->hasActiveFocus(), false);
- QCOMPARE(rootFocusSpy.count(), 2);
- QCOMPARE(rootActiveFocusSpy.count(), 2);
- QCOMPARE(scope1FocusSpy.count(), 0);
- QCOMPARE(scope1ActiveFocusSpy.count(), 2);
- QCOMPARE(item1FocusSpy.count(), 0);
- QCOMPARE(item1ActiveFocusSpy.count(), 2);
+ QCOMPARE(rootFocusSpy.size(), 2);
+ QCOMPARE(rootActiveFocusSpy.size(), 2);
+ QCOMPARE(scope1FocusSpy.size(), 0);
+ QCOMPARE(scope1ActiveFocusSpy.size(), 2);
+ QCOMPARE(item1FocusSpy.size(), 0);
+ QCOMPARE(item1ActiveFocusSpy.size(), 2);
// window does not have focus, so item2 will not get active focus
@@ -584,16 +559,16 @@ void tst_qquickfocusscope::canvasFocus()
QCOMPARE(item2->hasFocus(), true);
QCOMPARE(item2->hasActiveFocus(), false);
- QCOMPARE(rootFocusSpy.count(), 2);
- QCOMPARE(rootActiveFocusSpy.count(), 2);
- QCOMPARE(scope1FocusSpy.count(), 1);
- QCOMPARE(scope1ActiveFocusSpy.count(), 2);
- QCOMPARE(item1FocusSpy.count(), 0);
- QCOMPARE(item1ActiveFocusSpy.count(), 2);
- QCOMPARE(scope2FocusSpy.count(), 1);
- QCOMPARE(scope2ActiveFocusSpy.count(), 0);
- QCOMPARE(item2FocusSpy.count(), 1);
- QCOMPARE(item2ActiveFocusSpy.count(), 0);
+ QCOMPARE(rootFocusSpy.size(), 2);
+ QCOMPARE(rootActiveFocusSpy.size(), 2);
+ QCOMPARE(scope1FocusSpy.size(), 1);
+ QCOMPARE(scope1ActiveFocusSpy.size(), 2);
+ QCOMPARE(item1FocusSpy.size(), 0);
+ QCOMPARE(item1ActiveFocusSpy.size(), 2);
+ QCOMPARE(scope2FocusSpy.size(), 1);
+ QCOMPARE(scope2ActiveFocusSpy.size(), 0);
+ QCOMPARE(item2FocusSpy.size(), 1);
+ QCOMPARE(item2ActiveFocusSpy.size(), 0);
// give the window focus, and item2 will get active focus
view->show();
@@ -607,12 +582,12 @@ void tst_qquickfocusscope::canvasFocus()
QCOMPARE(scope2->hasActiveFocus(), true);
QCOMPARE(item2->hasFocus(), true);
QCOMPARE(item2->hasActiveFocus(), true);
- QCOMPARE(rootFocusSpy.count(), 3);
- QCOMPARE(rootActiveFocusSpy.count(), 3);
- QCOMPARE(scope2FocusSpy.count(), 1);
- QCOMPARE(scope2ActiveFocusSpy.count(), 1);
- QCOMPARE(item2FocusSpy.count(), 1);
- QCOMPARE(item2ActiveFocusSpy.count(), 1);
+ QCOMPARE(rootFocusSpy.size(), 3);
+ QCOMPARE(rootActiveFocusSpy.size(), 3);
+ QCOMPARE(scope2FocusSpy.size(), 1);
+ QCOMPARE(scope2ActiveFocusSpy.size(), 1);
+ QCOMPARE(item2FocusSpy.size(), 1);
+ QCOMPARE(item2ActiveFocusSpy.size(), 1);
delete view;
}
diff --git a/tests/auto/quick/qquickfontloader/CMakeLists.txt b/tests/auto/quick/qquickfontloader/CMakeLists.txt
index bfaa048bca..22f98b36d5 100644
--- a/tests/auto/quick/qquickfontloader/CMakeLists.txt
+++ b/tests/auto/quick/qquickfontloader/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickfontloader.pro.
#####################################################################
## tst_qquickfontloader Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickfontloader LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,18 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickfontloader
SOURCES
- ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h
- ../../shared/util.cpp ../../shared/util.h
tst_qquickfontloader.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -32,10 +38,10 @@ qt_internal_add_test(tst_qquickfontloader
qt_internal_extend_target(tst_qquickfontloader CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickfontloader CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp b/tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp
index 94d603654d..a94d9fdd21 100644
--- a/tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp
+++ b/tests/auto/quick/qquickfontloader/tst_qquickfontloader.cpp
@@ -1,38 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtTest/QSignalSpy>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlcontext.h>
#include <QtQuick/private/qquickfontloader_p.h>
-#include "../../shared/util.h"
-#include "../../shared/testhttpserver.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/testhttpserver_p.h>
#include <QtQuick/QQuickView>
#include <QtQuick/QQuickItem>
@@ -59,6 +34,7 @@ private:
};
tst_qquickfontloader::tst_qquickfontloader()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
@@ -171,27 +147,27 @@ void tst_qquickfontloader::changeFont()
QSignalSpy statusSpy(fontObject, SIGNAL(statusChanged()));
QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Ready);
- QCOMPARE(nameSpy.count(), 0);
- QCOMPARE(statusSpy.count(), 0);
+ QCOMPARE(nameSpy.size(), 0);
+ QCOMPARE(statusSpy.size(), 0);
QTRY_COMPARE(fontObject->name(), QString("OCRA"));
ctxt->setContextProperty("fnt", server.urlString("/daniel.ttf"));
QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Loading);
QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Ready);
- QCOMPARE(nameSpy.count(), 1);
- QCOMPARE(statusSpy.count(), 2);
+ QCOMPARE(nameSpy.size(), 1);
+ QCOMPARE(statusSpy.size(), 2);
QTRY_COMPARE(fontObject->name(), QString("Daniel"));
ctxt->setContextProperty("fnt", testFileUrl("tarzeau_ocr_a.ttf"));
QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Ready);
- QCOMPARE(nameSpy.count(), 2);
- QCOMPARE(statusSpy.count(), 2);
+ QCOMPARE(nameSpy.size(), 2);
+ QCOMPARE(statusSpy.size(), 2);
QTRY_COMPARE(fontObject->name(), QString("OCRA"));
ctxt->setContextProperty("fnt", server.urlString("/daniel.ttf"));
QTRY_COMPARE(fontObject->status(), QQuickFontLoader::Ready);
- QCOMPARE(nameSpy.count(), 3);
- QCOMPARE(statusSpy.count(), 2);
+ QCOMPARE(nameSpy.size(), 3);
+ QCOMPARE(statusSpy.size(), 2);
QTRY_COMPARE(fontObject->name(), QString("Daniel"));
}
@@ -199,9 +175,7 @@ void tst_qquickfontloader::changeFontSourceViaState()
{
QQuickView window(testFileUrl("qtbug-20268.qml"));
window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
- QCOMPARE(&window, qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
QQuickFontLoader *fontObject = qobject_cast<QQuickFontLoader*>(qvariant_cast<QObject *>(window.rootObject()->property("fontloader")));
QVERIFY(fontObject != nullptr);
diff --git a/tests/auto/quick/qquickfontloader_static/CMakeLists.txt b/tests/auto/quick/qquickfontloader_static/CMakeLists.txt
index efdf13c95d..3d1fe63d6b 100644
--- a/tests/auto/quick/qquickfontloader_static/CMakeLists.txt
+++ b/tests/auto/quick/qquickfontloader_static/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickfontloader_static.pro.
#####################################################################
## tst_qquickfontloader_static Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickfontloader_static LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,19 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickfontloader_static
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickfontloader_static.cpp
- DEFINES
- QT_DISABLE_DEPRECATED_BEFORE=0
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -33,10 +38,10 @@ qt_internal_add_test(tst_qquickfontloader_static
qt_internal_extend_target(tst_qquickfontloader_static CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickfontloader_static CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickfontloader_static/tst_qquickfontloader_static.cpp b/tests/auto/quick/qquickfontloader_static/tst_qquickfontloader_static.cpp
index 7e848ef2fc..ed692fcdd0 100644
--- a/tests/auto/quick/qquickfontloader_static/tst_qquickfontloader_static.cpp
+++ b/tests/auto/quick/qquickfontloader_static/tst_qquickfontloader_static.cpp
@@ -1,35 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtGui/QGuiApplication>
#include <QtQuick/QQuickView>
#include <QtQml/QQmlComponent>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <qtest.h>
QByteArray qmltemplate("import QtQuick 2.0\n"
@@ -46,11 +21,11 @@ QByteArray qmltemplate("import QtQuick 2.0\n"
" }\n"
"}\n");
-int main(int argc, char **argv)
+int actualTest(int argc, char **argv)
{
for (int i = 0; i < 3; i++) {
QGuiApplication app(argc, argv);
- QQmlDataTest dataTest;
+ QQmlDataTest dataTest(QT_QMLTEST_DATADIR);
dataTest.initTestCase();
QQuickView window;
QQmlComponent component (window.engine());
@@ -64,3 +39,25 @@ int main(int argc, char **argv)
}
return 0;
}
+
+// we need the QTestLib infrastructure to create a log file
+struct FontLoaderStaticTester : public QObject
+{
+ Q_OBJECT
+
+public:
+ int result = -1;
+private slots:
+ void verify() { QCOMPARE(result, 0); }
+};
+
+int main(int argc, char **argv)
+{
+ int result = actualTest(argc, argv);
+ QCoreApplication app(argc, argv);
+ FontLoaderStaticTester tester;
+ tester.result = result;
+ QTest::qExec(&tester, argc, argv);
+}
+
+#include "tst_qquickfontloader_static.moc"
diff --git a/tests/auto/quick/qquickfontmetrics/CMakeLists.txt b/tests/auto/quick/qquickfontmetrics/CMakeLists.txt
index 785248fb99..02a23f988e 100644
--- a/tests/auto/quick/qquickfontmetrics/CMakeLists.txt
+++ b/tests/auto/quick/qquickfontmetrics/CMakeLists.txt
@@ -1,13 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickfontmetrics.pro.
#####################################################################
## tst_quickfontmetrics Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_quickfontmetrics LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_quickfontmetrics
SOURCES
tst_quickfontmetrics.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Qml
Qt::QuickPrivate
diff --git a/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp b/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp
index f760890e3c..090d47d652 100644
--- a/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp
+++ b/tests/auto/quick/qquickfontmetrics/tst_quickfontmetrics.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QFont>
#include <QFontDatabase>
@@ -55,16 +30,16 @@ tst_QuickFontMetrics::tst_QuickFontMetrics()
void tst_QuickFontMetrics::properties()
{
- QStringList families = QFontDatabase::families().mid(0, 10);
+ const QStringList families = QFontDatabase::families().mid(0, 10);
QQuickFontMetrics metrics;
- foreach (const QString &family, families) {
+ for (const QString &family : families) {
QFont font(family);
QFontMetricsF expected(font);
QSignalSpy spy(&metrics, SIGNAL(fontChanged(QFont)));
metrics.setFont(font);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(metrics.ascent(), expected.ascent());
QCOMPARE(metrics.descent(), expected.descent());
diff --git a/tests/auto/quick/qquickframebufferobject/BLACKLIST b/tests/auto/quick/qquickframebufferobject/BLACKLIST
index 93dd7e9d1c..1e814c5ebe 100644
--- a/tests/auto/quick/qquickframebufferobject/BLACKLIST
+++ b/tests/auto/quick/qquickframebufferobject/BLACKLIST
@@ -1,4 +1,3 @@
-# QTBUG-65614
-b2qt
+# QTBUG-102721
[testThatStuffWorks]
-b2qt
+android
diff --git a/tests/auto/quick/qquickframebufferobject/CMakeLists.txt b/tests/auto/quick/qquickframebufferobject/CMakeLists.txt
index 9f242842e6..9d87a5703d 100644
--- a/tests/auto/quick/qquickframebufferobject/CMakeLists.txt
+++ b/tests/auto/quick/qquickframebufferobject/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickframebufferobject.pro.
#####################################################################
## tst_qquickframebufferobject Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickframebufferobject LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,13 +21,11 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickframebufferobject
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickframebufferobject.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Quick
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -30,10 +37,10 @@ qt_internal_add_test(tst_qquickframebufferobject
qt_internal_extend_target(tst_qquickframebufferobject CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickframebufferobject CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickframebufferobject/data/testStuff.qml b/tests/auto/quick/qquickframebufferobject/data/testStuff.qml
index c93909a337..fbde7ecc93 100644
--- a/tests/auto/quick/qquickframebufferobject/data/testStuff.qml
+++ b/tests/auto/quick/qquickframebufferobject/data/testStuff.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tests of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
import FBOItem 1.0
diff --git a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp
index 5a77215624..ffd6478f9c 100644
--- a/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp
+++ b/tests/auto/quick/qquickframebufferobject/tst_qquickframebufferobject.cpp
@@ -1,33 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
+#include <QGuiApplication>
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickview.h>
#include <qopenglcontext.h>
@@ -36,7 +12,7 @@
#include <QtQuick/QQuickFramebufferObject>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
#ifndef GL_MAX_SAMPLES
#define GL_MAX_SAMPLES 0x8D57
@@ -53,9 +29,9 @@ struct FrameInfo {
class ColorRenderer : public QQuickFramebufferObject::Renderer, protected QOpenGLFunctions
{
public:
- void render();
- void synchronize(QQuickFramebufferObject *item);
- QOpenGLFramebufferObject *createFramebufferObject(const QSize &size);
+ void render() override;
+ void synchronize(QQuickFramebufferObject *item) override;
+ QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override;
QSize textureSize;
QColor color;
@@ -72,7 +48,7 @@ class FBOItem : public QQuickFramebufferObject
Q_PROPERTY(QSize textureSize READ textureSize WRITE setTextureSize NOTIFY textureSizeChanged)
public:
- Renderer *createRenderer() const { return new ColorRenderer(); }
+ Renderer *createRenderer() const override { return new ColorRenderer(); }
void setColor(const QColor &color) { m_color = color; colorChanged(m_color); }
QColor color() const { return m_color; }
@@ -143,6 +119,8 @@ class tst_QQuickFramebufferObject: public QQmlDataTest
{
Q_OBJECT
public:
+ tst_QQuickFramebufferObject();
+
private slots:
void initTestCase() override;
void testThatStuffWorks_data();
@@ -151,6 +129,11 @@ private slots:
void testInvalidate();
};
+tst_QQuickFramebufferObject::tst_QQuickFramebufferObject()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
void tst_QQuickFramebufferObject::initTestCase()
{
QQmlDataTest::initTestCase();
@@ -202,6 +185,10 @@ void tst_QQuickFramebufferObject::testThatStuffWorks()
view.requestActivate();
QVERIFY(QTest::qWaitForWindowExposed(&view));
+ if (QGuiApplication::platformName() == "offscreen" &&
+ view.rendererInterface()->graphicsApi() == QSGRendererInterface::Software)
+ QSKIP("offscreen software rendering doesn't work with FBOs");
+
QImage result = view.grabWindow();
QCOMPARE(frameInfo.renderCount, 1);
@@ -242,6 +229,10 @@ void tst_QQuickFramebufferObject::testInvalidate()
view.requestActivate();
QVERIFY(QTest::qWaitForWindowExposed(&view));
+ if (QGuiApplication::platformName() == "offscreen" &&
+ view.rendererInterface()->graphicsApi() == QSGRendererInterface::Software)
+ QSKIP("offscreen software rendering doesn't work with FBOs");
+
QCOMPARE(frameInfo.fboSize, QSize(200, 200));
frameInfo.createFBOCount = 0;
diff --git a/tests/auto/quick/qquickgraphicsinfo/CMakeLists.txt b/tests/auto/quick/qquickgraphicsinfo/CMakeLists.txt
index 5a45d8aabd..13759ea9e3 100644
--- a/tests/auto/quick/qquickgraphicsinfo/CMakeLists.txt
+++ b/tests/auto/quick/qquickgraphicsinfo/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickgraphicsinfo.pro.
#####################################################################
## tst_qquickgraphicsinfo Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickgraphicsinfo LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,13 +21,11 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickgraphicsinfo
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickgraphicsinfo.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Quick
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -30,10 +37,10 @@ qt_internal_add_test(tst_qquickgraphicsinfo
qt_internal_extend_target(tst_qquickgraphicsinfo CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickgraphicsinfo CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickgraphicsinfo/tst_qquickgraphicsinfo.cpp b/tests/auto/quick/qquickgraphicsinfo/tst_qquickgraphicsinfo.cpp
index 09c423890b..e142cbaad6 100644
--- a/tests/auto/quick/qquickgraphicsinfo/tst_qquickgraphicsinfo.cpp
+++ b/tests/auto/quick/qquickgraphicsinfo/tst_qquickgraphicsinfo.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/qtest.h>
#include <QtTest/qsignalspy.h>
@@ -33,20 +8,28 @@
#include <QtQuick/qquickview.h>
#include <QtQuick/qsgrendererinterface.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
class tst_QQuickGraphicsInfo : public QQmlDataTest
{
Q_OBJECT
+public:
+ tst_QQuickGraphicsInfo();
+
private slots:
void testProperties();
};
+tst_QQuickGraphicsInfo::tst_QQuickGraphicsInfo()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
void tst_QQuickGraphicsInfo::testProperties()
{
QQuickView view;
- view.setSource(QUrl("data/basic.qml"));
+ view.setSource(testFileUrl("basic.qml"));
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
diff --git a/tests/auto/quick/qquickgridview/BLACKLIST b/tests/auto/quick/qquickgridview/BLACKLIST
index e7bef365e4..a684b1e8bb 100644
--- a/tests/auto/quick/qquickgridview/BLACKLIST
+++ b/tests/auto/quick/qquickgridview/BLACKLIST
@@ -1,5 +1,6 @@
[snapOneRow]
-macos # QTBUG-86729
msvc-2019
+windows-10 gcc developer-build
[snapToRow]
msvc-2019
+windows-10 gcc developer-build
diff --git a/tests/auto/quick/qquickgridview/CMakeLists.txt b/tests/auto/quick/qquickgridview/CMakeLists.txt
index 07dd48c0a8..38dfc4f1f6 100644
--- a/tests/auto/quick/qquickgridview/CMakeLists.txt
+++ b/tests/auto/quick/qquickgridview/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickgridview.pro.
#####################################################################
## tst_qquickgridview Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickgridview LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,16 +21,8 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickgridview
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickgridview.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
@@ -29,6 +30,7 @@ qt_internal_add_test(tst_qquickgridview
Qt::QmlPrivate
Qt::QuickPrivate
Qt::QuickTest
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -40,10 +42,10 @@ qt_internal_add_test(tst_qquickgridview
qt_internal_extend_target(tst_qquickgridview CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickgridview CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickgridview/data/attachedProperties.qml b/tests/auto/quick/qquickgridview/data/attachedProperties.qml
index b1662dac44..f5fb173b89 100644
--- a/tests/auto/quick/qquickgridview/data/attachedProperties.qml
+++ b/tests/auto/quick/qquickgridview/data/attachedProperties.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickgridview/data/displayMargin.qml b/tests/auto/quick/qquickgridview/data/displayMargin.qml
index 4d6b74bba1..9bfdafbe61 100644
--- a/tests/auto/quick/qquickgridview/data/displayMargin.qml
+++ b/tests/auto/quick/qquickgridview/data/displayMargin.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Jolla Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.3
diff --git a/tests/auto/quick/qquickgridview/data/margins2.qml b/tests/auto/quick/qquickgridview/data/margins2.qml
index 346933d3c9..7735fc5362 100644
--- a/tests/auto/quick/qquickgridview/data/margins2.qml
+++ b/tests/auto/quick/qquickgridview/data/margins2.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.7
diff --git a/tests/auto/quick/qquickgridview/data/negativeDisplayMargin.qml b/tests/auto/quick/qquickgridview/data/negativeDisplayMargin.qml
index d4a36e315a..3d5c8494a6 100644
--- a/tests/auto/quick/qquickgridview/data/negativeDisplayMargin.qml
+++ b/tests/auto/quick/qquickgridview/data/negativeDisplayMargin.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.3
diff --git a/tests/auto/quick/qquickgridview/data/qtbug49218.qml b/tests/auto/quick/qquickgridview/data/qtbug49218.qml
index 1a55fe5b3a..3689c45b0e 100644
--- a/tests/auto/quick/qquickgridview/data/qtbug49218.qml
+++ b/tests/auto/quick/qquickgridview/data/qtbug49218.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.4
Item {
diff --git a/tests/auto/quick/qquickgridview/data/qtbug91461.qml b/tests/auto/quick/qquickgridview/data/qtbug91461.qml
new file mode 100644
index 0000000000..4a13984b80
--- /dev/null
+++ b/tests/auto/quick/qquickgridview/data/qtbug91461.qml
@@ -0,0 +1,34 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+import QtQuick
+
+Item {
+ width: 640
+ height: 800
+
+ property real cellSize: 100
+
+ GridView {
+ id: grid
+ anchors.fill: parent
+ model: 1000
+ cellWidth: cellSize
+ cellHeight: cellSize
+ cacheBuffer: 0
+ currentIndex: 0
+
+ delegate: Rectangle {
+ implicitWidth: grid.cellWidth - 10
+ implicitHeight: grid.cellHeight - 10
+ color: GridView.isCurrentItem ? "green" : "lightgreen"
+ radius: 5
+ border.width: GridView.isCurrentItem ? 3 : 1
+ border.color: "black"
+
+ Text {
+ anchors.centerIn: parent
+ text: model.index
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickgridview/data/qtbug92998.qml b/tests/auto/quick/qquickgridview/data/qtbug92998.qml
new file mode 100644
index 0000000000..d7db5fb843
--- /dev/null
+++ b/tests/auto/quick/qquickgridview/data/qtbug92998.qml
@@ -0,0 +1,53 @@
+import QtQuick 2.12
+import QtQuick.Window 2.12
+
+Item {
+ width: 450
+ height: 650
+ GridView {
+ objectName: "gridview"
+ id: gridView
+ width: 450
+ height: 650
+ layoutDirection: Qt.RightToLeft
+ property int cells: calcCells(width)
+ cellWidth: width / cells
+ cellHeight: cellWidth
+
+ delegate: Component {
+ Item {
+ width: gridView.cellWidth
+ height: gridView.cellHeight
+ Rectangle {
+ anchors {
+ fill: parent
+ margins: 10
+ }
+ color: "green"
+ }
+ }
+ }
+ model: [
+ { number: "1" },
+ { number: "2" },
+ { number: "3" },
+ { number: "4" },
+ { number: "5" },
+ { number: "6" },
+ { number: "7" },
+ { number: "8" },
+ { number: "9" },
+ { number: "10" },
+ { number: "11" },
+ { number: "12" },
+ { number: "13" },
+ { number: "14" },
+ { number: "15" },
+ { number: "16" }];
+ function calcCells(w) {
+ var rw = 120;
+ var c = Math.max(1, Math.round(w / rw));
+ return c;
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickgridview/data/removeAccessibleChildrenEvenIfReusingItems.qml b/tests/auto/quick/qquickgridview/data/removeAccessibleChildrenEvenIfReusingItems.qml
new file mode 100644
index 0000000000..a1d00bfbdf
--- /dev/null
+++ b/tests/auto/quick/qquickgridview/data/removeAccessibleChildrenEvenIfReusingItems.qml
@@ -0,0 +1,48 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.15
+
+Rectangle {
+ id: page
+ width: 640
+ height: 480
+
+ Accessible.role : Accessible.Client
+
+ GridView {
+ id: grid
+
+ width: 640
+ height: 480
+ model: listModel
+
+ cellWidth: 180
+ cellHeight: 30
+
+ delegate: Text {
+ id: textDelegate
+ text: name
+ Accessible.role: Accessible.Button
+ Accessible.name: name
+ }
+ reuseItems: true
+ Accessible.role : Accessible.Client
+ }
+
+ ListModel {
+ id: listModel
+ ListElement { name: "item11"}
+ ListElement { name: "item12"}
+ ListElement { name: "item13"}
+ ListElement { name: "item14"}
+ }
+
+ function replaceItems() {
+ listModel.clear()
+ listModel.insert(0, {"name" : "item21"})
+ listModel.insert(1, {"name" : "item22"})
+ listModel.insert(2, {"name" : "item23"})
+ listModel.insert(3, {"name" : "item24"})
+ }
+}
diff --git a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
index c625f99c00..3eb96e2bb4 100644
--- a/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
+++ b/tests/auto/quick/qquickgridview/tst_qquickgridview.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtCore/qstringlistmodel.h>
@@ -41,9 +16,9 @@
#include <QtQuick/private/qquickgridview_p.h>
#include <QtQuick/private/qquicktext_p.h>
#include <QtQmlModels/private/qqmllistmodel_p.h>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
-#include "../shared/visualtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <QtGui/qguiapplication.h>
#include "qplatformdefs.h"
@@ -55,8 +30,8 @@ Q_DECLARE_METATYPE(QQuickItemView::VerticalLayoutDirection)
Q_DECLARE_METATYPE(QQuickItemView::PositionMode)
Q_DECLARE_METATYPE(Qt::Key)
-using namespace QQuickViewTestUtil;
-using namespace QQuickVisualTestUtil;
+using namespace QQuickViewTestUtils;
+using namespace QQuickVisualTestUtils;
#define SHARE_VIEWS
@@ -67,7 +42,7 @@ public:
tst_QQuickGridView();
private slots:
- void init();
+ void init() override;
void cleanupTestCase();
void items();
void changed();
@@ -212,11 +187,14 @@ private slots:
void QTBUG_45640();
void QTBUG_49218();
+ void positionViewAtBeginningAfterResizingCells();
void QTBUG_48870_fastModelUpdates();
void QTBUG_86255();
+ void resizeDynamicCellWidthRtL();
void keyNavigationEnabled();
void releaseItems();
+ void removeAccessibleChildrenEvenIfReusingItems();
private:
QList<int> toIntList(const QVariantList &list);
@@ -318,12 +296,16 @@ private:
QString testForView;
};
-tst_QQuickGridView::tst_QQuickGridView() : m_view(nullptr)
+tst_QQuickGridView::tst_QQuickGridView()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+ , m_view(nullptr)
{
}
void tst_QQuickGridView::init()
{
+ QQmlDataTest::init();
+
#ifdef SHARE_VIEWS
if (m_view && QString(QTest::currentTestFunction()) != testForView) {
testForView = QString();
@@ -369,7 +351,7 @@ void tst_QQuickGridView::items()
QTRY_COMPARE(gridview->count(), model.count());
QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
- QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
+ QTRY_COMPARE(contentItem->childItems().size(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
for (int i = 0; i < model.count(); ++i) {
QQuickText *name = findItem<QQuickText>(contentItem, "textName", i);
@@ -384,7 +366,7 @@ void tst_QQuickGridView::items()
QaimModel model2;
ctxt->setContextProperty("testModel", &model2);
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
QTRY_COMPARE(itemCount, 0);
delete window;
@@ -449,7 +431,7 @@ void tst_QQuickGridView::inserted_basic()
model.insertItem(1, "Will", "9876");
QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
- QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
+ QTRY_COMPARE(contentItem->childItems().size(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
QTRY_VERIFY(name != nullptr);
@@ -471,7 +453,7 @@ void tst_QQuickGridView::inserted_basic()
model.insertItem(0, "Foo", "1111"); // zero index, and current item
- QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
+ QTRY_COMPARE(contentItem->childItems().size(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
name = findItem<QQuickText>(contentItem, "textName", 0);
QTRY_VERIFY(name != nullptr);
@@ -537,7 +519,7 @@ void tst_QQuickGridView::inserted_defaultLayout(QQuickGridView::Flow flow,
insertCount = insertCount_ttb;
}
if (setContentPos(gridview, contentYRowOffset))
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QList<QPair<QString, QString> > newData;
for (int i=0; i<insertCount; i++)
@@ -558,9 +540,9 @@ void tst_QQuickGridView::inserted_defaultLayout(QQuickGridView::Flow flow,
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
int firstVisibleIndex = -1;
- for (int i=0; i<items.count(); i++) {
+ for (int i=0; i<items.size(); i++) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
- if (item && delegateVisible(item)) {
+ if (item && isDelegateVisible(item)) {
firstVisibleIndex = i;
break;
}
@@ -568,7 +550,7 @@ void tst_QQuickGridView::inserted_defaultLayout(QQuickGridView::Flow flow,
QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
// Confirm items positioned correctly and indexes correct
- for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
+ for (int i = firstVisibleIndex; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
QCOMPARE(item->position(), expectedItemPos(gridview, i, rowOffsetAfterMove));
@@ -723,13 +705,13 @@ void tst_QQuickGridView::insertBeforeVisible()
QTRY_VERIFY(contentItem != nullptr);
gridview->setCacheBuffer(cacheBuffer);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
// trigger a refill (not just setting contentY) so that the visibleItems grid is updated
int firstVisibleIndex = 12; // move to an index where the top item is not visible
gridview->setContentY(firstVisibleIndex/3 * 60.0);
gridview->setCurrentIndex(firstVisibleIndex);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QTRY_COMPARE(gridview->currentIndex(), firstVisibleIndex);
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", firstVisibleIndex);
@@ -746,12 +728,12 @@ void tst_QQuickGridView::insertBeforeVisible()
// now, moving to the top of the view should position the inserted items correctly
int itemsOffsetAfterMove = (insertCount / 3) * -60.0;
gridview->setCurrentIndex(0);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QTRY_COMPARE(gridview->currentIndex(), 0);
QTRY_COMPARE(gridview->contentY(), 0.0 + itemsOffsetAfterMove);
// Confirm items positioned correctly and indexes correct
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
@@ -805,7 +787,7 @@ void tst_QQuickGridView::removed_basic()
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
model.removeItem(1);
QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
@@ -823,7 +805,7 @@ void tst_QQuickGridView::removed_basic()
QTRY_COMPARE(removed, QString("Item1"));
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -844,7 +826,7 @@ void tst_QQuickGridView::removed_basic()
// Confirm items positioned correctly
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -857,7 +839,7 @@ void tst_QQuickGridView::removed_basic()
QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
// Confirm items positioned correctly
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -892,10 +874,10 @@ void tst_QQuickGridView::removed_basic()
QTRY_VERIFY(gridview->currentItem() != oldCurrent);
gridview->setContentY(0);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
// Confirm items positioned correctly
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QTRY_COMPARE(item->x(), qreal((i%3)*80));
@@ -968,7 +950,7 @@ void tst_QQuickGridView::removed_defaultLayout(QQuickGridView::Flow flow,
firstVisible = firstVisible_ttb;
}
if (setContentPos(gridview, contentYRowOffset))
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
model.removeItems(removeIndex, removeCount);
gridview->forceLayout();
@@ -978,11 +960,11 @@ void tst_QQuickGridView::removed_defaultLayout(QQuickGridView::Flow flow,
int firstVisibleIndex = -1;
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
QRectF viewRect(gridview->contentX(), gridview->contentY(), gridview->width(), gridview->height());
- for (int i=0; i<items.count(); i++) {
+ for (int i=0; i<items.size(); i++) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (item) {
QRectF itemRect(item->x(), item->y(), item->width(), item->height());
- if (delegateVisible(item) && viewRect.intersects(itemRect)) {
+ if (isDelegateVisible(item) && viewRect.intersects(itemRect)) {
firstVisibleIndex = i;
QQmlExpression en(qmlContext(item), item, "name");
firstName = en.evaluate().toString();
@@ -994,7 +976,7 @@ void tst_QQuickGridView::removed_defaultLayout(QQuickGridView::Flow flow,
QCOMPARE(firstName, firstVisible);
// Confirm items positioned correctly and indexes correct
- for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
+ for (int i = firstVisibleIndex; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
QCOMPARE(item->position(), expectedItemPos(gridview, i, rowOffsetAfterMove));
@@ -1184,7 +1166,7 @@ void tst_QQuickGridView::addOrRemoveBeforeVisible()
gridview->setCurrentIndex(0);
qApp->processEvents();
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
// scroll down until item 0 is no longer drawn
// (bug not triggered if we just move using content y, since that doesn't
@@ -1195,7 +1177,7 @@ void tst_QQuickGridView::addOrRemoveBeforeVisible()
QTRY_COMPARE(gridview->currentIndex(), 24);
QTRY_COMPARE(gridview->contentY(), 220.0);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QTRY_VERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 0)); // 0 shouldn't be visible
if (doAdd) {
@@ -1219,7 +1201,7 @@ void tst_QQuickGridView::addOrRemoveBeforeVisible()
QCOMPARE(name->text(), QString("Item1"));
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QTRY_VERIFY(findItem<QQuickItem>(contentItem, "wrapper", i));
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
@@ -1256,7 +1238,7 @@ void tst_QQuickGridView::clear()
QVERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
model.clear();
gridview->forceLayout();
@@ -1309,7 +1291,7 @@ void tst_QQuickGridView::moved_defaultLayout(QQuickGridView::Flow flow,
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QQuickItem *currentItem = gridview->currentItem();
QTRY_VERIFY(currentItem != nullptr);
@@ -1320,24 +1302,24 @@ void tst_QQuickGridView::moved_defaultLayout(QQuickGridView::Flow flow,
count = count_ttb;
}
if (setContentPos(gridview, contentYRowOffset))
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
model.moveItems(from, to, count);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
// Confirm items positioned correctly and indexes correct
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
int firstVisibleIndex = -1;
- for (int i=0; i<items.count(); i++) {
+ for (int i=0; i<items.size(); i++) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
- if (item && delegateVisible(item)) {
+ if (item && isDelegateVisible(item)) {
firstVisibleIndex = i;
break;
}
}
QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
- for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
+ for (int i = firstVisibleIndex; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item &&
( (flow == QQuickGridView::FlowLeftToRight && i >= firstVisibleIndex + (3*6))
@@ -1562,9 +1544,9 @@ void tst_QQuickGridView::multipleChanges(bool condensed)
QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
QTRY_VERIFY(gridview != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
- for (int i=0; i<changes.count(); i++) {
+ for (int i=0; i<changes.size(); i++) {
switch (changes[i].type) {
case ListChange::Inserted:
{
@@ -1590,10 +1572,10 @@ void tst_QQuickGridView::multipleChanges(bool condensed)
break;
}
if (condensed) {
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
}
}
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QCOMPARE(gridview->count(), newCount);
QCOMPARE(gridview->count(), model.count());
@@ -1603,7 +1585,7 @@ void tst_QQuickGridView::multipleChanges(bool condensed)
QQuickText *number;
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i=0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
@@ -1836,7 +1818,7 @@ void tst_QQuickGridView::currentIndex()
QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
QVERIFY(gridview != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QQuickItem *contentItem = gridview->contentItem();
QVERIFY(contentItem != nullptr);
@@ -1910,9 +1892,9 @@ void tst_QQuickGridView::currentIndex()
// moving currentItem out of view should make it invisible
gridview->setCurrentIndex(0);
- QTRY_VERIFY(delegateVisible(gridview->currentItem()));
+ QTRY_VERIFY(isDelegateVisible(gridview->currentItem()));
gridview->setContentY(200);
- QTRY_VERIFY(!delegateVisible(gridview->currentItem()));
+ QTRY_VERIFY(!isDelegateVisible(gridview->currentItem()));
delete window;
}
@@ -1938,7 +1920,7 @@ void tst_QQuickGridView::noCurrentIndex()
QVERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
// current index should be -1
QCOMPARE(gridview->currentIndex(), -1);
@@ -1983,7 +1965,7 @@ void tst_QQuickGridView::keyNavigation()
gridview->setFlow(flow);
gridview->setLayoutDirection(layoutDirection);
gridview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
window->requestActivate();
QVERIFY(QTest::qWaitForWindowActive(window));
@@ -2191,7 +2173,7 @@ void tst_QQuickGridView::changeFlow()
QTRY_VERIFY(contentItem != nullptr);
// Confirm items positioned correctly and indexes correct
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -2209,7 +2191,7 @@ void tst_QQuickGridView::changeFlow()
ctxt->setContextProperty("testTopToBottom", QVariant(true));
// Confirm items positioned correctly and indexes correct
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -2227,7 +2209,7 @@ void tst_QQuickGridView::changeFlow()
ctxt->setContextProperty("testRightToLeft", QVariant(true));
// Confirm items positioned correctly and indexes correct
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -2247,7 +2229,7 @@ void tst_QQuickGridView::changeFlow()
QTRY_COMPARE(gridview->contentX(), 0.);
// Confirm items positioned correctly and indexes correct
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -2341,17 +2323,17 @@ void tst_QQuickGridView::propertyChanges()
QTRY_COMPARE(gridView->cacheBuffer(), 3);
QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowTopToBottom);
- QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
- QTRY_COMPARE(cacheBufferSpy.count(),1);
- QTRY_COMPARE(flowSpy.count(),1);
+ QTRY_COMPARE(keyNavigationWrapsSpy.size(),1);
+ QTRY_COMPARE(cacheBufferSpy.size(),1);
+ QTRY_COMPARE(flowSpy.size(),1);
gridView->setWrapEnabled(false);
gridView->setCacheBuffer(3);
gridView->setFlow(QQuickGridView::FlowTopToBottom);
- QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
- QTRY_COMPARE(cacheBufferSpy.count(),1);
- QTRY_COMPARE(flowSpy.count(),1);
+ QTRY_COMPARE(keyNavigationWrapsSpy.size(),1);
+ QTRY_COMPARE(cacheBufferSpy.size(),1);
+ QTRY_COMPARE(flowSpy.size(),1);
gridView->setFlow(QQuickGridView::FlowLeftToRight);
QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowLeftToRight);
@@ -2364,26 +2346,26 @@ void tst_QQuickGridView::propertyChanges()
QTRY_COMPARE(gridView->cacheBuffer(), 5);
QTRY_COMPARE(gridView->layoutDirection(), Qt::RightToLeft);
- QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
- QTRY_COMPARE(cacheBufferSpy.count(),2);
- QTRY_COMPARE(layoutSpy.count(),1);
- QTRY_COMPARE(flowSpy.count(),2);
+ QTRY_COMPARE(keyNavigationWrapsSpy.size(),2);
+ QTRY_COMPARE(cacheBufferSpy.size(),2);
+ QTRY_COMPARE(layoutSpy.size(),1);
+ QTRY_COMPARE(flowSpy.size(),2);
gridView->setWrapEnabled(true);
gridView->setCacheBuffer(5);
gridView->setLayoutDirection(Qt::RightToLeft);
- QTRY_COMPARE(keyNavigationWrapsSpy.count(),2);
- QTRY_COMPARE(cacheBufferSpy.count(),2);
- QTRY_COMPARE(layoutSpy.count(),1);
- QTRY_COMPARE(flowSpy.count(),2);
+ QTRY_COMPARE(keyNavigationWrapsSpy.size(),2);
+ QTRY_COMPARE(cacheBufferSpy.size(),2);
+ QTRY_COMPARE(layoutSpy.size(),1);
+ QTRY_COMPARE(flowSpy.size(),2);
gridView->setFlow(QQuickGridView::FlowTopToBottom);
QTRY_COMPARE(gridView->flow(), QQuickGridView::FlowTopToBottom);
- QTRY_COMPARE(flowSpy.count(),3);
+ QTRY_COMPARE(flowSpy.size(),3);
gridView->setFlow(QQuickGridView::FlowTopToBottom);
- QTRY_COMPARE(flowSpy.count(),3);
+ QTRY_COMPARE(flowSpy.size(),3);
delete window;
}
@@ -2423,24 +2405,24 @@ void tst_QQuickGridView::componentChanges()
QVERIFY(gridView->headerItem());
QVERIFY(gridView->footerItem());
- QTRY_COMPARE(highlightSpy.count(),1);
- QTRY_COMPARE(delegateSpy.count(),1);
- QTRY_COMPARE(headerSpy.count(),1);
- QTRY_COMPARE(footerSpy.count(),1);
- QTRY_COMPARE(headerItemSpy.count(),1);
- QTRY_COMPARE(footerItemSpy.count(),1);
+ QTRY_COMPARE(highlightSpy.size(),1);
+ QTRY_COMPARE(delegateSpy.size(),1);
+ QTRY_COMPARE(headerSpy.size(),1);
+ QTRY_COMPARE(footerSpy.size(),1);
+ QTRY_COMPARE(headerItemSpy.size(),1);
+ QTRY_COMPARE(footerItemSpy.size(),1);
gridView->setHighlight(&component);
gridView->setDelegate(&delegateComponent);
gridView->setHeader(&component);
gridView->setFooter(&component);
- QTRY_COMPARE(highlightSpy.count(),1);
- QTRY_COMPARE(delegateSpy.count(),1);
- QTRY_COMPARE(headerSpy.count(),1);
- QTRY_COMPARE(footerSpy.count(),1);
- QTRY_COMPARE(headerItemSpy.count(),1);
- QTRY_COMPARE(footerItemSpy.count(),1);
+ QTRY_COMPARE(highlightSpy.size(),1);
+ QTRY_COMPARE(delegateSpy.size(),1);
+ QTRY_COMPARE(headerSpy.size(),1);
+ QTRY_COMPARE(footerSpy.size(),1);
+ QTRY_COMPARE(headerItemSpy.size(),1);
+ QTRY_COMPARE(footerItemSpy.size(),1);
delete window;
}
@@ -2461,13 +2443,13 @@ void tst_QQuickGridView::modelChanges()
gridView->setModel(modelVariant);
QTRY_COMPARE(gridView->model(), modelVariant);
- QTRY_COMPARE(modelSpy.count(),1);
+ QTRY_COMPARE(modelSpy.size(),1);
gridView->setModel(modelVariant);
- QTRY_COMPARE(modelSpy.count(),1);
+ QTRY_COMPARE(modelSpy.size(),1);
gridView->setModel(QVariant());
- QTRY_COMPARE(modelSpy.count(),2);
+ QTRY_COMPARE(modelSpy.size(),2);
delete window;
}
@@ -2493,7 +2475,7 @@ void tst_QQuickGridView::positionViewAtBeginningEnd()
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
// positionViewAtBeginning
gridview->setContentY(150);
@@ -2580,10 +2562,10 @@ void tst_QQuickGridView::positionViewAtIndex()
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
window->rootObject()->setProperty("enforceRange", enforceRange);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
if (topToBottom)
gridview->setContentX(initContentPos);
@@ -2597,7 +2579,7 @@ void tst_QQuickGridView::positionViewAtIndex()
QTRY_COMPARE(gridview->contentY(), contentPos);
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = index; i < model.count() && i < itemCount-index-1; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -2734,14 +2716,14 @@ void tst_QQuickGridView::mirroring()
QCOMPARE(gridviewA->layoutDirection(), gridviewA->effectiveLayoutDirection());
// LTR != RTL
- foreach (const QString objectName, objectNames)
+ for (const QString &objectName : std::as_const(objectNames))
QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
gridviewB->setProperty("layoutDirection", Qt::LeftToRight);
// LTR == LTR
- foreach (const QString objectName, objectNames)
+ for (const QString &objectName : std::as_const(objectNames))
QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
QCOMPARE(gridviewB->layoutDirection(), gridviewB->effectiveLayoutDirection());
@@ -2749,25 +2731,25 @@ void tst_QQuickGridView::mirroring()
QVERIFY(gridviewB->layoutDirection() != gridviewB->effectiveLayoutDirection());
// LTR != LTR+mirror
- foreach (const QString objectName, objectNames)
+ for (const QString &objectName : std::as_const(objectNames))
QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
gridviewA->setProperty("layoutDirection", Qt::RightToLeft);
// RTL == LTR+mirror
- foreach (const QString objectName, objectNames)
+ for (const QString &objectName : std::as_const(objectNames))
QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
gridviewB->setProperty("layoutDirection", Qt::RightToLeft);
// RTL != RTL+mirror
- foreach (const QString objectName, objectNames)
+ for (const QString &objectName : std::as_const(objectNames))
QVERIFY(findItem<QQuickItem>(gridviewA, objectName)->x() != findItem<QQuickItem>(gridviewB, objectName)->x());
gridviewA->setProperty("layoutDirection", Qt::LeftToRight);
// LTR == RTL+mirror
- foreach (const QString objectName, objectNames)
+ for (const QString &objectName : std::as_const(objectNames))
QCOMPARE(findItem<QQuickItem>(gridviewA, objectName)->x(), findItem<QQuickItem>(gridviewB, objectName)->x());
delete windowA;
@@ -2793,7 +2775,7 @@ void tst_QQuickGridView::resetModel()
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QTRY_COMPARE(gridview->count(), model.rowCount());
@@ -2842,7 +2824,7 @@ void tst_QQuickGridView::enforceRange()
QTRY_COMPARE(gridview->preferredHighlightBegin(), 100.0);
QTRY_COMPARE(gridview->preferredHighlightEnd(), 100.0);
QTRY_COMPARE(gridview->highlightRangeMode(), QQuickGridView::StrictlyEnforceRange);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -3025,7 +3007,7 @@ void tst_QQuickGridView::footer()
gridview->setFlow(flow);
gridview->setLayoutDirection(layoutDirection);
gridview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -3092,7 +3074,7 @@ void tst_QQuickGridView::footer()
QSignalSpy footerItemSpy(gridview, SIGNAL(footerItemChanged()));
QMetaObject::invokeMethod(window->rootObject(), "changeFooter");
- QCOMPARE(footerItemSpy.count(), 1);
+ QCOMPARE(footerItemSpy.size(), 1);
footer = findItem<QQuickText>(contentItem, "footer");
QVERIFY(!footer);
@@ -3274,7 +3256,7 @@ void tst_QQuickGridView::header()
gridview->setFlow(flow);
gridview->setLayoutDirection(layoutDirection);
gridview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -3298,7 +3280,7 @@ void tst_QQuickGridView::header()
QCOMPARE(item->position(), firstDelegatePos);
model.clear();
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QCOMPARE(header->position(), initialHeaderPos); // header should stay where it is
if (flow == QQuickGridView::FlowLeftToRight)
QCOMPARE(gridview->contentHeight(), header->height());
@@ -3311,7 +3293,7 @@ void tst_QQuickGridView::header()
QSignalSpy headerItemSpy(gridview, SIGNAL(headerItemChanged()));
QMetaObject::invokeMethod(window->rootObject(), "changeHeader");
- QCOMPARE(headerItemSpy.count(), 1);
+ QCOMPARE(headerItemSpy.size(), 1);
header = findItem<QQuickText>(contentItem, "header");
QVERIFY(!header);
@@ -3351,7 +3333,7 @@ void tst_QQuickGridView::header()
gridview->setFlow(flow);
gridview->setLayoutDirection(layoutDirection);
gridview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
gridview->setWidth(240);
gridview->setHeight(320);
@@ -3496,7 +3478,7 @@ void tst_QQuickGridView::extents()
gridview->setFlow(flow);
gridview->setLayoutDirection(layoutDirection);
gridview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -3544,51 +3526,46 @@ void tst_QQuickGridView::extents_data()
QTest::newRow("LeftToRight, LtR, TtB")
<< QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::TopToBottom
- << QPointF(0, -20) << QPointF(0, 0)
- << QPointF(0, 20) << QPointF(240, 20)
+ << QPointF(0, -20) << QPointF(0, 0) << QPointF(0, 20) << QPointF(0, 20)
<< QPointF(0, -20) << QPointF(0, -20);
QTest::newRow("LeftToRight, RtL, TtB")
<< QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::TopToBottom
- << QPointF(0, -20) << QPointF(0, 0)
- << QPointF(0, 20) << QPointF(240, 20)
+ << QPointF(0, -20) << QPointF(0, 0) << QPointF(0, 20) << QPointF(0, 20)
<< QPointF(0, -20) << QPointF(0, -20);
QTest::newRow("LeftToRight, LtR, BtT")
<< QQuickGridView::FlowLeftToRight << Qt::LeftToRight << QQuickItemView::BottomToTop
- << QPointF(0, 0) << QPointF(0, -30)
- << QPointF(0, 320 - 20) << QPointF(240, 320 - 20) // content flow is reversed
+ << QPointF(0, 0) << QPointF(0, -30) << QPointF(0, 320 - 20)
+ << QPointF(0, 320 - 20) // content flow is reversed
<< QPointF(0, -30) << QPointF(0, (-60.0 * 10) - 30);
QTest::newRow("LeftToRight, RtL, BtT")
<< QQuickGridView::FlowLeftToRight << Qt::RightToLeft << QQuickItemView::BottomToTop
- << QPointF(0, 0) << QPointF(0, -30)
- << QPointF(0, 320 - 20) << QPointF(240, 320 - 20) // content flow is reversed
+ << QPointF(0, 0) << QPointF(0, -30) << QPointF(0, 320 - 20)
+ << QPointF(0, 320 - 20) // content flow is reversed
<< QPointF(0, -30) << QPointF(0, (-60.0 * 10) - 30);
-
QTest::newRow("TopToBottom, LtR, TtB")
<< QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::TopToBottom
- << QPointF(-20, 0) << QPointF(0, 0)
- << QPointF(20, 0) << QPointF(20, 320)
+ << QPointF(-20, 0) << QPointF(0, 0) << QPointF(20, 0) << QPointF(20, 0)
<< QPointF(-20, 0) << QPointF(-20, 0);
QTest::newRow("TopToBottom, RtL, TtB")
<< QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::TopToBottom
- << QPointF(0, 0) << QPointF(-30, 0)
- << QPointF(240 - 20, 0) << QPointF(240 - 20, 320) // content flow is reversed
+ << QPointF(0, 0) << QPointF(-30, 0) << QPointF(240 - 20, 0)
+ << QPointF(240 - 20, 0) // content flow is reversed
<< QPointF(-30, 0) << QPointF((-80.0 * 6) - 30, 0);
QTest::newRow("TopToBottom, LtR, BtT")
<< QQuickGridView::FlowTopToBottom << Qt::LeftToRight << QQuickItemView::BottomToTop
- << QPointF(-20, -320) << QPointF(0, -320)
- << QPointF(20, 0) << QPointF(20, 320)
+ << QPointF(-20, -320) << QPointF(0, -320) << QPointF(20, 0) << QPointF(20, 0)
<< QPointF(-20, 0) << QPointF(-20, 0);
QTest::newRow("TopToBottom, RtL, BtT")
<< QQuickGridView::FlowTopToBottom << Qt::RightToLeft << QQuickItemView::BottomToTop
- << QPointF(0, -320) << QPointF(-30, -320)
- << QPointF(240 - 20, 0) << QPointF(240 - 20, 320) // content flow is reversed
+ << QPointF(0, -320) << QPointF(-30, -320) << QPointF(240 - 20, 0)
+ << QPointF(240 - 20, 0) // content flow is reversed
<< QPointF(-30, 0) << QPointF((-80.0 * 6) - 30, 0);
}
@@ -3657,7 +3634,7 @@ void tst_QQuickGridView::resizeViewAndRepaint()
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
// item at index 10 should not be currently visible
QVERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
@@ -3670,37 +3647,37 @@ void tst_QQuickGridView::resizeViewAndRepaint()
// Ensure we handle -ve sizes
gridview->setHeight(-100);
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 3);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).size(), 3);
gridview->setCacheBuffer(120);
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 9);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).size(), 9);
// ensure items in cache become visible
gridview->setHeight(120);
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 15);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).size(), 15);
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
QTRY_VERIFY(item);
QTRY_COMPARE(item->x(), qreal((i%3)*80));
QTRY_COMPARE(item->y(), qreal((i/3)*60));
- QCOMPARE(delegateVisible(item), i < 9); // inside view visible, outside not visible
+ QCOMPARE(isDelegateVisible(item), i < 9); // inside view visible, outside not visible
}
// ensure items outside view become invisible
gridview->setHeight(60);
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 12);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).size(), 12);
- itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
QTRY_VERIFY(item);
QTRY_COMPARE(item->x(), qreal((i%3)*80));
QTRY_COMPARE(item->y(), qreal((i/3)*60));
- QCOMPARE(delegateVisible(item), i < 6); // inside view visible, outside not visible
+ QCOMPARE(isDelegateVisible(item), i < 6); // inside view visible, outside not visible
}
delete window;
@@ -3725,7 +3702,7 @@ void tst_QQuickGridView::resizeGrid()
ctxt->setContextProperty("testRightToLeft", layoutDirection == Qt::RightToLeft);
ctxt->setContextProperty("testBottomToTop", verticalLayoutDirection == QQuickGridView::BottomToTop);
window->setSource(testFileUrl("resizegrid.qml"));
- QQuickViewTestUtil::centerOnScreen(window, window->size());
+ QQuickViewTestUtils::centerOnScreen(window, window->size());
window->show();
qApp->processEvents();
@@ -3738,7 +3715,7 @@ void tst_QQuickGridView::resizeGrid()
// items are aligned correctly in right-to-left
window->rootObject()->setWidth(260);
window->rootObject()->setHeight(320);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QCOMPARE(gridview->contentX(), initialContentPos.x());
QCOMPARE(gridview->contentY(), initialContentPos.y());
@@ -3749,8 +3726,8 @@ void tst_QQuickGridView::resizeGrid()
// Confirm items positioned correctly and indexes correct
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
- QVERIFY(items.count() >= 18 && items.count() <= 21);
- for (int i = 0; i < model.count() && i < items.count(); ++i) {
+ QVERIFY(items.size() >= 18 && items.size() <= 21);
+ for (int i = 0; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
QCOMPARE(item->position(), expectedItemPos(gridview, i, 0));
@@ -3762,7 +3739,7 @@ void tst_QQuickGridView::resizeGrid()
// change from 3x5 grid to 4x7
window->rootObject()->setWidth(window->rootObject()->width() + 80);
window->rootObject()->setHeight(window->rootObject()->height() + 60*2);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
// other than in LeftToRight+RightToLeft layout, the first item should not move
// if view is resized
@@ -3781,8 +3758,8 @@ void tst_QQuickGridView::resizeGrid()
// Confirm items positioned correctly and indexes correct
items = findItems<QQuickItem>(contentItem, "wrapper");
- QVERIFY(items.count() >= 28);
- for (int i = 0; i < model.count() && i < items.count(); ++i) {
+ QVERIFY(items.size() >= 28);
+ for (int i = 0; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
QCOMPARE(item->position(), expectedItemPos(gridview, i, 0));
@@ -3867,10 +3844,10 @@ void tst_QQuickGridView::changeColumnCount()
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
// a single column of 6 items are visible
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
QCOMPARE(itemCount, 6);
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
@@ -3881,8 +3858,8 @@ void tst_QQuickGridView::changeColumnCount()
// now 6x3 grid is visible, plus 1 extra below for refill
gridview->setWidth(240);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
QCOMPARE(itemCount, 6*3 + 1);
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
@@ -3893,8 +3870,8 @@ void tst_QQuickGridView::changeColumnCount()
// back to single column
gridview->setWidth(100);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
QCOMPARE(itemCount, 6);
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
@@ -3995,8 +3972,8 @@ void tst_QQuickGridView::onAdd()
qApp->processEvents();
QVariantList result = gridview->property("addedDelegates").toList();
- QTRY_COMPARE(result.count(), items.count());
- for (int i=0; i<items.count(); i++)
+ QTRY_COMPARE(result.size(), items.size());
+ for (int i=0; i<items.size(); i++)
QCOMPARE(result[i].toString(), items[i].first);
releaseView(window);
@@ -4141,7 +4118,7 @@ void tst_QQuickGridView::margins()
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QCOMPARE(gridview->contentX(), -30.);
QCOMPARE(gridview->originX(), 0.);
@@ -4219,7 +4196,7 @@ void tst_QQuickGridView::margins()
// remove item before visible and check that left margin is maintained
// and originX is updated
gridview->setContentX(-400);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
model.removeItems(0, 4);
gridview->forceLayout();
QTRY_COMPARE(model.count(), gridview->count());
@@ -4261,7 +4238,7 @@ void tst_QQuickGridView::margins()
QVERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QCOMPARE(contentItem->x(), 200);
QCOMPARE(contentItem->y(), 20);
@@ -4332,7 +4309,7 @@ void tst_QQuickGridView::snapToRow()
QQuickView *window = getView();
- QQuickViewTestUtil::moveMouseAway(window);
+ QQuickViewTestUtils::moveMouseAway(window);
window->setSource(testFileUrl("snapToRow.qml"));
window->show();
qApp->processEvents();
@@ -4343,7 +4320,7 @@ void tst_QQuickGridView::snapToRow()
gridview->setFlow(flow);
gridview->setLayoutDirection(layoutDirection);
gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -4451,7 +4428,7 @@ void tst_QQuickGridView::snapOneRow()
qreal flickDuration = 180 * flickSlowdown;
QQuickView *window = getView();
- QQuickViewTestUtil::moveMouseAway(window);
+ QQuickViewTestUtils::moveMouseAway(window);
window->setSource(testFileUrl("snapOneRow.qml"));
window->show();
@@ -4463,7 +4440,7 @@ void tst_QQuickGridView::snapOneRow()
gridview->setFlow(flow);
gridview->setLayoutDirection(layoutDirection);
gridview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QQuickItem *contentItem = gridview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -4480,7 +4457,7 @@ void tst_QQuickGridView::snapOneRow()
if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
QCOMPARE(gridview->currentIndex(), 2);
- QCOMPARE(currentIndexSpy.count(), 1);
+ QCOMPARE(currentIndexSpy.size(), 1);
}
// flick to end
@@ -4493,7 +4470,7 @@ void tst_QQuickGridView::snapOneRow()
if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
QCOMPARE(gridview->currentIndex(), 6);
- QCOMPARE(currentIndexSpy.count(), 3);
+ QCOMPARE(currentIndexSpy.size(), 3);
}
if (flow == QQuickGridView::FlowLeftToRight)
@@ -4516,7 +4493,7 @@ void tst_QQuickGridView::snapOneRow()
if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
QCOMPARE(gridview->currentIndex(), 0);
- QCOMPARE(currentIndexSpy.count(), 6);
+ QCOMPARE(currentIndexSpy.size(), 6);
}
releaseView(window);
@@ -4625,12 +4602,12 @@ void tst_QQuickGridView::populateTransitions()
QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), 0);
QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 18);
} else {
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QCOMPARE(gridview->property("countPopulateTransitions").toInt(), 0);
QCOMPARE(gridview->property("countAddTransitions").toInt(), 0);
}
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i=0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
@@ -4652,7 +4629,7 @@ void tst_QQuickGridView::populateTransitions()
// clear the model
window->rootContext()->setContextProperty("testModel", QVariant());
QTRY_COMPARE(gridview->count(), 0);
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 0);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").size(), 0);
gridview->setProperty("countPopulateTransitions", 0);
gridview->setProperty("countAddTransitions", 0);
@@ -4661,12 +4638,12 @@ void tst_QQuickGridView::populateTransitions()
for (int i = 0; i < 30; i++)
model.addItem("item" + QString::number(i), "");
window->rootContext()->setContextProperty("testModel", &model);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), usePopulateTransition ? 18 : 0);
QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 0);
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i=0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
@@ -4684,7 +4661,7 @@ void tst_QQuickGridView::populateTransitions()
QTRY_COMPARE(gridview->property("countPopulateTransitions").toInt(), usePopulateTransition ? 18 : 0);
QTRY_COMPARE(gridview->property("countAddTransitions").toInt(), 0);
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i=0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
@@ -4749,11 +4726,11 @@ void tst_QQuickGridView::addTransitions()
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
if (contentYRowOffset != 0) {
gridview->setContentY(contentYRowOffset * 60.0);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
}
QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
@@ -4772,7 +4749,7 @@ void tst_QQuickGridView::addTransitions()
targetIndexes << i;
}
}
- QVERIFY(expectedTargetData.count() > 0);
+ QVERIFY(expectedTargetData.size() > 0);
}
// start animation
@@ -4785,7 +4762,7 @@ void tst_QQuickGridView::addTransitions()
QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
if (shouldAnimateTargets) {
- QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
+ QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.size());
QTRY_COMPARE(gridview->property("displaceTransitionsDone").toInt(),
expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
@@ -4811,7 +4788,7 @@ void tst_QQuickGridView::addTransitions()
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
int firstVisibleIndex = -1;
- for (int i=0; i<items.count(); i++) {
+ for (int i=0; i<items.size(); i++) {
if (items[i]->y() >= gridview->contentY()) {
QQmlExpression e(qmlContext(items[i]), items[i], "index");
firstVisibleIndex = e.evaluate().toInt();
@@ -4821,7 +4798,7 @@ void tst_QQuickGridView::addTransitions()
QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
// verify all items moved to the correct final positions
- for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
+ for (int i = firstVisibleIndex; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
QCOMPARE(item->x(), (i%3)*80.0);
@@ -4958,7 +4935,7 @@ void tst_QQuickGridView::moveTransitions()
if (contentYRowOffset != 0) {
gridview->setContentY(contentYRowOffset * 60.0);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
}
QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
@@ -4984,7 +4961,7 @@ void tst_QQuickGridView::moveTransitions()
model.moveItems(moveFrom, moveTo, moveCount);
gridview->forceLayout();
- QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
+ QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.size());
QTRY_COMPARE(gridview->property("displaceTransitionsDone").toInt(),
expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
@@ -5008,7 +4985,7 @@ void tst_QQuickGridView::moveTransitions()
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
int firstVisibleIndex = -1;
- for (int i=0; i<items.count(); i++) {
+ for (int i=0; i<items.size(); i++) {
if (items[i]->y() >= gridview->contentY()) {
QQmlExpression e(qmlContext(items[i]), items[i], "index");
firstVisibleIndex = e.evaluate().toInt();
@@ -5019,7 +4996,7 @@ void tst_QQuickGridView::moveTransitions()
// verify all items moved to the correct final positions
qreal pixelOffset = 60 * rowOffsetAfterMove;
- for (int i=firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
+ for (int i=firstVisibleIndex; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
QCOMPARE(item->x(), (i%3)*80.0);
@@ -5199,11 +5176,11 @@ void tst_QQuickGridView::removeTransitions()
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
if (contentYRowOffset != 0) {
gridview->setContentY(contentYRowOffset * 60.0);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
}
QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
@@ -5220,13 +5197,13 @@ void tst_QQuickGridView::removeTransitions()
targetIndexes << i;
}
}
- QVERIFY(expectedTargetData.count() > 0);
+ QVERIFY(expectedTargetData.size() > 0);
}
// calculate targetItems and expectedTargets before model changes
QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
QVariantMap expectedTargets;
- for (int i=0; i<targetIndexes.count(); i++)
+ for (int i=0; i<targetIndexes.size(); i++)
expectedTargets[model.name(targetIndexes[i])] = targetIndexes[i];
// start animation
@@ -5235,7 +5212,7 @@ void tst_QQuickGridView::removeTransitions()
QTRY_COMPARE(model.count(), gridview->count());
if (shouldAnimateTargets || expectedDisplacedIndexes.isValid()) {
- QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
+ QTRY_COMPARE(gridview->property("targetTransitionsDone").toInt(), expectedTargetData.size());
QTRY_COMPARE(gridview->property("displaceTransitionsDone").toInt(),
expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
@@ -5260,9 +5237,9 @@ void tst_QQuickGridView::removeTransitions()
}
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
- int itemCount = items.count();
+ int itemCount = items.size();
int firstVisibleIndex = -1;
- for (int i=0; i<items.count(); i++) {
+ for (int i=0; i<items.size(); i++) {
QQmlExpression e(qmlContext(items[i]), items[i], "index");
int index = e.evaluate().toInt();
if (firstVisibleIndex < 0 && items[i]->y() >= gridview->contentY())
@@ -5417,7 +5394,7 @@ void tst_QQuickGridView::displacedTransitions()
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
gridview->setProperty("displaceTransitionsDone", false);
@@ -5438,7 +5415,7 @@ void tst_QQuickGridView::displacedTransitions()
break;
case ListChange::Moved:
model.moveItems(change.index, change.to, change.count);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
break;
case ListChange::SetCurrent:
case ListChange::SetContentY:
@@ -5457,15 +5434,15 @@ void tst_QQuickGridView::displacedTransitions()
QTRY_VERIFY(gridview->property("displaceTransitionsDone").toBool());
// check the correct number of target items and indexes were received
- QCOMPARE(resultTargetIndexes.count(), expectedDisplacedIndexes.count());
- for (int i=0; i<resultTargetIndexes.count(); i++)
- QCOMPARE(resultTargetIndexes[i].value<QList<int> >().count(), change.count);
- QCOMPARE(resultTargetItems.count(), expectedDisplacedIndexes.count());
- for (int i=0; i<resultTargetItems.count(); i++)
- QCOMPARE(resultTargetItems[i].toList().count(), change.count);
+ QCOMPARE(resultTargetIndexes.size(), expectedDisplacedIndexes.count());
+ for (int i=0; i<resultTargetIndexes.size(); i++)
+ QCOMPARE(resultTargetIndexes[i].value<QList<int> >().size(), change.count);
+ QCOMPARE(resultTargetItems.size(), expectedDisplacedIndexes.count());
+ for (int i=0; i<resultTargetItems.size(); i++)
+ QCOMPARE(resultTargetItems[i].toList().size(), change.count);
} else {
- QCOMPARE(resultTargetIndexes.count(), 0);
- QCOMPARE(resultTargetItems.count(), 0);
+ QCOMPARE(resultTargetIndexes.size(), 0);
+ QCOMPARE(resultTargetItems.size(), 0);
}
if (change.type == ListChange::Inserted && useAddDisplaced && addDisplacedEnabled)
@@ -5492,7 +5469,7 @@ void tst_QQuickGridView::displacedTransitions()
// verify all items moved to the correct final positions
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
- for (int i=0; i < model.count() && i < items.count(); ++i) {
+ for (int i=0; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
QCOMPARE(item->x(), (i%3)*80.0);
@@ -5636,16 +5613,16 @@ void tst_QQuickGridView::multipleTransitions()
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
if (contentY != 0) {
gridview->setContentY(contentY);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
}
int timeBetweenActions = window->rootObject()->property("timeBetweenActions").toInt();
- for (int i=0; i<changes.count(); i++) {
+ for (int i=0; i<changes.size(); i++) {
switch (changes[i].type) {
case ListChange::Inserted:
{
@@ -5655,7 +5632,7 @@ void tst_QQuickGridView::multipleTransitions()
model.insertItems(changes[i].index, targetItems);
gridview->forceLayout();
QTRY_COMPARE(model.count(), gridview->count());
- if (i == changes.count() - 1) {
+ if (i == changes.size() - 1) {
QTRY_VERIFY(!gridview->property("runningAddTargets").toBool());
QTRY_VERIFY(!gridview->property("runningAddDisplaced").toBool());
} else {
@@ -5667,7 +5644,7 @@ void tst_QQuickGridView::multipleTransitions()
model.removeItems(changes[i].index, changes[i].count);
gridview->forceLayout();
QTRY_COMPARE(model.count(), gridview->count());
- if (i == changes.count() - 1) {
+ if (i == changes.size() - 1) {
QTRY_VERIFY(!gridview->property("runningRemoveTargets").toBool());
QTRY_VERIFY(!gridview->property("runningRemoveDisplaced").toBool());
} else {
@@ -5677,8 +5654,8 @@ void tst_QQuickGridView::multipleTransitions()
case ListChange::Moved:
model.moveItems(changes[i].index, changes[i].to, changes[i].count);
gridview->forceLayout();
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
- if (i == changes.count() - 1) {
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
+ if (i == changes.size() - 1) {
QTRY_VERIFY(!gridview->property("runningMoveTargets").toBool());
QTRY_VERIFY(!gridview->property("runningMoveDisplaced").toBool());
} else {
@@ -5687,12 +5664,12 @@ void tst_QQuickGridView::multipleTransitions()
break;
case ListChange::SetCurrent:
gridview->setCurrentIndex(changes[i].index);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
gridview->forceLayout();
break;
case ListChange::SetContentY:
gridview->setContentY(changes[i].pos);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
gridview->forceLayout();
break;
case ListChange::Polish:
@@ -5702,7 +5679,7 @@ void tst_QQuickGridView::multipleTransitions()
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
int firstVisibleIndex = -1;
- for (int i=0; i<items.count(); i++) {
+ for (int i=0; i<items.size(); i++) {
if (items[i]->y() >= contentY) {
QQmlExpression e(qmlContext(items[i]), items[i], "index");
firstVisibleIndex = e.evaluate().toInt();
@@ -5713,7 +5690,7 @@ void tst_QQuickGridView::multipleTransitions()
QVERIFY2(firstVisibleIndex >= 0, QTest::toString(firstVisibleIndex));
// verify all items moved to the correct final positions
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i=firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
@@ -5806,7 +5783,7 @@ void tst_QQuickGridView::multipleDisplaced()
QTRY_VERIFY(gridview != nullptr);
QQuickItem *contentItem = gridview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
model.moveItems(12, 8, 1);
QTest::qWait(window->rootObject()->property("duration").toInt() / 2);
@@ -5814,14 +5791,15 @@ void tst_QQuickGridView::multipleDisplaced()
QTRY_VERIFY(gridview->property("displaceTransitionsDone").toBool());
QVariantMap transitionsStarted = gridview->property("displaceTransitionsStarted").toMap();
- foreach (const QString &name, transitionsStarted.keys()) {
+ const QStringList keys = transitionsStarted.keys();
+ for (const QString &name : keys) {
QVERIFY2(transitionsStarted[name] == 1,
QTest::toString(QString("%1 was displaced %2 times").arg(name).arg(transitionsStarted[name].toInt())));
}
// verify all items moved to the correct final positions
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
- for (int i=0; i < model.count() && i < items.count(); ++i) {
+ for (int i=0; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
QTRY_COMPARE(item->x(), (i%3)*80.0);
@@ -5856,7 +5834,7 @@ void tst_QQuickGridView::regression_QTBUG_57225()
QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "grid");
QVERIFY(gridview != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(gridview));
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
model.removeItems(removeIndex, removeCount);
QTRY_VERIFY(gridview->property("animationDone").toBool());
@@ -5915,7 +5893,7 @@ void tst_QQuickGridView::cacheBuffer()
QVERIFY(gridview->model() != 0);
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QTRY_COMPARE(item->x(), (i%3)*80.0);
@@ -5945,7 +5923,7 @@ void tst_QQuickGridView::cacheBuffer()
}
int newItemCount = 0;
- newItemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
+ newItemCount = findItems<QQuickItem>(contentItem, "wrapper", false).size();
// Confirm items positioned correctly
for (int i = 0; i < model.count() && i < newItemCount; ++i) {
@@ -6072,23 +6050,23 @@ void tst_QQuickGridView::unrequestedVisibility()
QQuickItem *item;
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 9));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 10));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 3));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 4));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
rightview->setCurrentIndex(0);
@@ -6096,9 +6074,9 @@ void tst_QQuickGridView::unrequestedVisibility()
QTRY_COMPARE(rightview->contentY(), 0.0);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
- QTRY_COMPARE(delegateVisible(item), true);
+ QTRY_COMPARE(isDelegateVisible(item), true);
QVERIFY(!findItem<QQuickItem>(leftContent, "wrapper", 11));
QVERIFY(!findItem<QQuickItem>(rightContent, "wrapper", 11));
@@ -6109,98 +6087,98 @@ void tst_QQuickGridView::unrequestedVisibility()
QTRY_COMPARE(rightview->contentY(), 0.0);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
- QTRY_COMPARE(delegateVisible(item), false);
+ QTRY_COMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
// move a non-visible item into view
model.moveItems(10, 9, 1);
- QVERIFY(QQuickTest::qWaitForItemPolished(leftview));
+ QVERIFY(QQuickTest::qWaitForPolish(leftview));
QTRY_VERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 1));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 1));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 11));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 11));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
// move a visible item out of view
model.moveItems(5, 3, 1);
- QVERIFY(QQuickTest::qWaitForItemPolished(leftview));
+ QVERIFY(QQuickTest::qWaitForPolish(leftview));
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
// move a non-visible item into view
model.moveItems(3, 5, 1);
- QVERIFY(QQuickTest::qWaitForItemPolished(leftview));
+ QVERIFY(QQuickTest::qWaitForPolish(leftview));
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
// move a visible item out of view
model.moveItems(9, 10, 1);
- QVERIFY(QQuickTest::qWaitForItemPolished(leftview));
+ QVERIFY(QQuickTest::qWaitForPolish(leftview));
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
// move a non-visible item into view
model.moveItems(10, 9, 1);
- QVERIFY(QQuickTest::qWaitForItemPolished(leftview));
+ QVERIFY(QQuickTest::qWaitForPolish(leftview));
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 3));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
QVERIFY(item = findItem<QQuickItem>(leftContent, "wrapper", 5));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 9));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(rightContent, "wrapper", 10));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
delete window;
}
@@ -6423,7 +6401,7 @@ QList<int> tst_QQuickGridView::toIntList(const QVariantList &list)
{
QList<int> ret;
bool ok = true;
- for (int i=0; i<list.count(); i++) {
+ for (int i=0; i<list.size(); i++) {
ret << list[i].toInt(&ok);
if (!ok)
qWarning() << "tst_QQuickGridView::toIntList(): not a number:" << list[i];
@@ -6435,7 +6413,7 @@ QList<int> tst_QQuickGridView::toIntList(const QVariantList &list)
void tst_QQuickGridView::matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes)
{
const QSet<int> expectedIndexSet(expectedIndexes.cbegin(), expectedIndexes.cend());
- for (int i=0; i<indexLists.count(); i++) {
+ for (int i=0; i<indexLists.size(); i++) {
const auto &currentList = indexLists[i].value<QList<int> >();
const QSet<int> current(currentList.cbegin(), currentList.cend());
if (current != expectedIndexSet)
@@ -6455,19 +6433,19 @@ void tst_QQuickGridView::matchItemsAndIndexes(const QVariantMap &items, const Qa
qDebug() << itemIndex;
QCOMPARE(model.name(itemIndex), name);
}
- QCOMPARE(items.count(), expectedIndexes.count());
+ QCOMPARE(items.size(), expectedIndexes.size());
}
void tst_QQuickGridView::matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems)
{
- for (int i=0; i<itemLists.count(); i++) {
+ for (int i=0; i<itemLists.size(); i++) {
QVariantList current = itemLists[i].toList();
- for (int j=0; j<current.count(); j++) {
+ for (int j=0; j<current.size(); j++) {
QQuickItem *o = qobject_cast<QQuickItem*>(current[j].value<QObject*>());
QVERIFY2(o, QTest::toString(QString("Invalid actual item at %1").arg(j)));
QVERIFY2(expectedItems.contains(o), QTest::toString(QString("Cannot match item %1").arg(j)));
}
- QCOMPARE(current.count(), expectedItems.count());
+ QCOMPARE(current.size(), expectedItems.size());
}
}
@@ -6488,22 +6466,22 @@ void tst_QQuickGridView::displayMargin()
QQuickItem *item97;
QVERIFY(item0 = findItem<QQuickItem>(content, "delegate", 0));
- QCOMPARE(delegateVisible(item0), true);
+ QCOMPARE(isDelegateVisible(item0), true);
// the 97th item should be within the end margin
QVERIFY(item97 = findItem<QQuickItem>(content, "delegate", 96));
- QCOMPARE(delegateVisible(item97), true);
+ QCOMPARE(isDelegateVisible(item97), true);
// GridView staggers item creation, so the 118th item should be outside the end margin.
QVERIFY(findItem<QQuickItem>(content, "delegate", 117) == nullptr);
// the first delegate should still be within the begin margin
gridview->positionViewAtIndex(20, QQuickGridView::Beginning);
- QCOMPARE(delegateVisible(item0), true);
+ QCOMPARE(isDelegateVisible(item0), true);
// the first delegate should now be outside the begin margin
gridview->positionViewAtIndex(36, QQuickGridView::Beginning);
- QCOMPARE(delegateVisible(item0), false);
+ QCOMPARE(isDelegateVisible(item0), false);
delete window;
}
@@ -6527,26 +6505,26 @@ void tst_QQuickGridView::negativeDisplayMargin()
QVERIFY(content != nullptr);
QVERIFY(item = findItem<QQuickItem>(content, "delegate", 0));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(content, "delegate", 7));
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
QVERIFY(item = findItem<QQuickItem>(content, "delegate", 8));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
// Flick until contentY means that delegate8 should be visible
listview->setProperty("contentY", 500);
QVERIFY(item = findItem<QQuickItem>(content, "delegate", 8));
- QTRY_COMPARE(delegateVisible(item), true);
+ QTRY_COMPARE(isDelegateVisible(item), true);
listview->setProperty("contentY", 1000);
QTRY_VERIFY(item = findItem<QQuickItem>(content, "delegate", 14));
- QTRY_COMPARE(delegateVisible(item), true);
+ QTRY_COMPARE(isDelegateVisible(item), true);
listview->setProperty("contentY", 0);
QVERIFY(item = findItem<QQuickItem>(content, "delegate", 4));
- QTRY_COMPARE(delegateVisible(item), true);
+ QTRY_COMPARE(isDelegateVisible(item), true);
delete window;
}
@@ -6571,11 +6549,11 @@ void tst_QQuickGridView::jsArrayChange()
}
view->setModel(QVariant::fromValue(array1));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
// no change
view->setModel(QVariant::fromValue(array2));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
void tst_QQuickGridView::contentHeightWithDelayRemove_data()
@@ -6695,6 +6673,34 @@ void tst_QQuickGridView::QTBUG_49218()
delete window;
}
+void tst_QQuickGridView::positionViewAtBeginningAfterResizingCells()
+{
+ // Check that positionViewAtBeginning() ends up showing row 0, even
+ // if the cells are resized while the viewport is deep down in the list (QTBUG-91461).
+ std::unique_ptr<QQuickView> window(createView());
+ window->setSource(testFileUrl("qtbug91461.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.get()));
+
+ QQuickItem *rootItem = qobject_cast<QQuickItem*>(window->rootObject());
+ QQuickGridView *gridview = qobject_cast<QQuickGridView *>(rootItem->childItems().first());
+ QVERIFY(gridview != nullptr);
+
+ gridview->positionViewAtEnd();
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
+ rootItem->setProperty("cellSize", 200);
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
+ gridview->positionViewAtBeginning();
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
+
+ const QPointF topLeftCorner = window->contentItem()->mapToItem(gridview->contentItem(), QPointF(20, 20));
+ const auto item0 = gridview->itemAt(topLeftCorner.x(), topLeftCorner.y());
+ QVERIFY(item0);
+
+ const int index = qmlContext(item0)->contextProperty("index").toInt();
+ QCOMPARE(index, 0);
+}
+
void tst_QQuickGridView::keyNavigationEnabled()
{
QScopedPointer<QQuickView> window(createView());
@@ -6716,7 +6722,7 @@ void tst_QQuickGridView::keyNavigationEnabled()
// of disabling both mouse and keyboard interaction.
QSignalSpy enabledSpy(gridView, SIGNAL(keyNavigationEnabledChanged()));
gridView->setInteractive(false);
- QCOMPARE(enabledSpy.count(), 1);
+ QCOMPARE(enabledSpy.size(), 1);
QCOMPARE(gridView->isKeyNavigationEnabled(), false);
flick(window.data(), QPoint(200, 175), QPoint(200, 50), 100);
@@ -6729,17 +6735,17 @@ void tst_QQuickGridView::keyNavigationEnabled()
// Check that isKeyNavigationEnabled implicitly follows the value of interactive.
gridView->setInteractive(true);
- QCOMPARE(enabledSpy.count(), 2);
+ QCOMPARE(enabledSpy.size(), 2);
QCOMPARE(gridView->isKeyNavigationEnabled(), true);
// Change it back again for the next check.
gridView->setInteractive(false);
- QCOMPARE(enabledSpy.count(), 3);
+ QCOMPARE(enabledSpy.size(), 3);
QCOMPARE(gridView->isKeyNavigationEnabled(), false);
// Setting keyNavigationEnabled to true shouldn't enable mouse interaction.
gridView->setKeyNavigationEnabled(true);
- QCOMPARE(enabledSpy.count(), 4);
+ QCOMPARE(enabledSpy.size(), 4);
flick(window.data(), QPoint(200, 175), QPoint(200, 50), 100);
QVERIFY(!gridView->isMoving());
QCOMPARE(gridView->contentY(), 0.0);
@@ -6752,7 +6758,7 @@ void tst_QQuickGridView::keyNavigationEnabled()
// Changing interactive now shouldn't result in keyNavigationEnabled changing,
// since we broke the "binding".
gridView->setInteractive(true);
- QCOMPARE(enabledSpy.count(), 4);
+ QCOMPARE(enabledSpy.size(), 4);
// Keyboard interaction shouldn't work now.
gridView->setKeyNavigationEnabled(false);
@@ -6808,6 +6814,25 @@ void tst_QQuickGridView::QTBUG_86255()
QTRY_COMPARE(view->isFlicking(), false);
}
+void tst_QQuickGridView::resizeDynamicCellWidthRtL()
+{
+ QScopedPointer<QQuickView> window(createView());
+ QTRY_VERIFY(window);
+ window->setSource(testFileUrl("qtbug92998.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickGridView *gridview = findItem<QQuickGridView>(window->rootObject(), "gridview");
+ QTRY_VERIFY(gridview != nullptr);
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
+ gridview->setWidth(460);
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
+ QTRY_COMPARE(gridview->contentX(), 0.f);
+ gridview->setWidth(360);
+ QVERIFY(QQuickTest::qWaitForPolish(gridview));
+ QTRY_COMPARE(gridview->contentX(), 0.f);
+}
+
void tst_QQuickGridView::releaseItems()
{
QScopedPointer<QQuickView> view(createView());
@@ -6820,6 +6845,36 @@ void tst_QQuickGridView::releaseItems()
gridview->setModel(123);
}
+void tst_QQuickGridView::removeAccessibleChildrenEvenIfReusingItems()
+{
+ auto window = std::make_unique<QQuickView>();
+ window->setSource(testFileUrl("removeAccessibleChildrenEvenIfReusingItems.qml"));
+ window->show();
+
+ QQuickItem *contentItem = window->contentItem();
+ QVERIFY(contentItem);
+ QQuickItem *rootItem = contentItem->childItems().first();
+ QVERIFY(rootItem);
+
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(window.get());
+ QVERIFY(iface);
+ QAccessibleInterface *gridView = iface->child(0)->child(0);
+ QCOMPARE(gridView->childCount(), 4);
+ QCOMPARE(gridView->child(0)->text(QAccessible::Text::Name), "item11");
+ QCOMPARE(gridView->child(1)->text(QAccessible::Text::Name), "item12");
+ QCOMPARE(gridView->child(2)->text(QAccessible::Text::Name), "item13");
+ QCOMPARE(gridView->child(3)->text(QAccessible::Text::Name), "item14");
+
+ QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "replaceItems"));
+
+ QCOMPARE(gridView->childCount(), 4);
+ QTRY_COMPARE(gridView->child(0)->text(QAccessible::Text::Name), "item21");
+ QTRY_COMPARE(gridView->child(1)->text(QAccessible::Text::Name), "item22");
+ QTRY_COMPARE(gridView->child(2)->text(QAccessible::Text::Name), "item23");
+ QTRY_COMPARE(gridView->child(3)->text(QAccessible::Text::Name), "item24");
+}
+
+
QTEST_MAIN(tst_QQuickGridView)
#include "tst_qquickgridview.moc"
diff --git a/tests/auto/quick/qquickimage/BLACKLIST b/tests/auto/quick/qquickimage/BLACKLIST
new file mode 100644
index 0000000000..a5c718c4f0
--- /dev/null
+++ b/tests/auto/quick/qquickimage/BLACKLIST
@@ -0,0 +1,11 @@
+# QTBUG-102721
+[hugeImages]
+android
+[multiFrame]
+android
+[sourceClipRect]
+android
+[tiling_QTBUG_6716]
+android
+[mirror]
+android
diff --git a/tests/auto/quick/qquickimage/CMakeLists.txt b/tests/auto/quick/qquickimage/CMakeLists.txt
index b7e5479639..774bdf0dcd 100644
--- a/tests/auto/quick/qquickimage/CMakeLists.txt
+++ b/tests/auto/quick/qquickimage/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickimage.pro.
#####################################################################
## tst_qquickimage Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickimage LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,23 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickimage
SOURCES
- ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickimage.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -37,10 +38,10 @@ qt_internal_add_test(tst_qquickimage
qt_internal_extend_target(tst_qquickimage CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickimage CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickimage/data/hugeImages.qml b/tests/auto/quick/qquickimage/data/hugeImages.qml
index f52389e7cd..00aad415f0 100644
--- a/tests/auto/quick/qquickimage/data/hugeImages.qml
+++ b/tests/auto/quick/qquickimage/data/hugeImages.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickimage/data/qtbug_32513.qml b/tests/auto/quick/qquickimage/data/qtbug_32513.qml
index 8e0e77399d..6f8adc6ba4 100644
--- a/tests/auto/quick/qquickimage/data/qtbug_32513.qml
+++ b/tests/auto/quick/qquickimage/data/qtbug_32513.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickimage/data/statusChanged.qml b/tests/auto/quick/qquickimage/data/statusChanged.qml
new file mode 100644
index 0000000000..ce4b4c4be9
--- /dev/null
+++ b/tests/auto/quick/qquickimage/data/statusChanged.qml
@@ -0,0 +1,25 @@
+import QtQuick
+
+Image {
+ id: root
+ property var changeSignals: []
+ property var statusChanges: []
+ property size statusChangedFirstImplicitSize: Qt.size(-1,-1)
+
+ source: "heart.png"
+
+ onFrameCountChanged: root.changeSignals.push("frameCount")
+ onCurrentFrameChanged: root.changeSignals.push("currentFrame")
+ onSourceSizeChanged: root.changeSignals.push("sourceSize")
+ onImplicitWidthChanged: root.changeSignals.push("implicitWidth")
+ onImplicitHeightChanged: root.changeSignals.push("implicitHeight")
+ onPaintedWidthChanged: root.changeSignals.push("paintedWidth")
+ onPaintedHeightChanged: root.changeSignals.push("paintedHeight")
+ onProgressChanged: root.changeSignals.push("progress")
+ onStatusChanged: (status) => {
+ root.changeSignals.push("status")
+ root.statusChanges.push(status)
+ if (root.statusChangedFirstImplicitSize.width < 0)
+ root.statusChangedFirstImplicitSize = Qt.size(root.implicitWidth, root.implicitHeight)
+ }
+}
diff --git a/tests/auto/quick/qquickimage/tst_qquickimage.cpp b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
index c7007cf997..427a45977f 100644
--- a/tests/auto/quick/qquickimage/tst_qquickimage.cpp
+++ b/tests/auto/quick/qquickimage/tst_qquickimage.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QTextDocument>
#include <QTcpServer>
@@ -47,13 +22,16 @@
#include <QQuickImageProvider>
#include <QQmlAbstractUrlInterceptor>
-#include "../../shared/util.h"
-#include "../../shared/testhttpserver.h"
-#include "../shared/visualtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/testhttpserver_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
// #define DEBUG_WRITE_OUTPUT
-using namespace QQuickVisualTestUtil;
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+
+using namespace QQuickVisualTestUtils;
Q_DECLARE_METATYPE(QQuickImageBase::Status)
@@ -93,6 +71,7 @@ private slots:
void sourceClipRect_data();
void sourceClipRect();
void progressAndStatusChanges();
+ void progressAndChangeSignalOrder();
void sourceSizeChanges();
void correctStatus();
void highdpi();
@@ -110,6 +89,7 @@ private:
};
tst_qquickimage::tst_qquickimage()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
@@ -169,10 +149,11 @@ void tst_qquickimage::imageSource_data()
QTest::newRow("remote svg") << "/heart.svg" << 595.0 << 841.0 << true << false << false << "";
if (QImageReader::supportedImageFormats().contains("svgz"))
QTest::newRow("remote svgz") << "/heart.svgz" << 595.0 << 841.0 << true << false << false << "";
- if (graphicsApi == QSGRendererInterface::OpenGLRhi) {
+ if (graphicsApi != QSGRendererInterface::Software) {
QTest::newRow("texturefile pkm format") << testFileUrl("logo.pkm").toString() << 256.0 << 256.0 << false << false << true << "";
QTest::newRow("texturefile ktx format") << testFileUrl("car.ktx").toString() << 146.0 << 80.0 << false << false << true << "";
QTest::newRow("texturefile async") << testFileUrl("logo.pkm").toString() << 256.0 << 256.0 << false << true << true << "";
+ QTest::newRow("texturefile remote") << "/logo.pkm" << 256.0 << 256.0 << true << false << true << "";
}
QTest::newRow("remote not found") << "/no-such-file.png" << 0.0 << 0.0 << true
<< false << true << "<Unknown File>:2:1: QML Image: Error transferring {{ServerBaseUrl}}/no-such-file.png - server replied: Not found";
@@ -203,18 +184,6 @@ void tst_qquickimage::imageSource()
QFETCH(bool, cache);
QFETCH(QString, error);
-
-#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
- if (qstrcmp(QTest::currentDataTag(), "remote") == 0
- || qstrcmp(QTest::currentDataTag(), "remote redirected") == 0
- || qstrcmp(QTest::currentDataTag(), "remote svg") == 0
- || qstrcmp(QTest::currentDataTag(), "remote svgz") == 0
- || qstrcmp(QTest::currentDataTag(), "remote not found") == 0
- ) {
- QSKIP("Remote tests cause occasional hangs in the CI system -- QTBUG-45655");
- }
-#endif
-
TestHTTPServer server;
if (remote) {
QVERIFY2(server.listen(), qPrintable(server.errorString()));
@@ -339,20 +308,23 @@ void tst_qquickimage::smooth()
void tst_qquickimage::mirror()
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QMap<QQuickImage::FillMode, QImage> screenshots;
- QList<QQuickImage::FillMode> fillModes;
- fillModes << QQuickImage::Stretch << QQuickImage::PreserveAspectFit << QQuickImage::PreserveAspectCrop
- << QQuickImage::Tile << QQuickImage::TileVertically << QQuickImage::TileHorizontally << QQuickImage::Pad;
+ const QList<QQuickImage::FillMode> fillModes{QQuickImage::Stretch,
+ QQuickImage::PreserveAspectFit,
+ QQuickImage::PreserveAspectCrop,
+ QQuickImage::Tile,
+ QQuickImage::TileVertically,
+ QQuickImage::TileHorizontally,
+ QQuickImage::Pad};
qreal width = 300;
qreal height = 250;
qreal devicePixelRatio = 1.0;
- foreach (QQuickImage::FillMode fillMode, fillModes) {
+ for (QQuickImage::FillMode fillMode : fillModes) {
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("mirror.qml"));
@@ -369,7 +341,7 @@ void tst_qquickimage::mirror()
devicePixelRatio = window->devicePixelRatio();
}
- foreach (QQuickImage::FillMode fillMode, fillModes) {
+ for (QQuickImage::FillMode fillMode : fillModes) {
QPixmap srcPixmap;
QVERIFY(srcPixmap.load(testFile("pattern.png")));
@@ -489,9 +461,8 @@ void tst_qquickimage::geometry_data()
QTest::newRow("PreserveAspectCrop explicit width 300, height 400") << "PreserveAspectCrop" << true << true << 300.0 << 800.0 << 800.0 << 400.0 << 400.0 << 400.0;
// bounding rect, painted rect and item rect are equal in stretching and tiling images
- QStringList fillModes;
- fillModes << "Stretch" << "Tile" << "TileVertically" << "TileHorizontally";
- foreach (QString fillMode, fillModes) {
+ QStringList fillModes{"Stretch", "Tile", "TileVertically", "TileHorizontally"};
+ for (const auto &fillMode : fillModes) {
QTest::newRow(fillMode.toLatin1()) << fillMode << false << false << 200.0 << 200.0 << 200.0 << 100.0 << 100.0 << 100.0;
QTest::newRow(QString(fillMode + " explicit width 300").toLatin1()) << fillMode << true << false << 300.0 << 300.0 << 300.0 << 100.0 << 100.0 << 100.0;
QTest::newRow(QString(fillMode + " explicit height 400").toLatin1()) << fillMode << false << true << 200.0 << 200.0 << 200.0 << 400.0 << 400.0 << 400.0;
@@ -554,9 +525,8 @@ void tst_qquickimage::big()
void tst_qquickimage::tiling_QTBUG_6716()
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QFETCH(QString, source);
@@ -608,9 +578,9 @@ void tst_qquickimage::noLoading()
ctxt->setContextProperty("srcImage", testFileUrl("green.png"));
QTRY_COMPARE(obj->status(), QQuickImage::Ready);
QTRY_COMPARE(obj->progress(), 1.0);
- QTRY_COMPARE(sourceSpy.count(), 1);
- QTRY_COMPARE(progressSpy.count(), 0);
- QTRY_COMPARE(statusSpy.count(), 1);
+ QTRY_COMPARE(sourceSpy.size(), 1);
+ QTRY_COMPARE(progressSpy.size(), 0);
+ QTRY_COMPARE(statusSpy.size(), 1);
// Loading remote file
ctxt->setContextProperty("srcImage", server.url("/rect.png"));
@@ -618,9 +588,9 @@ void tst_qquickimage::noLoading()
QTRY_COMPARE(obj->progress(), 0.0);
QTRY_COMPARE(obj->status(), QQuickImage::Ready);
QTRY_COMPARE(obj->progress(), 1.0);
- QTRY_COMPARE(sourceSpy.count(), 2);
- QTRY_VERIFY(progressSpy.count() >= 2);
- QTRY_COMPARE(statusSpy.count(), 3);
+ QTRY_COMPARE(sourceSpy.size(), 2);
+ QTRY_VERIFY(progressSpy.size() >= 2);
+ QTRY_COMPARE(statusSpy.size(), 3);
// Loading remote file again - should not go through 'Loading' state.
progressSpy.clear();
@@ -628,9 +598,9 @@ void tst_qquickimage::noLoading()
ctxt->setContextProperty("srcImage", server.url("/rect.png"));
QTRY_COMPARE(obj->status(), QQuickImage::Ready);
QTRY_COMPARE(obj->progress(), 1.0);
- QTRY_COMPARE(sourceSpy.count(), 4);
- QTRY_COMPARE(progressSpy.count(), 0);
- QTRY_COMPARE(statusSpy.count(), 5);
+ QTRY_COMPARE(sourceSpy.size(), 4);
+ QTRY_COMPARE(progressSpy.size(), 0);
+ QTRY_COMPARE(statusSpy.size(), 5);
delete obj;
}
@@ -685,17 +655,17 @@ void tst_qquickimage::sourceSize_QTBUG_14303()
QTRY_COMPARE(obj->sourceSize().width(), 200);
QTRY_COMPARE(obj->sourceSize().height(), 200);
- QTRY_COMPARE(sourceSizeSpy.count(), 0);
+ QTRY_COMPARE(sourceSizeSpy.size(), 0);
ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
QTRY_COMPARE(obj->sourceSize().width(), 120);
QTRY_COMPARE(obj->sourceSize().height(), 120);
- QTRY_COMPARE(sourceSizeSpy.count(), 1);
+ QTRY_COMPARE(sourceSizeSpy.size(), 1);
ctxt->setContextProperty("srcImage", testFileUrl("heart200.png"));
QTRY_COMPARE(obj->sourceSize().width(), 200);
QTRY_COMPARE(obj->sourceSize().height(), 200);
- QTRY_COMPARE(sourceSizeSpy.count(), 2);
+ QTRY_COMPARE(sourceSizeSpy.size(), 2);
delete obj;
}
@@ -837,48 +807,48 @@ void tst_qquickimage::sourceSizeChanges()
// Local
ctxt->setContextProperty("srcImage", QUrl(""));
QTRY_COMPARE(img->status(), QQuickImage::Null);
- QTRY_COMPARE(sourceSizeSpy.count(), 0);
+ QTRY_COMPARE(sourceSizeSpy.size(), 0);
ctxt->setContextProperty("srcImage", testFileUrl("heart.png"));
QTRY_COMPARE(img->status(), QQuickImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 1);
+ QTRY_COMPARE(sourceSizeSpy.size(), 1);
ctxt->setContextProperty("srcImage", testFileUrl("heart.png"));
QTRY_COMPARE(img->status(), QQuickImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 1);
+ QTRY_COMPARE(sourceSizeSpy.size(), 1);
ctxt->setContextProperty("srcImage", testFileUrl("heart_copy.png"));
QTRY_COMPARE(img->status(), QQuickImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 1);
+ QTRY_COMPARE(sourceSizeSpy.size(), 1);
ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
QTRY_COMPARE(img->status(), QQuickImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 2);
+ QTRY_COMPARE(sourceSizeSpy.size(), 2);
ctxt->setContextProperty("srcImage", QUrl(""));
QTRY_COMPARE(img->status(), QQuickImage::Null);
- QTRY_COMPARE(sourceSizeSpy.count(), 3);
+ QTRY_COMPARE(sourceSizeSpy.size(), 3);
// Remote
ctxt->setContextProperty("srcImage", server.url("/heart.png"));
QTRY_COMPARE(img->status(), QQuickImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 4);
+ QTRY_COMPARE(sourceSizeSpy.size(), 4);
ctxt->setContextProperty("srcImage", server.url("/heart.png"));
QTRY_COMPARE(img->status(), QQuickImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 4);
+ QTRY_COMPARE(sourceSizeSpy.size(), 4);
ctxt->setContextProperty("srcImage", server.url("/heart_copy.png"));
QTRY_COMPARE(img->status(), QQuickImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 4);
+ QTRY_COMPARE(sourceSizeSpy.size(), 4);
ctxt->setContextProperty("srcImage", server.url("/colors.png"));
QTRY_COMPARE(img->status(), QQuickImage::Ready);
- QTRY_COMPARE(sourceSizeSpy.count(), 5);
+ QTRY_COMPARE(sourceSizeSpy.size(), 5);
ctxt->setContextProperty("srcImage", QUrl(""));
QTRY_COMPARE(img->status(), QQuickImage::Null);
- QTRY_COMPARE(sourceSizeSpy.count(), 6);
+ QTRY_COMPARE(sourceSizeSpy.size(), 6);
delete img;
}
@@ -934,8 +904,7 @@ void tst_qquickimage::sourceClipRect()
QCOMPARE(image->implicitWidth(), sourceClipRect.isNull() ? 300 : sourceClipRect.width());
QCOMPARE(image->implicitHeight(), sourceClipRect.isNull() ? 300 : sourceClipRect.height());
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
QImage contents = toUnscaledImage(window->grabWindow());
if (contents.width() < sourceClipRect.width())
@@ -981,17 +950,17 @@ void tst_qquickimage::progressAndStatusChanges()
ctxt->setContextProperty("srcImage", testFileUrl("heart.png"));
QTRY_COMPARE(obj->status(), QQuickImage::Ready);
QTRY_COMPARE(obj->progress(), 1.0);
- QTRY_COMPARE(sourceSpy.count(), 0);
- QTRY_COMPARE(progressSpy.count(), 0);
- QTRY_COMPARE(statusSpy.count(), 0);
+ QTRY_COMPARE(sourceSpy.size(), 0);
+ QTRY_COMPARE(progressSpy.size(), 0);
+ QTRY_COMPARE(statusSpy.size(), 0);
// Loading local file
ctxt->setContextProperty("srcImage", testFileUrl("colors.png"));
QTRY_COMPARE(obj->status(), QQuickImage::Ready);
QTRY_COMPARE(obj->progress(), 1.0);
- QTRY_COMPARE(sourceSpy.count(), 1);
- QTRY_COMPARE(progressSpy.count(), 0);
- QTRY_COMPARE(statusSpy.count(), 1);
+ QTRY_COMPARE(sourceSpy.size(), 1);
+ QTRY_COMPARE(progressSpy.size(), 0);
+ QTRY_COMPARE(statusSpy.size(), 1);
// Loading remote file
ctxt->setContextProperty("srcImage", server.url("/heart.png"));
@@ -999,26 +968,48 @@ void tst_qquickimage::progressAndStatusChanges()
QTRY_COMPARE(obj->progress(), 0.0);
QTRY_COMPARE(obj->status(), QQuickImage::Ready);
QTRY_COMPARE(obj->progress(), 1.0);
- QTRY_COMPARE(sourceSpy.count(), 2);
- QTRY_VERIFY(progressSpy.count() > 1);
- QTRY_COMPARE(statusSpy.count(), 3);
+ QTRY_COMPARE(sourceSpy.size(), 2);
+ QTRY_VERIFY(progressSpy.size() > 1);
+ QTRY_COMPARE(statusSpy.size(), 3);
ctxt->setContextProperty("srcImage", "");
QTRY_COMPARE(obj->status(), QQuickImage::Null);
QTRY_COMPARE(obj->progress(), 0.0);
- QTRY_COMPARE(sourceSpy.count(), 3);
- QTRY_VERIFY(progressSpy.count() > 2);
- QTRY_COMPARE(statusSpy.count(), 4);
+ QTRY_COMPARE(sourceSpy.size(), 3);
+ QTRY_VERIFY(progressSpy.size() > 2);
+ QTRY_COMPARE(statusSpy.size(), 4);
delete obj;
}
+void tst_qquickimage::progressAndChangeSignalOrder()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("statusChanged.qml")));
+ QQuickImage *image = qmlobject_cast<QQuickImage *>(window.rootObject());
+ QVERIFY(image);
+
+ QTRY_COMPARE(image->status(), QQuickImageBase::Ready);
+ // QTBUG-120205: implicitSize should be correct when status changes to Ready
+ QCOMPARE(image->property("statusChangedFirstImplicitSize").toSize(), QSize(300, 300));
+ QCOMPARE(image->property("statusChanges").toList().size(), 1); // just Ready
+ const QStringList signalOrder = image->property("changeSignals").toStringList();
+ const QStringList expectedOrder = {"progress", "paintedHeight", "paintedWidth",
+ "implicitWidth", "implicitHeight",
+ "paintedHeight", "paintedWidth",
+ "status", "sourceSize", "frameCount"};
+ qCDebug(lcTests) << "signal order" << signalOrder;
+ // exact order may not be critical, and repeated signals may be silly;
+ // but this way we'll find out when it changes
+ QCOMPARE(signalOrder, expectedOrder);
+}
+
class TestQImageProvider : public QQuickImageProvider
{
public:
TestQImageProvider() : QQuickImageProvider(Image) {}
- QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize)
+ QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize) override
{
Q_UNUSED(requestedSize);
if (id == QLatin1String("first-image.png")) {
@@ -1163,9 +1154,8 @@ void tst_qquickimage::highDpiFillModesAndSizes()
void tst_qquickimage::hugeImages()
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QQuickView view;
view.setSource(testFileUrl("hugeImages.qml"));
@@ -1186,7 +1176,7 @@ class MyInterceptor : public QQmlAbstractUrlInterceptor
{
public:
MyInterceptor(QUrl url) : QQmlAbstractUrlInterceptor(), m_url(url) {}
- QUrl intercept(const QUrl &url, QQmlAbstractUrlInterceptor::DataType)
+ QUrl intercept(const QUrl &url, QQmlAbstractUrlInterceptor::DataType) override
{
if (url.scheme() == "interceptthis")
return m_url;
@@ -1222,9 +1212,8 @@ void tst_qquickimage::multiFrame_data()
void tst_qquickimage::multiFrame()
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QFETCH(QString, qmlfile);
QFETCH(bool, asynchronous);
@@ -1238,7 +1227,7 @@ void tst_qquickimage::multiFrame()
if (asynchronous) {
QCOMPARE(image->frameCount(), 0);
QTRY_COMPARE(image->frameCount(), 4);
- QCOMPARE(countSpy.count(), 1);
+ QCOMPARE(countSpy.size(), 1);
} else {
QCOMPARE(image->frameCount(), 4);
}
@@ -1257,7 +1246,7 @@ void tst_qquickimage::multiFrame()
image->setCurrentFrame(1);
QTRY_COMPARE(image->status(), QQuickImageBase::Ready);
- QCOMPARE(currentSpy.count(), 1);
+ QCOMPARE(currentSpy.size(), 1);
QCOMPARE(image->currentFrame(), 1);
contents = toUnscaledImage(view.grabWindow());
// The second frame is a green ball, approximately qRgba(0x27, 0xc8, 0x22, 0xff)
diff --git a/tests/auto/quick/qquickimageprovider/BLACKLIST b/tests/auto/quick/qquickimageprovider/BLACKLIST
new file mode 100644
index 0000000000..e78bcb13e9
--- /dev/null
+++ b/tests/auto/quick/qquickimageprovider/BLACKLIST
@@ -0,0 +1,21 @@
+# QTBUG-103047
+[requestImage_sync]
+android
+[requestImage_async]
+android
+[requestImage_async_forced]
+android
+[requestPixmap_sync]
+android
+[requestPixmap_async]
+android
+[removeProvider]
+android
+[threadTest]
+android
+[asyncTextureTest]
+android
+[instantAsyncTextureTest]
+android
+[asyncImageThreadSafety]
+android
diff --git a/tests/auto/quick/qquickimageprovider/CMakeLists.txt b/tests/auto/quick/qquickimageprovider/CMakeLists.txt
index a336e28048..33ab315873 100644
--- a/tests/auto/quick/qquickimageprovider/CMakeLists.txt
+++ b/tests/auto/quick/qquickimageprovider/CMakeLists.txt
@@ -1,20 +1,47 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickimageprovider.pro.
#####################################################################
## tst_qquickimageprovider Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickimageprovider LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
qt_internal_add_test(tst_qquickimageprovider
SOURCES
tst_qquickimageprovider.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
)
## Scopes:
#####################################################################
+
+qt_internal_extend_target(tst_qquickimageprovider CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=":/data"
+ )
+
+qt_internal_extend_target(tst_qquickimageprovider CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+ )
diff --git a/tests/auto/quick/qquickimageprovider/data/forImports.qml b/tests/auto/quick/qquickimageprovider/data/forImports.qml
new file mode 100644
index 0000000000..c11b37f327
--- /dev/null
+++ b/tests/auto/quick/qquickimageprovider/data/forImports.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+Image {
+ source: "image://test/no-such-file.png";
+}
diff --git a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp
index 9dc9ad53ea..ae891c3f2a 100644
--- a/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp
+++ b/tests/auto/quick/qquickimageprovider/tst_qquickimageprovider.cpp
@@ -1,30 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#include <qtest.h>
#include <QtTest/QtTest>
#include <QtQml/qqmlengine.h>
@@ -34,14 +10,16 @@
#include <QWaitCondition>
#include <QThreadPool>
#include <private/qqmlengine_p.h>
+#include <QQmlComponent>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
Q_DECLARE_METATYPE(QQuickImageProvider*);
-class tst_qquickimageprovider : public QObject
+class tst_qquickimageprovider : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickimageprovider()
+ tst_qquickimageprovider() : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
@@ -72,7 +50,7 @@ private slots:
private:
QString newImageFileName() const;
- void fillRequestTestsData(const QString &id);
+ void fillRequestTestsData(const char *id);
void runTest(bool async, QQuickImageProvider *provider);
};
@@ -92,7 +70,7 @@ public:
*deleteWatch = true;
}
- QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize)
+ QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize) override
{
lastImageId = id;
@@ -129,7 +107,7 @@ public:
*deleteWatch = true;
}
- QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize)
+ QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize) override
{
lastImageId = id;
@@ -161,7 +139,7 @@ QString tst_qquickimageprovider::newImageFileName() const
return QString("image://test/image-%1.png").arg(count++);
}
-void tst_qquickimageprovider::fillRequestTestsData(const QString &id)
+void tst_qquickimageprovider::fillRequestTestsData(const char *id)
{
QTest::addColumn<QString>("source");
QTest::addColumn<QString>("imageId");
@@ -170,39 +148,39 @@ void tst_qquickimageprovider::fillRequestTestsData(const QString &id)
QTest::addColumn<QString>("error");
QString fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " simple test"))
+ QTest::addRow("%s simple test", id)
<< "image://test/" + fileName << fileName << "" << QSize(100,100) << "";
fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " simple test with capitalization"))//As it's a URL, should make no difference
+ QTest::addRow("%s simple test with capitalization", id)//As it's a URL, should make no difference
<< "image://Test/" + fileName << fileName << "" << QSize(100,100) << "";
fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " url with no id"))
+ QTest::addRow("%s url with no id", id)
<< "image://test/" + fileName << "" + fileName << "" << QSize(100,100) << "";
fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " url with path"))
+ QTest::addRow("%s url with path", id)
<< "image://test/test/path" + fileName << "test/path" + fileName << "" << QSize(100,100) << "";
fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " url with fragment"))
+ QTest::addRow("%s url with fragment", id)
<< "image://test/faq.html?#question13" + fileName << "faq.html?#question13" + fileName << "" << QSize(100,100) << "";
fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " url with query"))
+ QTest::addRow("%s url with query", id)
<< "image://test/cgi-bin/drawgraph.cgi?type=pie&color=green" + fileName << "cgi-bin/drawgraph.cgi?type=pie&color=green" + fileName
<< "" << QSize(100,100) << "";
fileName = newImageFileName();
- QTest::newRow(QTest::toString(id + " scaled image"))
+ QTest::addRow("%s scaled image", id)
<< "image://test/" + fileName << fileName << "sourceSize: \"80x30\"" << QSize(80,30) << "";
- QTest::newRow(QTest::toString(id + " missing"))
+ QTest::addRow("%s missing", id)
<< "image://test/no-such-file.png" << "no-such-file.png" << "" << QSize(100,100)
<< "<Unknown File>:2:1: QML Image: Failed to get image from provider: image://test/no-such-file.png";
- QTest::newRow(QTest::toString(id + " unknown provider"))
+ QTest::addRow("%s unknown provider", id)
<< "image://bogus/exists.png" << "" << "" << QSize()
<< "<Unknown File>:2:1: QML Image: Invalid image provider: image://bogus/exists.png";
}
@@ -401,7 +379,7 @@ class TestThreadProvider : public QQuickImageProvider
~TestThreadProvider() {}
- QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize)
+ QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize) override
{
mutex.lock();
if (!ok)
@@ -445,21 +423,19 @@ void tst_qquickimageprovider::threadTest()
QObject *obj = component.create();
//MUST not deadlock
QVERIFY(obj != nullptr);
- QList<QQuickImage *> images = obj->findChildren<QQuickImage *>();
- QCOMPARE(images.count(), 4);
+ const QList<QQuickImage *> images = obj->findChildren<QQuickImage *>();
+ QCOMPARE(images.size(), 4);
QTest::qWait(100);
- foreach (QQuickImage *img, images) {
+ for (QQuickImage *img : images)
QCOMPARE(img->status(), QQuickImage::Loading);
- }
{
QMutexLocker lock(&provider->mutex);
provider->ok = true;
provider->cond.wakeAll();
}
QTest::qWait(250);
- foreach (QQuickImage *img, images) {
+ for (QQuickImage *img : images)
QTRY_COMPARE(img->status(), QQuickImage::Ready);
- }
}
class TestImageResponseRunner : public QObject, public QRunnable {
@@ -470,7 +446,7 @@ public:
Q_SIGNAL void finished(QQuickTextureFactory *texture);
TestImageResponseRunner(QMutex *lock, QWaitCondition *condition, bool *ok, const QString &id, const QSize &requestedSize)
: m_lock(lock), m_condition(condition), m_ok(ok), m_id(id), m_requestedSize(requestedSize) {}
- void run()
+ void run() override
{
m_lock->lock();
if (!(*m_ok)) {
@@ -503,7 +479,7 @@ class TestImageResponse : public QQuickImageResponse
pool->start(runnable);
}
- QQuickTextureFactory *textureFactory() const
+ QQuickTextureFactory *textureFactory() const override
{
return m_texture;
}
@@ -531,7 +507,7 @@ class TestAsyncProvider : public QQuickAsyncImageProvider
~TestAsyncProvider() {}
- QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize)
+ QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override
{
TestImageResponse *response = new TestImageResponse(&lock, &condition, &ok, id, requestedSize, &pool);
return response;
@@ -564,21 +540,19 @@ void tst_qquickimageprovider::asyncTextureTest()
QObject *obj = component.create();
//MUST not deadlock
QVERIFY(obj != nullptr);
- QList<QQuickImage *> images = obj->findChildren<QQuickImage *>();
- QCOMPARE(images.count(), 4);
+ const QList<QQuickImage *> images = obj->findChildren<QQuickImage *>();
+ QCOMPARE(images.size(), 4);
QTRY_COMPARE(provider->pool.activeThreadCount(), 4);
- foreach (QQuickImage *img, images) {
+ for (QQuickImage *img : images)
QTRY_COMPARE(img->status(), QQuickImage::Loading);
- }
{
QMutexLocker lock(&provider->lock);
provider->ok = true;
provider->condition.wakeAll();
}
- foreach (QQuickImage *img, images) {
+ for (QQuickImage *img : images)
QTRY_COMPARE(img->status(), QQuickImage::Ready);
- }
}
class InstantAsyncImageResponse : public QQuickImageResponse
@@ -594,7 +568,7 @@ class InstantAsyncImageResponse : public QQuickImageResponse
emit finished();
}
- QQuickTextureFactory *textureFactory() const
+ QQuickTextureFactory *textureFactory() const override
{
return m_texture;
}
@@ -611,7 +585,7 @@ class InstancAsyncProvider : public QQuickAsyncImageProvider
~InstancAsyncProvider() {}
- QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize)
+ QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override
{
return new InstantAsyncImageResponse(id, requestedSize);
}
@@ -638,7 +612,7 @@ void tst_qquickimageprovider::instantAsyncTextureTest()
QVERIFY(!obj.isNull());
const QList<QQuickImage *> images = obj->findChildren<QQuickImage *>();
- QCOMPARE(images.count(), 4);
+ QCOMPARE(images.size(), 4);
for (QQuickImage *img: images) {
QTRY_COMPARE(img->status(), QQuickImage::Ready);
@@ -696,7 +670,7 @@ public:
~WaitingAsyncProvider() {}
- QQuickImageResponse *requestImageResponse(const QString & /* id */, const QSize & /* requestedSize */)
+ QQuickImageResponse *requestImageResponse(const QString & /* id */, const QSize & /* requestedSize */) override
{
auto response = new WaitingAsyncImageResponse(m_providerRemovedMutex, m_providerRemovedCond, m_providerRemoved, m_imageRequestedMutex, m_imageRequestedCondition, m_imageRequested);
pool.start(response);
diff --git a/tests/auto/quick/qquickitem/BLACKLIST b/tests/auto/quick/qquickitem/BLACKLIST
index d94a3ef102..6723c98812 100644
--- a/tests/auto/quick/qquickitem/BLACKLIST
+++ b/tests/auto/quick/qquickitem/BLACKLIST
@@ -1,2 +1,6 @@
[contains:hollow square: testing points inside]
xcb
+
+# QTBUG-100991
+[mousePropagationToParent]
+android
diff --git a/tests/auto/quick/qquickitem/CMakeLists.txt b/tests/auto/quick/qquickitem/CMakeLists.txt
index cbc91f8f50..82e7482e02 100644
--- a/tests/auto/quick/qquickitem/CMakeLists.txt
+++ b/tests/auto/quick/qquickitem/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickitem.pro.
#####################################################################
## tst_qquickitem Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickitem LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickitem
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickitem.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -34,18 +36,16 @@ qt_internal_add_test(tst_qquickitem
#####################################################################
qt_internal_extend_target(tst_qquickitem CONDITION TARGET Qt::Widgets
- DEFINES
- TEST_QTBUG_60123
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Widgets
)
qt_internal_extend_target(tst_qquickitem CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickitem CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickitem/data/childAtRectangle.qml b/tests/auto/quick/qquickitem/data/childAtRectangle.qml
index 2aaaedb06f..b21f52c3cd 100644
--- a/tests/auto/quick/qquickitem/data/childAtRectangle.qml
+++ b/tests/auto/quick/qquickitem/data/childAtRectangle.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickitem/data/containsContainmentMask.qml b/tests/auto/quick/qquickitem/data/containsContainmentMask.qml
new file mode 100644
index 0000000000..cbf7f9222f
--- /dev/null
+++ b/tests/auto/quick/qquickitem/data/containsContainmentMask.qml
@@ -0,0 +1,40 @@
+import QtQuick 2.11
+
+Item {
+ width: 200
+ height: 200
+
+ Item {
+ id: firstItem
+
+ objectName: "firstItem"
+ x: 6
+ y: 6
+ width: 1000
+ height: 1000
+
+ containmentMask: Item {
+ x: -5
+ y: -5
+ width: 10
+ height: 10
+ }
+ }
+
+ Item {
+ id: secondItem
+
+ objectName: "secondItem"
+ x: 6
+ y: 6
+ width: 0
+ height: 0
+
+ containmentMask: Item {
+ parent: secondItem
+ anchors.centerIn: parent
+ width: 10
+ height: 10
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickitem/data/mainWindowQtBug60123.qml b/tests/auto/quick/qquickitem/data/mainWindowQtBug60123.qml
index eeecd48cb2..8790c5beb3 100644
--- a/tests/auto/quick/qquickitem/data/mainWindowQtBug60123.qml
+++ b/tests/auto/quick/qquickitem/data/mainWindowQtBug60123.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickitem/data/objectCastInDestructor.qml b/tests/auto/quick/qquickitem/data/objectCastInDestructor.qml
new file mode 100644
index 0000000000..0cb3eea6e2
--- /dev/null
+++ b/tests/auto/quick/qquickitem/data/objectCastInDestructor.qml
@@ -0,0 +1,23 @@
+import QtQuick
+
+Rectangle {
+ width: 360
+ height: 360
+
+ Component {
+ id: crashComponent
+
+ Rectangle {
+ objectName: "testRectangle"
+ property bool customProperty: false
+ }
+ }
+
+ Loader {
+ id: loader
+ objectName: "loader"
+ anchors.fill: parent
+ sourceComponent: crashComponent
+ }
+}
+
diff --git a/tests/auto/quick/qquickitem/data/shortcutOverride.qml b/tests/auto/quick/qquickitem/data/shortcutOverride.qml
index 247b5fea04..cde49ebaf9 100644
--- a/tests/auto/quick/qquickitem/data/shortcutOverride.qml
+++ b/tests/auto/quick/qquickitem/data/shortcutOverride.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.8
import QtQuick.Window 2.1
diff --git a/tests/auto/quick/qquickitem/tst_qquickitem.cpp b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
index d7c9c0df2a..e4cc434909 100644
--- a/tests/auto/quick/qquickitem/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem/tst_qquickitem.cpp
@@ -1,37 +1,14 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
+#include <QtQml/QQmlComponent>
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickwindow.h>
#include <QtQuick/qquickview.h>
#include "private/qquickfocusscope_p.h"
+#include "private/qquickrectangle_p.h"
#include "private/qquickitem_p.h"
#include <QtGui/private/qevent_p.h>
#include <qpa/qwindowsysteminterface.h>
@@ -41,13 +18,13 @@
#include <QDebug>
#include <QTimer>
#include <QQmlEngine>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
#include <QSignalSpy>
#include <QTranslator>
#include <QtCore/qregularexpression.h>
-#ifdef TEST_QTBUG_60123
+#ifdef QT_WIDGETS_LIB
#include <QWidget>
#include <QMainWindow>
#endif
@@ -73,6 +50,7 @@ public:
QPoint lastWheelEventPos;
QPoint lastWheelEventGlobalPos;
int languageChangeEventCount = 0;
+ int localeChangeEventCount = 0;
protected:
void focusInEvent(QFocusEvent *event) override {
qCDebug(lcTests) << objectName() << event;
@@ -110,8 +88,16 @@ protected:
bool event(QEvent *e) override
{
Q_ASSERT(e->isAccepted()); // every event is constructed with the accept flag initialized to true
- if (e->type() == QEvent::LanguageChange)
- languageChangeEventCount++;
+ switch (e->type()) {
+ case QEvent::LanguageChange:
+ ++languageChangeEventCount;
+ break;
+ case QEvent::LocaleChange:
+ ++localeChangeEventCount;
+ break;
+ default:
+ break;
+ }
return QQuickItem::event(e); // default dispatch
}
};
@@ -142,7 +128,7 @@ public:
int repolishLoopCount = 0;
protected:
- virtual void updatePolish() {
+ void updatePolish() override {
wasPolished = true;
if (repolishLoopCount > 0) {
--repolishLoopCount;
@@ -164,14 +150,15 @@ public:
bool focused;
protected:
- virtual void focusInEvent(QFocusEvent *) { Q_ASSERT(!focused); focused = true; }
- virtual void focusOutEvent(QFocusEvent *) { Q_ASSERT(focused); focused = false; }
+ void focusInEvent(QFocusEvent *) override { Q_ASSERT(!focused); focused = true; }
+ void focusOutEvent(QFocusEvent *) override { Q_ASSERT(focused); focused = false; }
};
class tst_qquickitem : public QQmlDataTest
{
Q_OBJECT
public:
+ tst_qquickitem();
private slots:
void initTestCase() override;
@@ -185,6 +172,7 @@ private slots:
void focusSubItemInNonFocusScope();
void parentItemWithFocus();
void reparentFocusedItem();
+ void activeFocusChangedOrder();
void constructor();
void setParentItem();
@@ -220,6 +208,8 @@ private slots:
void contains_data();
void contains();
+ void containsContainmentMask_data();
+ void containsContainmentMask();
void childAt();
@@ -227,15 +217,21 @@ private slots:
void shortcutOverride();
-#ifdef TEST_QTBUG_60123
+#ifdef QT_WIDGETS_LIB
void qtBug60123();
#endif
void setParentCalledInOnWindowChanged();
void receivesLanguageChangeEvent();
+ void receivesLocaleChangeEvent();
void polishLoopDetection_data();
void polishLoopDetection();
+ void objectCastInDestructor();
+ void listsAreNotLists();
+
+ void transformChanged();
+
private:
enum PaintOrderOp {
@@ -251,6 +247,11 @@ private:
}
};
+tst_qquickitem::tst_qquickitem()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
void tst_qquickitem::initTestCase()
{
QQmlDataTest::initTestCase();
@@ -944,6 +945,93 @@ void tst_qquickitem::reparentFocusedItem()
FVERIFY();
}
+void tst_qquickitem::activeFocusChangedOrder()
+{
+ // This test checks that the activeFocusChanged signal first comes for an
+ // object that has lost focus, and only after that - for an object that
+ // has received focus.
+
+ {
+ // Two FocusScopes inside a Window
+ QQuickWindow window;
+ QVERIFY(ensureFocus(&window));
+ QTRY_COMPARE(QGuiApplication::focusWindow(), &window);
+
+ QQuickFocusScope scope1(window.contentItem());
+ QQuickItem scope1Child(&scope1);
+
+ QQuickFocusScope scope2(window.contentItem());
+ QQuickItem scope2Child(&scope2);
+
+ scope1Child.forceActiveFocus();
+ QTRY_VERIFY(scope1.hasActiveFocus());
+
+ int counter = 0;
+ connect(&scope1, &QQuickItem::activeFocusChanged, [&counter, &scope1](bool focus) {
+ QCOMPARE(scope1.childItems().front()->hasActiveFocus(), focus);
+ QCOMPARE(counter, 0);
+ counter++;
+ });
+ connect(&scope2, &QQuickItem::activeFocusChanged, [&counter, &scope2](bool focus) {
+ QCOMPARE(scope2.childItems().front()->hasActiveFocus(), focus);
+ QCOMPARE(counter, 1);
+ counter++;
+ });
+
+ // A guard is needed so that connections are destroyed before the items.
+ // Otherwise the slots will be called during destruction, and test will
+ // crash (because childItems will be empty).
+ auto guard = qScopeGuard([&scope1, &scope2]() {
+ scope1.disconnect();
+ scope2.disconnect();
+ });
+ Q_UNUSED(guard)
+
+ scope2Child.forceActiveFocus();
+ QTRY_VERIFY(scope2.hasActiveFocus());
+ QCOMPARE(counter, 2); // make sure that both signals are received
+ }
+
+ {
+ // Two Items inside a Window (no explicict FocusScopes)
+ QQuickWindow window;
+ QVERIFY(ensureFocus(&window));
+ QTRY_COMPARE(QGuiApplication::focusWindow(), &window);
+
+ QQuickItem item1(window.contentItem());
+
+ QQuickItem item2(window.contentItem());
+
+ item1.forceActiveFocus();
+ QTRY_VERIFY(item1.hasActiveFocus());
+
+ int counter = 0;
+ connect(&item1, &QQuickItem::activeFocusChanged, [&counter](bool focus) {
+ QVERIFY(!focus);
+ QCOMPARE(counter, 0);
+ counter++;
+ });
+ connect(&item2, &QQuickItem::activeFocusChanged, [&counter](bool focus) {
+ QVERIFY(focus);
+ QCOMPARE(counter, 1);
+ counter++;
+ });
+
+ // A guard is needed so that connections are destroyed before the items.
+ // Otherwise the slots will be called during destruction, and test will
+ // fail.
+ auto guard = qScopeGuard([&item1, &item2]() {
+ item1.disconnect();
+ item2.disconnect();
+ });
+ Q_UNUSED(guard)
+
+ item2.forceActiveFocus();
+ QTRY_VERIFY(item2.hasActiveFocus());
+ QCOMPARE(counter, 2); // make sure that both signals are received
+ }
+}
+
void tst_qquickitem::constructor()
{
QScopedPointer<QQuickItem> root(new QQuickItem);
@@ -953,13 +1041,13 @@ void tst_qquickitem::constructor()
QQuickItem *child1 = new QQuickItem(root.data());
QCOMPARE(child1->parent(), root.data());
QCOMPARE(child1->parentItem(), root.data());
- QCOMPARE(root->childItems().count(), 1);
+ QCOMPARE(root->childItems().size(), 1);
QCOMPARE(root->childItems().at(0), child1);
QQuickItem *child2 = new QQuickItem(root.data());
QCOMPARE(child2->parent(), root.data());
QCOMPARE(child2->parentItem(), root.data());
- QCOMPARE(root->childItems().count(), 2);
+ QCOMPARE(root->childItems().size(), 2);
QCOMPARE(root->childItems().at(0), child1);
QCOMPARE(root->childItems().at(1), child2);
}
@@ -977,7 +1065,7 @@ void tst_qquickitem::setParentItem()
child1->setParentItem(root);
QVERIFY(!child1->parent());
QCOMPARE(child1->parentItem(), root);
- QCOMPARE(root->childItems().count(), 1);
+ QCOMPARE(root->childItems().size(), 1);
QCOMPARE(root->childItems().at(0), child1);
QQuickItem *child2 = new QQuickItem;
@@ -986,14 +1074,14 @@ void tst_qquickitem::setParentItem()
child2->setParentItem(root);
QVERIFY(!child2->parent());
QCOMPARE(child2->parentItem(), root);
- QCOMPARE(root->childItems().count(), 2);
+ QCOMPARE(root->childItems().size(), 2);
QCOMPARE(root->childItems().at(0), child1);
QCOMPARE(root->childItems().at(1), child2);
child1->setParentItem(nullptr);
QVERIFY(!child1->parent());
QVERIFY(!child1->parentItem());
- QCOMPARE(root->childItems().count(), 1);
+ QCOMPARE(root->childItems().size(), 1);
QCOMPARE(root->childItems().at(0), child2);
delete root;
@@ -1009,7 +1097,9 @@ void tst_qquickitem::setParentItem()
void tst_qquickitem::visible()
{
+ QQuickWindow window;
QQuickItem *root = new QQuickItem;
+ root->setParentItem(window.contentItem());
QQuickItem *child1 = new QQuickItem;
child1->setParentItem(root);
@@ -1483,7 +1573,7 @@ void tst_qquickitem::polishLoopDetection()
}
QList<QQuickItem*> items = window.contentItem()->childItems();
- for (int i = 0; i < items.count(); ++i) {
+ for (int i = 0; i < items.size(); ++i) {
static_cast<TestPolishItem*>(items.at(i))->doPolish();
}
item = static_cast<TestPolishItem*>(items.first());
@@ -1559,18 +1649,37 @@ public:
int hoverEnterCount;
int hoverMoveCount;
int hoverLeaveCount;
+ QPoint hoverPosition;
+ QPoint hoverScenePosition;
+ QPoint hoverGlobalPosition;
+ QPoint hoverLastGlobalPosition;
protected:
- virtual void hoverEnterEvent(QHoverEvent *event) {
+ void hoverEnterEvent(QHoverEvent *event) override {
+ qCDebug(lcTests) << static_cast<QSinglePointEvent *>(event) << event->position() << event->scenePosition() << event->globalPosition();
event->accept();
++hoverEnterCount;
+ hoverPosition = event->position().toPoint();
+ hoverScenePosition = event->scenePosition().toPoint();
+ hoverGlobalPosition = event->globalPosition().toPoint();
+ hoverLastGlobalPosition = event->points().first().globalLastPosition().toPoint();
}
- virtual void hoverMoveEvent(QHoverEvent *event) {
+ void hoverMoveEvent(QHoverEvent *event) override {
+ qCDebug(lcTests) << static_cast<QSinglePointEvent *>(event) << event->position() << event->scenePosition() << event->globalPosition();
event->accept();
++hoverMoveCount;
+ hoverPosition = event->position().toPoint();
+ hoverScenePosition = event->scenePosition().toPoint();
+ hoverGlobalPosition = event->globalPosition().toPoint();
+ hoverLastGlobalPosition = event->points().first().globalLastPosition().toPoint();
}
- virtual void hoverLeaveEvent(QHoverEvent *event) {
+ void hoverLeaveEvent(QHoverEvent *event) override {
+ qCDebug(lcTests) << static_cast<QSinglePointEvent *>(event) << event->position() << event->scenePosition() << event->globalPosition();
event->accept();
++hoverLeaveCount;
+ hoverPosition = event->position().toPoint();
+ hoverScenePosition = event->scenePosition().toPoint();
+ hoverGlobalPosition = event->globalPosition().toPoint();
+ hoverLastGlobalPosition = event->points().first().globalLastPosition().toPoint();
}
};
@@ -1600,7 +1709,7 @@ void tst_qquickitem::hoverEvent()
QQuickWindow *window = new QQuickWindow();
window->resize(200, 200);
window->show();
- QTest::qWaitForWindowExposed(window);
+ QVERIFY(QTest::qWaitForWindowExposed(window));
#if QT_CONFIG(cursor) // Get the cursor out of the way.
QCursor::setPos(window->geometry().topRight() + QPoint(100, 100));
#endif
@@ -1613,6 +1722,13 @@ void tst_qquickitem::hoverEvent()
item->setVisible(visible);
item->setAcceptHoverEvents(acceptHoverEvents);
+ // Ensure that we don't get extra hover events delivered on the
+ // side, since it can affect the number of hover move events we receive below.
+ QQuickWindowPrivate::get(window)->deliveryAgentPrivate()->frameSynchronousHoverEnabled = false;
+ // And flush out any mouse events that might be queued up
+ // in QPA, since QTest::mouseMove() calls processEvents.
+ qGuiApp->processEvents();
+
const QPoint outside(150, 150);
const QPoint inside(50, 50);
const QPoint anotherInside(51, 51);
@@ -1620,16 +1736,33 @@ void tst_qquickitem::hoverEvent()
QTest::mouseMove(window, outside);
item->resetCounters();
+ auto checkPositions = [=](QPoint pt) {
+ QCOMPARE(item->hoverPosition, pt);
+ QCOMPARE(item->hoverScenePosition, item->mapToScene(pt).toPoint());
+ QCOMPARE(item->hoverGlobalPosition, item->mapToGlobal(pt).toPoint());
+ QVERIFY(!item->hoverLastGlobalPosition.isNull());
+ };
+
// Enter, then move twice inside, then leave.
+ const bool shouldReceiveHoverEvents = visible && acceptHoverEvents;
QTest::mouseMove(window, inside);
+ if (shouldReceiveHoverEvents)
+ checkPositions(inside);
QTest::mouseMove(window, anotherInside);
+ if (shouldReceiveHoverEvents)
+ checkPositions(anotherInside);
QTest::mouseMove(window, inside);
+ if (shouldReceiveHoverEvents)
+ checkPositions(inside);
QTest::mouseMove(window, outside);
+ if (shouldReceiveHoverEvents)
+ checkPositions(outside);
- const bool shouldReceiveHoverEvents = visible && acceptHoverEvents;
if (shouldReceiveHoverEvents) {
QCOMPARE(item->hoverEnterCount, 1);
- QCOMPARE(item->hoverMoveCount, 2);
+ QVERIFY(item->hoverMoveCount >= 2);
+ if (item->hoverMoveCount > 2)
+ qCDebug(lcTests) << "expected 2 hover move events, but got" << item->hoverMoveCount;
QCOMPARE(item->hoverLeaveCount, 1);
} else {
QCOMPARE(item->hoverEnterCount, 0);
@@ -1645,7 +1778,7 @@ void tst_qquickitem::hoverEventInParent()
QQuickWindow window;
window.resize(200, 200);
window.show();
- QTest::qWaitForWindowExposed(&window);
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
#if QT_CONFIG(cursor) // Get the cursor out of the way.
QCursor::setPos(window.geometry().topRight() + QPoint(100, 100));
#endif
@@ -1796,7 +1929,7 @@ void tst_qquickitem::paintOrder()
QList<QQuickItem*> list = QQuickItemPrivate::get(root)->paintOrderChildItems();
QStringList items;
- for (int i = 0; i < list.count(); ++i)
+ for (int i = 0; i < list.size(); ++i)
items << list.at(i)->objectName();
QCOMPARE(items, expected);
@@ -1863,13 +1996,6 @@ void tst_qquickitem::acceptedMouseButtons()
QCOMPARE(item.releaseCount, 3);
}
-static void gc(QQmlEngine &engine)
-{
- engine.collectGarbage();
- QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
-}
-
void tst_qquickitem::visualParentOwnership()
{
QQmlEngine engine;
@@ -2040,7 +2166,8 @@ void tst_qquickitem::contains_data()
QTest::newRow("(50, 0) = false") << 50 << 0 << false;
QTest::newRow("(0, 50) = false") << 0 << 50 << false;
QTest::newRow("(50, 50) = true") << 50 << 50 << true;
- QTest::newRow("(100, 100) = true") << 100 << 100 << true;
+ QTest::newRow("(99, 99) = true") << 99 << 99 << true;
+ QTest::newRow("(100, 100) = false") << 100 << 100 << false;
QTest::newRow("(150, 150) = false") << 150 << 150 << false;
}
@@ -2071,6 +2198,46 @@ void tst_qquickitem::contains()
QCOMPARE(result.toBool(), contains);
}
+void tst_qquickitem::containsContainmentMask_data()
+{
+ QTest::addColumn<QPointF>("point");
+ QTest::addColumn<bool>("contains");
+
+ QTest::newRow("(-6, -6) = false") << QPointF(-6, -6) << false;
+ QTest::newRow("(-5, -5) = true") << QPointF(-5, -5) << true;
+ QTest::newRow("(-4, -4) = true") << QPointF(-4, -4) << true;
+ QTest::newRow("(-3, -3) = true") << QPointF(-3, -3) << true;
+ QTest::newRow("(-2, -2) = true") << QPointF(-2, -2) << true;
+ QTest::newRow("(-1, -1) = true") << QPointF(-1, -1) << true;
+ QTest::newRow("(0, 0) = true") << QPointF(0, 0) << true;
+ QTest::newRow("(1, 1) = true") << QPointF(1, 1) << true;
+ QTest::newRow("(2, 2) = true") << QPointF(2, 2) << true;
+ QTest::newRow("(3, 3) = true") << QPointF(3, 3) << true;
+ QTest::newRow("(4, 4) = true") << QPointF(4, 4) << true;
+ QTest::newRow("(5, 5) = false") << QPointF(5, 5) << false;
+}
+
+void tst_qquickitem::containsContainmentMask()
+{
+ QFETCH(QPointF, point);
+ QFETCH(bool, contains);
+
+ QQuickView view;
+ view.setSource(testFileUrl("containsContainmentMask.qml"));
+
+ QQuickItem *root = qobject_cast<QQuickItem*>(view.rootObject());
+ QVERIFY(root);
+
+ QQuickItem *firstItem = root->findChild<QQuickItem*>("firstItem");
+ QVERIFY(firstItem);
+
+ QQuickItem *secondItem = root->findChild<QQuickItem*>("secondItem");
+ QVERIFY(secondItem);
+
+ QCOMPARE(firstItem->contains(point), contains);
+ QCOMPARE(secondItem->contains(point), contains);
+}
+
void tst_qquickitem::childAt()
{
QQuickView view;
@@ -2167,7 +2334,7 @@ void tst_qquickitem::shortcutOverride()
QCOMPARE(view.rootObject()->property("shortcutActivationCount").toInt(), 1);
}
-#ifdef TEST_QTBUG_60123
+#ifdef QT_WIDGETS_LIB
void tst_qquickitem::qtBug60123()
{
QMainWindow main;
@@ -2244,6 +2411,272 @@ void tst_qquickitem::receivesLanguageChangeEvent()
QCOMPARE(child2->languageChangeEventCount, 1);
}
+void tst_qquickitem::receivesLocaleChangeEvent()
+{
+ QQuickWindow window;
+ window.setFramePosition(QPoint(100, 100));
+ window.resize(200, 200);
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ QScopedPointer<TestItem> child1(new TestItem);
+ child1->setObjectName(QStringLiteral("child1"));
+ child1->setSize(QSizeF(200, 100));
+ child1->setParentItem(window.contentItem());
+
+ QScopedPointer<TestItem> child2(new TestItem);
+ child2->setObjectName(QStringLiteral("child2"));
+ child2->setSize(QSizeF(50, 50));
+ child2->setParentItem(child1.data());
+
+ QEvent e(QEvent::LocaleChange);
+ QCoreApplication::sendEvent(&window, &e);
+
+ QTRY_COMPARE(child1->localeChangeEventCount, 1);
+ QCOMPARE(child2->localeChangeEventCount, 1);
+}
+
+void tst_qquickitem::objectCastInDestructor()
+{
+ QQuickView view;
+ view.setSource(testFileUrl("objectCastInDestructor.qml"));
+ view.show();
+
+ QQuickItem *item = view.findChild<QQuickItem *>("testRectangle");
+ QVERIFY(item);
+ bool destroyed = false;
+ connect(item, &QObject::destroyed, [&]{
+ destroyed = true;
+ QCOMPARE(qobject_cast<QQuickItem *>(item), nullptr);
+ QCOMPARE(qobject_cast<QQuickRectangle *>(item), nullptr);
+ });
+
+ QQuickItem *loader = view.findChild<QQuickItem *>("loader");
+ QVERIFY(loader);
+ loader->setProperty("active", false);
+
+ QVERIFY(QTest::qWaitFor([&destroyed]{ return destroyed; }));
+}
+
+template<typename T>
+void verifyListProperty(const T &data)
+{
+ QVERIFY(data.object);
+ QVERIFY(data.append);
+ QVERIFY(data.count);
+ QVERIFY(data.at);
+ QVERIFY(data.clear);
+ QVERIFY(data.removeLast);
+
+ // We must not synthesize the replace and removeLast methods on those properties.
+ // They would be even more broken than the explicitly defined methods.
+ QVERIFY(!data.replace);
+}
+
+void tst_qquickitem::listsAreNotLists()
+{
+ QQuickItem item;
+ QQuickItem child;
+ QObject resource;
+
+ QQmlListProperty<QObject> data
+ = item.property("data").value<QQmlListProperty<QObject>>();
+ QQmlListProperty<QObject> resources
+ = item.property("resources").value<QQmlListProperty<QObject>>();
+ QQmlListProperty<QQuickItem> children
+ = item.property("children").value<QQmlListProperty<QQuickItem>>();
+
+ verifyListProperty(data);
+ verifyListProperty(resources);
+ verifyListProperty(children);
+
+
+ QCOMPARE(data.count(&data), 0);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 0);
+ children.append(&children, &child);
+ QCOMPARE(data.count(&data), 1);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 1);
+ children.removeLast(&children);
+ QCOMPARE(data.count(&data), 0);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 0);
+ data.append(&data, &child);
+ QCOMPARE(data.count(&data), 1);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 1);
+ data.removeLast(&data);
+ QCOMPARE(data.count(&data), 0);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 0);
+ children.append(&children, &child);
+ QCOMPARE(data.count(&data), 1);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 1);
+ data.removeLast(&data);
+ QCOMPARE(data.count(&data), 0);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 0);
+ data.append(&data, &child);
+ QCOMPARE(data.count(&data), 1);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 1);
+ children.removeLast(&children);
+ QCOMPARE(data.count(&data), 0);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 0);
+
+
+ resources.append(&resources, &resource);
+ QCOMPARE(data.count(&data), 1);
+ QCOMPARE(resources.count(&resources), 1);
+ QCOMPARE(children.count(&children), 0);
+ resources.removeLast(&resources);
+ QCOMPARE(data.count(&data), 0);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 0);
+ data.append(&data, &resource);
+ QCOMPARE(data.count(&data), 1);
+ QCOMPARE(resources.count(&resources), 1);
+ QCOMPARE(children.count(&children), 0);
+ data.removeLast(&data);
+ QCOMPARE(data.count(&data), 0);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 0);
+ resources.append(&resources, &resource);
+ QCOMPARE(data.count(&data), 1);
+ QCOMPARE(resources.count(&resources), 1);
+ QCOMPARE(children.count(&children), 0);
+ data.removeLast(&data);
+ QCOMPARE(data.count(&data), 0);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 0);
+ data.append(&data, &resource);
+ QCOMPARE(data.count(&data), 1);
+ QCOMPARE(resources.count(&resources), 1);
+ QCOMPARE(children.count(&children), 0);
+ resources.removeLast(&resources);
+ QCOMPARE(data.count(&data), 0);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 0);
+
+
+ children.append(&children, &child);
+ resources.append(&resources, &resource);
+ QCOMPARE(data.count(&data), 2);
+ QCOMPARE(resources.count(&resources), 1);
+ QCOMPARE(children.count(&children), 1);
+ children.removeLast(&children);
+ QCOMPARE(data.count(&data), 1);
+ QCOMPARE(resources.count(&resources), 1);
+ QCOMPARE(children.count(&children), 0);
+ resources.removeLast(&resources);
+ QCOMPARE(data.count(&data), 0);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 0);
+
+
+ children.append(&children, &child);
+ resources.append(&resources, &resource);
+ QCOMPARE(data.count(&data), 2);
+ QCOMPARE(resources.count(&resources), 1);
+ QCOMPARE(children.count(&children), 1);
+ resources.removeLast(&resources);
+ QCOMPARE(data.count(&data), 1);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 1);
+ children.removeLast(&children);
+ QCOMPARE(data.count(&data), 0);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 0);
+
+
+ data.append(&data, &child);
+ data.append(&data, &resource);
+ QCOMPARE(data.count(&data), 2);
+ QCOMPARE(resources.count(&resources), 1);
+ QCOMPARE(children.count(&children), 1);
+ data.removeLast(&data);
+ QCOMPARE(data.count(&data), 1);
+ QCOMPARE(resources.count(&resources), 1);
+ QCOMPARE(children.count(&children), 0);
+ data.removeLast(&data);
+ QCOMPARE(data.count(&data), 0);
+ QCOMPARE(resources.count(&resources), 0);
+ QCOMPARE(children.count(&children), 0);
+}
+
+class TransformItemPrivate;
+class TransformItem : public QQuickItem {
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(TransformItem)
+public:
+ TransformItem(QQuickItem *parent = nullptr);
+
+ bool transformChanged = false;
+};
+
+class TransformItemPrivate :public QQuickItemPrivate
+{
+protected:
+ Q_DECLARE_PUBLIC(TransformItem)
+
+ bool transformChanged(QQuickItem *transformedItem) override
+ {
+ Q_Q(TransformItem);
+ q->transformChanged = true;
+ return true;
+ }
+};
+
+TransformItem::TransformItem(QQuickItem *parent)
+ : QQuickItem(*(new TransformItemPrivate), parent)
+{
+}
+
+void tst_qquickitem::transformChanged()
+{
+ QQuickItem rootItem;
+ QQuickItem *parents[2][3] = {};
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 3; ++j) {
+ auto *item = new QQuickItem;
+ item->setObjectName(QString("Item-%1.%2").arg(i).arg(j));
+ item->setParentItem(j > 0 ? parents[i][j - 1] : &rootItem);
+ parents[i][j] = item;
+ }
+ }
+
+ // Setting the root item's position will result in transformChanged,
+ // which will clear the subtreeTransformChangedEnabled flag that is
+ // by default set to true, since there are no children that observe
+ // the viewport.
+ parents[0][0]->setPosition(QPoint(100, 100));
+ parents[1][0]->setPosition(QPoint(200, 200));
+
+ TransformItem transformItem;
+ transformItem.setParentItem(parents[0][2]);
+ transformItem.setFlag(QQuickItem::ItemObservesViewport);
+ QCOMPARE(transformItem.mapToScene(QPoint(0, 0)), parents[0][0]->position());
+
+ parents[0][0]->setPosition(QPoint(110, 110));
+ QVERIFY2(transformItem.transformChanged,
+ "Moving an ancestor should trigger transformChanged");
+
+ transformItem.transformChanged = false;
+ transformItem.setParentItem(parents[1][2]);
+ QVERIFY2(transformItem.transformChanged,
+ "Reparenting the item should result in a transformChanged");
+ QCOMPARE(transformItem.mapToScene(QPoint(0, 0)), parents[1][0]->position());
+
+ transformItem.transformChanged = false;
+ parents[1][0]->setPosition(QPoint(220, 220));
+ QVERIFY2(transformItem.transformChanged,
+ "Changing one of the new ancestors should result in transformChanged");
+ QCOMPARE(transformItem.mapToScene(QPoint(0, 0)), parents[1][0]->position());
+}
+
QTEST_MAIN(tst_qquickitem)
#include "tst_qquickitem.moc"
diff --git a/tests/auto/quick/qquickitem2/CMakeLists.txt b/tests/auto/quick/qquickitem2/CMakeLists.txt
index f60d1b2d55..7034acc184 100644
--- a/tests/auto/quick/qquickitem2/CMakeLists.txt
+++ b/tests/auto/quick/qquickitem2/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickitem2.pro.
#####################################################################
## tst_qquickitem2 Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickitem2 LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,16 +21,16 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickitem2
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickitem.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+ LIBRARIES
+ Qt::TestPrivate
TESTDATA ${test_data}
)
@@ -30,10 +39,10 @@ qt_internal_add_test(tst_qquickitem2
qt_internal_extend_target(tst_qquickitem2 CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickitem2 CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop3.qml b/tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop3.qml
new file mode 100644
index 0000000000..889e480f3b
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/activeFocusOnTab_infiniteLoop3.qml
@@ -0,0 +1,13 @@
+import QtQuick 2.6
+
+Item {
+ visible: true
+ Item {
+ visible: false
+ Item {
+ objectName: "hiddenChild"
+ activeFocusOnTab: true
+ focus: true
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/data/colorgroup.qml b/tests/auto/quick/qquickitem2/data/colorgroup.qml
new file mode 100644
index 0000000000..25782c9a52
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/colorgroup.qml
@@ -0,0 +1,34 @@
+import QtQuick
+
+Item {
+ width: 300
+ height: 300
+ visible: true
+
+ palette.active.base: "blue"
+ palette.inactive.base: "red"
+ palette.disabled.base: "gray"
+
+ Rectangle {
+ id: background
+ objectName: "background"
+
+ anchors.centerIn: parent
+ width: parent.width / 2
+ height: parent.height / 2
+
+ color: palette.base
+
+ Rectangle {
+ id: foreground
+ objectName: "foreground"
+
+ anchors.centerIn: parent
+ width: parent.width / 2
+ height: parent.height / 2
+
+ color: palette.base
+ border.color: "black"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/data/focusInScopeChanges.qml b/tests/auto/quick/qquickitem2/data/focusInScopeChanges.qml
new file mode 100644
index 0000000000..3bf765a29d
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/focusInScopeChanges.qml
@@ -0,0 +1,31 @@
+import QtQuick
+
+Item {
+ id: main
+ objectName: "main"
+ width: 800
+ height: 600
+
+ FocusScope {
+ objectName: "focusScope"
+
+ Column {
+ Rectangle {
+ id: rectangle
+ focus: true
+ objectName: "rect"
+ width: textInput.width
+ height: textInput.height
+ border.width: 1
+ onActiveFocusChanged: textInput.forceActiveFocus()
+ }
+
+ TextInput {
+ id: textInput
+ objectName: "textInput"
+ font.pixelSize: 40
+ text: "focus me"
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/data/focusReason.qml b/tests/auto/quick/qquickitem2/data/focusReason.qml
new file mode 100644
index 0000000000..7f9e303dba
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/focusReason.qml
@@ -0,0 +1,85 @@
+import QtQuick
+
+Item {
+ Component.onCompleted: item.focus = true
+ width: 640
+ height: 480
+
+ Column {
+ anchors.top: parent.top
+ anchors.topMargin: 10
+ spacing: 10
+ objectName: "column"
+ focusPolicy: Qt.ClickFocus
+
+ Item {
+ id: item
+ implicitWidth: 100
+ implicitHeight: 20
+ objectName: "item"
+ focusPolicy: Qt.TabFocus
+
+ Rectangle {
+ id: rect
+ anchors.fill: parent
+ color: "yellow"
+ opacity: 0.5
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ onClicked: function onClicked(mouseEvent) {
+ if (mouseEvent.button == Qt.RightButton)
+ rect.color = "pink"
+ }
+ }
+ }
+
+ Item {
+ id: customText
+ objectName: "customText"
+ implicitWidth: 100
+ implicitHeight: 50
+ TextInput {
+ anchors.fill: parent
+ objectName: "textInputChild"
+ text: parent.activeFocus ? "focus" : "no focus"
+ }
+ activeFocusOnTab: true
+ }
+
+ Item {
+ id: customItem
+ objectName: "customItem"
+ implicitWidth: 100
+ implicitHeight: 50
+ Rectangle {
+ anchors.fill: parent
+ color: parent.activeFocus ? "red" : "blue"
+ opacity: 0.3
+ }
+ focusPolicy: Qt.WheelFocus
+ }
+
+ Text {
+ id: hyperlink
+ objectName: "hyperlink"
+ color: "blue"
+ onLinkActivated: { text = "Clicked"; }
+ textFormat: Text.RichText
+ text: "<a href=\"http://qt-project.org\">Qt Project website</a>"
+ focusPolicy: Qt.StrongFocus
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ acceptedButtons: Qt.NoButton // Don't eat the mouse clicks
+ cursorShape: Qt.PointingHandCursor
+ // the acceptedButtons will take precedence
+ // and the click focus policy will be ignored
+ focusPolicy: Qt.ClickFocus
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/data/focusableItemReparentedToLoadedComponent.qml b/tests/auto/quick/qquickitem2/data/focusableItemReparentedToLoadedComponent.qml
new file mode 100644
index 0000000000..a690c4243b
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/focusableItemReparentedToLoadedComponent.qml
@@ -0,0 +1,51 @@
+import QtQuick 2.12
+
+Item {
+ width: 240; height: 240
+ Loader {
+ id: loader
+ sourceComponent: surfaceParent
+ anchors.fill: parent
+
+ onStatusChanged: {
+ if (status === Loader.Ready) {
+ holder.create()
+ holder.item.parent = item
+ } else if (status === Loader.Null){
+ holder.item.parent = null
+ }
+ }
+ }
+
+ property var holder: QtObject {
+ property bool created: false
+ function create()
+ {
+ if (!created)
+ surfaceComponent.createObject(item)
+ created = true
+ }
+
+ property Item item: Item {
+ anchors.fill: parent
+ Component {
+ id: surfaceComponent
+ Item {
+ anchors.fill: parent
+ TextInput {
+ width: parent.width
+ font.pixelSize: 40
+ text: "focus me"
+ }
+ }
+ }
+ }
+ }
+
+ Component {
+ id: surfaceParent
+ Rectangle {
+ anchors.fill: parent
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/data/grabToImage.qml b/tests/auto/quick/qquickitem2/data/grabToImage.qml
index 502472f120..1298a3c6a9 100644
--- a/tests/auto/quick/qquickitem2/data/grabToImage.qml
+++ b/tests/auto/quick/qquickitem2/data/grabToImage.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickitem2/data/hollowTestItem.qml b/tests/auto/quick/qquickitem2/data/hollowTestItem.qml
index d07d89c4f4..2f77f6ae51 100644
--- a/tests/auto/quick/qquickitem2/data/hollowTestItem.qml
+++ b/tests/auto/quick/qquickitem2/data/hollowTestItem.qml
@@ -31,7 +31,6 @@ Rectangle {
anchors.fill: parent
objectName: "hollowItem"
holeRadius: 50
- circle: circleShapeTest
}
}
}
diff --git a/tests/auto/quick/qquickitem2/data/keysforward.qml b/tests/auto/quick/qquickitem2/data/keysforward.qml
index 3497eb06b7..09a0f926ed 100644
--- a/tests/auto/quick/qquickitem2/data/keysforward.qml
+++ b/tests/auto/quick/qquickitem2/data/keysforward.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickitem2/data/mapCoordinates.qml b/tests/auto/quick/qquickitem2/data/mapCoordinates.qml
index 3e34633338..29cfdd73cb 100644
--- a/tests/auto/quick/qquickitem2/data/mapCoordinates.qml
+++ b/tests/auto/quick/qquickitem2/data/mapCoordinates.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml b/tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml
index c66d1e89b6..06f625624a 100644
--- a/tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml
+++ b/tests/auto/quick/qquickitem2/data/mapCoordinatesRect.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickitem2/data/mapCoordinatesWithWindows.qml b/tests/auto/quick/qquickitem2/data/mapCoordinatesWithWindows.qml
new file mode 100644
index 0000000000..8218c5230a
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/mapCoordinatesWithWindows.qml
@@ -0,0 +1,51 @@
+import QtQuick
+
+QtObject {
+ id: root
+
+ property Window windowA: Window {
+ visible: true
+ flags: Qt.FramelessWindowHint
+ color: "green"
+ x: 100; y: 100
+ width: 300; height: 300
+
+ Rectangle {
+ objectName: "childItem"
+ x: 50; y: 50
+ width: 100; height: 100
+ color: "red"
+ }
+
+ Window {
+ objectName: "childWindow"
+ parent: windowA
+ x: 100; y: 100
+ width: 100; height: 100
+ visible: true
+ color: "blue"
+
+ Rectangle {
+ objectName: "childItemInChildWindow"
+ x: 30; y: 30
+ width: 50; height: 50
+ color: "orange"
+ }
+ }
+ }
+
+ property Window windowB: Window {
+ visible: true
+ flags: Qt.FramelessWindowHint
+ color: "magenta"
+ x: 500; y: 200
+ width: 200; height: 200
+
+ Rectangle {
+ objectName: "childItem"
+ x: 50; y: 50
+ width: 100; height: 100
+ color: "cyan"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/data/paletteAllocate.qml b/tests/auto/quick/qquickitem2/data/paletteAllocate.qml
new file mode 100644
index 0000000000..6c959ddbcb
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/paletteAllocate.qml
@@ -0,0 +1,35 @@
+import QtQuick
+
+Item {
+ id: root
+ width: 300
+ height: 300
+ visible: true
+
+ palette.active.base: "blue"
+ palette.inactive.base: "red"
+ palette.disabled.base: "gray"
+
+ Rectangle {
+ id: background
+ objectName: "background"
+
+ anchors.centerIn: parent
+ width: parent.width / 2
+ height: parent.height / 2
+
+ color: root.palette.base
+
+ Rectangle {
+ id: foreground
+ objectName: "foreground"
+
+ anchors.centerIn: parent
+ width: parent.width / 2
+ height: parent.height / 2
+
+ color: root.palette.base
+ border.color: "black"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/data/standardkeys.qml b/tests/auto/quick/qquickitem2/data/standardkeys.qml
index c8a5923fe2..e19b0705c1 100644
--- a/tests/auto/quick/qquickitem2/data/standardkeys.qml
+++ b/tests/auto/quick/qquickitem2/data/standardkeys.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/qquickitem2/data/undefinedInvalid.qml b/tests/auto/quick/qquickitem2/data/undefinedInvalid.qml
new file mode 100644
index 0000000000..473038c5a1
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/undefinedInvalid.qml
@@ -0,0 +1,9 @@
+import QtQuick
+
+Item {
+ property var undef: undefined
+ width: undef
+ height: undef
+ implicitWidth: 200
+ implicitHeight: 300
+}
diff --git a/tests/auto/quick/qquickitem2/data/viewports.qml b/tests/auto/quick/qquickitem2/data/viewports.qml
new file mode 100644
index 0000000000..18258676b4
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/viewports.qml
@@ -0,0 +1,54 @@
+import QtQuick
+import Test 1.0
+
+Item {
+ width: 300
+ height: 300
+
+ Rectangle {
+ objectName: "outerViewport"
+
+ x: 40
+ y: 40
+ width: 220
+ height: 220
+ border.color: "green"
+ color: "transparent"
+
+ Rectangle {
+ objectName: "innerViewport"
+ width: parent.width
+ height: parent.height
+ x: 20
+ y: 20
+ border.color: "cyan"
+ color: "transparent"
+
+ Rectangle {
+ objectName: "innerRect"
+ color: "wheat"
+ opacity: 0.5
+ x: -55
+ y: -55
+ width: 290
+ height: 290
+ ViewportTestItem {
+ anchors.fill: parent
+ Rectangle {
+ id: viewportFillingRect
+ color: "transparent"
+ border.color: "red"
+ border.width: 3
+ x: parent.viewport.x
+ y: parent.viewport.y
+ width: parent.viewport.width
+ height: parent.viewport.height
+ }
+ }
+ }
+ }
+ }
+ Text {
+ text: "viewport " + viewportFillingRect.width + " x " + viewportFillingRect.height
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/data/visiblechanged.qml b/tests/auto/quick/qquickitem2/data/visiblechanged.qml
new file mode 100644
index 0000000000..6f87f955f6
--- /dev/null
+++ b/tests/auto/quick/qquickitem2/data/visiblechanged.qml
@@ -0,0 +1,39 @@
+import QtQuick
+
+Item {
+ id: root
+ width: 400
+ height: 300
+
+ Loader {
+ id: loader
+ objectName: "loader"
+ sourceComponent: Item {}
+ }
+ Rectangle {
+ id: parentItem
+ objectName: "parentItem"
+ width: 20
+ height: 20
+ color: "blue"
+ }
+ Rectangle {
+ id: childItem
+ objectName: "childItem"
+ parent: parentItem
+ width: 10
+ height: 10
+ color: "red"
+ }
+
+ Rectangle {
+ id: loaderChild
+ objectName: "loaderChild"
+ parent: loader.item
+ x: 100
+ y: 100
+ width: 10
+ height: 10
+ color: "green"
+ }
+}
diff --git a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
index 3170fb5918..57deb0a46a 100644
--- a/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
+++ b/tests/auto/quick/qquickitem2/tst_qquickitem.cpp
@@ -1,30 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#include <qtest.h>
#include <QtTest/QSignalSpy>
#include <QtQml/qqmlengine.h>
@@ -33,16 +9,24 @@
#include <QtQuick/qquickitemgrabresult.h>
#include <QtQuick/qquickview.h>
#include <QtGui/private/qinputmethod_p.h>
+#include <QtQuick/private/qquickloader_p.h>
+#include <QtQuick/private/qquickpalette_p.h>
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/private/qquicktextinput_p.h>
#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQuick/private/qquickanchors_p.h>
#include <QtGui/qstylehints.h>
#include <private/qquickitem_p.h>
-#include "../../shared/util.h"
-#include "../shared/visualtestutil.h"
-#include "../../shared/platforminputcontext.h"
+#include <QtQuickTest/QtQuickTest>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/platforminputcontext_p.h>
+#include <QtTest/private/qpropertytesthelper_p.h>
+
+using namespace QQuickVisualTestUtils;
-using namespace QQuickVisualTestUtil;
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
class tst_QQuickItem : public QQmlDataTest
{
@@ -66,6 +50,7 @@ private slots:
void activeFocusOnTab10();
void activeFocusOnTab_infiniteLoop_data();
void activeFocusOnTab_infiniteLoop();
+ void activeFocusOnTab_infiniteLoopControls();
void nextItemInFocusChain();
void nextItemInFocusChain2();
@@ -75,6 +60,7 @@ private slots:
void qtbug_50516();
void qtbug_50516_2_data();
void qtbug_50516_2();
+ void focusableItemReparentedToLoadedComponent();
void keys();
#if QT_CONFIG(shortcut)
@@ -103,6 +89,7 @@ private slots:
void mapCoordinates_data();
void mapCoordinatesRect();
void mapCoordinatesRect_data();
+ void mapCoordinatesWithWindows();
void propertyChanges();
void nonexistentPropertyConnection();
void transforms();
@@ -115,6 +102,8 @@ private slots:
void childrenProperty();
void resourcesProperty();
+ void bindableProperties_data();
+ void bindableProperties();
void changeListener();
void transformCrash();
@@ -129,6 +118,22 @@ private slots:
void grab();
+ void colorGroup();
+ void paletteAllocated();
+
+ void undefinedIsInvalidForWidthAndHeight();
+
+ void viewport_data();
+ void viewport();
+
+ void qobject_castOnDestruction();
+ void signalsOnDestruction_data();
+ void signalsOnDestruction();
+ void visibleChanged();
+
+ void lastFocusChangeReason();
+ void focusInScopeChanges();
+
private:
QQmlEngine engine;
bool qt_tab_all_widgets() {
@@ -202,7 +207,7 @@ public:
KeyTestItem(QQuickItem *parent=nullptr) : QQuickItem(parent), mKey(0) {}
protected:
- void keyPressEvent(QKeyEvent *e) {
+ void keyPressEvent(QKeyEvent *e) override {
mKey = e->key();
if (e->key() == Qt::Key_A)
@@ -211,7 +216,7 @@ protected:
e->ignore();
}
- void keyReleaseEvent(QKeyEvent *e) {
+ void keyReleaseEvent(QKeyEvent *e) override {
if (e->key() == Qt::Key_B)
e->accept();
else
@@ -225,7 +230,7 @@ public:
class FocusEventFilter : public QObject
{
protected:
- bool eventFilter(QObject *watched, QEvent *event) {
+ bool eventFilter(QObject *watched, QEvent *event) override {
if ((event->type() == QEvent::FocusIn) || (event->type() == QEvent::FocusOut)) {
QFocusEvent *focusEvent = static_cast<QFocusEvent *>(event);
lastFocusReason = focusEvent->reason();
@@ -242,8 +247,8 @@ QML_DECLARE_TYPE(KeyTestItem);
class HollowTestItem : public QQuickItem
{
Q_OBJECT
- Q_PROPERTY(bool circle READ isCircle WRITE setCircle)
- Q_PROPERTY(qreal holeRadius READ holeRadius WRITE setHoleRadius)
+ Q_PROPERTY(bool circle READ isCircle WRITE setCircle NOTIFY circleChanged)
+ Q_PROPERTY(qreal holeRadius READ holeRadius WRITE setHoleRadius NOTIFY holeRadiusChanged)
public:
HollowTestItem(QQuickItem *parent = nullptr)
@@ -261,12 +266,12 @@ public:
bool isHovered() const { return m_isHovered; }
bool isCircle() const { return m_isCircle; }
- void setCircle(bool circle) { m_isCircle = circle; }
+ void setCircle(bool circle) { m_isCircle = circle; emit circleChanged(); }
qreal holeRadius() const { return m_holeRadius; }
- void setHoleRadius(qreal radius) { m_holeRadius = radius; }
+ void setHoleRadius(qreal radius) { m_holeRadius = radius; emit holeRadiusChanged(); }
- bool contains(const QPointF &point) const {
+ bool contains(const QPointF &point) const override {
const qreal w = width();
const qreal h = height();
const qreal r = m_holeRadius;
@@ -287,11 +292,15 @@ public:
return dd > (r * r) && dd <= outerRadius * outerRadius;
}
+signals:
+ void circleChanged();
+ void holeRadiusChanged();
+
protected:
- void hoverEnterEvent(QHoverEvent *) { m_isHovered = true; }
- void hoverLeaveEvent(QHoverEvent *) { m_isHovered = false; }
- void mousePressEvent(QMouseEvent *) { m_isPressed = true; }
- void mouseReleaseEvent(QMouseEvent *) { m_isPressed = false; }
+ void hoverEnterEvent(QHoverEvent *) override { m_isHovered = true; }
+ void hoverLeaveEvent(QHoverEvent *) override { m_isHovered = false; }
+ void mousePressEvent(QMouseEvent *) override { m_isPressed = true; }
+ void mouseReleaseEvent(QMouseEvent *) override { m_isPressed = false; }
private:
bool m_isPressed;
@@ -302,6 +311,22 @@ private:
QML_DECLARE_TYPE(HollowTestItem);
+class ViewportTestItem : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QRectF viewport READ viewport NOTIFY viewportChanged)
+
+public:
+ ViewportTestItem(QQuickItem *parent = nullptr) : QQuickItem(parent) { }
+
+ QRectF viewport() const { return clipRect(); }
+
+signals:
+ void viewportChanged();
+};
+
+QML_DECLARE_TYPE(ViewportTestItem);
+
class TabFenceItem : public QQuickItem
{
Q_OBJECT
@@ -334,6 +359,7 @@ public:
QML_DECLARE_TYPE(TabFenceItem2);
tst_QQuickItem::tst_QQuickItem()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
@@ -342,6 +368,7 @@ void tst_QQuickItem::initTestCase()
QQmlDataTest::initTestCase();
qmlRegisterType<KeyTestItem>("Test",1,0,"KeyTestItem");
qmlRegisterType<HollowTestItem>("Test", 1, 0, "HollowTestItem");
+ qmlRegisterType<ViewportTestItem>("Test", 1, 0, "ViewportTestItem");
qmlRegisterType<TabFenceItem>("Test", 1, 0, "TabFence");
qmlRegisterType<TabFenceItem2>("Test", 1, 0, "TabFence2");
}
@@ -1143,6 +1170,17 @@ void tst_QQuickItem::activeFocusOnTab_infiniteLoop()
QCOMPARE(item, window->rootObject());
}
+
+void tst_QQuickItem::activeFocusOnTab_infiniteLoopControls()
+{
+ auto source = testFileUrl("activeFocusOnTab_infiniteLoop3.qml");
+ QScopedPointer<QQuickView>window(new QQuickView());
+ window->setSource(source);
+ window->show();
+ QVERIFY(window->errors().isEmpty());
+ QTest::keyClick(window.get(), Qt::Key_Tab); // should not hang
+}
+
void tst_QQuickItem::nextItemInFocusChain()
{
if (!qt_tab_all_widgets())
@@ -1284,14 +1322,13 @@ void verifyTabFocusChain(QQuickView *window, const char **focusChain, bool forwa
int idx = 0;
for (const char **objectName = focusChain; *objectName; ++objectName, ++idx) {
const QString &descrStr = QString("idx=%1 objectName=\"%2\"").arg(idx).arg(*objectName);
- const char *descr = descrStr.toLocal8Bit().data();
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, forward ? Qt::NoModifier : Qt::ShiftModifier);
QGuiApplication::sendEvent(window, &key);
- QVERIFY2(key.isAccepted(), descr);
+ QVERIFY2(key.isAccepted(), qPrintable(descrStr));
QQuickItem *item = findItem<QQuickItem>(window->rootObject(), *objectName);
- QVERIFY2(item, descr);
- QVERIFY2(item->hasActiveFocus(), descr);
+ QVERIFY2(item, qPrintable(descrStr));
+ QVERIFY2(item->hasActiveFocus(), qPrintable(descrStr));
}
}
@@ -1400,6 +1437,35 @@ void tst_QQuickItem::qtbug_50516_2()
delete window;
}
+void tst_QQuickItem::focusableItemReparentedToLoadedComponent() // QTBUG-89736
+{
+ QQuickView window;
+ window.setSource(testFileUrl("focusableItemReparentedToLoadedComponent.qml"));
+ window.show();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+ QCOMPARE(QGuiApplication::focusWindow(), &window);
+ QQuickLoader *loader = window.rootObject()->findChild<QQuickLoader *>();
+ QVERIFY(loader);
+ QTRY_VERIFY(loader->status() == QQuickLoader::Ready);
+ QQuickTextInput *textInput = window.rootObject()->findChild<QQuickTextInput *>();
+ QVERIFY(textInput);
+
+ // click to focus
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, {10, 10});
+ QTRY_VERIFY(textInput->hasActiveFocus());
+
+ // unload and reload
+ auto component = loader->sourceComponent();
+ loader->resetSourceComponent();
+ QTRY_VERIFY(loader->status() == QQuickLoader::Null);
+ loader->setSourceComponent(component);
+ QTRY_VERIFY(loader->status() == QQuickLoader::Ready);
+
+ // click to focus again
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, {10, 10});
+ QTRY_VERIFY(textInput->hasActiveFocus());
+}
+
void tst_QQuickItem::keys()
{
QQuickView *window = new QQuickView(nullptr);
@@ -1813,90 +1879,90 @@ void tst_QQuickItem::layoutMirroring()
QQuickItemPrivate *rootPrivate = QQuickItemPrivate::get(rootItem);
QVERIFY(rootPrivate);
- QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "mirrored2")->effectiveLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "notMirrored2")->effectiveLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, true);
-
- QCOMPARE(anchorsMirrored(rootItem, "mirrored1"), true);
- QCOMPARE(anchorsMirrored(rootItem, "mirrored2"), true);
- QCOMPARE(anchorsMirrored(rootItem, "notMirrored1"), false);
- QCOMPARE(anchorsMirrored(rootItem, "notMirrored2"), false);
- QCOMPARE(anchorsMirrored(rootItem, "inheritedMirror1"), true);
- QCOMPARE(anchorsMirrored(rootItem, "inheritedMirror2"), true);
-
- QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritedLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritedLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, true);
-
- QCOMPARE(childPrivate(rootItem, "mirrored1")->isMirrorImplicit, false);
- QCOMPARE(childPrivate(rootItem, "mirrored2")->isMirrorImplicit, false);
- QCOMPARE(childPrivate(rootItem, "notMirrored1")->isMirrorImplicit, false);
- QCOMPARE(childPrivate(rootItem, "notMirrored2")->isMirrorImplicit, true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->isMirrorImplicit, true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->isMirrorImplicit, true);
-
- QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritMirrorFromParent, true);
- QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritMirrorFromParent, false);
- QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromParent, true);
- QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritMirrorFromParent, false);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromParent, true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromParent, true);
-
- QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritMirrorFromItem, true);
- QCOMPARE(childPrivate(rootItem, "mirrored2")->inheritMirrorFromItem, false);
- QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromItem, false);
- QCOMPARE(childPrivate(rootItem, "notMirrored2")->inheritMirrorFromItem, false);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromItem, false);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromItem, false);
+ QVERIFY(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "mirrored2")->effectiveLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "notMirrored2")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror);
+
+ QVERIFY(anchorsMirrored(rootItem, "mirrored1"));
+ QVERIFY(anchorsMirrored(rootItem, "mirrored2"));
+ QVERIFY(!anchorsMirrored(rootItem, "notMirrored1"));
+ QVERIFY(!anchorsMirrored(rootItem, "notMirrored2"));
+ QVERIFY(anchorsMirrored(rootItem, "inheritedMirror1"));
+ QVERIFY(anchorsMirrored(rootItem, "inheritedMirror2"));
+
+ QVERIFY(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "mirrored2")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "notMirrored2")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror);
+
+ QVERIFY(!childPrivate(rootItem, "mirrored1")->isMirrorImplicit);
+ QVERIFY(!childPrivate(rootItem, "mirrored2")->isMirrorImplicit);
+ QVERIFY(!childPrivate(rootItem, "notMirrored1")->isMirrorImplicit);
+ QVERIFY(childPrivate(rootItem, "notMirrored2")->isMirrorImplicit);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror1")->isMirrorImplicit);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror2")->isMirrorImplicit);
+
+ QVERIFY(childPrivate(rootItem, "mirrored1")->inheritMirrorFromParent);
+ QVERIFY(!childPrivate(rootItem, "mirrored2")->inheritMirrorFromParent);
+ QVERIFY(childPrivate(rootItem, "notMirrored1")->inheritMirrorFromParent);
+ QVERIFY(!childPrivate(rootItem, "notMirrored2")->inheritMirrorFromParent);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromParent);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromParent);
+
+ QVERIFY(childPrivate(rootItem, "mirrored1")->inheritMirrorFromItem);
+ QVERIFY(!childPrivate(rootItem, "mirrored2")->inheritMirrorFromItem);
+ QVERIFY(!childPrivate(rootItem, "notMirrored1")->inheritMirrorFromItem);
+ QVERIFY(!childPrivate(rootItem, "notMirrored2")->inheritMirrorFromItem);
+ QVERIFY(!childPrivate(rootItem, "inheritedMirror1")->inheritMirrorFromItem);
+ QVERIFY(!childPrivate(rootItem, "inheritedMirror2")->inheritMirrorFromItem);
// load dynamic content using Loader that needs to inherit mirroring
rootItem->setProperty("state", "newContent");
- QCOMPARE(childPrivate(rootItem, "notMirrored3")->effectiveLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->effectiveLayoutMirror, true);
+ QVERIFY(!childPrivate(rootItem, "notMirrored3")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror3")->effectiveLayoutMirror);
- QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritedLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->inheritedLayoutMirror, true);
+ QVERIFY(childPrivate(rootItem, "notMirrored3")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror3")->inheritedLayoutMirror);
- QCOMPARE(childPrivate(rootItem, "notMirrored3")->isMirrorImplicit, false);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->isMirrorImplicit, true);
+ QVERIFY(!childPrivate(rootItem, "notMirrored3")->isMirrorImplicit);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror3")->isMirrorImplicit);
- QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromParent, true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror3")->inheritMirrorFromParent, true);
+ QVERIFY(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromParent);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror3")->inheritMirrorFromParent);
- QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem, false);
- QCOMPARE(childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem, false);
+ QVERIFY(!childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem);
+ QVERIFY(!childPrivate(rootItem, "notMirrored3")->inheritMirrorFromItem);
// disable inheritance
rootItem->setProperty("childrenInherit", false);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false);
+ QVERIFY(!childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, false);
- QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, false);
+ QVERIFY(!childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror);
// re-enable inheritance
rootItem->setProperty("childrenInherit", true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror, false);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror1")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror2")->effectiveLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "mirrored1")->effectiveLayoutMirror);
+ QVERIFY(!childPrivate(rootItem, "notMirrored1")->effectiveLayoutMirror);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror, true);
- QCOMPARE(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror, true);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror1")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "inheritedMirror2")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "mirrored1")->inheritedLayoutMirror);
+ QVERIFY(childPrivate(rootItem, "notMirrored1")->inheritedLayoutMirror);
//
// dynamic parenting
@@ -1909,24 +1975,24 @@ void tst_QQuickItem::layoutMirroring()
// inherit in constructor
QQuickItem *childItem1 = new QQuickItem(parentItem1);
- QCOMPARE(QQuickItemPrivate::get(childItem1)->effectiveLayoutMirror, true);
- QCOMPARE(QQuickItemPrivate::get(childItem1)->inheritMirrorFromParent, true);
+ QVERIFY(QQuickItemPrivate::get(childItem1)->effectiveLayoutMirror);
+ QVERIFY(QQuickItemPrivate::get(childItem1)->inheritMirrorFromParent);
// inherit through a parent change
QQuickItem *childItem2 = new QQuickItem();
- QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, false);
- QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, false);
+ QVERIFY(!QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror);
+ QVERIFY(!QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent);
childItem2->setParentItem(parentItem1);
- QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, true);
- QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, true);
+ QVERIFY(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror);
+ QVERIFY(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent);
// stop inherting through a parent change
QQuickItem *parentItem2 = new QQuickItem();
QQuickItemPrivate::get(parentItem2)->effectiveLayoutMirror = true; // LayoutMirroring.enabled: true
QQuickItemPrivate::get(parentItem2)->resolveLayoutMirror();
childItem2->setParentItem(parentItem2);
- QCOMPARE(QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror, false);
- QCOMPARE(QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent, false);
+ QVERIFY(!QQuickItemPrivate::get(childItem2)->effectiveLayoutMirror);
+ QVERIFY(!QQuickItemPrivate::get(childItem2)->inheritMirrorFromParent);
delete parentItem1;
delete parentItem2;
@@ -1942,11 +2008,11 @@ void tst_QQuickItem::layoutMirroringWindow()
window->show();
QQuickItemPrivate *content = QQuickItemPrivate::get(window->contentItem());
- QCOMPARE(content->effectiveLayoutMirror, true);
- QCOMPARE(content->inheritedLayoutMirror, true);
- QCOMPARE(content->isMirrorImplicit, false);
- QCOMPARE(content->inheritMirrorFromParent, true);
- QCOMPARE(content->inheritMirrorFromItem, true);
+ QVERIFY(content->effectiveLayoutMirror);
+ QVERIFY(content->inheritedLayoutMirror);
+ QVERIFY(!content->isMirrorImplicit);
+ QVERIFY(content->inheritMirrorFromParent);
+ QVERIFY(content->inheritMirrorFromItem);
}
void tst_QQuickItem::layoutMirroringIllegalParent()
@@ -2491,19 +2557,19 @@ void tst_QQuickItem::smooth()
item->setSmooth(true);
QVERIFY(item->smooth());
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
QList<QVariant> arguments = spy.first();
- QCOMPARE(arguments.count(), 1);
+ QCOMPARE(arguments.size(), 1);
QVERIFY(arguments.at(0).toBool());
item->setSmooth(true);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
item->setSmooth(false);
QVERIFY(!item->smooth());
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
item->setSmooth(false);
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
delete item;
}
@@ -2520,19 +2586,19 @@ void tst_QQuickItem::antialiasing()
item->setAntialiasing(true);
QVERIFY(item->antialiasing());
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
QList<QVariant> arguments = spy.first();
- QCOMPARE(arguments.count(), 1);
+ QCOMPARE(arguments.size(), 1);
QVERIFY(arguments.at(0).toBool());
item->setAntialiasing(true);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
item->setAntialiasing(false);
QVERIFY(!item->antialiasing());
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
item->setAntialiasing(false);
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
delete item;
}
@@ -2551,18 +2617,18 @@ void tst_QQuickItem::clip()
QVERIFY(item->clip());
QList<QVariant> arguments = spy.first();
- QCOMPARE(arguments.count(), 1);
+ QCOMPARE(arguments.size(), 1);
QVERIFY(arguments.at(0).toBool());
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
item->setClip(true);
- QCOMPARE(spy.count(),1);
+ QCOMPARE(spy.size(),1);
item->setClip(false);
QVERIFY(!item->clip());
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
item->setClip(false);
- QCOMPARE(spy.count(),2);
+ QCOMPARE(spy.size(),2);
delete item;
}
@@ -2637,15 +2703,17 @@ void tst_QQuickItem::mapCoordinates()
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
QCOMPARE(result.value<QPointF>(), -QPointF(150,150) + QPointF(x, y));
- QString warning1 = testFileUrl("mapCoordinates.qml").toString() + ":35:5: QML Item: mapToItem() given argument \"1122\" which is neither null nor an Item";
- QString warning2 = testFileUrl("mapCoordinates.qml").toString() + ":35:5: QML Item: mapFromItem() given argument \"1122\" which is neither null nor an Item";
+ QRegularExpression warning1 = QRegularExpression(".*Could not convert argument 0 at.*");
+ QRegularExpression warning2 = QRegularExpression(".*checkMapA.*Invalid@.*");
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+ QTest::ignoreMessage(QtWarningMsg, warning1);
+ QTest::ignoreMessage(QtWarningMsg, warning2);
QVERIFY(QMetaObject::invokeMethod(root, "checkMapAToInvalid",
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
QVERIFY(result.toBool());
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+ QTest::ignoreMessage(QtWarningMsg, warning1);
+ QTest::ignoreMessage(QtWarningMsg, warning2);
QVERIFY(QMetaObject::invokeMethod(root, "checkMapAFromInvalid",
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y)));
QVERIFY(result.toBool());
@@ -2669,7 +2737,7 @@ void tst_QQuickItem::mapCoordinatesRect()
QFETCH(int, width);
QFETCH(int, height);
- QQuickView *window = new QQuickView(nullptr);
+ std::unique_ptr<QQuickView> window = std::make_unique<QQuickView>();
window->setBaseSize(QSize(300, 300));
window->setSource(testFileUrl("mapCoordinatesRect.qml"));
window->show();
@@ -2708,20 +2776,20 @@ void tst_QQuickItem::mapCoordinatesRect()
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
QCOMPARE(result.value<QRectF>(), qobject_cast<QQuickItem*>(a)->mapRectFromScene(QRectF(x, y, width, height)));
- QString warning1 = testFileUrl("mapCoordinatesRect.qml").toString() + ":35:5: QML Item: mapToItem() given argument \"1122\" which is neither null nor an Item";
- QString warning2 = testFileUrl("mapCoordinatesRect.qml").toString() + ":35:5: QML Item: mapFromItem() given argument \"1122\" which is neither null nor an Item";
+ QRegularExpression warning1 = QRegularExpression(".*Could not convert argument 0 at.*");
+ QRegularExpression warning2 = QRegularExpression(".*checkMapA.*Invalid@.*");
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+ QTest::ignoreMessage(QtWarningMsg, warning1);
+ QTest::ignoreMessage(QtWarningMsg, warning2);
QVERIFY(QMetaObject::invokeMethod(root, "checkMapAToInvalid",
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
QVERIFY(result.toBool());
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+ QTest::ignoreMessage(QtWarningMsg, warning1);
+ QTest::ignoreMessage(QtWarningMsg, warning2);
QVERIFY(QMetaObject::invokeMethod(root, "checkMapAFromInvalid",
Q_RETURN_ARG(QVariant, result), Q_ARG(QVariant, x), Q_ARG(QVariant, y), Q_ARG(QVariant, width), Q_ARG(QVariant, height)));
QVERIFY(result.toBool());
-
- delete window;
}
void tst_QQuickItem::mapCoordinatesRect_data()
@@ -2735,6 +2803,76 @@ void tst_QQuickItem::mapCoordinatesRect_data()
QTest::newRow(QTest::toString(i)) << i << i << i << i;
}
+void tst_QQuickItem::mapCoordinatesWithWindows()
+{
+ QQmlComponent component(&engine, testFileUrl("mapCoordinatesWithWindows.qml"));
+ std::unique_ptr<QObject> root(component.create());
+ QVERIFY(root);
+
+ auto *windowA = root->property("windowA").value<QQuickWindow*>();
+ QVERIFY(windowA);
+
+ // The window container geometry, parenting, etc, is applied
+ // during polish, so to test these we need to wait for one.
+ QVERIFY(QQuickTest::qWaitForPolish(windowA));
+
+ auto *childItem = windowA->findChild<QQuickItem*>("childItem");
+ QVERIFY(childItem);
+
+ QPoint itemPos = childItem->position().toPoint();
+ QCOMPARE(childItem->mapToScene({0, 0}), itemPos);
+ QCOMPARE(childItem->mapToGlobal({0, 0}), windowA->position() + itemPos);
+
+ auto *childItemInChildWindow = windowA->findChild<QQuickItem*>("childItemInChildWindow");
+ QVERIFY(childItemInChildWindow);
+
+ QPoint windowItemPos = childItemInChildWindow->position().toPoint();
+ QCOMPARE(childItemInChildWindow->mapToScene({0, 0}), windowItemPos);
+ QCOMPARE(childItemInChildWindow->mapToGlobal({0, 0}), windowA->position()
+ + childItemInChildWindow->window()->position() + windowItemPos);
+
+ QCOMPARE(childItemInChildWindow->mapToItem(nullptr, {0, 0}), windowItemPos);
+
+ auto globalItemOffset = [](QQuickItem *a, QQuickItem *b) {
+ return a->mapToGlobal({0, 0}) - b->mapToGlobal({0, 0});
+ };
+
+ QCOMPARE(childItemInChildWindow->mapToItem(childItem, {0, 0}),
+ globalItemOffset(childItemInChildWindow, childItem));
+ QCOMPARE(childItemInChildWindow->mapFromItem(childItem, {0, 0}),
+ globalItemOffset(childItem, childItemInChildWindow));
+
+ QCOMPARE(childItem->mapToItem(childItemInChildWindow, {0, 0}),
+ globalItemOffset(childItem, childItemInChildWindow));
+ QCOMPARE(childItem->mapFromItem(childItemInChildWindow, {0, 0}),
+ globalItemOffset(childItemInChildWindow, childItem));
+
+ auto *windowB = root->property("windowB").value<QQuickWindow*>();
+ QVERIFY(windowA);
+ auto *childItemInOtherWindow = windowB->findChild<QQuickItem*>("childItem");
+ QVERIFY(childItemInOtherWindow);
+
+ QCOMPARE(childItemInOtherWindow->mapToItem(childItem, {0, 0}),
+ globalItemOffset(childItemInOtherWindow, childItem));
+ QCOMPARE(childItemInOtherWindow->mapFromItem(childItem, {0, 0}),
+ globalItemOffset(childItem, childItemInOtherWindow));
+
+ QCOMPARE(childItem->mapToItem(childItemInOtherWindow, {0, 0}),
+ globalItemOffset(childItem, childItemInOtherWindow));
+ QCOMPARE(childItem->mapFromItem(childItemInOtherWindow, {0, 0}),
+ globalItemOffset(childItemInOtherWindow, childItem));
+
+ QCOMPARE(childItemInOtherWindow->mapToItem(childItemInChildWindow, {0, 0}),
+ globalItemOffset(childItemInOtherWindow, childItemInChildWindow));
+ QCOMPARE(childItemInOtherWindow->mapFromItem(childItemInChildWindow, {0, 0}),
+ globalItemOffset(childItemInChildWindow, childItemInOtherWindow));
+
+ QCOMPARE(childItemInChildWindow->mapToItem(childItemInOtherWindow, {0, 0}),
+ globalItemOffset(childItemInChildWindow, childItemInOtherWindow));
+ QCOMPARE(childItemInChildWindow->mapFromItem(childItemInOtherWindow, {0, 0}),
+ globalItemOffset(childItemInOtherWindow, childItemInChildWindow));
+}
+
void tst_QQuickItem::transforms_data()
{
QTest::addColumn<QByteArray>("qml");
@@ -2812,6 +2950,30 @@ void tst_QQuickItem::resourcesProperty()
delete object;
}
+void tst_QQuickItem::bindableProperties_data()
+{
+ QTest::addColumn<qreal>("initialValue");
+ QTest::addColumn<qreal>("newValue");
+ QTest::addColumn<QString>("property");
+
+ // can't simply use 3. or 3.0 for the numbers as qreal might
+ // be float instead of double...
+ QTest::addRow("x") << qreal(3) << qreal(14) << "x";
+ QTest::addRow("y") << qreal(10) << qreal(20) << "y";
+ QTest::addRow("width") << qreal(100) << qreal(200) << "width";
+ QTest::addRow("height") << qreal(50) << qreal(40) << "height";
+}
+
+void tst_QQuickItem::bindableProperties()
+{
+ QQuickItem item;
+ QFETCH(qreal, initialValue);
+ QFETCH(qreal, newValue);
+ QFETCH(QString, property);
+
+ QTestPrivate::testReadWritePropertyBasics(item, initialValue, newValue, property.toUtf8().constData());
+}
+
void tst_QQuickItem::propertyChanges()
{
QQuickView *window = new QQuickView(nullptr);
@@ -2846,50 +3008,50 @@ void tst_QQuickItem::propertyChanges()
item->setBaselineOffset(10.0);
QCOMPARE(item->parentItem(), parentItem);
- QCOMPARE(parentSpy.count(),1);
+ QCOMPARE(parentSpy.size(),1);
QList<QVariant> parentArguments = parentSpy.first();
- QCOMPARE(parentArguments.count(), 1);
+ QCOMPARE(parentArguments.size(), 1);
QCOMPARE(item->parentItem(), qvariant_cast<QQuickItem *>(parentArguments.at(0)));
- QCOMPARE(childrenChangedSpy.count(),1);
+ QCOMPARE(childrenChangedSpy.size(),1);
item->setParentItem(parentItem);
- QCOMPARE(childrenChangedSpy.count(),1);
+ QCOMPARE(childrenChangedSpy.size(),1);
QCOMPARE(item->width(), 100.0);
- QCOMPARE(widthSpy.count(),1);
+ QCOMPARE(widthSpy.size(),1);
QCOMPARE(item->height(), 200.0);
- QCOMPARE(heightSpy.count(),1);
+ QCOMPARE(heightSpy.size(),1);
QCOMPARE(item->baselineOffset(), 10.0);
- QCOMPARE(baselineOffsetSpy.count(),1);
+ QCOMPARE(baselineOffsetSpy.size(),1);
QList<QVariant> baselineOffsetArguments = baselineOffsetSpy.first();
- QCOMPARE(baselineOffsetArguments.count(), 1);
+ QCOMPARE(baselineOffsetArguments.size(), 1);
QCOMPARE(item->baselineOffset(), baselineOffsetArguments.at(0).toReal());
QCOMPARE(parentItem->childrenRect(), QRectF(0.0,0.0,100.0,200.0));
- QCOMPARE(childrenRectSpy.count(),1);
+ QCOMPARE(childrenRectSpy.size(),1);
QList<QVariant> childrenRectArguments = childrenRectSpy.at(0);
- QCOMPARE(childrenRectArguments.count(), 1);
+ QCOMPARE(childrenRectArguments.size(), 1);
QCOMPARE(parentItem->childrenRect(), childrenRectArguments.at(0).toRectF());
QCOMPARE(item->hasActiveFocus(), true);
- QCOMPARE(focusSpy.count(),1);
+ QCOMPARE(focusSpy.size(),1);
QList<QVariant> focusArguments = focusSpy.first();
- QCOMPARE(focusArguments.count(), 1);
+ QCOMPARE(focusArguments.size(), 1);
QCOMPARE(focusArguments.at(0).toBool(), true);
QCOMPARE(parentItem->hasActiveFocus(), false);
QCOMPARE(parentItem->hasFocus(), false);
- QCOMPARE(wantsFocusSpy.count(),0);
+ QCOMPARE(wantsFocusSpy.size(),0);
item->setX(10.0);
QCOMPARE(item->x(), 10.0);
- QCOMPARE(xSpy.count(), 1);
+ QCOMPARE(xSpy.size(), 1);
item->setY(10.0);
QCOMPARE(item->y(), 10.0);
- QCOMPARE(ySpy.count(), 1);
+ QCOMPARE(ySpy.size(), 1);
delete window;
}
@@ -2936,7 +3098,7 @@ void tst_QQuickItem::childrenRectBug()
{
QQuickView *window = new QQuickView(nullptr);
- QString warning = testFileUrl("childrenRectBug.qml").toString() + ":7:5: QML Item: Binding loop detected for property \"height\"";
+ QString warning = testFileUrl("childrenRectBug.qml").toString() + ":11:9: QML Item: Binding loop detected for property \"height\"";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
@@ -2957,11 +3119,11 @@ void tst_QQuickItem::childrenRectBug2()
{
QQuickView *window = new QQuickView(nullptr);
- QString warning1 = testFileUrl("childrenRectBug2.qml").toString() + ":7:5: QML Item: Binding loop detected for property \"width\"";
+ QString warning1 = testFileUrl("childrenRectBug2.qml").toString() + ":10:9: QML Item: Binding loop detected for property \"width\"";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
- QString warning2 = testFileUrl("childrenRectBug2.qml").toString() + ":7:5: QML Item: Binding loop detected for property \"height\"";
+ QString warning2 = testFileUrl("childrenRectBug2.qml").toString() + ":11:9: QML Item: Binding loop detected for property \"height\"";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
@@ -3174,7 +3336,7 @@ void tst_QQuickItem::changeListener()
QCOMPARE(child2Listener.count(QQuickItemPrivate::Destroyed), 1);
QQuickItemPrivate::get(parent)->removeItemChangeListener(&parentListener, QQuickItemPrivate::Children);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// QTBUG-54732: all listeners should get invoked even if they remove themselves while iterating the listeners
QList<TestListener *> listeners;
@@ -3182,93 +3344,93 @@ void tst_QQuickItem::changeListener()
listeners << new TestListener(true);
// itemVisibilityChanged x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Visibility);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
parent->setVisible(false);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Visibility), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemRotationChanged x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Rotation);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
parent->setRotation(90);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Rotation), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemOpacityChanged x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Opacity);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
parent->setOpacity(0.5);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Opacity), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemChildAdded() x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
child1 = new QQuickItem(parent);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Children), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemParentChanged() x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(child1)->addItemChangeListener(listener, QQuickItemPrivate::Parent);
- QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.size(), listeners.size());
child1->setParentItem(nullptr);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Parent), 1);
- QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(child1)->changeListeners.size(), 0);
// itemImplicitWidthChanged() x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitWidth);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
parent->setImplicitWidth(parent->implicitWidth() + 1);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::ImplicitWidth), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemImplicitHeightChanged() x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::ImplicitHeight);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
parent->setImplicitHeight(parent->implicitHeight() + 1);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::ImplicitHeight), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemGeometryChanged() x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Geometry);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
parent->setWidth(parent->width() + 1);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Geometry), 1);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemChildRemoved() x 5
child1->setParentItem(parent);
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Children);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
delete child1;
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Children), 2);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), 0);
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), 0);
// itemDestroyed() x 5
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QQuickItemPrivate::get(parent)->addItemChangeListener(listener, QQuickItemPrivate::Destroyed);
- QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.count(), listeners.count());
+ QCOMPARE(QQuickItemPrivate::get(parent)->changeListeners.size(), listeners.size());
delete parent;
- foreach (TestListener *listener, listeners)
+ for (TestListener *listener : std::as_const(listeners))
QCOMPARE(listener->count(QQuickItemPrivate::Destroyed), 1);
}
@@ -3512,39 +3674,35 @@ void tst_QQuickItem::contains()
QFETCH(bool, insideTarget);
QFETCH(QList<QPoint>, points);
- QQuickView *window = new QQuickView(nullptr);
- window->rootContext()->setContextProperty("circleShapeTest", circleTest);
- window->setBaseSize(QSize(400, 400));
- window->setSource(testFileUrl("hollowTestItem.qml"));
- window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window));
- QCOMPARE(QGuiApplication::focusWindow(), window);
-
- QQuickItem *root = qobject_cast<QQuickItem *>(window->rootObject());
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("hollowTestItem.qml")));
+ QQuickItem *root = qobject_cast<QQuickItem *>(window.rootObject());
QVERIFY(root);
+ // Ensure that we don't get extra hover events delivered on the side.
+ QQuickWindowPrivate::get(&window)->deliveryAgentPrivate()->frameSynchronousHoverEnabled = false;
+ // Flush out any mouse events that might be queued up
+ qGuiApp->processEvents();
+
HollowTestItem *hollowItem = root->findChild<HollowTestItem *>("hollowItem");
QVERIFY(hollowItem);
+ hollowItem->setCircle(circleTest);
+
+ for (const QPoint &point : points) {
+ qCDebug(lcTests) << "hover and click @" << point;
- foreach (const QPoint &point, points) {
// check mouse hover
- QTest::mouseMove(window, point);
- QTest::qWait(10);
- QCOMPARE(hollowItem->isHovered(), insideTarget);
+ QTest::mouseMove(&window, point);
+ QTRY_COMPARE(hollowItem->isHovered(), insideTarget);
// check mouse press
- QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, point);
- QTest::qWait(10);
- QCOMPARE(hollowItem->isPressed(), insideTarget);
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, point);
+ QTRY_COMPARE(hollowItem->isPressed(), insideTarget);
// check mouse release
- QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, point);
- QTest::qWait(10);
- QCOMPARE(hollowItem->isPressed(), false);
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, point);
+ QTRY_COMPARE(hollowItem->isPressed(), false);
}
-
- delete window;
}
void tst_QQuickItem::childAt()
@@ -3586,9 +3744,8 @@ void tst_QQuickItem::childAt()
void tst_QQuickItem::grab()
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabToImage not functional on offscreen/minimal platforms");
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabToImage not functional on minimal platforms");
QQuickView view;
view.setSource(testFileUrl("grabToImage.qml"));
@@ -3661,6 +3818,619 @@ void tst_QQuickItem::isAncestorOf()
QVERIFY(!sub2.isAncestorOf(&sub2));
}
+/*
+ Verify that a nested item's palette responds to changes of the enabled state
+ and of the window's activation state by switching the current color group.
+*/
+void tst_QQuickItem::colorGroup()
+{
+ QQuickView view;
+
+ view.setSource(testFileUrl("colorgroup.qml"));
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickItem *root = qobject_cast<QQuickItem *>(view.rootObject());
+ QQuickItem *background = root->findChild<QQuickItem *>("background");
+ QVERIFY(background);
+ QQuickItem *foreground = root->findChild<QQuickItem *>("foreground");
+ QVERIFY(foreground);
+
+ QQuickPalette *palette = foreground->property("palette").value<QQuickPalette*>();
+ QVERIFY(palette);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QCOMPARE(palette->currentColorGroup(), QPalette::Active);
+ QCOMPARE(foreground->property("color").value<QColor>(), palette->active()->base());
+
+ background->setEnabled(false);
+ QCOMPARE(palette->currentColorGroup(), QPalette::Disabled);
+ QCOMPARE(foreground->property("color").value<QColor>(), palette->disabled()->base());
+
+ QWindow activationThief;
+ activationThief.show();
+ activationThief.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&activationThief));
+ QCOMPARE(palette->currentColorGroup(), QPalette::Disabled);
+ QCOMPARE(foreground->property("color").value<QColor>(), palette->disabled()->base());
+
+ background->setEnabled(true);
+ QCOMPARE(palette->currentColorGroup(), QPalette::Inactive);
+ QCOMPARE(foreground->property("color").value<QColor>(), palette->inactive()->base());
+
+ activationThief.hide();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+ QCOMPARE(palette->currentColorGroup(), QPalette::Active);
+ QCOMPARE(foreground->property("color").value<QColor>(), palette->active()->base());
+
+ activationThief.show();
+ activationThief.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&activationThief));
+ QCOMPARE(palette->currentColorGroup(), QPalette::Inactive);
+ QCOMPARE(foreground->property("color").value<QColor>(), palette->inactive()->base());
+}
+
+/*!
+ Verify that items don't allocate their own QQuickPalette instance
+ unnecessarily.
+*/
+void tst_QQuickItem::paletteAllocated()
+{
+ QQuickView view;
+
+ view.setSource(testFileUrl("paletteAllocate.qml"));
+
+ QQuickItem *root = qobject_cast<QQuickItem *>(view.rootObject());
+ QQuickItem *background = root->findChild<QQuickItem *>("background");
+ QVERIFY(background);
+ QQuickItem *foreground = root->findChild<QQuickItem *>("foreground");
+ QVERIFY(foreground);
+
+ bool backgroundHasPalette = false;
+ bool foregroundHasPalette = false;
+ QObject::connect(background, &QQuickItem::paletteCreated, this, [&]{ backgroundHasPalette = true; });
+ QObject::connect(foreground, &QQuickItem::paletteCreated, this, [&]{ foregroundHasPalette = true; });
+
+ view.show();
+ view.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QVERIFY(!backgroundHasPalette);
+ QVERIFY(!foregroundHasPalette);
+
+ view.close();
+
+ QVERIFY(!backgroundHasPalette);
+ QVERIFY(!foregroundHasPalette);
+
+ auto quickpalette = foreground->property("palette").value<QQuickPalette*>();
+ QVERIFY(!backgroundHasPalette);
+ QVERIFY(quickpalette);
+ QVERIFY(foregroundHasPalette);
+}
+
+void tst_QQuickItem::undefinedIsInvalidForWidthAndHeight()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("undefinedInvalid.qml"));
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+ auto item = qobject_cast<QQuickItem *>(root.get());
+ auto priv = QQuickItemPrivate::get(item);
+ QVERIFY(item);
+ QCOMPARE(item->height(), 300);
+ QCOMPARE(item->width(), 200);
+ QVERIFY(!priv->widthValid());
+ QVERIFY(!priv->heightValid());
+}
+
+void tst_QQuickItem::viewport_data()
+{
+ QTest::addColumn<bool>("contentObservesViewport");
+
+ QTest::addColumn<bool>("innerClip");
+ QTest::addColumn<bool>("innerViewport");
+ QTest::addColumn<bool>("innerObservesViewport");
+
+ QTest::addColumn<bool>("outerClip");
+ QTest::addColumn<bool>("outerViewport");
+ QTest::addColumn<bool>("outerObservesViewport");
+
+ QTest::addColumn<QPoint>("innerViewportOffset");
+ QTest::addColumn<QPoint>("outerViewportOffset");
+
+ QTest::addColumn<QRect>("expectedViewportTestRect");
+ QTest::addColumn<QRect>("expectedContentClipRect");
+
+ QTest::newRow("default") << false
+ << false << false << false
+ << false << false << false
+ << QPoint() << QPoint() << QRect(0, 0, 290, 290) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp, clipping and observing") << true
+ << true << true << true
+ << true << true << true
+ << QPoint() << QPoint() << QRect(55, 55, 200, 200) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp, clipping and observing; content not observing") << false
+ << true << true << true
+ << true << true << true
+ << QPoint() << QPoint() << QRect(0, 0, 290, 290) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing") << true
+ << false << true << true
+ << false << true << true
+ << QPoint() << QPoint() << QRect(55, 55, 200, 200) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing, inner pos offset") << true
+ << false << true << true
+ << false << true << true
+ << QPoint(120, 120) << QPoint() << QRect(55, 55, 80, 80) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing, inner neg offset") << true
+ << false << true << true
+ << false << true << true
+ << QPoint(-70, -50) << QPoint() << QRect(105, 85, 170, 190) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing, outer pos offset") << true
+ << false << true << true
+ << false << true << true
+ << QPoint() << QPoint(220, 220) << QRect(55, 55, 20, 20) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing, outer neg offset") << true
+ << false << true << true
+ << false << true << true
+ << QPoint() << QPoint(-70, -50) << QRect(65, 55, 190, 200) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing, pos and neg offset") << true
+ << false << true << true
+ << false << true << true
+ << QPoint(150, 150) << QPoint(-170, -150) << QRect(55, 55, 50, 50) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp and observing, neg and pos offset") << true
+ << false << true << true
+ << false << true << true
+ << QPoint(-180, -210) << QPoint(100, 115) << QRect(215, 245, 60, 30) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp not observing") << true
+ << false << true << false
+ << false << true << false
+ << QPoint() << QPoint() << QRect(55, 55, 220, 220) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp not observing, inner pos offset") << true
+ << false << true << false
+ << false << true << false
+ << QPoint(120, 120) << QPoint() << QRect(55, 55, 220, 220) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp not observing, inner neg offset") << true
+ << false << true << false
+ << false << true << false
+ << QPoint(-70, -50) << QPoint() << QRect(55, 55, 220, 220) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp not observing, outer pos offset") << true
+ << false << true << false
+ << false << true << false
+ << QPoint() << QPoint(220, 220) << QRect(55, 55, 220, 220) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner and outer: vp not observing, outer neg offset") << true
+ << false << true << false
+ << false << true << false
+ << QPoint() << QPoint(-70, -50) << QRect(55, 55, 220, 220) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner clipping and observing") << true
+ << true << true << true
+ << false << false << false
+ << QPoint() << QPoint() << QRect(55, 55, 220, 220) << QRect(0, 0, 290, 290);
+ QTest::newRow("inner clipping and observing only outer") << true
+ << true << true << true
+ << false << true << false
+ << QPoint() << QPoint() << QRect(55, 55, 200, 200) << QRect(0, 0, 290, 290);
+}
+
+void tst_QQuickItem::viewport()
+{
+ QFETCH(bool, contentObservesViewport);
+ QFETCH(bool, innerClip);
+ QFETCH(bool, innerViewport);
+ QFETCH(bool, innerObservesViewport);
+ QFETCH(bool, outerClip);
+ QFETCH(bool, outerViewport);
+ QFETCH(bool, outerObservesViewport);
+ QFETCH(QPoint, innerViewportOffset);
+ QFETCH(QPoint, outerViewportOffset);
+ QFETCH(QRect, expectedViewportTestRect);
+ QFETCH(QRect, expectedContentClipRect);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("viewports.qml")));
+
+ QQuickItem *root = qobject_cast<QQuickItem *>(window.rootObject());
+ QQuickItem *outer = root->findChild<QQuickItem *>("outerViewport");
+ QVERIFY(outer);
+ QQuickItem *inner = root->findChild<QQuickItem *>("innerViewport");
+ QVERIFY(inner);
+ QQuickItem *contentItem = root->findChild<QQuickItem *>("innerRect");
+ QVERIFY(contentItem);
+ ViewportTestItem *viewportTestItem = root->findChild<ViewportTestItem *>();
+ QVERIFY(viewportTestItem);
+
+ inner->setPosition(inner->position() + innerViewportOffset);
+ outer->setPosition(outer->position() + outerViewportOffset);
+ outer->setClip(outerClip);
+ QCOMPARE(outer->flags().testFlag(QQuickItem::ItemIsViewport), outerClip);
+ outer->setFlag(QQuickItem::ItemIsViewport, outerViewport);
+ outer->setFlag(QQuickItem::ItemObservesViewport, outerObservesViewport);
+ inner->setClip(innerClip);
+ QCOMPARE(inner->flags().testFlag(QQuickItem::ItemIsViewport), innerClip);
+ inner->setFlag(QQuickItem::ItemIsViewport, innerViewport);
+ inner->setFlag(QQuickItem::ItemObservesViewport, innerObservesViewport);
+ viewportTestItem->setFlag(QQuickItem::ItemObservesViewport, contentObservesViewport);
+ emit viewportTestItem->viewportChanged();
+
+ if (lcTests().isDebugEnabled())
+ QTest::qWait(1000);
+ if (contentObservesViewport) {
+ if (innerViewport)
+ QCOMPARE(viewportTestItem->viewportItem(), inner);
+ else if (outerViewport)
+ QCOMPARE(viewportTestItem->viewportItem(), outer);
+ else
+ QCOMPARE(viewportTestItem->viewportItem(), root->parentItem()); // QQuickRootItem
+ } else {
+ QCOMPARE(viewportTestItem->viewportItem(), root->parentItem()); // QQuickRootItem
+ }
+
+ QCOMPARE(contentItem->clipRect().toRect(), expectedContentClipRect);
+ QCOMPARE(viewportTestItem->clipRect().toRect(), expectedViewportTestRect);
+}
+
+// Test that in a slot connected to destroyed() the emitter is
+// is no longer a QQuickItem.
+void tst_QQuickItem::qobject_castOnDestruction()
+{
+ QQuickItem item;
+ QObject::connect(&item, &QObject::destroyed, [](QObject *object)
+ {
+ QVERIFY(!qobject_cast<QQuickItem *>(object));
+ QVERIFY(!dynamic_cast<QQuickItem *>(object));
+ QVERIFY(!object->isQuickItemType());
+ });
+}
+
+/*
+ Items that are getting destroyed should not emit property change notifications.
+*/
+void tst_QQuickItem::signalsOnDestruction_data()
+{
+ QTest::addColumn<bool>("childVisible");
+ QTest::addColumn<bool>("grandChildVisible");
+
+ QTest::addRow("Both visible") << true << true;
+ QTest::addRow("Child visible") << true << false;
+ QTest::addRow("Grand child visible") << false << true;
+ QTest::addRow("Both hidden") << false << false;
+}
+
+void tst_QQuickItem::signalsOnDestruction()
+{
+ QFETCH(bool, childVisible);
+ QFETCH(bool, grandChildVisible);
+
+ QQuickWindow window;
+ window.show();
+
+ int expectedChildVisibleCount = 0;
+ int expectedGrandChildVisibleCount = 0;
+
+ // Visual children, but not QObject children.
+ // Note: QQuickItem's visible property defaults to true after creation, as visual
+ // items are always expected to be added to a visual hierarchy. So for the sake
+ // of this test we first add, and then remove the item from a parent. This explicitly
+ // sets the effective visibility to false.
+ std::unique_ptr<QQuickItem> parent(new QQuickItem(window.contentItem()));
+ QVERIFY(parent->isVisible());
+ std::unique_ptr<QQuickItem> child(new QQuickItem);
+ child->setVisible(childVisible);
+ child->setParentItem(parent.get());
+ child->setParentItem(nullptr);
+ QVERIFY(!child->isVisible());
+ std::unique_ptr<QQuickItem> grandChild(new QQuickItem);
+ grandChild->setVisible(grandChildVisible);
+ grandChild->setParentItem(child.get());
+ grandChild->setParentItem(nullptr);
+ QVERIFY(!grandChild->isVisible());
+
+ QSignalSpy childrenSpy(parent.get(), &QQuickItem::childrenChanged);
+ QSignalSpy visibleChildrenSpy(parent.get(), &QQuickItem::visibleChildrenChanged);
+ QSignalSpy childParentSpy(child.get(), &QQuickItem::parentChanged);
+ QSignalSpy childVisibleSpy(child.get(), &QQuickItem::visibleChanged);
+ QSignalSpy childChildrenSpy(child.get(), &QQuickItem::childrenChanged);
+ QSignalSpy childVisibleChildrenSpy(child.get(), &QQuickItem::visibleChildrenChanged);
+ QSignalSpy grandChildParentSpy(grandChild.get(), &QQuickItem::parentChanged);
+ QSignalSpy grandChildVisibleSpy(grandChild.get(), &QQuickItem::visibleChanged);
+
+ child->setParentItem(parent.get());
+ QCOMPARE(childrenSpy.count(), 1);
+ if (childVisible)
+ ++expectedChildVisibleCount;
+ QCOMPARE(visibleChildrenSpy.count(), expectedChildVisibleCount);
+ QCOMPARE(childParentSpy.count(), 1);
+ QCOMPARE(childVisibleSpy.count(), expectedChildVisibleCount);
+ QCOMPARE(childChildrenSpy.count(), 0);
+ QCOMPARE(childVisibleChildrenSpy.count(), 0);
+
+ grandChild->setParentItem(child.get());
+ QCOMPARE(childrenSpy.count(), 1);
+ QCOMPARE(visibleChildrenSpy.count(), expectedChildVisibleCount);
+ QCOMPARE(childParentSpy.count(), 1);
+ QCOMPARE(childVisibleSpy.count(), expectedChildVisibleCount);
+ QCOMPARE(childChildrenSpy.count(), 1);
+ if (grandChildVisible && childVisible)
+ ++expectedGrandChildVisibleCount;
+ QCOMPARE(childVisibleChildrenSpy.count(), expectedGrandChildVisibleCount);
+ QCOMPARE(grandChildParentSpy.count(), 1);
+ QCOMPARE(grandChildVisibleSpy.count(), expectedGrandChildVisibleCount);
+
+ parent.reset();
+
+ QVERIFY(!child->parentItem());
+ QVERIFY(grandChild->parentItem());
+ QCOMPARE(childrenSpy.count(), 1);
+ QCOMPARE(visibleChildrenSpy.count(), expectedChildVisibleCount);
+ QCOMPARE(childParentSpy.count(), 2);
+ QCOMPARE(childChildrenSpy.count(), 1);
+ if (childVisible)
+ ++expectedChildVisibleCount;
+ QCOMPARE(childVisibleSpy.count(), expectedChildVisibleCount);
+ if (childVisible && grandChildVisible)
+ ++expectedGrandChildVisibleCount;
+ QCOMPARE(childVisibleChildrenSpy.count(), expectedGrandChildVisibleCount);
+ QCOMPARE(grandChildParentSpy.count(), 1);
+ QCOMPARE(grandChildVisibleSpy.count(), expectedGrandChildVisibleCount);
+}
+
+void tst_QQuickItem::visibleChanged()
+{
+ QQuickView window;
+ window.setSource(testFileUrl("visiblechanged.qml"));
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ QQuickItem *root = qobject_cast<QQuickItem*>(window.rootObject());
+ QVERIFY(root);
+
+ QPointer<QQuickItem> parentItem = root->findChild<QQuickItem *>("parentItem");
+ QPointer<QQuickItem> childItem = root->findChild<QQuickItem *>("childItem");
+ QPointer<QQuickItem> loader = root->findChild<QQuickItem *>("loader");
+ QPointer<QQuickItem> loaderChild = root->findChild<QQuickItem *>("loaderChild");
+ QVERIFY(parentItem);
+ QVERIFY(childItem);
+ QVERIFY(loader);
+ QVERIFY(loaderChild);
+
+ QSignalSpy parentItemSpy(parentItem.data(), &QQuickItem::visibleChanged);
+ QSignalSpy childItemSpy(childItem.data(), &QQuickItem::visibleChanged);
+ QSignalSpy loaderChildSpy(loaderChild.data(), &QQuickItem::visibleChanged);
+
+ loader->setProperty("active", false);
+ QCOMPARE(parentItemSpy.count(), 0);
+ QCOMPARE(childItemSpy.count(), 0);
+ QVERIFY(!loaderChild->parentItem());
+ QCOMPARE(loaderChildSpy.count(), 1);
+ QCOMPARE(loaderChild->isVisible(), false);
+
+ delete parentItem.data();
+ QVERIFY(!parentItem);
+ QVERIFY(childItem);
+ QVERIFY(!childItem->parentItem());
+
+ QCOMPARE(parentItemSpy.count(), 0);
+ QCOMPARE(childItemSpy.count(), 1);
+}
+
+void tst_QQuickItem::lastFocusChangeReason()
+{
+ std::unique_ptr<QQuickView> window = std::make_unique<QQuickView>();
+ window->setSource(testFileUrl("focusReason.qml"));
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window.get()));
+
+ QQuickItem *item = window->findChild<QQuickItem *>("item");
+ QQuickItem *customText = window->findChild<QQuickItem *>("customText");
+ QQuickItem *customItem = window->findChild<QQuickItem *>("customItem");
+ QQuickItem *hyperlink = window->findChild<QQuickItem *>("hyperlink");
+ QQuickItem *textInputChild = window->findChild<QQuickItem *>("textInputChild");
+
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ QQuickItemPrivate *customTextPrivate = QQuickItemPrivate::get(customText);
+ QQuickItemPrivate *customItemPrivate = QQuickItemPrivate::get(customItem);
+ QQuickItemPrivate *hyperlinkPrivate = QQuickItemPrivate::get(hyperlink);
+ QQuickItemPrivate *textInputChildPrivate = QQuickItemPrivate::get(textInputChild);
+
+ QVERIFY(item);
+ QVERIFY(customText);
+ QVERIFY(customItem);
+ QVERIFY(hyperlink);
+ QVERIFY(textInputChild);
+
+ QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusAllControls);
+ auto resetTabFocusBehavior = qScopeGuard([]{
+ QGuiApplication::styleHints()->setTabFocusBehavior(Qt::TabFocusBehavior(-1));
+ });
+
+ // helper for clicking into an item
+ const auto itemCenter = [](const QQuickItem *item) -> QPoint {
+ return item->mapToScene(item->clipRect().center()).toPoint();
+ };
+
+ // setting focusPolicy to Strong/WheelFocus doesn't implicitly turn on event delivery
+ customText->setAcceptedMouseButtons(Qt::LeftButton);
+ customItem->setAcceptedMouseButtons(Qt::LeftButton);
+ customItem->setAcceptTouchEvents(true);
+ customText->setAcceptTouchEvents(true);
+ hyperlink->setAcceptTouchEvents(true);
+
+ // window activation -> ActiveWindowFocusReason
+ QVERIFY(item->hasFocus());
+ QVERIFY(item->hasActiveFocus());
+ if (itemPrivate->lastFocusChangeReason() != Qt::ActiveWindowFocusReason
+ && QStringList{"windows", "offscreen"}.contains(QGuiApplication::platformName())) {
+ QEXPECT_FAIL("", "On Windows and offscreen platforms, window activation does not set focus reason", Continue);
+ }
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::ActiveWindowFocusReason);
+
+ // test setter/getter
+ item->setFocus(false, Qt::MouseFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+ item->setFocus(true, Qt::TabFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+ item->setFocus(false, Qt::BacktabFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+ item->forceActiveFocus(Qt::ShortcutFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::ShortcutFocusReason);
+ item->setFocus(false, Qt::NoFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::NoFocusReason);
+ QVERIFY(!item->hasFocus());
+
+ // programmatic focus changes
+ item->setFocus(true, Qt::OtherFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::OtherFocusReason);
+
+ QVERIFY(item->hasFocus());
+ QVERIFY(item->hasActiveFocus());
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::OtherFocusReason);
+
+ // tab focus -> TabFocusReason
+ QTest::keyClick(window.get(), Qt::Key_Tab);
+ QVERIFY(customText->hasFocus());
+ QVERIFY(customText->hasActiveFocus());
+ QCOMPARE(qApp->focusObject(), customText);
+ QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+
+ QTest::keyClick(window.get(), Qt::Key_Tab);
+ QVERIFY(customItem->hasFocus());
+ QVERIFY(customItem->hasActiveFocus());
+ QCOMPARE(qApp->focusObject(), customItem);
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+ QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+
+ QTest::keyClick(window.get(), Qt::Key_Tab);
+ QVERIFY(hyperlink->hasFocus());
+ QVERIFY(hyperlink->hasActiveFocus());
+ QCOMPARE(qApp->focusObject(), hyperlink);
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+ QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+
+ QTest::keyClick(window.get(), Qt::Key_Tab);
+ QVERIFY(item->hasFocus());
+ QVERIFY(item->hasActiveFocus());
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::TabFocusReason);
+
+ // backtab -> BacktabFocusReason
+ QTest::keyClick(window.get(), Qt::Key_Tab, Qt::ShiftModifier);
+ QVERIFY(hyperlink->hasFocus());
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+ QCOMPARE(itemPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+
+ QTest::keyClick(window.get(), Qt::Key_Tab, Qt::ShiftModifier);
+ QVERIFY(customItem->hasFocus());
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+
+ QTest::keyClick(window.get(), Qt::Key_Tab, Qt::ShiftModifier);
+ QVERIFY(customText->hasFocus());
+ QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::BacktabFocusReason);
+
+ // click focus -> MouseFocusReason
+ QTest::mouseClick(window.get(), Qt::LeftButton, {}, itemCenter(customItem));
+ QVERIFY(customItem->hasFocus());
+ QVERIFY(customItem->hasActiveFocus());
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+ QCOMPARE(customTextPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+
+ QTest::mouseClick(window.get(), Qt::LeftButton, {}, itemCenter(hyperlink));
+ QVERIFY(hyperlink->hasFocus());
+ QVERIFY(hyperlink->hasActiveFocus());
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+
+ QTest::mouseClick(window.get(), Qt::LeftButton, {}, itemCenter(customText));
+ QCOMPARE(textInputChild, textInputChild);
+ QVERIFY(textInputChild->hasFocus());
+ QVERIFY(textInputChild->hasActiveFocus());
+ QCOMPARE(textInputChildPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+
+ // touch focus -> MouseFocusReason
+ std::unique_ptr<QPointingDevice> touchDevice(QTest::createTouchDevice());
+
+ QTest::touchEvent(window.get(), touchDevice.get()).press(0, itemCenter(customItem));
+ QTest::touchEvent(window.get(), touchDevice.get()).press(0, itemCenter(customItem));
+ QTest::touchEvent(window.get(), touchDevice.get()).release(0, itemCenter(customItem));
+ QVERIFY(customItem->hasFocus());
+ QVERIFY(customItem->hasActiveFocus());
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+ QCOMPARE(textInputChildPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+
+ QTest::touchEvent(window.get(), touchDevice.get()).press(0, itemCenter(hyperlink));
+ QTest::touchEvent(window.get(), touchDevice.get()).release(0, itemCenter(hyperlink));
+ QVERIFY(hyperlink->hasFocus());
+ QVERIFY(hyperlink->hasActiveFocus());
+ QCOMPARE(hyperlinkPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+
+ // Wheel focus -> MouseFocusReason
+ QWheelEvent wheelEvent(QPointF(customItem->width() / 2, customItem->height() / 2), QPointF(),
+ QPoint(), QPoint(0, 10), Qt::NoButton, Qt::NoModifier,
+ Qt::NoScrollPhase, false);
+ QGuiApplication::sendEvent(customItem, &wheelEvent);
+ QVERIFY(customItem->hasActiveFocus());
+ QCOMPARE(customItemPrivate->lastFocusChangeReason(), Qt::MouseFocusReason);
+}
+
+void tst_QQuickItem::focusInScopeChanges()
+{
+ std::unique_ptr<QQuickView> window = std::make_unique<QQuickView>();
+ window->setSource(testFileUrl("focusInScopeChanges.qml"));
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowFocused(window.get()));
+
+ QQuickItem *main = window->rootObject();
+ QVERIFY(main);
+ QQuickItem *focusScope = main->findChild<QQuickItem *>("focusScope");
+ QQuickItem *rect = main->findChild<QQuickItem *>("rect");
+ QQuickItem *textInput = main->findChild<QQuickItem *>("textInput");
+
+ QVERIFY(focusScope);
+ QVERIFY(rect);
+ QVERIFY(textInput);
+ QVERIFY(window->contentItem());
+
+ QSignalSpy fsActiveFocusSpy(focusScope, SIGNAL(activeFocusChanged(bool)));
+ QSignalSpy rectActiveFocusSpy(rect, SIGNAL(activeFocusChanged(bool)));
+ QSignalSpy textInputActiveFocusSpy(textInput, SIGNAL(activeFocusChanged(bool)));
+
+ // The window's content item will have activeFocus if window is focused
+ QTRY_VERIFY(window->contentItem()->hasActiveFocus());
+
+ QVERIFY(!focusScope->hasActiveFocus());
+ QVERIFY(!rect->hasActiveFocus());
+ QVERIFY(!textInput->hasActiveFocus());
+ QCOMPARE(fsActiveFocusSpy.size(), 0);
+ QCOMPARE(rectActiveFocusSpy.size(), 0);
+ QCOMPARE(textInputActiveFocusSpy.size(), 0);
+
+ // setting focus to rect shouldn't affect activeFocus as long as its
+ // parent focus scope doesn't have the activeFocus
+ rect->setFocus(true);
+ QCOMPARE(fsActiveFocusSpy.size(), 0);
+ QCOMPARE(rectActiveFocusSpy.size(), 0);
+ QCOMPARE(textInputActiveFocusSpy.size(), 0);
+
+ // focusScope is the only child with focus in the parent
+ // scope, so it will gain activeFocus
+ focusScope->setFocus(true);
+ QCOMPARE(fsActiveFocusSpy.size(), 1);
+ QVERIFY(fsActiveFocusSpy.first().at(0).toBool());
+ // rect loses activeFocus because textInput gains it (as a result of code in signal handler)
+ QCOMPARE(rectActiveFocusSpy.size(), 2);
+ QVERIFY(!rect->hasActiveFocus());
+ QCOMPARE(textInputActiveFocusSpy.size(), 1);
+ QVERIFY(textInput->hasActiveFocus());
+}
+
QTEST_MAIN(tst_QQuickItem)
#include "tst_qquickitem.moc"
diff --git a/tests/auto/quick/qquickitemlayer/BLACKLIST b/tests/auto/quick/qquickitemlayer/BLACKLIST
new file mode 100644
index 0000000000..d74ee2928a
--- /dev/null
+++ b/tests/auto/quick/qquickitemlayer/BLACKLIST
@@ -0,0 +1,23 @@
+# QTBUG-103088
+[layerSmooth]
+android
+[layerVisibility]
+android
+[layerZOrder]
+android
+[changeZOrder]
+android
+[itemEffect]
+android
+[rectangleEffect]
+android
+[textureMirroring]
+android
+[layerEffect]
+android
+[layerSourceRect]
+android
+[layerIsTextureProvider]
+android
+[changeSamplerName]
+android
diff --git a/tests/auto/quick/qquickitemlayer/CMakeLists.txt b/tests/auto/quick/qquickitemlayer/CMakeLists.txt
index 37103b0c31..b83ada3081 100644
--- a/tests/auto/quick/qquickitemlayer/CMakeLists.txt
+++ b/tests/auto/quick/qquickitemlayer/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickitemlayer.pro.
#####################################################################
## tst_qquickitemlayer Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickitemlayer LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,16 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickitemlayer
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickitemlayer.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -33,10 +40,10 @@ qt_internal_add_test(tst_qquickitemlayer
qt_internal_extend_target(tst_qquickitemlayer CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickitemlayer CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickitemlayer/data/itemImageLayer.qml b/tests/auto/quick/qquickitemlayer/data/itemImageLayer.qml
new file mode 100644
index 0000000000..1f05aa882f
--- /dev/null
+++ b/tests/auto/quick/qquickitemlayer/data/itemImageLayer.qml
@@ -0,0 +1,14 @@
+import QtQuick
+
+Item {
+ width: 300
+ height: 300
+
+ Image {
+ objectName: "image"
+ anchors.fill: parent
+ fillMode: Image.PreserveAspectFit
+ source: "qt-logo.png"
+ layer.enabled: true
+ }
+}
diff --git a/tests/auto/quick/qquickitemlayer/data/qt-logo.png b/tests/auto/quick/qquickitemlayer/data/qt-logo.png
new file mode 100644
index 0000000000..dff7729515
--- /dev/null
+++ b/tests/auto/quick/qquickitemlayer/data/qt-logo.png
Binary files differ
diff --git a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp
index 0fbd9cc24e..fb18d2be54 100644
--- a/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp
+++ b/tests/auto/quick/qquickitemlayer/tst_qquickitemlayer.cpp
@@ -1,40 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickview.h>
#include <QtQuick/qsgrendererinterface.h>
+#include <QtQuick/private/qquickitem_p.h>
#include <qopenglcontext.h>
#include <qopenglfunctions.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpa/qplatformintegration.h>
@@ -85,6 +62,8 @@ private slots:
void textureMirroring_data();
void textureMirroring();
+ void effectSourceResizeToItem();
+
private:
void mirroringCheck(int mirroring, int x, bool shouldMirror, const QImage &fb);
};
@@ -97,7 +76,7 @@ bool isOffscreen()
const char skipOffscreenMsg[] =
"Skipping due to grabWindow not functional on offscreen/minimal platformsi (QTBUG-63185)";
-tst_QQuickItemLayer::tst_QQuickItemLayer() { }
+tst_QQuickItemLayer::tst_QQuickItemLayer() : QQmlDataTest(QT_QMLTEST_DATADIR) { }
void tst_QQuickItemLayer::initTestCase()
{
@@ -151,6 +130,9 @@ void tst_QQuickItemLayer::layerEnabled()
void tst_QQuickItemLayer::layerMipmap()
{
+ if (isOffscreen())
+ QSKIP(skipOffscreenMsg);
+
QImage fb = runTest("Mipmap.qml");
QVERIFY(fb.pixel(0, 0) != 0xff000000);
QVERIFY(fb.pixel(0, 0) != 0xffffffff);
@@ -372,12 +354,18 @@ void tst_QQuickItemLayer::changeZOrder()
void tst_QQuickItemLayer::toggleLayerAndEffect()
{
+ if (isOffscreen())
+ QSKIP(skipOffscreenMsg);
+
// This test passes if it doesn't crash.
runTest("ToggleLayerAndEffect.qml");
}
void tst_QQuickItemLayer::disableLayer()
{
+ if (isOffscreen())
+ QSKIP(skipOffscreenMsg);
+
// This test passes if it doesn't crash.
runTest("DisableLayer.qml");
}
@@ -468,6 +456,25 @@ void tst_QQuickItemLayer::textureMirroring()
mirroringCheck(mirroring, 200, true, fb);
}
+void tst_QQuickItemLayer::effectSourceResizeToItem() // QTBUG-104442
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("itemImageLayer.qml")));
+ window.setResizeMode(QQuickView::SizeRootObjectToView);
+ QQuickItem *image = window.rootObject()->findChild<QQuickItem*>("image");
+ QVERIFY(image);
+ QCOMPARE(image->size(), window.rootObject()->size());
+ QQuickItemLayer *layer = QQuickItemPrivate::get(image)->layer();
+ QVERIFY(layer);
+ auto *effectSource = layer->effectSource();
+ QVERIFY(effectSource);
+ QCOMPARE(effectSource->size(), image->size());
+
+ window.resize(200, 200); // shrink it a bit
+ QTRY_COMPARE(image->size().toSize(), QSize(200, 200)); // wait for the window system
+ QCOMPARE(effectSource->size(), image->size());
+}
+
void tst_QQuickItemLayer::mirroringCheck(int mirroring, int x, bool shouldMirror, const QImage &fb)
{
int offset = 10;
diff --git a/tests/auto/quick/qquicklayouts/BLACKLIST b/tests/auto/quick/qquicklayouts/BLACKLIST
new file mode 100644
index 0000000000..fe56b2d0b3
--- /dev/null
+++ b/tests/auto/quick/qquicklayouts/BLACKLIST
@@ -0,0 +1,10 @@
+[Tests_GridLayout::test_spacings]
+qnx
+
+# QTBUG-103060
+[Tests_GridLayout::test_spacings]
+android
+[Tests_RowLayout::test_distributeToPixelGrid]
+android
+[Tests_RowLayout::test_rearrangeFixedSizeLayout]
+android
diff --git a/tests/auto/quick/qquicklayouts/CMakeLists.txt b/tests/auto/quick/qquicklayouts/CMakeLists.txt
index 520d247394..4716ee4a37 100644
--- a/tests/auto/quick/qquicklayouts/CMakeLists.txt
+++ b/tests/auto/quick/qquicklayouts/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquicklayouts.pro.
#####################################################################
## tst_qquicklayouts Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicklayouts LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -15,7 +24,7 @@ qt_internal_add_test(tst_qquicklayouts
QMLTEST
SOURCES
tst_qquicklayouts.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/quick/qquicklayouts/data/LayoutHelperLibrary.js b/tests/auto/quick/qquicklayouts/data/LayoutHelperLibrary.js
new file mode 100644
index 0000000000..7dbbc1ad64
--- /dev/null
+++ b/tests/auto/quick/qquicklayouts/data/LayoutHelperLibrary.js
@@ -0,0 +1,42 @@
+.pragma library
+
+
+function buildLayout(layoutData, parentItem) {
+ let layout = null
+ switch (layoutData.type) {
+ case "GridLayout":
+ case "RowLayout":
+ case "ColumnLayout":
+ layout = Qt.createQmlObject("import QtQuick.Layouts\n" +
+ layoutData.type + " {}", parentItem)
+ break
+ default:
+ console.log("data.layout.type not recognized(" + layoutdata.type + ")")
+ }
+ if (layout) {
+ for (let name in layoutData) {
+ let val = layoutData[name]
+ switch (name) {
+ case "items":
+ let arrLayoutData = layoutData.items
+ for (let i = 0; i < arrLayoutData.length; i++) {
+ let layoutItemDesc = arrLayoutData[i]
+ let strProps = ""
+ for (let keyName in layoutItemDesc) {
+ strProps += "Layout." + keyName + ": " + layoutItemDesc[keyName] + ";"
+ }
+ // For some reason we cannot assign the "Layout." attached properties from
+ // here, so for now we have to serialize them as strings.
+ let rect = Qt.createQmlObject("import QtQuick\nimport QtQuick.Layouts\n\nRectangle { implicitWidth: 20; implicitHeight: 20; " + strProps + "}", layout)
+ }
+ break;
+ case "type":
+ break;
+ default:
+ layout[name] = val
+ break;
+ }
+ }
+ }
+ return layout
+}
diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml
index b72bc60835..9a5ae0cc7a 100644
--- a/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml
+++ b/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.7
import QtQuick.Layouts 1.3
diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml
index 364e2cc9b2..30880e2d91 100644
--- a/tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml
+++ b/tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.9
import QtQuick.Layouts 1.3
diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml
index f6c1199218..22cf2353da 100644
--- a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml
+++ b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.6
import QtQuick.Window 2.2
diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml
index 7439fe00e9..46fbae02a0 100644
--- a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml
+++ b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.6
diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml
index 39500cc19d..ac12868627 100644
--- a/tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml
+++ b/tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.7
import QtQuick.Layouts 1.3
diff --git a/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml
index 46d18a4384..f311cc34d6 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml
@@ -1,56 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.6
import QtTest 1.0
import QtQuick.Layouts 1.1
+import "LayoutHelperLibrary.js" as LayoutHelpers
Item {
id: container
@@ -254,7 +208,7 @@ Item {
}
function test_flowLeftToRightDefaultPositions() {
- ignoreWarning("QGridLayoutEngine::addItem: Cell (1, 0) already taken");
+ ignoreWarning(/QGridLayoutEngine::addItem: Can't add .* at cell \(1, 0\) because it's already taken by .*/);
var layout = createTemporaryObject(layout_flowLeftToRightDefaultPositions_Component, container);
compare(layout.implicitWidth, 40);
compare(layout.children[0].x, 0);
@@ -586,6 +540,56 @@ Item {
tryCompare(layout.children[4], "y", 60);
}
+ Component {
+ id: layout_alignBaseline_Component
+ GridLayout {
+ columns: 2
+ columnSpacing: 0
+ rowSpacing: 0
+ TextInput {
+ property var itemRect: [x, y, width, height]
+ text: "red"
+ baselineOffset: 7
+ color: "red"
+ verticalAlignment: TextInput.AlignVCenter
+ Layout.preferredWidth: 50
+ Layout.preferredHeight: 10
+ Layout.fillHeight: true
+ }
+ TextInput {
+ property var itemRect: [x, y, width, height]
+ text: "green"
+ baselineOffset: 7
+ color: "green"
+ verticalAlignment: TextInput.AlignVCenter
+ Layout.preferredWidth: 50
+ Layout.preferredHeight: 10
+ Layout.fillHeight: true
+ }
+
+ }
+ }
+
+ function test_alignBaseline_dont_always_invalidate()
+ {
+ var layout = createTemporaryObject(layout_alignBaseline_Component, container);
+ waitForItemPolished(layout)
+ layout.height = 20
+ // Adjusting height on an item that uses Qt.AlignBaseline might adjust the baseline
+ // Test if we don't get excessive number of polish() events because of baseline changes
+ // (In this case, we don't want to align by the baseline)
+ compare(isPolishScheduled(layout), false)
+ waitForItemPolished(layout)
+ var c0 = layout.children[0]
+ c0.Layout.alignment = Qt.AlignBaseline
+ var c1 = layout.children[1]
+ c1.Layout.alignment = Qt.AlignBaseline
+
+ // We want to align by baseline => expect a polish event
+ compare(isPolishScheduled(layout), true)
+ waitForItemPolished(layout)
+ }
+
Component {
id: layout_rightToLeft_Component
@@ -985,8 +989,10 @@ Item {
// reset left|rightMargin. It should then use the generic "margins" property
c0.Layout.leftMargin = undefined
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 10 + 20 + 4 + 4 + 20 + 6)
c0.Layout.bottomMargin = undefined
+ waitForItemPolished(layout)
compare(layout.implicitHeight, 3 + 20 + 10 + 4 + 20 + 5)
}
@@ -1139,7 +1145,7 @@ Item {
function test_columnIsOutsideGrid()
{
- ignoreWarning(/QML Item: Layout: column \(2\) should be less than the number of columns \(2\)/);
+ ignoreWarning(/.*: Layout: column \(2\) should be less than the number of columns \(2\)/);
var layout = layout_columnIsOutsideGrid_Component.createObject(container);
layout.width = layout.implicitWidth
layout.height = layout.implicitHeight
@@ -1203,5 +1209,173 @@ Item {
verify(waitForItemPolished(layout))
// Shouldn't be any warnings, but no way to verify this currently: QTBUG-70029
}
+
+ // ------------------
+ Component {
+ id: hfw_Component
+ GridLayout {
+ columns: 2
+
+ Text {
+ text: "Description:"
+ }
+ TextEdit {
+ Layout.fillWidth: true
+ wrapMode: TextEdit.WordWrap
+ text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
+ + " Mauris fermentum a ante et feugiat. Nam tortor velit, sagittis et nunc a, mattis efficitur dui."
+ + " Quisque nec blandit lacus. Morbi eget mi arcu."
+
+ }
+ Rectangle {
+ color: "lightgray"
+ Layout.row: 1
+ Layout.column: 0
+ Layout.columnSpan: 2
+ Layout.fillWidth: true
+ implicitHeight: 2
+ }
+ }
+ }
+ function test_hfw() {
+ // Test to see how layouts handle height-for-width items
+ // For TextEdit, changing the width will update its implicitHeight to match what's
+ // needed in order to display it's full text
+ // Therefore, reducing the width of the layout should also increase its implicitHeight.
+ var layout = createTemporaryObject(hfw_Component, container)
+ verify(layout)
+ verify(waitForItemPolished(layout))
+ var initialImplicitHeight = layout.implicitHeight
+ var oldImplicitHeight = initialImplicitHeight
+ for (var w = layout.width - 100; w >= 200; w -= 100) {
+ layout.width = w
+ // will trigger a change in implicitHeight, which will trigger a polish event
+ verify(waitForItemPolished(layout))
+ verify(layout.implicitHeight >= oldImplicitHeight)
+ oldImplicitHeight = layout.implicitHeight
+ }
+ verify(layout.implicitHeight > initialImplicitHeight)
+ }
+
+ function test_uniformCellSizes_data()
+ {
+ return [
+ {
+ tag: "hor 9/3",
+ layout: {
+ type: "GridLayout",
+ columns: 3,
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 9,
+ expectedWidths: [3, 3, 3],
+ expectedPositions: [0, 3, 6]
+ },
+ {
+ tag: "hor 30/3",
+ layout: {
+ type: "GridLayout",
+ columns: 3,
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 30,
+ expectedWidths: [10, 10, 10]
+ },
+ {
+ tag: "hor 60/3",
+ layout: {
+ type: "GridLayout",
+ columns: 3,
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 60,
+ expectedWidths: [20, 10, 20], // We are beyond the maximumWidth. of the middle item,
+ expectedPositions: [0, 20, 40] // check that *cellSize* is still uniform
+ // (middle item will be left-aligned in the cell by default)
+ },
+ {
+ tag: "hor 66/3",
+ layout: {
+ type: "GridLayout",
+ columns: 3,
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 66,
+ expectedWidths: [20, 10, 22],
+ expectedPositions: [0, 22, 44]
+ },
+ {
+ tag: "ver 66/3",
+ layout: {
+ type: "GridLayout",
+ columns: 1,
+ items: [
+ {minimumHeight: 1, preferredHeight: 10, maximumHeight: 20, fillHeight: true},
+ {minimumHeight: 1, preferredHeight: 4, maximumHeight: 10, fillHeight: true},
+ {minimumHeight: 1, preferredHeight: 50, maximumHeight: 99, fillHeight: true}
+ ]
+ },
+ layoutHeight: 66,
+ expectedHeights: [20, 10, 22],
+ // If items are too small to fit the cell, they have a default alignment of
+ // Qt::AlignLeft | Qt::AlignVCenter
+ expectedPositions: [1, 22+6, 44]
+ }
+ ];
+ }
+
+ function test_uniformCellSizes(data)
+ {
+ let layout = LayoutHelpers.buildLayout(data.layout, testCase)
+ let isHorizontal = data.hasOwnProperty("expectedWidths")
+ layout.rowSpacing = 0
+ layout.columnSpacing = 0
+ layout.uniformCellWidths = true
+ layout.uniformCellHeights = true
+ waitForPolish(layout)
+ if (data.hasOwnProperty('layoutWidth')) {
+ layout.width = data.layoutWidth
+ }
+ if (data.hasOwnProperty('layoutHeight')) {
+ layout.height = data.layoutHeight
+ }
+
+ let expectedSizes = isHorizontal ? data.expectedWidths : data.expectedHeights
+ let actualSizes = []
+ let i = 0
+ for (i = 0; i < layout.children.length; i++) {
+ let item = layout.children[i]
+ actualSizes.push(isHorizontal ? item.width : item.height)
+ }
+ compare(actualSizes, expectedSizes)
+
+ if (data.hasOwnProperty('expectedPositions')) {
+ let actualPositions = []
+ // If items are too small to fit the cell, they have a default alignment of
+ // Qt::AlignLeft | Qt::AlignVCenter
+ for (i = 0; i < layout.children.length; i++) {
+ let item = layout.children[i]
+ actualPositions.push(isHorizontal ? item.x : item.y)
+ }
+ compare(actualPositions, data.expectedPositions)
+ }
+ }
+
}
}
diff --git a/tests/auto/quick/qquicklayouts/data/tst_layoutproxy.qml b/tests/auto/quick/qquicklayouts/data/tst_layoutproxy.qml
new file mode 100644
index 0000000000..28b0f9a61c
--- /dev/null
+++ b/tests/auto/quick/qquicklayouts/data/tst_layoutproxy.qml
@@ -0,0 +1,687 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.6
+import QtTest 1.0
+import QtQuick.Layouts
+
+Item {
+ id: container
+ width: 200
+ height: 200
+ TestCase {
+ id: testCase
+ name: "Tests_LayoutProxy"
+ when: windowShown
+ width: parent.width
+ height: parent.height
+
+ Component {
+ id: layout_proxy_Component
+ Item {
+ anchors.fill: container
+
+ property var rect1: Rectangle {
+ id: redRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "red"
+ }
+
+
+ property var rect2: Rectangle {
+ id: blueRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "blue"
+ }
+
+ property var layout1: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ }
+
+ property var layout2: ColumnLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ }
+ }
+ }
+
+ function test_Proxy_simple()
+ {
+ var item = createTemporaryObject(layout_proxy_Component, container);
+
+ item.layout2.visible = false
+ item.layout1.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+
+ item.layout1.visible = false
+ item.layout2.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 100])
+ tryCompare(item.rect2, "itemRect", [ 0, 100, 200, 100])
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+
+ }
+
+ function test_Proxy_layout_destruction1()
+ {
+ var item = createTemporaryObject(layout_proxy_Component, container);
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+
+ item.layout1.visible = false
+ item.layout2.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 100])
+ tryCompare(item.rect2, "itemRect", [ 0, 100, 200, 100])
+
+ item.layout2.destroy() //destroy the layout that has control
+ wait(0) // process the scheduled delete and actually invoke the dtor
+ compare(item.layout2, null)
+ item.layout1.visible = true //check that the other one still works
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+ }
+
+ function test_Proxy_layout_destruction2()
+ {
+ var item = createTemporaryObject(layout_proxy_Component, container);
+
+ item.layout1.visible = false
+ item.layout2.visible = false
+
+ //destroy both layouts while none has control
+ item.layout1.destroy()
+ item.layout2.destroy()
+ wait(0) // process the scheduled delete and actually invoke the dtor
+ //all layouts should be gone now
+ compare(item.layout1, null)
+ compare(item.layout2, null)
+ //but the rectangles should still be here
+ verify(item.rect1 !== null)
+ verify(item.rect2 !== null)
+ }
+
+ function test_Proxy_layout_destruction3()
+ {
+ var item = createTemporaryObject(layout_proxy_Component, container);
+
+ item.layout1.visible = true
+ item.layout2.visible = true
+
+ //destroy both layouts while both have control
+ item.layout1.destroy()
+ item.layout2.destroy()
+ wait(0) // process the scheduled delete and actually invoke the dtor
+ //all layouts should be gone now
+ compare(item.layout1, null)
+ compare(item.layout2, null)
+ //but the rectangles should still be here
+ verify(item.rect1 !== null)
+ verify(item.rect2 !== null)
+ }
+
+ function test_Proxy_layout_destruction_of_targets()
+ {
+ var item = createTemporaryObject(layout_proxy_Component, container);
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ //destroy a rectangle just to see if the proxy crashes
+ item.rect1.destroy()
+ wait(0) // process the scheduled delete and actually invoke the dtor
+ compare(item.rect1, null)
+
+ //the proxy still has the size of the item and is still there
+ tryCompare(item.layout1.children[0], "x", 0)
+ tryCompare(item.layout1.children[0], "y", 0)
+ tryCompare(item.layout1.children[0], "width", 100)
+ tryCompare(item.layout1.children[0], "height", 200)
+ //the second item is still here
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+ //the most important thing is that it does not crash
+
+ }
+
+ Component {
+ id: layout_proxy_Component_Three
+ Item {
+ anchors.fill: container
+ property var rect1: Rectangle {
+ id: redRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "red"
+ }
+
+ property var rect2: Rectangle {
+ id: blueRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "blue"
+ }
+
+ property var layout1: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ }
+
+ property var layout2: ColumnLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ }
+
+ property var layout3: ColumnLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ color: "green"
+ }
+ }
+ }
+ }
+
+ function test_Proxy_native_item()
+ {
+ var item = createTemporaryObject(layout_proxy_Component_Three, container);
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+ item.layout3.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+
+ item.layout1.visible = false
+ item.layout2.visible = true
+ item.layout3.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 100])
+ tryCompare(item.rect2, "itemRect", [ 0, 100, 200, 100])
+
+ item.layout1.visible = false
+ item.layout2.visible = false
+ item.layout3.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 67]) //66.6 = 67
+ tryCompare(item.rect2, "itemRect", [ 0, 67, 200, 66])
+ }
+
+
+ Component {
+ id: layout_proxy_Component_overwrite
+ Item {
+ anchors.fill: container
+ property var rect1: Rectangle {
+ id: redRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.preferredWidth: 180
+ Layout.preferredHeight: 180
+ Layout.margins: 0
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "red"
+ }
+
+ property var rect2: Rectangle {
+ id: blueRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.preferredWidth: 20
+ Layout.preferredHeight: 20
+ Layout.margins: 0
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "blue"
+ }
+
+ property var layout1: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ }
+
+ property var layout2: ColumnLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ }
+ }
+ }
+
+ function test_Proxy_overwrite_layout_properties()
+ {
+ var item = createTemporaryObject(layout_proxy_Component_overwrite, container);
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 180, 200])
+ tryCompare(item.rect2, "itemRect", [ 180, 0, 20, 200])
+
+ item.layout1.visible = false
+ item.layout2.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 180])
+ tryCompare(item.rect2, "itemRect", [ 0, 180, 200, 20])
+
+ //should overwrite the rectangles preferences
+ item.layout1.children[0].Layout.preferredWidth = 100
+ item.layout1.children[0].Layout.preferredHeight = 100
+ item.layout1.children[1].Layout.preferredWidth = 100
+ item.layout1.children[1].Layout.preferredHeight = 100
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+ }
+
+ Component {
+ id: layout_proxy_Component_overwrite_declarative
+ Item {
+ anchors.fill: container
+ property var rect1: Rectangle {
+ id: redRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.minimumWidth: 1
+ Layout.minimumHeight: 1
+ Layout.maximumWidth: 3
+ Layout.maximumHeight: 3
+ Layout.preferredWidth: 2
+ Layout.preferredHeight: 2
+ Layout.margins: 1
+ Layout.leftMargin: 2
+ Layout.topMargin: 3
+ Layout.rightMargin: 4
+ Layout.bottomMargin: 5
+ Layout.alignment: Qt.AlignBottom
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "red"
+ }
+
+
+ property var layout1: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge
+ Layout.fillWidth: false
+ Layout.fillHeight: false
+ Layout.minimumWidth: 100
+ Layout.minimumHeight: 100
+ Layout.maximumWidth: 300
+ Layout.maximumHeight: 300
+ Layout.preferredWidth: 200
+ Layout.preferredHeight: 200
+ Layout.margins: 100
+ Layout.leftMargin: 200
+ Layout.topMargin: 300
+ Layout.rightMargin: 400
+ Layout.bottomMargin: 500
+ Layout.alignment: Qt.AlignTop
+ }
+ }
+
+ property var layout2: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ }
+ }
+ }
+
+ function test_Proxy_overwrite_layout_properties_declarative()
+ {
+ var item = createTemporaryObject(layout_proxy_Component_overwrite_declarative, container);
+
+ compare(item.layout2.children[0].Layout.fillWidth, item.rect1.Layout.fillWidth)
+ compare(item.layout2.children[0].Layout.fillHeight, item.rect1.Layout.fillHeight)
+ compare(item.layout2.children[0].Layout.minimumWidth, item.rect1.Layout.minimumWidth)
+ compare(item.layout2.children[0].Layout.minimumHeight, item.rect1.Layout.minimumHeight)
+ compare(item.layout2.children[0].Layout.maximumWidth, item.rect1.Layout.maximumWidth)
+ compare(item.layout2.children[0].Layout.maximumHeight, item.rect1.Layout.maximumHeight)
+ compare(item.layout2.children[0].Layout.preferredWidth, item.rect1.Layout.preferredWidth)
+ compare(item.layout2.children[0].Layout.preferredHeight, item.rect1.Layout.preferredHeight)
+ compare(item.layout2.children[0].Layout.margins, item.rect1.Layout.margins)
+ compare(item.layout2.children[0].Layout.leftMargin, item.rect1.Layout.leftMargin)
+ compare(item.layout2.children[0].Layout.topMargin, item.rect1.Layout.topMargin)
+ compare(item.layout2.children[0].Layout.rightMargin, item.rect1.Layout.rightMargin)
+ compare(item.layout2.children[0].Layout.bottomMargin, item.rect1.Layout.bottomMargin)
+ compare(item.layout2.children[0].Layout.alignment, item.rect1.Layout.alignment)
+
+ verify(item.layout1.children[0].Layout.fillWidth != item.rect1.Layout.fillWidth)
+ verify(item.layout1.children[0].Layout.fillHeight != item.rect1.Layout.fillHeight)
+ verify(item.layout1.children[0].Layout.minimumWidth != item.rect1.Layout.minimumWidth)
+ verify(item.layout1.children[0].Layout.minimumHeight != item.rect1.Layout.minimumHeight)
+ verify(item.layout1.children[0].Layout.maximumWidth != item.rect1.Layout.maximumWidth)
+ verify(item.layout1.children[0].Layout.maximumHeight != item.rect1.Layout.maximumHeight)
+ verify(item.layout1.children[0].Layout.preferredWidth != item.rect1.Layout.preferredWidth)
+ verify(item.layout1.children[0].Layout.preferredHeight != item.rect1.Layout.preferredHeight)
+ verify(item.layout1.children[0].Layout.margins != item.rect1.Layout.margins)
+ verify(item.layout1.children[0].Layout.leftMargin != item.rect1.Layout.leftMargin)
+ verify(item.layout1.children[0].Layout.topMargin != item.rect1.Layout.topMargin)
+ verify(item.layout1.children[0].Layout.rightMargin != item.rect1.Layout.rightMargin)
+ verify(item.layout1.children[0].Layout.bottomMargin != item.rect1.Layout.bottomMargin)
+ verify(item.layout1.children[0].Layout.alignment != item.rect1.alignment)
+
+ compare(item.layout1.children[0].Layout.fillWidth, false)
+ compare(item.layout1.children[0].Layout.fillHeight, false)
+ compare(item.layout1.children[0].Layout.minimumWidth, item.rect1.Layout.minimumWidth * 100)
+ compare(item.layout1.children[0].Layout.minimumHeight, item.rect1.Layout.minimumHeight * 100)
+ compare(item.layout1.children[0].Layout.maximumWidth, item.rect1.Layout.maximumWidth * 100)
+ compare(item.layout1.children[0].Layout.maximumHeight, item.rect1.Layout.maximumHeight * 100)
+ compare(item.layout1.children[0].Layout.preferredWidth, item.rect1.Layout.preferredWidth * 100)
+ compare(item.layout1.children[0].Layout.preferredHeight, item.rect1.Layout.preferredHeight * 100)
+ compare(item.layout1.children[0].Layout.margins, item.rect1.Layout.margins * 100)
+ compare(item.layout1.children[0].Layout.leftMargin, item.rect1.Layout.leftMargin * 100)
+ compare(item.layout1.children[0].Layout.topMargin, item.rect1.Layout.topMargin * 100)
+ compare(item.layout1.children[0].Layout.rightMargin, item.rect1.Layout.rightMargin * 100)
+ compare(item.layout1.children[0].Layout.bottomMargin, item.rect1.Layout.bottomMargin * 100)
+ compare(item.layout1.children[0].Layout.alignment, Qt.AlignTop)
+ }
+
+ Component {
+ id: layout_proxy_Component_nesting
+ Item {
+ anchors.fill: container
+
+ property var rect1: Rectangle {
+ id: redRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "red"
+ }
+
+
+ property var rect2: Rectangle {
+ id: blueRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "blue"
+ }
+
+ property var rect3: Rectangle {
+ id: greenRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "green"
+ }
+
+ property var layout1: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ ColumnLayout {
+ spacing: 0
+ LayoutItemProxy { target: blueRectanlge }
+ LayoutItemProxy { target: greenRectanlge }
+ }
+ }
+
+ property var layout2: ColumnLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ RowLayout {
+ spacing: 0
+ LayoutItemProxy { target: blueRectanlge }
+ LayoutItemProxy { target: greenRectanlge }
+ }
+ }
+ }
+ }
+
+ function test_Proxy_nesting()
+ {
+ var item = createTemporaryObject(layout_proxy_Component_nesting, container);
+
+ item.layout2.visible = false
+ item.layout1.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 100])
+ tryCompare(item.rect3, "itemRect", [ 100, 100, 100, 100])
+
+ item.layout1.visible = false
+ item.layout2.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 100])
+ tryCompare(item.rect2, "itemRect", [ 0, 100, 100, 100])
+ tryCompare(item.rect3, "itemRect", [ 100, 100, 100, 100])
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 100])
+ tryCompare(item.rect3, "itemRect", [ 100, 100, 100, 100])
+ }
+
+
+
+ Component {
+ id: layout_proxy_Component_nesting_item
+ Item {
+ anchors.fill: container
+
+ property var rect1: Rectangle {
+ id: redRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "red"
+ }
+
+ property var rect2: Rectangle {
+ id: blueRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "blue"
+ }
+
+ property var rect3: Rectangle {
+ id: greenRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "green"
+ }
+
+ property var rect4: Rectangle {
+ id: yellowRectangle
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "yellow"
+ }
+
+ property var rect5: Rectangle {
+ id: brownRectangle
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "brown"
+ }
+
+ property var layout1: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ ColumnLayout {
+ spacing: 0
+ LayoutItemProxy { target: blueRectanlge }
+ LayoutItemProxy { target: greenRectanlge }
+ Item {
+ implicitWidth: rll.implicitWidth
+ implicitHeight: rll.implicitHeight
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ RowLayout {
+ id: rll
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: yellowRectangle }
+ LayoutItemProxy { target: brownRectangle }
+ }
+ }
+ }
+ }
+
+ property var layout2: ColumnLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ RowLayout {
+ spacing: 0
+ LayoutItemProxy { target: blueRectanlge }
+ LayoutItemProxy { target: greenRectanlge }
+ Item {
+ implicitWidth: cll.implicitWidth
+ implicitHeight: cll.implicitHeight
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ ColumnLayout {
+ id: cll
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: yellowRectangle }
+ LayoutItemProxy { target: brownRectangle }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ function test_Proxy_nesting_item()
+ {
+ var item = createTemporaryObject(layout_proxy_Component_nesting_item, container);
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 67])
+ tryCompare(item.rect3, "itemRect", [ 100, 67, 100, 66])
+ tryCompare(item.rect4, "itemRect", [ 100, 133, 50, 67])
+ tryCompare(item.rect5, "itemRect", [ 150, 133, 50, 67])
+
+ item.layout2.visible = true
+ item.layout1.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 100])
+ tryCompare(item.rect2, "itemRect", [ 0, 100, 67, 100])
+ tryCompare(item.rect3, "itemRect", [ 67, 100, 66, 100])
+ tryCompare(item.rect4, "itemRect", [ 133, 100, 67, 50])
+ tryCompare(item.rect5, "itemRect", [ 133, 150, 67, 50])
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
index 87e0a01df2..d31a0b0fb8 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
@@ -1,56 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-import QtQuick 2.2
-import QtTest 1.0
-import QtQuick.Layouts 1.0
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtTest
+import QtQuick.Controls
+import QtQuick.Layouts
+import "LayoutHelperLibrary.js" as LayoutHelpers
+
+import org.qtproject.Test
Item {
id: container
@@ -68,6 +25,13 @@ Item {
return [item.x, item.y, item.width, item.height];
}
+ function cleanup() {
+ if (LayoutSetup.useDefaultSizePolicy) {
+ LayoutSetup.useDefaultSizePolicy = false
+ compare(LayoutSetup.useDefaultSizePolicy, false)
+ }
+ }
+
Component {
id: rectangle_Component
Rectangle {
@@ -77,6 +41,18 @@ Item {
}
Component {
+ id: layout_rowLayout_Component
+ RowLayout {
+ }
+ }
+
+ Component {
+ id: layout_columnLayout_Component
+ ColumnLayout {
+ }
+ }
+
+ Component {
id: itemsWithAnchorsLayout_Component
RowLayout {
spacing: 2
@@ -126,7 +102,7 @@ Item {
function test_warnAboutLayoutItemsWithAnchors()
{
- var regex = new RegExp("QML Item: Detected anchors on an item that is managed by a layout. "
+ var regex = new RegExp(".*: Detected anchors on an item that is managed by a layout. "
+ "This is undefined behavior; use Layout.alignment instead.")
for (var i = 0; i < 7; ++i) {
ignoreWarning(regex)
@@ -322,11 +298,12 @@ Item {
compare(row.implicitHeight, 6);
var r2 = row.children[2]
r2.implicitWidth = 20
- verify(waitForRendering(row))
+ waitForItemPolished(row)
compare(row.implicitWidth, 50 + 10 + 20)
var r3 = rectangle_Component.createObject(container)
r3.implicitWidth = 30
r3.parent = row
+ waitForItemPolished(row)
compare(row.implicitWidth, 50 + 10 + 20 + 30)
row.destroy()
}
@@ -443,12 +420,14 @@ Item {
compare(layout.implicitHeight, 0)
var rect0 = layoutItem_Component.createObject(layout)
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 20)
compare(layout.implicitHeight, 20)
var rect1 = layoutItem_Component.createObject(layout)
rect1.Layout.preferredWidth = 30;
rect1.Layout.preferredHeight = 30;
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 50)
compare(layout.implicitHeight, 30)
@@ -458,25 +437,30 @@ Item {
var rect3 = layoutItem_Component.createObject(col)
rect3.Layout.fillHeight = true
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 70)
compare(col.implicitHeight, 40)
compare(layout.implicitHeight, 40)
rect3.destroy()
wait(0) // this will hopefully effectuate the destruction of the object
+ waitForItemPolished(layout)
col.destroy()
wait(0)
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 50)
compare(layout.implicitHeight, 30)
rect0.destroy()
wait(0)
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 30)
compare(layout.implicitHeight, 30)
rect1.destroy()
wait(0)
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 0)
compare(layout.implicitHeight, 0)
}
@@ -523,7 +507,7 @@ Item {
var layout = layout_alignment_Component.createObject(container);
layout.width = 100;
layout.height = 40;
-
+ waitForItemPolished(layout)
compare(itemRect(layout.children[0]), [ 0, 0, 20, 40]);
compare(itemRect(layout.children[1]), [20, 10, 20, 20]);
compare(itemRect(layout.children[2]), [40, 0, 20, 20]);
@@ -532,6 +516,102 @@ Item {
layout.destroy();
}
+
+ function buildLayout(layout, arrLayoutData) {
+ for (let i = 0; i < arrLayoutData.length; i++) {
+ let layoutItemDesc = arrLayoutData[i]
+ let rect = layoutItem_Component.createObject(layout)
+ for (let keyName in layoutItemDesc) {
+ rect.Layout[keyName] = layoutItemDesc[keyName]
+ }
+ }
+ }
+
+ function test_dynamicAlignment_data()
+ {
+ return [
+ {
+ tag: "simple",
+
+ layout: {
+ type: "RowLayout",
+ items: [
+ {preferredWidth: 30, preferredHeight: 20, fillHeight: true},
+ {preferredWidth: 30, preferredHeight: 20},
+ ]
+ },
+ expectedGeometries: [
+ [ 0, 0, 30, 60],
+ [30, 20, 30, 20]
+ ]
+ },{
+ tag: "valign",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {preferredWidth: 12, preferredHeight: 20, fillHeight: true},
+ {preferredWidth: 12, preferredHeight: 20},
+ {preferredWidth: 12, preferredHeight: 20, alignment: Qt.AlignTop},
+ {preferredWidth: 12, preferredHeight: 20, alignment: Qt.AlignVCenter},
+ {preferredWidth: 12, preferredHeight: 20, alignment: Qt.AlignBottom}
+ ]
+ },
+ expectedGeometries: [
+ [ 0, 0, 12, 60],
+ [12, 20, 12, 20],
+ [24, 0, 12, 20],
+ [36, 20, 12, 20],
+ [48, 40, 12, 20]
+ ]
+ },{
+ tag: "halign",
+ layout: {
+ type: "ColumnLayout",
+ items: [
+ {preferredWidth: 20, preferredHeight: 12, fillWidth: true},
+ {preferredWidth: 20, preferredHeight: 12},
+ {preferredWidth: 20, preferredHeight: 12, alignment: Qt.AlignLeft},
+ {preferredWidth: 20, preferredHeight: 12, alignment: Qt.AlignHCenter},
+ {preferredWidth: 20, preferredHeight: 12, alignment: Qt.AlignRight}
+ ]
+ },
+ expectedGeometries: [
+ [ 0, 0, 60, 12],
+ [ 0, 12, 20, 12],
+ [ 0, 24, 20, 12],
+ [20, 36, 20, 12],
+ [40, 48, 20, 12]
+ ]
+ }
+ ]
+ }
+
+ function test_dynamicAlignment(data)
+ {
+ let layout
+ switch (data.layout.type) {
+ case "RowLayout":
+ layout = createTemporaryObject(layout_rowLayout_Component, container)
+ break
+ case "ColumnLayout":
+ layout = createTemporaryObject(layout_columnLayout_Component, container)
+ break
+ default:
+ console.log("data.layout.type not recognized(" + data.layout.type + ")")
+ }
+ layout.spacing = 0
+ buildLayout(layout, data.layout.items)
+ layout.width = 60
+ layout.height = 60 // divides in 1/2/3/4/5/6
+ waitForItemPolished(layout)
+
+ for (let i = 0; i < layout.children.length; ++i) {
+ let itm = layout.children[i]
+ compare(itemRect(itm), data.expectedGeometries[i])
+ }
+ }
+
+
Component {
id: layout_sizeHintNormalization_Component
GridLayout {
@@ -580,7 +660,7 @@ Item {
layout.children[0].Layout.minimumWidth = data.widthHints[0];
layout.children[0].Layout.preferredWidth = data.widthHints[1];
layout.children[0].Layout.maximumWidth = data.widthHints[2];
- wait(0); // Trigger processEvents() (allow LayoutRequest to be processed)
+ waitForItemPolished(layout)
var normalizedResult = [layout.Layout.minimumWidth, layout.implicitWidth, layout.Layout.maximumWidth]
compare(normalizedResult, data.expected);
layout.destroy();
@@ -667,6 +747,7 @@ Item {
child.Layout.preferredWidth = data.childHints[1]
child.Layout.maximumWidth = data.childHints[2]
+ waitForItemPolished(layout)
var effectiveSizeHintResult = [layout.Layout.minimumWidth, layout.implicitWidth, layout.Layout.maximumWidth]
compare(effectiveSizeHintResult, data.expected)
layout.destroy()
@@ -677,38 +758,49 @@ Item {
var child = layout.children[0].children[0]
child.Layout.minimumWidth = -1
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [0, 2, 3])
child.Layout.preferredWidth = -1
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [0, 1, 3])
child.Layout.maximumWidth = -1
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [0, 1, Number.POSITIVE_INFINITY])
layout.Layout.maximumWidth = 1000
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [0, 1, 1000])
layout.Layout.maximumWidth = -1
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [0, 1, Number.POSITIVE_INFINITY])
layout.implicitWidthChangedCount = 0
child.Layout.minimumWidth = 10
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [10, 10, Number.POSITIVE_INFINITY])
compare(layout.implicitWidthChangedCount, 1)
child.Layout.preferredWidth = 20
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [10, 20, Number.POSITIVE_INFINITY])
compare(layout.implicitWidthChangedCount, 2)
child.Layout.maximumWidth = 30
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [10, 20, 30])
compare(layout.implicitWidthChangedCount, 2)
child.Layout.maximumWidth = 15
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [10, 15, 15])
compare(layout.implicitWidthChangedCount, 3)
child.Layout.maximumWidth = 30
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [10, 20, 30])
compare(layout.implicitWidthChangedCount, 4)
layout.Layout.maximumWidth = 29
+ waitForItemPolished(layout)
compare(layout.Layout.maximumWidth, 29)
layout.Layout.maximumWidth = -1
compare(layout.Layout.maximumWidth, 30)
@@ -769,19 +861,13 @@ Item {
var r = layout.children[0]
r.Layout.preferredWidth = 20
r.Layout.preferredHeight = 30
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 20)
compare(layout.implicitHeight, 30)
layout.destroy();
}
-
- Component {
- id: layout_rowLayout_Component
- RowLayout {
- }
- }
-
function test_stretchItem_data()
{
return [
@@ -816,7 +902,7 @@ Item {
r.Layout.minimumWidth = data.minimumWidth
if (data.maximumWidth !== undefined)
r.Layout.maximumWidth = data.maximumWidth
-
+ waitForItemPolished(layout)
layout.width = 100
compare(r.width, data.expectedWidth)
@@ -824,6 +910,215 @@ Item {
layout.destroy();
}
+ function test_distribution_data()
+ {
+ return [
+ {
+ tag: "one",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ ]
+ },
+ layoutWidth: 28,
+ expectedWidths: [20, 8]
+ },{
+ tag: "two",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, horizontalStretchFactor: 4, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, horizontalStretchFactor: 1, fillWidth: true},
+ ]
+ },
+ layoutWidth: 28,
+ expectedWidths: [22, 6]
+ },{
+ tag: "resize_to_0_width",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {preferredWidth: 10, fillWidth: true},
+ ]
+ },
+ layoutWidth: 0,
+ expectedWidths: [0]
+ },{
+ tag: "preferred_infinity", // Do not crash/assert when the preferred size is infinity
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 10, preferredWidth: Number.POSITIVE_INFINITY, fillWidth: true},
+ {minimumWidth: 20, preferredWidth: Number.POSITIVE_INFINITY, fillWidth: true},
+ ]
+ },
+ layoutWidth: 31, // Important that this is between minimum and preferred width of the layout.
+ expectedWidths: [10, 21] // The result here does not have to be exact. (This
+ // test is mostly concerned about not crashing).
+ }
+ ];
+ }
+
+ function test_distribution(data)
+ {
+ var layout = layout_rowLayout_Component.createObject(container)
+ layout.spacing = 0
+ buildLayout(layout, data.layout.items)
+ waitForPolish(layout)
+ layout.width = data.layoutWidth
+
+ let actualWidths = []
+ for (let i = 0; i < layout.children.length; i++) {
+ actualWidths.push(layout.children[i].width)
+ }
+ compare(actualWidths, data.expectedWidths)
+ layout.destroy();
+ }
+
+ function test_uniformCellSizes_data()
+ {
+ return [
+ {
+ tag: "hor 9/3",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 9,
+ expectedWidths: [3, 3, 3],
+ expectedPositions: [0, 3, 6]
+ },
+ {
+ tag: "hor 30/3",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 30,
+ expectedWidths: [10, 10, 10]
+ },
+ {
+ tag: "hor 60/3",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 60,
+ expectedWidths: [20, 10, 20], // We are beyond the maximumWidth. of the middle item,
+ expectedPositions: [0, 20, 40] // check that *cellSize* is still uniform
+ // (middle item will be left-aligned in the cell by default)
+ },
+ {
+ tag: "hor 66/3",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 66,
+ expectedWidths: [20, 10, 22],
+ expectedPositions: [0, 22, 44]
+ },
+ {
+ tag: "ver 66/3",
+ layout: {
+ type: "ColumnLayout",
+ items: [
+ {minimumHeight: 1, preferredHeight: 10, maximumHeight: 20, fillHeight: true},
+ {minimumHeight: 1, preferredHeight: 4, maximumHeight: 10, fillHeight: true},
+ {minimumHeight: 1, preferredHeight: 50, maximumHeight: 99, fillHeight: true}
+ ]
+ },
+ layoutHeight: 66,
+ expectedHeights: [20, 10, 22],
+ // If items are too small to fit the cell, they have a default alignment of
+ // Qt::AlignLeft | Qt::AlignVCenter
+ expectedPositions: [1, 22+6, 44]
+ }
+ ];
+ }
+
+ function test_uniformCellSizes(data)
+ {
+ let layout = LayoutHelpers.buildLayout(data.layout, testCase)
+ let isHorizontal = data.hasOwnProperty("expectedWidths")
+ layout.spacing = 0
+ layout.uniformCellSizes = true
+ waitForPolish(layout)
+ if (data.hasOwnProperty('layoutWidth')) {
+ layout.width = data.layoutWidth
+ }
+ if (data.hasOwnProperty('layoutHeight')) {
+ layout.height = data.layoutHeight
+ }
+
+ let expectedSizes = (isHorizontal ? data.expectedWidths : data.expectedHeights)
+ let actualSizes = []
+ let i = 0
+ for (i = 0; i < layout.children.length; i++) {
+ let item = layout.children[i]
+ actualSizes.push(isHorizontal ? item.width : item.height)
+ }
+ compare(actualSizes, expectedSizes)
+
+ if (data.hasOwnProperty('expectedPositions')) {
+ let actualPositions = []
+ for (i = 0; i < layout.children.length; i++) {
+ let item = layout.children[i]
+ actualPositions.push(isHorizontal ? item.x : item.y)
+ }
+ compare(actualPositions, data.expectedPositions)
+ }
+ }
+
+ Component {
+ id: uniformCellSizes_QML_Component
+ RowLayout {
+ spacing: 0
+ uniformCellSizes: true
+ Rectangle {
+ implicitWidth: 1
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ color: "red"
+ }
+ Rectangle {
+ implicitWidth: 2
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ color: "blue"
+ }
+ }
+ }
+
+ function test_uniformCellSizes_QML(data)
+ {
+ var layout = createTemporaryObject(uniformCellSizes_QML_Component, testCase)
+ layout.width = 40
+ layout.height = 20
+ let expectedWidths = [20, 20]
+ let actualWidths = [layout.children[0].width, layout.children[1].width]
+ compare(actualWidths, expectedWidths)
+ }
+
+
Component {
id: layout_alignToPixelGrid_Component
RowLayout {
@@ -994,16 +1289,21 @@ Item {
compare(grid.visible, true) // LAYOUT SHOWN
compare(grid.implicitWidth, 2);
child.visible = false
+ waitForItemPolished(layout)
compare(grid.implicitWidth, 0);
child.visible = true
+ waitForItemPolished(layout)
compare(grid.implicitWidth, 2);
grid.visible = false // LAYOUT HIDDEN
+ waitForItemPolished(layout)
compare(grid.implicitWidth, 2);
child.visible = false
expectFail('', 'If GridLayout is hidden, GridLayout is not notified when child is explicitly hidden')
+ waitForItemPolished(grid)
compare(grid.implicitWidth, 0);
child.visible = true
+ waitForItemPolished(grid)
compare(grid.implicitWidth, 2);
layout.destroy();
@@ -1041,6 +1341,78 @@ Item {
}
Component {
+ id: sizeHintBindingLoopComp
+ Item {
+ id: root
+ anchors.fill: parent
+ property var customWidth: 100
+ RowLayout {
+ id: col
+ Item {
+ id: item
+ implicitHeight: 80
+ implicitWidth: Math.max(col2.implicitWidth, root.customWidth + 20)
+ ColumnLayout {
+ id: col2
+ width: parent.width
+ Item {
+ id: rect
+ implicitWidth: root.customWidth
+ implicitHeight: 80
+ }
+ }
+ }
+ }
+ }
+ }
+
+ function test_sizeHintBindingLoopIssue() {
+ var item = createTemporaryObject(sizeHintBindingLoopComp, container)
+ waitForRendering(item)
+ item.customWidth += 10
+ waitForRendering(item)
+ verify(!LayoutSetup.bindingLoopDetected, "Detected binding loop")
+ LayoutSetup.resetBindingLoopDetectedFlag()
+ }
+
+ Component {
+ id: polishLayoutItemComp
+ Item {
+ anchors.fill: parent
+ implicitHeight: contentLayout.implicitHeight
+ implicitWidth: contentLayout.implicitWidth
+ property alias textLayout: contentLayout
+ RowLayout {
+ width: parent.width
+ height: parent.height
+ ColumnLayout {
+ id: contentLayout
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
+ Layout.maximumWidth: 200
+ Repeater {
+ model: 2
+ Text {
+ Layout.fillWidth: true
+ text: "This is a long text causing line breaks to show the bug."
+ wrapMode: Text.Wrap
+ }
+ }
+ Item {
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+ }
+
+ function test_polishLayoutItemIssue() {
+ var rootItem = createTemporaryObject(polishLayoutItemComp, container)
+ waitForRendering(rootItem)
+ var textItem = rootItem.textLayout.children[1]
+ verify(textItem.y >= rootItem.textLayout.children[0].height)
+ }
+
+ Component {
id: rearrangeNestedLayouts_Component
RowLayout {
id: layout
@@ -1207,6 +1579,49 @@ Item {
compare(rootRect.item1.width, 100)
}
+ //---------------------------
+ // Layout with negative size
+ Component {
+ id: negativeSize_Component
+ Item {
+ id: rootItem
+ width: 0
+ height: 0
+ // default width x height: (0 x 0)
+ RowLayout {
+ spacing: 0
+ anchors.fill: parent
+ anchors.leftMargin: 1 // since parent size == (0 x 0), it causes layout size
+ anchors.bottomMargin: 1 // to become (-1, -1)
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+
+ function test_negativeSize() {
+ let rootItem = createTemporaryObject(negativeSize_Component, container)
+ let rowLayout = rootItem.children[0]
+ let item = rowLayout.children[0]
+
+ const arr = [7, 1, 7, 0]
+ arr.forEach((n) => {
+ rootItem.width = n
+ rootItem.height = n
+
+ // n === 0 is special: It will cause the layout to have a
+ // negative size. In this case it will simply not rearrange its
+ // child (and leave it at its previous size, 6)
+ const expectedItemExtent = n === 0 ? 6 : n - 1
+
+ compare(item.width, expectedItemExtent)
+ compare(item.height, expectedItemExtent)
+ });
+ }
+
+
//---------------------------
Component {
id: rowlayoutWithTextItems_Component
@@ -1262,13 +1677,224 @@ Item {
function test_dependentWidth_QTBUG_87253()
{
- var warningMsg = new RegExp("Qt Quick Layouts: Detected recursive rearrange. "
- + "Aborting after two iterations.")
- for (var i = 0; i < 10; ++i) {
- ignoreWarning(warningMsg)
- }
var layout = createTemporaryObject(layout_dependentWidth_QTBUG_87253_Component, container)
+ // Do not crash
waitForRendering(layout)
}
+
+ //---------------------------
+ Component {
+ id: rowlayoutWithRectangle_Component
+ RowLayout {
+ property alias spy : signalSpy
+ Rectangle {
+ color: "red"
+ implicitWidth: 10
+ implicitHeight: 10
+ }
+ SignalSpy {
+ id: signalSpy
+ target: parent
+ signalName: "implicitWidthChanged"
+ }
+ }
+ }
+
+ // QTBUG-93988
+ function test_ensurePolished() {
+ var layout = createTemporaryObject(rowlayoutWithRectangle_Component, container)
+ compare(layout.spy.count, 1)
+ waitForRendering(layout)
+ compare(layout.implicitWidth, 10)
+ var r0 = layout.children[0]
+
+ r0.implicitWidth = 42
+ compare(layout.spy.count, 1) // Not yet updated, awaiting PolishEvent...
+ layout.ensurePolished()
+ compare(layout.spy.count, 2)
+ compare(layout.implicitWidth, 42)
+ }
+
+ //---------------------------
+ Component {
+ id: rowlayoutCausesBindingLoop_Component
+ Item {
+ id: root
+ width: 100
+ height: 100
+ property real maxWidth : Math.max(header.implicitWidth, content.implicitWidth)
+
+ RowLayout {
+ id: header
+ y: 0
+
+ Rectangle {
+ color: "red"
+ implicitWidth: 10
+ implicitHeight: 10
+ }
+ }
+ Rectangle {
+ id: content
+ y: 10
+ implicitWidth: 42
+ implicitHeight: 10
+ color: Qt.rgba(root.maxWidth/66, 0, 1, 1)
+ }
+ }
+ }
+ function test_bindingLoop() {
+ var rootItem = createTemporaryObject(rowlayoutCausesBindingLoop_Component, container)
+ waitForRendering(rootItem)
+ var header = rootItem.children[0]
+ var content = rootItem.children[1]
+ var rect = header.children[0]
+ rect.implicitWidth = 20
+ content.implicitWidth = 66
+ waitForItemPolished(header)
+ compare(rootItem.maxWidth, 66)
+
+ // Should not trigger a binding loop
+ verify(!LayoutSetup.bindingLoopDetected, "Detected binding loop")
+ LayoutSetup.resetBindingLoopDetectedFlag()
+ }
+
+
+ //---------------------------
+ // QTBUG-111792
+ Component {
+ id: rowlayoutCrashes_Component
+ RowLayout {
+ spacing: 5
+ Rectangle {
+ color: "red"
+ implicitWidth: 10
+ implicitHeight: 10
+ }
+ Rectangle {
+ color: "green"
+ implicitWidth: 10
+ implicitHeight: 10
+ }
+ }
+ }
+
+ function test_dontCrashAfterDestroyingChildren_data() {
+ return [
+ { tag: "setWidth", func: function (layout) { layout.width = 42 } },
+ { tag: "setHeight", func: function (layout) { layout.height = 42 } },
+ { tag: "getImplicitWidth", func: function (layout) { let x = layout.implicitWidth } },
+ { tag: "getImplicitHeight", func: function (layout) { let x = layout.implicitHeight } },
+ ]
+ }
+
+ function test_dontCrashAfterDestroyingChildren(data) {
+ var layout = createTemporaryObject(rowlayoutCrashes_Component, container)
+ waitForRendering(layout)
+ compare(layout.implicitWidth, 25)
+ layout.children[0].destroy() // deleteLater()
+ wait(0) // process the scheduled delete and actually invoke the dtor
+ data.func(layout) // call a function that might ultimately access the deleted item (but shouldn't)
+ }
+
+ //---------------------------
+ // Default layout size policy
+ Component {
+ id: defaultLayoutComp
+ Item {
+ id: rootItem
+ width: 110
+ height: 100
+ // Check default layout size policy
+ RowLayout {
+ spacing: 0
+ anchors.fill: parent
+ // Rectangle item - SizePolicy { Horizontal: Fixed; Vertical: Fixed }
+ Rectangle {}
+ // Button item - SizePolicy { Horizontal: Preferred; Vertical: Fixed }
+ Button {}
+ // Frame item - SizePolicy { Horizontal: Preferred; Vertical: Preferred }
+ Frame {}
+ }
+ }
+ }
+
+ function test_defaultLayoutSize() {
+ let rootItem = createTemporaryObject(defaultLayoutComp, container)
+ waitForRendering(rootItem)
+
+ let rowLayout = rootItem.children[0]
+
+ // Test default size policy disabled by default
+ compare(LayoutSetup.useDefaultSizePolicy, false)
+
+ let defaultButtonWidth = rowLayout.children[1].width
+ let defaultFrameWidth = rowLayout.children[2].width
+
+ // Enable attached properties for items and check its size
+ {
+ rowLayout.children[0].Layout.fillWidth = true
+ rowLayout.children[0].Layout.fillHeight = true
+ rowLayout.children[1].Layout.fillWidth = true
+ rowLayout.children[1].Layout.fillHeight = true
+ rowLayout.children[2].Layout.fillWidth = true
+ rowLayout.children[2].Layout.fillHeight = true
+ waitForRendering(rowLayout)
+ let isAbovePreferred = rowLayout.width >= rowLayout.implicitWidth
+ // Removing rectangle as width & implicitWidth be zero always, which makes validation of no use
+ for (let i = 1; i < rowLayout.children.length; i++) {
+ compare(rowLayout.children[i].width >= rowLayout.children[i].implicitWidth, isAbovePreferred)
+ compare(rowLayout.children[i].height, rowLayout.height)
+ }
+ }
+
+ // Destroy existing object
+ rootItem.destroy()
+
+ // Enable default size policy
+ LayoutSetup.useDefaultSizePolicy = true
+ compare(LayoutSetup.useDefaultSizePolicy, true)
+ rootItem = createTemporaryObject(defaultLayoutComp, container)
+ waitForRendering(rootItem)
+ rowLayout = rootItem.children[0]
+
+ // The default size policy would stretch button and frame accordingly
+ {
+ verify(Math.abs(rowLayout.width - (rowLayout.children[0].width + rowLayout.children[1].width + rowLayout.children[2].width)) <= 1)
+ compare(rowLayout.children[1].width < rowLayout.children[2].width, rowLayout.children[1].implicitWidth < rowLayout.children[2].implicitWidth)
+ compare(rowLayout.children[1].height, rowLayout.children[1].implicitHeight)
+ compare(rowLayout.children[2].height, rowLayout.height)
+ }
+
+ // Change the width and height of the root item to see layout size change
+ // Since default size policy for button and frame are Preferred, these items should
+ // stretch
+ {
+ let szDefaultButtonWidth = rowLayout.children[1].width
+ let szDefaultFrameWidth = rowLayout.children[2].width
+
+ rootItem.width = 210
+ rootItem.height = 200
+ waitForRendering(rootItem)
+ verify(rowLayout.children[1].width > szDefaultButtonWidth)
+ compare(rowLayout.children[1].height, rowLayout.children[1].implicitHeight)
+ verify(rowLayout.children[2].width > szDefaultFrameWidth)
+ compare(rowLayout.children[2].height, rowLayout.height)
+ }
+
+ // Disable size policies through attached properties and check item size
+ {
+ rowLayout.children[1].Layout.fillWidth = false
+ rowLayout.children[2].Layout.fillWidth = false
+ rowLayout.children[2].Layout.fillHeight = false
+ waitForRendering(rowLayout)
+ compare(rowLayout.children[1].width, defaultButtonWidth)
+ compare(rowLayout.children[2].width, defaultFrameWidth)
+ for (let index = 1; index < rowLayout.children.length; index++)
+ compare(rowLayout.children[index].height, rowLayout.children[index].implicitHeight)
+ }
+
+ rootItem.destroy()
+ }
}
}
diff --git a/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml b/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
index c567b31db3..f627a90dfd 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.15
import QtTest 1.15
@@ -190,6 +143,27 @@ Item {
}
Component {
+ id: tabComponent
+ Rectangle {
+ color: "#ff0000"
+ }
+ }
+
+ function test_attachedDynamicRendered() {
+ let layout = createTemporaryObject(stackLayoutComponent, container, { "anchors.fill": parent })
+ verify(layout)
+
+ let item1 = tabComponent.createObject(layout, { objectName: "item1" })
+ verify(item1)
+ compare(item1.StackLayout.index, 0)
+ compare(item1.StackLayout.isCurrentItem, true)
+ compare(item1.StackLayout.layout, layout)
+
+ tryCompare(item1, "width", 200)
+ tryCompare(item1, "height", 200)
+ }
+
+ Component {
id: attachedStackLayoutComponent
StackLayout {
@@ -272,5 +246,624 @@ Item {
compare(layout.item2.isCurrentItem, false)
compare(layout.item2.layout, layout)
}
+
+ function test_implicitSize() {
+ let layout = createTemporaryObject(stackLayoutComponent, container)
+ verify(layout)
+ let item1 = itemComponent.createObject(layout, { objectName: "item1", implicitWidth: 10, implicitHeight: 10 })
+ verify(item1)
+ compare(item1.implicitWidth, 10)
+ compare(item1.implicitHeight, 10)
+ let item2 = itemComponent.createObject(layout, { objectName: "item2", implicitWidth: 20, implicitHeight: 20 })
+ verify(item2)
+ compare(item2.implicitWidth, 20)
+ compare(item2.implicitHeight, 20)
+ verify(isPolishScheduled(layout))
+ verify(waitForItemPolished(layout))
+ compare(layout.implicitWidth, 20)
+ compare(layout.implicitHeight, 20)
+ }
+
+ Component {
+ id: layout_setCurrentIndex_Component
+
+ StackLayout {
+ width: 200
+ height: 200
+
+ property alias firstItem : rect
+ property alias secondItem: rowLayout
+
+ Rectangle {
+ id: rect
+ color: "red"
+ implicitWidth: 10
+ implicitHeight: 10
+ }
+ RowLayout {
+ id: rowLayout
+ spacing: 0
+ Rectangle {
+ color: "green"
+ implicitWidth: 10
+ implicitHeight: 10
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ Rectangle {
+ color: "blue"
+ implicitWidth: 10
+ implicitHeight: 10
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+
+ function test_setCurrentIndex()
+ {
+ var layout = layout_setCurrentIndex_Component.createObject(container)
+ compare(layout.firstItem.width, 200)
+
+ // Invalidate the StackLayout (and its cached size hints)
+ layout.firstItem.implicitWidth = 42
+
+ layout.currentIndex = 1
+ compare(layout.secondItem.width, 200) // width should not be -1
+ layout.destroy()
+ }
+
+ function geometry(item) {
+ return [item.x, item.y, item.width, item.height]
+ }
+
+ Component {
+ id: countGeometryChanges_Component
+ StackLayout {
+ id: stack
+ property alias col: _col
+ property alias row: _row
+ width: 100
+ ColumnLayout {
+ id: _col
+ property alias r1: _r1
+ property alias r2: _r2
+ property alias r3: _r3
+ spacing: 0
+ property int counter : 0
+ onWidthChanged: { ++counter; }
+ Rectangle {
+ id: _r1
+ implicitWidth: 20
+ implicitHeight: 20
+ Layout.fillWidth: true
+ property int counter : 0
+ onWidthChanged: { ++counter; }
+ }
+ Rectangle {
+ id: _r2
+ implicitWidth: 50
+ implicitHeight: 50
+ Layout.fillWidth: true
+ property int counter : 0
+ onWidthChanged: { ++counter; }
+ }
+ Rectangle {
+ id: _r3
+ implicitWidth: 40
+ implicitHeight: 40
+ Layout.fillWidth: true
+ property int counter : 0
+ onWidthChanged: { ++counter; }
+ }
+ }
+ RowLayout {
+ id: _row
+ property alias r5: _r5
+ spacing: 0
+ property int counter : 0
+ onWidthChanged: { ++counter; }
+ Rectangle {
+ id: _r5
+ implicitWidth: 100
+ implicitHeight: 100
+ Layout.fillWidth: true
+ property int counter : 0
+ onWidthChanged: { ++counter; }
+ }
+ }
+ }
+ }
+
+ function test_countGeometryChanges() {
+
+ var stack = countGeometryChanges_Component.createObject(container)
+ compare(stack.currentIndex, 0)
+ compare(stack.col.width, 100)
+ compare(stack.col.height, 110)
+ compare(stack.row.width, 100)
+ compare(stack.row.height, 100)
+ verify(stack.col.r1.counter <= 2)
+ compare(stack.col.r2.counter, 1)
+ verify(stack.col.r3.counter <= 2)
+ verify(stack.col.counter <= 2)
+ compare(stack.row.counter, 1) // not visible, will only receive the initial geometry change
+ compare(stack.row.r5.counter, 0)
+ stack.destroy()
+ }
+
+
+ Component {
+ id: layoutItem_Component
+ Rectangle {
+ implicitWidth: 20
+ implicitHeight: 20
+ }
+ }
+
+ Component {
+ id: emtpy_StackLayout_Component
+ StackLayout {
+ property int num_onCountChanged: 0
+ property int num_onCurrentIndexChanged: 0
+ onCountChanged: { ++num_onCountChanged; }
+ onCurrentIndexChanged: { ++num_onCurrentIndexChanged; }
+ }
+ }
+
+ function test_addAndRemoveItems()
+ {
+ var stack = emtpy_StackLayout_Component.createObject(container)
+ stack.currentIndex = 2
+ compare(stack.implicitWidth, 0)
+ compare(stack.implicitHeight, 0)
+
+ var rect0 = layoutItem_Component.createObject(stack)
+ waitForPolish(stack)
+ compare(stack.implicitWidth, 20)
+ compare(stack.implicitHeight, 20)
+ compare(rect0.visible, false)
+
+ var rect1 = layoutItem_Component.createObject(stack)
+ rect1.Layout.preferredWidth = 30
+ rect1.Layout.preferredHeight = 10
+ waitForPolish(stack)
+ compare(stack.implicitWidth, 30)
+ compare(stack.implicitHeight, 20)
+ compare(rect0.visible, false)
+ compare(rect1.visible, false)
+
+ var rect2 = layoutItem_Component.createObject(stack)
+ rect2.x = 42 // ### items in a stacklayout will have their x and y positions discarded.
+ rect2.y = 42
+ rect2.Layout.preferredWidth = 80
+ rect2.Layout.preferredHeight = 30
+ rect2.Layout.fillWidth = true
+ waitForPolish(stack)
+ compare(stack.implicitWidth, 80)
+ compare(stack.implicitHeight, 30)
+ compare(rect0.visible, false)
+ compare(rect1.visible, false)
+ compare(rect2.visible, true)
+ compare(geometry(rect2), geometry(stack))
+
+ rect2.destroy()
+ wait(0)
+ waitForPolish(stack)
+ compare(stack.implicitWidth, 30)
+ compare(stack.implicitHeight, 20)
+
+ rect0.destroy()
+ wait(0)
+ waitForPolish(stack)
+ compare(stack.implicitWidth, 30)
+ compare(stack.implicitHeight, 10)
+
+ rect1.destroy()
+ wait(0)
+ waitForPolish(stack)
+ compare(stack.implicitWidth, 0)
+ compare(stack.implicitHeight, 0)
+
+ stack.destroy()
+ }
+
+ function test_sizeHint_data() {
+ return [
+ { tag: "propagateNone", layoutHints: [10, 20, 30], childHints: [11, 21, 31], expected:[10, 20, Number.POSITIVE_INFINITY]},
+ { tag: "propagateMinimumWidth", layoutHints: [-1, 20, 30], childHints: [10, 21, 31], expected:[10, 20, Number.POSITIVE_INFINITY]},
+ { tag: "propagatePreferredWidth", layoutHints: [10, -1, 30], childHints: [11, 20, 31], expected:[10, 20, Number.POSITIVE_INFINITY]},
+ { tag: "propagateMaximumWidth", layoutHints: [10, 20, -1], childHints: [11, 21, 30], expected:[10, 20, Number.POSITIVE_INFINITY]},
+ { tag: "propagateAll", layoutHints: [-1, -1, -1], childHints: [10, 20, 30], expected:[10, 20, Number.POSITIVE_INFINITY]},
+ { tag: "propagateCrazy", layoutHints: [-1, -1, -1], childHints: [40, 21, 30], expected:[30, 30, Number.POSITIVE_INFINITY]},
+ { tag: "expandMinToExplicitPref", layoutHints: [-1, 1, -1], childHints: [11, 21, 31], expected:[ 1, 1, Number.POSITIVE_INFINITY]},
+ { tag: "expandMaxToExplicitPref", layoutHints: [-1, 99, -1], childHints: [11, 21, 31], expected:[11, 99, Number.POSITIVE_INFINITY]},
+ { tag: "expandAllToExplicitMin", layoutHints: [99, -1, -1], childHints: [11, 21, 31], expected:[99, 99, Number.POSITIVE_INFINITY]},
+ { tag: "expandPrefToExplicitMin", layoutHints: [24, -1, -1], childHints: [11, 21, 31], expected:[24, 24, Number.POSITIVE_INFINITY]},
+ { tag: "boundPrefToExplicitMax", layoutHints: [-1, -1, 19], childHints: [11, 21, 31], expected:[11, 19, Number.POSITIVE_INFINITY]},
+ { tag: "boundAllToExplicitMax", layoutHints: [-1, -1, 9], childHints: [11, 21, 31], expected:[ 9, 9, Number.POSITIVE_INFINITY]},
+ ];
+ }
+
+ function itemSizeHints(item) {
+ return [item.Layout.minimumWidth, item.implicitWidth, item.Layout.maximumWidth]
+ }
+ Component {
+ id: stacklayout_sizeHint_Component
+ StackLayout {
+ property int implicitWidthChangedCount : 0
+ onImplicitWidthChanged: { ++implicitWidthChangedCount }
+ ColumnLayout {
+ Rectangle {
+ id: r1
+ color: "red"
+ Layout.minimumWidth: 1
+ Layout.preferredWidth: 2
+ Layout.maximumWidth: 3
+
+ Layout.minimumHeight: 20
+ Layout.preferredHeight: 20
+ Layout.maximumHeight: 20
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ function test_sizeHint(data) {
+ var layout = stacklayout_sizeHint_Component.createObject(container)
+
+ var col = layout.children[0]
+ col.Layout.minimumWidth = data.layoutHints[0]
+ col.Layout.preferredWidth = data.layoutHints[1]
+ col.Layout.maximumWidth = data.layoutHints[2]
+
+ var child = col.children[0]
+ if (data.implicitWidth !== undefined) {
+ child.implicitWidth = data.implicitWidth
+ }
+ child.Layout.minimumWidth = data.childHints[0]
+ child.Layout.preferredWidth = data.childHints[1]
+ child.Layout.maximumWidth = data.childHints[2]
+
+ waitForPolish(layout)
+ var effectiveSizeHintResult = [layout.Layout.minimumWidth, layout.implicitWidth, layout.Layout.maximumWidth]
+ compare(effectiveSizeHintResult, data.expected)
+ layout.destroy()
+ }
+
+ Component {
+ id: stacklayout_addIgnoredItem_Component
+ StackLayout {
+ Repeater {
+ id: rep
+ model: 1
+ Rectangle {
+ id: r
+ }
+ }
+ }
+ }
+
+ // Items with no size information is ignored.
+ function test_addIgnoredItem()
+ {
+ var stack = stacklayout_addIgnoredItem_Component.createObject(container)
+ compare(stack.count, 1)
+ compare(stack.implicitWidth, 0)
+ compare(stack.implicitHeight, 0)
+ var r = stack.children[0]
+ r.Layout.preferredWidth = 20
+ r.Layout.preferredHeight = 30
+ waitForPolish(stack)
+ compare(stack.count, 1)
+ compare(stack.implicitWidth, 20)
+ compare(stack.implicitHeight, 30)
+ stack.destroy();
+ }
+
+ function test_dontCrashWhenAnchoredToAWindow() {
+ var test_layoutStr =
+ 'import QtQuick; \
+ import QtQuick.Window; \
+ import QtQuick.Layouts; \
+ Window { \
+ visible: true; \
+ width: stack.implicitWidth; \
+ height: stack.implicitHeight; \
+ StackLayout { \
+ id: stack; \
+ currentIndex: 0; \
+ anchors.fill: parent; \
+ Rectangle { \
+ color: "red"; \
+ implicitWidth: 300; \
+ implicitHeight: 200; \
+ } \
+ } \
+ } '
+
+ var win = Qt.createQmlObject(test_layoutStr, container, '');
+ if (win.visibility === Window.Windowed) {
+ // on single-window systems (such as Android), the window geometry will be
+ // fullscreen, and most likely it will be set to screen size. Avoid this test for
+ // those systems, as the size of the window will not be determined by the layout
+ tryCompare(win, 'width', 300);
+ }
+ win.destroy()
+ }
+
+ Component {
+ id: test_dontCrashWhenChildIsResizedToNull_Component
+ StackLayout {
+ property alias rect : _rect
+ Rectangle {
+ id: _rect;
+ color: "red"
+ implicitWidth: 200
+ implicitHeight: 200
+ }
+ }
+ }
+
+ function test_dontCrashWhenChildIsResizedToNull() {
+ var layout = test_dontCrashWhenChildIsResizedToNull_Component.createObject(container)
+ layout.rect.width = 0
+ layout.width = 222 // trigger a rearrange with a valid size
+ layout.height = 222
+ }
+
+ Component {
+ id: test_currentIndex_Component
+ StackLayout {
+ currentIndex: 1
+ Text {
+ text: "0"
+ }
+ Text {
+ text: "1"
+ }
+ }
+ }
+
+ function test_currentIndex() {
+ var layout = test_currentIndex_Component.createObject(container)
+ var c0 = layout.children[0]
+ var c1 = layout.children[1]
+ compare(layout.currentIndex, 1)
+ tryCompare(layout, 'visible', true)
+ compare(c0.visible, false)
+ compare(c1.visible, true)
+ layout.currentIndex = 0
+ compare(c0.visible, true)
+ compare(c1.visible, false)
+ var c2 = layoutItem_Component.createObject(layout)
+ compare(c2.visible, false)
+
+ /*
+ * destroy the current item and check if visibility advances to next
+ */
+ c0.destroy()
+ tryCompare(c1, 'visible', true)
+ compare(c2.visible, false)
+ c1.destroy()
+ tryCompare(c2, 'visible', true)
+ c2.destroy()
+ tryCompare(layout, 'currentIndex', 0)
+
+ layout.destroy()
+
+ /*
+ * Test the default/implicit value of currentIndex, either -1 (if empty) or 0:
+ */
+ layout = emtpy_StackLayout_Component.createObject(container)
+ tryCompare(layout, 'visible', true)
+ compare(layout.currentIndex, -1)
+ compare(layout.num_onCurrentIndexChanged, 0)
+ // make it non-empty
+ c0 = layoutItem_Component.createObject(layout)
+ compare(layout.currentIndex, 0)
+ compare(layout.num_onCurrentIndexChanged, 1)
+ compare(c0.visible, true)
+ // make it empty again
+ c0.destroy()
+ wait(0)
+ compare(layout.currentIndex, -1)
+ //tryCompare(layout, 'currentIndex', -1)
+ compare(layout.num_onCurrentIndexChanged, 2)
+
+ /*
+ * Check that explicit value doesn't change,
+ * and that no items are visible if the index is invalid/out of range
+ */
+ layout.currentIndex = 2
+ compare(layout.currentIndex, 2)
+ compare(layout.num_onCurrentIndexChanged, 3)
+ c0 = layoutItem_Component.createObject(layout)
+ compare(layout.currentIndex, 2)
+ compare(c0.visible, false)
+
+ c1 = layoutItem_Component.createObject(layout)
+ compare(layout.currentIndex, 2)
+ compare(c0.visible, false)
+ compare(c1.visible, false)
+
+ c2 = layoutItem_Component.createObject(layout)
+ compare(layout.currentIndex, 2)
+ compare(c0.visible, false)
+ compare(c1.visible, false)
+ compare(c2.visible, true)
+
+ c2.destroy()
+ wait(0)
+ compare(layout.currentIndex, 2)
+ compare(c0.visible, false)
+ compare(c1.visible, false)
+ c1.destroy()
+ wait(0)
+ compare(layout.currentIndex, 2)
+ compare(c0.visible, false)
+ c0.destroy()
+ wait(0)
+ compare(layout.currentIndex, 2)
+ compare(layout.num_onCurrentIndexChanged, 3)
+ }
+
+ function test_count() {
+ var layout = emtpy_StackLayout_Component.createObject(container)
+ tryCompare(layout, 'visible', true)
+ compare(layout.count, 0)
+ compare(layout.currentIndex, -1)
+ compare(layout.num_onCountChanged, 0)
+ compare(layout.num_onCurrentIndexChanged, 0)
+ var c0 = layoutItem_Component.createObject(layout)
+ compare(layout.count, 1)
+ compare(layout.currentIndex, 0)
+ compare(layout.num_onCurrentIndexChanged, 1)
+ compare(layout.num_onCountChanged, 1)
+ }
+
+ // QTBUG-111902
+ Component {
+ id: stackComponent
+ Loader {
+ id: loader
+ asynchronous: true
+ sourceComponent: StackLayout {
+ id: stackLayout
+ Repeater {
+ model: 3
+ Item {
+ required property int index
+ }
+ }
+ }
+ }
+ }
+
+ function test_loadStackLayoutAsynchronously() {
+ var loaderObj = stackComponent.createObject(container)
+ // Check for loader status to be ready
+ tryCompare(loaderObj, 'status', 1)
+ // Get stack layout object
+ var stackLayoutObj = loaderObj.item
+ // Check repeater index of child object
+ compare(stackLayoutObj.children[0].index, 0)
+ compare(stackLayoutObj.children[1].index, 1)
+ compare(stackLayoutObj.children[2].index, 2)
+ // Check stack layout attached property index
+ compare(stackLayoutObj.children[0].StackLayout.index, 0)
+ compare(stackLayoutObj.children[1].StackLayout.index, 1)
+ compare(stackLayoutObj.children[2].StackLayout.index, 2)
+ }
+
+ Component {
+ id: test_repeater_Component
+
+ Item {
+ property alias stackLayout : stackLayout
+ property var model : ListModel {
+ /*
+ * We cannot programmatically reorder siblings (QQuickItem::stackBefore()
+ * and QQuickItem::stackAfter() are not not available to QML, and we cannot
+ * alter the Item::children property to reorder siblings)
+ * Therefore, we have to go through the hoops with a ListModel and Repeater in
+ * order to trigger sibling reordering, just as reported in QTBUG-112691.
+ * Adding an item to a specific index (with model.insert()), will be done in
+ * two steps:
+ * 1. Append an Item to be the last of the siblings
+ * 2. Reorder that Rectangle to be at the correct child index that corresponds
+ * to the index given to model.insert()
+ *
+ * Adding an item to a specific index will therefore test sibling reordering
+ */
+ id: listModel
+ }
+ StackLayout {
+ id: stackLayout
+ anchors.fill: parent
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ Repeater {
+ id: repeater
+ model:listModel
+ delegate: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 100
+ objectName: model.color
+ color: model.color
+ }
+ }
+ }
+ }
+ }
+
+ function test_repeater() {
+ let item = createTemporaryObject(test_repeater_Component, container)
+ let layout = item.stackLayout
+ let model = item.model
+ function verifyVisibilityOfItems() {
+ for (let i = 0; i < layout.count; ++i) {
+ compare(layout.children[i].visible, layout.currentIndex === i)
+ }
+ }
+
+ compare(layout.currentIndex, -1)
+ compare(layout.count, 0)
+
+ model.append({ "color": "red" })
+ compare(layout.currentIndex, 0)
+ compare(layout.count, 1)
+ verifyVisibilityOfItems()
+
+ model.append({ "color": "green" })
+ compare(layout.currentIndex, 0)
+ compare(layout.count, 2)
+ verifyVisibilityOfItems()
+
+ model.append({ "color": "blue" })
+ compare(layout.currentIndex, 0)
+ compare(layout.count, 3)
+ verifyVisibilityOfItems()
+
+ model.insert(0, { "color": "black" })
+ compare(layout.currentIndex, 1)
+ compare(layout.count, 4)
+ verifyVisibilityOfItems()
+
+ // An implicit currentIndex will reset back to -1 if
+ // the StackLayout is empty
+ model.clear()
+ compare(layout.currentIndex, -1)
+ compare(layout.count, 0)
+
+ // set explicit index to out of bounds
+ layout.currentIndex = 1
+ compare(layout.currentIndex, 1)
+ compare(layout.count, 0)
+ verifyVisibilityOfItems()
+
+ model.append({ "color": "red" })
+ compare(layout.currentIndex, 1)
+ compare(layout.count, 1)
+ verifyVisibilityOfItems()
+
+ model.append({ "color": "green" })
+ compare(layout.currentIndex, 1)
+ compare(layout.count, 2)
+ verifyVisibilityOfItems()
+
+ model.insert(1, { "color": "brown" })
+ compare(layout.currentIndex, 2)
+ compare(layout.count, 3)
+ verifyVisibilityOfItems()
+
+ // remove red, currentIndex should decrease
+ model.remove(0, 1)
+ compare(layout.currentIndex, 1)
+ compare(layout.count, 2)
+ verifyVisibilityOfItems()
+ }
}
}
diff --git a/tests/auto/quick/qquicklayouts/tst_qquicklayouts.cpp b/tests/auto/quick/qquicklayouts/tst_qquicklayouts.cpp
index 373019091f..98b5e96486 100644
--- a/tests/auto/quick/qquicklayouts/tst_qquicklayouts.cpp
+++ b/tests/auto/quick/qquicklayouts/tst_qquicklayouts.cpp
@@ -1,29 +1,44 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcontext.h>
#include <QtQuickTest/quicktest.h>
-QUICK_TEST_MAIN(qquicklayouts)
+
+class Setup : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool bindingLoopDetected READ wasBindingLoopDetected FINAL)
+ Q_PROPERTY(bool useDefaultSizePolicy READ useDefaultSizePolicy WRITE setUseDefaultSizePolicy FINAL)
+
+public:
+ Setup() {}
+
+ bool wasBindingLoopDetected() const { return mBindingLoopDetected; }
+
+ bool useDefaultSizePolicy() const { return QCoreApplication::testAttribute(Qt::AA_QtQuickUseDefaultSizePolicy); }
+ void setUseDefaultSizePolicy(bool policy) { QCoreApplication::setAttribute(Qt::AA_QtQuickUseDefaultSizePolicy, policy); }
+
+public slots:
+ void resetBindingLoopDetectedFlag() { mBindingLoopDetected = false; }
+
+ void qmlEngineAvailable(QQmlEngine *engine)
+ {
+ connect(engine, &QQmlEngine::warnings, this, &Setup::qmlWarnings);
+ qmlRegisterSingletonInstance("org.qtproject.Test", 1, 0, "LayoutSetup", this);
+ }
+
+ void qmlWarnings(const QList<QQmlError> &warnings)
+ {
+ for (const auto &error : warnings) {
+ if (error.messageType() == QtWarningMsg && error.description().contains(QStringLiteral("Binding loop detected")))
+ mBindingLoopDetected = true;
+ }
+ }
+
+private:
+ bool mBindingLoopDetected = false;
+};
+
+QUICK_TEST_MAIN_WITH_SETUP(tst_qquicklayouts, Setup)
+
+#include "tst_qquicklayouts.moc"
diff --git a/tests/auto/quick/qquicklistview/BLACKLIST b/tests/auto/quick/qquicklistview/BLACKLIST
index 6ef69550a4..e4da77acba 100644
--- a/tests/auto/quick/qquicklistview/BLACKLIST
+++ b/tests/auto/quick/qquicklistview/BLACKLIST
@@ -4,11 +4,12 @@ opensuse-leap
#QTBUG-53863
[populateTransitions]
opensuse-42.1
+# QTBUG-75202
[contentHeightWithDelayRemove]
-macos
-#QTBUG-75960
-#QTBUG-76652
-[currentIndex]
-macos
-opensuse-leap
-ubuntu-18.04
+macos ci
+
+# QTBUG-103089
+[QTBUG_48044_currentItemNotVisibleAfterTransition]
+android
+[contentHeightWithDelayRemove]
+android
diff --git a/tests/auto/quick/qquicklistview/CMakeLists.txt b/tests/auto/quick/qquicklistview/CMakeLists.txt
index 761d515eaf..cee287ae41 100644
--- a/tests/auto/quick/qquicklistview/CMakeLists.txt
+++ b/tests/auto/quick/qquicklistview/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquicklistview.pro.
#####################################################################
## tst_qquicklistview Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicklistview LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,20 +21,12 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquicklistview
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
incrementalmodel.cpp incrementalmodel.h
proxytestinnermodel.cpp proxytestinnermodel.h
randomsortmodel.cpp randomsortmodel.h
reusemodel.h
tst_qquicklistview.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
@@ -33,6 +34,7 @@ qt_internal_add_test(tst_qquicklistview
Qt::QmlPrivate
Qt::QuickPrivate
Qt::QuickTest
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -45,10 +47,10 @@ qt_internal_add_test(tst_qquicklistview
qt_internal_extend_target(tst_qquicklistview CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquicklistview CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquicklistview/data/addoncompleted.qml b/tests/auto/quick/qquicklistview/data/addoncompleted.qml
index 2341295868..34ee459aa4 100644
--- a/tests/auto/quick/qquicklistview/data/addoncompleted.qml
+++ b/tests/auto/quick/qquicklistview/data/addoncompleted.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.9
diff --git a/tests/auto/quick/qquicklistview/data/appendDuringScrollDown.qml b/tests/auto/quick/qquicklistview/data/appendDuringScrollDown.qml
index af35c29143..6ba6480297 100644
--- a/tests/auto/quick/qquicklistview/data/appendDuringScrollDown.qml
+++ b/tests/auto/quick/qquicklistview/data/appendDuringScrollDown.qml
@@ -1,10 +1,11 @@
import QtQuick 2.6
ListView {
+ id: listView
width: 320; height: 240
focus: true
delegate: Text {
- height: 40; width: parent.width
+ height: 40; width: listView.width
text: model.text
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
diff --git a/tests/auto/quick/qquicklistview/data/attachedProperties.qml b/tests/auto/quick/qquicklistview/data/attachedProperties.qml
index 09714b2c6e..72fdc009e0 100644
--- a/tests/auto/quick/qquicklistview/data/attachedProperties.qml
+++ b/tests/auto/quick/qquicklistview/data/attachedProperties.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquicklistview/data/contentHeightWithDelayRemove.qml b/tests/auto/quick/qquicklistview/data/contentHeightWithDelayRemove.qml
index 06011519b2..f74075f9c7 100644
--- a/tests/auto/quick/qquicklistview/data/contentHeightWithDelayRemove.qml
+++ b/tests/auto/quick/qquicklistview/data/contentHeightWithDelayRemove.qml
@@ -35,9 +35,12 @@ Item {
delegate: Text {
id: wrapper
height: 100
- text: index + listView.count
+ text: index
ListView.delayRemove: listView.useDelayRemove
- ListView.onRemove: SequentialAnimation {
+ ListView.onRemove: sequentialAnimation.start()
+
+ SequentialAnimation {
+ id: sequentialAnimation
PauseAnimation { duration: wrapper.ListView.delayRemove ? 100 : 0 }
PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false }
}
diff --git a/tests/auto/quick/qquicklistview/data/displayMargin.qml b/tests/auto/quick/qquicklistview/data/displayMargin.qml
index aafbb4235f..64b668326f 100644
--- a/tests/auto/quick/qquicklistview/data/displayMargin.qml
+++ b/tests/auto/quick/qquicklistview/data/displayMargin.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Jolla Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.3
@@ -44,7 +19,7 @@ Item {
model: 100
delegate: Rectangle {
objectName: "delegate"
- width: parent.width
+ width: view.width
height: 25
color: index % 2 ? "steelblue" : "lightsteelblue"
Text {
diff --git a/tests/auto/quick/qquicklistview/data/flickBothDirections.qml b/tests/auto/quick/qquicklistview/data/flickBothDirections.qml
index b491981edb..a9905adba5 100644
--- a/tests/auto/quick/qquicklistview/data/flickBothDirections.qml
+++ b/tests/auto/quick/qquicklistview/data/flickBothDirections.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.9
Rectangle {
diff --git a/tests/auto/quick/qquicklistview/data/headerCrash.qml b/tests/auto/quick/qquicklistview/data/headerCrash.qml
index 124fa894f2..972ecb2906 100644
--- a/tests/auto/quick/qquicklistview/data/headerCrash.qml
+++ b/tests/auto/quick/qquicklistview/data/headerCrash.qml
@@ -12,7 +12,7 @@ ListView {
}
delegate: Rectangle {
- width: parent.width; height: 20
+ width: myList.width; height: 20
color: index % 2 ? "green" : "red"
}
diff --git a/tests/auto/quick/qquicklistview/data/listview-itematindex.qml b/tests/auto/quick/qquicklistview/data/listview-itematindex.qml
index fba8b11933..2194f1edff 100644
--- a/tests/auto/quick/qquicklistview/data/listview-itematindex.qml
+++ b/tests/auto/quick/qquicklistview/data/listview-itematindex.qml
@@ -1,13 +1,14 @@
import QtQuick 2.0
ListView {
+ id: listView
width: 400
height: 400
focus: true
model: 3
delegate: Text {
- width: parent.width
+ width: listView.width
height: 10
property int idx: index
text: index
diff --git a/tests/auto/quick/qquicklistview/data/listview-sections_delegate.qml b/tests/auto/quick/qquicklistview/data/listview-sections_delegate.qml
index 11da286f4d..0ac8adc2b0 100644
--- a/tests/auto/quick/qquicklistview/data/listview-sections_delegate.qml
+++ b/tests/auto/quick/qquicklistview/data/listview-sections_delegate.qml
@@ -17,6 +17,17 @@ Rectangle {
property string prevSection: ListView.previousSection
height: 20;
width: 240
+
+ ListView.onRemove: sequentialAnimation.start()
+
+ SequentialAnimation {
+ id: sequentialAnimation
+
+ PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true }
+ NumberAnimation { target: wrapper; property: "height"; to: 0; duration: 100; easing.type: Easing.InOutQuad }
+ PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false }
+ }
+
Rectangle {
height: 20
width: parent.width
@@ -46,11 +57,6 @@ Rectangle {
text: wrapper.y
}
}
- ListView.onRemove: SequentialAnimation {
- PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true }
- NumberAnimation { target: wrapper; property: "height"; to: 0; duration: 100; easing.type: Easing.InOutQuad }
- PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false }
- }
}
}
]
diff --git a/tests/auto/quick/qquicklistview/data/listview-sections_delegate_required.qml b/tests/auto/quick/qquicklistview/data/listview-sections_delegate_required.qml
index 18ce406e3f..6b4dd733d2 100644
--- a/tests/auto/quick/qquicklistview/data/listview-sections_delegate_required.qml
+++ b/tests/auto/quick/qquicklistview/data/listview-sections_delegate_required.qml
@@ -17,6 +17,16 @@ Rectangle {
property string prevSection: ListView.previousSection
height: 20;
width: 240
+
+ ListView.onRemove: sequentialAnimation.start()
+
+ SequentialAnimation {
+ id: sequentialAnimation
+ PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true }
+ NumberAnimation { target: wrapper; property: "height"; to: 0; duration: 100; easing.type: Easing.InOutQuad }
+ PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false }
+ }
+
Rectangle {
height: 20
width: parent.width
@@ -46,11 +56,6 @@ Rectangle {
text: wrapper.y
}
}
- ListView.onRemove: SequentialAnimation {
- PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true }
- NumberAnimation { target: wrapper; property: "height"; to: 0; duration: 100; easing.type: Easing.InOutQuad }
- PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false }
- }
}
}
]
diff --git a/tests/auto/quick/qquicklistview/data/listviewtest-package.qml b/tests/auto/quick/qquicklistview/data/listviewtest-package.qml
index c26bbece03..bc3dfa0843 100644
--- a/tests/auto/quick/qquicklistview/data/listviewtest-package.qml
+++ b/tests/auto/quick/qquicklistview/data/listviewtest-package.qml
@@ -79,7 +79,20 @@ Rectangle {
objectName: "wrapper"
height: 20
width: 240
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+
Package.name: "package"
+
+ ListView.onRemove: sequentialAnimation.start()
+
+ SequentialAnimation {
+ id: sequentialAnimation
+ PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true }
+ NumberAnimation { target: wrapper; property: "scale"; to: 0; duration: 250; easing.type: "InOutQuad" }
+ PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false }
+
+ }
+
Text {
text: index
}
@@ -99,13 +112,6 @@ Rectangle {
x: 200
text: wrapper.y
}
- color: ListView.isCurrentItem ? "lightsteelblue" : "white"
- ListView.onRemove: SequentialAnimation {
- PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true }
- NumberAnimation { target: wrapper; property: "scale"; to: 0; duration: 250; easing.type: "InOutQuad" }
- PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: false }
-
- }
}
}
},
diff --git a/tests/auto/quick/qquicklistview/data/moveObjectModelItemToAnotherObjectModel.qml b/tests/auto/quick/qquicklistview/data/moveObjectModelItemToAnotherObjectModel.qml
index ebdebeb449..6f5160f13d 100644
--- a/tests/auto/quick/qquicklistview/data/moveObjectModelItemToAnotherObjectModel.qml
+++ b/tests/auto/quick/qquicklistview/data/moveObjectModelItemToAnotherObjectModel.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.14
import QtQml.Models 2.14
diff --git a/tests/auto/quick/qquicklistview/data/negativeDisplayMargin.qml b/tests/auto/quick/qquicklistview/data/negativeDisplayMargin.qml
index 380fd500dc..d34069d721 100644
--- a/tests/auto/quick/qquicklistview/data/negativeDisplayMargin.qml
+++ b/tests/auto/quick/qquicklistview/data/negativeDisplayMargin.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.3
@@ -88,8 +63,8 @@ ListView {
onHeightChanged: updatedDelegateCreationRange();
Connections {
target: list
- onContentYChanged: updatedDelegateCreationRange();
- onHeightChanged: updatedDelegateCreationRange();
+ function onContentYChanged() { updatedDelegateCreationRange(); }
+ function onHeightChanged() { updatedDelegateCreationRange(); }
}
}
diff --git a/tests/auto/quick/qquicklistview/data/objectModelCulling.qml b/tests/auto/quick/qquicklistview/data/objectModelCulling.qml
index c0a70ec485..9ca79ec8e4 100644
--- a/tests/auto/quick/qquicklistview/data/objectModelCulling.qml
+++ b/tests/auto/quick/qquicklistview/data/objectModelCulling.qml
@@ -3,6 +3,7 @@ import QtQuick 2.12
import QtQml.Models 2.12
Item {
+ anchors.fill: parent
ObjectModel {
id: model1
diff --git a/tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml b/tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml
index e0acaf49e4..2215252aef 100644
--- a/tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml
+++ b/tests/auto/quick/qquicklistview/data/outsideViewportChangeNotAffectingView.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.1
import QtTest 1.1
@@ -72,7 +25,7 @@ Item {
ListElement { size: 300; }
}
delegate: Rectangle {
- width: parent.width
+ width: list.width
color: index % 2 == 0 ? "red" : "blue"
height: size
Text { anchors.centerIn: parent; text: index }
diff --git a/tests/auto/quick/qquicklistview/data/proxytest.qml b/tests/auto/quick/qquicklistview/data/proxytest.qml
index 2cd95cab74..dad5dbad8a 100644
--- a/tests/auto/quick/qquicklistview/data/proxytest.qml
+++ b/tests/auto/quick/qquicklistview/data/proxytest.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.1
import Proxy 1.0
diff --git a/tests/auto/quick/qquicklistview/data/qtbug34576.qml b/tests/auto/quick/qquicklistview/data/qtbug34576.qml
index f407d8ebe3..fdc94c0c0b 100644
--- a/tests/auto/quick/qquicklistview/data/qtbug34576.qml
+++ b/tests/auto/quick/qquicklistview/data/qtbug34576.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.7
diff --git a/tests/auto/quick/qquicklistview/data/qtbug48044.qml b/tests/auto/quick/qquicklistview/data/qtbug48044.qml
index d318643c1c..368b6bd4bd 100644
--- a/tests/auto/quick/qquicklistview/data/qtbug48044.qml
+++ b/tests/auto/quick/qquicklistview/data/qtbug48044.qml
@@ -116,7 +116,7 @@ Item {
color: header ? "yellow" : "cyan"
border.color: "black"
height: 50
- width: parent.width
+ width: listView.width
Text {
anchors.centerIn: parent
diff --git a/tests/auto/quick/qquicklistview/data/qtbug61537_modelChangesAsync.qml b/tests/auto/quick/qquicklistview/data/qtbug61537_modelChangesAsync.qml
index 0dc9e6fdb5..c385a9b4b8 100644
--- a/tests/auto/quick/qquicklistview/data/qtbug61537_modelChangesAsync.qml
+++ b/tests/auto/quick/qquicklistview/data/qtbug61537_modelChangesAsync.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
Item {
diff --git a/tests/auto/quick/qquicklistview/data/repositionListViewOnPopulateTransition.qml b/tests/auto/quick/qquicklistview/data/repositionListViewOnPopulateTransition.qml
new file mode 100644
index 0000000000..7a313f7f87
--- /dev/null
+++ b/tests/auto/quick/qquicklistview/data/repositionListViewOnPopulateTransition.qml
@@ -0,0 +1,51 @@
+import QtQuick
+import QtQuick.Controls.Basic
+
+ListView {
+ id: listView
+
+ width: 100
+ height: 100
+
+ verticalLayoutDirection: ListView.BottomToTop
+ interactive: true
+ reuseItems: false
+
+ model: ListModel {
+ ListElement {index: 0; text: "Item0"}
+ }
+
+ delegate: Button {
+ id: button
+
+ required text
+
+ property alias yScale: scaleTransform.yScale
+ property bool inverted: ListView.view.verticalLayoutDirection === ListView.BottomToTop
+
+ transform: Scale {
+ id: scaleTransform
+ origin.y: button.inverted ? button.implicitHeight : 0
+ }
+ }
+
+ populate: Transition {
+ id: populateTransition
+
+ NumberAnimation {
+ // in this case we do want to animate y to achieve a smooth
+ // transition from y=0 to its assigned y location
+ property: "y"
+ duration: 500
+ easing.type: Easing.InOutQuad
+ }
+ NumberAnimation {
+ property: "yScale"
+ from: 0
+ to: 1
+ duration: 500
+ easing.type: Easing.InOutQuad
+ }
+ }
+}
+
diff --git a/tests/auto/quick/qquicklistview/data/resizeAfterComponentComplete.qml b/tests/auto/quick/qquicklistview/data/resizeAfterComponentComplete.qml
index 851d8f9a0c..fdeca4454a 100644
--- a/tests/auto/quick/qquicklistview/data/resizeAfterComponentComplete.qml
+++ b/tests/auto/quick/qquicklistview/data/resizeAfterComponentComplete.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
@@ -56,7 +9,7 @@ ListView {
anchors.fill: parent
model: 10
delegate: Rectangle {
- width: parent.width
+ width: listView.width
height: 40
border.color: "lightsteelblue"
Text {
diff --git a/tests/auto/quick/qquicklistview/data/reusedelegateitems.qml b/tests/auto/quick/qquicklistview/data/reusedelegateitems.qml
index 773fb50f81..c54d10f88c 100644
--- a/tests/auto/quick/qquicklistview/data/reusedelegateitems.qml
+++ b/tests/auto/quick/qquicklistview/data/reusedelegateitems.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.15
Rectangle {
diff --git a/tests/auto/quick/qquicklistview/data/roundingErrors.qml b/tests/auto/quick/qquicklistview/data/roundingErrors.qml
index 4545fcd617..f850b3573a 100644
--- a/tests/auto/quick/qquicklistview/data/roundingErrors.qml
+++ b/tests/auto/quick/qquicklistview/data/roundingErrors.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
import QtQml.Models 2.1
@@ -127,7 +80,7 @@ ListView {
DropArea {
anchors.fill: parent
- onPositionChanged: {
+ onPositionChanged: (drag) => {
var to = listview.indexAt(drag.x + listview.contentX, 0)
if (to !== -1) {
var from = drag.source.DelegateModel.itemsIndex
diff --git a/tests/auto/quick/qquicklistview/data/sectionSnapping.qml b/tests/auto/quick/qquicklistview/data/sectionSnapping.qml
index 2583cc0377..48a893f88c 100644
--- a/tests/auto/quick/qquicklistview/data/sectionSnapping.qml
+++ b/tests/auto/quick/qquicklistview/data/sectionSnapping.qml
@@ -1,6 +1,7 @@
import QtQuick 2.0
ListView {
+ id: listView
width: 400
height: 400
preferredHighlightBegin: 100
@@ -17,7 +18,7 @@ ListView {
}
delegate: Rectangle {
- width: parent.width
+ width: listView.width
height: 50
color: index % 2 ? "lightsteelblue" : "steelblue"
Text {
diff --git a/tests/auto/quick/qquicklistview/data/setpositiononlayout.qml b/tests/auto/quick/qquicklistview/data/setpositiononlayout.qml
index 6e12eeafca..a605b2103d 100644
--- a/tests/auto/quick/qquicklistview/data/setpositiononlayout.qml
+++ b/tests/auto/quick/qquicklistview/data/setpositiononlayout.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquicklistview/data/sizeTransitions.qml b/tests/auto/quick/qquicklistview/data/sizeTransitions.qml
index 44e4dada60..d1bddb2047 100644
--- a/tests/auto/quick/qquicklistview/data/sizeTransitions.qml
+++ b/tests/auto/quick/qquicklistview/data/sizeTransitions.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
import QtQuick.Window 2.1
diff --git a/tests/auto/quick/qquicklistview/data/snapOneItemResize.qml b/tests/auto/quick/qquicklistview/data/snapOneItemResize.qml
index 7ecc833a64..4603cd9f34 100644
--- a/tests/auto/quick/qquicklistview/data/snapOneItemResize.qml
+++ b/tests/auto/quick/qquicklistview/data/snapOneItemResize.qml
@@ -2,6 +2,7 @@ import QtQuick 2.0
ListView {
id: list
+ anchors.fill: parent
currentIndex: 5
snapMode: ListView.SnapOneItem
orientation: ListView.Horizontal
diff --git a/tests/auto/quick/qquicklistview/data/snapOneItemWrongDirection.qml b/tests/auto/quick/qquicklistview/data/snapOneItemWrongDirection.qml
index f5b7b35d0c..1dfbfe0feb 100644
--- a/tests/auto/quick/qquicklistview/data/snapOneItemWrongDirection.qml
+++ b/tests/auto/quick/qquicklistview/data/snapOneItemWrongDirection.qml
@@ -1,13 +1,14 @@
import QtQuick 2.0
ListView {
+ id: listView
width: 400
height: 400
focus: true
model: 10
delegate: Rectangle {
- width: parent.width
+ width: listView.width
height: 50
color: index % 2 ? "blue" : "green"
}
diff --git a/tests/auto/quick/qquicklistview/data/stickyPositioning-both.qml b/tests/auto/quick/qquicklistview/data/stickyPositioning-both.qml
index 57e7578ba5..ece0e2527b 100644
--- a/tests/auto/quick/qquicklistview/data/stickyPositioning-both.qml
+++ b/tests/auto/quick/qquicklistview/data/stickyPositioning-both.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.4
Rectangle {
diff --git a/tests/auto/quick/qquicklistview/data/stickyPositioning-footer.qml b/tests/auto/quick/qquicklistview/data/stickyPositioning-footer.qml
index fd815ea79e..568762b445 100644
--- a/tests/auto/quick/qquicklistview/data/stickyPositioning-footer.qml
+++ b/tests/auto/quick/qquicklistview/data/stickyPositioning-footer.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.4
Rectangle {
diff --git a/tests/auto/quick/qquicklistview/data/stickyPositioning-header.qml b/tests/auto/quick/qquicklistview/data/stickyPositioning-header.qml
index 94fb294474..6b5889a808 100644
--- a/tests/auto/quick/qquicklistview/data/stickyPositioning-header.qml
+++ b/tests/auto/quick/qquicklistview/data/stickyPositioning-header.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.4
Rectangle {
diff --git a/tests/auto/quick/qquicklistview/data/strictlyenforcerange-resize.qml b/tests/auto/quick/qquicklistview/data/strictlyenforcerange-resize.qml
index 338af38475..16b9c72b16 100644
--- a/tests/auto/quick/qquicklistview/data/strictlyenforcerange-resize.qml
+++ b/tests/auto/quick/qquicklistview/data/strictlyenforcerange-resize.qml
@@ -1,6 +1,7 @@
import QtQuick 2.0
ListView {
+ id: listView
width: 400
height: 400
focus: true
@@ -15,7 +16,7 @@ ListView {
model: 10
delegate: Item {
- width: parent.width
+ width: listView.width
height: ListView.isCurrentItem ? 100 : 50
Text {
diff --git a/tests/auto/quick/qquicklistview/data/usechooserwithoutdefault.qml b/tests/auto/quick/qquicklistview/data/usechooserwithoutdefault.qml
index 45164222f2..cba0ad5720 100644
--- a/tests/auto/quick/qquicklistview/data/usechooserwithoutdefault.qml
+++ b/tests/auto/quick/qquicklistview/data/usechooserwithoutdefault.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicklistview/incrementalmodel.cpp b/tests/auto/quick/qquicklistview/incrementalmodel.cpp
index 3f6f9681f5..f2c6219711 100644
--- a/tests/auto/quick/qquicklistview/incrementalmodel.cpp
+++ b/tests/auto/quick/qquicklistview/incrementalmodel.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "incrementalmodel.h"
#include <QGuiApplication>
diff --git a/tests/auto/quick/qquicklistview/incrementalmodel.h b/tests/auto/quick/qquicklistview/incrementalmodel.h
index 1494575edc..f61d38a3d1 100644
--- a/tests/auto/quick/qquicklistview/incrementalmodel.h
+++ b/tests/auto/quick/qquicklistview/incrementalmodel.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef IncrementalModel_H
#define IncrementalModel_H
@@ -38,14 +13,14 @@ class IncrementalModel : public QAbstractListModel
Q_OBJECT
public:
- IncrementalModel(QObject *parent = 0);
+ IncrementalModel(QObject *parent = nullptr);
- int rowCount(const QModelIndex &parent = QModelIndex()) const;
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
protected:
- bool canFetchMore(const QModelIndex &parent) const;
- void fetchMore(const QModelIndex &parent);
+ bool canFetchMore(const QModelIndex &parent) const override;
+ void fetchMore(const QModelIndex &parent) override;
private:
QStringList list;
diff --git a/tests/auto/quick/qquicklistview/proxytestinnermodel.cpp b/tests/auto/quick/qquicklistview/proxytestinnermodel.cpp
index 66f4f28812..e142a8a58b 100644
--- a/tests/auto/quick/qquicklistview/proxytestinnermodel.cpp
+++ b/tests/auto/quick/qquicklistview/proxytestinnermodel.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "proxytestinnermodel.h"
@@ -53,7 +28,7 @@ int ProxyTestInnerModel::rowCount(const QModelIndex &parent) const
if (parent.isValid())
return 0;
- return m_values.count();
+ return m_values.size();
}
int ProxyTestInnerModel::columnCount(const QModelIndex &parent) const
@@ -74,7 +49,7 @@ QVariant ProxyTestInnerModel::data(const QModelIndex &index, int role) const
void ProxyTestInnerModel::append(const QString &s)
{
- beginInsertRows(QModelIndex(), m_values.count(), m_values.count());
+ beginInsertRows(QModelIndex(), m_values.size(), m_values.size());
m_values << s;
endInsertRows();
}
diff --git a/tests/auto/quick/qquicklistview/proxytestinnermodel.h b/tests/auto/quick/qquicklistview/proxytestinnermodel.h
index 8599db4c87..5ea78ae864 100644
--- a/tests/auto/quick/qquicklistview/proxytestinnermodel.h
+++ b/tests/auto/quick/qquicklistview/proxytestinnermodel.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef INNERMODEL_H
#define INNERMODEL_H
@@ -36,11 +11,11 @@ class ProxyTestInnerModel : public QAbstractItemModel
Q_OBJECT
public:
ProxyTestInnerModel();
- virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
- virtual QModelIndex parent(const QModelIndex & /*parent*/) const;
- virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
- virtual int columnCount(const QModelIndex &parent) const;
- virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex & /*parent*/) const override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Q_INVOKABLE void doStuff();
diff --git a/tests/auto/quick/qquicklistview/randomsortmodel.cpp b/tests/auto/quick/qquicklistview/randomsortmodel.cpp
index 65d7fdb6e8..0e5f562e4b 100644
--- a/tests/auto/quick/qquicklistview/randomsortmodel.cpp
+++ b/tests/auto/quick/qquicklistview/randomsortmodel.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "randomsortmodel.h"
#include <QRandomGenerator>
@@ -48,7 +23,7 @@ QHash<int, QByteArray> RandomSortModel::roleNames() const
int RandomSortModel::rowCount(const QModelIndex& parent) const
{
if (!parent.isValid())
- return mData.count();
+ return mData.size();
return 0;
}
@@ -59,7 +34,7 @@ QVariant RandomSortModel::data(const QModelIndex& index, int role) const
return QVariant();
}
- if (index.row() >= mData.count()) {
+ if (index.row() >= mData.size()) {
return QVariant();
}
@@ -74,14 +49,14 @@ QVariant RandomSortModel::data(const QModelIndex& index, int role) const
void RandomSortModel::randomize()
{
- const int row = QRandomGenerator::global()->bounded(int(mData.count()));
+ const int row = QRandomGenerator::global()->bounded(mData.size());
int random;
bool exists = false;
// Make sure we won't end up with two items with the same weight, as that
// would make unit-testing much harder
do {
exists = false;
- random = QRandomGenerator::global()->bounded(int(mData.count() * 10));
+ random = QRandomGenerator::global()->bounded(mData.size() * 10);
QList<QPair<QString, int> >::ConstIterator iter, end;
for (iter = mData.constBegin(), end = mData.constEnd(); iter != end; ++iter) {
if ((*iter).second == random) {
diff --git a/tests/auto/quick/qquicklistview/randomsortmodel.h b/tests/auto/quick/qquicklistview/randomsortmodel.h
index 2430e87f20..9d53a8cff3 100644
--- a/tests/auto/quick/qquicklistview/randomsortmodel.h
+++ b/tests/auto/quick/qquicklistview/randomsortmodel.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef RANDOMSORTMODEL_H
#define RANDOMSORTMODEL_H
@@ -36,11 +11,11 @@ class RandomSortModel : public QAbstractListModel
Q_OBJECT
public:
- explicit RandomSortModel(QObject* parent = 0);
- QHash<int, QByteArray> roleNames() const;
+ explicit RandomSortModel(QObject *parent = nullptr);
+ QHash<int, QByteArray> roleNames() const override;
- QVariant data(const QModelIndex& index, int role) const;
- int rowCount(const QModelIndex& parent = QModelIndex()) const;
+ QVariant data(const QModelIndex& index, int role) const override;
+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
void randomize();
diff --git a/tests/auto/quick/qquicklistview/reusemodel.h b/tests/auto/quick/qquicklistview/reusemodel.h
index 21e6739384..0a23a2bda4 100644
--- a/tests/auto/quick/qquicklistview/reusemodel.h
+++ b/tests/auto/quick/qquicklistview/reusemodel.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef REUSEMODEL_H
#define REUSEMODEL_H
diff --git a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
index d99459a4af..48171266de 100644
--- a/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
+++ b/tests/auto/quick/qquicklistview/tst_qquicklistview.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtCore/QStringListModel>
@@ -37,18 +12,20 @@
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlexpression.h>
#include <QtQml/qqmlincubator.h>
+#include <QtQml/qqmlcomponent.h>
#include <QtQuick/private/qquickitemview_p_p.h>
#include <QtQuick/private/qquicklistview_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
#include <QtQuick/private/qquicktext_p.h>
#include <QtQuick/private/qquickrectangle_p.h>
+#include <QtQuick/private/qquicktransition_p.h>
#include <QtQmlModels/private/qqmlobjectmodel_p.h>
#include <QtQmlModels/private/qqmllistmodel_p.h>
#include <QtQmlModels/private/qqmldelegatemodel_p.h>
#include <qpa/qwindowsysteminterface.h>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
-#include "../shared/visualtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include "incrementalmodel.h"
#include "proxytestinnermodel.h"
#include "randomsortmodel.h"
@@ -62,8 +39,8 @@ Q_DECLARE_METATYPE(QQuickListView::Orientation)
Q_DECLARE_METATYPE(QQuickFlickable::FlickableDirection)
Q_DECLARE_METATYPE(Qt::Key)
-using namespace QQuickViewTestUtil;
-using namespace QQuickVisualTestUtil;
+using namespace QQuickViewTestUtils;
+using namespace QQuickVisualTestUtils;
#define SHARE_VIEWS
@@ -72,9 +49,12 @@ class tst_QQuickListView : public QQmlDataTest
Q_OBJECT
public:
tst_QQuickListView();
+ ~tst_QQuickListView() { delete touchDevice; }
private slots:
- void init();
+ // WARNING: please add new tests to tst_qquicklistview2; this file is too slow to work with.
+
+ void init() override;
void cleanupTestCase();
// Test QAbstractItemModel model types
void qAbstractItemModel_package_items();
@@ -207,6 +187,7 @@ private slots:
void populateTransitions();
void populateTransitions_data();
+ void repositionFirstItemOnPopulateTransition();
void sizeTransitions();
void sizeTransitions_data();
@@ -301,6 +282,8 @@ private slots:
void clickHeaderAndFooterWhenClip();
void animatedDelegate();
+ // WARNING: please add new tests to tst_qquicklistview2; this file is too slow to work with.
+
private:
template <class T> void items(const QUrl &source);
template <class T> void changed(const QUrl &source);
@@ -397,12 +380,16 @@ public:
int mCacheBuffer;
};
-tst_QQuickListView::tst_QQuickListView() : m_view(nullptr)
+tst_QQuickListView::tst_QQuickListView()
+ : QQmlDataTest(QT_QMLTEST_DATADIR, FailOnWarningsPolicy::FailOnWarnings)
+ , m_view(nullptr)
{
}
void tst_QQuickListView::init()
{
+ QQmlDataTest::init();
+
#ifdef SHARE_VIEWS
if (m_view && QString(QTest::currentTestFunction()) != testForView) {
testForView = QString();
@@ -427,6 +414,9 @@ void tst_QQuickListView::cleanupTestCase()
template <class T>
void tst_QQuickListView::items(const QUrl &source)
{
+ // Make sure we outlive the view, or the context property will become null.
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
T model;
@@ -437,7 +427,6 @@ void tst_QQuickListView::items(const QUrl &source)
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(source);
@@ -457,7 +446,7 @@ void tst_QQuickListView::items(const QUrl &source)
QTRY_COMPARE(listview->count(), model.count());
QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
listview->forceLayout();
- QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
+ QTRY_COMPARE(contentItem->childItems().size(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
// current item should be first item
QTRY_COMPARE(listview->currentItem(), findItem<QQuickItem>(contentItem, "wrapper", 0));
@@ -508,6 +497,8 @@ void tst_QQuickListView::items(const QUrl &source)
template <class T>
void tst_QQuickListView::changed(const QUrl &source)
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
T model;
@@ -518,7 +509,6 @@ void tst_QQuickListView::changed(const QUrl &source)
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(source);
@@ -546,6 +536,8 @@ void tst_QQuickListView::changed(const QUrl &source)
template <class T>
void tst_QQuickListView::inserted(const QUrl &source)
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
@@ -558,7 +550,6 @@ void tst_QQuickListView::inserted(const QUrl &source)
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(source);
@@ -573,7 +564,7 @@ void tst_QQuickListView::inserted(const QUrl &source)
model.insertItem(1, "Will", "9876");
QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
- QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
+ QTRY_COMPARE(contentItem->childItems().size(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
QQuickText *name = findItem<QQuickText>(contentItem, "textName", 1);
QTRY_VERIFY(name != nullptr);
@@ -591,7 +582,7 @@ void tst_QQuickListView::inserted(const QUrl &source)
model.insertItem(0, "Foo", "1111"); // zero index, and current item
QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
- QTRY_COMPARE(contentItem->childItems().count(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
+ QTRY_COMPARE(contentItem->childItems().size(), model.count()+1); // assumes all are visible, +1 for the (default) highlight item
name = findItem<QQuickText>(contentItem, "textName", 0);
QTRY_VERIFY(name != nullptr);
@@ -650,11 +641,12 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v
for (int i = 0; i < 30; i++)
model.addItem("Item" + QString::number(i), "");
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QQuickView *window = getView();
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(testFileUrl("listviewtest.qml"));
@@ -668,7 +660,7 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v
if (verticalLayoutDirection == QQuickItemView::BottomToTop) {
listview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
contentY = -listview->height() - contentY;
}
listview->setContentY(contentY);
@@ -681,7 +673,7 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v
model.insertItems(insertIndex, newData);
//Wait for polish (updates list to the model changes)
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_COMPARE(listview->property("count").toInt(), model.count());
@@ -706,7 +698,7 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
int firstVisibleIndex = -1;
- for (int i=0; i<items.count(); i++) {
+ for (int i=0; i<items.size(); i++) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (item && !QQuickItemPrivate::get(item)->culled) {
firstVisibleIndex = i;
@@ -720,7 +712,7 @@ void tst_QQuickListView::inserted_more(QQuickItemView::VerticalLayoutDirection v
QQuickText *number;
const qreal visibleFromPos = listview->contentY() - listview->displayMarginBeginning() - listview->cacheBuffer();
const qreal visibleToPos = listview->contentY() + listview->height() + listview->displayMarginEnd() + listview->cacheBuffer();
- for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
+ for (int i = firstVisibleIndex; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
qreal pos = i*20.0 + itemsOffsetAfterMove;
@@ -861,7 +853,7 @@ void tst_QQuickListView::insertBeforeVisible()
QTRY_VERIFY(contentItem != nullptr);
listview->setCacheBuffer(cacheBuffer);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// trigger a refill (not just setting contentY) so that the visibleItems grid is updated
int firstVisibleIndex = 20; // move to an index where the top item is not visible
@@ -869,7 +861,7 @@ void tst_QQuickListView::insertBeforeVisible()
listview->setCurrentIndex(firstVisibleIndex);
qApp->processEvents();
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_COMPARE(listview->currentIndex(), firstVisibleIndex);
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", firstVisibleIndex);
QVERIFY(item);
@@ -889,12 +881,12 @@ void tst_QQuickListView::insertBeforeVisible()
// now, moving to the top of the view should position the inserted items correctly
int itemsOffsetAfterMove = (removeCount - insertCount) * 20;
listview->setCurrentIndex(0);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_COMPARE(listview->currentIndex(), 0);
QTRY_COMPARE(listview->contentY(), 0.0 + itemsOffsetAfterMove);
// Confirm items positioned correctly and indexes correct
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
@@ -951,6 +943,8 @@ void tst_QQuickListView::insertBeforeVisible_data()
template <class T>
void tst_QQuickListView::removed(const QUrl &source, bool /* animated */)
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
T model;
@@ -960,7 +954,6 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */)
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(source);
@@ -971,7 +964,7 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */)
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
model.removeItem(1);
QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
@@ -984,7 +977,7 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */)
QTRY_COMPARE(number->text(), model.number(1));
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -1004,7 +997,7 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */)
QTRY_COMPARE(number->text(), model.number(0));
// Confirm items positioned correctly
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -1017,7 +1010,7 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */)
QTRY_COMPARE(window->rootObject()->property("count").toInt(), model.count());
// Confirm items positioned correctly
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -1050,10 +1043,10 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */)
listview->setContentY(20); // That's the top now
// let transitions settle.
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Confirm items positioned correctly
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -1064,7 +1057,7 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */)
// remove current item beyond visible items.
listview->setCurrentIndex(20);
listview->setContentY(40);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
model.removeItem(20);
QTRY_COMPARE(listview->currentIndex(), 20);
@@ -1072,7 +1065,7 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */)
// remove item before current, but visible
listview->setCurrentIndex(8);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
oldCurrent = listview->currentItem();
model.removeItem(6);
@@ -1080,14 +1073,14 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */)
QTRY_COMPARE(listview->currentItem(), oldCurrent);
listview->setContentY(80);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// remove all visible items
model.removeItems(1, 18);
QTRY_COMPARE(listview->count() , model.count());
// Confirm items positioned correctly
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount-1; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i+1);
if (!item) qWarning() << "Item" << i+1 << "not found";
@@ -1122,7 +1115,7 @@ void tst_QQuickListView::removed(const QUrl &source, bool /* animated */)
listview->positionViewAtEnd();
for (int i = 0; i < 18; ++i)
model.removeItems(model.count() - 1, 1);
- QTRY_VERIFY(findItems<QQuickItem>(contentItem, "wrapper").count() > 16);
+ QTRY_VERIFY(findItems<QQuickItem>(contentItem, "wrapper").size() > 16);
}
template <class T>
@@ -1156,14 +1149,14 @@ void tst_QQuickListView::removed_more(const QUrl &source, QQuickItemView::Vertic
if (verticalLayoutDirection == QQuickItemView::BottomToTop) {
listview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
contentY = -listview->height() - contentY;
}
listview->setContentY(contentY);
model.removeItems(removeIndex, removeCount);
//Wait for polish (updates list to the model changes)
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_COMPARE(listview->property("count").toInt(), model.count());
@@ -1178,9 +1171,9 @@ void tst_QQuickListView::removed_more(const QUrl &source, QQuickItemView::Vertic
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
int firstVisibleIndex = -1;
- for (int i=0; i<items.count(); i++) {
+ for (int i=0; i<items.size(); i++) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
- if (item && delegateVisible(item)) {
+ if (item && isDelegateVisible(item)) {
firstVisibleIndex = i;
break;
}
@@ -1190,7 +1183,7 @@ void tst_QQuickListView::removed_more(const QUrl &source, QQuickItemView::Vertic
// Confirm items positioned correctly and indexes correct
QQuickText *name;
QQuickText *number;
- for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
+ for (int i = firstVisibleIndex; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
qreal pos = i*20.0 + itemsOffsetAfterMove;
@@ -1314,6 +1307,8 @@ void tst_QQuickListView::removed_more_data()
template <class T>
void tst_QQuickListView::clear(const QUrl &source, QQuickItemView::VerticalLayoutDirection verticalLayoutDirection)
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
T model;
@@ -1323,7 +1318,6 @@ void tst_QQuickListView::clear(const QUrl &source, QQuickItemView::VerticalLayou
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(source);
@@ -1336,11 +1330,11 @@ void tst_QQuickListView::clear(const QUrl &source, QQuickItemView::VerticalLayou
QTRY_VERIFY(contentItem != nullptr);
listview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
model.clear();
- QTRY_COMPARE(findItems<QQuickListView>(contentItem, "wrapper").count(), 0);
+ QTRY_COMPARE(findItems<QQuickListView>(contentItem, "wrapper").size(), 0);
QTRY_COMPARE(listview->count(), 0);
QTRY_VERIFY(!listview->currentItem());
if (verticalLayoutDirection == QQuickItemView::TopToBottom)
@@ -1392,26 +1386,26 @@ void tst_QQuickListView::moved(const QUrl &source, QQuickItemView::VerticalLayou
QTRY_VERIFY(contentItem != nullptr);
// always need to wait for view to be painted before the first move()
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
bool waitForPolish = (contentY != 0);
if (verticalLayoutDirection == QQuickItemView::BottomToTop) {
listview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
contentY = -listview->height() - contentY;
}
listview->setContentY(contentY);
if (waitForPolish)
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
model.moveItems(from, to, count);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
int firstVisibleIndex = -1;
- for (int i=0; i<items.count(); i++) {
+ for (int i=0; i<items.size(); i++) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
- if (item && delegateVisible(item)) {
+ if (item && isDelegateVisible(item)) {
firstVisibleIndex = i;
break;
}
@@ -1419,7 +1413,7 @@ void tst_QQuickListView::moved(const QUrl &source, QQuickItemView::VerticalLayou
QVERIFY2(firstVisibleIndex >= 0, QByteArray::number(firstVisibleIndex));
// Confirm items positioned correctly and indexes correct
- for (int i = firstVisibleIndex; i < model.count() && i < items.count(); ++i) {
+ for (int i = firstVisibleIndex; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
qreal pos = i*20.0 + itemsOffsetAfterMove;
@@ -1617,9 +1611,9 @@ void tst_QQuickListView::multipleChanges(bool condensed)
QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
QTRY_VERIFY(listview != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
- for (int i=0; i<changes.count(); i++) {
+ for (int i=0; i<changes.size(); i++) {
switch (changes[i].type) {
case ListChange::Inserted:
{
@@ -1645,10 +1639,10 @@ void tst_QQuickListView::multipleChanges(bool condensed)
continue;
}
if (!condensed) {
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
}
}
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QCOMPARE(listview->count(), newCount);
QCOMPARE(listview->count(), model.count());
@@ -1658,7 +1652,7 @@ void tst_QQuickListView::multipleChanges(bool condensed)
QQuickText *number;
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i=0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
@@ -1846,6 +1840,8 @@ void tst_QQuickListView::multipleChanges_data()
void tst_QQuickListView::swapWithFirstItem()
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
QaimModel model;
@@ -1855,7 +1851,6 @@ void tst_QQuickListView::swapWithFirstItem()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(testFileUrl("listviewtest.qml"));
@@ -1864,7 +1859,7 @@ void tst_QQuickListView::swapWithFirstItem()
QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
QTRY_VERIFY(listview != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// ensure content position is stable
listview->setContentY(0);
@@ -1874,6 +1869,8 @@ void tst_QQuickListView::swapWithFirstItem()
void tst_QQuickListView::checkCountForMultiColumnModels()
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
// Check that a list view will only load items for the first
// column, even if the model reports that it got several columns.
// We test this since QQmlDelegateModel has been changed to
@@ -1891,7 +1888,6 @@ void tst_QQuickListView::checkCountForMultiColumnModels()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(testFileUrl("listviewtest.qml"));
@@ -1925,7 +1921,7 @@ void tst_QQuickListView::enforceRange()
QTRY_COMPARE(listview->preferredHighlightBegin(), 100.0);
QTRY_COMPARE(listview->preferredHighlightEnd(), 100.0);
QTRY_COMPARE(listview->highlightRangeMode(), QQuickListView::StrictlyEnforceRange);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -2005,7 +2001,7 @@ void tst_QQuickListView::enforceRange_withoutHighlight()
QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
QTRY_VERIFY(listview != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
qreal expectedPos = -100.0;
@@ -2028,6 +2024,8 @@ void tst_QQuickListView::enforceRange_withoutHighlight()
void tst_QQuickListView::spacing()
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
QaimModel model;
@@ -2037,7 +2035,6 @@ void tst_QQuickListView::spacing()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(testFileUrl("listviewtest.qml"));
@@ -2049,10 +2046,10 @@ void tst_QQuickListView::spacing()
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -2064,7 +2061,7 @@ void tst_QQuickListView::spacing()
QTRY_COMPARE(listview->spacing(), qreal(10));
// Confirm items positioned correctly
- QTRY_VERIFY(findItems<QQuickItem>(contentItem, "wrapper").count() == 11);
+ QTRY_VERIFY(findItems<QQuickItem>(contentItem, "wrapper").size() == 11);
for (int i = 0; i < 11; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -2075,7 +2072,7 @@ void tst_QQuickListView::spacing()
listview->setSpacing(0);
// Confirm items positioned correctly
- QTRY_VERIFY(findItems<QQuickItem>(contentItem, "wrapper").count() >= 16);
+ QTRY_VERIFY(findItems<QQuickItem>(contentItem, "wrapper").size() >= 16);
for (int i = 0; i < 16; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -2106,10 +2103,10 @@ void tst_QQuickListView::sections(const QUrl &source)
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY(item);
@@ -2163,12 +2160,12 @@ void tst_QQuickListView::sections(const QUrl &source)
listview->setContentY(140);
QTRY_COMPARE(listview->currentSection(), QString("1"));
- QTRY_COMPARE(currentSectionChangedSpy.count(), 1);
+ QTRY_COMPARE(currentSectionChangedSpy.size(), 1);
listview->setContentY(20);
QTRY_COMPARE(listview->currentSection(), QString("0"));
- QTRY_COMPARE(currentSectionChangedSpy.count(), 2);
+ QTRY_COMPARE(currentSectionChangedSpy.size(), 2);
item = findItem<QQuickItem>(contentItem, "wrapper", 1);
QTRY_VERIFY(item);
@@ -2176,9 +2173,9 @@ void tst_QQuickListView::sections(const QUrl &source)
// check that headers change when item changes
listview->setContentY(0);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
model.modifyItem(0, "changed", "2");
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
item = findItem<QQuickItem>(contentItem, "wrapper", 1);
QTRY_VERIFY(item);
@@ -2215,10 +2212,10 @@ void tst_QQuickListView::sectionsDelegate()
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QTRY_VERIFY(item);
@@ -2239,7 +2236,7 @@ void tst_QQuickListView::sectionsDelegate()
model.modifyItem(2, "Three", "aaa");
model.modifyItem(3, "Four", "aaa");
model.modifyItem(4, "Five", "aaa");
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
for (int i = 0; i < 3; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem,
@@ -2260,7 +2257,7 @@ void tst_QQuickListView::sectionsDelegate()
// QTBUG-17606
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "sect_1");
- QCOMPARE(items.count(), 1);
+ QCOMPARE(items.size(), 1);
// QTBUG-17759
model.modifyItem(0, "One", "aaa");
@@ -2275,11 +2272,11 @@ void tst_QQuickListView::sectionsDelegate()
model.modifyItem(9, "Two", "aaa");
model.modifyItem(10, "Two", "aaa");
model.modifyItem(11, "Two", "aaa");
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "sect_aaa").count(), 1);
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "sect_aaa").size(), 1);
window->rootObject()->setProperty("sectionProperty", "name");
// ensure view has settled.
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "sect_Four").count(), 1);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "sect_Four").size(), 1);
for (int i = 0; i < 4; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem,
"sect_" + model.name(i*3));
@@ -2305,7 +2302,7 @@ void tst_QQuickListView::sectionsDragOutsideBounds()
QFETCH(int, cacheBuffer);
QQuickView *window = getView();
- QQuickViewTestUtil::moveMouseAway(window);
+ QQuickViewTestUtils::moveMouseAway(window);
QaimModel model;
for (int i = 0; i < 10; i++)
@@ -2325,7 +2322,7 @@ void tst_QQuickListView::sectionsDragOutsideBounds()
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// QTBUG-17769
// Drag view up beyond bounds
@@ -2340,8 +2337,15 @@ void tst_QQuickListView::sectionsDragOutsideBounds()
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(20,0));
QTest::mouseMove(window, QPoint(20,20));
QTest::mouseMove(window, QPoint(20,70));
+ // This should also apply to the negative coordinates above, but: QTBUG-104046.
+ static const QRegularExpression warningRegex("Mouse event at \\d+, \\d+ occurs outside target window \\(\\d+x\\d+\\).*");
+ QVERIFY(warningRegex.isValid());
+ if (distance >= window->size().height())
+ QTest::ignoreMessage(QtWarningMsg, warningRegex);
QTest::mouseMove(window, QPoint(20,distance));
+ if (distance >= window->size().height())
+ QTest::ignoreMessage(QtWarningMsg, warningRegex);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(20,distance));
// view should settle back at 0
QTRY_COMPARE(listview->contentY(), 0.0);
@@ -2371,11 +2375,11 @@ void tst_QQuickListView::sectionsDelegate_headerVisibility()
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// ensure section header is maintained in view
listview->setCurrentIndex(20);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_VERIFY(qFuzzyCompare(listview->contentY(), 200.0));
QTRY_VERIFY(!listview->isMoving());
listview->setCurrentIndex(0);
@@ -2402,7 +2406,7 @@ void tst_QQuickListView::sectionsPositioning()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
for (int i = 0; i < 3; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "sect_" + QString::number(i));
@@ -2420,12 +2424,12 @@ void tst_QQuickListView::sectionsPositioning()
// move down a little and check that section header is at top
listview->setContentY(10);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QCOMPARE(topItem->y(), 0.);
// push the top header up
listview->setContentY(110);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
topItem = findVisibleChild(contentItem, "sect_0"); // section header
QVERIFY(topItem);
QCOMPARE(topItem->y(), 100.);
@@ -2440,13 +2444,13 @@ void tst_QQuickListView::sectionsPositioning()
// Move past section 0
listview->setContentY(120);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
topItem = findVisibleChild(contentItem, "sect_0"); // section header
QVERIFY(!topItem);
// Push section footer down
listview->setContentY(70);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
bottomItem = findVisibleChild(contentItem, "sect_4"); // section footer
QVERIFY(bottomItem);
QCOMPARE(bottomItem->y(), 380.);
@@ -2458,7 +2462,7 @@ void tst_QQuickListView::sectionsPositioning()
model.modifyItem(2, "Three", "aAa");
model.modifyItem(3, "Four", "aaA");
model.modifyItem(4, "Five", "Aaa");
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_COMPARE(listview->currentSection(), QString("aaa"));
@@ -2474,7 +2478,7 @@ void tst_QQuickListView::sectionsPositioning()
// remove section boundary
listview->setContentY(120);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
model.removeItem(5);
listview->forceLayout();
QTRY_COMPARE(listview->count(), model.count());
@@ -2491,27 +2495,27 @@ void tst_QQuickListView::sectionsPositioning()
// Change the next section
listview->setContentY(0);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
bottomItem = findVisibleChild(contentItem, "sect_3"); // section footer
QVERIFY(bottomItem);
QTRY_COMPARE(bottomItem->y(), 300.);
model.modifyItem(14, "New", "new");
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_VERIFY(bottomItem = findVisibleChild(contentItem, "sect_new")); // section footer
QTRY_COMPARE(bottomItem->y(), 300.);
// delegate size increase should push section footer down
listview->setContentY(70);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_VERIFY(bottomItem = findVisibleChild(contentItem, "sect_3")); // section footer
QTRY_COMPARE(bottomItem->y(), 370.);
QQuickItem *inlineSection = findVisibleChild(contentItem, "sect_new");
item = findItem<QQuickItem>(contentItem, "wrapper", 13);
QVERIFY(item);
item->setHeight(40.);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_COMPARE(bottomItem->y(), 380.);
QCOMPARE(inlineSection->y(), 360.);
item->setHeight(20.);
@@ -2519,14 +2523,14 @@ void tst_QQuickListView::sectionsPositioning()
// Turn sticky footer off
listview->setContentY(20);
window->rootObject()->setProperty("sectionPositioning", QVariant(int(QQuickViewSection::InlineLabels | QQuickViewSection::CurrentLabelAtStart)));
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_VERIFY(item = findVisibleChild(contentItem, "sect_new")); // inline label restored
QCOMPARE(item->y(), 340.);
// Turn sticky header off
listview->setContentY(30);
window->rootObject()->setProperty("sectionPositioning", QVariant(int(QQuickViewSection::InlineLabels)));
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_VERIFY(item = findVisibleChild(contentItem, "sect_aaa")); // inline label restored
QCOMPARE(item->y(), 0.);
@@ -2562,7 +2566,7 @@ void tst_QQuickListView::sectionPropertyChange()
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Confirm items positioned correctly
for (int i = 0; i < 2; ++i) {
@@ -2572,7 +2576,7 @@ void tst_QQuickListView::sectionPropertyChange()
}
QMetaObject::invokeMethod(window->rootObject(), "switchGroups");
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Confirm items positioned correctly
for (int i = 0; i < 2; ++i) {
@@ -2582,7 +2586,7 @@ void tst_QQuickListView::sectionPropertyChange()
}
QMetaObject::invokeMethod(window->rootObject(), "switchGroups");
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Confirm items positioned correctly
for (int i = 0; i < 2; ++i) {
@@ -2592,7 +2596,7 @@ void tst_QQuickListView::sectionPropertyChange()
}
QMetaObject::invokeMethod(window->rootObject(), "switchGrouped");
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Confirm items positioned correctly
for (int i = 0; i < 2; ++i) {
@@ -2602,7 +2606,7 @@ void tst_QQuickListView::sectionPropertyChange()
}
QMetaObject::invokeMethod(window->rootObject(), "switchGrouped");
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Confirm items positioned correctly
for (int i = 0; i < 2; ++i) {
@@ -2626,10 +2630,10 @@ void tst_QQuickListView::sectionDelegateChange()
QQuickItem *contentItem = listview->contentItem();
QVERIFY(contentItem != nullptr);
- QQuickTest::qWaitForItemPolished(listview);
+ QQuickTest::qWaitForPolish(listview);
- QVERIFY(findItems<QQuickItem>(contentItem, "section1").count() > 0);
- QCOMPARE(findItems<QQuickItem>(contentItem, "section2").count(), 0);
+ QVERIFY(findItems<QQuickItem>(contentItem, "section1").size() > 0);
+ QCOMPARE(findItems<QQuickItem>(contentItem, "section2").size(), 0);
for (int i = 0; i < 3; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "item", i);
@@ -2638,10 +2642,10 @@ void tst_QQuickListView::sectionDelegateChange()
}
QMetaObject::invokeMethod(window->rootObject(), "switchDelegates");
- QQuickTest::qWaitForItemPolished(listview);
+ QQuickTest::qWaitForPolish(listview);
- QCOMPARE(findItems<QQuickItem>(contentItem, "section1").count(), 0);
- QVERIFY(findItems<QQuickItem>(contentItem, "section2").count() > 0);
+ QCOMPARE(findItems<QQuickItem>(contentItem, "section1").size(), 0);
+ QVERIFY(findItems<QQuickItem>(contentItem, "section2").size() > 0);
for (int i = 0; i < 3; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "item", i);
@@ -2670,7 +2674,7 @@ void tst_QQuickListView::sectionsItemInsertion()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
for (int i = 0; i < 3; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "sect_" + QString::number(i));
@@ -2686,9 +2690,9 @@ void tst_QQuickListView::sectionsItemInsertion()
for (int i = 0; i < 10; i++)
model.insertItem(i, "Item" + QString::number(i), QLatin1String("A"));
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
QVERIFY(itemCount > 10);
// Verify that the new items are postioned correctly, and have the correct attached section properties
@@ -2736,7 +2740,7 @@ void tst_QQuickListView::sectionsSnap()
QTRY_VERIFY(listview != nullptr);
listview->setSnapMode(snapMode);
- QTRY_COMPARE(QQuickItemPrivate::get(listview)->polishScheduled, false);
+ QTRY_VERIFY(!QQuickItemPrivate::get(listview)->polishScheduled);
QTRY_COMPARE(listview->currentIndex(), 0);
QCOMPARE(listview->contentY(), qreal(-50));
@@ -2788,7 +2792,7 @@ void tst_QQuickListView::currentIndex_delayedItemCreation()
QSignalSpy spy(listview, SIGNAL(currentItemChanged()));
//QCOMPARE(listview->currentIndex(), 0);
listview->forceLayout();
- QTRY_COMPARE(spy.count(), 1);
+ QTRY_COMPARE(spy.size(), 1);
releaseView(window);
}
@@ -2824,7 +2828,7 @@ void tst_QQuickListView::currentIndex()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// currentIndex is initialized to 20
// currentItem should be in view
@@ -2894,9 +2898,9 @@ void tst_QQuickListView::currentIndex()
// moving currentItem out of view should make it invisible
listview->setCurrentIndex(0);
- QTRY_VERIFY(delegateVisible(listview->currentItem()));
+ QTRY_VERIFY(isDelegateVisible(listview->currentItem()));
listview->setContentY(200);
- QTRY_VERIFY(!delegateVisible(listview->currentItem()));
+ QTRY_VERIFY(!isDelegateVisible(listview->currentItem()));
// empty model should reset currentIndex to -1
QaimModel emptyModel;
@@ -2929,7 +2933,7 @@ void tst_QQuickListView::noCurrentIndex()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// current index should be -1 at startup
// and we should not have a currentItem or highlightItem
@@ -2958,8 +2962,8 @@ void tst_QQuickListView::keyNavigation()
for (int i = 0; i < 30; i++)
model.addItem("Item" + QString::number(i), "");
- QQuickView *window = getView();
QScopedPointer<TestObject> testObject(new TestObject);
+ QQuickView *window = getView();
window->rootContext()->setContextProperty("testModel", &model);
window->rootContext()->setContextProperty("testObject", testObject.data());
window->setSource(testFileUrl("listviewtest.qml"));
@@ -2972,7 +2976,7 @@ void tst_QQuickListView::keyNavigation()
listview->setOrientation(orientation);
listview->setLayoutDirection(layoutDirection);
listview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
window->requestActivate();
QVERIFY(QTest::qWaitForWindowActive(window));
@@ -3128,41 +3132,43 @@ void tst_QQuickListView::itemListFlicker()
QQuickItem *item = findItem<QQuickItem>(contentItem, "item1");
QVERIFY(item);
- QVERIFY(delegateVisible(item));
+ QVERIFY(isDelegateVisible(item));
item = findItem<QQuickItem>(contentItem, "item2");
QVERIFY(item);
- QVERIFY(delegateVisible(item));
+ QVERIFY(isDelegateVisible(item));
item = findItem<QQuickItem>(contentItem, "item3");
QVERIFY(item);
- QVERIFY(delegateVisible(item));
+ QVERIFY(isDelegateVisible(item));
listview->setCurrentIndex(1);
item = findItem<QQuickItem>(contentItem, "item1");
QVERIFY(item);
- QVERIFY(delegateVisible(item));
+ QVERIFY(isDelegateVisible(item));
item = findItem<QQuickItem>(contentItem, "item2");
QVERIFY(item);
- QVERIFY(delegateVisible(item));
+ QVERIFY(isDelegateVisible(item));
item = findItem<QQuickItem>(contentItem, "item3");
QVERIFY(item);
- QVERIFY(delegateVisible(item));
+ QVERIFY(isDelegateVisible(item));
listview->setCurrentIndex(2);
item = findItem<QQuickItem>(contentItem, "item1");
QVERIFY(item);
- QVERIFY(delegateVisible(item));
+ QVERIFY(isDelegateVisible(item));
item = findItem<QQuickItem>(contentItem, "item2");
QVERIFY(item);
- QVERIFY(delegateVisible(item));
+ QVERIFY(isDelegateVisible(item));
item = findItem<QQuickItem>(contentItem, "item3");
QVERIFY(item);
- QVERIFY(delegateVisible(item));
+ QVERIFY(isDelegateVisible(item));
}
void tst_QQuickListView::cacheBuffer()
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
QaimModel model;
@@ -3172,7 +3178,6 @@ void tst_QQuickListView::cacheBuffer()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(testFileUrl("listviewtest.qml"));
@@ -3189,7 +3194,7 @@ void tst_QQuickListView::cacheBuffer()
QTRY_VERIFY(listview->highlight() != nullptr);
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -3220,7 +3225,7 @@ void tst_QQuickListView::cacheBuffer()
}
int newItemCount = 0;
- newItemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ newItemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
// Confirm items positioned correctly
for (int i = 0; i < model.count() && i < newItemCount; ++i) {
@@ -3258,13 +3263,16 @@ void tst_QQuickListView::cacheBuffer()
controller.incubateWhile(&b);
}
- // negative cache buffer is ignored
+ // it should warn when setting a negative cache buffer
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*Cannot set a negative cache buffer"));
listview->setCacheBuffer(-1);
QCOMPARE(listview->cacheBuffer(), 200);
}
void tst_QQuickListView::positionViewAtBeginningEnd()
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
QaimModel model;
@@ -3274,7 +3282,6 @@ void tst_QQuickListView::positionViewAtBeginningEnd()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->show();
window->setSource(testFileUrl("listviewtest.qml"));
@@ -3284,7 +3291,7 @@ void tst_QQuickListView::positionViewAtBeginningEnd()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
listview->setContentY(100);
@@ -3323,6 +3330,8 @@ void tst_QQuickListView::positionViewAtIndex()
QFETCH(QQuickListView::PositionMode, mode);
QFETCH(qreal, contentY);
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QQuickView *window = getView();
QaimModel model;
@@ -3332,7 +3341,6 @@ void tst_QQuickListView::positionViewAtIndex()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->show();
window->setSource(testFileUrl("listviewtest.qml"));
@@ -3342,10 +3350,10 @@ void tst_QQuickListView::positionViewAtIndex()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
window->rootObject()->setProperty("enforceRange", enforceRange);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
listview->setContentY(initContentY);
@@ -3353,7 +3361,7 @@ void tst_QQuickListView::positionViewAtIndex()
QTRY_COMPARE(listview->contentY(), contentY);
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = index; i < model.count() && i < itemCount-index-1; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -3422,7 +3430,7 @@ void tst_QQuickListView::resetModel()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_COMPARE(listview->count(), model.rowCount());
@@ -3486,13 +3494,13 @@ void tst_QQuickListView::propertyChanges()
QTRY_COMPARE(listView->cacheBuffer(), 3);
QTRY_COMPARE(listView->snapMode(), QQuickListView::SnapOneItem);
- QTRY_COMPARE(highlightFollowsCurrentItemSpy.count(),1);
- QTRY_COMPARE(preferredHighlightBeginSpy.count(),1);
- QTRY_COMPARE(preferredHighlightEndSpy.count(),1);
- QTRY_COMPARE(highlightRangeModeSpy.count(),1);
- QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
- QTRY_COMPARE(cacheBufferSpy.count(),1);
- QTRY_COMPARE(snapModeSpy.count(),1);
+ QTRY_COMPARE(highlightFollowsCurrentItemSpy.size(),1);
+ QTRY_COMPARE(preferredHighlightBeginSpy.size(),1);
+ QTRY_COMPARE(preferredHighlightEndSpy.size(),1);
+ QTRY_COMPARE(highlightRangeModeSpy.size(),1);
+ QTRY_COMPARE(keyNavigationWrapsSpy.size(),1);
+ QTRY_COMPARE(cacheBufferSpy.size(),1);
+ QTRY_COMPARE(snapModeSpy.size(),1);
listView->setHighlightFollowsCurrentItem(false);
listView->setPreferredHighlightBegin(1.0);
@@ -3502,13 +3510,13 @@ void tst_QQuickListView::propertyChanges()
listView->setCacheBuffer(3);
listView->setSnapMode(QQuickListView::SnapOneItem);
- QTRY_COMPARE(highlightFollowsCurrentItemSpy.count(),1);
- QTRY_COMPARE(preferredHighlightBeginSpy.count(),1);
- QTRY_COMPARE(preferredHighlightEndSpy.count(),1);
- QTRY_COMPARE(highlightRangeModeSpy.count(),1);
- QTRY_COMPARE(keyNavigationWrapsSpy.count(),1);
- QTRY_COMPARE(cacheBufferSpy.count(),1);
- QTRY_COMPARE(snapModeSpy.count(),1);
+ QTRY_COMPARE(highlightFollowsCurrentItemSpy.size(),1);
+ QTRY_COMPARE(preferredHighlightBeginSpy.size(),1);
+ QTRY_COMPARE(preferredHighlightEndSpy.size(),1);
+ QTRY_COMPARE(highlightRangeModeSpy.size(),1);
+ QTRY_COMPARE(keyNavigationWrapsSpy.size(),1);
+ QTRY_COMPARE(cacheBufferSpy.size(),1);
+ QTRY_COMPARE(snapModeSpy.size(),1);
}
void tst_QQuickListView::componentChanges()
@@ -3540,20 +3548,20 @@ void tst_QQuickListView::componentChanges()
QTRY_COMPARE(listView->footer(), &component);
QTRY_COMPARE(listView->delegate(), &delegateComponent);
- QTRY_COMPARE(highlightSpy.count(),1);
- QTRY_COMPARE(delegateSpy.count(),1);
- QTRY_COMPARE(headerSpy.count(),1);
- QTRY_COMPARE(footerSpy.count(),1);
+ QTRY_COMPARE(highlightSpy.size(),1);
+ QTRY_COMPARE(delegateSpy.size(),1);
+ QTRY_COMPARE(headerSpy.size(),1);
+ QTRY_COMPARE(footerSpy.size(),1);
listView->setHighlight(&component);
listView->setHeader(&component);
listView->setFooter(&component);
listView->setDelegate(&delegateComponent);
- QTRY_COMPARE(highlightSpy.count(),1);
- QTRY_COMPARE(delegateSpy.count(),1);
- QTRY_COMPARE(headerSpy.count(),1);
- QTRY_COMPARE(footerSpy.count(),1);
+ QTRY_COMPARE(highlightSpy.size(),1);
+ QTRY_COMPARE(delegateSpy.size(),1);
+ QTRY_COMPARE(headerSpy.size(),1);
+ QTRY_COMPARE(footerSpy.size(),1);
}
void tst_QQuickListView::modelChanges()
@@ -3571,13 +3579,13 @@ void tst_QQuickListView::modelChanges()
listView->setModel(modelVariant);
QTRY_COMPARE(listView->model(), modelVariant);
- QTRY_COMPARE(modelSpy.count(),1);
+ QTRY_COMPARE(modelSpy.size(),1);
listView->setModel(modelVariant);
- QTRY_COMPARE(modelSpy.count(),1);
+ QTRY_COMPARE(modelSpy.size(),1);
listView->setModel(QVariant());
- QTRY_COMPARE(modelSpy.count(),2);
+ QTRY_COMPARE(modelSpy.size(),2);
}
void tst_QQuickListView::QTBUG_9791()
@@ -3599,7 +3607,7 @@ void tst_QQuickListView::QTBUG_9791()
qApp->processEvents();
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).size();
QCOMPARE(itemCount, 3);
for (int i = 0; i < itemCount; ++i) {
@@ -3628,12 +3636,12 @@ void tst_QQuickListView::QTBUG_33568()
listview->incrementCurrentIndex();
QTRY_COMPARE(listview->contentY(), -100.0);
- QVERIFY(spy.count() > 1);
+ QVERIFY(spy.size() > 1);
spy.clear();
listview->incrementCurrentIndex();
QTRY_COMPARE(listview->contentY(), -50.0);
- QVERIFY(spy.count() > 1);
+ QVERIFY(spy.size() > 1);
}
void tst_QQuickListView::manualHighlight()
@@ -3672,6 +3680,8 @@ void tst_QQuickListView::manualHighlight()
void tst_QQuickListView::QTBUG_11105()
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
QaimModel model;
for (int i = 0; i < 30; i++)
@@ -3680,7 +3690,6 @@ void tst_QQuickListView::QTBUG_11105()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(testFileUrl("listviewtest.qml"));
@@ -3691,10 +3700,10 @@ void tst_QQuickListView::QTBUG_11105()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -3711,7 +3720,7 @@ void tst_QQuickListView::QTBUG_11105()
ctxt->setContextProperty("testModel", &model2);
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
QCOMPARE(itemCount, 5);
}
@@ -3781,7 +3790,7 @@ void tst_QQuickListView::header()
listview->setOrientation(orientation);
listview->setLayoutDirection(layoutDirection);
listview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -3819,7 +3828,7 @@ void tst_QQuickListView::header()
QSignalSpy headerItemSpy(listview, SIGNAL(headerItemChanged()));
QMetaObject::invokeMethod(window->rootObject(), "changeHeader");
- QCOMPARE(headerItemSpy.count(), 1);
+ QCOMPARE(headerItemSpy.size(), 1);
header = findItem<QQuickText>(contentItem, "header");
QVERIFY(!header);
@@ -3860,7 +3869,7 @@ void tst_QQuickListView::header()
listview->setOrientation(orientation);
listview->setLayoutDirection(layoutDirection);
listview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
listview->setWidth(240);
listview->setHeight(320);
@@ -3967,7 +3976,7 @@ void tst_QQuickListView::headerChangesViewport()
QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
QTRY_VERIFY(listview != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -4017,7 +4026,7 @@ void tst_QQuickListView::footer()
listview->setOrientation(orientation);
listview->setLayoutDirection(layoutDirection);
listview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -4078,7 +4087,7 @@ void tst_QQuickListView::footer()
QSignalSpy footerItemSpy(listview, SIGNAL(footerItemChanged()));
QMetaObject::invokeMethod(window->rootObject(), "changeFooter");
- QCOMPARE(footerItemSpy.count(), 1);
+ QCOMPARE(footerItemSpy.size(), 1);
footer = findItem<QQuickText>(contentItem, "footer");
QVERIFY(!footer);
@@ -4221,7 +4230,7 @@ void tst_QQuickListView::extents()
listview->setOrientation(orientation);
listview->setLayoutDirection(layoutDirection);
listview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -4277,26 +4286,24 @@ void tst_QQuickListView::extents_data()
QTest::newRow("Vertical, TopToBottom")
<< QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom
- << QPointF(0, -20) << QPointF(0, 0)
- << QPointF(0, 20) << QPointF(240, 20)
+ << QPointF(0, -20) << QPointF(0, 0) << QPointF(0, 20) << QPointF(0, 20)
<< QPointF(0, -20) << QPointF(0, -20) << QPointF(0, -20);
QTest::newRow("Vertical, BottomToTop")
<< QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop
- << QPointF(0, 0) << QPointF(0, -30)
- << QPointF(0, 320 - 20) << QPointF(240, 320 - 20) // content flow is reversed
+ << QPointF(0, 0) << QPointF(0, -30) << QPointF(0, 320 - 20)
+ << QPointF(0, 320 - 20) // content flow is reversed
<< QPointF(0, -30) << QPointF(0, (-30.0 * 3) - 30) << QPointF(0, (-30.0 * 30) - 30);
QTest::newRow("Horizontal, LeftToRight")
<< QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom
- << QPointF(-20, 0) << QPointF(0, 0)
- << QPointF(20, 0) << QPointF(20, 320)
+ << QPointF(-20, 0) << QPointF(0, 0) << QPointF(20, 0) << QPointF(20, 0)
<< QPointF(-20, 0) << QPointF(-20, 0) << QPointF(-20, 0);
QTest::newRow("Horizontal, RightToLeft")
<< QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom
- << QPointF(0, 0) << QPointF(-30, 0)
- << QPointF(240 - 20, 0) << QPointF(240 - 20, 320) // content flow is reversed
+ << QPointF(0, 0) << QPointF(-30, 0) << QPointF(240 - 20, 0)
+ << QPointF(240 - 20, 0) // content flow is reversed
<< QPointF(-30, 0) << QPointF((-240.0 * 3) - 30, 0) << QPointF((-240.0 * 30) - 30, 0);
}
@@ -4342,6 +4349,8 @@ void tst_QQuickListView::resetModel_headerFooter()
void tst_QQuickListView::resizeView()
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
QaimModel model;
for (int i = 0; i < 40; i++)
@@ -4350,7 +4359,6 @@ void tst_QQuickListView::resizeView()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(testFileUrl("listviewtest.qml"));
@@ -4361,10 +4369,10 @@ void tst_QQuickListView::resizeView()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -4377,42 +4385,42 @@ void tst_QQuickListView::resizeView()
QCOMPARE(heightRatio.toReal(), 0.4);
listview->setHeight(200);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QMetaObject::invokeMethod(window->rootObject(), "heightRatio", Q_RETURN_ARG(QVariant, heightRatio));
QCOMPARE(heightRatio.toReal(), 0.25);
// Ensure we handle -ve sizes
listview->setHeight(-100);
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 1);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).size(), 1);
listview->setCacheBuffer(200);
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 11);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).size(), 11);
// ensure items in cache become visible
listview->setHeight(200);
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 21);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).size(), 21);
- itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
QTRY_VERIFY(item);
QTRY_COMPARE(item->y(), i*20.);
- QCOMPARE(delegateVisible(item), i < 11); // inside view visible, outside not visible
+ QCOMPARE(isDelegateVisible(item), i < 11); // inside view visible, outside not visible
}
// ensure items outside view become invisible
listview->setHeight(100);
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).count(), 16);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper", false).size(), 16);
- itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper", false).size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
QTRY_VERIFY(item);
QTRY_COMPARE(item->y(), i*20.);
- QCOMPARE(delegateVisible(item), i < 6); // inside view visible, outside not visible
+ QCOMPARE(isDelegateVisible(item), i < 6); // inside view visible, outside not visible
}
}
@@ -4436,7 +4444,7 @@ void tst_QQuickListView::resizeViewAndRepaint()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// item at index 10 should not be currently visible
QVERIFY(!findItem<QQuickItem>(contentItem, "wrapper", 10));
@@ -4451,6 +4459,8 @@ void tst_QQuickListView::resizeViewAndRepaint()
void tst_QQuickListView::sizeLessThan1()
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
QaimModel model;
@@ -4460,7 +4470,6 @@ void tst_QQuickListView::sizeLessThan1()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(testFileUrl("sizelessthan1.qml"));
@@ -4471,10 +4480,10 @@ void tst_QQuickListView::sizeLessThan1()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Confirm items positioned correctly
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i = 0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -4521,13 +4530,13 @@ void tst_QQuickListView::resizeDelegate()
QVERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QCOMPARE(listview->count(), model.rowCount());
listview->setCurrentIndex(25);
listview->setContentY(0);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
for (int i = 0; i < 16; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
@@ -4539,7 +4548,7 @@ void tst_QQuickListView::resizeDelegate()
QTRY_COMPARE(listview->highlightItem()->y(), 500.0);
window->rootObject()->setProperty("delegateHeight", 30);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
for (int i = 0; i < 11; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
@@ -4553,7 +4562,7 @@ void tst_QQuickListView::resizeDelegate()
listview->setCurrentIndex(1);
listview->positionViewAtIndex(25, QQuickListView::Beginning);
listview->positionViewAtIndex(5, QQuickListView::Beginning);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
for (int i = 5; i < 16; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
@@ -4565,7 +4574,7 @@ void tst_QQuickListView::resizeDelegate()
QTRY_COMPARE(listview->highlightItem()->y(), 30.0);
window->rootObject()->setProperty("delegateHeight", 20);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
for (int i = 5; i < 11; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
@@ -4581,6 +4590,8 @@ void tst_QQuickListView::resizeFirstDelegate()
{
// QTBUG-20712: Content Y jumps constantly if first delegate height == 0
// and other delegates have height > 0
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QScopedPointer<QQuickView> window(createView());
// bug only occurs when all items in the model are visible
@@ -4591,7 +4602,6 @@ void tst_QQuickListView::resizeFirstDelegate()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(testFileUrl("listviewtest.qml"));
@@ -4602,7 +4612,7 @@ void tst_QQuickListView::resizeFirstDelegate()
QVERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQuickItem *item = nullptr;
for (int i = 0; i < model.count(); ++i) {
@@ -4618,7 +4628,7 @@ void tst_QQuickListView::resizeFirstDelegate()
QCOMPARE(listview->contentY(), 0.0);
QSignalSpy spy(listview, SIGNAL(contentYChanged()));
QTest::qWait(100);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
for (int i = 1; i < model.count(); ++i) {
item = findItem<QQuickItem>(contentItem, "wrapper", i);
@@ -4641,7 +4651,7 @@ void tst_QQuickListView::resizeFirstDelegate()
listview->setCurrentIndex(19);
qApp->processEvents();
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// items 0-2 should have been deleted
for (int i=0; i<3; i++) {
@@ -4670,7 +4680,7 @@ void tst_QQuickListView::repositionResizedDelegate()
QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject());
QTRY_VERIFY(listview != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQuickItem *positioner = findItem<QQuickItem>(window->rootObject(), "positioner");
QVERIFY(positioner);
@@ -4685,14 +4695,14 @@ void tst_QQuickListView::repositionResizedDelegate()
listview->setContentX(contentPos_itemFirstHalfVisible.x());
listview->setContentY(contentPos_itemFirstHalfVisible.y());
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
- prevSpyCount = spy.count();
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+ prevSpyCount = spy.size();
QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "incrementRepeater"));
QTRY_COMPARE(positioner->boundingRect().size(), resizedPositionerRect.size());
QTRY_COMPARE(positioner->position(), resizedPositionerRect.topLeft());
QCOMPARE(listview->contentX(), contentPos_itemFirstHalfVisible.x());
QCOMPARE(listview->contentY(), contentPos_itemFirstHalfVisible.y());
- QCOMPARE(spy.count(), prevSpyCount);
+ QCOMPARE(spy.size(), prevSpyCount);
QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "decrementRepeater"));
QTRY_COMPARE(positioner->boundingRect().size(), origPositionerRect.size());
@@ -4702,8 +4712,8 @@ void tst_QQuickListView::repositionResizedDelegate()
listview->setContentX(contentPos_itemSecondHalfVisible.x());
listview->setContentY(contentPos_itemSecondHalfVisible.y());
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
- prevSpyCount = spy.count();
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+ prevSpyCount = spy.size();
QVERIFY(QMetaObject::invokeMethod(window->rootObject(), "incrementRepeater"));
positioner = findItem<QQuickItem>(window->rootObject(), "positioner");
@@ -4712,7 +4722,7 @@ void tst_QQuickListView::repositionResizedDelegate()
QCOMPARE(listview->contentX(), contentPos_itemSecondHalfVisible.x());
QCOMPARE(listview->contentY(), contentPos_itemSecondHalfVisible.y());
qApp->processEvents();
- QCOMPARE(spy.count(), prevSpyCount);
+ QCOMPARE(spy.size(), prevSpyCount);
releaseView(window);
}
@@ -4789,6 +4799,8 @@ void tst_QQuickListView::indexAt_itemAt()
QFETCH(qreal, y);
QFETCH(int, index);
+ QScopedPointer<TestObject> testObject(new TestObject);
+
QQuickView *window = getView();
QaimModel model;
@@ -4798,7 +4810,6 @@ void tst_QQuickListView::indexAt_itemAt()
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testModel", &model);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(testFileUrl("listviewtest.qml"));
@@ -4810,7 +4821,7 @@ void tst_QQuickListView::indexAt_itemAt()
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQuickItem *item = nullptr;
if (index >= 0) {
@@ -4901,8 +4912,8 @@ void tst_QQuickListView::onAdd()
QTRY_COMPARE(listview->property("count").toInt(), model.count());
QVariantList result = listview->property("addedDelegates").toList();
- QCOMPARE(result.count(), items.count());
- for (int i=0; i<items.count(); i++)
+ QCOMPARE(result.size(), items.size());
+ for (int i=0; i<items.size(); i++)
QCOMPARE(result[i].toString(), items[i].first);
}
@@ -4990,7 +5001,7 @@ void tst_QQuickListView::rightToLeft()
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQmlObjectModel *model = window->rootObject()->findChild<QQmlObjectModel*>("itemModel");
QTRY_VERIFY(model != nullptr);
@@ -5048,14 +5059,14 @@ void tst_QQuickListView::test_mirroring()
QCOMPARE(listviewA->layoutDirection(), listviewA->effectiveLayoutDirection());
// LTR != RTL
- foreach (const QString objectName, objectNames)
+ for (const QString &objectName : std::as_const(objectNames))
QVERIFY(findItem<QQuickItem>(listviewA, objectName)->x() != findItem<QQuickItem>(listviewB, objectName)->x());
listviewA->setProperty("layoutDirection", Qt::LeftToRight);
listviewB->setProperty("layoutDirection", Qt::LeftToRight);
// LTR == LTR
- foreach (const QString objectName, objectNames)
+ for (const QString &objectName : std::as_const(objectNames))
QCOMPARE(findItem<QQuickItem>(listviewA, objectName)->x(), findItem<QQuickItem>(listviewB, objectName)->x());
QCOMPARE(listviewB->layoutDirection(), listviewB->effectiveLayoutDirection());
@@ -5063,25 +5074,25 @@ void tst_QQuickListView::test_mirroring()
QVERIFY(listviewB->layoutDirection() != listviewB->effectiveLayoutDirection());
// LTR != LTR+mirror
- foreach (const QString objectName, objectNames)
+ for (const QString &objectName : std::as_const(objectNames))
QVERIFY(findItem<QQuickItem>(listviewA, objectName)->x() != findItem<QQuickItem>(listviewB, objectName)->x());
listviewA->setProperty("layoutDirection", Qt::RightToLeft);
// RTL == LTR+mirror
- foreach (const QString objectName, objectNames)
+ for (const QString &objectName : std::as_const(objectNames))
QCOMPARE(findItem<QQuickItem>(listviewA, objectName)->x(), findItem<QQuickItem>(listviewB, objectName)->x());
listviewB->setProperty("layoutDirection", Qt::RightToLeft);
// RTL != RTL+mirror
- foreach (const QString objectName, objectNames)
+ for (const QString &objectName : std::as_const(objectNames))
QVERIFY(findItem<QQuickItem>(listviewA, objectName)->x() != findItem<QQuickItem>(listviewB, objectName)->x());
listviewA->setProperty("layoutDirection", Qt::LeftToRight);
// LTR == RTL+mirror
- foreach (const QString objectName, objectNames)
+ for (const QString &objectName : std::as_const(objectNames))
QCOMPARE(findItem<QQuickItem>(listviewA, objectName)->x(), findItem<QQuickItem>(listviewB, objectName)->x());
}
@@ -5103,7 +5114,7 @@ void tst_QQuickListView::margins()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QCOMPARE(listview->contentY(), -30.);
QCOMPARE(listview->originY(), 0.);
@@ -5112,7 +5123,7 @@ void tst_QQuickListView::margins()
listview->positionViewAtEnd();
qreal pos = listview->contentY();
listview->setContentY(pos + 80);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
listview->returnToBounds();
QTRY_COMPARE(listview->contentY(), pos + 50);
@@ -5123,7 +5134,7 @@ void tst_QQuickListView::margins()
listview->forceLayout();
QTRY_COMPARE(listview->count(), model.count());
listview->setContentY(-50);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
listview->returnToBounds();
QCOMPARE(listview->originY(), 20.);
QTRY_COMPARE(listview->contentY(), -10.);
@@ -5158,15 +5169,17 @@ void tst_QQuickListView::marginsResize()
QPoint flickStart(20, 20);
QPoint flickEnd(20, 20);
+ // We use 179 instead of 180 as we want to avoid the "Mouse event occurs outside target window" warning.
+ const int flickDistance = 179;
if (orientation == QQuickListView::Vertical)
- flickStart.ry() += (verticalLayoutDirection == QQuickItemView::TopToBottom) ? 180 : -180;
+ flickStart.ry() += (verticalLayoutDirection == QQuickItemView::TopToBottom) ? flickDistance : -flickDistance;
else
- flickStart.rx() += (layoutDirection == Qt::LeftToRight) ? 180 : -180;
+ flickStart.rx() += (layoutDirection == Qt::LeftToRight) ? flickDistance : -flickDistance;
QQuickView *window = getView();
window->setSource(testFileUrl("margins2.qml"));
- QQuickViewTestUtil::moveMouseAway(window);
+ QQuickViewTestUtils::moveMouseAway(window);
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window));
@@ -5176,7 +5189,7 @@ void tst_QQuickListView::marginsResize()
listview->setOrientation(orientation);
listview->setLayoutDirection(layoutDirection);
listview->setVerticalLayoutDirection(verticalLayoutDirection);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// view is resized after componentCompleted - top margin should still be visible
if (orientation == QQuickListView::Vertical)
@@ -5192,7 +5205,7 @@ void tst_QQuickListView::marginsResize()
QTRY_COMPARE(listview->contentX(), end);
// flick past the end and check content pos still settles on correct extents
- flick(window, flickStart, flickEnd, 180);
+ flick(window, flickStart, flickEnd, flickDistance);
QTRY_VERIFY(!listview->isMoving());
if (orientation == QQuickListView::Vertical)
QTRY_COMPARE(listview->contentY(), end);
@@ -5207,7 +5220,7 @@ void tst_QQuickListView::marginsResize()
QTRY_COMPARE(listview->contentX(), start);
// flick past the beginning and check content pos still settles on correct extents
- flick(window, flickEnd, flickStart, 180);
+ flick(window, flickEnd, flickStart, flickDistance);
QTRY_VERIFY(!listview->isMoving());
if (orientation == QQuickListView::Vertical)
QTRY_COMPARE(listview->contentY(), start);
@@ -5302,7 +5315,7 @@ void tst_QQuickListView::snapToItem()
QFETCH(qreal, startExtent);
QQuickView *window = getView();
- QQuickViewTestUtil::moveMouseAway(window);
+ QQuickViewTestUtils::moveMouseAway(window);
window->setSource(testFileUrl("snapToItem.qml"));
window->show();
@@ -5316,7 +5329,7 @@ void tst_QQuickListView::snapToItem()
listview->setLayoutDirection(layoutDirection);
listview->setVerticalLayoutDirection(verticalLayoutDirection);
listview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -5368,7 +5381,7 @@ void tst_QQuickListView::snapToItemWithSpacing_QTBUG_59852()
auto *listView = qobject_cast<QQuickListView*>(window->rootObject());
QVERIFY(listView);
- QVERIFY(QQuickTest::qWaitForItemPolished(listView));
+ QVERIFY(QQuickTest::qWaitForPolish(listView));
// each item in the list is 100 pixels tall, and the spacing is 100
@@ -5467,7 +5480,7 @@ void tst_QQuickListView::headerSnapToItem()
listview->setVerticalLayoutDirection(static_cast<QQuickItemView::VerticalLayoutDirection>(layoutDirection));
listview->setHeaderPositioning(headerPositioning);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQuickItem *contentItem = listview->contentItem();
QVERIFY(contentItem != nullptr);
@@ -5986,7 +5999,7 @@ void tst_QQuickListView::snapOneItemResize_QTBUG_43555()
QScopedPointer<QQuickView> window(createView());
window->resize(QSize(100, 320));
window->setResizeMode(QQuickView::SizeRootObjectToView);
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("snapOneItemResize.qml"));
window->show();
@@ -5997,17 +6010,17 @@ void tst_QQuickListView::snapOneItemResize_QTBUG_43555()
QSignalSpy currentIndexSpy(listview, SIGNAL(currentIndexChanged()));
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_COMPARE(listview->currentIndex(), 5);
currentIndexSpy.clear();
window->resize(QSize(400, 320));
QTRY_COMPARE(int(listview->width()), 400);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_COMPARE(listview->currentIndex(), 5);
- QCOMPARE(currentIndexSpy.count(), 0);
+ QCOMPARE(currentIndexSpy.size(), 0);
}
void tst_QQuickListView::qAbstractItemModel_package_items()
@@ -6300,7 +6313,7 @@ void tst_QQuickListView::snapOneItem()
qreal flickDuration = 180 * flickSlowdown;
QQuickView *window = getView();
- QQuickViewTestUtil::moveMouseAway(window);
+ QQuickViewTestUtils::moveMouseAway(window);
window->setSource(testFileUrl("snapOneItem.qml"));
window->show();
@@ -6314,7 +6327,7 @@ void tst_QQuickListView::snapOneItem()
listview->setLayoutDirection(layoutDirection);
listview->setVerticalLayoutDirection(verticalLayoutDirection);
listview->setHighlightRangeMode(QQuickItemView::HighlightRangeMode(highlightRangeMode));
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
@@ -6331,7 +6344,7 @@ void tst_QQuickListView::snapOneItem()
if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
QCOMPARE(listview->currentIndex(), 1);
- QCOMPARE(currentIndexSpy.count(), 1);
+ QCOMPARE(currentIndexSpy.size(), 1);
}
// flick to end
@@ -6349,7 +6362,7 @@ void tst_QQuickListView::snapOneItem()
if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
QCOMPARE(listview->currentIndex(), 3);
- QCOMPARE(currentIndexSpy.count(), 3);
+ QCOMPARE(currentIndexSpy.size(), 3);
}
// flick to start
@@ -6367,7 +6380,7 @@ void tst_QQuickListView::snapOneItem()
if (QQuickItemView::HighlightRangeMode(highlightRangeMode) == QQuickItemView::StrictlyEnforceRange) {
QCOMPARE(listview->currentIndex(), 0);
- QCOMPARE(currentIndexSpy.count(), 6);
+ QCOMPARE(currentIndexSpy.size(), 6);
}
releaseView(window);
@@ -6383,17 +6396,17 @@ void tst_QQuickListView::snapOneItemCurrentIndexRemoveAnimation()
QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject());
QTRY_VERIFY(listview != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_COMPARE(listview->currentIndex(), 0);
QSignalSpy currentIndexSpy(listview, SIGNAL(currentIndexChanged()));
QMetaObject::invokeMethod(window->rootObject(), "removeItemZero");
QTRY_COMPARE(listview->property("transitionsRun").toInt(), 1);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QCOMPARE(listview->currentIndex(), 0);
- QCOMPARE(currentIndexSpy.count(), 0);
+ QCOMPARE(currentIndexSpy.size(), 0);
}
void tst_QQuickListView::snapOneItemWrongDirection()
@@ -6406,7 +6419,7 @@ void tst_QQuickListView::snapOneItemWrongDirection()
QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject());
QTRY_VERIFY(listview != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QTRY_COMPARE(listview->currentIndex(), 0);
listview->flick(0,500);
@@ -6483,30 +6496,30 @@ void tst_QQuickListView::unrequestedVisibility()
const QString wrapperObjectName = QStringLiteral("wrapper");
QQuickItem *item = findItem<QQuickItem>(leftContent, wrapperObjectName, 1);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 1);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 19);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 19);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 16);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 17);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 3);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 4);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
rightview->setCurrentIndex(0);
@@ -6515,10 +6528,10 @@ void tst_QQuickListView::unrequestedVisibility()
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 1);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 1);
QVERIFY(item);
- QTRY_COMPARE(delegateVisible(item), true);
+ QTRY_COMPARE(isDelegateVisible(item), true);
QVERIFY(!findItem<QQuickItem>(leftContent, wrapperObjectName, 19));
QVERIFY(!findItem<QQuickItem>(rightContent, wrapperObjectName, 19));
@@ -6530,123 +6543,123 @@ void tst_QQuickListView::unrequestedVisibility()
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 1);
QVERIFY(item);
- QTRY_COMPARE(delegateVisible(item), false);
+ QTRY_COMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 1);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 19);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 19);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 3);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 4);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 16);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 17);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
model.moveItems(19, 1, 1);
- QVERIFY(QQuickTest::qWaitForItemPolished(leftview));
+ QVERIFY(QQuickTest::qWaitForPolish(leftview));
QTRY_VERIFY((item = findItem<QQuickItem>(leftContent, wrapperObjectName, 1)));
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 1);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 19);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 19);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 4);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 5);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 16);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 17);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
model.moveItems(3, 4, 1);
- QVERIFY(QQuickTest::qWaitForItemPolished(leftview));
+ QVERIFY(QQuickTest::qWaitForPolish(leftview));
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 4);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 5);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 16);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 17);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
model.moveItems(4, 3, 1);
- QVERIFY(QQuickTest::qWaitForItemPolished(leftview));
+ QVERIFY(QQuickTest::qWaitForPolish(leftview));
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 4);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 5);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 16);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 17);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
model.moveItems(16, 17, 1);
- QVERIFY(QQuickTest::qWaitForItemPolished(leftview));
+ QVERIFY(QQuickTest::qWaitForPolish(leftview));
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 4);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 5);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 16);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 17);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
model.moveItems(17, 16, 1);
- QVERIFY(QQuickTest::qWaitForItemPolished(leftview));
+ QVERIFY(QQuickTest::qWaitForPolish(leftview));
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 4);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
item = findItem<QQuickItem>(leftContent, wrapperObjectName, 5);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 16);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(rightContent, wrapperObjectName, 17);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
}
void tst_QQuickListView::populateTransitions()
@@ -6666,8 +6679,8 @@ void tst_QQuickListView::populateTransitions()
model.addItem("item" + QString::number(i), "");
}
+ QScopedPointer<TestObject> testObject(new TestObject());
QQuickView *window = getView();
- QScopedPointer<TestObject> testObject(new TestObject(window->rootContext()));
window->rootContext()->setContextProperty("testModel", &model);
window->rootContext()->setContextProperty("testObject", testObject.data());
window->rootContext()->setContextProperty("usePopulateTransition", usePopulateTransition);
@@ -6692,12 +6705,12 @@ void tst_QQuickListView::populateTransitions()
QTRY_COMPARE(listview->property("countPopulateTransitions").toInt(), 0);
QTRY_COMPARE(listview->property("countAddTransitions").toInt(), 16);
} else {
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QCOMPARE(listview->property("countPopulateTransitions").toInt(), 0);
QCOMPARE(listview->property("countAddTransitions").toInt(), 0);
}
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i=0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
@@ -6720,7 +6733,7 @@ void tst_QQuickListView::populateTransitions()
window->rootContext()->setContextProperty("testModel", QVariant());
listview->forceLayout();
QTRY_COMPARE(listview->count(), 0);
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 0);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").size(), 0);
listview->setProperty("countPopulateTransitions", 0);
listview->setProperty("countAddTransitions", 0);
@@ -6732,7 +6745,7 @@ void tst_QQuickListView::populateTransitions()
QTRY_COMPARE(listview->property("countPopulateTransitions").toInt(), usePopulateTransition ? 16 : 0);
QTRY_COMPARE(listview->property("countAddTransitions").toInt(), 0);
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i=0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
@@ -6750,7 +6763,7 @@ void tst_QQuickListView::populateTransitions()
QTRY_COMPARE(listview->property("countPopulateTransitions").toInt(), usePopulateTransition ? 16 : 0);
QTRY_COMPARE(listview->property("countAddTransitions").toInt(), 0);
- itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i=0; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
@@ -6780,6 +6793,20 @@ void tst_QQuickListView::populateTransitions_data()
QTest::newRow("empty to start with, no populate") << false << false << false;
}
+// QTBUG-111050
+/* Reposition first visible item in list view on populate transition
+ Note: Occurs only in BottomToTop or RightToLeft layout */
+void tst_QQuickListView::repositionFirstItemOnPopulateTransition()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("repositionListViewOnPopulateTransition.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = qobject_cast<QQuickListView*>(window->rootObject());
+ QTRY_VERIFY(listview != nullptr);
+ QTRY_COMPARE(listview->contentY(), -100.0);
+}
/*
* Tests if the first visible item is not repositioned if the same item
@@ -6790,12 +6817,12 @@ void tst_QQuickListView::populateTransitions_data()
void tst_QQuickListView::sizeTransitions()
{
QFETCH(bool, topToBottom);
+ QScopedPointer<TestObject> testObject(new TestObject);
QQuickView *window = getView();
QQmlContext *ctxt = window->rootContext();
QaimModel model;
ctxt->setContextProperty("testModel", &model);
ctxt->setContextProperty("topToBottom", topToBottom);
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testObject", &model);
window->setSource(testFileUrl("sizeTransitions.qml"));
window->show();
@@ -6803,7 +6830,7 @@ void tst_QQuickListView::sizeTransitions()
QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
QTRY_VERIFY(listview != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// the following will start the transition
model.addItem(QLatin1String("Test"), "");
@@ -6850,9 +6877,9 @@ void tst_QQuickListView::addTransitions()
QaimModel model_targetItems_transitionFrom;
QaimModel model_displacedItems_transitionVia;
+ QScopedPointer<TestObject> testObject(new TestObject);
QQuickView *window = getView();
QQmlContext *ctxt = window->rootContext();
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testModel", &model);
ctxt->setContextProperty("model_targetItems_transitionFrom", &model_targetItems_transitionFrom);
ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
@@ -6867,11 +6894,11 @@ void tst_QQuickListView::addTransitions()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
if (contentY != 0) {
listview->setContentY(contentY);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
}
QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
@@ -6889,7 +6916,7 @@ void tst_QQuickListView::addTransitions()
targetIndexes << i;
}
}
- QVERIFY(expectedTargetData.count() > 0);
+ QVERIFY(expectedTargetData.size() > 0);
}
// start animation
@@ -6902,7 +6929,7 @@ void tst_QQuickListView::addTransitions()
QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
if (shouldAnimateTargets) {
- QTRY_COMPARE(listview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
+ QTRY_COMPARE(listview->property("targetTransitionsDone").toInt(), expectedTargetData.size());
QTRY_COMPARE(listview->property("displaceTransitionsDone").toInt(),
expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
@@ -6929,8 +6956,8 @@ void tst_QQuickListView::addTransitions()
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
int firstVisibleIndex = -1;
- int itemCount = items.count();
- for (int i=0; i<items.count(); i++) {
+ int itemCount = items.size();
+ for (int i=0; i<items.size(); i++) {
if (items[i]->y() >= contentY) {
QQmlExpression e(qmlContext(items[i]), items[i], "index");
firstVisibleIndex = e.evaluate().toInt();
@@ -7045,9 +7072,9 @@ void tst_QQuickListView::moveTransitions()
QaimModel model_targetItems_transitionVia;
QaimModel model_displacedItems_transitionVia;
+ QScopedPointer<TestObject> testObject(new TestObject);
QQuickView *window = getView();
QQmlContext *ctxt = window->rootContext();
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testModel", &model);
ctxt->setContextProperty("model_targetItems_transitionVia", &model_targetItems_transitionVia);
ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
@@ -7066,7 +7093,7 @@ void tst_QQuickListView::moveTransitions()
if (contentY != 0) {
listview->setContentY(contentY);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
}
QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
@@ -7089,7 +7116,7 @@ void tst_QQuickListView::moveTransitions()
// start animation
model.moveItems(moveFrom, moveTo, moveCount);
- QTRY_COMPARE(listview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
+ QTRY_COMPARE(listview->property("targetTransitionsDone").toInt(), expectedTargetData.size());
QTRY_COMPARE(listview->property("displaceTransitionsDone").toInt(),
expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
@@ -7113,7 +7140,7 @@ void tst_QQuickListView::moveTransitions()
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
int firstVisibleIndex = -1;
- for (int i=0; i<items.count(); i++) {
+ for (int i=0; i<items.size(); i++) {
if (items[i]->y() >= contentY) {
QQmlExpression e(qmlContext(items[i]), items[i], "index");
firstVisibleIndex = e.evaluate().toInt();
@@ -7123,7 +7150,7 @@ void tst_QQuickListView::moveTransitions()
QVERIFY2(firstVisibleIndex >= 0, QByteArray::number(firstVisibleIndex));
// verify all items moved to the correct final positions
- int itemCount = findItems<QQuickItem>(contentItem, "wrapper").count();
+ int itemCount = findItems<QQuickItem>(contentItem, "wrapper").size();
for (int i=firstVisibleIndex; i < model.count() && i < itemCount; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
@@ -7247,9 +7274,9 @@ void tst_QQuickListView::removeTransitions()
QaimModel model_targetItems_transitionTo;
QaimModel model_displacedItems_transitionVia;
+ QScopedPointer<TestObject> testObject(new TestObject);
QQuickView *window = getView();
QQmlContext *ctxt = window->rootContext();
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testModel", &model);
ctxt->setContextProperty("model_targetItems_transitionTo", &model_targetItems_transitionTo);
ctxt->setContextProperty("model_displacedItems_transitionVia", &model_displacedItems_transitionVia);
@@ -7264,11 +7291,11 @@ void tst_QQuickListView::removeTransitions()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
if (contentY != 0) {
listview->setContentY(contentY);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
}
QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
@@ -7283,13 +7310,13 @@ void tst_QQuickListView::removeTransitions()
targetIndexes << i;
}
}
- QVERIFY(expectedTargetData.count() > 0);
+ QVERIFY(expectedTargetData.size() > 0);
}
// calculate targetItems and expectedTargets before model changes
QList<QQuickItem *> targetItems = findItems<QQuickItem>(contentItem, "wrapper", targetIndexes);
QVariantMap expectedTargets;
- for (int i=0; i<targetIndexes.count(); i++)
+ for (int i=0; i<targetIndexes.size(); i++)
expectedTargets[model.name(targetIndexes[i])] = targetIndexes[i];
// start animation
@@ -7297,7 +7324,7 @@ void tst_QQuickListView::removeTransitions()
QTRY_COMPARE(model.count(), listview->count());
if (shouldAnimateTargets) {
- QTRY_COMPARE(listview->property("targetTransitionsDone").toInt(), expectedTargetData.count());
+ QTRY_COMPARE(listview->property("targetTransitionsDone").toInt(), expectedTargetData.size());
QTRY_COMPARE(listview->property("displaceTransitionsDone").toInt(),
expectedDisplacedIndexes.isValid() ? expectedDisplacedIndexes.count() : 0);
@@ -7323,9 +7350,9 @@ void tst_QQuickListView::removeTransitions()
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
int firstVisibleIndex = -1;
- int itemCount = items.count();
+ int itemCount = items.size();
- for (int i=0; i<items.count(); i++) {
+ for (int i=0; i<items.size(); i++) {
QQmlExpression e(qmlContext(items[i]), items[i], "index");
int index = e.evaluate().toInt();
if (firstVisibleIndex < 0 && items[i]->y() >= contentY)
@@ -7445,9 +7472,9 @@ void tst_QQuickListView::displacedTransitions()
QPointF moveDisplaced_transitionVia(50, -100);
QPointF removeDisplaced_transitionVia(150, 100);
+ QScopedPointer<TestObject> testObject(new TestObject());
QQuickView *window = getView();
QQmlContext *ctxt = window->rootContext();
- QScopedPointer<TestObject> testObject(new TestObject(window));
ctxt->setContextProperty("testModel", &model);
ctxt->setContextProperty("testObject", testObject.data());
ctxt->setContextProperty("model_displaced_transitionVia", &model_displaced_transitionVia);
@@ -7474,7 +7501,7 @@ void tst_QQuickListView::displacedTransitions()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QList<QPair<QString,QString> > expectedDisplacedValues = expectedDisplacedIndexes.getModelDataValues(model);
listview->setProperty("displaceTransitionsDone", false);
@@ -7495,7 +7522,7 @@ void tst_QQuickListView::displacedTransitions()
break;
case ListChange::Moved:
model.moveItems(change.index, change.to, change.count);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
break;
case ListChange::SetCurrent:
case ListChange::SetContentY:
@@ -7514,15 +7541,15 @@ void tst_QQuickListView::displacedTransitions()
QTRY_VERIFY(listview->property("displaceTransitionsDone").toBool());
// check the correct number of target items and indexes were received
- QCOMPARE(resultTargetIndexes.count(), expectedDisplacedIndexes.count());
- for (int i=0; i<resultTargetIndexes.count(); i++)
- QCOMPARE(resultTargetIndexes[i].value<QList<int> >().count(), change.count);
- QCOMPARE(resultTargetItems.count(), expectedDisplacedIndexes.count());
- for (int i=0; i<resultTargetItems.count(); i++)
- QCOMPARE(resultTargetItems[i].toList().count(), change.count);
+ QCOMPARE(resultTargetIndexes.size(), expectedDisplacedIndexes.count());
+ for (int i=0; i<resultTargetIndexes.size(); i++)
+ QCOMPARE(resultTargetIndexes[i].value<QList<int> >().size(), change.count);
+ QCOMPARE(resultTargetItems.size(), expectedDisplacedIndexes.count());
+ for (int i=0; i<resultTargetItems.size(); i++)
+ QCOMPARE(resultTargetItems[i].toList().size(), change.count);
} else {
- QCOMPARE(resultTargetIndexes.count(), 0);
- QCOMPARE(resultTargetItems.count(), 0);
+ QCOMPARE(resultTargetIndexes.size(), 0);
+ QCOMPARE(resultTargetItems.size(), 0);
}
if (change.type == ListChange::Inserted && useAddDisplaced && addDisplacedEnabled)
@@ -7549,7 +7576,7 @@ void tst_QQuickListView::displacedTransitions()
// verify all items moved to the correct final positions
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
- for (int i=0; i < model.count() && i < items.count(); ++i) {
+ for (int i=0; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
QCOMPARE(item->x(), 0.0);
@@ -7671,9 +7698,9 @@ void tst_QQuickListView::multipleTransitions()
for (int i = 0; i < initialCount; i++)
model.addItem("Original item" + QString::number(i), "");
+ QScopedPointer<TestObject> testObject(new TestObject);
QQuickView *window = getView();
QQmlContext *ctxt = window->rootContext();
- QScopedPointer<TestObject> testObject(new TestObject);
ctxt->setContextProperty("testModel", &model);
ctxt->setContextProperty("testObject", testObject.data());
ctxt->setContextProperty("addTargets_transitionFrom", addTargets_transitionFrom);
@@ -7694,16 +7721,16 @@ void tst_QQuickListView::multipleTransitions()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
if (contentY != 0) {
listview->setContentY(contentY);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
}
int timeBetweenActions = window->rootObject()->property("timeBetweenActions").toInt();
- for (int i=0; i<changes.count(); i++) {
+ for (int i=0; i<changes.size(); i++) {
switch (changes[i].type) {
case ListChange::Inserted:
{
@@ -7712,7 +7739,7 @@ void tst_QQuickListView::multipleTransitions()
targetItems << qMakePair(QString("new item %1").arg(j), QString::number(j));
model.insertItems(changes[i].index, targetItems);
QTRY_COMPARE(model.count(), listview->count());
- if (i == changes.count() - 1) {
+ if (i == changes.size() - 1) {
QTRY_VERIFY(!listview->property("runningAddTargets").toBool());
QTRY_VERIFY(!listview->property("runningAddDisplaced").toBool());
} else {
@@ -7723,7 +7750,7 @@ void tst_QQuickListView::multipleTransitions()
case ListChange::Removed:
model.removeItems(changes[i].index, changes[i].count);
QTRY_COMPARE(model.count(), listview->count());
- if (i == changes.count() - 1) {
+ if (i == changes.size() - 1) {
QTRY_VERIFY(!listview->property("runningRemoveTargets").toBool());
QTRY_VERIFY(!listview->property("runningRemoveDisplaced").toBool());
} else {
@@ -7732,8 +7759,8 @@ void tst_QQuickListView::multipleTransitions()
break;
case ListChange::Moved:
model.moveItems(changes[i].index, changes[i].to, changes[i].count);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
- if (i == changes.count() - 1) {
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+ if (i == changes.size() - 1) {
QTRY_VERIFY(!listview->property("runningMoveTargets").toBool());
QTRY_VERIFY(!listview->property("runningMoveDisplaced").toBool());
} else {
@@ -7745,7 +7772,7 @@ void tst_QQuickListView::multipleTransitions()
break;
case ListChange::SetContentY:
listview->setContentY(changes[i].pos);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
break;
case ListChange::Polish:
break;
@@ -7757,7 +7784,7 @@ void tst_QQuickListView::multipleTransitions()
// verify all items moved to the correct final positions
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
- for (int i=0; i < model.count() && i < items.count(); ++i) {
+ for (int i=0; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
QTRY_COMPARE(item->x(), 0.0);
@@ -7838,9 +7865,9 @@ void tst_QQuickListView::multipleDisplaced()
for (int i = 0; i < 30; i++)
model.addItem("Original item" + QString::number(i), "");
+ QScopedPointer<TestObject> testObject(new TestObject());
QQuickView *window = getView();
QQmlContext *ctxt = window->rootContext();
- QScopedPointer<TestObject> testObject(new TestObject(window));
ctxt->setContextProperty("testModel", &model);
ctxt->setContextProperty("testObject", testObject.data());
window->setSource(testFileUrl("multipleDisplaced.qml"));
@@ -7851,7 +7878,7 @@ void tst_QQuickListView::multipleDisplaced()
QTRY_VERIFY(listview != nullptr);
QQuickItem *contentItem = listview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
model.moveItems(12, 8, 1);
QTest::qWait(window->rootObject()->property("duration").toInt() / 2);
@@ -7859,14 +7886,15 @@ void tst_QQuickListView::multipleDisplaced()
QTRY_VERIFY(listview->property("displaceTransitionsDone").toBool());
QVariantMap transitionsStarted = listview->property("displaceTransitionsStarted").toMap();
- foreach (const QString &name, transitionsStarted.keys()) {
+ const QStringList keys = transitionsStarted.keys();
+ for (const QString &name : keys) {
QVERIFY2(transitionsStarted[name] == 1,
qPrintable(QString("%1 was displaced %2 times").arg(name).arg(transitionsStarted[name].toInt())));
}
// verify all items moved to the correct final positions
QList<QQuickItem*> items = findItems<QQuickItem>(contentItem, "wrapper");
- for (int i=0; i < model.count() && i < items.count(); ++i) {
+ for (int i=0; i < model.count() && i < items.size(); ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
QTRY_COMPARE(item->x(), 0.0);
@@ -7883,7 +7911,7 @@ QList<int> tst_QQuickListView::toIntList(const QVariantList &list)
{
QList<int> ret;
bool ok = true;
- for (int i=0; i<list.count(); i++) {
+ for (int i=0; i<list.size(); i++) {
ret << list[i].toInt(&ok);
if (!ok)
qWarning() << "tst_QQuickListView::toIntList(): not a number:" << list[i];
@@ -7895,7 +7923,7 @@ QList<int> tst_QQuickListView::toIntList(const QVariantList &list)
void tst_QQuickListView::matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes)
{
const QSet<int> expectedIndexSet(expectedIndexes.cbegin(), expectedIndexes.cend());
- for (int i=0; i<indexLists.count(); i++) {
+ for (int i=0; i<indexLists.size(); i++) {
const auto &currentList = indexLists[i].value<QList<int> >();
const QSet<int> current(currentList.cbegin(), currentList.cend());
if (current != expectedIndexSet)
@@ -7915,27 +7943,27 @@ void tst_QQuickListView::matchItemsAndIndexes(const QVariantMap &items, const Qa
qDebug() << itemIndex;
QCOMPARE(model.name(itemIndex), name);
}
- QCOMPARE(items.count(), expectedIndexes.count());
+ QCOMPARE(items.size(), expectedIndexes.size());
}
void tst_QQuickListView::matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems)
{
- for (int i=0; i<itemLists.count(); i++) {
+ for (int i=0; i<itemLists.size(); i++) {
QCOMPARE(itemLists[i].typeId(), QMetaType::QVariantList);
QVariantList current = itemLists[i].toList();
- for (int j=0; j<current.count(); j++) {
+ for (int j=0; j<current.size(); j++) {
QQuickItem *o = qobject_cast<QQuickItem*>(current[j].value<QObject*>());
QVERIFY2(o, qPrintable(QString("Invalid actual item at %1").arg(j)));
QVERIFY2(expectedItems.contains(o), qPrintable(QString("Cannot match item %1").arg(j)));
}
- QCOMPARE(current.count(), expectedItems.count());
+ QCOMPARE(current.size(), expectedItems.size());
}
}
void tst_QQuickListView::flickBeyondBounds()
{
QScopedPointer<QQuickView> window(createView());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("flickBeyondBoundsBug.qml"));
window->show();
@@ -7947,7 +7975,7 @@ void tst_QQuickListView::flickBeyondBounds()
QQuickItem *contentItem = listview->contentItem();
QTRY_VERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
// Flick view up beyond bounds
flick(window.data(), QPoint(10, 10), QPoint(10, -2000), 180);
@@ -7958,7 +7986,7 @@ void tst_QQuickListView::flickBeyondBounds()
// We're really testing that we don't get stuck in a loop,
// but also confirm items positioned correctly.
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 2);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").size(), 2);
for (int i = 0; i < 2; ++i) {
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", i);
if (!item) qWarning() << "Item" << i << "not found";
@@ -7977,7 +8005,7 @@ void tst_QQuickListView::flickBothDirections()
QFETCH(QPointF, targetPos);
QQuickView *window = getView();
- QQuickViewTestUtil::moveMouseAway(window);
+ QQuickViewTestUtils::moveMouseAway(window);
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("initialOrientation", initValues ? orientation : QQuickListView::Vertical);
@@ -8001,7 +8029,7 @@ void tst_QQuickListView::flickBothDirections()
listview->setContentHeight(contentHeight);
}
- flick(window, QPoint(100, 100), QPoint(25, 25), 50);
+ flick(window, QPoint(140, 140), QPoint(25, 25), 50);
QVERIFY(listview->isMoving());
QTRY_VERIFY(!listview->isMoving());
QCOMPARE(listview->contentX(), targetPos.x());
@@ -8059,13 +8087,13 @@ void tst_QQuickListView::destroyItemOnCreation()
QQuickItem *contentItem = listview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QCOMPARE(window->rootObject()->property("createdIndex").toInt(), -1);
model.addItem("new item", "");
QTRY_COMPARE(window->rootObject()->property("createdIndex").toInt(), 0);
- QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").count(), 0);
+ QTRY_COMPARE(findItems<QQuickItem>(contentItem, "wrapper").size(), 0);
QCOMPARE(model.count(), 0);
}
@@ -8090,7 +8118,7 @@ void tst_QQuickListView::parentBinding()
QQuickItem *contentItem = listview->contentItem();
QVERIFY(contentItem != nullptr);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QQuickItem *item = findItem<QQuickItem>(contentItem, "wrapper", 0);
QVERIFY(item);
@@ -8150,7 +8178,7 @@ void tst_QQuickListView::delayedChanges_QTBUG_30555()
void tst_QQuickListView::outsideViewportChangeNotAffectingView()
{
QScopedPointer<QQuickView> window(createView());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("outsideViewportChangeNotAffectingView.qml"));
QQuickListView *listview = window->rootObject()->findChild<QQuickListView*>();
@@ -8184,7 +8212,7 @@ void tst_QQuickListView::outsideViewportChangeNotAffectingView()
void tst_QQuickListView::testProxyModelChangedAfterMove()
{
QScopedPointer<QQuickView> window(createView());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("proxytest.qml"));
QQuickListView *listview = window->rootObject()->findChild<QQuickListView*>();
@@ -8229,24 +8257,24 @@ void tst_QQuickListView::displayMargin()
QQuickItem *item0 = findItem<QQuickItem>(content, "delegate", 0);
QVERIFY(item0);
- QCOMPARE(delegateVisible(item0), true);
+ QCOMPARE(isDelegateVisible(item0), true);
// the 14th item should be within the end margin
QQuickItem *item14 = findItem<QQuickItem>(content, "delegate", 13);
QVERIFY(item14);
- QCOMPARE(delegateVisible(item14), true);
+ QCOMPARE(isDelegateVisible(item14), true);
// the 15th item should be outside the end margin
QVERIFY(findItem<QQuickItem>(content, "delegate", 14) == nullptr);
// the first delegate should still be within the begin margin
listview->positionViewAtIndex(3, QQuickListView::Beginning);
- QCOMPARE(delegateVisible(item0), true);
+ QCOMPARE(isDelegateVisible(item0), true);
// the first delegate should now be outside the begin margin
listview->positionViewAtIndex(4, QQuickListView::Beginning);
- QCOMPARE(delegateVisible(item0), false);
+ QCOMPARE(isDelegateVisible(item0), false);
}
void tst_QQuickListView::negativeDisplayMargin()
@@ -8268,29 +8296,29 @@ void tst_QQuickListView::negativeDisplayMargin()
QQuickItem *item = findItem<QQuickItem>(content, "delegate", 0);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(content, "delegate", 7);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), true);
+ QCOMPARE(isDelegateVisible(item), true);
item = findItem<QQuickItem>(content, "delegate", 8);
QVERIFY(item);
- QCOMPARE(delegateVisible(item), false);
+ QCOMPARE(isDelegateVisible(item), false);
// Flick until contentY means that delegate8 should be visible
listview->setProperty("contentY", 500);
item = findItem<QQuickItem>(content, "delegate", 8);
QVERIFY(item);
- QTRY_COMPARE(delegateVisible(item), true);
+ QTRY_COMPARE(isDelegateVisible(item), true);
listview->setProperty("contentY", 1000);
QTRY_VERIFY((item = findItem<QQuickItem>(content, "delegate", 14)));
- QTRY_COMPARE(delegateVisible(item), true);
+ QTRY_COMPARE(isDelegateVisible(item), true);
listview->setProperty("contentY", 0);
QTRY_VERIFY(item = findItem<QQuickItem>(content, "delegate", 4));
- QTRY_COMPARE(delegateVisible(item), true);
+ QTRY_COMPARE(isDelegateVisible(item), true);
}
void tst_QQuickListView::highlightItemGeometryChanges()
@@ -8392,7 +8420,7 @@ void tst_QQuickListView::stickyPositioning()
listview->positionViewAtIndex(positionIndex, positionMode);
- foreach (const QPointF &offset, movement) {
+ for (const QPointF &offset : std::as_const(movement)) {
listview->setContentX(listview->contentX() + offset.x());
listview->setContentY(listview->contentY() + offset.y());
}
@@ -8833,7 +8861,7 @@ void tst_QQuickListView::QTBUG_38209()
listview->flick(0, 1000);
// ensure we move more than just a couple pixels
- QTRY_VERIFY(contentY - listview->contentY() > qreal(100.0));
+ QTRY_COMPARE_GE(contentY - listview->contentY(), 100);
}
void tst_QQuickListView::programmaticFlickAtBounds()
@@ -9056,11 +9084,11 @@ void tst_QQuickListView::jsArrayChange()
}
view->setModel(QVariant::fromValue(array1));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
// no change
view->setModel(QVariant::fromValue(array2));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
static bool compareObjectModel(QQuickListView *listview, QQmlObjectModel *model)
@@ -9245,7 +9273,7 @@ void tst_QQuickListView::keyNavigationEnabled()
// of disabling both mouse and keyboard interaction.
QSignalSpy enabledSpy(listView, SIGNAL(keyNavigationEnabledChanged()));
listView->setInteractive(false);
- QCOMPARE(enabledSpy.count(), 1);
+ QCOMPARE(enabledSpy.size(), 1);
QCOMPARE(listView->isKeyNavigationEnabled(), false);
flick(window.data(), QPoint(200, 200), QPoint(200, 50), 100);
@@ -9258,17 +9286,17 @@ void tst_QQuickListView::keyNavigationEnabled()
// Check that isKeyNavigationEnabled implicitly follows the value of interactive.
listView->setInteractive(true);
- QCOMPARE(enabledSpy.count(), 2);
+ QCOMPARE(enabledSpy.size(), 2);
QCOMPARE(listView->isKeyNavigationEnabled(), true);
// Change it back again for the next check.
listView->setInteractive(false);
- QCOMPARE(enabledSpy.count(), 3);
+ QCOMPARE(enabledSpy.size(), 3);
QCOMPARE(listView->isKeyNavigationEnabled(), false);
// Setting keyNavigationEnabled to true shouldn't enable mouse interaction.
listView->setKeyNavigationEnabled(true);
- QCOMPARE(enabledSpy.count(), 4);
+ QCOMPARE(enabledSpy.size(), 4);
flick(window.data(), QPoint(200, 200), QPoint(200, 50), 100);
QVERIFY(!listView->isMoving());
QCOMPARE(listView->contentY(), 0.0);
@@ -9282,7 +9310,7 @@ void tst_QQuickListView::keyNavigationEnabled()
// Changing interactive now shouldn't result in keyNavigationEnabled changing,
// since we broke the "binding".
listView->setInteractive(true);
- QCOMPARE(enabledSpy.count(), 4);
+ QCOMPARE(enabledSpy.size(), 4);
// Keyboard interaction shouldn't work now.
listView->setKeyNavigationEnabled(false);
@@ -9459,7 +9487,7 @@ void tst_QQuickListView::QTBUG_66163_setModelViewPortSizeChange()
delegate: Rectangle {
color: index % 2 ? "green" : "orange"
- width: parent.width
+ width: view.width
height: 50
}
@@ -9478,7 +9506,7 @@ void tst_QQuickListView::QTBUG_66163_setModelViewPortSizeChange()
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
auto view = root->findChild<QQuickListView *>("view");
QVERIFY(view);
- QVERIFY(QQuickTest::qWaitForItemPolished(view));
+ QVERIFY(QQuickTest::qWaitForPolish(view));
QSignalSpy spy(view, &QQuickListView::contentYChanged);
auto transition = view->property("populate").value<QQuickTransition*>();
QVERIFY(transition);
@@ -9490,7 +9518,7 @@ void tst_QQuickListView::QTBUG_66163_setModelViewPortSizeChange()
QTest::qWait(1100); // animation takes 1000ms, + 10% extra delay
/* the viewport should not have changed, thus there should not have
been any contentYChanged signal*/
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
}
void tst_QQuickListView::itemFiltered()
@@ -9511,8 +9539,8 @@ void tst_QQuickListView::itemFiltered()
QScopedPointer<QQuickView> window(createView());
window->engine()->rootContext()->setContextProperty("_model", &proxy2);
QQmlComponent component(window->engine());
- component.setData("import QtQuick 2.4; ListView { "
- "anchors.fill: parent; model: _model; delegate: Text { width: parent.width;"
+ component.setData("import QtQuick 2.4; ListView { id: listView; "
+ "anchors.fill: parent; model: _model; delegate: Text { width: listView.width;"
"text: model.display; } }",
QUrl());
window->setContent(QUrl(), &component, component.create());
@@ -9550,7 +9578,7 @@ void tst_QQuickListView::QTBUG_34576_velocityZero()
QVERIFY(listview);
QQuickItem *contentItem = listview->contentItem();
QVERIFY(contentItem);
- QVERIFY(QQuickTest::qWaitForItemPolished(listview));
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
QSignalSpy horizontalVelocitySpy(listview, SIGNAL(horizontalVelocityChanged()));
@@ -9561,7 +9589,7 @@ void tst_QQuickListView::QTBUG_34576_velocityZero()
window->rootObject()->setProperty("horizontalVelocityZeroCount", QVariant(0));
listview->setCurrentIndex(2);
QTRY_COMPARE(window->rootObject()->property("current").toInt(), 2);
- QCOMPARE(horizontalVelocitySpy.count(), 0);
+ QCOMPARE(horizontalVelocitySpy.size(), 0);
QCOMPARE(window->rootObject()->property("horizontalVelocityZeroCount").toInt(), 0);
QSignalSpy currentIndexChangedSpy(listview, SIGNAL(currentIndexChanged()));
@@ -9571,11 +9599,11 @@ void tst_QQuickListView::QTBUG_34576_velocityZero()
QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(295,215));
// verify that currentIndexChanged is triggered
- QTRY_VERIFY(currentIndexChangedSpy.count() > 0);
+ QTRY_VERIFY(currentIndexChangedSpy.size() > 0);
// since we have set currentIndex to an item out of view, the listview will scroll
QTRY_COMPARE(window->rootObject()->property("current").toInt(), 3);
- QTRY_VERIFY(horizontalVelocitySpy.count() > 0);
+ QTRY_VERIFY(horizontalVelocitySpy.size() > 0);
// velocity should be always > 0.0
QTRY_COMPARE(window->rootObject()->property("horizontalVelocityZeroCount").toInt(), 0);
@@ -9604,7 +9632,7 @@ void tst_QQuickListView::QTBUG_61537_modelChangesAsync()
// Check that the number of delegates we expect to be visible in
// the listview matches the number of items we find if we count.
int reportedCount = listView->count();
- int actualCount = findItems<QQuickItem>(listView, "delegate").count();
+ int actualCount = findItems<QQuickItem>(listView, "delegate").size();
QCOMPARE(reportedCount, actualCount);
}
@@ -9679,7 +9707,7 @@ void tst_QQuickListView::touchCancel() // QTBUG-74679
QPoint p1(300, 300);
QTest::touchEvent(window.data(), touchDevice).press(0, p1, window.data());
QQuickTouchUtils::flush(window.data());
- QTRY_VERIFY(mouseArea->pressed());
+ QTRY_VERIFY(mouseArea->isPressed());
// and because Flickable filtered it, QQuickFlickablePrivate::pressed
// should be true, but it's not easily tested here
@@ -9735,7 +9763,7 @@ public:
m_animals.push_back(Animal {5, QLatin1String("Cherry")});
}
- int rowCount(const QModelIndex & = QModelIndex()) const override {return m_animals.count();}
+ int rowCount(const QModelIndex & = QModelIndex()) const override {return m_animals.size();}
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override {
if (!checkIndex(index))
@@ -9795,12 +9823,24 @@ void tst_QQuickListView::delegateWithRequiredProperties()
void tst_QQuickListView::reuse_reuseIsOffByDefault()
{
+ QScopedPointer<TestObject> testObject(new TestObject);
+
// Check that delegate recycling is off by default. The reason is that
// ListView needs to be backwards compatible with legacy applications. And
// when using delegate recycling, there are certain differences, like that
// a delegates Component.onCompleted will just be called the first time the
// item is created, and not when it's reused.
QScopedPointer<QQuickView> window(createView());
+
+ QaimModel model;
+ for (int i = 0; i < 40; i++)
+ model.addItem("Item" + QString::number(i), "");
+
+ QQmlContext *ctxt = window->rootContext();
+ ctxt->setContextProperty("testModel", &model);
+
+ ctxt->setContextProperty("testObject", testObject.data());
+
window->setSource(testFileUrl("listviewtest.qml"));
window->resize(640, 480);
window->show();
@@ -9839,14 +9879,14 @@ void tst_QQuickListView::reuse_checkThatItemsAreReused()
QVERIFY(listView->reuseItems());
auto items = findItems<QQuickItem>(listView, "delegate");
- const int initialItemCount = items.count();
+ const int initialItemCount = items.size();
QVERIFY(initialItemCount > 0);
// Sanity check that the size of the initial list of items match the count we tracked from QML
QCOMPARE(listView->property("delegatesCreatedCount").toInt(), initialItemCount);
// Go through all the initial items and check that they have not been reused yet
- for (const auto item : qAsConst(items))
+ for (const auto item : std::as_const(items))
QCOMPARE(item->property("reusedCount").toInt(), 0);
// Flick one page down and count how many items we have created thus
@@ -9855,7 +9895,7 @@ void tst_QQuickListView::reuse_checkThatItemsAreReused()
const qreal delegateHeight = items.at(0)->height();
const qreal flickDistance = (initialItemCount * delegateHeight) + 1;
listView->setContentY(flickDistance);
- QVERIFY(QQuickTest::qWaitForItemPolished(listView));
+ QVERIFY(QQuickTest::qWaitForPolish(listView));
const int countAfterDownFlick = listView->property("delegatesCreatedCount").toInt();
QCOMPARE(countAfterDownFlick, initialItemCount * 2);
@@ -9870,7 +9910,7 @@ void tst_QQuickListView::reuse_checkThatItemsAreReused()
// QML model classes, we need to catch it through a binding instead (which is
// OK, since then we can also check that bindings are updated when reused).
items = findItems<QQuickItem>(listView, "delegate");
- for (const auto item : qAsConst(items)) {
+ for (const auto item : std::as_const(items)) {
const QString display = item->property("displayBinding").toString();
const int modelIndex = item->property("modelIndex").toInt();
QVERIFY(modelIndex >= initialItemCount);
@@ -9882,7 +9922,7 @@ void tst_QQuickListView::reuse_checkThatItemsAreReused()
// in the pool during the flick, we also fill it up again with all the items that
// were inside the page that was flicked out.
listView->setContentY(0);
- QVERIFY(QQuickTest::qWaitForItemPolished(listView));
+ QVERIFY(QQuickTest::qWaitForPolish(listView));
const int countAfterUpFlick = listView->property("delegatesCreatedCount").toInt();
const int poolSizeAfterUpFlick = itemView_d->model->poolSize();
QCOMPARE(countAfterUpFlick, countAfterDownFlick);
@@ -9892,7 +9932,7 @@ void tst_QQuickListView::reuse_checkThatItemsAreReused()
// (except for ListView.currentItem, which was never released).
const auto listViewCurrentItem = listView->currentItem();
items = findItems<QQuickItem>(listView, "delegate");
- for (const auto item : qAsConst(items)) {
+ for (const auto item : std::as_const(items)) {
const int reusedCount = item->property("reusedCount").toInt();
if (item == listViewCurrentItem)
QCOMPARE(reusedCount, 0);
@@ -9903,7 +9943,7 @@ void tst_QQuickListView::reuse_checkThatItemsAreReused()
// Go through all items again and check that all model data inside the delegate
// have correct values now that they have been reused.
items = findItems<QQuickItem>(listView, "delegate");
- for (const auto item : qAsConst(items)) {
+ for (const auto item : std::as_const(items)) {
const QString display = item->property("displayBinding").toString();
const int modelIndex = item->property("modelIndex").toInt();
QVERIFY(modelIndex < initialItemCount);
@@ -9914,7 +9954,7 @@ void tst_QQuickListView::reuse_checkThatItemsAreReused()
void tst_QQuickListView::dragOverFloatingHeaderOrFooter() // QTBUG-74046
{
QQuickView *window = getView();
- QQuickViewTestUtil::moveMouseAway(window);
+ QQuickViewTestUtils::moveMouseAway(window);
window->setSource(testFileUrl("qtbug63974.qml"));
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window));
@@ -9973,13 +10013,13 @@ void tst_QQuickListView::moveObjectModelItemToAnotherObjectModel()
QVERIFY(QMetaObject::invokeMethod(root, "moveRedRectToModel2"));
QVERIFY(QQuickTest::qIsPolishScheduled(listView2));
- QVERIFY(QQuickTest::qWaitForItemPolished(listView2));
+ QVERIFY(QQuickTest::qWaitForPolish(listView2));
QVERIFY(redRect->isVisible());
QVERIFY(!QQuickItemPrivate::get(redRect)->culled);
QVERIFY(QMetaObject::invokeMethod(root, "moveRedRectToModel1"));
QVERIFY(QQuickTest::qIsPolishScheduled(listView1));
- QVERIFY(QQuickTest::qWaitForItemPolished(listView1));
+ QVERIFY(QQuickTest::qWaitForPolish(listView1));
QVERIFY(redRect->isVisible());
QVERIFY(!QQuickItemPrivate::get(redRect)->culled);
}
@@ -9995,7 +10035,7 @@ void tst_QQuickListView::changeModelAndDestroyTheOldOne() // QTBUG-80203
QQuickItem *root = window->rootObject();
QVERIFY(root);
- QVERIFY(QQuickTest::qWaitForItemPolished(root));
+ QVERIFY(QQuickTest::qWaitForPolish(root));
// no crash
}
@@ -10064,9 +10104,9 @@ void tst_QQuickListView::requiredObjectListModel()
const auto *root = qobject_cast<QQuickListView *>(view.rootObject());
QVERIFY(root);
- QCOMPARE(root->count(), dataList.count());
+ QCOMPARE(root->count(), dataList.size());
- for (int i = 0, end = dataList.count(); i != end; ++i) {
+ for (int i = 0, end = dataList.size(); i != end; ++i) {
const auto *rect = qobject_cast<QQuickRectangle *>(root->itemAtIndex(i));
QVERIFY(rect);
const auto *data = qobject_cast<DataObject *>(dataList.at(i));
@@ -10117,6 +10157,8 @@ void tst_QQuickListView::animatedDelegate()
}
}
+// WARNING: please add new tests to tst_qquicklistview2; this file is too slow to work with.
+
QTEST_MAIN(tst_QQuickListView)
#include "tst_qquicklistview.moc"
diff --git a/tests/auto/quick/qquicklistview2/BLACKLIST b/tests/auto/quick/qquicklistview2/BLACKLIST
new file mode 100644
index 0000000000..0162bbc852
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/BLACKLIST
@@ -0,0 +1,5 @@
+[tapDelegateDuringFlicking]
+android # QTBUG-104471
+[flickDuringFlicking]
+android # QTBUG-104471
+macos ci # QTBUG-105190
diff --git a/tests/auto/quick/qquicklistview2/CMakeLists.txt b/tests/auto/quick/qquicklistview2/CMakeLists.txt
new file mode 100644
index 0000000000..faa86ce733
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/CMakeLists.txt
@@ -0,0 +1,46 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicklistview2 LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_qquicklistview2
+ SOURCES
+ typerolemodel.h typerolemodel.cpp
+ tst_qquicklistview2.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::QmlModelsPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ Qt::QuickTest
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
+)
+
+qt_policy(SET QTP0001 NEW)
+
+qt6_add_qml_module(tst_qquicklistview2
+ URI Test
+)
+
+qt_internal_extend_target(tst_qquicklistview2 CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=":/data"
+)
+
+qt_internal_extend_target(tst_qquicklistview2 CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+)
diff --git a/tests/auto/quick/qquicklistview2/data/areaZeroView.qml b/tests/auto/quick/qquicklistview2/data/areaZeroView.qml
new file mode 100644
index 0000000000..e0329f4e83
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/areaZeroView.qml
@@ -0,0 +1,22 @@
+import QtQuick
+
+Window {
+ width: 600
+ height: 600
+ visible: true
+ property int delegateCreationCounter: 0
+
+ ListView {
+ id: lv
+ anchors.fill: parent
+ model: 6000
+
+ delegate: Rectangle {
+ width: ListView.view.width
+ height: ListView.view.width / 6
+ color: "white"
+ border.width: 1
+ Component.onCompleted: ++delegateCreationCounter
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/bindOnHeaderAndFooterXPosition.qml b/tests/auto/quick/qquicklistview2/data/bindOnHeaderAndFooterXPosition.qml
new file mode 100644
index 0000000000..69431fb525
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/bindOnHeaderAndFooterXPosition.qml
@@ -0,0 +1,29 @@
+import QtQuick
+
+ListView {
+ width: 200
+ height: 300
+ spacing: 20
+ orientation: ListView.Vertical
+
+ header: Rectangle {
+ x: (ListView.view.width - width) / 2
+ color: 'tomato'
+ width: 50
+ height: 50
+ }
+
+ footer: Rectangle {
+ x: (ListView.view.width - width) / 2
+ color: 'lime'
+ width: 50
+ height: 50
+ }
+
+ model: 3
+ delegate: Text {
+ text: 'Foobar'
+ horizontalAlignment: Text.AlignHCenter
+ width: ListView.view.width
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/bindOnHeaderAndFooterYPosition.qml b/tests/auto/quick/qquicklistview2/data/bindOnHeaderAndFooterYPosition.qml
new file mode 100644
index 0000000000..a484a154a7
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/bindOnHeaderAndFooterYPosition.qml
@@ -0,0 +1,29 @@
+import QtQuick
+
+ListView {
+ width: 300
+ height: 200
+ spacing: 20
+ orientation: ListView.Horizontal
+
+ header: Rectangle {
+ y: (ListView.view.height - height) / 2
+ color: 'tomato'
+ width: 50
+ height: 50
+ }
+
+ footer: Rectangle {
+ y: (ListView.view.height - height) / 2
+ color: 'lime'
+ width: 50
+ height: 50
+ }
+
+ model: 3
+ delegate: Text {
+ text: 'Foobar'
+ verticalAlignment: Text.AlignVCenter
+ height: ListView.view.height
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/boundDelegateComponent.qml b/tests/auto/quick/qquicklistview2/data/boundDelegateComponent.qml
new file mode 100644
index 0000000000..5e4de1a08d
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/boundDelegateComponent.qml
@@ -0,0 +1,64 @@
+pragma ComponentBehavior: Bound
+
+import QtQuick
+Item {
+ id: outer
+ objectName: "outer"
+ ListView {
+ id: listView
+ width: 100
+ height: 100
+ model: 1
+ property string foo: "foo"
+ delegate: Text {
+ property var notThere: index
+ objectName: listView.foo + outer.objectName + notThere
+ }
+ }
+
+ ListView {
+ id: listView2
+ width: 100
+ height: 100
+ model: 1
+ delegate: Text {
+ required property int index
+ objectName: listView.foo + outer.objectName + index
+ }
+ }
+
+ Component {
+ id: outerComponent
+ Item {
+ ListModel {
+ id: listModel
+ ListElement {
+ myColor: "red"
+ }
+
+ ListElement {
+ myColor: "green"
+ }
+
+ ListElement {
+ myColor: "blue"
+ }
+ }
+
+ Component {
+ id: innerComponent
+ Rectangle {
+ objectName: model.myColor
+ }
+ }
+
+ ListView {
+ width: 100
+ height: 100
+ id: innerListView
+ model: listModel
+ delegate: innerComponent
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/buttonDelegate.qml b/tests/auto/quick/qquicklistview2/data/buttonDelegate.qml
new file mode 100644
index 0000000000..a40ba1cd7e
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/buttonDelegate.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+ListView {
+ id: root
+ width: 320
+ height: 480
+ model: 100
+
+ property var pressedDelegates: []
+ property var releasedDelegates: []
+ property var tappedDelegates: []
+ property var canceledDelegates: []
+
+ delegate: Button {
+ required property int index
+ objectName: text
+ text: "button " + index
+ height: 100
+ width: 320
+
+ onPressed: root.pressedDelegates.push(index)
+ onReleased: root.releasedDelegates.push(index)
+ onClicked: root.tappedDelegates.push(index)
+ onCanceled: root.canceledDelegates.push(index)
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/changingOrientationWithListModel.qml b/tests/auto/quick/qquicklistview2/data/changingOrientationWithListModel.qml
new file mode 100644
index 0000000000..366b20b029
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/changingOrientationWithListModel.qml
@@ -0,0 +1,47 @@
+import QtQuick
+
+ListView {
+ id: root
+
+ function allDelegates(valueSelector) {
+ let sum = 0;
+ for (let i = 0; i < root.count; i++)
+ sum += valueSelector(root.itemAtIndex(i));
+ return sum;
+ }
+
+ readonly property bool isXReset: allDelegates(function(item) { return item?.x ?? 0; }) === 0
+ readonly property bool isYReset: allDelegates(function(item) { return item?.y ?? 0; }) === 0
+
+ width: 500
+ height: 500
+ delegate: Rectangle {
+ width: root.width
+ height: root.height
+ color: c
+ }
+ model: ListModel {
+ ListElement {
+ c: "red"
+ }
+ ListElement {
+ c: "green"
+ }
+ ListElement {
+ c: "blue"
+ }
+ ListElement {
+ c: "cyan"
+ }
+ ListElement {
+ c: "magenta"
+ }
+ ListElement {
+ c: "teal"
+ }
+ }
+ clip: true
+ orientation: ListView.Vertical
+ snapMode: ListView.SnapOneItem
+ highlightRangeMode: ListView.StrictlyEnforceRange
+} \ No newline at end of file
diff --git a/tests/auto/quick/qquicklistview2/data/changingOrientationWithObjectModel.qml b/tests/auto/quick/qquicklistview2/data/changingOrientationWithObjectModel.qml
new file mode 100644
index 0000000000..1d165a496e
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/changingOrientationWithObjectModel.qml
@@ -0,0 +1,54 @@
+import QtQuick
+
+ListView {
+ id: root
+
+ readonly property bool isXReset: red.x === 0 && green.x === 0 && blue.x === 0 && cyan.x === 0 && magenta.x === 0 && teal.x === 0
+
+ readonly property bool isYReset: red.y === 0 && green.y === 0 && blue.y === 0 && cyan.y === 0 && magenta.y === 0 && teal.y === 0
+
+ width: 500
+ height: 500
+ model: ObjectModel {
+ Rectangle {
+ id: red
+ width: root.width
+ height: root.height
+ color: "red"
+ }
+ Rectangle {
+ id: green
+ width: root.width
+ height: root.height
+ color: "green"
+ }
+ Rectangle {
+ id: blue
+ width: root.width
+ height: root.height
+ color: "blue"
+ }
+ Rectangle {
+ id: cyan
+ width: root.width
+ height: root.height
+ color: "cyan"
+ }
+ Rectangle {
+ id: magenta
+ width: root.width
+ height: root.height
+ color: "magenta"
+ }
+ Rectangle {
+ id: teal
+ width: root.width
+ height: root.height
+ color: "teal"
+ }
+ }
+ clip: true
+ orientation: ListView.Vertical
+ snapMode: ListView.SnapOneItem
+ highlightRangeMode: ListView.StrictlyEnforceRange
+} \ No newline at end of file
diff --git a/tests/auto/quick/qquicklistview2/data/delegateChooserEnumRole.qml b/tests/auto/quick/qquicklistview2/data/delegateChooserEnumRole.qml
new file mode 100644
index 0000000000..66e92c5616
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/delegateChooserEnumRole.qml
@@ -0,0 +1,41 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import Qt.labs.qmlmodels
+import Test
+
+ListView {
+ width: 300; height: 300
+ model: TypeRoleModel {}
+ delegate: DelegateChooser {
+ role: "type"
+ DelegateChoice {
+ roleValue: 0
+ Text {
+ property int delegateType: 0
+ text: model.text + " of type " + model.type
+ }
+ }
+ DelegateChoice {
+ roleValue: "Markdown"
+ Text {
+ property int delegateType: 1
+ text: model.text + " of **type** " + model.type
+ textFormat: Text.MarkdownText
+ }
+ }
+ DelegateChoice {
+ roleValue: TypeRoleModel.Rect
+ Rectangle {
+ property int delegateType: 2
+ width: 300; height: 20
+ color: "wheat"
+ Text {
+ text: model.text + " of type " + model.type
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/delegateContextHandling.qml b/tests/auto/quick/qquicklistview2/data/delegateContextHandling.qml
new file mode 100644
index 0000000000..4c513df905
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/delegateContextHandling.qml
@@ -0,0 +1,75 @@
+pragma ComponentBehavior: Bound
+
+import QtQuick
+import QtQuick.Window
+
+Item {
+ id: win
+ height: 640
+ width: 480
+
+ property string currentModel: 'foo'
+
+ function toggle() : Item {
+ var ret = listView.itemAtIndex(0);
+ win.currentModel = win.currentModel === 'foo' ? 'bar' : 'foo'
+
+ switch (win.currentModel) {
+ case 'foo':
+ if (listView.model) {
+ listView.model.destroy()
+ }
+ listView.model = fooModelComponent.createObject(win)
+ break
+
+ case 'bar':
+ if (listView.model) {
+ listView.model.destroy()
+ }
+ listView.model = barModelComponent.createObject(win)
+ break
+ }
+
+ return ret;
+ }
+
+ Component {
+ id: fooModelComponent
+ ListModel {
+ ListElement { textValue: "foo1" }
+ }
+ }
+
+ Component {
+ id: barModelComponent
+ ListModel {
+ ListElement { textValue: "bar1" }
+ }
+ }
+
+ ListView {
+ states: [
+ State {
+ when: win.currentModel === 'bar'
+ PropertyChanges {
+ listView.section.property: 'sectionProp'
+ }
+ }
+ ]
+
+ id: listView
+ model: fooModelComponent.createObject(win)
+ anchors.fill: parent
+
+ section.delegate: Text {
+ required property string section
+ text: section
+ }
+
+ delegate: Text {
+ id: delg
+ text: delg.textValue
+ required property string textValue
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/delegateModelRefresh.qml b/tests/auto/quick/qquicklistview2/data/delegateModelRefresh.qml
new file mode 100644
index 0000000000..7a22f1a0f4
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/delegateModelRefresh.qml
@@ -0,0 +1,53 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+import QtQml.Models
+
+ApplicationWindow {
+ id: window
+ visible: true
+ width: 400
+ height: 800
+ property bool done: false
+
+ ListView {
+ model: delegateModel
+ anchors.fill: parent
+ }
+
+ DelegateModel {
+ id: delegateModel
+ model: ListModel {
+ ListElement {
+ available: true
+ }
+ ListElement {
+ available: true
+ }
+ ListElement {
+ available: true
+ }
+ }
+
+ Component.onCompleted: {
+ delegateModel.refresh()
+ done = true;
+ }
+ function refresh() {
+ var rowCount = delegateModel.model.count;
+ const flatItemsList = []
+ for (var i = 0; i < rowCount; i++) {
+ var entry = delegateModel.model.get(i);
+ flatItemsList.push(entry)
+ }
+
+ for (i = 0; i < flatItemsList.length; ++i) {
+ var item = flatItemsList[i]
+ if (item !== null)
+ items.insert(item)
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/delegateWithMouseArea.qml b/tests/auto/quick/qquicklistview2/data/delegateWithMouseArea.qml
new file mode 100644
index 0000000000..f447f913e6
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/delegateWithMouseArea.qml
@@ -0,0 +1,73 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Rectangle {
+
+ width: 240
+ height: 320
+ color: "#ffffff"
+
+ Component {
+ id: myDelegate
+ Rectangle {
+ id: wrapper
+ width: list.orientation == ListView.Vertical ? 240 : 20
+ height: list.orientation == ListView.Vertical ? 20 : 240
+ border.width: 1
+ border.color: "black"
+ MouseArea {
+ anchors.fill: parent
+ }
+ Text {
+ text: index + ":" + (list.orientation == ListView.Vertical ? parent.y : parent.x).toFixed(0)
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "white"
+ }
+ }
+
+ ListView {
+ id: list
+ objectName: "list"
+ focus: true
+ width: 240
+ height: 200
+ clip: true
+ model: 30
+ headerPositioning: ListView.OverlayHeader
+ delegate: myDelegate
+
+ header: Rectangle {
+ width: list.orientation == Qt.Vertical ? 240 : 30
+ height: list.orientation == Qt.Vertical ? 30 : 240
+ color: "green"
+ z: 11
+ Text {
+ anchors.centerIn: parent
+ text: "header " + (list.orientation == ListView.Vertical ? parent.y : parent.x).toFixed(1)
+ }
+ }
+ }
+
+ // debug
+ Rectangle {
+ color: "#40ff0000"
+ border.width: txt.x
+ border.color: "black"
+ radius: 5
+ width: txt.implicitWidth + 50
+ height: txt.implicitHeight + 2 * txt.x
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ anchors.left: parent.left
+
+ Text {
+ id: txt
+ x: 3
+ y: x
+ text: "header position: " + (list.orientation == ListView.Vertical ? list.headerItem.y : list.headerItem.x).toFixed(1)
+ + "\ncontent position: " + (list.orientation == ListView.Vertical ? list.contentY : list.contentX).toFixed(1)
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/fetchMore.qml b/tests/auto/quick/qquicklistview2/data/fetchMore.qml
new file mode 100644
index 0000000000..4ce53e4d28
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/fetchMore.qml
@@ -0,0 +1,21 @@
+import QtQuick
+import org.qtproject.Test
+
+ListView {
+ id: listView
+ width: 300
+ height: 150
+ flickDeceleration: 10000
+
+ model: FetchMoreModel
+ delegate: Text {
+ height: 50
+ text: model.display
+ }
+
+ Text {
+ anchors.right: parent.right
+ text: "count " + listView.count
+ color: listView.moving ? "red" : "blue"
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/footerUpdate.qml b/tests/auto/quick/qquicklistview2/data/footerUpdate.qml
new file mode 100644
index 0000000000..c5729ad633
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/footerUpdate.qml
@@ -0,0 +1,39 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Rectangle {
+ id: root
+ width: 800
+ height: 800
+ Component.onCompleted: { list.model.remove(0); }
+ ListView {
+ id: list
+ objectName: "list"
+ anchors.fill: parent
+ model: ListModel {
+ ListElement {
+ txt: "Foo"
+ }
+ }
+ delegate: Rectangle {
+ id: myDelegate
+ color: "red"
+ width: 800
+ height: 100
+ ListView.onRemove: SequentialAnimation {
+ PropertyAction { target: myDelegate; property: "ListView.delayRemove"; value: true }
+ NumberAnimation { target: myDelegate; property: "scale"; to: 0; duration: 1; }
+ PropertyAction { target: myDelegate; property: "ListView.delayRemove"; value: false }
+ }
+
+ }
+ footer: Rectangle {
+ id: listFooter
+ color: "blue"
+ width: 800
+ height: 100
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/highlightWithBound.qml b/tests/auto/quick/qquicklistview2/data/highlightWithBound.qml
new file mode 100644
index 0000000000..6cedd3e7d3
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/highlightWithBound.qml
@@ -0,0 +1,10 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+
+ListView {
+ model: 3
+ delegate: Item {}
+ highlight: Item {
+ objectName: "highlight"
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/innerRequired.qml b/tests/auto/quick/qquicklistview2/data/innerRequired.qml
new file mode 100644
index 0000000000..c0862cec0d
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/innerRequired.qml
@@ -0,0 +1,35 @@
+import QtQuick
+
+Item {
+ ListModel {
+ id: myModel
+ ListElement { type: "Dog"; age: 8; noise: "meow" }
+ ListElement { type: "Cat"; age: 5; noise: "woof" }
+ }
+
+ component SomeDelegate: Item {
+ required property int age
+ property string text
+ }
+
+ component AnotherDelegate: Item {
+ property int age
+ property string text
+
+ SomeDelegate {
+ age: 0
+ text: ""
+ }
+ }
+
+ ListView {
+ id: listView
+ model: myModel
+ width: 100
+ height: 100
+ delegate: AnotherDelegate {
+ age: model.age
+ text: model.noise
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/maxXExtent.qml b/tests/auto/quick/qquicklistview2/data/maxXExtent.qml
new file mode 100644
index 0000000000..d72f825654
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/maxXExtent.qml
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Item {
+ property alias view: view
+
+ ListView {
+ id: view
+ model: 10
+ width: 200
+ height: 200
+
+ Rectangle {
+ anchors.fill: parent
+ color: "transparent"
+ border.color: "darkorange"
+ }
+
+ delegate: Rectangle {
+ width: 100
+ height: 100
+ Text {
+ text: modelData
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/maxYExtent.qml b/tests/auto/quick/qquicklistview2/data/maxYExtent.qml
new file mode 100644
index 0000000000..b8a1f0e12b
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/maxYExtent.qml
@@ -0,0 +1,30 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Item {
+ property alias view: view
+
+ ListView {
+ id: view
+ model: 10
+ width: 200
+ height: 200
+ orientation: ListView.Horizontal
+
+ Rectangle {
+ anchors.fill: parent
+ color: "transparent"
+ border.color: "darkorange"
+ }
+
+ delegate: Rectangle {
+ width: 100
+ height: 100
+ Text {
+ text: modelData
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/metaSequenceAsModel.qml b/tests/auto/quick/qquicklistview2/data/metaSequenceAsModel.qml
new file mode 100644
index 0000000000..461450239f
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/metaSequenceAsModel.qml
@@ -0,0 +1,14 @@
+import QtQuick
+
+ListView {
+ id: view
+ width: 100
+ height: 100
+ property list<rect> rects: [ Qt.rect(1, 2, 3, 4), Qt.rect(5, 6, 7, 8) ]
+ property list<string> texts
+
+ model: rects
+ delegate: Item {
+ Component.onCompleted: view.texts.push(modelData.x + "/" + modelData.y)
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/mouseAreaDelegate.qml b/tests/auto/quick/qquicklistview2/data/mouseAreaDelegate.qml
new file mode 100644
index 0000000000..ad556913a5
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/mouseAreaDelegate.qml
@@ -0,0 +1,30 @@
+import QtQuick 2.15
+
+ListView {
+ id: root
+ width: 320
+ height: 480
+ model: 100
+
+ property var pressedDelegates: []
+ property var releasedDelegates: []
+ property var tappedDelegates: []
+ property var canceledDelegates: []
+
+ delegate: MouseArea {
+ height: 100
+ width: 320
+
+ onPressed: root.pressedDelegates.push(index)
+ onReleased: root.releasedDelegates.push(index)
+ onClicked: root.tappedDelegates.push(index)
+ onCanceled: root.canceledDelegates.push(index)
+
+ Rectangle {
+ id: buttonArea
+ anchors.fill: parent
+ border.color: "#41cd52"
+ color: parent.pressed ? "lightsteelblue" : "beige"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/noCrashOnIndexChange.qml b/tests/auto/quick/qquicklistview2/data/noCrashOnIndexChange.qml
new file mode 100644
index 0000000000..6065d09981
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/noCrashOnIndexChange.qml
@@ -0,0 +1,48 @@
+import QtQuick
+import QtQml.Models
+
+Item {
+ ListModel {
+ id: myModel
+ ListElement { role_display: "One"; role_value: 0; }
+ ListElement { role_display: "One"; role_value: 2; }
+ ListElement { role_display: "One"; role_value: 3; }
+ ListElement { role_display: "One"; role_value: 4; }
+ ListElement { role_details: "Two"; role_value: 5; }
+ ListElement { role_details: "Three"; role_value: 6; }
+ ListElement { role_details: "Four"; role_value: 7; }
+ ListElement { role_details: "Five"; role_value: 8; }
+ ListElement { role_details: "Six"; role_value: 9; }
+ ListElement { role_keyID: "Seven"; role_value: 10; }
+ ListElement { role_keyID: "Eight"; role_value: 11; }
+ ListElement { role_keyID: "hello"; role_value: 12; }
+ }
+
+ DelegateModel {
+ id: displayDelegateModel
+ delegate: Text { text: role_display }
+ model: myModel
+ groups: [
+ DelegateModelGroup {
+ includeByDefault: false
+ name: "displayField"
+ }
+ ]
+ filterOnGroup: "displayField"
+ Component.onCompleted: {
+ var rowCount = myModel.count;
+ items.remove(0, rowCount);
+ for (var i = 0; i < rowCount; i++) {
+ var entry = myModel.get(i);
+ if (entry.role_display) {
+ items.insert(entry, "displayField");
+ }
+ }
+ }
+ }
+
+ ListView {
+ model: displayDelegateModel
+ }
+}
+
diff --git a/tests/auto/quick/qquicklistview2/data/qtbug104679_footer.qml b/tests/auto/quick/qquicklistview2/data/qtbug104679_footer.qml
new file mode 100644
index 0000000000..919cf4d2ec
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/qtbug104679_footer.qml
@@ -0,0 +1,21 @@
+import QtQuick
+
+Rectangle {
+ width: 640
+ height: 480
+
+ ListView {
+ anchors.fill: parent
+ spacing: 5
+
+ footerPositioning: ListView.PullBackFooter
+ footer: Rectangle { width: ListView.view.width; color: "blue"; implicitHeight: 46 }
+
+ model: 3 // crashed if less items than a full list page
+ delegate: Rectangle {
+ width: ListView.view.width
+ height: 50
+ color: index % 2 ? "black" : "gray"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/qtbug104679_header.qml b/tests/auto/quick/qquicklistview2/data/qtbug104679_header.qml
new file mode 100644
index 0000000000..40ddf27988
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/qtbug104679_header.qml
@@ -0,0 +1,21 @@
+import QtQuick
+
+Rectangle {
+ width: 640
+ height: 480
+
+ ListView {
+ anchors.fill: parent
+ spacing: 5
+
+ headerPositioning: ListView.PullBackHeader
+ header: Rectangle { width: ListView.view.width; color: "red"; implicitHeight: 46 }
+
+ model: 3 // crashed if less items than a full list page
+ delegate: Rectangle {
+ width: ListView.view.width
+ height: 50
+ color: index % 2 ? "black" : "gray"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/qtbug86744.qml b/tests/auto/quick/qquicklistview2/data/qtbug86744.qml
new file mode 100644
index 0000000000..d8b89a147d
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/qtbug86744.qml
@@ -0,0 +1,25 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQml.Models
+
+Item {
+ height: 200
+ width: 100
+ DelegateModel {
+ id: dm
+ model: 2
+ delegate: Item {
+ width: 100
+ height: 20
+ property bool isCurrent: ListView.isCurrentItem
+ }
+ }
+ ListView {
+ objectName: "listView"
+ model: dm
+ currentIndex: 1
+ anchors.fill: parent
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/qtbug98315.qml b/tests/auto/quick/qquicklistview2/data/qtbug98315.qml
new file mode 100644
index 0000000000..4035915c6d
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/qtbug98315.qml
@@ -0,0 +1,98 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQml.Models
+
+Item {
+ width: 500
+ height: 200
+
+ property list<QtObject> myModel: [
+ QtObject {
+ objectName: "Item 0"
+ property bool selected: true
+ },
+ QtObject {
+ objectName: "Item 1"
+ property bool selected: false
+ },
+ QtObject {
+ objectName: "Item 2"
+ property bool selected: false
+ },
+ QtObject {
+ objectName: "Item 3"
+ property bool selected: true
+ },
+ QtObject {
+ objectName: "Item 4"
+ property bool selected: true
+ },
+ QtObject {
+ objectName: "Item 5"
+ property bool selected: true
+ },
+ QtObject {
+ objectName: "Item 6"
+ property bool selected: false
+ }
+ ]
+
+ ListView {
+ objectName: "listView"
+ id: listview
+ width: 500
+ height: 200
+
+ focus: true
+ clip: true
+ spacing: 2
+ orientation: ListView.Horizontal
+ highlightMoveDuration: 300
+ highlightMoveVelocity: -1
+ preferredHighlightBegin: (500 - 100) / 2
+ preferredHighlightEnd: (500 + 100) / 2
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ cacheBuffer: 500
+ currentIndex: 1
+
+ model: DelegateModel {
+ id: delegateModel
+ filterOnGroup: "visible"
+ model: myModel
+ groups: [
+ DelegateModelGroup {
+ name: "visible"
+ includeByDefault: true
+ }
+ ]
+ delegate: Rectangle {
+ id: tile
+ objectName: model.modelData.objectName
+
+ width: 100
+ height: 100
+ border.width: 0
+ anchors.verticalCenter: parent.verticalCenter
+
+ visible: model.modelData.selected
+ Component.onCompleted: {
+ DelegateModel.inPersistedItems = true
+ DelegateModel.inVisible = Qt.binding(function () {
+ return model.modelData.selected
+ })
+ }
+
+ property bool isCurrent: ListView.isCurrentItem
+ color: isCurrent ? "red" : "green"
+
+ Text {
+ id: valueText
+ anchors.centerIn: parent
+ text: model.modelData.objectName
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/qtbug_92809.qml b/tests/auto/quick/qquicklistview2/data/qtbug_92809.qml
new file mode 100644
index 0000000000..7507e83f73
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/qtbug_92809.qml
@@ -0,0 +1,71 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Rectangle {
+ id: root
+ width: 800
+ height: 480
+
+ property list<QtObject> myModel: [
+ QtObject { property string name: "Item 0"; property bool selected: true },
+ QtObject { property string name: "Item 1"; property bool selected: true },
+ QtObject { property string name: "Item 2"; property bool selected: true },
+ QtObject { property string name: "Item 3"; property bool selected: true },
+ QtObject { property string name: "Item 4"; property bool selected: true },
+ QtObject { property string name: "Item 5"; property bool selected: true },
+ QtObject { property string name: "Item 6"; property bool selected: true },
+ QtObject { property string name: "Item 7"; property bool selected: true },
+ QtObject { property string name: "Item 8"; property bool selected: true },
+ QtObject { property string name: "Item 9"; property bool selected: true },
+ QtObject { property string name: "Press Enter here"; property bool selected: true }
+ ]
+
+ DelegateModel {
+ objectName: "model"
+ id: visualModel
+ model: myModel
+ filterOnGroup: "selected"
+
+ groups: [
+ DelegateModelGroup {
+ name: "selected"
+ includeByDefault: true
+ }
+ ]
+
+ delegate: Rectangle {
+ width: 180
+ height: 180
+ visible: DelegateModel.inSelected
+ color: ListView.isCurrentItem ? "orange" : "yellow"
+ Component.onCompleted: {
+ DelegateModel.inPersistedItems = true
+ DelegateModel.inSelected = Qt.binding(function() { return model.selected })
+ }
+ }
+ }
+
+ ListView {
+ objectName: "list"
+ anchors.fill: parent
+ spacing: 180/15
+ orientation: ListView.Horizontal
+ model: visualModel
+ focus: true
+ currentIndex: 0
+ preferredHighlightBegin: (width-180)/2
+ preferredHighlightEnd: (width+180)/2
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ highlightMoveDuration: 300
+ highlightMoveVelocity: -1
+ cacheBuffer: 0
+
+ onCurrentIndexChanged: {
+ if (currentIndex === 10) {
+ myModel[6].selected = !myModel[6].selected
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/sectionBoundComponent.qml b/tests/auto/quick/qquicklistview2/data/sectionBoundComponent.qml
new file mode 100644
index 0000000000..74ab6b59fa
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/sectionBoundComponent.qml
@@ -0,0 +1,14 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+ListView {
+ id: view
+ width: 100
+ height: 100
+ model: ListModel {
+ ListElement { name: "foo"; age: 42 }
+ ListElement { name: "bar"; age: 13 }
+ }
+ delegate: Text { required property string name; text: name}
+ section.property: "age"
+ section.delegate: Rectangle { color: "gray"; width: view.width; height: 20; required property string section; Text {text: parent.section} }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/sectionGeometryChange.qml b/tests/auto/quick/qquicklistview2/data/sectionGeometryChange.qml
new file mode 100644
index 0000000000..6981af51ec
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/sectionGeometryChange.qml
@@ -0,0 +1,58 @@
+import QtQuick
+import QtQuick.Controls
+
+Rectangle {
+ width: 640
+ height: 480
+ color: "#FFFFFF"
+ ListView {
+ objectName: "list"
+ anchors.fill: parent
+
+ delegate: Rectangle {
+ objectName: value
+ implicitHeight: text.implicitHeight
+ color: "#ff3"
+
+ Text {
+ id: text
+ width: parent.width
+ padding: 5
+ font.pixelSize: 20
+ text: value
+ }
+ }
+
+ section {
+ property: "section"
+
+ delegate: Rectangle {
+ objectName: section
+ width: parent.width
+ implicitHeight: text.implicitHeight
+ color: "#3ff"
+
+ Text {
+ id: text
+ width: parent.width
+ padding: 5
+ font.pixelSize: 20
+ text: section
+ wrapMode: Text.Wrap
+ }
+ }
+ }
+
+ model: ListModel {
+ ListElement { value: "Element1"; section: "Section1" }
+ ListElement { value: "Element2"; section: "Section1" }
+ ListElement { value: "Element3"; section: "Section1" }
+ ListElement { value: "Element4"; section: "Section2" }
+ ListElement { value: "Element5"; section: "Section2" }
+ ListElement { value: "Element6"; section: "Section2" }
+ ListElement { value: "Element7"; section: "Section2" }
+ ListElement { value: "Element8"; section: "Section3" }
+ ListElement { value: "Element9"; section: "Section3" }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/sectionsNoOverlap.qml b/tests/auto/quick/qquicklistview2/data/sectionsNoOverlap.qml
new file mode 100644
index 0000000000..3a22626032
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/sectionsNoOverlap.qml
@@ -0,0 +1,77 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+Rectangle {
+ property string sectionProperty: "section"
+ property int sectionPositioning: ViewSection.InlineLabels
+
+ width: 640
+ height: 480
+ color: "#FFFFFF"
+
+ resources: [
+ Component {
+ id: myDelegate
+ Text {
+ objectName: model.title
+ width: parent.width
+ height: 40
+ text: "NormalDelegate: " + model.title
+ visible: model.isVisible
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+ ]
+ ListView {
+ id: list
+ objectName: "list"
+ anchors.fill: parent
+ clip: true
+
+ model: ListModel {
+ ListElement {
+ title: "element1"
+ isVisible: true
+ section: "section1"
+ }
+ ListElement {
+ title: "element2"
+ isVisible: true
+ section: "section1"
+ }
+ ListElement {
+ title: "element3"
+ isVisible: true
+ section: "section2"
+ }
+ ListElement {
+ title: "element4"
+ isVisible: true
+ section: "section2"
+ }
+ }
+
+ delegate: myDelegate
+
+ section.property: "section"
+ section.criteria: ViewSection.FullString
+ section.delegate: Component {
+ Text {
+ id: sectionDelegate
+ objectName: section
+ visible: false
+ width: parent.width
+ height: visible ? 48 : 0
+ text: "Section delegate: " + section
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideMiddle
+ Component.onCompleted: function(){
+ Qt.callLater(function(){sectionDelegate.visible = true})
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/singletonModelLifetime.qml b/tests/auto/quick/qquicklistview2/data/singletonModelLifetime.qml
new file mode 100644
index 0000000000..f230786723
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/singletonModelLifetime.qml
@@ -0,0 +1,32 @@
+import QtQuick 2.15
+import QtQuick.Window 2.15
+import test 1.0
+
+Window {
+ id: root
+ visible: true
+ width: 800
+ height: 680
+ property bool alive: false
+
+ Component {
+ id: view
+ ListView {
+ model: SingletonModel
+ }
+ }
+ function compare(a,b) {
+ root.alive = (a === b)
+ }
+
+ function test_singletonModelCrash() {
+ SingletonModel.objectName = "model"
+ var o = view.createObject(root)
+ o.destroy()
+ Qt.callLater(function() {
+ compare(SingletonModel.objectName, "model")
+ })
+ }
+
+ Component.onCompleted: root.test_singletonModelCrash()
+}
diff --git a/tests/auto/quick/qquicklistview2/data/snapOneItem.qml b/tests/auto/quick/qquicklistview2/data/snapOneItem.qml
new file mode 100644
index 0000000000..a27f220865
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/snapOneItem.qml
@@ -0,0 +1,34 @@
+import QtQuick
+
+ListView {
+ id: list
+ snapMode: ListView.SnapOneItem
+ model: 4
+ width: 200
+ height: 200
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ highlight: Rectangle { width: 200; height: 200; color: "yellow" }
+ delegate: Rectangle {
+ id: wrapper
+ width: list.width
+ height: list.height
+ Column {
+ Text {
+ text: index
+ }
+ Text {
+ text: wrapper.x + ", " + wrapper.y
+ }
+ }
+ color: ListView.isCurrentItem ? "lightsteelblue" : "transparent"
+ }
+ // speed up test runs
+ flickDeceleration: 5000
+ rebound: Transition {
+ NumberAnimation {
+ properties: "x,y"
+ duration: 30
+ easing.type: Easing.OutBounce
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/urlListModel.qml b/tests/auto/quick/qquicklistview2/data/urlListModel.qml
new file mode 100644
index 0000000000..38237234e0
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/urlListModel.qml
@@ -0,0 +1,22 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Rectangle {
+ id: root
+
+ property var model
+ property alias view: view
+
+ ListView {
+ id: view
+ anchors.fill: parent
+ objectName: "view"
+ model: root.model
+ delegate: Text {
+ height: view.width
+ text: modelData
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklistview2/data/viewportAvoidUndesiredMovementOnSetCurrentIndex.qml b/tests/auto/quick/qquicklistview2/data/viewportAvoidUndesiredMovementOnSetCurrentIndex.qml
new file mode 100644
index 0000000000..cd3865d55b
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/data/viewportAvoidUndesiredMovementOnSetCurrentIndex.qml
@@ -0,0 +1,47 @@
+import QtQuick
+
+Item {
+ id: root
+ width: 400
+ height: 600
+
+ ListView {
+ id: rawList
+ objectName: "list"
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: 300
+
+ // full disabling of automatic viewport positioning
+ highlightFollowsCurrentItem: false
+ snapMode: ListView.NoSnap
+ highlightRangeMode: ListView.NoHighlightRange
+
+ delegate: Rectangle {
+ color: model.index === rawList.currentIndex ? "red" : "white"
+ border.color: rawList.currentItem === this ? "red" : "black"
+ height: 100
+ width: 400
+
+ Text {
+ anchors.centerIn: parent
+ text: model.index
+ font.pixelSize: 50
+ }
+
+ MouseArea {
+ // only for using this file to do manual testing
+ // autotest calls setCurrentIndex
+ anchors.fill: parent
+
+ onClicked: {
+ rawList.currentIndex = model.index;
+ }
+ }
+ }
+
+ model: 30
+ }
+
+}
diff --git a/tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp b/tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp
new file mode 100644
index 0000000000..bdac2112b6
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/tst_qquicklistview2.cpp
@@ -0,0 +1,1255 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+#include <QtQuick/qquickview.h>
+#include <QtQuick/private/qquickitemview_p_p.h>
+#include <QtQuick/private/qquicklistview_p.h>
+#include <QtQuickTest/QtQuickTest>
+#include <QStringListModel>
+#include <QQmlApplicationEngine>
+
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+
+using namespace QQuickViewTestUtils;
+using namespace QQuickVisualTestUtils;
+
+class tst_QQuickListView2 : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_QQuickListView2();
+
+private slots:
+ void urlListModel();
+ void dragDelegateWithMouseArea_data();
+ void dragDelegateWithMouseArea();
+ void delegateChooserEnumRole();
+ void QTBUG_92809();
+ void footerUpdate();
+ void singletonModelLifetime();
+ void delegateModelRefresh();
+ void wheelSnap();
+ void wheelSnap_data();
+
+ void sectionsNoOverlap();
+ void metaSequenceAsModel();
+ void noCrashOnIndexChange();
+ void innerRequired();
+ void boundDelegateComponent();
+ void tapDelegateDuringFlicking_data();
+ void tapDelegateDuringFlicking();
+ void flickDuringFlicking_data();
+ void flickDuringFlicking();
+ void maxExtent_data();
+ void maxExtent();
+ void isCurrentItem_DelegateModel();
+ void isCurrentItem_NoRegressionWithDelegateModelGroups();
+
+ void pullbackSparseList();
+ void highlightWithBound();
+ void sectionIsCompatibleWithBoundComponents();
+ void sectionGeometryChange();
+ void areaZeroviewDoesNotNeedlesslyPopulateWholeModel();
+ void viewportAvoidUndesiredMovementOnSetCurrentIndex();
+
+ void delegateContextHandling();
+ void fetchMore_data();
+ void fetchMore();
+
+ void changingOrientationResetsPreviousAxisValues_data();
+ void changingOrientationResetsPreviousAxisValues();
+ void bindingDirectlyOnPositionInHeaderAndFooterDelegates_data();
+ void bindingDirectlyOnPositionInHeaderAndFooterDelegates();
+
+ void clearObjectListModel();
+
+private:
+ void flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to);
+ QScopedPointer<QPointingDevice> touchDevice = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
+};
+
+tst_QQuickListView2::tst_QQuickListView2()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
+void tst_QQuickListView2::urlListModel()
+{
+ QScopedPointer<QQuickView> window(createView());
+ QVERIFY(window);
+
+ QList<QUrl> model = { QUrl::fromLocalFile("abc"), QUrl::fromLocalFile("123") };
+ window->setInitialProperties({{ "model", QVariant::fromValue(model) }});
+
+ window->setSource(testFileUrl("urlListModel.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *view = window->rootObject()->property("view").value<QQuickListView*>();
+ QVERIFY(view);
+ if (QQuickTest::qIsPolishScheduled(view))
+ QVERIFY(QQuickTest::qWaitForPolish(view));
+ QCOMPARE(view->count(), model.size());
+}
+
+static void dragListView(QWindow *window, QPoint *startPos, const QPoint &delta)
+{
+ auto drag_helper = [&](QWindow *window, QPoint *startPos, const QPoint &d) {
+ QPoint pos = *startPos;
+ const int dragDistance = d.manhattanLength();
+ const QPoint unitVector(qBound(-1, d.x(), 1), qBound(-1, d.y(), 1));
+ for (int i = 0; i < dragDistance; ++i) {
+ QTest::mouseMove(window, pos);
+ pos += unitVector;
+ }
+ // Move to the final position
+ pos = *startPos + d;
+ QTest::mouseMove(window, pos);
+ *startPos = pos;
+ };
+
+ if (delta.manhattanLength() == 0)
+ return;
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
+ const QPoint unitVector(qBound(-1, delta.x(), 1), qBound(-1, delta.y(), 1));
+ // go just beyond the drag theshold
+ drag_helper(window, startPos, unitVector * (dragThreshold + 1));
+ drag_helper(window, startPos, unitVector);
+
+ // next drag will actually scroll the listview
+ drag_helper(window, startPos, delta);
+}
+
+void tst_QQuickListView2::dragDelegateWithMouseArea_data()
+{
+ QTest::addColumn<QQuickItemView::LayoutDirection>("layoutDirection");
+
+ for (int layDir = QQuickItemView::LeftToRight; layDir <= (int)QQuickItemView::VerticalBottomToTop; layDir++) {
+ const char *enumValueName = QMetaEnum::fromType<QQuickItemView::LayoutDirection>().valueToKey(layDir);
+ QTest::newRow(enumValueName) << static_cast<QQuickItemView::LayoutDirection>(layDir);
+ }
+}
+
+void tst_QQuickListView2::viewportAvoidUndesiredMovementOnSetCurrentIndex()
+{
+ QScopedPointer<QQuickView> window(createView());
+ QVERIFY(window);
+ window->setFlag(Qt::FramelessWindowHint);
+ window->setSource(testFileUrl("viewportAvoidUndesiredMovementOnSetCurrentIndex.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+ QVERIFY(window->rootObject());
+ QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
+ QVERIFY(listview);
+ listview->setCurrentIndex(2); // change current item
+ // partially obscure first item
+ QCOMPARE(listview->contentY(), 0);
+ listview->setContentY(50);
+ QTRY_COMPARE(listview->contentY(), 50);
+ listview->setCurrentIndex(0); // change current item back to first one
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+ // that shouldn't have caused any movement
+ QCOMPARE(listview->contentY(), 50);
+
+ // that even applies to the case where the current item is completely out of the viewport
+ listview->setCurrentIndex(25);
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+ QCOMPARE(listview->contentY(), 50);
+}
+
+void tst_QQuickListView2::dragDelegateWithMouseArea()
+{
+ QFETCH(QQuickItemView::LayoutDirection, layoutDirection);
+
+ QScopedPointer<QQuickView> window(createView());
+ QVERIFY(window);
+ window->setFlag(Qt::FramelessWindowHint);
+ window->setSource(testFileUrl("delegateWithMouseArea.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
+ QVERIFY(listview != nullptr);
+
+ const bool horizontal = layoutDirection < QQuickItemView::VerticalTopToBottom;
+ listview->setOrientation(horizontal ? QQuickListView::Horizontal : QQuickListView::Vertical);
+
+ if (horizontal)
+ listview->setLayoutDirection(static_cast<Qt::LayoutDirection>(layoutDirection));
+ else
+ listview->setVerticalLayoutDirection(static_cast<QQuickItemView::VerticalLayoutDirection>(layoutDirection));
+
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+
+ auto contentPosition = [&](QQuickListView *listview) {
+ return (listview->orientation() == QQuickListView::Horizontal ? listview->contentX(): listview->contentY());
+ };
+
+ qreal expectedContentPosition = contentPosition(listview);
+ QPoint startPos = (QPointF(listview->width(), listview->height())/2).toPoint();
+ QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, startPos, 200);
+
+ QPoint dragDelta(0, -10);
+
+ if (layoutDirection == QQuickItemView::RightToLeft || layoutDirection == QQuickItemView::VerticalBottomToTop)
+ dragDelta = -dragDelta;
+ expectedContentPosition -= dragDelta.y();
+ if (horizontal)
+ dragDelta = dragDelta.transposed();
+
+ dragListView(window.data(), &startPos, dragDelta);
+
+ QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, startPos, 200); // Wait 200 ms before we release to avoid trigger a flick
+
+ // wait for the "fixup" animation to finish
+ QVERIFY(QTest::qWaitFor([&]()
+ { return !listview->isMoving();}
+ ));
+
+ QCOMPARE(contentPosition(listview), expectedContentPosition);
+}
+
+
+void tst_QQuickListView2::delegateChooserEnumRole()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("delegateChooserEnumRole.qml")));
+ QQuickListView *listview = qobject_cast<QQuickListView*>(window.rootObject());
+ QVERIFY(listview);
+ QTRY_COMPARE(listview->count(), 3);
+ QCOMPARE(listview->itemAtIndex(0)->property("delegateType").toInt(), 0);
+ QCOMPARE(listview->itemAtIndex(1)->property("delegateType").toInt(), 1);
+ QCOMPARE(listview->itemAtIndex(2)->property("delegateType").toInt(), 2);
+}
+
+void tst_QQuickListView2::QTBUG_92809()
+{
+ QScopedPointer<QQuickView> window(createView());
+ QTRY_VERIFY(window);
+ window->setSource(testFileUrl("qtbug_92809.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
+ QTRY_VERIFY(listview != nullptr);
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+ listview->setCurrentIndex(1);
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+ listview->setCurrentIndex(2);
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+ listview->setCurrentIndex(3);
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+ QTest::qWait(500);
+ listview->setCurrentIndex(10);
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+ QTest::qWait(500);
+ int currentIndex = listview->currentIndex();
+ QTRY_COMPARE(currentIndex, 9);
+}
+
+void tst_QQuickListView2::footerUpdate()
+{
+ QScopedPointer<QQuickView> window(createView());
+ QTRY_VERIFY(window);
+ window->setSource(testFileUrl("footerUpdate.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
+ QTRY_VERIFY(listview != nullptr);
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+ QQuickItem *footer = listview->footerItem();
+ QTRY_VERIFY(footer);
+ QVERIFY(QQuickTest::qWaitForPolish(footer));
+ QTRY_COMPARE(footer->y(), 0);
+}
+
+void tst_QQuickListView2::sectionsNoOverlap()
+{
+ QScopedPointer<QQuickView> window(createView());
+ QTRY_VERIFY(window);
+ window->setSource(testFileUrl("sectionsNoOverlap.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
+ QTRY_VERIFY(listview != nullptr);
+
+ QQuickItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem != nullptr);
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+
+ const unsigned int sectionCount = 2, normalDelegateCount = 2;
+ const unsigned int expectedSectionHeight = 48;
+ const unsigned int expectedNormalDelegateHeight = 40;
+
+ unsigned int normalDelegateCounter = 0;
+ for (unsigned int sectionIndex = 0; sectionIndex < sectionCount; ++sectionIndex) {
+ QQuickItem *sectionDelegate =
+ findItem<QQuickItem>(contentItem, "section" + QString::number(sectionIndex + 1));
+ QVERIFY(sectionDelegate);
+
+ QCOMPARE(sectionDelegate->height(), expectedSectionHeight);
+ QVERIFY(sectionDelegate->isVisible());
+ QCOMPARE(sectionDelegate->y(),
+ qreal(sectionIndex * expectedSectionHeight
+ + (sectionIndex * normalDelegateCount * expectedNormalDelegateHeight)));
+
+ for (; normalDelegateCounter < ((sectionIndex + 1) * normalDelegateCount);
+ ++normalDelegateCounter) {
+ QQuickItem *normalDelegate = findItem<QQuickItem>(
+ contentItem, "element" + QString::number(normalDelegateCounter + 1));
+ QVERIFY(normalDelegate);
+
+ QCOMPARE(normalDelegate->height(), expectedNormalDelegateHeight);
+ QVERIFY(normalDelegate->isVisible());
+ QCOMPARE(normalDelegate->y(),
+ qreal((sectionIndex + 1) * expectedSectionHeight
+ + normalDelegateCounter * expectedNormalDelegateHeight
+ + listview->spacing() * normalDelegateCounter));
+ }
+ }
+}
+
+void tst_QQuickListView2::metaSequenceAsModel()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("metaSequenceAsModel.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+ QStringList strings = qvariant_cast<QStringList>(o->property("texts"));
+ QCOMPARE(strings.size(), 2);
+ QCOMPARE(strings[0], QStringLiteral("1/2"));
+ QCOMPARE(strings[1], QStringLiteral("5/6"));
+}
+
+void tst_QQuickListView2::noCrashOnIndexChange()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("noCrashOnIndexChange.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QObject *delegateModel = qmlContext(o.data())->objectForName("displayDelegateModel");
+ QVERIFY(delegateModel);
+
+ QObject *items = qvariant_cast<QObject *>(delegateModel->property("items"));
+ QCOMPARE(items->property("name").toString(), QStringLiteral("items"));
+ QCOMPARE(items->property("count").toInt(), 4);
+}
+
+void tst_QQuickListView2::innerRequired()
+{
+ QQmlEngine engine;
+ const QUrl url(testFileUrl("innerRequired.qml"));
+ QQmlComponent component(&engine, url);
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY2(!o.isNull(), qPrintable(component.errorString()));
+
+ QQuickListView *a = qobject_cast<QQuickListView *>(
+ qmlContext(o.data())->objectForName(QStringLiteral("listView")));
+ QVERIFY(a);
+
+ QCOMPARE(a->count(), 2);
+ QCOMPARE(a->itemAtIndex(0)->property("age").toInt(), 8);
+ QCOMPARE(a->itemAtIndex(0)->property("text").toString(), u"meow");
+ QCOMPARE(a->itemAtIndex(1)->property("age").toInt(), 5);
+ QCOMPARE(a->itemAtIndex(1)->property("text").toString(), u"woof");
+}
+
+void tst_QQuickListView2::boundDelegateComponent()
+{
+ QQmlEngine engine;
+ const QUrl url(testFileUrl("boundDelegateComponent.qml"));
+ QQmlComponent c(&engine, url);
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+
+ QTest::ignoreMessage(
+ QtWarningMsg, qPrintable(QLatin1String("%1:14: ReferenceError: index is not defined")
+ .arg(url.toString())));
+
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QQmlContext *context = qmlContext(o.data());
+
+ QObject *inner = context->objectForName(QLatin1String("listView"));
+ QVERIFY(inner != nullptr);
+ QQuickListView *listView = qobject_cast<QQuickListView *>(inner);
+ QVERIFY(listView != nullptr);
+ QObject *item = listView->itemAtIndex(0);
+ QVERIFY(item);
+ QCOMPARE(item->objectName(), QLatin1String("fooouterundefined"));
+
+ QObject *inner2 = context->objectForName(QLatin1String("listView2"));
+ QVERIFY(inner2 != nullptr);
+ QQuickListView *listView2 = qobject_cast<QQuickListView *>(inner2);
+ QVERIFY(listView2 != nullptr);
+ QObject *item2 = listView2->itemAtIndex(0);
+ QVERIFY(item2);
+ QCOMPARE(item2->objectName(), QLatin1String("fooouter0"));
+
+ QQmlComponent *comp = qobject_cast<QQmlComponent *>(
+ context->objectForName(QLatin1String("outerComponent")));
+ QVERIFY(comp != nullptr);
+
+ for (int i = 0; i < 3; ++i) {
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ qPrintable(QLatin1String("%1:51:21: ReferenceError: model is not defined")
+ .arg(url.toString())));
+ }
+
+ QScopedPointer<QObject> outerItem(comp->create(context));
+ QVERIFY(!outerItem.isNull());
+ QQuickListView *innerListView = qobject_cast<QQuickListView *>(
+ qmlContext(outerItem.data())->objectForName(QLatin1String("innerListView")));
+ QVERIFY(innerListView != nullptr);
+ QCOMPARE(innerListView->count(), 3);
+ for (int i = 0; i < 3; ++i)
+ QVERIFY(innerListView->itemAtIndex(i)->objectName().isEmpty());
+}
+
+void tst_QQuickListView2::tapDelegateDuringFlicking_data()
+{
+ QTest::addColumn<QByteArray>("qmlFile");
+ QTest::addColumn<QQuickFlickable::BoundsBehavior>("boundsBehavior");
+ QTest::addColumn<bool>("expectCanceled");
+
+ QTest::newRow("Button StopAtBounds") << QByteArray("buttonDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds) << false;
+ QTest::newRow("MouseArea StopAtBounds") << QByteArray("mouseAreaDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds) << true;
+ QTest::newRow("Button DragOverBounds") << QByteArray("buttonDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds) << false;
+ QTest::newRow("MouseArea DragOverBounds") << QByteArray("mouseAreaDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds) << true;
+ QTest::newRow("Button OvershootBounds") << QByteArray("buttonDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds) << false;
+ QTest::newRow("MouseArea OvershootBounds") << QByteArray("mouseAreaDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds) << true;
+ QTest::newRow("Button DragAndOvershootBounds") << QByteArray("buttonDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds) << false;
+ QTest::newRow("MouseArea DragAndOvershootBounds") << QByteArray("mouseAreaDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds) << true;
+}
+
+void tst_QQuickListView2::tapDelegateDuringFlicking() // QTBUG-103832
+{
+ QFETCH(QByteArray, qmlFile);
+ QFETCH(QQuickFlickable::BoundsBehavior, boundsBehavior);
+ QFETCH(bool, expectCanceled);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl(qmlFile.constData())));
+ QQuickListView *listView = qobject_cast<QQuickListView*>(window.rootObject());
+ QVERIFY(listView);
+ listView->setBoundsBehavior(boundsBehavior);
+
+ flickWithTouch(&window, {100, 400}, {100, 100});
+ QTRY_VERIFY(listView->contentY() > 501); // let it flick some distance
+ QVERIFY(listView->isFlicking()); // we want to test the case when it's still moving while we tap
+ // @y = 400 we pressed the 4th delegate; started flicking, and the press was canceled
+ QCOMPARE(listView->property("pressedDelegates").toList().first(), 4);
+ // At first glance one would expect MouseArea and Button would be consistent about this;
+ // but in fact, before ListView takes over the grab via filtering,
+ // Button.pressed transitions to false because QQuickAbstractButtonPrivate::handleMove
+ // sees that the touchpoint has strayed outside its bounds, but it does NOT emit the canceled signal
+ if (expectCanceled) {
+ const QVariantList canceledDelegates = listView->property("canceledDelegates").toList();
+ QCOMPARE(canceledDelegates.size(), 1);
+ QCOMPARE(canceledDelegates.first(), 4);
+ }
+ QCOMPARE(listView->property("releasedDelegates").toList().size(), 0);
+
+ // press a delegate during flicking (at y > 501 + 100, so likely delegate 6)
+ QTest::touchEvent(&window, touchDevice.data()).press(0, {100, 100});
+ QQuickTouchUtils::flush(&window);
+ QTest::touchEvent(&window, touchDevice.data()).release(0, {100, 100});
+ QQuickTouchUtils::flush(&window);
+
+ const QVariantList pressedDelegates = listView->property("pressedDelegates").toList();
+ const QVariantList releasedDelegates = listView->property("releasedDelegates").toList();
+ const QVariantList tappedDelegates = listView->property("tappedDelegates").toList();
+ const QVariantList canceledDelegates = listView->property("canceledDelegates").toList();
+
+ qCDebug(lcTests) << "pressed" << pressedDelegates; // usually [4, 6]
+ qCDebug(lcTests) << "released" << releasedDelegates;
+ qCDebug(lcTests) << "tapped" << tappedDelegates;
+ qCDebug(lcTests) << "canceled" << canceledDelegates;
+
+ // which delegate received the second press, during flicking?
+ const int lastPressed = pressedDelegates.last().toInt();
+ QVERIFY(lastPressed > 5);
+ QCOMPARE(releasedDelegates.last(), lastPressed);
+ QCOMPARE(tappedDelegates.last(), lastPressed);
+ QCOMPARE(canceledDelegates.size(), expectCanceled ? 1 : 0); // only the first press was canceled, not the second
+}
+
+void tst_QQuickListView2::flickDuringFlicking_data()
+{
+ QTest::addColumn<QByteArray>("qmlFile");
+ QTest::addColumn<QQuickFlickable::BoundsBehavior>("boundsBehavior");
+
+ QTest::newRow("Button StopAtBounds") << QByteArray("buttonDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds);
+ QTest::newRow("MouseArea StopAtBounds") << QByteArray("mouseAreaDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::StopAtBounds);
+ QTest::newRow("Button DragOverBounds") << QByteArray("buttonDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds);
+ QTest::newRow("MouseArea DragOverBounds") << QByteArray("mouseAreaDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragOverBounds);
+ QTest::newRow("Button OvershootBounds") << QByteArray("buttonDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds);
+ QTest::newRow("MouseArea OvershootBounds") << QByteArray("mouseAreaDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::OvershootBounds);
+ QTest::newRow("Button DragAndOvershootBounds") << QByteArray("buttonDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds);
+ QTest::newRow("MouseArea DragAndOvershootBounds") << QByteArray("mouseAreaDelegate.qml")
+ << QQuickFlickable::BoundsBehavior(QQuickFlickable::DragAndOvershootBounds);
+}
+
+void tst_QQuickListView2::flickDuringFlicking() // QTBUG-103832
+{
+ QFETCH(QByteArray, qmlFile);
+ QFETCH(QQuickFlickable::BoundsBehavior, boundsBehavior);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl(qmlFile.constData())));
+ QQuickListView *listView = qobject_cast<QQuickListView*>(window.rootObject());
+ QVERIFY(listView);
+ listView->setBoundsBehavior(boundsBehavior);
+
+ flickWithTouch(&window, {100, 400}, {100, 100});
+ // let it flick some distance
+ QTRY_COMPARE_GT(listView->contentY(), 500);
+ QVERIFY(listView->isFlicking()); // we want to test the case when it's moving and then we flick again
+ const qreal posBeforeSecondFlick = listView->contentY();
+
+ // flick again during flicking, and make sure that it doesn't jump back to the first delegate,
+ // but flicks incrementally further from the position at that time
+ QTest::touchEvent(&window, touchDevice.data()).press(0, {100, 400});
+ QQuickTouchUtils::flush(&window);
+ qCDebug(lcTests) << "second press: contentY" << posBeforeSecondFlick << "->" << listView->contentY();
+ qCDebug(lcTests) << "pressed delegates" << listView->property("pressedDelegates").toList();
+ QVERIFY(listView->contentY() >= posBeforeSecondFlick);
+
+ QTest::qWait(20);
+ QTest::touchEvent(&window, touchDevice.data()).move(0, {100, 300});
+ QQuickTouchUtils::flush(&window);
+ qCDebug(lcTests) << "first move after second press: contentY" << posBeforeSecondFlick << "->" << listView->contentY();
+ QVERIFY(listView->contentY() >= posBeforeSecondFlick);
+
+ QTest::qWait(20);
+ QTest::touchEvent(&window, touchDevice.data()).move(0, {100, 200});
+ QQuickTouchUtils::flush(&window);
+ qCDebug(lcTests) << "second move after second press: contentY" << posBeforeSecondFlick << "->" << listView->contentY();
+ QVERIFY(listView->contentY() >= posBeforeSecondFlick + 100);
+
+ QTest::touchEvent(&window, touchDevice.data()).release(0, {100, 100});
+}
+
+void tst_QQuickListView2::flickWithTouch(QQuickWindow *window, const QPoint &from, const QPoint &to)
+{
+ QTest::touchEvent(window, touchDevice.data()).press(0, from, window);
+ QQuickTouchUtils::flush(window);
+
+ QPoint diff = to - from;
+ for (int i = 1; i <= 8; ++i) {
+ QTest::touchEvent(window, touchDevice.data()).move(0, from + i * diff / 8, window);
+ QQuickTouchUtils::flush(window);
+ }
+ QTest::touchEvent(window, touchDevice.data()).release(0, to, window);
+ QQuickTouchUtils::flush(window);
+}
+
+class SingletonModel : public QStringListModel
+{
+ Q_OBJECT
+public:
+ SingletonModel(QObject* parent = nullptr) : QStringListModel(parent) { }
+};
+
+void tst_QQuickListView2::singletonModelLifetime()
+{
+ // this does not really test any functionality of listview, but we do not have a good way
+ // to unit test QQmlAdaptorModel in isolation.
+ qmlRegisterSingletonType<SingletonModel>("test", 1, 0, "SingletonModel",
+ [](QQmlEngine* , QJSEngine*) -> QObject* { return new SingletonModel; });
+
+ QQmlApplicationEngine engine(testFile("singletonModelLifetime.qml"));
+ // needs event loop iteration for callLater to execute
+ QTRY_VERIFY(engine.rootObjects().first()->property("alive").toBool());
+}
+
+void tst_QQuickListView2::delegateModelRefresh()
+{
+ // Test case originates from QTBUG-100161
+ QQmlApplicationEngine engine(testFile("delegateModelRefresh.qml"));
+ QVERIFY(!engine.rootObjects().isEmpty());
+ // needs event loop iteration for callLater to execute
+ QTRY_VERIFY(engine.rootObjects().first()->property("done").toBool());
+}
+
+void tst_QQuickListView2::wheelSnap()
+{
+ QFETCH(QQuickListView::Orientation, orientation);
+ QFETCH(Qt::LayoutDirection, layoutDirection);
+ QFETCH(QQuickItemView::VerticalLayoutDirection, verticalLayoutDirection);
+ QFETCH(QQuickItemView::HighlightRangeMode, highlightRangeMode);
+ QFETCH(QPoint, forwardAngleDelta);
+ QFETCH(qreal, snapAlignment);
+ QFETCH(qreal, endExtent);
+ QFETCH(qreal, startExtent);
+ QFETCH(qreal, preferredHighlightBegin);
+ QFETCH(qreal, preferredHighlightEnd);
+
+ // Helpers begin
+ quint64 timestamp = 10;
+ auto sendWheelEvent = [&timestamp](QQuickView *window, const QPoint &angleDelta) {
+ QPoint pos(100, 100);
+ QWheelEvent event(pos, window->mapToGlobal(pos), QPoint(), angleDelta, Qt::NoButton,
+ Qt::NoModifier, Qt::NoScrollPhase, false);
+ event.setAccepted(false);
+ event.setTimestamp(timestamp);
+ QGuiApplication::sendEvent(window, &event);
+ timestamp += 50;
+ };
+
+ auto atEnd = [&layoutDirection, &orientation,
+ &verticalLayoutDirection](QQuickListView *listview) {
+ if (orientation == QQuickListView::Horizontal) {
+ if (layoutDirection == Qt::LeftToRight)
+ return listview->isAtXEnd();
+
+ return listview->isAtXBeginning();
+ } else {
+ if (verticalLayoutDirection == QQuickItemView::VerticalLayoutDirection::TopToBottom)
+ return listview->isAtYEnd();
+
+ return listview->isAtYBeginning();
+ }
+ };
+
+ auto atBegin = [&layoutDirection, &orientation,
+ &verticalLayoutDirection](QQuickListView *listview) {
+ if (orientation == QQuickListView::Horizontal) {
+ if (layoutDirection == Qt::LeftToRight)
+ return listview->isAtXBeginning();
+
+ return listview->isAtXEnd();
+ } else {
+ if (verticalLayoutDirection == QQuickItemView::VerticalLayoutDirection::TopToBottom)
+ return listview->isAtYBeginning();
+
+ return listview->isAtYEnd();
+ }
+ };
+ // Helpers end
+
+ QScopedPointer<QQuickView> window(createView());
+ QTRY_VERIFY(window);
+ QQuickViewTestUtils::moveMouseAway(window.data());
+ window->setSource(testFileUrl("snapOneItem.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = qobject_cast<QQuickListView *>(window->rootObject());
+ QTRY_VERIFY(listview);
+
+ listview->setOrientation(orientation);
+ listview->setVerticalLayoutDirection(verticalLayoutDirection);
+ listview->setLayoutDirection(layoutDirection);
+ listview->setHighlightRangeMode(highlightRangeMode);
+ listview->setPreferredHighlightBegin(preferredHighlightBegin);
+ listview->setPreferredHighlightEnd(preferredHighlightEnd);
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+
+ QQuickItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem);
+
+ QSignalSpy currentIndexSpy(listview, &QQuickListView::currentIndexChanged);
+
+ // confirm that a flick hits the next item boundary
+ int indexCounter = 0;
+ sendWheelEvent(window.data(), forwardAngleDelta);
+ QTRY_VERIFY(listview->isMoving() == false); // wait until it stops
+
+ if (orientation == QQuickListView::Vertical)
+ QCOMPARE(listview->contentY(), snapAlignment);
+ else
+ QCOMPARE(listview->contentX(), snapAlignment);
+
+ if (highlightRangeMode == QQuickItemView::StrictlyEnforceRange) {
+ ++indexCounter;
+ QTRY_VERIFY(listview->currentIndex() == indexCounter);
+ }
+
+ // flick to end
+ do {
+ sendWheelEvent(window.data(), forwardAngleDelta);
+ QTRY_VERIFY(listview->isMoving() == false); // wait until it stops
+ if (highlightRangeMode == QQuickItemView::StrictlyEnforceRange) {
+ ++indexCounter;
+ QTRY_VERIFY(listview->currentIndex() == indexCounter);
+ }
+ } while (!atEnd(listview));
+
+ if (orientation == QQuickListView::Vertical)
+ QCOMPARE(listview->contentY(), endExtent);
+ else
+ QCOMPARE(listview->contentX(), endExtent);
+
+ if (highlightRangeMode == QQuickItemView::StrictlyEnforceRange) {
+ QCOMPARE(listview->currentIndex(), listview->count() - 1);
+ QCOMPARE(currentIndexSpy.count(), listview->count() - 1);
+ }
+
+ // flick to start
+ const QPoint backwardAngleDelta(-forwardAngleDelta.x(), -forwardAngleDelta.y());
+ do {
+ sendWheelEvent(window.data(), backwardAngleDelta);
+ QTRY_VERIFY(listview->isMoving() == false); // wait until it stops
+ if (highlightRangeMode == QQuickItemView::StrictlyEnforceRange) {
+ --indexCounter;
+ QTRY_VERIFY(listview->currentIndex() == indexCounter);
+ }
+ } while (!atBegin(listview));
+
+ if (orientation == QQuickListView::Vertical)
+ QCOMPARE(listview->contentY(), startExtent);
+ else
+ QCOMPARE(listview->contentX(), startExtent);
+
+ if (highlightRangeMode == QQuickItemView::StrictlyEnforceRange) {
+ QCOMPARE(listview->currentIndex(), 0);
+ QCOMPARE(currentIndexSpy.count(), (listview->count() - 1) * 2);
+ }
+}
+
+void tst_QQuickListView2::wheelSnap_data()
+{
+ QTest::addColumn<QQuickListView::Orientation>("orientation");
+ QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
+ QTest::addColumn<QQuickItemView::VerticalLayoutDirection>("verticalLayoutDirection");
+ QTest::addColumn<QQuickItemView::HighlightRangeMode>("highlightRangeMode");
+ QTest::addColumn<QPoint>("forwardAngleDelta");
+ QTest::addColumn<qreal>("snapAlignment");
+ QTest::addColumn<qreal>("endExtent");
+ QTest::addColumn<qreal>("startExtent");
+ QTest::addColumn<qreal>("preferredHighlightBegin");
+ QTest::addColumn<qreal>("preferredHighlightEnd");
+
+ QTest::newRow("vertical, top to bottom")
+ << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom
+ << QQuickItemView::NoHighlightRange << QPoint(20, -240) << 200.0 << 600.0 << 0.0 << 0.0
+ << 0.0;
+
+ QTest::newRow("vertical, bottom to top")
+ << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop
+ << QQuickItemView::NoHighlightRange << QPoint(20, 240) << -400.0 << -800.0 << -200.0
+ << 0.0 << 0.0;
+
+ QTest::newRow("horizontal, left to right")
+ << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom
+ << QQuickItemView::NoHighlightRange << QPoint(-240, 20) << 200.0 << 600.0 << 0.0 << 0.0
+ << 0.0;
+
+ QTest::newRow("horizontal, right to left")
+ << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom
+ << QQuickItemView::NoHighlightRange << QPoint(240, 20) << -400.0 << -800.0 << -200.0
+ << 0.0 << 0.0;
+
+ QTest::newRow("vertical, top to bottom, enforce range")
+ << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom
+ << QQuickItemView::StrictlyEnforceRange << QPoint(20, -240) << 200.0 << 600.0 << 0.0
+ << 0.0 << 0.0;
+
+ QTest::newRow("vertical, bottom to top, enforce range")
+ << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop
+ << QQuickItemView::StrictlyEnforceRange << QPoint(20, 240) << -400.0 << -800.0 << -200.0
+ << 0.0 << 0.0;
+
+ QTest::newRow("horizontal, left to right, enforce range")
+ << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom
+ << QQuickItemView::StrictlyEnforceRange << QPoint(-240, 20) << 200.0 << 600.0 << 0.0
+ << 0.0 << 0.0;
+
+ QTest::newRow("horizontal, right to left, enforce range")
+ << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom
+ << QQuickItemView::StrictlyEnforceRange << QPoint(240, 20) << -400.0 << -800.0 << -200.0
+ << 0.0 << 0.0;
+
+ QTest::newRow("vertical, top to bottom, apply range")
+ << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom
+ << QQuickItemView::ApplyRange << QPoint(20, -240) << 200.0 << 600.0 << 0.0 << 0.0
+ << 0.0;
+
+ QTest::newRow("vertical, bottom to top, apply range")
+ << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop
+ << QQuickItemView::ApplyRange << QPoint(20, 240) << -400.0 << -800.0 << -200.0 << 0.0
+ << 0.0;
+
+ QTest::newRow("horizontal, left to right, apply range")
+ << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom
+ << QQuickItemView::ApplyRange << QPoint(-240, 20) << 200.0 << 600.0 << 0.0 << 0.0
+ << 0.0;
+
+ QTest::newRow("horizontal, right to left, apply range")
+ << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom
+ << QQuickItemView::ApplyRange << QPoint(240, 20) << -400.0 << -800.0 << -200.0 << 0.0
+ << 0.0;
+
+ QTest::newRow("vertical, top to bottom with highlightRange")
+ << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom
+ << QQuickItemView::NoHighlightRange << QPoint(20, -240) << 190.0 << 600.0 << 0.0 << 10.0
+ << 210.0;
+
+ QTest::newRow("vertical, bottom to top with highlightRange")
+ << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop
+ << QQuickItemView::NoHighlightRange << QPoint(20, 240) << -390.0 << -800.0 << -200.0
+ << 10.0 << 210.0;
+
+ QTest::newRow("horizontal, left to right with highlightRange")
+ << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom
+ << QQuickItemView::NoHighlightRange << QPoint(-240, 20) << 190.0 << 600.0 << 0.0 << 10.0
+ << 210.0;
+
+ QTest::newRow("horizontal, right to left with highlightRange")
+ << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom
+ << QQuickItemView::NoHighlightRange << QPoint(240, 20) << -390.0 << -800.0 << -200.0
+ << 10.0 << 210.0;
+
+ QTest::newRow("vertical, top to bottom, enforce range with highlightRange")
+ << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom
+ << QQuickItemView::StrictlyEnforceRange << QPoint(20, -240) << 190.0 << 590.0 << -10.0
+ << 10.0 << 210.0;
+
+ QTest::newRow("vertical, bottom to top, enforce range with highlightRange")
+ << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop
+ << QQuickItemView::StrictlyEnforceRange << QPoint(20, 240) << -390.0 << -790.0 << -190.0
+ << 10.0 << 210.0;
+
+ QTest::newRow("horizontal, left to right, enforce range with highlightRange")
+ << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom
+ << QQuickItemView::StrictlyEnforceRange << QPoint(-240, 20) << 190.0 << 590.0 << -10.0
+ << 10.0 << 210.0;
+
+ QTest::newRow("horizontal, right to left, enforce range with highlightRange")
+ << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom
+ << QQuickItemView::StrictlyEnforceRange << QPoint(240, 20) << -390.0 << -790.0 << -190.0
+ << 10.0 << 210.0;
+
+ QTest::newRow("vertical, top to bottom, apply range with highlightRange")
+ << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::TopToBottom
+ << QQuickItemView::ApplyRange << QPoint(20, -240) << 190.0 << 600.0 << 0.0 << 10.0
+ << 210.0;
+
+ QTest::newRow("vertical, bottom to top, apply range with highlightRange")
+ << QQuickListView::Vertical << Qt::LeftToRight << QQuickItemView::BottomToTop
+ << QQuickItemView::ApplyRange << QPoint(20, 240) << -390.0 << -800.0 << -200.0 << 10.0
+ << 210.0;
+
+ QTest::newRow("horizontal, left to right, apply range with highlightRange")
+ << QQuickListView::Horizontal << Qt::LeftToRight << QQuickItemView::TopToBottom
+ << QQuickItemView::ApplyRange << QPoint(-240, 20) << 190.0 << 600.0 << 0.0 << 10.0
+ << 210.0;
+
+ QTest::newRow("horizontal, right to left, apply range with highlightRange")
+ << QQuickListView::Horizontal << Qt::RightToLeft << QQuickItemView::TopToBottom
+ << QQuickItemView::ApplyRange << QPoint(240, 20) << -390.0 << -800.0 << -200.0 << 10.0
+ << 210.0;
+}
+
+class FriendlyItemView : public QQuickItemView
+{
+ friend class ItemViewAccessor;
+};
+
+class ItemViewAccessor
+{
+public:
+ ItemViewAccessor(QQuickItemView *itemView) :
+ mItemView(reinterpret_cast<FriendlyItemView*>(itemView))
+ {
+ }
+
+ qreal maxXExtent() const
+ {
+ return mItemView->maxXExtent();
+ }
+
+ qreal maxYExtent() const
+ {
+ return mItemView->maxYExtent();
+ }
+
+private:
+ FriendlyItemView *mItemView = nullptr;
+};
+
+void tst_QQuickListView2::maxExtent_data()
+{
+ QTest::addColumn<QString>("qmlFilePath");
+ QTest::addRow("maxXExtent") << "maxXExtent.qml";
+ QTest::addRow("maxYExtent") << "maxYExtent.qml";
+}
+
+void tst_QQuickListView2::maxExtent()
+{
+ QFETCH(QString, qmlFilePath);
+
+ QScopedPointer<QQuickView> window(createView());
+ QVERIFY(window);
+ window->setSource(testFileUrl(qmlFilePath));
+ QVERIFY2(window->status() == QQuickView::Ready, qPrintable(QDebug::toString(window->errors())));
+ window->resize(640, 480);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *view = window->rootObject()->property("view").value<QQuickListView*>();
+ QVERIFY(view);
+ ItemViewAccessor viewAccessor(view);
+ if (view->orientation() == QQuickListView::Vertical)
+ QCOMPARE(viewAccessor.maxXExtent(), 0);
+ else if (view->orientation() == QQuickListView::Horizontal)
+ QCOMPARE(viewAccessor.maxYExtent(), 0);
+}
+
+void tst_QQuickListView2::isCurrentItem_DelegateModel()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("qtbug86744.qml"));
+ window->resize(640, 480);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+ QQuickListView* listView = window->rootObject()->findChild<QQuickListView*>("listView");
+ QVERIFY(listView);
+ QVariant value = listView->itemAtIndex(1)->property("isCurrent");
+ QVERIFY(value.toBool() == true);
+}
+
+void tst_QQuickListView2::isCurrentItem_NoRegressionWithDelegateModelGroups()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("qtbug98315.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+ QQuickListView* listView = window->rootObject()->findChild<QQuickListView*>("listView");
+ QVERIFY(listView);
+
+ QQuickItem *item3 = listView->itemAtIndex(1);
+ QVERIFY(item3);
+ QCOMPARE(item3->property("isCurrent").toBool(), true);
+
+ QObject *item0 = listView->itemAtIndex(0);
+ QVERIFY(item0);
+ QCOMPARE(item0->property("isCurrent").toBool(), false);
+
+ // Press left arrow key -> Item 1 should become current, Item 3 should not
+ // be current anymore. After a previous fix of QTBUG-86744 it was working
+ // incorrectly - see QTBUG-98315
+ QTest::keyPress(window.get(), Qt::Key_Left);
+
+ QTRY_COMPARE(item0->property("isCurrent").toBool(), true);
+ QCOMPARE(item3->property("isCurrent").toBool(), false);
+}
+
+void tst_QQuickListView2::pullbackSparseList() // QTBUG_104679
+{
+ // check if PullbackHeader crashes
+ QScopedPointer<QQuickView> window(createView());
+ QVERIFY(window);
+ window->setSource(testFileUrl("qtbug104679_header.qml"));
+ QVERIFY2(window->status() == QQuickView::Ready, qPrintable(QDebug::toString(window->errors())));
+ window->resize(640, 480);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ // check if PullbackFooter crashes
+ window.reset(createView());
+ QVERIFY(window);
+ window->setSource(testFileUrl("qtbug104679_footer.qml"));
+ QVERIFY2(window->status() == QQuickView::Ready, qPrintable(QDebug::toString(window->errors())));
+ window->resize(640, 480);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+}
+
+void tst_QQuickListView2::highlightWithBound()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("highlightWithBound.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+ QQuickListView *listView = qobject_cast<QQuickListView *>(o.data());
+ QVERIFY(listView);
+ QQuickItem *highlight = listView->highlightItem();
+ QVERIFY(highlight);
+ QCOMPARE(highlight->objectName(), QStringLiteral("highlight"));
+}
+
+void tst_QQuickListView2::sectionIsCompatibleWithBoundComponents()
+{
+ QTest::failOnWarning(".?");
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("sectionBoundComponent.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+ QQuickListView *listView = qobject_cast<QQuickListView *>(o.data());
+ QVERIFY(listView);
+ QTRY_COMPARE(listView->currentSection(), "42");
+}
+
+void tst_QQuickListView2::sectionGeometryChange()
+{
+ QScopedPointer<QQuickView> window(createView());
+ QTRY_VERIFY(window);
+ window->setSource(testFileUrl("sectionGeometryChange.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickListView *listview = findItem<QQuickListView>(window->rootObject(), "list");
+ QTRY_VERIFY(listview);
+
+ QQuickItem *contentItem = listview->contentItem();
+ QTRY_VERIFY(contentItem);
+ QVERIFY(QQuickTest::qWaitForPolish(listview));
+
+ QQuickItem *section1 = findItem<QQuickItem>(contentItem, "Section1");
+ QVERIFY(section1);
+ QQuickItem *element1 = findItem<QQuickItem>(contentItem, "Element1");
+ QVERIFY(element1);
+
+ QCOMPARE(element1->y(), section1->y() + section1->height());
+
+ // Update the height of the section delegate and verify that the next element is not overlapping
+ section1->setHeight(section1->height() + 10);
+ QTRY_COMPARE(element1->y(), section1->y() + section1->height());
+}
+
+void tst_QQuickListView2::areaZeroviewDoesNotNeedlesslyPopulateWholeModel()
+{
+ QTest::failOnWarning(QRegularExpression(".*"));
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("areaZeroView.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ std::unique_ptr<QObject> root(c.create());
+ QVERIFY(root);
+ auto delegateCreationCounter = [&]() {
+ return root->property("delegateCreationCounter").toInt();
+ };
+ // wait for onComplete to be settled
+ QTRY_VERIFY(delegateCreationCounter() != 0);
+ auto view = qobject_cast<QQuickListView *>(qmlContext(root.get())->objectForName("lv"));
+ QVERIFY(view);
+ QCOMPARE(view->count(), 6'000);
+ // we use 100, which is < 6000, but larger than the actual expected value
+ // that's to give the test some leniency in case the ListView implementation
+ // changes in the future to instantiate a few more items outside of the viewport
+ QVERIFY(delegateCreationCounter() < 100);
+}
+
+void tst_QQuickListView2::delegateContextHandling()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("delegateContextHandling.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ std::unique_ptr<QObject> o(c.create());
+ QVERIFY(o);
+
+ for (int i = 0; i < 10; ++i) {
+ QQuickItem *delegate = nullptr;
+ QMetaObject::invokeMethod(o.get(), "toggle", Q_RETURN_ARG(QQuickItem *, delegate));
+ QVERIFY(delegate);
+ }
+
+}
+
+class TestFetchMoreModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ QVariant data(const QModelIndex& index, int role) const override
+ {
+ if (role == Qt::DisplayRole)
+ return QString::number(index.row());
+ return {};
+ }
+
+ int columnCount(const QModelIndex&) const override { return 1; }
+
+ int rowCount(const QModelIndex& parent) const override
+ {
+ return parent.isValid() ? 0 : m_lines;
+ }
+
+ QModelIndex parent(const QModelIndex&) const override { return {}; }
+
+ bool canFetchMore(const QModelIndex &) const override { return true; }
+
+ void fetchMore(const QModelIndex & parent) override
+ {
+ if (Q_UNLIKELY(parent.isValid()))
+ return;
+ beginInsertRows(parent, m_lines, m_lines);
+ m_lines++;
+ endInsertRows();
+ }
+
+ int m_lines = 3;
+};
+
+void tst_QQuickListView2::fetchMore_data()
+{
+ QTest::addColumn<bool>("reuseItems");
+ QTest::addColumn<int>("cacheBuffer");
+
+ QTest::newRow("no reuseItems, default buffer") << false << -1;
+ QTest::newRow("reuseItems, default buffer") << true << -1;
+ QTest::newRow("no reuseItems, no buffer") << false << 0;
+ QTest::newRow("reuseItems, no buffer") << true << 0;
+ QTest::newRow("no reuseItems, buffer 100 px") << false << 100;
+ QTest::newRow("reuseItems, buffer 100 px") << true << 100;
+}
+
+void tst_QQuickListView2::fetchMore() // QTBUG-95107
+{
+ QFETCH(bool, reuseItems);
+ QFETCH(int, cacheBuffer);
+
+ TestFetchMoreModel model;
+ qmlRegisterSingletonInstance("org.qtproject.Test", 1, 0, "FetchMoreModel", &model);
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("fetchMore.qml")));
+ auto *listView = qobject_cast<QQuickListView*>(window.rootObject());
+ QVERIFY(listView);
+ listView->setReuseItems(reuseItems);
+ if (cacheBuffer >= 0)
+ listView->setCacheBuffer(cacheBuffer);
+
+ for (int i = 0; i < 3; ++i) {
+ const int rowCount = listView->count();
+ if (lcTests().isDebugEnabled()) QTest::qWait(1000);
+ listView->flick(0, -5000);
+ QTRY_VERIFY(!listView->isMoving());
+ qCDebug(lcTests) << "after flick: contentY" << listView->contentY()
+ << "rows" << rowCount << "->" << listView->count();
+ QCOMPARE_GT(listView->count(), rowCount);
+ QCOMPARE_GE(model.m_lines, listView->count()); // fetchMore() was called
+ }
+}
+
+void tst_QQuickListView2::changingOrientationResetsPreviousAxisValues_data()
+{
+ QTest::addColumn<QByteArray>("sourceFile");
+ QTest::newRow("ObjectModel") << QByteArray("changingOrientationWithObjectModel.qml");
+ QTest::newRow("ListModel") << QByteArray("changingOrientationWithListModel.qml");
+}
+
+void tst_QQuickListView2::changingOrientationResetsPreviousAxisValues() // QTBUG-115696
+{
+ QFETCH(QByteArray, sourceFile);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl(QString::fromLatin1(sourceFile))));
+ auto *listView = qobject_cast<QQuickListView *>(window.rootObject());
+ QVERIFY(listView);
+
+ // Starts of with vertical orientation. X should be 0 for all delegates, but not Y.
+ QVERIFY(listView->property("isXReset").toBool());
+ QVERIFY(!listView->property("isYReset").toBool());
+
+ listView->setOrientation(QQuickListView::Orientation::Horizontal);
+
+ // Y should be 0 for all delegates, but not X.
+ QVERIFY(!listView->property("isXReset").toBool());
+ QVERIFY(listView->property("isYReset").toBool());
+
+ listView->setOrientation(QQuickListView::Orientation::Vertical);
+
+ // X should be 0 for all delegates, but not Y.
+ QVERIFY(listView->property("isXReset").toBool());
+ QVERIFY(!listView->property("isYReset").toBool());
+}
+
+void tst_QQuickListView2::bindingDirectlyOnPositionInHeaderAndFooterDelegates_data()
+{
+ QTest::addColumn<QByteArray>("sourceFile");
+ QTest::addColumn<qreal(QQuickItem::*)()const>("pos");
+ QTest::addColumn<qreal(QQuickItem::*)()const>("size");
+ QTest::newRow("XPosition") << QByteArray("bindOnHeaderAndFooterXPosition.qml") << &QQuickItem::x << &QQuickItem::width;
+ QTest::newRow("YPosition") << QByteArray("bindOnHeaderAndFooterYPosition.qml") << &QQuickItem::y << &QQuickItem::height;
+}
+void tst_QQuickListView2::bindingDirectlyOnPositionInHeaderAndFooterDelegates()
+{
+
+ typedef qreal (QQuickItem::*position_func_t)() const;
+ QFETCH(QByteArray, sourceFile);
+ QFETCH(position_func_t, pos);
+ QFETCH(position_func_t, size);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl(QString::fromLatin1(sourceFile))));
+ auto *listView = qobject_cast<QQuickListView *>(window.rootObject());
+ QVERIFY(listView);
+
+ const qreal widthOrHeight = (listView->*size)();
+
+ QCOMPARE((listView->headerItem()->*pos)(), (widthOrHeight - 50) / 2);
+ QCOMPARE((listView->footerItem()->*pos)(), (widthOrHeight - 50) / 2);
+
+ // Verify that the "regular" delegate items, don't honor x and y bindings.
+ // This should only be allowed for header and footer delegates.
+ for (int i = 0; i < listView->count(); ++i)
+ QCOMPARE((listView->itemAtIndex(i)->*pos)(), 0);
+}
+
+void tst_QQuickListView2::clearObjectListModel()
+{
+ QQmlEngine engine;
+ QQmlComponent delegate(&engine);
+
+ // Need one required property to trigger the incremental rebuilding of metaobjects.
+ delegate.setData("import QtQuick\nItem { required property int index }", QUrl());
+
+ QQuickListView list;
+ engine.setContextForObject(&list, engine.rootContext());
+ list.setDelegate(&delegate);
+ list.setWidth(640);
+ list.setHeight(480);
+
+ QScopedPointer modelObject(new QObject);
+
+ // Use a list that might also carry something non-QObject
+
+ list.setModel(QVariantList {
+ QVariant::fromValue(modelObject.data()),
+ QVariant::fromValue(modelObject.data())
+ });
+
+ QVERIFY(list.itemAtIndex(0));
+
+ modelObject.reset();
+
+ // list should not access dangling pointer from old model data anymore.
+ list.setModel(QVariantList());
+
+ QVERIFY(!list.itemAtIndex(0));
+}
+
+QTEST_MAIN(tst_QQuickListView2)
+
+#include "tst_qquicklistview2.moc"
diff --git a/tests/auto/quick/qquicklistview2/typerolemodel.cpp b/tests/auto/quick/qquicklistview2/typerolemodel.cpp
new file mode 100644
index 0000000000..94da87beda
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/typerolemodel.cpp
@@ -0,0 +1,41 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "typerolemodel.h"
+
+TypeRoleModel::TypeRoleModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+ _mapRoleNames[TypeRole] = "type";
+ _mapRoleNames[TextRole] = "text";
+}
+
+int TypeRoleModel::rowCount(const QModelIndex &) const
+{
+ return 3;
+}
+
+QVariant TypeRoleModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return {};
+
+ constexpr Type types[] = {
+ Type::PlainText,
+ Type::Markdown,
+ Type::Rect
+ };
+ switch (role) {
+ case TypeRole: {
+ const Type type = types[index.row() % std::size(types)];
+ return QVariant::fromValue(type);
+ }
+ case TextRole: {
+ if (index.row() % std::size(types) == int(Type::Markdown))
+ return "*row* " + QString::number(index.row());
+ return "row " + QString::number(index.row());
+ }
+ }
+
+ return {};
+}
diff --git a/tests/auto/quick/qquicklistview2/typerolemodel.h b/tests/auto/quick/qquicklistview2/typerolemodel.h
new file mode 100644
index 0000000000..f47400a88c
--- /dev/null
+++ b/tests/auto/quick/qquicklistview2/typerolemodel.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QAbstractListModel>
+#include <qqml.h>
+
+class TypeRoleModel : public QAbstractListModel
+{
+ Q_OBJECT
+ QML_ELEMENT
+
+public:
+ enum Role {
+ TypeRole = Qt::UserRole + 1,
+ TextRole,
+ };
+ Q_ENUM(Role)
+
+ enum class Type { PlainText, Markdown, Rect };
+ Q_ENUM(Type)
+
+ explicit TypeRoleModel(QObject *parent = nullptr);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QHash<int, QByteArray> roleNames() const override { return _mapRoleNames; }
+
+private:
+ QHash<int, QByteArray> _mapRoleNames;
+};
diff --git a/tests/auto/quick/qquickloader/BLACKLIST b/tests/auto/quick/qquickloader/BLACKLIST
index 30c02e4c13..a45a300607 100644
--- a/tests/auto/quick/qquickloader/BLACKLIST
+++ b/tests/auto/quick/qquickloader/BLACKLIST
@@ -2,5 +2,3 @@
# QTBUG-63049
[asyncToSync1]
b2qt
-[urlToComponent]
-macos
diff --git a/tests/auto/quick/qquickloader/CMakeLists.txt b/tests/auto/quick/qquickloader/CMakeLists.txt
index 785d5348a6..f7192df326 100644
--- a/tests/auto/quick/qquickloader/CMakeLists.txt
+++ b/tests/auto/quick/qquickloader/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickloader.pro.
#####################################################################
## tst_qquickloader Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickloader LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,23 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickloader
SOURCES
- ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickloader.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -37,10 +38,10 @@ qt_internal_add_test(tst_qquickloader
qt_internal_extend_target(tst_qquickloader CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickloader CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickloader/data/Rect120x60.qml b/tests/auto/quick/qquickloader/data/Rect120x60.qml
index fc9e447e69..6a0bb3d766 100644
--- a/tests/auto/quick/qquickloader/data/Rect120x60.qml
+++ b/tests/auto/quick/qquickloader/data/Rect120x60.qml
@@ -1,6 +1,10 @@
import QtQuick 2.0
Rectangle {
- width: 120
- height:60
+ property int base: 60
+ property int w: base*2
+ property int h: base
+ property int ignore: 0
+ width: w
+ height: h
}
diff --git a/tests/auto/quick/qquickloader/data/bindings.qml b/tests/auto/quick/qquickloader/data/bindings.qml
index e0eae2a3e5..5ea4ba34f4 100644
--- a/tests/auto/quick/qquickloader/data/bindings.qml
+++ b/tests/auto/quick/qquickloader/data/bindings.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the manual tests of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickloader/data/boundComponent.qml b/tests/auto/quick/qquickloader/data/boundComponent.qml
new file mode 100644
index 0000000000..84924611ba
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/boundComponent.qml
@@ -0,0 +1,12 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+
+Item {
+ id: root
+
+ Loader {
+ sourceComponent: Item {
+ Component.onCompleted: root.objectName = "loaded"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickloader/data/itemLoaderItemWindow.qml b/tests/auto/quick/qquickloader/data/itemLoaderItemWindow.qml
index e4e6088ebe..0d355f6c38 100644
--- a/tests/auto/quick/qquickloader/data/itemLoaderItemWindow.qml
+++ b/tests/auto/quick/qquickloader/data/itemLoaderItemWindow.qml
@@ -18,7 +18,7 @@ Item {
color: "red"
title: "red"
flags: Qt.Dialog
- onVisibilityChanged: console.log("visibility " + visibility)
+ onVisibilityChanged: (visibility) => console.log("visibility " + visibility)
onVisibleChanged: console.log("visible " + visible)
}
}
diff --git a/tests/auto/quick/qquickloader/data/itemLoaderWindow.qml b/tests/auto/quick/qquickloader/data/itemLoaderWindow.qml
index e3eb0f7e9a..c5d4dd1509 100644
--- a/tests/auto/quick/qquickloader/data/itemLoaderWindow.qml
+++ b/tests/auto/quick/qquickloader/data/itemLoaderWindow.qml
@@ -14,7 +14,7 @@ Item {
color: "red"
title: "red"
flags: Qt.Dialog
- onVisibilityChanged: console.log("visibility " + visibility)
+ onVisibilityChanged: (visibility) => console.log("visibility " + visibility)
onVisibleChanged: console.log("visible " + visible)
}
}
diff --git a/tests/auto/quick/qquickloader/data/loader-async-race-rect.qml b/tests/auto/quick/qquickloader/data/loader-async-race-rect.qml
new file mode 100644
index 0000000000..a56dcea5ad
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/loader-async-race-rect.qml
@@ -0,0 +1,10 @@
+import QtQuick 2.15
+
+Rectangle {
+ anchors.fill: parent
+ color: "blue"
+ Item {
+ Item {
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickloader/data/loader-async-race.qml b/tests/auto/quick/qquickloader/data/loader-async-race.qml
new file mode 100644
index 0000000000..8ba625c5c1
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/loader-async-race.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.15
+
+Item {
+ id: root
+ Component.onCompleted: {
+ myloader.active = false
+ }
+ Loader {
+ id: myloader
+ anchors.fill: parent
+ asynchronous: true
+ source: "loader-async-race-rect.qml"
+ }
+}
diff --git a/tests/auto/quick/qquickloader/data/noEngine.qml b/tests/auto/quick/qquickloader/data/noEngine.qml
new file mode 100644
index 0000000000..821ed30649
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/noEngine.qml
@@ -0,0 +1,32 @@
+import QtQuick 2
+
+Item {
+ id: root
+ property bool a: false
+ property int changes: 0
+ onAChanged: {
+ m.model = 0
+ m.model = 1
+ ++changes;
+ }
+
+ Repeater {
+ id: m
+ model: 1
+
+ Item {
+ Timer {
+ onTriggered: {
+ root.a = true
+ l.source = "BlueRect.qml"
+ }
+ interval: 0
+ running: true
+ }
+
+ Loader {
+ id: l
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickloader/data/overflow.qml b/tests/auto/quick/qquickloader/data/overflow.qml
new file mode 100644
index 0000000000..e5fdfee182
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/overflow.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Loader {
+ source: "overflow.qml"
+}
diff --git a/tests/auto/quick/qquickloader/data/overflow2.qml b/tests/auto/quick/qquickloader/data/overflow2.qml
new file mode 100644
index 0000000000..8da1678466
--- /dev/null
+++ b/tests/auto/quick/qquickloader/data/overflow2.qml
@@ -0,0 +1,7 @@
+import QtQuick
+
+Item {
+Loader {
+ source: "overflow2.qml"
+}
+}
diff --git a/tests/auto/quick/qquickloader/data/parentErrors.qml b/tests/auto/quick/qquickloader/data/parentErrors.qml
index 36607e7f05..f73213c433 100644
--- a/tests/auto/quick/qquickloader/data/parentErrors.qml
+++ b/tests/auto/quick/qquickloader/data/parentErrors.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the manual tests of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickloader/data/rootContext.qml b/tests/auto/quick/qquickloader/data/rootContext.qml
index 277db43d57..f73df2c53c 100644
--- a/tests/auto/quick/qquickloader/data/rootContext.qml
+++ b/tests/auto/quick/qquickloader/data/rootContext.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the manual tests of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index 7a945c8c5c..26dfd595cd 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -1,30 +1,6 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#include <qtest.h>
#include <QSignalSpy>
@@ -36,9 +12,9 @@
#include <QtQuick/qquickview.h>
#include <private/qquickloader_p.h>
#include <private/qquickwindowmodule_p.h>
-#include "testhttpserver.h"
-#include "../../shared/util.h"
-#include "../shared/geometrytestutil.h"
+#include <QtQuickTestUtils/private/geometrytestutils_p.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/testhttpserver_p.h>
#include <QQmlApplicationEngine>
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
@@ -63,11 +39,11 @@ public:
bool incubated = false;
protected:
- virtual void timerEvent(QTimerEvent *) {
+ void timerEvent(QTimerEvent *) override {
incubateFor(15);
}
- virtual void incubatingObjectCountChanged(int count) {
+ void incubatingObjectCountChanged(int count) override {
if (count)
incubated = true;
}
@@ -88,6 +64,7 @@ private slots:
void componentToUrl();
void anchoredLoader();
void sizeLoaderToItem();
+ void sizeItemToLoader_data();
void sizeItemToLoader();
void noResize();
void networkRequestUrl();
@@ -133,11 +110,19 @@ private slots:
void statusChangeOnlyEmittedOnce();
void setSourceAndCheckStatus();
+ void loadComponentWithStates();
+ void asyncLoaderRace();
+ void noEngine();
+
+ void stackOverflow();
+ void stackOverflow2();
+ void boundComponent();
};
Q_DECLARE_METATYPE(QList<QQmlError>)
tst_QQuickLoader::tst_QQuickLoader()
+ : QQmlDataTest(QT_QMLTEST_DATADIR, FailOnWarningsPolicy::FailOnWarnings)
{
qmlRegisterType<SlowComponent>("LoaderTest", 1, 0, "SlowComponent");
qRegisterMetaType<QList<QQmlError>>();
@@ -183,7 +168,7 @@ void tst_QQuickLoader::sourceOrComponent()
QCOMPARE(loader->progress(), 1.0);
QCOMPARE(loader->status(), error ? QQuickLoader::Error : QQuickLoader::Ready);
- QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().count(), error ? 0: 1);
+ QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().size(), error ? 0: 1);
if (!error) {
bool sourceComponentIsChildOfLoader = false;
@@ -244,12 +229,12 @@ void tst_QQuickLoader::clear()
QVERIFY(loader != nullptr);
QVERIFY(loader->item());
QCOMPARE(loader->progress(), 1.0);
- QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().count(), 1);
+ QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().size(), 1);
QTRY_VERIFY(!loader->item());
QCOMPARE(loader->progress(), 0.0);
QCOMPARE(loader->status(), QQuickLoader::Null);
- QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().count(), 0);
+ QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().size(), 0);
}
{
QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
@@ -260,14 +245,14 @@ void tst_QQuickLoader::clear()
QVERIFY(loader);
QVERIFY(loader->item());
QCOMPARE(loader->progress(), 1.0);
- QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
+ QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().size(), 1);
loader->setSourceComponent(nullptr);
QVERIFY(!loader->item());
QCOMPARE(loader->progress(), 0.0);
QCOMPARE(loader->status(), QQuickLoader::Null);
- QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
+ QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().size(), 0);
}
{
QQmlComponent component(&engine, testFileUrl("/SetSourceComponent.qml"));
@@ -278,14 +263,14 @@ void tst_QQuickLoader::clear()
QVERIFY(loader);
QVERIFY(loader->item());
QCOMPARE(loader->progress(), 1.0);
- QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
+ QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().size(), 1);
QMetaObject::invokeMethod(item.data(), "clear");
QVERIFY(!loader->item());
QCOMPARE(loader->progress(), 0.0);
QCOMPARE(loader->status(), QQuickLoader::Null);
- QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
+ QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().size(), 0);
}
}
@@ -306,7 +291,7 @@ void tst_QQuickLoader::urlToComponent()
QTRY_VERIFY(loader != nullptr);
QVERIFY(loader->item());
QCOMPARE(loader->progress(), 1.0);
- QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().count(), 1);
+ QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().size(), 1);
QCOMPARE(loader->width(), 10.0);
QCOMPARE(loader->height(), 10.0);
}
@@ -322,12 +307,12 @@ void tst_QQuickLoader::componentToUrl()
QVERIFY(loader);
QVERIFY(loader->item());
QCOMPARE(loader->progress(), 1.0);
- QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
+ QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().size(), 1);
- loader->setSource(testFileUrl("/Rect120x60.qml"));
+ loader->setSourceWithoutResolve(testFileUrl("/Rect120x60.qml"));
QVERIFY(loader->item());
QCOMPARE(loader->progress(), 1.0);
- QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
+ QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().size(), 1);
QCOMPARE(loader->width(), 120.0);
QCOMPARE(loader->height(), 60.0);
}
@@ -394,8 +379,29 @@ void tst_QQuickLoader::sizeLoaderToItem()
QCOMPARE(rect->height(), 30.0);
}
+void tst_QQuickLoader::sizeItemToLoader_data()
+{
+ QTest::addColumn<QString>("property");
+ QTest::addColumn<int>("value");
+ QTest::addColumn<bool>("atOnce");
+
+ QTest::addRow("none_atonce") << "ignore" << 42 << true;
+ QTest::addRow("width_atonce") << "w" << 42 << true;
+ QTest::addRow("height_atonce") << "h" << 42 << true;
+ QTest::addRow("both_atonce") << "both" << 42 << true;
+
+
+ QTest::addRow("none") << "ignore" << 42 << false;
+ QTest::addRow("width") << "w" << 42 << false;
+ QTest::addRow("height") << "h" << 42 << false;
+ QTest::addRow("both") << "both" << 42 << false;
+}
+
void tst_QQuickLoader::sizeItemToLoader()
{
+ QFETCH(QString, property);
+ QFETCH(int, value);
+ QFETCH(bool, atOnce);
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("/SizeToLoader.qml"));
QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create()));
@@ -405,17 +411,25 @@ void tst_QQuickLoader::sizeItemToLoader()
QQuickItem *rect = qobject_cast<QQuickItem*>(loader->item());
QVERIFY(rect);
+ rect->setProperty(property.toUtf8(), value);
QCOMPARE(rect->width(), 200.0);
QCOMPARE(rect->height(), 80.0);
// Check resize
QSizeChangeListener sizeListener(rect);
const QSizeF size(180, 30);
- loader->setSize(size);
+ if (atOnce) {
+ loader->setSize(size);
+ } else {
+ loader->setWidth(size.width());
+ loader->setHeight(size.height());
+ }
QVERIFY2(!sizeListener.isEmpty(), "There should be at least one signal about the size changed");
- for (const QSizeF sizeOnGeometryChanged : sizeListener) {
- // Check that we have the correct size on all signals
- QCOMPARE(sizeOnGeometryChanged, size);
+ if (atOnce) {
+ for (const QSizeF sizeOnGeometryChanged : sizeListener) {
+ // Check that we have the correct size on all signals
+ QCOMPARE(sizeOnGeometryChanged, size);
+ }
}
QCOMPARE(rect->width(), size.width());
QCOMPARE(rect->height(), size.height());
@@ -457,7 +471,7 @@ void tst_QQuickLoader::networkRequestUrl()
QVERIFY(loader->item());
QCOMPARE(loader->progress(), 1.0);
QCOMPARE(loader->property("signalCount").toInt(), 1);
- QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().count(), 1);
+ QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().size(), 1);
}
/* XXX Component waits until all dependencies are loaded. Is this actually possible? */
@@ -488,7 +502,7 @@ void tst_QQuickLoader::networkComponent()
QVERIFY(loader->item());
QCOMPARE(loader->progress(), 1.0);
QCOMPARE(loader->status(), QQuickLoader::Ready);
- QCOMPARE(static_cast<QQuickItem*>(loader)->children().count(), 1);
+ QCOMPARE(static_cast<QQuickItem*>(loader)->children().size(), 1);
}
@@ -511,7 +525,7 @@ void tst_QQuickLoader::failNetworkRequest()
QVERIFY(!loader->item());
QCOMPARE(loader->progress(), 1.0);
QCOMPARE(loader->property("did_load").toInt(), 123);
- QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().count(), 0);
+ QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().size(), 0);
}
void tst_QQuickLoader::active()
@@ -708,7 +722,7 @@ void tst_QQuickLoader::initialPropertyValues_data()
<< (QVariantList() << 12);
QTest::newRow("initial property errors get reported") << testFileUrl("initialPropertyTriggerException.qml")
- << (QStringList() << "^.*: Error: Cannot assign JavaScript function to int")
+ << (QStringList() << "^.*:10: Error: Cannot assign JavaScript function to int")
<< QStringList()
<< QVariantList();
}
@@ -722,7 +736,7 @@ void tst_QQuickLoader::initialPropertyValues()
ThreadedTestHTTPServer server(dataDirectory());
- foreach (const QString &warning, expectedWarnings)
+ for (const QString &warning : std::as_const(expectedWarnings))
QTest::ignoreMessage(QtWarningMsg, QRegularExpression(warning.toLatin1().constData()));
QQmlEngine engine;
@@ -768,8 +782,10 @@ void tst_QQuickLoader::initialPropertyValuesError_data()
QTest::newRow("nonexistent source url") << testFileUrl("initialPropertyValues.error.2.qml")
<< (QStringList() << QString(testFileUrl("NonexistentSourceComponent.qml").toString() + ": No such file or directory"));
- QTest::newRow("invalid source url") << testFileUrl("initialPropertyValues.error.3.qml")
- << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Expected token `:'"));
+ QTest::newRow("invalid source url")
+ << testFileUrl("initialPropertyValues.error.3.qml")
+ << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString()
+ + ":4:5: Incomplete binding, expected token `:` or `{`"));
QTest::newRow("invalid initial property values object with invalid property access") << testFileUrl("initialPropertyValues.error.4.qml")
<< (QStringList() << QString(testFileUrl("initialPropertyValues.error.4.qml").toString() + ":7:5: QML Loader: setSource: value is not an object")
@@ -781,7 +797,7 @@ void tst_QQuickLoader::initialPropertyValuesError()
QFETCH(QUrl, qmlFile);
QFETCH(QStringList, expectedWarnings);
- foreach (const QString &warning, expectedWarnings)
+ for (const QString &warning : std::as_const(expectedWarnings))
QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData());
QQmlEngine engine;
@@ -811,7 +827,7 @@ void tst_QQuickLoader::deleteComponentCrash()
QCOMPARE(loader->status(), QQuickLoader::Ready);
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
QCoreApplication::processEvents();
- QTRY_COMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
+ QTRY_COMPARE(static_cast<QQuickItem*>(loader)->childItems().size(), 1);
QCOMPARE(loader->source(), QUrl("BlueRect.qml"));
}
@@ -888,8 +904,8 @@ void tst_QQuickLoader::implicitSize()
QCOMPARE(loader->property("implicitWidth").toReal(), 200.);
QCOMPARE(loader->property("implicitHeight").toReal(), 300.);
- QCOMPARE(implWidthSpy.count(), 1);
- QCOMPARE(implHeightSpy.count(), 1);
+ QCOMPARE(implWidthSpy.size(), 1);
+ QCOMPARE(implHeightSpy.size(), 1);
}
void tst_QQuickLoader::QTBUG_17114()
@@ -914,8 +930,10 @@ void tst_QQuickLoader::asynchronous_data()
QTest::newRow("Non-existent component") << testFileUrl("IDoNotExist.qml")
<< (QStringList() << QString(testFileUrl("IDoNotExist.qml").toString() + ": No such file or directory"));
- QTest::newRow("Invalid component") << testFileUrl("InvalidSourceComponent.qml")
- << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString() + ":5:1: Expected token `:'"));
+ QTest::newRow("Invalid component")
+ << testFileUrl("InvalidSourceComponent.qml")
+ << (QStringList() << QString(testFileUrl("InvalidSourceComponent.qml").toString()
+ + ":4:5: Incomplete binding, expected token `:` or `{`"));
}
void tst_QQuickLoader::asynchronous()
@@ -924,9 +942,9 @@ void tst_QQuickLoader::asynchronous()
QFETCH(QStringList, expectedWarnings);
QQmlEngine engine;
- PeriodicIncubationController *controller = new PeriodicIncubationController;
+ QScopedPointer<PeriodicIncubationController> controller(new PeriodicIncubationController);
QQmlIncubationController *previous = engine.incubationController();
- engine.setIncubationController(controller);
+ engine.setIncubationController(controller.data());
delete previous;
QQmlComponent component(&engine, testFileUrl("asynchronous.qml"));
@@ -936,7 +954,7 @@ void tst_QQuickLoader::asynchronous()
QQuickLoader *loader = root->findChild<QQuickLoader*>("loader");
QVERIFY(loader);
- foreach (const QString &warning, expectedWarnings)
+ for (const QString &warning : std::as_const(expectedWarnings))
QTest::ignoreMessage(QtWarningMsg, warning.toUtf8().constData());
QVERIFY(!loader->item());
@@ -963,9 +981,9 @@ void tst_QQuickLoader::asynchronous()
void tst_QQuickLoader::asynchronous_clear()
{
QQmlEngine engine;
- PeriodicIncubationController *controller = new PeriodicIncubationController;
+ QScopedPointer<PeriodicIncubationController> controller(new PeriodicIncubationController);
QQmlIncubationController *previous = engine.incubationController();
- engine.setIncubationController(controller);
+ engine.setIncubationController(controller.data());
delete previous;
QQmlComponent component(&engine, testFileUrl("asynchronous.qml"));
@@ -992,7 +1010,7 @@ void tst_QQuickLoader::asynchronous_clear()
QCOMPARE(loader->progress(), 0.0);
QCOMPARE(loader->status(), QQuickLoader::Null);
- QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 0);
+ QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().size(), 0);
// check loading component
root->setProperty("comp", "BigComponent.qml");
@@ -1005,15 +1023,15 @@ void tst_QQuickLoader::asynchronous_clear()
QTRY_VERIFY(loader->item());
QCOMPARE(loader->progress(), 1.0);
QCOMPARE(loader->status(), QQuickLoader::Ready);
- QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
+ QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().size(), 1);
}
void tst_QQuickLoader::simultaneousSyncAsync()
{
QQmlEngine engine;
- PeriodicIncubationController *controller = new PeriodicIncubationController;
+ QScopedPointer<PeriodicIncubationController> controller(new PeriodicIncubationController);
QQmlIncubationController *previous = engine.incubationController();
- engine.setIncubationController(controller);
+ engine.setIncubationController(controller.data());
delete previous;
QQmlComponent component(&engine, testFileUrl("simultaneous.qml"));
@@ -1043,9 +1061,9 @@ void tst_QQuickLoader::simultaneousSyncAsync()
void tst_QQuickLoader::asyncToSync1()
{
QQmlEngine engine;
- PeriodicIncubationController *controller = new PeriodicIncubationController;
+ QScopedPointer<PeriodicIncubationController> controller(new PeriodicIncubationController);
QQmlIncubationController *previous = engine.incubationController();
- engine.setIncubationController(controller);
+ engine.setIncubationController(controller.data());
delete previous;
QQmlComponent component(&engine, testFileUrl("asynchronous.qml"));
@@ -1069,15 +1087,15 @@ void tst_QQuickLoader::asyncToSync1()
QVERIFY(loader->item());
QCOMPARE(loader->progress(), 1.0);
QCOMPARE(loader->status(), QQuickLoader::Ready);
- QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
+ QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().size(), 1);
}
void tst_QQuickLoader::asyncToSync2()
{
QQmlEngine engine;
- PeriodicIncubationController *controller = new PeriodicIncubationController;
+ QScopedPointer<PeriodicIncubationController> controller(new PeriodicIncubationController);
QQmlIncubationController *previous = engine.incubationController();
- engine.setIncubationController(controller);
+ engine.setIncubationController(controller.data());
delete previous;
QQmlComponent component(&engine, testFileUrl("asynchronous.qml"));
@@ -1101,15 +1119,15 @@ void tst_QQuickLoader::asyncToSync2()
QVERIFY(loader->item());
QCOMPARE(loader->progress(), 1.0);
QCOMPARE(loader->status(), QQuickLoader::Ready);
- QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().count(), 1);
+ QCOMPARE(static_cast<QQuickItem*>(loader)->childItems().size(), 1);
}
void tst_QQuickLoader::loadedSignal()
{
QQmlEngine engine;
- PeriodicIncubationController *controller = new PeriodicIncubationController;
+ QScopedPointer<PeriodicIncubationController> controller(new PeriodicIncubationController);
QQmlIncubationController *previous = engine.incubationController();
- engine.setIncubationController(controller);
+ engine.setIncubationController(controller.data());
delete previous;
{
@@ -1309,7 +1327,7 @@ void tst_QQuickLoader::sourceComponentGarbageCollection()
if (spy.isEmpty())
QVERIFY(spy.wait());
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
// QTBUG-51995
@@ -1441,7 +1459,7 @@ void tst_QQuickLoader::sourceURLKeepComponent()
dataDirectoryUrl());
QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create()));
- loader->setSource(testFileUrl("/Rect120x60.qml"));
+ loader->setSourceWithoutResolve(testFileUrl("/Rect120x60.qml"));
QVERIFY(loader);
QVERIFY(loader->item());
@@ -1467,7 +1485,7 @@ void tst_QQuickLoader::sourceURLKeepComponent()
QCOMPARE(sourceComponent.data(), loader->sourceComponent());
//Ensure changing source url causes component to be recreated when inactive
- loader->setSource(testFileUrl("/BlueRect.qml"));
+ loader->setSourceWithoutResolve(testFileUrl("/BlueRect.qml"));
loader->setActive(true);
QVERIFY(loader->item());
@@ -1477,7 +1495,7 @@ void tst_QQuickLoader::sourceURLKeepComponent()
QVERIFY(sourceComponent.data() != newSourceComponent.data());
//Ensure changing source url causes component to be recreated when active
- loader->setSource(testFileUrl("/Rect120x60.qml"));
+ loader->setSourceWithoutResolve(testFileUrl("/Rect120x60.qml"));
QVERIFY(loader->sourceComponent() != newSourceComponent.data());
}
@@ -1509,8 +1527,95 @@ void tst_QQuickLoader::setSourceAndCheckStatus()
QMetaObject::invokeMethod(loader, "load", Q_ARG(QVariant, QVariant::fromValue(QStringLiteral(""))));
QCOMPARE(loader->status(), QQuickLoader::Null);
- QMetaObject::invokeMethod(loader, "load", Q_ARG(QVariant, QVariant()));
+ QMetaObject::invokeMethod(loader, "load", Q_ARG(QVariant, QVariant(QUrl())));
+ QCOMPARE(loader->status(), QQuickLoader::Null);
+}
+
+void tst_QQuickLoader::loadComponentWithStates()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(QByteArray("import QtQuick\n"
+ "Loader {\n"
+ "id: loader\n"
+ "property int createdObjCount: 0\n"
+ "states: [ State { when: true; PropertyChanges { target: loader; sourceComponent: myComp } } ]\n"
+ "Component { id: myComp; Item { Component.onCompleted: { ++createdObjCount } } }\n"
+ "}" )
+ , dataDirectoryUrl());
+ QScopedPointer<QQuickLoader> loader(qobject_cast<QQuickLoader*>(component.create()));
+ QTest::qWait(200);
+ QTRY_VERIFY(loader != nullptr);
+ QVERIFY(loader->item());
+ QCOMPARE(static_cast<QQuickItem*>(loader.data())->childItems().size(), 1);
+ QCOMPARE(loader->property("createdObjCount").toInt(), 1);
+}
+
+void tst_QQuickLoader::asyncLoaderRace()
+{
+ QQmlApplicationEngine engine;
+ auto url = testFileUrl("loader-async-race.qml");
+ engine.load(url);
+ auto root = engine.rootObjects().at(0);
+ QVERIFY(root);
+
+ QQuickLoader *loader = root->findChild<QQuickLoader *>();
+ QCOMPARE(loader->active(), false);
QCOMPARE(loader->status(), QQuickLoader::Null);
+ QCOMPARE(loader->item(), nullptr);
+
+ QSignalSpy spy(loader, &QQuickLoader::itemChanged);
+ QVERIFY(!spy.wait(100));
+ QCOMPARE(loader->item(), nullptr);
+}
+
+void tst_QQuickLoader::noEngine()
+{
+ QQmlEngine engine;
+ const QUrl url = testFileUrl("noEngine.qml");
+ QQmlComponent component(&engine, url);
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> o(component.create());
+
+ const QString message = url.toString()
+ + QStringLiteral(":27:13: QML Loader: createComponent: Cannot find a QML engine.");
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(message));
+ QTRY_COMPARE(o->property("changes").toInt(), 1);
+}
+
+static void qTestForOverflow(const QUrl &url)
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, url);
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ const QString message = url.toString() + QStringLiteral(": Maximum call stack size exceeded.");
+ QTest::ignoreMessage(QtCriticalMsg, qPrintable(message));
+ QScopedPointer<QObject> o(component.create());
+}
+
+void tst_QQuickLoader::stackOverflow()
+{
+ auto t = QThread::create(qTestForOverflow, testFileUrl("overflow.qml"));
+ t->setStackSize(1024 * 1024);
+ t->start();
+ t->wait();
+}
+
+void tst_QQuickLoader::stackOverflow2()
+{
+ auto t = QThread::create(qTestForOverflow, testFileUrl("overflow2.qml"));
+ t->setStackSize(1024 * 1024);
+ t->start();
+ t->wait();
+}
+
+void tst_QQuickLoader::boundComponent()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("boundComponent.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> o(component.create());
+ QCOMPARE(o->objectName(), QStringLiteral("loaded"));
}
QTEST_MAIN(tst_QQuickLoader)
diff --git a/tests/auto/quick/qquickmousearea/BLACKLIST b/tests/auto/quick/qquickmousearea/BLACKLIST
index 61eb8043e2..ba5aeb5851 100644
--- a/tests/auto/quick/qquickmousearea/BLACKLIST
+++ b/tests/auto/quick/qquickmousearea/BLACKLIST
@@ -1,11 +1,13 @@
+# QTBUG-82043
[pressAndHold]
macos ci
-# QTBUG-78153
-[nestedStopAtBounds]
-opensuse-leap
-
# QTBUG-82282
[pressOneAndTapAnother]
opensuse-leap
+# QTBUG-103092
+[pressOneAndTapAnother]
+android
+[containsMouseAndVisibility]
+android
diff --git a/tests/auto/quick/qquickmousearea/CMakeLists.txt b/tests/auto/quick/qquickmousearea/CMakeLists.txt
index 7061c92384..48262229fc 100644
--- a/tests/auto/quick/qquickmousearea/CMakeLists.txt
+++ b/tests/auto/quick/qquickmousearea/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickmousearea.pro.
#####################################################################
## tst_qquickmousearea Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickmousearea LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,23 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickmousearea
SOURCES
- ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickmousearea.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -40,10 +41,10 @@ qt_internal_add_test(tst_qquickmousearea
qt_internal_extend_target(tst_qquickmousearea CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickmousearea CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickmousearea/data/clickThrough2.qml b/tests/auto/quick/qquickmousearea/data/clickThrough2.qml
index 2624108225..4e87b4eeb5 100644
--- a/tests/auto/quick/qquickmousearea/data/clickThrough2.qml
+++ b/tests/auto/quick/qquickmousearea/data/clickThrough2.qml
@@ -28,8 +28,8 @@ Item{
enabled: true
anchors.fill: parent
propagateComposedEvents: !noPropagation
- onClicked: mouse.accepted = !letThrough;
- onDoubleClicked: mouse.accepted = !letThrough;
- onPressAndHold: mouse.accepted = !letThrough;
+ onClicked: function (mouse) { mouse.accepted = !letThrough; }
+ onDoubleClicked: function (mouse) { mouse.accepted = !letThrough; }
+ onPressAndHold: function (mouse) { mouse.accepted = !letThrough; }
}
}
diff --git a/tests/auto/quick/qquickmousearea/data/containsMouseAndHoverDisabled.qml b/tests/auto/quick/qquickmousearea/data/containsMouseAndHoverDisabled.qml
new file mode 100644
index 0000000000..d98ef85c55
--- /dev/null
+++ b/tests/auto/quick/qquickmousearea/data/containsMouseAndHoverDisabled.qml
@@ -0,0 +1,15 @@
+import QtQuick
+
+Rectangle {
+ width: 200
+ height: 200
+ visible: true
+ MouseArea {
+ id: mouseArea
+ objectName: "mouseArea"
+ anchors.fill: parent
+ hoverEnabled: false
+ onPressed: function(mouse) { mouse.accepted = false }
+ }
+}
+
diff --git a/tests/auto/quick/qquickmousearea/data/containsMouseMasked.qml b/tests/auto/quick/qquickmousearea/data/containsMouseMasked.qml
new file mode 100644
index 0000000000..35cfd4b7ef
--- /dev/null
+++ b/tests/auto/quick/qquickmousearea/data/containsMouseMasked.qml
@@ -0,0 +1,24 @@
+import QtQuick
+
+Rectangle {
+ width: 200
+ height: 200
+ visible: true
+ MouseArea {
+ id: mouseArea1
+ objectName: "mouseArea1"
+ anchors.fill: parent
+ hoverEnabled: true
+ visible: true
+ }
+
+ MouseArea {
+ id: mouseArea2
+ objectName: "mouseArea2"
+ anchors.centerIn: mouseArea1
+ width: 50
+ height: 50
+ hoverEnabled: true
+ visible: true
+ }
+}
diff --git a/tests/auto/quick/qquickmousearea/data/cursorUpdating.qml b/tests/auto/quick/qquickmousearea/data/cursorUpdating.qml
new file mode 100644
index 0000000000..2d06543c78
--- /dev/null
+++ b/tests/auto/quick/qquickmousearea/data/cursorUpdating.qml
@@ -0,0 +1,71 @@
+import QtQuick
+
+Item {
+ width: 600
+ height: 600
+
+ ListModel {
+ id: cursorsModel
+ ListElement { cursorShape: Qt.ArrowCursor; text: "Arrow" }
+ ListElement { cursorShape: Qt.UpArrowCursor; text: "UpArrow" }
+ ListElement { cursorShape: Qt.CrossCursor; text: "Cross" }
+ ListElement { cursorShape: Qt.WaitCursor; text: "Wait" }
+ ListElement { cursorShape: Qt.IBeamCursor; text: "IBeam" }
+ ListElement { cursorShape: Qt.SizeVerCursor; text: "SizeVer" }
+ ListElement { cursorShape: Qt.SizeHorCursor; text: "SizeHor" }
+ ListElement { cursorShape: Qt.SizeBDiagCursor; text: "SizeBDiag" }
+ ListElement { cursorShape: Qt.SizeFDiagCursor; text: "SizeFDiag" }
+ ListElement { cursorShape: Qt.SizeAllCursor; text: "SizeAll" }
+ ListElement { cursorShape: Qt.BlankCursor; text: "Blank" }
+ ListElement { cursorShape: Qt.SplitVCursor; text: "SplitV" }
+ ListElement { cursorShape: Qt.SplitHCursor; text: "SplitH" }
+ ListElement { cursorShape: Qt.PointingHandCursor; text: "PointingHand" }
+ ListElement { cursorShape: Qt.ForbiddenCursor; text: "Forbidden" }
+ ListElement { cursorShape: Qt.WhatsThisCursor; text: "WhatsThis" }
+ ListElement { cursorShape: Qt.BusyCursor; text: "Busy" }
+ ListElement { cursorShape: Qt.OpenHandCursor; text: "OpenHand" }
+ ListElement { cursorShape: Qt.ClosedHandCursor; text: "ClosedHand" }
+ ListElement { cursorShape: Qt.DragCopyCursor; text: "DragCopy" }
+ ListElement { cursorShape: Qt.DragMoveCursor; text: "DragMove" }
+ ListElement { cursorShape: Qt.DragLinkCursor; text: "DragLink" }
+ }
+
+ Flickable {
+ anchors.fill: parent
+ contentHeight: flow.height
+ Flow {
+ id: flow
+ width: parent.width
+ Repeater {
+ model: cursorsModel
+ Rectangle {
+ id: root
+ color: "white"
+ border.width: 5
+ border.color: "black"
+
+ width: 200
+ height: 200
+
+ Text {
+ id: textItem
+ anchors.fill: parent
+ anchors.margins: parent.width * 0.1
+ text: model.text
+ fontSizeMode: Text.Fit
+ minimumPixelSize: 10; font.pixelSize: height
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: model.cursorShape
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickmousearea/data/disableParentOnPress.qml b/tests/auto/quick/qquickmousearea/data/disableParentOnPress.qml
new file mode 100644
index 0000000000..ddd3b5b86d
--- /dev/null
+++ b/tests/auto/quick/qquickmousearea/data/disableParentOnPress.qml
@@ -0,0 +1,14 @@
+import QtQuick
+
+Rectangle {
+ id: whiteRect
+ width: 200
+ height: 200
+ color: ma.pressed ? "lightsteelblue" : "white"
+ MouseArea {
+ id: ma
+ objectName: "mousearea"
+ anchors.fill: parent
+ onPressed: parent.enabled = false
+ }
+}
diff --git a/tests/auto/quick/qquickmousearea/data/doubleClickToHide.qml b/tests/auto/quick/qquickmousearea/data/doubleClickToHide.qml
new file mode 100644
index 0000000000..01f6eaabed
--- /dev/null
+++ b/tests/auto/quick/qquickmousearea/data/doubleClickToHide.qml
@@ -0,0 +1,19 @@
+import QtQuick 2.0
+
+Item {
+ id: root
+ property int clicked: 0
+ property int doubleClicked: 0
+ property int released: 0
+
+ MouseArea {
+ width: 200; height: 200
+ onClicked: { root.clicked++ }
+ onDoubleClicked: {
+ root.doubleClicked++
+ visible = false
+ }
+ onReleased: { root.released++ }
+ }
+}
+
diff --git a/tests/auto/quick/qquickmousearea/data/hoverAfterPress.qml b/tests/auto/quick/qquickmousearea/data/hoverAfterPress.qml
index 69ec8fbd47..97512d1106 100644
--- a/tests/auto/quick/qquickmousearea/data/hoverAfterPress.qml
+++ b/tests/auto/quick/qquickmousearea/data/hoverAfterPress.qml
@@ -16,7 +16,7 @@ Item {
objectName: "mouseArea"
anchors.fill: parent
hoverEnabled: true
- onPressed: mouse.accepted = false
+ onPressed: function (mouse) { mouse.accepted = false }
//onContainsMouseChanged: print("containsMouse changed =", containsMouse)
Rectangle {
diff --git a/tests/auto/quick/qquickmousearea/data/ignoreBySource.qml b/tests/auto/quick/qquickmousearea/data/ignoreBySource.qml
index a53cbf7b1d..bb20a317f7 100644
--- a/tests/auto/quick/qquickmousearea/data/ignoreBySource.qml
+++ b/tests/auto/quick/qquickmousearea/data/ignoreBySource.qml
@@ -21,7 +21,7 @@ Item {
MouseArea {
id: ma
objectName: "mousearea"
- onPressed: {
+ onPressed: function (mouse) {
root.lastEventSource = mouse.source
if (mouse.source !== root.allowedSource)
mouse.accepted = false
diff --git a/tests/auto/quick/qquickmousearea/data/mask.qml b/tests/auto/quick/qquickmousearea/data/mask.qml
index ec315c2a63..ab8ecbf32d 100644
--- a/tests/auto/quick/qquickmousearea/data/mask.qml
+++ b/tests/auto/quick/qquickmousearea/data/mask.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 Ford Motor Company
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 Ford Motor Company
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.11
import Test 1.0
diff --git a/tests/auto/quick/qquickmousearea/data/moveAndReleaseWithoutPress.qml b/tests/auto/quick/qquickmousearea/data/moveAndReleaseWithoutPress.qml
index 6c68f0c7c8..4b7324a98a 100644
--- a/tests/auto/quick/qquickmousearea/data/moveAndReleaseWithoutPress.qml
+++ b/tests/auto/quick/qquickmousearea/data/moveAndReleaseWithoutPress.qml
@@ -7,7 +7,7 @@ MouseArea {
property bool hadMove: false
property bool hadRelease: false
- onPressed: mouse.accepted = false
+ onPressed: function (mouse) { mouse.accepted = false }
onPositionChanged: hadMove = true
onReleased: hadRelease = true
}
diff --git a/tests/auto/quick/qquickmousearea/data/preventStealingListViewChild.qml b/tests/auto/quick/qquickmousearea/data/preventStealingListViewChild.qml
new file mode 100644
index 0000000000..3833c5a8a9
--- /dev/null
+++ b/tests/auto/quick/qquickmousearea/data/preventStealingListViewChild.qml
@@ -0,0 +1,31 @@
+import QtQuick 2.15
+
+ListView {
+ id: flick
+ width: 640
+ height: 480
+ model: 100
+
+ delegate: Rectangle {
+ border.color: "#81e889"
+ width: 640; height: 100
+ Text { text: "Row " + index }
+ }
+
+ Rectangle {
+ anchors.right: parent.right
+ anchors.margins: 2
+ color: ma.pressed ? "#81e889" : "#c2f4c6"
+ width: 50; height: 50
+ radius: 5
+ MouseArea {
+ id: ma
+ anchors.fill: parent
+ preventStealing: true
+ drag {
+ target: parent
+ axis: Drag.YAxis
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickmousearea/data/qtbug34368.qml b/tests/auto/quick/qquickmousearea/data/qtbug34368.qml
index 42d8ddd3b6..96e72a8edc 100644
--- a/tests/auto/quick/qquickmousearea/data/qtbug34368.qml
+++ b/tests/auto/quick/qquickmousearea/data/qtbug34368.qml
@@ -12,7 +12,7 @@ Rectangle {
anchors.fill: parent
propagateComposedEvents: true
z: 1
- onClicked: {
+ onClicked: function (mouse) {
mouse.accepted = false;
clicksEnabled += 1;
//console.log("Upper click");
@@ -23,7 +23,7 @@ Rectangle {
propagateComposedEvents: true
z: 0
enabled: !disableLower
- onClicked: {
+ onClicked: function (mouse) {
mouse.accepted = false;
clicksDisabled += 1;
//console.log("Lower click");
diff --git a/tests/auto/quick/qquickmousearea/data/qtbug49100.qml b/tests/auto/quick/qquickmousearea/data/qtbug49100.qml
index 39b293c8fa..d3dfe64d94 100644
--- a/tests/auto/quick/qquickmousearea/data/qtbug49100.qml
+++ b/tests/auto/quick/qquickmousearea/data/qtbug49100.qml
@@ -8,7 +8,7 @@ ListView {
delegate: Text {
text: index + 1
height: 30
- width: parent.width
+ width: ListView.view.width
MouseArea {
anchors.fill: parent
}
diff --git a/tests/auto/quick/qquickmousearea/data/rejectEvent.qml b/tests/auto/quick/qquickmousearea/data/rejectEvent.qml
index 48b68ee845..03a075300a 100644
--- a/tests/auto/quick/qquickmousearea/data/rejectEvent.qml
+++ b/tests/auto/quick/qquickmousearea/data/rejectEvent.qml
@@ -23,7 +23,7 @@ Rectangle {
id: mouseRegion2
objectName: "mouseRegion2"
width: 120; height: 120
- onPressed: { root.mr2_pressed = true; mouse.accepted = false }
+ onPressed: function (mouse) { root.mr2_pressed = true; mouse.accepted = false }
onReleased: { root.mr2_released = true }
onCanceled: { root.mr2_canceled = true }
}
diff --git a/tests/auto/quick/qquickmousearea/data/simple.qml b/tests/auto/quick/qquickmousearea/data/simple.qml
index 56d561e5af..2b8a2af118 100644
--- a/tests/auto/quick/qquickmousearea/data/simple.qml
+++ b/tests/auto/quick/qquickmousearea/data/simple.qml
@@ -4,8 +4,9 @@ Rectangle {
id: whiteRect
width: 200
height: 200
- color: "white"
+ color: ma.pressed ? "lightsteelblue" : "white"
MouseArea {
+ id: ma
objectName: "mousearea"
anchors.fill: parent
}
diff --git a/tests/auto/quick/qquickmousearea/data/updateMousePosOnResize.qml b/tests/auto/quick/qquickmousearea/data/updateMousePosOnResize.qml
index 55af864060..a20f752864 100644
--- a/tests/auto/quick/qquickmousearea/data/updateMousePosOnResize.qml
+++ b/tests/auto/quick/qquickmousearea/data/updateMousePosOnResize.qml
@@ -22,19 +22,19 @@ Rectangle {
property bool mouseMatchesPos: true
anchors.fill: brother
- onPressed: {
+ onPressed: function (mouse) {
if (mouse.x != mouseX || mouse.y != mouseY)
mouseMatchesPos = false
x1 = mouseX; y1 = mouseY
anchors.fill = parent
}
onPositionChanged: { emitPositionChanged = true }
- onMouseXChanged: {
+ onMouseXChanged: function (mouse) {
if (mouse.x != mouseX || mouse.y != mouseY)
mouseMatchesPos = false
x2 = mouseX; y2 = mouseY
}
- onMouseYChanged: {
+ onMouseYChanged: function (mouse) {
if (mouse.x != mouseX || mouse.y != mouseY)
mouseMatchesPos = false
x2 = mouseX; y2 = mouseY
diff --git a/tests/auto/quick/qquickmousearea/data/wheel.qml b/tests/auto/quick/qquickmousearea/data/wheel.qml
index 3e0c0c2a48..6cd367b22f 100644
--- a/tests/auto/quick/qquickmousearea/data/wheel.qml
+++ b/tests/auto/quick/qquickmousearea/data/wheel.qml
@@ -14,7 +14,7 @@ Rectangle {
MouseArea {
anchors.fill: parent
- onWheel: {
+ onWheel: function (wheel) {
root.angleDeltaY = wheel.angleDelta.y;
root.mouseX = wheel.x;
root.mouseY = wheel.y;
diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
index 1e9f76c8ce..37d8c910f5 100644
--- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
+++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtTest/QSignalSpy>
@@ -36,15 +11,23 @@
#include <QtQuick/qquickview.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlengine.h>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
#include <QtGui/qstylehints.h>
#include <QtGui/QCursor>
#include <QtGui/QScreen>
+#include <QEvent>
+#include <QQmlComponent>
#include <qpa/qwindowsysteminterface.h>
+#include <qpa/qwindowsysteminterface_p.h>
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+static bool isPlatformWayland()
+{
+ return !QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive);
+}
+
class CircleMask : public QObject
{
Q_OBJECT
@@ -89,6 +72,7 @@ class tst_QQuickMouseArea: public QQmlDataTest
Q_OBJECT
public:
tst_QQuickMouseArea()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
qmlRegisterType<CircleMask>("Test", 1, 0, "CircleMask");
qmlRegisterType<EventSender>("Test", 1, 0, "EventSender");
@@ -116,19 +100,24 @@ private slots:
void pressedCanceledOnWindowDeactivate();
void doubleClick_data() { acceptedButton_data(); }
void doubleClick();
+ void doubleTap();
void clickTwice_data() { acceptedButton_data(); }
void clickTwice();
void invalidClick_data() { rejectedButton_data(); }
void invalidClick();
void pressedOrdering();
void preventStealing();
+ void preventStealingListViewChild();
void clickThrough();
void hoverPosition();
void hoverPropagation();
void hoverVisible();
void hoverAfterPress();
void subtreeHoverEnabled();
+ void hoverWhenDisabled();
void disableAfterPress();
+ void disableParentOnPress_data();
+ void disableParentOnPress();
void onWheel();
void transformedMouseArea_data();
void transformedMouseArea();
@@ -137,6 +126,7 @@ private slots:
void changeAxis();
#if QT_CONFIG(cursor)
void cursorShape();
+ void cursorUpdating();
#endif
void moveAndReleaseWithoutPress();
void nestedStopAtBounds();
@@ -155,6 +145,14 @@ private slots:
void settingHiddenInPressUngrabs();
void negativeZStackingOrder();
void containsMouseAndVisibility();
+ void containsMouseAndVisibilityMasked();
+ void containsMouseAndHoverDisabled();
+ void doubleClickToHide();
+ void releaseFirstTouchAfterSecond();
+#if QT_CONFIG(tabletevent)
+ void tabletStylusTap();
+#endif
+ void syntheticRightClick();
private:
int startDragDistance() const {
@@ -162,7 +160,7 @@ private:
}
void acceptedButton_data();
void rejectedButton_data();
- QPointingDevice *device = QTest::createTouchDevice();
+ QPointingDevice *device = QTest::createTouchDevice(); // TODO const after fixing QTBUG-107864
};
Q_DECLARE_METATYPE(Qt::MouseButton)
@@ -210,18 +208,18 @@ void tst_QQuickMouseArea::dragProperties()
QVERIFY(rootItem != nullptr);
QSignalSpy targetSpy(drag, SIGNAL(targetChanged()));
drag->setTarget(rootItem);
- QCOMPARE(targetSpy.count(),1);
+ QCOMPARE(targetSpy.size(),1);
drag->setTarget(rootItem);
- QCOMPARE(targetSpy.count(),1);
+ QCOMPARE(targetSpy.size(),1);
// axis
QCOMPARE(drag->axis(), QQuickDrag::XAndYAxis);
QSignalSpy axisSpy(drag, SIGNAL(axisChanged()));
drag->setAxis(QQuickDrag::XAxis);
QCOMPARE(drag->axis(), QQuickDrag::XAxis);
- QCOMPARE(axisSpy.count(),1);
+ QCOMPARE(axisSpy.size(),1);
drag->setAxis(QQuickDrag::XAxis);
- QCOMPARE(axisSpy.count(),1);
+ QCOMPARE(axisSpy.size(),1);
// minimum and maximum properties
QSignalSpy xminSpy(drag, SIGNAL(minimumXChanged()));
@@ -244,20 +242,20 @@ void tst_QQuickMouseArea::dragProperties()
QCOMPARE(drag->ymin(), 10.0);
QCOMPARE(drag->ymax(), 10.0);
- QCOMPARE(xminSpy.count(),1);
- QCOMPARE(xmaxSpy.count(),1);
- QCOMPARE(yminSpy.count(),1);
- QCOMPARE(ymaxSpy.count(),1);
+ QCOMPARE(xminSpy.size(),1);
+ QCOMPARE(xmaxSpy.size(),1);
+ QCOMPARE(yminSpy.size(),1);
+ QCOMPARE(ymaxSpy.size(),1);
drag->setXmin(10);
drag->setXmax(10);
drag->setYmin(10);
drag->setYmax(10);
- QCOMPARE(xminSpy.count(),1);
- QCOMPARE(xmaxSpy.count(),1);
- QCOMPARE(yminSpy.count(),1);
- QCOMPARE(ymaxSpy.count(),1);
+ QCOMPARE(xminSpy.size(),1);
+ QCOMPARE(xmaxSpy.size(),1);
+ QCOMPARE(yminSpy.size(),1);
+ QCOMPARE(ymaxSpy.size(),1);
// filterChildren
QSignalSpy filterChildrenSpy(drag, SIGNAL(filterChildrenChanged()));
@@ -265,24 +263,24 @@ void tst_QQuickMouseArea::dragProperties()
drag->setFilterChildren(true);
QVERIFY(drag->filterChildren());
- QCOMPARE(filterChildrenSpy.count(), 1);
+ QCOMPARE(filterChildrenSpy.size(), 1);
drag->setFilterChildren(true);
- QCOMPARE(filterChildrenSpy.count(), 1);
+ QCOMPARE(filterChildrenSpy.size(), 1);
// threshold
QCOMPARE(int(drag->threshold()), qApp->styleHints()->startDragDistance());
QSignalSpy thresholdSpy(drag, SIGNAL(thresholdChanged()));
drag->setThreshold(0.0);
QCOMPARE(drag->threshold(), 0.0);
- QCOMPARE(thresholdSpy.count(), 1);
+ QCOMPARE(thresholdSpy.size(), 1);
drag->setThreshold(99);
- QCOMPARE(thresholdSpy.count(), 2);
+ QCOMPARE(thresholdSpy.size(), 2);
drag->setThreshold(99);
- QCOMPARE(thresholdSpy.count(), 2);
+ QCOMPARE(thresholdSpy.size(), 2);
drag->resetThreshold();
QCOMPARE(int(drag->threshold()), qApp->styleHints()->startDragDistance());
- QCOMPARE(thresholdSpy.count(), 3);
+ QCOMPARE(thresholdSpy.size(), 3);
}
void tst_QQuickMouseArea::resetDrag()
@@ -307,7 +305,7 @@ void tst_QQuickMouseArea::resetDrag()
auto root = window.rootObject();
QQmlProperty haveTarget {root, "haveTarget"};
haveTarget.write(false);
- QCOMPARE(targetSpy.count(),1);
+ QCOMPARE(targetSpy.size(),1);
QVERIFY(!drag->target());
}
@@ -740,7 +738,9 @@ void tst_QQuickMouseArea::updateMouseAreaPosOnResize()
QCOMPARE(mouseRegion->mouseX(), 0.0);
QCOMPARE(mouseRegion->mouseY(), 0.0);
- QMouseEvent event(QEvent::MouseButtonPress, rect->position().toPoint(), Qt::LeftButton, Qt::LeftButton, {});
+ QMouseEvent event(QEvent::MouseButtonPress, rect->position().toPoint(),
+ window.mapToGlobal(rect->position().toPoint()),
+ Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &event);
QVERIFY(!mouseRegion->property("emitPositionChanged").toBool());
@@ -853,8 +853,10 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate()
QCOMPARE(window.rootObject()->property("released").toInt(), expectedRelease);
QCOMPARE(window.rootObject()->property("clicked").toInt(), expectedClicks);
- QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
- QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100),
+ window.mapToGlobal(QPoint(100, 100)), Qt::LeftButton, Qt::LeftButton, {});
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100),
+ window.mapToGlobal(QPoint(100, 100)), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &pressEvent);
@@ -871,7 +873,8 @@ void tst_QQuickMouseArea::pressedCanceledOnWindowDeactivate()
QCOMPARE(window.rootObject()->property("clicked").toInt(), ++expectedClicks);
QGuiApplication::sendEvent(&window, &pressEvent);
- QMouseEvent pressEvent2(QEvent::MouseButtonDblClick, QPoint(100, 100), Qt::LeftButton, Qt::LeftButton, {});
+ QMouseEvent pressEvent2(QEvent::MouseButtonDblClick, QPoint(100, 100),
+ window.mapToGlobal(QPoint(100, 100)), Qt::LeftButton, Qt::LeftButton, {});
QGuiApplication::sendEvent(&window, &pressEvent2);
QTRY_VERIFY(window.rootObject()->property("pressed").toBool());
@@ -917,16 +920,19 @@ void tst_QQuickMouseArea::doubleClick()
// The sequence for a double click is:
// press, release, (click), press, double click, release
- QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, {});
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100),
+ window.mapToGlobal(QPoint(100, 100)), button, button, {});
QGuiApplication::sendEvent(&window, &pressEvent);
- QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, {});
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100),
+ window.mapToGlobal(QPoint(100, 100)), button, button, {});
QGuiApplication::sendEvent(&window, &releaseEvent);
QCOMPARE(window.rootObject()->property("released").toInt(), 1);
QGuiApplication::sendEvent(&window, &pressEvent);
- QMouseEvent pressEvent2 = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, {});
+ QMouseEvent pressEvent2 = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100),
+ window.mapToGlobal(QPoint(100, 100)), button, button, {});
QGuiApplication::sendEvent(&window, &pressEvent2);
QGuiApplication::sendEvent(&window, &releaseEvent);
@@ -935,6 +941,61 @@ void tst_QQuickMouseArea::doubleClick()
QCOMPARE(window.rootObject()->property("released").toInt(), 2);
}
+void tst_QQuickMouseArea::doubleTap() // QTBUG-112434
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("doubleclick.qml")));
+
+ QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>("mousearea");
+ QVERIFY(mouseArea);
+ QPoint p1 = mouseArea->mapToScene(mouseArea->boundingRect().center()).toPoint();
+
+ QTest::touchEvent(&window, device).press(0, p1);
+ QQuickTouchUtils::flush(&window);
+ QTest::touchEvent(&window, device).release(0, p1);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(window.rootObject()->property("released").toInt(), 1);
+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 1);
+
+ p1 += QPoint(1, -1); // movement less than QPlatformTheme::TouchDoubleTapDistance
+ QTest::touchEvent(&window, device).press(1, p1); // touchpoint ID is different the second time
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(mouseArea->isPressed(), true);
+ // at this time QQuickDeliveryAgentPrivate::deliverTouchAsMouse() synthesizes the double-click event
+ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1);
+
+ QTest::touchEvent(&window, device).release(1, p1);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(window.rootObject()->property("released").toInt(), 2);
+ QCOMPARE(mouseArea->isPressed(), false);
+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 1);
+
+ // now tap with two fingers simultaneously: only one of them generates synth-mouse
+ QPoint p2 = p1 + QPoint(50, 5);
+ QTest::touchEvent(&window, device).press(2, p1).press(3, p2);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(mouseArea->isPressed(), true);
+ QTest::touchEvent(&window, device).release(2, p1).release(3, p2);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(window.rootObject()->property("released").toInt(), 3);
+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 2);
+ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1);
+ QCOMPARE(mouseArea->isPressed(), false);
+
+ // tap with two fingers simultaneously again: get another double-click from one point
+ p1 -= QPoint(1, -1);
+ p2 += QPoint(1, -1);
+ QTest::touchEvent(&window, device).press(4, p1).press(5, p2);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(mouseArea->isPressed(), true);
+ QTest::touchEvent(&window, device).release(4, p1).release(5, p2);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(window.rootObject()->property("released").toInt(), 4);
+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 2);
+ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 2);
+ QCOMPARE(mouseArea->isPressed(), false); // make sure it doesn't get stuck
+}
+
// QTBUG-14832
void tst_QQuickMouseArea::clickTwice()
{
@@ -948,10 +1009,12 @@ void tst_QQuickMouseArea::clickTwice()
QVERIFY(mouseArea);
mouseArea->setAcceptedButtons(acceptedButtons);
- QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, {});
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100),
+ window.mapToGlobal(QPoint(100, 100)), button, button, {});
QGuiApplication::sendEvent(&window, &pressEvent);
- QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, {});
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100),
+ window.mapToGlobal(QPoint(100, 100)), button, button, {});
QGuiApplication::sendEvent(&window, &releaseEvent);
QCOMPARE(window.rootObject()->property("pressed").toInt(), 1);
@@ -960,7 +1023,8 @@ void tst_QQuickMouseArea::clickTwice()
QGuiApplication::sendEvent(&window, &pressEvent);
- QMouseEvent pressEvent2 = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, {});
+ QMouseEvent pressEvent2 = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100),
+ window.mapToGlobal(QPoint(100, 100)), button, button, {});
QGuiApplication::sendEvent(&window, &pressEvent2);
QGuiApplication::sendEvent(&window, &releaseEvent);
@@ -983,16 +1047,19 @@ void tst_QQuickMouseArea::invalidClick()
// The sequence for a double click is:
// press, release, (click), press, double click, release
- QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100), button, button, {});
+ QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(100, 100),
+ window.mapToGlobal(QPoint(100, 100)), button, button, {});
QGuiApplication::sendEvent(&window, &pressEvent);
- QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100), button, button, {});
+ QMouseEvent releaseEvent(QEvent::MouseButtonRelease, QPoint(100, 100),
+ window.mapToGlobal(QPoint(100, 100)), button, button, {});
QGuiApplication::sendEvent(&window, &releaseEvent);
QCOMPARE(window.rootObject()->property("released").toInt(), 0);
QGuiApplication::sendEvent(&window, &pressEvent);
- QMouseEvent pressEvent2 = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100), button, button, {});
+ QMouseEvent pressEvent2 = QMouseEvent(QEvent::MouseButtonDblClick, QPoint(100, 100),
+ window.mapToGlobal(QPoint(100, 100)), button, button, {});
QGuiApplication::sendEvent(&window, &pressEvent2);
QGuiApplication::sendEvent(&window, &releaseEvent);
@@ -1050,9 +1117,9 @@ void tst_QQuickMouseArea::preventStealing()
QTest::mouseMove(&window, p);
// We should have received all four move events
- QTRY_COMPARE(mousePositionSpy.count(), 4);
+ QTRY_COMPARE(mousePositionSpy.size(), 4);
mousePositionSpy.clear();
- QVERIFY(mouseArea->pressed());
+ QVERIFY(mouseArea->isPressed());
// Flickable content should not have moved.
QCOMPARE(flickable->contentX(), 0.);
@@ -1079,9 +1146,9 @@ void tst_QQuickMouseArea::preventStealing()
QTest::mouseMove(&window, p);
// We should only have received the first move event
- QTRY_COMPARE(mousePositionSpy.count(), 1);
+ QTRY_COMPARE(mousePositionSpy.size(), 1);
// Our press should be taken away
- QVERIFY(!mouseArea->pressed());
+ QVERIFY(!mouseArea->isPressed());
// Flickable swallows the first move, then moves 2*10 px
QTRY_COMPARE(flickable->contentX(), 20.);
@@ -1090,6 +1157,36 @@ void tst_QQuickMouseArea::preventStealing()
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p);
}
+// QTBUG-103522
+void tst_QQuickMouseArea::preventStealingListViewChild()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("preventStealingListViewChild.qml")));
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable*>(window.rootObject());
+ QVERIFY(flickable);
+ QQuickMouseArea *mouseArea = flickable->findChild<QQuickMouseArea*>();
+ QVERIFY(mouseArea);
+ QPoint p = mouseArea->mapToScene(mouseArea->boundingRect().center()).toPoint();
+ const int threshold = qApp->styleHints()->startDragDistance();
+
+ flickable->flick(0, -10000);
+ for (int i = 0; i < 2; ++i) {
+ QVERIFY(flickable->isMovingVertically());
+ QTest::touchEvent(&window, device).press(0, p);
+ QQuickTouchUtils::flush(&window);
+ for (int j = 0; j < 4 && !mouseArea->drag()->active(); ++j) {
+ p += QPoint(0, threshold);
+ QTest::touchEvent(&window, device).move(0, p);
+ QQuickTouchUtils::flush(&window);
+ }
+ // MouseArea should be dragged because of preventStealing; ListView does not steal the grab.
+ QVERIFY(mouseArea->drag()->active());
+ QCOMPARE(flickable->isDragging(), false);
+ QTest::touchEvent(&window, device).release(0, p);
+ QCOMPARE(mouseArea->drag()->active(), false);
+ }
+}
+
void tst_QQuickMouseArea::clickThrough()
{
// timestamp delay to avoid generating a double click
@@ -1272,9 +1369,8 @@ void tst_QQuickMouseArea::hoverPropagation()
void tst_QQuickMouseArea::hoverVisible()
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QQuickView window;
QVERIFY(QQuickTest::showView(window, testFileUrl("hoverVisible.qml")));
@@ -1291,12 +1387,12 @@ void tst_QQuickMouseArea::hoverVisible()
QTest::mouseMove(&window,QPoint(11,33));
QCOMPARE(mouseTracker->hovered(), false);
- QCOMPARE(enteredSpy.count(), 0);
+ QCOMPARE(enteredSpy.size(), 0);
mouseTracker->setVisible(true);
QCOMPARE(mouseTracker->hovered(), true);
- QCOMPARE(enteredSpy.count(), 1);
+ QCOMPARE(enteredSpy.size(), 1);
QCOMPARE(QPointF(mouseTracker->mouseX(), mouseTracker->mouseY()), QPointF(11,33));
@@ -1371,6 +1467,37 @@ void tst_QQuickMouseArea::subtreeHoverEnabled()
QCOMPARE(mouseArea->hovered(), false);
}
+void tst_QQuickMouseArea::hoverWhenDisabled()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("hoverVisible.qml")));
+ QQuickItem *root = window.rootObject();
+ QVERIFY(root);
+
+ QQuickMouseArea *mouseArea = root->findChild<QQuickMouseArea*>();
+ QVERIFY(mouseArea);
+ mouseArea->setVisible(true);
+
+ QTest::mouseMove(&window, QPoint(50, 50));
+ QVERIFY(mouseArea->hovered());
+
+ mouseArea->setEnabled(false);
+ QTest::mouseMove(&window, QPoint(51, 50));
+ QVERIFY(!mouseArea->hovered());
+
+ mouseArea->setEnabled(true);
+ QTest::mouseMove(&window, QPoint(50, 50));
+ QVERIFY(mouseArea->hovered());
+
+ mouseArea->setHoverEnabled(false);
+ QTest::mouseMove(&window, QPoint(51, 50));
+ QVERIFY(!mouseArea->hovered());
+
+ mouseArea->setHoverEnabled(true);
+ QTest::mouseMove(&window, QPoint(50, 50));
+ QVERIFY(mouseArea->hovered());
+}
+
void tst_QQuickMouseArea::disableAfterPress()
{
QQuickView window;
@@ -1395,7 +1522,7 @@ void tst_QQuickMouseArea::disableAfterPress()
QVERIFY(!drag->active());
QPoint p = QPoint(100,100);
QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p);
- QTRY_COMPARE(mousePressSpy.count(), 1);
+ QTRY_COMPARE(mousePressSpy.size(), 1);
QVERIFY(!drag->active());
QCOMPARE(blackRect->x(), 50.0);
@@ -1409,7 +1536,7 @@ void tst_QQuickMouseArea::disableAfterPress()
p += QPoint(11, 11);
QTest::mouseMove(&window, p);
- QTRY_COMPARE(mousePositionSpy.count(), 2);
+ QTRY_COMPARE(mousePositionSpy.size(), 2);
QTRY_VERIFY(drag->active());
QTRY_COMPARE(blackRect->x(), 61.0);
@@ -1423,24 +1550,24 @@ void tst_QQuickMouseArea::disableAfterPress()
p += QPoint(11, 11);
QTest::mouseMove(&window, p);
- QTRY_COMPARE(mousePositionSpy.count(), 4);
+ QTRY_COMPARE(mousePositionSpy.size(), 4);
QVERIFY(drag->active());
QCOMPARE(blackRect->x(), 83.0);
QCOMPARE(blackRect->y(), 83.0);
- QVERIFY(mouseArea->pressed());
+ QVERIFY(mouseArea->isPressed());
QVERIFY(mouseArea->hovered());
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p);
- QTRY_COMPARE(mouseReleaseSpy.count(), 1);
+ QTRY_COMPARE(mouseReleaseSpy.size(), 1);
QVERIFY(!drag->active());
QCOMPARE(blackRect->x(), 83.0);
QCOMPARE(blackRect->y(), 83.0);
- QVERIFY(!mouseArea->pressed());
+ QVERIFY(!mouseArea->isPressed());
QVERIFY(!mouseArea->hovered()); // since hover is not enabled
// Next press will be ignored
@@ -1453,14 +1580,14 @@ void tst_QQuickMouseArea::disableAfterPress()
QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100,100));
QTest::qWait(50);
- QCOMPARE(mousePressSpy.count(), 0);
+ QCOMPARE(mousePressSpy.size(), 0);
QTest::mouseMove(&window, QPoint(111,111));
QTest::qWait(50);
QTest::mouseMove(&window, QPoint(122,122));
QTest::qWait(50);
- QCOMPARE(mousePositionSpy.count(), 0);
+ QCOMPARE(mousePositionSpy.size(), 0);
QVERIFY(!drag->active());
QCOMPARE(blackRect->x(), 50.0);
@@ -1469,7 +1596,54 @@ void tst_QQuickMouseArea::disableAfterPress()
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(122,122));
QTest::qWait(50);
- QCOMPARE(mouseReleaseSpy.count(), 0);
+ QCOMPARE(mouseReleaseSpy.size(), 0);
+}
+
+void tst_QQuickMouseArea::disableParentOnPress_data()
+{
+ QTest::addColumn<const QPointingDevice *>("device");
+
+ QTest::newRow("core pointer") << QPointingDevice::primaryPointingDevice();
+ QTest::newRow("touch") << static_cast<const QPointingDevice *>(device); // TODO QTBUG-107864
+}
+
+void tst_QQuickMouseArea::disableParentOnPress() // QTBUG-39806 and QTBUG-103788
+{
+ QFETCH(const QPointingDevice *, device);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("disableParentOnPress.qml")));
+ QQuickItem *root = window.rootObject();
+ QVERIFY(root);
+ QQuickMouseArea *mouseArea = root->findChild<QQuickMouseArea*>();
+ QVERIFY(mouseArea);
+
+ QSignalSpy pressedChangedSpy(mouseArea, &QQuickMouseArea::pressedChanged);
+ QSignalSpy canceledSpy(mouseArea, &QQuickMouseArea::canceled);
+ QSignalSpy enabledSpy(mouseArea, &QQuickMouseArea::enabledChanged);
+ QSignalSpy parentEnabledSpy(root, &QQuickItem::enabledChanged);
+ const QPoint p(100, 100);
+
+ QQuickTest::pointerPress(device, &window, 0, p);
+ QTRY_COMPARE(parentEnabledSpy.size(), 1);
+ QVERIFY(!root->isEnabled());
+ QVERIFY(mouseArea->isEnabled()); // enabled is independent, unfortunately (inverse of QTBUG-38364)
+ QVERIFY(!QQuickItemPrivate::get(mouseArea)->effectiveEnable);
+ // bug fix: it knows it got effectively disabled, so now it's no longer pressed
+ QVERIFY(!mouseArea->isPressed());
+ QCOMPARE(canceledSpy.size(), 1); // ...because the press was canceled
+ QCOMPARE(pressedChangedSpy.size(), 2); // kerchunk
+ QQuickTest::pointerRelease(device, &window, 0, p);
+
+ // now re-enable it and try again
+ root->setEnabled(true);
+ QQuickTest::pointerPress(device, &window, 0, p);
+ QTRY_VERIFY(!root->isEnabled());
+ QVERIFY(!QQuickItemPrivate::get(mouseArea)->effectiveEnable);
+ QVERIFY(!mouseArea->isPressed());
+ QCOMPARE(canceledSpy.size(), 2);
+ QCOMPARE(pressedChangedSpy.size(), 4);
+ QQuickTest::pointerRelease(device, &window, 0, p);
}
void tst_QQuickMouseArea::onWheel()
@@ -1632,18 +1806,18 @@ void tst_QQuickMouseArea::pressedMultipleButtons()
mouseArea->setAcceptedMouseButtons(accepted);
QPoint point(10, 10);
- for (int i = 0; i < mouseEvents.count(); ++i) {
+ for (int i = 0; i < mouseEvents.size(); ++i) {
const MouseEvent mouseEvent = mouseEvents.at(i);
if (mouseEvent.type == QEvent::MouseButtonPress)
QTest::mousePress(&window, mouseEvent.button, Qt::NoModifier, point);
else
QTest::mouseRelease(&window, mouseEvent.button, Qt::NoModifier, point);
- QCOMPARE(mouseArea->pressed(), pressed.at(i));
+ QCOMPARE(mouseArea->isPressed(), pressed.at(i));
QCOMPARE(mouseArea->pressedButtons(), pressedButtons.at(i));
}
- QCOMPARE(pressedSpy.count(), 2);
- QCOMPARE(pressedButtonsSpy.count(), changeCount);
+ QCOMPARE(pressedSpy.size(), 2);
+ QCOMPARE(pressedButtonsSpy.size(), changeCount);
}
void tst_QQuickMouseArea::changeAxis()
@@ -1723,15 +1897,47 @@ void tst_QQuickMouseArea::cursorShape()
mouseArea->setCursorShape(Qt::IBeamCursor);
QCOMPARE(mouseArea->cursorShape(), Qt::IBeamCursor);
QCOMPARE(mouseArea->cursor().shape(), Qt::IBeamCursor);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
mouseArea->setCursorShape(Qt::IBeamCursor);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
mouseArea->setCursorShape(Qt::WaitCursor);
QCOMPARE(mouseArea->cursorShape(), Qt::WaitCursor);
QCOMPARE(mouseArea->cursor().shape(), Qt::WaitCursor);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
+}
+
+void tst_QQuickMouseArea::cursorUpdating()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("cursorUpdating.qml")));
+ QQuickItem *root = window.rootObject();
+ QVERIFY(root);
+ QQuickFlickable *flickable = root->findChild<QQuickFlickable*>();
+ QVERIFY(flickable);
+ QQuickItemPrivate *rootPrivate = QQuickItemPrivate::get(root);
+ QVERIFY(rootPrivate->subtreeCursorEnabled);
+
+ QTest::mouseMove(&window, QPoint(40, 40));
+ QCOMPARE(window.cursor().shape(), Qt::ArrowCursor);
+
+ QTest::mouseMove(&window, QPoint(240, 40));
+ QCOMPARE(window.cursor().shape(), Qt::UpArrowCursor);
+
+ if (isPlatformWayland())
+ QSKIP("Wayland: QCursor::setPos() doesn't work.");
+
+ // QTBUG-53987: with the cursor physically hovering, use wheel to
+ // position a different item that requests a different cursor
+ const QPoint p(240, 40);
+ const QPoint pg = window.mapToGlobal(p);
+ QCursor::setPos(pg);
+ QWheelEvent wheelEvent(p, pg, QPoint(60, -400), QPoint(0, -600),
+ Qt::NoButton, Qt::ControlModifier, Qt::NoScrollPhase, false);
+ QGuiApplication::sendEvent(&window, &wheelEvent);
+ QTRY_VERIFY(flickable->contentY() > 300);
+ QCOMPARE(window.cursor().shape(), Qt::IBeamCursor);
}
#endif
@@ -1797,7 +2003,12 @@ void tst_QQuickMouseArea::nestedStopAtBounds()
QTest::mouseMove(&window, position);
axis += invert ? threshold : -threshold;
QTest::mouseMove(&window, position);
- QTRY_COMPARE(outer->drag()->active(), true);
+
+ // outer drag will not receive mouse event, when the focus has been stolen.
+ // => try to regain and time out if it fails.
+ while (!QTest::qWaitFor([&outer]() { return outer->drag()->active(); }))
+ window.raise();
+
QCOMPARE(inner->drag()->active(), false);
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, position);
@@ -1932,37 +2143,37 @@ void tst_QQuickMouseArea::containsPress()
QTest::mouseMove(&window, QPoint(22,33));
QCOMPARE(mouseArea->hovered(), false);
- QCOMPARE(mouseArea->pressed(), false);
+ QCOMPARE(mouseArea->isPressed(), false);
QCOMPARE(mouseArea->containsPress(), false);
QTest::mouseMove(&window, QPoint(200,200));
QCOMPARE(mouseArea->hovered(), hoverEnabled);
- QCOMPARE(mouseArea->pressed(), false);
+ QCOMPARE(mouseArea->isPressed(), false);
QCOMPARE(mouseArea->containsPress(), false);
QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(200,200));
QCOMPARE(mouseArea->hovered(), true);
- QTRY_COMPARE(mouseArea->pressed(), true);
+ QTRY_COMPARE(mouseArea->isPressed(), true);
QCOMPARE(mouseArea->containsPress(), true);
- QCOMPARE(containsPressSpy.count(), 1);
+ QCOMPARE(containsPressSpy.size(), 1);
QTest::mouseMove(&window, QPoint(22,33));
QCOMPARE(mouseArea->hovered(), false);
- QCOMPARE(mouseArea->pressed(), true);
+ QCOMPARE(mouseArea->isPressed(), true);
QCOMPARE(mouseArea->containsPress(), false);
- QCOMPARE(containsPressSpy.count(), 2);
+ QCOMPARE(containsPressSpy.size(), 2);
QTest::mouseMove(&window, QPoint(200,200));
QCOMPARE(mouseArea->hovered(), true);
- QCOMPARE(mouseArea->pressed(), true);
+ QCOMPARE(mouseArea->isPressed(), true);
QCOMPARE(mouseArea->containsPress(), true);
- QCOMPARE(containsPressSpy.count(), 3);
+ QCOMPARE(containsPressSpy.size(), 3);
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(200,200));
QCOMPARE(mouseArea->hovered(), hoverEnabled);
- QCOMPARE(mouseArea->pressed(), false);
+ QCOMPARE(mouseArea->isPressed(), false);
QCOMPARE(mouseArea->containsPress(), false);
- QCOMPARE(containsPressSpy.count(), 4);
+ QCOMPARE(containsPressSpy.size(), 4);
}
void tst_QQuickMouseArea::ignoreBySource()
@@ -2087,7 +2298,7 @@ void tst_QQuickMouseArea::notPressedAfterStolenGrab() // QTBUG-55325
[&]() { qCDebug(lcTests) << "stealing grab now"; window.contentItem()->grabMouse(); });
QTest::mouseClick(&window, Qt::LeftButton);
- QVERIFY(!ma->pressed());
+ QVERIFY(!ma->isPressed());
}
void tst_QQuickMouseArea::pressAndHold_data()
@@ -2161,35 +2372,35 @@ void tst_QQuickMouseArea::pressOneAndTapAnother()
// press them both
if (pressMouseFirst) {
QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, lower);
- QTRY_COMPARE(bottomMA->pressed(), true);
+ QTRY_COMPARE(bottomMA->isPressed(), true);
QTest::touchEvent(&window, device).press(0, lower, &window);
QQuickTouchUtils::flush(&window);
- QTRY_COMPARE(bottomMA->pressed(), true);
+ QTRY_COMPARE(bottomMA->isPressed(), true);
} else {
QTest::touchEvent(&window, device).press(0, lower, &window);
QQuickTouchUtils::flush(&window);
- QTRY_COMPARE(bottomMA->pressed(), true);
+ QTRY_COMPARE(bottomMA->isPressed(), true);
QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, lower);
- QTRY_COMPARE(bottomMA->pressed(), true);
+ QTRY_COMPARE(bottomMA->isPressed(), true);
}
// release them both and make sure neither one gets stuck
if (releaseMouseFirst) {
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, lower);
- QTRY_COMPARE(bottomMA->pressed(), false);
+ QTRY_COMPARE(bottomMA->isPressed(), false);
QTest::touchEvent(&window, device).release(0, upper, &window);
QQuickTouchUtils::flush(&window);
- QTRY_COMPARE(topMA->pressed(), false);
+ QTRY_COMPARE(topMA->isPressed(), false);
} else {
QTest::touchEvent(&window, device).release(0, upper, &window);
QQuickTouchUtils::flush(&window);
- QTRY_COMPARE(topMA->pressed(), false);
+ QTRY_COMPARE(topMA->isPressed(), false);
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, lower);
- QTRY_COMPARE(bottomMA->pressed(), false);
+ QTRY_COMPARE(bottomMA->isPressed(), false);
}
}
@@ -2255,7 +2466,7 @@ void tst_QQuickMouseArea::settingHiddenInPressUngrabs()
// The click hides the cat area
QTRY_VERIFY(!catArea->isVisible());
// The cat area is not stuck in pressed state.
- QVERIFY(!catArea->pressed());
+ QVERIFY(!catArea->isPressed());
QQuickMouseArea *mouseArea = window->findChild<QQuickMouseArea*>("mouse");
QVERIFY(mouseArea != nullptr);
@@ -2266,7 +2477,7 @@ void tst_QQuickMouseArea::settingHiddenInPressUngrabs()
// The click disables the mouse area
QTRY_VERIFY(!mouseArea->isEnabled());
// The mouse area is not stuck in pressed state.
- QVERIFY(!mouseArea->pressed());
+ QVERIFY(!mouseArea->isPressed());
}
void tst_QQuickMouseArea::negativeZStackingOrder() // QTBUG-83114
@@ -2284,8 +2495,8 @@ void tst_QQuickMouseArea::negativeZStackingOrder() // QTBUG-83114
QSignalSpy clickSpyChild(childMouseArea, &QQuickMouseArea::clicked);
QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, QPoint(150, 100));
- QCOMPARE(clickSpyChild.count(), 1);
- QCOMPARE(clickSpyParent.count(), 0);
+ QCOMPARE(clickSpyChild.size(), 1);
+ QCOMPARE(clickSpyParent.size(), 0);
auto order = root->property("clicks").toList();
QVERIFY(order.at(0) == "childMouseArea");
@@ -2293,8 +2504,8 @@ void tst_QQuickMouseArea::negativeZStackingOrder() // QTBUG-83114
childMouseArea->parentItem()->setZ(-1);
root->setProperty("clicks", QVariantList());
QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, QPoint(150, 100));
- QCOMPARE(clickSpyChild.count(), 1);
- QCOMPARE(clickSpyParent.count(), 1);
+ QCOMPARE(clickSpyChild.size(), 1);
+ QCOMPARE(clickSpyParent.size(), 1);
order = root->property("clicks").toList();
QVERIFY(order.at(0) == "parentMouseArea");
}
@@ -2344,6 +2555,169 @@ void tst_QQuickMouseArea::containsMouseAndVisibility()
QVERIFY(!mouseArea->hovered());
}
+// QTBUG-109567
+void tst_QQuickMouseArea::containsMouseAndVisibilityMasked()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("containsMouseMasked.qml")));
+
+ QQuickMouseArea *mouseArea1 = window.rootObject()->findChild<QQuickMouseArea *>("mouseArea1");
+ QVERIFY(mouseArea1 != nullptr);
+ QVERIFY(mouseArea1->isVisible());
+
+ QQuickMouseArea *mouseArea2 = window.rootObject()->findChild<QQuickMouseArea *>("mouseArea2");
+ QVERIFY(mouseArea2 != nullptr);
+ QVERIFY(mouseArea2->isVisible());
+
+ QTest::mouseMove(&window, QPoint(window.width() / 2, window.height() / 2));
+
+ // Check that mouseArea" (i.e. the masking MouseArea) is the only hovered MouseArea.
+ QTRY_VERIFY(!mouseArea1->hovered());
+ QTRY_VERIFY(mouseArea2->hovered());
+
+ // Toggle the visibility of the masked MouseArea (mouseArea1).
+ mouseArea1->setVisible(false);
+ QVERIFY(!mouseArea1->isVisible());
+
+ mouseArea1->setVisible(true);
+ QVERIFY(mouseArea1->isVisible());
+
+ // Check that the masked MouseArea is not now hovered depite being under the mouse after
+ // changing the visibility to visible. mouseArea2 should be the only hovered MouseArea still.
+ QTRY_VERIFY(!mouseArea1->hovered());
+ QTRY_VERIFY(mouseArea2->hovered());
+
+ QTest::mouseMove(&window, QPoint(10, 10));
+
+ QTRY_VERIFY(mouseArea1->hovered());
+ QTRY_VERIFY(!mouseArea2->hovered());
+
+ // Toggle the visibility of the masked MouseArea (mouseArea1).
+ mouseArea1->setVisible(false);
+ QVERIFY(!mouseArea1->isVisible());
+
+ mouseArea1->setVisible(true);
+ QVERIFY(mouseArea1->isVisible());
+
+ QTRY_VERIFY(mouseArea1->hovered());
+ QTRY_VERIFY(!mouseArea2->hovered());
+}
+
+// QTBUG-110594
+void tst_QQuickMouseArea::containsMouseAndHoverDisabled()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("containsMouseAndHoverDisabled.qml")));
+
+ QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>("mouseArea");
+ QVERIFY(mouseArea != nullptr);
+ QVERIFY(!mouseArea->hoverEnabled());
+
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 100));
+ QTRY_VERIFY(!mouseArea->hovered());
+}
+
+// QTBUG-35995 and QTBUG-102158
+void tst_QQuickMouseArea::doubleClickToHide()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("doubleClickToHide.qml")));
+
+ QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>();
+ QVERIFY(mouseArea);
+
+ QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, {10, 10});
+
+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 1);
+ QCOMPARE(window.rootObject()->property("doubleClicked").toInt(), 1);
+ QCOMPARE(mouseArea->isVisible(), false);
+ QCOMPARE(mouseArea->isPressed(), false);
+ QCOMPARE(mouseArea->pressedButtons(), Qt::NoButton);
+
+ mouseArea->setVisible(true);
+
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, {10, 10});
+ QCOMPARE(window.rootObject()->property("clicked").toInt(), 2);
+}
+
+void tst_QQuickMouseArea::releaseFirstTouchAfterSecond() // QTBUG-103766
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("simple.qml")));
+ QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>();
+ QVERIFY(mouseArea);
+ QSignalSpy pressSpy(mouseArea, SIGNAL(pressed(QQuickMouseEvent*)));
+ QSignalSpy releaseSpy(mouseArea, &QQuickMouseArea::released);
+
+ QTest::touchEvent(&window, device).press(0, {20, 20});
+ QTRY_COMPARE(pressSpy.size(), 1);
+ QTest::touchEvent(&window, device).stationary(0).press(1, {100, 20});
+ QCOMPARE(pressSpy.size(), 1); // touchpoint 0 is the touchmouse, touchpoint 1 is ignored
+ QTest::touchEvent(&window, device).stationary(0).release(1, {100, 20});
+ QCOMPARE(releaseSpy.size(), 0); // touchpoint 0 is the touchmouse, and remains pressed
+ QTest::touchEvent(&window, device).release(0, {20, 20});
+ QTRY_COMPARE(releaseSpy.size(), 1);
+}
+
+#if QT_CONFIG(tabletevent)
+void tst_QQuickMouseArea::tabletStylusTap()
+{
+ QVERIFY(qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)); // MouseArea depends on it
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("simple.qml")));
+ QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>();
+ QVERIFY(mouseArea);
+ QSignalSpy pressSpy(mouseArea, SIGNAL(pressed(QQuickMouseEvent*)));
+ QSignalSpy releaseSpy(mouseArea, &QQuickMouseArea::released);
+ QSignalSpy clickSpy(mouseArea, &QQuickMouseArea::clicked);
+ const qint64 stylusId = 1234567890;
+
+ const QPoint point(100,100);
+ QWindowSystemInterface::handleTabletEvent(&window, point, window.mapToGlobal(point),
+ int(QInputDevice::DeviceType::Stylus), int(QPointingDevice::PointerType::Pen),
+ Qt::LeftButton, 0.5, 0, 0, 0, 0, 0, stylusId, Qt::NoModifier);
+ if (QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse)
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, point); // simulate what the platform does
+ QTRY_COMPARE(pressSpy.size(), 1);
+ QWindowSystemInterface::handleTabletEvent(&window, point, window.mapToGlobal(point),
+ int(QInputDevice::DeviceType::Stylus), int(QPointingDevice::PointerType::Pen),
+ Qt::NoButton, 0.5, 0, 0, 0, 0, 0, stylusId, Qt::NoModifier);
+ if (QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse)
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, point);
+ QTRY_COMPARE(releaseSpy.size(), 1);
+ QCOMPARE(clickSpy.size(), 1);
+ QCOMPARE(pressSpy.size(), 1);
+}
+#endif
+
+void tst_QQuickMouseArea::syntheticRightClick()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("simple.qml")));
+ QQuickMouseArea *mouseArea = window.rootObject()->findChild<QQuickMouseArea *>();
+ QVERIFY(mouseArea);
+ mouseArea->setAcceptedButtons(Qt::RightButton);
+
+ QSignalSpy clickSpy(mouseArea, &QQuickMouseArea::clicked);
+ const QPointF p(20, 20);
+ quint64 timestamp = 10;
+
+ // The right-click is probably synthesized from a touch long-press IRL, but it doesn't matter for the DA's logic.
+ // We could set QT_QUICK_ALLOW_SYNTHETIC_RIGHT_CLICK=0 to opt out, but otherwise it's allowed.
+ QMouseEvent press(QEvent::MouseButtonPress, p, mouseArea->mapToScene(p), mouseArea->mapToGlobal(p),
+ Qt::RightButton, Qt::RightButton, Qt::NoModifier, Qt::MouseEventSynthesizedBySystem);
+ press.setTimestamp(timestamp++);
+ QGuiApplication::sendEvent(&window, &press);
+ QCOMPARE(mouseArea->pressedButtons(), Qt::RightButton);
+
+ QMouseEvent release(QEvent::MouseButtonRelease, p, mouseArea->mapToScene(p), mouseArea->mapToGlobal(p),
+ Qt::RightButton, Qt::RightButton, Qt::NoModifier, Qt::MouseEventSynthesizedBySystem);
+ release.setTimestamp(timestamp);
+ QGuiApplication::sendEvent(&window, &release);
+ QCOMPARE(mouseArea->pressedButtons(), Qt::NoButton);
+ QCOMPARE(clickSpy.size(), 1);
+}
+
QTEST_MAIN(tst_QQuickMouseArea)
#include "tst_qquickmousearea.moc"
diff --git a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
index abe504d20c..c79f4b6a29 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
+++ b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST
@@ -1,4 +1,10 @@
[nonOverlapping]
ubuntu-20.04
+ubuntu-22.04
[nested]
ubuntu-20.04
+ubuntu-22.04
+
+# QTBUG-118065
+[mouseGestureStarted]
+opensuse-leap
diff --git a/tests/auto/quick/qquickmultipointtoucharea/CMakeLists.txt b/tests/auto/quick/qquickmultipointtoucharea/CMakeLists.txt
index 1902b3fefa..277df556cc 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/CMakeLists.txt
+++ b/tests/auto/quick/qquickmultipointtoucharea/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickmultipointtoucharea.pro.
#####################################################################
## tst_qquickmultipointtoucharea Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickmultipointtoucharea LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickmultipointtoucharea
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickmultipointtoucharea.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,10 +37,10 @@ qt_internal_add_test(tst_qquickmultipointtoucharea
qt_internal_extend_target(tst_qquickmultipointtoucharea CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickmultipointtoucharea CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/cancel.qml b/tests/auto/quick/qquickmultipointtoucharea/data/cancel.qml
index e108003bca..493257ac7e 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/data/cancel.qml
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/cancel.qml
@@ -30,12 +30,12 @@ MultiPointTouchArea {
property int touchCount: 0
property bool touchUpdatedHandled: false
- onPressed: { touchPointPressCount = touchPoints.length }
- onUpdated: { touchPointUpdateCount = touchPoints.length }
- onReleased: { touchPointReleaseCount = touchPoints.length }
- onCanceled: { touchPointCancelCount = touchPoints.length }
- onTouchUpdated: {
- touchCount = touchPoints.length
+ onPressed: (points) => { touchPointPressCount = points.length }
+ onUpdated: (points) => { touchPointUpdateCount = points.length }
+ onReleased: (points) => { touchPointReleaseCount = v.length }
+ onCanceled: (points) => { touchPointCancelCount = points.length }
+ onTouchUpdated: (points) => {
+ touchCount = points.length
touchUpdatedHandled = true
}
}
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/inFlickable.qml b/tests/auto/quick/qquickmultipointtoucharea/data/inFlickable.qml
index 32733613b3..e03ad43816 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/data/inFlickable.qml
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/inFlickable.qml
@@ -32,7 +32,7 @@ Rectangle {
anchors.fill: parent
minimumTouchPoints: 2
maximumTouchPoints: 2
- onGestureStarted: {
+ onGestureStarted: (gesture) => {
if ((Math.abs(point2.x - point2.startX) > gesture.dragThreshold/2) &&
(Math.abs(point1.x - point1.startX) > gesture.dragThreshold/2)) {
gesture.grab()
@@ -43,8 +43,8 @@ Rectangle {
TouchPoint { id: point2; objectName: "point2" }
]
- onCanceled: root.cancelCount = touchPoints.length
- onTouchUpdated: root.touchCount = touchPoints.length
+ onCanceled: (touchPoints) => root.cancelCount = touchPoints.length
+ onTouchUpdated: (touchPoints) => root.touchCount = touchPoints.length
Text {
text: "â‘ "
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/mouse.qml b/tests/auto/quick/qquickmultipointtoucharea/data/mouse.qml
index b0410dac4a..6b9dd5b7c7 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/data/mouse.qml
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/mouse.qml
@@ -17,10 +17,10 @@ MultiPointTouchArea {
TouchPoint { objectName: "point2" }
]
- onPressed: { touchCount = touchPoints.length }
- onTouchUpdated: { touchCount = touchPoints.length }
- onCanceled: { cancelCount = touchPoints.length }
- onGestureStarted: {
+ onPressed: (points) => { touchCount = points.length }
+ onTouchUpdated: (points) => { touchCount = points.length }
+ onCanceled: (points) => { cancelCount = points.length }
+ onGestureStarted: (gesture) => {
gestureStartedX = gesture.touchPoints[0].startX
gestureStartedY = gesture.touchPoints[0].startY
if (grabGesture)
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/nested.qml b/tests/auto/quick/qquickmultipointtoucharea/data/nested.qml
index 8ab10a6926..dca1ffa07b 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/data/nested.qml
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/nested.qml
@@ -66,7 +66,7 @@ MultiPointTouchArea {
anchors.fill: parent
minimumTouchPoints: 3
maximumTouchPoints: 3
- onGestureStarted: if (grabInnerArea) gesture.grab()
+ onGestureStarted: (gesture) => { if (grabInnerArea) gesture.grab() }
touchPoints: [
TouchPoint { id: point21; objectName: "point21" },
TouchPoint { id: point22; objectName: "point22" },
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/nestedMouseArea.qml b/tests/auto/quick/qquickmultipointtoucharea/data/nestedMouseArea.qml
new file mode 100644
index 0000000000..7ca3f187d6
--- /dev/null
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/nestedMouseArea.qml
@@ -0,0 +1,26 @@
+import QtQuick 2.12
+
+Item {
+ id: root
+ width: 300; height: 300
+ property point mptaPoint
+ property point maPoint
+ MultiPointTouchArea {
+ anchors.fill : parent
+ onPressed: function(touchPoints) {
+ root.mptaPoint = Qt.point(touchPoints[0].x, touchPoints[0].y)
+ }
+ MouseArea {
+ id: ma
+ width: 100; height: 100
+ anchors.centerIn: parent
+ onPressed: function(mouse) {
+ root.maPoint = Qt.point(mouse.x, mouse.y)
+ }
+ }
+ Rectangle {
+ anchors.fill: ma
+ border.color: "grey"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml b/tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml
new file mode 100644
index 0000000000..0e51804b30
--- /dev/null
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/nestedPinchArea.qml
@@ -0,0 +1,44 @@
+import QtQuick 2.15
+
+MultiPointTouchArea {
+ width: 240
+ height: 320
+ mouseEnabled: true
+ property int pressedCount: 0
+ property int updatedCount: 0
+ property int releasedCount: 0
+
+ onPressed: (points) => { pressedCount = points.length }
+ onUpdated: (points) => { updatedCount = points.length }
+ onReleased: (points) => { releasedCount = points.length }
+
+ touchPoints: [
+ TouchPoint {
+ id: point1
+ objectName: "point1"
+ },
+ TouchPoint {
+ id: point2
+ objectName: "point2"
+ }
+ ]
+
+ PinchArea {
+ anchors.fill: parent
+ }
+
+ Rectangle {
+ width: 30; height: 30
+ color: "green"
+ x: point1.x
+ y: point1.y
+ }
+
+ Rectangle {
+ id: rectangle
+ width: 30; height: 30
+ color: "yellow"
+ x: point2.x
+ y: point2.y
+ }
+}
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/nestedTouchPosCheck.qml b/tests/auto/quick/qquickmultipointtoucharea/data/nestedTouchPosCheck.qml
new file mode 100644
index 0000000000..700f06a3ac
--- /dev/null
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/nestedTouchPosCheck.qml
@@ -0,0 +1,52 @@
+import QtQuick
+import QtTest
+
+Item {
+ width: 300; height: 200
+ id: topLevelItem
+ MultiPointTouchArea {
+ objectName: "topMPTA"
+ anchors.fill: parent
+ Column {
+ width: parent.width
+ height: parent.height
+
+ Rectangle {
+ width: parent.width
+ height: 100
+ color: "green"
+ }
+ Rectangle {
+ id: rect
+ width: parent.width
+ height: 600
+ color: "red"
+
+ MultiPointTouchArea {
+
+ property var xPressed: 0
+ property var yPressed: 0
+ property var xReleased: 0
+ property var yReleased: 0
+
+ objectName: "bottomMPTA"
+ anchors.fill: parent
+ onPressed: (touchPoints) => {
+ for (let tp in touchPoints) {
+ let touch = touchPoints[tp]
+ xPressed = touch.x
+ yPressed = touch.y
+ }
+ }
+ onReleased: (touchPoints) => {
+ for (let tp in touchPoints) {
+ let touch = touchPoints[tp]
+ xReleased = touch.x
+ yReleased = touch.y
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml b/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml
index 027f90c7f4..4130bc8dde 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/nonOverlapping.qml
@@ -9,7 +9,7 @@ Rectangle {
height: 160
minimumTouchPoints: 2
maximumTouchPoints: 2
- onGestureStarted: gesture.grab()
+ onGestureStarted: (gesture) => gesture.grab()
touchPoints: [
TouchPoint { id: point11; objectName: "point11" },
TouchPoint { id: point12; objectName: "point12" }
@@ -34,7 +34,7 @@ Rectangle {
y: 160
minimumTouchPoints: 3
maximumTouchPoints: 3
- onGestureStarted: gesture.grab()
+ onGestureStarted: (gesture) => gesture.grab()
touchPoints: [
TouchPoint { id: point21; objectName: "point21" },
TouchPoint { id: point22; objectName: "point22" },
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/signalTest.qml b/tests/auto/quick/qquickmultipointtoucharea/data/signalTest.qml
index 54b160c182..9ba3029193 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/data/signalTest.qml
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/signalTest.qml
@@ -20,11 +20,17 @@ MultiPointTouchArea {
maximumTouchPoints: 5
- onPressed: { touchPointPressCount = touchPoints.length }
- onUpdated: { touchPointUpdateCount = touchPoints.length }
+ // recommended syntax for a signal handler
+ onPressed: (points) => { touchPointPressCount = points.length }
+
+ // one with "touchPoints" being the signal argument rather than the property
+ onUpdated: (touchPoints) => { touchPointUpdateCount = touchPoints.length }
+
+ // one without the formal parameter, to test that it still works (with a warning)
onReleased: { touchPointReleaseCount = touchPoints.length }
- onTouchUpdated: {
- touchCount = touchPoints.length
+
+ onTouchUpdated: (points) => {
+ touchCount = points.length
touchUpdatedHandled = true
}
}
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/touchOverMouseArea.qml b/tests/auto/quick/qquickmultipointtoucharea/data/touchOverMouseArea.qml
new file mode 100644
index 0000000000..ffe3751ec3
--- /dev/null
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/touchOverMouseArea.qml
@@ -0,0 +1,21 @@
+
+import QtQuick
+
+Rectangle {
+ x: 20
+ y: 20
+ width: 300
+ height: 200
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ }
+
+ MultiPointTouchArea {
+ id: touchArea
+ anchors.fill: parent
+ enabled: false
+ }
+}
diff --git a/tests/auto/quick/qquickmultipointtoucharea/data/transformedMultiPointTouchArea.qml b/tests/auto/quick/qquickmultipointtoucharea/data/transformedMultiPointTouchArea.qml
index 296bf7996f..02985581e0 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/data/transformedMultiPointTouchArea.qml
+++ b/tests/auto/quick/qquickmultipointtoucharea/data/transformedMultiPointTouchArea.qml
@@ -19,8 +19,8 @@ Rectangle {
property int pointCount: 0
- onPressed: pointCount = touchPoints.length;
- onTouchUpdated: pointCount = touchPoints.length;
+ onPressed: (points) => pointCount = points.length;
+ onTouchUpdated: (points) => pointCount = points.length;
}
}
}
diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
index b5ab520055..b233ed0232 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
+++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
@@ -1,33 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtTest/QSignalSpy>
+#include <private/qquickitem_p.h>
#include <private/qquickmultipointtoucharea_p.h>
#include <private/qquickflickable_p.h>
#include <private/qquickmousearea_p.h>
@@ -36,17 +12,20 @@
#include <QtQuick/qquickview.h>
#include <QtGui/QScreen>
#include <QtGui/private/qevent_p.h>
+#include <QtGui/private/qeventpoint_p.h>
#include <QtGui/private/qpointingdevice_p.h>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+using namespace Qt::StringLiterals;
+
class tst_QQuickMultiPointTouchArea : public QQmlDataTest
{
Q_OBJECT
public:
- tst_QQuickMultiPointTouchArea() { }
+ tst_QQuickMultiPointTouchArea() : QQmlDataTest(QT_QMLTEST_DATADIR) { }
private slots:
void cleanupTestCase() {}
@@ -57,6 +36,7 @@ private slots:
void reuse();
void nonOverlapping();
void nested();
+ void nestedTouchPosCheck();
void inFlickable();
void inFlickable2();
void inFlickableWithPressDelay();
@@ -71,6 +51,9 @@ private slots:
void mouseGestureStarted();
void cancel();
void stationaryTouchWithChangingPressure();
+ void touchFiltering();
+ void nestedPinchAreaMouse();
+ void disabledIgnoresHover();
private:
QQuickView *createAndShowView(const QString &file);
@@ -94,6 +77,12 @@ void tst_QQuickMultiPointTouchArea::properties()
void tst_QQuickMultiPointTouchArea::signalTest()
{
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ QTest::ignoreMessage(QtWarningMsg, QString(testFileUrl("signalTest.qml").toString() +
+ u":30:5 Parameter \"touchPoints\" is not declared. Injection of parameters into signal handlers "
+ "is deprecated. Use JavaScript functions with formal parameters instead."_s).toLatin1().constData());
+#endif
+
QScopedPointer<QQuickView> window(createAndShowView("signalTest.qml"));
QVERIFY(window->rootObject() != nullptr);
@@ -572,6 +561,30 @@ void tst_QQuickMultiPointTouchArea::nested()
QQuickTouchUtils::flush(window.data());
}
+
+void tst_QQuickMultiPointTouchArea::nestedTouchPosCheck()
+{
+ QScopedPointer<QQuickView> window(createAndShowView("nestedTouchPosCheck.qml"));
+ QVERIFY(window->rootObject() != nullptr);
+
+ auto *bottomMPTA = window->rootObject()->findChild<QQuickMultiPointTouchArea *>("bottomMPTA");
+ QVERIFY(bottomMPTA != nullptr);
+
+ QTest::QTouchEventSequence sequence = QTest::touchEvent(window.data(), device);
+
+ sequence.press(0, QPoint(10, 110)).commit();
+ QQuickTouchUtils::flush(window.data());
+
+ sequence.release(0, QPoint(10, 110)).commit();
+ QQuickTouchUtils::flush(window.data());
+
+ QCOMPARE(bottomMPTA->property("xPressed").toInt(), 10);
+ QCOMPARE(bottomMPTA->property("yPressed").toInt(), 10);
+ QCOMPARE(bottomMPTA->property("xReleased").toInt(), 10);
+ QCOMPARE(bottomMPTA->property("yReleased").toInt(), 10);
+
+}
+
void tst_QQuickMultiPointTouchArea::inFlickable()
{
QScopedPointer<QQuickView> window(createAndShowView("inFlickable.qml"));
@@ -592,7 +605,7 @@ void tst_QQuickMultiPointTouchArea::inFlickable()
QPoint p1(20,100);
QPoint p2(40,100);
- // moving one point vertically
+ // moving one point vertically: flickable gets the grab
QTest::touchEvent(window.data(), device).press(0, p1);
QQuickTouchUtils::flush(window.data());
@@ -616,10 +629,14 @@ void tst_QQuickMultiPointTouchArea::inFlickable()
QTRY_VERIFY(!flickable->isMoving());
- // moving two points vertically
+ // moving two points vertically: MPTAs handle them, Flickable ignores multi-touch.
+ // The stray mouse events simulate OS-level synth-from-touch, and should not interfere.
p1 = QPoint(20,100);
QTest::touchEvent(window.data(), device).press(0, p1).press(1, p2);
- QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, p1);
+ QWindowSystemInterface::handleMouseEvent(window.data(), device, p1, window->mapToGlobal(p1),
+ Qt::LeftButton, Qt::LeftButton, QEvent::MouseButtonPress,
+ Qt::NoModifier, Qt::MouseEventSynthesizedBySystem);
+ qApp->processEvents();
QQuickTouchUtils::flush(window.data());
QCOMPARE(point11->pressed(), true);
@@ -632,20 +649,26 @@ void tst_QQuickMultiPointTouchArea::inFlickable()
QTest::qWait(250);
p1 += delta; p2 += delta;
QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2);
- QTest::mouseMove(window.data(), p1);
+ QWindowSystemInterface::handleMouseEvent(window.data(), device, p1, window->mapToGlobal(p1),
+ Qt::LeftButton, Qt::NoButton, QEvent::MouseMove,
+ Qt::NoModifier, Qt::MouseEventSynthesizedBySystem);
+ qApp->processEvents();
QQuickTouchUtils::flush(window.data());
qCDebug(lcTests, "after drags %d to %d,%d and %d,%d contentY is %lf",
i, p1.x(), p1.y(), p2.x(), p2.y(), flickable->contentY());
}
- QVERIFY(flickable->contentY() < 0);
- QCOMPARE(point11->pressed(), false);
- QCOMPARE(point12->pressed(), false);
- QCOMPARE(window->rootObject()->property("cancelCount").toInt(), 2);
- QCOMPARE(window->rootObject()->property("touchCount").toInt(), 0);
+ QCOMPARE(flickable->contentY(), 0);
+ QCOMPARE(point11->pressed(), true);
+ QCOMPARE(point12->pressed(), true);
+ QCOMPARE(window->rootObject()->property("cancelCount").toInt(), 0);
+ QCOMPARE(window->rootObject()->property("touchCount").toInt(), 2);
QTest::touchEvent(window.data(), device).release(0, p1).release(1, p2);
- QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, p1);
+ QWindowSystemInterface::handleMouseEvent(window.data(), device, p1, window->mapToGlobal(p1),
+ Qt::NoButton, Qt::LeftButton, QEvent::MouseButtonRelease,
+ Qt::NoModifier, Qt::MouseEventSynthesizedBySystem);
+ qApp->processEvents();
QQuickTouchUtils::flush(window.data());
QTRY_VERIFY(!flickable->isMoving());
@@ -655,10 +678,15 @@ void tst_QQuickMultiPointTouchArea::inFlickable()
p2 = QPoint(40,100);
QTest::touchEvent(window.data(), device).press(0, p1).press(1, p2);
QQuickTouchUtils::flush(window.data());
+ QCOMPARE(point11->pressed(), true);
+ QCOMPARE(point12->pressed(), true);
// ensure that mouse events do not fall through to the Flickable
mpta->setMaximumTouchPoints(3);
mpta->setAcceptedMouseButtons(Qt::LeftButton);
- QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, p1);
+ QWindowSystemInterface::handleMouseEvent(window.data(), device, p1, window->mapToGlobal(p1),
+ Qt::LeftButton, Qt::LeftButton, QEvent::MouseButtonPress,
+ Qt::NoModifier, Qt::MouseEventSynthesizedBySystem);
+ qApp->processEvents();
QCOMPARE(point11->pressed(), true);
QCOMPARE(point12->pressed(), true);
@@ -671,32 +699,40 @@ void tst_QQuickMultiPointTouchArea::inFlickable()
delta = QPoint(0, 15);
p1 += delta; p2 += delta;
QTest::touchEvent(window.data(), device).move(0, p1).move(1, p2);
- QTest::mouseMove(window.data(), p1);
+ QWindowSystemInterface::handleMouseEvent(window.data(), device, p1, window->mapToGlobal(p1),
+ Qt::LeftButton, Qt::NoButton, QEvent::MouseMove,
+ Qt::NoModifier, Qt::MouseEventSynthesizedBySystem);
+ qApp->processEvents();
QQuickTouchUtils::flush(window.data());
qCDebug(lcTests, "after drags %d to %d,%d and %d,%d contentY is %lf",
i, p1.x(), p1.y(), p2.x(), p2.y(), flickable->contentY());
}
- QEXPECT_FAIL("", "currently flickable does grab the actual mouse", Continue);
QCOMPARE(flickable->contentY(), qreal(0));
QCOMPARE(point11->pressed(), true);
- QEXPECT_FAIL("", "currently flickable does grab the actual mouse", Continue);
QCOMPARE(point12->pressed(), true);
QTest::touchEvent(window.data(), device).release(0, p1).release(1, p2);
- QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, p1);
+ QWindowSystemInterface::handleMouseEvent(window.data(), device, p1, window->mapToGlobal(p1),
+ Qt::NoButton, Qt::LeftButton, QEvent::MouseButtonRelease,
+ Qt::NoModifier, Qt::MouseEventSynthesizedBySystem);
+ qApp->processEvents();
QQuickTouchUtils::flush(window.data());
}
// test that dragging out of a Flickable containing a MPTA doesn't harm Flickable's state.
void tst_QQuickMultiPointTouchArea::inFlickable2()
{
+ const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
QScopedPointer<QQuickView> window(createAndShowView("inFlickable2.qml"));
QVERIFY(window->rootObject() != nullptr);
QQuickFlickable *flickable = window->rootObject()->findChild<QQuickFlickable*>("flickable");
QVERIFY(flickable != nullptr);
+ QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild<QQuickMultiPointTouchArea*>();
+ QVERIFY(mpta);
+
QQuickTouchPoint *point11 = window->rootObject()->findChild<QQuickTouchPoint*>("point1");
QVERIFY(point11);
@@ -709,25 +745,12 @@ void tst_QQuickMultiPointTouchArea::inFlickable2()
QQuickTouchUtils::flush(window.data());
QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, p1);
- p1 += QPoint(15,0);
- QTest::touchEvent(window.data(), device).move(0, p1);
- QQuickTouchUtils::flush(window.data());
- QTest::mouseMove(window.data(), p1);
-
- p1 += QPoint(15,0);
- QTest::touchEvent(window.data(), device).move(0, p1);
- QQuickTouchUtils::flush(window.data());
- QTest::mouseMove(window.data(), p1);
-
- p1 += QPoint(15,0);
- QTest::touchEvent(window.data(), device).move(0, p1);
- QQuickTouchUtils::flush(window.data());
- QTest::mouseMove(window.data(), p1);
-
- p1 += QPoint(15,0);
- QTest::touchEvent(window.data(), device).move(0, p1);
- QQuickTouchUtils::flush(window.data());
- QTest::mouseMove(window.data(), p1);
+ for (int i = 0; i < 4; ++i) {
+ p1 += QPoint(dragThreshold, 0);
+ QTest::touchEvent(window.data(), device).move(0, p1);
+ QQuickTouchUtils::flush(window.data());
+ QTest::mouseMove(window.data(), p1);
+ }
QVERIFY(!flickable->isMoving());
QVERIFY(point11->pressed());
@@ -740,27 +763,21 @@ void tst_QQuickMultiPointTouchArea::inFlickable2()
QTRY_VERIFY(!flickable->isMoving());
// Check that we can still move the Flickable
+ QSignalSpy gestureStartedSpy(mpta, &QQuickMultiPointTouchArea::gestureStarted);
p1 = QPoint(50,100);
QTest::touchEvent(window.data(), device).press(0, p1);
QQuickTouchUtils::flush(window.data());
QCOMPARE(point11->pressed(), true);
- p1 += QPoint(0,15);
- QTest::touchEvent(window.data(), device).move(0, p1);
- QQuickTouchUtils::flush(window.data());
-
- p1 += QPoint(0,15);
- QTest::touchEvent(window.data(), device).move(0, p1);
- QQuickTouchUtils::flush(window.data());
-
- p1 += QPoint(0,15);
- QTest::touchEvent(window.data(), device).move(0, p1);
- QQuickTouchUtils::flush(window.data());
-
- p1 += QPoint(0,15);
- QTest::touchEvent(window.data(), device).move(0, p1);
- QQuickTouchUtils::flush(window.data());
+ for (int i = 0; i < 4; ++i) {
+ p1 += QPoint(0, dragThreshold);
+ QTest::touchEvent(window.data(), device).move(0, p1);
+ QQuickTouchUtils::flush(window.data());
+ // QTBUG-113653: gestureStarted is emitted when touch delta exceeds drag threshold,
+ // regardless of the filtering Flickable parent
+ QCOMPARE(gestureStartedSpy.size(), i > 0 ? 1 : 0);
+ }
QVERIFY(flickable->contentY() < 0);
QVERIFY(flickable->isMoving());
@@ -1051,10 +1068,13 @@ void tst_QQuickMultiPointTouchArea::mouseAsTouchpoint()
QPoint touch1(10,10);
QPoint touch2(100,10);
- touch1rect->setX(10);
- touch1rect->setY(10);
- touch2rect->setX(20);
- touch2rect->setY(10);
+ // do not break the QML bindings
+ auto t1priv = QQuickItemPrivate::get(touch1rect);
+ auto t2priv = QQuickItemPrivate::get(touch2rect);
+ t1priv->x.setValueBypassingBindings(10);
+ t1priv->y.setValueBypassingBindings(10);
+ t2priv->x.setValueBypassingBindings(20);
+ t2priv->y.setValueBypassingBindings(10);
// Start with mouse, move it, touch a point, move it, touch another.
// Mouse is ignored, both touch points are heeded.
@@ -1257,26 +1277,26 @@ void tst_QQuickMultiPointTouchArea::mouseGestureStarted() // QTBUG-70258
area->setProperty("grabGesture", grabGesture);
QQuickTouchPoint *point1 = view->rootObject()->findChild<QQuickTouchPoint*>("point1");
QCOMPARE(point1->pressed(), false);
- QSignalSpy gestureStartedSpy(area, SIGNAL(gestureStarted(QQuickGrabGestureEvent *)));
+ QSignalSpy gestureStartedSpy(area, SIGNAL(gestureStarted(QQuickGrabGestureEvent*)));
QPoint p1 = QPoint(distanceFromOrigin, distanceFromOrigin);
QTest::mousePress(view.data(), Qt::LeftButton, Qt::NoModifier, p1);
- QCOMPARE(gestureStartedSpy.count(), 0);
+ QCOMPARE(gestureStartedSpy.size(), 0);
p1 += QPoint(dragThreshold, dragThreshold);
QTest::mouseMove(view.data(), p1);
- QCOMPARE(gestureStartedSpy.count(), 0);
+ QCOMPARE(gestureStartedSpy.size(), 0);
p1 += QPoint(1, 1);
QTest::mouseMove(view.data(), p1);
- QTRY_COMPARE(gestureStartedSpy.count(), 1);
+ QTRY_COMPARE(gestureStartedSpy.size(), 1);
QTRY_COMPARE(area->property("gestureStartedX").toInt(), distanceFromOrigin);
QCOMPARE(area->property("gestureStartedY").toInt(), distanceFromOrigin);
p1 += QPoint(10, 10);
QTest::mouseMove(view.data(), p1);
// if nobody called gesteure->grab(), gestureStarted will keep happening
- QTRY_COMPARE(gestureStartedSpy.count(), grabGesture ? 1 : 2);
+ QTRY_COMPARE(gestureStartedSpy.size(), grabGesture ? 1 : 2);
QCOMPARE(area->property("gestureStartedX").toInt(), distanceFromOrigin);
QCOMPARE(area->property("gestureStartedY").toInt(), distanceFromOrigin);
@@ -1346,26 +1366,26 @@ void tst_QQuickMultiPointTouchArea::stationaryTouchWithChangingPressure() // QTB
QCOMPARE(point1->pressed(), false);
QPoint p1(20,100);
- QMutableEventPoint tp1(1);
+ QEventPoint tp1(1);
- tp1.setGlobalPosition(window->mapToGlobal(p1));
- tp1.setState(QEventPoint::State::Pressed);
- tp1.setPressure(0.5);
+ QMutableEventPoint::setGlobalPosition(tp1, window->mapToGlobal(p1));
+ QMutableEventPoint::setState(tp1, QEventPoint::State::Pressed);
+ QMutableEventPoint::setPressure(tp1, 0.5);
qt_handleTouchEvent(window.data(), device, {tp1});
QQuickTouchUtils::flush(window.data());
QCOMPARE(point1->pressed(), true);
QCOMPARE(point1->pressure(), 0.5);
- tp1.setState(QEventPoint::State::Stationary);
- tp1.setPressure(0.6);
+ QMutableEventPoint::setState(tp1, QEventPoint::State::Stationary);
+ QMutableEventPoint::setPressure(tp1, 0.6);
qt_handleTouchEvent(window.data(), device, {tp1});
QQuickTouchUtils::flush(window.data());
QCOMPARE(point1->pressure(), 0.6);
- tp1.setState(QEventPoint::State::Released);
- tp1.setPressure(0);
+ QMutableEventPoint::setState(tp1, QEventPoint::State::Released);
+ QMutableEventPoint::setPressure(tp1, 0);
qt_handleTouchEvent(window.data(), device, {tp1});
QQuickTouchUtils::flush(window.data());
@@ -1373,6 +1393,87 @@ void tst_QQuickMultiPointTouchArea::stationaryTouchWithChangingPressure() // QTB
QCOMPARE(point1->pressure(), 0);
}
+void tst_QQuickMultiPointTouchArea::touchFiltering() // QTBUG-74028
+{
+ QScopedPointer<QQuickView> window(createAndShowView("nestedMouseArea.qml"));
+ QVERIFY(window->rootObject() != nullptr);
+ QQuickMultiPointTouchArea *mpta = window->rootObject()->findChild<QQuickMultiPointTouchArea*>();
+ QVERIFY(mpta);
+ QQuickMouseArea *ma = window->rootObject()->findChild<QQuickMouseArea*>();
+ QVERIFY(ma);
+
+ QSignalSpy mptaSpy(mpta, &QQuickMultiPointTouchArea::pressed);
+ const QPoint pt = window->rootObject()->boundingRect().center().toPoint();
+ QTest::touchEvent(window.data(), device).press(1, pt);
+ QQuickTouchUtils::flush(window.data());
+ QTRY_COMPARE(mpta->parentItem()->property("mptaPoint").toPoint(), pt);
+ QCOMPARE(mpta->parentItem()->property("maPoint").toPoint(), ma->boundingRect().center().toPoint());
+ QCOMPARE(mptaSpy.size(), 1);
+}
+
+void tst_QQuickMultiPointTouchArea::nestedPinchAreaMouse() // QTBUG-83662
+{
+ QScopedPointer<QQuickView> window(createAndShowView("nestedPinchArea.qml"));
+ QQuickMultiPointTouchArea *mpta = qobject_cast<QQuickMultiPointTouchArea *>(window->rootObject());
+ QVERIFY(mpta);
+
+ QQuickTouchPoint *point1 = mpta->findChild<QQuickTouchPoint*>("point1");
+ QCOMPARE(point1->pressed(), false);
+ QQuickTouchPoint *point2 = mpta->findChild<QQuickTouchPoint*>("point2");
+ QCOMPARE(point2->pressed(), false);
+ QSignalSpy pressedSpy(mpta, &QQuickMultiPointTouchArea::pressed);
+ QSignalSpy updatedSpy(mpta, &QQuickMultiPointTouchArea::updated);
+ QSignalSpy releasedSpy(mpta, &QQuickMultiPointTouchArea::released);
+
+ QPoint p1(20, 20);
+ QTest::mousePress(window.data(), Qt::LeftButton, Qt::NoModifier, p1);
+ QCOMPARE(point1->pressed(), true);
+ QCOMPARE(point2->pressed(), false);
+ QCOMPARE(pressedSpy.size(), 1);
+ QCOMPARE(mpta->property("pressedCount").toInt(), 1);
+ QCOMPARE(updatedSpy.size(), 0);
+ QCOMPARE(mpta->property("updatedCount").toInt(), 0);
+ QCOMPARE(releasedSpy.size(), 0);
+ QCOMPARE(mpta->property("releasedCount").toInt(), 0);
+
+ p1 += QPoint(0, 15);
+ QTest::mouseMove(window.data(), p1);
+ QCOMPARE(point1->pressed(), true);
+ QCOMPARE(point2->pressed(), false);
+ QCOMPARE(pressedSpy.size(), 1);
+ QCOMPARE(mpta->property("pressedCount").toInt(), 1);
+ QCOMPARE(updatedSpy.size(), 1);
+ QCOMPARE(mpta->property("updatedCount").toInt(), 1);
+ QCOMPARE(releasedSpy.size(), 0);
+ QCOMPARE(mpta->property("releasedCount").toInt(), 0);
+
+ QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, p1);
+ QCOMPARE(point1->pressed(), false);
+ QCOMPARE(point2->pressed(), false);
+ QCOMPARE(pressedSpy.size(), 1);
+ QCOMPARE(mpta->property("pressedCount").toInt(), 1);
+ QCOMPARE(updatedSpy.size(), 1);
+ QCOMPARE(mpta->property("updatedCount").toInt(), 1);
+ QCOMPARE(releasedSpy.size(), 1);
+ QCOMPARE(mpta->property("releasedCount").toInt(), 1);
+}
+
+/*
+ A disabled MultiPointTouchArea should not interfere with hover event
+ propagation to siblings underneath.
+*/
+void tst_QQuickMultiPointTouchArea::disabledIgnoresHover()
+{
+ QScopedPointer<QQuickView> window(createAndShowView("touchOverMouseArea.qml"));
+ QQuickItem *root = qobject_cast<QQuickItem *>(window->rootObject());
+ QVERIFY(root);
+
+ QQuickMouseArea *mouseArea = root->findChild<QQuickMouseArea *>();
+
+ QTest::mouseMove(window.data(), QPoint(40, 40));
+ QTest::mouseMove(window.data(), QPoint(50, 50));
+ QVERIFY(mouseArea->hovered());
+}
QTEST_MAIN(tst_QQuickMultiPointTouchArea)
diff --git a/tests/auto/quick/qquickpainteditem/BLACKLIST b/tests/auto/quick/qquickpainteditem/BLACKLIST
index 9b58325f6c..6d8597b830 100644
--- a/tests/auto/quick/qquickpainteditem/BLACKLIST
+++ b/tests/auto/quick/qquickpainteditem/BLACKLIST
@@ -1,27 +1,34 @@
# QTBUG-63053
[opaquePainting]
b2qt
+qnx
# QTBUG-63053
[antialiasing]
b2qt
+qnx
# QTBUG-63053
[mipmap]
b2qt
+qnx
# QTBUG-63053
[performanceHints]
b2qt
+qnx
# QTBUG-63053
[contentScale]
b2qt
+qnx
# QTBUG-63053
[contentsBoundingRect]
b2qt
+qnx
# QTBUG-63053
[fillColor]
b2qt
+qnx
diff --git a/tests/auto/quick/qquickpainteditem/CMakeLists.txt b/tests/auto/quick/qquickpainteditem/CMakeLists.txt
index 9649ffc032..ef92df98e3 100644
--- a/tests/auto/quick/qquickpainteditem/CMakeLists.txt
+++ b/tests/auto/quick/qquickpainteditem/CMakeLists.txt
@@ -1,13 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickpainteditem.pro.
#####################################################################
## tst_qquickpainteditem Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickpainteditem LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qquickpainteditem
SOURCES
tst_qquickpainteditem.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp b/tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp
index 2661762669..eca935c258 100644
--- a/tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp
+++ b/tests/auto/quick/qquickpainteditem/tst_qquickpainteditem.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtTest/QSignalSpy>
@@ -65,16 +40,18 @@ public:
: QQuickPaintedItem(parent)
, paintNode(nullptr)
, paintRequests(0)
+ , painterHadAA(false)
{
}
- void paint(QPainter *painter)
+ void paint(QPainter *painter) override
{
++paintRequests;
+ painterHadAA = painter->testRenderHint(QPainter::Antialiasing);
clipRect = painter->clipBoundingRect();
}
#if QT_CONFIG(opengl)
- QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) override
{
paintNode = static_cast<QSGDefaultPainterNode *>(QQuickPaintedItem::updatePaintNode(oldNode, data));
return paintNode;
@@ -91,9 +68,12 @@ public:
QSGSoftwarePainterNode *paintNode;
#endif
int paintRequests;
+ bool painterHadAA;
QRectF clipRect;
};
+static bool hasDirtyAAFlag(QQuickItem *item) {
+ return QQuickItemPrivate::get(item)->dirtyAttributes & QQuickItemPrivate::Antialiasing; }
static bool hasDirtyContentFlag(QQuickItem *item) {
return QQuickItemPrivate::get(item)->dirtyAttributes & QQuickItemPrivate::Content; }
static void clearDirtyContentFlag(QQuickItem *item) {
@@ -192,32 +172,35 @@ void tst_QQuickPaintedItem::antialiasing()
item.setAntialiasing(false);
QCOMPARE(item.antialiasing(), false);
- QCOMPARE(hasDirtyContentFlag(&item), false);
+ QCOMPARE(hasDirtyAAFlag(&item), false);
item.update();
QTRY_COMPARE(hasDirtyContentFlag(&item), false);
QVERIFY(item.paintNode);
QCOMPARE(item.paintNode->smoothPainting(), false);
+ QCOMPARE(item.painterHadAA, false);
item.setAntialiasing(true);
QCOMPARE(item.antialiasing(), true);
- QCOMPARE(hasDirtyContentFlag(&item), true);
+ QCOMPARE(hasDirtyAAFlag(&item), true);
- QTRY_COMPARE(hasDirtyContentFlag(&item), false);
+ QTRY_COMPARE(hasDirtyAAFlag(&item), false);
QVERIFY(item.paintNode);
QCOMPARE(item.paintNode->smoothPainting(), true);
+ QCOMPARE(item.painterHadAA, true);
item.setAntialiasing(true);
QCOMPARE(item.antialiasing(), true);
- QCOMPARE(hasDirtyContentFlag(&item), false);
+ QCOMPARE(hasDirtyAAFlag(&item), false);
item.setAntialiasing(false);
QCOMPARE(item.antialiasing(), false);
- QCOMPARE(hasDirtyContentFlag(&item), true);
+ QCOMPARE(hasDirtyAAFlag(&item), true);
- QTRY_COMPARE(hasDirtyContentFlag(&item), false);
+ QTRY_COMPARE(hasDirtyAAFlag(&item), false);
QVERIFY(item.paintNode);
QCOMPARE(item.paintNode->smoothPainting(), false);
+ QCOMPARE(item.painterHadAA, false);
}
void tst_QQuickPaintedItem::mipmap()
@@ -307,24 +290,24 @@ void tst_QQuickPaintedItem::contentsSize()
item.setContentsSize(QSize());
QCOMPARE(item.contentsSize(), QSize());
QCOMPARE(hasDirtyContentFlag(&item), false);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
item.setContentsSize(QSize(320, 240));
QCOMPARE(item.contentsSize(), QSize(320, 240));
QCOMPARE(hasDirtyContentFlag(&item), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
clearDirtyContentFlag(&item);
item.setContentsSize(QSize(320, 240));
QCOMPARE(item.contentsSize(), QSize(320, 240));
QCOMPARE(hasDirtyContentFlag(&item), false);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
item.resetContentsSize();
QCOMPARE(item.contentsSize(), QSize());
QCOMPARE(hasDirtyContentFlag(&item), true);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
void tst_QQuickPaintedItem::contentScale()
@@ -340,7 +323,7 @@ void tst_QQuickPaintedItem::contentScale()
item.setContentsScale(1.);
QCOMPARE(item.contentsScale(), 1.);
QCOMPARE(hasDirtyContentFlag(&item), false);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
item.update();
QTRY_COMPARE(hasDirtyContentFlag(&item), false);
@@ -350,7 +333,7 @@ void tst_QQuickPaintedItem::contentScale()
item.setContentsScale(0.4);
QCOMPARE(item.contentsScale(), 0.4);
QCOMPARE(hasDirtyContentFlag(&item), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QTRY_COMPARE(hasDirtyContentFlag(&item), false);
QVERIFY(item.paintNode);
@@ -359,12 +342,12 @@ void tst_QQuickPaintedItem::contentScale()
item.setContentsScale(0.4);
QCOMPARE(item.contentsScale(), 0.4);
QCOMPARE(hasDirtyContentFlag(&item), false);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
item.setContentsScale(2.5);
QCOMPARE(item.contentsScale(), 2.5);
QCOMPARE(hasDirtyContentFlag(&item), true);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
QTRY_COMPARE(hasDirtyContentFlag(&item), false);
QVERIFY(item.paintNode);
@@ -422,7 +405,7 @@ void tst_QQuickPaintedItem::fillColor()
item.setFillColor(QColor(Qt::transparent));
QCOMPARE(item.fillColor(), QColor(Qt::transparent));
QCOMPARE(hasDirtyContentFlag(&item), false);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
item.update();
QTRY_COMPARE(hasDirtyContentFlag(&item), false);
@@ -432,7 +415,7 @@ void tst_QQuickPaintedItem::fillColor()
item.setFillColor(QColor(Qt::green));
QCOMPARE(item.fillColor(), QColor(Qt::green));
QCOMPARE(hasDirtyContentFlag(&item), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QTRY_COMPARE(hasDirtyContentFlag(&item), false);
QVERIFY(item.paintNode);
@@ -441,12 +424,12 @@ void tst_QQuickPaintedItem::fillColor()
item.setFillColor(QColor(Qt::green));
QCOMPARE(item.fillColor(), QColor(Qt::green));
QCOMPARE(hasDirtyContentFlag(&item), false);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
item.setFillColor(QColor(Qt::blue));
QCOMPARE(item.fillColor(), QColor(Qt::blue));
QCOMPARE(hasDirtyContentFlag(&item), true);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
QTRY_COMPARE(hasDirtyContentFlag(&item), false);
QVERIFY(item.paintNode);
@@ -465,24 +448,24 @@ void tst_QQuickPaintedItem::renderTarget()
item.setRenderTarget(QQuickPaintedItem::Image);
QCOMPARE(item.renderTarget(), QQuickPaintedItem::Image);
QCOMPARE(hasDirtyContentFlag(&item), false);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
item.setRenderTarget(QQuickPaintedItem::FramebufferObject);
QCOMPARE(item.renderTarget(), QQuickPaintedItem::FramebufferObject);
QCOMPARE(hasDirtyContentFlag(&item), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
clearDirtyContentFlag(&item);
item.setRenderTarget(QQuickPaintedItem::FramebufferObject);
QCOMPARE(item.renderTarget(), QQuickPaintedItem::FramebufferObject);
QCOMPARE(hasDirtyContentFlag(&item), false);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
item.setRenderTarget(QQuickPaintedItem::InvertedYFramebufferObject);
QCOMPARE(item.renderTarget(), QQuickPaintedItem::InvertedYFramebufferObject);
QCOMPARE(hasDirtyContentFlag(&item), true);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
QTEST_MAIN(tst_QQuickPaintedItem)
diff --git a/tests/auto/quick/qquickpalette/CMakeLists.txt b/tests/auto/quick/qquickpalette/CMakeLists.txt
index a68873d5dc..c938212d28 100644
--- a/tests/auto/quick/qquickpalette/CMakeLists.txt
+++ b/tests/auto/quick/qquickpalette/CMakeLists.txt
@@ -1,18 +1,36 @@
-# Generated from qquickpalette.pro.
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
-#####################################################################
-## tst_qquickpalette Test:
-#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickpalette LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickpalette
SOURCES
tst_qquickpalette.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
+)
+
+qt_internal_extend_target(tst_qquickpalette CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=":/data"
)
-## Scopes:
-#####################################################################
+qt_internal_extend_target(tst_qquickpalette CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+)
diff --git a/tests/auto/quick/qquickpalette/data/palette-item-custom.qml b/tests/auto/quick/qquickpalette/data/palette-item-custom.qml
new file mode 100644
index 0000000000..a7a3a1d0b8
--- /dev/null
+++ b/tests/auto/quick/qquickpalette/data/palette-item-custom.qml
@@ -0,0 +1,26 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Item {
+ palette.alternateBase: "aqua"
+ palette.base: "azure"
+ palette.brightText: "beige"
+ palette.button: "bisque"
+ palette.buttonText: "chocolate"
+ palette.dark: "coral"
+ palette.highlight: "crimson"
+ palette.highlightedText: "fuchsia"
+ palette.light: "gold"
+ palette.link: "indigo"
+ palette.linkVisited: "ivory"
+ palette.mid: "khaki"
+ palette.midlight: "lavender"
+ palette.shadow: "linen"
+ palette.text: "moccasin"
+ palette.toolTipBase: "navy"
+ palette.toolTipText: "orchid"
+ palette.window: "plum"
+ palette.windowText: "salmon"
+}
diff --git a/tests/auto/quick/qquickpalette/data/palette-item-default.qml b/tests/auto/quick/qquickpalette/data/palette-item-default.qml
new file mode 100644
index 0000000000..3d60a51195
--- /dev/null
+++ b/tests/auto/quick/qquickpalette/data/palette-item-default.qml
@@ -0,0 +1,7 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Item {
+}
diff --git a/tests/auto/quick/qquickpalette/data/palette-window-custom.qml b/tests/auto/quick/qquickpalette/data/palette-window-custom.qml
new file mode 100644
index 0000000000..60bed45405
--- /dev/null
+++ b/tests/auto/quick/qquickpalette/data/palette-window-custom.qml
@@ -0,0 +1,26 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick.Window
+
+Window {
+ palette.alternateBase: "aqua"
+ palette.base: "azure"
+ palette.brightText: "beige"
+ palette.button: "bisque"
+ palette.buttonText: "chocolate"
+ palette.dark: "coral"
+ palette.highlight: "crimson"
+ palette.highlightedText: "fuchsia"
+ palette.light: "gold"
+ palette.link: "indigo"
+ palette.linkVisited: "ivory"
+ palette.mid: "khaki"
+ palette.midlight: "lavender"
+ palette.shadow: "linen"
+ palette.text: "moccasin"
+ palette.toolTipBase: "navy"
+ palette.toolTipText: "orchid"
+ palette.window: "plum"
+ palette.windowText: "salmon"
+}
diff --git a/tests/auto/quick/qquickpalette/data/palette-window-default.qml b/tests/auto/quick/qquickpalette/data/palette-window-default.qml
new file mode 100644
index 0000000000..cd0036ac64
--- /dev/null
+++ b/tests/auto/quick/qquickpalette/data/palette-window-default.qml
@@ -0,0 +1,7 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick.Window
+
+Window {
+}
diff --git a/tests/auto/quick/qquickpalette/tst_qquickpalette.cpp b/tests/auto/quick/qquickpalette/tst_qquickpalette.cpp
index e211a034ee..7b7eace30b 100644
--- a/tests/auto/quick/qquickpalette/tst_qquickpalette.cpp
+++ b/tests/auto/quick/qquickpalette/tst_qquickpalette.cpp
@@ -1,53 +1,31 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/qtest.h>
#include <QtTest/QSignalSpy>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlengine.h>
+
#include <QtQuick/private/qquickpalette_p.h>
#include <QtQuick/private/qquickabstractpaletteprovider_p.h>
#include <QtQuick/private/qquickpalettecolorprovider_p.h>
-class tst_QQuickPalette : public QObject
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+
+// Use this to get a more descriptive failure message (QTBUG-87039).
+#define COMPARE_PALETTES(actualPalette, expectedPalette) \
+ QVERIFY2(actualPalette == expectedPalette, \
+ qPrintable(QString::fromLatin1("\n Actual: %1\n Expected: %2") \
+ .arg(QDebug::toString(actualPalette)).arg(QDebug::toString(expectedPalette))));
+
+class tst_QQuickPalette : public QQmlDataTest
{
Q_OBJECT
+public:
+ tst_QQuickPalette();
+
private Q_SLOTS:
void resolvingColor();
void resolvingColor_data();
@@ -73,11 +51,19 @@ private Q_SLOTS:
void createFromQtPalette();
void convertToQtPalette();
+
+ void qml_data();
+ void qml();
};
using GroupGetter = QQuickColorGroup* (QQuickPalette::* )() const;
Q_DECLARE_METATYPE(GroupGetter);
+tst_QQuickPalette::tst_QQuickPalette()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
void tst_QQuickPalette::resolvingColor()
{
QFETCH(QPalette::ColorGroup, colorGroup);
@@ -131,8 +117,8 @@ void tst_QQuickPalette::newColorSubgroup()
anotherPalette.fromQPalette(Qt::red);
(p.*setter)((anotherPalette.*getter)());
- QCOMPARE(subgroupChanged.count(), 1);
- QCOMPARE(paletteChanged.count(), 1);
+ QCOMPARE(subgroupChanged.size(), 1);
+ QCOMPARE(paletteChanged.size(), 1);
}
}
@@ -175,7 +161,7 @@ void tst_QQuickPalette::paletteChangedWhenColorGroupChanged()
p.inactive()->setMid(Qt::green);
p.disabled()->setMid(Qt::blue);
- QCOMPARE(sp.count(), 3);
+ QCOMPARE(sp.size(), 3);
}
void tst_QQuickPalette::createDefault()
@@ -196,7 +182,7 @@ void tst_QQuickPalette::changeCurrentColorGroup()
palette.setCurrentGroup(QPalette::Disabled);
QCOMPARE(palette.currentColorGroup(), QPalette::Disabled);
- QCOMPARE(ss.count(), 1);
+ QCOMPARE(ss.size(), 1);
}
void tst_QQuickPalette::inheritColor()
@@ -280,10 +266,10 @@ void tst_QQuickPalette::createFromQtPalette()
QSignalSpy sp(&palette, &QQuickColorGroup::changed);
palette.fromQPalette(QPalette());
- QCOMPARE(sp.count(), 0);
+ QCOMPARE(sp.size(), 0);
palette.fromQPalette(somePalette);
- QCOMPARE(sp.count(), 1);
+ QCOMPARE(sp.size(), 1);
}
void tst_QQuickPalette::convertToQtPalette()
@@ -299,6 +285,58 @@ void tst_QQuickPalette::convertToQtPalette()
QCOMPARE(palette.toQPalette(), somePalette.resolve(pp->defaultPalette()));
}
+// QTBUG-93691
+void tst_QQuickPalette::qml_data()
+{
+ QTest::addColumn<QString>("testFile");
+ QTest::addColumn<QPalette>("expectedPalette");
+
+ const QPalette defaultPalette;
+ QTest::newRow("Item") << "palette-item-default.qml" << defaultPalette;
+ QTest::newRow("Window") << "palette-window-default.qml" << defaultPalette;
+
+ QPalette customPalette;
+ customPalette.setColor(QPalette::AlternateBase, QColor("aqua"));
+ customPalette.setColor(QPalette::Base, QColor("azure"));
+ customPalette.setColor(QPalette::BrightText, QColor("beige"));
+ customPalette.setColor(QPalette::Button, QColor("bisque"));
+ customPalette.setColor(QPalette::ButtonText, QColor("chocolate"));
+ customPalette.setColor(QPalette::Dark, QColor("coral"));
+ customPalette.setColor(QPalette::Highlight, QColor("crimson"));
+ customPalette.setColor(QPalette::HighlightedText, QColor("fuchsia"));
+ customPalette.setColor(QPalette::Light, QColor("gold"));
+ customPalette.setColor(QPalette::Link, QColor("indigo"));
+ customPalette.setColor(QPalette::LinkVisited, QColor("ivory"));
+ customPalette.setColor(QPalette::Mid, QColor("khaki"));
+ customPalette.setColor(QPalette::Midlight, QColor("lavender"));
+ customPalette.setColor(QPalette::Shadow, QColor("linen"));
+ customPalette.setColor(QPalette::Text, QColor("moccasin"));
+ customPalette.setColor(QPalette::ToolTipBase, QColor("navy"));
+ customPalette.setColor(QPalette::ToolTipText, QColor("orchid"));
+ customPalette.setColor(QPalette::Window, QColor("plum"));
+ customPalette.setColor(QPalette::WindowText, QColor("salmon"));
+
+ QTest::newRow("Item:custom") << "palette-item-custom.qml" << customPalette;
+ QTest::newRow("Window:custom") << "palette-window-custom.qml" << customPalette;
+}
+
+void tst_QQuickPalette::qml()
+{
+ QFETCH(QString, testFile);
+ QFETCH(QPalette, expectedPalette);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl(testFile));
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY2(!object.isNull(), qPrintable(component.errorString()));
+
+ const QVariant var = object->property("palette");
+ QVERIFY(var.isValid());
+ COMPARE_PALETTES(var.value<QQuickPalette*>()->toQPalette(), expectedPalette);
+}
+
QTEST_MAIN(tst_QQuickPalette)
#include "tst_qquickpalette.moc"
diff --git a/tests/auto/quick/qquickpath/CMakeLists.txt b/tests/auto/quick/qquickpath/CMakeLists.txt
index c616519987..80c6ed9980 100644
--- a/tests/auto/quick/qquickpath/CMakeLists.txt
+++ b/tests/auto/quick/qquickpath/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickpath.pro.
#####################################################################
## tst_qquickpath Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickpath LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,16 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickpath
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickpath.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -33,10 +40,10 @@ qt_internal_add_test(tst_qquickpath
qt_internal_extend_target(tst_qquickpath CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickpath CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickpath/tst_qquickpath.cpp b/tests/auto/quick/qquickpath/tst_qquickpath.cpp
index c89ce730a8..9fd4d9ec8a 100644
--- a/tests/auto/quick/qquickpath/tst_qquickpath.cpp
+++ b/tests/auto/quick/qquickpath/tst_qquickpath.cpp
@@ -1,43 +1,18 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQuick/private/qquickpath_p.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
class tst_QuickPath : public QQmlDataTest
{
Q_OBJECT
public:
- tst_QuickPath() {}
+ tst_QuickPath() : QQmlDataTest(QT_QMLTEST_DATADIR) {}
private slots:
void arc();
diff --git a/tests/auto/quick/qquickpathview/CMakeLists.txt b/tests/auto/quick/qquickpathview/CMakeLists.txt
index 2f3bd53500..a7f74bafce 100644
--- a/tests/auto/quick/qquickpathview/CMakeLists.txt
+++ b/tests/auto/quick/qquickpathview/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickpathview.pro.
#####################################################################
## tst_qquickpathview Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickpathview LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,16 +21,8 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickpathview
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickpathview.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
@@ -29,6 +30,7 @@ qt_internal_add_test(tst_qquickpathview
Qt::QmlPrivate
Qt::QuickPrivate
Qt::QuickTest
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -36,16 +38,16 @@ qt_internal_add_test(tst_qquickpathview
#####################################################################
qt_internal_extend_target(tst_qquickpathview CONDITION TARGET Qt::Widgets
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Widgets
)
qt_internal_extend_target(tst_qquickpathview CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickpathview CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickpathview/data/flickableDelegate.qml b/tests/auto/quick/qquickpathview/data/flickableDelegate.qml
index 0304efaa31..0cb42dcf86 100644
--- a/tests/auto/quick/qquickpathview/data/flickableDelegate.qml
+++ b/tests/auto/quick/qquickpathview/data/flickableDelegate.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickpathview/data/mousePressAfterFlick.qml b/tests/auto/quick/qquickpathview/data/mousePressAfterFlick.qml
new file mode 100644
index 0000000000..a30234127b
--- /dev/null
+++ b/tests/auto/quick/qquickpathview/data/mousePressAfterFlick.qml
@@ -0,0 +1,61 @@
+import QtQuick
+
+Item {
+ id: root
+ width: 360
+ height: 900
+
+ MouseArea {
+ id: rootMouseArea
+ objectName: "rootMouseArea"
+ anchors.fill: parent
+ }
+
+ PathView {
+ id: pathView
+ objectName: "pathView"
+ anchors.centerIn: parent
+ width: 150
+ height: parent.height
+ dragMargin: Number.POSITIVE_INFINITY
+
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+ pathItemCount: 9
+
+ Item {
+ anchors.fill: parent
+ }
+
+ model: 10
+
+ delegate: Rectangle {
+ id: delegate
+ width: parent.width
+ height: 120
+ color: "red"
+ Text {
+ anchors.fill: parent
+ horizontalAlignment: Qt.AlignHCenter
+ text: "Path element " + modelData
+ }
+ }
+
+ path: Path {
+ id: path
+ property int width: pathView.width
+ startX: path.width / 2
+ startY: 0
+
+ PathCurve {
+ x: path.width / 2
+ relativeY: 32
+ }
+ PathCurve {
+ x: path.width / 2
+ relativeY: pathView.height - 32
+ }
+ }
+ }
+}
+
diff --git a/tests/auto/quick/qquickpathview/data/nestedInFlickable.qml b/tests/auto/quick/qquickpathview/data/nestedInFlickable.qml
index 216a25b8e2..35f5b12d17 100644
--- a/tests/auto/quick/qquickpathview/data/nestedInFlickable.qml
+++ b/tests/auto/quick/qquickpathview/data/nestedInFlickable.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickpathview/data/nestedmousearea2.qml b/tests/auto/quick/qquickpathview/data/nestedmousearea2.qml
index ff11002552..985b53cd45 100644
--- a/tests/auto/quick/qquickpathview/data/nestedmousearea2.qml
+++ b/tests/auto/quick/qquickpathview/data/nestedmousearea2.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickpathview/data/objectModelMove.qml b/tests/auto/quick/qquickpathview/data/objectModelMove.qml
index d5fa510d69..04102d0956 100644
--- a/tests/auto/quick/qquickpathview/data/objectModelMove.qml
+++ b/tests/auto/quick/qquickpathview/data/objectModelMove.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQml.Models 2.11
import QtQuick 2.11
diff --git a/tests/auto/quick/qquickpathview/data/overcached.qml b/tests/auto/quick/qquickpathview/data/overcached.qml
new file mode 100644
index 0000000000..734b0cd7cf
--- /dev/null
+++ b/tests/auto/quick/qquickpathview/data/overcached.qml
@@ -0,0 +1,27 @@
+import QtQuick 2.0
+
+PathView {
+ id: view
+ property int delegatesCreated: 0
+ property int delegatesDestroyed: 0
+
+ anchors.fill: parent
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+ pathItemCount: 10
+ interactive: true
+ model: 15
+ // Much bigger cache than model - pathItemCount
+ cacheItemCount: 100
+ delegate: Text {
+ text: modelData
+ Component.onCompleted: view.delegatesCreated++;
+ Component.onDestruction: view.delegatesDestroyed++;
+ }
+ path: Path {
+ PathLine {
+ x: 0
+ y: 400
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickpathview/data/qtbug37815.qml b/tests/auto/quick/qquickpathview/data/qtbug37815.qml
index 28affbac38..8854164b5c 100644
--- a/tests/auto/quick/qquickpathview/data/qtbug37815.qml
+++ b/tests/auto/quick/qquickpathview/data/qtbug37815.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Netris
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Netris
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickpathview/data/qtbug46487.qml b/tests/auto/quick/qquickpathview/data/qtbug46487.qml
new file mode 100644
index 0000000000..840d77ffe4
--- /dev/null
+++ b/tests/auto/quick/qquickpathview/data/qtbug46487.qml
@@ -0,0 +1,28 @@
+import QtQuick 2.0
+
+PathView {
+ id: view
+ property int delegatesCreated: 0
+ property int delegatesDestroyed: 0
+
+ width: 400
+ height: 400
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+ pathItemCount: 5
+ currentIndex: 1
+ model: customModel
+ delegate: Text {
+ text: "item: " + index + " of: " + view.count
+ Component.onCompleted: view.delegatesCreated++;
+ Component.onDestruction: view.delegatesDestroyed++;
+ }
+ path: Path {
+ startX: 50
+ startY: 0
+ PathLine {
+ x: 50
+ y: 400
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickpathview/data/qtbug53464.qml b/tests/auto/quick/qquickpathview/data/qtbug53464.qml
index 123cafb04c..df16763ccb 100644
--- a/tests/auto/quick/qquickpathview/data/qtbug53464.qml
+++ b/tests/auto/quick/qquickpathview/data/qtbug53464.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Netris
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Netris
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickpathview/data/qtbug90479.qml b/tests/auto/quick/qquickpathview/data/qtbug90479.qml
new file mode 100644
index 0000000000..bfa4ab8243
--- /dev/null
+++ b/tests/auto/quick/qquickpathview/data/qtbug90479.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.0
+
+PathView {
+ id: view
+ property int delegatesCreated: 0
+ property int delegatesDestroyed: 0
+
+ anchors.fill: parent
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+ pathItemCount: 6
+ interactive: true
+ model: 19
+ delegate: Text {
+ text: modelData
+ Component.onCompleted: view.delegatesCreated++;
+ Component.onDestruction: view.delegatesDestroyed++;
+ }
+ path: Path {
+ PathLine {
+ x: 0
+ y: 400
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
index 733281c20d..1b06e0047b 100644
--- a/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
+++ b/tests/auto/quick/qquickpathview/tst_qquickpathview.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtQuick/qquickview.h>
@@ -38,23 +13,25 @@
#include <QtQuick/private/qquickpath_p.h>
#include <QtQuick/private/qquicktext_p.h>
#include <QtQuick/private/qquickrectangle_p.h>
+#include <QtQuick/private/qquickmousearea_p.h>
#include <QtQuickTest/QtQuickTest>
#include <QtQmlModels/private/qqmllistmodel_p.h>
#include <QtQml/private/qqmlvaluetype_p.h>
#include <QtGui/qstandarditemmodel.h>
#include <QStringListModel>
#include <QFile>
+#include <QEvent>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
-#include "../shared/visualtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <math.h>
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
-using namespace QQuickViewTestUtil;
-using namespace QQuickVisualTestUtil;
+using namespace QQuickViewTestUtils;
+using namespace QQuickVisualTestUtils;
Q_DECLARE_METATYPE(QQuickPathView::HighlightRangeMode)
Q_DECLARE_METATYPE(QQuickPathView::PositionMode)
@@ -153,6 +130,14 @@ private slots:
void objectModelMove();
void requiredPropertiesInDelegate();
void requiredPropertiesInDelegatePreventUnrelated();
+ void touchMove();
+ void mousePressAfterFlick();
+ void qtbug90479();
+ void overCached();
+ void qtbug46487();
+
+private:
+ QScopedPointer<QPointingDevice> touchDevice = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
};
class TestObject : public QObject
@@ -186,6 +171,7 @@ private:
};
tst_QQuickPathView::tst_QQuickPathView()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
@@ -230,7 +216,7 @@ void tst_QQuickPathView::items()
QCOMPARE(pathview->count(), model.count());
QCOMPARE(window->rootObject()->property("count").toInt(), model.count());
- QCOMPARE(pathview->childItems().count(), model.count()+1); // assumes all are visible, including highlight
+ QCOMPARE(pathview->childItems().size(), model.count()+1); // assumes all are visible, including highlight
for (int i = 0; i < model.count(); ++i) {
QQuickText *name = findItem<QQuickText>(pathview, "textName", i);
@@ -700,7 +686,7 @@ void tst_QQuickPathView::consecutiveModelChanges()
else
pathview->setOffset(4);
- for (int i=0; i<changes.count(); i++) {
+ for (int i=0; i<changes.size(); i++) {
switch (changes[i].type) {
case ListChange::Inserted:
{
@@ -720,15 +706,15 @@ void tst_QQuickPathView::consecutiveModelChanges()
pathview->setCurrentIndex(changes[i].index);
break;
case ListChange::Polish:
- QQuickTest::qWaitForItemPolished(pathview);
+ QQuickTest::qWaitForPolish(pathview);
break;
default:
continue;
}
}
- QQuickTest::qWaitForItemPolished(pathview);
+ QQuickTest::qWaitForPolish(pathview);
- QCOMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), count);
+ QCOMPARE(findItems<QQuickItem>(pathview, "wrapper").size(), count);
QCOMPARE(pathview->count(), count);
QTRY_COMPARE(pathview->offset(), offset);
@@ -831,7 +817,7 @@ void tst_QQuickPathView::dataModel()
QTest::qWait(100);
QCOMPARE(window->rootObject()->property("viewCount").toInt(), model.count());
- QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 14);
+ QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").size(), 14);
QCOMPARE(pathview->currentIndex(), 0);
QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 0));
@@ -851,7 +837,7 @@ void tst_QQuickPathView::dataModel()
QMetaObject::invokeMethod(window->rootObject(), "checkProperties");
QVERIFY(!testObject->error());
- QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
+ QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").size(), 5);
QQuickRectangle *testItem = findItem<QQuickRectangle>(pathview, "wrapper", 4);
QVERIFY(testItem != nullptr);
@@ -864,7 +850,7 @@ void tst_QQuickPathView::dataModel()
model.insertItem(2, "pink", "2");
- QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
+ QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").size(), 5);
QCOMPARE(pathview->currentIndex(), 1);
QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
@@ -872,24 +858,23 @@ void tst_QQuickPathView::dataModel()
QCOMPARE(text->text(), model.name(2));
model.removeItem(3);
- QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
+ QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").size(), 5);
text = findItem<QQuickText>(pathview, "myText", 3);
QVERIFY(text);
QCOMPARE(text->text(), model.name(3));
QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
model.moveItem(3, 5);
- QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
- QList<QQuickItem*> items = findItems<QQuickItem>(pathview, "wrapper");
- foreach (QQuickItem *item, items) {
+ QTRY_COMPARE(findItems<QQuickItem>(pathview, "wrapper").size(), 5);
+ const QList<QQuickItem *> items = findItems<QQuickItem>(pathview, "wrapper");
+ for (QQuickItem *item : items)
QVERIFY(item->property("onPath").toBool());
- }
QCOMPARE(pathview->currentItem(), findItem<QQuickItem>(pathview, "wrapper", 1));
// QTBUG-14199
pathview->setOffset(7);
pathview->setOffset(0);
- QCOMPARE(findItems<QQuickItem>(pathview, "wrapper").count(), 5);
+ QCOMPARE(findItems<QQuickItem>(pathview, "wrapper").size(), 5);
pathview->setCurrentIndex(model.count()-1);
QTRY_COMPARE(pathview->offset(), 1.0);
@@ -1140,7 +1125,7 @@ void tst_QQuickPathView::setCurrentIndex()
pathview->setSnapMode(QQuickPathView::SnapToItem);
pathview->setCurrentIndex(3);
QTRY_COMPARE(pathview->currentIndex(), 3);
- QCOMPARE(currentIndexSpy.count(), 1);
+ QCOMPARE(currentIndexSpy.size(), 1);
}
void tst_QQuickPathView::setCurrentIndexWrap()
@@ -1161,8 +1146,8 @@ void tst_QQuickPathView::setCurrentIndexWrap()
pathview->setCurrentIndex(0);
pathview->setCurrentIndex(4);
QCOMPARE(pathview->currentIndex(), 4);
- QCOMPARE(currentIndexSpy.count(), 2);
- QCOMPARE(movementStartedSpy.count(), 0);
+ QCOMPARE(currentIndexSpy.size(), 2);
+ QCOMPARE(movementStartedSpy.size(), 0);
}
void tst_QQuickPathView::resetModel()
@@ -1227,21 +1212,21 @@ void tst_QQuickPathView::propertyChanges()
QCOMPARE(pathView->preferredHighlightEnd(), 0.4);
QCOMPARE(pathView->dragMargin(), 20.0);
- QCOMPARE(snapPositionSpy.count(), 1);
- QCOMPARE(dragMarginSpy.count(), 1);
+ QCOMPARE(snapPositionSpy.size(), 1);
+ QCOMPARE(dragMarginSpy.size(), 1);
pathView->setPreferredHighlightBegin(0.4);
pathView->setPreferredHighlightEnd(0.4);
pathView->setDragMargin(20.0);
- QCOMPARE(snapPositionSpy.count(), 1);
- QCOMPARE(dragMarginSpy.count(), 1);
+ QCOMPARE(snapPositionSpy.size(), 1);
+ QCOMPARE(dragMarginSpy.size(), 1);
QSignalSpy maximumFlickVelocitySpy(pathView, SIGNAL(maximumFlickVelocityChanged()));
pathView->setMaximumFlickVelocity(1000);
- QCOMPARE(maximumFlickVelocitySpy.count(), 1);
+ QCOMPARE(maximumFlickVelocitySpy.size(), 1);
pathView->setMaximumFlickVelocity(1000);
- QCOMPARE(maximumFlickVelocitySpy.count(), 1);
+ QCOMPARE(maximumFlickVelocitySpy.size(), 1);
}
@@ -1269,14 +1254,14 @@ void tst_QQuickPathView::pathChanges()
QCOMPARE(path->startX(), 240.0);
QCOMPARE(path->startY(), 220.0);
- QCOMPARE(startXSpy.count(),1);
- QCOMPARE(startYSpy.count(),1);
+ QCOMPARE(startXSpy.size(),1);
+ QCOMPARE(startYSpy.size(),1);
path->setStartX(240);
path->setStartY(220);
- QCOMPARE(startXSpy.count(),1);
- QCOMPARE(startYSpy.count(),1);
+ QCOMPARE(startXSpy.size(),1);
+ QCOMPARE(startYSpy.size(),1);
QQuickPath *alternatePath = window->rootObject()->findChild<QQuickPath*>("alternatePath");
QVERIFY(alternatePath);
@@ -1287,10 +1272,10 @@ void tst_QQuickPathView::pathChanges()
pathView->setPath(alternatePath);
QCOMPARE(pathView->path(), alternatePath);
- QCOMPARE(pathSpy.count(),1);
+ QCOMPARE(pathSpy.size(),1);
pathView->setPath(alternatePath);
- QCOMPARE(pathSpy.count(),1);
+ QCOMPARE(pathSpy.size(),1);
QQuickPathAttribute *pathAttribute = window->rootObject()->findChild<QQuickPathAttribute*>("pathAttribute");
QVERIFY(pathAttribute);
@@ -1300,10 +1285,10 @@ void tst_QQuickPathView::pathChanges()
pathAttribute->setName("scale");
QCOMPARE(pathAttribute->name(), QString("scale"));
- QCOMPARE(nameSpy.count(),1);
+ QCOMPARE(nameSpy.size(),1);
pathAttribute->setName("scale");
- QCOMPARE(nameSpy.count(),1);
+ QCOMPARE(nameSpy.size(),1);
}
void tst_QQuickPathView::componentChanges()
@@ -1322,10 +1307,10 @@ void tst_QQuickPathView::componentChanges()
pathView->setDelegate(&delegateComponent);
QCOMPARE(pathView->delegate(), &delegateComponent);
- QCOMPARE(delegateSpy.count(),1);
+ QCOMPARE(delegateSpy.size(),1);
pathView->setDelegate(&delegateComponent);
- QCOMPARE(delegateSpy.count(),1);
+ QCOMPARE(delegateSpy.size(),1);
}
void tst_QQuickPathView::modelChanges()
@@ -1348,17 +1333,17 @@ void tst_QQuickPathView::modelChanges()
QCOMPARE(pathView->currentIndex(), 3);
pathView->setModel(modelVariant);
QCOMPARE(pathView->model(), modelVariant);
- QCOMPARE(modelSpy.count(),1);
+ QCOMPARE(modelSpy.size(),1);
QCOMPARE(pathView->currentIndex(), 0);
- QCOMPARE(currentIndexSpy.count(), 1);
+ QCOMPARE(currentIndexSpy.size(), 1);
pathView->setModel(modelVariant);
- QCOMPARE(modelSpy.count(),1);
+ QCOMPARE(modelSpy.size(),1);
pathView->setModel(QVariant());
- QCOMPARE(modelSpy.count(),2);
+ QCOMPARE(modelSpy.size(),2);
QCOMPARE(pathView->currentIndex(), 0);
- QCOMPARE(currentIndexSpy.count(), 1);
+ QCOMPARE(currentIndexSpy.size(), 1);
}
@@ -1389,8 +1374,7 @@ void tst_QQuickPathView::package()
QVERIFY(window);
window->setSource(testFileUrl("pathview_package.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathView = window->rootObject()->findChild<QQuickPathView*>("photoPathView");
QVERIFY(pathView);
@@ -1399,7 +1383,7 @@ void tst_QQuickPathView::package()
QSKIP("QTBUG-27170 view does not reliably receive polish without a running animation");
#endif
- QQuickTest::qWaitForItemPolished(pathView);
+ QQuickTest::qWaitForPolish(pathView);
QQuickItem *item = findItem<QQuickItem>(pathView, "pathItem");
QVERIFY(item);
QVERIFY(item->scale() != 1.0);
@@ -1515,12 +1499,10 @@ void tst_QQuickPathView::undefinedPath()
void tst_QQuickPathView::mouseDrag()
{
QScopedPointer<QQuickView> window(createView());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("dragpath.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
QVERIFY(pathview != nullptr);
@@ -1538,21 +1520,23 @@ void tst_QQuickPathView::mouseDrag()
QTest::qWait(100);
{
- QMouseEvent mv(QEvent::MouseMove, QPoint(50,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QMouseEvent mv(QEvent::MouseMove, QPoint(50,100), window->mapToGlobal(QPoint(50,100)),
+ Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
QGuiApplication::sendEvent(window.data(), &mv);
}
// first move beyond threshold does not trigger drag
QVERIFY(!pathview->isMoving());
QVERIFY(!pathview->isDragging());
- QCOMPARE(movingSpy.count(), 0);
- QCOMPARE(moveStartedSpy.count(), 0);
- QCOMPARE(moveEndedSpy.count(), 0);
- QCOMPARE(draggingSpy.count(), 0);
- QCOMPARE(dragStartedSpy.count(), 0);
- QCOMPARE(dragEndedSpy.count(), 0);
+ QCOMPARE(movingSpy.size(), 0);
+ QCOMPARE(moveStartedSpy.size(), 0);
+ QCOMPARE(moveEndedSpy.size(), 0);
+ QCOMPARE(draggingSpy.size(), 0);
+ QCOMPARE(dragStartedSpy.size(), 0);
+ QCOMPARE(dragEndedSpy.size(), 0);
{
- QMouseEvent mv(QEvent::MouseMove, QPoint(90,100), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QMouseEvent mv(QEvent::MouseMove, QPoint(90,100), window->mapToGlobal(QPoint(90,100)),
+ Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
QGuiApplication::sendEvent(window.data(), &mv);
}
// next move beyond threshold does trigger drag
@@ -1562,36 +1546,33 @@ void tst_QQuickPathView::mouseDrag()
#endif // Q_OS_WIN
QVERIFY(pathview->isMoving());
QVERIFY(pathview->isDragging());
- QCOMPARE(movingSpy.count(), 1);
- QCOMPARE(moveStartedSpy.count(), 1);
- QCOMPARE(moveEndedSpy.count(), 0);
- QCOMPARE(draggingSpy.count(), 1);
- QCOMPARE(dragStartedSpy.count(), 1);
- QCOMPARE(dragEndedSpy.count(), 0);
+ QCOMPARE(movingSpy.size(), 1);
+ QCOMPARE(moveStartedSpy.size(), 1);
+ QCOMPARE(moveEndedSpy.size(), 0);
+ QCOMPARE(draggingSpy.size(), 1);
+ QCOMPARE(dragStartedSpy.size(), 1);
+ QCOMPARE(dragEndedSpy.size(), 0);
QVERIFY(pathview->currentIndex() != current);
QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(40,100));
QVERIFY(!pathview->isDragging());
- QCOMPARE(draggingSpy.count(), 2);
- QCOMPARE(dragStartedSpy.count(), 1);
- QCOMPARE(dragEndedSpy.count(), 1);
- QTRY_COMPARE(movingSpy.count(), 2);
- QTRY_COMPARE(moveEndedSpy.count(), 1);
- QCOMPARE(moveStartedSpy.count(), 1);
+ QCOMPARE(draggingSpy.size(), 2);
+ QCOMPARE(dragStartedSpy.size(), 1);
+ QCOMPARE(dragEndedSpy.size(), 1);
+ QTRY_COMPARE(movingSpy.size(), 2);
+ QTRY_COMPARE(moveEndedSpy.size(), 1);
+ QCOMPARE(moveStartedSpy.size(), 1);
}
void tst_QQuickPathView::nestedMouseAreaDrag()
{
QScopedPointer<QQuickView> window(createView());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("nestedmousearea.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
-
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
QVERIFY(pathview != nullptr);
@@ -1608,12 +1589,10 @@ void tst_QQuickPathView::nestedMouseAreaDrag()
void tst_QQuickPathView::flickNClick() // QTBUG-77173
{
QScopedPointer<QQuickView> window(createView());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("nestedmousearea2.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
QVERIFY(pathview != nullptr);
@@ -1640,32 +1619,32 @@ void tst_QQuickPathView::flickNClick() // QTBUG-77173
flickStartedSpy.clear();
flickEndedSpy.clear();
// Dragging the child mouse area should animate the PathView (MA has no drag target)
- flick(window.data(), QPoint(200,200), QPoint(400,200), duration);
+ flick(window.data(), QPoint(199,199), QPoint(399,199), duration);
QVERIFY(pathview->isMoving());
- QCOMPARE(movingChangedSpy.count(), 1);
- QCOMPARE(draggingSpy.count(), 2);
- QCOMPARE(dragStartedSpy.count(), 1);
- QCOMPARE(dragEndedSpy.count(), 1);
- QVERIFY(currentIndexSpy.count() > 0);
- QCOMPARE(moveStartedSpy.count(), 1);
- QCOMPARE(moveEndedSpy.count(), 0);
- QCOMPARE(flickingSpy.count(), 1);
- QCOMPARE(flickStartedSpy.count(), 1);
- QCOMPARE(flickEndedSpy.count(), 0);
+ QCOMPARE(movingChangedSpy.size(), 1);
+ QCOMPARE(draggingSpy.size(), 2);
+ QCOMPARE(dragStartedSpy.size(), 1);
+ QCOMPARE(dragEndedSpy.size(), 1);
+ QVERIFY(currentIndexSpy.size() > 0);
+ QCOMPARE(moveStartedSpy.size(), 1);
+ QCOMPARE(moveEndedSpy.size(), 0);
+ QCOMPARE(flickingSpy.size(), 1);
+ QCOMPARE(flickStartedSpy.size(), 1);
+ QCOMPARE(flickEndedSpy.size(), 0);
// Now while it's still moving, click it.
// The PathView should stop at a position such that offset is a whole number.
QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(200, 200));
QTRY_VERIFY(!pathview->isMoving());
- QCOMPARE(movingChangedSpy.count(), 2); // QTBUG-78926
- QCOMPARE(draggingSpy.count(), 2);
- QCOMPARE(dragStartedSpy.count(), 1);
- QCOMPARE(dragEndedSpy.count(), 1);
- QCOMPARE(moveStartedSpy.count(), 1);
- QCOMPARE(moveEndedSpy.count(), 1);
- QCOMPARE(flickingSpy.count(), 2);
- QCOMPARE(flickStartedSpy.count(), 1);
- QCOMPARE(flickEndedSpy.count(), 1);
+ QCOMPARE(movingChangedSpy.size(), 2); // QTBUG-78926
+ QCOMPARE(draggingSpy.size(), 2);
+ QCOMPARE(dragStartedSpy.size(), 1);
+ QCOMPARE(dragEndedSpy.size(), 1);
+ QCOMPARE(moveStartedSpy.size(), 1);
+ QCOMPARE(moveEndedSpy.size(), 1);
+ QCOMPARE(flickingSpy.size(), 2);
+ QCOMPARE(flickStartedSpy.size(), 1);
+ QCOMPARE(flickEndedSpy.size(), 1);
QVERIFY(qFuzzyIsNull(pathview->offset() - int(pathview->offset())));
}
}
@@ -1702,9 +1681,7 @@ void tst_QQuickPathView::changePreferredHighlight()
window->setGeometry(0,0,400,200);
window->setSource(testFileUrl("dragpath.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
QVERIFY(pathview != nullptr);
@@ -1789,7 +1766,7 @@ void tst_QQuickPathView::currentOffsetOnInsertion()
model.insertItem(0, "item1", "1");
qApp->processEvents();
- QCOMPARE(currentIndexSpy.count(), 1);
+ QCOMPARE(currentIndexSpy.size(), 1);
// currentIndex is now 1
item = findItem<QQuickRectangle>(pathview, "wrapper", 1);
@@ -1802,7 +1779,7 @@ void tst_QQuickPathView::currentOffsetOnInsertion()
model.insertItem(0, "item2", "2");
qApp->processEvents();
- QCOMPARE(currentIndexSpy.count(), 2);
+ QCOMPARE(currentIndexSpy.size(), 2);
// currentIndex is now 2
item = findItem<QQuickRectangle>(pathview, "wrapper", 2);
@@ -1815,7 +1792,7 @@ void tst_QQuickPathView::currentOffsetOnInsertion()
model.removeItem(0);
qApp->processEvents();
- QCOMPARE(currentIndexSpy.count(), 3);
+ QCOMPARE(currentIndexSpy.size(), 3);
// currentIndex is now 1
item = findItem<QQuickRectangle>(pathview, "wrapper", 1);
@@ -1903,11 +1880,9 @@ void tst_QQuickPathView::cancelDrag()
{
QScopedPointer<QQuickView> window(createView());
window->setSource(testFileUrl("dragpath.qml"));
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
QVERIFY(pathview != nullptr);
@@ -1925,23 +1900,24 @@ void tst_QQuickPathView::cancelDrag()
QTRY_VERIFY(hasFraction(pathview->offset()));
QTRY_VERIFY(pathview->isMoving());
QVERIFY(pathview->isDragging());
- QCOMPARE(draggingSpy.count(), 1);
- QCOMPARE(dragStartedSpy.count(), 1);
- QCOMPARE(dragEndedSpy.count(), 0);
+ QCOMPARE(draggingSpy.size(), 1);
+ QCOMPARE(dragStartedSpy.size(), 1);
+ QCOMPARE(dragEndedSpy.size(), 0);
// steal mouse grab - cancels PathView dragging
auto mouse = QPointingDevice::primaryPointingDevice();
auto mousePriv = QPointingDevicePrivate::get(const_cast<QPointingDevice *>(mouse));
- QMouseEvent fakeMouseEv(QEvent::MouseMove, QPoint(130, 100), Qt::NoButton, Qt::LeftButton, Qt::NoModifier, mouse);
+ QMouseEvent fakeMouseEv(QEvent::MouseMove, QPoint(130, 100), QPoint(130, 100),
+ Qt::NoButton, Qt::LeftButton, Qt::NoModifier, mouse);
mousePriv->setExclusiveGrabber(&fakeMouseEv, fakeMouseEv.points().first(), nullptr);
// returns to a snap point.
QTRY_COMPARE(pathview->offset(), qreal(qFloor(pathview->offset())));
QTRY_VERIFY(!pathview->isMoving());
QVERIFY(!pathview->isDragging());
- QCOMPARE(draggingSpy.count(), 2);
- QCOMPARE(dragStartedSpy.count(), 1);
- QCOMPARE(dragEndedSpy.count(), 1);
+ QCOMPARE(draggingSpy.size(), 2);
+ QCOMPARE(dragStartedSpy.size(), 1);
+ QCOMPARE(dragEndedSpy.size(), 1);
QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(40,100));
}
@@ -1950,11 +1926,9 @@ void tst_QQuickPathView::maximumFlickVelocity()
{
QScopedPointer<QQuickView> window(createView());
window->setSource(testFileUrl("dragpath.qml"));
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
QVERIFY(pathview != nullptr);
@@ -1996,12 +1970,10 @@ void tst_QQuickPathView::snapToItem()
QFETCH(bool, enforceRange);
QScopedPointer<QQuickView> window(createView());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("panels.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = window->rootObject()->findChild<QQuickPathView*>("view");
QVERIFY(pathview != nullptr);
@@ -2040,12 +2012,10 @@ void tst_QQuickPathView::snapOneItem()
QFETCH(bool, enforceRange);
QScopedPointer<QQuickView> window(createView());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("panels.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = window->rootObject()->findChild<QQuickPathView*>("view");
QVERIFY(pathview != nullptr);
@@ -2055,7 +2025,7 @@ void tst_QQuickPathView::snapOneItem()
QSignalSpy snapModeSpy(pathview, SIGNAL(snapModeChanged()));
window->rootObject()->setProperty("snapOne", true);
- QCOMPARE(snapModeSpy.count(), 1);
+ QCOMPARE(snapModeSpy.size(), 1);
QTRY_VERIFY(!pathview->isMoving()); // ensure stable
int currentIndex = pathview->currentIndex();
@@ -2096,9 +2066,7 @@ void tst_QQuickPathView::positionViewAtIndex()
QScopedPointer<QQuickView> window(createView());
window->setSource(testFileUrl("pathview3.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
QVERIFY(pathview != nullptr);
@@ -2159,9 +2127,7 @@ void tst_QQuickPathView::indexAt_itemAt()
QScopedPointer<QQuickView> window(createView());
window->setSource(testFileUrl("pathview3.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
QVERIFY(pathview != nullptr);
@@ -2285,8 +2251,7 @@ void tst_QQuickPathView::changePathDuringRefill()
window->setSource(testFileUrl("changePathDuringRefill.qml"));
window->show();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathView = qobject_cast<QQuickPathView*>(window->rootObject());
QVERIFY(pathView != nullptr);
@@ -2309,12 +2274,10 @@ void tst_QQuickPathView::changePathDuringRefill()
void tst_QQuickPathView::nestedinFlickable()
{
QScopedPointer<QQuickView> window(createView());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("nestedInFlickable.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "pathView");
QVERIFY(pathview != nullptr);
@@ -2343,22 +2306,22 @@ void tst_QQuickPathView::nestedinFlickable()
// first move beyond threshold does not trigger drag
QVERIFY(!pathview->isMoving());
QVERIFY(!pathview->isDragging());
- QCOMPARE(movingSpy.count(), 0);
- QCOMPARE(moveStartedSpy.count(), 0);
- QCOMPARE(moveEndedSpy.count(), 0);
- QCOMPARE(fflickingSpy.count(), 0);
- QCOMPARE(fflickStartedSpy.count(), 0);
- QCOMPARE(fflickEndedSpy.count(), 0);
+ QCOMPARE(movingSpy.size(), 0);
+ QCOMPARE(moveStartedSpy.size(), 0);
+ QCOMPARE(moveEndedSpy.size(), 0);
+ QCOMPARE(fflickingSpy.size(), 0);
+ QCOMPARE(fflickStartedSpy.size(), 0);
+ QCOMPARE(fflickEndedSpy.size(), 0);
// no further moves after the initial move beyond threshold
QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(73,219));
- QTRY_COMPARE(movingSpy.count(), 2);
- QTRY_COMPARE(moveEndedSpy.count(), 1);
- QCOMPARE(moveStartedSpy.count(), 1);
+ QTRY_COMPARE(movingSpy.size(), 2);
+ QTRY_COMPARE(moveEndedSpy.size(), 1);
+ QCOMPARE(moveStartedSpy.size(), 1);
// Flickable should not handle this
- QCOMPARE(fflickingSpy.count(), 0);
- QCOMPARE(fflickStartedSpy.count(), 0);
- QCOMPARE(fflickEndedSpy.count(), 0);
+ QCOMPARE(fflickingSpy.size(), 0);
+ QCOMPARE(fflickStartedSpy.size(), 0);
+ QCOMPARE(fflickEndedSpy.size(), 0);
// now test that two quick flicks are both handled by the pathview
movingSpy.clear();
@@ -2392,37 +2355,35 @@ void tst_QQuickPathView::nestedinFlickable()
// we allow the multiple signal count case, rather than simply:
// QTRY_COMPARE(moveEndedSpy.count(), 1);
// QCOMPARE(moveStartedSpy.count(), 1);
- QTRY_VERIFY(moveEndedSpy.count() > 0);
+ QTRY_VERIFY(moveEndedSpy.size() > 0);
qCDebug(lcTests) << "After receiving moveEnded signal:"
- << "moveEndedSpy.count():" << moveEndedSpy.count()
- << "moveStartedSpy.count():" << moveStartedSpy.count()
- << "fflickingSpy.count():" << fflickingSpy.count()
- << "fflickStartedSpy.count():" << fflickStartedSpy.count()
- << "fflickEndedSpy.count():" << fflickEndedSpy.count();
- QTRY_COMPARE(moveStartedSpy.count(), moveEndedSpy.count());
+ << "moveEndedSpy.count():" << moveEndedSpy.size()
+ << "moveStartedSpy.count():" << moveStartedSpy.size()
+ << "fflickingSpy.count():" << fflickingSpy.size()
+ << "fflickStartedSpy.count():" << fflickStartedSpy.size()
+ << "fflickEndedSpy.count():" << fflickEndedSpy.size();
+ QTRY_COMPARE(moveStartedSpy.size(), moveEndedSpy.size());
qCDebug(lcTests) << "After receiving matched moveEnded signal(s):"
- << "moveEndedSpy.count():" << moveEndedSpy.count()
- << "moveStartedSpy.count():" << moveStartedSpy.count()
- << "fflickingSpy.count():" << fflickingSpy.count()
- << "fflickStartedSpy.count():" << fflickStartedSpy.count()
- << "fflickEndedSpy.count():" << fflickEndedSpy.count();
- QVERIFY(moveStartedSpy.count() <= 2);
+ << "moveEndedSpy.count():" << moveEndedSpy.size()
+ << "moveStartedSpy.count():" << moveStartedSpy.size()
+ << "fflickingSpy.count():" << fflickingSpy.size()
+ << "fflickStartedSpy.count():" << fflickStartedSpy.size()
+ << "fflickEndedSpy.count():" << fflickEndedSpy.size();
+ QVERIFY(moveStartedSpy.size() <= 2);
// Flickable should not handle this
- QCOMPARE(fflickingSpy.count(), 0);
- QCOMPARE(fflickStartedSpy.count(), 0);
- QCOMPARE(fflickEndedSpy.count(), 0);
+ QCOMPARE(fflickingSpy.size(), 0);
+ QCOMPARE(fflickStartedSpy.size(), 0);
+ QCOMPARE(fflickEndedSpy.size(), 0);
}
void tst_QQuickPathView::ungrabNestedinFlickable()
{
QScopedPointer<QQuickView> window(createView());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("ungrabNestedinFlickable.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = findItem<QQuickPathView>(window->rootObject(), "pathView");
QVERIFY(pathview != nullptr);
@@ -2451,12 +2412,10 @@ void tst_QQuickPathView::ungrabNestedinFlickable()
void tst_QQuickPathView::flickableDelegate()
{
QScopedPointer<QQuickView> window(createView());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("flickableDelegate.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
QVERIFY(pathview != nullptr);
@@ -2485,22 +2444,22 @@ void tst_QQuickPathView::flickableDelegate()
// first move beyond threshold does not trigger drag
QVERIFY(!flickable->isMoving());
QVERIFY(!flickable->isDragging());
- QCOMPARE(movingSpy.count(), 0);
- QCOMPARE(moveStartedSpy.count(), 0);
- QCOMPARE(moveEndedSpy.count(), 0);
- QCOMPARE(fflickingSpy.count(), 0);
- QCOMPARE(fflickStartedSpy.count(), 0);
- QCOMPARE(fflickEndedSpy.count(), 0);
+ QCOMPARE(movingSpy.size(), 0);
+ QCOMPARE(moveStartedSpy.size(), 0);
+ QCOMPARE(moveEndedSpy.size(), 0);
+ QCOMPARE(fflickingSpy.size(), 0);
+ QCOMPARE(fflickStartedSpy.size(), 0);
+ QCOMPARE(fflickEndedSpy.size(), 0);
// no further moves after the initial move beyond threshold
QTest::mouseRelease(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(53,100));
- QTRY_COMPARE(fflickingSpy.count(), 2);
- QTRY_COMPARE(fflickStartedSpy.count(), 1);
- QCOMPARE(fflickEndedSpy.count(), 1);
+ QTRY_COMPARE(fflickingSpy.size(), 2);
+ QTRY_COMPARE(fflickStartedSpy.size(), 1);
+ QCOMPARE(fflickEndedSpy.size(), 1);
// PathView should not handle this
- QTRY_COMPARE(movingSpy.count(), 0);
- QTRY_COMPARE(moveEndedSpy.count(), 0);
- QCOMPARE(moveStartedSpy.count(), 0);
+ QTRY_COMPARE(movingSpy.size(), 0);
+ QTRY_COMPARE(moveEndedSpy.size(), 0);
+ QCOMPARE(moveStartedSpy.size(), 0);
}
void tst_QQuickPathView::jsArrayChange()
@@ -2523,11 +2482,11 @@ void tst_QQuickPathView::jsArrayChange()
}
view->setModel(QVariant::fromValue(array1));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
// no change
view->setModel(QVariant::fromValue(array2));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
void tst_QQuickPathView::qtbug37815()
@@ -2536,8 +2495,7 @@ void tst_QQuickPathView::qtbug37815()
window->setSource(testFileUrl("qtbug37815.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
// cache items will be created async. Let's wait...
QTest::qWait(1000);
@@ -2548,7 +2506,8 @@ void tst_QQuickPathView::qtbug37815()
const int pathItemCount = pathView->pathItemCount();
const int cacheItemCount = pathView->cacheItemCount();
int totalCount = 0;
- foreach (QQuickItem *item, pathView->childItems()) {
+ const auto childItems = pathView->childItems();
+ for (QQuickItem *item : childItems) {
if (item->objectName().startsWith(QLatin1String("delegate")))
++totalCount;
}
@@ -2567,8 +2526,7 @@ void tst_QQuickPathView::qtbug42716()
window->setSource(testFileUrl("qtbug42716.qml"));
window->show();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathView = findItem<QQuickPathView>(window->rootObject(), "pathView");
QVERIFY(pathView != nullptr);
@@ -2609,8 +2567,7 @@ void tst_QQuickPathView::qtbug53464()
window->setSource(testFileUrl("qtbug53464.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathView = findItem<QQuickPathView>(window->rootObject(), "pathView");
QVERIFY(pathView != nullptr);
@@ -2619,7 +2576,8 @@ void tst_QQuickPathView::qtbug53464()
const int pathItemCount = pathView->pathItemCount();
int totalCount = 0;
- foreach (QQuickItem *item, pathView->childItems()) {
+ const auto childItems = pathView->childItems();
+ for (QQuickItem *item : childItems) {
if (item->objectName().startsWith(QLatin1String("delegate")))
++totalCount;
}
@@ -2684,12 +2642,10 @@ void tst_QQuickPathView::movementDirection()
QFETCH(qreal, tooffset);
QScopedPointer<QQuickView> window(createView());
- QQuickViewTestUtil::moveMouseAway(window.data());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
window->setSource(testFileUrl("movementDirection.qml"));
window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window.data()));
- QCOMPARE(window.data(), qGuiApp->focusWindow());
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
QQuickPathView *pathview = window->rootObject()->findChild<QQuickPathView*>("view");
QVERIFY(pathview != nullptr);
@@ -2742,7 +2698,7 @@ void tst_QQuickPathView::objectModelMove()
QVector<QString> itemObjectNames;
itemObjectNames << QLatin1String("red") << QLatin1String("green") << QLatin1String("blue");
QVector<QQuickItem*> childItems;
- for (const QString &itemObjectName : qAsConst(itemObjectNames)) {
+ for (const QString &itemObjectName : std::as_const(itemObjectNames)) {
QQuickItem *childItem = findItem<QQuickItem>(pathView, itemObjectName);
QVERIFY(childItem);
childItems.append(childItem);
@@ -2755,7 +2711,7 @@ void tst_QQuickPathView::objectModelMove()
QTRY_VERIFY(pathView.isNull());
// By this point, all of its cached items should have been released,
// which means none of the items should have any listeners.
- for (const auto childItem : qAsConst(childItems)) {
+ for (const auto childItem : std::as_const(childItems)) {
const QQuickItemPrivate *childItemPrivate = QQuickItemPrivate::get(childItem);
QCOMPARE(childItemPrivate->changeListeners.size(), 0);
}
@@ -2779,7 +2735,6 @@ void tst_QQuickPathView::requiredPropertiesInDelegate()
}
{
QScopedPointer<QQuickView> window(createView());
- QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression("Writing to \"name\" broke the binding to the underlying model"));
window->setSource(testFileUrl("delegateWithRequiredProperties.3.qml"));
window->show();
QTRY_VERIFY(window->rootObject()->property("working").toBool());
@@ -2796,6 +2751,253 @@ void tst_QQuickPathView::requiredPropertiesInDelegatePreventUnrelated()
window->show();
}
+void tst_QQuickPathView::touchMove()
+{
+ QScopedPointer<QQuickView> window(createView());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
+ window->setSource(testFileUrl("dragpath.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
+ QVERIFY(pathview != nullptr);
+
+ QSignalSpy movingSpy(pathview, SIGNAL(movingChanged()));
+ QSignalSpy moveStartedSpy(pathview, SIGNAL(movementStarted()));
+ QSignalSpy moveEndedSpy(pathview, SIGNAL(movementEnded()));
+ QSignalSpy draggingSpy(pathview, SIGNAL(draggingChanged()));
+ QSignalSpy dragStartedSpy(pathview, SIGNAL(dragStarted()));
+ QSignalSpy dragEndedSpy(pathview, SIGNAL(dragEnded()));
+ QSignalSpy flickStartedSpy(pathview, SIGNAL(flickStarted()));
+ QSignalSpy flickEndedSpy(pathview, SIGNAL(flickEnded()));
+
+ int current = pathview->currentIndex();
+
+ // touch move from left to right
+ QPoint from(250, 100);
+ QPoint to(10, 100);
+
+ QTest::touchEvent(window.data(), touchDevice.data()).press(0, from, window.data());
+ QQuickTouchUtils::flush(window.data());
+
+ QVERIFY(!pathview->isMoving());
+ QVERIFY(!pathview->isDragging());
+ QCOMPARE(movingSpy.size(), 0);
+ QCOMPARE(moveStartedSpy.size(), 0);
+ QCOMPARE(moveEndedSpy.size(), 0);
+ QCOMPARE(draggingSpy.size(), 0);
+ QCOMPARE(dragStartedSpy.size(), 0);
+ QCOMPARE(dragEndedSpy.size(), 0);
+ QCOMPARE(flickStartedSpy.size(), 0);
+ QCOMPARE(flickEndedSpy.size(), 0);
+
+ from -= QPoint(QGuiApplication::styleHints()->startDragDistance() + 1, 0);
+ QTest::touchEvent(window.data(), touchDevice.data()).move(0, from, window.data());
+ QQuickTouchUtils::flush(window.data());
+
+ // first move does not trigger move/drag
+ QVERIFY(!pathview->isMoving());
+ QVERIFY(!pathview->isDragging());
+ QCOMPARE(movingSpy.size(), 0);
+ QCOMPARE(moveStartedSpy.size(), 0);
+ QCOMPARE(moveEndedSpy.size(), 0);
+ QCOMPARE(draggingSpy.size(), 0);
+ QCOMPARE(dragStartedSpy.size(), 0);
+ QCOMPARE(dragEndedSpy.size(), 0);
+ QCOMPARE(flickStartedSpy.size(), 0);
+ QCOMPARE(flickEndedSpy.size(), 0);
+
+ QPoint diff = from - to;
+ int moveCount = 4;
+ for (int i = 1; i <= moveCount; ++i) {
+ QTest::touchEvent(window.data(), touchDevice.data()).move(0, from - i * diff / moveCount, window.data());
+ QQuickTouchUtils::flush(window.data());
+
+ QVERIFY(pathview->isMoving());
+ QVERIFY(pathview->isDragging());
+ QCOMPARE(movingSpy.size(), 1);
+ QCOMPARE(moveStartedSpy.size(), 1);
+ QCOMPARE(moveEndedSpy.size(), 0);
+ QCOMPARE(draggingSpy.size(), 1);
+ QCOMPARE(dragStartedSpy.size(), 1);
+ QCOMPARE(dragEndedSpy.size(), 0);
+ QCOMPARE(flickStartedSpy.size(), 0);
+ QCOMPARE(flickEndedSpy.size(), 0);
+ }
+ QVERIFY(pathview->currentIndex() != current);
+
+ QTest::touchEvent(window.data(), touchDevice.data()).release(0, to, window.data());
+ QQuickTouchUtils::flush(window.data());
+
+ QVERIFY(pathview->isMoving());
+ QVERIFY(!pathview->isDragging());
+ QCOMPARE(movingSpy.size(), 1);
+ QCOMPARE(moveStartedSpy.size(), 1);
+ QCOMPARE(moveEndedSpy.size(), 0);
+ QCOMPARE(draggingSpy.size(), 2);
+ QCOMPARE(dragStartedSpy.size(), 1);
+ QCOMPARE(dragEndedSpy.size(), 1);
+ QCOMPARE(flickStartedSpy.size(), 1);
+ QCOMPARE(flickEndedSpy.size(), 0);
+
+ // Wait for the flick to finish
+ QVERIFY(QTest::qWaitFor([&]()
+ { return !pathview->isFlicking(); }
+ ));
+ QVERIFY(!pathview->isMoving());
+ QVERIFY(!pathview->isDragging());
+ QCOMPARE(movingSpy.size(), 2);
+ QCOMPARE(moveStartedSpy.size(), 1);
+ QCOMPARE(moveEndedSpy.size(), 1);
+ QCOMPARE(draggingSpy.size(), 2);
+ QCOMPARE(dragStartedSpy.size(), 1);
+ QCOMPARE(dragEndedSpy.size(), 1);
+ QCOMPARE(flickStartedSpy.size(), 1);
+ QCOMPARE(flickEndedSpy.size(), 1);
+
+}
+
+void tst_QQuickPathView::mousePressAfterFlick() // QTBUG-115121
+{
+ QScopedPointer<QQuickView> window(createView());
+ QQuickVisualTestUtils::moveMouseAway(window.data());
+ window->setSource(testFileUrl("mousePressAfterFlick.qml"));
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QQuickPathView *pathview = window->rootObject()->findChild<QQuickPathView *>("pathView");
+ QVERIFY(pathview != nullptr);
+
+ QQuickMouseArea *mouseArea = window->rootObject()->findChild<QQuickMouseArea *>("rootMouseArea");
+ QVERIFY(mouseArea != nullptr);
+
+ QSignalSpy flickingSpy(pathview, SIGNAL(flickingChanged()));
+ QSignalSpy flickStartedSpy(pathview, SIGNAL(flickStarted()));
+ QSignalSpy flickEndedSpy(pathview, SIGNAL(flickEnded()));
+
+ QSignalSpy pressedSpy(mouseArea, &QQuickMouseArea::pressed);
+
+ flickingSpy.clear();
+ flickStartedSpy.clear();
+ flickEndedSpy.clear();
+
+ // Dragging the child mouse area should animate the PathView (MA has no drag target)
+ QPoint from = QPoint((window->width() / 2), (window->height() * 3 / 4));
+ QPoint to = QPoint((window->width() / 2), (window->height() / 4));
+ flick(window.data(), from, to, 100);
+ QVERIFY(pathview->isMoving());
+ QCOMPARE(flickingSpy.size(), 1);
+ QCOMPARE(flickStartedSpy.size(), 1);
+ QCOMPARE(flickEndedSpy.size(), 0);
+
+ // Now while it's still moving, click it.
+ // The PathView should stop at a position
+ QTest::mouseClick(window.data(), Qt::LeftButton, Qt::NoModifier, QPoint(window->width() / 2, window->height() / 4));
+ QTRY_VERIFY(!pathview->isMoving());
+ QCOMPARE(flickEndedSpy.size(), 1);
+ QCOMPARE(pressedSpy.size(), 0);
+}
+
+void tst_QQuickPathView::qtbug90479()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("qtbug90479.qml"));
+
+ window->show();
+ qApp->processEvents();
+
+ QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
+ QVERIFY(pathview);
+
+ // cache items will be created async. Let's wait...
+ QTest::qWait(1000);
+
+ // Should create just pathItemCount amount and not destroy any
+ QCOMPARE(pathview->property("delegatesCreated").toInt(), 6);
+ QCOMPARE(pathview->property("delegatesDestroyed").toInt(), 0);
+}
+
+void tst_QQuickPathView::overCached()
+{
+ QScopedPointer<QQuickView> window(createView());
+ window->setSource(testFileUrl("overcached.qml"));
+
+ window->show();
+ qApp->processEvents();
+
+ QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
+ QVERIFY(pathview);
+
+ // cache items will be created async. Let's wait...
+ QTest::qWait(1000);
+
+ // Should create max model + 1 amount with the current implementation
+ QVERIFY(pathview->property("delegatesCreated").toInt() <= 16);
+ QVERIFY(pathview->property("delegatesDestroyed").toInt() <= 1);
+}
+
+class CustomModel : public QAbstractListModel
+{
+public:
+ CustomModel(QObject *parent = 0) : QAbstractListModel(parent) {
+ m_values << 0 << 1 << 2 << 3 << 4;
+ }
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const {
+ Q_UNUSED(parent);
+ return m_values.count();
+ }
+ QVariant data(const QModelIndex &index, int role) const {
+ if (index.row() < 0 || m_values.count() <= index.row())
+ return QVariant();
+
+ return m_values[index.row()];
+ }
+
+ Q_INVOKABLE void shrink() {
+ beginResetModel();
+ m_values.takeLast();
+ m_values.takeLast();
+ endResetModel();
+ }
+
+private:
+ QList<int> m_values;
+};
+
+void tst_QQuickPathView::qtbug46487()
+{
+ QScopedPointer<QQuickView> window(createView());
+
+ CustomModel* model = new CustomModel;
+ QQmlContext *ctxt = window->rootContext();
+ ctxt->setContextProperty("customModel", model);
+
+ window->setSource(testFileUrl("qtbug46487.qml"));
+ window->show();
+ qApp->processEvents();
+
+ QQuickPathView *pathview = qobject_cast<QQuickPathView*>(window->rootObject());
+ QVERIFY(pathview);
+
+ QTest::qWait(500);
+
+ // Should create just pathItemCount amount and not destroy any
+ QCOMPARE(pathview->count(), 5);
+ QCOMPARE(pathview->property("delegatesCreated").toInt(), 5);
+ QCOMPARE(pathview->property("delegatesDestroyed").toInt(), 0);
+
+ // Resets the model and removes 2 items.
+ model->shrink();
+ QTest::qWait(500);
+
+ // Should destroy previous items (begin/endResetModel) and
+ // (re)create 3 new items.
+ QCOMPARE(pathview->count(), 3);
+ QCOMPARE(pathview->property("delegatesCreated").toInt(), 5 + 3);
+ QCOMPARE(pathview->property("delegatesDestroyed").toInt(), 5);
+}
+
QTEST_MAIN(tst_QQuickPathView)
#include "tst_qquickpathview.moc"
diff --git a/tests/auto/quick/qquickpincharea/CMakeLists.txt b/tests/auto/quick/qquickpincharea/CMakeLists.txt
index 4f417366a1..4d0af2d3a0 100644
--- a/tests/auto/quick/qquickpincharea/CMakeLists.txt
+++ b/tests/auto/quick/qquickpincharea/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickpincharea.pro.
#####################################################################
## tst_qquickpincharea Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickpincharea LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickpincharea
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickpincharea.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,10 +37,10 @@ qt_internal_add_test(tst_qquickpincharea
qt_internal_extend_target(tst_qquickpincharea CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickpincharea CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickpincharea/data/draggablePinchArea.qml b/tests/auto/quick/qquickpincharea/data/draggablePinchArea.qml
new file mode 100644
index 0000000000..3acf67b4b6
--- /dev/null
+++ b/tests/auto/quick/qquickpincharea/data/draggablePinchArea.qml
@@ -0,0 +1,70 @@
+import QtQuick 2.12
+
+Rectangle {
+ id: root
+ width: 600
+ height: 600
+
+ Rectangle {
+ objectName: "paContainer"
+ width: parent.width -100
+ height: parent.height - 100
+ border.color: "black"
+ anchors.centerIn: parent
+ transformOrigin: Item.Center
+
+ Rectangle {
+ width: 300
+ height: 300
+ color: "tomato"
+ PinchArea {
+ id: pa
+ anchors.fill: parent
+ pinch.target: parent
+ pinch.minimumScale: 0.5
+ pinch.maximumScale: 2
+ pinch.minimumRotation: -360
+ pinch.maximumRotation: 360
+ pinch.dragAxis: Pinch.XAndYAxis
+ pinch.minimumX: -100
+ pinch.maximumX: 300
+ pinch.minimumY: -100
+ pinch.maximumY: 300
+ }
+
+
+ Text { text: "this way up" }
+ }
+ }
+
+ // only for touch feedback / troubleshooting
+ Item {
+ id: glassPane
+ z: 10000
+ anchors.fill: parent
+
+ PointHandler {
+ id: ph1
+ target: Rectangle {
+ parent: glassPane
+ color: "green"
+ visible: ph1.active
+ x: ph1.point.position.x - width / 2
+ y: ph1.point.position.y - height / 2
+ width: 20; height: width; radius: width / 2
+ }
+ }
+
+ PointHandler {
+ id: ph2
+ target: Rectangle {
+ parent: glassPane
+ color: "blue"
+ visible: ph2.active
+ x: ph2.point.position.x - width / 2
+ y: ph2.point.position.y - height / 2
+ width: 20; height: width; radius: width / 2
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickpincharea/data/pinchAreaInPathView.qml b/tests/auto/quick/qquickpincharea/data/pinchAreaInPathView.qml
new file mode 100644
index 0000000000..dc909c2c7c
--- /dev/null
+++ b/tests/auto/quick/qquickpincharea/data/pinchAreaInPathView.qml
@@ -0,0 +1,48 @@
+import QtQuick
+
+PathView {
+ width: 600
+ height: 200
+
+ model: 3
+ delegate: Rectangle {
+ width: 200
+ height: 200
+ color: "salmon"
+ opacity: PathView.isCurrentItem ? 1 : 0.5
+
+ property alias pinchArea: pinchArea
+
+ Text {
+ text: "Test"
+ font.pixelSize: 100
+ anchors.fill: parent
+ fontSizeMode: Text.Fit
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ PinchArea {
+ id: pinchArea
+ anchors.fill: parent
+ pinch.target: parent
+ pinch.dragAxis: Pinch.XAndYAxis
+ pinch.minimumScale: 1.0
+ pinch.maximumScale: 5.0
+
+ onPinchFinished: (pinch) => {
+ parent.scale = 1
+ parent.x = 0
+ parent.y = 0
+ }
+ }
+ }
+ path: Path {
+ startX: 100
+ startY: 100
+ PathLine {
+ x: 700
+ y: 100
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickpincharea/data/pinchproperties.qml b/tests/auto/quick/qquickpincharea/data/pinchproperties.qml
index 899c6380da..42096d0b77 100644
--- a/tests/auto/quick/qquickpincharea/data/pinchproperties.qml
+++ b/tests/auto/quick/qquickpincharea/data/pinchproperties.qml
@@ -31,18 +31,18 @@ Rectangle {
pinch.maximumScale: 2.0
pinch.minimumRotation: 0.0
pinch.maximumRotation: 90.0
- onPinchStarted: {
+ onPinchStarted: (pinch) => {
whiteRect.center = pinch.center
whiteRect.scale = pinch.scale
whiteRect.pointCount = pinch.pointCount;
whiteRect.pinchActive = true;
}
- onPinchUpdated: {
+ onPinchUpdated: (pinch) => {
whiteRect.center = pinch.center
whiteRect.scale = pinch.scale
whiteRect.pointCount = pinch.pointCount;
}
- onPinchFinished: {
+ onPinchFinished: (pinch) => {
whiteRect.center = pinch.center
whiteRect.scale = pinch.scale
whiteRect.pointCount = pinch.pointCount;
diff --git a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
index a9f35e8727..1bab22c4e2 100644
--- a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
+++ b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
@@ -1,48 +1,29 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+#include <QtCore/private/qvariantanimation_p.h>
#include <QtTest/QtTest>
#include <QtTest/QSignalSpy>
#include <QtGui/QStyleHints>
#include <QtGui/private/qevent_p.h>
+#include <QtGui/private/qeventpoint_p.h>
#include <qpa/qwindowsysteminterface.h>
#include <private/qquickpincharea_p.h>
+#include <QtQuick/private/qquickpathview_p.h>
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/qquickview.h>
#include <QtQml/qqmlcontext.h>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+
+using namespace QQuickVisualTestUtils;
class tst_QQuickPinchArea: public QQmlDataTest
{
Q_OBJECT
public:
- tst_QQuickPinchArea() { }
+ tst_QQuickPinchArea() : QQmlDataTest(QT_QMLTEST_DATADIR) { }
private slots:
void cleanupTestCase();
void pinchProperties();
@@ -52,6 +33,10 @@ private slots:
void cancel();
void transformedPinchArea_data();
void transformedPinchArea();
+ void dragTransformedPinchArea_data();
+ void dragTransformedPinchArea();
+ void pinchAreaKeepsDragInView();
+ void pinchInPathView();
private:
QQuickView *createView();
@@ -82,18 +67,18 @@ void tst_QQuickPinchArea::pinchProperties()
QVERIFY(rootItem != nullptr);
QSignalSpy targetSpy(pinch, SIGNAL(targetChanged()));
pinch->setTarget(rootItem);
- QCOMPARE(targetSpy.count(),1);
+ QCOMPARE(targetSpy.size(),1);
pinch->setTarget(rootItem);
- QCOMPARE(targetSpy.count(),1);
+ QCOMPARE(targetSpy.size(),1);
// axis
QCOMPARE(pinch->axis(), QQuickPinch::XAndYAxis);
QSignalSpy axisSpy(pinch, SIGNAL(dragAxisChanged()));
pinch->setAxis(QQuickPinch::XAxis);
QCOMPARE(pinch->axis(), QQuickPinch::XAxis);
- QCOMPARE(axisSpy.count(),1);
+ QCOMPARE(axisSpy.size(),1);
pinch->setAxis(QQuickPinch::XAxis);
- QCOMPARE(axisSpy.count(),1);
+ QCOMPARE(axisSpy.size(),1);
// minimum and maximum drag properties
QSignalSpy xminSpy(pinch, SIGNAL(minimumXChanged()));
@@ -116,20 +101,20 @@ void tst_QQuickPinchArea::pinchProperties()
QCOMPARE(pinch->ymin(), 10.0);
QCOMPARE(pinch->ymax(), 10.0);
- QCOMPARE(xminSpy.count(),1);
- QCOMPARE(xmaxSpy.count(),1);
- QCOMPARE(yminSpy.count(),1);
- QCOMPARE(ymaxSpy.count(),1);
+ QCOMPARE(xminSpy.size(),1);
+ QCOMPARE(xmaxSpy.size(),1);
+ QCOMPARE(yminSpy.size(),1);
+ QCOMPARE(ymaxSpy.size(),1);
pinch->setXmin(10);
pinch->setXmax(10);
pinch->setYmin(10);
pinch->setYmax(10);
- QCOMPARE(xminSpy.count(),1);
- QCOMPARE(xmaxSpy.count(),1);
- QCOMPARE(yminSpy.count(),1);
- QCOMPARE(ymaxSpy.count(),1);
+ QCOMPARE(xminSpy.size(),1);
+ QCOMPARE(xmaxSpy.size(),1);
+ QCOMPARE(yminSpy.size(),1);
+ QCOMPARE(ymaxSpy.size(),1);
// minimum and maximum scale properties
QSignalSpy scaleMinSpy(pinch, SIGNAL(minimumScaleChanged()));
@@ -144,14 +129,14 @@ void tst_QQuickPinchArea::pinchProperties()
QCOMPARE(pinch->minimumScale(), 0.5);
QCOMPARE(pinch->maximumScale(), 1.5);
- QCOMPARE(scaleMinSpy.count(),1);
- QCOMPARE(scaleMaxSpy.count(),1);
+ QCOMPARE(scaleMinSpy.size(),1);
+ QCOMPARE(scaleMaxSpy.size(),1);
pinch->setMinimumScale(0.5);
pinch->setMaximumScale(1.5);
- QCOMPARE(scaleMinSpy.count(),1);
- QCOMPARE(scaleMaxSpy.count(),1);
+ QCOMPARE(scaleMinSpy.size(),1);
+ QCOMPARE(scaleMaxSpy.size(),1);
// minimum and maximum rotation properties
QSignalSpy rotMinSpy(pinch, SIGNAL(minimumRotationChanged()));
@@ -166,22 +151,22 @@ void tst_QQuickPinchArea::pinchProperties()
QCOMPARE(pinch->minimumRotation(), -90.0);
QCOMPARE(pinch->maximumRotation(), 45.0);
- QCOMPARE(rotMinSpy.count(),1);
- QCOMPARE(rotMaxSpy.count(),1);
+ QCOMPARE(rotMinSpy.size(),1);
+ QCOMPARE(rotMaxSpy.size(),1);
pinch->setMinimumRotation(-90.0);
pinch->setMaximumRotation(45.0);
- QCOMPARE(rotMinSpy.count(),1);
- QCOMPARE(rotMaxSpy.count(),1);
+ QCOMPARE(rotMinSpy.size(),1);
+ QCOMPARE(rotMaxSpy.size(),1);
}
-QMutableEventPoint makeTouchPoint(int id, QPoint p, QQuickView *v, QQuickItem *i)
+QEventPoint makeTouchPoint(int id, QPoint p, QQuickView *v, QQuickItem *i)
{
- QMutableEventPoint touchPoint(id);
- touchPoint.setPosition(i->mapFromScene(p));
- touchPoint.setGlobalPosition(v->mapToGlobal(p));
- touchPoint.setScenePosition(p);
+ QEventPoint touchPoint(id);
+ QMutableEventPoint::setPosition(touchPoint, i->mapFromScene(p));
+ QMutableEventPoint::setGlobalPosition(touchPoint, v->mapToGlobal(p));
+ QMutableEventPoint::setScenePosition(touchPoint, p);
return touchPoint;
}
@@ -406,7 +391,7 @@ void tst_QQuickPinchArea::retouch()
pinchSequence.move(0, p1,window).move(1, p2,window).commit();
QQuickTouchUtils::flush(window);
- QCOMPARE(startedSpy.count(), 1);
+ QCOMPARE(startedSpy.size(), 1);
QCOMPARE(root->property("scale").toReal(), 1.5);
QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50
@@ -414,15 +399,15 @@ void tst_QQuickPinchArea::retouch()
QCOMPARE(window->rootObject()->property("pointCount").toInt(), 2);
- QCOMPARE(startedSpy.count(), 1);
- QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(startedSpy.size(), 1);
+ QCOMPARE(finishedSpy.size(), 0);
// Hold down the first finger but release the second one
pinchSequence.stationary(0).release(1, p2, window).commit();
QQuickTouchUtils::flush(window);
- QCOMPARE(startedSpy.count(), 1);
- QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(startedSpy.size(), 1);
+ QCOMPARE(finishedSpy.size(), 0);
QCOMPARE(window->rootObject()->property("pointCount").toInt(), 1);
@@ -435,8 +420,8 @@ void tst_QQuickPinchArea::retouch()
QQuickTouchUtils::flush(window);
// Lifting and retouching results in onPinchStarted being called again
- QCOMPARE(startedSpy.count(), 2);
- QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(startedSpy.size(), 2);
+ QCOMPARE(finishedSpy.size(), 0);
QCOMPARE(window->rootObject()->property("pointCount").toInt(), 2);
@@ -444,8 +429,8 @@ void tst_QQuickPinchArea::retouch()
QQuickTouchUtils::flush(window);
QVERIFY(!root->property("pinchActive").toBool());
- QCOMPARE(startedSpy.count(), 2);
- QCOMPARE(finishedSpy.count(), 1);
+ QCOMPARE(startedSpy.size(), 2);
+ QCOMPARE(finishedSpy.size(), 1);
}
}
@@ -576,6 +561,198 @@ void tst_QQuickPinchArea::transformedPinchArea()
}
}
+void tst_QQuickPinchArea::dragTransformedPinchArea_data()
+{
+ QTest::addColumn<int>("rotation");
+ QTest::addColumn<QPoint>("p1");
+ QTest::addColumn<QPoint>("p2");
+ QTest::addColumn<QPoint>("delta");
+
+ QTest::newRow("unrotated")
+ << 0 << QPoint(100, 100) << QPoint(200, 100) << QPoint(40, 40);
+ QTest::newRow("20 deg")
+ << 20 << QPoint(100, 100) << QPoint(200, 100) << QPoint(40, 40);
+ QTest::newRow("90 deg")
+ << 90 << QPoint(100, 100) << QPoint(200, 100) << QPoint(0, 40);
+ QTest::newRow("180 deg")
+ << 180 << QPoint(100, 100) << QPoint(200, 100) << QPoint(40, 0);
+ QTest::newRow("225 deg")
+ << 210 << QPoint(200, 200) << QPoint(300, 200) << QPoint(80, 80);
+}
+
+void tst_QQuickPinchArea::dragTransformedPinchArea() // QTBUG-63673
+{
+ QFETCH(int, rotation);
+ QFETCH(QPoint, p1);
+ QFETCH(QPoint, p2);
+ QFETCH(QPoint, delta);
+ const int threshold = qApp->styleHints()->startDragDistance();
+
+ QQuickView *view = createView();
+ QScopedPointer<QQuickView> scope(view);
+ view->setSource(testFileUrl("draggablePinchArea.qml"));
+ view->show();
+ QVERIFY(QTest::qWaitForWindowExposed(view));
+ QVERIFY(view->rootObject());
+ QQuickPinchArea *pinchArea = view->rootObject()->findChild<QQuickPinchArea*>();
+ QVERIFY(pinchArea);
+ QQuickItem *pinchAreaTarget = pinchArea->parentItem();
+ QVERIFY(pinchAreaTarget);
+ QQuickItem *pinchAreaContainer = pinchAreaTarget->parentItem();
+ QVERIFY(pinchAreaContainer);
+ pinchAreaContainer->setRotation(rotation);
+
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(view, device);
+ // start pinch
+ pinchSequence.press(1, pinchArea->mapToScene(p1).toPoint(), view)
+ .press(2, pinchArea->mapToScene(p2).toPoint(), view).commit();
+ QQuickTouchUtils::flush(view);
+ pinchSequence.move(1, pinchArea->mapToScene(p1 + QPoint(threshold, threshold)).toPoint(), view)
+ .move(2, pinchArea->mapToScene(p2 + QPoint(threshold, threshold)).toPoint(), view).commit();
+ QQuickTouchUtils::flush(view);
+ pinchSequence.move(1, pinchArea->mapToScene(p1 + delta).toPoint(), view)
+ .move(2, pinchArea->mapToScene(p2 + delta).toPoint(), view).commit();
+ QQuickTouchUtils::flush(view);
+ QCOMPARE(pinchArea->pinch()->active(), true);
+ auto error = delta - QPoint(threshold, threshold) -
+ pinchAreaTarget->position().toPoint(); // expect 0, 0
+ QVERIFY(qAbs(error.x()) <= 1);
+ QVERIFY(qAbs(error.y()) <= 1);
+
+ // release pinch
+ pinchSequence.release(1, p1, view).release(2, p2, view).commit();
+ QQuickTouchUtils::flush(view);
+ QCOMPARE(pinchArea->pinch()->active(), false);
+}
+
+// QTBUG-105058
+void tst_QQuickPinchArea::pinchAreaKeepsDragInView()
+{
+ QQuickView view;
+ view.setSource(testFileUrl("pinchAreaInPathView.qml"));
+ QVERIFY(view.rootObject());
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickPathView *pathView = qobject_cast<QQuickPathView*>(view.rootObject());
+ QVERIFY(pathView);
+ QCOMPARE(pathView->count(), 3);
+
+ const QQuickItem *pinchDelegateItem = pathView->itemAtIndex(0);
+ QQuickPinchArea *pinchArea = pinchDelegateItem->property("pinchArea").value<QQuickPinchArea*>();
+ QVERIFY(pinchArea);
+
+ // Press.
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(&view, device);
+ QPoint point1Start = { 80, 120 };
+ QPoint point2Start = { 120, 80 };
+ const int dragThreshold = qApp->styleHints()->startDragDistance();
+ pinchSequence.press(1, pinchArea->mapToScene(point1Start).toPoint(), &view)
+ .press(2, pinchArea->mapToScene(point2Start).toPoint(), &view).commit();
+ QQuickTouchUtils::flush(&view);
+
+ // Move past the drag threshold to begin the pinch.
+ const int steps = 30;
+ QPoint point1End = point1Start + QPoint(-dragThreshold, dragThreshold);
+ QPoint point2End = point2Start + QPoint(dragThreshold, -dragThreshold);
+
+ forEachStep(steps, [&](qreal progress) {
+ pinchSequence.move(1, lerpPoints(point1Start, point1End, progress), &view)
+ .move(2, lerpPoints(point2Start, point2End, progress), &view).commit();
+ QQuickTouchUtils::flush(&view);
+ QTest::qWait(5);
+ });
+ QCOMPARE(pinchArea->pinch()->active(), true);
+ QVERIFY2(pinchDelegateItem->scale() > 1.0, qPrintable(QString::number(pinchDelegateItem->scale())));
+ // The PathView contents shouldn't have moved.
+ QCOMPARE(pathView->offset(), 0);
+
+ // Release a touch point.
+ pinchSequence.stationary(1).release(2, point2End, &view).commit();
+ QQuickTouchUtils::flush(&view);
+
+ // Press it again.
+ pinchSequence.stationary(1).press(2, point2End, &view).commit();
+ QQuickTouchUtils::flush(&view);
+ QCOMPARE(pinchArea->pinch()->active(), true);
+
+ // Drag to the right; the PathView still shouldn't move.
+ point1Start = point1End;
+ point2Start = point2End;
+ point1End = point1Start + QPoint(100, 0);
+ point2End = point2Start + QPoint(100, 0);
+ forEachStep(steps, [&](qreal progress) {
+ pinchSequence.move(1, lerpPoints(point1Start, point1End, progress), &view)
+ .move(2, lerpPoints(point2Start, point2End, progress), &view).commit();
+ QQuickTouchUtils::flush(&view);
+ QTest::qWait(5);
+ });
+ QCOMPARE(pinchArea->pinch()->active(), true);
+ QVERIFY2(pinchDelegateItem->scale() > 1.0, qPrintable(QString::number(pinchDelegateItem->scale())));
+ QCOMPARE(pathView->offset(), 0);
+
+ // Release pinch.
+ pinchSequence.release(1, point1End, &view).release(2, point2End, &view).commit();
+ QQuickTouchUtils::flush(&view);
+ QCOMPARE(pinchArea->pinch()->active(), false);
+ QCOMPARE(pathView->offset(), 0);
+}
+
+void tst_QQuickPinchArea::pinchInPathView()
+{
+ QQuickView view;
+ view.setSource(testFileUrl("pinchAreaInPathView.qml"));
+ QVERIFY(view.rootObject());
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickPathView *pathView = qobject_cast<QQuickPathView*>(view.rootObject());
+ QVERIFY(pathView);
+ QCOMPARE(pathView->count(), 3);
+
+ const QQuickItem *pinchDelegateItem = pathView->itemAtIndex(0);
+ QQuickPinchArea *pinchArea = pinchDelegateItem->property("pinchArea").value<QQuickPinchArea*>();
+ QVERIFY(pinchArea);
+
+ // press
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(&view, device);
+ QPoint point1Start = { 10, 10 };
+ QPoint point2Start = { 100, 100 };
+ const int dragThreshold = qApp->styleHints()->startDragDistance();
+ pinchSequence.press(0, point1Start, &view)
+ .press(1, point2Start, &view)
+ .commit();
+ QQuickTouchUtils::flush(&view);
+ QTest::qWait(20);
+
+ // move
+ QPoint moveDistance = QPoint(dragThreshold * 3, dragThreshold * 3);
+ QPoint point2End = point2Start + moveDistance;
+ pinchSequence.stationary(0)
+ .move(1, point2End, &view)
+ .commit();
+ QQuickTouchUtils::flush(&view);
+ QTest::qWait(20);
+
+ point2End += moveDistance;
+ pinchSequence.stationary(0)
+ .move(1, point2End, &view)
+ .commit();
+ QQuickTouchUtils::flush(&view);
+ QTest::qWait(20);
+
+ QCOMPARE(pinchArea->pinch()->active(), true);
+ QVERIFY2(pinchDelegateItem->scale() > 1.0, qPrintable(QString::number(pinchDelegateItem->scale())));
+ // PathView shouldn't have moved.
+ QCOMPARE(pathView->offset(), 0);
+
+ // release pinch.
+ pinchSequence.release(0, point1Start, &view).release(1, point2End, &view).commit();
+ QQuickTouchUtils::flush(&view);
+ QCOMPARE(pinchArea->pinch()->active(), false);
+ QCOMPARE(pathView->offset(), 0);
+}
+
QQuickView *tst_QQuickPinchArea::createView()
{
QQuickView *window = new QQuickView(nullptr);
diff --git a/tests/auto/quick/qquickpixmapcache/BLACKLIST b/tests/auto/quick/qquickpixmapcache/BLACKLIST
new file mode 100644
index 0000000000..00d8eb5619
--- /dev/null
+++ b/tests/auto/quick/qquickpixmapcache/BLACKLIST
@@ -0,0 +1,3 @@
+# QTBUG-118064
+[slowDevice]
+*
diff --git a/tests/auto/quick/qquickpixmapcache/CMakeLists.txt b/tests/auto/quick/qquickpixmapcache/CMakeLists.txt
index e50a6eb6a8..97735172f2 100644
--- a/tests/auto/quick/qquickpixmapcache/CMakeLists.txt
+++ b/tests/auto/quick/qquickpixmapcache/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickpixmapcache.pro.
#####################################################################
## tst_qquickpixmapcache Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickpixmapcache LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,19 +21,16 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickpixmapcache
SOURCES
- ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h
- ../../shared/util.cpp ../../shared/util.h
tst_qquickpixmapcache.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
- Qt::Concurrent
+ deviceloadingimage.h deviceloadingimage.cpp
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -33,10 +39,20 @@ qt_internal_add_test(tst_qquickpixmapcache
qt_internal_extend_target(tst_qquickpixmapcache CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickpixmapcache CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+)
+
+qt_internal_extend_target(tst_qquickpixmapcache CONDITION QT_FEATURE_concurrent
+ LIBRARIES
+ Qt::Concurrent
+)
+
+qt_policy(SET QTP0001 NEW)
+qt_add_qml_module(tst_qquickpixmapcache
+ URI PixmapCacheTest
)
diff --git a/tests/auto/quick/qquickpixmapcache/data/tableViewWithDeviceLoadingImages.qml b/tests/auto/quick/qquickpixmapcache/data/tableViewWithDeviceLoadingImages.qml
new file mode 100644
index 0000000000..68119ac1a9
--- /dev/null
+++ b/tests/auto/quick/qquickpixmapcache/data/tableViewWithDeviceLoadingImages.qml
@@ -0,0 +1,45 @@
+import QtQuick
+import PixmapCacheTest
+
+TableView {
+ id: root
+ width: 640
+ height: 480
+ model: 100
+ rowSpacing: 6
+ property real size: 40
+ columnWidthProvider: function(col) { return root.size }
+ rowHeightProvider: function(col) { return root.size }
+
+ Timer {
+ interval: 200
+ repeat: true
+ running: true
+ onTriggered: {
+ root.size = Math.random() * 200
+ root.positionViewAtRow(Math.round(Math.random() * 100), TableView.Visible)
+ }
+ }
+
+ delegate: DeviceLoadingImage {
+ required property int index
+ width: root.size; height: root.size
+ asynchronous: true
+ source: "image://slow/" + index
+ sourceSize.width: width
+ sourceSize.height: height
+
+ Rectangle {
+ anchors.fill: parent
+ color: "transparent"
+ border.color: "red"
+ }
+
+ Text {
+ color: "red"
+ style: Text.Outline
+ styleColor: "white"
+ text: index + "\nsize " + root.size.toFixed(1)
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickpixmapcache/deviceloadingimage.cpp b/tests/auto/quick/qquickpixmapcache/deviceloadingimage.cpp
new file mode 100644
index 0000000000..72a956d1d2
--- /dev/null
+++ b/tests/auto/quick/qquickpixmapcache/deviceloadingimage.cpp
@@ -0,0 +1,43 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "deviceloadingimage.h"
+
+#include <QtQuick/private/qquickimage_p_p.h>
+
+Q_DECLARE_LOGGING_CATEGORY(lcTests)
+
+void DeviceLoadingImage::load()
+{
+ auto *d = static_cast<QQuickImagePrivate *>(QQuickImagePrivate::get(this));
+ static int thisRequestFinished = -1;
+ if (thisRequestFinished == -1) {
+ thisRequestFinished =
+ QQuickImageBase::staticMetaObject.indexOfSlot("requestFinished()");
+ }
+ const QQmlContext *context = qmlContext(this);
+ Q_ASSERT(context);
+ QUrl resolved = context->resolvedUrl(d->url);
+ device = std::make_unique<QFile>(resolved.toLocalFile());
+ d->pix.loadImageFromDevice(qmlEngine(this), device.get(), context->resolvedUrl(d->url),
+ d->sourceClipRect.toRect(), d->sourcesize * d->devicePixelRatio,
+ QQuickImageProviderOptions(), d->currentFrame, d->frameCount);
+
+ qCDebug(lcTests) << "loading page" << d->currentFrame << "of" << d->frameCount << "status" << d->pix.status();
+
+ switch (d->pix.status()) {
+ case QQuickPixmap::Ready:
+ pixmapChange();
+ break;
+ case QQuickPixmap::Loading:
+ d->pix.connectFinished(this, thisRequestFinished);
+ if (d->status != Loading) {
+ d->status = Loading;
+ emit statusChanged(d->status);
+ }
+ break;
+ default:
+ qCWarning(lcTests) << "unexpected status" << d->pix.status();
+ break;
+ }
+}
diff --git a/tests/auto/quick/qquickpixmapcache/deviceloadingimage.h b/tests/auto/quick/qquickpixmapcache/deviceloadingimage.h
new file mode 100644
index 0000000000..062f51d16f
--- /dev/null
+++ b/tests/auto/quick/qquickpixmapcache/deviceloadingimage.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtCore/QFile>
+#include <QtQuick/private/qquickimage_p.h>
+
+class DeviceLoadingImage : public QQuickImage
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(DeviceLoadingImage)
+
+public:
+ DeviceLoadingImage(QQuickItem *parent = nullptr) : QQuickImage(parent) { }
+
+protected:
+ void load() override;
+
+ std::unique_ptr<QFile> device;
+};
diff --git a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
index 13a3378905..fce9bba0c6 100644
--- a/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
+++ b/tests/auto/quick/qquickpixmapcache/tst_qquickpixmapcache.cpp
@@ -1,52 +1,58 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtTest/QtTest>
#include <QtQuick/private/qquickpixmapcache_p.h>
#include <QtQml/qqmlengine.h>
#include <QtQuick/qquickimageprovider.h>
+#include <QtQuick/qquickview.h>
#include <QtQml/QQmlComponent>
#include <QNetworkReply>
-#include "../../shared/util.h"
-#include "testhttpserver.h"
+#include <QtGui/qpainter.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/testhttpserver_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
#if QT_CONFIG(concurrent)
#include <qtconcurrentrun.h>
#include <qfuture.h>
#endif
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+
+class SlowProvider : public QQuickImageProvider
+{
+public:
+ SlowProvider() : QQuickImageProvider(Pixmap) {}
+
+ QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize) override
+ {
+ const int row = id.toInt();
+ qCDebug(lcTests) << requestCount << QThread::currentThread() << "row" << row << requestedSize;
+ QPixmap image(requestedSize);
+ QPainter painter(&image);
+ const QColor c(128, row % 8 * 32, 64);
+ painter.fillRect(0, 0, requestedSize.width(), requestedSize.height(), c);
+ if (size)
+ *size = requestedSize;
+ ++requestCount;
+ QThread::currentThread()->msleep(row);
+ return image;
+ }
+
+ int requestCount = 0;
+};
+Q_DECLARE_METATYPE(SlowProvider*);
+
+QT_BEGIN_NAMESPACE
+
#define PIXMAP_DATA_LEAK_TEST 0
class tst_qquickpixmapcache : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickpixmapcache() {}
+ tst_qquickpixmapcache() : QQmlDataTest(QT_QMLTEST_DATADIR) {}
private slots:
void initTestCase() override;
@@ -66,6 +72,7 @@ private slots:
#if PIXMAP_DATA_LEAK_TEST
void dataLeak();
#endif
+ void slowDevice();
private:
QQmlEngine engine;
TestHTTPServer server;
@@ -228,7 +235,7 @@ void tst_qquickpixmapcache::parallel()
QList<bool> pending;
QList<Slotter*> getters;
- for (int i=0; i<targets.count(); ++i) {
+ for (int i=0; i<targets.size(); ++i) {
QUrl target = targets.at(i);
QQuickPixmap *pixmap = new QQuickPixmap;
@@ -248,9 +255,9 @@ void tst_qquickpixmapcache::parallel()
}
}
- if (incache + slotters != targets.count())
+ if (incache + slotters != targets.size())
QFAIL(QString::fromLatin1("pixmap counts don't add up: %1 incache, %2 slotters, %3 total")
- .arg(incache).arg(slotters).arg(targets.count()).toLatin1().constData());
+ .arg(incache).arg(slotters).arg(targets.size()).toLatin1().constData());
if (cancel >= 0) {
pixmaps.at(cancel)->clear(getters[cancel]);
@@ -262,7 +269,7 @@ void tst_qquickpixmapcache::parallel()
QVERIFY(!QTestEventLoop::instance().timeout());
}
- for (int i=0; i<targets.count(); ++i) {
+ for (int i=0; i<targets.size(); ++i) {
QQuickPixmap *pixmap = pixmaps[i];
if (i == cancel) {
@@ -417,6 +424,9 @@ void tst_qquickpixmapcache::lockingCrash()
void tst_qquickpixmapcache::uncached()
{
+#ifdef Q_OS_WEBOS
+ QSKIP("QQuickPixmap always loads with QQuickPixmap::Cache option in webOS");
+#endif
QQmlEngine engine;
engine.addImageProvider(QLatin1String("mypixmaps"), new MyPixmapProvider);
@@ -472,7 +482,6 @@ void tst_qquickpixmapcache::asynchronousNoCache()
QScopedPointer<QObject> root {component.create()}; // should not crash
}
-
#if PIXMAP_DATA_LEAK_TEST
// This test should not be enabled by default as it
// produces spurious output in the expected case.
@@ -482,9 +491,9 @@ class DataLeakView : public QQuickView
Q_OBJECT
public:
- explicit DataLeakView() : QQuickView()
+ explicit DataLeakView(const QUrl &src) : QQuickView()
{
- setSource(testFileUrl("dataLeak.qml"));
+ setSource(src);
}
void showFor2Seconds()
@@ -502,14 +511,14 @@ Q_GLOBAL_STATIC(QQuickPixmap, dataLeakPixmap)
void tst_qquickpixmapcache::dataLeak()
{
// Should not leak cached QQuickPixmapData.
- // Unfortunately, since the QQuickPixmapStore
- // is a global static, and it releases the cache
+ // Unfortunately, since the QQuickPixmapCache
+ // is a singleton, and it releases the cache
// entries on dtor (application exit), we must use
- // valgrind to determine whether it leaks or not.
+ // valgrind or ASAN to determine whether it leaks or not.
QQuickPixmap *p1 = new QQuickPixmap;
QQuickPixmap *p2 = new QQuickPixmap;
{
- QScopedPointer<DataLeakView> test(new DataLeakView);
+ QScopedPointer<DataLeakView> test(new DataLeakView(testFileUrl("dataLeak.qml")));
test->showFor2Seconds();
dataLeakPixmap()->load(test->engine(), testFileUrl("exists.png"));
p1->load(test->engine(), testFileUrl("exists.png"));
@@ -519,12 +528,45 @@ void tst_qquickpixmapcache::dataLeak()
// When the (global static) dataLeakPixmap is deleted, it
// shouldn't attempt to dereference a QQuickPixmapData
- // which has been deleted by the QQuickPixmapStore
+ // which has been deleted by the QQuickPixmapCache
// destructor.
}
#endif
#undef PIXMAP_DATA_LEAK_TEST
+/*!
+ Test lots of async QQuickPixmap::loadImageFromDevice() jobs with random
+ sizes and frames, so that cached images are seldom reused. Some jobs get
+ cancelled, some succeed. This should not lead to any cache leaks.
+ Similar to the QtPdf usecase in QTBUG-114953
+*/
+void tst_qquickpixmapcache::slowDevice()
+{
+#ifdef QT_BUILD_INTERNAL
+ auto *provider = new SlowProvider;
+ engine.addImageProvider("slow", provider); // takes ownership
+
+ {
+ QQuickView window(&engine, nullptr);
+ QVERIFY(QQuickTest::showView(window, testFileUrl("tableViewWithDeviceLoadingImages.qml")));
+ // Timer generates 5 requests / sec; TableView shows multiple delegates (depending on size);
+ // so we should get 100 requests in some fraction of 20 sec. Give it 30 to be sure.
+ QTRY_COMPARE_GE_WITH_TIMEOUT(provider->requestCount, 100, 30000);
+ const int cacheCount = QQuickPixmapCache::instance()->m_cache.size();
+ qCDebug(lcTests) << "cached pixmaps" << cacheCount;
+ QCOMPARE_GT(cacheCount, 0);
+ } // window goes out of scope: all QQuickPixmapData instances should be eventually unreferenced
+
+ QTRY_COMPARE(QQuickPixmapCache::instance()->referencedCost(), 0);
+ const int leakedPixmaps = QQuickPixmapCache::instance()->destroyCache();
+ QCOMPARE(leakedPixmaps, 0);
+#else
+ QSKIP("This test relies on private APIs that are only exported in developer-builds");
+#endif
+}
+
+QT_END_NAMESPACE
+
QTEST_MAIN(tst_qquickpixmapcache)
#include "tst_qquickpixmapcache.moc"
diff --git a/tests/auto/quick/qquickpositioners/CMakeLists.txt b/tests/auto/quick/qquickpositioners/CMakeLists.txt
index e72958c6cd..fb046e3d45 100644
--- a/tests/auto/quick/qquickpositioners/CMakeLists.txt
+++ b/tests/auto/quick/qquickpositioners/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickpositioners.pro.
#####################################################################
## tst_qquickpositioners Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickpositioners LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,22 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickpositioners
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickpositioners.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
Qt::QuickTest
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -36,10 +38,10 @@ qt_internal_add_test(tst_qquickpositioners
qt_internal_extend_target(tst_qquickpositioners CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickpositioners CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
index 3885dd4a9a..c250fbf554 100644
--- a/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
+++ b/tests/auto/quick/qquickpositioners/tst_qquickpositioners.cpp
@@ -1,45 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#include <QtTest/QtTest>
#include <QtQuick/qquickview.h>
#include <qqmlengine.h>
+#include <QtQml/qqmlcomponent.h>
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/private/qquickpositioners_p.h>
#include <QtQuick/private/qquicktransition_p.h>
#include <QtQuickTest/QtQuickTest>
#include <private/qquickitem_p.h>
#include <qqmlexpression.h>
-#include "../shared/viewtestutil.h"
-#include "../shared/visualtestutil.h"
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
-using namespace QQuickViewTestUtil;
-using namespace QQuickVisualTestUtil;
+using namespace QQuickViewTestUtils;
+using namespace QQuickVisualTestUtils;
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
@@ -306,6 +283,7 @@ void tst_qquickpositioners::moveTransitions_flow_data()
}
tst_qquickpositioners::tst_qquickpositioners()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
@@ -1023,7 +1001,7 @@ void tst_qquickpositioners::populateTransitions(const QString &positionerObjectN
QaimModel model_targetItems_transitionFrom;
QaimModel model_displacedItems_transitionVia;
- QScopedPointer<QQuickView> window(QQuickViewTestUtil::createView());
+ QScopedPointer<QQuickView> window(QQuickViewTestUtils::createView());
window->setInitialProperties({
{"usePopulateTransition", usePopulateTransition},
@@ -1064,7 +1042,7 @@ void tst_qquickpositioners::populateTransitions(const QString &positionerObjectN
QTRY_COMPARE(window->rootObject()->property("populateTransitionsDone").toInt(), 0);
QTRY_COMPARE(window->rootObject()->property("addTransitionsDone").toInt(), model.count());
} else {
- QVERIFY(QQuickTest::qWaitForItemPolished(positioner));
+ QVERIFY(QQuickTest::qWaitForPolish(positioner));
QTRY_COMPARE(window->rootObject()->property("populateTransitionsDone").toInt(), 0);
QTRY_COMPARE(window->rootObject()->property("addTransitionsDone").toInt(), 0);
}
@@ -1111,7 +1089,7 @@ void tst_qquickpositioners::addTransitions(const QString &positionerObjectName)
QaimModel model_targetItems_transitionFrom;
QaimModel model_displacedItems_transitionVia;
- QScopedPointer<QQuickView> window(QQuickViewTestUtil::createView());
+ QScopedPointer<QQuickView> window(QQuickViewTestUtils::createView());
window->setInitialProperties({
{"usePopulateTransition", QVariant(false)},
{"enableAddTransition", QVariant(true)},
@@ -1131,7 +1109,7 @@ void tst_qquickpositioners::addTransitions(const QString &positionerObjectName)
QQuickItem *positioner = window->rootObject()->findChild<QQuickItem*>(positionerObjectName);
QVERIFY(positioner);
positioner->findChild<QQuickItem*>("repeater")->setProperty("model", QVariant::fromValue(&model));
- QVERIFY(QQuickTest::qWaitForItemPolished(positioner));
+ QVERIFY(QQuickTest::qWaitForPolish(positioner));
for (int i = 0; i < initialItemCount; i++)
model.addItem("Original item" + QString::number(i), "");
@@ -1172,7 +1150,7 @@ void tst_qquickpositioners::addTransitions(const QString &positionerObjectName)
targetItems = findItems<QQuickItem>(positioner, "wrapper", targetIndexes);
- QTRY_COMPARE(window->rootObject()->property("addTransitionsDone").toInt(), targetData.count());
+ QTRY_COMPARE(window->rootObject()->property("addTransitionsDone").toInt(), targetData.size());
QTRY_COMPARE(window->rootObject()->property("displaceTransitionsDone").toInt(), expectedDisplacedIndexes.count());
// check the target and displaced items were animated
@@ -1235,7 +1213,7 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName)
QaimModel model_targetItems_transitionFrom;
QaimModel model_displacedItems_transitionVia;
- QScopedPointer<QQuickView> window(QQuickViewTestUtil::createView());
+ QScopedPointer<QQuickView> window(QQuickViewTestUtils::createView());
window->setInitialProperties({
{"usePopulateTransition", QVariant(false)},
{"enableAddTransition", QVariant(false)},
@@ -1257,7 +1235,7 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName)
QQuickItem *positioner = window->rootObject()->findChild<QQuickItem*>(positionerObjectName);
QVERIFY(positioner);
positioner->findChild<QQuickItem*>("repeater")->setProperty("model", QVariant::fromValue(&model));
- QVERIFY(QQuickTest::qWaitForItemPolished(positioner));
+ QVERIFY(QQuickTest::qWaitForPolish(positioner));
switch (change.type) {
case ListChange::Removed:
@@ -1266,12 +1244,12 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName)
break;
case ListChange::Moved:
model.moveItems(change.index, change.to, change.count);
- QVERIFY(QQuickTest::qWaitForItemPolished(positioner));
+ QVERIFY(QQuickTest::qWaitForPolish(positioner));
break;
case ListChange::Inserted:
case ListChange::SetCurrent:
case ListChange::SetContentY:
- QVERIFY(false);
+ QFAIL("Wrong change type");
break;
case ListChange::Polish:
break;
@@ -1285,9 +1263,9 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName)
model_displacedItems_transitionVia.matchAgainst(expectedDisplacedValues, "wasn't animated with displaced anim", "shouldn't have been animated with displaced anim");
// check attached properties
- QCOMPARE(window->rootObject()->property("targetTrans_items").toMap().count(), 0);
- QCOMPARE(window->rootObject()->property("targetTrans_targetIndexes").toList().count(), 0);
- QCOMPARE(window->rootObject()->property("targetTrans_targetItems").toList().count(), 0);
+ QCOMPARE(window->rootObject()->property("targetTrans_items").toMap().size(), 0);
+ QCOMPARE(window->rootObject()->property("targetTrans_targetIndexes").toList().size(), 0);
+ QCOMPARE(window->rootObject()->property("targetTrans_targetItems").toList().size(), 0);
if (expectedDisplacedIndexes.isValid()) {
// adjust expectedDisplacedIndexes to their final values after the move
QList<int> displacedIndexes;
@@ -1298,16 +1276,16 @@ void tst_qquickpositioners::moveTransitions(const QString &positionerObjectName)
else if (change.type == ListChange::Removed)
displacedIndexes = adjustIndexesForRemoveDisplaced(expectedDisplacedIndexes.indexes, change.index, change.count);
else
- QVERIFY(false);
+ QFAIL("Wrong change type");
matchItemsAndIndexes(window->rootObject()->property("displacedTrans_items").toMap(), model, displacedIndexes);
QVariantList listOfEmptyIntLists;
- for (int i=0; i<displacedIndexes.count(); i++)
+ for (int i=0; i<displacedIndexes.size(); i++)
listOfEmptyIntLists << QVariant::fromValue(QList<int>());
QCOMPARE(window->rootObject()->property("displacedTrans_targetIndexes").toList(), listOfEmptyIntLists);
QVariantList listOfEmptyObjectLists;
- for (int i=0; i<displacedIndexes.count(); i++)
- listOfEmptyObjectLists.insert(listOfEmptyObjectLists.count(), QVariantList());
+ for (int i=0; i<displacedIndexes.size(); i++)
+ listOfEmptyObjectLists.insert(listOfEmptyObjectLists.size(), QVariantList());
QCOMPARE(window->rootObject()->property("displacedTrans_targetItems").toList(), listOfEmptyObjectLists);
}
@@ -1351,7 +1329,7 @@ void tst_qquickpositioners::checkItemPositions(QQuickItem *positioner, QaimModel
for (int i=0; i<model->count(); ++i) {
QQuickItem *item = findItem<QQuickItem>(positioner, "wrapper", i);
- QVERIFY2(item, QTest::toString(QString("Item %1 not found").arg(i)));
+ QVERIFY2(item, qPrintable(QString("Item %1 not found").arg(i)));
QCOMPARE(item->width(), currentSize);
QCOMPARE(item->height(), currentSize);
@@ -2961,35 +2939,37 @@ void tst_qquickpositioners::test_propertychanges()
grid->setMove(rowTransition);
QCOMPARE(grid->add(), rowTransition);
QCOMPARE(grid->move(), rowTransition);
- QCOMPARE(addSpy.count(),1);
- QCOMPARE(moveSpy.count(),1);
+ QCOMPARE(addSpy.size(),1);
+ QCOMPARE(moveSpy.size(),1);
grid->setAdd(rowTransition);
grid->setMove(rowTransition);
- QCOMPARE(addSpy.count(),1);
- QCOMPARE(moveSpy.count(),1);
+ QCOMPARE(addSpy.size(),1);
+ QCOMPARE(moveSpy.size(),1);
grid->setAdd(nullptr);
grid->setMove(nullptr);
- QCOMPARE(addSpy.count(),2);
- QCOMPARE(moveSpy.count(),2);
+ QCOMPARE(addSpy.size(),2);
+ QCOMPARE(moveSpy.size(),2);
grid->setColumns(-1);
grid->setRows(3);
QCOMPARE(grid->columns(), -1);
QCOMPARE(grid->rows(), 3);
- QCOMPARE(columnsSpy.count(),1);
- QCOMPARE(rowsSpy.count(),1);
+ QCOMPARE(columnsSpy.size(),1);
+ QCOMPARE(rowsSpy.size(),1);
grid->setColumns(-1);
grid->setRows(3);
- QCOMPARE(columnsSpy.count(),1);
- QCOMPARE(rowsSpy.count(),1);
+ QCOMPARE(columnsSpy.size(),1);
+ QCOMPARE(rowsSpy.size(),1);
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*QML Grid: Grid contains more visible items \\(20\\) than rows\\*columns \\(6\\)"));
grid->setColumns(2);
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*QML Grid: Grid contains more visible items \\(20\\) than rows\\*columns \\(4\\)"));
grid->setRows(2);
- QCOMPARE(columnsSpy.count(),2);
- QCOMPARE(rowsSpy.count(),2);
+ QCOMPARE(columnsSpy.size(),2);
+ QCOMPARE(rowsSpy.size(),2);
}
@@ -3778,7 +3758,7 @@ void tst_qquickpositioners::test_mirroring()
QList<QString> objectNames;
objectNames << "one" << "two" << "three" << "four" << "five";
- foreach (const QString qmlFile, qmlFiles) {
+ for (const QString &qmlFile : std::as_const(qmlFiles)) {
QScopedPointer<QQuickView> windowA(createView(testFile(qmlFile)));
QQuickItem *rootA = qobject_cast<QQuickItem*>(windowA->rootObject());
@@ -3791,7 +3771,7 @@ void tst_qquickpositioners::test_mirroring()
rootA->setProperty("testRightToLeft", true); // layoutDirection: Qt.RightToLeft
// LTR != RTL
- foreach (const QString objectName, objectNames) {
+ for (const QString &objectName : std::as_const(objectNames)) {
// horizontal.qml and horizontal-padding.qml only have three items
if (qmlFile.startsWith(QString("horizontal")) && objectName == QString("four"))
break;
@@ -3806,7 +3786,7 @@ void tst_qquickpositioners::test_mirroring()
inheritProp.write(true);
// RTL == mirror
- foreach (const QString objectName, objectNames) {
+ for (const QString &objectName : std::as_const(objectNames)) {
// horizontal.qml and horizontal-padding.qml only have three items
if (qmlFile.startsWith(QString("horizontal")) && objectName == QString("four"))
break;
@@ -3819,7 +3799,7 @@ void tst_qquickpositioners::test_mirroring()
QQuickItem *positionerB = itemB->parentItem();
positionerA->setWidth(positionerA->width() * 2);
positionerB->setWidth(positionerB->width() * 2);
- QVERIFY(QQuickTest::qWaitForItemPolished(positionerA) && QQuickTest::qWaitForItemPolished(positionerB));
+ QVERIFY(QQuickTest::qWaitForPolish(positionerA) && QQuickTest::qWaitForPolish(positionerB));
QTRY_COMPARE(itemA->x(), itemB->x());
}
@@ -3827,7 +3807,7 @@ void tst_qquickpositioners::test_mirroring()
rootB->setProperty("testRightToLeft", true); // layoutDirection: Qt.RightToLeft
// LTR == RTL + mirror
- foreach (const QString objectName, objectNames) {
+ for (const QString &objectName : std::as_const(objectNames)) {
// horizontal.qml and horizontal-padding.qml only have three items
if (qmlFile.startsWith(QString("horizontal")) && objectName == QString("four"))
break;
@@ -4033,7 +4013,7 @@ QQuickView *tst_qquickpositioners::createView(const QString &filename, bool wait
void tst_qquickpositioners::matchIndexLists(const QVariantList &indexLists, const QList<int> &expectedIndexes)
{
const QSet<int> expectedIndexSet(expectedIndexes.cbegin(), expectedIndexes.cend());
- for (int i=0; i<indexLists.count(); i++) {
+ for (int i=0; i<indexLists.size(); i++) {
const auto &currentList = indexLists[i].value<QList<int> >();
const QSet<int> current(currentList.cbegin(), currentList.cend());
if (current != expectedIndexSet)
@@ -4048,25 +4028,25 @@ void tst_qquickpositioners::matchItemsAndIndexes(const QVariantMap &items, const
QCOMPARE(it.value().typeId(), QMetaType::Int);
QString name = it.key();
int itemIndex = it.value().toInt();
- QVERIFY2(expectedIndexes.contains(itemIndex), QTest::toString(QString("Index %1 not found in expectedIndexes").arg(itemIndex)));
+ QVERIFY2(expectedIndexes.contains(itemIndex), qPrintable(QString("Index %1 not found in expectedIndexes").arg(itemIndex)));
if (model.name(itemIndex) != name)
qDebug() << itemIndex;
QCOMPARE(model.name(itemIndex), name);
}
- QCOMPARE(items.count(), expectedIndexes.count());
+ QCOMPARE(items.size(), expectedIndexes.size());
}
void tst_qquickpositioners::matchItemLists(const QVariantList &itemLists, const QList<QQuickItem *> &expectedItems)
{
- for (int i=0; i<itemLists.count(); i++) {
+ for (int i=0; i<itemLists.size(); i++) {
QCOMPARE(itemLists[i].typeId(), QMetaType::QVariantList);
QVariantList current = itemLists[i].toList();
- for (int j=0; j<current.count(); j++) {
+ for (int j=0; j<current.size(); j++) {
QQuickItem *o = qobject_cast<QQuickItem*>(current[j].value<QObject*>());
- QVERIFY2(o, QTest::toString(QString("Invalid actual item at %1").arg(j)));
- QVERIFY2(expectedItems.contains(o), QTest::toString(QString("Cannot match item %1").arg(j)));
+ QVERIFY2(o, qPrintable(QString("Invalid actual item at %1").arg(j)));
+ QVERIFY2(expectedItems.contains(o), qPrintable(QString("Cannot match item %1").arg(j)));
}
- QCOMPARE(current.count(), expectedItems.count());
+ QCOMPARE(current.size(), expectedItems.size());
}
}
diff --git a/tests/auto/quick/qquickrectangle/CMakeLists.txt b/tests/auto/quick/qquickrectangle/CMakeLists.txt
index 5ccb12a3f7..2d12b1df71 100644
--- a/tests/auto/quick/qquickrectangle/CMakeLists.txt
+++ b/tests/auto/quick/qquickrectangle/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickrectangle.pro.
#####################################################################
## tst_qquickrectangle Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickrectangle LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickrectangle
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickrectangle.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,10 +37,10 @@ qt_internal_add_test(tst_qquickrectangle
qt_internal_extend_target(tst_qquickrectangle CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickrectangle CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickrectangle/data/multi-radius.qml b/tests/auto/quick/qquickrectangle/data/multi-radius.qml
new file mode 100644
index 0000000000..18c74a2dd9
--- /dev/null
+++ b/tests/auto/quick/qquickrectangle/data/multi-radius.qml
@@ -0,0 +1,27 @@
+import QtQuick
+
+Item {
+ property alias firstRectangle: r1
+ property alias secondRectangle: r2
+ property alias thirdRectangle: r3
+ Rectangle {
+ id: r1
+ anchors.fill: parent
+ radius: 5
+ topLeftRadius: 10
+ bottomRightRadius: 2
+ }
+ Rectangle {
+ id: r2
+ anchors.fill: parent
+ radius: 5
+ topRightRadius: 10
+ bottomLeftRadius: 2
+ }
+ Rectangle {
+ id: r3
+ anchors.fill: parent
+ radius: 5
+ }
+}
+
diff --git a/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp b/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp
index 536280337a..4472be7d17 100644
--- a/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp
+++ b/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtTest/QSignalSpy>
@@ -35,7 +10,7 @@
#include <private/qquickitem_p.h>
#include <private/qquickrectangle_p.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
class tst_qquickrectangle : public QQmlDataTest
{
@@ -51,17 +26,23 @@ private slots:
void gradient_multiple();
void gradient_preset();
void antialiasing();
+ void multiRadius();
private:
QQmlEngine engine;
};
tst_qquickrectangle::tst_qquickrectangle()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
void tst_qquickrectangle::color()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("Test does not work on Android because of QTBUG-102345");
+#endif
+
if (QGuiApplication::primaryScreen()->depth() < 24)
QSKIP("This test does not work at display depths < 24");
@@ -71,9 +52,8 @@ void tst_qquickrectangle::color()
QVERIFY(QTest::qWaitForWindowExposed(&view));
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimal platforms", Abort);
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
QImage image = view.grabWindow();
QVERIFY(image.pixel(0,0) == QColor("#020202").rgba());
@@ -96,7 +76,7 @@ void tst_qquickrectangle::gradient()
QCOMPARE(stops.at(&stops, 1)->color(), QColor("white"));
QGradientStops gradientStops = grad->gradientStops();
- QCOMPARE(gradientStops.count(), 2);
+ QCOMPARE(gradientStops.size(), 2);
QCOMPARE(gradientStops.at(0).first, 0.0);
QCOMPARE(gradientStops.at(0).second, QColor("gray"));
QCOMPARE(gradientStops.at(1).first, 1.0);
@@ -210,46 +190,122 @@ void tst_qquickrectangle::antialiasing()
rect->setAntialiasing(true);
QCOMPARE(rect->antialiasing(), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
rect->setAntialiasing(true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
rect->resetAntialiasing();
QCOMPARE(rect->antialiasing(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
rect->setRadius(5);
QCOMPARE(rect->antialiasing(), true);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
rect->resetAntialiasing();
QCOMPARE(rect->antialiasing(), true);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
rect->setRadius(0);
QCOMPARE(rect->antialiasing(), false);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
rect->resetAntialiasing();
QCOMPARE(rect->antialiasing(), false);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
rect->setRadius(5);
QCOMPARE(rect->antialiasing(), true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
rect->resetAntialiasing();
QCOMPARE(rect->antialiasing(), true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
rect->setAntialiasing(false);
QCOMPARE(rect->antialiasing(), false);
- QCOMPARE(spy.count(), 6);
+ QCOMPARE(spy.size(), 6);
rect->resetAntialiasing();
QCOMPARE(rect->antialiasing(), true);
- QCOMPARE(spy.count(), 7);
+ QCOMPARE(spy.size(), 7);
+}
+
+void tst_qquickrectangle::multiRadius()
+{
+ QQuickView view;
+ view.setSource(testFileUrl("multi-radius.qml"));
+ view.show();
+
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickRectangle *firstRect = qobject_cast<QQuickRectangle*>(view.rootObject()->property("firstRectangle").value<QObject*>());
+ QQuickRectangle *secondRect = qobject_cast<QQuickRectangle*>(view.rootObject()->property("secondRectangle").value<QObject*>());
+ QQuickRectangle *thirdRect = qobject_cast<QQuickRectangle*>(view.rootObject()->property("thirdRectangle").value<QObject*>());
+ QVERIFY(firstRect);
+ QVERIFY(secondRect);
+ QVERIFY(thirdRect);
+
+ QCOMPARE(firstRect->topLeftRadius(), 10.);
+ QCOMPARE(firstRect->topRightRadius(), 5.);
+ QCOMPARE(firstRect->bottomLeftRadius(), 5.);
+ QCOMPARE(firstRect->bottomRightRadius(), 2.);
+
+ QSignalSpy spytl(firstRect, SIGNAL(topLeftRadiusChanged()));
+ QSignalSpy spytr(firstRect, SIGNAL(topRightRadiusChanged()));
+ QSignalSpy spybl(firstRect, SIGNAL(bottomLeftRadiusChanged()));
+ QSignalSpy spybr(firstRect, SIGNAL(bottomRightRadiusChanged()));
+
+ firstRect->setRadius(12);
+
+ QCOMPARE(firstRect->topLeftRadius(), 10.);
+ QCOMPARE(firstRect->topRightRadius(), 12.);
+ QCOMPARE(firstRect->bottomLeftRadius(), 12.);
+ QCOMPARE(firstRect->bottomRightRadius(), 2.);
+
+ QCOMPARE(spytl.size(), 0);
+ QCOMPARE(spytr.size(), 1);
+ QCOMPARE(spybl.size(), 1);
+ QCOMPARE(spybr.size(), 0);
+
+ firstRect->resetTopLeftRadius();
+ firstRect->resetBottomRightRadius();
+ QCOMPARE(firstRect->topRightRadius(), 12.);
+ QCOMPARE(firstRect->bottomLeftRadius(), 12.);
+
+ QCOMPARE(secondRect->topLeftRadius(), 5.);
+ QCOMPARE(secondRect->topRightRadius(), 10.);
+ QCOMPARE(secondRect->bottomLeftRadius(), 2.);
+ QCOMPARE(secondRect->bottomRightRadius(), 5.);
+
+ QSignalSpy spytl2(secondRect, SIGNAL(topLeftRadiusChanged()));
+ QSignalSpy spytr2(secondRect, SIGNAL(topRightRadiusChanged()));
+ QSignalSpy spybl2(secondRect, SIGNAL(bottomLeftRadiusChanged()));
+ QSignalSpy spybr2(secondRect, SIGNAL(bottomRightRadiusChanged()));
+
+ secondRect->setRadius(12);
+
+ QCOMPARE(secondRect->topLeftRadius(), 12.);
+ QCOMPARE(secondRect->topRightRadius(), 10.);
+ QCOMPARE(secondRect->bottomLeftRadius(), 2.);
+ QCOMPARE(secondRect->bottomRightRadius(), 12.);
+
+ QCOMPARE(spytl2.size(), 1);
+ QCOMPARE(spytr2.size(), 0);
+ QCOMPARE(spybl2.size(), 0);
+ QCOMPARE(spybr2.size(), 1);
+
+ secondRect->resetTopRightRadius();
+ secondRect->resetBottomLeftRadius();
+ QCOMPARE(secondRect->topRightRadius(), 12.);
+ QCOMPARE(secondRect->bottomLeftRadius(), 12.);
+
+ QCOMPARE(thirdRect->topLeftRadius(), 5.);
+ QCOMPARE(thirdRect->topRightRadius(), 5.);
+ QCOMPARE(thirdRect->bottomLeftRadius(), 5.);
+ QCOMPARE(thirdRect->bottomRightRadius(), 5.);
+
}
QTEST_MAIN(tst_qquickrectangle)
diff --git a/tests/auto/quick/qquickrendercontrol/BLACKLIST b/tests/auto/quick/qquickrendercontrol/BLACKLIST
new file mode 100644
index 0000000000..5c4846d821
--- /dev/null
+++ b/tests/auto/quick/qquickrendercontrol/BLACKLIST
@@ -0,0 +1,3 @@
+# QTBUG-103258
+[renderAndReadBackWithRhi]
+android
diff --git a/tests/auto/quick/qquickrendercontrol/CMakeLists.txt b/tests/auto/quick/qquickrendercontrol/CMakeLists.txt
index 46cfc1513c..3dd086f42b 100644
--- a/tests/auto/quick/qquickrendercontrol/CMakeLists.txt
+++ b/tests/auto/quick/qquickrendercontrol/CMakeLists.txt
@@ -1,21 +1,35 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickrendercontrol.pro.
#####################################################################
## tst_qquickrendercontrol Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickrendercontrol LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
qt_internal_add_test(tst_qquickrendercontrol
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickrendercontrol.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
)
#### Keys ignored in scope 1:.:.:qquickrendercontrol.pro:<TRUE>:
@@ -26,10 +40,10 @@ qt_internal_add_test(tst_qquickrendercontrol
qt_internal_extend_target(tst_qquickrendercontrol CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickrendercontrol CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickrendercontrol/data/rect.qml b/tests/auto/quick/qquickrendercontrol/data/rect.qml
index 5f58869fb5..bd4d7c15af 100644
--- a/tests/auto/quick/qquickrendercontrol/data/rect.qml
+++ b/tests/auto/quick/qquickrendercontrol/data/rect.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/qquickrendercontrol/data/rect_depth.qml b/tests/auto/quick/qquickrendercontrol/data/rect_depth.qml
new file mode 100644
index 0000000000..49709aa0ae
--- /dev/null
+++ b/tests/auto/quick/qquickrendercontrol/data/rect_depth.qml
@@ -0,0 +1,28 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Rectangle {
+ width: 200
+ height: 200
+ color: "steelblue"
+ Rectangle {
+ id: r
+ width: 150
+ height: 150
+ anchors.centerIn: parent
+ color: "palegreen"
+ NumberAnimation on rotation { from: 0; to: 360; duration: 5000; loops: -1 }
+ }
+ Rectangle {
+ width: 100
+ height: 100
+ color: "red"
+ z: -1 // not visible as it is completely below, but this only works if depth testing works (and there's a depth buffer) since these are opaque items
+ }
+ Text {
+ text: "Hello World\n\nrotation=" + Math.round(r.rotation)
+ anchors.centerIn: parent
+ }
+}
diff --git a/tests/auto/quick/qquickrendercontrol/tst_qquickrendercontrol.cpp b/tests/auto/quick/qquickrendercontrol/tst_qquickrendercontrol.cpp
index 539ac25adb..938f0a12b2 100644
--- a/tests/auto/quick/qquickrendercontrol/tst_qquickrendercontrol.cpp
+++ b/tests/auto/quick/qquickrendercontrol/tst_qquickrendercontrol.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
@@ -39,13 +14,12 @@
#include <QQmlEngine>
#include <QQmlComponent>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpa/qplatformintegration.h>
-#include <QtGui/private/qrhi_p.h>
-#include <QtQuick/private/qquickrendercontrol_p.h>
+#include <rhi/qrhi.h>
#if QT_CONFIG(vulkan)
#include <QVulkanInstance>
@@ -79,12 +53,16 @@ class tst_RenderControl : public QQmlDataTest
{
Q_OBJECT
+public:
+ tst_RenderControl();
+
private slots:
void initTestCase() override;
void cleanupTestCase();
void renderAndReadBackWithRhi_data();
void renderAndReadBackWithRhi();
void renderAndReadBackWithVulkanNative();
+ void renderAndReadBackWithVulkanAndCustomDepthTexture();
private:
#if QT_CONFIG(vulkan)
@@ -93,6 +71,11 @@ private:
AnimationDriver *animDriver;
};
+tst_RenderControl::tst_RenderControl()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
void tst_RenderControl::initTestCase()
{
QQmlDataTest::initTestCase();
@@ -122,28 +105,35 @@ void tst_RenderControl::renderAndReadBackWithRhi_data()
QTest::addColumn<QSGRendererInterface::GraphicsApi>("api");
#if QT_CONFIG(opengl)
- QTest::newRow("OpenGL") << QSGRendererInterface::OpenGLRhi;
+ QTest::newRow("OpenGL") << QSGRendererInterface::OpenGL;
#endif
#if QT_CONFIG(vulkan)
- QTest::newRow("Vulkan") << QSGRendererInterface::VulkanRhi;
+ QTest::newRow("Vulkan") << QSGRendererInterface::Vulkan;
#endif
#ifdef Q_OS_WIN
- if (QOperatingSystemVersion::current() > QOperatingSystemVersion::Windows7)
- QTest::newRow("D3D11") << QSGRendererInterface::Direct3D11Rhi;
+ QTest::newRow("D3D11") << QSGRendererInterface::Direct3D11;
+ QTest::newRow("D3D12") << QSGRendererInterface::Direct3D12;
#endif
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
- QTest::newRow("Metal") << QSGRendererInterface::MetalRhi;
+#if QT_CONFIG(metal)
+ QTest::newRow("Metal") << QSGRendererInterface::Metal;
#endif
}
void tst_RenderControl::renderAndReadBackWithRhi()
{
QFETCH(QSGRendererInterface::GraphicsApi, api);
+
#if QT_CONFIG(vulkan)
- if (api == QSGRendererInterface::VulkanRhi && !vulkanInstance.isValid())
+ if (api == QSGRendererInterface::Vulkan && !vulkanInstance.isValid())
QSKIP("Skipping Vulkan-based QRhi readback test due to failing to create a VkInstance");
#endif
+#ifdef Q_OS_ANDROID
+ // QTBUG-102780
+ if (api == QSGRendererInterface::Vulkan)
+ QSKIP("Vulkan-based rendering tests on Android are flaky.");
+#endif
+
// Changing the graphics api is not possible once a QQuickWindow et al is
// created, however we do support changing it once all QQuickWindow,
// QQuickRenderControl, etc. instances are destroyed, before creating new
@@ -154,7 +144,7 @@ void tst_RenderControl::renderAndReadBackWithRhi()
QScopedPointer<QQuickRenderControl> renderControl(new QQuickRenderControl);
QScopedPointer<QQuickWindow> quickWindow(new QQuickWindow(renderControl.data()));
#if QT_CONFIG(vulkan)
- if (api == QSGRendererInterface::VulkanRhi)
+ if (api == QSGRendererInterface::Vulkan)
quickWindow->setVulkanInstance(&vulkanInstance);
#endif
@@ -177,7 +167,8 @@ void tst_RenderControl::renderAndReadBackWithRhi()
QQuickItem *rootItem = qobject_cast<QQuickItem *>(rootObject);
QVERIFY(rootItem);
- QCOMPARE(rootItem->size(), QSize(200, 200));
+ static const QSize ITEM_SIZE = QSize(200, 200);
+ QCOMPARE(rootItem->size(), ITEM_SIZE);
quickWindow->contentItem()->setSize(rootItem->size());
quickWindow->setGeometry(0, 0, rootItem->width(), rootItem->height());
@@ -192,7 +183,7 @@ void tst_RenderControl::renderAndReadBackWithRhi()
// failed. The exception for now is OpenGL - that should (usually) work.
if (!initSuccess) {
#if QT_CONFIG(opengl)
- if (api != QSGRendererInterface::OpenGLRhi
+ if (api != QSGRendererInterface::OpenGL
|| !QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL))
#endif
{
@@ -204,13 +195,7 @@ void tst_RenderControl::renderAndReadBackWithRhi()
QCOMPARE(quickWindow->rendererInterface()->graphicsApi(), api);
- // What comes now is technically cheating - as long as QRhi is not a public
- // API this is not something applications can follow doing. However, it
- // allows us to test out the pipeline without having to write 4 different
- // native (Vulkan, Metal, D3D11, OpenGL) implementations of all what's below.
-
- QQuickRenderControlPrivate *rd = QQuickRenderControlPrivate::get(renderControl.data());
- QRhi *rhi = rd->rhi;
+ QRhi *rhi = renderControl->rhi();
Q_ASSERT(rhi);
const QSize size = rootItem->size().toSize();
@@ -218,9 +203,6 @@ void tst_RenderControl::renderAndReadBackWithRhi()
QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
QVERIFY(tex->create());
- // depth-stencil is mandatory with RHI, although strictly speaking the
- // scenegraph could operate without one, but it has no means to figure out
- // the lack of a ds buffer, so just be nice and provide one.
QScopedPointer<QRhiRenderBuffer> ds(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size, 1));
QVERIFY(ds->create());
@@ -244,9 +226,27 @@ void tst_RenderControl::renderAndReadBackWithRhi()
QVERIFY(tex->create()); // internally we now have a whole new native texture object
ds->setPixelSize(currentSize);
QVERIFY(ds->create());
- QVERIFY(texRt->create());
- // setRenderTarget is mandatory upon changing something, even if the texRt pointer itself is the same
- quickWindow->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(texRt.data()));
+
+ // Starting from Qt 6.3 we need neither a texRt->create() nor a
+ // quickWindow->setRenderTarget() here. Just recreating the
+ // internal native objects behing tex and ds should (must!) be
+ // functional on its own.
+
+ } else if (frame == 85) {
+ // like the above but now change the size radically so that we can
+ // test that rendering (viewports etc.) is corect.
+ currentSize = QSize(100, 100);
+ tex->setPixelSize(currentSize);
+ QVERIFY(tex->create());
+ ds->setPixelSize(currentSize);
+ QVERIFY(ds->create());
+ } else if (frame == 86) {
+ // reset to the default size
+ currentSize = ITEM_SIZE;
+ tex->setPixelSize(currentSize);
+ QVERIFY(tex->create());
+ ds->setPixelSize(currentSize);
+ QVERIFY(ds->create());
} else if (frame == 90) {
// Go berserk, destroy and recreate the texture and related stuff
// (the QRhi objects themselves, not just the native stuff
@@ -298,7 +298,7 @@ void tst_RenderControl::renderAndReadBackWithRhi()
};
QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch();
readbackBatch->readBackTexture(tex.data(), &readResult);
- rd->cb->resourceUpdate(readbackBatch);
+ renderControl->commandBuffer()->resourceUpdate(readbackBatch);
// our frame is done, submit
renderControl->endFrame();
@@ -321,24 +321,31 @@ void tst_RenderControl::renderAndReadBackWithRhi()
QVERIFY(qAbs(qGreen(background) - 130) < maxFuzz);
QVERIFY(qAbs(qBlue(background) - 180) < maxFuzz);
- background = img.pixel(195, 195);
- QVERIFY(qAbs(qRed(background) - 70) < maxFuzz);
- QVERIFY(qAbs(qGreen(background) - 130) < maxFuzz);
- QVERIFY(qAbs(qBlue(background) - 180) < maxFuzz);
+ // Frame 85 is where we resize to (100, 100), skip for that but from 86
+ // we will back to the proper (200, 200). If failures occur from frame
+ // 85 or - more likely - 86, that is likely because the
+ // scenegraph/QQuickWindow does not correctly pick up the render target
+ // size changes.
+ if (frame != 85) {
+ background = img.pixel(195, 195);
+ QVERIFY(qAbs(qRed(background) - 70) < maxFuzz);
+ QVERIFY(qAbs(qGreen(background) - 130) < maxFuzz);
+ QVERIFY(qAbs(qBlue(background) - 180) < maxFuzz);
- // after about 1.25 seconds (animation time, one iteration is 16 ms
- // thanks to our custom animation driver) the rectangle reaches a 90
- // degree rotation, that should be frame 76
- if (frame <= 2 || (frame >= 76 && frame <= 80)) {
- QRgb c = img.pixel(28, 28); // rectangle
- QVERIFY(qAbs(qRed(c) - 152) < maxFuzz);
- QVERIFY(qAbs(qGreen(c) - 251) < maxFuzz);
- QVERIFY(qAbs(qBlue(c) - 152) < maxFuzz);
- } else {
- QRgb c = img.pixel(28, 28); // background because rectangle got rotated so this pixel is not covered by it
- QVERIFY(qAbs(qRed(c) - 70) < maxFuzz);
- QVERIFY(qAbs(qGreen(c) - 130) < maxFuzz);
- QVERIFY(qAbs(qBlue(c) - 180) < maxFuzz);
+ // after about 1.25 seconds (animation time, one iteration is 16 ms
+ // thanks to our custom animation driver) the rectangle reaches a 90
+ // degree rotation, that should be frame 76
+ if (frame <= 2 || (frame >= 76 && frame <= 80)) {
+ QRgb c = img.pixel(28, 28); // rectangle
+ QVERIFY(qAbs(qRed(c) - 152) < maxFuzz);
+ QVERIFY(qAbs(qGreen(c) - 251) < maxFuzz);
+ QVERIFY(qAbs(qBlue(c) - 152) < maxFuzz);
+ } else {
+ QRgb c = img.pixel(28, 28); // background because rectangle got rotated so this pixel is not covered by it
+ QVERIFY(qAbs(qRed(c) - 70) < maxFuzz);
+ QVERIFY(qAbs(qGreen(c) - 130) < maxFuzz);
+ QVERIFY(qAbs(qBlue(c) - 180) < maxFuzz);
+ }
}
}
}
@@ -349,7 +356,7 @@ void tst_RenderControl::renderAndReadBackWithVulkanNative()
if (!vulkanInstance.isValid())
QSKIP("Skipping native Vulkan test due to failing to create a VkInstance");
- QQuickWindow::setGraphicsApi(QSGRendererInterface::VulkanRhi);
+ QQuickWindow::setGraphicsApi(QSGRendererInterface::Vulkan);
// We will create our own VkDevice and friends, which will then get used by
// Qt Quick as well (instead of creating its own objects), so this is a test
@@ -377,7 +384,7 @@ void tst_RenderControl::renderAndReadBackWithVulkanNative()
f->vkGetPhysicalDeviceQueueFamilyProperties(physDev, &queueCount, queueFamilyProps.data());
int gfxQueueFamilyIdx = -1;
- for (int i = 0; i < queueFamilyProps.count(); ++i) {
+ for (int i = 0; i < queueFamilyProps.size(); ++i) {
if (queueFamilyProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
gfxQueueFamilyIdx = i;
break;
@@ -655,21 +662,6 @@ void tst_RenderControl::renderAndReadBackWithVulkanNative()
QVERIFY(qAbs(qGreen(background) - 130) < maxFuzz);
QVERIFY(qAbs(qBlue(background) - 180) < maxFuzz);
- // after about 1.25 seconds (animation time, one iteration is 16 ms
- // thanks to our custom animation driver) the rectangle reaches a 90
- // degree rotation, that should be frame 76
- if (frame <= 2 || (frame >= 76 && frame <= 80)) {
- QRgb c = img.pixel(28, 28); // rectangle
- QVERIFY(qAbs(qRed(c) - 152) < maxFuzz);
- QVERIFY(qAbs(qGreen(c) - 251) < maxFuzz);
- QVERIFY(qAbs(qBlue(c) - 152) < maxFuzz);
- } else {
- QRgb c = img.pixel(28, 28); // background because rectangle got rotated so this pixel is not covered by it
- QVERIFY(qAbs(qRed(c) - 70) < maxFuzz);
- QVERIFY(qAbs(qGreen(c) - 130) < maxFuzz);
- QVERIFY(qAbs(qBlue(c) - 180) < maxFuzz);
- }
-
img = QImage();
df->vkUnmapMemory(dev, bufMem);
}
@@ -691,6 +683,151 @@ void tst_RenderControl::renderAndReadBackWithVulkanNative()
#endif
}
+void tst_RenderControl::renderAndReadBackWithVulkanAndCustomDepthTexture()
+{
+#if QT_CONFIG(vulkan)
+ if (!vulkanInstance.isValid())
+ QSKIP("Skipping native Vulkan test due to failing to create a VkInstance");
+
+ QQuickWindow::setGraphicsApi(QSGRendererInterface::Vulkan);
+
+#ifdef Q_OS_ANDROID
+ if (QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan)
+ QSKIP("Vulkan support is broken in Android emulator, skipping");
+#endif
+
+ QScopedPointer<QQuickRenderControl> renderControl(new QQuickRenderControl);
+ QScopedPointer<QQuickWindow> quickWindow(new QQuickWindow(renderControl.data()));
+
+ quickWindow->setVulkanInstance(&vulkanInstance);
+
+ QScopedPointer<QQmlEngine> qmlEngine(new QQmlEngine);
+ QScopedPointer<QQmlComponent> qmlComponent(new QQmlComponent(qmlEngine.data(),
+ testFileUrl(QLatin1String("rect_depth.qml"))));
+ QVERIFY(!qmlComponent->isLoading());
+ if (qmlComponent->isError()) {
+ for (const QQmlError &error : qmlComponent->errors())
+ qWarning() << error.url() << error.line() << error;
+ }
+ QVERIFY(!qmlComponent->isError());
+
+ QObject *rootObject = qmlComponent->create();
+ if (qmlComponent->isError()) {
+ for (const QQmlError &error : qmlComponent->errors())
+ qWarning() << error.url() << error.line() << error;
+ }
+ QVERIFY(!qmlComponent->isError());
+
+ QQuickItem *rootItem = qobject_cast<QQuickItem *>(rootObject);
+ QVERIFY(rootItem);
+ static const QSize ITEM_SIZE = QSize(200, 200);
+ QCOMPARE(rootItem->size(), ITEM_SIZE);
+
+ quickWindow->contentItem()->setSize(rootItem->size());
+ quickWindow->setGeometry(0, 0, rootItem->width(), rootItem->height());
+
+ rootItem->setParentItem(quickWindow->contentItem());
+
+ const bool initSuccess = renderControl->initialize();
+
+ if (!initSuccess)
+ QSKIP("Could not initialize graphics, perhaps unsupported graphics API, skipping");
+
+ QRhi *rhi = renderControl->rhi();
+ Q_ASSERT(rhi);
+
+ const QSize size = rootItem->size().toSize();
+ QScopedPointer<QRhiTexture> tex(rhi->newTexture(QRhiTexture::RGBA8, size, 1,
+ QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
+ QVERIFY(tex->create());
+
+ // In this test we use QRhiTexture to create resources but pull out the
+ // native VkImage and pass that in via fromVulkanImage(). This is to
+ // exercise additional features, such as setting a custom depth texture,
+ // which is not available (not relevant) when using fromRhiRenderTarget().
+ // In particular, this setup (fromVulkanImage + setDepthTexture) exercises
+ // what we get in Qt Quick 3D with OpenXR, where rendering happens into a
+ // XrSwapchain-provided color and depth texture. (granted, here we only
+ // exercise the non-multiview, non-MSAA case).
+
+ QScopedPointer<QRhiTexture> depthTex(rhi->newTexture(QRhiTexture::D24S8, size, 1, QRhiTexture::RenderTarget));
+ QVERIFY(depthTex->create());
+
+ QQuickRenderTarget rt = QQuickRenderTarget::fromVulkanImage(VkImage(tex->nativeTexture().object),
+ VkImageLayout(tex->nativeTexture().layout),
+ VK_FORMAT_R8G8B8A8_UNORM,
+ VK_FORMAT_R8G8B8A8_UNORM,
+ size,
+ 1,
+ 0,
+ {});
+ rt.setDepthTexture(depthTex.data());
+ quickWindow->setRenderTarget(rt);
+
+ QSize currentSize = size;
+
+ for (int frame = 0; frame < 100; ++frame) {
+ QCoreApplication::processEvents();
+
+ if (frame > 0)
+ animDriver->advance();
+
+ renderControl->polishItems();
+
+ renderControl->beginFrame();
+
+ renderControl->sync();
+ renderControl->render();
+
+ bool readCompleted = false;
+ QRhiReadbackResult readResult;
+ QImage result;
+ readResult.completed = [&readCompleted, &readResult, &result, &rhi] {
+ readCompleted = true;
+ QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888_Premultiplied);
+ if (rhi->isYUpInFramebuffer())
+ result = wrapperImage.mirrored();
+ else
+ result = wrapperImage.copy();
+ };
+ QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch();
+ readbackBatch->readBackTexture(tex.data(), &readResult);
+ renderControl->commandBuffer()->resourceUpdate(readbackBatch);
+
+ renderControl->endFrame();
+
+ QVERIFY(readCompleted);
+
+ QImage img = result;
+ QVERIFY(!img.isNull());
+ QCOMPARE(img.size(), currentSize);
+
+ const int maxFuzz = 2;
+
+ // The scene is: background, rectangle, text
+ // where rectangle rotates
+
+ QRgb background = img.pixel(5, 5);
+
+ // with rect_depth.qml the following would not pass if the depth buffering
+ // was not functional (because the red rectangle with z: -1 would still
+ // go on top, not below)
+ QVERIFY(qAbs(qRed(background) - 70) < maxFuzz);
+ QVERIFY(qAbs(qGreen(background) - 130) < maxFuzz);
+ QVERIFY(qAbs(qBlue(background) - 180) < maxFuzz);
+
+ background = img.pixel(195, 195);
+ QVERIFY(qAbs(qRed(background) - 70) < maxFuzz);
+ QVERIFY(qAbs(qGreen(background) - 130) < maxFuzz);
+ QVERIFY(qAbs(qBlue(background) - 180) < maxFuzz);
+ }
+#else
+ QSKIP("No Vulkan support in Qt build, skipping native Vulkan test");
+#endif
+}
+
#include "tst_qquickrendercontrol.moc"
QTEST_MAIN(tst_RenderControl)
diff --git a/tests/auto/quick/qquickrepeater/CMakeLists.txt b/tests/auto/quick/qquickrepeater/CMakeLists.txt
index 3e7fda53c0..91a55a6609 100644
--- a/tests/auto/quick/qquickrepeater/CMakeLists.txt
+++ b/tests/auto/quick/qquickrepeater/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickrepeater.pro.
#####################################################################
## tst_qquickrepeater Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickrepeater LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,22 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickrepeater
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickrepeater.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlModelsPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -36,10 +38,10 @@ qt_internal_add_test(tst_qquickrepeater
qt_internal_extend_target(tst_qquickrepeater CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickrepeater CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickrepeater/data/boundDelegateComponent.qml b/tests/auto/quick/qquickrepeater/data/boundDelegateComponent.qml
new file mode 100644
index 0000000000..4707e67ede
--- /dev/null
+++ b/tests/auto/quick/qquickrepeater/data/boundDelegateComponent.qml
@@ -0,0 +1,25 @@
+pragma ComponentBehavior: Bound
+
+import QtQuick
+
+Item {
+ id: root
+ objectName: "root"
+ Repeater {
+ id: undefinedModelData
+ model: ["aa", "bb", "cc"]
+ Item {
+ property var notHere: modelData
+ objectName: root.objectName + notHere
+ }
+ }
+
+ Repeater {
+ id: requiredModelData
+ model: ["aa", "bb", "cc"]
+ Item {
+ required property string modelData
+ objectName: root.objectName + modelData
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickrepeater/data/innerRequired.qml b/tests/auto/quick/qquickrepeater/data/innerRequired.qml
new file mode 100644
index 0000000000..5498232fc1
--- /dev/null
+++ b/tests/auto/quick/qquickrepeater/data/innerRequired.qml
@@ -0,0 +1,33 @@
+import QtQuick
+
+Item {
+ ListModel {
+ id: myModel
+ ListElement { type: "Dog"; age: 8; noise: "meow" }
+ ListElement { type: "Cat"; age: 5; noise: "woof" }
+ }
+
+ component SomeDelegate: Item {
+ required property int age
+ property string text
+ }
+
+ component AnotherDelegate: Item {
+ property int age
+ property string text
+
+ SomeDelegate {
+ age: 0
+ text: ""
+ }
+ }
+
+ Repeater {
+ id: repeater
+ model: myModel
+ delegate: AnotherDelegate {
+ age: model.age
+ text: model.noise
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp
index 32e4a1a05a..821770bae7 100644
--- a/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp
+++ b/tests/auto/quick/qquickrepeater/tst_qquickrepeater.cpp
@@ -1,35 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtTest/QSignalSpy>
#include <QtQml/qqmlengine.h>
#include <QtQuick/qquickview.h>
+#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlexpression.h>
#include <QtQml/qqmlincubator.h>
@@ -39,13 +15,14 @@
#include <QtQmlModels/private/qqmlobjectmodel_p.h>
#include <QtGui/qstandarditemmodel.h>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
-#include "../shared/visualtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
-using namespace QQuickViewTestUtil;
-using namespace QQuickVisualTestUtil;
+using namespace QQuickViewTestUtils;
+using namespace QQuickVisualTestUtils;
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests.repeater")
class tst_QQuickRepeater : public QQmlDataTest
{
@@ -82,6 +59,8 @@ private slots:
void ownership();
void requiredProperties();
void contextProperties();
+ void innerRequired();
+ void boundDelegateComponent();
};
class TestObject : public QObject
@@ -109,24 +88,25 @@ private:
};
tst_QQuickRepeater::tst_QQuickRepeater()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
void tst_QQuickRepeater::numberModel()
{
- QQuickView *window = createView();
+ std::unique_ptr<QQuickView> window { createView() };
QQmlContext *ctxt = window->rootContext();
ctxt->setContextProperty("testData", 5);
- TestObject *testObject = new TestObject;
- ctxt->setContextProperty("testObject", testObject);
+ std::unique_ptr<TestObject> testObject = std::make_unique<TestObject>();
+ ctxt->setContextProperty("testObject", testObject.get());
window->setSource(testFileUrl("intmodel.qml"));
qApp->processEvents();
QQuickRepeater *repeater = findItem<QQuickRepeater>(window->rootObject(), "repeater");
QVERIFY(repeater != nullptr);
- QCOMPARE(repeater->parentItem()->childItems().count(), 5+1);
+ QCOMPARE(repeater->parentItem()->childItems().size(), 5+1);
QVERIFY(!repeater->itemAt(-1));
for (int i=0; i<repeater->count(); i++)
@@ -137,13 +117,10 @@ void tst_QQuickRepeater::numberModel()
QVERIFY(!testObject->error());
ctxt->setContextProperty("testData", std::numeric_limits<int>::max());
- QCOMPARE(repeater->parentItem()->childItems().count(), 1);
+ QCOMPARE(repeater->parentItem()->childItems().size(), 1);
ctxt->setContextProperty("testData", -1234);
- QCOMPARE(repeater->parentItem()->childItems().count(), 1);
-
- delete testObject;
- delete window;
+ QCOMPARE(repeater->parentItem()->childItems().size(), 1);
}
void tst_QQuickRepeater::objectList_data()
@@ -169,8 +146,11 @@ public:
void tst_QQuickRepeater::objectList()
{
QFETCH(QUrl, filename);
- QQuickView *window = createView();
+ std::unique_ptr<QQuickView> window { createView() };
QObjectList data;
+ auto cleanup = qScopeGuard([&]() {
+ qDeleteAll(data);
+ });
for (int i=0; i<100; i++)
data << new MyObject(i);
@@ -186,18 +166,15 @@ void tst_QQuickRepeater::objectList()
QCOMPARE(repeater->property("instantiated").toInt(), 100);
QVERIFY(!repeater->itemAt(-1));
- for (int i=0; i<data.count(); i++)
+ for (int i=0; i<data.size(); i++)
QCOMPARE(repeater->itemAt(i), repeater->parentItem()->childItems().at(i));
- QVERIFY(!repeater->itemAt(data.count()));
+ QVERIFY(!repeater->itemAt(data.size()));
QSignalSpy addedSpy(repeater, SIGNAL(itemAdded(int,QQuickItem*)));
QSignalSpy removedSpy(repeater, SIGNAL(itemRemoved(int,QQuickItem*)));
ctxt->setContextProperty("testData", QVariant::fromValue(data));
- QCOMPARE(addedSpy.count(), data.count());
- QCOMPARE(removedSpy.count(), data.count());
-
- qDeleteAll(data);
- delete window;
+ QCOMPARE(addedSpy.size(), data.size());
+ QCOMPARE(removedSpy.size(), data.size());
}
/*
@@ -207,7 +184,7 @@ elements to test this.
*/
void tst_QQuickRepeater::stringList()
{
- QQuickView *window = createView();
+ std::unique_ptr<QQuickView> window { createView() };
QStringList data;
data << "One";
@@ -227,22 +204,22 @@ void tst_QQuickRepeater::stringList()
QQuickItem *container = findItem<QQuickItem>(window->rootObject(), "container");
QVERIFY(container != nullptr);
- QCOMPARE(container->childItems().count(), data.count() + 3);
+ QCOMPARE(container->childItems().size(), data.size() + 3);
bool saw_repeater = false;
- for (int i = 0; i < container->childItems().count(); ++i) {
+ for (int i = 0; i < container->childItems().size(); ++i) {
if (i == 0) {
QQuickText *name = qobject_cast<QQuickText*>(container->childItems().at(i));
QVERIFY(name != nullptr);
QCOMPARE(name->text(), QLatin1String("Zero"));
- } else if (i == container->childItems().count() - 2) {
+ } else if (i == container->childItems().size() - 2) {
// The repeater itself
QQuickRepeater *rep = qobject_cast<QQuickRepeater*>(container->childItems().at(i));
QCOMPARE(rep, repeater);
saw_repeater = true;
continue;
- } else if (i == container->childItems().count() - 1) {
+ } else if (i == container->childItems().size() - 1) {
QQuickText *name = qobject_cast<QQuickText*>(container->childItems().at(i));
QVERIFY(name != nullptr);
QCOMPARE(name->text(), QLatin1String("Last"));
@@ -253,16 +230,14 @@ void tst_QQuickRepeater::stringList()
}
}
QVERIFY(saw_repeater);
-
- delete window;
}
void tst_QQuickRepeater::dataModel_adding()
{
- QQuickView *window = createView();
+ std::unique_ptr<QQuickView> window { createView() };
QQmlContext *ctxt = window->rootContext();
- TestObject *testObject = new TestObject;
- ctxt->setContextProperty("testObject", testObject);
+ std::unique_ptr<TestObject> testObject = std::make_unique<TestObject>();
+ ctxt->setContextProperty("testObject", testObject.get());
QaimModel testModel;
ctxt->setContextProperty("testData", &testModel);
@@ -282,8 +257,8 @@ void tst_QQuickRepeater::dataModel_adding()
// add to empty model
testModel.addItem("two", "2");
QCOMPARE(repeater->itemAt(0), container->childItems().at(0));
- QCOMPARE(countSpy.count(), 1); countSpy.clear();
- QCOMPARE(addedSpy.count(), 1);
+ QCOMPARE(countSpy.size(), 1); countSpy.clear();
+ QCOMPARE(addedSpy.size(), 1);
QCOMPARE(addedSpy.at(0).at(0).toInt(), 0);
QCOMPARE(addedSpy.at(0).at(1).value<QQuickItem*>(), container->childItems().at(0));
addedSpy.clear();
@@ -291,8 +266,8 @@ void tst_QQuickRepeater::dataModel_adding()
// insert at start
testModel.insertItem(0, "one", "1");
QCOMPARE(repeater->itemAt(0), container->childItems().at(0));
- QCOMPARE(countSpy.count(), 1); countSpy.clear();
- QCOMPARE(addedSpy.count(), 1);
+ QCOMPARE(countSpy.size(), 1); countSpy.clear();
+ QCOMPARE(addedSpy.size(), 1);
QCOMPARE(addedSpy.at(0).at(0).toInt(), 0);
QCOMPARE(addedSpy.at(0).at(1).value<QQuickItem*>(), container->childItems().at(0));
addedSpy.clear();
@@ -300,8 +275,8 @@ void tst_QQuickRepeater::dataModel_adding()
// insert at end
testModel.insertItem(2, "four", "4");
QCOMPARE(repeater->itemAt(2), container->childItems().at(2));
- QCOMPARE(countSpy.count(), 1); countSpy.clear();
- QCOMPARE(addedSpy.count(), 1);
+ QCOMPARE(countSpy.size(), 1); countSpy.clear();
+ QCOMPARE(addedSpy.size(), 1);
QCOMPARE(addedSpy.at(0).at(0).toInt(), 2);
QCOMPARE(addedSpy.at(0).at(1).value<QQuickItem*>(), container->childItems().at(2));
addedSpy.clear();
@@ -309,8 +284,8 @@ void tst_QQuickRepeater::dataModel_adding()
// insert in middle
testModel.insertItem(2, "three", "3");
QCOMPARE(repeater->itemAt(2), container->childItems().at(2));
- QCOMPARE(countSpy.count(), 1); countSpy.clear();
- QCOMPARE(addedSpy.count(), 1);
+ QCOMPARE(countSpy.size(), 1); countSpy.clear();
+ QCOMPARE(addedSpy.size(), 1);
QCOMPARE(addedSpy.at(0).at(0).toInt(), 2);
QCOMPARE(addedSpy.at(0).at(1).value<QQuickItem*>(), container->childItems().at(2));
addedSpy.clear();
@@ -320,25 +295,24 @@ void tst_QQuickRepeater::dataModel_adding()
QList<QPair<QString, QString> > multiData;
multiData << qMakePair(QStringLiteral("five"), QStringLiteral("5")) << qMakePair(QStringLiteral("six"), QStringLiteral("6")) << qMakePair(QStringLiteral("seven"), QStringLiteral("7"));
testModel.insertItems(1, multiData);
- QCOMPARE(countSpy.count(), 1);
- QCOMPARE(addedSpy.count(), 3);
+ QCOMPARE(countSpy.size(), 1);
+ QCOMPARE(addedSpy.size(), 3);
QCOMPARE(container->childItems().size(), childItemsSize + 3);
QCOMPARE(repeater->itemAt(2), container->childItems().at(2));
addedSpy.clear();
countSpy.clear();
- delete testObject;
+ testObject.reset();
addedSpy.clear();
countSpy.clear();
- delete window;
}
void tst_QQuickRepeater::dataModel_removing()
{
- QQuickView *window = createView();
+ std::unique_ptr<QQuickView> window { createView() };
QQmlContext *ctxt = window->rootContext();
- TestObject *testObject = new TestObject;
- ctxt->setContextProperty("testObject", testObject);
+ auto testObject = std::make_unique<TestObject>();
+ ctxt->setContextProperty("testObject", testObject.get());
QaimModel testModel;
testModel.addItem("one", "1");
@@ -355,7 +329,7 @@ void tst_QQuickRepeater::dataModel_removing()
QVERIFY(repeater != nullptr);
QQuickItem *container = findItem<QQuickItem>(window->rootObject(), "container");
QVERIFY(container != nullptr);
- QCOMPARE(container->childItems().count(), repeater->count()+1);
+ QCOMPARE(container->childItems().size(), repeater->count()+1);
QSignalSpy countSpy(repeater, SIGNAL(countChanged()));
QSignalSpy removedSpy(repeater, SIGNAL(itemRemoved(int,QQuickItem*)));
@@ -366,8 +340,8 @@ void tst_QQuickRepeater::dataModel_removing()
testModel.removeItem(0);
QVERIFY(repeater->itemAt(0) != item);
- QCOMPARE(countSpy.count(), 1); countSpy.clear();
- QCOMPARE(removedSpy.count(), 1);
+ QCOMPARE(countSpy.size(), 1); countSpy.clear();
+ QCOMPARE(removedSpy.size(), 1);
QCOMPARE(removedSpy.at(0).at(0).toInt(), 0);
QCOMPARE(removedSpy.at(0).at(1).value<QQuickItem*>(), item);
removedSpy.clear();
@@ -379,8 +353,8 @@ void tst_QQuickRepeater::dataModel_removing()
testModel.removeItem(lastIndex);
QVERIFY(repeater->itemAt(lastIndex) != item);
- QCOMPARE(countSpy.count(), 1); countSpy.clear();
- QCOMPARE(removedSpy.count(), 1);
+ QCOMPARE(countSpy.size(), 1); countSpy.clear();
+ QCOMPARE(removedSpy.size(), 1);
QCOMPARE(removedSpy.at(0).at(0).toInt(), lastIndex);
QCOMPARE(removedSpy.at(0).at(1).value<QQuickItem*>(), item);
removedSpy.clear();
@@ -391,22 +365,19 @@ void tst_QQuickRepeater::dataModel_removing()
testModel.removeItem(1);
QVERIFY(repeater->itemAt(lastIndex) != item);
- QCOMPARE(countSpy.count(), 1); countSpy.clear();
- QCOMPARE(removedSpy.count(), 1);
+ QCOMPARE(countSpy.size(), 1); countSpy.clear();
+ QCOMPARE(removedSpy.size(), 1);
QCOMPARE(removedSpy.at(0).at(0).toInt(), 1);
QCOMPARE(removedSpy.at(0).at(1).value<QQuickItem*>(), item);
removedSpy.clear();
-
- delete testObject;
- delete window;
}
void tst_QQuickRepeater::dataModel_changes()
{
- QQuickView *window = createView();
+ std::unique_ptr<QQuickView> window { createView() };
QQmlContext *ctxt = window->rootContext();
- TestObject *testObject = new TestObject;
- ctxt->setContextProperty("testObject", testObject);
+ auto testObject = std::make_unique<TestObject>();
+ ctxt->setContextProperty("testObject", testObject.get());
QaimModel testModel;
testModel.addItem("one", "1");
@@ -421,7 +392,7 @@ void tst_QQuickRepeater::dataModel_changes()
QVERIFY(repeater != nullptr);
QQuickItem *container = findItem<QQuickItem>(window->rootObject(), "container");
QVERIFY(container != nullptr);
- QCOMPARE(container->childItems().count(), repeater->count()+1);
+ QCOMPARE(container->childItems().size(), repeater->count()+1);
// Check that model changes are propagated
QQuickText *text = findItem<QQuickText>(window->rootObject(), "myName", 1);
@@ -436,17 +407,14 @@ void tst_QQuickRepeater::dataModel_changes()
text = findItem<QQuickText>(window->rootObject(), "myNumber", 1);
QVERIFY(text);
QCOMPARE(text->text(), QString("_2"));
-
- delete testObject;
- delete window;
}
void tst_QQuickRepeater::itemModel()
{
- QQuickView *window = createView();
+ std::unique_ptr<QQuickView> window { createView() };
QQmlContext *ctxt = window->rootContext();
- TestObject *testObject = new TestObject;
- ctxt->setContextProperty("testObject", testObject);
+ auto testObject = std::make_unique<TestObject>();
+ ctxt->setContextProperty("testObject", testObject.get());
window->setSource(testFileUrl("itemlist.qml"));
qApp->processEvents();
@@ -457,34 +425,38 @@ void tst_QQuickRepeater::itemModel()
QQuickItem *container = findItem<QQuickItem>(window->rootObject(), "container");
QVERIFY(container != nullptr);
- QCOMPARE(container->childItems().count(), 1);
+ QCOMPARE(container->childItems().size(), 1);
testObject->setUseModel(true);
QMetaObject::invokeMethod(window->rootObject(), "checkProperties");
QVERIFY(!testObject->error());
- QCOMPARE(container->childItems().count(), 4);
+ if (lcTests().isDebugEnabled()) {
+ qCDebug(lcTests) << "=== item tree:";
+ window->contentItem()->dumpItemTree();
+ qCDebug(lcTests) << "=== object tree:";
+ window->dumpObjectTree();
+ }
+
+ QCOMPARE(container->childItems().size(), 4);
QCOMPARE(qobject_cast<QObject*>(container->childItems().at(0))->objectName(), QLatin1String("item1"));
QCOMPARE(qobject_cast<QObject*>(container->childItems().at(1))->objectName(), QLatin1String("item2"));
QCOMPARE(qobject_cast<QObject*>(container->childItems().at(2))->objectName(), QLatin1String("item3"));
QCOMPARE(container->childItems().at(3), repeater);
QMetaObject::invokeMethod(window->rootObject(), "switchModel");
- QCOMPARE(container->childItems().count(), 3);
+ QCOMPARE(container->childItems().size(), 3);
QCOMPARE(qobject_cast<QObject*>(container->childItems().at(0))->objectName(), QLatin1String("item4"));
QCOMPARE(qobject_cast<QObject*>(container->childItems().at(1))->objectName(), QLatin1String("item5"));
QCOMPARE(container->childItems().at(2), repeater);
testObject->setUseModel(false);
- QCOMPARE(container->childItems().count(), 1);
-
- delete testObject;
- delete window;
+ QCOMPARE(container->childItems().size(), 1);
}
void tst_QQuickRepeater::resetModel()
{
- QQuickView *window = createView();
+ std::unique_ptr<QQuickView> window { createView() };
QStringList dataA;
for (int i=0; i<10; i++)
@@ -499,7 +471,7 @@ void tst_QQuickRepeater::resetModel()
QQuickItem *container = findItem<QQuickItem>(window->rootObject(), "container");
QVERIFY(container != nullptr);
- QCOMPARE(repeater->count(), dataA.count());
+ QCOMPARE(repeater->count(), dataA.size());
for (int i=0; i<repeater->count(); i++)
QCOMPARE(repeater->itemAt(i), container->childItems().at(i+1)); // +1 to skip first Text object
@@ -514,13 +486,13 @@ void tst_QQuickRepeater::resetModel()
// reset context property
ctxt->setContextProperty("testData", dataB);
- QCOMPARE(repeater->count(), dataB.count());
+ QCOMPARE(repeater->count(), dataB.size());
- QCOMPARE(modelChangedSpy.count(), 1);
- QCOMPARE(countSpy.count(), 1);
- QCOMPARE(removedSpy.count(), dataA.count());
- QCOMPARE(addedSpy.count(), dataB.count());
- for (int i=0; i<dataB.count(); i++) {
+ QCOMPARE(modelChangedSpy.size(), 1);
+ QCOMPARE(countSpy.size(), 1);
+ QCOMPARE(removedSpy.size(), dataA.size());
+ QCOMPARE(addedSpy.size(), dataB.size());
+ for (int i=0; i<dataB.size(); i++) {
QCOMPARE(addedSpy.at(i).at(0).toInt(), i);
QCOMPARE(addedSpy.at(i).at(1).value<QQuickItem*>(), repeater->itemAt(i));
}
@@ -531,13 +503,13 @@ void tst_QQuickRepeater::resetModel()
// reset via setModel()
repeater->setModel(dataA);
- QCOMPARE(repeater->count(), dataA.count());
+ QCOMPARE(repeater->count(), dataA.size());
- QCOMPARE(modelChangedSpy.count(), 1);
- QCOMPARE(countSpy.count(), 1);
- QCOMPARE(removedSpy.count(), dataB.count());
- QCOMPARE(addedSpy.count(), dataA.count());
- for (int i=0; i<dataA.count(); i++) {
+ QCOMPARE(modelChangedSpy.size(), 1);
+ QCOMPARE(countSpy.size(), 1);
+ QCOMPARE(removedSpy.size(), dataB.size());
+ QCOMPARE(addedSpy.size(), dataA.size());
+ for (int i=0; i<dataA.size(); i++) {
QCOMPARE(addedSpy.at(i).at(0).toInt(), i);
QCOMPARE(addedSpy.at(i).at(1).value<QQuickItem*>(), repeater->itemAt(i));
}
@@ -546,8 +518,6 @@ void tst_QQuickRepeater::resetModel()
countSpy.clear();
removedSpy.clear();
addedSpy.clear();
-
- delete window;
}
// QTBUG-17156
@@ -556,7 +526,8 @@ void tst_QQuickRepeater::modelChanged()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("modelChanged.qml"));
- QQuickItem *rootObject = qobject_cast<QQuickItem*>(component.create());
+ std::unique_ptr<QObject> root { component.create() };
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(root.get());
QVERIFY(rootObject);
QQuickRepeater *repeater = findItem<QQuickRepeater>(rootObject, "repeater");
QVERIFY(repeater);
@@ -564,14 +535,12 @@ void tst_QQuickRepeater::modelChanged()
repeater->setModel(4);
QCOMPARE(repeater->count(), 4);
QCOMPARE(repeater->property("itemsCount").toInt(), 4);
- QCOMPARE(repeater->property("itemsFound").toList().count(), 4);
+ QCOMPARE(repeater->property("itemsFound").toList().size(), 4);
repeater->setModel(10);
QCOMPARE(repeater->count(), 10);
QCOMPARE(repeater->property("itemsCount").toInt(), 10);
- QCOMPARE(repeater->property("itemsFound").toList().count(), 10);
-
- delete rootObject;
+ QCOMPARE(repeater->property("itemsFound").toList().size(), 10);
}
void tst_QQuickRepeater::modelReset()
@@ -606,10 +575,10 @@ void tst_QQuickRepeater::modelReset()
model.resetItems(items);
- QCOMPARE(countSpy.count(), 1);
- QCOMPARE(removedSpy.count(), 0);
- QCOMPARE(addedSpy.count(), items.count());
- for (int i = 0; i< items.count(); i++) {
+ QCOMPARE(countSpy.size(), 1);
+ QCOMPARE(removedSpy.size(), 0);
+ QCOMPARE(addedSpy.size(), items.size());
+ for (int i = 0; i< items.size(); i++) {
QCOMPARE(addedSpy.at(i).at(0).toInt(), i);
QCOMPARE(addedSpy.at(i).at(1).value<QQuickItem*>(), repeater->itemAt(i));
}
@@ -618,10 +587,10 @@ void tst_QQuickRepeater::modelReset()
addedSpy.clear();
model.reset();
- QCOMPARE(countSpy.count(), 0);
- QCOMPARE(removedSpy.count(), 3);
- QCOMPARE(addedSpy.count(), 3);
- for (int i = 0; i< items.count(); i++) {
+ QCOMPARE(countSpy.size(), 0);
+ QCOMPARE(removedSpy.size(), 3);
+ QCOMPARE(addedSpy.size(), 3);
+ for (int i = 0; i< items.size(); i++) {
QCOMPARE(addedSpy.at(i).at(0).toInt(), i);
QCOMPARE(addedSpy.at(i).at(1).value<QQuickItem*>(), repeater->itemAt(i));
}
@@ -633,10 +602,10 @@ void tst_QQuickRepeater::modelReset()
items.append(qMakePair(QString::fromLatin1("five"), QString::fromLatin1("5")));
model.resetItems(items);
- QCOMPARE(countSpy.count(), 1);
- QCOMPARE(removedSpy.count(), 3);
- QCOMPARE(addedSpy.count(), 5);
- for (int i = 0; i< items.count(); i++) {
+ QCOMPARE(countSpy.size(), 1);
+ QCOMPARE(removedSpy.size(), 3);
+ QCOMPARE(addedSpy.size(), 5);
+ for (int i = 0; i< items.size(); i++) {
QCOMPARE(addedSpy.at(i).at(0).toInt(), i);
QCOMPARE(addedSpy.at(i).at(1).value<QQuickItem*>(), repeater->itemAt(i));
}
@@ -647,9 +616,9 @@ void tst_QQuickRepeater::modelReset()
items.clear();
model.resetItems(items);
- QCOMPARE(countSpy.count(), 1);
- QCOMPARE(removedSpy.count(), 5);
- QCOMPARE(addedSpy.count(), 0);
+ QCOMPARE(countSpy.size(), 1);
+ QCOMPARE(removedSpy.size(), 5);
+ QCOMPARE(addedSpy.size(), 0);
}
// QTBUG-46828
@@ -658,7 +627,8 @@ void tst_QQuickRepeater::modelCleared()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("modelCleared.qml"));
- QQuickItem *rootObject = qobject_cast<QQuickItem*>(component.create());
+ std::unique_ptr<QObject> root { component.create() };
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(root.get());
QVERIFY(rootObject);
QQuickRepeater *repeater = findItem<QQuickRepeater>(rootObject, "repeater");
@@ -668,8 +638,6 @@ void tst_QQuickRepeater::modelCleared()
QQmlTestMessageHandler messageHandler;
repeater->setModel(0);
QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString()));
-
- delete rootObject;
}
void tst_QQuickRepeater::properties()
@@ -677,7 +645,8 @@ void tst_QQuickRepeater::properties()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("properties.qml"));
- QQuickItem *rootObject = qobject_cast<QQuickItem*>(component.create());
+ std::unique_ptr<QObject> root { component.create() };
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(root.get());
QVERIFY(rootObject);
QQuickRepeater *repeater = findItem<QQuickRepeater>(rootObject, "repeater");
@@ -685,9 +654,9 @@ void tst_QQuickRepeater::properties()
QSignalSpy modelSpy(repeater, SIGNAL(modelChanged()));
repeater->setModel(3);
- QCOMPARE(modelSpy.count(),1);
+ QCOMPARE(modelSpy.size(),1);
repeater->setModel(3);
- QCOMPARE(modelSpy.count(),1);
+ QCOMPARE(modelSpy.size(),1);
QSignalSpy delegateSpy(repeater, SIGNAL(delegateChanged()));
@@ -695,16 +664,14 @@ void tst_QQuickRepeater::properties()
rectComponent.setData("import QtQuick 2.0; Rectangle {}", QUrl::fromLocalFile(""));
repeater->setDelegate(&rectComponent);
- QCOMPARE(delegateSpy.count(),1);
+ QCOMPARE(delegateSpy.size(),1);
repeater->setDelegate(&rectComponent);
- QCOMPARE(delegateSpy.count(),1);
-
- delete rootObject;
+ QCOMPARE(delegateSpy.size(),1);
}
void tst_QQuickRepeater::asynchronous()
{
- QQuickView *window = createView();
+ std::unique_ptr<QQuickView> window { createView() };
window->show();
QQmlIncubationController controller;
window->engine()->setIncubationController(&controller);
@@ -755,8 +722,6 @@ void tst_QQuickRepeater::asynchronous()
QQuickItem *item = findItem<QQuickItem>(container, name);
QTRY_COMPARE(item->y(), i * 50.0);
}
-
- delete window;
}
void tst_QQuickRepeater::initParent()
@@ -764,7 +729,8 @@ void tst_QQuickRepeater::initParent()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("initparent.qml"));
- QQuickItem *rootObject = qobject_cast<QQuickItem*>(component.create());
+ std::unique_ptr<QObject> root { component.create() };
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(root.get());
QVERIFY(rootObject);
QCOMPARE(qvariant_cast<QQuickItem*>(rootObject->property("parentItem")), rootObject);
@@ -776,7 +742,8 @@ void tst_QQuickRepeater::dynamicModelCrash()
QQmlComponent component(&engine, testFileUrl("dynamicmodelcrash.qml"));
// Don't crash
- QQuickItem *rootObject = qobject_cast<QQuickItem*>(component.create());
+ std::unique_ptr<QObject> root { component.create() };
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(root.get());
QVERIFY(rootObject);
QQuickRepeater *repeater = findItem<QQuickRepeater>(rootObject, "rep");
@@ -789,10 +756,9 @@ void tst_QQuickRepeater::visualItemModelCrash()
// This used to crash because the model would get
// deleted before the repeater, leading to double-deletion
// of the items.
- QQuickView *window = createView();
+ std::unique_ptr<QQuickView> window { createView() };
window->setSource(testFileUrl("visualitemmodel.qml"));
qApp->processEvents();
- delete window;
}
class BadModel : public QAbstractListModel
@@ -804,8 +770,8 @@ public:
endResetModel();
}
- QVariant data(const QModelIndex &, int) const { return QVariant(); }
- int rowCount(const QModelIndex &) const { return 0; }
+ QVariant data(const QModelIndex &, int) const override { return QVariant(); }
+ int rowCount(const QModelIndex &) const override { return 0; }
};
@@ -818,7 +784,7 @@ void tst_QQuickRepeater::invalidContextCrash()
engine.rootContext()->setContextProperty("badModel", model);
QScopedPointer<QObject> root(component.create());
- QCOMPARE(root->children().count(), 1);
+ QCOMPARE(root->children().size(), 1);
QObject *repeater = root->children().first();
// Make sure the model comes first in the child list, so it will be
@@ -828,7 +794,7 @@ void tst_QQuickRepeater::invalidContextCrash()
repeater->setParent(nullptr);
repeater->setParent(root.data());
- QCOMPARE(root->children().count(), 2);
+ QCOMPARE(root->children().size(), 2);
QCOMPARE(root->children().at(0), model);
QCOMPARE(root->children().at(1), repeater);
@@ -857,11 +823,11 @@ void tst_QQuickRepeater::jsArrayChange()
}
repeater->setModel(QVariant::fromValue(array1));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
// no change
repeater->setModel(QVariant::fromValue(array2));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
void tst_QQuickRepeater::clearRemovalOrder()
@@ -872,7 +838,8 @@ void tst_QQuickRepeater::clearRemovalOrder()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("clearremovalorder.qml"));
- QQuickItem *rootObject = qobject_cast<QQuickItem*>(component.create());
+ std::unique_ptr<QObject> root { component.create() };
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(root.get());
QVERIFY(rootObject);
QQuickRepeater *repeater = findItem<QQuickRepeater>(rootObject, "repeater");
@@ -889,15 +856,13 @@ void tst_QQuickRepeater::clearRemovalOrder()
// we should have 0 items, and 3 removal signals.
QCOMPARE(repeater->count(), 0);
- QCOMPARE(removedSpy.count(), 3);
+ QCOMPARE(removedSpy.size(), 3);
// column 1 is for the items, we won't bother verifying these. just look at
// the indices and make sure they're sane.
QCOMPARE(removedSpy.at(0).at(0).toInt(), 2);
QCOMPARE(removedSpy.at(1).at(0).toInt(), 1);
QCOMPARE(removedSpy.at(2).at(0).toInt(), 0);
-
- delete rootObject;
}
void tst_QQuickRepeater::destroyCount()
@@ -905,7 +870,8 @@ void tst_QQuickRepeater::destroyCount()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("destroycount.qml"));
- QQuickItem *rootObject = qobject_cast<QQuickItem*>(component.create());
+ std::unique_ptr<QObject> root { component.create() };
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(root.get());
QVERIFY(rootObject);
QQuickRepeater *repeater = findItem<QQuickRepeater>(rootObject, "repeater");
@@ -940,7 +906,8 @@ void tst_QQuickRepeater::stackingOrder()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("stackingorder.qml"));
- QQuickItem *rootObject = qobject_cast<QQuickItem*>(component.create());
+ std::unique_ptr<QObject> root { component.create() };
+ QQuickItem *rootObject = qobject_cast<QQuickItem*>(root.get());
QVERIFY(rootObject);
QQuickRepeater *repeater = findItem<QQuickRepeater>(rootObject, "repeater");
@@ -969,7 +936,8 @@ void tst_QQuickRepeater::objectModel()
QQmlEngine engine;
QQmlComponent component(&engine, testFileUrl("objectmodel.qml"));
- QQuickItem *positioner = qobject_cast<QQuickItem *>(component.create());
+ std::unique_ptr<QObject> root { component.create() };
+ QQuickItem *positioner = qobject_cast<QQuickItem *>(root.get());
QVERIFY(positioner);
QQuickRepeater *repeater = findItem<QQuickRepeater>(positioner, "repeater");
@@ -1007,8 +975,6 @@ void tst_QQuickRepeater::objectModel()
model->clear();
QCOMPARE(model->count(), 0);
QCOMPARE(repeater->count(), 0);
-
- delete positioner;
}
class Ctrl : public QObject
@@ -1025,7 +991,7 @@ public:
void tst_QQuickRepeater::QTBUG54859_asynchronousMove()
{
Ctrl ctrl;
- QQuickView* view = createView();
+ std::unique_ptr<QQuickView> view { createView() };
view->rootContext()->setContextProperty("ctrl", &ctrl);
view->setSource(testFileUrl("asynchronousMove.qml"));
view->show();
@@ -1090,8 +1056,7 @@ void tst_QQuickRepeater::ownership()
QVERIFY(!QQmlData::keepAliveDuringGarbageCollection(aim.get()));
- engine.collectGarbage();
- QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
+ gc(engine);
QVERIFY(modelGuard);
@@ -1109,8 +1074,7 @@ void tst_QQuickRepeater::ownership()
QVERIFY(!QQmlData::keepAliveDuringGarbageCollection(delegate.get()));
- engine.collectGarbage();
- QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
+ gc(engine);
QVERIFY(delegateGuard);
@@ -1123,8 +1087,7 @@ void tst_QQuickRepeater::ownership()
delegate.release();
aim.release();
- engine.collectGarbage();
- QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
+ gc(engine);
QVERIFY(!delegateGuard);
QVERIFY(!modelGuard);
@@ -1158,12 +1121,70 @@ void tst_QQuickRepeater::contextProperties()
while (!items.isEmpty()) {
QQuickItem *item = items.dequeue();
- QVERIFY(!QQmlContextData::get(qmlContext(item))->extraObject());
+ QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(qmlContext(item));
+
+ // Context object and extra object should never be the same. There are ways for the extra
+ // object to exist even without required properties, though.
+ QVERIFY(contextData->contextObject() != contextData->extraObject());
for (QQuickItem *child : item->childItems())
items.enqueue(child);
}
}
+void tst_QQuickRepeater::innerRequired()
+{
+ QQmlEngine engine;
+ const QUrl url(testFileUrl("innerRequired.qml"));
+ QQmlComponent component(&engine, url);
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY2(!o.isNull(), qPrintable(component.errorString()));
+
+ QQuickRepeater *a = qobject_cast<QQuickRepeater *>(
+ qmlContext(o.data())->objectForName(QStringLiteral("repeater")));
+ QVERIFY(a);
+
+ QCOMPARE(a->count(), 2);
+ QCOMPARE(a->itemAt(0)->property("age").toInt(), 8);
+ QCOMPARE(a->itemAt(0)->property("text").toString(), u"meow");
+ QCOMPARE(a->itemAt(1)->property("age").toInt(), 5);
+ QCOMPARE(a->itemAt(1)->property("text").toString(), u"woof");
+}
+
+void tst_QQuickRepeater::boundDelegateComponent()
+{
+ QQmlEngine engine;
+ const QUrl url(testFileUrl("boundDelegateComponent.qml"));
+ QQmlComponent component(&engine, url);
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+
+ for (int i = 0; i < 3; ++i) {
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ qPrintable(QLatin1String("%1:12: ReferenceError: modelData is not defined")
+ .arg(url.toString())));
+ }
+
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY2(!o.isNull(), qPrintable(component.errorString()));
+
+ QQuickRepeater *a = qobject_cast<QQuickRepeater *>(
+ qmlContext(o.data())->objectForName(QStringLiteral("undefinedModelData")));
+ QVERIFY(a);
+ QCOMPARE(a->count(), 3);
+ for (int i = 0; i < 3; ++i)
+ QCOMPARE(a->itemAt(i)->objectName(), QStringLiteral("rootundefined"));
+
+ QQuickRepeater *b = qobject_cast<QQuickRepeater *>(
+ qmlContext(o.data())->objectForName(QStringLiteral("requiredModelData")));
+ QVERIFY(b);
+ QCOMPARE(b->count(), 3);
+ QCOMPARE(b->itemAt(0)->objectName(), QStringLiteral("rootaa"));
+ QCOMPARE(b->itemAt(1)->objectName(), QStringLiteral("rootbb"));
+ QCOMPARE(b->itemAt(2)->objectName(), QStringLiteral("rootcc"));
+}
+
QTEST_MAIN(tst_QQuickRepeater)
#include "tst_qquickrepeater.moc"
diff --git a/tests/auto/quick/qquickrhiitem/BLACKLIST b/tests/auto/quick/qquickrhiitem/BLACKLIST
new file mode 100644
index 0000000000..03e5bc8c1d
--- /dev/null
+++ b/tests/auto/quick/qquickrhiitem/BLACKLIST
@@ -0,0 +1,3 @@
+# QTBUG-102721
+[rhiItem]
+android
diff --git a/tests/auto/quick/qquickrhiitem/CMakeLists.txt b/tests/auto/quick/qquickrhiitem/CMakeLists.txt
new file mode 100644
index 0000000000..ef9858ea6d
--- /dev/null
+++ b/tests/auto/quick/qquickrhiitem/CMakeLists.txt
@@ -0,0 +1,52 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickrhiitem LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_qquickrhiitem
+ SOURCES
+ tst_qquickrhiitem.cpp
+ testrhiitem.cpp testrhiitem.h
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
+)
+
+qt_internal_extend_target(tst_qquickrhiitem CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=":/data"
+)
+
+qt_internal_extend_target(tst_qquickrhiitem CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+)
+
+qt_internal_add_shaders(tst_qquickrhiitem "shaders"
+ PREFIX
+ "/"
+ FILES
+ "texture.vert"
+ "texture.frag"
+)
+
+qt_policy(SET QTP0001 NEW)
+
+qt_add_qml_module(tst_qquickrhiitem
+ URI Testqquickrhiitem
+)
diff --git a/tests/auto/quick/qquickrhiitem/data/test.qml b/tests/auto/quick/qquickrhiitem/data/test.qml
new file mode 100644
index 0000000000..92fbfdb016
--- /dev/null
+++ b/tests/auto/quick/qquickrhiitem/data/test.qml
@@ -0,0 +1,41 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import Testqquickrhiitem
+
+Item {
+ width: 640
+ height: 480
+
+ Text {
+ id: apiInfo
+ color: "black"
+ font.pixelSize: 16
+ property int api: GraphicsInfo.api
+ text: {
+ if (GraphicsInfo.api === GraphicsInfo.OpenGL)
+ "OpenGL on QRhi";
+ else if (GraphicsInfo.api === GraphicsInfo.Direct3D11)
+ "D3D11 on QRhi";
+ else if (GraphicsInfo.api === GraphicsInfo.Direct3D12)
+ "D3D12 on QRhi";
+ else if (GraphicsInfo.api === GraphicsInfo.Vulkan)
+ "Vulkan on QRhi";
+ else if (GraphicsInfo.api === GraphicsInfo.Metal)
+ "Metal on QRhi";
+ else if (GraphicsInfo.api === GraphicsInfo.Null)
+ "Null on QRhi";
+ else
+ "Unknown API";
+ }
+ }
+
+ TestRhiItem {
+ anchors.centerIn: parent
+ width: 400
+ height: 400
+ color: "red"
+ objectName: "rhiitem"
+ }
+}
diff --git a/tests/auto/quick/qquickrhiitem/testrhiitem.cpp b/tests/auto/quick/qquickrhiitem/testrhiitem.cpp
new file mode 100644
index 0000000000..65fc329630
--- /dev/null
+++ b/tests/auto/quick/qquickrhiitem/testrhiitem.cpp
@@ -0,0 +1,157 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "testrhiitem.h"
+#include <QFile>
+
+static const QSize TEX_SIZE(512, 512);
+
+void TestRenderer::initialize(QRhiCommandBuffer *)
+{
+ if (m_rhi != rhi()) {
+ m_rhi = rhi();
+ scene = {};
+ }
+
+ if (m_sampleCount != renderTarget()->sampleCount()) {
+ m_sampleCount = renderTarget()->sampleCount();
+ scene = {};
+ }
+
+ if (!scene.vbuf)
+ initScene();
+
+ const QSize outputSize = renderTarget()->pixelSize();
+ scene.mvp = m_rhi->clipSpaceCorrMatrix();
+ scene.mvp.perspective(45.0f, outputSize.width() / (float) outputSize.height(), 0.01f, 1000.0f);
+ scene.mvp.translate(0, 0, -4);
+ if (!scene.resourceUpdates)
+ scene.resourceUpdates = m_rhi->nextResourceUpdateBatch();
+ scene.resourceUpdates->updateDynamicBuffer(scene.ubuf.get(), 0, 64, scene.mvp.constData());
+}
+
+static QShader getShader(const QString &name)
+{
+ QFile f(name);
+ if (f.open(QIODevice::ReadOnly))
+ return QShader::fromSerialized(f.readAll());
+
+ return QShader();
+}
+
+void TestRenderer::updateTexture()
+{
+ QImage img(TEX_SIZE, QImage::Format_RGBA8888);
+ img.fill(itemData.color);
+
+ if (!scene.resourceUpdates)
+ scene.resourceUpdates = m_rhi->nextResourceUpdateBatch();
+
+ scene.resourceUpdates->uploadTexture(scene.tex.get(), img);
+}
+
+void TestRenderer::initScene()
+{
+ static const float tri[] = {
+ 0.0f, 0.5f, 0.0f, 1.0f,
+ -0.5f, -0.5f, 0.0f, 0.0f,
+ 0.5f, -0.5f, 1.0f, 0.0f
+ };
+
+ scene.vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(tri)));
+ scene.vbuf->create();
+
+ scene.resourceUpdates = m_rhi->nextResourceUpdateBatch();
+ scene.resourceUpdates->uploadStaticBuffer(scene.vbuf.get(), tri);
+
+ scene.ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68));
+ scene.ubuf->create();
+
+ const qint32 flip = m_rhi->isYUpInFramebuffer() ? 1 : 0;
+ scene.resourceUpdates->updateDynamicBuffer(scene.ubuf.get(), 64, 4, &flip);
+
+ scene.tex.reset(m_rhi->newTexture(QRhiTexture::RGBA8, TEX_SIZE));
+ scene.tex->create();
+
+ scene.sampler.reset(m_rhi->newSampler(QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
+ QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
+ scene.sampler->create();
+
+ scene.srb.reset(m_rhi->newShaderResourceBindings());
+ scene.srb->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage, scene.ubuf.get()),
+ QRhiShaderResourceBinding::sampledTexture(1, QRhiShaderResourceBinding::FragmentStage, scene.tex.get(), scene.sampler.get())
+ });
+ scene.srb->create();
+
+ scene.ps.reset(m_rhi->newGraphicsPipeline());
+ scene.ps->setDepthTest(true);
+ scene.ps->setDepthWrite(true);
+ scene.ps->setDepthOp(QRhiGraphicsPipeline::Less);
+ scene.ps->setCullMode(QRhiGraphicsPipeline::Back);
+ scene.ps->setFrontFace(QRhiGraphicsPipeline::CCW);
+ QShader vs = getShader(QLatin1String(":/texture.vert.qsb"));
+ Q_ASSERT(vs.isValid());
+ QShader fs = getShader(QLatin1String(":/texture.frag.qsb"));
+ Q_ASSERT(fs.isValid());
+ scene.ps->setShaderStages({
+ { QRhiShaderStage::Vertex, vs },
+ { QRhiShaderStage::Fragment, fs }
+ });
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({
+ { 4 * sizeof(float) },
+ });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
+ { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) }
+ });
+ scene.ps->setVertexInputLayout(inputLayout);
+ scene.ps->setSampleCount(m_sampleCount);
+ scene.ps->setShaderResourceBindings(scene.srb.get());
+ scene.ps->setRenderPassDescriptor(renderTarget()->renderPassDescriptor());
+ scene.ps->create();
+
+ updateTexture();
+}
+
+void TestRenderer::synchronize(QQuickRhiItem *rhiItem)
+{
+ TestRhiItem *item = static_cast<TestRhiItem *>(rhiItem);
+ if (item->color() != itemData.color) {
+ itemData.color = item->color();
+ updateTexture();
+ }
+}
+
+void TestRenderer::render(QRhiCommandBuffer *cb)
+{
+ QRhiResourceUpdateBatch *rub = scene.resourceUpdates;
+ if (rub)
+ scene.resourceUpdates = nullptr;
+
+ const QColor clearColor = QColor::fromRgbF(0.4f, 0.7f, 0.0f, 1.0f);
+ cb->beginPass(renderTarget(), clearColor, { 1.0f, 0 }, rub);
+
+ cb->setGraphicsPipeline(scene.ps.get());
+ const QSize outputSize = renderTarget()->pixelSize();
+ cb->setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height()));
+ cb->setShaderResources();
+ const QRhiCommandBuffer::VertexInput vbufBindings[] = {
+ { scene.vbuf.get(), 0 },
+ };
+ cb->setVertexInput(0, 1, vbufBindings);
+ cb->draw(3);
+
+ cb->endPass();
+}
+
+void TestRhiItem::setColor(QColor c)
+{
+ if (m_color == c)
+ return;
+
+ m_color = c;
+ emit colorChanged();
+ update();
+}
diff --git a/tests/auto/quick/qquickrhiitem/testrhiitem.h b/tests/auto/quick/qquickrhiitem/testrhiitem.h
new file mode 100644
index 0000000000..6778f96d7b
--- /dev/null
+++ b/tests/auto/quick/qquickrhiitem/testrhiitem.h
@@ -0,0 +1,61 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef TESTRHIITEM_H
+#define TESTRHIITEM_H
+
+#include <QQuickRhiItem>
+#include <rhi/qrhi.h>
+
+class TestRenderer : public QQuickRhiItemRenderer
+{
+protected:
+ void initialize(QRhiCommandBuffer *cb) override;
+ void synchronize(QQuickRhiItem *item) override;
+ void render(QRhiCommandBuffer *cb) override;
+
+private:
+ QRhi *m_rhi = nullptr;
+ int m_sampleCount = 1;
+
+ struct {
+ QRhiResourceUpdateBatch *resourceUpdates = nullptr;
+ std::unique_ptr<QRhiBuffer> vbuf;
+ std::unique_ptr<QRhiBuffer> ubuf;
+ std::unique_ptr<QRhiShaderResourceBindings> srb;
+ std::unique_ptr<QRhiGraphicsPipeline> ps;
+ std::unique_ptr<QRhiSampler> sampler;
+ std::unique_ptr<QRhiTexture> tex;
+ QMatrix4x4 mvp;
+ } scene;
+
+ struct {
+ QColor color;
+ } itemData;
+
+ void initScene();
+ void updateTexture();
+
+ friend class tst_QQuickRhiItem;
+};
+
+class TestRhiItem : public QQuickRhiItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(TestRhiItem)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
+
+public:
+ QQuickRhiItemRenderer *createRenderer() override { return new TestRenderer; }
+
+ QColor color() const { return m_color; }
+ void setColor(QColor c);
+
+signals:
+ void colorChanged();
+
+private:
+ QColor m_color;
+};
+
+#endif
diff --git a/tests/auto/quick/qquickrhiitem/texture.frag b/tests/auto/quick/qquickrhiitem/texture.frag
new file mode 100644
index 0000000000..a7b8bce0ad
--- /dev/null
+++ b/tests/auto/quick/qquickrhiitem/texture.frag
@@ -0,0 +1,18 @@
+#version 440
+
+layout(location = 0) in vec2 v_texcoord;
+
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 mvp;
+ int flip;
+};
+
+layout(binding = 1) uniform sampler2D tex;
+
+void main()
+{
+ vec4 c = texture(tex, v_texcoord);
+ fragColor = vec4(c.rgb * c.a, c.a);
+}
diff --git a/tests/auto/quick/qquickrhiitem/texture.vert b/tests/auto/quick/qquickrhiitem/texture.vert
new file mode 100644
index 0000000000..bf678d1e9b
--- /dev/null
+++ b/tests/auto/quick/qquickrhiitem/texture.vert
@@ -0,0 +1,19 @@
+#version 440
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec2 texcoord;
+
+layout(location = 0) out vec2 v_texcoord;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 mvp;
+ int flip;
+};
+
+void main()
+{
+ v_texcoord = texcoord;
+ if (flip != 0)
+ v_texcoord.y = 1.0 - v_texcoord.y;
+ gl_Position = mvp * position;
+}
diff --git a/tests/auto/quick/qquickrhiitem/tst_qquickrhiitem.cpp b/tests/auto/quick/qquickrhiitem/tst_qquickrhiitem.cpp
new file mode 100644
index 0000000000..e6c5b079ca
--- /dev/null
+++ b/tests/auto/quick/qquickrhiitem/tst_qquickrhiitem.cpp
@@ -0,0 +1,150 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <qtest.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QQuickView>
+#include <QSGRendererInterface>
+#include <private/qsgrhisupport_p.h>
+#include <private/qquickrhiitem_p.h>
+#include "testrhiitem.h"
+
+class tst_QQuickRhiItem : public QQmlDataTest
+{
+ Q_OBJECT
+
+public:
+ tst_QQuickRhiItem();
+
+private slots:
+ void initTestCase() override;
+ void cleanupTestCase();
+ void rhiItem();
+ void properties();
+};
+
+tst_QQuickRhiItem::tst_QQuickRhiItem()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
+void tst_QQuickRhiItem::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ qDebug() << "RHI backend:" << QSGRhiSupport::instance()->rhiBackendName();
+}
+
+void tst_QQuickRhiItem::cleanupTestCase()
+{
+}
+
+void tst_QQuickRhiItem::rhiItem()
+{
+ if (QGuiApplication::platformName() == QLatin1String("offscreen")
+ || QGuiApplication::platformName() == QLatin1String("minimal"))
+ {
+ QSKIP("Skipping on offscreen/minimal");
+ }
+
+ // Load up a scene that instantiates a TestRhiItem, which in turn
+ // renders a triangle with QRhi into a QRhiTexture and then draws
+ // a quad textured with it.
+
+ QQuickView view;
+ view.setSource(testFileUrl(QLatin1String("test.qml")));
+ view.setResizeMode(QQuickView::SizeViewToRootObject);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ if (!QSGRendererInterface::isApiRhiBased(view.rendererInterface()->graphicsApi()))
+ QSKIP("Scenegraph does not use QRhi, test is pointless");
+
+ QImage result = view.grabWindow();
+ QVERIFY(!result.isNull());
+
+ const int tolerance = 5;
+
+ // The result is a red triangle in the center of the view, confirm at least one pixel.
+ QRgb a = result.pixel(result.width() / 2, result.height() / 2);
+ QRgb b = QColor(Qt::red).rgb();
+ QVERIFY(qAbs(qRed(a) - qRed(b)) <= tolerance
+ && qAbs(qGreen(a) - qGreen(b)) <= tolerance
+ && qAbs(qBlue(a) - qBlue(b)) <= tolerance);
+}
+
+void tst_QQuickRhiItem::properties()
+{
+ if (QGuiApplication::platformName() == QLatin1String("offscreen")
+ || QGuiApplication::platformName() == QLatin1String("minimal"))
+ {
+ QSKIP("Skipping on offscreen/minimal");
+ }
+
+ QQuickView view;
+ view.setSource(testFileUrl(QLatin1String("test.qml")));
+ view.setResizeMode(QQuickView::SizeViewToRootObject);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ if (!QSGRendererInterface::isApiRhiBased(view.rendererInterface()->graphicsApi()))
+ QSKIP("Scenegraph does not use QRhi, test is pointless");
+
+ QQuickRhiItem *item = view.rootObject()->findChild<QQuickRhiItem *>("rhiitem");
+ QVERIFY(item);
+
+ view.grabWindow(); // to ensure there's a frame
+ // not quite safe in theory (threads etc.) but we know it works in practice
+ QQuickRhiItemPrivate *d = QQuickRhiItemPrivate::get(item);
+ QVERIFY(d->node);
+ TestRenderer *r = static_cast<TestRenderer *>(d->node->m_renderer.get());
+ QVERIFY(r);
+ QRhi *rhi = r->rhi();
+ QVERIFY(rhi);
+
+ QVERIFY(r->colorTexture());
+ QVERIFY(!r->msaaColorBuffer());
+ QVERIFY(r->depthStencilBuffer());
+ QVERIFY(r->renderTarget());
+ QCOMPARE(item->effectiveColorBufferSize(), r->colorTexture()->pixelSize());
+
+ QCOMPARE(item->sampleCount(), 1);
+ item->setSampleCount(4);
+
+ view.grabWindow(); // just to ensure the render thread rendered with the changed properties
+
+ if (rhi->supportedSampleCounts().contains(4)) {
+ QVERIFY(!r->colorTexture());
+ QVERIFY(r->msaaColorBuffer());
+ QCOMPARE(r->msaaColorBuffer()->sampleCount(), 4);
+ QCOMPARE(r->depthStencilBuffer()->sampleCount(), 4);
+ QCOMPARE(item->effectiveColorBufferSize(), r->msaaColorBuffer()->pixelSize());
+ }
+
+ QCOMPARE(item->alphaBlending(), false);
+ item->setAlphaBlending(true);
+
+ QCOMPARE(item->isMirrorVerticallyEnabled(), false);
+ item->setMirrorVertically(true);
+
+ item->setSampleCount(1);
+ item->setFixedColorBufferWidth(123);
+ item->setFixedColorBufferHeight(456);
+ view.grabWindow();
+ QCOMPARE(r->colorTexture()->pixelSize(), QSize(123, 456));
+ QCOMPARE(item->fixedColorBufferWidth(), 123);
+ QCOMPARE(item->fixedColorBufferHeight(), 456);
+ QCOMPARE(item->effectiveColorBufferSize(), QSize(123, 456));
+
+ QImage result = view.grabWindow();
+ QVERIFY(!result.isNull());
+ const int tolerance = 5;
+ QRgb a = result.pixel(result.width() / 2, result.height() / 2);
+ QRgb b = QColor(Qt::red).rgb();
+ QVERIFY(qAbs(qRed(a) - qRed(b)) <= tolerance
+ && qAbs(qGreen(a) - qGreen(b)) <= tolerance
+ && qAbs(qBlue(a) - qBlue(b)) <= tolerance);
+}
+
+#include "tst_qquickrhiitem.moc"
+
+QTEST_MAIN(tst_QQuickRhiItem)
diff --git a/tests/auto/quick/qquickscreen/CMakeLists.txt b/tests/auto/quick/qquickscreen/CMakeLists.txt
index 65c5538be3..0b269c736c 100644
--- a/tests/auto/quick/qquickscreen/CMakeLists.txt
+++ b/tests/auto/quick/qquickscreen/CMakeLists.txt
@@ -1,21 +1,35 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickscreen.pro.
#####################################################################
## tst_qquickscreen Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickscreen LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
qt_internal_add_test(tst_qquickscreen
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickscreen.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
)
## Scopes:
@@ -23,10 +37,10 @@ qt_internal_add_test(tst_qquickscreen
qt_internal_extend_target(tst_qquickscreen CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickscreen CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp b/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp
index ff6031619c..74d50eed22 100644
--- a/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp
+++ b/tests/auto/quick/qquickscreen/tst_qquickscreen.cpp
@@ -1,49 +1,33 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QDebug>
#include <QQmlEngine>
+#include <QQmlComponent>
#include <QtQuick/QQuickItem>
#include <QtQuick/QQuickView>
#include <QtGui/QScreen>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtQuick/private/qquickscreen_p.h>
#include <QDebug>
class tst_qquickscreen : public QQmlDataTest
{
Q_OBJECT
+public:
+ tst_qquickscreen();
+
private slots:
void basicProperties();
void screenOnStartup();
void fullScreenList();
};
+tst_qquickscreen::tst_qquickscreen()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
void tst_qquickscreen::basicProperties()
{
QQuickView view;
@@ -66,7 +50,7 @@ void tst_qquickscreen::basicProperties()
QCOMPARE(screen->geometry().x(), root->property("vx").toInt());
QCOMPARE(screen->geometry().y(), root->property("vy").toInt());
- QVERIFY(root->property("screenCount").toInt() == QGuiApplication::screens().count());
+ QVERIFY(root->property("screenCount").toInt() == QGuiApplication::screens().size());
}
void tst_qquickscreen::screenOnStartup()
@@ -105,7 +89,7 @@ void tst_qquickscreen::fullScreenList()
QVERIFY(screensArray.isArray());
int length = screensArray.property("length").toInt();
const QList<QScreen *> screenList = QGuiApplication::screens();
- QVERIFY(length == screenList.count());
+ QVERIFY(length == screenList.size());
for (int i = 0; i < length; ++i) {
QQuickScreenInfo *info = qobject_cast<QQuickScreenInfo *>(screensArray.property(i).toQObject());
diff --git a/tests/auto/quick/qquickshadereffect/CMakeLists.txt b/tests/auto/quick/qquickshadereffect/CMakeLists.txt
index 6eebadeedf..9aa9140337 100644
--- a/tests/auto/quick/qquickshadereffect/CMakeLists.txt
+++ b/tests/auto/quick/qquickshadereffect/CMakeLists.txt
@@ -1,21 +1,28 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickshadereffect.pro.
#####################################################################
## tst_qquickshadereffect Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickshadereffect LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qquickshadereffect
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickshadereffect.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
)
# Resources:
@@ -23,6 +30,7 @@ set(resources_resource_files
"data/+qsb/red.frag"
"data/+qsb/test.frag"
"data/+qsb/test.vert"
+ "data/+qsb/testprop.frag"
"data/MyIcon.qml"
"data/connections.qml"
"data/deleteShaderEffectSource.qml"
@@ -34,6 +42,8 @@ set(resources_resource_files
"data/test.frag"
"data/test.vert"
"data/twoImagesOneShaderEffect.qml"
+ "data/testprop.frag"
+ "data/testProperties.qml"
)
qt_internal_add_resource(tst_qquickshadereffect "resources"
@@ -49,10 +59,10 @@ qt_internal_add_resource(tst_qquickshadereffect "resources"
qt_internal_extend_target(tst_qquickshadereffect CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickshadereffect CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickshadereffect/data/+qsb/testprop.frag b/tests/auto/quick/qquickshadereffect/data/+qsb/testprop.frag
new file mode 100644
index 0000000000..97d2430699
--- /dev/null
+++ b/tests/auto/quick/qquickshadereffect/data/+qsb/testprop.frag
Binary files differ
diff --git a/tests/auto/quick/qquickshadereffect/data/MyIcon.qml b/tests/auto/quick/qquickshadereffect/data/MyIcon.qml
index 0ed8f36580..f48b3698e1 100644
--- a/tests/auto/quick/qquickshadereffect/data/MyIcon.qml
+++ b/tests/auto/quick/qquickshadereffect/data/MyIcon.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.4
diff --git a/tests/auto/quick/qquickshadereffect/data/compile.bat b/tests/auto/quick/qquickshadereffect/data/compile.bat
index 6b276aea69..112acfb1c0 100644
--- a/tests/auto/quick/qquickshadereffect/data/compile.bat
+++ b/tests/auto/quick/qquickshadereffect/data/compile.bat
@@ -2,3 +2,5 @@ qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/test.vert test_rhi.ver
qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/red.frag red_rhi.frag
qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/test.frag test_rhi.frag
+
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/testprop.frag testprop.frag
diff --git a/tests/auto/quick/qquickshadereffect/data/deleteShaderEffectSource.qml b/tests/auto/quick/qquickshadereffect/data/deleteShaderEffectSource.qml
index 95fdfee91a..eee1e212e7 100644
--- a/tests/auto/quick/qquickshadereffect/data/deleteShaderEffectSource.qml
+++ b/tests/auto/quick/qquickshadereffect/data/deleteShaderEffectSource.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
import QtQuick.Particles 2.0
diff --git a/tests/auto/quick/qquickshadereffect/data/deleteSourceItem.qml b/tests/auto/quick/qquickshadereffect/data/deleteSourceItem.qml
index 9257e9a01a..88e44bab68 100644
--- a/tests/auto/quick/qquickshadereffect/data/deleteSourceItem.qml
+++ b/tests/auto/quick/qquickshadereffect/data/deleteSourceItem.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
import QtQuick.Particles 2.0
diff --git a/tests/auto/quick/qquickshadereffect/data/hideParent.qml b/tests/auto/quick/qquickshadereffect/data/hideParent.qml
index e862dfaa01..2566cc276e 100644
--- a/tests/auto/quick/qquickshadereffect/data/hideParent.qml
+++ b/tests/auto/quick/qquickshadereffect/data/hideParent.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/qquickshadereffect/data/testProperties.qml b/tests/auto/quick/qquickshadereffect/data/testProperties.qml
new file mode 100644
index 0000000000..e513cf0406
--- /dev/null
+++ b/tests/auto/quick/qquickshadereffect/data/testProperties.qml
@@ -0,0 +1,48 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Item {
+ id: root
+ width: 640
+ height: 480
+
+ property bool finished
+
+ Rectangle {
+ id: rect
+ color: "red"
+ width: 300
+ height: 300
+ Text {
+ text: "Hello world"
+ anchors.centerIn: parent
+ color: "#00FF00"
+ }
+ layer.enabled: true
+ layer.effect: ShaderEffect {
+ objectName: "shaderEffect"
+ fragmentShader: "qrc:/data/testprop.frag"
+
+ // This is intended to exercise the uniform data copy logic in
+ // QSGRhiShaderEffectMaterialShader::updateUniformData() to see if
+ // the undocumented combinations for passing in a vector with more
+ // components than the shader variable works, and no assertions or
+ // crashes occur.
+
+ property variant aVec4: Qt.point(0.1, 0.0) // third and fourth are 0
+ property variant aVec3: Qt.point(0.1, 0.5) // third will be 0
+ property variant aVec2: Qt.vector4d(0.1, 0.5, 1.0, 1.0) // only first two are used
+ property real f: 0.0
+ property variant aFloat: Qt.size(0.1 + f, 0.1) // only first is used
+
+ NumberAnimation on f {
+ from: 0.0
+ to: 1.0
+ duration: 1000
+ onFinished: root.finished = true
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickshadereffect/data/testprop.frag b/tests/auto/quick/qquickshadereffect/data/testprop.frag
new file mode 100644
index 0000000000..86f007bcb4
--- /dev/null
+++ b/tests/auto/quick/qquickshadereffect/data/testprop.frag
@@ -0,0 +1,28 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D source;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ vec4 aVec4;
+ vec3 aVec3;
+ vec2 aVec2;
+ float aFloat;
+};
+
+void main()
+{
+ vec4 c = texture(source, qt_TexCoord0);
+ vec4 v = aVec4;
+ v.rgb += aVec3;
+ v.rg += aVec2;
+ v.r += aFloat;
+ c *= v;
+ if (c.a == 0.0)
+ c.a = 1.0;
+ fragColor = c * qt_Opacity;
+}
diff --git a/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml b/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml
index 46d81f2106..b32dc7fbb6 100644
--- a/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml
+++ b/tests/auto/quick/qquickshadereffect/data/twoImagesOneShaderEffect.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Canonical Limited and/or its subsidiary(-ies).
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.4
diff --git a/tests/auto/quick/qquickshadereffect/resources.qrc b/tests/auto/quick/qquickshadereffect/resources.qrc
deleted file mode 100644
index 50c4c82036..0000000000
--- a/tests/auto/quick/qquickshadereffect/resources.qrc
+++ /dev/null
@@ -1,18 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>data/connections.qml</file>
- <file>data/deleteShaderEffectSource.qml</file>
- <file>data/deleteSourceItem.qml</file>
- <file>data/MyIcon.qml</file>
- <file>data/star.png</file>
- <file>data/test.frag</file>
- <file>data/test.vert</file>
- <file>data/twoImagesOneShaderEffect.qml</file>
- <file>data/red.frag</file>
- <file>data/+qsb/test.vert</file>
- <file>data/+qsb/test.frag</file>
- <file>data/+qsb/red.frag</file>
- <file>data/hideParent.qml</file>
- <file>data/opacity-mask.frag.qsb</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp
index 4115c27910..27cf89407a 100644
--- a/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp
+++ b/tests/auto/quick/qquickshadereffect/tst_qquickshadereffect.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
@@ -32,9 +7,11 @@
#include <QByteArray>
#include <private/qquickshadereffect_p.h>
#include <QMatrix4x4>
-#include <QtQuick/QQuickView>
#include <QtQml/QQmlEngine>
-#include "../../shared/util.h"
+#include <QtQuick/QQuickView>
+#include <QtQuick/private/qquickshadereffectsource_p.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
class TestShaderEffect : public QQuickShaderEffect
{
@@ -56,8 +33,15 @@ public:
int signalsConnected = 0;
protected:
- void connectNotify(const QMetaMethod &) override { ++signalsConnected; }
- void disconnectNotify(const QMetaMethod &) override { --signalsConnected; }
+ void connectNotify(const QMetaMethod &s) override {
+ if (s.name() == "sourceChanged")
+ ++signalsConnected;
+ }
+ void disconnectNotify(const QMetaMethod &s) override
+ {
+ if (s.name() == "sourceChanged")
+ --signalsConnected;
+ }
signals:
void dummyChanged();
@@ -83,6 +67,7 @@ private slots:
void withoutQmlEngine();
void hideParent();
+ void testPropertyMappings();
private:
enum PresenceFlags {
@@ -95,6 +80,7 @@ private:
};
tst_qquickshadereffect::tst_qquickshadereffect()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
qmlRegisterType<TestShaderEffect>("ShaderEffectTest", 1, 0, "TestShaderEffect");
}
@@ -111,17 +97,17 @@ void tst_qquickshadereffect::cleanupTestCase()
void tst_qquickshadereffect::testConnection()
{
// verify that the property notify signal is connected
- QQuickView *view = new QQuickView(nullptr);
- view->setSource(QUrl(QStringLiteral("qrc:/data/connections.qml")));
+ QQuickView view;
+ QVERIFY(QQuickTest::initView(view, QStringLiteral("qrc:/data/connections.qml")));
- auto *shaderEffectItem = qobject_cast<TestShaderEffect*>(view->rootObject());
+ auto *shaderEffectItem = qobject_cast<TestShaderEffect*>(view.rootObject());
QVERIFY(shaderEffectItem);
QCOMPARE(shaderEffectItem->signalsConnected, 0);
- view->show();
- QVERIFY(QTest::qWaitForWindowExposed(view));
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
- QSGRendererInterface *rif = view->rendererInterface();
+ QSGRendererInterface *rif = view.rendererInterface();
if (rif && rif->graphicsApi() != QSGRendererInterface::Software)
QCOMPARE(shaderEffectItem->signalsConnected, 1);
}
@@ -129,66 +115,62 @@ void tst_qquickshadereffect::testConnection()
void tst_qquickshadereffect::deleteSourceItem()
{
// purely to ensure that deleting the sourceItem of a shader doesn't cause a crash
- QQuickView *view = new QQuickView(nullptr);
- view->setSource(QUrl(QStringLiteral("qrc:/data/deleteSourceItem.qml")));
- view->show();
- QVERIFY(QTest::qWaitForWindowExposed(view));
- QVERIFY(view);
- QObject *obj = view->rootObject();
+ QQuickView view;
+ QVERIFY(QQuickTest::showView(view, QStringLiteral("qrc:/data/deleteSourceItem.qml")));
+ QObject *obj = view.rootObject();
QVERIFY(obj);
QMetaObject::invokeMethod(obj, "setDeletedSourceItem");
- QTest::qWait(50);
- delete view;
+ const auto shaderEffectSource = obj->findChild<QQuickShaderEffectSource*>();
+ QVERIFY(shaderEffectSource);
+ QTRY_VERIFY(!shaderEffectSource->sourceItem());
}
void tst_qquickshadereffect::deleteShaderEffectSource()
{
- // purely to ensure that deleting the sourceItem of a shader doesn't cause a crash
- QQuickView *view = new QQuickView(nullptr);
- view->setSource(QUrl(QStringLiteral("qrc:/data/deleteShaderEffectSource.qml")));
- view->show();
- QVERIFY(QTest::qWaitForWindowExposed(view));
- QVERIFY(view);
- QObject *obj = view->rootObject();
+ // purely to ensure that deleting the ShaderEffectSource doesn't cause a crash
+ QQuickView view;
+ QVERIFY(QQuickTest::showView(view, QStringLiteral("qrc:/data/deleteShaderEffectSource.qml")));
+ QObject *obj = view.rootObject();
QVERIFY(obj);
+ const QPointer<QQuickShaderEffectSource> shaderEffectSource = obj->findChild<QQuickShaderEffectSource*>();
+ QVERIFY(shaderEffectSource);
QMetaObject::invokeMethod(obj, "setDeletedShaderEffectSource");
- QTest::qWait(50);
- delete view;
+ QTRY_VERIFY(shaderEffectSource);
}
void tst_qquickshadereffect::twoImagesOneShaderEffect()
{
// Don't crash when having a ShaderEffect and an Image sharing the texture via supportsAtlasTextures
- QQuickView *view = new QQuickView(nullptr);
- view->setSource(QUrl(QStringLiteral("qrc:/data/twoImagesOneShaderEffect.qml")));
- view->show();
- QVERIFY(QTest::qWaitForWindowExposed(view));
- QVERIFY(view);
- QObject *obj = view->rootObject();
+ QQuickView view;
+ QVERIFY(QQuickTest::showView(view, QStringLiteral("qrc:/data/twoImagesOneShaderEffect.qml")));
+ QObject *obj = view.rootObject();
QVERIFY(obj);
- delete view;
}
void tst_qquickshadereffect::withoutQmlEngine()
{
// using a shader without QML engine used to crash
- auto window = new QQuickWindow;
- auto shaderEffect = new TestShaderEffect(window->contentItem());
+ const QQuickWindow window;
+ auto shaderEffect = new TestShaderEffect(window.contentItem());
shaderEffect->setVertexShader(QUrl());
QVERIFY(shaderEffect->isComponentComplete());
- delete window;
}
// QTBUG-86402: hiding the parent of an item that uses an effect should not cause a crash.
void tst_qquickshadereffect::hideParent()
{
- QScopedPointer<QQuickView> view(new QQuickView);
- view->setSource(QUrl(QStringLiteral("qrc:/data/hideParent.qml")));
- QCOMPARE(view->status(), QQuickView::Ready);
- view->show();
- QVERIFY(QTest::qWaitForWindowExposed(view.data()));
+ QQuickView view;
+ view.setSource(QUrl(QStringLiteral("qrc:/data/hideParent.qml")));
+ QVERIFY(QQuickTest::showView(view, QStringLiteral("qrc:/data/hideParent.qml")));
// Should finish without crashing.
- QTRY_VERIFY(view->rootObject()->property("finished").toBool());
+ QTRY_VERIFY(view.rootObject()->property("finished").toBool());
+}
+
+void tst_qquickshadereffect::testPropertyMappings()
+{
+ QQuickView view;
+ view.setSource(QUrl(QStringLiteral("qrc:/data/testProperties.qml")));
+ QTRY_VERIFY(view.rootObject()->property("finished").toBool());
}
QTEST_MAIN(tst_qquickshadereffect)
diff --git a/tests/auto/quick/qquickshape/BLACKLIST b/tests/auto/quick/qquickshape/BLACKLIST
new file mode 100644
index 0000000000..f0d5bcd351
--- /dev/null
+++ b/tests/auto/quick/qquickshape/BLACKLIST
@@ -0,0 +1,19 @@
+# QTBUG-103094
+[render]
+android
+[renderWithMultipleSp]
+android
+[radialGrad]
+android
+[conicalGrad]
+android
+[renderPolyline]
+android
+[renderMultiline]
+android
+[polylineDataTypes]
+android
+[multilineDataTypes]
+android
+[multilineStronglyTyped]
+android
diff --git a/tests/auto/quick/qquickshape/CMakeLists.txt b/tests/auto/quick/qquickshape/CMakeLists.txt
index 325d812ed2..b7b536e29d 100644
--- a/tests/auto/quick/qquickshape/CMakeLists.txt
+++ b/tests/auto/quick/qquickshape/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickshape.pro.
#####################################################################
## tst_qquickshape Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickshape LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,22 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickshape
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickshape.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
Qt::QuickShapesPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -38,16 +40,16 @@ qt_internal_add_test(tst_qquickshape
#####################################################################
qt_internal_extend_target(tst_qquickshape CONDITION TARGET Qt::Widgets
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Widgets
)
qt_internal_extend_target(tst_qquickshape CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickshape CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickshape/data/multiline.qml b/tests/auto/quick/qquickshape/data/multiline.qml
index ad07506972..edf92057c2 100644
--- a/tests/auto/quick/qquickshape/data/multiline.qml
+++ b/tests/auto/quick/qquickshape/data/multiline.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.14
import QtQuick.Shapes 1.14
diff --git a/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml b/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml
index 46d650e053..64c61f4331 100644
--- a/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml
+++ b/tests/auto/quick/qquickshape/data/multilineStronglyTyped.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.14
import QtQuick.Shapes 1.14
diff --git a/tests/auto/quick/qquickshape/data/pathitem7.qml b/tests/auto/quick/qquickshape/data/pathitem7.qml
index b3ef47a4dd..43b42ecabc 100644
--- a/tests/auto/quick/qquickshape/data/pathitem7.qml
+++ b/tests/auto/quick/qquickshape/data/pathitem7.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.14
import tst_qquickpathitem 1.0
diff --git a/tests/auto/quick/qquickshape/data/pathitem8.qml b/tests/auto/quick/qquickshape/data/pathitem8.qml
index 9789ff90e0..8b78dc9429 100644
--- a/tests/auto/quick/qquickshape/data/pathitem8.qml
+++ b/tests/auto/quick/qquickshape/data/pathitem8.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.14
import QtQuick.Shapes 1.14
diff --git a/tests/auto/quick/qquickshape/data/polyline.qml b/tests/auto/quick/qquickshape/data/polyline.qml
index e62d952ae7..9c81bf4031 100644
--- a/tests/auto/quick/qquickshape/data/polyline.qml
+++ b/tests/auto/quick/qquickshape/data/polyline.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.14
import QtQuick.Shapes 1.14
diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
index 3a26f7e382..f846cc4e4f 100644
--- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp
+++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtQuick/qquickview.h>
@@ -36,12 +11,12 @@
#include <QtQuickShapes/private/qquickshape_p.h>
#include <QStandardPaths>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
-#include "../shared/visualtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
-using namespace QQuickViewTestUtil;
-using namespace QQuickVisualTestUtil;
+using namespace QQuickViewTestUtils;
+using namespace QQuickVisualTestUtils;
class PolygonProvider : public QObject
{
@@ -93,6 +68,7 @@ private:
};
tst_QQuickShape::tst_QQuickShape()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
// Force the software backend to get reliable rendering results regardless of the hw and drivers.
QQuickWindow::setGraphicsApi(QSGRendererInterface::Software);
@@ -228,7 +204,7 @@ void tst_QQuickShape::changeSignals()
QSignalSpy asyncPropSpy(obj, SIGNAL(asynchronousChanged()));
obj->setAsynchronous(true);
obj->setAsynchronous(false);
- QCOMPARE(asyncPropSpy.count(), 2);
+ QCOMPARE(asyncPropSpy.size(), 2);
QQmlListReference list(obj, "data");
QQuickShapePath *vp = qobject_cast<QQuickShapePath *>(list.at(0));
@@ -248,29 +224,29 @@ void tst_QQuickShape::changeSignals()
vp->setCapStyle(QQuickShapePath::RoundCap);
vp->setDashOffset(10);
vp->setDashPattern(QVector<qreal>() << 1 << 2 << 3 << 4);
- QCOMPARE(strokeColorPropSpy.count(), 1);
- QCOMPARE(vpChangeSpy.count(), 10);
+ QCOMPARE(strokeColorPropSpy.size(), 1);
+ QCOMPARE(vpChangeSpy.size(), 10);
// Verify that property changes from Path and its elements bubble up and result in shapePathChanged().
QQuickPath *path = vp;
path->setStartX(30);
- QCOMPARE(vpChangeSpy.count(), 11);
+ QCOMPARE(vpChangeSpy.size(), 11);
QQmlListReference pathList(path, "pathElements");
qobject_cast<QQuickPathLine *>(pathList.at(1))->setY(200);
- QCOMPARE(vpChangeSpy.count(), 12);
+ QCOMPARE(vpChangeSpy.size(), 12);
// Verify that property changes from the gradient bubble up and result in shapePathChanged().
vp->setFillGradient(g);
- QCOMPARE(vpChangeSpy.count(), 13);
+ QCOMPARE(vpChangeSpy.size(), 13);
QQuickShapeLinearGradient *lgrad = qobject_cast<QQuickShapeLinearGradient *>(g);
lgrad->setX2(200);
- QCOMPARE(vpChangeSpy.count(), 14);
+ QCOMPARE(vpChangeSpy.size(), 14);
QQmlListReference stopList(lgrad, "stops");
QCOMPARE(stopList.count(), 5);
qobject_cast<QQuickGradientStop *>(stopList.at(1))->setPosition(0.3);
- QCOMPARE(vpChangeSpy.count(), 15);
+ QCOMPARE(vpChangeSpy.size(), 15);
qobject_cast<QQuickGradientStop *>(stopList.at(1))->setColor(Qt::black);
- QCOMPARE(vpChangeSpy.count(), 16);
+ QCOMPARE(vpChangeSpy.size(), 16);
}
void tst_QQuickShape::render()
@@ -281,19 +257,18 @@ void tst_QQuickShape::render()
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimal platforms", Abort);
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QImage img = window->grabWindow();
QVERIFY(!img.isNull());
- QImage refImg(testFileUrl("pathitem3.png").toLocalFile());
+ QImage refImg(testFile("pathitem3.png"));
QVERIFY(!refImg.isNull());
QString errorMessage;
const QImage actualImg = img.convertToFormat(refImg.format());
- QVERIFY2(QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage),
+ QVERIFY2(QQuickVisualTestUtils::compareImages(actualImg, refImg, &errorMessage),
qPrintable(errorMessage));
}
@@ -305,19 +280,18 @@ void tst_QQuickShape::renderWithMultipleSp()
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimal platforms", Abort);
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QImage img = window->grabWindow();
QVERIFY(!img.isNull());
- QImage refImg(testFileUrl("pathitem4.png").toLocalFile());
+ QImage refImg(testFile("pathitem4.png"));
QVERIFY(!refImg.isNull());
QString errorMessage;
const QImage actualImg = img.convertToFormat(refImg.format());
- QVERIFY2(QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage),
+ QVERIFY2(QQuickVisualTestUtils::compareImages(actualImg, refImg, &errorMessage),
qPrintable(errorMessage));
}
@@ -329,19 +303,18 @@ void tst_QQuickShape::radialGrad()
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimal platforms", Abort);
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QImage img = window->grabWindow();
QVERIFY(!img.isNull());
- QImage refImg(testFileUrl("pathitem5.png").toLocalFile());
+ QImage refImg(testFile("pathitem5.png"));
QVERIFY(!refImg.isNull());
QString errorMessage;
const QImage actualImg = img.convertToFormat(refImg.format());
- QVERIFY2(QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage),
+ QVERIFY2(QQuickVisualTestUtils::compareImages(actualImg, refImg, &errorMessage),
qPrintable(errorMessage));
}
@@ -353,19 +326,18 @@ void tst_QQuickShape::conicalGrad()
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimal platforms", Abort);
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QImage img = window->grabWindow();
QVERIFY(!img.isNull());
- QImage refImg(testFileUrl("pathitem6.png").toLocalFile());
+ QImage refImg(testFile("pathitem6.png"));
QVERIFY(!refImg.isNull());
QString errorMessage;
const QImage actualImg = img.convertToFormat(refImg.format());
- QVERIFY2(QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage),
+ QVERIFY2(QQuickVisualTestUtils::compareImages(actualImg, refImg, &errorMessage),
qPrintable(errorMessage));
}
@@ -377,19 +349,18 @@ void tst_QQuickShape::renderPolyline()
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimal platforms", Abort);
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QImage img = window->grabWindow();
QVERIFY(!img.isNull());
- QImage refImg(testFileUrl("pathitem3.png").toLocalFile()); // It's a recreation of pathitem3 using PathPolyline
+ QImage refImg(testFile("pathitem3.png")); // It's a recreation of pathitem3 using PathPolyline
QVERIFY(!refImg.isNull());
QString errorMessage;
const QImage actualImg = img.convertToFormat(refImg.format());
- const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ const bool res = QQuickVisualTestUtils::compareImages(actualImg, refImg, &errorMessage);
if (!res) { // For visual inspection purposes.
QTest::qWait(5000);
const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
@@ -406,19 +377,18 @@ void tst_QQuickShape::renderMultiline()
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimal platforms", Abort);
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QImage img = window->grabWindow();
QVERIFY(!img.isNull());
- QImage refImg(testFileUrl("pathitem8.png").toLocalFile());
+ QImage refImg(testFile("pathitem8.png"));
QVERIFY(!refImg.isNull());
QString errorMessage;
const QImage actualImg = img.convertToFormat(refImg.format());
- const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ const bool res = QQuickVisualTestUtils::compareImages(actualImg, refImg, &errorMessage);
if (!res) { // For visual inspection purposes.
QTest::qWait(5000);
const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
@@ -472,19 +442,18 @@ void tst_QQuickShape::polylineDataTypes()
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimal platforms", Abort);
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QImage img = window->grabWindow();
QVERIFY(!img.isNull());
- QImage refImg(testFileUrl("polyline.png").toLocalFile());
+ QImage refImg(testFile("polyline.png"));
QVERIFY(!refImg.isNull());
QString errorMessage;
const QImage actualImg = img.convertToFormat(refImg.format());
- const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ const bool res = QQuickVisualTestUtils::compareImages(actualImg, refImg, &errorMessage);
if (!res) { // For visual inspection purposes.
QTest::qWait(5000);
const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
@@ -623,19 +592,18 @@ void tst_QQuickShape::multilineDataTypes()
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimal platforms", Abort);
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QImage img = window->grabWindow();
QVERIFY(!img.isNull());
- QImage refImg(testFileUrl("multiline.png").toLocalFile());
+ QImage refImg(testFile("multiline.png"));
QVERIFY(!refImg.isNull());
QString errorMessage;
const QImage actualImg = img.convertToFormat(refImg.format());
- const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ const bool res = QQuickVisualTestUtils::compareImages(actualImg, refImg, &errorMessage);
if (!res) { // For visual inspection purposes.
QTest::qWait(5000);
const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
@@ -671,19 +639,18 @@ void tst_QQuickShape::multilineStronglyTyped()
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
provider->setPaths(m_lowPolyLogo);
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimal platforms", Abort);
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QImage img = window->grabWindow();
QVERIFY(!img.isNull());
- QImage refImg(testFileUrl("multiline.png").toLocalFile());
+ QImage refImg(testFile("multiline.png"));
QVERIFY(!refImg.isNull());
QString errorMessage;
const QImage actualImg = img.convertToFormat(refImg.format());
- const bool res = QQuickVisualTestUtil::compareImages(actualImg, refImg, &errorMessage);
+ const bool res = QQuickVisualTestUtils::compareImages(actualImg, refImg, &errorMessage);
if (!res) { // For visual inspection purposes.
QTest::qWait(5000);
const QString &tempLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
diff --git a/tests/auto/quick/qquickshortcut/CMakeLists.txt b/tests/auto/quick/qquickshortcut/CMakeLists.txt
index dda488abff..1056534634 100644
--- a/tests/auto/quick/qquickshortcut/CMakeLists.txt
+++ b/tests/auto/quick/qquickshortcut/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickshortcut.pro.
#####################################################################
## tst_qquickshortcut Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickshortcut LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,14 +21,12 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickshortcut
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickshortcut.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Qml
Qt::Quick
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -27,16 +34,16 @@ qt_internal_add_test(tst_qquickshortcut
#####################################################################
qt_internal_extend_target(tst_qquickshortcut CONDITION TARGET Qt::Widgets
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::QuickWidgets
)
qt_internal_extend_target(tst_qquickshortcut CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickshortcut CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickshortcut/data/embedded.qml b/tests/auto/quick/qquickshortcut/data/embedded.qml
new file mode 100644
index 0000000000..4b80363b70
--- /dev/null
+++ b/tests/auto/quick/qquickshortcut/data/embedded.qml
@@ -0,0 +1,20 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+
+Rectangle {
+ id: root
+
+ width: 300
+ height: 300
+
+ property bool activated: false
+ property alias shortcut: shortcut
+
+ Shortcut {
+ id: shortcut
+ onActivated: root.activated = true
+ }
+}
diff --git a/tests/auto/quick/qquickshortcut/data/multiple.qml b/tests/auto/quick/qquickshortcut/data/multiple.qml
index 2b58327cf0..0ecfbc44fc 100644
--- a/tests/auto/quick/qquickshortcut/data/multiple.qml
+++ b/tests/auto/quick/qquickshortcut/data/multiple.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.9
import QtQuick.Window 2.2
diff --git a/tests/auto/quick/qquickshortcut/data/shortcuts.qml b/tests/auto/quick/qquickshortcut/data/shortcuts.qml
index b8b69d0b3d..cf88c93eee 100644
--- a/tests/auto/quick/qquickshortcut/data/shortcuts.qml
+++ b/tests/auto/quick/qquickshortcut/data/shortcuts.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.5
import QtQuick.Window 2.2
diff --git a/tests/auto/quick/qquickshortcut/data/shortcutsRect.qml b/tests/auto/quick/qquickshortcut/data/shortcutsRect.qml
index 9aced4e530..80d337aeda 100644
--- a/tests/auto/quick/qquickshortcut/data/shortcutsRect.qml
+++ b/tests/auto/quick/qquickshortcut/data/shortcutsRect.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.5
diff --git a/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp b/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp
index 6351b97fb3..312f77e99a 100644
--- a/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp
+++ b/tests/auto/quick/qquickshortcut/tst_qquickshortcut.cpp
@@ -1,46 +1,28 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/qtest.h>
#include <QtQuick/qquickwindow.h>
#include <QtQml/qqmlapplicationengine.h>
#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickview.h>
#include <QtTest/qsignalspy.h>
+#ifdef QT_WIDGETS_LIB
+#include <QtWidgets/qboxlayout.h>
+#endif
#ifdef QT_QUICKWIDGETS_LIB
#include <QtQuickWidgets/qquickwidget.h>
#endif
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
class tst_QQuickShortcut : public QQmlDataTest
{
Q_OBJECT
+public:
+ tst_QQuickShortcut();
+
private slots:
void standardShortcuts_data();
void standardShortcuts();
@@ -56,6 +38,8 @@ private slots:
void matcher();
void multiple_data();
void multiple();
+ void embedded_data();
+ void embedded();
#ifdef QT_QUICKWIDGETS_LIB
void quickWidgetShortcuts_data();
void quickWidgetShortcuts();
@@ -83,6 +67,11 @@ static QVariant shortcutMap(const QVariant &key, bool enabled = true, bool autoR
return shortcutMap(key, Qt::WindowShortcut, enabled, autoRepeat);
}
+tst_QQuickShortcut::tst_QQuickShortcut()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
void tst_QQuickShortcut::standardShortcuts_data()
{
QTest::addColumn<QKeySequence::StandardKey>("standardKey");
@@ -594,6 +583,87 @@ void tst_QQuickShortcut::contextChange()
QCOMPARE(inactiveWindow->property("activated").toBool(), activated);
}
+void tst_QQuickShortcut::embedded_data()
+{
+ QTest::addColumn<Qt::Key>("testKey");
+ QTest::addColumn<Qt::KeyboardModifiers>("testModifiers");
+ QTest::addColumn<QString>("windowShortcutSequence");
+ QTest::addColumn<bool>("windowShortcutActivated");
+
+ QTest::newRow("windowActivated") << Qt::Key_W << (Qt::ControlModifier|Qt::AltModifier)
+ << "Ctrl+Alt+W" << true;
+}
+
+void tst_QQuickShortcut::embedded()
+{
+#ifndef QT_WIDGETS_LIB
+ QSKIP("Skipping due to QT_WIDGETS_LIB is not defined");
+#else
+ QFETCH(Qt::Key, testKey);
+ QFETCH(Qt::KeyboardModifiers, testModifiers);
+ QFETCH(QString, windowShortcutSequence);
+ QFETCH(bool, windowShortcutActivated);
+
+ QWidget window;
+ QVBoxLayout *layout = new QVBoxLayout {&window};
+ QQuickView *quickView = new QQuickView;
+ quickView->setResizeMode(QQuickView::SizeRootObjectToView);
+ quickView->setSource(testFileUrl("embedded.qml"));
+
+ QWidget *container = QWidget::createWindowContainer(quickView);
+ container->setMinimumSize(quickView->size());
+ container->setFocusPolicy(Qt::TabFocus);
+
+ QWidget *widget = new QWidget;
+ // We will set focus to the widget and its default is NoFocus.
+ widget->setFocusPolicy(Qt::FocusPolicy::StrongFocus);
+
+ layout->addWidget(widget);
+ layout->addWidget(container);
+
+ window.show();
+ QTRY_VERIFY(window.isVisible());
+ // The widget can get focused only when the including window has exposed.
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ widget->setFocus();
+ QTRY_VERIFY(widget->hasFocus());
+
+ // If the window-context shortcut is expected to be activated,
+ // then the QuickView window needs to be active.
+ // On Linux, the embedded QuickView window is active immediately
+ // after the containing window is active, but on Windows,
+ // the embedded QuickView window is activated after a delay
+ // once the containing window is active.
+ if (windowShortcutActivated)
+ QVERIFY(QTest::qWaitForWindowActive(quickView));
+
+ QQuickItem *item = quickView->rootObject();
+ QVERIFY(item);
+
+ QObject *windowShortcut = item->property("shortcut").value<QObject *>();
+ QVERIFY(windowShortcut);
+
+ windowShortcut->setProperty("context", Qt::WindowShortcut);
+ windowShortcut->setProperty("sequence", windowShortcutSequence);
+
+ QTest::keyPress(&window, testKey, testModifiers);
+ QTest::keyRelease(&window, testKey, testModifiers);
+ QCOMPARE(item->property("activated").toBool(), windowShortcutActivated);
+
+ quickView->requestActivate();
+ QTRY_VERIFY(quickView->isActive());
+ QVERIFY(quickView->isActive());
+
+ item->setProperty("activated", false);
+ QVERIFY(!item->property("activated").toBool());
+
+ QTest::keyPress(&window, testKey, testModifiers);
+ QTest::keyRelease(&window, testKey, testModifiers);
+ QCOMPARE(item->property("activated").toBool(), true);
+#endif
+}
+
#ifdef QT_QUICKWIDGETS_LIB
void tst_QQuickShortcut::quickWidgetShortcuts_data()
{
diff --git a/tests/auto/quick/qquicksmoothedanimation/CMakeLists.txt b/tests/auto/quick/qquicksmoothedanimation/CMakeLists.txt
index f487e786ab..2a277441c4 100644
--- a/tests/auto/quick/qquicksmoothedanimation/CMakeLists.txt
+++ b/tests/auto/quick/qquicksmoothedanimation/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquicksmoothedanimation.pro.
#####################################################################
## tst_qquicksmoothedanimation Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicksmoothedanimation LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,16 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquicksmoothedanimation
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquicksmoothedanimation.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -30,10 +37,10 @@ qt_internal_add_test(tst_qquicksmoothedanimation
qt_internal_extend_target(tst_qquicksmoothedanimation CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquicksmoothedanimation CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp b/tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp
index 14d2e858e8..7bd1b09d0f 100644
--- a/tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp
+++ b/tests/auto/quick/qquicksmoothedanimation/tst_qquicksmoothedanimation.cpp
@@ -1,37 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQuick/private/qquicksmoothedanimation_p.h>
#include <QtQuick/private/qquickrectangle_p.h>
#include <private/qqmlvaluetype_p.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
class tst_qquicksmoothedanimation : public QQmlDataTest
{
@@ -55,6 +30,7 @@ private:
};
tst_qquicksmoothedanimation::tst_qquicksmoothedanimation()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
diff --git a/tests/auto/quick/qquickspringanimation/CMakeLists.txt b/tests/auto/quick/qquickspringanimation/CMakeLists.txt
index b90f76cdf6..0fa7b717c5 100644
--- a/tests/auto/quick/qquickspringanimation/CMakeLists.txt
+++ b/tests/auto/quick/qquickspringanimation/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickspringanimation.pro.
#####################################################################
## tst_qquickspringanimation Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickspringanimation LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,16 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickspringanimation
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickspringanimation.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -30,10 +37,10 @@ qt_internal_add_test(tst_qquickspringanimation
qt_internal_extend_target(tst_qquickspringanimation CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickspringanimation CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp b/tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp
index 9042e94c75..f78157ab26 100644
--- a/tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp
+++ b/tests/auto/quick/qquickspringanimation/tst_qquickspringanimation.cpp
@@ -1,37 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQuick/qquickview.h>
#include <private/qquickspringanimation_p.h>
#include <private/qqmlvaluetype_p.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
class tst_qquickspringanimation : public QQmlDataTest
{
@@ -50,6 +25,7 @@ private:
};
tst_qquickspringanimation::tst_qquickspringanimation()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
diff --git a/tests/auto/quick/qquickspritesequence/CMakeLists.txt b/tests/auto/quick/qquickspritesequence/CMakeLists.txt
index 3955536260..c492a16183 100644
--- a/tests/auto/quick/qquickspritesequence/CMakeLists.txt
+++ b/tests/auto/quick/qquickspritesequence/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickspritesequence.pro.
#####################################################################
## tst_qquickspritesequence Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickspritesequence LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,17 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickspritesequence
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickspritesequence.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::Network
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -31,10 +38,10 @@ qt_internal_add_test(tst_qquickspritesequence
qt_internal_extend_target(tst_qquickspritesequence CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickspritesequence CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickspritesequence/data/advance.qml b/tests/auto/quick/qquickspritesequence/data/advance.qml
index f151e8ad8f..2242c28705 100644
--- a/tests/auto/quick/qquickspritesequence/data/advance.qml
+++ b/tests/auto/quick/qquickspritesequence/data/advance.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickspritesequence/data/basic.qml b/tests/auto/quick/qquickspritesequence/data/basic.qml
index f618ca8205..c2caad4f6e 100644
--- a/tests/auto/quick/qquickspritesequence/data/basic.qml
+++ b/tests/auto/quick/qquickspritesequence/data/basic.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickspritesequence/data/crashonstart.qml b/tests/auto/quick/qquickspritesequence/data/crashonstart.qml
index e20e42f263..cee94fdf91 100644
--- a/tests/auto/quick/qquickspritesequence/data/crashonstart.qml
+++ b/tests/auto/quick/qquickspritesequence/data/crashonstart.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
//QTBUG-24797
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickspritesequence/data/huge.qml b/tests/auto/quick/qquickspritesequence/data/huge.qml
index d0acc5f5a6..58d365ec84 100644
--- a/tests/auto/quick/qquickspritesequence/data/huge.qml
+++ b/tests/auto/quick/qquickspritesequence/data/huge.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickspritesequence/data/spriteaftergoal.qml b/tests/auto/quick/qquickspritesequence/data/spriteaftergoal.qml
index d0c0830236..eeee289b54 100644
--- a/tests/auto/quick/qquickspritesequence/data/spriteaftergoal.qml
+++ b/tests/auto/quick/qquickspritesequence/data/spriteaftergoal.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// QTBUG-40595
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickspritesequence/data/spritebeforegoal.qml b/tests/auto/quick/qquickspritesequence/data/spritebeforegoal.qml
index 08256ac454..b1695ff820 100644
--- a/tests/auto/quick/qquickspritesequence/data/spritebeforegoal.qml
+++ b/tests/auto/quick/qquickspritesequence/data/spritebeforegoal.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// QTBUG-40595
import QtQuick 2.0
diff --git a/tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp b/tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp
index e5d55a6871..ffaa45449f 100644
--- a/tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp
+++ b/tests/auto/quick/qquickspritesequence/tst_qquickspritesequence.cpp
@@ -1,32 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtQuick/qquickview.h>
#include <private/qquickspritesequence_p.h>
@@ -34,7 +9,7 @@ class tst_qquickspritesequence : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickspritesequence(){}
+ tst_qquickspritesequence() : QQmlDataTest(QT_QMLTEST_DATADIR) {}
private slots:
void test_properties();
diff --git a/tests/auto/quick/qquickstates/CMakeLists.txt b/tests/auto/quick/qquickstates/CMakeLists.txt
index 00b259e763..20141a489b 100644
--- a/tests/auto/quick/qquickstates/CMakeLists.txt
+++ b/tests/auto/quick/qquickstates/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickstates.pro.
#####################################################################
## tst_qquickstates Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickstates LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,28 +21,51 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickstates
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquickstates.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
+qt_internal_add_test(tst_qquickstates_no_deferred_properties
+ SOURCES
+ tst_qquickstates.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
+ DEFINES
+ QML_DISABLE_INTERNAL_DEFERRED_PROPERTIES
+)
+
## Scopes:
#####################################################################
qt_internal_extend_target(tst_qquickstates CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickstates CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+)
+
+qt_internal_extend_target(tst_qquickstates_no_deferred_properties CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=":/data"
+)
+
+qt_internal_extend_target(tst_qquickstates_no_deferred_properties CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickstates/data/anchorRewind.qml b/tests/auto/quick/qquickstates/data/anchorRewind.qml
new file mode 100644
index 0000000000..740c94cf42
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/anchorRewind.qml
@@ -0,0 +1,31 @@
+import QtQuick
+
+Item {
+ width: 400
+ height: 400
+ Item {
+ id: outer
+ anchors.fill: parent
+ Item {
+ id: inner
+ width: parent.width / 2
+ height: parent.height / 2
+ anchors.left: parent.right
+ anchors.top: parent.bottom
+ }
+ states: [
+ State {
+ when: true
+ AnchorChanges {
+ target: inner
+ anchors.left: outer.left
+ anchors.top: outer.top
+ }
+ }
+ ]
+ transitions: Transition {
+ AnchorAnimation {}
+ }
+ }
+}
+
diff --git a/tests/auto/quick/qquickstates/data/anchorRewindSize.qml b/tests/auto/quick/qquickstates/data/anchorRewindSize.qml
new file mode 100644
index 0000000000..8fbae05c6d
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/anchorRewindSize.qml
@@ -0,0 +1,30 @@
+import QtQuick
+
+Item {
+ id: root
+ width: 400
+ height: 400
+ property bool changeState: false
+ Item {
+ id: outer
+ anchors.fill: parent
+ Item {
+ id: inner
+ width: 100
+ height: 100
+ anchors.left: outer.left
+ anchors.top: outer.top
+ }
+ states: [
+ State {
+ when: root.changeState
+ AnchorChanges {
+ target: inner
+ anchors.right: outer.right
+ anchors.bottom: outer.bottom
+ }
+ }
+ ]
+ }
+}
+
diff --git a/tests/auto/quick/qquickstates/data/broken.qml b/tests/auto/quick/qquickstates/data/broken.qml
new file mode 100644
index 0000000000..8813c8bb39
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/broken.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Item {
+ states: ["test"]
+}
diff --git a/tests/auto/quick/qquickstates/data/cleanPropertyChange.qml b/tests/auto/quick/qquickstates/data/cleanPropertyChange.qml
new file mode 100644
index 0000000000..48108d6e7a
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/cleanPropertyChange.qml
@@ -0,0 +1,27 @@
+import QtQuick
+
+Rectangle {
+ id: extendedRect
+ property color extendedColor: "cyan"
+ signal didSomething()
+
+ width: 100
+ height: 100
+ color: "red"
+
+ states: State {
+ name: "green"
+ PropertyChanges {
+ extendedRect {
+ color: "yellow"
+ width: 90
+ height: 90
+ extendedColor: "blue"
+ onDidSomething: {
+ extendedRect.color = "green"
+ extendedRect.extendedColor = "green"
+ }
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickstates/data/jsValueWhen.qml b/tests/auto/quick/qquickstates/data/jsValueWhen.qml
new file mode 100644
index 0000000000..6d5eb1600c
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/jsValueWhen.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.15
+
+Item {
+ id: root
+ property var prop: null
+ property bool works: false
+ states: [
+ State {
+ name: "mystate"
+ when: root.prop
+ PropertyChanges {
+ target: root
+ works: "works"
+ }
+ }
+ ]
+ Component.onCompleted: root.prop = new Object
+}
diff --git a/tests/auto/quick/qquickstates/data/jsValueWhen2.qml b/tests/auto/quick/qquickstates/data/jsValueWhen2.qml
new file mode 100644
index 0000000000..e1f173138e
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/jsValueWhen2.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.15
+
+Item {
+ id: root
+ property var prop: null
+ property bool works: false
+ states: [
+ State {
+ name: "mystate"
+ when: root.prop
+ PropertyChanges {
+ target: root
+ works: "works"
+ }
+ }
+ ]
+ Component.onCompleted: root.prop = Qt.createQmlObject(
+ "import QtQml 2.15\nQtObject {}",
+ root, "dynamicSnippet")
+}
diff --git a/tests/auto/quick/qquickstates/data/noStateOsciallation.qml b/tests/auto/quick/qquickstates/data/noStateOsciallation.qml
new file mode 100644
index 0000000000..f0d7aeeb6d
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/noStateOsciallation.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.15
+
+Item {
+ id: root
+ property int number: 2
+ property int stateChangeCounter: 0
+
+ Item {
+ id: item
+ onStateChanged: ++stateChangeCounter
+ states: [
+ State {
+ name: "n1"
+ when: root.number === 1
+ },
+ State {
+ name: "n2"
+ when: root.number === 2
+ }
+ ]
+ }
+}
diff --git a/tests/auto/quick/qquickstates/data/parentChangeInvolvingBindings.qml b/tests/auto/quick/qquickstates/data/parentChangeInvolvingBindings.qml
new file mode 100644
index 0000000000..d3873883cd
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/parentChangeInvolvingBindings.qml
@@ -0,0 +1,43 @@
+import QtQuick
+
+Item {
+ id: root
+ property alias childWidth: firstChild.width
+ property alias childX: firstChild.x
+ property alias childRotation: firstChild.rotation
+ property double myrotation: 100
+ property double myrotation2: 200
+ height: 400
+ y: 40
+
+ Item {
+ id: firstChild
+ height: parent.height
+ width: height
+ y: parent.y
+ x: y
+ rotation: root.myrotation
+
+ Item {
+ id: inner
+ anchors.fill: parent
+ }
+ }
+
+ states: State {
+ name: "reparented"
+ ParentChange {
+ target: firstChild
+ parent: otherChild
+ width: 2 *height
+ x: 2 * y
+ rotation: root.myrotation2
+ }
+ }
+
+ Item {
+ height: parent.height
+ y: parent.y
+ id: otherChild
+ }
+}
diff --git a/tests/auto/quick/qquickstates/data/removeBindingWithTransition.qml b/tests/auto/quick/qquickstates/data/removeBindingWithTransition.qml
new file mode 100644
index 0000000000..ed40e18374
--- /dev/null
+++ b/tests/auto/quick/qquickstates/data/removeBindingWithTransition.qml
@@ -0,0 +1,23 @@
+import QtQuick
+
+Item {
+ id: root
+ property bool toggle: true
+ property int state1Width: 500
+
+ states: [
+ State {
+ when: root.toggle
+ PropertyChanges { root.width: root.state1Width }
+ },
+ State {
+ when: !root.toggle
+ PropertyChanges { root.width: 300 }
+ }
+ ]
+
+ transitions: Transition {
+ id: transition
+ SmoothedAnimation { target: root; property: "width"; velocity: 200 }
+ }
+}
diff --git a/tests/auto/quick/qquickstates/tst_qquickstates.cpp b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
index cbc36ad1b5..3bdbe29d1e 100644
--- a/tests/auto/quick/qquickstates/tst_qquickstates.cpp
+++ b/tests/auto/quick/qquickstates/tst_qquickstates.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcomponent.h>
@@ -37,7 +12,8 @@
#include <QtQuick/private/qquickstategroup_p.h>
#include <private/qquickitem_p.h>
#include <private/qqmlproperty_p.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtTest/qsignalspy.h>
class MyAttached : public QObject
{
@@ -143,7 +119,12 @@ class tst_qquickstates : public QQmlDataTest
{
Q_OBJECT
public:
- tst_qquickstates() {}
+ tst_qquickstates() : QQmlDataTest(QT_QMLTEST_DATADIR)
+ {
+#ifdef QML_DISABLE_INTERNAL_DEFERRED_PROPERTIES
+ qputenv("QML_DISABLE_INTERNAL_DEFERRED_PROPERTIES", "1");
+#endif
+ }
private:
QByteArray fullDataPath(const QString &path) const;
@@ -199,9 +180,18 @@ private slots:
void revertListMemoryLeak();
void duplicateStateName();
void trivialWhen();
+ void jsValueWhen_data();
+ void jsValueWhen();
+ void noStateOsciallation();
void parentChangeCorrectReversal();
void revertNullObjectBinding();
void bindableProperties();
+ void parentChangeInvolvingBindings();
+ void deferredProperties();
+ void rewindAnchorChange();
+ void rewindAnchorChangeSize();
+ void bindingProperlyRemovedWithTransition();
+ void doNotCrashOnBroken();
};
void tst_qquickstates::initTestCase()
@@ -1053,23 +1043,23 @@ void tst_qquickstates::anchorRewindBug()
QQuickItem * column = rect->findChild<QQuickItem*>("column");
QVERIFY(column != nullptr);
- QVERIFY(!QQuickItemPrivate::get(column)->heightValid);
- QVERIFY(!QQuickItemPrivate::get(column)->widthValid);
+ QVERIFY(!QQuickItemPrivate::get(column)->heightValid());
+ QVERIFY(!QQuickItemPrivate::get(column)->widthValid());
QCOMPARE(column->height(), 200.0);
QQuickItemPrivate::get(rect)->setState("reanchored");
// column height and width should stay implicit
// and column's implicit resizing should still work
- QVERIFY(!QQuickItemPrivate::get(column)->heightValid);
- QVERIFY(!QQuickItemPrivate::get(column)->widthValid);
+ QVERIFY(!QQuickItemPrivate::get(column)->heightValid());
+ QVERIFY(!QQuickItemPrivate::get(column)->widthValid());
QTRY_COMPARE(column->height(), 100.0);
QQuickItemPrivate::get(rect)->setState("");
// column height and width should stay implicit
// and column's implicit resizing should still work
- QVERIFY(!QQuickItemPrivate::get(column)->heightValid);
- QVERIFY(!QQuickItemPrivate::get(column)->widthValid);
+ QVERIFY(!QQuickItemPrivate::get(column)->heightValid());
+ QVERIFY(!QQuickItemPrivate::get(column)->widthValid());
QTRY_COMPARE(column->height(), 200.0);
}
@@ -1346,7 +1336,7 @@ void tst_qquickstates::illegalObjectCreation()
QQmlComponent component(&engine, testFileUrl("illegalObj.qml"));
QList<QQmlError> errors = component.errors();
- QCOMPARE(errors.count(), 1);
+ QCOMPARE(errors.size(), 1);
const QQmlError &error = errors.at(0);
QCOMPARE(error.line(), 9);
QCOMPARE(error.column(), 23);
@@ -1482,7 +1472,7 @@ void tst_qquickstates::editProperties()
QQuickRectangle *childRect = rect->findChild<QQuickRectangle*>("rect2");
QVERIFY(childRect != nullptr);
QCOMPARE(childRect->width(), qreal(402));
- QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
+ QVERIFY(QQmlAnyBinding::ofProperty(QQmlProperty(childRect, "width")));
QCOMPARE(childRect->height(), qreal(200));
rectPrivate->setState("blue");
@@ -1501,7 +1491,7 @@ void tst_qquickstates::editProperties()
rectPrivate->setState("");
- QCOMPARE(propertyChangesBlue->actions().length(), 2);
+ QCOMPARE(propertyChangesBlue->actions().size(), 2);
QVERIFY(propertyChangesBlue->containsValue("width"));
QVERIFY(!propertyChangesBlue->containsProperty("x"));
QCOMPARE(propertyChangesBlue->value("width").toInt(), 50);
@@ -1509,38 +1499,38 @@ void tst_qquickstates::editProperties()
propertyChangesBlue->changeValue("width", 60);
QCOMPARE(propertyChangesBlue->value("width").toInt(), 60);
- QCOMPARE(propertyChangesBlue->actions().length(), 2);
+ QCOMPARE(propertyChangesBlue->actions().size(), 2);
propertyChangesBlue->changeExpression("width", "myRectangle.width / 2");
QVERIFY(!propertyChangesBlue->containsValue("width"));
QVERIFY(propertyChangesBlue->containsExpression("width"));
QCOMPARE(propertyChangesBlue->value("width").toInt(), 0);
- QCOMPARE(propertyChangesBlue->actions().length(), 2);
+ QCOMPARE(propertyChangesBlue->actions().size(), 2);
propertyChangesBlue->changeValue("width", 50);
QVERIFY(propertyChangesBlue->containsValue("width"));
QVERIFY(!propertyChangesBlue->containsExpression("width"));
QCOMPARE(propertyChangesBlue->value("width").toInt(), 50);
- QCOMPARE(propertyChangesBlue->actions().length(), 2);
+ QCOMPARE(propertyChangesBlue->actions().size(), 2);
- QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
+ QVERIFY(QQmlAnyBinding::ofProperty(QQmlProperty(childRect, "width")));
rectPrivate->setState("blue");
QCOMPARE(childRect->width(), qreal(50));
QCOMPARE(childRect->height(), qreal(40));
propertyChangesBlue->changeValue("width", 60);
QCOMPARE(propertyChangesBlue->value("width").toInt(), 60);
- QCOMPARE(propertyChangesBlue->actions().length(), 2);
+ QCOMPARE(propertyChangesBlue->actions().size(), 2);
QCOMPARE(childRect->width(), qreal(60));
- QVERIFY(!QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
+ QVERIFY(!QQmlAnyBinding::ofProperty(QQmlProperty(childRect, "width")));
propertyChangesBlue->changeExpression("width", "myRectangle.width / 2");
QVERIFY(!propertyChangesBlue->containsValue("width"));
QVERIFY(propertyChangesBlue->containsExpression("width"));
QCOMPARE(propertyChangesBlue->value("width").toInt(), 0);
- QCOMPARE(propertyChangesBlue->actions().length(), 2);
- QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
+ QCOMPARE(propertyChangesBlue->actions().size(), 2);
+ QVERIFY(QQmlAnyBinding::ofProperty(QQmlProperty(childRect, "width")));
QCOMPARE(childRect->width(), qreal(200));
propertyChangesBlue->changeValue("width", 50);
@@ -1548,25 +1538,25 @@ void tst_qquickstates::editProperties()
rectPrivate->setState("");
QCOMPARE(childRect->width(), qreal(402));
- QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
+ QVERIFY(QQmlAnyBinding::ofProperty(QQmlProperty(childRect, "width")));
- QCOMPARE(propertyChangesGreen->actions().length(), 2);
+ QCOMPARE(propertyChangesGreen->actions().size(), 2);
rectPrivate->setState("green");
QCOMPARE(childRect->width(), qreal(200));
QCOMPARE(childRect->height(), qreal(100));
- QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
+ QVERIFY(QQmlAnyBinding::ofProperty(QQmlProperty(childRect, "width")));
QVERIFY(greenState->bindingInRevertList(childRect, "width"));
- QCOMPARE(propertyChangesGreen->actions().length(), 2);
+ QCOMPARE(propertyChangesGreen->actions().size(), 2);
propertyChangesGreen->removeProperty("height");
- QVERIFY(!QQmlPropertyPrivate::binding(QQmlProperty(childRect, "height")));
+ QVERIFY(!QQmlAnyBinding::ofProperty(QQmlProperty(childRect, "height")));
QCOMPARE(childRect->height(), qreal(200));
QVERIFY(greenState->bindingInRevertList(childRect, "width"));
QVERIFY(greenState->containsPropertyInRevertList(childRect, "width"));
propertyChangesGreen->removeProperty("width");
- QVERIFY(QQmlPropertyPrivate::binding(QQmlProperty(childRect, "width")));
+ QVERIFY(QQmlAnyBinding::ofProperty(QQmlProperty(childRect, "width")));
QCOMPARE(childRect->width(), qreal(402));
QVERIFY(!greenState->bindingInRevertList(childRect, "width"));
QVERIFY(!greenState->containsPropertyInRevertList(childRect, "width"));
@@ -1660,9 +1650,20 @@ void tst_qquickstates::QTBUG_38492()
QCOMPARE(item->property("text").toString(), QString("Test"));
}
+static int getRefCount(const QQmlAnyBinding &binding)
+{
+ if (binding.isAbstractPropertyBinding()) {
+ return binding.asAbstractBinding()->ref;
+ } else {
+ // this temporarily adds a refcount because we construc a new untypedpropertybinding
+ // thus -1
+ return QPropertyBindingPrivate::get(binding.asUntypedPropertyBinding())->refCount() - 1;
+ }
+}
+
void tst_qquickstates::revertListMemoryLeak()
{
- QQmlAbstractBinding::Ptr bindingPtr;
+ QQmlAnyBinding bindingPtr;
{
QQmlEngine engine;
@@ -1674,12 +1675,12 @@ void tst_qquickstates::revertListMemoryLeak()
item->setState("testState");
- QQmlAbstractBinding *binding = state->bindingInRevertList(item.get(), "height").asAbstractBinding();
+ auto binding = state->bindingInRevertList(item.get(), "height");
QVERIFY(binding);
bindingPtr = binding;
- QVERIFY(bindingPtr->ref > 1);
+ QVERIFY(getRefCount(bindingPtr) > 1);
}
- QVERIFY(bindingPtr->ref == 1);
+ QVERIFY(getRefCount(bindingPtr) == 1);
}
void tst_qquickstates::duplicateStateName()
@@ -1702,6 +1703,39 @@ void tst_qquickstates::trivialWhen()
QVERIFY(root);
}
+
+void tst_qquickstates::jsValueWhen_data()
+{
+ QTest::addColumn<QByteArray>("fileName");
+ QTest::addRow("jsObject") << QByteArray("jsValueWhen.qml");
+ QTest::addRow("qmlObject") << QByteArray("jsValueWhen2.qml");
+}
+
+void tst_qquickstates::jsValueWhen()
+{
+ QFETCH(QByteArray, fileName);
+ QQmlEngine engine;
+
+ QQmlComponent c(&engine, testFileUrl(fileName.constData()));
+ QScopedPointer<QObject> root(c.create());
+ QVERIFY(root);
+ QVERIFY(root->property("works").toBool());
+}
+
+void tst_qquickstates::noStateOsciallation()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("noStateOsciallation.qml"));
+ QScopedPointer<QObject> root {component.create()};
+ QVERIFY(root);
+ // set to 1 on initial transition from "" to "n2"
+ QCOMPARE(root->property("stateChangeCounter").toInt(), 1);
+ root->setProperty("number", 1);
+ // setting number to 1 changes directly from "n2" to "n1"
+ // without any intermediate transition to ""
+ QCOMPARE(root->property("stateChangeCounter").toInt(), 2);
+}
+
void tst_qquickstates::parentChangeCorrectReversal()
{
QQmlEngine engine;
@@ -1768,6 +1802,256 @@ void tst_qquickstates::bindableProperties()
}
}
+struct Listener : QQuickItemChangeListener
+{
+ // We want to get notified about all the states.
+ constexpr static const QRectF expectations[] = {
+ QRectF(40, 40, 400, 400),
+ QRectF(40, 0, 400, 400),
+ QRectF(0, 0, 400, 400),
+ QRectF(0, 0, 800, 400),
+ QRectF(0, 0, 800, 200),
+ QRectF(0, 0, 400, 200),
+ QRectF(0, 20, 400, 200),
+ QRectF(40, 20, 400, 200),
+ QRectF(84, 42, 400, 200),
+ QRectF(84, 42, 86, 43),
+ QRectF(40, 40, 86, 43),
+ QRectF(40, 40, 400, 400),
+ QRectF(40, 20, 400, 400),
+ QRectF(40, 20, 400, 200),
+ QRectF(20, 20, 400, 200),
+ QRectF(20, 20, 200, 200),
+ QRectF(20, 20, 200, 300),
+ QRectF(20, 20, 300, 300),
+ QRectF(20, 30, 300, 300),
+ QRectF(30, 30, 300, 300),
+ };
+
+ int position = 0;
+ bool ok = true;
+
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &rect) override
+ {
+ if (rect != expectations[position]) {
+ qDebug() << position << rect;
+ ok = false;
+ }
+ ++position;
+ }
+};
+
+void tst_qquickstates::parentChangeInvolvingBindings()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("parentChangeInvolvingBindings.qml"));
+ Listener listener;
+ QScopedPointer<QQuickItem> root { qobject_cast<QQuickItem *>(c.create()) };
+ QVERIFY2(root, qPrintable(c.errorString()));
+
+ QObject *child = qmlContext(root.data())->objectForName(QStringLiteral("firstChild"));
+ QVERIFY(child);
+ QQuickItem *childItem = qobject_cast<QQuickItem *>(child);
+ QVERIFY(childItem);
+ QQuickItemPrivate::get(childItem)->addItemChangeListener(&listener, QQuickItemPrivate::Geometry);
+
+
+ QCOMPARE(root->property("childWidth").toInt(), 400);
+ QCOMPARE(root->property("childX").toInt(), 40);
+ QCOMPARE(root->property("childRotation").toInt(), 100);
+ root->setState("reparented");
+
+ QCOMPARE(root->property("childWidth").toInt(), 800);
+ QCOMPARE(root->property("childX").toInt(), 0); // x gets zeroed here, from unrelated place.
+ QCOMPARE(root->property("childRotation").toInt(), 200);
+
+ root->setProperty("myrotation2", 300);
+ root->setHeight(200);
+ root->setY(20);
+ QCOMPARE(root->property("childRotation").toInt(), 300);
+ QCOMPARE(root->property("childWidth").toInt(), 400);
+ QCOMPARE(root->property("childX").toInt(), 40);
+
+ QObject *inner = qmlContext(root.data())->objectForName(QStringLiteral("inner"));
+ QVERIFY(inner);
+ QQuickItem *innerItem = qobject_cast<QQuickItem *>(inner);
+ QVERIFY(innerItem);
+
+ QCOMPARE(innerItem->size(), childItem->size());
+
+ // Does not break bindings and does not survive the state change.
+ // However, since the binding between x and y stays intact, we don't know
+ // whether x is set another time from the new y. We pass a pair of numbers that
+ // matches the binding.
+ childItem->setPosition(QPointF(84, 42));
+ QCOMPARE(root->property("childX").toInt(), 84);
+ QVERIFY(listener.ok);
+ childItem->setSize(QSizeF(86, 43));
+ QCOMPARE(root->property("childWidth").toInt(), 86);
+ QVERIFY(listener.ok);
+
+ QCOMPARE(innerItem->size(), childItem->size());
+
+ QSignalSpy xSpy(childItem, SIGNAL(xChanged()));
+ QSignalSpy widthSpy(childItem, SIGNAL(widthChanged()));
+
+ root->setState("");
+
+ QVERIFY(listener.ok);
+ QCOMPARE(root->property("childRotation").toInt(), 100);
+
+ // First change to 40 via reverse(), then to 20 via binding.
+ QCOMPARE(xSpy.size(), 2);
+
+ // First change to 400 via reverse(), then to 200 via binding.
+ QCOMPARE(widthSpy.size(), 2);
+
+ QCOMPARE(root->property("childX").toInt(), 20);
+ QCOMPARE(root->property("childWidth").toInt(), 200);
+
+ QCOMPARE(innerItem->size(), childItem->size());
+
+ root->setProperty("myrotation", 50);
+ root->setHeight(300);
+ QVERIFY(listener.ok);
+ root->setY(30);
+ QVERIFY(listener.ok);
+ QCOMPARE(root->property("childWidth").toInt(), 300);
+ QCOMPARE(root->property("childX").toInt(), 30);
+ QCOMPARE(root->property("childRotation").toInt(), 50);
+
+ QCOMPARE(innerItem->size(), childItem->size());
+}
+
+void tst_qquickstates::deferredProperties()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("cleanPropertyChange.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QQuickRectangle> root(qobject_cast<QQuickRectangle *>(c.create()));
+ QVERIFY(root);
+
+ QCOMPARE(root->color(), QColor(Qt::red));
+ QCOMPARE(qvariant_cast<QColor>(root->property("extendedColor")), QColor(Qt::cyan));
+ QCOMPARE(root->width(), 100.0);
+ QCOMPARE(root->height(), 100.0);
+
+ QCOMPARE(root->state(), QString());
+ root->setState(QStringLiteral("green"));
+
+ QCOMPARE(root->color(), QColor(Qt::yellow));
+ QCOMPARE(qvariant_cast<QColor>(root->property("extendedColor")), QColor(Qt::blue));
+ QCOMPARE(root->width(), 90.0);
+ QCOMPARE(root->height(), 90.0);
+
+ QMetaObject::invokeMethod(root.get(), "didSomething");
+ const QColor green = qRgb(0x00, 0x80, 0x00);
+ QCOMPARE(root->color(), green);
+ QCOMPARE(qvariant_cast<QColor>(root->property("extendedColor")), green);
+ QCOMPARE(root->width(), 90.0);
+ QCOMPARE(root->height(), 90.0);
+
+ root->setState(QString());
+
+ QCOMPARE(root->color(), QColor(Qt::red));
+ QCOMPARE(qvariant_cast<QColor>(root->property("extendedColor")), QColor(Qt::cyan));
+ QCOMPARE(root->width(), 100.0);
+ QCOMPARE(root->height(), 100.0);
+}
+
+void tst_qquickstates::rewindAnchorChange()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("anchorRewind.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> root(c.create());
+ QVERIFY(root);
+
+ QQmlContext *context = qmlContext(root.data());
+ QVERIFY(context);
+
+ QObject *inner = context->objectForName(QStringLiteral("inner"));
+ QVERIFY(inner);
+
+ QQuickItem *innerRect = qobject_cast<QQuickItem *>(inner);
+ QVERIFY(innerRect);
+
+ QTRY_COMPARE(innerRect->x(), 0);
+ QTRY_COMPARE(innerRect->y(), 0);
+ QTRY_COMPARE(innerRect->width(), 200);
+ QTRY_COMPARE(innerRect->height(), 200);
+}
+
+void tst_qquickstates::rewindAnchorChangeSize()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("anchorRewindSize.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ std::unique_ptr<QObject> root(c.create());
+ QVERIFY(root);
+
+ QQmlContext *context = qmlContext(root.get());
+ QVERIFY(context);
+
+ QObject *inner = context->objectForName(QStringLiteral("inner"));
+ QVERIFY(inner);
+
+ QQuickItem *innerRect = qobject_cast<QQuickItem *>(inner);
+ QVERIFY(innerRect);
+
+ QCOMPARE(innerRect->x(), 0);
+ QCOMPARE(innerRect->y(), 0);
+ QCOMPARE(innerRect->width(), 100);
+ QCOMPARE(innerRect->height(), 100);
+
+ root->setProperty("changeState", true);
+ QCOMPARE(innerRect->x(), 0);
+ QCOMPARE(innerRect->y(), 0);
+ QCOMPARE(innerRect->width(), 400);
+ QCOMPARE(innerRect->height(), 400);
+
+ root->setProperty("changeState", false);
+ QCOMPARE(innerRect->x(), 0);
+ QCOMPARE(innerRect->y(), 0);
+ QCOMPARE(innerRect->width(), 100);
+ QCOMPARE(innerRect->height(), 100);
+}
+
+void tst_qquickstates::bindingProperlyRemovedWithTransition()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("removeBindingWithTransition.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> root(c.create());
+ QVERIFY(root);
+ QQuickItem *item = qobject_cast<QQuickItem *>(root.get());
+ QVERIFY(item);
+
+ item->setProperty("toggle", false);
+ QTRY_COMPARE(item->width(), 300);
+
+ item->setProperty("state1Width", 100);
+ QCOMPARE(item->width(), 300);
+
+ item->setProperty("toggle", true);
+ QTRY_COMPARE(item->width(), 100);
+}
+
+void tst_qquickstates::doNotCrashOnBroken()
+{
+ QQmlEngine engine;
+ QQmlComponent c(&engine, testFileUrl("broken.qml"));
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+ QScopedPointer<QObject> root(c.create());
+ QVERIFY(root);
+ QQuickItem *item = qobject_cast<QQuickItem *>(root.get());
+ QVERIFY(item);
+
+ QQmlListReference states(item, "states");
+ QCOMPARE(states.size(), 1);
+ QCOMPARE(states.at(0), nullptr);
+}
+
QTEST_MAIN(tst_qquickstates)
#include "tst_qquickstates.moc"
diff --git a/tests/auto/quick/qquickstyledtext/CMakeLists.txt b/tests/auto/quick/qquickstyledtext/CMakeLists.txt
index a22a4157d7..9cac845e6d 100644
--- a/tests/auto/quick/qquickstyledtext/CMakeLists.txt
+++ b/tests/auto/quick/qquickstyledtext/CMakeLists.txt
@@ -1,13 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickstyledtext.pro.
#####################################################################
## tst_qquickstyledtext Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickstyledtext LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qquickstyledtext
SOURCES
tst_qquickstyledtext.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp b/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp
index 88b0e95e0a..f0367e27f5 100644
--- a/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp
+++ b/tests/auto/quick/qquickstyledtext/tst_qquickstyledtext.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtTest/QtTest>
#include <QtGui/QTextLayout>
@@ -152,9 +127,14 @@ void tst_qquickstyledtext::textOutput_data()
QTest::newRow("space leading bold") << "this is<b> bold</b>" << "this is bold" << (FormatList() << Format(Format::Bold, 7, 5)) << false;
QTest::newRow("space trailing bold") << "this is <b>bold </b>" << "this is bold " << (FormatList() << Format(Format::Bold, 8, 5)) << false;
QTest::newRow("img") << "a<img src=\"blah.png\"/>b" << "a b" << FormatList() << false;
+ QTest::newRow("img") << "a<img />b" << "a b" << FormatList() << false;
QTest::newRow("tag mix") << "<f6>ds<b></img><pro>gfh</b><w><w>ghj</stron><ql><sl><pl>dfg</j6><img><bol><r><prp>dfg<bkj></b><up><string>ewrq</al><bl>jklhj<zl>" << "dsgfhghjdfgdfgewrqjklhj" << (FormatList() << Format(Format::Bold, 2, 3)) << false;
QTest::newRow("named html entities") << "&gt; &lt; &amp; &quot; &nbsp;" << QLatin1String("> < & \" ") + QChar(QChar::Nbsp) << FormatList() << false;
QTest::newRow("invalid html entities") << "a &hello & a &goodbye;" << "a &hello & a " << FormatList() << false;
+ QTest::newRow("upper case tags 1") << "<B><I><S><U>text</U></S></I></B>" << "text" << (FormatList() << Format(Format::Bold|Format::Italic|Format::StrikeOut|Format::Underline, 0, 4)) << false;
+ QTest::newRow("upper case tags 2") << "<STRONG><DEL>text</DEL></STRONG>" << "text" << (FormatList() << Format(Format::Bold|Format::StrikeOut, 0, 4)) << false;
+ QTest::newRow("upper case font") << "<FONT COLOR=\"red\" SIZE=\"1\">text</FONT>" << "text" << (FormatList() << Format(0, 0, 4)) << true;
+ QTest::newRow("upper case entities") << "&LT;b&GT;&QUOT;this&QUOT; &AMP; that&LT;/b&GT;" << "<b>\"this\" & that</b>" << FormatList() << false;
}
void tst_qquickstyledtext::textOutput()
@@ -173,8 +153,8 @@ void tst_qquickstyledtext::textOutput()
const QVector<QTextLayout::FormatRange> layoutFormats = layout.formats();
- QCOMPARE(layoutFormats.count(), formats.count());
- for (int i = 0; i < formats.count(); ++i) {
+ QCOMPARE(layoutFormats.size(), formats.size());
+ for (int i = 0; i < formats.size(); ++i) {
QCOMPARE(layoutFormats.at(i).start, formats.at(i).start);
QCOMPARE(layoutFormats.at(i).length, formats.at(i).length);
if (formats.at(i).type & Format::Bold)
@@ -203,8 +183,8 @@ void tst_qquickstyledtext::anchors()
const QVector<QTextLayout::FormatRange> layoutFormats = layout.formats();
- QCOMPARE(layoutFormats.count(), formats.count());
- for (int i = 0; i < formats.count(); ++i) {
+ QCOMPARE(layoutFormats.size(), formats.size());
+ for (int i = 0; i < formats.size(); ++i) {
QCOMPARE(layoutFormats.at(i).start, formats.at(i).start);
QCOMPARE(layoutFormats.at(i).length, formats.at(i).length);
QVERIFY(layoutFormats.at(i).format.isAnchor() == bool(formats.at(i).type & Format::Anchor));
diff --git a/tests/auto/quick/qquicksystempalette/CMakeLists.txt b/tests/auto/quick/qquicksystempalette/CMakeLists.txt
index 5951dc1d07..b747b51978 100644
--- a/tests/auto/quick/qquicksystempalette/CMakeLists.txt
+++ b/tests/auto/quick/qquicksystempalette/CMakeLists.txt
@@ -1,24 +1,51 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquicksystempalette.pro.
#####################################################################
## tst_qquicksystempalette Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicksystempalette LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
qt_internal_add_test(tst_qquicksystempalette
SOURCES
tst_qquicksystempalette.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
)
## Scopes:
#####################################################################
qt_internal_extend_target(tst_qquicksystempalette CONDITION TARGET Qt::Widgets
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Widgets
)
+
+qt_internal_extend_target(tst_qquicksystempalette CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=":/data"
+)
+
+qt_internal_extend_target(tst_qquicksystempalette CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+)
diff --git a/tests/auto/quick/qquicksystempalette/data/systemPalette.qml b/tests/auto/quick/qquicksystempalette/data/systemPalette.qml
new file mode 100644
index 0000000000..3a1395ec18
--- /dev/null
+++ b/tests/auto/quick/qquicksystempalette/data/systemPalette.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.0
+
+SystemPalette {
+}
diff --git a/tests/auto/quick/qquicksystempalette/data/systemPaletteDisabled.qml b/tests/auto/quick/qquicksystempalette/data/systemPaletteDisabled.qml
new file mode 100644
index 0000000000..3eaeac8985
--- /dev/null
+++ b/tests/auto/quick/qquicksystempalette/data/systemPaletteDisabled.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+SystemPalette {
+ colorGroup: SystemPalette.Disabled
+}
diff --git a/tests/auto/quick/qquicksystempalette/data/systemPaletteInactive.qml b/tests/auto/quick/qquicksystempalette/data/systemPaletteInactive.qml
new file mode 100644
index 0000000000..f43e7073c6
--- /dev/null
+++ b/tests/auto/quick/qquicksystempalette/data/systemPaletteInactive.qml
@@ -0,0 +1,5 @@
+import QtQuick 2.0
+
+SystemPalette {
+ colorGroup: SystemPalette.Inactive
+}
diff --git a/tests/auto/quick/qquicksystempalette/tst_qquicksystempalette.cpp b/tests/auto/quick/qquicksystempalette/tst_qquicksystempalette.cpp
index 071dcafc97..e9b6054130 100644
--- a/tests/auto/quick/qquicksystempalette/tst_qquicksystempalette.cpp
+++ b/tests/auto/quick/qquicksystempalette/tst_qquicksystempalette.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QDebug>
@@ -32,8 +7,9 @@
#include <QtQml/qqmlcomponent.h>
#include <QtQuick/private/qquicksystempalette_p.h>
#include <qpalette.h>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
-class tst_qquicksystempalette : public QObject
+class tst_qquicksystempalette : public QQmlDataTest
{
Q_OBJECT
public:
@@ -51,15 +27,11 @@ private:
QQmlEngine engine;
};
-tst_qquicksystempalette::tst_qquicksystempalette()
-{
-}
+tst_qquicksystempalette::tst_qquicksystempalette() : QQmlDataTest(QT_QMLTEST_DATADIR) { }
void tst_qquicksystempalette::activePalette()
{
- QString componentStr = "import QtQuick 2.0\nSystemPalette { }";
- QQmlComponent component(&engine);
- component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QQmlComponent component(&engine, testFileUrl("systemPalette.qml"));
QQuickSystemPalette *object = qobject_cast<QQuickSystemPalette*>(component.create());
QVERIFY(object != nullptr);
@@ -80,15 +52,15 @@ void tst_qquicksystempalette::activePalette()
QCOMPARE(palette.shadow().color(), object->shadow());
QCOMPARE(palette.highlight().color(), object->highlight());
QCOMPARE(palette.highlightedText().color(), object->highlightedText());
+ QCOMPARE(palette.placeholderText().color(), object->placeholderText());
+ QCOMPARE(palette.accent().color(), object->accent());
delete object;
}
void tst_qquicksystempalette::inactivePalette()
{
- QString componentStr = "import QtQuick 2.0\nSystemPalette { colorGroup: SystemPalette.Inactive }";
- QQmlComponent component(&engine);
- component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QQmlComponent component(&engine, testFileUrl("systemPaletteInactive.qml"));
QQuickSystemPalette *object = qobject_cast<QQuickSystemPalette*>(component.create());
QVERIFY(object != nullptr);
@@ -110,15 +82,15 @@ void tst_qquicksystempalette::inactivePalette()
QCOMPARE(palette.shadow().color(), object->shadow());
QCOMPARE(palette.highlight().color(), object->highlight());
QCOMPARE(palette.highlightedText().color(), object->highlightedText());
+ QCOMPARE(palette.placeholderText().color(), object->placeholderText());
+ QCOMPARE(palette.accent().color(), object->accent());
delete object;
}
void tst_qquicksystempalette::disabledPalette()
{
- QString componentStr = "import QtQuick 2.0\nSystemPalette { colorGroup: SystemPalette.Disabled }";
- QQmlComponent component(&engine);
- component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QQmlComponent component(&engine, testFileUrl("systemPaletteDisabled.qml"));
QQuickSystemPalette *object = qobject_cast<QQuickSystemPalette*>(component.create());
QVERIFY(object != nullptr);
@@ -140,6 +112,8 @@ void tst_qquicksystempalette::disabledPalette()
QCOMPARE(palette.shadow().color(), object->shadow());
QCOMPARE(palette.highlight().color(), object->highlight());
QCOMPARE(palette.highlightedText().color(), object->highlightedText());
+ QCOMPARE(palette.placeholderText().color(), object->placeholderText());
+ QCOMPARE(palette.accent().color(), object->accent());
delete object;
}
@@ -147,9 +121,7 @@ void tst_qquicksystempalette::disabledPalette()
#ifndef QT_NO_WIDGETS
void tst_qquicksystempalette::paletteChanged()
{
- QString componentStr = "import QtQuick 2.0\nSystemPalette { }";
- QQmlComponent component(&engine);
- component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
+ QQmlComponent component(&engine, testFileUrl("systemPalette.qml"));
QQuickSystemPalette *object = qobject_cast<QQuickSystemPalette*>(component.create());
QVERIFY(object != nullptr);
diff --git a/tests/auto/quick/qquicktableview/CMakeLists.txt b/tests/auto/quick/qquicktableview/CMakeLists.txt
index 04842aaae2..77c7f5f06a 100644
--- a/tests/auto/quick/qquicktableview/CMakeLists.txt
+++ b/tests/auto/quick/qquicktableview/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquicktableview.pro.
#####################################################################
## tst_qquicktableview Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicktableview LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,17 +21,9 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquicktableview
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
testmodel.h
tst_qquicktableview.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
@@ -30,6 +31,7 @@ qt_internal_add_test(tst_qquicktableview
Qt::QmlPrivate
Qt::QuickPrivate
Qt::QuickTest
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -41,10 +43,10 @@ qt_internal_add_test(tst_qquicktableview
qt_internal_extend_target(tst_qquicktableview CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquicktableview CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquicktableview/data/alternatingrowheightcolumnwidth.qml b/tests/auto/quick/qquicktableview/data/alternatingrowheightcolumnwidth.qml
index e6cf9bf2a4..106a95de7f 100644
--- a/tests/auto/quick/qquicktableview/data/alternatingrowheightcolumnwidth.qml
+++ b/tests/auto/quick/qquicktableview/data/alternatingrowheightcolumnwidth.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/asyncloader.qml b/tests/auto/quick/qquicktableview/data/asyncloader.qml
index ba99430416..ac901323f1 100644
--- a/tests/auto/quick/qquicktableview/data/asyncloader.qml
+++ b/tests/auto/quick/qquicktableview/data/asyncloader.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
diff --git a/tests/auto/quick/qquicktableview/data/asyncplain.qml b/tests/auto/quick/qquicktableview/data/asyncplain.qml
index df09d3e276..25eb14b016 100644
--- a/tests/auto/quick/qquicktableview/data/asyncplain.qml
+++ b/tests/auto/quick/qquicktableview/data/asyncplain.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/boundDelegateComponent.qml b/tests/auto/quick/qquicktableview/data/boundDelegateComponent.qml
new file mode 100644
index 0000000000..419df15fd3
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/boundDelegateComponent.qml
@@ -0,0 +1,67 @@
+pragma ComponentBehavior: Bound
+
+import QtQuick
+import Qt.labs.qmlmodels
+
+Item {
+ id: outer
+ objectName: "outer"
+ TableView {
+ id: tableView
+ width: 10
+ height: 10
+ model: 1
+ property string foo: "foo"
+ delegate: Text {
+ property var notThere: index
+ text: "."
+ objectName: tableView.foo + outer.objectName + notThere
+ }
+ }
+
+ TableView {
+ id: tableView2
+ width: 10
+ height: 10
+ model: 1
+ delegate: Text {
+ required property int index
+ text: "."
+ objectName: tableView.foo + outer.objectName + index
+ }
+ }
+
+ Component {
+ id: outerComponent
+ Item {
+ TableModel {
+ id: tableModel
+ TableModelColumn { display: "color" }
+ TableModelColumn { display: "amount" }
+ rows: [
+ { color: "red", amount: 1 },
+ { color: "green", amount: 3 },
+ { color: "blue", amount: 8 },
+ ]
+
+ }
+
+ Component {
+ id: innerComponent
+ Rectangle {
+ implicitWidth: 1
+ implicitHeight: 1
+ objectName: model.myColor
+ }
+ }
+
+ TableView {
+ width: 10
+ height: 10
+ id: innerTableView
+ model: tableModel
+ delegate: innerComponent
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktableview/data/changemodelfromdelegate.qml b/tests/auto/quick/qquicktableview/data/changemodelfromdelegate.qml
index 79a8e4351a..60b02bc245 100644
--- a/tests/auto/quick/qquicktableview/data/changemodelfromdelegate.qml
+++ b/tests/auto/quick/qquicktableview/data/changemodelfromdelegate.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/changemodelordelegateduringupdate.qml b/tests/auto/quick/qquicktableview/data/changemodelordelegateduringupdate.qml
index de404be63d..f0c7814186 100644
--- a/tests/auto/quick/qquicktableview/data/changemodelordelegateduringupdate.qml
+++ b/tests/auto/quick/qquicktableview/data/changemodelordelegateduringupdate.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/checkalwaysemit.qml b/tests/auto/quick/qquicktableview/data/checkalwaysemit.qml
index 33db6f6d02..463e21342c 100644
--- a/tests/auto/quick/qquicktableview/data/checkalwaysemit.qml
+++ b/tests/auto/quick/qquicktableview/data/checkalwaysemit.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/checkmodelpropertyrevision.qml b/tests/auto/quick/qquicktableview/data/checkmodelpropertyrevision.qml
index 0550f20bac..f89fff8de1 100644
--- a/tests/auto/quick/qquicktableview/data/checkmodelpropertyrevision.qml
+++ b/tests/auto/quick/qquicktableview/data/checkmodelpropertyrevision.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.12
diff --git a/tests/auto/quick/qquicktableview/data/checkrowandcolumnnotchanged.qml b/tests/auto/quick/qquicktableview/data/checkrowandcolumnnotchanged.qml
index bef0df2501..fa15f2f54b 100644
--- a/tests/auto/quick/qquicktableview/data/checkrowandcolumnnotchanged.qml
+++ b/tests/auto/quick/qquicktableview/data/checkrowandcolumnnotchanged.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/columnwidthboundtoviewwidth.qml b/tests/auto/quick/qquicktableview/data/columnwidthboundtoviewwidth.qml
new file mode 100644
index 0000000000..eaf0cd692d
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/columnwidthboundtoviewwidth.qml
@@ -0,0 +1,40 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.12
+import QtQuick.Window 2.3
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+ property Component delegate: tableViewDelegate
+
+ TableView {
+ id: tableView
+ width: 600
+ height: 400
+ anchors.margins: 1
+ clip: true
+ delegate: tableViewDelegate
+ columnSpacing: 1
+ rowSpacing: 1
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ implicitWidth: tableView.width
+ implicitHeight: 50
+ objectName: "tableViewDelegate"
+ color: "lightgray"
+ border.width: 1
+ Text {
+ anchors.centerIn: parent
+ text: modelData
+ }
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/data/contentwidthheight.qml b/tests/auto/quick/qquicktableview/data/contentwidthheight.qml
index 6b15e8dd21..f6ae474bf4 100644
--- a/tests/auto/quick/qquicktableview/data/contentwidthheight.qml
+++ b/tests/auto/quick/qquicktableview/data/contentwidthheight.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/countingtableview.qml b/tests/auto/quick/qquicktableview/data/countingtableview.qml
index ecd4ca3cc7..a73cb6e4cf 100644
--- a/tests/auto/quick/qquicktableview/data/countingtableview.qml
+++ b/tests/auto/quick/qquicktableview/data/countingtableview.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/delegateWithRequired.qml b/tests/auto/quick/qquicktableview/data/delegateWithRequired.qml
index bebfd86931..728de37266 100644
--- a/tests/auto/quick/qquicktableview/data/delegateWithRequired.qml
+++ b/tests/auto/quick/qquicktableview/data/delegateWithRequired.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/delegatewithRequiredUnset.qml b/tests/auto/quick/qquicktableview/data/delegatewithRequiredUnset.qml
index 0c685cd49e..43a1eed402 100644
--- a/tests/auto/quick/qquicktableview/data/delegatewithRequiredUnset.qml
+++ b/tests/auto/quick/qquicktableview/data/delegatewithRequiredUnset.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/delegatewithanchors.qml b/tests/auto/quick/qquicktableview/data/delegatewithanchors.qml
index 0b549f09a4..8b192e0b9e 100644
--- a/tests/auto/quick/qquicktableview/data/delegatewithanchors.qml
+++ b/tests/auto/quick/qquicktableview/data/delegatewithanchors.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/deletedDelegate.qml b/tests/auto/quick/qquicktableview/data/deletedDelegate.qml
new file mode 100644
index 0000000000..ec3161bbac
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/deletedDelegate.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.15
+
+Item {
+ width: 800
+ height: 600
+
+ Component {
+ id: dyn
+ Item {
+ property Component comp: Item {}
+ }
+ }
+
+ TableView {
+ id: tv
+ anchors.fill: parent
+ objectName: "tableview"
+ }
+
+ Component.onCompleted: {
+ let o = dyn.createObject();
+ tv.delegate = o.comp;
+ o.destroy();
+ }
+}
diff --git a/tests/auto/quick/qquicktableview/data/deprecatedapi.qml b/tests/auto/quick/qquicktableview/data/deprecatedapi.qml
new file mode 100644
index 0000000000..2abeeb6ae9
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/deprecatedapi.qml
@@ -0,0 +1,25 @@
+import QtQuick
+
+Item {
+ width: 400
+ height: 300
+ visible: true
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ delegate: Rectangle {
+ implicitWidth: 40
+ implicitHeight: 20
+ border.width: 1
+ }
+
+ function positionUsingDeprecatedEnum()
+ {
+ // Using Qt.Alignment for the second argument is deprecated, but supported
+ positionViewAtCell(columns - 1, rows - 1, Qt.AlignBottom | Qt.AlignRight)
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktableview/data/editdelegate.qml b/tests/auto/quick/qquicktableview/data/editdelegate.qml
new file mode 100644
index 0000000000..0c8bee2b27
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/editdelegate.qml
@@ -0,0 +1,60 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Window
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ clip: true
+
+ property Item editItem: null
+ property var editIndex
+
+ selectionModel: ItemSelectionModel {}
+
+ delegate: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 50
+
+ required property bool editing
+
+ Text {
+ anchors.centerIn: parent
+ text: display
+ }
+
+ TableView.editDelegate: TextInput {
+ id: editRoot
+ anchors.fill: parent
+ text: display
+ horizontalAlignment: TextInput.AlignHCenter
+ verticalAlignment: TextInput.AlignVCenter
+ activeFocusOnTab: true
+
+ required property bool current
+ required property bool selected
+ required property bool editing
+
+ Component.onCompleted: {
+ tableView.editItem = editRoot
+ tableView.editIndex = tableView.index(row, column)
+ selectAll()
+ }
+
+ Component.onDestruction: {
+ tableView.editItem = null
+ tableView.editIndex = tableView.index(-1, -1)
+ }
+ }
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/data/editdelegate_combobox.qml b/tests/auto/quick/qquicktableview/data/editdelegate_combobox.qml
new file mode 100644
index 0000000000..c1344575ff
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/editdelegate_combobox.qml
@@ -0,0 +1,67 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Controls
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ clip: true
+
+ property Item editItem: null
+ property Item focusItem: null
+ property var editIndex
+ property int commitCount: 0
+ property int comboFocusCount: 0
+
+ selectionModel: ItemSelectionModel {}
+
+ delegate: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 50
+
+ required property bool editing
+
+ Text {
+ anchors.centerIn: parent
+ text: display
+ visible: !editing
+ }
+
+ TableView.editDelegate: FocusScope {
+ id: editRoot
+ anchors.fill: parent
+ required property bool current
+ required property bool selected
+ required property bool editing
+
+ TableView.onCommit: tableView.commitCount++;
+
+ Component.onCompleted: {
+ tableView.editItem = editRoot
+ tableView.editIndex = tableView.index(row, column)
+ }
+
+ Component.onDestruction: {
+ tableView.editItem = null
+ tableView.editIndex = tableView.index(-1, -1)
+ }
+
+ ComboBox {
+ focus: true
+ model: 4
+ onActiveFocusChanged: if (activeFocus) tableView.comboFocusCount++;
+ }
+ }
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/data/forcelayout.qml b/tests/auto/quick/qquicktableview/data/forcelayout.qml
index f03dc2f25b..5beaf2bd25 100644
--- a/tests/auto/quick/qquicktableview/data/forcelayout.qml
+++ b/tests/auto/quick/qquicktableview/data/forcelayout.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/hiderowsandcolumns.qml b/tests/auto/quick/qquicktableview/data/hiderowsandcolumns.qml
index b11cb1476c..1a2737ad28 100644
--- a/tests/auto/quick/qquicktableview/data/hiderowsandcolumns.qml
+++ b/tests/auto/quick/qquicktableview/data/hiderowsandcolumns.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/iscolumnloaded.qml b/tests/auto/quick/qquicktableview/data/iscolumnloaded.qml
new file mode 100644
index 0000000000..84cbe981bd
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/iscolumnloaded.qml
@@ -0,0 +1,67 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Window
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+ property int itemsInColumnAfterLoaded: 0
+ property int itemsInRowAfterLoaded: 0
+
+ TableView {
+ id: tableView
+ width: 600
+ height: 400
+ anchors.margins: 1
+ clip: true
+ delegate: tableViewDelegate
+ columnSpacing: 1
+ rowSpacing: 1
+ columnWidthProvider: function(column) {
+ if (isColumnLoaded(column)) {
+ var count = 0;
+ for (var row = topRow; row <= bottomRow; ++row) {
+ var item = itemAtCell(Qt.point(column, row))
+ if (item)
+ count++;
+ }
+ itemsInColumnAfterLoaded = count;
+ }
+
+ return -1
+ }
+ rowHeightProvider: function(row) {
+ if (isRowLoaded(row)) {
+ var count = 0;
+ for (var column = leftColumn; column <= rightColumn; ++column) {
+ var item = itemAtCell(Qt.point(column, row))
+ if (item)
+ count++;
+ }
+ itemsInRowAfterLoaded = count;
+ }
+
+ return -1
+ }
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ objectName: "tableViewDelegate"
+ implicitWidth: 20
+ implicitHeight: 20
+ color: "lightgray"
+ border.width: 1
+ Text {
+ anchors.centerIn: parent
+ text: modelData
+ }
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/data/plaintableview.qml b/tests/auto/quick/qquicktableview/data/plaintableview.qml
index 90271eda71..a18b1c03eb 100644
--- a/tests/auto/quick/qquicktableview/data/plaintableview.qml
+++ b/tests/auto/quick/qquicktableview/data/plaintableview.qml
@@ -1,44 +1,7 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-import QtQuick 2.12
-import QtQuick.Window 2.3
+import QtQuick
Item {
width: 640
@@ -59,6 +22,7 @@ Item {
delegate: tableViewDelegate
columnSpacing: 1
rowSpacing: 1
+ animate: false
}
Component {
diff --git a/tests/auto/quick/qquicktableview/data/positionlast.qml b/tests/auto/quick/qquicktableview/data/positionlast.qml
new file mode 100644
index 0000000000..fcc2f34fae
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/positionlast.qml
@@ -0,0 +1,52 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Item {
+ width: 300
+ height: 300
+
+ property alias tableView: tableView
+ property bool positionOnRowsChanged: false
+ property bool positionOnColumnsChanged: false
+ property bool positionOnContentHeightChanged: false
+ property bool positionOnContentWidthChanged: false
+
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ clip: true
+
+ delegate: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 100
+ Text {
+ anchors.centerIn: parent
+ text: "row:" + row + "\ncol:" + column
+ font.pixelSize: 10
+ }
+ }
+
+ onRowsChanged: {
+ if (positionOnRowsChanged)
+ positionViewAtRow(rows - 1, TableView.AlignBottom)
+ }
+
+ onColumnsChanged: {
+ if (positionOnColumnsChanged)
+ positionViewAtColumn(columns - 1, TableView.AlignRight)
+ }
+
+ onContentHeightChanged: {
+ if (positionOnContentHeightChanged)
+ positionViewAtRow(rows - 1, TableView.AlignBottom)
+ }
+
+ onContentWidthChanged: {
+ if (positionOnContentWidthChanged)
+ positionViewAtColumn(columns - 1, TableView.AlignRight)
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/data/qqmllistpropertymodel.qml b/tests/auto/quick/qquicktableview/data/qqmllistpropertymodel.qml
index 38fca2c5cb..851fcb7310 100644
--- a/tests/auto/quick/qquicktableview/data/qqmllistpropertymodel.qml
+++ b/tests/auto/quick/qquicktableview/data/qqmllistpropertymodel.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/resetJsModelData.qml b/tests/auto/quick/qquicktableview/data/resetJsModelData.qml
new file mode 100644
index 0000000000..def5346147
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/resetJsModelData.qml
@@ -0,0 +1,19 @@
+import QtQuick
+
+Item {
+ width: 100
+ height: 300
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ property int modelUpdated: 0
+ onModelChanged: { ++modelUpdated }
+ delegate: Item {
+ implicitHeight: 10
+ implicitWidth: 10
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktableview/data/resetModelData.qml b/tests/auto/quick/qquicktableview/data/resetModelData.qml
new file mode 100644
index 0000000000..f7b3ec3009
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/resetModelData.qml
@@ -0,0 +1,25 @@
+import QtQuick
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ height: 300
+ width: 200
+
+ property bool success: false
+
+ delegate: Rectangle {
+ required property var model
+ implicitWidth: 100
+ implicitHeight: 50
+ property var mydata: model?.custom ?? model.display
+ onMydataChanged: tableView.success = mydata === 42
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktableview/data/setcontentpos.qml b/tests/auto/quick/qquicktableview/data/setcontentpos.qml
index fa040d3959..69cf73164f 100644
--- a/tests/auto/quick/qquicktableview/data/setcontentpos.qml
+++ b/tests/auto/quick/qquicktableview/data/setcontentpos.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/sizefromdelegate.qml b/tests/auto/quick/qquicktableview/data/sizefromdelegate.qml
new file mode 100644
index 0000000000..deb6b81f8e
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/sizefromdelegate.qml
@@ -0,0 +1,38 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.12
+import QtQuick.Window 2.3
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ width: 600
+ height: 400
+ anchors.margins: 1
+ delegate: tableViewDelegate
+ columnSpacing: 1
+ rowSpacing: 1
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ color: "lightgray"
+ implicitWidth: text.width
+ implicitHeight: text.height
+
+ Text {
+ id: text
+ anchors.centerIn: parent
+ text: modelData
+ }
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/data/syncviewsimple.qml b/tests/auto/quick/qquicktableview/data/syncviewsimple.qml
index 012cceaa9d..0fc2e6a819 100644
--- a/tests/auto/quick/qquicktableview/data/syncviewsimple.qml
+++ b/tests/auto/quick/qquicktableview/data/syncviewsimple.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.14
import QtQuick.Window 2.3
@@ -49,6 +13,9 @@ Item {
property alias tableViewV: tableViewV
property alias tableViewHV: tableViewHV
+ property real delegateWidth: 30
+ property real delegateHeight: 60
+
Column {
spacing: 10
TableView {
@@ -93,7 +60,7 @@ Item {
height: 100
anchors.margins: 1
clip: true
- delegate: tableViewDelegate
+ delegate: tableViewDelegateMainView
columnSpacing: 1
rowSpacing: 1
@@ -106,10 +73,27 @@ Item {
id: tableViewDelegate
Rectangle {
objectName: "tableViewDelegate"
+ color: "lightblue"
+ border.width: 1
+ implicitWidth: 100
+ implicitHeight: 100
+
+ Text {
+ anchors.centerIn: parent
+ font.pixelSize: 10
+ text: parent.TableView.view.objectName + "\n" + column + ", " + row
+ }
+ }
+ }
+
+ Component {
+ id: tableViewDelegateMainView
+ Rectangle {
+ objectName: "tableViewDelegate"
color: "lightgray"
border.width: 1
- implicitWidth: 30
- implicitHeight: 60
+ implicitWidth: delegateWidth
+ implicitHeight: delegateHeight
Text {
anchors.centerIn: parent
diff --git a/tests/auto/quick/qquicktableview/data/tableviewdefaultspacing.qml b/tests/auto/quick/qquicktableview/data/tableviewdefaultspacing.qml
index f4a3094dd2..f3563500c9 100644
--- a/tests/auto/quick/qquicktableview/data/tableviewdefaultspacing.qml
+++ b/tests/auto/quick/qquicktableview/data/tableviewdefaultspacing.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/tableviewfocus.qml b/tests/auto/quick/qquicktableview/data/tableviewfocus.qml
index c388e2c8de..3bb7040e7f 100644
--- a/tests/auto/quick/qquicktableview/data/tableviewfocus.qml
+++ b/tests/auto/quick/qquicktableview/data/tableviewfocus.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml b/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml
index 425b950fce..54414b6a71 100644
--- a/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml
+++ b/tests/auto/quick/qquicktableview/data/tableviewimplicitsize.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/tableviewinteractive.qml b/tests/auto/quick/qquicktableview/data/tableviewinteractive.qml
new file mode 100644
index 0000000000..526313dc24
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/tableviewinteractive.qml
@@ -0,0 +1,32 @@
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ id: rootItem
+
+ width: 200
+ height: 200
+ visible: true
+
+ property int eventCount: 0
+ property alias tableView: tableView
+
+ MouseArea {
+ anchors.fill: parent
+ onPressed: function(mouse) {
+ ++eventCount
+ }
+ }
+
+ TableView {
+ id: tableView
+ objectName: "tableView"
+ anchors.fill: parent
+ model: 1
+ delegate: Rectangle {
+ color: "red"
+ implicitWidth: 200
+ implicitHeight: 200
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktableview/data/tableviewwithselected1.qml b/tests/auto/quick/qquicktableview/data/tableviewwithselected1.qml
new file mode 100644
index 0000000000..f0396c2c34
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/tableviewwithselected1.qml
@@ -0,0 +1,38 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Window
+import QtQml.Models
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ width: 600
+ height: 400
+ anchors.margins: 1
+ clip: true
+ delegate: tableViewDelegate
+ columnSpacing: 1
+ rowSpacing: 1
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ objectName: "tableViewDelegate"
+ implicitWidth: 20
+ implicitHeight: 20
+ required property bool selected
+ required property bool current
+ color: selected ? "lightgray" : "green"
+ border.color: current ? "red" : "transparent"
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/data/tableviewwithselected2.qml b/tests/auto/quick/qquicktableview/data/tableviewwithselected2.qml
new file mode 100644
index 0000000000..489a00b3f8
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/tableviewwithselected2.qml
@@ -0,0 +1,39 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Window
+import QtQml.Models
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ width: 600
+ height: 400
+ anchors.margins: 1
+ clip: true
+ delegate: tableViewDelegate
+ columnSpacing: 1
+ rowSpacing: 1
+ selectionModel: ItemSelectionModel {}
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ objectName: "tableViewDelegate"
+ implicitWidth: 100
+ implicitHeight: 100
+ // Add a selected property, but since it's not
+ // required, TableView should not touch it.
+ property bool selected
+ color: selected ? "lightgray" : "green"
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/data/tweakimplicitsize.qml b/tests/auto/quick/qquicktableview/data/tweakimplicitsize.qml
index ecc79a9368..e0e9c01908 100644
--- a/tests/auto/quick/qquicktableview/data/tweakimplicitsize.qml
+++ b/tests/auto/quick/qquicktableview/data/tweakimplicitsize.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/unloadheader.qml b/tests/auto/quick/qquicktableview/data/unloadheader.qml
new file mode 100644
index 0000000000..5b15e4c752
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/unloadheader.qml
@@ -0,0 +1,43 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import Qt.labs.qmlmodels
+
+Item {
+ width: 640
+ height: 480
+
+ property alias tableView: tableView
+ property alias loader: verticalHeaderLoader
+
+ Loader {
+ id: verticalHeaderLoader
+ x: 0
+ width: item ? item.contentWidth : 0
+ height: parent.height
+ sourceComponent: TableView {
+ model: 5
+ syncView: tableView
+ syncDirection: Qt.Vertical
+ delegate: Text {
+ text: index
+ }
+ }
+ }
+
+ TableView {
+ id: tableView
+ anchors {
+ left: verticalHeaderLoader.right
+ right: parent.right
+ top: parent.top
+ bottom: parent.bottom
+ }
+
+ model: 5
+ delegate: Text {
+ text: index
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktableview/data/usechooserwithoutdefault.qml b/tests/auto/quick/qquicktableview/data/usechooserwithoutdefault.qml
index 847500d71f..4ff2a7401f 100644
--- a/tests/auto/quick/qquicktableview/data/usechooserwithoutdefault.qml
+++ b/tests/auto/quick/qquicktableview/data/usechooserwithoutdefault.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/usefaultyrowcolumnprovider.qml b/tests/auto/quick/qquicktableview/data/usefaultyrowcolumnprovider.qml
index 1e35d65bcd..65d918e072 100644
--- a/tests/auto/quick/qquicktableview/data/usefaultyrowcolumnprovider.qml
+++ b/tests/auto/quick/qquicktableview/data/usefaultyrowcolumnprovider.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/userowcolumnprovider.qml b/tests/auto/quick/qquicktableview/data/userowcolumnprovider.qml
index e9f01b6abf..686bed12d0 100644
--- a/tests/auto/quick/qquicktableview/data/userowcolumnprovider.qml
+++ b/tests/auto/quick/qquicktableview/data/userowcolumnprovider.qml
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
import QtQuick.Window 2.3
diff --git a/tests/auto/quick/qquicktableview/data/zerosizedtableview.qml b/tests/auto/quick/qquicktableview/data/zerosizedtableview.qml
new file mode 100644
index 0000000000..b885684b18
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/zerosizedtableview.qml
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Window
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ width: 0
+ height: 0
+ delegate: tableViewDelegate
+
+ Component.onCompleted: {
+ positionViewAtCell(
+ Qt.point(0,0),
+ TableView.AlignHCenter,
+ Qt.point(-5,-5)
+ );
+ }
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ objectName: "tableViewDelegate"
+ implicitWidth: tableView.width
+ implicitHeight: 50
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/data/zerosizedviewport.qml b/tests/auto/quick/qquicktableview/data/zerosizedviewport.qml
new file mode 100644
index 0000000000..f32c7bd3b2
--- /dev/null
+++ b/tests/auto/quick/qquicktableview/data/zerosizedviewport.qml
@@ -0,0 +1,31 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Window
+
+Item {
+ width: 640
+ height: 450
+
+ property alias tableView: tableView
+
+ TableView {
+ id: tableView
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ width: contentWidth
+ delegate: tableViewDelegate
+ }
+
+ Component {
+ id: tableViewDelegate
+ Rectangle {
+ objectName: "tableViewDelegate"
+ implicitWidth: tableView.width
+ implicitHeight: 50
+ }
+ }
+
+}
diff --git a/tests/auto/quick/qquicktableview/testmodel.h b/tests/auto/quick/qquicktableview/testmodel.h
index 3db32938be..21ed7e03a5 100644
--- a/tests/auto/quick/qquicktableview/testmodel.h
+++ b/tests/auto/quick/qquicktableview/testmodel.h
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QtCore>
#include <QtGui/QStandardItemModel>
@@ -61,13 +36,27 @@ public:
QVariant data(const QModelIndex &index, int role) const override
{
- if (!index.isValid() || role != Qt::DisplayRole)
+ if (!index.isValid())
return QVariant();
- int serializedIndex = index.row() + (index.column() * m_columns);
- if (modelData.contains(serializedIndex))
- return modelData.value(serializedIndex);
- return QStringLiteral("%1").arg(index.row());
+ QVariant ret;
+
+ switch (role) {
+ case Qt::UserRole:
+ ret = 42;
+ break;
+ case Qt::DisplayRole: {
+ int serializedIndex = index.row() + (index.column() * m_columns);
+ if (modelData.contains(serializedIndex))
+ ret = modelData.value(serializedIndex);
+ else
+ ret = QStringLiteral("%1").arg(index.row()); }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
}
Q_INVOKABLE QVariant dataFromSerializedIndex(int index) const
@@ -79,9 +68,18 @@ public:
QHash<int, QByteArray> roleNames() const override
{
+ if (m_useCustomRoleNames)
+ return { { Qt::UserRole, "custom"} };
return { {Qt::DisplayRole, "display"} };
}
+ Q_INVOKABLE void useCustomRoleNames(bool use)
+ {
+ beginResetModel();
+ m_useCustomRoleNames = use;
+ endResetModel();
+ }
+
Q_INVOKABLE void setModelData(const QPoint &cell, const QSize &span, const QString &string)
{
for (int c = 0; c < span.width(); ++c) {
@@ -184,6 +182,22 @@ public:
insertRow(row, QModelIndex());
}
+ Q_INVOKABLE void addColumn(int column)
+ {
+ insertColumn(column, QModelIndex());
+ }
+
+ Qt::ItemFlags flags(const QModelIndex &index) const override
+ {
+ Q_UNUSED(index)
+ return m_flags;
+ }
+
+ void setFlags(Qt::ItemFlags flags)
+ {
+ m_flags = flags;
+ }
+
signals:
void rowCountChanged();
void columnCountChanged();
@@ -192,7 +206,9 @@ private:
int m_rows = 0;
int m_columns = 0;
bool m_dataCanBeFetched = false;
+ bool m_useCustomRoleNames = false;
QHash<int, QString> modelData;
+ Qt::ItemFlags m_flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
};
#define TestModelAsVariant(...) QVariant::fromValue(QSharedPointer<TestModel>(new TestModel(__VA_ARGS__)))
diff --git a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
index 2bd7c38a11..bb425b5a6f 100644
--- a/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
+++ b/tests/auto/quick/qquicktableview/tst_qquicktableview.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
#include <QtQuickTest/quicktest.h>
@@ -33,22 +8,25 @@
#include <QtQuick/private/qquicktableview_p.h>
#include <QtQuick/private/qquicktableview_p_p.h>
#include <QtQuick/private/qquickloader_p.h>
+#include <QtQuick/private/qquickdraghandler_p.h>
+#include <QtQuick/private/qquicktextinput_p.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlexpression.h>
#include <QtQml/qqmlincubator.h>
+#include <QtQml/qqmlcomponent.h>
#include <QtQmlModels/private/qqmlobjectmodel_p.h>
#include <QtQmlModels/private/qqmllistmodel_p.h>
#include "testmodel.h"
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
-#include "../shared/visualtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
-using namespace QQuickViewTestUtil;
-using namespace QQuickVisualTestUtil;
+using namespace QQuickViewTestUtils;
+using namespace QQuickVisualTestUtils;
static const char* kDelegateObjectName = "tableViewDelegate";
static const char *kDelegatesCreatedCountProp = "delegatesCreatedCount";
@@ -65,6 +43,7 @@ Q_DECLARE_METATYPE(QMarginsF);
#define LOAD_TABLEVIEW(fileName) \
view->setSource(testFileUrl(fileName)); \
view->show(); \
+ view->requestActivate(); \
QVERIFY(QTest::qWaitForWindowActive(view)); \
GET_QML_TABLEVIEW(tableView)
@@ -73,14 +52,14 @@ Q_DECLARE_METATYPE(QMarginsF);
view->show(); \
QVERIFY(QTest::qWaitForWindowActive(view)); \
auto loader = view->rootObject()->property("loader").value<QQuickLoader *>(); \
- loader->setSource(QUrl::fromLocalFile("data/" fileName)); \
+ loader->setSourceWithoutResolve(testFileUrl(fileName)); \
QTRY_VERIFY(loader->item()); \
QCOMPARE(loader->status(), QQuickLoader::Status::Ready); \
GET_QML_TABLEVIEW(tableView)
#define WAIT_UNTIL_POLISHED_ARG(item) \
QVERIFY(QQuickTest::qIsPolishScheduled(item)); \
- QVERIFY(QQuickTest::qWaitForItemPolished(item))
+ QVERIFY(QQuickTest::qWaitForPolish(item))
#define WAIT_UNTIL_POLISHED WAIT_UNTIL_POLISHED_ARG(tableView)
class tst_QQuickTableView : public QQmlDataTest
@@ -107,21 +86,29 @@ private slots:
void checkPreload();
void checkZeroSizedDelegate();
void checkImplicitSizeDelegate();
+ void checkZeroSizedTableView();
+ void checkZeroSizedViewPort();
void checkColumnWidthWithoutProvider();
+ void checkColumnWidthAndRowHeightFunctions();
void checkDelegateWithAnchors();
void checkColumnWidthProvider();
void checkColumnWidthProviderInvalidReturnValues();
void checkColumnWidthProviderNegativeReturnValue();
void checkColumnWidthProviderNotCallable();
+ void checkColumnWidthBoundToViewWidth();
void checkRowHeightWithoutProvider();
void checkRowHeightProvider();
void checkRowHeightProviderInvalidReturnValues();
void checkRowHeightProviderNegativeReturnValue();
void checkRowHeightProviderNotCallable();
+ void isColumnLoadedAndIsRowLoaded();
void checkForceLayoutFunction();
void checkForceLayoutEndUpDoingALayout();
- void checkForceLayoutDuringModelChange();
+ void checkForceLayoutInbetweenAddingRowsToModel();
+ void checkForceLayoutWhenAllItemsAreHidden();
+ void checkLayoutChangedSignal();
void checkContentWidthAndHeight();
+ void checkContentWidthAndHeightForSmallTables();
void checkPageFlicking();
void checkExplicitContentWidthAndHeight();
void checkExtents_origin();
@@ -167,16 +154,21 @@ private slots:
void checkTableviewInsideAsyncLoader();
void hideRowsAndColumns_data();
void hideRowsAndColumns();
+ void hideAndShowFirstColumn();
+ void hideAndShowFirstRow();
void checkThatRevisionedPropertiesCannotBeUsedInOldImports();
void checkSyncView_rootView_data();
void checkSyncView_rootView();
void checkSyncView_childViews_data();
void checkSyncView_childViews();
void checkSyncView_differentSizedModels();
+ void checkSyncView_differentGeometry();
void checkSyncView_connect_late_data();
void checkSyncView_connect_late();
void checkSyncView_pageFlicking();
void checkSyncView_emptyModel();
+ void checkSyncView_topLeftChanged();
+ void checkSyncView_unloadHeader();
void delegateWithRequiredProperties();
void checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable();
void replaceModel();
@@ -186,15 +178,111 @@ private slots:
void positionViewAtRow();
void positionViewAtColumn_data();
void positionViewAtColumn();
+ void positionViewAtRowClamped_data();
+ void positionViewAtRowClamped();
+ void positionViewAtColumnClamped_data();
+ void positionViewAtColumnClamped();
+ void positionViewAtCellWithAnimation();
+ void positionViewAtCell_VisibleAndContain_data();
+ void positionViewAtCell_VisibleAndContain();
+ void positionViewAtCell_VisibleAndContain_SubRect_data();
+ void positionViewAtCell_VisibleAndContain_SubRect();
+ void positionViewAtCellForLargeCells_data();
+ void positionViewAtCellForLargeCells();
+ void positionViewAtCellForLargeCellsUsingSubrect();
+ void positionViewAtLastRow_data();
+ void positionViewAtLastRow();
+ void positionViewAtLastColumn_data();
+ void positionViewAtLastColumn();
void itemAtCell_data();
void itemAtCell();
void leftRightTopBottomProperties_data();
void leftRightTopBottomProperties();
+ void leftRightTopBottomUpdatedBeforeSignalEmission();
void checkContentSize_data();
void checkContentSize();
+ void checkSelectionModelWithRequiredSelectedProperty_data();
+ void checkSelectionModelWithRequiredSelectedProperty();
+ void checkSelectionModelWithUnrequiredSelectedProperty();
+ void removeAndAddSelectionModel();
+ void warnOnWrongModelInSelectionModel();
+ void selectionBehaviorCells_data();
+ void selectionBehaviorCells();
+ void selectionBehaviorRows();
+ void selectionBehaviorColumns();
+ void selectionBehaviorDisabled();
+ void testSelectableStartPosEndPosOutsideView();
+ void testSelectableScrollTowardsPos();
+ void setCurrentIndexFromSelectionModel();
+ void clearSelectionOnTap_data();
+ void clearSelectionOnTap();
+ void moveCurrentIndexUsingArrowKeys();
+ void moveCurrentIndexUsingHomeAndEndKeys();
+ void moveCurrentIndexUsingPageUpDownKeys();
+ void moveCurrentIndexUsingTabKey_data();
+ void moveCurrentIndexUsingTabKey();
+ void respectActiveFocusOnTabDisabled();
+ void setCurrentIndexOnFirstKeyPress_data();
+ void setCurrentIndexOnFirstKeyPress();
+ void setCurrentIndexFromMouse();
+ void showMarginsWhenNavigatingToEnd();
+ void disableKeyNavigation();
+ void disablePointerNavigation();
+ void selectUsingArrowKeys();
+ void selectUsingHomeAndEndKeys();
+ void selectUsingPageUpDownKeys();
+ void testDeprecatedApi();
+ void alternatingRows();
+ void boundDelegateComponent();
+ void setColumnWidth_data();
+ void setColumnWidth();
+ void setColumnWidthWhenProviderIsSet();
+ void setColumnWidthForInvalidColumn();
+ void setColumnWidthWhenUsingSyncView();
+ void resetColumnWidth();
+ void clearColumnWidths();
+ void setRowHeight_data();
+ void setRowHeight();
+ void setRowHeightWhenProviderIsSet();
+ void setRowHeightForInvalidRow();
+ void setRowHeightWhenUsingSyncView();
+ void resetRowHeight();
+ void clearRowHeights();
+ void deletedDelegate();
+ void columnResizing_data();
+ void columnResizing();
+ void tableViewInteractive();
+ void rowResizing_data();
+ void rowResizing();
+ void rowAndColumnResizing_data();
+ void rowAndColumnResizing();
+ void columnResizingDisabled();
+ void rowResizingDisabled();
+ void dragFromCellCenter();
+ void tapOnResizeArea_data();
+ void tapOnResizeArea();
+ void editUsingEditTriggers_data();
+ void editUsingEditTriggers();
+ void editUsingTab();
+ void editDelegateComboBox();
+ void editOnNonEditableCell_data();
+ void editOnNonEditableCell();
+ void noEditDelegate_data();
+ void noEditDelegate();
+ void editAndCloseEditor();
+ void editWarning_noEditDelegate();
+ void editWarning_invalidIndex();
+ void editWarning_nonEditableModelItem();
+ void attachedPropertiesOnEditDelegate();
+ void requiredPropertiesOnEditDelegate();
+ void resettingRolesRespected();
+ void checkScroll_data();
+ void checkScroll();
+ void checkRebuildJsModel();
};
tst_QQuickTableView::tst_QQuickTableView()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
@@ -224,6 +312,18 @@ QPoint tst_QQuickTableView::getContextRowAndColumn(const QQuickItem *item) const
return QPoint(column, row);
}
+static void sendWheelEvent(QQuickWindow *window, QPoint pos, QPoint angleDelta,
+ QPoint pixelDelta,
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier,
+ Qt::ScrollPhase phase = Qt::NoScrollPhase,
+ bool inverted = false) {
+ QWheelEvent wheelEvent(pos, window->mapToGlobal(pos), pixelDelta,
+ angleDelta, Qt::NoButton, modifiers, phase,
+ inverted);
+ QGuiApplication::sendEvent(window, &wheelEvent);
+ qApp->processEvents();
+}
+
void tst_QQuickTableView::setAndGetModel_data()
{
QTest::addColumn<QVariant>("model");
@@ -260,8 +360,9 @@ void tst_QQuickTableView::emptyModel()
LOAD_TABLEVIEW("plaintableview.qml");
tableView->setModel(model);
- WAIT_UNTIL_POLISHED;
- QCOMPARE(tableViewPrivate->loadedItems.count(), 0);
+ if (QQuickTest::qIsPolishScheduled(tableView))
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(tableViewPrivate->loadedItems.size(), 0);
}
void tst_QQuickTableView::checkPreload_data()
@@ -344,6 +445,54 @@ void tst_QQuickTableView::checkImplicitSizeDelegate()
}
}
+void tst_QQuickTableView::checkZeroSizedTableView()
+{
+ // Check that we don't load any delegates if TableView
+ // itself has zero size.
+ LOAD_TABLEVIEW("zerosizedtableview.qml");
+
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ QVERIFY(tableViewPrivate->loadedItems.isEmpty());
+
+ // Resize TableView. This should load delegate. Since
+ // the delegate's implicitWidth is bound to TableView.width,
+ // we expect the delegates to now get the same width.
+ tableView->setWidth(200);
+ tableView->setHeight(100);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewPrivate->loadedItems.size(), 2);
+ const auto item = tableView->itemAtIndex(tableView->index(0, 0));
+ QVERIFY(item);
+ QCOMPARE(item->width(), 200);
+
+ // Hide TableView again, and check that all items are
+ // unloaded, except the topLeft corner item.
+ tableView->setWidth(0);
+ tableView->setHeight(0);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewPrivate->loadedItems.size(), 1);
+}
+
+void tst_QQuickTableView::checkZeroSizedViewPort()
+{
+ LOAD_TABLEVIEW("zerosizedviewport.qml");
+
+ auto model = TestModelAsVariant(20, 20);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ QVERIFY(!tableViewPrivate->loadedItems.isEmpty());
+}
+
void tst_QQuickTableView::checkColumnWidthWithoutProvider()
{
// Checks that a function isn't assigned to the columnWidthProvider property
@@ -357,15 +506,42 @@ void tst_QQuickTableView::checkColumnWidthWithoutProvider()
WAIT_UNTIL_POLISHED;
- for (const int column : tableViewPrivate->loadedColumns.keys()) {
+ for (const int column : tableViewPrivate->loadedColumns) {
const qreal expectedColumnWidth = tableViewPrivate->sizeHintForColumn(column);
- for (const int row : tableViewPrivate->loadedRows.keys()) {
+ for (const int row : tableViewPrivate->loadedRows) {
const auto item = tableViewPrivate->loadedTableItem(QPoint(column, row))->item;
QCOMPARE(item->width(), expectedColumnWidth);
}
}
}
+void tst_QQuickTableView::checkColumnWidthAndRowHeightFunctions()
+{
+ // Checks that the column width and row height functions return
+ // the correct sizes. When we have row-, or columnWidthProviders
+ // the actual row and column sizes will normally differ from the
+ // minimum row and column sizes (which is the maximum implicit
+ // size found among the delegates).
+ LOAD_TABLEVIEW("userowcolumnprovider.qml");
+
+ const int count = 4;
+ auto model = TestModelAsVariant(count, count);
+
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ const qreal expectedimplicitSize = 20;
+
+ for (int i = 0; i < count; ++i) {
+ const qreal expectedSize = i + 10;
+ QCOMPARE(tableView->columnWidth(i), expectedSize);
+ QCOMPARE(tableView->rowHeight(i), expectedSize);
+ QCOMPARE(tableView->implicitColumnWidth(i), expectedimplicitSize);
+ QCOMPARE(tableView->implicitRowHeight(i), expectedimplicitSize);
+ }
+}
+
void tst_QQuickTableView::checkDelegateWithAnchors()
{
// Checks that we issue a warning if the delegate has anchors
@@ -453,6 +629,27 @@ void tst_QQuickTableView::checkColumnWidthProviderNotCallable()
QCOMPARE(fxItem->item->width(), kDefaultColumnWidth);
}
+void tst_QQuickTableView::checkColumnWidthBoundToViewWidth()
+{
+ // Check that you can bind the width of a delegate to the
+ // width of TableView, and that it updates when TableView is resized.
+ LOAD_TABLEVIEW("columnwidthboundtoviewwidth.qml");
+
+ auto model = TestModelAsVariant(10, 1);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ for (auto fxItem : tableViewPrivate->loadedItems)
+ QCOMPARE(fxItem->item->width(), tableView->width());
+
+ tableView->setWidth(200);
+ WAIT_UNTIL_POLISHED;
+
+ for (auto fxItem : tableViewPrivate->loadedItems)
+ QCOMPARE(fxItem->item->width(), 200);
+}
+
void tst_QQuickTableView::checkRowHeightWithoutProvider()
{
// Checks that a function isn't assigned to the rowHeightProvider property
@@ -466,9 +663,9 @@ void tst_QQuickTableView::checkRowHeightWithoutProvider()
WAIT_UNTIL_POLISHED;
- for (const int row : tableViewPrivate->loadedRows.keys()) {
+ for (const int row : tableViewPrivate->loadedRows) {
const qreal expectedRowHeight = tableViewPrivate->sizeHintForRow(row);
- for (const int column : tableViewPrivate->loadedColumns.keys()) {
+ for (const int column : tableViewPrivate->loadedColumns) {
const auto item = tableViewPrivate->loadedTableItem(QPoint(column, row))->item;
QCOMPARE(item->height(), expectedRowHeight);
}
@@ -551,6 +748,26 @@ void tst_QQuickTableView::checkRowHeightProviderNotCallable()
QCOMPARE(fxItem->item->height(), kDefaultRowHeight);
}
+void tst_QQuickTableView::isColumnLoadedAndIsRowLoaded()
+{
+ // Check that all the delegate items are loaded and available from
+ // the columnWidthProvider/rowHeightProvider when 'isColumnLoaded()'
+ // and 'isRowLoaded()' returns true.
+ LOAD_TABLEVIEW("iscolumnloaded.qml");
+
+ auto model = TestModelAsVariant(4, 5);
+
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ const int itemsInColumnAfterLoaded = view->rootObject()->property("itemsInColumnAfterLoaded").toInt();
+ const int itemsInRowAfterLoaded = view->rootObject()->property("itemsInRowAfterLoaded").toInt();
+
+ QCOMPARE(itemsInColumnAfterLoaded, tableView->rows());
+ QCOMPARE(itemsInRowAfterLoaded, tableView->columns());
+}
+
void tst_QQuickTableView::checkForceLayoutFunction()
{
// When we set the 'columnWidths' property in the test file, the
@@ -612,10 +829,11 @@ void tst_QQuickTableView::checkForceLayoutEndUpDoingALayout()
QCOMPARE(tableView->contentHeight(), (9 * (newDelegateSize + rowSpacing)) - rowSpacing);
}
-void tst_QQuickTableView::checkForceLayoutDuringModelChange()
+void tst_QQuickTableView::checkForceLayoutInbetweenAddingRowsToModel()
{
- // Check that TableView doesn't assert if we call
- // forceLayout() in the middle of a model change.
+ // Check that TableView doesn't assert if we call forceLayout() while waiting
+ // for a callback from the model that the row count has changed. Also make sure
+ // that we don't move the contentItem while doing so.
LOAD_TABLEVIEW("plaintableview.qml");
const int initialRowCount = 10;
@@ -630,9 +848,91 @@ void tst_QQuickTableView::checkForceLayoutDuringModelChange()
WAIT_UNTIL_POLISHED;
+ const int contentY = 10;
+ tableView->setContentY(contentY);
QCOMPARE(tableView->rows(), initialRowCount);
+ QCOMPARE(tableView->contentY(), contentY);
model.addRow(0);
QCOMPARE(tableView->rows(), initialRowCount + 1);
+ QCOMPARE(tableView->contentY(), contentY);
+}
+
+void tst_QQuickTableView::checkForceLayoutWhenAllItemsAreHidden()
+{
+ // Check that you can have a TableView where all columns are
+ // initially hidden, and then show some columns and call
+ // forceLayout(). This should make the columns become visible.
+ LOAD_TABLEVIEW("forcelayout.qml");
+
+ // Tell all columns to be hidden
+ const char *propertyName = "columnWidths";
+ view->rootObject()->setProperty(propertyName, 0);
+
+ const int rows = 3;
+ const int columns = 3;
+ auto model = TestModelAsVariant(rows, columns);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that the we have no items loaded
+ QCOMPARE(tableViewPrivate->loadedColumns.count(), 0);
+ QCOMPARE(tableViewPrivate->loadedRows.count(), 0);
+ QCOMPARE(tableViewPrivate->loadedItems.size(), 0);
+
+ // Tell all columns to be visible
+ view->rootObject()->setProperty(propertyName, 10);
+ tableView->forceLayout();
+
+ QCOMPARE(tableViewPrivate->loadedRows.count(), rows);
+ QCOMPARE(tableViewPrivate->loadedColumns.count(), columns);
+ QCOMPARE(tableViewPrivate->loadedItems.size(), rows * columns);
+}
+
+void tst_QQuickTableView::checkLayoutChangedSignal()
+{
+ // Check that the layoutChanged signal is emitted
+ // when the layout has changed.
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ const QSignalSpy layoutChanges(tableView, &QQuickTableView::layoutChanged);
+ TestModel model(100, 100);
+ tableView->setModel(QVariant::fromValue(&model));
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(layoutChanges.size(), 1);
+
+ tableView->forceLayout();
+ QCOMPARE(layoutChanges.size(), 2);
+
+ tableView->setRowHeight(1, 10);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(layoutChanges.size(), 3);
+
+ tableView->setColumnWidth(1, 10);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(layoutChanges.size(), 4);
+
+ tableView->setContentX(30);
+ QCOMPARE(layoutChanges.size(), 5);
+
+ tableView->setContentY(30);
+ QCOMPARE(layoutChanges.size(), 6);
+
+ tableView->setContentX(0);
+ QCOMPARE(layoutChanges.size(), 7);
+
+ tableView->setContentY(0);
+ QCOMPARE(layoutChanges.size(), 8);
+
+ model.addRow(1);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(layoutChanges.size(), 9);
+
+ model.removeRow(1);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(layoutChanges.size(), 10);
}
void tst_QQuickTableView::checkContentWidthAndHeight()
@@ -683,6 +983,30 @@ void tst_QQuickTableView::checkContentWidthAndHeight()
QCOMPARE(tableView->contentHeight(), expectedSizeInit);
}
+void tst_QQuickTableView::checkContentWidthAndHeightForSmallTables()
+{
+ // For tables where all the columns in the model are loaded, we know
+ // the exact table width, and can therefore update the content width
+ // if e.g new rows are added or removed. The same is true for rows.
+ // This test will check that we do so.
+ LOAD_TABLEVIEW("sizefromdelegate.qml");
+
+ TestModel model(3, 3);
+ tableView->setModel(QVariant::fromValue(&model));
+ WAIT_UNTIL_POLISHED;
+
+ const qreal initialContentWidth = tableView->contentWidth();
+ const qreal initialContentHeight = tableView->contentHeight();
+ const QString longText = QStringLiteral("Adding a row with a very long text");
+ model.insertRow(0);
+ model.setModelData(QPoint(0, 0), QSize(1, 1), longText);
+
+ WAIT_UNTIL_POLISHED;
+
+ QVERIFY(tableView->contentWidth() > initialContentWidth);
+ QVERIFY(tableView->contentHeight() > initialContentHeight);
+}
+
void tst_QQuickTableView::checkPageFlicking()
{
// Check that we rebuild the table instead of refilling edges, if the viewport moves
@@ -992,7 +1316,7 @@ void tst_QQuickTableView::noDelegate()
WAIT_UNTIL_POLISHED;
items = tableViewPrivate->loadedItems;
- QCOMPARE(items.count(), rows * columns);
+ QCOMPARE(items.size(), rows * columns);
// And then unset the delegate again, and check
// that we end up with no items.
@@ -1081,11 +1405,11 @@ void tst_QQuickTableView::countDelegateItems()
// Check that tableview internals contain the expected number of items
auto const items = tableViewPrivate->loadedItems;
- QCOMPARE(items.count(), count);
+ QCOMPARE(items.size(), count);
// Check that this also matches the items found in the view
auto foundItems = findItems<QQuickItem>(tableView, kDelegateObjectName);
- QCOMPARE(foundItems.count(), count);
+ QCOMPARE(foundItems.size(), count);
}
void tst_QQuickTableView::checkLayoutOfEqualSizedDelegateItems_data()
@@ -2167,7 +2491,7 @@ void tst_QQuickTableView::checkChangingModelFromDelegate()
// And since the QML code tried to add another row as well, we
// expect rebuildScheduled to be true, and a polish event to be pending.
QVERIFY(tableViewPrivate->scheduledRebuildOptions);
- QCOMPARE(tableViewPrivate->polishScheduled, true);
+ QVERIFY(tableViewPrivate->polishScheduled);
WAIT_UNTIL_POLISHED;
// After handling the polish event, we expect also the third row to now be added
@@ -2198,7 +2522,7 @@ void tst_QQuickTableView::checkRebuildViewportOnly()
// Set reuse items to false, just to make it easier to
// check the number of items created during a rebuild.
tableView->setReuseItems(false);
- const int itemCountBeforeRebuild = tableViewPrivate->loadedItems.count();
+ const int itemCountBeforeRebuild = tableViewPrivate->loadedItems.size();
// Since all cells have the same size, we expect that we end up creating
// the same amount of items that were already showing before, even after
@@ -2353,18 +2677,94 @@ void tst_QQuickTableView::hideRowsAndColumns()
WAIT_UNTIL_POLISHED;
- const int expectedRowCount = modelSize - rowsToHideList.count();
- const int expectedColumnCount = modelSize - columnsToHideList.count();
+ const int expectedRowCount = modelSize - rowsToHideList.size();
+ const int expectedColumnCount = modelSize - columnsToHideList.size();
QCOMPARE(tableViewPrivate->loadedRows.count(), expectedRowCount);
QCOMPARE(tableViewPrivate->loadedColumns.count(), expectedColumnCount);
- for (const int row : tableViewPrivate->loadedRows.keys())
+ for (const int row : tableViewPrivate->loadedRows)
QVERIFY(!rowsToHideList.contains(row));
- for (const int column : tableViewPrivate->loadedColumns.keys())
+ for (const int column : tableViewPrivate->loadedColumns)
QVERIFY(!columnsToHideList.contains(column));
}
+void tst_QQuickTableView::hideAndShowFirstColumn()
+{
+ // Check that if we hide the first column, it will move
+ // the second column to the origin of the viewport. Then check
+ // that if we show the first column again, it will reappear at
+ // the origin of the viewport, and as such, pushing the second
+ // column to the right of it.
+ LOAD_TABLEVIEW("hiderowsandcolumns.qml");
+
+ const int modelSize = 5;
+ auto model = TestModelAsVariant(modelSize, modelSize);
+ tableView->setModel(model);
+
+ // Start by making the first column hidden
+ const auto columnsToHideList = QList<int>() << 0;
+ view->rootObject()->setProperty("columnsToHide", QVariant::fromValue(columnsToHideList));
+
+ WAIT_UNTIL_POLISHED;
+
+ const int expectedColumnCount = modelSize - columnsToHideList.size();
+ QCOMPARE(tableViewPrivate->loadedColumns.count(), expectedColumnCount);
+ QCOMPARE(tableViewPrivate->leftColumn(), 1);
+ QCOMPARE(tableView->contentX(), 0);
+ QCOMPARE(tableViewPrivate->loadedTableOuterRect.x(), 0);
+
+ // Make the first column in the model visible again
+ const auto emptyList = QList<int>();
+ view->rootObject()->setProperty("columnsToHide", QVariant::fromValue(emptyList));
+ tableView->forceLayout();
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewPrivate->loadedColumns.count(), modelSize);
+ QCOMPARE(tableViewPrivate->leftColumn(), 0);
+ QCOMPARE(tableView->contentX(), 0);
+ QCOMPARE(tableViewPrivate->loadedTableOuterRect.x(), 0);
+}
+
+void tst_QQuickTableView::hideAndShowFirstRow()
+{
+ // Check that if we hide the first row, it will move
+ // the second row to the origin of the viewport. Then check
+ // that if we show the first row again, it will reappear at
+ // the origin of the viewport, and as such, pushing the second
+ // row below it.
+ LOAD_TABLEVIEW("hiderowsandcolumns.qml");
+
+ const int modelSize = 5;
+ auto model = TestModelAsVariant(modelSize, modelSize);
+ tableView->setModel(model);
+
+ // Start by making the first row hidden
+ const auto rowsToHideList = QList<int>() << 0;
+ view->rootObject()->setProperty("rowsToHide", QVariant::fromValue(rowsToHideList));
+
+ WAIT_UNTIL_POLISHED;
+
+ const int expectedRowsCount = modelSize - rowsToHideList.size();
+ QCOMPARE(tableViewPrivate->loadedRows.count(), expectedRowsCount);
+ QCOMPARE(tableViewPrivate->topRow(), 1);
+ QCOMPARE(tableView->contentY(), 0);
+ QCOMPARE(tableViewPrivate->loadedTableOuterRect.y(), 0);
+
+ // Make the first row in the model visible again
+ const auto emptyList = QList<int>();
+ view->rootObject()->setProperty("rowsToHide", QVariant::fromValue(emptyList));
+ tableView->forceLayout();
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewPrivate->loadedRows.count(), modelSize);
+ QCOMPARE(tableViewPrivate->topRow(), 0);
+ QCOMPARE(tableView->contentY(), 0);
+ QCOMPARE(tableViewPrivate->loadedTableOuterRect.y(), 0);
+}
+
void tst_QQuickTableView::checkThatRevisionedPropertiesCannotBeUsedInOldImports()
{
// Check that if you use a QQmlAdaptorModel together with a Repeater, the
@@ -2379,9 +2779,21 @@ void tst_QQuickTableView::checkThatRevisionedPropertiesCannotBeUsedInOldImports(
void tst_QQuickTableView::checkSyncView_rootView_data()
{
QTest::addColumn<qreal>("flickToPos");
+ QTest::addColumn<qreal>("rowSpacing");
+ QTest::addColumn<qreal>("columnSpacing");
+ QTest::addColumn<qreal>("leftMargin");
+ QTest::addColumn<qreal>("rightMargin");
+ QTest::addColumn<qreal>("topMargin");
+ QTest::addColumn<qreal>("bottomMargin");
- QTest::newRow("pos:110") << 110.;
- QTest::newRow("pos:2010") << 2010.;
+ QTest::newRow("pos:110") << 110. << 0. << 0. << 0. << 0. << 0. << 0.;
+ QTest::newRow("pos:2010") << 2010. << 0. << 0. << 0. << 0. << 0. << 0.;
+
+ QTest::newRow("pos:110, spacing") << 110. << 10. << 20. << 0. << 0. << 0. << 0.;
+ QTest::newRow("pos:2010, spacing") << 2010. << 10. << 20. << 0. << 0. << 0. << 0.;
+
+ QTest::newRow("pos:110, margins") << 110. << 0. << 0. << 10. << 10. << 20. << 20.;
+ QTest::newRow("pos:2010, margins") << 2010. << 0. << 0. << 10. << 10. << 20. << 20.;
}
void tst_QQuickTableView::checkSyncView_rootView()
@@ -2390,6 +2802,13 @@ void tst_QQuickTableView::checkSyncView_rootView()
// no other view as syncView), all the other tableviews will sync
// their content view position according to their syncDirection flag.
QFETCH(qreal, flickToPos);
+ QFETCH(qreal, rowSpacing);
+ QFETCH(qreal, columnSpacing);
+ QFETCH(qreal, leftMargin);
+ QFETCH(qreal, rightMargin);
+ QFETCH(qreal, topMargin);
+ QFETCH(qreal, bottomMargin);
+
LOAD_TABLEVIEW("syncviewsimple.qml");
GET_QML_TABLEVIEW(tableViewH);
GET_QML_TABLEVIEW(tableViewV);
@@ -2402,18 +2821,32 @@ void tst_QQuickTableView::checkSyncView_rootView()
for (auto view : views)
view->setModel(model);
+ tableView->setRowSpacing(rowSpacing);
+ tableView->setColumnSpacing(columnSpacing);
+ tableView->setLeftMargin(leftMargin);
+ tableView->setRightMargin(rightMargin);
+ tableView->setTopMargin(topMargin);
+ tableView->setBottomMargin(bottomMargin);
tableView->setContentX(flickToPos);
tableView->setContentY(flickToPos);
WAIT_UNTIL_POLISHED;
- // Check that geometry properties are mirrored
+ // Check that geometry properties are mirrored accoring to sync direction
QCOMPARE(tableViewH->columnSpacing(), tableView->columnSpacing());
QCOMPARE(tableViewH->rowSpacing(), 0);
QCOMPARE(tableViewH->contentWidth(), tableView->contentWidth());
+ QCOMPARE(tableViewH->leftMargin(), tableView->leftMargin());
+ QCOMPARE(tableViewH->rightMargin(), tableView->rightMargin());
+ QCOMPARE(tableViewH->topMargin(), 0);
+ QCOMPARE(tableViewH->bottomMargin(), 0);
QCOMPARE(tableViewV->columnSpacing(), 0);
QCOMPARE(tableViewV->rowSpacing(), tableView->rowSpacing());
QCOMPARE(tableViewV->contentHeight(), tableView->contentHeight());
+ QCOMPARE(tableViewV->topMargin(), tableView->topMargin());
+ QCOMPARE(tableViewV->bottomMargin(), tableView->bottomMargin());
+ QCOMPARE(tableViewV->leftMargin(), 0);
+ QCOMPARE(tableViewV->rightMargin(), 0);
// Check that viewport is in sync after the flick
QCOMPARE(tableView->contentX(), flickToPos);
@@ -2444,6 +2877,18 @@ void tst_QQuickTableView::checkSyncView_rootView()
QCOMPARE(tableViewVPrivate->loadedTableOuterRect.left(), 0);
QCOMPARE(tableViewHVPrivate->loadedTableOuterRect, tableViewPrivate->loadedTableOuterRect);
+
+ // Check that the column widths are in sync
+ for (int column = tableView->leftColumn(); column < tableView->rightColumn(); ++column) {
+ QCOMPARE(tableViewH->columnWidth(column), tableView->columnWidth(column));
+ QCOMPARE(tableViewHV->columnWidth(column), tableView->columnWidth(column));
+ }
+
+ // Check that the row heights are in sync
+ for (int row = tableView->topRow(); row < tableView->bottomRow(); ++row) {
+ QCOMPARE(tableViewV->rowHeight(row), tableView->rowHeight(row));
+ QCOMPARE(tableViewHV->rowHeight(row), tableView->rowHeight(row));
+ }
}
void tst_QQuickTableView::checkSyncView_childViews_data()
@@ -2549,6 +2994,18 @@ void tst_QQuickTableView::checkSyncView_childViews()
QCOMPARE(tableViewHVPrivate->bottomRow(), tableViewPrivate->bottomRow());
QCOMPARE(tableViewHVPrivate->loadedTableOuterRect, tableViewPrivate->loadedTableOuterRect);
}
+
+ // Check that the column widths are in sync
+ for (int column = tableView->leftColumn(); column < tableView->rightColumn(); ++column) {
+ QCOMPARE(tableViewH->columnWidth(column), tableView->columnWidth(column));
+ QCOMPARE(tableViewHV->columnWidth(column), tableView->columnWidth(column));
+ }
+
+ // Check that the row heights are in sync
+ for (int row = tableView->topRow(); row < tableView->bottomRow(); ++row) {
+ QCOMPARE(tableViewV->rowHeight(row), tableView->rowHeight(row));
+ QCOMPARE(tableViewHV->rowHeight(row), tableView->rowHeight(row));
+ }
}
void tst_QQuickTableView::checkSyncView_differentSizedModels()
@@ -2614,6 +3071,61 @@ void tst_QQuickTableView::checkSyncView_differentSizedModels()
QVERIFY(tableViewHVPrivate->loadedColumns.isEmpty());
}
+void tst_QQuickTableView::checkSyncView_differentGeometry()
+{
+ // Check that you can have two tables in a syncView relation, where
+ // the sync "child" is larger than the sync view. This means that the
+ // child will display more rows and columns than the parent.
+ // In that case, the sync view will anyway need to load the same rows
+ // and columns as the child, otherwise the column and row sizes
+ // cannot be determined for the child.
+ LOAD_TABLEVIEW("syncviewsimple.qml");
+ GET_QML_TABLEVIEW(tableViewH);
+ GET_QML_TABLEVIEW(tableViewV);
+ GET_QML_TABLEVIEW(tableViewHV);
+
+ tableView->setWidth(40);
+ tableView->setHeight(40);
+
+ auto tableViewModel = TestModelAsVariant(100, 100);
+
+ tableView->setModel(tableViewModel);
+ tableViewH->setModel(tableViewModel);
+ tableViewV->setModel(tableViewModel);
+ tableViewHV->setModel(tableViewModel);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that the column widths are in sync
+ for (int column = tableViewH->leftColumn(); column < tableViewH->rightColumn(); ++column) {
+ QCOMPARE(tableViewH->columnWidth(column), tableView->columnWidth(column));
+ QCOMPARE(tableViewHV->columnWidth(column), tableView->columnWidth(column));
+ }
+
+ // Check that the row heights are in sync
+ for (int row = tableViewV->topRow(); row < tableViewV->bottomRow(); ++row) {
+ QCOMPARE(tableViewV->rowHeight(row), tableView->rowHeight(row));
+ QCOMPARE(tableViewHV->rowHeight(row), tableView->rowHeight(row));
+ }
+
+ // Flick a bit, and do the same test again
+ tableView->setContentX(200);
+ tableView->setContentY(200);
+ WAIT_UNTIL_POLISHED;
+
+ // Check that the column widths are in sync
+ for (int column = tableViewH->leftColumn(); column < tableViewH->rightColumn(); ++column) {
+ QCOMPARE(tableViewH->columnWidth(column), tableView->columnWidth(column));
+ QCOMPARE(tableViewHV->columnWidth(column), tableView->columnWidth(column));
+ }
+
+ // Check that the row heights are in sync
+ for (int row = tableViewV->topRow(); row < tableViewV->bottomRow(); ++row) {
+ QCOMPARE(tableViewV->rowHeight(row), tableView->rowHeight(row));
+ QCOMPARE(tableViewHV->rowHeight(row), tableView->rowHeight(row));
+ }
+}
+
void tst_QQuickTableView::checkSyncView_connect_late_data()
{
QTest::addColumn<qreal>("flickToPos");
@@ -2781,6 +3293,57 @@ void tst_QQuickTableView::checkSyncView_emptyModel()
QCOMPARE(tableViewVPrivate->loadedTableOuterRect.left(), 0);
}
+void tst_QQuickTableView::checkSyncView_unloadHeader()
+{
+ // Check that we don't get a crash in TableView if one
+ // of the sync children is suddenly deleted (from e.g a Loader).
+ LOAD_TABLEVIEW("unloadheader.qml");
+
+ const auto loader = view->rootObject()->property("loader").value<QQuickLoader *>();
+ QVERIFY(loader);
+ QVERIFY(loader->item());
+ loader->setActive(false);
+ QVERIFY(!loader->item());
+ gc(*qmlEngine(tableView));
+ tableView->forceLayout();
+}
+
+void tst_QQuickTableView::checkSyncView_topLeftChanged()
+{
+ LOAD_TABLEVIEW("syncviewsimple.qml");
+ GET_QML_TABLEVIEW(tableViewH);
+ GET_QML_TABLEVIEW(tableViewV);
+ GET_QML_TABLEVIEW(tableViewHV);
+ QQuickTableView *views[] = {tableViewH, tableViewV, tableViewHV};
+
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+
+ for (auto view : views)
+ view->setModel(model);
+
+ tableView->setColumnWidthProvider(QJSValue());
+ tableView->setRowHeightProvider(QJSValue());
+ view->rootObject()->setProperty("delegateWidth", 300);
+ view->rootObject()->setProperty("delegateHeight", 300);
+ tableView->forceLayout();
+
+ tableViewHV->setContentX(350);
+ tableViewHV->setContentY(350);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableViewH->leftColumn(), tableView->leftColumn());
+ QCOMPARE(tableViewV->topRow(), tableView->topRow());
+
+ view->rootObject()->setProperty("delegateWidth", 50);
+ view->rootObject()->setProperty("delegateHeight", 50);
+ tableView->forceLayout();
+
+ QCOMPARE(tableViewH->leftColumn(), tableView->leftColumn());
+ QCOMPARE(tableViewV->topRow(), tableView->topRow());
+}
+
void tst_QQuickTableView::checkThatFetchMoreIsCalledWhenScrolledToTheEndOfTable()
{
LOAD_TABLEVIEW("plaintableview.qml");
@@ -2871,9 +3434,10 @@ void tst_QQuickTableView::replaceModel()
void tst_QQuickTableView::cellAtPos_data()
{
QTest::addColumn<QPointF>("contentStartPos");
- QTest::addColumn<QPointF>("position");
+ QTest::addColumn<QPointF>("localPos");
QTest::addColumn<bool>("includeSpacing");
QTest::addColumn<QPoint>("expectedCell");
+ QTest::addColumn<QSizeF>("margins");
const int spacing = 10;
const QPointF cellSize(100, 50);
@@ -2886,109 +3450,109 @@ void tst_QQuickTableView::cellAtPos_data()
return QPointF(x, y);
};
- QTest::newRow("1") << QPointF(0, 0) << cellStart(0, 0) << false << QPoint(0, 0);
- QTest::newRow("2") << QPointF(0, 0) << cellStart(1, 0) << false << QPoint(1, 0);
- QTest::newRow("3") << QPointF(0, 0) << cellStart(0, 1) << false << QPoint(0, 1);
- QTest::newRow("4") << QPointF(0, 0) << cellStart(1, 1) << false << QPoint(1, 1);
-
- QTest::newRow("5") << QPointF(0, 0) << cellStart(1, 1) - quadSpace << false << QPoint(-1, -1);
- QTest::newRow("6") << QPointF(0, 0) << cellStart(0, 0) + cellSize + quadSpace << false << QPoint(-1, -1);
- QTest::newRow("7") << QPointF(0, 0) << cellStart(0, 1) + cellSize + quadSpace << false << QPoint(-1, -1);
-
- QTest::newRow("8") << QPointF(0, 0) << cellStart(1, 1) - quadSpace << true << QPoint(1, 1);
- QTest::newRow("9") << QPointF(0, 0) << cellStart(0, 0) + cellSize + quadSpace << true << QPoint(0, 0);
- QTest::newRow("10") << QPointF(0, 0) << cellStart(0, 1) + cellSize + quadSpace << true << QPoint(0, 1);
-
- QTest::newRow("11") << cellStart(50, 50) << cellStart(0, 0) << false << QPoint(50, 50);
- QTest::newRow("12") << cellStart(50, 50) << cellStart(4, 4) << false << QPoint(54, 54);
- QTest::newRow("13") << cellStart(50, 50) << cellStart(4, 4) - quadSpace << false << QPoint(-1, -1);
- QTest::newRow("14") << cellStart(50, 50) << cellStart(4, 4) + cellSize + quadSpace << false << QPoint(-1, -1);
- QTest::newRow("15") << cellStart(50, 50) << cellStart(4, 4) - quadSpace << true << QPoint(54, 54);
- QTest::newRow("16") << cellStart(50, 50) << cellStart(4, 4) + cellSize + quadSpace << true << QPoint(54, 54);
-
- QTest::newRow("17") << cellStart(50, 50) + halfCell << cellStart(0, 0) << false << QPoint(50, 50);
- QTest::newRow("18") << cellStart(50, 50) + halfCell << cellStart(1, 1) << false << QPoint(51, 51);
- QTest::newRow("19") << cellStart(50, 50) + halfCell << cellStart(4, 4) << false << QPoint(54, 54);
+ QTest::newRow("1") << QPointF(0, 0) << cellStart(0, 0) << false << QPoint(0, 0) << QSizeF(0, 0);
+ QTest::newRow("2") << QPointF(0, 0) << cellStart(1, 0) << false << QPoint(1, 0) << QSizeF(0, 0);
+ QTest::newRow("3") << QPointF(0, 0) << cellStart(0, 1) << false << QPoint(0, 1) << QSizeF(0, 0);
+ QTest::newRow("4") << QPointF(0, 0) << cellStart(1, 1) << false << QPoint(1, 1) << QSizeF(0, 0);
+
+ QTest::newRow("5") << QPointF(0, 0) << cellStart(1, 1) - quadSpace << false << QPoint(-1, -1) << QSizeF(0, 0);
+ QTest::newRow("6") << QPointF(0, 0) << cellStart(0, 0) + cellSize + quadSpace << false << QPoint(-1, -1) << QSizeF(0, 0);
+ QTest::newRow("7") << QPointF(0, 0) << cellStart(0, 1) + cellSize + quadSpace << false << QPoint(-1, -1) << QSizeF(0, 0);
+
+ QTest::newRow("8") << QPointF(0, 0) << cellStart(1, 1) - quadSpace << true << QPoint(1, 1) << QSizeF(0, 0);
+ QTest::newRow("9") << QPointF(0, 0) << cellStart(0, 0) + cellSize + quadSpace << true << QPoint(0, 0) << QSizeF(0, 0);
+ QTest::newRow("10") << QPointF(0, 0) << cellStart(0, 1) + cellSize + quadSpace << true << QPoint(0, 1) << QSizeF(0, 0);
+
+ QTest::newRow("11") << cellStart(50, 50) << cellStart(50, 50) << false << QPoint(50, 50) << QSizeF(0, 0);
+ QTest::newRow("12") << cellStart(50, 50) << cellStart(54, 54) << false << QPoint(54, 54) << QSizeF(0, 0);
+ QTest::newRow("13") << cellStart(50, 50) << cellStart(54, 54) - quadSpace << false << QPoint(-1, -1) << QSizeF(0, 0);
+ QTest::newRow("14") << cellStart(50, 50) << cellStart(54, 54) + cellSize + quadSpace << false << QPoint(-1, -1) << QSizeF(0, 0);
+ QTest::newRow("15") << cellStart(50, 50) << cellStart(54, 54) - quadSpace << true << QPoint(54, 54) << QSizeF(0, 0);
+ QTest::newRow("16") << cellStart(50, 50) << cellStart(54, 54) + cellSize + quadSpace << true << QPoint(54, 54) << QSizeF(0, 0);
+
+ QTest::newRow("17") << cellStart(50, 50) + halfCell << cellStart(50, 50) << false << QPoint(50, 50) << QSizeF(0, 0);
+ QTest::newRow("18") << cellStart(50, 50) + halfCell << cellStart(51, 51) << false << QPoint(51, 51) << QSizeF(0, 0);
+ QTest::newRow("19") << cellStart(50, 50) + halfCell << cellStart(54, 54) << false << QPoint(54, 54) << QSizeF(0, 0);
+
+ QTest::newRow("20") << QPointF(0, 0) << cellStart(0, 0) << false << QPoint(0, 0) << QSizeF(150, 150);
+ QTest::newRow("20") << QPointF(0, 0) << cellStart(5, 5) << false << QPoint(5, 5) << QSizeF(150, 150);
+
+ QTest::newRow("20") << QPointF(-150, -150) << cellStart(0, 0) << false << QPoint(0, 0) << QSizeF(150, 150);
+ QTest::newRow("21") << QPointF(-150, -150) << cellStart(4, 0) + halfCell << false << QPoint(4, 0) << QSizeF(150, 150);
+ QTest::newRow("22") << QPointF(-150, -150) << cellStart(0, 4) + halfCell << false << QPoint(0, 4) << QSizeF(150, 150);
+ QTest::newRow("23") << QPointF(-150, -150) << cellStart(4, 4) + halfCell << false << QPoint(4, 4) << QSizeF(150, 150);
}
void tst_QQuickTableView::cellAtPos()
{
QFETCH(QPointF, contentStartPos);
- QFETCH(QPointF, position);
+ QFETCH(QPointF, localPos);
QFETCH(bool, includeSpacing);
QFETCH(QPoint, expectedCell);
+ QFETCH(QSizeF, margins);
LOAD_TABLEVIEW("plaintableview.qml");
auto model = TestModelAsVariant(100, 100);
tableView->setModel(model);
tableView->setRowSpacing(10);
tableView->setColumnSpacing(10);
+ tableView->setLeftMargin(margins.width());
+ tableView->setLeftMargin(margins.height());
+ tableView->setTopMargin(margins.height());
tableView->setContentX(contentStartPos.x());
tableView->setContentY(contentStartPos.y());
WAIT_UNTIL_POLISHED;
- QPoint cell = tableView->cellAtPos(position, includeSpacing);
+ QPoint cell = tableView->cellAtPosition(localPos, includeSpacing);
QCOMPARE(cell, expectedCell);
}
void tst_QQuickTableView::positionViewAtRow_data()
{
QTest::addColumn<int>("row");
- QTest::addColumn<Qt::AlignmentFlag>("alignment");
+ QTest::addColumn<QQuickTableView::PositionModeFlag>("alignment");
QTest::addColumn<qreal>("offset");
+ QTest::addColumn<QRectF>("subRect");
QTest::addColumn<qreal>("contentYStartPos");
- QTest::newRow("AlignTop 0") << 0 << Qt::AlignTop << 0. << 0.;
- QTest::newRow("AlignTop 1") << 1 << Qt::AlignTop << 0. << 0.;
- QTest::newRow("AlignTop 1") << 1 << Qt::AlignTop << 0. << 50.;
- QTest::newRow("AlignTop 50") << 50 << Qt::AlignTop << 0. << -1.;
- QTest::newRow("AlignTop 0") << 0 << Qt::AlignTop << 0. << -1.;
- QTest::newRow("AlignTop 99") << 99 << Qt::AlignTop << 0. << -1.;
-
- QTest::newRow("AlignTop 0") << 0 << Qt::AlignTop << -10. << 0.;
- QTest::newRow("AlignTop 1") << 1 << Qt::AlignTop << -10. << 0.;
- QTest::newRow("AlignTop 1") << 1 << Qt::AlignTop << -10. << 50.;
- QTest::newRow("AlignTop 50") << 50 << Qt::AlignTop << -10. << -1.;
- QTest::newRow("AlignTop 0") << 0 << Qt::AlignTop << -10. << -1.;
- QTest::newRow("AlignTop 99") << 99 << Qt::AlignTop << -10. << -1.;
-
- QTest::newRow("AlignBottom 0") << 0 << Qt::AlignBottom << 0. << 0.;
- QTest::newRow("AlignBottom 1") << 1 << Qt::AlignBottom << 0. << 0.;
- QTest::newRow("AlignBottom 1") << 1 << Qt::AlignBottom << 0. << 50.;
- QTest::newRow("AlignBottom 50") << 50 << Qt::AlignBottom << 0. << -1.;
- QTest::newRow("AlignBottom 0") << 0 << Qt::AlignBottom << 0. << -1.;
- QTest::newRow("AlignBottom 99") << 99 << Qt::AlignBottom << 0. << -1.;
-
- QTest::newRow("AlignBottom 0") << 0 << Qt::AlignBottom << 10. << 0.;
- QTest::newRow("AlignBottom 1") << 1 << Qt::AlignBottom << 10. << 0.;
- QTest::newRow("AlignBottom 1") << 1 << Qt::AlignBottom << 10. << 50.;
- QTest::newRow("AlignBottom 50") << 50 << Qt::AlignBottom << 10. << -1.;
- QTest::newRow("AlignBottom 0") << 0 << Qt::AlignBottom << 10. << -1.;
- QTest::newRow("AlignBottom 99") << 99 << Qt::AlignBottom << 10. << -1.;
-
- QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << 0. << 0.;
- QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << 0. << 0.;
- QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << 0. << 50.;
- QTest::newRow("AlignCenter 50") << 50 << Qt::AlignCenter << 0. << -1.;
- QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << 0. << -1.;
- QTest::newRow("AlignCenter 99") << 99 << Qt::AlignCenter << 0. << -1.;
-
- QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << -10. << 0.;
- QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << -10. << 0.;
- QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << -10. << 50.;
- QTest::newRow("AlignCenter 50") << 50 << Qt::AlignCenter << -10. << -1.;
- QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << -10. << -1.;
- QTest::newRow("AlignCenter 99") << 99 << Qt::AlignCenter << -10. << -1.;
+ QRectF subRects[] = { QRectF(), QRectF(11, 12, 13, 14) };
+
+ for (auto subRect : subRects) {
+ QTest::newRow("AlignTop 0") << 0 << QQuickTableView::AlignTop << 0. << subRect << 0.;
+ QTest::newRow("AlignTop 1") << 1 << QQuickTableView::AlignTop << 0. << subRect << 0.;
+ QTest::newRow("AlignTop 1") << 1 << QQuickTableView::AlignTop << 0. << subRect << 50.;
+ QTest::newRow("AlignTop 50") << 50 << QQuickTableView::AlignTop << 0. << subRect << -1.;
+ QTest::newRow("AlignTop 0") << 0 << QQuickTableView::AlignTop << 0. << subRect << -1.;
+ QTest::newRow("AlignTop 1") << 1 << QQuickTableView::AlignTop << -10. << subRect << 0.;
+ QTest::newRow("AlignTop 1") << 1 << QQuickTableView::AlignTop << -10. << subRect << 50.;
+ QTest::newRow("AlignTop 50") << 50 << QQuickTableView::AlignTop << -10. << subRect << -1.;
+
+ QTest::newRow("AlignBottom 50") << 50 << QQuickTableView::AlignBottom << 0. << subRect << -1.;
+ QTest::newRow("AlignBottom 98") << 98 << QQuickTableView::AlignBottom << 0. << subRect << -1.;
+ QTest::newRow("AlignBottom 99") << 99 << QQuickTableView::AlignBottom << 0. << subRect << -1.;
+ QTest::newRow("AlignBottom 50") << 40 << QQuickTableView::AlignBottom << 10. << subRect << -1.;
+ QTest::newRow("AlignBottom 40") << 50 << QQuickTableView::AlignBottom << -10. << subRect << -1.;
+ QTest::newRow("AlignBottom 98") << 98 << QQuickTableView::AlignBottom << 10. << subRect << -1.;
+ QTest::newRow("AlignBottom 99") << 99 << QQuickTableView::AlignBottom << -10. << subRect << -1.;
+
+ QTest::newRow("AlignCenter 40") << 40 << QQuickTableView::AlignCenter << 0. << subRect << -1.;
+ QTest::newRow("AlignCenter 50") << 50 << QQuickTableView::AlignCenter << 0. << subRect << -1.;
+ QTest::newRow("AlignCenter 40") << 40 << QQuickTableView::AlignCenter << 10. << subRect << -1.;
+ QTest::newRow("AlignCenter 50") << 50 << QQuickTableView::AlignCenter << -10. << subRect << -1.;
+ }
}
void tst_QQuickTableView::positionViewAtRow()
{
// Check that positionViewAtRow actually flicks the view
- // to the right position so that the row becomes visible
+ // to the right position so that the row becomes visible.
+ // For this test, we only check cells that can be placed exactly
+ // according to the given alignment.
QFETCH(int, row);
- QFETCH(Qt::AlignmentFlag, alignment);
+ QFETCH(QQuickTableView::PositionModeFlag, alignment);
QFETCH(qreal, offset);
+ QFETCH(QRectF, subRect);
QFETCH(qreal, contentYStartPos);
LOAD_TABLEVIEW("plaintableview.qml");
@@ -2999,24 +3563,26 @@ void tst_QQuickTableView::positionViewAtRow()
WAIT_UNTIL_POLISHED;
- tableView->positionViewAtRow(row, alignment, offset);
+ tableView->positionViewAtRow(row, alignment, offset, subRect);
- WAIT_UNTIL_POLISHED;
+ if (!tableView->isRowLoaded(row))
+ WAIT_UNTIL_POLISHED;
const QPoint cell(0, row);
const int modelIndex = tableViewPrivate->modelIndexAtCell(cell);
QVERIFY(tableViewPrivate->loadedItems.contains(modelIndex));
- const auto geometry = tableViewPrivate->loadedTableItem(cell)->geometry();
+ const QRectF cellRect = tableViewPrivate->loadedTableItem(cell)->geometry();
+ const QRectF alignmentRect = subRect.isValid() ? subRect.translated(cellRect.topLeft()) : cellRect;
switch (alignment) {
- case Qt::AlignTop:
- QCOMPARE(geometry.y(), tableView->contentY() - offset);
+ case QQuickTableView::AlignTop:
+ QCOMPARE(alignmentRect.y(), tableView->contentY() - offset);
break;
- case Qt::AlignBottom:
- QCOMPARE(geometry.bottom(), tableView->contentY() + tableView->height() - offset);
+ case QQuickTableView::AlignBottom:
+ QCOMPARE(alignmentRect.bottom(), tableView->contentY() + tableView->height() - offset);
break;
- case Qt::AlignCenter:
- QCOMPARE(geometry.y(), tableView->contentY() + (tableView->height() / 2) - (geometry.height() / 2) - offset);
+ case QQuickTableView::AlignCenter:
+ QCOMPARE(alignmentRect.y(), tableView->contentY() + (tableView->height() / 2) - (alignmentRect.height() / 2) - offset);
break;
default:
Q_UNREACHABLE();
@@ -3026,60 +3592,45 @@ void tst_QQuickTableView::positionViewAtRow()
void tst_QQuickTableView::positionViewAtColumn_data()
{
QTest::addColumn<int>("column");
- QTest::addColumn<Qt::AlignmentFlag>("alignment");
+ QTest::addColumn<QQuickTableView::PositionModeFlag>("alignment");
QTest::addColumn<qreal>("offset");
+ QTest::addColumn<QRectF>("subRect");
QTest::addColumn<qreal>("contentXStartPos");
- QTest::newRow("AlignLeft 0") << 0 << Qt::AlignLeft << 0. << 0.;
- QTest::newRow("AlignLeft 1") << 1 << Qt::AlignLeft << 0. << 0.;
- QTest::newRow("AlignLeft 1") << 1 << Qt::AlignLeft << 0. << 50.;
- QTest::newRow("AlignLeft 50") << 50 << Qt::AlignLeft << 0. << -1.;
- QTest::newRow("AlignLeft 0") << 0 << Qt::AlignLeft << 0. << -1.;
- QTest::newRow("AlignLeft 99") << 99 << Qt::AlignLeft << 0. << -1.;
-
- QTest::newRow("AlignLeft 0") << 0 << Qt::AlignLeft << -10. << 0.;
- QTest::newRow("AlignLeft 1") << 1 << Qt::AlignLeft << -10. << 0.;
- QTest::newRow("AlignLeft 1") << 1 << Qt::AlignLeft << -10. << 50.;
- QTest::newRow("AlignLeft 50") << 50 << Qt::AlignLeft << -10. << -1.;
- QTest::newRow("AlignLeft 0") << 0 << Qt::AlignLeft << -10. << -1.;
- QTest::newRow("AlignLeft 99") << 99 << Qt::AlignLeft << -10. << -1.;
-
- QTest::newRow("AlignRight 0") << 0 << Qt::AlignRight << 0. << 0.;
- QTest::newRow("AlignRight 1") << 1 << Qt::AlignRight << 0. << 0.;
- QTest::newRow("AlignRight 1") << 1 << Qt::AlignRight << 0. << 50.;
- QTest::newRow("AlignRight 50") << 50 << Qt::AlignRight << 0. << -1.;
- QTest::newRow("AlignRight 0") << 0 << Qt::AlignRight << 0. << -1.;
- QTest::newRow("AlignRight 99") << 99 << Qt::AlignRight << 0. << -1.;
-
- QTest::newRow("AlignRight 0") << 0 << Qt::AlignRight << 10. << 0.;
- QTest::newRow("AlignRight 1") << 1 << Qt::AlignRight << 10. << 0.;
- QTest::newRow("AlignRight 1") << 1 << Qt::AlignRight << 10. << 50.;
- QTest::newRow("AlignRight 50") << 50 << Qt::AlignRight << 10. << -1.;
- QTest::newRow("AlignRight 0") << 0 << Qt::AlignRight << 10. << -1.;
- QTest::newRow("AlignRight 99") << 99 << Qt::AlignRight << 10. << -1.;
-
- QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << 0. << 0.;
- QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << 0. << 0.;
- QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << 0. << 50.;
- QTest::newRow("AlignCenter 50") << 50 << Qt::AlignCenter << 0. << -1.;
- QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << 0. << -1.;
- QTest::newRow("AlignCenter 99") << 99 << Qt::AlignCenter << 0. << -1.;
-
- QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << -10. << 0.;
- QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << -10. << 0.;
- QTest::newRow("AlignCenter 1") << 1 << Qt::AlignCenter << -10. << 50.;
- QTest::newRow("AlignCenter 50") << 50 << Qt::AlignCenter << -10. << -1.;
- QTest::newRow("AlignCenter 0") << 0 << Qt::AlignCenter << -10. << -1.;
- QTest::newRow("AlignCenter 99") << 99 << Qt::AlignCenter << -10. << -1.;
+ QRectF subRects[] = { QRectF(), QRectF(11, 12, 13, 14) };
+
+ for (auto subRect : subRects) {
+ QTest::newRow("AlignLeft 0") << 0 << QQuickTableView::AlignLeft << 0. << subRect << 0.;
+ QTest::newRow("AlignLeft 1") << 1 << QQuickTableView::AlignLeft << 0. << subRect << 0.;
+ QTest::newRow("AlignLeft 1") << 1 << QQuickTableView::AlignLeft << 0. << subRect << 50.;
+ QTest::newRow("AlignLeft 50") << 50 << QQuickTableView::AlignLeft << 0. << subRect << -1.;
+ QTest::newRow("AlignLeft 0") << 0 << QQuickTableView::AlignLeft << 0. << subRect << -1.;
+ QTest::newRow("AlignLeft 1") << 1 << QQuickTableView::AlignLeft << -10. << subRect << 0.;
+ QTest::newRow("AlignLeft 1") << 1 << QQuickTableView::AlignLeft << -10. << subRect << 50.;
+ QTest::newRow("AlignLeft 50") << 50 << QQuickTableView::AlignLeft << -10. << subRect << -1.;
+
+ QTest::newRow("AlignRight 50") << 50 << QQuickTableView::AlignRight << 0. << subRect << -1.;
+ QTest::newRow("AlignRight 99") << 99 << QQuickTableView::AlignRight << 0. << subRect << -1.;
+ QTest::newRow("AlignRight 50") << 50 << QQuickTableView::AlignRight << 10. << subRect << -1.;
+ QTest::newRow("AlignRight 99") << 99 << QQuickTableView::AlignRight << -10. << subRect << -1.;
+
+ QTest::newRow("AlignCenter 40") << 50 << QQuickTableView::AlignCenter << 0. << subRect << -1.;
+ QTest::newRow("AlignCenter 50") << 50 << QQuickTableView::AlignCenter << 0. << subRect << -1.;
+ QTest::newRow("AlignCenter 40") << 50 << QQuickTableView::AlignCenter << 10. << subRect << -1.;
+ QTest::newRow("AlignCenter 50") << 50 << QQuickTableView::AlignCenter << -10. << subRect << -1.;
+ }
}
void tst_QQuickTableView::positionViewAtColumn()
{
// Check that positionViewAtColumn actually flicks the view
- // to the right position so that the row becomes visible
+ // to the right position so that the row becomes visible.
+ // For this test, we only check cells that can be placed exactly
+ // according to the given alignment.
QFETCH(int, column);
- QFETCH(Qt::AlignmentFlag, alignment);
+ QFETCH(QQuickTableView::PositionModeFlag, alignment);
QFETCH(qreal, offset);
+ QFETCH(QRectF, subRect);
QFETCH(qreal, contentXStartPos);
LOAD_TABLEVIEW("plaintableview.qml");
@@ -3090,30 +3641,607 @@ void tst_QQuickTableView::positionViewAtColumn()
WAIT_UNTIL_POLISHED;
- tableView->positionViewAtColumn(column, alignment, offset);
+ tableView->positionViewAtColumn(column, alignment, offset, subRect);
- WAIT_UNTIL_POLISHED;
+ if (!tableView->isColumnLoaded(column))
+ WAIT_UNTIL_POLISHED;
const QPoint cell(column, 0);
const int modelIndex = tableViewPrivate->modelIndexAtCell(cell);
QVERIFY(tableViewPrivate->loadedItems.contains(modelIndex));
- const auto geometry = tableViewPrivate->loadedTableItem(cell)->geometry();
+ const QRectF cellRect = tableViewPrivate->loadedTableItem(cell)->geometry();
+ const QRectF alignmentRect = subRect.isValid() ? subRect.translated(cellRect.topLeft()) : cellRect;
switch (alignment) {
- case Qt::AlignLeft:
- QCOMPARE(geometry.x(), tableView->contentX() - offset);
+ case QQuickTableView::AlignLeft:
+ QCOMPARE(alignmentRect.x(), tableView->contentX() - offset);
break;
- case Qt::AlignRight:
- QCOMPARE(geometry.right(), tableView->contentX() + tableView->width() - offset);
+ case QQuickTableView::AlignRight:
+ QCOMPARE(alignmentRect.right(), tableView->contentX() + tableView->width() - offset);
break;
- case Qt::AlignCenter:
- QCOMPARE(geometry.x(), tableView->contentX() + (tableView->width() / 2) - (geometry.width() / 2) - offset);
+ case QQuickTableView::AlignCenter:
+ QCOMPARE(alignmentRect.x(), tableView->contentX() + (tableView->width() / 2) - (alignmentRect.width() / 2) - offset);
break;
default:
Q_UNREACHABLE();
}
}
+void tst_QQuickTableView::positionViewAtRowClamped_data()
+{
+ QTest::addColumn<int>("row");
+ QTest::addColumn<QQuickTableView::PositionModeFlag>("alignment");
+ QTest::addColumn<qreal>("offset");
+ QTest::addColumn<QRectF>("subRect");
+ QTest::addColumn<qreal>("contentYStartPos");
+
+ QRectF subRects[] = { QRectF(), QRectF(1, 2, 3, 4) };
+
+ for (auto subRect : subRects) {
+ QTest::newRow("AlignTop 0") << 0 << QQuickTableView::AlignTop << -10. << subRect << 0.;
+ QTest::newRow("AlignTop 0") << 0 << QQuickTableView::AlignTop << -10. << subRect << -1.;
+ QTest::newRow("AlignTop 99") << 99 << QQuickTableView::AlignTop << 0. << subRect << -1.;
+ QTest::newRow("AlignTop 99") << 99 << QQuickTableView::AlignTop << -10. << subRect << -1.;
+
+ QTest::newRow("AlignBottom 0") << 0 << QQuickTableView::AlignBottom << 0. << subRect << 0.;
+ QTest::newRow("AlignBottom 1") << 1 << QQuickTableView::AlignBottom << 0. << subRect << 0.;
+ QTest::newRow("AlignBottom 1") << 1 << QQuickTableView::AlignBottom << 0. << subRect << 50.;
+ QTest::newRow("AlignBottom 0") << 0 << QQuickTableView::AlignBottom << 0. << subRect << -1.;
+
+ QTest::newRow("AlignBottom 0") << 0 << QQuickTableView::AlignBottom << 10. << subRect << 0.;
+ QTest::newRow("AlignBottom 1") << 1 << QQuickTableView::AlignBottom << 10. << subRect << 0.;
+ QTest::newRow("AlignBottom 1") << 1 << QQuickTableView::AlignBottom << 10. << subRect << 50.;
+ QTest::newRow("AlignBottom 0") << 0 << QQuickTableView::AlignBottom << 10. << subRect << -1.;
+ QTest::newRow("AlignBottom 99") << 99 << QQuickTableView::AlignBottom << 50. << subRect << -1.;
+
+ QTest::newRow("AlignCenter 0") << 0 << QQuickTableView::AlignCenter << 0. << subRect << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << QQuickTableView::AlignCenter << 0. << subRect << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << QQuickTableView::AlignCenter << 0. << subRect << 50.;
+ QTest::newRow("AlignCenter 0") << 0 << QQuickTableView::AlignCenter << 0. << subRect << -1.;
+ QTest::newRow("AlignCenter 99") << 99 << QQuickTableView::AlignCenter << 0. << subRect << -1.;
+
+ QTest::newRow("AlignCenter 0") << 0 << QQuickTableView::AlignCenter << -10. << subRect << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << QQuickTableView::AlignCenter << -10. << subRect << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << QQuickTableView::AlignCenter << -10. << subRect << 50.;
+ QTest::newRow("AlignCenter 0") << 0 << QQuickTableView::AlignCenter << -10. << subRect << -1.;
+ QTest::newRow("AlignCenter 99") << 99 << QQuickTableView::AlignCenter << -10. << subRect << -1.;
+ }
+}
+
+void tst_QQuickTableView::positionViewAtRowClamped()
+{
+ // Check that positionViewAtRow actually flicks the table to the
+ // right position so that the row becomes visible. For this test, we
+ // only test cells that cannot be placed exactly at the given alignment,
+ // because it would cause the table to overshoot. Instead the
+ // table should be flicked to the edge of the viewport, close to the
+ // requested alignment.
+ QFETCH(int, row);
+ QFETCH(QQuickTableView::PositionModeFlag, alignment);
+ QFETCH(qreal, offset);
+ QFETCH(QRectF, subRect);
+ QFETCH(qreal, contentYStartPos);
+
+ LOAD_TABLEVIEW("plaintableview.qml");
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+ if (contentYStartPos >= 0)
+ tableView->setContentY(contentYStartPos);
+
+ if (!tableView->isRowLoaded(row))
+ WAIT_UNTIL_POLISHED;
+
+ tableView->positionViewAtRow(row, alignment, offset, subRect);
+
+ if (!tableView->isRowLoaded(row))
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->contentY(), row < 50 ? 0 : tableView->contentHeight() - tableView->height());
+}
+
+void tst_QQuickTableView::positionViewAtColumnClamped_data()
+{
+ QTest::addColumn<int>("column");
+ QTest::addColumn<QQuickTableView::PositionModeFlag>("alignment");
+ QTest::addColumn<qreal>("offset");
+ QTest::addColumn<QRectF>("subRect");
+ QTest::addColumn<qreal>("contentXStartPos");
+
+ QRectF subRects[] = { QRectF(), QRectF(1, 2, 3, 4) };
+
+ for (auto subRect : subRects) {
+ QTest::newRow("AlignLeft 0") << 0 << QQuickTableView::AlignLeft << -10. << subRect << 0.;
+ QTest::newRow("AlignLeft 0") << 0 << QQuickTableView::AlignLeft << -10. << subRect << -1.;
+ QTest::newRow("AlignLeft 99") << 99 << QQuickTableView::AlignLeft << 0. << subRect << -1.;
+ QTest::newRow("AlignLeft 99") << 99 << QQuickTableView::AlignLeft << -10. << subRect << -1.;
+
+ QTest::newRow("AlignRight 0") << 0 << QQuickTableView::AlignRight << 0. << subRect << 0.;
+ QTest::newRow("AlignRight 1") << 1 << QQuickTableView::AlignRight << 0. << subRect << 0.;
+ QTest::newRow("AlignRight 1") << 1 << QQuickTableView::AlignRight << 0. << subRect << 50.;
+ QTest::newRow("AlignRight 0") << 0 << QQuickTableView::AlignRight << 0. << subRect << -1.;
+
+ QTest::newRow("AlignRight 0") << 0 << QQuickTableView::AlignRight << 10. << subRect << 0.;
+ QTest::newRow("AlignRight 1") << 1 << QQuickTableView::AlignRight << 10. << subRect << 0.;
+ QTest::newRow("AlignRight 1") << 1 << QQuickTableView::AlignRight << 10. << subRect << 50.;
+ QTest::newRow("AlignRight 0") << 0 << QQuickTableView::AlignRight << 10. << subRect << -1.;
+ QTest::newRow("AlignRight 99") << 99 << QQuickTableView::AlignRight << 100. << subRect << -1.;
+
+ QTest::newRow("AlignCenter 0") << 0 << QQuickTableView::AlignCenter << 0. << subRect << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << QQuickTableView::AlignCenter << 0. << subRect << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << QQuickTableView::AlignCenter << 0. << subRect << 50.;
+ QTest::newRow("AlignCenter 0") << 0 << QQuickTableView::AlignCenter << 0. << subRect << -1.;
+ QTest::newRow("AlignCenter 99") << 99 << QQuickTableView::AlignCenter << 0. << subRect << -1.;
+
+ QTest::newRow("AlignCenter 0") << 0 << QQuickTableView::AlignCenter << -10. << subRect << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << QQuickTableView::AlignCenter << -10. << subRect << 0.;
+ QTest::newRow("AlignCenter 1") << 1 << QQuickTableView::AlignCenter << -10. << subRect << 50.;
+ QTest::newRow("AlignCenter 0") << 0 << QQuickTableView::AlignCenter << -10. << subRect << -1.;
+ QTest::newRow("AlignCenter 99") << 99 << QQuickTableView::AlignCenter << -10. << subRect << -1.;
+ }
+}
+
+void tst_QQuickTableView::positionViewAtColumnClamped()
+{
+ // Check that positionViewAtColumn actually flicks the table to the
+ // right position so that the column becomes visible. For this test, we
+ // only test cells that cannot be placed exactly at the given alignment,
+ // because it would cause the table to overshoot. Instead the
+ // table should be flicked to the edge of the viewport, close to the
+ // requested alignment.
+ QFETCH(int, column);
+ QFETCH(QQuickTableView::PositionModeFlag, alignment);
+ QFETCH(qreal, offset);
+ QFETCH(QRectF, subRect);
+ QFETCH(qreal, contentXStartPos);
+
+ LOAD_TABLEVIEW("plaintableview.qml");
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+ if (contentXStartPos >= 0)
+ tableView->setContentX(contentXStartPos);
+
+ WAIT_UNTIL_POLISHED;
+
+ tableView->positionViewAtColumn(column, alignment, offset, subRect);
+
+ if (!tableView->isColumnLoaded(column))
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->contentX(), column < 50 ? 0 : tableView->contentWidth() - tableView->width());
+}
+
+void tst_QQuickTableView::positionViewAtCellWithAnimation()
+{
+ // Check that when we flick to already loaded cell in the
+ // table, this will start the animation, and the view will
+ // be position correctly after the expected duration.
+
+ LOAD_TABLEVIEW("plaintableview.qml");
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+ tableView->setAnimate(true);
+
+ WAIT_UNTIL_POLISHED;
+
+ QPoint cell(tableView->rightColumn(), tableView->bottomRow());
+ const QRectF cellGeometry = tableViewPrivate->loadedTableItem(cell)->geometry();
+ const int serializedIndex = tableViewPrivate->modelIndexAtCell(cell);
+ const QModelIndex index = tableView->index(cell.y(), cell.x());
+
+ QVERIFY(tableViewPrivate->loadedItems.contains(serializedIndex));
+ QVERIFY(!tableViewPrivate->positionXAnimation.isRunning());
+ QVERIFY(!tableViewPrivate->positionYAnimation.isRunning());
+
+ // Animate the cell to the top left location in the view
+ tableView->positionViewAtIndex(index, QQuickTableView::AlignTop | QQuickTableView::AlignLeft);
+
+ // Wait for animation to finish
+ QVERIFY(tableViewPrivate->positionXAnimation.isRunning());
+ QVERIFY(tableViewPrivate->positionYAnimation.isRunning());
+ QTRY_COMPARE(tableViewPrivate->positionXAnimation.isRunning(), false);
+ QTRY_COMPARE(tableViewPrivate->positionYAnimation.isRunning(), false);
+
+ // Check that the cell is now placed in the top left corner
+ QVERIFY(tableViewPrivate->loadedItems.contains(serializedIndex));
+ QPointF expectedPos = tableView->mapToItem(tableView->contentItem(), QPointF(0, 0));
+ QCOMPARE(cellGeometry.x(), expectedPos.x());
+ QCOMPARE(cellGeometry.y(), expectedPos.y());
+
+ // Animate the cell to the top right location in the view
+ tableView->positionViewAtIndex(index, QQuickTableView::AlignTop | QQuickTableView::AlignRight);
+
+ // Wait for animation to finish
+ QVERIFY(tableViewPrivate->positionXAnimation.isRunning());
+ QVERIFY(!tableViewPrivate->positionYAnimation.isRunning());
+ QTRY_COMPARE(tableViewPrivate->positionXAnimation.isRunning(), false);
+
+ // Check that the cell is now placed in the top right corner
+ QVERIFY(tableViewPrivate->loadedItems.contains(serializedIndex));
+ expectedPos = tableView->mapToItem(tableView->contentItem(), QPointF(tableView->width(), 0));
+ QCOMPARE(cellGeometry.right(), expectedPos.x());
+ QCOMPARE(cellGeometry.y(), expectedPos.y());
+
+ // Animate the cell to the bottom left location in the view
+ tableView->positionViewAtIndex(index, QQuickTableView::AlignBottom | QQuickTableView::AlignLeft);
+
+ // Wait for animation to finish
+ QVERIFY(tableViewPrivate->positionXAnimation.isRunning());
+ QVERIFY(tableViewPrivate->positionYAnimation.isRunning());
+ QTRY_COMPARE(tableViewPrivate->positionXAnimation.isRunning(), false);
+ QTRY_COMPARE(tableViewPrivate->positionYAnimation.isRunning(), false);
+
+ // Check that the cell is now placed in the bottom left corner
+ QVERIFY(tableViewPrivate->loadedItems.contains(serializedIndex));
+ expectedPos = tableView->mapToItem(tableView->contentItem(), QPointF(0, tableView->height()));
+ QCOMPARE(cellGeometry.x(), expectedPos.x());
+ QCOMPARE(cellGeometry.bottom(), expectedPos.y());
+
+ // Animate the cell to the bottom right location in the view
+ tableView->positionViewAtCell(cell, QQuickTableView::AlignBottom | QQuickTableView::AlignRight);
+
+ // Wait for animation to finish
+ QVERIFY(tableViewPrivate->positionXAnimation.isRunning());
+ QVERIFY(!tableViewPrivate->positionYAnimation.isRunning());
+ QTRY_COMPARE(tableViewPrivate->positionXAnimation.isRunning(), false);
+
+ // Check that the cell is now placed in the bottom right corner
+ QVERIFY(tableViewPrivate->loadedItems.contains(serializedIndex));
+ expectedPos = tableView->mapToItem(tableView->contentItem(), QPointF(tableView->width(), tableView->height()));
+ QCOMPARE(cellGeometry.right(), expectedPos.x());
+ QCOMPARE(cellGeometry.bottom(), expectedPos.y());
+}
+
+void tst_QQuickTableView::positionViewAtCell_VisibleAndContain_data()
+{
+ QTest::addColumn<QPoint>("cell");
+ QTest::addColumn<QQuickTableView::PositionModeFlag>("mode");
+ QTest::addColumn<QPointF>("offset");
+
+ QTest::newRow("99, 99, Contain") << QPoint{99, 99} << QQuickTableView::Contain << QPointF{0, 0};
+ QTest::newRow("0, 0, Contain") << QPoint{0, 0} << QQuickTableView::Contain << QPointF{0, 0};
+ QTest::newRow("5, 0, Contain") << QPoint{5, 0} << QQuickTableView::Contain << QPointF{0, 0};
+ QTest::newRow("0, 7, Contain") << QPoint{0, 7} << QQuickTableView::Contain << QPointF{0, 0};
+ QTest::newRow("1, 1, Contain") << QPoint{1, 1} << QQuickTableView::Contain << QPointF{0, 0};
+ QTest::newRow("10, 10, Contain") << QPoint{10, 10} << QQuickTableView::Contain << QPointF{0, 0};
+
+ QTest::newRow("99, 99, Visible") << QPoint{99, 99} << QQuickTableView::Visible << QPointF{0, 0};
+ QTest::newRow("0, 0, Visible") << QPoint{0, 0} << QQuickTableView::Visible << QPointF{0, 0};
+ QTest::newRow("5, 1, Visible") << QPoint{5, 1} << QQuickTableView::Visible << QPointF{0, 0};
+ QTest::newRow("1, 7, Visible") << QPoint{1, 7} << QQuickTableView::Visible << QPointF{0, 0};
+ QTest::newRow("1, 1, Visible") << QPoint{1, 1} << QQuickTableView::Visible << QPointF{0, 0};
+ QTest::newRow("10, 10, Visible") << QPoint{10, 10} << QQuickTableView::Visible << QPointF{0, 0};
+
+ QTest::newRow("99, 99, Contain, margins") << QPoint{99, 99} << QQuickTableView::Contain << QPointF{10, 10};
+ QTest::newRow("0, 0, Contain, margins") << QPoint{0, 0} << QQuickTableView::Contain << QPointF{10, 10};
+ QTest::newRow("5, 0, Contain, margins") << QPoint{5, 1} << QQuickTableView::Contain << QPointF{10, 10};
+ QTest::newRow("1, 7, Contain, margins") << QPoint{1, 7} << QQuickTableView::Contain << QPointF{10, 10};
+ QTest::newRow("1, 1, Contain, margins") << QPoint{1, 1} << QQuickTableView::Contain << QPointF{10, 10};
+ QTest::newRow("10, 10, Contain, margins") << QPoint{10, 10} << QQuickTableView::Contain << QPointF{10, 10};
+}
+
+void tst_QQuickTableView::positionViewAtCell_VisibleAndContain()
+{
+ // Check that the PositionModes "Visible" and "Contain" works according
+ // to the documentation.
+ QFETCH(QPoint, cell);
+ QFETCH(QQuickTableView::PositionModeFlag, mode);
+ QFETCH(QPointF, offset);
+
+ LOAD_TABLEVIEW("plaintableview.qml");
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+ tableView->setAnimate(true);
+
+ WAIT_UNTIL_POLISHED;
+
+ const bool cellIsVisible = tableView->itemAtCell(cell) != nullptr;
+ bool cellIsCompletelyVisible = false;
+ if (cellIsVisible) {
+ const QRectF cellRect = tableViewPrivate->loadedTableItem(cell)->geometry();
+ QRectF viewportRect = tableViewPrivate->viewportRect;
+ viewportRect.adjust(offset.x(), offset.y(), -offset.x(), -offset.y());
+ cellIsCompletelyVisible = viewportRect.contains(cellRect);
+ }
+
+ tableView->positionViewAtCell(cell, mode, offset);
+
+ if (cellIsCompletelyVisible || (cellIsVisible && mode == QQuickTableView::Visible)) {
+ // Nothing to do!
+ QVERIFY(!tableViewPrivate->positionXAnimation.isRunning());
+ QVERIFY(!tableViewPrivate->positionYAnimation.isRunning());
+ QVERIFY(!QQuickTest::qIsPolishScheduled(tableView));
+ } else if (cellIsVisible) {
+ // TableView will scroll towards the cell, unless it'a already at the correct place
+ QTRY_COMPARE(tableViewPrivate->positionXAnimation.isRunning(), false);
+ QTRY_COMPARE(tableViewPrivate->positionYAnimation.isRunning(), false);
+ } else {
+ // TableView will rebuild on top of the cell
+ QVERIFY(!tableViewPrivate->positionXAnimation.isRunning());
+ QVERIFY(!tableViewPrivate->positionYAnimation.isRunning());
+ WAIT_UNTIL_POLISHED;
+ }
+
+ QVERIFY(tableView->itemAtCell(cell));
+}
+
+void tst_QQuickTableView::positionViewAtCell_VisibleAndContain_SubRect_data()
+{
+ QTest::addColumn<QPoint>("cell");
+ QTest::addColumn<QQuickTableView::PositionModeFlag>("mode");
+ QTest::addColumn<QRectF>("subRect");
+ QTest::addColumn<QPointF>("contentStartPos");
+
+ QRectF subRects[] = { QRectF(0, 0, 10, 10),
+ QRectF(10, 10, 10, 10),
+ QRectF(80, 30, 10, 10),
+ QRectF(90, 40, 10, 10),
+ QRectF(0, 0, 100, 50) };
+
+ for (auto subRect : subRects) {
+ QTest::newRow("99, 99, Contain") << QPoint{99, 99} << QQuickTableView::Contain << subRect << QPointF(0, 0);
+ QTest::newRow("0, 0, Contain") << QPoint{0, 0} << QQuickTableView::Contain << subRect << QPointF(0, 0);
+ QTest::newRow("0, 0, Contain, start: 50, 25") << QPoint{0, 0} << QQuickTableView::Contain << subRect << QPointF(50, 25);
+ QTest::newRow("5, 0, Contain") << QPoint{5, 0} << QQuickTableView::Contain << subRect << QPointF(0, 0);
+ QTest::newRow("0, 7, Contain") << QPoint{0, 7} << QQuickTableView::Contain << subRect << QPointF(0, 0);
+ QTest::newRow("5, 7, Contain, start: -50, -25") << QPoint{5, 7} << QQuickTableView::Contain << subRect << QPointF(-50, -25);
+
+ QTest::newRow("99, 99, Visible") << QPoint{99, 99} << QQuickTableView::Visible << subRect << QPointF(0, 0);
+ QTest::newRow("0, 0, Visible") << QPoint{0, 0} << QQuickTableView::Visible << subRect << QPointF(0, 0);
+ QTest::newRow("0, 0, Visible, start: 50, 25") << QPoint{0, 0} << QQuickTableView::Visible << subRect << QPointF(50, 25);
+ QTest::newRow("5, 1, Visible") << QPoint{5, 1} << QQuickTableView::Visible << subRect << QPointF(0, 0);
+ QTest::newRow("1, 7, Visible") << QPoint{1, 7} << QQuickTableView::Visible << subRect << QPointF(0, 0);
+ QTest::newRow("5, 7, Visible, start: -50, -25") << QPoint{5, 7} << QQuickTableView::Visible << subRect << QPointF(-50, -25);
+ }
+}
+
+void tst_QQuickTableView::positionViewAtCell_VisibleAndContain_SubRect()
+{
+ // Check that the PositionModes "Visible" and "Contain" works when using subrects
+ QFETCH(QPoint, cell);
+ QFETCH(QQuickTableView::PositionModeFlag, mode);
+ QFETCH(QRectF, subRect);
+ QFETCH(QPointF, contentStartPos);
+
+ LOAD_TABLEVIEW("plaintableview.qml");
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+ tableView->setAnimate(true);
+ tableView->setContentX(contentStartPos.x());
+ tableView->setContentY(contentStartPos.y());
+
+ WAIT_UNTIL_POLISHED;
+
+ const bool cellIsVisible = tableView->itemAtCell(cell) != nullptr;
+ bool subRectIsVisible = false;
+ bool subRectIsContained = false;
+
+ if (cellIsVisible) {
+ const QRectF cellRect = tableViewPrivate->loadedTableItem(cell)->geometry();
+ const QRectF alignmentRect = subRect.translated(cellRect.topLeft());
+ const QRectF viewportRect = tableViewPrivate->viewportRect;
+ subRectIsVisible = viewportRect.intersects(alignmentRect);
+ subRectIsContained = viewportRect.contains(alignmentRect);
+ }
+
+ tableView->positionViewAtCell(cell, mode, QPointF(), subRect);
+
+ if (cellIsVisible) {
+ if ((mode == QQuickTableView::Visible && subRectIsVisible) ||
+ (mode == QQuickTableView::Contain && subRectIsContained)) {
+ // The mode is already fulfilled, so verify that no animation (or rebuild) runs
+ QVERIFY(!tableViewPrivate->positionXAnimation.isRunning());
+ QVERIFY(!tableViewPrivate->positionYAnimation.isRunning());
+ QVERIFY(!QQuickTest::qIsPolishScheduled(tableView));
+ } else {
+ // TableView will scroll towards the cell
+ QVERIFY(tableViewPrivate->positionXAnimation.isRunning()
+ || tableViewPrivate->positionYAnimation.isRunning());
+ QTRY_VERIFY(!tableViewPrivate->positionXAnimation.isRunning()
+ && !tableViewPrivate->positionYAnimation.isRunning());
+ }
+ } else {
+ // The cell is not loaded, so TableView will rebuild
+ WAIT_UNTIL_POLISHED;
+ }
+
+ // Check that the subRect is now visible inside the viewport, according to the mode
+ QVERIFY(tableView->itemAtCell(cell));
+ const QRectF cellRectAfterPositioning = tableViewPrivate->loadedTableItem(cell)->geometry();
+ const QRectF alignmentRectAfterPositioning = subRect.translated(cellRectAfterPositioning.topLeft());
+ const QRectF viewportRect = tableViewPrivate->viewportRect;
+
+ if (mode == QQuickTableView::Visible)
+ QVERIFY(viewportRect.intersects(alignmentRectAfterPositioning));
+ else // QQuickTableView::Contain
+ QVERIFY(viewportRect.contains(alignmentRectAfterPositioning));
+}
+
+void tst_QQuickTableView::positionViewAtCellForLargeCells_data()
+{
+ QTest::addColumn<qreal>("cellSize");
+
+ QTest::newRow("200") << 200.;
+ QTest::newRow("800") << 800.;
+}
+
+void tst_QQuickTableView::positionViewAtCellForLargeCells()
+{
+ // Position the view on a cell outside the viewport. When the cells are larger
+ // than the viewport, check that TableView.Contain will place the cell top-left.
+ // When the cells are smaller than the viewport, it should be placed bottom-right.
+ QFETCH(qreal, cellSize);
+
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(10, 10);
+ tableView->setModel(model);
+
+ view->rootObject()->setProperty("delegateWidth", cellSize);
+ view->rootObject()->setProperty("delegateHeight", cellSize);
+
+ WAIT_UNTIL_POLISHED;
+
+ const QPoint cell(5, 5);
+ tableView->positionViewAtCell(cell, QQuickTableView::Contain);
+
+ WAIT_UNTIL_POLISHED;
+
+ const QQuickItem *item = tableView->itemAtCell(cell);
+ QVERIFY(item);
+
+ QPointF expectedPos;
+ if (cellSize > tableView->width()) {
+ expectedPos = tableView->mapToItem(tableView->contentItem(), QPointF(0, 0));
+ } else {
+ expectedPos = tableView->mapToItem(tableView->contentItem(), QPointF(tableView->width(), tableView->height()));
+ expectedPos -= QPointF(item->width(), item->height());
+ }
+
+ QCOMPARE(item->x(), expectedPos.x());
+ QCOMPARE(item->y(), expectedPos.y());
+}
+
+void tst_QQuickTableView::positionViewAtCellForLargeCellsUsingSubrect()
+{
+ // Position the view on a cell outside the viewport. When a cell is larger
+ // than the viewport, TableView.Contain will normally place it top-left.
+ // But if we specify a subRect that is close to the bottom-right edge (and
+ // the subRect is smaller than the viewport), TableView should align
+ // bottom-right of the subRect instead.
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(10, 10);
+ tableView->setModel(model);
+ tableView->setAnimate(false);
+
+ const qreal cellSize = 800;
+ view->rootObject()->setProperty("delegateWidth", cellSize);
+ view->rootObject()->setProperty("delegateHeight", cellSize);
+
+ WAIT_UNTIL_POLISHED;
+
+ const QRectF subRect(cellSize - 100, cellSize - 100, 10, 10);
+ tableView->positionViewAtCell(QPoint(0, 0), QQuickTableView::Contain, QPointF(), subRect);
+ QCOMPARE(tableView->contentX(), -(tableView->width() - subRect.right()));
+ QCOMPARE(tableView->contentY(), -(tableView->height() - subRect.bottom()));
+}
+
+void tst_QQuickTableView::positionViewAtLastRow_data()
+{
+ QTest::addColumn<QString>("signalToTest");
+ QTest::addColumn<bool>("animate");
+
+ QTest::newRow("positionOnRowsChanged, animate=false") << "positionOnRowsChanged" << false;
+ QTest::newRow("positionOnRowsChanged, animate=true") << "positionOnRowsChanged" << true;
+ QTest::newRow("positionOnContentHeightChanged, animate=false") << "positionOnContentHeightChanged" << false;
+ QTest::newRow("positionOnContentHeightChanged, animate=true") << "positionOnContentHeightChanged" << true;
+}
+
+void tst_QQuickTableView::positionViewAtLastRow()
+{
+ // Check that we can make TableView always scroll to the
+ // last row in the model by positioning the view upon
+ // a rowsChanged callback
+ QFETCH(QString, signalToTest);
+ QFETCH(bool, animate);
+
+ LOAD_TABLEVIEW("positionlast.qml");
+
+ // Use a very large model to indirectly test that we "fast-flick" to
+ // the end at start-up (instead of loading and unloading rows, which
+ // would take forever).
+ TestModel model(2000000, 2000000);
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setAnimate(animate);
+
+ view->rootObject()->setProperty(signalToTest.toUtf8().constData(), true);
+
+ WAIT_UNTIL_POLISHED;
+
+ const qreal delegateSize = 100.;
+ const qreal viewportRowCount = tableView->height() / delegateSize;
+
+ // Check that the viewport is positioned at the last row at start-up
+ QCOMPARE(tableView->rows(), model.rowCount());
+ QCOMPARE(tableView->bottomRow(), model.rowCount() - 1);
+ QCOMPARE(tableView->contentY(), (model.rowCount() - viewportRowCount) * delegateSize);
+
+ // Check that the viewport is positioned at the last
+ // row after more rows are added.
+ for (int row = 0; row < 2; ++row) {
+ model.addRow(model.rowCount() - 1);
+
+ WAIT_UNTIL_POLISHED;
+
+ if (tableView->animate()) {
+ QVERIFY(tableViewPrivate->positionYAnimation.isRunning());
+ QTRY_VERIFY(!tableViewPrivate->positionYAnimation.isRunning());
+ }
+
+ QCOMPARE(tableView->rows(), model.rowCount());
+ QCOMPARE(tableView->bottomRow(), model.rowCount() - 1);
+ QCOMPARE(tableView->contentY(), (model.rowCount() - viewportRowCount) * delegateSize);
+ }
+}
+
+void tst_QQuickTableView::positionViewAtLastColumn_data()
+{
+ QTest::addColumn<QString>("signalToTest");
+ QTest::addColumn<bool>("animate");
+
+ QTest::newRow("positionOnColumnsChanged, animate=false") << "positionOnColumnsChanged" << false;
+ QTest::newRow("positionOnColumnsChanged, animate=true") << "positionOnColumnsChanged" << true;
+ QTest::newRow("positionOnContentWidthChanged, animate=false") << "positionOnContentWidthChanged" << false;
+ QTest::newRow("positionOnContentWidthChanged, animate=true") << "positionOnContentWidthChanged" << true;
+}
+
+void tst_QQuickTableView::positionViewAtLastColumn()
+{
+ // Check that we can make TableView always scroll to the
+ // last column in the model by positioning the view upon
+ // a columnsChanged callback
+ QFETCH(QString, signalToTest);
+ QFETCH(bool, animate);
+
+ LOAD_TABLEVIEW("positionlast.qml");
+
+ // Use a very large model to indirectly test that we "fast-flick" to
+ // the end at start-up (instead of loading and unloading columns, which
+ // would take forever).
+ TestModel model(2000000, 2000000);
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setAnimate(animate);
+
+ view->rootObject()->setProperty(signalToTest.toUtf8().constData(), true);
+
+ WAIT_UNTIL_POLISHED;
+
+ const qreal delegateSize = 100.;
+ const qreal viewportColumnCount = tableView->width() / delegateSize;
+
+ // Check that the viewport is positioned at the last column at start-up
+ QCOMPARE(tableView->columns(), model.columnCount());
+ QCOMPARE(tableView->rightColumn(), model.columnCount() - 1);
+ QCOMPARE(tableView->contentX(), (model.columnCount() - viewportColumnCount) * delegateSize);
+
+ // Check that the viewport is positioned at the last
+ // column after more columns are added.
+ for (int column = 0; column < 2; ++column) {
+ model.addColumn(model.columnCount() - 1);
+
+ WAIT_UNTIL_POLISHED;
+
+ if (tableView->animate()) {
+ QVERIFY(tableViewPrivate->positionXAnimation.isRunning());
+ QTRY_VERIFY(!tableViewPrivate->positionXAnimation.isRunning());
+ }
+
+ QCOMPARE(tableView->columns(), model.columnCount());
+ QCOMPARE(tableView->rightColumn(), model.columnCount() - 1);
+ QCOMPARE(tableView->contentX(), (model.columnCount() - viewportColumnCount) * delegateSize);
+ }
+}
+
void tst_QQuickTableView::itemAtCell_data()
{
QTest::addColumn<QPoint>("cell");
@@ -3190,10 +4318,37 @@ void tst_QQuickTableView::leftRightTopBottomProperties()
QCOMPARE(tableView->rightColumn(), expectedTable.right());
QCOMPARE(tableView->bottomRow(), expectedTable.bottom());
- QCOMPARE(leftSpy.count(), expectedSignalCount.left());
- QCOMPARE(rightSpy.count(), expectedSignalCount.right());
- QCOMPARE(topSpy.count(), expectedSignalCount.top());
- QCOMPARE(bottomSpy.count(), expectedSignalCount.bottom());
+ QCOMPARE(leftSpy.size(), expectedSignalCount.left());
+ QCOMPARE(rightSpy.size(), expectedSignalCount.right());
+ QCOMPARE(topSpy.size(), expectedSignalCount.top());
+ QCOMPARE(bottomSpy.size(), expectedSignalCount.bottom());
+}
+
+void tst_QQuickTableView::leftRightTopBottomUpdatedBeforeSignalEmission()
+{
+ // Check that leftColumn, rightColumn, topRow and bottomRow are
+ // actually updated before the changed signals are emitted.
+ LOAD_TABLEVIEW("plaintableview.qml");
+ auto model = TestModelAsVariant(100, 100);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ connect(tableView, &QQuickTableView::leftColumnChanged, [=]{
+ QCOMPARE(tableView->leftColumn(), 1);
+ });
+ connect(tableView, &QQuickTableView::rightColumnChanged, [=]{
+ QCOMPARE(tableView->rightColumn(), 6);
+ });
+ connect(tableView, &QQuickTableView::topRowChanged, [=]{
+ QCOMPARE(tableView->topRow(), 1);
+ });
+ connect(tableView, &QQuickTableView::bottomRowChanged, [=]{
+ QCOMPARE(tableView->bottomRow(), 8);
+ });
+
+ tableView->setContentX(100);
+ tableView->setContentY(50);
}
void tst_QQuickTableView::checkContentSize_data()
@@ -3266,6 +4421,3133 @@ void tst_QQuickTableView::checkContentSize()
QCOMPARE(tableView->contentHeight(), rowCount == 0 ? 0 : (rowCount * (delegateHeight + rowSpacing)) - rowSpacing);
}
+void tst_QQuickTableView::checkSelectionModelWithRequiredSelectedProperty_data()
+{
+ QTest::addColumn<QVector<QPoint>>("selected");
+ QTest::addColumn<QPoint>("toggle");
+
+ QTest::newRow("nothing selected") << QVector<QPoint>() << QPoint(0,0);
+ QTest::newRow("one item selected") << (QVector<QPoint>() << QPoint(0, 0)) << QPoint(1, 1);
+ QTest::newRow("two items selected") << (QVector<QPoint>() << QPoint(1, 1) << QPoint(2, 2)) << QPoint(1, 1);
+}
+
+void tst_QQuickTableView::checkSelectionModelWithRequiredSelectedProperty()
+{
+ // Check that if you add a "required property selected" to the delegate,
+ // TableView will give it a value upon creation that matches the state
+ // in the selection model.
+ QFETCH(QVector<QPoint>, selected);
+ QFETCH(QPoint, toggle);
+
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(10, 10);
+ QItemSelectionModel selectionModel(&model);
+
+ // Set initially selected cells
+ for (auto it = selected.constBegin(); it != selected.constEnd(); ++it) {
+ const QPoint &cell = *it;
+ selectionModel.select(model.index(cell.y(), cell.x()), QItemSelectionModel::Select);
+ }
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that all delegates have "selected" set with the initial value
+ for (auto fxItem : tableViewPrivate->loadedItems) {
+ const auto context = qmlContext(fxItem->item.data());
+ const int row = context->contextProperty("row").toInt();
+ const int column = context->contextProperty("column").toInt();
+ const bool selected = fxItem->item->property("selected").toBool();
+ const auto modelIndex = model.index(row, column);
+ QCOMPARE(selected, selectionModel.isSelected(modelIndex));
+ }
+
+ // Toggle selected on one of the model indices, and check
+ // that the "selected" property got updated as well
+ const QModelIndex toggleIndex = model.index(toggle.y(), toggle.x());
+ const bool wasSelected = selectionModel.isSelected(toggleIndex);
+ selectionModel.select(toggleIndex, QItemSelectionModel::Toggle);
+ const auto fxItem = tableViewPrivate->loadedTableItem(toggle);
+ const bool isSelected = fxItem->item->property("selected").toBool();
+ QCOMPARE(isSelected, !wasSelected);
+}
+
+void tst_QQuickTableView::checkSelectionModelWithUnrequiredSelectedProperty()
+{
+ // Check that if there is a property "selected" in the delegate, but it's
+ // not required, then TableView will not touch it. This is for legacy reasons, to
+ // not break applications written before Qt 6.2 that has such a property
+ // added for application logic.
+ LOAD_TABLEVIEW("tableviewwithselected2.qml");
+
+ TestModel model(10, 10);
+ tableView->setModel(QVariant::fromValue(&model));
+ QItemSelectionModel *selectionModel = tableView->selectionModel();
+ QVERIFY(selectionModel);
+
+ // Select a cell
+ selectionModel->select(model.index(1, 1), QItemSelectionModel::Select);
+
+ WAIT_UNTIL_POLISHED;
+
+ const auto fxItem = tableViewPrivate->loadedTableItem(QPoint(1, 1));
+ const bool selected = fxItem->item->property("selected").toBool();
+ QCOMPARE(selected, false);
+}
+
+void tst_QQuickTableView::removeAndAddSelectionModel()
+{
+ // Check that if we remove the selection model from TableView, all delegates
+ // will be unselected. And opposite, if we add the selection model back, the
+ // delegates will be updated.
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(10, 10);
+ QItemSelectionModel selectionModel(&model);
+
+ // Select a cell in the selection model
+ selectionModel.select(model.index(1, 1), QItemSelectionModel::Select);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that the delegate item is selected
+ const auto fxItem = tableViewPrivate->loadedTableItem(QPoint(1, 1));
+ bool selected = fxItem->item->property("selected").toBool();
+ QCOMPARE(selected, true);
+
+ // Remove the selection model, and check that the delegate item is now unselected
+ tableView->setSelectionModel(nullptr);
+ selected = fxItem->item->property("selected").toBool();
+ QCOMPARE(selected, false);
+
+ // Add the selection model back, and check that the delegate item is selected again
+ tableView->setSelectionModel(&selectionModel);
+ selected = fxItem->item->property("selected").toBool();
+ QCOMPARE(selected, true);
+}
+
+void tst_QQuickTableView::warnOnWrongModelInSelectionModel()
+{
+ // The model set on the SelectionModel should always match the model
+ // set on TableView. This is normally handled automatically, but it's
+ // possible to circumvent. This test will check that we warn if that happens.
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model1(10, 10);
+ TestModel model2(10, 10);
+
+ tableView->setModel(QVariant::fromValue(&model1));
+ QItemSelectionModel selectionModel;
+ tableView->setSelectionModel(&selectionModel);
+
+ // Set a different model
+ selectionModel.setModel(&model2);
+
+ // And change currentIndex. This will produce a warning.
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*TableView.selectionModel.model.*"));
+ selectionModel.setCurrentIndex(model2.index(0, 0), QItemSelectionModel::NoUpdate);
+}
+
+void tst_QQuickTableView::selectionBehaviorCells_data()
+{
+ QTest::addColumn<QPoint>("endCellDist");
+
+ QTest::newRow("single cell") << QPoint(0, 0);
+
+ QTest::newRow("left to right") << QPoint(1, 0);
+ QTest::newRow("left to right") << QPoint(2, 0);
+ QTest::newRow("right to left") << QPoint(-1, 0);
+ QTest::newRow("right to left") << QPoint(-2, 0);
+
+ QTest::newRow("top to bottom") << QPoint(0, 1);
+ QTest::newRow("top to bottom") << QPoint(0, 2);
+ QTest::newRow("bottom to top") << QPoint(0, -1);
+ QTest::newRow("bottom to top") << QPoint(0, -2);
+
+ QTest::newRow("diagonal top left to bottom right") << QPoint(1, 1);
+ QTest::newRow("diagonal top left to bottom right") << QPoint(2, 2);
+ QTest::newRow("diagonal bottom left to top right") << QPoint(-1, -1);
+ QTest::newRow("diagonal bottom left to top right") << QPoint(-2, -2);
+ QTest::newRow("diagonal top right to bottom left") << QPoint(-1, 1);
+ QTest::newRow("diagonal top right to bottom left") << QPoint(-2, 2);
+ QTest::newRow("diagonal bottom right to top left") << QPoint(1, -1);
+ QTest::newRow("diagonal bottom right to top left") << QPoint(2, -2);
+}
+
+void tst_QQuickTableView::selectionBehaviorCells()
+{
+ // Check that the TableView implement QQuickSelectableInterface startSelection,
+ // setSelectionStartPos, setSelectionEndPos and clearSelection correctly. Do this by
+ // calling setSelectionStartPos/setSelectionEndPos on top of different cells, and see
+ // that we end up with the expected selections.
+ QFETCH(QPoint, endCellDist);
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(10, 10);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(selectionModel.hasSelection(), false);
+ QCOMPARE(tableView->selectionBehavior(), QQuickTableView::SelectCells);
+
+ const QPoint startCell(5, 5);
+ const QPoint endCell = startCell + endCellDist;
+ const QPoint endCellWrapped = startCell - endCellDist;
+
+ const QQuickItem *startItem = tableView->itemAtCell(startCell);
+ const QQuickItem *endItem = tableView->itemAtCell(endCell);
+ const QQuickItem *endItemWrapped = tableView->itemAtCell(endCellWrapped);
+ QVERIFY(startItem);
+ QVERIFY(endItem);
+ QVERIFY(endItemWrapped);
+
+ const QPointF startPos(startItem->x(), startItem->y());
+ const QPointF endPos(endItem->x(), endItem->y());
+ const QPointF endPosWrapped(endItemWrapped->x(), endItemWrapped->y());
+
+ QVERIFY(tableViewPrivate->startSelection(startPos, Qt::NoModifier));
+ tableViewPrivate->setSelectionStartPos(startPos);
+ tableViewPrivate->setSelectionEndPos(endPos);
+
+ QCOMPARE(selectionModel.hasSelection(), true);
+
+ const int x1 = qMin(startCell.x(), endCell.x());
+ const int x2 = qMax(startCell.x(), endCell.x());
+ const int y1 = qMin(startCell.y(), endCell.y());
+ const int y2 = qMax(startCell.y(), endCell.y());
+
+ for (int x = x1; x < x2; ++x) {
+ for (int y = y1; y < y2; ++y) {
+ const auto index = model.index(y, x);
+ QVERIFY(selectionModel.isSelected(index));
+ }
+ }
+
+ const int expectedCount = (x2 - x1 + 1) * (y2 - y1 + 1);
+ const int actualCount = selectionModel.selectedIndexes().size();
+ QCOMPARE(actualCount, expectedCount);
+
+ // Wrap the selection
+ tableViewPrivate->setSelectionEndPos(endPosWrapped);
+
+ for (int x = x2; x < x1; ++x) {
+ for (int y = y2; y < y1; ++y) {
+ const auto index = model.index(y, x);
+ QVERIFY(selectionModel.isSelected(index));
+ }
+ }
+
+ const int actualCountAfterWrap = selectionModel.selectedIndexes().size();
+ QCOMPARE(actualCountAfterWrap, expectedCount);
+
+ tableViewPrivate->clearSelection();
+ QCOMPARE(selectionModel.hasSelection(), false);
+}
+
+void tst_QQuickTableView::selectionBehaviorRows()
+{
+ // Check that the TableView implement QQuickSelectableInterface startSelection,
+ // setSelectionStartPos, setSelectionEndPos and clearSelection correctly for
+ // QQuickTableView::SelectRows.
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(10, 10);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setSelectionBehavior(QQuickTableView::SelectRows);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(selectionModel.hasSelection(), false);
+
+ // Drag from row 0 to row 3
+ QVERIFY(tableViewPrivate->startSelection(QPointF(0, 0), Qt::NoModifier));
+ tableViewPrivate->setSelectionStartPos(QPointF(0, 0));
+ tableViewPrivate->setSelectionEndPos(QPointF(60, 60));
+
+ QCOMPARE(selectionModel.hasSelection(), true);
+
+ const int expectedCount = 10 * 3; // all columns * three rows
+ int actualCount = selectionModel.selectedIndexes().size();
+ QCOMPARE(actualCount, expectedCount);
+
+ for (int x = 0; x < tableView->columns(); ++x) {
+ for (int y = 0; y < 3; ++y) {
+ const auto index = model.index(y, x);
+ QVERIFY(selectionModel.isSelected(index));
+ }
+ }
+
+ selectionModel.clear();
+ QCOMPARE(selectionModel.hasSelection(), false);
+
+ // Drag from row 3 to row 0 (and overshoot mouse)
+ QVERIFY(tableViewPrivate->startSelection(QPointF(60, 60), Qt::NoModifier));
+ tableViewPrivate->setSelectionStartPos(QPointF(60, 60));
+ tableViewPrivate->setSelectionEndPos(QPointF(-10, -10));
+
+ QCOMPARE(selectionModel.hasSelection(), true);
+
+ actualCount = selectionModel.selectedIndexes().size();
+ QCOMPARE(actualCount, expectedCount);
+
+ for (int x = 0; x < tableView->columns(); ++x) {
+ for (int y = 0; y < 3; ++y) {
+ const auto index = model.index(y, x);
+ QVERIFY(selectionModel.isSelected(index));
+ }
+ }
+}
+
+void tst_QQuickTableView::selectionBehaviorColumns()
+{
+ // Check that the TableView implement QQuickSelectableInterface startSelection,
+ // setSelectionStartPos, setSelectionEndPos and clearSelection correctly for
+ // QQuickTableView::SelectColumns.
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(10, 10);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setSelectionBehavior(QQuickTableView::SelectColumns);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(selectionModel.hasSelection(), false);
+
+ // Drag from column 0 to column 3
+ QVERIFY(tableViewPrivate->startSelection(QPointF(60, 60), Qt::NoModifier));
+ tableViewPrivate->setSelectionStartPos(QPointF(0, 0));
+ tableViewPrivate->setSelectionEndPos(QPointF(60, 60));
+
+ QCOMPARE(selectionModel.hasSelection(), true);
+
+ const int expectedCount = 10 * 3; // all rows * three columns
+ int actualCount = selectionModel.selectedIndexes().size();
+ QCOMPARE(actualCount, expectedCount);
+
+ for (int x = 0; x < 3; ++x) {
+ for (int y = 0; y < tableView->rows(); ++y) {
+ const auto index = model.index(y, x);
+ QVERIFY(selectionModel.isSelected(index));
+ }
+ }
+
+ selectionModel.clear();
+ QCOMPARE(selectionModel.hasSelection(), false);
+
+ // Drag from column 3 to column 0 (and overshoot mouse)
+ QVERIFY(tableViewPrivate->startSelection(QPointF(60, 60), Qt::NoModifier));
+ tableViewPrivate->setSelectionStartPos(QPointF(60, 60));
+ tableViewPrivate->setSelectionEndPos(QPointF(-10, -10));
+
+ QCOMPARE(selectionModel.hasSelection(), true);
+
+ actualCount = selectionModel.selectedIndexes().size();
+ QCOMPARE(actualCount, expectedCount);
+
+ for (int x = 0; x < 3; ++x) {
+ for (int y = 0; y < tableView->rows(); ++y) {
+ const auto index = model.index(y, x);
+ QVERIFY(selectionModel.isSelected(index));
+ }
+ }
+}
+
+void tst_QQuickTableView::selectionBehaviorDisabled()
+{
+ // Check that the TableView implement QQuickSelectableInterface startSelection
+ // correctly for QQuickTableView::SelectionDisabled.
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(10, 10);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setSelectionBehavior(QQuickTableView::SelectionDisabled);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(selectionModel.hasSelection(), false);
+
+ // Try to start a selection
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*TableView.SelectionDisabled"));
+ QVERIFY(!tableViewPrivate->startSelection(QPointF(0, 0), Qt::NoModifier));
+
+ QCOMPARE(selectionModel.hasSelection(), false);
+}
+
+void tst_QQuickTableView::testSelectableStartPosEndPosOutsideView()
+{
+ // Call startSelection, setSelectionStartPos and setSelectionEndPos with positions
+ // outside the view. This should first of all not crash, but instead just clamp the
+ // selection to the cells that are visible inside the view.
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(10, 10);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+
+ WAIT_UNTIL_POLISHED;
+
+ const QPoint centerCell(5, 5);
+ const QQuickItem *centerItem = tableView->itemAtCell(centerCell);
+ QVERIFY(centerItem);
+
+ const QPointF centerPos(centerItem->x(), centerItem->y());
+ const QPointF outsideLeft(-100, centerPos.y());
+ const QPointF outsideRight(tableView->width() + 100, centerPos.y());
+ const QPointF outsideTop(centerPos.x(), -100);
+ const QPointF outsideBottom(centerPos.x(), tableView->height() + 100);
+
+ QVERIFY(tableViewPrivate->startSelection(centerPos, Qt::NoModifier));
+ tableViewPrivate->setSelectionStartPos(centerPos);
+
+ tableViewPrivate->setSelectionEndPos(outsideLeft);
+ for (int x = 0; x <= centerCell.x(); ++x) {
+ const auto index = model.index(centerCell.y(), x);
+ QVERIFY(selectionModel.isSelected(index));
+ }
+
+ tableViewPrivate->setSelectionEndPos(outsideRight);
+ for (int x = centerCell.x(); x < model.columnCount(); ++x) {
+ const auto index = model.index(centerCell.y(), x);
+ QVERIFY(selectionModel.isSelected(index));
+ }
+
+ tableViewPrivate->setSelectionEndPos(outsideTop);
+ for (int y = 0; y <= centerCell.y(); ++y) {
+ const auto index = model.index(y, centerCell.x());
+ QVERIFY(selectionModel.isSelected(index));
+ }
+
+ tableViewPrivate->setSelectionEndPos(outsideBottom);
+ for (int y = centerCell.y(); y < model.rowCount(); ++y) {
+ const auto index = model.index(y, centerCell.x());
+ QVERIFY(selectionModel.isSelected(index));
+ }
+}
+
+void tst_QQuickTableView::testSelectableScrollTowardsPos()
+{
+ // Check that TableView will implement the scrollTowardsSelectionPoint function
+ // correctly, and move the content item towards the given position
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(200, 200);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->contentX(), 0);
+ QCOMPARE(tableView->contentY(), 0);
+
+ const QSizeF step(1, 1);
+ const QPointF topLeft(-100, -100);
+ const QPointF topRight(tableView->width() + 100, -100);
+ const QPointF bottomLeft(-100, tableView->height() + 100);
+ const QPointF bottomRight(tableView->width() + 100, tableView->height() + 100);
+
+ tableViewPrivate->scrollTowardsSelectionPoint(topRight, step);
+ QCOMPARE(tableView->contentX(), step.width());
+ QCOMPARE(tableView->contentY(), 0);
+
+ tableViewPrivate->scrollTowardsSelectionPoint(bottomRight, step);
+ QCOMPARE(tableView->contentX(), step.width() * 2);
+ QCOMPARE(tableView->contentY(), step.height());
+
+ tableViewPrivate->scrollTowardsSelectionPoint(bottomLeft, step);
+ QCOMPARE(tableView->contentX(), step.width());
+ QCOMPARE(tableView->contentY(), step.height() * 2);
+
+ tableViewPrivate->scrollTowardsSelectionPoint(topLeft, step);
+ QCOMPARE(tableView->contentX(), 0);
+ QCOMPARE(tableView->contentY(), step.height());
+
+ tableViewPrivate->scrollTowardsSelectionPoint(topLeft, step);
+ QCOMPARE(tableView->contentX(), 0);
+ QCOMPARE(tableView->contentY(), 0);
+}
+
+void tst_QQuickTableView::setCurrentIndexFromSelectionModel()
+{
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(40, 40);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setFocus(true);
+ const char kCurrent[] = "current";
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that all delegates have current set to false upon start
+ for (auto fxItem : tableViewPrivate->loadedItems)
+ QVERIFY(!fxItem->item->property(kCurrent).toBool());
+
+ // Start by making cell 0, 0 current
+ const QPoint cell0_0(0, 0);
+ selectionModel.setCurrentIndex(tableView->modelIndex(cell0_0), QItemSelectionModel::NoUpdate);
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+
+ // Move currentIndex to a cell outside the viewport by accessing the selection
+ // model directly, scroll to it, and check current status.
+ const QPoint cellAtEnd(tableView->columns() - 1, tableView->rows() - 1);
+ selectionModel.setCurrentIndex(tableView->modelIndex(cellAtEnd), QItemSelectionModel::NoUpdate);
+ QVERIFY(!tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+
+ tableView->positionViewAtCell(cellAtEnd, QQuickTableView::AlignBottom | QQuickTableView::AlignRight);
+ WAIT_UNTIL_POLISHED;
+ QVERIFY(tableView->itemAtCell(cellAtEnd));
+ QVERIFY(tableView->itemAtCell(cellAtEnd)->property(kCurrent).toBool());
+}
+
+void tst_QQuickTableView::clearSelectionOnTap_data()
+{
+ QTest::addColumn<bool>("selectionEnabled");
+ QTest::newRow("selections enabled") << true;
+ QTest::newRow("selections disabled") << false;
+}
+
+void tst_QQuickTableView::clearSelectionOnTap()
+{
+ // Check that we clear the current selection when tapping
+ // inside TableView. But only if TableView has selections
+ // enabled. Otherwise, TableView should not touch the selection model.
+ QFETCH(bool, selectionEnabled);
+ LOAD_TABLEVIEW("tableviewwithselected2.qml");
+
+ TestModel model(40, 40);
+ tableView->setModel(QVariant::fromValue(&model));
+ if (!selectionEnabled)
+ tableView->setSelectionBehavior(QQuickTableView::SelectionDisabled);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Select root item
+ const auto index = tableView->selectionModel()->model()->index(0, 0);
+ tableView->selectionModel()->select(index, QItemSelectionModel::Select);
+ QCOMPARE(tableView->selectionModel()->selectedIndexes().size(), 1);
+
+ // Click on a cell
+ const auto item = tableView->itemAtIndex(tableView->index(0, 0));
+ QVERIFY(item);
+ QPoint localPos = QPoint(item->width() / 2, item->height() / 2);
+ QPoint pos = item->window()->contentItem()->mapFromItem(item, localPos).toPoint();
+ QTest::mouseClick(item->window(), Qt::LeftButton, Qt::NoModifier, pos);
+
+ QCOMPARE(tableView->selectionModel()->hasSelection(), !selectionEnabled);
+}
+
+void tst_QQuickTableView::moveCurrentIndexUsingArrowKeys()
+{
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(40, 40);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setFocus(true);
+ QQuickWindow *window = tableView->window();
+ const char kCurrent[] = "current";
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that all delegates have current set to false upon start
+ for (auto fxItem : tableViewPrivate->loadedItems)
+ QVERIFY(!fxItem->item->property(kCurrent).toBool());
+
+ QCOMPARE(tableView->currentColumn(), -1);
+ QCOMPARE(tableView->currentRow(), -1);
+
+ // Start by making cell 0, 0 current
+ const QPoint cell0_0(0, 0);
+ selectionModel.setCurrentIndex(tableView->modelIndex(cell0_0), QItemSelectionModel::NoUpdate);
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+
+ // Trying to move the index out of the table with the keys should be a no-op:
+ QTest::keyPress(window, Qt::Key_Left);
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QTest::keyPress(window, Qt::Key_Up);
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+
+ // Move currentIndex right
+ const QPoint cell1_0(1, 0);
+ QTest::keyPress(window, Qt::Key_Right);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell1_0));
+ QVERIFY(!tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QVERIFY(tableView->itemAtCell(cell1_0)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell1_0.x());
+ QCOMPARE(tableView->currentRow(), cell1_0.y());
+
+ // Move currentIndex left
+ QTest::keyPress(window, Qt::Key_Left);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QVERIFY(!tableView->itemAtCell(cell1_0)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+
+ // Move currentIndex down
+ const QPoint cell0_1(0, 1);
+ QTest::keyPress(window, Qt::Key_Down);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_1));
+ QVERIFY(!tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QVERIFY(tableView->itemAtCell(cell0_1)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_1.x());
+ QCOMPARE(tableView->currentRow(), cell0_1.y());
+
+ // Move currentIndex up
+ QTest::keyPress(window, Qt::Key_Up);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QVERIFY(!tableView->itemAtCell(cell0_1)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+}
+
+void tst_QQuickTableView::moveCurrentIndexUsingHomeAndEndKeys()
+{
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(40, 40);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setFocus(true);
+ QQuickWindow *window = tableView->window();
+ const char kCurrent[] = "current";
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that all delegates have current set to false upon start
+ for (auto fxItem : tableViewPrivate->loadedItems)
+ QVERIFY(!fxItem->item->property(kCurrent).toBool());
+
+ QCOMPARE(tableView->currentColumn(), -1);
+ QCOMPARE(tableView->currentRow(), -1);
+
+ const QPoint cell0_0(0, 0);
+ const QPoint cellHorEnd(tableView->columns() - 1, 0);
+
+ // Start by making cell 0, 0 current
+ selectionModel.setCurrentIndex(tableView->modelIndex(cell0_0), QItemSelectionModel::NoUpdate);
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+
+ // Move currentIndex to end
+ QTest::keyPress(window, Qt::Key_End);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cellHorEnd));
+ QTRY_VERIFY(tableView->itemAtCell(cellHorEnd));
+ QVERIFY(tableView->itemAtCell(cellHorEnd)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cellHorEnd.x());
+ QCOMPARE(tableView->currentRow(), cellHorEnd.y());
+
+ // Move currentIndex to end once more is a no-op
+ QTest::keyPress(window, Qt::Key_End);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cellHorEnd));
+ QVERIFY(tableView->itemAtCell(cellHorEnd)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cellHorEnd.x());
+ QCOMPARE(tableView->currentRow(), cellHorEnd.y());
+
+ // Move currentIndex to home
+ QTest::keyPress(window, Qt::Key_Home);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QTRY_VERIFY(tableView->itemAtCell(cell0_0));
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+
+ // Move currentIndex to home once more is a no-op
+ QTest::keyPress(window, Qt::Key_Home);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+}
+
+void tst_QQuickTableView::moveCurrentIndexUsingPageUpDownKeys()
+{
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(40, 40);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setFocus(true);
+ QQuickWindow *window = tableView->window();
+ const char kCurrent[] = "current";
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that all delegates have current set to false upon start
+ for (auto fxItem : tableViewPrivate->loadedItems)
+ QVERIFY(!fxItem->item->property(kCurrent).toBool());
+
+ QCOMPARE(tableView->currentColumn(), -1);
+ QCOMPARE(tableView->currentRow(), -1);
+
+ // Start by making cell 0, 0 current
+ const QPoint cell0_0(0, 0);
+ selectionModel.setCurrentIndex(tableView->modelIndex(cell0_0), QItemSelectionModel::NoUpdate);
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+
+ // Move currentIndex page down
+ const QPoint bottomCell(0, tableView->bottomRow());
+ QTest::keyPress(window, Qt::Key_PageDown);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(bottomCell));
+ QVERIFY(tableView->itemAtCell(cell0_0));
+ QVERIFY(tableView->itemAtCell(bottomCell));
+ QVERIFY(!tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QVERIFY(tableView->itemAtCell(bottomCell)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), bottomCell.x());
+ QCOMPARE(tableView->currentRow(), bottomCell.y());
+
+ // Move currentIndex page up
+ QTest::keyPress(window, Qt::Key_PageUp);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QVERIFY(tableView->itemAtCell(cell0_0));
+ QVERIFY(tableView->itemAtCell(bottomCell));
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QVERIFY(!tableView->itemAtCell(bottomCell)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+
+ // Move currentIndex page down a second. The second time will cause a fast-flick.
+ const QPoint bottomCellPageTwo(0, 38);
+ QTest::keyPress(window, Qt::Key_PageDown);
+ QTest::keyPress(window, Qt::Key_PageDown);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(bottomCellPageTwo));
+ QTRY_VERIFY(tableView->itemAtCell(bottomCellPageTwo));
+ QVERIFY(tableView->itemAtCell(bottomCellPageTwo)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), bottomCellPageTwo.x());
+ QCOMPARE(tableView->currentRow(), bottomCellPageTwo.y());
+
+ // Move currentIndex page down a third time. This will hit the end of the table
+ // before a whole page can be reached.
+ const QPoint cellVerEnd(0, tableView->rows() - 1);
+ QTest::keyPress(window, Qt::Key_PageDown);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cellVerEnd));
+ QTRY_VERIFY(tableView->itemAtCell(cellVerEnd));
+ QVERIFY(tableView->itemAtCell(cellVerEnd)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cellVerEnd.x());
+ QCOMPARE(tableView->currentRow(), cellVerEnd.y());
+
+ // Move currentIndex page down once more is a no-op
+ QTest::keyPress(window, Qt::Key_PageDown);
+ QVERIFY(tableView->itemAtCell(cellVerEnd)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cellVerEnd.x());
+ QCOMPARE(tableView->currentRow(), cellVerEnd.y());
+
+ // Move currentIndex page up
+ const QPoint cellTop1(0, tableView->topRow());
+ QTest::keyPress(window, Qt::Key_PageUp);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cellTop1));
+ QVERIFY(tableView->itemAtCell(cellTop1));
+ QVERIFY(tableView->itemAtCell(cellTop1)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cellTop1.x());
+ QCOMPARE(tableView->currentRow(), cellTop1.y());
+
+ // Move currentIndex page up a second time. This will cause a fast-flick, which
+ // happens to end up on row 1.
+ const QPoint cell0_1(0, 1);
+ QTest::keyPress(window, Qt::Key_PageUp);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_1));
+ QTRY_VERIFY(tableView->itemAtCell(cell0_1));
+ QVERIFY(tableView->itemAtCell(cell0_1)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_1.x());
+ QCOMPARE(tableView->currentRow(), cell0_1.y());
+
+ // Move currentIndex page up a third time. This will bring the table
+ // all the way to the top.
+ QTest::keyPress(window, Qt::Key_PageUp);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QTRY_VERIFY(tableView->itemAtCell(cell0_0));
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+
+ // Move currentIndex page up once more. This will be a no-op.
+ QTest::keyPress(window, Qt::Key_PageUp);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+
+ // Move currentIndex to a cell outside the viewport by accessing the selection
+ // model directly, scroll to it, and check current status.
+ const QPoint cellAtEnd(tableView->columns() - 1, tableView->rows() - 1);
+ selectionModel.setCurrentIndex(tableView->modelIndex(cellAtEnd), QItemSelectionModel::NoUpdate);
+ tableView->positionViewAtCell(cellAtEnd, QQuickTableView::AlignBottom | QQuickTableView::AlignRight);
+ QTRY_VERIFY(tableView->itemAtCell(cellAtEnd));
+ QVERIFY(tableView->itemAtCell(cellAtEnd)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cellAtEnd.x());
+ QCOMPARE(tableView->currentRow(), cellAtEnd.y());
+}
+
+void tst_QQuickTableView::moveCurrentIndexUsingTabKey_data()
+{
+ QTest::addColumn<bool>("hide");
+
+ QTest::newRow("all visible") << false;
+ QTest::newRow("some hidden") << true;
+}
+
+void tst_QQuickTableView::moveCurrentIndexUsingTabKey()
+{
+ QFETCH(bool, hide);
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(5, 6);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setFocus(true);
+ QQuickWindow *window = tableView->window();
+ const char kCurrent[] = "current";
+
+ int lastRow = 4;
+ int lastColumn = 5;
+
+ if (hide) {
+ // Hide last row and column. Those sections should
+ // no longer be taking into account when tabbing.
+ tableView->setRowHeight(lastRow, 0);
+ tableView->setColumnWidth(lastColumn, 0);
+ lastRow--;
+ lastColumn--;
+ }
+
+ WAIT_UNTIL_POLISHED;
+
+ QVERIFY(tableView->activeFocusOnTab());
+
+ QCOMPARE(tableView->currentColumn(), -1);
+ QCOMPARE(tableView->currentRow(), -1);
+
+ // Start by making cell 0, 0 current
+ const QPoint cell0_0(0, 0);
+ selectionModel.setCurrentIndex(tableView->modelIndex(cell0_0), QItemSelectionModel::NoUpdate);
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+
+ // Press Tab
+ const QPoint cell1_0(1, 0);
+ QTest::keyPress(window, Qt::Key_Tab);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell1_0));
+ QVERIFY(!tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QVERIFY(tableView->itemAtCell(cell1_0)->property(kCurrent).toBool());
+
+ // Press Backtab
+ QTest::keyPress(window, Qt::Key_Backtab);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QVERIFY(!tableView->itemAtCell(cell1_0)->property(kCurrent).toBool());
+ QVERIFY(!selectionModel.hasSelection());
+
+ // Press Backtab again. This wraps current index to the
+ // bottom right of the table
+ const QPoint cell_bottomRight(lastColumn, lastRow);
+ QTest::keyPress(window, Qt::Key_Backtab);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell_bottomRight));
+ QVERIFY(!tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QVERIFY(tableView->itemAtCell(cell_bottomRight)->property(kCurrent).toBool());
+ QVERIFY(!selectionModel.hasSelection());
+
+ // Press Tab. This wraps current index back to the 0_0
+ QTest::keyPress(window, Qt::Key_Tab);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QVERIFY(!tableView->itemAtCell(cell_bottomRight)->property(kCurrent).toBool());
+ QVERIFY(!selectionModel.hasSelection());
+
+ // Make 0_1 current, and press Backtab. This should
+ // wrap current index to the last column, but on the row above.
+ const QPoint cell0_1(0, 1);
+ const QPoint cellRightAbove(lastColumn, 0);
+ selectionModel.setCurrentIndex(tableView->modelIndex(cell0_1), QItemSelectionModel::NoUpdate);
+ QVERIFY(!tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QVERIFY(tableView->itemAtCell(cell0_1)->property(kCurrent).toBool());
+ QTest::keyPress(window, Qt::Key_Backtab);
+ QVERIFY(tableView->itemAtCell(cellRightAbove)->property(kCurrent).toBool());
+ QVERIFY(!tableView->itemAtCell(cell0_1)->property(kCurrent).toBool());
+ QVERIFY(!selectionModel.hasSelection());
+
+ // Press Tab. This wraps current index back to 0_1
+ QTest::keyPress(window, Qt::Key_Tab);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_1));
+ QVERIFY(!tableView->itemAtCell(cellRightAbove)->property(kCurrent).toBool());
+ QVERIFY(tableView->itemAtCell(cell0_1)->property(kCurrent).toBool());
+ QVERIFY(!selectionModel.hasSelection());
+}
+
+void tst_QQuickTableView::respectActiveFocusOnTabDisabled()
+{
+ // Ensure that we don't move focus for tab or backtab
+ // when TableView.setActiveFocusOnTab is false.
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(3, 3);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setActiveFocusOnTab(false);
+ tableView->setFocus(true);
+
+ QQuickWindow *window = tableView->window();
+ const char kCurrent[] = "current";
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->currentColumn(), -1);
+ QCOMPARE(tableView->currentRow(), -1);
+ QVERIFY(!tableView->activeFocusOnTab());
+
+ // Start by making cell 0, 0 current
+ const QPoint cell0_0(0, 0);
+ selectionModel.setCurrentIndex(tableView->modelIndex(cell0_0), QItemSelectionModel::NoUpdate);
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+
+ // Press Tab
+ const QPoint cell1_0(1, 0);
+ QTest::keyPress(window, Qt::Key_Tab);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+ QVERIFY(!tableView->itemAtCell(cell1_0)->property(kCurrent).toBool());
+
+ // Press Backtab
+ QTest::keyPress(window, Qt::Key_Backtab);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kCurrent).toBool());
+}
+
+void tst_QQuickTableView::setCurrentIndexOnFirstKeyPress_data()
+{
+ QTest::addColumn<Qt::Key>("arrowKey");
+
+ QTest::newRow("left") << Qt::Key_Left;
+ QTest::newRow("right") << Qt::Key_Right;
+ QTest::newRow("up") << Qt::Key_Up;
+ QTest::newRow("down") << Qt::Key_Down;
+}
+
+void tst_QQuickTableView::setCurrentIndexOnFirstKeyPress()
+{
+ // Check that TableView has focus, but no cell is current, the
+ // first key press on any of the arrow keys will assign the
+ // top left cell to be current.
+ QFETCH(Qt::Key, arrowKey);
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(2, 2);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setFocus(true);
+ QQuickWindow *window = tableView->window();
+ const char kCurrent[] = "current";
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that all delegates have current set to false upon start
+ for (auto fxItem : tableViewPrivate->loadedItems)
+ QVERIFY(!fxItem->item->property(kCurrent).toBool());
+
+ QCOMPARE(tableView->currentColumn(), -1);
+ QCOMPARE(tableView->currentRow(), -1);
+
+ // Pressing a random key, e.g 'a', should not change current index
+ QTest::keyPress(window, Qt::Key_A);
+ QVERIFY(!selectionModel.currentIndex().isValid());
+ QCOMPARE(tableView->currentColumn(), -1);
+ QCOMPARE(tableView->currentRow(), -1);
+
+ // Press the given arrow key
+ const QPoint topLeftCell(0, 0);
+ QTest::keyPress(window, arrowKey);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(topLeftCell));
+ QVERIFY(tableView->itemAtCell(topLeftCell)->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), topLeftCell.x());
+ QCOMPARE(tableView->currentRow(), topLeftCell.y());
+}
+
+void tst_QQuickTableView::setCurrentIndexFromMouse()
+{
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(40, 40);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setFocus(true);
+ QQuickWindow *window = tableView->window();
+ QQuickItem *contentItem = window->contentItem();
+ const char kCurrent[] = "current";
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that all delegates have current set to false upon start
+ for (auto fxItem : tableViewPrivate->loadedItems)
+ QVERIFY(!fxItem->item->property(kCurrent).toBool());
+
+ QCOMPARE(tableView->currentColumn(), -1);
+ QCOMPARE(tableView->currentRow(), -1);
+
+ // Click on cell 0, 0
+ const QPoint cell0_0(0, 0);
+ const auto item0_0 = tableView->itemAtCell(cell0_0);
+ QVERIFY(item0_0);
+ QPoint pos = contentItem->mapFromItem(item0_0, QPointF(5, 5)).toPoint();
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, pos);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell0_0));
+ QVERIFY(item0_0->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+
+ // Click on cell 1, 2
+ const QPoint cell1_2(1, 2);
+ auto item1_2 = tableView->itemAtCell(cell1_2);
+ QVERIFY(item1_2);
+ pos = contentItem->mapFromItem(item1_2, QPointF(5, 5)).toPoint();
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, pos);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell1_2));
+ QVERIFY(!item0_0->property(kCurrent).toBool());
+ QVERIFY(item1_2->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cell1_2.x());
+ QCOMPARE(tableView->currentRow(), cell1_2.y());
+
+ // Position the view at the end of the table, and click on the bottom-right cell
+ const QPoint cellAtEnd(tableView->columns() - 1, tableView->rows() - 1);
+ tableView->positionViewAtCell(cellAtEnd, QQuickTableView::AlignBottom | QQuickTableView::AlignRight);
+ WAIT_UNTIL_POLISHED;
+ auto itemAtEnd = tableView->itemAtCell(cellAtEnd);
+ QVERIFY(itemAtEnd);
+ QVERIFY(!itemAtEnd->property(kCurrent).toBool());
+ pos = contentItem->mapFromItem(itemAtEnd, QPointF(5, 5)).toPoint();
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, pos);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cellAtEnd));
+ QVERIFY(itemAtEnd->property(kCurrent).toBool());
+ QCOMPARE(tableView->currentColumn(), cellAtEnd.x());
+ QCOMPARE(tableView->currentRow(), cellAtEnd.y());
+}
+
+void tst_QQuickTableView::showMarginsWhenNavigatingToEnd()
+{
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ TestModel model(40, 40);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setAnimate(false);
+ tableView->setFocus(true);
+
+ QQuickWindow *window = tableView->window();
+
+ WAIT_UNTIL_POLISHED;
+
+ const qreal margin = 10;
+ tableView->setLeftMargin(margin);
+ tableView->setRightMargin(margin);
+ tableView->setTopMargin(margin);
+ tableView->setBottomMargin(margin);
+
+ selectionModel.setCurrentIndex(tableView->modelIndex(QPoint(1, 1)), QItemSelectionModel::NoUpdate);
+
+ // move to cell 0, 1
+ QCOMPARE(tableView->contentX(), 0);
+ QTest::keyPress(window, Qt::Key_Left);
+ QCOMPARE(tableView->contentX(), -margin);
+
+ // move to cell 0, 0
+ QCOMPARE(tableView->contentY(), 0);
+ QTest::keyPress(window, Qt::Key_Up);
+ QCOMPARE(tableView->contentY(), -margin);
+
+ selectionModel.setCurrentIndex(tableView->modelIndex(QPoint(38, 38)), QItemSelectionModel::NoUpdate);
+ tableView->positionViewAtCell(tableView->cellAtIndex(selectionModel.currentIndex()), QQuickTableView::Contain);
+
+ WAIT_UNTIL_POLISHED;
+
+ // move to cell 39, 38
+ QTest::keyPress(window, Qt::Key_Right);
+ const qreal cellRightEdge = tableViewPrivate->loadedTableOuterRect.right();
+ QCOMPARE(tableView->contentX(), cellRightEdge + margin - tableView->width());
+
+ // move to cell 39, 39
+ QTest::keyPress(window, Qt::Key_Down);
+ const qreal cellBottomEdge = tableViewPrivate->loadedTableOuterRect.bottom();
+ QCOMPARE(tableView->contentY(), cellBottomEdge + margin - tableView->height());
+}
+
+void tst_QQuickTableView::disablePointerNavigation()
+{
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(40, 40);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setFocus(true);
+ tableView->setPointerNavigationEnabled(false);
+ QQuickWindow *window = tableView->window();
+ QQuickItem *contentItem = window->contentItem();
+
+ WAIT_UNTIL_POLISHED;
+
+ QVERIFY(!selectionModel.currentIndex().isValid());
+
+ // Click on cell 0, 0, nothing should happen
+ const QPoint cell0_0(0, 0);
+ const auto item0_0 = tableView->itemAtCell(cell0_0);
+ QVERIFY(item0_0);
+ QPoint pos = contentItem->mapFromItem(item0_0, QPointF(5, 5)).toPoint();
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, pos);
+ QVERIFY(!selectionModel.currentIndex().isValid());
+ QVERIFY(!item0_0->property("current").toBool());
+ QCOMPARE(tableView->currentColumn(), -1);
+ QCOMPARE(tableView->currentRow(), -1);
+
+ // Enable navigation, and try again
+ tableView->setPointerNavigationEnabled(true);
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, pos);
+ QCOMPARE(selectionModel.currentIndex(), tableView->index(0, 0));
+ QVERIFY(item0_0->property("current").toBool());
+ QCOMPARE(tableView->currentColumn(), cell0_0.x());
+ QCOMPARE(tableView->currentRow(), cell0_0.y());
+
+ // Set an invalid current index in the selection model
+ selectionModel.setCurrentIndex(QModelIndex(), QItemSelectionModel::NoUpdate);
+ QVERIFY(!item0_0->property("current").toBool());
+ QCOMPARE(tableView->currentColumn(), -1);
+ QCOMPARE(tableView->currentRow(), -1);
+}
+
+void tst_QQuickTableView::disableKeyNavigation()
+{
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(40, 40);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setKeyNavigationEnabled(false);
+ tableView->setFocus(true);
+ QQuickWindow *window = tableView->window();
+ const char kCurrent[] = "current";
+
+ WAIT_UNTIL_POLISHED;
+
+ // Start by making cell 1, 1 current
+ const QPoint cell1_1(1, 1);
+ selectionModel.setCurrentIndex(tableView->modelIndex(cell1_1), QItemSelectionModel::NoUpdate);
+ QCOMPARE(tableView->itemAtCell(cell1_1)->property(kCurrent).toBool(), true);
+
+ // Try to move currentIndex right by pressing Key_Right. Nothing should happen.
+ const QPoint cell2_1(2, 1);
+ QTest::keyPress(window, Qt::Key_Right);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell1_1));
+ QVERIFY(tableView->itemAtCell(cell1_1)->property(kCurrent).toBool());
+ QVERIFY(!tableView->itemAtCell(cell2_1)->property(kCurrent).toBool());
+
+ // Enable navigation, and try again
+ tableView->setKeyNavigationEnabled(true);
+ QTest::keyPress(window, Qt::Key_Right);
+ QCOMPARE(selectionModel.currentIndex(), tableView->modelIndex(cell2_1));
+ QVERIFY(!tableView->itemAtCell(cell1_1)->property(kCurrent).toBool());
+ QVERIFY(tableView->itemAtCell(cell2_1)->property(kCurrent).toBool());
+}
+
+void tst_QQuickTableView::selectUsingArrowKeys()
+{
+ // Select cells in the view using the keyboard
+ // by going in a square around cell 1, 1
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(40, 40);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setFocus(true);
+ QQuickWindow *window = tableView->window();
+ const char kSelected[] = "selected";
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that all delegates have selected set to false upon start
+ for (auto fxItem : tableViewPrivate->loadedItems)
+ QCOMPARE(fxItem->item->property(kSelected).toBool(), false);
+
+ // Start by making cell 1, 1 current
+ const QPoint cell1_1(1, 1);
+ selectionModel.setCurrentIndex(tableView->modelIndex(cell1_1), QItemSelectionModel::NoUpdate);
+ QCOMPARE(tableView->itemAtCell(cell1_1)->property(kSelected).toBool(), false);
+
+ // Move currentIndex right while holding down shift to select
+ const QPoint cell2_1(2, 1);
+ QTest::keyPress(window, Qt::Key_Right, Qt::ShiftModifier);
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell1_1)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell2_1)));
+ QVERIFY(tableView->itemAtCell(cell1_1)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell2_1)->property(kSelected).toBool());
+
+ // Move currentIndex down while holding down shift to select
+ const QPoint cell2_2(2, 2);
+ const QPoint cell1_2(1, 2);
+ QTest::keyPress(window, Qt::Key_Down, Qt::ShiftModifier);
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell1_1)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell2_1)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell2_2)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell1_2)));
+ QVERIFY(tableView->itemAtCell(cell1_1)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell2_1)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell2_2)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell1_2)->property(kSelected).toBool());
+
+ // Move currentIndex left while holding down shift to select
+ QTest::keyPress(window, Qt::Key_Left, Qt::ShiftModifier);
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell1_1)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell1_2)));
+ QVERIFY(!selectionModel.isSelected(tableView->modelIndex(cell2_1)));
+ QVERIFY(!selectionModel.isSelected(tableView->modelIndex(cell2_2)));
+ QVERIFY(tableView->itemAtCell(cell1_1)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell1_2)->property(kSelected).toBool());
+ QVERIFY(!tableView->itemAtCell(cell2_1)->property(kSelected).toBool());
+ QVERIFY(!tableView->itemAtCell(cell2_2)->property(kSelected).toBool());
+
+ // Move currentIndex left while holding down shift to select
+ const QPoint cell0_1(0, 1);
+ const QPoint cell0_2(0, 2);
+ QTest::keyPress(window, Qt::Key_Left, Qt::ShiftModifier);
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell0_1)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell0_2)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell1_1)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell1_2)));
+ QVERIFY(tableView->itemAtCell(cell0_1)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell0_2)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell1_1)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell1_2)->property(kSelected).toBool());
+
+ // Move currentIndex up while holding down shift to select
+ QTest::keyPress(window, Qt::Key_Up, Qt::ShiftModifier);
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell0_1)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell1_1)));
+ QVERIFY(!selectionModel.isSelected(tableView->modelIndex(cell0_2)));
+ QVERIFY(!selectionModel.isSelected(tableView->modelIndex(cell1_2)));
+ QVERIFY(tableView->itemAtCell(cell0_1)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell1_1)->property(kSelected).toBool());
+ QVERIFY(!tableView->itemAtCell(cell0_2)->property(kSelected).toBool());
+ QVERIFY(!tableView->itemAtCell(cell1_2)->property(kSelected).toBool());
+
+ // Move currentIndex up while holding down shift to select
+ const QPoint cell0_0(0, 0);
+ const QPoint cell1_0(1, 0);
+ QTest::keyPress(window, Qt::Key_Up, Qt::ShiftModifier);
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell0_0)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell0_1)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell1_0)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell1_1)));
+ QVERIFY(tableView->itemAtCell(cell0_0)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell0_1)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell1_0)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell1_1)->property(kSelected).toBool());
+
+ // Move currentIndex right while holding down shift to select
+ QTest::keyPress(window, Qt::Key_Right, Qt::ShiftModifier);
+ QVERIFY(!selectionModel.isSelected(tableView->modelIndex(cell0_0)));
+ QVERIFY(!selectionModel.isSelected(tableView->modelIndex(cell0_1)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell1_0)));
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell1_1)));
+ QVERIFY(!tableView->itemAtCell(cell0_0)->property(kSelected).toBool());
+ QVERIFY(!tableView->itemAtCell(cell0_1)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell1_0)->property(kSelected).toBool());
+ QVERIFY(tableView->itemAtCell(cell1_1)->property(kSelected).toBool());
+
+ // Finally, move currentIndex _without_ shift, which should clear the selection
+ QTest::keyPress(window, Qt::Key_Right);
+ QVERIFY(!selectionModel.isSelected(tableView->modelIndex(cell1_0)));
+ QVERIFY(!selectionModel.isSelected(tableView->modelIndex(cell1_1)));
+ QVERIFY(!tableView->itemAtCell(cell1_0)->property(kSelected).toBool());
+ QVERIFY(!tableView->itemAtCell(cell1_1)->property(kSelected).toBool());
+}
+
+void tst_QQuickTableView::selectUsingHomeAndEndKeys()
+{
+ // Select cells in the view by using the home and end keys
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(4, 40);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setFocus(true);
+ QQuickWindow *window = tableView->window();
+ const char kSelected[] = "selected";
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that all delegates have selected set to false upon start
+ for (auto fxItem : tableViewPrivate->loadedItems)
+ QVERIFY(!fxItem->item->property(kSelected).toBool());
+
+ // Start by making cell 0, 0 current
+ const QPoint cell0_0(0, 0);
+ selectionModel.setCurrentIndex(tableView->modelIndex(cell0_0), QItemSelectionModel::NoUpdate);
+ QVERIFY(!tableView->itemAtCell(cell0_0)->property(kSelected).toBool());
+
+ // Move currentIndex to the end while holding down shift to select
+ const QPoint cellAtHorEnd(tableView->columns() - 1, 0);
+ QTest::keyPress(window, Qt::Key_End, Qt::ShiftModifier);
+ QTRY_VERIFY(tableView->itemAtCell(cellAtHorEnd));
+ for (int c = 0; c <= cellAtHorEnd.x(); ++c) {
+ const QPoint cell(c, cellAtHorEnd.y());
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell)));
+ const QQuickItem *item = tableView->itemAtCell(cell);
+ if (item)
+ QVERIFY(item->property(kSelected).toBool());
+ }
+
+ // Move currentIndex to home while holding down shift to select.
+ // This should result in only the first cell being selected.
+ const QPoint cellAtHome(0, 0);
+ QTest::keyPress(window, Qt::Key_Home, Qt::ShiftModifier);
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cellAtHome)));
+ QTRY_VERIFY(tableView->itemAtCell(cellAtHome));
+ QVERIFY(tableView->itemAtCell(cellAtHome)->property(kSelected).toBool());
+ for (int c = 1; c <= cellAtHorEnd.x(); ++c) {
+ const QPoint cell(c, cellAtHorEnd.y());
+ QVERIFY(!selectionModel.isSelected(tableView->modelIndex(cell)));
+ const QQuickItem *item = tableView->itemAtCell(cell);
+ if (item)
+ QVERIFY(!item->property(kSelected).toBool());
+ }
+
+ // Reverse the test, by starting from cellAtHorEnd
+ selectionModel.setCurrentIndex(tableView->modelIndex(cellAtHorEnd), QItemSelectionModel::Clear);
+ tableView->positionViewAtCell(cellAtHorEnd, QQuickTableView::AlignTop | QQuickTableView::AlignRight);
+ WAIT_UNTIL_POLISHED;
+ QQuickItem *itemAtHorEnd = tableView->itemAtCell(cellAtHorEnd);
+ QVERIFY(itemAtHorEnd);
+ QCOMPARE(itemAtHorEnd->property(kSelected).toBool(), false);
+
+ // Move currentIndex home while holding down shift to select
+ QTest::keyPress(window, Qt::Key_Home, Qt::ShiftModifier);
+ QTRY_VERIFY(tableView->itemAtCell(cellAtHome));
+ for (int c = 0; c <= cellAtHorEnd.x(); ++c) {
+ const QPoint cell(c, cellAtHorEnd.y());
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell)));
+ const QQuickItem *item = tableView->itemAtCell(cell);
+ if (item)
+ QVERIFY(item->property(kSelected).toBool());
+ }
+
+ // Move currentIndex to end while holding down shift to select.
+ // This should result in only cellAtHorEnd being selected.
+ QTest::keyPress(window, Qt::Key_End, Qt::ShiftModifier);
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cellAtHorEnd)));
+ QTRY_VERIFY(tableView->itemAtCell(cellAtHorEnd));
+ QVERIFY(tableView->itemAtCell(cellAtHorEnd)->property(kSelected).toBool());
+ for (int c = 0; c < cellAtHorEnd.x(); ++c) {
+ const QPoint cell(c, cellAtHorEnd.y());
+ QVERIFY(!selectionModel.isSelected(tableView->modelIndex(cell)));
+ const QQuickItem *item = tableView->itemAtCell(cell);
+ if (item)
+ QVERIFY(!item->property(kSelected).toBool());
+ }
+}
+
+void tst_QQuickTableView::selectUsingPageUpDownKeys()
+{
+ // Select cells in the view by using the page up and down keys
+ LOAD_TABLEVIEW("tableviewwithselected1.qml");
+
+ TestModel model(30, 3);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+ tableView->setFocus(true);
+ QQuickWindow *window = tableView->window();
+ const char kSelected[] = "selected";
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that all delegates have selected set to false upon start
+ for (auto fxItem : tableViewPrivate->loadedItems)
+ QVERIFY(!fxItem->item->property(kSelected).toBool());
+
+ // Start by making cell 0, 0 current
+ const QPoint cell0_0(0, 0);
+ selectionModel.setCurrentIndex(tableView->modelIndex(cell0_0), QItemSelectionModel::NoUpdate);
+ QVERIFY(!tableView->itemAtCell(cell0_0)->property(kSelected).toBool());
+
+ // Move currentIndex page down while holding down shift to select
+ const QPoint cellAtBottom(0, tableView->bottomRow());
+ QTest::keyPress(window, Qt::Key_PageDown, Qt::ShiftModifier);
+ QVERIFY(tableView->itemAtCell(cellAtBottom));
+ for (int r = 0; r <= cellAtBottom.y(); ++r) {
+ const QPoint cell(cellAtBottom.x(), r);
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell)));
+ const QQuickItem *item = tableView->itemAtCell(cell);
+ if (item)
+ QVERIFY(item->property(kSelected).toBool());
+ }
+
+ // Move currentIndex page up while holding down shift to select
+ const QPoint cellAtTop(0, 0);
+ QTest::keyPress(window, Qt::Key_PageUp, Qt::ShiftModifier);
+ QVERIFY(tableView->itemAtCell(cellAtTop));
+ QVERIFY(tableView->itemAtCell(cellAtTop)->property(kSelected).toBool());
+ for (int r = 1; r <= cellAtBottom.y(); ++r) {
+ const QPoint cell(cellAtBottom.x(), r);
+ QVERIFY(!selectionModel.isSelected(tableView->modelIndex(cell)));
+ const QQuickItem *item = tableView->itemAtCell(cell);
+ if (item)
+ QVERIFY(!item->property(kSelected).toBool());
+ }
+
+ // Move currentIndex page down twice while holding down shift to select.
+ // This will select all cells in the first column, even the ones that are initially hidden.
+ const QPoint cellAtVerEnd(0, tableView->rows() - 1);
+ QTest::keyPress(window, Qt::Key_PageDown, Qt::ShiftModifier);
+ QTest::keyPress(window, Qt::Key_PageDown, Qt::ShiftModifier);
+ QTRY_VERIFY(tableView->itemAtCell(cellAtVerEnd));
+ QCOMPARE(tableView->bottomRow(), cellAtVerEnd.y());
+ for (int r = 0; r <= cellAtBottom.y(); ++r) {
+ const QPoint cell(cellAtBottom.x(), r);
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell)));
+ const QQuickItem *item = tableView->itemAtCell(cell);
+ if (item)
+ QVERIFY(item->property(kSelected).toBool());
+ }
+
+ // Reverse the test, by starting from cellAtVerEnd
+ selectionModel.clearSelection();
+ QVERIFY(!tableView->itemAtCell(cellAtVerEnd)->property(kSelected).toBool());
+
+ // Move currentIndex page up while holding down shift to select
+ const QPoint cellAtTopRow(0, tableView->topRow());
+ QTest::keyPress(window, Qt::Key_PageUp, Qt::ShiftModifier);
+ QTRY_VERIFY(tableView->itemAtCell(cellAtTopRow));
+ for (int r = cellAtTopRow.y(); r <= cellAtVerEnd.y(); ++r) {
+ const QPoint cell(cellAtBottom.x(), r);
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell)));
+ const QQuickItem *item = tableView->itemAtCell(cell);
+ if (item)
+ QVERIFY(item->property(kSelected).toBool());
+ }
+
+ // Move currentIndex page up once more while holding down shift to select.
+ // This will bring currentIndex to the top.
+ QTest::keyPress(window, Qt::Key_PageUp, Qt::ShiftModifier);
+ QTRY_VERIFY(tableView->itemAtCell(cellAtTop));
+ for (int r = cellAtTop.y(); r <= cellAtVerEnd.y(); ++r) {
+ const QPoint cell(cellAtBottom.x(), r);
+ QVERIFY(selectionModel.isSelected(tableView->modelIndex(cell)));
+ const QQuickItem *item = tableView->itemAtCell(cell);
+ if (item)
+ QVERIFY(item->property(kSelected).toBool());
+ }
+}
+
+void tst_QQuickTableView::testDeprecatedApi()
+{
+ // Check that you can still use Qt.Alignment as second argument
+ // to positionViewAtCell() (for backwards compatibility before Qt 6.4)
+ LOAD_TABLEVIEW("deprecatedapi.qml");
+
+ TestModel model(200, 200);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+
+ WAIT_UNTIL_POLISHED;
+
+ QMetaObject::invokeMethod(tableView, "positionUsingDeprecatedEnum");
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->rightColumn(), model.columnCount() - 1);
+ QCOMPARE(tableView->bottomRow(), model.rowCount() - 1);
+}
+
+void tst_QQuickTableView::alternatingRows()
+{
+ // Check that you can set 'alternate'
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ QVERIFY(tableView->alternatingRows());
+ tableView->setAlternatingRows(false);
+ QVERIFY(!tableView->alternatingRows());
+ tableView->setAlternatingRows(true);
+ QVERIFY(tableView->alternatingRows());
+}
+
+void tst_QQuickTableView::boundDelegateComponent()
+{
+ QQmlEngine engine;
+ const QUrl url(testFileUrl("boundDelegateComponent.qml"));
+ QQmlComponent c(&engine, url);
+ QVERIFY2(c.isReady(), qPrintable(c.errorString()));
+
+ QTest::ignoreMessage(
+ QtWarningMsg, qPrintable(QLatin1String("%1:16: ReferenceError: index is not defined")
+ .arg(url.toString())));
+
+ QScopedPointer<QObject> o(c.create());
+ QVERIFY(!o.isNull());
+
+ QQmlContext *context = qmlContext(o.data());
+
+ QObject *inner = context->objectForName(QLatin1String("tableView"));
+ QVERIFY(inner != nullptr);
+ QQuickTableView *tableView = qobject_cast<QQuickTableView *>(inner);
+ QVERIFY(tableView != nullptr);
+ QObject *item = tableView->itemAtCell({0, 0});
+ QVERIFY(item);
+ QCOMPARE(item->objectName(), QLatin1String("fooouterundefined"));
+
+ QObject *inner2 = context->objectForName(QLatin1String("tableView2"));
+ QVERIFY(inner2 != nullptr);
+ QQuickTableView *tableView2 = qobject_cast<QQuickTableView *>(inner2);
+ QVERIFY(tableView2 != nullptr);
+ QObject *item2 = tableView2->itemAtCell({0, 0});
+ QVERIFY(item2);
+ QCOMPARE(item2->objectName(), QLatin1String("fooouter0"));
+
+ QQmlComponent *comp = qobject_cast<QQmlComponent *>(
+ context->objectForName(QLatin1String("outerComponent")));
+ QVERIFY(comp != nullptr);
+
+ for (int i = 0; i < 3 * 2; ++i) {
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ qPrintable(QLatin1String("%1:54:21: ReferenceError: model is not defined")
+ .arg(url.toString())));
+ }
+
+ QScopedPointer<QObject> outerItem(comp->create(context));
+ QVERIFY(!outerItem.isNull());
+ QQuickTableView *innerTableView = qobject_cast<QQuickTableView *>(
+ qmlContext(outerItem.data())->objectForName(QLatin1String("innerTableView")));
+ QVERIFY(innerTableView != nullptr);
+ QCOMPARE(innerTableView->rows(), 3);
+ for (int i = 0; i < 3; ++i)
+ QVERIFY(innerTableView->itemAtIndex(innerTableView->index(i, 0))->objectName().isEmpty());
+}
+
+void tst_QQuickTableView::setColumnWidth_data()
+{
+ QTest::addColumn<int>("columnCount");
+ QTest::addColumn<int>("column");
+ QTest::addColumn<qreal>("size");
+
+ QTest::newRow("first column") << 5 << 0 << 10.;
+ QTest::newRow("second column") << 5 << 2 << 10.;
+ QTest::newRow("a hidden column") << 20 << 19 << 10.;
+ QTest::newRow("a column outside model") << 1 << 5 << 10.;
+}
+
+void tst_QQuickTableView::setColumnWidth()
+{
+ // Test that you can set the width of a column explicitly
+ QFETCH(int, columnCount);
+ QFETCH(int, column);
+ QFETCH(qreal, size);
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(2, columnCount);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ tableView->setColumnWidth(column, size);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitColumnWidth(column), size);
+ if (tableView->isColumnLoaded(column))
+ QCOMPARE(tableView->columnWidth(column), size);
+ else
+ QCOMPARE(tableView->columnWidth(column), -1);
+}
+
+
+void tst_QQuickTableView::setColumnWidthWhenProviderIsSet()
+{
+ // Test that explicitly set column widths will be
+ // ignored if a columnWidthProvider is set
+ LOAD_TABLEVIEW("userowcolumnprovider.qml");
+
+ auto model = TestModelAsVariant(5, 5);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ tableView->setColumnWidth(1, 100);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitColumnWidth(1), 100);
+ QCOMPARE(tableView->columnWidth(1), 11);
+}
+
+void tst_QQuickTableView::setColumnWidthForInvalidColumn()
+{
+ // Check that you cannot set a column width for
+ // a negative column index.
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(5, 5);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*column must be greather than, or equal to, zero"));
+ tableView->setColumnWidth(-1, 10);
+
+ QCOMPARE(tableView->explicitColumnWidth(-1), -1);
+ QCOMPARE(tableView->columnWidth(-1), -1);
+}
+
+void tst_QQuickTableView::setColumnWidthWhenUsingSyncView()
+{
+ // Test that if you set an explicit column width on a TableView
+ // that has a sync view, then we set the column width on the
+ // sync view instead.
+ LOAD_TABLEVIEW("syncviewsimple.qml");
+ GET_QML_TABLEVIEW(tableViewH);
+ GET_QML_TABLEVIEW(tableViewHV);
+
+ const auto model = TestModelAsVariant(3, 3);
+ QQuickTableView *views[] = {tableView, tableViewH, tableViewHV};
+ for (auto view : views)
+ view->setModel(model);
+
+ const int column = 1;
+ const qreal size = 200;
+
+ tableView->setColumnWidthProvider(QJSValue());
+ tableViewH->setColumnWidth(column, size);
+
+ WAIT_UNTIL_POLISHED;
+
+ for (auto view : views) {
+ QCOMPARE(view->explicitColumnWidth(column), size);
+ QCOMPARE(view->columnWidth(column), size);
+ }
+}
+
+void tst_QQuickTableView::resetColumnWidth()
+{
+ // Check that you can reset a column width
+ // by setting its width to -1
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(5, 5);
+ tableView->setModel(model);
+
+ const int column = 1;
+ const qreal size = 10.;
+ const qreal defaultSize = 100.;
+
+ WAIT_UNTIL_POLISHED;
+
+ tableView->setColumnWidth(column, size);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitColumnWidth(column), size);
+ QCOMPARE(tableView->columnWidth(column), size);
+
+ tableView->setColumnWidth(column, -1);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitColumnWidth(column), -1);
+ QCOMPARE(tableView->columnWidth(column), defaultSize);
+}
+
+void tst_QQuickTableView::clearColumnWidths()
+{
+ // Check that clearColumnWidths() works as documented
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(5, 5);
+ tableView->setModel(model);
+
+ const qreal defaultSize = 100.;
+
+ WAIT_UNTIL_POLISHED;
+
+ tableView->setColumnWidth(0, 10);
+ tableView->setColumnWidth(1, 20);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitColumnWidth(0), 10);
+ QCOMPARE(tableView->columnWidth(0), 10);
+ QCOMPARE(tableView->explicitColumnWidth(1), 20);
+ QCOMPARE(tableView->columnWidth(1), 20);
+
+ tableView->clearColumnWidths();
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitColumnWidth(0), -1);
+ QCOMPARE(tableView->columnWidth(0), defaultSize);
+ QCOMPARE(tableView->explicitColumnWidth(1), -1);
+ QCOMPARE(tableView->columnWidth(1), defaultSize);
+}
+
+void tst_QQuickTableView::setRowHeight_data()
+{
+ QTest::addColumn<int>("rowCount");
+ QTest::addColumn<int>("row");
+ QTest::addColumn<qreal>("size");
+
+ QTest::newRow("first row") << 5 << 0 << 10.;
+ QTest::newRow("second row") << 5 << 2 << 10.;
+ QTest::newRow("a hidden row") << 20 << 19 << 10.;
+ QTest::newRow("a row outside model") << 1 << 5 << 10.;
+}
+
+void tst_QQuickTableView::setRowHeight()
+{
+ // Test that you can set the height of a row explicitly
+ QFETCH(int, rowCount);
+ QFETCH(int, row);
+ QFETCH(qreal, size);
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(rowCount, 2);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ tableView->setRowHeight(row, size);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitRowHeight(row), size);
+ if (tableView->isRowLoaded(row))
+ QCOMPARE(tableView->rowHeight(row), size);
+ else
+ QCOMPARE(tableView->rowHeight(row), -1);
+}
+
+void tst_QQuickTableView::setRowHeightWhenProviderIsSet()
+{
+ // Test that explicitly set row heights will be
+ // ignored if a rowHeightProvider is set
+ LOAD_TABLEVIEW("userowcolumnprovider.qml");
+
+ auto model = TestModelAsVariant(5, 5);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ tableView->setRowHeight(1, 100);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitRowHeight(1), 100);
+ QCOMPARE(tableView->rowHeight(1), 11);
+}
+
+void tst_QQuickTableView::setRowHeightForInvalidRow()
+{
+ // Check that you cannot set a row height for
+ // a negative row index.
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(5, 5);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*row must be greather than, or equal to, zero"));
+ tableView->setRowHeight(-1, 10);
+
+ QCOMPARE(tableView->explicitRowHeight(-1), -1);
+ QCOMPARE(tableView->rowHeight(-1), -1);
+}
+
+void tst_QQuickTableView::setRowHeightWhenUsingSyncView()
+{
+ // Test that if you set an explicit row height on a TableView
+ // that has a sync view, then we set the column width on the
+ // sync view instead.
+ LOAD_TABLEVIEW("syncviewsimple.qml");
+ GET_QML_TABLEVIEW(tableViewV);
+ GET_QML_TABLEVIEW(tableViewHV);
+
+ const auto model = TestModelAsVariant(3, 3);
+ QQuickTableView *views[] = {tableView, tableViewV, tableViewHV};
+ for (auto view : views)
+ view->setModel(model);
+
+ const int row = 1;
+ const qreal size = 200;
+
+ tableView->setRowHeightProvider(QJSValue());
+ tableViewV->setRowHeight(row, size);
+
+ WAIT_UNTIL_POLISHED;
+
+ for (auto view : views) {
+ QCOMPARE(view->explicitRowHeight(row), size);
+ QCOMPARE(view->rowHeight(row), size);
+ }
+}
+
+void tst_QQuickTableView::resetRowHeight()
+{
+ // Check that you can reset a row height
+ // by setting its width to -1
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(5, 5);
+ tableView->setModel(model);
+
+ const int row = 1;
+ const qreal size = 10.;
+ const qreal defaultSize = 50.;
+
+ WAIT_UNTIL_POLISHED;
+
+ tableView->setRowHeight(row, size);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitRowHeight(row), size);
+ QCOMPARE(tableView->rowHeight(row), size);
+
+ tableView->setRowHeight(row, -1);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitRowHeight(row), -1);
+ QCOMPARE(tableView->rowHeight(row), defaultSize);
+}
+
+void tst_QQuickTableView::clearRowHeights()
+{
+ // Check that clearRowHeights() works as documented
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(5, 5);
+ tableView->setModel(model);
+
+ const qreal defaultSize = 50.;
+
+ WAIT_UNTIL_POLISHED;
+
+ tableView->setRowHeight(0, 10);
+ tableView->setRowHeight(1, 20);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitRowHeight(0), 10);
+ QCOMPARE(tableView->rowHeight(0), 10);
+ QCOMPARE(tableView->explicitRowHeight(1), 20);
+ QCOMPARE(tableView->rowHeight(1), 20);
+
+ tableView->clearRowHeights();
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitRowHeight(0), -1);
+ QCOMPARE(tableView->rowHeight(0), defaultSize);
+ QCOMPARE(tableView->explicitRowHeight(1), -1);
+ QCOMPARE(tableView->rowHeight(1), defaultSize);
+}
+
+void tst_QQuickTableView::deletedDelegate()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("deletedDelegate.qml"));
+ std::unique_ptr<QObject> root(component.create());
+ QVERIFY(root);
+ auto tv = root->findChild<QQuickTableView *>("tableview");
+ QVERIFY(tv);
+ // we need one event loop iteration for the deferred delete to trigger
+ // thus the QTRY_VERIFY
+ QTRY_COMPARE(tv->delegate(), nullptr);
+}
+
+void tst_QQuickTableView::tableViewInteractive()
+{
+ LOAD_TABLEVIEW("tableviewinteractive.qml");
+
+ auto *root = view->rootObject();
+ QVERIFY(root);
+ auto *window = root->window();
+ QVERIFY(window);
+
+ int eventCount = root->property("eventCount").toInt();
+ QCOMPARE(eventCount, 0);
+
+ // Event though we make 'interactive' as false, the TableView has
+ // pointerNacigationEnabled set as true by default, which allows it to consume
+ // mouse events and thus, eventCount still be zero
+ tableView->setInteractive(false);
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 100));
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 100));
+ eventCount = root->property("eventCount").toInt();
+ QCOMPARE(eventCount, 0);
+
+ // Making both 'interactive' and 'pointerNavigationEnabled' as false, doesn't
+ // allow TableView (and its parent Flickable) to consume mouse event and it
+ // passes to the below visual item
+ tableView->setInteractive(false);
+ tableView->setPointerNavigationEnabled(false);
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 100));
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 100));
+ eventCount = root->property("eventCount").toInt();
+ QCOMPARE(eventCount, 1);
+
+ // Making 'interactive' as true and 'pointerNavigationEnabled' as false,
+ // allows parent of TableView (i.e. Flickable) to consume mouse events
+ tableView->setInteractive(true);
+ tableView->setPointerNavigationEnabled(false);
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 100));
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(100, 100));
+ eventCount = root->property("eventCount").toInt();
+ QCOMPARE(eventCount, 1);
+}
+
+void tst_QQuickTableView::columnResizing_data()
+{
+ QTest::addColumn<int>("column");
+ QTest::addColumn<bool>("pointerNavigationEnabled");
+
+ QTest::newRow("first") << 0 << true;
+ QTest::newRow("middle") << 1 << true;
+ QTest::newRow("middle") << 1 << false;
+ QTest::newRow("last") << 2 << true;
+}
+
+void tst_QQuickTableView::columnResizing()
+{
+ // Check that the user can drag on the horizontal
+ // end of a cell to resize the whole column.
+ QFETCH(int, column);
+ QFETCH(bool, pointerNavigationEnabled);
+ LOAD_TABLEVIEW("tableviewwithselected2.qml");
+
+ auto model = TestModelAsVariant(3, 3);
+ tableView->setModel(model);
+ tableView->setResizableColumns(true);
+ // Resizing column should not be affected by pointerNavigationEnabled
+ // (since it is controller by its own property).
+ tableView->setPointerNavigationEnabled(pointerNavigationEnabled);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitColumnWidth(column), -1);
+
+ // A resize shouldn't also change the current index or start a selection.
+ QSignalSpy currentIndexSpy(tableView->selectionModel(), &QItemSelectionModel::currentChanged);
+ QSignalSpy selectionSpy(tableView->selectionModel(), &QItemSelectionModel::selectionChanged);
+
+ const auto item = tableView->itemAtIndex(tableView->index(0, column));
+ QQuickWindow *window = item->window();
+
+ const qreal columnStartWidth = tableView->columnWidth(column);
+ const QPoint localPos = QPoint(item->width(), item->height() / 2);
+ const QPoint startPos = window->contentItem()->mapFromItem(item, localPos).toPoint();
+ const QPoint startDragDist = QPoint(qApp->styleHints()->startDragDistance() + 1, 0);
+ const QPoint dragLength(100, 0);
+
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, startPos);
+ QTest::mouseMove(window, startPos + startDragDist);
+ QTest::mouseMove(window, startPos + dragLength);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, startPos + dragLength);
+
+ const qreal newColumnWidth = columnStartWidth + dragLength.x() - startDragDist.x();
+ QCOMPARE(tableView->explicitColumnWidth(column), newColumnWidth);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(tableView->columnWidth(column), newColumnWidth);
+
+ QCOMPARE(currentIndexSpy.count(), 0);
+ QCOMPARE(selectionSpy.count(), 0);
+}
+
+void tst_QQuickTableView::rowResizing_data()
+{
+ QTest::addColumn<int>("row");
+
+ QTest::newRow("first") << 0;
+ QTest::newRow("middle") << 1;
+ QTest::newRow("last") << 2;
+}
+
+void tst_QQuickTableView::rowResizing()
+{
+ // Check that the user can drag on the vertical
+ // end of a cell to resize the whole row.
+ QFETCH(int, row);
+ LOAD_TABLEVIEW("tableviewwithselected2.qml");
+
+ auto model = TestModelAsVariant(3, 3);
+ tableView->setModel(model);
+ tableView->setResizableRows(true);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitRowHeight(row), -1);
+
+ // A resize shouldn't also change the current index or start a selection.
+ QSignalSpy currentIndexSpy(tableView->selectionModel(), &QItemSelectionModel::currentChanged);
+ QSignalSpy selectionSpy(tableView->selectionModel(), &QItemSelectionModel::selectionChanged);
+
+ const auto item = tableView->itemAtIndex(tableView->index(row, 0));
+ QQuickWindow *window = item->window();
+
+ const qreal rowStartHeight = tableView->rowHeight(row);
+ const QPoint localPos = QPoint(item->width() / 2, item->height());
+ const QPoint startPos = window->contentItem()->mapFromItem(item, localPos).toPoint();
+ const QPoint startDragDist = QPoint(0, qApp->styleHints()->startDragDistance() + 1);
+ const QPoint dragLength(0, 100);
+
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, startPos);
+ QTest::mouseMove(window, startPos + startDragDist);
+ QTest::mouseMove(window, startPos + dragLength);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, startPos + dragLength);
+
+ const qreal newRowHeight = rowStartHeight + dragLength.y() - startDragDist.y();
+ QCOMPARE(tableView->explicitRowHeight(row), newRowHeight);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(tableView->rowHeight(row), newRowHeight);
+
+ QCOMPARE(currentIndexSpy.count(), 0);
+ QCOMPARE(selectionSpy.count(), 0);
+}
+
+void tst_QQuickTableView::rowAndColumnResizing_data()
+{
+ QTest::addColumn<int>("rowAndColumn");
+ QTest::addColumn<bool>("addDelegateDragHandler");
+
+ QTest::newRow("first") << 0 << false;
+ QTest::newRow("middle") << 1 << false;
+ QTest::newRow("last") << 2 << false;
+
+ QTest::newRow("first, addDelegateDragHandler") << 0 << true;
+}
+
+void tst_QQuickTableView::rowAndColumnResizing()
+{
+ // Check that the user can drag in the corner of a cell
+ // to resize both the row and the column at the same time.
+ QFETCH(int, rowAndColumn);
+ QFETCH(bool, addDelegateDragHandler);
+ LOAD_TABLEVIEW("tableviewwithselected2.qml");
+
+ auto model = TestModelAsVariant(3, 3);
+ tableView->setModel(model);
+ tableView->setResizableColumns(true);
+ tableView->setResizableRows(true);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->explicitColumnWidth(rowAndColumn), -1);
+ QCOMPARE(tableView->explicitRowHeight(rowAndColumn), -1);
+
+ const auto item = tableView->itemAtIndex(tableView->index(rowAndColumn, rowAndColumn));
+ QVERIFY(item);
+
+ if (addDelegateDragHandler) {
+ // Check that the grab permissions set on the resize handler
+ // allows you to add an ordinary drag handler to a delegate
+ // without blocking the resize handler.
+ new QQuickDragHandler(item);
+ }
+
+ QQuickWindow *window = item->window();
+
+ const qreal columnStartWidth = tableView->columnWidth(rowAndColumn);
+ const qreal rowStartHeight = tableView->rowHeight(rowAndColumn);
+
+ const QPoint localPos = QPoint(item->width(), item->height());
+ const QPoint startPos = window->contentItem()->mapFromItem(item, localPos).toPoint();
+ const qreal startDist = qApp->styleHints()->startDragDistance();
+ const QPoint startDragDist = QPoint(startDist + 1, startDist + 1);
+ const QPoint dragLength(100, 100);
+
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, startPos);
+ QTest::mouseMove(window, startPos + startDragDist);
+ QTest::mouseMove(window, startPos + dragLength);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, startPos + dragLength);
+
+ const qreal newColumnWidth = columnStartWidth + dragLength.x() - startDragDist.x();
+ const qreal newRowHeight = rowStartHeight + dragLength.y() - startDragDist.y();
+ QCOMPARE(tableView->explicitColumnWidth(rowAndColumn), newColumnWidth);
+ QCOMPARE(tableView->explicitRowHeight(rowAndColumn), newRowHeight);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(tableView->columnWidth(rowAndColumn), newColumnWidth);
+ QCOMPARE(tableView->rowHeight(rowAndColumn), newRowHeight);
+
+ // A resize shouldn't also change the current index
+ QVERIFY(!tableView->selectionModel()->currentIndex().isValid());
+}
+
+void tst_QQuickTableView::columnResizingDisabled()
+{
+ // Check that the user cannot drag on the horizontal end of a cell
+ // to resize a column if not resizableColumns is enabled.
+ // In that case, a drag should drag the flickable instead.
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(3, 3);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->contentY(), 0);
+
+ const int row = 1;
+ QCOMPARE(tableView->explicitRowHeight(row), -1);
+
+ const auto item = tableView->itemAtIndex(tableView->index(row, 0));
+ QQuickWindow *window = item->window();
+
+ const QPoint localPos = QPoint(item->width() / 2, item->height());
+ const QPoint startPos = window->contentItem()->mapFromItem(item, localPos).toPoint();
+ const QPoint startDragDist = QPoint(0, qApp->styleHints()->startDragDistance() + 1);
+ const QPoint dragLength(0, 100);
+
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, startPos);
+ QTest::mouseMove(window, startPos + startDragDist);
+ QTest::mouseMove(window, startPos + dragLength);
+ QTest::mouseMove(window, startPos + (dragLength * 2));
+ QVERIFY(tableView->contentY() < 0);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, startPos + dragLength);
+
+ QVERIFY(!QQuickTest::qIsPolishScheduled(item));
+ QCOMPARE(tableView->explicitRowHeight(row), -1);
+ QCOMPARE(tableView->rowHeight(row), 50);
+}
+
+void tst_QQuickTableView::rowResizingDisabled()
+{
+ // Check that the user cannot drag on the vertical end of a cell to
+ // resize a row if not resizableRows is enabled.
+ // In that case, a drag should drag the flickable instead.
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(3, 3);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->contentY(), 0);
+
+ const int row = 1;
+ QCOMPARE(tableView->explicitRowHeight(row), -1);
+
+ const auto item = tableView->itemAtIndex(tableView->index(row, 0));
+ QQuickWindow *window = item->window();
+
+ const QPoint localPos = QPoint(item->width() / 2, item->height());
+ const QPoint startPos = window->contentItem()->mapFromItem(item, localPos).toPoint();
+ const QPoint startDragDist = QPoint(0, qApp->styleHints()->startDragDistance() + 1);
+ const QPoint dragLength(0, 100);
+
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, startPos);
+ QTest::mouseMove(window, startPos + startDragDist);
+ QTest::mouseMove(window, startPos + dragLength);
+ QTest::mouseMove(window, startPos + (dragLength * 2));
+ QVERIFY(tableView->contentY() < 0);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, startPos + dragLength);
+
+ QVERIFY(!QQuickTest::qIsPolishScheduled(item));
+ QCOMPARE(tableView->explicitRowHeight(row), -1);
+ QCOMPARE(tableView->rowHeight(row), 50);
+}
+
+void tst_QQuickTableView::dragFromCellCenter()
+{
+ // Check that the user cannot resize a row (or column) by dragging
+ // from the center of a cell. In that case, a drag should
+ // drag the flickable instead.
+ LOAD_TABLEVIEW("plaintableview.qml");
+
+ auto model = TestModelAsVariant(3, 3);
+ tableView->setModel(model);
+ tableView->setResizableRows(true);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(tableView->contentY(), 0);
+
+ const int row = 1;
+ QCOMPARE(tableView->explicitRowHeight(row), -1);
+
+ const auto item = tableView->itemAtIndex(tableView->index(row, 0));
+ QQuickWindow *window = item->window();
+
+ const QPoint localPos = QPoint(item->width() / 2, item->height() / 2);
+ const QPoint startPos = window->contentItem()->mapFromItem(item, localPos).toPoint();
+ const QPoint startDragDist = QPoint(0, qApp->styleHints()->startDragDistance() + 1);
+ const QPoint dragLength(0, 100);
+
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, startPos);
+ QTest::mouseMove(window, startPos + startDragDist);
+ QTest::mouseMove(window, startPos + dragLength);
+ QTest::mouseMove(window, startPos + (dragLength * 2));
+ QVERIFY(tableView->contentY() < 0);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, startPos + dragLength);
+
+ QVERIFY(!QQuickTest::qIsPolishScheduled(item));
+ QCOMPARE(tableView->explicitRowHeight(row), -1);
+ QCOMPARE(tableView->rowHeight(row), 50);
+}
+
+void tst_QQuickTableView::tapOnResizeArea_data()
+{
+ QTest::addColumn<bool>("resizableRows");
+ QTest::addColumn<bool>("resizableColumns");
+ QTest::addColumn<bool>("interactive");
+
+ for (bool interactive : {true, false}) {
+ QTest::newRow("resize disabled") << false << false << interactive;
+ QTest::newRow("resizableRows") << true << false << interactive;
+ QTest::newRow("resizableColumns") << false << true << interactive;
+ QTest::newRow("resizableRows && resizableColumns") << true << true << interactive;
+ }
+}
+
+void tst_QQuickTableView::tapOnResizeArea()
+{
+ // Check that if a tap or a press happens on the resize area between the
+ // cells, we only change the current index if the resizing is disabled.
+ QFETCH(bool, resizableRows);
+ QFETCH(bool, resizableColumns);
+ QFETCH(bool, interactive);
+ LOAD_TABLEVIEW("tableviewwithselected2.qml");
+
+ auto model = TestModel(3, 3);
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setResizableRows(resizableRows);
+ tableView->setResizableColumns(resizableColumns);
+ tableView->setInteractive(interactive);
+ tableView->setPointerNavigationEnabled(true);
+
+ WAIT_UNTIL_POLISHED;
+
+ const QPoint cell(1, 1);
+ const auto item = tableView->itemAtCell(cell);
+ QQuickWindow *window = item->window();
+
+ const QPoint localPos = QPoint(item->width() - 1, item->height() - 1);
+ const QPoint tapPos = window->contentItem()->mapFromItem(item, localPos).toPoint();
+
+ // Start by moving the mouse out of the way
+ QTest::mouseMove(window, tapPos + QPoint(200, 200));
+ // Then do a tap on the resize area
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, tapPos);
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, tapPos);
+
+ if (resizableRows || resizableColumns)
+ QVERIFY(!tableView->selectionModel()->currentIndex().isValid());
+ else
+ QCOMPARE(tableView->selectionModel()->currentIndex(), model.index(1, 1));
+}
+
+void tst_QQuickTableView::editUsingEditTriggers_data()
+{
+ QTest::addColumn<QQuickTableView::EditTriggers>("editTriggers");
+ QTest::addColumn<bool>("interactive");
+
+ // We need to test both with and without interactive, since SingleTapped
+ // actions will happen already on press in a TableView that is not interactive!
+ for (bool interactive : {true, false}) {
+ QTest::newRow("NoEditTriggers") << QQuickTableView::EditTriggers(QQuickTableView::NoEditTriggers) << interactive;
+ QTest::newRow("SingleTapped") << QQuickTableView::EditTriggers(QQuickTableView::SingleTapped) << interactive;
+ QTest::newRow("DoubleTapped") << QQuickTableView::EditTriggers(QQuickTableView::DoubleTapped) << interactive;
+ QTest::newRow("SelectedTapped") << QQuickTableView::EditTriggers(QQuickTableView::SelectedTapped) << interactive;
+ QTest::newRow("EditKeyPressed") << QQuickTableView::EditTriggers(QQuickTableView::EditKeyPressed) << interactive;
+ QTest::newRow("AnyKeyPressed") << QQuickTableView::EditTriggers(QQuickTableView::EditKeyPressed) << interactive;
+ QTest::newRow("DoubleTapped | EditKeyPressed")
+ << QQuickTableView::EditTriggers(QQuickTableView::DoubleTapped | QQuickTableView::EditKeyPressed) << interactive;
+ QTest::newRow("SingleTapped | AnyKeyPressed")
+ << QQuickTableView::EditTriggers(QQuickTableView::SingleTapped | QQuickTableView::AnyKeyPressed) << interactive;
+ }
+}
+
+void tst_QQuickTableView::editUsingEditTriggers()
+{
+ // Check that you can start to edit in TableView
+ // using the available edit triggers.
+ QFETCH(QQuickTableView::EditTriggers, editTriggers);
+ QFETCH(bool, interactive);
+ LOAD_TABLEVIEW("editdelegate.qml");
+
+ auto model = TestModel(4, 4);
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setInteractive(interactive);
+ tableView->forceActiveFocus();
+
+ QCOMPARE(tableView->editTriggers(), QQuickTableView::DoubleTapped | QQuickTableView::EditKeyPressed);
+ tableView->setEditTriggers(editTriggers);
+
+ const char kEditItem[] = "editItem";
+ const char kEditIndex[] = "editIndex";
+
+ WAIT_UNTIL_POLISHED;
+
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+
+ const QPoint cell1(1, 1);
+ const QPoint cell2(2, 1);
+ const QModelIndex index1 = tableView->modelIndex(cell1);
+ const QModelIndex index2 = tableView->modelIndex(cell2);
+ const auto item1 = tableView->itemAtCell(cell1);
+ const auto item2 = tableView->itemAtCell(cell2);
+ QVERIFY(item1);
+ QVERIFY(item2);
+
+ QQuickWindow *window = tableView->window();
+
+ const QPoint localPos = QPoint(item1->width() - 1, item1->height() - 1);
+ const QPoint localPosOutside = QPoint(tableView->contentWidth() + 10, tableView->contentHeight() + 10);
+ const QPoint tapPos1 = window->contentItem()->mapFromItem(item1, localPos).toPoint();
+ const QPoint tapPos2 = window->contentItem()->mapFromItem(item2, localPos).toPoint();
+ const QPoint tapOutsideContentItem = window->contentItem()->mapFromItem(item2, localPosOutside).toPoint();
+
+ if (editTriggers & QQuickTableView::SingleTapped) {
+ // edit cell 1
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos1);
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index1);
+ const auto editItem1 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem1);
+ QVERIFY(editItem1->hasActiveFocus());
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index1);
+
+ // edit cell 2 (without closing the previous edit session first)
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos2);
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index2);
+ const auto editItem2 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem2);
+ QVERIFY(editItem2->hasActiveFocus());
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index2);
+
+ // single tap outside content item should close the editor
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapOutsideContentItem);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index2);
+ }
+
+ if (editTriggers & QQuickTableView::DoubleTapped) {
+ // edit cell 1
+ QTest::mouseDClick(window, Qt::LeftButton, Qt::NoModifier, tapPos1);
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index1);
+ const auto editItem1 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem1);
+ QVERIFY(editItem1->hasActiveFocus());
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index1);
+
+ // edit cell 2 (without closing the previous edit session first)
+ QTest::mouseDClick(window, Qt::LeftButton, Qt::NoModifier, tapPos2);
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index2);
+ const auto editItem2 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem2);
+ QVERIFY(editItem2->hasActiveFocus());
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index2);
+
+ // single tap outside the edit item should close the editor
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos1);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index1);
+
+ if (!(editTriggers & QQuickTableView::SingleTapped)) {
+ // single tap on a cell should not open the editor
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos1);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ // single tap outside content item should make sure editing ends
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapOutsideContentItem);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers & QQuickTableView::SelectedTapped) {
+ // select cell first, then tap on it
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::Select);
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos1);
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index1);
+ const auto editItem1 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem1);
+ QVERIFY(editItem1->hasActiveFocus());
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index1);
+
+ // tap on a non-selected cell. This should close the editor, and move
+ // the current index, but not begin to edit the cell.
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos2);
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index2);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+
+ // tap on a non-selected cell while no editor is active
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::NoUpdate);
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos2);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index2);
+
+ // tap on the current cell. This alone should not start an edit (unless it's also selected)
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos1);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers & QQuickTableView::EditKeyPressed) {
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::NoUpdate);
+ QTest::keyClick(window, Qt::Key_Return);
+ const auto editItem1 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem1);
+ QVERIFY(editItem1->hasActiveFocus());
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index1);
+
+ // Pressing escape should close the editor
+ QTest::keyClick(window, Qt::Key_Escape);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index1);
+
+ // Pressing Enter to open the editor again
+ QTest::keyClick(window, Qt::Key_Enter);
+ const auto editItem2 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem2);
+ QVERIFY(editItem2->hasActiveFocus());
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index1);
+
+ // single tap outside the edit item should close the editor
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos2);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers & QQuickTableView::AnyKeyPressed) {
+ // Pressing key x should start to edit. And in case of AnyKeyPressed, we
+ // also replay the key event to the focus object.
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::NoUpdate);
+ QTest::keyClick(window, Qt::Key_X);
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index1);
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index1);
+ auto textInput1 = tableView->property(kEditItem).value<QQuickTextInput *>();
+ QVERIFY(textInput1);
+ QVERIFY(textInput1->hasActiveFocus());
+ QCOMPARE(textInput1->text(), "x");
+
+ // Pressing escape should close the editor
+ QTest::keyClick(window, Qt::Key_Escape);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index1);
+
+ // Pressing a modifier key alone should not open the editor
+ QTest::keyClick(window, Qt::Key_Shift);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QTest::keyClick(window, Qt::Key_Control);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QTest::keyClick(window, Qt::Key_Alt);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QTest::keyClick(window, Qt::Key_Meta);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+
+ // Pressing enter should also start to edit. But this is a
+ // special case, we don't replay enter into the focus object.
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::NoUpdate);
+ QTest::keyClick(window, Qt::Key_Enter);
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index1);
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index1);
+ auto textInput2 = tableView->property(kEditItem).value<QQuickTextInput *>();
+ QVERIFY(textInput2);
+ QVERIFY(textInput2->hasActiveFocus());
+ QCOMPARE(textInput2->text(), "1");
+
+ if (!(editTriggers & QQuickTableView::SingleTapped)) {
+ // single tap outside the edit item should close the editor
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos2);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ // single tap outside content item should make sure editing ends
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapOutsideContentItem);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers == QQuickTableView::NoEditTriggers) {
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos1);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QTest::mouseDClick(window, Qt::LeftButton, Qt::NoModifier, tapPos1);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::NoUpdate);
+ QTest::keyClick(window, Qt::Key_Return);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QTest::keyClick(window, Qt::Key_Enter);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QTest::keyClick(window, Qt::Key_X);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+}
+
+void tst_QQuickTableView::editUsingTab()
+{
+ // Check that the you can commit and start to edit
+ // the next cell by pressing tab and backtab.
+ LOAD_TABLEVIEW("editdelegate.qml");
+
+ auto model = TestModel(4, 4);
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->forceActiveFocus();
+
+ const char kEditItem[] = "editItem";
+ const char kEditIndex[] = "editIndex";
+
+ WAIT_UNTIL_POLISHED;
+
+ const QPoint cell1(1, 1);
+ const QPoint cell2(2, 1);
+ const QModelIndex index1 = tableView->modelIndex(cell1);
+ const QModelIndex index2 = tableView->modelIndex(cell2);
+
+ QQuickWindow *window = tableView->window();
+
+ // Edit cell 1
+ tableView->edit(index1);
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index1);
+ const QQuickItem *editItem1 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem1);
+
+ // Press Tab to edit cell 2
+ QTest::keyClick(window, Qt::Key_Tab);
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index2);
+ const QQuickItem *editItem2 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem2);
+
+ // Press Backtab to edit cell 1
+ QTest::keyClick(window, Qt::Key_Backtab);
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index1);
+ const QQuickItem *editItem3 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem3);
+}
+
+void tst_QQuickTableView::editDelegateComboBox()
+{
+ // Using a ComboBox as an edit delegate should be a quite common
+ // use case. So test that it works.
+ LOAD_TABLEVIEW("editdelegate_combobox.qml");
+
+ auto model = TestModel(4, 4);
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->forceActiveFocus();
+
+ const char kEditItem[] = "editItem";
+ const char kEditIndex[] = "editIndex";
+ const char kCommitCount[] = "commitCount";
+ const char kComboFocusCount[] = "comboFocusCount";
+
+ WAIT_UNTIL_POLISHED;
+
+ const QPoint cell1(1, 1);
+ const QPoint cell2(2, 1);
+ const QModelIndex index1 = tableView->modelIndex(cell1);
+ const QModelIndex index2 = tableView->modelIndex(cell2);
+
+ QQuickWindow *window = tableView->window();
+
+ // Edit cell 1
+ tableView->edit(index1);
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index1);
+ const QQuickItem *editItem1 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem1);
+ QCOMPARE(tableView->property(kComboFocusCount).value<int>(), 1);
+
+ // Press Tab to edit cell 2
+ QTest::keyClick(window, Qt::Key_Tab);
+ QCOMPARE(tableView->property(kCommitCount).value<int>(), 1);
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index2);
+ const QQuickItem *editItem2 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem2);
+ QCOMPARE(tableView->property(kComboFocusCount).value<int>(), 2);
+
+ // Press Enter to commit
+ QTest::keyClick(window, Qt::Key_Enter);
+ QCOMPARE(tableView->property(kCommitCount).value<int>(), 2);
+ QCOMPARE(tableView->property(kComboFocusCount).value<int>(), 2);
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+
+ // Edit cell 1
+ tableView->edit(index1);
+ // Press escape to close editor
+ QTest::keyClick(window, Qt::Key_Escape);
+ QCOMPARE(tableView->property(kCommitCount).value<int>(), 2);
+ QCOMPARE(tableView->property(kComboFocusCount).value<int>(), 3);
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+
+ // Edit cell 2
+ tableView->edit(index2);
+ // Press space to open combo menu
+ QTest::keyClick(window, Qt::Key_Space);
+ // Press Enter to commit and close the editor
+ QTest::keyClick(window, Qt::Key_Enter);
+ QCOMPARE(tableView->property(kCommitCount).value<int>(), 3);
+ QCOMPARE(tableView->property(kComboFocusCount).value<int>(), 4);
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+}
+
+void tst_QQuickTableView::editOnNonEditableCell_data()
+{
+ QTest::addColumn<QQuickTableView::EditTriggers>("editTriggers");
+
+ QTest::newRow("SingleTapped") << QQuickTableView::EditTriggers(QQuickTableView::SingleTapped);
+ QTest::newRow("DoubleTapped") << QQuickTableView::EditTriggers(QQuickTableView::DoubleTapped);
+ QTest::newRow("SelectedTapped") << QQuickTableView::EditTriggers(QQuickTableView::SelectedTapped);
+ QTest::newRow("EditKeyPressed") << QQuickTableView::EditTriggers(QQuickTableView::EditKeyPressed);
+ QTest::newRow("AnyKeyPressed") << QQuickTableView::EditTriggers(QQuickTableView::EditKeyPressed);
+}
+
+void tst_QQuickTableView::editOnNonEditableCell()
+{
+ // Check that the user cannot edit a non-editable cell from the edit triggers.
+ // Note: we don't want TableView to print out warnings in this case, since
+ // the user is not doing anything wrong. We only want to print out warnings if
+ // the application is calling edit() explicitly on a cell that cannot be edited
+ // (separate test below).
+ QFETCH(QQuickTableView::EditTriggers, editTriggers);
+ LOAD_TABLEVIEW("editdelegate.qml");
+
+ auto model = TestModel(4, 4);
+ // set flags that exclude Qt::ItemIsEditable
+ model.setFlags(Qt::ItemIsEnabled);
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setEditTriggers(editTriggers);
+ tableView->forceActiveFocus();
+
+ const char kEditItem[] = "editItem";
+ const char kEditIndex[] = "editIndex";
+
+ WAIT_UNTIL_POLISHED;
+
+ const QPoint cell(1, 1);
+ const QModelIndex index1 = tableView->modelIndex(cell);
+ const auto item = tableView->itemAtCell(cell);
+ QVERIFY(item);
+
+ QQuickWindow *window = tableView->window();
+
+ const QPoint localPos = QPoint(item->width() - 1, item->height() - 1);
+ const QPoint tapPos = window->contentItem()->mapFromItem(item, localPos).toPoint();
+
+ if (editTriggers & QQuickTableView::SingleTapped) {
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers & QQuickTableView::DoubleTapped) {
+ QTest::mouseDClick(window, Qt::LeftButton, Qt::NoModifier, tapPos);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers & QQuickTableView::SelectedTapped) {
+ // select cell first, then tap on it
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::NoUpdate);
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers & QQuickTableView::EditKeyPressed) {
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::NoUpdate);
+ QTest::keyClick(window, Qt::Key_Enter);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QTest::keyClick(window, Qt::Key_Return);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers & QQuickTableView::AnyKeyPressed) {
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::NoUpdate);
+ QTest::keyClick(window, Qt::Key_X);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QTest::keyClick(window, Qt::Key_Enter);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+}
+
+void tst_QQuickTableView::noEditDelegate_data()
+{
+ QTest::addColumn<QQuickTableView::EditTriggers>("editTriggers");
+
+ QTest::newRow("NoEditTriggers") << QQuickTableView::EditTriggers(QQuickTableView::NoEditTriggers);
+ QTest::newRow("SingleTapped") << QQuickTableView::EditTriggers(QQuickTableView::SingleTapped);
+ QTest::newRow("DoubleTapped") << QQuickTableView::EditTriggers(QQuickTableView::DoubleTapped);
+ QTest::newRow("SelectedTapped") << QQuickTableView::EditTriggers(QQuickTableView::SelectedTapped);
+ QTest::newRow("EditKeyPressed") << QQuickTableView::EditTriggers(QQuickTableView::EditKeyPressed);
+ QTest::newRow("AnyKeyPressed") << QQuickTableView::EditTriggers(QQuickTableView::EditKeyPressed);
+}
+
+void tst_QQuickTableView::noEditDelegate()
+{
+ // Check that you cannot start to edit if
+ // no edit delegate has been set.
+ QFETCH(QQuickTableView::EditTriggers, editTriggers);
+ LOAD_TABLEVIEW("tableviewwithselected2.qml");
+
+ auto model = TestModel(4, 4);
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setEditTriggers(editTriggers);
+ tableView->forceActiveFocus();
+
+ const char kEditItem[] = "editItem";
+ const char kEditIndex[] = "editIndex";
+
+ WAIT_UNTIL_POLISHED;
+
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+
+ const QPoint cell(1, 1);
+ const QModelIndex index1 = tableView->modelIndex(cell);
+ const auto item = tableView->itemAtCell(cell);
+ QVERIFY(item);
+
+ QQuickWindow *window = tableView->window();
+
+ const QPoint localPos = QPoint(item->width() - 1, item->height() - 1);
+ const QPoint tapPos = window->contentItem()->mapFromItem(item, localPos).toPoint();
+
+ if (editTriggers & QQuickTableView::SingleTapped) {
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers & QQuickTableView::DoubleTapped) {
+ QTest::mouseDClick(window, Qt::LeftButton, Qt::NoModifier, tapPos);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers & QQuickTableView::SelectedTapped) {
+ // select cell first, then tap on it
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::NoUpdate);
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers & QQuickTableView::EditKeyPressed) {
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::NoUpdate);
+ QTest::keyClick(window, Qt::Key_Enter);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QTest::keyClick(window, Qt::Key_Return);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers & QQuickTableView::AnyKeyPressed) {
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::NoUpdate);
+ QTest::keyClick(window, Qt::Key_X);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QTest::keyClick(window, Qt::Key_Enter);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+
+ if (editTriggers == QQuickTableView::NoEditTriggers) {
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QTest::mouseDClick(window, Qt::LeftButton, Qt::NoModifier, tapPos);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ tableView->selectionModel()->setCurrentIndex(index1, QItemSelectionModel::NoUpdate);
+ QTest::keyClick(window, Qt::Key_Return);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QTest::keyClick(window, Qt::Key_Enter);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QTest::keyClick(window, Qt::Key_X);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ }
+}
+
+void tst_QQuickTableView::editAndCloseEditor()
+{
+ // Check that the application can call edit() and closeEditor()
+ LOAD_TABLEVIEW("editdelegate.qml");
+
+ auto model = TestModel(4, 4);
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->forceActiveFocus();
+
+ const char kEditItem[] = "editItem";
+ const char kEditIndex[] = "editIndex";
+
+ WAIT_UNTIL_POLISHED;
+
+ const QPoint cell1(1, 1);
+ const QPoint cell2(2, 2);
+ const QModelIndex index1 = tableView->modelIndex(cell1);
+ const QModelIndex index2 = tableView->modelIndex(cell2);
+
+ const auto cellItem1 = tableView->itemAtCell(tableView->cellAtIndex(index1));
+ const auto cellItem2 = tableView->itemAtCell(tableView->cellAtIndex(index2));
+ QVERIFY(cellItem1);
+ QVERIFY(cellItem2);
+ QCOMPARE(cellItem1->property("editing").toBool(), false);
+ QCOMPARE(cellItem2->property("editing").toBool(), false);
+
+ // Edit cell 1
+ tableView->edit(index1);
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index1);
+ const QQuickItem *editItem1 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem1);
+ QVERIFY(editItem1->hasActiveFocus());
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index1);
+ QCOMPARE(editItem1->parentItem(), cellItem1);
+ QCOMPARE(editItem1->property("editing").toBool(), true);
+ QCOMPARE(cellItem1->property("editing").toBool(), true);
+
+ // Edit cell 2
+ tableView->edit(index2);
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index2);
+ const QQuickItem *editItem2 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem2);
+ QVERIFY(editItem2->hasActiveFocus());
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index2);
+ QCOMPARE(editItem2->parentItem(), cellItem2);
+ QCOMPARE(editItem2->property("editing").toBool(), true);
+ QCOMPARE(cellItem2->property("editing").toBool(), true);
+ QCOMPARE(cellItem1->property("editing").toBool(), false);
+
+ // Close the editor
+ tableView->closeEditor();
+ QCOMPARE(tableView->selectionModel()->currentIndex(), index2);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QCOMPARE(cellItem2->property("editing").toBool(), false);
+}
+
+void tst_QQuickTableView::editWarning_noEditDelegate()
+{
+ // Check that the TableView will print out a warning if the
+ // application calls edit() on a cell that has no editDelegate.
+ LOAD_TABLEVIEW("tableviewwithselected2.qml");
+
+ auto model = TestModel(4, 4);
+ tableView->setModel(QVariant::fromValue(&model));
+
+ WAIT_UNTIL_POLISHED;
+
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*cannot edit: no TableView.editDelegate set!"));
+ tableView->edit(tableView->index(1, 1));
+}
+
+void tst_QQuickTableView::editWarning_invalidIndex()
+{
+ // Check that the TableView will print out a warning if the
+ // application calls edit() on an invalid index.
+ LOAD_TABLEVIEW("editdelegate.qml");
+
+ auto model = TestModel(4, 4);
+ tableView->setModel(QVariant::fromValue(&model));
+
+ WAIT_UNTIL_POLISHED;
+
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*cannot edit: index is not valid!"));
+ tableView->edit(tableView->index(-1, -1));
+}
+
+void tst_QQuickTableView::editWarning_nonEditableModelItem()
+{
+ // Check that the TableView will print out a warning if the
+ // application calls edit() on cell that cannot, according
+ // to the model flags, be edited.
+ LOAD_TABLEVIEW("editdelegate.qml");
+
+ auto model = TestModel(4, 4);
+ tableView->setModel(QVariant::fromValue(&model));
+ // set flags that exclude Qt::ItemIsEditable
+ model.setFlags(Qt::ItemIsEnabled);
+
+ WAIT_UNTIL_POLISHED;
+
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*cannot edit:.*flags.*Qt::ItemIsEditable"));
+ tableView->edit(tableView->index(1, 1));
+}
+
+void tst_QQuickTableView::attachedPropertiesOnEditDelegate()
+{
+ // Check that the TableView.commit signal is emitted when
+ // the user presses enter or return, but not when e.g pressing escape.
+ // Also check that TableView.view is correct.
+ LOAD_TABLEVIEW("editdelegate.qml");
+
+ auto model = TestModel(4, 4);
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->forceActiveFocus();
+
+ const char kEditItem[] = "editItem";
+ const char kEditIndex[] = "editIndex";
+
+ WAIT_UNTIL_POLISHED;
+
+ const QPoint cell(1, 1);
+ const QModelIndex index = tableView->modelIndex(cell);
+ QQuickWindow *window = tableView->window();
+
+ // Open the edit
+ tableView->edit(index);
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index);
+ QQuickItem *editItem1 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem1);
+ const auto attached1 = getAttachedObject(editItem1);
+ QVERIFY(attached1);
+ QSignalSpy commitSpy1(attached1, &QQuickTableViewAttached::commit);
+
+ // Check that TableView has been assigned to TableView.view
+ QCOMPARE(attached1->view(), tableView);
+
+ // Accept and close the edit, check commit signal
+ QTest::keyClick(window, Qt::Key_Enter);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QCOMPARE(commitSpy1.count(), 1);
+
+ // Repeat once more, but use Key_Return to accept instead
+ tableView->edit(index);
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index);
+ QQuickItem *editItem2 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem2);
+ const auto attached2 = getAttachedObject(editItem2);
+ QVERIFY(attached2);
+ QSignalSpy commitSpy2(attached2, &QQuickTableViewAttached::commit);
+
+ QTest::keyClick(window, Qt::Key_Return);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QCOMPARE(commitSpy1.count(), 1);
+ QCOMPARE(commitSpy2.count(), 1);
+
+ // Repeat once more, but use Key_Escape instead.
+ // This should close the edit, but without an accepted signal.
+ tableView->edit(index);
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index);
+ QQuickItem *editItem3 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem3);
+ const auto attached3 = getAttachedObject(editItem3);
+ QVERIFY(editItem3);
+ QSignalSpy commitSpy3(attached3, &QQuickTableViewAttached::commit);
+
+ QTest::keyClick(window, Qt::Key_Escape);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QCOMPARE(commitSpy3.count(), 0);
+
+ // Repeat once more, but tap outside the edit item.
+ // This should close the edit, but without an accepted signal.
+ tableView->edit(index);
+ QCOMPARE(tableView->property(kEditIndex).value<QModelIndex>(), index);
+ QQuickItem *editItem4 = tableView->property(kEditItem).value<QQuickItem *>();
+ QVERIFY(editItem4);
+ const auto attached4 = getAttachedObject(editItem4);
+ QVERIFY(editItem4);
+ QSignalSpy commitSpy4(attached4, &QQuickTableViewAttached::commit);
+
+ const QPoint tapPos = window->contentItem()->mapFromItem(editItem4, QPointF(-10, -10)).toPoint();
+ QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, tapPos);
+ QVERIFY(!tableView->property(kEditItem).value<QQuickItem *>());
+ QVERIFY(!tableView->property(kEditIndex).value<QModelIndex>().isValid());
+ QCOMPARE(commitSpy4.count(), 0);
+}
+
+void tst_QQuickTableView::requiredPropertiesOnEditDelegate()
+{
+ // Check that all expected required properties on the edit
+ // delegate (like row, column, current) has correct values.
+ LOAD_TABLEVIEW("editdelegate.qml");
+
+ TestModel model(4, 4);
+ QItemSelectionModel selectionModel(&model);
+
+ tableView->setModel(QVariant::fromValue(&model));
+ tableView->setSelectionModel(&selectionModel);
+
+ const char kEditItem[] = "editItem";
+
+ WAIT_UNTIL_POLISHED;
+
+ const QPoint cell(1, 1);
+ const QModelIndex index1 = tableView->modelIndex(cell);
+ const QModelIndex index2 = tableView->index(2, 2);
+
+ tableView->edit(index1);
+
+ auto textInput = tableView->property(kEditItem).value<QQuickTextInput *>();
+ QVERIFY(textInput);
+ // Check that "text: display" in the edit delegate works
+ QCOMPARE(textInput->text(), "1");
+
+ QCOMPARE(textInput->property("current").toBool(), true);
+ QCOMPARE(textInput->property("selected").toBool(), false);
+ QCOMPARE(textInput->property("editing").toBool(), true);
+ selectionModel.select(index1, QItemSelectionModel::Select);
+ QCOMPARE(textInput->property("selected").toBool(), true);
+ selectionModel.setCurrentIndex(index2, QItemSelectionModel::Select);
+ QCOMPARE(textInput->property("current").toBool(), false);
+}
+
+void tst_QQuickTableView::resettingRolesRespected()
+{
+ LOAD_TABLEVIEW("resetModelData.qml");
+
+ TestModel model(1, 1);
+ tableView->setModel(QVariant::fromValue(&model));
+
+ WAIT_UNTIL_POLISHED;
+
+ QVERIFY(!tableView->property("success").toBool());
+ model.useCustomRoleNames(true);
+ QTRY_VERIFY(tableView->property("success").toBool());
+}
+
+void tst_QQuickTableView::checkScroll_data()
+{
+ QTest::addColumn<bool>("resizableColumns");
+ QTest::addColumn<bool>("resizableRows");
+ QTest::newRow("T, T") << true << true;
+ QTest::newRow("T, F") << true << false;
+ QTest::newRow("F, T") << false << true;
+ QTest::newRow("F, F") << false << false;
+}
+
+/*!
+ Make sure that the TableView is scrollable regardless
+ of the values of resizableColumns and resizableRows.
+*/
+void tst_QQuickTableView::checkScroll() // QTBUG-116566
+{
+ QFETCH(bool, resizableColumns);
+ QFETCH(bool, resizableRows);
+ LOAD_TABLEVIEW("plaintableview.qml"); // gives us 'tableView' variable
+
+ tableView->setResizableColumns(resizableColumns);
+ tableView->setResizableRows(resizableRows);
+
+ auto model = TestModelAsVariant(20, 10);
+ tableView->setModel(model);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Scroll with the mouse wheel
+ sendWheelEvent(view, {10, 10}, {0, -120}, {0, -120});
+
+ // Check that scrolling succeeded
+ QTRY_COMPARE_GT(tableView->contentY(), 20);
+}
+
+void tst_QQuickTableView::checkRebuildJsModel()
+{
+ LOAD_TABLEVIEW("resetJsModelData.qml"); // gives us 'tableView' variable
+
+ // Generate javascript model
+ const int size = 5;
+ const char* modelUpdated = "modelUpdated";
+
+ QJSEngine jsEngine;
+ QJSValue jsArray;
+ jsArray = jsEngine.newArray(size);
+ for (int i = 0; i < size; ++i)
+ jsArray.setProperty(i, QRandomGenerator::global()->generate());
+
+ QVariant jsModel = QVariant::fromValue(jsArray);
+ tableView->setModel(jsModel);
+ WAIT_UNTIL_POLISHED;
+
+ // Model change would be triggered for the first time
+ QCOMPARE(tableView->property(modelUpdated).toInt(), 1);
+
+ // Set the same model once again and check if model changes
+ tableView->setModel(jsModel);
+ QCOMPARE(tableView->property(modelUpdated).toInt(), 1);
+}
+
QTEST_MAIN(tst_QQuickTableView)
#include "tst_qquicktableview.moc"
diff --git a/tests/auto/quick/qquicktext/BLACKLIST b/tests/auto/quick/qquicktext/BLACKLIST
index 1a3ea5492f..a4e9c44eab 100644
--- a/tests/auto/quick/qquicktext/BLACKLIST
+++ b/tests/auto/quick/qquicktext/BLACKLIST
@@ -10,3 +10,16 @@ sles
ci b2qt 32bit
[baselineOffset]
ci b2qt 32bit
+# QTBUG-102721
+[hAlignWidthDependsOnImplicitWidth]
+android
+[hAlignImplicitWidth]
+android
+[transparentBackground]
+android
+
+# QTBUG-103096
+[largeTextObservesViewport]
+android
+[baselineOffset]
+android
diff --git a/tests/auto/quick/qquicktext/CMakeLists.txt b/tests/auto/quick/qquicktext/CMakeLists.txt
index 569347e287..68330befd9 100644
--- a/tests/auto/quick/qquicktext/CMakeLists.txt
+++ b/tests/auto/quick/qquicktext/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquicktext.pro.
#####################################################################
## tst_qquicktext Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicktext LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,12 +21,8 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquicktext
SOURCES
- ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h
- ../../shared/util.cpp ../../shared/util.h
tst_qquicktext.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
@@ -25,6 +30,7 @@ qt_internal_add_test(tst_qquicktext
Qt::QmlPrivate
Qt::QuickPrivate
Qt::QuickTest
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -33,10 +39,10 @@ qt_internal_add_test(tst_qquicktext
qt_internal_extend_target(tst_qquicktext CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquicktext CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquicktext/data/elideZeroWidthWithMargins.qml b/tests/auto/quick/qquicktext/data/elideZeroWidthWithMargins.qml
new file mode 100644
index 0000000000..bb269e6ad5
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/elideZeroWidthWithMargins.qml
@@ -0,0 +1,27 @@
+import QtQuick
+
+Item {
+ id: root
+ property bool ok: false
+ width: 640
+ height: 480
+
+ Text {
+ id: text
+ text: "This is a quite long text. Click me and i should remain visible!!! Sadly this doesn't happen"
+ elide: Text.ElideRight
+ anchors {
+ fill: parent
+ margins: 1
+ }
+ }
+
+ Component.onCompleted: {
+ text.width = 300;
+ text.height = 0;
+ text.width = 0;
+ text.height = 30;
+ text.width = 300;
+ root.ok = text.paintedWidth > 0 && text.paintedHeight > 0
+ }
+}
diff --git a/tests/auto/quick/qquicktext/data/lineLayout.qml b/tests/auto/quick/qquicktext/data/lineLayout.qml
index 5a980de7da..74b9ecb500 100644
--- a/tests/auto/quick/qquicktext/data/lineLayout.qml
+++ b/tests/auto/quick/qquicktext/data/lineLayout.qml
@@ -20,7 +20,7 @@ Rectangle {
text: "<b>Lorem ipsum</b> dolor sit amet, consectetur adipiscing elit. Integer at ante dui. Sed eu egestas est.
<br/><p><i>Maecenas nec libero leo. Sed ac leo eget ipsum ultricies viverra sit amet eu orci. Praesent et tortor risus, viverra accumsan sapien. Sed faucibus eleifend lectus, sed euismod urna porta eu. Aenean ultricies lectus ut orci dictum quis convallis nisi ultrices. Nunc elit mi, iaculis a porttitor rutrum, venenatis malesuada nisi. Suspendisse turpis quam, euismod non imperdiet et, rutrum nec ligula. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam semper tristique metus eu sodales. Integer eget risus ipsum. Quisque ut risus ut nulla tristique volutpat at sit amet nisl. Aliquam pulvinar auctor diam nec bibendum.</i><br/><p>Quisque luctus sapien id arcu volutpat pharetra. Praesent pretium imperdiet euismod. Integer fringilla rhoncus condimentum. Quisque sit amet ornare nulla. Cras sapien augue, sagittis a dictum id, suscipit et nunc. Cras vitae augue in enim elementum venenatis sed nec risus. Sed nisi quam, mollis quis auctor ac, vestibulum in neque. Vivamus eu justo risus. Suspendisse vel mollis est. Vestibulum gravida interdum mi, in molestie neque gravida in. Donec nibh odio, mattis facilisis vulputate et, scelerisque ut felis. Sed ornare eros nec odio aliquam eu varius augue adipiscing. Vivamus sit amet massa dapibus sapien pulvinar consectetur a sit amet felis. Cras non mi id libero dictum iaculis id dignissim eros. Praesent eget enim dui, sed bibendum neque. Ut interdum nisl id leo malesuada ornare. Pellentesque id nisl eu odio volutpat posuere et at massa. Pellentesque nec lorem justo. Integer sem urna, pharetra sed sagittis vitae, condimentum ac felis. Ut vitae sapien ac tortor adipiscing pharetra. Cras tristique urna tempus ante volutpat eleifend non eu ligula. Mauris sodales nisl et lorem tristique sodales. Mauris arcu orci, vehicula semper cursus ac, dapibus ut mi."
- onLineLaidOut: {
+ onLineLaidOut: (line) => {
line.width = line.number * 15
if (line.number === 30 || line.number === 60) {
main.off = line.y
diff --git a/tests/auto/quick/qquicktext/data/lineLayoutFontUpdate.qml b/tests/auto/quick/qquicktext/data/lineLayoutFontUpdate.qml
new file mode 100644
index 0000000000..d018e31d29
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/lineLayoutFontUpdate.qml
@@ -0,0 +1,25 @@
+import QtQuick
+
+Item {
+ width: 640
+ height: 480
+
+ FontLoader {
+ id: fontIcons
+ source: "tarzeau_ocr_a.ttf"
+ }
+
+ Text {
+ id: exampleText
+ objectName: "exampleText"
+ text: "Example multiline text"
+ wrapMode: Text.WordWrap
+ width: 100
+ onLineLaidOut: (line) => {
+ if (line.number < 1) {
+ line.x += 40;
+ line.width -= 40;
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktext/data/lineLayoutImplicitWidth.qml b/tests/auto/quick/qquicktext/data/lineLayoutImplicitWidth.qml
index de5ca616b8..94a6ac2797 100644
--- a/tests/auto/quick/qquicktext/data/lineLayoutImplicitWidth.qml
+++ b/tests/auto/quick/qquicktext/data/lineLayoutImplicitWidth.qml
@@ -1,52 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 Jolla Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 Jolla Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.0
@@ -70,7 +23,7 @@ Rectangle {
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis ante tristique, fermentum magna at, varius lacus. Donec elementum orci sit amet ligula efficitur, eget sodales orci porttitor. Etiam laoreet tellus quis nisi mollis lacinia. Cras vitae nisl sed nunc semper blandit. Duis egestas commodo lacus non congue. Fusce quis rhoncus urna. And magna arcu, sodales vitae nunc vel, rutrum hendrerit magna. Nullam imperdiet porttitor sem at euismod. Morbi faucibus libero sit amet vestibulum aliquam. Duis consectetur lacinia malesuada. Sed quis ante dui. Name dignissim faucibus felis. Quisque dapibus aliquam ante, eu cursus elit dictum in. Mauris placerat efficitur rutrum."
- onLineLaidOut: {
+ onLineLaidOut: (line) => {
var n = line.number
// Save information about the line so the autotest can retrieve it
diff --git a/tests/auto/quick/qquicktext/data/lineLayoutRelayout.qml b/tests/auto/quick/qquicktext/data/lineLayoutRelayout.qml
index 2e1aa6a17d..2f46159602 100644
--- a/tests/auto/quick/qquicktext/data/lineLayoutRelayout.qml
+++ b/tests/auto/quick/qquicktext/data/lineLayoutRelayout.qml
@@ -29,7 +29,7 @@ leo eget ipsum ultricies viverra sit amet eu orci. Praesent et tortor risus,
viverra accumsan sapien. Sed faucibus eleifend lectus, sed euismod urna porta
eu. Quisque vitae accumsan lectus."
- onLineLaidOut: {
+ onLineLaidOut: (line) => {
line.width = width / 2
if (line.y + line.height >= height) {
diff --git a/tests/auto/quick/qquicktext/data/loaderActiveOnVisible.qml b/tests/auto/quick/qquicktext/data/loaderActiveOnVisible.qml
new file mode 100644
index 0000000000..915dc21d84
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/loaderActiveOnVisible.qml
@@ -0,0 +1,24 @@
+import QtQuick
+
+Rectangle {
+ id: root
+ visible: false
+ width: 320
+ height: 240
+ Flickable {
+ id: flickable
+ anchors {
+ fill: root
+ margins: 10
+ }
+ contentHeight: loader.height
+
+ Loader {
+ id: loader
+ width: flickable.width
+ active: root.visible
+ source: "long.qml"
+ }
+ }
+ Component.onCompleted: visible = true
+}
diff --git a/tests/auto/quick/qquicktext/data/long.qml b/tests/auto/quick/qquicktext/data/long.qml
new file mode 100644
index 0000000000..ca27efb35a
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/long.qml
@@ -0,0 +1,7 @@
+import QtQuick
+
+Text {
+ width: 300
+ wrapMode: Text.WordWrap
+ text: "GNU GENERAL PUBLIC LICENSE\r\nVersion 2, June 1991\r\nCopyright (C) 1989, 1991 Free Software Foundation, Inc.\r\n51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA\r\n\r\nEveryone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.\r\n\r\nPreamble\r\n\r\nThe licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too.\r\n\r\nWhen we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.\r\n\r\nTo protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.\r\n\r\nFor example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.\r\n\r\nWe protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and\/or modify the software.\r\n\r\nAlso, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.\r\n\r\nFinally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.\r\n\r\nThe precise terms and conditions for copying, distribution and modification follow.\r\n\r\nTERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\r\n\r\n1. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The \"Program\", below, refers to any such program or work, and a \"work based on the Program\" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and\/or translated into another language. (Hereinafter, translation is included without limitation in the term \"modification\".) Each licensee is addressed as \"you\".\r\n\r\nActivities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.\r\n\r\n2. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.\r\n\r\nYou may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.\r\n\r\n3. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:\r\n\r\na) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.\r\n\r\nb) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.\r\n\r\nc) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)\r\n\r\nThese requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.\r\n\r\nThus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.\r\n\r\nIn addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.\r\n\r\n4. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:\r\n\r\na) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\r\n\r\nb) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\r\n\r\nc) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)\r\n\r\nThe source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.\r\n\r\nIf distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.\r\n\r\n5. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.\r\n\r\n6. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.\r\n\r\n7. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.\r\n\r\n8. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.\r\n\r\nIf any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.\r\n\r\nIt is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author\/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.\r\n\r\nThis section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.\r\n\r\n9. If the distribution and\/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.\r\n\r\n10. The Free Software Foundation may publish revised and\/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\r\n\r\nEach version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and \"any later version\", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.\r\n\r\n11. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.\r\n\r\nNO WARRANTY\r\n\r\n12. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND\/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\r\n\r\n13. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND\/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\r\nEND OF TERMS AND CONDITIONS\r\n\r\n"
+}
diff --git a/tests/auto/quick/qquicktext/data/padding.qml b/tests/auto/quick/qquicktext/data/padding.qml
index ab0a37d041..f830af0e40 100644
--- a/tests/auto/quick/qquicktext/data/padding.qml
+++ b/tests/auto/quick/qquicktext/data/padding.qml
@@ -9,4 +9,30 @@ Text {
leftPadding: 30
rightPadding: 40
bottomPadding: 50
+
+ Rectangle {
+ width: parent.leftPadding
+ height: parent.height
+ color: "#6600FF00"
+ }
+
+ Rectangle {
+ width: parent.width
+ height: parent.topPadding
+ color: "#66888800"
+ }
+
+ Rectangle {
+ x: parent.width - parent.rightPadding
+ width: parent.rightPadding
+ height: parent.height
+ color: "#6600FFFF"
+ }
+
+ Rectangle {
+ y: parent.height - parent.bottomPadding
+ width: parent.width
+ height: parent.bottomPadding
+ color: "#66880088"
+ }
}
diff --git a/tests/auto/quick/qquicktext/data/paddingInLoader.qml b/tests/auto/quick/qquicktext/data/paddingInLoader.qml
new file mode 100644
index 0000000000..6ef7c25a9b
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/paddingInLoader.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.12
+
+Item {
+ width: 30
+ height: 30
+ Loader {
+ anchors.fill: parent
+ sourceComponent: Text {
+ rightPadding: 30
+ text: "Some text"
+ elide: Text.ElideRight
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktext/data/qtbug_106205.qml b/tests/auto/quick/qquicktext/data/qtbug_106205.qml
new file mode 100644
index 0000000000..e4db73557a
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/qtbug_106205.qml
@@ -0,0 +1,28 @@
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ id: root
+ objectName: "root"
+ visible: true
+
+ anchors.fill: parent
+ property string text: ""
+
+ ScrollView {
+ anchors.fill: parent
+ Rectangle {
+ x: 100
+ width: 100
+ height: 30
+ color: "lightgray"
+
+ Text {
+ objectName: "textOutsideViewport"
+ text: root.text
+ width: 50
+ clip: true
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktext/data/tarzeau_ocr_a.ttf b/tests/auto/quick/qquicktext/data/tarzeau_ocr_a.ttf
new file mode 100644
index 0000000000..cf93f9651f
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/tarzeau_ocr_a.ttf
Binary files differ
diff --git a/tests/auto/quick/qquicktext/data/viewport.qml b/tests/auto/quick/qquicktext/data/viewport.qml
new file mode 100644
index 0000000000..e5c8805670
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/viewport.qml
@@ -0,0 +1,19 @@
+import QtQuick
+
+Item {
+ width: 480; height: 480
+
+ Rectangle {
+ id: viewport
+ anchors.fill: parent
+ anchors.margins: 100
+ border.color: "red"
+
+ Text {
+ Component.onCompleted: {
+ for (let i = 0; i < 20; ++i)
+ text += "Line " + i + "\n";
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index 339bea0e6f..b731f1b069 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtTest/QSignalSpy>
#include <QTextDocument>
@@ -32,10 +7,12 @@
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qjsvalue.h>
#include <QtQuick/private/qquicktext_p.h>
+#include <QtQuick/private/qquickflickable_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
+#include <QtQuick/private/qquickpixmapcache_p.h>
#include <QtQuickTest/QtQuickTest>
#include <private/qquicktext_p_p.h>
-#include <private/qquicktextdocument_p.h>
+#include <private/qsginternaltextnode_p.h>
#include <private/qquickvaluetypes_p.h>
#include <QFontMetrics>
#include <qmath.h>
@@ -44,16 +21,24 @@
#include <private/qguiapplication_p.h>
#include <limits.h>
#include <QtGui/QMouseEvent>
-#include "../../shared/util.h"
-#include "testhttpserver.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/testhttpserver_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
Q_DECLARE_METATYPE(QQuickText::TextFormat)
+typedef QVector<QPointF> PointVector;
+Q_DECLARE_METATYPE(PointVector);
+
+typedef qreal (*ExpectedBaseline)(QQuickText *item);
+Q_DECLARE_METATYPE(ExpectedBaseline)
+
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+
QT_BEGIN_NAMESPACE
extern void qt_setQtEnableTestFont(bool value);
-QT_END_NAMESPACE
class tst_qquicktext : public QQmlDataTest
{
@@ -68,12 +53,14 @@ private slots:
void wrap();
void elide();
void elideParentChanged();
+ void elideRelayoutAfterZeroWidth_data();
void elideRelayoutAfterZeroWidth();
void multilineElide_data();
void multilineElide();
void implicitElide_data();
void implicitElide();
void textFormat();
+ void clipRectOutsideViewportDynamicallyChanged();
void baseUrl();
void embeddedImages_data();
@@ -109,6 +96,7 @@ private slots:
void implicitSize_data();
void implicitSize();
void implicitSizeChangeRewrap();
+ void implicitSizeMaxLineCount();
void dependentImplicitSizes();
void contentSize();
void implicitSizeBinding_data();
@@ -118,8 +106,12 @@ private slots:
void boundingRect_data();
void boundingRect();
void clipRect();
+ void largeTextObservesViewport_data();
+ void largeTextObservesViewport();
+ void largeTextInDelayedLoader();
void lineLaidOut();
void lineLaidOutRelayout();
+ void lineLaidOutFontUpdate();
void lineLaidOutHAlign();
void lineLaidOutImplicitWidth();
@@ -153,6 +145,7 @@ private slots:
void growFromZeroWidth();
void padding();
+ void paddingInLoader();
void hintingPreference();
@@ -198,6 +191,7 @@ void tst_qquicktext::cleanup()
}
tst_qquicktext::tst_qquicktext()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
standard << "the quick brown fox jumped over the lazy dog"
<< "the quick brown fox\n jumped over the lazy dog";
@@ -264,13 +258,12 @@ void tst_qquicktext::text()
{
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->text(), QString(""));
QCOMPARE(textObject->width(), qreal(0));
-
- delete textObject;
}
for (int i = 0; i < standard.size(); i++)
@@ -278,14 +271,12 @@ void tst_qquicktext::text()
QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
-
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->text(), standard.at(i));
QVERIFY(textObject->width() > 0);
-
- delete textObject;
}
for (int i = 0; i < richText.size(); i++)
@@ -293,14 +284,13 @@ void tst_qquicktext::text()
QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QString expected = richText.at(i);
QCOMPARE(textObject->text(), expected.replace("\\\"", "\""));
QVERIFY(textObject->width() > 0);
-
- delete textObject;
}
}
@@ -310,12 +300,11 @@ void tst_qquicktext::width()
{
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->width(), 0.);
-
- delete textObject;
}
bool requiresUnhintedMetrics = !qmlDisableDistanceField();
@@ -357,14 +346,13 @@ void tst_qquicktext::width()
QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QVERIFY(textObject->boundingRect().width() > 0);
QCOMPARE(textObject->width(), qreal(metricWidth));
QVERIFY(textObject->textFormat() == QQuickText::AutoText); // setting text doesn't change format
-
- delete textObject;
}
for (int i = 0; i < richText.size(); i++)
@@ -374,7 +362,8 @@ void tst_qquicktext::width()
QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\"; textFormat: Text.RichText }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
@@ -386,8 +375,6 @@ void tst_qquicktext::width()
QCOMPARE(int(textObject->width()), int(doc->idealWidth()));
QCOMPARE(textObject->textFormat(), QQuickText::RichText);
-
- delete textObject;
}
}
@@ -398,14 +385,13 @@ void tst_qquicktext::wrap()
{
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; wrapMode: Text.WordWrap; width: 300 }", QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
textHeight = textObject->height();
- QVERIFY(textObject != nullptr);
QCOMPARE(textObject->wrapMode(), QQuickText::WordWrap);
QCOMPARE(textObject->width(), 300.);
-
- delete textObject;
}
for (int i = 0; i < standard.size(); i++)
@@ -413,7 +399,8 @@ void tst_qquicktext::wrap()
QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->width(), 30.);
@@ -422,8 +409,6 @@ void tst_qquicktext::wrap()
int oldHeight = textObject->height();
textObject->setWidth(100);
QVERIFY(textObject->height() < oldHeight);
-
- delete textObject;
}
for (int i = 0; i < richText.size(); i++)
@@ -431,7 +416,8 @@ void tst_qquicktext::wrap()
QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->width(), 30.);
@@ -440,8 +426,6 @@ void tst_qquicktext::wrap()
qreal oldHeight = textObject->height();
textObject->setWidth(100);
QVERIFY(textObject->height() < oldHeight);
-
- delete textObject;
}
// Check that increasing width from idealWidth will cause a relayout
@@ -450,7 +434,8 @@ void tst_qquicktext::wrap()
QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; textFormat: Text.RichText; width: 30; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->width(), 30.);
@@ -469,8 +454,6 @@ void tst_qquicktext::wrap()
qreal oldHeight = textObject->height();
textObject->setWidth(100);
QVERIFY(textObject->height() < oldHeight);
-
- delete textObject;
}
// richtext again with a fixed height
@@ -479,7 +462,8 @@ void tst_qquicktext::wrap()
QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; height: 50; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->width(), 30.);
@@ -488,8 +472,6 @@ void tst_qquicktext::wrap()
qreal oldHeight = textObject->implicitHeight();
textObject->setWidth(100);
QVERIFY(textObject->implicitHeight() < oldHeight);
-
- delete textObject;
}
{
@@ -505,14 +487,14 @@ void tst_qquicktext::wrap()
textObject->setWrapMode(QQuickText::Wrap);
QCOMPARE(textObject->wrapMode(), QQuickText::Wrap);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
textObject->setWrapMode(QQuickText::Wrap);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
textObject->setWrapMode(QQuickText::NoWrap);
QCOMPARE(textObject->wrapMode(), QQuickText::NoWrap);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
}
@@ -527,12 +509,12 @@ void tst_qquicktext::elide()
{
QQmlComponent textComponent(&engine);
textComponent.setData(("import QtQuick 2.0\nText { text: \"\"; "+elide+" width: 100 }").toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->elideMode(), m);
QCOMPARE(textObject->width(), 100.);
-
- delete textObject;
}
for (int i = 0; i < standard.size(); i++)
@@ -540,15 +522,15 @@ void tst_qquicktext::elide()
QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->elideMode(), m);
QCOMPARE(textObject->width(), 100.);
if (m != QQuickText::ElideNone && !standard.at(i).contains('\n'))
QVERIFY(textObject->contentWidth() <= textObject->width());
-
- delete textObject;
}
for (int i = 0; i < richText.size(); i++)
@@ -556,15 +538,15 @@ void tst_qquicktext::elide()
QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->elideMode(), m);
QCOMPARE(textObject->width(), 100.);
if (m != QQuickText::ElideNone && standard.at(i).contains("<br>"))
QVERIFY(textObject->contentWidth() <= textObject->width());
-
- delete textObject;
}
}
}
@@ -608,10 +590,19 @@ void tst_qquicktext::elideParentChanged()
QCOMPARE(actualItemImageGrab, expectedItemImageGrab);
}
+void tst_qquicktext::elideRelayoutAfterZeroWidth_data()
+{
+ QTest::addColumn<QByteArray>("fileName");
+
+ QTest::newRow("no_margins") << QByteArray("elideZeroWidth.qml");
+ QTest::newRow("with_margins") << QByteArray("elideZeroWidthWithMargins.qml");
+}
+
void tst_qquicktext::elideRelayoutAfterZeroWidth()
{
+ QFETCH(const QByteArray, fileName);
QQmlEngine engine;
- QQmlComponent component(&engine, testFileUrl("elideZeroWidth.qml"));
+ QQmlComponent component(&engine, testFileUrl(fileName.constData()));
QScopedPointer<QObject> root(component.create());
QVERIFY2(root, qPrintable(component.errorString()));
QVERIFY(root->property("ok").toBool());
@@ -715,6 +706,7 @@ void tst_qquicktext::implicitElide()
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QVERIFY2(textObject, qPrintable(textComponent.errorString()));
QVERIFY(textObject->contentWidth() <= textObject->width());
textObject->setText("the quick brown fox jumped over");
@@ -728,7 +720,8 @@ void tst_qquicktext::textFormat()
{
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->textFormat(), QQuickText::RichText);
@@ -736,13 +729,12 @@ void tst_qquicktext::textFormat()
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
QVERIFY(textPrivate != nullptr);
QVERIFY(textPrivate->richText);
-
- delete textObject;
}
{
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\" }", QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->textFormat(), QQuickText::AutoText);
@@ -750,18 +742,15 @@ void tst_qquicktext::textFormat()
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
QVERIFY(textPrivate != nullptr);
QVERIFY(textPrivate->styledText);
-
- delete textObject;
}
{
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->textFormat(), QQuickText::PlainText);
-
- delete textObject;
}
{
@@ -777,14 +766,14 @@ void tst_qquicktext::textFormat()
text->setTextFormat(QQuickText::StyledText);
QCOMPARE(text->textFormat(), QQuickText::StyledText);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
text->setTextFormat(QQuickText::StyledText);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
text->setTextFormat(QQuickText::AutoText);
QCOMPARE(text->textFormat(), QQuickText::AutoText);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
{
@@ -843,6 +832,28 @@ void tst_qquicktext::textFormat()
}
}
+void tst_qquicktext::clipRectOutsideViewportDynamicallyChanged()
+{
+ // QTBUG-106205
+ QScopedPointer<QQuickView> view(createView(testFile("qtbug_106205.qml")));
+ view->setWidth(100);
+ view->setHeight(200);
+ view->showNormal();
+ QQuickItem *root = view->rootObject();
+ QVERIFY(root);
+ QVERIFY(QTest::qWaitForWindowExposed(view.get()));
+
+ auto clipRectMatches = [&]() -> bool {
+ auto *textOutsideInitialViewport = root->findChild<QQuickText *>("textOutsideViewport");
+ if (!textOutsideInitialViewport)
+ return false;
+ auto *clipNode = QQuickItemPrivate::get(textOutsideInitialViewport)->clipNode();
+
+ return textOutsideInitialViewport->clipRect() == clipNode->clipRect();
+ };
+ QTRY_VERIFY(clipRectMatches());
+}
+
//the alignment tests may be trivial o.oa
void tst_qquicktext::horizontalAlignment()
{
@@ -855,11 +866,11 @@ void tst_qquicktext::horizontalAlignment()
QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject, qPrintable(textComponent.errorString()));
QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
-
- delete textObject;
}
}
@@ -870,11 +881,11 @@ void tst_qquicktext::horizontalAlignment()
QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject, qPrintable(textComponent.errorString()));
QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
-
- delete textObject;
}
}
@@ -991,10 +1002,11 @@ void tst_qquicktext::horizontalAlignment_RightToLeft()
QString componentStr = "import QtQuick 2.0\nText {}";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->hAlign(), qApp->inputMethod()->inputDirection() == Qt::LeftToRight ?
QQuickText::AlignLeft : QQuickText::AlignRight);
- delete textObject;
}
int tst_qquicktext::numberOfNonWhitePixels(int fromX, int toX, const QImage &image)
@@ -1021,9 +1033,6 @@ static inline QByteArray msgNotLessThan(int n1, int n2)
void tst_qquicktext::hAlignImplicitWidth()
{
-#ifdef Q_OS_MACOS
- QSKIP("this test currently crashes on MacOS. See QTBUG-68047");
-#endif
QQuickView view(testFileUrl("hAlignImplicitWidth.qml"));
view.setFlags(view.flags() | Qt::WindowStaysOnTopHint); // Prevent being obscured by other windows.
view.show();
@@ -1047,9 +1056,8 @@ void tst_qquicktext::hAlignImplicitWidth()
const int centeredSection3End = centeredSection3 + sectionWidth;
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimal platforms", Abort);
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
// Left Align
QImage image = view.grabWindow();
@@ -1096,12 +1104,11 @@ void tst_qquicktext::verticalAlignment()
QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
-
- delete textObject;
}
}
@@ -1112,12 +1119,11 @@ void tst_qquicktext::verticalAlignment()
QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
-
- delete textObject;
}
}
@@ -1130,74 +1136,74 @@ void tst_qquicktext::font()
QString componentStr = "import QtQuick 2.0\nText { font.pointSize: 40; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->font().pointSize(), 40);
QCOMPARE(textObject->font().bold(), false);
QCOMPARE(textObject->font().italic(), false);
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { font.pixelSize: 40; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->font().pixelSize(), 40);
QCOMPARE(textObject->font().bold(), false);
QCOMPARE(textObject->font().italic(), false);
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { font.bold: true; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->font().bold(), true);
QCOMPARE(textObject->font().italic(), false);
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { font.italic: true; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->font().italic(), true);
QCOMPARE(textObject->font().bold(), false);
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { font.family: \"Helvetica\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->font().family(), QString("Helvetica"));
QCOMPARE(textObject->font().bold(), false);
QCOMPARE(textObject->font().italic(), false);
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { font.family: \"\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->font().family(), QString(""));
-
- delete textObject;
}
}
@@ -1209,17 +1215,19 @@ void tst_qquicktext::style()
QString componentStr = "import QtQuick 2.0\nText { style: \"" + styleStrings.at(i) + "\"; styleColor: \"white\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE((int)textObject->style(), (int)styles.at(i));
QCOMPARE(textObject->styleColor(), QColor("white"));
-
- delete textObject;
}
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QRectF brPre = textObject->boundingRect();
textObject->setStyle(QQuickText::Outline);
@@ -1227,8 +1235,6 @@ void tst_qquicktext::style()
QVERIFY(brPre.width() < brPost.width());
QVERIFY(brPre.height() < brPost.height());
-
- delete textObject;
}
void tst_qquicktext::color()
@@ -1239,13 +1245,13 @@ void tst_qquicktext::color()
QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
QCOMPARE(textObject->styleColor(), QColor("black"));
QCOMPARE(textObject->linkColor(), QColor("blue"));
-
- delete textObject;
}
for (int i = 0; i < colorStrings.size(); i++)
@@ -1253,7 +1259,9 @@ void tst_qquicktext::color()
QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
// default color to black?
@@ -1265,27 +1273,25 @@ void tst_qquicktext::color()
textObject->setColor(QColor("white"));
QCOMPARE(textObject->color(), QColor("white"));
- QCOMPARE(colorSpy.count(), 1);
+ QCOMPARE(colorSpy.size(), 1);
textObject->setLinkColor(QColor("black"));
QCOMPARE(textObject->linkColor(), QColor("black"));
- QCOMPARE(linkColorSpy.count(), 1);
+ QCOMPARE(linkColorSpy.size(), 1);
textObject->setColor(QColor("white"));
- QCOMPARE(colorSpy.count(), 1);
+ QCOMPARE(colorSpy.size(), 1);
textObject->setLinkColor(QColor("black"));
- QCOMPARE(linkColorSpy.count(), 1);
+ QCOMPARE(linkColorSpy.size(), 1);
textObject->setColor(QColor("black"));
QCOMPARE(textObject->color(), QColor("black"));
- QCOMPARE(colorSpy.count(), 2);
+ QCOMPARE(colorSpy.size(), 2);
textObject->setLinkColor(QColor("blue"));
QCOMPARE(textObject->linkColor(), QColor("blue"));
- QCOMPARE(linkColorSpy.count(), 2);
-
- delete textObject;
+ QCOMPARE(linkColorSpy.size(), 2);
}
for (int i = 0; i < colorStrings.size(); i++)
@@ -1293,13 +1299,13 @@ void tst_qquicktext::color()
QString componentStr = "import QtQuick 2.0\nText { linkColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->styleColor(), QColor("black"));
QCOMPARE(textObject->color(), QColor("black"));
QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(i)));
-
- delete textObject;
}
for (int i = 0; i < colorStrings.size(); i++)
@@ -1313,13 +1319,13 @@ void tst_qquicktext::color()
"text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
QCOMPARE(textObject->linkColor(), QColor(colorStrings.at(j)));
-
- delete textObject;
}
}
{
@@ -1330,11 +1336,11 @@ void tst_qquicktext::color()
QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->color(), testColor);
-
- delete textObject;
} {
QString colorStr = "#001234";
QColor testColor(colorStr);
@@ -1344,18 +1350,19 @@ void tst_qquicktext::color()
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(textComponent.create());
QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QSignalSpy spy(textObject, SIGNAL(colorChanged()));
QCOMPARE(textObject->color(), testColor);
textObject->setColor(testColor);
QCOMPARE(textObject->color(), testColor);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
testColor = QColor("black");
textObject->setColor(testColor);
QCOMPARE(textObject->color(), testColor);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
} {
QString colorStr = "#001234";
QColor testColor(colorStr);
@@ -1365,18 +1372,19 @@ void tst_qquicktext::color()
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(textComponent.create());
QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QSignalSpy spy(textObject, SIGNAL(styleColorChanged()));
QCOMPARE(textObject->styleColor(), testColor);
textObject->setStyleColor(testColor);
QCOMPARE(textObject->styleColor(), testColor);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
testColor = QColor("black");
textObject->setStyleColor(testColor);
QCOMPARE(textObject->styleColor(), testColor);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
} {
QString colorStr = "#001234";
QColor testColor(colorStr);
@@ -1386,18 +1394,19 @@ void tst_qquicktext::color()
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(textComponent.create());
QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QSignalSpy spy(textObject, SIGNAL(linkColorChanged()));
QCOMPARE(textObject->linkColor(), testColor);
textObject->setLinkColor(testColor);
QCOMPARE(textObject->linkColor(), testColor);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
testColor = QColor("black");
textObject->setLinkColor(testColor);
QCOMPARE(textObject->linkColor(), testColor);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
}
}
@@ -1409,19 +1418,19 @@ void tst_qquicktext::smooth()
QString componentStr = "import QtQuick 2.0\nText { smooth: false; text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->smooth(), false);
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->smooth(), true);
-
- delete textObject;
}
}
for (int i = 0; i < richText.size(); i++)
@@ -1430,19 +1439,19 @@ void tst_qquicktext::smooth()
QString componentStr = "import QtQuick 2.0\nText { smooth: false; text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->smooth(), false);
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject != nullptr, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->smooth(), true);
-
- delete textObject;
}
}
}
@@ -1461,14 +1470,14 @@ void tst_qquicktext::renderType()
text->setRenderType(QQuickText::NativeRendering);
QCOMPARE(text->renderType(), QQuickText::NativeRendering);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
text->setRenderType(QQuickText::NativeRendering);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
text->setRenderType(QQuickText::QtRendering);
QCOMPARE(text->renderType(), QQuickText::QtRendering);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
void tst_qquicktext::antialiasing()
@@ -1485,14 +1494,14 @@ void tst_qquicktext::antialiasing()
text->setAntialiasing(false);
QCOMPARE(text->antialiasing(), false);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
text->setAntialiasing(false);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
text->resetAntialiasing();
QCOMPARE(text->antialiasing(), true);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
// QTBUG-39047
component.setData("import QtQuick 2.0\n Text { antialiasing: true }", QUrl());
@@ -1508,23 +1517,21 @@ void tst_qquicktext::weight()
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE((int)textObject->font().weight(), int(QQuickFontEnums::Normal));
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { font.weight: Font.Bold; text: \"Hello world!\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE((int)textObject->font().weight(), int(QQuickFontEnums::Bold));
-
- delete textObject;
}
}
@@ -1573,56 +1580,51 @@ void tst_qquicktext::capitalization()
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE((int)textObject->font().capitalization(), int(QQuickFontEnums::MixedCase));
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE((int)textObject->font().capitalization(), int(QQuickFontEnums::AllUppercase));
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE((int)textObject->font().capitalization(), int(QQuickFontEnums::AllLowercase));
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE((int)textObject->font().capitalization(), int(QQuickFontEnums::SmallCaps));
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE((int)textObject->font().capitalization(), int(QQuickFontEnums::Capitalize));
-
- delete textObject;
}
}
@@ -1632,34 +1634,31 @@ void tst_qquicktext::letterSpacing()
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->font().letterSpacing(), 0.0);
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->font().letterSpacing(), -2.);
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->font().letterSpacing(), 3.);
-
- delete textObject;
}
}
@@ -1669,34 +1668,31 @@ void tst_qquicktext::wordSpacing()
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->font().wordSpacing(), 0.0);
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->font().wordSpacing(), -50.);
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->font().wordSpacing(), 200.);
-
- delete textObject;
}
}
@@ -1823,10 +1819,6 @@ public:
QTextLayout layout;
};
-
-typedef QVector<QPointF> PointVector;
-Q_DECLARE_METATYPE(PointVector);
-
void tst_qquicktext::linkInteraction_data()
{
QTest::addColumn<QString>("text");
@@ -2088,7 +2080,8 @@ void tst_qquicktext::linkInteraction()
"}";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
@@ -2096,14 +2089,15 @@ void tst_qquicktext::linkInteraction()
QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
QObject::connect(textObject, SIGNAL(linkHovered(QString)), &test, SLOT(linkHovered(QString)));
- QVERIFY(mousePositions.count() > 0);
+ QVERIFY(mousePositions.size() > 0);
QPointF mousePosition = mousePositions.first();
+ auto globalPos = textObject->mapToGlobal(mousePosition);
{
- QHoverEvent he(QEvent::HoverEnter, mousePosition, QPointF());
+ QHoverEvent he(QEvent::HoverEnter, mousePosition, globalPos, QPointF());
static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&he);
- QMouseEvent me(QEvent::MouseButtonPress, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+ QMouseEvent me(QEvent::MouseButtonPress, mousePosition, globalPos, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
}
@@ -2111,13 +2105,14 @@ void tst_qquicktext::linkInteraction()
QCOMPARE(textObject->hoveredLink(), hoverEnterLink);
QCOMPARE(textObject->linkAt(mousePosition.x(), mousePosition.y()), hoverEnterLink);
- for (int i = 1; i < mousePositions.count(); ++i) {
+ for (int i = 1; i < mousePositions.size(); ++i) {
mousePosition = mousePositions.at(i);
+ auto globalPos = textObject->mapToGlobal(mousePosition);
- QHoverEvent he(QEvent::HoverMove, mousePosition, QPointF());
+ QHoverEvent he(QEvent::HoverMove, mousePosition, globalPos, QPointF());
static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&he);
- QMouseEvent me(QEvent::MouseMove, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+ QMouseEvent me(QEvent::MouseMove, mousePosition, globalPos, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
}
@@ -2126,10 +2121,10 @@ void tst_qquicktext::linkInteraction()
QCOMPARE(textObject->linkAt(mousePosition.x(), mousePosition.y()), hoverMoveLink);
{
- QHoverEvent he(QEvent::HoverLeave, mousePosition, QPointF());
+ QHoverEvent he(QEvent::HoverLeave, mousePosition, globalPos, QPointF());
static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&he);
- QMouseEvent me(QEvent::MouseButtonRelease, mousePosition, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
+ QMouseEvent me(QEvent::MouseButtonRelease, mousePosition, globalPos, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
static_cast<EventSender*>(static_cast<QQuickItem*>(textObject))->sendEvent(&me);
}
@@ -2137,8 +2132,6 @@ void tst_qquicktext::linkInteraction()
QCOMPARE(test.hoveredLink, QString());
QCOMPARE(textObject->hoveredLink(), QString());
QCOMPARE(textObject->linkAt(-1, -1), QString());
-
- delete textObject;
}
void tst_qquicktext::baseUrl()
@@ -2149,6 +2142,7 @@ void tst_qquicktext::baseUrl()
QQmlComponent textComponent(&engine);
textComponent.setData("import QtQuick 2.0\n Text {}", localUrl);
QQuickText *textObject = qobject_cast<QQuickText *>(textComponent.create());
+ QVERIFY2(textObject, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->baseUrl(), localUrl);
@@ -2156,25 +2150,28 @@ void tst_qquicktext::baseUrl()
textObject->setBaseUrl(localUrl);
QCOMPARE(textObject->baseUrl(), localUrl);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
textObject->setBaseUrl(remoteUrl);
QCOMPARE(textObject->baseUrl(), remoteUrl);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
textObject->resetBaseUrl();
QCOMPARE(textObject->baseUrl(), localUrl);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
void tst_qquicktext::embeddedImages_data()
{
+ // Cancel some mess left by clipRectOutsideViewportDynamicallyChanged():
+ qmlClearTypeRegistrations();
+
QTest::addColumn<QUrl>("qmlfile");
QTest::addColumn<QString>("error");
QTest::newRow("local") << testFileUrl("embeddedImagesLocal.qml") << "";
QTest::newRow("local-error") << testFileUrl("embeddedImagesLocalError.qml")
<< testFileUrl("embeddedImagesLocalError.qml").toString()+":3:1: QML Text: Cannot open: " + testFileUrl("http/notexists.png").toString();
- QTest::newRow("local") << testFileUrl("embeddedImagesLocalRelative.qml") << "";
+ QTest::newRow("local-relative") << testFileUrl("embeddedImagesLocalRelative.qml") << "";
QTest::newRow("remote") << testFileUrl("embeddedImagesRemote.qml") << "";
QTest::newRow("remote-error") << testFileUrl("embeddedImagesRemoteError.qml")
<< testFileUrl("embeddedImagesRemoteError.qml").toString()+":3:1: QML Text: Error transferring {{ServerBaseUrl}}/notexists.png - server replied: Not found";
@@ -2188,14 +2185,6 @@ void tst_qquicktext::embeddedImages()
QFETCH(QUrl, qmlfile);
QFETCH(QString, error);
-#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
- if (qstrcmp(QTest::currentDataTag(), "remote") == 0
- || qstrcmp(QTest::currentDataTag(), "remote-error") == 0
- || qstrcmp(QTest::currentDataTag(), "remote-relative") == 0) {
- QSKIP("Remote tests cause occasional hangs in the CI system -- QTBUG-45655");
- }
-#endif
-
TestHTTPServer server;
QVERIFY2(server.listen(), qPrintable(server.errorString()));
server.serveDirectory(testFile("http"));
@@ -2204,13 +2193,10 @@ void tst_qquicktext::embeddedImages()
if (!error.isEmpty())
QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
- QQuickView *view = new QQuickView;
- view->rootContext()->setContextProperty(QStringLiteral("serverBaseUrl"), server.baseUrl());
- view->setSource(qmlfile);
- view->show();
- view->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(view));
- QQuickText *textObject = qobject_cast<QQuickText*>(view->rootObject());
+ QQuickView view;
+ view.rootContext()->setContextProperty(QStringLiteral("serverBaseUrl"), server.baseUrl());
+ QVERIFY(QQuickTest::showView(view, qmlfile));
+ QQuickText *textObject = qobject_cast<QQuickText*>(view.rootObject());
QVERIFY(textObject != nullptr);
QTRY_COMPARE(textObject->resourcesLoading(), 0);
@@ -2225,7 +2211,9 @@ void tst_qquicktext::embeddedImages()
QCOMPARE(textObject->height(), 16.0);
}
- delete view;
+ // QTextDocument images are cached in QTextDocumentPrivate::cachedResources,
+ // so verify that we don't redundantly cache them in QQuickPixmapCache
+ QCOMPARE(QQuickPixmapCache::instance()->m_cache.size(), 0);
}
void tst_qquicktext::lineCount()
@@ -2364,6 +2352,10 @@ void tst_qquicktext::implicitSize_data()
void tst_qquicktext::implicitSize()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("This segfaults on Android, QTBUG-103096");
+#endif
+
QFETCH(QString, text);
QFETCH(QString, width);
QFETCH(QString, format);
@@ -2379,7 +2371,9 @@ void tst_qquicktext::implicitSize()
"maximumLineCount: 2 }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
+ QVERIFY2(textObject, qPrintable(textComponent.errorString()));
QVERIFY(textObject->width() < textObject->implicitWidth());
QCOMPARE(textObject->height(), textObject->implicitHeight());
@@ -2388,8 +2382,20 @@ void tst_qquicktext::implicitSize()
textObject->resetWidth();
QCOMPARE(textObject->width(), textObject->implicitWidth());
QCOMPARE(textObject->height(), textObject->implicitHeight());
+}
+
+void tst_qquicktext::implicitSizeMaxLineCount()
+{
+ QScopedPointer<QQuickText> textObject(new QQuickText);
- delete textObject;
+ textObject->setText("1st line");
+ const auto referenceWidth = textObject->implicitWidth();
+
+ textObject->setText(textObject->text() + "\n2nd long long long long long line");
+ QCOMPARE_GT(textObject->implicitWidth(), referenceWidth);
+
+ textObject->setMaximumLineCount(1);
+ QCOMPARE_EQ(textObject->implicitWidth(), referenceWidth);
}
void tst_qquicktext::dependentImplicitSizes()
@@ -2455,6 +2461,7 @@ void tst_qquicktext::contentSize()
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(textComponent.create());
QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
+ QVERIFY2(textObject, qPrintable(textComponent.errorString()));
QSignalSpy spySize(textObject, SIGNAL(contentSizeChanged()));
QSignalSpy spyWidth(textObject, SIGNAL(contentWidthChanged(qreal)));
@@ -2464,23 +2471,23 @@ void tst_qquicktext::contentSize()
QVERIFY(textObject->contentWidth() > textObject->width());
QVERIFY(textObject->contentHeight() < textObject->height());
- QCOMPARE(spySize.count(), 1);
- QCOMPARE(spyWidth.count(), 1);
- QCOMPARE(spyHeight.count(), 0);
+ QCOMPARE(spySize.size(), 1);
+ QCOMPARE(spyWidth.size(), 1);
+ QCOMPARE(spyHeight.size(), 0);
textObject->setWrapMode(QQuickText::WordWrap);
QVERIFY(textObject->contentWidth() <= textObject->width());
QVERIFY(textObject->contentHeight() > textObject->height());
- QCOMPARE(spySize.count(), 2);
- QCOMPARE(spyWidth.count(), 2);
- QCOMPARE(spyHeight.count(), 1);
+ QCOMPARE(spySize.size(), 2);
+ QCOMPARE(spyWidth.size(), 2);
+ QCOMPARE(spyHeight.size(), 1);
textObject->setElideMode(QQuickText::ElideRight);
QVERIFY(textObject->contentWidth() <= textObject->width());
QVERIFY(textObject->contentHeight() < textObject->height());
- QCOMPARE(spySize.count(), 3);
- QCOMPARE(spyWidth.count(), 3);
- QCOMPARE(spyHeight.count(), 2);
+ QCOMPARE(spySize.size(), 3);
+ QCOMPARE(spyWidth.size(), 3);
+ QCOMPARE(spyHeight.size(), 2);
int spyCount = 3;
qreal elidedWidth = textObject->contentWidth();
@@ -2489,16 +2496,16 @@ void tst_qquicktext::contentSize()
QVERIFY(textObject->contentHeight() < textObject->height());
// this text probably won't have the same elided width, but it's not guaranteed.
if (textObject->contentWidth() != elidedWidth)
- QCOMPARE(spySize.count(), ++spyCount);
+ QCOMPARE(spySize.size(), ++spyCount);
else
- QCOMPARE(spySize.count(), spyCount);
+ QCOMPARE(spySize.size(), spyCount);
textObject->setElideMode(QQuickText::ElideNone);
QVERIFY(textObject->contentWidth() > textObject->width());
QVERIFY(textObject->contentHeight() > textObject->height());
- QCOMPARE(spySize.count(), ++spyCount);
- QCOMPARE(spyWidth.count(), spyCount);
- QCOMPARE(spyHeight.count(), 3);
+ QCOMPARE(spySize.size(), ++spyCount);
+ QCOMPARE(spyWidth.size(), spyCount);
+ QCOMPARE(spyHeight.size(), 3);
}
void tst_qquicktext::geometryChanged()
@@ -2512,6 +2519,7 @@ void tst_qquicktext::geometryChanged()
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(textComponent.create());
QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
+ QVERIFY2(textObject, qPrintable(textComponent.errorString()));
const qreal implicitHeight = textObject->implicitHeight();
@@ -2771,6 +2779,7 @@ void tst_qquicktext::implicitSizeBinding()
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
QScopedPointer<QObject> object(textComponent.create());
QQuickText *textObject = qobject_cast<QQuickText *>(object.data());
+ QVERIFY2(textObject, qPrintable(textComponent.errorString()));
QCOMPARE(textObject->width(), textObject->implicitWidth());
QCOMPARE(textObject->height(), textObject->implicitHeight());
@@ -2938,6 +2947,128 @@ void tst_qquicktext::clipRect()
QCOMPARE(text->clipRect().height(), text->height() + 2);
}
+void tst_qquicktext::largeTextObservesViewport_data()
+{
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<QQuickText::TextFormat>("textFormat");
+ QTest::addColumn<int>("linesAboveViewport");
+ QTest::addColumn<bool>("parentIsViewport");
+
+ QString text;
+ {
+ QStringList lines;
+ // "line 100" is 8 characters; many lines are longer, some are shorter
+ // so we populate 1250 lines, 11389 characters
+ const int lineCount = QQuickTextPrivate::largeTextSizeThreshold / 8;
+ lines.reserve(lineCount);
+ for (int i = 0; i < lineCount; ++i)
+ lines << QLatin1String("line ") + QString::number(i);
+ text = lines.join('\n');
+ }
+ Q_ASSERT(text.size() > QQuickTextPrivate::largeTextSizeThreshold);
+
+ // by default, the root item acts as the viewport:
+ // QSGInternalTextNode doesn't populate lines of text beyond the bottom of the window
+ QTest::newRow("default plain text") << text << QQuickText::PlainText << 0 << false;
+ // make the rectangle into a viewport item, and move the text upwards:
+ // QSGInternalTextNode doesn't populate lines of text beyond the bottom of the viewport rectangle
+ QTest::newRow("clipped plain text") << text << QQuickText::PlainText << 10 << true;
+
+ {
+ QStringList lines;
+ // "line 100" is 8 characters; many lines are longer, some are shorter
+ // so we populate 1250 lines, 11389 characters
+ const int lineCount = QQuickTextPrivate::largeTextSizeThreshold / 8;
+ lines.reserve(lineCount);
+ for (int i = 0; i < lineCount; ++i) {
+ if (i > 0 && i % 50 == 0)
+ lines << QLatin1String("<h1>chapter ") + QString::number(i / 50) + QLatin1String("</h1>");
+ lines << QLatin1String("<p>line ") + QString::number(i) + QLatin1String("</p>");
+ }
+ text = lines.join('\n');
+ }
+ Q_ASSERT(text.size() > QQuickTextPrivate::largeTextSizeThreshold);
+
+ // by default, the root item acts as the viewport:
+ // QQuickTextNodeEngine doesn't populate blocks beyond the bottom of the window
+ QTest::newRow("default styled text") << text << QQuickText::StyledText << 0 << false;
+ // make the rectangle into a viewport item, and move the text upwards:
+ // QQuickTextNodeEngine doesn't populate blocks that don't intersect the viewport rectangle
+ QTest::newRow("clipped styled text") << text << QQuickText::StyledText << 10 << true;
+ // get a chapter heading into the viewport
+ QTest::newRow("heading visible") << text << QQuickText::StyledText << 90 << true;
+}
+
+void tst_qquicktext::largeTextObservesViewport()
+{
+ QFETCH(QString, text);
+ QFETCH(QQuickText::TextFormat, textFormat);
+ QFETCH(int, linesAboveViewport);
+ QFETCH(bool, parentIsViewport);
+
+ QQuickView window;
+ QByteArray errorMessage;
+ QVERIFY2(QQuickTest::initView(window, testFileUrl("viewport.qml"), true, &errorMessage), errorMessage.constData());
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QQuickText *textItem = window.rootObject()->findChild<QQuickText*>();
+ QVERIFY(textItem);
+ QQuickItem *viewportItem = textItem->parentItem();
+ QQuickTextPrivate *textPriv = QQuickTextPrivate::get(textItem);
+ QSGInternalTextNode *node = static_cast<QSGInternalTextNode *>(textPriv->paintNode);
+ QFontMetricsF fm(textItem->font());
+ const qreal expectedTextHeight = (parentIsViewport ? viewportItem->height() : window.height() - viewportItem->y());
+ const qreal lineSpacing = qCeil(fm.height());
+ // A paragraph break is the same as an extra line break; so since our "lines" are paragraphs in StyledText,
+ // visually, with StyledText we skip down 10 "lines", but the first paragraph you see says "line 5".
+ // It's OK anyway for the test, because QSGTextNode::addTextLayout() treats the paragraph breaks like lines of text.
+ const int expectedLastLine = linesAboveViewport + int(expectedTextHeight / lineSpacing);
+
+ viewportItem->setFlag(QQuickItem::ItemIsViewport, parentIsViewport);
+ textItem->setY(lineSpacing * -linesAboveViewport);
+ textItem->setTextFormat(textFormat);
+ textItem->setText(text);
+ qCDebug(lcTests) << "text size" << textItem->text().size() << "lines" << textItem->lineCount() << "font" << textItem->font();
+ Q_ASSERT(textItem->text().size() > QQuickTextPrivate::largeTextSizeThreshold);
+ QVERIFY(textItem->flags().testFlag(QQuickItem::ItemObservesViewport)); // large text sets this flag automatically
+ QCOMPARE(textItem->viewportItem(), parentIsViewport ? viewportItem : viewportItem->parentItem());
+ QTRY_VERIFY(node->renderedLineRange().first >= 0); // wait for rendering
+ auto renderedLineRange = node->renderedLineRange();
+ qCDebug(lcTests) << "first line rendered" << renderedLineRange.first
+ << "expected" << linesAboveViewport
+ << "first line past viewport" << renderedLineRange.second
+ << "expected last line" << expectedLastLine
+ << "based on available height" << expectedTextHeight
+ << "and line height" << lineSpacing << "rather than spacing" << fm.lineSpacing();
+// QTest::qWait(2000); // uncomment for visual check
+ QCOMPARE(renderedLineRange.first, linesAboveViewport);
+ // if linesAboveViewport == 90, a chapter heading is visible, and those take more space
+ QVERIFY(qAbs(renderedLineRange.second - (expectedLastLine + 1)) < (linesAboveViewport > 80 ? 4 : 2));
+}
+
+void tst_qquicktext::largeTextInDelayedLoader() // QTBUG-115687
+{
+ QQuickView view;
+ QVERIFY(QQuickTest::showView(view, testFileUrl("loaderActiveOnVisible.qml")));
+ auto flick = view.rootObject()->findChild<QQuickFlickable*>();
+ QVERIFY(flick);
+ auto textItem = view.rootObject()->findChild<QQuickText*>();
+ QVERIFY(textItem);
+ QQuickTextPrivate *textPriv = QQuickTextPrivate::get(textItem);
+ QSGInternalTextNode *node = static_cast<QSGInternalTextNode *>(textPriv->paintNode);
+ const auto initialLineRange = node->renderedLineRange();
+ qCDebug(lcTests) << "first line rendered" << initialLineRange.first
+ << "; first line past viewport" << initialLineRange.second;
+ flick->setContentY(500);
+ QTRY_COMPARE_NE(node->renderedLineRange(), initialLineRange);
+ const auto scrolledLineRange = node->renderedLineRange();
+ qCDebug(lcTests) << "after scroll: first line rendered" << scrolledLineRange.first
+ << "; first line past viewport" << scrolledLineRange.second;
+ // We scrolled a good bit more than one window-height, so we must render a
+ // non-overlapping range of text some distance past the initial blocks.
+ QCOMPARE_GT(scrolledLineRange.first, initialLineRange.second);
+}
+
void tst_qquicktext::lineLaidOut()
{
QScopedPointer<QQuickView> window(createView(testFile("lineLayout.qml")));
@@ -2952,11 +3083,11 @@ void tst_qquicktext::lineLaidOut()
for (int i = 0; i < textPrivate->layout.lineCount(); ++i) {
QRectF r = textPrivate->layout.lineAt(i).rect();
- QVERIFY(r.width() == i * 15);
+ QCOMPARE(r.width(), i * 15);
if (i >= 30)
- QVERIFY(r.x() == r.width() + 30);
+ QCOMPARE(r.x(), r.width() + 30);
if (i >= 60) {
- QVERIFY(r.x() == r.width() * 2 + 60);
+ QCOMPARE(r.x(), r.width() * 2 + 60);
QCOMPARE(r.height(), qreal(20));
}
}
@@ -3001,6 +3132,29 @@ void tst_qquicktext::lineLaidOutRelayout()
}
}
+void tst_qquicktext::lineLaidOutFontUpdate()
+{
+ QScopedPointer<QQuickView> window(createView(testFile("lineLayoutFontUpdate.qml")));
+
+ window->show();
+ window->requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(window.data()));
+
+ auto *myText = window->rootObject()->findChild<QQuickText*>("exampleText");
+ QVERIFY(myText != nullptr);
+
+ QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
+ QVERIFY(textPrivate != nullptr);
+
+ QCOMPARE(textPrivate->layout.lineCount(), 2);
+
+ QTextLine firstLine = textPrivate->layout.lineAt(0);
+ QTextLine secondLine = textPrivate->layout.lineAt(1);
+
+ QCOMPARE(firstLine.rect().x(), secondLine.rect().x() + 40);
+ QCOMPARE(firstLine.rect().width(), secondLine.rect().width() - 40);
+}
+
void tst_qquicktext::lineLaidOutHAlign()
{
QScopedPointer<QQuickView> window(createView(testFile("lineLayoutHAlign.qml")));
@@ -3165,12 +3319,12 @@ void tst_qquicktext::imgTagsAlign_data()
QTest::addColumn<QString>("src");
QTest::addColumn<int>("imgHeight");
QTest::addColumn<QString>("align");
- QTest::newRow("heart-bottom") << "data/images/heart200.png" << 181 << "bottom";
- QTest::newRow("heart-middle") << "data/images/heart200.png" << 181 << "middle";
- QTest::newRow("heart-top") << "data/images/heart200.png" << 181 << "top";
- QTest::newRow("starfish-bottom") << "data/images/starfish_2.png" << 217 << "bottom";
- QTest::newRow("starfish-middle") << "data/images/starfish_2.png" << 217 << "middle";
- QTest::newRow("starfish-top") << "data/images/starfish_2.png" << 217 << "top";
+ QTest::newRow("heart-bottom") << "images/heart200.png" << 181 << "bottom";
+ QTest::newRow("heart-middle") << "images/heart200.png" << 181 << "middle";
+ QTest::newRow("heart-top") << "images/heart200.png" << 181 << "top";
+ QTest::newRow("starfish-bottom") << "images/starfish_2.png" << 217 << "bottom";
+ QTest::newRow("starfish-middle") << "images/starfish_2.png" << 217 << "middle";
+ QTest::newRow("starfish-top") << "images/starfish_2.png" << 217 << "top";
}
void tst_qquicktext::imgTagsAlign()
@@ -3180,8 +3334,9 @@ void tst_qquicktext::imgTagsAlign()
QFETCH(QString, align);
QString componentStr = "import QtQuick 2.0\nText { text: \"This is a test <img src=\\\"" + src + "\\\" align=\\\"" + align + "\\\"> of image.\" }";
QQmlComponent textComponent(&engine);
- textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("."));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ textComponent.setData(componentStr.toLatin1(), testFileUrl("."));
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->height(), qreal(imgHeight));
@@ -3196,80 +3351,77 @@ void tst_qquicktext::imgTagsAlign()
QVERIFY(br.y() == imgHeight / 2.0 - br.height() / 2.0);
else if (align == "top")
QCOMPARE(br.y(), qreal(0));
-
- delete textObject;
}
void tst_qquicktext::imgTagsMultipleImages()
{
- QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"data/images/starfish_2.png\\\" width=\\\"60\\\" height=\\\"60\\\" > and another one<img src=\\\"data/images/heart200.png\\\" width=\\\"85\\\" height=\\\"85\\\">.\" }";
+ QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"images/starfish_2.png\\\" width=\\\"60\\\" height=\\\"60\\\" > and another one<img src=\\\"images/heart200.png\\\" width=\\\"85\\\" height=\\\"85\\\">.\" }";
QQmlComponent textComponent(&engine);
- textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile("."));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ textComponent.setData(componentStr.toLatin1(), testFileUrl("."));
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE(textObject->height(), qreal(85));
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
QVERIFY(textPrivate != nullptr);
- QCOMPARE(textPrivate->extra->visibleImgTags.count(), 2);
-
- delete textObject;
+ QCOMPARE(textPrivate->extra->visibleImgTags.size(), 2);
}
void tst_qquicktext::imgTagsElide()
{
QScopedPointer<QQuickView> window(createView(testFile("imgTagsElide.qml")));
- QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
- QVERIFY(myText != nullptr);
+ QScopedPointer<QQuickText> myText(window->rootObject()->findChild<QQuickText*>("myText"));
+ QVERIFY(myText);
- QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
+ QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText.data());
QVERIFY(textPrivate != nullptr);
- QCOMPARE(textPrivate->extra->visibleImgTags.count(), 0);
+ QCOMPARE(textPrivate->extra->visibleImgTags.size(), 0);
myText->setMaximumLineCount(20);
- QTRY_COMPARE(textPrivate->extra->visibleImgTags.count(), 1);
-
- delete myText;
+ QTRY_COMPARE(textPrivate->extra->visibleImgTags.size(), 1);
}
void tst_qquicktext::imgTagsUpdates()
{
QScopedPointer<QQuickView> window(createView(testFile("imgTagsUpdates.qml")));
- QQuickText *myText = window->rootObject()->findChild<QQuickText*>("myText");
- QVERIFY(myText != nullptr);
+ QScopedPointer<QQuickText> myText(window->rootObject()->findChild<QQuickText*>("myText"));
+ QVERIFY(myText);
- QSignalSpy spy(myText, SIGNAL(contentSizeChanged()));
+ QSignalSpy spy(myText.data(), SIGNAL(contentSizeChanged()));
- QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText);
+ QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(myText.data());
QVERIFY(textPrivate != nullptr);
myText->setText("This is a heart<img src=\"images/heart200.png\">.");
- QCOMPARE(textPrivate->extra->visibleImgTags.count(), 1);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(textPrivate->extra->visibleImgTags.size(), 1);
+ QCOMPARE(spy.size(), 1);
myText->setMaximumLineCount(2);
myText->setText("This is another heart<img src=\"images/heart200.png\">.");
- QTRY_COMPARE(textPrivate->extra->visibleImgTags.count(), 1);
+ QTRY_COMPARE(textPrivate->extra->visibleImgTags.size(), 1);
// if maximumLineCount is set and the img tag doesn't have an explicit size
// we relayout twice.
- QCOMPARE(spy.count(), 3);
-
- delete myText;
+ QCOMPARE(spy.size(), 3);
}
void tst_qquicktext::imgTagsError()
{
- QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"data/images/starfish_2.pn\\\" width=\\\"60\\\" height=\\\"60\\\">.\" }";
+ QString componentStr = "import QtQuick 2.0\nText { text: \"This is a starfish<img src=\\\"images/starfish_2.pn\\\" width=\\\"60\\\" height=\\\"60\\\">.\" }";
QQmlComponent textComponent(&engine);
- QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:2:1: QML Text: Cannot open: file:data/images/starfish_2.pn");
- textComponent.setData(componentStr.toLatin1(), QUrl("file:"));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ const QString expectedMessage(
+ testFileUrl(".").toString()
+ + ":2:1: QML Text: Cannot open: "
+ + testFileUrl("images/starfish_2.pn").toString());
+ QTest::ignoreMessage(QtWarningMsg, expectedMessage.toLatin1());
+ textComponent.setData(componentStr.toLatin1(), testFileUrl("."));
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
- delete textObject;
}
void tst_qquicktext::fontSizeMode_data()
@@ -3290,7 +3442,7 @@ void tst_qquicktext::fontSizeMode()
QVERIFY(myText != nullptr);
myText->setText(text);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
qreal originalWidth = myText->contentWidth();
qreal originalHeight = myText->contentHeight();
@@ -3304,7 +3456,7 @@ void tst_qquicktext::fontSizeMode()
myText->setFont(font);
myText->setFontSizeMode(QQuickText::HorizontalFit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// Font size reduced to fit within the width of the item.
qreal horizontalFitWidth = myText->contentWidth();
qreal horizontalFitHeight = myText->contentHeight();
@@ -3313,28 +3465,28 @@ void tst_qquicktext::fontSizeMode()
// Elide won't affect the size with HorizontalFit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideLeft);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideMiddle);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::VerticalFit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// Font size increased to fill the height of the item.
qreal verticalFitHeight = myText->contentHeight();
QVERIFY(myText->contentWidth() > myText->width());
@@ -3343,57 +3495,57 @@ void tst_qquicktext::fontSizeMode()
// Elide won't affect the height of a single line with VerticalFit but will crop the width.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(myText->truncated());
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideLeft);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(myText->truncated());
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideMiddle);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(myText->truncated());
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::Fit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// Should be the same as HorizontalFit with no wrapping.
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
// Elide won't affect the size with Fit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideLeft);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideMiddle);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::FixedSize);
myText->setWrapMode(QQuickText::Wrap);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
originalWidth = myText->contentWidth();
originalHeight = myText->contentHeight();
@@ -3403,7 +3555,7 @@ void tst_qquicktext::fontSizeMode()
QVERIFY(originalHeight > myText->height());
myText->setFontSizeMode(QQuickText::HorizontalFit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
// same size as without text wrapping.
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
@@ -3411,16 +3563,16 @@ void tst_qquicktext::fontSizeMode()
// Elide won't affect the size with HorizontalFit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::VerticalFit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// VerticalFit should reduce the size to the wrapped text within the vertical height.
verticalFitHeight = myText->contentHeight();
qreal verticalFitWidth = myText->contentWidth();
@@ -3430,40 +3582,40 @@ void tst_qquicktext::fontSizeMode()
// Elide won't affect the height or width of a wrapped text with VerticalFit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::Fit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// Should be the same as VerticalFit with wrapping.
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
// Elide won't affect the size with Fit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::FixedSize);
myText->setMaximumLineCount(2);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// The original text wrapped should exceed the height of the item.
QVERIFY(originalWidth <= myText->width() + 2);
QVERIFY(originalHeight > myText->height());
myText->setFontSizeMode(QQuickText::HorizontalFit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
// same size as without text wrapping.
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
@@ -3471,16 +3623,16 @@ void tst_qquicktext::fontSizeMode()
// Elide won't affect the size with HorizontalFit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::VerticalFit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// VerticalFit should reduce the size to the wrapped text within the vertical height.
verticalFitHeight = myText->contentHeight();
verticalFitWidth = myText->contentWidth();
@@ -3490,29 +3642,69 @@ void tst_qquicktext::fontSizeMode()
// Elide won't affect the height or width of a wrapped text with VerticalFit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::Fit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// Should be the same as VerticalFit with wrapping.
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
// Elide won't affect the size with Fit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
+
+ // Growing height needs to update the baselineOffset when AlignBottom is used
+ // and text is NOT wrapped
+ myText->setVAlign(QQuickText::AlignBottom);
+ myText->setFontSizeMode(QQuickText::Fit);
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
+
+ int baselineOffset = myText->baselineOffset();
+ myText->setHeight(myText->height() * 2);
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
+ QVERIFY(myText->baselineOffset() > baselineOffset);
+
+ // Growing height needs to update the baselineOffset when AlignBottom is used
+ // and the text is wrapped
+ myText->setVAlign(QQuickText::AlignBottom);
+ myText->setFontSizeMode(QQuickText::Fit);
+ myText->setWrapMode(QQuickText::NoWrap);
+ myText->resetMaximumLineCount();
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
+
+ baselineOffset = myText->baselineOffset();
+ myText->setHeight(myText->height() * 2);
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
+ QVERIFY(myText->baselineOffset() > baselineOffset);
+
+ // Check baselineOffset for the HorizontalFit case
+ myText->setVAlign(QQuickText::AlignBottom);
+ myText->setFontSizeMode(QQuickText::HorizontalFit);
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
+ QSignalSpy baselineOffsetSpy(myText, SIGNAL(baselineOffsetChanged(qreal)));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
+ const qreal oldBaselineOffset = myText->baselineOffset();
+ myText->setHeight(myText->height() + 42);
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
+ QCOMPARE(baselineOffsetSpy.size(), 1);
+ QCOMPARE(myText->baselineOffset(), oldBaselineOffset + 42);
+ myText->setHeight(myText->height() - 42);
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
+ QCOMPARE(baselineOffsetSpy.size(), 2);
+ QCOMPARE(myText->baselineOffset(), oldBaselineOffset);
}
void tst_qquicktext::fontSizeModeMultiline_data()
@@ -3533,7 +3725,7 @@ void tst_qquicktext::fontSizeModeMultiline()
QVERIFY(myText != nullptr);
myText->setText(text);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
qreal originalWidth = myText->contentWidth();
qreal originalHeight = myText->contentHeight();
@@ -3548,7 +3740,7 @@ void tst_qquicktext::fontSizeModeMultiline()
myText->setFont(font);
myText->setFontSizeMode(QQuickText::HorizontalFit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// Font size reduced to fit within the width of the item.
QCOMPARE(myText->lineCount(), 2);
qreal horizontalFitWidth = myText->contentWidth();
@@ -3558,7 +3750,7 @@ void tst_qquicktext::fontSizeModeMultiline()
// Right eliding will remove the last line
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(myText->truncated());
QCOMPARE(myText->lineCount(), 1);
QVERIFY(myText->contentWidth() <= myText->width() + 2);
@@ -3566,22 +3758,22 @@ void tst_qquicktext::fontSizeModeMultiline()
// Left or middle eliding wont have any effect.
myText->setElideMode(QQuickText::ElideLeft);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideMiddle);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
QCOMPARE(myText->contentHeight(), horizontalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::VerticalFit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// Font size reduced to fit within the height of the item.
qreal verticalFitWidth = myText->contentWidth();
qreal verticalFitHeight = myText->contentHeight();
@@ -3590,58 +3782,58 @@ void tst_qquicktext::fontSizeModeMultiline()
// Elide will have no effect.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideLeft);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideMiddle);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::Fit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// Should be the same as VerticalFit with no wrapping.
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
// Elide won't affect the size with Fit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideLeft);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideMiddle);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::FixedSize);
myText->setWrapMode(QQuickText::Wrap);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
originalWidth = myText->contentWidth();
originalHeight = myText->contentHeight();
@@ -3651,7 +3843,7 @@ void tst_qquicktext::fontSizeModeMultiline()
QVERIFY(originalHeight > myText->height());
myText->setFontSizeMode(QQuickText::HorizontalFit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
// same size as without text wrapping.
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
@@ -3659,16 +3851,16 @@ void tst_qquicktext::fontSizeModeMultiline()
// Text will be elided vertically with HorizontalFit
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(myText->truncated());
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QVERIFY(myText->contentHeight() <= myText->height() + 2);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::VerticalFit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// VerticalFit should reduce the size to the wrapped text within the vertical height.
verticalFitHeight = myText->contentHeight();
verticalFitWidth = myText->contentWidth();
@@ -3678,40 +3870,40 @@ void tst_qquicktext::fontSizeModeMultiline()
// Elide won't affect the height or width of a wrapped text with VerticalFit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::Fit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// Should be the same as VerticalFit with wrapping.
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
// Elide won't affect the size with Fit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::FixedSize);
myText->setMaximumLineCount(2);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// The original text wrapped should exceed the height of the item.
QVERIFY(originalWidth <= myText->width() + 2);
QVERIFY(originalHeight > myText->height());
myText->setFontSizeMode(QQuickText::HorizontalFit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// HorizontalFit should reduce the font size to minimize wrapping, which brings it back to the
// same size as without text wrapping.
QCOMPARE(myText->contentWidth(), horizontalFitWidth);
@@ -3719,16 +3911,16 @@ void tst_qquicktext::fontSizeModeMultiline()
// Elide won't affect the size with HorizontalFit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(myText->truncated());
QVERIFY(myText->contentWidth() <= myText->width() + 2);
QVERIFY(myText->contentHeight() <= myText->height() + 2);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::VerticalFit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// VerticalFit should reduce the size to the wrapped text within the vertical height.
verticalFitHeight = myText->contentHeight();
verticalFitWidth = myText->contentWidth();
@@ -3738,29 +3930,29 @@ void tst_qquicktext::fontSizeModeMultiline()
// Elide won't affect the height or width of a wrapped text with VerticalFit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
myText->setFontSizeMode(QQuickText::Fit);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
// Should be the same as VerticalFit with wrapping.
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
// Elide won't affect the size with Fit.
myText->setElideMode(QQuickText::ElideRight);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QVERIFY(!myText->truncated());
QCOMPARE(myText->contentWidth(), verticalFitWidth);
QCOMPARE(myText->contentHeight(), verticalFitHeight);
myText->setElideMode(QQuickText::ElideNone);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
}
void tst_qquicktext::multilengthStrings_data()
@@ -3785,17 +3977,17 @@ void tst_qquicktext::multilengthStrings()
const QString shortText = "fox jumped dog";
myText->setText(longText);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
const qreal longWidth = myText->contentWidth();
const qreal longHeight = myText->contentHeight();
myText->setText(mediumText);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
const qreal mediumWidth = myText->contentWidth();
const qreal mediumHeight = myText->contentHeight();
myText->setText(shortText);
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
const qreal shortWidth = myText->contentWidth();
const qreal shortHeight = myText->contentHeight();
@@ -3803,21 +3995,21 @@ void tst_qquicktext::multilengthStrings()
myText->setText(longText + QLatin1Char('\x9c') + mediumText + QLatin1Char('\x9c') + shortText);
myText->setSize(QSizeF(longWidth, longHeight));
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QCOMPARE(myText->contentWidth(), longWidth);
QCOMPARE(myText->contentHeight(), longHeight);
QCOMPARE(myText->truncated(), false);
myText->setSize(QSizeF(mediumWidth, mediumHeight));
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QCOMPARE(myText->contentWidth(), mediumWidth);
QCOMPARE(myText->contentHeight(), mediumHeight);
QCOMPARE(myText->truncated(), true);
myText->setSize(QSizeF(shortWidth, shortHeight));
- QVERIFY(QQuickTest::qWaitForItemPolished(myText));
+ QVERIFY(QQuickTest::qWaitForPolish(myText));
QCOMPARE(myText->contentWidth(), shortWidth);
QCOMPARE(myText->contentHeight(), shortHeight);
@@ -3851,13 +4043,11 @@ void tst_qquicktext::fontFormatSizes()
QFETCH(QString, textWithTag);
QFETCH(bool, fontIsBigger);
- QQuickView *view = new QQuickView;
{
- view->setSource(testFileUrl("pointFontSizes.qml"));
- view->show();
-
- QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
- QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
+ QQuickView view;
+ QVERIFY(QQuickTest::showView(view, testFileUrl("pointFontSizes.qml")));
+ QQuickText *qtext = view.rootObject()->findChild<QQuickText*>("text");
+ QQuickText *qtextWithTag = view.rootObject()->findChild<QQuickText*>("textWithTag");
QVERIFY(qtext != nullptr);
QVERIFY(qtextWithTag != nullptr);
@@ -3865,7 +4055,7 @@ void tst_qquicktext::fontFormatSizes()
qtextWithTag->setText(textWithTag);
for (int size = 6; size < 100; size += 4) {
- view->rootObject()->setProperty("pointSize", size);
+ view.rootObject()->setProperty("pointSize", size);
if (fontIsBigger)
QVERIFY(qtext->height() <= qtextWithTag->height());
else
@@ -3874,9 +4064,10 @@ void tst_qquicktext::fontFormatSizes()
}
{
- view->setSource(testFileUrl("pixelFontSizes.qml"));
- QQuickText *qtext = view->rootObject()->findChild<QQuickText*>("text");
- QQuickText *qtextWithTag = view->rootObject()->findChild<QQuickText*>("textWithTag");
+ QQuickView view;
+ QVERIFY(QQuickTest::showView(view, testFileUrl("pixelFontSizes.qml")));
+ QQuickText *qtext = view.rootObject()->findChild<QQuickText*>("text");
+ QQuickText *qtextWithTag = view.rootObject()->findChild<QQuickText*>("textWithTag");
QVERIFY(qtext != nullptr);
QVERIFY(qtextWithTag != nullptr);
@@ -3884,19 +4075,15 @@ void tst_qquicktext::fontFormatSizes()
qtextWithTag->setText(textWithTag);
for (int size = 6; size < 100; size += 4) {
- view->rootObject()->setProperty("pixelSize", size);
+ view.rootObject()->setProperty("pixelSize", size);
if (fontIsBigger)
QVERIFY(qtext->height() <= qtextWithTag->height());
else
QVERIFY(qtext->height() >= qtextWithTag->height());
}
}
- delete view;
}
-typedef qreal (*ExpectedBaseline)(QQuickText *item);
-Q_DECLARE_METATYPE(ExpectedBaseline)
-
static qreal expectedBaselineTop(QQuickText *item)
{
QFontMetricsF fm(item->font());
@@ -3943,7 +4130,11 @@ static qreal expectedBaselineScaled(QQuickText *item)
{
QFont font = item->font();
QTextLayout layout(item->text().replace(QLatin1Char('\n'), QChar::LineSeparator));
- do {
+
+ qreal low = 0;
+ qreal high = 10000;
+
+ while (low < high) {
layout.setFont(font);
qreal width = 0;
layout.beginLayout();
@@ -3953,12 +4144,23 @@ static qreal expectedBaselineScaled(QQuickText *item)
}
layout.endLayout();
- if (width < item->width()) {
- QFontMetricsF fm(layout.font());
- return fm.ascent() + item->topPadding();
+ if (width > item->width()) {
+ high = font.pointSizeF();
+ font.setPointSizeF((high + low) / 2);
+ } else {
+ low = font.pointSizeF();
+
+ // When fontSizeMode != FixedSize, the font size will be scaled to a value
+ // The goal is to find a pointSize that uses as much space as possible while
+ // still fitting inside the available space. 0.01 is chosen as the threshold.
+ if ((high - low) < qreal(0.01)) {
+ QFontMetricsF fm(layout.font());
+ return fm.ascent() + item->topPadding();
+ }
+
+ font.setPointSizeF((high + low) / 2);
}
- font.setPointSize(font.pointSize() - 1);
- } while (font.pointSize() > 0);
+ }
return item->topPadding();
}
@@ -4046,7 +4248,7 @@ void tst_qquicktext::baselineOffset_data()
QTest::newRow("customLine")
<< "hello world"
<< "hello\nworld"
- << QByteArray("height: 200; onLineLaidOut: line.y += 16")
+ << QByteArray("height: 200; onLineLaidOut: (line) => { line.y += 16; }")
<< &expectedBaselineCustom
<< &expectedBaselineCustom;
@@ -4142,7 +4344,8 @@ void tst_qquicktext::baselineOffset_data()
QTest::newRow("customLine with padding")
<< "hello world"
<< "hello\nworld"
- << QByteArray("height: 200; topPadding: 10; bottomPadding: 20; onLineLaidOut: line.y += 16")
+ << QByteArray("height: 200; topPadding: 10; bottomPadding: 20; "
+ "onLineLaidOut: (line) => { line.y += 16; }")
<< &expectedBaselineCustom
<< &expectedBaselineCustom;
@@ -4240,7 +4443,7 @@ void tst_qquicktext::htmlLists()
QFETCH(QString, text);
QFETCH(int, nbLines);
- QQuickView *view = createView(testFile("htmlLists.qml"));
+ QScopedPointer<QQuickView>view(createView(testFile("htmlLists.qml")));
QQuickText *textObject = view->rootObject()->findChild<QQuickText*>("myText");
QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(textObject);
@@ -4252,11 +4455,9 @@ void tst_qquicktext::htmlLists()
view->show();
view->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(view));
+ QVERIFY(QTest::qWaitForWindowActive(view.get()));
QCOMPARE(textPrivate->extra->doc->lineCount(), nbLines);
-
- delete view;
}
void tst_qquicktext::htmlLists_data()
@@ -4341,9 +4542,9 @@ void tst_qquicktext::padding()
QTRY_COMPARE(window->status(), QQuickView::Ready);
window->show();
QVERIFY(QTest::qWaitForWindowExposed(window.data()));
- QQuickItem *root = window->rootObject();
+ QScopedPointer<QQuickItem> root(window->rootObject());
QVERIFY(root);
- QQuickText *obj = qobject_cast<QQuickText*>(root);
+ QQuickText *obj = qobject_cast<QQuickText*>(root.data());
QVERIFY(obj != nullptr);
qreal cw = obj->contentWidth();
@@ -4380,6 +4581,20 @@ void tst_qquicktext::padding()
obj->setElideMode(QQuickText::ElideRight);
QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding());
QCOMPARE(obj->implicitHeight(), ch + obj->topPadding() + obj->bottomPadding());
+
+ obj->setLeftPadding(0);
+ QCOMPARE(obj->implicitWidth(), cw + obj->leftPadding() + obj->rightPadding());
+
+ obj->setWidth(cw);
+ obj->setRightPadding(cw);
+ QCOMPARE(obj->contentWidth(), 0);
+
+ for (int incr = 1; incr < 50 && qFuzzyIsNull(obj->contentWidth()); ++incr)
+ obj->setWidth(cw + incr);
+ QVERIFY(obj->contentWidth() > 0);
+ qCDebug(lcTests) << "increasing Text width from" << cw << "to" << obj->width()
+ << "rendered a character: contentWidth now" << obj->contentWidth();
+
obj->setElideMode(QQuickText::ElideNone);
obj->resetWidth();
@@ -4420,8 +4635,32 @@ void tst_qquicktext::padding()
QCOMPARE(obj->leftPadding(), 0.0);
QCOMPARE(obj->rightPadding(), 0.0);
QCOMPARE(obj->bottomPadding(), 0.0);
+}
- delete root;
+void tst_qquicktext::paddingInLoader() // QTBUG-83413
+{
+ QQuickView view;
+ QVERIFY(QQuickTest::showView(view, testFileUrl("paddingInLoader.qml")));
+ QQuickText *qtext = view.rootObject()->findChild<QQuickText*>();
+ QVERIFY(qtext);
+ QQuickTextPrivate *textPrivate = QQuickTextPrivate::get(qtext);
+ QVERIFY(textPrivate);
+ QCOMPARE(qtext->contentWidth(), 0); // does not render text, because width == rightPadding
+ QCOMPARE(textPrivate->availableWidth(), 0);
+
+ qtext->setLeftPadding(qtext->width());
+ qtext->setRightPadding(0);
+ QCOMPARE(qtext->contentWidth(), 0); // does not render text, because width == leftPadding
+ QCOMPARE(textPrivate->availableWidth(), 0);
+
+ qtext->setRightPadding(qtext->width());
+ QCOMPARE(qtext->contentWidth(), 0); // does not render text: available space is negative
+ QCOMPARE(textPrivate->availableWidth(), -qtext->width());
+
+ qtext->setLeftPadding(2);
+ qtext->setRightPadding(2);
+ QVERIFY(qtext->contentWidth() > 0); // finally space is available to render text
+ QCOMPARE(textPrivate->availableWidth(), qtext->width() - 4);
}
void tst_qquicktext::hintingPreference()
@@ -4430,23 +4669,21 @@ void tst_qquicktext::hintingPreference()
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE((int)textObject->font().hintingPreference(), (int)QFont::PreferDefaultHinting);
-
- delete textObject;
}
{
QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.hintingPreference: Font.PreferNoHinting }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
- QQuickText *textObject = qobject_cast<QQuickText*>(textComponent.create());
+ QScopedPointer<QObject> object(textComponent.create());
+ QQuickText *textObject = qobject_cast<QQuickText*>(object.data());
QVERIFY(textObject != nullptr);
QCOMPARE((int)textObject->font().hintingPreference(), (int)QFont::PreferNoHinting);
-
- delete textObject;
}
}
@@ -4522,6 +4759,7 @@ void tst_qquicktext::fontInfo()
QScopedPointer<QObject> object(component.create());
QObject *root = object.data();
+ QVERIFY2(root, qPrintable(component.errorString()));
QQuickText *main = root->findChild<QQuickText *>("main");
QVERIFY(main);
@@ -4576,9 +4814,8 @@ void tst_qquicktext::verticallyAlignedImageInTable()
void tst_qquicktext::transparentBackground()
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabToImage not functional on offscreen/minimal platforms");
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("transparentBackground.qml"));
@@ -4597,9 +4834,8 @@ void tst_qquicktext::transparentBackground()
void tst_qquicktext::displaySuperscriptedTag()
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabToImage not functional on offscreen/minimal platforms");
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
QScopedPointer<QQuickView> window(new QQuickView);
window->setSource(testFileUrl("displaySuperscriptedTag.qml"));
@@ -4620,6 +4856,8 @@ void tst_qquicktext::displaySuperscriptedTag()
QCOMPARE(color.green(), 255);
}
+QT_END_NAMESPACE
+
QTEST_MAIN(tst_qquicktext)
#include "tst_qquicktext.moc"
diff --git a/tests/auto/quick/qquicktextdocument/CMakeLists.txt b/tests/auto/quick/qquicktextdocument/CMakeLists.txt
index c2e52317fe..5bcad96b0a 100644
--- a/tests/auto/quick/qquicktextdocument/CMakeLists.txt
+++ b/tests/auto/quick/qquicktextdocument/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquicktextdocument.pro.
#####################################################################
## tst_qquicktextdocument Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicktextdocument LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,16 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquicktextdocument
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_qquicktextdocument.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -30,10 +37,10 @@ qt_internal_add_test(tst_qquicktextdocument
qt_internal_extend_target(tst_qquicktextdocument CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquicktextdocument CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquicktextdocument/data/hello-8857-7.html b/tests/auto/quick/qquicktextdocument/data/hello-8857-7.html
new file mode 100644
index 0000000000..6bf900858a
--- /dev/null
+++ b/tests/auto/quick/qquicktextdocument/data/hello-8857-7.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="iso-8859-7">
+</head>
+<body>
+<p>ÃåéÜ óïõ Êüóìå!</p>
+</body>
+</html>
diff --git a/tests/auto/quick/qquicktextdocument/data/hello-utf16be.html b/tests/auto/quick/qquicktextdocument/data/hello-utf16be.html
new file mode 100644
index 0000000000..be84e0d63c
--- /dev/null
+++ b/tests/auto/quick/qquicktextdocument/data/hello-utf16be.html
Binary files differ
diff --git a/tests/auto/quick/qquicktextdocument/data/hello.html b/tests/auto/quick/qquicktextdocument/data/hello.html
new file mode 100644
index 0000000000..c160cd5e63
--- /dev/null
+++ b/tests/auto/quick/qquicktextdocument/data/hello.html
@@ -0,0 +1 @@
+Γειά σου <i>Κόσμε</i>!
diff --git a/tests/auto/quick/qquicktextdocument/data/hello.md b/tests/auto/quick/qquicktextdocument/data/hello.md
new file mode 100644
index 0000000000..290f3f1397
--- /dev/null
+++ b/tests/auto/quick/qquicktextdocument/data/hello.md
@@ -0,0 +1 @@
+Γειά σου *Κόσμε*!
diff --git a/tests/auto/quick/qquicktextdocument/data/hello.txt b/tests/auto/quick/qquicktextdocument/data/hello.txt
new file mode 100644
index 0000000000..1f72c3f7a4
--- /dev/null
+++ b/tests/auto/quick/qquicktextdocument/data/hello.txt
@@ -0,0 +1 @@
+Γειά σου Κόσμε!
diff --git a/tests/auto/quick/qquicktextdocument/data/sideBySideIndependent.qml b/tests/auto/quick/qquicktextdocument/data/sideBySideIndependent.qml
new file mode 100644
index 0000000000..8275e7f5bd
--- /dev/null
+++ b/tests/auto/quick/qquicktextdocument/data/sideBySideIndependent.qml
@@ -0,0 +1,21 @@
+import QtQuick
+
+Row {
+ width: 480; height: 200
+ TextEdit {
+ objectName: "plain"
+ width: parent.width / 2 - 1
+ textFormat: TextEdit.PlainText
+ textDocument.source: "hello.md"
+ }
+ Rectangle {
+ width: 2; height: parent.height
+ color: "lightsteelblue"
+ }
+ TextEdit {
+ objectName: "markdown"
+ width: parent.width / 2 - 1
+ textFormat: TextEdit.MarkdownText
+ textDocument.source: "hello.md"
+ }
+}
diff --git a/tests/auto/quick/qquicktextdocument/data/sideBySideIndependentReverse.qml b/tests/auto/quick/qquicktextdocument/data/sideBySideIndependentReverse.qml
new file mode 100644
index 0000000000..cbd92accec
--- /dev/null
+++ b/tests/auto/quick/qquicktextdocument/data/sideBySideIndependentReverse.qml
@@ -0,0 +1,21 @@
+import QtQuick
+
+Row {
+ width: 480; height: 200
+ TextEdit {
+ objectName: "plain"
+ width: parent.width / 2 - 1
+ textDocument.source: "hello.md"
+ textFormat: TextEdit.PlainText
+ }
+ Rectangle {
+ width: 2; height: parent.height
+ color: "lightsteelblue"
+ }
+ TextEdit {
+ objectName: "markdown"
+ width: parent.width / 2 - 1
+ textDocument.source: "hello.md"
+ textFormat: TextEdit.MarkdownText
+ }
+}
diff --git a/tests/auto/quick/qquicktextdocument/data/text.qml b/tests/auto/quick/qquicktextdocument/data/text.qml
index 43a8c6bb82..9544471114 100644
--- a/tests/auto/quick/qquicktextdocument/data/text.qml
+++ b/tests/auto/quick/qquicktextdocument/data/text.qml
@@ -1,6 +1,14 @@
-import QtQuick 2.1
+import QtQuick
TextEdit {
- text: ""
-}
+ id: te
+ property int sourceChangeCount: 0
+ property int modifiedChangeCount: 0
+ property var statusHistory: []
+
+ text: "" // this is not a document modification
+ textDocument.onSourceChanged: ++te.sourceChangeCount
+ textDocument.onModifiedChanged: ++te.modifiedChangeCount
+ textDocument.onStatusChanged: te.statusHistory.push(textDocument.status)
+}
diff --git a/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp b/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp
index e9c699db6a..535f20e7bb 100644
--- a/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp
+++ b/tests/auto/quick/qquicktextdocument/tst_qquicktextdocument.cpp
@@ -1,53 +1,122 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtTest/QtTest>
-#include <QtQuick/QQuickTextDocument>
#include <QtQuick/QQuickItem>
-#include <QtQuick/private/qquicktextedit_p.h>
+#include <QtQuick/QQuickTextDocument>
+#include <QtQuick/QQuickView>
#include <QtQuick/private/qquicktextdocument_p.h>
+#include <QtQuick/private/qquicktextedit_p.h>
+#include <QtQuick/private/qquicktextedit_p_p.h>
+#include <QtCore/QStringConverter>
+#include <QtGui/QTextBlock>
#include <QtGui/QTextDocument>
#include <QtGui/QTextDocumentWriter>
-#include <QtQml/QQmlEngine>
#include <QtQml/QQmlComponent>
-#include "../../shared/util.h"
+#include <QtQml/QQmlEngine>
+#include <QtQml/QQmlFile>
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#ifdef Q_OS_UNIX
+#include <unistd.h>
+#endif
+
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+
+using namespace Qt::StringLiterals;
class tst_qquicktextdocument : public QQmlDataTest
{
Q_OBJECT
+public:
+ tst_qquicktextdocument();
+
+private:
+ QPair<int, int> fragmentsAndItalics(const QTextDocument *doc);
+ bool isMainFontFixed();
+
private slots:
void textDocumentWriter();
- void textDocumentWithImage();
+ void customDocument();
+ void sourceAndSave_data();
+ void sourceAndSave();
+ void loadErrorNoSuchFile();
+ void loadErrorPermissionDenied();
+ void overrideTextFormat_data();
+ void overrideTextFormat();
+ void independentDocumentsSameSource_data();
+ void independentDocumentsSameSource();
};
QString text = QStringLiteral("foo bar");
+// similar to TestDocument in tst_qtextdocument.cpp
+class FakeImageDocument : public QTextDocument
+{
+public:
+ inline FakeImageDocument(const QUrl &testUrl, const QString &testString)
+ : url(testUrl), string(testString), resourceLoaded(false) {}
+
+ bool hasResourceCached();
+
+protected:
+ virtual QVariant loadResource(int type, const QUrl &name) override;
+
+private:
+ QUrl url;
+ QString string;
+ bool resourceLoaded;
+};
+
+bool FakeImageDocument::hasResourceCached()
+{
+ return resourceLoaded;
+}
+
+QVariant FakeImageDocument::loadResource(int type, const QUrl &name)
+{
+ qCDebug(lcTests) << type << name << ": expecting" << int(QTextDocument::ImageResource) << url;
+ if (type == QTextDocument::ImageResource && name == url) {
+ resourceLoaded = true;
+ return string;
+ }
+ return QTextDocument::loadResource(type, name);
+}
+
+tst_qquicktextdocument::tst_qquicktextdocument()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
+/*! \internal
+ Returns {fragmentCount, italicFragmentIndex}. If no italic fragment is found,
+ italicFragmentIndex is -1.
+*/
+QPair<int, int> tst_qquicktextdocument::fragmentsAndItalics(const QTextDocument *doc)
+{
+ int fragmentCount = 0;
+ int italicFragment = -1;
+ for (QTextBlock::iterator it = doc->firstBlock().begin(); !(it.atEnd()); ++it) {
+ QTextFragment currentFragment = it.fragment();
+ if (currentFragment.charFormat().fontItalic())
+ italicFragment = fragmentCount;
+ ++fragmentCount;
+ qCDebug(lcTests) << (currentFragment.charFormat().fontItalic() ? "italic" : "roman") << currentFragment.text();
+ }
+ return {fragmentCount, italicFragment};
+}
+
+bool tst_qquicktextdocument::isMainFontFixed()
+{
+ bool ret = QFontInfo(QGuiApplication::font()).fixedPitch();
+ if (ret) {
+ qCWarning(lcTests) << "QFontDatabase::GeneralFont is monospaced: markdown writing is likely to use too many backticks"
+ << QFontDatabase::systemFont(QFontDatabase::GeneralFont);
+ }
+ return ret;
+}
+
void tst_qquicktextdocument::textDocumentWriter()
{
QQmlEngine e;
@@ -71,18 +140,427 @@ void tst_qquicktextdocument::textDocumentWriter()
delete o;
}
-void tst_qquicktextdocument::textDocumentWithImage()
+/*! \internal
+ Verify that it's OK to replace the default QTextDocument that TextEdit creates
+ with a user-created QTextDocument.
+
+ Also verify that the user can still override QTextDocument::loadResource().
+ QTextDocument::loadResource() can call its QObject parent's loadResource();
+ the default QTextDocument's parent is the QQuickTextEdit, which provides an
+ implementation of QQuickTextEdit::loadResource(), which uses QQuickPixmap
+ to load and cache images. This will be bypassed if the user overrides
+ loadResource() to do something different.
+*/
+void tst_qquicktextdocument::customDocument()
{
- QQuickTextDocumentWithImageResources document(nullptr);
- QImage image(1, 1, QImage::Format_Mono);
- image.fill(1);
+ QQmlEngine e;
+ QQmlComponent c(&e, testFileUrl("text.qml"));
+ QScopedPointer<QQuickTextEdit> textEdit(qobject_cast<QQuickTextEdit*>(c.create()));
+ QCOMPARE(textEdit.isNull(), false);
+ auto *textEditPriv = QQuickTextEditPrivate::get(textEdit.get());
+ QVERIFY(textEditPriv->ownsDocument);
+
+ QQuickTextDocument *quickDocument = textEdit->property("textDocument").value<QQuickTextDocument*>();
+ QVERIFY(quickDocument);
+ QPointer<QTextDocument> defaultDocument(quickDocument->textDocument());
+ const QString imageUrl = "https://www.qt.io/hubfs/Qt-logo-neon-small.png";
+ const QString fakeImageData = "foo!";
+
+ FakeImageDocument fdoc(QUrl(imageUrl), fakeImageData);
+ quickDocument->setTextDocument(&fdoc);
+ QVERIFY(defaultDocument.isNull()); // deleted because of being replaced (don't leak)
+ QCOMPARE(textEditPriv->ownsDocument, false);
+
+ // QQuickTextEdit::setText() -> QQuickTextControl::setHtml() ->
+ // QQuickTextControlPrivate::setContent() -> fdoc->setHtml()
+ // and eventually fdoc->loadResource() which substitutes a string for the requested image
+ textEdit->setTextFormat(QQuickTextEdit::RichText);
+ textEdit->setText("an image: <img src='" + imageUrl + "'/>");
+ QCOMPARE(fdoc.hasResourceCached(), true);
+
+ auto firstBlock = fdoc.firstBlock();
+ // check that image loading has been bypassed by FakeImageDocument
+ bool foundImage = false;
+ int fragmentCount = 0;
+ for (QTextBlock::iterator it = firstBlock.begin(); !(it.atEnd()); ++it) {
+ QTextFragment currentFragment = it.fragment();
+ QVERIFY(currentFragment.isValid());
+ ++fragmentCount;
+ const QString imageName = currentFragment.charFormat().stringProperty(QTextFormat::ImageName);
+ if (!imageName.isEmpty()) {
+ QCOMPARE(imageName, imageUrl);
+ foundImage = true;
+ QCOMPARE(fdoc.resource(QTextDocument::ImageResource, imageUrl).toString(), fakeImageData);
+ }
+ }
+ QVERIFY(foundImage);
+ QCOMPARE(fragmentCount, 2);
+}
+
+void tst_qquicktextdocument::sourceAndSave_data()
+{
+ QTest::addColumn<QQuickTextEdit::TextFormat>("textFormat");
+ QTest::addColumn<QString>("source");
+ QTest::addColumn<std::optional<QStringConverter::Encoding>>("expectedEncoding");
+ QTest::addColumn<Qt::TextFormat>("expectedTextFormat");
+ QTest::addColumn<int>("minCharCount");
+ QTest::addColumn<QString>("expectedPlainText");
+
+ const std::optional<QStringConverter::Encoding> nullEnc;
+
+ QTest::newRow("plain") << QQuickTextEdit::PlainText << "hello.txt"
+ << nullEnc << Qt::PlainText << 15 << u"Γειά σου Κόσμε!"_s;
+ QTest::newRow("markdown") << QQuickTextEdit::MarkdownText << "hello.md"
+ << nullEnc << Qt::MarkdownText << 15 << u"Γειά σου Κόσμε!"_s;
+ QTest::newRow("html") << QQuickTextEdit::RichText << "hello.html"
+ << std::optional<QStringConverter::Encoding>(QStringConverter::Utf8)
+ << Qt::RichText << 15 << u"Γειά σου Κόσμε!"_s;
+ QTest::newRow("html-utf16be") << QQuickTextEdit::AutoText << "hello-utf16be.html"
+ << std::optional<QStringConverter::Encoding>(QStringConverter::Utf16BE)
+ << Qt::RichText << 15 << u"Γειά σου Κόσμε!"_s;
+}
+
+void tst_qquicktextdocument::sourceAndSave()
+{
+ QFETCH(QQuickTextEdit::TextFormat, textFormat);
+ QFETCH(QString, source);
+ QFETCH(std::optional<QStringConverter::Encoding>, expectedEncoding);
+ QFETCH(Qt::TextFormat, expectedTextFormat);
+ QFETCH(int, minCharCount);
+ QFETCH(QString, expectedPlainText);
+
+ QQmlEngine e;
+ QQmlComponent c(&e, testFileUrl("text.qml"));
+ QScopedPointer<QQuickTextEdit> textEdit(qobject_cast<QQuickTextEdit*>(c.create()));
+ QCOMPARE(textEdit.isNull(), false);
+ QQuickTextDocument *qqdoc = textEdit->property("textDocument").value<QQuickTextDocument*>();
+ QVERIFY(qqdoc);
+ const QQmlContext *ctxt = e.rootContext();
+ // text.qml has text: "" but that's not a real change; QQuickTextEdit::setText() returns early
+ // QQuickTextEditPrivate::init() also modifies defaults and then resets the modified state
+ QCOMPARE(qqdoc->isModified(), false);
+ // no stray signals should be visible to QML during init
+ QCOMPARE(textEdit->property("modifiedChangeCount").toInt(), 0);
+ QCOMPARE(textEdit->property("sourceChangeCount").toInt(), 0);
+ QTextDocument *doc = qqdoc->textDocument();
+ QVERIFY(doc);
+ QSignalSpy sourceChangedSpy(qqdoc, &QQuickTextDocument::sourceChanged);
+ QSignalSpy modifiedChangedSpy(qqdoc, &QQuickTextDocument::modifiedChanged);
+ QSignalSpy statusChangedSpy(qqdoc, &QQuickTextDocument::statusChanged);
+
+ QTemporaryDir tmpDir;
+ QVERIFY(tmpDir.isValid());
+ QFile sf(QQmlFile::urlToLocalFileOrQrc(ctxt->resolvedUrl(testFileUrl(source))));
+ qCDebug(lcTests) << source << "orig ->" << sf.fileName();
+ QVERIFY(sf.exists());
+ QString tmpPath = tmpDir.filePath(source);
+ QVERIFY(sf.copy(tmpPath));
+ qCDebug(lcTests) << source << "copy ->" << tmpDir.path() << ":" << tmpPath;
+
+ QCOMPARE(statusChangedSpy.size(), 0);
+ QCOMPARE(qqdoc->status(), QQuickTextDocument::Status::Null);
+ textEdit->setTextFormat(textFormat);
+ qqdoc->setProperty("source", QUrl::fromLocalFile(tmpPath));
+ QCOMPARE(sourceChangedSpy.size(), 1);
+ QCOMPARE(textEdit->property("sourceChangeCount").toInt(), 1);
+ QCOMPARE(statusChangedSpy.size(), 2); // Loading, then Loaded
+ QCOMPARE(qqdoc->status(), QQuickTextDocument::Status::Loaded);
+ QVERIFY(qqdoc->errorString().isEmpty());
+ const auto *qqdp = QQuickTextDocumentPrivate::get(qqdoc);
+ QCOMPARE(qqdp->detectedFormat, expectedTextFormat);
+ QCOMPARE_GE(doc->characterCount(), minCharCount);
+ QCOMPARE(doc->toPlainText().trimmed(), expectedPlainText);
+ QCOMPARE(qqdp->encoding, expectedEncoding);
+
+ textEdit->setText("hello");
+ QCOMPARE(qqdoc->isModified(), false);
+ QCOMPARE_GE(textEdit->property("modifiedChangeCount").toInt(), 1);
+ QCOMPARE(textEdit->property("modifiedChangeCount").toInt(), modifiedChangedSpy.size());
+ modifiedChangedSpy.clear();
+ textEdit->insert(5, "!");
+ QCOMPARE_GE(modifiedChangedSpy.size(), 1);
+ QCOMPARE(qqdoc->isModified(), true);
+
+ qqdoc->save();
+ QCOMPARE(statusChangedSpy.size(), 4); // Saving, then Saved
+ QCOMPARE(qqdoc->status(), QQuickTextDocument::Status::Saved);
+ QVERIFY(qqdoc->errorString().isEmpty());
+ QFile tf(tmpPath);
+ QVERIFY(tf.open(QIODeviceBase::ReadOnly));
+ auto readBack = tf.readAll();
+ if (expectedTextFormat == Qt::RichText) {
+ QStringDecoder dec(*expectedEncoding);
+ const QString decStr = dec(readBack);
+ QVERIFY(decStr.contains("hello!</p>"));
+ } else {
+ QVERIFY(readBack.contains("hello!"));
+ }
+ QCOMPARE(textEdit->property("sourceChangeCount").toInt(), sourceChangedSpy.size());
+}
+
+void tst_qquicktextdocument::loadErrorNoSuchFile()
+{
+ QQmlEngine e;
+ QQmlComponent c(&e, testFileUrl("text.qml"));
+ QScopedPointer<QQuickTextEdit> textEdit(qobject_cast<QQuickTextEdit*>(c.create()));
+ QCOMPARE(textEdit.isNull(), false);
+ QQuickTextDocument *qqdoc = textEdit->property("textDocument").value<QQuickTextDocument*>();
+ QVERIFY(qqdoc);
+ QCOMPARE(textEdit->property("sourceChangeCount").toInt(), 0);
+ QTextDocument *doc = qqdoc->textDocument();
+ QVERIFY(doc);
+ QSignalSpy sourceChangedSpy(qqdoc, &QQuickTextDocument::sourceChanged);
+ QSignalSpy statusChangedSpy(qqdoc, &QQuickTextDocument::statusChanged);
+
+ QCOMPARE(statusChangedSpy.size(), 0);
+ QCOMPARE(qqdoc->status(), QQuickTextDocument::Status::Null);
+ const QRegularExpression err(".*does not exist");
+ QTest::ignoreMessage(QtWarningMsg, err);
+ qqdoc->setProperty("source", testFileUrl("nosuchfile.md"));
+ QCOMPARE(sourceChangedSpy.size(), 1);
+ QCOMPARE(textEdit->property("sourceChangeCount").toInt(), 1);
+ qCDebug(lcTests) << "status history" << textEdit->property("statusHistory").toList();
+ QCOMPARE(statusChangedSpy.size(), 1);
+ QCOMPARE(qqdoc->status(), QQuickTextDocument::Status::ReadError);
+ QVERIFY(qqdoc->errorString().contains(err));
+}
+
+void tst_qquicktextdocument::loadErrorPermissionDenied()
+{
+#ifdef Q_OS_UNIX
+ if (geteuid() == 0)
+ QSKIP("Permission will not be denied with root privileges.");
+#endif
+ QQmlEngine e;
+ QQmlComponent c(&e, testFileUrl("text.qml"));
+ QScopedPointer<QQuickTextEdit> textEdit(qobject_cast<QQuickTextEdit*>(c.create()));
+ QCOMPARE(textEdit.isNull(), false);
+ QQuickTextDocument *qqdoc = textEdit->property("textDocument").value<QQuickTextDocument*>();
+ QVERIFY(qqdoc);
+ const QQmlContext *ctxt = e.rootContext();
+ QCOMPARE(textEdit->property("sourceChangeCount").toInt(), 0);
+ QTextDocument *doc = qqdoc->textDocument();
+ QVERIFY(doc);
+ QSignalSpy sourceChangedSpy(qqdoc, &QQuickTextDocument::sourceChanged);
+ QSignalSpy statusChangedSpy(qqdoc, &QQuickTextDocument::statusChanged);
+
+ QTemporaryDir tmpDir;
+ QVERIFY(tmpDir.isValid());
+ const QString source("hello.md");
+ QFile sf(QQmlFile::urlToLocalFileOrQrc(ctxt->resolvedUrl(testFileUrl(source))));
+ qCDebug(lcTests) << source << "orig ->" << sf.fileName();
+ QVERIFY(sf.exists());
+ QString tmpPath = tmpDir.filePath(source);
+ QVERIFY(sf.copy(tmpPath));
+ qCDebug(lcTests) << source << "copy ->" << tmpDir.path() << ":" << tmpPath;
+ if (!QFile::setPermissions(tmpPath, QFileDevice::Permissions{})) // no permissions at all
+ QSKIP("Failed to change permissions of temporary file: cannot continue.");
+
+ QCOMPARE(statusChangedSpy.size(), 0);
+ QCOMPARE(qqdoc->status(), QQuickTextDocument::Status::Null);
+ const QRegularExpression err(".*Failed to read: Permission denied");
+ QTest::ignoreMessage(QtWarningMsg, err);
+ qqdoc->setProperty("source", QUrl::fromLocalFile(tmpPath));
+ QCOMPARE(sourceChangedSpy.size(), 1);
+ QCOMPARE(textEdit->property("sourceChangeCount").toInt(), 1);
+ qCDebug(lcTests) << "status history" << textEdit->property("statusHistory").toList();
+ QCOMPARE(statusChangedSpy.size(), 1);
+ QCOMPARE(qqdoc->status(), QQuickTextDocument::Status::ReadError);
+ QVERIFY(qqdoc->errorString().contains(err));
+}
+
+void tst_qquicktextdocument::overrideTextFormat_data()
+{
+ QTest::addColumn<QUrl>("qmlfile");
+ QTest::addColumn<QQuickTextEdit::TextFormat>("initialFormat");
+ QTest::addColumn<QUrl>("source");
+ QTest::addColumn<int>("expectedInitialFragmentCount");
+ QTest::addColumn<int>("expectedInitialItalicFragment");
+ // first part of TextEdit.text after loading
+ QTest::addColumn<QString>("expectedTextPrefix");
+
+ QTest::addColumn<QQuickTextEdit::TextFormat>("replacementFormat");
+ QTest::addColumn<int>("expectedFragmentCount");
+ QTest::addColumn<int>("expectedItalicFragment");
+ // first part of TextEdit.text after switching to replacementFormat
+ QTest::addColumn<QString>("expectedReplacementPrefix");
+ QTest::addColumn<int>("expectedTextChangedSignalsAfterReplacement");
+
+ QTest::addColumn<QQuickTextEdit::TextFormat>("finalFormat");
+ QTest::addColumn<int>("expectedFinalFragmentCount");
+ QTest::addColumn<int>("expectedFinalItalicFragment");
+ // first part of TextEdit.text after switching to finalFormat
+ QTest::addColumn<QString>("expectedFinalPrefix");
+
+ QTest::newRow("load md, switch to plain, back to md")
+ << testFileUrl("text.qml") << QQuickTextEdit::MarkdownText << testFileUrl("hello.md")
+ << 3 << 1 << u"Γειά σου *Κόσμε*!"_s
+ << QQuickTextEdit::PlainText << 1 << -1 << u"Γειά σου *Κόσμε*!"_s << 2
+ << QQuickTextEdit::MarkdownText << 3 << 1 << u"Γειά σου *Κόσμε*!"_s;
+ QTest::newRow("load md, switch to plain, then auto")
+ << testFileUrl("text.qml") << QQuickTextEdit::MarkdownText << testFileUrl("hello.md")
+ << 3 << 1 << u"Γειά σου *Κόσμε*!"_s
+ << QQuickTextEdit::PlainText << 1 << -1 << u"Γειά σου *Κόσμε*!"_s << 2
+ << QQuickTextEdit::AutoText << 3 << 1 << u"Γειά σου *Κόσμε*!"_s;
+ QTest::newRow("load md, switch to html, then plain")
+ << testFileUrl("text.qml") << QQuickTextEdit::MarkdownText << testFileUrl("hello.md")
+ << 3 << 1 << u"Γειά σου *Κόσμε*!"_s
+ << QQuickTextEdit::RichText << 3 << 1 << u"<!DOCTYPE HTML"_s << 2
+ << QQuickTextEdit::PlainText << 1 << -1 << u"<!DOCTYPE HTML"_s;
+ QTest::newRow("load md as plain text, switch to md, back to plain")
+ << testFileUrl("text.qml") << QQuickTextEdit::PlainText << testFileUrl("hello.md")
+ << 1 << -1 << u"Γειά σου *Κόσμε*!"_s
+ << QQuickTextEdit::MarkdownText << 3 << 1 << u"Γειά σου *Κόσμε*!"_s << 2
+ << QQuickTextEdit::PlainText << 1 << -1 << u"Γειά σου *Κόσμε*!"_s;
+ QTest::newRow("load md as autotext, switch to plain, back to auto")
+ << testFileUrl("text.qml") << QQuickTextEdit::AutoText << testFileUrl("hello.md")
+ << 3 << 1 << u"Γειά σου *Κόσμε*!"_s
+ << QQuickTextEdit::PlainText << 1 << -1 << u"Γειά σου *Κόσμε*!"_s << 2
+ << QQuickTextEdit::AutoText << 3 << 1 << u"Γειά σου *Κόσμε*!"_s;
+ QTest::newRow("load md as autotext, switch to md, then plain")
+ << testFileUrl("text.qml") << QQuickTextEdit::AutoText << testFileUrl("hello.md")
+ << 3 << 1 << u"Γειά σου *Κόσμε*!"_s
+ << QQuickTextEdit::MarkdownText << 3 << 1 << u"Γειά σου *Κόσμε*!"_s
+ // going from AutoText to a matching explicit format does not cause extra textChanged()
+ << 1
+ << QQuickTextEdit::PlainText << 1 << -1 << u"Γειά σου *Κόσμε*!"_s;
+ QTest::newRow("load md as autotext, switch to html, then plain")
+ << testFileUrl("text.qml") << QQuickTextEdit::AutoText << testFileUrl("hello.md")
+ << 3 << 1 << u"Γειά σου *Κόσμε*!"_s
+ << QQuickTextEdit::RichText << 3 << 1 << u"<!DOCTYPE HTML"_s << 2
+ << QQuickTextEdit::PlainText << 1 << -1 << u"<!DOCTYPE HTML"_s;
+
+ QTest::newRow("load html, switch to plain, back to rich")
+ << testFileUrl("text.qml") << QQuickTextEdit::RichText << testFileUrl("hello.html")
+ << 3 << 1 << u"<!DOCTYPE HTML"_s
+ << QQuickTextEdit::PlainText << 1 << -1 << u"<!DOCTYPE HTML"_s << 2
+ << QQuickTextEdit::RichText << 3 << 1 << u"<!DOCTYPE HTML"_s;
+ QTest::newRow("load html as plain text, switch to html, back to plain")
+ << testFileUrl("text.qml") << QQuickTextEdit::PlainText << testFileUrl("hello.html")
+ << 1 << -1 << u"Γειά σου <i>Κόσμε</i>!"_s
+ << QQuickTextEdit::RichText << 3 << 1 << u"<!DOCTYPE HTML"_s << 2
+ << QQuickTextEdit::PlainText << 1 << -1 << u"<!DOCTYPE HTML"_s;
+ QTest::newRow("load html as autotext, switch to plain, back to auto")
+ << testFileUrl("text.qml") << QQuickTextEdit::AutoText << testFileUrl("hello.html")
+ << 3 << 1 << u"<!DOCTYPE HTML"_s
+ << QQuickTextEdit::PlainText << 1 << -1 << u"<!DOCTYPE HTML"_s << 2
+ << QQuickTextEdit::AutoText << 3 << 1 << u"<!DOCTYPE HTML"_s;
+ QTest::newRow("load html as autotext, switch to html, then plain")
+ << testFileUrl("text.qml") << QQuickTextEdit::AutoText << testFileUrl("hello.html")
+ << 3 << 1 << u"<!DOCTYPE HTML"_s
+ << QQuickTextEdit::RichText << 3 << 1 << u"<!DOCTYPE HTML"_s
+ // going from AutoText to a matching explicit format does not cause extra textChanged()
+ << 1
+ << QQuickTextEdit::PlainText << 1 << -1 << u"<!DOCTYPE HTML"_s;
+ QTest::newRow("load html as autotext, switch to markdown, then plain")
+ << testFileUrl("text.qml") << QQuickTextEdit::AutoText << testFileUrl("hello.html")
+ << 3 << 1 << u"<!DOCTYPE HTML"_s
+ << QQuickTextEdit::MarkdownText << 3 << 1 << u"Γειά σου *Κόσμε*!"_s << 2
+ << QQuickTextEdit::PlainText << 1 << -1 << u"Γειά σου *Κόσμε*!"_s;
+}
+
+void tst_qquicktextdocument::overrideTextFormat() // QTBUG-120772
+{
+ if (isMainFontFixed())
+ QSKIP("fixed-pitch main font (QTBUG-103484)");
+
+ QFETCH(QUrl, qmlfile);
+ QFETCH(QQuickTextEdit::TextFormat, initialFormat);
+ QFETCH(QUrl, source);
+ QFETCH(int, expectedInitialFragmentCount);
+ QFETCH(int, expectedInitialItalicFragment);
+ QFETCH(QString, expectedTextPrefix);
+
+ QFETCH(QQuickTextEdit::TextFormat, replacementFormat);
+ QFETCH(int, expectedFragmentCount);
+ QFETCH(int, expectedItalicFragment);
+ QFETCH(QString, expectedReplacementPrefix);
+ QFETCH(int, expectedTextChangedSignalsAfterReplacement);
+
+ QFETCH(QQuickTextEdit::TextFormat, finalFormat);
+ QFETCH(int, expectedFinalFragmentCount);
+ QFETCH(int, expectedFinalItalicFragment);
+ QFETCH(QString, expectedFinalPrefix);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, qmlfile));
+ QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(window.rootObject());
+ QVERIFY(textEdit);
+ QQuickTextDocument *qqdoc = textEdit->property("textDocument").value<QQuickTextDocument*>();
+ QVERIFY(qqdoc);
+ QTextDocument *doc = qqdoc->textDocument();
+ QVERIFY(doc);
+
+ textEdit->setTextFormat(initialFormat);
+ QCOMPARE(qqdoc->isModified(), false);
+ QCOMPARE(textEdit->property("sourceChangeCount").toInt(), 0);
+ QSignalSpy sourceChangedSpy(qqdoc, &QQuickTextDocument::sourceChanged);
+ QSignalSpy textChangedSpy(textEdit, &QQuickTextEdit::textChanged);
+
+ qqdoc->setProperty("source", source);
+ QCOMPARE(sourceChangedSpy.size(), 1);
+ QCOMPARE(textEdit->property("sourceChangeCount").toInt(), 1);
+ QCOMPARE_GE(textChangedSpy.size(), 1);
+ auto fragCountAndItalic = fragmentsAndItalics(doc);
+ QCOMPARE(fragCountAndItalic.first, expectedInitialFragmentCount);
+ QCOMPARE(fragCountAndItalic.second, expectedInitialItalicFragment);
+ QString textPropValue = textEdit->text();
+ qCDebug(lcTests) << "expect text()" << textPropValue.first(qMin(20, textPropValue.size() - 1))
+ << "to start with" << expectedTextPrefix;
+ QVERIFY(textPropValue.startsWith(expectedTextPrefix));
+
+ textEdit->setTextFormat(replacementFormat);
+ QCOMPARE(qqdoc->isModified(), false);
+ QCOMPARE(sourceChangedSpy.size(), 1);
+ QCOMPARE_GE(textChangedSpy.size(), expectedTextChangedSignalsAfterReplacement);
+ fragCountAndItalic = fragmentsAndItalics(doc);
+ QCOMPARE(fragCountAndItalic.first, expectedFragmentCount);
+ QCOMPARE(fragCountAndItalic.second, expectedItalicFragment);
+ textPropValue = textEdit->text();
+ qCDebug(lcTests) << "expect text()" << textPropValue.first(qMin(20, textPropValue.size() - 1))
+ << "to start with" << expectedReplacementPrefix;
+ QVERIFY(textPropValue.startsWith(expectedReplacementPrefix));
+
+ textEdit->setTextFormat(finalFormat);
+ QCOMPARE(qqdoc->isModified(), false);
+ QCOMPARE(sourceChangedSpy.size(), 1);
+ QCOMPARE_GE(textChangedSpy.size(), expectedTextChangedSignalsAfterReplacement + 1);
+ fragCountAndItalic = fragmentsAndItalics(doc);
+ QCOMPARE(fragCountAndItalic.first, expectedFinalFragmentCount);
+ QCOMPARE(fragCountAndItalic.second, expectedFinalItalicFragment);
+ textPropValue = textEdit->text();
+ qCDebug(lcTests) << "expect text()" << textPropValue.first(qMin(20, textPropValue.size() - 1))
+ << "to start with" << expectedFinalPrefix;
+ QVERIFY(textPropValue.startsWith(expectedFinalPrefix));
+}
+
+void tst_qquicktextdocument::independentDocumentsSameSource_data()
+{
+ QTest::addColumn<QUrl>("qmlfile");
+
+ QTest::newRow("textFormat above source") << testFileUrl("sideBySideIndependent.qml");
+ QTest::newRow("source above textFormat") << testFileUrl("sideBySideIndependentReverse.qml");
+}
+
+// ensure that two TextEdits' textFormat properties take effect, regardless of qml init order
+void tst_qquicktextdocument::independentDocumentsSameSource() // QTBUG-120772
+{
+ QFETCH(QUrl, qmlfile);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, qmlfile));
+ QQuickTextEdit *textEditPlain = window.rootObject()->findChild<QQuickTextEdit *>("plain");
+ QVERIFY(textEditPlain);
+ QQuickTextEdit *textEditMarkdown = window.rootObject()->findChild<QQuickTextEdit *>("markdown");
+ QVERIFY(textEditMarkdown);
+
+ auto fragCountAndItalic = fragmentsAndItalics(textEditPlain->textDocument()->textDocument());
+ QCOMPARE(fragCountAndItalic.first, 1);
+ QCOMPARE(fragCountAndItalic.second, -1);
- QString name = "image";
- document.addResource(QTextDocument::ImageResource, name, image);
- QTextImageFormat format;
- format.setName(name);
- QCOMPARE(image, document.image(format));
- QCOMPARE(image, document.resource(QTextDocument::ImageResource, name).value<QImage>());
+ fragCountAndItalic = fragmentsAndItalics(textEditMarkdown->textDocument()->textDocument());
+ QCOMPARE(fragCountAndItalic.first, 3);
+ QCOMPARE(fragCountAndItalic.second, 1);
}
QTEST_MAIN(tst_qquicktextdocument)
diff --git a/tests/auto/quick/qquicktextedit/BLACKLIST b/tests/auto/quick/qquicktextedit/BLACKLIST
index 48108566e0..d9c889dde3 100644
--- a/tests/auto/quick/qquicktextedit/BLACKLIST
+++ b/tests/auto/quick/qquicktextedit/BLACKLIST
@@ -11,3 +11,29 @@ macos ci
[hAlignVisual]
sles
+
+# QTBUG-103098
+[hAlignVisual]
+android
+[linkHover]
+android
+[cursorVisible]
+android
+[transparentSelectionColor]
+android
+
+# QTBUG-100991
+[selectionOnFocusOut]
+android
+
+# QTBUG-108346
+[pasteHtmlIntoMarkdown]
+ubuntu-20.04
+
+# QTBUG-118066
+[inFlickableMouse]
+opensuse-leap
+
+# QTBUG-118066
+[inFlickableTouch]
+opensuse-leap
diff --git a/tests/auto/quick/qquicktextedit/CMakeLists.txt b/tests/auto/quick/qquicktextedit/CMakeLists.txt
index 57a955877b..76ac64d876 100644
--- a/tests/auto/quick/qquicktextedit/CMakeLists.txt
+++ b/tests/auto/quick/qquicktextedit/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquicktextedit.pro.
#####################################################################
## tst_qquicktextedit Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicktextedit LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,23 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquicktextedit
SOURCES
- ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquicktextedit.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::NetworkPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -36,16 +37,16 @@ qt_internal_add_test(tst_qquicktextedit
#####################################################################
qt_internal_extend_target(tst_qquicktextedit CONDITION MACOS
- PUBLIC_LIBRARIES
+ LIBRARIES
${FWAppKit}
)
qt_internal_extend_target(tst_qquicktextedit CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquicktextedit CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquicktextedit/data/embeddedImagesLocalError.qml b/tests/auto/quick/qquicktextedit/data/embeddedImagesLocalError.qml
index 067b6d72da..869ef455df 100644
--- a/tests/auto/quick/qquicktextedit/data/embeddedImagesLocalError.qml
+++ b/tests/auto/quick/qquicktextedit/data/embeddedImagesLocalError.qml
@@ -1,4 +1,4 @@
-import QtQuick 2.0
+import QtQuick
TextEdit {
textFormat: TextEdit.RichText
diff --git a/tests/auto/quick/qquicktextedit/data/embeddedImagesRemote.qml b/tests/auto/quick/qquicktextedit/data/embeddedImagesRemote.qml
index 6fc12edf35..a80e669140 100644
--- a/tests/auto/quick/qquicktextedit/data/embeddedImagesRemote.qml
+++ b/tests/auto/quick/qquicktextedit/data/embeddedImagesRemote.qml
@@ -1,4 +1,4 @@
-import QtQuick 2.0
+import QtQuick
TextEdit {
property string serverBaseUrl;
diff --git a/tests/auto/quick/qquicktextedit/data/embeddedImagesRemoteError.qml b/tests/auto/quick/qquicktextedit/data/embeddedImagesRemoteError.qml
index 7ac59e2db4..75b0c5fd5d 100644
--- a/tests/auto/quick/qquicktextedit/data/embeddedImagesRemoteError.qml
+++ b/tests/auto/quick/qquicktextedit/data/embeddedImagesRemoteError.qml
@@ -1,4 +1,4 @@
-import QtQuick 2.0
+import QtQuick
TextEdit {
property string serverBaseUrl;
diff --git a/tests/auto/quick/qquicktextedit/data/focusByDefault.qml b/tests/auto/quick/qquicktextedit/data/focusByDefault.qml
new file mode 100644
index 0000000000..0f518aa7da
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/focusByDefault.qml
@@ -0,0 +1,7 @@
+import QtQuick
+
+TextEdit {
+ width: 200
+ height: 100
+ focus: true
+}
diff --git a/tests/auto/quick/qquicktextedit/data/httpfail/warning.png b/tests/auto/quick/qquicktextedit/data/httpfail/warning.png
new file mode 100644
index 0000000000..08d74b8b83
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/httpfail/warning.png
Binary files differ
diff --git a/tests/auto/quick/qquicktextedit/data/httpslow/turtle.svg b/tests/auto/quick/qquicktextedit/data/httpslow/turtle.svg
new file mode 100644
index 0000000000..6f34022d0e
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/httpslow/turtle.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="355.07501" height="205.41908" viewBox="0 0 284.06001 164.33527" version="1.1" id="svg2" inkscape:version="0.48.4 r9939" sodipodi:docname="AnimalSilhouettes2-Rabbit.svg"><link xmlns="" type="text/css" rel="stylesheet" id="dark-mode-custom-link"/><link xmlns="" type="text/css" rel="stylesheet" id="dark-mode-general-link"/><style xmlns="" lang="en" type="text/css" id="dark-mode-custom-style"/><style xmlns="" lang="en" type="text/css" id="dark-mode-native-style"/><style xmlns="" lang="en" type="text/css" id="dark-mode-native-sheet"/>
+ <metadata id="metadata11474">
+ <rdf:RDF>
+ <cc:Work rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+ <dc:title/>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs id="defs11472"/>
+ <sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1855" inkscape:window-height="1056" id="namedview11470" showgrid="false" units="in" fit-margin-top="0.25" fit-margin-left="0.25" fit-margin-right="0.25" fit-margin-bottom="0.25" inkscape:zoom="0.56869759" inkscape:cx="-269.65967" inkscape:cy="538.58793" inkscape:window-x="65" inkscape:window-y="24" inkscape:window-maximized="1" inkscape:current-layer="svg2"/>
+ <path d="m 116.14,18.675268 c 5.28,-0.32 10.73,-1.18 16,-0.09 1.71,0.51 3.5,0.69 5.3,0.64 0.66,0.08 1.99,0.24 2.65,0.32 0.98,0.67 2.07,0.89 3.26,0.67 l 0.84,0.14 c 0.53,0.21 1.6,0.63 2.13,0.84 l 0.82,-0.07 0.82,0.24 c 0.57,0.2 1.7,0.6 2.27,0.8 l 0.82,0.3 c 0.57,0.22 1.69,0.67 2.26,0.89 0.55,0.24 1.64,0.73 2.19,0.98 l 0.74,0.33 c 0.34,0.16 1.02,0.49 1.36,0.65 l 0.68,0.34 c 0.31,0.17 0.95,0.51 1.26,0.68 l 0.64,0.35 c 0.29,0.18 0.87,0.53 1.17,0.71 0.26,0.19 0.78,0.58 1.04,0.78 l 0.63,0.28 c 0.28,0.2 0.85,0.6 1.13,0.8 0.29,0.21 0.88,0.63 1.17,0.84 l 0.62,0.45 c 0.29,0.22 0.87,0.66 1.16,0.88 0.27,0.21 0.83,0.65 1.11,0.87 0.27,0.22 0.82,0.65 1.09,0.87 0.25,0.23 0.74,0.7 0.99,0.93 l 0.62,0.36 c 0.26,0.24 0.79,0.71 1.06,0.95 0.26,0.24 0.77,0.74 1.03,0.99 0.24,0.25 0.74,0.77 0.99,1.02 0.24,0.27 0.72,0.8 0.96,1.07 l 0.38,0.61 c 0.24,0.25 0.72,0.74 0.96,0.99 0.23,0.26 0.69,0.8 0.92,1.06 0.23,0.27 0.71,0.8 0.94,1.06 0.24,0.26 0.72,0.79 0.96,1.05 0.24,0.27 0.72,0.8 0.96,1.06 0.24,0.27 0.71,0.8 0.95,1.07 0.24,0.27 0.7,0.81 0.94,1.08 l 0.37,0.62 c 0.23,0.24 0.71,0.73 0.94,0.98 0.23,0.26 0.68,0.79 0.91,1.05 0.23,0.26 0.69,0.78 0.92,1.04 0.23,0.26 0.7,0.78 0.94,1.04 0.23,0.26 0.7,0.79 0.93,1.05 0.24,0.27 0.71,0.8 0.95,1.07 0.23,0.28 0.71,0.84 0.95,1.13 l 0.49,0.6 c 0.23,0.28 0.71,0.84 0.94,1.13 0.24,0.26 0.72,0.8 0.96,1.07 0.24,0.25 0.72,0.77 0.97,1.02 0.24,0.25 0.74,0.75 0.98,1 0.26,0.24 0.77,0.72 1.02,0.96 0.26,0.23 0.78,0.69 1.04,0.92 0.27,0.22 0.8,0.66 1.07,0.88 0.25,0.21 0.77,0.64 1.02,0.86 l 0.63,0.32 c 0.28,0.19 0.86,0.56 1.14,0.75 0.28,0.19 0.83,0.56 1.1,0.75 l 0.65,0.25 c 0.29,0.18 0.88,0.54 1.17,0.72 l 0.72,0.21 0.72,0.32 c 0.36,0.15 1.07,0.47 1.43,0.62 l 0.79,0.32 c 0.57,0.23 1.72,0.69 2.29,0.92 l 0.82,0.3 c 0.53,0.28 1.58,0.86 2.1,1.15 l 0.62,0.55 c 0,0.39 0.01,1.16 0.01,1.54 l -0.01,0.7 c -0.14,0.27 -0.42,0.81 -0.56,1.09 -0.13,0.24 -0.38,0.72 -0.5,0.96 l -0.19,0.5 c -0.1,0.23 -0.28,0.69 -0.38,0.92 -0.08,0.22 -0.24,0.66 -0.32,0.89 l -0.14,0.47 -0.16,0.48 c 0.2,-0.11 0.61,-0.34 0.81,-0.45 l 0.55,-0.03 c 0.3,-0.03 0.92,-0.1 1.22,-0.14 l 0.72,-0.12 c 0.52,-0.22 1.56,-0.66 2.09,-0.88 l 0.73,-0.2 c 0.31,-0.18 0.91,-0.55 1.21,-0.73 l 0.69,-0.21 c 0.3,-0.18 0.9,-0.54 1.2,-0.72 l 0.69,-0.22 c 0.3,-0.18 0.9,-0.55 1.2,-0.73 l 0.71,-0.22 c 0.3,-0.19 0.9,-0.55 1.21,-0.73 l 0.7,-0.23 c 0.3,-0.18 0.9,-0.54 1.2,-0.72 l 0.69,-0.23 c 0.3,-0.17 0.89,-0.53 1.19,-0.71 l 0.68,-0.2 c 0.29,-0.18 0.87,-0.53 1.16,-0.7 l 0.7,-0.18 c 0.29,-0.19 0.88,-0.55 1.18,-0.74 0.54,-0.23 1.61,-0.71 2.14,-0.94 l 0.76,-0.34 c 0.35,-0.15 1.07,-0.47 1.42,-0.62 l 0.77,-0.32 c 0.56,-0.2 1.69,-0.62 2.25,-0.83 l 0.82,-0.27 c 0.58,-0.18 1.74,-0.55 2.32,-0.74 0.44,-0.1 1.31,-0.3 1.75,-0.4 0.61,-0.15 1.84,-0.45 2.45,-0.61 0.73,-0.09 2.18,-0.27 2.91,-0.36 1.62,0.07 3.26,0.15 4.9,0.19 l 0.93,0.11 0.89,0.32 c 0.63,0.18 1.88,0.55 2.5,0.74 0.2,0.22 0.61,0.66 0.81,0.87 l 0.61,0.29 c 0.29,0.18 0.85,0.55 1.14,0.73 0.28,0.2 0.85,0.6 1.13,0.8 l 0.59,0.44 c 0.27,0.22 0.8,0.67 1.07,0.89 0.24,0.24 0.74,0.7 0.98,0.94 0.23,0.25 0.68,0.75 0.9,1 0.21,0.27 0.62,0.82 0.83,1.09 l 0.2,0.68 c 0.19,0.3 0.58,0.9 0.77,1.2 l 0.13,0.81 c 0.04,1.24 0.12,2.49 0.22,3.75 l -0.09,0.96 -0.27,0.95 c -0.2,0.66 -0.6,1.99 -0.8,2.65 -0.22,0.21 -0.66,0.62 -0.88,0.83 l -0.3,0.59 c -0.19,0.26 -0.57,0.78 -0.77,1.04 -0.21,0.24 -0.62,0.73 -0.83,0.97 -0.22,0.22 -0.67,0.67 -0.89,0.9 -0.24,0.21 -0.72,0.64 -0.95,0.85 -0.27,0.2 -0.8,0.61 -1.06,0.82 l -0.59,0.4 c -0.31,0.2 -0.92,0.59 -1.23,0.78 -0.53,0.24 -1.61,0.73 -2.15,0.97 -0.42,0.14 -1.26,0.41 -1.68,0.55 -0.59,0.18 -1.76,0.54 -2.34,0.73 l -0.83,0.25 c -0.57,0.19 -1.7,0.57 -2.27,0.76 l -0.81,0.25 c -0.57,0.17 -1.7,0.53 -2.27,0.7 -0.42,0.1 -1.26,0.29 -1.68,0.39 -0.56,0.17 -1.69,0.51 -2.26,0.69 l -0.82,0.23 c -0.57,0.17 -1.71,0.53 -2.27,0.7 -0.43,0.1 -1.27,0.29 -1.7,0.39 -0.57,0.18 -1.71,0.53 -2.29,0.71 l -0.82,0.24 c -0.56,0.19 -1.69,0.57 -2.25,0.76 l -0.81,0.23 -0.83,-0.05 c -0.53,0.21 -1.59,0.65 -2.12,0.87 l -0.83,0.19 c -0.57,0.18 -1.72,0.54 -2.29,0.73 l -0.82,0.250002 c -0.57,0.19 -1.7,0.58 -2.27,0.77 l -0.81,0.23 -0.83,-0.05 c -0.53,0.21 -1.58,0.65 -2.11,0.87 l -0.83,0.18 c -0.57,0.18 -1.69,0.54 -2.26,0.72 l -0.81,0.24 c -0.56,0.19 -1.67,0.57 -2.22,0.76 l -0.81,0.25 c -0.52,0.23 -1.58,0.67 -2.1,0.9 -0.53,0.2 -1.59,0.59 -2.12,0.79 l -0.77,0.25 c -0.54,0.13 -1.6,0.4 -2.14,0.53 l -0.62,0.4 0.17,0.54 c 0.23,0.76 0.46,1.52 0.7,2.29 l 0.19,0.61 c 0.42,-0.01 1.26,-0.03 1.68,-0.04 l 0.85,0 c 0.55,0.17 1.65,0.52 2.21,0.7 l 0.8,0.25 c 0.55,0.19 1.65,0.56 2.21,0.75 l 0.8,0.25 c 0.57,0.18 1.7,0.54 2.26,0.71 l 0.83,0.2 c 0.53,0.21 1.61,0.63 2.14,0.84 l 0.83,-0.07 0.83,0.2 c 0.96,0.75 2.04,1.01 3.25,0.79 l 0.88,-0.04 c 0.68,0.11 2.03,0.32 2.71,0.43 0.6,0.15 1.81,0.45 2.42,0.59 0.42,0.1 1.27,0.3 1.69,0.4 0.54,0.2 1.61,0.59 2.15,0.79 l 0.68,0.32 c 0.33,0.09 0.99,0.25 1.31,0.34 l 0.71,-0.02 c -0.2,0.55 -0.58,1.64 -0.78,2.19 -0.45,1.29 -1.09,2.52 -1.69,3.76 -1.54,0 -2.88,0.8 -4.06,1.7 -0.25,0.2 -0.75,0.61 -1,0.82 l -0.48,0.43 c -0.25,0.21 -0.75,0.61 -1,0.81 -1.23,0.36 -2.39,0.94 -3.3,1.85 -0.36,0.4 -1.1,1.21 -1.47,1.62 l -0.5,0.5 c -0.28,0.18 -0.83,0.52 -1.1,0.69 l -0.63,0.02 -0.63,-0.04 c -0.27,-0.14 -0.81,-0.41 -1.08,-0.55 -0.26,-0.16 -0.78,-0.49 -1.04,-0.66 -0.28,-0.18 -0.83,-0.54 -1.1,-0.72 l -0.59,-0.4 c -0.29,-0.2 -0.87,-0.6 -1.16,-0.79 -0.3,-0.2 -0.89,-0.59 -1.19,-0.79 l -0.63,-0.4 c -0.3,-0.19 -0.9,-0.57 -1.2,-0.76 -0.28,-0.21 -0.82,-0.61 -1.09,-0.82 l -0.67,-0.27 c -0.31,-0.19 -0.93,-0.58 -1.24,-0.77 l -0.65,-0.41 c -0.31,-0.2 -0.93,-0.6 -1.23,-0.8 -0.31,-0.21 -0.93,-0.61 -1.24,-0.81 l -0.64,-0.42 c -0.31,-0.21 -0.91,-0.62 -1.22,-0.83 -0.3,-0.21 -0.9,-0.62 -1.2,-0.82 l -0.63,-0.43 c -0.29,-0.2 -0.87,-0.62 -1.16,-0.82 -0.28,-0.2 -0.83,-0.6 -1.11,-0.8 -0.26,-0.21 -0.77,-0.63 -1.03,-0.84 l -0.62,-0.31 c -0.29,-0.2 -0.86,-0.6 -1.14,-0.81 -0.3,-0.2 -0.89,-0.6 -1.18,-0.81 l -0.63,-0.41 c -0.3,-0.2 -0.9,-0.6 -1.2,-0.8 -0.31,-0.19 -0.92,-0.56 -1.22,-0.75 l -0.64,-0.36 c -0.31,-0.17 -0.92,-0.51 -1.23,-0.68 -0.29,-0.15 -0.88,-0.46 -1.18,-0.62 l -0.72,-0.14 -0.74,-0.2 c -0.58,-1.39 -1.32,-1.5 -2.22,-0.32 -0.66,0.02 -1.99,0.07 -2.66,0.09 -1.79,-0.26 -3.55,0.52 -4.44,2.13 l -0.54,0.65 c -0.15,0.57 -0.44,1.71 -0.58,2.27 l -0.2,0.84 c -0.18,0.57 -0.55,1.72 -0.73,2.3 l -0.24,0.85 c -0.15,0.63 -0.46,1.89 -0.61,2.52 0.08,0.49 0.22,1.49 0.3,1.98 l -0.52,-0.35 c 0.08,0.3 0.24,0.91 0.32,1.21 0.15,0.32 0.45,0.96 0.6,1.28 0.17,0.29 0.5,0.86 0.67,1.15 0.21,0.25 0.63,0.75 0.84,1 0.24,0.22 0.72,0.67 0.97,0.89 l 0.52,0.44 c 0.24,0.21 0.73,0.64 0.98,0.85 0.22,0.22 0.65,0.67 0.86,0.89 l 0.53,0.38 c 0.2,0.26 0.59,0.8 0.78,1.07 0.09,0.34 0.25,1.02 0.34,1.36 0,0.31 0.01,0.94 0.02,1.25 l 0.39,-0.45 c -0.2,0.56 -0.61,1.66 -0.81,2.22 -0.07,0.32 -0.2,0.96 -0.27,1.28 l 0.49,-0.42 -0.67,0.52 c -0.32,0.48 -0.97,1.43 -1.3,1.91 l -0.17,0.79 c -0.03,0.4 -0.09,1.2 -0.11,1.61 -0.46,0.06 -1.37,0.18 -1.83,0.25 -1.52,0.03 -3,0.37 -4.37,0.98 -0.7,0.1 -2.11,0.28 -2.81,0.38 l -0.94,0.04 c -1.75,-0.01 -5.24,-0.03 -6.98,-0.04 -0.73,-0.11 -2.19,-0.33 -2.91,-0.44 -1,-0.7 -2.09,-0.99 -3.29,-0.87 l -0.73,-0.27 c -0.31,-0.14 -0.95,-0.43 -1.27,-0.58 l -0.61,-0.31 c -0.28,-0.18 -0.83,-0.53 -1.11,-0.71 l -0.53,-0.41 c -0.23,-0.25 -0.69,-0.74 -0.92,-0.99 l -0.39,-0.6 c -0.16,-0.34 -0.49,-1.01 -0.65,-1.35 l -0.24,-0.81 c -0.06,-0.69 -0.18,-2.07 -0.25,-2.75 0.07,-0.71 0.19,-2.13 0.25,-2.83 0.17,-0.36 0.5,-1.08 0.67,-1.43 -0.01,-0.43 -0.01,-1.28 -0.02,-1.71 l 0.18,-0.82 c 0.18,-0.34 0.54,-1 0.73,-1.34 0.02,-0.42 0.07,-1.27 0.09,-1.7 l 0.23,-0.85 c 0.17,-0.58 0.53,-1.75 0.7,-2.33 l 0.19,-0.8 c 0.2,-0.31 0.61,-0.91 0.82,-1.21 0.05,-0.41 0.15,-1.23 0.2,-1.65 l 0.36,-0.77 c 0.14,-0.4 0.42,-1.21 0.56,-1.61 l -0.78,-0.26 c -2.71,-0.95 -5.39,-1.57 -8.1,-2.36 -0.38,0.05 -1.15,0.14 -1.53,0.19 -3.58,-0.27 -7.09,-0.38 -10.65,-0.39 -6.39,-0.14 -12.77,0.3 -19.13,-0.1 -0.54,0.18 -1.61,0.52 -2.15,0.69 -0.36,0.09 -1.08,0.27 -1.44,0.36 -0.3,0.1 -0.89,0.3 -1.19,0.4 l 0.71,0.26 c -1.46,-0.04 -1.69,0.56 -0.71,1.8 l 0.07,0.82 c 0,0.4 0,1.21 0,1.61 0.16,0.33 0.47,0.98 0.63,1.31 l 0.14,0.79 c 0.06,0.61 0.17,1.82 0.22,2.43 0.17,0.32 0.5,0.97 0.67,1.29 l 0.24,0.77 c 0.27,0.51 0.8,1.53 1.07,2.04 0.49,0.31 1.48,0.93 1.98,1.23 0.42,0.11 1.25,0.32 1.67,0.42 1.31,0.63 2.73,1 4.19,1.09 0.45,0.07 1.34,0.21 1.79,0.29 0.02,0.43 0.05,1.29 0.07,1.71 l 0.11,0.87 c 0.05,0.43 0.14,1.31 0.19,1.75 l -0.19,0.89 c -0.04,0.44 -0.12,1.33 -0.16,1.77 -1.16,-0.14 -2.02,0.34 -2.57,1.45 -0.43,0.36 -1.3,1.07 -1.73,1.42 -0.12,0.39 -0.35,1.16 -0.47,1.55 l -0.87,-0.12 c -1.23,-0.3 -2.33,-0.04 -3.3,0.79 -1.69,-0.03 -5.06,-0.09 -6.74,-0.13 -1.78,-0.4 -3.59,-0.63 -5.4,-0.61 l -0.87,-0.04 c -0.42,-0.08 -1.28,-0.25 -1.71,-0.34 -0.56,-0.17 -1.67,-0.51 -2.23,-0.68 l -0.7,-0.26 c -0.26,-0.18 -0.79,-0.55 -1.05,-0.73 l -0.63,-0.19 c -0.25,-0.23 -0.74,-0.68 -0.99,-0.9 -0.31,-0.44 -0.94,-1.33 -1.25,-1.77 -0.22,-0.55 -0.65,-1.63 -0.87,-2.17 -0.11,-0.42 -0.34,-1.26 -0.46,-1.67 -0.15,-0.59 -0.47,-1.76 -0.62,-2.35 -0.08,-0.43 -0.24,-1.29 -0.32,-1.72 0.24,-1.21 0,-2.31 -0.7,-3.29 -0.07,-0.43 -0.23,-1.3 -0.3,-1.73 0.24,-1.21 0.01,-2.32 -0.68,-3.31 -0.09,-0.67 -0.27,-1.99 -0.36,-2.65 0.28,-1.2 0.08,-2.3 -0.6,-3.29 -0.12,-0.42 -0.36,-1.25 -0.47,-1.66 -0.4,-0.41 -1.19,-1.21 -1.58,-1.62 -1.12,-0.22 -2.23,-0.48 -3.31,-0.79 -1.11,-0.93 -2.62,-0.28 -2.98,1.03 -0.23,0.22 -0.69,0.65 -0.92,0.86 l -0.33,0.58 c -0.19,0.29 -0.57,0.85 -0.76,1.13 l -0.39,0.59 c -0.19,0.29 -0.57,0.86 -0.75,1.15 -0.2,0.26 -0.6,0.79 -0.8,1.06 l -0.28,0.63 c -0.19,0.28 -0.58,0.86 -0.77,1.14 -0.21,0.27 -0.63,0.8 -0.84,1.06 l -0.32,0.65 c -0.21,0.3 -0.63,0.88 -0.85,1.17 -0.22,0.3 -0.66,0.9 -0.88,1.2 l -0.47,0.62 c -0.23,0.29 -0.7,0.87 -0.93,1.16 -0.24,0.27 -0.71,0.81 -0.95,1.08 -0.24,0.25 -0.72,0.77 -0.96,1.02 -0.25,0.25 -0.75,0.75 -1,0.99 -0.25,0.24 -0.76,0.71 -1.02,0.95 -0.26,0.23 -0.79,0.68 -1.06,0.91 -0.28,0.21 -0.84,0.64 -1.11,0.85 l -0.65,0.28 c -0.28,0.2 -0.82,0.59 -1.1,0.79 l -0.67,0.19 c -0.3,0.16 -0.89,0.49 -1.19,0.65 l -0.67,0.25 c -0.34,0.09 -1.01,0.29 -1.34,0.38 l -0.7,0.06 c -0.32,-0.08 -0.97,-0.23 -1.29,-0.31 l -0.73,0.01 c -0.36,-0.13 -1.07,-0.37 -1.43,-0.5 -0.32,-0.17 -0.95,-0.53 -1.26,-0.71 l -0.6,-0.43 c -0.24,-0.26 -0.73,-0.77 -0.97,-1.03 -0.36,-0.12 -1.1,-0.36 -1.47,-0.49 -0.04,-1.19 -0.55,-2.15 -1.52,-2.86 -0.17,-0.37 -0.49,-1.11 -0.65,-1.47 l -0.35,-0.82 c -0.02,-3.04 -0.02,-5.92 0.08,-8.89 l 0.13,-0.88 0.25,-0.81 c 0.17,-0.3 0.51,-0.91 0.68,-1.21 l 0.13,-0.68 c 0.19,-0.25 0.57,-0.76 0.76,-1.01 l 0.26,-0.59 c 0.22,-0.24 0.65,-0.72 0.86,-0.96 0.26,-0.21 0.78,-0.65 1.03,-0.86 l 0.61,-0.41 c 0.32,-0.19 0.97,-0.57 1.29,-0.75 l 0.74,-0.36 c 0.57,-0.25 1.71,-0.73 2.28,-0.98 l 0.81,-0.34 c 0.52,-0.29 1.57,-0.86 2.09,-1.14 l 0.6,-0.46 c 0.23,-0.21 0.69,-0.65 0.92,-0.86 l 0.29,-0.54 c 0.12,-0.25 0.37,-0.76 0.49,-1.01 l 0.15,-0.55 c 0.09,-0.25 0.25,-0.74 0.33,-0.99 -0.16,-0.21 -0.49,-0.62 -0.66,-0.83 -0.4,-0.33 -1.2,-1.000002 -1.6,-1.330002 l -0.66,-0.34 c -0.28,-0.17 -0.85,-0.51 -1.14,-0.68 l -0.7,-0.15 -0.67,-0.29 c -0.33,-0.14 -0.98,-0.43 -1.31,-0.57 l -0.67,-0.3 c -0.34,-0.15 -1,-0.44 -1.34,-0.59 l -0.71,-0.3 c -0.36,-0.14 -1.09,-0.42 -1.45,-0.56 -0.42,-0.14 -1.25,-0.41 -1.67,-0.54 -1.07,-0.7 -2.23,-0.98 -3.48,-0.83 -0.44,-0.08 -1.33,-0.23 -1.77,-0.31 -0.36,-0.16 -1.07,-0.48 -1.43,-0.64 -0.65,-0.04 -1.94,-0.11 -2.59,-0.15 l -0.84,-0.16 c -0.34,-0.17 -1.03,-0.51 -1.38,-0.68 -0.42,-0.02 -1.27,-0.05 -1.7,-0.06 l -0.83,-0.19 c -0.34,-0.18 -1.03,-0.55 -1.37,-0.74 -0.44,-0.03 -1.33,-0.09 -1.77,-0.11 l -0.88,-0.26 c -0.6,-0.19 -1.82,-0.58 -2.43,-0.78 l -0.8,-0.26 c -0.32,-0.17 -0.97,-0.51 -1.29,-0.68 l -0.76,-0.1 -0.7,-0.3 c -0.33,-0.16 -0.99,-0.47 -1.31,-0.63 l -0.65,-0.32 c -0.29,-0.16 -0.88,-0.49 -1.18,-0.66 l -0.57,-0.32 c -0.24,-0.18 -0.73,-0.52 -0.98,-0.69 -0.21,-0.18 -0.64,-0.54 -0.85,-0.72 -0.2,-0.21 -0.6,-0.63 -0.8,-0.83 l -0.01,-0.64 0.39,-0.57 0.69,0.24 c 0.55,0.12 1.65,0.37 2.19,0.5 l 0.82,0.18 c 0.54,0.2 1.62,0.61 2.16,0.82 l 0.83,-0.06 0.83,0.18 c 0.55,0.22 1.65,0.65 2.2,0.87 l 0.85,-0.05 0.85,0.23 c 1.03,0.7 2.18,0.97 3.43,0.8 0.69,0.12 2.06,0.35 2.75,0.47 1.27,0.5 2.68,1.04 4.06,0.59 l 0.74,-0.14 c 0.91,-0.41 2.71,-0.11 2.88,-1.4 -0.06,-0.25 -0.19,-0.76 -0.26,-1.01 -0.22,-0.18 -0.68,-0.55 -0.91,-0.73 l -0.49,-0.32 c -0.23,-0.16 -0.69,-0.49 -0.92,-0.65 -0.21,-0.16 -0.63,-0.5 -0.84,-0.67 l -0.45,-0.32 c -0.17,-0.21 -0.53,-0.62 -0.7,-0.82 -0.12,-0.25 -0.35,-0.74 -0.46,-0.99 l 0.01,-0.56 0.33,-0.46 c 0.16,-0.23 0.46,-0.7 0.61,-0.93 l 0.45,-0.38 c 0.2,-0.23 0.58,-0.7 0.78,-0.93 0.21,-0.27 0.64,-0.82 0.85,-1.09 l 0.47,-0.63 c 0.31,-0.49 0.94,-1.47 1.25,-1.96 0.22,-0.27 0.67,-0.82 0.89,-1.09 l 0.28,-0.66 c 0.21,-0.28 0.63,-0.82 0.84,-1.1 0.22,-0.26 0.64,-0.79 0.86,-1.05 0.22,-0.26 0.65,-0.78 0.87,-1.04 0.22,-0.27 0.66,-0.81 0.88,-1.08 0.22,-0.29 0.65,-0.86 0.87,-1.15 l 0.45,-0.63 c 0.22,-0.3 0.65,-0.9 0.86,-1.21 0.21,-0.31 0.63,-0.93 0.84,-1.24 l 0.42,-0.65 c 0.2,-0.31 0.6,-0.92 0.8,-1.23 0.22,-0.27 0.64,-0.82 0.85,-1.09 l 0.29,-0.67 c 0.19,-0.29 0.59,-0.89 0.78,-1.18 0.21,-0.27 0.64,-0.82 0.85,-1.09 l 0.3,-0.66 c 0.2,-0.3 0.6,-0.9 0.8,-1.2 0.22,-0.27 0.65,-0.82 0.87,-1.1 l 0.31,-0.67 c 0.2,-0.3 0.61,-0.9 0.81,-1.2 0.22,-0.28 0.66,-0.83 0.87,-1.1 l 0.32,-0.67 c 0.2,-0.3 0.62,-0.9 0.82,-1.19 0.23,-0.27 0.67,-0.81 0.9,-1.08 l 0.32,-0.66 c 0.22,-0.29 0.65,-0.87 0.87,-1.16 0.21,-0.29 0.64,-0.86 0.86,-1.14 0.22,-0.26 0.68,-0.77 0.91,-1.03 l 0.35,-0.63 c 0.22,-0.28 0.67,-0.84 0.89,-1.11 0.23,-0.28 0.69,-0.83 0.91,-1.1 0.23,-0.28 0.69,-0.83 0.92,-1.11 0.23,-0.29 0.7,-0.86 0.93,-1.14 l 0.48,-0.61 c 0.24,-0.27 0.71,-0.83 0.94,-1.11 0.24,-0.26 0.71,-0.79 0.94,-1.05 0.24,-0.25 0.71,-0.75 0.95,-1 0.24,-0.25 0.73,-0.73 0.97,-0.97 0.25,-0.24 0.75,-0.71 1,-0.94 0.25,-0.24 0.77,-0.7 1.03,-0.93 0.28,-0.23 0.82,-0.69 1.1,-0.92 l 0.58,-0.47 c 0.28,-0.22 0.84,-0.67 1.12,-0.89 0.27,-0.22 0.81,-0.65 1.08,-0.87 0.27,-0.22 0.82,-0.65 1.09,-0.87 0.28,-0.21 0.85,-0.64 1.13,-0.85 l 0.61,-0.43 c 0.29,-0.2 0.88,-0.61 1.18,-0.82 0.3,-0.19 0.9,-0.58 1.2,-0.77 l 0.63,-0.38 c 0.3,-0.17 0.91,-0.51 1.22,-0.68 l 0.63,-0.26 c 0.21,-0.22 0.63,-0.66 0.84,-0.87 0.61,-0.19 1.82,-0.56 2.42,-0.75 l 0.84,-0.37 c 0.57,-0.24 1.73,-0.71 2.31,-0.94 0.41,-0.04 1.24,-0.11 1.66,-0.15 0.31,-0.2 0.93,-0.6 1.24,-0.8 l 0.81,-0.2 c 0.6,-0.16 1.8,-0.48 2.4,-0.64 0.45,-0.08 1.36,-0.25 1.81,-0.34 1.19,0 2.39,-0.04 3.59,-0.11 l 0.82,0.17 0.38,-0.76 c 1.2,-0.18 2.41,-0.29 3.64,-0.33 2.49,-0.05 4.98,-0.21 7.47,-0.48 z" id="path9046" inkscape:connector-curvature="0" style="fill:#000000;stroke:#000000;stroke-width:0.09375"/>
+</svg> \ No newline at end of file
diff --git a/tests/auto/quick/qquicktextedit/data/inFlickable.qml b/tests/auto/quick/qquicktextedit/data/inFlickable.qml
index 7a896db29b..183ddd6701 100644
--- a/tests/auto/quick/qquicktextedit/data/inFlickable.qml
+++ b/tests/auto/quick/qquicktextedit/data/inFlickable.qml
@@ -1,6 +1,7 @@
import QtQuick 2.0
Flickable {
+ id: flick
width: 320; height: 120; contentHeight: text.height
TextEdit {
id: text
@@ -8,4 +9,10 @@ Flickable {
font.pixelSize: 20
text: "several\nlines\nof\ntext\n-\ntry\nto\nflick"
}
+ Text {
+ color: "red"
+ parent: flick // stay on top
+ anchors.right: parent.right
+ text: flick.contentY.toFixed(1)
+ }
}
diff --git a/tests/auto/quick/qquicktextedit/data/keyEventPropagation.qml b/tests/auto/quick/qquicktextedit/data/keyEventPropagation.qml
new file mode 100644
index 0000000000..7793827b77
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/keyEventPropagation.qml
@@ -0,0 +1,31 @@
+import QtQuick
+
+FocusScope {
+ Component.onCompleted: edit.forceActiveFocus()
+
+ anchors.fill: parent
+
+ Keys.onPressed: function(event) { keyDown(event.key) }
+ Keys.onReleased: function(event) { keyUp(event.key) }
+ signal keyDown(int key)
+ signal keyUp(int key)
+
+ TextEdit {
+ id: edit
+ anchors.centerIn: parent
+ width: 50
+ height: 50
+ Keys.onPressed: function(event) {
+ event.accepted = event.key == Qt.Key_A || event.key == Qt.Key_Right
+ }
+ Keys.onReleased: function(event) {
+ event.accepted = event.key == Qt.Key_A
+ }
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: -5
+ color: "transparent"
+ border.width: 1
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktextedit/data/keys_shortcutoverride.qml b/tests/auto/quick/qquicktextedit/data/keys_shortcutoverride.qml
index 24bd434830..b753d844be 100644
--- a/tests/auto/quick/qquicktextedit/data/keys_shortcutoverride.qml
+++ b/tests/auto/quick/qquicktextedit/data/keys_shortcutoverride.qml
@@ -14,7 +14,7 @@ Item {
id: txt
x: 100
text: "enter text"
- Keys.onShortcutOverride: {
+ Keys.onShortcutOverride: (event) => {
who = "TextEdit"
event.accepted = (event.key === Qt.Key_Escape)
}
@@ -26,7 +26,7 @@ Item {
height: width
focus: true
color: focus ? "red" : "gray"
- Keys.onShortcutOverride: {
+ Keys.onShortcutOverride: (event) => {
who = "Rectangle"
event.accepted = (event.key === Qt.Key_Escape)
}
diff --git a/tests/auto/quick/qquicktextedit/data/markdown.qml b/tests/auto/quick/qquicktextedit/data/markdown.qml
new file mode 100644
index 0000000000..aaabccb2a6
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/markdown.qml
@@ -0,0 +1,9 @@
+import QtQuick
+
+TextEdit {
+ id: te
+ width: 200
+ height: 200
+ textFormat: TextEdit.MarkdownText
+ Component.onCompleted: te.insert(te.length, "*whee*")
+}
diff --git a/tests/auto/quick/qquicktextedit/data/mouseselection_default.qml b/tests/auto/quick/qquicktextedit/data/mouseselection_old_default.qml
index ac32f4ced7..f08a2d72eb 100644
--- a/tests/auto/quick/qquicktextedit/data/mouseselection_default.qml
+++ b/tests/auto/quick/qquicktextedit/data/mouseselection_old_default.qml
@@ -1,7 +1,6 @@
-import QtQuick 2.0
+import QtQuick 6.3
TextEdit {
focus: true
text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- selectByMouse: false
}
diff --git a/tests/auto/quick/qquicktextedit/data/mouseselectionmode_default.qml b/tests/auto/quick/qquicktextedit/data/mouseselectionmode_default.qml
index 7c7cb0b6fc..9088357a5f 100644
--- a/tests/auto/quick/qquicktextedit/data/mouseselectionmode_default.qml
+++ b/tests/auto/quick/qquicktextedit/data/mouseselectionmode_default.qml
@@ -1,7 +1,6 @@
-import QtQuick 2.0
+import QtQuick
TextEdit {
focus: true
text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- selectByMouse: true
}
diff --git a/tests/auto/quick/qquicktextedit/data/multipleRemoteImages.md b/tests/auto/quick/qquicktextedit/data/multipleRemoteImages.md
new file mode 100644
index 0000000000..370924e739
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/multipleRemoteImages.md
@@ -0,0 +1,13 @@
+# Images
+
+Unsupported URL scheme: ![alt text](gopher://qt.io/icon48.png "Qt doesnt't support gopher")
+
+Just an image, expected to work: ![alt text](serverBaseUrl/exists.png "Qt logo")
+
+Reference-style, same image: ![alt text][logo]
+
+[logo]: serverBaseUrl/exists.png "Qt logo"
+
+Slow: ![Turtle](serverBaseUrl/turtle.svg "Behold the turtle")
+
+Fails to load from server: ![FailBang](serverBaseUrl/warning.png "Warning")
diff --git a/tests/auto/quick/qquicktextedit/data/qtConfigureHelp.qml b/tests/auto/quick/qquicktextedit/data/qtConfigureHelp.qml
new file mode 100644
index 0000000000..58ef58b372
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/qtConfigureHelp.qml
@@ -0,0 +1,186 @@
+import QtQuick
+import Qt.test 1.0
+
+NodeCheckerTextEdit {
+ id: textedit
+ width: 640
+ height: 480
+ text: "Usage: configure [options] [-- cmake-options]
+
+This is a convenience script for configuring Qt with CMake.
+Options after the double dash are directly passed to CMake.
+
+Top-level installation directories:
+ -prefix <dir> ...... The deployment directory, as seen on the target device.
+ [/usr/local/Qt-$QT_VERSION; qtbase build directory if
+ -developer-build]
+ -no-prefix ......... The deployment directory is set to the qtbase build
+ directory. Can be used instead of -developer-build
+ to not have to install, as well as avoid
+ -developer-build's default of -warnings-are-errors.
+ -extprefix <dir> ... The installation directory, as seen on the host machine.
+ [SYSROOT/PREFIX]
+
+Fine tuning of installation directory layout. Note that all directories
+except -sysconfdir should be located under -prefix:
+
+ -bindir <dir> ......... Executables [PREFIX/bin]
+ -headerdir <dir> ...... Header files [PREFIX/include]
+ -libdir <dir> ......... Libraries [PREFIX/lib]
+ -archdatadir <dir> .... Arch-dependent data [PREFIX]
+ -plugindir <dir> ...... Plugins [ARCHDATADIR/plugins]
+ -libexecdir <dir> ..... Helper programs [ARCHDATADIR/bin on Windows,
+ ARCHDATADIR/libexec otherwise]
+ -qmldir <dir> ......... QML imports [ARCHDATADIR/qml]
+ -datadir <dir> ........ Arch-independent data [PREFIX]
+ -docdir <dir> ......... Documentation [DATADIR/doc]
+ -translationdir <dir> . Translations [DATADIR/translations]
+ -sysconfdir <dir> ..... Settings used by Qt programs [PREFIX/etc/xdg]
+ -examplesdir <dir> .... Examples [PREFIX/examples]
+ -testsdir <dir> ....... Tests [PREFIX/tests]
+ -hostdatadir <dir> .... Data used by qmake [PREFIX]
+
+Conventions for the remaining options: When an option's description is
+followed by a list of values in brackets, the interpretation is as follows:
+'yes' represents the bare option; all other values are possible prefixes to
+the option, e.g., -no-gui. Alternatively, the value can be assigned, e.g.,
+--gui=yes. Values are listed in the order they are tried if not specified;
+'auto' is a shorthand for 'yes/no'. Solitary 'yes' and 'no' represent binary
+options without auto-detection.
+
+Configure meta:
+
+ -help, -h ............ Display this help screen
+ -redo ................ Re-configure with previously used options. In addition,
+ redo removes CMakeCache.txt file and CMakeFiles/ directory
+ and recreates them from scratch.
+ Additional options may be passed, but will not be
+ saved for later use by -redo.
+
+ -feature-<feature> ... Enable <feature>
+ -no-feature-<feature> Disable <feature> [none]
+ -list-features ....... List available features. Note that some features
+ have dedicated command line options as well.
+
+Build options:
+
+ -cmake-generator <name> ... Explicitly specify the build system generator for
+ CMake instead of auto-detecting one.
+ -cmake-use-default-generator ... Turn off auto-detection of the CMake build
+ system generatsr.
+ -cmake-file-api ...... Let CMake store build metadata for loading the build
+ into an IDE. [no; yes if -developer-build]
+ -no-guess-compiler ... Do not guess the compiler from the target mkspec.
+ -release ............. Build Qt with debugging turned off [yes]
+ -debug ............... Build Qt with debugging turned on [no]
+ -debug-and-release ... Build two versions of Qt, with and without
+ debugging turned on [yes] (Apple and Windows only)
+ -optimize-debug ...... Enable debug-friendly optimizations in debug builds
+ [auto] (Not supported with MSVC or Clang toolchains)
+ -optimize-size ....... Optimize release builds for size instead of speed [no]
+ -force-debug-info .... Create symbol files for release builds [no]
+ -separate-debug-info . Split off debug information to separate files [no]
+ -gdb-index ........... Index the debug info to speed up GDB
+ [no; auto if -developer-build with debug info]
+ -gc-binaries ......... Place each function or data item into its own section
+ and enable linker garbage collection of unused
+ sections. [auto for static builds, otherwise no]
+ -force-asserts ....... Enable Q_ASSERT even in release builds [no]
+ -developer-build ..... Compile and link Qt for developing Qt itself
+ (exports for auto-tests, extra checks, etc.) [no]
+
+ -shared .............. Build shared Qt libraries [yes] (no for UIKit)
+ -static .............. Build static Qt libraries [no] (yes for UIKit)
+ -framework ........... Build Qt framework bundles [yes] (Apple only)
+
+ -platform <target> ... Select mkspec for the qmake companion files
+ -device <name> ....... Select devices/mkspec for the qmake companion files
+ -device-option <key=value> ... Add option for the device mkspec
+
+ -appstore-compliant .. Disable code that is not allowed in platform app stores.
+ This is on by default for platforms which require distribution
+ through an app store by default, in particular Android,
+ iOS, tvOS, and watchOS. [auto]
+
+ -qt-host-path <path> . Specify path to a Qt host build for cross-compiling.
+ -qtnamespace <name> .. Wrap all Qt library code in 'namespace <name> {...}'.
+ -qtlibinfix <infix> .. Rename all libQt6*.so to libQt6*<infix>.so.
+
+ -testcocoon .......... Instrument with the TestCocoon code coverage tool [no]
+ -gcov ................ Instrument with the GCov code coverage tool [no]
+
+ -trace [backend] ..... Enable instrumentation with tracepoints.
+ Currently supported backends are 'etw' (Windows) and
+ 'lttng' (Linux), or 'yes' for auto-detection. [no]
+
+ -sanitize {address|thread|memory|fuzzer-no-link|undefined}
+ Instrument with the specified compiler sanitizer.
+ Note that some sanitizers cannot be combined;
+ for example, -sanitize address cannot be combined with
+ -sanitize thread.
+
+ -mips_dsp/-mips_dspr2 Use MIPS DSP/rev2 instructions [auto]
+
+ -qreal <type> ........ typedef qreal to the specified type. [double]
+ Note: this affects binary compatibility.
+
+ -R <string> .......... Add an explicit runtime library path to the Qt
+ libraries. Supports paths relative to LIBDIR.
+ -rpath ............... Link Qt libraries and executables using the library
+ install path as a runtime library path. Similar to
+ -R LIBDIR. On Apple platforms, disabling this implies
+ using absolute install names (based in LIBDIR) for
+ dynamic libraries and frameworks. [auto]
+
+ -reduce-exports ...... Reduce amount of exported symbols [auto]
+ -reduce-relocations .. Reduce amount of relocations [auto] (Unix only)
+
+ -plugin-manifests .... Embed manifests into plugins [no] (Windows only)
+ -static-runtime ...... With -static, use static runtime [no] (Windows only)
+
+ -pch ................. Use precompiled headers [auto]
+ -ltcg ................ Use Link Time Code Generation [no]
+ -intelcet ............ Use Intel Control-flow Enforcement Technology [no]
+ -linker [bfd,gold,lld,mold]
+ Force use of the GNU ld, GNU gold, LLVM/LLD or mold
+ linker instead of default one (GCC and clang only)
+ -ccache .............. Use the ccache compiler cache [no] (Unix only)
+ -unity-build ......... Enable Unity (Jumbo) build
+ -unity-build-batch-size <int>
+ Maximum number of source files used by the unity build
+ to create unity source files [8]
+
+ -warnings-are-errors . Treat warnings as errors [no; yes if -developer-build]
+
+ -disable-deprecated-up-to <version>
+ Set the QT_DISABLE_DEPRECATED_UP_TO value to <version>.
+ QT_DISABLE_DEPRECATED_UP_TO is used to remove
+ deprecated methods from both API and ABI.
+ <version> is a hex value, for example 0x060500 can be
+ used to remove all code deprecated in Qt 6.5.0 or
+ earlier releases.
+ By default <version> is set to 0x040000 and 0x050000 on
+ Windows, and non-Windows respectively.
+ -disable-deprecated-up-to <version>
+ Set the QT_DISABLE_DEPRECATED_UP_TO value to <version>.
+ QT_DISABLE_DEPRECATED_UP_TO is used to remove
+ deprecated methods from both API and ABI.
+ <version> is a hex value, for example 0x060500 can be
+ used to remove all code deprecated in Qt 6.5.0 or
+ earlier releases.
+ By default <version> is set to 0x040000 and 0x050000 on
+ Windows, and non-Windows respectively.
+used to remove all code deprecated in Qt 6.5.0 or
+ earlier releases.
+
+Build environment:
+
+ -sysroot <dir> ....... Set <dir> as the target sysroot
+
+ -pkg-config .......... Use pkg-config [auto] (Unix only)
+
+ -D <string> .......... Pass additional preprocessor define
+ -I <string> .......... Pass additional include path
+ -L <string> .......... Pass additional library path
+ -F <string> .......... Pass additional framework path (Apple only)>"
+}
diff --git a/tests/auto/quick/qquicktextedit/data/qtbug-112858.qml b/tests/auto/quick/qquicktextedit/data/qtbug-112858.qml
new file mode 100644
index 0000000000..95f7905737
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/qtbug-112858.qml
@@ -0,0 +1,12 @@
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ id: layout
+ TextEdit {
+ readOnly: true
+ text: 'שדגשגשגשגדוגמ×
+בעיות יישור
+טֶקסט'
+ }
+}
diff --git a/tests/auto/quick/qquicktextedit/data/resizeTextEditPolish.qml b/tests/auto/quick/qquicktextedit/data/resizeTextEditPolish.qml
new file mode 100644
index 0000000000..44819a0de9
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/resizeTextEditPolish.qml
@@ -0,0 +1,42 @@
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: 400
+ height: 150
+
+ TextEdit {
+ id: textEdit
+ anchors {
+ top: parent.top
+ left: parent.left
+ right: parent.right
+ }
+ readOnly: true
+ wrapMode: Text.WordWrap
+ verticalAlignment: Text.AlignVCenter
+ text: "Lorem ipsum dolor sit amet, consectetur adipisicing"
+ states: [
+ State {
+ name: "multi-line"
+ when: textEdit.lineCount > 1
+ AnchorChanges {
+ target: textEdit
+ anchors.bottom: undefined
+ }
+ PropertyChanges {
+ target: textEdit
+ height: undefined
+ }
+ },
+ State {
+ name: "single-line"
+ when: true
+ AnchorChanges {
+ target: textEdit
+ anchors.bottom: { return textEdit.parent.bottom }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/auto/quick/qquicktextedit/data/tarzeau_ocr_a.ttf b/tests/auto/quick/qquicktextedit/data/tarzeau_ocr_a.ttf
new file mode 100644
index 0000000000..cf93f9651f
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/tarzeau_ocr_a.ttf
Binary files differ
diff --git a/tests/auto/quick/qquicktextedit/data/textEdit.qml b/tests/auto/quick/qquicktextedit/data/textEdit.qml
new file mode 100644
index 0000000000..3bcc40350e
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/textEdit.qml
@@ -0,0 +1,6 @@
+import QtQuick
+
+TextEdit {
+ width: 400
+ height: 540
+}
diff --git a/tests/auto/quick/qquicktextedit/data/threeLines.qml b/tests/auto/quick/qquicktextedit/data/threeLines.qml
new file mode 100644
index 0000000000..cee03bfa15
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/threeLines.qml
@@ -0,0 +1,7 @@
+import QtQuick
+import Qt.test 1.0
+
+NodeCheckerTextEdit {
+ width: 200; height: 100
+ text: "Line 1\nLine 2\nLine 3\n"
+}
diff --git a/tests/auto/quick/qquicktextedit/data/twoInAColumn.qml b/tests/auto/quick/qquicktextedit/data/twoInAColumn.qml
new file mode 100644
index 0000000000..4fde0e0170
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/twoInAColumn.qml
@@ -0,0 +1,32 @@
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ height: 200
+ width: 400
+ spacing: -6
+ Rectangle {
+ border.color: top.activeFocus ? "steelblue" : "lightgrey"
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ Layout.margins: 6
+ TextEdit {
+ id: top
+ objectName: "top"
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ anchors.fill: parent
+ }
+ }
+ Rectangle {
+ border.color: bottom.activeFocus ? "steelblue" : "lightgrey"
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ Layout.margins: 6
+ TextEdit {
+ id: bottom
+ objectName: "bottom"
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ anchors.fill: parent
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktextedit/data/viewport.qml b/tests/auto/quick/qquicktextedit/data/viewport.qml
new file mode 100644
index 0000000000..0e2cc139a6
--- /dev/null
+++ b/tests/auto/quick/qquicktextedit/data/viewport.qml
@@ -0,0 +1,33 @@
+import QtQuick
+
+Item {
+ width: 480; height: 480
+
+ Rectangle {
+ id: viewport
+ anchors.fill: parent
+ anchors.margins: 100
+ border.color: "red"
+
+ FontLoader {
+ id: ocr
+ source: "tarzeau_ocr_a.ttf"
+ }
+
+ TextEdit {
+ font.family: ocr.font.family
+ font.styleName: ocr.font.styleName
+ font.pixelSize: 15
+ cursorDelegate: Rectangle {
+ border.color: "green"
+ border.width: 2
+ color: "transparent"
+ width: 10
+ }
+ Component.onCompleted: {
+ for (let i = 0; i < 25; ++i)
+ text += "Line " + i + "\n";
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
index 83d0fd9d27..cc994fe783 100644
--- a/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
+++ b/tests/auto/quick/qquicktextedit/tst_qquicktextedit.cpp
@@ -1,47 +1,27 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtTest/QSignalSpy>
-#include "../../shared/testhttpserver.h"
+#include <QtQuickTestUtils/private/testhttpserver_p.h>
#include <math.h>
#include <QFile>
+#include <QtQuick/QQuickTextDocument>
+#include <QtQuickTest/QtQuickTest>
#include <QTextDocument>
+#include <QtGui/qtextobject.h>
+#include <QtGui/QTextTable>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlexpression.h>
#include <QtQml/qqmlcomponent.h>
#include <QtGui/qguiapplication.h>
+#include <QtGui/private/qguiapplication_p.h>
#include <private/qquickflickable_p.h>
#include <private/qquickrectangle_p.h>
#include <private/qquicktextedit_p.h>
#include <private/qquicktextedit_p_p.h>
#include <private/qquicktext_p.h>
-#include <private/qquicktextdocument_p.h>
+#include <QtQuick/private/qquickpixmapcache_p.h>
#include <QFontMetrics>
#include <QtQuick/QQuickView>
#include <QDir>
@@ -50,46 +30,44 @@
#include <QClipboard>
#include <QMimeData>
#include <private/qquicktextcontrol_p.h>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
-#include "../../shared/platformquirks.h"
-#include "../../shared/platforminputcontext.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+#include <QtQuickTestUtils/private/platformquirks_p.h>
+#include <QtQuickTestUtils/private/platforminputcontext_p.h>
#include <private/qinputmethod_p.h>
#include <QtGui/qstylehints.h>
#include <qmath.h>
-#ifdef Q_OS_MAC
-#include <Carbon/Carbon.h>
-#endif
-
Q_DECLARE_METATYPE(QQuickTextEdit::SelectionMode)
Q_DECLARE_METATYPE(Qt::Key)
DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
-Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
+typedef QList<int> IntList;
+Q_DECLARE_METATYPE(IntList)
-static bool isPlatformWayland()
-{
- return !QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive);
-}
+typedef QPair<int, QChar> Key;
+typedef QList<Key> KeyList;
+Q_DECLARE_METATYPE(KeyList)
-QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& actual)
-{
- // XXX This will be replaced by some clever persistent platform image store.
- QString persistent_dir = QQmlDataTest::instance()->dataDirectory();
- QString arch = "unknown-architecture"; // QTest needs to help with this.
+Q_DECLARE_METATYPE(QQuickTextEdit::HAlignment)
+Q_DECLARE_METATYPE(QQuickTextEdit::VAlignment)
+Q_DECLARE_METATYPE(QQuickTextEdit::TextFormat)
+
+#if QT_CONFIG(shortcut)
+Q_DECLARE_METATYPE(QKeySequence::StandardKey)
+#endif
- QString expectfile = persistent_dir + QDir::separator() + filebasename + QLatin1Char('-') + arch + ".png";
+Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
- if (!QFile::exists(expectfile)) {
- actual.save(expectfile);
- qWarning() << "created" << expectfile;
- }
+// #define DEBUG_WRITE_INPUT
- return expectfile;
+static bool isPlatformWayland()
+{
+ return !QGuiApplication::platformName().compare(QLatin1String("wayland"), Qt::CaseInsensitive);
}
-typedef QPair<int, QChar> Key;
+QT_BEGIN_NAMESPACE
class tst_qquicktextedit : public QQmlDataTest
@@ -99,6 +77,8 @@ public:
tst_qquicktextedit();
private slots:
+ void initTestCase() override;
+
void cleanup();
void text();
void width();
@@ -178,6 +158,12 @@ private slots:
void clipRect();
void implicitSizeBinding_data();
void implicitSizeBinding();
+ void largeTextObservesViewport_data();
+ void largeTextObservesViewport();
+ void largeTextSelection();
+ void renderingAroundSelection();
+ void largeTextTables_data();
+ void largeTextTables();
void signal_editingfinished();
@@ -214,6 +200,7 @@ private slots:
void baseUrl();
void embeddedImages();
void embeddedImages_data();
+ void remoteImagesInDocumentSource();
void emptytags_QTBUG_22058();
void cursorRectangle_QTBUG_38947();
@@ -232,6 +219,24 @@ private slots:
void inFlickableTouch_data();
void inFlickableTouch();
+ void keyEventPropagation();
+
+ void markdown();
+#if QT_CONFIG(clipboard)
+ void pasteHtmlIntoMarkdown();
+#endif
+
+ void touchscreenDoesNotSelect_data();
+ void touchscreenDoesNotSelect();
+ void touchscreenSetsFocusAndMovesCursor();
+
+ void longPressInputMethod();
+
+ void rtlAlignmentInColumnLayout_QTBUG_112858();
+
+ void fontManipulationWithCursorSelection();
+ void resizeTextEditPolish();
+
private:
void simulateKeys(QWindow *window, const QList<Key> &keys);
#if QT_CONFIG(shortcut)
@@ -239,6 +244,8 @@ private:
#endif
void simulateKey(QWindow *, int key, Qt::KeyboardModifiers modifiers = {});
+ bool isMainFontFixed();
+ static bool hasWindowActivation();
QStringList standard;
QStringList richText;
@@ -256,19 +263,9 @@ private:
QPointingDevice *touchDevice = QTest::createTouchDevice();
};
-typedef QList<int> IntList;
-Q_DECLARE_METATYPE(IntList)
-
-typedef QList<Key> KeyList;
-Q_DECLARE_METATYPE(KeyList)
-
-Q_DECLARE_METATYPE(QQuickTextEdit::HAlignment)
-Q_DECLARE_METATYPE(QQuickTextEdit::VAlignment)
-Q_DECLARE_METATYPE(QQuickTextEdit::TextFormat)
-
void tst_qquicktextedit::simulateKeys(QWindow *window, const QList<Key> &keys)
{
- for (int i = 0; i < keys.count(); ++i) {
+ for (int i = 0; i < keys.size(); ++i) {
const int key = keys.at(i).first;
const int modifiers = key & Qt::KeyboardModifierMask;
const QString text = !keys.at(i).second.isNull() ? QString(keys.at(i).second) : QString();
@@ -292,7 +289,7 @@ void tst_qquicktextedit::simulateKeys(QWindow *window, const QKeySequence &seque
QList<Key> &operator <<(QList<Key> &keys, const QKeySequence &sequence)
{
for (int i = 0; i < sequence.count(); ++i)
- keys << Key(sequence[i], QChar());
+ keys << Key(sequence[i].toCombined(), QChar());
return keys;
}
@@ -315,6 +312,7 @@ QList<Key> &operator <<(QList<Key> &keys, Qt::Key key)
}
tst_qquicktextedit::tst_qquicktextedit()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
qRegisterMetaType<QQuickTextEdit::TextFormat>();
qRegisterMetaType<QQuickTextEdit::SelectionMode>();
@@ -362,6 +360,54 @@ tst_qquicktextedit::tst_qquicktextedit()
//
}
+class NodeCheckerTextEdit : public QQuickTextEdit
+{
+public:
+ NodeCheckerTextEdit(QQuickItem *parent = nullptr) : QQuickTextEdit(parent) {}
+
+ void populateLinePositions(QSGNode *node)
+ {
+ sortedLinePositions.clear();
+ lastLinePosition = 0;
+ QSGNode *ch = node->firstChild();
+ while (ch != node->lastChild()) {
+ QCOMPARE(ch->type(), QSGNode::TransformNodeType);
+ QSGTransformNode *tn = static_cast<QSGTransformNode *>(ch);
+ int y = 0;
+ if (!tn->matrix().isIdentity())
+ y = tn->matrix().column(3).y();
+ if (tn->childCount() == 0) {
+ // A TransformNode with no children is a waste of memory.
+ // So far, QQuickTextEdit still creates a couple of extras.
+ qCDebug(lcTests) << "ignoring leaf TransformNode" << tn << "@ y" << y;
+ } else {
+ qCDebug(lcTests) << "child" << tn << "@ y" << y << "has children" << tn->childCount();
+ sortedLinePositions.append(y);
+ lastLinePosition = qMax(lastLinePosition, y);
+ }
+ ch = ch->nextSibling();
+ }
+ std::sort(sortedLinePositions.begin(), sortedLinePositions.end());
+ }
+
+ QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data) override
+ {
+ QSGNode *ret = QQuickTextEdit::updatePaintNode(node, data);
+ qCDebug(lcTests) << "updated root node" << ret;
+ populateLinePositions(ret);
+ return ret;
+ }
+
+ QList<int> sortedLinePositions;
+ int lastLinePosition;
+};
+
+void tst_qquicktextedit::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ qmlRegisterType<NodeCheckerTextEdit>("Qt.test", 1, 0, "NodeCheckerTextEdit");
+}
+
void tst_qquicktextedit::cleanup()
{
// ensure not even skipped tests with custom input context leave it dangling
@@ -390,7 +436,7 @@ void tst_qquicktextedit::text()
QVERIFY(textEditObject != nullptr);
QCOMPARE(textEditObject->text(), standard.at(i));
- QCOMPARE(textEditObject->length(), standard.at(i).length());
+ QCOMPARE(textEditObject->length(), standard.at(i).size());
}
for (int i = 0; i < richText.size(); i++)
@@ -406,7 +452,7 @@ void tst_qquicktextedit::text()
QString expected = richText.at(i);
expected.replace(QRegularExpression("\\\\(.)"),"\\1");
QCOMPARE(textEditObject->text(), expected);
- QCOMPARE(textEditObject->length(), expected.length());
+ QCOMPARE(textEditObject->length(), expected.size());
}
for (int i = 0; i < standard.size(); i++)
@@ -425,7 +471,7 @@ void tst_qquicktextedit::text()
actual.remove(QRegularExpression("(<[^>]*>)+"));
expected.remove("\n");
QCOMPARE(actual.simplified(), expected);
- QCOMPARE(textEditObject->length(), expected.length());
+ QCOMPARE(textEditObject->length(), expected.size());
}
for (int i = 0; i < richText.size(); i++)
@@ -445,7 +491,7 @@ void tst_qquicktextedit::text()
QCOMPARE(actual.simplified(),expected.simplified());
expected.replace("<>", " ");
- QCOMPARE(textEditObject->length(), expected.simplified().length());
+ QCOMPARE(textEditObject->length(), expected.simplified().size());
}
for (int i = 0; i < standard.size(); i++)
@@ -457,7 +503,7 @@ void tst_qquicktextedit::text()
QVERIFY(textEditObject != nullptr);
QCOMPARE(textEditObject->text(), standard.at(i));
- QCOMPARE(textEditObject->length(), standard.at(i).length());
+ QCOMPARE(textEditObject->length(), standard.at(i).size());
}
for (int i = 0; i < richText.size(); i++)
@@ -477,7 +523,7 @@ void tst_qquicktextedit::text()
QCOMPARE(actual.simplified(),expected.simplified());
expected.replace("<>", " ");
- QCOMPARE(textEditObject->length(), expected.simplified().length());
+ QCOMPARE(textEditObject->length(), expected.simplified().size());
}
}
@@ -595,14 +641,14 @@ void tst_qquicktextedit::wrap()
edit->setWrapMode(QQuickTextEdit::Wrap);
QCOMPARE(edit->wrapMode(), QQuickTextEdit::Wrap);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
edit->setWrapMode(QQuickTextEdit::Wrap);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
edit->setWrapMode(QQuickTextEdit::NoWrap);
QCOMPARE(edit->wrapMode(), QQuickTextEdit::NoWrap);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
}
@@ -626,6 +672,19 @@ void tst_qquicktextedit::textFormat()
QCOMPARE(textObject->textFormat(), QQuickTextEdit::PlainText);
}
{
+ QQmlComponent textComponent(&engine);
+ textComponent.setData("import QtQuick 2.0\nTextEdit { text: \"_Hello_\"; textFormat: Text.MarkdownText }", QUrl::fromLocalFile(""));
+ QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.create());
+
+ QVERIFY(textObject != nullptr);
+ QCOMPARE(textObject->textFormat(), QQuickTextEdit::MarkdownText);
+ QVERIFY(textObject->textDocument());
+ auto doc = textObject->textDocument()->textDocument();
+ QVERIFY(doc);
+ QTextCursor cursor(doc);
+ QVERIFY(cursor.charFormat().fontUnderline());
+ }
+ {
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0\n TextEdit {}", QUrl());
QScopedPointer<QObject> object(component.create());
@@ -638,14 +697,18 @@ void tst_qquicktextedit::textFormat()
edit->setTextFormat(QQuickTextEdit::RichText);
QCOMPARE(edit->textFormat(), QQuickTextEdit::RichText);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
edit->setTextFormat(QQuickTextEdit::RichText);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
edit->setTextFormat(QQuickTextEdit::PlainText);
QCOMPARE(edit->textFormat(), QQuickTextEdit::PlainText);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
+
+ edit->setTextFormat(QQuickTextEdit::MarkdownText);
+ QCOMPARE(edit->textFormat(), QQuickTextEdit::MarkdownText);
+ QCOMPARE(spy.size(), 3);
}
}
@@ -670,9 +733,9 @@ void tst_qquicktextedit::lineCount_data()
void tst_qquicktextedit::lineCount()
{
- QFETCH(QStringList, texts);
+ QFETCH(const QStringList, texts);
- foreach (const QString& text, texts) {
+ for (const QString& text : texts) {
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0\nTextEdit { }", QUrl());
@@ -847,7 +910,7 @@ void tst_qquicktextedit::hAlign_RightToLeft()
QSignalSpy cursorRectangleSpy(textEdit, SIGNAL(cursorRectangleChanged()));
platformInputContext.setInputDirection(Qt::RightToLeft);
- QCOMPARE(cursorRectangleSpy.count(), 1);
+ QCOMPARE(cursorRectangleSpy.size(), 1);
QCOMPARE(qApp->inputMethod()->inputDirection(), Qt::RightToLeft);
QCOMPARE(textEdit->hAlign(), QQuickTextEdit::AlignRight);
QVERIFY(textEdit->positionToRectangle(0).x() > window.width()/2);
@@ -928,7 +991,7 @@ void tst_qquicktextedit::hAlignVisual()
// Try to check whether alignment works by checking the number of black
// pixels in the thirds of the grabbed image.
- const int windowWidth = 200;
+ const int windowWidth = view.width();
const int textWidth = qCeil(text->implicitWidth());
QVERIFY2(textWidth < windowWidth, "System font too large.");
const int sectionWidth = textWidth / 3;
@@ -938,9 +1001,8 @@ void tst_qquicktextedit::hAlignVisual()
const int centeredSection3End = centeredSection3 + sectionWidth;
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QEXPECT_FAIL("", "Failure due to grabWindow not functional on offscreen/minimal platforms", Abort);
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
// Left Align
QImage image = view.grabWindow();
@@ -976,7 +1038,7 @@ void tst_qquicktextedit::hAlignVisual()
{
// Left Align
QImage image = view.grabWindow();
- int x = qCeil(text->implicitWidth());
+ int x = qCeil(text->implicitWidth() * view.devicePixelRatio());
int left = numberOfNonWhitePixels(0, x, image);
int right = numberOfNonWhitePixels(x, image.width() - x, image);
QVERIFY2(left > 0, msgNotGreaterThan(left, 0).constData());
@@ -986,7 +1048,7 @@ void tst_qquicktextedit::hAlignVisual()
// HCenter Align
text->setHAlign(QQuickText::AlignHCenter);
QImage image = view.grabWindow();
- int x1 = qFloor(image.width() - text->implicitWidth()) / 2;
+ int x1 = qFloor(image.width() - text->implicitWidth() * view.devicePixelRatio()) / 2;
int x2 = image.width() - x1;
int left = numberOfNonWhitePixels(0, x1, image);
int mid = numberOfNonWhitePixels(x1, x2 - x1, image);
@@ -999,7 +1061,7 @@ void tst_qquicktextedit::hAlignVisual()
// Right Align
text->setHAlign(QQuickText::AlignRight);
QImage image = view.grabWindow();
- int x = image.width() - qCeil(text->implicitWidth());
+ int x = image.width() - qCeil(text->implicitWidth() * view.devicePixelRatio());
int left = numberOfNonWhitePixels(0, x, image);
int right = numberOfNonWhitePixels(x, image.width() - x, image);
QCOMPARE(left, 0);
@@ -1159,36 +1221,36 @@ void tst_qquicktextedit::color()
textEditObject->setColor(QColor("white"));
QCOMPARE(textEditObject->color(), QColor("white"));
- QCOMPARE(colorSpy.count(), 1);
+ QCOMPARE(colorSpy.size(), 1);
textEditObject->setSelectionColor(QColor("black"));
QCOMPARE(textEditObject->selectionColor(), QColor("black"));
- QCOMPARE(selectionColorSpy.count(), 1);
+ QCOMPARE(selectionColorSpy.size(), 1);
textEditObject->setSelectedTextColor(QColor("blue"));
QCOMPARE(textEditObject->selectedTextColor(), QColor("blue"));
- QCOMPARE(selectedTextColorSpy.count(), 1);
+ QCOMPARE(selectedTextColorSpy.size(), 1);
textEditObject->setColor(QColor("white"));
- QCOMPARE(colorSpy.count(), 1);
+ QCOMPARE(colorSpy.size(), 1);
textEditObject->setSelectionColor(QColor("black"));
- QCOMPARE(selectionColorSpy.count(), 1);
+ QCOMPARE(selectionColorSpy.size(), 1);
textEditObject->setSelectedTextColor(QColor("blue"));
- QCOMPARE(selectedTextColorSpy.count(), 1);
+ QCOMPARE(selectedTextColorSpy.size(), 1);
textEditObject->setColor(QColor("black"));
QCOMPARE(textEditObject->color(), QColor("black"));
- QCOMPARE(colorSpy.count(), 2);
+ QCOMPARE(colorSpy.size(), 2);
textEditObject->setSelectionColor(QColor("blue"));
QCOMPARE(textEditObject->selectionColor(), QColor("blue"));
- QCOMPARE(selectionColorSpy.count(), 2);
+ QCOMPARE(selectionColorSpy.size(), 2);
textEditObject->setSelectedTextColor(QColor("white"));
QCOMPARE(textEditObject->selectedTextColor(), QColor("white"));
- QCOMPARE(selectedTextColorSpy.count(), 2);
+ QCOMPARE(selectedTextColorSpy.size(), 2);
}
//test normal
@@ -1254,10 +1316,8 @@ void tst_qquicktextedit::textMargin()
void tst_qquicktextedit::persistentSelection()
{
- QQuickView window(testFileUrl("persistentSelection.qml"));
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("persistentSelection.qml")));
QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(edit);
@@ -1269,7 +1329,7 @@ void tst_qquicktextedit::persistentSelection()
edit->setPersistentSelection(false);
QCOMPARE(edit->persistentSelection(), false);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
edit->select(1, 4);
QCOMPARE(edit->property("selected").toString(), QLatin1String("ell"));
@@ -1282,7 +1342,7 @@ void tst_qquicktextedit::persistentSelection()
edit->setPersistentSelection(true);
QCOMPARE(edit->persistentSelection(), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
edit->select(1, 4);
QCOMPARE(edit->property("selected").toString(), QLatin1String("ell"));
@@ -1298,7 +1358,7 @@ void tst_qquicktextedit::persistentSelection()
edit->setPersistentSelection(false);
QCOMPARE(edit->persistentSelection(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
edit->select(1, 4);
QCOMPARE(edit->property("selected").toString(), QLatin1String("ell"));
@@ -1311,7 +1371,7 @@ void tst_qquicktextedit::persistentSelection()
edit->setPersistentSelection(true);
QCOMPARE(edit->persistentSelection(), true);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
edit->select(1, 4);
QCOMPARE(edit->property("selected").toString(), QLatin1String("ell"));
@@ -1361,12 +1421,13 @@ void tst_qquicktextedit::selectionOnFocusOut()
QVERIFY(edit2->hasActiveFocus());
edit2->setFocus(false, Qt::PopupFocusReason);
- QVERIFY(edit2->hasActiveFocus());
+ QVERIFY(!edit2->hasActiveFocus());
QCOMPARE(edit2->selectedText(), QLatin1String("text 2"));
}
void tst_qquicktextedit::focusOnPress()
{
+ const int doubleClickInterval = qApp->styleHints()->mouseDoubleClickInterval();
QString componentStr =
"import QtQuick 2.0\n"
"TextEdit {\n"
@@ -1389,7 +1450,7 @@ void tst_qquicktextedit::focusOnPress()
textEditObject->setFocusOnPress(true);
QCOMPARE(textEditObject->focusOnPress(), true);
- QCOMPARE(activeFocusOnPressSpy.count(), 0);
+ QCOMPARE(activeFocusOnPressSpy.size(), 0);
QQuickWindow window;
window.resize(100, 50);
@@ -1407,45 +1468,45 @@ void tst_qquicktextedit::focusOnPress()
QGuiApplication::processEvents();
QCOMPARE(textEditObject->hasFocus(), true);
QCOMPARE(textEditObject->hasActiveFocus(), true);
- QCOMPARE(focusSpy.count(), 1);
- QCOMPARE(activeFocusSpy.count(), 1);
+ QCOMPARE(focusSpy.size(), 1);
+ QCOMPARE(activeFocusSpy.size(), 1);
QCOMPARE(textEditObject->selectedText(), QString());
QTest::mouseRelease(&window, Qt::LeftButton, noModifiers, centerPoint);
textEditObject->setFocusOnPress(false);
QCOMPARE(textEditObject->focusOnPress(), false);
- QCOMPARE(activeFocusOnPressSpy.count(), 1);
+ QCOMPARE(activeFocusOnPressSpy.size(), 1);
textEditObject->setFocus(false);
QCOMPARE(textEditObject->hasFocus(), false);
QCOMPARE(textEditObject->hasActiveFocus(), false);
- QCOMPARE(focusSpy.count(), 2);
- QCOMPARE(activeFocusSpy.count(), 2);
+ QCOMPARE(focusSpy.size(), 2);
+ QCOMPARE(activeFocusSpy.size(), 2);
// Wait for double click timeout to expire before clicking again.
- QTest::qWait(400);
+ QTest::qWait(doubleClickInterval + 1);
QTest::mousePress(&window, Qt::LeftButton, noModifiers, centerPoint);
QGuiApplication::processEvents();
QCOMPARE(textEditObject->hasFocus(), false);
QCOMPARE(textEditObject->hasActiveFocus(), false);
- QCOMPARE(focusSpy.count(), 2);
- QCOMPARE(activeFocusSpy.count(), 2);
+ QCOMPARE(focusSpy.size(), 2);
+ QCOMPARE(activeFocusSpy.size(), 2);
QTest::mouseRelease(&window, Qt::LeftButton, noModifiers, centerPoint);
textEditObject->setFocusOnPress(true);
QCOMPARE(textEditObject->focusOnPress(), true);
- QCOMPARE(activeFocusOnPressSpy.count(), 2);
+ QCOMPARE(activeFocusOnPressSpy.size(), 2);
// Test a selection made in the on(Active)FocusChanged handler isn't overwritten.
textEditObject->setProperty("selectOnFocus", true);
- QTest::qWait(400);
+ QTest::qWait(doubleClickInterval + 1);
QTest::mousePress(&window, Qt::LeftButton, noModifiers, centerPoint);
QGuiApplication::processEvents();
QCOMPARE(textEditObject->hasFocus(), true);
QCOMPARE(textEditObject->hasActiveFocus(), true);
- QCOMPARE(focusSpy.count(), 3);
- QCOMPARE(activeFocusSpy.count(), 3);
+ QCOMPARE(focusSpy.size(), 3);
+ QCOMPARE(activeFocusSpy.size(), 3);
QCOMPARE(textEditObject->selectedText(), textEditObject->text());
QTest::mouseRelease(&window, Qt::LeftButton, noModifiers, centerPoint);
}
@@ -1482,7 +1543,7 @@ void tst_qquicktextedit::selection()
QCOMPARE(textEditObject->selectionEnd(), 0);
QVERIFY(textEditObject->selectedText().isNull());
- textEditObject->setCursorPosition(textEditObject->text().count()+1);
+ textEditObject->setCursorPosition(textEditObject->text().size()+1);
QCOMPARE(textEditObject->cursorPosition(), 0);
QCOMPARE(textEditObject->selectionStart(), 0);
QCOMPARE(textEditObject->selectionEnd(), 0);
@@ -1536,54 +1597,46 @@ void tst_qquicktextedit::selection()
void tst_qquicktextedit::overwriteMode()
{
- QString componentStr = "import QtQuick 2.0\nTextEdit { focus: true; }";
- QQmlComponent textEditComponent(&engine);
- textEditComponent.setData(componentStr.toLatin1(), QUrl());
- QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
- QVERIFY(textEdit != nullptr);
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("focusByDefault.qml")));
+ QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(window.rootObject());
QSignalSpy spy(textEdit, SIGNAL(overwriteModeChanged(bool)));
- QQuickWindow window;
- textEdit->setParentItem(window.contentItem());
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
-
QVERIFY(textEdit->hasActiveFocus());
textEdit->setOverwriteMode(true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(true, textEdit->overwriteMode());
textEdit->setOverwriteMode(false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
QCOMPARE(false, textEdit->overwriteMode());
QVERIFY(!textEdit->overwriteMode());
QString insertString = "Some first text";
- for (int j = 0; j < insertString.length(); j++)
+ for (int j = 0; j < insertString.size(); j++)
QTest::keyClick(&window, insertString.at(j).toLatin1());
QCOMPARE(textEdit->text(), QString("Some first text"));
textEdit->setOverwriteMode(true);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
textEdit->setCursorPosition(5);
insertString = "shiny";
- for (int j = 0; j < insertString.length(); j++)
+ for (int j = 0; j < insertString.size(); j++)
QTest::keyClick(&window, insertString.at(j).toLatin1());
QCOMPARE(textEdit->text(), QString("Some shiny text"));
- textEdit->setCursorPosition(textEdit->text().length());
+ textEdit->setCursorPosition(textEdit->text().size());
QTest::keyClick(&window, Qt::Key_Enter);
textEdit->setOverwriteMode(false);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
insertString = "Second paragraph";
- for (int j = 0; j < insertString.length(); j++)
+ for (int j = 0; j < insertString.size(); j++)
QTest::keyClick(&window, insertString.at(j).toLatin1());
QCOMPARE(textEdit->lineCount(), 2);
@@ -1592,10 +1645,10 @@ void tst_qquicktextedit::overwriteMode()
QCOMPARE(textEdit->cursorPosition(), 15);
textEdit->setOverwriteMode(true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
insertString = " blah";
- for (int j = 0; j < insertString.length(); j++)
+ for (int j = 0; j < insertString.size(); j++)
QTest::keyClick(&window, insertString.at(j).toLatin1());
QCOMPARE(textEdit->lineCount(), 2);
@@ -1639,34 +1692,30 @@ void tst_qquicktextedit::isRightToLeft()
// first test that the right string is delivered to the QString::isRightToLeft()
QCOMPARE(textEdit.isRightToLeft(0,0), text.mid(0,0).isRightToLeft());
QCOMPARE(textEdit.isRightToLeft(0,1), text.mid(0,1).isRightToLeft());
- QCOMPARE(textEdit.isRightToLeft(text.count()-2, text.count()-1), text.mid(text.count()-2, text.count()-1).isRightToLeft());
- QCOMPARE(textEdit.isRightToLeft(text.count()/2, text.count()/2 + 1), text.mid(text.count()/2, text.count()/2 + 1).isRightToLeft());
- QCOMPARE(textEdit.isRightToLeft(0,text.count()/4), text.mid(0,text.count()/4).isRightToLeft());
- QCOMPARE(textEdit.isRightToLeft(text.count()/4,3*text.count()/4), text.mid(text.count()/4,3*text.count()/4).isRightToLeft());
+ QCOMPARE(textEdit.isRightToLeft(text.size()-2, text.size()-1), text.mid(text.size()-2, text.size()-1).isRightToLeft());
+ QCOMPARE(textEdit.isRightToLeft(text.size()/2, text.size()/2 + 1), text.mid(text.size()/2, text.size()/2 + 1).isRightToLeft());
+ QCOMPARE(textEdit.isRightToLeft(0,text.size()/4), text.mid(0,text.size()/4).isRightToLeft());
+ QCOMPARE(textEdit.isRightToLeft(text.size()/4,3*text.size()/4), text.mid(text.size()/4,3*text.size()/4).isRightToLeft());
if (text.isEmpty())
QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextEdit: isRightToLeft(start, end) called with the end property being smaller than the start.");
- QCOMPARE(textEdit.isRightToLeft(3*text.count()/4,text.count()-1), text.mid(3*text.count()/4,text.count()-1).isRightToLeft());
+ QCOMPARE(textEdit.isRightToLeft(3*text.size()/4,text.size()-1), text.mid(3*text.size()/4,text.size()-1).isRightToLeft());
// then test that the feature actually works
QCOMPARE(textEdit.isRightToLeft(0,0), emptyString);
QCOMPARE(textEdit.isRightToLeft(0,1), firstCharacter);
- QCOMPARE(textEdit.isRightToLeft(text.count()-2, text.count()-1), lastCharacter);
- QCOMPARE(textEdit.isRightToLeft(text.count()/2, text.count()/2 + 1), middleCharacter);
- QCOMPARE(textEdit.isRightToLeft(0,text.count()/4), startString);
- QCOMPARE(textEdit.isRightToLeft(text.count()/4,3*text.count()/4), midString);
+ QCOMPARE(textEdit.isRightToLeft(text.size()-2, text.size()-1), lastCharacter);
+ QCOMPARE(textEdit.isRightToLeft(text.size()/2, text.size()/2 + 1), middleCharacter);
+ QCOMPARE(textEdit.isRightToLeft(0,text.size()/4), startString);
+ QCOMPARE(textEdit.isRightToLeft(text.size()/4,3*text.size()/4), midString);
if (text.isEmpty())
QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextEdit: isRightToLeft(start, end) called with the end property being smaller than the start.");
- QCOMPARE(textEdit.isRightToLeft(3*text.count()/4,text.count()-1), endString);
+ QCOMPARE(textEdit.isRightToLeft(3*text.size()/4,text.size()-1), endString);
}
void tst_qquicktextedit::keySelection()
{
- QQuickView window(testFileUrl("navigation.qml"));
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
-
- QVERIFY(window.rootObject() != nullptr);
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("navigation.qml")));
QQuickTextEdit *input = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window.rootObject()->property("myInput")));
@@ -1678,31 +1727,31 @@ void tst_qquicktextedit::keySelection()
simulateKey(&window, Qt::Key_Right, Qt::ShiftModifier);
QVERIFY(input->hasActiveFocus());
QCOMPARE(input->selectedText(), QString("a"));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
simulateKey(&window, Qt::Key_Right);
QVERIFY(input->hasActiveFocus());
QCOMPARE(input->selectedText(), QString());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
simulateKey(&window, Qt::Key_Right);
QVERIFY(!input->hasActiveFocus());
QCOMPARE(input->selectedText(), QString());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
simulateKey(&window, Qt::Key_Left);
QVERIFY(input->hasActiveFocus());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
simulateKey(&window, Qt::Key_Left, Qt::ShiftModifier);
QVERIFY(input->hasActiveFocus());
QCOMPARE(input->selectedText(), QString("a"));
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
simulateKey(&window, Qt::Key_Left);
QVERIFY(input->hasActiveFocus());
QCOMPARE(input->selectedText(), QString());
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
simulateKey(&window, Qt::Key_Left);
QVERIFY(!input->hasActiveFocus());
QCOMPARE(input->selectedText(), QString());
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
}
void tst_qquicktextedit::moveCursorSelection_data()
@@ -2043,7 +2092,7 @@ void tst_qquicktextedit::moveCursorSelectionSequence()
void tst_qquicktextedit::mouseSelection_data()
{
- QTest::addColumn<QString>("qmlfile");
+ QTest::addColumn<QUrl>("qmlfile");
QTest::addColumn<int>("from");
QTest::addColumn<int>("to");
QTest::addColumn<QString>("selectedText");
@@ -2052,64 +2101,64 @@ void tst_qquicktextedit::mouseSelection_data()
QTest::addColumn<int>("clicks");
// import installed
- QTest::newRow("on") << testFile("mouseselection_true.qml") << 4 << 9 << "45678" << true << true << 1;
- QTest::newRow("off") << testFile("mouseselection_false.qml") << 4 << 9 << QString() << true << true << 1;
- QTest::newRow("default") << testFile("mouseselection_default.qml") << 4 << 9 << QString() << true << true << 1;
- QTest::newRow("off word selection") << testFile("mouseselection_false_words.qml") << 4 << 9 << QString() << true << true << 1;
- QTest::newRow("on word selection (4,9)") << testFile("mouseselection_true_words.qml") << 4 << 9 << "0123456789" << true << true << 1;
-
- QTest::newRow("on unfocused") << testFile("mouseselection_true.qml") << 4 << 9 << "45678" << false << false << 1;
- QTest::newRow("on word selection (4,9) unfocused") << testFile("mouseselection_true_words.qml") << 4 << 9 << "0123456789" << false << false << 1;
-
- QTest::newRow("on focus on press") << testFile("mouseselection_true.qml") << 4 << 9 << "45678" << false << true << 1;
- QTest::newRow("on word selection (4,9) focus on press") << testFile("mouseselection_true_words.qml") << 4 << 9 << "0123456789" << false << true << 1;
-
- QTest::newRow("on word selection (2,13)") << testFile("mouseselection_true_words.qml") << 2 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
- QTest::newRow("on word selection (2,30)") << testFile("mouseselection_true_words.qml") << 2 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
- QTest::newRow("on word selection (9,13)") << testFile("mouseselection_true_words.qml") << 9 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
- QTest::newRow("on word selection (9,30)") << testFile("mouseselection_true_words.qml") << 9 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
- QTest::newRow("on word selection (13,2)") << testFile("mouseselection_true_words.qml") << 13 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
- QTest::newRow("on word selection (20,2)") << testFile("mouseselection_true_words.qml") << 20 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
- QTest::newRow("on word selection (12,9)") << testFile("mouseselection_true_words.qml") << 12 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
- QTest::newRow("on word selection (30,9)") << testFile("mouseselection_true_words.qml") << 30 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
-
- QTest::newRow("on double click (4,9)") << testFile("mouseselection_true.qml") << 4 << 9 << "0123456789" << true << true << 2;
- QTest::newRow("on double click (2,13)") << testFile("mouseselection_true.qml") << 2 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
- QTest::newRow("on double click (2,30)") << testFile("mouseselection_true.qml") << 2 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
- QTest::newRow("on double click (9,13)") << testFile("mouseselection_true.qml") << 9 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
- QTest::newRow("on double click (9,30)") << testFile("mouseselection_true.qml") << 9 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
- QTest::newRow("on double click (13,2)") << testFile("mouseselection_true.qml") << 13 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
- QTest::newRow("on double click (20,2)") << testFile("mouseselection_true.qml") << 20 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
- QTest::newRow("on double click (12,9)") << testFile("mouseselection_true.qml") << 12 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
- QTest::newRow("on double click (30,9)") << testFile("mouseselection_true.qml") << 30 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
-
- QTest::newRow("on triple click (4,9)") << testFile("mouseselection_true.qml") << 4 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
- QTest::newRow("on triple click (2,13)") << testFile("mouseselection_true.qml") << 2 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
- QTest::newRow("on triple click (2,30)") << testFile("mouseselection_true.qml") << 2 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
- QTest::newRow("on triple click (9,13)") << testFile("mouseselection_true.qml") << 9 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
- QTest::newRow("on triple click (9,30)") << testFile("mouseselection_true.qml") << 9 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
- QTest::newRow("on triple click (13,2)") << testFile("mouseselection_true.qml") << 13 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
- QTest::newRow("on triple click (20,2)") << testFile("mouseselection_true.qml") << 20 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
- QTest::newRow("on triple click (12,9)") << testFile("mouseselection_true.qml") << 12 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
- QTest::newRow("on triple click (30,9)") << testFile("mouseselection_true.qml") << 30 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
-
- QTest::newRow("on triple click (2,40)") << testFile("mouseselection_true.qml") << 2 << 40 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n9876543210\n" << true << true << 3;
- QTest::newRow("on triple click (2,50)") << testFile("mouseselection_true.qml") << 2 << 50 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n9876543210\n\nZXYWVUTSRQPON MLKJIHGFEDCBA" << true << true << 3;
- QTest::newRow("on triple click (25,40)") << testFile("mouseselection_true.qml") << 25 << 40 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n9876543210\n" << true << true << 3;
- QTest::newRow("on triple click (25,50)") << testFile("mouseselection_true.qml") << 25 << 50 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n9876543210\n\nZXYWVUTSRQPON MLKJIHGFEDCBA" << true << true << 3;
- QTest::newRow("on triple click (40,25)") << testFile("mouseselection_true.qml") << 40 << 25 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n9876543210\n" << true << true << 3;
- QTest::newRow("on triple click (40,50)") << testFile("mouseselection_true.qml") << 40 << 50 << "9876543210\n\nZXYWVUTSRQPON MLKJIHGFEDCBA" << true << true << 3;
- QTest::newRow("on triple click (50,25)") << testFile("mouseselection_true.qml") << 50 << 25 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n9876543210\n\nZXYWVUTSRQPON MLKJIHGFEDCBA" << true << true << 3;
- QTest::newRow("on triple click (50,40)") << testFile("mouseselection_true.qml") << 50 << 40 << "9876543210\n\nZXYWVUTSRQPON MLKJIHGFEDCBA" << true << true << 3;
-
- QTest::newRow("on tr align") << testFile("mouseselection_align_tr.qml") << 4 << 9 << "45678" << true << true << 1;
- QTest::newRow("on center align") << testFile("mouseselection_align_center.qml") << 4 << 9 << "45678" << true << true << 1;
- QTest::newRow("on bl align") << testFile("mouseselection_align_bl.qml") << 4 << 9 << "45678" << true << true << 1;
+ QTest::newRow("on") << testFileUrl("mouseselection_true.qml") << 4 << 9 << "45678" << true << true << 1;
+ QTest::newRow("off") << testFileUrl("mouseselection_false.qml") << 4 << 9 << QString() << true << true << 1;
+ QTest::newRow("default") << testFileUrl("mouseselectionmode_default.qml") << 4 << 9 << "45678" << true << true << 1;
+ QTest::newRow("off word selection") << testFileUrl("mouseselection_false_words.qml") << 4 << 9 << QString() << true << true << 1;
+ QTest::newRow("on word selection (4,9)") << testFileUrl("mouseselection_true_words.qml") << 4 << 9 << "0123456789" << true << true << 1;
+
+ QTest::newRow("on unfocused") << testFileUrl("mouseselection_true.qml") << 4 << 9 << "45678" << false << false << 1;
+ QTest::newRow("on word selection (4,9) unfocused") << testFileUrl("mouseselection_true_words.qml") << 4 << 9 << "0123456789" << false << false << 1;
+
+ QTest::newRow("on focus on press") << testFileUrl("mouseselection_true.qml") << 4 << 9 << "45678" << false << true << 1;
+ QTest::newRow("on word selection (4,9) focus on press") << testFileUrl("mouseselection_true_words.qml") << 4 << 9 << "0123456789" << false << true << 1;
+
+ QTest::newRow("on word selection (2,13)") << testFileUrl("mouseselection_true_words.qml") << 2 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
+ QTest::newRow("on word selection (2,30)") << testFileUrl("mouseselection_true_words.qml") << 2 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
+ QTest::newRow("on word selection (9,13)") << testFileUrl("mouseselection_true_words.qml") << 9 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
+ QTest::newRow("on word selection (9,30)") << testFileUrl("mouseselection_true_words.qml") << 9 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
+ QTest::newRow("on word selection (13,2)") << testFileUrl("mouseselection_true_words.qml") << 13 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
+ QTest::newRow("on word selection (20,2)") << testFileUrl("mouseselection_true_words.qml") << 20 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
+ QTest::newRow("on word selection (12,9)") << testFileUrl("mouseselection_true_words.qml") << 12 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
+ QTest::newRow("on word selection (30,9)") << testFileUrl("mouseselection_true_words.qml") << 30 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 1;
+
+ QTest::newRow("on double click (4,9)") << testFileUrl("mouseselection_true.qml") << 4 << 9 << "0123456789" << true << true << 2;
+ QTest::newRow("on double click (2,13)") << testFileUrl("mouseselection_true.qml") << 2 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
+ QTest::newRow("on double click (2,30)") << testFileUrl("mouseselection_true.qml") << 2 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
+ QTest::newRow("on double click (9,13)") << testFileUrl("mouseselection_true.qml") << 9 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
+ QTest::newRow("on double click (9,30)") << testFileUrl("mouseselection_true.qml") << 9 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
+ QTest::newRow("on double click (13,2)") << testFileUrl("mouseselection_true.qml") << 13 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
+ QTest::newRow("on double click (20,2)") << testFileUrl("mouseselection_true.qml") << 20 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
+ QTest::newRow("on double click (12,9)") << testFileUrl("mouseselection_true.qml") << 12 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
+ QTest::newRow("on double click (30,9)") << testFileUrl("mouseselection_true.qml") << 30 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" << true << true << 2;
+
+ QTest::newRow("on triple click (4,9)") << testFileUrl("mouseselection_true.qml") << 4 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
+ QTest::newRow("on triple click (2,13)") << testFileUrl("mouseselection_true.qml") << 2 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
+ QTest::newRow("on triple click (2,30)") << testFileUrl("mouseselection_true.qml") << 2 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
+ QTest::newRow("on triple click (9,13)") << testFileUrl("mouseselection_true.qml") << 9 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
+ QTest::newRow("on triple click (9,30)") << testFileUrl("mouseselection_true.qml") << 9 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
+ QTest::newRow("on triple click (13,2)") << testFileUrl("mouseselection_true.qml") << 13 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
+ QTest::newRow("on triple click (20,2)") << testFileUrl("mouseselection_true.qml") << 20 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
+ QTest::newRow("on triple click (12,9)") << testFileUrl("mouseselection_true.qml") << 12 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
+ QTest::newRow("on triple click (30,9)") << testFileUrl("mouseselection_true.qml") << 30 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n" << true << true << 3;
+
+ QTest::newRow("on triple click (2,40)") << testFileUrl("mouseselection_true.qml") << 2 << 40 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n9876543210\n" << true << true << 3;
+ QTest::newRow("on triple click (2,50)") << testFileUrl("mouseselection_true.qml") << 2 << 50 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n9876543210\n\nZXYWVUTSRQPON MLKJIHGFEDCBA" << true << true << 3;
+ QTest::newRow("on triple click (25,40)") << testFileUrl("mouseselection_true.qml") << 25 << 40 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n9876543210\n" << true << true << 3;
+ QTest::newRow("on triple click (25,50)") << testFileUrl("mouseselection_true.qml") << 25 << 50 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n9876543210\n\nZXYWVUTSRQPON MLKJIHGFEDCBA" << true << true << 3;
+ QTest::newRow("on triple click (40,25)") << testFileUrl("mouseselection_true.qml") << 40 << 25 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n9876543210\n" << true << true << 3;
+ QTest::newRow("on triple click (40,50)") << testFileUrl("mouseselection_true.qml") << 40 << 50 << "9876543210\n\nZXYWVUTSRQPON MLKJIHGFEDCBA" << true << true << 3;
+ QTest::newRow("on triple click (50,25)") << testFileUrl("mouseselection_true.qml") << 50 << 25 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ\n9876543210\n\nZXYWVUTSRQPON MLKJIHGFEDCBA" << true << true << 3;
+ QTest::newRow("on triple click (50,40)") << testFileUrl("mouseselection_true.qml") << 50 << 40 << "9876543210\n\nZXYWVUTSRQPON MLKJIHGFEDCBA" << true << true << 3;
+
+ QTest::newRow("on tr align") << testFileUrl("mouseselection_align_tr.qml") << 4 << 9 << "45678" << true << true << 1;
+ QTest::newRow("on center align") << testFileUrl("mouseselection_align_center.qml") << 4 << 9 << "45678" << true << true << 1;
+ QTest::newRow("on bl align") << testFileUrl("mouseselection_align_bl.qml") << 4 << 9 << "45678" << true << true << 1;
}
void tst_qquicktextedit::mouseSelection()
{
- QFETCH(QString, qmlfile);
+ QFETCH(QUrl, qmlfile);
QFETCH(int, from);
QFETCH(int, to);
QFETCH(QString, selectedText);
@@ -2117,13 +2166,8 @@ void tst_qquicktextedit::mouseSelection()
QFETCH(bool, focusOnPress);
QFETCH(int, clicks);
- QQuickView window(QUrl::fromLocalFile(qmlfile));
-
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
-
- QVERIFY(window.rootObject() != nullptr);
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, qmlfile));
QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(textEditObject != nullptr);
@@ -2141,8 +2185,6 @@ void tst_qquicktextedit::mouseSelection()
QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, p1, moreThanDoubleClickInterval);
else if (clicks == 3)
QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p1, moreThanDoubleClickInterval);
- // cancel the 500ms delta QTestLib adds in order to properly synthesize a triple click within the required interval
- QTest::lastMouseTimestamp -= QTest::mouseDoubleClickInterval;
QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p1);
QTest::mouseMove(&window, p2);
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p2);
@@ -2150,28 +2192,18 @@ void tst_qquicktextedit::mouseSelection()
// Clicking and shift to clicking between the same points should select the same text.
textEditObject->setCursorPosition(0);
- if (clicks > 1) {
- QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p1);
- // cancel the 500ms delta QTestLib adds in order to properly synthesize a triple click within the required interval
- QTest::lastMouseTimestamp -= QTest::mouseDoubleClickInterval;
- }
+ if (clicks > 1)
+ QTest::mouseDClick(&window, Qt::LeftButton, Qt::NoModifier, p1, 10);
if (clicks != 2)
- QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, p1);
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, p1, 10);
QTest::mouseClick(&window, Qt::LeftButton, Qt::ShiftModifier, p2);
QTRY_COMPARE(textEditObject->selectedText(), selectedText);
}
void tst_qquicktextedit::dragMouseSelection()
{
- QString qmlfile = testFile("mouseselection_true.qml");
-
- QQuickView window(QUrl::fromLocalFile(qmlfile));
-
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
-
- QVERIFY(window.rootObject() != nullptr);
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("mouseselection_true.qml")));
QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(textEditObject != nullptr);
@@ -2182,9 +2214,8 @@ void tst_qquicktextedit::dragMouseSelection()
QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x1,y));
QTest::mouseMove(&window, QPoint(x2, y));
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x2,y));
- QTest::qWait(300);
QString str1;
- QTRY_VERIFY((str1 = textEditObject->selectedText()).length() > 3);
+ QTRY_VERIFY((str1 = textEditObject->selectedText()).size() > 3);
// press and drag the current selection.
x1 = 40;
@@ -2192,9 +2223,8 @@ void tst_qquicktextedit::dragMouseSelection()
QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x1,y));
QTest::mouseMove(&window, QPoint(x2, y));
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x2,y));
- QTest::qWait(300);
QString str2;
- QTRY_VERIFY((str2 = textEditObject->selectedText()).length() > 3);
+ QTRY_VERIFY((str2 = textEditObject->selectedText()).size() > 3);
QVERIFY(str1 != str2); // Verify the second press and drag is a new selection and not the first moved.
@@ -2202,31 +2232,28 @@ void tst_qquicktextedit::dragMouseSelection()
void tst_qquicktextedit::mouseSelectionMode_data()
{
- QTest::addColumn<QString>("qmlfile");
+ QTest::addColumn<QUrl>("qmlfile");
QTest::addColumn<bool>("selectWords");
// import installed
- QTest::newRow("SelectWords") << testFile("mouseselectionmode_words.qml") << true;
- QTest::newRow("SelectCharacters") << testFile("mouseselectionmode_characters.qml") << false;
- QTest::newRow("default") << testFile("mouseselectionmode_default.qml") << false;
+ QTest::newRow("SelectWords") << testFileUrl("mouseselectionmode_words.qml") << true;
+ QTest::newRow("SelectCharacters") << testFileUrl("mouseselectionmode_characters.qml") << false;
+ QTest::newRow("default") << testFileUrl("mouseselectionmode_default.qml") << false;
}
void tst_qquicktextedit::mouseSelectionMode()
{
- QFETCH(QString, qmlfile);
+ QFETCH(QUrl, qmlfile);
QFETCH(bool, selectWords);
- QString text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
- QQuickView window(QUrl::fromLocalFile(qmlfile));
+ const QString text = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, qmlfile));
- QVERIFY(window.rootObject() != nullptr);
QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(textEditObject != nullptr);
+ textEditObject->setSelectByMouse(true);
// press-and-drag-and-release from x1 to x2
int x1 = 10;
@@ -2239,7 +2266,7 @@ void tst_qquicktextedit::mouseSelectionMode()
if (selectWords) {
QTRY_COMPARE(textEditObject->selectedText(), text);
} else {
- QTRY_VERIFY(textEditObject->selectedText().length() > 3);
+ QTRY_VERIFY(textEditObject->selectedText().size() > 3);
QVERIFY(str != text);
}
}
@@ -2258,14 +2285,14 @@ void tst_qquicktextedit::mouseSelectionMode_accessors()
edit->setMouseSelectionMode(QQuickTextEdit::SelectWords);
QCOMPARE(edit->mouseSelectionMode(), QQuickTextEdit::SelectWords);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
edit->setMouseSelectionMode(QQuickTextEdit::SelectWords);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
edit->setMouseSelectionMode(QQuickTextEdit::SelectCharacters);
QCOMPARE(edit->mouseSelectionMode(), QQuickTextEdit::SelectCharacters);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
void tst_qquicktextedit::selectByMouse()
@@ -2282,15 +2309,15 @@ void tst_qquicktextedit::selectByMouse()
edit->setSelectByMouse(true);
QCOMPARE(edit->selectByMouse(), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(spy.at(0).at(0).toBool(), true);
edit->setSelectByMouse(true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
edit->setSelectByMouse(false);
QCOMPARE(edit->selectByMouse(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
QCOMPARE(spy.at(1).at(0).toBool(), false);
}
@@ -2313,28 +2340,26 @@ void tst_qquicktextedit::selectByKeyboard()
edit->setReadOnly(true);
QCOMPARE(edit->selectByKeyboard(), false);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(spy.at(0).at(0).toBool(), false);
edit->setSelectByKeyboard(true);
QCOMPARE(edit->selectByKeyboard(), true);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
QCOMPARE(spy.at(1).at(0).toBool(), true);
edit->setReadOnly(false);
QCOMPARE(edit->selectByKeyboard(), true);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
edit->setSelectByKeyboard(false);
QCOMPARE(edit->selectByKeyboard(), false);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
QCOMPARE(spy.at(2).at(0).toBool(), false);
}
#if QT_CONFIG(shortcut)
-Q_DECLARE_METATYPE(QKeySequence::StandardKey)
-
void tst_qquicktextedit::keyboardSelection_data()
{
QTest::addColumn<QString>("text");
@@ -2394,27 +2419,19 @@ void tst_qquicktextedit::keyboardSelection()
QFETCH(QKeySequence::StandardKey, standardKey);
QFETCH(QString, selectedText);
- QQmlComponent component(&engine);
- component.setData("import QtQuick 2.1\n TextEdit { focus: true }", QUrl());
- QScopedPointer<QObject> object(component.create());
- QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(object.data());
- QVERIFY(edit);
-
- edit->setText(text);
- edit->setSelectByKeyboard(selectByKeyboard);
- edit->setReadOnly(readOnly);
- edit->setCursorPosition(cursorPosition);
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("focusByDefault.qml")));
+ QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(window.rootObject());
+ QVERIFY(textEdit->hasActiveFocus());
- QQuickWindow window;
- edit->setParentItem(window.contentItem());
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
- QVERIFY(edit->hasActiveFocus());
+ textEdit->setText(text);
+ textEdit->setSelectByKeyboard(selectByKeyboard);
+ textEdit->setReadOnly(readOnly);
+ textEdit->setCursorPosition(cursorPosition);
simulateKeys(&window, standardKey);
- QCOMPARE(edit->selectedText(), selectedText);
+ QCOMPARE(textEdit->selectedText(), selectedText);
}
#endif // QT_CONFIG(shortcut)
@@ -2433,32 +2450,29 @@ void tst_qquicktextedit::renderType()
edit->setRenderType(QQuickTextEdit::NativeRendering);
QCOMPARE(edit->renderType(), QQuickTextEdit::NativeRendering);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
edit->setRenderType(QQuickTextEdit::NativeRendering);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
edit->setRenderType(QQuickTextEdit::QtRendering);
QCOMPARE(edit->renderType(), QQuickTextEdit::QtRendering);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
void tst_qquicktextedit::inputMethodHints()
{
- QQuickView window(testFileUrl("inputmethodhints.qml"));
- window.show();
- window.requestActivate();
-
- QVERIFY(window.rootObject() != nullptr);
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("inputmethodhints.qml")));
QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(textEditObject != nullptr);
QVERIFY(textEditObject->inputMethodHints() & Qt::ImhNoPredictiveText);
QSignalSpy inputMethodHintSpy(textEditObject, SIGNAL(inputMethodHintsChanged()));
textEditObject->setInputMethodHints(Qt::ImhUppercaseOnly);
QVERIFY(textEditObject->inputMethodHints() & Qt::ImhUppercaseOnly);
- QCOMPARE(inputMethodHintSpy.count(), 1);
+ QCOMPARE(inputMethodHintSpy.size(), 1);
textEditObject->setInputMethodHints(Qt::ImhUppercaseOnly);
- QCOMPARE(inputMethodHintSpy.count(), 1);
+ QCOMPARE(inputMethodHintSpy.size(), 1);
QQuickTextEdit plainTextEdit;
QCOMPARE(plainTextEdit.inputMethodHints(), Qt::ImhNone);
@@ -2484,11 +2498,8 @@ void tst_qquicktextedit::positionAt()
QFETCH(QQuickTextEdit::HAlignment, horizontalAlignment);
QFETCH(QQuickTextEdit::VAlignment, verticalAlignment);
- QQuickView window(testFileUrl("positionAt.qml"));
- QVERIFY(window.rootObject() != nullptr);
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("positionAt.qml")));
QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(texteditObject != nullptr);
@@ -2581,8 +2592,8 @@ void tst_qquicktextedit::linkHover()
QQuickView window(testFileUrl("linkInteraction.qml"));
window.setFlag(Qt::FramelessWindowHint);
QVERIFY(window.rootObject() != nullptr);
- QQuickViewTestUtil::centerOnScreen(&window);
- QQuickViewTestUtil::moveMouseAway(&window);
+ QQuickVisualTestUtils::centerOnScreen(&window);
+ QQuickVisualTestUtils::moveMouseAway(&window);
window.show();
window.requestActivate();
QVERIFY(QTest::qWaitForWindowActive(&window));
@@ -2596,38 +2607,31 @@ void tst_qquicktextedit::linkHover()
const QPoint textPos = window.mapToGlobal(texteditObject->positionToRectangle(2).center().toPoint());
QCursor::setPos(linkPos);
- QTRY_COMPARE(hover.count(), 1);
+ QTRY_COMPARE(hover.size(), 1);
QCOMPARE(window.cursor().shape(), Qt::PointingHandCursor);
QCOMPARE(hover.last()[0].toString(), link);
QCursor::setPos(textPos);
- QTRY_COMPARE(hover.count(), 2);
+ QTRY_COMPARE(hover.size(), 2);
QCOMPARE(window.cursor().shape(), Qt::IBeamCursor);
QCOMPARE(hover.last()[0].toString(), QString());
- texteditObject->setCursor(Qt::OpenHandCursor);
-
QCursor::setPos(linkPos);
- QTRY_COMPARE(hover.count(), 3);
+ QTRY_COMPARE(hover.size(), 3);
QCOMPARE(window.cursor().shape(), Qt::PointingHandCursor);
QCOMPARE(hover.last()[0].toString(), link);
QCursor::setPos(textPos);
- QTRY_COMPARE(hover.count(), 4);
- QCOMPARE(window.cursor().shape(), Qt::OpenHandCursor);
+ QTRY_COMPARE(hover.size(), 4);
+ QCOMPARE(window.cursor().shape(), Qt::IBeamCursor);
QCOMPARE(hover.last()[0].toString(), QString());
}
#endif
void tst_qquicktextedit::linkInteraction()
{
- QQuickView window(testFileUrl("linkInteraction.qml"));
- QVERIFY(window.rootObject() != nullptr);
- QQuickViewTestUtil::centerOnScreen(&window);
- QQuickViewTestUtil::moveMouseAway(&window);
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("linkInteraction.qml")));
QQuickTextEdit *texteditObject = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(texteditObject != nullptr);
@@ -2641,16 +2645,16 @@ void tst_qquicktextedit::linkInteraction()
const QPointF textPos = texteditObject->positionToRectangle(2).center();
QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, linkPos.toPoint());
- QTRY_COMPARE(spy.count(), 1);
- QTRY_COMPARE(hover.count(), 1);
+ QTRY_COMPARE(spy.size(), 1);
+ QTRY_COMPARE(hover.size(), 1);
QCOMPARE(spy.last()[0].toString(), link);
QCOMPARE(hover.last()[0].toString(), link);
QCOMPARE(texteditObject->hoveredLink(), link);
QCOMPARE(texteditObject->linkAt(linkPos.x(), linkPos.y()), link);
QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, textPos.toPoint());
- QTRY_COMPARE(spy.count(), 1);
- QTRY_COMPARE(hover.count(), 2);
+ QTRY_COMPARE(spy.size(), 1);
+ QTRY_COMPARE(hover.size(), 2);
QCOMPARE(hover.last()[0].toString(), QString());
QCOMPARE(texteditObject->hoveredLink(), QString());
QCOMPARE(texteditObject->linkAt(textPos.x(), textPos.y()), QString());
@@ -2658,16 +2662,16 @@ void tst_qquicktextedit::linkInteraction()
texteditObject->setReadOnly(true);
QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, linkPos.toPoint());
- QTRY_COMPARE(spy.count(), 2);
- QTRY_COMPARE(hover.count(), 3);
+ QTRY_COMPARE(spy.size(), 2);
+ QTRY_COMPARE(hover.size(), 3);
QCOMPARE(spy.last()[0].toString(), link);
QCOMPARE(hover.last()[0].toString(), link);
QCOMPARE(texteditObject->hoveredLink(), link);
QCOMPARE(texteditObject->linkAt(linkPos.x(), linkPos.y()), link);
QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, textPos.toPoint());
- QTRY_COMPARE(spy.count(), 2);
- QTRY_COMPARE(hover.count(), 4);
+ QTRY_COMPARE(spy.size(), 2);
+ QTRY_COMPARE(hover.size(), 4);
QCOMPARE(hover.last()[0].toString(), QString());
QCOMPARE(texteditObject->hoveredLink(), QString());
QCOMPARE(texteditObject->linkAt(textPos.x(), textPos.y()), QString());
@@ -2684,11 +2688,11 @@ void tst_qquicktextedit::cursorDelegate_data()
void tst_qquicktextedit::cursorDelegate()
{
QFETCH(QUrl, source);
- QQuickView view(source);
- view.show();
- view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
- QQuickTextEdit *textEditObject = view.rootObject()->findChild<QQuickTextEdit*>("textEditObject");
+
+ const int doubleClickInterval = qApp->styleHints()->mouseDoubleClickInterval();
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, source));
+ QQuickTextEdit *textEditObject = window.rootObject()->findChild<QQuickTextEdit*>("textEditObject");
QVERIFY(textEditObject != nullptr);
// Delegate creation is deferred until focus in or cursor visibility is forced.
QVERIFY(!textEditObject->findChild<QQuickItem*>("cursorInstance"));
@@ -2700,7 +2704,7 @@ void tst_qquicktextedit::cursorDelegate()
QVERIFY(delegateObject);
QCOMPARE(delegateObject->property("localProperty").toString(), QString("Hello"));
//Test Delegate gets moved
- for (int i=0; i<= textEditObject->text().length(); i++) {
+ for (int i=0; i<= textEditObject->text().size(); i++) {
textEditObject->setCursorPosition(i);
QCOMPARE(textEditObject->cursorRectangle().x(), delegateObject->x());
QCOMPARE(textEditObject->cursorRectangle().y(), delegateObject->y());
@@ -2710,9 +2714,8 @@ void tst_qquicktextedit::cursorDelegate()
textEditObject->setSelectByMouse(true);
textEditObject->setCursorPosition(0);
const QPoint point1 = textEditObject->positionToRectangle(5).center().toPoint();
- QTest::qWait(400); //ensure this isn't treated as a double-click
- QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, point1);
- QTest::qWait(50);
+ QTest::qWait(doubleClickInterval + 1); // ensure this isn't treated as a double-click
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, point1);
QTRY_VERIFY(textEditObject->cursorPosition() != 0);
QCOMPARE(textEditObject->cursorRectangle().x(), delegateObject->x());
QCOMPARE(textEditObject->cursorRectangle().y(), delegateObject->y());
@@ -2720,28 +2723,26 @@ void tst_qquicktextedit::cursorDelegate()
// Test delegate gets moved on mouse drag
textEditObject->setCursorPosition(0);
const QPoint point2 = textEditObject->positionToRectangle(10).center().toPoint();
- QTest::qWait(400); //ensure this isn't treated as a double-click
- QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, point1);
- QMouseEvent mv(QEvent::MouseMove, point2, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
- QGuiApplication::sendEvent(&view, &mv);
- QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, point2);
- QTest::qWait(50);
+ QTest::qWait(doubleClickInterval + 1);
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, point1);
+ QMouseEvent mv(QEvent::MouseMove, point2, window.mapToGlobal(point2),
+ Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QGuiApplication::sendEvent(&window, &mv);
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, point2);
QTRY_COMPARE(textEditObject->cursorRectangle().x(), delegateObject->x());
QCOMPARE(textEditObject->cursorRectangle().y(), delegateObject->y());
textEditObject->setReadOnly(true);
textEditObject->setCursorPosition(0);
- QTest::qWait(400); //ensure this isn't treated as a double-click
- QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, textEditObject->positionToRectangle(5).center().toPoint());
- QTest::qWait(50);
+ QTest::qWait(doubleClickInterval + 1);
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, textEditObject->positionToRectangle(5).center().toPoint());
QTRY_VERIFY(textEditObject->cursorPosition() != 0);
QCOMPARE(textEditObject->cursorRectangle().x(), delegateObject->x());
QCOMPARE(textEditObject->cursorRectangle().y(), delegateObject->y());
textEditObject->setCursorPosition(0);
- QTest::qWait(400); //ensure this isn't treated as a double-click
- QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, textEditObject->positionToRectangle(5).center().toPoint());
- QTest::qWait(50);
+ QTest::qWait(doubleClickInterval + 1);
+ QTest::mouseClick(&window, Qt::LeftButton, Qt::NoModifier, textEditObject->positionToRectangle(5).center().toPoint());
QTRY_VERIFY(textEditObject->cursorPosition() != 0);
QCOMPARE(textEditObject->cursorRectangle().x(), delegateObject->x());
QCOMPARE(textEditObject->cursorRectangle().y(), delegateObject->y());
@@ -2755,7 +2756,7 @@ void tst_qquicktextedit::cursorDelegate()
// Delegate moved when text is entered
textEditObject->setText(QString());
for (int i = 0; i < 20; ++i) {
- QTest::keyClick(&view, Qt::Key_A);
+ QTest::keyClick(&window, Qt::Key_A);
QCOMPARE(textEditObject->cursorRectangle().x(), delegateObject->x());
QCOMPARE(textEditObject->cursorRectangle().y(), delegateObject->y());
}
@@ -2825,37 +2826,36 @@ void tst_qquicktextedit::cursorVisible()
edit.componentComplete();
QSignalSpy spy(&edit, SIGNAL(cursorVisibleChanged(bool)));
- QQuickView view(testFileUrl("cursorVisible.qml"));
- view.show();
- view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
- QCOMPARE(&view, qGuiApp->focusWindow());
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("cursorVisible.qml")));
+
+ QCOMPARE(qGuiApp->focusWindow(), &window);
QCOMPARE(edit.isCursorVisible(), false);
edit.setCursorVisible(true);
QCOMPARE(edit.isCursorVisible(), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
edit.setCursorVisible(false);
QCOMPARE(edit.isCursorVisible(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
edit.setFocus(true);
QCOMPARE(edit.isCursorVisible(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
- edit.setParentItem(view.rootObject());
+ edit.setParentItem(window.rootObject());
QCOMPARE(edit.isCursorVisible(), true);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
edit.setFocus(false);
QCOMPARE(edit.isCursorVisible(), false);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
edit.setFocus(true);
QCOMPARE(edit.isCursorVisible(), true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
QWindow alternateView;
alternateView.show();
@@ -2863,12 +2863,12 @@ void tst_qquicktextedit::cursorVisible()
QVERIFY(QTest::qWaitForWindowActive(&alternateView));
QCOMPARE(edit.isCursorVisible(), false);
- QCOMPARE(spy.count(), 6);
+ QCOMPARE(spy.size(), 6);
- view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
+ window.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
QCOMPARE(edit.isCursorVisible(), true);
- QCOMPARE(spy.count(), 7);
+ QCOMPARE(spy.size(), 7);
{ // Cursor attribute with 0 length hides cursor.
QInputMethodEvent ev(QString(), QList<QInputMethodEvent::Attribute>()
@@ -2876,7 +2876,7 @@ void tst_qquicktextedit::cursorVisible()
QCoreApplication::sendEvent(&edit, &ev);
}
QCOMPARE(edit.isCursorVisible(), false);
- QCOMPARE(spy.count(), 8);
+ QCOMPARE(spy.size(), 8);
{ // Cursor attribute with non zero length shows cursor.
QInputMethodEvent ev(QString(), QList<QInputMethodEvent::Attribute>()
@@ -2884,7 +2884,7 @@ void tst_qquicktextedit::cursorVisible()
QCoreApplication::sendEvent(&edit, &ev);
}
QCOMPARE(edit.isCursorVisible(), true);
- QCOMPARE(spy.count(), 9);
+ QCOMPARE(spy.size(), 9);
{ // If the cursor is hidden by the input method and the text is changed it should be visible again.
@@ -2893,11 +2893,11 @@ void tst_qquicktextedit::cursorVisible()
QCoreApplication::sendEvent(&edit, &ev);
}
QCOMPARE(edit.isCursorVisible(), false);
- QCOMPARE(spy.count(), 10);
+ QCOMPARE(spy.size(), 10);
edit.setText("something");
QCOMPARE(edit.isCursorVisible(), true);
- QCOMPARE(spy.count(), 11);
+ QCOMPARE(spy.size(), 11);
{ // If the cursor is hidden by the input method and the cursor position is changed it should be visible again.
QInputMethodEvent ev(QString(), QList<QInputMethodEvent::Attribute>()
@@ -2905,11 +2905,11 @@ void tst_qquicktextedit::cursorVisible()
QCoreApplication::sendEvent(&edit, &ev);
}
QCOMPARE(edit.isCursorVisible(), false);
- QCOMPARE(spy.count(), 12);
+ QCOMPARE(spy.size(), 12);
edit.setCursorPosition(5);
QCOMPARE(edit.isCursorVisible(), true);
- QCOMPARE(spy.count(), 13);
+ QCOMPARE(spy.size(), 13);
}
void tst_qquicktextedit::delegateLoading_data()
@@ -2970,11 +2970,9 @@ void tst_qquicktextedit::delegateLoading()
void tst_qquicktextedit::cursorDelegateHeight()
{
- QQuickView view(testFileUrl("cursorHeight.qml"));
- view.show();
- view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
- QQuickTextEdit *textEditObject = view.rootObject()->findChild<QQuickTextEdit*>("textEditObject");
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("cursorHeight.qml")));
+ QQuickTextEdit *textEditObject = window.rootObject()->findChild<QQuickTextEdit*>();
QVERIFY(textEditObject);
// Delegate creation is deferred until focus in or cursor visibility is forced.
QVERIFY(!textEditObject->findChild<QQuickItem*>("cursorInstance"));
@@ -3011,12 +3009,8 @@ the extent of the text, then they should ignore the keys.
*/
void tst_qquicktextedit::navigation()
{
- QQuickView window(testFileUrl("navigation.qml"));
- window.show();
- window.requestActivate();
-
- QVERIFY(window.rootObject() != nullptr);
-
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("navigation.qml")));
QQuickTextEdit *input = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window.rootObject()->property("myInput")));
QVERIFY(input != nullptr);
@@ -3056,16 +3050,16 @@ void tst_qquicktextedit::copyAndPaste()
QVERIFY(textEdit != nullptr);
// copy and paste
- QCOMPARE(textEdit->text().length(), 12);
- textEdit->select(0, textEdit->text().length());;
+ QCOMPARE(textEdit->text().size(), 12);
+ textEdit->select(0, textEdit->text().size());;
textEdit->copy();
QCOMPARE(textEdit->selectedText(), QString("Hello world!"));
- QCOMPARE(textEdit->selectedText().length(), 12);
+ QCOMPARE(textEdit->selectedText().size(), 12);
textEdit->setCursorPosition(0);
QVERIFY(textEdit->canPaste());
textEdit->paste();
QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
- QCOMPARE(textEdit->text().length(), 24);
+ QCOMPARE(textEdit->text().size(), 24);
// canPaste
QVERIFY(textEdit->canPaste());
@@ -3073,7 +3067,7 @@ void tst_qquicktextedit::copyAndPaste()
QVERIFY(!textEdit->canPaste());
textEdit->paste();
QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
- QCOMPARE(textEdit->text().length(), 24);
+ QCOMPARE(textEdit->text().size(), 24);
textEdit->setReadOnly(false);
QVERIFY(textEdit->canPaste());
@@ -3101,10 +3095,10 @@ void tst_qquicktextedit::copyAndPaste()
// select all and cut
textEdit->selectAll();
textEdit->cut();
- QCOMPARE(textEdit->text().length(), 0);
+ QCOMPARE(textEdit->text().size(), 0);
textEdit->paste();
QCOMPARE(textEdit->text(), QString("Hello world!Hello world!"));
- QCOMPARE(textEdit->text().length(), 24);
+ QCOMPARE(textEdit->text().size(), 24);
// Copy first word.
textEdit->setCursorPosition(0);
@@ -3162,13 +3156,8 @@ void tst_qquicktextedit::middleClickPaste()
if (!PlatformQuirks::isClipboardAvailable())
QSKIP("This machine doesn't support the clipboard");
- QQuickView window(testFileUrl("mouseselection_true.qml"));
-
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
-
- QVERIFY(window.rootObject() != nullptr);
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("mouseselection_true.qml")));
QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(textEditObject != nullptr);
@@ -3190,7 +3179,7 @@ void tst_qquicktextedit::middleClickPaste()
QTest::mouseClick(&window, Qt::MiddleButton, Qt::NoModifier, p3);
if (QGuiApplication::clipboard()->supportsSelection())
- QCOMPARE(textEditObject->text().mid(1, selectedText.length()), selectedText);
+ QCOMPARE(textEditObject->text().mid(1, selectedText.size()), selectedText);
else
QCOMPARE(textEditObject->text(), originalText);
}
@@ -3198,9 +3187,8 @@ void tst_qquicktextedit::middleClickPaste()
void tst_qquicktextedit::readOnly()
{
- QQuickView window(testFileUrl("readOnly.qml"));
- window.show();
- window.requestActivate();
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("readOnly.qml")));
QVERIFY(window.rootObject() != nullptr);
@@ -3220,7 +3208,7 @@ void tst_qquicktextedit::readOnly()
edit->setCursorPosition(3);
edit->setReadOnly(false);
QCOMPARE(edit->isReadOnly(), false);
- QCOMPARE(edit->cursorPosition(), edit->text().length());
+ QCOMPARE(edit->cursorPosition(), edit->text().size());
}
void tst_qquicktextedit::inFlickableMouse_data()
@@ -3240,11 +3228,9 @@ void tst_qquicktextedit::inFlickableMouse()
QFETCH(int, expectFlickingAfter);
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
- QQuickView view(testFileUrl("inFlickable.qml"));
- view.show();
- view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
- QQuickFlickable *flick = qobject_cast<QQuickFlickable *>(view.rootObject());
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("inFlickable.qml")));
+ QQuickFlickable *flick = qobject_cast<QQuickFlickable *>(window.rootObject());
QVERIFY(flick);
QQuickTextEdit *edit = flick->findChild<QQuickTextEdit*>("text");
QVERIFY(edit);
@@ -3253,7 +3239,7 @@ void tst_qquicktextedit::inFlickableMouse()
// flick with mouse
QPoint p(10, 100);
- QTest::mousePress(&view, Qt::LeftButton, {}, p);
+ QTest::mousePress(&window, Qt::LeftButton, {}, p);
QObject *pressGrabber = QPointingDevicePrivate::get(QPointingDevice::primaryPointingDevice())->firstPointExclusiveGrabber();
// even if TextEdit is readonly, it still grabs on press. But not if it's disabled.
if (enabled)
@@ -3264,14 +3250,14 @@ void tst_qquicktextedit::inFlickableMouse()
// after a couple of events, Flickable steals the grab and starts moving
for (; i < 4 && !flick->isMoving(); ++i) {
p -= QPoint(0, dragThreshold);
- QTest::mouseMove(&view, p);
+ QTest::mouseMove(&window, p);
}
QCOMPARE(flick->isMoving(), bool(expectFlickingAfter));
if (expectFlickingAfter) {
qCDebug(lcTests) << "flickable started moving after" << i << "moves, when we got to" << p;
QCOMPARE(i, expectFlickingAfter);
}
- QTest::mouseRelease(&view, Qt::LeftButton, {}, p);
+ QTest::mouseRelease(&window, Qt::LeftButton, {}, p);
}
void tst_qquicktextedit::inFlickableTouch_data()
@@ -3336,13 +3322,26 @@ void tst_qquicktextedit::simulateKey(QWindow *view, int key, Qt::KeyboardModifie
QGuiApplication::sendEvent(view, &release);
}
+bool tst_qquicktextedit::isMainFontFixed()
+{
+ bool ret = QFontInfo(QGuiApplication::font()).fixedPitch();
+ if (ret) {
+ qCWarning(lcTests) << "QFontDatabase::GeneralFont is monospaced: markdown writing is likely to use too many backticks"
+ << QFontDatabase::systemFont(QFontDatabase::GeneralFont);
+ }
+ return ret;
+}
+
+bool tst_qquicktextedit::hasWindowActivation()
+{
+ return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
+}
+
void tst_qquicktextedit::textInput()
{
- QQuickView view(testFileUrl("inputMethodEvent.qml"));
- view.show();
- view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
- QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("inputMethodEvent.qml")));
+ QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(edit);
QVERIFY(edit->hasActiveFocus());
@@ -3352,7 +3351,7 @@ void tst_qquicktextedit::textInput()
event.setCommitString( "Hello world!", 0, 0);
QGuiApplication::sendEvent(edit, &event);
QCOMPARE(edit->text(), QString("Hello world!"));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
// QTBUG-12339
// test that document and internal text attribute are in sync
@@ -3391,11 +3390,9 @@ void tst_qquicktextedit::inputMethodUpdate()
QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
inputMethodPrivate->testContext = &platformInputContext;
- QQuickView view(testFileUrl("inputMethodEvent.qml"));
- view.show();
- view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
- QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("inputMethodEvent.qml")));
+ QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(edit);
QVERIFY(edit->hasActiveFocus());
@@ -3481,12 +3478,10 @@ void tst_qquicktextedit::openInputPanel()
QInputMethodPrivate *inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
inputMethodPrivate->testContext = &platformInputContext;
- QQuickView view(testFileUrl("openInputPanel.qml"));
- view.showNormal();
- view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("openInputPanel.qml")));
- QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
+ QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(edit);
// check default values
@@ -3497,36 +3492,36 @@ void tst_qquicktextedit::openInputPanel()
QCOMPARE(qApp->inputMethod()->isVisible(), false);
// input panel should open on focus
- QPoint centerPoint(view.width()/2, view.height()/2);
+ QPoint centerPoint(window.width()/2, window.height()/2);
Qt::KeyboardModifiers noModifiers = Qt::NoModifier;
- QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
+ QTest::mousePress(&window, Qt::LeftButton, noModifiers, centerPoint);
QGuiApplication::processEvents();
QVERIFY(edit->hasActiveFocus());
QCOMPARE(qApp->focusObject(), edit);
QCOMPARE(qApp->inputMethod()->isVisible(), true);
- QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
+ QTest::mouseRelease(&window, Qt::LeftButton, noModifiers, centerPoint);
// input panel should be re-opened when pressing already focused TextEdit
qApp->inputMethod()->hide();
QCOMPARE(qApp->inputMethod()->isVisible(), false);
QVERIFY(edit->hasActiveFocus());
- QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
+ QTest::mousePress(&window, Qt::LeftButton, noModifiers, centerPoint);
QGuiApplication::processEvents();
QCOMPARE(qApp->inputMethod()->isVisible(), true);
- QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
+ QTest::mouseRelease(&window, Qt::LeftButton, noModifiers, centerPoint);
// input panel should stay visible if focus is lost to another text editor
QSignalSpy inputPanelVisibilitySpy(qApp->inputMethod(), SIGNAL(visibleChanged()));
QQuickTextEdit anotherEdit;
- anotherEdit.setParentItem(view.rootObject());
+ anotherEdit.setParentItem(window.rootObject());
anotherEdit.setFocus(true);
QCOMPARE(qApp->inputMethod()->isVisible(), true);
QCOMPARE(qApp->focusObject(), qobject_cast<QObject*>(&anotherEdit));
- QCOMPARE(inputPanelVisibilitySpy.count(), 0);
+ QCOMPARE(inputPanelVisibilitySpy.size(), 0);
anotherEdit.setFocus(false);
QVERIFY(qApp->focusObject() != &anotherEdit);
- QCOMPARE(view.activeFocusItem(), view.contentItem());
+ QCOMPARE(window.activeFocusItem(), window.contentItem());
anotherEdit.setFocus(true);
qApp->inputMethod()->hide();
@@ -3535,8 +3530,8 @@ void tst_qquicktextedit::openInputPanel()
edit->setReadOnly(true);
edit->setFocus(true);
QCOMPARE(qApp->inputMethod()->isVisible(), false);
- QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
- QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
+ QTest::mousePress(&window, Qt::LeftButton, noModifiers, centerPoint);
+ QTest::mouseRelease(&window, Qt::LeftButton, noModifiers, centerPoint);
QGuiApplication::processEvents();
QCOMPARE(qApp->inputMethod()->isVisible(), false);
@@ -3545,8 +3540,8 @@ void tst_qquicktextedit::openInputPanel()
edit->setFocus(false);
edit->setFocus(true);
QCOMPARE(qApp->inputMethod()->isVisible(), false);
- QTest::mousePress(&view, Qt::LeftButton, noModifiers, centerPoint);
- QTest::mouseRelease(&view, Qt::LeftButton, noModifiers, centerPoint);
+ QTest::mousePress(&window, Qt::LeftButton, noModifiers, centerPoint);
+ QTest::mouseRelease(&window, Qt::LeftButton, noModifiers, centerPoint);
QCOMPARE(qApp->inputMethod()->isVisible(), false);
inputMethodPrivate->testContext = nullptr;
@@ -3638,18 +3633,18 @@ void tst_qquicktextedit::contentSize()
QVERIFY(textObject->contentWidth() > textObject->width());
QVERIFY(textObject->contentHeight() < textObject->height());
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
textObject->setWrapMode(QQuickTextEdit::WordWrap);
QVERIFY(textObject->contentWidth() <= textObject->width());
QVERIFY(textObject->contentHeight() > textObject->height());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
textObject->setText("The quickredfoxjumpedoverthe lazy brown dog");
QVERIFY(textObject->contentWidth() > textObject->width());
QVERIFY(textObject->contentHeight() > textObject->height());
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
}
void tst_qquicktextedit::implicitSizeBinding_data()
@@ -3680,22 +3675,332 @@ void tst_qquicktextedit::implicitSizeBinding()
QCOMPARE(textObject->height(), textObject->implicitHeight());
}
-void tst_qquicktextedit::signal_editingfinished()
+void tst_qquicktextedit::largeTextObservesViewport_data()
{
- QQuickView *window = new QQuickView(nullptr);
- window->setBaseSize(QSize(800,600));
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<QQuickTextEdit::TextFormat>("textFormat");
+ QTest::addColumn<bool>("parentIsViewport");
+ QTest::addColumn<int>("cursorPos");
+ QTest::addColumn<int>("scrollDelta"); // non-zero to move TextEdit in viewport
- window->setSource(testFileUrl("signal_editingfinished.qml"));
- window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window));
- QCOMPARE(QGuiApplication::focusWindow(), window);
+ QTest::addColumn<int>("expectedBlockTolerance");
+ QTest::addColumn<int>("expectedBlocksAboveViewport");
+ QTest::addColumn<int>("expectedBlocksPastViewport");
+ QTest::addColumn<int>("expectedRenderedRegionMin");
+ QTest::addColumn<int>("expectedRenderedRegionMax");
- QVERIFY(window->rootObject() != nullptr);
+ QString text;
+ {
+ QStringList lines;
+ // "line 100" is 8 characters; many lines are longer, some are shorter
+ // so we populate 1250 lines, 11389 characters
+ const int lineCount = QQuickTextEditPrivate::largeTextSizeThreshold / 8;
+ lines.reserve(lineCount);
+ for (int i = 0; i < lineCount; ++i)
+ lines << QLatin1String("line ") + QString::number(i);
+ text = lines.join('\n');
+ }
+ Q_ASSERT(text.size() > QQuickTextEditPrivate::largeTextSizeThreshold);
+
+ // by default, the root item acts as the viewport:
+ // QQuickTextEdit doesn't populate lines of text beyond the bottom of the window
+ // cursor position 1000 is on line 121
+ QTest::newRow("default plain text") << text << QQuickTextEdit::PlainText << false << 1000 << 2
+ << 3 << 118 << 144 << 2150 << 3000;
+ // make the rectangle into a viewport item, and move the text upwards:
+ // QQuickTextEdit doesn't populate lines of text beyond the bottom of the viewport rectangle
+ QTest::newRow("clipped plain text") << text << QQuickTextEdit::PlainText << true << 1000 << 0
+ << 3 << 123 << 137 << 2200 << 3000;
+
+ // scroll backwards
+ QTest::newRow("scroll backwards in plain text") << text << QQuickTextEdit::PlainText << true << 1000 << 600
+ << 3 << 91 << 108 << 1475 << 2300;
+
+ {
+ QStringList lines;
+ // "line 100" is 8 characters; many lines are longer, some are shorter
+ // so we populate 1250 lines, 11389 characters
+ const int lineCount = QQuickTextEditPrivate::largeTextSizeThreshold / 8;
+ lines.reserve(lineCount);
+ // add a table (of contents, perhaps): ensure that doesn't get included in renderedRegion after we've scrolled past it
+ lines << QLatin1String("<table border='1'><tr><td>Chapter 1<td></tr><tr><td>Chapter 2</td></tr><tr><td>etc</td></tr></table>");
+ for (int i = 0; i < lineCount; ++i) {
+ if (i > 0 && i % 50 == 0)
+ // chapter heading with floating image: ensure that doesn't get included in renderedRegion after we've scrolled past it
+ lines << QLatin1String("<img style='float:left;' src='http/exists.png' height='32'/><h1>chapter ") +
+ QString::number(i / 50) + QLatin1String("</h1>");
+ lines << QLatin1String("<p>line ") + QString::number(i) + QLatin1String("</p>");
+ }
+ text = lines.join('\n');
+ }
+ Q_ASSERT(text.size() > QQuickTextEditPrivate::largeTextSizeThreshold);
+
+ // by default, the root item acts as the viewport:
+ // QQuickTextEdit doesn't populate blocks beyond the bottom of the window
+ QTest::newRow("default styled text") << text << QQuickTextEdit::RichText << false << 1000 << 0
+ << 3 << 122 << 139 << 3600 << 4500;
+ // make the rectangle into a viewport item, and move the text upwards:
+ // QQuickTextEdit doesn't populate blocks that don't intersect the viewport rectangle
+ QTest::newRow("clipped styled text") << text << QQuickTextEdit::RichText << true << 1000 << 0
+ << 3 << 127 << 136 << 3700 << 4360;
+ // get the "chapter 2" heading into the viewport
+ QTest::newRow("heading visible") << text << QQuickTextEdit::RichText << true << 800 << 0
+ << 3 << 105 << 113 << 3050 << 3600;
+ // get the "chapter 2" heading into the viewport, and then scroll backwards
+ QTest::newRow("scroll backwards") << text << QQuickTextEdit::RichText << true << 800 << 20
+ << 3 << 104 << 113 << 3000 << 3600;
+ // get the "chapter 2" heading into the viewport, and then scroll forwards
+ QTest::newRow("scroll forwards") << text << QQuickTextEdit::RichText << true << 800 << -50
+ << 3 << 106 << 115 << 3000 << 3670;
+}
+
+void tst_qquicktextedit::largeTextObservesViewport()
+{
+ if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
+ || (QGuiApplication::platformName() == QLatin1String("minimal")))
+ QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
+ QFETCH(QString, text);
+ QFETCH(QQuickTextEdit::TextFormat, textFormat);
+ QFETCH(bool, parentIsViewport);
+ QFETCH(int, cursorPos);
+ QFETCH(int, scrollDelta);
+ QFETCH(int, expectedBlockTolerance);
+ QFETCH(int, expectedBlocksAboveViewport);
+ QFETCH(int, expectedBlocksPastViewport);
+ QFETCH(int, expectedRenderedRegionMin);
+ QFETCH(int, expectedRenderedRegionMax);
+
+ QQuickView window;
+ QByteArray errorMessage;
+ QVERIFY2(QQuickTest::initView(window, testFileUrl("viewport.qml"), true, &errorMessage), errorMessage.constData());
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QQuickTextEdit *textItem = window.rootObject()->findChild<QQuickTextEdit*>();
+ QVERIFY(textItem);
+ QQuickItem *viewportItem = textItem->parentItem();
+ QQuickTextEditPrivate *textPriv = QQuickTextEditPrivate::get(textItem);
+
+ viewportItem->setFlag(QQuickItem::ItemIsViewport, parentIsViewport);
+ textItem->setTextFormat(textFormat);
+ textItem->setText(text);
+ textItem->setFocus(true);
+ if (lcTests().isDebugEnabled())
+ QTest::qWait(1000);
+ textItem->setCursorPosition(cursorPos);
+ auto cursorRect = textItem->cursorRectangle();
+ textItem->setY(-cursorRect.top());
+ if (lcTests().isDebugEnabled())
+ QTest::qWait(500);
+ if (scrollDelta) {
+ textItem->setY(textItem->y() + scrollDelta);
+ if (lcTests().isDebugEnabled())
+ QTest::qWait(500);
+ }
+ qCDebug(lcTests) << "text size" << textItem->text().size() << "lines" << textItem->lineCount() << "font" << textItem->font();
+ Q_ASSERT(textItem->text().size() > QQuickTextEditPrivate::largeTextSizeThreshold);
+ QVERIFY(textItem->flags().testFlag(QQuickItem::ItemObservesViewport)); // large text sets this flag automatically
+ QCOMPARE(textItem->viewportItem(), parentIsViewport ? viewportItem : viewportItem->parentItem());
+ QTRY_COMPARE_GT(textPriv->firstBlockInViewport, 0); // wait for rendering
+ qCDebug(lcTests) << "first block rendered" << textPriv->firstBlockInViewport
+ << "expected" << expectedBlocksAboveViewport
+ << "first block past viewport" << textPriv->firstBlockPastViewport
+ << "expected" << expectedBlocksPastViewport
+ << "region" << textPriv->renderedRegion << "bottom" << textPriv->renderedRegion.bottom()
+ << "expected range" << expectedRenderedRegionMin << expectedRenderedRegionMax;
+ if (scrollDelta >= 0) { // unfortunately firstBlockInViewport isn't always reliable after scrolling
+ QTRY_IMPL((qAbs(textPriv->firstBlockInViewport - expectedBlocksAboveViewport) <= expectedBlockTolerance), 5000);
+ }
+ QVERIFY2((qAbs(textPriv->firstBlockInViewport - expectedBlocksAboveViewport) <= expectedBlockTolerance),
+ qPrintable(QString::fromLatin1("Expected first block in viewport %1 to be near %2 (tolerance: %3)")
+ .arg(textPriv->firstBlockInViewport).arg(expectedBlocksAboveViewport).arg(expectedBlockTolerance)));
+ QVERIFY2((qAbs(textPriv->firstBlockPastViewport - expectedBlocksPastViewport) <= expectedBlockTolerance),
+ qPrintable(QString::fromLatin1("Expected first block past viewport %1 to be near %2 (tolerance: %3)")
+ .arg(textPriv->firstBlockPastViewport).arg(expectedBlocksPastViewport).arg(expectedBlockTolerance)));
+ QCOMPARE_GT(textPriv->renderedRegion.top(), expectedRenderedRegionMin);
+ QCOMPARE_LT(textPriv->renderedRegion.bottom(), expectedRenderedRegionMax);
+ QVERIFY(textPriv->cursorItem);
+ qCDebug(lcTests) << "cursor rect" << textItem->cursorRectangle() << "visible?" << textPriv->cursorItem->isVisible();
+ QCOMPARE(textPriv->cursorItem->isVisible(), textPriv->renderedRegion.intersects(textItem->cursorRectangle()));
+}
+
+void tst_qquicktextedit::largeTextSelection()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("qtConfigureHelp.qml")));
+ NodeCheckerTextEdit *textItem = qmlobject_cast<NodeCheckerTextEdit *>(window.rootObject());
+ QVERIFY(textItem);
+ QTRY_VERIFY(textItem->sortedLinePositions.size() > 0);
+ const auto sortedLinePositions = textItem->sortedLinePositions;
+
+ QQuickTextEditPrivate *textPriv = QQuickTextEditPrivate::get(textItem);
+ QSignalSpy renderSpy(&window, &QQuickWindow::afterRendering);
+ if (lcTests().isDebugEnabled())
+ QTest::qWait(500); // for visual check; not needed in CI
+
+ const int renderCount = renderSpy.size();
+ textItem->setCursorPosition(200);
+ textItem->moveCursorSelection(220);
+ QTRY_COMPARE_GT(renderSpy.size(), renderCount);
+
+ if (lcTests().isDebugEnabled())
+ QTest::qWait(500); // for visual check; not needed in CI
+
+ qCDebug(lcTests) << "TextEdit's nodes" << textPriv->textNodeMap;
+ qCDebug(lcTests) << "font" << textItem->font() << "line positions"
+ << textItem->sortedLinePositions << "expected" << sortedLinePositions;
+
+ const bool eachTextNodeRenderedOnlyOnce = [textItem]() -> bool {
+ for (auto i = 1; i < textItem->sortedLinePositions.count(); ++i)
+ if (textItem->sortedLinePositions[i - 1] == textItem->sortedLinePositions[i])
+ return false;
+ return true;
+ }();
+ QVERIFY(eachTextNodeRenderedOnlyOnce);
+}
- QQuickTextEdit *input1 = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window->rootObject()->property("input1")));
+void tst_qquicktextedit::renderingAroundSelection()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("threeLines.qml")));
+ NodeCheckerTextEdit *textItem = qmlobject_cast<NodeCheckerTextEdit*>(window.rootObject());
+ QVERIFY(textItem);
+ QTRY_VERIFY(textItem->sortedLinePositions.size() > 0);
+ const auto sortedLinePositions = textItem->sortedLinePositions;
+ const int lastLinePosition = textItem->lastLinePosition;
+ QQuickTextEditPrivate *textPriv = QQuickTextEditPrivate::get(textItem);
+ QSignalSpy renderSpy(&window, &QQuickWindow::afterRendering);
+
+ if (lcTests().isDebugEnabled())
+ QTest::qWait(500); // for visual check; not needed in CI
+
+ const int renderCount = renderSpy.size();
+ QPoint p1 = textItem->mapToScene(textItem->positionToRectangle(8).center()).toPoint();
+ QPoint p2 = textItem->mapToScene(textItem->positionToRectangle(10).center()).toPoint();
+ qCDebug(lcTests) << "drag from" << p1 << "to" << p2;
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, p1);
+ QTest::mouseMove(&window, p2);
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, p2);
+ // ensure that QQuickTextEdit::updatePaintNode() has a chance to run
+ QTRY_COMPARE_GT(renderSpy.size(), renderCount);
+
+ if (lcTests().isDebugEnabled())
+ QTest::qWait(500); // for visual check; not needed in CI
+
+ qCDebug(lcTests) << "TextEdit's nodes" << textPriv->textNodeMap;
+ qCDebug(lcTests) << "font" << textItem->font() << "line positions" << textItem->sortedLinePositions << "should be" << sortedLinePositions;
+ QCOMPARE(textItem->lastLinePosition, lastLinePosition);
+ QTRY_COMPARE(textItem->sortedLinePositions, sortedLinePositions);
+}
+
+struct OffsetAndExpectedBlocks {
+ int tableIndex; // which nested frame
+ qreal tableOffset; // fraction of that frame's height to scroll to
+ int minExpectedBlockCount;
+
+ OffsetAndExpectedBlocks(int i, qreal o, int c)
+ : tableIndex(i), tableOffset(o), minExpectedBlockCount(c) {}
+};
+
+typedef QList<OffsetAndExpectedBlocks> OffsetAndExpectedBlocksList;
+
+void tst_qquicktextedit::largeTextTables_data()
+{
+ QTest::addColumn<int>("tables");
+ QTest::addColumn<int>("tableCols");
+ QTest::addColumn<int>("tableRows");
+ QTest::addColumn<OffsetAndExpectedBlocksList>("steps");
+
+ QTest::newRow("one big table") << 1 << 3 << 70
+ << OffsetAndExpectedBlocksList{
+ OffsetAndExpectedBlocks(1, 0.75, 150),
+ OffsetAndExpectedBlocks(1, 0.5, 150)};
+ QTest::newRow("short tables") << 5 << 3 << 10
+ << OffsetAndExpectedBlocksList{
+ OffsetAndExpectedBlocks(4, 0.75, 35),
+ OffsetAndExpectedBlocks(3, 0.25, 50),
+ OffsetAndExpectedBlocks(2, 0.75, 50)};
+}
+
+void tst_qquicktextedit::largeTextTables() // QTBUG-118636
+{
+ QFETCH(int, tables);
+ QFETCH(int, tableCols);
+ QFETCH(int, tableRows);
+ QFETCH(OffsetAndExpectedBlocksList, steps);
+
+ QStringList lines;
+
+ lines << QLatin1String("<h1>") + QTest::currentDataTag() + "</h1>";
+ for (int t = 0; t < tables; ++t) {
+ if (t > 0)
+ lines << QString("<p>table %1</p>").arg(t);
+ lines << "<table border='1'>";
+ for (int r = 0; r < tableRows; ++r) {
+ lines << " <tr>";
+ for (int c = 0; c < tableCols; ++c)
+ lines << QString(" <td>table %1 cell %2, %3</td>").arg(t).arg(c).arg(r);
+ lines << " </tr>";
+ }
+ lines << "</table>";
+ }
+ lines << "<p>here endeth the tables</p>";
+ QString html = lines.join('\n');
+
+#ifdef DEBUG_WRITE_INPUT
+ QFile f(QLatin1String("/tmp/") + QTest::currentDataTag() + ".html");
+ f.open(QFile::WriteOnly);
+ f.write(html.toUtf8());
+ f.close();
+#endif
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("inFlickable.qml")));
+ QQuickFlickable *flick = qmlobject_cast<QQuickFlickable *>(window.rootObject());
+ QVERIFY(flick);
+ QQuickTextEdit *te = window.rootObject()->findChild<QQuickTextEdit *>();
+ QVERIFY(te);
+ auto *tePriv = QQuickTextEditPrivate::get(te);
+ auto font = te->font();
+ font.setPixelSize(10);
+ te->setFont(font);
+
+ te->setTextFormat(QQuickTextEdit::RichText);
+ te->setText(html);
+ te->setFlag(QQuickItem::ItemObservesViewport); // this isn't "large text", but test viewporting anyway
+
+ QTextDocument *doc = te->textDocument()->textDocument();
+ QList<QTextFrame *> frames = doc->rootFrame()->childFrames();
+ frames.prepend(doc->rootFrame());
+ qCDebug(lcTests) << "blocks" << doc->blockCount() << "chars" << doc->characterCount() << "frames" << frames;
+
+ for (const OffsetAndExpectedBlocks &oeb : steps) {
+ QCOMPARE_GT(frames.size(), oeb.tableIndex);
+ const QTextFrame *textFrame = frames.at(oeb.tableIndex);
+ const QTextCursor top = textFrame->firstCursorPosition();
+ const qreal yTop = te->positionToRectangle(top.position()).top();
+ const QTextCursor bottom = textFrame->lastCursorPosition();
+ const qreal yBottom = te->positionToRectangle(bottom.position()).bottom();
+ const qreal y = yTop + (yBottom - yTop) * oeb.tableOffset;
+ qCDebug(lcTests) << "frame" << textFrame << "goes from pos" << top.position() << "y" << yTop
+ << "to pos" << bottom.position() << "y" << yBottom << "; scrolling to" << y
+ << "which is at" << oeb.tableOffset << "of table height" << (yBottom - yTop);
+ flick->setContentY(y);
+ qCDebug(lcTests) << tePriv->renderedRegion << "rendered blocks" << tePriv->renderedBlockCount << ":"
+ << tePriv->firstBlockInViewport << "to" << tePriv->firstBlockPastViewport;
+ QTRY_COMPARE_GE(tePriv->renderedBlockCount, oeb.minExpectedBlockCount);
+ }
+}
+
+void tst_qquicktextedit::signal_editingfinished()
+{
+ QQuickView window;
+ window.setBaseSize(QSize(800, 600));
+ QVERIFY(QQuickTest::showView(window, testFileUrl("signal_editingfinished.qml")));
+ QCOMPARE(QGuiApplication::focusWindow(), &window);
+
+ QQuickTextEdit *input1 = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window.rootObject()->property("input1")));
QVERIFY(input1);
- QQuickTextEdit *input2 = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window->rootObject()->property("input2")));
+ QQuickTextEdit *input2 = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window.rootObject()->property("input2")));
QVERIFY(input2);
QSignalSpy editingFinished1Spy(input1, SIGNAL(editingFinished()));
@@ -3706,9 +4011,9 @@ void tst_qquicktextedit::signal_editingfinished()
{
QKeyEvent key(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
- QGuiApplication::sendEvent(window, &key);
+ QGuiApplication::sendEvent(&window, &key);
QVERIFY(key.isAccepted());
- QTRY_COMPARE(editingFinished1Spy.count(), 1);
+ QTRY_COMPARE(editingFinished1Spy.size(), 1);
QTRY_VERIFY(!input1->hasActiveFocus());
QTRY_VERIFY(input2->hasActiveFocus());
@@ -3722,9 +4027,9 @@ void tst_qquicktextedit::signal_editingfinished()
{
QKeyEvent key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
- QGuiApplication::sendEvent(window, &key);
+ QGuiApplication::sendEvent(&window, &key);
QVERIFY(key.isAccepted());
- QTRY_COMPARE(editingFinished2Spy.count(), 1);
+ QTRY_COMPARE(editingFinished2Spy.size(), 1);
QTRY_VERIFY(input1->hasActiveFocus());
QTRY_VERIFY(!input2->hasActiveFocus());
@@ -3904,12 +4209,10 @@ void tst_qquicktextedit::preeditCursorRectangle()
{
QString preeditText = "super";
- QQuickView view(testFileUrl("inputMethodEvent.qml"));
- view.show();
- view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("inputMethodEvent.qml")));
- QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
+ QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(edit);
QQuickItem *cursor = edit->findChild<QQuickItem *>("cursor");
@@ -3928,7 +4231,7 @@ void tst_qquicktextedit::preeditCursorRectangle()
// Verify that the micro focus rect is positioned the same for position 0 as
// it would be if there was no preedit text.
QInputMethodEvent imEvent(preeditText, QList<QInputMethodEvent::Attribute>()
- << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, preeditText.length(), QVariant()));
+ << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, preeditText.size(), QVariant()));
QCoreApplication::sendEvent(edit, &imEvent);
QCoreApplication::sendEvent(edit, &query);
currentRect = query.value(Qt::ImCursorRectangle).toRectF();
@@ -3942,15 +4245,15 @@ void tst_qquicktextedit::preeditCursorRectangle()
panelSpy.clear();
for (int i = 1; i <= 5; ++i) {
QInputMethodEvent imEvent(preeditText, QList<QInputMethodEvent::Attribute>()
- << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, i, preeditText.length(), QVariant()));
+ << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, i, preeditText.size(), QVariant()));
QCoreApplication::sendEvent(edit, &imEvent);
QCoreApplication::sendEvent(edit, &query);
currentRect = query.value(Qt::ImCursorRectangle).toRectF();
QCOMPARE(edit->cursorRectangle(), currentRect);
QCOMPARE(cursor->position(), currentRect.topLeft());
QVERIFY(previousRect.left() < currentRect.left());
- QCOMPARE(editSpy.count(), 1); editSpy.clear();
- QCOMPARE(panelSpy.count(), 1); panelSpy.clear();
+ QCOMPARE(editSpy.size(), 1); editSpy.clear();
+ QCOMPARE(panelSpy.size(), 1); panelSpy.clear();
previousRect = currentRect;
}
@@ -3965,8 +4268,8 @@ void tst_qquicktextedit::preeditCursorRectangle()
currentRect = query.value(Qt::ImCursorRectangle).toRectF();
QCOMPARE(edit->cursorRectangle(), currentRect);
QCOMPARE(cursor->position(), currentRect.topLeft());
- QCOMPARE(editSpy.count(), 1);
- QCOMPARE(panelSpy.count(), 1);
+ QCOMPARE(editSpy.size(), 1);
+ QCOMPARE(panelSpy.size(), 1);
// Verify that if there is no preedit cursor then the micro focus rect is the
// same as it would be if it were positioned at the end of the preedit text.
@@ -3979,20 +4282,18 @@ void tst_qquicktextedit::preeditCursorRectangle()
QCOMPARE(edit->cursorRectangle(), currentRect);
QCOMPARE(cursor->position(), currentRect.topLeft());
QCOMPARE(currentRect, previousRect);
- QCOMPARE(editSpy.count(), 1);
- QCOMPARE(panelSpy.count(), 1);
+ QCOMPARE(editSpy.size(), 1);
+ QCOMPARE(panelSpy.size(), 1);
}
void tst_qquicktextedit::inputMethodComposing()
{
QString text = "supercalifragisiticexpialidocious!";
- QQuickView view(testFileUrl("inputContext.qml"));
- view.show();
- view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("inputContext.qml")));
- QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(view.rootObject());
+ QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(edit);
QCOMPARE(QGuiApplication::focusObject(), static_cast<QObject *>(edit));
@@ -4007,37 +4308,37 @@ void tst_qquicktextedit::inputMethodComposing()
}
QCOMPARE(edit->isInputMethodComposing(), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
{
QInputMethodEvent event(text.mid(12), QList<QInputMethodEvent::Attribute>());
QGuiApplication::sendEvent(edit, &event);
}
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
{
QInputMethodEvent event;
QGuiApplication::sendEvent(edit, &event);
}
QCOMPARE(edit->isInputMethodComposing(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
// Changing the text while not composing doesn't alter the composing state.
edit->setText(text.mid(0, 16));
QCOMPARE(edit->isInputMethodComposing(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
{
QInputMethodEvent event(text.mid(16), QList<QInputMethodEvent::Attribute>());
QGuiApplication::sendEvent(edit, &event);
}
QCOMPARE(edit->isInputMethodComposing(), true);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
// Changing the text while composing cancels composition.
edit->setText(text.mid(0, 12));
QCOMPARE(edit->isInputMethodComposing(), false);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
{ // Preedit cursor positioned outside (empty) preedit; composing.
QInputMethodEvent event(QString(), QList<QInputMethodEvent::Attribute>()
@@ -4045,7 +4346,7 @@ void tst_qquicktextedit::inputMethodComposing()
QGuiApplication::sendEvent(edit, &event);
}
QCOMPARE(edit->isInputMethodComposing(), true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
{ // Cursor hidden; composing
QInputMethodEvent event(QString(), QList<QInputMethodEvent::Attribute>()
@@ -4053,7 +4354,7 @@ void tst_qquicktextedit::inputMethodComposing()
QGuiApplication::sendEvent(edit, &event);
}
QCOMPARE(edit->isInputMethodComposing(), true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
{ // Default cursor attributes; composing.
QInputMethodEvent event(QString(), QList<QInputMethodEvent::Attribute>()
@@ -4061,7 +4362,7 @@ void tst_qquicktextedit::inputMethodComposing()
QGuiApplication::sendEvent(edit, &event);
}
QCOMPARE(edit->isInputMethodComposing(), true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
{ // Selections are persisted: not composing
QInputMethodEvent event(QString(), QList<QInputMethodEvent::Attribute>()
@@ -4069,7 +4370,7 @@ void tst_qquicktextedit::inputMethodComposing()
QGuiApplication::sendEvent(edit, &event);
}
QCOMPARE(edit->isInputMethodComposing(), false);
- QCOMPARE(spy.count(), 6);
+ QCOMPARE(spy.size(), 6);
edit->setCursorPosition(0);
@@ -4081,14 +4382,14 @@ void tst_qquicktextedit::inputMethodComposing()
QGuiApplication::sendEvent(edit, &event);
}
QCOMPARE(edit->isInputMethodComposing(), true);
- QCOMPARE(spy.count(), 7);
+ QCOMPARE(spy.size(), 7);
{
QInputMethodEvent event;
QGuiApplication::sendEvent(edit, &event);
}
QCOMPARE(edit->isInputMethodComposing(), false);
- QCOMPARE(spy.count(), 8);
+ QCOMPARE(spy.size(), 8);
}
void tst_qquicktextedit::cursorRectangleSize_data()
@@ -4103,11 +4404,11 @@ void tst_qquicktextedit::cursorRectangleSize()
{
QFETCH(bool, useCursorDelegate);
- QQuickView *window = new QQuickView(testFileUrl("positionAt.qml"));
- QVERIFY(window->rootObject() != nullptr);
- QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(window->rootObject());
+ QQuickView window(testFileUrl("positionAt.qml"));
+ QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(window.rootObject());
+ QVERIFY(textEdit);
- QQmlComponent cursorDelegate(window->engine());
+ QQmlComponent cursorDelegate(window.engine());
if (useCursorDelegate) {
cursorDelegate.setData("import QtQuick 2.0\nRectangle { width:10; height:10; }", QUrl());
textEdit->setCursorDelegate(&cursorDelegate);
@@ -4119,9 +4420,9 @@ void tst_qquicktextedit::cursorRectangleSize()
textEdit->setCursorPosition(3);
QVERIFY(textEdit != nullptr);
textEdit->setFocus(true);
- window->show();
- window->requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(window));
+ window.show();
+ window.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
QInputMethodQueryEvent event(Qt::ImCursorRectangle);
qApp->sendEvent(textEdit, &event);
@@ -4146,8 +4447,6 @@ void tst_qquicktextedit::cursorRectangleSize()
// input panel cursorRectangle property and tranformed item cursor rectangle match
QRectF sceneCursorRect = QQuickItemPrivate::get(textEdit)->itemToWindowTransform().mapRect(cursorRectFromItem);
QCOMPARE(sceneCursorRect, qApp->inputMethod()->cursorRectangle());
-
- delete window;
}
void tst_qquicktextedit::getText_data()
@@ -4164,7 +4463,7 @@ void tst_qquicktextedit::getText_data()
QTest::newRow("all plain text")
<< standard.at(0)
- << 0 << standard.at(0).length()
+ << 0 << standard.at(0).size()
<< standard.at(0);
QTest::newRow("plain text sub string")
@@ -4184,17 +4483,17 @@ void tst_qquicktextedit::getText_data()
QTest::newRow("plain text cropped end")
<< standard.at(0)
- << 23 << standard.at(0).length() + 8
+ << 23 << standard.at(0).size() + 8
<< standard.at(0).mid(23);
QTest::newRow("plain text cropped beginning and end")
<< standard.at(0)
- << -9 << standard.at(0).length() + 4
+ << -9 << standard.at(0).size() + 4
<< standard.at(0);
QTest::newRow("all rich text")
<< richBoldText
- << 0 << plainBoldText.length()
+ << 0 << plainBoldText.size()
<< plainBoldText;
QTest::newRow("rich text sub string")
@@ -4205,7 +4504,7 @@ void tst_qquicktextedit::getText_data()
// Line break.
QTest::newRow("all plain text (line break)")
<< standard.at(1)
- << 0 << standard.at(1).length()
+ << 0 << standard.at(1).size()
<< standard.at(1);
QTest::newRow("plain text sub string (line break)")
@@ -4225,17 +4524,17 @@ void tst_qquicktextedit::getText_data()
QTest::newRow("plain text cropped end (line break)")
<< standard.at(1)
- << 23 << standard.at(1).length() + 8
+ << 23 << standard.at(1).size() + 8
<< standard.at(1).mid(23);
QTest::newRow("plain text cropped beginning and end (line break)")
<< standard.at(1)
- << -9 << standard.at(1).length() + 4
+ << -9 << standard.at(1).size() + 4
<< standard.at(1);
QTest::newRow("all rich text (line break)")
<< richBoldTextLB
- << 0 << plainBoldTextLB.length()
+ << 0 << plainBoldTextLB.size()
<< plainBoldTextLB;
QTest::newRow("rich text sub string (line break)")
@@ -4274,7 +4573,7 @@ void tst_qquicktextedit::getFormattedText_data()
QTest::newRow("all plain text")
<< standard.at(0)
<< QQuickTextEdit::PlainText
- << 0 << standard.at(0).length()
+ << 0 << standard.at(0).size()
<< standard.at(0);
QTest::newRow("plain text sub string")
@@ -4298,31 +4597,31 @@ void tst_qquicktextedit::getFormattedText_data()
QTest::newRow("plain text cropped end")
<< standard.at(0)
<< QQuickTextEdit::PlainText
- << 23 << standard.at(0).length() + 8
+ << 23 << standard.at(0).size() + 8
<< standard.at(0).mid(23);
QTest::newRow("plain text cropped beginning and end")
<< standard.at(0)
<< QQuickTextEdit::PlainText
- << -9 << standard.at(0).length() + 4
+ << -9 << standard.at(0).size() + 4
<< standard.at(0);
QTest::newRow("all rich (Auto) text")
<< richBoldText
<< QQuickTextEdit::AutoText
- << 0 << plainBoldText.length()
+ << 0 << plainBoldText.size()
<< QString("This is some \\<.*\\>bold\\</.*\\> text");
QTest::newRow("all rich (Rich) text")
<< richBoldText
<< QQuickTextEdit::RichText
- << 0 << plainBoldText.length()
+ << 0 << plainBoldText.size()
<< QString("This is some \\<.*\\>bold\\</.*\\> text");
QTest::newRow("all rich (Plain) text")
<< richBoldText
<< QQuickTextEdit::PlainText
- << 0 << richBoldText.length()
+ << 0 << richBoldText.size()
<< richBoldText;
QTest::newRow("rich (Auto) text sub string")
@@ -4401,10 +4700,10 @@ void tst_qquicktextedit::append_data()
QTest::newRow("cursor follows (end)")
<< standard.at(0) << QQuickTextEdit::PlainText
- << standard.at(0).length() << standard.at(0).length()
+ << standard.at(0).size() << standard.at(0).size()
<< QString("Hello")
<< standard.at(0) + QString("\nHello")
- << standard.at(0).length() + 6 << standard.at(0).length() + 6 << standard.at(0).length() + 6
+ << standard.at(0).size() + 6 << standard.at(0).size() + 6 << standard.at(0).size() + 6
<< false << true;
QTest::newRow("selection kept intact (beginning)")
@@ -4425,10 +4724,10 @@ void tst_qquicktextedit::append_data()
QTest::newRow("selection kept intact, cursor follows (end)")
<< standard.at(0) << QQuickTextEdit::PlainText
- << 18 << standard.at(0).length()
+ << 18 << standard.at(0).size()
<< QString("Hello")
<< standard.at(0) + QString("\nHello")
- << 18 << standard.at(0).length() + 6 << standard.at(0).length() + 6
+ << 18 << standard.at(0).size() + 6 << standard.at(0).size() + 6
<< true << true;
QTest::newRow("reversed selection kept intact")
@@ -4462,6 +4761,22 @@ void tst_qquicktextedit::append_data()
<< standard.at(0) + QString("\nHello")
<< 0 << 0 << 0
<< false << false;
+
+ QTest::newRow("markdown into markdown")
+ << QString("**Hello**") << QQuickTextEdit::MarkdownText
+ << 0 << 0
+ << QString(" *world*")
+ << QString("Hello\u2029world")
+ << 0 << 0 << 0
+ << false << false;
+
+ QTest::newRow("rich text into markdown")
+ << QString("**Hello**") << QQuickTextEdit::MarkdownText
+ << 0 << 0
+ << QString(" <i>world</i>")
+ << QString("Hello\u2029world")
+ << 0 << 0 << 0
+ << false << false;
}
void tst_qquicktextedit::append()
@@ -4495,14 +4810,15 @@ void tst_qquicktextedit::append()
textEdit->append(appendText);
- if (textFormat == QQuickTextEdit::RichText || (textFormat == QQuickTextEdit::AutoText && (
- Qt::mightBeRichText(text) || Qt::mightBeRichText(appendText)))) {
- QCOMPARE(textEdit->getText(0, expectedText.length()), expectedText);
+ if (textFormat == QQuickTextEdit::RichText || textFormat == QQuickTextEdit::MarkdownText ||
+ (textFormat == QQuickTextEdit::AutoText &&
+ (Qt::mightBeRichText(text) || Qt::mightBeRichText(appendText)))) {
+ QCOMPARE(textEdit->getText(0, expectedText.size()), expectedText);
} else {
QCOMPARE(textEdit->text(), expectedText);
}
- QCOMPARE(textEdit->length(), expectedText.length());
+ QCOMPARE(textEdit->length(), expectedText.size());
QCOMPARE(textEdit->selectionStart(), expectedSelectionStart);
QCOMPARE(textEdit->selectionEnd(), expectedSelectionEnd);
@@ -4511,11 +4827,11 @@ void tst_qquicktextedit::append()
if (selectionStart > selectionEnd)
qSwap(selectionStart, selectionEnd);
- QCOMPARE(selectionSpy.count() > 0, selectionChanged);
- QCOMPARE(selectionStartSpy.count() > 0, selectionStart != expectedSelectionStart);
- QCOMPARE(selectionEndSpy.count() > 0, selectionEnd != expectedSelectionEnd);
- QCOMPARE(textSpy.count() > 0, text != expectedText);
- QCOMPARE(cursorPositionSpy.count() > 0, cursorPositionChanged);
+ QCOMPARE(selectionSpy.size() > 0, selectionChanged);
+ QCOMPARE(selectionStartSpy.size() > 0, selectionStart != expectedSelectionStart);
+ QCOMPARE(selectionEndSpy.size() > 0, selectionEnd != expectedSelectionEnd);
+ QCOMPARE(textSpy.size() > 0, text != expectedText);
+ QCOMPARE(cursorPositionSpy.size() > 0, cursorPositionChanged);
}
void tst_qquicktextedit::insert_data()
@@ -4543,10 +4859,10 @@ void tst_qquicktextedit::insert_data()
QTest::newRow("at cursor position (end)")
<< standard.at(0) << QQuickTextEdit::PlainText
- << standard.at(0).length() << standard.at(0).length() << standard.at(0).length()
+ << standard.at(0).size() << standard.at(0).size() << standard.at(0).size()
<< QString("Hello")
<< standard.at(0) + QString("Hello")
- << standard.at(0).length() + 5 << standard.at(0).length() + 5 << standard.at(0).length() + 5
+ << standard.at(0).size() + 5 << standard.at(0).size() + 5 << standard.at(0).size() + 5
<< false << true;
QTest::newRow("at cursor position (middle)")
@@ -4567,10 +4883,10 @@ void tst_qquicktextedit::insert_data()
QTest::newRow("before cursor position (end)")
<< standard.at(0) << QQuickTextEdit::PlainText
- << standard.at(0).length() << standard.at(0).length() << 18
+ << standard.at(0).size() << standard.at(0).size() << 18
<< QString("Hello")
<< standard.at(0).mid(0, 18) + QString("Hello") + standard.at(0).mid(18)
- << standard.at(0).length() + 5 << standard.at(0).length() + 5 << standard.at(0).length() + 5
+ << standard.at(0).size() + 5 << standard.at(0).size() + 5 << standard.at(0).size() + 5
<< false << true;
QTest::newRow("before cursor position (middle)")
@@ -4583,7 +4899,7 @@ void tst_qquicktextedit::insert_data()
QTest::newRow("after cursor position (middle)")
<< standard.at(0) << QQuickTextEdit::PlainText
- << 18 << 18 << standard.at(0).length()
+ << 18 << 18 << standard.at(0).size()
<< QString("Hello")
<< standard.at(0) + QString("Hello")
<< 18 << 18 << 18
@@ -4607,7 +4923,7 @@ void tst_qquicktextedit::insert_data()
QTest::newRow("after selection")
<< standard.at(0) << QQuickTextEdit::PlainText
- << 14 << 19 << standard.at(0).length()
+ << 14 << 19 << standard.at(0).size()
<< QString("Hello")
<< standard.at(0) + QString("Hello")
<< 14 << 19 << 19
@@ -4615,7 +4931,7 @@ void tst_qquicktextedit::insert_data()
QTest::newRow("after reversed selection")
<< standard.at(0) << QQuickTextEdit::PlainText
- << 19 << 14 << standard.at(0).length()
+ << 19 << 14 << standard.at(0).size()
<< QString("Hello")
<< standard.at(0) + QString("Hello")
<< 14 << 19 << 14
@@ -4671,11 +4987,44 @@ void tst_qquicktextedit::insert_data()
QTest::newRow("past end")
<< standard.at(0) << QQuickTextEdit::PlainText
- << 0 << 0 << standard.at(0).length() + 3
+ << 0 << 0 << standard.at(0).size() + 3
<< QString("Hello")
<< standard.at(0)
<< 0 << 0 << 0
<< false << false;
+
+ const QString markdownBaseString("# Hello\nWorld\n");
+ QTest::newRow("markdown into markdown at end")
+ << markdownBaseString << QQuickTextEdit::MarkdownText
+ << 0 << 0 << 11
+ << QString("\n## Other\ntext")
+ << QString("Hello\u2029World\u2029Other\u2029text")
+ << 0 << 0 << 0
+ << false << false;
+
+ QTest::newRow("markdown into markdown in the middle")
+ << markdownBaseString << QQuickTextEdit::MarkdownText
+ << 0 << 0 << 6
+ << QString("## Other\ntext\n")
+ << QString("Hello\u2029Other\u2029text\u2029World")
+ << 0 << 0 << 0
+ << false << false;
+
+ QTest::newRow("markdown into markdown in the middle no newlines")
+ << markdownBaseString << QQuickTextEdit::MarkdownText
+ << 0 << 0 << 6
+ << QString("## Other\ntext")
+ << QString("Hello\u2029Other\u2029textWorld")
+ << 0 << 0 << 0
+ << false << false;
+
+ QTest::newRow("markdown with bold span into markdown")
+ << QString("# Heading\n text") << QQuickTextEdit::MarkdownText
+ << 0 << 0 << 8
+ << QString("*Body*")
+ << QString("Heading\u2029Bodytext")
+ << 0 << 0 << 0
+ << false << false;
}
void tst_qquicktextedit::insert()
@@ -4710,14 +5059,15 @@ void tst_qquicktextedit::insert()
textEdit->insert(insertPosition, insertText);
- if (textFormat == QQuickTextEdit::RichText || (textFormat == QQuickTextEdit::AutoText && (
- Qt::mightBeRichText(text) || Qt::mightBeRichText(insertText)))) {
- QCOMPARE(textEdit->getText(0, expectedText.length()), expectedText);
+ if (textFormat == QQuickTextEdit::RichText || textFormat == QQuickTextEdit::MarkdownText ||
+ (textFormat == QQuickTextEdit::AutoText &&
+ (Qt::mightBeRichText(text) || Qt::mightBeRichText(insertText)))) {
+ QCOMPARE(textEdit->getText(0, expectedText.size()), expectedText);
+ qCDebug(lcTests) << "with formatting:" << textEdit->getFormattedText(0, 100);
} else {
QCOMPARE(textEdit->text(), expectedText);
-
}
- QCOMPARE(textEdit->length(), expectedText.length());
+ QCOMPARE(textEdit->length(), expectedText.size());
QCOMPARE(textEdit->selectionStart(), expectedSelectionStart);
QCOMPARE(textEdit->selectionEnd(), expectedSelectionEnd);
@@ -4726,11 +5076,11 @@ void tst_qquicktextedit::insert()
if (selectionStart > selectionEnd)
qSwap(selectionStart, selectionEnd);
- QCOMPARE(selectionSpy.count() > 0, selectionChanged);
- QCOMPARE(selectionStartSpy.count() > 0, selectionStart != expectedSelectionStart);
- QCOMPARE(selectionEndSpy.count() > 0, selectionEnd != expectedSelectionEnd);
- QCOMPARE(textSpy.count() > 0, text != expectedText);
- QCOMPARE(cursorPositionSpy.count() > 0, cursorPositionChanged);
+ QCOMPARE(selectionSpy.size() > 0, selectionChanged);
+ QCOMPARE(selectionStartSpy.size() > 0, selectionStart != expectedSelectionStart);
+ QCOMPARE(selectionEndSpy.size() > 0, selectionEnd != expectedSelectionEnd);
+ QCOMPARE(textSpy.size() > 0, text != expectedText);
+ QCOMPARE(cursorPositionSpy.size() > 0, cursorPositionChanged);
}
void tst_qquicktextedit::remove_data()
@@ -4769,18 +5119,18 @@ void tst_qquicktextedit::remove_data()
QTest::newRow("to cursor position (end)")
<< standard.at(0) << QQuickTextEdit::PlainText
- << standard.at(0).length() << standard.at(0).length()
- << standard.at(0).length() << standard.at(0).length() - 5
- << standard.at(0).mid(0, standard.at(0).length() - 5)
- << standard.at(0).length() - 5 << standard.at(0).length() - 5 << standard.at(0).length() - 5
+ << standard.at(0).size() << standard.at(0).size()
+ << standard.at(0).size() << standard.at(0).size() - 5
+ << standard.at(0).mid(0, standard.at(0).size() - 5)
+ << standard.at(0).size() - 5 << standard.at(0).size() - 5 << standard.at(0).size() - 5
<< false << true;
QTest::newRow("to cursor position (end)")
<< standard.at(0) << QQuickTextEdit::PlainText
- << standard.at(0).length() << standard.at(0).length()
- << standard.at(0).length() - 5 << standard.at(0).length()
- << standard.at(0).mid(0, standard.at(0).length() - 5)
- << standard.at(0).length() - 5 << standard.at(0).length() - 5 << standard.at(0).length() - 5
+ << standard.at(0).size() << standard.at(0).size()
+ << standard.at(0).size() - 5 << standard.at(0).size()
+ << standard.at(0).mid(0, standard.at(0).size() - 5)
+ << standard.at(0).size() - 5 << standard.at(0).size() - 5 << standard.at(0).size() - 5
<< false << true;
QTest::newRow("from cursor position (middle)")
@@ -4809,10 +5159,10 @@ void tst_qquicktextedit::remove_data()
QTest::newRow("before cursor position (end)")
<< standard.at(0) << QQuickTextEdit::PlainText
- << standard.at(0).length() << standard.at(0).length()
+ << standard.at(0).size() << standard.at(0).size()
<< 18 << 23
<< standard.at(0).mid(0, 18) + standard.at(0).mid(23)
- << standard.at(0).length() - 5 << standard.at(0).length() - 5 << standard.at(0).length() - 5
+ << standard.at(0).size() - 5 << standard.at(0).size() - 5 << standard.at(0).size() - 5
<< false << true;
QTest::newRow("before cursor position (middle)")
@@ -4850,16 +5200,16 @@ void tst_qquicktextedit::remove_data()
QTest::newRow("after selection")
<< standard.at(0) << QQuickTextEdit::PlainText
<< 14 << 19
- << standard.at(0).length() - 5 << standard.at(0).length()
- << standard.at(0).mid(0, standard.at(0).length() - 5)
+ << standard.at(0).size() - 5 << standard.at(0).size()
+ << standard.at(0).mid(0, standard.at(0).size() - 5)
<< 14 << 19 << 19
<< false << false;
QTest::newRow("after reversed selection")
<< standard.at(0) << QQuickTextEdit::PlainText
<< 19 << 14
- << standard.at(0).length() - 5 << standard.at(0).length()
- << standard.at(0).mid(0, standard.at(0).length() - 5)
+ << standard.at(0).size() - 5 << standard.at(0).size()
+ << standard.at(0).mid(0, standard.at(0).size() - 5)
<< 14 << 19 << 14
<< false << false;
@@ -4890,7 +5240,7 @@ void tst_qquicktextedit::remove_data()
QTest::newRow("plain text cropped end")
<< standard.at(0) << QQuickTextEdit::PlainText
<< 0 << 0
- << 23 << standard.at(0).length() + 8
+ << 23 << standard.at(0).size() + 8
<< standard.at(0).mid(0, 23)
<< 0 << 0 << 0
<< false << false;
@@ -4898,7 +5248,7 @@ void tst_qquicktextedit::remove_data()
QTest::newRow("plain text cropped beginning and end")
<< standard.at(0) << QQuickTextEdit::PlainText
<< 0 << 0
- << -9 << standard.at(0).length() + 4
+ << -9 << standard.at(0).size() + 4
<< QString()
<< 0 << 0 << 0
<< false << false;
@@ -4906,7 +5256,7 @@ void tst_qquicktextedit::remove_data()
QTest::newRow("all rich text")
<< richBoldText << QQuickTextEdit::RichText
<< 0 << 0
- << 0 << plainBoldText.length()
+ << 0 << plainBoldText.size()
<< QString()
<< 0 << 0 << 0
<< false << false;
@@ -4954,11 +5304,11 @@ void tst_qquicktextedit::remove()
if (textFormat == QQuickTextEdit::RichText
|| (textFormat == QQuickTextEdit::AutoText && Qt::mightBeRichText(text))) {
- QCOMPARE(textEdit->getText(0, expectedText.length()), expectedText);
+ QCOMPARE(textEdit->getText(0, expectedText.size()), expectedText);
} else {
QCOMPARE(textEdit->text(), expectedText);
}
- QCOMPARE(textEdit->length(), expectedText.length());
+ QCOMPARE(textEdit->length(), expectedText.size());
if (selectionStart > selectionEnd) //
qSwap(selectionStart, selectionEnd);
@@ -4967,14 +5317,14 @@ void tst_qquicktextedit::remove()
QCOMPARE(textEdit->selectionEnd(), expectedSelectionEnd);
QCOMPARE(textEdit->cursorPosition(), expectedCursorPosition);
- QCOMPARE(selectionSpy.count() > 0, selectionChanged);
- QCOMPARE(selectionStartSpy.count() > 0, selectionStart != expectedSelectionStart);
- QCOMPARE(selectionEndSpy.count() > 0, selectionEnd != expectedSelectionEnd);
- QCOMPARE(textSpy.count() > 0, text != expectedText);
+ QCOMPARE(selectionSpy.size() > 0, selectionChanged);
+ QCOMPARE(selectionStartSpy.size() > 0, selectionStart != expectedSelectionStart);
+ QCOMPARE(selectionEndSpy.size() > 0, selectionEnd != expectedSelectionEnd);
+ QCOMPARE(textSpy.size() > 0, text != expectedText);
if (cursorPositionChanged) //
- QVERIFY(cursorPositionSpy.count() > 0);
+ QVERIFY(cursorPositionSpy.size() > 0);
}
#if QT_CONFIG(shortcut)
@@ -5281,17 +5631,9 @@ void tst_qquicktextedit::undo()
QFETCH(IntList, insertMode);
QFETCH(QStringList, expectedString);
- QString componentStr = "import QtQuick 2.0\nTextEdit { focus: true }";
- QQmlComponent textEditComponent(&engine);
- textEditComponent.setData(componentStr.toLatin1(), QUrl());
- QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
- QVERIFY(textEdit != nullptr);
-
- QQuickWindow window;
- textEdit->setParentItem(window.contentItem());
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("focusByDefault.qml")));
+ QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(textEdit->hasActiveFocus());
QVERIFY(!textEdit->canUndo());
@@ -5313,11 +5655,11 @@ void tst_qquicktextedit::undo()
// QTest::keyClick(testWidget, Qt::Key_End, Qt::ShiftModifier);
}
- for (int j = 0; j < insertString.at(i).length(); j++)
+ for (int j = 0; j < insertString.at(i).size(); j++)
QTest::keyClick(&window, insertString.at(i).at(j).toLatin1());
}
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
// STEP 2: Next call undo several times and see if we can restore to the previous state
for (i = 0; i < expectedString.size() - 1; ++i) {
@@ -5329,7 +5671,7 @@ void tst_qquicktextedit::undo()
// STEP 3: Verify that we have undone everything
QVERIFY(textEdit->text().isEmpty());
QVERIFY(!textEdit->canUndo());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
void tst_qquicktextedit::redo_data()
@@ -5367,17 +5709,10 @@ void tst_qquicktextedit::redo()
QFETCH(IntList, insertIndex);
QFETCH(QStringList, expectedString);
- QString componentStr = "import QtQuick 2.0\nTextEdit { focus: true }";
- QQmlComponent textEditComponent(&engine);
- textEditComponent.setData(componentStr.toLatin1(), QUrl());
- QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
- QVERIFY(textEdit != nullptr);
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("focusByDefault.qml")));
+ QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(window.rootObject());
- QQuickWindow window;
- textEdit->setParentItem(window.contentItem());
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
QVERIFY(textEdit->hasActiveFocus());
QVERIFY(!textEdit->canUndo());
@@ -5390,13 +5725,13 @@ void tst_qquicktextedit::redo()
for (i = 0; i < insertString.size(); ++i) {
if (insertIndex[i] > -1)
textEdit->setCursorPosition(insertIndex[i]);
- for (int j = 0; j < insertString.at(i).length(); j++)
+ for (int j = 0; j < insertString.at(i).size(); j++)
QTest::keyClick(&window, insertString.at(i).at(j).toLatin1());
QVERIFY(textEdit->canUndo());
QVERIFY(!textEdit->canRedo());
}
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
// undo everything
while (!textEdit->text().isEmpty()) {
@@ -5405,7 +5740,7 @@ void tst_qquicktextedit::redo()
QVERIFY(textEdit->canRedo());
}
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
for (i = 0; i < expectedString.size(); ++i) {
QVERIFY(textEdit->canRedo());
@@ -5414,7 +5749,7 @@ void tst_qquicktextedit::redo()
QVERIFY(textEdit->canUndo());
}
QVERIFY(!textEdit->canRedo());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
#if QT_CONFIG(shortcut)
@@ -5590,17 +5925,10 @@ void tst_qquicktextedit::undo_keypressevents()
QFETCH(KeyList, keys);
QFETCH(QStringList, expectedString);
- QString componentStr = "import QtQuick 2.0\nTextEdit { focus: true }";
- QQmlComponent textEditComponent(&engine);
- textEditComponent.setData(componentStr.toLatin1(), QUrl());
- QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
- QVERIFY(textEdit != nullptr);
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("focusByDefault.qml")));
+ QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(window.rootObject());
- QQuickWindow window;
- textEdit->setParentItem(window.contentItem());
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
QVERIFY(textEdit->hasActiveFocus());
simulateKeys(&window, keys);
@@ -5616,17 +5944,9 @@ void tst_qquicktextedit::undo_keypressevents()
void tst_qquicktextedit::clear()
{
- QString componentStr = "import QtQuick 2.0\nTextEdit { focus: true }";
- QQmlComponent textEditComponent(&engine);
- textEditComponent.setData(componentStr.toLatin1(), QUrl());
- QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit*>(textEditComponent.create());
- QVERIFY(textEdit != nullptr);
-
- QQuickWindow window;
- textEdit->setParentItem(window.contentItem());
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("focusByDefault.qml")));
+ QQuickTextEdit *textEdit = qobject_cast<QQuickTextEdit *>(window.rootObject());
QVERIFY(textEdit->hasActiveFocus());
QSignalSpy spy(textEdit, SIGNAL(canUndoChanged()));
@@ -5636,12 +5956,12 @@ void tst_qquicktextedit::clear()
textEdit->clear();
QVERIFY(textEdit->text().isEmpty());
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
// checks that clears can be undone
textEdit->undo();
QVERIFY(!textEdit->canUndo());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
QCOMPARE(textEdit->text(), QString("I am Legend"));
textEdit->setCursorPosition(4);
@@ -5653,12 +5973,12 @@ void tst_qquicktextedit::clear()
textEdit->clear();
QVERIFY(textEdit->text().isEmpty());
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
// checks that clears can be undone
textEdit->undo();
QVERIFY(!textEdit->canUndo());
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
QCOMPARE(textEdit->text(), QString("I am Legend"));
textEdit->setText(QString("<i>I am Legend</i>"));
@@ -5666,11 +5986,11 @@ void tst_qquicktextedit::clear()
textEdit->clear();
QVERIFY(textEdit->text().isEmpty());
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
// checks that clears can be undone
textEdit->undo();
- QCOMPARE(spy.count(), 6);
+ QCOMPARE(spy.size(), 6);
QCOMPARE(textEdit->text(), QString("<i>I am Legend</i>"));
}
@@ -5689,15 +6009,15 @@ void tst_qquicktextedit::baseUrl()
textObject->setBaseUrl(localUrl);
QCOMPARE(textObject->baseUrl(), localUrl);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
textObject->setBaseUrl(remoteUrl);
QCOMPARE(textObject->baseUrl(), remoteUrl);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
textObject->resetBaseUrl();
QCOMPARE(textObject->baseUrl(), localUrl);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
void tst_qquicktextedit::embeddedImages_data()
@@ -5707,11 +6027,11 @@ void tst_qquicktextedit::embeddedImages_data()
QTest::newRow("local") << testFileUrl("embeddedImagesLocal.qml") << "";
QTest::newRow("local-error") << testFileUrl("embeddedImagesLocalError.qml")
<< testFileUrl("embeddedImagesLocalError.qml").toString()+":3:1: QML TextEdit: Cannot open: " + testFileUrl("http/notexists.png").toString();
- QTest::newRow("local") << testFileUrl("embeddedImagesLocalRelative.qml") << "";
+ QTest::newRow("local-relative") << testFileUrl("embeddedImagesLocalRelative.qml") << "";
QTest::newRow("remote") << testFileUrl("embeddedImagesRemote.qml") << "";
QTest::newRow("remote-error") << testFileUrl("embeddedImagesRemoteError.qml")
<< testFileUrl("embeddedImagesRemoteError.qml").toString()+":3:1: QML TextEdit: Error transferring {{ServerBaseUrl}}/notexists.png - server replied: Not found";
- QTest::newRow("remote") << testFileUrl("embeddedImagesRemoteRelative.qml") << "";
+ QTest::newRow("remote-relative") << testFileUrl("embeddedImagesRemoteRelative.qml") << "";
}
void tst_qquicktextedit::embeddedImages()
@@ -5729,40 +6049,93 @@ void tst_qquicktextedit::embeddedImages()
QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
QQmlComponent textComponent(&engine, qmlfile);
- QQuickTextEdit *textObject = qobject_cast<QQuickTextEdit*>(textComponent.beginCreate(engine.rootContext()));
- QVERIFY(textObject != nullptr);
+ QScopedPointer<QQuickTextEdit> textObject(qobject_cast<QQuickTextEdit*>(textComponent.beginCreate(engine.rootContext())));
+ QVERIFY(!textObject.isNull());
const int baseUrlPropertyIndex = textObject->metaObject()->indexOfProperty("serverBaseUrl");
if (baseUrlPropertyIndex != -1) {
QMetaProperty prop = textObject->metaObject()->property(baseUrlPropertyIndex);
- QVERIFY(prop.write(textObject, server.baseUrl().toString()));
+ QVERIFY(prop.write(textObject.get(), server.baseUrl().toString()));
}
textComponent.completeCreate();
- QTRY_COMPARE(QQuickTextEditPrivate::get(textObject)->document->resourcesLoading(), 0);
+ QTRY_COMPARE(textObject->resourcesLoading(), 0);
QPixmap pm(testFile("http/exists.png"));
if (error.isEmpty()) {
- QCOMPARE(textObject->width(), double(pm.width()));
- QCOMPARE(textObject->height(), double(pm.height()));
+ QCOMPARE(textObject->width(), pm.width());
+ QCOMPARE(textObject->height(), pm.height());
} else {
QVERIFY(16 != pm.width()); // check test is effective
- QCOMPARE(textObject->width(), 16.0); // default size of QTextDocument broken image icon
- QCOMPARE(textObject->height(), 16.0);
+ QCOMPARE(textObject->width(), 16); // default size of QTextDocument broken image icon
+ QCOMPARE(textObject->height(), 16);
}
- delete textObject;
+ // QTextDocument images are cached in QTextDocumentPrivate::cachedResources,
+ // so verify that we don't redundantly cache them in QQuickPixmapCache
+ QCOMPARE(QQuickPixmapCache::instance()->m_cache.size(), 0);
}
-void tst_qquicktextedit::emptytags_QTBUG_22058()
+void tst_qquicktextedit::remoteImagesInDocumentSource()
{
- QQuickView window(testFileUrl("qtbug-22058.qml"));
- QVERIFY(window.rootObject() != nullptr);
+ TestHTTPServer server;
+ QVERIFY2(server.listen(), qPrintable(server.errorString()));
+ server.serveDirectory(testFile("http"));
+ server.serveDirectory(testFile("httpfail"), TestHTTPServer::Disconnect);
+ server.serveDirectory(testFile("httpslow"), TestHTTPServer::Delay);
- window.show();
- window.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&window));
+ QTemporaryDir tmpDir;
+ QVERIFY(tmpDir.isValid());
+ QString tmpPath = tmpDir.filePath("multipleRemoteImages.md");
+ QByteArray markdownBuf;
+ {
+ QFile sf(QQmlFile::urlToLocalFileOrQrc(testFileUrl("multipleRemoteImages.md")));
+ QVERIFY(sf.open(QIODeviceBase::ReadOnly));
+ markdownBuf = sf.readAll();
+ qCDebug(lcTests) << sf.fileName() << "->" << tmpPath
+ << "s/serverBaseUrl/" << server.baseUrl().toString()
+ << "/ in markdown: size" << markdownBuf.size();
+ }
+ markdownBuf.replace("serverBaseUrl", server.baseUrl().toString().toLocal8Bit());
+ {
+ QFile of(tmpPath);
+ QVERIFY(of.open(QIODeviceBase::WriteOnly));
+ QCOMPARE(of.write(markdownBuf), markdownBuf.size());
+ }
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("textEdit.qml")));
+ auto *textEdit = qmlobject_cast<QQuickTextEdit *>(window.rootObject());
+ QVERIFY(textEdit);
+ QQuickTextEditPrivate *priv = QQuickTextEditPrivate::get(textEdit);
+ QSignalSpy implicitHeightChangedSpy(textEdit, &QQuickTextEdit::implicitHeightChanged);
+
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*Protocol \"gopher\" is unknown"));
+ QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*Connection closed")); // httpfail/warning.png
+ textEdit->setTextFormat(QQuickTextEdit::MarkdownText);
+ textEdit->textDocument()->setSource(QUrl::fromLocalFile(tmpPath));
+
+ // the document gets loaded first, then the resources
+ QTRY_COMPARE(textEdit->textDocument()->status(), QQuickTextDocument::Status::Loaded);
+ const qreal implicitHeight = textEdit->implicitHeight();
+
+ // all resource-loading jobs complete or fail eventually
+ QTRY_COMPARE(priv->pixmapsInProgress.size(), 0);
+
+ // after httpslow/turtle.svg loads, implicitHeight increases
+ QCOMPARE(implicitHeightChangedSpy.size(), 2);
+ QCOMPARE_GT(textEdit->implicitHeight(), implicitHeight);
+
+ // QTextDocument images are cached in QTextDocumentPrivate::cachedResources,
+ // so verify that we don't redundantly cache them in QQuickPixmapCache
+ QCOMPARE(QQuickPixmapCache::instance()->m_cache.size(), 0);
+}
+
+void tst_qquicktextedit::emptytags_QTBUG_22058()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("qtbug-22058.qml")));
QQuickTextEdit *input = qobject_cast<QQuickTextEdit *>(qvariant_cast<QObject *>(window.rootObject()->property("inputField")));
QVERIFY(input->hasActiveFocus());
@@ -5795,7 +6168,7 @@ void tst_qquicktextedit::cursorRectangle_QTBUG_38947()
QRectF rect = edit->positionToRectangle(i);
QTest::mouseMove(&window, rect.center().toPoint());
QCOMPARE(edit->cursorRectangle(), rect);
- QCOMPARE(spy.count(), i);
+ QCOMPARE(spy.size(), i);
}
QPoint to = edit->positionToRectangle(edit->length() - 1).center().toPoint();
@@ -5824,13 +6197,13 @@ void tst_qquicktextedit::doubleSelect_QTBUG_38704()
QSignalSpy selectionSpy(textEdit, SIGNAL(selectedTextChanged()));
textEdit->select(0,1); //Select some text initially
- QCOMPARE(selectionSpy.count(), 1);
+ QCOMPARE(selectionSpy.size(), 1);
textEdit->select(0,1); //No change to selection start/end
- QCOMPARE(selectionSpy.count(), 1);
+ QCOMPARE(selectionSpy.size(), 1);
textEdit->select(0,2); //Change selection end
- QCOMPARE(selectionSpy.count(), 2);
+ QCOMPARE(selectionSpy.size(), 2);
textEdit->select(1,2); //Change selection start
- QCOMPARE(selectionSpy.count(), 3);
+ QCOMPARE(selectionSpy.size(), 3);
}
void tst_qquicktextedit::padding()
@@ -5949,51 +6322,39 @@ void tst_qquicktextedit::QTBUG_51115_readOnlyResetsSelection()
void tst_qquicktextedit::keys_shortcutoverride()
{
// Tests that QML TextEdit receives Keys.onShortcutOverride (QTBUG-68711)
- QQuickView view;
- view.setSource(testFileUrl("keys_shortcutoverride.qml"));
- view.show();
- view.requestActivate();
- QVERIFY(QTest::qWaitForWindowActive(&view));
- QObject *root = view.rootObject();
- QVERIFY(root);
-
- QQuickTextEdit *textEdit = root->findChild<QQuickTextEdit*>();
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("keys_shortcutoverride.qml")));
+ QQuickTextEdit *textEdit = window.rootObject()->findChild<QQuickTextEdit*>();
QVERIFY(textEdit);
- QQuickRectangle *rectangle = root->findChild<QQuickRectangle*>(QLatin1String("rectangle"));
+ QQuickRectangle *rectangle = window.rootObject()->findChild<QQuickRectangle*>(QLatin1String("rectangle"));
QVERIFY(rectangle);
// Precondition: check if its not already changed
- QCOMPARE(root->property("who").value<QString>(), QLatin1String("nobody"));
+ QCOMPARE(window.rootObject()->property("who").value<QString>(), QLatin1String("nobody"));
// send Key_Escape to the Rectangle
QVERIFY(rectangle->hasActiveFocus());
- QTest::keyPress(&view, Qt::Key_Escape);
- QCOMPARE(root->property("who").value<QString>(), QLatin1String("Rectangle"));
+ QTest::keyPress(&window, Qt::Key_Escape);
+ QCOMPARE(window.rootObject()->property("who").value<QString>(), QLatin1String("Rectangle"));
// send Key_Escape to TextEdit
textEdit->setFocus(true);
- QTest::keyPress(&view, Qt::Key_Escape);
- QCOMPARE(root->property("who").value<QString>(), QLatin1String("TextEdit"));
+ QTest::keyPress(&window, Qt::Key_Escape);
+ QCOMPARE(window.rootObject()->property("who").value<QString>(), QLatin1String("TextEdit"));
}
void tst_qquicktextedit::transparentSelectionColor()
{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabToImage not functional on offscreen/minimal platforms");
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
- QQuickView view;
- view.setSource(testFileUrl("transparentSelectionColor.qml"));
- view.show();
- QVERIFY(QTest::qWaitForWindowExposed(&view));
- QObject *root = view.rootObject();
- QVERIFY(root);
-
- QQuickTextEdit *textEdit = root->findChild<QQuickTextEdit *>();
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("transparentSelectionColor.qml")));
+ QQuickTextEdit *textEdit = window.rootObject()->findChild<QQuickTextEdit *>();
QVERIFY(textEdit);
textEdit->selectAll();
- QImage img = view.grabWindow();
+ QImage img = window.grabWindow();
QCOMPARE(img.isNull(), false);
QColor color = img.pixelColor(int(textEdit->width() / 2), int(textEdit->height()) / 2);
@@ -6002,6 +6363,368 @@ void tst_qquicktextedit::transparentSelectionColor()
QVERIFY(color.green() < 10);
}
+void tst_qquicktextedit::keyEventPropagation()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("keyEventPropagation.qml")));
+ QObject *root = window.rootObject();
+ QVERIFY(root);
+
+ QSignalSpy downSpy(root, SIGNAL(keyDown(int)));
+ QSignalSpy upSpy(root, SIGNAL(keyUp(int)));
+
+ QQuickTextEdit *textEdit = root->findChild<QQuickTextEdit *>();
+ QVERIFY(textEdit->hasActiveFocus());
+ simulateKey(&window, Qt::Key_Back);
+ QCOMPARE(downSpy.size(), 1);
+ QCOMPARE(upSpy.size(), 1);
+ auto downKey = downSpy.takeFirst();
+ auto upKey = upSpy.takeFirst();
+ QCOMPARE(downKey.at(0).toInt(), Qt::Key_Back);
+ QCOMPARE(upKey.at(0).toInt(), Qt::Key_Back);
+
+ simulateKey(&window, Qt::Key_Shift);
+ QCOMPARE(downSpy.size(), 1);
+ QCOMPARE(upSpy.size(), 1);
+ downKey = downSpy.takeFirst();
+ upKey = upSpy.takeFirst();
+ QCOMPARE(downKey.at(0).toInt(), Qt::Key_Shift);
+ QCOMPARE(upKey.at(0).toInt(), Qt::Key_Shift);
+
+ simulateKey(&window, Qt::Key_A);
+ QCOMPARE(downSpy.size(), 0);
+ QCOMPARE(upSpy.size(), 0);
+
+ simulateKey(&window, Qt::Key_Right);
+ QCOMPARE(downSpy.size(), 0);
+ QCOMPARE(upSpy.size(), 1);
+ upKey = upSpy.takeFirst();
+ QCOMPARE(upKey.at(0).toInt(), Qt::Key_Right);
+}
+
+void tst_qquicktextedit::markdown()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("markdown.qml")));
+ QQuickTextEdit *te = qobject_cast<QQuickTextEdit *>(window.rootObject());
+ QVERIFY(te);
+ QVERIFY(te->textDocument());
+ auto doc = te->textDocument()->textDocument();
+ QVERIFY(doc);
+ const QString mdSource("# Heading\n\nBody\n\n");
+
+ // Component.onCompleted has pre-populated a string in italics
+ QCOMPARE(te->text(), "*whee*\n\n");
+ QCOMPARE(te->getText(0, 100), "whee");
+ QCOMPARE(te->getFormattedText(0, 100), "*whee*\n\n");
+ QVERIFY(QTextCursor(doc).charFormat().font().italic());
+
+ if (isMainFontFixed())
+ QSKIP("fixed-pitch main font (QTBUG-103484)");
+ te->clear();
+ te->insert(0, mdSource);
+ QCOMPARE(te->text(), mdSource);
+ QCOMPARE(te->getText(0, 12), "Heading\u2029Body");
+ QCOMPARE(te->getFormattedText(0, 12), "# Heading\n\nBody\n\n");
+ QCOMPARE(QTextCursor(doc).blockFormat().headingLevel(), 1);
+
+ te->selectAll();
+ QCOMPARE(te->selectedText(), "Heading\u2029Body");
+
+ te->clear();
+ te->setText(mdSource);
+ QCOMPARE(te->text(), mdSource);
+ QCOMPARE(te->getText(0, 12), "Heading\u2029Body");
+ QCOMPARE(te->getFormattedText(0, 12), "# Heading\n\nBody\n\n");
+ QCOMPARE(QTextCursor(doc).blockFormat().headingLevel(), 1);
+
+ te->insert(12, "_text_");
+ QCOMPARE(te->text(), "# Heading\n\nBody_text_\n\n");
+ QCOMPARE(te->getText(0, 100), "Heading\u2029Bodytext");
+ QCOMPARE(te->getFormattedText(0, 100), "# Heading\n\nBody_text_\n\n");
+ QTextCursor cursor(doc);
+ cursor.movePosition(QTextCursor::End);
+ QVERIFY(cursor.charFormat().fontUnderline());
+}
+
+#if QT_CONFIG(clipboard)
+void tst_qquicktextedit::pasteHtmlIntoMarkdown()
+{
+ if (isMainFontFixed())
+ QSKIP("fixed-pitch main font (QTBUG-103484)");
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("markdown.qml")));
+ QQuickTextEdit *te = qobject_cast<QQuickTextEdit *>(window.rootObject());
+ QVERIFY(te);
+ QVERIFY(te->textDocument());
+ auto doc = te->textDocument()->textDocument();
+ QVERIFY(doc);
+
+ QMimeData *mData = new QMimeData; // not a leak: if it's stack-allocated, we get a double free
+ mData->setHtml("<b>Hello <i>world</i></b>");
+ QGuiApplication::clipboard()->setMimeData(mData);
+
+ te->selectAll();
+ te->paste();
+ QTRY_COMPARE(te->text(), "**Hello *world***\n\n");
+ QCOMPARE(te->getFormattedText(0, 100), "**Hello *world***\n\n");
+ QCOMPARE(te->textFormat(), QQuickTextEdit::MarkdownText);
+ QCOMPARE(te->getText(0, 100), "Hello world");
+
+ QGuiApplication::clipboard()->clear();
+ te->selectAll();
+ te->copy();
+ QTRY_VERIFY(QGuiApplication::clipboard()->mimeData()->hasHtml());
+ QVERIFY(QGuiApplication::clipboard()->mimeData()->hasText());
+ const auto *md = QGuiApplication::clipboard()->mimeData();
+ qCDebug(lcTests) << "mime types available" << md->formats();
+ qCDebug(lcTests) << "HTML" << md->html();
+ // QTextDocumentFragment::toHtml() is subject to change, so we don't QCOMPARE this verbose HTML
+ QVERIFY(md->html().toLatin1().startsWith('<'));
+}
+#endif
+
+void tst_qquicktextedit::touchscreenDoesNotSelect_data()
+{
+ QTest::addColumn<QUrl>("src");
+ QTest::addColumn<bool>("mouseOnly");
+ QTest::newRow("new") << testFileUrl("mouseselectionmode_default.qml") << true;
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ QTest::newRow("old") << testFileUrl("mouseselection_old_default.qml") << false;
+#endif
+}
+
+void tst_qquicktextedit::touchscreenDoesNotSelect()
+{
+ QFETCH(QUrl, src);
+ QFETCH(bool, mouseOnly);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, src));
+
+ QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(window.rootObject());
+ QVERIFY(textEditObject != nullptr);
+ QCOMPARE(textEditObject->selectByMouse(), mouseOnly);
+ textEditObject->setSelectByMouse(true); // enable selection with pre-6.4 import version
+
+ // press-drag-and-release from x1 to x2
+ int x1 = 10;
+ int x2 = 70;
+ int y = QFontMetrics(textEditObject->font()).height() / 2;
+ QTest::touchEvent(&window, touchDevice).press(0, QPoint(x1,y), &window);
+ QTest::touchEvent(&window, touchDevice).move(0, QPoint(x2,y), &window);
+ QTest::touchEvent(&window, touchDevice).release(0, QPoint(x2,y), &window);
+ QQuickTouchUtils::flush(&window);
+ // if the import version is old enough, fall back to old behavior: touch swipe _does_ select text
+ QCOMPARE(textEditObject->selectedText().isEmpty(), mouseOnly);
+}
+
+void tst_qquicktextedit::touchscreenSetsFocusAndMovesCursor()
+{
+ if (!hasWindowActivation())
+ QSKIP("Window activation is not supported");
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("twoInAColumn.qml")));
+ window.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+
+ QQuickTextEdit *top = window.rootObject()->findChild<QQuickTextEdit*>("top");
+ QVERIFY(top);
+ QQuickTextEdit *bottom = window.rootObject()->findChild<QQuickTextEdit*>("bottom");
+ QVERIFY(bottom);
+ const auto len = bottom->text().size();
+
+ // tap the bottom field
+ QPoint p1 = bottom->mapToScene({6, 6}).toPoint();
+ QTest::touchEvent(&window, touchDevice).press(0, p1, &window);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(qApp->focusObject(), bottom);
+ // text cursor is at 0 by default, on press
+ QCOMPARE(bottom->cursorPosition(), 0);
+ // so typing a character prepends it
+ QVERIFY(!bottom->text().startsWith('q'));
+ QTest::keyClick(&window, Qt::Key_Q);
+ QVERIFY(bottom->text().startsWith('q'));
+ QCOMPARE(bottom->text().size(), len + 1);
+ QTest::touchEvent(&window, touchDevice).release(0, p1, &window);
+ QQuickTouchUtils::flush(&window);
+ // the cursor gets moved on release, as long as TextInput's grab wasn't stolen (e.g. by Flickable)
+ QVERIFY(bottom->cursorPosition() < 5);
+
+ // press-drag-and-release from p1 to p2 on the top field
+ p1 = top->mapToScene({6, 6}).toPoint();
+ QPoint p2 = top->mapToScene({76, 6}).toPoint();
+ QTest::touchEvent(&window, touchDevice).press(0, p1, &window);
+ QTest::touchEvent(&window, touchDevice).move(0, p2, &window);
+ QTest::touchEvent(&window, touchDevice).release(0, p2, &window);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(qApp->focusObject(), top);
+ QVERIFY(top->selectedText().isEmpty());
+}
+
+void tst_qquicktextedit::longPressInputMethod() // QTBUG-115004
+{
+ QQuickView window;
+ window.setMinimumWidth(200);
+ window.setMinimumHeight(100);
+ QVERIFY(QQuickTest::showView(window, testFileUrl("positionAt.qml")));
+ QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(window.rootObject());
+ QVERIFY(edit);
+
+ // Realistically there are touch events. But QQuickTextEdit doesn't handle them yet;
+ // so we only test the synth-mouse events for now.
+ QPoint pos = edit->positionToRectangle(20).center().toPoint(); // in the word "pi|ece"
+ QTest::mousePress(&window, Qt::LeftButton, {}, pos);
+
+ // Simulate input method events as seen on Android during long-press
+ {
+ QInputMethodEvent imEvent({}, QList<QInputMethodEvent::Attribute>()
+ << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 20, 0, {}));
+ QCoreApplication::sendEvent(edit, &imEvent);
+ }
+ {
+ QInputMethodEvent imEvent({}, QList<QInputMethodEvent::Attribute>()
+ << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, 0, 0, {})
+ << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 13, -5, {}));
+ QCoreApplication::sendEvent(edit, &imEvent);
+ }
+
+ // Release later => long press
+ QTest::mouseRelease(&window, Qt::LeftButton, {}, pos, 1500);
+
+ QTRY_COMPARE(edit->selectedText(), "piece");
+}
+
+void tst_qquicktextedit::rtlAlignmentInColumnLayout_QTBUG_112858()
+{
+ QQuickView window(testFileUrl("qtbug-112858.qml"));
+ QVERIFY(window.rootObject() != nullptr);
+
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ QQuickTextEdit *edit = window.rootObject()->findChild<QQuickTextEdit *>();
+ QVERIFY(edit != nullptr);
+
+ const auto text = edit->text();
+ const auto lines = text.split("\n");
+ QCOMPARE(lines.size(), edit->lineCount());
+
+ int currentLineStartPos = 0;
+ QRectF firstLineStartPosRect;
+
+ // check that all lines are aligned, for RTL text it means that they have the same pos at the right
+ for (int i = 0; i < lines.size(); ++i) {
+ const auto lineStartPosRect = edit->positionToRectangle(currentLineStartPos);
+ QVERIFY(lineStartPosRect.isValid());
+
+ if (i == 0)
+ firstLineStartPosRect = lineStartPosRect;
+ else
+ QCOMPARE(lineStartPosRect.right(), firstLineStartPosRect.right());
+
+ currentLineStartPos += lines.at(i).size() + 1;
+ }
+}
+
+void tst_qquicktextedit::fontManipulationWithCursorSelection()
+{
+ QString testStr = standard[0];//TODO: What should happen for multiline/rich text?
+ QString componentStr = "import QtQuick 2.0\nTextEdit { text: \""+ testStr +"\"; }";
+ QQmlComponent texteditComponent(&engine);
+ texteditComponent.setData(componentStr.toLatin1(), QUrl());
+ QQuickTextEdit *textEditObject = qobject_cast<QQuickTextEdit *>(texteditComponent.create());
+ QVERIFY(textEditObject != nullptr);
+
+ const int originalStartPos = 0;
+ const int originalEndPos = (testStr.size() - 1) / 2;
+
+ textEditObject->select(originalStartPos, originalEndPos);
+ QCOMPARE(textEditObject->selectionStart(), originalStartPos);
+ QCOMPARE(textEditObject->selectionEnd(), originalEndPos);
+
+ QCOMPARE(textEditObject->cursorSelection()->text(), textEditObject->text().mid(originalStartPos, originalEndPos));
+
+ // test font manipulation
+ QFont font = textEditObject->cursorSelection()->font();
+ QVERIFY(!font.bold());
+ font.setBold(true);
+ textEditObject->cursorSelection()->setFont(font);
+ QVERIFY(textEditObject->cursorSelection()->font().bold());
+
+ // test color manipulation
+ QCOMPARE_NE(textEditObject->cursorSelection()->color(), QColorConstants::Cyan);
+ textEditObject->cursorSelection()->setColor(QColorConstants::Cyan);
+ QCOMPARE(textEditObject->cursorSelection()->color(), QColorConstants::Cyan);
+
+ // test alignment
+ QCOMPARE(textEditObject->cursorSelection()->alignment(), Qt::AlignLeft);
+ textEditObject->cursorSelection()->setAlignment(Qt::AlignRight);
+ QCOMPARE(textEditObject->cursorSelection()->alignment(), Qt::AlignRight);
+
+ // change seleciton and verify that we don't keep the same formatting
+ const int newStartPos = testStr.size() / 2;
+ const int newEndPos = testStr.size() - 1;
+
+ textEditObject->select(newStartPos, newEndPos);
+ QCOMPARE(textEditObject->selectionStart(), newStartPos);
+ QCOMPARE(textEditObject->selectionEnd(), newEndPos);
+ QVERIFY(!textEditObject->cursorSelection()->font().bold());
+ QCOMPARE_NE(textEditObject->cursorSelection()->color(), QColorConstants::Cyan);
+ QEXPECT_FAIL("", "The text alignment doesn't update when changing selection", Continue);
+ QCOMPARE(textEditObject->cursorSelection()->alignment(), Qt::AlignLeft);
+
+ // change back to the previous fragment, and verify that we have the old formatting
+ textEditObject->select(originalStartPos, originalEndPos);
+ QVERIFY(font.bold());
+ QCOMPARE(textEditObject->cursorSelection()->color(), QColorConstants::Cyan);
+ QCOMPARE(textEditObject->cursorSelection()->alignment(), Qt::AlignRight);
+
+ // test text manipulation
+ textEditObject->cursorSelection()->setText("Q");
+ QEXPECT_FAIL("", "QQuickTextSelection::text doesn't currently work correctly", Continue);
+ QCOMPARE(textEditObject->text(), QLatin1String("Q%1").arg(testStr.mid(newStartPos, newEndPos)));
+
+ // Make sure that QQuickTextEdit::setFont() affects all blocks
+ font.setItalic(true);
+ font.setWeight(QFont::Black);
+ textEditObject->setFont(font);
+ const auto *doc = textEditObject->textDocument()->textDocument();
+ for (QTextBlock block = doc->begin(); block != doc->end(); block = block.next())
+ QCOMPARE(block.charFormat().font(), font);
+}
+
+void tst_qquicktextedit::resizeTextEditPolish()
+{
+ QQuickView window(testFileUrl("resizeTextEditPolish.qml"));
+ QVERIFY(window.rootObject() != nullptr);
+
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+
+ auto *edit = window.rootObject()->findChild<QQuickTextEdit *>();
+ QVERIFY(edit != nullptr);
+ QCOMPARE(edit->lineCount(), 1);
+
+ QSignalSpy spy(edit, SIGNAL(lineCountChanged()));
+
+ // Resize item and check for item polished
+ auto *item = edit->parentItem();
+ item->setWidth(item->width() - (item->width() / 2));
+
+ QVERIFY(QQuickTest::qIsPolishScheduled(edit));
+ QVERIFY(QQuickTest::qWaitForPolish(edit));
+
+ QTRY_COMPARE(spy.size(), 1);
+ QVERIFY(edit->lineCount() > 1);
+ QCOMPARE(edit->state(), QString("multi-line"));
+ auto *editPriv = QQuickTextEditPrivate::get(edit);
+ QCOMPARE(editPriv->xoff, 0);
+ QCOMPARE(editPriv->yoff, 0);
+}
+
+QT_END_NAMESPACE
+
QTEST_MAIN(tst_qquicktextedit)
#include "tst_qquicktextedit.moc"
diff --git a/tests/auto/quick/qquicktextinput/BLACKLIST b/tests/auto/quick/qquicktextinput/BLACKLIST
index 7f3128d7fc..2af586c68a 100644
--- a/tests/auto/quick/qquicktextinput/BLACKLIST
+++ b/tests/auto/quick/qquicktextinput/BLACKLIST
@@ -9,3 +9,7 @@ macos ci
# QTQAINFRA-4127
[passwordCharacter]
ci b2qt 32bit
+
+# QTBUG-103256
+[copyAndPasteKeySequence]
+android
diff --git a/tests/auto/quick/qquicktextinput/CMakeLists.txt b/tests/auto/quick/qquicktextinput/CMakeLists.txt
index 6e8d855a58..70003a63b8 100644
--- a/tests/auto/quick/qquicktextinput/CMakeLists.txt
+++ b/tests/auto/quick/qquicktextinput/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquicktextinput.pro.
#####################################################################
## tst_qquicktextinput Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicktextinput LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,17 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquicktextinput
SOURCES
- ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h
- ../../shared/util.cpp ../../shared/util.h
tst_qquicktextinput.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -30,16 +36,16 @@ qt_internal_add_test(tst_qquicktextinput
#####################################################################
qt_internal_extend_target(tst_qquicktextinput CONDITION MACOS
- PUBLIC_LIBRARIES
+ LIBRARIES
${FWAppKit}
)
qt_internal_extend_target(tst_qquicktextinput CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquicktextinput CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquicktextinput/data/checkCursorDelegateWhenPaddingChanged.qml b/tests/auto/quick/qquicktextinput/data/checkCursorDelegateWhenPaddingChanged.qml
new file mode 100644
index 0000000000..e6f07b4687
--- /dev/null
+++ b/tests/auto/quick/qquicktextinput/data/checkCursorDelegateWhenPaddingChanged.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.12
+
+Rectangle {
+ width: 200
+ height: 200
+ TextInput {
+ objectName: "textInput"
+ leftPadding: 10
+ focus: true
+ cursorDelegate: Rectangle {
+ objectName: "cursorDelegate"
+ width: 5
+ color: "red"
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktextinput/data/cursorTest.qml b/tests/auto/quick/qquicktextinput/data/cursorTest.qml
index 363d37174b..44e81f9522 100644
--- a/tests/auto/quick/qquicktextinput/data/cursorTest.qml
+++ b/tests/auto/quick/qquicktextinput/data/cursorTest.qml
@@ -2,7 +2,7 @@ import QtQuick 2.0
Rectangle { id:rect; width: 300; height: 300; color: "white"
property string contextualProperty: "Hello"
- TextInput { text: "Hello world!"; id: textInputObject; objectName: "textInputObject"
+ TextInput { text: "Hello my wonderful world!"; id: textInputObject; objectName: "textInputObject"
width: 300; height: 300
resources: [ Component { id:cursor; Item { id:cursorInstance; objectName: "cursorInstance"; property string localProperty: contextualProperty } } ]
cursorDelegate: cursor
diff --git a/tests/auto/quick/qquicktextinput/data/cursorTestExternal.qml b/tests/auto/quick/qquicktextinput/data/cursorTestExternal.qml
index 31ee01db99..1e2c91e9cc 100644
--- a/tests/auto/quick/qquicktextinput/data/cursorTestExternal.qml
+++ b/tests/auto/quick/qquicktextinput/data/cursorTestExternal.qml
@@ -3,7 +3,7 @@ import QtQuick 2.0
Rectangle { width: 300; height: 300; color: "white"
property string contextualProperty: "Hello"
TextInput {
- text: "Hello world!"
+ text: "Hello my wonderful world!"
id: textInputObject;
objectName: "textInputObject"
width: 300; height: 300
diff --git a/tests/auto/quick/qquicktextinput/data/cursorTestInline.qml b/tests/auto/quick/qquicktextinput/data/cursorTestInline.qml
index b699ed2752..b7ad69962e 100644
--- a/tests/auto/quick/qquicktextinput/data/cursorTestInline.qml
+++ b/tests/auto/quick/qquicktextinput/data/cursorTestInline.qml
@@ -3,7 +3,7 @@ import QtQuick 2.0
Rectangle { width: 300; height: 300; color: "white"
property string contextualProperty: "Hello"
TextInput {
- text: "Hello world!"
+ text: "Hello my wonderful world!"
id: textInputObject
objectName: "textInputObject"
width: 300; height: 300
diff --git a/tests/auto/quick/qquicktextinput/data/focusReason.qml b/tests/auto/quick/qquicktextinput/data/focusReason.qml
new file mode 100644
index 0000000000..7ac913d363
--- /dev/null
+++ b/tests/auto/quick/qquicktextinput/data/focusReason.qml
@@ -0,0 +1,39 @@
+import QtQuick 2.2
+
+Rectangle {
+ width: 400
+ height: 400
+
+ Column {
+ spacing: 5
+ TextInput {
+ id: first
+ objectName: "first"
+ width: 100
+ Rectangle { anchors.fill: parent; color: parent.activeFocus ? "red" : "blue"; opacity: 0.3 }
+ KeyNavigation.backtab: third
+ KeyNavigation.tab: second
+ KeyNavigation.down: second
+ }
+ TextInput {
+ id: second
+ objectName: "second"
+ width: 100
+ Rectangle { anchors.fill: parent; color: parent.activeFocus ? "red" : "blue"; opacity: 0.3 }
+ KeyNavigation.up: first
+ KeyNavigation.backtab: first
+ KeyNavigation.tab: third
+ }
+ TextInput {
+ objectName: "third"
+ id: third
+ width: 100
+ Rectangle { anchors.fill: parent; color: parent.activeFocus ? "red" : "blue"; opacity: 0.3 }
+ KeyNavigation.backtab: second
+ KeyNavigation.tab: first
+ }
+ Component.onCompleted: {
+ first.focus = true
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicktextinput/data/mouseselection_true.qml b/tests/auto/quick/qquicktextinput/data/mouseselection_old_default.qml
index 974041b04a..42ab4931ea 100644
--- a/tests/auto/quick/qquicktextinput/data/mouseselection_true.qml
+++ b/tests/auto/quick/qquicktextinput/data/mouseselection_old_default.qml
@@ -3,5 +3,4 @@ import QtQuick 2.0
TextInput {
focus: true
text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- selectByMouse: true
}
diff --git a/tests/auto/quick/qquicktextinput/data/mouseselectionmode_default.qml b/tests/auto/quick/qquicktextinput/data/mouseselectionmode_default.qml
index 974041b04a..ad19fa8c2a 100644
--- a/tests/auto/quick/qquicktextinput/data/mouseselectionmode_default.qml
+++ b/tests/auto/quick/qquicktextinput/data/mouseselectionmode_default.qml
@@ -1,7 +1,6 @@
-import QtQuick 2.0
+import QtQuick
TextInput {
focus: true
text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- selectByMouse: true
}
diff --git a/tests/auto/quick/qquicktextinput/data/twoInAColumn.qml b/tests/auto/quick/qquicktextinput/data/twoInAColumn.qml
new file mode 100644
index 0000000000..dbc70afe4b
--- /dev/null
+++ b/tests/auto/quick/qquicktextinput/data/twoInAColumn.qml
@@ -0,0 +1,14 @@
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ height: 100
+ TextInput {
+ objectName: "top"
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ }
+ TextInput {
+ objectName: "bottom"
+ text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ }
+}
diff --git a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
index d0e5425c0f..b7e689e147 100644
--- a/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/quick/qquicktextinput/tst_qquicktextinput.cpp
@@ -1,42 +1,22 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
#include <qtest.h>
#include <QtTest/QSignalSpy>
-#include "../../shared/util.h"
-#include "../../shared/testhttpserver.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/testhttpserver_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
#include <private/qinputmethod_p.h>
#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlexpression.h>
#include <QFile>
#include <QtQuick/qquickview.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qstylehints.h>
#include <QtGui/qvalidator.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qpointingdevice_p.h>
#include <QInputMethod>
#include <private/qquicktextinput_p.h>
#include <private/qquicktextinput_p_p.h>
@@ -46,13 +26,9 @@
#include <math.h>
#include <qmath.h>
-#ifdef Q_OS_OSX
-#include <Carbon/Carbon.h>
-#endif
-
#include "qplatformdefs.h"
-#include "../../shared/platformquirks.h"
-#include "../../shared/platforminputcontext.h"
+#include <QtQuickTestUtils/private/platformquirks_p.h>
+#include <QtQuickTestUtils/private/platforminputcontext_p.h>
Q_DECLARE_METATYPE(QQuickTextInput::SelectionMode)
Q_DECLARE_METATYPE(QQuickTextInput::EchoMode)
@@ -60,22 +36,6 @@ Q_DECLARE_METATYPE(Qt::Key)
DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
-QString createExpectedFileIfNotFound(const QString& filebasename, const QImage& actual)
-{
- // XXX This will be replaced by some clever persistent platform image store.
- QString persistent_dir = QQmlDataTest::instance()->dataDirectory();
- QString arch = "unknown-architecture"; // QTest needs to help with this.
-
- QString expectfile = persistent_dir + QDir::separator() + filebasename + QLatin1Char('-') + arch + ".png";
-
- if (!QFile::exists(expectfile)) {
- actual.save(expectfile);
- qWarning() << "created" << expectfile;
- }
-
- return expectfile;
-}
-
template <typename T> static T evaluate(QObject *scope, const QString &expression)
{
QQmlExpression expr(qmlContext(scope), scope, expression);
@@ -135,6 +95,8 @@ private slots:
void validators();
void inputMethods();
+ void inputMethodQueryEnterKeyType();
+
void signal_accepted();
void signal_editingfinished();
void signal_textEdited();
@@ -238,15 +200,25 @@ private slots:
void QTBUG_51115_readOnlyResetsSelection();
void QTBUG_77814_InsertRemoveNoSelection();
+ void checkCursorDelegateWhenPaddingChanged();
+
+ void focusReason();
+
+ void touchscreenDoesNotSelect_data();
+ void touchscreenDoesNotSelect();
+ void touchscreenSetsFocusAndMovesCursor();
+
private:
void simulateKeys(QWindow *window, const QList<Key> &keys);
#if QT_CONFIG(shortcut)
void simulateKeys(QWindow *window, const QKeySequence &sequence);
#endif
+ static bool hasWindowActivation();
QQmlEngine engine;
QStringList standard;
QStringList colorStrings;
+ QScopedPointer<QPointingDevice> touchscreen = QScopedPointer<QPointingDevice>(QTest::createTouchDevice());
};
typedef QList<int> IntList;
@@ -257,7 +229,7 @@ Q_DECLARE_METATYPE(KeyList)
void tst_qquicktextinput::simulateKeys(QWindow *window, const QList<Key> &keys)
{
- for (int i = 0; i < keys.count(); ++i) {
+ for (int i = 0; i < keys.size(); ++i) {
const Qt::KeyboardModifiers modifiers = keys.at(i).keyCombination.keyboardModifiers();
const QChar character = keys.at(i).character;
if (!character.isNull())
@@ -267,6 +239,11 @@ void tst_qquicktextinput::simulateKeys(QWindow *window, const QList<Key> &keys)
}
}
+bool tst_qquicktextinput::hasWindowActivation()
+{
+ return (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation));
+}
+
#if QT_CONFIG(shortcut)
void tst_qquicktextinput::simulateKeys(QWindow *window, const QKeySequence &sequence)
@@ -299,6 +276,7 @@ void tst_qquicktextinput::cleanup()
}
tst_qquicktextinput::tst_qquicktextinput()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
standard << "the quick brown fox jumped over the lazy dog"
<< "It's supercalifragisiticexpialidocious!"
@@ -343,7 +321,7 @@ void tst_qquicktextinput::text()
QVERIFY(textinputObject != nullptr);
QCOMPARE(textinputObject->text(), standard.at(i));
- QCOMPARE(textinputObject->length(), standard.at(i).length());
+ QCOMPARE(textinputObject->length(), standard.at(i).size());
delete textinputObject;
}
@@ -495,36 +473,36 @@ void tst_qquicktextinput::color()
textInputObject->setColor(QColor("white"));
QCOMPARE(textInputObject->color(), QColor("white"));
- QCOMPARE(colorSpy.count(), 1);
+ QCOMPARE(colorSpy.size(), 1);
textInputObject->setSelectionColor(QColor("black"));
QCOMPARE(textInputObject->selectionColor(), QColor("black"));
- QCOMPARE(selectionColorSpy.count(), 1);
+ QCOMPARE(selectionColorSpy.size(), 1);
textInputObject->setSelectedTextColor(QColor("blue"));
QCOMPARE(textInputObject->selectedTextColor(), QColor("blue"));
- QCOMPARE(selectedTextColorSpy.count(), 1);
+ QCOMPARE(selectedTextColorSpy.size(), 1);
textInputObject->setColor(QColor("white"));
- QCOMPARE(colorSpy.count(), 1);
+ QCOMPARE(colorSpy.size(), 1);
textInputObject->setSelectionColor(QColor("black"));
- QCOMPARE(selectionColorSpy.count(), 1);
+ QCOMPARE(selectionColorSpy.size(), 1);
textInputObject->setSelectedTextColor(QColor("blue"));
- QCOMPARE(selectedTextColorSpy.count(), 1);
+ QCOMPARE(selectedTextColorSpy.size(), 1);
textInputObject->setColor(QColor("black"));
QCOMPARE(textInputObject->color(), QColor("black"));
- QCOMPARE(colorSpy.count(), 2);
+ QCOMPARE(colorSpy.size(), 2);
textInputObject->setSelectionColor(QColor("blue"));
QCOMPARE(textInputObject->selectionColor(), QColor("blue"));
- QCOMPARE(selectionColorSpy.count(), 2);
+ QCOMPARE(selectionColorSpy.size(), 2);
textInputObject->setSelectedTextColor(QColor("white"));
QCOMPARE(textInputObject->selectedTextColor(), QColor("white"));
- QCOMPARE(selectedTextColorSpy.count(), 2);
+ QCOMPARE(selectedTextColorSpy.size(), 2);
}
//test color
@@ -600,7 +578,7 @@ void tst_qquicktextinput::wrap()
delete textObject;
}
- for (int i = 0; i < standard.count(); i++) {
+ for (int i = 0; i < standard.size(); i++) {
QString componentStr = "import QtQuick 2.0\nTextInput { wrapMode: Text.WrapAnywhere; width: 30; text: \"" + standard.at(i) + "\" }";
QQmlComponent textComponent(&engine);
textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
@@ -630,14 +608,14 @@ void tst_qquicktextinput::wrap()
input->setWrapMode(QQuickTextInput::Wrap);
QCOMPARE(input->wrapMode(), QQuickTextInput::Wrap);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
input->setWrapMode(QQuickTextInput::Wrap);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
input->setWrapMode(QQuickTextInput::NoWrap);
QCOMPARE(input->wrapMode(), QQuickTextInput::NoWrap);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
}
@@ -673,7 +651,7 @@ void tst_qquicktextinput::selection()
QCOMPARE(textinputObject->selectionEnd(), 0);
QVERIFY(textinputObject->selectedText().isNull());
- textinputObject->setCursorPosition(textinputObject->text().count()+1);
+ textinputObject->setCursorPosition(textinputObject->text().size() + 1);
QCOMPARE(textinputObject->cursorPosition(), 0);
QCOMPARE(textinputObject->selectionStart(), 0);
QCOMPARE(textinputObject->selectionEnd(), 0);
@@ -733,7 +711,7 @@ void tst_qquicktextinput::selection()
QInputMethodEvent event("", attributes);
QGuiApplication::sendEvent(textinputObject, &event);
}
- QCOMPARE(selectionSpy.count(), 1);
+ QCOMPARE(selectionSpy.size(), 1);
QCOMPARE(textinputObject->selectionStart(), 12);
QCOMPARE(textinputObject->selectionEnd(), 17);
@@ -757,7 +735,7 @@ void tst_qquicktextinput::persistentSelection()
input->setPersistentSelection(false);
QCOMPARE(input->persistentSelection(), false);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
input->select(1, 4);
QCOMPARE(input->property("selected").toString(), QLatin1String("ell"));
@@ -770,7 +748,7 @@ void tst_qquicktextinput::persistentSelection()
input->setPersistentSelection(true);
QCOMPARE(input->persistentSelection(), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
input->select(1, 4);
QCOMPARE(input->property("selected").toString(), QLatin1String("ell"));
@@ -801,25 +779,25 @@ void tst_qquicktextinput::overwriteMode()
QVERIFY(textInput->hasActiveFocus());
textInput->setOverwriteMode(true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(true, textInput->overwriteMode());
textInput->setOverwriteMode(false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
QCOMPARE(false, textInput->overwriteMode());
QVERIFY(!textInput->overwriteMode());
QString insertString = "Some first text";
- for (int j = 0; j < insertString.length(); j++)
+ for (int j = 0; j < insertString.size(); j++)
QTest::keyClick(&window, insertString.at(j).toLatin1());
QCOMPARE(textInput->text(), QString("Some first text"));
textInput->setOverwriteMode(true);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
textInput->setCursorPosition(5);
insertString = "shiny";
- for (int j = 0; j < insertString.length(); j++)
+ for (int j = 0; j < insertString.size(); j++)
QTest::keyClick(&window, insertString.at(j).toLatin1());
QCOMPARE(textInput->text(), QString("Some shiny text"));
}
@@ -861,24 +839,24 @@ void tst_qquicktextinput::isRightToLeft()
// first test that the right string is delivered to the QString::isRightToLeft()
QCOMPARE(textInput.isRightToLeft(0,0), text.mid(0,0).isRightToLeft());
QCOMPARE(textInput.isRightToLeft(0,1), text.mid(0,1).isRightToLeft());
- QCOMPARE(textInput.isRightToLeft(text.count()-2, text.count()-1), text.mid(text.count()-2, text.count()-1).isRightToLeft());
- QCOMPARE(textInput.isRightToLeft(text.count()/2, text.count()/2 + 1), text.mid(text.count()/2, text.count()/2 + 1).isRightToLeft());
- QCOMPARE(textInput.isRightToLeft(0,text.count()/4), text.mid(0,text.count()/4).isRightToLeft());
- QCOMPARE(textInput.isRightToLeft(text.count()/4,3*text.count()/4), text.mid(text.count()/4,3*text.count()/4).isRightToLeft());
+ QCOMPARE(textInput.isRightToLeft(text.size()-2, text.size()-1), text.mid(text.size()-2, text.size()-1).isRightToLeft());
+ QCOMPARE(textInput.isRightToLeft(text.size()/2, text.size()/2 + 1), text.mid(text.size()/2, text.size()/2 + 1).isRightToLeft());
+ QCOMPARE(textInput.isRightToLeft(0,text.size()/4), text.mid(0,text.size()/4).isRightToLeft());
+ QCOMPARE(textInput.isRightToLeft(text.size()/4,3*text.size()/4), text.mid(text.size()/4,3*text.size()/4).isRightToLeft());
if (text.isEmpty())
QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextInput: isRightToLeft(start, end) called with the end property being smaller than the start.");
- QCOMPARE(textInput.isRightToLeft(3*text.count()/4,text.count()-1), text.mid(3*text.count()/4,text.count()-1).isRightToLeft());
+ QCOMPARE(textInput.isRightToLeft(3*text.size()/4,text.size()-1), text.mid(3*text.size()/4,text.size()-1).isRightToLeft());
// then test that the feature actually works
QCOMPARE(textInput.isRightToLeft(0,0), emptyString);
QCOMPARE(textInput.isRightToLeft(0,1), firstCharacter);
- QCOMPARE(textInput.isRightToLeft(text.count()-2, text.count()-1), lastCharacter);
- QCOMPARE(textInput.isRightToLeft(text.count()/2, text.count()/2 + 1), middleCharacter);
- QCOMPARE(textInput.isRightToLeft(0,text.count()/4), startString);
- QCOMPARE(textInput.isRightToLeft(text.count()/4,3*text.count()/4), midString);
+ QCOMPARE(textInput.isRightToLeft(text.size()-2, text.size()-1), lastCharacter);
+ QCOMPARE(textInput.isRightToLeft(text.size()/2, text.size()/2 + 1), middleCharacter);
+ QCOMPARE(textInput.isRightToLeft(0,text.size()/4), startString);
+ QCOMPARE(textInput.isRightToLeft(text.size()/4,3*text.size()/4), midString);
if (text.isEmpty())
QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML TextInput: isRightToLeft(start, end) called with the end property being smaller than the start.");
- QCOMPARE(textInput.isRightToLeft(3*text.count()/4,text.count()-1), endString);
+ QCOMPARE(textInput.isRightToLeft(3*text.size()/4,text.size()-1), endString);
}
void tst_qquicktextinput::moveCursorSelection_data()
@@ -1293,7 +1271,7 @@ void tst_qquicktextinput::moveCursorSelectionSequence()
void tst_qquicktextinput::dragMouseSelection()
{
- QString qmlfile = testFile("mouseselection_true.qml");
+ QString qmlfile = testFile("mouseselectionmode_default.qml");
QQuickView window(QUrl::fromLocalFile(qmlfile));
@@ -1304,6 +1282,7 @@ void tst_qquicktextinput::dragMouseSelection()
QVERIFY(window.rootObject() != nullptr);
QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput *>(window.rootObject());
QVERIFY(textInputObject != nullptr);
+ textInputObject->setSelectByMouse(true);
// press-and-drag-and-release from x1 to x2
int x1 = 10;
@@ -1313,8 +1292,8 @@ void tst_qquicktextinput::dragMouseSelection()
QTest::mouseMove(&window, QPoint(x2, y));
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x2,y));
QString str1;
- QTRY_VERIFY((str1 = textInputObject->selectedText()).length() > 3);
- QTRY_VERIFY(str1.length() > 3);
+ QTRY_VERIFY((str1 = textInputObject->selectedText()).size() > 3);
+ QTRY_VERIFY(str1.size() > 3);
// press and drag the current selection.
x1 = 40;
@@ -1323,7 +1302,7 @@ void tst_qquicktextinput::dragMouseSelection()
QTest::mouseMove(&window, QPoint(x2, y));
QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, QPoint(x2,y));
QString str2 = textInputObject->selectedText();
- QTRY_VERIFY(str2.length() > 3);
+ QTRY_VERIFY(str2.size() > 3);
QTRY_VERIFY(str1 != str2);
}
@@ -1379,7 +1358,7 @@ void tst_qquicktextinput::mouseSelectionMode()
if (selectWords) {
QTRY_COMPARE(textInputObject->selectedText(), text);
} else {
- QTRY_VERIFY(textInputObject->selectedText().length() > 3);
+ QTRY_VERIFY(textInputObject->selectedText().size() > 3);
QVERIFY(textInputObject->selectedText() != text);
}
}
@@ -1398,14 +1377,14 @@ void tst_qquicktextinput::mouseSelectionMode_accessors()
input->setMouseSelectionMode(QQuickTextInput::SelectWords);
QCOMPARE(input->mouseSelectionMode(), QQuickTextInput::SelectWords);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
input->setMouseSelectionMode(QQuickTextInput::SelectWords);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
input->setMouseSelectionMode(QQuickTextInput::SelectCharacters);
QCOMPARE(input->mouseSelectionMode(), QQuickTextInput::SelectCharacters);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
void tst_qquicktextinput::selectByMouse()
@@ -1422,15 +1401,15 @@ void tst_qquicktextinput::selectByMouse()
input->setSelectByMouse(true);
QCOMPARE(input->selectByMouse(), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
QCOMPARE(spy.at(0).at(0).toBool(), true);
input->setSelectByMouse(true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
input->setSelectByMouse(false);
QCOMPARE(input->selectByMouse(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
QCOMPARE(spy.at(1).at(0).toBool(), false);
}
@@ -1448,14 +1427,14 @@ void tst_qquicktextinput::renderType()
input->setRenderType(QQuickTextInput::NativeRendering);
QCOMPARE(input->renderType(), QQuickTextInput::NativeRendering);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
input->setRenderType(QQuickTextInput::NativeRendering);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
input->setRenderType(QQuickTextInput::QtRendering);
QCOMPARE(input->renderType(), QQuickTextInput::QtRendering);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
void tst_qquicktextinput::horizontalAlignment_RightToLeft()
@@ -1565,7 +1544,7 @@ void tst_qquicktextinput::horizontalAlignment_RightToLeft()
QSignalSpy cursorRectangleSpy(textInput, SIGNAL(cursorRectangleChanged()));
platformInputContext.setInputDirection(Qt::RightToLeft);
QCOMPARE(qApp->inputMethod()->inputDirection(), Qt::RightToLeft);
- QCOMPARE(cursorRectangleSpy.count(), 1);
+ QCOMPARE(cursorRectangleSpy.size(), 1);
QCOMPARE(textInput->hAlign(), QQuickTextInput::AlignRight);
QVERIFY(textInput->boundingRect().right() >= textInput->width() - 1);
QVERIFY(textInput->boundingRect().right() <= textInput->width() + 1);
@@ -1899,16 +1878,16 @@ void tst_qquicktextinput::maxLength()
QVERIFY(textinputObject != nullptr);
QVERIFY(textinputObject->text().isEmpty());
QCOMPARE(textinputObject->maxLength(), 10);
- foreach (const QString &str, standard) {
- QVERIFY(textinputObject->text().length() <= 10);
+ for (const QString &str : std::as_const(standard)) {
+ QVERIFY(textinputObject->text().size() <= 10);
textinputObject->setText(str);
- QVERIFY(textinputObject->text().length() <= 10);
+ QVERIFY(textinputObject->text().size() <= 10);
}
textinputObject->setText("");
QTRY_VERIFY(textinputObject->hasActiveFocus());
for (int i=0; i<20; i++) {
- QTRY_COMPARE(textinputObject->text().length(), qMin(i,10));
+ QTRY_COMPARE(textinputObject->text().size(), qMin(i,10));
QTest::keyClick(&window, Qt::Key_A);
}
}
@@ -1924,11 +1903,11 @@ void tst_qquicktextinput::masks()
QQuickTextInput *textinputObject = qobject_cast<QQuickTextInput *>(window.rootObject());
QVERIFY(textinputObject != nullptr);
QTRY_VERIFY(textinputObject->hasActiveFocus());
- QCOMPARE(textinputObject->text().length(), 0);
+ QCOMPARE(textinputObject->text().size(), 0);
QCOMPARE(textinputObject->inputMask(), QString("HHHHhhhh; "));
QCOMPARE(textinputObject->length(), 8);
for (int i=0; i<10; i++) {
- QTRY_COMPARE(qMin(i,8), textinputObject->text().length());
+ QTRY_COMPARE(qMin(i,8), textinputObject->text().size());
QCOMPARE(textinputObject->length(), 8);
QCOMPARE(textinputObject->getText(0, qMin(i, 8)), QString(qMin(i, 8), 'a'));
QCOMPARE(textinputObject->getText(qMin(i, 8), 8), QString(8 - qMin(i, 8), ' '));
@@ -1980,10 +1959,10 @@ void tst_qquicktextinput::validators()
QTRY_COMPARE(intInput->text(), QLatin1String("1"));
QCOMPARE(intInput->hasAcceptableInput(), false);
QCOMPARE(intInput->property("acceptable").toBool(), false);
- QCOMPARE(intSpy.count(), 0);
+ QCOMPARE(intSpy.size(), 0);
QCOMPARE(intInput->hasAcceptableInput(), false);
QCOMPARE(intInput->property("acceptable").toBool(), false);
- QCOMPARE(intSpy.count(), 0);
+ QCOMPARE(intSpy.size(), 0);
QTest::keyPress(&window, Qt::Key_Period);
QTest::keyRelease(&window, Qt::Key_Period, Qt::NoModifier);
QTRY_COMPARE(intInput->text(), QLatin1String("1"));
@@ -2011,13 +1990,13 @@ void tst_qquicktextinput::validators()
QCOMPARE(intInput->text(), QLatin1String("11"));
QCOMPARE(intInput->hasAcceptableInput(), true);
QCOMPARE(intInput->property("acceptable").toBool(), true);
- QCOMPARE(intSpy.count(), 1);
+ QCOMPARE(intSpy.size(), 1);
QTest::keyPress(&window, Qt::Key_0);
QTest::keyRelease(&window, Qt::Key_0, Qt::NoModifier);
QCOMPARE(intInput->text(), QLatin1String("11"));
QCOMPARE(intInput->hasAcceptableInput(), true);
QCOMPARE(intInput->property("acceptable").toBool(), true);
- QCOMPARE(intSpy.count(), 1);
+ QCOMPARE(intSpy.size(), 1);
QQuickTextInput *dblInput = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("dblInput")));
QVERIFY(dblInput);
@@ -2043,13 +2022,13 @@ void tst_qquicktextinput::validators()
QTRY_COMPARE(dblInput->text(), QLatin1String("1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 0);
+ QCOMPARE(dblSpy.size(), 0);
QTest::keyPress(&window, Qt::Key_2);
QTest::keyRelease(&window, Qt::Key_2, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
- QCOMPARE(dblSpy.count(), 1);
+ QCOMPARE(dblSpy.size(), 1);
QTest::keyPress(&window, Qt::Key_Comma);
QTest::keyRelease(&window, Qt::Key_Comma, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12,"));
@@ -2090,84 +2069,84 @@ void tst_qquicktextinput::validators()
QTRY_COMPARE(dblInput->text(), QLatin1String("12."));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
- QCOMPARE(dblSpy.count(), 1 + extraSignals);
+ QCOMPARE(dblSpy.size(), 1 + extraSignals);
QTest::keyPress(&window, Qt::Key_1);
QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.1"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
- QCOMPARE(dblSpy.count(), 1 + extraSignals);
+ QCOMPARE(dblSpy.size(), 1 + extraSignals);
QTest::keyPress(&window, Qt::Key_1);
QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
- QCOMPARE(dblSpy.count(), 1 + extraSignals);
+ QCOMPARE(dblSpy.size(), 1 + extraSignals);
QTest::keyPress(&window, Qt::Key_1);
QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), true);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
- QCOMPARE(dblSpy.count(), 1 + extraSignals);
+ QCOMPARE(dblSpy.size(), 1 + extraSignals);
// Ensure the validator doesn't prevent characters being removed.
dblInput->setValidator(intInput->validator());
QCOMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 2 + extraSignals);
+ QCOMPARE(dblSpy.size(), 2 + extraSignals);
QTest::keyPress(&window, Qt::Key_Backspace);
QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 2 + extraSignals);
+ QCOMPARE(dblSpy.size(), 2 + extraSignals);
// Once unacceptable input is in anything goes until it reaches an acceptable state again.
QTest::keyPress(&window, Qt::Key_1);
QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.11"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
- QCOMPARE(dblSpy.count(), 2 + extraSignals);
+ QCOMPARE(dblSpy.size(), 2 + extraSignals);
QTest::keyPress(&window, Qt::Key_Backspace);
QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12.1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 2 + extraSignals);
+ QCOMPARE(dblSpy.size(), 2 + extraSignals);
QTest::keyPress(&window, Qt::Key_Backspace);
QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12."));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 2 + extraSignals);
+ QCOMPARE(dblSpy.size(), 2 + extraSignals);
QTest::keyPress(&window, Qt::Key_Backspace);
QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("12"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 2 + extraSignals);
+ QCOMPARE(dblSpy.size(), 2 + extraSignals);
QTest::keyPress(&window, Qt::Key_Backspace);
QTest::keyRelease(&window, Qt::Key_Backspace, Qt::NoModifier);
QTRY_COMPARE(dblInput->text(), QLatin1String("1"));
QCOMPARE(dblInput->hasAcceptableInput(), false);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
- QCOMPARE(dblSpy.count(), 2 + extraSignals);
+ QCOMPARE(dblSpy.size(), 2 + extraSignals);
QTest::keyPress(&window, Qt::Key_1);
QTest::keyRelease(&window, Qt::Key_1, Qt::NoModifier);
QCOMPARE(dblInput->text(), QLatin1String("11"));
QCOMPARE(dblInput->property("acceptable").toBool(), true);
QCOMPARE(dblInput->hasAcceptableInput(), true);
- QCOMPARE(dblSpy.count(), 3 + extraSignals);
+ QCOMPARE(dblSpy.size(), 3 + extraSignals);
// Changing the validator properties will re-evaluate whether the input is acceptable.
intValidator->setTop(10);
QCOMPARE(dblInput->property("acceptable").toBool(), false);
QCOMPARE(dblInput->hasAcceptableInput(), false);
- QCOMPARE(dblSpy.count(), 4 + extraSignals);
+ QCOMPARE(dblSpy.size(), 4 + extraSignals);
intValidator->setTop(12);
QCOMPARE(dblInput->property("acceptable").toBool(), true);
QCOMPARE(dblInput->hasAcceptableInput(), true);
- QCOMPARE(dblSpy.count(), 5 + extraSignals);
+ QCOMPARE(dblSpy.size(), 5 + extraSignals);
QQuickTextInput *strInput = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("strInput")));
QVERIFY(strInput);
@@ -2181,37 +2160,37 @@ void tst_qquicktextinput::validators()
QTRY_COMPARE(strInput->text(), QLatin1String(""));
QCOMPARE(strInput->hasAcceptableInput(), false);
QCOMPARE(strInput->property("acceptable").toBool(), false);
- QCOMPARE(strSpy.count(), 0);
+ QCOMPARE(strSpy.size(), 0);
QTest::keyPress(&window, Qt::Key_A);
QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(strInput->text(), QLatin1String("a"));
QCOMPARE(strInput->hasAcceptableInput(), false);
QCOMPARE(strInput->property("acceptable").toBool(), false);
- QCOMPARE(strSpy.count(), 0);
+ QCOMPARE(strSpy.size(), 0);
QTest::keyPress(&window, Qt::Key_A);
QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(strInput->text(), QLatin1String("aa"));
QCOMPARE(strInput->hasAcceptableInput(), true);
QCOMPARE(strInput->property("acceptable").toBool(), true);
- QCOMPARE(strSpy.count(), 1);
+ QCOMPARE(strSpy.size(), 1);
QTest::keyPress(&window, Qt::Key_A);
QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(strInput->text(), QLatin1String("aaa"));
QCOMPARE(strInput->hasAcceptableInput(), true);
QCOMPARE(strInput->property("acceptable").toBool(), true);
- QCOMPARE(strSpy.count(), 1);
+ QCOMPARE(strSpy.size(), 1);
QTest::keyPress(&window, Qt::Key_A);
QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(strInput->text(), QLatin1String("aaaa"));
QCOMPARE(strInput->hasAcceptableInput(), true);
QCOMPARE(strInput->property("acceptable").toBool(), true);
- QCOMPARE(strSpy.count(), 1);
+ QCOMPARE(strSpy.size(), 1);
QTest::keyPress(&window, Qt::Key_A);
QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(strInput->text(), QLatin1String("aaaa"));
QCOMPARE(strInput->hasAcceptableInput(), true);
QCOMPARE(strInput->property("acceptable").toBool(), true);
- QCOMPARE(strSpy.count(), 1);
+ QCOMPARE(strSpy.size(), 1);
QQuickTextInput *unvalidatedInput = qobject_cast<QQuickTextInput *>(qvariant_cast<QObject *>(window.rootObject()->property("unvalidatedInput")));
QVERIFY(unvalidatedInput);
@@ -2225,13 +2204,13 @@ void tst_qquicktextinput::validators()
QTRY_COMPARE(unvalidatedInput->text(), QLatin1String("1"));
QCOMPARE(unvalidatedInput->hasAcceptableInput(), true);
QCOMPARE(unvalidatedInput->property("acceptable").toBool(), true);
- QCOMPARE(unvalidatedSpy.count(), 0);
+ QCOMPARE(unvalidatedSpy.size(), 0);
QTest::keyPress(&window, Qt::Key_A);
QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(unvalidatedInput->text(), QLatin1String("1a"));
QCOMPARE(unvalidatedInput->hasAcceptableInput(), true);
QCOMPARE(unvalidatedInput->property("acceptable").toBool(), true);
- QCOMPARE(unvalidatedSpy.count(), 0);
+ QCOMPARE(unvalidatedSpy.size(), 0);
}
void tst_qquicktextinput::inputMethods()
@@ -2249,9 +2228,9 @@ void tst_qquicktextinput::inputMethods()
QSignalSpy inputMethodHintSpy(input, SIGNAL(inputMethodHintsChanged()));
input->setInputMethodHints(Qt::ImhUppercaseOnly);
QVERIFY(input->inputMethodHints() & Qt::ImhUppercaseOnly);
- QCOMPARE(inputMethodHintSpy.count(), 1);
+ QCOMPARE(inputMethodHintSpy.size(), 1);
input->setInputMethodHints(Qt::ImhUppercaseOnly);
- QCOMPARE(inputMethodHintSpy.count(), 1);
+ QCOMPARE(inputMethodHintSpy.size(), 1);
// default value
QQuickTextInput plainInput;
@@ -2310,8 +2289,8 @@ void tst_qquicktextinput::inputMethods()
// input should reset selection even if replacement parameters are out of bounds
input->setText("text");
input->setCursorPosition(0);
- input->moveCursorSelection(input->text().length());
- event.setCommitString("replacement", -input->text().length(), input->text().length());
+ input->moveCursorSelection(input->text().size());
+ event.setCommitString("replacement", -input->text().size(), input->text().size());
QGuiApplication::sendEvent(input, &event);
QCOMPARE(input->selectionStart(), input->selectionEnd());
QCOMPARE(input->text(), QString("replacement"));
@@ -2326,6 +2305,36 @@ void tst_qquicktextinput::inputMethods()
QCOMPARE(enabledQueryEvent.value(Qt::ImEnabled).toBool(), false);
}
+void tst_qquicktextinput::inputMethodQueryEnterKeyType()
+{
+ QQuickView view(testFileUrl("focusReason.qml"));
+
+ QQuickTextInput *first = view.rootObject()->findChild<QQuickTextInput *>("first");
+ QQuickTextInput *second = view.rootObject()->findChild<QQuickTextInput *>("second");
+ QQuickTextInput *third = view.rootObject()->findChild<QQuickTextInput *>("third");
+ QVERIFY(first && second && third);
+
+ first->setActiveFocusOnTab(true);
+ second->setActiveFocusOnTab(true);
+ third->setActiveFocusOnTab(true);
+
+ view.show();
+
+ QVariant enterTypeFirst = first->inputMethodQuery(Qt::ImEnterKeyType);
+ QVariant enterTypeSecond = second->inputMethodQuery(Qt::ImEnterKeyType);
+ QVariant enterTypeThird = third->inputMethodQuery(Qt::ImEnterKeyType);
+#ifdef Q_OS_ANDROID
+ // QTBUG-61652
+ // EnterKey is changed to EnterKeyNext if the focus can be moved to item below
+ QCOMPARE(enterTypeFirst.value<Qt::EnterKeyType>(), Qt::EnterKeyNext);
+ QCOMPARE(enterTypeSecond.value<Qt::EnterKeyType>(), Qt::EnterKeyNext);
+#else
+ QCOMPARE(enterTypeFirst.value<Qt::EnterKeyType>(), Qt::EnterKeyDefault);
+ QCOMPARE(enterTypeSecond.value<Qt::EnterKeyType>(), Qt::EnterKeyDefault);
+#endif
+ QCOMPARE(enterTypeThird.value<Qt::EnterKeyType>(), Qt::EnterKeyDefault);
+}
+
void tst_qquicktextinput::signal_accepted()
{
QQuickView window(testFileUrl("signal_accepted.qml"));
@@ -2350,22 +2359,22 @@ void tst_qquicktextinput::signal_accepted()
QTRY_COMPARE(input->text(), QLatin1String("a"));
QCOMPARE(input->hasAcceptableInput(), false);
QCOMPARE(input->property("acceptable").toBool(), false);
- QTRY_COMPARE(inputSpy.count(), 0);
+ QTRY_COMPARE(inputSpy.size(), 0);
QTest::keyPress(&window, Qt::Key_Enter);
QTest::keyRelease(&window, Qt::Key_Enter, Qt::NoModifier);
- QTRY_COMPARE(acceptedSpy.count(), 0);
+ QTRY_COMPARE(acceptedSpy.size(), 0);
QTest::keyPress(&window, Qt::Key_A);
QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(input->text(), QLatin1String("aa"));
QCOMPARE(input->hasAcceptableInput(), true);
QCOMPARE(input->property("acceptable").toBool(), true);
- QTRY_COMPARE(inputSpy.count(), 1);
+ QTRY_COMPARE(inputSpy.size(), 1);
QTest::keyPress(&window, Qt::Key_Enter);
QTest::keyRelease(&window, Qt::Key_Enter, Qt::NoModifier);
- QTRY_COMPARE(acceptedSpy.count(), 1);
+ QTRY_COMPARE(acceptedSpy.size(), 1);
}
void tst_qquicktextinput::signal_editingfinished()
@@ -2393,23 +2402,23 @@ void tst_qquicktextinput::signal_editingfinished()
QTRY_COMPARE(input1->text(), QLatin1String("a"));
QCOMPARE(input1->hasAcceptableInput(), false);
QCOMPARE(input1->property("acceptable").toBool(), false);
- QTRY_COMPARE(input1Spy.count(), 0);
+ QTRY_COMPARE(input1Spy.size(), 0);
QTest::keyPress(&window, Qt::Key_Enter);
QTest::keyRelease(&window, Qt::Key_Enter, Qt::NoModifier);
- QTRY_COMPARE(editingFinished1Spy.count(), 0);
+ QTRY_COMPARE(editingFinished1Spy.size(), 0);
QTest::keyPress(&window, Qt::Key_A);
QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(input1->text(), QLatin1String("aa"));
QCOMPARE(input1->hasAcceptableInput(), true);
QCOMPARE(input1->property("acceptable").toBool(), true);
- QTRY_COMPARE(input1Spy.count(), 1);
+ QTRY_COMPARE(input1Spy.size(), 1);
QTest::keyPress(&window, Qt::Key_Enter);
QTest::keyRelease(&window, Qt::Key_Enter, Qt::NoModifier);
- QTRY_COMPARE(editingFinished1Spy.count(), 1);
- QTRY_COMPARE(input1Spy.count(), 1);
+ QTRY_COMPARE(editingFinished1Spy.size(), 1);
+ QTRY_COMPARE(input1Spy.size(), 1);
QSignalSpy editingFinished2Spy(input2, SIGNAL(editingFinished()));
QSignalSpy input2Spy(input2, SIGNAL(acceptableInputChanged()));
@@ -2423,19 +2432,19 @@ void tst_qquicktextinput::signal_editingfinished()
QTRY_COMPARE(input2->text(), QLatin1String("a"));
QCOMPARE(input2->hasAcceptableInput(), false);
QCOMPARE(input2->property("acceptable").toBool(), false);
- QTRY_COMPARE(input2Spy.count(), 0);
+ QTRY_COMPARE(input2Spy.size(), 0);
QTest::keyPress(&window, Qt::Key_A);
QTest::keyRelease(&window, Qt::Key_A, Qt::NoModifier);
QTRY_COMPARE(input2->text(), QLatin1String("aa"));
QCOMPARE(input2->hasAcceptableInput(), true);
QCOMPARE(input2->property("acceptable").toBool(), true);
- QTRY_COMPARE(input2Spy.count(), 1);
+ QTRY_COMPARE(input2Spy.size(), 1);
input1->setFocus(true);
QTRY_VERIFY(input1->hasActiveFocus());
QTRY_VERIFY(!input2->hasActiveFocus());
- QTRY_COMPARE(editingFinished2Spy.count(), 1);
+ QTRY_COMPARE(editingFinished2Spy.size(), 1);
}
void tst_qquicktextinput::signal_textEdited()
@@ -2461,32 +2470,32 @@ void tst_qquicktextinput::signal_textEdited()
int textEdits = 0;
QTest::keyClick(&window, Qt::Key_A);
- QCOMPARE(textChangedSpy.count(), ++textChanges);
- QCOMPARE(textEditedSpy.count(), ++textEdits);
+ QCOMPARE(textChangedSpy.size(), ++textChanges);
+ QCOMPARE(textEditedSpy.size(), ++textEdits);
QTest::keyClick(&window, Qt::Key_B);
- QCOMPARE(textChangedSpy.count(), ++textChanges);
- QCOMPARE(textEditedSpy.count(), ++textEdits);
+ QCOMPARE(textChangedSpy.size(), ++textChanges);
+ QCOMPARE(textEditedSpy.size(), ++textEdits);
QTest::keyClick(&window, Qt::Key_C);
- QCOMPARE(textChangedSpy.count(), ++textChanges);
- QCOMPARE(textEditedSpy.count(), ++textEdits);
+ QCOMPARE(textChangedSpy.size(), ++textChanges);
+ QCOMPARE(textEditedSpy.size(), ++textEdits);
QTest::keyClick(&window, Qt::Key_Space);
- QCOMPARE(textChangedSpy.count(), ++textChanges);
- QCOMPARE(textEditedSpy.count(), ++textEdits);
+ QCOMPARE(textChangedSpy.size(), ++textChanges);
+ QCOMPARE(textEditedSpy.size(), ++textEdits);
QTest::keyClick(&window, Qt::Key_Backspace);
- QCOMPARE(textChangedSpy.count(), ++textChanges);
- QCOMPARE(textEditedSpy.count(), ++textEdits);
+ QCOMPARE(textChangedSpy.size(), ++textChanges);
+ QCOMPARE(textEditedSpy.size(), ++textEdits);
input->clear();
- QCOMPARE(textChangedSpy.count(), ++textChanges);
- QCOMPARE(textEditedSpy.count(), textEdits);
+ QCOMPARE(textChangedSpy.size(), ++textChanges);
+ QCOMPARE(textEditedSpy.size(), textEdits);
input->setText("TextInput");
- QCOMPARE(textChangedSpy.count(), ++textChanges);
- QCOMPARE(textEditedSpy.count(), textEdits);
+ QCOMPARE(textChangedSpy.size(), ++textChanges);
+ QCOMPARE(textEditedSpy.size(), textEdits);
}
/*
@@ -2512,12 +2521,12 @@ void tst_qquicktextinput::navigation()
QTest::keyClick(&window, Qt::Key_Right);
QVERIFY(input->hasActiveFocus());
//QT-2944: If text is selected, ensure we deselect upon cursor motion
- input->setCursorPosition(input->text().length());
- input->select(0,input->text().length());
+ input->setCursorPosition(input->text().size());
+ input->select(0,input->text().size());
QVERIFY(input->selectionStart() != input->selectionEnd());
QTest::keyClick(&window, Qt::Key_Right);
QCOMPARE(input->selectionStart(), input->selectionEnd());
- QCOMPARE(input->selectionStart(), input->text().length());
+ QCOMPARE(input->selectionStart(), input->text().size());
QVERIFY(input->hasActiveFocus());
QTest::keyClick(&window, Qt::Key_Right);
QVERIFY(!input->hasActiveFocus());
@@ -2568,7 +2577,7 @@ void tst_qquicktextinput::navigation_RTL()
QTest::keyClick(&window, Qt::Key_Left);
QVERIFY(input->hasActiveFocus());
- input->setCursorPosition(input->text().length());
+ input->setCursorPosition(input->text().size());
QVERIFY(input->hasActiveFocus());
// move off
@@ -2593,16 +2602,16 @@ void tst_qquicktextinput::copyAndPaste()
QVERIFY(textInput != nullptr);
// copy and paste
- QCOMPARE(textInput->text().length(), 12);
- textInput->select(0, textInput->text().length());
+ QCOMPARE(textInput->text().size(), 12);
+ textInput->select(0, textInput->text().size());
textInput->copy();
QCOMPARE(textInput->selectedText(), QString("Hello world!"));
- QCOMPARE(textInput->selectedText().length(), 12);
+ QCOMPARE(textInput->selectedText().size(), 12);
textInput->setCursorPosition(0);
QTRY_VERIFY(textInput->canPaste());
textInput->paste();
QCOMPARE(textInput->text(), QString("Hello world!Hello world!"));
- QCOMPARE(textInput->text().length(), 24);
+ QCOMPARE(textInput->text().size(), 24);
// can paste
QVERIFY(textInput->canPaste());
@@ -2610,7 +2619,7 @@ void tst_qquicktextinput::copyAndPaste()
QVERIFY(!textInput->canPaste());
textInput->paste();
QCOMPARE(textInput->text(), QString("Hello world!Hello world!"));
- QCOMPARE(textInput->text().length(), 24);
+ QCOMPARE(textInput->text().size(), 24);
textInput->setReadOnly(false);
QVERIFY(textInput->canPaste());
@@ -2632,10 +2641,10 @@ void tst_qquicktextinput::copyAndPaste()
// select all and cut
textInput->selectAll();
textInput->cut();
- QCOMPARE(textInput->text().length(), 0);
+ QCOMPARE(textInput->text().size(), 0);
textInput->paste();
QCOMPARE(textInput->text(), QString("Hello world!Hello world!"));
- QCOMPARE(textInput->text().length(), 24);
+ QCOMPARE(textInput->text().size(), 24);
// Copy first word.
textInput->setCursorPosition(0);
@@ -2662,7 +2671,7 @@ void tst_qquicktextinput::copyAndPaste()
QQuickTextInput::EchoMode echoMode = QQuickTextInput::EchoMode(index);
textInput->setEchoMode(echoMode);
textInput->setText("My password");
- textInput->select(0, textInput->text().length());
+ textInput->select(0, textInput->text().size());
textInput->copy();
if (echoMode == QQuickTextInput::Normal) {
QVERIFY(!clipboard->text().isEmpty());
@@ -2698,24 +2707,24 @@ void tst_qquicktextinput::copyAndPasteKeySequence()
// copy and paste
QVERIFY(textInput->hasActiveFocus());
- QCOMPARE(textInput->text().length(), 12);
- textInput->select(0, textInput->text().length());
+ QCOMPARE(textInput->text().size(), 12);
+ textInput->select(0, textInput->text().size());
simulateKeys(&window, QKeySequence::Copy);
QCOMPARE(textInput->selectedText(), QString("Hello world!"));
- QCOMPARE(textInput->selectedText().length(), 12);
+ QCOMPARE(textInput->selectedText().size(), 12);
textInput->setCursorPosition(0);
QVERIFY(textInput->canPaste());
simulateKeys(&window, QKeySequence::Paste);
QCOMPARE(textInput->text(), QString("Hello world!Hello world!"));
- QCOMPARE(textInput->text().length(), 24);
+ QCOMPARE(textInput->text().size(), 24);
// select all and cut
simulateKeys(&window, QKeySequence::SelectAll);
simulateKeys(&window, QKeySequence::Cut);
- QCOMPARE(textInput->text().length(), 0);
+ QCOMPARE(textInput->text().size(), 0);
simulateKeys(&window, QKeySequence::Paste);
QCOMPARE(textInput->text(), QString("Hello world!Hello world!"));
- QCOMPARE(textInput->text().length(), 24);
+ QCOMPARE(textInput->text().size(), 24);
// clear copy buffer
QClipboard *clipboard = QGuiApplication::clipboard();
@@ -2730,7 +2739,7 @@ void tst_qquicktextinput::copyAndPasteKeySequence()
QQuickTextInput::EchoMode echoMode = QQuickTextInput::EchoMode(index);
textInput->setEchoMode(echoMode);
textInput->setText("My password");
- textInput->select(0, textInput->text().length());
+ textInput->select(0, textInput->text().size());
simulateKeys(&window, QKeySequence::Copy);
if (echoMode == QQuickTextInput::Normal) {
QVERIFY(!clipboard->text().isEmpty());
@@ -2749,15 +2758,18 @@ void tst_qquicktextinput::copyAndPasteKeySequence()
#if QT_CONFIG(clipboard) && QT_CONFIG(shortcut)
void tst_qquicktextinput::canPasteEmpty()
{
+ if (!PlatformQuirks::isClipboardAvailable())
+ QSKIP("This machine has no clipboard support.");
+
QGuiApplication::clipboard()->clear();
- QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\" }";
+ const QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\" }";
QQmlComponent textInputComponent(&engine);
textInputComponent.setData(componentStr.toLatin1(), QUrl());
QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create());
QVERIFY(textInput != nullptr);
- bool cp = !textInput->isReadOnly() && QGuiApplication::clipboard()->text().length() != 0;
+ const bool cp = !textInput->isReadOnly() && QGuiApplication::clipboard()->text().size() != 0;
QCOMPARE(textInput->canPaste(), cp);
}
#endif
@@ -2765,15 +2777,18 @@ void tst_qquicktextinput::canPasteEmpty()
#if QT_CONFIG(clipboard) && QT_CONFIG(shortcut)
void tst_qquicktextinput::canPaste()
{
+ if (!PlatformQuirks::isClipboardAvailable())
+ QSKIP("This machine has no clipboard support.");
+
QGuiApplication::clipboard()->setText("Some text");
- QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\" }";
+ const QString componentStr = "import QtQuick 2.0\nTextInput { text: \"Hello world!\" }";
QQmlComponent textInputComponent(&engine);
textInputComponent.setData(componentStr.toLatin1(), QUrl());
QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create());
QVERIFY(textInput != nullptr);
- bool cp = !textInput->isReadOnly() && QGuiApplication::clipboard()->text().length() != 0;
+ const bool cp = !textInput->isReadOnly() && QGuiApplication::clipboard()->text().size() != 0;
QCOMPARE(textInput->canPaste(), cp);
}
#endif
@@ -2782,9 +2797,9 @@ void tst_qquicktextinput::canPaste()
void tst_qquicktextinput::middleClickPaste()
{
if (!PlatformQuirks::isClipboardAvailable())
- QSKIP("This machine doesn't support the clipboard");
+ QSKIP("This machine has no clipboard support.");
- QQuickView window(testFileUrl("mouseselection_true.qml"));
+ QQuickView window(testFileUrl("mouseselectionmode_default.qml"));
window.show();
window.requestActivate();
@@ -2793,11 +2808,12 @@ void tst_qquicktextinput::middleClickPaste()
QVERIFY(window.rootObject() != nullptr);
QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput *>(window.rootObject());
QVERIFY(textInputObject != nullptr);
+ textInputObject->setSelectByMouse(true);
textInputObject->setFocus(true);
- QString originalText = textInputObject->text();
- QString selectedText = "234567";
+ const QString originalText = textInputObject->text();
+ const QString selectedText = "234567";
// press-and-drag-and-release from x1 to x2
const QPoint p1 = textInputObject->positionToRectangle(2).center().toPoint();
@@ -2815,7 +2831,7 @@ void tst_qquicktextinput::middleClickPaste()
QTest::qWait(QGuiApplication::styleHints()->mouseDoubleClickInterval() + 10);
if (QGuiApplication::clipboard()->supportsSelection())
- QCOMPARE(textInputObject->text().mid(1, selectedText.length()), selectedText);
+ QCOMPARE(textInputObject->text().mid(1, selectedText.size()), selectedText);
else
QCOMPARE(textInputObject->text(), originalText);
}
@@ -2867,7 +2883,7 @@ void tst_qquicktextinput::cursorDelegate()
QVERIFY(delegateObject);
QCOMPARE(delegateObject->property("localProperty").toString(), QString("Hello"));
//Test Delegate gets moved
- for (int i=0; i<= textInputObject->text().length(); i++) {
+ for (int i=0; i<= textInputObject->text().size(); i++) {
textInputObject->setCursorPosition(i);
QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x());
QCOMPARE(textInputObject->cursorRectangle().y(), delegateObject->y());
@@ -2879,7 +2895,7 @@ void tst_qquicktextinput::cursorDelegate()
// Test delegate gets moved on mouse press.
textInputObject->setSelectByMouse(true);
textInputObject->setCursorPosition(0);
- const QPoint point1 = textInputObject->positionToRectangle(5).center().toPoint();
+ const QPoint point1 = textInputObject->positionToRectangle(10).center().toPoint();
QTest::qWait(400); //ensure this isn't treated as a double-click
QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, point1);
QTest::qWait(50);
@@ -2889,10 +2905,11 @@ void tst_qquicktextinput::cursorDelegate()
// Test delegate gets moved on mouse drag
textInputObject->setCursorPosition(0);
- const QPoint point2 = textInputObject->positionToRectangle(10).center().toPoint();
+ const QPoint point2 = textInputObject->positionToRectangle(15).center().toPoint();
QTest::qWait(400); //ensure this isn't treated as a double-click
QTest::mousePress(&view, Qt::LeftButton, Qt::NoModifier, point1);
- QMouseEvent mv(QEvent::MouseMove, point2, Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
+ QMouseEvent mv(QEvent::MouseMove, point2, textInputObject->mapToGlobal(point2),
+ Qt::LeftButton, Qt::LeftButton,Qt::NoModifier);
QGuiApplication::sendEvent(&view, &mv);
QTest::mouseRelease(&view, Qt::LeftButton, Qt::NoModifier, point2);
QTest::qWait(50);
@@ -2902,7 +2919,7 @@ void tst_qquicktextinput::cursorDelegate()
textInputObject->setReadOnly(true);
textInputObject->setCursorPosition(0);
QTest::qWait(400); //ensure this isn't treated as a double-click
- QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, textInputObject->positionToRectangle(5).center().toPoint());
+ QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, textInputObject->positionToRectangle(10).center().toPoint());
QTest::qWait(50);
QTRY_VERIFY(textInputObject->cursorPosition() != 0);
QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x());
@@ -2910,7 +2927,7 @@ void tst_qquicktextinput::cursorDelegate()
textInputObject->setCursorPosition(0);
QTest::qWait(400); //ensure this isn't treated as a double-click
- QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, textInputObject->positionToRectangle(5).center().toPoint());
+ QTest::mouseClick(&view, Qt::LeftButton, Qt::NoModifier, textInputObject->positionToRectangle(10).center().toPoint());
QTest::qWait(50);
QTRY_VERIFY(textInputObject->cursorPosition() != 0);
QCOMPARE(textInputObject->cursorRectangle().x(), delegateObject->x());
@@ -3004,27 +3021,27 @@ void tst_qquicktextinput::cursorVisible()
input.setCursorVisible(true);
QCOMPARE(input.isCursorVisible(), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
input.setCursorVisible(false);
QCOMPARE(input.isCursorVisible(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
input.setFocus(true);
QCOMPARE(input.isCursorVisible(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
input.setParentItem(view.rootObject());
QCOMPARE(input.isCursorVisible(), true);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
input.setFocus(false);
QCOMPARE(input.isCursorVisible(), false);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
input.setFocus(true);
QCOMPARE(input.isCursorVisible(), true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
QQuickView alternateView;
alternateView.show();
@@ -3032,12 +3049,12 @@ void tst_qquicktextinput::cursorVisible()
QVERIFY(QTest::qWaitForWindowActive(&alternateView));
QCOMPARE(input.isCursorVisible(), false);
- QCOMPARE(spy.count(), 6);
+ QCOMPARE(spy.size(), 6);
view.requestActivate();
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(input.isCursorVisible(), true);
- QCOMPARE(spy.count(), 7);
+ QCOMPARE(spy.size(), 7);
{ // Cursor attribute with 0 length hides cursor.
QInputMethodEvent ev(QString(), QList<QInputMethodEvent::Attribute>()
@@ -3045,7 +3062,7 @@ void tst_qquicktextinput::cursorVisible()
QCoreApplication::sendEvent(&input, &ev);
}
QCOMPARE(input.isCursorVisible(), false);
- QCOMPARE(spy.count(), 8);
+ QCOMPARE(spy.size(), 8);
{ // Cursor attribute with non zero length shows cursor.
QInputMethodEvent ev(QString(), QList<QInputMethodEvent::Attribute>()
@@ -3053,7 +3070,7 @@ void tst_qquicktextinput::cursorVisible()
QCoreApplication::sendEvent(&input, &ev);
}
QCOMPARE(input.isCursorVisible(), true);
- QCOMPARE(spy.count(), 9);
+ QCOMPARE(spy.size(), 9);
{ // If the cursor is hidden by the input method and the text is changed it should be visible again.
QInputMethodEvent ev(QString(), QList<QInputMethodEvent::Attribute>()
@@ -3061,11 +3078,11 @@ void tst_qquicktextinput::cursorVisible()
QCoreApplication::sendEvent(&input, &ev);
}
QCOMPARE(input.isCursorVisible(), false);
- QCOMPARE(spy.count(), 10);
+ QCOMPARE(spy.size(), 10);
input.setText("something");
QCOMPARE(input.isCursorVisible(), true);
- QCOMPARE(spy.count(), 11);
+ QCOMPARE(spy.size(), 11);
{ // If the cursor is hidden by the input method and the cursor position is changed it should be visible again.
QInputMethodEvent ev(QString(), QList<QInputMethodEvent::Attribute>()
@@ -3073,11 +3090,11 @@ void tst_qquicktextinput::cursorVisible()
QCoreApplication::sendEvent(&input, &ev);
}
QCOMPARE(input.isCursorVisible(), false);
- QCOMPARE(spy.count(), 12);
+ QCOMPARE(spy.size(), 12);
input.setCursorPosition(5);
QCOMPARE(input.isCursorVisible(), true);
- QCOMPARE(spy.count(), 13);
+ QCOMPARE(spy.size(), 13);
}
void tst_qquicktextinput::cursorRectangle_data()
@@ -3154,14 +3171,14 @@ void tst_qquicktextinput::cursorRectangle()
// Check the cursor rectangle remains within the input bounding rect when auto scrolling.
QCOMPARE(r.left(), leftToRight ? input.width() : 0);
- for (int i = positionAtWidth + 1; i < text.length(); ++i) {
+ for (int i = positionAtWidth + 1; i < text.size(); ++i) {
input.setCursorPosition(i);
QCOMPARE(r, input.cursorRectangle());
COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r);
QCOMPARE(input.positionToRectangle(i), r);
}
- for (int i = text.length() - 2; i >= 0; --i) {
+ for (int i = text.size() - 2; i >= 0; --i) {
input.setCursorPosition(i);
r = input.cursorRectangle();
QCOMPARE(r.top(), 0.);
@@ -3200,7 +3217,7 @@ void tst_qquicktextinput::cursorRectangle()
COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r);
QCOMPARE(input.positionToRectangle(11), r);
- for (int i = wrapPosition + 1; i < text.length(); ++i) {
+ for (int i = wrapPosition + 1; i < text.size(); ++i) {
input.setCursorPosition(i);
r = input.cursorRectangle();
QVERIFY(r.top() >= line.height() - 5);
@@ -3241,7 +3258,7 @@ void tst_qquicktextinput::cursorRectangle()
COMPARE_INPUT_METHOD_QUERY(QRectF, (&input), Qt::ImCursorRectangle, toRectF, r);
QCOMPARE(input.positionToRectangle(11), r);
- for (int i = wrapPosition + 1; i < text.length(); ++i) {
+ for (int i = wrapPosition + 1; i < text.size(); ++i) {
input.setCursorPosition(i);
r = input.cursorRectangle();
QVERIFY(r.bottom() >= input.height());
@@ -3249,7 +3266,7 @@ void tst_qquicktextinput::cursorRectangle()
QCOMPARE(input.positionToRectangle(i), r);
}
- for (int i = text.length() - 2; i >= wrapPosition; --i) {
+ for (int i = text.size() - 2; i >= wrapPosition; --i) {
input.setCursorPosition(i);
r = input.cursorRectangle();
QVERIFY(r.bottom() >= input.height());
@@ -3290,7 +3307,7 @@ void tst_qquicktextinput::cursorRectangle()
widerText[1] = 'W'; // Assumes shortText is at least two characters long.
input.setText(widerText);
- QCOMPARE(cursorRectangleSpy.count(), 1);
+ QCOMPARE(cursorRectangleSpy.size(), 1);
}
void tst_qquicktextinput::readOnly()
@@ -3318,7 +3335,7 @@ void tst_qquicktextinput::readOnly()
input->setCursorPosition(3);
input->setReadOnly(false);
QCOMPARE(input->isReadOnly(), false);
- QCOMPARE(input->cursorPosition(), input->text().length());
+ QCOMPARE(input->cursorPosition(), input->text().size());
QVERIFY(input->isCursorVisible());
}
@@ -3440,7 +3457,7 @@ void tst_qquicktextinput::passwordEchoDelay()
QSignalSpy cursorSpy(input, SIGNAL(cursorRectangleChanged()));
QTest::qWait(maskDelay);
QTRY_COMPARE(input->displayText(), QString(5, fillChar));
- QCOMPARE(cursorSpy.count(), 1);
+ QCOMPARE(cursorSpy.size(), 1);
QCOMPARE(input->cursorRectangle().topLeft(), cursor->position());
QTest::keyPress(&window, '5');
@@ -3491,7 +3508,7 @@ void tst_qquicktextinput::focusOnPress()
textInputObject->setFocusOnPress(true);
QCOMPARE(textInputObject->focusOnPress(), true);
- QCOMPARE(activeFocusOnPressSpy.count(), 0);
+ QCOMPARE(activeFocusOnPressSpy.size(), 0);
QQuickWindow window;
window.resize(100, 50);
@@ -3508,20 +3525,20 @@ void tst_qquicktextinput::focusOnPress()
QGuiApplication::processEvents();
QCOMPARE(textInputObject->hasFocus(), true);
QCOMPARE(textInputObject->hasActiveFocus(), true);
- QCOMPARE(focusSpy.count(), 1);
- QCOMPARE(activeFocusSpy.count(), 1);
+ QCOMPARE(focusSpy.size(), 1);
+ QCOMPARE(activeFocusSpy.size(), 1);
QCOMPARE(textInputObject->selectedText(), QString());
QTest::mouseRelease(&window, Qt::LeftButton, noModifiers);
textInputObject->setFocusOnPress(false);
QCOMPARE(textInputObject->focusOnPress(), false);
- QCOMPARE(activeFocusOnPressSpy.count(), 1);
+ QCOMPARE(activeFocusOnPressSpy.size(), 1);
textInputObject->setFocus(false);
QCOMPARE(textInputObject->hasFocus(), false);
QCOMPARE(textInputObject->hasActiveFocus(), false);
- QCOMPARE(focusSpy.count(), 2);
- QCOMPARE(activeFocusSpy.count(), 2);
+ QCOMPARE(focusSpy.size(), 2);
+ QCOMPARE(activeFocusSpy.size(), 2);
// Wait for double click timeout to expire before clicking again.
QTest::qWait(400);
@@ -3529,13 +3546,13 @@ void tst_qquicktextinput::focusOnPress()
QGuiApplication::processEvents();
QCOMPARE(textInputObject->hasFocus(), false);
QCOMPARE(textInputObject->hasActiveFocus(), false);
- QCOMPARE(focusSpy.count(), 2);
- QCOMPARE(activeFocusSpy.count(), 2);
+ QCOMPARE(focusSpy.size(), 2);
+ QCOMPARE(activeFocusSpy.size(), 2);
QTest::mouseRelease(&window, Qt::LeftButton, noModifiers);
textInputObject->setFocusOnPress(true);
QCOMPARE(textInputObject->focusOnPress(), true);
- QCOMPARE(activeFocusOnPressSpy.count(), 2);
+ QCOMPARE(activeFocusOnPressSpy.size(), 2);
// Test a selection made in the on(Active)FocusChanged handler isn't overwritten.
textInputObject->setProperty("selectOnFocus", true);
@@ -3545,8 +3562,8 @@ void tst_qquicktextinput::focusOnPress()
QGuiApplication::processEvents();
QCOMPARE(textInputObject->hasFocus(), true);
QCOMPARE(textInputObject->hasActiveFocus(), true);
- QCOMPARE(focusSpy.count(), 3);
- QCOMPARE(activeFocusSpy.count(), 3);
+ QCOMPARE(focusSpy.size(), 3);
+ QCOMPARE(activeFocusSpy.size(), 3);
QCOMPARE(textInputObject->selectedText(), textInputObject->text());
QTest::mouseRelease(&window, Qt::LeftButton, noModifiers);
}
@@ -3637,7 +3654,7 @@ void tst_qquicktextinput::openInputPanel()
anotherInput.setFocus(true);
QCOMPARE(qApp->inputMethod()->isVisible(), true);
QCOMPARE(qApp->focusObject(), qobject_cast<QObject*>(&anotherInput));
- QCOMPARE(inputPanelVisibilitySpy.count(), 0);
+ QCOMPARE(inputPanelVisibilitySpy.size(), 0);
anotherInput.setFocus(false);
QVERIFY(qApp->focusObject() != &anotherInput);
@@ -3672,7 +3689,7 @@ public:
{
nbPaint = 0;
}
- virtual QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data)
+ QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data) override
{
nbPaint++;
return QQuickTextInput::updatePaintNode(node, data);
@@ -3752,8 +3769,6 @@ void tst_qquicktextinput::focusOutNotClearSelection()
input.setFocus(false, Qt::PopupFocusReason);
QGuiApplication::processEvents();
QTRY_COMPARE(input.selectedText(), QLatin1String("llo"));
- // QTBUG-36332 and 36292: a popup window does not take focus
- QTRY_COMPARE(input.hasActiveFocus(), true);
input.setFocus(true);
QTRY_COMPARE(input.hasActiveFocus(), true);
@@ -3788,18 +3803,18 @@ void tst_qquicktextinput::contentSize()
QVERIFY(textObject->contentWidth() > textObject->width());
QVERIFY(textObject->contentHeight() < textObject->height());
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
textObject->setWrapMode(QQuickTextInput::WordWrap);
QVERIFY(textObject->contentWidth() <= textObject->width());
QVERIFY(textObject->contentHeight() > textObject->height());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
textObject->setText("The quickredfoxjumpedoverthe lazy brown dog");
QVERIFY(textObject->contentWidth() > textObject->width());
QVERIFY(textObject->contentHeight() > textObject->height());
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
textObject->setText("The quick red fox jumped over the lazy brown dog");
for (int w = 60; w < 120; ++w) {
@@ -3812,7 +3827,7 @@ void tst_qquicktextinput::contentSize()
static void sendPreeditText(QQuickItem *item, const QString &text, int cursor)
{
QInputMethodEvent event(text, QList<QInputMethodEvent::Attribute>()
- << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursor, text.length(), QVariant()));
+ << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursor, text.size(), QVariant()));
QCoreApplication::sendEvent(item, &event);
}
@@ -3837,14 +3852,14 @@ void tst_qquicktextinput::preeditAutoScroll()
sendPreeditText(input, preeditText.mid(0, 3), 1);
QVERIFY(evaluate<int>(input, QString("positionAt(0)")) != 0);
QVERIFY(input->cursorRectangle().left() < input->boundingRect().width());
- QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
+ QCOMPARE(cursorRectangleSpy.size(), ++cursorRectangleChanges);
// test the text is scrolled back when the preedit is removed.
QInputMethodEvent imEvent;
QCoreApplication::sendEvent(input, &imEvent);
QCOMPARE(evaluate<int>(input, QString("positionAt(%1)").arg(0)), 0);
QCOMPARE(evaluate<int>(input, QString("positionAt(%1)").arg(input->width())), 5);
- QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
+ QCOMPARE(cursorRectangleSpy.size(), ++cursorRectangleChanges);
QTextLayout layout(preeditText);
layout.setFont(input->font());
@@ -3865,7 +3880,7 @@ void tst_qquicktextinput::preeditAutoScroll()
int width = ceil(line.cursorToX(i, QTextLine::Trailing)) - floor(line.cursorToX(i));
QVERIFY(input->cursorRectangle().right() >= width - 3);
QVERIFY(input->positionToRectangle(0).x() < x);
- QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
+ QCOMPARE(cursorRectangleSpy.size(), ++cursorRectangleChanges);
x = input->positionToRectangle(0).x();
}
for (int i = 1; i >= 0; --i) {
@@ -3873,24 +3888,24 @@ void tst_qquicktextinput::preeditAutoScroll()
int width = ceil(line.cursorToX(i, QTextLine::Trailing)) - floor(line.cursorToX(i));
QVERIFY(input->cursorRectangle().right() >= width - 3);
QVERIFY(input->positionToRectangle(0).x() > x);
- QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
+ QCOMPARE(cursorRectangleSpy.size(), ++cursorRectangleChanges);
x = input->positionToRectangle(0).x();
}
// Test incrementing the preedit cursor doesn't cause further
// scrolling when right most text is visible.
- sendPreeditText(input, preeditText, preeditText.length() - 3);
- QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
+ sendPreeditText(input, preeditText, preeditText.size() - 3);
+ QCOMPARE(cursorRectangleSpy.size(), ++cursorRectangleChanges);
x = input->positionToRectangle(0).x();
for (int i = 2; i >= 0; --i) {
- sendPreeditText(input, preeditText, preeditText.length() - i);
+ sendPreeditText(input, preeditText, preeditText.size() - i);
QCOMPARE(input->positionToRectangle(0).x(), x);
- QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
+ QCOMPARE(cursorRectangleSpy.size(), ++cursorRectangleChanges);
}
for (int i = 1; i < 3; ++i) {
- sendPreeditText(input, preeditText, preeditText.length() - i);
+ sendPreeditText(input, preeditText, preeditText.size() - i);
QCOMPARE(input->positionToRectangle(0).x(), x);
- QCOMPARE(cursorRectangleSpy.count(), ++cursorRectangleChanges);
+ QCOMPARE(cursorRectangleSpy.size(), ++cursorRectangleChanges);
}
// Test disabling auto scroll.
@@ -3944,8 +3959,8 @@ void tst_qquicktextinput::preeditCursorRectangle()
QVERIFY(previousRect.left() < currentRect.left());
QCOMPARE(input->cursorRectangle(), currentRect);
QCOMPARE(cursor->position(), currentRect.topLeft());
- QVERIFY(inputSpy.count() > 0); inputSpy.clear();
- QVERIFY(panelSpy.count() > 0); panelSpy.clear();
+ QVERIFY(inputSpy.size() > 0); inputSpy.clear();
+ QVERIFY(panelSpy.size() > 0); panelSpy.clear();
previousRect = currentRect;
}
@@ -3958,8 +3973,8 @@ void tst_qquicktextinput::preeditCursorRectangle()
currentRect = query.value(Qt::ImCursorRectangle).toRectF();
QCOMPARE(input->cursorRectangle(), currentRect);
QCOMPARE(cursor->position(), currentRect.topLeft());
- QCOMPARE(inputSpy.count(), 1);
- QCOMPARE(panelSpy.count(), 1);
+ QCOMPARE(inputSpy.size(), 1);
+ QCOMPARE(panelSpy.size(), 1);
// Verify that if there is no preedit cursor then the micro focus rect is the
// same as it would be if it were positioned at the end of the preedit text.
@@ -3972,8 +3987,8 @@ void tst_qquicktextinput::preeditCursorRectangle()
QCOMPARE(currentRect, previousRect);
QCOMPARE(input->cursorRectangle(), currentRect);
QCOMPARE(cursor->position(), currentRect.topLeft());
- QCOMPARE(inputSpy.count(), 1);
- QCOMPARE(panelSpy.count(), 1);
+ QCOMPARE(inputSpy.size(), 1);
+ QCOMPARE(panelSpy.size(), 1);
}
void tst_qquicktextinput::inputContextMouseHandler()
@@ -4040,37 +4055,37 @@ void tst_qquicktextinput::inputMethodComposing()
QGuiApplication::sendEvent(input, &event);
}
QCOMPARE(input->isInputMethodComposing(), true);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
{
QInputMethodEvent event(text.mid(12), QList<QInputMethodEvent::Attribute>());
QGuiApplication::sendEvent(input, &event);
}
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
{
QInputMethodEvent event;
QGuiApplication::sendEvent(input, &event);
}
QCOMPARE(input->isInputMethodComposing(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
// Changing the text while not composing doesn't alter the composing state.
input->setText(text.mid(0, 16));
QCOMPARE(input->isInputMethodComposing(), false);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
{
QInputMethodEvent event(text.mid(16), QList<QInputMethodEvent::Attribute>());
QGuiApplication::sendEvent(input, &event);
}
QCOMPARE(input->isInputMethodComposing(), true);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
// Changing the text while composing cancels composition.
input->setText(text.mid(0, 12));
QCOMPARE(input->isInputMethodComposing(), false);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
{ // Preedit cursor positioned outside (empty) preedit; composing.
QInputMethodEvent event(QString(), QList<QInputMethodEvent::Attribute>()
@@ -4078,7 +4093,7 @@ void tst_qquicktextinput::inputMethodComposing()
QGuiApplication::sendEvent(input, &event);
}
QCOMPARE(input->isInputMethodComposing(), true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
{ // Cursor hidden; composing
@@ -4087,7 +4102,7 @@ void tst_qquicktextinput::inputMethodComposing()
QGuiApplication::sendEvent(input, &event);
}
QCOMPARE(input->isInputMethodComposing(), true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
{ // Default cursor attributes; composing.
QInputMethodEvent event(QString(), QList<QInputMethodEvent::Attribute>()
@@ -4095,7 +4110,7 @@ void tst_qquicktextinput::inputMethodComposing()
QGuiApplication::sendEvent(input, &event);
}
QCOMPARE(input->isInputMethodComposing(), true);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
{ // Selections are persisted: not composing
QInputMethodEvent event(QString(), QList<QInputMethodEvent::Attribute>()
@@ -4103,7 +4118,7 @@ void tst_qquicktextinput::inputMethodComposing()
QGuiApplication::sendEvent(input, &event);
}
QCOMPARE(input->isInputMethodComposing(), false);
- QCOMPARE(spy.count(), 6);
+ QCOMPARE(spy.size(), 6);
input->setCursorPosition(12);
@@ -4115,14 +4130,14 @@ void tst_qquicktextinput::inputMethodComposing()
QGuiApplication::sendEvent(input, &event);
}
QCOMPARE(input->isInputMethodComposing(), true);
- QCOMPARE(spy.count(), 7);
+ QCOMPARE(spy.size(), 7);
{
QInputMethodEvent event;
QGuiApplication::sendEvent(input, &event);
}
QCOMPARE(input->isInputMethodComposing(), false);
- QCOMPARE(spy.count(), 8);
+ QCOMPARE(spy.size(), 8);
}
void tst_qquicktextinput::inputMethodUpdate()
@@ -4309,7 +4324,7 @@ void tst_qquicktextinput::getText_data()
QTest::newRow("all plain text")
<< standard.at(0)
<< QString()
- << 0 << standard.at(0).length()
+ << 0 << standard.at(0).size()
<< standard.at(0);
QTest::newRow("plain text sub string")
@@ -4333,13 +4348,13 @@ void tst_qquicktextinput::getText_data()
QTest::newRow("plain text cropped end")
<< standard.at(0)
<< QString()
- << 23 << standard.at(0).length() + 8
+ << 23 << standard.at(0).size() + 8
<< standard.at(0).mid(23);
QTest::newRow("plain text cropped beginning and end")
<< standard.at(0)
<< QString()
- << -9 << standard.at(0).length() + 4
+ << -9 << standard.at(0).size() + 4
<< standard.at(0);
}
@@ -4387,10 +4402,10 @@ void tst_qquicktextinput::insert_data()
QTest::newRow("at cursor position (end)")
<< standard.at(0)
<< QString()
- << standard.at(0).length() << standard.at(0).length() << standard.at(0).length()
+ << standard.at(0).size() << standard.at(0).size() << standard.at(0).size()
<< QString("Hello")
<< standard.at(0) + QString("Hello")
- << standard.at(0).length() + 5 << standard.at(0).length() + 5 << standard.at(0).length() + 5
+ << standard.at(0).size() + 5 << standard.at(0).size() + 5 << standard.at(0).size() + 5
<< false << true;
QTest::newRow("at cursor position (middle)")
@@ -4414,10 +4429,10 @@ void tst_qquicktextinput::insert_data()
QTest::newRow("before cursor position (end)")
<< standard.at(0)
<< QString()
- << standard.at(0).length() << standard.at(0).length() << 18
+ << standard.at(0).size() << standard.at(0).size() << 18
<< QString("Hello")
<< standard.at(0).mid(0, 18) + QString("Hello") + standard.at(0).mid(18)
- << standard.at(0).length() + 5 << standard.at(0).length() + 5 << standard.at(0).length() + 5
+ << standard.at(0).size() + 5 << standard.at(0).size() + 5 << standard.at(0).size() + 5
<< false << true;
QTest::newRow("before cursor position (middle)")
@@ -4432,7 +4447,7 @@ void tst_qquicktextinput::insert_data()
QTest::newRow("after cursor position (middle)")
<< standard.at(0)
<< QString()
- << 18 << 18 << standard.at(0).length()
+ << 18 << 18 << standard.at(0).size()
<< QString("Hello")
<< standard.at(0) + QString("Hello")
<< 18 << 18 << 18
@@ -4459,7 +4474,7 @@ void tst_qquicktextinput::insert_data()
QTest::newRow("after selection")
<< standard.at(0)
<< QString()
- << 14 << 19 << standard.at(0).length()
+ << 14 << 19 << standard.at(0).size()
<< QString("Hello")
<< standard.at(0) + QString("Hello")
<< 14 << 19 << 19
@@ -4468,7 +4483,7 @@ void tst_qquicktextinput::insert_data()
QTest::newRow("after reversed selection")
<< standard.at(0)
<< QString()
- << 19 << 14 << standard.at(0).length()
+ << 19 << 14 << standard.at(0).size()
<< QString("Hello")
<< standard.at(0) + QString("Hello")
<< 14 << 19 << 14
@@ -4513,7 +4528,7 @@ void tst_qquicktextinput::insert_data()
QTest::newRow("past end")
<< standard.at(0)
<< QString()
- << 0 << 0 << standard.at(0).length() + 3
+ << 0 << 0 << standard.at(0).size() + 3
<< QString("Hello")
<< standard.at(0)
<< 0 << 0 << 0
@@ -4534,10 +4549,10 @@ void tst_qquicktextinput::insert_data()
QTest::newRow("mask: at cursor position (end)")
<< ip
<< inputMask
- << inputMask.length() << inputMask.length() << inputMask.length()
+ << inputMask.size() << inputMask.size() << inputMask.size()
<< QString("8")
<< ip
- << inputMask.length() << inputMask.length() << inputMask.length()
+ << inputMask.size() << inputMask.size() << inputMask.size()
<< false << false;
QTest::newRow("mask: at cursor position (middle)")
@@ -4561,10 +4576,10 @@ void tst_qquicktextinput::insert_data()
QTest::newRow("mask: before cursor position (end)")
<< ip
<< inputMask
- << inputMask.length() << inputMask.length() << 6
+ << inputMask.size() << inputMask.size() << 6
<< QString("75.2")
<< QString("192.167.5.24")
- << inputMask.length() << inputMask.length() << inputMask.length()
+ << inputMask.size() << inputMask.size() << inputMask.size()
<< false << false;
QTest::newRow("mask: before cursor position (middle)")
@@ -4651,7 +4666,7 @@ void tst_qquicktextinput::insert_data()
QTest::newRow("mask: past end")
<< ip
<< inputMask
- << 0 << 0 << ip.length() + 3
+ << 0 << 0 << ip.size() + 3
<< QString("4")
<< ip
<< 0 << 0 << 0
@@ -4708,7 +4723,7 @@ void tst_qquicktextinput::insert()
textInput->insert(insertPosition, insertText);
QCOMPARE(textInput->text(), expectedText);
- QCOMPARE(textInput->length(), inputMask.isEmpty() ? expectedText.length() : inputMask.length());
+ QCOMPARE(textInput->length(), inputMask.isEmpty() ? expectedText.size() : inputMask.size());
QCOMPARE(textInput->selectionStart(), expectedSelectionStart);
QCOMPARE(textInput->selectionEnd(), expectedSelectionEnd);
@@ -4717,11 +4732,11 @@ void tst_qquicktextinput::insert()
if (selectionStart > selectionEnd)
qSwap(selectionStart, selectionEnd);
- QCOMPARE(selectionSpy.count() > 0, selectionChanged);
- QCOMPARE(selectionStartSpy.count() > 0, selectionStart != expectedSelectionStart);
- QCOMPARE(selectionEndSpy.count() > 0, selectionEnd != expectedSelectionEnd);
- QCOMPARE(textSpy.count() > 0, text != expectedText);
- QCOMPARE(cursorPositionSpy.count() > 0, cursorPositionChanged);
+ QCOMPARE(selectionSpy.size() > 0, selectionChanged);
+ QCOMPARE(selectionStartSpy.size() > 0, selectionStart != expectedSelectionStart);
+ QCOMPARE(selectionEndSpy.size() > 0, selectionEnd != expectedSelectionEnd);
+ QCOMPARE(textSpy.size() > 0, text != expectedText);
+ QCOMPARE(cursorPositionSpy.size() > 0, cursorPositionChanged);
}
void tst_qquicktextinput::remove_data()
@@ -4760,19 +4775,19 @@ void tst_qquicktextinput::remove_data()
QTest::newRow("to cursor position (end)")
<< standard.at(0)
<< QString()
- << standard.at(0).length() << standard.at(0).length()
- << standard.at(0).length() << standard.at(0).length() - 5
- << standard.at(0).mid(0, standard.at(0).length() - 5)
- << standard.at(0).length() - 5 << standard.at(0).length() - 5 << standard.at(0).length() - 5
+ << standard.at(0).size() << standard.at(0).size()
+ << standard.at(0).size() << standard.at(0).size() - 5
+ << standard.at(0).mid(0, standard.at(0).size() - 5)
+ << standard.at(0).size() - 5 << standard.at(0).size() - 5 << standard.at(0).size() - 5
<< false << true;
QTest::newRow("to cursor position (end)")
<< standard.at(0)
<< QString()
- << standard.at(0).length() << standard.at(0).length()
- << standard.at(0).length() - 5 << standard.at(0).length()
- << standard.at(0).mid(0, standard.at(0).length() - 5)
- << standard.at(0).length() - 5 << standard.at(0).length() - 5 << standard.at(0).length() - 5
+ << standard.at(0).size() << standard.at(0).size()
+ << standard.at(0).size() - 5 << standard.at(0).size()
+ << standard.at(0).mid(0, standard.at(0).size() - 5)
+ << standard.at(0).size() - 5 << standard.at(0).size() - 5 << standard.at(0).size() - 5
<< false << true;
QTest::newRow("from cursor position (middle)")
@@ -4805,10 +4820,10 @@ void tst_qquicktextinput::remove_data()
QTest::newRow("before cursor position (end)")
<< standard.at(0)
<< QString()
- << standard.at(0).length() << standard.at(0).length()
+ << standard.at(0).size() << standard.at(0).size()
<< 18 << 23
<< standard.at(0).mid(0, 18) + standard.at(0).mid(23)
- << standard.at(0).length() - 5 << standard.at(0).length() - 5 << standard.at(0).length() - 5
+ << standard.at(0).size() - 5 << standard.at(0).size() - 5 << standard.at(0).size() - 5
<< false << true;
QTest::newRow("before cursor position (middle)")
@@ -4851,8 +4866,8 @@ void tst_qquicktextinput::remove_data()
<< standard.at(0)
<< QString()
<< 14 << 19
- << standard.at(0).length() - 5 << standard.at(0).length()
- << standard.at(0).mid(0, standard.at(0).length() - 5)
+ << standard.at(0).size() - 5 << standard.at(0).size()
+ << standard.at(0).mid(0, standard.at(0).size() - 5)
<< 14 << 19 << 19
<< false << false;
@@ -4860,8 +4875,8 @@ void tst_qquicktextinput::remove_data()
<< standard.at(0)
<< QString()
<< 19 << 14
- << standard.at(0).length() - 5 << standard.at(0).length()
- << standard.at(0).mid(0, standard.at(0).length() - 5)
+ << standard.at(0).size() - 5 << standard.at(0).size()
+ << standard.at(0).mid(0, standard.at(0).size() - 5)
<< 14 << 19 << 14
<< false << false;
@@ -4896,7 +4911,7 @@ void tst_qquicktextinput::remove_data()
<< standard.at(0)
<< QString()
<< 0 << 0
- << 23 << standard.at(0).length() + 8
+ << 23 << standard.at(0).size() + 8
<< standard.at(0).mid(0, 23)
<< 0 << 0 << 0
<< false << false;
@@ -4905,7 +4920,7 @@ void tst_qquicktextinput::remove_data()
<< standard.at(0)
<< QString()
<< 0 << 0
- << -9 << standard.at(0).length() + 4
+ << -9 << standard.at(0).size() + 4
<< QString()
<< 0 << 0 << 0
<< false << false;
@@ -5063,7 +5078,7 @@ void tst_qquicktextinput::remove()
textInput->remove(removeStart, removeEnd);
QCOMPARE(textInput->text(), expectedText);
- QCOMPARE(textInput->length(), inputMask.isEmpty() ? expectedText.length() : inputMask.length());
+ QCOMPARE(textInput->length(), inputMask.isEmpty() ? expectedText.size() : inputMask.size());
if (selectionStart > selectionEnd) //
qSwap(selectionStart, selectionEnd);
@@ -5072,13 +5087,13 @@ void tst_qquicktextinput::remove()
QCOMPARE(textInput->selectionEnd(), expectedSelectionEnd);
QCOMPARE(textInput->cursorPosition(), expectedCursorPosition);
- QCOMPARE(selectionSpy.count() > 0, selectionChanged);
- QCOMPARE(selectionStartSpy.count() > 0, selectionStart != expectedSelectionStart);
- QCOMPARE(selectionEndSpy.count() > 0, selectionEnd != expectedSelectionEnd);
- QCOMPARE(textSpy.count() > 0, text != expectedText);
+ QCOMPARE(selectionSpy.size() > 0, selectionChanged);
+ QCOMPARE(selectionStartSpy.size() > 0, selectionStart != expectedSelectionStart);
+ QCOMPARE(selectionEndSpy.size() > 0, selectionEnd != expectedSelectionEnd);
+ QCOMPARE(textSpy.size() > 0, text != expectedText);
if (cursorPositionChanged) //
- QVERIFY(cursorPositionSpy.count() > 0);
+ QVERIFY(cursorPositionSpy.size() > 0);
}
#if QT_CONFIG(shortcut)
@@ -5438,11 +5453,11 @@ void tst_qquicktextinput::undo()
// QTest::keyClick(testWidget, Qt::Key_End, Qt::ShiftModifier);
}
- for (int j = 0; j < insertString.at(i).length(); j++)
+ for (int j = 0; j < insertString.at(i).size(); j++)
QTest::keyClick(&window, insertString.at(i).at(j).toLatin1());
}
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
// STEP 2: Next call undo several times and see if we can restore to the previous state
for (i = 0; i < expectedString.size() - 1; ++i) {
@@ -5454,7 +5469,7 @@ void tst_qquicktextinput::undo()
// STEP 3: Verify that we have undone everything
QVERIFY(textInput->text().isEmpty());
QVERIFY(!textInput->canUndo());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
void tst_qquicktextinput::redo_data()
@@ -5515,13 +5530,13 @@ void tst_qquicktextinput::redo()
for (i = 0; i < insertString.size(); ++i) {
if (insertIndex[i] > -1)
textInput->setCursorPosition(insertIndex[i]);
- for (int j = 0; j < insertString.at(i).length(); j++)
+ for (int j = 0; j < insertString.at(i).size(); j++)
QTest::keyClick(&window, insertString.at(i).at(j).toLatin1());
QVERIFY(textInput->canUndo());
QVERIFY(!textInput->canRedo());
}
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
// undo everything
while (!textInput->text().isEmpty()) {
@@ -5530,7 +5545,7 @@ void tst_qquicktextinput::redo()
QVERIFY(textInput->canRedo());
}
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
for (i = 0; i < expectedString.size(); ++i) {
QVERIFY(textInput->canRedo());
@@ -5539,7 +5554,7 @@ void tst_qquicktextinput::redo()
QVERIFY(textInput->canUndo());
}
QVERIFY(!textInput->canRedo());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
}
#if QT_CONFIG(shortcut)
@@ -5873,12 +5888,12 @@ void tst_qquicktextinput::clear()
textInput->clear();
QVERIFY(textInput->text().isEmpty());
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
// checks that clears can be undone
textInput->undo();
QVERIFY(!textInput->canUndo());
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
QCOMPARE(textInput->text(), QString("I am Legend"));
textInput->setCursorPosition(4);
@@ -5890,14 +5905,16 @@ void tst_qquicktextinput::clear()
textInput->clear();
QVERIFY(textInput->text().isEmpty());
+ QVERIFY2(textInput->preeditText().isEmpty(), "Pre-edit text must be empty after clear");
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
// checks that clears can be undone
textInput->undo();
QVERIFY(!textInput->canUndo());
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
QCOMPARE(textInput->text(), QString("I am Legend"));
+ QVERIFY2(textInput->preeditText().isEmpty(), "Pre-edit text must be empty after undo");
}
void tst_qquicktextinput::backspaceSurrogatePairs()
@@ -5912,7 +5929,7 @@ void tst_qquicktextinput::backspaceSurrogatePairs()
QQuickTextInput *textInput = qobject_cast<QQuickTextInput*>(textInputComponent.create());
QVERIFY(textInput != nullptr);
textInput->setText(text);
- textInput->setCursorPosition(text.length());
+ textInput->setCursorPosition(text.size());
QQuickWindow window;
textInput->setParentItem(window.contentItem());
@@ -5921,7 +5938,7 @@ void tst_qquicktextinput::backspaceSurrogatePairs()
QVERIFY(QTest::qWaitForWindowActive(&window));
QCOMPARE(QGuiApplication::focusWindow(), &window);
- for (int i = text.length(); i >= 0; i -= 2) {
+ for (int i = text.size(); i >= 0; i -= 2) {
QCOMPARE(textInput->text(), text.mid(0, i));
QTest::keyClick(&window, Qt::Key_Backspace, Qt::NoModifier);
}
@@ -5930,7 +5947,7 @@ void tst_qquicktextinput::backspaceSurrogatePairs()
textInput->setText(text);
textInput->setCursorPosition(0);
- for (int i = 0; i < text.length(); i += 2) {
+ for (int i = 0; i < text.size(); i += 2) {
QCOMPARE(textInput->text(), text.mid(i));
QTest::keyClick(&window, Qt::Key_Delete, Qt::NoModifier);
}
@@ -6417,9 +6434,9 @@ void tst_qquicktextinput::setInputMask()
// inputMaskChanged signal
QString unescapedMask = mask; // mask is escaped, because '\' is also escape in a JS string
unescapedMask.replace(QLatin1String("\\\\"), QLatin1String("\\")); // simple unescape
- QSignalSpy spy(textInput, SIGNAL(inputMaskChanged(const QString &)));
+ QSignalSpy spy(textInput, SIGNAL(inputMaskChanged(QString)));
textInput->setInputMask(unescapedMask);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
// then either insert using insert() or keyboard
if (insert_text) {
@@ -6433,7 +6450,7 @@ void tst_qquicktextinput::setInputMask()
QVERIFY(textInput->hasActiveFocus());
QTest::keyClick(&window, Qt::Key_Home);
- for (int i = 0; i < input.length(); i++)
+ for (int i = 0; i < input.size(); i++)
QTest::keyClick(&window, input.at(i).toLatin1());
}
@@ -6713,8 +6730,8 @@ class TestValidator : public QValidator
public:
TestValidator(QObject *parent = nullptr) : QValidator(parent) { }
- State validate(QString &input, int &) const { return input == QStringLiteral("ok") ? Acceptable : Intermediate; }
- void fixup(QString &input) const { input = QStringLiteral("ok"); }
+ State validate(QString &input, int &) const override { return input == QStringLiteral("ok") ? Acceptable : Intermediate; }
+ void fixup(QString &input) const override { input = QStringLiteral("ok"); }
};
void tst_qquicktextinput::fixup()
@@ -6913,7 +6930,7 @@ void tst_qquicktextinput::ensureVisible()
input->ensureVisible(input->length());
- QCOMPARE(cursorSpy.count(), 1);
+ QCOMPARE(cursorSpy.size(), 1);
QCOMPARE(input->boundingRect().x(), input->width() - line.naturalTextWidth());
QCOMPARE(input->boundingRect().y(), qreal(0));
@@ -7023,6 +7040,209 @@ void tst_qquicktextinput::QTBUG_77814_InsertRemoveNoSelection()
QCOMPARE(textInput->selectedText(), QString());
}
+void tst_qquicktextinput::checkCursorDelegateWhenPaddingChanged()
+{
+ QQuickView view;
+ view.setSource(testFileUrl("checkCursorDelegateWhenPaddingChanged.qml"));
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickTextInput *textInput = view.rootObject()->findChild<QQuickTextInput *>("textInput");
+ QVERIFY(textInput);
+
+ QQuickItem *cursorDelegate = textInput->findChild<QQuickItem *>("cursorDelegate");
+ QVERIFY(cursorDelegate);
+
+ QCOMPARE(cursorDelegate->x(), textInput->leftPadding());
+ QCOMPARE(cursorDelegate->y(), textInput->topPadding());
+
+ textInput->setPadding(5);
+ QCOMPARE(cursorDelegate->x(), textInput->leftPadding());
+ QCOMPARE(cursorDelegate->y(), textInput->topPadding());
+
+ textInput->setTopPadding(10);
+ QCOMPARE(cursorDelegate->x(), textInput->leftPadding());
+ QCOMPARE(cursorDelegate->y(), textInput->topPadding());
+
+ textInput->setLeftPadding(10);
+ QCOMPARE(cursorDelegate->x(), textInput->leftPadding());
+ QCOMPARE(cursorDelegate->y(), textInput->topPadding());
+}
+
+/*!
+ Verifies that TextInput items get focus in/out events with the
+ correct focus reason set.
+
+ Up and Down keys translates to Backtab and Tab focus reasons.
+
+ See QTBUG-75862.
+*/
+void tst_qquicktextinput::focusReason()
+{
+ QQuickView view;
+ view.setSource(testFileUrl("focusReason.qml"));
+
+ QQuickTextInput *first = view.rootObject()->findChild<QQuickTextInput *>("first");
+ QQuickTextInput *second = view.rootObject()->findChild<QQuickTextInput *>("second");
+ QQuickTextInput *third = view.rootObject()->findChild<QQuickTextInput *>("third");
+ QVERIFY(first && second && third);
+
+ class FocusEventFilter : public QObject
+ {
+ public:
+ using QObject::QObject;
+
+ QHash<QObject*, Qt::FocusReason> lastFocusReason;
+ protected:
+ bool eventFilter(QObject *o, QEvent *e) override
+ {
+ if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut) {
+ QFocusEvent *fe = static_cast<QFocusEvent*>(e);
+ lastFocusReason[o] = fe->reason();
+ }
+ return QObject::eventFilter(o, e);
+ }
+ } eventFilter;
+ first->installEventFilter(&eventFilter);
+ second->installEventFilter(&eventFilter);
+ third->installEventFilter(&eventFilter);
+
+ view.show();
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+
+ QCOMPARE(qApp->focusObject(), first);
+ // on some platforms we don't get ActiveWindowFocusReason; tolerate this,
+ // it's not what we are testing in this test
+ if (eventFilter.lastFocusReason[first] != Qt::ActiveWindowFocusReason) {
+ QEXPECT_FAIL("", qPrintable(QString("No window activation event on the %1 platform")
+ .arg(QGuiApplication::platformName())),
+ Continue);
+ }
+ QCOMPARE(eventFilter.lastFocusReason[first], Qt::ActiveWindowFocusReason);
+
+ QTest::mouseClick(&view, Qt::LeftButton, {},
+ (second->boundingRect().center() + second->position()).toPoint());
+ QTRY_COMPARE(qApp->focusObject(), second);
+ QCOMPARE(eventFilter.lastFocusReason[first], Qt::MouseFocusReason);
+ QCOMPARE(eventFilter.lastFocusReason[second], Qt::MouseFocusReason);
+
+ QTest::keyClick(&view, Qt::Key_Tab);
+ QCOMPARE(qApp->focusObject(), third);
+ QCOMPARE(eventFilter.lastFocusReason[second], Qt::TabFocusReason);
+ QCOMPARE(eventFilter.lastFocusReason[third], Qt::TabFocusReason);
+
+ QTest::keyClick(&view, Qt::Key_Backtab);
+ QCOMPARE(qApp->focusObject(), second);
+ QCOMPARE(eventFilter.lastFocusReason[third], Qt::BacktabFocusReason);
+ QCOMPARE(eventFilter.lastFocusReason[second], Qt::BacktabFocusReason);
+
+ QTest::keyClick(&view, Qt::Key_Up);
+ QCOMPARE(qApp->focusObject(), first);
+ QCOMPARE(eventFilter.lastFocusReason[second], Qt::BacktabFocusReason);
+ QCOMPARE(eventFilter.lastFocusReason[first], Qt::BacktabFocusReason);
+
+ QTest::keyClick(&view, Qt::Key_Down);
+ QCOMPARE(qApp->focusObject(), second);
+ QCOMPARE(eventFilter.lastFocusReason[second], Qt::TabFocusReason);
+ QCOMPARE(eventFilter.lastFocusReason[first], Qt::TabFocusReason);
+}
+
+void tst_qquicktextinput::touchscreenDoesNotSelect_data()
+{
+ QTest::addColumn<QUrl>("src");
+ QTest::addColumn<bool>("expectDefaultSelectByMouse");
+ QTest::addColumn<bool>("overrideSelectByMouseFalse");
+ QTest::newRow("new default") << testFileUrl("mouseselectionmode_default.qml") << true << false;
+ QTest::newRow("new override") << testFileUrl("mouseselectionmode_default.qml") << true << true;
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ QTest::newRow("old default") << testFileUrl("mouseselection_old_default.qml") << false << false;
+#endif
+}
+
+void tst_qquicktextinput::touchscreenDoesNotSelect()
+{
+ QFETCH(QUrl, src);
+ QFETCH(bool, expectDefaultSelectByMouse);
+ QFETCH(bool, overrideSelectByMouseFalse);
+
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, src));
+
+ QQuickTextInput *textInputObject = qobject_cast<QQuickTextInput *>(window.rootObject());
+ QVERIFY(textInputObject);
+ QCOMPARE(textInputObject->selectByMouse(), expectDefaultSelectByMouse);
+ if (overrideSelectByMouseFalse)
+ textInputObject->setSelectByMouse(overrideSelectByMouseFalse);
+
+ // press-drag-and-release from x1 to x2
+ int x1 = 10;
+ int x2 = 70;
+ int y = textInputObject->height() / 2;
+ QTest::touchEvent(&window, touchscreen.data()).press(0, QPoint(x1,y), &window);
+ QTest::touchEvent(&window, touchscreen.data()).move(0, QPoint(x2,y), &window);
+ QTest::touchEvent(&window, touchscreen.data()).release(0, QPoint(x2,y), &window);
+ QQuickTouchUtils::flush(&window);
+ QVERIFY(textInputObject->selectedText().isEmpty());
+
+ // select all text (which moves the cursor to the end), then tap:
+ // with old API, it deselects, and moves the cursor (QTBUG-116606)
+ // with new API, it remains selected, and the cursor remains at the end
+ textInputObject->selectAll();
+ const int cursorPos = textInputObject->cursorPosition();
+ QTest::touchEvent(&window, touchscreen.data()).press(0, QPoint(x2,y), &window);
+ QTest::touchEvent(&window, touchscreen.data()).release(0, QPoint(x2,y), &window);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(textInputObject->selectedText().isEmpty(), !expectDefaultSelectByMouse);
+ if (expectDefaultSelectByMouse)
+ QCOMPARE(textInputObject->cursorPosition(), cursorPos);
+ else
+ QCOMPARE_NE(textInputObject->cursorPosition(), cursorPos);
+}
+
+void tst_qquicktextinput::touchscreenSetsFocusAndMovesCursor()
+{
+ if (!hasWindowActivation())
+ QSKIP("Window activation is not supported");
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("twoInAColumn.qml")));
+ window.requestActivate();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+
+ QQuickTextInput *top = window.rootObject()->findChild<QQuickTextInput*>("top");
+ QVERIFY(top);
+ QQuickTextInput *bottom = window.rootObject()->findChild<QQuickTextInput*>("bottom");
+ QVERIFY(bottom);
+
+ // tap the bottom field
+ int x1 = 10;
+ int y = bottom->position().y() + bottom->height() / 2;
+ QTest::touchEvent(&window, touchscreen.data()).press(0, QPoint(x1,y), &window);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(qApp->focusObject(), bottom);
+ // text cursor is at the end by default, on press
+ const auto len = bottom->text().size();
+ QCOMPARE(bottom->cursorPosition(), len);
+ // so typing a character appends it
+ QVERIFY(!bottom->text().endsWith('q'));
+ QTest::keyClick(&window, Qt::Key_Q);
+ QVERIFY(bottom->text().endsWith('q'));
+ QCOMPARE(bottom->text().size(), len + 1);
+ QTest::touchEvent(&window, touchscreen.data()).release(0, QPoint(x1,y), &window);
+ QQuickTouchUtils::flush(&window);
+ // the cursor gets moved on release, as long as TextInput's grab wasn't stolen (e.g. by Flickable)
+ QVERIFY(bottom->cursorPosition() < 5);
+
+ // press-drag-and-release from x1 to x2 on the top field
+ int x2 = 70;
+ y = top->position().y() + top->height() / 2;
+ QTest::touchEvent(&window, touchscreen.data()).press(0, QPoint(x1,y), &window);
+ QTest::touchEvent(&window, touchscreen.data()).move(0, QPoint(x2,y), &window);
+ QTest::touchEvent(&window, touchscreen.data()).release(0, QPoint(x2,y), &window);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(qApp->focusObject(), top);
+ QVERIFY(top->selectedText().isEmpty());
+}
+
QTEST_MAIN(tst_qquicktextinput)
#include "tst_qquicktextinput.moc"
diff --git a/tests/auto/quick/qquicktextmetrics/CMakeLists.txt b/tests/auto/quick/qquicktextmetrics/CMakeLists.txt
index 510baafaca..86bc976156 100644
--- a/tests/auto/quick/qquicktextmetrics/CMakeLists.txt
+++ b/tests/auto/quick/qquicktextmetrics/CMakeLists.txt
@@ -1,13 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquicktextmetrics.pro.
#####################################################################
## tst_qquicktextmetrics Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicktextmetrics LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qquicktextmetrics
SOURCES
tst_qquicktextmetrics.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::Qml
Qt::QuickPrivate
diff --git a/tests/auto/quick/qquicktextmetrics/tst_qquicktextmetrics.cpp b/tests/auto/quick/qquicktextmetrics/tst_qquicktextmetrics.cpp
index 74521ae496..8c3448d422 100644
--- a/tests/auto/quick/qquicktextmetrics/tst_qquicktextmetrics.cpp
+++ b/tests/auto/quick/qquicktextmetrics/tst_qquicktextmetrics.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QFont>
#include <QString>
diff --git a/tests/auto/quick/qquicktimeline/CMakeLists.txt b/tests/auto/quick/qquicktimeline/CMakeLists.txt
index 2ce3b2f8c4..e4e1de1346 100644
--- a/tests/auto/quick/qquicktimeline/CMakeLists.txt
+++ b/tests/auto/quick/qquicktimeline/CMakeLists.txt
@@ -1,13 +1,22 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquicktimeline.pro.
#####################################################################
## tst_qquicktimeline Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicktimeline LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
qt_internal_add_test(tst_qquicktimeline
SOURCES
tst_qquicktimeline.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
diff --git a/tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp b/tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp
index b3c3b4e713..247af56fd7 100644
--- a/tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp
+++ b/tests/auto/quick/qquicktimeline/tst_qquicktimeline.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <private/qquicktimeline_p_p.h>
diff --git a/tests/auto/quick/qquicktreeview/CMakeLists.txt b/tests/auto/quick/qquicktreeview/CMakeLists.txt
new file mode 100644
index 0000000000..1fa487c2e8
--- /dev/null
+++ b/tests/auto/quick/qquicktreeview/CMakeLists.txt
@@ -0,0 +1,50 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_qquicktreeview Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquicktreeview LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_qquicktreeview
+ SOURCES
+ testmodel.h testmodel.cpp
+ tst_qquicktreeview.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::QmlModelsPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ Qt::QuickTest
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
+)
+
+#### Keys ignored in scope 1:.:.:qquicktableview.pro:<TRUE>:
+# DISTFILES = <EMPTY>
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_qquicktreeview CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=":/data"
+)
+
+qt_internal_extend_target(tst_qquicktreeview CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+)
diff --git a/tests/auto/quick/qquicktreeview/data/CustomDelegate.qml b/tests/auto/quick/qquicktreeview/data/CustomDelegate.qml
new file mode 100644
index 0000000000..525f9ea337
--- /dev/null
+++ b/tests/auto/quick/qquicktreeview/data/CustomDelegate.qml
@@ -0,0 +1,47 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import TestModel
+
+Rectangle {
+ id: root
+
+ implicitWidth: 100 // hard-coded to make it easier to test the layout
+ implicitHeight: 25
+ clip: true
+ color: current || selected ? "lightgreen" : "white"
+
+ property alias text: label.text
+
+ readonly property real indent: 20
+ readonly property real padding: 5
+
+ // Assigned to by TreeView:
+ required property TreeView treeView
+ required property bool isTreeNode
+ required property bool expanded
+ required property int hasChildren
+ required property int depth
+ required property bool current
+ required property bool selected
+
+ TapHandler {
+ onTapped: treeView.toggleExpanded(row)
+ }
+
+ Text {
+ id: indicator
+ visible: root.isTreeNode && root.hasChildren
+ x: padding + (root.depth * root.indent)
+ text: root.expanded ? "â–¼" : "â–¶"
+ }
+
+ Text {
+ id: label
+ x: padding + (root.isTreeNode ? (root.depth + 1) * root.indent : 0)
+ width: root.width - root.padding - x
+ clip: true
+ text: model.display
+ }
+}
diff --git a/tests/auto/quick/qquicktreeview/data/normaltreeview.qml b/tests/auto/quick/qquicktreeview/data/normaltreeview.qml
new file mode 100644
index 0000000000..7a68646c80
--- /dev/null
+++ b/tests/auto/quick/qquicktreeview/data/normaltreeview.qml
@@ -0,0 +1,23 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import TestModel
+
+Item {
+ width: 800
+ height: 600
+
+ property alias treeView: treeView
+
+ TreeView {
+ id: treeView
+ anchors.fill:parent
+ anchors.margins: 10
+ model: TestModel {}
+ selectionModel: ItemSelectionModel {}
+ clip: true
+
+ delegate: CustomDelegate {}
+ }
+}
diff --git a/tests/auto/quick/qquicktreeview/testmodel.cpp b/tests/auto/quick/qquicktreeview/testmodel.cpp
new file mode 100644
index 0000000000..66fbf9b656
--- /dev/null
+++ b/tests/auto/quick/qquicktreeview/testmodel.cpp
@@ -0,0 +1,160 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "testmodel.h"
+
+TreeItem::TreeItem(TreeItem *parent)
+ : m_parentItem(parent)
+{}
+
+TreeItem::~TreeItem()
+{
+ qDeleteAll(m_childItems);
+}
+
+int TreeItem::row() const
+{
+ if (!m_parentItem)
+ return 0;
+ return m_parentItem->m_childItems.indexOf(const_cast<TreeItem *>(this));
+}
+
+TestModel::TestModel(QObject *parent)
+ : QAbstractItemModel(parent)
+{
+ m_rootItem.reset(new TreeItem());
+ for (int col = 0; col < m_columnCount; ++col)
+ m_rootItem.data()->m_entries << QVariant(QString("0, %1").arg(col));
+ createTreeRecursive(m_rootItem.data(), 4, 1);
+}
+
+void TestModel::createTreeRecursive(TreeItem *item, int childCount, int currentDepth)
+{
+ if (currentDepth > maxDepth())
+ return;
+
+ for (int row = 0; row < childCount; ++row) {
+ auto childItem = new TreeItem(item);
+ for (int col = 0; col < m_columnCount; ++col)
+ childItem->m_entries << QVariant(QString("%1, %2").arg(row).arg(col));
+ item->m_childItems.append(childItem);
+ if (row == childCount - 2 && currentDepth != maxDepth()) {
+ // Add a branch that doesn't recurse
+ createTreeRecursive(childItem, childCount, maxDepth());
+ }
+ if (row == childCount - 1) {
+ // Add a branch that recurses
+ createTreeRecursive(childItem, childCount, currentDepth + 1);
+ }
+ }
+}
+
+TreeItem *TestModel::treeItem(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return m_rootItem.data();
+ return static_cast<TreeItem *>(index.internalPointer());
+}
+
+int TestModel::rowCount(const QModelIndex &parent) const
+{
+ if (!parent.isValid())
+ return 1; // root of the tree
+ return treeItem(parent)->m_childItems.size();
+}
+
+int TestModel::columnCount(const QModelIndex &) const
+{
+ return m_columnCount;
+}
+
+QVariant TestModel::data(const QModelIndex &index, int role) const
+{
+ Q_UNUSED(role)
+ if (!index.isValid())
+ return QVariant();
+ TreeItem *item = treeItem(index);
+ return item->m_entries.at(index.column());
+}
+
+bool TestModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ Q_UNUSED(role)
+ if (!index.isValid())
+ return false;
+ TreeItem *item = treeItem(index);
+ if (!item)
+ return false;
+ item->m_entries[index.column()] = value;
+ emit dataChanged(index, index);
+ return true;
+}
+
+QModelIndex TestModel::index(int row, int column, const QModelIndex &parent) const
+{
+ Q_UNUSED(column)
+ if (!hasIndex(row, column, parent))
+ return QModelIndex();
+ if (!parent.isValid())
+ return createIndex(row, column, m_rootItem.data());
+ return createIndex(row, column, treeItem(parent)->m_childItems.at(row));
+}
+
+QModelIndex TestModel::parent(const QModelIndex &index) const
+{
+ TreeItem *parentItem = treeItem(index)->m_parentItem;
+ if (!parentItem)
+ return QModelIndex();
+ return createIndex(parentItem->row(), 0, parentItem);
+}
+
+bool TestModel::insertRows(int position, int rows, const QModelIndex &parent)
+{
+ if (!parent.isValid()) {
+ qWarning() << "Cannot insert rows on an invalid parent!";
+ return false;
+ }
+
+ beginInsertRows(parent, position, position + rows - 1);
+ TreeItem *parentItem = treeItem(parent);
+
+ for (int row = 0; row < rows; ++row) {
+ auto newChildItem = new TreeItem(parentItem);
+ for (int col = 0; col < m_columnCount; ++col)
+ newChildItem->m_entries << QVariant(QString("%1, %2 (inserted)").arg(position + row).arg(col));
+ parentItem->m_childItems.insert(position + row, newChildItem);
+ }
+
+ endInsertRows();
+ return true;
+}
+
+
+void insertColumnsRecursive(TreeItem *item, int row, int pos, int cols)
+{
+ for (int col = 0; col < cols; col++)
+ item->m_entries.insert(pos + col, QVariant(QString("%1, %2 (inserted)").arg(row).arg(pos + col)));
+ for (auto child : item->m_childItems) {
+ insertColumnsRecursive(child, row, pos, cols);
+ row++;
+ }
+}
+
+bool TestModel::insertColumns(int position, int cols, const QModelIndex &parent)
+{
+ if (!parent.isValid()) {
+ qWarning() << "Cannot insert columns on an invalid parent!";
+ return false;
+ }
+
+ beginInsertColumns(parent, position, position + cols - 1);
+ TreeItem *parentItem = treeItem(parent);
+
+ TreeItem *item = m_rootItem.data();
+
+ insertColumnsRecursive(item, 0, position, cols);
+ m_columnCount += cols;
+
+ endInsertColumns();
+ return true;
+}
diff --git a/tests/auto/quick/qquicktreeview/testmodel.h b/tests/auto/quick/qquicktreeview/testmodel.h
new file mode 100644
index 0000000000..e12d0ae1d6
--- /dev/null
+++ b/tests/auto/quick/qquicktreeview/testmodel.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef TESTMODEL_H
+#define TESTMODEL_H
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtQuick/qquickview.h>
+
+class TreeItem
+{
+public:
+ explicit TreeItem(TreeItem *parent = nullptr);
+ ~TreeItem();
+
+ int row() const;
+ QVector<TreeItem *> m_childItems;
+ TreeItem *m_parentItem;
+ QVector<QVariant> m_entries;
+};
+
+// ########################################################
+
+class TestModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ explicit TestModel(QObject *parent = nullptr);
+
+ void createTreeRecursive(TreeItem *item, int childCount, int currentDepth);
+ TreeItem *treeItem(const QModelIndex &index) const;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex & = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex &index) const override;
+ int maxDepth() { return 4; }
+
+ bool insertRows(int position, int rows, const QModelIndex &parent) override;
+ bool insertColumns(int position, int cols, const QModelIndex &parent) override;
+
+private:
+ QScopedPointer<TreeItem> m_rootItem;
+ int m_columnCount = 5;
+};
+
+#define TestModelAsVariant(...) QVariant::fromValue(QSharedPointer<TestModel>(new TestModel(__VA_ARGS__)))
+
+#endif // TESTMODEL_H
diff --git a/tests/auto/quick/qquicktreeview/tst_qquicktreeview.cpp b/tests/auto/quick/qquicktreeview/tst_qquicktreeview.cpp
new file mode 100644
index 0000000000..d41d811496
--- /dev/null
+++ b/tests/auto/quick/qquicktreeview/tst_qquicktreeview.cpp
@@ -0,0 +1,1311 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/QtTest>
+#include <QtQuickTest/quicktest.h>
+
+#include <QtQuick/qquickview.h>
+#include <QtQuick/private/qquicktreeview_p.h>
+#include <QtQuick/private/qquicktreeview_p_p.h>
+
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlexpression.h>
+#include <QtQml/qqmlincubator.h>
+#include <QtQmlModels/private/qqmlobjectmodel_p.h>
+#include <QtQmlModels/private/qqmllistmodel_p.h>
+
+#include "testmodel.h"
+
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+
+using namespace QQuickViewTestUtils;
+using namespace QQuickVisualTestUtils;
+
+using namespace Qt::StringLiterals;
+
+#define LOAD_TREEVIEW(fileName) \
+ view->setSource(testFileUrl(fileName)); \
+ view->show(); \
+ view->requestActivate(); \
+ QVERIFY(QTest::qWaitForWindowActive(view)); \
+ auto treeView = view->rootObject()->property("treeView").value<QQuickTreeView *>(); \
+ QVERIFY(treeView); \
+ auto treeViewPrivate = QQuickTreeViewPrivate::get(treeView); \
+ Q_UNUSED(treeViewPrivate) \
+ auto model = treeView->model().value<TestModel *>(); \
+ Q_UNUSED(model)
+
+#define WAIT_UNTIL_POLISHED_ARG(item) \
+ QVERIFY(QQuickTest::qIsPolishScheduled(item)); \
+ QVERIFY(QQuickTest::qWaitForPolish(item))
+#define WAIT_UNTIL_POLISHED WAIT_UNTIL_POLISHED_ARG(treeView)
+
+// ########################################################
+
+class tst_qquicktreeview : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_qquicktreeview();
+
+private:
+ QQuickView *view = nullptr;
+
+private slots:
+ void initTestCase() override;
+ void showTreeView();
+ void invalidArguments();
+ void expandAndCollapseRoot();
+ void toggleExpanded();
+ void expandAndCollapseChildren();
+ void expandChildPendingToBeVisible();
+ void expandRecursivelyRoot_data();
+ void expandRecursivelyRoot();
+ void expandRecursivelyChild_data();
+ void expandRecursivelyChild();
+ void expandRecursivelyWholeTree();
+ void collapseRecursivelyRoot();
+ void collapseRecursivelyChild();
+ void collapseRecursivelyWholeTree();
+ void expandToIndex();
+ void requiredPropertiesRoot();
+ void requiredPropertiesChildren();
+ void emptyModel();
+ void updatedModifiedModel();
+ void insertRows();
+ void insertColumns();
+ void toggleExpandedUsingArrowKeys();
+ void expandAndCollapsUsingDoubleClick();
+ void selectionBehaviorCells_data();
+ void selectionBehaviorCells();
+ void selectionBehaviorRows();
+ void selectionBehaviorColumns();
+ void selectionBehaviorDisabled();
+ void sortTreeModel_data();
+ void sortTreeModel();
+ void sortTreeModelDynamic_data();
+ void sortTreeModelDynamic();
+ void setRootIndex();
+ void setRootIndexToLeaf();
+};
+
+tst_qquicktreeview::tst_qquicktreeview()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
+void tst_qquicktreeview::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ qmlRegisterType<TestModel>("TestModel", 1, 0, "TestModel");
+ view = createView();
+}
+
+void tst_qquicktreeview::showTreeView()
+{
+ LOAD_TREEVIEW("normaltreeview.qml");
+ // Check that the view is showing the root of the tree
+ QCOMPARE(treeViewPrivate->loadedRows.count(), 1);
+}
+
+
+void tst_qquicktreeview::invalidArguments()
+{
+ // Check that we handle gracefully invalid arguments
+ LOAD_TREEVIEW("normaltreeview.qml");
+
+ treeView->expand(-2);
+ QCOMPARE(treeView->rows(), 1);
+ treeView->expandRecursively(200);
+ QCOMPARE(treeView->rows(), 1);
+ treeView->expandRecursively(-2);
+ QCOMPARE(treeView->rows(), 1);
+ treeView->expandRecursively(200);
+ QCOMPARE(treeView->rows(), 1);
+
+ treeView->collapse(-2);
+ QCOMPARE(treeView->rows(), 1);
+ treeView->collapseRecursively(200);
+ QCOMPARE(treeView->rows(), 1);
+ treeView->collapseRecursively(-2);
+ QCOMPARE(treeView->rows(), 1);
+ treeView->collapseRecursively(200);
+ QCOMPARE(treeView->rows(), 1);
+}
+
+void tst_qquicktreeview::expandAndCollapseRoot()
+{
+ LOAD_TREEVIEW("normaltreeview.qml");
+ // Check that the view only has one row loaded so far (the root of the tree)
+ QCOMPARE(treeViewPrivate->loadedRows.count(), 1);
+
+ QSignalSpy expandedSpy(treeView, SIGNAL(expanded(int,int)));
+
+ // Expand the root
+ treeView->expand(0);
+
+ QCOMPARE(expandedSpy.size(), 1);
+ auto signalArgs = expandedSpy.takeFirst();
+ QVERIFY(signalArgs.at(0).toInt() == 0);
+ QVERIFY(signalArgs.at(1).toInt() == 1);
+
+ WAIT_UNTIL_POLISHED;
+ // We now expect 5 rows, the root pluss it's 4 children
+ QCOMPARE(treeViewPrivate->loadedRows.count(), 5);
+
+ treeView->collapse(0);
+ WAIT_UNTIL_POLISHED;
+ // Check that the view only has one row loaded again (the root of the tree)
+ QCOMPARE(treeViewPrivate->loadedRows.count(), 1);
+}
+
+void tst_qquicktreeview::toggleExpanded()
+{
+ LOAD_TREEVIEW("normaltreeview.qml");
+ // Check that the view only has one row loaded so far (the root of the tree)
+ QCOMPARE(treeViewPrivate->loadedRows.count(), 1);
+
+ // Expand the root
+ treeView->toggleExpanded(0);
+ WAIT_UNTIL_POLISHED;
+ // We now expect 5 rows, the root pluss it's 4 children
+ QCOMPARE(treeViewPrivate->loadedRows.count(), 5);
+
+ treeView->toggleExpanded(0);
+ WAIT_UNTIL_POLISHED;
+ // Check that the view only has one row loaded again (the root of the tree)
+ QCOMPARE(treeViewPrivate->loadedRows.count(), 1);
+}
+
+void tst_qquicktreeview::expandAndCollapseChildren()
+{
+ // Check that we can expand and collapse children, and that
+ // the tree ends up with the expected rows
+ LOAD_TREEVIEW("normaltreeview.qml");
+
+ const int childCount = 4;
+ QSignalSpy expandedSpy(treeView, SIGNAL(expanded(int,int)));
+
+ // Expand the last child of a parent recursively four times
+ for (int level = 0; level < 4; ++level) {
+ const int nodeToExpand = level * childCount;
+ const int firstChildRow = nodeToExpand + 1; // (+ 1 for the root)
+ const int lastChildRow = firstChildRow + 4;
+
+ treeView->expand(nodeToExpand);
+
+ QCOMPARE(expandedSpy.size(), 1);
+ auto signalArgs = expandedSpy.takeFirst();
+ QVERIFY(signalArgs.at(0).toInt() == nodeToExpand);
+ QVERIFY(signalArgs.at(1).toInt() == 1);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(treeView->rows(), lastChildRow);
+
+ auto childItem1 = treeViewPrivate->loadedTableItem(QPoint(0, firstChildRow))->item;
+ QCOMPARE(childItem1->property("text").toString(), "0, 0");
+ auto childItem2 = treeViewPrivate->loadedTableItem(QPoint(0, firstChildRow + 1))->item;
+ QCOMPARE(childItem2->property("text").toString(), "1, 0");
+ auto childItem3 = treeViewPrivate->loadedTableItem(QPoint(0, firstChildRow + 2))->item;
+ QCOMPARE(childItem3->property("text").toString(), "2, 0");
+ }
+
+ // Collapse down from level 2 (deliberatly not mirroring the expansion by
+ // instead collapsing both level 3 and 4 in one go)
+ for (int level = 2; level > 0; --level) {
+ const int nodeToCollapse = level * childCount;
+ const int firstChildRow = nodeToCollapse - childCount + 1;
+ const int lastChildRow = nodeToCollapse + 1; // (+ 1 for the root)
+
+ treeView->collapse(nodeToCollapse);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(treeView->rows(), lastChildRow);
+
+ auto childItem1 = treeViewPrivate->loadedTableItem(QPoint(0, firstChildRow))->item;
+ QCOMPARE(childItem1->property("text").toString(), "0, 0");
+ auto childItem2 = treeViewPrivate->loadedTableItem(QPoint(0, firstChildRow + 1))->item;
+ QCOMPARE(childItem2->property("text").toString(), "1, 0");
+ auto childItem3 = treeViewPrivate->loadedTableItem(QPoint(0, firstChildRow + 2))->item;
+ QCOMPARE(childItem3->property("text").toString(), "2, 0");
+ }
+
+ // Collapse the root
+ treeView->collapse(0);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(treeView->rows(), 1);
+}
+
+void tst_qquicktreeview::requiredPropertiesRoot()
+{
+ LOAD_TREEVIEW("normaltreeview.qml");
+ QCOMPARE(treeViewPrivate->loadedRows.count(), 1);
+
+ const auto rootFxItem = treeViewPrivate->loadedTableItem(QPoint(0, 0));
+ QVERIFY(rootFxItem);
+ const auto rootItem = rootFxItem->item;
+ QVERIFY(rootItem);
+
+ const auto context = qmlContext(rootItem.data());
+ const auto viewProp = context->contextProperty("treeView").value<QQuickTreeView *>();
+ const auto isTreeNode = context->contextProperty("isTreeNode").toBool();
+ const auto expanded = context->contextProperty("expanded").toBool();
+ const auto hasChildren = context->contextProperty("hasChildren").toBool();
+ const auto depth = context->contextProperty("depth").toInt();
+
+ QCOMPARE(viewProp, treeView);
+ QCOMPARE(isTreeNode, true);
+ QCOMPARE(expanded, false);
+ QCOMPARE(hasChildren, true);
+ QCOMPARE(depth, 0);
+
+ treeView->expand(0);
+ WAIT_UNTIL_POLISHED;
+
+ const auto isExpandedAfterExpand = context->contextProperty("expanded").toBool();
+ QCOMPARE(isExpandedAfterExpand, true);
+}
+
+void tst_qquicktreeview::requiredPropertiesChildren()
+{
+ LOAD_TREEVIEW("normaltreeview.qml");
+ treeView->expand(0);
+ WAIT_UNTIL_POLISHED;
+ // We now expect 5 rows, the root pluss it's 4 children
+ QCOMPARE(treeViewPrivate->loadedRows.count(), 5);
+
+ // The last child has it's own children, so expand that one as well
+ const auto rootIndex = model->index(0, 0);
+ const int childCount = model->rowCount(rootIndex);
+ QCOMPARE(childCount, 4);
+ const auto lastChildIndex = model->index(childCount - 1, 0, rootIndex);
+ QVERIFY(lastChildIndex.isValid());
+ QCOMPARE(model->hasChildren(lastChildIndex), true);
+
+ treeView->expand(4);
+ WAIT_UNTIL_POLISHED;
+ // We now expect root + 4 children + 4 children = 9 rows
+ const int rowCount = treeViewPrivate->loadedRows.count();
+ QCOMPARE(rowCount, 9);
+
+ // Go through all rows in the view, except the root
+ for (int row = 1; row < rowCount; ++row) {
+ const auto childFxItem = treeViewPrivate->loadedTableItem(QPoint(0, row));
+ QVERIFY(childFxItem);
+ const auto childItem = childFxItem->item;
+ QVERIFY(childItem);
+
+ const auto context = qmlContext(childItem.data());
+ const auto viewProp = context->contextProperty("treeView").value<QQuickTreeView *>();
+ const auto isTreeNode = context->contextProperty("isTreeNode").toBool();
+ const auto expanded = context->contextProperty("expanded").toBool();
+ const auto hasChildren = context->contextProperty("hasChildren").toBool();
+ const auto depth = context->contextProperty("depth").toInt();
+
+ QCOMPARE(viewProp, treeView);
+ QCOMPARE(isTreeNode, true);
+ QCOMPARE(expanded, row == 4);
+ QCOMPARE(hasChildren, model->hasChildren(treeView->index(row, 0)));
+ QCOMPARE(depth, row <= 4 ? 1 : 2);
+ }
+}
+
+void tst_qquicktreeview::emptyModel()
+{
+ // Check that you can assign an empty model, and that
+ // calling functions will work as expected (and at least not crash)
+ LOAD_TREEVIEW("normaltreeview.qml");
+ treeView->setModel(QVariant());
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(treeViewPrivate->loadedItems.size(), 0);
+ QCOMPARE(treeView->rows(), 0);
+ QCOMPARE(treeView->columns(), 0);
+
+ // Check that we don't crash:
+ treeView->expand(10);
+ treeView->collapse(5);
+
+ QCOMPARE(treeView->depth(0), -1);
+ QCOMPARE(treeView->isExpanded(0), false);
+ QVERIFY(!treeView->index(10, 10).isValid());
+ QCOMPARE(treeView->rowAtIndex(QModelIndex()), -1);
+ QCOMPARE(treeView->columnAtIndex(QModelIndex()), -1);
+}
+
+void tst_qquicktreeview::updatedModifiedModel()
+{
+ // Check that if we change the data in the model, the
+ // delegate items get updated.
+ LOAD_TREEVIEW("normaltreeview.qml");
+ treeView->expand(0);
+ WAIT_UNTIL_POLISHED;
+ // We now expect 5 rows, the root plus it's 4 children
+ QCOMPARE(treeViewPrivate->loadedRows.count(), 5);
+
+ auto rootFxItem = treeViewPrivate->loadedTableItem(QPoint(0, 0));
+ QVERIFY(rootFxItem);
+ auto rootItem = rootFxItem->item;
+ QVERIFY(rootItem);
+ QCOMPARE(rootItem->property("text"), "0, 0");
+ model->setData(model->index(0, 0), QVariant(QString("Changed")));
+ QCOMPARE(rootItem->property("text"), "Changed");
+
+ auto rootFxItemCol1 = treeViewPrivate->loadedTableItem(QPoint(1, 2));
+ QVERIFY(rootFxItemCol1);
+ auto rootItemCol1 = rootFxItemCol1->item;
+ QVERIFY(rootItemCol1);
+ QCOMPARE(rootItemCol1->property("text"), "1, 1");
+ model->setData(model->index(1, 1, model->index(0,0)), QVariant(QString("Changed")));
+ QCOMPARE(rootItemCol1->property("text"), "Changed");
+}
+
+void tst_qquicktreeview::insertRows()
+{
+ // Check that if we add new rows to the model, TreeView gets updated
+ // to contain the new expected number of rows (flattened to a list)
+ LOAD_TREEVIEW("normaltreeview.qml");
+ treeView->expand(0);
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(treeView->rows(), 5);
+
+ const QModelIndex rootNode = model->index(0, 0, QModelIndex());
+ model->insertRows(0, 2, rootNode);
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(treeView->rows(), 7);
+ auto childItem1 = treeViewPrivate->loadedTableItem(QPoint(0, 1))->item;
+ QCOMPARE(childItem1->property("text").toString(), "0, 0 (inserted)");
+ auto childItem2 = treeViewPrivate->loadedTableItem(QPoint(0, 2))->item;
+ QCOMPARE(childItem2->property("text").toString(), "1, 0 (inserted)");
+ auto childItem3 = treeViewPrivate->loadedTableItem(QPoint(0, 3))->item;
+ QCOMPARE(childItem3->property("text").toString(), "0, 0");
+
+ const QModelIndex indexOfInsertedChild = model->index(1, 0, rootNode);
+ model->insertRows(0, 2, indexOfInsertedChild);
+ treeView->expand(2);
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(treeView->rows(), 9);
+}
+
+void tst_qquicktreeview::insertColumns()
+{
+ // Check that if we add new columns to the model, TreeView gets updated
+ // to contain the new expected number of rows (flattened to a list)
+ LOAD_TREEVIEW("normaltreeview.qml");
+ treeView->expand(0);
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(treeView->columns(), 5);
+
+ const QModelIndex rootNode = model->index(0, 0, QModelIndex());
+ model->insertColumns(0, 2, rootNode);
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(treeView->columns(), 7);
+ auto childItem1 = treeViewPrivate->loadedTableItem(QPoint(0, 1))->item;
+ QCOMPARE(childItem1->property("text").toString(), "0, 0 (inserted)");
+ auto childItem2 = treeViewPrivate->loadedTableItem(QPoint(0, 2))->item;
+ QCOMPARE(childItem2->property("text").toString(), "1, 0 (inserted)");
+ auto childItem3 = treeViewPrivate->loadedTableItem(QPoint(0, 3))->item;
+ QCOMPARE(childItem3->property("text").toString(), "2, 0 (inserted)");
+ auto childItem4 = treeViewPrivate->loadedTableItem(QPoint(3, 0))->item;
+ QCOMPARE(childItem4->property("text").toString(), "0, 1");
+ auto childItem5 = treeViewPrivate->loadedTableItem(QPoint(3, 1))->item;
+ QCOMPARE(childItem5->property("text").toString(), "0, 1");
+
+ const QModelIndex indexOfInsertedChild = model->index(1, 0, rootNode);
+ model->insertRows(0, 2, indexOfInsertedChild);
+ treeView->expand(2);
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(treeView->rows(), 7);
+ QCOMPARE(treeView->columns(), 7);
+
+ for (int i = 0; i < 7; i++) {
+ for (int j = 0; j < 7; j++) {
+ auto childItem = treeViewPrivate->loadedTableItem(QPoint(j, i))->item;
+ QVERIFY(childItem);
+ }
+ }
+}
+
+void tst_qquicktreeview::expandChildPendingToBeVisible()
+{
+ // Check that if we expand a row r1, and that row has a child r2 that can
+ // be expanded, we can continue to expand c2 immediately, even if r1 is
+ // still pending to be shown as expanded in the view.
+ LOAD_TREEVIEW("normaltreeview.qml");
+ treeView->expand(0);
+ QVERIFY(treeView->isExpanded(0));
+ // The view has not yet been updated at this point to show
+ // the newly expanded children, so it still has only one row.
+ QCOMPARE(treeView->rows(), 1);
+ // ...but we still expand row 5, which is a child that has children
+ // in the proxy model
+ treeView->expand(4);
+ QVERIFY(treeView->isExpanded(4));
+ QCOMPARE(treeView->rows(), 1);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Now the view have updated to show
+ // all the rows that has been expanded.
+ QCOMPARE(treeView->rows(), 9);
+}
+
+void tst_qquicktreeview::expandRecursivelyRoot_data()
+{
+ QTest::addColumn<int>("rowToExpand");
+ QTest::addColumn<int>("depth");
+
+ QTest::newRow("0, -1") << 0 << -1;
+ QTest::newRow("0, 0") << 0 << 0;
+ QTest::newRow("0, 1") << 0 << 1;
+ QTest::newRow("0, 2") << 0 << 2;
+}
+
+void tst_qquicktreeview::expandRecursivelyRoot()
+{
+ // Check that we can expand the root node (row 0), and that
+ // all its children are expanded recursively down to the
+ // given depth.
+ QFETCH(int, rowToExpand);
+ QFETCH(int, depth);
+
+ LOAD_TREEVIEW("normaltreeview.qml");
+ QSignalSpy spy(treeView, SIGNAL(expanded(int,int)));
+
+ treeView->expandRecursively(rowToExpand, depth);
+
+ if (depth == 0) {
+ QCOMPARE(spy.size(), 0);
+ } else {
+
+ QCOMPARE(spy.size(), 1);
+ const auto signalArgs = spy.takeFirst();
+ QVERIFY(signalArgs.at(0).toInt() == rowToExpand);
+ QVERIFY(signalArgs.at(1).toInt() == depth);
+ }
+
+ WAIT_UNTIL_POLISHED;
+
+ const int rowToExpandDepth = treeView->depth(rowToExpand);
+ const int effectiveMaxDepth = depth != -1 ? rowToExpandDepth + depth : model->maxDepth();
+
+ if (depth > 0 || depth == -1)
+ QVERIFY(treeView->isExpanded(rowToExpand));
+ else
+ QVERIFY(!treeView->isExpanded(rowToExpand));
+
+ // Check that all rows after rowToExpand, that are also
+ // children of that row, is expanded (down to depth)
+ for (int currentRow = rowToExpand + 1; currentRow < treeView->rows(); ++currentRow) {
+ const auto modelIndex = treeView->index(currentRow, 0);
+ const int currentDepth = treeView->depth(currentRow);
+ const bool isChild = currentDepth > rowToExpandDepth;
+ const bool isExpandable = model->rowCount(modelIndex) > 0;
+ const bool shouldBeExpanded = isChild && isExpandable && currentDepth < effectiveMaxDepth;
+ QCOMPARE(treeView->isExpanded(currentRow), shouldBeExpanded);
+ }
+}
+
+void tst_qquicktreeview::expandRecursivelyChild_data()
+{
+ QTest::addColumn<int>("rowToExpand");
+ QTest::addColumn<int>("depth");
+
+ QTest::newRow("5, -1") << 4 << -1;
+ QTest::newRow("5, 0") << 4 << 0;
+ QTest::newRow("5, 1") << 4 << 1;
+ QTest::newRow("5, 2") << 4 << 2;
+ QTest::newRow("5, 3") << 4 << 3;
+}
+
+void tst_qquicktreeview::expandRecursivelyChild()
+{
+ // Check that we can first expand the root node, and the expand
+ // recursive the first child node with children (row 4), and that all
+ // its children of that node are expanded recursively according to depth.
+ QFETCH(int, rowToExpand);
+ QFETCH(int, depth);
+
+ LOAD_TREEVIEW("normaltreeview.qml");
+ QSignalSpy spy(treeView, SIGNAL(expanded(int,int)));
+
+ treeView->expand(0);
+
+ QCOMPARE(spy.size(), 1);
+ auto signalArgs = spy.takeFirst();
+ QVERIFY(signalArgs.at(0).toInt() == 0);
+ QVERIFY(signalArgs.at(1).toInt() == 1);
+
+ treeView->expandRecursively(rowToExpand, depth);
+
+ if (depth == 0) {
+ QCOMPARE(spy.size(), 0);
+ } else {
+ QCOMPARE(spy.size(), 1);
+ signalArgs = spy.takeFirst();
+ QVERIFY(signalArgs.at(0).toInt() == rowToExpand);
+ QVERIFY(signalArgs.at(1).toInt() == depth);
+ }
+
+ WAIT_UNTIL_POLISHED;
+
+ const int rowToExpandDepth = treeView->depth(rowToExpand);
+ const int effectiveMaxDepth = depth != -1 ? rowToExpandDepth + depth : model->maxDepth();
+
+ // Check that none of the rows before rowToExpand are expanded
+ // (except the root node)
+ for (int currentRow = 1; currentRow < rowToExpand; ++currentRow)
+ QVERIFY(!treeView->isExpanded(currentRow));
+
+ // Check if rowToExpand is expanded
+ if (depth > 0 || depth == -1)
+ QVERIFY(treeView->isExpanded(rowToExpand));
+ else
+ QVERIFY(!treeView->isExpanded(rowToExpand));
+
+ // Check that any row after rowToExpand, that is also
+ // a child of that row, is expanded (down to depth)
+ for (int currentRow = rowToExpand + 1; currentRow < treeView->rows(); ++currentRow) {
+ const int currentDepth = treeView->depth(currentRow);
+ const bool isChild = currentDepth > rowToExpandDepth;
+ const auto modelIndex = treeView->index(currentRow, 0);
+ const bool isExpandable = model->rowCount(modelIndex) > 0;
+ const bool shouldBeExpanded = isChild && isExpandable && currentDepth < effectiveMaxDepth;
+ QCOMPARE(treeView->isExpanded(currentRow), shouldBeExpanded);
+ }
+}
+
+void tst_qquicktreeview::expandRecursivelyWholeTree()
+{
+ // Check that we expand the whole tree recursively by passing -1, -1
+ LOAD_TREEVIEW("normaltreeview.qml");
+ QSignalSpy spy(treeView, SIGNAL(expanded(int,int)));
+ treeView->expandRecursively(-1, -1);
+
+ QCOMPARE(spy.size(), 1);
+ auto signalArgs = spy.takeFirst();
+ QVERIFY(signalArgs.at(0).toInt() == -1);
+ QVERIFY(signalArgs.at(1).toInt() == -1);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Check that all rows that have children are expanded
+ for (int currentRow = 0; currentRow < treeView->rows(); ++currentRow) {
+ const auto modelIndex = treeView->index(currentRow, 0);
+ const bool isExpandable = model->rowCount(modelIndex) > 0;
+ QCOMPARE(treeView->isExpanded(currentRow), isExpandable);
+ }
+}
+
+void tst_qquicktreeview::collapseRecursivelyRoot()
+{
+ // Check that we can collapse the root node (row 0), and that
+ // all its children are collapsed recursively down to the leaves.
+ LOAD_TREEVIEW("normaltreeview.qml");
+ treeView->expandRecursively();
+ WAIT_UNTIL_POLISHED;
+
+ // Verify that the tree is now fully expanded
+ // The number of rows should be the root, + 4 children per level. All parents
+ // (minus the root), will also have a node with 4 non-recursive children.
+ const int expectedRowCount = 1 + (model->maxDepth() * 8) - 4;
+ QCOMPARE(treeView->rows(), expectedRowCount);
+
+ QSignalSpy spy(treeView, SIGNAL(collapsed(int,bool)));
+
+ // Collapse the whole tree again. This time, only the root should end up visible
+ treeView->collapseRecursively();
+
+ QCOMPARE(spy.size(), 1);
+ const auto signalArgs = spy.takeFirst();
+ QVERIFY(signalArgs.at(0).toInt() == -1);
+ QVERIFY(signalArgs.at(1).toBool() == true);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(treeView->rows(), 1);
+
+ // We need to check that all descendants are collapsed as well. But since they're
+ // now no longer visible in the view, we need to expand each parent one by one again to make
+ // them visible, and check that the child inside that has children is still collapsed.
+ // We can do that by simply iterate over the rows in the view as we expand.
+ int currentRow = 0;
+ while (currentRow < treeView->rows()) {
+ const QModelIndex currentIndex = treeView->index(currentRow, 0);
+ if (model->hasChildren(currentIndex)) {
+ QVERIFY(!treeView->isExpanded(currentRow));
+ treeView->expand(currentRow);
+ WAIT_UNTIL_POLISHED;
+ }
+ currentRow++;
+ }
+
+ // Sanity check that we ended up with all rows expanded again
+ QCOMPARE(currentRow, expectedRowCount);
+}
+
+void tst_qquicktreeview::collapseRecursivelyChild()
+{
+ // Check that we can collapse a child node (row 4), and that all its children
+ // are collapsed recursively down to the leaves (without touching the root).
+ LOAD_TREEVIEW("normaltreeview.qml");
+ treeView->expandRecursively();
+ WAIT_UNTIL_POLISHED;
+
+ // Verify that the tree is now fully expanded
+ // The number of rows should be the root, + 4 children per level. All parents
+ // (minus the root), will also have a node with 4 non-recursive children.
+ const int expectedRowCount = 1 + (model->maxDepth() * 8) - 4;
+ QCOMPARE(treeView->rows(), expectedRowCount);
+
+ QSignalSpy spy(treeView, SIGNAL(collapsed(int,bool)));
+
+ // Collapse the 8th child recursive
+ const int rowToCollapse = 8;
+ const QModelIndex collapseIndex = treeView->index(rowToCollapse, 0);
+ const auto expectedLabel = model->data(collapseIndex, Qt::DisplayRole);
+ QCOMPARE(expectedLabel, QStringLiteral("3, 0"));
+ treeView->collapseRecursively(rowToCollapse);
+
+ QCOMPARE(spy.size(), 1);
+ const auto signalArgs = spy.takeFirst();
+ QVERIFY(signalArgs.at(0).toInt() == rowToCollapse);
+ QVERIFY(signalArgs.at(1).toBool() == true);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(treeView->rows(), 9); // root + 4 children + 4 grand children of the 3rd row
+
+ // We need to check that all descendants are collapsed as well. But since they're
+ // now no longer visible in the view, we need to expand each parent one by one again to make
+ // them visible, and check that the child inside that has children is still collapsed.
+ // We can do that by simply iterate over the rows in the view as we expand.
+ int currentRow = 1; // start at first child
+ while (currentRow < treeView->rows()) {
+ const QModelIndex currentIndex = treeView->index(currentRow, 0);
+ if (model->hasChildren(currentIndex)) {
+ if (treeView->depth(currentRow) == 1 && currentIndex.row() == 2) {
+ // We did only recursively expand the 4th child, so the
+ // third should still be expanded
+ QVERIFY(treeView->isExpanded(currentRow));
+ } else {
+ QVERIFY(!treeView->isExpanded(currentRow));
+ treeView->expand(currentRow);
+ WAIT_UNTIL_POLISHED;
+ }
+ }
+ currentRow++;
+ }
+
+ // Sanity check that we ended up with all rows expanded again
+ QCOMPARE(currentRow, expectedRowCount);
+}
+
+void tst_qquicktreeview::collapseRecursivelyWholeTree()
+{
+ // Check that we collapse the whole tree recursively by passing -1
+ LOAD_TREEVIEW("normaltreeview.qml");
+ QSignalSpy spy(treeView, SIGNAL(collapsed(int,bool)));
+ treeView->expandRecursively();
+ treeView->collapseRecursively();
+
+ QCOMPARE(spy.size(), 1);
+ auto signalArgs = spy.takeFirst();
+ QVERIFY(signalArgs.at(0).toInt() == -1);
+ QVERIFY(signalArgs.at(1).toBool() == true);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(treeView->rows(), 1); // root
+}
+
+void tst_qquicktreeview::expandToIndex()
+{
+ // Check that expandToIndex(index) expands the tree so
+ // that index becomes visible in the view
+ LOAD_TREEVIEW("normaltreeview.qml");
+ QSignalSpy spy(treeView, SIGNAL(expanded(int,int)));
+
+ const QModelIndex root = model->index(0, 0);
+ const QModelIndex child1 = model->index(3, 0, root);
+ const QModelIndex child2 = model->index(3, 0, child1);
+
+ QVERIFY(model->hasChildren(root));
+ QVERIFY(model->hasChildren(child1));
+ QVERIFY(model->hasChildren(child2));
+
+ QVERIFY(!treeView->isExpanded(treeView->rowAtIndex(root)));
+ QVERIFY(!treeView->isExpanded(treeView->rowAtIndex(child1)));
+ QVERIFY(!treeView->isExpanded(treeView->rowAtIndex(child2)));
+
+ const QModelIndex childToExpand = model->index(1, 0, child2);
+ treeView->expandToIndex(childToExpand);
+
+ QVERIFY(treeView->isExpanded(treeView->rowAtIndex(root)));
+ QVERIFY(treeView->isExpanded(treeView->rowAtIndex(child1)));
+ QVERIFY(treeView->isExpanded(treeView->rowAtIndex(child2)));
+
+ QCOMPARE(spy.size(), 1);
+ auto signalArgs = spy.takeFirst();
+ QVERIFY(signalArgs.at(0).toInt() == 0);
+ QVERIFY(signalArgs.at(1).toInt() == 3);
+
+ WAIT_UNTIL_POLISHED;
+
+ // The view should now have 13 rows:
+ // root + 3 expanded nodes that each have 4 children
+ QCOMPARE(treeView->rows(), 13);
+}
+
+void tst_qquicktreeview::toggleExpandedUsingArrowKeys()
+{
+ // Check that you can use the left and right arrow key to
+ // expand and collapse nodes in the tree.
+ LOAD_TREEVIEW("normaltreeview.qml");
+
+ treeView->setFocus(true);
+ QQuickWindow *window = treeView->window();
+
+ // Start by making cell 0, 0 current
+ treeView->selectionModel()->setCurrentIndex(treeView->index(0, 0), QItemSelectionModel::NoUpdate);
+
+ // Expand row 0
+ const int row0 = 0;
+ QCOMPARE(treeView->rows(), 1);
+ QVERIFY(!treeView->isExpanded(row0));
+ QTest::keyPress(window, Qt::Key_Right);
+ QVERIFY(treeView->isExpanded(row0));
+
+ // A polish event was scheduled, but since the call to keyPress() processes
+ // events, WAIT_UNTIL_POLISHED will be unreliable. So use QTRY_COMPARE instead.
+ QTRY_COMPARE(treeView->rows(), 5);
+
+ // Hitting Key_Right again should be a no-op
+ QTest::keyPress(window, Qt::Key_Right);
+ QVERIFY(treeView->isExpanded(row0));
+ QCOMPARE(treeView->selectionModel()->currentIndex(), treeView->index(row0, 0));
+
+ // Move down to row 1 and try to expand it. Since Row 1
+ // doesn't have children, expanding it will be a no-op.
+ // And also, it shouldn't move currentIndex to the next
+ // column either, it should stay in the tree column.
+ const int row1 = 1;
+ QVERIFY(!treeView->isExpanded(row1));
+ QTest::keyPress(window, Qt::Key_Down);
+ QTest::keyPress(window, Qt::Key_Right);
+ QVERIFY(!treeView->isExpanded(row1));
+ QCOMPARE(treeView->selectionModel()->currentIndex(), treeView->index(row1, 0));
+
+ // Move down to row 4 and expand it
+ const int row4 = 4;
+ QCOMPARE(treeView->rows(), 5);
+ while (treeView->currentRow() != row4)
+ QTest::keyPress(window, Qt::Key_Down);
+ QVERIFY(!treeView->isExpanded(row4));
+ QTest::keyPress(window, Qt::Key_Right);
+ QVERIFY(treeView->isExpanded(row4));
+ QCOMPARE(treeView->selectionModel()->currentIndex(), treeView->index(row4, 0));
+
+ // Move up again to row 0 and collapse it
+ while (treeView->currentRow() != row0)
+ QTest::keyPress(window, Qt::Key_Up);
+ QVERIFY(treeView->isExpanded(row0));
+ QTest::keyPress(window, Qt::Key_Left);
+ QVERIFY(!treeView->isExpanded(row0));
+ QTRY_COMPARE(treeView->rows(), 1);
+
+ // Hitting Key_Left again should be a no-op
+ QTest::keyPress(window, Qt::Key_Left);
+ QVERIFY(!treeView->isExpanded(row0));
+ QCOMPARE(treeView->selectionModel()->currentIndex(), treeView->index(row0, 0));
+}
+
+void tst_qquicktreeview::expandAndCollapsUsingDoubleClick()
+{
+ LOAD_TREEVIEW("normaltreeview.qml");
+ // Check that the view only has one row loaded so far (the root of the tree)
+ QCOMPARE(treeViewPrivate->loadedRows.count(), 1);
+
+ // Expand the root by double clicking on the row
+ const auto item = treeView->itemAtIndex(treeView->index(0, 0));
+ QVERIFY(item);
+ const QPoint localPos = QPoint(item->width() / 2, item->height() / 2);
+ const QPoint pos = item->window()->contentItem()->mapFromItem(item, localPos).toPoint();
+ QTest::mouseDClick(item->window(), Qt::LeftButton, Qt::NoModifier, pos);
+
+ // We now expect 5 rows, the root pluss it's 4 children. Since
+ // mouseDClick calls processEvents(), it becomes random at this
+ // point if the view has been polished or not. So use QTRY_COMPARE.
+ QTRY_COMPARE(treeViewPrivate->loadedRows.count(), 5);
+
+ // Collapse the root again
+ QTest::mouseDClick(item->window(), Qt::LeftButton, Qt::NoModifier, pos);
+ QTRY_COMPARE(treeViewPrivate->loadedRows.count(), 1);
+
+ // If edit triggers has DoubleTapped set, we should
+ // start to edit instead of expanding.
+ treeView->setEditTriggers(QQuickTableView::DoubleTapped);
+ QTest::mouseDClick(item->window(), Qt::LeftButton, Qt::NoModifier, pos);
+ if (QQuickTest::qIsPolishScheduled(treeView))
+ QVERIFY(QQuickTest::qWaitForPolish(treeView));
+ QTRY_COMPARE(treeViewPrivate->loadedRows.count(), 1);
+}
+
+void tst_qquicktreeview::selectionBehaviorCells_data()
+{
+ QTest::addColumn<QPoint>("startCell");
+ QTest::addColumn<QPoint>("endCellDist");
+
+ QTest::newRow("QPoint(0, 0), QPoint(0, 0)") << QPoint(0, 0) << QPoint(0, 0);
+
+ QTest::newRow("QPoint(0, 1), QPoint(0, 1)") << QPoint(0, 1) << QPoint(0, 1);
+ QTest::newRow("QPoint(0, 2), QPoint(0, 2)") << QPoint(0, 2) << QPoint(0, 2);
+
+ QTest::newRow("QPoint(2, 2), QPoint(0, 0)") << QPoint(2, 2) << QPoint(0, 0);
+ QTest::newRow("QPoint(2, 2), QPoint(1, 0)") << QPoint(2, 2) << QPoint(1, 0);
+ QTest::newRow("QPoint(2, 2), QPoint(2, 0)") << QPoint(2, 2) << QPoint(2, 0);
+ QTest::newRow("QPoint(2, 2), QPoint(-1, 0)") << QPoint(2, 2) << QPoint(-1, 0);
+ QTest::newRow("QPoint(2, 2), QPoint(-2, 0)") << QPoint(2, 2) << QPoint(-2, 0);
+ QTest::newRow("QPoint(2, 2), QPoint(0, 1)") << QPoint(2, 2) << QPoint(0, 1);
+ QTest::newRow("QPoint(2, 2), QPoint(0, 2)") << QPoint(2, 2) << QPoint(0, 2);
+ QTest::newRow("QPoint(2, 2), QPoint(0, -1)") << QPoint(2, 2) << QPoint(0, -1);
+ QTest::newRow("QPoint(2, 2), QPoint(0, -2)") << QPoint(2, 2) << QPoint(0, -2);
+
+ QTest::newRow("QPoint(2, 2), QPoint(1, 1)") << QPoint(2, 2) << QPoint(1, 1);
+ QTest::newRow("QPoint(2, 2), QPoint(1, 2)") << QPoint(2, 2) << QPoint(1, 2);
+ QTest::newRow("QPoint(2, 2), QPoint(1, -1)") << QPoint(2, 2) << QPoint(1, -1);
+ QTest::newRow("QPoint(2, 2), QPoint(1, -2)") << QPoint(2, 2) << QPoint(1, -2);
+
+ QTest::newRow("QPoint(2, 2), QPoint(-1, 1)") << QPoint(2, 2) << QPoint(-1, 1);
+ QTest::newRow("QPoint(2, 2), QPoint(-1, 2)") << QPoint(2, 2) << QPoint(-1, 2);
+ QTest::newRow("QPoint(2, 2), QPoint(-1, -1)") << QPoint(2, 2) << QPoint(-1, -1);
+ QTest::newRow("QPoint(2, 2), QPoint(-1, -2)") << QPoint(2, 2) << QPoint(-1, -2);
+}
+
+void tst_qquicktreeview::selectionBehaviorCells()
+{
+ // Check that the TreeView implement the overridden updateSelection()
+ // function correctly wrt QQuickTableView::SelectCells.
+ QFETCH(QPoint, startCell);
+ QFETCH(QPoint, endCellDist);
+ LOAD_TREEVIEW("normaltreeview.qml");
+
+ const auto selectionModel = treeView->selectionModel();
+ treeView->expand(0);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(selectionModel->hasSelection(), false);
+ treeView->setSelectionBehavior(QQuickTableView::SelectCells);
+
+ const QPoint endCell = startCell + endCellDist;
+ const QPoint endCellWrapped = startCell - endCellDist;
+
+ const QQuickItem *startItem = treeView->itemAtCell(startCell);
+ const QQuickItem *endItem = treeView->itemAtCell(endCell);
+ const QQuickItem *endItemWrapped = treeView->itemAtCell(endCellWrapped);
+ QVERIFY(startItem);
+ QVERIFY(endItem);
+ QVERIFY(endItemWrapped);
+
+ const QPointF startPos(startItem->x(), startItem->y());
+ const QPointF endPos(endItem->x(), endItem->y());
+ const QPointF endPosWrapped(endItemWrapped->x(), endItemWrapped->y());
+
+ QVERIFY(treeViewPrivate->startSelection(startPos, Qt::NoModifier));
+ treeViewPrivate->setSelectionStartPos(startPos);
+ treeViewPrivate->setSelectionEndPos(endPos);
+
+ QCOMPARE(selectionModel->hasSelection(), true);
+
+ const int x1 = qMin(startCell.x(), endCell.x());
+ const int x2 = qMax(startCell.x(), endCell.x());
+ const int y1 = qMin(startCell.y(), endCell.y());
+ const int y2 = qMax(startCell.y(), endCell.y());
+
+ for (int x = x1; x < x2; ++x) {
+ for (int y = y1; y < y2; ++y) {
+ const auto index = treeView->index(y, x);
+ QVERIFY(selectionModel->isSelected(index));
+ }
+ }
+
+ const int expectedCount = (x2 - x1 + 1) * (y2 - y1 + 1);
+ const int actualCount = selectionModel->selectedIndexes().size();
+ QCOMPARE(actualCount, expectedCount);
+
+ // Wrap the selection
+ treeViewPrivate->setSelectionEndPos(endPosWrapped);
+
+ for (int x = x2; x < x1; ++x) {
+ for (int y = y2; y < y1; ++y) {
+ const auto index = model->index(y, x);
+ QVERIFY(selectionModel->isSelected(index));
+ }
+ }
+
+ const int actualCountAfterWrap = selectionModel->selectedIndexes().size();
+ QCOMPARE(actualCountAfterWrap, expectedCount);
+
+ treeViewPrivate->clearSelection();
+ QCOMPARE(selectionModel->hasSelection(), false);
+}
+
+void tst_qquicktreeview::selectionBehaviorRows()
+{
+ // Check that the TreeView implement the overridden updateSelection()
+ // function correctly wrt QQuickTableView::SelectionRows.
+ LOAD_TREEVIEW("normaltreeview.qml");
+
+ const auto selectionModel = treeView->selectionModel();
+ QCOMPARE(treeView->selectionBehavior(), QQuickTableView::SelectRows);
+ treeView->expand(0);
+ treeView->setInteractive(false);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(selectionModel->hasSelection(), false);
+
+ // Drag from row 0 to row 3
+ QVERIFY(treeViewPrivate->startSelection(QPointF(0, 0), Qt::NoModifier));
+ treeViewPrivate->setSelectionStartPos(QPointF(0, 0));
+ treeViewPrivate->setSelectionEndPos(QPointF(80, 60));
+
+ QCOMPARE(selectionModel->hasSelection(), true);
+
+ const int expectedCount = treeView->columns() * 3; // all columns * three rows
+ int actualCount = selectionModel->selectedIndexes().size();
+ QCOMPARE(actualCount, expectedCount);
+
+ for (int x = 0; x < treeView->columns(); ++x) {
+ for (int y = 0; y < 3; ++y) {
+ const auto index = treeView->index(y, x);
+ QVERIFY(selectionModel->isSelected(index));
+ }
+ }
+
+ selectionModel->clear();
+ QCOMPARE(selectionModel->hasSelection(), false);
+
+ // Drag from row 3 to row 0 (and overshoot mouse)
+ QVERIFY(treeViewPrivate->startSelection(QPointF(80, 60), Qt::NoModifier));
+ treeViewPrivate->setSelectionStartPos(QPointF(80, 60));
+ treeViewPrivate->setSelectionEndPos(QPointF(-10, -10));
+
+ QCOMPARE(selectionModel->hasSelection(), true);
+
+ actualCount = selectionModel->selectedIndexes().size();
+ QCOMPARE(actualCount, expectedCount);
+
+ for (int x = 0; x < treeView->columns(); ++x) {
+ for (int y = 0; y < 3; ++y) {
+ const auto index = treeView->index(y, x);
+ QVERIFY(selectionModel->isSelected(index));
+ }
+ }
+}
+
+void tst_qquicktreeview::selectionBehaviorColumns()
+{
+ // Check that the TreeView implement the overridden updateSelection()
+ // function correctly wrt QQuickTableView::SelectColumns.
+ LOAD_TREEVIEW("normaltreeview.qml");
+
+ const auto selectionModel = treeView->selectionModel();
+ treeView->setSelectionBehavior(QQuickTableView::SelectColumns);
+ treeView->expand(0);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(selectionModel->hasSelection(), false);
+
+ // Drag from column 0 to column 3
+ QVERIFY(treeViewPrivate->startSelection(QPointF(0, 0), Qt::NoModifier));
+ treeViewPrivate->setSelectionStartPos(QPointF(0, 0));
+ treeViewPrivate->setSelectionEndPos(QPointF(225, 90));
+
+ QCOMPARE(selectionModel->hasSelection(), true);
+
+ const int expectedCount = treeView->rows() * 3; // all rows * three columns
+ int actualCount = selectionModel->selectedIndexes().size();
+ QCOMPARE(actualCount, expectedCount);
+
+ for (int x = 0; x < 3; ++x) {
+ for (int y = 0; y < treeView->rows(); ++y) {
+ const auto index = treeView->index(y, x);
+ QVERIFY(selectionModel->isSelected(index));
+ }
+ }
+
+ selectionModel->clear();
+ QCOMPARE(selectionModel->hasSelection(), false);
+
+ // Drag from column 3 to column 0 (and overshoot mouse)
+ QVERIFY(treeViewPrivate->startSelection(QPointF(225, 90), Qt::NoModifier));
+ treeViewPrivate->setSelectionStartPos(QPointF(225, 90));
+ treeViewPrivate->setSelectionEndPos(QPointF(-10, -10));
+
+ QCOMPARE(selectionModel->hasSelection(), true);
+
+ actualCount = selectionModel->selectedIndexes().size();
+ QCOMPARE(actualCount, expectedCount);
+
+ for (int x = 0; x < 3; ++x) {
+ for (int y = 0; y < treeView->rows(); ++y) {
+ const auto index = treeView->index(y, x);
+ QVERIFY(selectionModel->isSelected(index));
+ }
+ }
+}
+
+void tst_qquicktreeview::selectionBehaviorDisabled()
+{
+ // Check that the TreeView implement the overridden updateSelection()
+ // function correctly wrt QQuickTableView::SelectionDisabled.
+ LOAD_TREEVIEW("normaltreeview.qml");
+
+ const auto selectionModel = treeView->selectionModel();
+ treeView->setSelectionBehavior(QQuickTableView::SelectionDisabled);
+
+ WAIT_UNTIL_POLISHED;
+
+ QCOMPARE(selectionModel->hasSelection(), false);
+
+ // Try to start a selection. treeViewPrivate->startSelection() should
+ // reject that, and and return false. The selectionFlag will there stay as
+ // QItemSelectionModel::NoUpdate, meaning no active selection is ongoing.
+ QVERIFY(!treeViewPrivate->startSelection(QPointF(0, 0), Qt::NoModifier));
+ QCOMPARE(treeViewPrivate->selectionFlag, QItemSelectionModel::NoUpdate);
+ QCOMPARE(selectionModel->hasSelection(), false);
+}
+
+void tst_qquicktreeview::sortTreeModel_data()
+{
+ QTest::addColumn<QSharedPointer<QAbstractItemModel>>("treeModel");
+
+ const auto stringList = QStringList() << "1" << "2" << "3";
+ QTest::newRow("TreeModel") << QSharedPointer<QAbstractItemModel>(new TestModel());
+ QTest::newRow("Number model") << QSharedPointer<QAbstractItemModel>(new QStringListModel(stringList));
+}
+
+void tst_qquicktreeview::sortTreeModel()
+{
+ // Check that if you assign a QSortFilterProxyModel to to a TreeView, the
+ // view will end up sorted correctly if the proxy model is sorted.
+ QFETCH(QSharedPointer<QAbstractItemModel>, treeModel);
+ LOAD_TREEVIEW("normaltreeview.qml");
+
+ QSortFilterProxyModel proxyModel;
+ proxyModel.setSourceModel(treeModel.data());
+ treeView->setModel(QVariant::fromValue(&proxyModel));
+
+ // Expand some nodes
+ treeView->expand(0);
+ treeView->expand(4);
+ treeView->expand(3);
+
+ WAIT_UNTIL_POLISHED;
+
+ // Go through all rows in the view, and check that display in the model
+ // is the same as in the view. That means that QQmlTreeModelToTableModel
+ // and QSortFilterProxyModel are in sync.
+ for (int row = 0; row < treeView->rows(); ++row) {
+ const auto index = treeView->index(row, 0);
+ const QString modelDisplay = proxyModel.data(index, Qt::DisplayRole).toString();
+ const auto childFxItem = treeViewPrivate->loadedTableItem(QPoint(0, row));
+ QVERIFY(childFxItem);
+ const auto childItem = childFxItem->item;
+ QVERIFY(childItem);
+ const auto context = qmlContext(childItem.data());
+ const auto itemDisplay = context->contextProperty("display").toString();
+ QCOMPARE(itemDisplay, modelDisplay);
+ }
+
+ // Now sort the model, and do the same test again
+ proxyModel.sort(0, Qt::DescendingOrder);
+ WAIT_UNTIL_POLISHED;
+
+ for (int row = 0; row < treeView->rows(); ++row) {
+ const auto index = treeView->index(row, 0);
+ const QString modelDisplay = proxyModel.data(index, Qt::DisplayRole).toString();
+ const auto childFxItem = treeViewPrivate->loadedTableItem(QPoint(0, row));
+ QVERIFY(childFxItem);
+ const auto childItem = childFxItem->item;
+ QVERIFY(childItem);
+ const auto context = qmlContext(childItem.data());
+ const auto itemDisplay = context->contextProperty("display").toString();
+ QCOMPARE(itemDisplay, modelDisplay);
+ }
+}
+
+void tst_qquicktreeview::sortTreeModelDynamic_data()
+{
+ QTest::addColumn<QSharedPointer<QAbstractItemModel>>("treeModel");
+ QTest::addColumn<int>("row");
+
+ const auto stringList = QStringList() << "1" << "2" << "3";
+ QTest::newRow("TreeModel 0") << QSharedPointer<QAbstractItemModel>(new TestModel()) << 0;
+ QTest::newRow("TreeModel 1") << QSharedPointer<QAbstractItemModel>(new TestModel()) << 1;
+ QTest::newRow("TreeModel 3") << QSharedPointer<QAbstractItemModel>(new TestModel()) << 3;
+ QTest::newRow("TreeModel 6") << QSharedPointer<QAbstractItemModel>(new TestModel()) << 6;
+ QTest::newRow("Number model") << QSharedPointer<QAbstractItemModel>(new QStringListModel(stringList)) << 1;
+}
+
+void tst_qquicktreeview::sortTreeModelDynamic()
+{
+ // Check that if you assign a QSortFilterProxyModel to a TreeView, and
+ // set DynamicSortFilter to true, the view will end up sorted correctly
+ // if you change the text for one of the items.
+ QFETCH(QSharedPointer<QAbstractItemModel>, treeModel);
+ QFETCH(int, row);
+ LOAD_TREEVIEW("normaltreeview.qml");
+
+ QSortFilterProxyModel proxyModel;
+ proxyModel.setSourceModel(treeModel.data());
+ proxyModel.setDynamicSortFilter(true);
+ proxyModel.sort(Qt::AscendingOrder);
+ treeView->setModel(QVariant::fromValue(&proxyModel));
+
+ // Expand some nodes
+ treeView->expand(0);
+ treeView->expand(4);
+ treeView->expand(3);
+
+ // Go through all rows in the view, and check that display in the model
+ // is the same as in the view. That means that QQmlTreeModelToTableModel
+ // and QSortFilterProxyModel are in sync.
+ for (int row = 0; row < treeView->rows(); ++row) {
+ const auto index = treeView->index(row, 0);
+ const QString modelDisplay = proxyModel.data(index, Qt::DisplayRole).toString();
+ const auto childFxItem = treeViewPrivate->loadedTableItem(QPoint(0, row));
+ QVERIFY(childFxItem);
+ const auto childItem = childFxItem->item;
+ QVERIFY(childItem);
+ const auto context = qmlContext(childItem.data());
+ const auto itemDisplay = context->contextProperty("display").toString();
+ QCOMPARE(itemDisplay, modelDisplay);
+ }
+
+ // Now change the text in one of the items. This will trigger
+ // a sort for only one of the parents in the model.
+ proxyModel.setData(treeView->index(row, 0), u"xxx"_s, Qt::DisplayRole);
+
+ for (int row = 0; row < treeView->rows(); ++row) {
+ const auto index = treeView->index(row, 0);
+ const QString modelDisplay = proxyModel.data(index, Qt::DisplayRole).toString();
+ const auto childFxItem = treeViewPrivate->loadedTableItem(QPoint(0, row));
+ QVERIFY(childFxItem);
+ const auto childItem = childFxItem->item;
+ QVERIFY(childItem);
+ const auto context = qmlContext(childItem.data());
+ const auto itemDisplay = context->contextProperty("display").toString();
+ QCOMPARE(itemDisplay, modelDisplay);
+ }
+}
+
+void tst_qquicktreeview::setRootIndex()
+{
+ // Check that if you can change the root index in the view to point
+ // at a child branch in the model
+ LOAD_TREEVIEW("normaltreeview.qml");
+
+ const QModelIndex rootIndex = model->index(0, 0);
+ const QModelIndex childIndex = model->index(3, 0, rootIndex);
+ QVERIFY(model->hasChildren(childIndex));
+ treeView->setRootIndex(childIndex);
+
+ // Go through all rows in the view, and check that view shows the
+ // same display text as the display role in the model (under the
+ // given root).
+ for (int row = 0; row < treeView->rows(); ++row) {
+ const auto index = model->index(row, 0, childIndex);
+ const QString modelDisplay = model->data(index, Qt::DisplayRole).toString();
+ const auto childFxItem = treeViewPrivate->loadedTableItem(QPoint(0, row));
+ QVERIFY(childFxItem);
+ const auto childItem = childFxItem->item;
+ QVERIFY(childItem);
+ const auto context = qmlContext(childItem.data());
+ const auto itemDisplay = context->contextProperty("display").toString();
+ QCOMPARE(itemDisplay, modelDisplay);
+ }
+
+ // Do the same once more, but this time choose a child that is deeper in the model
+ const QModelIndex childIndex2 = model->index(3, 0, childIndex);
+ QVERIFY(model->hasChildren(childIndex2));
+ treeView->setRootIndex(childIndex);
+
+ for (int row = 0; row < treeView->rows(); ++row) {
+ const auto index = model->index(row, 0, childIndex2);
+ const QString modelDisplay = model->data(index, Qt::DisplayRole).toString();
+ const auto childFxItem = treeViewPrivate->loadedTableItem(QPoint(0, row));
+ QVERIFY(childFxItem);
+ const auto childItem = childFxItem->item;
+ QVERIFY(childItem);
+ const auto context = qmlContext(childItem.data());
+ const auto itemDisplay = context->contextProperty("display").toString();
+ QCOMPARE(itemDisplay, modelDisplay);
+ }
+
+ // Reset rootIndex. This should show the whole model again
+ treeView->setRootIndex(QModelIndex());
+
+ for (int row = 0; row < treeView->rows(); ++row) {
+ const auto index = model->index(row, 0);
+ const QString modelDisplay = model->data(index, Qt::DisplayRole).toString();
+ const auto childFxItem = treeViewPrivate->loadedTableItem(QPoint(0, row));
+ QVERIFY(childFxItem);
+ const auto childItem = childFxItem->item;
+ QVERIFY(childItem);
+ const auto context = qmlContext(childItem.data());
+ const auto itemDisplay = context->contextProperty("display").toString();
+ QCOMPARE(itemDisplay, modelDisplay);
+ }
+}
+
+void tst_qquicktreeview::setRootIndexToLeaf()
+{
+ // When you set a custom root index, the root index itself will not
+ // be shown. Therefore, check that if you change the root index to a
+ // leaf in the model, TreeView will be empty.
+ LOAD_TREEVIEW("normaltreeview.qml");
+
+ const QModelIndex rootIndex = model->index(0, 0);
+ const QModelIndex leafIndex = model->index(1, 0, rootIndex);
+ QVERIFY(!model->hasChildren(leafIndex));
+ treeView->setRootIndex(leafIndex);
+ WAIT_UNTIL_POLISHED;
+ QCOMPARE(treeView->rows(), 0);
+
+ // According to the docs, you can set rootIndex to undefined
+ // in order to show the whole model again. This is the same
+ // as calling 'reset' on the property from c++. Verify that this works.
+ const QMetaObject *metaObject = treeView->metaObject();
+ const int propertyIndex = metaObject->indexOfProperty("rootIndex");
+ QVERIFY(propertyIndex != -1);
+ metaObject->property(propertyIndex).reset(treeView);
+
+ for (int row = 0; row < treeView->rows(); ++row) {
+ const auto index = model->index(row, 0);
+ const QString modelDisplay = model->data(index, Qt::DisplayRole).toString();
+ const auto childFxItem = treeViewPrivate->loadedTableItem(QPoint(0, row));
+ QVERIFY(childFxItem);
+ const auto childItem = childFxItem->item;
+ QVERIFY(childItem);
+ const auto context = qmlContext(childItem.data());
+ const auto itemDisplay = context->contextProperty("display").toString();
+ QCOMPARE(itemDisplay, modelDisplay);
+ }
+}
+
+QTEST_MAIN(tst_qquicktreeview)
+
+#include "tst_qquicktreeview.moc"
diff --git a/tests/auto/quick/qquickview/CMakeLists.txt b/tests/auto/quick/qquickview/CMakeLists.txt
index 16babb106a..658d957de5 100644
--- a/tests/auto/quick/qquickview/CMakeLists.txt
+++ b/tests/auto/quick/qquickview/CMakeLists.txt
@@ -1,9 +1,20 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickview.pro.
#####################################################################
## tst_qquickview Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickview LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_policy(SET QTP0001 NEW)
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,33 +23,34 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickview
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickview.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
+
+qt_add_qml_module(
+ tst_qquickview
+ URI test
+ QML_FILES
+ "data/TestQml.qml"
+)
+
## Scopes:
#####################################################################
qt_internal_extend_target(tst_qquickview CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickview CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickview/data/TestQml.qml b/tests/auto/quick/qquickview/data/TestQml.qml
new file mode 100644
index 0000000000..3052615aef
--- /dev/null
+++ b/tests/auto/quick/qquickview/data/TestQml.qml
@@ -0,0 +1,3 @@
+import QtQuick
+
+Item {}
diff --git a/tests/auto/quick/qquickview/data/overlay.qml b/tests/auto/quick/qquickview/data/overlay.qml
new file mode 100644
index 0000000000..cefaaed8bd
--- /dev/null
+++ b/tests/auto/quick/qquickview/data/overlay.qml
@@ -0,0 +1,17 @@
+// RootItem.qml
+import QtQuick
+import QtQuick.Controls.Basic
+
+Item {
+ id: root
+ width: 640
+ height: 480
+
+ property double scaleFactor: 2.0
+ Scale {
+ id: scale
+ xScale: root.scaleFactor
+ yScale: root.scaleFactor
+ }
+ Overlay.overlay.transform: scale
+}
diff --git a/tests/auto/quick/qquickview/tst_qquickview.cpp b/tests/auto/quick/qquickview/tst_qquickview.cpp
index 7e47e0ca59..91a45077fb 100644
--- a/tests/auto/quick/qquickview/tst_qquickview.cpp
+++ b/tests/auto/quick/qquickview/tst_qquickview.cpp
@@ -1,42 +1,21 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtTest/QSignalSpy>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlcontext.h>
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtGui/QWindow>
#include <QtCore/QDebug>
#include <QtQml/qqmlengine.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4mm_p.h>
-#include "../shared/geometrytestutil.h"
+#include <QtQuickTestUtils/private/geometrytestutils_p.h>
+
+using namespace Qt::StringLiterals;
class tst_QQuickView : public QQmlDataTest
{
@@ -45,16 +24,52 @@ public:
tst_QQuickView();
private slots:
+ void gc();
void resizemodeitem();
void errors();
void engine();
void findChild();
void setInitialProperties();
+ void fromModuleCtor();
+ void loadFromModule_data();
+ void loadFromModule();
+ void overlay();
};
tst_QQuickView::tst_QQuickView()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
+void tst_QQuickView::gc()
{
+ QQuickView view;
+ QQmlEngine *engine = view.engine();
+ QV4::ExecutionEngine *v4 = engine->handle();
+
+ v4->memoryManager->gcStateMachine->deadline = QDeadlineTimer(QDeadlineTimer::Forever);
+ auto sm = v4->memoryManager->gcStateMachine.get();
+ sm->reset();
+ while (sm->state != QV4::GCState::CallDestroyObjects) {
+ QV4::GCStateInfo& stateInfo = sm->stateInfoMap[int(sm->state)];
+ sm->state = stateInfo.execute(sm, sm->stateData);
+ }
+ view.loadFromModule("test", "TestQml");
+ auto root = view.rootObject();
+ QVERIFY(root);
+ auto ddata = QQmlData::get(root, false);
+ while (sm->state != QV4::GCState::DoSweep) {
+ if (sm->state > QV4::GCState::InitCallDestroyObjects) {
+ sm->mm->collectFromJSStack(sm->mm->markStack());
+ sm->mm->m_markStack->drain();
+ }
+ QV4::GCStateInfo& stateInfo = sm->stateInfoMap[int(sm->state)];
+ sm->state = stateInfo.execute(sm, sm->stateData);
+ }
+ QVERIFY(ddata);
+ QVERIFY(ddata->jsWrapper.asManaged());
+ QVERIFY(ddata->jsWrapper.asManaged()->markBit());
}
void tst_QQuickView::resizemodeitem()
@@ -147,7 +162,7 @@ void tst_QQuickView::resizemodeitem()
view->resize(QSize(200,300));
QTRY_COMPARE(item->width(), 200.0);
- for (int i = 0; i < sizeListener.count(); ++i) {
+ for (int i = 0; i < sizeListener.size(); ++i) {
// Check that we have the correct geometry on all signals
QCOMPARE(sizeListener.at(i), view->size());
}
@@ -195,7 +210,7 @@ void tst_QQuickView::errors()
QQmlTestMessageHandler messageHandler;
view.setSource(testFileUrl("error1.qml"));
QCOMPARE(view.status(), QQuickView::Error);
- QCOMPARE(view.errors().count(), 1);
+ QCOMPARE(view.errors().size(), 1);
}
{
@@ -203,7 +218,7 @@ void tst_QQuickView::errors()
QQmlTestMessageHandler messageHandler;
view.setSource(testFileUrl("error2.qml"));
QCOMPARE(view.status(), QQuickView::Error);
- QCOMPARE(view.errors().count(), 1);
+ QCOMPARE(view.errors().size(), 1);
view.show();
}
}
@@ -294,6 +309,50 @@ void tst_QQuickView::setInitialProperties()
QCOMPARE(rootObject->property("width").toInt(), 100);
}
+void tst_QQuickView::fromModuleCtor()
+{
+ QQuickView view("QtQuick", "Rectangle");
+ // creation is always synchronous for C++ defined types, so we don't need _TRY
+ QObject *rootObject = view.rootObject();
+ QVERIFY(rootObject);
+ QCOMPARE(rootObject->metaObject()->className(), "QQuickRectangle");
+}
+
+void tst_QQuickView::loadFromModule_data()
+{
+ QTest::addColumn<QString>("module");
+ QTest::addColumn<QString>("typeName");
+ QTest::addColumn<QUrl>("url");
+ QTest::addColumn<QQuickView::Status>("status");
+
+ QTest::addRow("Item") << u"QtQuick"_s << u"Item"_s << QUrl() << QQuickView::Ready;
+ QTest::addRow("composite") << u"test"_s << u"TestQml"_s << QUrl("qrc:/qt/qml/test/data/TestQml.qml") << QQuickView::Ready;
+ QTest::addRow("nonexistent") << u"missing"_s << u"Type"_s << QUrl() << QQuickView::Error;
+}
+
+void tst_QQuickView::loadFromModule()
+{
+ QFETCH(QString, module);
+ QFETCH(QString, typeName);
+ QFETCH(QUrl, url);
+ QFETCH(QQuickView::Status, status);
+
+ QQuickView view;
+ view.loadFromModule(module, typeName);
+ QTRY_COMPARE(view.status(), status);
+ QCOMPARE(view.source(), url);
+}
+
+void tst_QQuickView::overlay()
+{
+ QTest::ignoreMessage(QtWarningMsg,
+ QRegularExpression(".*: Cannot set properties on overlay as it is null"));
+ QQuickView view;
+ view.setSource(testFileUrl("overlay.qml"));
+ QObject *rootObject = view.rootObject();
+ QVERIFY(!rootObject);
+}
+
QTEST_MAIN(tst_QQuickView)
#include "tst_qquickview.moc"
diff --git a/tests/auto/quick/qquickview_extra/CMakeLists.txt b/tests/auto/quick/qquickview_extra/CMakeLists.txt
index 4fa75da811..4287c97f51 100644
--- a/tests/auto/quick/qquickview_extra/CMakeLists.txt
+++ b/tests/auto/quick/qquickview_extra/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickview_extra.pro.
#####################################################################
## tst_qquickview_extra Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickview_extra LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickview_extra
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickview_extra.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,10 +37,10 @@ qt_internal_add_test(tst_qquickview_extra
qt_internal_extend_target(tst_qquickview_extra CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickview_extra CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickview_extra/tst_qquickview_extra.cpp b/tests/auto/quick/qquickview_extra/tst_qquickview_extra.cpp
index f697a438bd..9fbd318669 100644
--- a/tests/auto/quick/qquickview_extra/tst_qquickview_extra.cpp
+++ b/tests/auto/quick/qquickview_extra/tst_qquickview_extra.cpp
@@ -1,36 +1,11 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtTest/QSignalSpy>
#include <QtQuick/qquickview.h>
#include <QtQuick/qquickitem.h>
#include <QtQml/qqmlengine.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <QtCore/QDebug>
#include <QtCore/QTimer>
@@ -45,7 +20,7 @@ private slots:
void qtbug_87228();
};
-tst_QQuickViewExtra::tst_QQuickViewExtra() { }
+tst_QQuickViewExtra::tst_QQuickViewExtra() : QQmlDataTest(QT_QMLTEST_DATADIR) { }
void tst_QQuickViewExtra::qtbug_87228()
{
@@ -67,9 +42,9 @@ void tst_QQuickViewExtra::qtbug_87228()
auto children = contentItem->childItems();
QVERIFY(children.size() > 0);
// for the sake of this test, any child would be suitable, so pick first
- deletionSpy.reset(new QSignalSpy(children[0], SIGNAL(destroyed(QObject *))));
+ deletionSpy.reset(new QSignalSpy(children[0], SIGNAL(destroyed(QObject*))));
}
- QCOMPARE(deletionSpy->count(), 1);
+ QCOMPARE(deletionSpy->size(), 1);
}
QTEST_APPLESS_MAIN(tst_QQuickViewExtra)
diff --git a/tests/auto/quick/qquickvisualdatamodel/CMakeLists.txt b/tests/auto/quick/qquickvisualdatamodel/CMakeLists.txt
index 8222fd001f..2b11d7233a 100644
--- a/tests/auto/quick/qquickvisualdatamodel/CMakeLists.txt
+++ b/tests/auto/quick/qquickvisualdatamodel/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickvisualdatamodel.pro.
#####################################################################
## tst_qquickvisualdatamodel Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickvisualdatamodel LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,22 +21,15 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickvisualdatamodel
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickvisualdatamodel.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlModelsPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,16 +37,16 @@ qt_internal_add_test(tst_qquickvisualdatamodel
#####################################################################
qt_internal_extend_target(tst_qquickvisualdatamodel CONDITION TARGET Qt::Widgets
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Widgets
)
qt_internal_extend_target(tst_qquickvisualdatamodel CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickvisualdatamodel CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickvisualdatamodel/data/attachedDeclarativelySet.qml b/tests/auto/quick/qquickvisualdatamodel/data/attachedDeclarativelySet.qml
new file mode 100644
index 0000000000..db83d897be
--- /dev/null
+++ b/tests/auto/quick/qquickvisualdatamodel/data/attachedDeclarativelySet.qml
@@ -0,0 +1,23 @@
+import QtQml
+import QtQml.Models
+
+
+QtObject {
+ id: root
+ property bool includeAll: false
+ property alias count: instantiator.count
+ readonly property DelegateModel mprop: DelegateModel {
+ id: dm
+ model: 10
+
+ delegate: QtObject {
+ required property int index
+ DelegateModel.inItems: index % 2 === 0 || root.includeAll
+ }
+ }
+
+ readonly property Instantiator instProp: Instantiator {
+ id: instantiator
+ model: dm
+ }
+}
diff --git a/tests/auto/quick/qquickvisualdatamodel/data/externalManagedModel.qml b/tests/auto/quick/qquickvisualdatamodel/data/externalManagedModel.qml
index 44c157b824..f067e7a841 100644
--- a/tests/auto/quick/qquickvisualdatamodel/data/externalManagedModel.qml
+++ b/tests/auto/quick/qquickvisualdatamodel/data/externalManagedModel.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tests of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick.Window 2.2
import QtQuick 2.6
diff --git a/tests/auto/quick/qquickvisualdatamodel/data/objectDeletion.qml b/tests/auto/quick/qquickvisualdatamodel/data/objectDeletion.qml
new file mode 100644
index 0000000000..4e01b0a1ba
--- /dev/null
+++ b/tests/auto/quick/qquickvisualdatamodel/data/objectDeletion.qml
@@ -0,0 +1,20 @@
+import QtQuick
+import TestTypes
+
+ListView {
+ id: listView
+ anchors.fill: parent
+ model: InventoryModel {}
+ delegate: Text {
+ width: listView.width
+ text: itemName
+
+ required property int index
+ required property string itemName
+ required property ComponentEntity entity
+ }
+
+ function removeLast() { model.removeLast() }
+}
+
+
diff --git a/tests/auto/quick/qquickvisualdatamodel/data/setDelegateNoDoubleChange.qml b/tests/auto/quick/qquickvisualdatamodel/data/setDelegateNoDoubleChange.qml
new file mode 100644
index 0000000000..b4739d036e
--- /dev/null
+++ b/tests/auto/quick/qquickvisualdatamodel/data/setDelegateNoDoubleChange.qml
@@ -0,0 +1,43 @@
+import QtQuick
+
+Item {
+ width: 200
+ height: 200
+ id: root
+ property int creationCount: 0
+ property bool testStarted: false
+
+ ListModel {
+ id: mymodel
+ ListElement {message: "This is my alarm"}
+ }
+
+ Component {
+ id: aDelegate
+ Rectangle {
+ color: "blue"
+ width: 100
+ height: 100
+ }
+ }
+
+ Component {
+ id: bDelegate
+ Rectangle {
+ color: "red"
+ width: 100
+ height: 100
+ Text {text: model.message }
+ Component.onCompleted: root.creationCount++
+ }
+ }
+
+
+ ListView {
+ width: 200
+ height: 200
+ id: myListView
+ model: mymodel
+ delegate: testStarted ? bDelegate : aDelegate
+ }
+}
diff --git a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp
index 7ae0476f15..0821669703 100644
--- a/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp
+++ b/tests/auto/quick/qquickvisualdatamodel/tst_qquickvisualdatamodel.cpp
@@ -1,33 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include "../../shared/util.h"
-#include "../shared/visualtestutil.h"
-#include "../shared/viewtestutil.h"
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
#include <qtest.h>
#include <QtCore/qregularexpression.h>
@@ -47,8 +23,8 @@
#include <math.h>
#include <QtGui/qstandarditemmodel.h>
-using namespace QQuickVisualTestUtil;
-using namespace QQuickViewTestUtil;
+using namespace QQuickVisualTestUtils;
+using namespace QQuickViewTestUtils;
template <typename T, int N> int lengthOf(const T (&)[N]) { return N; }
@@ -84,9 +60,9 @@ public:
struct Branch {
Branch(Branch *parent = nullptr) : parent(parent) {}
- ~Branch() { foreach (const Node &child, children) delete child.branch; }
+ ~Branch() { for (const Node &child : std::as_const(children)) delete child.branch; }
int indexOf(Branch *branch) const {
- for (int i = 0; i < children.count(); ++i) {
+ for (int i = 0; i < children.size(); ++i) {
if (children.at(i).branch == branch)
return i;
}
@@ -100,12 +76,12 @@ public:
SingleRoleModel(const QStringList &list = QStringList(), const QByteArray &role = "name", QObject *parent = nullptr)
: QAbstractItemModel(parent), m_role(role)
{
- foreach (const QString &string, list)
+ for (const QString &string : list)
trunk.children.append(Node(string));
}
~SingleRoleModel() {}
- QHash<int,QByteArray> roleNames() const
+ QHash<int,QByteArray> roleNames() const override
{
QHash<int,QByteArray> roles;
roles.insert(Qt::DisplayRole, m_role);
@@ -130,42 +106,42 @@ public:
}
}
- QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const {
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override {
if (row < 0 || column != 0)
return QModelIndex();
Branch * const branch = branchForIndex(parent);
- return branch && row < branch->children.count()
+ return branch && row < branch->children.size()
? createIndex(row, column, branch)
: QModelIndex();
}
- QModelIndex parent(const QModelIndex &child) const {
+ QModelIndex parent(const QModelIndex &child) const override {
Branch * const branch = static_cast<Branch *>(child.internalPointer());
return branch->parent
? createIndex(branch->parent->indexOf(branch), 0, branch->parent)
: QModelIndex();
}
- int rowCount(const QModelIndex &parent) const {
+ int rowCount(const QModelIndex &parent) const override {
Branch * const branch = branchForIndex(parent);
- return branch ? branch->children.count() : 0;
+ return branch ? branch->children.size() : 0;
}
- int columnCount(const QModelIndex &parent) const {
+ int columnCount(const QModelIndex &parent) const override {
Branch * const branch = branchForIndex(parent);
return branch ? 1 : 0;
}
- QVariant data(const QModelIndex &index, int role) const {
+ QVariant data(const QModelIndex &index, int role) const override {
return index.isValid() && role == Qt::DisplayRole
? static_cast<Branch *>(index.internalPointer())->children.at(index.row()).display
: QVariant();
}
void insert(const QModelIndex &parent, int index, const QStringList &data) {
- beginInsertRows(parent, index, index + data.count() - 1);
+ beginInsertRows(parent, index, index + data.size() - 1);
Branch * const branch = createBranchForIndex(parent);
- for (int i = 0; i < data.count(); ++i)
+ for (int i = 0; i < data.size(); ++i)
branch->children.insert(index + i, Node(data.at(i)));
endInsertRows();
}
@@ -207,21 +183,21 @@ public:
QStringList getList() const {
QStringList list;
- foreach (const Node &node, trunk.children)
+ for (const Node &node : trunk.children)
list.append(node.display);
return list;
}
void setList(const QStringList &l) {
- if (trunk.children.count() > 0) {
- beginRemoveRows(QModelIndex(), 0, trunk.children.count() - 1);
- foreach (const Node &child, trunk.children) delete child.branch;
+ if (trunk.children.size() > 0) {
+ beginRemoveRows(QModelIndex(), 0, trunk.children.size() - 1);
+ for (const Node &child : std::as_const(trunk.children)) delete child.branch;
trunk.children.clear();
endRemoveRows();
}
- if (l.count() > 0) {
- beginInsertRows(QModelIndex(), 0, l.count() -1);
- foreach (const QString &string, l)
+ if (l.size() > 0) {
+ beginInsertRows(QModelIndex(), 0, l.size() -1);
+ for (const QString &string : l)
trunk.children.append(Node(string));
endInsertRows();
}
@@ -424,6 +400,7 @@ private slots:
void warnings_data();
void warnings();
void invalidAttachment();
+ void declarativeAssignViaAttached();
void asynchronousInsert_data();
void asynchronousInsert();
void asynchronousRemove_data();
@@ -434,8 +411,10 @@ private slots:
void invalidContext();
void externalManagedModel();
void delegateModelChangeDelegate();
+ void noDoubleDelegateUpdate();
void checkFilterGroupForDelegate();
void readFromProxyObject();
+ void noWarningOnObjectDeletion();
private:
template <int N> void groups_verify(
@@ -502,6 +481,7 @@ void tst_qquickvisualdatamodel::cleanupTestCase()
}
tst_qquickvisualdatamodel::tst_qquickvisualdatamodel()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
}
@@ -624,7 +604,8 @@ void tst_qquickvisualdatamodel::childChanged()
QVERIFY(name);
QCOMPARE(name->text(), QString("Row 2 updated child"));
- model.item(1,0)->appendRow(new QStandardItem(QLatin1String("Row 2 Child Item 2")));
+ QStandardItem item(QLatin1String("Row 2 Child Item 2"));
+ model.item(1,0)->appendRow(&item);
QCOMPARE(listview->count(), 2);
listview->forceLayout();
@@ -656,10 +637,10 @@ void tst_qquickvisualdatamodel::objectListModel()
QQuickView view;
QList<QObject*> dataList;
- dataList.append(new DataObject("Item 1", "red"));
- dataList.append(new DataObject("Item 2", "green"));
- dataList.append(new DataObject("Item 3", "blue"));
- dataList.append(new DataObject("Item 4", "yellow"));
+ dataList.append(new DataObject("Item 1", "red", &view));
+ dataList.append(new DataObject("Item 2", "green", &view));
+ dataList.append(new DataObject("Item 3", "blue", &view));
+ dataList.append(new DataObject("Item 4", "yellow", &view));
QQmlContext *ctxt = view.rootContext();
ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
@@ -798,10 +779,10 @@ void tst_qquickvisualdatamodel::modelProperties()
QQuickView view;
QList<QObject*> dataList;
- dataList.append(new DataObject("Item 1", "red"));
- dataList.append(new DataObject("Item 2", "green"));
- dataList.append(new DataObject("Item 3", "blue"));
- dataList.append(new DataObject("Item 4", "yellow"));
+ dataList.append(new DataObject("Item 1", "red", &view));
+ dataList.append(new DataObject("Item 2", "green", &view));
+ dataList.append(new DataObject("Item 3", "blue", &view));
+ dataList.append(new DataObject("Item 4", "yellow", &view));
QQmlContext *ctxt = view.rootContext();
ctxt->setContextProperty("myModel", QVariant::fromValue(dataList));
@@ -867,12 +848,9 @@ void tst_qquickvisualdatamodel::modelProperties()
QUrl source(testFileUrl("modelproperties2.qml"));
//3 items, 3 i each
- QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: modelData is not defined");
- QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: modelData is not defined");
- QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: ReferenceError: modelData is not defined");
- QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: modelData is not defined");
- QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: modelData is not defined");
- QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":11: ReferenceError: modelData is not defined");
+ QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: TypeError: Cannot read property 'display' of undefined");
+ QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: TypeError: Cannot read property 'display' of undefined");
+ QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":13: TypeError: Cannot read property 'display' of undefined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Cannot read property 'display' of undefined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Cannot read property 'display' of undefined");
QTest::ignoreMessage(QtWarningMsg, source.toString().toLatin1() + ":17: TypeError: Cannot read property 'display' of undefined");
@@ -1061,14 +1039,14 @@ void tst_qquickvisualdatamodel::qaimRowsMoved()
QSignalSpy spy(obj, SIGNAL(modelUpdated(QQmlChangeSet,bool)));
model.emitMove(sourceFirst, sourceLast, destinationChild);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
- QCOMPARE(spy[0].count(), 2);
+ QCOMPARE(spy[0].size(), 2);
QQmlChangeSet changeSet = spy[0][0].value<QQmlChangeSet>();
- QCOMPARE(changeSet.removes().count(), 1);
+ QCOMPARE(changeSet.removes().size(), 1);
QCOMPARE(changeSet.removes().at(0).index, expectFrom);
QCOMPARE(changeSet.removes().at(0).count, expectCount);
- QCOMPARE(changeSet.inserts().count(), 1);
+ QCOMPARE(changeSet.inserts().size(), 1);
QCOMPARE(changeSet.inserts().at(0).index, expectTo);
QCOMPARE(changeSet.inserts().at(0).count, expectCount);
QCOMPARE(changeSet.removes().at(0).moveId, changeSet.inserts().at(0).moveId);
@@ -1130,33 +1108,33 @@ void tst_qquickvisualdatamodel::subtreeRowsMoved()
// Move items from the current root index to a sub tree.
model.move(QModelIndex(), 1, model.index(0, 0), 3, 2);
QCOMPARE(vdm->count(), 2);
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
changeSet = spy.last().at(0).value<QQmlChangeSet>();
- QCOMPARE(changeSet.removes().count(), 1);
+ QCOMPARE(changeSet.removes().size(), 1);
QCOMPARE(changeSet.removes().at(0).index, 1);
QCOMPARE(changeSet.removes().at(0).count, 2);
- QCOMPARE(changeSet.inserts().count(), 0);
+ QCOMPARE(changeSet.inserts().size(), 0);
// Move items from a sub tree to the current root index.
model.move(model.index(0, 0), 4, QModelIndex(), 2, 1);
QCOMPARE(vdm->count(), 3);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
changeSet = spy.last().at(0).value<QQmlChangeSet>();
- QCOMPARE(changeSet.removes().count(), 0);
- QCOMPARE(changeSet.inserts().count(), 1);
+ QCOMPARE(changeSet.removes().size(), 0);
+ QCOMPARE(changeSet.inserts().size(), 1);
QCOMPARE(changeSet.inserts().at(0).index, 2);
QCOMPARE(changeSet.inserts().at(0).count, 1);
vdm->setRootIndex(QVariant::fromValue(model.index(2, 0)));
QCOMPARE(vdm->rootIndex().value<QModelIndex>(), model.index(2, 0));
QCOMPARE(vdm->count(), 3);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
changeSet = spy.at(2).at(0).value<QQmlChangeSet>();
- QCOMPARE(changeSet.removes().count(), 1);
+ QCOMPARE(changeSet.removes().size(), 1);
QCOMPARE(changeSet.removes().at(0).index, 0);
QCOMPARE(changeSet.removes().at(0).count, 3);
changeSet = spy.last().at(0).value<QQmlChangeSet>();
- QCOMPARE(changeSet.inserts().count(), 1);
+ QCOMPARE(changeSet.inserts().size(), 1);
QCOMPARE(changeSet.inserts().at(0).index, 0);
QCOMPARE(changeSet.inserts().at(0).count, 3);
@@ -1164,41 +1142,41 @@ void tst_qquickvisualdatamodel::subtreeRowsMoved()
model.move(QModelIndex(), 2, QModelIndex(), 0, 1);
QCOMPARE(vdm->rootIndex().value<QModelIndex>(), model.index(0, 0));
QCOMPARE(vdm->count(), 3);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
// Move the current root index, changing its parent.
model.move(QModelIndex(), 0, model.index(1, 0), 0, 1);
QCOMPARE(vdm->rootIndex().value<QModelIndex>(), model.index(0, 0, model.index(0, 0)));
QCOMPARE(vdm->count(), 3);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
model.insert(model.index(0, 0), 0, QStringList() << "new1" << "new2");
QCOMPARE(vdm->rootIndex().value<QModelIndex>(), model.index(2, 0, model.index(0, 0)));
QCOMPARE(vdm->count(), 3);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
model.remove(model.index(0, 0), 1, 1);
QCOMPARE(vdm->rootIndex().value<QModelIndex>(), model.index(1, 0, model.index(0, 0)));
QCOMPARE(vdm->count(), 3);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
model.remove(model.index(0, 0), 1, 1);
QCOMPARE(vdm->rootIndex().value<QModelIndex>(), QModelIndex());
QCOMPARE(vdm->count(), 0);
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
changeSet = spy.last().at(0).value<QQmlChangeSet>();
- QCOMPARE(changeSet.removes().count(), 1);
+ QCOMPARE(changeSet.removes().size(), 1);
QCOMPARE(changeSet.removes().at(0).index, 0);
QCOMPARE(changeSet.removes().at(0).count, 3);
- QCOMPARE(changeSet.inserts().count(), 0);
+ QCOMPARE(changeSet.inserts().size(), 0);
vdm->setRootIndex(QVariant::fromValue(QModelIndex()));
QCOMPARE(vdm->rootIndex().value<QModelIndex>(), QModelIndex());
QCOMPARE(vdm->count(), 2);
- QCOMPARE(spy.count(), 6);
+ QCOMPARE(spy.size(), 6);
changeSet = spy.last().at(0).value<QQmlChangeSet>();
- QCOMPARE(changeSet.removes().count(), 0);
- QCOMPARE(changeSet.inserts().count(), 1);
+ QCOMPARE(changeSet.removes().size(), 0);
+ QCOMPARE(changeSet.inserts().size(), 1);
QCOMPARE(changeSet.inserts().at(0).index, 0);
QCOMPARE(changeSet.inserts().at(0).count, 2);
}
@@ -1230,44 +1208,44 @@ void tst_qquickvisualdatamodel::watchedRoles()
QCOMPARE(vdm->count(), 30);
emit model.dataChanged(model.index(0), model.index(4));
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
emit model.dataChanged(model.index(0), model.index(4), QVector<int>() << QaimModel::Name);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
emit model.dataChanged(model.index(0), model.index(4), QVector<int>() << QaimModel::Number);
- QCOMPARE(spy.count(), 0);
+ QCOMPARE(spy.size(), 0);
vdm->setWatchedRoles(QList<QByteArray>() << "name" << "dummy");
emit model.dataChanged(model.index(0), model.index(4));
- QCOMPARE(spy.count(), 1);
+ QCOMPARE(spy.size(), 1);
changeSet = spy.last().at(0).value<QQmlChangeSet>();
QCOMPARE(changeSet.changes().at(0).index, 0);
QCOMPARE(changeSet.changes().at(0).count, 5);
emit model.dataChanged(model.index(1), model.index(6), QVector<int>() << QaimModel::Name);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
changeSet = spy.last().at(0).value<QQmlChangeSet>();
QCOMPARE(changeSet.changes().at(0).index, 1);
QCOMPARE(changeSet.changes().at(0).count, 6);
emit model.dataChanged(model.index(8), model.index(8), QVector<int>() << QaimModel::Number);
- QCOMPARE(spy.count(), 2);
+ QCOMPARE(spy.size(), 2);
vdm->setWatchedRoles(QList<QByteArray>() << "number" << "dummy");
emit model.dataChanged(model.index(0), model.index(4));
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
changeSet = spy.last().at(0).value<QQmlChangeSet>();
QCOMPARE(changeSet.changes().at(0).index, 0);
QCOMPARE(changeSet.changes().at(0).count, 5);
emit model.dataChanged(model.index(1), model.index(6), QVector<int>() << QaimModel::Name);
- QCOMPARE(spy.count(), 3);
+ QCOMPARE(spy.size(), 3);
emit model.dataChanged(model.index(8), model.index(8), QVector<int>() << QaimModel::Number);
- QCOMPARE(spy.count(), 4);
+ QCOMPARE(spy.size(), 4);
changeSet = spy.last().at(0).value<QQmlChangeSet>();
QCOMPARE(changeSet.changes().at(0).index, 8);
QCOMPARE(changeSet.changes().at(0).count, 1);
@@ -1275,19 +1253,19 @@ void tst_qquickvisualdatamodel::watchedRoles()
vdm->setWatchedRoles(QList<QByteArray>() << "number" << "name");
emit model.dataChanged(model.index(0), model.index(4));
- QCOMPARE(spy.count(), 5);
+ QCOMPARE(spy.size(), 5);
changeSet = spy.last().at(0).value<QQmlChangeSet>();
QCOMPARE(changeSet.changes().at(0).index, 0);
QCOMPARE(changeSet.changes().at(0).count, 5);
emit model.dataChanged(model.index(1), model.index(6), QVector<int>() << QaimModel::Name);
- QCOMPARE(spy.count(), 6);
+ QCOMPARE(spy.size(), 6);
changeSet = spy.last().at(0).value<QQmlChangeSet>();
QCOMPARE(changeSet.changes().at(0).index, 1);
QCOMPARE(changeSet.changes().at(0).count, 6);
emit model.dataChanged(model.index(8), model.index(8), QVector<int>() << QaimModel::Number);
- QCOMPARE(spy.count(), 7);
+ QCOMPARE(spy.size(), 7);
changeSet = spy.last().at(0).value<QQmlChangeSet>();
QCOMPARE(changeSet.changes().at(0).index, 8);
QCOMPARE(changeSet.changes().at(0).count, 1);
@@ -2282,7 +2260,7 @@ void tst_qquickvisualdatamodel::onChanged()
evaluate<void>(object.data(), expression);
- foreach (const QString &test, tests) {
+ for (const QString &test : std::as_const(tests)) {
bool passed = evaluate<bool>(object.data(), test);
if (!passed)
qWarning() << test;
@@ -2448,24 +2426,24 @@ void tst_qquickvisualdatamodel::incompleteModel()
QSignalSpy persistedItemsSpy(model->items(), SIGNAL(countChanged()));
evaluate<void>(model, "items.removeGroups(0, items.count, \"items\")");
- QCOMPARE(itemsSpy.count(), 0);
- QCOMPARE(persistedItemsSpy.count(), 0);
+ QCOMPARE(itemsSpy.size(), 0);
+ QCOMPARE(persistedItemsSpy.size(), 0);
evaluate<void>(model, "items.setGroups(0, items.count, \"persistedItems\")");
- QCOMPARE(itemsSpy.count(), 0);
- QCOMPARE(persistedItemsSpy.count(), 0);
+ QCOMPARE(itemsSpy.size(), 0);
+ QCOMPARE(persistedItemsSpy.size(), 0);
evaluate<void>(model, "items.addGroups(0, items.count, \"persistedItems\")");
- QCOMPARE(itemsSpy.count(), 0);
- QCOMPARE(persistedItemsSpy.count(), 0);
+ QCOMPARE(itemsSpy.size(), 0);
+ QCOMPARE(persistedItemsSpy.size(), 0);
evaluate<void>(model, "items.remove(0, items.count)");
- QCOMPARE(itemsSpy.count(), 0);
- QCOMPARE(persistedItemsSpy.count(), 0);
+ QCOMPARE(itemsSpy.size(), 0);
+ QCOMPARE(persistedItemsSpy.size(), 0);
evaluate<void>(model, "items.insert([ \"color\": \"blue\" ])");
- QCOMPARE(itemsSpy.count(), 0);
- QCOMPARE(persistedItemsSpy.count(), 0);
+ QCOMPARE(itemsSpy.size(), 0);
+ QCOMPARE(persistedItemsSpy.size(), 0);
QTest::ignoreMessage(QtWarningMsg, QRegularExpression(".*get: index out of range"));
QVERIFY(evaluate<bool>(model, "items.get(0) === undefined"));
@@ -3091,7 +3069,7 @@ void tst_qquickvisualdatamodel::insert()
QCOMPARE(evaluate<int>(visualModel, "visibleItems.count"), visible ? visualCount : modelCount);
QCOMPARE(evaluate<int>(visualModel, "selectedItems.count"), selected ? 1 : 0);
- QCOMPARE(propertyData.count(), visualCount);
+ QCOMPARE(propertyData.size(), visualCount);
for (int i = 0; i < visualCount; ++i) {
int modelIndex = i;
if (modelIndex > index)
@@ -3559,7 +3537,7 @@ void tst_qquickvisualdatamodel::resolve()
QCOMPARE(evaluate<int>(visualModel, "visibleItems.count"), visible ? visualCount : modelCount);
QCOMPARE(evaluate<int>(visualModel, "selectedItems.count"), selected ? 1 : 0);
- QCOMPARE(propertyData.count(), visualCount);
+ QCOMPARE(propertyData.size(), visualCount);
for (int i = 0; i < visualCount; ++i) {
int modelIndex = i;
@@ -3960,7 +3938,7 @@ void tst_qquickvisualdatamodel::invalidAttachment()
QScopedPointer<QObject> object(component.create());
QVERIFY(object);
- QCOMPARE(component.errors().count(), 0);
+ QCOMPARE(component.errors().size(), 0);
QVariant property = object->property("invalidVdm");
QCOMPARE(property.userType(), qMetaTypeId<QQmlDelegateModel *>());
@@ -3975,7 +3953,19 @@ void tst_qquickvisualdatamodel::invalidAttachment()
property = item->property("invalidVdm");
QCOMPARE(property.userType(), qMetaTypeId<QQmlDelegateModel *>());
- QVERIFY(!property.value<QQmlDelegateModel *>());
+ // has been explicitly requested by specifying the attached property
+ QVERIFY(property.value<QQmlDelegateModel *>());
+}
+
+void tst_qquickvisualdatamodel::declarativeAssignViaAttached()
+{
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("attachedDeclarativelySet.qml"));
+
+ QScopedPointer<QObject> root(component.create());
+ QCOMPARE(root->property("count").toInt(), 6); // 1 (from instantiator + 5 from model)
+ root->setProperty("includeAll", true);
+ QCOMPARE(root->property("count").toInt(), 11); // 1 (from instantiator + 10 from model)
}
void tst_qquickvisualdatamodel::asynchronousInsert_data()
@@ -4007,7 +3997,8 @@ void tst_qquickvisualdatamodel::asynchronousInsert()
engine.rootContext()->setContextProperty("myModel", &model);
- QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(c.create());
+ QScopedPointer<QObject> o(c.create());
+ QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(o.data());
QVERIFY(visualModel);
ItemRequester requester;
@@ -4072,7 +4063,8 @@ void tst_qquickvisualdatamodel::asynchronousRemove()
engine.rootContext()->setContextProperty("myModel", &model);
- QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(c.create());
+ QScopedPointer<QObject> o(c.create());
+ QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(o.data());
QVERIFY(visualModel);
ItemRequester requester;
@@ -4151,7 +4143,8 @@ void tst_qquickvisualdatamodel::asynchronousMove()
engine.rootContext()->setContextProperty("myModel", &model);
- QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(c.create());
+ QScopedPointer<QObject> o(c.create());
+ QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(o.data());
QVERIFY(visualModel);
ItemRequester requester;
@@ -4199,7 +4192,8 @@ void tst_qquickvisualdatamodel::asynchronousCancel()
engine.rootContext()->setContextProperty("myModel", &model);
- QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(c.create());
+ QScopedPointer<QObject> o(c.create());
+ QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(o.data());
QVERIFY(visualModel);
QQuickItem *item = qobject_cast<QQuickItem*>(visualModel->object(requestIndex, QQmlIncubator::Asynchronous));
@@ -4235,7 +4229,7 @@ void tst_qquickvisualdatamodel::invalidContext()
QVERIFY(item);
visualModel->release(item);
- delete context.take();
+ context.reset();
model.insertItem(4, "new item", "");
@@ -4277,7 +4271,7 @@ public:
static qsizetype listLength(QQmlListProperty<QObject> *property)
{
auto objectsProvider = qobject_cast<ObjectsProvider*>(property->object);
- return objectsProvider ? objectsProvider->m_objects.length() : 0;
+ return objectsProvider ? objectsProvider->m_objects.size() : 0;
}
static QObject* listAt(QQmlListProperty<QObject> *property, qsizetype index)
@@ -4321,7 +4315,8 @@ void tst_qquickvisualdatamodel::delegateModelChangeDelegate()
c.setData("import QtQml.Models 2.2\nDelegateModel {}\n", QUrl());
QCOMPARE(c.status(), QQmlComponent::Ready);
- QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(c.create(context.data()));
+ QScopedPointer<QObject> o(c.create(context.data()));
+ QQmlDelegateModel *visualModel = qobject_cast<QQmlDelegateModel*>(o.data());
QVERIFY(visualModel);
visualModel->setModel(QVariant(3));
@@ -4349,6 +4344,20 @@ void tst_qquickvisualdatamodel::delegateModelChangeDelegate()
QCOMPARE(visualModel->count(), 3);
}
+void tst_qquickvisualdatamodel::noDoubleDelegateUpdate()
+{
+ // changing a delegate only refreshes its instances once
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("setDelegateNoDoubleChange.qml"));
+
+ QScopedPointer<QObject> root(component.create());
+ QVERIFY(root);
+
+ bool ok = root->setProperty("testStarted", true);
+ QVERIFY(ok);
+ QCOMPARE(root->property("creationCount").toInt(), 1);
+}
+
void tst_qquickvisualdatamodel::checkFilterGroupForDelegate()
{
QQuickView view;
@@ -4377,6 +4386,106 @@ void tst_qquickvisualdatamodel::readFromProxyObject()
QTRY_VERIFY(window->property("name").toString() != QLatin1String("wrong"));
}
+
+class ComponentEntity : public QObject
+{
+ Q_OBJECT
+
+public:
+ ComponentEntity(QObject *parent = nullptr) : QObject(parent)
+ {
+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
+ }
+};
+
+class InventoryModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ InventoryModel() {
+ for (int i = 0; i < 10; ++i) {
+ QSharedPointer<ComponentEntity> entity(new ComponentEntity());
+ entity->setObjectName(QString::fromLatin1("Item %1").arg(i));
+ mContents.append(entity);
+ }
+ }
+
+ int rowCount(const QModelIndex &) const override { return mContents.size(); }
+
+ QVariant data(const QModelIndex &index, int role) const override
+ {
+ if (!checkIndex(index, CheckIndexOption::IndexIsValid))
+ return {};
+
+ auto entity = mContents.at(index.row()).data();
+ switch (role) {
+ case ItemNameRole: return entity->objectName();
+ case EntityRole: return QVariant::fromValue(entity);
+ }
+
+ return {};
+ }
+
+ Q_INVOKABLE void removeLast() {
+ const int index = rowCount(QModelIndex()) - 1;
+ if (index < 0)
+ return;
+
+ const auto item = mContents.at(index);
+ beginRemoveRows(QModelIndex(), index, index);
+ mContents.takeLast();
+ endRemoveRows();
+ }
+
+ enum InventoryModelRoles {
+ ItemNameRole = Qt::UserRole,
+ EntityRole
+ };
+
+ virtual QHash<int, QByteArray> roleNames() const override {
+ QHash<int, QByteArray> names;
+ names.insert(ItemNameRole, "itemName");
+ names.insert(EntityRole, "entity");
+ return names;
+ }
+
+private:
+ QVector<QSharedPointer<ComponentEntity>> mContents;
+};
+
+
+static QString lastWarning;
+static QtMessageHandler oldHandler;
+static void warningsHandler(QtMsgType type, const QMessageLogContext &ctxt, const QString &msg)
+{
+ if (type == QtWarningMsg)
+ lastWarning = msg;
+ else
+ oldHandler(type, ctxt, msg);
+}
+
+void tst_qquickvisualdatamodel::noWarningOnObjectDeletion()
+{
+ qmlRegisterType<InventoryModel>("TestTypes", 1, 0, "InventoryModel");
+ qmlRegisterUncreatableType<ComponentEntity>("TestTypes", 1, 0, "ComponentEntity", "no");
+
+ oldHandler = qInstallMessageHandler(warningsHandler);
+ const auto guard = qScopeGuard([&]() { qInstallMessageHandler(oldHandler); });
+
+ {
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("objectDeletion.qml"));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+ for (int i = 0; i < 5; ++i)
+ o->metaObject()->invokeMethod(o.data(), "removeLast");
+ }
+
+ QVERIFY2(lastWarning.isEmpty(), qPrintable(lastWarning));
+}
+
QTEST_MAIN(tst_qquickvisualdatamodel)
#include "tst_qquickvisualdatamodel.moc"
diff --git a/tests/auto/quick/qquickwindow/BLACKLIST b/tests/auto/quick/qquickwindow/BLACKLIST
index b4b7d2d761..6c3888daa1 100644
--- a/tests/auto/quick/qquickwindow/BLACKLIST
+++ b/tests/auto/quick/qquickwindow/BLACKLIST
@@ -1,3 +1,15 @@
[openglContextCreatedSignal]
opensuse-42.3
opensuse-leap
+
+# QTBUG-103078
+[defaultState]
+android
+[grab]
+android
+[requestActivate]
+android
+[contentItemSize]
+android
+[attachedProperty]
+android
diff --git a/tests/auto/quick/qquickwindow/CMakeLists.txt b/tests/auto/quick/qquickwindow/CMakeLists.txt
index 4b353cb277..0bec56ea73 100644
--- a/tests/auto/quick/qquickwindow/CMakeLists.txt
+++ b/tests/auto/quick/qquickwindow/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from qquickwindow.pro.
#####################################################################
## tst_qquickwindow Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickwindow LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_qquickwindow
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_qquickwindow.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -38,10 +40,10 @@ qt_internal_add_test(tst_qquickwindow
qt_internal_extend_target(tst_qquickwindow CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_qquickwindow CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/qquickwindow/data/conflictingVisibleFalse.qml b/tests/auto/quick/qquickwindow/data/conflictingVisibleFalse.qml
new file mode 100644
index 0000000000..98f374a741
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/data/conflictingVisibleFalse.qml
@@ -0,0 +1,6 @@
+import QtQuick
+
+Window {
+ visibility: Window.Windowed
+ visible: false
+}
diff --git a/tests/auto/quick/qquickwindow/data/conflictingVisibleTrue.qml b/tests/auto/quick/qquickwindow/data/conflictingVisibleTrue.qml
new file mode 100644
index 0000000000..52d9b2fc34
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/data/conflictingVisibleTrue.qml
@@ -0,0 +1,6 @@
+import QtQuick
+
+Window {
+ visibility: Window.Hidden
+ visible: true
+}
diff --git a/tests/auto/quick/qquickwindow/data/earlyGrab.qml b/tests/auto/quick/qquickwindow/data/earlyGrab.qml
new file mode 100644
index 0000000000..74427c9492
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/data/earlyGrab.qml
@@ -0,0 +1,25 @@
+import QtQuick
+import Test
+
+Window {
+ id: window
+ width: 400
+ height: 400
+ color: "red"
+
+ // Important for the test to set visible early on, not wait until
+ // show() from C++. What is really verified here is that the
+ // content grabbing takes the real window state into account
+ // (visible vs. exposed).
+ visible: true
+
+ Grabber {
+ id: grabber
+ objectName: "grabber"
+ }
+
+ Item {
+ anchors.fill: parent
+ Component.onCompleted: grabber.grab(window)
+ }
+}
diff --git a/tests/auto/quick/qquickwindow/data/eventTypes.qml b/tests/auto/quick/qquickwindow/data/eventTypes.qml
new file mode 100644
index 0000000000..05d80bfbd1
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/data/eventTypes.qml
@@ -0,0 +1,20 @@
+import QtQuick
+import QtQuick.Window
+
+Window {
+ id: root
+ function handleKey(e: KeyEvent) {}
+ function handleMouse(e: MouseEvent) {}
+ function handleWheel(e: WheelEvent) {}
+ function handleClose(e: CloseEvent) {}
+
+ Item {
+ Keys.onDeletePressed: root.handleKey
+ MouseArea {
+ onClicked: root.handleMouse
+ onWheel: root.handleWheel
+ }
+ }
+
+ onClosing: handleClose
+}
diff --git a/tests/auto/quick/qquickwindow/data/maximized.qml b/tests/auto/quick/qquickwindow/data/maximized.qml
new file mode 100644
index 0000000000..4d7054645b
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/data/maximized.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Window {
+ visibility: Window.Maximized
+}
diff --git a/tests/auto/quick/qquickwindow/data/shortcut.qml b/tests/auto/quick/qquickwindow/data/shortcut.qml
index 2632e27859..892eca1727 100644
--- a/tests/auto/quick/qquickwindow/data/shortcut.qml
+++ b/tests/auto/quick/qquickwindow/data/shortcut.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.9
import QtQuick.Window 2.2
diff --git a/tests/auto/quick/qquickwindow/data/shortcutOverride.qml b/tests/auto/quick/qquickwindow/data/shortcutOverride.qml
new file mode 100644
index 0000000000..960035c10f
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/data/shortcutOverride.qml
@@ -0,0 +1,30 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+import QtQuick
+import QtQuick.Window
+
+Window {
+ id: root
+ visible: true
+ width: 200
+ height: 200
+
+ property bool overridden: false
+ property bool receivedA: false
+ property bool receivedB: false
+ Item {
+ Keys.onShortcutOverride: (e) => e.accepted = root.overridden = (e.key === Qt.Key_A)
+
+ Item {
+ focus: true
+ Shortcut {
+ sequence: "A"
+ onActivated: root.receivedA = true
+ }
+ Shortcut {
+ sequence: "B"
+ onActivated: root.receivedB = true
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickwindow/data/visibilityDoesntClobberWindowState.qml b/tests/auto/quick/qquickwindow/data/visibilityDoesntClobberWindowState.qml
new file mode 100644
index 0000000000..af899ec5dd
--- /dev/null
+++ b/tests/auto/quick/qquickwindow/data/visibilityDoesntClobberWindowState.qml
@@ -0,0 +1,5 @@
+import QtQuick
+
+Window {
+
+}
diff --git a/tests/auto/quick/qquickwindow/data/windowattached.qml b/tests/auto/quick/qquickwindow/data/windowattached.qml
index 66083db428..2f0d08984f 100644
--- a/tests/auto/quick/qquickwindow/data/windowattached.qml
+++ b/tests/auto/quick/qquickwindow/data/windowattached.qml
@@ -1,5 +1,4 @@
-import QtQuick 2.4
-import QtQuick.Window 2.2
+import QtQuick
Rectangle {
id: root
@@ -19,6 +18,7 @@ Rectangle {
property Window extraWindow: Window {
objectName: "extraWindow"
title: "extra window"
+ transientParent: null
Text {
objectName: "extraWindowText"
anchors.centerIn: parent
diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
index 05fda64654..ff3edb3b64 100644
--- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
+++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp
@@ -1,33 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QDebug>
+#include <QEvent>
#include <QMimeData>
#include <QTouchEvent>
#include <QtQuick/QQuickItem>
@@ -38,9 +14,9 @@
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/private/qquickloader_p.h>
#include <QtQuick/private/qquickmousearea_p.h>
-#include "../../shared/util.h"
-#include "../shared/visualtestutil.h"
-#include "../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
#include <QSignalSpy>
#include <private/qquickwindow_p.h>
#include <private/qguiapplication_p.h>
@@ -50,7 +26,8 @@
#include <QQuickRenderControl>
#include <QOperatingSystemVersion>
#include <functional>
-#include <QtGui/private/qrhi_p.h>
+#include <QtGui/private/qeventpoint_p.h>
+#include <rhi/qrhi.h>
#if QT_CONFIG(opengl)
#include <QOpenGLContext>
#endif
@@ -68,16 +45,16 @@ struct TouchEventData {
QList<QEventPoint> touchPoints;
};
-static QMutableEventPoint makeTouchPoint(QQuickItem *item, const QPointF &p, const QPointF &lastPoint = QPointF())
+static QEventPoint makeTouchPoint(QQuickItem *item, const QPointF &p, const QPointF &lastPoint = QPointF())
{
QPointF last = lastPoint.isNull() ? p : lastPoint;
- QMutableEventPoint tp;
+ QEventPoint tp;
- tp.setPosition(p);
- tp.setScenePosition(item->mapToScene(p));
- tp.setGlobalPosition(item->mapToGlobal(p));
- tp.setGlobalLastPosition(item->mapToGlobal(last));
+ QMutableEventPoint::setPosition(tp, p);
+ QMutableEventPoint::setScenePosition(tp, item->mapToScene(p));
+ QMutableEventPoint::setGlobalPosition(tp, item->mapToGlobal(p));
+ QMutableEventPoint::setGlobalLastPosition(tp, item->mapToGlobal(last));
return tp;
}
@@ -86,7 +63,7 @@ static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, QEventPoint::
{
TouchEventData d = { type, nullptr, w, states, touchPoints };
for (auto &pt : d.touchPoints)
- QMutableEventPoint::from(pt).detach();
+ QMutableEventPoint::detach(pt);
return d;
}
static TouchEventData makeTouchData(QEvent::Type type, QWindow *w, QEventPoint::States states,
@@ -211,7 +188,8 @@ public:
QPointF lastMousePos;
QInputDevice::Capabilities lastMouseCapabilityFlags;
- void touchEvent(QTouchEvent *event) {
+ void touchEvent(QTouchEvent *event) override
+ {
if (!acceptTouchEvents) {
event->ignore();
return;
@@ -229,7 +207,8 @@ public:
}
}
- void mousePressEvent(QMouseEvent *e) {
+ void mousePressEvent(QMouseEvent *e) override
+ {
if (!acceptMouseEvents) {
e->ignore();
return;
@@ -239,7 +218,8 @@ public:
lastMouseCapabilityFlags = e->device()->capabilities();
}
- void mouseMoveEvent(QMouseEvent *e) {
+ void mouseMoveEvent(QMouseEvent *e) override
+ {
if (!acceptMouseEvents) {
e->ignore();
return;
@@ -250,7 +230,8 @@ public:
lastMousePos = e->position().toPoint();
}
- void mouseReleaseEvent(QMouseEvent *e) {
+ void mouseReleaseEvent(QMouseEvent *e) override
+ {
if (!acceptMouseEvents) {
e->ignore();
return;
@@ -260,12 +241,14 @@ public:
lastMouseCapabilityFlags = e->device()->capabilities();
}
- void mouseUngrabEvent() {
+ void mouseUngrabEvent() override
+ {
qCDebug(lcTests) << objectName();
++mouseUngrabEventCount;
}
- bool childMouseEventFilter(QQuickItem *item, QEvent *e) {
+ bool childMouseEventFilter(QQuickItem *item, QEvent *e) override
+ {
qCDebug(lcTests) << objectName() << "filtering" << e << "ahead of delivery to" << item->metaObject()->className() << item->objectName();
switch (e->type()) {
case QEvent::MouseButtonPress:
@@ -295,7 +278,8 @@ int TestTouchItem::mouseReleaseNum = 0;
class EventFilter : public QObject
{
public:
- bool eventFilter(QObject *watched, QEvent *event) {
+ bool eventFilter(QObject *watched, QEvent *event) override
+ {
Q_UNUSED(watched);
events.append(event->type());
return false;
@@ -312,37 +296,76 @@ public:
int iterations;
protected:
- QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *){
+ QSGNode* updatePaintNode(QSGNode *, UpdatePaintNodeData *) override
+ {
iterations++;
update();
return nullptr;
}
};
-class MouseRecordingWindow : public QQuickWindow
+class PointerRecordingWindow : public QQuickWindow
{
public:
- explicit MouseRecordingWindow(QWindow *parent = nullptr) : QQuickWindow(parent) { }
+ explicit PointerRecordingWindow(QWindow *parent = nullptr) : QQuickWindow(parent) { }
protected:
+ bool event(QEvent *event) override {
+ if (event->isPointerEvent()) {
+ qCDebug(lcTests) << event;
+ m_events << PointerEvent { event->type(), static_cast<QPointerEvent *>(event)->pointingDevice() };
+ }
+ return QQuickWindow::event(event);
+ }
+
void mousePressEvent(QMouseEvent *event) override {
qCDebug(lcTests) << event;
- m_mouseEvents << event->source();
+ m_mouseEvents << PointerEvent { event->type(), event->pointingDevice() };
QQuickWindow::mousePressEvent(event);
}
void mouseMoveEvent(QMouseEvent *event) override {
qCDebug(lcTests) << event;
- m_mouseEvents << event->source();
+ m_mouseEvents << PointerEvent { event->type(), event->pointingDevice() };
QQuickWindow::mouseMoveEvent(event);
}
void mouseReleaseEvent(QMouseEvent *event) override {
qCDebug(lcTests) << event;
- m_mouseEvents << event->source();
+ m_mouseEvents << PointerEvent { event->type(), event->pointingDevice() };
QQuickWindow::mouseReleaseEvent(event);
}
+ void touchEvent(QTouchEvent * event) override {
+ qCDebug(lcTests) << event;
+ m_touchEvents << PointerEvent { event->type(), event->pointingDevice() };
+ QQuickWindow::touchEvent(event);
+ }
+
+#if QT_CONFIG(tabletevent)
+ void tabletEvent(QTabletEvent * event) override {
+ qCDebug(lcTests) << event;
+ m_tabletEvents << PointerEvent { event->type(), event->pointingDevice() };
+ QQuickWindow::tabletEvent(event);
+ }
+#endif
+
+#if QT_CONFIG(wheelevent)
+ void wheelEvent(QWheelEvent * event) override {
+ qCDebug(lcTests) << event;
+ m_tabletEvents << PointerEvent { event->type(), event->pointingDevice() };
+ QQuickWindow::wheelEvent(event);
+ }
+#endif
+
public:
- QList<Qt::MouseEventSource> m_mouseEvents;
+ struct PointerEvent
+ {
+ QEvent::Type type;
+ const QPointingDevice *device;
+ };
+ QList<PointerEvent> m_events;
+ QList<PointerEvent> m_mouseEvents;
+ QList<PointerEvent> m_touchEvents;
+ QList<PointerEvent> m_tabletEvents;
};
class MouseRecordingItem : public QQuickItem
@@ -394,14 +417,19 @@ class tst_qquickwindow : public QQmlDataTest
Q_OBJECT
public:
tst_qquickwindow()
- : touchDevice(QTest::createTouchDevice())
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+ , touchDevice(QTest::createTouchDevice())
, touchDeviceWithVelocity(QTest::createTouchDevice(QInputDevice::DeviceType::TouchScreen,
QInputDevice::Capability::Position | QPointingDevice::Capability::Velocity))
+ , tabletStylusDevice(QPointingDevicePrivate::tabletDevice(QInputDevice::DeviceType::Stylus,
+ QPointingDevice::PointerType::Pen,
+ QPointingDeviceUniqueId::fromNumericId(1234567890)))
{
QQuickWindow::setDefaultAlphaBuffer(true);
}
private slots:
+ void initTestCase() override;
void cleanup();
void aboutToStopSignal();
@@ -438,6 +466,7 @@ private slots:
void grab_data();
void grab();
+ void earlyGrab();
void multipleWindows();
void animationsWhileHidden();
@@ -501,8 +530,13 @@ private slots:
void testChildMouseEventFilter_data();
void cleanupGrabsOnRelease();
+ void subclassWithPointerEventVirtualOverrides_data();
+ void subclassWithPointerEventVirtualOverrides();
+
#if QT_CONFIG(shortcut)
void testShortCut();
+ void shortcutOverride_data();
+ void shortcutOverride();
#endif
void rendererInterface();
@@ -510,15 +544,40 @@ private slots:
void rendererInterfaceWithRenderControl_data();
void rendererInterfaceWithRenderControl();
+ void graphicsConfiguration();
+
+ void visibleVsVisibility_data();
+ void visibleVsVisibility();
+
+ void visibilityDoesntClobberWindowState();
+
+ void eventTypes();
+
private:
- QPointingDevice *touchDevice;
- QPointingDevice *touchDeviceWithVelocity;
+ QPointingDevice *touchDevice; // TODO make const after fixing QTBUG-107864
+ const QPointingDevice *touchDeviceWithVelocity;
+ const QPointingDevice *tabletStylusDevice;
};
#if QT_CONFIG(opengl)
Q_DECLARE_METATYPE(QOpenGLContext *);
#endif
+void tst_qquickwindow::initTestCase()
+{
+ // for the graphicsConfiguration test
+ qunsetenv("QSG_NO_DEPTH_BUFFER");
+ qunsetenv("QSG_RHI_DEBUG_LAYER");
+ qunsetenv("QSG_RHI_PROFILE");
+ qunsetenv("QSG_RHI_PREFER_SOFTWARE_RENDERER");
+ qunsetenv("QT_DISABLE_SHADER_DISK_CACHE");
+ qunsetenv("QSG_RHI_DISABLE_DISK_CACHE");
+ qunsetenv("QSG_RHI_PIPELINE_CACHE_SAVE");
+ qunsetenv("QSG_RHI_PIPELINE_CACHE_LOAD");
+
+ QQmlDataTest::initTestCase();
+}
+
void tst_qquickwindow::cleanup()
{
QVERIFY(QGuiApplication::topLevelWindows().isEmpty());
@@ -535,7 +594,7 @@ void tst_qquickwindow::aboutToStopSignal()
window.hide();
- QTRY_VERIFY(spy.count() > 0);
+ QTRY_VERIFY(spy.size() > 0);
}
//If the item calls update inside updatePaintNode, it should schedule another sync pass
@@ -551,8 +610,8 @@ void tst_qquickwindow::constantUpdates()
QSignalSpy afterSpy(&window, SIGNAL(afterSynchronizing()));
QTRY_VERIFY(item.iterations > 10);
- QTRY_VERIFY(beforeSpy.count() > 10);
- QTRY_VERIFY(afterSpy.count() > 10);
+ QTRY_VERIFY(beforeSpy.size() > 10);
+ QTRY_VERIFY(afterSpy.size() > 10);
}
void tst_qquickwindow::constantUpdatesOnWindow_data()
@@ -653,7 +712,7 @@ void tst_qquickwindow::touchEvent_basic()
// press single point
touchSeq.press(0, topItem->mapToScene(pos).toPoint(),window).commit();
QQuickTouchUtils::flush(window);
- QTRY_COMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QTRY_COMPARE(topItem->lastEvent.touchPoints.size(), 1);
QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
@@ -667,9 +726,9 @@ void tst_qquickwindow::touchEvent_basic()
touchSeq.press(0, topItem->mapToScene(pos).toPoint(), window)
.press(1, bottomItem->mapToScene(pos).toPoint(), window).commit();
QQuickTouchUtils::flush(window);
- QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QCOMPARE(topItem->lastEvent.touchPoints.size(), 1);
QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
- QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ QCOMPARE(bottomItem->lastEvent.touchPoints.size(), 1);
COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, makeTouchPoint(topItem, pos)));
COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, makeTouchPoint(bottomItem, pos)));
topItem->reset();
@@ -681,7 +740,7 @@ void tst_qquickwindow::touchEvent_basic()
QQuickTouchUtils::flush(window);
touchSeq.move(0, bottomItem->mapToScene(pos).toPoint(), window).commit();
QQuickTouchUtils::flush(window);
- QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QCOMPARE(topItem->lastEvent.touchPoints.size(), 1);
COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, QEventPoint::State::Updated,
makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
topItem->reset();
@@ -692,7 +751,7 @@ void tst_qquickwindow::touchEvent_basic()
QQuickTouchUtils::flush(window);
touchSeq.move(0, topItem->mapToScene(pos).toPoint(), window).commit();
QQuickTouchUtils::flush(window);
- QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ QCOMPARE(bottomItem->lastEvent.touchPoints.size(), 1);
COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, QEventPoint::State::Updated,
makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos), pos)));
bottomItem->reset();
@@ -704,9 +763,9 @@ void tst_qquickwindow::touchEvent_basic()
touchSeq.stationary(0)
.press(1, bottomItem->mapToScene(pos).toPoint(), window).commit();
QQuickTouchUtils::flush(window);
- QCOMPARE(topItem->lastEvent.touchPoints.count(), 1); // received press and then stationary
+ QCOMPARE(topItem->lastEvent.touchPoints.size(), 1); // received press and then stationary
QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
- QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ QCOMPARE(bottomItem->lastEvent.touchPoints.size(), 1);
COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchUpdate, window, QEventPoint::State::Stationary, makeTouchPoint(topItem, pos)));
COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, makeTouchPoint(bottomItem, pos)));
topItem->reset();
@@ -722,7 +781,7 @@ void tst_qquickwindow::touchEvent_basic()
QQuickTouchUtils::flush(window);
touchSeq.release(0, bottomItem->mapToScene(pos).toPoint(),window).commit();
QQuickTouchUtils::flush(window);
- QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QCOMPARE(topItem->lastEvent.touchPoints.size(), 1);
COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchEnd, window, QEventPoint::State::Released,
makeTouchPoint(topItem, topItem->mapFromItem(bottomItem, pos), pos)));
topItem->reset();
@@ -736,9 +795,9 @@ void tst_qquickwindow::touchEvent_basic()
touchSeq.release(0, bottomItem->mapToScene(pos).toPoint(), window)
.stationary(1).commit();
QQuickTouchUtils::flush(window);
- QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QCOMPARE(topItem->lastEvent.touchPoints.size(), 1);
QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
- QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ QCOMPARE(bottomItem->lastEvent.touchPoints.size(), 1);
// Since qtbase 2692237bb1b0c0f50b7cc5d920eb8ab065063d47, if the point didn't have a different position on release,
// then lastPosition is not changed. So in this case, it still holds the press position. I.e. on release,
// it's the last position that was actually different.
@@ -799,7 +858,7 @@ void tst_qquickwindow::touchEvent_propagation()
// single touch to top item, should be received by middle item
QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window);
- QTRY_COMPARE(middleItem->lastEvent.touchPoints.count(), 1);
+ QTRY_COMPARE(middleItem->lastEvent.touchPoints.size(), 1);
QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed,
@@ -809,7 +868,7 @@ void tst_qquickwindow::touchEvent_propagation()
// touch top and middle items, middle item should get both events
QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window)
.press(1, pointInMiddleItem, window);
- QTRY_COMPARE(middleItem->lastEvent.touchPoints.count(), 2);
+ QTRY_COMPARE(middleItem->lastEvent.touchPoints.size(), 2);
QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed,
@@ -828,7 +887,7 @@ void tst_qquickwindow::touchEvent_propagation()
// touch top and middle items, bottom item should get all events
QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window)
.press(1, pointInMiddleItem, window);
- QTRY_COMPARE(bottomItem->lastEvent.touchPoints.count(), 2);
+ QTRY_COMPARE(bottomItem->lastEvent.touchPoints.size(), 2);
QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed,
@@ -868,12 +927,12 @@ void tst_qquickwindow::touchEvent_propagation()
// middle item is disabled or has 0 opacity, bottom item receives the event
QVERIFY(topItem->lastEvent.touchPoints.isEmpty());
QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
- QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 1);
+ QCOMPARE(bottomItem->lastEvent.touchPoints.size(), 1);
COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed,
makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos))));
} else {
// middle item ignores event, sends it to the top item (top-most child)
- QCOMPARE(topItem->lastEvent.touchPoints.count(), 1);
+ QCOMPARE(topItem->lastEvent.touchPoints.size(), 1);
QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed,
@@ -919,7 +978,7 @@ void tst_qquickwindow::touchEvent_cancel()
QTest::touchEvent(window, touchDevice).press(0, item->mapToScene(pos).toPoint(), window);
QCoreApplication::processEvents();
- QTRY_COMPARE(item->lastEvent.touchPoints.count(), 1);
+ QTRY_COMPARE(item->lastEvent.touchPoints.size(), 1);
TouchEventData d = makeTouchData(QEvent::TouchBegin, window, QEventPoint::State::Pressed, makeTouchPoint(item, pos));
COMPARE_TOUCH_DATA(item->lastEvent, d);
item->reset();
@@ -1020,13 +1079,13 @@ void tst_qquickwindow::touchEvent_velocity()
item->setPosition(QPointF(50, 50));
item->setSize(QSizeF(150, 150));
- QList<QMutableEventPoint> points;
- QMutableEventPoint tp(1, QEventPoint::State::Pressed);
+ QList<QEventPoint> points;
+ QEventPoint tp(1, QEventPoint::State::Pressed, {}, {});
const QPointF localPos = item->mapToScene(QPointF(10, 10));
const QPointF screenPos = window->mapToGlobal(localPos.toPoint());
- tp.setPosition(localPos);
- tp.setGlobalPosition(screenPos);
- tp.setEllipseDiameters(QSizeF(4, 4));
+ QMutableEventPoint::setPosition(tp, localPos);
+ QMutableEventPoint::setGlobalPosition(tp, screenPos);
+ QMutableEventPoint::setEllipseDiameters(tp, QSizeF(4, 4));
points << tp;
QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity,
QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window));
@@ -1034,17 +1093,17 @@ void tst_qquickwindow::touchEvent_velocity()
QQuickTouchUtils::flush(window);
QCOMPARE(item->touchEventCount, 1);
- points[0].setState(QEventPoint::State::Updated);
- points[0].setPosition(localPos + QPointF(5, 5));
- points[0].setGlobalPosition(screenPos + QPointF(5, 5));
+ QMutableEventPoint::setState(points[0], QEventPoint::State::Updated);
+ QMutableEventPoint::setPosition(points[0], localPos + QPointF(5, 5));
+ QMutableEventPoint::setGlobalPosition(points[0], screenPos + QPointF(5, 5));
QVector2D velocity(1.5, 2.5);
- points[0].setVelocity(velocity);
+ QMutableEventPoint::setVelocity(points[0], velocity);
QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity,
QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window));
QGuiApplication::processEvents();
QQuickTouchUtils::flush(window);
QCOMPARE(item->touchEventCount, 2);
- QCOMPARE(item->lastEvent.touchPoints.count(), 1);
+ QCOMPARE(item->lastEvent.touchPoints.size(), 1);
QCOMPARE(item->lastVelocity, velocity);
// Now have a transformation on the item and check if position is transformed accordingly.
@@ -1052,8 +1111,8 @@ void tst_qquickwindow::touchEvent_velocity()
// during delivery. If we want it to be transformed, we should add QEventPoint::sceneVelocity
// so that we can keep transforming it repeatedly during Item-localization.)
item->setRotation(90); // clockwise
- points[0].setPosition(points[0].position() + QPointF(5, 5));
- points[0].setGlobalPosition(points[0].globalPosition() + QPointF(5, 5));
+ QMutableEventPoint::setPosition(points[0], points[0].position() + QPointF(5, 5));
+ QMutableEventPoint::setGlobalPosition(points[0], points[0].globalPosition() + QPointF(5, 5));
QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity,
QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window));
QGuiApplication::processEvents();
@@ -1063,7 +1122,7 @@ void tst_qquickwindow::touchEvent_velocity()
QPoint itemLocalPosFromEvent = item->lastEvent.touchPoints[0].position().toPoint();
QCOMPARE(itemLocalPos, itemLocalPosFromEvent);
- points[0].setState(QEventPoint::State::Released);
+ QMutableEventPoint::setState(points[0], QEventPoint::State::Released);
QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity,
QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window));
QGuiApplication::processEvents();
@@ -1160,28 +1219,28 @@ void tst_qquickwindow::mouseFromTouch_basic()
// the first point in each touch event should generate a synth-mouse event.
item->setAcceptTouchEvents(false);
- QList<QMutableEventPoint> points;
- QMutableEventPoint tp(1, QEventPoint::State::Pressed);
+ QList<QEventPoint> points;
+ QEventPoint tp(1, QEventPoint::State::Pressed, {}, {});
const QPointF localPos = item->mapToScene(QPointF(10, 10));
const QPointF screenPos = window->mapToGlobal(localPos.toPoint());
- tp.setPosition(localPos);
- tp.setGlobalPosition(screenPos);
- tp.setEllipseDiameters(QSizeF(4, 4));
+ QMutableEventPoint::setPosition(tp, localPos);
+ QMutableEventPoint::setGlobalPosition(tp, screenPos);
+ QMutableEventPoint::setEllipseDiameters(tp, QSizeF(4, 4));
points << tp;
QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity,
QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window));
QGuiApplication::processEvents();
QQuickTouchUtils::flush(window);
- points[0].setState(QEventPoint::State::Updated);
- points[0].setPosition(localPos + QPointF(5, 5));
- points[0].setGlobalPosition(screenPos + QPointF(5, 5));
+ QMutableEventPoint::setState(points[0], QEventPoint::State::Updated);
+ QMutableEventPoint::setPosition(points[0], localPos + QPointF(5, 5));
+ QMutableEventPoint::setGlobalPosition(points[0], screenPos + QPointF(5, 5));
QVector2D velocity(1.5, 2.5);
- points[0].setVelocity(velocity);
+ QMutableEventPoint::setVelocity(points[0], velocity);
QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity,
QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window));
QGuiApplication::processEvents();
QQuickTouchUtils::flush(window);
- points[0].setState(QEventPoint::State::Released);
+ QMutableEventPoint::setState(points[0], QEventPoint::State::Released);
QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity,
QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window));
QGuiApplication::processEvents();
@@ -1195,19 +1254,20 @@ void tst_qquickwindow::mouseFromTouch_basic()
QCOMPARE(item->lastVelocityFromMouseMove, velocity);
// QVERIFY(item->lastMouseCapabilityFlags.testFlag(QInputDevice::Capability::Velocity)); // TODO
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10); // avoid generating a double-click
// Now the same with a transformation.
item->setRotation(90); // clockwise
- points[0].setState(QEventPoint::State::Pressed);
- points[0].setVelocity(velocity);
- tp.setPosition(localPos);
- tp.setGlobalPosition(screenPos);
+ QMutableEventPoint::setState(points[0], QEventPoint::State::Pressed);
+ QMutableEventPoint::setVelocity(points[0], velocity);
+ QMutableEventPoint::setPosition(tp, localPos);
+ QMutableEventPoint::setGlobalPosition(tp, screenPos);
QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity,
QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window));
QGuiApplication::processEvents();
QQuickTouchUtils::flush(window);
- points[0].setState(QEventPoint::State::Updated);
- points[0].setPosition(localPos + QPointF(5, 5));
- points[0].setGlobalPosition(screenPos + QPointF(5, 5));
+ QMutableEventPoint::setState(points[0], QEventPoint::State::Updated);
+ QMutableEventPoint::setPosition(points[0], localPos + QPointF(5, 5));
+ QMutableEventPoint::setGlobalPosition(points[0], screenPos + QPointF(5, 5));
QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity,
QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window));
QGuiApplication::processEvents();
@@ -1215,7 +1275,7 @@ void tst_qquickwindow::mouseFromTouch_basic()
QCOMPARE(item->lastMousePos.toPoint(), item->mapFromScene(points[0].position()).toPoint());
QCOMPARE(item->lastVelocityFromMouseMove, velocity); // Velocity is always in scene coords
- points[0].setState(QEventPoint::State::Released);
+ QMutableEventPoint::setState(points[0], QEventPoint::State::Released);
QWindowSystemInterface::handleTouchEvent(window, touchDeviceWithVelocity,
QWindowSystemInterfacePrivate::toNativeTouchPoints(points, window));
QCoreApplication::processEvents();
@@ -1240,7 +1300,7 @@ void tst_qquickwindow::synthMouseFromTouch()
QFETCH(bool, acceptTouch);
QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, synthMouse);
- QScopedPointer<MouseRecordingWindow> window(new MouseRecordingWindow);
+ QScopedPointer<PointerRecordingWindow> window(new PointerRecordingWindow);
QScopedPointer<MouseRecordingItem> item(new MouseRecordingItem(acceptTouch, nullptr));
item->setParentItem(window->contentItem());
window->resize(250, 250);
@@ -1258,9 +1318,9 @@ void tst_qquickwindow::synthMouseFromTouch()
QTest::touchEvent(window.data(), touchDevice).release(0, p2, window.data());
QQuickTouchUtils::flush(window.data());
- QCOMPARE(item->m_touchEvents.count(), acceptTouch ? 3 : 0);
- QCOMPARE(item->m_mouseEvents.count(), (acceptTouch || !synthMouse) ? 0 : 3);
- QCOMPARE(window->m_mouseEvents.count(), 0);
+ QCOMPARE(item->m_touchEvents.size(), acceptTouch ? 3 : 0);
+ QCOMPARE(item->m_mouseEvents.size(), (acceptTouch || !synthMouse) ? 0 : 3);
+ QCOMPARE(window->m_mouseEvents.size(), 0);
for (const auto &ev : item->m_mouseEvents)
QCOMPARE(ev.source, Qt::MouseEventSynthesizedByQt);
}
@@ -1285,7 +1345,7 @@ void tst_qquickwindow::synthMouseDoubleClickFromTouch()
QFETCH(bool, expectedSynthesizedDoubleClickEvent);
QCoreApplication::setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, true);
- QScopedPointer<MouseRecordingWindow> window(new MouseRecordingWindow);
+ QScopedPointer<PointerRecordingWindow> window(new PointerRecordingWindow);
QScopedPointer<MouseRecordingItem> item(new MouseRecordingItem(false, nullptr));
item->setParentItem(window->contentItem());
window->resize(250, 250);
@@ -1305,7 +1365,7 @@ void tst_qquickwindow::synthMouseDoubleClickFromTouch()
QTest::touchEvent(window.data(), touchDevice).move(1, p2 + movement, window.data());
QTest::touchEvent(window.data(), touchDevice).release(1, p2 + movement, window.data());
- const int eventCount = item->m_mouseEvents.count();
+ const int eventCount = item->m_mouseEvents.size();
QVERIFY(eventCount >= 2);
const int nDoubleClicks = std::count_if(item->m_mouseEvents.constBegin(), item->m_mouseEvents.constEnd(),
@@ -1518,8 +1578,7 @@ void tst_qquickwindow::grab()
}
QImage content = window.grabWindow();
- QCOMPARE(content.width(), int(window.width() * window.devicePixelRatio()));
- QCOMPARE(content.height(), int(window.height() * window.devicePixelRatio()));
+ QCOMPARE(content.size(), window.size() * window.devicePixelRatio());
if (alpha) {
QCOMPARE((uint) content.convertToFormat(QImage::Format_ARGB32_Premultiplied).pixel(0, 0), (uint) 0x00000000);
@@ -1534,8 +1593,7 @@ void tst_qquickwindow::grab()
// never was renderable before grabbing.
window.hide();
QImage content = window.grabWindow();
- QCOMPARE(content.width(), int(window.width() * window.devicePixelRatio()));
- QCOMPARE(content.height(), int(window.height() * window.devicePixelRatio()));
+ QCOMPARE(content.size(), window.size() * window.devicePixelRatio());
if (alpha) {
QCOMPARE((uint) content.convertToFormat(QImage::Format_ARGB32_Premultiplied).pixel(0, 0), (uint) 0x00000000);
} else {
@@ -1546,8 +1604,7 @@ void tst_qquickwindow::grab()
window.show();
QVERIFY(QTest::qWaitForWindowExposed(&window));
content = window.grabWindow();
- QCOMPARE(content.width(), int(window.width() * window.devicePixelRatio()));
- QCOMPARE(content.height(), int(window.height() * window.devicePixelRatio()));
+ QCOMPARE(content.size(), window.size() * window.devicePixelRatio());
if (alpha) {
QCOMPARE((uint) content.convertToFormat(QImage::Format_ARGB32_Premultiplied).pixel(0, 0), (uint) 0x00000000);
} else {
@@ -1556,6 +1613,39 @@ void tst_qquickwindow::grab()
}
}
+class Grabber : public QObject
+{
+ Q_OBJECT
+public:
+ Q_INVOKABLE void grab(QObject *obj) {
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(obj);
+ images.append(window->grabWindow());
+ }
+ QVector<QImage> images;
+};
+
+void tst_qquickwindow::earlyGrab()
+{
+ if (QGuiApplication::platformName() == QLatin1String("minimal"))
+ QSKIP("Skipping due to grabWindow not functional on minimal platforms");
+
+ qmlRegisterType<Grabber>("Test", 1, 0, "Grabber");
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("earlyGrab.qml"));
+ QScopedPointer<QQuickWindow> window(qobject_cast<QQuickWindow *>(component.create()));
+ QVERIFY(!window.isNull());
+ window->setTitle(QTest::currentTestFunction());
+
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ Grabber *grabber = qobject_cast<Grabber *>(window->findChild<QObject *>("grabber"));
+ QVERIFY(grabber);
+ QCOMPARE(grabber->images.size(), 1);
+ QVERIFY(!grabber->images[0].isNull());
+ QCOMPARE(grabber->images[0].convertToFormat(QImage::Format_RGBX8888).pixel(10, 20), QColor(Qt::red).rgb());
+}
+
void tst_qquickwindow::multipleWindows()
{
QList<QQuickWindow *> windows;
@@ -1658,7 +1748,7 @@ void tst_qquickwindow::headless()
// Verify that the visual output is the same
QImage newContent = window->grabWindow();
QString errorMessage;
- QVERIFY2(QQuickVisualTestUtil::compareImages(newContent, originalContent, &errorMessage),
+ QVERIFY2(QQuickVisualTestUtils::compareImages(newContent, originalContent, &errorMessage),
qPrintable(errorMessage));
}
@@ -1693,7 +1783,7 @@ void tst_qquickwindow::destroyShowWithoutHide()
QImage newContent = window->grabWindow();
QString errorMessage;
- QVERIFY2(QQuickVisualTestUtil::compareImages(newContent, originalContent, &errorMessage),
+ QVERIFY2(QQuickVisualTestUtils::compareImages(newContent, originalContent, &errorMessage),
qPrintable(errorMessage));
}
@@ -1719,19 +1809,19 @@ void tst_qquickwindow::focusObject()
QVERIFY(QTest::qWaitForWindowActive(window));
QCOMPARE(window->contentItem(), window->focusObject());
- QCOMPARE(focusObjectSpy.count(), 1);
+ QCOMPARE(focusObjectSpy.size(), 1);
QQuickItem *item1 = window->findChild<QQuickItem*>("item1");
QVERIFY(item1);
item1->setFocus(true);
QCOMPARE(item1, window->focusObject());
- QCOMPARE(focusObjectSpy.count(), 2);
+ QCOMPARE(focusObjectSpy.size(), 2);
QQuickItem *item2 = window->findChild<QQuickItem*>("item2");
QVERIFY(item2);
item2->setFocus(true);
QCOMPARE(item2, window->focusObject());
- QCOMPARE(focusObjectSpy.count(), 3);
+ QCOMPARE(focusObjectSpy.size(), 3);
// set focus for item in non-focused focus scope and
// ensure focusObject does not change and signal is not emitted
@@ -1739,7 +1829,7 @@ void tst_qquickwindow::focusObject()
QVERIFY(item3);
item3->setFocus(true);
QCOMPARE(item2, window->focusObject());
- QCOMPARE(focusObjectSpy.count(), 3);
+ QCOMPARE(focusObjectSpy.size(), 3);
}
void tst_qquickwindow::focusReason()
@@ -1784,24 +1874,24 @@ void tst_qquickwindow::ignoreUnhandledMouseEvents()
item->setParentItem(window->contentItem());
{
- QMouseEvent me(QEvent::MouseButtonPress, QPointF(50, 50), Qt::LeftButton, Qt::LeftButton,
- Qt::NoModifier);
+ QMouseEvent me(QEvent::MouseButtonPress, QPointF(50, 50), window->mapToGlobal(QPointF(50, 50)),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
me.setAccepted(true);
QVERIFY(QCoreApplication::sendEvent(window, &me));
QVERIFY(!me.isAccepted());
}
{
- QMouseEvent me(QEvent::MouseMove, QPointF(51, 51), Qt::LeftButton, Qt::LeftButton,
- Qt::NoModifier);
+ QMouseEvent me(QEvent::MouseMove, QPointF(51, 51), window->mapToGlobal(QPointF(51, 51)),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
me.setAccepted(true);
QVERIFY(QCoreApplication::sendEvent(window, &me));
QVERIFY(!me.isAccepted());
}
{
- QMouseEvent me(QEvent::MouseButtonRelease, QPointF(51, 51), Qt::LeftButton, Qt::LeftButton,
- Qt::NoModifier);
+ QMouseEvent me(QEvent::MouseButtonRelease, QPointF(51, 51), window->mapToGlobal(QPointF(51, 51)),
+ Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
me.setAccepted(true);
QVERIFY(QCoreApplication::sendEvent(window, &me));
QVERIFY(!me.isAccepted());
@@ -2080,6 +2170,10 @@ void tst_qquickwindow::testExpose()
void tst_qquickwindow::requestActivate()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("tst_qquickwindow::requestActivate crashes on Android, see QTBUG-103078.");
+#endif
+
QQmlEngine engine;
QQmlComponent component(&engine);
component.loadUrl(testFileUrl("active.qml"));
@@ -2106,7 +2200,7 @@ void tst_qquickwindow::requestActivate()
QTRY_COMPARE(QGuiApplication::focusWindow(), window1.data());
QVERIFY(window1->isActive());
- QQuickItem *item = QQuickVisualTestUtil::findItem<QQuickItem>(window1->contentItem(), "item1");
+ QQuickItem *item = QQuickVisualTestUtils::findItem<QQuickItem>(window1->contentItem(), "item1");
QVERIFY(item);
//copied from src/qmltest/quicktestevent.cpp
@@ -2115,18 +2209,14 @@ void tst_qquickwindow::requestActivate()
{
QMouseEvent me(QEvent::MouseButtonPress, pos, window1->mapToGlobal(pos), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QSpontaneKeyEvent::setSpontaneous(&me);
- if (!qApp->notify(window1.data(), &me)) {
- QString warning = QString::fromLatin1("Mouse event MousePress not accepted by receiving window");
- QWARN(warning.toLatin1().data());
- }
+ if (!qApp->notify(window1.data(), &me))
+ qWarning("Mouse event MousePress not accepted by receiving window");
}
{
QMouseEvent me = QMouseEvent(QEvent::MouseButtonPress, pos, window1->mapToGlobal(pos), Qt::LeftButton, {}, Qt::NoModifier);
QSpontaneKeyEvent::setSpontaneous(&me);
- if (!qApp->notify(window1.data(), &me)) {
- QString warning = QString::fromLatin1("Mouse event MouseRelease not accepted by receiving window");
- QWARN(warning.toLatin1().data());
- }
+ if (!qApp->notify(window1.data(), &me))
+ qWarning("Mouse event MouseRelease not accepted by receiving window");
}
QTRY_COMPARE(QGuiApplication::focusWindow(), windows.at(0));
@@ -2135,6 +2225,10 @@ void tst_qquickwindow::requestActivate()
void tst_qquickwindow::testWindowVisibilityOrder()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("tst_qquickwindow::testWindowVisibilityOrder crashes on Android, see QTBUG-103078.");
+#endif
+
QQmlEngine engine;
QQmlComponent component(&engine);
component.loadUrl(testFileUrl("windoworder.qml"));
@@ -2252,6 +2346,10 @@ void tst_qquickwindow::unloadSubWindow()
// QTBUG-52573
void tst_qquickwindow::changeVisibilityInCompleted()
{
+#ifdef Q_OS_ANDROID
+ QSKIP("tst_qquickwindow::changeVisibilityInCompleted crashes on Android, see QTBUG-103078.");
+#endif
+
QQmlEngine engine;
QQmlComponent component(&engine);
component.loadUrl(testFileUrl("changeVisibilityInCompleted.qml"));
@@ -2293,7 +2391,7 @@ void tst_qquickwindow::qobjectEventFilter_touch()
// press single point
QTest::touchEvent(&window, touchDevice).press(0, item->mapToScene(pos).toPoint(), &window);
- QCOMPARE(eventFilter.events.count(), 1);
+ QCOMPARE(eventFilter.events.size(), 1);
QCOMPARE(eventFilter.events.first(), (int)QEvent::TouchBegin);
}
@@ -2364,7 +2462,7 @@ void tst_qquickwindow::animatingSignal()
window.show();
QTRY_VERIFY(window.isExposed());
- QTRY_VERIFY(spy.count() > 1);
+ QTRY_VERIFY(spy.size() > 1);
}
void tst_qquickwindow::frameSignals()
@@ -2381,9 +2479,9 @@ void tst_qquickwindow::frameSignals()
QSGRendererInterface *rif = window.rendererInterface();
QVERIFY(rif);
- QTRY_VERIFY(beforeSpy.count() > 1);
- QTRY_VERIFY(afterSpy.count() > 1);
- QTRY_COMPARE(beforeSpy.count(), afterSpy.count());
+ QTRY_VERIFY(beforeSpy.size() > 1);
+ QTRY_VERIFY(afterSpy.size() > 1);
+ QTRY_COMPARE(beforeSpy.size(), afterSpy.size());
}
// QTBUG-36938
@@ -2513,7 +2611,8 @@ public:
~RenderJob() { ++deleted; }
QQuickWindow::RenderStage stage;
QList<QQuickWindow::RenderStage> *list;
- void run() {
+ void run() override
+ {
list->append(stage);
}
static int deleted;
@@ -2697,9 +2796,12 @@ public:
setAcceptHoverEvents(true);
}
- void hoverEnterEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); }
- void hoverLeaveEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); }
- void hoverMoveEvent(QHoverEvent *event) { hoverTimestamps << event->timestamp(); }
+ void hoverEnterEvent(QHoverEvent *event) override
+ { hoverTimestamps << event->timestamp(); }
+ void hoverLeaveEvent(QHoverEvent *event) override
+ { hoverTimestamps << event->timestamp(); }
+ void hoverMoveEvent(QHoverEvent *event) override
+ { hoverTimestamps << event->timestamp(); }
QList<ulong> hoverTimestamps;
};
@@ -2828,8 +2930,8 @@ void tst_qquickwindow::test_circleMapItem()
mat->setObjectName("Top Item/MouseArea");
mat->setSize(QSizeF(40, 40));
- QSignalSpy bottomSpy(mab, SIGNAL(clicked(QQuickMouseEvent *)));
- QSignalSpy topSpy(mat, SIGNAL(clicked(QQuickMouseEvent *)));
+ QSignalSpy bottomSpy(mab, SIGNAL(clicked(QQuickMouseEvent*)));
+ QSignalSpy topSpy(mat, SIGNAL(clicked(QQuickMouseEvent*)));
window.show();
QVERIFY(QTest::qWaitForWindowExposed(&window));
@@ -2838,15 +2940,15 @@ void tst_qquickwindow::test_circleMapItem()
QPoint pos(50, 50);
QTest::mouseClick(&window, Qt::LeftButton, Qt::KeyboardModifiers(), pos);
- QCOMPARE(topSpy.count(), 1);
- QCOMPARE(bottomSpy.count(), 0);
+ QCOMPARE(topSpy.size(), 1);
+ QCOMPARE(bottomSpy.size(), 0);
// Outside the "Circles" "input area", but on top of the bottomItem rectangle
pos = QPoint(66, 66);
QTest::mouseClick(&window, Qt::LeftButton, Qt::KeyboardModifiers(), pos);
- QCOMPARE(bottomSpy.count(), 1);
- QCOMPARE(topSpy.count(), 1);
+ QCOMPARE(bottomSpy.size(), 1);
+ QCOMPARE(topSpy.size(), 1);
}
void tst_qquickwindow::grabContentItemToImage()
@@ -2892,19 +2994,19 @@ public:
dropAccept = true;
}
- void dragEnterEvent(QDragEnterEvent *event)
+ void dragEnterEvent(QDragEnterEvent *event) override
{
event->setAccepted(enterAccept);
event->setDropAction(enterDropAction);
}
- void dragMoveEvent(QDragMoveEvent *event)
+ void dragMoveEvent(QDragMoveEvent *event) override
{
event->setAccepted(moveAccept);
event->setDropAction(moveDropAction);
}
- void dropEvent(QDropEvent *event)
+ void dropEvent(QDropEvent *event) override
{
event->setAccepted(dropAccept);
event->setDropAction(dropDropAction);
@@ -3199,57 +3301,48 @@ public:
*/
bool testFilterPreConditions() const { return !m_filterNotPreAccepted; }
static QVector<DeliveryRecord> &deliveryList() { return m_deliveryList; }
- static QSet<QEvent::Type> &includedEventTypes()
+ static void setExpectedDeliveryList(const QVector<DeliveryRecord> &v) { m_expectedDeliveryList = v; }
+
+ bool isRelevant(QQuickItem *receiver, QEvent *e)
{
- if (m_includedEventTypes.isEmpty())
- m_includedEventTypes << QEvent::MouseButtonPress;
- return m_includedEventTypes;
+ if (receiver->acceptTouchEvents())
+ return e->type() == QEvent::TouchBegin;
+ return e->type() == QEvent::MouseButtonPress;
}
- static void setExpectedDeliveryList(const QVector<DeliveryRecord> &v) { m_expectedDeliveryList = v; }
protected:
bool childMouseEventFilter(QQuickItem *i, QEvent *e) override
{
+ if (!isRelevant(i, e))
+ return QQuickRectangle::childMouseEventFilter(i, e);
+
appendEvent(this, i, e);
- switch (e->type()) {
- case QEvent::MouseButtonPress:
- if (!e->isAccepted())
- m_filterNotPreAccepted = true;
- e->setAccepted(m_filterAccepts);
- // qCDebug(lcTests) << objectName() << i->objectName();
- return m_filterReturns;
- default:
- break;
- }
- return QQuickRectangle::childMouseEventFilter(i, e);
+ if (!e->isAccepted())
+ m_filterNotPreAccepted = true;
+ e->setAccepted(m_filterAccepts);
+ return m_filterReturns;
}
bool event(QEvent *e) override
{
+ if (!isRelevant(this, e))
+ QQuickRectangle::event(e);
+
appendEvent(nullptr, this, e);
- switch (e->type()) {
- case QEvent::MouseButtonPress:
- // qCDebug(lcTests) << objectName();
- e->setAccepted(m_eventAccepts);
- return true;
- default:
- break;
- }
- return QQuickRectangle::event(e);
+ e->setAccepted(m_eventAccepts);
+ return true;
}
private:
static void appendEvent(QQuickItem *filter, QQuickItem *receiver, QEvent *event) {
- if (includedEventTypes().contains(event->type())) {
- auto record = DeliveryRecord(filter ? filter->objectName() : QString(), receiver ? receiver->objectName() : QString());
- int i = m_deliveryList.count();
- if (m_expectedDeliveryList.count() > i && m_expectedDeliveryList[i] == record)
- qCDebug(lcTests).noquote().nospace() << i << ": " << record;
- else
- qCDebug(lcTests).noquote().nospace() << i << ": " << record
- << ", expected " << (m_expectedDeliveryList.count() > i ? m_expectedDeliveryList[i].toString() : QLatin1String("nothing")) << " <---";
- m_deliveryList << record;
- }
+ auto record = DeliveryRecord(filter ? filter->objectName() : QString(), receiver ? receiver->objectName() : QString());
+ int i = m_deliveryList.size();
+ if (m_expectedDeliveryList.size() > i && m_expectedDeliveryList[i] == record)
+ qCDebug(lcTests).noquote().nospace() << i << ": " << record;
+ else
+ qCDebug(lcTests).noquote().nospace() << i << ": " << record
+ << ", expected " << (m_expectedDeliveryList.size() > i ? m_expectedDeliveryList[i].toString() : QLatin1String("nothing")) << " <---";
+ m_deliveryList << record;
}
bool m_eventAccepts;
bool m_filterReturns;
@@ -3259,12 +3352,10 @@ private:
// list of (filtering-parent . receiver) pairs
static DeliveryRecordVector m_expectedDeliveryList;
static DeliveryRecordVector m_deliveryList;
- static QSet<QEvent::Type> m_includedEventTypes;
};
DeliveryRecordVector EventItem::m_expectedDeliveryList;
DeliveryRecordVector EventItem::m_deliveryList;
-QSet<QEvent::Type> EventItem::m_includedEventTypes;
typedef QVector<const char*> CharStarVector;
@@ -3289,11 +3380,17 @@ void tst_qquickwindow::testChildMouseEventFilter_data()
// r0->r1->r2->r3
//
QTest::addColumn<QPoint>("mousePos");
+ QTest::addColumn<QString>("eventMode");
QTest::addColumn<InputState>("inputState");
QTest::addColumn<DeliveryRecordVector>("expectedDeliveryOrder");
- QTest::newRow("if filtered and rejected, do not deliver it to the item that filtered it")
+ for (const QString &eventMode : {"mouse", "touch", "touchToMouse"}) {
+
+ #define desc(txt) qPrintable(QString("%1 events, ").arg(eventMode) + txt)
+
+ QTest::newRow(desc("if filtered and rejected, do not deliver it to the item that filtered it"))
<< QPoint(100, 100)
+ << eventMode
<< InputState({
// | event() | child mouse filter
// +---------+---------+---------+---------
@@ -3311,8 +3408,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data()
<< DeliveryRecord("r1")
);
- QTest::newRow("no filtering, no accepting")
+ QTest::newRow(desc("no filtering, no accepting"))
<< QPoint(100, 100)
+ << eventMode
<< InputState({
// | event() | child mouse filter
// +---------+---------+---------+---------
@@ -3331,8 +3429,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data()
<< DeliveryRecord("root")
);
- QTest::newRow("all filtering, no accepting")
+ QTest::newRow(desc("all filtering, no accepting"))
<< QPoint(100, 100)
+ << eventMode
<< InputState({
// | event() | child mouse filter
// +---------+---------+---------+---------
@@ -3358,8 +3457,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data()
);
- QTest::newRow("some filtering, no accepting")
+ QTest::newRow(desc("some filtering, no accepting"))
<< QPoint(100, 100)
+ << eventMode
<< InputState({
// | event() | child mouse filter
// +---------+---------+---------+---------
@@ -3383,8 +3483,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data()
<< DeliveryRecord("root")
);
- QTest::newRow("r1 accepts")
+ QTest::newRow(desc("r1 accepts"))
<< QPoint(100, 100)
+ << eventMode
<< InputState({
// | event() | child mouse filter
// +---------+---------+---------+---------
@@ -3406,8 +3507,9 @@ void tst_qquickwindow::testChildMouseEventFilter_data()
<< DeliveryRecord("r1")
);
- QTest::newRow("r1 rejects and filters")
+ QTest::newRow(desc("r1 rejects and filters"))
<< QPoint(100, 100)
+ << eventMode
<< InputState({
// | event() | child mouse filter
// +---------+---------+---------+---------
@@ -3430,12 +3532,13 @@ void tst_qquickwindow::testChildMouseEventFilter_data()
<< DeliveryRecord("r0")
<< DeliveryRecord("root")
);
-
+ }
}
void tst_qquickwindow::testChildMouseEventFilter()
{
QFETCH(QPoint, mousePos);
+ QFETCH(QString, eventMode);
QFETCH(InputState, inputState);
QFETCH(DeliveryRecordVector, expectedDeliveryOrder);
@@ -3450,21 +3553,28 @@ void tst_qquickwindow::testChildMouseEventFilter()
QScopedPointer<EventFilter> rootFilter(new EventFilter);
root->installEventFilter(rootFilter.data());
+ const bool useMouseEvents = eventMode == "mouse";
+ const bool acceptTouchEvents = eventMode == "touch";
+
// Create 4 items; each item a child of the previous item.
EventItem *r[4];
r[0] = new EventItem(root);
r[0]->setColor(QColor(0x404040));
r[0]->setWidth(200);
r[0]->setHeight(200);
+ r[0]->setAcceptTouchEvents(acceptTouchEvents);
r[1] = new EventItem(r[0]);
r[1]->setColor(QColor(0x606060));
+ r[1]->setAcceptTouchEvents(acceptTouchEvents);
r[2] = new EventItem(r[1]);
r[2]->setColor(Qt::red);
+ r[2]->setAcceptTouchEvents(acceptTouchEvents);
r[3] = new EventItem(r[2]);
r[3]->setColor(Qt::green);
+ r[3]->setAcceptTouchEvents(acceptTouchEvents);
for (uint i = 0; i < sizeof(r)/sizeof(EventItem*); ++i) {
r[i]->setEventAccepts(inputState.r[i].eventAccepts);
@@ -3481,13 +3591,17 @@ void tst_qquickwindow::testChildMouseEventFilter()
DeliveryRecordVector &actualDeliveryOrder = EventItem::deliveryList();
actualDeliveryOrder.clear();
- QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, mousePos);
+
+ if (useMouseEvents)
+ QTest::mousePress(&window, Qt::LeftButton, Qt::NoModifier, mousePos);
+ else
+ QTest::touchEvent(&window, touchDevice).press(0, mousePos, &window);
// Check if event got delivered to the root item. If so, append it to the list of items the event got delivered to
if (rootFilter->events.contains(QEvent::MouseButtonPress))
actualDeliveryOrder.append(DeliveryRecord("root"));
- for (int i = 0; i < qMax(actualDeliveryOrder.count(), expectedDeliveryOrder.count()); ++i) {
+ for (int i = 0; i < qMax(actualDeliveryOrder.size(), expectedDeliveryOrder.size()); ++i) {
const DeliveryRecord expectedNames = expectedDeliveryOrder.value(i);
const DeliveryRecord actualNames = actualDeliveryOrder.value(i);
QCOMPARE(actualNames.toString(), expectedNames.toString());
@@ -3497,8 +3611,11 @@ void tst_qquickwindow::testChildMouseEventFilter()
QVERIFY(item->testFilterPreConditions());
}
- // "restore" mouse state
- QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, mousePos);
+ // "restore" mouse/touch state
+ if (useMouseEvents)
+ QTest::mouseRelease(&window, Qt::LeftButton, Qt::NoModifier, mousePos);
+ else
+ QTest::touchEvent(&window, touchDevice).release(0, mousePos, &window);
}
void tst_qquickwindow::cleanupGrabsOnRelease()
@@ -3537,6 +3654,48 @@ void tst_qquickwindow::cleanupGrabsOnRelease()
QCOMPARE(parent->mouseUngrabEventCount, 1);
}
+void tst_qquickwindow::subclassWithPointerEventVirtualOverrides_data()
+{
+ QTest::addColumn<const QPointingDevice *>("device");
+
+ QTest::newRow("mouse click") << QPointingDevice::primaryPointingDevice();
+ QTest::newRow("touch tap") << static_cast<const QPointingDevice*>(touchDevice); // TODO QTBUG-107864
+ QTest::newRow("stylus tap") << tabletStylusDevice;
+}
+
+void tst_qquickwindow::subclassWithPointerEventVirtualOverrides() // QTBUG-97859
+{
+ QFETCH(const QPointingDevice *, device);
+
+ PointerRecordingWindow window;
+ window.resize(250, 250);
+ window.setPosition(100, 100);
+ window.setTitle(QTest::currentTestFunction());
+ window.show();
+ QVERIFY(QTest::qWaitForWindowActive(&window));
+ const QPoint pos(120, 120);
+
+ QQuickTest::pointerPress(device, &window, 0, pos);
+ QQuickTest::pointerRelease(device, &window, 0, pos);
+
+ switch (device->type()) {
+ case QPointingDevice::DeviceType::Mouse:
+ QTRY_COMPARE(window.m_mouseEvents.size(), 3); // separate move before press
+ QCOMPARE(window.m_events.size(), 3);
+ break;
+ case QPointingDevice::DeviceType::TouchScreen:
+ QTRY_COMPARE(window.m_touchEvents.size(), 2);
+ QCOMPARE(window.m_events.size(), 2);
+ break;
+ case QPointingDevice::DeviceType::Stylus:
+ QTRY_COMPARE(window.m_tabletEvents.size(), 2);
+ QVERIFY(window.m_events.size() >= window.m_tabletEvents.size()); // tablet + synth-mouse events
+ break;
+ default:
+ break;
+ }
+}
+
#if QT_CONFIG(shortcut)
void tst_qquickwindow::testShortCut()
{
@@ -3559,6 +3718,39 @@ void tst_qquickwindow::testShortCut()
QVERIFY(eventFilter.events.contains(int(QEvent::ShortcutOverride)));
QVERIFY(window->property("received").value<bool>());
}
+
+void tst_qquickwindow::shortcutOverride_data()
+{
+ QTest::addColumn<Qt::Key>("key");
+ QTest::addColumn<bool>("overridden");
+ QTest::addColumn<bool>("receivedA");
+ QTest::addColumn<bool>("receivedB");
+
+ QTest::addRow("Space") << Qt::Key_Space << false << false << false;
+ QTest::addRow("A") << Qt::Key_A << true << false << false;
+ QTest::addRow("B") << Qt::Key_B << false << false << true;
+}
+
+void tst_qquickwindow::shortcutOverride()
+{
+ QFETCH(Qt::Key, key);
+ QFETCH(bool, overridden);
+ QFETCH(bool, receivedA);
+ QFETCH(bool, receivedB);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("shortcutOverride.qml"));
+
+ QScopedPointer<QWindow> window(qobject_cast<QQuickWindow *>(component.create()));
+ QVERIFY(window);
+ QVERIFY(QTest::qWaitForWindowActive(window.get()));
+
+ QTest::keyPress(window.get(), key);
+ QCOMPARE(window->property("overridden").value<bool>(), overridden);
+ QCOMPARE(window->property("receivedA").value<bool>(), receivedA);
+ QCOMPARE(window->property("receivedB").value<bool>(), receivedB);
+}
#endif
void tst_qquickwindow::rendererInterface()
@@ -3676,10 +3868,9 @@ void tst_qquickwindow::rendererInterfaceWithRenderControl_data()
QTest::newRow("Vulkan") << QSGRendererInterface::VulkanRhi;
#endif
#ifdef Q_OS_WIN
- if (QOperatingSystemVersion::current() > QOperatingSystemVersion::Windows7)
- QTest::newRow("D3D11") << QSGRendererInterface::Direct3D11Rhi;
+ QTest::newRow("D3D11") << QSGRendererInterface::Direct3D11Rhi;
#endif
-#if defined(Q_OS_MACOS) || defined(Q_OS_IOS)
+#if QT_CONFIG(metal)
QTest::newRow("Metal") << QSGRendererInterface::MetalRhi;
#endif
}
@@ -3878,6 +4069,122 @@ void tst_qquickwindow::rendererInterfaceWithRenderControl()
QQuickWindow::setGraphicsApi(QSGRendererInterface::Unknown);
}
+void tst_qquickwindow::graphicsConfiguration()
+{
+ QQuickGraphicsConfiguration config;
+ qDebug() << config;
+ QVERIFY(config.isDepthBufferEnabledFor2D());
+ QVERIFY(!config.isDebugLayerEnabled());
+ QVERIFY(!config.isDebugMarkersEnabled());
+ QVERIFY(!config.prefersSoftwareDevice());
+ QVERIFY(config.isAutomaticPipelineCacheEnabled());
+ QVERIFY(config.pipelineCacheSaveFile().isEmpty());
+ QVERIFY(config.pipelineCacheLoadFile().isEmpty());
+
+ QQuickGraphicsConfiguration config2 = config;
+ config.setDebugLayer(true);
+ config.setDepthBufferFor2D(false);
+ QVERIFY(config.isDebugLayerEnabled());
+ QVERIFY(!config2.isDebugLayerEnabled());
+
+ config2 = config;
+ QVERIFY(config2.isDebugLayerEnabled());
+ QVERIFY(!config2.isDepthBufferEnabledFor2D());
+
+ config.setAutomaticPipelineCache(false);
+ config.setPipelineCacheSaveFile(QLatin1String("save"));
+ config.setPipelineCacheLoadFile(QLatin1String("load"));
+ config2 = config;
+ QVERIFY(!config2.isAutomaticPipelineCacheEnabled());
+ QCOMPARE(config2.pipelineCacheSaveFile(), QLatin1String("save"));
+ QCOMPARE(config2.pipelineCacheLoadFile(), QLatin1String("load"));
+
+#if QT_CONFIG(vulkan)
+ QCOMPARE(QQuickGraphicsConfiguration::preferredInstanceExtensions(), QRhiVulkanInitParams::preferredInstanceExtensions());
+#endif
+}
+
+void tst_qquickwindow::visibleVsVisibility_data()
+{
+ QTest::addColumn<QUrl>("qmlfile");
+ QTest::addColumn<bool>("expectVisible");
+ QTest::addColumn<bool>("expectConflictingPropertyWarning");
+
+ QTest::newRow("default invisible") << testFileUrl("window.qml") << false << false;
+ QTest::newRow("just visibility") << testFileUrl("maximized.qml") << true << false;
+ // In these conflicting cases, the 'visibility' property "wins" (see QQuickWindowQmlImpl::setWindowVisibility())
+ QTest::newRow("conflicting invisible") << testFileUrl("conflictingVisibleFalse.qml") << true << true;
+ QTest::newRow("conflicting visible") << testFileUrl("conflictingVisibleTrue.qml") << false << true;
+}
+
+void tst_qquickwindow::visibleVsVisibility()
+{
+ QFETCH(QUrl, qmlfile);
+ QFETCH(bool, expectVisible);
+ QFETCH(bool, expectConflictingPropertyWarning);
+
+ const QString warningMsg = qmlfile.toString() + ":3:1: QML Window: Conflicting properties 'visible' and 'visibility'";
+
+ QTest::failOnWarning(QRegularExpression(".*"));
+ if (expectConflictingPropertyWarning)
+ QTest::ignoreMessage(QtWarningMsg, warningMsg.toUtf8().data());
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(qmlfile);
+ QObject *created = component.create();
+ QScopedPointer<QObject> cleanup(created);
+ QVERIFY(created);
+
+ QQuickWindow *window = qobject_cast<QQuickWindow*>(created);
+ QVERIFY(window);
+ QCOMPARE(window->isVisible(), expectVisible);
+}
+
+void tst_qquickwindow::visibilityDoesntClobberWindowState()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("visibilityDoesntClobberWindowState.qml"));
+ QObject *created = component.create();
+ QScopedPointer<QObject> cleanup(created);
+ QVERIFY(created);
+
+ QQuickWindow *window = qobject_cast<QQuickWindow*>(created);
+ QVERIFY(window);
+
+ window->showMaximized();
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ QCOMPARE(window->windowState(), Qt::WindowMaximized);
+
+ window->setProperty("visible", false);
+ window->setProperty("visible", true);
+
+ QVERIFY(QTest::qWaitForWindowExposed(window));
+ QCOMPARE(window->windowState(), Qt::WindowMaximized);
+
+ EventFilter eventFilter;
+ window->installEventFilter(&eventFilter);
+ window->setProperty("visibility", QWindow::FullScreen);
+ QTRY_VERIFY(eventFilter.events.contains(QEvent::WindowStateChange));
+ QCOMPARE(window->windowState(), Qt::WindowFullScreen);
+
+ eventFilter.events.clear();
+ window->setWindowState(Qt::WindowMaximized);
+ QTRY_VERIFY(eventFilter.events.contains(QEvent::WindowStateChange));
+ QTRY_COMPARE(window->windowState(), Qt::WindowMaximized);
+}
+
+void tst_qquickwindow::eventTypes()
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.loadUrl(testFileUrl("eventTypes.qml"));
+ QObject *created = component.create();
+ QScopedPointer<QObject> cleanup(created);
+ QVERIFY(created);
+}
+
QTEST_MAIN(tst_qquickwindow)
#include "tst_qquickwindow.moc"
diff --git a/tests/auto/quick/qquickwindowcontainer/CMakeLists.txt b/tests/auto/quick/qquickwindowcontainer/CMakeLists.txt
new file mode 100644
index 0000000000..6a02080cfc
--- /dev/null
+++ b/tests/auto/quick/qquickwindowcontainer/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_qquickwindowcontainer LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_qquickwindowcontainer
+ SOURCES
+ tst_qquickwindowcontainer.cpp
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
+)
+
+if(ANDROID OR IOS)
+ set(TESTDATA_DIR ":/data")
+else()
+ set(TESTDATA_DIR "${CMAKE_CURRENT_SOURCE_DIR}/data")
+endif()
+
+qt_internal_extend_target(tst_qquickwindowcontainer
+ DEFINES
+ QT_QMLTEST_DATADIR="${TESTDATA_DIR}"
+)
diff --git a/tests/auto/quick/qquickwindowcontainer/data/basicFunctionality_container.qml b/tests/auto/quick/qquickwindowcontainer/data/basicFunctionality_container.qml
new file mode 100644
index 0000000000..3e0bd8ae1c
--- /dev/null
+++ b/tests/auto/quick/qquickwindowcontainer/data/basicFunctionality_container.qml
@@ -0,0 +1,15 @@
+import QtQuick
+
+Window {
+ id: topLevel
+ Item {
+ id: childItem
+ x: 100; y: 100
+
+ WindowContainer {
+ window: Window {
+ objectName: "childWindow"
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickwindowcontainer/data/basicFunctionality_item.qml b/tests/auto/quick/qquickwindowcontainer/data/basicFunctionality_item.qml
new file mode 100644
index 0000000000..301c5f1494
--- /dev/null
+++ b/tests/auto/quick/qquickwindowcontainer/data/basicFunctionality_item.qml
@@ -0,0 +1,15 @@
+import QtQuick
+
+Window {
+ id: topLevel
+ Item {
+ id: childItem
+ x: 100; y: 100
+
+ Window {
+ parent: childItem
+ objectName: "childWindow"
+ x: 100; y: 100
+ }
+ }
+}
diff --git a/tests/auto/quick/qquickwindowcontainer/data/basicFunctionality_window.qml b/tests/auto/quick/qquickwindowcontainer/data/basicFunctionality_window.qml
new file mode 100644
index 0000000000..d6d2c9dff0
--- /dev/null
+++ b/tests/auto/quick/qquickwindowcontainer/data/basicFunctionality_window.qml
@@ -0,0 +1,10 @@
+import QtQuick
+
+Window {
+ id: topLevel
+ Window {
+ parent: topLevel
+ objectName: "childWindow"
+ x: 100; y: 100
+ }
+}
diff --git a/tests/auto/quick/qquickwindowcontainer/data/deferredVisibilityWithoutWindow.qml b/tests/auto/quick/qquickwindowcontainer/data/deferredVisibilityWithoutWindow.qml
new file mode 100644
index 0000000000..3bd882defe
--- /dev/null
+++ b/tests/auto/quick/qquickwindowcontainer/data/deferredVisibilityWithoutWindow.qml
@@ -0,0 +1,11 @@
+import QtQuick
+
+Window {
+ id: topLevel
+ visible: true
+ Window {
+ parent: topLevel
+ objectName: "childWindow"
+ visible: true
+ }
+}
diff --git a/tests/auto/quick/qquickwindowcontainer/data/windowComponent.qml b/tests/auto/quick/qquickwindowcontainer/data/windowComponent.qml
new file mode 100644
index 0000000000..48a067030b
--- /dev/null
+++ b/tests/auto/quick/qquickwindowcontainer/data/windowComponent.qml
@@ -0,0 +1,28 @@
+import QtQuick
+
+Window {
+ Item { id: itemParent; objectName: "itemParent" }
+ Window { id: windowParent; objectName: "windowParent" }
+
+ property QtObject window_item: null
+ property QtObject window_window: null
+
+ property QtObject window_item_parent: null
+ property QtObject window_window_parent: null
+
+ Component { id: windowComponent; Window{} }
+
+ Component.onCompleted: {
+ // Windows created with QObjects, Items, or Windows as their parent
+ // do not their visual parent set via auto-parenting -- only their
+ // transient parent.
+ window_item = windowComponent.createObject(itemParent);
+ window_window = windowComponent.createObject(windowParent);
+
+ // A visual parent must be set explicitly
+ window_item_parent = windowComponent.createObject(itemParent);
+ window_item_parent.parent = itemParent;
+ window_window_parent = windowComponent.createObject(windowParent);
+ window_window_parent.parent = windowParent;
+ }
+}
diff --git a/tests/auto/quick/qquickwindowcontainer/tst_qquickwindowcontainer.cpp b/tests/auto/quick/qquickwindowcontainer/tst_qquickwindowcontainer.cpp
new file mode 100644
index 0000000000..c702cf96dc
--- /dev/null
+++ b/tests/auto/quick/qquickwindowcontainer/tst_qquickwindowcontainer.cpp
@@ -0,0 +1,192 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtTest/qtest.h>
+#include <QtTest/qsignalspy.h>
+
+#include <QtQuickTest/QtQuickTest>
+
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlfile.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlapplicationengine.h>
+
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/private/qquickwindowcontainer_p.h>
+
+class tst_QQuickWindowContainer : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_QQuickWindowContainer()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+ {
+ }
+
+private slots:
+ void init() override;
+ void cleanup();
+
+ void basicFunctionality_data();
+ void basicFunctionality();
+
+ void windowDestroyed();
+ void windowLifetimeFollowsContainer();
+ void deferredVisibilityWithoutWindow();
+ void windowComponent();
+
+private:
+ std::unique_ptr<QQmlApplicationEngine> m_engine;
+};
+
+void tst_QQuickWindowContainer::init()
+{
+ QQmlDataTest::init();
+
+ QString testFile = QTest::currentTestFunction();
+ if (auto *dataTag = QTest::currentDataTag())
+ testFile += QChar('_') % dataTag;
+ testFile += ".qml";
+
+ const auto testUrl = testFileUrl(testFile);
+ if (QFileInfo::exists(QQmlFile::urlToLocalFileOrQrc(testUrl))) {
+ m_engine.reset(new QQmlApplicationEngine(testUrl));
+ QVERIFY(m_engine->rootObjects().size() > 0);
+ }
+}
+
+void tst_QQuickWindowContainer::cleanup()
+{
+ m_engine.reset(nullptr);
+}
+
+void tst_QQuickWindowContainer::basicFunctionality_data()
+{
+ QTest::addColumn<QPoint>("position");
+
+ QTest::newRow("window") << QPoint(100, 100);
+ QTest::newRow("item") << QPoint(200, 200);
+ QTest::newRow("container") << QPoint(100, 100);
+}
+
+void tst_QQuickWindowContainer::basicFunctionality()
+{
+ QFETCH(QPoint, position);
+
+ auto *topLevelWindow = qobject_cast<QQuickWindow*>(m_engine->rootObjects().first());
+ auto *childWindow = topLevelWindow->findChild<QWindow*>("childWindow");
+ QVERIFY(childWindow);
+
+ // The top level isn't visible yet, so there hasn't been any
+ // polish, which we rely on for the actual reparenting.
+ QCOMPARE(childWindow->parent(), nullptr);
+
+ topLevelWindow->setVisible(true);
+ QVERIFY(QQuickTest::qWaitForPolish(topLevelWindow));
+ QCOMPARE(childWindow->parent(), topLevelWindow);
+
+ QCOMPARE(childWindow->position(), position);
+}
+
+void tst_QQuickWindowContainer::windowDestroyed()
+{
+ std::unique_ptr<QWindow> window(new QWindow);
+
+ QQuickWindowContainer container;
+ QSignalSpy spy(&container, &QQuickWindowContainer::containedWindowChanged);
+
+ container.setContainedWindow(window.get());
+ QCOMPARE(container.containedWindow(), window.get());
+ QCOMPARE(spy.size(), 1);
+
+ window.reset(nullptr);
+
+ QVERIFY(!container.containedWindow());
+ QCOMPARE(spy.size(), 2);
+}
+
+void tst_QQuickWindowContainer::windowLifetimeFollowsContainer()
+{
+ QWindow window;
+ QPointer<QWindow> windowGuard = &window;
+
+ QQuickWindowContainer container;
+ container.setContainedWindow(&window);
+
+ {
+ QQuickWindow quickWindow;
+ container.setParentItem(quickWindow.contentItem());
+ quickWindow.show();
+ QVERIFY(QQuickTest::qWaitForPolish(&quickWindow));
+ QCOMPARE(window.parent(), &quickWindow);
+
+ // Decouple container from Quick window
+ container.setParentItem(nullptr);
+ }
+
+ QVERIFY(windowGuard);
+}
+
+void tst_QQuickWindowContainer::deferredVisibilityWithoutWindow()
+{
+ auto *topLevelWindow = qobject_cast<QQuickWindow*>(m_engine->rootObjects().first());
+ auto *childWindow = topLevelWindow->findChild<QQuickWindow*>("childWindow");
+ QVERIFY(childWindow);
+ QVERIFY(QQuickTest::qWaitForPolish(topLevelWindow));
+
+ QSignalSpy spy(childWindow, &QWindow::visibleChanged);
+ m_engine.reset(nullptr);
+
+ // Deleting the engine should only hide the window once,
+ // not hide, show, and then hide again, which would be
+ // the result of applying visibility without a window.
+ QCOMPARE(spy.count(), 1);
+}
+
+void tst_QQuickWindowContainer::windowComponent()
+{
+ auto *root = qobject_cast<QQuickWindow *>(m_engine->rootObjects().first());
+ QVERIFY(root);
+ auto *itemParent = root->findChild<QQuickItem*>("itemParent");
+ auto *windowParent = root->findChild<QQuickWindow*>("windowParent");
+ QVERIFY(itemParent);
+ QVERIFY(windowParent);
+
+ root->setVisible(true);
+ QVERIFY(QQuickTest::qWaitForPolish(root));
+ windowParent->setVisible(true);
+ QVERIFY(QQuickTest::qWaitForPolish(windowParent));
+
+ QObject *window_item = root->property("window_item").value<QObject*>();
+ QObject *window_window = root->property("window_window").value<QObject*>();
+ QObject *window_item_parent = root->property("window_item_parent").value<QObject*>();
+ QObject *window_window_parent = root->property("window_window_parent").value<QObject*>();
+
+ QVERIFY(window_item);
+ QVERIFY(window_window);
+ QVERIFY(window_item_parent);
+ QVERIFY(window_window_parent);
+
+ QCOMPARE(window_item->parent(), itemParent);
+ QCOMPARE(window_window->parent(), windowParent);
+ QCOMPARE(window_item_parent->parent(), root);
+ QCOMPARE(window_window_parent->parent(), windowParent);
+
+ QCOMPARE(qobject_cast<QQuickWindow *>(window_item)->transientParent(), root);
+ QCOMPARE(qobject_cast<QQuickWindow *>(window_window)->transientParent(), windowParent);
+ QCOMPARE(qobject_cast<QQuickWindow *>(window_item)->parent(), nullptr);
+ QCOMPARE(qobject_cast<QQuickWindow *>(window_window)->parent(), nullptr);
+
+ QEXPECT_FAIL("", "The automatic transient parent logic doesn't account for visual parent", Continue);
+ QCOMPARE(qobject_cast<QQuickWindow *>(window_item_parent)->transientParent(), nullptr);
+ QEXPECT_FAIL("", "The automatic transient parent logic doesn't account for visual parent", Continue);
+ QCOMPARE(qobject_cast<QQuickWindow *>(window_window_parent)->transientParent(), nullptr);
+ QCOMPARE(qobject_cast<QQuickWindow *>(window_item_parent)->parent(), root);
+ QCOMPARE(qobject_cast<QQuickWindow *>(window_window_parent)->parent(), windowParent);
+}
+
+QTEST_MAIN(tst_QQuickWindowContainer)
+
+#include "tst_qquickwindowcontainer.moc"
diff --git a/tests/auto/quick/rendernode/CMakeLists.txt b/tests/auto/quick/rendernode/CMakeLists.txt
index 037ff85843..db5fac6439 100644
--- a/tests/auto/quick/rendernode/CMakeLists.txt
+++ b/tests/auto/quick/rendernode/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from rendernode.pro.
#####################################################################
## tst_rendernode Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_rendernode LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,16 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_rendernode
SOURCES
- ../../shared/util.cpp ../../shared/util.h
tst_rendernode.cpp
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -33,10 +40,18 @@ qt_internal_add_test(tst_rendernode
qt_internal_extend_target(tst_rendernode CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_rendernode CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+)
+
+qt_internal_add_shaders(tst_rendernode "rendernode_shaders"
+ PREFIX
+ /shaders
+ FILES
+ color.vert
+ color.frag
)
diff --git a/tests/auto/quick/rendernode/color.frag b/tests/auto/quick/rendernode/color.frag
new file mode 100644
index 0000000000..6e0a3bc91f
--- /dev/null
+++ b/tests/auto/quick/rendernode/color.frag
@@ -0,0 +1,15 @@
+#version 440
+
+layout(location = 0) in vec3 v_color;
+
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 mvp;
+ float opacity;
+};
+
+void main()
+{
+ fragColor = vec4(v_color * opacity, opacity);
+}
diff --git a/tests/auto/quick/rendernode/color.vert b/tests/auto/quick/rendernode/color.vert
new file mode 100644
index 0000000000..70852ab86c
--- /dev/null
+++ b/tests/auto/quick/rendernode/color.vert
@@ -0,0 +1,17 @@
+#version 440
+
+layout(location = 0) in vec4 position;
+layout(location = 1) in vec3 color;
+
+layout(location = 0) out vec3 v_color;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 mvp;
+ float opacity;
+};
+
+void main()
+{
+ v_color = color;
+ gl_Position = mvp * position;
+}
diff --git a/tests/auto/quick/rendernode/data/MessUpState.qml b/tests/auto/quick/rendernode/data/MessUpState.qml
deleted file mode 100644
index 84f32b7692..0000000000
--- a/tests/auto/quick/rendernode/data/MessUpState.qml
+++ /dev/null
@@ -1,33 +0,0 @@
-import QtQuick 2.0
-import Test 1.0
-
-Rectangle {
- id: root
- width: 160
- height: 240
- color: "black"
- Rectangle {
- width: root.width
- height: root.height / 2;
- anchors.centerIn: parent
- clip: true
- color: "white"
- Rectangle {
- width: root.width / 2;
- height: root.height / 2
- anchors.centerIn: parent
- rotation: 45
- color: "blue"
- clip: true
- MessUpItem {
- anchors.fill: parent
- }
- Rectangle {
- anchors.fill: parent
- anchors.margins: -100
- color: "red"
- opacity: 0.5
- }
- }
- }
-}
diff --git a/tests/auto/quick/rendernode/data/RenderOrder.qml b/tests/auto/quick/rendernode/data/RenderOrder.qml
deleted file mode 100644
index c7cc6cdeb9..0000000000
--- a/tests/auto/quick/rendernode/data/RenderOrder.qml
+++ /dev/null
@@ -1,53 +0,0 @@
-import QtQuick 2.0
-import Test 1.0
-
-Rectangle {
- id: root
-
- width: 200
- height: 200
- color: "black"
-
- Rectangle {
- width: root.width / 2
- height: root.height / 2
- anchors.top: parent.top
- anchors.left: parent.left
- color: "red"
- opacity: 0.5
- }
-
- Rectangle {
- width: root.width / 2
- height: root.height / 2
- anchors.bottom: parent.bottom
- anchors.left: parent.left
- color: "red"
- }
-
- ClearItem {
- width: root.width / 2
- height: root.height / 2
- anchors.centerIn: parent
- color: "white"
- clip: true
- }
-
- Rectangle {
- width: root.width / 2
- height: root.height / 2
- anchors.top: parent.top
- anchors.right: parent.right
- color: "blue"
- }
-
- Rectangle {
- width: root.width / 2
- height: root.height / 2
- anchors.bottom: parent.bottom
- anchors.right: parent.right
- color: "blue"
- opacity: 0.5
- }
-
-}
diff --git a/tests/auto/quick/rendernode/data/glsimple.qml b/tests/auto/quick/rendernode/data/glsimple.qml
new file mode 100644
index 0000000000..da038476b3
--- /dev/null
+++ b/tests/auto/quick/rendernode/data/glsimple.qml
@@ -0,0 +1,26 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import Test
+
+Rectangle {
+ color: "red"
+ Rectangle {
+ color: "transparent"
+ border.color: "yellow"
+ border.width: 2
+ width: parent.width / 2
+ height: parent.height / 2
+ anchors.centerIn: parent
+ GLSimpleItem {
+ anchors.fill: parent
+ Rectangle {
+ color: "gray"
+ width: 50
+ height: 50
+ anchors.centerIn: parent
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/rendernode/data/matrix.qml b/tests/auto/quick/rendernode/data/matrix.qml
deleted file mode 100644
index 8e20342870..0000000000
--- a/tests/auto/quick/rendernode/data/matrix.qml
+++ /dev/null
@@ -1,74 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-import QtQuick 2.0
-import RenderNode 1.0
-
-Item {
- width: 320
- height: 480
-
- Item { x: 10; y: 10; width: 10; height: 10;
- StateRecorder { x: 10; y: 10; objectName: "no-clip; no-rotation"; }
- }
-
- Item { x: 10; y: 10; width: 10; height: 10; clip: true
- StateRecorder { x: 10; y: 10; objectName: "parent-clip; no-rotation"; }
- }
-
- Item { x: 10; y: 10; width: 10; height: 10;
- StateRecorder { x: 10; y: 10; objectName: "self-clip; no-rotation"; clip: true }
- }
-
-
- Item { x: 10; y: 10; width: 10; height: 10; rotation: 90
- StateRecorder { x: 10; y: 10; objectName: "no-clip; parent-rotation"; }
- }
-
- Item { x: 10; y: 10; width: 10; height: 10; clip: true; rotation: 90
- StateRecorder { x: 10; y: 10; objectName: "parent-clip; parent-rotation"; }
- }
-
- Item { x: 10; y: 10; width: 10; height: 10; rotation: 90
- StateRecorder { x: 10; y: 10; objectName: "self-clip; parent-rotation"; clip: true }
- }
-
-
- Item { x: 10; y: 10; width: 10; height: 10;
- StateRecorder { x: 10; y: 10; objectName: "no-clip; self-rotation"; rotation: 90 }
- }
-
- Item { x: 10; y: 10; width: 10; height: 10; clip: true;
- StateRecorder { x: 10; y: 10; objectName: "parent-clip; self-rotation"; rotation: 90}
- }
-
- Item { x: 10; y: 10; width: 10; height: 10;
- StateRecorder { x: 10; y: 10; objectName: "self-clip; self-rotation"; clip: true; rotation: 90 }
- }
-
-}
diff --git a/tests/auto/quick/rendernode/data/simple.qml b/tests/auto/quick/rendernode/data/simple.qml
new file mode 100644
index 0000000000..2194d3484f
--- /dev/null
+++ b/tests/auto/quick/rendernode/data/simple.qml
@@ -0,0 +1,26 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import Test
+
+Rectangle {
+ color: "red"
+ Rectangle {
+ color: "transparent"
+ border.color: "yellow"
+ border.width: 2
+ width: parent.width / 2
+ height: parent.height / 2
+ anchors.centerIn: parent
+ SimpleItem {
+ anchors.fill: parent
+ Rectangle {
+ color: "gray"
+ width: 50
+ height: 50
+ anchors.centerIn: parent
+ }
+ }
+ }
+}
diff --git a/tests/auto/quick/rendernode/tst_rendernode.cpp b/tests/auto/quick/rendernode/tst_rendernode.cpp
index 87d710ee47..b21c1f01b1 100644
--- a/tests/auto/quick/rendernode/tst_rendernode.cpp
+++ b/tests/auto/quick/rendernode/tst_rendernode.cpp
@@ -1,367 +1,391 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickview.h>
-#include <qopenglcontext.h>
-#include <qopenglfunctions.h>
-#include <QtGui/qscreen.h>
#include <private/qsgrendernode_p.h>
+#include <rhi/qrhi.h>
-#include "../../shared/util.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+
+#if QT_CONFIG(opengl)
+#include <QOpenGLContext>
+#include <QOpenGLFunctions>
+#endif
class tst_rendernode: public QQmlDataTest
{
Q_OBJECT
+
public:
tst_rendernode();
- QImage runTest(const QString &fileName)
- {
- QQuickView view(&outerWindow);
- view.setResizeMode(QQuickView::SizeViewToRootObject);
- view.setSource(testFileUrl(fileName));
- view.setVisible(true);
- return QTest::qWaitForWindowExposed(&view) ? view.grabWindow() : QImage();
- }
-
- //It is important for platforms that only are able to show fullscreen windows
- //to have a container for the window that is painted on.
- QQuickWindow outerWindow;
-
private slots:
- void renderOrder();
- void messUpState();
- void matrix();
+ void test_data();
+ void test();
+#if QT_CONFIG(opengl)
+ void gltest_data();
+ void gltest();
+#endif
private:
+ QQuickView *createView(const QString &file, QWindow *parent, int x, int y, int w, int h);
bool isRunningOnRhi() const;
};
-class ClearNode : public QSGRenderNode
+static QShader getShader(const QString &name)
+{
+ QFile f(name);
+ if (f.open(QIODevice::ReadOnly))
+ return QShader::fromSerialized(f.readAll());
+
+ return QShader();
+}
+
+// *****
+// * *
+// * *
+// *
+// assumes the top-left scenegraph coordinate system, will be scaled to the item size
+static float vertexData[] = {
+ 0, 0, 0, 0, 1, // blue
+ 0, 1, 0, 0, 1,
+ 1, 0, 0, 0, 1
+};
+
+class SimpleNode : public QSGRenderNode
{
public:
+ SimpleNode(QQuickWindow *window)
+ : m_window(window)
+ {
+ }
+
StateFlags changedStates() const override
{
- return ColorState;
+ return ViewportState; // nothing else matters in Qt 6
+ }
+
+ RenderingFlags flags() const override
+ {
+ // this node uses QRhi directly and is also well behaving depth-wise
+ return NoExternalRendering | DepthAwareRendering;
+ }
+
+ void prepare() override
+ {
+ QSGRendererInterface *rif = m_window->rendererInterface();
+ QRhi *rhi = static_cast<QRhi *>(rif->getResource(m_window, QSGRendererInterface::RhiResource));
+ QVERIFY(rhi);
+
+ QSGRenderNodePrivate *d = QSGRenderNodePrivate::get(this);
+ QRhiRenderTarget *rt = d->m_rt.rt;
+ QRhiCommandBuffer *cb = d->m_rt.cb;
+
+ QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch();
+
+ if (!m_vbuf) {
+ m_vbuf.reset(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertexData)));
+ QVERIFY(m_vbuf->create());
+ u->uploadStaticBuffer(m_vbuf.data(), vertexData);
+ }
+
+ if (!m_ubuf) {
+ m_ubuf.reset(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 68));
+ QVERIFY(m_ubuf->create());
+ }
+
+ if (!m_srb) {
+ m_srb.reset(rhi->newShaderResourceBindings());
+ m_srb->setBindings({
+ QRhiShaderResourceBinding::uniformBuffer(0,
+ QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage,
+ m_ubuf.get())
+ });
+ m_srb->create();
+ }
+
+ if (!m_ps) {
+ m_ps.reset(rhi->newGraphicsPipeline());
+
+ const QShader vs = getShader(QLatin1String(":/shaders/color.vert.qsb"));
+ if (!vs.isValid())
+ qFatal("Failed to load shader pack (vertex)");
+ const QShader fs = getShader(QLatin1String(":/shaders/color.frag.qsb"));
+ if (!fs.isValid())
+ qFatal("Failed to load shader pack (fragment)");
+
+ m_ps->setShaderStages({
+ { QRhiShaderStage::Vertex, vs },
+ { QRhiShaderStage::Fragment, fs }
+ });
+
+ m_ps->setCullMode(QRhiGraphicsPipeline::Back);
+ // important to test against what's already in the depth buffer from the opaque pass
+ m_ps->setDepthTest(true);
+ m_ps->setDepthOp(QRhiGraphicsPipeline::LessOrEqual);
+ // we are in the alpha pass always so not writing out the depth
+ m_ps->setDepthWrite(false);
+
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({
+ { 5 * sizeof(float) }
+ });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
+ { 0, 1, QRhiVertexInputAttribute::Float3, 2 * sizeof(float) }
+ });
+
+ m_ps->setVertexInputLayout(inputLayout);
+ m_ps->setShaderResourceBindings(m_srb.data());
+ m_ps->setRenderPassDescriptor(rt->renderPassDescriptor());
+
+ QVERIFY(m_ps->create());
+ }
+
+ // follow what the scenegraph tells us, hence DepthAwareRendering from
+ // flags, the downside is that we are stuck with the scenegraph
+ // coordinate system but that's enough for this test.
+ QMatrix4x4 mvp = *projectionMatrix() * *matrix();
+
+ mvp.scale(m_itemSize.width(), m_itemSize.height());
+ u->updateDynamicBuffer(m_ubuf.data(), 0, 64, mvp.constData());
+
+ const float opacity = inheritedOpacity();
+ u->updateDynamicBuffer(m_ubuf.data(), 64, 4, &opacity);
+
+ cb->resourceUpdate(u);
}
void render(const RenderState *) override
{
- // If clip has been set, scissoring will make sure the right area is cleared.
- QOpenGLContext::currentContext()->functions()->glClearColor(color.redF(), color.greenF(), color.blueF(), 1.0f);
- QOpenGLContext::currentContext()->functions()->glClear(GL_COLOR_BUFFER_BIT);
+ QSGRenderNodePrivate *d = QSGRenderNodePrivate::get(this);
+ QRhiRenderTarget *rt = d->m_rt.rt;
+ QRhiCommandBuffer *cb = d->m_rt.cb;
+
+ cb->setGraphicsPipeline(m_ps.data());
+ cb->setViewport({ 0, 0, float(rt->pixelSize().width()), float(rt->pixelSize().height()) });
+ cb->setShaderResources();
+ const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
+ cb->setVertexInput(0, 1, &vbufBinding);
+ cb->draw(3);
}
- QColor color;
+ QQuickWindow *m_window;
+ QScopedPointer<QRhiBuffer> m_vbuf;
+ QScopedPointer<QRhiBuffer> m_ubuf;
+ QScopedPointer<QRhiShaderResourceBindings> m_srb;
+ QScopedPointer<QRhiGraphicsPipeline> m_ps;
+ QSizeF m_itemSize;
};
-class ClearItem : public QQuickItem
+class SimpleItem : public QQuickItem
{
Q_OBJECT
- Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
public:
- ClearItem() : m_color(Qt::black)
+ SimpleItem()
{
setFlag(ItemHasContents, true);
}
-
- QColor color() const { return m_color; }
- void setColor(const QColor &color)
- {
- if (color == m_color)
- return;
- m_color = color;
- emit colorChanged();
- }
-
protected:
- virtual QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override
{
- ClearNode *node = static_cast<ClearNode *>(oldNode);
+ if (size().isEmpty()) {
+ delete oldNode;
+ return nullptr;
+ }
+
+ SimpleNode *node = static_cast<SimpleNode *>(oldNode);
if (!node)
- node = new ClearNode;
- node->color = m_color;
- return node;
- }
+ node = new SimpleNode(window());
-Q_SIGNALS:
- void colorChanged();
+ node->m_itemSize = size();
-private:
- QColor m_color;
+ return node;
+ }
};
-class MessUpNode : public QSGRenderNode, protected QOpenGLFunctions
+#if QT_CONFIG(opengl)
+class GLNode : public QSGRenderNode
{
public:
- MessUpNode() {}
-
StateFlags changedStates() const override
{
- return StateFlags(DepthState) | StencilState | ScissorState | ColorState | BlendState
- | CullState | ViewportState | RenderTargetState;
+ return ViewportState; // nothing else matters in Qt 6
}
- void render(const RenderState *) override
+ RenderingFlags flags() const override
{
- if (!initialized) {
- initializeOpenGLFunctions();
- initialized = true;
- }
- // Don't draw anything, just mess up the state
- glViewport(10, 10, 10, 10);
- glDisable(GL_SCISSOR_TEST);
- glDepthMask(true);
- glEnable(GL_DEPTH_TEST);
- glDepthFunc(GL_EQUAL);
- glClearDepthf(1);
- glClearStencil(42);
- glClearColor(1.0f, 0.5f, 1.0f, 0.0f);
- glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- glEnable(GL_SCISSOR_TEST);
- glScissor(190, 190, 10, 10);
- glStencilFunc(GL_EQUAL, 28, 0xff);
- glBlendFunc(GL_ZERO, GL_ZERO);
- GLint frontFace;
- glGetIntegerv(GL_FRONT_FACE, &frontFace);
- glFrontFace(frontFace == GL_CW ? GL_CCW : GL_CW);
- glEnable(GL_CULL_FACE);
- GLuint fbo;
- glGenFramebuffers(1, &fbo);
- glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ return {};
}
- bool initialized = false;
+ void prepare() override
+ {
+ QVERIFY(QOpenGLContext::currentContext());
+ }
+
+ void render(const RenderState *) override
+ {
+ QVERIFY(QOpenGLContext::currentContext());
+ QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
+ QVERIFY(f);
+ f->glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ f->glClear(GL_COLOR_BUFFER_BIT);
+ }
};
-class MessUpItem : public QQuickItem
+class GLItem : public QQuickItem
{
Q_OBJECT
public:
- MessUpItem()
+ GLItem()
{
setFlag(ItemHasContents, true);
}
-
protected:
- virtual QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override
{
- MessUpNode *node = static_cast<MessUpNode *>(oldNode);
+ if (size().isEmpty()) {
+ delete oldNode;
+ return nullptr;
+ }
+
+ GLNode *node = static_cast<GLNode *>(oldNode);
if (!node)
- node = new MessUpNode;
+ node = new GLNode;
+
return node;
}
};
+#endif // QT_CONFIG(opengl)
tst_rendernode::tst_rendernode()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{
- qmlRegisterType<ClearItem>("Test", 1, 0, "ClearItem");
- qmlRegisterType<MessUpItem>("Test", 1, 0, "MessUpItem");
- outerWindow.showNormal();
- outerWindow.setGeometry(0,0,400,400);
+ qmlRegisterType<SimpleItem>("Test", 1, 0, "SimpleItem");
+#if QT_CONFIG(opengl)
+ qmlRegisterType<GLItem>("Test", 1, 0, "GLSimpleItem");
+#endif
}
-static bool fuzzyCompareColor(QRgb x, QRgb y, QByteArray *errorMessage)
+void tst_rendernode::test_data()
{
- enum { fuzz = 4 };
- if (qAbs(qRed(x) - qRed(y)) >= fuzz || qAbs(qGreen(x) - qGreen(y)) >= fuzz || qAbs(qBlue(x) - qBlue(y)) >= fuzz) {
- QString s;
- QDebug(&s).nospace() << Qt::hex << "Color mismatch 0x" << x << " 0x" << y << Qt::dec << " (fuzz=" << fuzz << ").";
- *errorMessage = s.toLocal8Bit();
- return false;
- }
- return true;
-}
+ QTest::addColumn<QString>("file");
-static inline QByteArray msgColorMismatchAt(const QByteArray &colorMsg, int x, int y)
-{
- return colorMsg + QByteArrayLiteral(" at ") + QByteArray::number(x) +',' + QByteArray::number(y);
+ QTest::newRow("simple") << QStringLiteral("simple.qml");
}
-/* The test draws four rects, each 100x100 and verifies
- * that a rendernode which calls glClear() is stacked
- * correctly. The red rectangles come under the white
- * and are obscured.
- */
-void tst_rendernode::renderOrder()
+void tst_rendernode::test()
{
- if (QGuiApplication::primaryScreen()->depth() < 24)
- QSKIP("This test does not work at display depths < 24");
-
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
- if (isRunningOnRhi())
- QSKIP("Render nodes not yet supported with QRhi");
-
- QImage fb = runTest("RenderOrder.qml");
- QVERIFY(!fb.isNull());
+ if (!isRunningOnRhi())
+ QSKIP("Skipping QSGRenderNode test due to not running with QRhi");
+
+ QFETCH(QString, file);
+
+ QScopedPointer<QQuickView> view(createView(file, nullptr, 100, 100, 320, 200));
+ QVERIFY(QTest::qWaitForWindowExposed(view.data()));
+ QImage result = view->grabWindow();
+
+ const int maxFuzz = 5;
+ // red background
+ int x = 10, y = 10;
+ QVERIFY(qAbs(qRed(result.pixel(x, y)) - 255) < maxFuzz);
+ QVERIFY(qAbs(qGreen(result.pixel(x, y))) < maxFuzz);
+ QVERIFY(qAbs(qBlue(result.pixel(x, y))) < maxFuzz);
+
+ // gray rectangle in the middle
+ x = result.width() / 2;
+ y = result.height() / 2;
+ QVERIFY(qAbs(qRed(result.pixel(x, y)) - 128) < maxFuzz);
+ QVERIFY(qAbs(qGreen(result.pixel(x, y)) - 128) < maxFuzz);
+ QVERIFY(qAbs(qBlue(result.pixel(x, y)) - 128) < maxFuzz);
+
+ // check a bit up and left, this catches if the triangle is not depth
+ // tested correctly and so appears above the gray rect, not below as it should
+ x = result.width() / 2 - 5;
+ y = result.height() / 2 - 5;
+ QVERIFY(qAbs(qRed(result.pixel(x, y)) - 128) < maxFuzz);
+ QVERIFY(qAbs(qGreen(result.pixel(x, y)) - 128) < maxFuzz);
+ QVERIFY(qAbs(qBlue(result.pixel(x, y)) - 128) < maxFuzz);
+
+ // in search for blue pixels
+ int blueCount = 0;
+ for (y = 0; y < result.height(); ++y) {
+ for (x = 0; x < result.width(); ++x) {
+ if (qAbs(qRed(result.pixel(x, y))) < maxFuzz
+ && qAbs(qGreen(result.pixel(x, y))) < maxFuzz
+ && qAbs(qBlue(result.pixel(x, y)) - 255) < maxFuzz)
+ {
+ ++blueCount;
+ }
+ }
+ }
- const qreal scaleFactor = QGuiApplication::primaryScreen()->devicePixelRatio();
- QCOMPARE(fb.width(), qRound(200 * scaleFactor));
- QCOMPARE(fb.height(), qRound(200 * scaleFactor));
+ // if the blue triangle is rendered by SimpleNode, there should be lots of
+ // blue pixels present
+ QVERIFY(blueCount > 5000);
+}
- QCOMPARE(fb.pixel(50 * scaleFactor, 50 * scaleFactor), qRgb(0xff, 0xff, 0xff));
- QCOMPARE(fb.pixel(50 * scaleFactor, 150 * scaleFactor), qRgb(0xff, 0xff, 0xff));
- QCOMPARE(fb.pixel(150 * scaleFactor, 50 * scaleFactor), qRgb(0x00, 0x00, 0xff));
+#if QT_CONFIG(opengl)
+void tst_rendernode::gltest_data()
+{
+ QTest::addColumn<QString>("file");
- QByteArray errorMessage;
- const qreal coordinate = 150 * scaleFactor;
- QVERIFY2(fuzzyCompareColor(fb.pixel(coordinate, coordinate), qRgb(0x7f, 0x7f, 0xff), &errorMessage),
- msgColorMismatchAt(errorMessage, coordinate, coordinate).constData());
+ QTest::newRow("simple") << QStringLiteral("glsimple.qml");
}
-/* The test uses a number of nested rectangles with clipping
- * and rotation to verify that using a render node which messes
- * with the state does not break rendering that comes after it.
- */
-void tst_rendernode::messUpState()
+void tst_rendernode::gltest()
{
- if (QGuiApplication::primaryScreen()->depth() < 24)
- QSKIP("This test does not work at display depths < 24");
-
if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
|| (QGuiApplication::platformName() == QLatin1String("minimal")))
QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
- if (isRunningOnRhi())
- QSKIP("Render nodes not yet supported with QRhi");
-
- QImage fb = runTest("MessUpState.qml");
- QVERIFY(!fb.isNull());
- int x1 = 0;
- int x2 = fb.width() / 2;
- int x3 = fb.width() - 1;
- int y1 = 0;
- int y2 = fb.height() * 3 / 16;
- int y3 = fb.height() / 2;
- int y4 = fb.height() * 13 / 16;
- int y5 = fb.height() - 1;
-
- QCOMPARE(fb.pixel(x1, y3), qRgb(0xff, 0xff, 0xff));
- QCOMPARE(fb.pixel(x3, y3), qRgb(0xff, 0xff, 0xff));
-
- QCOMPARE(fb.pixel(x2, y1), qRgb(0x00, 0x00, 0x00));
- QCOMPARE(fb.pixel(x2, y2), qRgb(0x00, 0x00, 0x00));
- QByteArray errorMessage;
- QVERIFY2(fuzzyCompareColor(fb.pixel(x2, y3), qRgb(0x7f, 0x00, 0x7f), &errorMessage),
- msgColorMismatchAt(errorMessage, x2, y3).constData());
- QCOMPARE(fb.pixel(x2, y4), qRgb(0x00, 0x00, 0x00));
- QCOMPARE(fb.pixel(x2, y5), qRgb(0x00, 0x00, 0x00));
-}
+ if (!isRunningOnRhi())
+ QSKIP("Skipping QSGRenderNode test due to not running with QRhi");
-class StateRecordingRenderNode : public QSGRenderNode
-{
-public:
- StateFlags changedStates() const override { return StateFlags(-1); }
- void render(const RenderState *) override {
- matrices[name] = *matrix();
+ if (QQuickWindow::graphicsApi() != QSGRendererInterface::OpenGL)
+ QSKIP("Skipping test due to not using OpenGL");
- }
+ QFETCH(QString, file);
- QString name;
- static QHash<QString, QMatrix4x4> matrices;
-};
+ QScopedPointer<QQuickView> view(createView(file, nullptr, 100, 100, 320, 200));
+ QVERIFY(QTest::qWaitForWindowExposed(view.data()));
+ QImage result = view->grabWindow();
-QHash<QString, QMatrix4x4> StateRecordingRenderNode::matrices;
+ const int maxFuzz = 5;
-class StateRecordingRenderNodeItem : public QQuickItem
-{
- Q_OBJECT
-public:
- StateRecordingRenderNodeItem() { setFlag(ItemHasContents, true); }
- QSGNode *updatePaintNode(QSGNode *r, UpdatePaintNodeData *) {
- if (r)
- return r;
- StateRecordingRenderNode *rn = new StateRecordingRenderNode();
- rn->name = objectName();
- return rn;
- }
-};
-
-void tst_rendernode::matrix()
-{
- if ((QGuiApplication::platformName() == QLatin1String("offscreen"))
- || (QGuiApplication::platformName() == QLatin1String("minimal")))
- QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms");
-
- if (isRunningOnRhi())
- QSKIP("Render nodes not yet supported with QRhi");
-
- qmlRegisterType<StateRecordingRenderNodeItem>("RenderNode", 1, 0, "StateRecorder");
- StateRecordingRenderNode::matrices.clear();
- QVERIFY(!runTest("matrix.qml").isNull());
+ // green
+ int x = 10, y = 10;
+ QVERIFY(qAbs(qRed(result.pixel(x, y))) < maxFuzz);
+ QVERIFY(qAbs(qGreen(result.pixel(x, y)) - 255) < maxFuzz);
+ QVERIFY(qAbs(qBlue(result.pixel(x, y))) < maxFuzz);
- QMatrix4x4 noRotateOffset;
- noRotateOffset.translate(20, 20);
- { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("no-clip; no-rotation"));
- QCOMPARE(result, noRotateOffset);
- }
- { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("parent-clip; no-rotation"));
- QCOMPARE(result, noRotateOffset);
- }
- { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("self-clip; no-rotation"));
- QCOMPARE(result, noRotateOffset);
- }
-
- QMatrix4x4 parentRotation;
- parentRotation.translate(10, 10); // parent at x/y: 10
- parentRotation.translate(5, 5); // rotate 90 around center (width/height: 10)
- parentRotation.rotate(90, 0, 0, 1);
- parentRotation.translate(-5, -5);
- parentRotation.translate(10, 10); // StateRecorder at: x/y: 10
- { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("no-clip; parent-rotation"));
- QCOMPARE(result, parentRotation);
- }
- { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("parent-clip; parent-rotation"));
- QCOMPARE(result, parentRotation);
- }
- { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("self-clip; parent-rotation"));
- QCOMPARE(result, parentRotation);
- }
+ // gray rectangle in the middle
+ x = result.width() / 2;
+ y = result.height() / 2;
+ QVERIFY(qAbs(qRed(result.pixel(x, y)) - 128) < maxFuzz);
+ QVERIFY(qAbs(qGreen(result.pixel(x, y)) - 128) < maxFuzz);
+ QVERIFY(qAbs(qBlue(result.pixel(x, y)) - 128) < maxFuzz);
+}
+#endif // QT_CONFIG(opengl)
- QMatrix4x4 selfRotation;
- selfRotation.translate(10, 10); // parent at x/y: 10
- selfRotation.translate(10, 10); // StateRecorder at: x/y: 10
- selfRotation.rotate(90, 0, 0, 1); // rotate 90, width/height: 0
- { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("no-clip; self-rotation"));
- QCOMPARE(result, selfRotation);
- }
- { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("parent-clip; self-rotation"));
- QCOMPARE(result, selfRotation);
- }
- { QMatrix4x4 result = StateRecordingRenderNode::matrices.value(QStringLiteral("self-clip; self-rotation"));
- QCOMPARE(result, selfRotation);
- }
+QQuickView *tst_rendernode::createView(const QString &file, QWindow *parent, int x, int y, int w, int h)
+{
+ QQuickView *view = new QQuickView(parent);
+ view->setResizeMode(QQuickView::SizeRootObjectToView);
+ view->setSource(testFileUrl(file));
+ if (x >= 0 && y >= 0)
+ view->setPosition(x, y);
+ if (w >= 0 && h >= 0)
+ view->resize(w, h);
+ view->show();
+ return view;
}
bool tst_rendernode::isRunningOnRhi() const
diff --git a/tests/auto/quick/scenegraph/CMakeLists.txt b/tests/auto/quick/scenegraph/CMakeLists.txt
index 046629ba04..c8d8ad34c1 100644
--- a/tests/auto/quick/scenegraph/CMakeLists.txt
+++ b/tests/auto/quick/scenegraph/CMakeLists.txt
@@ -1,26 +1,45 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from scenegraph.pro.
#####################################################################
## tst_scenegraph Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_scenegraph LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+# Collect test data
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ data/*)
+list(APPEND test_data ${test_data_glob})
+
qt_internal_add_test(tst_scenegraph
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_scenegraph.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+ TESTDATA ${test_data}
+)
+
+qt_internal_add_shaders(tst_scenegraph "shaders"
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ "/"
+ FILES
+ "data/render_bug37422.frag"
)
#### Keys ignored in scope 1:.:.:scenegraph.pro:<TRUE>:
@@ -31,10 +50,10 @@ qt_internal_add_test(tst_scenegraph
qt_internal_extend_target(tst_scenegraph CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_scenegraph CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/scenegraph/data/RenderTestBase.qml b/tests/auto/quick/scenegraph/data/RenderTestBase.qml
index 8a999b0354..c753c76512 100644
--- a/tests/auto/quick/scenegraph/data/RenderTestBase.qml
+++ b/tests/auto/quick/scenegraph/data/RenderTestBase.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/manyWindows_dftext.qml b/tests/auto/quick/scenegraph/data/manyWindows_dftext.qml
index fcba3329c3..4e0107c416 100644
--- a/tests/auto/quick/scenegraph/data/manyWindows_dftext.qml
+++ b/tests/auto/quick/scenegraph/data/manyWindows_dftext.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/manyWindows_image.qml b/tests/auto/quick/scenegraph/data/manyWindows_image.qml
index 9454649990..8db982ce52 100644
--- a/tests/auto/quick/scenegraph/data/manyWindows_image.qml
+++ b/tests/auto/quick/scenegraph/data/manyWindows_image.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/manyWindows_ntext.qml b/tests/auto/quick/scenegraph/data/manyWindows_ntext.qml
index b6e5756e07..9792a0c3ab 100644
--- a/tests/auto/quick/scenegraph/data/manyWindows_ntext.qml
+++ b/tests/auto/quick/scenegraph/data/manyWindows_ntext.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/manyWindows_rects.qml b/tests/auto/quick/scenegraph/data/manyWindows_rects.qml
index 212b4b29bc..d2b9ace55f 100644
--- a/tests/auto/quick/scenegraph/data/manyWindows_rects.qml
+++ b/tests/auto/quick/scenegraph/data/manyWindows_rects.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/renderControl_rect.qml b/tests/auto/quick/scenegraph/data/renderControl_rect.qml
new file mode 100644
index 0000000000..3c24bf57fd
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/renderControl_rect.qml
@@ -0,0 +1,16 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+Rectangle {
+ width: 200
+ height: 200
+ color: "steelblue"
+ Rectangle {
+ width: 150
+ height: 150
+ anchors.centerIn: parent
+ color: "red"
+ }
+}
diff --git a/tests/auto/quick/scenegraph/data/render_AlphaOverlapRebuild.qml b/tests/auto/quick/scenegraph/data/render_AlphaOverlapRebuild.qml
new file mode 100644
index 0000000000..e9a72cfddd
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/render_AlphaOverlapRebuild.qml
@@ -0,0 +1,90 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+
+/*
+ QTBUG-92984.
+
+ Have three Image (with semi-transparency) and two semi-transparent
+ Rectangle elements, and so all in the alpha render list, with images that
+ are big enough to not get atlased. (meaning the underlying nodes never get
+ merged, but the nodes for the Rectangle elements might)
+
+ Lay them out vertically below each other, with the two Rectangles on top of
+ the second and third Images, respectively. Then change (swap) the source
+ property of the Images. This triggers a rebuild in the batch renderer.
+
+ Verify that the results are still correct, i.e. that the two Rectangle
+ elements do not get merged. An incorrect result would be having the third
+ Image rendered on top of the corresponding Rectangle due the two Rectangles
+ (incorrectly) being in one merged batch. The Image should always be below,
+ regardless of which nodes get changed, invalidated, and how batches get
+ rebuilt.
+
+ The base-final sample set 1 just verifies that the Image changes from the
+ bluish to greenish. The important part is the second set of samples: this
+ checks that the red(ish) rectangle is still on top of the third Image. With
+ incorrect merging behavior the second final result would be the same as the
+ first final one (i.e. the "background" Image rendered, incorrectly, on top
+ of the Rectangle).
+
+ #samples: 4
+ PixelPos R G B Error-tolerance
+ #base: 30 115 0.24313 0.30588 0.99607 0.05
+ #base: 30 124 0.847059 0.062745 0.2 0.05
+ #final: 30 115 0.36078 0.99607 0.42745 0.05
+ #final: 30 124 0.870588 0.2 0.0862745 0.05
+*/
+
+RenderTestBase {
+ id: root
+
+ property string selectedItem: "item2"
+
+ Item {
+ width: 150; height: 50
+ Image {
+ width: parent.width
+ objectName: "item1"
+ source: "widebtn1.png"
+ }
+ }
+
+ Item {
+ y: 50; width: 150; height: 50
+ Image {
+ width: parent.width
+ objectName: "item2"
+ source: selectedItem == objectName ? "widebtn2.png" : "widebtn1.png"
+ }
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 20
+ color: "red"
+ opacity: 0.8
+ }
+ }
+
+ Item {
+ y: 100; width: 150; height: 50
+ Image {
+ id: img3
+ width: parent.width
+ objectName: "item3"
+ source: selectedItem == objectName ? "widebtn2.png" : "widebtn1.png"
+ }
+ Rectangle {
+ width: parent.width + 50
+ anchors.centerIn: parent
+ height: img3.height - 40
+ color: "red"
+ opacity: 0.8
+ }
+ }
+
+ onEnterFinalStage: {
+ selectedItem = "item3";
+ finalStageComplete = true;
+ }
+}
diff --git a/tests/auto/quick/scenegraph/data/render_BreakOpacityBatch.qml b/tests/auto/quick/scenegraph/data/render_BreakOpacityBatch.qml
index 754c7f22df..9f4fd9b482 100644
--- a/tests/auto/quick/scenegraph/data/render_BreakOpacityBatch.qml
+++ b/tests/auto/quick/scenegraph/data/render_BreakOpacityBatch.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/render_DrawSets.qml b/tests/auto/quick/scenegraph/data/render_DrawSets.qml
index cde29b6085..ab1a50098b 100644
--- a/tests/auto/quick/scenegraph/data/render_DrawSets.qml
+++ b/tests/auto/quick/scenegraph/data/render_DrawSets.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
import SceneGraphTest 1.0
diff --git a/tests/auto/quick/scenegraph/data/render_ImageFiltering.qml b/tests/auto/quick/scenegraph/data/render_ImageFiltering.qml
index af9d3259df..1a2d1b2e1c 100644
--- a/tests/auto/quick/scenegraph/data/render_ImageFiltering.qml
+++ b/tests/auto/quick/scenegraph/data/render_ImageFiltering.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/render_Mipmap.qml b/tests/auto/quick/scenegraph/data/render_Mipmap.qml
index f40c9143b0..858f4b2fef 100644
--- a/tests/auto/quick/scenegraph/data/render_Mipmap.qml
+++ b/tests/auto/quick/scenegraph/data/render_Mipmap.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.3
import QtQuick.Window 2.2
diff --git a/tests/auto/quick/scenegraph/data/render_MovingOverlap.qml b/tests/auto/quick/scenegraph/data/render_MovingOverlap.qml
index 7adf64a8f1..15cc358023 100644
--- a/tests/auto/quick/scenegraph/data/render_MovingOverlap.qml
+++ b/tests/auto/quick/scenegraph/data/render_MovingOverlap.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/render_OpacityThroughBatchRoot.qml b/tests/auto/quick/scenegraph/data/render_OpacityThroughBatchRoot.qml
index b71ad56fd7..a26ba374a6 100644
--- a/tests/auto/quick/scenegraph/data/render_OpacityThroughBatchRoot.qml
+++ b/tests/auto/quick/scenegraph/data/render_OpacityThroughBatchRoot.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/render_OutOfFloatRange.qml b/tests/auto/quick/scenegraph/data/render_OutOfFloatRange.qml
index 3ca2bceb23..a4262ed1f7 100644
--- a/tests/auto/quick/scenegraph/data/render_OutOfFloatRange.qml
+++ b/tests/auto/quick/scenegraph/data/render_OutOfFloatRange.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/render_Overlap.qml b/tests/auto/quick/scenegraph/data/render_Overlap.qml
index 9a8743558f..fafe103ef6 100644
--- a/tests/auto/quick/scenegraph/data/render_Overlap.qml
+++ b/tests/auto/quick/scenegraph/data/render_Overlap.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/render_StackingOrder.qml b/tests/auto/quick/scenegraph/data/render_StackingOrder.qml
index bfe1a7c263..416a5db329 100644
--- a/tests/auto/quick/scenegraph/data/render_StackingOrder.qml
+++ b/tests/auto/quick/scenegraph/data/render_StackingOrder.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/render_bug37422.frag.qsb b/tests/auto/quick/scenegraph/data/render_bug37422.frag.qsb
deleted file mode 100644
index b8770b1332..0000000000
--- a/tests/auto/quick/scenegraph/data/render_bug37422.frag.qsb
+++ /dev/null
Binary files differ
diff --git a/tests/auto/quick/scenegraph/data/render_bug37422.qml b/tests/auto/quick/scenegraph/data/render_bug37422.qml
index 09661d8ccb..d9b294c766 100644
--- a/tests/auto/quick/scenegraph/data/render_bug37422.qml
+++ b/tests/auto/quick/scenegraph/data/render_bug37422.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.12
@@ -73,7 +48,7 @@ RenderTestBase
y: 10
fragmentShader: GraphicsInfo.shaderType === GraphicsInfo.GLSL
? "varying highp vec2 qt_TexCoord0; void main() { gl_FragColor = vec4(1, 0, 0, 1); }"
- : "file:data/render_bug37422.frag.qsb"
+ : "qrc:/data/render_bug37422.frag.qsb"
Rectangle {
width: 5
diff --git a/tests/auto/quick/scenegraph/data/simple.qml b/tests/auto/quick/scenegraph/data/simple.qml
index 18fed625e9..a8eb2ad516 100644
--- a/tests/auto/quick/scenegraph/data/simple.qml
+++ b/tests/auto/quick/scenegraph/data/simple.qml
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.2
diff --git a/tests/auto/quick/scenegraph/data/widebtn1.png b/tests/auto/quick/scenegraph/data/widebtn1.png
new file mode 100644
index 0000000000..1150b67a7a
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/widebtn1.png
Binary files differ
diff --git a/tests/auto/quick/scenegraph/data/widebtn2.png b/tests/auto/quick/scenegraph/data/widebtn2.png
new file mode 100644
index 0000000000..40afe08363
--- /dev/null
+++ b/tests/auto/quick/scenegraph/data/widebtn2.png
Binary files differ
diff --git a/tests/auto/quick/scenegraph/tst_scenegraph.cpp b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
index 0cb3ff428a..1d76fe3181 100644
--- a/tests/auto/quick/scenegraph/tst_scenegraph.cpp
+++ b/tests/auto/quick/scenegraph/tst_scenegraph.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
@@ -44,14 +19,15 @@
#include <private/qsgcontext_p.h>
#include <private/qsgrenderloop_p.h>
#include <private/qsgrhisupport_p.h>
+#include <private/qsgplaintexture_p.h>
-#include "../../shared/util.h"
-#include "../shared/visualtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpa/qplatformintegration.h>
-using namespace QQuickVisualTestUtil;
+using namespace QQuickVisualTestUtils;
class PerPixelRect : public QQuickItem
{
@@ -71,7 +47,7 @@ public:
QColor color() const { return m_color; }
- QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
+ QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override
{
delete node;
node = new QSGNode;
@@ -102,6 +78,9 @@ class tst_SceneGraph : public QQmlDataTest
{
Q_OBJECT
+public:
+ tst_SceneGraph();
+
private slots:
void initTestCase() override;
@@ -115,6 +94,9 @@ private slots:
#endif
void createTextureFromImage_data();
void createTextureFromImage();
+ void withAdoptedRhi();
+ void resizeTextureFromImage();
+ void textureNativeInterface();
private:
QQuickView *createView(const QString &file, QWindow *parent = nullptr, int x = -1, int y = -1, int w = -1, int h = -1);
@@ -126,6 +108,11 @@ public:
~ScopedList() { qDeleteAll(*this); }
};
+tst_SceneGraph::tst_SceneGraph()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
void tst_SceneGraph::initTestCase()
{
qmlRegisterType<PerPixelRect>("SceneGraphTest", 1, 0, "PerPixelRect");
@@ -271,7 +258,7 @@ void tst_SceneGraph::manyWindows()
}
struct Sample {
- Sample(int xx, int yy, qreal rr, qreal gg, qreal bb, qreal errorMargin = 0.05)
+ constexpr Sample(int xx, int yy, qreal rr, qreal gg, qreal bb, qreal errorMargin = 0.05)
: x(xx)
, y(yy)
, r(rr)
@@ -280,8 +267,18 @@ struct Sample {
, tolerance(errorMargin)
{
}
- Sample(const Sample &o) : x(o.x), y(o.y), r(o.r), g(o.g), b(o.b), tolerance(o.tolerance) { }
- Sample() : x(0), y(0), r(0), g(0), b(0), tolerance(0) { }
+ constexpr Sample(const Sample &o) : x(o.x), y(o.y), r(o.r), g(o.g), b(o.b), tolerance(o.tolerance) { }
+ constexpr Sample() : x(0), y(0), r(0), g(0), b(0), tolerance(0) { }
+ constexpr Sample &operator=(const Sample &o)
+ {
+ x = o.x;
+ y = o.y;
+ r = o.r;
+ g = o.g;
+ b = o.b;
+ tolerance = o.tolerance;
+ return *this;
+ }
QString toString(const QImage &image) const {
QColor color(image.pixel(x,y));
@@ -293,7 +290,9 @@ struct Sample {
}
bool check(const QImage &image, qreal scale) {
- QColor color(image.pixel(x * scale, y * scale));
+ const int scaledX = qRound(x * scale);
+ const int scaledY = qRound(y * scale);
+ const QColor color(image.pixel(scaledX, scaledY));
return qAbs(color.redF() - r) <= tolerance
&& qAbs(color.greenF() - g) <= tolerance
&& qAbs(color.blueF() - b) <= tolerance;
@@ -366,23 +365,24 @@ void tst_SceneGraph::render_data()
<< "render_ImageFiltering.qml"
<< "render_bug37422.qml"
<< "render_OpacityThroughBatchRoot.qml"
- << "render_Mipmap.qml";
+ << "render_Mipmap.qml"
+ << "render_AlphaOverlapRebuild.qml";
QRegularExpression sampleCount("#samples: *(\\d+)");
// X:int Y:int R:float G:float B:float Error:float
QRegularExpression baseSamples("#base: *(\\d+) *(\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+)");
QRegularExpression finalSamples("#final: *(\\d+) *(\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+) *(\\d\\.\\d+)");
- foreach (QString fileName, files) {
+ for (QString fileName : std::as_const(files)) {
QFile file(testFile(fileName));
if (!file.open(QFile::ReadOnly)) {
qFatal("render_data: QFile::open failed! file=%s, error=%s",
qPrintable(fileName), qPrintable(file.errorString()));
}
- QStringList contents = QString::fromLatin1(file.readAll()).split(QLatin1Char('\n'));
+ const QStringList contents = QString::fromLatin1(file.readAll()).split(QLatin1Char('\n'));
int samples = -1;
- foreach (QString line, contents) {
+ for (const QString &line : contents) {
auto match = sampleCount.match(line);
if (match.hasMatch()) {
samples = match.captured(1).toInt();
@@ -393,7 +393,7 @@ void tst_SceneGraph::render_data()
qFatal("render_data: failed to find string '#samples: [count], file=%s", qPrintable(fileName));
QList<Sample> baseStage, finalStage;
- foreach (QString line, contents) {
+ for (const QString &line : contents) {
auto match = baseSamples.match(line);
if (match.hasMatch())
baseStage << sample_from_regexp(&match);
@@ -433,6 +433,10 @@ void tst_SceneGraph::render()
// ideal world.
// Just keep this in mind when writing tests.
qreal scale = view.devicePixelRatio();
+ const bool isIntegerScale = qFuzzyIsNull(qreal(qFloor(scale)) - scale);
+
+ if (file == "render_OutOfFloatRange.qml" && !isIntegerScale)
+ QSKIP("render_OutOfFloatRange doesn't work with non-integer scaling factors");
// Grab the window and check all our base stage samples
QImage content = view.grabWindow();
@@ -530,6 +534,309 @@ void tst_SceneGraph::createTextureFromImage()
QCOMPARE(texture->hasAlphaChannel(), expectedAlpha);
}
+#if QT_CONFIG(vulkan)
+static QVulkanInstance *TestOffscreenScene_vkinst = nullptr;
+#endif
+
+struct TestOffscreenScene
+{
+ QQuickRenderControl *renderControl = nullptr;
+ QQuickWindow *window = nullptr;
+ QQmlEngine *engine = nullptr;
+ QQmlComponent *component = nullptr;
+ QQuickItem *rootItem = nullptr;
+
+ // to be called at the end of each test case once all TestOffscreenScene instances are destroyed
+ static void cleanup()
+ {
+#if QT_CONFIG(vulkan)
+ delete TestOffscreenScene_vkinst;
+ TestOffscreenScene_vkinst = nullptr;
+#endif
+ }
+
+ ~TestOffscreenScene()
+ {
+ delete component;
+ delete engine;
+ delete window;
+ delete renderControl;
+ }
+};
+
+static TestOffscreenScene *createOffscreenScene(const QUrl &url, QQuickWindow *compatibleWindow = nullptr)
+{
+ std::unique_ptr<TestOffscreenScene> scene(new TestOffscreenScene);
+ scene->renderControl = new QQuickRenderControl;
+ scene->window = new QQuickWindow(scene->renderControl);
+
+ if (compatibleWindow) {
+ scene->window->setGraphicsApi(compatibleWindow->rendererInterface()->graphicsApi());
+
+#if QT_CONFIG(vulkan)
+ if (compatibleWindow->rendererInterface()->graphicsApi() == QSGRendererInterface::VulkanRhi)
+ scene->window->setVulkanInstance(compatibleWindow->vulkanInstance());
+#endif
+
+ QRhi *rhi = static_cast<QRhi *>(compatibleWindow->rendererInterface()->getResource(compatibleWindow, QSGRendererInterface::RhiResource));
+ if (rhi) {
+ // make it so that the rendercontrol will not create a new QRhi, but rather use what we specify here
+ scene->window->setGraphicsDevice(QQuickGraphicsDevice::fromRhi(rhi));
+ } else {
+ qWarning("No QRhi from the specified compatibleWindow, this is unexpected");
+ }
+ } else {
+#if QT_CONFIG(vulkan)
+ if (QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan) { // honor what QSG_RHI_BACKEND says
+ if (!TestOffscreenScene_vkinst) {
+ TestOffscreenScene_vkinst = new QVulkanInstance;
+ TestOffscreenScene_vkinst->setExtensions(QQuickGraphicsConfiguration::preferredInstanceExtensions());
+ TestOffscreenScene_vkinst->create();
+ }
+ scene->window->setVulkanInstance(TestOffscreenScene_vkinst);
+ }
+#endif
+ }
+
+ scene->engine = new QQmlEngine;
+ scene->component = new QQmlComponent(scene->engine, url);
+ if (scene->component->isError()) {
+ for (const QQmlError &error : scene->component->errors())
+ qWarning() << error.url() << error.line() << error;
+ return nullptr;
+ }
+
+ QObject *rootObject = scene->component->create();
+ if (scene->component->isError()) {
+ for (const QQmlError &error : scene->component->errors())
+ qWarning() << error.url() << error.line() << error;
+ }
+
+ scene->rootItem = qobject_cast<QQuickItem *>(rootObject);
+ if (!scene->rootItem) {
+ qWarning("No root QQuickItem");
+ return nullptr;
+ }
+
+ scene->window->contentItem()->setSize(scene->rootItem->size());
+ scene->window->setGeometry(0, 0, scene->rootItem->width(), scene->rootItem->height());
+ scene->rootItem->setParentItem(scene->window->contentItem());
+
+ if (!scene->renderControl->initialize()) {
+ qWarning("Failed to initialize rendercontrol");
+ return nullptr;
+ }
+
+ return scene.release();
+}
+
+void tst_SceneGraph::withAdoptedRhi()
+{
+ if (!isRunningOnRhi())
+ QSKIP("Skipping test due to not running with QRhi");
+
+ // Use only QQuickRenderControl-based, single-threaded scenes for this
+ // test. QQuickView would not be suitable because it it uses the threaded
+ // render loop, then we end up in threading issues with graphics resources.
+
+ TestOffscreenScene *scene1 = createOffscreenScene(testFileUrl(QLatin1String("renderControl_rect.qml")));
+ QVERIFY(scene1->renderControl && scene1->window && scene1->rootItem);
+
+ // Now another one, but this time sharing the same QRhi as the first one.
+ TestOffscreenScene *scene2 = createOffscreenScene(testFileUrl(QLatin1String("renderControl_rect.qml")), scene1->window);
+ QVERIFY(scene2->renderControl && scene2->window && scene2->rootItem);
+
+ QRhi *rhi = static_cast<QRhi *>(scene1->window->rendererInterface()->getResource(scene1->window, QSGRendererInterface::RhiResource));
+ QCOMPARE(rhi, static_cast<QRhi *>(scene2->window->rendererInterface()->getResource(scene2->window, QSGRendererInterface::RhiResource)));
+
+ { // scope to get resources destroyed before the QRhi
+ const QSize size = scene1->rootItem->size().toSize();
+ QCOMPARE(size, scene2->rootItem->size().toSize());
+ QScopedPointer<QRhiRenderBuffer> ds(rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, size, 1));
+ QVERIFY(ds->create());
+
+ // texture for scene1
+ QScopedPointer<QRhiTexture> tex1(rhi->newTexture(QRhiTexture::RGBA8, size, 1,
+ QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
+ QVERIFY(tex1->create());
+ QRhiTextureRenderTargetDescription rtDesc1(QRhiColorAttachment(tex1.data()));
+ rtDesc1.setDepthStencilBuffer(ds.data());
+ QScopedPointer<QRhiTextureRenderTarget> texRt1(rhi->newTextureRenderTarget(rtDesc1));
+ QScopedPointer<QRhiRenderPassDescriptor> rp1(texRt1->newCompatibleRenderPassDescriptor());
+ texRt1->setRenderPassDescriptor(rp1.data());
+ QVERIFY(texRt1->create());
+ scene1->window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(texRt1.data()));
+
+ // for scene2
+ QScopedPointer<QRhiTexture> tex2(rhi->newTexture(QRhiTexture::RGBA8, size, 1,
+ QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
+ QVERIFY(tex2->create());
+ QRhiTextureRenderTargetDescription rtDesc2(QRhiColorAttachment(tex2.data()));
+ rtDesc2.setDepthStencilBuffer(ds.data());
+ QScopedPointer<QRhiTextureRenderTarget> texRt2(rhi->newTextureRenderTarget(rtDesc2));
+ QScopedPointer<QRhiRenderPassDescriptor> rp2(texRt2->newCompatibleRenderPassDescriptor());
+ texRt2->setRenderPassDescriptor(rp2.data());
+ QVERIFY(texRt2->create());
+ scene2->window->setRenderTarget(QQuickRenderTarget::fromRhiRenderTarget(texRt2.data()));
+
+ // render a frame, first with scene1, then with scene2, targeting their respective textures
+ scene1->renderControl->polishItems();
+ scene1->renderControl->beginFrame();
+ scene1->renderControl->sync();
+ scene1->renderControl->render();
+ scene1->renderControl->endFrame();
+
+ scene2->renderControl->polishItems();
+ scene2->renderControl->beginFrame();
+ scene2->renderControl->sync();
+ scene2->renderControl->render();
+ scene2->renderControl->endFrame();
+
+ // Both tex1 and tex2 belong to the same one QRhi. Read back the
+ // contents. In a real world application one could now render with the
+ // QRhi to some other window, using both textures.
+ for (int stage = 0; stage < 2; ++stage) {
+ QRhiCommandBuffer *cb = nullptr;
+ rhi->beginOffscreenFrame(&cb);
+ bool readCompleted = false;
+ QRhiReadbackResult readResult;
+ QImage result;
+ readResult.completed = [&readCompleted, &readResult, &result, &rhi] {
+ readCompleted = true;
+ QImage wrapperImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888_Premultiplied);
+ if (rhi->isYUpInFramebuffer())
+ result = wrapperImage.mirrored();
+ else
+ result = wrapperImage.copy();
+ };
+ QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch();
+ readbackBatch->readBackTexture(stage == 0 ? tex1.data() : tex2.data(), &readResult);
+ cb->resourceUpdate(readbackBatch);
+ rhi->endOffscreenFrame();
+
+ QVERIFY(readCompleted);
+ QCOMPARE(result.size(), QSize(200, 200));
+ const int maxFuzz = 2;
+ // red
+ QVERIFY(qAbs(qRed(result.pixel(100, 100)) - 255) < maxFuzz);
+ QVERIFY(qAbs(qGreen(result.pixel(100, 100))) < maxFuzz);
+ QVERIFY(qAbs(qBlue(result.pixel(100, 100))) < maxFuzz);
+ }
+ }
+
+ delete scene2; // this does not destroy the QRhi
+ // call anything on the QRhi just to test if it is still valid
+ QVERIFY(!rhi->isDeviceLost());
+ delete scene1; // this does
+
+ TestOffscreenScene::cleanup();
+}
+
+static inline void commitTexture(QRhi *rhi, QSGTexture *texture)
+{
+ QRhiResourceUpdateBatch *rub = rhi->nextResourceUpdateBatch();
+ texture->commitTextureOperations(rhi, rub);
+ QRhiCommandBuffer *cb = nullptr;
+ rhi->beginOffscreenFrame(&cb);
+ cb->resourceUpdate(rub);
+ rhi->endOffscreenFrame();
+}
+
+void tst_SceneGraph::resizeTextureFromImage()
+{
+ if (!isRunningOnRhi())
+ QSKIP("Skipping test due to not running with QRhi");
+
+ // We will need to directly work with QSGTexture and QRhi so have
+ // to be on the same thread as the scene graph. Hence using the
+ // offscreen infrastructure from other tests.
+
+ // note the lifetimes: (vulkan instance) > scenegraph(incl. QRhi) > QSGTexture
+ {
+ QScopedPointer<TestOffscreenScene> scene(createOffscreenScene(testFileUrl(QLatin1String("renderControl_rect.qml"))));
+ QVERIFY(scene->renderControl && scene->window && scene->rootItem);
+
+ {
+ QImage image(256, 128, QImage::Format_RGBA8888);
+ QScopedPointer<QSGTexture> texture(scene->window->createTextureFromImage(image, QQuickWindow::TextureHasAlphaChannel));
+ QRhi *rhi = static_cast<QRhi *>(scene->window->rendererInterface()->getResource(scene->window, QSGRendererInterface::RhiResource));
+ QVERIFY(rhi);
+ commitTexture(rhi, texture.data());
+ // neither is too big nor relies on optional features like NPoT repeat so the size should match always
+ QCOMPARE(texture->textureSize(), image.size());
+ QCOMPARE(texture->rhiTexture()->pixelSize(), image.size());
+
+ QSGPlainTexture *plainTex = qobject_cast<QSGPlainTexture *>(texture.data());
+ QVERIFY(plainTex);
+
+ // QTBUG-96190 - the commitTexture call here used to crash due to not
+ // updating the QRhiTexture size correctly in QSGPlainTexture.
+ image = QImage(512, 256, QImage::Format_RGBA8888);
+ plainTex->setImage(image);
+ commitTexture(rhi, texture.data());
+ QCOMPARE(texture->textureSize(), image.size());
+ QCOMPARE(texture->rhiTexture()->pixelSize(), image.size());
+ }
+ }
+
+ TestOffscreenScene::cleanup();
+}
+
+void tst_SceneGraph::textureNativeInterface()
+{
+ if (!isRunningOnRhi())
+ QSKIP("Skipping texture native interface tests due to not running with QRhi");
+
+ // test it offscreen because we want to do QSG stuff here on the main thread
+ QScopedPointer<TestOffscreenScene> scene(createOffscreenScene(testFileUrl(QLatin1String("renderControl_rect.qml"))));
+ QVERIFY(scene->renderControl && scene->window && scene->rootItem);
+
+ QImage image(512, 512, QImage::Format_RGBA8888);
+
+ QScopedPointer<QSGTexture> texture(scene->window->createTextureFromImage(image, QQuickWindow::TextureHasAlphaChannel));
+ QVERIFY(texture.data());
+
+ commitTexture(scene->window->rhi(), texture.data());
+
+#if QT_CONFIG(metal)
+ if (scene->window->graphicsApi() == QSGRendererInterface::Metal) {
+ auto texNatIf = texture->nativeInterface<QNativeInterface::QSGMetalTexture>();
+ QVERIFY(texNatIf);
+ QVERIFY(texNatIf->nativeTexture());
+ }
+#endif
+
+#if defined(Q_OS_WIN)
+ if (scene->window->graphicsApi() == QSGRendererInterface::Direct3D11) {
+ auto texNatIf = texture->nativeInterface<QNativeInterface::QSGD3D11Texture>();
+ QVERIFY(texNatIf);
+ QVERIFY(texNatIf->nativeTexture());
+ } else if (scene->window->graphicsApi() == QSGRendererInterface::Direct3D12) {
+ auto texNatIf = texture->nativeInterface<QNativeInterface::QSGD3D12Texture>();
+ QVERIFY(texNatIf);
+ QVERIFY(texNatIf->nativeTexture());
+ }
+#endif
+
+#if QT_CONFIG(opengl)
+ if (scene->window->graphicsApi() == QSGRendererInterface::OpenGL) {
+ auto texNatIf = texture->nativeInterface<QNativeInterface::QSGOpenGLTexture>();
+ QVERIFY(texNatIf);
+ QVERIFY(texNatIf->nativeTexture());
+ }
+#endif
+
+#if QT_CONFIG(vulkan)
+ if (scene->window->graphicsApi() == QSGRendererInterface::Vulkan) {
+ auto texNatIf = texture->nativeInterface<QNativeInterface::QSGVulkanTexture>();
+ QVERIFY(texNatIf);
+ QVERIFY(texNatIf->nativeImage());
+ }
+#endif
+}
+
bool tst_SceneGraph::isRunningOnRhi()
{
static bool retval = false;
diff --git a/tests/auto/quick/shared/geometrytestutil.cpp b/tests/auto/quick/shared/geometrytestutil.cpp
deleted file mode 100644
index 07a755e9a5..0000000000
--- a/tests/auto/quick/shared/geometrytestutil.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "geometrytestutil.h"
-
-#include <QQuickItem>
-
-QSizeChangeListener::QSizeChangeListener(QQuickItem *item) :
- item(item)
-{
- connect(item, &QQuickItem::widthChanged, this, &QSizeChangeListener::onSizeChanged);
- connect(item, &QQuickItem::heightChanged, this, &QSizeChangeListener::onSizeChanged);
-}
-
-void QSizeChangeListener::onSizeChanged()
-{
- append(QSize(item->width(), item->height()));
-}
diff --git a/tests/auto/quick/shared/geometrytestutil.h b/tests/auto/quick/shared/geometrytestutil.h
deleted file mode 100644
index 2cf19ed7ff..0000000000
--- a/tests/auto/quick/shared/geometrytestutil.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQUICKGEOMETRYTESTUTIL_H
-#define QQUICKGEOMETRYTESTUTIL_H
-
-#include <QObject>
-#include <QVector>
-#include <QSize>
-
-QT_FORWARD_DECLARE_CLASS(QQuickItem)
-
-class QSizeChangeListener : public QObject, public QVector<QSize>
-{
- Q_OBJECT
-public:
- explicit QSizeChangeListener(QQuickItem *item);
-private slots:
- void onSizeChanged();
-private:
- QQuickItem *item;
-};
-
-#endif // QQUICKGEOMETRYTESTUTIL_H
diff --git a/tests/auto/quick/shared/viewtestutil.cpp b/tests/auto/quick/shared/viewtestutil.cpp
deleted file mode 100644
index 5d9e6ba8dc..0000000000
--- a/tests/auto/quick/shared/viewtestutil.cpp
+++ /dev/null
@@ -1,531 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "viewtestutil.h"
-
-#include <QtCore/QRandomGenerator>
-#include <QtQuick/QQuickView>
-#include <QtQuick/QQuickView>
-#include <QtGui/QScreen>
-
-#include <QtTest/QTest>
-
-#include <QtQuick/private/qquickdeliveryagent_p_p.h>
-#include <QtQuick/private/qquickitemview_p_p.h>
-#include <QtQuick/private/qquickwindow_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QQuickView *QQuickViewTestUtil::createView()
-{
- QQuickView *window = new QQuickView(0);
- const QSize size(240, 320);
- window->resize(size);
- QQuickViewTestUtil::centerOnScreen(window, size);
- return window;
-}
-
-void QQuickViewTestUtil::centerOnScreen(QQuickView *window, const QSize &size)
-{
- const QRect screenGeometry = window->screen()->availableGeometry();
- const QPoint offset = QPoint(size.width() / 2, size.height() / 2);
- window->setFramePosition(screenGeometry.center() - offset);
-}
-
-void QQuickViewTestUtil::centerOnScreen(QQuickView *window)
-{
- QQuickViewTestUtil::centerOnScreen(window, window->size());
-}
-
-void QQuickViewTestUtil::moveMouseAway(QQuickView *window)
-{
-#if QT_CONFIG(cursor) // Get the cursor out of the way.
- QCursor::setPos(window->geometry().topRight() + QPoint(100, 100));
-#else
- Q_UNUSED(window);
-#endif
-}
-
-void QQuickViewTestUtil::moveAndRelease(QQuickView *window, const QPoint &position)
-{
- QTest::mouseMove(window, position);
- QTest::mouseRelease(window, Qt::LeftButton, {}, position);
-}
-
-void QQuickViewTestUtil::moveAndPress(QQuickView *window, const QPoint &position)
-{
- QTest::mouseMove(window, position);
- QTest::mousePress(window, Qt::LeftButton, {}, position);
-}
-
-void QQuickViewTestUtil::flick(QQuickView *window, const QPoint &from, const QPoint &to, int duration)
-{
- const int pointCount = 5;
- QPoint diff = to - from;
-
- // send press, five equally spaced moves, and release.
- moveAndPress(window, from);
-
- for (int i = 0; i < pointCount; ++i)
- QTest::mouseMove(window, from + (i+1)*diff/pointCount, duration / pointCount);
-
- moveAndRelease(window, to);
- QTest::qWait(50);
-}
-
-QList<int> QQuickViewTestUtil::adjustIndexesForAddDisplaced(const QList<int> &indexes, int index, int count)
-{
- QList<int> result;
- for (int i=0; i<indexes.count(); i++) {
- int num = indexes[i];
- if (num >= index) {
- num += count;
- }
- result << num;
- }
- return result;
-}
-
-QList<int> QQuickViewTestUtil::adjustIndexesForMove(const QList<int> &indexes, int from, int to, int count)
-{
- QList<int> result;
- for (int i=0; i<indexes.count(); i++) {
- int num = indexes[i];
- if (from < to) {
- if (num >= from && num < from + count)
- num += (to - from); // target
- else if (num >= from && num < to + count)
- num -= count; // displaced
- } else if (from > to) {
- if (num >= from && num < from + count)
- num -= (from - to); // target
- else if (num >= to && num < from + count)
- num += count; // displaced
- }
- result << num;
- }
- return result;
-}
-
-QList<int> QQuickViewTestUtil::adjustIndexesForRemoveDisplaced(const QList<int> &indexes, int index, int count)
-{
- QList<int> result;
- for (int i=0; i<indexes.count(); i++) {
- int num = indexes[i];
- if (num >= index)
- num -= count;
- result << num;
- }
- return result;
-}
-
-QQuickViewTestUtil::QaimModel::QaimModel(QObject *parent)
- : QAbstractListModel(parent)
-{
-}
-
-int QQuickViewTestUtil::QaimModel::rowCount(const QModelIndex &parent) const
-{
- Q_UNUSED(parent);
- return list.count();
-}
-
-int QQuickViewTestUtil::QaimModel::columnCount(const QModelIndex &parent) const
-{
- Q_UNUSED(parent);
- return columns;
-}
-
-QHash<int,QByteArray> QQuickViewTestUtil::QaimModel::roleNames() const
-{
- QHash<int,QByteArray> roles = QAbstractListModel::roleNames();
- roles.insert(Name, "name");
- roles.insert(Number, "number");
- return roles;
-}
-
-QVariant QQuickViewTestUtil::QaimModel::data(const QModelIndex &index, int role) const
-{
- QVariant rv;
- if (role == Name)
- rv = list.at(index.row()).first;
- else if (role == Number)
- rv = list.at(index.row()).second;
-
- return rv;
-}
-
-int QQuickViewTestUtil::QaimModel::count() const
-{
- return rowCount() * columnCount();
-}
-
-QString QQuickViewTestUtil::QaimModel::name(int index) const
-{
- return list.at(index).first;
-}
-
-QString QQuickViewTestUtil::QaimModel::number(int index) const
-{
- return list.at(index).second;
-}
-
-void QQuickViewTestUtil::QaimModel::addItem(const QString &name, const QString &number)
-{
- emit beginInsertRows(QModelIndex(), list.count(), list.count());
- list.append(QPair<QString,QString>(name, number));
- emit endInsertRows();
-}
-
-void QQuickViewTestUtil::QaimModel::addItems(const QList<QPair<QString, QString> > &items)
-{
- emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
- for (int i=0; i<items.count(); i++)
- list.append(QPair<QString,QString>(items[i].first, items[i].second));
- emit endInsertRows();
-}
-
-void QQuickViewTestUtil::QaimModel::insertItem(int index, const QString &name, const QString &number)
-{
- emit beginInsertRows(QModelIndex(), index, index);
- list.insert(index, QPair<QString,QString>(name, number));
- emit endInsertRows();
-}
-
-void QQuickViewTestUtil::QaimModel::insertItems(int index, const QList<QPair<QString, QString> > &items)
-{
- emit beginInsertRows(QModelIndex(), index, index+items.count()-1);
- for (int i=0; i<items.count(); i++)
- list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
- emit endInsertRows();
-}
-
-void QQuickViewTestUtil::QaimModel::removeItem(int index)
-{
- emit beginRemoveRows(QModelIndex(), index, index);
- list.removeAt(index);
- emit endRemoveRows();
-}
-
-void QQuickViewTestUtil::QaimModel::removeItems(int index, int count)
-{
- emit beginRemoveRows(QModelIndex(), index, index+count-1);
- while (count--)
- list.removeAt(index);
- emit endRemoveRows();
-}
-
-void QQuickViewTestUtil::QaimModel::moveItem(int from, int to)
-{
- emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
- list.move(from, to);
- emit endMoveRows();
-}
-
-void QQuickViewTestUtil::QaimModel::moveItems(int from, int to, int count)
-{
- emit beginMoveRows(QModelIndex(), from, from+count-1, QModelIndex(), to > from ? to+count : to);
- qquickmodelviewstestutil_move(from, to, count, &list);
- emit endMoveRows();
-}
-
-void QQuickViewTestUtil::QaimModel::modifyItem(int idx, const QString &name, const QString &number)
-{
- list[idx] = QPair<QString,QString>(name, number);
- emit dataChanged(index(idx,0), index(idx,0));
-}
-
-void QQuickViewTestUtil::QaimModel::clear()
-{
- int count = list.count();
- if (count > 0) {
- beginRemoveRows(QModelIndex(), 0, count-1);
- list.clear();
- endRemoveRows();
- }
-}
-
-void QQuickViewTestUtil::QaimModel::reset()
-{
- emit beginResetModel();
- emit endResetModel();
-}
-
-void QQuickViewTestUtil::QaimModel::resetItems(const QList<QPair<QString, QString> > &items)
-{
- beginResetModel();
- list = items;
- endResetModel();
-}
-
-class ScopedPrintable
-{
- Q_DISABLE_COPY_MOVE(ScopedPrintable)
-
-public:
- ScopedPrintable(const QString &string) : data(QTest::toString(string)) {}
- ~ScopedPrintable() { delete[] data; }
-
- operator const char*() const { return data; }
-
-private:
- const char *data;
-};
-
-void QQuickViewTestUtil::QaimModel::matchAgainst(const QList<QPair<QString, QString> > &other, const QString &error1, const QString &error2) {
- for (int i=0; i<other.count(); i++) {
- QVERIFY2(list.contains(other[i]),
- ScopedPrintable(other[i].first + QLatin1Char(' ') + other[i].second + QLatin1Char(' ') + error1));
- }
- for (int i=0; i<list.count(); i++) {
- QVERIFY2(other.contains(list[i]),
- ScopedPrintable(list[i].first + QLatin1Char(' ') + list[i].second + QLatin1Char(' ') + error2));
- }
-}
-
-
-
-QQuickViewTestUtil::ListRange::ListRange()
- : valid(false)
-{
-}
-
-QQuickViewTestUtil::ListRange::ListRange(const ListRange &other)
- : valid(other.valid)
-{
- indexes = other.indexes;
-}
-
-QQuickViewTestUtil::ListRange::ListRange(int start, int end)
- : valid(true)
-{
- for (int i=start; i<=end; i++)
- indexes << i;
-}
-
-QQuickViewTestUtil::ListRange::~ListRange()
-{
-}
-
-QQuickViewTestUtil::ListRange QQuickViewTestUtil::ListRange::operator+(const ListRange &other) const
-{
- if (other == *this)
- return *this;
- ListRange a(*this);
- a.indexes.append(other.indexes);
- return a;
-}
-
-bool QQuickViewTestUtil::ListRange::operator==(const ListRange &other) const
-{
- return QSet<int>(indexes.cbegin(), indexes.cend())
- == QSet<int>(other.indexes.cbegin(), other.indexes.cend());
-}
-
-bool QQuickViewTestUtil::ListRange::operator!=(const ListRange &other) const
-{
- return !(*this == other);
-}
-
-bool QQuickViewTestUtil::ListRange::isValid() const
-{
- return valid;
-}
-
-int QQuickViewTestUtil::ListRange::count() const
-{
- return indexes.count();
-}
-
-QList<QPair<QString,QString> > QQuickViewTestUtil::ListRange::getModelDataValues(const QaimModel &model)
-{
- QList<QPair<QString,QString> > data;
- if (!valid)
- return data;
- for (int i=0; i<indexes.count(); i++)
- data.append(qMakePair(model.name(indexes[i]), model.number(indexes[i])));
- return data;
-}
-
-QQuickViewTestUtil::StressTestModel::StressTestModel()
- : QAbstractListModel()
- , m_rowCount(20)
-{
- QTimer *t = new QTimer(this);
- t->setInterval(500);
- t->start();
-
- connect(t, &QTimer::timeout, this, &StressTestModel::updateModel);
-}
-
-int QQuickViewTestUtil::StressTestModel::rowCount(const QModelIndex &) const
-{
- return m_rowCount;
-}
-
-QVariant QQuickViewTestUtil::StressTestModel::data(const QModelIndex &, int) const
-{
- return QVariant();
-}
-
-void QQuickViewTestUtil::StressTestModel::updateModel()
-{
- if (m_rowCount > 10) {
- for (int i = 0; i < 10; ++i) {
- int rnum = QRandomGenerator::global()->bounded(m_rowCount);
- beginRemoveRows(QModelIndex(), rnum, rnum);
- m_rowCount--;
- endRemoveRows();
- }
- }
- if (m_rowCount < 20) {
- for (int i = 0; i < 10; ++i) {
- int rnum = QRandomGenerator::global()->bounded(m_rowCount);
- beginInsertRows(QModelIndex(), rnum, rnum);
- m_rowCount++;
- endInsertRows();
- }
- }
-}
-
-bool QQuickViewTestUtil::testVisibleItems(const QQuickItemViewPrivate *priv, bool *nonUnique, FxViewItem **failItem, int *expectedIdx)
-{
- QHash<QQuickItem*, int> uniqueItems;
-
- int skip = 0;
- for (int i = 0; i < priv->visibleItems.count(); ++i) {
- FxViewItem *item = priv->visibleItems.at(i);
- if (!item) {
- *failItem = nullptr;
- return false;
- }
-#if 0
- qDebug() << "\t" << item->index
- << item->item
- << item->position()
- << (!item->item || QQuickItemPrivate::get(item->item)->culled ? "hidden" : "visible");
-#endif
- if (item->index == -1) {
- ++skip;
- } else if (item->index != priv->visibleIndex + i - skip) {
- *nonUnique = false;
- *failItem = item;
- *expectedIdx = priv->visibleIndex + i - skip;
- return false;
- } else if (uniqueItems.contains(item->item)) {
- *nonUnique = true;
- *failItem = item;
- *expectedIdx = uniqueItems.find(item->item).value();
- return false;
- }
-
- uniqueItems.insert(item->item, item->index);
- }
-
- return true;
-}
-
-namespace QQuickTouchUtils {
-
- /* QQuickWindow does event compression and only delivers events just
- * before it is about to render the next frame. Since some tests
- * rely on events being delivered immediately AND that no other
- * event processing has occurred in the meanwhile, we flush the
- * event manually and immediately.
- */
- void flush(QQuickWindow *window) {
- if (!window)
- return;
- QQuickDeliveryAgentPrivate *da = QQuickWindowPrivate::get(window)->deliveryAgentPrivate();
- if (!da || !da->delayedTouch)
- return;
- da->deliverDelayedTouchEvent();
- }
-
-}
-
-namespace QQuickTest {
-
- /*! \internal
- Initialize \a view, set \a url, center in available geometry, move mouse away if desired.
- If \a errorMessage is given, QQuickView::errors() will be concatenated into it;
- otherwise, the QWARN messages are generally enough to debug the test.
-
- Returns \c false if the view fails to load the QML. That should be fatal in most tests,
- so normally the return value should be checked with QVERIFY.
- */
- bool initView(QQuickView &view, const QUrl &url, bool moveMouseOut, QByteArray *errorMessage)
- {
- view.setSource(url);
- while (view.status() == QQuickView::Loading)
- QTest::qWait(10);
- if (view.status() != QQuickView::Ready) {
- if (errorMessage) {
- for (const QQmlError &e : view.errors())
- errorMessage->append(e.toString().toLocal8Bit() + '\n');
- }
- return false;
- }
- const QRect screenGeometry = view.screen()->availableGeometry();
- const QSize size = view.size();
- const QPoint offset = QPoint(size.width() / 2, size.height() / 2);
- view.setFramePosition(screenGeometry.center() - offset);
- #if QT_CONFIG(cursor) // Get the cursor out of the way.
- if (moveMouseOut)
- QCursor::setPos(view.geometry().topRight() + QPoint(100, 100));
- #else
- Q_UNUSED(moveMouseOut);
- #endif
- return true;
- }
-
- /*! \internal
- Initialize \a view, set \a url, center in available geometry, move mouse away,
- show the \a view, wait for it to be exposed, and verify that its rootObject is not null.
-
- Returns \c false if anything fails, which should be fatal in most tests.
- The usual way to call this function is
- \code
- QQuickView window;
- QVERIFY(QQuickTest::showView(window, testFileUrl("myitems.qml")));
- \endcode
- */
- bool showView(QQuickView &view, const QUrl &url)
- {
- if (!initView(view, url))
- return false;
- view.show();
- if (!QTest::qWaitForWindowExposed(&view))
- return false;
- if (!view.rootObject())
- return false;
- return true;
- }
-}
-
-QT_END_NAMESPACE
diff --git a/tests/auto/quick/shared/viewtestutil.h b/tests/auto/quick/shared/viewtestutil.h
deleted file mode 100644
index 377296b095..0000000000
--- a/tests/auto/quick/shared/viewtestutil.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQUICKVIEWTESTUTIL_H
-#define QQUICKVIEWTESTUTIL_H
-
-#include <QtQuick/QQuickItem>
-#include <QtQml/QQmlExpression>
-#include <QtCore/QAbstractListModel>
-
-QT_FORWARD_DECLARE_CLASS(QQuickView)
-QT_FORWARD_DECLARE_CLASS(QQuickItemViewPrivate)
-QT_FORWARD_DECLARE_CLASS(FxViewItem)
-
-QT_BEGIN_NAMESPACE
-
-namespace QQuickViewTestUtil
-{
- QQuickView *createView();
-
- void flick(QQuickView *window, const QPoint &from, const QPoint &to, int duration);
- void centerOnScreen(QQuickView *window, const QSize &size);
- void centerOnScreen(QQuickView *window);
- void moveMouseAway(QQuickView *window);
- void moveAndPress(QQuickView *window, const QPoint &position);
- void moveAndRelease(QQuickView *window, const QPoint &position);
-
- QList<int> adjustIndexesForAddDisplaced(const QList<int> &indexes, int index, int count);
- QList<int> adjustIndexesForMove(const QList<int> &indexes, int from, int to, int count);
- QList<int> adjustIndexesForRemoveDisplaced(const QList<int> &indexes, int index, int count);
-
- struct ListChange {
- enum { Inserted, Removed, Moved, SetCurrent, SetContentY, Polish } type;
- int index;
- int count;
- int to; // Move
- qreal pos; // setContentY
-
- static ListChange insert(int index, int count = 1) { ListChange c = { Inserted, index, count, -1, 0.0 }; return c; }
- static ListChange remove(int index, int count = 1) { ListChange c = { Removed, index, count, -1, 0.0 }; return c; }
- static ListChange move(int index, int to, int count) { ListChange c = { Moved, index, count, to, 0.0 }; return c; }
- static ListChange setCurrent(int index) { ListChange c = { SetCurrent, index, -1, -1, 0.0 }; return c; }
- static ListChange setContentY(qreal pos) { ListChange c = { SetContentY, -1, -1, -1, pos }; return c; }
- static ListChange polish() { ListChange c = { Polish, -1, -1, -1, 0.0 }; return c; }
- };
-
- class QaimModel : public QAbstractListModel
- {
- Q_OBJECT
- public:
- enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
-
- QaimModel(QObject *parent=0);
-
- int rowCount(const QModelIndex &parent=QModelIndex()) const override;
- int columnCount(const QModelIndex &parent=QModelIndex()) const override;
- QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override;
- QHash<int,QByteArray> roleNames() const override;
-
- int count() const;
- QString name(int index) const;
- QString number(int index) const;
-
- Q_INVOKABLE void addItem(const QString &name, const QString &number);
- void addItems(const QList<QPair<QString, QString> > &items);
- void insertItem(int index, const QString &name, const QString &number);
- void insertItems(int index, const QList<QPair<QString, QString> > &items);
-
- Q_INVOKABLE void removeItem(int index);
- void removeItems(int index, int count);
-
- void moveItem(int from, int to);
- void moveItems(int from, int to, int count);
-
- void modifyItem(int idx, const QString &name, const QString &number);
-
- void clear();
- void reset();
- void resetItems(const QList<QPair<QString, QString> > &items);
-
- void matchAgainst(const QList<QPair<QString, QString> > &other, const QString &error1, const QString &error2);
-
- using QAbstractListModel::dataChanged;
-
- int columns = 1;
-
- private:
- QList<QPair<QString,QString> > list;
- };
-
- class ListRange
- {
- public:
- ListRange();
- ListRange(const ListRange &other);
- ListRange(int start, int end);
-
- ~ListRange();
-
- ListRange operator+(const ListRange &other) const;
- bool operator==(const ListRange &other) const;
- bool operator!=(const ListRange &other) const;
-
- bool isValid() const;
- int count() const;
-
- QList<QPair<QString,QString> > getModelDataValues(const QaimModel &model);
-
- QList<int> indexes;
- bool valid;
- };
-
- template<typename T>
- static void qquickmodelviewstestutil_move(int from, int to, int n, T *items)
- {
- if (from > to) {
- // Only move forwards - flip if backwards moving
- int tfrom = from;
- int tto = to;
- from = tto;
- to = tto+n;
- n = tfrom-tto;
- }
-
- T replaced;
- int i=0;
- typename T::ConstIterator it=items->begin(); it += from+n;
- for (; i<to-from; ++i,++it)
- replaced.append(*it);
- i=0;
- it=items->begin(); it += from;
- for (; i<n; ++i,++it)
- replaced.append(*it);
- typename T::ConstIterator f=replaced.begin();
- typename T::Iterator t=items->begin(); t += from;
- for (; f != replaced.end(); ++f, ++t)
- *t = *f;
- }
-
- class StressTestModel : public QAbstractListModel
- {
- Q_OBJECT
-
- public:
-
- StressTestModel();
-
- int rowCount(const QModelIndex &) const override;
- QVariant data(const QModelIndex &, int) const override;
-
- public Q_SLOTS:
- void updateModel();
-
- private:
- int m_rowCount;
- };
-
- bool testVisibleItems(const QQuickItemViewPrivate *priv, bool *nonUnique, FxViewItem **failItem, int *expectedIdx);
-}
-
-namespace QQuickTouchUtils {
- void flush(QQuickWindow *window);
-}
-
-namespace QQuickTest {
- bool initView(QQuickView &v, const QUrl &url, bool moveMouseOut = true, QByteArray *errorMessage = nullptr);
- bool showView(QQuickView &v, const QUrl &url);
-}
-
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(QQuickViewTestUtil::QaimModel*)
-Q_DECLARE_METATYPE(QQuickViewTestUtil::ListChange)
-Q_DECLARE_METATYPE(QList<QQuickViewTestUtil::ListChange>)
-Q_DECLARE_METATYPE(QQuickViewTestUtil::ListRange)
-
-
-#endif // QQUICKVIEWTESTUTIL_H
diff --git a/tests/auto/quick/shared/visualtestutil.cpp b/tests/auto/quick/shared/visualtestutil.cpp
deleted file mode 100644
index 06f7386902..0000000000
--- a/tests/auto/quick/shared/visualtestutil.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "visualtestutil.h"
-
-#include <QtQuick/QQuickItem>
-#include <QtCore/QDebug>
-
-bool QQuickVisualTestUtil::delegateVisible(QQuickItem *item)
-{
- return item->isVisible() && !QQuickItemPrivate::get(item)->culled;
-}
-
-QQuickItem *QQuickVisualTestUtil::findVisibleChild(QQuickItem *parent, const QString &objectName)
-{
- QQuickItem *item = 0;
- QList<QQuickItem*> items = parent->findChildren<QQuickItem*>(objectName);
- for (int i = 0; i < items.count(); ++i) {
- if (items.at(i)->isVisible() && !QQuickItemPrivate::get(items.at(i))->culled) {
- item = items.at(i);
- break;
- }
- }
- return item;
-}
-
-void QQuickVisualTestUtil::dumpTree(QQuickItem *parent, int depth)
-{
- static QString padding(" ");
- for (int i = 0; i < parent->childItems().count(); ++i) {
- QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
- if (!item)
- continue;
- qDebug() << padding.left(depth*2) << item;
- dumpTree(item, depth+1);
- }
-}
-
-// A custom compare function to avoid issues such as:
-// When running on native Nvidia graphics cards on linux, the
-// distance field glyph pixels have a measurable, but not visible
-// pixel error. This was GT-216 with the ubuntu "nvidia-319" driver package.
-// llvmpipe does not show the same issue.
-
-bool QQuickVisualTestUtil::compareImages(const QImage &ia, const QImage &ib, QString *errorMessage)
-{
- if (ia.size() != ib.size()) {
- QDebug(errorMessage) << "Images are of different size:" << ia.size() << ib.size()
- << "DPR:" << ia.devicePixelRatio() << ib.devicePixelRatio();
- return false;
- }
- if (ia.format() != ib.format()) {
- QDebug(errorMessage) << "Images are of different formats:" << ia.format() << ib.format();
- return false;
- }
-
- int w = ia.width();
- int h = ia.height();
- const int tolerance = 5;
- for (int y=0; y<h; ++y) {
- const uint *as= (const uint *) ia.constScanLine(y);
- const uint *bs= (const uint *) ib.constScanLine(y);
- for (int x=0; x<w; ++x) {
- uint a = as[x];
- uint b = bs[x];
-
- // No tolerance for error in the alpha.
- if ((a & 0xff000000) != (b & 0xff000000)
- || qAbs(qRed(a) - qRed(b)) > tolerance
- || qAbs(qRed(a) - qRed(b)) > tolerance
- || qAbs(qRed(a) - qRed(b)) > tolerance) {
- QDebug(errorMessage) << "Mismatch at:" << x << y << ':'
- << Qt::hex << Qt::showbase << a << b;
- return false;
- }
- }
- }
- return true;
-}
diff --git a/tests/auto/quick/shared/visualtestutil.h b/tests/auto/quick/shared/visualtestutil.h
deleted file mode 100644
index e623e3e225..0000000000
--- a/tests/auto/quick/shared/visualtestutil.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQUICKVISUALTESTUTIL_H
-#define QQUICKVISUALTESTUTIL_H
-
-#include <QtQuick/QQuickItem>
-#include <QtQml/QQmlExpression>
-
-#include <QtQuick/private/qquickitem_p.h>
-
-namespace QQuickVisualTestUtil
-{
- QQuickItem *findVisibleChild(QQuickItem *parent, const QString &objectName);
-
- void dumpTree(QQuickItem *parent, int depth = 0);
-
- bool delegateVisible(QQuickItem *item);
-
- /*
- Find an item with the specified objectName. If index is supplied then the
- item must also evaluate the {index} expression equal to index
- */
- template<typename T>
- T *findItem(QQuickItem *parent, const QString &objectName, int index = -1)
- {
- const QMetaObject &mo = T::staticMetaObject;
- for (int i = 0; i < parent->childItems().count(); ++i) {
- QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
- if (!item)
- continue;
- if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
- if (index != -1) {
- QQmlExpression e(qmlContext(item), item, "index");
- if (e.evaluate().toInt() == index)
- return static_cast<T*>(item);
- } else {
- return static_cast<T*>(item);
- }
- }
- item = findItem<T>(item, objectName, index);
- if (item)
- return static_cast<T*>(item);
- }
-
- return 0;
- }
-
- template<typename T>
- QList<T*> findItems(QQuickItem *parent, const QString &objectName, bool visibleOnly = true)
- {
- QList<T*> items;
- const QMetaObject &mo = T::staticMetaObject;
- for (int i = 0; i < parent->childItems().count(); ++i) {
- QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
- if (!item || (visibleOnly && (!item->isVisible() || QQuickItemPrivate::get(item)->culled)))
- continue;
- if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName))
- items.append(static_cast<T*>(item));
- items += findItems<T>(item, objectName);
- }
-
- return items;
- }
-
- template<typename T>
- QList<T*> findItems(QQuickItem *parent, const QString &objectName, const QList<int> &indexes)
- {
- QList<T*> items;
- for (int i=0; i<indexes.count(); i++)
- items << qobject_cast<QQuickItem*>(findItem<T>(parent, objectName, indexes[i]));
- return items;
- }
-
- bool compareImages(const QImage &ia, const QImage &ib, QString *errorMessage);
-}
-
-#endif // QQUICKVISUALTESTUTIL_H
diff --git a/tests/auto/quick/sharedimage/CMakeLists.txt b/tests/auto/quick/sharedimage/CMakeLists.txt
index c69b150c97..c6d71896c6 100644
--- a/tests/auto/quick/sharedimage/CMakeLists.txt
+++ b/tests/auto/quick/sharedimage/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from sharedimage.pro.
#####################################################################
## tst_sharedimage Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_sharedimage LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -13,7 +22,7 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_sharedimage
SOURCES
tst_sharedimage.cpp
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
Qt::QuickPrivate
TESTDATA ${test_data}
diff --git a/tests/auto/quick/sharedimage/tst_sharedimage.cpp b/tests/auto/quick/sharedimage/tst_sharedimage.cpp
index afadb76ad0..e3d87f68dd 100644
--- a/tests/auto/quick/sharedimage/tst_sharedimage.cpp
+++ b/tests/auto/quick/sharedimage/tst_sharedimage.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest>
#include <private/qquickimage_p.h>
@@ -49,6 +24,14 @@ void tst_sharedimage::initTestCase()
#if !QT_CONFIG(systemsemaphore)
QSKIP("Shared image not supported");
#endif
+
+#ifdef Q_OS_ANDROID
+ /*
+ * On Android, images are usually in resources, not in
+ * files on the file system.
+ */
+ QSKIP("Shared image not useful on Android, skipping test");
+#endif
}
void tst_sharedimage::compareToPlainLoad_data()
diff --git a/tests/auto/quick/softwarerenderer/CMakeLists.txt b/tests/auto/quick/softwarerenderer/CMakeLists.txt
new file mode 100644
index 0000000000..9e8433f8df
--- /dev/null
+++ b/tests/auto/quick/softwarerenderer/CMakeLists.txt
@@ -0,0 +1,35 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_softwarerenderer Test:
+#####################################################################
+
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_softwarerenderer LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
+qt_internal_add_test(tst_softwarerenderer
+ SOURCES
+ tst_softwarerenderer.cpp
+ LIBRARIES
+ Qt::Gui
+ Qt::Quick
+ Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
+)
+
+## Scopes:
+#####################################################################
+
+qt_internal_extend_target(tst_softwarerenderer CONDITION ANDROID OR IOS
+ DEFINES
+ QT_QMLTEST_DATADIR=":/data"
+)
+
+qt_internal_extend_target(tst_softwarerenderer CONDITION NOT ANDROID AND NOT IOS
+ DEFINES
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+)
diff --git a/tests/auto/quick/softwarerenderer/tst_softwarerenderer.cpp b/tests/auto/quick/softwarerenderer/tst_softwarerenderer.cpp
new file mode 100644
index 0000000000..034c6b8139
--- /dev/null
+++ b/tests/auto/quick/softwarerenderer/tst_softwarerenderer.cpp
@@ -0,0 +1,99 @@
+// Copyright (C) 2022 zccrs <zccrs@live.com>, JiDe Zhang <zhangjide@uniontech.com>.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include <QtQuick>
+#include <QtQml>
+#include <QGuiApplication>
+
+#include <private/qsgrenderloop_p.h>
+
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+
+class tst_SoftwareRenderer : public QQmlDataTest
+{
+ Q_OBJECT
+
+public:
+ tst_SoftwareRenderer();
+
+private slots:
+ void initTestCase() override;
+
+ void renderTarget();
+};
+
+tst_SoftwareRenderer::tst_SoftwareRenderer()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
+{
+}
+
+void tst_SoftwareRenderer::initTestCase()
+{
+ QQuickWindow::setGraphicsApi(QSGRendererInterface::Software);
+ QSGRenderLoop *loop = QSGRenderLoop::instance();
+ qDebug() << "RenderLoop:" << loop
+ << "Graph backend:" << QQuickWindow::sceneGraphBackend();
+}
+
+void tst_SoftwareRenderer::renderTarget()
+{
+ if (QQuickWindow::sceneGraphBackend() != "software")
+ QSKIP("Skipping complex rendering tests due to not running with software");
+
+ QQuickRenderControl rc;
+ QScopedPointer<QQuickWindow> window(new QQuickWindow(&rc));
+ window->setWidth(10);
+ window->setHeight(10);
+
+ QImage renderTarget1(window->size(), QImage::Format_ARGB32_Premultiplied);
+ renderTarget1.fill(Qt::red);
+ auto rt1 = QQuickRenderTarget::fromPaintDevice(&renderTarget1);
+ rt1.setDevicePixelRatio(renderTarget1.devicePixelRatio());
+ window->setRenderTarget(rt1);
+ window->setColor(Qt::blue);
+
+ rc.polishItems();
+
+ rc.beginFrame();
+ rc.sync();
+ rc.render();
+ rc.endFrame();
+
+ QImage content = window->grabWindow();
+ QString errorMessage;
+ QVERIFY2(QQuickVisualTestUtils::compareImages(content, renderTarget1, &errorMessage),
+ qPrintable(errorMessage));
+
+ QImage renderTarget2(window->size(), QImage::Format_ARGB32_Premultiplied);
+ renderTarget2.fill(Qt::green);
+ auto rt2 = QQuickRenderTarget::fromPaintDevice(&renderTarget2);
+ rt2.setDevicePixelRatio(renderTarget2.devicePixelRatio());
+ window->setRenderTarget(rt2);
+
+ rc.polishItems();
+
+ rc.beginFrame();
+ rc.sync();
+ rc.render();
+ rc.endFrame();
+
+ content = window->grabWindow();
+ QVERIFY2(QQuickVisualTestUtils::compareImages(content, renderTarget2, &errorMessage),
+ qPrintable(errorMessage));
+ QVERIFY2(QQuickVisualTestUtils::compareImages(renderTarget2, renderTarget1, &errorMessage),
+ qPrintable(errorMessage));
+
+ // Clear render target
+ window->setRenderTarget(QQuickRenderTarget());
+ QImage content2 = window->grabWindow();
+ content2 = content2.scaled(content.size());
+ QVERIFY2(QQuickVisualTestUtils::compareImages(content, content2, &errorMessage),
+ qPrintable(errorMessage));
+}
+
+#include "tst_softwarerenderer.moc"
+
+QTEST_MAIN(tst_SoftwareRenderer)
+
diff --git a/tests/auto/quick/touchmouse/BLACKLIST b/tests/auto/quick/touchmouse/BLACKLIST
index 9afc86c2fe..aaf5b8e95d 100644
--- a/tests/auto/quick/touchmouse/BLACKLIST
+++ b/tests/auto/quick/touchmouse/BLACKLIST
@@ -8,3 +8,7 @@ windows gcc developer-build
# QTBUG-74517
[touchButtonOnFlickable]
windows gcc developer-build
+
+# QTBUG-118059
+[tapOnDismissiveTopMouseAreaClicksBottomOne]
+opensuse-leap
diff --git a/tests/auto/quick/touchmouse/CMakeLists.txt b/tests/auto/quick/touchmouse/CMakeLists.txt
index 703f4f7578..bca541bbfb 100644
--- a/tests/auto/quick/touchmouse/CMakeLists.txt
+++ b/tests/auto/quick/touchmouse/CMakeLists.txt
@@ -1,9 +1,18 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
# Generated from touchmouse.pro.
#####################################################################
## tst_touchmouse Test:
#####################################################################
+if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ cmake_minimum_required(VERSION 3.16)
+ project(tst_touchmouse LANGUAGES CXX)
+ find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST)
+endif()
+
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
@@ -12,21 +21,14 @@ list(APPEND test_data ${test_data_glob})
qt_internal_add_test(tst_touchmouse
SOURCES
- ../../shared/util.cpp ../../shared/util.h
- ../shared/geometrytestutil.cpp ../shared/geometrytestutil.h
- ../shared/viewtestutil.cpp ../shared/viewtestutil.h
- ../shared/visualtestutil.cpp ../shared/visualtestutil.h
tst_touchmouse.cpp
- DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
- INCLUDE_DIRECTORIES
- ../../shared
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::CorePrivate
Qt::Gui
Qt::GuiPrivate
Qt::QmlPrivate
Qt::QuickPrivate
+ Qt::QuickTestUtilsPrivate
TESTDATA ${test_data}
)
@@ -35,10 +37,10 @@ qt_internal_add_test(tst_touchmouse
qt_internal_extend_target(tst_touchmouse CONDITION ANDROID OR IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\":/data\\\"
+ QT_QMLTEST_DATADIR=":/data"
)
qt_internal_extend_target(tst_touchmouse CONDITION NOT ANDROID AND NOT IOS
DEFINES
- QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\"
+ QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
)
diff --git a/tests/auto/quick/touchmouse/data/oneMouseArea.qml b/tests/auto/quick/touchmouse/data/oneMouseArea.qml
new file mode 100644
index 0000000000..dccc5792c8
--- /dev/null
+++ b/tests/auto/quick/touchmouse/data/oneMouseArea.qml
@@ -0,0 +1,14 @@
+import QtQuick 2.0
+
+Item {
+ width: 320; height: 240
+
+ Rectangle {
+ width: parent.width / 2; height: parent.height; x: width
+ color: ma.containsPress ? "steelblue" : "lightsteelblue"
+ MouseArea {
+ id: ma
+ anchors.fill: parent
+ }
+ }
+}
diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp
index ef0df0cddb..501d996797 100644
--- a/tests/auto/quick/touchmouse/tst_touchmouse.cpp
+++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest/QtTest>
@@ -46,8 +21,8 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlproperty.h>
-#include "../../shared/util.h"
-#include "../shared/viewtestutil.h"
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/viewtestutils_p.h>
Q_LOGGING_CATEGORY(lcTests, "qt.quick.tests")
@@ -79,7 +54,7 @@ QDebug operator<<(QDebug dbg, const struct Event &event) {
if (event.points.isEmpty())
dbg << " @ " << event.mousePos << " global " << event.mousePosGlobal;
else
- dbg << ", " << event.points.count() << " touchpoints: " << event.points;
+ dbg << ", " << event.points.size() << " touchpoints: " << event.points;
dbg << ')';
return dbg;
}
@@ -150,6 +125,12 @@ public:
++touchUngrabCount;
}
+ void dumpEventList()
+ {
+ for (const auto &event : eventList)
+ qDebug() << event;
+ }
+
bool event(QEvent *event) override {
return QQuickItem::event(event);
}
@@ -185,12 +166,22 @@ class GrabMonitor : public QObject
{
public:
QObject *exclusiveGrabber = nullptr;
+ int transitionCount = 0;
bool fromMouseEvent = false;
bool canceled = false;
+ void reset()
+ {
+ exclusiveGrabber = nullptr;
+ transitionCount = 0;
+ fromMouseEvent = false;
+ canceled = false;
+ }
+
void onGrabChanged(QObject *grabber, QPointingDevice::GrabTransition transition, const QPointerEvent *event, const QEventPoint &point)
{
qCDebug(lcTests) << grabber << transition << event << point << point.device();
+ ++transitionCount;
switch (transition) {
case QPointingDevice::GrabTransition::GrabExclusive:
exclusiveGrabber = grabber;
@@ -217,6 +208,7 @@ class tst_TouchMouse : public QQmlDataTest
Q_OBJECT
public:
tst_TouchMouse()
+ : QQmlDataTest(QT_QMLTEST_DATADIR)
{}
private slots:
@@ -246,6 +238,11 @@ private slots:
void hoverEnabled();
void implicitUngrab();
+ void touchCancelWillCancelMousePress();
+
+ void oneTouchInsideAndOneOutside();
+
+ void strayTouchDoesntAutograb();
protected:
bool eventFilter(QObject *, QEvent *event) override
@@ -429,7 +426,7 @@ void tst_TouchMouse::testEventFilter()
// QScopedPointer<QQuickView> window(createView());
// window.setSource(testFileUrl("singleitem.qml"));
// window.show();
-// QQuickViewTestUtil::centerOnScreen(&window);
+// QQuickVisualTestUtils::centerOnScreen(&window);
// QVERIFY(QTest::qWaitForWindowActive(&window));
// QVERIFY(window->rootObject() != 0);
@@ -716,7 +713,7 @@ void tst_TouchMouse::touchButtonOnFlickable()
QTRY_COMPARE(eventItem2->touchUngrabCount, 1);
qCDebug(lcTests) << "expected delivered events: press(touch) move(touch)" << eventItem2->eventList;
- QCOMPARE(eventItem2->eventList.size(), 2);
+ QCOMPARE(eventItem2->eventList.size(), 3);
QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchUpdate);
QCOMPARE(grabMonitor.exclusiveGrabber, flickable);
// both EventItem and Flickable handled the actual touch, so synth-mouse doesn't happen
@@ -799,7 +796,7 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable()
qCDebug(lcTests) << "expected filtered events: actual TouchBegin and replayed TouchBegin" << filteredEventList;
QTRY_COMPARE(eventItem1->eventList.size(), 1);
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
- QCOMPARE(filteredEventList.count(), 2); // actual touch begin and replayed touch begin
+ QCOMPARE(filteredEventList.size(), 2); // actual touch begin and replayed touch begin
}
if (!releaseBeforeDelayIsOver) {
@@ -814,7 +811,7 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable()
if (scrollBeforeDelayIsOver) {
QCOMPARE(eventItem1->eventList.size(), 0);
qCDebug(lcTests) << "expected filtered events: 1 TouchBegin and 3 TouchUpdate" << filteredEventList;
- QCOMPARE(filteredEventList.count(), 4);
+ QCOMPARE(filteredEventList.size(), 4);
} else {
qCDebug(lcTests) << "expected delivered events: press(mouse), move(mouse), move(mouse), ungrab(mouse)" << eventItem1->eventList;
QCOMPARE(eventItem1->eventList.size(), 4);
@@ -822,7 +819,7 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable()
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseMove);
QCOMPARE(eventItem1->eventList.last().type, QEvent::UngrabMouse);
qCDebug(lcTests) << "expected filtered events: 2 TouchBegin and 3 TouchUpdate" << filteredEventList;
- QCOMPARE(filteredEventList.count(), 5);
+ QCOMPARE(filteredEventList.size(), 5);
}
// flickable should have the touchpoint grab: it no longer relies on synth-mouse
@@ -843,17 +840,17 @@ void tst_TouchMouse::buttonOnDelayedPressFlickable()
QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonRelease);
QCOMPARE(eventItem1->eventList.last().type, QEvent::UngrabMouse);
// QQuickWindow filters the delayed press and release
- QCOMPARE(filteredEventList.count(), 4);
- QCOMPARE(filteredEventList.at(filteredEventList.count() - 2).type, QEvent::TouchBegin);
+ QCOMPARE(filteredEventList.size(), 4);
+ QCOMPARE(filteredEventList.at(filteredEventList.size() - 2).type, QEvent::TouchBegin);
QCOMPARE(filteredEventList.last().type, QEvent::TouchEnd);
} else {
// QQuickWindow filters the delayed press if there was one
if (scrollBeforeDelayIsOver) {
qCDebug(lcTests) << "expected filtered events: 1 TouchBegin, 3 TouchUpdate, 1 TouchEnd" << filteredEventList;
- QCOMPARE(filteredEventList.count(), 5);
+ QCOMPARE(filteredEventList.size(), 5);
} else {
qCDebug(lcTests) << "expected filtered events: 2 TouchBegin, 3 TouchUpdate, 1 TouchEnd" << filteredEventList;
- QCOMPARE(filteredEventList.count(), 6);
+ QCOMPARE(filteredEventList.size(), 6);
QCOMPARE(filteredEventList.at(0).type, QEvent::TouchBegin);
QCOMPARE(filteredEventList.last().type, QEvent::TouchEnd);
}
@@ -968,7 +965,7 @@ void tst_TouchMouse::buttonOnTouch()
touchSeq.press(0, p1, &window).press(1, p2, &window).commit();
QQuickTouchUtils::flush(&window);
QCOMPARE(button1->scale(), 1);
- QCOMPARE(eventItem1->eventList.count(), 1);
+ QCOMPARE(eventItem1->eventList.size(), 1);
QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
p1 -= QPoint(10, 0);
@@ -1280,16 +1277,16 @@ void tst_TouchMouse::tapOnDismissiveTopMouseAreaClicksBottomOne()
QTest::touchEvent(&window, device).release(0, p1, &window);
QQuickTouchUtils::flush(&window);
- QCOMPARE(bottomClickedSpy.count(), 1);
- QCOMPARE(bottomDoubleClickedSpy.count(), 0);
+ QCOMPARE(bottomClickedSpy.size(), 1);
+ QCOMPARE(bottomDoubleClickedSpy.size(), 0);
QTest::touchEvent(&window, device).press(0, p1, &window);
QQuickTouchUtils::flush(&window);
QTest::touchEvent(&window, device).release(0, p1, &window);
QQuickTouchUtils::flush(&window);
- QCOMPARE(bottomClickedSpy.count(), 1);
- QCOMPARE(bottomDoubleClickedSpy.count(), 1);
+ QCOMPARE(bottomClickedSpy.size(), 1);
+ QCOMPARE(bottomDoubleClickedSpy.size(), 1);
}
/*
@@ -1443,6 +1440,7 @@ void tst_TouchMouse::hoverEnabled() // QTBUG-40856
QQuickView window;
QVERIFY(QQuickTest::showView(window, testFileUrl("hoverMouseAreas.qml")));
QQuickItem *root = window.rootObject();
+ auto deliveryAgent = QQuickWindowPrivate::get(&window)->deliveryAgentPrivate();
QQuickMouseArea *mouseArea1 = root->findChild<QQuickMouseArea*>("mouseArea1");
QVERIFY(mouseArea1 != nullptr);
@@ -1452,11 +1450,11 @@ void tst_TouchMouse::hoverEnabled() // QTBUG-40856
QSignalSpy enterSpy1(mouseArea1, SIGNAL(entered()));
QSignalSpy exitSpy1(mouseArea1, SIGNAL(exited()));
- QSignalSpy clickSpy1(mouseArea1, SIGNAL(clicked(QQuickMouseEvent *)));
+ QSignalSpy clickSpy1(mouseArea1, SIGNAL(clicked(QQuickMouseEvent*)));
QSignalSpy enterSpy2(mouseArea2, SIGNAL(entered()));
QSignalSpy exitSpy2(mouseArea2, SIGNAL(exited()));
- QSignalSpy clickSpy2(mouseArea2, SIGNAL(clicked(QQuickMouseEvent *)));
+ QSignalSpy clickSpy2(mouseArea2, SIGNAL(clicked(QQuickMouseEvent*)));
QPoint p1(150, 150);
QPoint p2(150, 250);
@@ -1464,54 +1462,60 @@ void tst_TouchMouse::hoverEnabled() // QTBUG-40856
// ------------------------- Mouse move to mouseArea1
QTest::mouseMove(&window, p1);
- QVERIFY(enterSpy1.count() == 1);
+ QVERIFY(enterSpy1.size() == 1);
QVERIFY(mouseArea1->hovered());
QVERIFY(!mouseArea2->hovered());
// ------------------------- Touch click on mouseArea1
QTest::touchEvent(&window, device).press(0, p1, &window);
+ deliveryAgent->flushFrameSynchronousEvents(&window);
- QCOMPARE(enterSpy1.count(), 1);
- QCOMPARE(enterSpy2.count(), 0);
- QVERIFY(mouseArea1->pressed());
+ QCOMPARE(enterSpy1.size(), 1);
+ QCOMPARE(enterSpy2.size(), 0);
+ QVERIFY(mouseArea1->isPressed());
QVERIFY(mouseArea1->hovered());
QVERIFY(!mouseArea2->hovered());
QTest::touchEvent(&window, device).release(0, p1, &window);
- QVERIFY(clickSpy1.count() == 1);
+ deliveryAgent->flushFrameSynchronousEvents(&window);
+ QVERIFY(clickSpy1.size() == 1);
QVERIFY(mouseArea1->hovered());
QVERIFY(!mouseArea2->hovered());
// ------------------------- Touch click on mouseArea2
QTest::touchEvent(&window, device).press(0, p2, &window);
+ deliveryAgent->flushFrameSynchronousEvents(&window);
- QVERIFY(mouseArea1->hovered());
+ QVERIFY(!mouseArea1->hovered());
QVERIFY(mouseArea2->hovered());
- QVERIFY(mouseArea2->pressed());
- QCOMPARE(enterSpy1.count(), 1);
- QCOMPARE(enterSpy2.count(), 1);
+ QVERIFY(mouseArea2->isPressed());
+ QCOMPARE(enterSpy1.size(), 1);
+ QCOMPARE(enterSpy2.size(), 1);
QTest::touchEvent(&window, device).release(0, p2, &window);
+ deliveryAgent->flushFrameSynchronousEvents(&window);
- QVERIFY(clickSpy2.count() == 1);
- QVERIFY(mouseArea1->hovered());
+ QVERIFY(clickSpy2.size() == 1);
+ QVERIFY(!mouseArea1->hovered());
QVERIFY(!mouseArea2->hovered());
- QCOMPARE(exitSpy1.count(), 0);
- QCOMPARE(exitSpy2.count(), 1);
+ QCOMPARE(exitSpy1.size(), 1);
+ QCOMPARE(exitSpy2.size(), 1);
// ------------------------- Another touch click on mouseArea1
QTest::touchEvent(&window, device).press(0, p1, &window);
+ deliveryAgent->flushFrameSynchronousEvents(&window);
- QCOMPARE(enterSpy1.count(), 1);
- QCOMPARE(enterSpy2.count(), 1);
- QVERIFY(mouseArea1->pressed());
+ QCOMPARE(enterSpy1.size(), 2);
+ QCOMPARE(enterSpy2.size(), 1);
+ QVERIFY(mouseArea1->isPressed());
QVERIFY(mouseArea1->hovered());
QVERIFY(!mouseArea2->hovered());
QTest::touchEvent(&window, device).release(0, p1, &window);
- QCOMPARE(clickSpy1.count(), 2);
+ deliveryAgent->flushFrameSynchronousEvents(&window);
+ QCOMPARE(clickSpy1.size(), 2);
QVERIFY(mouseArea1->hovered());
- QVERIFY(!mouseArea1->pressed());
+ QVERIFY(!mouseArea1->isPressed());
QVERIFY(!mouseArea2->hovered());
}
@@ -1545,6 +1549,117 @@ void tst_TouchMouse::implicitUngrab()
QCOMPARE(eventItem->eventList.at(0).type, QEvent::UngrabMouse);
QTest::touchEvent(&window, device).release(0, p1); // clean up potential state
}
+
+void tst_TouchMouse::touchCancelWillCancelMousePress()
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("singleitem.qml")));
+ QQuickItem *root = window.rootObject();
+ QVERIFY(root != nullptr);
+
+ EventItem *eventItem = root->findChild<EventItem*>("eventItem1");
+ eventItem->acceptMouse = true;
+ eventItem->setAcceptTouchEvents(false);
+ QPoint p1(20, 20);
+
+ // Begin a new touch, that gets converted to a mouse press
+ QTest::touchEvent(&window, device).press(0, p1);
+ QCOMPARE(eventItem->eventList.size(), 1);
+ QCOMPARE(eventItem->eventList.at(0).type, QEvent::MouseButtonPress);
+
+ // Cancel it...
+ QTouchEvent cancelEvent(QEvent::TouchCancel, device);
+ QCoreApplication::sendEvent(&window, &cancelEvent);
+ QCOMPARE(eventItem->eventList.size(), 3);
+ QCOMPARE(eventItem->eventList.at(1).type, QEvent::TouchCancel);
+ QCOMPARE(eventItem->eventList.at(2).type, QEvent::UngrabMouse);
+
+ // Begin a second touch. Since the last one was cancelled, this
+ // should end up as a new mouse press on the target item.
+ QTest::touchEvent(&window, device).press(0, p1);
+ QVERIFY(eventItem->eventList.size() >= 5);
+ QCOMPARE(eventItem->eventList.at(3).type, QEvent::MouseButtonPress);
+
+ QTest::touchEvent(&window, device).release(0, p1); // clean up potential state
+}
+
+void tst_TouchMouse::oneTouchInsideAndOneOutside() // QTBUG-102996
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("oneMouseArea.qml")));
+ QQuickItem *root = window.rootObject();
+ QVERIFY(root);
+ QQuickMouseArea *ma = root->findChild<QQuickMouseArea*>();
+ QVERIFY(ma);
+
+ // Press the MouseArea
+ QPoint p1 = ma->mapToScene(ma->boundingRect().center()).toPoint();
+ QTest::touchEvent(&window, device).press(1, p1);
+ QQuickTouchUtils::flush(&window);
+ QVERIFY(ma->isPressed());
+
+ // Tap outside the MouseArea with a second finger
+ QPoint p2(100, 100);
+ QTest::touchEvent(&window, device).stationary(1).press(2, p2);
+ QQuickTouchUtils::flush(&window);
+ QTest::touchEvent(&window, device).stationary(1).release(2, p2);
+ QQuickTouchUtils::flush(&window);
+ QVERIFY(ma->isPressed());
+
+ // Press again outside the MouseArea with a second finger
+ QTest::touchEvent(&window, device).stationary(1).press(2, p2);
+
+ // Release the first finger: MouseArea should be released
+ QTest::touchEvent(&window, device).release(1, p1).stationary(2);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(ma->isPressed(), false);
+
+ // Release the second finger
+ QTest::touchEvent(&window, device).release(2, p2);
+ QQuickTouchUtils::flush(&window);
+}
+
+void tst_TouchMouse::strayTouchDoesntAutograb() // QTBUG-107867
+{
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("singleitem.qml")));
+ QQuickItem *root = window.rootObject();
+ QVERIFY(root);
+ EventItem *eventItem = root->findChild<EventItem*>();
+ QVERIFY(eventItem);
+ // This item accepts (synth-)mouse events but NOT touch
+ eventItem->acceptMouse = true;
+ QCOMPARE(eventItem->acceptTouchEvents(), false); // the default in Qt 6
+ QPoint p1(6, 6);
+ grabMonitor.reset();
+
+ // Begin a new touch, that gets converted to a mouse press
+ QTest::touchEvent(&window, device).press(0, p1);
+ QQuickTouchUtils::flush(&window);
+ qCDebug(lcTests) << "after touch press:" << eventItem->eventList;
+ QCOMPARE(eventItem->eventList.size(), 1);
+ QCOMPARE(eventItem->eventList.at(0).type, QEvent::MouseButtonPress);
+ QCOMPARE(grabMonitor.exclusiveGrabber, eventItem);
+
+ // Drag
+ for (int i = 0; i < 3; ++i) {
+ QTest::touchEvent(&window, device).move(0, p1 + QPoint(i * 5, i * 5), &window);
+ QQuickTouchUtils::flush(&window);
+ QCOMPARE(grabMonitor.transitionCount, 1); // no new grab
+ QCOMPARE(eventItem->eventList.size(), i + 2);
+ QCOMPARE(eventItem->eventList.last().type, QEvent::MouseMove);
+ }
+
+ // Press an extra point: EventItem should see nothing
+ QTest::touchEvent(&window, device).stationary(0).press(1, p1);
+ QQuickTouchUtils::flush(&window);
+ qCDebug(lcTests) << "after press of second touchpoint:" << eventItem->eventList;
+ QCOMPARE(eventItem->eventList.size(), 4);
+ QCOMPARE(grabMonitor.transitionCount, 1); // no new grab
+
+ QTest::touchEvent(&window, device).release(0, p1).release(1, p1);
+}
+
QTEST_MAIN(tst_TouchMouse)
#include "tst_touchmouse.moc"