diff options
Diffstat (limited to 'tests')
14 files changed, 634 insertions, 33 deletions
diff --git a/tests/auto/corelib/platform/android/tst_android.cpp b/tests/auto/corelib/platform/android/tst_android.cpp index b4bb0323f8a..93d3f1102c9 100644 --- a/tests/auto/corelib/platform/android/tst_android.cpp +++ b/tests/auto/corelib/platform/android/tst_android.cpp @@ -251,6 +251,12 @@ void tst_Android::safeAreaWithWindowFlagsAndStates() QFETCH(Qt::WindowStates, windowStates); QFETCH(Qt::WindowFlags, windowFlags); + if ((QNativeInterface::QAndroidApplication::sdkVersion() > __ANDROID_API_V__) && + qgetenv("QTEST_ENVIRONMENT").split(' ').contains("ci") & + (!(windowFlags & Qt::ExpandedClientAreaHint) && + !(windowStates & Qt::WindowFullScreen))) + QSKIP("Normal fails on Android 16 (QTBUG-140846)."); + QWidget widget; QPalette palette = widget.palette(); palette.setColor(QPalette::Window, Qt::red); @@ -338,6 +344,10 @@ void tst_Android::safeAreaWithWindowFlagsAndStates() // QTBUG-107604 void tst_Android::testFullScreenDimensions() { + if ((QNativeInterface::QAndroidApplication::sdkVersion() > __ANDROID_API_V__) && + qgetenv("QTEST_ENVIRONMENT").split(' ').contains("ci") ) + QSKIP("Keep on failing on Android 16 (QTBUG-141712)."); + QJniObject activity = QNativeInterface::QAndroidApplication::context(); QVERIFY(activity.isValid()); diff --git a/tests/auto/other/android/deployment_settings/CMakeLists.txt b/tests/auto/other/android/deployment_settings/CMakeLists.txt index d4546c0ca94..ed373493f97 100644 --- a/tests/auto/other/android/deployment_settings/CMakeLists.txt +++ b/tests/auto/other/android/deployment_settings/CMakeLists.txt @@ -33,11 +33,11 @@ set_target_properties(${target} PROPERTIES my_package_source_dir "path/to/source/dir" my_libs_property "some/path/to/lib2.so;some/path/to/lib3.so" my_plugins_property "some/path/to/plugin2.so;some/path/to/plugin3.so" - - QT_ANDROID_SDK_BUILD_TOOLS_REVISION "23.0.2" + # Below build tools should match to minimum supported OS API level version + QT_ANDROID_SDK_BUILD_TOOLS_REVISION "28.0.3" QT_ANDROID_MIN_SDK_VERSION "1" QT_ANDROID_TARGET_SDK_VERSION "2" - QT_ANDROID_COMPILE_SDK_VERSION "35" + QT_ANDROID_COMPILE_SDK_VERSION "36" QT_ANDROID_APP_NAME "Android Deployment Settings Test" QT_ANDROID_PACKAGE_NAME "org.qtproject.android_deployment_settings_test" QT_ANDROID_DEPLOYMENT_DEPENDENCIES "dep1.so;dep2.so;dep3.so" @@ -62,10 +62,11 @@ qt6_policy(SET QTP0002 OLD) set(target tst_android_deployment_settings_old) qt6_add_executable(${target} MANUAL_FINALIZATION EXCLUDE_FROM_ALL noop.cpp) set_target_properties(${target} PROPERTIES - QT_ANDROID_SDK_BUILD_TOOLS_REVISION "23.0.2" + # Below build tools should match to minimum supported OS API level version + QT_ANDROID_SDK_BUILD_TOOLS_REVISION "28.0.3" QT_ANDROID_MIN_SDK_VERSION "1" QT_ANDROID_TARGET_SDK_VERSION "2" - QT_ANDROID_COMPILE_SDK_VERSION "35" + QT_ANDROID_COMPILE_SDK_VERSION "36" QT_ANDROID_APP_NAME "Android Deployment Settings Test" QT_ANDROID_PACKAGE_NAME "org.qtproject.android_deployment_settings_test" QT_ANDROID_DEPLOYMENT_DEPENDENCIES "dep1.so;dep2.so;dep3.so" diff --git a/tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp b/tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp index 03724b7a225..6eed5506324 100644 --- a/tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp +++ b/tests/auto/other/android/deployment_settings/tst_android_deployment_settings.cpp @@ -60,7 +60,7 @@ void tst_android_deployment_settings::DeploymentSettings_data() QTest::addColumn<QString>("value"); QTest::newRow("sdkBuildToolsRevision") << "sdkBuildToolsRevision" - << "23.0.2"; + << "28.0.3"; QTest::newRow("deployment-dependencies") << "deployment-dependencies" << "dep1.so,dep2.so,dep3.so"; QTest::newRow("android-extra-plugins") @@ -78,7 +78,7 @@ void tst_android_deployment_settings::DeploymentSettings_data() QTest::newRow("android-target-sdk-version") << "android-target-sdk-version" << "2"; QTest::newRow("android-compile-sdk-version") << "android-compile-sdk-version" - << "35"; + << "36"; QTest::newRow("android-package-name") << "android-package-name" << "org.qtproject.android_deployment_settings_test"; QTest::newRow("android-app-name") << "android-app-name" diff --git a/tests/auto/tools/rcc/data/deduplication/deduplication.expected b/tests/auto/tools/rcc/data/deduplication/deduplication.expected new file mode 100644 index 00000000000..bd873437b46 --- /dev/null +++ b/tests/auto/tools/rcc/data/deduplication/deduplication.expected @@ -0,0 +1,157 @@ +/**************************************************************************** +** Resource object code +** +IGNORE:** Created by: The Resource Compiler for Qt version 6.9.0 +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#ifdef _MSC_VER +// disable informational message "function ... selected for automatic inline expansion" +#pragma warning (disable: 4711) +#endif + +static const unsigned char qt_resource_data[] = { + // b.txt + 0x0,0x0,0x0,0xb, + 0x62, + 0x20,0x74,0x65,0x73,0x74,0x20,0x66,0x69,0x6c,0x65, + // c_with_a_content.txt + 0x0,0x0,0x0,0xb, + 0x61, + 0x20,0x74,0x65,0x73,0x74,0x20,0x66,0x69,0x6c,0x65, + // b.txt + 0x0,0x0,0x0,0xb, + 0x62, + 0x20,0x74,0x65,0x73,0x74,0x20,0x66,0x69,0x6c,0x65, + +}; + +static const unsigned char qt_resource_name[] = { + // files + 0x0,0x5, + 0x0,0x6d,0x2,0xc3, + 0x0,0x66, + 0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x73, + // b.txt + 0x0,0x5, + 0x0,0x65,0x5b,0xf4, + 0x0,0x62, + 0x0,0x2e,0x0,0x74,0x0,0x78,0x0,0x74, + // c_with_a_content.txt + 0x0,0x14, + 0x1,0x61,0x1d,0x34, + 0x0,0x63, + 0x0,0x5f,0x0,0x77,0x0,0x69,0x0,0x74,0x0,0x68,0x0,0x5f,0x0,0x61,0x0,0x5f,0x0,0x63,0x0,0x6f,0x0,0x6e,0x0,0x74,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x2e, + 0x0,0x74,0x0,0x78,0x0,0x74, + // a.txt + 0x0,0x5, + 0x0,0x64,0x5b,0xf4, + 0x0,0x61, + 0x0,0x2e,0x0,0x74,0x0,0x78,0x0,0x74, + // alias_of_b_compress9.txt + 0x0,0x18, + 0xb,0x26,0xf,0xb4, + 0x0,0x61, + 0x0,0x6c,0x0,0x69,0x0,0x61,0x0,0x73,0x0,0x5f,0x0,0x6f,0x0,0x66,0x0,0x5f,0x0,0x62,0x0,0x5f,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x70,0x0,0x72,0x0,0x65, + 0x0,0x73,0x0,0x73,0x0,0x39,0x0,0x2e,0x0,0x74,0x0,0x78,0x0,0x74, + // alias_of_b.txt + 0x0,0xe, + 0x1,0xa4,0x6d,0x34, + 0x0,0x61, + 0x0,0x6c,0x0,0x69,0x0,0x61,0x0,0x73,0x0,0x5f,0x0,0x6f,0x0,0x66,0x0,0x5f,0x0,0x62,0x0,0x2e,0x0,0x74,0x0,0x78,0x0,0x74, + // alias_of_b_compress9_dupe.txt + 0x0,0x1d, + 0x9,0x4,0x7a,0x14, + 0x0,0x61, + 0x0,0x6c,0x0,0x69,0x0,0x61,0x0,0x73,0x0,0x5f,0x0,0x6f,0x0,0x66,0x0,0x5f,0x0,0x62,0x0,0x5f,0x0,0x63,0x0,0x6f,0x0,0x6d,0x0,0x70,0x0,0x72,0x0,0x65, + 0x0,0x73,0x0,0x73,0x0,0x39,0x0,0x5f,0x0,0x64,0x0,0x75,0x0,0x70,0x0,0x65,0x0,0x2e,0x0,0x74,0x0,0x78,0x0,0x74, + +}; + +static const unsigned char qt_resource_struct[] = { + // : + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + // :/files + 0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x2, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + // :/files/a.txt + 0x0,0x0,0x0,0x4e,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xf, +TIMESTAMP:files/a.txt + // :/files/b.txt + 0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0, +TIMESTAMP:files/b.txt + // :/files/c_with_a_content.txt + 0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0xf, +TIMESTAMP:files/c_with_a_content.txt + // :/files/alias_of_b.txt + 0x0,0x0,0x0,0x94,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0, +TIMESTAMP:files/b.txt + // :/files/alias_of_b_compress9_dupe.txt + 0x0,0x0,0x0,0xb6,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1e, +TIMESTAMP:files/b.txt + // :/files/alias_of_b_compress9.txt + 0x0,0x0,0x0,0x5e,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1e, +TIMESTAMP:files/b.txt + +}; + +#ifdef QT_NAMESPACE +# define QT_RCC_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::name +# define QT_RCC_MANGLE_NAMESPACE0(x) x +# define QT_RCC_MANGLE_NAMESPACE1(a, b) a##_##b +# define QT_RCC_MANGLE_NAMESPACE2(a, b) QT_RCC_MANGLE_NAMESPACE1(a,b) +# define QT_RCC_MANGLE_NAMESPACE(name) QT_RCC_MANGLE_NAMESPACE2( \ + QT_RCC_MANGLE_NAMESPACE0(name), QT_RCC_MANGLE_NAMESPACE0(QT_NAMESPACE)) +#else +# define QT_RCC_PREPEND_NAMESPACE(name) name +# define QT_RCC_MANGLE_NAMESPACE(name) name +#endif + +#if defined(QT_INLINE_NAMESPACE) +inline namespace QT_NAMESPACE { +#elif defined(QT_NAMESPACE) +namespace QT_NAMESPACE { +#endif + +bool qRegisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *); +bool qUnregisterResourceData(int, const unsigned char *, const unsigned char *, const unsigned char *); + +#ifdef QT_NAMESPACE +} +#endif + +int QT_RCC_MANGLE_NAMESPACE(qInitResources)(); +int QT_RCC_MANGLE_NAMESPACE(qInitResources)() +{ + int version = 3; + QT_RCC_PREPEND_NAMESPACE(qRegisterResourceData) + (version, qt_resource_struct, qt_resource_name, qt_resource_data); + return 1; +} + +int QT_RCC_MANGLE_NAMESPACE(qCleanupResources)(); +int QT_RCC_MANGLE_NAMESPACE(qCleanupResources)() +{ + int version = 3; + QT_RCC_PREPEND_NAMESPACE(qUnregisterResourceData) + (version, qt_resource_struct, qt_resource_name, qt_resource_data); + return 1; +} + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wexit-time-destructors" +#endif + +namespace { + struct initializer { + initializer() { QT_RCC_MANGLE_NAMESPACE(qInitResources)(); } + ~initializer() { QT_RCC_MANGLE_NAMESPACE(qCleanupResources)(); } + } dummy; +} + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif diff --git a/tests/auto/tools/rcc/data/deduplication/deduplication.qrc b/tests/auto/tools/rcc/data/deduplication/deduplication.qrc new file mode 100644 index 00000000000..fd8a776503e --- /dev/null +++ b/tests/auto/tools/rcc/data/deduplication/deduplication.qrc @@ -0,0 +1,10 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>files/a.txt</file> + <file>files/b.txt</file> + <file alias="files/alias_of_b.txt">files/b.txt</file> + <file>files/c_with_a_content.txt</file> + <file alias="files/alias_of_b_compress9.txt" compress="9">files/b.txt</file> + <file alias="files/alias_of_b_compress9_dupe.txt" compress="9">files/b.txt</file> +</qresource> +</RCC> diff --git a/tests/auto/tools/rcc/data/deduplication/files/a.txt b/tests/auto/tools/rcc/data/deduplication/files/a.txt new file mode 100644 index 00000000000..abd91bd4652 --- /dev/null +++ b/tests/auto/tools/rcc/data/deduplication/files/a.txt @@ -0,0 +1 @@ +a test file
\ No newline at end of file diff --git a/tests/auto/tools/rcc/data/deduplication/files/b.txt b/tests/auto/tools/rcc/data/deduplication/files/b.txt new file mode 100644 index 00000000000..01e4d76fc57 --- /dev/null +++ b/tests/auto/tools/rcc/data/deduplication/files/b.txt @@ -0,0 +1 @@ +b test file
\ No newline at end of file diff --git a/tests/auto/tools/rcc/data/deduplication/files/c_with_a_content.txt b/tests/auto/tools/rcc/data/deduplication/files/c_with_a_content.txt new file mode 100644 index 00000000000..abd91bd4652 --- /dev/null +++ b/tests/auto/tools/rcc/data/deduplication/files/c_with_a_content.txt @@ -0,0 +1 @@ +a test file
\ No newline at end of file diff --git a/tests/auto/tools/rcc/tst_rcc.cpp b/tests/auto/tools/rcc/tst_rcc.cpp index f5edfbcaa51..ba7e5841185 100644 --- a/tests/auto/tools/rcc/tst_rcc.cpp +++ b/tests/auto/tools/rcc/tst_rcc.cpp @@ -152,6 +152,11 @@ void tst_rcc::rcc_data() QTest::newRow("legal") << m_dataPath + QLatin1StringView("/legal") << "legal.qrc" << "rcc_legal.cpp"; + + if (sizeof(size_t) == 8) { + const QString deduplicationPath = m_dataPath + QLatin1String("/deduplication"); + QTest::newRow("deduplication") << deduplicationPath << "deduplication.qrc" << "deduplication.expected"; + } } static QStringList readLinesFromFile(const QString &fileName, diff --git a/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp b/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp index febb9e2c9dc..255bcaa5bec 100644 --- a/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp +++ b/tests/auto/widgets/kernel/qgesturerecognizer/tst_qgesturerecognizer.cpp @@ -9,11 +9,14 @@ #include <QtGui/QScreen> #include <QtGui/QPointingDevice> #include <QtCore/QList> +#include <QtCore/QLoggingCategory> #include <QtCore/QString> #include <QtCore/QHash> #include <QtCore/QDebug> #include <memory> +Q_LOGGING_CATEGORY(lcTests, "qt.widgets.tests") + class tst_QGestureRecognizer : public QObject { Q_OBJECT @@ -60,14 +63,30 @@ public: bool gestureReceived(Qt::GestureType gestureType) const { return m_receivedGestures.value(gestureType); } -protected: - bool event(QEvent * event) override; + void clearReceivedGestures(); -private: - typedef QHash<Qt::GestureType, bool> GestureTypeHash; - GestureTypeHash m_receivedGestures; + qreal lastSwipeAngle = 0; + QSwipeGesture::SwipeDirection lastHorizontalDirection = QSwipeGesture::NoDirection; + QSwipeGesture::SwipeDirection lastVerticalDirection = QSwipeGesture::NoDirection; + Qt::GestureState lastSwipeState = Qt::NoGesture; + + protected: + bool event(QEvent *event) override; + + private: + typedef QHash<Qt::GestureType, bool> GestureTypeHash; + GestureTypeHash m_receivedGestures; }; +void TestWidget::clearReceivedGestures() +{ + m_receivedGestures.clear(); + lastSwipeAngle = {}; + lastHorizontalDirection = QSwipeGesture::NoDirection; + lastVerticalDirection = QSwipeGesture::NoDirection; + lastSwipeState = Qt::NoGesture; +} + TestWidget::TestWidget(const GestureTypeVector &gestureTypes) { setAttribute(Qt::WA_AcceptTouchEvents); @@ -95,8 +114,22 @@ bool TestWidget::event(QEvent * event) it.value() = true; } } - } + for (const QGesture *gesture : gestureEvent->activeGestures()) { + switch (gesture->gestureType()) { + case Qt::SwipeGesture: { + const auto *swipe = static_cast<const QSwipeGesture *>(gesture); + lastSwipeAngle = swipe->swipeAngle(); + lastHorizontalDirection = swipe->horizontalDirection(); + lastVerticalDirection = swipe->verticalDirection(); + lastSwipeState = gesture->state(); + break; + } + default: + break; + } + } break; + } default: break; } @@ -241,10 +274,26 @@ enum SwipeSubTest { void tst_QGestureRecognizer::swipeGesture_data() { QTest::addColumn<int>("swipeSubTest"); + QTest::addColumn<QPoint>("moveDelta"); QTest::addColumn<bool>("gestureExpected"); - QTest::newRow("Line") << int(SwipeLineSubTest) << true; - QTest::newRow("DirectionChange") << int(SwipeDirectionChangeSubTest) << false; - QTest::newRow("SmallDirectionChange") << int(SwipeSmallDirectionChangeSubTest) << true; + QTest::addColumn<int>("expectedAngle"); + QTest::addColumn<QSwipeGesture::SwipeDirection>("expectedHorizontalDirection"); + QTest::addColumn<QSwipeGesture::SwipeDirection>("expectedVerticalDirection"); + + QTest::newRow("UpRight Line") << int(SwipeLineSubTest) << QPoint(42, -25) + << true << 30 << QSwipeGesture::Right << QSwipeGesture::Up; + QTest::newRow("DownRight Line") << int(SwipeLineSubTest) << QPoint(42, 25) + << true << 329 << QSwipeGesture::Right << QSwipeGesture::Down; + QTest::newRow("OutRight Line") << int(SwipeLineSubTest) << QPoint(42, 0) + << true << 360 << QSwipeGesture::Right << QSwipeGesture::NoDirection; + QTest::newRow("DownLeft Line") << int(SwipeLineSubTest) << QPoint(-42, 25) + << true << 211 << QSwipeGesture::Left << QSwipeGesture::Down; + QTest::newRow("Up Line") << int(SwipeLineSubTest) << QPoint(0, -25) + << true << 90 << QSwipeGesture::NoDirection << QSwipeGesture::Up; + QTest::newRow("DirectionChange") << int(SwipeDirectionChangeSubTest) << QPoint(42, 25) + << false << 0 << QSwipeGesture::NoDirection << QSwipeGesture::NoDirection; + QTest::newRow("SmallDirectionChange") << int(SwipeSmallDirectionChangeSubTest) << QPoint(42, -25) + << true << 359 << QSwipeGesture::Right << QSwipeGesture::Down; } void tst_QGestureRecognizer::swipeGesture() @@ -252,7 +301,11 @@ void tst_QGestureRecognizer::swipeGesture() enum { swipePoints = 3 }; QFETCH(int, swipeSubTest); + QFETCH(QPoint, moveDelta); QFETCH(bool, gestureExpected); + QFETCH(int, expectedAngle); + QFETCH(QSwipeGesture::SwipeDirection, expectedHorizontalDirection); + QFETCH(QSwipeGesture::SwipeDirection, expectedVerticalDirection); const Qt::GestureType gestureType = Qt::SwipeGesture; TestWidget widget(GestureTypeVector(1, gestureType)); @@ -264,20 +317,27 @@ void tst_QGestureRecognizer::swipeGesture() // Start a swipe sequence with 2 points (QTBUG-15768) const QPoint fingerDistance(m_fingerDistance, m_fingerDistance); QList<QPoint> points; - for (int i = 0; i < swipePoints - 1; ++i) + for (int i = 1; i < swipePoints; ++i) points.append(fingerDistance + i * fingerDistance); QTest::QTouchEventWidgetSequence swipeSequence = QTest::touchEvent(&widget, m_touchDevice.get()); pressSequence(swipeSequence, points, &widget); + // Move a little: nothing happens + points[0] += {1, 1}; + points[1] += {1, 1}; + swipeSequence.move(0, points[0], &widget).move(1, points[1], &widget).commit(); + QCoreApplication::processEvents(); + QVERIFY(!widget.gestureReceived(gestureType)); + // Press point #3 points.append(points.last() + fingerDistance); swipeSequence.stationary(0).stationary(1).press(points.size() - 1, points.last(), &widget); swipeSequence.commit(); Q_ASSERT(points.size() == swipePoints); + QCOMPARE(widget.lastSwipeState, Qt::NoGesture); // Move. - const QPoint moveDelta(60, 20); switch (swipeSubTest) { case SwipeLineSubTest: linearSequence(5, moveDelta, swipeSequence, points, &widget); @@ -294,15 +354,37 @@ void tst_QGestureRecognizer::swipeGesture() } break; } + QCOMPARE(widget.lastSwipeState, Qt::GestureUpdated); - releaseSequence(swipeSequence, points, &widget); - + // release any point: the gesture ends + swipeSequence.release(0, points[0], &widget).commit(); if (gestureExpected) { QTRY_VERIFY(widget.gestureReceived(gestureType)); + qCDebug(lcTests) << "started @" << fingerDistance + << "; ended with angle" << widget.lastSwipeAngle + << "expected" << expectedAngle + << "dirns" << widget.lastHorizontalDirection << widget.lastVerticalDirection; + QCOMPARE(qRound(widget.lastSwipeAngle), expectedAngle); + QEXPECT_FAIL("Up Line", "90 degrees (up) should be NoDirection on horizontal axis", Continue); + QCOMPARE(widget.lastHorizontalDirection, expectedHorizontalDirection); + QEXPECT_FAIL("OutRight Line", "0 degrees (to the right) should be NoDirection on the vertical axis", Continue); + QCOMPARE(widget.lastVerticalDirection, expectedVerticalDirection); + QCOMPARE(widget.lastSwipeState, Qt::GestureFinished); } else { QCoreApplication::processEvents(); QVERIFY(!widget.gestureReceived(gestureType)); + QCOMPARE(widget.lastSwipeState, Qt::GestureUpdated); } + + // move the others a little, then release: no further swipe (it needs 3 fingers) + widget.clearReceivedGestures(); + points[1] += {1, 1}; + points[2] += {1, 1}; + swipeSequence.move(1, points[1], &widget).move(2, points[2], &widget).commit(); + swipeSequence.release(1, points[1], &widget).release(2, points[2], &widget).commit(); + QCoreApplication::processEvents(); + QVERIFY(!widget.gestureReceived(gestureType)); + QCOMPARE(widget.lastSwipeState, Qt::NoGesture); } void tst_QGestureRecognizer::touchReplay() diff --git a/tests/manual/wasm/localfiles/main.cpp b/tests/manual/wasm/localfiles/main.cpp index 862bff50a47..90e8c2e90f6 100644 --- a/tests/manual/wasm/localfiles/main.cpp +++ b/tests/manual/wasm/localfiles/main.cpp @@ -5,6 +5,81 @@ #include <emscripten/val.h> #include <emscripten.h> +class DropZone : public QLabel +{ + Q_OBJECT +public: + explicit DropZone(QWidget *parent = nullptr) : QLabel(parent) + { + setAcceptDrops(true); + setFrameStyle(QFrame::Box | QFrame::Sunken); + setAlignment(Qt::AlignCenter); + setText("Drop files here\n(will read first file)"); + setMinimumSize(400, 150); + setStyleSheet("QLabel { background-color: #f0f0f0; border: 2px dashed #999; padding: 20px; }"); + } + +Q_SIGNALS: + void filesDropped(const QList<QUrl> &urls); + +protected: + void dragEnterEvent(QDragEnterEvent *event) override + { + if (event->mimeData()->hasUrls()) { + event->acceptProposedAction(); + setStyleSheet("QLabel { background-color: #e0f0ff; border: 2px dashed #0066cc; padding: 20px; }"); + } + } + + void dragLeaveEvent(QDragLeaveEvent *event) override + { + Q_UNUSED(event); + setStyleSheet("QLabel { background-color: #f0f0f0; border: 2px dashed #999; padding: 20px; }"); + } + + void dropEvent(QDropEvent *event) override + { + const QMimeData *mimeData = event->mimeData(); + + if (mimeData->hasUrls()) { + QList<QUrl> urls = mimeData->urls(); + + qDebug() << "=== Files Dropped ==="; + qDebug() << "Number of files:" << urls.size(); + + for (int i = 0; i < urls.size(); ++i) { + const QUrl &url = urls.at(i); + qDebug() << "\n--- File" << (i + 1) << "---"; + qDebug() << "URL:" << url; + qDebug() << "URL toString:" << url.toString(); + qDebug() << "URL scheme:" << url.scheme(); + qDebug() << "URL path:" << url.path(); + qDebug() << "URL fileName:" << url.fileName(); + qDebug() << "isLocalFile:" << url.isLocalFile(); + + if (url.isLocalFile()) { + QString filePath = url.toLocalFile(); + qDebug() << "Local file path:" << filePath; + + QFileInfo fileInfo(filePath); + qDebug() << "File name:" << fileInfo.fileName(); + qDebug() << "File size:" << fileInfo.size(); + qDebug() << "File exists:" << fileInfo.exists(); + qDebug() << "Is readable:" << fileInfo.isReadable(); + qDebug() << "Absolute path:" << fileInfo.absoluteFilePath(); + qDebug() << "Last modified:" << fileInfo.lastModified().toString(); + } + } + qDebug() << "===================\n"; + + event->acceptProposedAction(); + emit filesDropped(urls); + } + + setStyleSheet("QLabel { background-color: #f0f0f0; border: 2px dashed #999; padding: 20px; }"); + } +}; + class AppWindow : public QObject { Q_OBJECT @@ -12,21 +87,39 @@ public: AppWindow() : m_layout(new QVBoxLayout(&m_loadFileUi)), m_window(emscripten::val::global("window")), m_showOpenFilePickerFunction(m_window["showOpenFilePicker"]), - m_showSaveFilePickerFunction(m_window["showSaveFilePicker"]) + m_showSaveFilePickerFunction(m_window["showSaveFilePicker"]), + m_fileDialog(new QFileDialog(&m_loadFileUi)), + m_isLoadOperation(true) { - addWidget<QLabel>("Filename filter"); - const bool localFileApiAvailable = !m_showOpenFilePickerFunction.isUndefined() && !m_showSaveFilePickerFunction.isUndefined(); m_useLocalFileApisCheckbox = addWidget<QCheckBox>("Use the window.showXFilePicker APIs"); m_useLocalFileApisCheckbox->setEnabled(localFileApiAvailable); m_useLocalFileApisCheckbox->setChecked(localFileApiAvailable); + connect(m_useLocalFileApisCheckbox, &QCheckBox::toggled, + std::bind(&AppWindow::onUseLocalFileApisCheckboxToggled, this)); + + m_useStandardFileDialogCheckbox = addWidget<QCheckBox>("Use standard QFileDialog API"); + connect(m_useStandardFileDialogCheckbox, &QCheckBox::toggled, + std::bind(&AppWindow::onUseStandardFileDialogCheckboxToggled, this)); + m_useStandardFileDialogCheckbox->setChecked(true); + + m_useExecModeCheckbox = addWidget<QCheckBox>("Use exec() instead of open()"); + m_useExecModeCheckbox->setChecked(false); + + addWidget<QLabel>("Filename filter"); - m_filterEdit = addWidget<QLineEdit>("Images (*.png *.jpg);;PDF (*.pdf);;*.txt"); + m_filterCombo = addWidget<QComboBox>(); + m_filterCombo->addItem("*"); + m_filterCombo->addItem("Images (*.png *.jpg);;PDF (*.pdf);;*.txt"); + m_filterCombo->setCurrentIndex(0); // Make "*" the default auto* loadFile = addWidget<QPushButton>("Load File"); + m_dropZone = addWidget<DropZone>(); + connect(m_dropZone, &DropZone::filesDropped, this, &AppWindow::onFilesDropped); + m_fileInfo = addWidget<QLabel>("Opened file:"); m_fileInfo->setTextInteractionFlags(Qt::TextSelectableByMouse); @@ -43,11 +136,13 @@ public: m_loadFileUi.setLayout(m_layout); - QObject::connect(m_useLocalFileApisCheckbox, &QCheckBox::toggled, std::bind(&AppWindow::onUseLocalFileApisCheckboxToggled, this)); QObject::connect(loadFile, &QPushButton::clicked, this, &AppWindow::onLoadClicked); - QObject::connect(m_saveFile, &QPushButton::clicked, std::bind(&AppWindow::onSaveClicked, this)); + + // Connect to both fileSelected and accepted signals for compatibility + QObject::connect(m_fileDialog, &QFileDialog::fileSelected, this, &AppWindow::onFileSelected); + QObject::connect(m_fileDialog, &QFileDialog::accepted, this, &AppWindow::onDialogAccepted); } void show() { @@ -67,6 +162,29 @@ private Q_SLOTS: m_showSaveFilePickerFunction : emscripten::val::undefined()); } + void onUseStandardFileDialogCheckboxToggled() + { + m_useLocalFileApisCheckbox->setChecked(m_useStandardFileDialogCheckbox->isChecked()); + } + + void onFilesDropped(const QList<QUrl> &urls) + { + if (urls.isEmpty()) + return; + + // Load the first dropped file + const QUrl &url = urls.first(); + + if (url.isLocalFile()) { + QString filePath = url.toLocalFile(); + loadFileWithQFile(filePath); + } else { + // Try using the URL string directly for non-file:// URLs (like weblocalfile://) + QString urlString = url.toString(); + loadFileWithQFile(urlString); + } + } + void onFileContentReady(const QString &fileName, const QByteArray &fileContents) { m_fileContent = fileContents; @@ -89,16 +207,108 @@ private Q_SLOTS: void onLoadClicked() { - QFileDialog::getOpenFileContent( - m_filterEdit->text(), - std::bind(&AppWindow::onFileContentReady, this, std::placeholders::_1, std::placeholders::_2), - &m_loadFileUi); + if (m_useStandardFileDialogCheckbox->isChecked()) { + m_isLoadOperation = true; + m_fileDialog->setFileMode(QFileDialog::ExistingFile); + m_fileDialog->setAcceptMode(QFileDialog::AcceptOpen); + m_fileDialog->setNameFilter(m_filterCombo->currentText()); + m_fileDialog->setWindowTitle("Open File"); + + if (m_useExecModeCheckbox->isChecked()) { + qDebug() << "Using exec() mode"; + int result = m_fileDialog->exec(); + if (result == QDialog::Accepted) { + QStringList files = m_fileDialog->selectedFiles(); + if (!files.isEmpty()) { + onFileSelected(files.first()); + } + } + } else { + qDebug() << "Using open() mode"; + m_fileDialog->open(); + } + } else { + QFileDialog::getOpenFileContent( + m_filterCombo->currentText(), + std::bind(&AppWindow::onFileContentReady, this, std::placeholders::_1, std::placeholders::_2), + &m_loadFileUi); + } } void onSaveClicked() { - m_fileInfo->setText("Saving file... (no result information with current API)"); - QFileDialog::saveFileContent(m_fileContent, m_savedFileNameEdit->text()); + if (m_useStandardFileDialogCheckbox->isChecked()) { + m_isLoadOperation = false; + m_fileDialog->setFileMode(QFileDialog::AnyFile); + m_fileDialog->setAcceptMode(QFileDialog::AcceptSave); + m_fileDialog->setNameFilter(m_filterCombo->currentText()); + m_fileDialog->setWindowTitle("Save File"); + m_fileDialog->selectFile(m_savedFileNameEdit->text()); + + if (m_useExecModeCheckbox->isChecked()) { + qDebug() << "Using exec() mode for save"; + int result = m_fileDialog->exec(); + if (result == QDialog::Accepted) { + QStringList files = m_fileDialog->selectedFiles(); + if (!files.isEmpty()) { + onFileSelected(files.first()); + } + } + } else { + qDebug() << "Using open() mode for save"; + m_fileDialog->open(); + } + } else { + m_fileInfo->setText("Saving file... (no result information with current API)"); + QFileDialog::saveFileContent(m_fileContent, m_savedFileNameEdit->text()); + } + } + + void onDialogAccepted() + { + QStringList files = m_fileDialog->selectedFiles(); + if (!files.isEmpty()) { + onFileSelected(files.first()); + } + } + + void onFileSelected(const QString &fileName) + { + qDebug() << "onFileSelected" << fileName; + + if (m_isLoadOperation) { + loadFileWithQFile(fileName); + } else { + saveFileWithQFile(fileName); + } + } + + void loadFileWithQFile(const QString &fileName) + { + qDebug() << "loadFileWithQFile" << fileName; + + QFile file(fileName); + if (file.open(QIODevice::ReadOnly)) { + qDebug() << "loadFileWithQFile" << fileName; + QByteArray fileContents = file.readAll(); + file.close(); + onFileContentReady(QFileInfo(fileName).fileName(), fileContents); + } else { + m_fileInfo->setText(QString("Failed to open file: %1").arg(file.errorString())); + } + } + + void saveFileWithQFile(const QString &fileName) + { + QFile file(fileName); + if (file.open(QIODevice::WriteOnly)) { + qint64 bytesWritten = file.write(m_fileContent); + file.close(); + bool success = (bytesWritten == m_fileContent.size()); + m_fileInfo->setText(QString("File save result: %1").arg(success ? "success" : "failed")); + } else { + m_fileInfo->setText(QString("Failed to save file: %1").arg(file.errorString())); + } } private: @@ -113,7 +323,10 @@ private: QWidget m_loadFileUi; QCheckBox* m_useLocalFileApisCheckbox; - QLineEdit* m_filterEdit; + QCheckBox* m_useStandardFileDialogCheckbox; + QCheckBox* m_useExecModeCheckbox; + DropZone* m_dropZone; + QComboBox* m_filterCombo; QVBoxLayout *m_layout; QLabel* m_fileInfo; QLabel* m_fileHash; @@ -124,6 +337,9 @@ private: emscripten::val m_showOpenFilePickerFunction; emscripten::val m_showSaveFilePickerFunction; + QFileDialog* m_fileDialog; + bool m_isLoadOperation; + QByteArray m_fileContent; }; diff --git a/tests/manual/widgets/itemviews/CMakeLists.txt b/tests/manual/widgets/itemviews/CMakeLists.txt index 4a67078103c..bae613b4fb9 100644 --- a/tests/manual/widgets/itemviews/CMakeLists.txt +++ b/tests/manual/widgets/itemviews/CMakeLists.txt @@ -5,3 +5,4 @@ add_subdirectory(qheaderview) add_subdirectory(qtreeview) add_subdirectory(qtreewidget) add_subdirectory(tableview-span-navigation) +add_subdirectory(qtablewidget-sort-indicator) diff --git a/tests/manual/widgets/itemviews/qtablewidget-sort-indicator/CMakeLists.txt b/tests/manual/widgets/itemviews/qtablewidget-sort-indicator/CMakeLists.txt new file mode 100644 index 00000000000..9d1ef6e7931 --- /dev/null +++ b/tests/manual/widgets/itemviews/qtablewidget-sort-indicator/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## qtablewidget-sort-indicator Binary: +##################################################################### + +qt_internal_add_manual_test(qtablewidget-sort-indicator + GUI + SOURCES + main.cpp + LIBRARIES + Qt::CorePrivate + Qt::Gui + Qt::Widgets +) diff --git a/tests/manual/widgets/itemviews/qtablewidget-sort-indicator/main.cpp b/tests/manual/widgets/itemviews/qtablewidget-sort-indicator/main.cpp new file mode 100644 index 00000000000..b3464c67c89 --- /dev/null +++ b/tests/manual/widgets/itemviews/qtablewidget-sort-indicator/main.cpp @@ -0,0 +1,100 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QApplication> +#include <QTableWidget> +#include <QHeaderView> +#include <QVBoxLayout> +#include <QGroupBox> +#include <QRadioButton> +#include <QLabel> + +QString createStyleSheet(const char *sortArrowPos) +{ + QString styleSheet {R"( + QHeaderView::section { + background-color: #f0f0f0; + padding: 5px; + border: 1px solid #ffffff; + font-weight: bold; + } + + QHeaderView::up-arrow, QHeaderView::down-arrow { + width: 24px; + height: 24px; + subcontrol-position: %1; + subcontrol-origin: padding; + } + )"}; + + return styleSheet.arg(sortArrowPos); +} + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + + QWidget mainWidget; + mainWidget.setWindowTitle("QTableWidget sort indicator overlap with clipping"); + + const QStringList headerLabels { "Header", "LongHeaderText"}; + const QStringList column1 { "Alpha", "Beta", "Gamma" }; + const QStringList column2 { "1", "2", "3" }; + + QTableWidget tableWidget(3, 2, &mainWidget); + tableWidget.setHorizontalHeaderLabels(headerLabels); + + for (int i {0} ; i < column1.size() ; ++i) { + tableWidget.setItem(i, 0, new QTableWidgetItem(column1[i])); + tableWidget.setItem(i, 1, new QTableWidgetItem(column2[i])); + } + + tableWidget.setSortingEnabled(true); + tableWidget.setStyleSheet(createStyleSheet("center right")); + tableWidget.adjustSize(); + + QVBoxLayout mainLayout {&mainWidget}; + QGroupBox buttonBox; + QVBoxLayout buttonLayout {&buttonBox}; + QRadioButton leftButton {"Left-aligned sort indicator"}; + QRadioButton centerButton {"Center-aligned sort indicator"}; + QRadioButton rightButton {"Right-aligned sort indicator"}; + + buttonLayout.addWidget(&leftButton); + buttonLayout.addWidget(¢erButton); + buttonLayout.addWidget(&rightButton); + + mainLayout.addWidget(&tableWidget); + mainLayout.addWidget(&buttonBox); + + QLabel instructions { QT_TR_NOOP(R"(<html>Instructions: +<ol> +<li>There are 3 options for alignment of the column header sort arrow: left, center, and right. Click one of the 3 radio buttons to select the sort arrow alignment. +</li> +<li>Click the left column header to sort the table. The sort arrow should appear at its correct alignment without overlapping the text. +</li> +<li>Click the right column header. The sort arrow should appear at its correct alignment. The left and right alignment should clip the text without changing its position. The center alignment should not clip the text at all. +</ol> + </html>)")}; + instructions.setTextFormat(Qt::AutoText); + instructions.setWordWrap(true); + mainLayout.addWidget(&instructions); + + QObject::connect(&leftButton, &QRadioButton::clicked, &app, [&](bool checked) { + if (checked) + tableWidget.setStyleSheet(createStyleSheet("center left")); + }); + QObject::connect(¢erButton, &QRadioButton::clicked, &app, [&](bool checked) { + if (checked) + tableWidget.setStyleSheet(createStyleSheet("top center")); + }); + QObject::connect(&rightButton, &QRadioButton::clicked, &app, [&](bool checked) { + if (checked) + tableWidget.setStyleSheet(createStyleSheet("center right")); + }); + + leftButton.click(); + mainWidget.show(); + + return app.exec(); +} |
