Merge remote-tracking branch 'origin/5.14' into 5.15

Change-Id: Ie69d40d2efc5559b31e28ba71f88e3cda741e051
bb10
Qt Forward Merge Bot 2019-09-11 01:00:09 +02:00
commit dc4ecf0641
62 changed files with 1159 additions and 571 deletions

109
dist/changes-5.12.5 vendored Normal file
View File

@ -0,0 +1,109 @@
Qt 5.12.5 is a bug-fix release. It maintains both forward and backward
compatibility (source and binary) with Qt 5.12.0 through 5.12.4.
For more details, refer to the online documentation included in this
distribution. The documentation is also available online:
https://doc.qt.io/qt-5/index.html
The Qt version 5.12 series is binary compatible with the 5.11.x series.
Applications compiled for 5.11 will continue to run with 5.12.
Some of the changes listed in this file include issue tracking numbers
corresponding to tasks in the Qt Bug Tracker:
https://bugreports.qt.io/
Each of these identifiers can be entered in the bug tracker to obtain more
information about a particular change.
****************************************************************************
* QtCore *
****************************************************************************
- QBitArray:
* Fixed two bugs that caused QBitArrays created using fromBits() not to
compare equal to the equivalent QBitArray created using other methods
if the size was zero or not a multiple of 4. If the size modulus 8 was
5, 6, or 7, the data was actually incorrect.
- QCborStreamReader:
* Fixed a bug that caused the QIODevice that the data was being read
from not to show the entire CBOR message as consumed. This allows the
user to consume data that may follow the CBOR payload.
- QCryptographicHash:
* Fixed a bug that caused the SHA-3 and Keccak algorithms to crash if
passed 256 MB of data or more.
- QObject:
* Fixed a resource leak caused by a race condition if multiple QObjects
were created at the same time, for the first time in an application,
from multiple threads (implies threads not started with QThread).
- QStorageInfo:
* Fixed a bug that caused QStorageInfo to be unable to report all
filesystems if the options to mounted filesystems were too long (over
900 characters, roughly), such as those found in Docker overlay
mounts.
- QTimeZone:
* The IANA timezone database backend now properly follows symlinks even
when they point to variable locations like /run or /var (useful when
/etc is mounted read-only).
****************************************************************************
* QtGui *
****************************************************************************
- QImage:
* Improve loading time when loading png files that have the same size as
the target.
- QPixmapCache:
* [QTBUG-76694][QTBUG-72523] Ignore unsafe access from non-main threads
- Text:
* [QTBUG-76219] Fixed a bug which could cause the font cache to grow
larger than it was supposed to.
* [QTBUG-55096][QTBUG-74761] Fixed bug where regular text rendered with
a color font would always display in black.
* [QTBUG-69546] Fixed a crash bug in
QTextDocument::clearUndoRedoStacks(QTextDocument::UndoStack).
****************************************************************************
* QtNetwork *
****************************************************************************
- QHostInfo:
* Functors used in the lookupHost overloads are now called correctly in
the thread of the context object. When used without context object,
the thread that initiates the lookup will run the functor, and is
required to run an event loop.
- Windows:
* Correctly emit errors when trying to reach unreachable hosts or
services
****************************************************************************
* QtWidgets *
****************************************************************************
- QGraphicsView:
* Ignore disabled items when setting the mouse cursor.
- QSplashScreen:
* On macOS, lower the splash screen when a modal dialog is shown to make
sure the user sees the dialog.
- QSystemTrayIcon:
* On macOS, show the icon passed into showMessage in the notification
popup
****************************************************************************
* Android *
****************************************************************************
- [QTBUG-76293] Fix NDK r20 linking.
- [QTBUG-76036] Fixed an issue where menus would not work on 64 bit
builds.

141
dist/changes-5.13.1 vendored Normal file
View File

@ -0,0 +1,141 @@
Qt 5.13.1 is a bug-fix release. It maintains both forward and backward
compatibility (source and binary) with Qt 5.13.0.
For more details, refer to the online documentation included in this
distribution. The documentation is also available online:
https://doc.qt.io/qt-5/index.html
The Qt version 5.13 series is binary compatible with the 5.12.x series.
Applications compiled for 5.12 will continue to run with 5.13.
Some of the changes listed in this file include issue tracking numbers
corresponding to tasks in the Qt Bug Tracker:
https://bugreports.qt.io/
Each of these identifiers can be entered in the bug tracker to obtain more
information about a particular change.
****************************************************************************
* Important Behavior Changes *
****************************************************************************
- [QTBUG-76521] RCC's default compression algorithm was changed back to
Zlib, as it was in all previous releases until 5.13.0. The default will
remain Zlib for all Qt 5.x releases but will change in Qt 6.0. To
activate Zstd compression for your resources, either pass the
--compress-algo=zstd option to the rcc tool or add the XML attribute
compression-algorithm="zstd" to the <file> tags in the .qrc file.
****************************************************************************
* Android *
****************************************************************************
- [QTBUG-76293] Fix NDK r20 linking.
****************************************************************************
* QtCore *
****************************************************************************
- Global:
* [QTBUG-72073] Added the QT_NO_FLOAT16_OPERATORS macro in order to work
around a Microsoft <= VS2017 compiler bug that is exposed when using
std::bitset along with any Qt header that includes <qfloat16.h>.
- QCborStreamReader:
* Fixed a bug that caused the QIODevice that the data was being read
from not to show the entire CBOR message as consumed. This allows the
user to consume data that may follow the CBOR payload.
- QDeadlineTimer:
* [QTBUG-69750] Fixed integer overflows leading to immediate timeouts.
- QStorageInfo:
* Fixed a bug that caused QStorageInfo to be unable to report all
filesystems if the options to mounted filesystems were too long (over
900 characters, roughly), such as those found in Docker overlay
mounts.
- QTextBoundaryFinder:
* Sentence breaking now no longer breaks between uppercase letters and
comma. This is a deviation from the Unicode specification, but
produces less surprising behavior.
- QTimeZone:
* The IANA timezone database backend now properly follows symlinks even
when they point to variable locations like /run or /var (useful when
/etc is mounted read-only).
- QVector:
* Fixed a regression that caused fill() not to detach, corrupting shared
copies.
****************************************************************************
* QtNetwork *
****************************************************************************
- Windows:
* Correctly emit errors when trying to reach unreachable hosts or
services
- QNetworkAccessManager:
* Fixed QNetworkAccessManager::sendCustomRequest for Qt For WebAssembly.
****************************************************************************
* QtGui *
****************************************************************************
- [QTBUG-73231] QWindow::mapToGlobal()/mapFromGlobal() now handle windows
spanning screens correctly.
- QImage:
* Improve loading time when loading png files that have the same size as
the target.
- QPixmapCache:
* [QTBUG-76694][QTBUG-72523] Ignore unsafe access from non-main threads
- Text:
* [QTBUG-76219] Fixed a bug which could cause the font cache to grow
larger than it was supposed to.
* [QTBUG-55096][QTBUG-74761] Fixed bug where regular text rendered with
a color font would always display in black.
****************************************************************************
* QtWidgets *
****************************************************************************
- QSystemTrayIcon:
* On macOS, show the icon passed into showMessage in the notification
popup
- QDateTimeEdit:
* Use the information provided by the locale to determine the AM/PM
strings, unless they are already translated.
- QGraphicsView:
* Ignore disabled items when setting the mouse cursor.
- QMenu:
* Shortcuts are again shown by default in context menus, except on
macOS. They can be forced off by setting
AA_DontShowShortcutsInContextMenus to true.
- QSplashScreen:
* On macOS, lower the splash screen when a modal dialog is shown to make
sure the user sees the dialog.
****************************************************************************
* Third-Party Code *
****************************************************************************
- Updated bundled SQLite to version 3.28.0
- Updated QLocale's data to CLDR v35.1
****************************************************************************
* qmake *
****************************************************************************
- [QTBUG-75653] The CONFIG value c++latest was added to select the latest
C++ standard the currently used toolchain supports.

View File

@ -1,6 +1,8 @@
TEMPLATE = aux
global_docs.files = $$PWD/global
global_docs.files = \
$$PWD/global \
$$PWD/config
global_docs.path = $$[QT_INSTALL_DOCS]
INSTALLS += global_docs
!prefix_build:!equals(OUT_PWD, $$PWD): \

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@ -61,6 +61,18 @@
\externalpage http://doc.qt.io/qtcreator/creator-quick-tour.html
\title Qt Creator: User Interface
*/
/*!
\externalpage http://doc.qt.io/qtcreator/creator-modes.html
\title Qt Creator: Selecting Modes
*/
/*!
\externalpage http://doc.qt.io/qtcreator/creator-sidebar-views.html
\title Qt Creator: Browsing Project Contents
*/
/*!
\externalpage http://doc.qt.io/qtcreator/creator-output-panes.html
\title Qt Creator: Viewing Output
*/
/*!
\externalpage http://doc.qt.io/qtcreator/creator-cli.html
\title Qt Creator: Using Command Line Options
@ -125,7 +137,7 @@
\externalpage http://doc.qt.io/qtcreator/quick-signals.html
\title Qt Creator: Connecting Objects to Signals
*/
* /*!
/*!
\externalpage http://doc.qt.io/qtcreator/quick-dynamic-properties.html
\title Qt Creator: Specifying Dynamic Properties
*/
@ -153,6 +165,10 @@
\externalpage http://doc.qt.io/qtcreator/creator-qml-modules-with-plugins.html
\title Qt Creator: Using QML Modules with Plugins
*/
/*!
\externalpage http://doc.qt.io/qtcreator/quick-converting-ui-projects.html
\title Qt Creator: Converting UI Projects to Applications
*/
/*!
\externalpage http://doc.qt.io/qtcreator/creator-visual-editor.html
\title Qt Creator: Developing Qt Quick Applications
@ -553,6 +569,10 @@
\externalpage http://doc.qt.io/qtcreator/creator-cpu-usage-analyzer.html
\title Qt Creator: Analyzing CPU Usage
*/
/*!
\externalpage http://doc.qt.io/qtcreator/creator-cppcheck.html
\title Qt Creator: Analyzing Code with Cppcheck
*/
/*!
\externalpage http://doc.qt.io/qtcreator/creator-autotest.html
\title Qt Creator: Running Autotests
@ -581,3 +601,27 @@
\externalpage http://doc.qt.io/qtcreator/creator-scxml.html
\title Qt Creator: Editing State Charts
*/
/*!
\externalpage http://doc.qt.io/qtcreator/studio-timeline.html
\title Qt Creator: Creating Animations
*/
/*!
\externalpage http://doc.qt.io/qtcreator/creator-language-servers.html
\title Qt Creator: Using Language Servers
*/
/*!
\externalpage http://doc.qt.io/qtcreator/qtcreator-toc.html
\title Qt Creator: All Topics
*/
/*!
\externalpage http://doc.qt.io/qtcreator/creator-live-preview.html
\title Qt Creator: Previewing
*/
/*!
\externalpage http://doc.qt.io/qtcreator/creator-live-preview-desktop.html
\title Qt Creator: Previewing on Desktop
*/
/*!
\externalpage http://doc.qt.io/qtcreator/creator-live-preview-devices.html
\title Qt Creator: Previewing on Devices
*/

View File

@ -8,7 +8,7 @@ QMAKE_MAC_SDK = macosx
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.12
QMAKE_APPLE_DEVICE_ARCHS = x86_64
QT_MAC_SDK_VERSION_MIN = 10.13
QT_MAC_SDK_VERSION_MAX = 10.14
QT_MAC_SDK_VERSION_MAX = 10.15
device.sdk = macosx
device.target = device

View File

