QmlDesigner: Move 3D asset import to puppet

Moved 3D asset import to puppet to ensure import always uses the
correct version of the QtQuick3D.

Fixes: QDS-3154
Change-Id: I630a833e7231383b87bf8b7214d3545d12de15ab
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Miikka Heikkinen
2021-01-22 17:51:46 +02:00
parent f15fef7ee1
commit 99a3ddbd23
27 changed files with 507 additions and 251 deletions

View File

@@ -34,7 +34,13 @@ namespace QmlDesigner {
class PuppetToCreatorCommand class PuppetToCreatorCommand
{ {
public: public:
enum Type { Edit3DToolState, Render3DView, ActiveSceneChanged, RenderModelNodePreviewImage, None }; enum Type {
Edit3DToolState,
Render3DView,
ActiveSceneChanged,
RenderModelNodePreviewImage,
Import3DSupport,
None };
PuppetToCreatorCommand(Type type, const QVariant &data); PuppetToCreatorCommand(Type type, const QVariant &data);
PuppetToCreatorCommand() = default; PuppetToCreatorCommand() = default;

View File

@@ -0,0 +1,79 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "import3d.h"
#ifdef IMPORT_QUICK3D_ASSETS
#include <QtQuick3DAssetImport/private/qssgassetimportmanager_p.h>
#endif
#include <QJsonDocument>
#include <QJsonObject>
#include <QCoreApplication>
#include <QTimer>
#include <QScopedPointer>
namespace Import3D
{
void import3D(const QString &sourceAsset, const QString &outDir, int exitId, const QString &options)
{
#ifdef IMPORT_QUICK3D_ASSETS
QScopedPointer importer {new QSSGAssetImportManager};
QJsonParseError error;
QJsonDocument optDoc = QJsonDocument::fromJson(options.toUtf8(), &error);
if (!optDoc.isNull() && optDoc.isObject()) {
QString errorStr;
QJsonObject optObj = optDoc.object();
if (importer->importFile(sourceAsset, outDir, optObj.toVariantMap(), &errorStr)
!= QSSGAssetImportManager::ImportState::Success) {
qWarning() << __FUNCTION__ << "Failed to import 3D asset"
<< sourceAsset << "with error:" << errorStr;
} else {
// Allow little time for file operations to finish
QTimer::singleShot(2000, nullptr, [exitId]() {
qApp->exit(exitId);
});
return;
}
} else {
qWarning() << __FUNCTION__ << "Failed to parse import options:" << error.errorString();
}
#else
Q_UNUSED(sourceAsset)
Q_UNUSED(outDir)
Q_UNUSED(exitId)
Q_UNUSED(options)
qWarning() << __FUNCTION__ << "Failed to parse import options, Quick3DAssetImport not available";
#endif
QTimer::singleShot(0, nullptr, [exitId]() {
// Negative exitId means import failure
qApp->exit(-exitId);
});
}
}

View File

@@ -0,0 +1,33 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QString>
namespace Import3D
{
void import3D(const QString &sourceAsset, const QString &outDir, int id, const QString &options);
};

View File

@@ -0,0 +1,3 @@
HEADERS += $$PWD/import3d.h
SOURCES += $$PWD/import3d.cpp

View File

@@ -1,9 +1,15 @@
INCLUDEPATH += $$PWD/ INCLUDEPATH += $$PWD/
versionAtLeast(QT_VERSION, 5.15.0):qtHaveModule(quick3d) { versionAtLeast(QT_VERSION, 5.15.0) {
qtHaveModule(quick3d) {
QT *= quick3d-private QT *= quick3d-private
DEFINES *= QUICK3D_MODULE DEFINES *= QUICK3D_MODULE
} }
qtHaveModule(quick3dassetimport) {
QT *= quick3dassetimport-private
DEFINES *= IMPORT_QUICK3D_ASSETS
}
}
HEADERS += $$PWD/qt5nodeinstanceserver.h \ HEADERS += $$PWD/qt5nodeinstanceserver.h \
$$PWD/capturenodeinstanceserverdispatcher.h \ $$PWD/capturenodeinstanceserverdispatcher.h \

View File

@@ -102,6 +102,10 @@
#endif #endif
#endif #endif
#ifdef IMPORT_QUICK3D_ASSETS
#include <QtQuick3DAssetImport/private/qssgassetimportmanager_p.h>
#endif
// Uncomment to display FPS counter on the lower left corner of edit 3D view // Uncomment to display FPS counter on the lower left corner of edit 3D view
//#define FPS_COUNTER //#define FPS_COUNTER
#ifdef FPS_COUNTER #ifdef FPS_COUNTER
@@ -253,6 +257,37 @@ void Qt5InformationNodeInstanceServer::handleInputEvents()
} }
} }
void Qt5InformationNodeInstanceServer::resolveImportSupport()
{
#ifdef IMPORT_QUICK3D_ASSETS
QSSGAssetImportManager importManager;
const QHash<QString, QStringList> supportedExtensions = importManager.getSupportedExtensions();
const QHash<QString, QVariantMap> supportedOptions = importManager.getAllOptions();
QVariantMap supportMap;
QVariantMap extMap;
auto itExt = supportedExtensions.constBegin();
while (itExt != supportedExtensions.constEnd()) {
extMap.insert(itExt.key(), itExt.value());
++itExt;
}
QVariantMap optMap;
auto itOpt = supportedOptions.constBegin();
while (itOpt != supportedOptions.constEnd()) {
optMap.insert(itOpt.key(), itOpt.value());
++itOpt;
}
supportMap.insert("options", optMap);
supportMap.insert("extensions", extMap);
nodeInstanceClient()->handlePuppetToCreatorCommand(
{PuppetToCreatorCommand::Import3DSupport, QVariant(supportMap)});
#endif
}
void Qt5InformationNodeInstanceServer::createEditView3D() void Qt5InformationNodeInstanceServer::createEditView3D()
{ {
#ifdef QUICK3D_MODULE #ifdef QUICK3D_MODULE
@@ -1462,6 +1497,9 @@ void Qt5InformationNodeInstanceServer::createScene(const CreateSceneCommand &com
QObject::connect(&m_renderModelNodeImageViewTimer, &QTimer::timeout, QObject::connect(&m_renderModelNodeImageViewTimer, &QTimer::timeout,
this, &Qt5InformationNodeInstanceServer::doRenderModelNodeImageView); this, &Qt5InformationNodeInstanceServer::doRenderModelNodeImageView);
#ifdef IMPORT_QUICK3D_ASSETS
QTimer::singleShot(0, this, &Qt5InformationNodeInstanceServer::resolveImportSupport);
#endif
} }
void Qt5InformationNodeInstanceServer::sendChildrenChangedCommand(const QList<ServerNodeInstance> &childList) void Qt5InformationNodeInstanceServer::sendChildrenChangedCommand(const QList<ServerNodeInstance> &childList)

View File

@@ -131,6 +131,7 @@ private:
void doRenderModelNode2DImageView(); void doRenderModelNode2DImageView();
void updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances); void updateLockedAndHiddenStates(const QSet<ServerNodeInstance> &instances);
void handleInputEvents(); void handleInputEvents();
void resolveImportSupport();
void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData); void createAuxiliaryQuickView(const QUrl &url, RenderViewData &viewData);

