QmlDesigner: Delay rebaking until exposed properties are seen

It takes a moment for the code model to realize there are new exposed
properties available, so add a timer to check.

Fixes: QDS-15058
Change-Id: Iab2649f2f17100cdac5814122593b48f09c23eb1
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Miikka Heikkinen
2025-04-07 15:47:50 +03:00
parent a5da69fc3c
commit 826ecdde6d
4 changed files with 64 additions and 4 deletions

View File

@@ -38,7 +38,6 @@
#include <QSaveFile> #include <QSaveFile>
#include <QTextCursor> #include <QTextCursor>
#include <QTextDocument> #include <QTextDocument>
#include <QTimer>
#include <QVariant> #include <QVariant>
namespace QmlDesigner { namespace QmlDesigner {
@@ -74,6 +73,9 @@ BakeLights::BakeLights(AbstractView *view)
return; return;
} }
m_pendingRebakeTimer.setInterval(100);
connect(&m_pendingRebakeTimer, &QTimer::timeout, this, &BakeLights::handlePendingRebakeTimeout);
showSetupDialog(); showSetupDialog();
} }
@@ -215,7 +217,8 @@ void BakeLights::rebake()
void BakeLights::exposeModelsAndLights(const QString &nodeId) void BakeLights::exposeModelsAndLights(const QString &nodeId)
{ {
ModelNode compNode = m_view->modelNodeForId(nodeId); ModelNode compNode = m_view->modelNodeForId(nodeId);
if (!compNode.isValid() || !compNode.isComponent()) { if (!compNode.isValid() || !compNode.isComponent()
|| (m_pendingRebakeTimer.isActive() && compNode == m_pendingRebakeCheckNode)) {
return; return;
} }
@@ -294,8 +297,9 @@ void BakeLights::exposeModelsAndLights(const QString &nodeId)
compModel->setRewriterView({}); compModel->setRewriterView({});
// Rebake to relaunch setup dialog with updated properties m_pendingRebakeTimerCount = 0;
rebake(); m_pendingRebakeCheckNode = compNode;
m_pendingRebakeTimer.start();
} }
void BakeLights::showSetupDialog() void BakeLights::showSetupDialog()
@@ -376,6 +380,8 @@ void BakeLights::cleanup()
m_model.reset(); m_model.reset();
} }
pendingRebakeCleanup();
delete m_setupDialog; delete m_setupDialog;
delete m_progressDialog; delete m_progressDialog;
delete m_rewriterView; delete m_rewriterView;
@@ -386,6 +392,43 @@ void BakeLights::cleanup()
m_manualMode = false; m_manualMode = false;
} }
void BakeLights::handlePendingRebakeTimeout()
{
QScopeGuard timerCleanup([this]() {
pendingRebakeCleanup();
});
if (m_view.isNull() || !m_pendingRebakeCheckNode || !m_pendingRebakeCheckNode.isComponent())
return;
const Model *model = m_pendingRebakeCheckNode.model();
if (!model)
return;
const QList<AbstractProperty> props = m_pendingRebakeCheckNode.properties();
PropertyMetaInfos metaInfos = m_pendingRebakeCheckNode.metaInfo().properties();
for (const PropertyMetaInfo &mi : metaInfos) {
if (mi.isValid() && !mi.isPrivate() && mi.isWritable()) {
if (mi.propertyType().isBasedOn(model->qtQuick3DModelMetaInfo(),
model->qtQuick3DLightMetaInfo())) {
// Rebake to relaunch setup dialog with updated properties
rebake();
return;
}
}
}
if (++m_pendingRebakeTimerCount < 100)
timerCleanup.dismiss();
}
void BakeLights::pendingRebakeCleanup()
{
m_pendingRebakeTimer.stop();
m_pendingRebakeTimerCount = 0;
m_pendingRebakeCheckNode = {};
}
void BakeLights::cancel() void BakeLights::cancel()
{ {
if (!m_setupDialog.isNull() && m_setupDialog->isVisible()) if (!m_setupDialog.isNull() && m_setupDialog->isVisible())

View File

@@ -7,6 +7,7 @@
#include <QObject> #include <QObject>
#include <QPointer> #include <QPointer>
#include <QTimer>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QQuickView; class QQuickView;
@@ -53,6 +54,8 @@ private:
void showSetupDialog(); void showSetupDialog();
void showProgressDialog(); void showProgressDialog();
void cleanup(); void cleanup();
void handlePendingRebakeTimeout();
void pendingRebakeCleanup();
// Separate dialogs for setup and progress, as setup needs to be modal // Separate dialogs for setup and progress, as setup needs to be modal
QPointer<QQuickView> m_setupDialog; QPointer<QQuickView> m_setupDialog;
@@ -66,6 +69,9 @@ private:
ModelPointer m_model; ModelPointer m_model;
QString m_view3dId; QString m_view3dId;
bool m_manualMode = false; bool m_manualMode = false;
QTimer m_pendingRebakeTimer;
ModelNode m_pendingRebakeCheckNode;
int m_pendingRebakeTimerCount = 0;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -172,6 +172,7 @@ public:
NodeMetaInfo qtQuick3DBakedLightmapMetaInfo() const; NodeMetaInfo qtQuick3DBakedLightmapMetaInfo() const;
NodeMetaInfo qtQuick3DDefaultMaterialMetaInfo() const; NodeMetaInfo qtQuick3DDefaultMaterialMetaInfo() const;
NodeMetaInfo qtQuick3DDirectionalLightMetaInfo() const; NodeMetaInfo qtQuick3DDirectionalLightMetaInfo() const;
NodeMetaInfo qtQuick3DLightMetaInfo() const;
NodeMetaInfo qtQuick3DMaterialMetaInfo() const; NodeMetaInfo qtQuick3DMaterialMetaInfo() const;
NodeMetaInfo qtQuick3DModelMetaInfo() const; NodeMetaInfo qtQuick3DModelMetaInfo() const;
NodeMetaInfo qtQuick3DNodeMetaInfo() const; NodeMetaInfo qtQuick3DNodeMetaInfo() const;

View File

@@ -2724,6 +2724,16 @@ NodeMetaInfo Model::qtQuick3DDefaultMaterialMetaInfo() const
} }
} }
NodeMetaInfo Model::qtQuick3DLightMetaInfo() const
{
if constexpr (useProjectStorage()) {
using namespace Storage::Info;
return createNodeMetaInfo<QtQuick3D, Light>();
} else {
return metaInfo("QtQuick3D.Light");
}
}
NodeMetaInfo Model::qtQuick3DDirectionalLightMetaInfo() const NodeMetaInfo Model::qtQuick3DDirectionalLightMetaInfo() const
{ {
if constexpr (useProjectStorage()) { if constexpr (useProjectStorage()) {