forked from qt-creator/qt-creator
QmlDesigner: Fix crash for list view model
There was a type, so it crashed. The code is now under tests so we cannot break it anymore. Task-number: QDS-2563 Change-Id: I81426a9f8a568b217b7bf9c8c261b24be14ff61a Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -363,32 +363,30 @@ public:
|
||||
|
||||
bool isEnabled(const SelectionContext &) const override { return true; }
|
||||
|
||||
static ModelNode listModelNode(const ModelNode &listViewNode)
|
||||
{
|
||||
if (listViewNode.hasProperty("model")) {
|
||||
if (listViewNode.hasBindingProperty("model"))
|
||||
return listViewNode.bindingProperty("model").resolveToModelNode();
|
||||
else if (listViewNode.hasNodeProperty("model"))
|
||||
return listViewNode.nodeProperty("model").modelNode();
|
||||
}
|
||||
|
||||
ModelNode newModel = listViewNode.view()->createModelNode("QtQml.Models.ListModel", 2, 15);
|
||||
listViewNode.nodeProperty("mode").reparentHere(newModel);
|
||||
|
||||
return newModel;
|
||||
}
|
||||
|
||||
static void openDialog(const SelectionContext &selectionState)
|
||||
{
|
||||
ListModelEditorModel model;
|
||||
|
||||
ModelNode targetNode = selectionState.targetNode();
|
||||
if (!targetNode.isValid())
|
||||
targetNode = selectionState.currentSingleSelectedNode();
|
||||
if (!targetNode.isValid())
|
||||
return;
|
||||
|
||||
model.setListModel(listModelNode(targetNode));
|
||||
AbstractView *view = targetNode.view();
|
||||
NodeMetaInfo modelMetaInfo = view->model()->metaInfo("ListModel");
|
||||
NodeMetaInfo elementMetaInfo = view->model()->metaInfo("ListElement");
|
||||
|
||||
ListModelEditorModel model{[&] {
|
||||
return view->createModelNode(modelMetaInfo.typeName(),
|
||||
modelMetaInfo.majorVersion(),
|
||||
modelMetaInfo.minorVersion());
|
||||
},
|
||||
[&] {
|
||||
return view->createModelNode(elementMetaInfo.typeName(),
|
||||
elementMetaInfo.majorVersion(),
|
||||
elementMetaInfo.minorVersion());
|
||||
}};
|
||||
|
||||
model.setListView(targetNode);
|
||||
|
||||
ListModelEditorDialog dialog{Core::ICore::mainWindow()};
|
||||
dialog.setModel(&model);
|
||||
|
@@ -26,7 +26,9 @@
|
||||
#include "listmodeleditormodel.h"
|
||||
|
||||
#include <abstractview.h>
|
||||
#include <bindingproperty.h>
|
||||
#include <nodelistproperty.h>
|
||||
#include <nodeproperty.h>
|
||||
#include <variantproperty.h>
|
||||
|
||||
#include <QVariant>
|
||||
@@ -185,6 +187,22 @@ void renameProperties(const QStandardItemModel *model,
|
||||
static_cast<ListModelItem *>(model->item(rowIndex, columnIndex))->renameProperty(newPropertyName);
|
||||
}
|
||||
|
||||
ModelNode listModelNode(const ModelNode &listViewNode,
|
||||
const std::function<ModelNode()> &createModelCallback)
|
||||
{
|
||||
if (listViewNode.hasProperty("model")) {
|
||||
if (listViewNode.hasBindingProperty("model"))
|
||||
return listViewNode.bindingProperty("model").resolveToModelNode();
|
||||
else if (listViewNode.hasNodeProperty("model"))
|
||||
return listViewNode.nodeProperty("model").modelNode();
|
||||
}
|
||||
|
||||
ModelNode newModel = createModelCallback();
|
||||
listViewNode.nodeProperty("model").reparentHere(newModel);
|
||||
|
||||
return newModel;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ListModelEditorModel::populateModel()
|
||||
@@ -214,9 +232,20 @@ void ListModelEditorModel::appendItems(const ModelNode &listElementNode)
|
||||
appendRow(row);
|
||||
}
|
||||
|
||||
void ListModelEditorModel::setListModel(ModelNode node)
|
||||
{
|
||||
m_listModelNode = node;
|
||||
populateModel();
|
||||
}
|
||||
|
||||
void ListModelEditorModel::setListView(ModelNode listView)
|
||||
{
|
||||
setListModel(listModelNode(listView, m_createModelCallback));
|
||||
}
|
||||
|
||||
void ListModelEditorModel::addRow()
|
||||
{
|
||||
auto newElement = m_listModelNode.view()->createModelNode("QtQml.Models.ListElement", 2, 15);
|
||||
auto newElement = m_createElementCallback();
|
||||
m_listModelNode.defaultNodeListProperty().reparentHere(newElement);
|
||||
|
||||
appendItems(newElement);
|
||||
|
@@ -38,11 +38,15 @@ class ListModelEditorModel : public QStandardItemModel
|
||||
using QStandardItemModel::removeRows;
|
||||
|
||||
public:
|
||||
void setListModel(ModelNode node)
|
||||
{
|
||||
m_listModelNode = node;
|
||||
populateModel();
|
||||
}
|
||||
ListModelEditorModel(std::function<ModelNode()> createModelCallback,
|
||||
std::function<ModelNode()> createElementCallback)
|
||||
: m_createModelCallback(std::move(createModelCallback))
|
||||
, m_createElementCallback(std::move(createElementCallback))
|
||||
{}
|
||||
|
||||
void setListModel(ModelNode node);
|
||||
|
||||
void setListView(ModelNode listView);
|
||||
|
||||
void addRow();
|
||||
void addColumn(const QString &columnName);
|
||||
@@ -70,6 +74,8 @@ private:
|
||||
private:
|
||||
ModelNode m_listModelNode;
|
||||
QList<QmlDesigner::PropertyName> m_propertyNames;
|
||||
std::function<ModelNode()> m_createModelCallback;
|
||||
std::function<ModelNode()> m_createElementCallback;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -31,8 +31,10 @@
|
||||
|
||||
#include <qmldesigner/components/listmodeleditor/listmodeleditormodel.h>
|
||||
#include <qmldesigner/designercore/include/abstractview.h>
|
||||
#include <qmldesigner/designercore/include/bindingproperty.h>
|
||||
#include <qmldesigner/designercore/include/model.h>
|
||||
#include <qmldesigner/designercore/include/nodelistproperty.h>
|
||||
#include <qmldesigner/designercore/include/nodeproperty.h>
|
||||
#include <qmldesigner/designercore/include/variantproperty.h>
|
||||
|
||||
namespace {
|
||||
@@ -94,6 +96,7 @@ public:
|
||||
|
||||
emptyListModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
|
||||
|
||||
listViewNode = mockView.createModelNode("QtQuick.ListView", 2, 15);
|
||||
listModelNode = mockView.createModelNode("QtQml.Models.ListModel", 2, 15);
|
||||
mockView.rootModelNode().defaultNodeListProperty().reparentHere(listModelNode);
|
||||
element1 = createElement({{"name", "foo"}, {"value", 1}, {"value2", 42}});
|
||||
@@ -183,7 +186,10 @@ public:
|
||||
protected:
|
||||
std::unique_ptr<QmlDesigner::Model> designerModel{QmlDesigner::Model::create("QtQuick.Item", 1, 1)};
|
||||
NiceMock<MockListModelEditorView> mockView;
|
||||
QmlDesigner::ListModelEditorModel model;
|
||||
QmlDesigner::ListModelEditorModel model{
|
||||
[&] { return mockView.createModelNode("QtQml.Models.ListModel", 2, 15); },
|
||||
[&] { return mockView.createModelNode("QtQml.Models.ListElement", 2, 15); }};
|
||||
ModelNode listViewNode;
|
||||
ModelNode listModelNode;
|
||||
ModelNode emptyListModelNode;
|
||||
ModelNode element1;
|
||||
@@ -1272,4 +1278,36 @@ TEST_F(ListModelEditor, SelectionAfterMoveRowsUp)
|
||||
index(2, 3)));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ListViewHasNoModel)
|
||||
{
|
||||
model.setListView(listViewNode);
|
||||
|
||||
ASSERT_THAT(listViewNode.nodeProperty("model").modelNode().type(), Eq("QtQml.Models.ListModel"));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ListViewHasModelInside)
|
||||
{
|
||||
listViewNode.nodeProperty("model").reparentHere(listModelNode);
|
||||
|
||||
model.setListView(listViewNode);
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||
ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||
ElementsAre("pic.png", "poo", 111, IsInvalid())));
|
||||
}
|
||||
|
||||
TEST_F(ListModelEditor, ListViewHasModelBinding)
|
||||
{
|
||||
listModelNode.setIdWithoutRefactoring("listModel");
|
||||
listViewNode.bindingProperty("model").setExpression("listModel");
|
||||
|
||||
model.setListView(listViewNode);
|
||||
|
||||
ASSERT_THAT(displayValues(),
|
||||
ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42),
|
||||
ElementsAre("pic.png", "bar", 4, IsInvalid()),
|
||||
ElementsAre("pic.png", "poo", 111, IsInvalid())));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
Reference in New Issue
Block a user