View File

@@ -24,6 +24,7 @@ include (../interfaces/interfaces.pri)
include (../types/types.pri) include (../types/types.pri)
include (../qmlprivategate/qmlprivategate.pri) include (../qmlprivategate/qmlprivategate.pri)
include (iconrenderer/iconrenderer.pri) include (iconrenderer/iconrenderer.pri)
include (import3d/import3d.pri)
SOURCES += $$PWD/qml2puppetmain.cpp SOURCES += $$PWD/qml2puppetmain.cpp
RESOURCES += $$PWD/../qmlpuppet.qrc RESOURCES += $$PWD/../qmlpuppet.qrc

View File

@@ -35,6 +35,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "iconrenderer/iconrenderer.h" #include "iconrenderer/iconrenderer.h"
#include "import3d/import3d.h"
#include <qt5nodeinstanceclientproxy.h> #include <qt5nodeinstanceclientproxy.h>
#include <QQmlComponent> #include <QQmlComponent>
@@ -152,12 +153,14 @@ int internalMain(QGuiApplication *application)
if (application->arguments().count() < 2 if (application->arguments().count() < 2
|| (application->arguments().at(1) == "--readcapturedstream" && application->arguments().count() < 3) || (application->arguments().at(1) == "--readcapturedstream" && application->arguments().count() < 3)
|| (application->arguments().at(1) == "--rendericon" && application->arguments().count() < 5)) { || (application->arguments().at(1) == "--rendericon" && application->arguments().count() < 5)
|| (application->arguments().at(1) == "--import3dAsset" && application->arguments().count() < 6)) {
qDebug() << "Usage:\n"; qDebug() << "Usage:\n";
qDebug() << "--test"; qDebug() << "--test";
qDebug() << "--version"; qDebug() << "--version";
qDebug() << "--readcapturedstream <stream file> [control stream file]"; qDebug() << "--readcapturedstream <stream file> [control stream file]";
qDebug() << "--rendericon <icon size> <icon file name> <icon source qml>"; qDebug() << "--rendericon <icon size> <icon file name> <icon source qml>";
qDebug() << "--import3dAsset <source asset file name> <output dir> <id number> <import options JSON>";
return -1; return -1;
} }
@@ -220,6 +223,17 @@ int internalMain(QGuiApplication *application)
return application->exec(); return application->exec();
} }
if (application->arguments().at(1) == "--import3dAsset") {
QString sourceAsset = application->arguments().at(2);
QString outDir = application->arguments().at(3);
int exitId = application->arguments().at(4).toInt();
QString options = application->arguments().at(5);
Import3D::import3D(sourceAsset, outDir, exitId, options);
return application->exec();
}
#ifdef ENABLE_QT_BREAKPAD #ifdef ENABLE_QT_BREAKPAD
const QString libexecPath = QCoreApplication::applicationDirPath() + '/' + RELATIVE_LIBEXEC_PATH; const QString libexecPath = QCoreApplication::applicationDirPath() + '/' + RELATIVE_LIBEXEC_PATH;
QtSystemExceptionHandler systemExceptionHandler(libexecPath); QtSystemExceptionHandler systemExceptionHandler(libexecPath);

View File

@@ -326,14 +326,6 @@ extend_qtc_plugin(QmlDesigner
itemlibraryiconimageprovider.cpp itemlibraryiconimageprovider.h itemlibraryiconimageprovider.cpp itemlibraryiconimageprovider.h
) )
find_package(Qt5 COMPONENTS Quick3DAssetImport QUIET)
extend_qtc_plugin(QmlDesigner
CONDITION TARGET Qt5::Quick3DAssetImport
FEATURE_INFO "Qt Quick 3D asset import"
DEPENDS Qt5::Quick3DAssetImportPrivate
DEFINES IMPORT_QUICK3D_ASSETS
)
extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/navigator SOURCES_PREFIX components/navigator
SOURCES SOURCES

View File

