diff options
Diffstat (limited to 'src')
44 files changed, 1906 insertions, 335 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); ** ){ ** // do something with pVal ** } -** if( rc!=SQLITE_OK ){ +** if( rc!=SQLITE_DONE ){ ** // an error has occurred ** } ** </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); ** ){ ** // do something with pVal ** } -** if( rc!=SQLITE_OK ){ +** if( rc!=SQLITE_DONE ){ ** // an error has occurred ** } ** </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/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..7fbb356d9a0 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,211 @@ 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::Reference<QMetaAssociation::Iterable::Iterator> QMetaAssociation::Iterable::Iterator::operator[](qsizetype n) const + Returns the item offset from the current one by \a n, 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 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. +*/ + +/*! + \fn QVariant QMetaAssociation::Iterable::ConstIterator::operator[](qsizetype n) const + Returns the item offset from the current one by \a n, converted to a + QVariant. The returned value is 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..d7b3fb65242 --- /dev/null +++ b/src/corelib/kernel/qmetaassociation.h @@ -0,0 +1,273 @@ +// 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); } + reference operator[](qsizetype n) const { return reference(*this + n); } +}; + +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); } + mapped_type operator[](qsizetype n) const; +}; + +} // 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); +} + +inline AssociativeConstIterator::mapped_type AssociativeConstIterator::operator[](qsizetype n) const +{ + return reference(*this + n); +} + +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..f8e73a8b0a2 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,69 @@ 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; + QVariant::Reference<Iterator> operator[](qsizetype n) const; + }; + + class ConstIterator : public QConstIterator<QMetaAssociation> + { + public: + QVariant key() const; + QVariant value() const; + + 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(); + + 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/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/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 Binary files differindex 7516e4ee4f8..7516e4ee4f8 100644 --- a/src/widgets/styles/images/fusion_normalizedockup_10.png +++ b/src/widgets/styles/images/fusion_normalizedockup-10.png diff --git a/src/widgets/styles/images/fusion_normalizedockup_20.png b/src/widgets/styles/images/fusion_normalizedockup-20.png Binary files differindex 2bc9421d5ac..2bc9421d5ac 100644 --- a/src/widgets/styles/images/fusion_normalizedockup_20.png +++ b/src/widgets/styles/images/fusion_normalizedockup-20.png diff --git a/src/widgets/styles/images/fusion_normalizedockup_48.png b/src/widgets/styles/images/fusion_normalizedockup-48.png Binary files differindex 6c497abdded..6c497abdded 100644 --- a/src/widgets/styles/images/fusion_normalizedockup_48.png +++ b/src/widgets/styles/images/fusion_normalizedockup-48.png diff --git a/src/widgets/styles/images/fusion_normalizedockup_64.png b/src/widgets/styles/images/fusion_normalizedockup-64.png Binary files differindex 5ec620e5a04..5ec620e5a04 100644 --- a/src/widgets/styles/images/fusion_normalizedockup_64.png +++ b/src/widgets/styles/images/fusion_normalizedockup-64.png |
