diff --git a/src/corelib/itemmodels/qabstractitemmodel_p.h b/src/corelib/itemmodels/qabstractitemmodel_p.h index e8f00975edc..edc5ad61169 100644 --- a/src/corelib/itemmodels/qabstractitemmodel_p.h +++ b/src/corelib/itemmodels/qabstractitemmodel_p.h @@ -157,6 +157,52 @@ public: }; Q_DECLARE_TYPEINFO(QAbstractItemModelPrivate::Change, Q_RELOCATABLE_TYPE); +namespace QtPrivate { + +/*! + \internal + This is a workaround for QTBUG-75172. + + Some predefined model roles are supposed to use certain enum/flag + types (e.g. fetching Qt::TextAlignmentRole is supposed to return a + variant containing a Qt::Alignment object). + + For historical reasons, a plain `int` was used sometimes. This is + surprising to end-users and also sloppy on Qt's part; users were + forced to use `int` rather than the correct datatype. + + This function tries both the "right" type and plain `int`, for a + given QVariant. This fixes the problem (using the correct datatype) + but also keeps compatibility with existing code using `int`. + + ### Qt 7: get rid of this. Always use the correct datatype. +*/ +template +T legacyEnumValueFromModelData(const QVariant &data) +{ + static_assert(std::is_enum_v); + if (data.userType() == qMetaTypeId()) + return data.value(); + else if (data.userType() == qMetaTypeId()) + return T(data.toInt()); + + return T(); +} + +template +T legacyFlagValueFromModelData(const QVariant &data) +{ + if (data.userType() == qMetaTypeId()) + return data.value(); + else if (data.userType() == qMetaTypeId()) + return T::fromInt(data.toInt()); + + return T(); +} + +} // namespace QtPrivate + + QT_END_NAMESPACE #endif // QABSTRACTITEMMODEL_P_H diff --git a/src/widgets/itemviews/qabstractitemdelegate_p.h b/src/widgets/itemviews/qabstractitemdelegate_p.h index da76d31e8b8..fc0aa9a73fa 100644 --- a/src/widgets/itemviews/qabstractitemdelegate_p.h +++ b/src/widgets/itemviews/qabstractitemdelegate_p.h @@ -55,6 +55,9 @@ #include "qabstractitemdelegate.h" #include +#include +#include + QT_REQUIRE_CONFIG(itemviews); QT_BEGIN_NAMESPACE diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 27866ecbb00..8fc0df84e21 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -60,6 +60,7 @@ #endif #include #include +#include #ifndef QT_NO_DATASTREAM #include @@ -2936,9 +2937,9 @@ void QHeaderView::initStyleOptionForIndex(QStyleOptionHeader *option, int logica Qt::TextAlignmentRole); opt.section = logicalIndex; opt.state |= state; - opt.textAlignment = Qt::Alignment(textAlignment.isValid() - ? Qt::Alignment(textAlignment.toInt()) - : d->defaultAlignment); + opt.textAlignment = textAlignment.isValid() + ? QtPrivate::legacyFlagValueFromModelData(textAlignment) + : d->defaultAlignment; opt.iconAlignment = Qt::AlignVCenter; opt.text = d->model->headerData(logicalIndex, d->orientation, diff --git a/src/widgets/itemviews/qitemdelegate.cpp b/src/widgets/itemviews/qitemdelegate.cpp index 2640d7163d6..e481dcae729 100644 --- a/src/widgets/itemviews/qitemdelegate.cpp +++ b/src/widgets/itemviews/qitemdelegate.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -432,7 +433,7 @@ void QItemDelegate::paint(QPainter *painter, Qt::CheckState checkState = Qt::Unchecked; value = index.data(Qt::CheckStateRole); if (value.isValid()) { - checkState = static_cast(value.toInt()); + checkState = QtPrivate::legacyEnumValueFromModelData(value); checkRect = doCheck(opt, opt.rect, value); } @@ -1182,7 +1183,7 @@ bool QItemDelegate::editorEvent(QEvent *event, return false; } - Qt::CheckState state = static_cast(value.toInt()); + Qt::CheckState state = QtPrivate::legacyEnumValueFromModelData(value); if (flags & Qt::ItemIsUserTristate) state = ((Qt::CheckState)((state + 1) % 3)); else @@ -1209,7 +1210,7 @@ QStyleOptionViewItem QItemDelegate::setOptions(const QModelIndex &index, // set text alignment value = index.data(Qt::TextAlignmentRole); if (value.isValid()) - opt.displayAlignment = Qt::Alignment(value.toInt()); + opt.displayAlignment = QtPrivate::legacyFlagValueFromModelData(value); // set foreground brush value = index.data(Qt::ForegroundRole); diff --git a/src/widgets/itemviews/qstyleditemdelegate.cpp b/src/widgets/itemviews/qstyleditemdelegate.cpp index ddf706c0e6f..6379031f6af 100644 --- a/src/widgets/itemviews/qstyleditemdelegate.cpp +++ b/src/widgets/itemviews/qstyleditemdelegate.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -302,7 +303,7 @@ void QStyledItemDelegate::initStyleOption(QStyleOptionViewItem *option, value = modelRoleDataSpan.dataForRole(Qt::TextAlignmentRole); if (value->isValid() && !value->isNull()) - option->displayAlignment = Qt::Alignment(value->toInt()); + option->displayAlignment = QtPrivate::legacyFlagValueFromModelData(*value); value = modelRoleDataSpan.dataForRole(Qt::ForegroundRole); if (value->canConvert()) @@ -311,7 +312,7 @@ void QStyledItemDelegate::initStyleOption(QStyleOptionViewItem *option, value = modelRoleDataSpan.dataForRole(Qt::CheckStateRole); if (value->isValid() && !value->isNull()) { option->features |= QStyleOptionViewItem::HasCheckIndicator; - option->checkState = static_cast(value->toInt()); + option->checkState = QtPrivate::legacyEnumValueFromModelData(*value); } value = modelRoleDataSpan.dataForRole(Qt::DecorationRole); @@ -633,7 +634,7 @@ bool QStyledItemDelegate::editorEvent(QEvent *event, return false; } - Qt::CheckState state = static_cast(value.toInt()); + Qt::CheckState state = QtPrivate::legacyEnumValueFromModelData(value); if (flags & Qt::ItemIsUserTristate) state = ((Qt::CheckState)((state + 1) % 3)); else