@@ -199,6 +199,15 @@ void DesignerActionManager::registerAddResourceHandler(const AddResourceHandler
m_addResourceHandler.append(handler); m_addResourceHandler.append(handler);
} }
void DesignerActionManager::unregisterAddResourceHandlers(const QString &category)
{
for (int i = m_addResourceHandler.size() - 1; i >= 0 ; --i) {
const AddResourceHandler &handler = m_addResourceHandler[i];
if (handler.category == category)
m_addResourceHandler.removeAt(i);
}
}
void DesignerActionManager::registerModelNodePreviewHandler(const ModelNodePreviewImageHandler &handler) void DesignerActionManager::registerModelNodePreviewHandler(const ModelNodePreviewImageHandler &handler)
{ {
m_modelNodePreviewImageHandlers.append(handler); m_modelNodePreviewImageHandlers.append(handler);

View File

@@ -129,6 +129,7 @@ public:
QList<AddResourceHandler> addResourceHandler() const; QList<AddResourceHandler> addResourceHandler() const;
void registerAddResourceHandler(const AddResourceHandler &handler); void registerAddResourceHandler(const AddResourceHandler &handler);
void unregisterAddResourceHandlers(const QString &category);
void registerModelNodePreviewHandler(const ModelNodePreviewImageHandler &handler); void registerModelNodePreviewHandler(const ModelNodePreviewImageHandler &handler);
bool hasModelNodePreviewHandler(const ModelNode &node) const; bool hasModelNodePreviewHandler(const ModelNode &node) const;

View File

@@ -1,10 +1,5 @@
VPATH += $$PWD VPATH += $$PWD
qtHaveModule(quick3dassetimport) {
QT *= quick3dassetimport-private
DEFINES *= IMPORT_QUICK3D_ASSETS
}
# Input # Input
HEADERS += itemlibraryview.h \ HEADERS += itemlibraryview.h \
$$PWD/itemlibraryiconimageprovider.h \ $$PWD/itemlibraryiconimageprovider.h \

View File

@@ -71,10 +71,13 @@ static const int rowHeight = 26;
} }
ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &importFiles, ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &importFiles,
const QString &defaulTargetDirectory, QWidget *parent) : const QString &defaulTargetDirectory,
QDialog(parent), const QVariantMap &supportedExts,
ui(new Ui::ItemLibraryAssetImportDialog), const QVariantMap &supportedOpts,
m_importer(this) QWidget *parent) :
QDialog(parent)
, ui(new Ui::ItemLibraryAssetImportDialog)
, m_importer(this)
{ {
setModal(true); setModal(true);
ui->setupUi(this); ui->setupUi(this);
@@ -83,15 +86,24 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
m_outputFormatter->setPlainTextEdit(ui->plainTextEdit); m_outputFormatter->setPlainTextEdit(ui->plainTextEdit);
// Skip unsupported assets // Skip unsupported assets
bool skipSome = false; QHash<QString, bool> supportMap;
for (const auto &file : importFiles) { for (const auto &file : importFiles) {
if (m_importer.isQuick3DAsset(file)) QString suffix = QFileInfo(file).suffix();
if (!supportMap.contains(suffix)) {
bool supported = false;
for (const auto &exts : supportedExts) {
if (exts.toStringList().contains(suffix)) {
supported = true;
break;
}
}
supportMap.insert(suffix, supported);
}
if (supportMap[suffix])
m_quick3DFiles << file; m_quick3DFiles << file;
else
skipSome = true;
} }
if (skipSome) if (m_quick3DFiles.size() != importFiles.size())
addWarning("Cannot import 3D and other assets simultaneously. Skipping non-3D assets."); addWarning("Cannot import 3D and other assets simultaneously. Skipping non-3D assets.");
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Import")); ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Import"));
@@ -153,14 +165,12 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
m_quick3DImportPath = candidatePath; m_quick3DImportPath = candidatePath;
if (!m_quick3DFiles.isEmpty()) { if (!m_quick3DFiles.isEmpty()) {
const QHash<QString, QVariantMap> allOptions = m_importer.allOptions();
const QHash<QString, QStringList> supportedExtensions = m_importer.supportedExtensions();
QVector<QJsonObject> groups; QVector<QJsonObject> groups;
auto optIt = allOptions.constBegin(); auto optIt = supportedOpts.constBegin();
int optIndex = 0; int optIndex = 0;
while (optIt != allOptions.constEnd()) { while (optIt != supportedOpts.constEnd()) {
QJsonObject options = QJsonObject::fromVariantMap(optIt.value()); QJsonObject options = QJsonObject::fromVariantMap(qvariant_cast<QVariantMap>(optIt.value()));
m_importOptions << options.value("options").toObject(); m_importOptions << options.value("options").toObject();
groups << options.value("groups").toObject(); groups << options.value("groups").toObject();
const auto &exts = optIt.key().split(':'); const auto &exts = optIt.key().split(':');
@@ -173,10 +183,10 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
// Create tab for each supported extension group that also has files included in the import // Create tab for each supported extension group that also has files included in the import
QMap<QString, int> tabMap; // QMap used for alphabetical order QMap<QString, int> tabMap; // QMap used for alphabetical order
for (const auto &file : qAsConst(m_quick3DFiles)) { for (const auto &file : qAsConst(m_quick3DFiles)) {
auto extIt = supportedExtensions.constBegin(); auto extIt = supportedExts.constBegin();
QString ext = QFileInfo(file).suffix().toLower(); QString ext = QFileInfo(file).suffix().toLower();
while (extIt != supportedExtensions.constEnd()) { while (extIt != supportedExts.constEnd()) {
if (!tabMap.contains(extIt.key()) && extIt.value().contains(ext)) { if (!tabMap.contains(extIt.key()) && extIt.value().toStringList().contains(ext)) {
tabMap.insert(extIt.key(), m_extToImportOptionsMap.value(ext)); tabMap.insert(extIt.key(), m_extToImportOptionsMap.value(ext));
break; break;
} }

View File

@@ -46,7 +46,10 @@ class ItemLibraryAssetImportDialog : public QDialog
public: public:
explicit ItemLibraryAssetImportDialog(const QStringList &importFiles, explicit ItemLibraryAssetImportDialog(const QStringList &importFiles,
const QString &defaulTargetDirectory, QWidget *parent = nullptr); const QString &defaulTargetDirectory,
const QVariantMap &supportedExts,
const QVariantMap &supportedOpts,
QWidget *parent = nullptr);
~ItemLibraryAssetImportDialog(); ~ItemLibraryAssetImportDialog();
protected: protected:

View File

@@ -30,18 +30,15 @@
#include "model.h" #include "model.h"
#include "puppetcreator.h" #include "puppetcreator.h"
#include <QtCore/qdir.h> #include <QDir>
#include <QtCore/qdiriterator.h> #include <QDirIterator>
#include <QtCore/qsavefile.h> #include <QSaveFile>
#include <QtCore/qfile.h> #include <QFile>
#include <QtCore/qloggingcategory.h> #include <QLoggingCategory>
#include <QtCore/qtemporarydir.h> #include <QTemporaryDir>
#include <QtWidgets/qapplication.h> #include <QApplication>
#include <QtWidgets/qmessagebox.h> #include <QMessageBox>
#include <QJsonDocument>
#ifdef IMPORT_QUICK3D_ASSETS
#include <QtQuick3DAssetImport/private/qssgassetimportmanager_p.h>
#endif
namespace namespace
{ {
@@ -53,9 +50,6 @@ namespace QmlDesigner {
ItemLibraryAssetImporter::ItemLibraryAssetImporter(QObject *parent) : ItemLibraryAssetImporter::ItemLibraryAssetImporter(QObject *parent) :
QObject (parent) QObject (parent)
{ {
#ifdef IMPORT_QUICK3D_ASSETS
m_quick3DAssetImporter.reset(new QSSGAssetImportManager);
#endif
} }
ItemLibraryAssetImporter::~ItemLibraryAssetImporter() { ItemLibraryAssetImporter::~ItemLibraryAssetImporter() {
@@ -73,7 +67,6 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
reset(); reset();
m_isImporting = true; m_isImporting = true;
#ifdef IMPORT_QUICK3D_ASSETS
if (!m_tempDir->isValid()) { if (!m_tempDir->isValid()) {
addError(tr("Could not create a temporary directory for import.")); addError(tr("Could not create a temporary directory for import."));
notifyFinished(); notifyFinished();
@@ -85,24 +78,27 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
parseFiles(inputFiles, options, extToImportOptionsMap); parseFiles(inputFiles, options, extToImportOptionsMap);
if (!isCancelled()) { if (!isCancelled()) {
// Wait for icon generation processes to finish const auto parseData = m_parseData;
for (const auto &pd : parseData) {
if (!startImportProcess(pd)) {
addError(tr("Failed to start import 3D asset process"),
pd.sourceInfo.absoluteFilePath());
m_parseData.remove(pd.importId);
}
}
}
if (!isCancelled()) {
// Wait for puppet processes to finish
if (m_qmlPuppetProcesses.empty()) { if (m_qmlPuppetProcesses.empty()) {
finalizeQuick3DImport(); postImport();
} else { } else {
m_qmlPuppetCount = static_cast<int>(m_qmlPuppetProcesses.size()); m_qmlPuppetCount = static_cast<int>(m_qmlPuppetProcesses.size());
const QString progressTitle = tr("Generating icons."); const QString progressTitle = tr("Importing 3D assets.");
addInfo(progressTitle); addInfo(progressTitle);
notifyProgress(0, progressTitle); notifyProgress(0, progressTitle);
} }
} }
#else
Q_UNUSED(inputFiles)
Q_UNUSED(importPath)
Q_UNUSED(options)
Q_UNUSED(extToImportOptionsMap)
addError(tr("Importing 3D assets requires building against Qt Quick 3D module."));
notifyFinished();
#endif
} }
bool ItemLibraryAssetImporter::isImporting() const bool ItemLibraryAssetImporter::isImporting() const
@@ -135,67 +131,47 @@ void ItemLibraryAssetImporter::addInfo(const QString &infoMsg, const QString &sr
emit infoReported(infoMsg, srcPath); emit infoReported(infoMsg, srcPath);
} }
bool ItemLibraryAssetImporter::isQuick3DAsset(const QString &fileName) const void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{ {
#ifdef IMPORT_QUICK3D_ASSETS Q_UNUSED(exitStatus)
static QStringList quick3DExt;
if (quick3DExt.isEmpty()) { ++m_qmlImportFinishedCount;
const auto exts = m_quick3DAssetImporter->getSupportedExtensions();
for (const auto &ext : exts) m_qmlPuppetProcesses.erase(
quick3DExt << ext; std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(),
} [&](const auto &entry) {
return quick3DExt.contains(QFileInfo(fileName).suffix().toLower()); return !entry || entry->state() == QProcess::NotRunning;
#else }));
Q_UNUSED(fileName)
return false; if (m_parseData.contains(-exitCode)) {
#endif const ParseData pd = m_parseData.take(-exitCode);
addError(tr("Asset import process failed for: \"%1\"").arg(pd.sourceInfo.absoluteFilePath()));
} }
QVariantMap ItemLibraryAssetImporter::supportedOptions(const QString &modelFile) const if (m_qmlImportFinishedCount == m_qmlPuppetCount) {
{ notifyProgress(100);
#ifdef IMPORT_QUICK3D_ASSETS QTimer::singleShot(0, this, &ItemLibraryAssetImporter::postImport);
return m_quick3DAssetImporter->getOptionsForFile(modelFile); } else {
#else notifyProgress(int(100. * (double(m_qmlImportFinishedCount) / double(m_qmlPuppetCount))));
Q_UNUSED(modelFile) }
return {};
#endif
} }
QHash<QString, QVariantMap> ItemLibraryAssetImporter::allOptions() const void ItemLibraryAssetImporter::iconProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
#ifdef IMPORT_QUICK3D_ASSETS
return m_quick3DAssetImporter->getAllOptions();
#else
return {};
#endif
}
QHash<QString, QStringList> ItemLibraryAssetImporter::supportedExtensions() const
{
#ifdef IMPORT_QUICK3D_ASSETS
return m_quick3DAssetImporter->getSupportedExtensions();
#else
return {};
#endif
}
void ItemLibraryAssetImporter::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
{ {
Q_UNUSED(exitCode) Q_UNUSED(exitCode)
Q_UNUSED(exitStatus) Q_UNUSED(exitStatus)
m_qmlPuppetProcesses.erase( m_qmlPuppetProcesses.erase(
std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(), [&](const auto &entry) { std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(),
[&](const auto &entry) {
return !entry || entry->state() == QProcess::NotRunning; return !entry || entry->state() == QProcess::NotRunning;
})); }));
const QString progressTitle = tr("Generating icons.");
if (m_qmlPuppetProcesses.empty()) { if (m_qmlPuppetProcesses.empty()) {
notifyProgress(100, progressTitle); notifyProgress(100);
finalizeQuick3DImport(); QTimer::singleShot(0, this, &ItemLibraryAssetImporter::finalizeQuick3DImport);
} else { } else {
notifyProgress(int(100. * (1. - double(m_qmlPuppetCount) / double(m_qmlPuppetProcesses.size()))), notifyProgress(int(100. * (1. - (double(m_qmlPuppetProcesses.size()) / double(m_qmlPuppetCount)))));
progressTitle);
} }
} }
@@ -210,14 +186,14 @@ void ItemLibraryAssetImporter::reset()
m_isImporting = false; m_isImporting = false;
m_cancelled = false; m_cancelled = false;
#ifdef IMPORT_QUICK3D_ASSETS
delete m_tempDir; delete m_tempDir;
m_tempDir = new QTemporaryDir; m_tempDir = new QTemporaryDir;
m_importFiles.clear(); m_importFiles.clear();
m_overwrittenImports.clear(); m_overwrittenImports.clear();
m_qmlPuppetProcesses.clear(); m_qmlPuppetProcesses.clear();
m_qmlPuppetCount = 0; m_qmlPuppetCount = 0;
#endif m_qmlImportFinishedCount = 0;
m_parseData.clear();
} }
void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths, void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths,
@@ -235,99 +211,86 @@ void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths,
notifyProgress(qRound(quota * (count + value)), progressTitle); notifyProgress(qRound(quota * (count + value)), progressTitle);
}; };
for (const QString &file : filePaths) { for (const QString &file : filePaths) {
if (isCancelled())
return;
if (isQuick3DAsset(file)) {
int index = extToImportOptionsMap.value(QFileInfo(file).suffix()); int index = extToImportOptionsMap.value(QFileInfo(file).suffix());
parseQuick3DAsset(file, options[index].toVariantMap()); ParseData pd;
pd.options = options[index];
if (preParseQuick3DAsset(file, pd)) {
pd.importId = ++m_importIdCounter;
m_parseData.insert(pd.importId, pd);
} }
notifyProgress(qRound(++count * quota), progressTitle); notifyProgress(qRound(++count * quota), progressTitle);
} }
notifyProgress(100, progressTitle);
} }
void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVariantMap &options) bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseData &pd)
{ {
#ifdef IMPORT_QUICK3D_ASSETS pd.targetDir = QDir(m_importPath);
addInfo(tr("Parsing 3D Model"), file); pd.outDir = QDir(m_tempDir->path());
pd.sourceInfo = QFileInfo(file);
pd.assetName = pd.sourceInfo.completeBaseName();
QString errorString; if (!pd.assetName.isEmpty()) {
QDir targetDir(m_importPath);
QDir outDir(m_tempDir->path());
QFileInfo sourceInfo(file);
QString assetName = sourceInfo.completeBaseName();
if (!assetName.isEmpty()) {
// Fix name so it plays nice with imports // Fix name so it plays nice with imports
for (QChar &currentChar : assetName) { for (QChar &currentChar : pd.assetName) {
if (!currentChar.isLetter() && !currentChar.isDigit()) if (!currentChar.isLetter() && !currentChar.isDigit())
currentChar = QLatin1Char('_'); currentChar = QLatin1Char('_');
} }
const QChar firstChar = assetName[0]; const QChar firstChar = pd.assetName[0];
if (firstChar.isDigit()) if (firstChar.isDigit())
assetName[0] = QLatin1Char('_'); pd.assetName[0] = QLatin1Char('_');
if (firstChar.isLower()) if (firstChar.isLower())
assetName[0] = firstChar.toUpper(); pd.assetName[0] = firstChar.toUpper();
} }
QString targetDirPath = targetDir.filePath(assetName); pd.targetDirPath = pd.targetDir.filePath(pd.assetName);
if (outDir.exists(assetName)) { if (pd.outDir.exists(pd.assetName)) {
addWarning(tr("Skipped import of duplicate asset: \"%1\"").arg(assetName)); addWarning(tr("Skipped import of duplicate asset: \"%1\"").arg(pd.assetName));
return; return false;
} }
QString originalAssetName = assetName; pd.originalAssetName = pd.assetName;
if (targetDir.exists(assetName)) { if (pd.targetDir.exists(pd.assetName)) {
// If we have a file system with case insensitive filenames, assetName may be // If we have a file system with case insensitive filenames, assetName may be
// different from the existing name. Modify assetName to ensure exact match to // different from the existing name. Modify assetName to ensure exact match to
// the overwritten old asset capitalization // the overwritten old asset capitalization
const QStringList assetDirs = targetDir.entryList({assetName}, QDir::Dirs); const QStringList assetDirs = pd.targetDir.entryList({pd.assetName}, QDir::Dirs);
if (assetDirs.size() == 1) { if (assetDirs.size() == 1) {
assetName = assetDirs[0]; pd.assetName = assetDirs[0];
targetDirPath = targetDir.filePath(assetName); pd.targetDirPath = pd.targetDir.filePath(pd.assetName);
} }
if (!confirmAssetOverwrite(assetName)) { if (!confirmAssetOverwrite(pd.assetName)) {
addWarning(tr("Skipped import of existing asset: \"%1\"").arg(assetName)); addWarning(tr("Skipped import of existing asset: \"%1\"").arg(pd.assetName));
return; return false;
} }
m_overwrittenImports << targetDirPath; m_overwrittenImports << pd.targetDirPath;
} }
outDir.mkpath(assetName); pd.outDir.mkpath(pd.assetName);
if (!outDir.cd(assetName)) { if (!pd.outDir.cd(pd.assetName)) {
addError(tr("Could not access temporary asset directory: \"%1\"") addError(tr("Could not access temporary asset directory: \"%1\"")
.arg(outDir.filePath(assetName))); .arg(pd.outDir.filePath(pd.assetName)));
return; return false;
}
return true;
} }
addInfo(tr("Generating 3D assets for: \"%1\"").arg(targetDir.absoluteFilePath(assetName))); void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd)
{
if (m_quick3DAssetImporter->importFile( QDir outDir = pd.outDir;
sourceInfo.absoluteFilePath(), outDir, options, &errorString) if (pd.originalAssetName != pd.assetName) {
!= QSSGAssetImportManager::ImportState::Success) {
addError(tr("Failed to import 3D asset with error: %1").arg(errorString),
sourceInfo.absoluteFilePath());
return;
}
// The importer is reset after every import to avoid issues with it caching various things
m_quick3DAssetImporter.reset(new QSSGAssetImportManager);
if (originalAssetName != assetName) {
// Fix the generated qml file name // Fix the generated qml file name
const QString assetQml = originalAssetName + ".qml"; const QString assetQml = pd.originalAssetName + ".qml";
if (outDir.exists(assetQml)) if (outDir.exists(assetQml))
outDir.rename(assetQml, assetName + ".qml"); outDir.rename(assetQml, pd.assetName + ".qml");
} }
QHash<QString, QString> assetFiles; QHash<QString, QString> assetFiles;
const int outDirPathSize = outDir.path().size(); const int outDirPathSize = outDir.path().size();
auto insertAsset = [&](const QString &filePath) { auto insertAsset = [&](const QString &filePath) {
QString targetPath = filePath.mid(outDirPathSize); QString targetPath = filePath.mid(outDirPathSize);
targetPath.prepend(targetDirPath); targetPath.prepend(pd.targetDirPath);
assetFiles.insert(filePath, targetPath); assetFiles.insert(filePath, targetPath);
}; };
@@ -348,7 +311,7 @@ void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVar
qmlInfo.append("module "); qmlInfo.append("module ");
qmlInfo.append(m_importPath.split('/').last()); qmlInfo.append(m_importPath.split('/').last());
qmlInfo.append("."); qmlInfo.append(".");
qmlInfo.append(assetName); qmlInfo.append(pd.assetName);
qmlInfo.append('\n'); qmlInfo.append('\n');
while (qmlIt.hasNext()) { while (qmlIt.hasNext()) {
qmlIt.next(); qmlIt.next();
@@ -382,7 +345,7 @@ void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVar
out << "canBeDroppedInView3D: true" << Qt::endl; out << "canBeDroppedInView3D: true" << Qt::endl;
file.close(); file.close();
} }
if (generateComponentIcon(24, iconFileName, qmlIt.filePath())) { if (startIconProcess(24, iconFileName, qmlIt.filePath())) {
// 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.
@@ -395,7 +358,7 @@ void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVar
qmldirFile.write(qmlInfo.toUtf8()); qmldirFile.write(qmlInfo.toUtf8());
qmldirFile.commit(); qmldirFile.commit();
} else { } else {
addError(tr("Failed to create qmldir file for asset: \"%1\"").arg(assetName)); addError(tr("Failed to create qmldir file for asset: \"%1\"").arg(pd.assetName));
} }
} }
} }
@@ -408,19 +371,13 @@ void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVar
} }
// Copy the original asset into a subdirectory // Copy the original asset into a subdirectory
assetFiles.insert(sourceInfo.absoluteFilePath(), assetFiles.insert(pd.sourceInfo.absoluteFilePath(),
targetDirPath + QStringLiteral("/source scene/") + sourceInfo.fileName()); pd.targetDirPath + QStringLiteral("/source scene/") + pd.sourceInfo.fileName());
m_importFiles.insert(assetFiles); m_importFiles.insert(assetFiles);
#else
Q_UNUSED(file)
Q_UNUSED(options)
#endif
} }
void ItemLibraryAssetImporter::copyImportedFiles() void ItemLibraryAssetImporter::copyImportedFiles()
{ {
#ifdef IMPORT_QUICK3D_ASSETS
if (!m_overwrittenImports.isEmpty()) { if (!m_overwrittenImports.isEmpty()) {
const QString progressTitle = tr("Removing old overwritten assets."); const QString progressTitle = tr("Removing old overwritten assets.");
addInfo(progressTitle); addInfo(progressTitle);
@@ -461,15 +418,20 @@ void ItemLibraryAssetImporter::copyImportedFiles()
} }
notifyProgress(100, progressTitle); notifyProgress(100, progressTitle);
} }
#endif
} }
void ItemLibraryAssetImporter::notifyProgress(int value, const QString &text) const void ItemLibraryAssetImporter::notifyProgress(int value, const QString &text)
{ {
emit progressChanged(value, text); m_progressTitle = text;
emit progressChanged(value, m_progressTitle);
keepUiAlive(); keepUiAlive();
} }
void ItemLibraryAssetImporter::notifyProgress(int value)
{
notifyProgress(value, m_progressTitle);
}
void ItemLibraryAssetImporter::keepUiAlive() const void ItemLibraryAssetImporter::keepUiAlive() const
{ {
QApplication::processEvents(); QApplication::processEvents();
@@ -484,7 +446,41 @@ bool ItemLibraryAssetImporter::confirmAssetOverwrite(const QString &assetName)
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes; QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes;
} }
bool ItemLibraryAssetImporter::generateComponentIcon(int size, const QString &iconFile, bool ItemLibraryAssetImporter::startImportProcess(const ParseData &pd)
{
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
Model *model = doc ? doc->currentModel() : nullptr;
if (model) {
PuppetCreator puppetCreator(doc->currentTarget(), model);
puppetCreator.createQml2PuppetExecutableIfMissing();
QStringList puppetArgs;
QJsonDocument optDoc(pd.options);
puppetArgs << "--import3dAsset" << pd.sourceInfo.absoluteFilePath()
<< pd.outDir.absolutePath() << QString::number(pd.importId)
<< QString::fromUtf8(optDoc.toJson());
QProcessUniquePointer process = puppetCreator.createPuppetProcess(
"custom",
{},
std::function<void()>(),
[&](int exitCode, QProcess::ExitStatus exitStatus) {
importProcessFinished(exitCode, exitStatus);
},
puppetArgs);
if (process->waitForStarted(5000)) {
m_qmlPuppetProcesses.push_back(std::move(process));
return true;
} else {
process.reset();
}
}
return false;
}
bool ItemLibraryAssetImporter::startIconProcess(int size, const QString &iconFile,
const QString &iconSource) const QString &iconSource)
{ {
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument(); auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
@@ -500,7 +496,7 @@ bool ItemLibraryAssetImporter::generateComponentIcon(int size, const QString &ic
{}, {},
std::function<void()>(), std::function<void()>(),
[&](int exitCode, QProcess::ExitStatus exitStatus) { [&](int exitCode, QProcess::ExitStatus exitStatus) {
processFinished(exitCode, exitStatus); iconProcessFinished(exitCode, exitStatus);
}, },
puppetArgs); puppetArgs);
@@ -514,9 +510,30 @@ bool ItemLibraryAssetImporter::generateComponentIcon(int size, const QString &ic
return false; return false;
} }
void ItemLibraryAssetImporter::postImport()
{
Q_ASSERT(m_qmlPuppetProcesses.empty());
if (!isCancelled()) {
for (const auto &pd : qAsConst(m_parseData))
postParseQuick3DAsset(pd);
}
if (!isCancelled()) {
// Wait for icon generation processes to finish
if (m_qmlPuppetProcesses.empty()) {
finalizeQuick3DImport();
} else {
m_qmlPuppetCount = static_cast<int>(m_qmlPuppetProcesses.size());
const QString progressTitle = tr("Generating icons.");
addInfo(progressTitle);
notifyProgress(0, progressTitle);
}
}
}
void ItemLibraryAssetImporter::finalizeQuick3DImport() void ItemLibraryAssetImporter::finalizeQuick3DImport()
{ {
#ifdef IMPORT_QUICK3D_ASSETS
if (!isCancelled()) { if (!isCancelled()) {
// Don't allow cancel anymore as existing asset overwrites are not trivially recoverable. // Don't allow cancel anymore as existing asset overwrites are not trivially recoverable.
// Also, on Windows at least you can't delete a subdirectory of a watched directory, // Also, on Windows at least you can't delete a subdirectory of a watched directory,
@@ -562,7 +579,6 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport()
notifyFinished(); notifyFinished();
} }
} }
#endif
} }
bool ItemLibraryAssetImporter::isCancelled() const bool ItemLibraryAssetImporter::isCancelled() const

