diff options
Diffstat (limited to 'src')
61 files changed, 1181 insertions, 323 deletions
diff --git a/src/3rdparty/pcre2/qt_attribution.json b/src/3rdparty/pcre2/qt_attribution.json index ef29ad7d951..0468bca1b3e 100644 --- a/src/3rdparty/pcre2/qt_attribution.json +++ b/src/3rdparty/pcre2/qt_attribution.json @@ -30,7 +30,7 @@ "Homepage": "http://www.pcre.org/", "Version": "10.47", "DownloadLocation": "https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.47/pcre2-10.47.tar.bz2", - "PURL": "pkg:github/PCRE2Project/pcre2@$<VERSION>", + "PURL": "pkg:github/PCRE2Project/pcre2@pcre2-$<VERSION>", "CPE": "cpe:2.3:a:pcre:pcre2:$<VERSION>:*:*:*:*:*:*:*", "License": "BSD 2-clause \"Simplified\" License", "LicenseId": "BSD-2-Clause", diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt index 1147205b79f..380b571c3cf 100644 --- a/src/corelib/CMakeLists.txt +++ b/src/corelib/CMakeLists.txt @@ -638,6 +638,7 @@ qt_internal_extend_target(Core CONDITION WIN32 platform/windows/qcomptr_p.h platform/windows/qbstr_p.h platform/windows/qcomvariant_p.h + platform/windows/quniquehandle_types_windows.cpp platform/windows/quniquehandle_types_windows_p.h LIBRARIES advapi32 authz @@ -1028,7 +1029,7 @@ qt_internal_extend_target(Core qt_internal_extend_target(Core CONDITION - QT_FEATURE_timezone AND UNIX + QT_FEATURE_timezone AND UNIX AND NOT VXWORKS AND NOT ANDROID AND NOT APPLE AND NOT QT_FEATURE_timezone_tzdb SOURCES time/qtimezoneprivate_tz.cpp @@ -1037,7 +1038,7 @@ qt_internal_extend_target(Core qt_internal_extend_target(Core CONDITION QT_FEATURE_icu AND QT_FEATURE_timezone - AND NOT UNIX AND NOT QT_FEATURE_timezone_tzdb + AND (VXWORKS OR NOT UNIX) AND NOT QT_FEATURE_timezone_tzdb SOURCES time/qtimezoneprivate_icu.cpp ) diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake index d951b85c147..edcfba0f6ce 100644 --- a/src/corelib/configure.cmake +++ b/src/corelib/configure.cmake @@ -1150,7 +1150,7 @@ qt_feature("timezone" PUBLIC SECTION "Utilities" LABEL "QTimeZone" PURPOSE "Provides support for time-zone handling." - CONDITION NOT WASM AND NOT VXWORKS + CONDITION NOT WASM ) qt_feature("timezone_locale" PRIVATE SECTION "Utilities" diff --git a/src/corelib/doc/images/javaiterators1.svg b/src/corelib/doc/images/javaiterators1.svg new file mode 100644 index 00000000000..468dbe5371c --- /dev/null +++ b/src/corelib/doc/images/javaiterators1.svg @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="340" + height="110" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .line-style { stroke: red; fill: none } + svg .text-style { font: 20px arial; fill: black } + svg .fill-style { stroke: none; fill: red } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .line-style { stroke: red; fill: none } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .fill-style { stroke: none; fill: red } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .line-style { stroke: red; fill: none } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .fill-style { stroke: none; fill: red } +</style> + +<g transform="translate(10.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">A</text> +<path d="M 0,60 v 30" class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +</g> + +<g transform="translate(90.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">B</text> +<path d="M 0,60 v 30" class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +</g> + +<g transform="translate(170.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">C</text> +<path d="M 0,60 v 30" class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +</g> + +<g transform="translate(250.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">D</text> +<path d="M 0,60 v 30" class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +</g> + +<g transform="translate(330.5, 10.5)"> +<path d="M 0,60 v 30" class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +</g> + +</svg> diff --git a/src/corelib/doc/images/javaiterators2.svg b/src/corelib/doc/images/javaiterators2.svg new file mode 100644 index 00000000000..df4c6b352a6 --- /dev/null +++ b/src/corelib/doc/images/javaiterators2.svg @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + version="1.1" + width="340" + height="130" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + +<style> + svg .box-style { stroke: black; fill: white } + svg .line-style { stroke: red; fill: none } + svg .fill-style { stroke: none; fill: red } + svg .np-line-style { stroke: blue; fill: none } + svg .np-fill-style { stroke: none; fill: blue } + svg .text-style { font: 20px arial; fill: black } + svg .small-text-style { font: 12px monospace; fill: black } + + [data-theme="dark"] svg .box-style { stroke: #f2f2f2; fill: black } + [data-theme="dark"] svg .line-style { stroke: red; fill: none } + [data-theme="dark"] svg .fill-style { stroke: none; fill: red } + [data-theme="dark"] svg .np-line-style { stroke: #4080ff; fill: none; stroke-width: 1.5 } + [data-theme="dark"] svg .np-fill-style { stroke: none; fill: #4080ff } + [data-theme="dark"] svg .text-style { font: 20px arial; fill: #f2f2f2 } + [data-theme="dark"] svg .small-text-style { font: 12px monospace; fill: #f2f2f2 } + + [data-theme="light"] svg .box-style { stroke: black; fill: white } + [data-theme="light"] svg .line-style { stroke: red; fill: none } + [data-theme="light"] svg .fill-style { stroke: none; fill: red } + [data-theme="light"] svg .np-line-style { stroke: blue; fill: none } + [data-theme="light"] svg .np-fill-style { stroke: none; fill: blue } + [data-theme="light"] svg .text-style { font: 20px arial; fill: black } + [data-theme="light"] svg .small-text-style { font: 12px monospace; fill: black } +</style> + +<g transform="translate(10.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">A</text> +</g> + +<g transform="translate(90.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">B</text> +<path d="M 0,60 c 0,30 50,40 80,30" class="np-line-style" /> +<path d="M 0,60 l -2,14 l 11,-4 z" class="np-fill-style" /> +<text x="-15" y="110" class="small-text-style">previous()</text> +</g> + +<g transform="translate(170.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">C</text> +<path d="M 0,60 v 50" class="line-style" /> +<path d="M 0,60 l -5,10 l 10,0 z" class="fill-style" /> +<text x="30" y="110" class="small-text-style">next()</text> +</g> + +<g transform="translate(250.5, 10.5)"> +<path d="m 0,0 h 80 v 60 h -80 z" class="box-style" /> +<text x="35" y="36" class="text-style">D</text> +<path d="M 0,60 c 0,30 -50,40 -80,30" class="np-line-style" /> +<path d="M 0,60 l 2,14 l -11,-4 z" class="np-fill-style" /> +</g> + +</svg> diff --git a/src/corelib/doc/src/java-style-iterators.qdoc b/src/corelib/doc/src/java-style-iterators.qdoc index 856005cb66c..a0e5c53d633 100644 --- a/src/corelib/doc/src/java-style-iterators.qdoc +++ b/src/corelib/doc/src/java-style-iterators.qdoc @@ -42,7 +42,7 @@ diagram below shows the valid iterator positions as red arrows for a list containing four items: - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's a typical loop for iterating through all the elements of a QList<QString> in order: @@ -70,7 +70,7 @@ \l{QListIterator::next()}{next()} and \l{QListIterator::previous()}{previous()} on an iterator: - \image javaiterators2.png + \image javaiterators2.png Iterating to the next and previous items The following table summarizes the QListIterator API: diff --git a/src/corelib/itemmodels/qrangemodel.cpp b/src/corelib/itemmodels/qrangemodel.cpp index 05e3a39e589..b0c6c46b125 100644 --- a/src/corelib/itemmodels/qrangemodel.cpp +++ b/src/corelib/itemmodels/qrangemodel.cpp @@ -20,6 +20,8 @@ public: private: std::unique_ptr<QRangeModelImplBase, QRangeModelImplBase::Deleter> impl; + friend class QRangeModelImplBase; + mutable QHash<int, QByteArray> m_roleNames; }; @@ -28,6 +30,16 @@ QRangeModel::QRangeModel(QRangeModelImplBase *impl, QObject *parent) { } +QRangeModelImplBase *QRangeModelImplBase::getImplementation(QRangeModel *model) +{ + return model->d_func()->impl.get(); +} + +const QRangeModelImplBase *QRangeModelImplBase::getImplementation(const QRangeModel *model) +{ + return model->d_func()->impl.get(); +} + /*! \class QRangeModel \inmodule QtCore diff --git a/src/corelib/itemmodels/qrangemodel_impl.h b/src/corelib/itemmodels/qrangemodel_impl.h index f38dc88c0d9..c2f473542d7 100644 --- a/src/corelib/itemmodels/qrangemodel_impl.h +++ b/src/corelib/itemmodels/qrangemodel_impl.h @@ -842,6 +842,11 @@ namespace QRangeModelDetails { using protocol = wrapped_t<Protocol>; using row = typename range_traits<wrapped_t<Range>>::value_type; + static constexpr bool is_tree = std::conjunction_v<protocol_parentRow<protocol, row>, + protocol_childRows<protocol, row>>; + static constexpr bool is_list = static_size_v<row> == 0 + && (!has_metaobject_v<row> || row_category<row>::isMultiRole); + static constexpr bool is_table = !is_list && !is_tree; static constexpr bool has_newRow = protocol_newRow<protocol>(); static constexpr bool has_deleteRow = protocol_deleteRow<protocol, row>(); @@ -1046,6 +1051,9 @@ public: typename C::MultiData >; + static Q_CORE_EXPORT QRangeModelImplBase *getImplementation(QRangeModel *model); + static Q_CORE_EXPORT const QRangeModelImplBase *getImplementation(const QRangeModel *model); + private: friend class QRangeModelPrivate; QRangeModel *m_rangeModel; @@ -1147,13 +1155,6 @@ protected: } } - static constexpr bool isMutable() - { - return range_features::is_mutable && row_features::is_mutable - && std::is_reference_v<row_reference> - && Structure::is_mutable_impl; - } - static constexpr int static_row_count = QRangeModelDetails::static_size_v<range_type>; static constexpr bool rows_are_raw_pointers = std::is_pointer_v<row_type>; static constexpr bool rows_are_owning_or_raw_pointers = @@ -1161,9 +1162,6 @@ protected: static constexpr int static_column_count = QRangeModelDetails::static_size_v<row_type>; static constexpr bool one_dimensional_range = static_column_count == 0; - static constexpr bool dynamicRows() { return isMutable() && static_row_count < 0; } - static constexpr bool dynamicColumns() { return static_column_count < 0; } - // A row might be a value (or range of values), or a pointer. // row_ptr is always a pointer, and const_row_ptr is a pointer to const. using row_ptr = wrapped_row_type *; @@ -1205,6 +1203,15 @@ protected: "The range holding a move-only row-type must support insert(pos, start, end)"); public: + static constexpr bool isMutable() + { + return range_features::is_mutable && row_features::is_mutable + && std::is_reference_v<row_reference> + && Structure::is_mutable_impl; + } + static constexpr bool dynamicRows() { return isMutable() && static_row_count < 0; } + static constexpr bool dynamicColumns() { return static_column_count < 0; } + explicit QRangeModelImpl(Range &&model, Protocol&& protocol, QRangeModel *itemModel) : Ancestor(itemModel) , ProtocolStorage{std::forward<Protocol>(protocol)} @@ -1236,7 +1243,7 @@ public: if (row == index.row() && column == index.column()) return index; - if (column < 0 || column >= this->itemModel().columnCount()) + if (column < 0 || column >= this->columnCount({})) return {}; if (row == index.row()) @@ -1974,8 +1981,8 @@ public: } if (sourceRow == destRow || sourceRow == destRow - 1 || count <= 0 - || sourceRow < 0 || sourceRow + count - 1 >= this->itemModel().rowCount(sourceParent) - || destRow < 0 || destRow > this->itemModel().rowCount(destParent)) { + || sourceRow < 0 || sourceRow + count - 1 >= this->rowCount(sourceParent) + || destRow < 0 || destRow > this->rowCount(destParent)) { return false; } @@ -1995,11 +2002,14 @@ public: } } - QModelIndex parent(const QModelIndex &child) const { return that().parent(child); } + const protocol_type& protocol() const { return QRangeModelDetails::refTo(ProtocolStorage::object()); } + protocol_type& protocol() { return QRangeModelDetails::refTo(ProtocolStorage::object()); } + + QModelIndex parent(const QModelIndex &child) const { return that().parentImpl(child); } - int rowCount(const QModelIndex &parent) const { return that().rowCount(parent); } + int rowCount(const QModelIndex &parent) const { return that().rowCountImpl(parent); } - int columnCount(const QModelIndex &parent) const { return that().columnCount(parent); } + int columnCount(const QModelIndex &parent) const { return that().columnCountImpl(parent); } void destroy() { delete std::addressof(that()); } @@ -2035,6 +2045,11 @@ public: protected: ~QRangeModelImpl() { + deleteOwnedRows(); + } + + void deleteOwnedRows() + { // We delete row objects if we are not operating on a reference or pointer // to a range, as in that case, the owner of the referenced/pointed to // range also owns the row entries. @@ -2335,9 +2350,6 @@ protected: } - const protocol_type& protocol() const { return QRangeModelDetails::refTo(ProtocolStorage::object()); } - protocol_type& protocol() { return QRangeModelDetails::refTo(ProtocolStorage::object()); } - ModelData m_data; }; @@ -2385,7 +2397,7 @@ protected: return this->createIndex(row, column, QRangeModelDetails::pointerTo(*it)); } - QModelIndex parent(const QModelIndex &child) const + QModelIndex parentImpl(const QModelIndex &child) const { if (!child.isValid()) return {}; @@ -2410,12 +2422,12 @@ protected: return {}; } - int rowCount(const QModelIndex &parent) const + int rowCountImpl(const QModelIndex &parent) const { return Base::size(this->childRange(parent)); } - int columnCount(const QModelIndex &) const + int columnCountImpl(const QModelIndex &) const { // all levels of a tree have to have the same, static, column count if constexpr (Base::one_dimensional_range) @@ -2662,6 +2674,9 @@ class QGenericTableItemModelImpl using Base = QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>; friend class QRangeModelImpl<QGenericTableItemModelImpl<Range>, Range>; + static constexpr bool is_mutable_impl = true; + +public: using range_type = typename Base::range_type; using range_features = typename Base::range_features; using row_type = typename Base::row_type; @@ -2669,9 +2684,6 @@ class QGenericTableItemModelImpl using row_traits = typename Base::row_traits; using row_features = typename Base::row_features; - static constexpr bool is_mutable_impl = true; - -public: explicit QGenericTableItemModelImpl(Range &&model, QRangeModel *itemModel) : Base(std::forward<Range>(model), {}, itemModel) {} @@ -2692,19 +2704,19 @@ protected: } } - QModelIndex parent(const QModelIndex &) const + QModelIndex parentImpl(const QModelIndex &) const { return {}; } - int rowCount(const QModelIndex &parent) const + int rowCountImpl(const QModelIndex &parent) const { if (parent.isValid()) return 0; return int(Base::size(*this->m_data.model())); } - int columnCount(const QModelIndex &parent) const + int columnCountImpl(const QModelIndex &parent) const { if (parent.isValid()) return 0; @@ -2760,7 +2772,7 @@ protected: // dynamically sized rows all have to have the same column count if constexpr (Base::dynamicColumns() && row_features::has_resize) { if (QRangeModelDetails::isValid(empty_row)) - QRangeModelDetails::refTo(empty_row).resize(this->itemModel().columnCount()); + QRangeModelDetails::refTo(empty_row).resize(this->columnCount({})); } return empty_row; diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 8366787ea66..57089f164b2 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -2974,4 +2974,156 @@ const QVariant *QVariantConstPointer::operator->() const implement operator->(). */ +/*! + \class QVariant::ConstReference + \since 6.11 + \inmodule QtCore + \brief The QVariant::ConstReference acts as a const reference to a QVariant. + + As the generic iterators don't actually instantiate a QVariant on each + step, they cannot return a reference to one from operator*(). + QVariant::ConstReference provides the same functionality as an actual + reference to a QVariant would, but is backed a referred-to value given as + template parameter. The template is implemented for + QMetaSequence::ConstIterator, QMetaSequence::Iterator, + QMetaAssociation::ConstIterator, and QMetaAssociation::Iterator. +*/ + +/*! + \fn template<typename Referred> QVariant::ConstReference<Referred>::ConstReference(const Referred &referred) + + Creates a QVariant::ConstReference from a \a referred. + */ + +/*! + \fn template<typename Referred> QVariant::ConstReference<Referred>::ConstReference(Referred &&referred) + + Creates a QVariant::ConstReference from a \a referred. + */ + +/*! + \fn template<typename Referred> QVariant::ConstReference<Referred>::operator QVariant() const + + Dereferences the reference to a QVariant. + This method needs to be specialized for each Referred type. It is + pre-defined for QMetaSequence::ConstIterator, QMetaSequence::Iterator, + QMetaAssociation::ConstIterator, and QMetaAssociation::Iterator. + */ + + +/*! + \class QVariant::Reference + \since 6.11 + \inmodule QtCore + \brief The QVariant::Reference acts as a non-const reference to a QVariant. + + As the generic iterators don't actually instantiate a QVariant on each + step, they cannot return a reference to one from operator*(). + QVariant::Reference provides the same functionality as an actual reference + to a QVariant would, but is backed a referred-to value given as template + parameter. The template is implemented for QMetaSequence::Iterator and + QMetaAssociation::Iterator. +*/ + +/*! + \fn template<typename Referred> QVariant::Reference<Referred>::Reference(const Referred &referred) + + Creates a QVariant::Reference from a \a referred. + */ + +/*! + \fn template<typename Referred> QVariant::Reference<Referred>::Reference(Referred &&referred) + + Creates a QVariant::Reference from a \a referred. + */ + +/*! + \fn template<typename Referred> QVariant::Reference<Referred> &QVariant::Reference<Referred>::operator=(const Reference<Referred> &value) + + Assigns a new \a value to the value referred to by this QVariant::Reference. + */ + +/*! + \fn template<typename Referred> QVariant::Reference<Referred> &QVariant::Reference<Referred>::operator=(Reference<Referred> &&value) + + Assigns a new \a value to the value referred to by this QVariant::Reference. +*/ + +/*! + \fn template<typename Referred> QVariant::Reference<Referred> &QVariant::Reference<Referred>::operator=(const QVariant &value) + + Assigns a new \a value to the value referred to by this QVariant::Reference. + This method needs to be specialized for each Referred type. It is + pre-defined for QMetaSequence::Iterator and QMetaAssociation::Iterator. + */ + +/*! + \fn template<typename Referred> QVariant::Reference<Referred>::operator QVariant() const + + Dereferences the reference to a QVariant. By default this instantiates a + temporary QVariant::ConstReference and calls dereferences that. In cases + where instantiating a temporary ConstReference is expensive, this method + should be specialized. + */ + +/*! + \class QVariant::ConstPointer + \since 6.11 + \inmodule QtCore + \brief QVariant::ConstPointer is a template class that emulates a const pointer to QVariant. + + QVariant::ConstPointer wraps pointed-to value and returns a + QVariant::ConstReference to it from its operator*(). This makes it suitable + as replacement for an actual pointer. We cannot return an actual pointer + from generic iterators as the iterators don't hold an actual QVariant. +*/ + +/*! + \fn template<typename Pointed> QVariant::ConstPointer<Pointed>::ConstPointer(const Pointed &pointed) + + Constructs a QVariant::ConstPointer from the value \a pointed to. + */ + +/*! + \fn template<typename Pointed> QVariant::ConstPointer<Pointed>::ConstPointer(Pointed &&pointed) + + Constructs a QVariant::ConstPointer from the value \a pointed to. + */ + +/*! + \fn template<typename Pointed> QVariant::ConstReference<Pointer> QVariant::ConstPointer<Pointed>::operator*() const + + Dereferences the QVariant::ConstPointer to a QVariant::ConstReference. + */ + +/*! + \class QVariant::Pointer + \since 6.11 + \inmodule QtCore + \brief QVariant::Pointer is a template class that emulates a non-const pointer to QVariant. + + QVariant::Pointer wraps pointed-to value and returns a QVariant::Reference + to it from its operator*(). This makes it suitable as replacement for an + actual pointer. We cannot return an actual pointer from generic iterators as + the iterators don't hold an actual QVariant. +*/ + +/*! + \fn template<typename Pointed> QVariant::Pointer<Pointed>::Pointer(const Pointed &pointed) + + Constructs a QVariant::Pointer from the value \a pointed to. + */ + +/*! + \fn template<typename Pointed> QVariant::Pointer<Pointed>::Pointer(Pointed &&pointed) + + Constructs a QVariant::Pointer from the value \a pointed to. + */ + +/*! + \fn template<typename Pointed> QVariant::Reference<Pointer> QVariant::Pointer<Pointed>::operator*() const + + Dereferences the QVariant::Pointer to a QVariant::Reference. + */ + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index 542b1d9b709..9b219d089b5 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -61,7 +61,20 @@ inline T qvariant_cast(const QVariant &); namespace QtPrivate { template<> constexpr inline bool qIsRelocatable<QVariant> = true; -} + +template<typename Referred> +class ConstReference; + +template<typename Referred> +class Reference; + +template<typename Pointed> +class ConstPointer; + +template<typename Pointed> +class Pointer; +} // namespace QtPrivate + class Q_CORE_EXPORT QVariant { template <typename T, typename... Args> @@ -228,6 +241,123 @@ private: >; public: + template<typename Referred> + class ConstReference + { + private: + const Referred m_referred; + + public: + // You can initialize a const reference from another one, but you can't assign to it. + + explicit ConstReference(const Referred &referred) + noexcept(std::is_nothrow_copy_constructible_v<Referred>) + : m_referred(referred) {} + explicit ConstReference(Referred &&referred) + noexcept(std::is_nothrow_move_constructible_v<Referred>) + : m_referred(std::move(referred)) {} + ConstReference(const ConstReference &) = default; + ConstReference(ConstReference &&) = default; + ~ConstReference() = default; + ConstReference &operator=(const ConstReference &value) = delete; + ConstReference &operator=(ConstReference &&value) = delete; + + // To be specialized for each Referred + operator QVariant() const noexcept(Referred::canNoexceptConvertToQVariant); + }; + + template<typename Referred> + class Reference + { + private: + Referred m_referred; + + friend void swap(Reference a, Reference b) { return a.swap(std::move(b)); } + + public: + // Assigning and initializing are different operations for references. + + explicit Reference(const Referred &referred) + noexcept(std::is_nothrow_copy_constructible_v<Referred>) + : m_referred(referred) {} + explicit Reference(Referred &&referred) + noexcept(std::is_nothrow_move_constructible_v<Referred>) + : m_referred(std::move(referred)) {} + Reference(const Reference &) = default; + Reference(Reference &&) = default; + ~Reference() = default; + + Reference &operator=(const Reference &value) + noexcept(Referred::canNoexceptAssignQVariant) + { + return operator=(QVariant(value)); + } + + Reference &operator=(Reference &&value) + noexcept(Referred::canNoexceptAssignQVariant) + { + return operator=(QVariant(value)); + } + + operator QVariant() const noexcept(Referred::canNoexceptConvertToQVariant) + { + return ConstReference(m_referred); + } + + void swap(Reference b) + { + // swapping a reference is not swapping the referred item, but swapping its contents. + QVariant tmp = *this; + *this = std::move(b); + b = std::move(tmp); + } + + // To be specialized for each Referred + Reference &operator=(const QVariant &value) noexcept(Referred::canNoexceptAssignQVariant); + }; + + template<typename Pointed> + class ConstPointer + { + private: + Pointed m_pointed; + + public: + explicit ConstPointer(const Pointed &pointed) + noexcept(std::is_nothrow_copy_constructible_v<Pointed>) + : m_pointed(pointed) {} + explicit ConstPointer(Pointed &&pointed) + noexcept(std::is_nothrow_move_constructible_v<Pointed>) + : m_pointed(std::move(pointed)) {} + + ConstReference<Pointed> operator*() + const noexcept(std::is_nothrow_copy_constructible_v<Pointed>) + { + return ConstReference<Pointed>(m_pointed); + } + }; + + template<typename Pointed> + class Pointer + { + private: + Pointed m_pointed; + + public: + explicit Pointer(const Pointed &pointed) + noexcept(std::is_nothrow_copy_constructible_v<Pointed>) + : m_pointed(pointed) {} + explicit Pointer(Pointed &&pointed) + noexcept(std::is_nothrow_move_constructible_v<Pointed>) + : m_pointed(std::move(pointed)) {} + + Reference<Pointed> operator*() + const noexcept(std::is_nothrow_copy_constructible_v<Pointed>) + { + return Reference<Pointed>(m_pointed); + } + }; + template <typename T, typename... Args, if_constructible<T, Args...> = true> explicit QVariant(std::in_place_type_t<T>, Args&&... args) diff --git a/src/corelib/platform/windows/quniquehandle_types_windows.cpp b/src/corelib/platform/windows/quniquehandle_types_windows.cpp new file mode 100644 index 00000000000..801c9ab13d6 --- /dev/null +++ b/src/corelib/platform/windows/quniquehandle_types_windows.cpp @@ -0,0 +1,17 @@ +// 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 "quniquehandle_types_windows_p.h" + +QT_BEGIN_NAMESPACE + +namespace QtUniqueHandleTraits { + +bool HDCTraits::close(Type handle, HWND hwnd) noexcept +{ + return ::ReleaseDC(hwnd, handle); +} + +} // namespace QtUniqueHandleTraits + +QT_END_NAMESPACE diff --git a/src/corelib/platform/windows/quniquehandle_types_windows_p.h b/src/corelib/platform/windows/quniquehandle_types_windows_p.h new file mode 100644 index 00000000000..0b832d2b9d1 --- /dev/null +++ b/src/corelib/platform/windows/quniquehandle_types_windows_p.h @@ -0,0 +1,65 @@ +// 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 QUNIQUEHANDLE_TYPES_WINDOWS_P_H +#define QUNIQUEHANDLE_TYPES_WINDOWS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#if defined(Q_OS_WIN) || defined(Q_QDOC) + +#include <QtCore/qnamespace.h> +#include <QtCore/qt_windows.h> +#include <QtCore/private/quniquehandle_p.h> + +QT_BEGIN_NAMESPACE + +namespace QtUniqueHandleTraits { + +struct HDCTraits +{ + using Type = HDC; + static Type invalidValue() noexcept { return nullptr; } + Q_CORE_EXPORT static bool close(Type handle, HWND hwnd) noexcept; +}; + +struct HDCDeleter +{ + using Type = HDCTraits::Type; + + constexpr HDCDeleter() noexcept = default; + explicit constexpr HDCDeleter(HWND hwnd) noexcept + : hwnd(hwnd) + {} + + void operator()(Type handle) const noexcept + { + if (handle != HDCTraits::invalidValue()) { + const bool success = HDCTraits::close(handle, hwnd); + Q_ASSERT(success); + } + } + + HWND hwnd{ nullptr }; +}; + +} // namespace QtUniqueHandleTraits +using QUniqueHDCHandle = QUniqueHandle< + QtUniqueHandleTraits::HDCTraits, + QtUniqueHandleTraits::HDCDeleter +>; + +QT_END_NAMESPACE + +#endif // Q_OS_WIN + +#endif // QUNIQUEHANDLE_TYPES_WINDOWS_P_H diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp index 711b70ebf8f..c01c1a9999d 100644 --- a/src/corelib/text/qstring.cpp +++ b/src/corelib/text/qstring.cpp @@ -3681,95 +3681,24 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs) \sa remove() */ - -/*! \internal - Instead of detaching, or reallocating if "before" is shorter than "after" - and there isn't enough capacity, create a new string, copy characters to it - as needed, then swap it with "str". -*/ -static void replace_with_copy(QString &str, QSpan<size_t> indices, qsizetype blen, - QStringView after) -{ - const qsizetype alen = after.size(); - const char16_t *after_b = after.utf16(); - - const QString::DataPointer &str_d = str.data_ptr(); - auto src_start = str_d.begin(); - const qsizetype newSize = str_d.size + indices.size() * (alen - blen); - QString copy{ newSize, Qt::Uninitialized }; - QString::DataPointer ©_d = copy.data_ptr(); - auto dst = copy_d.begin(); - for (size_t index : indices) { - auto hit = str_d.begin() + index; - dst = std::copy(src_start, hit, dst); - dst = std::copy_n(after_b, alen, dst); - src_start = hit + blen; - } - dst = std::copy(src_start, str_d.end(), dst); - str.swap(copy); -} - -// No detaching or reallocation is needed -static void replace_in_place(QString &str, QSpan<size_t> indices, - qsizetype blen, QStringView after) -{ - const qsizetype alen = after.size(); - const char16_t *after_b = after.utf16(); - const char16_t *after_e = after.utf16() + after.size(); - - if (blen == alen) { // Replace in place - for (size_t index : indices) - std::copy_n(after_b, alen, str.data_ptr().begin() + index); - } else if (blen > alen) { // Replace from front - char16_t *begin = str.data_ptr().begin(); - char16_t *hit = begin + indices.front(); - char16_t *to = hit; - to = std::copy_n(after_b, alen, to); - char16_t *movestart = hit + blen; - for (size_t index : indices.sliced(1)) { - hit = begin + index; - to = std::move(movestart, hit, to); - to = std::copy_n(after_b, alen, to); - movestart = hit + blen; - } - to = std::move(movestart, str.data_ptr().end(), to); - str.resize(std::distance(begin, to)); - } else { // blen < alen, Replace from back - const qsizetype oldSize = str.data_ptr().size; - const qsizetype adjust = indices.size() * (alen - blen); - const qsizetype newSize = oldSize + adjust; - - str.resize(newSize); - char16_t *begin = str.data_ptr().begin(); - char16_t *moveend = begin + oldSize; - char16_t *to = str.data_ptr().end(); - - for (auto it = indices.rbegin(), end = indices.rend(); it != end; ++it) { - char16_t *hit = begin + *it; - char16_t *movestart = hit + blen; - to = std::move_backward(movestart, moveend, to); - to = std::copy_backward(after_b, after_e, to); - moveend = hit; - } - } -} - -static void replace_helper(QString &str, QSpan<size_t> indices, qsizetype blen, QStringView after) +static void replace_helper(QString &str, QSpan<qsizetype> indices, qsizetype blen, QStringView after) { const qsizetype oldSize = str.data_ptr().size; const qsizetype adjust = indices.size() * (after.size() - blen); const qsizetype newSize = oldSize + adjust; + using A = QStringAlgorithms<QString>; if (str.data_ptr().needsDetach() || needsReallocate(str, newSize)) { - replace_with_copy(str, indices, blen, after); + A::replace_helper(str, blen, after, indices); return; } - if (QtPrivate::q_points_into_range(after.begin(), str)) + if (QtPrivate::q_points_into_range(after.begin(), str)) { // Copy after if it lies inside our own d.b area (which we could // possibly invalidate via a realloc or modify by replacement) - replace_in_place(str, indices, blen, QVarLengthArray(after.begin(), after.end())); - else - replace_in_place(str, indices, blen, after); + A::replace_helper(str, blen, QVarLengthArray(after.begin(), after.end()), indices); + } else { + A::replace_helper(str, blen, after, indices); + } } /*! @@ -3811,8 +3740,8 @@ QString &QString::replace(qsizetype pos, qsizetype len, const QChar *after, qsiz if (len > this->size() - pos) len = this->size() - pos; - size_t index = pos; - replace_helper(*this, QSpan(&index, 1), len, QStringView{after, alen}); + qsizetype indices[] = {pos}; + replace_helper(*this, indices, len, QStringView{after, alen}); return *this; } @@ -3890,7 +3819,7 @@ QString &QString::replace(const QChar *before, qsizetype blen, qsizetype index = 0; - QVarLengthArray<size_t> indices; + QVarLengthArray<qsizetype> indices; while ((index = matcher.indexIn(*this, index)) != -1) { indices.push_back(index); if (blen) // Step over before: @@ -3925,7 +3854,7 @@ QString& QString::replace(QChar ch, const QString &after, Qt::CaseSensitivity cs const char16_t cc = (cs == Qt::CaseSensitive ? ch.unicode() : ch.toCaseFolded().unicode()); - QVarLengthArray<size_t> indices; + QVarLengthArray<qsizetype> indices; if (cs == Qt::CaseSensitive) { const char16_t *begin = d.begin(); const char16_t *end = d.end(); diff --git a/src/corelib/time/qgregoriancalendar.cpp b/src/corelib/time/qgregoriancalendar.cpp index d46d24ac30d..dfb99c5073d 100644 --- a/src/corelib/time/qgregoriancalendar.cpp +++ b/src/corelib/time/qgregoriancalendar.cpp @@ -31,6 +31,7 @@ static_assert(qDivMod<86400>(-172800).remainder == 0); /*! \since 5.14 + \internal \class QGregorianCalendar \inmodule QtCore diff --git a/src/corelib/time/qjalalicalendar.cpp b/src/corelib/time/qjalalicalendar.cpp index 8bc9fe125e7..683ce6e7712 100644 --- a/src/corelib/time/qjalalicalendar.cpp +++ b/src/corelib/time/qjalalicalendar.cpp @@ -39,6 +39,7 @@ qint64 firstDayOfYear(int year, int cycleNo) /*! \since 5.14 + \internal \class QJalaliCalendar \inmodule QtCore diff --git a/src/corelib/time/qjuliancalendar.cpp b/src/corelib/time/qjuliancalendar.cpp index 47da952b84a..cf3718f471d 100644 --- a/src/corelib/time/qjuliancalendar.cpp +++ b/src/corelib/time/qjuliancalendar.cpp @@ -13,6 +13,7 @@ using namespace QRoundingDown; /*! \since 5.14 + \internal \class QJulianCalendar \inmodule QtCore diff --git a/src/corelib/time/qmilankoviccalendar.cpp b/src/corelib/time/qmilankoviccalendar.cpp index a3ffa2a3053..14aef83afe3 100644 --- a/src/corelib/time/qmilankoviccalendar.cpp +++ b/src/corelib/time/qmilankoviccalendar.cpp @@ -13,6 +13,7 @@ using namespace QRoundingDown; /*! \since 5.14 + \internal \class QMilankovicCalendar \inmodule QtCore diff --git a/src/corelib/time/qromancalendar.cpp b/src/corelib/time/qromancalendar.cpp index ae113cf8323..a8ce027275a 100644 --- a/src/corelib/time/qromancalendar.cpp +++ b/src/corelib/time/qromancalendar.cpp @@ -9,6 +9,7 @@ QT_BEGIN_NAMESPACE /*! \since 5.14 + \internal \class QRomanCalendar \inmodule QtCore diff --git a/src/corelib/time/qtimezone.cpp b/src/corelib/time/qtimezone.cpp index f44c681ea80..7b43aab22d1 100644 --- a/src/corelib/time/qtimezone.cpp +++ b/src/corelib/time/qtimezone.cpp @@ -29,7 +29,7 @@ static QTimeZonePrivate *newBackendTimeZone() return new QMacTimeZonePrivate(); #elif defined(Q_OS_ANDROID) return new QAndroidTimeZonePrivate(); -#elif defined(Q_OS_UNIX) +#elif defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) return new QTzTimeZonePrivate(); #elif QT_CONFIG(icu) return new QIcuTimeZonePrivate(); @@ -50,7 +50,7 @@ static QTimeZonePrivate *newBackendTimeZone(const QByteArray &ianaId) return new QMacTimeZonePrivate(ianaId); #elif defined(Q_OS_ANDROID) return new QAndroidTimeZonePrivate(ianaId); -#elif defined(Q_OS_UNIX) +#elif defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) return new QTzTimeZonePrivate(ianaId); #elif QT_CONFIG(icu) return new QIcuTimeZonePrivate(ianaId); @@ -1482,7 +1482,8 @@ QTimeZone QTimeZone::utc() bool QTimeZone::isTimeZoneIdAvailable(const QByteArray &ianaId) { -#if defined(Q_OS_UNIX) && !(defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN)) +#if defined(Q_OS_UNIX) && !(QT_CONFIG(timezone_tzdb) || defined(Q_OS_DARWIN) \ + || defined(Q_OS_ANDROID) || defined(Q_OS_VXWORKS)) // Keep #if-ery consistent with selection of QTzTimeZonePrivate in // newBackendTimeZone(). Skip the pre-check, as the TZ backend accepts POSIX // zone IDs, which need not be valid IANA IDs. See also QTBUG-112006. diff --git a/src/corelib/time/qtimezonelocale.cpp b/src/corelib/time/qtimezonelocale.cpp index a794682fe0b..6ad4aa1479c 100644 --- a/src/corelib/time/qtimezonelocale.cpp +++ b/src/corelib/time/qtimezonelocale.cpp @@ -611,6 +611,27 @@ QString QTimeZonePrivate::localeName(qint64 atMSecsSinceEpoch, int offsetFromUtc // Custom zone with perverse m_id ? return; } + const auto isMixedCaseAbbrev = [tail](char ch) { + // cv-RU and en-GU abbreviate Chamorro as ChST + // scn-IT abbreviates Cuba as CuT/CuST/CuDT + // blo-BJ abbreviates GMT as Gk + switch (tail.size()) { + case 2: return tail == "Gk"; + case 3: return tail == "CuT"; + case 4: + if (tail[0] == 'C' && tail[1] == ch && tail[3] == 'T') { + switch (ch) { + case 'h': return tail[2] == 'S'; + case 'u': return tail[2] == 'S' || tail[2] == 'D'; + default: break; + } + } + return false; + default: + break; + } + return false; + }; // Even if it is abbr or city name, we don't care if we've found one before. bool maybeAbbr = ianaAbbrev.isEmpty(), maybeCityName = ianaTail.isEmpty(), inword = false; @@ -632,7 +653,7 @@ QString QTimeZonePrivate::localeName(qint64 atMSecsSinceEpoch, int offsetFromUtc maybeCityName = false; inword = false; } else if (QChar::isLower(ch)) { - maybeAbbr = false; + maybeAbbr = isMixedCaseAbbrev(ch); // Dar_es_Salaam shows both cases as word starts inword = true; } else if (QChar::isUpper(ch)) { @@ -891,8 +912,11 @@ QTimeZonePrivate::findLongNamePrefix(QStringView text, const QLocale &locale, if (best.ianaIdIndex != invalidIanaId) return { QByteArray(ianaIdData + best.ianaIdIndex), best.nameLength, best.timeType }; - // Now try for a region format: - best = {}; + // Now try for a region format. + // Since we may get the IANA ID directly from a zone, we may not need an + // ianaIdIndex from CLDR-derived tables: and the active backend may know + // some zones newer than our latest CLDR. + NamePrefixMatch found; for (const qsizetype locInd : indices) { const LocaleZoneData &locData = localeZoneData[locInd]; const LocaleZoneData &nextData = localeZoneData[locInd + 1]; @@ -928,11 +952,11 @@ QTimeZonePrivate::findLongNamePrefix(QStringView text, const QLocale &locale, QStringView city = row.exemplarCity().viewData(exemplarCityTable); if (textMatches(city)) { qsizetype length = cut + city.size() + suffix.size(); - if (length > best.nameLength) { - bool gotZone = row.ianaIdIndex == best.ianaIdIndex + if (length > found.nameLength) { + bool gotZone = row.ianaId() == found.ianaId // (cheap pre-test) || QTimeZone::isTimeZoneIdAvailable(row.ianaId().toByteArray()); if (gotZone) - best = { length, timeType, row.ianaIdIndex }; + found = { row.ianaId().toByteArray(), length, timeType }; } } } @@ -945,38 +969,16 @@ QTimeZonePrivate::findLongNamePrefix(QStringView text, const QLocale &locale, QString city = QString::fromLatin1(local.replace('_', ' ')); if (textMatches(city)) { qsizetype length = cut + city.size() + suffix.size(); - if (length > best.nameLength) { - // Have to find iana in ianaIdData. Although its entries - // from locale-independent data are nicely sorted, the - // rest are (sadly) not. - QByteArrayView run(ianaIdData, qstrlen(ianaIdData)); - // std::size includes the trailing '\0', so subtract one: - const char *stop = ianaIdData + std::size(ianaIdData) - 1; - while (run != iana) { - if (run.end() < stop) { // Step to the next: - run = QByteArrayView(run.end() + 1); - } else { - run = QByteArrayView(); - break; - } - } - if (!run.isEmpty()) { - Q_ASSERT(run == iana); - const auto ianaIdIndex = run.begin() - ianaIdData; - Q_ASSERT(ianaIdIndex <= (std::numeric_limits<quint16>::max)()); - best = { length, timeType, quint16(ianaIdIndex) }; - } - } + if (length > found.nameLength) + found = { iana, length, timeType }; } } // TODO: similar for territories, at least once localeName() does so. } } - if (best.ianaIdIndex != invalidIanaId) - return { QByteArray(ianaIdData + best.ianaIdIndex), best.nameLength, best.timeType }; #undef localeRows - return {}; // No match found. + return found; } QTimeZonePrivate::NamePrefixMatch diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp index 556f7e21402..3f0254b1c5f 100644 --- a/src/corelib/time/qtimezoneprivate.cpp +++ b/src/corelib/time/qtimezoneprivate.cpp @@ -1177,7 +1177,7 @@ QUtcTimeZonePrivate::QUtcTimeZonePrivate(qint32 offsetSeconds) } Q_ASSERT(!name.isEmpty()); } else { // Fall back to a UTC-offset name: - name = isoOffsetFormat(offsetSeconds, QTimeZone::ShortName); + name = isoOffsetFormat(offsetSeconds, QTimeZone::OffsetName); id = name.toUtf8(); } init(id, offsetSeconds, name, name, QLocale::AnyTerritory, name); @@ -1292,12 +1292,16 @@ QString QUtcTimeZonePrivate::displayName(QTimeZone::TimeType timeType, if (!(name.startsWith("GMT"_L1) || name.startsWith("UTC"_L1)) || name.size() < 5) return false; // Fallback drops trailing ":00" minute: - QStringView tail{avoid}; + QStringView tail{avoid}; // TODO: deal with sign earlier ! Also: invisible Unicode ! tail = tail.sliced(3); - if (tail.endsWith(":00"_L1)) - tail = tail.chopped(3); if (name.sliced(3) == tail) return true; + while (tail.endsWith(":00"_L1)) + tail = tail.chopped(3); + while (name.endsWith(":00"_L1)) + name = name.chopped(3); + if (name == tail) + return true; // Accept U+2212 as minus sign: const QChar sign = name[3] == u'\u2212' ? u'-' : name[3]; // Fallback doesn't zero-pad hour: diff --git a/src/corelib/time/qtimezoneprivate_p.h b/src/corelib/time/qtimezoneprivate_p.h index 804c28af372..9a86ded6efb 100644 --- a/src/corelib/time/qtimezoneprivate_p.h +++ b/src/corelib/time/qtimezoneprivate_p.h @@ -50,7 +50,7 @@ class Q_AUTOTEST_EXPORT QTimeZonePrivate : public QSharedData { // Nothing should be copy-assigning instances of either this or its derived // classes (only clone() should copy, using the copy-constructor): - bool operator=(const QTimeZonePrivate &) const = delete; + QTimeZonePrivate &operator=(const QTimeZonePrivate &) const = delete; protected: QTimeZonePrivate(const QTimeZonePrivate &other) = default; public: @@ -210,7 +210,7 @@ Q_DECLARE_TYPEINFO(QTimeZonePrivate::Data, Q_RELOCATABLE_TYPE); class Q_AUTOTEST_EXPORT QUtcTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QUtcTimeZonePrivate &) const = delete; + QUtcTimeZonePrivate &operator=(const QUtcTimeZonePrivate &) const = delete; QUtcTimeZonePrivate(const QUtcTimeZonePrivate &other); public: // Create default UTC time zone @@ -273,7 +273,7 @@ private: #if QT_CONFIG(timezone_tzdb) class QChronoTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QChronoTimeZonePrivate &) const = delete; + QChronoTimeZonePrivate &operator=(const QChronoTimeZonePrivate &) const = delete; QChronoTimeZonePrivate(const QChronoTimeZonePrivate &) = default; public: QChronoTimeZonePrivate(); @@ -307,7 +307,7 @@ private: #elif defined(Q_OS_DARWIN) class Q_AUTOTEST_EXPORT QMacTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QMacTimeZonePrivate &) const = delete; + QMacTimeZonePrivate &operator=(const QMacTimeZonePrivate &) const = delete; QMacTimeZonePrivate(const QMacTimeZonePrivate &other); public: // Create default time zone @@ -353,7 +353,7 @@ private: #elif defined(Q_OS_ANDROID) class QAndroidTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QAndroidTimeZonePrivate &) const = delete; + QAndroidTimeZonePrivate &operator=(const QAndroidTimeZonePrivate &) const = delete; QAndroidTimeZonePrivate(const QAndroidTimeZonePrivate &) = default; public: // Create default time zone @@ -388,7 +388,7 @@ private: QJniObject androidTimeZone; }; -#elif defined(Q_OS_UNIX) +#elif defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) struct QTzTransitionTime { qint64 atMSecsSinceEpoch; @@ -421,7 +421,7 @@ struct QTzTimeZoneCacheEntry class Q_AUTOTEST_EXPORT QTzTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QTzTimeZonePrivate &) const = delete; + QTzTimeZonePrivate &operator=(const QTzTimeZonePrivate &) const = delete; QTzTimeZonePrivate(const QTzTimeZonePrivate &) = default; public: // Create default time zone @@ -474,7 +474,7 @@ private: #elif QT_CONFIG(icu) class Q_AUTOTEST_EXPORT QIcuTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QIcuTimeZonePrivate &) const = delete; + QIcuTimeZonePrivate &operator=(const QIcuTimeZonePrivate &) const = delete; QIcuTimeZonePrivate(const QIcuTimeZonePrivate &other); public: // Create default time zone @@ -518,7 +518,7 @@ private: #elif defined(Q_OS_WIN) class Q_AUTOTEST_EXPORT QWinTimeZonePrivate final : public QTimeZonePrivate { - bool operator=(const QWinTimeZonePrivate &) const = delete; + QWinTimeZonePrivate &operator=(const QWinTimeZonePrivate &) const = delete; QWinTimeZonePrivate(const QWinTimeZonePrivate &) = default; public: struct QWinTransitionRule { diff --git a/src/corelib/tools/qiterator.qdoc b/src/corelib/tools/qiterator.qdoc index 3d8ea595167..d517457027a 100644 --- a/src/corelib/tools/qiterator.qdoc +++ b/src/corelib/tools/qiterator.qdoc @@ -165,7 +165,7 @@ position between the second and third item, and returns the second item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's how to iterate over the elements in reverse order: @@ -211,7 +211,7 @@ position between the second and third item, returning the second item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items If you want to find all occurrences of a particular value, use findNext() in a loop. @@ -260,7 +260,7 @@ position between the second and third item, returning the second item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's how to iterate over the elements in reverse order: @@ -321,7 +321,7 @@ position between the second and third item, returning the second item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items If you want to remove items as you iterate over the set, use remove(). @@ -718,7 +718,7 @@ next() advances the iterator to the position between the second and third item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's how to iterate over the elements in reverse order: @@ -768,7 +768,7 @@ next() advances the iterator to the position between the second and third item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's how to iterate over the elements in reverse order: @@ -819,7 +819,7 @@ next() advances the iterator to the position between the second and third item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items If you want to find all occurrences of a particular value, use findNext() in a loop. For example: @@ -867,7 +867,7 @@ next() advances the iterator to the position between the second and third item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's how to iterate over the elements in reverse order: @@ -931,7 +931,7 @@ next() advances the iterator to the position between the second and third item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items Here's how to iterate over the elements in reverse order: @@ -994,7 +994,7 @@ next() advances the iterator to the position between the second and third item; and so on. - \image javaiterators1.png + \image javaiterators1.svg Java-style iterators point between items If you want to find all occurrences of a particular value, use findNext() in a loop. For example: diff --git a/src/corelib/tools/quniquehandle_p.h b/src/corelib/tools/quniquehandle_p.h index 3ba557e838d..fd6ab693912 100644 --- a/src/corelib/tools/quniquehandle_p.h +++ b/src/corelib/tools/quniquehandle_p.h @@ -18,6 +18,7 @@ #include <QtCore/qtconfigmacros.h> #include <QtCore/qassert.h> #include <QtCore/qcompare.h> +#include <QtCore/qfunctionaltools_impl.h> #include <QtCore/qswap.h> #include <QtCore/qtclasshelpermacros.h> @@ -99,6 +100,42 @@ QT_BEGIN_NAMESPACE ... + Example 3: + + struct TempFileTraits { + using Type = FILE*; + + static Type invalidValue() { + return nullptr; + } + + static bool close(Type handle) { + return fclose(handle) == 0; + } + }; + + struct TempFileDeleter { + using Type = TempFileTraits::Type; + + void operator()(Type handle) { + if (handle != TempFileTraits::invalidValue()) { + TempFileTraits::close(handle); + if (path) + remove(path); + } + } + + const char* path{ nullptr }; + }; + + using TempFileHandle = QUniqueHandle<TempFileTraits, TempFileDeleter>; + + Usage: + + TempFileHandle tempFile(fopen("temp.bin", "wb"), TempFileDeleter{ "my_temp.bin" }); + + ... + NOTE: The QUniqueHandle assumes that closing a resource is guaranteed to succeed, and provides no support for handling failure to close a resource. It is therefore only recommended for use cases @@ -108,9 +145,32 @@ QT_BEGIN_NAMESPACE // clang-format off +namespace QtUniqueHandleTraits { + template <typename HandleTraits> -class QUniqueHandle +struct DefaultDeleter { + using Type = typename HandleTraits::Type; + + void operator()(Type handle) const noexcept + { + if (handle != HandleTraits::invalidValue()) { + const bool success = HandleTraits::close(handle); + Q_ASSERT(success); + } + } +}; + +} // namespace QtUniqueHandleTraits + +template <typename HandleTraits, typename Deleter = QtUniqueHandleTraits::DefaultDeleter<HandleTraits>> +class QUniqueHandle : private QtPrivate::CompactStorage<Deleter> +{ + using Storage = QtPrivate::CompactStorage<Deleter>; + + template <typename D> + using if_default_constructible = std::enable_if_t<std::is_default_constructible_v<D>, bool>; + public: using Type = typename HandleTraits::Type; static_assert(std::is_nothrow_default_constructible_v<Type>); @@ -120,6 +180,11 @@ public: static_assert(std::is_nothrow_copy_assignable_v<Type>); static_assert(std::is_nothrow_move_assignable_v<Type>); static_assert(std::is_nothrow_destructible_v<Type>); + static_assert(std::is_nothrow_copy_constructible_v<Deleter>); + static_assert(std::is_nothrow_move_constructible_v<Deleter>); + static_assert(std::is_nothrow_copy_assignable_v<Deleter>); + static_assert(std::is_nothrow_move_assignable_v<Deleter>); + static_assert(std::is_nothrow_destructible_v<Deleter>); static_assert(noexcept(std::declval<Type>() == std::declval<Type>())); static_assert(noexcept(std::declval<Type>() != std::declval<Type>())); static_assert(noexcept(std::declval<Type>() < std::declval<Type>())); @@ -127,16 +192,24 @@ public: static_assert(noexcept(std::declval<Type>() > std::declval<Type>())); static_assert(noexcept(std::declval<Type>() >= std::declval<Type>())); - QUniqueHandle() = default; - - explicit QUniqueHandle(const Type &handle) noexcept + template <if_default_constructible<Deleter> = true> + explicit QUniqueHandle(const Type& handle = HandleTraits::invalidValue()) noexcept : m_handle{ handle } {} - QUniqueHandle(QUniqueHandle &&other) noexcept - : m_handle{ other.release() } + QUniqueHandle(const Type &handle, const Deleter &deleter) noexcept + : Storage{ deleter }, m_handle{ handle } + {} + + QUniqueHandle(const Type &handle, Deleter &&deleter) noexcept + : Storage{ std::move(deleter) }, m_handle{ handle } {} + QUniqueHandle(QUniqueHandle &&other) noexcept + : Storage{ std::move(other.deleter()) }, m_handle{ other.release() } + { + } + ~QUniqueHandle() noexcept { close(); @@ -145,6 +218,7 @@ public: void swap(QUniqueHandle &other) noexcept { qSwap(m_handle, other.m_handle); + qSwap(deleter(), other.deleter()); } QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QUniqueHandle) @@ -168,6 +242,16 @@ public: return m_handle; } + [[nodiscard]] Deleter& deleter() noexcept + { + return Storage::object(); + } + + [[nodiscard]] const Deleter& deleter() const noexcept + { + return Storage::object(); + } + void reset(const Type& handle = HandleTraits::invalidValue()) noexcept { if (handle == m_handle) @@ -193,8 +277,7 @@ public: if (!isValid()) return; - const bool success = HandleTraits::close(m_handle); - Q_ASSERT(success); + deleter()(m_handle); m_handle = HandleTraits::invalidValue(); } @@ -222,8 +305,8 @@ private: // clang-format on -template <typename Trait> -void swap(QUniqueHandle<Trait> &lhs, QUniqueHandle<Trait> &rhs) noexcept +template <typename Trait, typename Deleter> +void swap(QUniqueHandle<Trait, Deleter> &lhs, QUniqueHandle<Trait, Deleter> &rhs) noexcept { lhs.swap(rhs); } diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index ae730a9b3af..7b1e76cc78f 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -1146,6 +1146,33 @@ Q_IMPL_POINTER_EVENT(QHoverEvent) */ /*! + \property QWheelEvent::device + \brief the device from which the wheel event originated + + \sa pointingDevice() +*/ + +/*! + \property QWheelEvent::inverted + \since 5.7 + \brief whether the delta values delivered with the event are inverted + + Normally, a vertical wheel will produce a QWheelEvent with positive delta + values if the top of the wheel is rotating away from the hand operating it. + Similarly, a horizontal wheel movement will produce a QWheelEvent with + positive delta values if the top of the wheel is moved to the left. + + However, on some platforms this is configurable, so that the same + operations described above will produce negative delta values (but with the + same magnitude). With the inverted property a wheel event consumer can + choose to always follow the direction of the wheel, regardless of the + system settings, but only for specific widgets. + + \note Many platforms provide no such information. On such platforms + \l inverted always returns false. +*/ + +/*! \fn bool QWheelEvent::inverted() const \since 5.7 @@ -1236,6 +1263,24 @@ bool QWheelEvent::isEndEvent() const #endif // QT_CONFIG(wheelevent) /*! + \property QWheelEvent::pixelDelta + \brief the scrolling distance in pixels on screen + + This value is provided on platforms that support high-resolution + pixel-based delta values, such as \macos. The value should be used + directly to scroll content on screen. + + \note On platforms that support scrolling \l{phase()}{phases}, the delta + may be null when scrolling is about to begin (Qt::ScrollBegin) or has + ended (Qt::ScrollEnd). + + \note On X11 this value is driver-specific and unreliable, use + angleDelta() instead. + + \sa angleDelta() +*/ + +/*! \fn QPoint QWheelEvent::pixelDelta() const Returns the scrolling distance in pixels on screen. This value is @@ -1256,6 +1301,27 @@ bool QWheelEvent::isEndEvent() const */ /*! + \property QWheelEvent::angleDelta + \brief the relative amount that the wheel was rotated, in eighths of a degree + + A positive value indicates that the wheel was rotated forwards away from the + user; a negative value indicates that the wheel was rotated backwards toward + the user. \c angleDelta().y() provides the angle through which the common + vertical mouse wheel was rotated since the previous event. \c angleDelta().x() + provides the angle through which the horizontal mouse wheel was rotated, if + the mouse has a horizontal wheel; otherwise it stays at zero. + + Most mouse types work in steps of 15 degrees, in which case the delta value + is a multiple of 120; i.e., 120 units * 1/8 = 15 degrees. + + \note On platforms that support scrolling \l{phase()}{phases}, the delta + may be null when scrolling is about to begin (Qt::ScrollBegin) or has + ended (Qt::ScrollEnd). + + \sa pixelDelta() +*/ + +/*! \fn QPoint QWheelEvent::angleDelta() const Returns the relative amount that the wheel was rotated, in eighths of a @@ -1294,6 +1360,15 @@ bool QWheelEvent::isEndEvent() const */ /*! + \property QWheelEvent::phase + \since 5.2 + \brief the scrolling phase of this wheel event + + \note The Qt::ScrollBegin and Qt::ScrollEnd phases are currently + supported only on \macos. +*/ + +/*! \fn Qt::ScrollPhase QWheelEvent::phase() const \since 5.2 diff --git a/src/gui/kernel/qinputdevice.cpp b/src/gui/kernel/qinputdevice.cpp index 8e5c38922e0..caed0fc6135 100644 --- a/src/gui/kernel/qinputdevice.cpp +++ b/src/gui/kernel/qinputdevice.cpp @@ -187,6 +187,11 @@ QString QInputDevice::name() const } /*! + \property QInputDevice::type + \brief the device type +*/ + +/*! Returns the device type. */ QInputDevice::DeviceType QInputDevice::type() const diff --git a/src/gui/kernel/qpointingdevice.cpp b/src/gui/kernel/qpointingdevice.cpp index dcce354688a..7062340b287 100644 --- a/src/gui/kernel/qpointingdevice.cpp +++ b/src/gui/kernel/qpointingdevice.cpp @@ -241,6 +241,11 @@ void QPointingDevice::setMaximumTouchPoints(int c) #endif // QT_DEPRECATED_SINCE(6, 0) /*! + \property QPointingDevice::pointerType + \brief the pointer type +*/ + +/*! Returns the pointer type. */ QPointingDevice::PointerType QPointingDevice::pointerType() const @@ -250,6 +255,12 @@ QPointingDevice::PointerType QPointingDevice::pointerType() const } /*! + \property QPointingDevice::maximumPoints + \brief the maximum number of simultaneous touch points (fingers) that + can be detected +*/ + +/*! Returns the maximum number of simultaneous touch points (fingers) that can be detected. */ @@ -260,6 +271,11 @@ int QPointingDevice::maximumPoints() const } /*! + \property QPointingDevice::buttonCount + \brief the maximum number of on-device buttons that can be detected +*/ + +/*! Returns the maximum number of on-device buttons that can be detected. */ int QPointingDevice::buttonCount() const @@ -269,6 +285,13 @@ int QPointingDevice::buttonCount() const } /*! + \property QPointingDevice::uniqueId + \brief a unique ID (of dubious utility) for the device + + You probably should rather be concerned with QPointerEventPoint::uniqueId(). +*/ + +/*! Returns a unique ID (of dubious utility) for the device. You probably should rather be concerned with QPointerEventPoint::uniqueId(). diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 62b7ab6efb0..5590f2fb431 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -7186,6 +7186,26 @@ QRhiResource::Type QRhiGraphicsPipeline::resourceType() const */ /*! + \fn bool QRhiGraphicsPipeline::hasDepthClamp() const + \return true if depth clamp is enabled. + + \since 6.11 + */ + +/*! + \fn void QRhiGraphicsPipeline::setDepthClamp(bool enable) + + Enables depth clamping when \a enable is true. When depth clamping is + enabled, primitives that would otherwise be clipped by the near or far + clip plane are rasterized and their depth values are clamped to the + depth range. When disabled (the default), such primitives are clipped. + + \note This setting is ignored on OpenGL ES. + + \since 6.11 + */ + +/*! \fn QRhiGraphicsPipeline::CompareOp QRhiGraphicsPipeline::depthOp() const \return the depth comparison function. */ diff --git a/src/gui/rhi/qrhi.h b/src/gui/rhi/qrhi.h index b5a3f7b43be..5ee2a9acd13 100644 --- a/src/gui/rhi/qrhi.h +++ b/src/gui/rhi/qrhi.h @@ -1453,6 +1453,9 @@ public: bool hasDepthWrite() const { return m_depthWrite; } void setDepthWrite(bool enable) { m_depthWrite = enable; } + bool hasDepthClamp() const { return m_depthClamp; } + void setDepthClamp(bool enable) { m_depthClamp = enable; } + CompareOp depthOp() const { return m_depthOp; } void setDepthOp(CompareOp op) { m_depthOp = op; } @@ -1524,6 +1527,7 @@ protected: QVarLengthArray<TargetBlend, 8> m_targetBlends; bool m_depthTest = false; bool m_depthWrite = false; + bool m_depthClamp = false; CompareOp m_depthOp = Less; bool m_stencilTest = false; StencilOpState m_stencilFront; diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index a5f860e7724..1441be24043 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -4673,7 +4673,7 @@ bool QD3D11GraphicsPipeline::create() rastDesc.FrontCounterClockwise = m_frontFace == CCW; rastDesc.DepthBias = m_depthBias; rastDesc.SlopeScaledDepthBias = m_slopeScaledDepthBias; - rastDesc.DepthClipEnable = true; + rastDesc.DepthClipEnable = m_depthClamp ? FALSE : TRUE; rastDesc.ScissorEnable = m_flags.testFlag(UsesScissor); rastDesc.MultisampleEnable = rhiD->effectiveSampleDesc(m_sampleCount).Count > 1; HRESULT hr = rhiD->dev->CreateRasterizerState(&rastDesc, &rastState); diff --git a/src/gui/rhi/qrhid3d12.cpp b/src/gui/rhi/qrhid3d12.cpp index 4f09b3c136b..b68b65b1063 100644 --- a/src/gui/rhi/qrhid3d12.cpp +++ b/src/gui/rhi/qrhid3d12.cpp @@ -6263,7 +6263,7 @@ bool QD3D12GraphicsPipeline::create() stream.rasterizerState.object.FrontCounterClockwise = m_frontFace == CCW; stream.rasterizerState.object.DepthBias = m_depthBias; stream.rasterizerState.object.SlopeScaledDepthBias = m_slopeScaledDepthBias; - stream.rasterizerState.object.DepthClipEnable = TRUE; + stream.rasterizerState.object.DepthClipEnable = m_depthClamp ? FALSE : TRUE; stream.rasterizerState.object.MultisampleEnable = sampleDesc.Count > 1; stream.depthStencilState.object.DepthEnable = m_depthTest; diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 15f5cd8f7e8..1308d4362e5 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -585,6 +585,10 @@ QT_BEGIN_NAMESPACE #define GL_PROGRAM 0x82E2 #endif +#ifndef GL_DEPTH_CLAMP +#define GL_DEPTH_CLAMP 0x864F +#endif + /*! Constructs a new QRhiGles2InitParams. @@ -998,6 +1002,13 @@ bool QRhiGles2::create(QRhi::Flags flags) } if (caps.gles) + caps.depthClamp = false; + else + caps.depthClamp = caps.ctxMajor > 3 || (caps.ctxMajor == 3 && caps.ctxMinor >= 2); // Desktop 3.2 + if (!caps.depthClamp) + caps.depthClamp = ctx->hasExtension("GL_EXT_depth_clamp") || ctx->hasExtension("GL_ARB_depth_clamp"); + + if (caps.gles) caps.textureCompareMode = caps.ctxMajor >= 3; // ES 3.0 else caps.textureCompareMode = true; @@ -3959,6 +3970,7 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) break; case QGles2CommandBuffer::Command::InvalidateFramebuffer: if (caps.gles && caps.ctxMajor >= 3) { + f->glBindFramebuffer(GL_FRAMEBUFFER, cmd.args.invalidateFramebuffer.fbo); f->glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, cmd.args.invalidateFramebuffer.attCount, cmd.args.invalidateFramebuffer.att); @@ -4095,6 +4107,15 @@ void QRhiGles2::executeBindGraphicsPipeline(QGles2CommandBuffer *cbD, QGles2Grap f->glDepthMask(depthWrite); } + const bool depthClamp = psD->m_depthClamp; + if (caps.depthClamp && (forceUpdate || depthClamp != state.depthClamp)) { + state.depthClamp = depthClamp; + if (depthClamp) + f->glEnable(GL_DEPTH_CLAMP); + else + f->glDisable(GL_DEPTH_CLAMP); + } + const GLenum depthFunc = toGlCompareOp(psD->m_depthOp); if (forceUpdate || depthFunc != state.depthFunc) { state.depthFunc = depthFunc; @@ -4881,6 +4902,7 @@ void QRhiGles2::endPass(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resource if (mayDiscardDepthStencil) { QGles2CommandBuffer::Command &cmd(cbD->commands.get()); cmd.cmd = QGles2CommandBuffer::Command::InvalidateFramebuffer; + cmd.args.invalidateFramebuffer.fbo = rtTex->framebuffer; if (caps.needsDepthStencilCombinedAttach) { cmd.args.invalidateFramebuffer.attCount = 1; cmd.args.invalidateFramebuffer.att[0] = GL_DEPTH_STENCIL_ATTACHMENT; diff --git a/src/gui/rhi/qrhigles2_p.h b/src/gui/rhi/qrhigles2_p.h index 725e71a3665..70dd96a8dc7 100644 --- a/src/gui/rhi/qrhigles2_p.h +++ b/src/gui/rhi/qrhigles2_p.h @@ -547,6 +547,7 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer GLbitfield barriers; } barrier; struct { + GLuint fbo; int attCount; GLenum att[3]; } invalidateFramebuffer; @@ -592,6 +593,7 @@ struct QGles2CommandBuffer : public QRhiCommandBuffer } blend[16]; bool depthTest; bool depthWrite; + bool depthClamp; GLenum depthFunc; bool stencilTest; GLuint stencilReadMask; @@ -1074,6 +1076,7 @@ public: uint baseVertex : 1; uint compute : 1; uint textureCompareMode : 1; + uint depthClamp : 1; uint properMapBuffer : 1; uint nonBaseLevelFramebufferTexture : 1; uint texelFetch : 1; diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index c3f1031b44b..7fa05f69232 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -403,6 +403,7 @@ struct QMetalGraphicsPipelineData MTLWinding winding; MTLCullMode cullMode; MTLTriangleFillMode triangleFillMode; + MTLDepthClipMode depthClipMode; float depthBias; float slopeScaledDepthBias; QMetalShader vs; @@ -1477,7 +1478,6 @@ void QMetalGraphicsPipeline::makeActiveForCurrentRenderPassEncoder(QMetalCommand [cbD->d->currentRenderPassEncoder setDepthStencilState: d->ds]; cbD->d->currentDepthStencilState = d->ds; } - if (cbD->currentCullMode == -1 || d->cullMode != uint(cbD->currentCullMode)) { [cbD->d->currentRenderPassEncoder setCullMode: d->cullMode]; cbD->currentCullMode = int(d->cullMode); @@ -1486,6 +1486,10 @@ void QMetalGraphicsPipeline::makeActiveForCurrentRenderPassEncoder(QMetalCommand [cbD->d->currentRenderPassEncoder setTriangleFillMode: d->triangleFillMode]; cbD->currentTriangleFillMode = int(d->triangleFillMode); } + if (cbD->currentDepthClipMode == -1 || d->depthClipMode != uint(cbD->currentDepthClipMode)) { + [cbD->d->currentRenderPassEncoder setDepthClipMode: d->depthClipMode]; + cbD->currentDepthClipMode = int(d->depthClipMode); + } if (cbD->currentFrontFaceWinding == -1 || d->winding != uint(cbD->currentFrontFaceWinding)) { [cbD->d->currentRenderPassEncoder setFrontFacingWinding: d->winding]; cbD->currentFrontFaceWinding = int(d->winding); @@ -5035,6 +5039,7 @@ void QMetalGraphicsPipeline::mapStates() d->winding = m_frontFace == CCW ? MTLWindingCounterClockwise : MTLWindingClockwise; d->cullMode = toMetalCullMode(m_cullMode); d->triangleFillMode = toMetalTriangleFillMode(m_polygonMode); + d->depthClipMode = m_depthClamp ? MTLDepthClipModeClamp : MTLDepthClipModeClip; d->depthBias = float(m_depthBias); d->slopeScaledDepthBias = m_slopeScaledDepthBias; } @@ -6257,6 +6262,7 @@ void QMetalCommandBuffer::resetPerPassCachedState() currentIndexFormat = QRhiCommandBuffer::IndexUInt16; currentCullMode = -1; currentTriangleFillMode = -1; + currentDepthClipMode = -1; currentFrontFaceWinding = -1; currentDepthBiasValues = { 0.0f, 0.0f }; diff --git a/src/gui/rhi/qrhimetal_p.h b/src/gui/rhi/qrhimetal_p.h index 7c19ae9e767..6649a6cd304 100644 --- a/src/gui/rhi/qrhimetal_p.h +++ b/src/gui/rhi/qrhimetal_p.h @@ -299,6 +299,7 @@ struct QMetalCommandBuffer : public QRhiCommandBuffer QRhiCommandBuffer::IndexFormat currentIndexFormat; int currentCullMode; int currentTriangleFillMode; + int currentDepthClipMode; int currentFrontFaceWinding; std::pair<float, float> currentDepthBiasValues; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index c5167a6e7de..481ffd57b5d 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -949,6 +949,8 @@ bool QRhiVulkan::create(QRhi::Flags flags) // elsewhere states that the minimum bufferOffset is 4... texbufAlign = qMax<VkDeviceSize>(4, physDevProperties.limits.optimalBufferCopyOffsetAlignment); + caps.depthClamp = physDevFeatures.depthClamp; + caps.wideLines = physDevFeatures.wideLines; caps.texture3DSliceAs2D = caps.apiVersion >= QVersionNumber(1, 1); @@ -8402,6 +8404,8 @@ bool QVkGraphicsPipeline::create() VkPipelineRasterizationStateCreateInfo rastInfo = {}; rastInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + if (m_depthClamp && rhiD->caps.depthClamp) + rastInfo.depthClampEnable = m_depthClamp; rastInfo.cullMode = toVkCullMode(m_cullMode); rastInfo.frontFace = toVkFrontFace(m_frontFace); if (m_depthBias != 0 || !qFuzzyIsNull(m_slopeScaledDepthBias)) { diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h index d141a84c5fb..1e9318513fd 100644 --- a/src/gui/rhi/qrhivulkan_p.h +++ b/src/gui/rhi/qrhivulkan_p.h @@ -936,6 +936,7 @@ public: struct { bool compute = false; + bool depthClamp = false; bool wideLines = false; bool debugUtils = false; bool vertexAttribDivisor = false; diff --git a/src/gui/text/qfontvariableaxis.cpp b/src/gui/text/qfontvariableaxis.cpp index be83a3e02ce..bbc14f4cd11 100644 --- a/src/gui/text/qfontvariableaxis.cpp +++ b/src/gui/text/qfontvariableaxis.cpp @@ -60,6 +60,18 @@ QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QFontVariableAxisPrivate) QFontVariableAxis::QFontVariableAxis(const QFontVariableAxis &axis) = default; /*! + \property QFontVariableAxis::tag + \brief the tag of the axis + + This is a four-character sequence which identifies the axis. Certain tags + have standardized meanings, such as "wght" (weight) and "wdth" (width), + but any sequence of four latin-1 characters is a valid tag. By convention, + non-standard/custom axes are denoted by tags in all uppercase. + + \sa QFont::setVariableAxis(), name() +*/ + +/*! Returns the tag of the axis. This is a four-character sequence which identifies the axis. Certain tags have standardized meanings, such as "wght" (weight) and "wdth" (width), but any sequence of four latin-1 characters is a valid tag. By convention, non-standard/custom axes @@ -91,6 +103,13 @@ void QFontVariableAxis::setTag(QFont::Tag tag) } /*! + \property QFontVariableAxis::name + \brief the name of the axis, if provided by the font + + \sa tag() +*/ + +/*! Returns the name of the axis, if provided by the font. \sa tag() @@ -153,6 +172,15 @@ void QFontVariableAxis::setMinimumValue(qreal minimumValue) } /*! + \property QFontVariableAxis::maximumValue + \brief the maximum value of the axis + + Setting the axis to a value which is higher than this is not supported. + + \sa minimumValue(), defaultValue() +*/ + +/*! Returns the maximum value of the axis. Setting the axis to a value which is higher than this is not supported. @@ -182,6 +210,16 @@ void QFontVariableAxis::setMaximumValue(qreal maximumValue) } /*! + \property QFontVariableAxis::defaultValue + \brief the default value of the axis + + This is the value the axis will have if none has been provided in the + QFont query. + + \sa minimumValue(), maximumValue() +*/ + +/*! Returns the default value of the axis. This is the value the axis will have if none has been provided in the QFont query. diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp index 3452d0a448e..dbcccd8e943 100644 --- a/src/network/access/qhttp2protocolhandler.cpp +++ b/src/network/access/qhttp2protocolhandler.cpp @@ -333,10 +333,16 @@ void QHttp2ProtocolHandler::handleHeadersReceived(const HPack::HttpHeader &heade // of parsing and related errors/bugs, but it would be nice to have // more detailed validation of headers. if (name == ":status") { - statusCode = value.left(3).toInt(); - httpReply->setStatusCode(statusCode); - m_channel->lastStatus = statusCode; // Mostly useless for http/2, needed for auth - httpReply->setReasonPhrase(QString::fromLatin1(value.mid(4))); + bool ok = false; + if (int status = value.toInt(&ok); ok && status >= 0 && status <= 999) { + statusCode = status; + httpReply->setStatusCode(statusCode); + m_channel->lastStatus = statusCode; // Mostly useless for http/2, needed for auth + } else { + finishStreamWithError(stream, QNetworkReply::ProtocolInvalidOperationError, + "invalid :status value"_L1); + return; + } } else if (name == "content-length") { bool ok = false; const qlonglong length = value.toLongLong(&ok); diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index f680950701c..f76d79571c3 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -272,6 +272,11 @@ void QNetworkReplyHttpImpl::close() void QNetworkReplyHttpImpl::abort() { + abortImpl(QNetworkReply::OperationCanceledError); +} + +void QNetworkReplyHttpImpl::abortImpl(QNetworkReply::NetworkError error) +{ Q_D(QNetworkReplyHttpImpl); // FIXME if (d->state == QNetworkReplyPrivate::Finished || d->state == QNetworkReplyPrivate::Aborted) @@ -282,7 +287,8 @@ void QNetworkReplyHttpImpl::abort() if (d->state != QNetworkReplyPrivate::Finished) { // call finished which will emit signals // FIXME shouldn't this be emitted Queued? - d->error(OperationCanceledError, tr("Operation canceled")); + d->error(error, + error == TimeoutError ? tr("Operation timed out") : tr("Operation canceled")); d->finished(); } @@ -2120,7 +2126,7 @@ void QNetworkReplyHttpImplPrivate::_q_bufferOutgoingData() void QNetworkReplyHttpImplPrivate::_q_transferTimedOut() { Q_Q(QNetworkReplyHttpImpl); - q->abort(); + q->abortImpl(QNetworkReply::TimeoutError); } void QNetworkReplyHttpImplPrivate::setupTransferTimeout() @@ -2242,8 +2248,10 @@ void QNetworkReplyHttpImplPrivate::error(QNetworkReplyImpl::NetworkError code, c // Can't set and emit multiple errors. if (errorCode != QNetworkReply::NoError) { // But somewhat unavoidable if we have cancelled the request: - if (errorCode != QNetworkReply::OperationCanceledError) + if (errorCode != QNetworkReply::OperationCanceledError + && errorCode != QNetworkReply::TimeoutError) { qWarning("QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once."); + } return; } diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index 0d16d02ff53..a354b388ad6 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -59,6 +59,7 @@ public: void close() override; void abort() override; + void abortImpl(QNetworkReply::NetworkError error); qint64 bytesAvailable() const override; bool isSequential () const override; qint64 size() const override; diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index e0ef6cec794..4c4e5fac962 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -491,7 +491,7 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions; return; if (m_panel.visible) { - const QString selection = QString::fromNSString(m_panel.URL.path); + const QString selection = QString::fromNSString(m_panel.URL.path).normalized(QString::NormalizationForm_C); if (selection != m_currentSelection) { m_currentSelection = selection; emit m_helper->currentChanged(QUrl::fromLocalFile(selection)); diff --git a/src/plugins/platforms/cocoa/qcocoamessagedialog.mm b/src/plugins/platforms/cocoa/qcocoamessagedialog.mm index dab348beaa4..7a6f010ba8f 100644 --- a/src/plugins/platforms/cocoa/qcocoamessagedialog.mm +++ b/src/plugins/platforms/cocoa/qcocoamessagedialog.mm @@ -88,6 +88,11 @@ bool QCocoaMessageDialog::show(Qt::WindowFlags windowFlags, Qt::WindowModality w return false; } + // Tahoe has issues with window-modal alert buttons not responding to mouse + if (windowModality == Qt::WindowModal + && QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSTahoe) + return false; + // And without options we don't know what to show if (!options()) return false; diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.cpp b/src/plugins/platforms/wasm/qwasmaccessibility.cpp index a87c33c8346..eb36f7351d0 100644 --- a/src/plugins/platforms/wasm/qwasmaccessibility.cpp +++ b/src/plugins/platforms/wasm/qwasmaccessibility.cpp @@ -322,6 +322,16 @@ void QWasmAccessibility::setProperty(emscripten::val element, const std::string element.set(property, val); } +void QWasmAccessibility::setNamedAttribute(QAccessibleInterface *iface, const std::string &attribute, QAccessible::Text text) +{ + const emscripten::val element = getHtmlElement(iface); + setAttribute(element, attribute, iface->text(text).toStdString()); +} +void QWasmAccessibility::setNamedProperty(QAccessibleInterface *iface, const std::string &property, QAccessible::Text text) +{ + const emscripten::val element = getHtmlElement(iface); + setProperty(element, property, iface->text(text).toStdString()); +} void QWasmAccessibility::addEventListener(QAccessibleInterface *iface, emscripten::val element, const char *eventType) { @@ -331,6 +341,17 @@ void QWasmAccessibility::addEventListener(QAccessibleInterface *iface, emscripte true); } +void QWasmAccessibility::sendEvent(QAccessibleInterface *iface, QAccessible::Event eventType) +{ + if (iface->object()) { + QAccessibleEvent event(iface->object(), eventType); + handleUpdateByInterfaceRole(&event); + } else { + QAccessibleEvent event(iface, eventType); + handleUpdateByInterfaceRole(&event); + } +} + emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *iface) { // Get the html container element for the interface; this depends on which @@ -484,11 +505,11 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac m_elements[iface] = element; setHtmlElementGeometry(iface); - setHtmlElementTextName(iface); setHtmlElementDisabled(iface); setHtmlElementVisibility(iface, !iface->state().invisible); handleIdentifierUpdate(iface); handleDescriptionChanged(iface); + sendEvent(iface, QAccessible::NameChanged); linkToParent(iface); // Link in child elements @@ -586,14 +607,7 @@ void QWasmAccessibility::linkToParent(QAccessibleInterface *iface) void QWasmAccessibility::setHtmlElementVisibility(QAccessibleInterface *iface, bool visible) { emscripten::val element = getHtmlElement(iface); - - if (visible) { - setAttribute(element, "aria-hidden", false); - setAttribute(element, "tabindex", ""); - } else { - setAttribute(element, "aria-hidden", true); // aria-hidden mean completely hidden; maybe some sort of soft-hidden should be used. - setAttribute(element, "tabindex", "-1"); - } + setAttribute(element, "aria-hidden", !visible); } void QWasmAccessibility::setHtmlElementGeometry(QAccessibleInterface *iface) @@ -631,28 +645,6 @@ void QWasmAccessibility::setHtmlElementGeometry(emscripten::val element, QRect g style.set("height", std::to_string(geometry.height()) + "px"); } -void QWasmAccessibility::setHtmlElementTextName(QAccessibleInterface *iface) -{ - const emscripten::val element = getHtmlElement(iface); - const QString name = iface->text(QAccessible::Name); - const QString value = iface->text(QAccessible::Value); - - // A <div> cannot contain aria-label - if (iface->role() == QAccessible::StaticText) - setProperty(element, "innerText", name.toStdString()); - else if (iface->role() == QAccessible::EditableText) - setProperty(element, "value", value.toStdString()); - else - setAttribute(element, "aria-label", name.toStdString()); -} - -void QWasmAccessibility::setHtmlElementTextNameLE(QAccessibleInterface *iface) -{ - const emscripten::val element = getHtmlElement(iface); - QString value = iface->text(QAccessible::Value); - setProperty(element, "value", value.toStdString()); -} - void QWasmAccessibility::setHtmlElementFocus(QAccessibleInterface *iface) { const auto element = getHtmlElement(iface); @@ -684,7 +676,8 @@ void QWasmAccessibility::handleStaticTextUpdate(QAccessibleEvent *event) { switch (event->type()) { case QAccessible::NameChanged: { - setHtmlElementTextName(event->accessibleInterface()); + // StaticText is a div + setNamedProperty(event->accessibleInterface(), "innerText", QAccessible::Name); } break; default: qCDebug(lcQpaAccessibility) << "TODO: implement handleStaticTextUpdate for event" << event->type(); @@ -705,7 +698,7 @@ void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event) setProperty(element, "type", "text"); } break; case QAccessible::NameChanged: { - setHtmlElementTextName(event->accessibleInterface()); + setNamedProperty(event->accessibleInterface(), "value", QAccessible::Value); } break; case QAccessible::ObjectShow: case QAccessible::Focus: { @@ -718,12 +711,12 @@ void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event) else setProperty(element, "type", "text"); } - setHtmlElementTextNameLE(iface); + setNamedProperty(event->accessibleInterface(), "value", QAccessible::Value); } break; case QAccessible::TextRemoved: case QAccessible::TextInserted: case QAccessible::TextCaretMoved: { - setHtmlElementTextNameLE(event->accessibleInterface()); + setNamedProperty(event->accessibleInterface(), "value", QAccessible::Value); } break; default: qCDebug(lcQpaAccessibility) << "TODO: implement handleLineEditUpdate for event" << event->type(); @@ -758,7 +751,15 @@ void QWasmAccessibility::handleEventFromHtmlElement(const emscripten::val event) void QWasmAccessibility::handleButtonUpdate(QAccessibleEvent *event) { - qCDebug(lcQpaAccessibility) << "TODO: implement handleButtonUpdate for event" << event->type(); + switch (event->type()) { + case QAccessible::Focus: + case QAccessible::NameChanged: { + setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name); + } break; + default: + qCDebug(lcQpaAccessibility) << "TODO: implement handleCheckBoxUpdate for event" << event->type(); + break; + } } void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event) @@ -766,7 +767,7 @@ void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event) switch (event->type()) { case QAccessible::Focus: case QAccessible::NameChanged: { - setHtmlElementTextName(event->accessibleInterface()); + setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name); } break; case QAccessible::StateChanged: { QAccessibleInterface *accessible = event->accessibleInterface(); @@ -785,7 +786,8 @@ void QWasmAccessibility::handleSwitchUpdate(QAccessibleEvent *event) switch (event->type()) { case QAccessible::Focus: case QAccessible::NameChanged: { - setHtmlElementTextName(event->accessibleInterface()); + /* A switch is like a button in this regard */ + setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name); } break; case QAccessible::StateChanged: { QAccessibleInterface *accessible = event->accessibleInterface(); @@ -848,7 +850,7 @@ void QWasmAccessibility::handleDialogUpdate(QAccessibleEvent *event) { case QAccessible::Focus: case QAccessible::DialogStart: case QAccessible::StateChanged: { - setHtmlElementTextName(event->accessibleInterface()); + setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name); } break; default: qCDebug(lcQpaAccessibility) << "TODO: implement handleLineEditUpdate for event" << event->type(); @@ -876,10 +878,10 @@ void QWasmAccessibility::populateAccessibilityTree(QAccessibleInterface *iface) linkToParent(iface); setHtmlElementVisibility(iface, !iface->state().invisible); setHtmlElementGeometry(iface); - setHtmlElementTextName(iface); setHtmlElementDisabled(iface); handleIdentifierUpdate(iface); handleDescriptionChanged(iface); + sendEvent(iface, QAccessible::NameChanged); } } for (int i = 0; i < iface->childCount(); ++i) @@ -891,7 +893,7 @@ void QWasmAccessibility::handleRadioButtonUpdate(QAccessibleEvent *event) switch (event->type()) { case QAccessible::Focus: case QAccessible::NameChanged: { - setHtmlElementTextName(event->accessibleInterface()); + setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name); } break; case QAccessible::StateChanged: { QAccessibleInterface *accessible = event->accessibleInterface(); @@ -912,7 +914,7 @@ void QWasmAccessibility::handleSpinBoxUpdate(QAccessibleEvent *event) } break; case QAccessible::Focus: case QAccessible::NameChanged: { - setHtmlElementTextName(event->accessibleInterface()); + setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name); } break; case QAccessible::ValueChanged: { QAccessibleInterface *accessible = event->accessibleInterface(); @@ -934,7 +936,7 @@ void QWasmAccessibility::handleSliderUpdate(QAccessibleEvent *event) } break; case QAccessible::Focus: case QAccessible::NameChanged: { - setHtmlElementTextName(event->accessibleInterface()); + setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name); } break; case QAccessible::ValueChanged: { QAccessibleInterface *accessible = event->accessibleInterface(); @@ -953,7 +955,7 @@ void QWasmAccessibility::handleScrollBarUpdate(QAccessibleEvent *event) switch (event->type()) { case QAccessible::Focus: case QAccessible::NameChanged: { - setHtmlElementTextName(event->accessibleInterface()); + setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name); } break; case QAccessible::ValueChanged: { QAccessibleInterface *accessible = event->accessibleInterface(); @@ -972,10 +974,10 @@ void QWasmAccessibility::handlePageTabUpdate(QAccessibleEvent *event) { switch (event->type()) { case QAccessible::NameChanged: { - setHtmlElementTextName(event->accessibleInterface()); + setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name); } break; case QAccessible::Focus: { - setHtmlElementTextName(event->accessibleInterface()); + setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name); } break; default: qDebug() << "TODO: implement handlePageTabUpdate for event" << event->type(); @@ -987,10 +989,10 @@ void QWasmAccessibility::handlePageTabListUpdate(QAccessibleEvent *event) { switch (event->type()) { case QAccessible::NameChanged: { - setHtmlElementTextName(event->accessibleInterface()); + setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name); } break; case QAccessible::Focus: { - setHtmlElementTextName(event->accessibleInterface()); + setNamedAttribute(event->accessibleInterface(), "aria-label", QAccessible::Name); } break; default: qDebug() << "TODO: implement handlePageTabUpdate for event" << event->type(); @@ -1113,13 +1115,19 @@ void QWasmAccessibility::relinkParentForChildren(QAccessibleInterface *iface) void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) { + if (handleUpdateByEventType(event)) + handleUpdateByInterfaceRole(event); +} + +bool QWasmAccessibility::handleUpdateByEventType(QAccessibleEvent *event) +{ if (!m_accessibilityEnabled) - return; + return false; QAccessibleInterface *iface = event->accessibleInterface(); if (!iface) { - qWarning() << "notifyAccessibilityUpdate with null a11y interface" << event->type() << event->object(); - return; + qWarning() << "handleUpdateByEventType with null a11y interface" << event->type() << event->object(); + return false; } // Handle event types that creates/removes objects. @@ -1127,13 +1135,13 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) case QAccessible::ObjectCreated: // Do nothing, there are too many changes to the interface // before ObjectShow is called - return; + return false; case QAccessible::ObjectDestroyed: // The object might be under destruction, and the interface is not valid // but we can look at the pointer, removeObject(iface); - return; + return false; case QAccessible::ObjectShow: // We do not get ObjectCreated from widgets, we get ObjectShow createObject(iface); @@ -1149,7 +1157,7 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) }; if (getHtmlElement(iface).isUndefined()) - return; + return false; // Handle some common event types. See // https://doc.qt.io/qt-5/qaccessible.html#Event-enum @@ -1162,7 +1170,7 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) case QAccessible::DescriptionChanged: handleDescriptionChanged(iface); - return; + return false; case QAccessible::Focus: // We do not get all callbacks for the geometry @@ -1173,7 +1181,7 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) case QAccessible::IdentifierChanged: handleIdentifierUpdate(iface); - return; + return false; case QAccessible::ObjectShow: linkToParent(iface); @@ -1181,23 +1189,37 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) // Sync up properties on show; setHtmlElementGeometry(iface); - setHtmlElementTextName(iface); + sendEvent(iface, QAccessible::NameChanged); break; case QAccessible::ObjectHide: linkToParent(iface); setHtmlElementVisibility(iface, false); - return; + return false; case QAccessible::LocationChanged: setHtmlElementGeometry(iface); - return; + return false; // TODO: maybe handle more types here default: break; }; + return true; +} + +void QWasmAccessibility::handleUpdateByInterfaceRole(QAccessibleEvent *event) +{ + if (!m_accessibilityEnabled) + return; + + QAccessibleInterface *iface = event->accessibleInterface(); + if (!iface) { + qWarning() << "handleUpdateByInterfaceRole with null a11y interface" << event->type() << event->object(); + return; + } + // Switch on interface role, see // https://doc.qt.io/qt-5/qaccessibleinterface.html#role switch (iface->role()) { @@ -1205,7 +1227,7 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) handleStaticTextUpdate(event); break; case QAccessible::Button: - handleStaticTextUpdate(event); + handleButtonUpdate(event); break; case QAccessible::CheckBox: handleCheckBoxUpdate(event); diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.h b/src/plugins/platforms/wasm/qwasmaccessibility.h index ddbfec918d6..f20c7db5ac3 100644 --- a/src/plugins/platforms/wasm/qwasmaccessibility.h +++ b/src/plugins/platforms/wasm/qwasmaccessibility.h @@ -73,8 +73,6 @@ private: void setHtmlElementVisibility(QAccessibleInterface *iface, bool visible); void setHtmlElementGeometry(QAccessibleInterface *iface); void setHtmlElementGeometry(emscripten::val element, QRect geometry); - void setHtmlElementTextName(QAccessibleInterface *iface); - void setHtmlElementTextNameLE(QAccessibleInterface *iface); void setHtmlElementFocus(QAccessibleInterface *iface); void setHtmlElementDisabled(QAccessibleInterface *iface); void setHtmlElementOrientation(emscripten::val element, QAccessibleInterface *iface); @@ -105,6 +103,9 @@ private: void relinkParentForChildren(QAccessibleInterface *iface); void notifyAccessibilityUpdate(QAccessibleEvent *event) override; + bool handleUpdateByEventType(QAccessibleEvent *event); + void handleUpdateByInterfaceRole(QAccessibleEvent *event); + void setRootObject(QObject *o) override; void initialize() override; void cleanup() override; @@ -117,7 +118,11 @@ private: void setProperty(emscripten::val element, const std::string &attr, const char *val); void setProperty(emscripten::val element, const std::string &attr, bool val); + void setNamedAttribute(QAccessibleInterface *iface, const std::string &attribute, QAccessible::Text text); + void setNamedProperty(QAccessibleInterface *iface, const std::string &property, QAccessible::Text text); + void addEventListener(QAccessibleInterface *, emscripten::val element, const char *eventType); + void sendEvent(QAccessibleInterface *iface, QAccessible::Event eventType); private: static QWasmAccessibility *s_instance; diff --git a/src/plugins/platforms/wayland/global/qwaylandclientextension.cpp b/src/plugins/platforms/wayland/global/qwaylandclientextension.cpp index 92c746d3541..edbeb1f72ea 100644 --- a/src/plugins/platforms/wayland/global/qwaylandclientextension.cpp +++ b/src/plugins/platforms/wayland/global/qwaylandclientextension.cpp @@ -40,6 +40,11 @@ void QWaylandClientExtensionPrivate::globalRemoved(const RegistryGlobal &global) } } +/*! + \class QWaylandClientExtension + \internal +*/ + void QWaylandClientExtension::initialize() { Q_D(QWaylandClientExtension); diff --git a/src/plugins/platforms/wayland/qwaylandinputcontext.cpp b/src/plugins/platforms/wayland/qwaylandinputcontext.cpp index 0ccc4dba57a..5ab285ad97d 100644 --- a/src/plugins/platforms/wayland/qwaylandinputcontext.cpp +++ b/src/plugins/platforms/wayland/qwaylandinputcontext.cpp @@ -192,10 +192,12 @@ void QWaylandInputContext::setFocusObject(QObject *object) if (window && window->handle()) { if (mCurrentWindow.data() != window) { if (!inputMethodAccepted()) { - auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface(); - if (surface) - inputInterface->disableSurface(surface); - mCurrentWindow.clear(); + if (mCurrentWindow) { + auto *surface = static_cast<QWaylandWindow *>(mCurrentWindow->handle())->wlSurface(); + if (surface) + inputInterface->disableSurface(surface); + mCurrentWindow.clear(); + } } else { auto *surface = static_cast<QWaylandWindow *>(window->handle())->wlSurface(); if (surface) { diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 1c3a3909bc2..15ab167c83f 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -179,9 +179,6 @@ QWindowsContextPrivate::QWindowsContextPrivate() QWindowsContext::QWindowsContext() : d(new QWindowsContextPrivate) { -#ifdef Q_CC_MSVC -# pragma warning( disable : 4996 ) -#endif m_instance = this; } diff --git a/src/plugins/platforms/windows/qwindowsiconengine.cpp b/src/plugins/platforms/windows/qwindowsiconengine.cpp index 71103183183..edc1ea3a9dc 100644 --- a/src/plugins/platforms/windows/qwindowsiconengine.cpp +++ b/src/plugins/platforms/windows/qwindowsiconengine.cpp @@ -63,8 +63,8 @@ static QString getGlyphs(QStringView iconName) {"go-home"_L1, u"\ue80f"}, // {"go-jump"_L1, u"\uf719"}, //{"go-last"_L1, u"\ue5dd"}, - {"go-next"_L1, u"\ue893"}, - {"go-previous"_L1, u"\ue892"}, + {"go-next"_L1, u"\ue72a"}, + {"go-previous"_L1, u"\ue72b"}, //{"go-top"_L1, u"\ue25a"}, {"go-up"_L1, u"\ue74a"}, {"help-about"_L1, u"\ue946"}, @@ -100,7 +100,7 @@ static QString getGlyphs(QStringView iconName) //{"object-flip-vertical"_L1, u"\u"}, {"object-rotate-left"_L1, u"\ue80c"}, {"object-rotate-right"_L1, u"\ue80d"}, - //{"process-stop"_L1, u"\ue5c9"}, + {"process-stop"_L1, u"\uf140"}, {"system-lock-screen"_L1, u"\uee3f"}, {"system-log-out"_L1, u"\uf3b1"}, //{"system-run"_L1, u"\u"}, diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 8e3ab67ced5..72daffb56b1 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -466,15 +466,17 @@ static bool applyBlurBehindWindow(HWND hwnd) return result; } +static bool shouldShowTitlebarButton(Qt::WindowFlags flags, Qt::WindowFlags button) +{ + return !flags.testFlag(Qt::CustomizeWindowHint) || flags.testFlags(Qt::CustomizeWindowHint | button); +} + // from qwidget_win.cpp, pass flags separately in case they have been "autofixed". static bool shouldShowMaximizeButton(const QWindow *w, Qt::WindowFlags flags) { - if ((flags & Qt::MSWindowsFixedSizeDialogHint) || !(flags & Qt::WindowMaximizeButtonHint)) - return false; - // if the user explicitly asked for the maximize button, we try to add - // it even if the window has fixed size. - return (flags & Qt::CustomizeWindowHint) || - w->maximumSize() == QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX); + return !flags.testFlag(Qt::MSWindowsFixedSizeDialogHint) && + (shouldShowTitlebarButton(flags, Qt::WindowMaximizeButtonHint) || + w->maximumSize() == QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX)); } bool QWindowsWindow::hasNoNativeFrame(HWND hwnd, Qt::WindowFlags flags) @@ -805,6 +807,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag if (topLevel) { if ((type == Qt::Window || dialog || tool)) { + const bool defaultTitlebar = !flags.testFlag(Qt::CustomizeWindowHint); if (!(flags & Qt::FramelessWindowHint)) { style |= WS_POPUP; if (flags & Qt::MSWindowsFixedSizeDialogHint) { @@ -812,16 +815,16 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag } else { style |= WS_THICKFRAME; } - if (flags & Qt::WindowTitleHint) + if (defaultTitlebar || flags.testFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint)) style |= WS_CAPTION; // Contains WS_DLGFRAME } - if (flags & Qt::WindowSystemMenuHint) + if (defaultTitlebar || flags.testFlags(Qt::CustomizeWindowHint | Qt::WindowSystemMenuHint)) style |= WS_SYSMENU; - else if (dialog && (flags & Qt::WindowCloseButtonHint) && !(flags & Qt::FramelessWindowHint)) { + else if (dialog && (defaultTitlebar || flags.testFlags(Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint)) && !(flags & Qt::FramelessWindowHint)) { style |= WS_SYSMENU | WS_BORDER; // QTBUG-2027, dialogs without system menu. exStyle |= WS_EX_DLGMODALFRAME; } - const bool showMinimizeButton = flags & Qt::WindowMinimizeButtonHint; + const bool showMinimizeButton = shouldShowTitlebarButton(flags, Qt::WindowMinimizeButtonHint); if (showMinimizeButton) style |= WS_MINIMIZEBOX; const bool showMaximizeButton = shouldShowMaximizeButton(w, flags); diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp index 2944c02fd79..c8cd7c26f61 100644 --- a/src/plugins/styles/modernwindows/qwindows11style.cpp +++ b/src/plugins/styles/modernwindows/qwindows11style.cpp @@ -109,6 +109,7 @@ inline ControlState calcControlState(const QStyleOption *option) #define More u"\uE712"_s #define Help u"\uE897"_s +#define Clear u"\uE894"_s template <typename R, typename P, typename B> static inline void drawRoundedRect(QPainter *p, R &&rect, P &&pen, B &&brush) @@ -1720,9 +1721,10 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op } case CE_ItemViewItem: { if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) { - QRect checkRect = proxy()->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget); - QRect iconRect = proxy()->subElementRect(SE_ItemViewItemDecoration, vopt, widget); - QRect textRect = proxy()->subElementRect(SE_ItemViewItemText, vopt, widget); + const auto p = proxy(); + QRect checkRect = p->subElementRect(SE_ItemViewItemCheckIndicator, vopt, widget); + QRect iconRect = p->subElementRect(SE_ItemViewItemDecoration, vopt, widget); + QRect textRect = p->subElementRect(SE_ItemViewItemText, vopt, widget); // draw the background proxy()->drawPrimitive(PE_PanelItemViewItem, option, painter, widget); @@ -1823,16 +1825,17 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op d->viewItemDrawText(painter, vopt, textRect); // paint a vertical marker for QListView - if (vopt->state & State_Selected) { + if (vopt->state & State_Selected && !highContrastTheme) { if (const QListView *lv = qobject_cast<const QListView *>(widget); - lv && lv->viewMode() != QListView::IconMode && !highContrastTheme) { - painter->setPen(vopt->palette.accent().color()); - const auto xPos = isRtl ? rect.right() - 1 : rect.left(); - const QLineF lines[2] = { - QLineF(xPos, rect.y() + 2, xPos, rect.y() + rect.height() - 2), - QLineF(xPos + 1, rect.y() + 2, xPos + 1, rect.y() + rect.height() - 2), - }; - painter->drawLines(lines, 2); + lv && lv->viewMode() != QListView::IconMode) { + const auto col = vopt->palette.accent().color(); + painter->setBrush(col); + painter->setPen(col); + const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f; + const auto yOfs = rect.height() / 4.; + QRectF r(QPointF(xPos, rect.y() + yOfs), + QPointF(xPos + 1, rect.y() + rect.height() - yOfs)); + painter->drawRoundedRect(r, 1, 1); } } } @@ -1872,7 +1875,7 @@ QRect QWindows11Style::subElementRect(QStyle::SubElement element, const QStyleOp case QStyle::SE_RadioButtonIndicator: case QStyle::SE_CheckBoxIndicator: ret = QWindowsVistaStyle::subElementRect(element, option, widget); - ret.moveLeft(contentItemHMargin); + ret.moveLeft(ret.left() + contentItemHMargin); break; case QStyle::SE_ComboBoxFocusRect: case QStyle::SE_CheckBoxFocusRect: @@ -1883,22 +1886,29 @@ QRect QWindows11Style::subElementRect(QStyle::SubElement element, const QStyleOp case QStyle::SE_LineEditContents: ret = option->rect.adjusted(4,0,-4,0); break; - case QStyle::SE_ItemViewItemText: - if (const auto *item = qstyleoption_cast<const QStyleOptionViewItem *>(option)) { - const int decorationOffset = item->features.testFlag(QStyleOptionViewItem::HasDecoration) ? item->decorationSize.width() : 0; - const int checkboxOffset = item->features.testFlag(QStyleOptionViewItem::HasCheckIndicator) ? 16 : 0; - if (widget && qobject_cast<QComboBoxPrivateContainer *>(widget->parentWidget())) { - if (option->direction == Qt::LeftToRight) - ret = option->rect.adjusted(decorationOffset + checkboxOffset + 5, 0, -5, 0); - else - ret = option->rect.adjusted(5, 0, decorationOffset - checkboxOffset - 5, 0); + case SE_ItemViewItemCheckIndicator: + case SE_ItemViewItemDecoration: + case SE_ItemViewItemText: { + ret = QWindowsVistaStyle::subElementRect(element, option, widget); + if (!ret.isValid() || highContrastTheme) + return ret; + + if (const QListView *lv = qobject_cast<const QListView *>(widget); + lv && lv->viewMode() != QListView::IconMode) { + const int xOfs = contentHMargin; + const bool isRtl = option->direction == Qt::RightToLeft; + if (isRtl) { + ret.moveRight(ret.right() - xOfs); + if (ret.left() < option->rect.left()) + ret.setLeft(option->rect.left()); } else { - ret = QWindowsVistaStyle::subElementRect(element, option, widget); + ret.moveLeft(ret.left() + xOfs); + if (ret.right() > option->rect.right()) + ret.setRight(option->rect.right()); } - } else { - ret = QWindowsVistaStyle::subElementRect(element, option, widget); } break; + } #if QT_CONFIG(progressbar) case SE_ProgressBarGroove: case SE_ProgressBarContents: @@ -2091,6 +2101,19 @@ QRect QWindows11Style::subControlRect(ComplexControl control, const QStyleOption } break; } +#if QT_CONFIG(groupbox) + case CC_GroupBox: { + ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget); + switch (subControl) { + case SC_GroupBoxCheckBox: + ret.moveTop(1); + break; + default: + break; + } + break; + } +#endif // QT_CONFIG(groupbox) default: ret = QWindowsVistaStyle::subControlRect(control, option, subControl, widget); } @@ -2234,6 +2257,25 @@ QSize QWindows11Style::sizeFromContents(ContentsType type, const QStyleOption *o contentSize.rwidth() += 2 * contentHMargin - oldMargin; break; } + case CT_ItemViewItem: { + if (const auto *viewItemOpt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) { + if (const QListView *lv = qobject_cast<const QListView *>(widget); + lv && lv->viewMode() != QListView::IconMode) { + QStyleOptionViewItem vOpt(*viewItemOpt); + // viewItemSize only takes PM_FocusFrameHMargin into account but no additional + // margin, therefore adjust it here for a correct width during layouting when + // WrapText is enabled + vOpt.rect.setRight(vOpt.rect.right() - contentHMargin); + contentSize = QWindowsVistaStyle::sizeFromContents(type, &vOpt, size, widget); + contentSize.rwidth() += contentHMargin; + contentSize.rheight() += 2 * contentHMargin; + + } else { + contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget); + } + } + break; + } default: contentSize = QWindowsVistaStyle::sizeFromContents(type, option, size, widget); break; @@ -2544,6 +2586,7 @@ void QWindows11Style::polish(QPalette& result) d->m_titleBarCloseIcon = QIcon(); d->m_titleBarNormalIcon = QIcon(); d->m_toolbarExtensionButton = QIcon(); + d->m_lineEditClearButton = QIcon(); } QPixmap QWindows11Style::standardPixmap(StandardPixmap standardPixmap, @@ -2568,10 +2611,17 @@ QIcon QWindows11Style::standardIcon(StandardPixmap standardIcon, { auto *d = const_cast<QWindows11StylePrivate*>(d_func()); switch (standardIcon) { + case SP_LineEditClearButton: { + if (d->m_lineEditClearButton.isNull()) { + auto e = new WinFontIconEngine(Clear.at(0), d->assetFont); + d->m_lineEditClearButton = QIcon(e); + } + return d->m_lineEditClearButton; + } case SP_ToolBarHorizontalExtensionButton: case SP_ToolBarVerticalExtensionButton: { if (d->m_toolbarExtensionButton.isNull()) { - auto e = new WinFontIconEngine(More.at(0), d->assetFont); + auto e = new WinFontIconEngine(More, d->assetFont); e->setScale(1.0); d->m_toolbarExtensionButton = QIcon(e); } diff --git a/src/plugins/styles/modernwindows/qwindows11style_p.h b/src/plugins/styles/modernwindows/qwindows11style_p.h index 736caae956c..a51a93ddd9b 100644 --- a/src/plugins/styles/modernwindows/qwindows11style_p.h +++ b/src/plugins/styles/modernwindows/qwindows11style_p.h @@ -123,6 +123,7 @@ class QWindows11StylePrivate : public QWindowsVistaStylePrivate { protected: QIcon m_toolbarExtensionButton; + QIcon m_lineEditClearButton; }; QT_END_NAMESPACE diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp index 22ca18b10bf..fa0d0260f3c 100644 --- a/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp +++ b/src/plugins/styles/modernwindows/qwindowsvistastyle.cpp @@ -4959,8 +4959,7 @@ QIcon QWindowsVistaStyle::standardIcon(StandardPixmap standardIcon, return QWindowsStyle::standardIcon(standardIcon, option, widget); } - -WinFontIconEngine::WinFontIconEngine(const QChar &glyph, const QFont &font) +WinFontIconEngine::WinFontIconEngine(const QString &glyph, const QFont &font) : QFontIconEngine({}, font) , m_font(font) , m_glyph(glyph) diff --git a/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h b/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h index cf982ceb133..23b34547faa 100644 --- a/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h +++ b/src/plugins/styles/modernwindows/qwindowsvistastyle_p_p.h @@ -184,7 +184,7 @@ private: class WinFontIconEngine : public QFontIconEngine { public: - WinFontIconEngine(const QChar &glyph, const QFont &font); + WinFontIconEngine(const QString &glyph, const QFont &font); QString key() const override; QIconEngine *clone() const override; @@ -194,7 +194,7 @@ public: protected: QFont m_font; - QChar m_glyph; + QString m_glyph; double m_scale = 0.7; }; diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 784e69d2486..a98f5da2389 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -410,7 +410,7 @@ public: static QMetaMethod findMethod(const QObject *obj, const char *signature); private: - bool invokeTest(int index, QLatin1StringView tag, std::optional<WatchDog> &watchDog) const; + void invokeTest(int index, QLatin1StringView tag, std::optional<WatchDog> &watchDog) const; void invokeTestOnData(int index) const; QMetaMethod m_initTestCaseMethod; // might not exist, check isValid(). @@ -1315,11 +1315,8 @@ static void printUnknownDataTagError(QLatin1StringView name, QLatin1StringView t Call slot_data(), init(), slot(), cleanup(), init(), slot(), cleanup(), ... If data is set then it is the only test that is performed - - If the function was successfully called, true is returned, otherwise - false. */ -bool TestMethods::invokeTest(int index, QLatin1StringView tag, std::optional<WatchDog> &watchDog) const +void TestMethods::invokeTest(int index, QLatin1StringView tag, std::optional<WatchDog> &watchDog) const { QBenchmarkTestMethodData benchmarkData; QBenchmarkTestMethodData::current = &benchmarkData; @@ -1422,8 +1419,6 @@ bool TestMethods::invokeTest(int index, QLatin1StringView tag, std::optional<Wat QTestResult::finishedCurrentTestFunction(); QTestResult::setSkipCurrentTest(false); QTestResult::setBlacklistCurrentTest(false); - - return true; } void *fetchData(QTestData *data, const char *tagName, int typeId) @@ -1743,10 +1738,8 @@ void TestMethods::invokeTests(QObject *testObject) const const char *data = nullptr; if (i < QTest::testTags.size() && !QTest::testTags.at(i).isEmpty()) data = qstrdup(QTest::testTags.at(i).toLatin1().constData()); - const bool ok = invokeTest(i, QLatin1StringView(data), watchDog); + invokeTest(i, QLatin1StringView(data), watchDog); delete [] data; - if (!ok) - break; } } diff --git a/src/widgets/accessible/itemviews.cpp b/src/widgets/accessible/itemviews.cpp index fc969e17380..265c523eae0 100644 --- a/src/widgets/accessible/itemviews.cpp +++ b/src/widgets/accessible/itemviews.cpp @@ -60,7 +60,7 @@ int QAccessibleTable::logicalIndex(const QModelIndex &index) const } QAccessibleTable::QAccessibleTable(QWidget *w) - : QAccessibleObject(w) + : QAccessibleWidgetV2(w) { Q_ASSERT(view()); @@ -677,7 +677,7 @@ void *QAccessibleTable::interface_cast(QAccessible::InterfaceType t) return static_cast<QAccessibleSelectionInterface*>(this); if (t == QAccessible::TableInterface) return static_cast<QAccessibleTableInterface*>(this); - return nullptr; + return QAccessibleWidgetV2::interface_cast(t); } void QAccessibleTable::modelChange(QAccessibleTableModelChangeEvent *event) diff --git a/src/widgets/accessible/itemviews_p.h b/src/widgets/accessible/itemviews_p.h index 9b30f36ced3..79f9a7f2f05 100644 --- a/src/widgets/accessible/itemviews_p.h +++ b/src/widgets/accessible/itemviews_p.h @@ -31,7 +31,9 @@ QT_BEGIN_NAMESPACE class QAccessibleTableCell; class QAccessibleTableHeaderCell; -class QAccessibleTable :public QAccessibleTableInterface, public QAccessibleSelectionInterface, public QAccessibleObject +class QAccessibleTable : public QAccessibleTableInterface, + public QAccessibleSelectionInterface, + public QAccessibleWidgetV2 { public: explicit QAccessibleTable(QWidget *w); diff --git a/src/widgets/accessible/rangecontrols.cpp b/src/widgets/accessible/rangecontrols.cpp index c0de5357c9a..1f7b20833dd 100644 --- a/src/widgets/accessible/rangecontrols.cpp +++ b/src/widgets/accessible/rangecontrols.cpp @@ -65,6 +65,16 @@ QAccessibleInterface *QAccessibleAbstractSpinBox::lineEditIface() const #endif } +QAccessible::State QAccessibleAbstractSpinBox::state() const +{ + QAccessible::State state = QAccessibleWidgetV2::state(); + if (abstractSpinBox()->isReadOnly()) + state.readOnly = true; + else + state.editable = true; + return state; +} + QString QAccessibleAbstractSpinBox::text(QAccessible::Text t) const { if (t == QAccessible::Value) diff --git a/src/widgets/accessible/rangecontrols_p.h b/src/widgets/accessible/rangecontrols_p.h index dd5a6a4531c..5a023d2f00b 100644 --- a/src/widgets/accessible/rangecontrols_p.h +++ b/src/widgets/accessible/rangecontrols_p.h @@ -42,6 +42,7 @@ public: explicit QAccessibleAbstractSpinBox(QWidget *w); virtual ~QAccessibleAbstractSpinBox(); + QAccessible::State state() const override; QString text(QAccessible::Text t) const override; void *interface_cast(QAccessible::InterfaceType t) override; diff --git a/src/widgets/dialogs/qfontdialog.cpp b/src/widgets/dialogs/qfontdialog.cpp index 870b0c40faf..c4f8af1a639 100644 --- a/src/widgets/dialogs/qfontdialog.cpp +++ b/src/widgets/dialogs/qfontdialog.cpp @@ -172,7 +172,7 @@ void QFontDialogPrivate::init() sizeAccel = new QLabel(q); #ifndef QT_NO_SHORTCUT - sizeAccel->setBuddy(sizeEdit); + sizeAccel->setBuddy(sizeList); #endif sizeAccel->setIndent(2); diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp index 00f9766af29..5ba92714f6c 100644 --- a/src/widgets/kernel/qlayout.cpp +++ b/src/widgets/kernel/qlayout.cpp @@ -345,6 +345,17 @@ void QLayout::getContentsMargins(int *left, int *top, int *right, int *bottom) c } /*! + \property QLayout::contentsMargins + \since 4.6 + \brief the margins used around the layout + + By default, QLayout uses the values provided by the style. On + most platforms, the margin is 11 pixels in all directions. + + \sa setContentsMargins(), getContentsMargins() +*/ + +/*! \since 4.6 Returns the margins used around the layout. |
