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()) {
|
||||
justCreated = true;
|
||||
|
||||
// Force code model reset to notice changes to existing module
|
||||
auto modelManager = QmlJS::ModelManagerInterface::instance();
|
||||
if (modelManager)
|
||||
modelManager->resetCodeModel();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -19,15 +19,16 @@
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/projectmanager.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace {
|
||||
|
||||
inline bool isStudioCollectionModel(const QmlDesigner::ModelNode &node)
|
||||
@@ -139,6 +140,12 @@ void CollectionView::modelAttached(Model *model)
|
||||
resetDataStoreNode();
|
||||
}
|
||||
|
||||
void CollectionView::modelAboutToBeDetached([[maybe_unused]] Model *model)
|
||||
{
|
||||
m_libraryInfoIsUpdated = false;
|
||||
disconnect(m_documentUpdateConnection);
|
||||
}
|
||||
|
||||
void CollectionView::nodeReparented(const ModelNode &node,
|
||||
[[maybe_unused]] const NodeAbstractProperty &newPropertyParent,
|
||||
[[maybe_unused]] const NodeAbstractProperty &oldPropertyParent,
|
||||
@@ -292,6 +299,10 @@ void CollectionView::assignCollectionToNode(const QString &collectionName, const
|
||||
}
|
||||
|
||||
NodeProperty delegateProperty = node.nodeProperty("delegate");
|
||||
// Remove the old model node if is available
|
||||
if (delegateProperty.modelNode())
|
||||
delegateProperty.modelNode().destroy();
|
||||
|
||||
delegateProperty.setModelNode(rowItem);
|
||||
}
|
||||
});
|
||||
@@ -324,8 +335,29 @@ void CollectionView::ensureDataStoreExists()
|
||||
{
|
||||
bool filesJustCreated = false;
|
||||
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();
|
||||
} else {
|
||||
m_libraryInfoIsUpdated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString CollectionView::collectionNameFromDataStoreChildren(const PropertyName &childPropertyName) const
|
||||
@@ -387,9 +419,62 @@ void CollectionView::onItemLibraryNodeCreated(const ModelNode &node)
|
||||
sourceModel->addCollectionToSource(dataStoreNode(),
|
||||
newCollectionName,
|
||||
CollectionEditorUtils::defaultColorCollection());
|
||||
assignCollectionToNode(newCollectionName, node);
|
||||
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
|
||||
|
@@ -7,6 +7,9 @@
|
||||
#include "datastoremodelnode.h"
|
||||
#include "modelnode.h"
|
||||
|
||||
namespace QmlJS {
|
||||
class Document;
|
||||
}
|
||||
namespace QmlDesigner {
|
||||
|
||||
class CollectionWidget;
|
||||
@@ -23,6 +26,7 @@ public:
|
||||
WidgetInfo widgetInfo() override;
|
||||
|
||||
void modelAttached(Model *model) override;
|
||||
void modelAboutToBeDetached(Model *model) override;
|
||||
|
||||
void nodeReparented(const ModelNode &node,
|
||||
const NodeAbstractProperty &newPropertyParent,
|
||||
@@ -58,14 +62,41 @@ public:
|
||||
void ensureDataStoreExists();
|
||||
QString collectionNameFromDataStoreChildren(const PropertyName &childPropertyName) const;
|
||||
|
||||
bool isDataStoreReady() const { return m_libraryInfoIsUpdated; }
|
||||
|
||||
private:
|
||||
void refreshModel();
|
||||
NodeMetaInfo jsonCollectionMetaInfo() const;
|
||||
NodeMetaInfo csvCollectionMetaInfo() const;
|
||||
void ensureStudioModelImport();
|
||||
void onItemLibraryNodeCreated(const ModelNode &node);
|
||||
void onDocumentUpdated(const QSharedPointer<const QmlJS::Document> &doc);
|
||||
|
||||
QPointer<CollectionWidget> m_widget;
|
||||
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
|
||||
|
@@ -459,8 +459,16 @@ void DataStoreModelNode::assignCollectionToNode(AbstractView *view,
|
||||
|
||||
view->executeInTransaction("assignCollectionToNode", [&]() {
|
||||
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");
|
||||
modelProperty.setExpression(identifier);
|
||||
|
||||
if (CollectionEditorUtils::hasTextRoleProperty(targetNode)) {
|
||||
VariantProperty textRoleProperty = targetNode.variantProperty("textRole");
|
||||
const QVariant currentTextRoleValue = textRoleProperty.value();
|
||||
|
@@ -4,40 +4,38 @@
|
||||
import QtQuick 1.0
|
||||
|
||||
ListView {
|
||||
width: 110
|
||||
height: 160
|
||||
width: 160
|
||||
height: 80
|
||||
model: ListModel {
|
||||
ListElement {
|
||||
name: "Grey"
|
||||
colorCode: "grey"
|
||||
}
|
||||
ListElement {
|
||||
name: "Red"
|
||||
colorCode: "red"
|
||||
}
|
||||
ListElement {
|
||||
name: "Green"
|
||||
colorCode: "green"
|
||||
}
|
||||
ListElement {
|
||||
name: "Blue"
|
||||
colorCode: "blue"
|
||||
}
|
||||
ListElement {
|
||||
name: "Green"
|
||||
colorCode: "green"
|
||||
name: "White"
|
||||
colorCode: "white"
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
width: 80
|
||||
height: 40
|
||||
x: 5
|
||||
Row {
|
||||
id: row1
|
||||
spacing: 10
|
||||
Rectangle { width: 40; height: 40; color: colorCode; }
|
||||
Text {
|
||||
text: name
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.bold: true
|
||||
delegate: Row {
|
||||
spacing: 5
|
||||
Rectangle {
|
||||
width: 100
|
||||
height: 20
|
||||
color: colorCode
|
||||
}
|
||||
|
||||
Text {
|
||||
width: 100
|
||||
text: name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -4,40 +4,38 @@
|
||||
import QtQuick 2.0
|
||||
|
||||
ListView {
|
||||
width: 110
|
||||
height: 160
|
||||
width: 160
|
||||
height: 80
|
||||
model: ListModel {
|
||||
ListElement {
|
||||
name: "Grey"
|
||||
colorCode: "grey"
|
||||
}
|
||||
ListElement {
|
||||
name: "Red"
|
||||
colorCode: "red"
|
||||
}
|
||||
ListElement {
|
||||
name: "Green"
|
||||
colorCode: "green"
|
||||
}
|
||||
ListElement {
|
||||
name: "Blue"
|
||||
colorCode: "blue"
|
||||
}
|
||||
ListElement {
|
||||
name: "Green"
|
||||
colorCode: "green"
|
||||
name: "White"
|
||||
colorCode: "white"
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
width: 80
|
||||
height: 40
|
||||
x: 5
|
||||
Row {
|
||||
id: row1
|
||||
spacing: 10
|
||||
Rectangle { width: 40; height: 40; color: colorCode; }
|
||||
Text {
|
||||
text: name
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.bold: true
|
||||
delegate: Row {
|
||||
spacing: 5
|
||||
Rectangle {
|
||||
width: 100
|
||||
height: 20
|
||||
color: colorCode
|
||||
}
|
||||
|
||||
Text {
|
||||
width: 100
|
||||
text: name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user