forked from qt-creator/qt-creator
QmlDesigner: Add row move up and move down buttons
Task-number: QDS-2294 Change-Id: Ia1e64d0811f55151dfe529db4868821840a8fba9 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -27,6 +27,7 @@
|
|||||||
#include "listmodeleditormodel.h"
|
#include "listmodeleditormodel.h"
|
||||||
|
|
||||||
#include <theme.h>
|
#include <theme.h>
|
||||||
|
#include <qmldesignericons.h>
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
@@ -71,6 +72,10 @@ ListModelEditorDialog::ListModelEditorDialog(QWidget *parent)
|
|||||||
m_addColumnAction = toolBar->addAction(getIcon(Theme::Icon::addColumnAfter), tr("Add Column"));
|
m_addColumnAction = toolBar->addAction(getIcon(Theme::Icon::addColumnAfter), tr("Add Column"));
|
||||||
m_removeColumnsAction = toolBar->addAction(getIcon(Theme::Icon::deleteColumn),
|
m_removeColumnsAction = toolBar->addAction(getIcon(Theme::Icon::deleteColumn),
|
||||||
tr("Remove Columns"));
|
tr("Remove Columns"));
|
||||||
|
m_moveDownAction = toolBar->addAction(Icons::ARROW_DOWN.icon(), tr("Move down (CTRL + Down)."));
|
||||||
|
m_moveDownAction->setShortcut(QKeySequence(Qt::Key_Down | Qt::CTRL));
|
||||||
|
m_moveUpAction = toolBar->addAction(Icons::ARROW_UP.icon(), tr("Move up (CTRL + Up)."));
|
||||||
|
m_moveDownAction->setShortcut(QKeySequence(Qt::Key_Up | Qt::CTRL));
|
||||||
}
|
}
|
||||||
|
|
||||||
ListModelEditorDialog::~ListModelEditorDialog() = default;
|
ListModelEditorDialog::~ListModelEditorDialog() = default;
|
||||||
@@ -83,6 +88,8 @@ void ListModelEditorDialog::setModel(ListModelEditorModel *model)
|
|||||||
connect(m_addColumnAction, &QAction::triggered, this, &ListModelEditorDialog::openColumnDialog);
|
connect(m_addColumnAction, &QAction::triggered, this, &ListModelEditorDialog::openColumnDialog);
|
||||||
connect(m_removeRowsAction, &QAction::triggered, this, &ListModelEditorDialog::removeRows);
|
connect(m_removeRowsAction, &QAction::triggered, this, &ListModelEditorDialog::removeRows);
|
||||||
connect(m_removeColumnsAction, &QAction::triggered, this, &ListModelEditorDialog::removeColumns);
|
connect(m_removeColumnsAction, &QAction::triggered, this, &ListModelEditorDialog::removeColumns);
|
||||||
|
connect(m_moveDownAction, &QAction::triggered, this, &ListModelEditorDialog::moveRowsDown);
|
||||||
|
connect(m_moveUpAction, &QAction::triggered, this, &ListModelEditorDialog::moveRowsUp);
|
||||||
connect(m_tableView->horizontalHeader(),
|
connect(m_tableView->horizontalHeader(),
|
||||||
&QHeaderView::sectionDoubleClicked,
|
&QHeaderView::sectionDoubleClicked,
|
||||||
this,
|
this,
|
||||||
@@ -134,4 +141,16 @@ void ListModelEditorDialog::changeHeader(int column)
|
|||||||
m_model->renameColumn(column, newPropertyName);
|
m_model->renameColumn(column, newPropertyName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ListModelEditorDialog::moveRowsDown()
|
||||||
|
{
|
||||||
|
QItemSelection selection = m_model->moveRowsDown(m_tableView->selectionModel()->selectedRows());
|
||||||
|
m_tableView->selectionModel()->select(selection, QItemSelectionModel::Select);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ListModelEditorDialog::moveRowsUp()
|
||||||
|
{
|
||||||
|
QItemSelection selection = m_model->moveRowsUp(m_tableView->selectionModel()->selectedRows());
|
||||||
|
m_tableView->selectionModel()->select(selection, QItemSelectionModel::Select);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -59,6 +59,8 @@ private:
|
|||||||
void removeRows();
|
void removeRows();
|
||||||
void removeColumns();
|
void removeColumns();
|
||||||
void changeHeader(int column);
|
void changeHeader(int column);
|
||||||
|
void moveRowsDown();
|
||||||
|
void moveRowsUp();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ListModelEditorModel *m_model{};
|
ListModelEditorModel *m_model{};
|
||||||
@@ -66,6 +68,8 @@ private:
|
|||||||
QAction *m_removeRowsAction{};
|
QAction *m_removeRowsAction{};
|
||||||
QAction *m_addColumnAction{};
|
QAction *m_addColumnAction{};
|
||||||
QAction *m_removeColumnsAction{};
|
QAction *m_removeColumnsAction{};
|
||||||
|
QAction *m_moveUpAction{};
|
||||||
|
QAction *m_moveDownAction{};
|
||||||
QTableView *m_tableView{};
|
QTableView *m_tableView{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -319,6 +319,42 @@ void ListModelEditorModel::renameColumn(int oldColumn, const QString &newColumnN
|
|||||||
setHorizontalHeaderLabels(convertToStringList(m_propertyNames));
|
setHorizontalHeaderLabels(convertToStringList(m_propertyNames));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QItemSelection ListModelEditorModel::moveRowsUp(const QList<QModelIndex> &indices)
|
||||||
|
{
|
||||||
|
std::vector<int> rows = filterRows(indices);
|
||||||
|
|
||||||
|
if (rows.empty() || rows.front() < 1)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto nodeListProperty = m_listModelNode.defaultNodeListProperty();
|
||||||
|
|
||||||
|
for (int row : rows) {
|
||||||
|
insertRow(row - 1, takeRow(row));
|
||||||
|
nodeListProperty.slide(row, row - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {index(rows.front() - 1, 0), index(rows.back() - 1, columnCount() - 1)};
|
||||||
|
}
|
||||||
|
|
||||||
|
QItemSelection ListModelEditorModel::moveRowsDown(const QList<QModelIndex> &indices)
|
||||||
|
{
|
||||||
|
std::vector<int> rows = filterRows(indices);
|
||||||
|
|
||||||
|
if (rows.empty() || rows.back() >= (rowCount() - 1))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto nodeListProperty = m_listModelNode.defaultNodeListProperty();
|
||||||
|
|
||||||
|
std::reverse(rows.begin(), rows.end());
|
||||||
|
|
||||||
|
for (int row : rows) {
|
||||||
|
insertRow(row + 1, takeRow(row));
|
||||||
|
nodeListProperty.slide(row, row + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {index(rows.front() + 1, 0), index(rows.back() + 1, columnCount() - 1)};
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<int> ListModelEditorModel::filterColumns(const QList<QModelIndex> &indices)
|
std::vector<int> ListModelEditorModel::filterColumns(const QList<QModelIndex> &indices)
|
||||||
{
|
{
|
||||||
std::vector<int> columns;
|
std::vector<int> columns;
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include <modelnode.h>
|
#include <modelnode.h>
|
||||||
|
|
||||||
|
#include <QItemSelection>
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
@@ -53,6 +54,8 @@ public:
|
|||||||
void removeColumns(const QList<QModelIndex> &indices);
|
void removeColumns(const QList<QModelIndex> &indices);
|
||||||
void removeRows(const QList<QModelIndex> &indices);
|
void removeRows(const QList<QModelIndex> &indices);
|
||||||
void renameColumn(int column, const QString &newColumnName);
|
void renameColumn(int column, const QString &newColumnName);
|
||||||
|
QItemSelection moveRowsUp(const QList<QModelIndex> &indices);
|
||||||
|
QItemSelection moveRowsDown(const QList<QModelIndex> &indices);
|
||||||
|
|
||||||
static std::vector<int> filterColumns(const QList<QModelIndex> &indices);
|
static std::vector<int> filterColumns(const QList<QModelIndex> &indices);
|
||||||
static std::vector<int> filterRows(const QList<QModelIndex> &indices);
|
static std::vector<int> filterRows(const QList<QModelIndex> &indices);
|
||||||
|
@@ -175,6 +175,11 @@ public:
|
|||||||
|
|
||||||
QModelIndex index(int row, int column) const { return model.index(row, column); }
|
QModelIndex index(int row, int column) const { return model.index(row, column); }
|
||||||
|
|
||||||
|
QList<ModelNode> elements(const ModelNode &node) const
|
||||||
|
{
|
||||||
|
return node.defaultNodeListProperty().toModelNodeList();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unique_ptr<QmlDesigner::Model> designerModel{QmlDesigner::Model::create("QtQuick.Item", 1, 1)};
|
std::unique_ptr<QmlDesigner::Model> designerModel{QmlDesigner::Model::create("QtQuick.Item", 1, 1)};
|
||||||
NiceMock<MockListModelEditorView> mockView;
|
NiceMock<MockListModelEditorView> mockView;
|
||||||
@@ -1033,4 +1038,238 @@ TEST_F(ListModelEditor, FilterRowsEmptyInput)
|
|||||||
ASSERT_THAT(rows, IsEmpty());
|
ASSERT_THAT(rows, IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, CannotMoveEmptyRowsUp)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(-1, 1)};
|
||||||
|
|
||||||
|
model.moveRowsUp(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(elements(listModelNode), ElementsAre(element1, element2, element3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, MoveRowUp)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(1, 1), index(1, 2), index(1, 0)};
|
||||||
|
|
||||||
|
model.moveRowsUp(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(elements(listModelNode), ElementsAre(element2, element1, element3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, MoveRowsUp)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(1, 1), index(2, 2), index(1, 0)};
|
||||||
|
|
||||||
|
model.moveRowsUp(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(elements(listModelNode), ElementsAre(element2, element3, element1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, CannotMoveFirstRowsUp)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(0, 1), index(1, 2), index(0, 0)};
|
||||||
|
|
||||||
|
model.moveRowsUp(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(elements(listModelNode), ElementsAre(element1, element2, element3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, CannotMoveEmptyRowsUpDisplayValues)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(-1, 1)};
|
||||||
|
|
||||||
|
model.moveRowsUp(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(displayValues(),
|
||||||
|
ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||||
|
ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||||
|
ElementsAre("pic.png", "poo", 111, IsInvalid())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, CannotMoveFirstRowUpDisplayValues)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(0, 1), index(1, 2), index(0, 0)};
|
||||||
|
|
||||||
|
model.moveRowsUp(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(displayValues(),
|
||||||
|
ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||||
|
ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||||
|
ElementsAre("pic.png", "poo", 111, IsInvalid())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, MoveRowsUpDisplayValues)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(1, 1), index(2, 2), index(1, 0)};
|
||||||
|
|
||||||
|
model.moveRowsUp(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(displayValues(),
|
||||||
|
ElementsAre(ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||||
|
ElementsAre("pic.png", "poo", 111, IsInvalid()),
|
||||||
|
ElementsAre(IsInvalid(), "foo", 1, 42)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, NoSelectionAfterCannotMoveLastRowsDown)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(0, 1), index(1, 2), index(0, 0)};
|
||||||
|
|
||||||
|
auto selection = model.moveRowsUp(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(selection.indexes(), IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, NoSelectionAfterMoveEmptyRowsDown)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(-1, 1)};
|
||||||
|
|
||||||
|
auto selection = model.moveRowsUp(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(selection.indexes(), IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, SelectionAfterMoveRowsDown)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(1, 1), index(2, 2), index(1, 0)};
|
||||||
|
|
||||||
|
auto selection = model.moveRowsUp(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(selection.indexes(),
|
||||||
|
ElementsAre(index(0, 0),
|
||||||
|
index(0, 1),
|
||||||
|
index(0, 2),
|
||||||
|
index(0, 3),
|
||||||
|
index(1, 0),
|
||||||
|
index(1, 1),
|
||||||
|
index(1, 2),
|
||||||
|
index(1, 3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, CannotMoveEmptyRowsDown)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(-1, 1)};
|
||||||
|
|
||||||
|
model.moveRowsDown(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(elements(listModelNode), ElementsAre(element1, element2, element3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, MoveRowDown)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(1, 1), index(1, 2), index(1, 0)};
|
||||||
|
|
||||||
|
model.moveRowsDown(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(elements(listModelNode), ElementsAre(element1, element3, element2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, MoveRowsDown)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(1, 1), index(0, 2), index(1, 0)};
|
||||||
|
|
||||||
|
model.moveRowsDown(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(elements(listModelNode), ElementsAre(element3, element1, element2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, CannotMoveLastRowsDown)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(2, 1), index(1, 2), index(2, 0)};
|
||||||
|
|
||||||
|
model.moveRowsDown(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(elements(listModelNode), ElementsAre(element1, element2, element3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, CannotMoveEmptyRowsDownDisplayValues)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(-1, 1)};
|
||||||
|
|
||||||
|
model.moveRowsDown(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(displayValues(),
|
||||||
|
ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||||
|
ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||||
|
ElementsAre("pic.png", "poo", 111, IsInvalid())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, CannotMoveLastRowDownDisplayValues)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(2, 1), index(1, 2), index(2, 0)};
|
||||||
|
|
||||||
|
model.moveRowsDown(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(displayValues(),
|
||||||
|
ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||||
|
ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||||
|
ElementsAre("pic.png", "poo", 111, IsInvalid())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, MoveRowsDownDisplayValues)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(1, 1), index(0, 2), index(1, 0)};
|
||||||
|
|
||||||
|
model.moveRowsDown(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(displayValues(),
|
||||||
|
ElementsAre(ElementsAre("pic.png", "poo", 111, IsInvalid()),
|
||||||
|
ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||||
|
ElementsAre("pic.png", "bar", 4, IsInvalid())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, NoSelectionAfterCannotMoveLastRowsUp)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(2, 1), index(1, 2), index(2, 0)};
|
||||||
|
|
||||||
|
auto selection = model.moveRowsDown(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(selection.indexes(), IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, NoSelectionAfterMoveEmptyRowsUp)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(-1, 1)};
|
||||||
|
|
||||||
|
auto selection = model.moveRowsDown(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(selection.indexes(), IsEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ListModelEditor, SelectionAfterMoveRowsUp)
|
||||||
|
{
|
||||||
|
model.setListModel(listModelNode);
|
||||||
|
QList<QModelIndex> indices = {index(1, 1), index(0, 2), index(1, 0)};
|
||||||
|
|
||||||
|
auto selection = model.moveRowsDown(indices);
|
||||||
|
|
||||||
|
ASSERT_THAT(selection.indexes(),
|
||||||
|
ElementsAre(index(1, 0),
|
||||||
|
index(1, 1),
|
||||||
|
index(1, 2),
|
||||||
|
index(1, 3),
|
||||||
|
index(2, 0),
|
||||||
|
index(2, 1),
|
||||||
|
index(2, 2),
|
||||||
|
index(2, 3)));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
Reference in New Issue
Block a user