View File

@@ -29,11 +29,13 @@
#include <qprocessuniqueptr.h> #include <qprocessuniqueptr.h>
#include <QSet> #include <QSet>
#include <QtCore/qhash.h> #include <QHash>
#include <QtCore/qjsonobject.h> #include <QJsonObject>
#include <QtCore/qobject.h> #include <QObject>
#include <QtCore/qprocess.h> #include <QProcess>
#include <QtCore/qstringlist.h> #include <QStringList>
#include <QDir>
#include <QFileInfo>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QSSGAssetImportManager; class QSSGAssetImportManager;
@@ -62,11 +64,6 @@ public:
void addWarning(const QString &warningMsg, const QString &srcPath = {}) const; void addWarning(const QString &warningMsg, const QString &srcPath = {}) const;
void addInfo(const QString &infoMsg, const QString &srcPath = {}) const; void addInfo(const QString &infoMsg, const QString &srcPath = {}) const;
bool isQuick3DAsset(const QString &fileName) const;
QVariantMap supportedOptions(const QString &modelFile) const;
QHash<QString, QVariantMap> allOptions() const;
QHash<QString, QStringList> supportedExtensions() const;
signals: signals:
void errorReported(const QString &, const QString &) const; void errorReported(const QString &, const QString &) const;
void warningReported(const QString &, const QString &) const; void warningReported(const QString &, const QString &) const;
@@ -76,32 +73,49 @@ signals:
void importFinished(); void importFinished();
private slots: private slots:
void processFinished(int exitCode, QProcess::ExitStatus exitStatus); void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void iconProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
private: private:
struct ParseData {
QJsonObject options;
QDir targetDir;
QDir outDir;
QString targetDirPath;
QFileInfo sourceInfo;
QString assetName;
QString originalAssetName;
int importId;
};
void notifyFinished(); void notifyFinished();
void reset(); void reset();
void parseFiles(const QStringList &filePaths, const QVector<QJsonObject> &options, void parseFiles(const QStringList &filePaths, const QVector<QJsonObject> &options,
const QHash<QString, int> &extToImportOptionsMap); const QHash<QString, int> &extToImportOptionsMap);
void parseQuick3DAsset(const QString &file, const QVariantMap &options); bool preParseQuick3DAsset(const QString &file, ParseData &pd);
void postParseQuick3DAsset(const ParseData &pd);
void copyImportedFiles(); void copyImportedFiles();
void notifyProgress(int value, const QString &text) const; void notifyProgress(int value, const QString &text);
void notifyProgress(int value);
void keepUiAlive() const; void keepUiAlive() const;
bool confirmAssetOverwrite(const QString &assetName); bool confirmAssetOverwrite(const QString &assetName);
bool generateComponentIcon(int size, const QString &iconFile, const QString &iconSource); bool startImportProcess(const ParseData &pd);
bool startIconProcess(int size, const QString &iconFile, const QString &iconSource);
void postImport();
void finalizeQuick3DImport(); void finalizeQuick3DImport();
#ifdef IMPORT_QUICK3D_ASSETS
QScopedPointer<QSSGAssetImportManager> m_quick3DAssetImporter;
QSet<QHash<QString, QString>> m_importFiles; QSet<QHash<QString, QString>> m_importFiles;
QSet<QString> m_overwrittenImports; QSet<QString> m_overwrittenImports;
#endif
bool m_isImporting = false; bool m_isImporting = false;
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; std::vector<QProcessUniquePointer> m_qmlPuppetProcesses;
int m_qmlPuppetCount = 0; int m_qmlPuppetCount = 0;
int m_qmlImportFinishedCount = 0;
int m_importIdCounter = 1000000; // Use ids in range unlikely to clash with any normal process exit codes
QHash<int, ParseData> m_parseData;
QString m_progressTitle;
}; };
} // QmlDesigner } // QmlDesigner

