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:
Marco Bubke
2020-08-06 10:45:02 +02:00
parent 97cc02b781
commit b4027b7943
4 changed files with 96 additions and 25 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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