mirror of https://github.com/qt/qtbase.git
QRangeModel: implement roleNames for ranges of gadgets
If the item type for all columns is identical, and has a meta object, then we can use the property names and map them to Qt::UserRole values. Add the necessary traits to detect whether the types of all columns are identical, and what the type is. They are identical for rows that are ranges or single values (including MultiRole gadgets). For tuples, we test if all elements have the same type. Adapt the test, and improve the diagnostic output for failing calls to setItemData. Discussed during API review. Pick-to: 6.10 Change-Id: Idd806e85f9eeec636aedf381ca69611afd9dbb29 Reviewed-by: Artem Dyomin <artem.dyomin@qt.io>
This commit is contained in:
parent
c35676b9d2
commit
f101e9931b
|
@ -1023,6 +1023,15 @@ void QRangeModel::multiData(const QModelIndex &index, QModelRoleDataSpan roleDat
|
|||
\property QRangeModel::roleNames
|
||||
\brief the role names for the model.
|
||||
|
||||
If all columns in the range are of the same type, and if that type provides
|
||||
a meta object (i.e., it is a gadget, or a QObject subclass), then this
|
||||
property holds the names of the properties of that type, mapped to values of
|
||||
Qt::ItemDataRole values from Qt::UserRole and up.
|
||||
|
||||
Override this default behavior by setting this property explicitly to a non-
|
||||
empty mapping. Setting this property to an empty mapping, or using
|
||||
resetRoleNames(), restores the default behavior.
|
||||
|
||||
\sa QAbstractItemModel::roleNames()
|
||||
*/
|
||||
|
||||
|
@ -1036,7 +1045,8 @@ QHash<int, QByteArray> QRangeModel::roleNames() const
|
|||
{
|
||||
Q_D(const QRangeModel);
|
||||
if (d->m_roleNames.isEmpty())
|
||||
d->m_roleNames = QAbstractItemModel::roleNames();
|
||||
d->m_roleNames = d->call<QHash<int, QByteArray>>(QRangeModelImplBase::RoleNames);
|
||||
|
||||
return d->m_roleNames;
|
||||
}
|
||||
|
||||
|
|
|
@ -330,6 +330,7 @@ namespace QRangeModelDetails
|
|||
// A static size of 0 indicates that the specified type doesn't
|
||||
// represent static or dynamic range.
|
||||
static constexpr int static_size = is_range ? -1 : 0;
|
||||
using item_type = std::conditional_t<is_range, typename range_traits<T>::value_type, void>;
|
||||
static constexpr int fixed_size() { return 1; }
|
||||
static constexpr bool hasMetaObject = false;
|
||||
};
|
||||
|
@ -340,6 +341,17 @@ namespace QRangeModelDetails
|
|||
static constexpr std::size_t size64 = std::tuple_size_v<T>;
|
||||
static_assert(q20::in_range<int>(size64));
|
||||
static constexpr int static_size = int(size64);
|
||||
|
||||
// are the types in a tuple all the same
|
||||
template <std::size_t ...I>
|
||||
static constexpr bool allSameTypes(std::index_sequence<I...>)
|
||||
{
|
||||
return (std::is_same_v<std::tuple_element_t<0, T>,
|
||||
std::tuple_element_t<I, T>> && ...);
|
||||
}
|
||||
|
||||
using item_type = std::conditional_t<allSameTypes(std::make_index_sequence<size64>{}),
|
||||
std::tuple_element_t<0, T>, void>;
|
||||
static constexpr int fixed_size() { return 0; }
|
||||
static constexpr bool hasMetaObject = false;
|
||||
};
|
||||
|
@ -354,6 +366,7 @@ namespace QRangeModelDetails
|
|||
{
|
||||
static_assert(q20::in_range<int>(N));
|
||||
static constexpr int static_size = int(N);
|
||||
using item_type = T;
|
||||
static constexpr int fixed_size() { return 0; }
|
||||
static constexpr bool hasMetaObject = false;
|
||||
};
|
||||
|
@ -362,6 +375,7 @@ namespace QRangeModelDetails
|
|||
struct metaobject_row_traits
|
||||
{
|
||||
static constexpr int static_size = 0;
|
||||
using item_type = std::conditional_t<row_category<T>::isMultiRole, T, void>;
|
||||
static int fixed_size() {
|
||||
if constexpr (row_category<T>::isMultiRole) {
|
||||
return 1;
|
||||
|
@ -629,6 +643,7 @@ public:
|
|||
HeaderData,
|
||||
Data,
|
||||
ItemData,
|
||||
RoleNames,
|
||||
};
|
||||
|
||||
enum Op {
|
||||
|
@ -832,6 +847,8 @@ public:
|
|||
break;
|
||||
case ItemData: makeCall(that, &Self::itemData, r, args);
|
||||
break;
|
||||
case RoleNames: makeCall(that, &Self::roleNames, r, args);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1204,7 +1221,8 @@ public:
|
|||
}
|
||||
}
|
||||
if (!written) {
|
||||
qWarning("Failed to write value for %s", roleName.data());
|
||||
qWarning("Failed to write value '%s' to role '%s'",
|
||||
qPrintable(QDebug::toString(value)), roleName.data());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1266,6 +1284,29 @@ public:
|
|||
return success;
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> roleNames() const
|
||||
{
|
||||
// will be 'void' if columns don't all have the same type
|
||||
using item_type = typename row_traits::item_type;
|
||||
if constexpr (QRangeModelDetails::has_metaobject_v<item_type>) {
|
||||
const QMetaObject &metaObject = QRangeModelDetails::wrapped_t<item_type>::staticMetaObject;
|
||||
const auto defaults = itemModel().QAbstractItemModel::roleNames();
|
||||
QHash<int, QByteArray> result;
|
||||
const int offset = metaObject.propertyOffset();
|
||||
for (int i = offset; i < metaObject.propertyCount(); ++i) {
|
||||
const auto name = metaObject.property(i).name();
|
||||
const int defaultRole = defaults.key(name, -1);
|
||||
if (defaultRole != -1)
|
||||
result[defaultRole] = name;
|
||||
else
|
||||
result[Qt::UserRole + i - offset] = name;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return itemModel().QAbstractItemModel::roleNames();
|
||||
}
|
||||
|
||||
bool insertColumns(int column, int count, const QModelIndex &parent)
|
||||
{
|
||||
if constexpr (dynamicColumns() && isMutable() && row_features::has_insert) {
|
||||
|
|
|
@ -306,6 +306,7 @@ private slots:
|
|||
void ownership();
|
||||
void overrideRoleNames();
|
||||
void setRoleNames();
|
||||
void defaultRoleNames();
|
||||
|
||||
void dimensions_data() { createTestData(); }
|
||||
void dimensions();
|
||||
|
@ -1082,6 +1083,57 @@ void tst_QRangeModel::setRoleNames()
|
|||
QCOMPARE(model.roleNames(), roleNames);
|
||||
}
|
||||
|
||||
void tst_QRangeModel::defaultRoleNames()
|
||||
{
|
||||
[]{
|
||||
const QHash<int, QByteArray> expectedRoleNames = {
|
||||
{Qt::UserRole, "string"},
|
||||
{Qt::UserRole + 1, "number"},
|
||||
};
|
||||
|
||||
QCOMPARE(QRangeModel(QList<QRangeModel::SingleColumn<Object *>>{}).roleNames(),
|
||||
expectedRoleNames);
|
||||
QCOMPARE(QRangeModel(QList<std::tuple<Object *, Object *>>{}).roleNames(),
|
||||
expectedRoleNames);
|
||||
}();
|
||||
|
||||
[]{
|
||||
const QHash<int, QByteArray> expectedRoleNames = {
|
||||
{Qt::DisplayRole, "display"},
|
||||
{Qt::DecorationRole, "decoration"},
|
||||
{Qt::ToolTipRole, "toolTip"},
|
||||
};
|
||||
QCOMPARE(QRangeModel(QList<QRangeModel::SingleColumn<Item>>{}).roleNames(),
|
||||
expectedRoleNames);
|
||||
QCOMPARE(QRangeModel(QList<std::tuple<Item, Item, Item>>{}).roleNames(),
|
||||
expectedRoleNames);
|
||||
QCOMPARE(QRangeModel(QList<QList<Item>>{}).roleNames(),
|
||||
expectedRoleNames);
|
||||
}();
|
||||
|
||||
[]{
|
||||
const QHash<int, QByteArray> expectedRoleNames = {
|
||||
{Qt::DisplayRole, "display"},
|
||||
{Qt::DecorationRole, "decoration"},
|
||||
};
|
||||
QCOMPARE(QRangeModel(QList<MultiRoleGadget>{}).roleNames(),
|
||||
expectedRoleNames);
|
||||
QCOMPARE(QRangeModel(QList<QList<MultiRoleGadget>>{}).roleNames(),
|
||||
expectedRoleNames);
|
||||
QCOMPARE(QRangeModel(std::vector<std::array<MultiRoleGadget, 5>>{}).roleNames(),
|
||||
expectedRoleNames);
|
||||
}();
|
||||
|
||||
[]{
|
||||
const auto expectedRoleNames = QRangeModel(QList<Row>{}).QAbstractItemModel::roleNames();
|
||||
QCOMPARE(QRangeModel(QList<Row>{}).roleNames(), expectedRoleNames);
|
||||
QCOMPARE(QRangeModel(QList<std::tuple<Item, MultiRoleGadget>>{}).roleNames(),
|
||||
expectedRoleNames);
|
||||
QCOMPARE(QRangeModel(QList<int>{}).roleNames(), expectedRoleNames);
|
||||
QCOMPARE(QRangeModel(QList<QList<QString>>{}).roleNames(), expectedRoleNames);
|
||||
}();
|
||||
}
|
||||
|
||||
void tst_QRangeModel::dimensions()
|
||||
{
|
||||
QFETCH(Factory, factory);
|
||||
|
@ -1208,7 +1260,7 @@ void tst_QRangeModel::setItemData()
|
|||
for (int role : roles) {
|
||||
if (role == Qt::EditRole) // faked
|
||||
continue;
|
||||
QVariant data = role != Qt::DecorationRole ? QVariant(QStringLiteral("Role %1").arg(role))
|
||||
QVariant data = role != Qt::DecorationRole ? QVariant(QStringLiteral("%1").arg(role))
|
||||
: QVariant(QColor(Qt::magenta));
|
||||
itemData.insert(role, data);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue