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);
|
||||
}
|
||||
|
||||
/*!
|
||||
\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]
|
||||
\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 insertColumns(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 removeRows(int row, int count, const QModelIndex &parent = {}) override;
|
||||
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
|
||||
@ -120,6 +122,18 @@ void QGenericItemModelImplBase::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)
|
||||
{
|
||||
m_itemModel->beginInsertRows(parent, start, count);
|
||||
@ -290,6 +304,8 @@ public:
|
||||
break;
|
||||
case RemoveColumns: makeCall(that, &Self::removeColumns, r, args);
|
||||
break;
|
||||
case MoveColumns: makeCall(that, &Self::moveColumns, r, args);
|
||||
break;
|
||||
case InsertRows: makeCall(that, &Self::insertRows, r, args);
|
||||
break;
|
||||
case RemoveRows: makeCall(that, &Self::removeRows, r, args);
|
||||
@ -779,6 +795,47 @@ public:
|
||||
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)
|
||||
{
|
||||
if constexpr (Structure::canInsertRows()) {
|
||||
@ -1222,6 +1279,11 @@ protected:
|
||||
&& Base::dynamicRows() && range_features::has_erase;
|
||||
}
|
||||
|
||||
static constexpr bool canMoveColumns(const QModelIndex &, const QModelIndex &)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static constexpr bool canMoveRows(const QModelIndex &, const QModelIndex &)
|
||||
{
|
||||
return true;
|
||||
@ -1507,6 +1569,11 @@ protected:
|
||||
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)
|
||||
{
|
||||
return !source.isValid() && !destination.isValid();
|
||||
|
@ -493,6 +493,7 @@ public:
|
||||
ClearItemData,
|
||||
InsertColumns,
|
||||
RemoveColumns,
|
||||
MoveColumns,
|
||||
InsertRows,
|
||||
RemoveRows,
|
||||
MoveRows,
|
||||
@ -532,6 +533,9 @@ protected:
|
||||
inline void endInsertColumns();
|
||||
inline void beginRemoveColumns(const QModelIndex &parent, int start, int count);
|
||||
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 endInsertRows();
|
||||
inline void beginRemoveRows(const QModelIndex &parent, int start, int count);
|
||||
|
@ -300,6 +300,8 @@ private slots:
|
||||
void insertColumns();
|
||||
void removeColumns_data() { createTestData(); }
|
||||
void removeColumns();
|
||||
void moveColumns_data() { createTestData(); }
|
||||
void moveColumns();
|
||||
|
||||
void inconsistentColumnCount();
|
||||
|
||||
@ -1207,6 +1209,51 @@ void tst_QGenericItemModel::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()
|
||||
{
|
||||
QTest::ignoreMessage(QtCriticalMsg, "QGenericItemModel: "
|
||||
|
Loading…
x
Reference in New Issue
Block a user