QmlDesigner: Add DataStore Dynamically to the project

Task-number: QDS-11400
Change-Id: I0ad20a6aad604aa66d4d0f24ca32a19fb9e94a08
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Ali Kianian
2023-11-27 23:50:53 +02:00
parent 1423740e09
commit 4129c7703b
7 changed files with 166 additions and 34 deletions

View File

@@ -11,6 +11,7 @@
#include <variant>
#include <coreplugin/icore.h>
#include <utils/qtcassert.h>
#include <projectexplorer/project.h>
@@ -66,6 +67,43 @@ 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 {};
return currentProject->projectDirectory().pathAppended("/imports/"
+ currentProject->displayName());
}
inline Utils::FilePath collectionPath(const QString &filePath)
{
return dataStoreDir().pathAppended("/" + filePath);
}
inline Utils::FilePath qmlDirFilePath()
{
return collectionPath("qmldir");
}
} // namespace
namespace QmlDesigner::CollectionEditor {
@@ -126,6 +164,16 @@ void assignCollectionToNode(AbstractView *view,
});
}
Utils::FilePath dataStoreJsonFilePath()
{
return collectionPath("models.json");
}
Utils::FilePath dataStoreQmlFilePath()
{
return collectionPath("DataStore.qml");
}
bool canAcceptCollectionAsModel(const ModelNode &node)
{
const NodeMetaInfo nodeMetaInfo = node.metaInfo();
@@ -143,13 +191,10 @@ bool canAcceptCollectionAsModel(const ModelNode &node)
QString getSourceCollectionPath(const ModelNode &dataStoreNode)
{
using Utils::FilePath;
ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject();
if (!currentProject || !dataStoreNode.isValid())
if (!dataStoreNode.isValid())
return {};
const FilePath expectedFile = currentProject->projectDirectory().pathAppended(
"/imports/" + currentProject->displayName() + "/DataStore.json");
const FilePath expectedFile = dataStoreJsonFilePath();
if (expectedFile.exists())
return expectedFile.toFSPathString();
@@ -160,13 +205,14 @@ QString getSourceCollectionPath(const ModelNode &dataStoreNode)
bool isDataStoreNode(const ModelNode &dataStoreNode)
{
using Utils::FilePath;
ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject();
if (!currentProject || !dataStoreNode.isValid())
if (!dataStoreNode.isValid())
return false;
const FilePath expectedFile = currentProject->projectDirectory().pathAppended(
"/imports/" + currentProject->displayName() + "/DataStore.qml");
const FilePath expectedFile = dataStoreQmlFilePath();
if (!expectedFile.exists())
return false;
FilePath modelPath = FilePath::fromUserInput(dataStoreNode.model()->fileUrl().toLocalFile());
@@ -183,4 +229,84 @@ QJsonArray defaultCollectionArray()
return initialCollection;
}
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;
}
templatePath.copyFile(filePath);
if (filePath.exists()) {
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;
}
} // namespace QmlDesigner::CollectionEditor

View File

@@ -10,6 +10,10 @@ QT_BEGIN_NAMESPACE
class QJsonArray;
QT_END_NAMESPACE
namespace Utils {
class FilePath;
}
namespace QmlDesigner::CollectionEditor {
bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails::DataType type);
@@ -25,8 +29,14 @@ void assignCollectionToNode(AbstractView *view,
const ModelNode &collectionSourceNode,
const QString &collectionName);
Utils::FilePath dataStoreJsonFilePath();
Utils::FilePath dataStoreQmlFilePath();
bool isDataStoreNode(const ModelNode &dataStoreNode);
bool ensureDataStoreExists(bool &justCreated);
bool canAcceptCollectionAsModel(const ModelNode &node);
QJsonArray defaultCollectionArray();

View File

@@ -211,6 +211,11 @@ void CollectionView::resetDataStoreNode()
refreshModel();
}
ModelNode CollectionView::dataStoreNode() const
{
return m_dataStore->modelNode();
}
void CollectionView::refreshModel()
{
if (!model())

View File

@@ -46,6 +46,7 @@ public:
static void registerDeclarativeType();
void resetDataStoreNode();
ModelNode dataStoreNode() const;
private:
void refreshModel();

View File

@@ -316,6 +316,7 @@ bool CollectionWidget::importCollectionToDataStore(const QString &collectionName
bool CollectionWidget::addCollectionToDataStore(const QString &collectionName)
{
ensureDataStoreExists();
const ModelNode node = dataStoreNode();
if (!node.isValid()) {
warn(tr("Can not import to the main model"), tr("The default model node is not available."));
@@ -349,14 +350,17 @@ void CollectionWidget::assignCollectionToSelectedNode(const QString collectionNa
CollectionEditor::assignCollectionToNode(m_view, targetNode, dsNode, collectionName);
}
void CollectionWidget::ensureDataStoreExists()
{
bool filesJustCreated = false;
bool filesExist = CollectionEditor::ensureDataStoreExists(filesJustCreated);
if (filesExist && filesJustCreated)
m_view->resetDataStoreNode();
}
ModelNode CollectionWidget::dataStoreNode() const
{
for (int i = 0; i < m_sourceModel->rowCount(); ++i) {
const ModelNode node = m_sourceModel->sourceNodeAt(i);
if (CollectionEditor::getSourceCollectionFormat(node) == CollectionEditor::SourceFormat::Json)
return node;
}
return {};
return m_view->dataStoreNode();
}
void CollectionWidget::warn(const QString &title, const QString &body)

View File

@@ -54,6 +54,8 @@ public:
Q_INVOKABLE void assignCollectionToSelectedNode(const QString collectionName);
Q_INVOKABLE void ensureDataStoreExists();
Q_INVOKABLE ModelNode dataStoreNode() const;
void warn(const QString &title, const QString &body);

View File

@@ -4,6 +4,7 @@
#include "datastoremodelnode.h"
#include "collectioneditorconstants.h"
#include "collectioneditorutils.h"
#include "model/qmltextgenerator.h"
#include <model.h>
@@ -23,21 +24,6 @@
namespace {
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 {};
}
QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node)
{
using QmlDesigner::AbstractProperty;
@@ -74,10 +60,8 @@ void DataStoreModelNode::reloadModel()
}
bool forceUpdate = false;
const FilePath projectFilePath = ProjectExplorer::ProjectManager::startupProject()->projectDirectory();
const FilePath importsPath = FilePath::fromString(projectFilePath.path() + "/imports");
FilePath dataStoreQmlPath = findFile(importsPath, "DataStore.qml");
FilePath dataStoreJsonPath = findFile(importsPath, "DataStore.json");
const FilePath dataStoreQmlPath = CollectionEditor::dataStoreQmlFilePath();
const FilePath dataStoreJsonPath = CollectionEditor::dataStoreJsonFilePath();
QUrl dataStoreQmlUrl = dataStoreQmlPath.toUrl();
if (dataStoreQmlPath.exists() && dataStoreJsonPath.exists()) {