View File

@@ -25,6 +25,7 @@
#include "itemlibraryview.h" #include "itemlibraryview.h"
#include "itemlibrarywidget.h" #include "itemlibrarywidget.h"
#include "itemlibraryassetimportdialog.h"
#include "metainfo.h" #include "metainfo.h"
#include <asynchronousimagecache.h> #include <asynchronousimagecache.h>
#include <bindingproperty.h> #include <bindingproperty.h>
@@ -216,4 +217,46 @@ void ItemLibraryView::updateImports()
m_widget->delayedUpdateModel(); m_widget->delayedUpdateModel();
} }
void ItemLibraryView::updateImport3DSupport(const QVariantMap &supportMap)
{
QVariantMap extMap = qvariant_cast<QVariantMap>(supportMap.value("extensions"));
if (m_importableExtensions3DMap != extMap) {
DesignerActionManager *actionManager =
&QmlDesignerPlugin::instance()->viewManager().designerActionManager();
// All things importable by QSSGAssetImportManager are considered to be in the same category
// so we don't get multiple separate import dialogs when different file types are imported.
const QString category = tr("3D Assets");
if (!m_importableExtensions3DMap.isEmpty())
actionManager->unregisterAddResourceHandlers(category);
m_importableExtensions3DMap = extMap;
auto handle3DModel = [this](const QStringList &fileNames, const QString &defaultDir) -> bool {
auto importDlg = new ItemLibraryAssetImportDialog(fileNames, defaultDir,
m_importableExtensions3DMap,
m_importOptions3DMap,
Core::ICore::mainWindow());
importDlg->show();
return true;
};
auto add3DHandler = [&](const QString &category, const QString &ext) {
const QString filter = QStringLiteral("*.%1").arg(ext);
actionManager->registerAddResourceHandler(
AddResourceHandler(category, filter, handle3DModel, 10));
};
const auto groups = extMap.keys();
for (const auto &group : groups) {
const QStringList exts = extMap[group].toStringList();
for (const auto &ext : exts)
add3DHandler(category, ext);
}
}
m_importOptions3DMap = qvariant_cast<QVariantMap>(supportMap.value("options"));
}
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -53,6 +53,7 @@ public:
void modelAboutToBeDetached(Model *model) override; void modelAboutToBeDetached(Model *model) override;
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override; void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
void documentMessagesChanged(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings) override; void documentMessagesChanged(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings) override;
void updateImport3DSupport(const QVariantMap &supportMap) override;
void setResourcePath(const QString &resourcePath); void setResourcePath(const QString &resourcePath);
@@ -66,6 +67,8 @@ private:
QPointer<ItemLibraryWidget> m_widget; QPointer<ItemLibraryWidget> m_widget;
ImportManagerView *m_importManagerView; ImportManagerView *m_importManagerView;
bool m_hasErrors = false; bool m_hasErrors = false;
QVariantMap m_importableExtensions3DMap;
QVariantMap m_importOptions3DMap;
}; };
} }

