diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 14) set(REQUIRED_QT_VERSION "5.9.0") -find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Core Network Qml Quick Test Sql Multimedia Svg Gui Widgets) +find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Core Network Qml Quick Test Sql Multimedia Svg Gui Widgets QuickTest) set(REQUIRED_KF5_VERSION "5.32.0") find_package(ECM ${REQUIRED_KF5_VERSION} REQUIRED NO_MODULE) diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -440,3 +440,19 @@ target_include_directories(elisaapplicationtest PRIVATE ${CMAKE_SOURCE_DIR}/src) endif() + +if (Qt5Quick_FOUND AND Qt5Widgets_FOUND) + set(elisaqmltests_SOURCES + elisaqmltests.cpp + qmltests/tst_GridBrowserDelegate.qml + ) + + ecm_add_test(${elisaqmltests_SOURCES} + TEST_NAME "elisaqmltests" + LINK_LIBRARIES Qt5::Core Qt5::Widgets Qt5::Test Qt5::QuickTest + GUI) + + target_compile_definitions(elisaqmltests PRIVATE QUICK_TEST_SOURCE_DIR="${CMAKE_SOURCE_DIR}/autotests/qmltests") + + target_include_directories(elisaqmltests PRIVATE ${CMAKE_SOURCE_DIR}/src) +endif() diff --git a/autotests/elisaqmltests.cpp b/autotests/elisaqmltests.cpp new file mode 100644 --- /dev/null +++ b/autotests/elisaqmltests.cpp @@ -0,0 +1,22 @@ +/* + * Copyright 2018 Matthieu Gallien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include + +QUICK_TEST_MAIN(ElisaQmlTests) diff --git a/autotests/qmltests/tst_GridBrowserDelegate.qml b/autotests/qmltests/tst_GridBrowserDelegate.qml new file mode 100644 --- /dev/null +++ b/autotests/qmltests/tst_GridBrowserDelegate.qml @@ -0,0 +1,337 @@ +/* + * Copyright 2018 Matthieu Gallien + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.3 +import QtTest 1.0 +import "../../src" + +FocusScope { + GridBrowserDelegate { + id: delegateItem + + height: 160 + width: 100 + + shadowForImage: true + mainText: "hello" + secondaryText: "hello secondary" + + function i18nc() { + } + + Item { + id: myPalette + + property color text + } + + Item { + id: elisaTheme + } + } + + Item { + id: otherItem + + focus: true + + width: 50 + height: 50 + anchors.top: delegateItem.bottom + } + + TestCase { + name: "TestGridBrowserDelegate" + + SignalSpy { + id: enqueueSpy + target: delegateItem + signalName: "enqueue" + } + + SignalSpy { + id: replaceAndPlaySpy + target: delegateItem + signalName: "replaceAndPlay" + } + + SignalSpy { + id: openSpy + target: delegateItem + signalName: "open" + } + + SignalSpy { + id: selectedSpy + target: delegateItem + signalName: "selected" + } + + when: windowShown + + function init() { + otherItem.focus = true + enqueueSpy.clear(); + replaceAndPlaySpy.clear(); + openSpy.clear(); + selectedSpy.clear(); + } + + function test_focus() { + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 0); + compare(selectedSpy.count, 0); + compare(delegateItem.focus, false, "delegateItem.focus"); + + delegateItem.forceActiveFocus(); + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 0); + compare(selectedSpy.count, 0); + compare(delegateItem.focus, true, "delegateItem.focus"); + + var enqueueButtonItem = findChild(delegateItem, "enqueueButton"); + var openButtonItem = findChild(delegateItem, "openButton"); + var replaceAndPlayButtonItem = findChild(delegateItem, "replaceAndPlayButton"); + verify(enqueueButtonItem !== null, "valid enqueueButton") + verify(openButtonItem !== null, "valid openButton") + verify(replaceAndPlayButtonItem !== null, "valid replaceAndPlayButton") + + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + + keyClick(Qt.Key_Tab) + compare(enqueueSpy.count, 0) + compare(replaceAndPlaySpy.count, 0) + compare(openSpy.count, 0) + compare(selectedSpy.count, 0) + compare(delegateItem.focus, true, "delegateItem.focus"); + compare(enqueueButtonItem.focus, true, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + + keyClick(Qt.Key_Tab) + compare(enqueueSpy.count, 0) + compare(replaceAndPlaySpy.count, 0) + compare(openSpy.count, 0) + compare(selectedSpy.count, 0) + compare(delegateItem.focus, true, "delegateItem.focus"); + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, true, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + + keyClick(Qt.Key_Tab) + compare(enqueueSpy.count, 0) + compare(replaceAndPlaySpy.count, 0) + compare(openSpy.count, 0) + compare(selectedSpy.count, 0) + compare(delegateItem.focus, true, "delegateItem.focus"); + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, true, "enqueueButton.focus"); + + enqueueButtonItem.focus = false; + openButtonItem.focus = false; + replaceAndPlayButtonItem.focus = false; + otherItem.focus = true; + compare(enqueueSpy.count, 0) + compare(replaceAndPlaySpy.count, 0) + compare(openSpy.count, 0) + compare(selectedSpy.count, 0) + compare(delegateItem.focus, false, "delegateItem.focus"); + } + + function test_mouse_clicks() { + compare(delegateItem.focus, false, "delegateItem.focus"); + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 0); + compare(selectedSpy.count, 0); + + mouseMove(delegateItem, 0, 0); + compare(delegateItem.focus, false, "delegateItem.focus"); + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 0); + compare(selectedSpy.count, 0); + + var enqueueButtonItem = findChild(delegateItem, "enqueueButton"); + var openButtonItem = findChild(delegateItem, "openButton"); + var replaceAndPlayButtonItem = findChild(delegateItem, "replaceAndPlayButton"); + verify(enqueueButtonItem !== null, "valid enqueueButton") + verify(openButtonItem !== null, "valid openButton") + verify(replaceAndPlayButtonItem !== null, "valid replaceAndPlayButton") + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + + mouseClick(delegateItem, 0, 0); + compare(delegateItem.focus, false, "delegateItem.focus"); + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 0); + compare(selectedSpy.count, 1); + + mouseDoubleClickSequence(delegateItem, 0, 0); + openSpy.wait(150); + compare(delegateItem.focus, false, "delegateItem.focus"); + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 1); + compare(selectedSpy.count, 2); + + mouseMove(enqueueButtonItem); + mouseClick(enqueueButtonItem); + compare(delegateItem.focus, false, "delegateItem.focus"); + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + compare(enqueueSpy.count, 1); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 1); + compare(selectedSpy.count, 2); + + mouseMove(openButtonItem); + mouseClick(openButtonItem); + compare(delegateItem.focus, false, "delegateItem.focus"); + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + compare(enqueueSpy.count, 1); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 2); + compare(selectedSpy.count, 2); + + mouseMove(replaceAndPlayButtonItem); + mouseClick(replaceAndPlayButtonItem); + compare(delegateItem.focus, false, "delegateItem.focus"); + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + compare(enqueueSpy.count, 1); + compare(replaceAndPlaySpy.count, 1); + compare(openSpy.count, 2); + compare(selectedSpy.count, 2); + + mouseMove(otherItem, 0, 0); + compare(delegateItem.focus, false, "delegateItem.focus"); + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + compare(enqueueSpy.count, 1); + compare(replaceAndPlaySpy.count, 1); + compare(openSpy.count, 2); + compare(selectedSpy.count, 2); + + enqueueButtonItem.focus = false; + openButtonItem.focus = false; + replaceAndPlayButtonItem.focus = false; + otherItem.focus = true; + } + + function test_keyboard() { + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 0); + compare(selectedSpy.count, 0); + compare(delegateItem.focus, false, "delegateItem.focus"); + + delegateItem.forceActiveFocus(); + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 0); + compare(selectedSpy.count, 0); + compare(delegateItem.focus, true, "delegateItem.focus"); + + var enqueueButtonItem = findChild(delegateItem, "enqueueButton"); + var openButtonItem = findChild(delegateItem, "openButton"); + var replaceAndPlayButtonItem = findChild(delegateItem, "replaceAndPlayButton"); + verify(enqueueButtonItem !== null, "valid enqueueButton") + verify(openButtonItem !== null, "valid openButton") + verify(replaceAndPlayButtonItem !== null, "valid replaceAndPlayButton") + + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + + keyClick(Qt.Key_Tab); + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 0); + compare(selectedSpy.count, 0); + compare(delegateItem.focus, true, "delegateItem.focus"); + compare(enqueueButtonItem.focus, true, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + + keyClick(Qt.Key_Tab); + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 0); + compare(selectedSpy.count, 0); + compare(delegateItem.focus, true, "delegateItem.focus"); + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, true, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, false, "enqueueButton.focus"); + + keyClick(Qt.Key_Tab); + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 0); + compare(selectedSpy.count, 0); + compare(delegateItem.focus, true, "delegateItem.focus"); + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, true, "enqueueButton.focus"); + + keyClick(Qt.Key_Enter); + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 1); + compare(selectedSpy.count, 0); + compare(delegateItem.focus, true, "delegateItem.focus"); + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, true, "enqueueButton.focus"); + + keyClick(Qt.Key_Return); + compare(enqueueSpy.count, 0); + compare(replaceAndPlaySpy.count, 0); + compare(openSpy.count, 2); + compare(selectedSpy.count, 0); + compare(delegateItem.focus, true, "delegateItem.focus"); + compare(enqueueButtonItem.focus, false, "enqueueButton.focus"); + compare(openButtonItem.focus, false, "enqueueButton.focus"); + compare(replaceAndPlayButtonItem.focus, true, "enqueueButton.focus"); + + enqueueButtonItem.focus = false; + openButtonItem.focus = false; + replaceAndPlayButtonItem.focus = false; + otherItem.focus = true; + } + } +} diff --git a/src/qml/GridBrowserDelegate.qml b/src/qml/GridBrowserDelegate.qml --- a/src/qml/GridBrowserDelegate.qml +++ b/src/qml/GridBrowserDelegate.qml @@ -25,9 +25,7 @@ import QtQuick.Layouts 1.2 import QtGraphicalEffects 1.0 -import org.kde.elisa 1.0 - -Item { +FocusScope { id: gridEntry property var imageUrl @@ -66,8 +64,8 @@ onTriggered: replaceAndPlay(containerData) } - Keys.onReturnPressed: open() - Keys.onEnterPressed: open() + Keys.onReturnPressed: openAction.trigger(this) + Keys.onEnterPressed: openAction.trigger(this) ColumnLayout { anchors.fill: parent @@ -79,17 +77,15 @@ hoverEnabled: true acceptedButtons: Qt.LeftButton - focus: true Layout.preferredHeight: gridEntry.width * 0.85 + elisaTheme.layoutVerticalMargin * 0.5 + mainLabelSize.height + secondaryLabelSize.height Layout.fillWidth: true onClicked: { - hoverHandle.forceActiveFocus() gridEntry.selected() } - onDoubleClicked: open() + onDoubleClicked: openAction.trigger(this) TextMetrics { id: mainLabelSize @@ -115,8 +111,6 @@ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - focus: true - Loader { id: hoverLoader active: false @@ -130,6 +124,7 @@ ToolButton { id: enqueueButton + objectName: 'enqueueButton' action: enqueueAction @@ -139,6 +134,7 @@ ToolButton { id: openButton + objectName: 'openButton' action: openAction @@ -148,6 +144,7 @@ ToolButton { id: replaceAndPlayButton + objectName: 'replaceAndPlayButton' action: replaceAndPlayAction @@ -167,7 +164,7 @@ fillMode: Image.PreserveAspectFit smooth: true - source: gridEntry.imageUrl + source: (gridEntry.imageUrl !== undefined ? gridEntry.imageUrl : "") asynchronous: true