QGIM: implement moveColumns
We can move columns when the row-type is a range (which guarantees that all columns are of the same type), and if the columns are moved within the same parent. Otherwise we would end up with different branches of a tree having different column counts, which we don't allow. Since we require trees to use statically sized row types, the former implies the latter anyway. Change-Id: Iaf9513d3642d6143cd4880937f2c022a0621c70d Reviewed-by: Artem Dyomin <artem.dyomin@qt.io>
This commit is contained in:
parent
1c44eb8e16
commit
ec200659da
@ -688,6 +688,23 @@ bool QGenericItemModel::removeColumns(int column, int count, const QModelIndex &
|
|||||||
return impl->call<bool>(QGenericItemModelImplBase::RemoveColumns, column, count, parent);
|
return impl->call<bool>(QGenericItemModelImplBase::RemoveColumns, column, count, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\reimp
|
||||||
|
|
||||||
|
Moves \a count columns starting with the given \a sourceColumn under parent
|
||||||
|
\a sourceParent to column \a destinationColumn under parent \a destinationParent.
|
||||||
|
|
||||||
|
Returns \c{true} if the columns were successfully moved; otherwise returns
|
||||||
|
\c{false}.
|
||||||
|
*/
|
||||||
|
bool QGenericItemModel::moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count,
|
||||||
|
const QModelIndex &destinationParent, int destinationColumn)
|
||||||
|
{
|
||||||
|
return impl->call<bool>(QGenericItemModelImplBase::MoveColumns,
|
||||||
|
sourceParent, sourceColumn, count,
|
||||||
|
destinationParent, destinationColumn);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
//! [row-change-requirement]
|
//! [row-change-requirement]
|
||||||
\note The range needs to be dynamically sized and provide a \c{\1}
|
\note The range needs to be dynamically sized and provide a \c{\1}
|
||||||
|
@ -72,6 +72,8 @@ public:
|
|||||||
bool clearItemData(const QModelIndex &index) override;
|
bool clearItemData(const QModelIndex &index) override;
|
||||||
bool insertColumns(int column, int count, const QModelIndex &parent = {}) override;
|
bool insertColumns(int column, int count, const QModelIndex &parent = {}) override;
|
||||||
bool removeColumns(int column, int count, const QModelIndex &parent = {}) override;
|
bool removeColumns(int column, int count, const QModelIndex &parent = {}) override;
|
||||||
|
bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count,
|
||||||
|
const QModelIndex &destParent, int destColumn) override;
|
||||||
bool insertRows(int row, int count, const QModelIndex &parent = {}) override;
|
bool insertRows(int row, int count, const QModelIndex &parent = {}) override;
|
||||||
bool removeRows(int row, int count, const QModelIndex &parent = {}) override;
|
bool removeRows(int row, int count, const QModelIndex &parent = {}) override;
|
||||||
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
|
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
|
||||||
@ -120,6 +122,18 @@ void QGenericItemModelImplBase::endRemoveColumns()
|
|||||||
{
|
{
|
||||||
m_itemModel->endRemoveColumns();
|
m_itemModel->endRemoveColumns();
|
||||||
}
|
}
|
||||||
|
bool QGenericItemModelImplBase::beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst,
|
||||||
|
int sourceLast, const QModelIndex &destParent,
|
||||||
|
int destColumn)
|
||||||
|
{
|
||||||
|
return m_itemModel->beginMoveColumns(sourceParent, sourceFirst, sourceLast,
|
||||||
|
destParent, destColumn);
|
||||||
|
}
|
||||||
|
void QGenericItemModelImplBase::endMoveColumns()
|
||||||
|
{
|
||||||
|
m_itemModel->endMoveColumns();
|
||||||
|
}
|
||||||
|
|
||||||
void QGenericItemModelImplBase::beginInsertRows(const QModelIndex &parent, int start, int count)
|
void QGenericItemModelImplBase::beginInsertRows(const QModelIndex &parent, int start, int count)
|
||||||
{
|
{
|
||||||
m_itemModel->beginInsertRows(parent, start, count);
|
m_itemModel->beginInsertRows(parent, start, count);
|
||||||
@ -290,6 +304,8 @@ public:
|
|||||||
break;
|
break;
|
||||||
case RemoveColumns: makeCall(that, &Self::removeColumns, r, args);
|
case RemoveColumns: makeCall(that, &Self::removeColumns, r, args);
|
||||||
break;
|
break;
|
||||||
|
case MoveColumns: makeCall(that, &Self::moveColumns, r, args);
|
||||||
|
break;
|
||||||
case InsertRows: makeCall(that, &Self::insertRows, r, args);
|
case InsertRows: makeCall(that, &Self::insertRows, r, args);
|
||||||
break;
|
break;
|
||||||
case RemoveRows: makeCall(that, &Self::removeRows, r, args);
|
case RemoveRows: makeCall(that, &Self::removeRows, r, args);
|
||||||
@ -779,6 +795,47 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool moveColumns(const QModelIndex &sourceParent, int sourceColumn, int count,
|
||||||
|
const QModelIndex &destParent, int destColumn)
|
||||||
|
{
|
||||||
|
// we only support moving columns within the same parent
|
||||||
|
if (sourceParent != destParent)
|
||||||
|
return false;
|
||||||
|
if constexpr (isMutable()) {
|
||||||
|
if (!Structure::canMoveColumns(sourceParent, destParent))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if constexpr (dynamicColumns()) {
|
||||||
|
// we only support ranges as columns, as other types might
|
||||||
|
// not have the same data type across all columns
|
||||||
|
range_type * const children = childRange(sourceParent);
|
||||||
|
if (!children)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!beginMoveColumns(sourceParent, sourceColumn, sourceColumn + count - 1,
|
||||||
|
destParent, destColumn)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &child : *children) {
|
||||||
|
const auto begin = std::begin(child);
|
||||||
|
const auto first = std::next(begin, sourceColumn);
|
||||||
|
const auto middle = std::next(begin, sourceColumn + count);
|
||||||
|
const auto last = std::next(begin, destColumn);
|
||||||
|
|
||||||
|
if (sourceColumn < destColumn) // moving right
|
||||||
|
std::rotate(first, middle, last);
|
||||||
|
else // moving left
|
||||||
|
std::rotate(last, first, middle);
|
||||||
|
}
|
||||||
|
|
||||||
|
endMoveColumns();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool insertRows(int row, int count, const QModelIndex &parent)
|
bool insertRows(int row, int count, const QModelIndex &parent)
|
||||||
{
|
{
|
||||||
if constexpr (Structure::canInsertRows()) {
|
if constexpr (Structure::canInsertRows()) {
|
||||||
@ -1222,6 +1279,11 @@ protected:
|
|||||||
&& Base::dynamicRows() && range_features::has_erase;
|
&& Base::dynamicRows() && range_features::has_erase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr bool canMoveColumns(const QModelIndex &, const QModelIndex &)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr bool canMoveRows(const QModelIndex &, const QModelIndex &)
|
static constexpr bool canMoveRows(const QModelIndex &, const QModelIndex &)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@ -1507,6 +1569,11 @@ protected:
|
|||||||
return Base::dynamicRows() && range_features::has_erase;
|
return Base::dynamicRows() && range_features::has_erase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr bool canMoveColumns(const QModelIndex &source, const QModelIndex &destination)
|
||||||
|
{
|
||||||
|
return !source.isValid() && !destination.isValid();
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr bool canMoveRows(const QModelIndex &source, const QModelIndex &destination)
|
static constexpr bool canMoveRows(const QModelIndex &source, const QModelIndex &destination)
|
||||||
{
|
{
|
||||||
return !source.isValid() && !destination.isValid();
|
return !source.isValid() && !destination.isValid();
|
||||||
|
@ -493,6 +493,7 @@ public:
|
|||||||
ClearItemData,
|
ClearItemData,
|
||||||
InsertColumns,
|
InsertColumns,
|
||||||
RemoveColumns,
|
RemoveColumns,
|
||||||
|
MoveColumns,
|
||||||
InsertRows,
|
InsertRows,
|
||||||
RemoveRows,
|
RemoveRows,
|
||||||
MoveRows,
|
MoveRows,
|
||||||
@ -532,6 +533,9 @@ protected:
|
|||||||
inline void endInsertColumns();
|
inline void endInsertColumns();
|
||||||
inline void beginRemoveColumns(const QModelIndex &parent, int start, int count);
|
inline void beginRemoveColumns(const QModelIndex &parent, int start, int count);
|
||||||
inline void endRemoveColumns();
|
inline void endRemoveColumns();
|
||||||
|
inline bool beginMoveColumns(const QModelIndex &sourceParent, int sourceFirst, int sourceLast,
|
||||||
|
const QModelIndex &destParent, int destRow);
|
||||||
|
inline void endMoveColumns();
|
||||||
inline void beginInsertRows(const QModelIndex &parent, int start, int count);
|
inline void beginInsertRows(const QModelIndex &parent, int start, int count);
|
||||||
inline void endInsertRows();
|
inline void endInsertRows();
|
||||||
inline void beginRemoveRows(const QModelIndex &parent, int start, int count);
|
inline void beginRemoveRows(const QModelIndex &parent, int start, int count);
|
||||||
|
@ -300,6 +300,8 @@ private slots:
|
|||||||
void insertColumns();
|
void insertColumns();
|
||||||
void removeColumns_data() { createTestData(); }
|
void removeColumns_data() { createTestData(); }
|
||||||
void removeColumns();
|
void removeColumns();
|
||||||
|
void moveColumns_data() { createTestData(); }
|
||||||
|
void moveColumns();
|
||||||
|
|
||||||
void inconsistentColumnCount();
|
void inconsistentColumnCount();
|
||||||
|
|
||||||
@ -1207,6 +1209,51 @@ void tst_QGenericItemModel::removeColumns()
|
|||||||
changeActions.testFlag(ChangeAction::RemoveColumns));
|
changeActions.testFlag(ChangeAction::RemoveColumns));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QGenericItemModel::moveColumns()
|
||||||
|
{
|
||||||
|
QFETCH(Factory, factory);
|
||||||
|
auto model = factory();
|
||||||
|
QFETCH(const int, expectedColumnCount);
|
||||||
|
QFETCH(const ChangeActions, changeActions);
|
||||||
|
|
||||||
|
QCOMPARE(model->columnCount(), expectedColumnCount);
|
||||||
|
if (expectedColumnCount < 2)
|
||||||
|
QSKIP("Cannot test moveColumns with a single-column model");
|
||||||
|
|
||||||
|
const QVariant first = model->index(0, 0).data();
|
||||||
|
const QVariant second = model->index(0, 1).data();
|
||||||
|
const QVariant last = model->index(0, expectedColumnCount - 1).data();
|
||||||
|
|
||||||
|
QCOMPARE(model->moveColumns({}, 0, 1, {}, expectedColumnCount),
|
||||||
|
bool(changeActions & ChangeAction::ChangeColumns));
|
||||||
|
if (!(changeActions & ChangeAction::ChangeColumns))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QCOMPARE(model->index(0, 0).data(), second);
|
||||||
|
QCOMPARE(model->index(0, expectedColumnCount - 2).data(), last);
|
||||||
|
QCOMPARE(model->index(0, expectedColumnCount - 1).data(), first);
|
||||||
|
|
||||||
|
// the rest only makes sense for models with at least 3 columns
|
||||||
|
if (expectedColumnCount >= 3) {
|
||||||
|
// move all but one column to the end - this restores the order
|
||||||
|
QVERIFY(model->moveColumns({}, 0, expectedColumnCount - 1,
|
||||||
|
{}, expectedColumnCount));
|
||||||
|
QCOMPARE(model->index(0, 0).data(), first);
|
||||||
|
QCOMPARE(model->index(0, 1).data(), second);
|
||||||
|
QCOMPARE(model->index(0, expectedColumnCount - 1).data(), last);
|
||||||
|
|
||||||
|
// move the last row step by step up to the top
|
||||||
|
for (int column = model->columnCount() - 1; column > 0; --column)
|
||||||
|
QVERIFY(model->moveColumn({}, column, {}, column - 1));
|
||||||
|
QCOMPARE(model->index(0, 0).data(), last);
|
||||||
|
// move all except the first row up - this restores the order again
|
||||||
|
QVERIFY(model->moveColumns({}, 1, expectedColumnCount - 1, {}, 0));
|
||||||
|
QCOMPARE(model->index(0, 0).data(), first);
|
||||||
|
QCOMPARE(model->index(0, 1).data(), second);
|
||||||
|
QCOMPARE(model->index(0, expectedColumnCount - 1).data(), last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void tst_QGenericItemModel::inconsistentColumnCount()
|
void tst_QGenericItemModel::inconsistentColumnCount()
|
||||||
{
|
{
|
||||||
QTest::ignoreMessage(QtCriticalMsg, "QGenericItemModel: "
|
QTest::ignoreMessage(QtCriticalMsg, "QGenericItemModel: "
|
||||||
|
Loading…
x
Reference in New Issue
Block a user