Commit 75f867b9 authored by Tim Jenssen's avatar Tim Jenssen Committed by Thomas Hartmann

QmlDesigner: Implementing changing the type of a node in the model

The type of a ModelNode can now be changed in the model.
The rewriter can already handle the case and the NodeInstanceView
does a reset.
We still have to expose this new feature in the UI.

Change-Id: I9bc405d40b123f257324ba582a4451fbd395f24f
Reviewed-by: Tim Jenssen's avatarTim Jenssen <tim.jenssen@qt.io>
parent 31e2fcc8
......@@ -238,6 +238,12 @@ void NavigatorView::rootNodeTypeChanged(const QString & /*type*/, int /*majorVer
m_treeModel->updateItemRow(rootModelNode());
}
void NavigatorView::nodeTypeChanged(const ModelNode &node, const TypeName &, int , int)
{
if (m_treeModel->isInTree(node))
m_treeModel->updateItemRow(node);
}
void NavigatorView::auxiliaryDataChanged(const ModelNode &modelNode, const PropertyName & name, const QVariant & /*data*/)
{
if (name == "invisible" && m_treeModel->isInTree(modelNode))
......
......@@ -62,6 +62,7 @@ public:
void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override;
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override;
void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) override;
void propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList) override;
void propertiesRemoved(const QList<AbstractProperty>& propertyList) override;
......
......@@ -720,6 +720,12 @@ void PropertyEditorView::rootNodeTypeChanged(const QString &/*type*/, int /*majo
// TODO: we should react to this case
}
void PropertyEditorView::nodeTypeChanged(const ModelNode &node, const TypeName &, int, int)
{
if (node == m_selectedNode)
delayedResetView();
}
void PropertyEditorView::nodeReparented(const ModelNode &node,
const NodeAbstractProperty & /*newPropertyParent*/,
const NodeAbstractProperty & /*oldPropertyParent*/,
......
......@@ -80,6 +80,7 @@ public:
void instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &propertyList) override;
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override;
void nodeReparented(const ModelNode &node,
const NodeAbstractProperty &newPropertyParent,
......
......@@ -194,6 +194,7 @@ public:
virtual void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange);
virtual void signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty>& propertyList, PropertyChangeFlags propertyChange);
virtual void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion);
virtual void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion);
virtual void instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &propertyList);
virtual void instanceErrorChanged(const QVector<ModelNode> &errorNodeList);
......
......@@ -102,6 +102,7 @@ public:
NodeAbstractProperty parentProperty() const;
void setParentProperty(NodeAbstractProperty parent);
void changeType(const TypeName &typeName, int majorVersion, int minorVersion);
void setParentProperty(const ModelNode &newParentNode, const PropertyName &propertyName);
bool hasParentProperty() const;
......
......@@ -91,6 +91,7 @@ public:
const NodeAbstractProperty &oldPropertyParent,
AbstractView::PropertyChangeFlags propertyChange) override;
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override;
void fileUrlChanged(const QUrl &oldUrl, const QUrl &newUrl) override;
void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) override;
void nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex) override;
......
......@@ -89,6 +89,7 @@ public:
void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) override;
void nodeOrderChanged(const NodeListProperty &listProperty, const ModelNode &movedNode, int oldIndex) override;
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override;
void customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList,
const QList<QVariant> &data) override;
......
......@@ -365,6 +365,11 @@ void NodeInstanceView::rootNodeTypeChanged(const QString &/*type*/, int /*majorV
restartProcess();
}
void NodeInstanceView::nodeTypeChanged(const ModelNode &, const TypeName &, int, int)
{
restartProcess();
}
void NodeInstanceView::bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags /*propertyChange*/)
{
nodeInstanceServer()->changePropertyBindings(createChangeBindingCommand(propertyList));
......
......@@ -325,6 +325,11 @@ void AbstractView::rootNodeTypeChanged(const QString &/*type*/, int /*majorVersi
{
}
void AbstractView::nodeTypeChanged(const ModelNode & /*node*/, const TypeName & /*type*/, int /*majorVersion*/, int /*minorVersion*/)
{
}
void AbstractView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
{
}
......
......@@ -186,6 +186,22 @@ void ModelPrivate::setFileUrl(const QUrl &fileUrl)
}
}
void ModelPrivate::changeNodeType(const InternalNodePointer &internalNodePointer, const TypeName &typeName, int majorVersion, int minorVersion)
{
internalNodePointer->setType(typeName);
internalNodePointer->setMajorVersion(majorVersion);
internalNodePointer->setMinorVersion(minorVersion);
try {
notifyNodeTypeChanged(internalNodePointer, typeName, majorVersion, minorVersion);
} catch (const RewritingException &e) {
throw InvalidArgumentException(__LINE__, __FUNCTION__, __FILE__, e.description().toUtf8());
}
}
InternalNode::Pointer ModelPrivate::createNode(const TypeName &typeName,
int majorVersion,
int minorVersion,
......@@ -953,6 +969,37 @@ void ModelPrivate::notifyNodeRemoved(const InternalNodePointer &internalNodePoin
resetModelByRewriter(description);
}
void ModelPrivate::notifyNodeTypeChanged(const InternalNodePointer &internalNodePointer, const TypeName &type, int majorVersion, int minorVersion)
{
bool resetModel = false;
QString description;
try {
if (rewriterView()) {
ModelNode modelNode(internalNodePointer, model(), rewriterView());
rewriterView()->nodeTypeChanged(modelNode, type, majorVersion, minorVersion);
}
} catch (const RewritingException &e) {
description = e.description();
resetModel = true;
}
foreach (const QPointer<AbstractView> &view, m_viewList) {
Q_ASSERT(view != 0);
ModelNode modelNode(internalNodePointer, model(), view.data());
view->nodeTypeChanged(modelNode, type, majorVersion, minorVersion);
}
if (nodeInstanceView()) {
ModelNode modelNode(internalNodePointer, model(), nodeInstanceView());
nodeInstanceView()->nodeTypeChanged(modelNode, type, majorVersion, minorVersion);
}
if (resetModel)
resetModelByRewriter(description);
}
void ModelPrivate::notifyNodeIdChanged(const InternalNode::Pointer& internalNodePointer, const QString& newId, const QString& oldId)
{
bool resetModel = false;
......
......@@ -109,6 +109,7 @@ public:
void removeNode(const InternalNodePointer &node);
void changeNodeId(const InternalNodePointer& internalNodePointer, const QString& id);
void changeNodeType(const InternalNodePointer& internalNodePointer, const TypeName &typeName, int majorVersion, int minorVersion);
InternalNodePointer rootNode() const;
InternalNodePointer findNode(const QString &id) const;
......@@ -130,6 +131,7 @@ public:
void notifyNodeAboutToBeRemoved(const InternalNodePointer &internalNodePointer);
void notifyNodeRemoved(const InternalNodePointer &internalNodePointer, const InternalNodePointer &parentNodePointer, const PropertyName &parentPropertyName, AbstractView::PropertyChangeFlags propertyChange);
void notifyNodeIdChanged(const InternalNodePointer& internalNodePointer, const QString& newId, const QString& oldId);
void notifyNodeTypeChanged(const InternalNodePointer& internalNodePointer, const TypeName &type, int majorVersion, int minorVersion);
void notifyPropertiesRemoved(const QList<PropertyPair> &propertyList);
void notifyPropertiesAboutToBeRemoved(const QList<InternalPropertyPointer> &internalPropertyList);
......
......@@ -408,6 +408,17 @@ void ModelNode::setParentProperty(NodeAbstractProperty parent)
parent.reparentHere(*this);
}
void ModelNode::changeType(const TypeName &typeName, int majorVersion, int minorVersion)
{
if (!isValid()) {
Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid");
throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__);
}
model()->d->changeNodeType(internalNode(), typeName, majorVersion, minorVersion);
}
void ModelNode::setParentProperty(const ModelNode &newParentNode, const PropertyName &propertyName)
{
setParentProperty(newParentNode.nodeAbstractProperty(propertyName));
......
......@@ -285,6 +285,18 @@ void RewriterView::rootNodeTypeChanged(const QString &type, int majorVersion, in
applyChanges();
}
void RewriterView::nodeTypeChanged(const ModelNode &node, const TypeName &type, int majorVersion, int minorVersion)
{
Q_ASSERT(textModifier());
if (textToModelMerger()->isActive())
return;
modelToTextMerger()->nodeTypeChanged(node, QString::fromLatin1(type), majorVersion, minorVersion);
if (!isModificationGroupActive())
applyChanges();
}
void RewriterView::customNotification(const AbstractView * /*view*/, const QString &identifier, const QList<ModelNode> & /* nodeList */, const QList<QVariant> & /*data */)
{
if (identifier == StartRewriterAmend || identifier == EndRewriterAmend)
......
......@@ -6149,6 +6149,95 @@ void tst_TestCore::testModelNodeIsAncestorOf()
QVERIFY(item3.isAncestorOf(item4));
}
void tst_TestCore::testModelChangeType()
{
const QLatin1String qmlString("\n"
"import QtQuick 2.1\n"
"\n"
"Rectangle {\n"
" id: rootItem\n"
" Item {\n"
" id: firstItem\n"
" x: 10\n"
" }\n"
" Item {\n"
" id: secondItem\n"
" x: 20\n"
" }\n"
"}");
QPlainTextEdit textEdit;
textEdit.setPlainText(qmlString);
NotIndentingTextEditModifier textModifier(&textEdit);
QScopedPointer<Model> model(Model::create("QtQuick.Item", 2, 1));
QVERIFY(model.data());
QScopedPointer<TestView> view(new TestView(model.data()));
model->attachView(view.data());
// read in
QScopedPointer<TestRewriterView> testRewriterView(new TestRewriterView());
testRewriterView->setTextModifier(&textModifier);
model->attachView(testRewriterView.data());
ModelNode rootNode = view->rootModelNode();
QVERIFY(rootNode.isValid());
QCOMPARE(rootNode.type(), QmlDesigner::TypeName("QtQuick.Rectangle"));
QCOMPARE(rootNode.id(), QLatin1String("rootItem"));
ModelNode childNode = rootNode.nodeListProperty(("data")).toModelNodeList().at(0);
QVERIFY(childNode.isValid());
QCOMPARE(childNode.type(), QmlDesigner::TypeName("QtQuick.Item"));
QCOMPARE(childNode.id(), QLatin1String("firstItem"));
childNode.changeType("QtQuick.Rectangle", 2, 0);
QCOMPARE(childNode.type(), QmlDesigner::TypeName("QtQuick.Rectangle"));
const QLatin1String expectedQmlCode1("\n"
"import QtQuick 2.1\n"
"\n"
"Rectangle {\n"
" id: rootItem\n"
" Rectangle {\n"
" id: firstItem\n"
" x: 10\n"
" }\n"
" Item {\n"
" id: secondItem\n"
" x: 20\n"
" }\n"
"}");
QCOMPARE(textEdit.toPlainText(), expectedQmlCode1);
childNode = rootNode.nodeListProperty(("data")).toModelNodeList().at(1);
QVERIFY(childNode.isValid());
QCOMPARE(childNode.type(), QmlDesigner::TypeName("QtQuick.Item"));
QCOMPARE(childNode.id(), QLatin1String("secondItem"));
childNode.changeType("QtQuick.Rectangle", 2, 0);
QCOMPARE(childNode.type(), QmlDesigner::TypeName("QtQuick.Rectangle"));
const QLatin1String expectedQmlCode2("\n"
"import QtQuick 2.1\n"
"\n"
"Rectangle {\n"
" id: rootItem\n"
" Rectangle {\n"
" id: firstItem\n"
" x: 10\n"
" }\n"
" Rectangle {\n"
" id: secondItem\n"
" x: 20\n"
" }\n"
"}");
QCOMPARE(textEdit.toPlainText(), expectedQmlCode2);
}
void tst_TestCore::testModelDefaultProperties()
{
QScopedPointer<Model> model(createModel("QtQuick.Rectangle", 2, 0));
......
......@@ -87,6 +87,7 @@ private slots:
void testModelPropertyValueTypes();
void testModelNodeInHierarchy();
void testModelNodeIsAncestorOf();
void testModelChangeType();
//
// unit tests Rewriter
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment