QmlDesigner: Fix poor snapshot quality

It removes the image cache in the AssetsLibraryView too because it is not
used. Fix ODR violation too.

Fixes: QDS-6553
Change-Id: I83d8f8b7cd385e2c8352986e4b5a5abd76ac7d5b
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Marco Bubke
2022-04-11 17:20:37 +02:00
parent 63aaa65439
commit 4bd71ebf6a
16 changed files with 99 additions and 93 deletions

View File

@@ -25,9 +25,10 @@
#pragma once #pragma once
#include <qmetatype.h> #include <QSize>
#include <QUrl> #include <QUrl>
#include <QVector> #include <QVector>
#include <qmetatype.h>
#include "instancecontainer.h" #include "instancecontainer.h"
#include "reparentcontainer.h" #include "reparentcontainer.h"
@@ -55,6 +56,8 @@ public:
const QUrl &resourceUrl, const QUrl &resourceUrl,
const QHash<QString, QVariantMap> &edit3dToolStates, const QHash<QString, QVariantMap> &edit3dToolStates,
const QString &language, const QString &language,
QSize captureImageMinimumSize,
QSize captureImageMaximumSize,
qint32 stateInstanceId) qint32 stateInstanceId)
: instances(instanceContainer) : instances(instanceContainer)
, reparentInstances(reparentContainer) , reparentInstances(reparentContainer)
@@ -68,6 +71,8 @@ public:
, resourceUrl(resourceUrl) , resourceUrl(resourceUrl)
, edit3dToolStates(edit3dToolStates) , edit3dToolStates(edit3dToolStates)
, language(language) , language(language)
, captureImageMinimumSize(captureImageMinimumSize)
, captureImageMaximumSize(captureImageMaximumSize)
, stateInstanceId{stateInstanceId} , stateInstanceId{stateInstanceId}
{} {}
@@ -86,6 +91,8 @@ public:
out << command.edit3dToolStates; out << command.edit3dToolStates;
out << command.language; out << command.language;
out << command.stateInstanceId; out << command.stateInstanceId;
out << command.captureImageMinimumSize;
out << command.captureImageMaximumSize;
return out; return out;
} }
@@ -105,6 +112,8 @@ public:
in >> command.edit3dToolStates; in >> command.edit3dToolStates;
in >> command.language; in >> command.language;
in >> command.stateInstanceId; in >> command.stateInstanceId;
in >> command.captureImageMinimumSize;
in >> command.captureImageMaximumSize;
return in; return in;
} }
@@ -122,6 +131,8 @@ public:
QUrl resourceUrl; QUrl resourceUrl;
QHash<QString, QVariantMap> edit3dToolStates; QHash<QString, QVariantMap> edit3dToolStates;
QString language; QString language;
QSize captureImageMinimumSize;
QSize captureImageMaximumSize;
qint32 stateInstanceId = 0; qint32 stateInstanceId = 0;
}; };

View File

