EffectMaker: Update changed effect to 2D/property views

The effect directory will be rescanned to update the types,
and the puppet is reset if updated types are in use in the
current document. If updated effect was also selected,
selection is refreshed to update property view.

Fixes: QDS-11367
Change-Id: I79cf476d8a70295f79525b6e1a5eeda27bb0b637
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
This commit is contained in:
Miikka Heikkinen
2023-12-08 12:04:12 +02:00
parent 19a81c13df
commit 4ab995da59
4 changed files with 103 additions and 1 deletions

View File

@@ -720,6 +720,8 @@ void EffectMakerModel::exportResources(const QString &name)
if (!source.copyFile(target))
qWarning() << __FUNCTION__ << " Failed to copy file: " << source;
}
emit resourcesExported(QString("Effects.%1.%1").arg(name).toUtf8(), effectPath);
}
void EffectMakerModel::resetEffectError(int type)

View File

@@ -100,6 +100,7 @@ signals:
void currentCompositionChanged();
void nodesChanged();
void resourcesExported(const QByteArray &type, const Utils::FilePath &path);
private:
enum Roles {

View File

@@ -17,16 +17,21 @@
#include <coreplugin/icore.h>
#include <qmldesigner/documentmanager.h>
#include <qmldesigner/qmldesignerconstants.h>
#include <qmldesigner/qmldesignerplugin.h>
#include <studioquickwidget.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <utils/algorithm.h>
#include <utils/async.h>
#include <utils/environment.h>
#include <utils/qtcassert.h>
#include <QHBoxLayout>
#include <QQmlEngine>
#include <QTimer>
namespace EffectMaker {
@@ -77,9 +82,27 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view)
QmlDesigner::QmlDesignerPlugin::trackWidgetFocusTime(
this, QmlDesigner::Constants::EVENT_NEWEFFECTMAKER_TIME);
connect(m_effectMakerModel.data(), &EffectMakerModel::nodesChanged, [this]() {
connect(m_effectMakerModel.data(), &EffectMakerModel::nodesChanged, this, [this]() {
m_effectMakerNodesModel->updateCanBeAdded(m_effectMakerModel->uniformNames());
});
connect(m_effectMakerModel.data(), &EffectMakerModel::resourcesExported,
this, [this](const QmlDesigner::TypeName &type, const Utils::FilePath &path) {
if (!m_importScan.timer) {
m_importScan.timer = new QTimer(this);
connect(m_importScan.timer, &QTimer::timeout,
this, &EffectMakerWidget::handleImportScanTimer);
}
if (m_importScan.timer->isActive() && !m_importScan.future.isFinished())
m_importScan.future.cancel();
m_importScan.counter = 0;
m_importScan.type = type;
m_importScan.path = path;
m_importScan.timer->start(100);
});
}
@@ -177,5 +200,65 @@ void EffectMakerWidget::reloadQmlSource()
m_quickWidget->setSource(QUrl::fromLocalFile(effectMakerQmlPath));
}
void EffectMakerWidget::handleImportScanTimer()
{
++m_importScan.counter;
if (m_importScan.counter == 1) {
// Rescan the effect import to update code model
auto modelManager = QmlJS::ModelManagerInterface::instance();
if (modelManager) {
QmlJS::PathsAndLanguages pathToScan;
pathToScan.maybeInsert(m_importScan.path);
m_importScan.future = ::Utils::asyncRun(&QmlJS::ModelManagerInterface::importScan,
modelManager->workingCopy(),
pathToScan, modelManager, true, true, true);
}
} else if (m_importScan.counter < 100) {
// 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.
if (m_importScan.future.isCanceled() || m_importScan.future.isFinished())
m_importScan.counter = 100; // skip the timeout step
} else if (m_importScan.counter == 100) {
// Scanning is taking too long, abort
m_importScan.future.cancel();
m_importScan.timer->stop();
m_importScan.counter = 0;
} else if (m_importScan.counter == 101) {
if (m_effectMakerView->model() && m_effectMakerView->model()->rewriterView()) {
QmlDesigner::QmlDesignerPlugin::instance()->documentManager().resetPossibleImports();
m_effectMakerView->model()->rewriterView()->forceAmend();
}
} else if (m_importScan.counter == 102) {
if (m_effectMakerView->model()) {
// If type is in use, we have to reset puppet to update 2D view
if (!m_effectMakerView->allModelNodesOfType(
m_effectMakerView->model()->metaInfo(m_importScan.type)).isEmpty()) {
m_effectMakerView->resetPuppet();
}
}
} else if (m_importScan.counter >= 103) {
// Refresh property view by resetting selection if any selected node is of updated type
if (m_effectMakerView->model() && m_effectMakerView->hasSelectedModelNodes()) {
const auto nodes = m_effectMakerView->selectedModelNodes();
QmlDesigner::MetaInfoType metaType
= m_effectMakerView->model()->metaInfo(m_importScan.type).type();
bool match = false;
for (const QmlDesigner::ModelNode &node : nodes) {
if (node.metaInfo().type() == metaType) {
match = true;
break;
}
}
if (match) {
m_effectMakerView->clearSelectedModelNodes();
m_effectMakerView->setSelectedModelNodes(nodes);
}
}
m_importScan.timer->stop();
m_importScan.counter = 0;
}
}
} // namespace EffectMaker

View File

@@ -9,9 +9,14 @@
#include <coreplugin/icontext.h>
#include <QFrame>
#include <QFuture>
class StudioQuickWidget;
QT_BEGIN_NAMESPACE
class QTimer;
QT_END_NAMESPACE
namespace EffectMaker {
class EffectMakerView;
@@ -51,6 +56,7 @@ protected:
private:
void reloadQmlSource();
void handleImportScanTimer();
QPointer<EffectMakerModel> m_effectMakerModel;
QPointer<EffectMakerNodesModel> m_effectMakerNodesModel;
@@ -58,6 +64,16 @@ private:
QPointer<StudioQuickWidget> m_quickWidget;
QmlDesigner::QmlModelNodeProxy m_backendModelNode;
QmlDesigner::QmlAnchorBindingProxy m_backendAnchorBinding;
struct ImportScanData {
QFuture<void> future;
int counter = 0;
QTimer *timer = nullptr;
QmlDesigner::TypeName type;
Utils::FilePath path;
};
ImportScanData m_importScan;
};
} // namespace EffectMaker