summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Bubke <marco.bubke@qt.io>2020-07-02 19:19:52 +0200
committerMarco Bubke <marco.bubke@qt.io>2020-07-08 09:17:41 +0000
commitb73ce9eccfc5f3e06fa92efb53bd8c341c13f3e7 (patch)
tree97a669c36de59d330faefb7840c0ccd79b875978
parent7504c966bf64a4b38b8e9ff200c93b2e8470acad (diff)
downloadqt-creator-b73ce9eccfc5f3e06fa92efb53bd8c341c13f3e7.tar.gz
QmlDesigner: Add row move up and move down buttons
Task-number: QDS-2294 Change-Id: Ia1e64d0811f55151dfe529db4868821840a8fba9 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
-rw-r--r--src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.cpp19
-rw-r--r--src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.h4
-rw-r--r--src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp36
-rw-r--r--src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h3
-rw-r--r--tests/unit/unittest/listmodeleditor-test.cpp239
5 files changed, 301 insertions, 0 deletions
diff --git a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.cpp b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.cpp
index 968c719af0..0cf73976a8 100644
--- a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.cpp
+++ b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.cpp
@@ -27,6 +27,7 @@
#include "listmodeleditormodel.h"
#include <theme.h>
+#include <qmldesignericons.h>
#include <coreplugin/icore.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_removeColumnsAction = toolBar->addAction(getIcon(Theme::Icon::deleteColumn),
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;
@@ -83,6 +88,8 @@ void ListModelEditorDialog::setModel(ListModelEditorModel *model)
connect(m_addColumnAction, &QAction::triggered, this, &ListModelEditorDialog::openColumnDialog);
connect(m_removeRowsAction, &QAction::triggered, this, &ListModelEditorDialog::removeRows);
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(),
&QHeaderView::sectionDoubleClicked,
this,
@@ -134,4 +141,16 @@ void ListModelEditorDialog::changeHeader(int column)
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
diff --git a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.h b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.h
index 519d0869fa..24e19c8ff9 100644
--- a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.h
+++ b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.h
@@ -59,6 +59,8 @@ private:
void removeRows();
void removeColumns();
void changeHeader(int column);
+ void moveRowsDown();
+ void moveRowsUp();
private:
ListModelEditorModel *m_model{};
@@ -66,6 +68,8 @@ private:
QAction *m_removeRowsAction{};
QAction *m_addColumnAction{};
QAction *m_removeColumnsAction{};
+ QAction *m_moveUpAction{};
+ QAction *m_moveDownAction{};
QTableView *m_tableView{};
};
diff --git a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp
index 066af6e345..0aeabb8b89 100644
--- a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp
+++ b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp
@@ -319,6 +319,42 @@ void ListModelEditorModel::renameColumn(int oldColumn, const QString &newColumnN
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> columns;
diff --git a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h
index 3976b34a9d..3056d32dbb 100644
--- a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h
+++ b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h
@@ -27,6 +27,7 @@
#include <modelnode.h>
+#include <QItemSelection>
#include <QStandardItemModel>
namespace QmlDesigner {
@@ -53,6 +54,8 @@ public:
void removeColumns(const QList<QModelIndex> &indices);
void removeRows(const QList<QModelIndex> &indices);
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> filterRows(const QList<QModelIndex> &indices);
diff --git a/tests/unit/unittest/listmodeleditor-test.cpp b/tests/unit/unittest/listmodeleditor-test.cpp
index 1dcd54c286..af4009ae9b 100644
--- a/tests/unit/unittest/listmodeleditor-test.cpp
+++ b/tests/unit/unittest/listmodeleditor-test.cpp
@@ -175,6 +175,11 @@ public:
QModelIndex index(int row, int column) const { return model.index(row, column); }
+ QList<ModelNode> elements(const ModelNode &node) const
+ {
+ return node.defaultNodeListProperty().toModelNodeList();
+ }
+
protected:
std::unique_ptr<QmlDesigner::Model> designerModel{QmlDesigner::Model::create("QtQuick.Item", 1, 1)};
NiceMock<MockListModelEditorView> mockView;
@@ -1033,4 +1038,238 @@ TEST_F(ListModelEditor, FilterRowsEmptyInput)
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