QmlDesigner: Remove QmlJS usage from 3D related content

Removed unnecessary QmlJS usage from 3D importer, lights baking, and
bundle importer. Also simplified bundle importer significantly and
added usage of new addQuick3DImportAndView3D() function to 3D importer
instead of just adding QtQuick3D import.

Fixes: QDS-14922
Change-Id: I5c8a4073a146ebe3fbbc89705acffa16cb466ea6
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Miikka Heikkinen
2025-03-13 14:26:06 +02:00
parent c993e33613
commit 5dd4fcd1f4
7 changed files with 120 additions and 62 deletions

View File

@@ -12,7 +12,9 @@
#include <rewritingexception.h> #include <rewritingexception.h>
#include <modelutils.h> #include <modelutils.h>
#ifndef QDS_USE_PROJECTSTORAGE
#include <qmljs/qmljsmodelmanagerinterface.h> #include <qmljs/qmljsmodelmanagerinterface.h>
#endif
#include <utils/async.h> #include <utils/async.h>
#include <QJsonDocument> #include <QJsonDocument>
@@ -52,15 +54,19 @@ QString BundleImporter::importComponent(const QString &bundleDir,
if (!bundleImportPath.exists() && !bundleImportPath.createDir()) if (!bundleImportPath.exists() && !bundleImportPath.createDir())
return QStringLiteral("Failed to create bundle import folder: '%1'").arg(bundleImportPath.toUrlishString()); return QStringLiteral("Failed to create bundle import folder: '%1'").arg(bundleImportPath.toUrlishString());
#ifndef QDS_USE_PROJECTSTORAGE
bool doScan = false; bool doScan = false;
bool doReset = false; bool doReset = false;
#endif
FilePath qmldirPath = bundleImportPath.pathAppended("qmldir"); FilePath qmldirPath = bundleImportPath.pathAppended("qmldir");
QString qmldirContent = QString::fromUtf8(qmldirPath.fileContents().value_or(QByteArray())); QString qmldirContent = QString::fromUtf8(qmldirPath.fileContents().value_or(QByteArray()));
if (qmldirContent.isEmpty()) { if (qmldirContent.isEmpty()) {
qmldirContent.append("module "); qmldirContent.append("module ");
qmldirContent.append(module); qmldirContent.append(module);
qmldirContent.append('\n'); qmldirContent.append('\n');
#ifndef QDS_USE_PROJECTSTORAGE
doScan = true; doScan = true;
#endif
} }
FilePath qmlSourceFile = bundleImportPath.pathAppended(qmlFile); FilePath qmlSourceFile = bundleImportPath.pathAppended(qmlFile);
@@ -75,7 +81,9 @@ QString BundleImporter::importComponent(const QString &bundleDir,
qmldirContent.append(qmlFile); qmldirContent.append(qmlFile);
qmldirContent.append('\n'); qmldirContent.append('\n');
qmldirPath.writeFileContents(qmldirContent.toUtf8()); qmldirPath.writeFileContents(qmldirContent.toUtf8());
#ifndef QDS_USE_PROJECTSTORAGE
doReset = true; doReset = true;
#endif
} }
QStringList allFiles; QStringList allFiles;
@@ -118,15 +126,15 @@ QString BundleImporter::importComponent(const QString &bundleDir,
ImportData data; ImportData data;
data.isImport = true; data.isImport = true;
data.type = type; data.type = type;
Import import = Import::createLibraryImport(module, "1.0");
#ifdef QDS_USE_PROJECTSTORAGE
model->changeImports({import}, {});
#else
if (doScan) if (doScan)
data.pathToScan = bundleImportPath; data.pathToScan = bundleImportPath;
else else
data.fullReset = doReset; data.fullReset = doReset;
Import import = Import::createLibraryImport(module, "1.0");
#ifdef QDS_USE_PROJECTSTORAGE
model->changeImports({import}, {});
#else
if (!model->hasImport(import)) { if (!model->hasImport(import)) {
if (model->possibleImports().contains(import)) { if (model->possibleImports().contains(import)) {
try { try {
@@ -151,6 +159,51 @@ QString BundleImporter::importComponent(const QString &bundleDir,
void BundleImporter::handleImportTimer() void BundleImporter::handleImportTimer()
{ {
#ifdef QDS_USE_PROJECTSTORAGE
auto handleFailure = [this] {
m_importTimer.stop();
m_importTimerCount = 0;
// Emit dummy finished signals for all pending types
const QList<TypeName> pendingTypes = m_pendingImports.keys();
for (const TypeName &pendingType : pendingTypes) {
ImportData data = m_pendingImports.take(pendingType);
if (data.isImport)
emit importFinished({}, m_bundleId);
else
emit unimportFinished({}, m_bundleId);
}
m_bundleId.clear();
};
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
Model *model = doc ? doc->currentModel() : nullptr;
if (!model || ++m_importTimerCount > 100) {
handleFailure();
return;
}
const QList<TypeName> keys = m_pendingImports.keys();
for (const TypeName &type : keys) {
ImportData &data = m_pendingImports[type];
// Verify that code model has the new type fully available (or removed for unimport)
NodeMetaInfo metaInfo = model->metaInfo(type);
const bool typeComplete = metaInfo.isValid() && !metaInfo.prototypes().empty();
if (data.isImport == typeComplete) {
m_pendingImports.remove(type);
if (data.isImport)
emit importFinished(type, m_bundleId);
else
emit unimportFinished(metaInfo, m_bundleId);
}
}
if (m_pendingImports.isEmpty()) {
m_bundleId.clear();
m_importTimer.stop();
m_importTimerCount = 0;
}
#else
auto handleFailure = [this] { auto handleFailure = [this] {
m_importTimer.stop(); m_importTimer.stop();
m_importTimerCount = 0; m_importTimerCount = 0;
@@ -277,11 +330,7 @@ void BundleImporter::handleImportTimer()
if (data.isImport == typeComplete) { if (data.isImport == typeComplete) {
m_pendingImports.remove(type); m_pendingImports.remove(type);
if (data.isImport) if (data.isImport)
#ifdef QDS_USE_PROJECTSTORAGE
emit importFinished(type, m_bundleId);
#else
emit importFinished(metaInfo, m_bundleId); emit importFinished(metaInfo, m_bundleId);
#endif
else else
emit unimportFinished(metaInfo, m_bundleId); emit unimportFinished(metaInfo, m_bundleId);
} }
@@ -296,6 +345,7 @@ void BundleImporter::handleImportTimer()
m_importTimerCount = 0; m_importTimerCount = 0;
disconnect(m_libInfoConnection); disconnect(m_libInfoConnection);
} }
#endif
} }
QVariantHash BundleImporter::loadAssetRefMap(const FilePath &bundlePath) QVariantHash BundleImporter::loadAssetRefMap(const FilePath &bundlePath)
@@ -411,7 +461,9 @@ QString BundleImporter::unimportComponent(const TypeName &type, const QString &q
ImportData data; ImportData data;
data.isImport = false; data.isImport = false;
data.type = type; data.type = type;
#ifndef QDS_USE_PROJECTSTORAGE
data.fullReset = true; data.fullReset = true;
#endif
m_pendingImports.insert(type, data); m_pendingImports.insert(type, data);
m_importTimerCount = 0; m_importTimerCount = 0;

View File

@@ -7,7 +7,9 @@
#include <utils/filepath.h> #include <utils/filepath.h>
#ifndef QDS_USE_PROJECTSTORAGE
#include <QFuture> #include <QFuture>
#endif
#include <QTimer> #include <QTimer>
#include <QVariantHash> #include <QVariantHash>
@@ -48,6 +50,13 @@ private:
QTimer m_importTimer; QTimer m_importTimer;
int m_importTimerCount = 0; int m_importTimerCount = 0;
QString m_bundleId; QString m_bundleId;
#ifdef QDS_USE_PROJECTSTORAGE
struct ImportData
{
bool isImport = true; // false = unimport
TypeName type;
};
#else
struct ImportData struct ImportData
{ {
enum State { enum State {
@@ -66,8 +75,10 @@ private:
State state = Starting; State state = Starting;
}; };
QHash<TypeName, ImportData> m_pendingImports;
QMetaObject::Connection m_libInfoConnection; QMetaObject::Connection m_libInfoConnection;
#endif
QHash<TypeName, ImportData> m_pendingImports;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -369,18 +369,20 @@ ModelNode createMaterial(AbstractView *view, const NodeMetaInfo &metaInfo)
} }
#endif #endif
void addQuick3DImportAndView3D(AbstractView *view) bool addQuick3DImportAndView3D(AbstractView *view, bool suppressWarningDialog)
{ {
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
if (!view || !view->model() || !document || document->inFileComponentModelActive()) { if (!view || !view->model() || !document || document->inFileComponentModelActive()) {
if (!suppressWarningDialog) {
Core::AsynchronousMessageBox::warning(Tr::tr("Failed to Add Import"), Core::AsynchronousMessageBox::warning(Tr::tr("Failed to Add Import"),
Tr::tr("Could not add QtQuick3D import to the document.")); Tr::tr("Could not add QtQuick3D import to the document."));
return; }
return false;
} }
QString importName{"QtQuick3D"}; QString importName{"QtQuick3D"};
if (view->model()->hasImport(importName)) if (view->model()->hasImport(importName))
return; return true;
view->executeInTransaction(__FUNCTION__, [&] { view->executeInTransaction(__FUNCTION__, [&] {
Import import = Import::createLibraryImport(importName); Import import = Import::createLibraryImport(importName);
@@ -417,6 +419,7 @@ void addQuick3DImportAndView3D(AbstractView *view)
if (!models.isEmpty()) if (!models.isEmpty())
assignMaterialTo3dModel(view, models.at(0)); assignMaterialTo3dModel(view, models.at(0));
}); });
return true;
} }
// Assigns given material to a 3D model. // Assigns given material to a 3D model.

View File

@@ -60,7 +60,7 @@ ModelNode createMaterial(AbstractView *view);
void renameMaterial(const ModelNode &material, const QString &newName); void renameMaterial(const ModelNode &material, const QString &newName);
void duplicateMaterial(AbstractView *view, const ModelNode &material); void duplicateMaterial(AbstractView *view, const ModelNode &material);
void addQuick3DImportAndView3D(AbstractView *view); bool addQuick3DImportAndView3D(AbstractView *view, bool suppressWarningDialog = false);
void assignMaterialTo3dModel(AbstractView *view, const ModelNode &modelNode, void assignMaterialTo3dModel(AbstractView *view, const ModelNode &modelNode,
const ModelNode &materialNode = {}); const ModelNode &materialNode = {});

View File

@@ -22,7 +22,9 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <projectexplorer/projectmanager.h> #include <projectexplorer/projectmanager.h>
#ifndef QDS_USE_PROJECTSTORAGE
#include <qmljs/qmljsmodelmanagerinterface.h> #include <qmljs/qmljsmodelmanagerinterface.h>
#endif
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/environment.h> #include <utils/environment.h>
@@ -283,11 +285,12 @@ void BakeLights::exposeModelsAndLights(const QString &nodeId)
} }
} }
#ifndef QDS_USE_PROJECTSTORAGE
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
QmlJS::Document::Ptr doc = rewriter.document(); QmlJS::Document::Ptr doc = rewriter.document();
modelManager->updateDocument(doc); modelManager->updateDocument(doc);
m_view->model()->rewriterView()->forceAmend(); m_view->model()->rewriterView()->forceAmend();
#endif
compModel->setRewriterView({}); compModel->setRewriterView({});

View File

@@ -16,8 +16,11 @@
#include "viewmanager.h" #include "viewmanager.h"
#include <modelutils.h> #include <modelutils.h>
#include <utils3d.h>
#ifndef QDS_USE_PROJECTSTORAGE
#include <qmljs/qmljsmodelmanagerinterface.h> #include <qmljs/qmljsmodelmanagerinterface.h>
#endif
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/async.h> #include <utils/async.h>
@@ -241,7 +244,6 @@ void Import3dImporter::reset()
m_importFiles.clear(); m_importFiles.clear();
m_puppetProcess.reset(); m_puppetProcess.reset();
m_parseData.clear(); m_parseData.clear();
m_requiredImports.clear();
m_currentImportId = 0; m_currentImportId = 0;
m_puppetQueue.clear(); m_puppetQueue.clear();
m_importIdToAssetNameMap.clear(); m_importIdToAssetNameMap.clear();
@@ -449,12 +451,6 @@ void Import3dImporter::postParseQuick3DAsset(ParseData &pd)
} }
} }
} }
// Add quick3D import unless it is already added
if (impVersionMajor > 0 && (m_requiredImports.isEmpty()
|| m_requiredImports.first() != "QtQuick3D")) {
m_requiredImports.prepend("QtQuick3D");
}
} }
} }
} }
@@ -698,6 +694,11 @@ void Import3dImporter::finalizeQuick3DImport()
addInfo(progressTitle); addInfo(progressTitle);
notifyProgress(0, progressTitle); notifyProgress(0, progressTitle);
QTimer *timer = new QTimer(parent());
static int counter;
counter = 0;
#ifndef QDS_USE_PROJECTSTORAGE
auto modelManager = QmlJS::ModelManagerInterface::instance(); auto modelManager = QmlJS::ModelManagerInterface::instance();
QFuture<void> result; QFuture<void> result;
if (modelManager) { if (modelManager) {
@@ -711,49 +712,17 @@ void Import3dImporter::finalizeQuick3DImport()
true, true,
true); true);
} }
// First we have to wait a while to ensure qmljs detects new files and updates its // First we have to wait a while to ensure qmljs detects new files and updates its
// internal model. Then we force amend on rewriter to trigger qmljs snapshot update. // internal model. Then we force amend on rewriter to trigger qmljs snapshot update.
QTimer *timer = new QTimer(parent());
static int counter;
counter = 0;
timer->callOnTimeout([this, timer, progressTitle, model, result]() { timer->callOnTimeout([this, timer, progressTitle, model, result]() {
if (!isCancelled()) { if (!isCancelled()) {
notifyProgress(++counter * 2, progressTitle); notifyProgress(++counter * 2, progressTitle);
if (counter < 49) { if (counter == 1) {
if (!Utils3D::addQuick3DImportAndView3D(model->rewriterView(), true))
addError(tr("Failed to insert QtQuick3D import to the qml document."));
} else if (counter < 50) {
if (result.isCanceled() || result.isFinished()) if (result.isCanceled() || result.isFinished())
counter = 48; // skip to next step counter = 49; // skip to next step
} else if (counter == 49) {
#ifndef QDS_USE_PROJECTSTORAGE
QmlDesignerPlugin::instance()->documentManager().resetPossibleImports();
model->rewriterView()->forceAmend();
try {
RewriterTransaction transaction = model->rewriterView()->beginRewriterTransaction(
QByteArrayLiteral("Import3dImporter::finalizeQuick3DImport"));
bool success = ModelUtils::addImportsWithCheck(m_requiredImports, model);
if (!success)
addError(tr("Failed to insert import statement into qml document."));
transaction.commit();
#else
const Imports &imports = model->imports();
Imports importsToAdd;
for (const QString &importName : std::as_const(m_requiredImports)) {
auto hasName = [&](const auto &import) {
return import.url() == importName || import.file() == importName;
};
if (!Utils::anyOf(imports, hasName)) {
Import import = Import::createLibraryImport(importName);
importsToAdd.push_back(import);
}
}
try {
model->changeImports(std::move(importsToAdd), {});
#endif
} catch (const RewritingException &e) {
addError(tr("Failed to update imports: %1").arg(e.description()));
}
} else if (counter >= 50) { } else if (counter >= 50) {
for (const ParseData &pd : std::as_const(m_parseData)) { for (const ParseData &pd : std::as_const(m_parseData)) {
if (!pd.overwrittenImports.isEmpty()) { if (!pd.overwrittenImports.isEmpty()) {
@@ -766,6 +735,27 @@ void Import3dImporter::finalizeQuick3DImport()
notifyFinished(); notifyFinished();
model->rewriterView()->emitCustomNotification("asset_import_finished"); model->rewriterView()->emitCustomNotification("asset_import_finished");
} }
#else
counter = 0;
timer->callOnTimeout([this, timer, progressTitle, model]() {
if (!isCancelled()) {
notifyProgress(++counter * 50, progressTitle);
if (counter == 1) {
if (!Utils3D::addQuick3DImportAndView3D(model->rewriterView(), true))
addError(tr("Failed to insert QtQuick3D import to the qml document."));
} else if (counter > 1) {
for (const ParseData &pd : std::as_const(m_parseData)) {
if (!pd.overwrittenImports.isEmpty()) {
model->rewriterView()->resetPuppet();
model->rewriterView()->emitCustomNotification("asset_import_update");
break;
}
}
timer->stop();
notifyFinished();
model->rewriterView()->emitCustomNotification("asset_import_finished");
}
#endif
} else { } else {
timer->stop(); timer->stop();
} }

View File

@@ -126,7 +126,6 @@ private:
QHash<int, QString> m_importIdToAssetNameMap; QHash<int, QString> m_importIdToAssetNameMap;
QHash<QString, ParseData> m_parseData; // Key: asset name QHash<QString, ParseData> m_parseData; // Key: asset name
QString m_progressTitle; QString m_progressTitle;
QStringList m_requiredImports;
QList<int> m_puppetQueue; QList<int> m_puppetQueue;
}; };
} // QmlDesigner } // QmlDesigner