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 <modelutils.h>
#ifndef QDS_USE_PROJECTSTORAGE
#include <qmljs/qmljsmodelmanagerinterface.h>
#endif
#include <utils/async.h>
#include <QJsonDocument>
@@ -52,15 +54,19 @@ QString BundleImporter::importComponent(const QString &bundleDir,
if (!bundleImportPath.exists() && !bundleImportPath.createDir())
return QStringLiteral("Failed to create bundle import folder: '%1'").arg(bundleImportPath.toUrlishString());
#ifndef QDS_USE_PROJECTSTORAGE
bool doScan = false;
bool doReset = false;
#endif
FilePath qmldirPath = bundleImportPath.pathAppended("qmldir");
QString qmldirContent = QString::fromUtf8(qmldirPath.fileContents().value_or(QByteArray()));
if (qmldirContent.isEmpty()) {
qmldirContent.append("module ");
qmldirContent.append(module);
qmldirContent.append('\n');
#ifndef QDS_USE_PROJECTSTORAGE
doScan = true;
#endif
}
FilePath qmlSourceFile = bundleImportPath.pathAppended(qmlFile);
@@ -75,7 +81,9 @@ QString BundleImporter::importComponent(const QString &bundleDir,
qmldirContent.append(qmlFile);
qmldirContent.append('\n');
qmldirPath.writeFileContents(qmldirContent.toUtf8());
#ifndef QDS_USE_PROJECTSTORAGE
doReset = true;
#endif
}
QStringList allFiles;
@@ -118,15 +126,15 @@ QString BundleImporter::importComponent(const QString &bundleDir,
ImportData data;
data.isImport = true;
data.type = type;
Import import = Import::createLibraryImport(module, "1.0");
#ifdef QDS_USE_PROJECTSTORAGE
model->changeImports({import}, {});
#else
if (doScan)
data.pathToScan = bundleImportPath;
else
data.fullReset = doReset;
Import import = Import::createLibraryImport(module, "1.0");
#ifdef QDS_USE_PROJECTSTORAGE
model->changeImports({import}, {});
#else
if (!model->hasImport(import)) {
if (model->possibleImports().contains(import)) {
try {
@@ -151,6 +159,51 @@ QString BundleImporter::importComponent(const QString &bundleDir,
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] {
m_importTimer.stop();
m_importTimerCount = 0;
@@ -277,11 +330,7 @@ void BundleImporter::handleImportTimer()
if (data.isImport == typeComplete) {
m_pendingImports.remove(type);
if (data.isImport)
#ifdef QDS_USE_PROJECTSTORAGE
emit importFinished(type, m_bundleId);
#else
emit importFinished(metaInfo, m_bundleId);
#endif
else
emit unimportFinished(metaInfo, m_bundleId);
}
@@ -296,6 +345,7 @@ void BundleImporter::handleImportTimer()
m_importTimerCount = 0;
disconnect(m_libInfoConnection);
}
#endif
}
QVariantHash BundleImporter::loadAssetRefMap(const FilePath &bundlePath)
@@ -411,7 +461,9 @@ QString BundleImporter::unimportComponent(const TypeName &type, const QString &q
ImportData data;
data.isImport = false;
data.type = type;
#ifndef QDS_USE_PROJECTSTORAGE
data.fullReset = true;
#endif
m_pendingImports.insert(type, data);
m_importTimerCount = 0;

View File

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

View File

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

View File

@@ -22,7 +22,9 @@
#include <coreplugin/icore.h>
#include <projectexplorer/projectmanager.h>
#ifndef QDS_USE_PROJECTSTORAGE
#include <qmljs/qmljsmodelmanagerinterface.h>
#endif
#include <utils/algorithm.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::Document::Ptr doc = rewriter.document();
modelManager->updateDocument(doc);
m_view->model()->rewriterView()->forceAmend();
#endif
compModel->setRewriterView({});

View File

@@ -16,8 +16,11 @@
#include "viewmanager.h"
#include <modelutils.h>
#include <utils3d.h>
#ifndef QDS_USE_PROJECTSTORAGE
#include <qmljs/qmljsmodelmanagerinterface.h>
#endif
#include <utils/algorithm.h>
#include <utils/async.h>
@@ -241,7 +244,6 @@ void Import3dImporter::reset()
m_importFiles.clear();
m_puppetProcess.reset();
m_parseData.clear();
m_requiredImports.clear();
m_currentImportId = 0;
m_puppetQueue.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);
notifyProgress(0, progressTitle);
QTimer *timer = new QTimer(parent());
static int counter;
counter = 0;
#ifndef QDS_USE_PROJECTSTORAGE
auto modelManager = QmlJS::ModelManagerInterface::instance();
QFuture<void> result;
if (modelManager) {
@@ -711,49 +712,17 @@ void Import3dImporter::finalizeQuick3DImport()
true,
true);
}
// 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.
QTimer *timer = new QTimer(parent());
static int counter;
counter = 0;
timer->callOnTimeout([this, timer, progressTitle, model, result]() {
if (!isCancelled()) {
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())
counter = 48; // 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()));
}
counter = 49; // skip to next step
} else if (counter >= 50) {
for (const ParseData &pd : std::as_const(m_parseData)) {
if (!pd.overwrittenImports.isEmpty()) {
@@ -766,6 +735,27 @@ void Import3dImporter::finalizeQuick3DImport()
notifyFinished();
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 {
timer->stop();
}

View File

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