View File

@@ -26,7 +26,6 @@
#include "itemlibrarywidget.h" #include "itemlibrarywidget.h"
#include "customfilesystemmodel.h" #include "customfilesystemmodel.h"
#include "itemlibraryassetimportdialog.h"
#include "itemlibraryiconimageprovider.h" #include "itemlibraryiconimageprovider.h"
#include <theme.h> #include <theme.h>
@@ -53,10 +52,6 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/messagebox.h> #include <coreplugin/messagebox.h>
#ifdef IMPORT_QUICK3D_ASSETS
#include <QtQuick3DAssetImport/private/qssgassetimportmanager_p.h>
#endif
#include <QApplication> #include <QApplication>
#include <QDrag> #include <QDrag>
#include <QFileDialog> #include <QFileDialog>
@@ -205,49 +200,6 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
addResources({}); addResources({});
}); });
#ifdef IMPORT_QUICK3D_ASSETS
DesignerActionManager *actionManager =
&QmlDesignerPlugin::instance()->viewManager().designerActionManager();
auto handle3DModel = [](const QStringList &fileNames, const QString &defaultDir) -> bool {
auto importDlg = new ItemLibraryAssetImportDialog(fileNames, defaultDir, Core::ICore::mainWindow());
importDlg->show();
return true;
};
auto add3DHandler = [&](const QString &category, const QString &ext) {
const QString filter = QStringLiteral("*.%1").arg(ext);
actionManager->registerAddResourceHandler(
AddResourceHandler(category, filter, handle3DModel, 10));
};
QSSGAssetImportManager importManager;
QHash<QString, QStringList> supportedExtensions = importManager.getSupportedExtensions();
// All things importable by QSSGAssetImportManager are considered to be in the same category
// so we don't get multiple separate import dialogs when different file types are imported.
const QString category = tr("3D Assets");
// Skip if 3D asset handlers have already been added
const QList<AddResourceHandler> handlers = actionManager->addResourceHandler();
bool categoryAlreadyAdded = false;
for (const auto &handler : handlers) {
if (handler.category == category) {
categoryAlreadyAdded = true;
break;
}
}
if (!categoryAlreadyAdded) {
const auto groups = supportedExtensions.keys();
for (const auto &group : groups) {
const auto extensions = supportedExtensions[group];
for (const auto &ext : extensions)
add3DHandler(category, ext);
}
}
#endif
const auto dropSupport = new Utils::DropSupport( const auto dropSupport = new Utils::DropSupport(
m_resourcesView.data(), [this](QDropEvent *event, Utils::DropSupport *) { m_resourcesView.data(), [this](QDropEvent *event, Utils::DropSupport *) {
// Accept supported file types // Accept supported file types

View File

@@ -189,6 +189,7 @@ public:
void emitRenderImage3DChanged(const QImage &image); void emitRenderImage3DChanged(const QImage &image);
void emitUpdateActiveScene3D(const QVariantMap &sceneState); void emitUpdateActiveScene3D(const QVariantMap &sceneState);
void emitModelNodelPreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); void emitModelNodelPreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
void emitImport3DSupportChanged(const QVariantMap &supportMap);
void sendTokenToInstances(const QString &token, int number, const QVector<ModelNode> &nodeVector); void sendTokenToInstances(const QString &token, int number, const QVector<ModelNode> &nodeVector);
@@ -248,6 +249,7 @@ public:
virtual void renderImage3DChanged(const QImage &image); virtual void renderImage3DChanged(const QImage &image);
virtual void updateActiveScene3D(const QVariantMap &sceneState); virtual void updateActiveScene3D(const QVariantMap &sceneState);
virtual void updateImport3DSupport(const QVariantMap &supportMap);
virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); virtual void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion); void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion);

