forked from qt-creator/qt-creator
QmlDesigner: Fix the bug for dropping ListView when DataStore is missing
* Creating ListView will be postponed when the dataStore is just created so that the model manager can update the information of DataStore. * The initial delegate and model for the listview are faked in order to show the same shape before and after the assignment. Change-Id: I45ac7486890556136ca98fc131f90896efc3b839 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
@@ -347,12 +347,6 @@ bool ensureDataStoreExists(bool &justCreated)
|
|||||||
|
|
||||||
if (qmlDirSaver.finalize()) {
|
if (qmlDirSaver.finalize()) {
|
||||||
justCreated = true;
|
justCreated = true;
|
||||||
|
|
||||||
// Force code model reset to notice changes to existing module
|
|
||||||
auto modelManager = QmlJS::ModelManagerInterface::instance();
|
|
||||||
if (modelManager)
|
|
||||||
modelManager->resetCodeModel();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,15 +19,16 @@
|
|||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
#include <projectexplorer/projectexplorer.h>
|
#include <projectexplorer/projectexplorer.h>
|
||||||
#include <projectexplorer/projectmanager.h>
|
#include <projectexplorer/projectmanager.h>
|
||||||
|
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
inline bool isStudioCollectionModel(const QmlDesigner::ModelNode &node)
|
inline bool isStudioCollectionModel(const QmlDesigner::ModelNode &node)
|
||||||
@@ -139,6 +140,12 @@ void CollectionView::modelAttached(Model *model)
|
|||||||
resetDataStoreNode();
|
resetDataStoreNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CollectionView::modelAboutToBeDetached([[maybe_unused]] Model *model)
|
||||||
|
{
|
||||||
|
m_libraryInfoIsUpdated = false;
|
||||||
|
disconnect(m_documentUpdateConnection);
|
||||||
|
}
|
||||||
|
|
||||||
void CollectionView::nodeReparented(const ModelNode &node,
|
void CollectionView::nodeReparented(const ModelNode &node,
|
||||||
[[maybe_unused]] const NodeAbstractProperty &newPropertyParent,
|
[[maybe_unused]] const NodeAbstractProperty &newPropertyParent,
|
||||||
[[maybe_unused]] const NodeAbstractProperty &oldPropertyParent,
|
[[maybe_unused]] const NodeAbstractProperty &oldPropertyParent,
|
||||||
@@ -292,6 +299,10 @@ void CollectionView::assignCollectionToNode(const QString &collectionName, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
NodeProperty delegateProperty = node.nodeProperty("delegate");
|
NodeProperty delegateProperty = node.nodeProperty("delegate");
|
||||||
|
// Remove the old model node if is available
|
||||||
|
if (delegateProperty.modelNode())
|
||||||
|
delegateProperty.modelNode().destroy();
|
||||||
|
|
||||||
delegateProperty.setModelNode(rowItem);
|
delegateProperty.setModelNode(rowItem);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -324,8 +335,29 @@ void CollectionView::ensureDataStoreExists()
|
|||||||
{
|
{
|
||||||
bool filesJustCreated = false;
|
bool filesJustCreated = false;
|
||||||
bool filesExist = CollectionEditorUtils::ensureDataStoreExists(filesJustCreated);
|
bool filesExist = CollectionEditorUtils::ensureDataStoreExists(filesJustCreated);
|
||||||
if (filesExist && filesJustCreated)
|
if (filesExist) {
|
||||||
|
if (filesJustCreated) {
|
||||||
|
// Force code model reset to notice changes to existing module
|
||||||
|
auto modelManager = QmlJS::ModelManagerInterface::instance();
|
||||||
|
if (modelManager) {
|
||||||
|
m_libraryInfoIsUpdated = false;
|
||||||
|
|
||||||
|
m_expectedDocumentUpdates.clear();
|
||||||
|
m_expectedDocumentUpdates << CollectionEditorUtils::dataStoreQmlFilePath()
|
||||||
|
<< CollectionEditorUtils::dataStoreJsonFilePath();
|
||||||
|
|
||||||
|
m_documentUpdateConnection = connect(modelManager,
|
||||||
|
&QmlJS::ModelManagerInterface::documentUpdated,
|
||||||
|
this,
|
||||||
|
&CollectionView::onDocumentUpdated);
|
||||||
|
|
||||||
|
modelManager->resetCodeModel();
|
||||||
|
}
|
||||||
resetDataStoreNode();
|
resetDataStoreNode();
|
||||||
|
} else {
|
||||||
|
m_libraryInfoIsUpdated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CollectionView::collectionNameFromDataStoreChildren(const PropertyName &childPropertyName) const
|
QString CollectionView::collectionNameFromDataStoreChildren(const PropertyName &childPropertyName) const
|
||||||
@@ -387,9 +419,62 @@ void CollectionView::onItemLibraryNodeCreated(const ModelNode &node)
|
|||||||
sourceModel->addCollectionToSource(dataStoreNode(),
|
sourceModel->addCollectionToSource(dataStoreNode(),
|
||||||
newCollectionName,
|
newCollectionName,
|
||||||
CollectionEditorUtils::defaultColorCollection());
|
CollectionEditorUtils::defaultColorCollection());
|
||||||
assignCollectionToNode(newCollectionName, node);
|
|
||||||
m_widget->openCollection(newCollectionName);
|
m_widget->openCollection(newCollectionName);
|
||||||
|
new DelayedAssignCollectionToItem(this, node, newCollectionName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CollectionView::onDocumentUpdated(const QSharedPointer<const QmlJS::Document> &doc)
|
||||||
|
{
|
||||||
|
if (m_expectedDocumentUpdates.contains(doc->fileName()))
|
||||||
|
m_expectedDocumentUpdates.remove(doc->fileName());
|
||||||
|
|
||||||
|
if (m_expectedDocumentUpdates.isEmpty()) {
|
||||||
|
disconnect(m_documentUpdateConnection);
|
||||||
|
m_libraryInfoIsUpdated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DelayedAssignCollectionToItem::DelayedAssignCollectionToItem(CollectionView *parent,
|
||||||
|
const ModelNode &node,
|
||||||
|
const QString &collectionName)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_collectionView(parent)
|
||||||
|
, m_node(node)
|
||||||
|
, m_name(collectionName)
|
||||||
|
{
|
||||||
|
checkAndAssign();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DelayedAssignCollectionToItem::checkAndAssign()
|
||||||
|
{
|
||||||
|
AbstractView *view = m_node.view();
|
||||||
|
|
||||||
|
if (!m_node || !m_collectionView || !view || ++m_counter > 50) {
|
||||||
|
deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dataStoreFound = false;
|
||||||
|
|
||||||
|
if (m_collectionView->isDataStoreReady()) {
|
||||||
|
for (const QmlTypeData &cppTypeData : view->rewriterView()->getQMLTypes()) {
|
||||||
|
if (cppTypeData.isSingleton && cppTypeData.typeName == "DataStore")
|
||||||
|
dataStoreFound = true;
|
||||||
|
}
|
||||||
|
if (!dataStoreFound && !m_rewriterAmended) {
|
||||||
|
m_collectionView->model()->rewriterView()->forceAmend();
|
||||||
|
m_rewriterAmended = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dataStoreFound) {
|
||||||
|
QTimer::singleShot(100, this, &DelayedAssignCollectionToItem::checkAndAssign);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_collectionView->assignCollectionToNode(m_name, m_node);
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -7,6 +7,9 @@
|
|||||||
#include "datastoremodelnode.h"
|
#include "datastoremodelnode.h"
|
||||||
#include "modelnode.h"
|
#include "modelnode.h"
|
||||||
|
|
||||||
|
namespace QmlJS {
|
||||||
|
class Document;
|
||||||
|
}
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class CollectionWidget;
|
class CollectionWidget;
|
||||||
@@ -23,6 +26,7 @@ public:
|
|||||||
WidgetInfo widgetInfo() override;
|
WidgetInfo widgetInfo() override;
|
||||||
|
|
||||||
void modelAttached(Model *model) override;
|
void modelAttached(Model *model) override;
|
||||||
|
void modelAboutToBeDetached(Model *model) override;
|
||||||
|
|
||||||
void nodeReparented(const ModelNode &node,
|
void nodeReparented(const ModelNode &node,
|
||||||
const NodeAbstractProperty &newPropertyParent,
|
const NodeAbstractProperty &newPropertyParent,
|
||||||
@@ -58,14 +62,41 @@ public:
|
|||||||
void ensureDataStoreExists();
|
void ensureDataStoreExists();
|
||||||
QString collectionNameFromDataStoreChildren(const PropertyName &childPropertyName) const;
|
QString collectionNameFromDataStoreChildren(const PropertyName &childPropertyName) const;
|
||||||
|
|
||||||
|
bool isDataStoreReady() const { return m_libraryInfoIsUpdated; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void refreshModel();
|
void refreshModel();
|
||||||
NodeMetaInfo jsonCollectionMetaInfo() const;
|
NodeMetaInfo jsonCollectionMetaInfo() const;
|
||||||
NodeMetaInfo csvCollectionMetaInfo() const;
|
NodeMetaInfo csvCollectionMetaInfo() const;
|
||||||
void ensureStudioModelImport();
|
void ensureStudioModelImport();
|
||||||
void onItemLibraryNodeCreated(const ModelNode &node);
|
void onItemLibraryNodeCreated(const ModelNode &node);
|
||||||
|
void onDocumentUpdated(const QSharedPointer<const QmlJS::Document> &doc);
|
||||||
|
|
||||||
QPointer<CollectionWidget> m_widget;
|
QPointer<CollectionWidget> m_widget;
|
||||||
std::unique_ptr<DataStoreModelNode> m_dataStore;
|
std::unique_ptr<DataStoreModelNode> m_dataStore;
|
||||||
|
QSet<Utils::FilePath> m_expectedDocumentUpdates;
|
||||||
|
QMetaObject::Connection m_documentUpdateConnection;
|
||||||
|
bool m_libraryInfoIsUpdated = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DelayedAssignCollectionToItem : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DelayedAssignCollectionToItem(CollectionView *parent,
|
||||||
|
const ModelNode &node,
|
||||||
|
const QString &collectionName);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void checkAndAssign();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPointer<CollectionView> m_collectionView;
|
||||||
|
ModelNode m_node;
|
||||||
|
QString m_name;
|
||||||
|
int m_counter = 0;
|
||||||
|
bool m_rewriterAmended = false;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
@@ -459,8 +459,16 @@ void DataStoreModelNode::assignCollectionToNode(AbstractView *view,
|
|||||||
|
|
||||||
view->executeInTransaction("assignCollectionToNode", [&]() {
|
view->executeInTransaction("assignCollectionToNode", [&]() {
|
||||||
QString identifier = QString("DataStore.%1").arg(QString::fromLatin1(sourceProperty.name()));
|
QString identifier = QString("DataStore.%1").arg(QString::fromLatin1(sourceProperty.name()));
|
||||||
|
|
||||||
|
// Remove the old model node property if exists
|
||||||
|
NodeProperty modelNodeProperty = targetNode.nodeProperty("model");
|
||||||
|
if (modelNodeProperty.modelNode())
|
||||||
|
modelNodeProperty.modelNode().destroy();
|
||||||
|
|
||||||
|
// Assign the collection to the node
|
||||||
BindingProperty modelProperty = targetNode.bindingProperty("model");
|
BindingProperty modelProperty = targetNode.bindingProperty("model");
|
||||||
modelProperty.setExpression(identifier);
|
modelProperty.setExpression(identifier);
|
||||||
|
|
||||||
if (CollectionEditorUtils::hasTextRoleProperty(targetNode)) {
|
if (CollectionEditorUtils::hasTextRoleProperty(targetNode)) {
|
||||||
VariantProperty textRoleProperty = targetNode.variantProperty("textRole");
|
VariantProperty textRoleProperty = targetNode.variantProperty("textRole");
|
||||||
const QVariant currentTextRoleValue = textRoleProperty.value();
|
const QVariant currentTextRoleValue = textRoleProperty.value();
|
||||||
|
@@ -4,40 +4,38 @@
|
|||||||
import QtQuick 1.0
|
import QtQuick 1.0
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
width: 110
|
width: 160
|
||||||
height: 160
|
height: 80
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
ListElement {
|
|
||||||
name: "Grey"
|
|
||||||
colorCode: "grey"
|
|
||||||
}
|
|
||||||
ListElement {
|
ListElement {
|
||||||
name: "Red"
|
name: "Red"
|
||||||
colorCode: "red"
|
colorCode: "red"
|
||||||
}
|
}
|
||||||
|
ListElement {
|
||||||
|
name: "Green"
|
||||||
|
colorCode: "green"
|
||||||
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
name: "Blue"
|
name: "Blue"
|
||||||
colorCode: "blue"
|
colorCode: "blue"
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
name: "Green"
|
name: "White"
|
||||||
colorCode: "green"
|
colorCode: "white"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: Item {
|
delegate: Row {
|
||||||
width: 80
|
spacing: 5
|
||||||
height: 40
|
Rectangle {
|
||||||
x: 5
|
width: 100
|
||||||
Row {
|
height: 20
|
||||||
id: row1
|
color: colorCode
|
||||||
spacing: 10
|
|
||||||
Rectangle { width: 40; height: 40; color: colorCode; }
|
|
||||||
Text {
|
|
||||||
text: name
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
font.bold: true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: 100
|
||||||
|
text: name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,40 +4,38 @@
|
|||||||
import QtQuick 2.0
|
import QtQuick 2.0
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
width: 110
|
width: 160
|
||||||
height: 160
|
height: 80
|
||||||
model: ListModel {
|
model: ListModel {
|
||||||
ListElement {
|
|
||||||
name: "Grey"
|
|
||||||
colorCode: "grey"
|
|
||||||
}
|
|
||||||
ListElement {
|
ListElement {
|
||||||
name: "Red"
|
name: "Red"
|
||||||
colorCode: "red"
|
colorCode: "red"
|
||||||
}
|
}
|
||||||
|
ListElement {
|
||||||
|
name: "Green"
|
||||||
|
colorCode: "green"
|
||||||
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
name: "Blue"
|
name: "Blue"
|
||||||
colorCode: "blue"
|
colorCode: "blue"
|
||||||
}
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
name: "Green"
|
name: "White"
|
||||||
colorCode: "green"
|
colorCode: "white"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: Item {
|
delegate: Row {
|
||||||
width: 80
|
spacing: 5
|
||||||
height: 40
|
Rectangle {
|
||||||
x: 5
|
width: 100
|
||||||
Row {
|
height: 20
|
||||||
id: row1
|
color: colorCode
|
||||||
spacing: 10
|
|
||||||
Rectangle { width: 40; height: 40; color: colorCode; }
|
|
||||||
Text {
|
|
||||||
text: name
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
font.bold: true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: 100
|
||||||
|
text: name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user