forked from qt-creator/qt-creator
QmlDesigner: Queue puppet processes during import
On some systems launcing multiple simultaneous import processes causes imports to fail. Fixed by only launching single process at a time and queuing the rest. Fixes: QDS-7107 Change-Id: I330c5920dcbd74d3b4f2e7f40899795a4fbaf3ac Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -198,8 +198,7 @@ void IconRenderer::finishCreateIcon()
|
|||||||
|
|
||||||
render(saveFile);
|
render(saveFile);
|
||||||
|
|
||||||
// Allow little time for file operations to finish
|
QTimer::singleShot(0, qGuiApp, &QGuiApplication::quit);
|
||||||
QTimer::singleShot(1000, qGuiApp, &QGuiApplication::quit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IconRenderer::render(const QString &fileName)
|
void IconRenderer::render(const QString &fileName)
|
||||||
|
@@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@@ -90,21 +91,16 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
|
|||||||
|
|
||||||
if (!isCancelled()) {
|
if (!isCancelled()) {
|
||||||
const auto parseData = m_parseData;
|
const auto parseData = m_parseData;
|
||||||
for (const auto &pd : parseData) {
|
for (const auto &pd : parseData)
|
||||||
if (!startImportProcess(pd)) {
|
m_puppetQueue.append(pd.importId);
|
||||||
addError(tr("Failed to start import 3D asset process."),
|
startNextImportProcess();
|
||||||
pd.sourceInfo.absoluteFilePath());
|
|
||||||
m_parseData.remove(pd.importId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isCancelled()) {
|
if (!isCancelled()) {
|
||||||
// Wait for puppet processes to finish
|
// Wait for puppet processes to finish
|
||||||
if (m_qmlPuppetProcesses.empty()) {
|
if (m_puppetQueue.isEmpty() && !m_puppetProcess) {
|
||||||
postImport();
|
postImport();
|
||||||
} else {
|
} else {
|
||||||
m_qmlPuppetCount = static_cast<int>(m_qmlPuppetProcesses.size());
|
|
||||||
const QString progressTitle = tr("Importing 3D assets.");
|
const QString progressTitle = tr("Importing 3D assets.");
|
||||||
addInfo(progressTitle);
|
addInfo(progressTitle);
|
||||||
notifyProgress(0, progressTitle);
|
notifyProgress(0, progressTitle);
|
||||||
@@ -142,21 +138,14 @@ void ItemLibraryAssetImporter::addInfo(const QString &infoMsg, const QString &sr
|
|||||||
emit infoReported(infoMsg, srcPath);
|
emit infoReported(infoMsg, srcPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus,
|
void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||||
int importId)
|
|
||||||
{
|
{
|
||||||
Q_UNUSED(exitCode)
|
Q_UNUSED(exitCode)
|
||||||
|
|
||||||
++m_qmlImportFinishedCount;
|
m_puppetProcess.reset();
|
||||||
|
|
||||||
m_qmlPuppetProcesses.erase(
|
if (m_parseData.contains(m_currentImportId)) {
|
||||||
std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(),
|
const ParseData &pd = m_parseData[m_currentImportId];
|
||||||
[&](const auto &entry) {
|
|
||||||
return !entry || entry->state() == QProcess::NotRunning;
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (m_parseData.contains(importId)) {
|
|
||||||
const ParseData &pd = m_parseData[importId];
|
|
||||||
QString errStr;
|
QString errStr;
|
||||||
if (exitStatus == QProcess::ExitStatus::CrashExit) {
|
if (exitStatus == QProcess::ExitStatus::CrashExit) {
|
||||||
errStr = tr("Import process crashed.");
|
errStr = tr("Import process crashed.");
|
||||||
@@ -179,15 +168,19 @@ void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::Exi
|
|||||||
addError(tr("Asset import process failed: \"%1\".")
|
addError(tr("Asset import process failed: \"%1\".")
|
||||||
.arg(pd.sourceInfo.absoluteFilePath()));
|
.arg(pd.sourceInfo.absoluteFilePath()));
|
||||||
addError(errStr);
|
addError(errStr);
|
||||||
m_parseData.remove(importId);
|
m_parseData.remove(m_currentImportId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_qmlImportFinishedCount == m_qmlPuppetCount) {
|
int finishedCount = m_parseData.size() - m_puppetQueue.size();
|
||||||
|
if (!m_puppetQueue.isEmpty())
|
||||||
|
startNextImportProcess();
|
||||||
|
|
||||||
|
if (m_puppetQueue.isEmpty() && !m_puppetProcess) {
|
||||||
notifyProgress(100);
|
notifyProgress(100);
|
||||||
QTimer::singleShot(0, this, &ItemLibraryAssetImporter::postImport);
|
QTimer::singleShot(0, this, &ItemLibraryAssetImporter::postImport);
|
||||||
} else {
|
} else {
|
||||||
notifyProgress(int(100. * (double(m_qmlImportFinishedCount) / double(m_qmlPuppetCount))));
|
notifyProgress(int(100. * (double(finishedCount) / double(m_parseData.size()))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,17 +189,17 @@ void ItemLibraryAssetImporter::iconProcessFinished(int exitCode, QProcess::ExitS
|
|||||||
Q_UNUSED(exitCode)
|
Q_UNUSED(exitCode)
|
||||||
Q_UNUSED(exitStatus)
|
Q_UNUSED(exitStatus)
|
||||||
|
|
||||||
m_qmlPuppetProcesses.erase(
|
m_puppetProcess.reset();
|
||||||
std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(),
|
|
||||||
[&](const auto &entry) {
|
|
||||||
return !entry || entry->state() == QProcess::NotRunning;
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (m_qmlPuppetProcesses.empty()) {
|
int finishedCount = m_parseData.size() - m_puppetQueue.size();
|
||||||
|
if (!m_puppetQueue.isEmpty())
|
||||||
|
startNextIconProcess();
|
||||||
|
|
||||||
|
if (m_puppetQueue.isEmpty() && !m_puppetProcess) {
|
||||||
notifyProgress(100);
|
notifyProgress(100);
|
||||||
QTimer::singleShot(0, this, &ItemLibraryAssetImporter::finalizeQuick3DImport);
|
QTimer::singleShot(0, this, &ItemLibraryAssetImporter::finalizeQuick3DImport);
|
||||||
} else {
|
} else {
|
||||||
notifyProgress(int(100. * (1. - (double(m_qmlPuppetProcesses.size()) / double(m_qmlPuppetCount)))));
|
notifyProgress(int(100. * (double(finishedCount) / double(m_parseData.size()))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,11 +218,11 @@ void ItemLibraryAssetImporter::reset()
|
|||||||
m_tempDir = new QTemporaryDir;
|
m_tempDir = new QTemporaryDir;
|
||||||
m_importFiles.clear();
|
m_importFiles.clear();
|
||||||
m_overwrittenImports.clear();
|
m_overwrittenImports.clear();
|
||||||
m_qmlPuppetProcesses.clear();
|
m_puppetProcess.reset();
|
||||||
m_qmlPuppetCount = 0;
|
|
||||||
m_qmlImportFinishedCount = 0;
|
|
||||||
m_parseData.clear();
|
m_parseData.clear();
|
||||||
m_requiredImports.clear();
|
m_requiredImports.clear();
|
||||||
|
m_currentImportId = 0;
|
||||||
|
m_puppetQueue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths,
|
void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths,
|
||||||
@@ -351,7 +344,7 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd)
|
void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd)
|
||||||
{
|
{
|
||||||
QDir outDir = pd.outDir;
|
QDir outDir = pd.outDir;
|
||||||
if (pd.originalAssetName != pd.assetName) {
|
if (pd.originalAssetName != pd.assetName) {
|
||||||
@@ -452,8 +445,10 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd)
|
|||||||
"QtQuick3D", impVersionStr));
|
"QtQuick3D", impVersionStr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (impVersionMajor > 0 && impVersionMajor < 6
|
if (impVersionMajor > 0 && impVersionMajor < 6) {
|
||||||
&& startIconProcess(24, iconFileName, qmlIt.filePath())) {
|
pd.iconFile = iconFileName;
|
||||||
|
pd.iconSource = qmlIt.filePath();
|
||||||
|
m_puppetQueue.append(pd.importId);
|
||||||
// Since icon is generated by external process, the file won't be
|
// Since icon is generated by external process, the file won't be
|
||||||
// ready for asset gathering below, so assume its generation succeeds
|
// ready for asset gathering below, so assume its generation succeeds
|
||||||
// and add it now.
|
// and add it now.
|
||||||
@@ -589,84 +584,101 @@ ItemLibraryAssetImporter::OverwriteResult ItemLibraryAssetImporter::confirmAsset
|
|||||||
return OverwriteResult::Skip;
|
return OverwriteResult::Skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ItemLibraryAssetImporter::startImportProcess(const ParseData &pd)
|
void ItemLibraryAssetImporter::startNextImportProcess()
|
||||||
{
|
{
|
||||||
|
if (m_puppetQueue.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||||
Model *model = doc ? doc->currentModel() : nullptr;
|
Model *model = doc ? doc->currentModel() : nullptr;
|
||||||
|
|
||||||
if (model) {
|
if (model) {
|
||||||
PuppetCreator puppetCreator(doc->currentTarget(), model);
|
PuppetCreator puppetCreator(doc->currentTarget(), model);
|
||||||
puppetCreator.createQml2PuppetExecutableIfMissing();
|
puppetCreator.createQml2PuppetExecutableIfMissing();
|
||||||
QStringList puppetArgs;
|
|
||||||
QJsonDocument optDoc(pd.options);
|
|
||||||
|
|
||||||
puppetArgs << "--import3dAsset" << pd.sourceInfo.absoluteFilePath()
|
bool done = false;
|
||||||
<< pd.outDir.absolutePath() << QString::fromUtf8(optDoc.toJson());
|
while (!m_puppetQueue.isEmpty() && !done) {
|
||||||
|
const ParseData pd = m_parseData.value(m_puppetQueue.takeLast());
|
||||||
|
QStringList puppetArgs;
|
||||||
|
QJsonDocument optDoc(pd.options);
|
||||||
|
|
||||||
QProcessUniquePointer process = puppetCreator.createPuppetProcess(
|
puppetArgs << "--import3dAsset" << pd.sourceInfo.absoluteFilePath()
|
||||||
"custom",
|
<< pd.outDir.absolutePath() << QString::fromUtf8(optDoc.toJson());
|
||||||
{},
|
|
||||||
[&] {},
|
|
||||||
[&](int exitCode, QProcess::ExitStatus exitStatus) {
|
|
||||||
importProcessFinished(exitCode, exitStatus, pd.importId);
|
|
||||||
},
|
|
||||||
puppetArgs);
|
|
||||||
|
|
||||||
if (process->waitForStarted(5000)) {
|
m_currentImportId = pd.importId;
|
||||||
m_qmlPuppetProcesses.push_back(std::move(process));
|
m_puppetProcess = puppetCreator.createPuppetProcess(
|
||||||
return true;
|
"custom",
|
||||||
} else {
|
{},
|
||||||
process.reset();
|
[&] {},
|
||||||
|
[&](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||||
|
importProcessFinished(exitCode, exitStatus);
|
||||||
|
},
|
||||||
|
puppetArgs);
|
||||||
|
|
||||||
|
if (m_puppetProcess->waitForStarted(10000)) {
|
||||||
|
done = true;
|
||||||
|
} else {
|
||||||
|
addError(tr("Failed to start import 3D asset process."),
|
||||||
|
pd.sourceInfo.absoluteFilePath());
|
||||||
|
m_parseData.remove(pd.importId);
|
||||||
|
m_puppetProcess.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ItemLibraryAssetImporter::startIconProcess(int size, const QString &iconFile,
|
void ItemLibraryAssetImporter::startNextIconProcess()
|
||||||
const QString &iconSource)
|
|
||||||
{
|
{
|
||||||
|
if (m_puppetQueue.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||||
Model *model = doc ? doc->currentModel() : nullptr;
|
Model *model = doc ? doc->currentModel() : nullptr;
|
||||||
|
|
||||||
if (model) {
|
if (model) {
|
||||||
PuppetCreator puppetCreator(doc->currentTarget(), model);
|
PuppetCreator puppetCreator(doc->currentTarget(), model);
|
||||||
puppetCreator.createQml2PuppetExecutableIfMissing();
|
puppetCreator.createQml2PuppetExecutableIfMissing();
|
||||||
QStringList puppetArgs;
|
|
||||||
puppetArgs << "--rendericon" << QString::number(size) << iconFile << iconSource;
|
|
||||||
QProcessUniquePointer process = puppetCreator.createPuppetProcess(
|
|
||||||
"custom",
|
|
||||||
{},
|
|
||||||
[&] {},
|
|
||||||
[&](int exitCode, QProcess::ExitStatus exitStatus) {
|
|
||||||
iconProcessFinished(exitCode, exitStatus);
|
|
||||||
},
|
|
||||||
puppetArgs);
|
|
||||||
|
|
||||||
if (process->waitForStarted(5000)) {
|
bool done = false;
|
||||||
m_qmlPuppetProcesses.push_back(std::move(process));
|
while (!m_puppetQueue.isEmpty() && !done) {
|
||||||
return true;
|
const ParseData pd = m_parseData.value(m_puppetQueue.takeLast());
|
||||||
} else {
|
QStringList puppetArgs;
|
||||||
process.reset();
|
puppetArgs << "--rendericon" << QString::number(24) << pd.iconFile << pd.iconSource;
|
||||||
|
m_puppetProcess = puppetCreator.createPuppetProcess(
|
||||||
|
"custom",
|
||||||
|
{},
|
||||||
|
[&] {},
|
||||||
|
[&](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||||
|
iconProcessFinished(exitCode, exitStatus);
|
||||||
|
},
|
||||||
|
puppetArgs);
|
||||||
|
|
||||||
|
if (m_puppetProcess->waitForStarted(10000)) {
|
||||||
|
done = true;
|
||||||
|
} else {
|
||||||
|
addError(tr("Failed to start icon generation process."),
|
||||||
|
pd.sourceInfo.absoluteFilePath());
|
||||||
|
m_puppetProcess.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemLibraryAssetImporter::postImport()
|
void ItemLibraryAssetImporter::postImport()
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_qmlPuppetProcesses.empty());
|
QTC_ASSERT(m_puppetQueue.isEmpty() && !m_puppetProcess, return);
|
||||||
|
|
||||||
if (!isCancelled()) {
|
if (!isCancelled()) {
|
||||||
for (const auto &pd : qAsConst(m_parseData))
|
for (auto &pd : m_parseData)
|
||||||
postParseQuick3DAsset(pd);
|
postParseQuick3DAsset(pd);
|
||||||
|
startNextIconProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isCancelled()) {
|
if (!isCancelled()) {
|
||||||
// Wait for icon generation processes to finish
|
// Wait for icon generation processes to finish
|
||||||
if (m_qmlPuppetProcesses.empty()) {
|
if (m_puppetQueue.isEmpty() && !m_puppetProcess) {
|
||||||
finalizeQuick3DImport();
|
finalizeQuick3DImport();
|
||||||
} else {
|
} else {
|
||||||
m_qmlPuppetCount = static_cast<int>(m_qmlPuppetProcesses.size());
|
|
||||||
const QString progressTitle = tr("Generating icons.");
|
const QString progressTitle = tr("Generating icons.");
|
||||||
addInfo(progressTitle);
|
addInfo(progressTitle);
|
||||||
notifyProgress(0, progressTitle);
|
notifyProgress(0, progressTitle);
|
||||||
|
@@ -74,7 +74,7 @@ signals:
|
|||||||
void importFinished();
|
void importFinished();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus, int importId);
|
void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
void iconProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
void iconProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -87,6 +87,8 @@ private:
|
|||||||
QString assetName;
|
QString assetName;
|
||||||
QString originalAssetName;
|
QString originalAssetName;
|
||||||
int importId;
|
int importId;
|
||||||
|
QString iconFile;
|
||||||
|
QString iconSource;
|
||||||
};
|
};
|
||||||
|
|
||||||
void notifyFinished();
|
void notifyFinished();
|
||||||
@@ -96,7 +98,7 @@ private:
|
|||||||
const QSet<QString> &preselectedFilesForOverwrite);
|
const QSet<QString> &preselectedFilesForOverwrite);
|
||||||
bool preParseQuick3DAsset(const QString &file, ParseData &pd,
|
bool preParseQuick3DAsset(const QString &file, ParseData &pd,
|
||||||
const QSet<QString> &preselectedFilesForOverwrite);
|
const QSet<QString> &preselectedFilesForOverwrite);
|
||||||
void postParseQuick3DAsset(const ParseData &pd);
|
void postParseQuick3DAsset(ParseData &pd);
|
||||||
void copyImportedFiles();
|
void copyImportedFiles();
|
||||||
|
|
||||||
void notifyProgress(int value, const QString &text);
|
void notifyProgress(int value, const QString &text);
|
||||||
@@ -110,8 +112,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
OverwriteResult confirmAssetOverwrite(const QString &assetName);
|
OverwriteResult confirmAssetOverwrite(const QString &assetName);
|
||||||
bool startImportProcess(const ParseData &pd);
|
void startNextImportProcess();
|
||||||
bool startIconProcess(int size, const QString &iconFile, const QString &iconSource);
|
void startNextIconProcess();
|
||||||
void postImport();
|
void postImport();
|
||||||
void finalizeQuick3DImport();
|
void finalizeQuick3DImport();
|
||||||
QString sourceSceneTargetFilePath(const ParseData &pd);
|
QString sourceSceneTargetFilePath(const ParseData &pd);
|
||||||
@@ -122,12 +124,12 @@ private:
|
|||||||
bool m_cancelled = false;
|
bool m_cancelled = false;
|
||||||
QString m_importPath;
|
QString m_importPath;
|
||||||
QTemporaryDir *m_tempDir = nullptr;
|
QTemporaryDir *m_tempDir = nullptr;
|
||||||
std::vector<QProcessUniquePointer> m_qmlPuppetProcesses;
|
QProcessUniquePointer m_puppetProcess;
|
||||||
int m_qmlPuppetCount = 0;
|
|
||||||
int m_qmlImportFinishedCount = 0;
|
|
||||||
int m_importIdCounter = 0;
|
int m_importIdCounter = 0;
|
||||||
|
int m_currentImportId = 0;
|
||||||
QHash<int, ParseData> m_parseData;
|
QHash<int, ParseData> m_parseData;
|
||||||
QString m_progressTitle;
|
QString m_progressTitle;
|
||||||
QList<Import> m_requiredImports;
|
QList<Import> m_requiredImports;
|
||||||
|
QList<int> m_puppetQueue;
|
||||||
};
|
};
|
||||||
} // QmlDesigner
|
} // QmlDesigner
|
||||||
|
Reference in New Issue
Block a user