View File

@@ -1578,6 +1578,9 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand
updatePreviewImageForNode(node, image); updatePreviewImageForNode(node, image);
} }
} }
} else if (command.type() == PuppetToCreatorCommand::Import3DSupport) {
const QVariantMap supportMap = qvariant_cast<QVariantMap>(command.data());
emitImport3DSupportChanged(supportMap);
} }
} }

View File

@@ -386,6 +386,10 @@ void AbstractView::updateActiveScene3D(const QVariantMap & /*sceneState*/)
{ {
} }
void AbstractView::updateImport3DSupport(const QVariantMap & /*supportMap*/)
{
}
void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, const QPixmap & /*pixmap*/) void AbstractView::modelNodePreviewPixmapChanged(const ModelNode & /*node*/, const QPixmap & /*pixmap*/)
{ {
} }
@@ -804,6 +808,12 @@ void AbstractView::emitModelNodelPreviewPixmapChanged(const ModelNode &node, con
model()->d->notifyModelNodePreviewPixmapChanged(node, pixmap); model()->d->notifyModelNodePreviewPixmapChanged(node, pixmap);
} }
void AbstractView::emitImport3DSupportChanged(const QVariantMap &supportMap)
{
if (model())
model()->d->notifyImport3DSupportChanged(supportMap);
}
void AbstractView::emitRewriterEndTransaction() void AbstractView::emitRewriterEndTransaction()
{ {
if (model()) if (model())

View File

@@ -575,6 +575,11 @@ void ModelPrivate::notifyModelNodePreviewPixmapChanged(const ModelNode &node, co
[&](AbstractView *view) { view->modelNodePreviewPixmapChanged(node, pixmap); }); [&](AbstractView *view) { view->modelNodePreviewPixmapChanged(node, pixmap); });
} }
void ModelPrivate::notifyImport3DSupportChanged(const QVariantMap &supportMap)
{
notifyInstanceChanges([&](AbstractView *view) { view->updateImport3DSupport(supportMap); });
}
void ModelPrivate::notifyRewriterBeginTransaction() void ModelPrivate::notifyRewriterBeginTransaction()
{ {
notifyNodeInstanceViewLast([&](AbstractView *view) { view->rewriterBeginTransaction(); }); notifyNodeInstanceViewLast([&](AbstractView *view) { view->rewriterBeginTransaction(); });

View File

@@ -176,6 +176,7 @@ public:
void notifyRenderImage3DChanged(const QImage &image); void notifyRenderImage3DChanged(const QImage &image);
void notifyUpdateActiveScene3D(const QVariantMap &sceneState); void notifyUpdateActiveScene3D(const QVariantMap &sceneState);
void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap); void notifyModelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap);
void notifyImport3DSupportChanged(const QVariantMap &supportMap);
void setDocumentMessages(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings); void setDocumentMessages(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings);

