QmlDesigner: Add image for broken preview

Task-number: QDS-9048
Change-Id: Ic2ce8bf4d51f72c3ddae588709820728fc7c76b5
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Marco Bubke
2023-02-27 16:13:58 +01:00
parent c2915c6963
commit 130453fe15
9 changed files with 38 additions and 17 deletions

View File

@@ -37,6 +37,7 @@ QQuickImageResponse *ItemLibraryIconImageProvider::requestImageResponse(const QS
[response, abortReason] { [response, abortReason] {
switch (abortReason) { switch (abortReason) {
case ImageCache::AbortReason::Failed: case ImageCache::AbortReason::Failed:
case ImageCache::AbortReason::NoEntry:
if (response) if (response)
response->abort(); response->abort();
break; break;

View File

@@ -60,10 +60,14 @@ void AsynchronousExplicitImageCache::request(Utils::SmallStringView name,
}; };
const auto entry = requestImageFromStorage(requestType); const auto entry = requestImageFromStorage(requestType);
if (entry && !entry->isNull()) if (entry) {
captureCallback(*entry); if (entry->isNull())
else abortCallback(ImageCache::AbortReason::Failed);
abortCallback(ImageCache::AbortReason::Failed); else
captureCallback(*entry);
} else {
abortCallback(ImageCache::AbortReason::NoEntry);
}
} }
void AsynchronousExplicitImageCache::wait() void AsynchronousExplicitImageCache::wait()

View File

@@ -27,16 +27,20 @@ QQuickImageResponse *ExplicitImageCacheImageProvider::requestImageResponse(const
}, },
Qt::QueuedConnection); Qt::QueuedConnection);
}, },
[response = QPointer<ImageCacheImageResponse>(response.get())]( [response = QPointer<ImageCacheImageResponse>(response.get()),
ImageCache::AbortReason abortReason) { failedImage = m_failedImage](ImageCache::AbortReason abortReason) {
QMetaObject::invokeMethod( QMetaObject::invokeMethod(
response, response,
[response, abortReason] { [response, abortReason, failedImage] {
switch (abortReason) { switch (abortReason) {
case ImageCache::AbortReason::Failed: case ImageCache::AbortReason::NoEntry:
if (response) if (response)
response->abort(); response->abort();
break; break;
case ImageCache::AbortReason::Failed:
if (response)
response->setImage(failedImage);
break;
case ImageCache::AbortReason::Abort: case ImageCache::AbortReason::Abort:
response->cancel(); response->cancel();
break; break;

View File

@@ -14,9 +14,11 @@ class ExplicitImageCacheImageProvider : public QQuickAsyncImageProvider
{ {
public: public:
ExplicitImageCacheImageProvider(AsynchronousExplicitImageCache &imageCache, ExplicitImageCacheImageProvider(AsynchronousExplicitImageCache &imageCache,
const QImage &defaultImage) const QImage &defaultImage,
const QImage &failedImage)
: m_cache(imageCache) : m_cache(imageCache)
, m_defaultImage(defaultImage) , m_defaultImage(defaultImage)
, m_failedImage(failedImage)
{} {}
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override; QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
@@ -24,6 +26,7 @@ public:
private: private:
AsynchronousExplicitImageCache &m_cache; AsynchronousExplicitImageCache &m_cache;
QImage m_defaultImage; QImage m_defaultImage;
QImage m_failedImage;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -32,6 +32,7 @@ QQuickImageResponse *MidSizeImageCacheProvider::requestImageResponse(const QStri
[response, abortReason] { [response, abortReason] {
switch (abortReason) { switch (abortReason) {
case ImageCache::AbortReason::Failed: case ImageCache::AbortReason::Failed:
case ImageCache::AbortReason::NoEntry:
if (response) if (response)
response->abort(); response->abort();
break; break;

View File

@@ -33,6 +33,7 @@ QQuickImageResponse *SmallImageCacheProvider::requestImageResponse(const QString
[response, abortReason] { [response, abortReason] {
switch (abortReason) { switch (abortReason) {
case ImageCache::AbortReason::Failed: case ImageCache::AbortReason::Failed:
case ImageCache::AbortReason::NoEntry:
if (response) if (response)
response->abort(); response->abort();
break; break;

View File

@@ -43,7 +43,7 @@ using AuxiliaryData = std::variant<std::monostate,
FontCollectorSizeAuxiliaryData, FontCollectorSizeAuxiliaryData,
FontCollectorSizesAuxiliaryData>; FontCollectorSizesAuxiliaryData>;
enum class AbortReason : char { Abort, Failed }; enum class AbortReason : char { Abort, Failed, NoEntry };
using CaptureImageCallback = std::function<void(const QImage &)>; using CaptureImageCallback = std::function<void(const QImage &)>;
using CaptureImageWithScaledImagesCallback = std::function< using CaptureImageWithScaledImagesCallback = std::function<

View File

@@ -54,11 +54,16 @@ ProjectExplorer::Target *activeTarget(ProjectExplorer::Project *project)
return {}; return {};
} }
QString defaultImagePath() QString previewDefaultImagePath()
{ {
return Core::ICore::resourcePath("qmldesigner/welcomepage/images/newThumbnail.png").toString(); return Core::ICore::resourcePath("qmldesigner/welcomepage/images/newThumbnail.png").toString();
} }
QString previewBrokenImagePath()
{
return Core::ICore::resourcePath("qmldesigner/welcomepage/images/newPreview.png").toString();
}
::QmlProjectManager::QmlBuildSystem *getQmlBuildSystem(::ProjectExplorer::Target *target) ::QmlProjectManager::QmlBuildSystem *getQmlBuildSystem(::ProjectExplorer::Target *target)
{ {
return qobject_cast<::QmlProjectManager::QmlBuildSystem *>(target->buildSystem()); return qobject_cast<::QmlProjectManager::QmlBuildSystem *>(target->buildSystem());
@@ -147,7 +152,7 @@ public:
QSize{300, 300}, QSize{300, 300},
QSize{1000, 1000}, QSize{1000, 1000},
externalDependencies, externalDependencies,
ImageCacheCollectorNullImageHandling::DontCaptureNullImage} ImageCacheCollectorNullImageHandling::CaptureNullImage}
{ {
timer.setSingleShot(true); timer.setSingleShot(true);
} }
@@ -260,8 +265,10 @@ QmlDesignerProjectManager::~QmlDesignerProjectManager() = default;
void QmlDesignerProjectManager::registerPreviewImageProvider(QQmlEngine *engine) const void QmlDesignerProjectManager::registerPreviewImageProvider(QQmlEngine *engine) const
{ {
auto imageProvider = std::make_unique<ExplicitImageCacheImageProvider>(m_previewImageCacheData->cache, auto imageProvider = std::make_unique<ExplicitImageCacheImageProvider>(
QImage{defaultImagePath()}); m_previewImageCacheData->cache,
QImage{previewDefaultImagePath()},
QImage{previewBrokenImagePath()});
engine->addImageProvider("project_preview", imageProvider.release()); engine->addImageProvider("project_preview", imageProvider.release());
} }

View File

@@ -74,7 +74,7 @@ TEST_F(AsynchronousExplicitImageCache, RequestImageCallsAbortCallbackWithoutEntr
ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _)) ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{})); .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{}));
EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::Failed))) EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::NoEntry)))
.WillRepeatedly([&](auto) { notification.notify(); }); .WillRepeatedly([&](auto) { notification.notify(); });
cache.requestImage("/path/to/Component.qml", cache.requestImage("/path/to/Component.qml",
@@ -131,7 +131,7 @@ TEST_F(AsynchronousExplicitImageCache, RequestMidSizeImageCallsAbortCallbackWith
ON_CALL(mockStorage, fetchMidSizeImage(Eq("/path/to/Component.qml"), _)) ON_CALL(mockStorage, fetchMidSizeImage(Eq("/path/to/Component.qml"), _))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{})); .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{}));
EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::Failed))) EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::NoEntry)))
.WillRepeatedly([&](auto) { notification.notify(); }); .WillRepeatedly([&](auto) { notification.notify(); });
cache.requestMidSizeImage("/path/to/Component.qml", cache.requestMidSizeImage("/path/to/Component.qml",
@@ -188,7 +188,7 @@ TEST_F(AsynchronousExplicitImageCache, RequestSmallImageCallsAbortCallbackWithou
ON_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml"), _)) ON_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml"), _))
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{})); .WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{}));
EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::Failed))) EXPECT_CALL(mockAbortCallback, Call(Eq(QmlDesigner::ImageCache::AbortReason::NoEntry)))
.WillRepeatedly([&](auto) { notification.notify(); }); .WillRepeatedly([&](auto) { notification.notify(); });
cache.requestSmallImage("/path/to/Component.qml", cache.requestSmallImage("/path/to/Component.qml",