@@ -38,16 +38,22 @@ namespace QmlDesigner {
namespace { namespace {
QImage renderImage(ServerNodeInstance rootNodeInstance) QImage renderImage(ServerNodeInstance rootNodeInstance, QSize minimumSize, QSize maximumSize)
{ {
rootNodeInstance.updateDirtyNodeRecursive(); rootNodeInstance.updateDirtyNodeRecursive();
QSize previewImageSize = rootNodeInstance.boundingRect().size().toSize(); QSize previewImageSize = rootNodeInstance.boundingRect().size().toSize();
if (previewImageSize.isEmpty()) if (previewImageSize.isEmpty()) {
previewImageSize = {150, 150}; previewImageSize = minimumSize;
} else if (previewImageSize.width() < minimumSize.width()
|| previewImageSize.height() < minimumSize.height()) {
previewImageSize.scale(minimumSize, Qt::KeepAspectRatio);
}
if (previewImageSize.width() > 150 || previewImageSize.height() > 150) if (previewImageSize.width() > maximumSize.width()
previewImageSize.scale({150, 150}, Qt::KeepAspectRatio); || previewImageSize.height() > maximumSize.height()) {
previewImageSize.scale(maximumSize, Qt::KeepAspectRatio);
}
QImage previewImage = rootNodeInstance.renderPreviewImage(previewImageSize); QImage previewImage = rootNodeInstance.renderPreviewImage(previewImageSize);
@@ -73,7 +79,7 @@ void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands(
DesignerSupport::polishItems(quickWindow()); DesignerSupport::polishItems(quickWindow());
QImage image = renderImage(rooNodeInstance); QImage image = renderImage(rooNodeInstance, m_minimumSize, m_maximumSize);
nodeInstanceClient()->capturedData(CapturedDataCommand{std::move(image)}); nodeInstanceClient()->capturedData(CapturedDataCommand{std::move(image)});
@@ -82,4 +88,12 @@ void Qt5CaptureImageNodeInstanceServer::collectItemChangesAndSendChangeCommands(
} }
} }
void QmlDesigner::Qt5CaptureImageNodeInstanceServer::createScene(const CreateSceneCommand &command)
{
m_minimumSize = command.captureImageMinimumSize;
m_maximumSize = command.captureImageMaximumSize;
Qt5PreviewNodeInstanceServer::createScene(command);
}
} // namespace } // namespace

View File

@@ -36,10 +36,14 @@ public:
: Qt5PreviewNodeInstanceServer(nodeInstanceClient) : Qt5PreviewNodeInstanceServer(nodeInstanceClient)
{} {}
void createScene(const CreateSceneCommand &command) override;
protected: protected:
void collectItemChangesAndSendChangeCommands() override; void collectItemChangesAndSendChangeCommands() override;
private: private:
QSize m_minimumSize;
QSize m_maximumSize;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -50,31 +50,17 @@
namespace QmlDesigner { namespace QmlDesigner {
namespace { class AssetsLibraryView::ImageCacheData
ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project)
{
if (project)
return project->activeTarget();
return {};
}
} // namespace
class ImageCacheData
{ {
public: public:
Sqlite::Database database{Utils::PathString{ Sqlite::Database database{Utils::PathString{
Core::ICore::cacheResourcePath("imagecache-v2.db").toString()}, Core::ICore::cacheResourcePath("fontimagecache.db").toString()},
Sqlite::JournalMode::Wal, Sqlite::JournalMode::Wal,
Sqlite::LockingMode::Normal}; Sqlite::LockingMode::Normal};
ImageCacheStorage<Sqlite::Database> storage{database}; ImageCacheStorage<Sqlite::Database> storage{database};
ImageCacheConnectionManager connectionManager;
ImageCacheCollector collector{connectionManager};
ImageCacheFontCollector fontCollector; ImageCacheFontCollector fontCollector;
ImageCacheGenerator generator{collector, storage};
ImageCacheGenerator fontGenerator{fontCollector, storage}; ImageCacheGenerator fontGenerator{fontCollector, storage};
TimeStampProvider timeStampProvider; TimeStampProvider timeStampProvider;
AsynchronousImageCache cache{storage, generator, timeStampProvider};
AsynchronousImageCache asynchronousFontImageCache{storage, fontGenerator, timeStampProvider}; AsynchronousImageCache asynchronousFontImageCache{storage, fontGenerator, timeStampProvider};
SynchronousImageCache synchronousFontImageCache{storage, timeStampProvider, fontCollector}; SynchronousImageCache synchronousFontImageCache{storage, timeStampProvider, fontCollector};
}; };
@@ -94,8 +80,7 @@ bool AssetsLibraryView::hasWidget() const
WidgetInfo AssetsLibraryView::widgetInfo() WidgetInfo AssetsLibraryView::widgetInfo()
{ {
if (m_widget.isNull()) { if (m_widget.isNull()) {
m_widget = new AssetsLibraryWidget{imageCacheData()->cache, m_widget = new AssetsLibraryWidget{imageCacheData()->asynchronousFontImageCache,
imageCacheData()->asynchronousFontImageCache,
imageCacheData()->synchronousFontImageCache}; imageCacheData()->synchronousFontImageCache};
} }
@@ -133,49 +118,18 @@ void AssetsLibraryView::setResourcePath(const QString &resourcePath)
m_lastResourcePath = resourcePath; m_lastResourcePath = resourcePath;
if (m_widget.isNull()) { if (m_widget.isNull()) {
m_widget = new AssetsLibraryWidget{m_imageCacheData->cache, m_widget = new AssetsLibraryWidget{imageCacheData()->asynchronousFontImageCache,
m_imageCacheData->asynchronousFontImageCache, imageCacheData()->synchronousFontImageCache};
m_imageCacheData->synchronousFontImageCache};
} }
m_widget->setResourcePath(resourcePath); m_widget->setResourcePath(resourcePath);
} }
ImageCacheData *AssetsLibraryView::imageCacheData() AssetsLibraryView::ImageCacheData *AssetsLibraryView::imageCacheData()
{ {
std::call_once(imageCacheFlag, [this]() { std::call_once(imageCacheFlag,
m_imageCacheData = std::make_unique<ImageCacheData>(); [this]() { m_imageCacheData = std::make_unique<ImageCacheData>(); });
auto setTargetInImageCache =
[imageCacheData = m_imageCacheData.get()](ProjectExplorer::Target *target) {
if (target == imageCacheData->collector.target())
return;
if (target)
imageCacheData->cache.clean();
imageCacheData->collector.setTarget(target);
};
if (auto project = ProjectExplorer::SessionManager::startupProject(); project) {
m_imageCacheData->collector.setTarget(project->activeTarget());
connect(project,
&ProjectExplorer::Project::activeTargetChanged,
this,
setTargetInImageCache);
}
connect(ProjectExplorer::SessionManager::instance(),
&ProjectExplorer::SessionManager::startupProjectChanged,
this,
[=](ProjectExplorer::Project *project) {
setTargetInImageCache(activeTarget(project));
});
});
return m_imageCacheData.get(); return m_imageCacheData.get();
} }
AsynchronousImageCache &AssetsLibraryView::imageCache()
{
return imageCacheData()->cache;
}
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -34,7 +34,6 @@
namespace QmlDesigner { namespace QmlDesigner {
class AssetsLibraryWidget; class AssetsLibraryWidget;
class ImageCacheData;
class AsynchronousImageCache; class AsynchronousImageCache;
class AssetsLibraryView : public AbstractView class AssetsLibraryView : public AbstractView
@@ -54,9 +53,8 @@ public:
void setResourcePath(const QString &resourcePath); void setResourcePath(const QString &resourcePath);
AsynchronousImageCache &imageCache();
private: private:
class ImageCacheData;
ImageCacheData *imageCacheData(); ImageCacheData *imageCacheData();
std::once_flag imageCacheFlag; std::once_flag imageCacheFlag;

View File

@@ -110,8 +110,7 @@ bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event)
return QObject::eventFilter(obj, event); return QObject::eventFilter(obj, event);
} }
AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &imageCache, AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFontImageCache,
AsynchronousImageCache &asynchronousFontImageCache,
SynchronousImageCache &synchronousFontImageCache) SynchronousImageCache &synchronousFontImageCache)
: m_itemIconSize(24, 24) : m_itemIconSize(24, 24)
, m_fontImageCache(synchronousFontImageCache) , m_fontImageCache(synchronousFontImageCache)
@@ -119,7 +118,6 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &imageCache,
, m_fileSystemWatcher(new Utils::FileSystemWatcher(this)) , m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
, m_assetsModel(new AssetsLibraryModel(m_fileSystemWatcher, this)) , m_assetsModel(new AssetsLibraryModel(m_fileSystemWatcher, this))
, m_assetsWidget(new QQuickWidget(this)) , m_assetsWidget(new QQuickWidget(this))
, m_imageCache{imageCache}
{ {
m_assetCompressionTimer.setInterval(200); m_assetCompressionTimer.setInterval(200);
m_assetCompressionTimer.setSingleShot(true); m_assetCompressionTimer.setSingleShot(true);

View File

@@ -60,8 +60,7 @@ class AssetsLibraryWidget : public QFrame
Q_OBJECT Q_OBJECT
public: public:
AssetsLibraryWidget(AsynchronousImageCache &imageCache, AssetsLibraryWidget(AsynchronousImageCache &asynchronousFontImageCache,
AsynchronousImageCache &asynchronousFontImageCache,
SynchronousImageCache &synchronousFontImageCache); SynchronousImageCache &synchronousFontImageCache);
~AssetsLibraryWidget(); ~AssetsLibraryWidget();
@@ -110,7 +109,6 @@ private:
std::unique_ptr<PreviewTooltipBackend> m_fontPreviewTooltipBackend; std::unique_ptr<PreviewTooltipBackend> m_fontPreviewTooltipBackend;
QShortcut *m_qmlSourceUpdateShortcut = nullptr; QShortcut *m_qmlSourceUpdateShortcut = nullptr;
AsynchronousImageCache &m_imageCache;
QPointer<Model> m_model; QPointer<Model> m_model;
QStringList m_assetsToDrag; QStringList m_assetsToDrag;
bool m_updateRetry = false; bool m_updateRetry = false;

View File

@@ -62,7 +62,7 @@ ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project)
} }
} // namespace } // namespace
class ImageCacheData class ItemLibraryView::ImageCacheData
{ {
public: public:
Sqlite::Database database{Utils::PathString{ Sqlite::Database database{Utils::PathString{
@@ -71,7 +71,7 @@ public:
Sqlite::LockingMode::Normal}; Sqlite::LockingMode::Normal};
ImageCacheStorage<Sqlite::Database> storage{database}; ImageCacheStorage<Sqlite::Database> storage{database};
ImageCacheConnectionManager connectionManager; ImageCacheConnectionManager connectionManager;
ImageCacheCollector collector{connectionManager}; ImageCacheCollector collector{connectionManager, QSize{300, 300}, QSize{600, 600}};
ImageCacheFontCollector fontCollector; ImageCacheFontCollector fontCollector;
ImageCacheGenerator generator{collector, storage}; ImageCacheGenerator generator{collector, storage};
ImageCacheGenerator fontGenerator{fontCollector, storage}; ImageCacheGenerator fontGenerator{fontCollector, storage};
@@ -182,7 +182,7 @@ void ItemLibraryView::usedImportsChanged(const QList<Import> &usedImports)
m_widget->updateUsedImports(usedImports); m_widget->updateUsedImports(usedImports);
} }
ImageCacheData *ItemLibraryView::imageCacheData() ItemLibraryView::ImageCacheData *ItemLibraryView::imageCacheData()
{ {
std::call_once(imageCacheFlag, [this]() { std::call_once(imageCacheFlag, [this]() {
m_imageCacheData = std::make_unique<ImageCacheData>(); m_imageCacheData = std::make_unique<ImageCacheData>();

View File

@@ -34,7 +34,6 @@
namespace QmlDesigner { namespace QmlDesigner {
class ItemLibraryWidget; class ItemLibraryWidget;
class ImageCacheData;
class AsynchronousImageCache; class AsynchronousImageCache;
class ItemLibraryView : public AbstractView class ItemLibraryView : public AbstractView
@@ -65,6 +64,7 @@ protected:
void updateImports(); void updateImports();
private: private:
class ImageCacheData;
ImageCacheData *imageCacheData(); ImageCacheData *imageCacheData();
std::once_flag imageCacheFlag; std::once_flag imageCacheFlag;

View File

@@ -68,7 +68,8 @@ void PreviewImageTooltip::setImage(const QImage &image, bool scale)
if (scale) { if (scale) {
m_ui->imageLabel->setPixmap(pm.scaled(m_ui->imageLabel->width(), m_ui->imageLabel->setPixmap(pm.scaled(m_ui->imageLabel->width(),
m_ui->imageLabel->height(), m_ui->imageLabel->height(),
Qt::KeepAspectRatio)); Qt::KeepAspectRatio,
Qt::SmoothTransformation));
} else { } else {
m_ui->imageLabel->setPixmap(pm); m_ui->imageLabel->setPixmap(pm);
} }

View File

@@ -61,8 +61,12 @@ QString fileToString(const QString &filename)
} // namespace } // namespace
ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connectionManager, ImageCacheCollector::ImageCacheCollector(ImageCacheConnectionManager &connectionManager,
QSize captureImageMinimumSize,
QSize captureImageMaximumSize,
ImageCacheCollectorNullImageHandling nullImageHandling) ImageCacheCollectorNullImageHandling nullImageHandling)
: m_connectionManager{connectionManager} : m_connectionManager{connectionManager}
, captureImageMinimumSize{captureImageMinimumSize}
, captureImageMaximumSize{captureImageMaximumSize}
, nullImageHandling{nullImageHandling} , nullImageHandling{nullImageHandling}
{} {}
@@ -76,6 +80,8 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
{ {
RewriterView rewriterView{RewriterView::Amend, nullptr}; RewriterView rewriterView{RewriterView::Amend, nullptr};
NodeInstanceView nodeInstanceView{m_connectionManager}; NodeInstanceView nodeInstanceView{m_connectionManager};
nodeInstanceView.setCaptureImageMinimumAndMaximumSize(captureImageMinimumSize,
captureImageMaximumSize);
const QString filePath{name}; const QString filePath{name};
std::unique_ptr<Model> model{QmlDesigner::Model::create("QtQuick/Item", 2, 1)}; std::unique_ptr<Model> model{QmlDesigner::Model::create("QtQuick/Item", 2, 1)};
@@ -107,7 +113,10 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
|| !image.isNull()) { || !image.isNull()) {
QSize smallImageSize = image.size().scaled(QSize{96, 96}.boundedTo(image.size()), QSize smallImageSize = image.size().scaled(QSize{96, 96}.boundedTo(image.size()),
Qt::KeepAspectRatio); Qt::KeepAspectRatio);
QImage smallImage = image.isNull() ? QImage{} : image.scaled(smallImageSize); QImage smallImage = image.isNull() ? QImage{}
: image.scaled(smallImageSize,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
captureCallback(image, smallImage); captureCallback(image, smallImage);
} }
}; };

View File

@@ -51,6 +51,8 @@ class ImageCacheCollector final : public ImageCacheCollectorInterface
{ {
public: public:
ImageCacheCollector(ImageCacheConnectionManager &connectionManager, ImageCacheCollector(ImageCacheConnectionManager &connectionManager,
QSize captureImageMinimumSize,
QSize captureImageMaximumSize,
ImageCacheCollectorNullImageHandling nullImageHandling = {}); ImageCacheCollectorNullImageHandling nullImageHandling = {});
~ImageCacheCollector(); ~ImageCacheCollector();
@@ -75,6 +77,8 @@ public:
private: private:
ImageCacheConnectionManager &m_connectionManager; ImageCacheConnectionManager &m_connectionManager;
QPointer<ProjectExplorer::Target> m_target; QPointer<ProjectExplorer::Target> m_target;
QSize captureImageMinimumSize;
QSize captureImageMaximumSize;
ImageCacheCollectorNullImageHandling nullImageHandling{}; ImageCacheCollectorNullImageHandling nullImageHandling{};
}; };

View File

@@ -161,6 +161,13 @@ public:
m_crashCallback = std::move(crashCallback); m_crashCallback = std::move(crashCallback);
} }
void setCaptureImageMinimumAndMaximumSize(QSize captureImageMinimumSize,
QSize captureImageMaximumSize)
{
m_captureImageMinimumSize = captureImageMinimumSize;
m_captureImageMaximumSize = captureImageMaximumSize;
}
void startNanotrace(); void startNanotrace();
void endNanotrace(); void endNanotrace();
@@ -293,6 +300,8 @@ private:
QHash<QString, QStringList> m_qsbPathToFilterMap; QHash<QString, QStringList> m_qsbPathToFilterMap;
int m_remainingQsbTargets = 0; int m_remainingQsbTargets = 0;
QTimer m_rotBlockTimer; QTimer m_rotBlockTimer;
QSize m_captureImageMinimumSize{150, 150};
QSize m_captureImageMaximumSize{1000, 1000};
}; };
} // namespace ProxyNodeInstanceView } // namespace ProxyNodeInstanceView

View File

@@ -1138,7 +1138,8 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0)) if (stateNode.isValid() && stateNode.metaInfo().isSubclassOf("QtQuick.State", 1, 0))
stateInstanceId = stateNode.internalId(); stateInstanceId = stateNode.internalId();
return CreateSceneCommand(instanceContainerList, return CreateSceneCommand(
instanceContainerList,
reparentContainerList, reparentContainerList,
idContainerList, idContainerList,
valueContainerList, valueContainerList,
@@ -1148,13 +1149,15 @@ CreateSceneCommand NodeInstanceView::createCreateSceneCommand()
mockupTypesVector, mockupTypesVector,
model()->fileUrl(), model()->fileUrl(),
#ifndef QMLDESIGNER_TEST #ifndef QMLDESIGNER_TEST
QUrl::fromLocalFile(QmlDesigner::DocumentManager::currentResourcePath() QUrl::fromLocalFile(
.toFileInfo().absoluteFilePath()), QmlDesigner::DocumentManager::currentResourcePath().toFileInfo().absoluteFilePath()),
#else #else
QUrl::fromLocalFile(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath()), QUrl::fromLocalFile(QFileInfo(model()->fileUrl().toLocalFile()).absolutePath()),
#endif #endif
m_edit3DToolStates[model()->fileUrl()], m_edit3DToolStates[model()->fileUrl()],
lastUsedLanguage, lastUsedLanguage,
m_captureImageMinimumSize,
m_captureImageMaximumSize,
stateInstanceId); stateInstanceId);
} }

View File

@@ -108,6 +108,8 @@ public:
{} {}
ImageCacheConnectionManager connectionManager; ImageCacheConnectionManager connectionManager;
ImageCacheCollector collector{connectionManager, ImageCacheCollector collector{connectionManager,
QSize{300, 300},
QSize{1000, 1000},
ImageCacheCollectorNullImageHandling::DontCaptureNullImage}; ImageCacheCollectorNullImageHandling::DontCaptureNullImage};
TimeStampProvider timeStampProvider; TimeStampProvider timeStampProvider;
AsynchronousImageFactory factory; AsynchronousImageFactory factory;

View File

@@ -116,6 +116,7 @@ Item {
id: image id: image
width: 240 width: 240
height: 125 height: 125
mipmap: true
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
} }
} }