View File

@@ -137,6 +137,14 @@ extend_qtc_executable(qml2puppet
icongizmoimageprovider.cpp icongizmoimageprovider.h icongizmoimageprovider.cpp icongizmoimageprovider.h
) )
find_package(Qt5 5.15.0 COMPONENTS Quick3DAssetImport QUIET)
extend_qtc_executable(qml2puppet
CONDITION TARGET Qt5::Quick3DAssetImport
FEATURE_INFO "Qt Quick 3D asset import"
DEPENDS Qt5::Quick3DAssetImportPrivate
DEFINES IMPORT_QUICK3D_ASSETS
)
extend_qtc_executable(qml2puppet extend_qtc_executable(qml2puppet
CONDITION Qt5_VERSION VERSION_GREATER_EQUAL 6.0.0 CONDITION Qt5_VERSION VERSION_GREATER_EQUAL 6.0.0
@@ -151,6 +159,12 @@ extend_qtc_executable(qml2puppet
iconrenderer.cpp iconrenderer.h iconrenderer.cpp iconrenderer.h
) )
extend_qtc_executable(qml2puppet
SOURCES_PREFIX "${SRCDIR}/qml2puppet/import3d"
SOURCES
import3d.cpp import3d.h
)
extend_qtc_executable(qml2puppet extend_qtc_executable(qml2puppet
SOURCES_PREFIX "${SRCDIR}/qml2puppet/instances" SOURCES_PREFIX "${SRCDIR}/qml2puppet/instances"
SOURCES SOURCES

View File

@@ -243,6 +243,8 @@ QtcTool {
"editor3d/icongizmoimageprovider.h", "editor3d/icongizmoimageprovider.h",
"iconrenderer/iconrenderer.cpp", "iconrenderer/iconrenderer.cpp",
"iconrenderer/iconrenderer.h", "iconrenderer/iconrenderer.h",
"import3d/import3d.cpp",
"import3d/import3d.h",
"qml2puppetmain.cpp", "qml2puppetmain.cpp",
] ]