summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/CMakeLists.txt13
-rw-r--r--src/corelib/configure.cmake2
-rw-r--r--src/corelib/io/qrandomaccessasyncfile_darwin.mm728
-rw-r--r--src/corelib/io/qrandomaccessasyncfile_p_p.h112
-rw-r--r--src/corelib/kernel/qobject.cpp39
-rw-r--r--src/corelib/platform/android/qandroidnativeinterface.cpp5
-rw-r--r--src/corelib/time/qtimezoneprivate.cpp6
-rw-r--r--src/corelib/time/qtimezoneprivate_p.h2
-rw-r--r--src/corelib/tools/qhashfunctions.h4
-rw-r--r--src/corelib/tools/qlist.h7
-rw-r--r--src/gui/kernel/qguiapplication.cpp10
-rw-r--r--src/gui/kernel/qwindow.cpp6
-rw-r--r--src/gui/painting/qpainterpath.cpp11
-rw-r--r--src/gui/platform/darwin/qappleiconengine.mm188
-rw-r--r--src/gui/platform/darwin/qapplekeymapper.mm153
-rw-r--r--src/network/kernel/qhostaddress.cpp7
-rw-r--r--src/network/kernel/qhostaddress_p.h8
-rw-r--r--src/network/kernel/qnetworkinformation.cpp1
-rw-r--r--src/network/socket/qnativesocketengine_unix.cpp22
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm3
-rw-r--r--src/plugins/platforms/ios/qiosdocumentpickercontroller.mm13
-rw-r--r--src/plugins/platforms/wasm/qwasminputcontext.cpp4
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style.cpp7
-rw-r--r--src/testlib/qtestcase.h2
-rw-r--r--src/testlib/qtestregistry_p.h2
-rw-r--r--src/tools/macdeployqt/macdeployqt/main.cpp8
-rw-r--r--src/tools/macdeployqt/shared/shared.cpp1
-rw-r--r--src/widgets/doc/images/designer-stylesheet-options.pngbin18914 -> 0 bytes
-rw-r--r--src/widgets/doc/images/designer-stylesheet-options.webpbin0 -> 20214 bytes
-rw-r--r--src/widgets/doc/images/designer-stylesheet-usage.pngbin8128 -> 0 bytes
-rw-r--r--src/widgets/doc/images/designer-stylesheet-usage.webpbin0 -> 6816 bytes
-rw-r--r--src/widgets/doc/images/designer-validator-highlighter.pngbin27153 -> 0 bytes
-rw-r--r--src/widgets/doc/images/designer-validator-highlighter.webpbin0 -> 20718 bytes
-rw-r--r--src/widgets/doc/src/modelview.qdoc277
-rw-r--r--src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc13
-rw-r--r--src/widgets/itemviews/qabstractitemview.h2
-rw-r--r--src/widgets/styles/qstylesheetstyle.cpp35
-rw-r--r--src/widgets/widgets/qmdisubwindow.cpp5
-rw-r--r--src/widgets/widgets/qmenu.cpp2
-rw-r--r--tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp4
-rw-r--r--tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp47
-rw-r--r--tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp2
-rw-r--r--tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp29
-rw-r--r--tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp14
-rw-r--r--tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp2
-rw-r--r--tests/auto/corelib/kernel/qobject/tst_qobject.cpp6
-rw-r--r--tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp8
-rw-r--r--tests/auto/corelib/serialization/json/tst_qtjson.cpp22
-rw-r--r--tests/auto/corelib/thread/qfuture/tst_qfuture.cpp2
-rw-r--r--tests/auto/corelib/tools/qhash/tst_qhash.cpp2
-rw-r--r--tests/auto/corelib/tools/qlist/tst_qlist.cpp222
-rw-r--r--tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp8
-rw-r--r--tests/auto/gui/kernel/qwindow/tst_qwindow.cpp1
-rw-r--r--tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp26
-rw-r--r--tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp67
-rw-r--r--tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp79
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST3
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp63
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp99
59 files changed, 1669 insertions, 735 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index 337703bda3a..1147205b79f 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -577,10 +577,15 @@ if(QT_FEATURE_async_io)
io/qrandomaccessasyncfile.cpp io/qrandomaccessasyncfile_p.h io/qrandomaccessasyncfile_p_p.h
)
- # TODO: This should become the last (fallback) condition later.
- # We migth also want to rewrite it so that it does not depend on
- # QT_FEATURE_future.
- if(QT_FEATURE_thread AND QT_FEATURE_future)
+ if(APPLE)
+ qt_internal_extend_target(Core
+ SOURCES
+ io/qrandomaccessasyncfile_darwin.mm
+ )
+ elseif(QT_FEATURE_thread AND QT_FEATURE_future)
+ # TODO: This should become the last (fallback) condition later.
+ # We migth also want to rewrite it so that it does not depend on
+ # QT_FEATURE_future.
qt_internal_extend_target(Core
SOURCES
io/qrandomaccessasyncfile_threadpool.cpp
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake
index 535e3742cd2..d951b85c147 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -1233,7 +1233,7 @@ qt_feature("openssl-hash" PRIVATE
qt_feature("async-io" PRIVATE
LABEL "Async File I/O"
PURPOSE "Provides support for asynchronous file I/O."
- CONDITION QT_FEATURE_thread AND QT_FEATURE_future
+ CONDITION (QT_FEATURE_thread AND QT_FEATURE_future) OR APPLE
)
qt_configure_add_summary_section(NAME "Qt Core")
diff --git a/src/corelib/io/qrandomaccessasyncfile_darwin.mm b/src/corelib/io/qrandomaccessasyncfile_darwin.mm
new file mode 100644
index 00000000000..2d7d3b196b2
--- /dev/null
+++ b/src/corelib/io/qrandomaccessasyncfile_darwin.mm
@@ -0,0 +1,728 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// Qt-Security score:significant reason:default
+
+#include "qrandomaccessasyncfile_p_p.h"
+
+#include "qiooperation_p.h"
+#include "qiooperation_p_p.h"
+#include "qplatformdefs.h"
+
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/private/qfilesystemengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+static bool isBarrierOperation(QIOOperation::Type type)
+{
+ return type == QIOOperation::Type::Flush || type == QIOOperation::Type::Open;
+}
+
+} // anonymous namespace
+
+// Fine to provide the definition here, because all the usages are in this file
+// only!
+template <typename Operation, typename ...Args>
+Operation *
+QRandomAccessAsyncFilePrivate::addOperation(QIOOperation::Type type, qint64 offset, Args &&...args)
+{
+ auto dataStorage = new QtPrivate::QIOOperationDataStorage(std::forward<Args>(args)...);
+ auto *priv = new QIOOperationPrivate(dataStorage);
+ priv->offset = offset;
+ priv->type = type;
+
+ Operation *op = new Operation(*priv, q_ptr);
+ auto opId = getNextId();
+ m_operations.push_back(OperationInfo(opId, op));
+ startOperationsUntilBarrier();
+
+ return op;
+}
+
+QRandomAccessAsyncFilePrivate::QRandomAccessAsyncFilePrivate()
+ : QObjectPrivate()
+{
+}
+
+QRandomAccessAsyncFilePrivate::~QRandomAccessAsyncFilePrivate()
+ = default;
+
+void QRandomAccessAsyncFilePrivate::init()
+{
+}
+
+void QRandomAccessAsyncFilePrivate::cancelAndWait(QIOOperation *op)
+{
+ auto it = std::find_if(m_operations.cbegin(), m_operations.cend(),
+ [op](const auto &opInfo) {
+ return opInfo.operation.get() == op;
+ });
+ // not found
+ if (it == m_operations.cend())
+ return;
+
+ const auto opInfo = m_operations.takeAt(std::distance(m_operations.cbegin(), it));
+
+ if (opInfo.state == OpState::Running) {
+ // cancel this operation
+ m_mutex.lock();
+ if (m_runningOps.contains(opInfo.opId)) {
+ m_opToCancel = opInfo.opId;
+ closeIoChannel(opInfo.channel);
+ m_cancellationCondition.wait(&m_mutex);
+ m_opToCancel = kInvalidOperationId; // reset
+ }
+ m_mutex.unlock();
+ } // otherwise it was not started yet
+
+ // clean up the operation
+ releaseIoChannel(opInfo.channel);
+ auto *priv = QIOOperationPrivate::get(opInfo.operation);
+ priv->setError(QIOOperation::Error::Aborted);
+
+ // we could cancel a barrier operation, so try to execute next operations
+ startOperationsUntilBarrier();
+}
+
+void QRandomAccessAsyncFilePrivate::close()
+{
+ if (m_fileState == FileState::Closed)
+ return;
+
+ // cancel all operations
+ m_mutex.lock();
+ m_opToCancel = kAllOperationIds;
+ for (const auto &op : m_operations)
+ closeIoChannel(op.channel);
+ closeIoChannel(m_ioChannel);
+ // we're not interested in any results anymore
+ if (!m_runningOps.isEmpty() || m_ioChannel)
+ m_cancellationCondition.wait(&m_mutex);
+ m_opToCancel = kInvalidOperationId; // reset
+ m_mutex.unlock();
+
+ // clean up all operations
+ for (auto &opInfo : m_operations) {
+ releaseIoChannel(opInfo.channel);
+ auto *priv = QIOOperationPrivate::get(opInfo.operation);
+ priv->setError(QIOOperation::Error::Aborted);
+ }
+ m_operations.clear();
+
+ releaseIoChannel(m_ioChannel);
+
+ if (m_fd >= 0) {
+ ::close(m_fd);
+ m_fd = -1;
+ }
+
+ m_fileState = FileState::Closed;
+}
+
+qint64 QRandomAccessAsyncFilePrivate::size() const
+{
+ if (m_fileState != FileState::Opened)
+ return -1;
+
+ QFileSystemMetaData metaData;
+ if (QFileSystemEngine::fillMetaData(m_fd, metaData))
+ return metaData.size();
+
+ return -1;
+}
+
+QIOOperation *
+QRandomAccessAsyncFilePrivate::open(const QString &path, QIODeviceBase::OpenMode mode)
+{
+ if (m_fileState == FileState::Closed) {
+ m_filePath = path;
+ m_openMode = mode;
+ // Open is a barrier, so we won't have two open() operations running
+ // in parallel
+ m_fileState = FileState::OpenPending;
+ }
+
+ return addOperation<QIOOperation>(QIOOperation::Type::Open, 0);
+}
+
+QIOOperation *QRandomAccessAsyncFilePrivate::flush()
+{
+ return addOperation<QIOOperation>(QIOOperation::Type::Flush, 0);
+}
+
+QIOReadOperation *QRandomAccessAsyncFilePrivate::read(qint64 offset, qint64 maxSize)
+{
+ QByteArray array(maxSize, Qt::Uninitialized);
+ return addOperation<QIOReadOperation>(QIOOperation::Type::Read, offset, std::move(array));
+}
+
+QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, const QByteArray &data)
+{
+ QByteArray copy = data;
+ return write(offset, std::move(copy));
+}
+
+QIOWriteOperation *QRandomAccessAsyncFilePrivate::write(qint64 offset, QByteArray &&data)
+{
+ return addOperation<QIOWriteOperation>(QIOOperation::Type::Write, offset, std::move(data));
+}
+
+QIOVectoredReadOperation *
+QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<std::byte> buffer)
+{
+ return addOperation<QIOVectoredReadOperation>(QIOOperation::Type::Read, offset,
+ QSpan<const QSpan<std::byte>>{buffer});
+}
+
+QIOVectoredWriteOperation *
+QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const std::byte> buffer)
+{
+ return addOperation<QIOVectoredWriteOperation>(QIOOperation::Type::Write, offset,
+ QSpan<const QSpan<const std::byte>>{buffer});
+}
+
+QIOVectoredReadOperation *
+QRandomAccessAsyncFilePrivate::readInto(qint64 offset, QSpan<const QSpan<std::byte>> buffers)
+{
+ // GCD implementation does not have vectored read. Spawning several read
+ // operations (each with an updated offset), is not ideal, because some
+ // of them could fail, and it wouldn't be clear what would be the return
+ // value in such case.
+ // So, we'll just execute several reads one-after-another, and complete the
+ // whole operation only when they all finish (or when an operation fails
+ // at some point).
+
+ return addOperation<QIOVectoredReadOperation>(QIOOperation::Type::Read, offset, buffers);
+}
+
+QIOVectoredWriteOperation *
+QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers)
+{
+ return addOperation<QIOVectoredWriteOperation>(QIOOperation::Type::Write, offset, buffers);
+}
+
+dispatch_io_t QRandomAccessAsyncFilePrivate::createMainChannel(int fd)
+{
+ auto sharedThis = this;
+ return dispatch_io_create(DISPATCH_IO_RANDOM, fd,
+ dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0),
+ ^(int /*error*/) {
+ // Notify that the file descriptor can be closed
+ QMutexLocker locker(&sharedThis->m_mutex);
+ sharedThis->m_cancellationCondition.wakeOne();
+ });
+}
+
+dispatch_io_t QRandomAccessAsyncFilePrivate::duplicateIoChannel(OperationId opId)
+{
+ if (!m_ioChannel)
+ return nullptr;
+ // We need to create a new channel for each operation, because the only way
+ // to cancel an operation is to call dispatch_io_close() with
+ // DISPATCH_IO_STOP flag.
+ // We do not care about the callback in this case, because we have the
+ // callback from the "main" io channel to do all the proper cleanup
+ auto channel =
+ dispatch_io_create_with_io(DISPATCH_IO_RANDOM, m_ioChannel,
+ dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0),
+ ^(int){ /* empty callback */ });
+
+ if (channel) {
+ QMutexLocker locker(&m_mutex);
+ m_runningOps.insert(opId);
+ }
+ return channel;
+}
+
+void QRandomAccessAsyncFilePrivate::closeIoChannel(dispatch_io_t channel)
+{
+ if (channel)
+ dispatch_io_close(channel, DISPATCH_IO_STOP);
+}
+
+void QRandomAccessAsyncFilePrivate::releaseIoChannel(dispatch_io_t channel)
+{
+ if (channel) {
+ dispatch_release(channel);
+ channel = nullptr;
+ }
+}
+
+void QRandomAccessAsyncFilePrivate::handleOperationComplete(const OperationResult &opResult)
+{
+ // try to start next operations on return
+ auto onReturn = qScopeGuard([this] {
+ startOperationsUntilBarrier();
+ });
+
+ auto it = std::find_if(m_operations.cbegin(), m_operations.cend(),
+ [opId = opResult.opId](const auto &opInfo) {
+ return opInfo.opId == opId;
+ });
+ if (it == m_operations.cend())
+ return;
+ qsizetype idx = std::distance(m_operations.cbegin(), it);
+
+ const OperationInfo info = m_operations.takeAt(idx);
+ closeIoChannel(info.channel);
+ releaseIoChannel(info.channel);
+
+ if (!info.operation)
+ return;
+
+ auto convertError = [](int error, QIOOperation::Type type) {
+ if (error == 0) {
+ return QIOOperation::Error::None;
+ } else if (error == ECANCELED) {
+ return QIOOperation::Error::Aborted;
+ } else if (error == EBADF) {
+ return QIOOperation::Error::FileNotOpen;
+ } else if (error == EINVAL) {
+ switch (type) {
+ case QIOOperation::Type::Read:
+ case QIOOperation::Type::Write:
+ return QIOOperation::Error::IncorrectOffset;
+ case QIOOperation::Type::Flush:
+ return QIOOperation::Error::Flush;
+ case QIOOperation::Type::Open:
+ return QIOOperation::Error::Open;
+ case QIOOperation::Type::Unknown:
+ Q_UNREACHABLE_RETURN(QIOOperation::Error::FileNotOpen);
+ }
+ } else {
+ switch (type) {
+ case QIOOperation::Type::Read:
+ return QIOOperation::Error::Read;
+ case QIOOperation::Type::Write:
+ return QIOOperation::Error::Write;
+ case QIOOperation::Type::Flush:
+ return QIOOperation::Error::Flush;
+ case QIOOperation::Type::Open:
+ return QIOOperation::Error::Open;
+ case QIOOperation::Type::Unknown:
+ Q_UNREACHABLE_RETURN(QIOOperation::Error::FileNotOpen);
+ }
+ }
+ };
+
+ auto *priv = QIOOperationPrivate::get(info.operation);
+ switch (priv->type) {
+ case QIOOperation::Type::Read:
+ case QIOOperation::Type::Write:
+ priv->appendBytesProcessed(opResult.result);
+ // make sure that read buffers are truncated to the actual amount of
+ // bytes read
+ if (priv->type == QIOOperation::Type::Read) {
+ auto dataStorage = priv->dataStorage.get();
+ auto processed = priv->processed;
+ if (dataStorage->containsByteArray()) {
+ QByteArray &array = dataStorage->getByteArray();
+ array.truncate(processed);
+ } else if (dataStorage->containsReadSpans()) {
+ qint64 left = processed;
+ auto &readBuffers = dataStorage->getReadSpans();
+ for (auto &s : readBuffers) {
+ const qint64 spanSize = qint64(s.size_bytes());
+ const qint64 newSize = (std::min)(left, spanSize);
+ if (newSize < spanSize)
+ s.chop(spanSize - newSize);
+ left -= newSize;
+ }
+ }
+ }
+ priv->operationComplete(convertError(opResult.error, priv->type));
+ break;
+ case QIOOperation::Type::Flush: {
+ const QIOOperation::Error error = convertError(opResult.error, priv->type);
+ priv->operationComplete(error);
+ break;
+ }
+ case QIOOperation::Type::Open: {
+ const QIOOperation::Error error = convertError(opResult.error, priv->type);
+ if (opResult.result >= 0 && error == QIOOperation::Error::None) {
+ m_fd = (int)opResult.result;
+ m_ioChannel = createMainChannel(m_fd);
+ m_fileState = FileState::Opened;
+ } else {
+ m_fileState = FileState::Closed;
+ }
+ priv->operationComplete(error);
+ break;
+ }
+ case QIOOperation::Type::Unknown:
+ Q_UNREACHABLE();
+ break;
+ }
+}
+
+void QRandomAccessAsyncFilePrivate::queueCompletion(OperationId opId, int error)
+{
+ const OperationResult res = { opId, 0LL, error };
+ QMetaObject::invokeMethod(q_ptr, [this, res] {
+ handleOperationComplete(res);
+ }, Qt::QueuedConnection);
+}
+
+void QRandomAccessAsyncFilePrivate::startOperationsUntilBarrier()
+{
+ // starts all operations until barrier, or a barrier operation if it's the
+ // first one
+ bool first = true;
+ for (auto &opInfo : m_operations) {
+ const bool isBarrier = isBarrierOperation(opInfo.operation->type());
+ const bool shouldExecute = (opInfo.state == OpState::Pending) && (!isBarrier || first);
+ first = false;
+ if (shouldExecute) {
+ opInfo.state = OpState::Running;
+ switch (opInfo.operation->type()) {
+ case QIOOperation::Type::Read:
+ executeRead(opInfo);
+ break;
+ case QIOOperation::Type::Write:
+ executeWrite(opInfo);
+ break;
+ case QIOOperation::Type::Flush:
+ executeFlush(opInfo);
+ break;
+ case QIOOperation::Type::Open:
+ executeOpen(opInfo);
+ break;
+ case QIOOperation::Type::Unknown:
+ Q_UNREACHABLE();
+ break;
+ }
+ }
+ if (isBarrier)
+ break;
+ }
+}
+
+void QRandomAccessAsyncFilePrivate::executeRead(OperationInfo &opInfo)
+{
+ opInfo.channel = duplicateIoChannel(opInfo.opId);
+ if (!opInfo.channel) {
+ queueCompletion(opInfo.opId, EBADF);
+ return;
+ }
+ auto priv = QIOOperationPrivate::get(opInfo.operation);
+ auto dataStorage = priv->dataStorage.get();
+ if (dataStorage->containsByteArray()) {
+ auto &array = dataStorage->getByteArray();
+ char *bytesPtr = array.data();
+ qint64 maxSize = array.size();
+ readOneBufferHelper(opInfo.opId, opInfo.channel, priv->offset,
+ bytesPtr, maxSize,
+ 0, 1, 0);
+ } else {
+ Q_ASSERT(dataStorage->containsReadSpans());
+ auto &readBuffers = dataStorage->getReadSpans();
+ const auto totalBuffers = readBuffers.size();
+ if (totalBuffers == 0) {
+ queueCompletion(opInfo.opId, 0);
+ return;
+ }
+ auto buf = readBuffers[0];
+ readOneBufferHelper(opInfo.opId, opInfo.channel, priv->offset,
+ buf.data(), buf.size(),
+ 0, totalBuffers, 0);
+ }
+}
+
+void QRandomAccessAsyncFilePrivate::executeWrite(OperationInfo &opInfo)
+{
+ opInfo.channel = duplicateIoChannel(opInfo.opId);
+ if (!opInfo.channel) {
+ queueCompletion(opInfo.opId, EBADF);
+ return;
+ }
+ auto priv = QIOOperationPrivate::get(opInfo.operation);
+ auto dataStorage = priv->dataStorage.get();
+ if (dataStorage->containsByteArray()) {
+ const auto &array = dataStorage->getByteArray();
+ const char *dataPtr = array.constData();
+ const qint64 dataSize = array.size();
+
+ dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0);
+ // We handle the bytes on our own, so we need to specify an empty block as
+ // a destructor.
+ // dataToWrite is retained, so should be properly cleaned up. We always do
+ // it in the callback.
+ dispatch_data_t dataToWrite = dispatch_data_create(dataPtr, dataSize, queue, ^{});
+
+ writeHelper(opInfo.opId, opInfo.channel, priv->offset, dataToWrite, dataSize);
+ } else {
+ Q_ASSERT(dataStorage->containsWriteSpans());
+
+ const auto &writeBuffers = dataStorage->getWriteSpans();
+ const auto totalBuffers = writeBuffers.size();
+ if (totalBuffers == 0) {
+ queueCompletion(opInfo.opId, 0);
+ return;
+ }
+
+ dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0);
+ qsizetype idx = 0;
+ dispatch_data_t dataToWrite = dispatch_data_empty;
+ qint64 totalSize = 0;
+ do {
+ const std::byte *dataPtr = writeBuffers[idx].data();
+ const qint64 dataSize = writeBuffers[idx].size();
+ dispatch_data_t data = dispatch_data_create(dataPtr, dataSize, queue, ^{});
+ dataToWrite = dispatch_data_create_concat(dataToWrite, data);
+ [data release];
+ totalSize += dataSize;
+ } while (++idx < totalBuffers);
+
+ writeHelper(opInfo.opId, opInfo.channel, priv->offset, dataToWrite, totalSize);
+ }
+}
+
+void QRandomAccessAsyncFilePrivate::executeFlush(OperationInfo &opInfo)
+{
+ opInfo.channel = duplicateIoChannel(opInfo.opId);
+ if (!opInfo.channel) {
+ queueCompletion(opInfo.opId, EBADF);
+ return;
+ }
+
+ // flush() is a barrier operation, but dispatch_io_barrier does not work
+ // as documented with multiple channels :(
+ auto sharedThis = this;
+ const int fd = m_fd;
+ const OperationId opId = opInfo.opId;
+ dispatch_io_barrier(opInfo.channel, ^{
+ const int err = fsync(fd);
+
+ QMutexLocker locker(&sharedThis->m_mutex);
+ sharedThis->m_runningOps.remove(opId);
+ const auto cancelId = sharedThis->m_opToCancel;
+ if (cancelId == kAllOperationIds || cancelId == opId) {
+ if (cancelId == opId)
+ sharedThis->m_cancellationCondition.wakeOne();
+ } else {
+ auto context = sharedThis->q_ptr;
+ const OperationResult res = { opId, 0LL, err };
+ QMetaObject::invokeMethod(context, [sharedThis](const OperationResult &r) {
+ sharedThis->handleOperationComplete(r);
+ }, Qt::QueuedConnection, res);
+ }
+ });
+}
+
+// stolen from qfsfileengine_unix.cpp
+static inline int openModeToOpenFlags(QIODevice::OpenMode mode)
+{
+ int oflags = QT_OPEN_RDONLY;
+#ifdef QT_LARGEFILE_SUPPORT
+ oflags |= QT_OPEN_LARGEFILE;
+#endif
+ if ((mode & QIODevice::ReadWrite) == QIODevice::ReadWrite)
+ oflags = QT_OPEN_RDWR;
+ else if (mode & QIODevice::WriteOnly)
+ oflags = QT_OPEN_WRONLY;
+ if ((mode & QIODevice::WriteOnly)
+ && !(mode & QIODevice::ExistingOnly)) // QFSFileEnginePrivate::openModeCanCreate(mode))
+ oflags |= QT_OPEN_CREAT;
+ if (mode & QIODevice::Truncate)
+ oflags |= QT_OPEN_TRUNC;
+ if (mode & QIODevice::Append)
+ oflags |= QT_OPEN_APPEND;
+ if (mode & QIODevice::NewOnly)
+ oflags |= QT_OPEN_EXCL;
+ return oflags;
+}
+
+void QRandomAccessAsyncFilePrivate::executeOpen(OperationInfo &opInfo)
+{
+ if (m_fileState != FileState::OpenPending) {
+ queueCompletion(opInfo.opId, EINVAL);
+ return;
+ }
+
+ const QByteArray nativeName = QFile::encodeName(QDir::toNativeSeparators(m_filePath));
+
+ int openFlags = openModeToOpenFlags(m_openMode);
+ openFlags |= O_NONBLOCK;
+
+ auto sharedThis = this;
+ const OperationId opId = opInfo.opId;
+
+ // We don'd call duplicateIOChannel(), so need to update the running ops
+ // explicitly.
+ m_mutex.lock();
+ m_runningOps.insert(opId);
+ m_mutex.unlock();
+
+ dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0),
+ ^{
+ int err = 0;
+ const int fd = ::open(nativeName.data(), openFlags);
+ if (fd < 0)
+ err = errno;
+
+ QMutexLocker locker(&sharedThis->m_mutex);
+ sharedThis->m_runningOps.remove(opId);
+ const auto cancelId = sharedThis->m_opToCancel;
+ if (cancelId == kAllOperationIds || cancelId == opId) {
+ // open() is a barrier operation, so it's always the
+ // only executing operation.
+ // Also, the main IO channel is not created yet.
+ // So we need to notify the condition variable in
+ // any both cases.
+ Q_ASSERT(sharedThis->m_runningOps.isEmpty());
+ sharedThis->m_cancellationCondition.wakeOne();
+ } else {
+ auto context = sharedThis->q_ptr;
+ const OperationResult res = { opId, qint64(fd), err };
+ QMetaObject::invokeMethod(context, [sharedThis](const OperationResult &r) {
+ sharedThis->handleOperationComplete(r);
+ }, Qt::QueuedConnection, res);
+ }
+ });
+}
+
+void QRandomAccessAsyncFilePrivate::readOneBuffer(OperationId opId, qsizetype bufferIdx,
+ qint64 alreadyRead)
+{
+ // we need to lookup the operation again, because it could have beed removed
+ // by the user...
+
+ auto it = std::find_if(m_operations.cbegin(), m_operations.cend(),
+ [opId](const auto &opInfo) {
+ return opId == opInfo.opId;
+ });
+ if (it == m_operations.cend())
+ return;
+
+ auto op = it->operation; // QPointer could be null
+ if (!op) {
+ closeIoChannel(it->channel);
+ return;
+ }
+
+ auto *priv = QIOOperationPrivate::get(op);
+ Q_ASSERT(priv->type == QIOOperation::Type::Read);
+ Q_ASSERT(priv->dataStorage->containsReadSpans());
+
+ auto &readBuffers = priv->dataStorage->getReadSpans();
+ Q_ASSERT(readBuffers.size() > bufferIdx);
+
+ qint64 newOffset = priv->offset;
+ for (qsizetype idx = 0; idx < bufferIdx; ++idx)
+ newOffset += readBuffers[idx].size();
+
+ std::byte *bytesPtr = readBuffers[bufferIdx].data();
+ qint64 maxSize = readBuffers[bufferIdx].size();
+
+ readOneBufferHelper(opId, it->channel, newOffset, bytesPtr, maxSize, bufferIdx,
+ readBuffers.size(), alreadyRead);
+}
+
+void QRandomAccessAsyncFilePrivate::readOneBufferHelper(OperationId opId, dispatch_io_t channel,
+ qint64 offset, void *bytesPtr,
+ qint64 maxSize, qsizetype currentBufferIdx,
+ qsizetype totalBuffers, qint64 alreadyRead)
+{
+ auto sharedThis = this;
+ __block size_t readFromBuffer = 0;
+ dispatch_io_read(channel, offset, maxSize,
+ dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0),
+ ^(bool done, dispatch_data_t data, int error) {
+ // Handle data. If there's an error, handle as much as
+ // we can.
+ if (data) {
+ dispatch_data_apply(data, ^(dispatch_data_t /*region*/, size_t offset,
+ const void *buffer, size_t size) {
+ const char *startPtr =
+ reinterpret_cast<const char *>(buffer) + offset;
+ // NOTE: This is a copy, but looks like we
+ // cannot do better :(
+ std::memcpy((std::byte *)bytesPtr + readFromBuffer,
+ startPtr, size);
+ readFromBuffer += size;
+ return true; // Keep processing if there is more data.
+ });
+ }
+
+ QMutexLocker locker(&sharedThis->m_mutex);
+ const auto cancelId = sharedThis->m_opToCancel;
+ if (cancelId == kAllOperationIds || cancelId == opId) {
+ sharedThis->m_runningOps.remove(opId);
+ if (cancelId == opId)
+ sharedThis->m_cancellationCondition.wakeOne();
+ } else if (done) {
+ sharedThis->m_runningOps.remove(opId);
+ auto context = sharedThis->q_ptr;
+ // if error, or last buffer, or read less than expected,
+ // report operation completion
+ qint64 totalRead = qint64(readFromBuffer) + alreadyRead;
+ qsizetype nextBufferIdx = currentBufferIdx + 1;
+ if (error || nextBufferIdx == totalBuffers
+ || qint64(readFromBuffer) != maxSize) {
+ const OperationResult res = { opId, totalRead, error };
+ QMetaObject::invokeMethod(context,
+ [sharedThis](const OperationResult &r) {
+ sharedThis->handleOperationComplete(r);
+ }, Qt::QueuedConnection, res);
+ } else {
+ // else execute read for the next buffer
+ QMetaObject::invokeMethod(context,
+ [sharedThis, opId, nextBufferIdx, totalRead] {
+ sharedThis->readOneBuffer(opId, nextBufferIdx, totalRead);
+ }, Qt::QueuedConnection);
+ }
+ }
+ });
+}
+
+void QRandomAccessAsyncFilePrivate::writeHelper(OperationId opId, dispatch_io_t channel,
+ qint64 offset, dispatch_data_t dataToWrite,
+ qint64 dataSize)
+{
+ auto sharedThis = this;
+ dispatch_io_write(channel, offset, dataToWrite,
+ dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0),
+ ^(bool done, dispatch_data_t data, int error) {
+ // Either an error or complete write.
+ // If there's an error, return the amount that we have
+ // written so far
+ QMutexLocker locker(&sharedThis->m_mutex);
+ const auto cancelId = sharedThis->m_opToCancel;
+ if (cancelId == kAllOperationIds || cancelId == opId) {
+ // Operation is canceled - do nothing
+ sharedThis->m_runningOps.remove(opId);
+ if (cancelId == opId)
+ sharedThis->m_cancellationCondition.wakeOne();
+ } else if (done) {
+ sharedThis->m_runningOps.remove(opId);
+ // if no error, an attempt to access the data will
+ // crash, because it seems to have no buffer
+ // allocated (as everything was written)
+ const size_t toBeWritten =
+ (error == 0) ? 0 : dispatch_data_get_size(data);
+ const size_t written = dataSize - toBeWritten;
+ [dataToWrite release];
+
+ auto context = sharedThis->q_ptr;
+ const OperationResult res = { opId, qint64(written), error };
+ QMetaObject::invokeMethod(context,
+ [sharedThis](const OperationResult &r) {
+ sharedThis->handleOperationComplete(r);
+ }, Qt::QueuedConnection, res);
+ }
+ });
+}
+
+QRandomAccessAsyncFilePrivate::OperationId QRandomAccessAsyncFilePrivate::getNextId()
+{
+ // never return reserved values
+ static OperationId opId = kInvalidOperationId;
+ if (++opId == kAllOperationIds)
+ opId = kInvalidOperationId + 1;
+ return opId;
+}
+
+QT_END_NAMESPACE
diff --git a/src/corelib/io/qrandomaccessasyncfile_p_p.h b/src/corelib/io/qrandomaccessasyncfile_p_p.h
index ef996c37f07..73d7eebdf72 100644
--- a/src/corelib/io/qrandomaccessasyncfile_p_p.h
+++ b/src/corelib/io/qrandomaccessasyncfile_p_p.h
@@ -32,6 +32,17 @@
#endif // QT_RANDOMACCESSASYNCFILE_THREAD
+#ifdef Q_OS_DARWIN
+
+#include <QtCore/qlist.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qset.h>
+#include <QtCore/qwaitcondition.h>
+
+#include <dispatch/dispatch.h>
+
+#endif // Q_OS_DARWIN
+
QT_BEGIN_NAMESPACE
class QRandomAccessAsyncFilePrivate : public QObjectPrivate
@@ -69,6 +80,18 @@ public:
writeFrom(qint64 offset, QSpan<const QSpan<const std::byte>> buffers);
private:
+ // common for all backends
+ enum class FileState : quint8
+ {
+ Closed,
+ OpenPending, // already got an open request
+ Opened,
+ };
+
+ QString m_filePath;
+ QIODeviceBase::OpenMode m_openMode;
+ FileState m_fileState = FileState::Closed;
+
#ifdef QT_RANDOMACCESSASYNCFILE_THREAD
public:
struct OperationResult
@@ -78,13 +101,6 @@ public:
};
private:
- enum class FileState : quint8
- {
- Closed,
- OpenPending, // already got an open request
- Opened,
- };
-
mutable QBasicMutex m_engineMutex;
std::unique_ptr<QFSFileEngine> m_engine;
QFutureWatcher<OperationResult> m_watcher;
@@ -93,16 +109,90 @@ private:
QPointer<QIOOperation> m_currentOperation;
qsizetype numProcessedBuffers = 0;
- QString m_filePath;
- QIODeviceBase::OpenMode m_openMode;
- FileState m_fileState = FileState::Closed;
-
void executeNextOperation();
void processBufferAt(qsizetype idx);
void processFlush();
void processOpen();
void operationComplete();
#endif
+#ifdef Q_OS_DARWIN
+ using OperationId = quint64;
+ static constexpr OperationId kInvalidOperationId = 0;
+ static constexpr OperationId kAllOperationIds = std::numeric_limits<OperationId>::max();
+
+ struct OperationResult
+ {
+ OperationId opId;
+ qint64 result; // num bytes processed or file descriptor
+ int error;
+ };
+
+ enum class OpState : quint8
+ {
+ Pending,
+ Running,
+ };
+
+ struct OperationInfo
+ {
+ OperationId opId;
+ dispatch_io_t channel;
+ QPointer<QIOOperation> operation;
+ OpState state;
+
+ OperationInfo(OperationId _id, QIOOperation *_op)
+ : opId(_id),
+ channel(nullptr),
+ operation(_op),
+ state(OpState::Pending)
+ {}
+ };
+
+ // We need to maintain an actual queue of the operations, because
+ // certain operations (i.e. flush) should act like barriers. The docs
+ // for dispatch_io_barrier mention that it can synchronize between multiple
+ // channels handling the same file descriptor, but that DOES NOT work in
+ // practice. It works correctly only when there's a signle IO channel. But
+ // with a signle IO channel we're not able to cancel individual operations.
+ // As a result, we need to make sure that all previous operations are
+ // completed before starting a barrier operation. Similarly, we cannot start
+ // any other operation until a barrier operation is finished.
+ QList<OperationInfo> m_operations;
+ dispatch_io_t m_ioChannel = nullptr;
+ int m_fd = -1;
+
+ QMutex m_mutex;
+ // the members below should only be accessed with the mutex
+ OperationId m_opToCancel = kInvalidOperationId;
+ QSet<OperationId> m_runningOps;
+ QWaitCondition m_cancellationCondition;
+
+ static OperationId getNextId();
+
+ template <typename Operation, typename ...Args>
+ Operation *addOperation(QIOOperation::Type type, qint64 offset, Args &&...args);
+
+ dispatch_io_t createMainChannel(int fd);
+ dispatch_io_t duplicateIoChannel(OperationId opId);
+ void closeIoChannel(dispatch_io_t channel);
+ void releaseIoChannel(dispatch_io_t channel);
+ void handleOperationComplete(const OperationResult &opResult);
+
+ void queueCompletion(OperationId opId, int error);
+
+ void startOperationsUntilBarrier();
+ void executeRead(OperationInfo &opInfo);
+ void executeWrite(OperationInfo &opInfo);
+ void executeFlush(OperationInfo &opInfo);
+ void executeOpen(OperationInfo &opInfo);
+
+ void readOneBuffer(OperationId opId, qsizetype bufferIdx, qint64 alreadyRead);
+ void readOneBufferHelper(OperationId opId, dispatch_io_t channel, qint64 offset,
+ void *bytesPtr, qint64 maxSize, qsizetype currentBufferIdx,
+ qsizetype totalBuffers, qint64 alreadyRead);
+ void writeHelper(OperationId opId, dispatch_io_t channel, qint64 offset,
+ dispatch_data_t dataToWrite, qint64 dataSize);
+#endif
};
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 560a8c7d789..02c9f00f301 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -2715,6 +2715,20 @@ static void err_info_about_objects(const char *func, const QObject *sender, cons
qCWarning(lcConnect, "QObject::%s: (receiver name: '%s')", func, b.toLocal8Bit().data());
}
+Q_DECL_COLD_FUNCTION
+static void connectWarning(const QObject *sender,
+ const QMetaObject *senderMetaObject,
+ const QObject *receiver,
+ const char *message)
+{
+ const char *senderString = sender ? sender->metaObject()->className()
+ : senderMetaObject ? senderMetaObject->className()
+ : "Unknown";
+ const char *receiverString = receiver ? receiver->metaObject()->className()
+ : "Unknown";
+ qCWarning(lcConnect, "QObject::connect(%s, %s): %s", senderString, receiverString, message);
+}
+
/*!
Returns a pointer to the object that sent the signal, if called in
a slot activated by a signal; otherwise it returns \nullptr. The pointer
@@ -4105,8 +4119,9 @@ QMetaObject::Connection QMetaObject::connectImpl(const QObject *sender, const QM
{
QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
+ const QMetaObject *senderMetaObject = sender->metaObject();
if (!signal.isValid() || signal.methodType() != QMetaMethod::Signal) {
- qCWarning(lcConnect, "QObject::connect: invalid signal parameter");
+ connectWarning(sender, senderMetaObject, receiver, "invalid signal parameter");
return QMetaObject::Connection();
}
@@ -4116,7 +4131,6 @@ QMetaObject::Connection QMetaObject::connectImpl(const QObject *sender, const QM
QMetaObjectPrivate::memberIndexes(sender, signal, &signal_index, &dummy);
}
- const QMetaObject *senderMetaObject = sender->metaObject();
if (signal_index == -1) {
qCWarning(lcConnect, "QObject::connect: Can't find signal %s on instance of class %s",
signal.methodSignature().constData(), senderMetaObject->className());
@@ -5433,7 +5447,7 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa
{
QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
if (!signal) {
- qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter");
+ connectWarning(sender, senderMetaObject, receiver, "invalid nullptr parameter");
return QMetaObject::Connection();
}
@@ -5445,26 +5459,13 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa
break;
}
if (!senderMetaObject) {
- qCWarning(lcConnect, "QObject::connect: signal not found in %s", sender->metaObject()->className());
+ connectWarning(sender, senderMetaObject, receiver, "signal not found");
return QMetaObject::Connection(nullptr);
}
signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj.release(), type, types, senderMetaObject);
}
-static void connectWarning(const QObject *sender,
- const QMetaObject *senderMetaObject,
- const QObject *receiver,
- const char *message)
-{
- const char *senderString = sender ? sender->metaObject()->className()
- : senderMetaObject ? senderMetaObject->className()
- : "Unknown";
- const char *receiverString = receiver ? receiver->metaObject()->className()
- : "Unknown";
- qCWarning(lcConnect, "QObject::connect(%s, %s): %s", senderString, receiverString, message);
-}
-
/*!
\internal
@@ -5495,7 +5496,7 @@ QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int s
QOrderedMutexLocker locker(signalSlotLock(sender),
signalSlotLock(receiver));
- if (type & Qt::UniqueConnection && slot) {
+ if (type & Qt::UniqueConnection) {
QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s)->connections.loadRelaxed();
if (connections && connections->signalVectorCount() > signal_index) {
const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed()->at(signal_index).first.loadRelaxed();
@@ -5683,7 +5684,7 @@ QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signa
{
QtPrivate::SlotObjUniquePtr slotObj(slotObjRaw);
if (!sender) {
- qCWarning(lcConnect, "QObject::connect: invalid nullptr parameter");
+ connectWarning(sender, nullptr, receiver, "invalid nullptr parameter");
return QMetaObject::Connection();
}
const QMetaObject *senderMetaObject = sender->metaObject();
diff --git a/src/corelib/platform/android/qandroidnativeinterface.cpp b/src/corelib/platform/android/qandroidnativeinterface.cpp
index 680725dc6a1..5771d28f3a9 100644
--- a/src/corelib/platform/android/qandroidnativeinterface.cpp
+++ b/src/corelib/platform/android/qandroidnativeinterface.cpp
@@ -48,8 +48,9 @@ QT_DEFINE_NATIVE_INTERFACE(QAndroidApplication);
/*!
\fn QJniObject QNativeInterface::QAndroidApplication::context()
- Returns the Android context as a \c QJniObject. The context is an \c Activity
- if the most recently started activity object is valid. Otherwise, the context is a \c Service.
+ Returns the Android context as a \c QtJniTypes::Context. The context
+ is an \c Activity if the most recently started activity object is valid.
+ Otherwise, the context is a \c Service.
\since 6.2
*/
diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp
index 5b61940cbbe..d8434f4fe1b 100644
--- a/src/corelib/time/qtimezoneprivate.cpp
+++ b/src/corelib/time/qtimezoneprivate.cpp
@@ -1081,12 +1081,6 @@ QList<QByteArray> QTimeZonePrivate::windowsIdToIanaIds(const QByteArray &windows
return list;
}
-// Define template for derived classes to reimplement so QSharedDataPointer clone() works correctly
-template<> QTimeZonePrivate *QSharedDataPointer<QTimeZonePrivate>::clone()
-{
- return d->clone();
-}
-
static bool isEntryInIanaList(QByteArrayView id, QByteArrayView ianaIds)
{
qsizetype cut;
diff --git a/src/corelib/time/qtimezoneprivate_p.h b/src/corelib/time/qtimezoneprivate_p.h
index 2714c67b093..b1217402ce7 100644
--- a/src/corelib/time/qtimezoneprivate_p.h
+++ b/src/corelib/time/qtimezoneprivate_p.h
@@ -209,8 +209,6 @@ protected:
};
Q_DECLARE_TYPEINFO(QTimeZonePrivate::Data, Q_RELOCATABLE_TYPE);
-template<> QTimeZonePrivate *QSharedDataPointer<QTimeZonePrivate>::clone();
-
class Q_AUTOTEST_EXPORT QUtcTimeZonePrivate final : public QTimeZonePrivate
{
bool operator=(const QUtcTimeZonePrivate &) const = delete;
diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h
index d1e76b250bb..de749ee112e 100644
--- a/src/corelib/tools/qhashfunctions.h
+++ b/src/corelib/tools/qhashfunctions.h
@@ -413,14 +413,14 @@ qHashMultiCommutative(size_t seed, const T &... args)
template <typename InputIterator>
inline size_t qHashRange(InputIterator first, InputIterator last, size_t seed = 0)
- noexcept(noexcept(qHash(*first))) // assume iterator operations don't throw
+ noexcept(noexcept(qHash(*first, 0))) // assume iterator operations don't throw
{
return std::accumulate(first, last, seed, QtPrivate::QHashCombine(seed));
}
template <typename InputIterator>
inline size_t qHashRangeCommutative(InputIterator first, InputIterator last, size_t seed = 0)
- noexcept(noexcept(qHash(*first))) // assume iterator operations don't throw
+ noexcept(noexcept(qHash(*first, 0))) // assume iterator operations don't throw
{
return std::accumulate(first, last, seed, QtPrivate::QHashCombineCommutative(seed));
}
diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h
index 93f7ddb9465..a11f7913dc7 100644
--- a/src/corelib/tools/qlist.h
+++ b/src/corelib/tools/qlist.h
@@ -579,7 +579,12 @@ public:
{ d->assign(first, last); return *this; }
QList &assign(std::initializer_list<T> l)
- { return assign(l.begin(), l.end()); }
+ {
+ if (l.size())
+ return assign(l.begin(), l.end());
+ clear();
+ return *this;
+ }
template <typename ...Args>
iterator emplace(const_iterator before, Args&&... args)
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index e44d9b1468b..518843ffcbd 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -2626,7 +2626,6 @@ void QGuiApplicationPrivate::processEnterEvent(QWindowSystemInterfacePrivate::En
}
currentMouseWindow = e->enter;
- lastCursorPosition = e->globalPos;
// TODO later: EnterEvent must report _which_ mouse entered the window; for now we assume primaryPointingDevice()
QEnterEvent event(e->localPos, e->localPos, e->globalPos);
@@ -3408,6 +3407,15 @@ void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::E
return;
QWindowPrivate *p = qt_window_private(window);
+ if (e->isExposed) {
+ // If the window has been automatically positioned or resized by the
+ // window manager, we now assume those have taken effect, even for
+ // asynchronous window managers. From this point on we want the window
+ // to keep its geometry, even when recreated.
+ p->positionAutomatic = false;
+ p->resizeAutomatic = false;
+ }
+
if (!p->receivedExpose) {
if (p->resizeEventPending) {
// as a convenience for plugins, send a resize event before the first expose event if they haven't done so
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index c23be8eb3ad..bad5932c457 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -582,12 +582,6 @@ void QWindowPrivate::create(bool recursive)
platformWindow->initialize();
- // Now that the window is created and initialized the platform has had
- // a chance to position and size it automatically. From this point on
- // we want the window to keep its geometry, even when recreated.
- positionAutomatic = false;
- resizeAutomatic = false;
-
QObjectList childObjects = q->children();
for (int i = 0; i < childObjects.size(); i ++) {
QObject *object = childObjects.at(i);
diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp
index 5763696266a..38c4a9ea87f 100644
--- a/src/gui/painting/qpainterpath.cpp
+++ b/src/gui/painting/qpainterpath.cpp
@@ -2937,6 +2937,8 @@ qreal QPainterPath::percentAtLength(qreal len) const
if (len > totalLength)
return 1;
+ Q_ASSERT(totalLength != 0);
+
if (d->cacheEnabled) {
const int ei = qMax(d->elementAtT(len / totalLength), 1); // Skip initial MoveTo
qreal res = 0;
@@ -3117,6 +3119,7 @@ QPointF QPainterPath::pointAtPercent(qreal t) const
qreal curLen = 0;
qreal bezierLen = 0;
QBezier b = d_ptr->bezierAtT(*this, t, &curLen, &bezierLen);
+ Q_ASSERT(bezierLen != 0);
qreal realT = (totalLength * t - curLen) / bezierLen;
return b.pointAt(qBound(qreal(0), realT, qreal(1)));
@@ -3141,10 +3144,14 @@ qreal QPainterPath::angleAtPercent(qreal t) const
return 0;
}
+ if (isEmpty())
+ return 0;
+
qreal totalLength = length();
qreal curLen = 0;
qreal bezierLen = 0;
QBezier bez = d_ptr->bezierAtT(*this, t, &curLen, &bezierLen);
+ Q_ASSERT(bezierLen != 0);
qreal realT = (totalLength * t - curLen) / bezierLen;
qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
@@ -3170,10 +3177,14 @@ qreal QPainterPath::slopeAtPercent(qreal t) const
return 0;
}
+ if (isEmpty())
+ return 0;
+
qreal totalLength = length();
qreal curLen = 0;
qreal bezierLen = 0;
QBezier bez = d_ptr->bezierAtT(*this, t, &curLen, &bezierLen);
+ Q_ASSERT(bezierLen != 0);
qreal realT = (totalLength * t - curLen) / bezierLen;
qreal m1 = slopeAt(realT, bez.x1, bez.x2, bez.x3, bez.x4);
diff --git a/src/gui/platform/darwin/qappleiconengine.mm b/src/gui/platform/darwin/qappleiconengine.mm
index 20d50b0d8a8..3228b97fdb0 100644
--- a/src/gui/platform/darwin/qappleiconengine.mm
+++ b/src/gui/platform/darwin/qappleiconengine.mm
@@ -30,27 +30,28 @@ auto *loadImage(const QString &iconName)
{"call-start"_L1, @"phone.arrow.up.right"},
{"call-stop"_L1, @"phone.down"},
{"contact-new"_L1, @"person.crop.circle.badge.plus"},
- {"document-new"_L1, @"doc.badge.plus"},
- {"document-open"_L1, @"folder"},
- {"document-open-recent"_L1, @"doc.badge.clock"},
- {"document-page-setup"_L1, @"doc.badge.gearshape"},
+ {"document-new"_L1, @"plus"},
+ {"document-open"_L1, @"arrow.up.forward"},
+ {"document-open-recent"_L1, @"clock"},
+ {"document-page-setup"_L1, @"text.page"},
{"document-print"_L1, @"printer"},
- //{"document-print-preview"_L1, @""},
- {"document-properties"_L1, @"doc.badge.ellipsis"},
- //{"document-revert"_L1, @""},
+ {"document-print-preview"_L1, @"richtext.page"},
+ {"document-properties"_L1, @"info.circle.text.page"},
+ {"document-revert"_L1, @"arrow.counterclockwise"},
{"document-save"_L1, @"square.and.arrow.down"},
- //{"document-save-as"_L1, @""},
+ {"document-save-as"_L1, @"square.and.arrow.down.on.square"},
{"document-send"_L1, @"paperplane"},
+ {"document-export"_L1, @"square.and.arrow.up"},
{"edit-clear"_L1, @"xmark.circle"},
{"edit-copy"_L1, @"doc.on.doc"},
{"edit-cut"_L1, @"scissors"},
- {"edit-delete"_L1, @"delete.left"},
- {"edit-find"_L1, @"magnifyingglass"},
+ {"edit-delete"_L1, @"trash"},
+ {"edit-find"_L1, @"text.page.badge.magnifyingglass"},
//{"edit-find-replace"_L1, @"arrow.up.left.and.down.right.magnifyingglass"},
- {"edit-paste"_L1, @"clipboard"},
- {"edit-redo"_L1, @"arrowshape.turn.up.right"},
- //{"edit-select-all"_L1, @""},
- {"edit-undo"_L1, @"arrowshape.turn.up.left"},
+ {"edit-paste"_L1, @"document.on.clipboard"},
+ {"edit-redo"_L1, @"arrow.uturn.forward"},
+ {"edit-select-all"_L1, @"character.textbox"},
+ {"edit-undo"_L1, @"arrow.uturn.backward"},
{"folder-new"_L1, @"folder.badge.plus"},
{"format-indent-less"_L1, @"decrease.indent"},
{"format-indent-more"_L1, @"increase.indent"},
@@ -65,35 +66,36 @@ auto *loadImage(const QString &iconName)
{"format-text-underline"_L1, @"underline"},
{"format-text-strikethrough"_L1, @"strikethrough"},
//{"go-bottom"_L1, @""},
- {"go-down"_L1, @"arrowshape.down"},
- {"go-first"_L1, @"increase.indent"},
+ {"go-down"_L1, @"chevron.down"},
+ //{"go-first"_L1, @""},
{"go-home"_L1, @"house"},
//{"go-jump"_L1, @""},
//{"go-last"_L1, @""},
- {"go-next"_L1, @"arrowshape.right"},
- {"go-previous"_L1, @"arrowshape.left"},
+ {"go-next"_L1, @"chevron.right"},
+ {"go-previous"_L1, @"chevron.left"},
//{"go-top"_L1, @""},
- {"go-up"_L1, @"arrowshape.up"},
+ {"go-up"_L1, @"chevron.up"},
{"help-about"_L1, @"info.circle"},
//{"help-contents"_L1, @""},
{"help-faq"_L1, @"questionmark.app"},
{"insert-image"_L1, @"photo.badge.plus"},
{"insert-link"_L1, @"link.badge.plus"},
- //{"insert-object"_L1, @""},
- {"insert-text"_L1, @"textformat"},
+ {"insert-object"_L1, @"widget.small.badge.plus"},
+ {"insert-text"_L1, @"text.badge.plus"},
{"list-add"_L1, @"plus.circle"},
{"list-remove"_L1, @"minus.circle"},
{"mail-forward"_L1, @"arrowshape.turn.up.right"},
{"mail-mark-important"_L1, @"star"},
{"mail-mark-junk"_L1, @"xmark.bin"},
- {"mail-mark-notjunk"_L1, @"trash.slash"},
+ {"mail-mark-notjunk"_L1, @"arrow.up.bin"},
{"mail-mark-read"_L1, @"envelope.open"},
- {"mail-mark-unread"_L1, @"envelope.fill"},
+ {"mail-mark-unread"_L1, @"envelope.badge"},
{"mail-message-new"_L1, @"square.and.pencil"},
{"mail-reply-all"_L1, @"arrowshape.turn.up.left.2"},
{"mail-reply-sender"_L1, @"arrowshape.turn.up.left"},
- {"mail-send"_L1, @"paperplane"},
- {"mail-send-receive"_L1, @"envelope.arrow.triangle.branch"},
+ {"mail-send"_L1, @"arrow.up.circle.fill"},
+ {"mail-send-receive"_L1, @"arrow.trianglehead.2.clockwise.rotate.90"},
+ {"mail-replied"_L1, @"envelope.and.arrow.trianglehead.branch"},
{"media-eject"_L1, @"eject"},
{"media-playback-pause"_L1, @"pause"},
{"media-playback-start"_L1, @"play"},
@@ -108,61 +110,61 @@ auto *loadImage(const QString &iconName)
{"object-rotate-left"_L1, @"rotate.left"},
{"object-rotate-right"_L1, @"rotate.right"},
{"process-stop"_L1, @"stop.circle"},
- {"system-lock-screen"_L1, @"lock.display"},
- {"system-log-out"_L1, @"door.left.hand.open"},
+ {"system-lock-screen"_L1, @"lock"},
+ {"system-log-out"_L1, @"person.crop.circle"},
//{"system-run"_L1, @""},
{"system-search"_L1, @"magnifyingglass"},
- //{"system-reboot"_L1, @""},
+ {"system-reboot"_L1, @"restart"},
{"system-shutdown"_L1, @"power"},
- //{"tools-check-spelling"_L1, @""},
+ {"tools-check-spelling"_L1, @"textformat.characters.dottedunderline"},
{"view-fullscreen"_L1, @"arrow.up.left.and.arrow.down.right"},
{"view-refresh"_L1, @"arrow.clockwise"},
{"view-restore"_L1, @"arrow.down.right.and.arrow.up.left"},
- //{"view-sort-ascending"_L1, @""},
- //{"view-sort-descending"_L1, @""},
+ {"view-sort-ascending"_L1, @"arrow.up"},
+ {"view-sort-descending"_L1, @"arrow.down"},
{"window-close"_L1, @"xmark.circle"},
{"window-new"_L1, @"macwindow.badge.plus"},
{"zoom-fit-best"_L1, @"square.arrowtriangle.4.outward"},
{"zoom-in"_L1, @"plus.magnifyingglass"},
- //{"zoom-original"_L1, @""},
+ {"zoom-original"_L1, @"1.magnifyingglass"},
{"zoom-out"_L1, @"minus.magnifyingglass"},
{"process-working"_L1, @"circle.dotted"},
- //{"accessories-calculator"_L1, @""},
- //{"accessories-character-map"_L1, @""},
+ {"accessories-calculator"_L1, @"plus.forwardslash.minus"},
+ {"accessories-character-map"_L1, @"keyboard.macwindow"},
{"accessories-dictionary"_L1, @"character.book.closed"},
{"accessories-text-editor"_L1, @"textformat"},
{"help-browser"_L1, @"folder.badge.questionmark"},
{"multimedia-volume-control"_L1, @"speaker.wave.3"},
{"preferences-desktop-accessibility"_L1, @"accessibility"},
- //{"preferences-desktop-font"_L1, @""},
- {"preferences-desktop-keyboard"_L1, @"keyboard.badge.ellipsis"},
- //{"preferences-desktop-locale"_L1, @""},
- //{"preferences-desktop-multimedia"_L1, @""},
- //{"preferences-desktop-screensaver"_L1, @""},
- //{"preferences-desktop-theme"_L1, @""},
- //{"preferences-desktop-wallpaper"_L1, @""},
+ {"preferences-desktop-font"_L1, @"textformat.characters"},
+ {"preferences-desktop-keyboard"_L1, @"keyboard"},
+ {"preferences-desktop-locale"_L1, @"mappin.and.ellipse"},
+ {"preferences-desktop-multimedia"_L1, @"music.note.tv"},
+ {"preferences-desktop-screensaver"_L1, @"display"},
+ {"preferences-desktop-theme"_L1, @"paintpalette"},
+ {"preferences-desktop-wallpaper"_L1, @"photo.tv"},
{"system-file-manager"_L1, @"folder.badge.gearshape"},
- //{"system-software-install"_L1, @""},
- //{"system-software-update"_L1, @""}, d
- //{"utilities-system-monitor"_L1, @""},
+ {"system-software-install"_L1, @"laptopcomputer.and.arrow.down"},
+ {"system-software-update"_L1, @"laptopcomputer.badge.checkmark"},
+ {"utilities-system-monitor"_L1, @"chart.bar.xaxis"},
{"utilities-terminal"_L1, @"apple.terminal"},
- //{"applications-accessories"_L1, @""},
- //{"applications-development"_L1, @""},
- //{"applications-engineering"_L1, @""},
- {"applications-games"_L1, @"gamecontroller"},
- //{"applications-graphics"_L1, @""},
+ {"applications-accessories"_L1, @"scanner"},
+ {"applications-development"_L1, @"hammer"},
+ {"applications-engineering"_L1, @"wrench.and.screwdriver"},
+ {"applications-games"_L1, @"gamecontroller.circle"},
+ {"applications-graphics"_L1, @"theatermask.and.paintbrush"},
{"applications-internet"_L1, @"network"},
{"applications-multimedia"_L1, @"tv.and.mediabox"},
- //{"applications-office"_L1, @""},
- //{"applications-other"_L1, @""},
+ {"applications-office"_L1, @"square.and.pencil.circle"},
+ {"applications-other"_L1, @"app.grid"},
{"applications-science"_L1, @"atom"},
- //{"applications-system"_L1, @""},
- //{"applications-utilities"_L1, @""},
+ {"applications-system"_L1, @"gear"},
+ {"applications-utilities"_L1, @"wrench.and.screwdriver"},
{"preferences-desktop"_L1, @"menubar.dock.rectangle"},
- //{"preferences-desktop-peripherals"_L1, @""},
- //{"preferences-desktop-personal"_L1, @""},
- //{"preferences-other"_L1, @""},
- //{"preferences-system"_L1, @""},
+ {"preferences-desktop-peripherals"_L1, @"iphone.and.ipod"},
+ {"preferences-desktop-personal"_L1, @"person.badge.key"},
+ {"preferences-other"_L1, @"gear"},
+ {"preferences-system"_L1, @"gear"},
{"preferences-system-network"_L1, @"network"},
{"system-help"_L1, @"questionmark.diamond"},
{"audio-card"_L1, @"waveform.circle"},
@@ -175,40 +177,40 @@ auto *loadImage(const QString &iconName)
{"drive-harddisk"_L1, @"internaldrive"},
{"drive-optical"_L1, @"opticaldiscdrive"},
{"drive-removable-media"_L1, @"externaldrive"},
- {"input-gaming"_L1, @"gamecontroller"}, // "games" also using this one
+ {"input-gaming"_L1, @"gamecontroller"},
{"input-keyboard"_L1, @"keyboard"},
{"input-mouse"_L1, @"computermouse"},
{"input-tablet"_L1, @"ipad"},
{"media-flash"_L1, @"mediastick"},
//{"media-floppy"_L1, @""},
- //{"media-optical"_L1, @""},
+ {"media-optical"_L1, @"opticaldisc"},
{"media-tape"_L1, @"recordingtape"},
- //{"modem"_L1, @""},
- {"multimedia-player"_L1, @"play.rectangle"},
+ {"modem"_L1, @"phone.connection"},
+ {"multimedia-player"_L1, @"ipod"},
{"network-wired"_L1, @"app.connected.to.app.below.fill"},
{"network-wireless"_L1, @"wifi"},
{"network-workgroup"_L1, @"network"},
- //{"pda"_L1, @""},
+ {"pda"_L1, @"flipphone"},
{"phone"_L1, @"iphone"},
{"printer"_L1, @"printer"},
{"scanner"_L1, @"scanner"},
{"video-display"_L1, @"play.display"},
- //{"emblem-default"_L1, @""},
+ {"emblem-default"_L1, @"circle"},
{"emblem-documents"_L1, @"doc.circle"},
{"emblem-downloads"_L1, @"arrow.down.circle"},
- {"emblem-favorite"_L1, @"star"},
- {"emblem-important"_L1, @"exclamationmark.bubble.circle"},
- {"emblem-mail"_L1, @"envelope"},
- {"emblem-photos"_L1, @"photo.stack"},
- //{"emblem-readonly"_L1, @""},
- {"emblem-shared"_L1, @"folder.badge.person.crop"},
+ {"emblem-favorite"_L1, @"star.circle"},
+ {"emblem-important"_L1, @"exclamationmark.circle"},
+ {"emblem-mail"_L1, @"envelope.circle"},
+ {"emblem-photos"_L1, @"photo.circle"},
+ {"emblem-readonly"_L1, @"eye.circle"},
+ {"emblem-shared"_L1, @"person.2.circle"},
{"emblem-symbolic-link"_L1, @"link.circle"},
{"emblem-synchronized"_L1, @"arrow.triangle.2.circlepath.circle"},
- {"emblem-system"_L1, @"gear"},
- //{"emblem-unreadable"_L1, @""},
+ {"emblem-system"_L1, @"gear.circle"},
+ {"emblem-unreadable"_L1, @"eye.slash.circle"},
{"text-x-generic"_L1, @"doc"}, // until iOS 18/macOS 15; @"document" after that
{"folder"_L1, @"folder"},
- //{"folder-remote"_L1, @""},
+ {"folder-remote"_L1, @"icloud"},
{"network-server"_L1, @"server.rack"},
//{"start-here"_L1, @""},
{"user-bookmarks"_L1, @"bookmark.circle"},
@@ -229,28 +231,28 @@ auto *loadImage(const QString &iconName)
{"dialog-question"_L1, @"questionmark.circle"},
{"dialog-warning"_L1, @"exclamationmark.octagon"},
{"folder-drag-accept"_L1, @"plus.rectangle.on.folder"},
- //{"folder-open"_L1, @""},
+ {"folder-open"_L1, @"arrow.forward.folder"},
{"folder-visiting"_L1, @"folder.circle"},
- {"image-loading"_L1, @"photo.circle"},
- {"image-missing"_L1, @"photo"},
+ {"image-loading"_L1, @"photo.badge.arrow.down"},
+ {"image-missing"_L1, @"photo.badge.exclamationmark"},
{"mail-attachment"_L1, @"paperclip"},
{"mail-unread"_L1, @"envelope.badge"},
{"mail-read"_L1, @"envelope.open"},
- {"mail-replied"_L1, @"arrowshape.turn.up.left"},
+ //{"mail-replied"_L1, @""},
//{"mail-signed"_L1, @""},
- //{"mail-signed-verified"_L1, @""},
- {"media-playlist-repeat"_L1, @"repet"},
+ {"mail-signed-verified"_L1, @"envelope.badge.shield.half.filled"},
+ {"media-playlist-repeat"_L1, @"repeat"},
{"media-playlist-shuffle"_L1, @"shuffle"},
- //{"network-error"_L1, @""},
- //{"network-idle"_L1, @""},
- {"network-offline"_L1, @"network.slash"},
- //{"network-receive"_L1, @""},
- //{"network-transmit"_L1, @""},
- //{"network-transmit-receive"_L1, @""},
+ {"network-error"_L1, @"xmark.icloud"},
+ {"network-idle"_L1, @"icloud"},
+ {"network-offline"_L1, @"icloud.slash"},
+ {"network-receive"_L1, @"icloud.and.arrow.down"},
+ {"network-transmit"_L1, @"icloud.and.arrow.up"},
+ {"network-transmit-receive"_L1, @"arrow.trianglehead.2.clockwise.rotate.90.icloud"},
//{"printer-error"_L1, @""},
- {"printer-printing"_L1, @"printer.dotmatrix.filled.and.paper"}, // not sure
- {"security-high"_L1, @"lock.shield"},
- //{"security-medium"_L1, @""},
+ {"printer-printing"_L1, @"printer.dotmatrix"},
+ {"security-high"_L1, @"lock.badge.checkmark"},
+ {"security-medium"_L1, @"lock"},
{"security-low"_L1, @"lock.trianglebadge.exclamationmark"},
{"software-update-available"_L1, @"arrowshape.up.circle"},
{"software-update-urgent"_L1, @"exclamationmark.transmission"},
@@ -258,9 +260,9 @@ auto *loadImage(const QString &iconName)
{"sync-synchronizing"_L1, @"arrow.triangle.2.circlepath"},
{"task-due"_L1, @"clock.badge.exclamationmark"},
{"task-past-due"_L1, @"clock.badge.xmark"},
- {"user-available"_L1, @"person.crop.circle.badge.checkmark"},
- {"user-away"_L1, @"person.crop.circle.badge.clock"},
- //{"user-idle"_L1, @""},
+ {"user-available"_L1, @"person.crop.circle.badge"},
+ {"user-away"_L1, @"person.crop.circle.badge.moon"},
+ {"user-idle"_L1, @"person.crop.circle.badge.clock"},
{"user-offline"_L1, @"person.crop.circle.badge.xmark"},
//{"user-trash-full"_L1, @""},
{"weather-clear"_L1, @"sun.max"},
@@ -269,9 +271,9 @@ auto *loadImage(const QString &iconName)
{"weather-few-clouds-night"_L1, @"cloud.moon"},
{"weather-fog"_L1, @"cloud.fog"},
{"weather-overcast"_L1, @"cloud"},
- //{"weather-severe-alert"_L1, @""},
- {"weather-showers"_L1, @"cloud.rain"},
- //{"weather-showers-scattered"_L1, @""},
+ {"weather-severe-alert"_L1, @"cloud.bolt.rain"},
+ {"weather-showers"_L1, @"cloud.heavyrain"},
+ {"weather-showers-scattered"_L1, @"cloud.drizzle"},
{"weather-snow"_L1, @"cloud.snow"},
{"weather-storm"_L1, @"tropicalstorm"},
};
diff --git a/src/gui/platform/darwin/qapplekeymapper.mm b/src/gui/platform/darwin/qapplekeymapper.mm
index 214865864ff..49f7a8ff0cb 100644
--- a/src/gui/platform/darwin/qapplekeymapper.mm
+++ b/src/gui/platform/darwin/qapplekeymapper.mm
@@ -94,60 +94,10 @@ static CarbonModifiers toCarbonModifiers(Qt::KeyboardModifiers qtModifiers)
return carbonModifiers;
}
-// Keyboard keys (non-modifiers)
-static QHash<char16_t, Qt::Key> standardKeys = {
- { kHomeCharCode, Qt::Key_Home },
- { kEnterCharCode, Qt::Key_Enter },
- { kEndCharCode, Qt::Key_End },
- { kBackspaceCharCode, Qt::Key_Backspace },
- { kTabCharCode, Qt::Key_Tab },
- { kPageUpCharCode, Qt::Key_PageUp },
- { kPageDownCharCode, Qt::Key_PageDown },
- { kReturnCharCode, Qt::Key_Return },
- { kEscapeCharCode, Qt::Key_Escape },
- { kLeftArrowCharCode, Qt::Key_Left },
- { kRightArrowCharCode, Qt::Key_Right },
- { kUpArrowCharCode, Qt::Key_Up },
- { kDownArrowCharCode, Qt::Key_Down },
- { kHelpCharCode, Qt::Key_Help },
- { kDeleteCharCode, Qt::Key_Delete },
- // ASCII maps, for debugging
- { ':', Qt::Key_Colon },
- { ';', Qt::Key_Semicolon },
- { '<', Qt::Key_Less },
- { '=', Qt::Key_Equal },
- { '>', Qt::Key_Greater },
- { '?', Qt::Key_Question },
- { '@', Qt::Key_At },
- { ' ', Qt::Key_Space },
- { '!', Qt::Key_Exclam },
- { '"', Qt::Key_QuoteDbl },
- { '#', Qt::Key_NumberSign },
- { '$', Qt::Key_Dollar },
- { '%', Qt::Key_Percent },
- { '&', Qt::Key_Ampersand },
- { '\'', Qt::Key_Apostrophe },
- { '(', Qt::Key_ParenLeft },
- { ')', Qt::Key_ParenRight },
- { '*', Qt::Key_Asterisk },
- { '+', Qt::Key_Plus },
- { ',', Qt::Key_Comma },
- { '-', Qt::Key_Minus },
- { '.', Qt::Key_Period },
- { '/', Qt::Key_Slash },
- { '[', Qt::Key_BracketLeft },
- { ']', Qt::Key_BracketRight },
- { '\\', Qt::Key_Backslash },
- { '_', Qt::Key_Underscore },
- { '`', Qt::Key_QuoteLeft },
- { '{', Qt::Key_BraceLeft },
- { '}', Qt::Key_BraceRight },
- { '|', Qt::Key_Bar },
- { '~', Qt::Key_AsciiTilde },
- { '^', Qt::Key_AsciiCircum }
-};
-
-static QHash<char16_t, Qt::Key> virtualKeys = {
+// NSEvent.keyCode codes for keys that are independent of keyboard layout.
+// Some of these are technically possible to add custom key maps for, but
+// doing so would be unexpected.
+static QHash<char16_t, Qt::Key> layoutIndependentKeyCodes = {
{ kVK_F1, Qt::Key_F1 },
{ kVK_F2, Qt::Key_F2 },
{ kVK_F3, Qt::Key_F3 },
@@ -164,16 +114,57 @@ static QHash<char16_t, Qt::Key> virtualKeys = {
{ kVK_F14, Qt::Key_F14 },
{ kVK_F15, Qt::Key_F15 },
{ kVK_F16, Qt::Key_F16 },
+ { kVK_F17, Qt::Key_F17 },
+ { kVK_F18, Qt::Key_F18 },
+ { kVK_F19, Qt::Key_F19 },
+ { kVK_F20, Qt::Key_F20 },
+
{ kVK_Return, Qt::Key_Return },
{ kVK_Tab, Qt::Key_Tab },
+ { kVK_Space, Qt::Key_Space },
{ kVK_Escape, Qt::Key_Escape },
- { kVK_Help, Qt::Key_Help },
+ { kVK_Delete, Qt::Key_Backspace },
+ { kVK_ForwardDelete, Qt::Key_Delete },
+
+ { kVK_Home, Qt::Key_Home },
+ { kVK_End, Qt::Key_End },
+ { kVK_PageUp, Qt::Key_PageUp },
+ { kVK_PageDown, Qt::Key_PageDown },
+
{ kVK_UpArrow, Qt::Key_Up },
{ kVK_DownArrow, Qt::Key_Down },
{ kVK_LeftArrow, Qt::Key_Left },
{ kVK_RightArrow, Qt::Key_Right },
- { kVK_PageUp, Qt::Key_PageUp },
- { kVK_PageDown, Qt::Key_PageDown }
+
+ { kVK_CapsLock, Qt::Key_CapsLock },
+ { kVK_Shift, Qt::Key_Shift },
+ { kVK_RightShift, Qt::Key_Shift },
+
+#if 0
+ // FIXME: Map these here instead of relying on
+ // custom logic in [QNSView flagsChanged:]
+
+ { kVK_Command, Qt::Key_unknown },
+ { kVK_RightCommand, Qt::Key_unknown },
+ { kVK_Option, Qt::Key_unknown },
+ { kVK_RightOption, Qt::Key_unknown },
+ { kVK_Control, Qt::Key_unknown },
+ { kVK_RightControl, Qt::Key_unknown },
+ { kVK_Function, Qt::Key_unknown },
+#endif
+
+ { kVK_VolumeUp, Qt::Key_VolumeUp },
+ { kVK_VolumeDown, Qt::Key_VolumeDown },
+ { kVK_Mute, Qt::Key_VolumeMute },
+
+#if 0
+ // FIXME: Figure out which Qt::Key this maps to
+ { kVK_ContextualMenu, Qt::Key_unknown },
+#endif
+ { kVK_Help, Qt::Key_Help },
+
+ { kVK_ANSI_KeypadClear, Qt::Key_Clear },
+ { kVK_ANSI_KeypadEnter, Qt::Key_Enter },
};
static QHash<char16_t, Qt::Key> functionKeys = {
@@ -211,41 +202,19 @@ static int toKeyCode(const QChar &key, int virtualKey, int modifiers)
qCDebug(lcQpaKeyMapperKeys, "Mapping key: %d (0x%04x) / vk %d (0x%04x)",
key.unicode(), key.unicode(), virtualKey, virtualKey);
- if (key == char16_t(kClearCharCode) && virtualKey == 0x47)
- return Qt::Key_Clear;
-
- if (key.isDigit()) {
- qCDebug(lcQpaKeyMapperKeys, "Got digit key: %d", key.digitValue());
- return key.digitValue() + Qt::Key_0;
- }
-
- if (key.isLetter()) {
- qCDebug(lcQpaKeyMapperKeys, "Got letter key: %d", (key.toUpper().unicode() - 'A'));
- return (key.toUpper().unicode() - 'A') + Qt::Key_A;
- }
- if (key.isSymbol()) {
- qCDebug(lcQpaKeyMapperKeys, "Got symbol key: %d", (key.unicode()));
- return key.unicode();
- }
-
- if (auto qtKey = standardKeys.value(key.unicode())) {
+ // Check first if we have a virtual key that should be treated as layout
+ // independent. If so, we want to return early without inspecting the key.
+ if (auto qtKey = layoutIndependentKeyCodes.value(virtualKey)) {
+ qCDebug(lcQpaKeyMapperKeys) << "Got" << qtKey << "based on layout independent virtual key";
// To work like Qt for X11 we issue Backtab when Shift + Tab are pressed
if (qtKey == Qt::Key_Tab && (modifiers & Qt::ShiftModifier)) {
- qCDebug(lcQpaKeyMapperKeys, "Got key: Qt::Key_Backtab");
+ qCDebug(lcQpaKeyMapperKeys, "Transformed into Qt::Key_Backtab");
return Qt::Key_Backtab;
}
-
- qCDebug(lcQpaKeyMapperKeys) << "Got" << qtKey;
- return qtKey;
- }
-
- // Last ditch try to match the scan code
- if (auto qtKey = virtualKeys.value(virtualKey)) {
- qCDebug(lcQpaKeyMapperKeys) << "Got scancode" << qtKey;
return qtKey;
}
- // Check if they belong to key codes in private unicode range
+ // Then check if the key is one of the functions keys in the private Unicode range
if (key >= char16_t(NSUpArrowFunctionKey) && key <= char16_t(NSModeSwitchFunctionKey)) {
if (auto qtKey = functionKeys.value(key.unicode())) {
qCDebug(lcQpaKeyMapperKeys) << "Got" << qtKey;
@@ -257,6 +226,20 @@ static int toKeyCode(const QChar &key, int virtualKey, int modifiers)
}
}
+ if (key.isDigit()) {
+ qCDebug(lcQpaKeyMapperKeys, "Got digit key: %d", key.digitValue());
+ return key.digitValue() + Qt::Key_0;
+ }
+
+ if (key.isLetter()) {
+ qCDebug(lcQpaKeyMapperKeys, "Got letter key: %d", (key.toUpper().unicode() - 'A'));
+ return (key.toUpper().unicode() - 'A') + Qt::Key_A;
+ }
+ if (key.isSymbol()) {
+ qCDebug(lcQpaKeyMapperKeys, "Got symbol key: %d", (key.unicode()));
+ return key.unicode();
+ }
+
qCDebug(lcQpaKeyMapperKeys, "Unknown case.. %d[%d] %d", key.unicode(), key.toLatin1(), virtualKey);
return Qt::Key_unknown;
}
diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp
index ec67ee80a1e..82632110d32 100644
--- a/src/network/kernel/qhostaddress.cpp
+++ b/src/network/kernel/qhostaddress.cpp
@@ -140,13 +140,6 @@ bool QHostAddressPrivate::parse(const QString &ipString)
return false;
}
-void QHostAddressPrivate::clear()
-{
- a = 0;
- protocol = QHostAddress::UnknownNetworkLayerProtocol;
- memset(&a6, 0, sizeof(a6));
-}
-
AddressClassification QHostAddressPrivate::classify() const
{
if (a) {
diff --git a/src/network/kernel/qhostaddress_p.h b/src/network/kernel/qhostaddress_p.h
index 6cc28cd5a9b..608080e9ede 100644
--- a/src/network/kernel/qhostaddress_p.h
+++ b/src/network/kernel/qhostaddress_p.h
@@ -74,7 +74,13 @@ public:
void setAddress(const Q_IPV6ADDR &a_);
bool parse(const QString &ipString);
- void clear();
+ void clear()
+ {
+ a6 = {};
+ a = 0;
+ protocol = QHostAddress::UnknownNetworkLayerProtocol;
+ scopeId.clear();
+ }
QString scopeId;
diff --git a/src/network/kernel/qnetworkinformation.cpp b/src/network/kernel/qnetworkinformation.cpp
index 80551b64633..5c4e65839c5 100644
--- a/src/network/kernel/qnetworkinformation.cpp
+++ b/src/network/kernel/qnetworkinformation.cpp
@@ -16,7 +16,6 @@
#include <algorithm>
#include <memory>
-#include <mutex>
QT_BEGIN_NAMESPACE
diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp
index 120d2ecbc78..430197ccc6e 100644
--- a/src/network/socket/qnativesocketengine_unix.cpp
+++ b/src/network/socket/qnativesocketengine_unix.cpp
@@ -33,7 +33,7 @@
#include <sys/socket.h>
#include <netinet/sctp.h>
#endif
-#ifdef Q_OS_BSD4
+#ifdef AF_LINK
# include <net/if_dl.h>
#endif
@@ -142,10 +142,6 @@ static void convertToLevelAndOption(QNativeSocketEngine::SocketOption opt,
level = IPPROTO_IP;
#ifdef IP_PKTINFO
n = IP_PKTINFO;
-#elif defined(IP_RECVDSTADDR)
- // variant found in QNX and FreeBSD; it will get us only the
- // destination address, not the interface; we need IP_RECVIF for that.
- n = IP_RECVDSTADDR;
#endif
}
break;
@@ -360,6 +356,18 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt
case QNativeSocketEngine::BindExclusively:
return true;
+ case QNativeSocketEngine::ReceivePacketInformation:
+ if (socketProtocol == QAbstractSocket::IPv4Protocol) {
+#if !defined(IP_PKTINFO) && defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
+ // Seen on FreeBSD and QNX. We need both to get the information we want.
+ int r = 0;
+ r += ::setsockopt(socketDescriptor, IPPROTO_IP, IP_RECVDSTADDR, &v, sizeof(v));
+ r += ::setsockopt(socketDescriptor, IPPROTO_IP, IP_RECVIF, &v, sizeof(v));
+ return r == 0;
+#endif
+ }
+ break;
+
case QNativeSocketEngine::MaxStreamsSocketOption: {
#ifndef QT_NO_SCTP
sctp_initmsg sctpInitMsg;
@@ -915,7 +923,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
{
// we use quintptr to force the alignment
quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int))
-#if !defined(IP_PKTINFO) && defined(IP_RECVIF) && defined(Q_OS_BSD4)
+#if !defined(IP_PKTINFO) && defined(IP_RECVIF) && defined(AF_LINK)
+ CMSG_SPACE(sizeof(sockaddr_dl))
#endif
#ifndef QT_NO_SCTP
@@ -1007,7 +1015,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS
header->destinationAddress.setAddress(ntohl(addr->s_addr));
}
# endif
-# if defined(IP_RECVIF) && defined(Q_OS_BSD4)
+# if defined(IP_RECVIF) && defined(AF_LINK)
if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVIF
&& cmsgptr->cmsg_len >= CMSG_LEN(sizeof(sockaddr_dl))) {
sockaddr_dl *sdl = reinterpret_cast<sockaddr_dl *>(CMSG_DATA(cmsgptr));
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index d4c5d0f0425..e0ef6cec794 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -161,7 +161,8 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
bool selectable = (m_options->acceptMode() == QFileDialogOptions::AcceptSave)
|| [self panel:m_panel shouldEnableURL:url];
- m_panel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
+ if (!openpanel_cast(m_panel))
+ m_panel.nameFieldStringValue = selectable ? info.fileName().toNSString() : @"";
[self updateProperties];
diff --git a/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm b/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
index 4e019b69cc4..6ca6554f673 100644
--- a/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
+++ b/src/plugins/platforms/ios/qiosdocumentpickercontroller.mm
@@ -7,8 +7,10 @@
#include "qiosdocumentpickercontroller.h"
+#include <QtCore/qpointer.h>
+
@implementation QIOSDocumentPickerController {
- QIOSFileDialog *m_fileDialog;
+ QPointer<QIOSFileDialog> m_fileDialog;
}
- (instancetype)initWithQIOSFileDialog:(QIOSFileDialog *)fileDialog
@@ -61,6 +63,9 @@
{
Q_UNUSED(controller);
+ if (!m_fileDialog)
+ return;
+
QList<QUrl> files;
for (NSURL* url in urls)
files.append(QUrl::fromNSURL(url));
@@ -71,12 +76,18 @@
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller
{
+ if (!m_fileDialog)
+ return;
+
Q_UNUSED(controller);
emit m_fileDialog->reject();
}
- (void)presentationControllerDidDismiss:(UIPresentationController *)presentationController
{
+ if (!m_fileDialog)
+ return;
+
Q_UNUSED(presentationController);
// "Called on the delegate when the user has taken action to dismiss the
diff --git a/src/plugins/platforms/wasm/qwasminputcontext.cpp b/src/plugins/platforms/wasm/qwasminputcontext.cpp
index 614d5bd25a3..18a457198f1 100644
--- a/src/plugins/platforms/wasm/qwasminputcontext.cpp
+++ b/src/plugins/platforms/wasm/qwasminputcontext.cpp
@@ -225,8 +225,8 @@ void QWasmInputContext::updateGeometry()
qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "propagating inputItemRectangle:" << inputItemRectangle;
m_inputElement["style"].set("left", std::to_string(inputItemRectangle.x()) + "px");
m_inputElement["style"].set("top", std::to_string(inputItemRectangle.y()) + "px");
- m_inputElement["style"].set("width", std::to_string(inputItemRectangle.width()) + "px");
- m_inputElement["style"].set("height", std::to_string(inputItemRectangle.height()) + "px");
+ m_inputElement["style"].set("width", "1px");
+ m_inputElement["style"].set("height", "1px");
}
}
diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp
index 25142612c4f..3b1b7a7eacb 100644
--- a/src/plugins/styles/modernwindows/qwindows11style.cpp
+++ b/src/plugins/styles/modernwindows/qwindows11style.cpp
@@ -923,15 +923,13 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption
case PE_IndicatorRadioButton: {
const bool isRtl = option->direction == Qt::RightToLeft;
const bool isOn = option->state & State_On;
- qreal innerRadius = 7.0f;
+ qreal innerRadius = radioButtonInnerRadius(state);
if (d->transitionsEnabled() && option->styleObject) {
if (option->styleObject->property("_q_end_radius").isNull())
option->styleObject->setProperty("_q_end_radius", innerRadius);
QNumberStyleAnimation *animation = qobject_cast<QNumberStyleAnimation *>(d->animation(option->styleObject));
innerRadius = animation ? animation->currentValue() : option->styleObject->property("_q_end_radius").toFloat();
option->styleObject->setProperty("_q_inner_radius", innerRadius);
- } else {
- innerRadius = radioButtonInnerRadius(state);
}
QRectF rect = isRtl ? option->rect.adjusted(0, 0, -2, 0) : option->rect.adjusted(2, 0, 0, 0);
@@ -2452,9 +2450,6 @@ void QWindows11Style::polish(QPalette& result)
SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::Text, result.text().color());
SET_IF_UNRESOLVED(QPalette::Inactive, QPalette::WindowText, result.windowText().color());
- if (highContrastTheme)
- result.setColor(QPalette::Active, QPalette::HighlightedText, result.windowText().color());
-
auto *d = const_cast<QWindows11StylePrivate *>(d_func());
d->m_titleBarMinIcon = QIcon();
d->m_titleBarMaxIcon = QIcon();
diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h
index ebb32238d67..ad3874bd4c9 100644
--- a/src/testlib/qtestcase.h
+++ b/src/testlib/qtestcase.h
@@ -430,7 +430,7 @@ namespace QTest
Q_TESTLIB_EXPORT int qExec(QObject *testObject, const QStringList &arguments);
#if QT_CONFIG(batch_test_support) || defined(Q_QDOC)
- using TestEntryFunction = int (*)(int, char **);
+ using TestEntryFunction = std::function<int(int, char **)>;
Q_TESTLIB_EXPORT void qRegisterTestCase(const QString &name, TestEntryFunction entryFunction);
#endif // QT_CONFIG(batch_test_support)
diff --git a/src/testlib/qtestregistry_p.h b/src/testlib/qtestregistry_p.h
index 85e236cd046..fcfa6c60701 100644
--- a/src/testlib/qtestregistry_p.h
+++ b/src/testlib/qtestregistry_p.h
@@ -26,7 +26,7 @@ QT_BEGIN_NAMESPACE
namespace QTest {
class TestRegistry {
public:
- using TestEntryFunction = int(*)(int argv, char** argc);
+ using TestEntryFunction = std::function<int(int, char **)>;
static TestRegistry* instance();
diff --git a/src/tools/macdeployqt/macdeployqt/main.cpp b/src/tools/macdeployqt/macdeployqt/main.cpp
index f5e6ab8f31a..ecbccdef2b3 100644
--- a/src/tools/macdeployqt/macdeployqt/main.cpp
+++ b/src/tools/macdeployqt/macdeployqt/main.cpp
@@ -77,7 +77,7 @@ int main(int argc, char **argv)
QStringList qmlDirs;
QStringList qmlImportPaths;
extern bool runCodesign;
- extern QString codesignIdentiy;
+ QString codesignIdentity = QStringLiteral("-");
extern bool hardenedRuntime;
bool noCodesignExplicit = false;
extern bool appstoreCompliant;
@@ -166,7 +166,7 @@ int main(int argc, char **argv)
return 1;
} else {
runCodesign = true;
- codesignIdentiy = argument.mid(index+1);
+ codesignIdentity = argument.mid(index + 1);
}
} else if (argument.startsWith(QByteArray("-sign-for-notarization"))) {
LogDebug() << "Argument found:" << argument;
@@ -182,7 +182,7 @@ int main(int argc, char **argv)
runCodesign = true;
hardenedRuntime = true;
secureTimestamp = true;
- codesignIdentiy = argument.mid(index+1);
+ codesignIdentity = argument.mid(index + 1);
}
} else if (argument.startsWith(QByteArray("-hardened-runtime"))) {
LogDebug() << "Argument found:" << argument;
@@ -273,7 +273,7 @@ int main(int argc, char **argv)
stripAppBinary(appBundlePath);
if (runCodesign)
- codesign(codesignIdentiy, appBundlePath);
+ codesign(codesignIdentity, appBundlePath);
if (dmg) {
LogNormal();
diff --git a/src/tools/macdeployqt/shared/shared.cpp b/src/tools/macdeployqt/shared/shared.cpp
index 4e81229ebf5..bd7f4fba854 100644
--- a/src/tools/macdeployqt/shared/shared.cpp
+++ b/src/tools/macdeployqt/shared/shared.cpp
@@ -30,7 +30,6 @@ bool runStripEnabled = true;
bool alwaysOwerwriteEnabled = false;
bool runCodesign = true;
QStringList librarySearchPath;
-QString codesignIdentiy = "-";
QString extraEntitlements;
bool hardenedRuntime = false;
bool secureTimestamp = false;
diff --git a/src/widgets/doc/images/designer-stylesheet-options.png b/src/widgets/doc/images/designer-stylesheet-options.png
deleted file mode 100644
index a6893e770bc..00000000000
--- a/src/widgets/doc/images/designer-stylesheet-options.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/designer-stylesheet-options.webp b/src/widgets/doc/images/designer-stylesheet-options.webp
new file mode 100644
index 00000000000..14d1ad368fc
--- /dev/null
+++ b/src/widgets/doc/images/designer-stylesheet-options.webp
Binary files differ
diff --git a/src/widgets/doc/images/designer-stylesheet-usage.png b/src/widgets/doc/images/designer-stylesheet-usage.png
deleted file mode 100644
index f6875900def..00000000000
--- a/src/widgets/doc/images/designer-stylesheet-usage.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/designer-stylesheet-usage.webp b/src/widgets/doc/images/designer-stylesheet-usage.webp
new file mode 100644
index 00000000000..79dd6803853
--- /dev/null
+++ b/src/widgets/doc/images/designer-stylesheet-usage.webp
Binary files differ
diff --git a/src/widgets/doc/images/designer-validator-highlighter.png b/src/widgets/doc/images/designer-validator-highlighter.png
deleted file mode 100644
index a6661d5c955..00000000000
--- a/src/widgets/doc/images/designer-validator-highlighter.png
+++ /dev/null
Binary files differ
diff --git a/src/widgets/doc/images/designer-validator-highlighter.webp b/src/widgets/doc/images/designer-validator-highlighter.webp
new file mode 100644
index 00000000000..7ca6cdf6eb3
--- /dev/null
+++ b/src/widgets/doc/images/designer-validator-highlighter.webp
Binary files differ
diff --git a/src/widgets/doc/src/modelview.qdoc b/src/widgets/doc/src/modelview.qdoc
index b2448a2c705..121cc30ed09 100644
--- a/src/widgets/doc/src/modelview.qdoc
+++ b/src/widgets/doc/src/modelview.qdoc
@@ -573,281 +573,10 @@
out of range when using ModelTest.
- \section1 4. Good Sources of Additional Information
-
- \section2 4.1 Books
-
- Model/View programming is covered quite extensively in the documentation of
- Qt but also in several good books.
-
- \list 1
- \li \b{C++ GUI Programming with Qt 4} / Jasmin Blanchette, Mark Summerfield,
- \e{Prentice Hall, 2nd edition}, ISBN 0-13-235416-0. Also available in
- German: \b{C++ GUI Programmierung mit Qt 4: Die offizielle Einführung},
- \e{Addison-Wesley}, ISBN 3-827327-29-6
- \li \b{The Book of Qt4, The Art of Building Qt Applications} / Daniel Molkentin,
- \e{Open Source Press}, ISBN 1-59327-147-6.
- Translated from \b{Qt 4, Einführung in die Applikationsentwicklung},
- \e{Open Source Press}, ISBN 3-937514-12-0.
- \li \b{Foundations of Qt Development} / Johan Thelin, \e{Apress}, ISBN 1-59059-831-8.
- \li \b{Advanced Qt Programming} / Mark Summerfield, \e{Prentice Hall}, ISBN 0-321-63590-6.
- This book covers Model/View programming on more than 150 pages.
- \endlist
-
- The following list provides an overview of example programs contained in the first three
- books listed above. Some of them make very good templates for developing similar
- applications.
-
- \table
- \header
- \li Example name
- \li View class used
- \li Model used
- \li Aspects covered
- \li
- \row
- \li Team Leaders
- \li QListview
- \li QStringListModel
- \li
- \li Book 1, Chapter 10, Figure 10.6
- \row
- \li Color Names
- \li QListView
- \li QSortFilterProxyModel
- applied to QStringListModel
- \li
- \li Book 1, Chapter 10, Figure 10.8
- \row
- \li Currencies
- \li QTableView
- \li custom model based on
- QAbstractTableModel
- \li Read only
- \li Book 1, Chapter 10, Figure 10.10
- \row
- \li Cities
- \li QTableView
- \li Custom model based on
- QAbstractTableModel
- \li Read / write
- \li Book 1, Chapter 10, Figure 10.12
- \row
- \li Boolean Parser
- \li QTreeView
- \li Custom model based on
- QAbstractItemModel
- \li Read only
- \li Book 1, Chapter 10, Figure 10.14
- \row
- \li Track Editor
- \li {2, 1} QTableWidget
- \li Custom delegate providing a custom editor
- \li Book 1, Chapter 10, Figure 10.15
-
- \row
- \li Address Book
- \li QListView
- QTableView
- QTreeView
- \li Custom model based on
- QAbstractTableModel
- \li Read / write
- \li Book2, Chapter 8.4
- \row
- \li Address Book with sorting
- \li
- \li QSortfilterProxyModel
- \li Introducing sort and filter capabilities
- \li Book2, Chapter 8.5
- \row
- \li Address Book
- with checkboxes
- \li
- \li
- \li Introducing checkboxes in model/view
- \li Book2, Chapter 8.6
- \row
- \li Address Book with transposed grid
- \li
- \li Custom proxy Model based on QAbstractProxyModel
- \li Introducing a custom model
- \li Book2, Chapter 8.7
- \row
- \li Address Book with drag and drop
- \li
- \li
- \li Introducing drag and drop support
- \li Book2, Chapter 8.8
- \row
- \li Address Book with custom editor
- \li
- \li
- \li Introducing custom delegates
- \li Book2, Chapter 8.9
- \row
- \li Views
- \li QListView
- QTableView
- QTreeView
- \li QStandardItemModel
- \li Read only
- \li Book 3, Chapter 5, figure 5-3
- \row
- \li Bardelegate
- \li QTableView
- \li
- \li Custom delegate for presentation based on QAbstractItemDelegate
- \li Book 3, Chapter 5, figure 5-5
- \row
- \li Editdelegate
- \li QTableView
- \li
- \li Custom delegate for editing based on QAbstractItemDelegate
- \li Book 3, Chapter 5, figure 5-6
- \row
- \li Singleitemview
- \li Custom view based on QAbstractItemView
- \li
- \li Custom view
- \li Book 3,
- Chapter 5,
- figure 5-7
- \row
- \li listmodel
- \li QTableView
- \li Custom Model based on QAbstractTableModel
- \li Read only
- \li Book 3, Chapter 5, Figure 5-8
- \row
- \li treemodel
- \li QTreeView
- \li Custom Model based on QAbstractItemModel
- \li Read only
- \li Book 3, Chapter 5, Figure 5-10
- \row
- \li edit integers
- \li QListView
- \li Custom Model based on QAbstractListModel
- \li Read / write
- \li Book 3, Chapter 5, Listing 5-37, Figure 5-11
- \row
- \li sorting
- \li QTableView
- \li QSortFilterProxyModel applied to QStringListModel
- \li Demonstrates sorting
- \li Book 3, Chapter 5, Figure 5-12
- \endtable
-
-
- \section2 4.2 Qt Documentation
-
- Qt 5.0 comes with 19 examples for model/view.
- The examples can be found on the \l{Item Views Examples} page.
-
- \table
- \header
- \li Example name
- \li View class used
- \li Model used
- \li Aspects covered
- \row
- \li Address Book
- \li QTableView
- \li QAbstractTableModel
- QSortFilterProxyModel
- \li Usage of QSortFilterProxyModel to generate different
- subsets from one data pool
- \row
- \li Basic Sort/Filter Model
- \li QTreeView
- \li QStandardItemModel
- QSortFilterProxyModel
- \li
- \row
- \li Chart
- \li Custom view
- \li QStandardItemModel
- \li Designing custom views that cooperate with selection models
- \row
- \li Color Editor Factory
- \li {2, 1} QTableWidget
- \li Enhancing the standard delegate with a new custom editor to choose colours
- \row
- \li Combo Widget Mapper
- \li QDataWidgetMapper to map QLineEdit, QTextEdit and QComboBox
- \li QStandardItemModel
- \li Shows how a QComboBox can serve as a view class
- \row
- \li Custom Sort/Filter Model
- \li QTreeView
- \li QStandardItemModel
- QSortFilterProxyModel
- \li Subclass QSortFilterProxyModel for advanced sorting and filtering
- \row
- \li Dir View
- \li QTreeView
- \li QFileSystemModel
- \li Very small example to demonstrate how to assign a model to a view
- \row
- \li Editable Tree Model
- \li QTreeView
- \li Custom tree model
- \li Comprehensive example for working with trees, demonstrates
- editing cells and tree structure with an underlying custom
- model
- \row
- \li Fetch More
- \li QListView
- \li Custom list model
- \li Dynamically changing model
- \row
- \li Frozen Column
- \li QTableView
- \li QStandardItemModel
- \li
- \row
- \li Interview
- \li Multiple
- \li Custom item model
- \li Multiple views
- \row
- \li Pixelator
- \li QTableView
- \li Custom table model
- \li Implementation of a custom delegate
- \row
- \li Puzzle
- \li QListView
- \li Custom list model
- \li Model/view with drag and drop
- \row
- \li Simple DOM Model
- \li QTreeView
- \li Custom tree model
- \li Read only example for a custom tree model
- \row
- \li Simple Tree Model
- \li QTreeView
- \li Custom tree model
- \li Read only example for a custom tree model
- \row
- \li Simple Widget Mapper
- \li QDataWidgetMapper to map QLineEdit, QTextEdit and QSpinBox
- \li QStandardItemModel
- \li Basic QDataWidgetMapper usage
- \row
- \li Spreadsheet
- \li {2, 1} QTableView
- \li Custom delegates
- \row
- \li Star Delegate
- \li {2, 1} QTableWidget
- \li Comprehensive custom delegate example.
- \endtable
+ \section1 Examples
- A \l{Model/View Programming}{reference document} for model/view technology
- is also available.
+ Qt comes with multiple examples for model/view. You can find them on the
+ \l{Item Views Examples} page.
*/
/*!
diff --git a/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc b/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc
index 841948b671f..84226fdb5b5 100644
--- a/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc
+++ b/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc
@@ -536,21 +536,20 @@
to preview style sheets. You can right-click on any widget in Designer
and select \uicontrol{Change styleSheet...} to set the style sheet.
- \image designer-stylesheet-options.png
+ \image designer-stylesheet-options.webp
{Editing a form in Qt Widgets Designer}
- In Qt 4.2 and later, \QD also includes a
- style sheet syntax highlighter and validator. The validator indicates
- if the syntax is valid or invalid, at the bottom left of the \uicontrol{Edit
- Style Sheet} dialog.
+ \QD also includes a style sheet syntax highlighter and validator. The
+ validator indicates if the syntax is valid or invalid, at the bottom left
+ of the \uicontrol{Edit Style Sheet} dialog.
- \image designer-validator-highlighter.png
+ \image designer-validator-highlighter.webp
{Editing and validating a stylesheet}
When you click \uicontrol{OK} or \uicontrol{Apply}, \QD will automatically display
the widget with its new stylesheet.
- \image designer-stylesheet-usage.png
+ \image designer-stylesheet-usage.webp
{Preview of a form with the new stylesheet}
*/
diff --git a/src/widgets/itemviews/qabstractitemview.h b/src/widgets/itemviews/qabstractitemview.h
index 973a9b044cb..ce509dc9e98 100644
--- a/src/widgets/itemviews/qabstractitemview.h
+++ b/src/widgets/itemviews/qabstractitemview.h
@@ -209,7 +209,7 @@ public:
virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const override;
- using QAbstractScrollArea::update;
+ using QWidget::update;
public Q_SLOTS:
virtual void reset();
diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp
index 82d16cb1252..b2cfb27e814 100644
--- a/src/widgets/styles/qstylesheetstyle.cpp
+++ b/src/widgets/styles/qstylesheetstyle.cpp
@@ -3419,29 +3419,28 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC
}
QRect gr = subControlRect(cc, opt, SC_SliderGroove, w);
- if (slider->subControls & SC_SliderGroove) {
+ if (slider->subControls & SC_SliderGroove)
grooveSubRule.drawRule(p, gr);
- }
if (slider->subControls & SC_SliderHandle) {
QRect hr = subControlRect(cc, opt, SC_SliderHandle, w);
- QRenderRule subRule1 = renderRule(w, opt, PseudoElement_SliderSubPage);
- if (subRule1.hasDrawable()) {
- QRect r(gr.topLeft(),
- slider->orientation == Qt::Horizontal
- ? QPoint(hr.x()+hr.width()/2, gr.y()+gr.height() - 1)
- : QPoint(gr.x()+gr.width() - 1, hr.y()+hr.height()/2));
- subRule1.drawRule(p, r);
- }
-
- QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SliderAddPage);
- if (subRule2.hasDrawable()) {
- QRect r(slider->orientation == Qt::Horizontal
- ? QPoint(hr.x()+hr.width()/2+1, gr.y())
- : QPoint(gr.x(), hr.y()+hr.height()/2+1),
- gr.bottomRight());
- subRule2.drawRule(p, r);
+ if (slider->subControls & SC_SliderGroove) {
+ const bool isHor = slider->orientation == Qt::Horizontal;
+ QRenderRule subRule1 = renderRule(w, opt, PseudoElement_SliderSubPage);
+ if (subRule1.hasDrawable()) {
+ QRect r(gr.topLeft(),
+ isHor ? QPoint(hr.x() + hr.width() / 2, gr.y() + gr.height() - 1)
+ : QPoint(gr.x() + gr.width() - 1, hr.y() + hr.height() / 2));
+ subRule1.drawRule(p, r);
+ }
+ QRenderRule subRule2 = renderRule(w, opt, PseudoElement_SliderAddPage);
+ if (subRule2.hasDrawable()) {
+ QRect r(isHor ? QPoint(hr.x() + hr.width() / 2 + 1, gr.y())
+ : QPoint(gr.x(), hr.y() + hr.height() / 2 + 1),
+ gr.bottomRight());
+ subRule2.drawRule(p, r);
+ }
}
handleSubRule.drawRule(p, handleSubRule.boxRect(hr, Margin));
diff --git a/src/widgets/widgets/qmdisubwindow.cpp b/src/widgets/widgets/qmdisubwindow.cpp
index 1ca6b8a47a1..7aff0da3327 100644
--- a/src/widgets/widgets/qmdisubwindow.cpp
+++ b/src/widgets/widgets/qmdisubwindow.cpp
@@ -2220,7 +2220,7 @@ QMdiSubWindow::QMdiSubWindow(QWidget *parent, Qt::WindowFlags flags)
d->titleBarPalette = d->desktopPalette();
d->font = QApplication::font("QMdiSubWindowTitleBar");
// We don't want the menu icon by default on mac.
-#ifndef Q_OS_MAC
+#ifndef Q_OS_DARWIN
if (windowIcon().isNull())
d->menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, nullptr, this);
else
@@ -2847,8 +2847,11 @@ bool QMdiSubWindow::event(QEvent *event)
break;
case QEvent::WindowIconChange:
d->menuIcon = windowIcon();
+ // We don't want the default menu icon on mac.
+#ifndef Q_OS_DARWIN
if (d->menuIcon.isNull())
d->menuIcon = style()->standardIcon(QStyle::SP_TitleBarMenuButton, nullptr, this);
+#endif
if (d->controlContainer)
d->controlContainer->updateWindowIcon(d->menuIcon);
if (!maximizedSystemMenuIconWidget())
diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp
index 69548c4e17e..92ff14dd44f 100644
--- a/src/widgets/widgets/qmenu.cpp
+++ b/src/widgets/widgets/qmenu.cpp
@@ -2972,7 +2972,7 @@ void QMenu::mouseReleaseEvent(QMouseEvent *e)
#endif
d->activateAction(action, QAction::Trigger);
}
- } else if ((!action || action->isEnabled()) && !action->isSeparator()) {
+ } else if (!action || (action->isEnabled() && !action->isSeparator())) {
d->hideUpToMenuBar();
}
}
diff --git a/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp b/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp
index ee50a311efa..185887e5d87 100644
--- a/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp
+++ b/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp
@@ -54,6 +54,7 @@ void tst_qxp_function_ref::basics()
{
Q_CONSTINIT static int invoked = 0;
+ invoked = 0;
auto lambda = [](int i) noexcept { ++invoked; return i; };
const qxp::function_ref<int(int)> f = lambda;
QCOMPARE(invoked, 0);
@@ -85,6 +86,7 @@ void tst_qxp_function_ref::basics()
}
{
Q_CONSTINIT static int invoked = 0;
+ invoked = 0;
auto lambda = [] { ++invoked; return 42; };
const qxp::function_ref<int()> f = lambda;
QCOMPARE(invoked, 0);
@@ -106,6 +108,7 @@ void tst_qxp_function_ref::basics()
}
{
Q_CONSTINIT static int invoked = 0;
+ invoked = 0;
auto lambda = [] { ++invoked; };
const qxp::function_ref<void()> f = lambda;
QCOMPARE(invoked, 0);
@@ -157,6 +160,7 @@ void tst_qxp_function_ref::constOverloads()
void tst_qxp_function_ref::constExpr()
{
Q_CONSTINIT static int invoked = 0;
+ invoked = 0;
{
Q_CONSTINIT static auto lambda = [] (int i) { ++invoked; return i; };
// the function object constructor is constexpr, so this should be constinit:
diff --git a/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp b/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp
index 593cae6ddfc..29b78415924 100644
--- a/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp
+++ b/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp
@@ -92,8 +92,8 @@ private slots:
void uncPaths();
#endif
#ifndef Q_OS_WIN
- void hiddenFiles();
- void hiddenDirs();
+ void hidden_data();
+ void hidden();
#endif
void withStdAlgorithms();
@@ -871,45 +871,46 @@ void tst_QDirListing::uncPaths()
// anything starting by a '.' is a hidden file.
// For that reason these two tests aren't run on Windows.
-void tst_QDirListing::hiddenFiles()
+void tst_QDirListing::hidden_data()
{
- QStringList expected = {
+ QTest::addColumn<QDirListing::IteratorFlags>("flags");
+ QTest::addColumn<QStringList>("expected");
+
+ using F = QDirListing::IteratorFlag;
+
+ QTest::newRow("Recursive-ExcludeDirs")
+ << (F::ExcludeDirs | F::IncludeHidden | F::Recursive)
+ << QStringList{
"hiddenDirs_hiddenFiles/.hiddenDirectory/.hiddenFile"_L1,
"hiddenDirs_hiddenFiles/.hiddenDirectory/normalFile"_L1,
"hiddenDirs_hiddenFiles/.hiddenFile"_L1,
"hiddenDirs_hiddenFiles/normalDirectory/.hiddenFile"_L1,
"hiddenDirs_hiddenFiles/normalDirectory/normalFile"_L1,
"hiddenDirs_hiddenFiles/normalFile"_L1,
- };
-
- constexpr auto flags = ItFlag::ExcludeDirs | ItFlag::IncludeHidden | ItFlag::Recursive;
- QStringList list;
- list.reserve(expected.size());
- for (const auto &dirEntry : QDirListing(u"hiddenDirs_hiddenFiles"_s, flags)) {
- QVERIFY(dirEntry.isFile());
- list.emplace_back(dirEntry.filePath());
- }
- list.sort();
-
- QCOMPARE_EQ(list, expected);
-}
+ };
-void tst_QDirListing::hiddenDirs()
-{
- QStringList expected = {
+ QTest::newRow("Recursive-ExcludeFiles")
+ << (F::ExcludeFiles | F::IncludeHidden | F::Recursive)
+ << QStringList{
"hiddenDirs_hiddenFiles/.hiddenDirectory"_L1,
"hiddenDirs_hiddenFiles/.hiddenDirectory/.hidden-subdir"_L1,
"hiddenDirs_hiddenFiles/.hiddenDirectory/subdir"_L1,
"hiddenDirs_hiddenFiles/normalDirectory"_L1,
"hiddenDirs_hiddenFiles/normalDirectory/.hidden-subdir"_L1,
"hiddenDirs_hiddenFiles/normalDirectory/subdir"_L1,
- };
+ };
+}
+
+void tst_QDirListing::hidden()
+{
+ QFETCH(QDirListing::IteratorFlags, flags);
+ QFETCH(QStringList, expected);
- constexpr auto flags = ItFlag::ExcludeFiles | ItFlag::IncludeHidden | ItFlag::Recursive;
QStringList list;
list.reserve(expected.size());
+ bool isDir = flags.testFlags(ItFlag::ExcludeFiles);
for (const auto &dirEntry : QDirListing(u"hiddenDirs_hiddenFiles"_s, flags)) {
- QVERIFY(dirEntry.isDir());
+ QVERIFY(isDir ? dirEntry.isDir() : dirEntry.isFile());
list.emplace_back(dirEntry.filePath());
}
list.sort();
diff --git a/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp b/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp
index 560d4196b28..6a898e7af0d 100644
--- a/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp
+++ b/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp
@@ -291,7 +291,7 @@ void tst_QProcessEnvironment::putenv()
static bool testRan = false;
if (testRan)
- QFAIL("You cannot run this test more than once, since we modify the environment");
+ QSKIP("You cannot run this test more than once, since we modify the environment");
testRan = true;
QByteArray valBefore = qgetenv(envname);
diff --git a/tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp b/tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp
index 4fb54581a6d..6dceb583469 100644
--- a/tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp
+++ b/tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp
@@ -464,7 +464,12 @@ void tst_QRandomAccessAsyncFile::errorHandling_data()
<< qint64(0) << QIOOperation::Error::FileNotOpen;
QTest::newRow("read_writeonly")
<< QIOOperation::Type::Read << QIODeviceBase::WriteOnly
- << qint64(0) << QIOOperation::Error::Read;
+ << qint64(0)
+#ifdef Q_OS_DARWIN
+ << QIOOperation::Error::FileNotOpen;
+#else
+ << QIOOperation::Error::Read;
+#endif
QTest::newRow("read_negative_offset")
<< QIOOperation::Type::Read << QIODeviceBase::ReadOnly
<< qint64(-1) << QIOOperation::Error::IncorrectOffset;
@@ -478,7 +483,12 @@ void tst_QRandomAccessAsyncFile::errorHandling_data()
<< qint64(0) << QIOOperation::Error::FileNotOpen;
QTest::newRow("write_readonly")
<< QIOOperation::Type::Write << QIODeviceBase::ReadOnly
- << qint64(0) << QIOOperation::Error::Write;
+ << qint64(0)
+#ifdef Q_OS_DARWIN
+ << QIOOperation::Error::FileNotOpen;
+#else
+ << QIOOperation::Error::Write;
+#endif
QTest::newRow("write_negative_offset")
<< QIOOperation::Type::Write << QIODeviceBase::WriteOnly
<< qint64(-1) << QIOOperation::Error::IncorrectOffset;
@@ -545,8 +555,9 @@ void tst_QRandomAccessAsyncFile::fileClosedInProgress()
}
constexpr qint64 OneMb = 1024 * 1024;
- std::array<QIOOperation *, 5> operations;
- std::array<QByteArray, 5> buffers;
+ constexpr size_t NumOps = 5;
+ std::array<QIOOperation *, NumOps> operations;
+ std::array<QByteArray, NumOps> buffers;
for (size_t i = 0; i < operations.size(); ++i) {
const qint64 offset = i * OneMb;
@@ -596,8 +607,9 @@ void tst_QRandomAccessAsyncFile::fileRemovedInProgress()
QFETCH(const QIOOperation::Type, operation);
constexpr qint64 OneMb = 1024 * 1024;
- std::array<QIOOperation *, 5> operations;
- std::array<QByteArray, 5> buffers;
+ constexpr size_t NumOps = 5;
+ std::array<QIOOperation *, NumOps> operations;
+ std::array<QByteArray, NumOps> buffers;
{
QRandomAccessAsyncFile file;
@@ -655,8 +667,9 @@ void tst_QRandomAccessAsyncFile::operationsDeletedInProgress()
}
constexpr qint64 OneMb = 1024 * 1024;
- std::array<QIOOperation *, 5> operations;
- std::array<QByteArray, 5> buffers;
+ constexpr size_t NumOps = 5;
+ std::array<QIOOperation *, NumOps> operations;
+ std::array<QByteArray, NumOps> buffers;
for (size_t i = 0; i < operations.size(); ++i) {
const qint64 offset = i * OneMb;
diff --git a/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp b/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp
index 472e03adcac..00672ef0b6a 100644
--- a/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp
+++ b/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp
@@ -678,8 +678,20 @@ void tst_QResourceEngine::registerNestedRccFile()
"/registeredNestedRccFile"));
QVERIFY2(QResource::registerResource(":/nestedrcc/runtime_resource.rcc",
"/registeredNestedRccFile"),
- "Second QResource::registerResource call failed.");
+ "Second QResource::registerResource call does not failed.");
QVERIFY(QFile::exists(":/registeredNestedRccFile/runtime_resource/search_file.txt"));
+
+ // clean up
+ QVERIFY(QResource::unregisterResource(":/nestedrcc/runtime_resource.rcc",
+ "/registeredNestedRccFile"));
+
+ QVERIFY(QFile::exists(":/registeredNestedRccFile/runtime_resource/search_file.txt"));
+
+ QVERIFY(QResource::unregisterResource(":/nestedrcc/runtime_resource.rcc",
+ "/registeredNestedRccFile"));
+
+ // verify clean up
+ QVERIFY(!QFile::exists(":/registeredNestedRccFile/runtime_resource/search_file.txt"));
}
QTEST_MAIN(tst_QResourceEngine)
diff --git a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
index 291b7136bce..bb7555f0329 100644
--- a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
+++ b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
@@ -1732,7 +1732,7 @@ void tst_QMetaObjectBuilder::usage_templateConnect()
testObject.data(), &TestObject::voidSlotInt));
// Something that isn't a signal
- QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in TestObject");
+ QTest::ignoreMessage(QtWarningMsg, "QObject::connect(TestObject, TestObject): signal not found");
con = QObject::connect(testObject.data(), &TestObject::setIntProp,
testObject.data(), &TestObject::intPropChanged);
QVERIFY(!con);
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
index 220d3af568b..afb0bf0169a 100644
--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
@@ -4864,18 +4864,18 @@ void tst_QObject::pointerConnect()
QVERIFY(!QObject::disconnect(con));
//connect a slot to a signal (== error)
- QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in ReceiverObject");
+ QTest::ignoreMessage(QtWarningMsg, "QObject::connect(ReceiverObject, SenderObject): signal not found");
con = connect(&r1, &ReceiverObject::slot4 , &s, &SenderObject::signal4);
QVERIFY(!con);
QVERIFY(!QObject::disconnect(con));
//connect an arbitrary PMF to a slot
- QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in ReceiverObject");
+ QTest::ignoreMessage(QtWarningMsg, "QObject::connect(ReceiverObject, ReceiverObject): signal not found");
con = connect(&r1, &ReceiverObject::reset, &r1, &ReceiverObject::slot1);
QVERIFY(!con);
QVERIFY(!QObject::disconnect(con));
- QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in ReceiverObject");
+ QTest::ignoreMessage(QtWarningMsg, "QObject::connect(ReceiverObject, ReceiverObject): signal not found");
con = connect(&r1, &ReceiverObject::reset, &r1, [](){});
QVERIFY(!con);
QVERIFY(!QObject::disconnect(con));
diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp
index adff512e6a3..81316b061d0 100644
--- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp
+++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp
@@ -45,11 +45,11 @@ using namespace std::chrono_literals;
class tst_QTimer : public QObject
{
Q_OBJECT
-public:
- static void initMain();
private slots:
+ void initTestCase();
void cleanupTestCase();
+
void zeroTimer();
void singleShotTimeout();
void timeout();
@@ -1678,11 +1678,11 @@ struct StaticSingleShotUser
};
// NOTE: to prevent any static initialization order fiasco, we implement
-// initMain() to instantiate staticSingleShotUser before qApp
+// initTestCase() to instantiate staticSingleShotUser before qApp
static StaticSingleShotUser *s_staticSingleShotUser = nullptr;
-void tst_QTimer::initMain()
+void tst_QTimer::initTestCase()
{
s_staticSingleShotUser = new StaticSingleShotUser;
}
diff --git a/tests/auto/corelib/serialization/json/tst_qtjson.cpp b/tests/auto/corelib/serialization/json/tst_qtjson.cpp
index 2e0d8dd7be2..dbaf6873af2 100644
--- a/tests/auto/corelib/serialization/json/tst_qtjson.cpp
+++ b/tests/auto/corelib/serialization/json/tst_qtjson.cpp
@@ -3595,7 +3595,7 @@ void tst_QtJson::bom()
QCOMPARE(error.error, QJsonParseError::NoError);
}
-void tst_QtJson::nesting()
+static void nesting_test()
{
// check that we abort parsing too deeply nested json documents.
// this is to make sure we don't crash because the parser exhausts the
@@ -3654,6 +3654,26 @@ void tst_QtJson::nesting()
}
+void tst_QtJson::nesting()
+{
+#if defined(Q_OS_QNX) || defined(Q_OS_VXWORKS) || defined(Q_OS_WASM)
+ // This test misbehaving probably indicates a stack overflow due to the
+ // recursive parser in qjsonparser.cpp. The recursion prevention limit may
+ // be too high for this platform. Someone should investigate.
+ QSKIP("Test freezes or crashes - probably a stack overflow");
+#endif
+
+ QThread *thr = QThread::create(nesting_test);
+#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) || \
+ defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)
+ // force a larger stack size - 8 MB seems sufficient
+ thr->setStackSize(8192 * 1024);
+#endif
+ thr->start();
+ thr->wait();
+ delete thr;
+}
+
void tst_QtJson::longStrings()
{
// test around 15 and 16 bit boundaries, as these are limits
diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
index 76fcee11b7b..806b6b43161 100644
--- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
+++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
@@ -3998,7 +3998,7 @@ void tst_QFuture::signalConnect()
#if defined(Q_CC_MSVC_ONLY) && (Q_CC_MSVC < 1940 || !defined(_DEBUG))
#define EXPECT_FUTURE_CONNECT_FAIL() QEXPECT_FAIL("", "QTBUG-101761, test fails on Windows/MSVC", Continue)
#else
- QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in SenderObject");
+ QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SenderObject, SenderObject): signal not found");
#define EXPECT_FUTURE_CONNECT_FAIL()
#endif
diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
index b03750389bd..8ec9cb516d3 100644
--- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp
+++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
@@ -3153,6 +3153,8 @@ qHash(const StdHashKeyType<HasQHash> &s, size_t seed)
template <typename T>
void stdHashImpl()
{
+ T::StdHashUsed = false;
+
QHash<T, int> hash;
for (int i = 0; i < 1000; ++i)
hash.insert(T{i}, i);
diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp
index e84c35691da..a19cebe3faf 100644
--- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp
+++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp
@@ -121,6 +121,84 @@ Q_DECLARE_TYPEINFO(Movable, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
Q_DECLARE_METATYPE(Movable);
+struct NoexceptMovable
+{
+ NoexceptMovable(char input = 'j') noexcept
+ : i(input)
+ {
+ counter.fetchAndAddRelaxed(1);
+ }
+ NoexceptMovable(const NoexceptMovable &other) noexcept
+ : i(other.i)
+ {
+ check(other.state, Constructed);
+ counter.fetchAndAddRelaxed(1);
+ }
+ NoexceptMovable(NoexceptMovable &&other) noexcept
+ : i(other.i)
+ {
+ check(other.state, Constructed);
+ counter.fetchAndAddRelaxed(1);
+ other.that = nullptr;
+ }
+
+ ~NoexceptMovable() // implicitly noexcept
+ {
+ check(state, Constructed);
+ i = 0;
+ counter.fetchAndAddRelaxed(-1);
+ state = Destructed; // this is likely a dead store
+ }
+
+ bool operator ==(const NoexceptMovable &other) const noexcept
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ return i == other.i;
+ }
+
+ NoexceptMovable &operator=(const NoexceptMovable &other) noexcept
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ i = other.i;
+ that = this;
+ return *this;
+ }
+ NoexceptMovable &operator=(NoexceptMovable &&other) noexcept
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ i = other.i;
+ that = other.that;
+ other.that = nullptr;
+ return *this;
+ }
+ bool wasConstructedAt(const NoexceptMovable *other) const noexcept
+ {
+ return that == other;
+ }
+ char i;
+ static inline QAtomicInt counter;
+private:
+ NoexceptMovable *that = this; // used to check if an instance was moved
+
+ enum State { Constructed = 106, Destructed = 110 };
+ State state = Constructed;
+
+ static void check(const State state1, const State state2) noexcept
+ {
+ QCOMPARE(state1, state2);
+ }
+
+ friend inline size_t qHash(const NoexceptMovable &key, size_t seed) noexcept
+ { return qHash(key.i, seed); }
+};
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(NoexceptMovable, Q_RELOCATABLE_TYPE);
+QT_END_NAMESPACE
+
struct Custom {
Custom(char input = 'j')
: i(input)
@@ -225,37 +303,47 @@ private slots:
void constructors_reserveAndInitialize() const;
void copyConstructorInt() const { copyConstructor<int>(); }
void copyConstructorMovable() const { copyConstructor<Movable>(); }
+ void copyConstructorNoexceptMovable() const { copyConstructor<NoexceptMovable>(); }
void copyConstructorCustom() const { copyConstructor<Custom>(); }
void assignmentInt() const { testAssignment<int>(); }
void assignmentMovable() const { testAssignment<Movable>(); }
+ void assignmentNoexceptMovable() const { testAssignment<NoexceptMovable>(); }
void assignmentCustom() const { testAssignment<Custom>(); }
void assignFromInitializerListInt() const { assignFromInitializerList<int>(); }
void assignFromInitializerListMovable() const { assignFromInitializerList<Movable>(); }
+ void assignFromInitializerListNoexceptMovable() const { assignFromInitializerList<NoexceptMovable>(); }
void assignFromInitializerListCustom() const { assignFromInitializerList<Custom>(); }
void addInt() const { add<int>(); }
void addMovable() const { add<Movable>(); }
+ void addNoexceptMovable() const { add<NoexceptMovable>(); }
void addCustom() const { add<Custom>(); }
void appendInt() const { append<int>(); }
void appendMovable() const { append<Movable>(); }
+ void appendNoexceptMovable() const { append<NoexceptMovable>(); }
void appendCustom() const { append<Custom>(); }
void appendRvalue() const;
void appendList() const;
void assignEmpty() const;
void assignInt() const { assign<int>(); }
void assignMovable() const { assign<Movable>(); }
+ void assignNoexceptMovable() const { assign<NoexceptMovable>(); }
void assignCustom() const { assign<Custom>(); }
void assignUsesPrependBuffer_int_data() { assignUsesPrependBuffer_data(); }
void assignUsesPrependBuffer_int() const { assignUsesPrependBuffer<int>(); }
void assignUsesPrependBuffer_Movable_data() { assignUsesPrependBuffer_data(); }
void assignUsesPrependBuffer_Movable() const { assignUsesPrependBuffer<Movable>(); }
+ void assignUsesPrependBuffer_NoexceptMovable_data() { assignUsesPrependBuffer_data(); }
+ void assignUsesPrependBuffer_NoexceptMovable() const { assignUsesPrependBuffer<NoexceptMovable>(); }
void assignUsesPrependBuffer_Custom_data() { assignUsesPrependBuffer_data(); }
void assignUsesPrependBuffer_Custom() const { assignUsesPrependBuffer<Custom>(); }
void at() const;
void capacityInt() const { capacity<int>(); }
void capacityMovable() const { capacity<Movable>(); }
+ void capacityNoexceptMovable() const { capacity<NoexceptMovable>(); }
void capacityCustom() const { capacity<Custom>(); }
void clearInt() const { clear<int>(); }
void clearMovable() const { clear<Movable>(); }
+ void clearNoexceptMovable() const { clear<NoexceptMovable>(); }
void clearCustom() const { clear<Custom>(); }
void constData() const;
void constFirst() const;
@@ -263,43 +351,54 @@ private slots:
void contains() const;
void countInt() const { count<int>(); }
void countMovable() const { count<Movable>(); }
+ void countNoexceptMovable() const { count<NoexceptMovable>(); }
void countCustom() const { count<Custom>(); }
void cpp17ctad() const;
void data() const;
void reinterpreted() const;
void emptyInt() const { empty<int>(); }
void emptyMovable() const { empty<Movable>(); }
+ void emptyNoexceptMovable() const { empty<NoexceptMovable>(); }
void emptyCustom() const { empty<Custom>(); }
void endsWith() const;
void eraseEmptyInt() const { eraseEmpty<int>(); }
void eraseEmptyMovable() const { eraseEmpty<Movable>(); }
+ void eraseEmptyNoexceptMovable() const { eraseEmpty<NoexceptMovable>(); }
void eraseEmptyCustom() const { eraseEmpty<Custom>(); }
void eraseEmptyReservedInt() const { eraseEmptyReserved<int>(); }
void eraseEmptyReservedMovable() const { eraseEmptyReserved<Movable>(); }
+ void eraseEmptyReservedNoexceptMovable() const { eraseEmptyReserved<NoexceptMovable>(); }
void eraseEmptyReservedCustom() const { eraseEmptyReserved<Custom>(); }
void eraseInt() const { erase<int>(false); }
void eraseIntShared() const { erase<int>(true); }
void eraseMovable() const { erase<Movable>(false); }
+ void eraseNoexceptMovable() const { erase<NoexceptMovable>(false); }
void eraseMovableShared() const { erase<Movable>(true); }
+ void eraseNoexceptMovableShared() const { erase<NoexceptMovable>(true); }
void eraseCustom() const { erase<Custom>(false); }
void eraseCustomShared() const { erase<Custom>(true); }
void eraseReservedInt() const { eraseReserved<int>(); }
void eraseReservedMovable() const { eraseReserved<Movable>(); }
+ void eraseReservedNoexceptMovable() const { eraseReserved<NoexceptMovable>(); }
void eraseReservedCustom() const { eraseReserved<Custom>(); }
void fillInt() const { fill<int>(); }
void fillMovable() const { fill<Movable>(); }
+ void fillNoexceptMovable() const { fill<NoexceptMovable>(); }
void fillCustom() const { fill<Custom>(); }
void fillDetachInt() const { fillDetach<int>(); }
void fillDetachMovable() const { fillDetach<Movable>(); }
+ void fillDetachNoexceptMovable() const { fillDetach<NoexceptMovable>(); }
void fillDetachCustom() const { fillDetach<Custom>(); }
void first() const;
void freeSpaceAtBeginEventuallyShrinks() const;
void fromListInt() const { fromList<int>(); }
void fromListMovable() const { fromList<Movable>(); }
+ void fromListNoexceptMovable() const { fromList<NoexceptMovable>(); }
void fromListCustom() const { fromList<Custom>(); }
void indexOf() const;
void insertInt() const { insert<int>(); }
void insertMovable() const { insert<Movable>(); }
+ void insertNoexceptMovable() const { insert<NoexceptMovable>(); }
void insertCustom() const { insert<Custom>(); }
void insertZeroCount_data();
void insertZeroCount() const;
@@ -310,17 +409,21 @@ private slots:
void sliced() const;
void moveInt() const { move<int>(); }
void moveMovable() const { move<Movable>(); }
+ void moveNoexceptMovable() const { move<NoexceptMovable>(); }
void moveCustom() const { move<Custom>(); }
void prependInt() const { prepend<int>(); }
void prependMovable() const { prepend<Movable>(); }
+ void prependNoexceptMovable() const { prepend<NoexceptMovable>(); }
void prependCustom() const { prepend<Custom>(); }
void prependRvalue() const;
void qhashInt() const { qhash<int>(); }
void qhashMovable() const { qhash<Movable>(); }
+ void qhashNoexceptMovable() const { qhash<NoexceptMovable>(); }
void qhashCustom() const { qhash<Custom>(); }
void removeAllWithAlias() const;
void removeInt() const { remove<int>(); }
void removeMovable() const { remove<Movable>(); }
+ void removeNoexceptMovable() const { remove<NoexceptMovable>(); }
void removeCustom() const { remove<Custom>(); }
void removeFirstLast() const;
void resizePOD_data() const;
@@ -339,10 +442,12 @@ private slots:
void reverseIterators() const;
void sizeInt() const { size<int>(); }
void sizeMovable() const { size<Movable>(); }
+ void sizeNoexceptMovable() const { size<NoexceptMovable>(); }
void sizeCustom() const { size<Custom>(); }
void startsWith() const;
void swapInt() const { swap<int>(); }
void swapMovable() const { swap<Movable>(); }
+ void swapNoexceptMovable() const { swap<NoexceptMovable>(); }
void swapCustom() const { swap<Custom>(); }
void toAddress() const;
void toList() const;
@@ -356,10 +461,12 @@ private slots:
void reserveZero();
void initializeListInt() { initializeList<int>(); }
void initializeListMovable() { initializeList<Movable>(); }
+ void initializeListNoexceptMovable() { initializeList<NoexceptMovable>(); }
void initializeListCustom() { initializeList<Custom>(); }
void const_shared_null();
void detachInt() const { detach<int>(); }
void detachMovable() const { detach<Movable>(); }
+ void detachNoexceptMovable() const { detach<NoexceptMovable>(); }
void detachCustom() const { detach<Custom>(); }
void detachThreadSafetyInt() const;
void detachThreadSafetyMovable() const;
@@ -369,9 +476,11 @@ private slots:
void emplaceInt() { emplaceImpl<int>(); }
void emplaceCustom() { emplaceImpl<Custom>(); }
void emplaceMovable() { emplaceImpl<Movable>(); }
+ void emplaceNoexceptMovable() { emplaceImpl<NoexceptMovable>(); }
void emplaceConsistentWithStdVectorInt() { emplaceConsistentWithStdVectorImpl<int>(); }
void emplaceConsistentWithStdVectorCustom() { emplaceConsistentWithStdVectorImpl<Custom>(); }
void emplaceConsistentWithStdVectorMovable() { emplaceConsistentWithStdVectorImpl<Movable>(); }
+ void emplaceConsistentWithStdVectorNoexceptMovable() { emplaceConsistentWithStdVectorImpl<NoexceptMovable>(); }
void emplaceConsistentWithStdVectorQString() { emplaceConsistentWithStdVectorImpl<QString>(); }
void emplaceReturnsIterator();
void emplaceFront() const;
@@ -383,35 +492,45 @@ private slots:
void replaceInt() const { replace<int>(); }
void replaceCustom() const { replace<Custom>(); }
void replaceMovable() const { replace<Movable>(); }
+ void replaceNoexceptMovable() const { replace<NoexceptMovable>(); }
void fromReadOnlyData() const;
void reallocateCustomAlignedType_qtbug90359() const;
void reinsertToBeginInt_qtbug91360() const { reinsertToBegin<int>(); }
void reinsertToBeginMovable_qtbug91360() const { reinsertToBegin<Movable>(); }
+ void reinsertToBeginNoexceptMovable_qtbug91360() const { reinsertToBegin<NoexceptMovable>(); }
void reinsertToBeginCustom_qtbug91360() const { reinsertToBegin<Custom>(); }
void reinsertToEndInt_qtbug91360() const { reinsertToEnd<int>(); }
void reinsertToEndMovable_qtbug91360() const { reinsertToEnd<Movable>(); }
+ void reinsertToEndNoexceptMovable_qtbug91360() const { reinsertToEnd<NoexceptMovable>(); }
void reinsertToEndCustom_qtbug91360() const { reinsertToEnd<Custom>(); }
void reinsertRangeToEndInt_qtbug91360() const { reinsertRangeToEnd<int>(); }
void reinsertRangeToEndMovable_qtbug91360() const { reinsertRangeToEnd<Movable>(); }
+ void reinsertRangeToEndNoexceptMovable_qtbug91360() const { reinsertRangeToEnd<NoexceptMovable>(); }
void reinsertRangeToEndCustom_qtbug91360() const { reinsertRangeToEnd<Custom>(); }
// QList reference stability tests:
void stability_reserveInt() const { stability_reserve<int>(); }
void stability_reserveMovable() const { stability_reserve<Movable>(); }
+ void stability_reserveNoexceptMovable() const { stability_reserve<NoexceptMovable>(); }
void stability_reserveCustom() const { stability_reserve<Custom>(); }
void stability_eraseInt() const { stability_erase<int>(); }
void stability_eraseMovable() const { stability_erase<Movable>(); }
+ void stability_eraseNoexceptMovable() const { stability_erase<NoexceptMovable>(); }
void stability_eraseCustom() const { stability_erase<Custom>(); }
void stability_appendInt() const { stability_append<int>(); }
void stability_appendMovable() const { stability_append<Movable>(); }
+ void stability_appendNoexceptMovable() const { stability_append<NoexceptMovable>(); }
void stability_appendCustom() const { stability_append<Custom>(); }
void stability_insertElementInt() const { stability_insertElement<int>(); }
void stability_insertElementMovable() const { stability_insertElement<Movable>(); }
+ void stability_insertElementNoexceptMovable() const { stability_insertElement<NoexceptMovable>(); }
void stability_insertElementCustom() const { stability_insertElement<Custom>(); }
void stability_emplaceInt() const { stability_emplace<int>(); }
void stability_emplaceMovable() const { stability_emplace<Movable>(); }
+ void stability_emplaceNoexceptMovable() const { stability_emplace<NoexceptMovable>(); }
void stability_emplaceCustom() const { stability_emplace<Custom>(); }
void stability_resizeInt() const { stability_resize<int>(); }
void stability_resizeMovable() const { stability_resize<Movable>(); }
+ void stability_resizeNoexceptMovable() const { stability_resize<NoexceptMovable>(); }
void stability_resizeCustom() const { stability_resize<Custom>(); }
private:
@@ -515,16 +634,9 @@ template<typename T> struct SimpleValue
}
static const uint MaxIndex = 6;
- static const T Values[MaxIndex];
+ static inline const T Values[MaxIndex] = { 110, 105, 101, 114, 111, 98 };
};
-template<>
-const int SimpleValue<int>::Values[] = { 110, 105, 101, 114, 111, 98 };
-template<>
-const Movable SimpleValue<Movable>::Values[] = { 110, 105, 101, 114, 111, 98 };
-template<>
-const Custom SimpleValue<Custom>::Values[] = { 110, 105, 101, 114, 111, 98 };
-
// Make some macros for the tests to use in order to be slightly more readable...
#define T_FOO SimpleValue<T>::at(0)
#define T_BAR SimpleValue<T>::at(1)
@@ -656,12 +768,36 @@ void tst_QList::assignFromInitializerList() const
T val2(SimpleValue<T>::at(2));
T val3(SimpleValue<T>::at(3));
- QList<T> v1 = {val1, val2, val3};
+ QList<T> v1 = {};
+ QCOMPARE(v1.size(), 0);
+
+ v1 = {val1, val2, val3};
QCOMPARE(v1, QList<T>() << val1 << val2 << val3);
QCOMPARE(v1, (QList<T> {val1, val2, val3}));
v1 = {};
QCOMPARE(v1.size(), 0);
+
+ // repeat, but make v1 shared before we assign
+ QList v2 = {val3, val1, val2};
+ v1 = v2;
+ v1 = {val1, val2, val3};
+ QCOMPARE(v1, QList<T>() << val1 << val2 << val3);
+ QCOMPARE(v1, (QList<T> {val1, val2, val3}));
+ v1 = v2;
+ v1 = {};
+ QCOMPARE(v1.size(), 0);
+
+ // repeat again, but now detached copies
+ v1 = v2;
+ v1.detach();
+ v1 = {val1, val2, val3};
+ QCOMPARE(v1, QList<T>() << val1 << val2 << val3);
+ QCOMPARE(v1, (QList<T> {val1, val2, val3}));
+ v1 = v2;
+ v1.detach();
+ v1 = {};
+ QCOMPARE(v1.size(), 0);
}
template<typename T>
@@ -834,6 +970,65 @@ void tst_QList::assign() const
QVERIFY(!myvecCopy.isSharedWith(myvec));
QCOMPARE(myvecCopy, QList<T>() << T_FOO << T_FOO);
}
+
+ // test assigning an empty range to an empty list
+ {
+ QList<T> myvec, empty;
+
+ const T *ptr = nullptr;
+ myvec.assign(ptr, ptr);
+ QVERIFY(myvec.isEmpty());
+
+ ptr = SimpleValue<T>::Values + 3;
+ myvec.assign(ptr, ptr);
+ QVERIFY(myvec.isEmpty());
+ }
+
+ // test assigning empty to non-empty
+ {
+ QList<T> nonempty = SimpleValue<T>::vector(2);
+ QList<T> myvec;
+
+ const T *ptr = nullptr;
+ myvec = nonempty;
+ myvec.assign(ptr, ptr);
+ QVERIFY(myvec.isEmpty());
+
+ ptr = SimpleValue<T>::Values + 3;
+ myvec = nonempty;
+ myvec.assign(ptr, ptr);
+ QVERIFY(myvec.isEmpty());
+
+ // repeat, after having detached
+ ptr = nullptr;
+ myvec = nonempty;
+ myvec.detach();
+ myvec.assign(ptr, ptr);
+ QVERIFY(myvec.isEmpty());
+
+ ptr = SimpleValue<T>::Values + 3;
+ myvec = nonempty;
+ myvec.detach();
+ myvec.assign(ptr, ptr);
+ QVERIFY(myvec.isEmpty());
+ }
+
+ // assign a smaller range
+ {
+ QList<T> myvec = SimpleValue<T>::vector(3);
+ QCOMPARE(myvec.size(), 3);
+
+ myvec.assign(SimpleValue<T>::Values + 3, SimpleValue<T>::Values + 5);
+ QCOMPARE(myvec.size(), 2);
+ QCOMPARE(myvec.at(0), T_CAT);
+ QCOMPARE(myvec.at(1), T_DOG);
+
+ // with detaching:
+ QList copy = myvec;
+ myvec.assign(SimpleValue<T>::Values, SimpleValue<T>::Values + 1);
+ QCOMPARE(myvec.size(), 1);
+ QCOMPARE(myvec.at(0), T_FOO);
+ }
}
inline namespace Scenarios {
@@ -2108,10 +2303,15 @@ void tst_QList::qhash() const
TST_QLIST_CHECK_LEAKS(T)
QList<T> l1, l2;
- QCOMPARE(qHash(l1), qHash(l2));
+ QCOMPARE(qHash(l1, 0), qHash(l2, 0));
l1 << SimpleValue<T>::at(0);
l2 << SimpleValue<T>::at(0);
- QCOMPARE(qHash(l1), qHash(l2));
+ QCOMPARE(qHash(l1, 0), qHash(l2, 0));
+
+ QCOMPARE(qHash(l1, 1), qHash(l2, 1));
+ l1.clear();
+ l2.clear();
+ QCOMPARE(qHash(l1, 1), qHash(l2, 1));
}
template <typename T>
diff --git a/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp b/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp
index 1dadbb9efea..b3f96588304 100644
--- a/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp
+++ b/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp
@@ -26,6 +26,8 @@ private Q_SLOTS:
void optionalGuard();
void leavingScope();
void exceptions();
+
+ void init();
};
void func()
@@ -169,7 +171,6 @@ void tst_QScopeGuard::leavingScope()
void tst_QScopeGuard::exceptions()
{
- s_globalState = 0;
bool caught = false;
QT_TRY
{
@@ -187,5 +188,10 @@ void tst_QScopeGuard::exceptions()
}
+void tst_QScopeGuard::init()
+{
+ s_globalState = 0;
+}
+
QTEST_MAIN(tst_QScopeGuard)
#include "tst_qscopeguard.moc"
diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
index 9c61cb503fb..f7c5af53310 100644
--- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
+++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
@@ -3250,7 +3250,6 @@ void tst_QWindow::enterLeaveOnWindowShowHide()
++expectedEnter;
QTRY_COMPARE_WITH_TIMEOUT(window.numEnterEvents, expectedEnter, 250);
QCOMPARE(window.enterPosition, window.mapFromGlobal(QCursor::pos()));
- QCOMPARE(QGuiApplicationPrivate::lastCursorPosition, cursorPos);
QWindow secondary;
secondary.setFlag(windowType);
diff --git a/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp b/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp
index bd9e00fc376..7b4193e3749 100644
--- a/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp
+++ b/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp
@@ -86,6 +86,9 @@ private slots:
void intersectionPointOnEdge();
void boundsAtStartPoint();
+
+ void percentAtEmptyPath_data();
+ void percentAtEmptyPath();
};
void tst_QPainterPath::cleanupTestCase()
@@ -1637,6 +1640,29 @@ void tst_QPainterPath::boundsAtStartPoint()
QCOMPARE(constructedPath.controlPointRect(), defaultPath.controlPointRect());
}
+void tst_QPainterPath::percentAtEmptyPath_data()
+{
+ const QPointF qpf(2., 2.);
+ QTest::addColumn<QPainterPath>("path");
+
+ QTest::newRow("defaultConstructed") << QPainterPath();
+ QTest::newRow("withStartPoint") << QPainterPath(qpf);
+ QPainterPath pp(qpf);
+ pp.lineTo(qpf);
+ QTest::newRow("equalPoints") << pp;
+}
+
+void tst_QPainterPath::percentAtEmptyPath()
+{
+ QFETCH(QPainterPath, path);
+
+ path.angleAtPercent(0.5);
+ path.pointAtPercent(0.5);
+ path.slopeAtPercent(0.5);
+
+ path.percentAtLength(0);
+}
+
QTEST_APPLESS_MAIN(tst_QPainterPath)
#include "tst_qpainterpath.moc"
diff --git a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp
index 0d2b7bfde64..7417f0648e4 100644
--- a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp
+++ b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp
@@ -30,6 +30,7 @@ public:
tst_QHostAddress();
private slots:
+ void constructor();
void constructor_QString_data();
void constructor_QString();
void setAddress_QString_data();
@@ -62,6 +63,43 @@ tst_QHostAddress::tst_QHostAddress()
qRegisterMetaType<QHostAddress>("QHostAddress");
}
+static void verifyClear(const QHostAddress &addr)
+{
+ QVERIFY(addr.isNull());
+ QVERIFY(!addr.isLoopback());
+ QVERIFY(!addr.isGlobal());
+ QVERIFY(!addr.isLinkLocal());
+ QVERIFY(!addr.isSiteLocal());
+ QVERIFY(!addr.isUniqueLocalUnicast());
+ QVERIFY(!addr.isMulticast());
+ QVERIFY(!addr.isBroadcast());
+ QVERIFY(!addr.isPrivateUse());
+ QCOMPARE(addr, QHostAddress());
+ QCOMPARE(addr, QHostAddress::Null);
+ QCOMPARE(addr.protocol(), QHostAddress::UnknownNetworkLayerProtocol);
+
+ bool ok = true;
+ QCOMPARE(addr.toIPv4Address(&ok), 0);
+ QVERIFY(!ok);
+
+ QCOMPARE(QByteArrayView::fromArray(addr.toIPv6Address().c),
+ QByteArrayView::fromArray(QIPv6Address{}.c));
+ QCOMPARE(addr.scopeId(), QString());
+
+ QCOMPARE(addr.toString(), QString());
+
+ size_t seed = QHashSeed::globalSeed();
+ QCOMPARE(qHash(addr, seed), qHash(QHostAddress(), seed));
+ seed = 0;
+ QCOMPARE(qHash(addr, seed), qHash(QHostAddress(), seed));
+}
+
+void tst_QHostAddress::constructor()
+{
+ QHostAddress addr;
+ verifyClear(addr);
+}
+
void tst_QHostAddress::constructor_QString_data()
{
setAddress_QString_data();
@@ -94,6 +132,9 @@ void tst_QHostAddress::constructor_QString()
QVERIFY( hostAddr.isNull() );
QVERIFY( hostAddr.protocol() == QHostAddress::UnknownNetworkLayerProtocol );
}
+
+ hostAddr.clear();
+ verifyClear(hostAddr);
}
void tst_QHostAddress::setAddress_QString_data()
@@ -201,6 +242,9 @@ void tst_QHostAddress::setAddress_QString()
QVERIFY( hostAddr.isNull() );
QVERIFY( hostAddr.protocol() == QHostAddress::UnknownNetworkLayerProtocol );
}
+
+ hostAddr.clear();
+ verifyClear(hostAddr);
}
void tst_QHostAddress::specialAddresses_data()
@@ -239,6 +283,7 @@ void tst_QHostAddress::specialAddresses()
QFETCH(QHostAddress::SpecialAddress, address);
QFETCH(bool, result);
QCOMPARE(QHostAddress(text) == address, result);
+ size_t seed = QHashSeed::globalSeed();
//check special address equal to itself (QTBUG-22898), note two overloads of operator==
QVERIFY(QHostAddress(address) == QHostAddress(address));
@@ -252,11 +297,19 @@ void tst_QHostAddress::specialAddresses()
QHostAddress ha;
ha.setAddress(address);
QVERIFY(ha == address);
+ QCOMPARE(qHash(ha, seed), qHash(QHostAddress(address), seed));
+ QCOMPARE(qHash(ha, 0), qHash(QHostAddress(address), 0));
}
QHostAddress setter;
setter.setAddress(text);
- QCOMPARE(setter == address, result);
+ if (result) {
+ QCOMPARE(setter, address);
+ QCOMPARE(qHash(setter, seed), qHash(QHostAddress(address), seed));
+ QCOMPARE(qHash(setter, 0), qHash(QHostAddress(address), 0));
+ } else {
+ QCOMPARE_NE(setter, address);
+ }
}
@@ -288,8 +341,11 @@ void tst_QHostAddress::compare()
QCOMPARE(first == second, result);
QCOMPARE(second == first, result);
- if (result == true)
- QCOMPARE(qHash(first), qHash(second));
+ if (result == true) {
+ size_t seed = QHashSeed::globalSeed();
+ QCOMPARE(qHash(first, seed), qHash(second, seed));
+ QCOMPARE(qHash(first, 0), qHash(second, 0));
+ }
}
void tst_QHostAddress::isEqual_data()
@@ -370,6 +426,11 @@ void tst_QHostAddress::scopeId()
address2 = address;
QCOMPARE(address2.scopeId(), QString("eth0"));
QCOMPARE(address2.toString().toLower(), QString("fe80::2e0:4cff:fefb:662a%eth0"));
+
+ address.clear();
+ verifyClear(address);
+ address2.clear();
+ verifyClear(address2);
}
void tst_QHostAddress::hashKey()
diff --git a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
index 4814206cd75..40292f0c44d 100644
--- a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
+++ b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
@@ -132,6 +132,7 @@ private:
bool m_skipUnsupportedIPv6Tests;
bool m_workaroundLinuxKernelBug;
+ int loopbackInterface = 0; // unknown by default
QList<QHostAddress> allAddresses;
QHostAddress multicastGroup4, multicastGroup6;
QList<QHostAddress> linklocalMulticastGroups;
@@ -140,6 +141,16 @@ private:
QUdpSocket *m_asyncReceiver;
};
+// Unlike for IPv6 with IPV6_PKTINFO, IPv4 has no standardized way of obtaining
+// the packet's destination addresses. This means the destinationAddress() be
+// empty, so whitelist the OSes for which we know we have an implementation.
+// That's currently all of them, which means there probably is code in this
+// test that assumes this works without checking this variable.
+//
+// Note: this applies to single-stack operations; dual stack implementations
+// appear to be buggy or not present at all in some OSes.
+static constexpr bool HasWorkingIPv4DestinationAddress = true;
+
#ifdef SHOULD_CHECK_SYSCALL_SUPPORT
bool tst_QUdpSocket::ipv6SetsockoptionMissing(int level, int optname)
{
@@ -246,7 +257,23 @@ void tst_QUdpSocket::initTestCase()
if (!QtNetworkSettings::verifyTestNetworkSettings())
QSKIP("No network test server available");
#endif
- allAddresses = QNetworkInterface::allAddresses();
+
+ allAddresses.clear();
+ for (const QNetworkInterface &iface : QNetworkInterface::allInterfaces()) {
+ if (!iface.flags().testAnyFlags(QNetworkInterface::IsUp))
+ continue;
+ if (iface.flags().testAnyFlags(QNetworkInterface::IsLoopBack))
+ loopbackInterface = iface.index();
+
+ // add this interface's addresses
+ const QList<QNetworkAddressEntry> addresses = iface.addressEntries();
+ for (const QNetworkAddressEntry &entry : addresses) {
+ allAddresses += entry.ip();
+ if (!loopbackInterface && entry.ip().isLoopback())
+ loopbackInterface = iface.index();
+ }
+ }
+
m_skipUnsupportedIPv6Tests = shouldSkipIpv6TestsForBrokenSetsockopt();
// Create a pair of random multicast groups so we avoid clashing with any
@@ -568,12 +595,12 @@ void tst_QUdpSocket::broadcasting()
QVERIFY2(allAddresses.contains(dgram.senderAddress()),
dgram.senderAddress().toString().toLatin1());
QCOMPARE(dgram.senderPort(), int(broadcastSocket.localPort()));
- if (!dgram.destinationAddress().isNull()) {
+ if (HasWorkingIPv4DestinationAddress) {
QVERIFY2(dgram.destinationAddress() == QHostAddress::Broadcast
|| broadcastAddresses.contains(dgram.destinationAddress()),
dgram.destinationAddress().toString().toLatin1());
- QCOMPARE(dgram.destinationPort(), int(serverSocket.localPort()));
}
+ QCOMPARE(dgram.destinationPort(), int(serverSocket.localPort()));
int ttl = dgram.hopLimit();
if (ttl != -1)
@@ -738,15 +765,7 @@ void tst_QUdpSocket::loop()
QCOMPARE(paulDatagram.senderPort(), int(peter.localPort()));
QCOMPARE(peterDatagram.senderPort(), int(paul.localPort()));
- // Unlike for IPv6 with IPV6_PKTINFO, IPv4 has no standardized way of
- // obtaining the packet's destination addresses. The destinationAddress and
- // destinationPort calls could fail, so whitelist the OSes for which we
- // know we have an implementation.
-#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) || defined(Q_OS_WIN)
- QVERIFY(peterDatagram.destinationPort() != -1);
- QVERIFY(paulDatagram.destinationPort() != -1);
-#endif
- if (peterDatagram.destinationPort() == -1) {
+ if (!HasWorkingIPv4DestinationAddress) {
QCOMPARE(peterDatagram.destinationAddress().protocol(), QAbstractSocket::UnknownNetworkLayerProtocol);
QCOMPARE(paulDatagram.destinationAddress().protocol(), QAbstractSocket::UnknownNetworkLayerProtocol);
} else {
@@ -754,6 +773,11 @@ void tst_QUdpSocket::loop()
QCOMPARE(paulDatagram.destinationAddress(), makeNonAny(paul.localAddress()));
QVERIFY(peterDatagram.destinationAddress().isEqual(makeNonAny(peter.localAddress())));
QVERIFY(paulDatagram.destinationAddress().isEqual(makeNonAny(paul.localAddress())));
+
+ if (loopbackInterface) {
+ QCOMPARE(peterDatagram.interfaceIndex(), loopbackInterface);
+ QCOMPARE(paulDatagram.interfaceIndex(), loopbackInterface);
+ }
}
}
@@ -820,6 +844,11 @@ void tst_QUdpSocket::ipv6Loop()
QCOMPARE(paulDatagram.destinationAddress(), makeNonAny(paul.localAddress()));
QCOMPARE(peterDatagram.destinationPort(), peterPort);
QCOMPARE(paulDatagram.destinationPort(), paulPort);
+
+ if (loopbackInterface) {
+ QCOMPARE(peterDatagram.interfaceIndex(), loopbackInterface);
+ QCOMPARE(paulDatagram.interfaceIndex(), loopbackInterface);
+ }
}
void tst_QUdpSocket::dualStack()
@@ -850,6 +879,8 @@ void tst_QUdpSocket::dualStack()
QCOMPARE(dgram.destinationPort(), int(dualSock.localPort()));
QVERIFY(dgram.destinationAddress().isEqual(makeNonAny(dualSock.localAddress(), QHostAddress::LocalHost)));
} else {
+ // Observed on QNX: the IPV6_PKTINFO ancillary data appears to be
+ // missing if the sender is IPv4.
qInfo("Getting IPv4 destination address failed.");
}
@@ -889,12 +920,11 @@ void tst_QUdpSocket::dualStack()
QCOMPARE(dgram.data(), dualData);
QCOMPARE(dgram.senderPort(), int(dualSock.localPort()));
QCOMPARE(dgram.senderAddress(), makeNonAny(dualSock.localAddress(), QHostAddress::LocalHost));
-#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) || defined(Q_OS_WIN)
- QVERIFY(dgram.destinationPort() != -1);
-#endif
- if (dgram.destinationPort() != -1) {
- QCOMPARE(dgram.destinationPort(), int(v4Sock.localPort()));
+ QCOMPARE(dgram.destinationPort(), int(v4Sock.localPort()));
+ if (HasWorkingIPv4DestinationAddress) {
QCOMPARE(dgram.destinationAddress(), makeNonAny(v4Sock.localAddress(), QHostAddress::LocalHost));
+ if (loopbackInterface)
+ QCOMPARE(dgram.interfaceIndex(), loopbackInterface);
}
}
@@ -1748,10 +1778,10 @@ void tst_QUdpSocket::multicast()
QVERIFY2(allAddresses.contains(dgram.senderAddress()),
dgram.senderAddress().toString().toLatin1());
QCOMPARE(dgram.senderPort(), int(sender.localPort()));
- if (!dgram.destinationAddress().isNull()) {
+ if (HasWorkingIPv4DestinationAddress) {
QCOMPARE(dgram.destinationAddress(), groupAddress);
- QCOMPARE(dgram.destinationPort(), int(receiver.localPort()));
}
+ QCOMPARE(dgram.destinationPort(), int(receiver.localPort()));
int ttl = dgram.hopLimit();
if (ttl != -1)
@@ -1962,19 +1992,12 @@ void tst_QUdpSocket::linkLocalIPv4()
QCOMPARE(dgram.data().size(), testData.size());
QCOMPARE(dgram.data(), testData);
- // Unlike for IPv6 with IPV6_PKTINFO, IPv4 has no standardized way of
- // obtaining the packet's destination addresses. The destinationAddress
- // and destinationPort calls could fail, so whitelist the OSes we know
- // we have an implementation.
-#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) || defined(Q_OS_WIN)
- QVERIFY(dgram.destinationPort() != -1);
-#endif
- if (dgram.destinationPort() == -1) {
+ if (!HasWorkingIPv4DestinationAddress) {
QCOMPARE(dgram.destinationAddress().protocol(), QAbstractSocket::UnknownNetworkLayerProtocol);
} else {
QCOMPARE(dgram.destinationAddress(), s->localAddress());
- QCOMPARE(dgram.destinationPort(), int(neutral.localPort()));
}
+ QCOMPARE(dgram.destinationPort(), int(neutral.localPort()));
QVERIFY(neutral.writeDatagram(dgram.makeReply(testData)));
QVERIFY2(s->waitForReadyRead(10000), QtNetworkSettings::msgSocketError(*s).constData());
diff --git a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST
index 7bde411761b..8f8c065560a 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST
+++ b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/BLACKLIST
@@ -9,6 +9,3 @@ android
android
[windowOpacity]
macos # QTBUG-139950
-[clickFocus]
-windows-10 # QTBUG-141386
-
diff --git a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
index 17acdea014e..2f0cbf78b25 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
@@ -25,6 +25,7 @@
#include <QtWidgets/qtablewidget.h>
#include <QtGui/qevent.h>
+#include <QtGui/qstylehints.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtCore/qmimedata.h>
@@ -3333,7 +3334,7 @@ void tst_QGraphicsProxyWidget::clickFocus()
EventSpy proxySpy(proxy);
EventSpy widgetSpy(proxy->widget());
- view.setFrameStyle(0);
+ view.setFrameStyle(QFrame::NoFrame);
view.resize(300, 300);
view.show();
QVERIFY(QTest::qWaitForWindowFocused(&view));
@@ -3469,10 +3470,12 @@ void tst_QGraphicsProxyWidget::QTBUG_6986_sendMouseEventToAlienWidget()
auto *hoverButton = new HoverButton(background);
hoverButton->setText("Second button"_L1);
hoverButton->setGeometry(10, 10, 200, 50);
+ hoverButton->setAttribute(Qt::WA_Hover, true);
scene.addWidget(background);
auto *hideButton = new QPushButton("I'm a button with a very very long text"_L1);
hideButton->setGeometry(10, 10, 400, 50);
+ hideButton->setAttribute(Qt::WA_Hover, true);
QGraphicsProxyWidget *topButton = scene.addWidget(hideButton);
connect(hideButton, &QPushButton::clicked, &scene, [&]() { topButton->hide(); });
topButton->setFocus();
@@ -3659,6 +3662,11 @@ public:
return QWidget::event(event);
}
+ void paintEvent(QPaintEvent *) override
+ {
+ QPainter p(this);
+ p.fillRect(rect(), Qt::green);
+ }
};
#if QT_CONFIG(wheelevent)
@@ -3676,6 +3684,11 @@ public:
*/
void tst_QGraphicsProxyWidget::wheelEventPropagation()
{
+ qApp->styleHints()->setWheelScrollLines(3);
+ const auto guard = qScopeGuard([&]() {
+ qApp->styleHints()->setWheelScrollLines(-1);
+ });
+
QGraphicsScene scene(0, 0, 600, 600);
auto *label = new QLabel("Direct"_L1);
@@ -3697,6 +3710,11 @@ void tst_QGraphicsProxyWidget::wheelEventPropagation()
int wheelEventCount = 0;
protected:
+ void paintEvent(QPaintEvent *) override
+ {
+ QPainter p(this);
+ p.fillRect(rect(), Qt::green);
+ }
void wheelEvent(QWheelEvent *) override
{
++wheelEventCount;
@@ -3710,10 +3728,13 @@ void tst_QGraphicsProxyWidget::wheelEventPropagation()
QGraphicsView view(&scene);
view.setFixedHeight(200);
+ view.setFixedWidth(700);
+ view.setFrameStyle(QFrame::NoFrame);
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
QVERIFY(view.verticalScrollBar()->isVisible());
+ QVERIFY(!view.horizontalScrollBar()->isVisible());
view.verticalScrollBar()->setValue(0);
QSignalSpy scrollSpy(view.verticalScrollBar(), &QScrollBar::valueChanged);
@@ -3729,6 +3750,8 @@ void tst_QGraphicsProxyWidget::wheelEventPropagation()
phase);
QCoreApplication::processEvents();
};
+ auto vs = view.verticalScrollBar();
+ vs->setSingleStep(9); // each wheel event: wheelScrollLines() * 9 = 27px
qsizetype scrollCount = 0;
// test non-kinetic events; they are not grabbed, and should scroll the view unless
@@ -3816,6 +3839,7 @@ void tst_QGraphicsProxyWidget::forwardTouchEvent()
QGraphicsView view(&scene);
view.show();
+ view.setFrameStyle(QFrame::NoFrame);
QVERIFY(QTest::qWaitForWindowActive(&view));
EventSpy eventSpy(widget);
@@ -3832,16 +3856,14 @@ void tst_QGraphicsProxyWidget::forwardTouchEvent()
QTest::touchEvent(&view, device.get()).move(0, QPoint(16, 16), &view);
QTest::touchEvent(&view, device.get()).release(0, QPoint(15, 15), &view);
- QApplication::processEvents();
-
- QCOMPARE(eventSpy.counts[QEvent::TouchBegin], 1);
- QCOMPARE(eventSpy.counts[QEvent::TouchUpdate], 2);
- QCOMPARE(eventSpy.counts[QEvent::TouchEnd], 1);
+ QTRY_COMPARE(eventSpy.counts[QEvent::TouchBegin], 1);
+ QTRY_COMPARE(eventSpy.counts[QEvent::TouchUpdate], 2);
+ QTRY_COMPARE(eventSpy.counts[QEvent::TouchEnd], 1);
}
void tst_QGraphicsProxyWidget::touchEventPropagation()
{
- QGraphicsScene scene(0, 0, 300, 200);
+ QGraphicsScene scene;
auto *simpleWidget = new QWidget;
simpleWidget->setObjectName("simpleWidget");
simpleWidget->setAttribute(Qt::WA_AcceptTouchEvents, true);
@@ -3873,15 +3895,26 @@ void tst_QGraphicsProxyWidget::touchEventPropagation()
vbox->addWidget(touchWidget2);
QGraphicsProxyWidget *formProxy = scene.addWidget(formWidget);
formProxy->setAcceptTouchEvents(true);
- formProxy->setGeometry(QRectF(50, 50, 200, 160));
+ const auto minSize = formWidget->minimumSize();
+ formProxy->setGeometry(QRectF(50, 50, minSize.width(), minSize.height()));
+
+ // topLeft must be 0/0
+ const auto sceneRect = scene.sceneRect();
+ scene.setSceneRect(QRectF(0, 0, sceneRect.width(), sceneRect.height()));
QGraphicsView view(&scene);
+ // by setting NoFrame, view and view.viewport() have the same
+ // coordinate system
+ view.setFrameStyle(QFrame::NoFrame);
+ // make sure to not have scrollbars
view.setFixedSize(scene.width(), scene.height());
view.verticalScrollBar()->setValue(0);
view.horizontalScrollBar()->setValue(0);
view.viewport()->setObjectName("GraphicsView's Viewport");
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
+ QVERIFY(!view.horizontalScrollBar()->isVisible());
+ QVERIFY(!view.verticalScrollBar()->isVisible());
class TouchEventSpy : public QObject
{
@@ -3913,8 +3946,12 @@ void tst_QGraphicsProxyWidget::touchEventPropagation()
case QEvent::TouchEnd: {
auto *touchEvent = static_cast<QTouchEvent *>(event);
// instead of detaching each QEventPoint, just store the relative positions
- for (const auto &touchPoint : touchEvent->points())
- records[touchPoint.id()] << TouchRecord{receiver, event->type(), touchPoint.position()};
+ for (const auto& touchPoint : touchEvent->points()) {
+ records[touchPoint.id()]
+ << TouchRecord{ receiver, event->type(), touchPoint.position() };
+ qCDebug(lcTests) << touchPoint.id() << "recv:" << receiver << "type"
+ << event->type() << "pos" << touchPoint.position();
+ }
qCDebug(lcTests) << "Recording" << event << receiver;
break;
}
@@ -3944,9 +3981,9 @@ void tst_QGraphicsProxyWidget::touchEventPropagation()
};
// verify that the embedded widget gets the correctly translated event
- QTest::touchEvent(&view, touchDevice.get()).press(0, simpleCenter.toPoint());
+ QTest::touchEvent(&view, touchDevice.get()).press(0, view.mapFromScene(simpleCenter));
// window, viewport, scene, simpleProxy, simpleWidget
- QCOMPARE(eventSpy.count(), 5);
+ QTRY_COMPARE(eventSpy.count(), 5);
QCOMPARE(eventSpy.at(0).receiver, view.windowHandle());
QCOMPARE(eventSpy.at(1).receiver, view.viewport());
QCOMPARE(eventSpy.at(2).receiver, &scene);
@@ -3969,7 +4006,7 @@ void tst_QGraphicsProxyWidget::touchEventPropagation()
QCOMPARE(formWidget->childAt(touchWidget2->pos() + tw2Center), touchWidget2);
// touch events are sent to the view, in view coordinates
- const QPoint formProxyPox = view.mapFromScene(formProxy->pos().toPoint());
+ const QPoint formProxyPox = view.mapFromScene(formProxy->pos());
const QPoint pb1TouchPos = pushButton1->pos() + pb1Center + formProxyPox;
const QPoint pb2TouchPos = pushButton2->pos() + pb2Center + formProxyPox;
const QPoint tw1TouchPos = touchWidget1->pos() + tw1Center + formProxyPox;
diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp
index df19ea1568e..48310996c46 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp
@@ -2058,28 +2058,21 @@ void tst_QGraphicsView::mapFromSceneRect()
QWidget topLevel;
QGraphicsView view(&scene,&topLevel);
view.rotate(90);
- view.setFixedSize(200, 200);
- view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ const auto fw = view.frameWidth() * 2;
+ view.setFixedSize(200 + fw, 200 + fw);
topLevel.show();
- QVERIFY(QTest::qWaitForWindowActive(&view));
+ QVERIFY(QTest::qWaitForWindowActive(&topLevel));
+ QVERIFY(!view.horizontalScrollBar()->isVisible());
+ QVERIFY(!view.verticalScrollBar()->isVisible());
- QPolygon polygon;
- polygon << QPoint(98, 98);
- polygon << QPoint(98, 108);
- polygon << QPoint(88, 108);
- polygon << QPoint(88, 98);
-
-
- QPolygon viewPolygon = view.mapFromScene(0, 0, 10, 10);
- for (int i = 0; i < 4; ++i) {
- QVERIFY(qAbs(viewPolygon[i].x() - polygon[i].x()) < 3);
- QVERIFY(qAbs(viewPolygon[i].y() - polygon[i].y()) < 3);
- }
+ const QRectF input(0, 0, 10, 10);
+ // fixed size is 200x200 so center is 100x100
+ const QPolygon polygon{ QPoint(100, 100), QPoint(100, 110), QPoint(90, 110), QPoint(90, 100) };
+ const QPolygon viewPolygon = view.mapFromScene(input);
+ QCOMPARE(viewPolygon, polygon);
QPoint pt = view.mapFromScene(QPointF());
- QPolygon p;
- p << pt << pt << pt << pt;
+ QPolygon p{ pt, pt, pt, pt };
QCOMPARE(view.mapFromScene(QRectF()), p);
}
@@ -2088,28 +2081,18 @@ void tst_QGraphicsView::mapFromScenePoly()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.rotate(90);
- view.setFixedSize(200, 200);
- view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ const auto fw = view.frameWidth() * 2;
+ view.setFixedSize(200 + fw, 200 + fw);
view.show();
-
- QPolygonF polygon;
- polygon << QPoint(0, 0);
- polygon << QPoint(10, 0);
- polygon << QPoint(10, 10);
- polygon << QPoint(0, 10);
-
- QPolygon polygon2;
- polygon2 << QPoint(98, 98);
- polygon2 << QPoint(98, 108);
- polygon2 << QPoint(88, 108);
- polygon2 << QPoint(88, 98);
-
- QPolygon viewPolygon = view.mapFromScene(polygon);
- for (int i = 0; i < 4; ++i) {
- QVERIFY(qAbs(viewPolygon[i].x() - polygon2[i].x()) < 3);
- QVERIFY(qAbs(viewPolygon[i].y() - polygon2[i].y()) < 3);
- }
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+ QVERIFY(!view.horizontalScrollBar()->isVisible());
+ QVERIFY(!view.verticalScrollBar()->isVisible());
+
+ const QPolygonF input{ QPoint(0, 0), QPoint(10, 0), QPoint(10, 10), QPoint(0, 10) };
+ // fixed size is 200x200 so center is 100x100
+ const QPolygon polygon{ QPoint(100, 100), QPoint(100, 110), QPoint(90, 110), QPoint(90, 100) };
+ const QPolygon viewPolygon = view.mapFromScene(input);
+ QCOMPARE(viewPolygon, polygon);
}
void tst_QGraphicsView::mapFromScenePath()
@@ -2117,34 +2100,22 @@ void tst_QGraphicsView::mapFromScenePath()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.rotate(90);
- view.setFixedSize(200, 200);
- view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ const auto fw = view.frameWidth() * 2;
+ view.setFixedSize(200 + fw, 200 + fw);
view.show();
-
- QPolygonF polygon;
- polygon << QPoint(0, 0);
- polygon << QPoint(10, 0);
- polygon << QPoint(10, 10);
- polygon << QPoint(0, 10);
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+ QVERIFY(!view.horizontalScrollBar()->isVisible());
+ QVERIFY(!view.verticalScrollBar()->isVisible());
+
+ const QPolygonF input{ QPoint(0, 0), QPoint(10, 0), QPoint(10, 10), QPoint(0, 10) };
+ QPainterPath inputPath;
+ inputPath.addPolygon(input);
+ // fixed size is 200x200 so center is 100x100
+ const QPolygon polygon{ QPoint(100, 100), QPoint(100, 110), QPoint(90, 110), QPoint(90, 100) };
QPainterPath path;
path.addPolygon(polygon);
-
- QPolygon polygon2;
- polygon2 << QPoint(98, 98);
- polygon2 << QPoint(98, 108);
- polygon2 << QPoint(88, 108);
- polygon2 << QPoint(88, 98);
- QPainterPath path2;
- path2.addPolygon(polygon2);
-
- QPolygonF pathPoly = view.mapFromScene(path).toFillPolygon();
- QPolygonF path2Poly = path2.toFillPolygon();
-
- for (int i = 0; i < pathPoly.size(); ++i) {
- QVERIFY(qAbs(pathPoly[i].x() - path2Poly[i].x()) < 3);
- QVERIFY(qAbs(pathPoly[i].y() - path2Poly[i].y()) < 3);
- }
+ QPainterPath viewPath = view.mapFromScene(inputPath);
+ QCOMPARE(viewPath, path);
}
void tst_QGraphicsView::sendEvent()