summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/3rdparty/sqlite/qt_attribution.json4
-rw-r--r--src/3rdparty/sqlite/sqlite3.c58
-rw-r--r--src/3rdparty/sqlite/sqlite3.h14
-rwxr-xr-xsrc/3rdparty/sqlite/update_sqlite.sh2
-rw-r--r--src/corelib/CMakeLists.txt4
-rw-r--r--src/corelib/compat/removed_api.cpp14
-rw-r--r--src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp16
-rw-r--r--src/corelib/doc/src/jni.qdoc10
-rw-r--r--src/corelib/itemmodels/qrangemodel_impl.h22
-rw-r--r--src/corelib/kernel/qassociativeiterable.cpp14
-rw-r--r--src/corelib/kernel/qassociativeiterable.h51
-rw-r--r--src/corelib/kernel/qiterable.cpp38
-rw-r--r--src/corelib/kernel/qiterable.h12
-rw-r--r--src/corelib/kernel/qjniobject.cpp175
-rw-r--r--src/corelib/kernel/qjniobject.h11
-rw-r--r--src/corelib/kernel/qjnitypes.h3
-rw-r--r--src/corelib/kernel/qmetaassociation.cpp195
-rw-r--r--src/corelib/kernel/qmetaassociation.h266
-rw-r--r--src/corelib/kernel/qmetacontainer.h121
-rw-r--r--src/corelib/kernel/qmetasequence.cpp176
-rw-r--r--src/corelib/kernel/qmetasequence.h308
-rw-r--r--src/corelib/kernel/qmetatype.cpp188
-rw-r--r--src/corelib/kernel/qsequentialiterable.cpp14
-rw-r--r--src/corelib/kernel/qsequentialiterable.h39
-rw-r--r--src/corelib/kernel/qvariant.cpp10
-rw-r--r--src/corelib/kernel/qvariant.h27
-rw-r--r--src/gui/accessible/linux/atspiadaptor.cpp44
-rw-r--r--src/gui/platform/unix/qxkbcommon.cpp6
-rw-r--r--src/gui/rhi/qrhivulkan.cpp77
-rw-r--r--src/gui/rhi/qrhivulkan_p.h10
-rw-r--r--src/gui/text/qfont.cpp69
-rw-r--r--src/gui/text/qfont_p.h2
-rw-r--r--src/gui/text/qtextengine.cpp4
-rw-r--r--src/gui/text/qtextengine_p.h2
-rw-r--r--src/network/access/qhttp2protocolhandler_p.h1
-rw-r--r--src/network/socket/qabstractsocket.cpp14
-rw-r--r--src/network/socket/qabstractsocket_p.h2
-rw-r--r--src/plugins/platforms/directfb/qdirectfbconvenience.cpp1
-rw-r--r--src/plugins/platforms/wasm/qwasmdrag.cpp13
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style.cpp267
-rw-r--r--src/plugins/tls/schannel/qtls_schannel.cpp9
-rw-r--r--src/sql/doc/qtsql.qdocconf3
-rw-r--r--src/sql/doc/src/sql-programming.qdoc2
-rw-r--r--src/widgets/CMakeLists.txt8
-rw-r--r--src/widgets/kernel/qtooltip.cpp17
-rw-r--r--src/widgets/styles/images/fusion_normalizedockup-10.png (renamed from src/widgets/styles/images/fusion_normalizedockup_10.png)bin234 -> 234 bytes
-rw-r--r--src/widgets/styles/images/fusion_normalizedockup-20.png (renamed from src/widgets/styles/images/fusion_normalizedockup_20.png)bin342 -> 342 bytes
-rw-r--r--src/widgets/styles/images/fusion_normalizedockup-48.png (renamed from src/widgets/styles/images/fusion_normalizedockup_48.png)bin487 -> 487 bytes
-rw-r--r--src/widgets/styles/images/fusion_normalizedockup-64.png (renamed from src/widgets/styles/images/fusion_normalizedockup_64.png)bin579 -> 579 bytes
-rw-r--r--tests/auto/corelib/itemmodels/qrangemodel/data.h13
-rw-r--r--tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp23
-rw-r--r--tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp270
-rw-r--r--tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp2
-rw-r--r--tests/auto/gui/text/qfont/tst_qfont.cpp59
-rw-r--r--tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp47
-rw-r--r--tests/auto/network/ssl/qsslsocket/certs/no_common_name.crt20
-rw-r--r--tests/auto/network/ssl/qsslsocket/certs/no_common_name.key28
-rw-r--r--tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp18
58 files changed, 2376 insertions, 447 deletions
diff --git a/src/3rdparty/sqlite/qt_attribution.json b/src/3rdparty/sqlite/qt_attribution.json
index 2f8bbc30a94..392d7adf0e3 100644
--- a/src/3rdparty/sqlite/qt_attribution.json
+++ b/src/3rdparty/sqlite/qt_attribution.json
@@ -7,10 +7,10 @@
"Description": "SQLite is a small C library that implements a self-contained, embeddable, zero-configuration SQL database engine.",
"Homepage": "https://www.sqlite.org/",
- "Version": "3.51.0",
+ "Version": "3.51.1",
"PURL": "pkg:github/sqlite/sqlite@version-$<VERSION>",
"CPE": "cpe:2.3:a:sqlite:sqlite:$<VERSION>:*:*:*:*:*:*:*",
- "DownloadLocation": "https://www.sqlite.org/2025/sqlite-amalgamation-3510000.zip",
+ "DownloadLocation": "https://www.sqlite.org/2025/sqlite-amalgamation-3510100.zip",
"License": "SQLite Blessing",
"LicenseId": "blessing",
"Copyright": "The authors disclaim copyright to the source code. However, a license can be obtained if needed."
diff --git a/src/3rdparty/sqlite/sqlite3.c b/src/3rdparty/sqlite/sqlite3.c
index 03d65b62820..912ac26944c 100644
--- a/src/3rdparty/sqlite/sqlite3.c
+++ b/src/3rdparty/sqlite/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.51.0. By combining all the individual C code files into this
+** version 3.51.1. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -18,7 +18,7 @@
** separate file. This file contains only code for the core SQLite library.
**
** The content in this amalgamation comes from Fossil check-in
-** fb2c931ae597f8d00a37574ff67aeed3eced with changes in files:
+** 281fc0e9afc38674b9b0991943b9e9d1e64c with changes in files:
**
**
*/
@@ -467,12 +467,12 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.51.0"
-#define SQLITE_VERSION_NUMBER 3051000
-#define SQLITE_SOURCE_ID "2025-11-04 19:38:17 fb2c931ae597f8d00a37574ff67aeed3eced4e5547f9120744ae4bfa8e74527b"
-#define SQLITE_SCM_BRANCH "trunk"
-#define SQLITE_SCM_TAGS "release major-release version-3.51.0"
-#define SQLITE_SCM_DATETIME "2025-11-04T19:38:17.314Z"
+#define SQLITE_VERSION "3.51.1"
+#define SQLITE_VERSION_NUMBER 3051001
+#define SQLITE_SOURCE_ID "2025-11-28 17:28:25 281fc0e9afc38674b9b0991943b9e9d1e64c6cbdb133d35f6f5c87ff6af38a88"
+#define SQLITE_SCM_BRANCH "branch-3.51"
+#define SQLITE_SCM_TAGS "release version-3.51.1"
+#define SQLITE_SCM_DATETIME "2025-11-28T17:28:25.933Z"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -10747,7 +10747,7 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
** &nbsp; ){
** &nbsp; // do something with pVal
** &nbsp; }
-** &nbsp; if( rc!=SQLITE_OK ){
+** &nbsp; if( rc!=SQLITE_DONE ){
** &nbsp; // an error has occurred
** &nbsp; }
** </pre></blockquote>)^
@@ -38004,6 +38004,7 @@ SQLITE_PRIVATE void *sqlite3HashInsert(Hash *pH, const char *pKey, void *data){
return 0;
}
+
/************** End of hash.c ************************************************/
/************** Begin file opcodes.c *****************************************/
/* Automatically generated. Do not edit */
@@ -130655,6 +130656,7 @@ SQLITE_PRIVATE void sqlite3SchemaClear(void *p){
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
sqlite3DeleteTrigger(&xdb, (Trigger*)sqliteHashData(pElem));
}
+
sqlite3HashClear(&temp2);
sqlite3HashInit(&pSchema->tblHash);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
@@ -160976,9 +160978,12 @@ SQLITE_PRIVATE int sqlite3VtabEponymousTableInit(Parse *pParse, Module *pMod){
addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName));
addModuleArgument(pParse, pTab, 0);
addModuleArgument(pParse, pTab, sqlite3DbStrDup(db, pTab->zName));
+ db->nSchemaLock++;
rc = vtabCallConstructor(db, pTab, pMod, pModule->xConnect, &zErr);
+ db->nSchemaLock--;
if( rc ){
sqlite3ErrorMsg(pParse, "%s", zErr);
+ pParse->rc = rc;
sqlite3DbFree(db, zErr);
sqlite3VtabEponymousTableClear(db, pMod);
}
@@ -174040,8 +174045,22 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2);
}
#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
- if( pTabList->a[pLevel->iFrom].fg.fromExists ){
- sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+2);
+ if( pTabList->a[pLevel->iFrom].fg.fromExists && i==pWInfo->nLevel-1 ){
+ /* If the EXISTS-to-JOIN optimization was applied, then the EXISTS
+ ** loop(s) will be the inner-most loops of the join. There might be
+ ** multiple EXISTS loops, but they will all be nested, and the join
+ ** order will not have been changed by the query planner. If the
+ ** inner-most EXISTS loop sees a single successful row, it should
+ ** break out of *all* EXISTS loops. But only the inner-most of the
+ ** nested EXISTS loops should do this breakout. */
+ int nOuter = 0; /* Nr of outer EXISTS that this one is nested within */
+ while( nOuter<i ){
+ if( !pTabList->a[pLevel[-nOuter-1].iFrom].fg.fromExists ) break;
+ nOuter++;
+ }
+ testcase( nOuter>0 );
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel[-nOuter].addrBrk);
+ VdbeComment((v, "EXISTS break"));
}
/* The common case: Advance to the next row */
if( pLevel->addrCont ) sqlite3VdbeResolveLabel(v, pLevel->addrCont);
@@ -186225,6 +186244,7 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
/* Clear the TEMP schema separately and last */
if( db->aDb[1].pSchema ){
sqlite3SchemaClear(db->aDb[1].pSchema);
+ assert( db->aDb[1].pSchema->trigHash.count==0 );
}
sqlite3VtabUnlockList(db);
@@ -187553,7 +187573,7 @@ SQLITE_API const char *sqlite3_errmsg(sqlite3 *db){
*/
SQLITE_API int sqlite3_set_errmsg(sqlite3 *db, int errcode, const char *zMsg){
int rc = SQLITE_OK;
- if( !sqlite3SafetyCheckSickOrOk(db) ){
+ if( !sqlite3SafetyCheckOk(db) ){
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
@@ -249220,6 +249240,7 @@ static void fts5SegIterReverseInitPage(Fts5Index *p, Fts5SegIter *pIter){
while( 1 ){
u64 iDelta = 0;
+ if( i>=n ) break;
if( eDetail==FTS5_DETAIL_NONE ){
/* todo */
if( i<n && a[i]==0 ){
@@ -260283,7 +260304,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- sqlite3_result_text(pCtx, "fts5: 2025-11-04 19:38:17 fb2c931ae597f8d00a37574ff67aeed3eced4e5547f9120744ae4bfa8e74527b", -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(pCtx, "fts5: 2025-11-28 17:28:25 281fc0e9afc38674b9b0991943b9e9d1e64c6cbdb133d35f6f5c87ff6af38a88", -1, SQLITE_TRANSIENT);
}
/*
@@ -265104,7 +265125,12 @@ static int fts5VocabOpenMethod(
return rc;
}
+/*
+** Restore cursor pCsr to the state it was in immediately after being
+** created by the xOpen() method.
+*/
static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
+ int nCol = pCsr->pFts5->pConfig->nCol;
pCsr->rowid = 0;
sqlite3Fts5IterClose(pCsr->pIter);
sqlite3Fts5StructureRelease(pCsr->pStruct);
@@ -265114,6 +265140,12 @@ static void fts5VocabResetCursor(Fts5VocabCursor *pCsr){
pCsr->nLeTerm = -1;
pCsr->zLeTerm = 0;
pCsr->bEof = 0;
+ pCsr->iCol = 0;
+ pCsr->iInstPos = 0;
+ pCsr->iInstOff = 0;
+ pCsr->colUsed = 0;
+ memset(pCsr->aCnt, 0, sizeof(i64)*nCol);
+ memset(pCsr->aDoc, 0, sizeof(i64)*nCol);
}
/*
diff --git a/src/3rdparty/sqlite/sqlite3.h b/src/3rdparty/sqlite/sqlite3.h
index 70a4a1b1a5e..76c567d050a 100644
--- a/src/3rdparty/sqlite/sqlite3.h
+++ b/src/3rdparty/sqlite/sqlite3.h
@@ -146,12 +146,12 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.51.0"
-#define SQLITE_VERSION_NUMBER 3051000
-#define SQLITE_SOURCE_ID "2025-11-04 19:38:17 fb2c931ae597f8d00a37574ff67aeed3eced4e5547f9120744ae4bfa8e74527b"
-#define SQLITE_SCM_BRANCH "trunk"
-#define SQLITE_SCM_TAGS "release major-release version-3.51.0"
-#define SQLITE_SCM_DATETIME "2025-11-04T19:38:17.314Z"
+#define SQLITE_VERSION "3.51.1"
+#define SQLITE_VERSION_NUMBER 3051001
+#define SQLITE_SOURCE_ID "2025-11-28 17:28:25 281fc0e9afc38674b9b0991943b9e9d1e64c6cbdb133d35f6f5c87ff6af38a88"
+#define SQLITE_SCM_BRANCH "branch-3.51"
+#define SQLITE_SCM_TAGS "release version-3.51.1"
+#define SQLITE_SCM_DATETIME "2025-11-28T17:28:25.933Z"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -10426,7 +10426,7 @@ SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
** &nbsp; ){
** &nbsp; // do something with pVal
** &nbsp; }
-** &nbsp; if( rc!=SQLITE_OK ){
+** &nbsp; if( rc!=SQLITE_DONE ){
** &nbsp; // an error has occurred
** &nbsp; }
** </pre></blockquote>)^
diff --git a/src/3rdparty/sqlite/update_sqlite.sh b/src/3rdparty/sqlite/update_sqlite.sh
index 4b8e1869d8c..3f7447dc4e5 100755
--- a/src/3rdparty/sqlite/update_sqlite.sh
+++ b/src/3rdparty/sqlite/update_sqlite.sh
@@ -8,7 +8,7 @@
version_maj=3
version_min=51
-version_patch=0
+version_patch=1
year=2025
version=${version_maj}.${version_min}.${version_patch}
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index e12d824cebb..5d3d3024e0b 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -175,12 +175,12 @@ qt_internal_add_module(Core
kernel/qfunctions_p.h
kernel/qiterable.cpp kernel/qiterable.h kernel/qiterable_impl.h
kernel/qmath.cpp kernel/qmath.h
- kernel/qmetaassociation.cpp
+ kernel/qmetaassociation.cpp kernel/qmetaassociation.h
kernel/qmetacontainer.cpp kernel/qmetacontainer.h
kernel/qmetaobject.cpp kernel/qmetaobject.h kernel/qmetaobject_p.h
kernel/qmetaobject_moc_p.h
kernel/qmetaobjectbuilder.cpp kernel/qmetaobjectbuilder_p.h
- kernel/qmetasequence.cpp
+ kernel/qmetasequence.cpp kernel/qmetasequence.h
kernel/qmetatype.cpp kernel/qmetatype.h kernel/qmetatype_p.h
kernel/qmimedata.cpp kernel/qmimedata.h
kernel/qtmetamacros.h kernel/qtmocconstants.h kernel/qtmochelpers.h
diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp
index 7fe8aeb63b7..63fce94dfac 100644
--- a/src/corelib/compat/removed_api.cpp
+++ b/src/corelib/compat/removed_api.cpp
@@ -1291,13 +1291,6 @@ QByteArray QMetaEnum::valueToKeys(int value) const
#include "qmutex.h"
-#include "qbytearray.h"
-
-QByteArray QByteArray::percentDecoded(char percent) const
-{
- return fromPercentEncoding(*this, percent);
-}
-
#if QT_CONFIG(thread)
void QBasicMutex::destroyInternal(QMutexPrivate *d)
{
@@ -1495,6 +1488,13 @@ bool QObject::doSetProperty(const char *name, const QVariant *lvalue, QVariant *
#if QT_CORE_REMOVED_SINCE(6, 11)
+#include "qbytearray.h"
+
+QByteArray QByteArray::percentDecoded(char percent) const
+{
+ return fromPercentEncoding(*this, percent);
+}
+
#if QT_CONFIG(thread)
// some of the previously inlined API became removed
#include "qreadwritelock.h"
diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp
index e23f6c9d103..1d7a3fa6409 100644
--- a/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp
+++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp
@@ -7,8 +7,8 @@
#include <QVariant>
#include <QColor>
#include <QPalette>
-#include <QSequentialIterable>
-#include <QAssociativeIterable>
+#include <QMetaSequence>
+#include <QMetaAssociation>
QString tr(const char *s)
{
@@ -125,14 +125,14 @@ QVariant examples()
QVariant variant = QVariant::fromValue(intList);
if (variant.canConvert<QVariantList>()) {
- QSequentialIterable iterable = variant.value<QSequentialIterable>();
+ QMetaSequence::Iterable iterable = variant.value<QMetaSequence::Iterable>();
// Can use C++11 range-for:
for (const QVariant &v : iterable) {
qDebug() << v;
}
// Can use iterators:
- QSequentialIterable::const_iterator it = iterable.begin();
- const QSequentialIterable::const_iterator end = iterable.end();
+ QMetaSequence::Iterable::const_iterator it = iterable.begin();
+ const QMetaSequence::Iterable::const_iterator end = iterable.end();
for ( ; it != end; ++it) {
qDebug() << *it;
}
@@ -149,14 +149,14 @@ QVariant examples()
QVariant variant = QVariant::fromValue(mapping);
if (variant.canConvert<QVariantHash>()) {
- QAssociativeIterable iterable = variant.value<QAssociativeIterable>();
+ QMetaAssociation::Iterable iterable = variant.value<QMetaAssociation::Iterable>();
// Can use C++11 range-for over the values:
for (const QVariant &v : iterable) {
qDebug() << v;
}
// Can use iterators:
- QAssociativeIterable::const_iterator it = iterable.begin();
- const QAssociativeIterable::const_iterator end = iterable.end();
+ QMetaAssociation::Iterable::const_iterator it = iterable.begin();
+ const QMetaAssociation::Iterable::const_iterator end = iterable.end();
for ( ; it != end; ++it) {
qDebug() << *it; // The current value
qDebug() << it.key();
diff --git a/src/corelib/doc/src/jni.qdoc b/src/corelib/doc/src/jni.qdoc
index d05dd44ff60..72b29506c34 100644
--- a/src/corelib/doc/src/jni.qdoc
+++ b/src/corelib/doc/src/jni.qdoc
@@ -65,10 +65,10 @@
\endcode
The C++ classes \c{QtJniTypes::File} and \c{QtJniTypes::FileWriter} are
- then QJniObject-like types that can be used to instantiate the
- corresponding Java class, to call methods, and to pass such instances
- through QJniObject variadic template methods with automatic, compile-time
- signature deduction.
+ then QJniObject-like types (specializations of QtJniTypes::JObject, to be
+ precise) that can be used to instantiate the corresponding Java class, to
+ call methods, and to pass such instances through QJniObject variadic
+ template methods with automatic, compile-time signature deduction.
\code
using namespace QtJniTypes;
@@ -89,7 +89,7 @@
});
\endcode
- \sa Q_DECLARE_JNI_NATIVE_METHOD, Q_JNI_NATIVE_METHOD
+ \sa Q_DECLARE_JNI_NATIVE_METHOD, Q_JNI_NATIVE_METHOD, QtJniTypes::JObject
*/
/*!
diff --git a/src/corelib/itemmodels/qrangemodel_impl.h b/src/corelib/itemmodels/qrangemodel_impl.h
index 96dacda0260..a18ba7d0984 100644
--- a/src/corelib/itemmodels/qrangemodel_impl.h
+++ b/src/corelib/itemmodels/qrangemodel_impl.h
@@ -1656,6 +1656,13 @@ public:
return this->itemModel().QAbstractItemModel::roleNames();
}
+ template <typename Fn, std::size_t ...Is>
+ static bool forEachTupleElement(const row_type &row, Fn &&fn, std::index_sequence<Is...>)
+ {
+ using std::get;
+ return (std::forward<Fn>(fn)(QRangeModelDetails::pointerTo(get<Is>(row))) && ...);
+ }
+
template <typename Fn>
bool forEachColumn(const row_type &row, int rowIndex, const QModelIndex &parent, Fn &&fn) const
{
@@ -1664,17 +1671,16 @@ public:
const auto &model = this->itemModel();
if constexpr (one_dimensional_range) {
return fn(model.index(rowIndex, 0, parent), pointerTo(row));
- } else if constexpr (dynamicColumns()) {
+ } else if constexpr (dynamicColumns() || QRangeModelDetails::array_like_v<row_type>) {
int columnIndex = -1;
return std::all_of(begin(row), end(row), [&](const auto &item) {
return fn(model.index(rowIndex, ++columnIndex, parent), pointerTo(item));
});
- } else { // tuple-like
- int columnIndex = -1;
- return std::apply([fn = std::forward<Fn>(fn), &model, rowIndex, &columnIndex, parent]
- (const auto &...item) {
- return (fn(model.index(rowIndex, ++columnIndex, parent), pointerTo(item)) && ...);
- }, row);
+ } else { // tuple-like (but not necessarily std::tuple, so can't use std::apply)
+ int column = -1;
+ return forEachTupleElement(row, [&column, &fn, &model, &rowIndex, &parent](QObject *item){
+ return std::forward<Fn>(fn)(model.index(rowIndex, ++column, parent), item);
+ }, std::make_index_sequence<static_column_count>());
}
}
@@ -2635,7 +2641,7 @@ protected:
return false;
Q_ASSERT(QRangeModelDetails::isValid(row));
const auto &children = this->protocol().childRows(QRangeModelDetails::refTo(row));
- if (!autoConnectPropertiesRange(children,
+ if (!autoConnectPropertiesRange(QRangeModelDetails::refTo(children),
this->itemModel().index(rowIndex, 0, parent))) {
return false;
}
diff --git a/src/corelib/kernel/qassociativeiterable.cpp b/src/corelib/kernel/qassociativeiterable.cpp
index 8e3072169dd..7c85ce2c10a 100644
--- a/src/corelib/kernel/qassociativeiterable.cpp
+++ b/src/corelib/kernel/qassociativeiterable.cpp
@@ -7,6 +7,10 @@
QT_BEGIN_NAMESPACE
+#if QT_DEPRECATED_SINCE(6, 13)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+
/*!
\class QAssociativeIterator
\internal
@@ -103,6 +107,7 @@ QVariantConstPointer QAssociativeConstIterator::operator->() const
/*!
\class QAssociativeIterable
+ \deprecated [6.13] Use QMetaAssociation::Iterable instead.
\since 5.2
\inmodule QtCore
\brief The QAssociativeIterable class is an iterable interface for an associative container in a QVariant.
@@ -111,8 +116,6 @@ QVariantConstPointer QAssociativeConstIterator::operator->() const
a QVariant. An instance of QAssociativeIterable can be extracted from a QVariant if it can
be converted to a QVariantHash or QVariantMap or if a custom mutable view has been registered.
- \snippet code/src_corelib_kernel_qvariant.cpp 10
-
The container itself is not copied before iterating over it.
\sa QVariant
@@ -270,20 +273,20 @@ void QAssociativeIterable::setValue(const QVariant &key, const QVariant &mapped)
/*!
\typealias QAssociativeIterable::const_iterator
+ \deprecated [6.13] Use QMetaAssociation::Iterable::ConstIterator instead.
\inmodule QtCore
\brief The QAssociativeIterable::const_iterator allows iteration over a container in a QVariant.
A QAssociativeIterable::const_iterator can only be created by a QAssociativeIterable instance,
and can be used in a way similar to other stl-style iterators.
- \snippet code/src_corelib_kernel_qvariant.cpp 10
-
\sa QAssociativeIterable
*/
/*!
\typealias QAssociativeIterable::iterator
\since 6.0
+ \deprecated [6.13] Use QMetaAssociation::Iterable::Iterator instead.
\inmodule QtCore
\brief The QAssociativeIterable::iterator allows iteration over a container in a QVariant.
@@ -293,4 +296,7 @@ void QAssociativeIterable::setValue(const QVariant &key, const QVariant &mapped)
\sa QAssociativeIterable
*/
+QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 13)
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qassociativeiterable.h b/src/corelib/kernel/qassociativeiterable.h
index f3963d350ea..02038133fa5 100644
--- a/src/corelib/kernel/qassociativeiterable.h
+++ b/src/corelib/kernel/qassociativeiterable.h
@@ -9,7 +9,13 @@
QT_BEGIN_NAMESPACE
-class Q_CORE_EXPORT QAssociativeIterator : public QIterator<QMetaAssociation>
+#if QT_DEPRECATED_SINCE(6, 13)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+
+class
+QT_DEPRECATED_VERSION_X_6_13("Use QMetaAssociation::Iterable::Iterator instead.")
+QAssociativeIterator : public QIterator<QMetaAssociation>
{
public:
using key_type = QVariant;
@@ -21,14 +27,16 @@ public:
: QIterator(std::move(it))
{}
- QVariant key() const;
- QVariantRef<QAssociativeIterator> value() const;
+ Q_CORE_EXPORT QVariant key() const;
+ Q_CORE_EXPORT QVariantRef<QAssociativeIterator> value() const;
- QVariantRef<QAssociativeIterator> operator*() const;
- QVariantPointer<QAssociativeIterator> operator->() const;
+ Q_CORE_EXPORT QVariantRef<QAssociativeIterator> operator*() const;
+ Q_CORE_EXPORT QVariantPointer<QAssociativeIterator> operator->() const;
};
-class Q_CORE_EXPORT QAssociativeConstIterator : public QConstIterator<QMetaAssociation>
+class
+QT_DEPRECATED_VERSION_X_6_13("Use QMetaAssociation::Iterable::ConstIterator instead.")
+QAssociativeConstIterator : public QConstIterator<QMetaAssociation>
{
public:
using key_type = QVariant;
@@ -40,14 +48,16 @@ public:
: QConstIterator(std::move(it))
{}
- QVariant key() const;
- QVariant value() const;
+ Q_CORE_EXPORT QVariant key() const;
+ Q_CORE_EXPORT QVariant value() const;
- QVariant operator*() const;
- QVariantConstPointer operator->() const;
+ Q_CORE_EXPORT QVariant operator*() const;
+ Q_CORE_EXPORT QVariantConstPointer operator->() const;
};
-class Q_CORE_EXPORT QAssociativeIterable : public QIterable<QMetaAssociation>
+class
+QT_DEPRECATED_VERSION_X_6_13("Use QMetaAssociation::Iterable instead.")
+QAssociativeIterable : public QIterable<QMetaAssociation>
{
public:
using iterator = QTaggedIterator<QAssociativeIterator, void>;
@@ -86,14 +96,12 @@ public:
{
}
- // ### Qt7: Pass QMetaType as value rather than const ref.
QAssociativeIterable(const QMetaAssociation &metaAssociation, const QMetaType &metaType,
void *iterable)
: QIterable(metaAssociation, metaType.alignOf(), iterable)
{
}
- // ### Qt7: Pass QMetaType as value rather than const ref.
QAssociativeIterable(const QMetaAssociation &metaAssociation, const QMetaType &metaType,
const void *iterable)
: QIterable(metaAssociation, metaType.alignOf(), iterable)
@@ -117,16 +125,16 @@ public:
iterator mutableBegin() { return iterator(QIterable::mutableBegin()); }
iterator mutableEnd() { return iterator(QIterable::mutableEnd()); }
- const_iterator find(const QVariant &key) const;
+ Q_CORE_EXPORT const_iterator find(const QVariant &key) const;
const_iterator constFind(const QVariant &key) const { return find(key); }
- iterator mutableFind(const QVariant &key);
+ Q_CORE_EXPORT iterator mutableFind(const QVariant &key);
- bool containsKey(const QVariant &key);
- void insertKey(const QVariant &key);
- void removeKey(const QVariant &key);
+ Q_CORE_EXPORT bool containsKey(const QVariant &key);
+ Q_CORE_EXPORT void insertKey(const QVariant &key);
+ Q_CORE_EXPORT void removeKey(const QVariant &key);
- QVariant value(const QVariant &key) const;
- void setValue(const QVariant &key, const QVariant &mapped);
+ Q_CORE_EXPORT QVariant value(const QVariant &key) const;
+ Q_CORE_EXPORT void setValue(const QVariant &key, const QVariant &mapped);
};
template<>
@@ -168,6 +176,9 @@ Q_DECLARE_TYPEINFO(QAssociativeIterable, Q_RELOCATABLE_TYPE);
Q_DECLARE_TYPEINFO(QAssociativeIterable::iterator, Q_RELOCATABLE_TYPE);
Q_DECLARE_TYPEINFO(QAssociativeIterable::const_iterator, Q_RELOCATABLE_TYPE);
+QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 13)
+
QT_END_NAMESPACE
#endif // QASSOCIATIVEITERABLE_H
diff --git a/src/corelib/kernel/qiterable.cpp b/src/corelib/kernel/qiterable.cpp
index 976aafd13e5..ca2893e1090 100644
--- a/src/corelib/kernel/qiterable.cpp
+++ b/src/corelib/kernel/qiterable.cpp
@@ -2,9 +2,12 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qiterable.h>
+#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
+Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg);
+
/*!
\class QBaseIterator
\inmodule QtCore
@@ -119,7 +122,7 @@ QT_BEGIN_NAMESPACE
A QIterator can only be created by a QIterable instance, and can be used
in a way similar to other stl-style iterators. Generally, QIterator should
not be used directly, but through its derived classes provided by
- QSequentialIterable and QAssociativeIterable.
+ QMetaSequence::Iterable and QMetaAssociation::Iterable.
\sa QIterable
*/
@@ -155,7 +158,7 @@ QT_BEGIN_NAMESPACE
next item in the container and returns an iterator to the new current
item.
- Calling this function on QSequentialIterable::constEnd() leads to undefined results.
+ Calling this function on QMetaSequence::Iterable::constEnd() leads to undefined results.
\sa operator--()
*/
@@ -176,7 +179,7 @@ QT_BEGIN_NAMESPACE
The prefix \c{--} operator (\c{--it}) makes the preceding item
current and returns an iterator to the new current item.
- Calling this function on QSequentialIterable::constBegin() leads to undefined results.
+ Calling this function on QMetaSequence::Iterable::constBegin() leads to undefined results.
If the container in the QVariant does not support bi-directional iteration, calling this function
leads to undefined results.
@@ -389,7 +392,7 @@ QT_BEGIN_NAMESPACE
\class QIterable
\inmodule QtCore
\since 6.0
- \brief QIterable is a template class that is the base class for QSequentialIterable and QAssociativeIterable.
+ \brief QIterable is a template class that is the base class for QMetaSequence::Iterable and QMetaAssociation::Iterable.
*/
/*!
@@ -454,7 +457,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn template<class Container> QIterator<Container> QIterable<Container>::mutableEnd()
- Returns a QSequentialIterable::iterator for the end of the container. This
+ Returns a QMetaSequence::Iterable::iterator for the end of the container. This
can be used in stl-style iteration.
\sa mutableBegin(), constEnd()
@@ -464,6 +467,17 @@ QT_BEGIN_NAMESPACE
\fn template<class Container> qsizetype QIterable<Container>::size() const
Returns the number of values in the container.
+
+ \note If the underlying container does not provide a native way to query
+ the size, this method will synthesize the access using iterators.
+ This behavior is deprecated and will be removed in a future version
+ of Qt.
+*/
+
+/*!
+ \fn template<class Container> void QIterable<Container>::clear()
+
+ Clears the container.
*/
/*!
@@ -473,7 +487,7 @@ QT_BEGIN_NAMESPACE
\brief QTaggedIterator is a template class that wraps an iterator and exposes standard iterator traits.
In order to use an iterator any of the standard algorithms, its iterator
- traits need to be known. As QSequentialIterable can work with many different
+ traits need to be known. As QMetaSequence::Iterable can work with many different
kinds of containers, we cannot declare the traits in the iterator classes
themselves. A QTaggedIterator gives you a way to explicitly declare a trait for
a concrete instance of an iterator or QConstIterator.
@@ -512,7 +526,7 @@ QT_BEGIN_NAMESPACE
next item in the container and returns an iterator to the new current
item.
- Calling this function on QSequentialIterable::constEnd() leads to undefined results.
+ Calling this function on QMetaSequence::Iterable::constEnd() leads to undefined results.
\sa operator--()
*/
@@ -533,7 +547,7 @@ QT_BEGIN_NAMESPACE
The prefix \c{--} operator (\c{--it}) makes the preceding item
current and returns an iterator to the new current item.
- Calling this function on QSequentialIterable::constBegin() leads to undefined results.
+ Calling this function on QMetaSequence::Iterable::constBegin() leads to undefined results.
If the container in the QVariant does not support bi-directional iteration, calling this function
leads to undefined results.
@@ -609,4 +623,12 @@ QT_BEGIN_NAMESPACE
\sa operator+(), operator-=(), QIterable::canReverseIterate()
*/
+/*!
+ \internal
+ */
+void QtPrivate::warnSynthesizedAccess(const char *text)
+{
+ qCWarning(lcSynthesizedIterableAccess, "%s", text);
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qiterable.h b/src/corelib/kernel/qiterable.h
index 5e25dd1c0a5..baab2897967 100644
--- a/src/corelib/kernel/qiterable.h
+++ b/src/corelib/kernel/qiterable.h
@@ -64,6 +64,8 @@ namespace QtPrivate {
return m_pointer.tag() == Mutable ? reinterpret_cast<Type *>(m_pointer.data()) : nullptr;
}
};
+
+ Q_CORE_EXPORT void warnSynthesizedAccess(const char *text);
}
template<class Iterator, typename IteratorCategory>
@@ -499,6 +501,11 @@ public:
const void *container = constIterable();
if (m_metaContainer.hasSize())
return m_metaContainer.size(container);
+
+ // ### Qt7: Return -1 here. We shouldn't second-guess the underlying container
+ QtPrivate::warnSynthesizedAccess(
+ "size() called on an iterable without native size accessor. This is slow");
+
if (!m_metaContainer.hasConstIterator())
return -1;
@@ -510,6 +517,11 @@ public:
return size;
}
+ void clear()
+ {
+ m_metaContainer.clear(mutableIterable());
+ }
+
Container metaContainer() const
{
return m_metaContainer;
diff --git a/src/corelib/kernel/qjniobject.cpp b/src/corelib/kernel/qjniobject.cpp
index 59117bd01d4..abef9fdd663 100644
--- a/src/corelib/kernel/qjniobject.cpp
+++ b/src/corelib/kernel/qjniobject.cpp
@@ -1527,4 +1527,179 @@ jobject QJniObject::javaObject() const
return d->m_jobject;
}
+/*!
+ \class QtJniTypes::JObjectBase
+ \brief The JObjectBase in the QtJniTypes namespace is the base of all declared Java types.
+ \inmodule QtCore
+ \internal
+*/
+
+/*!
+ \class QtJniTypes::JObject
+ \inmodule QtCore
+ \brief The JObject template in the QtJniTypes namespace is the base of declared Java types.
+ \since Qt 6.8
+
+ This template gets specialized when using the Q_DECLARE_JNI_CLASS macro. The
+ specialization produces a unique type in the QtJniTypes namespace. This
+ allows the type system to deduce the correct signature in JNI calls when an
+ instance of the specialized type is passed as a parameter.
+
+ Instances can be implicitly converted to and from QJniObject and jobject,
+ and provide the same template API as QJniObject to call methods and access
+ properties. Since instances of JObject know about the Java type they hold,
+ APIs to access static methods or fields do not require the class name as an
+ explicit parameter.
+
+ \sa Q_DECLARE_JNI_CLASS
+*/
+
+/*!
+ \fn template <typename Type> QtJniTypes::JObject<Type>::JObject()
+
+ Default-constructs the JObject instance. This also default-constructs an
+ instance of the represented Java type.
+*/
+
+/*!
+ \fn template <typename Type> QtJniTypes::JObject<Type>::JObject(const QJniObject &other)
+
+ Constructs a JObject instance that holds a reference to the same jobject as \a other.
+*/
+
+/*!
+ \fn template <typename Type> QtJniTypes::JObject<Type>::JObject(jobject other)
+
+ Constructs a JObject instance that holds a reference to \a other.
+*/
+
+/*!
+ \fn template <typename Type> QtJniTypes::JObject<Type>::JObject(QJniObject &&other)
+
+ Move-constructs a JObject instance from \a other.
+*/
+
+/*!
+ \fn template <typename Type> bool QtJniTypes::JObject<Type>::isValid() const
+
+ Returns whether the JObject instance holds a valid reference to a jobject.
+
+ \sa QJniObject::isValid()
+*/
+
+/*!
+ \fn template <typename Type> jclass QtJniTypes::JObject<Type>::objectClass() const
+
+ Returns the Java class that this JObject is an instance of as a jclass.
+
+ \sa className(), QJniObject::objectClass()
+*/
+
+/*!
+ \fn template <typename Type> QString QtJniTypes::JObject<Type>::toString() const
+
+ Returns a QString with a string representation of the Java object.
+
+ \sa QJniObject::toString()
+*/
+
+/*!
+ \fn template <typename Type> QByteArray QtJniTypes::JObject<Type>::className() const
+
+ Returns the name of the Java class that this object is an instance of.
+
+ \sa objectClass(), QJniObject::className()
+*/
+
+/*!
+ \fn template <typename Type> bool QtJniTypes::JObject<Type>::isClassAvailable()
+
+ Returns whether the class that this JObject specialization represents is
+ available.
+
+ \sa QJniObject::isClassAvailable()
+*/
+
+/*!
+ \fn template <typename Type> JObject QtJniTypes::JObject<Type>::fromJObject(jobject object)
+
+ Constructs a JObject instance from \a object and returns that instance.
+*/
+
+/*!
+ \fn template <typename Type> template <typename ...Args> JObject QtJniTypes::JObject<Type>::construct(Args &&...args)
+
+ Constructs a Java object from \a args and returns a JObject instance that
+ holds a reference to that Java object.
+*/
+
+/*!
+ \fn template <typename Type> JObject QtJniTypes::JObject<Type>::fromLocalRef(jobject ref)
+
+ Constructs a JObject that holds a local reference to \a ref, and returns
+ that object.
+*/
+
+/*!
+ \fn template <typename Type> template <typename Ret, typename ...Args> auto QtJniTypes::JObject<Type>::callStaticMethod(const char *methodName, Args &&...args)
+
+ Calls the static method \a methodName with arguments \a args, and returns
+ the result of type \c Ret (unless \c Ret is \c void). If \c Ret is a
+ jobject type, then the returned value will be a QJniObject.
+
+ \sa QJniObject::callStaticMethod()
+*/
+
+/*!
+ \fn template <typename Type> bool QtJniTypes::JObject<Type>::registerNativeMethods(std::initializer_list<JNINativeMethod> methods)
+
+ Registers the Java methods in \a methods with the Java class represented by
+ the JObject specialization, and returns whether the registration was successful.
+
+ \sa QJniEnvironment::registerNativeMethods()
+*/
+
+/*!
+ \fn template <typename Type> template <typename T> auto QtJniTypes::JObject<Type>::getStaticField(const char *field)
+
+ Returns the value of the static field \a field.
+
+ \sa QJniObject::getStaticField()
+*/
+
+/*!
+ \fn template <typename Type> template <typename Ret, typename T> auto QtJniTypes::JObject<Type>::setStaticField(const char *field, T &&value)
+
+ Sets the static field \a field to \a value.
+
+ \sa QJniObject::setStaticField()
+*/
+
+/*!
+ \fn template <typename Type> template <typename Ret, typename ...Args> auto QtJniTypes::JObject<Type>::callMethod(const char *method, Args &&...args) const
+
+ Calls the instance method \a method with arguments \a args, and returns
+ the result of type \c Ret (unless \c Ret is \c void). If \c Ret is a
+ jobject type, then the returned value will be a QJniObject.
+
+ \sa QJniObject::callMethod()
+*/
+
+/*!
+ \fn template <typename Type> template <typename T> auto QtJniTypes::JObject<Type>::getField(const char *field) const
+
+ Returns the value of the instance field \a field.
+
+ \sa QJniObject::getField()
+*/
+
+/*!
+ \fn template <typename Type> template <typename Ret, typename T> auto QtJniTypes::JObject<Type>::setField(const char *field, T &&value)
+
+ Sets the value of the instance field \a field to \a value.
+
+ \sa QJniObject::setField()
+*/
+
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h
index 06dfc328b4b..c38bf60e051 100644
--- a/src/corelib/kernel/qjniobject.h
+++ b/src/corelib/kernel/qjniobject.h
@@ -812,7 +812,7 @@ inline bool operator!=(const QJniObject &obj1, const QJniObject &obj2)
}
namespace QtJniTypes {
-struct QT_TECH_PREVIEW_API JObjectBase
+struct JObjectBase
{
operator QJniObject() const { return m_object; }
@@ -841,7 +841,7 @@ protected:
};
template<typename Type>
-class QT_TECH_PREVIEW_API JObject : public JObjectBase
+class JObject : public JObjectBase
{
public:
using Class = Type;
@@ -885,6 +885,13 @@ public:
return JObject(QJniObject::fromLocalRef(lref));
}
+#ifdef Q_QDOC // from JObjectBase, which we don't document
+ bool isValid() const;
+ jclass objectClass() const;
+ QString toString() const;
+ template <typename T = jobject> object() const;
+#endif
+
static bool registerNativeMethods(std::initializer_list<JNINativeMethod> methods)
{
QJniEnvironment env;
diff --git a/src/corelib/kernel/qjnitypes.h b/src/corelib/kernel/qjnitypes.h
index 935388311a5..8ee367d188f 100644
--- a/src/corelib/kernel/qjnitypes.h
+++ b/src/corelib/kernel/qjnitypes.h
@@ -19,12 +19,11 @@
QT_BEGIN_NAMESPACE
-// QT_TECH_PREVIEW_API
#define Q_DECLARE_JNI_TYPE_HELPER(Type) \
struct Type##Tag { explicit Type##Tag() = default; }; \
using Type = JObject<Type##Tag>; \
-// QT_TECH_PREVIEW_API
+// internal - Q_DECLARE_JNI_CLASS is the public macro
#define Q_DECLARE_JNI_TYPE(Type, Signature) \
namespace QtJniTypes { \
Q_DECLARE_JNI_TYPE_HELPER(Type) \
diff --git a/src/corelib/kernel/qmetaassociation.cpp b/src/corelib/kernel/qmetaassociation.cpp
index dc239424e6d..5eae6658a57 100644
--- a/src/corelib/kernel/qmetaassociation.cpp
+++ b/src/corelib/kernel/qmetaassociation.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qmetacontainer.h>
+#include <QtCore/qmetaassociation.h>
#include <QtCore/qmetatype.h>
QT_BEGIN_NAMESPACE
@@ -287,7 +287,6 @@ QMetaType QMetaAssociation::mappedMetaType() const
Returns \c true if the QMetaAssociation \a lhs represents the same container type
as the QMetaAssociation \a rhs, otherwise returns \c false.
*/
-
/*!
\fn bool QMetaAssociation::operator!=(const QMetaAssociation &lhs, const QMetaAssociation &rhs)
@@ -295,5 +294,197 @@ QMetaType QMetaAssociation::mappedMetaType() const
type than the QMetaAssociation \a rhs, otherwise returns \c false.
*/
+/*!
+ \class QMetaAssociation::Iterable
+ \inherits QIterable
+ \since 6.11
+ \inmodule QtCore
+ \brief QMetaAssociation::Iterable is an iterable interface for an associative container in a QVariant.
+
+ This class allows several methods of accessing the elements of an
+ associative container held within a QVariant. An instance of
+ QMetaAssociation::Iterable can be extracted from a QVariant if it can be
+ converted to a QVariantHash or QVariantMap or if a custom mutable view has
+ been registered.
+
+ \snippet code/src_corelib_kernel_qvariant.cpp 10
+
+ The container itself is not copied before iterating over it.
+
+ \sa QVariant
+*/
+
+/*!
+ \typealias QMetaAssociation::Iterable::RandomAccessIterator
+ Exposes an iterator using std::random_access_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaAssociation::Iterable::BidirectionalIterator
+ Exposes an iterator using std::bidirectional_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaAssociation::Iterable::ForwardIterator
+ Exposes an iterator using std::forward_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaAssociation::Iterable::InputIterator
+ Exposes an iterator using std::input_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaAssociation::Iterable::RandomAccessConstIterator
+ Exposes a const_iterator using std::random_access_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaAssociation::Iterable::BidirectionalConstIterator
+ Exposes a const_iterator using std::bidirectional_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaAssociation::Iterable::ForwardConstIterator
+ Exposes a const_iterator using std::forward_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaAssociation::Iterable::InputConstIterator
+ Exposes a const_iterator using std::input_iterator_tag.
+*/
+
+/*!
+ \class QMetaAssociation::Iterable::ConstIterator
+ \inherits QConstIterator
+ \since 6.11
+ \inmodule QtCore
+ \brief QMetaAssociation::Iterable::ConstIterator allows iteration over a container in a QVariant.
+
+ A QMetaAssociation::Iterable::ConstIterator can only be created by a
+ QMetaAssociation::Iterable instance, and can be used in a way similar to
+ other stl-style iterators.
+
+ \snippet code/src_corelib_kernel_qvariant.cpp 10
+
+ \sa QMetaAssociation::Iterable
+*/
+
+/*!
+ \class QMetaAssociation::Iterable::Iterator
+ \inherits QIterator
+ \since 6.11
+ \inmodule QtCore
+ \brief The QMetaAssociation::Iterable::Iterator allows iteration over a container in a QVariant.
+
+ A QMetaAssociation::Iterable::Iterator can only be created by a
+ QMetaAssociation::Iterable instance, and can be used in a way similar to
+ other stl-style iterators.
+
+ \sa QMetaAssociation::Iterable
+*/
+
+/*!
+ \fn QMetaAssociation::Iterable::ConstIterator QMetaAssociation::Iterable::find(const QVariant &key) const
+ Retrieves a ConstIterator pointing to the element at the given \a key, or
+ the end of the container if that key does not exist. If the \a key isn't
+ convertible to the expected type, the end of the container is returned.
+ */
+
+/*!
+ \fn QMetaAssociation::Iterable::Iterator QMetaAssociation::Iterable::mutableFind(const QVariant &key)
+ Retrieves an iterator pointing to the element at the given \a key, or
+ the end of the container if that key does not exist. If the \a key isn't
+ convertible to the expected type, the end of the container is returned.
+ */
+
+/*!
+ \fn bool QMetaAssociation::Iterable::containsKey(const QVariant &key) const
+ Returns \c true if the container has an entry with the given \a key, or
+ \c false otherwise. If the \a key isn't convertible to the expected type,
+ \c false is returned.
+ */
+
+/*!
+ \fn void QMetaAssociation::Iterable::insertKey(const QVariant &key)
+ Inserts a new entry with the given \a key, or resets the mapped value of
+ any existing entry with the given \a key to the default constructed
+ mapped value. The \a key is coerced to the expected type: If it isn't
+ convertible, a default value is inserted.
+ */
+
+/*!
+ \fn void QMetaAssociation::Iterable::removeKey(const QVariant &key)
+ Removes the entry with the given \a key from the container. The \a key is
+ coerced to the expected type: If it isn't convertible, the default value
+ is removed.
+ */
+
+/*!
+ \fn QVariant QMetaAssociation::Iterable::value(const QVariant &key) const
+ Retrieves the mapped value at the given \a key, or a QVariant of a
+ default-constructed instance of the mapped type, if the key does not
+ exist. If the \a key is not convertible to the key type, the mapped value
+ associated with the default-constructed key is returned.
+ */
+
+/*!
+ \fn void QMetaAssociation::Iterable::setValue(const QVariant &key, const QVariant &mapped)
+ Sets the mapped value associated with \a key to \a mapped, if possible.
+ Inserts a new entry if none exists yet, for the given \a key. If the
+ \a key is not convertible to the key type, the value for the
+ default-constructed key type is overwritten.
+ */
+
+
+/*!
+ \fn QVariant QMetaAssociation::Iterable::Iterator::key() const
+ Returns the key this iterator points to.
+*/
+
+/*!
+ \fn QVariant::Reference<QMetaAssociation::Iterable::Iterator> QMetaAssociation::Iterable::Iterator::value() const
+ Returns the mapped value this iterator points to. If the container does not
+ provide a mapped value (for example a set), returns an invalid
+ QVariant::Reference.
+*/
+
+/*!
+ \fn QVariant::Reference<QMetaAssociation::Iterable::Iterator> QMetaAssociation::Iterable::Iterator::operator*() const
+ Returns the current item, converted to a QVariant::Reference. The resulting
+ QVariant::Reference resolves to the mapped value if there is one, or to the
+ key value if not.
+*/
+
+/*!
+ \fn QVariant::Pointer<QMetaAssociation::Iterable::Iterator> QMetaAssociation::Iterable::Iterator::operator->() const
+ Returns the current item, converted to a QVariant::Pointer. The resulting
+ QVariant::Pointer resolves to the mapped value if there is one, or to the
+ key value if not.
+*/
+
+/*!
+ \fn QVariant QMetaAssociation::Iterable::ConstIterator::key() const
+ Returns the key this iterator points to.
+*/
+
+/*!
+ \fn QVariant QMetaAssociation::Iterable::ConstIterator::value() const
+ Returns the mapped value this iterator points to, or an invalid QVariant if
+ there is no mapped value.
+*/
+
+/*!
+ \fn QVariant QMetaAssociation::Iterable::ConstIterator::operator*() const
+ Returns the current item, converted to a QVariant. The returned value is the
+ mapped value at the current iterator if there is one, or otherwise the key.
+*/
+
+/*!
+ \fn QVariant::ConstPointer<QMetaAssociation::Iterable::ConstIterator> QMetaAssociation::Iterable::ConstIterator::operator->() const
+ Returns the current item, converted to a QVariant::ConstPointer. The
+ QVariant::ConstPointer will resolve to the mapped value at the current
+ iterator if there is one, or otherwise the key.
+*/
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qmetaassociation.h b/src/corelib/kernel/qmetaassociation.h
new file mode 100644
index 00000000000..6d8de13e90a
--- /dev/null
+++ b/src/corelib/kernel/qmetaassociation.h
@@ -0,0 +1,266 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QMETAASSOCIATION_H
+#define QMETAASSOCIATION_H
+
+#if 0
+#pragma qt_class(QMetaAssociation)
+#endif
+
+#include <QtCore/qiterable.h>
+#include <QtCore/qiterable_impl.h>
+#include <QtCore/qmetacontainer.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtMetaContainerPrivate {
+
+class AssociativeIterator : public QIterator<QMetaAssociation>
+{
+public:
+ using key_type = QVariant;
+ using mapped_type = QVariant;
+ using reference = QVariant::Reference<AssociativeIterator>;
+ using pointer = QVariant::Pointer<AssociativeIterator>;
+
+ static constexpr bool canNoexceptAssignQVariant = false;
+ static constexpr bool canNoexceptConvertToQVariant = false;
+
+ AssociativeIterator(QIterator &&it) : QIterator(std::move(it)) {}
+
+ key_type key() const
+ {
+ const QMetaAssociation meta = metaContainer();
+ return QIterablePrivate::retrieveElement(meta.keyMetaType(), [&](void *dataPtr) {
+ meta.keyAtIterator(constIterator(), dataPtr);
+ });
+ }
+ reference value() const { return operator*(); }
+
+ reference operator*() const { return reference(*this); }
+ pointer operator->() const { return pointer(*this); }
+};
+
+class AssociativeConstIterator : public QConstIterator<QMetaAssociation>
+{
+public:
+ using key_type = QVariant;
+ using mapped_type = QVariant;
+ using reference = QVariant::ConstReference<AssociativeConstIterator>;
+ using pointer = QVariant::ConstPointer<AssociativeConstIterator>;
+
+ static constexpr bool canNoexceptConvertToQVariant = false;
+
+ AssociativeConstIterator(QConstIterator &&it) : QConstIterator(std::move(it)) {}
+
+ key_type key() const
+ {
+ const QMetaAssociation meta = metaContainer();
+ return QIterablePrivate::retrieveElement(meta.keyMetaType(), [&](void *dataPtr) {
+ meta.keyAtConstIterator(constIterator(), dataPtr);
+ });
+ }
+
+ mapped_type value() const { return operator*(); }
+
+ mapped_type operator*() const;
+ pointer operator->() const { return pointer(*this); }
+};
+
+} // namespace QtMetaContainerPrivate
+
+namespace QtPrivate {
+
+template<typename Referred>
+QVariant associativeIteratorToVariant(const Referred &referred)
+{
+ const auto metaAssociation = referred.metaContainer();
+ const QMetaType metaType(metaAssociation.mappedMetaType());
+ if (metaType.isValid(QT6_CALL_NEW_OVERLOAD)) {
+ return QIterablePrivate::retrieveElement(metaType, [&](void *dataPtr) {
+ metaAssociation.mappedAtConstIterator(referred.constIterator(), dataPtr);
+ });
+ }
+
+ return QIterablePrivate::retrieveElement(metaType, [&](void *dataPtr) {
+ metaAssociation.keyAtConstIterator(referred.constIterator(), dataPtr);
+ });
+}
+
+} // namespace QtPrivate
+
+template<>
+inline QVariant::Reference<QtMetaContainerPrivate::AssociativeIterator>::operator QVariant() const
+{
+ return QtPrivate::associativeIteratorToVariant(m_referred);
+}
+
+template<>
+inline QVariant::Reference<QtMetaContainerPrivate::AssociativeIterator> &
+QVariant::Reference<QtMetaContainerPrivate::AssociativeIterator>::operator=(const QVariant &value)
+{
+ const auto metaAssociation = m_referred.metaContainer();
+ const QMetaType metaType(metaAssociation.mappedMetaType());
+ if (!metaType.isValid(QT6_CALL_NEW_OVERLOAD))
+ return *this;
+
+ QtPrivate::QVariantTypeCoercer coercer;
+ metaAssociation.setMappedAtIterator(
+ m_referred.constIterator(), coercer.coerce(value, metaType));
+ return *this;
+}
+
+template<>
+inline QVariant::ConstReference<QtMetaContainerPrivate::AssociativeConstIterator>::operator QVariant() const
+{
+ return QtPrivate::associativeIteratorToVariant(m_referred);
+}
+
+namespace QtMetaContainerPrivate {
+inline AssociativeConstIterator::mapped_type AssociativeConstIterator::operator*() const
+{
+ return reference(*this);
+}
+
+class Association : public QIterable<QMetaAssociation>
+{
+public:
+ using Iterator
+ = QTaggedIterator<AssociativeIterator, void>;
+ using RandomAccessIterator
+ = QTaggedIterator<AssociativeIterator, std::random_access_iterator_tag>;
+ using BidirectionalIterator
+ = QTaggedIterator<AssociativeIterator, std::bidirectional_iterator_tag>;
+ using ForwardIterator
+ = QTaggedIterator<AssociativeIterator, std::forward_iterator_tag>;
+ using InputIterator
+ = QTaggedIterator<AssociativeIterator, std::input_iterator_tag>;
+
+ using ConstIterator
+ = QTaggedIterator<AssociativeConstIterator, void>;
+ using RandomAccessConstIterator
+ = QTaggedIterator<AssociativeConstIterator, std::random_access_iterator_tag>;
+ using BidirectionalConstIterator
+ = QTaggedIterator<AssociativeConstIterator, std::bidirectional_iterator_tag>;
+ using ForwardConstIterator
+ = QTaggedIterator<AssociativeConstIterator, std::forward_iterator_tag>;
+ using InputConstIterator
+ = QTaggedIterator<AssociativeConstIterator, std::input_iterator_tag>;
+
+ using iterator = Iterator;
+ using const_iterator = ConstIterator;
+
+ template<class T>
+ Association(const T *p) : QIterable(QMetaAssociation::fromContainer<T>(), p) {}
+
+ template<class T>
+ Association(T *p) : QIterable(QMetaAssociation::fromContainer<T>(), p) {}
+
+ Association() : QIterable(QMetaAssociation(), nullptr) {}
+
+ template<typename Pointer>
+ Association(const QMetaAssociation &metaAssociation, Pointer iterable)
+ : QIterable(metaAssociation, iterable)
+ {
+ }
+
+ Association(const QMetaAssociation &metaAssociation, QMetaType metaType, void *iterable)
+ : QIterable(metaAssociation, metaType.alignOf(), iterable)
+ {
+ }
+
+ Association(const QMetaAssociation &metaAssociation, QMetaType metaType, const void *iterable)
+ : QIterable(metaAssociation, metaType.alignOf(), iterable)
+ {
+ }
+
+ Association(QIterable<QMetaAssociation> &&other)
+ : QIterable(std::move(other))
+ {}
+
+ Association &operator=(QIterable<QMetaAssociation> &&other)
+ {
+ QIterable::operator=(std::move(other));
+ return *this;
+ }
+
+ ConstIterator begin() const { return constBegin(); }
+ ConstIterator end() const { return constEnd(); }
+
+ ConstIterator constBegin() const { return ConstIterator(QIterable::constBegin()); }
+ ConstIterator constEnd() const { return ConstIterator(QIterable::constEnd()); }
+
+ Iterator mutableBegin() { return Iterator(QIterable::mutableBegin()); }
+ Iterator mutableEnd() { return Iterator(QIterable::mutableEnd()); }
+
+ ConstIterator find(const QVariant &key) const
+ {
+ const QMetaAssociation meta = metaContainer();
+ QtPrivate::QVariantTypeCoercer coercer;
+ if (const void *keyData = coercer.convert(key, meta.keyMetaType())) {
+ return ConstIterator(QConstIterator<QMetaAssociation>(
+ this, meta.createConstIteratorAtKey(constIterable(), keyData)));
+ }
+ return constEnd();
+ }
+
+ ConstIterator constFind(const QVariant &key) const { return find(key); }
+
+ Iterator mutableFind(const QVariant &key)
+ {
+ const QMetaAssociation meta = metaContainer();
+ QtPrivate::QVariantTypeCoercer coercer;
+ if (const void *keyData = coercer.convert(key, meta.keyMetaType()))
+ return Iterator(QIterator(this, meta.createIteratorAtKey(mutableIterable(), keyData)));
+ return mutableEnd();
+ }
+
+ bool containsKey(const QVariant &key) const
+ {
+ const QMetaAssociation meta = metaContainer();
+ QtPrivate::QVariantTypeCoercer keyCoercer;
+ if (const void *keyData = keyCoercer.convert(key, meta.keyMetaType()))
+ return meta.containsKey(constIterable(), keyData);
+ return false;
+ }
+
+ void insertKey(const QVariant &key)
+ {
+ const QMetaAssociation meta = metaContainer();
+ QtPrivate::QVariantTypeCoercer keyCoercer;
+ meta.insertKey(mutableIterable(), keyCoercer.coerce(key, meta.keyMetaType()));
+ }
+
+ void removeKey(const QVariant &key)
+ {
+ const QMetaAssociation meta = metaContainer();
+ QtPrivate::QVariantTypeCoercer keyCoercer;
+ meta.removeKey(mutableIterable(), keyCoercer.coerce(key, meta.keyMetaType()));
+ }
+
+ QVariant value(const QVariant &key) const
+ {
+ const QMetaAssociation meta = metaContainer();
+ return QIterablePrivate::retrieveElement(meta.mappedMetaType(), [&](void *dataPtr) {
+ QtPrivate::QVariantTypeCoercer coercer;
+ meta.mappedAtKey(constIterable(), coercer.coerce(key, meta.keyMetaType()), dataPtr);
+ });
+ }
+
+ void setValue(const QVariant &key, const QVariant &mapped)
+ {
+ const QMetaAssociation meta = metaContainer();
+ QtPrivate::QVariantTypeCoercer keyCoercer;
+ QtPrivate::QVariantTypeCoercer mappedCoercer;
+ meta.setMappedAtKey(mutableIterable(), keyCoercer.coerce(key, meta.keyMetaType()),
+ mappedCoercer.coerce(mapped, meta.mappedMetaType()));
+ }
+};
+
+} // namespace QtMetaContainerPrivate
+
+QT_END_NAMESPACE
+
+#endif // QMETAASSOCIATION_H
diff --git a/src/corelib/kernel/qmetacontainer.h b/src/corelib/kernel/qmetacontainer.h
index 1bed7f9f7b3..c9d3a6bf9c6 100644
--- a/src/corelib/kernel/qmetacontainer.h
+++ b/src/corelib/kernel/qmetacontainer.h
@@ -22,6 +22,11 @@ constexpr const QMetaTypeInterface *qMetaTypeInterfaceForType();
namespace QtMetaContainerPrivate {
+class Sequence;
+class SequentialIterator;
+class Association;
+class AssociativeIterator;
+
enum IteratorCapability : quint8 {
InputCapability = 1 << 0,
ForwardCapability = 1 << 1,
@@ -922,9 +927,67 @@ protected:
const QtMetaContainerPrivate::QMetaContainerInterface *d_ptr = nullptr;
};
+// ### Qt7: Move this to qmetasequence.h, including QtMetaContainerPrivate parts above.
class Q_CORE_EXPORT QMetaSequence : public QMetaContainer
{
public:
+#ifdef Q_QDOC
+ class Iterable : public QIterable<QMetaSequence>
+ {
+ public:
+ class Iterator : public QIterator<QMetaSequence>
+ {
+ public:
+ QVariant::Reference<Iterator> operator*() const;
+ QVariant::Pointer<Iterator> operator->() const;
+ QVariant::Reference<Iterator> operator[](qsizetype n) const;
+ };
+
+ class ConstIterator : public QConstIterator<QMetaSequence>
+ {
+ public:
+ QVariant operator*() const;
+ QVariant::ConstPointer<ConstIterator> operator->() const;
+ QVariant operator[](qsizetype n) const;
+ };
+
+ using RandomAccessIterator = Iterator;
+ using BidirectionalIterator = Iterator;
+ using ForwardIterator = Iterator;
+ using InputIterator = Iterator;
+
+ using RandomAccessConstIterator = ConstIterator;
+ using BidirectionalConstIterator = ConstIterator;
+ using ForwardConstIterator = ConstIterator;
+ using InputConstIterator = ConstIterator;
+
+ ConstIterator begin() const;
+ ConstIterator end() const;
+
+ ConstIterator constBegin() const;
+ ConstIterator constEnd() const;
+
+ Iterator mutableBegin();
+ Iterator mutableEnd();
+
+ QVariant at(qsizetype idx) const;
+ void set(qsizetype idx, const QVariant &value);
+ void append(const QVariant &value);
+ void prepend(const QVariant &value);
+ void removeLast();
+ void removeFirst();
+
+#if QT_DEPRECATED_SINCE(6, 11)
+ enum Position: quint8 { Unspecified, AtBegin, AtEnd };
+ void addValue(const QVariant &value, Position position = Unspecified);
+ void removeValue(Position position = Unspecified);
+ QMetaType valueMetaType() const;
+#endif // QT_DEPRECATED_SINCE(6, 11)
+ };
+#else
+ using Iterable = QtMetaContainerPrivate::Sequence;
+#endif
+
QMetaSequence() = default;
explicit QMetaSequence(const QtMetaContainerPrivate::QMetaSequenceInterface *d) : QMetaContainer(d) {}
@@ -999,9 +1062,67 @@ private:
}
};
+// ### Qt7: Move this to qmetaassociation.h, including QtMetaContainerPrivate parts above.
class Q_CORE_EXPORT QMetaAssociation : public QMetaContainer
{
public:
+#ifdef Q_QDOC
+ class Iterable : public QIterable<QMetaAssociation>
+ {
+ public:
+ class Iterator : public QIterator<QMetaAssociation>
+ {
+ public:
+ QVariant key() const;
+ QVariant value() const;
+
+ QVariant::Reference<Iterator> operator*() const;
+ QVariant::Pointer<Iterator> operator->() const;
+ };
+
+ class ConstIterator : public QConstIterator<QMetaAssociation>
+ {
+ public:
+ QVariant key() const;
+ QVariant value() const;
+
+ QVariant operator*() const;
+ QVariant::ConstPointer<ConstIterator> operator->() const;
+ };
+
+ using RandomAccessIterator = Iterator;
+ using BidirectionalIterator = Iterator;
+ using ForwardIterator = Iterator;
+ using InputIterator = Iterator;
+
+ using RandomAccessConstIterator = ConstIterator;
+ using BidirectionalConstIterator = ConstIterator;
+ using ForwardConstIterator = ConstIterator;
+ using InputConstIterator = ConstIterator;
+
+ ConstIterator begin() const;
+ ConstIterator end() const;
+
+ ConstIterator constBegin() const;
+ ConstIterator constEnd() const;
+
+ Iterator mutableBegin();
+ Iterator mutableEnd();
+
+ ConstIterator find(const QVariant &key) const;
+ ConstIterator constFind(const QVariant &key) const;
+ Iterator mutableFind(const QVariant &key);
+
+ bool containsKey(const QVariant &key) const;
+ void insertKey(const QVariant &key);
+ void removeKey(const QVariant &key);
+ QVariant value(const QVariant &key) const;
+ void setValue(const QVariant &key, const QVariant &mapped);
+ };
+#else
+ using Iterable = QtMetaContainerPrivate::Association;
+#endif
+
QMetaAssociation() = default;
explicit QMetaAssociation(const QtMetaContainerPrivate::QMetaAssociationInterface *d) : QMetaContainer(d) {}
diff --git a/src/corelib/kernel/qmetasequence.cpp b/src/corelib/kernel/qmetasequence.cpp
index 1d3f3dfd080..2a3a923d5ca 100644
--- a/src/corelib/kernel/qmetasequence.cpp
+++ b/src/corelib/kernel/qmetasequence.cpp
@@ -1,8 +1,8 @@
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qmetacontainer.h"
-#include "qmetatype.h"
+#include <QtCore/qmetasequence.h>
+#include <QtCore/qmetatype.h>
QT_BEGIN_NAMESPACE
@@ -468,4 +468,176 @@ void QMetaSequence::valueAtConstIterator(const void *iterator, void *result) con
type than the QMetaSequence \a rhs, otherwise returns \c false.
*/
+/*!
+ \class QMetaSequence::Iterable
+ \inherits QIterable
+ \since 6.11
+ \inmodule QtCore
+ \brief The QMetaSequence::Iterable class is an iterable interface for a container in a QVariant.
+
+ This class allows several methods of accessing the values of a container
+ held within a QVariant. An instance of QMetaSequence::Iterable can be
+ extracted from a QVariant if it can be converted to a QVariantList, or if
+ the container it contains is registered using
+ Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE. Most sequential containers found
+ in Qt and some found in the C++ standard library are automatically
+ registered.
+
+ \snippet code/src_corelib_kernel_qvariant.cpp 9
+
+ The container itself is not copied before iterating over it.
+
+ \sa QVariant
+*/
+
+/*!
+ \typealias QMetaSequence::Iterable::RandomAccessIterator
+ Exposes an iterator using std::random_access_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaSequence::Iterable::BidirectionalIterator
+ Exposes an iterator using std::bidirectional_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaSequence::Iterable::ForwardIterator
+ Exposes an iterator using std::forward_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaSequence::Iterable::InputIterator
+ Exposes an iterator using std::input_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaSequence::Iterable::RandomAccessConstIterator
+ Exposes a const_iterator using std::random_access_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaSequence::Iterable::BidirectionalConstIterator
+ Exposes a const_iterator using std::bidirectional_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaSequence::Iterable::ForwardConstIterator
+ Exposes a const_iterator using std::forward_iterator_tag.
+*/
+
+/*!
+ \typealias QMetaSequence::Iterable::InputConstIterator
+ Exposes a const_iterator using std::input_iterator_tag.
+*/
+
+/*!
+ \enum QMetaSequence::Iterable::Position
+ \deprecated [6.11] Use append(), prepend(), removeFirst(), or removeLast()
+
+ Specifies the position at which an element shall be added to or removed from
+ the iterable.
+
+ \value AtBegin
+ Add or remove at the beginning of the iterable.
+ \value AtEnd
+ Add or remove at the end of the iterable.
+ \value Unspecified
+ Add or remove at an unspecified position in the iterable.
+ */
+
+/*!
+ \fn void QMetaSequence::Iterable::addValue(const QVariant &value, Position position)
+ \deprecated [6.11] Use append() or prepend()
+ Adds \a value to the container, at \a position, if possible.
+ */
+
+/*!
+ \deprecated [6.11] Use removeFirst() or removeLast()
+ \fn void QMetaSequence::Iterable::removeValue(Position position)
+ Removes a value from the container, at \a position, if possible.
+ */
+
+/*!
+ \deprecated [6.11] Use QMetaSequence::valueMetaType()
+ \fn QMetaType QMetaSequence::Iterable::valueMetaType() const
+ Returns the meta type for values stored in the underlying container.
+ */
+
+/*!
+ \fn QVariant QMetaSequence::Iterable::at(qsizetype idx) const
+ Returns the value at position \a idx in the container.
+
+ \note If the underlying container does not provide a native way to retrieve
+ an element at an index, this method will synthesize the access using
+ iterators. This behavior is deprecated and will be removed in a future
+ version of Qt.
+*/
+
+/*!
+ \fn void QMetaSequence::Iterable::set(qsizetype idx, const QVariant &value)
+ Sets the element at position \a idx in the container to \a value.
+
+ \note If the underlying container does not provide a native way to assign
+ an element at an index, this method will synthesize the assignment
+ using iterators. This behavior is deprecated and will be removed in a
+ future version of Qt.
+*/
+
+/*!
+ \class QMetaSequence::Iterable::ConstIterator
+ \inmodule QtCore
+ \inherits QConstIterator
+ \since 6.11
+ \brief QMetaSequence::Iterable::ConstIterator allows iteration over a container in a QVariant.
+
+ A QMetaSequence::Iterable::ConstIterator can only be created by a
+ QMetaSequence::Iterable instance, and can be used in a way similar to other
+ stl-style iterators.
+
+ \snippet code/src_corelib_kernel_qvariant.cpp 9
+*/
+
+/*!
+ \class QMetaSequence::Iterable::Iterator
+ \inmodule QtCore
+ \inherits QIterator
+ \since 6.11
+ \brief QMetaSequence::Iterable::Iterator allows iteration over a container in a QVariant.
+
+ A QMetaSequence::Iterable::Iterator can only be created by a QMetaSequence::Iterable
+ instance, and can be used in a way similar to other stl-style iterators.
+*/
+
+/*!
+ \fn QVariant::Reference<QMetaSequence::Iterable::Iterator> QMetaSequence::Iterable::Iterator::operator*() const
+ Returns the current item, converted to a QVariant::Reference.
+*/
+
+/*!
+ \fn QVariant::Pointer<QMetaSequence::Iterable::Iterator> QMetaSequence::Iterable::Iterator::operator->() const
+ Returns the current item, converted to a QVariant::Pointer.
+*/
+
+/*!
+ \fn QVariant::Reference<QMetaSequence::Iterable::Iterator> QMetaSequence::Iterable::Iterator::operator[](qsizetype n) const
+ Returns the item offset from the current one by \a n, converted to a
+ QVariant::Reference.
+*/
+
+/*!
+ \fn QVariant QMetaSequence::Iterable::ConstIterator::operator*() const
+ Returns the current item, converted to a QVariant.
+*/
+
+/*!
+ \fn QVariant::ConstPointer<QMetaSequence::Iterable::ConstIterator> QMetaSequence::Iterable::ConstIterator::operator->() const
+ Returns the current item, converted to a QVariant::ConstPointer.
+*/
+
+/*!
+ \fn QVariant QMetaSequence::Iterable::ConstIterator::operator[](qsizetype n) const
+ Returns the item offset from the current one by \a n, converted to a
+ QVariant.
+*/
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qmetasequence.h b/src/corelib/kernel/qmetasequence.h
new file mode 100644
index 00000000000..e9505054159
--- /dev/null
+++ b/src/corelib/kernel/qmetasequence.h
@@ -0,0 +1,308 @@
+// Copyright (C) 2025 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QMETASEQUENCE_H
+#define QMETASEQUENCE_H
+
+#if 0
+#pragma qt_class(QMetaSequence)
+#endif
+
+#include <QtCore/qiterable.h>
+#include <QtCore/qiterable_impl.h>
+#include <QtCore/qmetacontainer.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtMetaContainerPrivate {
+
+class SequentialIterator : public QIterator<QMetaSequence>
+{
+public:
+ using value_type = QVariant;
+ using reference = QVariant::Reference<SequentialIterator>;
+ using pointer = QVariant::Pointer<SequentialIterator>;
+
+ static constexpr bool canNoexceptAssignQVariant = false;
+ static constexpr bool canNoexceptConvertToQVariant = false;
+
+ SequentialIterator(QIterator &&it) : QIterator(std::move(it)) {}
+
+ reference operator*() const { return reference(*this); }
+ pointer operator->() const { return pointer(*this); }
+ reference operator[](qsizetype n) const { return reference(*this + n); }
+};
+
+class SequentialConstIterator : public QConstIterator<QMetaSequence>
+{
+public:
+ using value_type = QVariant;
+ using reference = QVariant::ConstReference<SequentialConstIterator>;
+ using pointer = QVariant::ConstPointer<SequentialConstIterator>;
+
+ static constexpr bool canNoexceptConvertToQVariant = false;
+
+ SequentialConstIterator(QConstIterator &&it) : QConstIterator(std::move(it)) {}
+
+ value_type operator*() const;
+ pointer operator->() const { return pointer(*this); }
+ value_type operator[](qsizetype n) const;
+};
+
+} // namespace QtMetaContainerPrivate
+
+namespace QtPrivate {
+template<typename Referred>
+QVariant sequentialIteratorToVariant(const Referred &referred)
+{
+ const auto metaSequence = referred.metaContainer();
+ return QIterablePrivate::retrieveElement(metaSequence.valueMetaType(), [&](void *dataPtr) {
+ metaSequence.valueAtConstIterator(referred.constIterator(), dataPtr);
+ });
+}
+} // namespace QtPrivate
+
+template<>
+inline QVariant::Reference<QtMetaContainerPrivate::SequentialIterator>::operator QVariant() const
+{
+ return QtPrivate::sequentialIteratorToVariant(m_referred);
+}
+
+template<>
+inline QVariant::Reference<QtMetaContainerPrivate::SequentialIterator> &
+QVariant::Reference<QtMetaContainerPrivate::SequentialIterator>::operator=(const QVariant &value)
+{
+ QtPrivate::QVariantTypeCoercer coercer;
+ m_referred.metaContainer().setValueAtIterator(
+ m_referred.mutableIterator(),
+ coercer.coerce(value, m_referred.metaContainer().valueMetaType()));
+ return *this;
+}
+
+template<>
+inline QVariant::ConstReference<QtMetaContainerPrivate::SequentialConstIterator>::operator QVariant() const
+{
+ return QtPrivate::sequentialIteratorToVariant(m_referred);
+}
+
+namespace QtMetaContainerPrivate {
+inline SequentialConstIterator::value_type SequentialConstIterator::operator*() const
+{
+ return reference(*this);
+}
+
+inline SequentialConstIterator::value_type SequentialConstIterator::operator[](qsizetype n) const
+{
+ return reference(*this + n);
+}
+
+class Sequence : public QIterable<QMetaSequence>
+{
+public:
+ using Iterator = QTaggedIterator<SequentialIterator, void>;
+ using RandomAccessIterator
+ = QTaggedIterator<SequentialIterator, std::random_access_iterator_tag>;
+ using BidirectionalIterator
+ = QTaggedIterator<SequentialIterator, std::bidirectional_iterator_tag>;
+ using ForwardIterator
+ = QTaggedIterator<SequentialIterator, std::forward_iterator_tag>;
+ using InputIterator
+ = QTaggedIterator<SequentialIterator, std::input_iterator_tag>;
+
+ using ConstIterator
+ = QTaggedIterator<SequentialConstIterator, void>;
+ using RandomAccessConstIterator
+ = QTaggedIterator<SequentialConstIterator, std::random_access_iterator_tag>;
+ using BidirectionalConstIterator
+ = QTaggedIterator<SequentialConstIterator, std::bidirectional_iterator_tag>;
+ using ForwardConstIterator
+ = QTaggedIterator<SequentialConstIterator, std::forward_iterator_tag>;
+ using InputConstIterator
+ = QTaggedIterator<SequentialConstIterator, std::input_iterator_tag>;
+
+ using iterator = Iterator;
+ using const_iterator = ConstIterator;
+
+ template<class T>
+ Sequence(const T *p)
+ : QIterable(QMetaSequence::fromContainer<T>(), p)
+ {
+ Q_UNUSED(m_revision);
+ }
+
+ template<class T>
+ Sequence(T *p)
+ : QIterable(QMetaSequence::fromContainer<T>(), p)
+ {
+ }
+
+ Sequence()
+ : QIterable(QMetaSequence(), nullptr)
+ {
+ }
+
+ template<typename Pointer>
+ Sequence(const QMetaSequence &metaSequence, Pointer iterable)
+ : QIterable(metaSequence, iterable)
+ {
+ }
+
+ Sequence(const QMetaSequence &metaSequence, QMetaType metaType, void *iterable)
+ : QIterable(metaSequence, metaType.alignOf(), iterable)
+ {
+ }
+
+ Sequence(const QMetaSequence &metaSequence, QMetaType metaType, const void *iterable)
+ : QIterable(metaSequence, metaType.alignOf(), iterable)
+ {
+ }
+
+ Sequence(QIterable<QMetaSequence> &&other) : QIterable(std::move(other)) {}
+
+ Sequence &operator=(QIterable<QMetaSequence> &&other)
+ {
+ QIterable::operator=(std::move(other));
+ return *this;
+ }
+
+ ConstIterator begin() const { return constBegin(); }
+ ConstIterator end() const { return constEnd(); }
+
+ ConstIterator constBegin() const { return ConstIterator(QIterable::constBegin()); }
+ ConstIterator constEnd() const { return ConstIterator(QIterable::constEnd()); }
+
+ Iterator mutableBegin() { return Iterator(QIterable::mutableBegin()); }
+ Iterator mutableEnd() { return Iterator(QIterable::mutableEnd()); }
+
+ QVariant at(qsizetype idx) const
+ {
+ const QMetaSequence meta = metaContainer();
+ return QIterablePrivate::retrieveElement(meta.valueMetaType(), [&](void *dataPtr) {
+ if (meta.canGetValueAtIndex()) {
+ meta.valueAtIndex(constIterable(), idx, dataPtr);
+ return;
+ }
+
+ // ### Qt7: Drop this code. We shouldn't second-guess the underlying container
+ QtPrivate::warnSynthesizedAccess(
+ "at() called on an iterable without native indexed accessors. This is slow");
+ void *it = meta.constBegin(m_iterable.constPointer());
+ meta.advanceConstIterator(it, idx);
+ meta.valueAtConstIterator(it, dataPtr);
+ meta.destroyConstIterator(it);
+ });
+ }
+
+ void set(qsizetype idx, const QVariant &value)
+ {
+ const QMetaSequence meta = metaContainer();
+ QtPrivate::QVariantTypeCoercer coercer;
+ const void *dataPtr = coercer.coerce(value, meta.valueMetaType());
+ if (meta.canSetValueAtIndex()) {
+ meta.setValueAtIndex(mutableIterable(), idx, dataPtr);
+ return;
+ }
+
+ // ### Qt7: Drop this code. We shouldn't second-guess the underlying container
+ QtPrivate::warnSynthesizedAccess(
+ "set() called on an iterable without native indexed accessors. This is slow");
+ void *it = meta.begin(m_iterable.mutablePointer());
+ meta.advanceIterator(it, idx);
+ meta.setValueAtIterator(it, dataPtr);
+ meta.destroyIterator(it);
+ }
+
+ void append(const QVariant &value)
+ {
+ const QMetaSequence meta = metaContainer();
+ QtPrivate::QVariantTypeCoercer coercer;
+ meta.addValueAtEnd(mutableIterable(), coercer.coerce(value, meta.valueMetaType()));
+ }
+
+ void prepend(const QVariant &value)
+ {
+ const QMetaSequence meta = metaContainer();
+ QtPrivate::QVariantTypeCoercer coercer;
+ meta.addValueAtBegin(mutableIterable(), coercer.coerce(value, meta.valueMetaType()));
+ }
+
+ void removeLast()
+ {
+ metaContainer().removeValueAtEnd(mutableIterable());
+ }
+
+ void removeFirst()
+ {
+ metaContainer().removeValueAtBegin(mutableIterable());
+ }
+
+#if QT_DEPRECATED_SINCE(6, 11)
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_DEPRECATED
+
+ enum
+ QT_DEPRECATED_VERSION_X_6_11("Use append(), prepend(), removeLast(), or removeFirst() instead.")
+ Position: quint8
+ {
+ Unspecified, AtBegin, AtEnd
+ };
+
+ QT_DEPRECATED_VERSION_X_6_11("Use append() or prepend() instead.")
+ void addValue(const QVariant &value, Position position = Unspecified)
+ {
+ const QMetaSequence meta = metaContainer();
+ QtPrivate::QVariantTypeCoercer coercer;
+ const void *valuePtr = coercer.coerce(value, meta.valueMetaType());
+
+ switch (position) {
+ case AtBegin:
+ if (meta.canAddValueAtBegin())
+ meta.addValueAtBegin(mutableIterable(), valuePtr);
+ break;
+ case AtEnd:
+ if (meta.canAddValueAtEnd())
+ meta.addValueAtEnd(mutableIterable(), valuePtr);
+ break;
+ case Unspecified:
+ if (meta.canAddValue())
+ meta.addValue(mutableIterable(), valuePtr);
+ break;
+ }
+ }
+
+ QT_DEPRECATED_VERSION_X_6_11("Use removeLast() or removeFirst() instead.")
+ void removeValue(Position position = Unspecified)
+ {
+ const QMetaSequence meta = metaContainer();
+
+ switch (position) {
+ case AtBegin:
+ if (meta.canRemoveValueAtBegin())
+ meta.removeValueAtBegin(mutableIterable());
+ break;
+ case AtEnd:
+ if (meta.canRemoveValueAtEnd())
+ meta.removeValueAtEnd(mutableIterable());
+ break;
+ case Unspecified:
+ if (meta.canRemoveValue())
+ meta.removeValue(mutableIterable());
+ break;
+ }
+ }
+
+ QT_DEPRECATED_VERSION_X_6_11("Use QMetaSequence::valueMetaType() instead.")
+ QMetaType valueMetaType() const
+ {
+ return metaContainer().valueMetaType();
+ }
+
+ QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 11)
+};
+} // namespace QtMetaContainerPrivate
+
+QT_END_NAMESPACE
+
+#endif // QMETASEQUENCE_H
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 1850a148d19..565f9182e68 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -43,7 +43,9 @@
# include "qjsonvalue.h"
# include "qline.h"
# include "qloggingcategory.h"
+# include "qmetaassociation.h"
# include "qmetaobject.h"
+# include "qmetasequence.h"
# include "qobject.h"
# include "qpoint.h"
# include "qrect.h"
@@ -2151,25 +2153,28 @@ static bool convertToEnum(QMetaType fromType, const void *from, QMetaType toType
}
}
-static bool convertIterableToVariantList(QMetaType fromType, const void *from, void *to)
+template<typename Iterable>
+bool convertIterableToVariantList(QMetaType fromType, const void *from, void *to)
{
- QSequentialIterable list;
- if (!QMetaType::convert(fromType, from, QMetaType::fromType<QSequentialIterable>(), &list))
+ Iterable list;
+ if (!QMetaType::convert(fromType, from, QMetaType::fromType<Iterable>(), &list))
return false;
QVariantList &l = *static_cast<QVariantList *>(to);
l.clear();
- l.reserve(list.size());
+ if (list.metaContainer().hasSize())
+ l.reserve(list.size());
auto end = list.end();
for (auto it = list.begin(); it != end; ++it)
l << *it;
return true;
}
-static bool convertIterableToVariantMap(QMetaType fromType, const void *from, void *to)
+template<typename Iterable>
+bool convertIterableToVariantMap(QMetaType fromType, const void *from, void *to)
{
- QAssociativeIterable map;
- if (!QMetaType::convert(fromType, from, QMetaType::fromType<QAssociativeIterable>(), &map))
+ Iterable map;
+ if (!QMetaType::convert(fromType, from, QMetaType::fromType<Iterable>(), &map))
return false;
QVariantMap &h = *static_cast<QVariantMap *>(to);
@@ -2180,10 +2185,11 @@ static bool convertIterableToVariantMap(QMetaType fromType, const void *from, vo
return true;
}
-static bool convertIterableToVariantHash(QMetaType fromType, const void *from, void *to)
+template<typename Iterable>
+bool convertIterableToVariantHash(QMetaType fromType, const void *from, void *to)
{
- QAssociativeIterable map;
- if (!QMetaType::convert(fromType, from, QMetaType::fromType<QAssociativeIterable>(), &map))
+ Iterable map;
+ if (!QMetaType::convert(fromType, from, QMetaType::fromType<Iterable>(), &map))
return false;
QVariantHash &h = *static_cast<QVariantHash *>(to);
@@ -2225,33 +2231,34 @@ static bool convertIterableToVariantPair(QMetaType fromType, const void *from, v
return true;
}
+template<typename Iterable>
static bool convertToSequentialIterable(QMetaType fromType, const void *from, void *to)
{
using namespace QtMetaTypePrivate;
const int fromTypeId = fromType.id();
- QSequentialIterable &i = *static_cast<QSequentialIterable *>(to);
+ Iterable &i = *static_cast<Iterable *>(to);
switch (fromTypeId) {
case QMetaType::QVariantList:
- i = QSequentialIterable(reinterpret_cast<const QVariantList *>(from));
+ i = Iterable(reinterpret_cast<const QVariantList *>(from));
return true;
case QMetaType::QStringList:
- i = QSequentialIterable(reinterpret_cast<const QStringList *>(from));
+ i = Iterable(reinterpret_cast<const QStringList *>(from));
return true;
case QMetaType::QByteArrayList:
- i = QSequentialIterable(reinterpret_cast<const QByteArrayList *>(from));
+ i = Iterable(reinterpret_cast<const QByteArrayList *>(from));
return true;
case QMetaType::QString:
- i = QSequentialIterable(reinterpret_cast<const QString *>(from));
+ i = Iterable(reinterpret_cast<const QString *>(from));
return true;
case QMetaType::QByteArray:
- i = QSequentialIterable(reinterpret_cast<const QByteArray *>(from));
+ i = Iterable(reinterpret_cast<const QByteArray *>(from));
return true;
default: {
- QSequentialIterable impl;
+ QIterable<QMetaSequence> j(QMetaSequence(), nullptr);
if (QMetaType::convert(
- fromType, from, QMetaType::fromType<QIterable<QMetaSequence>>(), &impl)) {
- i = std::move(impl);
+ fromType, from, QMetaType::fromType<QIterable<QMetaSequence>>(), &j)) {
+ i = std::move(j);
return true;
}
}
@@ -2289,27 +2296,28 @@ static bool canImplicitlyViewAsSequentialIterable(QMetaType fromType)
}
}
+template<typename Iterable>
static bool viewAsSequentialIterable(QMetaType fromType, void *from, void *to)
{
using namespace QtMetaTypePrivate;
const int fromTypeId = fromType.id();
- QSequentialIterable &i = *static_cast<QSequentialIterable *>(to);
+ Iterable &i = *static_cast<Iterable *>(to);
switch (fromTypeId) {
case QMetaType::QVariantList:
- i = QSequentialIterable(reinterpret_cast<QVariantList *>(from));
+ i = Iterable(reinterpret_cast<QVariantList *>(from));
return true;
case QMetaType::QStringList:
- i = QSequentialIterable(reinterpret_cast<QStringList *>(from));
+ i = Iterable(reinterpret_cast<QStringList *>(from));
return true;
case QMetaType::QByteArrayList:
- i = QSequentialIterable(reinterpret_cast<QByteArrayList *>(from));
+ i = Iterable(reinterpret_cast<QByteArrayList *>(from));
return true;
case QMetaType::QString:
- i = QSequentialIterable(reinterpret_cast<QString *>(from));
+ i = Iterable(reinterpret_cast<QString *>(from));
return true;
case QMetaType::QByteArray:
- i = QSequentialIterable(reinterpret_cast<QByteArray *>(from));
+ i = Iterable(reinterpret_cast<QByteArray *>(from));
return true;
default: {
QIterable<QMetaSequence> j(QMetaSequence(), nullptr);
@@ -2324,24 +2332,25 @@ static bool viewAsSequentialIterable(QMetaType fromType, void *from, void *to)
return false;
}
+template<typename Iterable>
static bool convertToAssociativeIterable(QMetaType fromType, const void *from, void *to)
{
using namespace QtMetaTypePrivate;
- QAssociativeIterable &i = *static_cast<QAssociativeIterable *>(to);
+ Iterable &i = *static_cast<Iterable *>(to);
if (fromType.id() == QMetaType::QVariantMap) {
- i = QAssociativeIterable(reinterpret_cast<const QVariantMap *>(from));
+ i = Iterable(reinterpret_cast<const QVariantMap *>(from));
return true;
}
if (fromType.id() == QMetaType::QVariantHash) {
- i = QAssociativeIterable(reinterpret_cast<const QVariantHash *>(from));
+ i = Iterable(reinterpret_cast<const QVariantHash *>(from));
return true;
}
- QAssociativeIterable impl;
+ QIterable<QMetaAssociation> j(QMetaAssociation(), nullptr);
if (QMetaType::convert(
- fromType, from, QMetaType::fromType<QIterable<QMetaAssociation>>(), &impl)) {
- i = std::move(impl);
+ fromType, from, QMetaType::fromType<QIterable<QMetaAssociation>>(), &j)) {
+ i = std::move(j);
return true;
}
@@ -2384,18 +2393,19 @@ static bool canImplicitlyViewAsAssociativeIterable(QMetaType fromType)
}
}
+template<typename Iterable>
static bool viewAsAssociativeIterable(QMetaType fromType, void *from, void *to)
{
using namespace QtMetaTypePrivate;
int fromTypeId = fromType.id();
- QAssociativeIterable &i = *static_cast<QAssociativeIterable *>(to);
+ Iterable &i = *static_cast<Iterable *>(to);
if (fromTypeId == QMetaType::QVariantMap) {
- i = QAssociativeIterable(reinterpret_cast<QVariantMap *>(from));
+ i = Iterable(reinterpret_cast<QVariantMap *>(from));
return true;
}
if (fromTypeId == QMetaType::QVariantHash) {
- i = QAssociativeIterable(reinterpret_cast<QVariantHash *>(from));
+ i = Iterable(reinterpret_cast<QVariantHash *>(from));
return true;
}
@@ -2493,20 +2503,54 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType,
return true;
// handle iterables
- if (toTypeId == QVariantList && convertIterableToVariantList(fromType, from, to))
+ if (toTypeId == QVariantList
+ && convertIterableToVariantList<QMetaSequence::Iterable>(fromType, from, to)) {
return true;
+ }
- if (toTypeId == QVariantMap && convertIterableToVariantMap(fromType, from, to))
+ if (toTypeId == QVariantMap
+ && convertIterableToVariantMap<QMetaAssociation::Iterable>(fromType, from, to)) {
return true;
+ }
- if (toTypeId == QVariantHash && convertIterableToVariantHash(fromType, from, to))
+ if (toTypeId == QVariantHash
+ && convertIterableToVariantHash<QMetaAssociation::Iterable>(fromType, from, to)) {
return true;
+ }
+
+ if (toTypeId == qMetaTypeId<QMetaSequence::Iterable>())
+ return convertToSequentialIterable<QMetaSequence::Iterable>(fromType, from, to);
+
+ if (toTypeId == qMetaTypeId<QMetaAssociation::Iterable>())
+ return convertToAssociativeIterable<QMetaAssociation::Iterable>(fromType, from, to);
+
+#if QT_DEPRECATED_SINCE(6, 13)
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_DEPRECATED
+
+ if (toTypeId == QVariantList
+ && convertIterableToVariantList<QSequentialIterable>(fromType, from, to)) {
+ return true;
+ }
+
+ if (toTypeId == QVariantMap
+ && convertIterableToVariantMap<QAssociativeIterable>(fromType, from, to)) {
+ return true;
+ }
+
+ if (toTypeId == QVariantHash
+ && convertIterableToVariantHash<QAssociativeIterable>(fromType, from, to)) {
+ return true;
+ }
if (toTypeId == qMetaTypeId<QSequentialIterable>())
- return convertToSequentialIterable(fromType, from, to);
+ return convertToSequentialIterable<QSequentialIterable>(fromType, from, to);
if (toTypeId == qMetaTypeId<QAssociativeIterable>())
- return convertToAssociativeIterable(fromType, from, to);
+ return convertToAssociativeIterable<QAssociativeIterable>(fromType, from, to);
+
+ QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 13)
return convertMetaObject(fromType, from, toType, to);
}
@@ -2528,11 +2572,24 @@ bool QMetaType::view(QMetaType fromType, void *from, QMetaType toType, void *to)
if (f)
return (*f)(from, to);
+ if (toTypeId == qMetaTypeId<QMetaSequence::Iterable>())
+ return viewAsSequentialIterable<QMetaSequence::Iterable>(fromType, from, to);
+
+ if (toTypeId == qMetaTypeId<QMetaAssociation::Iterable>())
+ return viewAsAssociativeIterable<QMetaAssociation::Iterable>(fromType, from, to);
+
+#if QT_DEPRECATED_SINCE(6, 13)
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_DEPRECATED
+
if (toTypeId == qMetaTypeId<QSequentialIterable>())
- return viewAsSequentialIterable(fromType, from, to);
+ return viewAsSequentialIterable<QSequentialIterable>(fromType, from, to);
if (toTypeId == qMetaTypeId<QAssociativeIterable>())
- return viewAsAssociativeIterable(fromType, from, to);
+ return viewAsAssociativeIterable<QAssociativeIterable>(fromType, from, to);
+
+ QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 13)
return convertMetaObject(fromType, from, toType, to);
}
@@ -2545,14 +2602,14 @@ bool QMetaType::view(QMetaType fromType, void *from, QMetaType toType, void *to)
function if a qobject_cast from the type described by \a fromType to the type described
by \a toType would succeed.
- You can create a mutable view of type QSequentialIterable on any container registered with
+ You can create a mutable view of type QMetaSequence::Iterable on any container registered with
Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE().
- Similarly you can create a mutable view of type QAssociativeIterable on any container
+ Similarly you can create a mutable view of type QMetaAssociation::Iterable on any container
registered with Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE().
- \sa convert(), QSequentialIterable, Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(),
- QAssociativeIterable, Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE()
+ \sa convert(), QMetaSequence::Iterable, Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(),
+ QMetaAssociation::Iterable, Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE()
*/
bool QMetaType::canView(QMetaType fromType, QMetaType toType)
{
@@ -2566,12 +2623,25 @@ bool QMetaType::canView(QMetaType fromType, QMetaType toType)
if (f)
return true;
+ if (toTypeId == qMetaTypeId<QMetaSequence::Iterable>())
+ return canImplicitlyViewAsSequentialIterable(fromType);
+
+ if (toTypeId == qMetaTypeId<QMetaAssociation::Iterable>())
+ return canImplicitlyViewAsAssociativeIterable(fromType);
+
+#if QT_DEPRECATED_SINCE(6, 13)
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_DEPRECATED
+
if (toTypeId == qMetaTypeId<QSequentialIterable>())
return canImplicitlyViewAsSequentialIterable(fromType);
if (toTypeId == qMetaTypeId<QAssociativeIterable>())
return canImplicitlyViewAsAssociativeIterable(fromType);
+ QT_WARNING_POP
+#endif
+
if (canConvertMetaObject(fromType, toType))
return true;
@@ -2660,8 +2730,8 @@ bool QMetaType::canView(QMetaType fromType, QMetaType toType)
Similarly, a cast from an associative container will also return true for this
function the \a toType is QVariantHash or QVariantMap.
- \sa convert(), QSequentialIterable, Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(), QAssociativeIterable,
- Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE()
+ \sa convert(), QMetaSequence::Iterable, Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(),
+ QMetaAssociation::Iterable, Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE()
*/
bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
{
@@ -2682,11 +2752,32 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
if (f)
return true;
+ if (toTypeId == qMetaTypeId<QMetaSequence::Iterable>())
+ return canConvertToSequentialIterable(fromType);
+
+ if (toTypeId == qMetaTypeId<QMetaAssociation::Iterable>())
+ return canConvertToAssociativeIterable(fromType);
+
+ if (toTypeId == QVariantList
+ && canConvert(fromType, QMetaType::fromType<QMetaSequence::Iterable>())) {
+ return true;
+ }
+
+ if ((toTypeId == QVariantHash || toTypeId == QVariantMap)
+ && canConvert(fromType, QMetaType::fromType<QMetaAssociation::Iterable>())) {
+ return true;
+ }
+
+#if QT_DEPRECATED_SINCE(6, 13)
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_DEPRECATED
+
if (toTypeId == qMetaTypeId<QSequentialIterable>())
return canConvertToSequentialIterable(fromType);
if (toTypeId == qMetaTypeId<QAssociativeIterable>())
return canConvertToAssociativeIterable(fromType);
+
if (toTypeId == QVariantList
&& canConvert(fromType, QMetaType::fromType<QSequentialIterable>())) {
return true;
@@ -2697,6 +2788,9 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
return true;
}
+ QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 13)
+
if (toTypeId == QVariantPair && hasRegisteredConverterFunction(
fromType, QMetaType::fromType<QtMetaTypePrivate::QPairVariantInterfaceImpl>()))
return true;
diff --git a/src/corelib/kernel/qsequentialiterable.cpp b/src/corelib/kernel/qsequentialiterable.cpp
index 32c58266045..5b040404654 100644
--- a/src/corelib/kernel/qsequentialiterable.cpp
+++ b/src/corelib/kernel/qsequentialiterable.cpp
@@ -7,8 +7,13 @@
QT_BEGIN_NAMESPACE
+#if QT_DEPRECATED_SINCE(6, 13)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+
/*!
\class QSequentialIterable
+ \deprecated [6.13] Use QMetaSequence::Iterable instead.
\since 5.2
\inmodule QtCore
\brief The QSequentialIterable class is an iterable interface for a container in a QVariant.
@@ -17,8 +22,6 @@ QT_BEGIN_NAMESPACE
a QVariant. An instance of QSequentialIterable can be extracted from a QVariant if it can
be converted to a QVariantList.
- \snippet code/src_corelib_kernel_qvariant.cpp 9
-
The container itself is not copied before iterating over it.
\sa QVariant
@@ -160,17 +163,17 @@ void QSequentialIterable::set(qsizetype idx, const QVariant &value)
/*!
\typealias QSequentialIterable::const_iterator
+ \deprecated [6.13] Use QMetaSequence::Iterable::ConstIterator instead.
\brief The QSequentialIterable::const_iterator allows iteration over a container in a QVariant.
A QSequentialIterable::const_iterator can only be created by a QSequentialIterable instance,
and can be used in a way similar to other stl-style iterators.
-
- \snippet code/src_corelib_kernel_qvariant.cpp 9
*/
/*!
\typealias QSequentialIterable::iterator
\since 6.0
+ \deprecated [6.13] Use QMetaSequence::Iterable::Iterator instead.
\brief The QSequentialIterable::iterator allows iteration over a container in a QVariant.
A QSequentialIterable::iterator can only be created by a QSequentialIterable instance,
@@ -221,4 +224,7 @@ QVariantConstPointer QSequentialConstIterator::operator->() const
return QVariantConstPointer(operator*());
}
+QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 13)
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qsequentialiterable.h b/src/corelib/kernel/qsequentialiterable.h
index dac146d2ad3..738bebf3631 100644
--- a/src/corelib/kernel/qsequentialiterable.h
+++ b/src/corelib/kernel/qsequentialiterable.h
@@ -9,7 +9,13 @@
QT_BEGIN_NAMESPACE
-class Q_CORE_EXPORT QSequentialIterator : public QIterator<QMetaSequence>
+#if QT_DEPRECATED_SINCE(6, 13)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+
+class
+QT_DEPRECATED_VERSION_X_6_13("Use QMetaSequence::Iterable::Iterator instead.")
+QSequentialIterator : public QIterator<QMetaSequence>
{
public:
using value_type = QVariant;
@@ -20,11 +26,13 @@ public:
: QIterator(std::move(it))
{}
- QVariantRef<QSequentialIterator> operator*() const;
- QVariantPointer<QSequentialIterator> operator->() const;
+ Q_CORE_EXPORT QVariantRef<QSequentialIterator> operator*() const;
+ Q_CORE_EXPORT QVariantPointer<QSequentialIterator> operator->() const;
};
-class Q_CORE_EXPORT QSequentialConstIterator : public QConstIterator<QMetaSequence>
+class
+QT_DEPRECATED_VERSION_X_6_13("Use QMetaSequence::Iterable::ConstIterator instead.")
+QSequentialConstIterator : public QConstIterator<QMetaSequence>
{
public:
using value_type = QVariant;
@@ -35,11 +43,13 @@ public:
: QConstIterator(std::move(it))
{}
- QVariant operator*() const;
- QVariantConstPointer operator->() const;
+ Q_CORE_EXPORT QVariant operator*() const;
+ Q_CORE_EXPORT QVariantConstPointer operator->() const;
};
-class Q_CORE_EXPORT QSequentialIterable : public QIterable<QMetaSequence>
+class
+QT_DEPRECATED_VERSION_X_6_13("Use QMetaSequence::Iterable instead.")
+QSequentialIterable : public QIterable<QMetaSequence>
{
public:
using iterator = QTaggedIterator<QSequentialIterator, void>;
@@ -79,14 +89,12 @@ public:
{
}
- // ### Qt7: Pass QMetaType as value rather than const ref.
QSequentialIterable(const QMetaSequence &metaSequence, const QMetaType &metaType,
void *iterable)
: QIterable(metaSequence, metaType.alignOf(), iterable)
{
}
- // ### Qt7: Pass QMetaType as value rather than const ref.
QSequentialIterable(const QMetaSequence &metaSequence, const QMetaType &metaType,
const void *iterable)
: QIterable(metaSequence, metaType.alignOf(), iterable)
@@ -110,14 +118,14 @@ public:
iterator mutableBegin() { return iterator(QIterable::mutableBegin()); }
iterator mutableEnd() { return iterator(QIterable::mutableEnd()); }
- QVariant at(qsizetype idx) const;
- void set(qsizetype idx, const QVariant &value);
+ Q_CORE_EXPORT QVariant at(qsizetype idx) const;
+ Q_CORE_EXPORT void set(qsizetype idx, const QVariant &value);
enum Position { Unspecified, AtBegin, AtEnd };
- void addValue(const QVariant &value, Position position = Unspecified);
- void removeValue(Position position = Unspecified);
+ Q_CORE_EXPORT void addValue(const QVariant &value, Position position = Unspecified);
+ Q_CORE_EXPORT void removeValue(Position position = Unspecified);
- QMetaType valueMetaType() const;
+ Q_CORE_EXPORT QMetaType valueMetaType() const;
};
template<>
@@ -150,6 +158,9 @@ Q_DECLARE_TYPEINFO(QSequentialIterable, Q_RELOCATABLE_TYPE);
Q_DECLARE_TYPEINFO(QSequentialIterable::iterator, Q_RELOCATABLE_TYPE);
Q_DECLARE_TYPEINFO(QSequentialIterable::const_iterator, Q_RELOCATABLE_TYPE);
+QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 13)
+
QT_END_NAMESPACE
#endif // QSEQUENTIALITERABLE_H
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 57089f164b2..d2b2aa1cebb 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -2852,9 +2852,14 @@ const void *QtPrivate::QVariantTypeCoercer::coerce(const QVariant &value, const
return converted.constData();
}
+#if QT_DEPRECATED_SINCE(6, 13)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+
/*!
\class QVariantRef
\since 6.0
+ \deprecated [6.13] Use QVariant::Reference instead.
\inmodule QtCore
\brief The QVariantRef acts as a non-const reference to a QVariant.
@@ -2909,6 +2914,7 @@ const void *QtPrivate::QVariantTypeCoercer::coerce(const QVariant &value, const
/*!
\class QVariantConstPointer
\since 6.0
+ \deprecated [6.13] Use QVariant::ConstPointer instead.
\inmodule QtCore
\brief Emulated const pointer to QVariant based on a pointer.
@@ -2946,6 +2952,7 @@ const QVariant *QVariantConstPointer::operator->() const
/*!
\class QVariantPointer
\since 6.0
+ \deprecated [6.13] Use QVariant::Pointer instead.
\inmodule QtCore
\brief QVariantPointer is a template class that emulates a pointer to QVariant based on a pointer.
@@ -2974,6 +2981,9 @@ const QVariant *QVariantConstPointer::operator->() const
implement operator->().
*/
+QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 13)
+
/*!
\class QVariant::ConstReference
\since 6.11
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index 9117c827afe..47fb34cbe65 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -983,8 +983,13 @@ private:
};
}
-template<typename Pointer>
-class QVariantRef
+#if QT_DEPRECATED_SINCE(6, 13)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+
+template<typename Pointer> class
+QT_DEPRECATED_VERSION_X_6_13("Use QVariant::Reference instead.")
+QVariantRef
{
private:
const Pointer *m_pointer = nullptr;
@@ -1008,20 +1013,23 @@ public:
}
};
-class Q_CORE_EXPORT QVariantConstPointer
+class
+QT_DEPRECATED_VERSION_X_6_13("Use QVariant::ConstPointer instead.")
+QVariantConstPointer
{
private:
QVariant m_variant;
public:
- explicit QVariantConstPointer(QVariant variant);
+ Q_CORE_EXPORT explicit QVariantConstPointer(QVariant variant);
- QVariant operator*() const;
- const QVariant *operator->() const;
+ Q_CORE_EXPORT QVariant operator*() const;
+ Q_CORE_EXPORT const QVariant *operator->() const;
};
-template<typename Pointer>
-class QVariantPointer
+template<typename Pointer> class
+QT_DEPRECATED_VERSION_X_6_13("Use QVariant::Pointer instead.")
+QVariantPointer
{
private:
const Pointer *m_pointer = nullptr;
@@ -1032,6 +1040,9 @@ public:
Pointer operator->() const { return *m_pointer; }
};
+QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 13)
+
QT_END_NAMESPACE
#endif // QVARIANT_H
diff --git a/src/gui/accessible/linux/atspiadaptor.cpp b/src/gui/accessible/linux/atspiadaptor.cpp
index dad0ac2b74a..dae83437b89 100644
--- a/src/gui/accessible/linux/atspiadaptor.cpp
+++ b/src/gui/accessible/linux/atspiadaptor.cpp
@@ -132,7 +132,7 @@ AtSpiAdaptor::~AtSpiAdaptor()
*/
QString AtSpiAdaptor::introspect(const QString &path) const
{
- static const QLatin1StringView accessibleIntrospection(
+ constexpr auto accessibleIntrospection =
" <interface name=\"org.a11y.atspi.Accessible\">\n"
" <property access=\"read\" type=\"s\" name=\"Name\"/>\n"
" <property access=\"read\" type=\"s\" name=\"Description\"/>\n"
@@ -182,9 +182,9 @@ QString AtSpiAdaptor::introspect(const QString &path) const
" <arg direction=\"out\" type=\"s\"/>\n"
" </method>\n"
" </interface>\n"
- );
+ ""_L1;
- static const QLatin1StringView actionIntrospection(
+ constexpr auto actionIntrospection =
" <interface name=\"org.a11y.atspi.Action\">\n"
" <property access=\"read\" type=\"i\" name=\"NActions\"/>\n"
" <method name=\"GetDescription\">\n"
@@ -208,9 +208,9 @@ QString AtSpiAdaptor::introspect(const QString &path) const
" <arg direction=\"out\" type=\"b\"/>\n"
" </method>\n"
" </interface>\n"
- );
+ ""_L1;
- static const QLatin1StringView applicationIntrospection(
+ constexpr auto applicationIntrospection =
" <interface name=\"org.a11y.atspi.Application\">\n"
" <property access=\"read\" type=\"s\" name=\"ToolkitName\"/>\n"
" <property access=\"read\" type=\"s\" name=\"Version\"/>\n"
@@ -223,9 +223,9 @@ QString AtSpiAdaptor::introspect(const QString &path) const
" <arg direction=\"out\" type=\"s\" name=\"address\"/>\n"
" </method>\n"
" </interface>\n"
- );
+ ""_L1;
- static const QLatin1StringView collectionIntrospection(
+ constexpr auto collectionIntrospection =
" <interface name=\"org.a11y.atspi.Collection\">\n"
" <method name=\"GetMatches\">\n"
" <arg direction=\"in\" name=\"rule\" type=\"(aiia{ss}iaiiasib)\"/>\n"
@@ -266,9 +266,9 @@ QString AtSpiAdaptor::introspect(const QString &path) const
" <annotation name=\"org.qtproject.QtDBus.QtTypeName.Out0\" value=\"QSpiReferenceSet\"/>\n"
" </method>\n"
" </interface>\n"
- );
+ ""_L1;
- static const QLatin1StringView componentIntrospection(
+ constexpr auto componentIntrospection =
" <interface name=\"org.a11y.atspi.Component\">\n"
" <method name=\"Contains\">\n"
" <arg direction=\"in\" type=\"i\" name=\"x\"/>\n"
@@ -329,9 +329,9 @@ QString AtSpiAdaptor::introspect(const QString &path) const
" <arg direction=\"out\" type=\"b\"/>\n"
" </method>\n"
" </interface>\n"
- );
+ ""_L1;
- static const QLatin1StringView editableTextIntrospection(
+ constexpr auto editableTextIntrospection =
" <interface name=\"org.a11y.atspi.EditableText\">\n"
" <method name=\"SetTextContents\">\n"
" <arg direction=\"in\" type=\"s\" name=\"newContents\"/>\n"
@@ -362,9 +362,9 @@ QString AtSpiAdaptor::introspect(const QString &path) const
" <arg direction=\"out\" type=\"b\"/>\n"
" </method>\n"
" </interface>\n"
- );
+ ""_L1;
- static const QLatin1StringView selectionIntrospection(
+ constexpr auto selectionIntrospection =
" <interface name=\"org.a11y.atspi.Selection\">\n"
" <property name=\"NSelectedChildren\" type=\"i\" access=\"read\"/>\n"
" <method name=\"GetSelectedChild\">\n"
@@ -395,9 +395,9 @@ QString AtSpiAdaptor::introspect(const QString &path) const
" <arg direction=\"out\" type=\"b\"/>\n"
" </method>\n"
" </interface>\n"
- );
+ ""_L1;
- static const QLatin1StringView tableIntrospection(
+ constexpr auto tableIntrospection =
" <interface name=\"org.a11y.atspi.Table\">\n"
" <property access=\"read\" type=\"i\" name=\"NRows\"/>\n"
" <property access=\"read\" type=\"i\" name=\"NColumns\"/>\n"
@@ -503,9 +503,9 @@ QString AtSpiAdaptor::introspect(const QString &path) const
" <arg direction=\"out\" type=\"b\" name=\"is_selected\"/>\n"
" </method>\n"
" </interface>\n"
- );
+ ""_L1;
- static const QLatin1StringView tableCellIntrospection(
+ constexpr auto tableCellIntrospection =
" <interface name=\"org.a11y.atspi.TableCell\">\n"
" <property access=\"read\" name=\"ColumnSpan\" type=\"i\" />\n"
" <property access=\"read\" name=\"Position\" type=\"(ii)\">\n"
@@ -531,9 +531,9 @@ QString AtSpiAdaptor::introspect(const QString &path) const
" <annotation value=\"QSpiObjectReferenceArray\" name=\"org.qtproject.QtDBus.QtTypeName.Out0\"/>\n"
" </method>\n"
" </interface>\n"
- );
+ ""_L1;
- static const QLatin1StringView textIntrospection(
+ constexpr auto textIntrospection =
" <interface name=\"org.a11y.atspi.Text\">\n"
" <property access=\"read\" type=\"i\" name=\"CharacterCount\"/>\n"
" <property access=\"read\" type=\"i\" name=\"CaretOffset\"/>\n"
@@ -670,9 +670,9 @@ QString AtSpiAdaptor::introspect(const QString &path) const
" <arg direction=\"out\" type=\"b\"/>\n"
" </method>\n"
" </interface>\n"
- );
+ ""_L1;
- static const QLatin1StringView valueIntrospection(
+ constexpr auto valueIntrospection =
" <interface name=\"org.a11y.atspi.Value\">\n"
" <property access=\"read\" type=\"d\" name=\"MinimumValue\"/>\n"
" <property access=\"read\" type=\"d\" name=\"MaximumValue\"/>\n"
@@ -682,7 +682,7 @@ QString AtSpiAdaptor::introspect(const QString &path) const
" <arg direction=\"in\" type=\"d\" name=\"value\"/>\n"
" </method>\n"
" </interface>\n"
- );
+ ""_L1;
QAccessibleInterface * interface = interfaceFromPath(path);
if (!interface) {
diff --git a/src/gui/platform/unix/qxkbcommon.cpp b/src/gui/platform/unix/qxkbcommon.cpp
index ebac9f108e8..e755892cf36 100644
--- a/src/gui/platform/unix/qxkbcommon.cpp
+++ b/src/gui/platform/unix/qxkbcommon.cpp
@@ -328,6 +328,12 @@ static constexpr const auto KeyTbl = qMakeArray(
Xkb2Qt<XKB_KEY_XF86Option, Qt::Key_Option>,
Xkb2Qt<XKB_KEY_XF86Paste, Qt::Key_Paste>,
Xkb2Qt<XKB_KEY_XF86Phone, Qt::Key_Phone>,
+#ifdef XKB_KEY_XF86PickupPhone
+ Xkb2Qt<XKB_KEY_XF86PickupPhone, Qt::Key_Call>,
+#endif
+#ifdef XKB_KEY_XF86HangupPhone
+ Xkb2Qt<XKB_KEY_XF86HangupPhone, Qt::Key_Hangup>,
+#endif
Xkb2Qt<XKB_KEY_XF86Reply, Qt::Key_Reply>,
Xkb2Qt<XKB_KEY_XF86Reload, Qt::Key_Reload>,
Xkb2Qt<XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows>,
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index a511eb854cb..33e35ba6694 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -2159,6 +2159,18 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
}
#endif
+ // Add self-dependency to be able to add memory barriers for writes in graphics stages
+ VkSubpassDependency selfDependency;
+ VkPipelineStageFlags stageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
+ selfDependency.srcSubpass = 0;
+ selfDependency.dstSubpass = 0;
+ selfDependency.srcStageMask = stageMask;
+ selfDependency.dstStageMask = stageMask;
+ selfDependency.srcAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ selfDependency.dstAccessMask = selfDependency.srcAccessMask;
+ selfDependency.dependencyFlags = 0;
+ rpD->subpassDeps.append(selfDependency);
+
// rpD->subpassDeps stays empty: don't yet know the correct initial/final
// access and stage stuff for the implicit deps at this point, so leave it
// to the resource tracking and activateTextureRenderTarget() to generate
@@ -4864,6 +4876,17 @@ void QRhiVulkan::recordPrimaryCommandBuffer(QVkCommandBuffer *cbD)
cmd.args.beginRenderPass.useSecondaryCb ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS
: VK_SUBPASS_CONTENTS_INLINE);
break;
+ case QVkCommandBuffer::Command::MemoryBarrier: {
+ VkMemoryBarrier barrier;
+ barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+ barrier.pNext = nullptr;
+ barrier.dstAccessMask = cmd.args.memoryBarrier.dstAccessMask;
+ barrier.srcAccessMask = cmd.args.memoryBarrier.srcAccessMask;
+ df->vkCmdPipelineBarrier(cbD->cb, cmd.args.memoryBarrier.srcStageMask, cmd.args.memoryBarrier.dstStageMask, cmd.args.memoryBarrier.dependencyFlags,
+ 1, &barrier,
+ 0, VK_NULL_HANDLE,
+ 0, VK_NULL_HANDLE);
+ } break;
case QVkCommandBuffer::Command::EndRenderPass:
df->vkCmdEndRenderPass(cbD->cb);
break;
@@ -5702,6 +5725,9 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
QVkShaderResourceBindings *srbD = QRHI_RES(QVkShaderResourceBindings, srb);
auto &descSetBd(srbD->boundResourceData[currentFrameSlot]);
bool rewriteDescSet = false;
+ bool addWriteBarrier = false;
+ VkPipelineStageFlags writeBarrierSrcStageMask = 0;
+ VkPipelineStageFlags writeBarrierDstStageMask = 0;
// Do host writes and mark referenced shader resources as in-use.
// Also prepare to ensure the descriptor set we are going to bind refers to up-to-date Vk objects.
@@ -5789,9 +5815,22 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
access = QRhiPassResourceTracker::TexStorageStore;
else
access = QRhiPassResourceTracker::TexStorageLoadStore;
+
+ const auto stage = QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage);
+ const auto prevAccess = passResTracker.textures().find(texD);
+ if (prevAccess != passResTracker.textures().end()) {
+ const QRhiPassResourceTracker::Texture &tex = prevAccess->second;
+ if (tex.access == QRhiPassResourceTracker::TexStorageStore
+ || tex.access == QRhiPassResourceTracker::TexStorageLoadStore) {
+ addWriteBarrier = true;
+ writeBarrierDstStageMask |= toVkPipelineStage(stage);
+ writeBarrierSrcStageMask |= toVkPipelineStage(tex.stage);
+ }
+ }
+
trackedRegisterTexture(&passResTracker, texD,
access,
- QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage));
+ stage);
if (texD->generation != bd.simage.generation || texD->m_id != bd.simage.id) {
rewriteDescSet = true;
@@ -5818,9 +5857,21 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
access = QRhiPassResourceTracker::BufStorageStore;
else
access = QRhiPassResourceTracker::BufStorageLoadStore;
+
+ const auto stage = QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage);
+ const auto prevAccess = passResTracker.buffers().find(bufD);
+ if (prevAccess != passResTracker.buffers().end()) {
+ const QRhiPassResourceTracker::Buffer &buf = prevAccess->second;
+ if (buf.access == QRhiPassResourceTracker::BufStorageStore
+ || buf.access == QRhiPassResourceTracker::BufStorageLoadStore) {
+ addWriteBarrier = true;
+ writeBarrierDstStageMask |= toVkPipelineStage(stage);
+ writeBarrierSrcStageMask |= toVkPipelineStage(buf.stage);
+ }
+ }
trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
access,
- QRhiPassResourceTracker::toPassTrackerBufferStage(b->stage));
+ stage);
if (bufD->generation != bd.sbuf.generation || bufD->m_id != bd.sbuf.id) {
rewriteDescSet = true;
@@ -5835,6 +5886,28 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
}
}
+ if (addWriteBarrier) {
+ if (cbD->passUsesSecondaryCb) {
+ VkMemoryBarrier barrier;
+ barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
+ barrier.pNext = nullptr;
+ barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ barrier.srcAccessMask = barrier.dstAccessMask;
+ df->vkCmdPipelineBarrier(cbD->activeSecondaryCbStack.last(), writeBarrierSrcStageMask, writeBarrierDstStageMask, 0,
+ 1, &barrier,
+ 0, VK_NULL_HANDLE,
+ 0, VK_NULL_HANDLE);
+ } else {
+ QVkCommandBuffer::Command &cmd(cbD->commands.get());
+ cmd.cmd = QVkCommandBuffer::Command::MemoryBarrier;
+ cmd.args.memoryBarrier.dependencyFlags = 0;
+ cmd.args.memoryBarrier.dstStageMask = writeBarrierDstStageMask;
+ cmd.args.memoryBarrier.srcStageMask = writeBarrierSrcStageMask;
+ cmd.args.memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
+ cmd.args.memoryBarrier.srcAccessMask = cmd.args.memoryBarrier.dstAccessMask;
+ }
+ }
+
// write descriptor sets, if needed
if (rewriteDescSet)
updateShaderResourceBindings(srb);
diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h
index 1e9318513fd..21044545ad2 100644
--- a/src/gui/rhi/qrhivulkan_p.h
+++ b/src/gui/rhi/qrhivulkan_p.h
@@ -425,7 +425,8 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
TransitionPassResources,
Dispatch,
ExecuteSecondary,
- SetShadingRate
+ SetShadingRate,
+ MemoryBarrier
};
Cmd cmd;
@@ -464,6 +465,13 @@ struct QVkCommandBuffer : public QRhiCommandBuffer
struct {
VkPipelineStageFlags srcStageMask;
VkPipelineStageFlags dstStageMask;
+ VkAccessFlags srcAccessMask;
+ VkAccessFlags dstAccessMask;
+ VkDependencyFlags dependencyFlags;
+ } memoryBarrier;
+ struct {
+ VkPipelineStageFlags srcStageMask;
+ VkPipelineStageFlags dstStageMask;
int count;
int index;
} bufferBarrier;
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 2b2f2a27fcd..17ed5fb7ed4 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -2170,6 +2170,7 @@ QString QFont::key() const
\li Style strategy
\li Font style
\li Font features
+ \li Variable axes
\endlist
\sa fromString()
@@ -2195,12 +2196,12 @@ QString QFont::toString() const
QString::number((int)styleStrategy()) + comma +
styleName();
- QMap<Tag, quint32> sortedFeatures;
+ fontDescription += comma + QString::number(d->features.size());
for (const auto &[tag, value] : std::as_const(d->features).asKeyValueRange())
- sortedFeatures.insert(tag, value);
+ fontDescription += comma + QLatin1StringView{tag.toString()} + u'=' + QString::number(value);
- fontDescription += comma + QString::number(sortedFeatures.size());
- for (const auto &[tag, value] : std::as_const(sortedFeatures).asKeyValueRange())
+ fontDescription += comma + QString::number(d->request.variableAxisValues.size());
+ for (const auto &[tag, value] : std::as_const(d->request.variableAxisValues).asKeyValueRange())
fontDescription += comma + QLatin1StringView{tag.toString()} + u'=' + QString::number(value);
return fontDescription;
@@ -2216,7 +2217,7 @@ size_t qHash(const QFont &font, size_t seed) noexcept
return qHash(QFontPrivate::get(font)->request, seed);
}
-static std::optional<std::pair<QFont::Tag, quint32>> tagAndValueFromString(QStringView view)
+static std::optional<std::pair<QFont::Tag, quint32>> fontFeatureFromString(QStringView view)
{
const int separator = view.indexOf(u'=');
if (separator == -1)
@@ -2234,6 +2235,24 @@ static std::optional<std::pair<QFont::Tag, quint32>> tagAndValueFromString(QStri
return std::make_pair(*tag, value);
}
+static std::optional<std::pair<QFont::Tag, float>> variableAxisFromString(QStringView view)
+{
+ const int separator = view.indexOf(u'=');
+ if (separator == -1)
+ return std::nullopt;
+
+ const std::optional<QFont::Tag> tag = QFont::Tag::fromString(view.sliced(0, separator));
+ if (!tag)
+ return std::nullopt;
+
+ bool valueOk = false;
+ const float value = view.sliced(separator + 1).toFloat(&valueOk);
+ if (!valueOk)
+ return std::nullopt;
+
+ return std::make_pair(*tag, value);
+}
+
/*!
Sets this font to match the description \a descrip. The description
is a comma-separated list of the font attributes, as returned by
@@ -2263,6 +2282,8 @@ bool QFont::fromString(const QString &descrip)
setUnderline(l[5].toInt());
setStrikeOut(l[6].toInt());
setFixedPitch(l[7].toInt());
+ if (!d->request.fixedPitch) // assume 'false' fixedPitch equals default
+ d->request.ignorePitch = true;
} else if (count >= 10) {
if (l[2].toInt() > 0)
setPixelSize(l[2].toInt());
@@ -2275,6 +2296,8 @@ bool QFont::fromString(const QString &descrip)
setUnderline(l[6].toInt());
setStrikeOut(l[7].toInt());
setFixedPitch(l[8].toInt());
+ if (!d->request.fixedPitch) // assume 'false' fixedPitch equals default
+ d->request.ignorePitch = true;
if (count >= 16) {
setCapitalization((Capitalization)l[10].toInt());
setLetterSpacing((SpacingType)l[11].toInt(), l[12].toDouble());
@@ -2291,19 +2314,33 @@ bool QFont::fromString(const QString &descrip)
d->request.styleName.clear();
clearFeatures();
- if (count >= 18) {
- const int featureCount = l[17].toInt();
- if (count >= featureCount + 18) {
- for (int i = 0; i < featureCount; ++i) {
- if (const auto feature = tagAndValueFromString(l[18 + i]))
- setFeature(feature->first, feature->second);
- }
- }
+ clearVariableAxes();
+
+ int position = 17;
+ if (position >= count)
+ return true;
+
+ const int featureCount = l[position++].toInt();
+ if (position + featureCount > count)
+ return true;
+
+ for (int i = 0; i < featureCount; ++i) {
+ if (const auto feature = fontFeatureFromString(l[position++]))
+ setFeature(feature->first, feature->second);
}
- }
- if (count >= 9 && !d->request.fixedPitch) // assume 'false' fixedPitch equals default
- d->request.ignorePitch = true;
+ if (position >= count)
+ return true;
+
+ const int variableAxisCount = l[position++].toInt();
+ if (position + variableAxisCount > count)
+ return true;
+
+ for (int i = 0; i < variableAxisCount; ++i) {
+ if (const auto axis = variableAxisFromString(l[position++]))
+ setVariableAxis(axis->first, axis->second);
+ }
+ }
return true;
}
diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h
index 27bc2a6a7cc..76ff29f6e91 100644
--- a/src/gui/text/qfont_p.h
+++ b/src/gui/text/qfont_p.h
@@ -192,7 +192,7 @@ public:
QFixed letterSpacing;
QFixed wordSpacing;
- QHash<QFont::Tag, quint32> features;
+ QMap<QFont::Tag, quint32> features;
mutable QFontPrivate *scFont;
QFont smallCapsFont() const { return QFont(smallCapsFontPrivate()); }
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 29fda652ef6..ede5409b112 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -1414,7 +1414,7 @@ void QTextEngine::shapeText(int item) const
#endif
bool letterSpacingIsAbsolute;
bool shapingEnabled = false;
- QHash<QFont::Tag, quint32> features;
+ QMap<QFont::Tag, quint32> features;
QFixed letterSpacing, wordSpacing;
#ifndef QT_NO_RAWFONT
if (useRawFont) {
@@ -1610,7 +1610,7 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st
int stringBaseIndex, int stringLength, int itemLength,
QFontEngine *fontEngine, QSpan<uint> itemBoundaries,
bool kerningEnabled, bool hasLetterSpacing,
- const QHash<QFont::Tag, quint32> &fontFeatures) const
+ const QMap<QFont::Tag, quint32> &fontFeatures) const
{
uint glyphs_shaped = 0;
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index e513fd598ba..f27463f7728 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -628,7 +628,7 @@ private:
int stringLength, int itemLength, QFontEngine *fontEngine,
QSpan<uint> itemBoundaries, bool kerningEnabled,
bool hasLetterSpacing,
- const QHash<QFont::Tag, quint32> &features) const;
+ const QMap<QFont::Tag, quint32> &features) const;
#endif
int endOfLine(int lineNum);
diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h
index 2fde9e4c9d5..37e960b19dc 100644
--- a/src/network/access/qhttp2protocolhandler_p.h
+++ b/src/network/access/qhttp2protocolhandler_p.h
@@ -93,7 +93,6 @@ private:
// Stream's lifecycle management:
QHttp2Stream *createNewStream(const HttpMessagePair &message, bool uploadDone = false);
void connectStream(const HttpMessagePair &message, QHttp2Stream *stream);
- quint32 popStreamToResume();
QHttp2Connection *h2Connection;
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 975332a14ab..eb95d891e42 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -1045,7 +1045,7 @@ void QAbstractSocketPrivate::_q_connectToNextAddress()
host = addresses.takeFirst();
#if defined(QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::_q_connectToNextAddress(), connecting to %s:%i, %d left to try",
- host.toString().toLatin1().constData(), port, addresses.count());
+ host.toString().toLatin1().constData(), port, int(addresses.count()));
#endif
if (cachedSocketDescriptor == -1 && !initSocketLayer(host.protocol())) {
@@ -1247,6 +1247,9 @@ void QAbstractSocketPrivate::emitReadyRead(int channel)
void QAbstractSocketPrivate::emitBytesWritten(qint64 bytes, int channel)
{
Q_Q(QAbstractSocket);
+
+ bytesWrittenEmissionCount++;
+
// Only emit bytesWritten() when not recursing.
if (!emittedBytesWritten && channel == currentWriteChannel) {
QScopedValueRollback<bool> r(emittedBytesWritten);
@@ -2265,6 +2268,8 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
if (d->writeBuffer.isEmpty())
return false;
+ const quint32 bwEmissionCountAtEntry = d->bytesWrittenEmissionCount;
+
QDeadlineTimer deadline{msecs};
// handle a socket in connecting state
@@ -2304,6 +2309,13 @@ bool QAbstractSocket::waitForBytesWritten(int msecs)
qDebug("QAbstractSocket::waitForBytesWritten returns true");
#endif
return true;
+ } else if (d->bytesWrittenEmissionCount != bwEmissionCountAtEntry) {
+ // A slot connected to any signal emitted by this method has written data, which
+ // fulfills the condition to return true that at least one byte has been written.
+#if defined (QABSTRACTSOCKET_DEBUG)
+ qDebug("QAbstractSocket::waitForBytesWritten returns true (write in signal handler)");
+#endif
+ return true;
}
}
diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h
index 5f33eddbc7b..5a0a6489e2e 100644
--- a/src/network/socket/qabstractsocket_p.h
+++ b/src/network/socket/qabstractsocket_p.h
@@ -117,6 +117,8 @@ public:
bool hasPendingData = false;
bool hasPendingDatagram = false;
+ quint32 bytesWrittenEmissionCount = 0;
+
QTimer *connectTimer = nullptr;
int hostLookupId = -1;
diff --git a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp
index 881a233e694..5b86c1e1725 100644
--- a/src/plugins/platforms/directfb/qdirectfbconvenience.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbconvenience.cpp
@@ -254,6 +254,7 @@ QDirectFbKeyMap::QDirectFbKeyMap()
insert(DIKS_FAVORITES , Qt::Key_Favorites);
insert(DIKS_KEYBOARD , Qt::Key_Keyboard);
insert(DIKS_PHONE , Qt::Key_Phone);
+ insert(DIKS_CALL , Qt::Key_Call)
insert(DIKS_PROGRAM , Qt::Key_Guide);
insert(DIKS_TIME , Qt::Key_Time);
diff --git a/src/plugins/platforms/wasm/qwasmdrag.cpp b/src/plugins/platforms/wasm/qwasmdrag.cpp
index 730816b9a99..1eed2acde53 100644
--- a/src/plugins/platforms/wasm/qwasmdrag.cpp
+++ b/src/plugins/platforms/wasm/qwasmdrag.cpp
@@ -16,6 +16,8 @@
#include <QtCore/qtimer.h>
#include <QFile>
+#include <private/qshapedpixmapdndwindow_p.h>
+
#include <functional>
#include <string>
#include <utility>
@@ -92,9 +94,8 @@ Qt::DropAction QWasmDrag::drag(QDrag *drag)
Qt::DropAction dragResult = Qt::IgnoreAction;
if (qstdweb::haveJspi()) {
- QEventLoop loop;
- m_dragState = std::make_unique<DragState>(drag, window, [&loop]() { loop.quit(); });
- loop.exec();
+ m_dragState = std::make_unique<DragState>(drag, window, [this]() { QSimpleDrag::cancelDrag(); });
+ QSimpleDrag::drag(drag);
dragResult = m_dragState->dropAction;
m_dragState.reset();
}
@@ -110,14 +111,16 @@ void QWasmDrag::onNativeDragStarted(DragEvent *event)
Q_ASSERT_X(event->type == EventType::DragStart, Q_FUNC_INFO,
"The event is not a DragStart event");
- event->webEvent.call<void>("preventDefault");
-
// It is possible for a drag start event to arrive from another window.
if (!m_dragState || m_dragState->window != event->targetWindow) {
event->cancelDragStart();
return;
}
+ // We have our own window
+ if (shapedPixmapWindow())
+ shapedPixmapWindow()->setVisible(false);
+
m_dragState->dragImage = std::make_unique<DragState::DragImage>(
m_dragState->drag->pixmap(), m_dragState->drag->mimeData(), event->targetWindow);
event->dataTransfer.setDragImage(m_dragState->dragImage->htmlElement(),
diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp
index 13682256370..6fd857828d3 100644
--- a/src/plugins/styles/modernwindows/qwindows11style.cpp
+++ b/src/plugins/styles/modernwindows/qwindows11style.cpp
@@ -87,34 +87,35 @@ inline ControlState calcControlState(const QStyleOption *option)
} // namespace StyleOptionHelper
-#define AcceptMedium u"\uF78C"_s
-// QStringLiteral(u"\uE73C")
-#define Dash12 u"\uE629"_s
-#define CheckMark u"\uE73E"_s
-
-#define CaretLeftSolid8 u"\uEDD9"_s
-#define CaretRightSolid8 u"\uEDDA"_s
-#define CaretUpSolid8 u"\uEDDB"_s
-#define CaretDownSolid8 u"\uEDDC"_s
-
-#define ChevronDown u"\uE70D"_s
-#define ChevronUp u"\uE70E"_s
-
-#define ChevronDownMed u"\uE972"_s
-#define ChevronLeftMed u"\uE973"_s
-#define ChevronRightMed u"\uE974"_s
-
-#define ChevronUpSmall u"\uE96D"_s
-#define ChevronDownSmall u"\uE96E"_s
-
-#define ChromeMinimize u"\uE921"_s
-#define ChromeMaximize u"\uE922"_s
-#define ChromeRestore u"\uE923"_s
-#define ChromeClose u"\uE8BB"_s
+enum class Icon : ushort
+{
+ AcceptMedium = 0xF78C,
+ Dash12 = 0xE629,
+ CheckMark = 0xE73E,
+ CaretLeftSolid8 = 0xEDD9,
+ CaretRightSolid8 = 0xEDDA,
+ CaretUpSolid8 = 0xEDDB,
+ CaretDownSolid8 = 0xEDDC,
+ ChevronDown = 0xE70D,
+ ChevronUp = 0xE70E,
+ ChevronDownMed = 0xE972,
+ ChevronLeftMed = 0xE973,
+ ChevronRightMed = 0xE974,
+ ChevronUpSmall = 0xE96D,
+ ChevronDownSmall = 0xE96E,
+ ChromeMinimize = 0xE921,
+ ChromeMaximize = 0xE922,
+ ChromeRestore = 0xE923,
+ ChromeClose = 0xE8BB,
+ More = 0xE712,
+ Help = 0xE897,
+ Clear = 0xE894,
+};
-#define More u"\uE712"_s
-#define Help u"\uE897"_s
-#define Clear u"\uE894"_s
+static inline QString fluentIcon(Icon i)
+{
+ return QChar(ushort(i));
+}
template <typename R, typename P, typename B>
static inline void drawRoundedRect(QPainter *p, R &&rect, P &&pen, B &&brush)
@@ -316,7 +317,7 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt
{
QWindows11StylePrivate *d = const_cast<QWindows11StylePrivate*>(d_func());
- const auto drawTitleBarButton = [&](ComplexControl control, SubControl sc, const QString &str) {
+ const auto drawTitleBarButton = [&](ComplexControl control, SubControl sc, Icon ico) {
using namespace StyleOptionHelper;
const QRect buttonRect = proxy()->subControlRect(control, option, sc, widget);
if (buttonRect.isValid()) {
@@ -324,10 +325,10 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt
if (hover)
painter->fillRect(buttonRect, winUI3Color(subtleHighlightColor));
painter->setPen(option->palette.color(QPalette::WindowText));
- painter->drawText(buttonRect, Qt::AlignCenter, str);
+ painter->drawText(buttonRect, Qt::AlignCenter, fluentIcon(ico));
}
};
- const auto drawTitleBarCloseButton = [&](ComplexControl control, SubControl sc, const QString &str) {
+ const auto drawTitleBarCloseButton = [&](ComplexControl control, SubControl sc, Icon ico) {
using namespace StyleOptionHelper;
const QRect buttonRect = proxy()->subControlRect(control, option, sc, widget);
if (buttonRect.isValid()) {
@@ -349,7 +350,7 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt
break;
}
painter->setPen(pen);
- painter->drawText(buttonRect, Qt::AlignCenter, str);
+ painter->drawText(buttonRect, Qt::AlignCenter, fluentIcon(ico));
}
};
@@ -416,18 +417,13 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt
sb, sb->rect.size());
if (cp.needsPainting()) {
const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
- drawRoundedRect(cp.painter(), frameRect, Qt::NoPen, option->palette.brush(QPalette::Base));
+ drawRoundedRect(cp.painter(), frameRect, Qt::NoPen, inputFillBrush(option, widget));
if (sb->frame && (sub & SC_SpinBoxFrame))
drawLineEditFrame(cp.painter(), frameRect, option);
- const bool isMouseOver = state & State_MouseOver;
- const bool hasFocus = state & State_HasFocus;
- const bool isEnabled = state & QStyle::State_Enabled;
- if (isEnabled && isMouseOver && !hasFocus && !highContrastTheme)
- drawRoundedRect(cp.painter(), frameRect, Qt::NoPen, winUI3Color(subtleHighlightColor));
-
const auto drawUpDown = [&](QStyle::SubControl sc) {
+ const bool isEnabled = state & QStyle::State_Enabled;
const bool isUp = sc == SC_SpinBoxUp;
const QRect rect = proxy()->subControlRect(CC_SpinBox, option, sc, widget);
if (isEnabled && sb->activeSubControls & sc)
@@ -437,7 +433,7 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt
cp->setFont(d->assetFont);
cp->setPen(sb->palette.buttonText().color());
cp->setBrush(Qt::NoBrush);
- cp->drawText(rect, Qt::AlignCenter, isUp ? ChevronUp : ChevronDown);
+ cp->drawText(rect, Qt::AlignCenter, fluentIcon(isUp ? Icon::ChevronUp : Icon::ChevronDown));
};
if (sub & SC_SpinBoxUp) drawUpDown(SC_SpinBoxUp);
if (sub & SC_SpinBoxDown) drawUpDown(SC_SpinBoxDown);
@@ -586,21 +582,22 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt
case CC_ComboBox:
if (const QStyleOptionComboBox *combobox = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
- drawRoundedRect(painter, frameRect, Qt::NoPen, option->palette.brush(QPalette::Base));
+ QStyleOption opt(*option);
+ opt.state.setFlag(QStyle::State_On, false);
+ drawRoundedRect(painter, frameRect, Qt::NoPen,
+ combobox->editable ? inputFillBrush(option, widget)
+ : controlFillBrush(&opt, ControlType::Control));
if (combobox->frame)
drawLineEditFrame(painter, frameRect, combobox, combobox->editable);
const bool hasFocus = state & State_HasFocus;
- QStyleOption opt(*option);
- opt.state.setFlag(QStyle::State_On, false);
- drawRoundedRect(painter, frameRect, Qt::NoPen, controlFillBrush(&opt, ControlType::Control));
if (sub & SC_ComboBoxArrow) {
- QRectF rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget).adjusted(4, 0, -4, 1);
+ QRectF rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
painter->setFont(d->assetFont);
painter->setPen(controlTextColor(option));
- painter->drawText(rect, Qt::AlignCenter, ChevronDownMed);
+ painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
}
if (state & State_KeyboardFocusChange && hasFocus) {
QStyleOptionFocusRect fropt;
@@ -662,9 +659,9 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt
f.setPointSize(6);
cp->setFont(f);
cp->setPen(Qt::gray);
- const auto str = vertical ? CaretDownSolid8
- : (isRtl ? CaretLeftSolid8 : CaretRightSolid8);
- cp->drawText(rect, Qt::AlignCenter, str);
+ const auto ico = vertical ? Icon::CaretDownSolid8
+ : (isRtl ? Icon::CaretLeftSolid8 : Icon::CaretRightSolid8);
+ cp->drawText(rect, Qt::AlignCenter, fluentIcon(ico));
}
}
if (sub & SC_ScrollBarSubLine) {
@@ -674,9 +671,9 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt
f.setPointSize(6);
cp->setFont(f);
cp->setPen(Qt::gray);
- const auto str = vertical ? CaretUpSolid8
- : (isRtl ? CaretRightSolid8 : CaretLeftSolid8);
- cp->drawText(rect, Qt::AlignCenter, str);
+ const auto ico = vertical ? Icon::CaretUpSolid8
+ : (isRtl ? Icon::CaretRightSolid8 : Icon::CaretLeftSolid8);
+ cp->drawText(rect, Qt::AlignCenter, fluentIcon(ico));
}
}
}
@@ -686,9 +683,9 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt
QFont buttonFont = QFont(d->assetFont);
buttonFont.setPointSize(8);
painter->setFont(buttonFont);
- drawTitleBarCloseButton(CC_MdiControls, SC_MdiCloseButton, ChromeClose);
- drawTitleBarButton(CC_MdiControls, SC_MdiNormalButton, ChromeRestore);
- drawTitleBarButton(CC_MdiControls, SC_MdiMinButton, ChromeMinimize);
+ drawTitleBarCloseButton(CC_MdiControls, SC_MdiCloseButton, Icon::ChromeClose);
+ drawTitleBarButton(CC_MdiControls, SC_MdiNormalButton, Icon::ChromeRestore);
+ drawTitleBarButton(CC_MdiControls, SC_MdiMinButton, Icon::ChromeMinimize);
}
break;
case CC_TitleBar:
@@ -716,18 +713,18 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt
// min button
if (shouldDrawButton(SC_TitleBarMinButton, Qt::WindowMinimizeButtonHint) &&
!(titlebar->titleBarState & Qt::WindowMinimized)) {
- drawTitleBarButton(CC_TitleBar, SC_TitleBarMinButton, ChromeMinimize);
+ drawTitleBarButton(CC_TitleBar, SC_TitleBarMinButton, Icon::ChromeMinimize);
}
// max button
if (shouldDrawButton(SC_TitleBarMaxButton, Qt::WindowMaximizeButtonHint) &&
!(titlebar->titleBarState & Qt::WindowMaximized)) {
- drawTitleBarButton(CC_TitleBar, SC_TitleBarMaxButton, ChromeMaximize);
+ drawTitleBarButton(CC_TitleBar, SC_TitleBarMaxButton, Icon::ChromeMaximize);
}
// close button
if (shouldDrawButton(SC_TitleBarCloseButton, Qt::WindowSystemMenuHint))
- drawTitleBarCloseButton(CC_TitleBar, SC_TitleBarCloseButton, ChromeClose);
+ drawTitleBarCloseButton(CC_TitleBar, SC_TitleBarCloseButton, Icon::ChromeClose);
// normalize button
if ((titlebar->subControls & SC_TitleBarNormalButton) &&
@@ -735,20 +732,20 @@ void QWindows11Style::drawComplexControl(ComplexControl control, const QStyleOpt
(titlebar->titleBarState & Qt::WindowMinimized)) ||
((titlebar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
(titlebar->titleBarState & Qt::WindowMaximized)))) {
- drawTitleBarButton(CC_TitleBar, SC_TitleBarNormalButton, ChromeRestore);
+ drawTitleBarButton(CC_TitleBar, SC_TitleBarNormalButton, Icon::ChromeRestore);
}
// context help button
if (shouldDrawButton(SC_TitleBarContextHelpButton, Qt::WindowContextHelpButtonHint))
- drawTitleBarButton(CC_TitleBar, SC_TitleBarContextHelpButton, Help);
+ drawTitleBarButton(CC_TitleBar, SC_TitleBarContextHelpButton, Icon::Help);
// shade button
if (shouldDrawButton(SC_TitleBarShadeButton, Qt::WindowShadeButtonHint))
- drawTitleBarButton(CC_TitleBar, SC_TitleBarShadeButton, ChevronUpSmall);
+ drawTitleBarButton(CC_TitleBar, SC_TitleBarShadeButton, Icon::ChevronUpSmall);
// unshade button
if (shouldDrawButton(SC_TitleBarUnshadeButton, Qt::WindowShadeButtonHint))
- drawTitleBarButton(CC_TitleBar, SC_TitleBarUnshadeButton, ChevronDownSmall);
+ drawTitleBarButton(CC_TitleBar, SC_TitleBarUnshadeButton, Icon::ChevronDownSmall);
// window icon for system menu
if (shouldDrawButton(SC_TitleBarSysMenu, Qt::WindowSystemMenuHint)) {
@@ -872,9 +869,9 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption
f.setPointSize(6);
painter->setFont(f);
painter->setPen(header->palette.text().color());
- painter->drawText(option->rect, Qt::AlignCenter,
- indicator == QStyleOptionHeader::SortUp ? ChevronDown
- : ChevronUp);
+ const auto ico = indicator == QStyleOptionHeader::SortUp ? Icon::ChevronDown
+ : Icon::ChevronUp;
+ painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
}
}
break;
@@ -892,8 +889,9 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption
painter->setFont(d->assetFont);
painter->setPen(controlTextColor(option, QPalette::Window));
qreal clipWidth = 1.0;
+ const QString str = fluentIcon(Icon::AcceptMedium);
QFontMetrics fm(d->assetFont);
- QRectF clipRect = fm.boundingRect(AcceptMedium);
+ QRectF clipRect = fm.boundingRect(str);
if (d->transitionsEnabled() && option->styleObject) {
QNumberStyleAnimation *animation = qobject_cast<QNumberStyleAnimation *>(
d->animation(option->styleObject));
@@ -904,13 +902,13 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption
clipRect.moveCenter(center);
clipRect.setLeft(rect.x() + (rect.width() - clipRect.width()) / 2.0 + 0.5);
clipRect.setWidth(clipWidth * clipRect.width());
- painter->drawText(clipRect, Qt::AlignVCenter | Qt::AlignLeft, AcceptMedium);
+ painter->drawText(clipRect, Qt::AlignVCenter | Qt::AlignLeft, str);
} else if (isPartial) {
QFont f(d->assetFont);
f.setPointSize(6);
painter->setFont(f);
painter->setPen(controlTextColor(option, QPalette::Window));
- painter->drawText(rect, Qt::AlignCenter, Dash12);
+ painter->drawText(rect, Qt::AlignCenter, fluentIcon(Icon::Dash12));
}
}
break;
@@ -923,8 +921,10 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption
painter->setFont(f);
painter->setPen(option->palette.color(isOpen ? QPalette::Active : QPalette::Disabled,
QPalette::WindowText));
- const auto str = isOpen ? ChevronDownMed : (isReverse ? ChevronLeftMed : ChevronRightMed);
- painter->drawText(option->rect, Qt::AlignCenter, str);
+ const auto ico = isOpen ? Icon::ChevronDownMed
+ : (isReverse ? Icon::ChevronLeftMed
+ : Icon::ChevronRightMed);
+ painter->drawText(option->rect, Qt::AlignCenter, fluentIcon(ico));
}
}
break;
@@ -995,10 +995,17 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption
}
case PE_PanelLineEdit:
if (const auto *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
- const auto frameRect = QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
- drawRoundedRect(painter, frameRect, Qt::NoPen, inputFillBrush(option, widget));
- if (panel->lineWidth > 0)
- proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
+ const bool isInSpinBox =
+ widget && qobject_cast<const QAbstractSpinBox *>(widget->parent()) != nullptr;
+ const bool isInComboBox =
+ widget && qobject_cast<const QComboBox *>(widget->parent()) != nullptr;
+ if (!isInSpinBox && !isInComboBox) {
+ const auto frameRect =
+ QRectF(option->rect).marginsRemoved(QMarginsF(1.5, 1.5, 1.5, 1.5));
+ drawRoundedRect(painter, frameRect, Qt::NoPen, inputFillBrush(option, widget));
+ if (panel->lineWidth > 0)
+ proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
+ }
}
break;
case PE_FrameLineEdit: {
@@ -1511,7 +1518,7 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
if (isEnabled)
penColor.setAlpha(percentToAlpha(60.63)); // fillColorTextSecondary
painter->setPen(penColor);
- painter->drawText(vindRect, Qt::AlignCenter, ChevronDownMed);
+ painter->drawText(vindRect, Qt::AlignCenter, fluentIcon(Icon::ChevronDownMed));
}
}
break;
@@ -1587,8 +1594,7 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
QPainterStateGuard psg(painter);
painter->setFont(d->assetFont);
painter->setPen(option->palette.text().color());
- const auto textToDraw = QStringLiteral(u"\uE73E");
- painter->drawText(vRect, Qt::AlignCenter, textToDraw);
+ painter->drawText(vRect, Qt::AlignCenter, fluentIcon(Icon::CheckMark));
}
if (menuitem->menuHasCheckableItems)
xOffset += checkMarkWidth + contentItemHMargin;
@@ -1669,8 +1675,8 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
QRect vSubMenuRect = visualMenuRect(submenuRect);
painter->setPen(option->palette.text().color());
const bool isReverse = option->direction == Qt::RightToLeft;
- const auto str = isReverse ? ChevronLeftMed : ChevronRightMed;
- painter->drawText(vSubMenuRect, Qt::AlignCenter, str);
+ const auto ico = isReverse ? Icon::ChevronLeftMed : Icon::ChevronRightMed;
+ painter->drawText(vSubMenuRect, Qt::AlignCenter, fluentIcon(ico));
}
}
break;
@@ -1936,32 +1942,31 @@ QRect QWindows11Style::subControlRect(ComplexControl control, const QStyleOption
#if QT_CONFIG(spinbox)
case CC_SpinBox:
if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
- QSize bs;
- int fw = spinbox->frame ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget) : 0;
- bs.setHeight(qMax(8, spinbox->rect.height() - fw));
- bs.setWidth(16);
- int y = fw + spinbox->rect.y();
- int x, lx, rx;
- x = spinbox->rect.x() + spinbox->rect.width() - fw - 2 * bs.width();
- lx = fw;
- rx = x - fw;
+ const bool hasButtons = spinbox->buttonSymbols != QAbstractSpinBox::NoButtons;
+ const int fw = spinbox->frame
+ ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget)
+ : 0;
+ const int buttonHeight = hasButtons
+ ? qMin(spinbox->rect.height() - 3 * fw, spinbox->fontMetrics.height() * 5 / 4)
+ : 0;
+ const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
+ const int textFieldLength = spinbox->rect.width() - 2 * fw - 2 * buttonSize.width();
+ const QPoint topLeft(spinbox->rect.topLeft() + QPoint(fw, fw));
switch (subControl) {
case SC_SpinBoxUp:
- if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
+ case SC_SpinBoxDown: {
+ if (!hasButtons)
return QRect();
- ret = QRect(x, y, bs.width(), bs.height());
- break;
- case SC_SpinBoxDown:
- if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
- return QRect();
- ret = QRect(x + bs.width(), y, bs.width(), bs.height());
+ const int yOfs = ((spinbox->rect.height() - 2 * fw) - buttonSize.height()) / 2;
+ ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
+ buttonSize.height());
+ if (subControl == SC_SpinBoxDown)
+ ret.moveRight(ret.right() + buttonSize.width());
break;
+ }
case SC_SpinBoxEditField:
- if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) {
- ret = QRect(lx, fw, spinbox->rect.width() - 2*fw, spinbox->rect.height() - 2*fw);
- } else {
- ret = QRect(lx, fw, rx, spinbox->rect.height() - 2*fw);
- }
+ ret = QRect(topLeft,
+ spinbox->rect.bottomRight() - QPoint(fw + 2 * buttonSize.width(), fw));
break;
case SC_SpinBoxFrame:
ret = spinbox->rect;
@@ -2076,16 +2081,37 @@ QRect QWindows11Style::subControlRect(ComplexControl control, const QStyleOption
break;
}
case CC_ComboBox: {
- if (subControl == SC_ComboBoxArrow) {
+ if (const auto *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
const auto indicatorWidth =
proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
- const int endX = option->rect.right() - contentHMargin - 2;
- const int startX = endX - indicatorWidth;
- const QRect rect(QPoint(startX, option->rect.top()),
- QPoint(endX, option->rect.bottom()));
- ret = visualRect(option->direction, option->rect, rect);
- } else {
- ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
+ switch (subControl) {
+ case SC_ComboBoxArrow: {
+ const int fw =
+ cb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget) : 0;
+ const int buttonHeight =
+ qMin(cb->rect.height() - 3 * fw, cb->fontMetrics.height() * 5 / 4);
+ const QSize buttonSize(buttonHeight * 6 / 5, buttonHeight);
+ const int textFieldLength = cb->rect.width() - 2 * fw - buttonSize.width();
+ const QPoint topLeft(cb->rect.topLeft() + QPoint(fw, fw));
+ const int yOfs = ((cb->rect.height() - 2 * fw) - buttonSize.height()) / 2;
+ ret = QRect(topLeft.x() + textFieldLength, topLeft.y() + yOfs, buttonSize.width(),
+ buttonSize.height());
+ ret = visualRect(option->direction, option->rect, ret);
+ break;
+ }
+ case SC_ComboBoxEditField: {
+ ret = option->rect;
+ if (cb->frame) {
+ const int fw = proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget);
+ ret = ret.marginsRemoved(QMargins(fw, fw, fw, fw));
+ }
+ ret.setWidth(ret.width() - indicatorWidth - contentHMargin * 2);
+ break;
+ }
+ default:
+ ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget);
+ break;
+ }
}
break;
}
@@ -2177,15 +2203,15 @@ QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *o
break;
#endif // QT_CONFIG(menu)
#if QT_CONFIG(spinbox)
- case QStyle::CT_SpinBox: {
+ case CT_SpinBox: {
if (const auto *spinBoxOpt = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
// Add button + frame widths
- const qreal dpi = QStyleHelper::dpi(option);
const bool hasButtons = (spinBoxOpt->buttonSymbols != QAbstractSpinBox::NoButtons);
const int margins = 8;
- const int buttonWidth = hasButtons ? qRound(QStyleHelper::dpiScaled(16, dpi)) : 0;
- const int frameWidth = spinBoxOpt->frame ? proxy()->pixelMetric(PM_SpinBoxFrameWidth,
- spinBoxOpt, widget) : 0;
+ const int buttonWidth = hasButtons ? 16 + contentItemHMargin : 0;
+ const int frameWidth = spinBoxOpt->frame
+ ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget)
+ : 0;
contentSize += QSize(2 * buttonWidth + 2 * frameWidth + 2 * margins, 2 * frameWidth);
}
@@ -2196,7 +2222,7 @@ QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *o
case CT_ComboBox:
if (const auto *comboBoxOpt = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget); // don't rely on QWindowsThemeData
- contentSize += QSize(4, 4); // default win11 style margins
+ contentSize += QSize(0, 4); // for the lineedit frame
if (comboBoxOpt->subControls & SC_ComboBoxArrow) {
const auto w = proxy()->pixelMetric(PM_MenuButtonIndicator, option, widget);
contentSize.rwidth() += w + contentItemHMargin;
@@ -2204,6 +2230,13 @@ QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *o
}
break;
#endif
+ case CT_LineEdit: {
+ if (qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ contentSize = QWindowsStyle::sizeFromContents(type, option, size, widget); // don't rely on QWindowsThemeData
+ contentSize += QSize(0, 4); // for the lineedit frame
+ }
+ break;
+ }
case CT_HeaderSection:
// windows vista does not honor the indicator (as it was drawn above the text, not on the
// side) so call QWindowsStyle::styleHint directly to get the correct size hint
@@ -2335,7 +2368,7 @@ int QWindows11Style::pixelMetric(PixelMetric metric, const QStyleOption *option,
QFont f(d->assetFont);
f.setPointSize(qRound(fontSize * 0.9f)); // a little bit smaller
QFontMetrics fm(f);
- const auto width = fm.horizontalAdvance(ChevronDownMed);
+ const auto width = fm.horizontalAdvance(fluentIcon(Icon::ChevronDownMed));
m_fontPoint2ChevronDownMedWidth.insert(fontSize, width);
res += width;
} else {
@@ -2346,6 +2379,8 @@ int QWindows11Style::pixelMetric(PixelMetric metric, const QStyleOption *option,
}
break;
}
+ case PM_ComboBoxFrameWidth:
+ case PM_SpinBoxFrameWidth:
case PM_DefaultFrameWidth:
res = 2;
break;
@@ -2601,7 +2636,7 @@ QIcon QWindows11Style::standardIcon(StandardPixmap standardIcon,
switch (standardIcon) {
case SP_LineEditClearButton: {
if (d->m_lineEditClearButton.isNull()) {
- auto e = new WinFontIconEngine(Clear, d->assetFont);
+ auto e = new WinFontIconEngine(fluentIcon(Icon::Clear), d->assetFont);
d->m_lineEditClearButton = QIcon(e);
}
return d->m_lineEditClearButton;
@@ -2609,7 +2644,7 @@ QIcon QWindows11Style::standardIcon(StandardPixmap standardIcon,
case SP_ToolBarHorizontalExtensionButton:
case SP_ToolBarVerticalExtensionButton: {
if (d->m_toolbarExtensionButton.isNull()) {
- auto e = new WinFontIconEngine(More, d->assetFont);
+ auto e = new WinFontIconEngine(fluentIcon(Icon::More), d->assetFont);
e->setScale(1.0);
d->m_toolbarExtensionButton = QIcon(e);
}
diff --git a/src/plugins/tls/schannel/qtls_schannel.cpp b/src/plugins/tls/schannel/qtls_schannel.cpp
index 667f2d8a6c3..1034e99b7e0 100644
--- a/src/plugins/tls/schannel/qtls_schannel.cpp
+++ b/src/plugins/tls/schannel/qtls_schannel.cpp
@@ -2267,14 +2267,19 @@ static void attachPrivateKeyToCertificate(const QSslCertificate &certificate,
}
const auto freeProvider = qScopeGuard([provider]() { NCryptFreeObject(provider); });
- const QString certName = certificate.subjectInfo(QSslCertificate::CommonName).front();
+ const QString certName = [certificate]() {
+ if (auto cn = certificate.subjectInfo(QSslCertificate::CommonName); !cn.isEmpty())
+ return cn.front();
+ return QString();
+ }();
QSpan<const QChar> nameSpan(certName);
NCryptBuffer nbuffer{ ULONG(nameSpan.size_bytes() + sizeof(char16_t)),
NCRYPTBUFFER_PKCS_KEY_NAME,
const_reinterpret_cast<void *>(nameSpan.data()) };
NCryptBufferDesc bufferDesc{ NCRYPTBUFFER_VERSION, 1, &nbuffer };
+ auto *bufferDescPtr = nameSpan.isEmpty() ? nullptr : &bufferDesc;
NCRYPT_KEY_HANDLE ncryptKey = 0;
- status = NCryptImportKey(provider, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, &bufferDesc, &ncryptKey,
+ status = NCryptImportKey(provider, 0, NCRYPT_PKCS8_PRIVATE_KEY_BLOB, bufferDescPtr, &ncryptKey,
PBYTE(buffer.data()), buffer.size(), 0);
if (status != SEC_E_OK) {
qCWarning(lcTlsBackendSchannel())
diff --git a/src/sql/doc/qtsql.qdocconf b/src/sql/doc/qtsql.qdocconf
index 2545bcf4050..03efa743957 100644
--- a/src/sql/doc/qtsql.qdocconf
+++ b/src/sql/doc/qtsql.qdocconf
@@ -58,3 +58,6 @@ manifestmeta.highlighted.names = \
# Enforce zero documentation warnings
warninglimit = 0
+
+# Report warnings for images without alt text
+reportmissingalttextforimages = true
diff --git a/src/sql/doc/src/sql-programming.qdoc b/src/sql/doc/src/sql-programming.qdoc
index 07daf942ac4..948baec6f38 100644
--- a/src/sql/doc/src/sql-programming.qdoc
+++ b/src/sql/doc/src/sql-programming.qdoc
@@ -419,7 +419,9 @@
\table
\row \li \inlineimage noforeignkeys.png
+ {Table showing city and country as numeric foreign key values}
\li \inlineimage foreignkeys.png
+ {Table showing city and country resolved to text strings}
\endtable
The screenshot on the left shows a plain QSqlTableModel in a
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
index f4fc96b867d..d43b6ec4fb2 100644
--- a/src/widgets/CMakeLists.txt
+++ b/src/widgets/CMakeLists.txt
@@ -339,12 +339,12 @@ set(qstyle_resource_fusion_files
"styles/images/fusion_closedock-32.png"
"styles/images/fusion_closedock-48.png"
"styles/images/fusion_closedock-64.png"
- "styles/images/fusion_normalizedockup_10.png"
+ "styles/images/fusion_normalizedockup-10.png"
"styles/images/fusion_normalizedockup-16.png"
- "styles/images/fusion_normalizedockup_20.png"
+ "styles/images/fusion_normalizedockup-20.png"
"styles/images/fusion_normalizedockup-32.png"
- "styles/images/fusion_normalizedockup_48.png"
- "styles/images/fusion_normalizedockup_64.png"
+ "styles/images/fusion_normalizedockup-48.png"
+ "styles/images/fusion_normalizedockup-64.png"
"styles/images/fusion_titlebar-min-10.png"
"styles/images/fusion_titlebar-min-16.png"
"styles/images/fusion_titlebar-min-20.png"
diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp
index d989feb7f91..fa17c94a23f 100644
--- a/src/widgets/kernel/qtooltip.cpp
+++ b/src/widgets/kernel/qtooltip.cpp
@@ -389,13 +389,16 @@ void QTipLabel::placeTip(const QPoint &pos, QWidget *w)
p += offset;
#if QT_CONFIG(wayland)
- create();
- if (auto waylandWindow = dynamic_cast<QNativeInterface::Private::QWaylandWindow*>(windowHandle()->handle())) {
- // based on the existing code below, by default position at 'p' stored at the bottom right of our rect
- // then flip to the other arbitrary 4x24 space if constrained
- const QRect controlGeometry(QRect(p.x() - 4, p.y() - 24, 4, 24));
- waylandWindow->setParentControlGeometry(controlGeometry);
- waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::ToolTip);
+ if (w) {
+ create();
+ if (auto waylandWindow = dynamic_cast<QNativeInterface::Private::QWaylandWindow*>(windowHandle()->handle())) {
+ // based on the existing code below, by default position at 'p' stored at the bottom right of our rect
+ // then flip to the other arbitrary 4x24 space if constrained
+ const QRect controlGeometry = QRect(p.x() - 4, p.y() - 24, 4, 24)
+ .translated(-w->window()->mapToGlobal(QPoint(0, 0)));
+ waylandWindow->setParentControlGeometry(controlGeometry);
+ waylandWindow->setExtendedWindowType(QNativeInterface::Private::QWaylandWindow::ToolTip);
+ }
}
#endif
diff --git a/src/widgets/styles/images/fusion_normalizedockup_10.png b/src/widgets/styles/images/fusion_normalizedockup-10.png
index 7516e4ee4f8..7516e4ee4f8 100644
--- a/src/widgets/styles/images/fusion_normalizedockup_10.png
+++ b/src/widgets/styles/images/fusion_normalizedockup-10.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_normalizedockup_20.png b/src/widgets/styles/images/fusion_normalizedockup-20.png
index 2bc9421d5ac..2bc9421d5ac 100644
--- a/src/widgets/styles/images/fusion_normalizedockup_20.png
+++ b/src/widgets/styles/images/fusion_normalizedockup-20.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_normalizedockup_48.png b/src/widgets/styles/images/fusion_normalizedockup-48.png
index 6c497abdded..6c497abdded 100644
--- a/src/widgets/styles/images/fusion_normalizedockup_48.png
+++ b/src/widgets/styles/images/fusion_normalizedockup-48.png
Binary files differ
diff --git a/src/widgets/styles/images/fusion_normalizedockup_64.png b/src/widgets/styles/images/fusion_normalizedockup-64.png
index 5ec620e5a04..5ec620e5a04 100644
--- a/src/widgets/styles/images/fusion_normalizedockup_64.png
+++ b/src/widgets/styles/images/fusion_normalizedockup-64.png
Binary files differ
diff --git a/tests/auto/corelib/itemmodels/qrangemodel/data.h b/tests/auto/corelib/itemmodels/qrangemodel/data.h
index bb4074e80f8..5015b8ab49e 100644
--- a/tests/auto/corelib/itemmodels/qrangemodel/data.h
+++ b/tests/auto/corelib/itemmodels/qrangemodel/data.h
@@ -145,6 +145,19 @@ private:
int m_number = -1;
};
+struct ObjectRow
+{
+ std::array<Object *, 5> m_objects = {};
+
+ template <std::size_t I> // read-only is enough for this
+ friend decltype(auto) get(const ObjectRow &row) { return row.m_objects[I]; }
+};
+
+namespace std {
+ template <> struct tuple_size<ObjectRow> : std::integral_constant<std::size_t, 5> {};
+ template <std::size_t I> struct tuple_element<I, ObjectRow> { using type = Object *; };
+}
+
// a class that can be both and requires disambiguation
class MetaObjectTuple : public QObject
{
diff --git a/tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp b/tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp
index 97122353ab3..1282049bb21 100644
--- a/tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp
+++ b/tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp
@@ -959,6 +959,29 @@ void tst_QRangeModel::autoConnectPolicy()
QCOMPARE(dataChangedSpy.at(0).at(1).value<QModelIndex>(), child01Index);
QCOMPARE(dataChangedSpy.at(0).at(2), QVariant::fromValue(QList{Qt::UserRole + 1}));
}();
+
+ // build tests
+ { // make sure we don't kill the compiler with recursive templates
+ QList<std::array<Object *, 1000000>> wideList;
+ QRangeModel model(wideList);
+ }
+
+ { // work with custom tuple types
+ QList<ObjectRow> objectRows;
+ QRangeModel model(objectRows);
+ }
+
+ { // correctly resolve optional children
+ struct Protocol {
+ ObjectRow *parentRow(const ObjectRow &) const { return nullptr; }
+ const auto &childRows(const ObjectRow &) const { return emptyRow; }
+
+ std::optional<std::vector<ObjectRow>> emptyRow = std::nullopt;
+ };
+ std::vector<ObjectRow> objectTree;
+ QRangeModel model(objectTree, Protocol{});
+ model.setAutoConnectPolicy(QRangeModel::AutoConnectPolicy::Full);
+ }
}
void tst_QRangeModel::dimensions()
diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
index b05a055252b..2fcfd056882 100644
--- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
+++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
@@ -56,7 +56,7 @@ CHECK_GET(MyVariant, const &&);
#include <QtGui/qtransform.h>
// QtCore:
-#include <QAssociativeIterable>
+#include <QMetaAssociation>
#include <QBitArray>
#include <QBuffer>
#include <QByteArrayList>
@@ -74,7 +74,7 @@ CHECK_GET(MyVariant, const &&);
#include <QQueue>
#include <QRegularExpression>
#include <QScopeGuard>
-#include <QSequentialIterable>
+#include <QMetaSequence>
#include <QSet>
#include <QStack>
#include <QTimeZone>
@@ -398,6 +398,7 @@ private slots:
void iterateAssociativeContainerElements() { runTestFunction(); }
void iterateContainerElements();
void emptyContainerInterface();
+ void modifyContainerElements();
void pairElements_data();
void pairElements() { runTestFunction(); }
@@ -5015,7 +5016,7 @@ struct KeyGetter<std::unordered_map<T, U> >
};
template<typename Iterator>
-void sortIterable(QSequentialIterable *iterable)
+void sortIterable(QMetaSequence::Iterable *iterable)
{
std::sort(Iterator(iterable->mutableBegin()), Iterator(iterable->mutableEnd()),
[&](const QVariant &a, const QVariant &b) {
@@ -5026,6 +5027,10 @@ void sortIterable(QSequentialIterable *iterable)
template<typename Container>
static void testSequentialIteration()
{
+ QFETCH(bool, hasSizeAccessor);
+ QFETCH(bool, hasIndexedAccessors);
+ QTest::failOnWarning();
+
int numSeen = 0;
Container sequence;
ContainerAPI<Container>::insert(sequence, 1);
@@ -5036,15 +5041,17 @@ static void testSequentialIteration()
QVERIFY(listVariant.canConvert<QVariantList>());
QVariantList varList = listVariant.value<QVariantList>();
QCOMPARE(varList.size(), (int)std::distance(sequence.begin(), sequence.end()));
- QSequentialIterable listIter = listVariant.view<QSequentialIterable>();
- QCOMPARE(varList.size(), listIter.size());
+ QMetaSequence::Iterable listIter = listVariant.view<QMetaSequence::Iterable>();
+ if (hasSizeAccessor)
+ QCOMPARE(listIter.size(), varList.size());
typename Container::iterator containerIter = sequence.begin();
const typename Container::iterator containerEnd = sequence.end();
- for (int i = 0; i < listIter.size(); ++i, ++containerIter, ++numSeen)
+ for (int i = 0, end = varList.size(); i < end; ++i, ++containerIter, ++numSeen)
{
- QVERIFY(ContainerAPI<Container >::compare(listIter.at(i), *containerIter));
- QVERIFY(ContainerAPI<Container >::compare(listIter.at(i), varList.at(i)));
+ QVERIFY(ContainerAPI<Container>::compare(*containerIter, varList.at(i)));
+ if (hasIndexedAccessors)
+ QVERIFY(ContainerAPI<Container>::compare(listIter.at(i), varList.at(i)));
}
QCOMPARE(numSeen, (int)std::distance(sequence.begin(), sequence.end()));
QCOMPARE(containerIter, containerEnd);
@@ -5059,9 +5066,8 @@ static void testSequentialIteration()
}
QCOMPARE(numSeen, (int)std::distance(sequence.begin(), sequence.end()));
- auto compareLists = [&]() {
+ auto compareLists = [&](const QVariantList &varList) {
int numSeen = 0;
- auto varList = listVariant.value<QVariantList>();
auto varIter = varList.begin();
for (const QVariant &v : std::as_const(listIter)) {
QVERIFY(ContainerAPI<Container>::compare(v, *varIter));
@@ -5077,49 +5083,53 @@ static void testSequentialIteration()
++numSeen;
}
QCOMPARE(numSeen, (int)std::distance(varList.begin(), varList.end()));
+
+ if (hasSizeAccessor)
+ QCOMPARE(listIter.size(), varList.size());
+
+ if (!hasIndexedAccessors)
+ return;
+
+ for (qsizetype i = 0, end = varList.size(); i < end; ++i)
+ QCOMPARE(listIter.at(i), varList.at(i));
};
- compareLists();
+ compareLists(varList);
+
+ QVariant first = varList.at(0);
+ QVariant second = varList.at(1);
+ QVariant third = varList.at(2);
+ QCOMPARE(varList.size(), 3);
+ compareLists(varList);
+
+ listIter.metaContainer().addValue(listIter.mutableIterable(), third.constData());
+ varList = listVariant.value<QVariantList>();
+ QCOMPARE(varList.size(), 4);
+ compareLists(varList);
- QVariant first = listIter.at(0);
- QVariant second = listIter.at(1);
- QVariant third = listIter.at(2);
- compareLists();
- listIter.addValue(third);
- compareLists();
- listIter.addValue(second);
- compareLists();
- listIter.addValue(first);
- compareLists();
+ listIter.metaContainer().addValue(listIter.mutableIterable(), second.constData());
+ varList = listVariant.value<QVariantList>();
+ QCOMPARE(varList.size(), 5);
+ compareLists(varList);
- QCOMPARE(listIter.size(), 6);
+ listIter.metaContainer().addValue(listIter.mutableIterable(), first.constData());
+ varList = listVariant.value<QVariantList>();
+ QCOMPARE(varList.size(), 6);
+ compareLists(varList);
if (listIter.canRandomAccessIterate())
- sortIterable<QSequentialIterable::RandomAccessIterator>(&listIter);
+ sortIterable<QMetaSequence::Iterable::RandomAccessIterator>(&listIter);
else if (listIter.canReverseIterate())
- sortIterable<QSequentialIterable::BidirectionalIterator>(&listIter);
+ sortIterable<QMetaSequence::Iterable::BidirectionalIterator>(&listIter);
else if (listIter.canForwardIterate())
return; // std::sort cannot sort with only forward iterators.
else
QFAIL("The container has no meaningful iterators");
- compareLists();
- QCOMPARE(listIter.size(), 6);
- QCOMPARE(listIter.at(0), first);
- QCOMPARE(listIter.at(1), first);
- QCOMPARE(listIter.at(2), second);
- QCOMPARE(listIter.at(3), second);
- QCOMPARE(listIter.at(4), third);
- QCOMPARE(listIter.at(5), third);
-
- if (listIter.metaContainer().canRemoveValue()) {
- listIter.removeValue();
- compareLists();
- QCOMPARE(listIter.size(), 5);
- QCOMPARE(listIter.at(0), first);
- QCOMPARE(listIter.at(1), first);
- QCOMPARE(listIter.at(2), second);
- QCOMPARE(listIter.at(3), second);
- QCOMPARE(listIter.at(4), third);
+ compareLists({first, first, second, second, third, third});
+
+ if (listIter.metaContainer().canRemoveValueAtEnd()) {
+ listIter.removeLast();
+ compareLists({first, first, second, second, third});
} else {
// QString and QByteArray have no pop_back or pop_front and it's unclear what other
// method we should use to remove an item.
@@ -5130,16 +5140,20 @@ static void testSequentialIteration()
QVERIFY(i != listIter.mutableEnd());
*i = QStringLiteral("17");
+ QVariant at0 = hasIndexedAccessors ? listIter.at(0) : *listIter.constBegin();
+
if (listIter.metaContainer().valueMetaType() == QMetaType::fromType<int>())
- QCOMPARE(listIter.at(0).toInt(), 17);
+ QCOMPARE(at0.toInt(), 17);
else if (listIter.metaContainer().valueMetaType() == QMetaType::fromType<bool>())
- QCOMPARE(listIter.at(0).toBool(), false);
+ QCOMPARE(at0.toBool(), false);
*i = QStringLiteral("true");
+ at0 = hasIndexedAccessors ? listIter.at(0) : *listIter.constBegin();
+
if (listIter.metaContainer().valueMetaType() == QMetaType::fromType<int>())
- QCOMPARE(listIter.at(0).toInt(), 0);
+ QCOMPARE(at0.toInt(), 0);
else if (listIter.metaContainer().valueMetaType() == QMetaType::fromType<bool>())
- QCOMPARE(listIter.at(0).toBool(), true);
+ QCOMPARE(at0.toBool(), true);
}
template<typename Container>
@@ -5156,7 +5170,7 @@ static void testAssociativeIteration()
QVariant mappingVariant = QVariant::fromValue(mapping);
QVariantMap varMap = mappingVariant.value<QVariantMap>();
QVariantMap varHash = mappingVariant.value<QVariantMap>();
- QAssociativeIterable mappingIter = mappingVariant.view<QAssociativeIterable>();
+ QMetaAssociation::Iterable mappingIter = mappingVariant.view<QMetaAssociation::Iterable>();
typename Container::const_iterator containerIter = mapping.begin();
const typename Container::const_iterator containerEnd = mapping.end();
@@ -5168,7 +5182,7 @@ static void testAssociativeIteration()
QCOMPARE(qvariant_cast<Mapped>(varMap.value(QString::number(key))), expected);
QCOMPARE(qvariant_cast<Mapped>(varHash.value(QString::number(key))), expected);
QCOMPARE(actual, expected);
- const QAssociativeIterable::const_iterator it = mappingIter.find(key);
+ const QMetaAssociation::Iterable::const_iterator it = mappingIter.find(key);
QVERIFY(it != mappingIter.end());
QCOMPARE(it.value().value<Mapped>(), expected);
}
@@ -5209,7 +5223,7 @@ static void testAssociativeIteration()
container[0] = true;
QVariant containerVariant = QVariant::fromValue(container);
- QAssociativeIterable iter = containerVariant.value<QAssociativeIterable>();
+ QMetaAssociation::Iterable iter = containerVariant.value<QMetaAssociation::Iterable>();
auto f = iter.constFind(QStringLiteral("anything"));
QCOMPARE(f, iter.constEnd());
}
@@ -5217,7 +5231,9 @@ static void testAssociativeIteration()
void tst_QVariant::iterateSequentialContainerElements_data()
{
QTest::addColumn<QFunctionPointer>("testFunction");
-#define ADD(T) QTest::newRow(#T) << &testSequentialIteration<T>
+ QTest::addColumn<bool>("hasSizeAccessor");
+ QTest::addColumn<bool>("hasIndexedAccessors");
+#define ADD(T) QTest::newRow(#T) << &testSequentialIteration<T> << true << true
ADD(QQueue<int>);
ADD(QQueue<QVariant>);
ADD(QQueue<QString>);
@@ -5231,14 +5247,19 @@ void tst_QVariant::iterateSequentialContainerElements_data()
ADD(std::vector<int>);
ADD(std::vector<QVariant>);
ADD(std::vector<QString>);
- ADD(std::list<int>);
- ADD(std::list<QVariant>);
- ADD(std::list<QString>);
ADD(QStringList);
ADD(QByteArrayList);
ADD(QString);
ADD(QByteArray);
+#undef ADD
+#define ADD(T) QTest::newRow(#T) << &testSequentialIteration<T> << true << false
+ ADD(std::list<int>);
+ ADD(std::list<QVariant>);
+ ADD(std::list<QString>);
+
+#undef ADD
+#define ADD(T) QTest::newRow(#T) << &testSequentialIteration<T> << false << false
#ifdef TEST_FORWARD_LIST
ADD(std::forward_list<int>);
ADD(std::forward_list<QVariant>);
@@ -5265,12 +5286,16 @@ void tst_QVariant::iterateContainerElements()
QVariantList ints;
ints << 1 << 2 << 3;
QVariant var = QVariant::fromValue(ints);
- QSequentialIterable iter = var.value<QSequentialIterable>();
- QSequentialIterable::const_iterator it = iter.begin();
- QSequentialIterable::const_iterator end = iter.end();
+ QMetaSequence::Iterable iter = var.value<QMetaSequence::Iterable>();
+ QMetaSequence::Iterable::const_iterator it = iter.begin();
+ QMetaSequence::Iterable::const_iterator end = iter.end();
QCOMPARE(ints.at(1), *(it + 1));
- int i = 0;
- for ( ; it != end; ++it, ++i) {
+
+ for (int i = 0, end = ints.size(); i != end; ++i) {
+ QCOMPARE(ints.at(i), it[i]);
+ }
+
+ for (int i = 0; it != end; ++it, ++i) {
QCOMPARE(ints.at(i), *it);
}
@@ -5289,12 +5314,12 @@ void tst_QVariant::iterateContainerElements()
mapping.insert(2, "two");
mapping.insert(3, "three");
QVariant var = QVariant::fromValue(mapping);
- QAssociativeIterable iter = var.value<QAssociativeIterable>();
- QAssociativeIterable::const_iterator it = iter.begin();
- QAssociativeIterable::const_iterator end = iter.end();
+ QMetaAssociation::Iterable iter = var.value<QMetaAssociation::Iterable>();
+ QMetaAssociation::Iterable::const_iterator it = iter.begin();
+ QMetaAssociation::Iterable::const_iterator end = iter.end();
QCOMPARE(*(++mapping.begin()), (*(it + 1)).toString());
- int i = 0;
- for ( ; it != end; ++it, ++i) {
+
+ for (int i = 0; it != end; ++it, ++i) {
QCOMPARE(*(std::next(mapping.begin(), i)), (*it).toString());
}
@@ -5316,7 +5341,7 @@ void tst_QVariant::iterateContainerElements()
container["one"] = 1;
auto containerVariant = QVariant::fromValue(container);
- auto iter = containerVariant.value<QAssociativeIterable>();
+ auto iter = containerVariant.value<QMetaAssociation::Iterable>();
auto value = iter.value("one");
QCOMPARE(value, QVariant(1));
@@ -5345,6 +5370,72 @@ void tst_QVariant::emptyContainerInterface()
QCOMPARE(mutableEnd - mutableBegin, 0);
}
+void tst_QVariant::modifyContainerElements()
+{
+ {
+ QList<int> ints({1, 2, 3});
+ QMetaSequence::Iterable iter;
+ QVERIFY(QMetaType::view(
+ QMetaType::fromType<QList<int>>(), &ints,
+ QMetaType::fromType<QMetaSequence::Iterable>(), &iter));
+ QMetaSequence::Iterable::iterator it = iter.mutableBegin();
+ QMetaSequence::Iterable::iterator end = iter.mutableEnd();
+
+ *(it + 1) = 4;
+ QCOMPARE(ints.at(1), 4);
+
+ for (int i = 0, end = ints.size(); i != end; ++i) {
+ it[i] = i + 10;
+ QCOMPARE(ints.at(i), i + 10);
+ }
+
+ for (int i = 0; it != end; ++it, ++i) {
+ *it = i + 20;
+ QCOMPARE(ints.at(i), i + 20);
+ }
+
+ it = iter.mutableBegin();
+ QCOMPARE(it[0], QVariant(20));
+ QCOMPARE(it[1], QVariant(21));
+ QCOMPARE(it[2], QVariant(22));
+ }
+
+ {
+ QMap<int, QString> mapping({ {1, "one"}, {2, "two"}, {3, "three"} });
+ QMetaAssociation::Iterable iter;
+ QVERIFY(QMetaType::view(
+ QMetaType::fromType<QMap<int, QString>>(), &mapping,
+ QMetaType::fromType<QMetaAssociation::Iterable>(), &iter));
+ QMetaAssociation::Iterable::iterator it = iter.mutableBegin();
+ QMetaAssociation::Iterable::iterator end = iter.mutableEnd();
+ *(it + 1) = QStringLiteral("four");
+ QCOMPARE(*(++mapping.begin()), "four");
+
+ for (int i = 0; it != end; ++it, ++i) {
+ *it = QString::number(i + 10);
+ QCOMPARE(*std::next(mapping.begin(), i), QString::number(i + 10));
+ }
+
+ it = iter.mutableBegin();
+ *(it++) = "one";
+ *(it++) = "two";
+ *(it++) = "three";
+
+ QCOMPARE(mapping, (QMap<int, QString>({ {1, "one"}, {2, "two"}, {3, "three"} })));
+ }
+
+ {
+ QVariantMap container({{"one", 1}});
+ QMetaAssociation::Iterable iter;
+ QMetaType::view(
+ QMetaType::fromType<QVariantMap>(), &container,
+ QMetaType::fromType<QMetaAssociation::Iterable>(), &iter);
+ iter.setValue("one", 5);
+ const auto f = iter.constFind("one");
+ QCOMPARE(*f, QVariant(5));
+ }
+}
+
template <typename Pair> static void testVariantPairElements()
{
QFETCH(std::function<void(void *)>, makeValue);
@@ -5602,9 +5693,9 @@ void tst_QVariant::accessSequentialContainerKey()
QVariant variant = QVariant::fromValue(mapping);
- QAssociativeIterable iterable = variant.value<QAssociativeIterable>();
- QAssociativeIterable::const_iterator iit = iterable.begin();
- const QAssociativeIterable::const_iterator end = iterable.end();
+ QMetaAssociation::Iterable iterable = variant.value<QMetaAssociation::Iterable>();
+ QMetaAssociation::Iterable::const_iterator iit = iterable.begin();
+ const QMetaAssociation::Iterable::const_iterator end = iterable.end();
for ( ; iit != end; ++iit) {
nameResult += iit.key().toString();
}
@@ -5651,7 +5742,7 @@ void tst_QVariant::shouldDeleteVariantDataWorksForSequential()
};
metaSequence.valueMetaType = QtPrivate::qMetaTypeInterfaceForType<MyType>();
- QSequentialIterable iterable(QMetaSequence(&metaSequence), nullptr);
+ QMetaSequence::Iterable iterable(QMetaSequence(&metaSequence), nullptr);
QVariant value1 = iterable.at(0);
QVERIFY(value1.canConvert<MyType>());
QCOMPARE(value1.value<MyType>().number, 1);
@@ -5673,21 +5764,26 @@ void tst_QVariant::shouldDeleteVariantDataWorksForAssociative()
iterator.keyMetaType = QtPrivate::qMetaTypeInterfaceForType<MyType>();
iterator.createConstIteratorFn = [](
const void *, QtMetaContainerPrivate::QMetaContainerInterface::Position) -> void * {
- return nullptr;
+ return new int(21);
};
iterator.advanceConstIteratorFn = [](void *, qsizetype) {};
- iterator.destroyConstIteratorFn = [](const void *){};
- iterator.compareConstIteratorFn = [](const void *, const void *) {
- return true; /*all iterators are nullptr*/
+ iterator.destroyConstIteratorFn = [](const void *it) {
+ delete static_cast<const int *>(it);
+ };
+ iterator.compareConstIteratorFn = [](const void *a, const void *b) {
+ return *static_cast<const int *>(a) == *static_cast<const int *>(b);
};
+
iterator.createConstIteratorAtKeyFn = [](const void *, const void *) -> void * {
- return reinterpret_cast<void *>(quintptr(42));
+ return new int(42);
+ };
+ iterator.copyConstIteratorFn = [](void *a, const void *b) {
+ *static_cast<int *>(a) = *static_cast<const int *>(b);
};
- iterator.copyConstIteratorFn = [](void *, const void *) {};
iterator.diffConstIteratorFn = [](const void *, const void *) -> qsizetype { return 0; };
iterator.keyAtConstIteratorFn = [](const void *iterator, void *dataPtr) -> void {
MyType mytype {1, "key"};
- if (reinterpret_cast<quintptr>(iterator) == 42) {
+ if (*static_cast<const int *>(iterator) == 42) {
mytype.number = 42;
mytype.text = "find_key";
}
@@ -5695,13 +5791,13 @@ void tst_QVariant::shouldDeleteVariantDataWorksForAssociative()
};
iterator.mappedAtConstIteratorFn = [](const void *iterator, void *dataPtr) -> void {
MyType mytype {2, "value"};
- if (reinterpret_cast<quintptr>(iterator) == 42) {
+ if (*static_cast<const int *>(iterator) == 42) {
mytype.number = 42;
mytype.text = "find_value";
}
*static_cast<MyType *>(dataPtr) = mytype;
};
- QAssociativeIterable iterable(QMetaAssociation(&iterator), nullptr);
+ QMetaAssociation::Iterable iterable(QMetaAssociation(&iterator), nullptr);
auto it = iterable.begin();
QVariant value1 = it.key();
QVERIFY(value1.canConvert<MyType>());
@@ -5834,8 +5930,8 @@ void tst_QVariant::sequentialIterableAppend()
{
QList<int> container { 1, 2 };
auto variant = QVariant::fromValue(container);
- QVERIFY(variant.canConvert<QSequentialIterable>());
- QSequentialIterable asIterable = variant.view<QSequentialIterable>();
+ QVERIFY(variant.canConvert<QMetaSequence::Iterable>());
+ QMetaSequence::Iterable asIterable = variant.view<QMetaSequence::Iterable>();
const int i = 3, j = 4;
void *mutableIterable = asIterable.mutableIterable();
asIterable.metaContainer().addValueAtEnd(mutableIterable, &i);
@@ -5854,8 +5950,8 @@ void tst_QVariant::sequentialIterableAppend()
{
QSet<QByteArray> container { QByteArray{"hello"}, QByteArray{"world"} };
auto variant = QVariant::fromValue(std::move(container));
- QVERIFY(variant.canConvert<QSequentialIterable>());
- QSequentialIterable asIterable = variant.view<QSequentialIterable>();
+ QVERIFY(variant.canConvert<QMetaSequence::Iterable>());
+ QMetaSequence::Iterable asIterable = variant.view<QMetaSequence::Iterable>();
QByteArray qba1 {"goodbye"};
QByteArray qba2 { "moon" };
void *mutableIterable = asIterable.mutableIterable();
@@ -5875,15 +5971,15 @@ void tst_QVariant::preferDirectConversionOverInterfaces()
static bool calledCorrectConverter = false;
calledCorrectConverter = false;
- QMetaType::registerConverter<MyType, QSequentialIterable>([](const MyType &) {
- return QSequentialIterable {};
+ QMetaType::registerConverter<MyType, QMetaSequence::Iterable>([](const MyType &) {
+ return QMetaSequence::Iterable {};
});
QMetaType::registerConverter<MyType, QVariantList>([&](const MyType &) {
calledCorrectConverter = true;
return QVariantList {};
});
- QMetaType::registerConverter<MyType, QAssociativeIterable>([](const MyType &) {
- return QAssociativeIterable {};
+ QMetaType::registerConverter<MyType, QMetaAssociation::Iterable>([](const MyType &) {
+ return QMetaAssociation::Iterable {};
});
QMetaType::registerConverter<MyType, QVariantHash>([&](const MyType &) {
calledCorrectConverter = true;
@@ -5895,9 +5991,9 @@ void tst_QVariant::preferDirectConversionOverInterfaces()
});
auto holder = QVariant::fromValue(MyType {});
- QVERIFY(holder.canConvert<QSequentialIterable>());
+ QVERIFY(holder.canConvert<QMetaSequence::Iterable>());
QVERIFY(holder.canConvert<QVariantList>());
- QVERIFY(holder.canConvert<QAssociativeIterable>());
+ QVERIFY(holder.canConvert<QMetaAssociation::Iterable>());
QVERIFY(holder.canConvert<QVariantHash>());
QVERIFY(holder.canConvert<QVariantMap>());
diff --git a/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp b/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp
index ff78d1a1d1f..0ca09ed0ba2 100644
--- a/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp
+++ b/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp
@@ -359,7 +359,7 @@ void tst_QGuiVariant::toString_data()
#endif
QFont font( "times", 12 );
- QTest::newRow("qfont") << QVariant::fromValue(font) << QString("times,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,,0");
+ QTest::newRow("qfont") << QVariant::fromValue(font) << QString("times,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,,0,0");
QTest::newRow( "qcolor" ) << QVariant::fromValue( QColor( 10, 10, 10 ) ) << QString( "#0a0a0a" );
}
diff --git a/tests/auto/gui/text/qfont/tst_qfont.cpp b/tests/auto/gui/text/qfont/tst_qfont.cpp
index 8c4b8c75a26..9771071a749 100644
--- a/tests/auto/gui/text/qfont/tst_qfont.cpp
+++ b/tests/auto/gui/text/qfont/tst_qfont.cpp
@@ -53,7 +53,7 @@ private slots:
void fromStringCompatibility_data();
void fromStringCompatibility();
void fromStringWithoutStyleName();
- void fromStringWithoutFeatures();
+ void fromStringWithoutFeaturesOrVariableAxes();
void fromDegenerateString_data();
void fromDegenerateString();
@@ -672,12 +672,22 @@ void tst_QFont::fromStringCompatibility_data()
QTest::addRow("Times New Roman, Qt 6.0") << false << QStringLiteral("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2,Regular") << fontFrom60;
QFont fontFrom611 = fontFrom60;
- QTest::addRow("Times New Roman, Qt 6.11") << true << QStringLiteral("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2,Regular,0") << fontFrom611;
+ QTest::addRow("Times New Roman (without font features and variable axes), Qt 6.11") << true << QStringLiteral("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2,Regular,0,0") << fontFrom611;
QFont fontFrom611WithFeatures = fontFrom60;
fontFrom611WithFeatures.setFeature("frac", 1);
fontFrom611WithFeatures.setFeature("liga", 0);
- QTest::addRow("Times New Roman (with features), Qt 6.11") << true << QStringLiteral("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2,Regular,2,frac=1,liga=0") << fontFrom611WithFeatures;
+ QTest::addRow("Times New Roman (with features), Qt 6.11") << true << QStringLiteral("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2,Regular,2,frac=1,liga=0,0") << fontFrom611WithFeatures;
+
+ QFont fontFrom611WithVariableAxes = fontFrom60;
+ fontFrom611WithVariableAxes.setVariableAxis("wght", 12.34f);
+ QTest::addRow("Times New Roman (with variable axes), Qt 6.11") << true << QStringLiteral("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2,Regular,0,1,wght=12.34") << fontFrom611WithVariableAxes;
+
+ QFont fontFrom611WithFontFeaturesAndVariableAxes = fontFrom60;
+ fontFrom611WithFontFeaturesAndVariableAxes.setFeature("frac", 1);
+ fontFrom611WithFontFeaturesAndVariableAxes.setFeature("liga", 0);
+ fontFrom611WithFontFeaturesAndVariableAxes.setVariableAxis("wght", 12.34f);
+ QTest::addRow("Times New Roman (with font features and variable axes), Qt 6.11") << true << QStringLiteral("Times New Roman,18,-1,5,700,1,0,0,1,0,1,0,150.5,2.5,50,2,Regular,2,frac=1,liga=0,1,wght=12.34") << fontFrom611WithFontFeaturesAndVariableAxes;
}
void tst_QFont::fromStringCompatibility()
@@ -745,17 +755,46 @@ void tst_QFont::fromStringWithoutStyleName()
}
}
-void tst_QFont::fromStringWithoutFeatures()
+void tst_QFont::fromStringWithoutFeaturesOrVariableAxes()
{
- // This test verifies that the font feature list will be reset if the from string contains no features.
+ // This test verifies that the font feature and the variable axis list will be reset if the string
+ // contains no features or variable axes, respectively.
- const QString fontStringWithoutFeatures = QStringLiteral("Noto Sans,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1");
+ const QString fontStringWithoutFeaturesAndVariableAxes = QStringLiteral("Noto Sans,12,-1,5,400,0,0,0,0,0,0,0,0,0,0,1");
const QString fontStringWithFeatures = QStringLiteral("Noto Sans,18,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,,2,calt=0,frac=1");
+ const QString fontStringWithVariableAxes = QStringLiteral("Noto Sans,18,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,,0,1,wght=12.34");
- QFont font;
- font.fromString(fontStringWithFeatures);
- font.fromString(fontStringWithoutFeatures);
- QVERIFY(font.featureTags().isEmpty());
+ {
+ QFont font;
+ font.fromString(fontStringWithFeatures);
+ font.fromString(fontStringWithoutFeaturesAndVariableAxes);
+ QVERIFY(font.featureTags().isEmpty());
+ QVERIFY(font.variableAxisTags().isEmpty());
+ }
+
+ {
+ QFont font;
+ font.fromString(fontStringWithVariableAxes);
+ font.fromString(fontStringWithoutFeaturesAndVariableAxes);
+ QVERIFY(font.featureTags().isEmpty());
+ QVERIFY(font.variableAxisTags().isEmpty());
+ }
+
+ {
+ QFont font;
+ font.fromString(fontStringWithFeatures);
+ font.fromString(fontStringWithVariableAxes);
+ QVERIFY(font.featureTags().isEmpty());
+ QVERIFY(!font.variableAxisTags().isEmpty());
+ }
+
+ {
+ QFont font;
+ font.fromString(fontStringWithVariableAxes);
+ font.fromString(fontStringWithFeatures);
+ QVERIFY(!font.featureTags().isEmpty());
+ QVERIFY(font.variableAxisTags().isEmpty());
+ }
}
void tst_QFont::fromDegenerateString_data()
diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
index 2814045bfbf..f21fb37f0e0 100644
--- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
+++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
@@ -128,6 +128,7 @@ private slots:
void readChunks();
void waitForBytesWritten();
void waitForBytesWrittenMinusOne();
+ void waitForBytesWrittenWriteInReadyReadSlot();
void waitForReadyRead();
void waitForReadyReadMinusOne();
void flush();
@@ -1682,6 +1683,52 @@ void tst_QTcpSocket::waitForBytesWrittenMinusOne()
}
//----------------------------------------------------------------------------------
+void tst_QTcpSocket::waitForBytesWrittenWriteInReadyReadSlot()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ SocketPair socketPair;
+ QVERIFY(socketPair.create());
+ QTcpSocket *client = socketPair.endPoints[0];
+ QTcpSocket *server = socketPair.endPoints[1];
+
+ QCOMPARE(client->state(), QTcpSocket::ConnectedState);
+ QCOMPARE(server->state(), QTcpSocket::ConnectedState);
+
+ server->write("ServerHello");
+ server->waitForBytesWritten();
+
+ // Make sure that the data from server has made it to client, but only read one byte from
+ // the OS buffer so that future polling for read will find more data ready.
+ client->setReadBufferSize(1);
+ QVERIFY(client->waitForReadyRead());
+
+ uint readyReadCount = 0;
+ connect(client, &QAbstractSocket::readyRead, [client, &readyReadCount]() {
+ // The commented out code is not necessary, but typically part of a real scenario
+ // client->readAll();
+ // client->write("response to whatever was read");
+ readyReadCount++;
+ client->flush();
+ });
+
+ client->write("ClientHello");
+
+ // Allow to fetch more data from the OS buffer ("new data", causes emission of readyRead())
+ client->setReadBufferSize(0);
+ QCOMPARE(readyReadCount, 0); // we missed the one from the first waitForReadyRead()
+
+ // If there is incoming data, waitForBytesWritten() emits readyRead() even *before* writing
+ // data, so if the readyRead handler already flushes outgoing data, the subsequent attempt
+ // in waitForBytesWritten() to flush outgoing data will fail.
+ // This tests that that doesn't happen anymore.
+ QVERIFY(client->waitForBytesWritten());
+ QCOMPARE(readyReadCount, 1);
+}
+
+//----------------------------------------------------------------------------------
void tst_QTcpSocket::waitForReadyRead()
{
QTcpSocket *socket = newSocket();
diff --git a/tests/auto/network/ssl/qsslsocket/certs/no_common_name.crt b/tests/auto/network/ssl/qsslsocket/certs/no_common_name.crt
new file mode 100644
index 00000000000..201519431ca
--- /dev/null
+++ b/tests/auto/network/ssl/qsslsocket/certs/no_common_name.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIUHVbLylWxSla5Ip55WjqQ767yHaYwDQYJKoZIhvcNAQEL
+BQAwKzETMBEGA1UECgwKQ2xpZW50Q2VydDEUMBIGA1UECwwLTG9jYWxDbGllbnQw
+HhcNMjUxMjAxMTAzNTExWhcNMjYxMjAxMTAzNTExWjArMRMwEQYDVQQKDApDbGll
+bnRDZXJ0MRQwEgYDVQQLDAtMb2NhbENsaWVudDCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAMzTT65W+Cq769PwteURV0hAjdGMb8eJZ9sb+msw3kxr/y/F
+k0qz1ksIimuyxq/eJzIX691ntCflYwPYWXRy1jvG+k9X9rYdFOggVzcyWwpW/jMV
+XeWAiSL6gqRzgBuD4AkU+qNgz6sLTZHaPim7zM3P/Vpz90Vkl+oN6schll0g4jEn
+KUTrIeu5WQukeLPofHRPAZZzP5PFbJRUnOYqjd1ohwLtpGGVj4yvJJBDOXxuwOHw
+Nxww8+u4Y9o1Wo1yGaaKMgr7lZSt85sHkITFTWBuDF8Z8MhpFDtZsk1Vx+7hC4py
+zaPBQqC9vjGBQJzDr9Knv7MSMHArvC8ly2uRAZcCAwEAAaNoMGYwHQYDVR0OBBYE
+FPEdy10KbujGEsb5Zd6a4Al24ZqwMB8GA1UdIwQYMBaAFPEdy10KbujGEsb5Zd6a
+4Al24ZqwMA8GA1UdEwEB/wQFMAMBAf8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJ
+KoZIhvcNAQELBQADggEBAGnGmVA8IyMRHLRCMwHNFnuOSDaAwtKWxnhZZcdGYkeU
+kvR52vsi+Wo6/AAX90St8lYUSssEzi7HgH1Reaju45/X7SGxs/39qAz/J5c7tLRy
+M+F9gY6qEv8Yzrvn7Kje20xwg7PVeJEdn45Zg5HILBO+xkGWBVgrVhrX61HkSjRt
+nHbZH04Bq85VEKlFIauD801cwi84B0xShosV67OkY6i0cnqC634QacJH5XVeQR3s
+UTXsfN6/aCBcKAJpKaERv2ISVq57SkvCvLs3vTzIXKMFVRUjOMOF5z8lD/An3hZ8
+RnIHOmjPYG4UdW+G5yITIog5eRVF918cjmDGZNRMklk=
+-----END CERTIFICATE-----
diff --git a/tests/auto/network/ssl/qsslsocket/certs/no_common_name.key b/tests/auto/network/ssl/qsslsocket/certs/no_common_name.key
new file mode 100644
index 00000000000..661d03b84be
--- /dev/null
+++ b/tests/auto/network/ssl/qsslsocket/certs/no_common_name.key
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDM00+uVvgqu+vT
+8LXlEVdIQI3RjG/HiWfbG/prMN5Ma/8vxZNKs9ZLCIprssav3icyF+vdZ7Qn5WMD
+2Fl0ctY7xvpPV/a2HRToIFc3MlsKVv4zFV3lgIki+oKkc4Abg+AJFPqjYM+rC02R
+2j4pu8zNz/1ac/dFZJfqDerHIZZdIOIxJylE6yHruVkLpHiz6Hx0TwGWcz+TxWyU
+VJzmKo3daIcC7aRhlY+MrySQQzl8bsDh8DccMPPruGPaNVqNchmmijIK+5WUrfOb
+B5CExU1gbgxfGfDIaRQ7WbJNVcfu4QuKcs2jwUKgvb4xgUCcw6/Sp7+zEjBwK7wv
+JctrkQGXAgMBAAECggEAFuXWphBN7QUWH5rs0r9mCQtCb3cqNd3cEOgnTh1n9JYs
+MIx/Y14Ialn5k4GoaZfFvPlkoltKDh28PH1OvtBpt8QOTplwWLqWkD6xUVfdSqIg
+B9jvJs2ARztHKJhK7YiIHqvMO0CC5sW8Nb52rZazlhyW36pQLd9Jhl5o7TsJgr6L
+kEb7YGV62/vWwVE0oVBooqbejep1geU/VTteheICroLa4+toPIgGWWJ9upg995Nw
+xoS4/DWNBoXKs3T7Awjvfn1qsxWvSO8T14Z2XMgyMJOuVhEp6X4DpX8NU+M+D6NB
+TKIPuXpktAR6gRU3mvh7f+uxbMwIgtbyPHfcHPRFbQKBgQDzMQ/JzPDBL6xSbqrl
+hY6xD0p86iu5P2tfPBpaizGhFvP0OHG8j4mffuzaphvViIZ/ektws70hmxvYWs8q
+MSXxxDXHHDcNX5haencU/wSAz7dQqrl8LOnVeBzlmeObtgDLw9OmLUXNHoFNuY9D
+AqmkpwRz49ZPmdEAHr1GegQx3QKBgQDXnPXS1TCdqBefTYBhs/ddmxb10lAbB13M
+5T65Cxg2gFf6I4W8dcYp1TqbOIvl30cFvlEFD49Cj/eT24Q467MpqzHn/SH88Xoi
+E9FJJUJ8asWNMEelzL/4QAHXe4lyF5m4uvS/qtIbpFUx2dgTJ4ZmExWqYSJcL4/c
+WmlNeu1cAwKBgQCuXkkhuk4NVi9KU4s5Uo/DKGGSOxzqkCxedmu27ALDq/9y5l22
+g3x73bfZ9iwS6Pb2xCr/PgCn7d0DPek4KVE5jiO5BeP7NMW6agCkD02dRlH8Bs1D
+2bg3lQ2zGqn15YOglmJUzjU0I2E254tu0qPsKMyqg3wQSwtt+Jxhwe7sCQKBgCOg
+duoQegkC9mxHNRhv0UbxUnjp+HyO2gv6MUQINkcDLAZUCkwatdTBu/5b+JnSK/0h
+9mc8q/JWsZUH57A0GhWfiQ6JQC14hTLOTX2ln3fJeL0cpioaS/osMWG2sv5cMfVZ
+RwnIoxEYNU+YbGC13jpNmv3dMP1EiqPheJbp4gCbAoGAc/4sgk8ySkpJJNaAydlo
+vZEp+UZGmVmvG9cw75qVWOWgQ2C8ExmLnxh2DEHzEJs+Y8DQgLzrZLD4rZfndWNC
+1DLE0WH69KJXhA/yu6GQgkQqZDXvMV3Cts2ofjVKyP8esGnsv+dCxR1uRxfKL0+m
+LSD+QHdz3uex3ip2TQA4Tm8=
+-----END PRIVATE KEY-----
diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
index 000a75a6284..ee1043bc725 100644
--- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
+++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp
@@ -157,6 +157,7 @@ private slots:
void connectToHostEncrypted();
void connectToHostEncryptedWithVerificationPeerName();
void sessionCipher();
+ void localCertificate_data();
void localCertificate();
void mode();
void peerCertificate();
@@ -1208,11 +1209,22 @@ void tst_QSslSocket::sessionCipher()
QVERIFY(socket->waitForDisconnected());
}
+void tst_QSslSocket::localCertificate_data()
+{
+ QTest::addColumn<QString>("certificatePath");
+ QTest::addColumn<QString>("keyPath");
+ QTest::newRow("fluke") << (testDataDir + "certs/fluke.cert") << (testDataDir + "certs/fluke.key");
+ QTest::newRow("no-common-name") << (testDataDir + "certs/no_common_name.crt") << (testDataDir + "certs/no_common_name.key");
+}
+
void tst_QSslSocket::localCertificate()
{
if (!QSslSocket::supportsSsl())
return;
+ QFETCH(QString, certificatePath);
+ QFETCH(QString, keyPath);
+
// This test does not make 100% sense yet. We just set some local CA/cert/key and use it
// to authenticate ourselves against the server. The server does not actually check this
// values. This test should just run the codepath inside qsslsocket_openssl.cpp
@@ -1224,8 +1236,10 @@ void tst_QSslSocket::localCertificate()
sslConfig.setCaCertificates(localCert);
socket->setSslConfiguration(sslConfig);
- socket->setLocalCertificate(testDataDir + "certs/fluke.cert");
- socket->setPrivateKey(testDataDir + "certs/fluke.key");
+ socket->setLocalCertificate(certificatePath);
+ socket->setPrivateKey(keyPath);
+ QVERIFY(!socket->localCertificateChain().isEmpty());
+ QVERIFY(!socket->privateKey().isNull());
socket->connectToHostEncrypted(QtNetworkSettings::httpServerName(), 443);
QFETCH_GLOBAL(bool, setProxy);