@ -53,7 +53,11 @@ function(_qt5_$${CMAKE_MODULE_NAME}_process_prl_file prl_file_location Configura
set(_lib_deps)
set(_link_flags)
get_filename_component(_qt5_install_libs \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/lib\" ABSOLUTE)
!!IF isEmpty(CMAKE_LIB_DIR_IS_ABSOLUTE)
set(_qt5_install_libs \"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}\")
!!ELSE
set(_qt5_install_libs \"$${CMAKE_LIB_DIR}\")
!!ENDIF
if(EXISTS \"${prl_file_location}\")
file(STRINGS \"${prl_file_location}\" _prl_strings REGEX \"QMAKE_PRL_LIBS_FOR_CMAKE[ \\t]*=\")

View File

@ -509,6 +509,56 @@ static QList<QVariantMap> provisioningTeams()
return flatTeams;
}
bool ProjectBuilderMakefileGenerator::replaceLibrarySuffix(const QString &lib_file,
const ProString &opt,
QString &name, QString &library)
{
/* This isn't real nice, but it is real useful. This looks in a prl
for what the library will ultimately be called so we can stick it
in the ProjectFile. If the prl format ever changes (not likely) then
this will not really work. However, more concerning is that it will
encode the version number in the Project file which might be a bad
things in days to come? --Sam
*/
if (lib_file.isEmpty())
return false;
QMakeMetaInfo libinfo;
if (!libinfo.readLib(lib_file) || libinfo.isEmpty("QMAKE_PRL_TARGET"))
return false;
const QString libDir = fileInfo(lib_file).absolutePath();
library = libDir + Option::dir_sep + libinfo.first("QMAKE_PRL_TARGET");
debug_msg(1, "pbuilder: Found library (%s) via PRL %s (%s)",
opt.toLatin1().constData(), lib_file.toLatin1().constData(), library.toLatin1().constData());
if (project->isActiveConfig("xcode_dynamic_library_suffix")) {
QString suffixSetting = project->first("QMAKE_XCODE_LIBRARY_SUFFIX_SETTING").toQString();
if (!suffixSetting.isEmpty()) {
QString librarySuffix = project->first("QMAKE_XCODE_LIBRARY_SUFFIX").toQString();
suffixSetting = "$(" + suffixSetting + ")";
if (!librarySuffix.isEmpty()) {
int pos = library.lastIndexOf(librarySuffix + '.');
if (pos == -1) {
warn_msg(WarnLogic, "Failed to find expected suffix '%s' for library '%s'.",
qPrintable(librarySuffix), qPrintable(library));
} else {
library.replace(pos, librarySuffix.length(), suffixSetting);
if (name.endsWith(librarySuffix))
name.chop(librarySuffix.length());
}
} else {
int pos = library.lastIndexOf(name);
if (pos != -1)
library.insert(pos + name.length(), suffixSetting);
}
}
}
return true;
}
bool
ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
{
@ -820,6 +870,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
}
if(!project->isActiveConfig("staticlib")) { //DUMP LIBRARIES
const ProStringList defaultLibDirs = project->values("QMAKE_DEFAULT_LIBDIRS");
ProStringList &libdirs = project->values("QMAKE_PBX_LIBPATHS"),
&frameworkdirs = project->values("QMAKE_FRAMEWORKPATH");
static const char * const libs[] = { "LIBS", "LIBS_PRIVATE",
@ -827,6 +878,7 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
for (int i = 0; libs[i]; i++) {
tmp = project->values(libs[i]);
for(int x = 0; x < tmp.count();) {
bool libSuffixReplaced = false;
bool remove = false;
QString library, name;
ProString opt = tmp[x];
@ -839,49 +891,12 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
QString lib("lib" + name);
for (ProStringList::Iterator lit = libdirs.begin(); lit != libdirs.end(); ++lit) {
if(project->isActiveConfig("link_prl")) {
/* This isn't real nice, but it is real useful. This looks in a prl
for what the library will ultimately be called so we can stick it
in the ProjectFile. If the prl format ever changes (not likely) then
this will not really work. However, more concerning is that it will
encode the version number in the Project file which might be a bad
things in days to come? --Sam
*/
QString lib_file = QMakeMetaInfo::checkLib(Option::normalizePath(
(*lit) + Option::dir_sep + lib + Option::prl_ext));
if (!lib_file.isEmpty()) {
QMakeMetaInfo libinfo;
if(libinfo.readLib(lib_file)) {
if(!libinfo.isEmpty("QMAKE_PRL_TARGET")) {
library = (*lit) + Option::dir_sep + libinfo.first("QMAKE_PRL_TARGET");
debug_msg(1, "pbuilder: Found library (%s) via PRL %s (%s)",
opt.toLatin1().constData(), lib_file.toLatin1().constData(), library.toLatin1().constData());
remove = true;
if (project->isActiveConfig("xcode_dynamic_library_suffix")) {
QString suffixSetting = project->first("QMAKE_XCODE_LIBRARY_SUFFIX_SETTING").toQString();
if (!suffixSetting.isEmpty()) {
QString librarySuffix = project->first("QMAKE_XCODE_LIBRARY_SUFFIX").toQString();
suffixSetting = "$(" + suffixSetting + ")";
if (!librarySuffix.isEmpty()) {
int pos = library.lastIndexOf(librarySuffix + '.');
if (pos == -1) {
warn_msg(WarnLogic, "Failed to find expected suffix '%s' for library '%s'.",
qPrintable(librarySuffix), qPrintable(library));
} else {
library.replace(pos, librarySuffix.length(), suffixSetting);
if (name.endsWith(librarySuffix))
name.chop(librarySuffix.length());
}
} else {
int pos = library.lastIndexOf(name);
if (pos != -1)
library.insert(pos + name.length(), suffixSetting);
}
}
}
}
}
}
const QString prlFilePath = QMakeMetaInfo::checkLib(
Option::normalizePath((*lit) + Option::dir_sep + lib
+ Option::prl_ext));
if (replaceLibrarySuffix(prlFilePath, opt, name, library))
remove = true;
libSuffixReplaced = true;
}
if(!remove) {
QString extns[] = { ".dylib", ".so", ".a", QString() };
@ -931,6 +946,16 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
}
}
if(!library.isEmpty()) {
if (!libSuffixReplaced) {
const QFileInfo fi = fileInfo(library);
const QString prlFilePath = QMakeMetaInfo::checkLib(
Option::normalizePath(fi.absolutePath() + '/' + fi.completeBaseName()
+ Option::prl_ext));
if (!prlFilePath.isEmpty()) {
name = fi.completeBaseName().mid(3);
replaceLibrarySuffix(prlFilePath, opt, name, library);
}
}
const int slsh = library.lastIndexOf(Option::dir_sep);
if(name.isEmpty()) {
if(slsh != -1)
@ -938,8 +963,10 @@ ProjectBuilderMakefileGenerator::writeMakeParts(QTextStream &t)
}
if(slsh != -1) {
const QString path = QFileInfo(library.left(slsh)).absoluteFilePath();
if(!path.isEmpty() && !libdirs.contains(path))
if (!path.isEmpty() && !libdirs.contains(path)
&& !defaultLibDirs.contains(path)) {
libdirs += path;
}
}
library = fileFixify(library, FileFixifyFromOutdir | FileFixifyAbsolute);
QString key = keyFor(library);

View File

@ -41,6 +41,8 @@ class ProjectBuilderMakefileGenerator : public UnixMakefileGenerator
bool writeSubDirs(QTextStream &);
bool writeMakeParts(QTextStream &);
bool writeMakefile(QTextStream &) override;
bool replaceLibrarySuffix(const QString &lib_file, const ProString &opt, QString &name,
QString &library);
QString pbxbuild();
QHash<QString, QString> keys;

View File

@ -1199,8 +1199,10 @@ void UnixMakefileGenerator::init2()
project->values("QMAKE_FRAMEWORK_VERSION").append(project->first("VER_MAJ"));
if (project->first("TEMPLATE") == "aux") {
project->values("PRL_TARGET") =
project->values("TARGET").first().prepend(project->first("QMAKE_PREFIX_STATICLIB"));
project->values("PRL_TARGET") = {
project->first("QMAKE_PREFIX_STATICLIB") +
project->first("TARGET")
};
} else if (!project->values("QMAKE_APP_FLAG").isEmpty()) {
if(!project->isEmpty("QMAKE_BUNDLE")) {
ProString bundle_loc = project->first("QMAKE_BUNDLE_LOCATION");

View File

@ -1803,8 +1803,8 @@ static void qt_message_print(QtMsgType msgType, const QMessageLogContext &contex
#ifndef QT_BOOTSTRAPPED
Q_TRACE(qt_message_print, msgType, context.category, context.function, context.file, context.line, message);
// qDebug, qWarning, ... macros do not check whether category is enabled
if (isDefaultCategory(context.category)) {
// qDebug, qWarning, ... macros do not check whether category is enabledgc
if (msgType != QtFatalMsg && isDefaultCategory(context.category)) {
if (QLoggingCategory *defaultCategory = QLoggingCategory::defaultCategory()) {
if (!defaultCategory->isEnabled(msgType))
return;

View File

@ -3287,7 +3287,7 @@
the application object is created, or by setting the QT_SCALE_FACTOR_ROUNDING_POLICY
environment variable.
\sa QGuiApplication::setHighDdpiScaleFactorRoundingPolicy()
\sa QGuiApplication::setHighDpiScaleFactorRoundingPolicy()
\sa AA_EnableHighDpiScaling.
\omitvalue Unset

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2017 Intel Corporation.
** Copyright (C) 2019 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
@ -103,17 +103,22 @@ static QT_FUNCTION_TARGET(RDRND) qsizetype qt_random_cpu(void *buffer, qsizetype
{
unsigned *ptr = reinterpret_cast<unsigned *>(buffer);
unsigned *end = ptr + count;
int retries = 10;
while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) {
if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)) == 0)
if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)))
ptr += sizeof(qregisteruint)/sizeof(*ptr);
else if (--retries == 0)
goto out;
ptr += sizeof(qregisteruint)/sizeof(*ptr);
}
if (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
if (_rdrand32_step(ptr))
goto out;
++ptr;
while (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) {
bool ok = _rdrand32_step(ptr);
if (!ok && --retries)
continue;
if (ok)
++ptr;
break;
}
out:

View File

@ -74,7 +74,7 @@ QT_BEGIN_NAMESPACE
# define QLIBRARY_AS_DEBUG true
#endif
#if defined(Q_OS_UNIX) || defined(Q_CC_MINGW)
#if defined(Q_OS_UNIX)
// We don't use separate debug and release libs on UNIX, so we want
// to allow loading plugins, regardless of how they were built.
# define QT_NO_DEBUG_PLUGIN_CHECK

View File

@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE
/*!
\since 5.14
\internal
\class QHijriCalendar
\inmodule QtCore

View File

@ -48,6 +48,7 @@ using namespace QRoundingDown;
/*!
\since 5.14
\internal
\class QIslamicCivilCalendar
\inmodule QtCore
@ -67,7 +68,7 @@ using namespace QRoundingDown;
long. Its determination of leap years follows a 30-year cycle, in each of
which the years 2, 5, 7, 10, 13, 16, 18, 21, 24, 26 and 29 are leap years.
\sa QJijriCalendar, QCalendar
\sa QHijriCalendar, QCalendar
*/
QIslamicCivilCalendar::QIslamicCivilCalendar()

View File

@ -281,7 +281,7 @@ static quint32 icon_name_hash(const char *p)
QVector<const char *> QIconCacheGtkReader::lookup(const QStringRef &name)
{
QVector<const char *> ret;
if (!isValid())
if (!isValid() || name.isEmpty())
return ret;
QByteArray nameUtf8 = name.toUtf8();

View File

@ -2762,7 +2762,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
QWindow *window = e->window.data();
typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
QHash<QWindow *, StatesAndTouchPoints> windowsNeedingEvents;
bool stationaryTouchPointChangedVelocity = false;
bool stationaryTouchPointChangedProperty = false;
for (int i = 0; i < e->points.count(); ++i) {
QTouchEvent::TouchPoint touchPoint = e->points.at(i);
@ -2842,7 +2842,11 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
if (touchPoint.state() == Qt::TouchPointStationary) {
if (touchInfo.touchPoint.velocity() != touchPoint.velocity()) {
touchInfo.touchPoint.setVelocity(touchPoint.velocity());
stationaryTouchPointChangedVelocity = true;
stationaryTouchPointChangedProperty = true;
}
if (!qFuzzyCompare(touchInfo.touchPoint.pressure(), touchPoint.pressure())) {
touchInfo.touchPoint.setPressure(touchPoint.pressure());
stationaryTouchPointChangedProperty = true;
}
} else {
touchInfo.touchPoint = touchPoint;
@ -2883,7 +2887,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
break;
case Qt::TouchPointStationary:
// don't send the event if nothing changed
if (!stationaryTouchPointChangedVelocity)
if (!stationaryTouchPointChangedProperty)
continue;
Q_FALLTHROUGH();
default:
@ -3501,7 +3505,7 @@ Qt::ApplicationState QGuiApplication::applicationState()
\since 5.14
Sets the high-DPI scale factor rounding policy for the application. The
policy decides how non-integer scale factors (such as Windows 150%) are
\a policy decides how non-integer scale factors (such as Windows 150%) are
handled, for applications that have AA_EnableHighDpiScaling enabled.
The two principal options are whether fractional scale factors should

View File

@ -538,7 +538,7 @@ void QHighDpiScaling::updateHighDpiScaling()
++i;
}
}
m_active = m_globalScalingActive || m_usePixelDensity;
m_active = m_globalScalingActive || m_screenFactorSet || m_usePixelDensity;
}
/*

View File

@ -5019,6 +5019,23 @@ QRhiProfiler *QRhi::profiler()
return &d->profiler;
}
/*!
Attempts to release resources in the backend's caches. This can include both
CPU and GPU resources. Only memory and resources that can be recreated
automatically are in scope. As an example, if the backend's
QRhiGraphicsPipeline implementation maintains a cache of shader compilation
results, calling this function leads to emptying that cache, thus
potentially freeing up memory and graphics resources.
Calling this function makes sense in resource constrained environments,
where at a certain point there is a need to ensure minimal resource usage,
at the expense of performance.
*/
void QRhi::releaseCachedResources()
{
d->releaseCachedResources();
}
/*!
\return a new graphics pipeline resource.

View File

@ -1420,6 +1420,8 @@ public:
static const int MAX_LAYERS = 6; // cubemaps only
static const int MAX_LEVELS = 16; // a width and/or height of 65536 should be enough for everyone
void releaseCachedResources();
protected:
QRhi();

View File

@ -157,6 +157,7 @@ public:
virtual const QRhiNativeHandles *nativeHandles() = 0;
virtual void sendVMemStatsToProfiler() = 0;
virtual void makeThreadLocalNativeContextCurrent() = 0;
virtual void releaseCachedResources() = 0;
bool isCompressedFormat(QRhiTexture::Format format) const;
void compressedFormatInfo(QRhiTexture::Format format, const QSize &size,
@ -205,6 +206,8 @@ public:
QRhi *q;
static const int MAX_SHADER_CACHE_ENTRIES = 128;
protected:
bool debugMarkers = false;
int currentFrameSlot = 0; // for vk, mtl, and similar. unused by gl and d3d11.

View File

@ -267,10 +267,20 @@ bool QRhiD3D11::create(QRhi::Flags flags)
return true;
}
void QRhiD3D11::clearShaderCache()
{
for (Shader &s : m_shaderCache)
s.s->Release();
m_shaderCache.clear();
}
void QRhiD3D11::destroy()
{
finishActiveReadbacks();
clearShaderCache();
if (annotations) {
annotations->Release();
annotations = nullptr;
@ -461,6 +471,11 @@ void QRhiD3D11::makeThreadLocalNativeContextCurrent()
// nothing to do here
}
void QRhiD3D11::releaseCachedResources()
{
clearShaderCache();
}
QRhiRenderBuffer *QRhiD3D11::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags)
{
@ -3408,30 +3423,57 @@ bool QD3D11GraphicsPipeline::build()
QByteArray vsByteCode;
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
QString error;
QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error);
if (bytecode.isEmpty()) {
qWarning("HLSL shader compilation failed: %s", qPrintable(error));
return false;
}
switch (shaderStage.type()) {
case QRhiShaderStage::Vertex:
hr = rhiD->dev->CreateVertexShader(bytecode.constData(), bytecode.size(), nullptr, &vs);
if (FAILED(hr)) {
qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr)));
auto cacheIt = rhiD->m_shaderCache.constFind(shaderStage);
if (cacheIt != rhiD->m_shaderCache.constEnd()) {
switch (shaderStage.type()) {
case QRhiShaderStage::Vertex:
vs = static_cast<ID3D11VertexShader *>(cacheIt->s);
vs->AddRef();
vsByteCode = cacheIt->bytecode;
break;
case QRhiShaderStage::Fragment:
fs = static_cast<ID3D11PixelShader *>(cacheIt->s);
fs->AddRef();
break;
default:
break;
}
} else {
QString error;
const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error);
if (bytecode.isEmpty()) {
qWarning("HLSL shader compilation failed: %s", qPrintable(error));
return false;
}
vsByteCode = bytecode;
break;
case QRhiShaderStage::Fragment:
hr = rhiD->dev->CreatePixelShader(bytecode.constData(), bytecode.size(), nullptr, &fs);
if (FAILED(hr)) {
qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr)));
return false;
if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES) {
// Use the simplest strategy: too many cached shaders -> drop them all.
rhiD->clearShaderCache();
}
switch (shaderStage.type()) {
case QRhiShaderStage::Vertex:
hr = rhiD->dev->CreateVertexShader(bytecode.constData(), bytecode.size(), nullptr, &vs);
if (FAILED(hr)) {
qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr)));
return false;
}
vsByteCode = bytecode;
rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs, bytecode));
vs->AddRef();
break;
case QRhiShaderStage::Fragment:
hr = rhiD->dev->CreatePixelShader(bytecode.constData(), bytecode.size(), nullptr, &fs);
if (FAILED(hr)) {
qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr)));
return false;
}
rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs, bytecode));
fs->AddRef();
break;
default:
break;
}
break;
default:
break;
}
}
@ -3501,18 +3543,30 @@ bool QD3D11ComputePipeline::build()
QRHI_RES_RHI(QRhiD3D11);
QString error;
QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error);
if (bytecode.isEmpty()) {
qWarning("HLSL compute shader compilation failed: %s", qPrintable(error));
return false;
auto cacheIt = rhiD->m_shaderCache.constFind(m_shaderStage);
if (cacheIt != rhiD->m_shaderCache.constEnd()) {
cs = static_cast<ID3D11ComputeShader *>(cacheIt->s);
} else {
QString error;
const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error);
if (bytecode.isEmpty()) {
qWarning("HLSL compute shader compilation failed: %s", qPrintable(error));
return false;
}
HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), bytecode.size(), nullptr, &cs);
if (FAILED(hr)) {
qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr)));
return false;
}
if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES)
rhiD->clearShaderCache();
rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs, bytecode));
}
HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), bytecode.size(), nullptr, &cs);
if (FAILED(hr)) {
qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr)));
return false;
}
cs->AddRef();
generation += 1;
rhiD->registerResource(this);

View File

@ -632,6 +632,7 @@ public:
const QRhiNativeHandles *nativeHandles() override;
void sendVMemStatsToProfiler() override;
void makeThreadLocalNativeContextCurrent() override;
void releaseCachedResources() override;
void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD,
int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc);
@ -646,6 +647,7 @@ public:
DXGI_SAMPLE_DESC effectiveSampleCount(int sampleCount) const;
void finishActiveReadbacks();
void reportLiveObjects(ID3D11Device *device);
void clearShaderCache();
bool debugLayer = false;
bool importedDevice = false;
@ -684,6 +686,14 @@ public:
QRhiTexture::Format format;
};
QVector<ActiveReadback> activeReadbacks;
struct Shader {
Shader() = default;
Shader(IUnknown *s, const QByteArray &bytecode) : s(s), bytecode(bytecode) { }
IUnknown *s;
QByteArray bytecode;
};
QHash<QRhiShaderStage, Shader> m_shaderCache;
};
Q_DECLARE_TYPEINFO(QRhiD3D11::ActiveReadback, Q_MOVABLE_TYPE);

View File

@ -502,6 +502,10 @@ void QRhiGles2::destroy()
ensureContext();
executeDeferredReleases();
for (uint shader : m_shaderCache)
f->glDeleteShader(shader);
m_shaderCache.clear();
if (!importedContext) {
delete ctx;
ctx = nullptr;
@ -757,6 +761,17 @@ void QRhiGles2::makeThreadLocalNativeContextCurrent()
ensureContext();
}
void QRhiGles2::releaseCachedResources()
{
if (!ensureContext())
return;
for (uint shader : m_shaderCache)
f->glDeleteShader(shader);
m_shaderCache.clear();
}
QRhiRenderBuffer *QRhiGles2::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags)
{
@ -2673,7 +2688,6 @@ static inline GLenum toGlShaderType(QRhiShaderStage::Type type)
bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage,
QShaderDescription *desc, int *glslVersionUsed)
{
GLuint shader = f->glCreateShader(toGlShaderType(shaderStage.type()));
const QShader bakedShader = shaderStage.shader();
QVector<int> versionsToTry;
QByteArray source;
@ -2733,27 +2747,40 @@ bool QRhiGles2::compileShader(GLuint program, const QRhiShaderStage &shaderStage
return false;
}
const char *srcStr = source.constData();
const GLint srcLength = source.count();
f->glShaderSource(shader, 1, &srcStr, &srcLength);
f->glCompileShader(shader);
GLint compiled = 0;
f->glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint infoLogLength = 0;
f->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
QByteArray log;
if (infoLogLength > 1) {
GLsizei length = 0;
log.resize(infoLogLength);
f->glGetShaderInfoLog(shader, infoLogLength, &length, log.data());
GLuint shader;
auto cacheIt = m_shaderCache.constFind(shaderStage);
if (cacheIt != m_shaderCache.constEnd()) {
shader = *cacheIt;
} else {
shader = f->glCreateShader(toGlShaderType(shaderStage.type()));
const char *srcStr = source.constData();
const GLint srcLength = source.count();
f->glShaderSource(shader, 1, &srcStr, &srcLength);
f->glCompileShader(shader);
GLint compiled = 0;
f->glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (!compiled) {
GLint infoLogLength = 0;
f->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
QByteArray log;
if (infoLogLength > 1) {
GLsizei length = 0;
log.resize(infoLogLength);
f->glGetShaderInfoLog(shader, infoLogLength, &length, log.data());
}
qWarning("Failed to compile shader: %s\nSource was:\n%s", log.constData(), source.constData());
return false;
}
qWarning("Failed to compile shader: %s\nSource was:\n%s", log.constData(), source.constData());
return false;
if (m_shaderCache.count() >= MAX_SHADER_CACHE_ENTRIES) {
// Use the simplest strategy: too many cached shaders -> drop them all.
for (uint shader : m_shaderCache)
f->glDeleteShader(shader); // does not actually get released yet when attached to a not-yet-released program
m_shaderCache.clear();
}
m_shaderCache.insert(shaderStage, shader);
}
f->glAttachShader(program, shader);
f->glDeleteShader(shader);
*desc = bakedShader.description();
return true;

View File

@ -665,6 +665,7 @@ public:
const QRhiNativeHandles *nativeHandles() override;
void sendVMemStatsToProfiler() override;
void makeThreadLocalNativeContextCurrent() override;
void releaseCachedResources() override;
bool ensureContext(QSurface *surface = nullptr) const;
void executeDeferredReleases();
@ -804,6 +805,8 @@ public:
bool active = false;
QGles2CommandBuffer cbWrapper;
} ofr;
QHash<QRhiShaderStage, uint> m_shaderCache;
};
Q_DECLARE_TYPEINFO(QRhiGles2::DeferredReleaseEntry, Q_MOVABLE_TYPE);

View File

@ -138,6 +138,20 @@ QT_BEGIN_NAMESPACE
\l{QRhiCommandBuffer::endPass()}.
*/
struct QMetalShader
{
id<MTLLibrary> lib = nil;
id<MTLFunction> func = nil;
std::array<uint, 3> localSize;
void release() {
[lib release];
lib = nil;
[func release];
func = nil;
}
};
struct QRhiMetalData
{
QRhiMetalData(QRhiImplementation *rhi) : ofr(rhi) { }
@ -206,6 +220,8 @@ struct QRhiMetalData
API_AVAILABLE(macos(10.13), ios(11.0)) id<MTLCaptureScope> captureScope = nil;
static const int TEXBUF_ALIGN = 256; // probably not accurate
QHash<QRhiShaderStage, QMetalShader> shaderCache;
};
Q_DECLARE_TYPEINFO(QRhiMetalData::DeferredReleaseEntry, Q_MOVABLE_TYPE);
@ -289,17 +305,14 @@ struct QMetalGraphicsPipelineData
MTLPrimitiveType primitiveType;
MTLWinding winding;
MTLCullMode cullMode;
id<MTLLibrary> vsLib = nil;
id<MTLFunction> vsFunc = nil;
id<MTLLibrary> fsLib = nil;
id<MTLFunction> fsFunc = nil;
QMetalShader vs;
QMetalShader fs;
};
struct QMetalComputePipelineData
{
id<MTLComputePipelineState> ps = nil;
id<MTLLibrary> csLib = nil;
id<MTLFunction> csFunc = nil;
QMetalShader cs;
MTLSize localSize;
};
@ -404,6 +417,10 @@ void QRhiMetal::destroy()
executeDeferredReleases(true);
finishActiveReadbacks(true);
for (QMetalShader &s : d->shaderCache)
s.release();
d->shaderCache.clear();
if (@available(macOS 10.13, iOS 11.0, *)) {
[d->captureScope release];
d->captureScope = nil;
@ -570,6 +587,14 @@ void QRhiMetal::makeThreadLocalNativeContextCurrent()
// nothing to do here
}
void QRhiMetal::releaseCachedResources()
{
for (QMetalShader &s : d->shaderCache)
s.release();
d->shaderCache.clear();
}
QRhiRenderBuffer *QRhiMetal::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags)
{
@ -2843,36 +2868,17 @@ void QMetalGraphicsPipeline::release()
{
QRHI_RES_RHI(QRhiMetal);
d->vs.release();
d->fs.release();
[d->ds release];
d->ds = nil;
if (!d->ps)
return;
if (d->ps) {
[d->ps release];
d->ps = nil;
}
if (d->ds) {
[d->ds release];
d->ds = nil;
}
if (d->vsFunc) {
[d->vsFunc release];
d->vsFunc = nil;
}
if (d->vsLib) {
[d->vsLib release];
d->vsLib = nil;
}
if (d->fsFunc) {
[d->fsFunc release];
d->fsFunc = nil;
}
if (d->fsLib) {
[d->fsLib release];
d->fsLib = nil;
}
[d->ps release];
d->ps = nil;
rhiD->unregisterResource(this);
}
@ -3159,34 +3165,66 @@ bool QMetalGraphicsPipeline::build()
// buffers not just the resource binding layout) so leave it at the default
for (const QRhiShaderStage &shaderStage : qAsConst(m_shaderStages)) {
QString error;
QByteArray entryPoint;
id<MTLLibrary> lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint);
if (!lib) {
qWarning("MSL shader compilation failed: %s", qPrintable(error));
return false;
}
id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
if (!func) {
qWarning("MSL function for entry point %s not found", entryPoint.constData());
[lib release];
return false;
}
switch (shaderStage.type()) {
case QRhiShaderStage::Vertex:
rpDesc.vertexFunction = func;
d->vsLib = lib;
d->vsFunc = func;
break;
case QRhiShaderStage::Fragment:
rpDesc.fragmentFunction = func;
d->fsLib = lib;
d->fsFunc = func;
break;
default:
[func release];
[lib release];
break;
auto cacheIt = rhiD->d->shaderCache.constFind(shaderStage);
if (cacheIt != rhiD->d->shaderCache.constEnd()) {
switch (shaderStage.type()) {
case QRhiShaderStage::Vertex:
d->vs = *cacheIt;
[d->vs.lib retain];
[d->vs.func retain];
rpDesc.vertexFunction = d->vs.func;
break;
case QRhiShaderStage::Fragment:
d->fs = *cacheIt;
[d->fs.lib retain];
[d->fs.func retain];
rpDesc.fragmentFunction = d->fs.func;
break;
default:
break;
}
} else {
QString error;
QByteArray entryPoint;
id<MTLLibrary> lib = rhiD->d->createMetalLib(shaderStage.shader(), shaderStage.shaderVariant(), &error, &entryPoint);
if (!lib) {
qWarning("MSL shader compilation failed: %s", qPrintable(error));
return false;
}
id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
if (!func) {
qWarning("MSL function for entry point %s not found", entryPoint.constData());
[lib release];
return false;
}
if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) {
// Use the simplest strategy: too many cached shaders -> drop them all.
for (QMetalShader &s : rhiD->d->shaderCache)
s.release();
rhiD->d->shaderCache.clear();
}
switch (shaderStage.type()) {
case QRhiShaderStage::Vertex:
d->vs.lib = lib;
d->vs.func = func;
rhiD->d->shaderCache.insert(shaderStage, d->vs);
[d->vs.lib retain];
[d->vs.func retain];
rpDesc.vertexFunction = func;
break;
case QRhiShaderStage::Fragment:
d->fs.lib = lib;
d->fs.func = func;
rhiD->d->shaderCache.insert(shaderStage, d->fs);
[d->fs.lib retain];
[d->fs.func retain];
rpDesc.fragmentFunction = func;
break;
default:
[func release];
[lib release];
break;
}
}
}
@ -3286,22 +3324,13 @@ void QMetalComputePipeline::release()
{
QRHI_RES_RHI(QRhiMetal);
if (d->csFunc) {
[d->csFunc release];
d->csFunc = nil;
}
if (d->csLib) {
[d->csLib release];
d->csLib = nil;
}
d->cs.release();
if (!d->ps)
return;
if (d->ps) {
[d->ps release];
d->ps = nil;
}
[d->ps release];
d->ps = nil;
rhiD->unregisterResource(this);
}
@ -3313,28 +3342,44 @@ bool QMetalComputePipeline::build()
QRHI_RES_RHI(QRhiMetal);
const QShader shader = m_shaderStage.shader();
QString error;
QByteArray entryPoint;
id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(),
&error, &entryPoint);
if (!lib) {
qWarning("MSL shader compilation failed: %s", qPrintable(error));
return false;
auto cacheIt = rhiD->d->shaderCache.constFind(m_shaderStage);
if (cacheIt != rhiD->d->shaderCache.constEnd()) {
d->cs = *cacheIt;
} else {
const QShader shader = m_shaderStage.shader();
QString error;
QByteArray entryPoint;
id<MTLLibrary> lib = rhiD->d->createMetalLib(shader, m_shaderStage.shaderVariant(),
&error, &entryPoint);
if (!lib) {
qWarning("MSL shader compilation failed: %s", qPrintable(error));
return false;
}
id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
if (!func) {
qWarning("MSL function for entry point %s not found", entryPoint.constData());
[lib release];
return false;
}
d->cs.lib = lib;
d->cs.func = func;
d->cs.localSize = shader.description().computeShaderLocalSize();
if (rhiD->d->shaderCache.count() >= QRhiMetal::MAX_SHADER_CACHE_ENTRIES) {
for (QMetalShader &s : rhiD->d->shaderCache)
s.release();
rhiD->d->shaderCache.clear();
}
rhiD->d->shaderCache.insert(m_shaderStage, d->cs);
}
id<MTLFunction> func = rhiD->d->createMSLShaderFunction(lib, entryPoint);
if (!func) {
qWarning("MSL function for entry point %s not found", entryPoint.constData());
[lib release];
return false;
}
d->csLib = lib;
d->csFunc = func;
std::array<uint, 3> localSize = shader.description().computeShaderLocalSize();
d->localSize = MTLSizeMake(localSize[0], localSize[1], localSize[2]);
[d->cs.lib retain];
[d->cs.func retain];
d->localSize = MTLSizeMake(d->cs.localSize[0], d->cs.localSize[1], d->cs.localSize[2]);
NSError *err = nil;
d->ps = [rhiD->d->dev newComputePipelineStateWithFunction: d->csFunc error: &err];
d->ps = [rhiD->d->dev newComputePipelineStateWithFunction: d->cs.func error: &err];
if (!d->ps) {
const QString msg = QString::fromNSString(err.localizedDescription);
qWarning("Failed to create render pipeline state: %s", qPrintable(msg));

View File

@ -417,6 +417,7 @@ public:
const QRhiNativeHandles *nativeHandles() override;
void sendVMemStatsToProfiler() override;
void makeThreadLocalNativeContextCurrent() override;
void releaseCachedResources() override;
void executeDeferredReleases(bool forced = false);
void finishActiveReadbacks(bool forced = false);

View File

@ -174,6 +174,11 @@ void QRhiNull::makeThreadLocalNativeContextCurrent()
// nothing to do here
}
void QRhiNull::releaseCachedResources()
{
// nothing to do here
}
QRhiRenderBuffer *QRhiNull::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags)
{

View File

@ -283,6 +283,7 @@ public:
const QRhiNativeHandles *nativeHandles() override;
void sendVMemStatsToProfiler() override;
void makeThreadLocalNativeContextCurrent() override;
void releaseCachedResources() override;
QRhiNullNativeHandles nativeHandlesStruct;
QRhiSwapChain *currentSwapChain = nullptr;

View File

@ -3744,6 +3744,11 @@ void QRhiVulkan::makeThreadLocalNativeContextCurrent()
// nothing to do here
}
void QRhiVulkan::releaseCachedResources()
{
// nothing to do here
}
QRhiRenderBuffer *QRhiVulkan::createRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize,
int sampleCount, QRhiRenderBuffer::Flags flags)
{

View File

@ -712,6 +712,7 @@ public:
const QRhiNativeHandles *nativeHandles() override;
void sendVMemStatsToProfiler() override;
void makeThreadLocalNativeContextCurrent() override;
void releaseCachedResources() override;
VkResult createDescriptorPool(VkDescriptorPool *pool);
bool allocateDescriptorSet(VkDescriptorSetAllocateInfo *allocInfo, VkDescriptorSet *result, int *resultPoolIndex);

View File

@ -2067,8 +2067,9 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
\enum QTextDocument::ResourceType
This enum describes the types of resources that can be loaded by
QTextDocument's loadResource() function.
QTextDocument's loadResource() function or by QTextBrowser::setSource().
\value UnknownResource No resource is loaded, or the resource type is not known.
\value HtmlResource The resource contains HTML.
\value ImageResource The resource contains image data.
Currently supported data types are QVariant::Pixmap and
@ -2082,7 +2083,7 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
\value UserResource The first available value for user defined
resource types.
\sa loadResource()
\sa loadResource(), QTextBrowser::sourceType()
*/
/*!

View File

@ -399,6 +399,7 @@ struct QBidiAlgorithm {
analysis[i].bidiDirection = (level & 1) ? QChar::DirR : QChar::DirL;
runHasContent = true;
lastRunWithContent = -1;
++isolatePairPosition;
}
int runBeforeIsolate = runs.size();
ushort newLevel = isRtl ? ((stack.top().level + 1) | 1) : ((stack.top().level + 2) & ~1);
@ -440,21 +441,19 @@ struct QBidiAlgorithm {
doEmbed(true, true, false);
break;
case QChar::DirLRI:
Q_ASSERT(isolatePairs.at(isolatePairPosition).start == i);
doEmbed(false, false, true);
++isolatePairPosition;
break;
case QChar::DirRLI:
Q_ASSERT(isolatePairs.at(isolatePairPosition).start == i);
doEmbed(true, false, true);
++isolatePairPosition;
break;
case QChar::DirFSI: {
const auto &pair = isolatePairs.at(isolatePairPosition);
Q_ASSERT(pair.start == i);
bool isRtl = QStringView(text + pair.start + 1, pair.end - pair.start - 1).isRightToLeft();
bool isRtl = false;
if (isolatePairPosition < isolatePairs.size()) {
const auto &pair = isolatePairs.at(isolatePairPosition);
Q_ASSERT(pair.start == i);
isRtl = QStringView(text + pair.start + 1, pair.end - pair.start - 1).isRightToLeft();
}
doEmbed(isRtl, false, true);
++isolatePairPosition;
break;
}

View File

@ -650,6 +650,7 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt)
\value TableColumns
\value TableColumnWidthConstraints
\value TableHeaderRowCount
\value TableBorderCollapse Specifies the \l QTextTableFormat::borderCollapse property.
Table cell properties

View File

@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QHttp2Configuration
\brief The QHttp2Configuration class controls HTTP/2 parameters and settings
\brief The QHttp2Configuration class controls HTTP/2 parameters and settings.
\since 5.14
\reentrant

View File

@ -854,8 +854,11 @@ void QHttpNetworkConnectionChannel::_q_disconnected()
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
state = QHttpNetworkConnectionChannel::IdleState;
requeueCurrentlyPipelinedRequests();
if (alreadyPipelinedRequests.length()) {
// If nothing was in a pipeline, no need in calling
// _q_startNextRequest (which it does):
requeueCurrentlyPipelinedRequests();
}
pendingEncrypt = false;
}

View File

@ -1512,7 +1512,7 @@ bool QSslSocket::addDefaultCaCertificates(const QString &path, QSsl::EncodingFor
SSL socket's CA certificate database is initialized to the default
CA certificate database.
\sa QSslConfiguration::defaultCaCertificates(), addCaCertificates()
\sa QSslConfiguration::caCertificates(), addCaCertificates()
*/
void QSslSocket::addDefaultCaCertificate(const QSslCertificate &certificate)
{

View File

@ -1360,6 +1360,18 @@ void QSslSocketBackendPrivate::transmit()
#endif
schannelState = SchannelState::Renegotiate;
renegotiating = true;
if (dataBuffer[3].BufferType == SECBUFFER_EXTRA) {
// https://docs.microsoft.com/en-us/windows/desktop/secauthn/extra-buffers-returned-by-schannel
// dataBuffer[3].cbBuffer indicates the amount of bytes _NOT_ processed,
// the rest need to be stored.
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcSsl) << "We've got excess data, moving it to the intermediate buffer:"
<< dataBuffer[3].cbBuffer << "bytes";
#endif
intermediateBuffer = ciphertext.right(int(dataBuffer[3].cbBuffer));
}
// We need to call 'continueHandshake' or else there's no guarantee it ever gets called
continueHandshake();
break;

View File

@ -535,7 +535,7 @@ void QEvdevTouchScreenData::processInputEvent(input_event *data)
m_currentData.state = Qt::TouchPointReleased;
if (m_typeB)
m_contacts[m_currentSlot].maj = m_currentData.maj;
} else if (data->code == ABS_PRESSURE) {
} else if (data->code == ABS_PRESSURE || data->code == ABS_MT_PRESSURE) {
m_currentData.pressure = qBound(hw_pressure_min, data->value, hw_pressure_max);
if (m_typeB || m_singleTouch)
m_contacts[m_currentSlot].pressure = m_currentData.pressure;

View File

@ -42,6 +42,7 @@
#include "qwindowswindow.h"
#include "qwindowsintegration.h"
#include "qwindowscursor.h"
#include "qwindowstheme.h"
#include <QtCore/qt_windows.h>
@ -543,10 +544,13 @@ bool QWindowsScreenManager::handleScreenChanges()
// Look for changed monitors, add new ones
const WindowsScreenDataList newDataList = monitorData();
const bool lockScreen = newDataList.size() == 1 && (newDataList.front().flags & QWindowsScreenData::LockScreen);
bool primaryScreenChanged = false;
for (const QWindowsScreenData &newData : newDataList) {
const int existingIndex = indexOfMonitor(m_screens, newData.name);
if (existingIndex != -1) {
m_screens.at(existingIndex)->handleChanges(newData);
if (existingIndex == 0)
primaryScreenChanged = true;
} else {
auto *newScreen = new QWindowsScreen(newData);
m_screens.push_back(newScreen);
@ -563,6 +567,8 @@ bool QWindowsScreenManager::handleScreenChanges()
removeScreen(i);
} // for existing screens
} // not lock screen
if (primaryScreenChanged)
QWindowsTheme::instance()->refreshFonts();
return true;
}

View File

@ -85,6 +85,8 @@ public:
static bool useNativeMenus();
void refreshFonts();
static const char *name;
private:
@ -92,7 +94,6 @@ private:
void clearPalettes();
void refreshPalettes();
void clearFonts();
void refreshFonts();
void refreshIconPixmapSizes();
static QWindowsTheme *m_instance;

View File

@ -51,6 +51,8 @@
#include <QtCore/QString>
#include <QtCore/private/qeventdispatcher_winrt_p.h>
#include <memory>
QT_BEGIN_NAMESPACE
using namespace QWinRTUiAutomation;
@ -105,19 +107,17 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaGridItemProvider::get_ContainingGrid(IIRawEle
*value = nullptr;
auto accid = id();
auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0));
auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId);
auto elementId = std::make_shared<QAccessible::Id>(0);
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementId]() {
if (QAccessibleInterface *accessible = accessibleForId(accid)) {
if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) {
if (QAccessibleInterface *table = tableCellInterface->table()) {
**ptrElementId = idForAccessible(table);
QWinRTUiaMetadataCache::instance()->load(**ptrElementId);
*elementId = idForAccessible(table);
QWinRTUiaMetadataCache::instance()->load(*elementId);
}
}
}
delete ptrElementId;
return S_OK;
}))) {
return E_FAIL;

View File

@ -51,6 +51,8 @@
#include <QtCore/QString>
#include <QtCore/private/qeventdispatcher_winrt_p.h>
#include <memory>
QT_BEGIN_NAMESPACE
using namespace QWinRTUiAutomation;
@ -104,21 +106,19 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaGridProvider::GetItem(INT32 row, INT32 column
*returnValue = nullptr;
auto accid = id();
auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0));
auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId);
auto elementId = std::make_shared<QAccessible::Id>(0);
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, row, column, ptrElementId]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, row, column, elementId]() {
if (QAccessibleInterface *accessible = accessibleForId(accid)) {
if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) {
if ((row >= 0) && (row < tableInterface->rowCount()) && (column >= 0) && (column < tableInterface->columnCount())) {
if (QAccessibleInterface *cell = tableInterface->cellAt(row, column)) {
**ptrElementId = idForAccessible(cell);
QWinRTUiaMetadataCache::instance()->load(**ptrElementId);
*elementId = idForAccessible(cell);
QWinRTUiaMetadataCache::instance()->load(*elementId);
}
}
}
}
delete ptrElementId;
return S_OK;
}))) {
return E_FAIL;

View File

@ -64,6 +64,8 @@
#include <QtCore/qfunctions_winrt.h>
#include <QtCore/private/qeventdispatcher_winrt_p.h>
#include <memory>
using namespace QWinRTUiAutomation;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
@ -179,7 +181,7 @@ HRESULT QWinRTUiaMainProvider::rawProviderForAccessibleId(QAccessible::Id elemen
}
// Returns an array of IIRawElementProviderSimple instances for a list of accessible interface ids.
HRESULT QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(const QList<QAccessible::Id> &elementIds,
HRESULT QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(const QVarLengthArray<QAccessible::Id> &elementIds,
UINT32 *returnValueSize,
IIRawElementProviderSimple ***returnValue)
{
@ -190,7 +192,7 @@ HRESULT QWinRTUiaMainProvider::rawProviderArrayForAccessibleIdList(const QList<Q
QList<IIRawElementProviderSimple *> rawProviderList;
for (auto elementId : qAsConst(elementIds)) {
for (auto elementId : elementIds) {
IIRawElementProviderSimple *rawProvider;
if (SUCCEEDED(rawProviderForAccessibleId(elementId, &rawProvider)))
rawProviderList.append(rawProvider);
@ -515,10 +517,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetChildrenCore(IVector<Automat
*returnValue = nullptr;
auto accid = id();
auto children = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
auto ptrChildren = new QSharedPointer<QList<QAccessible::Id>>(children);
auto children = std::make_shared<QVarLengthArray<QAccessible::Id>>();
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrChildren]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, children]() {
if (QAccessibleInterface *accessible = accessibleForId(accid)) {
int childCount = accessible->childCount();
for (int i = 0; i < childCount; ++i) {
@ -526,11 +527,10 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetChildrenCore(IVector<Automat
QAccessible::Id childId = idForAccessible(childAcc);
QWinRTUiaMetadataCache::instance()->load(childId);
if (!childAcc->state().invisible)
(*ptrChildren)->append(childId);
children->append(childId);
}
}
}
delete ptrChildren;
return S_OK;
}))) {
return E_FAIL;
@ -538,7 +538,7 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetChildrenCore(IVector<Automat
ComPtr<IVector<AutomationPeer *>> peerVector = Make<QWinRTUiaPeerVector>();
for (auto childId : qAsConst(*children)) {
for (auto childId : *children) {
if (ComPtr<QWinRTUiaMainProvider> provider = providerForAccessibleId(childId)) {
IAutomationPeer *peer;
if (SUCCEEDED(provider.CopyTo(&peer)))
@ -750,10 +750,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetPeerFromPointCore(ABI::Windo
// Scale coordinates from High DPI screens?
auto accid = id();
auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0));
auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId);
auto elementId = std::make_shared<QAccessible::Id>(0);
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId, point]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementId, point]() {
// Controls can be embedded within grouping elements. By default returns the innermost control.
QAccessibleInterface *target = accessibleForId(accid);
while (QAccessibleInterface *tmpacc = target->childAt(point.X, point.Y)) {
@ -761,9 +760,8 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaMainProvider::GetPeerFromPointCore(ABI::Windo
// For accessibility tools it may be better to return the text element instead of its subcomponents.
if (target->textInterface()) break;
}
**ptrElementId = idForAccessible(target);
QWinRTUiaMetadataCache::instance()->load(**ptrElementId);
delete ptrElementId;
*elementId = idForAccessible(target);
QWinRTUiaMetadataCache::instance()->load(*elementId);
return S_OK;
}))) {
return E_FAIL;

View File

@ -69,7 +69,7 @@ public:
virtual ~QWinRTUiaMainProvider();
static QWinRTUiaMainProvider *providerForAccessibleId(QAccessible::Id id);
static HRESULT rawProviderForAccessibleId(QAccessible::Id elementId, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple **returnValue);
static HRESULT rawProviderArrayForAccessibleIdList(const QList<QAccessible::Id> &elementIds, UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue);
static HRESULT rawProviderArrayForAccessibleIdList(const QVarLengthArray<QAccessible::Id> &elementIds, UINT32 *returnValueSize, ABI::Windows::UI::Xaml::Automation::Provider::IIRawElementProviderSimple ***returnValue);
static void notifyFocusChange(QAccessibleEvent *event);
static void notifyVisibilityChange(QAccessibleEvent *event);
static void notifyStateChange(QAccessibleStateChangeEvent *event);

View File

@ -51,6 +51,8 @@
#include <QtCore/QString>
#include <QtCore/private/qeventdispatcher_winrt_p.h>
#include <memory>
QT_BEGIN_NAMESPACE
using namespace QWinRTUiAutomation;
@ -94,21 +96,19 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionItemProvider::get_SelectionContainer
*value = nullptr;
auto accid = id();
auto elementId = QSharedPointer<QAccessible::Id>(new QAccessible::Id(0));
auto ptrElementId = new QSharedPointer<QAccessible::Id>(elementId);
auto elementId = std::make_shared<QAccessible::Id>(0);
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementId]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementId]() {
if (QAccessibleInterface *accessible = accessibleForId(accid)) {
// Radio buttons do not require a container.
if (accessible->role() == QAccessible::ListItem) {
if (QAccessibleInterface *parent = accessible->parent()) {
if (parent->role() == QAccessible::List) {
**ptrElementId = idForAccessible(parent);
*elementId = idForAccessible(parent);
}
}
}
}
delete ptrElementId;
return S_OK;
}))) {
return E_FAIL;

View File

@ -51,6 +51,8 @@
#include <QtCore/QString>
#include <QtCore/private/qeventdispatcher_winrt_p.h>
#include <memory>
QT_BEGIN_NAMESPACE
using namespace QWinRTUiAutomation;
@ -89,10 +91,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::get_IsSelectionRequired(bo
*value = false;
auto accid = id();
auto selectionRequired = QSharedPointer<bool>(new bool(false));
auto ptrSelectionRequired = new QSharedPointer<bool>(selectionRequired);
auto selectionRequired = std::make_shared<bool>(false);
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrSelectionRequired]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, selectionRequired]() {
// Initially returns false if none are selected. After the first selection, it may be required.
bool anySelected = false;
if (QAccessibleInterface *accessible = accessibleForId(accid)) {
@ -105,9 +106,8 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::get_IsSelectionRequired(bo
}
}
}
**ptrSelectionRequired = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable;
*selectionRequired = anySelected && !accessible->state().multiSelectable && !accessible->state().extSelectable;
}
delete ptrSelectionRequired;
return S_OK;
}))) {
return E_FAIL;
@ -128,10 +128,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::GetSelection(UINT32 *retur
*returnValue = nullptr;
auto accid = id();
auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>();
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() {
if (QAccessibleInterface *accessible = accessibleForId(accid)) {
int childCount = accessible->childCount();
for (int i = 0; i < childCount; ++i) {
@ -139,12 +138,11 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaSelectionProvider::GetSelection(UINT32 *retur
if (childAcc->state().selected) {
QAccessible::Id childId = idForAccessible(childAcc);
QWinRTUiaMetadataCache::instance()->load(childId);
(*ptrElementIds)->append(childId);
elementIds->append(childId);
}
}
}
}
delete ptrElementIds;
return S_OK;
}))) {
return E_FAIL;

View File

@ -51,6 +51,8 @@
#include <QtCore/QString>
#include <QtCore/private/qeventdispatcher_winrt_p.h>
#include <memory>
QT_BEGIN_NAMESPACE
using namespace QWinRTUiAutomation;
@ -79,21 +81,19 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTableItemProvider::GetColumnHeaderItems(UINT3
*returnValue = nullptr;
auto accid = id();
auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>();
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() {
if (QAccessibleInterface *accessible = accessibleForId(accid)) {
if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) {
QList<QAccessibleInterface *> headers = tableCellInterface->columnHeaderCells();
for (auto header : qAsConst(headers)) {
QAccessible::Id headerId = idForAccessible(header);
QWinRTUiaMetadataCache::instance()->load(headerId);
(*ptrElementIds)->append(headerId);
elementIds->append(headerId);
}
}
}
delete ptrElementIds;
return S_OK;
}))) {
return E_FAIL;
@ -113,21 +113,19 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTableItemProvider::GetRowHeaderItems(UINT32 *
*returnValue = nullptr;
auto accid = id();
auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>();
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() {
if (QAccessibleInterface *accessible = accessibleForId(accid)) {
if (QAccessibleTableCellInterface *tableCellInterface = accessible->tableCellInterface()) {
QList<QAccessibleInterface *> headers = tableCellInterface->rowHeaderCells();
for (auto header : qAsConst(headers)) {
QAccessible::Id headerId = idForAccessible(header);
QWinRTUiaMetadataCache::instance()->load(headerId);
(*ptrElementIds)->append(headerId);
elementIds->append(headerId);
}
}
}
delete ptrElementIds;
return S_OK;
}))) {
return E_FAIL;

View File

@ -51,6 +51,8 @@
#include <QtCore/QString>
#include <QtCore/private/qeventdispatcher_winrt_p.h>
#include <memory>
QT_BEGIN_NAMESPACE
using namespace QWinRTUiAutomation;
@ -91,10 +93,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetColumnHeaders(UINT32 *retur
*returnValue = nullptr;
auto accid = id();
auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>();
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() {
if (QAccessibleInterface *accessible = accessibleForId(accid)) {
if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) {
for (int i = 0; i < tableInterface->columnCount(); ++i) {
@ -105,14 +106,13 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetColumnHeaders(UINT32 *retur
for (auto header : qAsConst(headers)) {
QAccessible::Id headerId = idForAccessible(header);
QWinRTUiaMetadataCache::instance()->load(headerId);
(*ptrElementIds)->append(headerId);
elementIds->append(headerId);
}
}
}
}
}
}
delete ptrElementIds;
return S_OK;
}))) {
return E_FAIL;
@ -132,10 +132,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetRowHeaders(UINT32 *returnVa
*returnValue = nullptr;
auto accid = id();
auto elementIds = QSharedPointer<QList<QAccessible::Id>>(new QList<QAccessible::Id>);
auto ptrElementIds = new QSharedPointer<QList<QAccessible::Id>>(elementIds);
auto elementIds = std::make_shared<QVarLengthArray<QAccessible::Id>>();
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrElementIds]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, elementIds]() {
if (QAccessibleInterface *accessible = accessibleForId(accid)) {
if (QAccessibleTableInterface *tableInterface = accessible->tableInterface()) {
for (int i = 0; i < tableInterface->rowCount(); ++i) {
@ -146,14 +145,13 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTableProvider::GetRowHeaders(UINT32 *returnVa
for (auto header : qAsConst(headers)) {
QAccessible::Id headerId = idForAccessible(header);
QWinRTUiaMetadataCache::instance()->load(headerId);
(*ptrElementIds)->append(headerId);
elementIds->append(headerId);
}
}
}
}
}
}
delete ptrElementIds;
return S_OK;
}))) {
return E_FAIL;

View File

@ -51,6 +51,8 @@
#include <QtCore/QString>
#include <QtCore/private/qeventdispatcher_winrt_p.h>
#include <memory>
QT_BEGIN_NAMESPACE
using namespace QWinRTUiAutomation;
@ -104,26 +106,26 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetSelection(UINT32 *returnValu
*returnValueSize = 0;
*returnValue = nullptr;
auto accid = id();
auto selections = QSharedPointer<QList<QPair<int,int>>>(new QList<QPair<int,int>>);
auto ptrSelections = new QSharedPointer<QList<QPair<int,int>>>(selections);
struct Selection { int startOffset, endOffset; };
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, ptrSelections]() {
auto accid = id();
auto selections = std::make_shared<QVarLengthArray<Selection>>();
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, selections]() {
if (QAccessibleInterface *accessible = accessibleForId(accid)) {
if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
for (int i = 0; i < textInterface->selectionCount(); ++i) {
QPair<int,int> sel;
textInterface->selection(i, &sel.first, &sel.second);
(*ptrSelections)->append(sel);
int startOffset, endOffset;
textInterface->selection(i, &startOffset, &endOffset);
selections->append({startOffset, endOffset});
}
if ((*ptrSelections)->size() == 0) {
if (selections->size() == 0) {
// If there is no selection, we return an array with a single degenerate (empty) text range at the cursor position.
QPair<int,int> sel(textInterface->cursorPosition(), textInterface->cursorPosition());
(*ptrSelections)->append(sel);
auto cur = textInterface->cursorPosition();
selections->append({cur, cur});
}
}
}
delete ptrSelections;
return S_OK;
}))) {
return E_FAIL;
@ -137,9 +139,11 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::GetSelection(UINT32 *returnValu
if (!providerArray)
return E_OUTOFMEMORY;
for (int i = 0; i < selCount; ++i) {
ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider = Make<QWinRTUiaTextRangeProvider>(id(), (*selections)[i].first, (*selections)[i].second);
textRangeProvider.CopyTo(&providerArray[i]);
auto dst = providerArray;
for (auto sel : *selections) {
ComPtr<QWinRTUiaTextRangeProvider> textRangeProvider
= Make<QWinRTUiaTextRangeProvider>(id(), sel.startOffset, sel.endOffset);
textRangeProvider.CopyTo(dst++);
}
*returnValueSize = selCount;
*returnValue = providerArray;
@ -184,14 +188,12 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextProvider::RangeFromPoint(ABI::Windows::Fo
const QPoint pt(screenLocation.X, screenLocation.Y);
auto accid = id();
auto offset = QSharedPointer<int>(new int);
auto ptrOffset = new QSharedPointer<int>(offset);
auto offset = std::make_shared<int>();
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, pt, ptrOffset]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, pt, offset]() {
if (QAccessibleInterface *accessible = accessibleForId(accid))
if (QAccessibleTextInterface *textInterface = accessible->textInterface())
**ptrOffset = qBound(0, textInterface->offsetAtPoint(pt), textInterface->characterCount() - 1);
delete ptrOffset;
*offset = qBound(0, textInterface->offsetAtPoint(pt), textInterface->characterCount() - 1);
return S_OK;
}))) {
return E_FAIL;

View File

@ -51,6 +51,8 @@
#include <QtCore/QString>
#include <QtCore/private/qeventdispatcher_winrt_p.h>
#include <memory>
QT_BEGIN_NAMESPACE
using namespace QWinRTUiAutomation;
@ -212,10 +214,9 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetBoundingRectangles(UINT
auto accid = id();
auto startOffset = m_startOffset;
auto endOffset = m_endOffset;
auto rects = QSharedPointer<QList<QRect>>(new QList<QRect>);
auto ptrRects = new QSharedPointer<QList<QRect>>(rects);
auto rects = std::make_shared<QVarLengthArray<QRect>>();
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset, ptrRects]() {
if (!SUCCEEDED(QEventDispatcherWinRT::runOnMainThread([accid, startOffset, endOffset, rects]() {
if (QAccessibleInterface *accessible = accessibleForId(accid)) {
if (QAccessibleTextInterface *textInterface = accessible->textInterface()) {
int len = textInterface->characterCount();
@ -233,7 +234,7 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetBoundingRectangles(UINT
qMin(startRect.y(), endRect.y()),
qMax(startRect.x() + startRect.width(), endRect.x() + endRect.width()) - qMin(startRect.x(), endRect.x()),
qMax(startRect.y() + startRect.height(), endRect.y() + endRect.height()) - qMin(startRect.y(), endRect.y()));
(*ptrRects)->append(lineRect);
rects->append(lineRect);
}
if (end >= len) break;
textInterface->textAfterOffset(end + 1, QAccessible::LineBoundary, &start, &end);
@ -241,7 +242,6 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetBoundingRectangles(UINT
}
}
}
delete ptrRects;
return S_OK;
}))) {
return E_FAIL;
@ -251,11 +251,12 @@ HRESULT STDMETHODCALLTYPE QWinRTUiaTextRangeProvider::GetBoundingRectangles(UINT
if (!doubleArray)
return E_OUTOFMEMORY;
for (int i = 0; i < rects->size(); ++i) {
doubleArray[i*4] = (*rects)[i].left();
doubleArray[i*4+1] = (*rects)[i].top();
doubleArray[i*4+2] = (*rects)[i].width();
doubleArray[i*4+3] = (*rects)[i].height();
DOUBLE *dst = doubleArray;
for (auto rect : *rects) {
*dst++ = rect.left();
*dst++ = rect.top();
*dst++ = rect.width();
*dst++ = rect.height();
}
*returnValue = doubleArray;
*returnValueSize = 4 * rects->size();

View File

@ -57,6 +57,9 @@
#ifdef Q_OS_WIN
# include <QtCore/QVarLengthArray>
# include <qt_windows.h>
# ifndef Q_OS_WINRT
# include <shlobj.h>
# endif
#endif
QT_BEGIN_NAMESPACE
@ -837,8 +840,8 @@ QString QFileSystemModelPrivate::displayName(const QModelIndex &index) const
{
#if defined(Q_OS_WIN)
QFileSystemNode *dirNode = node(index);
if (!dirNode->volumeName.isNull())
return dirNode->volumeName + QLatin1String(" (") + name(index) + QLatin1Char(')');
if (!dirNode->volumeName.isEmpty())
return dirNode->volumeName;
#endif
return name(index);
}
@ -1773,6 +1776,27 @@ void QFileSystemModelPrivate::_q_directoryChanged(const QString &directory, cons
removeNode(parentNode, toRemove[i]);
}
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
static QString volumeName(const QString &path)
{
IShellItem *item = nullptr;
const QString native = QDir::toNativeSeparators(path);
HRESULT hr = SHCreateItemFromParsingName(reinterpret_cast<const wchar_t *>(native.utf16()),
nullptr, IID_IShellItem,
reinterpret_cast<void **>(&item));
if (FAILED(hr))
return QString();
LPWSTR name = nullptr;
hr = item->GetDisplayName(SIGDN_NORMALDISPLAY, &name);
if (FAILED(hr))
return QString();
QString result = QString::fromWCharArray(name);
CoTaskMemFree(name);
item->Release();
return result;
}
#endif // Q_OS_WIN && !Q_OS_WINRT
/*!
\internal
@ -1791,15 +1815,8 @@ QFileSystemModelPrivate::QFileSystemNode* QFileSystemModelPrivate::addNode(QFile
#endif
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
//The parentNode is "" so we are listing the drives
if (parentNode->fileName.isEmpty()) {
wchar_t name[MAX_PATH + 1];
//GetVolumeInformation requires to add trailing backslash
const QString nodeName = fileName + QLatin1String("\\");
BOOL success = ::GetVolumeInformation((wchar_t *)(nodeName.utf16()),
name, MAX_PATH + 1, NULL, 0, NULL, NULL, 0);
if (success && name[0])
node->volumeName = QString::fromWCharArray(name);
}
if (parentNode->fileName.isEmpty())
node->volumeName = volumeName(fileName);
#endif
Q_ASSERT(!parentNode->children.contains(fileName));
parentNode->children.insert(fileName, node);

View File

@ -659,24 +659,22 @@ int QShortcut::id() const
bool QShortcut::event(QEvent *e)
{
Q_D(QShortcut);
bool handled = false;
if (d->sc_enabled && e->type() == QEvent::Shortcut) {
auto se = static_cast<QShortcutEvent *>(e);
if (se->shortcutId() == d->sc_id && se->key() == d->sc_sequence){
#if QT_CONFIG(whatsthis)
if (QWhatsThis::inWhatsThisMode()) {
QWhatsThis::showText(QCursor::pos(), d->sc_whatsthis);
handled = true;
} else
#endif
if (se->isAmbiguous())
emit activatedAmbiguously();
else
emit activated();
handled = true;
return true;
}
}
return handled;
return QObject::event(e);
}
#endif // QT_NO_SHORTCUT

View File

@ -1760,7 +1760,7 @@ QStyleOptionMenuItem::QStyleOptionMenuItem(int version)
\value Exclusive The item is an exclusive check item (like a radio button).
\value NonExclusive The item is a non-exclusive check item (like a check box).
\sa checkType, QAction::checkable, QAction::checked, QActionGroup::exclusive
\sa checkType, QAction::checkable, QAction::checked, QActionGroup::exclusionPolicy
*/
/*!

View File

@ -862,6 +862,16 @@ QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption() const
when the choice is not changed. If you need to know when the
choice actually changes, use signal currentIndexChanged().
\obsolete Use QComboBox::textActivated() instead
*/
/*!
\fn void QComboBox::textActivated(const QString &text)
\since 5.14
This signal is sent when the user chooses an item in the combobox.
The item's \a text is passed. Note that this signal is sent even
when the choice is not changed. If you need to know when the
choice actually changes, use signal currentIndexChanged().
*/
/*!
@ -876,6 +886,15 @@ QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption() const
This signal is sent when an item in the combobox popup list is
highlighted by the user. The item's \a text is passed.
\obsolete Use textHighlighted() instead
*/
/*!
\fn void QComboBox::textHighlighted(const QString &text)
\since 5.14
This signal is sent when an item in the combobox popup list is
highlighted by the user. The item's \a text is passed.
*/
/*!
@ -888,7 +907,6 @@ QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption() const
currentIndex was reset.
*/
#if QT_DEPRECATED_SINCE(5, 13)
/*!
\fn void QComboBox::currentIndexChanged(const QString &text)
\since 4.1
@ -897,7 +915,6 @@ QStyleOptionComboBox QComboBoxPrivateContainer::comboStyleOption() const
changes either through user interaction or programmatically. The
item's \a text is passed.
*/
#endif
/*!
\fn void QComboBox::currentTextChanged(const QString &text)

View File

@ -2332,14 +2332,17 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
// However if the QMenu was constructed with a QDesktopScreenWidget as its parent,
// then initialScreenIndex was set, so we should respect that for the lifetime of this menu.
// Use d->popupScreen to remember, because initialScreenIndex will be reset after the first showing.
const int screenIndex = d->topData()->initialScreenIndex;
if (screenIndex >= 0)
d->popupScreen = screenIndex;
if (auto s = QGuiApplication::screens().value(d->popupScreen)) {
if (d->setScreen(s))
// However if eventLoop exists, then exec() already did this by calling createWinId(); so leave it alone. (QTBUG-76162)
if (!d->eventLoop) {
const int screenIndex = d->topData()->initialScreenIndex;
if (screenIndex >= 0)
d->popupScreen = screenIndex;
if (auto s = QGuiApplication::screens().value(d->popupScreen)) {
if (d->setScreen(s))
d->itemsDirty = true;
} else if (d->setScreenForPoint(p)) {
d->itemsDirty = true;
} else if (d->setScreenForPoint(p)) {
d->itemsDirty = true;
}
}
const bool contextMenu = d->isContextMenu();

View File

@ -139,6 +139,7 @@ private slots:
void superscriptCrash_qtbug53911();
void showLineAndParagraphSeparatorsCrash();
void koreanWordWrap();
void tooManyDirectionalCharctersCrash_qtbug77819();
private:
QFont testFont;
@ -2330,5 +2331,21 @@ void tst_QTextLayout::koreanWordWrap()
QCOMPARE(layout.lineAt(1).textLength(), 4);
}
void tst_QTextLayout::tooManyDirectionalCharctersCrash_qtbug77819()
{
QString data;
data += QString::fromUtf8("\xe2\x81\xa8"); // U+2068 FSI character
data += QString::fromUtf8("\xe2\x81\xa7"); // U+2067 RLI character
// duplicating the text
for (int i = 0; i < 10; i++)
data += data;
// Nothing to test. It must not crash in beginLayout().
QTextLayout tl(data);
tl.beginLayout();
tl.endLayout();
}
QTEST_MAIN(tst_QTextLayout)
#include "tst_qtextlayout.moc"

View File

@ -477,6 +477,9 @@ void tst_Http2::goaway_data()
// - server waits for some time (enough for ur to init several streams on a
// client side); then suddenly it replies with GOAWAY, never processing any
// request.
if (clearTextHTTP2)
QSKIP("This test requires TLS with ALPN to work");
QTest::addColumn<int>("responseTimeoutMS");
QTest::newRow("ImmediateGOAWAY") << 0;
QTest::newRow("DelayedGOAWAY") << 1000;

View File

@ -1010,7 +1010,10 @@ void PaintCommands::command_drawPixmap(QRegularExpressionMatch re)
qPrintable(re.captured(1)), pm.width(), pm.height(), pm.depth(),
tx, ty, tw, th, sx, sy, sw, sh);
m_painter->drawPixmap(QRectF(tx, ty, tw, th), pm, QRectF(sx, sy, sw, sh));
if (!re.capturedLength(4)) // at most two coordinates specified
m_painter->drawPixmap(QPointF(tx, ty), pm);
else
m_painter->drawPixmap(QRectF(tx, ty, tw, th), pm, QRectF(sx, sy, sw, sh));
}
/***************************************************************************************************/
@ -1057,7 +1060,10 @@ void PaintCommands::command_drawImage(QRegularExpressionMatch re)
printf(" -(lance) drawImage('%s' dim=(%d, %d), (%f, %f, %f, %f), (%f, %f, %f, %f)\n",
qPrintable(re.captured(1)), im.width(), im.height(), tx, ty, tw, th, sx, sy, sw, sh);
m_painter->drawImage(QRectF(tx, ty, tw, th), im, QRectF(sx, sy, sw, sh), Qt::OrderedDither | Qt::OrderedAlphaDither);
if (!re.capturedLength(4)) // at most two coordinates specified
m_painter->drawImage(QPointF(tx, ty), im);
else
m_painter->drawImage(QRectF(tx, ty, tw, th), im, QRectF(sx, sy, sw, sh));
}
/***************************************************************************************************/

View File

@ -26,15 +26,12 @@
**
****************************************************************************/
#include <QtTest/QtTest>
#include <qeventloop.h>
#include <qlist.h>
#include <qpair.h>
#include <qheaderview.h>
#include <qlineedit.h>
#include <qtablewidget.h>
#include <QHeaderView>
#include <QLineEdit>
#include <QMimeData>
#include <QSignalSpy>
#include <QTableWidget>
#include <QTest>
class QObjectTableItem : public QObject, public QTableWidgetItem
{
@ -46,11 +43,10 @@ class tst_QTableWidget : public QObject
Q_OBJECT
public:
tst_QTableWidget();
using QObject::QObject;
private slots:
void initTestCase();
void cleanupTestCase();
void init();
void getSetCheck();
void clear();
@ -97,12 +93,12 @@ private slots:
#endif
private:
QTableWidget *testWidget;
std::unique_ptr<QTableWidget> testWidget;
};
typedef QPair<int, int> IntPair;
typedef QList<int> IntList;
typedef QList<IntPair> IntIntList;
using IntPair = QPair<int, int>;
using IntList = QVector<int>;
using IntIntList = QVector<IntPair>;
Q_DECLARE_METATYPE(QTableWidgetSelectionRange)
@ -143,45 +139,36 @@ void tst_QTableWidget::getSetCheck()
obj1.setItem(3, 3, new QTableWidgetItem("3,3"));
obj1.setCurrentItem(var3);
QCOMPARE(var3, obj1.currentItem());
obj1.setCurrentItem((QTableWidgetItem *)0);
QCOMPARE((QTableWidgetItem *)0, obj1.currentItem());
obj1.setItem(0, 0, 0);
QCOMPARE((QTableWidgetItem *)0, obj1.item(0, 0));
obj1.setCurrentItem(nullptr);
QCOMPARE(obj1.currentItem(), nullptr);
obj1.setItem(0, 0, nullptr);
QCOMPARE(obj1.item(0, 0), nullptr);
// const QTableWidgetItem * QTableWidget::itemPrototype()
// void QTableWidget::setItemPrototype(const QTableWidgetItem *)
const QTableWidgetItem *var4 = new QTableWidgetItem;
obj1.setItemPrototype(var4);
QCOMPARE(var4, obj1.itemPrototype());
obj1.setItemPrototype((QTableWidgetItem *)0);
QCOMPARE((const QTableWidgetItem *)0, obj1.itemPrototype());
}
tst_QTableWidget::tst_QTableWidget(): testWidget(0)
{
obj1.setItemPrototype(nullptr);
QCOMPARE(obj1.itemPrototype(), nullptr);
}
void tst_QTableWidget::initTestCase()
{
testWidget = new QTableWidget();
testWidget.reset(new QTableWidget);
testWidget->show();
QApplication::setKeyboardInputInterval(100);
}
void tst_QTableWidget::cleanupTestCase()
{
delete testWidget;
}
void tst_QTableWidget::init()
{
testWidget->clear();
testWidget->setRowCount(5);
testWidget->setColumnCount(5);
for (int row=0; row < testWidget->rowCount(); ++row)
for (int row = 0; row < testWidget->rowCount(); ++row)
testWidget->showRow(row);
for (int column=0; column < testWidget->columnCount(); ++column)
for (int column = 0; column < testWidget->columnCount(); ++column)
testWidget->showColumn(column);
}
@ -319,13 +306,15 @@ void tst_QTableWidget::item()
QCOMPARE(testWidget->rowCount(), rowCount);
QCOMPARE(testWidget->columnCount(), columnCount);
for (int r = 0; r < testWidget->rowCount(); ++r)
for (int r = 0; r < testWidget->rowCount(); ++r) {
for (int c = 0; c < testWidget->columnCount(); ++c)
testWidget->setItem(r, c, new QTableWidgetItem(QString::number(r * c + c)));
}
for (int r = 0; r < testWidget->rowCount(); ++r)
for (int r = 0; r < testWidget->rowCount(); ++r) {
for (int c = 0; c < testWidget->columnCount(); ++c)
QCOMPARE(testWidget->item(r, c)->text(), QString::number(r * c + c));
}
QTableWidgetItem *item = testWidget->item(row, column);
QCOMPARE(!!item, expectItem);
@ -361,15 +350,17 @@ void tst_QTableWidget::takeItem()
QCOMPARE(testWidget->rowCount(), rowCount);
QCOMPARE(testWidget->columnCount(), columnCount);
for (int r = 0; r < testWidget->rowCount(); ++r)
for (int r = 0; r < testWidget->rowCount(); ++r) {
for (int c = 0; c < testWidget->columnCount(); ++c)
testWidget->setItem(r, c, new QTableWidgetItem(QString::number(r * c + c)));
}
for (int r = 0; r < testWidget->rowCount(); ++r)
for (int r = 0; r < testWidget->rowCount(); ++r) {
for (int c = 0; c < testWidget->columnCount(); ++c)
QCOMPARE(testWidget->item(r, c)->text(), QString::number(r * c + c));
}
QSignalSpy spy(testWidget, &QTableWidget::cellChanged);
QSignalSpy spy(testWidget.get(), &QTableWidget::cellChanged);
QTableWidgetItem *item = testWidget->takeItem(row, column);
QCOMPARE(!!item, expectItem);
if (expectItem) {
@ -516,11 +507,11 @@ void tst_QTableWidget::selectedItems()
{
QFETCH(int, rowCount);
QFETCH(int, columnCount);
QFETCH(IntIntList, createItems);
QFETCH(IntList, hiddenRows);
QFETCH(IntList, hiddenColumns);
QFETCH(QTableWidgetSelectionRange, selectionRange);
QFETCH(IntIntList, expectedItems);
QFETCH(const IntIntList, createItems);
QFETCH(const IntList, hiddenRows);
QFETCH(const IntList, hiddenColumns);
QFETCH(const QTableWidgetSelectionRange, selectionRange);
QFETCH(const IntIntList, expectedItems);
// set dimensions and test they are ok
testWidget->setRowCount(rowCount);
@ -529,15 +520,15 @@ void tst_QTableWidget::selectedItems()
QCOMPARE(testWidget->columnCount(), columnCount);
// create and set items
foreach (IntPair intPair, createItems) {
for (const auto &intPair : createItems) {
testWidget->setItem(intPair.first, intPair.second,
new QTableWidgetItem(QString("Item %1 %2")
.arg(intPair.first).arg(intPair.second)));
}
// hide rows/columns
foreach (int row, hiddenRows)
for (int row : hiddenRows)
testWidget->setRowHidden(row, true);
foreach (int column, hiddenColumns)
for (int column : hiddenColumns)
testWidget->setColumnHidden(column, true);
// make sure we don't have any previous selections hanging around
@ -557,31 +548,18 @@ void tst_QTableWidget::selectedItems()
}
// check that the correct number of items and the expected items are there
QList<QTableWidgetItem *> selectedItems = testWidget->selectedItems();
const QList<QTableWidgetItem *> selectedItems = testWidget->selectedItems();
QCOMPARE(selectedItems.count(), expectedItems.count());
foreach (IntPair intPair, expectedItems)
for (const auto &intPair : expectedItems)
QVERIFY(selectedItems.contains(testWidget->item(intPair.first, intPair.second)));
// check that setItemSelected agrees with selectedItems
for (int row = 0; row<testWidget->rowCount(); ++row) {
bool hidden = false;
foreach (int hiddenRow, hiddenRows){
if(hiddenRow == row){
hidden = true;
break;
}
}
if (hidden)
for (int row = 0; row < testWidget->rowCount(); ++row) {
if (hiddenRows.contains(row))
continue;
for (int column = 0; column<testWidget->columnCount(); ++column) {
foreach (int hiddenColumn, hiddenColumns){
if(hiddenColumn == column){
hidden = true;
break;
}
}
if (hidden)
for (int column = 0; column < testWidget->columnCount(); ++column) {
if (hiddenColumns.contains(column))
continue;
QTableWidgetItem *item = testWidget->item(row, column);
@ -621,11 +599,13 @@ void tst_QTableWidget::removeRow()
QCOMPARE(testWidget->columnCount(), columnCount);
// fill table with items
for (int r = 0; r < rowCount; ++r)
for (int c = 0; c < columnCount; ++c)
for (int r = 0; r < rowCount; ++r) {
const QString rRow = QString::number(r) + QLatin1Char(':');
for (int c = 0; c < columnCount; ++c) {
testWidget->setItem(r, c,
new QTableWidgetItem(
QString::number(r) + ":" + QString::number(c)));
new QTableWidgetItem(rRow + QString::number(c)));
}
}
// remove and compare the results
testWidget->removeRow(row);
@ -633,14 +613,18 @@ void tst_QTableWidget::removeRow()
QCOMPARE(testWidget->columnCount(), expectedColumnCount);
// check if the correct items were removed
for (int r = 0; r < expectedRowCount; ++r)
for (int c = 0; c < expectedColumnCount; ++c)
for (int r = 0; r < expectedRowCount; ++r) {
const QString rRow = QString::number(r < row ? r : r + 1) +
QLatin1Char(':');
for (int c = 0; c < expectedColumnCount; ++c) {
if (r < row)
QCOMPARE(testWidget->item(r, c)->text(),
QString::number(r) + ":" + QString::number(c));
rRow + QString::number(c));
else
QCOMPARE(testWidget->item(r, c)->text(),
QString::number(r + 1) + ":" + QString::number(c));
rRow + QString::number(c));
}
}
}
void tst_QTableWidget::removeColumn_data()
@ -673,11 +657,14 @@ void tst_QTableWidget::removeColumn()
QCOMPARE(testWidget->columnCount(), columnCount);
// fill table with items
for (int r = 0; r < rowCount; ++r)
for (int c = 0; c < columnCount; ++c)
for (int r = 0; r < rowCount; ++r) {
const QString rStr = QString::number(r) + QLatin1Char(':');
for (int c = 0; c < columnCount; ++c) {
testWidget->setItem(r, c,
new QTableWidgetItem(
QString::number(r) + ":" + QString::number(c)));
rStr + QString::number(c)));
}
}
// remove and compare the results
testWidget->removeColumn(column);
@ -686,14 +673,17 @@ void tst_QTableWidget::removeColumn()
// check if the correct items were removed
for (int r = 0; r < expectedRowCount; ++r)
for (int c = 0; c < expectedColumnCount; ++c)
for (int r = 0; r < expectedRowCount; ++r) {
const QString rStr = QString::number(r) + QLatin1Char(':');
for (int c = 0; c < expectedColumnCount; ++c) {
if (c < column)
QCOMPARE(testWidget->item(r, c)->text(),
QString::number(r) + ":" + QString::number(c));
rStr + QString::number(c));
else
QCOMPARE(testWidget->item(r, c)->text(),
QString::number(r) + ":" + QString::number(c + 1));
rStr + QString::number(c + 1));
}
}
}
void tst_QTableWidget::insertRow_data()
@ -819,7 +809,7 @@ void tst_QTableWidget::itemOwnership()
item = new QObjectTableItem();
testWidget->setItem(0, 0, item);
delete item;
QCOMPARE(testWidget->item(0, 0), (QTableWidgetItem *)0);
QCOMPARE(testWidget->item(0, 0), nullptr);
//delete vertical headeritem from outside
headerItem = new QObjectTableItem();
@ -887,7 +877,7 @@ void tst_QTableWidget::sortItems_data()
{
QTest::addColumn<int>("rowCount");
QTest::addColumn<int>("columnCount");
QTest::addColumn<int>("sortOrder");
QTest::addColumn<Qt::SortOrder>("sortOrder");
QTest::addColumn<int>("sortColumn");
QTest::addColumn<QStringList>("initial");
QTest::addColumn<QStringList>("expected");
@ -897,7 +887,7 @@ void tst_QTableWidget::sortItems_data()
QTest::newRow("ascending")
<< 4 << 5
<< static_cast<int>(Qt::AscendingOrder)
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
@ -915,7 +905,7 @@ void tst_QTableWidget::sortItems_data()
QTest::newRow("descending")
<< 4 << 5
<< static_cast<int>(Qt::DescendingOrder)
<< Qt::DescendingOrder
<< 0
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
@ -933,154 +923,151 @@ void tst_QTableWidget::sortItems_data()
QTest::newRow("empty table")
<< 4 << 5
<< static_cast<int>(Qt::AscendingOrder)
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< 0 << 0 << 0 << 0 << 0
<< 0 << 0 << 0 << 0 << 0
<< 0 << 0 << 0 << 0 << 0
<< 0 << 0 << 0 << 0 << 0)
<< QString() << QString() << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString())
<< (QStringList()
<< 0 << 0 << 0 << 0 << 0
<< 0 << 0 << 0 << 0 << 0
<< 0 << 0 << 0 << 0 << 0
<< 0 << 0 << 0 << 0 << 0)
<< QString() << QString() << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString())
<< IntList()
<< IntList()
<< IntList();
QTest::newRow("half-empty table")
<< 4 << 5
<< static_cast<int>(Qt::AscendingOrder)
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< "0" << 0 << 0 << 0 << 0
<< "3" << "d" << 0 << 0 << 0
<< "2" << "c" << 0 << 0 << 0
<< 0 << 0 << 0 << 0 << 0)
<< "0" << QString() << QString() << QString() << QString()
<< "3" << "d" << QString() << QString() << QString()
<< "2" << "c" << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString())
<< (QStringList()
<< "0" << 0 << 0 << 0 << 0
<< "2" << "c" << 0 << 0 << 0
<< "3" << "d" << 0 << 0 << 0
<< 0 << 0 << 0 << 0 << 0)
<< "0" << QString() << QString() << QString() << QString()
<< "2" << "c" << QString() << QString() << QString()
<< "3" << "d" << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString())
<< (IntList() << 0 << 2 << 1)
<< IntList()
<< IntList();
QTest::newRow("empty column, should not sort.")
<< 4 << 5
<< static_cast<int>(Qt::AscendingOrder)
<< Qt::AscendingOrder
<< 3
<< (QStringList()
<< "0" << 0 << 0 << 0 << 0
<< "3" << "d" << 0 << 0 << 0
<< "2" << "c" << 0 << 0 << 0
<< 0 << 0 << 0 << 0 << 0)
<< "0" << QString() << QString() << QString() << QString()
<< "3" << "d" << QString() << QString() << QString()
<< "2" << "c" << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString())
<< (QStringList()
<< "0" << 0 << 0 << 0 << 0
<< "3" << "d" << 0 << 0 << 0
<< "2" << "c" << 0 << 0 << 0
<< 0 << 0 << 0 << 0 << 0)
<< "0" << QString() << QString() << QString() << QString()
<< "3" << "d" << QString() << QString() << QString()
<< "2" << "c" << QString() << QString() << QString()
<< QString() << QString() << QString() << QString() << QString())
<< IntList()
<< IntList()
<< IntList();
QTest::newRow("descending with null cell, the null cell should be placed at the bottom")
<< 4 << 5
<< static_cast<int>(Qt::DescendingOrder)
<< Qt::DescendingOrder
<< 0
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< 0 << "b" << "7" << "3" << "u")
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< QString() << "b" << "7" << "3" << "u")
<< (QStringList()
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< "0" << "a" << "o" << "8" << "k"
<< 0 << "b" << "7" << "3" << "u")
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< "0" << "a" << "o" << "8" << "k"
<< QString() << "b" << "7" << "3" << "u")
<< (IntList() << 2 << 0 << 1)
<< IntList()
<< IntList();
QTest::newRow("ascending with null cell, the null cell should be placed at the bottom")
<< 4 << 5
<< static_cast<int>(Qt::AscendingOrder)
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< 0 << "b" << "7" << "3" << "u")
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< "2" << "c" << "9" << "y" << "8"
<< QString() << "b" << "7" << "3" << "u")
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "2" << "c" << "9" << "y" << "8"
<< "3" << "d" << "k" << "o" << "6"
<< 0 << "b" << "7" << "3" << "u")
<< "0" << "a" << "o" << "8" << "k"
<< "2" << "c" << "9" << "y" << "8"
<< "3" << "d" << "k" << "o" << "6"
<< QString() << "b" << "7" << "3" << "u")
<< (IntList() << 0 << 2 << 1)
<< IntList()
<< IntList();
QTest::newRow("ascending with null cells, the null cells should be placed at the bottom")
<< 4 << 5
<< static_cast<int>(Qt::AscendingOrder)
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< "3" << "d" << "k" << "o" << "6"
<< "0" << "a" << "o" << "8" << "k"
<< 0 << "c" << "9" << "y" << "8"
<< 0 << "b" << "7" << "3" << "u")
<< "3" << "d" << "k" << "o" << "6"
<< "0" << "a" << "o" << "8" << "k"
<< QString() << "c" << "9" << "y" << "8"
<< QString() << "b" << "7" << "3" << "u")
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< 0 << "c" << "9" << "y" << "8"
<< 0 << "b" << "7" << "3" << "u")
<< "0" << "a" << "o" << "8" << "k"
<< "3" << "d" << "k" << "o" << "6"
<< QString() << "c" << "9" << "y" << "8"
<< QString() << "b" << "7" << "3" << "u")
<< (IntList() << 1 << 0)
<< IntList()
<< IntList();
QTest::newRow("ascending... Check a bug in PersistentIndexes")
<< 4 << 5
<< static_cast<int>(Qt::AscendingOrder)
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< "3" << "c" << "9" << "y" << "8"
<< "2" << "b" << "7" << "3" << "u"
<< "4" << "d" << "k" << "o" << "6"
<< "1" << "a" << "o" << "8" << "k"
)
<< "1" << "a" << "o" << "8" << "k")
<< (QStringList()
<< "1" << "a" << "o" << "8" << "k"
<< "2" << "b" << "7" << "3" << "u"
<< "3" << "c" << "9" << "y" << "8"
<< "4" << "d" << "k" << "o" << "6"
)
<< "4" << "d" << "k" << "o" << "6")
<< (IntList() << 2 << 1 << 3 << 0)
<< IntList()
<< IntList();
QTest::newRow("ascending with some null cells inbetween")
<< 4 << 5
<< static_cast<int>(Qt::AscendingOrder)
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< 0 << "a" << "o" << "8" << "k"
<< "2" << "c" << "9" << "y" << "8"
<< 0 << "d" << "k" << "o" << "6"
<< "1" << "b" << "7" << "3" << "u")
<< QString() << "a" << "o" << "8" << "k"
<< "2" << "c" << "9" << "y" << "8"
<< QString() << "d" << "k" << "o" << "6"
<< "1" << "b" << "7" << "3" << "u")
<< (QStringList()
<< "1" << "b" << "7" << "3" << "u"
<< "2" << "c" << "9" << "y" << "8"
<< 0 << "a" << "o" << "8" << "k"
<< 0 << "d" << "k" << "o" << "6")
<< "1" << "b" << "7" << "3" << "u"
<< "2" << "c" << "9" << "y" << "8"
<< QString() << "a" << "o" << "8" << "k"
<< QString() << "d" << "k" << "o" << "6")
<< (IntList() << 1 << 0)
<< IntList()
<< IntList();
QTest::newRow("ascending hidden")
<< 4 << 5
<< static_cast<int>(Qt::AscendingOrder)
<< Qt::AscendingOrder
<< 0
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
@ -1098,7 +1085,7 @@ void tst_QTableWidget::sortItems_data()
QTest::newRow("descending hidden")
<< 4 << 5
<< static_cast<int>(Qt::DescendingOrder)
<< Qt::DescendingOrder
<< 0
<< (QStringList()
<< "0" << "a" << "o" << "8" << "k"
@ -1119,7 +1106,7 @@ void tst_QTableWidget::sortItems()
{
QFETCH(int, rowCount);
QFETCH(int, columnCount);
QFETCH(int, sortOrder);
QFETCH(Qt::SortOrder, sortOrder);
QFETCH(int, sortColumn);
QFETCH(QStringList, initial);
QFETCH(QStringList, expected);
@ -1131,13 +1118,13 @@ void tst_QTableWidget::sortItems()
testWidget->setColumnCount(columnCount);
QAbstractItemModel *model = testWidget->model();
QList<QPersistentModelIndex> persistent;
QVector<QPersistentModelIndex> persistent;
int ti = 0;
for (int r = 0; r < rowCount; ++r) {
for (int c = 0; c < columnCount; ++c) {
QString str = initial.at(ti++);
if (!str.isNull()) {
QString str = initial.at(ti++);
if (!str.isEmpty()) {
testWidget->setItem(r, c, new QTableWidgetItem(str));
}
}
@ -1150,7 +1137,7 @@ void tst_QTableWidget::sortItems()
QCOMPARE(testWidget->verticalHeader()->hiddenSectionCount(), initialHidden.count());
testWidget->sortItems(sortColumn, static_cast<Qt::SortOrder>(sortOrder));
testWidget->sortItems(sortColumn, sortOrder);
int te = 0;
for (int i = 0; i < rows.count(); ++i) {
@ -1175,7 +1162,7 @@ void tst_QTableWidget::setItemWithSorting_data()
{
QTest::addColumn<int>("rowCount");
QTest::addColumn<int>("columnCount");
QTest::addColumn<int>("sortOrder");
QTest::addColumn<Qt::SortOrder>("sortOrder");
QTest::addColumn<int>("sortColumn");
QTest::addColumn<QStringList>("initialValues");
QTest::addColumn<int>("row");
@ -1187,7 +1174,7 @@ void tst_QTableWidget::setItemWithSorting_data()
QTest::newRow("2x1 no change (ascending)")
<< 2 << 1
<< static_cast<int>(Qt::AscendingOrder) << 0
<< Qt::AscendingOrder << 0
<< (QStringList() << "0" << "1")
<< 1 << 0 << "2"
<< (QStringList() << "0" << "2")
@ -1195,7 +1182,7 @@ void tst_QTableWidget::setItemWithSorting_data()
<< false;
QTest::newRow("2x1 no change (descending)")
<< 2 << 1
<< static_cast<int>(Qt::DescendingOrder) << 0
<< Qt::DescendingOrder << 0
<< (QStringList() << "1" << "0")
<< 0 << 0 << "2"
<< (QStringList() << "2" << "0")
@ -1203,7 +1190,7 @@ void tst_QTableWidget::setItemWithSorting_data()
<< false;
QTest::newRow("2x1 reorder (ascending)")
<< 2 << 1
<< static_cast<int>(Qt::AscendingOrder) << 0
<< Qt::AscendingOrder << 0
<< (QStringList() << "0" << "1")
<< 0 << 0 << "2"
<< (QStringList() << "1" << "2")
@ -1211,7 +1198,7 @@ void tst_QTableWidget::setItemWithSorting_data()
<< true;
QTest::newRow("2x1 reorder (descending)")
<< 2 << 1
<< static_cast<int>(Qt::DescendingOrder) << 0
<< Qt::DescendingOrder << 0
<< (QStringList() << "1" << "0")
<< 1 << 0 << "2"
<< (QStringList() << "2" << "1")
@ -1219,7 +1206,7 @@ void tst_QTableWidget::setItemWithSorting_data()
<< true;
QTest::newRow("2x2 no change (ascending)")
<< 2 << 2
<< static_cast<int>(Qt::AscendingOrder) << 0
<< Qt::AscendingOrder << 0
<< (QStringList()
<< "0" << "00"
<< "1" << "11")
@ -1231,7 +1218,7 @@ void tst_QTableWidget::setItemWithSorting_data()
<< false;
QTest::newRow("2x2 reorder (ascending)")
<< 2 << 2
<< static_cast<int>(Qt::AscendingOrder) << 0
<< Qt::AscendingOrder << 0
<< (QStringList()
<< "0" << "00"
<< "1" << "11")
@ -1243,7 +1230,7 @@ void tst_QTableWidget::setItemWithSorting_data()
<< true;
QTest::newRow("2x2 reorder (ascending, sortColumn = 1)")
<< 2 << 2
<< static_cast<int>(Qt::AscendingOrder) << 1
<< Qt::AscendingOrder << 1
<< (QStringList()
<< "00" << "0"
<< "11" << "1")
@ -1255,7 +1242,7 @@ void tst_QTableWidget::setItemWithSorting_data()
<< true;
QTest::newRow("2x2 no change (column != sortColumn)")
<< 2 << 2
<< static_cast<int>(Qt::AscendingOrder) << 1
<< Qt::AscendingOrder << 1
<< (QStringList()
<< "00" << "0"
<< "11" << "1")
@ -1267,7 +1254,7 @@ void tst_QTableWidget::setItemWithSorting_data()
<< false;
QTest::newRow("8x4 reorder (ascending, sortColumn = 3)")
<< 8 << 4
<< static_cast<int>(Qt::AscendingOrder) << 3
<< Qt::AscendingOrder << 3
<< (QStringList()
<< "q" << "v" << "u" << "0"
<< "e" << "j" << "i" << "10"
@ -1293,9 +1280,13 @@ void tst_QTableWidget::setItemWithSorting_data()
void tst_QTableWidget::setItemWithSorting()
{
static int dummy1 = qRegisterMetaType<QList<QPersistentModelIndex>>();
static int dummy2 = qRegisterMetaType<QAbstractItemModel::LayoutChangeHint>();
Q_UNUSED(dummy1);
Q_UNUSED(dummy2);
QFETCH(int, rowCount);
QFETCH(int, columnCount);
QFETCH(int, sortOrder);
QFETCH(Qt::SortOrder, sortOrder);
QFETCH(int, sortColumn);
QFETCH(QStringList, initialValues);
QFETCH(int, row);
@ -1309,7 +1300,7 @@ void tst_QTableWidget::setItemWithSorting()
QTableWidget w(rowCount, columnCount);
QAbstractItemModel *model = w.model();
QList<QPersistentModelIndex> persistent;
QVector<QPersistentModelIndex> persistent;
int ti = 0;
for (int r = 0; r < rowCount; ++r) {
@ -1320,11 +1311,11 @@ void tst_QTableWidget::setItemWithSorting()
persistent << model->index(r, sortColumn);
}
w.sortItems(sortColumn, static_cast<Qt::SortOrder>(sortOrder));
w.sortItems(sortColumn, sortOrder);
w.setSortingEnabled(true);
QSignalSpy dataChangedSpy(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)));
QSignalSpy layoutChangedSpy(model, SIGNAL(layoutChanged()));
QSignalSpy dataChangedSpy(model, &QAbstractItemModel::dataChanged);
QSignalSpy layoutChangedSpy(model, &QAbstractItemModel::layoutChanged);
if (i == 0) {
// set a new item
@ -1376,7 +1367,7 @@ public:
void tst_QTableWidget::itemData()
{
QTableWidgetDataChanged widget(2, 2);
widget.setItem(0, 0, new QTableWidgetItem());
widget.setItem(0, 0, new QTableWidgetItem);
QTableWidgetItem *item = widget.item(0, 0);
QVERIFY(item);
item->setFlags(item->flags() | Qt::ItemIsEditable);
@ -1399,7 +1390,7 @@ void tst_QTableWidget::setItemData()
{
QTableWidgetDataChanged table(10, 10);
table.setSortingEnabled(false);
QSignalSpy dataChangedSpy(table.model(), SIGNAL(dataChanged(QModelIndex,QModelIndex)));
QSignalSpy dataChangedSpy(table.model(), &QAbstractItemModel::dataChanged);
QTableWidgetItem *item = new QTableWidgetItem;
table.setItem(0, 0, item);
@ -1432,11 +1423,11 @@ void tst_QTableWidget::cellWidget()
QTableWidget table(10, 10);
QWidget widget;
QCOMPARE(table.cellWidget(5, 5), static_cast<QWidget*>(0));
QCOMPARE(table.cellWidget(5, 5), nullptr);
table.setCellWidget(5, 5, &widget);
QCOMPARE(table.cellWidget(5, 5), &widget);
table.removeCellWidget(5, 5);
QCOMPARE(table.cellWidget(5, 5), static_cast<QWidget*>(0));
QCOMPARE(table.cellWidget(5, 5), nullptr);
}
void tst_QTableWidget::cellWidgetGeometry()
@ -1463,27 +1454,29 @@ void tst_QTableWidget::cellWidgetGeometry()
void tst_QTableWidget::sizeHint_data()
{
QTest::addColumn<int>("scrollBarPolicy");
QTest::addColumn<Qt::ScrollBarPolicy>("scrollBarPolicy");
QTest::addColumn<QSize>("viewSize");
QTest::newRow("ScrollBarAlwaysOn") << static_cast<int>(Qt::ScrollBarAlwaysOn) << QSize();
QTest::newRow("ScrollBarAlwaysOff") << static_cast<int>(Qt::ScrollBarAlwaysOff) << QSize();
QTest::newRow("ScrollBarAlwaysOn") << Qt::ScrollBarAlwaysOn << QSize();
QTest::newRow("ScrollBarAlwaysOff") << Qt::ScrollBarAlwaysOff << QSize();
// make sure the scrollbars are shown by resizing the view to 40x40
QTest::newRow("ScrollBarAsNeeded (40x40)") << static_cast<int>(Qt::ScrollBarAsNeeded) << QSize(40, 40);
QTest::newRow("ScrollBarAsNeeded (1000x1000)") << static_cast<int>(Qt::ScrollBarAsNeeded) << QSize(1000, 1000);
QTest::newRow("ScrollBarAsNeeded (40x40)") << Qt::ScrollBarAsNeeded << QSize(40, 40);
QTest::newRow("ScrollBarAsNeeded (1000x1000)") << Qt::ScrollBarAsNeeded << QSize(1000, 1000);
}
void tst_QTableWidget::sizeHint()
{
QFETCH(int, scrollBarPolicy);
QFETCH(Qt::ScrollBarPolicy, scrollBarPolicy);
QFETCH(QSize, viewSize);
QTableWidget view(2, 2);
view.setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
view.setVerticalScrollBarPolicy(static_cast<Qt::ScrollBarPolicy>(scrollBarPolicy));
view.setHorizontalScrollBarPolicy(static_cast<Qt::ScrollBarPolicy>(scrollBarPolicy));
for (int r = 0 ; r < view.rowCount(); ++r)
view.setVerticalScrollBarPolicy(scrollBarPolicy);
view.setHorizontalScrollBarPolicy(scrollBarPolicy);
for (int r = 0 ; r < view.rowCount(); ++r) {
const QString rStr = QString::number(r) + QLatin1Char('/');
for (int c = 0 ; c < view.columnCount(); ++c)
view.setItem(r, c, new QTableWidgetItem(QString("%1/%2").arg(r).arg(c)));
view.setItem(r, c, new QTableWidgetItem(rStr + QString::number(c)));
}
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
@ -1520,7 +1513,7 @@ void tst_QTableWidget::task231094()
if (y == 1)
twi->setFlags(Qt::ItemIsEnabled);
else
twi->setFlags(0);
twi->setFlags({});
tw.setItem(y, x, twi);
}
}
@ -1558,15 +1551,15 @@ void tst_QTableWidget::task262056_sortDuplicate()
testWidget->setColumnCount(2);
testWidget->setRowCount(8);
testWidget->setSortingEnabled(true);
QStringList items = (QStringList() << "AAA" << "BBB" << "CCC" << "CCC" << "DDD"\
<< "EEE" << "FFF" << "GGG");
for (int i = 0; i<8; i++ ) {
const QStringList items({"AAA", "BBB", "CCC", "CCC", "DDD",
"EEE", "FFF", "GGG"});
for (int i = 0; i < 8; i++ ) {
QTableWidgetItem *twi = new QTableWidgetItem(items.at(i));
testWidget->setItem(i,0,twi);
testWidget->setItem(i,1,new QTableWidgetItem(QLatin1String("item ") + QString::number(i)));
testWidget->setItem(i, 0, twi);
testWidget->setItem(i, 1, new QTableWidgetItem(QLatin1String("item ") + QString::number(i)));
}
testWidget->sortItems(0, Qt::AscendingOrder);
QSignalSpy layoutChangedSpy(testWidget->model(), SIGNAL(layoutChanged()));
QSignalSpy layoutChangedSpy(testWidget->model(), &QAbstractItemModel::layoutChanged);
testWidget->item(3,0)->setBackground(Qt::red);
QCOMPARE(layoutChangedSpy.count(),0);
@ -1586,18 +1579,14 @@ void tst_QTableWidget::itemWithHeaderItems()
QTableWidgetItem *item1_0 = new QTableWidgetItem(QTableWidgetItem::UserType);
table.setItem(1, 0, item1_0);
QCOMPARE(table.item(0, 1), static_cast<QTableWidgetItem *>(0));
QCOMPARE(table.item(0, 1), nullptr);
}
class TestTableWidget : public QTableWidget
{
Q_OBJECT
public:
TestTableWidget(int rows, int columns, QWidget *parent = 0)
: QTableWidget(rows, columns, parent)
{
}
using QTableWidget::QTableWidget;
using QTableWidget::mimeData;
using QTableWidget::indexFromItem;
using QTableWidget::keyPressEvent;
@ -1661,18 +1650,19 @@ void tst_QTableWidget::selectedRowAfterSorting()
{
TestTableWidget table(3,3);
table.setSelectionBehavior(QAbstractItemView::SelectRows);
for (int r = 0; r < 3; r++)
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++)
table.setItem(r,c,new QTableWidgetItem(QStringLiteral("0")));
table.setItem(r, c, new QTableWidgetItem(QStringLiteral("0")));
}
QHeaderView *localHorizontalHeader = table.horizontalHeader();
localHorizontalHeader->setSortIndicator(1,Qt::DescendingOrder);
table.setProperty("sortingEnabled",true);
table.selectRow(1);
table.item(1,1)->setText("9");
QCOMPARE(table.selectedItems().count(),3);
foreach (QTableWidgetItem *item, table.selectedItems()) {
QCOMPARE(item->row(),0);
}
const auto selectedItems = table.selectedItems();
for (QTableWidgetItem *item : selectedItems)
QCOMPARE(item->row(), 0);
}
void tst_QTableWidget::search()
@ -1717,10 +1707,11 @@ void tst_QTableWidget::search()
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void tst_QTableWidget::clearItemData()
{
QTableWidget table(3,3);
for (int r = 0; r < 3; r++)
QTableWidget table(3, 3);
for (int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++)
table.setItem(r,c,new QTableWidgetItem(QStringLiteral("0")));
table.setItem(r, c, new QTableWidgetItem(QStringLiteral("0")));
}
QSignalSpy dataChangeSpy(table.model(), &QAbstractItemModel::dataChanged);
QVERIFY(dataChangeSpy.isValid());
QVERIFY(!table.model()->clearItemData(QModelIndex()));

View File

@ -115,6 +115,7 @@ private slots:
void context();
void duplicatedShortcutOverride();
void shortcutToFocusProxy();
void deleteLater();
protected:
static Qt::KeyboardModifiers toButtons( int key );
@ -1263,5 +1264,14 @@ void tst_QShortcut::shortcutToFocusProxy()
QCOMPARE(le.text(), QString());
}
void tst_QShortcut::deleteLater()
{
QWidget w;
QPointer<QShortcut> sc(new QShortcut(QKeySequence(Qt::Key_1), &w));
sc->deleteLater();
QTRY_VERIFY(!sc);
}
QTEST_MAIN(tst_QShortcut)
#include "tst_qshortcut.moc"

View File

@ -28,10 +28,8 @@
#include "qbaselinetest.h"
#include "baselineprotocol.h"
#if QT_CONFIG(process)
# include <QtCore/QProcess>
#endif
#include <QtCore/QDir>
#include <QFile>
#define MAXCMDLINEARGS 128
@ -146,20 +144,15 @@ void addClientProperty(const QString& key, const QString& value)
*/
void fetchCustomClientProperties()
{
#if !QT_CONFIG(process)
QSKIP("This test requires QProcess support");
#else
QString script = "hostinfo.sh"; //### TBD: Windows implementation (hostinfo.bat)
QFile file("hostinfo.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&file);
QProcess runScript;
runScript.setWorkingDirectory(QCoreApplication::applicationDirPath());
runScript.start("sh", QStringList() << script, QIODevice::ReadOnly);
if (!runScript.waitForFinished(5000) || runScript.error() != QProcess::UnknownError) {
qWarning() << "QBaselineTest: Error running script" << runScript.workingDirectory() + QDir::separator() + script << ":" << runScript.errorString();
qDebug() << " stderr:" << runScript.readAllStandardError().trimmed();
}
while (!runScript.atEnd()) {
QByteArray line = runScript.readLine().trimmed(); // ###local8bit? utf8?
while (!in.atEnd()) {
QString line = in.readLine().trimmed(); // ###local8bit? utf8?
if (line.startsWith(QLatin1Char('#'))) // Ignore comments in file
continue;
QString key, val;
int colonPos = line.indexOf(':');
if (colonPos > 0) {
@ -171,7 +164,6 @@ void fetchCustomClientProperties()
else
qDebug() << "Unparseable script output ignored:" << line;
}
#endif // QT_CONFIG(process)
}