forked from qt-creator/qt-creator
QmlDesigner: Use GeneratedComponentsUtils in Model Editor
Change-Id: I567c746eb098c0c64d590ea7fed71f17de5adc76 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
@@ -407,16 +407,14 @@ void CollectionDetailsModel::renameCollection(const ModelNode &sourceNode,
|
|||||||
bool CollectionDetailsModel::saveDataStoreCollections()
|
bool CollectionDetailsModel::saveDataStoreCollections()
|
||||||
{
|
{
|
||||||
const ModelNode node = m_currentCollection.reference().node;
|
const ModelNode node = m_currentCollection.reference().node;
|
||||||
const Utils::FilePath path = CollectionEditorUtils::dataStoreJsonFilePath();
|
Utils::expected_str<QByteArray> jsonContents = m_jsonFilePath.fileContents();
|
||||||
Utils::FileReader fileData;
|
if (!jsonContents.has_value()) {
|
||||||
|
qWarning() << __FUNCTION__ << jsonContents.error();
|
||||||
if (!fileData.fetch(path)) {
|
|
||||||
qWarning() << Q_FUNC_INFO << "Cannot read the json file:" << fileData.errorString();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonParseError jpe;
|
QJsonParseError jpe;
|
||||||
QJsonDocument document = QJsonDocument::fromJson(fileData.data(), &jpe);
|
QJsonDocument document = QJsonDocument::fromJson(jsonContents.value(), &jpe);
|
||||||
|
|
||||||
if (jpe.error == QJsonParseError::NoError) {
|
if (jpe.error == QJsonParseError::NoError) {
|
||||||
QJsonObject obj = document.object();
|
QJsonObject obj = document.object();
|
||||||
@@ -432,7 +430,7 @@ bool CollectionDetailsModel::saveDataStoreCollections()
|
|||||||
|
|
||||||
document.setObject(obj);
|
document.setObject(obj);
|
||||||
|
|
||||||
if (CollectionEditorUtils::writeToJsonDocument(path, document)) {
|
if (CollectionEditorUtils::writeToJsonDocument(m_jsonFilePath, document)) {
|
||||||
const CollectionReference currentReference = m_currentCollection.reference();
|
const CollectionReference currentReference = m_currentCollection.reference();
|
||||||
for (CollectionDetails &collection : collectionsToBeSaved) {
|
for (CollectionDetails &collection : collectionsToBeSaved) {
|
||||||
collection.markSaved();
|
collection.markSaved();
|
||||||
@@ -618,6 +616,11 @@ QString CollectionDetailsModel::warningToString(DataTypeWarning::Warning warning
|
|||||||
return DataTypeWarning::getDataTypeWarningString(warning);
|
return DataTypeWarning::getDataTypeWarningString(warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CollectionDetailsModel::setJsonFilePath(const Utils::FilePath &filePath)
|
||||||
|
{
|
||||||
|
m_jsonFilePath = filePath;
|
||||||
|
}
|
||||||
|
|
||||||
void CollectionDetailsModel::setHasUnsavedChanges(bool val)
|
void CollectionDetailsModel::setHasUnsavedChanges(bool val)
|
||||||
{
|
{
|
||||||
if (m_hasUnsavedChanges == val)
|
if (m_hasUnsavedChanges == val)
|
||||||
|
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include "collectiondetails.h"
|
#include "collectiondetails.h"
|
||||||
|
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
|
||||||
@@ -60,6 +62,7 @@ public:
|
|||||||
Q_INVOKABLE void deselectAll();
|
Q_INVOKABLE void deselectAll();
|
||||||
Q_INVOKABLE QString warningToString(DataTypeWarning::Warning warning) const;
|
Q_INVOKABLE QString warningToString(DataTypeWarning::Warning warning) const;
|
||||||
|
|
||||||
|
void setJsonFilePath(const Utils::FilePath &filePath);
|
||||||
void loadCollection(const ModelNode &sourceNode, const QString &collection);
|
void loadCollection(const ModelNode &sourceNode, const QString &collection);
|
||||||
void removeCollection(const ModelNode &sourceNode, const QString &collection);
|
void removeCollection(const ModelNode &sourceNode, const QString &collection);
|
||||||
void removeAllCollections();
|
void removeAllCollections();
|
||||||
@@ -93,6 +96,7 @@ private:
|
|||||||
void ensureSingleCell();
|
void ensureSingleCell();
|
||||||
QJsonDocument readJsonFile(const QUrl &url);
|
QJsonDocument readJsonFile(const QUrl &url);
|
||||||
|
|
||||||
|
Utils::FilePath m_jsonFilePath;
|
||||||
QHash<CollectionReference, CollectionDetails> m_openedCollections;
|
QHash<CollectionReference, CollectionDetails> m_openedCollections;
|
||||||
CollectionDetails m_currentCollection;
|
CollectionDetails m_currentCollection;
|
||||||
bool m_isEmpty = true;
|
bool m_isEmpty = true;
|
||||||
|
@@ -16,4 +16,9 @@ inline constexpr char JSONCOLLECTIONMODEL_TYPENAME[] = "QtQuick.Studio.Ut
|
|||||||
inline constexpr char JSONCOLLECTIONCHILDMODEL_TYPENAME[] = "QtQuick.Studio.Utils.ChildListModel";
|
inline constexpr char JSONCOLLECTIONCHILDMODEL_TYPENAME[] = "QtQuick.Studio.Utils.ChildListModel";
|
||||||
inline constexpr char JSONBACKEND_TYPENAME[] = "JsonData";
|
inline constexpr char JSONBACKEND_TYPENAME[] = "JsonData";
|
||||||
|
|
||||||
|
inline constexpr QStringView DEFAULT_DATA_JSON_FILENAME = u"data.json";
|
||||||
|
inline constexpr QStringView DEFAULT_MODELS_JSON_FILENAME = u"models.json";
|
||||||
|
inline constexpr QStringView DEFAULT_DATASTORE_QML_FILENAME = u"DataStore.qml";
|
||||||
|
inline constexpr QStringView DEFAULT_JSONDATA_QML_FILENAME = u"JsonData.qml";
|
||||||
|
|
||||||
} // namespace QmlDesigner::CollectionEditorConstants
|
} // namespace QmlDesigner::CollectionEditorConstants
|
||||||
|
@@ -4,9 +4,11 @@
|
|||||||
#include "collectioneditorutils.h"
|
#include "collectioneditorutils.h"
|
||||||
|
|
||||||
#include "collectiondatatypemodel.h"
|
#include "collectiondatatypemodel.h"
|
||||||
|
#include "collectioneditorconstants.h"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "nodemetainfo.h"
|
#include "nodemetainfo.h"
|
||||||
#include "propertymetainfo.h"
|
#include "propertymetainfo.h"
|
||||||
|
#include "variantproperty.h"
|
||||||
|
|
||||||
#include <coreplugin/documentmanager.h>
|
#include <coreplugin/documentmanager.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
@@ -73,47 +75,6 @@ struct LessThanVisitor
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Utils::FilePath findFile(const Utils::FilePath &path, const QString &fileName)
|
|
||||||
{
|
|
||||||
QDirIterator it(path.toString(), QDirIterator::Subdirectories);
|
|
||||||
|
|
||||||
while (it.hasNext()) {
|
|
||||||
QFileInfo file(it.next());
|
|
||||||
if (file.isDir())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (file.fileName() == fileName)
|
|
||||||
return Utils::FilePath::fromFileInfo(file);
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Utils::FilePath dataStoreDir()
|
|
||||||
{
|
|
||||||
using Utils::FilePath;
|
|
||||||
ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject();
|
|
||||||
|
|
||||||
if (!currentProject)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
FilePath oldImportDirectory = currentProject->projectDirectory().pathAppended(
|
|
||||||
"imports/" + currentProject->displayName());
|
|
||||||
if (oldImportDirectory.exists())
|
|
||||||
return oldImportDirectory;
|
|
||||||
|
|
||||||
return currentProject->projectDirectory().pathAppended(currentProject->displayName());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Utils::FilePath collectionPath(const QString &filePath)
|
|
||||||
{
|
|
||||||
return dataStoreDir().pathAppended(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Utils::FilePath qmlDirFilePath()
|
|
||||||
{
|
|
||||||
return collectionPath("qmldir");
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace QmlDesigner::CollectionEditorUtils {
|
namespace QmlDesigner::CollectionEditorUtils {
|
||||||
@@ -123,25 +84,6 @@ bool variantIslessThan(const QVariant &a, const QVariant &b, DataType type)
|
|||||||
return std::visit(LessThanVisitor{}, valueToVariant(a, type), valueToVariant(b, type));
|
return std::visit(LessThanVisitor{}, valueToVariant(a, type), valueToVariant(b, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
QString getSourceCollectionType(const ModelNode &node)
|
|
||||||
{
|
|
||||||
using namespace QmlDesigner;
|
|
||||||
if (node.type() == CollectionEditorConstants::JSONCOLLECTIONMODEL_TYPENAME)
|
|
||||||
return "json";
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
Utils::FilePath dataStoreJsonFilePath()
|
|
||||||
{
|
|
||||||
return collectionPath("models.json");
|
|
||||||
}
|
|
||||||
|
|
||||||
Utils::FilePath dataStoreQmlFilePath()
|
|
||||||
{
|
|
||||||
return collectionPath("DataStore.qml");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool canAcceptCollectionAsModel(const ModelNode &node)
|
bool canAcceptCollectionAsModel(const ModelNode &node)
|
||||||
{
|
{
|
||||||
const NodeMetaInfo nodeMetaInfo = node.metaInfo();
|
const NodeMetaInfo nodeMetaInfo = node.metaInfo();
|
||||||
@@ -176,116 +118,25 @@ QString getSourceCollectionPath(const ModelNode &dataStoreNode)
|
|||||||
if (!dataStoreNode.isValid())
|
if (!dataStoreNode.isValid())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
const FilePath expectedFile = dataStoreJsonFilePath();
|
const QUrl dataStoreUrl = dataStoreNode.model()->fileUrl();
|
||||||
|
QUrl sourceValue = dataStoreNode.property("source").toVariantProperty().value().toUrl();
|
||||||
|
|
||||||
if (expectedFile.exists())
|
QUrl sourceUrl = sourceValue.isRelative() ? dataStoreUrl.resolved(sourceValue) : sourceValue;
|
||||||
|
|
||||||
|
const FilePath expectedFile = FilePath::fromUrl(sourceUrl);
|
||||||
|
|
||||||
|
if (expectedFile.isFile() && expectedFile.exists())
|
||||||
return expectedFile.toFSPathString();
|
return expectedFile.toFSPathString();
|
||||||
|
|
||||||
|
const FilePath defaultJsonFile = FilePath::fromUrl(
|
||||||
|
dataStoreUrl.resolved(CollectionEditorConstants::DEFAULT_MODELS_JSON_FILENAME.toString()));
|
||||||
|
|
||||||
|
if (defaultJsonFile.exists())
|
||||||
|
return defaultJsonFile.toFSPathString();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isDataStoreNode(const ModelNode &dataStoreNode)
|
|
||||||
{
|
|
||||||
using Utils::FilePath;
|
|
||||||
|
|
||||||
if (!dataStoreNode.isValid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const FilePath expectedFile = dataStoreQmlFilePath();
|
|
||||||
|
|
||||||
if (!expectedFile.exists())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
FilePath modelPath = FilePath::fromUserInput(dataStoreNode.model()->fileUrl().toLocalFile());
|
|
||||||
|
|
||||||
return modelPath.isSameFile(expectedFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ensureDataStoreExists(bool &justCreated)
|
|
||||||
{
|
|
||||||
using Utils::FilePath;
|
|
||||||
using Utils::FileReader;
|
|
||||||
using Utils::FileSaver;
|
|
||||||
|
|
||||||
FilePath qmlDestinationPath = dataStoreQmlFilePath();
|
|
||||||
justCreated = false;
|
|
||||||
|
|
||||||
auto extractDependency = [&justCreated](const FilePath &filePath) -> bool {
|
|
||||||
if (filePath.exists())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
const QString templateFileName = filePath.fileName() + u".tpl";
|
|
||||||
const FilePath templatePath = findFile(Core::ICore::resourcePath(), templateFileName);
|
|
||||||
if (!templatePath.exists()) {
|
|
||||||
qWarning() << Q_FUNC_INFO << __LINE__ << templateFileName << "does not exist";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!filePath.parentDir().ensureWritableDir()) {
|
|
||||||
qWarning() << Q_FUNC_INFO << __LINE__ << "Cannot create directory"
|
|
||||||
<< filePath.parentDir();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (templatePath.copyFile(filePath)) {
|
|
||||||
justCreated = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
qWarning() << Q_FUNC_INFO << __LINE__ << "Cannot copy" << templateFileName << "to" << filePath;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!extractDependency(dataStoreJsonFilePath()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!extractDependency(collectionPath("data.json")))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!extractDependency(collectionPath("JsonData.qml")))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!qmlDestinationPath.exists()) {
|
|
||||||
if (qmlDestinationPath.ensureExistingFile()) {
|
|
||||||
justCreated = true;
|
|
||||||
} else {
|
|
||||||
qWarning() << Q_FUNC_INFO << __LINE__ << "Can't create DataStore Qml File";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePath qmlDirPath = qmlDirFilePath();
|
|
||||||
qmlDirPath.ensureExistingFile();
|
|
||||||
|
|
||||||
FileReader qmlDirReader;
|
|
||||||
if (!qmlDirReader.fetch(qmlDirPath)) {
|
|
||||||
qWarning() << Q_FUNC_INFO << __LINE__ << "Can't read the content of the qmldir";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray qmlDirContent = qmlDirReader.data();
|
|
||||||
const QList<QByteArray> qmlDirLines = qmlDirContent.split('\n');
|
|
||||||
for (const QByteArray &line : qmlDirLines) {
|
|
||||||
if (line.startsWith("singleton DataStore "))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!qmlDirContent.isEmpty() && qmlDirContent.back() != '\n')
|
|
||||||
qmlDirContent.append("\n");
|
|
||||||
qmlDirContent.append("singleton DataStore 1.0 DataStore.qml\n");
|
|
||||||
|
|
||||||
FileSaver qmlDirSaver(qmlDirPath);
|
|
||||||
qmlDirSaver.write(qmlDirContent);
|
|
||||||
|
|
||||||
if (qmlDirSaver.finalize()) {
|
|
||||||
justCreated = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
qWarning() << Q_FUNC_INFO << __LINE__ << "Can't write to the qmldir file";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject defaultCollection()
|
QJsonObject defaultCollection()
|
||||||
{
|
{
|
||||||
QJsonObject collectionObject;
|
QJsonObject collectionObject;
|
||||||
@@ -337,6 +188,21 @@ QJsonObject defaultColorCollection()
|
|||||||
return collection.toLocalJson();
|
return collection.toLocalJson();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Utils::FilePath findFile(const Utils::FilePath &path, const QString &fileName)
|
||||||
|
{
|
||||||
|
QDirIterator it(path.toString(), QDirIterator::Subdirectories);
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
QFileInfo file(it.next());
|
||||||
|
if (file.isDir())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (file.fileName() == fileName)
|
||||||
|
return Utils::FilePath::fromFileInfo(file);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
bool writeToJsonDocument(const Utils::FilePath &path, const QJsonDocument &document, QString *errorString)
|
bool writeToJsonDocument(const Utils::FilePath &path, const QJsonDocument &document, QString *errorString)
|
||||||
{
|
{
|
||||||
Core::FileChangeBlocker fileBlocker(path);
|
Core::FileChangeBlocker fileBlocker(path);
|
||||||
|
@@ -4,7 +4,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "collectiondetails.h"
|
#include "collectiondetails.h"
|
||||||
#include "collectioneditorconstants.h"
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QJsonArray;
|
class QJsonArray;
|
||||||
@@ -19,22 +18,14 @@ namespace QmlDesigner::CollectionEditorUtils {
|
|||||||
|
|
||||||
bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails::DataType type);
|
bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails::DataType type);
|
||||||
|
|
||||||
QString getSourceCollectionType(const QmlDesigner::ModelNode &node);
|
|
||||||
|
|
||||||
QString getSourceCollectionPath(const QmlDesigner::ModelNode &dataStoreNode);
|
QString getSourceCollectionPath(const QmlDesigner::ModelNode &dataStoreNode);
|
||||||
|
|
||||||
Utils::FilePath dataStoreJsonFilePath();
|
Utils::FilePath findFile(const Utils::FilePath &path, const QString &fileName);
|
||||||
|
|
||||||
Utils::FilePath dataStoreQmlFilePath();
|
|
||||||
|
|
||||||
bool writeToJsonDocument(const Utils::FilePath &path,
|
bool writeToJsonDocument(const Utils::FilePath &path,
|
||||||
const QJsonDocument &document,
|
const QJsonDocument &document,
|
||||||
QString *errorString = nullptr);
|
QString *errorString = nullptr);
|
||||||
|
|
||||||
bool isDataStoreNode(const ModelNode &dataStoreNode);
|
|
||||||
|
|
||||||
bool ensureDataStoreExists(bool &justCreated);
|
|
||||||
|
|
||||||
bool canAcceptCollectionAsModel(const ModelNode &node);
|
bool canAcceptCollectionAsModel(const ModelNode &node);
|
||||||
|
|
||||||
bool hasTextRoleProperty(const ModelNode &node);
|
bool hasTextRoleProperty(const ModelNode &node);
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "collectionlistmodel.h"
|
#include "collectionlistmodel.h"
|
||||||
|
|
||||||
|
#include "collectioneditorconstants.h"
|
||||||
#include "collectioneditorutils.h"
|
#include "collectioneditorutils.h"
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
#include "qmldesignerplugin.h"
|
#include "qmldesignerplugin.h"
|
||||||
#include "variantproperty.h"
|
#include "variantproperty.h"
|
||||||
|
|
||||||
|
#include <designercore/generatedcomponentutils.h>
|
||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
#include <projectexplorer/projectexplorer.h>
|
#include <projectexplorer/projectexplorer.h>
|
||||||
#include <projectexplorer/projectmanager.h>
|
#include <projectexplorer/projectmanager.h>
|
||||||
@@ -77,8 +78,7 @@ CollectionView::CollectionView(ExternalDependenciesInterface &externalDependenci
|
|||||||
: AbstractView(externalDependencies)
|
: AbstractView(externalDependencies)
|
||||||
, m_dataStore(std::make_unique<DataStoreModelNode>())
|
, m_dataStore(std::make_unique<DataStoreModelNode>())
|
||||||
|
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
CollectionView::~CollectionView() = default;
|
CollectionView::~CollectionView() = default;
|
||||||
|
|
||||||
@@ -330,7 +330,8 @@ void CollectionView::resetDataStoreNode()
|
|||||||
if (!m_widget)
|
if (!m_widget)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_dataStore->reloadModel();
|
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||||
|
m_dataStore->reloadModel(compUtils.projectModulePath());
|
||||||
|
|
||||||
ModelNode dataStore = dataStoreNode();
|
ModelNode dataStore = dataStoreNode();
|
||||||
m_widget->setDataStoreExists(dataStore.isValid());
|
m_widget->setDataStoreExists(dataStore.isValid());
|
||||||
@@ -354,6 +355,7 @@ void CollectionView::resetDataStoreNode()
|
|||||||
|
|
||||||
if (dataStoreSingletonFound) {
|
if (dataStoreSingletonFound) {
|
||||||
m_widget->listModel()->setDataStoreNode(dataStore);
|
m_widget->listModel()->setDataStoreNode(dataStore);
|
||||||
|
m_widget->collectionDetailsModel()->setJsonFilePath(m_dataStore->jsonFilePath());
|
||||||
m_dataStoreTypeFound = true;
|
m_dataStoreTypeFound = true;
|
||||||
resetPuppet();
|
resetPuppet();
|
||||||
|
|
||||||
@@ -374,7 +376,7 @@ ModelNode CollectionView::dataStoreNode() const
|
|||||||
void CollectionView::ensureDataStoreExists()
|
void CollectionView::ensureDataStoreExists()
|
||||||
{
|
{
|
||||||
bool filesJustCreated = false;
|
bool filesJustCreated = false;
|
||||||
bool filesExist = CollectionEditorUtils::ensureDataStoreExists(filesJustCreated);
|
bool filesExist = createDataStore(filesJustCreated);
|
||||||
if (filesExist && filesJustCreated) {
|
if (filesExist && filesJustCreated) {
|
||||||
// Force code model reset to notice changes to existing module
|
// Force code model reset to notice changes to existing module
|
||||||
if (auto modelManager = QmlJS::ModelManagerInterface::instance())
|
if (auto modelManager = QmlJS::ModelManagerInterface::instance())
|
||||||
@@ -411,6 +413,103 @@ void CollectionView::unloadDataStore()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CollectionView::createDataStore(bool &justCreated) const
|
||||||
|
{
|
||||||
|
using Utils::FilePath;
|
||||||
|
using Utils::FileReader;
|
||||||
|
using Utils::FileSaver;
|
||||||
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
|
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
|
||||||
|
FilePath projectModulePath = compUtils.projectModulePath(true);
|
||||||
|
|
||||||
|
FilePath qmlTargetPath = projectModulePath.resolvePath(
|
||||||
|
CollectionEditorConstants::DEFAULT_DATASTORE_QML_FILENAME.toString());
|
||||||
|
justCreated = false;
|
||||||
|
|
||||||
|
auto extractDependency = [&justCreated](const FilePath &filePath) -> bool {
|
||||||
|
if (filePath.exists())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const QString templateFileName = filePath.fileName() + u".tpl";
|
||||||
|
const FilePath templatePath = CollectionEditorUtils::findFile(Core::ICore::resourcePath(),
|
||||||
|
templateFileName);
|
||||||
|
if (!templatePath.exists()) {
|
||||||
|
qWarning() << Q_FUNC_INFO << __LINE__ << templateFileName << "does not exist";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filePath.parentDir().ensureWritableDir()) {
|
||||||
|
qWarning() << Q_FUNC_INFO << __LINE__ << "Cannot create directory"
|
||||||
|
<< filePath.parentDir();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (templatePath.copyFile(filePath)) {
|
||||||
|
justCreated = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qWarning() << Q_FUNC_INFO << __LINE__ << "Cannot copy" << templateFileName << "to" << filePath;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!extractDependency(projectModulePath.resolvePath(
|
||||||
|
CollectionEditorConstants::DEFAULT_MODELS_JSON_FILENAME.toString()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!extractDependency(projectModulePath.resolvePath(
|
||||||
|
CollectionEditorConstants::DEFAULT_DATA_JSON_FILENAME.toString()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!extractDependency(projectModulePath.resolvePath(
|
||||||
|
CollectionEditorConstants::DEFAULT_JSONDATA_QML_FILENAME.toString()))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!qmlTargetPath.exists()) {
|
||||||
|
if (qmlTargetPath.ensureExistingFile()) {
|
||||||
|
justCreated = true;
|
||||||
|
} else {
|
||||||
|
qWarning() << Q_FUNC_INFO << __LINE__ << "Can't create DataStore Qml File";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath qmlDirPath = projectModulePath.resolvePath("qmldir"_L1);
|
||||||
|
qmlDirPath.ensureExistingFile();
|
||||||
|
|
||||||
|
FileReader qmlDirReader;
|
||||||
|
if (!qmlDirReader.fetch(qmlDirPath)) {
|
||||||
|
qWarning() << Q_FUNC_INFO << __LINE__ << "Can't read the content of the qmldir";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray qmlDirContent = qmlDirReader.data();
|
||||||
|
const QList<QByteArray> qmlDirLines = qmlDirContent.split('\n');
|
||||||
|
for (const QByteArray &line : qmlDirLines) {
|
||||||
|
if (line.startsWith("singleton DataStore "))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!qmlDirContent.isEmpty() && qmlDirContent.back() != '\n')
|
||||||
|
qmlDirContent.append("\n");
|
||||||
|
qmlDirContent.append("singleton DataStore 1.0 DataStore.qml\n");
|
||||||
|
|
||||||
|
FileSaver qmlDirSaver(qmlDirPath);
|
||||||
|
qmlDirSaver.write(qmlDirContent);
|
||||||
|
|
||||||
|
if (qmlDirSaver.finalize()) {
|
||||||
|
justCreated = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
qWarning() << Q_FUNC_INFO << __LINE__ << "Can't write to the qmldir file";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void CollectionView::ensureStudioModelImport()
|
void CollectionView::ensureStudioModelImport()
|
||||||
{
|
{
|
||||||
executeInTransaction(__FUNCTION__, [&] {
|
executeInTransaction(__FUNCTION__, [&] {
|
||||||
|
@@ -23,6 +23,7 @@ class CollectionListModel;
|
|||||||
class CollectionTask;
|
class CollectionTask;
|
||||||
class CollectionWidget;
|
class CollectionWidget;
|
||||||
class DataStoreModelNode;
|
class DataStoreModelNode;
|
||||||
|
class GeneratedComponentUtils;
|
||||||
|
|
||||||
class CollectionView : public AbstractView
|
class CollectionView : public AbstractView
|
||||||
{
|
{
|
||||||
@@ -69,6 +70,7 @@ private:
|
|||||||
|
|
||||||
NodeMetaInfo jsonCollectionMetaInfo() const;
|
NodeMetaInfo jsonCollectionMetaInfo() const;
|
||||||
void unloadDataStore();
|
void unloadDataStore();
|
||||||
|
bool createDataStore(bool &justCreated) const;
|
||||||
void ensureStudioModelImport();
|
void ensureStudioModelImport();
|
||||||
void onItemLibraryNodeCreated(const ModelNode &node);
|
void onItemLibraryNodeCreated(const ModelNode &node);
|
||||||
void addTask(QSharedPointer<CollectionTask> task);
|
void addTask(QSharedPointer<CollectionTask> task);
|
||||||
|
@@ -21,9 +21,7 @@
|
|||||||
#include <qmljstools/qmljstoolssettings.h>
|
#include <qmljstools/qmljstoolssettings.h>
|
||||||
|
|
||||||
#include <coreplugin/documentmanager.h>
|
#include <coreplugin/documentmanager.h>
|
||||||
#include <projectexplorer/project.h>
|
|
||||||
#include <projectexplorer/projectexplorer.h>
|
#include <projectexplorer/projectexplorer.h>
|
||||||
#include <projectexplorer/projectmanager.h>
|
|
||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
@@ -114,7 +112,6 @@ void setQmlContextToModel(QmlDesigner::Model *model, const QString &qmlContext)
|
|||||||
std::unique_ptr<RewriterView> rewriter = std::make_unique<RewriterView>(
|
std::unique_ptr<RewriterView> rewriter = std::make_unique<RewriterView>(
|
||||||
externalDependencies, QmlDesigner::RewriterView::Validate);
|
externalDependencies, QmlDesigner::RewriterView::Validate);
|
||||||
|
|
||||||
rewriter->setParent(model);
|
|
||||||
rewriter->setTextModifier(modifier.get());
|
rewriter->setTextModifier(modifier.get());
|
||||||
rewriter->setCheckSemanticErrors(false);
|
rewriter->setCheckSemanticErrors(false);
|
||||||
|
|
||||||
@@ -126,22 +123,21 @@ void setQmlContextToModel(QmlDesigner::Model *model, const QString &qmlContext)
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
DataStoreModelNode::DataStoreModelNode()
|
DataStoreModelNode::DataStoreModelNode() = default;
|
||||||
{
|
|
||||||
reloadModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataStoreModelNode::reloadModel()
|
void DataStoreModelNode::reloadModel(const Utils::FilePath &projectModulePath)
|
||||||
{
|
{
|
||||||
using Utils::FilePath;
|
using Utils::FilePath;
|
||||||
if (!ProjectExplorer::ProjectManager::startupProject()) {
|
if (!projectModulePath.exists()) {
|
||||||
reset();
|
reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool forceUpdate = false;
|
bool forceUpdate = false;
|
||||||
|
|
||||||
const FilePath dataStoreQmlPath = CollectionEditorUtils::dataStoreQmlFilePath();
|
const FilePath dataStoreQmlPath = projectModulePath.resolvePath(
|
||||||
const FilePath dataStoreJsonPath = CollectionEditorUtils::dataStoreJsonFilePath();
|
CollectionEditorConstants::DEFAULT_DATASTORE_QML_FILENAME.toString());
|
||||||
|
const FilePath dataStoreJsonPath = projectModulePath.resolvePath(
|
||||||
|
CollectionEditorConstants::DEFAULT_MODELS_JSON_FILENAME.toString());
|
||||||
QUrl dataStoreQmlUrl = dataStoreQmlPath.toUrl();
|
QUrl dataStoreQmlUrl = dataStoreQmlPath.toUrl();
|
||||||
|
|
||||||
if (dataStoreQmlPath.exists() && dataStoreJsonPath.exists()) {
|
if (dataStoreQmlPath.exists() && dataStoreJsonPath.exists()) {
|
||||||
@@ -196,6 +192,15 @@ ModelNode DataStoreModelNode::modelNode() const
|
|||||||
return m_model->rootModelNode();
|
return m_model->rootModelNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Utils::FilePath DataStoreModelNode::jsonFilePath() const
|
||||||
|
{
|
||||||
|
QUrl modelUrl = m_model->fileUrl();
|
||||||
|
return Utils::FilePath::fromUserInput(modelUrl.isLocalFile() ? modelUrl.toLocalFile()
|
||||||
|
: modelUrl.toString())
|
||||||
|
.parentDir()
|
||||||
|
.resolvePath(CollectionEditorConstants::DEFAULT_MODELS_JSON_FILENAME.toString());
|
||||||
|
}
|
||||||
|
|
||||||
QString DataStoreModelNode::getModelQmlText()
|
QString DataStoreModelNode::getModelQmlText()
|
||||||
{
|
{
|
||||||
ModelNode node = modelNode();
|
ModelNode node = modelNode();
|
||||||
|
@@ -24,11 +24,12 @@ public:
|
|||||||
|
|
||||||
DataStoreModelNode();
|
DataStoreModelNode();
|
||||||
|
|
||||||
void reloadModel();
|
void reloadModel(const Utils::FilePath &projectModulePath);
|
||||||
QStringList collectionNames() const;
|
QStringList collectionNames() const;
|
||||||
|
|
||||||
Model *model() const;
|
Model *model() const;
|
||||||
ModelNode modelNode() const;
|
ModelNode modelNode() const;
|
||||||
|
Utils::FilePath jsonFilePath() const;
|
||||||
|
|
||||||
void setCollectionNames(const QStringList &newCollectionNames);
|
void setCollectionNames(const QStringList &newCollectionNames);
|
||||||
void addCollection(const QString &collectionName);
|
void addCollection(const QString &collectionName);
|
||||||
|
@@ -2,11 +2,36 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include "generatedcomponentutils.h"
|
#include "generatedcomponentutils.h"
|
||||||
|
|
||||||
#include <qmldesignerconstants.h>
|
#include <qmldesignerconstants.h>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
bool couldBeProjectModule(const Utils::FilePath &path, const QString &projectName)
|
||||||
|
{
|
||||||
|
if (!path.exists())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Utils::FilePath qmlDirPath = path.pathAppended("qmldir");
|
||||||
|
if (qmlDirPath.exists()) {
|
||||||
|
Utils::expected_str<QByteArray> qmldirContents = qmlDirPath.fileContents();
|
||||||
|
if (!qmldirContents.has_value())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const QString expectedLine = QLatin1String("module %1").arg(projectName);
|
||||||
|
QByteArray fileContents = qmldirContents.value();
|
||||||
|
QTextStream stream(fileContents);
|
||||||
|
while (!stream.atEnd()) {
|
||||||
|
QString lineData = stream.readLine().trimmed();
|
||||||
|
if (lineData.startsWith(u"module "))
|
||||||
|
return lineData == expectedLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (path.endsWith(projectName))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
GeneratedComponentUtils::GeneratedComponentUtils(ExternalDependenciesInterface &externalDependencies)
|
GeneratedComponentUtils::GeneratedComponentUtils(ExternalDependenciesInterface &externalDependencies)
|
||||||
: m_externalDependencies(externalDependencies)
|
: m_externalDependencies(externalDependencies)
|
||||||
{
|
{
|
||||||
@@ -106,6 +131,36 @@ Utils::FilePath GeneratedComponentUtils::effectBundlePath() const
|
|||||||
return basePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE));
|
return basePath.resolvePath(QLatin1String(Constants::COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Utils::FilePath GeneratedComponentUtils::projectModulePath(bool generateIfNotExists) const
|
||||||
|
{
|
||||||
|
using Utils::FilePath;
|
||||||
|
FilePath projectPath = FilePath::fromString(m_externalDependencies.currentProjectDirPath());
|
||||||
|
|
||||||
|
if (projectPath.isEmpty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const QString projectName = m_externalDependencies.projectName();
|
||||||
|
|
||||||
|
FilePath newImportDirectory = projectPath.pathAppended(projectName);
|
||||||
|
if (couldBeProjectModule(newImportDirectory, projectName))
|
||||||
|
return newImportDirectory;
|
||||||
|
|
||||||
|
FilePath oldImportDirectory = projectPath.resolvePath(QLatin1String("imports/") + projectName);
|
||||||
|
if (couldBeProjectModule(oldImportDirectory, projectName))
|
||||||
|
return oldImportDirectory;
|
||||||
|
|
||||||
|
for (const QString &path : m_externalDependencies.projectModulePaths()) {
|
||||||
|
FilePath dir = FilePath::fromString(path);
|
||||||
|
if (couldBeProjectModule(dir, projectName))
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generateIfNotExists)
|
||||||
|
newImportDirectory.createDir();
|
||||||
|
|
||||||
|
return newImportDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
bool GeneratedComponentUtils::isImport3dPath(const QString &path) const
|
bool GeneratedComponentUtils::isImport3dPath(const QString &path) const
|
||||||
{
|
{
|
||||||
return path.contains('/' + QLatin1String(Constants::OLD_QUICK_3D_ASSETS_FOLDER))
|
return path.contains('/' + QLatin1String(Constants::OLD_QUICK_3D_ASSETS_FOLDER))
|
||||||
|
@@ -23,6 +23,7 @@ public:
|
|||||||
Utils::FilePath import3dBasePath() const;
|
Utils::FilePath import3dBasePath() const;
|
||||||
Utils::FilePath materialBundlePath() const;
|
Utils::FilePath materialBundlePath() const;
|
||||||
Utils::FilePath effectBundlePath() const;
|
Utils::FilePath effectBundlePath() const;
|
||||||
|
Utils::FilePath projectModulePath(bool generateIfNotExists = false) const;
|
||||||
|
|
||||||
bool isImport3dPath(const QString &path) const;
|
bool isImport3dPath(const QString &path) const;
|
||||||
bool isComposedEffectPath(const QString &path) const;
|
bool isComposedEffectPath(const QString &path) const;
|
||||||
|
@@ -28,6 +28,7 @@ public:
|
|||||||
virtual QString qmlPuppetFallbackDirectory() const = 0;
|
virtual QString qmlPuppetFallbackDirectory() const = 0;
|
||||||
virtual QString defaultPuppetToplevelBuildDirectory() const = 0;
|
virtual QString defaultPuppetToplevelBuildDirectory() const = 0;
|
||||||
virtual QUrl projectUrl() const = 0;
|
virtual QUrl projectUrl() const = 0;
|
||||||
|
virtual QString projectName() const = 0;
|
||||||
virtual QString currentProjectDirPath() const = 0;
|
virtual QString currentProjectDirPath() const = 0;
|
||||||
virtual QUrl currentResourcePath() const = 0;
|
virtual QUrl currentResourcePath() const = 0;
|
||||||
virtual void parseItemLibraryDescriptions() = 0;
|
virtual void parseItemLibraryDescriptions() = 0;
|
||||||
|
@@ -56,6 +56,11 @@ QUrl ExternalDependencies::projectUrl() const
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ExternalDependencies::projectName() const
|
||||||
|
{
|
||||||
|
return QmlDesignerPlugin::instance()->documentManager().currentProjectName();
|
||||||
|
}
|
||||||
|
|
||||||
QString ExternalDependencies::currentProjectDirPath() const
|
QString ExternalDependencies::currentProjectDirPath() const
|
||||||
{
|
{
|
||||||
return QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath().toString();
|
return QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath().toString();
|
||||||
|
@@ -21,6 +21,7 @@ public:
|
|||||||
QString qmlPuppetFallbackDirectory() const override;
|
QString qmlPuppetFallbackDirectory() const override;
|
||||||
QString defaultPuppetToplevelBuildDirectory() const override;
|
QString defaultPuppetToplevelBuildDirectory() const override;
|
||||||
QUrl projectUrl() const override;
|
QUrl projectUrl() const override;
|
||||||
|
QString projectName() const override;
|
||||||
QString currentProjectDirPath() const override;
|
QString currentProjectDirPath() const override;
|
||||||
QUrl currentResourcePath() const override;
|
QUrl currentResourcePath() const override;
|
||||||
void parseItemLibraryDescriptions() override;
|
void parseItemLibraryDescriptions() override;
|
||||||
|
@@ -149,6 +149,7 @@ public:
|
|||||||
QString defaultPuppetToplevelBuildDirectory() const override { return {}; }
|
QString defaultPuppetToplevelBuildDirectory() const override { return {}; }
|
||||||
QString qmlPuppetFallbackDirectory() const override { return {}; }
|
QString qmlPuppetFallbackDirectory() const override { return {}; }
|
||||||
QUrl projectUrl() const override { return {}; }
|
QUrl projectUrl() const override { return {}; }
|
||||||
|
QString projectName() const override { return {}; }
|
||||||
void parseItemLibraryDescriptions() override {}
|
void parseItemLibraryDescriptions() override {}
|
||||||
const QmlDesigner::DesignerSettings &designerSettings() const override { return settings; }
|
const QmlDesigner::DesignerSettings &designerSettings() const override { return settings; }
|
||||||
void undoOnCurrentDesignDocument() override {}
|
void undoOnCurrentDesignDocument() override {}
|
||||||
|
@@ -15,6 +15,7 @@ public:
|
|||||||
MOCK_METHOD(QString, qmlPuppetFallbackDirectory, (), (const, override));
|
MOCK_METHOD(QString, qmlPuppetFallbackDirectory, (), (const, override));
|
||||||
MOCK_METHOD(QString, defaultPuppetToplevelBuildDirectory, (), (const, override));
|
MOCK_METHOD(QString, defaultPuppetToplevelBuildDirectory, (), (const, override));
|
||||||
MOCK_METHOD(QUrl, projectUrl, (), (const, override));
|
MOCK_METHOD(QUrl, projectUrl, (), (const, override));
|
||||||
|
MOCK_METHOD(QString, projectName, (), (const, override));
|
||||||
MOCK_METHOD(QString, currentProjectDirPath, (), (const, override));
|
MOCK_METHOD(QString, currentProjectDirPath, (), (const, override));
|
||||||
MOCK_METHOD(QUrl, currentResourcePath, (), (const, override));
|
MOCK_METHOD(QUrl, currentResourcePath, (), (const, override));
|
||||||
MOCK_METHOD(void, parseItemLibraryDescriptions, (), (override));
|
MOCK_METHOD(void, parseItemLibraryDescriptions, (), (override));
|
||||||
|
Reference in New Issue
Block a user