diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml index 0e3099361a9..449bf3e6905 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ItemDelegate.qml @@ -38,6 +38,7 @@ Item { width: ItemLibraryBackend.itemLibraryIconWidth // to be set in Qml context height: ItemLibraryBackend.itemLibraryIconHeight // to be set in Qml context source: itemLibraryIconPath // to be set by model + fillMode: Image.PreserveAspectFit // Icons generated for components can change if the component is edited, // so don't cache them locally at Image level. diff --git a/src/libs/qmlpuppetcommunication/commands/createscenecommand.h b/src/libs/qmlpuppetcommunication/commands/createscenecommand.h index f052da1eaaa..80456169db5 100644 --- a/src/libs/qmlpuppetcommunication/commands/createscenecommand.h +++ b/src/libs/qmlpuppetcommunication/commands/createscenecommand.h @@ -36,8 +36,6 @@ public: const QUrl &resourceUrl, const QHash &edit3dToolStates, const QString &language, - QSize captureImageMinimumSize, - QSize captureImageMaximumSize, qint32 stateInstanceId) : instances(instanceContainer) , reparentInstances(reparentContainer) @@ -51,8 +49,6 @@ public: , resourceUrl(resourceUrl) , edit3dToolStates(edit3dToolStates) , language(language) - , captureImageMinimumSize(captureImageMinimumSize) - , captureImageMaximumSize(captureImageMaximumSize) , stateInstanceId{stateInstanceId} {} @@ -71,8 +67,6 @@ public: out << command.edit3dToolStates; out << command.language; out << command.stateInstanceId; - out << command.captureImageMinimumSize; - out << command.captureImageMaximumSize; return out; } @@ -92,8 +86,6 @@ public: in >> command.edit3dToolStates; in >> command.language; in >> command.stateInstanceId; - in >> command.captureImageMinimumSize; - in >> command.captureImageMaximumSize; return in; } @@ -111,8 +103,6 @@ public: QUrl resourceUrl; QHash edit3dToolStates; QString language; - QSize captureImageMinimumSize; - QSize captureImageMaximumSize; qint32 stateInstanceId = 0; }; diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 5e5e7ca998d..0ba34894e2a 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -517,8 +517,6 @@ extend_qtc_plugin(QmlDesigner SOURCES imagecachecollector.cpp imagecachecollector.h - imagecacheconnectionmanager.cpp - imagecacheconnectionmanager.h imagecachefontcollector.cpp imagecachefontcollector.h meshimagecachecollector.cpp diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp index c3c8ed5e33a..db90d66a275 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.h index 87d97d65d43..a7c3a66fb4a 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.h @@ -12,7 +12,6 @@ #include #include #include -#include #include diff --git a/src/plugins/qmldesigner/imagecachecollectors/imagecachecollector.cpp b/src/plugins/qmldesigner/imagecachecollectors/imagecachecollector.cpp index ae275b85041..aff2b792f2f 100644 --- a/src/plugins/qmldesigner/imagecachecollectors/imagecachecollector.cpp +++ b/src/plugins/qmldesigner/imagecachecollectors/imagecachecollector.cpp @@ -2,50 +2,31 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "imagecachecollector.h" -#include "imagecacheconnectionmanager.h" -#include -#include -#include -#include -#include +#include +#include +#include #include #include #include +#include #include -#include +#include +#include namespace QmlDesigner { namespace { -QByteArray fileToByteArray(const QString &filename) -{ - QFile file(filename); - QFileInfo fleInfo(file); - - if (fleInfo.exists() && file.open(QFile::ReadOnly)) - return file.readAll(); - - return {}; -} - -QString fileToString(const QString &filename) -{ - return QString::fromUtf8(fileToByteArray(filename)); -} - } // namespace -ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connectionManager, - QSize captureImageMinimumSize, +ImageCacheCollector::ImageCacheCollector(QSize captureImageMinimumSize, QSize captureImageMaximumSize, ExternalDependenciesInterface &externalDependencies, ImageCacheCollectorNullImageHandling nullImageHandling) - : m_connectionManager{connectionManager} - , captureImageMinimumSize{captureImageMinimumSize} + : captureImageMinimumSize{captureImageMinimumSize} , captureImageMaximumSize{captureImageMaximumSize} , m_externalDependencies{externalDependencies} , nullImageHandling{nullImageHandling} @@ -65,108 +46,41 @@ QImage scaleImage(const QImage &image, QSize targetSize) QSize scaledImageSize = image.size().scaled(targetSize.boundedTo(image.size()), Qt::KeepAspectRatio); return image.scaled(scaledImageSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - } } // namespace void ImageCacheCollector::start(Utils::SmallStringView name, - Utils::SmallStringView state, + Utils::SmallStringView, const ImageCache::AuxiliaryData &auxiliaryData, CaptureCallback captureCallback, AbortCallback abortCallback, ImageCache::TraceToken traceToken) { -#ifdef QDS_USE_PROJECTSTORAGE - if (!m_projectStorage || !m_pathCache) - return; -#endif - using namespace NanotraceHR::Literals; auto [collectorTraceToken, flowtoken] = traceToken.beginDurationWithFlow( "generate image in standard collector"); - RewriterView rewriterView{m_externalDependencies, RewriterView::Amend}; - rewriterView.setPossibleImportsEnabled(false); - NodeInstanceView nodeInstanceView{m_connectionManager, m_externalDependencies}; - nodeInstanceView.setCaptureImageMinimumAndMaximumSize(captureImageMinimumSize, - captureImageMaximumSize); + QTemporaryDir outDir(QDir::tempPath() + "/qds_imagecache_XXXXXX"); + QString outFile = outDir.filePath("capture.png"); - const QString filePath{name}; -#ifdef QDS_USE_PROJECTSTORAGE - auto model = QmlDesigner::Model::create({*m_projectStorage, *m_pathCache}, - "Item", - {}, - QUrl::fromLocalFile(filePath)); -#else - auto model = QmlDesigner::Model::create("QtQuick/Item", 2, 1); - model->setFileUrl(QUrl::fromLocalFile(filePath)); -#endif - - auto textDocument = std::make_unique(fileToString(filePath)); - - auto modifier = std::make_unique(textDocument.get(), - QTextCursor{textDocument.get()}); - - rewriterView.setTextModifier(modifier.get()); - - model->setRewriterView(&rewriterView); - - auto rootModelNodeMetaInfo = rewriterView.rootModelNode().metaInfo(); - bool is3DRoot = rewriterView.errors().isEmpty() - && (rootModelNodeMetaInfo.isQtQuick3DNode() - || rootModelNodeMetaInfo.isQtQuick3DMaterial()); - - if (!rewriterView.errors().isEmpty() || (!rewriterView.rootModelNode().metaInfo().isGraphicalItem() - && !is3DRoot)) { + QImage captureImage; + if (runProcess(createArguments(name, outFile, auxiliaryData))) { + captureImage.load(outFile); + } else { if (abortCallback) abortCallback(ImageCache::AbortReason::Failed, std::move(flowtoken)); return; } - if (is3DRoot) { - if (auto libIcon = std::get_if(&auxiliaryData)) - rewriterView.rootModelNode().setAuxiliaryData(AuxiliaryDataType::NodeInstancePropertyOverwrite, - "isLibraryIcon", - libIcon->enable); - } - - ModelNode stateNode = rewriterView.modelNodeForId(QString{state}); - - if (stateNode.isValid()) - rewriterView.setCurrentStateNode(stateNode); - - QImage captureImage; - - auto callback = [&](const QImage &image) { captureImage = image; }; - - if (!m_target) - return; - - nodeInstanceView.setTarget(m_target.data()); - m_connectionManager.setCallback(std::move(callback)); - bool isCrashed = false; - nodeInstanceView.setCrashCallback([&] { isCrashed = true; }); - model->setNodeInstanceView(&nodeInstanceView); - - bool capturedDataArrived = m_connectionManager.waitForCapturedData(); - - m_connectionManager.setCallback({}); - m_connectionManager.setCrashCallback({}); - - model->setNodeInstanceView({}); - model->setRewriterView({}); - - if (isCrashed) - abortCallback(ImageCache::AbortReason::Failed, std::move(flowtoken)); - - if (!capturedDataArrived && abortCallback) - abortCallback(ImageCache::AbortReason::Failed, std::move(flowtoken)); - if (nullImageHandling == ImageCacheCollectorNullImageHandling::CaptureNullImage || !captureImage.isNull()) { QImage midSizeImage = scaleImage(captureImage, QSize{300, 300}); QImage smallImage = scaleImage(midSizeImage, QSize{96, 96}); captureCallback(captureImage, midSizeImage, smallImage, std::move(flowtoken)); + } else { + if (abortCallback) + abortCallback(ImageCache::AbortReason::Failed, std::move(flowtoken)); + return; } } @@ -193,4 +107,72 @@ ProjectExplorer::Target *ImageCacheCollector::target() const return m_target; } +QStringList ImageCacheCollector::createArguments(Utils::SmallStringView name, + const QString &outFile, + const ImageCache::AuxiliaryData &auxiliaryData) const +{ + QStringList arguments; + const QString filePath{name}; + + arguments.append("--qml-renderer"); + arguments.append(filePath); + + if (m_target && m_target->project()) { + arguments.append("-i"); + arguments.append(m_target->project()->projectDirectory().toFSPathString()); + } + + arguments.append("-o"); + arguments.append(outFile); + + if (std::holds_alternative(auxiliaryData)) + arguments.append("--libIcon"); + + if (captureImageMinimumSize.isValid()) { + arguments.append("--minW"); + arguments.append(QString::number(captureImageMinimumSize.width())); + arguments.append("--minH"); + arguments.append(QString::number(captureImageMinimumSize.height())); + } + + if (captureImageMaximumSize.isValid()) { + arguments.append("--maxW"); + arguments.append(QString::number(captureImageMaximumSize.width())); + arguments.append("--maxH"); + arguments.append(QString::number(captureImageMaximumSize.height())); + } + + return arguments; +} + +bool ImageCacheCollector::runProcess(const QStringList &arguments) const +{ + if (!m_target) + return false; + + auto [workingDirectoryPath, puppetPath] = QmlDesigner::QmlPuppetPaths::qmlPuppetPaths( + target(), m_externalDependencies.designerSettings()); + if (puppetPath.isEmpty()) + return false; + + QProcessUniquePointer puppetProcess{new QProcess}; + + QObject::connect(QCoreApplication::instance(), + &QCoreApplication::aboutToQuit, + puppetProcess.get(), + &QProcess::kill); + + puppetProcess->setWorkingDirectory(workingDirectoryPath.toFSPathString()); + puppetProcess->setProcessChannelMode(QProcess::ForwardedChannels); + + puppetProcess->start(puppetPath.toFSPathString(), arguments); + + if (puppetProcess->waitForFinished(30000)) { + return puppetProcess->exitStatus() == QProcess::ExitStatus::NormalExit + && puppetProcess->exitCode() == 0; + } + + return false; +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/imagecachecollectors/imagecachecollector.h b/src/plugins/qmldesigner/imagecachecollectors/imagecachecollector.h index e6250393b2a..47ab9e8ab2e 100644 --- a/src/plugins/qmldesigner/imagecachecollectors/imagecachecollector.h +++ b/src/plugins/qmldesigner/imagecachecollectors/imagecachecollector.h @@ -5,25 +5,14 @@ #include -#include - #include -QT_BEGIN_NAMESPACE -class QTextDocument; -QT_END_NAMESPACE - namespace ProjectExplorer { class Target; } namespace QmlDesigner { -class Model; -class NotIndentingTextEditModifier; -class ImageCacheConnectionManager; -class RewriterView; -class NodeInstanceView; class ExternalDependenciesInterface; enum class ImageCacheCollectorNullImageHandling { CaptureNullImage, DontCaptureNullImage }; @@ -31,8 +20,7 @@ enum class ImageCacheCollectorNullImageHandling { CaptureNullImage, DontCaptureN class ImageCacheCollector final : public ImageCacheCollectorInterface { public: - ImageCacheCollector(ImageCacheConnectionManager &connectionManager, - QSize captureImageMinimumSize, + ImageCacheCollector(QSize captureImageMinimumSize, QSize captureImageMaximumSize, ExternalDependenciesInterface &externalDependencies, ImageCacheCollectorNullImageHandling nullImageHandling = {}); @@ -58,16 +46,17 @@ public: ProjectExplorer::Target *target() const; private: - ImageCacheConnectionManager &m_connectionManager; + bool runProcess(const QStringList &arguments) const; + QStringList createArguments(Utils::SmallStringView name, + const QString &outFile, + const ImageCache::AuxiliaryData &auxiliaryData) const; + +private: QPointer m_target; QSize captureImageMinimumSize; QSize captureImageMaximumSize; ExternalDependenciesInterface &m_externalDependencies; ImageCacheCollectorNullImageHandling nullImageHandling{}; -#ifdef QDS_USE_PROJECTSTORAGE - ProjectStorageType *m_projectStorage = nullptr; - PathCacheType *m_pathCache = nullptr; -#endif }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/imagecachecollectors/imagecacheconnectionmanager.cpp b/src/plugins/qmldesigner/imagecachecollectors/imagecacheconnectionmanager.cpp deleted file mode 100644 index f8a41b620bb..00000000000 --- a/src/plugins/qmldesigner/imagecachecollectors/imagecacheconnectionmanager.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "imagecacheconnectionmanager.h" - -#include - -#include - -namespace QmlDesigner { - -ImageCacheConnectionManager::ImageCacheConnectionManager() -{ - connections().emplace_back("Capture icon", "captureiconmode"); -} - -void ImageCacheConnectionManager::setCallback(ImageCacheConnectionManager::Callback callback) -{ - m_captureCallback = std::move(callback); -} - -bool ImageCacheConnectionManager::waitForCapturedData() -{ - if (connections().empty()) - return false; - - disconnect(connections().front().socket.get(), &QIODevice::readyRead, nullptr, nullptr); - - while (!m_capturedDataArrived) { - if (!(connections().front().socket)) - return false; - bool dataArrived = connections().front().socket->waitForReadyRead(10000); - - if (!dataArrived) - return false; - - readDataStream(connections().front()); - } - - m_capturedDataArrived = false; - - return true; -} - -void ImageCacheConnectionManager::dispatchCommand(const QVariant &command, - ConnectionManagerInterface::Connection &) -{ - static const int capturedDataCommandType = QMetaType::fromName("CapturedDataCommand").id(); - - if (command.typeId() == capturedDataCommandType) { - m_captureCallback(command.value().image); - m_capturedDataArrived = true; - } -} - -} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/imagecachecollectors/imagecacheconnectionmanager.h b/src/plugins/qmldesigner/imagecachecollectors/imagecacheconnectionmanager.h deleted file mode 100644 index 0a881665293..00000000000 --- a/src/plugins/qmldesigner/imagecachecollectors/imagecacheconnectionmanager.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace QmlDesigner { - -class CapturedDataCommand; - -class ImageCacheConnectionManager : public ConnectionManager -{ -public: - using Callback = std::function; - - ImageCacheConnectionManager(); - - void setCallback(Callback captureCallback); - - bool waitForCapturedData(); - -protected: - void dispatchCommand(const QVariant &command, Connection &connection) override; - -private: - Callback m_captureCallback; - bool m_capturedDataArrived = false; -}; - -} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/imagecachecollectors/meshimagecachecollector.cpp b/src/plugins/qmldesigner/imagecachecollectors/meshimagecachecollector.cpp index 0e0547c1935..690780a24ec 100644 --- a/src/plugins/qmldesigner/imagecachecollectors/meshimagecachecollector.cpp +++ b/src/plugins/qmldesigner/imagecachecollectors/meshimagecachecollector.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "meshimagecachecollector.h" -#include "imagecacheconnectionmanager.h" #include #include @@ -12,13 +11,11 @@ namespace QmlDesigner { -MeshImageCacheCollector::MeshImageCacheCollector(ImageCacheConnectionManager &connectionManager, - QSize captureImageMinimumSize, +MeshImageCacheCollector::MeshImageCacheCollector(QSize captureImageMinimumSize, QSize captureImageMaximumSize, ExternalDependenciesInterface &externalDependencies, ImageCacheCollectorNullImageHandling nullImageHandling) - : m_imageCacheCollector(connectionManager, - captureImageMinimumSize, + : m_imageCacheCollector(captureImageMinimumSize, captureImageMaximumSize, externalDependencies, nullImageHandling) diff --git a/src/plugins/qmldesigner/imagecachecollectors/meshimagecachecollector.h b/src/plugins/qmldesigner/imagecachecollectors/meshimagecachecollector.h index 9836e625e76..5272c317097 100644 --- a/src/plugins/qmldesigner/imagecachecollectors/meshimagecachecollector.h +++ b/src/plugins/qmldesigner/imagecachecollectors/meshimagecachecollector.h @@ -11,13 +11,10 @@ class Target; namespace QmlDesigner { -class ImageCacheConnectionManager; - class MeshImageCacheCollector final : public ImageCacheCollectorInterface { public: - MeshImageCacheCollector(ImageCacheConnectionManager &connectionManager, - QSize captureImageMinimumSize, + MeshImageCacheCollector(QSize captureImageMinimumSize, QSize captureImageMaximumSize, ExternalDependenciesInterface &externalDependencies, ImageCacheCollectorNullImageHandling nullImageHandling = {}); diff --git a/src/plugins/qmldesigner/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/instances/nodeinstanceview.cpp index f0af9d8e8e1..839e04be368 100644 --- a/src/plugins/qmldesigner/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/instances/nodeinstanceview.cpp @@ -1272,8 +1272,6 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand() m_externalDependencies.currentResourcePath(), sceneStates, lastUsedLanguage, - m_captureImageMinimumSize, - m_captureImageMaximumSize, stateInstanceId); } diff --git a/src/plugins/qmldesigner/instances/nodeinstanceview.h b/src/plugins/qmldesigner/instances/nodeinstanceview.h index 798d0c554b2..7a5ea908d94 100644 --- a/src/plugins/qmldesigner/instances/nodeinstanceview.h +++ b/src/plugins/qmldesigner/instances/nodeinstanceview.h @@ -156,13 +156,6 @@ public: m_crashCallback = std::move(crashCallback); } - void setCaptureImageMinimumAndMaximumSize(QSize captureImageMinimumSize, - QSize captureImageMaximumSize) - { - m_captureImageMinimumSize = captureImageMinimumSize; - m_captureImageMaximumSize = captureImageMaximumSize; - } - void startNanotrace(); void endNanotrace(); @@ -313,8 +306,6 @@ private: QHash m_qsbPathToFilterMap; int m_remainingQsbTargets = 0; QTimer m_rotBlockTimer; - QSize m_captureImageMinimumSize{150, 150}; - QSize m_captureImageMaximumSize{1000, 1000}; bool m_qsbEnabled = false; }; diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp index 5718ac7ae21..873b604833f 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include #include @@ -124,8 +123,8 @@ class QmlDesignerProjectManager::ImageCacheData { public: ImageCacheData(ExternalDependenciesInterface &externalDependencies) - : meshImageCollector{connectionManager, QSize{300, 300}, QSize{600, 600}, externalDependencies} - , nodeInstanceCollector{connectionManager, QSize{300, 300}, QSize{600, 600}, externalDependencies} + : meshImageCollector{QSize{300, 300}, QSize{600, 600}, externalDependencies} + , nodeInstanceCollector{QSize{300, 300}, QSize{600, 600}, externalDependencies} {} public: @@ -134,7 +133,6 @@ public: Sqlite::JournalMode::Wal, Sqlite::LockingMode::Normal}; ImageCacheStorage storage{database}; - ImageCacheConnectionManager connectionManager; MeshImageCacheCollector meshImageCollector; TextureImageCacheCollector textureImageCollector; ImageCacheCollector nodeInstanceCollector; @@ -153,8 +151,7 @@ class QmlDesignerProjectManager::PreviewImageCacheData { public: PreviewImageCacheData(ExternalDependenciesInterface &externalDependencies) - : collector{connectionManager, - QSize{300, 300}, + : collector{QSize{300, 300}, QSize{1000, 1000}, externalDependencies, ImageCacheCollectorNullImageHandling::CaptureNullImage} @@ -168,7 +165,6 @@ public: Sqlite::JournalMode::Wal, Sqlite::LockingMode::Normal}; ImageCacheStorage storage{database}; - ImageCacheConnectionManager connectionManager; ImageCacheCollector collector; PreviewTimeStampProvider timeStampProvider; AsynchronousExplicitImageCache cache{storage}; @@ -255,8 +251,7 @@ public: ::ProjectExplorer::Project *project, PathCacheType &pathCache, ExternalDependenciesInterface &externalDependencies) - : collector{connectionManager, - QSize{300, 300}, + : collector{QSize{300, 300}, QSize{1000, 1000}, externalDependencies, ImageCacheCollectorNullImageHandling::CaptureNullImage} @@ -264,7 +259,6 @@ public: , projectStorageData{createProjectStorageData(project, pathCache)} {} - ImageCacheConnectionManager connectionManager; ImageCacheCollector collector; PreviewTimeStampProvider timeStampProvider; AsynchronousImageFactory factory; diff --git a/src/tools/qmlpuppet/CMakeLists.txt b/src/tools/qmlpuppet/CMakeLists.txt index 9f20bbe3d9e..2c0ff6a1f50 100644 --- a/src/tools/qmlpuppet/CMakeLists.txt +++ b/src/tools/qmlpuppet/CMakeLists.txt @@ -168,7 +168,6 @@ extend_qtc_executable(qmlpuppet qt5capturepreviewnodeinstanceserver.cpp qt5capturepreviewnodeinstanceserver.h nodeinstanceserverdispatcher.cpp nodeinstanceserverdispatcher.h capturenodeinstanceserverdispatcher.cpp capturenodeinstanceserverdispatcher.h - qt5captureimagenodeinstanceserver.cpp qt5captureimagenodeinstanceserver.h viewconfig.cpp viewconfig.h animationdriver.cpp animationdriver.h ) diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/instances.pri b/src/tools/qmlpuppet/qmlpuppet/instances/instances.pri index 505dd748e49..9f1ce87e347 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/instances.pri +++ b/src/tools/qmlpuppet/qmlpuppet/instances/instances.pri @@ -22,7 +22,6 @@ versionAtLeast(QT_VERSION, 5.15.0) { HEADERS += $$PWD/qt5nodeinstanceserver.h \ $$PWD/capturenodeinstanceserverdispatcher.h \ $$PWD/nodeinstanceserverdispatcher.h \ - $$PWD/qt5captureimagenodeinstanceserver.h \ $$PWD/qt5capturepreviewnodeinstanceserver.h \ $$PWD/qt5testnodeinstanceserver.h \ $$PWD/qt5bakelightsnodeinstanceserver.h \ @@ -58,7 +57,6 @@ HEADERS += $$PWD/qt5nodeinstanceserver.h \ SOURCES += $$PWD/qt5nodeinstanceserver.cpp \ $$PWD/capturenodeinstanceserverdispatcher.cpp \ $$PWD/nodeinstanceserverdispatcher.cpp \ - $$PWD/qt5captureimagenodeinstanceserver.cpp \ $$PWD/qt5capturepreviewnodeinstanceserver.cpp \ $$PWD/qt5testnodeinstanceserver.cpp \ $$PWD/qt5bakelightsnodeinstanceserver.cpp \ diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserverdispatcher.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserverdispatcher.cpp index 9e3cdac151e..c7f1f053fe6 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserverdispatcher.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserverdispatcher.cpp @@ -4,7 +4,6 @@ #include "nodeinstanceserverdispatcher.h" #include "qt5bakelightsnodeinstanceserver.h" -#include "qt5captureimagenodeinstanceserver.h" #include "qt5capturepreviewnodeinstanceserver.h" #include "qt5import3dnodeinstanceserver.h" #include "qt5informationnodeinstanceserver.h" @@ -164,8 +163,6 @@ std::unique_ptr createNodeInstanceServer( { if (serverName == "capturemode") return std::make_unique(nodeInstanceClient); - else if (serverName == "captureiconmode") - return std::make_unique(nodeInstanceClient); else if (serverName == "rendermode") return std::make_unique(nodeInstanceClient); else if (serverName == "editormode") diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/qt5captureimagenodeinstanceserver.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/qt5captureimagenodeinstanceserver.cpp deleted file mode 100644 index 70625962cc8..00000000000 --- a/src/tools/qmlpuppet/qmlpuppet/instances/qt5captureimagenodeinstanceserver.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "qt5captureimagenodeinstanceserver.h" -#include "servernodeinstance.h" - -#include -#include -#include - -#include -#include -#include - -#include - -namespace QmlDesigner { - -namespace { - -QImage renderImage(ServerNodeInstance rootNodeInstance, QSize minimumSize, QSize maximumSize) -{ - rootNodeInstance.updateDirtyNodeRecursive(); - - QSize previewImageSize = rootNodeInstance.boundingRect().size().toSize(); - if (previewImageSize.isEmpty()) { - previewImageSize = minimumSize; - } else if (previewImageSize.width() < minimumSize.width() - || previewImageSize.height() < minimumSize.height()) { - previewImageSize.scale(minimumSize, Qt::KeepAspectRatio); - } - - if (previewImageSize.width() > maximumSize.width() - || previewImageSize.height() > maximumSize.height()) { - previewImageSize.scale(maximumSize, Qt::KeepAspectRatio); - } - - QImage previewImage = rootNodeInstance.renderPreviewImage(previewImageSize); - - return previewImage; -} -} // namespace - -void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands() -{ - static bool inFunction = false; - - if (!rootNodeInstance().holdsGraphical()) { - nodeInstanceClient()->capturedData(CapturedDataCommand{}); - return; - } - - if (!inFunction) { - inFunction = true; - - auto rooNodeInstance = rootNodeInstance(); - if (QQuickItem *qitem = rooNodeInstance.rootQuickItem()) - qitem->setClip(true); - - QQuickDesignerSupport::polishItems(quickWindow()); - - QImage image = renderImage(rooNodeInstance, m_minimumSize, m_maximumSize); - - nodeInstanceClient()->capturedData(CapturedDataCommand{std::move(image)}); - - slowDownRenderTimer(); - inFunction = false; - } -} - -void QmlDesigner::Qt5CaptureImageNodeInstanceServer::createScene(const CreateSceneCommand &command) -{ - m_minimumSize = command.captureImageMinimumSize; - m_maximumSize = command.captureImageMaximumSize; - - Qt5PreviewNodeInstanceServer::createScene(command); -} - -} // namespace diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/qt5captureimagenodeinstanceserver.h b/src/tools/qmlpuppet/qmlpuppet/instances/qt5captureimagenodeinstanceserver.h deleted file mode 100644 index f4a7c32a0c9..00000000000 --- a/src/tools/qmlpuppet/qmlpuppet/instances/qt5captureimagenodeinstanceserver.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -namespace QmlDesigner { - -class Qt5CaptureImageNodeInstanceServer : public Qt5PreviewNodeInstanceServer -{ -public: - explicit Qt5CaptureImageNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) - : Qt5PreviewNodeInstanceServer(nodeInstanceClient) - {} - - void createScene(const CreateSceneCommand &command) override; - -protected: - void collectItemChangesAndSendChangeCommands() override; - -private: - QSize m_minimumSize; - QSize m_maximumSize; -}; - -} // namespace QmlDesigner diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/qt5nodeinstanceclientproxy.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/qt5nodeinstanceclientproxy.cpp index c11899e0ec9..ee58004af82 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/qt5nodeinstanceclientproxy.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/qt5nodeinstanceclientproxy.cpp @@ -7,7 +7,6 @@ #include "capturenodeinstanceserverdispatcher.h" #include "qt5bakelightsnodeinstanceserver.h" -#include "qt5captureimagenodeinstanceserver.h" #include "qt5capturepreviewnodeinstanceserver.h" #include "qt5informationnodeinstanceserver.h" #include "qt5import3dnodeinstanceserver.h" @@ -65,9 +64,6 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) : } else if (QCoreApplication::arguments().at(2) == QLatin1String("capturemode")) { setNodeInstanceServer(std::make_unique(this)); initializeSocket(); - } else if (QCoreApplication::arguments().at(2) == QLatin1String("captureiconmode")) { - setNodeInstanceServer(std::make_unique(this)); - initializeSocket(); } else if (QCoreApplication::arguments().at(2) == QLatin1String("bakelightsmode")) { setNodeInstanceServer(std::make_unique(this)); initializeSocket(); diff --git a/src/tools/qmlpuppet/qmlpuppet/renderer/qmlrenderer.cpp b/src/tools/qmlpuppet/qmlpuppet/renderer/qmlrenderer.cpp index 2fd9487276a..3b8cff54c15 100644 --- a/src/tools/qmlpuppet/qmlpuppet/renderer/qmlrenderer.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/renderer/qmlrenderer.cpp @@ -16,6 +16,9 @@ #include #include +constexpr int DEFAULT_RENDER_DIM = 300; +constexpr int DEFAULT_MAX_DIM = 1024; + void QmlRenderer::initCoreApp() { #if defined QT_WIDGETS_LIB @@ -36,15 +39,29 @@ void QmlRenderer::populateParser() "Output image file path.", "path"}, - // "h" is reserved arg for help, so use capital letters for height/width - {QStringList{"H", "height"}, - "Height of the final rendered image.", + // The qml component is rendered at its preferred size if available + // Min/max dimensions specify a range of acceptable final scaled sizes + // If the size of rendered item is outside the min/max range, it is cropped in final scaling + {QStringList{"minW"}, + "Minimum width of the final scaled rendered image.", "pixels"}, - {QStringList{"W", "width"}, - "Width of the final rendered image.", + {QStringList{"minH"}, + "Minimum height of the final scaled rendered image.", "pixels"}, + {QStringList{"maxW"}, + QString("Maximum width of the final scaled rendered image."), + "pixels"}, + + {QStringList{"maxH"}, + "Maximum height of the final scaled rendered image.", + "pixels"}, + + {QStringList{"libIcon"}, + "Render library icon rather than regular preview." + "It zooms 3D objects bit more aggressively and suppresses the background."}, + {QStringList{"v", "verbose"}, "Display additional output."} }); @@ -56,10 +73,14 @@ void QmlRenderer::initQmlRunner() { if (m_argParser.isSet("importpath")) m_importPaths = m_argParser.value("importpath").split(";"); - if (m_argParser.isSet("width")) - m_requestedSize.setWidth(m_argParser.value("width").toInt()); - if (m_argParser.isSet("height")) - m_requestedSize.setHeight(m_argParser.value("height").toInt()); + if (m_argParser.isSet("minW")) + m_reqMinSize.setWidth(m_argParser.value("minW").toInt()); + if (m_argParser.isSet("minH")) + m_reqMinSize.setHeight(m_argParser.value("minH").toInt()); + if (m_argParser.isSet("maxW")) + m_reqMaxSize.setWidth(m_argParser.value("maxW").toInt()); + if (m_argParser.isSet("maxH")) + m_reqMaxSize.setHeight(m_argParser.value("maxH").toInt()); if (m_argParser.isSet("verbose")) m_verbose = true; @@ -76,17 +97,18 @@ void QmlRenderer::initQmlRunner() else m_outFile = m_sourceFile + ".png"; - if (m_requestedSize.width() <= 0) - m_requestedSize.setWidth(150); - if (m_requestedSize.height() <= 0) - m_requestedSize.setHeight(150); + if (m_argParser.isSet("libIcon")) + m_isLibIcon = true; if (m_verbose) { - info(QString("Import path = %1").arg(m_importPaths.join(";"))); - info(QString("Requested size = %1 x %2").arg(m_requestedSize.width()) - .arg(m_requestedSize.height())); - info(QString("Source file = %1").arg(m_sourceFile)); - info(QString("Output file = %1").arg(m_outFile)); + info(QString("Import path = %1").arg(m_importPaths.join(";"))); + info(QString("Requested min size = %1 x %2").arg(m_reqMinSize.width()) + .arg(m_reqMinSize.height())); + info(QString("Requested max size = %1 x %2").arg(m_reqMaxSize.width()) + .arg(m_reqMaxSize.height())); + info(QString("Source file = %1").arg(m_sourceFile)); + info(QString("Output file = %1").arg(m_outFile)); + info(QString("Is library icon = %1").arg(m_isLibIcon ? QString("true") : QString("false"))); } if (setupRenderer()) { @@ -140,6 +162,9 @@ bool QmlRenderer::setupRenderer() } m_containerItem->setParentItem(m_window->contentItem()); + if (m_isLibIcon) + QMetaObject::invokeMethod(m_containerItem, "setIconMode", Q_ARG(QVariant, true)); + contentItem3D = QQmlProperty::read(m_containerItem, "contentItem").value(); if (qobject_cast(renderObj)) { QMetaObject::invokeMethod( @@ -155,28 +180,25 @@ bool QmlRenderer::setupRenderer() } m_is3D = true; - m_renderSize = m_requestedSize; - contentItem3D->setSize(m_requestedSize); + setRenderSize({}); + contentItem3D->setSize(m_renderSize); } else #endif // QUICK3D_MODULE if (auto renderItem = qobject_cast(renderObj)) { - m_renderSize = renderItem->size().toSize(); - if (m_renderSize.width() <= 0) - m_renderSize.setWidth(m_requestedSize.width()); - if (m_renderSize.height() <= 0) - m_renderSize.setHeight(m_requestedSize.height()); + setRenderSize(renderItem->size().toSize()); renderItem->setSize(m_renderSize); renderItem->setParentItem(m_window->contentItem()); // When rendering 2D scenes, we just render the given QML without extra container m_containerItem = renderItem; } else if (auto renderWindow = qobject_cast(renderObj)) { // Hack to render Window items: reparent window content to m_window->contentItem() - m_renderSize = renderWindow->size(); + setRenderSize(renderWindow->size()); m_containerItem = m_window->contentItem(); // Suppress the original window. // Offscreen position ensures we don't get even brief flash of it. - renderWindow->setPosition(-100000, -100000); renderWindow->setVisible(false); + renderWindow->resize(2, 2); + renderWindow->setPosition(-10000, -10000); const QList childItems = renderWindow->contentItem()->childItems(); for (QQuickItem *item : childItems) { item->setParent(m_window->contentItem()); @@ -274,12 +296,32 @@ void QmlRenderer::render() QImage wrapperImage(reinterpret_cast(readResult.data.constData()), readResult.pixelSize.width(), readResult.pixelSize.height(), QImage::Format_RGBA8888_Premultiplied); - if (m_rhi->isYUpInFramebuffer()) - renderImage = wrapperImage.mirrored().scaled(m_requestedSize, Qt::IgnoreAspectRatio, + + QSize maxSize = m_reqMaxSize; + if (maxSize.width() <= 0) { + m_reqMinSize.width() > DEFAULT_MAX_DIM ? maxSize.setWidth(m_reqMinSize.width()) + : maxSize.setWidth(DEFAULT_MAX_DIM); + } + if (maxSize.height() <= 0) { + m_reqMinSize.height() > DEFAULT_MAX_DIM ? maxSize.setHeight(m_reqMinSize.height()) + : maxSize.setHeight(DEFAULT_MAX_DIM); + } + + QSize scaledSize = m_renderSize.scaled(m_renderSize.expandedTo(m_reqMinSize).boundedTo(maxSize), + Qt::KeepAspectRatio); + + info(QString("Rendered size = %1 x %2").arg(m_renderSize.width()) + .arg(m_renderSize.height())); + info(QString("Scaled size = %1 x %2").arg(scaledSize.width()) + .arg(scaledSize.height())); + + if (m_rhi->isYUpInFramebuffer()) { + renderImage = wrapperImage.mirrored().scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - else - renderImage = wrapperImage.copy().scaled(m_requestedSize, Qt::IgnoreAspectRatio, + } else { + renderImage = wrapperImage.copy().scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + } }; QRhiResourceUpdateBatch *readbackBatch = m_rhi->nextResourceUpdateBatch(); readbackBatch->readBackTexture(m_texture.get(), &readResult); @@ -316,3 +358,16 @@ void QmlRenderer::asyncQuit(int errorCode) exit(errorCode); }); } + +void QmlRenderer::setRenderSize(QSize size) +{ + m_renderSize = size; + if (m_renderSize.width() <= 0) { + m_reqMaxSize.width() > 0 ? m_renderSize.setWidth(m_reqMaxSize.width()) + : m_renderSize.setWidth(DEFAULT_RENDER_DIM); + } + if (m_renderSize.height() <= 0) { + m_reqMaxSize.height() > 0 ? m_renderSize.setHeight(m_reqMaxSize.height()) + : m_renderSize.setHeight(DEFAULT_RENDER_DIM); + } +} diff --git a/src/tools/qmlpuppet/qmlpuppet/renderer/qmlrenderer.h b/src/tools/qmlpuppet/qmlpuppet/renderer/qmlrenderer.h index 212f57074d3..9e5b2c99e23 100644 --- a/src/tools/qmlpuppet/qmlpuppet/renderer/qmlrenderer.h +++ b/src/tools/qmlpuppet/qmlpuppet/renderer/qmlrenderer.h @@ -34,14 +34,18 @@ private: void error(const QString &msg); void asyncQuit(int errorCode); + void setRenderSize(QSize size); + QStringList m_importPaths; - QSize m_requestedSize; + QSize m_reqMinSize; + QSize m_reqMaxSize; QSize m_renderSize; QString m_sourceFile; QString m_outFile; bool m_verbose = false; bool m_is3D = false; bool m_fit3D = false; + bool m_isLibIcon = false; QQuickItem *m_containerItem = nullptr; QRhi *m_rhi = nullptr;