forked from qt-creator/qt-creator
QmlDesigner: Improve imagecache
Instead of coding some arguments to extraId(state) we provide now a std::variant there extra arguments can be saved. Because it's a std::variant it can be easlily extended by new structs. There is a new synchronous interface too. It has an extra method for QIcon which saves icons in an extra table. It would be even nicer if we would have a mipmap image too. So we could do it asynchonously too but so far it works only in the main thread. Task-number: QDS-3579 Fixes: QDS-3584 Change-Id: If368d84d82308a91a5f4f037021e749c9ef868ed Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -249,11 +249,18 @@ void BaseStatement::bind(int index, Utils::SmallStringView text)
|
|||||||
|
|
||||||
void BaseStatement::bind(int index, BlobView blobView)
|
void BaseStatement::bind(int index, BlobView blobView)
|
||||||
{
|
{
|
||||||
int resultCode = sqlite3_bind_blob64(m_compiledStatement.get(),
|
int resultCode = SQLITE_OK;
|
||||||
|
|
||||||
|
if (blobView.empty()) {
|
||||||
|
sqlite3_bind_null(m_compiledStatement.get(), index);
|
||||||
|
} else {
|
||||||
|
resultCode = sqlite3_bind_blob64(m_compiledStatement.get(),
|
||||||
index,
|
index,
|
||||||
blobView.data(),
|
blobView.data(),
|
||||||
blobView.size(),
|
blobView.size(),
|
||||||
SQLITE_STATIC);
|
SQLITE_STATIC);
|
||||||
|
}
|
||||||
|
|
||||||
if (resultCode != SQLITE_OK)
|
if (resultCode != SQLITE_OK)
|
||||||
checkForBindingError(resultCode);
|
checkForBindingError(resultCode);
|
||||||
}
|
}
|
||||||
@@ -713,6 +720,26 @@ StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column)
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
Type BaseStatement::fetchType(int column) const
|
||||||
|
{
|
||||||
|
auto dataType = sqlite3_column_type(m_compiledStatement.get(), column);
|
||||||
|
|
||||||
|
switch (dataType) {
|
||||||
|
case SQLITE_INTEGER:
|
||||||
|
return Type::Integer;
|
||||||
|
case SQLITE_FLOAT:
|
||||||
|
return Type::Float;
|
||||||
|
case SQLITE3_TEXT:
|
||||||
|
return Type::Text;
|
||||||
|
case SQLITE_BLOB:
|
||||||
|
return Type::Blob;
|
||||||
|
case SQLITE_NULL:
|
||||||
|
return Type::Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Type::Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
int BaseStatement::fetchIntValue(int column) const
|
int BaseStatement::fetchIntValue(int column) const
|
||||||
{
|
{
|
||||||
return sqlite3_column_int(m_compiledStatement.get(), column);
|
return sqlite3_column_int(m_compiledStatement.get(), column);
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ namespace Sqlite {
|
|||||||
class Database;
|
class Database;
|
||||||
class DatabaseBackend;
|
class DatabaseBackend;
|
||||||
|
|
||||||
|
enum class Type : char { Invalid, Integer, Float, Text, Blob, Null };
|
||||||
|
|
||||||
class SQLITE_EXPORT BaseStatement
|
class SQLITE_EXPORT BaseStatement
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -65,6 +67,7 @@ public:
|
|||||||
void step() const;
|
void step() const;
|
||||||
void reset() const;
|
void reset() const;
|
||||||
|
|
||||||
|
Type fetchType(int column) const;
|
||||||
int fetchIntValue(int column) const;
|
int fetchIntValue(int column) const;
|
||||||
long fetchLongValue(int column) const;
|
long fetchLongValue(int column) const;
|
||||||
long long fetchLongLongValue(int column) const;
|
long long fetchLongLongValue(int column) const;
|
||||||
|
|||||||
@@ -509,8 +509,10 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
include/textmodifier.h
|
include/textmodifier.h
|
||||||
include/variantproperty.h
|
include/variantproperty.h
|
||||||
include/viewmanager.h
|
include/viewmanager.h
|
||||||
include/imagecache.h
|
include/asynchronousimagecache.h
|
||||||
include/imagecacheinterface.h
|
include/synchronousimagecache.h
|
||||||
|
include/imagecacheauxiliarydata.h
|
||||||
|
include/asynchronousimagecacheinterface.h
|
||||||
)
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
@@ -601,7 +603,8 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
imagecache/imagecachecollector.cpp
|
imagecache/imagecachecollector.cpp
|
||||||
imagecache/imagecachefontcollector.h
|
imagecache/imagecachefontcollector.h
|
||||||
imagecache/imagecachefontcollector.cpp
|
imagecache/imagecachefontcollector.cpp
|
||||||
imagecache/imagecache.cpp
|
imagecache/asynchronousimagecache.cpp
|
||||||
|
imagecache/synchronousimagecache.cpp
|
||||||
imagecache/imagecachecollectorinterface.h
|
imagecache/imagecachecollectorinterface.h
|
||||||
imagecache/imagecacheconnectionmanager.cpp
|
imagecache/imagecacheconnectionmanager.cpp
|
||||||
imagecache/imagecacheconnectionmanager.h
|
imagecache/imagecacheconnectionmanager.h
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
|
|
||||||
#include "customfilesystemmodel.h"
|
#include "customfilesystemmodel.h"
|
||||||
|
|
||||||
|
#include <synchronousimagecache.h>
|
||||||
#include <theme.h>
|
#include <theme.h>
|
||||||
#include <imagecache.h>
|
|
||||||
|
|
||||||
#include <utils/filesystemwatcher.h>
|
#include <utils/filesystemwatcher.h>
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ QString fontFamily(const QFileInfo &info)
|
|||||||
class ItemLibraryFileIconProvider : public QFileIconProvider
|
class ItemLibraryFileIconProvider : public QFileIconProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ItemLibraryFileIconProvider(ImageCache &fontImageCache)
|
ItemLibraryFileIconProvider(SynchronousImageCache &fontImageCache)
|
||||||
: QFileIconProvider()
|
: QFileIconProvider()
|
||||||
, m_fontImageCache(fontImageCache)
|
, m_fontImageCache(fontImageCache)
|
||||||
{
|
{
|
||||||
@@ -138,71 +138,29 @@ public:
|
|||||||
|
|
||||||
QIcon generateFontIcons(const QString &filePath) const
|
QIcon generateFontIcons(const QString &filePath) const
|
||||||
{
|
{
|
||||||
QIcon icon;
|
return m_fontImageCache.icon(
|
||||||
QString colorName = Theme::getColor(Theme::DStextColor).name();
|
|
||||||
std::condition_variable condition;
|
|
||||||
int count = iconSizes.size();
|
|
||||||
std::mutex mutex;
|
|
||||||
QList<QPair<QSize, QImage>> images;
|
|
||||||
|
|
||||||
for (auto iconSize : iconSizes) {
|
|
||||||
m_fontImageCache.requestImage(
|
|
||||||
filePath,
|
filePath,
|
||||||
[&images, &condition, &count, &mutex, iconSize](const QImage &image) {
|
{},
|
||||||
int currentCount;
|
ImageCache::FontCollectorSizesAuxiliaryData{Utils::span{iconSizes},
|
||||||
{
|
Theme::getColor(Theme::DStextColor).name(),
|
||||||
std::unique_lock lock{mutex};
|
"Abc"});
|
||||||
currentCount = --count;
|
|
||||||
images.append({iconSize, image});
|
|
||||||
}
|
|
||||||
if (currentCount <= 0)
|
|
||||||
condition.notify_all();
|
|
||||||
},
|
|
||||||
[&images, &condition, &count, &mutex, iconSize] {
|
|
||||||
int currentCount;
|
|
||||||
{
|
|
||||||
std::unique_lock lock{mutex};
|
|
||||||
currentCount = --count;
|
|
||||||
images.append({iconSize, {}});
|
|
||||||
}
|
|
||||||
if (currentCount <= 0)
|
|
||||||
condition.notify_all();
|
|
||||||
},
|
|
||||||
QStringLiteral("%1@%2@Abc").arg(QString::number(iconSize.width()),
|
|
||||||
colorName)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Block main thread until icons are generated, as it has to be done synchronously
|
|
||||||
std::unique_lock lock{mutex};
|
|
||||||
if (count > 0)
|
|
||||||
condition.wait(lock, [&]{ return count <= 0; });
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &pair : qAsConst(images)) {
|
|
||||||
QImage image = pair.second;
|
|
||||||
if (image.isNull())
|
|
||||||
icon.addPixmap(defaultPixmapForType("font", pair.first));
|
|
||||||
else
|
|
||||||
icon.addPixmap(QPixmap::fromImage(image));
|
|
||||||
}
|
|
||||||
|
|
||||||
return icon;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generated icon sizes should contain all ItemLibraryResourceView needed icon sizes, and their
|
// Generated icon sizes should contain all ItemLibraryResourceView needed icon sizes, and their
|
||||||
// x2 versions for HDPI sceens
|
// x2 versions for HDPI sceens
|
||||||
QList<QSize> iconSizes = {{384, 384}, {192, 192}, // Large
|
std::vector<QSize> iconSizes = {{384, 384},
|
||||||
{256, 256}, {128, 128}, // Drag
|
{192, 192}, // Large
|
||||||
|
{256, 256},
|
||||||
|
{128, 128}, // Drag
|
||||||
{96, 96}, // Medium
|
{96, 96}, // Medium
|
||||||
{48, 48}, // Small
|
{48, 48}, // Small
|
||||||
{64, 64}, {32, 32}}; // List
|
{64, 64},
|
||||||
|
{32, 32}}; // List
|
||||||
|
|
||||||
ImageCache &m_fontImageCache;
|
SynchronousImageCache &m_fontImageCache;
|
||||||
};
|
};
|
||||||
|
|
||||||
CustomFileSystemModel::CustomFileSystemModel(ImageCache &fontImageCache, QObject *parent)
|
CustomFileSystemModel::CustomFileSystemModel(SynchronousImageCache &fontImageCache, QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
, m_fileSystemModel(new QFileSystemModel(this))
|
, m_fileSystemModel(new QFileSystemModel(this))
|
||||||
, m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
|
, m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
|
||||||
|
|||||||
@@ -39,13 +39,14 @@ namespace Utils { class FileSystemWatcher; }
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class ImageCache;
|
class SynchronousImageCache;
|
||||||
|
|
||||||
class CustomFileSystemModel : public QAbstractListModel
|
class CustomFileSystemModel : public QAbstractListModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
CustomFileSystemModel(ImageCache &fontImageCache, QObject *parent = nullptr);
|
CustomFileSystemModel(QmlDesigner::SynchronousImageCache &fontImageCache,
|
||||||
|
QObject *parent = nullptr);
|
||||||
|
|
||||||
void setFilter(QDir::Filters filters);
|
void setFilter(QDir::Filters filters);
|
||||||
QString rootPath() const;
|
QString rootPath() const;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ QQuickImageResponse *ItemLibraryIconImageProvider::requestImageResponse(const QS
|
|||||||
{
|
{
|
||||||
auto response = std::make_unique<ImageRespose>();
|
auto response = std::make_unique<ImageRespose>();
|
||||||
|
|
||||||
m_cache.requestIcon(
|
m_cache.requestSmallImage(
|
||||||
id,
|
id,
|
||||||
[response = QPointer<ImageRespose>(response.get())](const QImage &image) {
|
[response = QPointer<ImageRespose>(response.get())](const QImage &image) {
|
||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
#include <rewriterview.h>
|
#include <rewriterview.h>
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <imagecache.h>
|
#include <asynchronousimagecache.h>
|
||||||
#include <imagecache/imagecachecollector.h>
|
#include <imagecache/imagecachecollector.h>
|
||||||
#include <imagecache/imagecacheconnectionmanager.h>
|
#include <imagecache/imagecacheconnectionmanager.h>
|
||||||
#include <imagecache/imagecachegenerator.h>
|
#include <imagecache/imagecachegenerator.h>
|
||||||
@@ -45,14 +45,14 @@ namespace QmlDesigner {
|
|||||||
class ItemLibraryIconImageProvider : public QQuickAsyncImageProvider
|
class ItemLibraryIconImageProvider : public QQuickAsyncImageProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ItemLibraryIconImageProvider(ImageCache &imageCache)
|
ItemLibraryIconImageProvider(AsynchronousImageCache &imageCache)
|
||||||
: m_cache{imageCache}
|
: m_cache{imageCache}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
|
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ImageCache &m_cache;
|
AsynchronousImageCache &m_cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
#include "customfilesystemmodel.h"
|
#include "customfilesystemmodel.h"
|
||||||
|
|
||||||
#include <theme.h>
|
#include <theme.h>
|
||||||
#include <imagecache.h>
|
#include <asynchronousimagecache.h>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
@@ -62,8 +62,9 @@ void ItemLibraryResourceView::addSizeAction(QActionGroup *group, const QString &
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemLibraryResourceView::ItemLibraryResourceView(ImageCache &fontImageCache, QWidget *parent) :
|
ItemLibraryResourceView::ItemLibraryResourceView(AsynchronousImageCache &fontImageCache,
|
||||||
QListView(parent)
|
QWidget *parent)
|
||||||
|
: QListView(parent)
|
||||||
{
|
{
|
||||||
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
@@ -113,13 +114,12 @@ ItemLibraryResourceView::ItemLibraryResourceView(ImageCache &fontImageCache, QWi
|
|||||||
// a commonly used sentence to preview the font glyphs in latin fonts.
|
// a commonly used sentence to preview the font glyphs in latin fonts.
|
||||||
// For fonts that do not have latin glyphs, the font family name will have to
|
// For fonts that do not have latin glyphs, the font family name will have to
|
||||||
// suffice for preview. Font family name is inserted into %1 at render time.
|
// suffice for preview. Font family name is inserted into %1 at render time.
|
||||||
m_fontPreviewTooltipBackend->setState(QStringLiteral("%1@%2@%3")
|
m_fontPreviewTooltipBackend->setAuxiliaryData(
|
||||||
.arg(QString::number(300),
|
ImageCache::FontCollectorSizeAuxiliaryData{QSize{300, 300},
|
||||||
Theme::getColor(Theme::DStextColor).name(),
|
Theme::getColor(Theme::DStextColor).name(),
|
||||||
QStringLiteral("%1\n\n"
|
QStringLiteral("The quick brown fox jumps\n"
|
||||||
"The quick brown fox jumps\n"
|
|
||||||
"over the lazy dog\n"
|
"over the lazy dog\n"
|
||||||
"1234567890")));
|
"1234567890")});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemLibraryResourceView::startDrag(Qt::DropActions /* supportedActions */)
|
void ItemLibraryResourceView::startDrag(Qt::DropActions /* supportedActions */)
|
||||||
|
|||||||
@@ -35,13 +35,14 @@ QT_END_NAMESPACE
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class ImageCache;
|
class AsynchronousImageCache;
|
||||||
|
|
||||||
class ItemLibraryResourceView : public QListView {
|
class ItemLibraryResourceView : public QListView {
|
||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit ItemLibraryResourceView(ImageCache &fontImageCache, QWidget *parent = nullptr);
|
explicit ItemLibraryResourceView(AsynchronousImageCache &fontImageCache,
|
||||||
|
QWidget *parent = nullptr);
|
||||||
|
|
||||||
void startDrag(Qt::DropActions supportedActions) override;
|
void startDrag(Qt::DropActions supportedActions) override;
|
||||||
bool viewportEvent(QEvent *event) override;
|
bool viewportEvent(QEvent *event) override;
|
||||||
|
|||||||
@@ -26,12 +26,12 @@
|
|||||||
#include "itemlibraryview.h"
|
#include "itemlibraryview.h"
|
||||||
#include "itemlibrarywidget.h"
|
#include "itemlibrarywidget.h"
|
||||||
#include "metainfo.h"
|
#include "metainfo.h"
|
||||||
|
#include <asynchronousimagecache.h>
|
||||||
#include <bindingproperty.h>
|
#include <bindingproperty.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <imagecache.h>
|
|
||||||
#include <imagecache/imagecachecollector.h>
|
#include <imagecache/imagecachecollector.h>
|
||||||
#include <imagecache/imagecachefontcollector.h>
|
|
||||||
#include <imagecache/imagecacheconnectionmanager.h>
|
#include <imagecache/imagecacheconnectionmanager.h>
|
||||||
|
#include <imagecache/imagecachefontcollector.h>
|
||||||
#include <imagecache/imagecachegenerator.h>
|
#include <imagecache/imagecachegenerator.h>
|
||||||
#include <imagecache/imagecachestorage.h>
|
#include <imagecache/imagecachestorage.h>
|
||||||
#include <imagecache/timestampprovider.h>
|
#include <imagecache/timestampprovider.h>
|
||||||
@@ -42,6 +42,7 @@
|
|||||||
#include <projectexplorer/target.h>
|
#include <projectexplorer/target.h>
|
||||||
#include <rewriterview.h>
|
#include <rewriterview.h>
|
||||||
#include <sqlitedatabase.h>
|
#include <sqlitedatabase.h>
|
||||||
|
#include <synchronousimagecache.h>
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <qmldesignerplugin.h>
|
#include <qmldesignerplugin.h>
|
||||||
#include <qmlitemnode.h>
|
#include <qmlitemnode.h>
|
||||||
@@ -52,7 +53,7 @@ class ImageCacheData
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Sqlite::Database database{
|
Sqlite::Database database{
|
||||||
Utils::PathString{Core::ICore::cacheResourcePath() + "/imagecache-v1.db"}};
|
Utils::PathString{Core::ICore::cacheResourcePath() + "/imagecache-v2.db"}};
|
||||||
ImageCacheStorage<Sqlite::Database> storage{database};
|
ImageCacheStorage<Sqlite::Database> storage{database};
|
||||||
ImageCacheConnectionManager connectionManager;
|
ImageCacheConnectionManager connectionManager;
|
||||||
ImageCacheCollector collector{connectionManager};
|
ImageCacheCollector collector{connectionManager};
|
||||||
@@ -60,8 +61,9 @@ public:
|
|||||||
ImageCacheGenerator generator{collector, storage};
|
ImageCacheGenerator generator{collector, storage};
|
||||||
ImageCacheGenerator fontGenerator{fontCollector, storage};
|
ImageCacheGenerator fontGenerator{fontCollector, storage};
|
||||||
TimeStampProvider timeStampProvider;
|
TimeStampProvider timeStampProvider;
|
||||||
ImageCache cache{storage, generator, timeStampProvider};
|
AsynchronousImageCache cache{storage, generator, timeStampProvider};
|
||||||
ImageCache fontImageCache{storage, fontGenerator, timeStampProvider};
|
AsynchronousImageCache asynchronousFontImageCache{storage, fontGenerator, timeStampProvider};
|
||||||
|
SynchronousImageCache synchronousFontImageCache{storage, timeStampProvider, fontCollector};
|
||||||
};
|
};
|
||||||
|
|
||||||
ItemLibraryView::ItemLibraryView(QObject* parent)
|
ItemLibraryView::ItemLibraryView(QObject* parent)
|
||||||
@@ -82,7 +84,9 @@ bool ItemLibraryView::hasWidget() const
|
|||||||
WidgetInfo ItemLibraryView::widgetInfo()
|
WidgetInfo ItemLibraryView::widgetInfo()
|
||||||
{
|
{
|
||||||
if (m_widget.isNull()) {
|
if (m_widget.isNull()) {
|
||||||
m_widget = new ItemLibraryWidget{m_imageCacheData->cache, m_imageCacheData->fontImageCache};
|
m_widget = new ItemLibraryWidget{m_imageCacheData->cache,
|
||||||
|
m_imageCacheData->asynchronousFontImageCache,
|
||||||
|
m_imageCacheData->synchronousFontImageCache};
|
||||||
m_widget->setImportsWidget(m_importManagerView->widgetInfo().widget);
|
m_widget->setImportsWidget(m_importManagerView->widgetInfo().widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,12 +163,14 @@ void ItemLibraryView::importsChanged(const QList<Import> &addedImports, const QL
|
|||||||
void ItemLibraryView::setResourcePath(const QString &resourcePath)
|
void ItemLibraryView::setResourcePath(const QString &resourcePath)
|
||||||
{
|
{
|
||||||
if (m_widget.isNull())
|
if (m_widget.isNull())
|
||||||
m_widget = new ItemLibraryWidget{m_imageCacheData->cache, m_imageCacheData->fontImageCache};
|
m_widget = new ItemLibraryWidget{m_imageCacheData->cache,
|
||||||
|
m_imageCacheData->asynchronousFontImageCache,
|
||||||
|
m_imageCacheData->synchronousFontImageCache};
|
||||||
|
|
||||||
m_widget->setResourcePath(resourcePath);
|
m_widget->setResourcePath(resourcePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageCache &ItemLibraryView::imageCache()
|
AsynchronousImageCache &ItemLibraryView::imageCache()
|
||||||
{
|
{
|
||||||
return m_imageCacheData->cache;
|
return m_imageCacheData->cache;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace QmlDesigner {
|
|||||||
class ItemLibraryWidget;
|
class ItemLibraryWidget;
|
||||||
class ImportManagerView;
|
class ImportManagerView;
|
||||||
class ImageCacheData;
|
class ImageCacheData;
|
||||||
class ImageCache;
|
class AsynchronousImageCache;
|
||||||
|
|
||||||
class ItemLibraryView : public AbstractView
|
class ItemLibraryView : public AbstractView
|
||||||
{
|
{
|
||||||
@@ -56,7 +56,7 @@ public:
|
|||||||
|
|
||||||
void setResourcePath(const QString &resourcePath);
|
void setResourcePath(const QString &resourcePath);
|
||||||
|
|
||||||
ImageCache &imageCache();
|
AsynchronousImageCache &imageCache();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void updateImports();
|
void updateImports();
|
||||||
|
|||||||
@@ -82,10 +82,12 @@ static QString propertyEditorResourcesPath() {
|
|||||||
return Core::ICore::resourcePath() + QStringLiteral("/qmldesigner/propertyEditorQmlSources");
|
return Core::ICore::resourcePath() + QStringLiteral("/qmldesigner/propertyEditorQmlSources");
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemLibraryWidget::ItemLibraryWidget(ImageCache &imageCache, ImageCache &fontImageCache)
|
ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
|
||||||
|
AsynchronousImageCache &asynchronousFontImageCache,
|
||||||
|
SynchronousImageCache &synchronousFontImageCache)
|
||||||
: m_itemIconSize(24, 24)
|
: m_itemIconSize(24, 24)
|
||||||
, m_itemViewQuickWidget(new QQuickWidget(this))
|
, m_itemViewQuickWidget(new QQuickWidget(this))
|
||||||
, m_resourcesView(new ItemLibraryResourceView(fontImageCache, this))
|
, m_resourcesView(new ItemLibraryResourceView(asynchronousFontImageCache, this))
|
||||||
, m_importTagsWidget(new QWidget(this))
|
, m_importTagsWidget(new QWidget(this))
|
||||||
, m_addResourcesWidget(new QWidget(this))
|
, m_addResourcesWidget(new QWidget(this))
|
||||||
, m_imageCache{imageCache}
|
, m_imageCache{imageCache}
|
||||||
@@ -118,7 +120,7 @@ ItemLibraryWidget::ItemLibraryWidget(ImageCache &imageCache, ImageCache &fontIma
|
|||||||
Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
|
Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
|
||||||
|
|
||||||
/* create Resources view and its model */
|
/* create Resources view and its model */
|
||||||
m_resourcesFileSystemModel = new CustomFileSystemModel(fontImageCache, this);
|
m_resourcesFileSystemModel = new CustomFileSystemModel(synchronousFontImageCache, this);
|
||||||
m_resourcesView->setModel(m_resourcesFileSystemModel.data());
|
m_resourcesView->setModel(m_resourcesFileSystemModel.data());
|
||||||
|
|
||||||
/* create image provider for loading item icons */
|
/* create image provider for loading item icons */
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ class CustomFileSystemModel;
|
|||||||
|
|
||||||
class ItemLibraryModel;
|
class ItemLibraryModel;
|
||||||
class ItemLibraryResourceView;
|
class ItemLibraryResourceView;
|
||||||
class ImageCache;
|
class SynchronousImageCache;
|
||||||
|
class AsynchronousImageCache;
|
||||||
class ImageCacheCollector;
|
class ImageCacheCollector;
|
||||||
|
|
||||||
class ItemLibraryWidget : public QFrame
|
class ItemLibraryWidget : public QFrame
|
||||||
@@ -69,7 +70,9 @@ class ItemLibraryWidget : public QFrame
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ItemLibraryWidget(ImageCache &imageCache, ImageCache &fontImageCache);
|
ItemLibraryWidget(AsynchronousImageCache &imageCache,
|
||||||
|
AsynchronousImageCache &asynchronousFontImageCache,
|
||||||
|
SynchronousImageCache &synchronousFontImageCache);
|
||||||
~ItemLibraryWidget();
|
~ItemLibraryWidget();
|
||||||
|
|
||||||
void setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo);
|
void setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo);
|
||||||
@@ -126,7 +129,7 @@ private:
|
|||||||
std::unique_ptr<PreviewTooltipBackend> m_previewTooltipBackend;
|
std::unique_ptr<PreviewTooltipBackend> m_previewTooltipBackend;
|
||||||
|
|
||||||
QShortcut *m_qmlSourceUpdateShortcut;
|
QShortcut *m_qmlSourceUpdateShortcut;
|
||||||
ImageCache &m_imageCache;
|
AsynchronousImageCache &m_imageCache;
|
||||||
QPointer<Model> m_model;
|
QPointer<Model> m_model;
|
||||||
FilterChangeFlag m_filterFlag;
|
FilterChangeFlag m_filterFlag;
|
||||||
ItemLibraryEntry m_currentitemLibraryEntry;
|
ItemLibraryEntry m_currentitemLibraryEntry;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
#include "previewimagetooltip.h"
|
#include "previewimagetooltip.h"
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <imagecache.h>
|
#include <asynchronousimagecache.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
PreviewTooltipBackend::PreviewTooltipBackend(ImageCache &cache)
|
PreviewTooltipBackend::PreviewTooltipBackend(AsynchronousImageCache &cache)
|
||||||
: m_cache{cache}
|
: m_cache{cache}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -64,8 +64,8 @@ void PreviewTooltipBackend::showTooltip()
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
[] {},
|
[] {},
|
||||||
m_state
|
m_extraId,
|
||||||
);
|
m_auxiliaryData);
|
||||||
|
|
||||||
reposition();
|
reposition();
|
||||||
}
|
}
|
||||||
@@ -155,17 +155,17 @@ void PreviewTooltipBackend::setInfo(const QString &info)
|
|||||||
emit infoChanged();
|
emit infoChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PreviewTooltipBackend::state() const
|
QString PreviewTooltipBackend::extraId() const
|
||||||
{
|
{
|
||||||
return m_state;
|
return m_extraId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the imageCache state hint. Valid content depends on image cache collector used.
|
// Sets the imageCache extraId hint. Valid content depends on image cache collector used.
|
||||||
void PreviewTooltipBackend::setState(const QString &state)
|
void PreviewTooltipBackend::setExtraId(const QString &extraId)
|
||||||
{
|
{
|
||||||
m_state = state;
|
m_extraId = extraId;
|
||||||
if (m_state != state)
|
if (m_extraId != extraId)
|
||||||
emit stateChanged();
|
emit extraIdChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <imagecacheauxiliarydata.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@
|
|||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class PreviewImageTooltip;
|
class PreviewImageTooltip;
|
||||||
class ImageCache;
|
class AsynchronousImageCache;
|
||||||
|
|
||||||
class PreviewTooltipBackend : public QObject
|
class PreviewTooltipBackend : public QObject
|
||||||
{
|
{
|
||||||
@@ -42,10 +44,10 @@ class PreviewTooltipBackend : public QObject
|
|||||||
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
||||||
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
|
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
|
||||||
Q_PROPERTY(QString info READ info WRITE setInfo NOTIFY infoChanged)
|
Q_PROPERTY(QString info READ info WRITE setInfo NOTIFY infoChanged)
|
||||||
Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged)
|
Q_PROPERTY(QString extraId READ extraId WRITE setExtraId NOTIFY extraIdChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PreviewTooltipBackend(ImageCache &cache);
|
PreviewTooltipBackend(AsynchronousImageCache &cache);
|
||||||
~PreviewTooltipBackend();
|
~PreviewTooltipBackend();
|
||||||
|
|
||||||
Q_INVOKABLE void showTooltip();
|
Q_INVOKABLE void showTooltip();
|
||||||
@@ -58,24 +60,30 @@ public:
|
|||||||
void setPath(const QString &path);
|
void setPath(const QString &path);
|
||||||
QString info() const;
|
QString info() const;
|
||||||
void setInfo(const QString &info);
|
void setInfo(const QString &info);
|
||||||
QString state() const;
|
QString extraId() const;
|
||||||
void setState(const QString &state);
|
void setExtraId(const QString &extraId);
|
||||||
|
|
||||||
bool isVisible() const;
|
bool isVisible() const;
|
||||||
|
|
||||||
|
void setAuxiliaryData(ImageCache::AuxiliaryData auxiliaryData)
|
||||||
|
{
|
||||||
|
m_auxiliaryData = std::move(auxiliaryData);
|
||||||
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void nameChanged();
|
void nameChanged();
|
||||||
void pathChanged();
|
void pathChanged();
|
||||||
void infoChanged();
|
void infoChanged();
|
||||||
void stateChanged();
|
void extraIdChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_name;
|
QString m_name;
|
||||||
QString m_path;
|
QString m_path;
|
||||||
QString m_info;
|
QString m_info;
|
||||||
QString m_state;
|
QString m_extraId;
|
||||||
std::unique_ptr<PreviewImageTooltip> m_tooltip;
|
std::unique_ptr<PreviewImageTooltip> m_tooltip;
|
||||||
ImageCache &m_cache;
|
ImageCache::AuxiliaryData m_auxiliaryData;
|
||||||
|
AsynchronousImageCache &m_cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,7 +88,8 @@ SOURCES += $$PWD/model/abstractview.cpp \
|
|||||||
$$PWD/model/qmltimelinekeyframegroup.cpp \
|
$$PWD/model/qmltimelinekeyframegroup.cpp \
|
||||||
$$PWD/model/annotation.cpp \
|
$$PWD/model/annotation.cpp \
|
||||||
$$PWD/model/stylesheetmerger.cpp \
|
$$PWD/model/stylesheetmerger.cpp \
|
||||||
$$PWD/imagecache/imagecache.cpp \
|
$$PWD/imagecache/asynchronousimagecache.cpp \
|
||||||
|
$$PWD/imagecache/synchronousimagecache.cpp \
|
||||||
$$PWD/imagecache/imagecacheconnectionmanager.cpp \
|
$$PWD/imagecache/imagecacheconnectionmanager.cpp \
|
||||||
$$PWD/imagecache/imagecachegenerator.cpp \
|
$$PWD/imagecache/imagecachegenerator.cpp \
|
||||||
$$PWD/imagecache/timestampprovider.cpp
|
$$PWD/imagecache/timestampprovider.cpp
|
||||||
@@ -174,7 +175,9 @@ HEADERS += $$PWD/include/qmldesignercorelib_global.h \
|
|||||||
$$PWD/include/qmltimelinekeyframegroup.h \
|
$$PWD/include/qmltimelinekeyframegroup.h \
|
||||||
$$PWD/include/annotation.h \
|
$$PWD/include/annotation.h \
|
||||||
$$PWD/include/stylesheetmerger.h \
|
$$PWD/include/stylesheetmerger.h \
|
||||||
$$PWD/include/imagecache.h \
|
$$PWD/include/asynchronousimagecache.h \
|
||||||
|
$$PWD/include/synchronousimagecache.h \
|
||||||
|
$$PWD/include/imagecacheauxiliarydata.h \
|
||||||
$$PWD/imagecache/imagecachecollectorinterface.h \
|
$$PWD/imagecache/imagecachecollectorinterface.h \
|
||||||
$$PWD/imagecache/imagecacheconnectionmanager.h \
|
$$PWD/imagecache/imagecacheconnectionmanager.h \
|
||||||
$$PWD/imagecache/imagecachegeneratorinterface.h \
|
$$PWD/imagecache/imagecachegeneratorinterface.h \
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "imagecache.h"
|
#include "asynchronousimagecache.h"
|
||||||
|
|
||||||
#include "imagecachegenerator.h"
|
#include "imagecachegenerator.h"
|
||||||
#include "imagecachestorage.h"
|
#include "imagecachestorage.h"
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
ImageCache::ImageCache(ImageCacheStorageInterface &storage,
|
AsynchronousImageCache::AsynchronousImageCache(ImageCacheStorageInterface &storage,
|
||||||
ImageCacheGeneratorInterface &generator,
|
ImageCacheGeneratorInterface &generator,
|
||||||
TimeStampProviderInterface &timeStampProvider)
|
TimeStampProviderInterface &timeStampProvider)
|
||||||
: m_storage(storage)
|
: m_storage(storage)
|
||||||
@@ -44,10 +44,11 @@ ImageCache::ImageCache(ImageCacheStorageInterface &storage,
|
|||||||
while (isRunning()) {
|
while (isRunning()) {
|
||||||
if (auto [hasEntry, entry] = getEntry(); hasEntry) {
|
if (auto [hasEntry, entry] = getEntry(); hasEntry) {
|
||||||
request(entry.name,
|
request(entry.name,
|
||||||
entry.state,
|
entry.extraId,
|
||||||
entry.requestType,
|
entry.requestType,
|
||||||
std::move(entry.captureCallback),
|
std::move(entry.captureCallback),
|
||||||
std::move(entry.abortCallback),
|
std::move(entry.abortCallback),
|
||||||
|
std::move(entry.auxiliaryData),
|
||||||
m_storage,
|
m_storage,
|
||||||
m_generator,
|
m_generator,
|
||||||
m_timeStampProvider);
|
m_timeStampProvider);
|
||||||
@@ -58,26 +59,27 @@ ImageCache::ImageCache(ImageCacheStorageInterface &storage,
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageCache::~ImageCache()
|
AsynchronousImageCache::~AsynchronousImageCache()
|
||||||
{
|
{
|
||||||
clean();
|
clean();
|
||||||
wait();
|
wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageCache::request(Utils::SmallStringView name,
|
void AsynchronousImageCache::request(Utils::SmallStringView name,
|
||||||
Utils::SmallStringView state,
|
Utils::SmallStringView extraId,
|
||||||
ImageCache::RequestType requestType,
|
AsynchronousImageCache::RequestType requestType,
|
||||||
ImageCache::CaptureCallback captureCallback,
|
AsynchronousImageCache::CaptureImageCallback captureCallback,
|
||||||
ImageCache::AbortCallback abortCallback,
|
AsynchronousImageCache::AbortCallback abortCallback,
|
||||||
|
ImageCache::AuxiliaryData auxiliaryData,
|
||||||
ImageCacheStorageInterface &storage,
|
ImageCacheStorageInterface &storage,
|
||||||
ImageCacheGeneratorInterface &generator,
|
ImageCacheGeneratorInterface &generator,
|
||||||
TimeStampProviderInterface &timeStampProvider)
|
TimeStampProviderInterface &timeStampProvider)
|
||||||
{
|
{
|
||||||
const auto id = state.empty() ? Utils::PathString{name} : Utils::PathString{name, "+", state};
|
const auto id = extraId.empty() ? Utils::PathString{name} : Utils::PathString{name, "+", extraId};
|
||||||
|
|
||||||
const auto timeStamp = timeStampProvider.timeStamp(name);
|
const auto timeStamp = timeStampProvider.timeStamp(name);
|
||||||
const auto entry = requestType == RequestType::Image ? storage.fetchImage(id, timeStamp)
|
const auto entry = requestType == RequestType::Image ? storage.fetchImage(id, timeStamp)
|
||||||
: storage.fetchIcon(id, timeStamp);
|
: storage.fetchSmallImage(id, timeStamp);
|
||||||
|
|
||||||
if (entry.hasEntry) {
|
if (entry.hasEntry) {
|
||||||
if (entry.image.isNull())
|
if (entry.image.isNull())
|
||||||
@@ -85,15 +87,20 @@ void ImageCache::request(Utils::SmallStringView name,
|
|||||||
else
|
else
|
||||||
captureCallback(entry.image);
|
captureCallback(entry.image);
|
||||||
} else {
|
} else {
|
||||||
|
auto callback = [captureCallback = std::move(captureCallback),
|
||||||
|
requestType](const QImage &image, const QImage &smallImage) {
|
||||||
|
captureCallback(requestType == RequestType::Image ? image : smallImage);
|
||||||
|
};
|
||||||
generator.generateImage(name,
|
generator.generateImage(name,
|
||||||
state,
|
extraId,
|
||||||
timeStamp,
|
timeStamp,
|
||||||
std::move(captureCallback),
|
std::move(callback),
|
||||||
std::move(abortCallback));
|
std::move(abortCallback),
|
||||||
|
std::move(auxiliaryData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageCache::wait()
|
void AsynchronousImageCache::wait()
|
||||||
{
|
{
|
||||||
stopThread();
|
stopThread();
|
||||||
m_condition.notify_all();
|
m_condition.notify_all();
|
||||||
@@ -101,46 +108,50 @@ void ImageCache::wait()
|
|||||||
m_backgroundThread.join();
|
m_backgroundThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageCache::requestImage(Utils::PathString name,
|
void AsynchronousImageCache::requestImage(Utils::PathString name,
|
||||||
ImageCache::CaptureCallback captureCallback,
|
AsynchronousImageCache::CaptureImageCallback captureCallback,
|
||||||
AbortCallback abortCallback,
|
AbortCallback abortCallback,
|
||||||
Utils::SmallString state)
|
Utils::SmallString extraId,
|
||||||
|
ImageCache::AuxiliaryData auxiliaryData)
|
||||||
{
|
{
|
||||||
addEntry(std::move(name),
|
addEntry(std::move(name),
|
||||||
std::move(state),
|
std::move(extraId),
|
||||||
std::move(captureCallback),
|
std::move(captureCallback),
|
||||||
std::move(abortCallback),
|
std::move(abortCallback),
|
||||||
|
std::move(auxiliaryData),
|
||||||
RequestType::Image);
|
RequestType::Image);
|
||||||
m_condition.notify_all();
|
m_condition.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageCache::requestIcon(Utils::PathString name,
|
void AsynchronousImageCache::requestSmallImage(Utils::PathString name,
|
||||||
ImageCache::CaptureCallback captureCallback,
|
AsynchronousImageCache::CaptureImageCallback captureCallback,
|
||||||
ImageCache::AbortCallback abortCallback,
|
AsynchronousImageCache::AbortCallback abortCallback,
|
||||||
Utils::SmallString state)
|
Utils::SmallString extraId,
|
||||||
|
ImageCache::AuxiliaryData auxiliaryData)
|
||||||
{
|
{
|
||||||
addEntry(std::move(name),
|
addEntry(std::move(name),
|
||||||
std::move(state),
|
std::move(extraId),
|
||||||
std::move(captureCallback),
|
std::move(captureCallback),
|
||||||
std::move(abortCallback),
|
std::move(abortCallback),
|
||||||
RequestType::Icon);
|
std::move(auxiliaryData),
|
||||||
|
RequestType::SmallImage);
|
||||||
m_condition.notify_all();
|
m_condition.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageCache::clean()
|
void AsynchronousImageCache::clean()
|
||||||
{
|
{
|
||||||
clearEntries();
|
clearEntries();
|
||||||
m_generator.clean();
|
m_generator.clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageCache::waitForFinished()
|
void AsynchronousImageCache::waitForFinished()
|
||||||
{
|
{
|
||||||
wait();
|
wait();
|
||||||
|
|
||||||
m_generator.waitForFinished();
|
m_generator.waitForFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<bool, ImageCache::Entry> ImageCache::getEntry()
|
std::tuple<bool, AsynchronousImageCache::Entry> AsynchronousImageCache::getEntry()
|
||||||
{
|
{
|
||||||
std::unique_lock lock{m_mutex};
|
std::unique_lock lock{m_mutex};
|
||||||
|
|
||||||
@@ -153,22 +164,24 @@ std::tuple<bool, ImageCache::Entry> ImageCache::getEntry()
|
|||||||
return {true, entry};
|
return {true, entry};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageCache::addEntry(Utils::PathString &&name,
|
void AsynchronousImageCache::addEntry(Utils::PathString &&name,
|
||||||
Utils::SmallString &&state,
|
Utils::SmallString &&extraId,
|
||||||
ImageCache::CaptureCallback &&captureCallback,
|
AsynchronousImageCache::CaptureImageCallback &&captureCallback,
|
||||||
AbortCallback &&abortCallback,
|
AbortCallback &&abortCallback,
|
||||||
|
ImageCache::AuxiliaryData &&auxiliaryData,
|
||||||
RequestType requestType)
|
RequestType requestType)
|
||||||
{
|
{
|
||||||
std::unique_lock lock{m_mutex};
|
std::unique_lock lock{m_mutex};
|
||||||
|
|
||||||
m_entries.emplace_back(std::move(name),
|
m_entries.emplace_back(std::move(name),
|
||||||
std::move(state),
|
std::move(extraId),
|
||||||
std::move(captureCallback),
|
std::move(captureCallback),
|
||||||
std::move(abortCallback),
|
std::move(abortCallback),
|
||||||
|
std::move(auxiliaryData),
|
||||||
requestType);
|
requestType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageCache::clearEntries()
|
void AsynchronousImageCache::clearEntries()
|
||||||
{
|
{
|
||||||
std::unique_lock lock{m_mutex};
|
std::unique_lock lock{m_mutex};
|
||||||
for (Entry &entry : m_entries)
|
for (Entry &entry : m_entries)
|
||||||
@@ -176,20 +189,20 @@ void ImageCache::clearEntries()
|
|||||||
m_entries.clear();
|
m_entries.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageCache::waitForEntries()
|
void AsynchronousImageCache::waitForEntries()
|
||||||
{
|
{
|
||||||
std::unique_lock lock{m_mutex};
|
std::unique_lock lock{m_mutex};
|
||||||
if (m_entries.empty())
|
if (m_entries.empty())
|
||||||
m_condition.wait(lock, [&] { return m_entries.size() || m_finishing; });
|
m_condition.wait(lock, [&] { return m_entries.size() || m_finishing; });
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageCache::stopThread()
|
void AsynchronousImageCache::stopThread()
|
||||||
{
|
{
|
||||||
std::unique_lock lock{m_mutex};
|
std::unique_lock lock{m_mutex};
|
||||||
m_finishing = true;
|
m_finishing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImageCache::isRunning()
|
bool AsynchronousImageCache::isRunning()
|
||||||
{
|
{
|
||||||
std::unique_lock lock{m_mutex};
|
std::unique_lock lock{m_mutex};
|
||||||
return !m_finishing || m_entries.size();
|
return !m_finishing || m_entries.size();
|
||||||
@@ -68,6 +68,7 @@ ImageCacheCollector::~ImageCacheCollector() = default;
|
|||||||
|
|
||||||
void ImageCacheCollector::start(Utils::SmallStringView name,
|
void ImageCacheCollector::start(Utils::SmallStringView name,
|
||||||
Utils::SmallStringView state,
|
Utils::SmallStringView state,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData,
|
||||||
CaptureCallback captureCallback,
|
CaptureCallback captureCallback,
|
||||||
AbortCallback abortCallback)
|
AbortCallback abortCallback)
|
||||||
{
|
{
|
||||||
@@ -97,7 +98,15 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
|
|||||||
if (stateNode.isValid())
|
if (stateNode.isValid())
|
||||||
rewriterView.setCurrentStateNode(stateNode);
|
rewriterView.setCurrentStateNode(stateNode);
|
||||||
|
|
||||||
m_connectionManager.setCallback(std::move(captureCallback));
|
auto callback = [captureCallback = std::move(captureCallback)](QImage &&image) {
|
||||||
|
QSize smallImageSize = image.size().scaled(QSize{96, 96}.boundedTo(image.size()),
|
||||||
|
Qt::KeepAspectRatio);
|
||||||
|
QImage smallImage = image.isNull() ? QImage{} : image.scaled(smallImageSize);
|
||||||
|
|
||||||
|
captureCallback(std::move(image), std::move(smallImage));
|
||||||
|
};
|
||||||
|
|
||||||
|
m_connectionManager.setCallback(std::move(callback));
|
||||||
|
|
||||||
nodeInstanceView.setTarget(m_target.data());
|
nodeInstanceView.setTarget(m_target.data());
|
||||||
nodeInstanceView.setCrashCallback(abortCallback);
|
nodeInstanceView.setCrashCallback(abortCallback);
|
||||||
@@ -115,6 +124,20 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
|
|||||||
abortCallback();
|
abortCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<QImage, QImage> ImageCacheCollector::createImage(Utils::SmallStringView filePath,
|
||||||
|
Utils::SmallStringView state,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon ImageCacheCollector::createIcon(Utils::SmallStringView filePath,
|
||||||
|
Utils::SmallStringView state,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void ImageCacheCollector::setTarget(ProjectExplorer::Target *target)
|
void ImageCacheCollector::setTarget(ProjectExplorer::Target *target)
|
||||||
{
|
{
|
||||||
m_target = target;
|
m_target = target;
|
||||||
|
|||||||
@@ -54,9 +54,18 @@ public:
|
|||||||
|
|
||||||
void start(Utils::SmallStringView filePath,
|
void start(Utils::SmallStringView filePath,
|
||||||
Utils::SmallStringView state,
|
Utils::SmallStringView state,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData,
|
||||||
CaptureCallback captureCallback,
|
CaptureCallback captureCallback,
|
||||||
AbortCallback abortCallback) override;
|
AbortCallback abortCallback) override;
|
||||||
|
|
||||||
|
std::pair<QImage, QImage> createImage(Utils::SmallStringView filePath,
|
||||||
|
Utils::SmallStringView state,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData) override;
|
||||||
|
|
||||||
|
QIcon createIcon(Utils::SmallStringView filePath,
|
||||||
|
Utils::SmallStringView state,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData) override;
|
||||||
|
|
||||||
void setTarget(ProjectExplorer::Target *target);
|
void setTarget(ProjectExplorer::Target *target);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <imagecacheauxiliarydata.h>
|
||||||
#include <utils/smallstringview.h>
|
#include <utils/smallstringview.h>
|
||||||
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
@@ -34,15 +35,26 @@ namespace QmlDesigner {
|
|||||||
class ImageCacheCollectorInterface
|
class ImageCacheCollectorInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using CaptureCallback = std::function<void(QImage &&image)>;
|
using CaptureCallback = std::function<void(QImage &&image, QImage &&smallImage)>;
|
||||||
using AbortCallback = std::function<void()>;
|
using AbortCallback = std::function<void()>;
|
||||||
|
using ImagePair = std::pair<QImage, QImage>;
|
||||||
|
|
||||||
virtual void start(Utils::SmallStringView filePath,
|
virtual void start(Utils::SmallStringView filePath,
|
||||||
Utils::SmallStringView state,
|
Utils::SmallStringView extraId,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData,
|
||||||
CaptureCallback captureCallback,
|
CaptureCallback captureCallback,
|
||||||
AbortCallback abortCallback)
|
AbortCallback abortCallback)
|
||||||
= 0;
|
= 0;
|
||||||
|
|
||||||
|
virtual ImagePair createImage(Utils::SmallStringView filePath,
|
||||||
|
Utils::SmallStringView extraId,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData)
|
||||||
|
= 0;
|
||||||
|
virtual QIcon createIcon(Utils::SmallStringView filePath,
|
||||||
|
Utils::SmallStringView extraId,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData)
|
||||||
|
= 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~ImageCacheCollectorInterface() = default;
|
~ImageCacheCollectorInterface() = default;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ ImageCacheFontCollector::ImageCacheFontCollector() = default;
|
|||||||
|
|
||||||
ImageCacheFontCollector::~ImageCacheFontCollector() = default;
|
ImageCacheFontCollector::~ImageCacheFontCollector() = default;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
QByteArray fileToByteArray(QString const &filename)
|
QByteArray fileToByteArray(QString const &filename)
|
||||||
{
|
{
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
@@ -53,29 +55,17 @@ QByteArray fileToByteArray(QString const &filename)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void ImageCacheFontCollector::start(Utils::SmallStringView name,
|
void ImageCacheFontCollector::start(Utils::SmallStringView name,
|
||||||
Utils::SmallStringView state,
|
Utils::SmallStringView,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryDataValue,
|
||||||
CaptureCallback captureCallback,
|
CaptureCallback captureCallback,
|
||||||
AbortCallback abortCallback)
|
AbortCallback abortCallback)
|
||||||
{
|
{
|
||||||
// State contains size, text color, and sample text
|
auto &&auxiliaryData = std::get<ImageCache::FontCollectorSizeAuxiliaryData>(auxiliaryDataValue);
|
||||||
QStringList hints = QString(state).split('@');
|
QColor textColor = auxiliaryData.colorName;
|
||||||
int dim(300);
|
QSize size = auxiliaryData.size;
|
||||||
if (hints.size() >= 1) {
|
|
||||||
bool ok = false;
|
|
||||||
int newDim = QString(hints[0]).toInt(&ok);
|
|
||||||
if (ok)
|
|
||||||
dim = newDim;
|
|
||||||
}
|
|
||||||
#ifndef QMLDESIGNER_TEST
|
|
||||||
QColor textColor(Theme::getColor(Theme::DStextColor));
|
|
||||||
#else
|
|
||||||
QColor textColor;
|
|
||||||
#endif
|
|
||||||
if (hints.size() >= 2)
|
|
||||||
textColor.setNamedColor(hints[1]);
|
|
||||||
QString text = hints.size() >= 3 ? hints[2] : "Abc";
|
|
||||||
QSize size(dim, dim);
|
|
||||||
QRect rect({0, 0}, size);
|
QRect rect({0, 0}, size);
|
||||||
|
|
||||||
QByteArray fontData(fileToByteArray(QString(name)));
|
QByteArray fontData(fileToByteArray(QString(name)));
|
||||||
@@ -86,8 +76,7 @@ void ImageCacheFontCollector::start(Utils::SmallStringView name,
|
|||||||
const QStringList families = QFontDatabase::applicationFontFamilies(fontId);
|
const QStringList families = QFontDatabase::applicationFontFamilies(fontId);
|
||||||
if (!families.isEmpty()) {
|
if (!families.isEmpty()) {
|
||||||
QString fontFamily = families.first();
|
QString fontFamily = families.first();
|
||||||
if (text.contains("%1"))
|
QString text = fontFamily + "\n\n" + auxiliaryData.text;
|
||||||
text = text.arg(fontFamily);
|
|
||||||
QFont font(fontFamily);
|
QFont font(fontFamily);
|
||||||
font.setStyle(rawFont.style());
|
font.setStyle(rawFont.style());
|
||||||
font.setStyleName(rawFont.styleName());
|
font.setStyleName(rawFont.styleName());
|
||||||
@@ -120,7 +109,7 @@ void ImageCacheFontCollector::start(Utils::SmallStringView name,
|
|||||||
painter.setFont(font);
|
painter.setFont(font);
|
||||||
painter.drawText(rect, flags, text);
|
painter.drawText(rect, flags, text);
|
||||||
|
|
||||||
captureCallback(std::move(image));
|
captureCallback(std::move(image), {});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QFontDatabase::removeApplicationFont(fontId);
|
QFontDatabase::removeApplicationFont(fontId);
|
||||||
@@ -129,4 +118,133 @@ void ImageCacheFontCollector::start(Utils::SmallStringView name,
|
|||||||
abortCallback();
|
abortCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<QImage, QImage> ImageCacheFontCollector::createImage(
|
||||||
|
Utils::SmallStringView name,
|
||||||
|
Utils::SmallStringView,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryDataValue)
|
||||||
|
{
|
||||||
|
auto &&auxiliaryData = std::get<ImageCache::FontCollectorSizeAuxiliaryData>(auxiliaryDataValue);
|
||||||
|
QColor textColor = auxiliaryData.colorName;
|
||||||
|
QSize size = auxiliaryData.size;
|
||||||
|
QRect rect({0, 0}, size);
|
||||||
|
|
||||||
|
QByteArray fontData(fileToByteArray(QString(name)));
|
||||||
|
if (!fontData.isEmpty()) {
|
||||||
|
int fontId = QFontDatabase::addApplicationFontFromData(fontData);
|
||||||
|
if (fontId != -1) {
|
||||||
|
QRawFont rawFont(fontData, 10.); // Pixel size is irrelevant, we only need style/weight
|
||||||
|
const QStringList families = QFontDatabase::applicationFontFamilies(fontId);
|
||||||
|
if (!families.isEmpty()) {
|
||||||
|
QString fontFamily = families.first();
|
||||||
|
QString text = fontFamily + "\n\n" + auxiliaryData.text;
|
||||||
|
QFont font(fontFamily);
|
||||||
|
font.setStyle(rawFont.style());
|
||||||
|
font.setStyleName(rawFont.styleName());
|
||||||
|
font.setWeight(rawFont.weight());
|
||||||
|
QImage image(size, QImage::Format_ARGB32);
|
||||||
|
image.fill(Qt::transparent);
|
||||||
|
int pixelSize(200);
|
||||||
|
int flags = Qt::AlignCenter;
|
||||||
|
while (pixelSize >= 2) {
|
||||||
|
font.setPixelSize(pixelSize);
|
||||||
|
QFontMetrics fm(font, &image);
|
||||||
|
QRect bounds = fm.boundingRect(rect, flags, text);
|
||||||
|
if (bounds.width() < rect.width() && bounds.height() < rect.height()) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
int newPixelSize = pixelSize - 1;
|
||||||
|
if (bounds.width() >= rect.width())
|
||||||
|
newPixelSize = int(qreal(pixelSize) * qreal(rect.width())
|
||||||
|
/ qreal(bounds.width()));
|
||||||
|
else if (bounds.height() >= rect.height())
|
||||||
|
newPixelSize = int(qreal(pixelSize) * qreal(rect.height())
|
||||||
|
/ qreal(bounds.height()));
|
||||||
|
if (newPixelSize < pixelSize)
|
||||||
|
pixelSize = newPixelSize;
|
||||||
|
else
|
||||||
|
--pixelSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainter painter(&image);
|
||||||
|
painter.setPen(textColor);
|
||||||
|
painter.setFont(font);
|
||||||
|
painter.drawText(rect, flags, text);
|
||||||
|
|
||||||
|
return {image, {}};
|
||||||
|
}
|
||||||
|
QFontDatabase::removeApplicationFont(fontId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon ImageCacheFontCollector::createIcon(Utils::SmallStringView name,
|
||||||
|
Utils::SmallStringView,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryDataValue)
|
||||||
|
{
|
||||||
|
auto &&auxiliaryData = std::get<ImageCache::FontCollectorSizesAuxiliaryData>(auxiliaryDataValue);
|
||||||
|
QColor textColor = auxiliaryData.colorName;
|
||||||
|
auto sizes = auxiliaryData.sizes;
|
||||||
|
|
||||||
|
QIcon icon;
|
||||||
|
|
||||||
|
QByteArray fontData(fileToByteArray(QString(name)));
|
||||||
|
if (!fontData.isEmpty()) {
|
||||||
|
int fontId = QFontDatabase::addApplicationFontFromData(fontData);
|
||||||
|
if (fontId != -1) {
|
||||||
|
QRawFont rawFont(fontData, 10.); // Pixel size is irrelevant, we only need style/weight
|
||||||
|
const QStringList families = QFontDatabase::applicationFontFamilies(fontId);
|
||||||
|
if (!families.isEmpty()) {
|
||||||
|
QString fontFamily = families.first();
|
||||||
|
QString text = auxiliaryData.text;
|
||||||
|
QFont font(fontFamily);
|
||||||
|
font.setStyle(rawFont.style());
|
||||||
|
font.setStyleName(rawFont.styleName());
|
||||||
|
font.setWeight(rawFont.weight());
|
||||||
|
for (QSize size : sizes) {
|
||||||
|
QPixmap pixmap(size);
|
||||||
|
pixmap.fill(Qt::transparent);
|
||||||
|
int pixelSize(200);
|
||||||
|
int flags = Qt::AlignCenter;
|
||||||
|
QRect rect({0, 0}, size);
|
||||||
|
while (pixelSize >= 2) {
|
||||||
|
font.setPixelSize(pixelSize);
|
||||||
|
QFontMetrics fm(font, &pixmap);
|
||||||
|
QRect bounds = fm.boundingRect(rect, flags, text);
|
||||||
|
if (bounds.width() < rect.width() && bounds.height() < rect.height()) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
int newPixelSize = pixelSize - 1;
|
||||||
|
if (bounds.width() >= rect.width())
|
||||||
|
newPixelSize = int(qreal(pixelSize) * qreal(rect.width())
|
||||||
|
/ qreal(bounds.width()));
|
||||||
|
else if (bounds.height() >= rect.height())
|
||||||
|
newPixelSize = int(qreal(pixelSize) * qreal(rect.height())
|
||||||
|
/ qreal(bounds.height()));
|
||||||
|
if (newPixelSize < pixelSize)
|
||||||
|
pixelSize = newPixelSize;
|
||||||
|
else
|
||||||
|
--pixelSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPainter painter(&pixmap);
|
||||||
|
painter.setPen(textColor);
|
||||||
|
painter.setFont(font);
|
||||||
|
painter.drawText(rect, flags, text);
|
||||||
|
|
||||||
|
icon.addPixmap(pixmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
QFontDatabase::removeApplicationFont(fontId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -37,9 +37,18 @@ public:
|
|||||||
~ImageCacheFontCollector();
|
~ImageCacheFontCollector();
|
||||||
|
|
||||||
void start(Utils::SmallStringView filePath,
|
void start(Utils::SmallStringView filePath,
|
||||||
Utils::SmallStringView state,
|
Utils::SmallStringView extraId,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData,
|
||||||
CaptureCallback captureCallback,
|
CaptureCallback captureCallback,
|
||||||
AbortCallback abortCallback) override;
|
AbortCallback abortCallback) override;
|
||||||
|
|
||||||
|
std::pair<QImage, QImage> createImage(Utils::SmallStringView filePath,
|
||||||
|
Utils::SmallStringView extraId,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData) override;
|
||||||
|
|
||||||
|
QIcon createIcon(Utils::SmallStringView filePath,
|
||||||
|
Utils::SmallStringView extraId,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -47,17 +47,18 @@ ImageCacheGenerator::~ImageCacheGenerator()
|
|||||||
waitForFinished();
|
waitForFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageCacheGenerator::generateImage(
|
void ImageCacheGenerator::generateImage(Utils::SmallStringView name,
|
||||||
Utils::SmallStringView name,
|
Utils::SmallStringView extraId,
|
||||||
Utils::SmallStringView state,
|
|
||||||
Sqlite::TimeStamp timeStamp,
|
Sqlite::TimeStamp timeStamp,
|
||||||
ImageCacheGeneratorInterface::CaptureCallback &&captureCallback,
|
ImageCacheGeneratorInterface::CaptureCallback &&captureCallback,
|
||||||
AbortCallback &&abortCallback)
|
AbortCallback &&abortCallback,
|
||||||
|
ImageCache::AuxiliaryData &&auxiliaryData)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
std::lock_guard lock{m_mutex};
|
std::lock_guard lock{m_mutex};
|
||||||
m_tasks.emplace_back(name,
|
m_tasks.emplace_back(name,
|
||||||
state,
|
extraId,
|
||||||
|
std::move(auxiliaryData),
|
||||||
timeStamp,
|
timeStamp,
|
||||||
std::move(captureCallback),
|
std::move(captureCallback),
|
||||||
std::move(abortCallback));
|
std::move(abortCallback));
|
||||||
@@ -82,6 +83,12 @@ void ImageCacheGenerator::waitForFinished()
|
|||||||
if (m_backgroundThread)
|
if (m_backgroundThread)
|
||||||
m_backgroundThread->wait();
|
m_backgroundThread->wait();
|
||||||
}
|
}
|
||||||
|
namespace {
|
||||||
|
Utils::PathString createId(Utils::SmallStringView name, Utils::SmallStringView extraId)
|
||||||
|
{
|
||||||
|
return extraId.empty() ? Utils::PathString{name} : Utils::PathString{name, "+", extraId};
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void ImageCacheGenerator::startGeneration()
|
void ImageCacheGenerator::startGeneration()
|
||||||
{
|
{
|
||||||
@@ -105,18 +112,22 @@ void ImageCacheGenerator::startGeneration()
|
|||||||
|
|
||||||
m_collector.start(
|
m_collector.start(
|
||||||
task.filePath,
|
task.filePath,
|
||||||
task.state,
|
task.extraId,
|
||||||
[this, task](QImage &&image) {
|
std::move(task.auxiliaryData),
|
||||||
|
[this, task](QImage &&image, QImage &&smallImage) {
|
||||||
if (image.isNull())
|
if (image.isNull())
|
||||||
task.abortCallback();
|
task.abortCallback();
|
||||||
else
|
else
|
||||||
task.captureCallback(image);
|
task.captureCallback(image, smallImage);
|
||||||
|
|
||||||
m_storage.storeImage(std::move(task.filePath), task.timeStamp, image);
|
m_storage.storeImage(createId(task.filePath, task.extraId),
|
||||||
|
task.timeStamp,
|
||||||
|
image,
|
||||||
|
smallImage);
|
||||||
},
|
},
|
||||||
[this, task] {
|
[this, task] {
|
||||||
task.abortCallback();
|
task.abortCallback();
|
||||||
m_storage.storeImage(std::move(task.filePath), task.timeStamp, {});
|
m_storage.storeImage(createId(task.filePath, task.extraId), task.timeStamp, {}, {});
|
||||||
});
|
});
|
||||||
|
|
||||||
std::lock_guard lock{m_mutex};
|
std::lock_guard lock{m_mutex};
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "imagecachegeneratorinterface.h"
|
#include "imagecachegeneratorinterface.h"
|
||||||
|
|
||||||
|
#include <imagecacheauxiliarydata.h>
|
||||||
#include <utils/smallstring.h>
|
#include <utils/smallstring.h>
|
||||||
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
@@ -51,10 +52,11 @@ public:
|
|||||||
~ImageCacheGenerator();
|
~ImageCacheGenerator();
|
||||||
|
|
||||||
void generateImage(Utils::SmallStringView filePath,
|
void generateImage(Utils::SmallStringView filePath,
|
||||||
Utils::SmallStringView state,
|
Utils::SmallStringView extraId,
|
||||||
Sqlite::TimeStamp timeStamp,
|
Sqlite::TimeStamp timeStamp,
|
||||||
CaptureCallback &&captureCallback,
|
CaptureCallback &&captureCallback,
|
||||||
AbortCallback &&abortCallback) override;
|
AbortCallback &&abortCallback,
|
||||||
|
ImageCache::AuxiliaryData &&auxiliaryData) override;
|
||||||
void clean() override;
|
void clean() override;
|
||||||
|
|
||||||
void waitForFinished() override;
|
void waitForFinished() override;
|
||||||
@@ -64,19 +66,22 @@ private:
|
|||||||
{
|
{
|
||||||
Task() = default;
|
Task() = default;
|
||||||
Task(Utils::SmallStringView filePath,
|
Task(Utils::SmallStringView filePath,
|
||||||
Utils::SmallStringView state,
|
Utils::SmallStringView extraId,
|
||||||
|
ImageCache::AuxiliaryData &&auxiliaryData,
|
||||||
Sqlite::TimeStamp timeStamp,
|
Sqlite::TimeStamp timeStamp,
|
||||||
CaptureCallback &&captureCallback,
|
CaptureCallback &&captureCallback,
|
||||||
AbortCallback &&abortCallback)
|
AbortCallback &&abortCallback)
|
||||||
: filePath(filePath)
|
: filePath(filePath)
|
||||||
, state(std::move(state))
|
, extraId(std::move(extraId))
|
||||||
|
, auxiliaryData(std::move(auxiliaryData))
|
||||||
, captureCallback(std::move(captureCallback))
|
, captureCallback(std::move(captureCallback))
|
||||||
, abortCallback(std::move(abortCallback))
|
, abortCallback(std::move(abortCallback))
|
||||||
, timeStamp(timeStamp)
|
, timeStamp(timeStamp)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Utils::PathString filePath;
|
Utils::PathString filePath;
|
||||||
Utils::SmallString state;
|
Utils::SmallString extraId;
|
||||||
|
ImageCache::AuxiliaryData auxiliaryData;
|
||||||
CaptureCallback captureCallback;
|
CaptureCallback captureCallback;
|
||||||
AbortCallback abortCallback;
|
AbortCallback abortCallback;
|
||||||
Sqlite::TimeStamp timeStamp;
|
Sqlite::TimeStamp timeStamp;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <imagecacheauxiliarydata.h>
|
||||||
#include <sqlitetimestamp.h>
|
#include <sqlitetimestamp.h>
|
||||||
#include <utils/smallstringview.h>
|
#include <utils/smallstringview.h>
|
||||||
|
|
||||||
@@ -35,14 +36,15 @@ namespace QmlDesigner {
|
|||||||
class ImageCacheGeneratorInterface
|
class ImageCacheGeneratorInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using CaptureCallback = std::function<void(const QImage &image)>;
|
using CaptureCallback = std::function<void(const QImage &image, const QImage &smallImage)>;
|
||||||
using AbortCallback = std::function<void()>;
|
using AbortCallback = std::function<void()>;
|
||||||
|
|
||||||
virtual void generateImage(Utils::SmallStringView name,
|
virtual void generateImage(Utils::SmallStringView name,
|
||||||
Utils::SmallStringView state,
|
Utils::SmallStringView extraId,
|
||||||
Sqlite::TimeStamp timeStamp,
|
Sqlite::TimeStamp timeStamp,
|
||||||
CaptureCallback &&captureCallback,
|
CaptureCallback &&captureCallback,
|
||||||
AbortCallback &&abortCallback)
|
AbortCallback &&abortCallback,
|
||||||
|
ImageCache::AuxiliaryData &&auxiliaryData)
|
||||||
= 0;
|
= 0;
|
||||||
|
|
||||||
virtual void clean() = 0;
|
virtual void clean() = 0;
|
||||||
|
|||||||
@@ -34,8 +34,8 @@
|
|||||||
#include <sqlitewritestatement.h>
|
#include <sqlitewritestatement.h>
|
||||||
|
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QImageReader>
|
#include <QIcon>
|
||||||
#include <QImageWriter>
|
#include <QImage>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ public:
|
|||||||
transaction.commit();
|
transaction.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry fetchImage(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
|
ImageEntry fetchImage(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Sqlite::DeferredTransaction transaction{database};
|
Sqlite::DeferredTransaction transaction{database};
|
||||||
@@ -62,21 +62,37 @@ public:
|
|||||||
|
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
|
|
||||||
if (optionalBlob) {
|
if (optionalBlob)
|
||||||
QBuffer buffer{&optionalBlob->byteArray};
|
return {readImage(optionalBlob->byteArray), true};
|
||||||
QImageReader reader{&buffer, "PNG"};
|
|
||||||
|
|
||||||
return Entry{reader.read(), true};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
} catch (const Sqlite::StatementIsBusy &) {
|
} catch (const Sqlite::StatementIsBusy &) {
|
||||||
return fetchImage(name, minimumTimeStamp);
|
return fetchImage(name, minimumTimeStamp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry fetchIcon(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
|
ImageEntry fetchSmallImage(Utils::SmallStringView name,
|
||||||
|
Sqlite::TimeStamp minimumTimeStamp) const override
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Sqlite::DeferredTransaction transaction{database};
|
||||||
|
|
||||||
|
auto optionalBlob = selectSmallImageStatement.template value<Sqlite::ByteArrayBlob>(
|
||||||
|
name, minimumTimeStamp.value);
|
||||||
|
|
||||||
|
transaction.commit();
|
||||||
|
|
||||||
|
if (optionalBlob)
|
||||||
|
return ImageEntry{readImage(optionalBlob->byteArray), true};
|
||||||
|
|
||||||
|
return {};
|
||||||
|
|
||||||
|
} catch (const Sqlite::StatementIsBusy &) {
|
||||||
|
return fetchSmallImage(name, minimumTimeStamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconEntry fetchIcon(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Sqlite::DeferredTransaction transaction{database};
|
Sqlite::DeferredTransaction transaction{database};
|
||||||
@@ -86,12 +102,8 @@ public:
|
|||||||
|
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
|
|
||||||
if (optionalBlob) {
|
if (optionalBlob)
|
||||||
QBuffer buffer{&optionalBlob->byteArray};
|
return {readIcon(optionalBlob->byteArray), true};
|
||||||
QImageReader reader{&buffer, "PNG"};
|
|
||||||
|
|
||||||
return Entry{reader.read(), true};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
@@ -100,29 +112,40 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void storeImage(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QImage &image) override
|
void storeImage(Utils::SmallStringView name,
|
||||||
|
Sqlite::TimeStamp newTimeStamp,
|
||||||
|
const QImage &image,
|
||||||
|
const QImage &smallImage) override
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Sqlite::ImmediateTransaction transaction{database};
|
Sqlite::ImmediateTransaction transaction{database};
|
||||||
|
|
||||||
if (image.isNull()) {
|
auto imageBuffer = createBuffer(image);
|
||||||
|
auto smallImageBuffer = createBuffer(smallImage);
|
||||||
upsertImageStatement.write(name,
|
upsertImageStatement.write(name,
|
||||||
newTimeStamp.value,
|
newTimeStamp.value,
|
||||||
Sqlite::NullValue{},
|
createBlobView(imageBuffer.get()),
|
||||||
Sqlite::NullValue{});
|
createBlobView(smallImageBuffer.get()));
|
||||||
} else {
|
|
||||||
QSize iconSize = image.size().scaled(QSize{96, 96}.boundedTo(image.size()),
|
|
||||||
Qt::KeepAspectRatio);
|
|
||||||
QImage icon = image.scaled(iconSize);
|
|
||||||
upsertImageStatement.write(name,
|
|
||||||
newTimeStamp.value,
|
|
||||||
Sqlite::BlobView{createImageBuffer(image)->data()},
|
|
||||||
Sqlite::BlobView{createImageBuffer(icon)->data()});
|
|
||||||
}
|
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
|
|
||||||
} catch (const Sqlite::StatementIsBusy &) {
|
} catch (const Sqlite::StatementIsBusy &) {
|
||||||
return storeImage(name, newTimeStamp, image);
|
return storeImage(name, newTimeStamp, image, smallImage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void storeIcon(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QIcon &icon)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
Sqlite::ImmediateTransaction transaction{database};
|
||||||
|
|
||||||
|
auto iconBuffer = createBuffer(icon);
|
||||||
|
upsertIconStatement.write(name, newTimeStamp.value, createBlobView(iconBuffer.get()));
|
||||||
|
|
||||||
|
transaction.commit();
|
||||||
|
|
||||||
|
} catch (const Sqlite::StatementIsBusy &) {
|
||||||
|
return storeIcon(name, newTimeStamp, icon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,41 +179,113 @@ private:
|
|||||||
|
|
||||||
void createImagesTable(DatabaseType &database)
|
void createImagesTable(DatabaseType &database)
|
||||||
{
|
{
|
||||||
Sqlite::Table table;
|
Sqlite::Table imageTable;
|
||||||
table.setUseIfNotExists(true);
|
imageTable.setUseIfNotExists(true);
|
||||||
table.setName("images");
|
imageTable.setName("images");
|
||||||
table.addColumn("id", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
imageTable.addColumn("id", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||||
table.addColumn("name", Sqlite::ColumnType::Text, {Sqlite::NotNull{}, Sqlite::Unique{}});
|
imageTable.addColumn("name",
|
||||||
table.addColumn("mtime", Sqlite::ColumnType::Integer);
|
Sqlite::ColumnType::Text,
|
||||||
table.addColumn("image", Sqlite::ColumnType::Blob);
|
{Sqlite::NotNull{}, Sqlite::Unique{}});
|
||||||
table.addColumn("icon", Sqlite::ColumnType::Blob);
|
imageTable.addColumn("mtime", Sqlite::ColumnType::Integer);
|
||||||
|
imageTable.addColumn("image", Sqlite::ColumnType::Blob);
|
||||||
|
imageTable.addColumn("smallImage", Sqlite::ColumnType::Blob);
|
||||||
|
|
||||||
table.initialize(database);
|
imageTable.initialize(database);
|
||||||
|
|
||||||
|
Sqlite::Table iconTable;
|
||||||
|
iconTable.setUseIfNotExists(true);
|
||||||
|
iconTable.setName("icons");
|
||||||
|
iconTable.addColumn("id", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||||
|
iconTable.addColumn("name",
|
||||||
|
Sqlite::ColumnType::Text,
|
||||||
|
{Sqlite::NotNull{}, Sqlite::Unique{}});
|
||||||
|
iconTable.addColumn("mtime", Sqlite::ColumnType::Integer);
|
||||||
|
iconTable.addColumn("icon", Sqlite::ColumnType::Blob);
|
||||||
|
|
||||||
|
iconTable.initialize(database);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<QBuffer> createImageBuffer(const QImage &image)
|
Sqlite::BlobView createBlobView(QBuffer *buffer)
|
||||||
{
|
{
|
||||||
|
if (buffer)
|
||||||
|
return Sqlite::BlobView{buffer->data()};
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<QBuffer> createBuffer(const QImage &image)
|
||||||
|
{
|
||||||
|
if (image.isNull())
|
||||||
|
return {};
|
||||||
|
|
||||||
auto buffer = std::make_unique<QBuffer>();
|
auto buffer = std::make_unique<QBuffer>();
|
||||||
buffer->open(QIODevice::WriteOnly);
|
buffer->open(QIODevice::WriteOnly);
|
||||||
QImageWriter writer{buffer.get(), "PNG"};
|
QDataStream out{buffer.get()};
|
||||||
writer.write(image);
|
|
||||||
|
out << image;
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<QBuffer> createBuffer(const QIcon &icon)
|
||||||
|
{
|
||||||
|
if (icon.isNull())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto buffer = std::make_unique<QBuffer>();
|
||||||
|
buffer->open(QIODevice::WriteOnly);
|
||||||
|
QDataStream out{buffer.get()};
|
||||||
|
|
||||||
|
out << icon;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QIcon readIcon(const QByteArray &byteArray)
|
||||||
|
{
|
||||||
|
QIcon icon;
|
||||||
|
QBuffer buffer;
|
||||||
|
buffer.setData(byteArray);
|
||||||
|
buffer.open(QIODevice::ReadOnly);
|
||||||
|
QDataStream in{&buffer};
|
||||||
|
|
||||||
|
in >> icon;
|
||||||
|
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QImage readImage(const QByteArray &byteArray)
|
||||||
|
{
|
||||||
|
QImage image;
|
||||||
|
QBuffer buffer;
|
||||||
|
buffer.setData(byteArray);
|
||||||
|
buffer.open(QIODevice::ReadOnly);
|
||||||
|
QDataStream in{&buffer};
|
||||||
|
|
||||||
|
in >> image;
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DatabaseType &database;
|
DatabaseType &database;
|
||||||
Initializer initializer{database};
|
Initializer initializer{database};
|
||||||
Sqlite::ImmediateNonThrowingDestructorTransaction transaction{database};
|
Sqlite::ImmediateNonThrowingDestructorTransaction transaction{database};
|
||||||
mutable ReadStatement selectImageStatement{
|
mutable ReadStatement selectImageStatement{
|
||||||
"SELECT image FROM images WHERE name=?1 AND mtime >= ?2", database};
|
"SELECT image FROM images WHERE name=?1 AND mtime >= ?2", database};
|
||||||
|
mutable ReadStatement selectSmallImageStatement{
|
||||||
|
"SELECT smallImage FROM images WHERE name=?1 AND mtime >= ?2", database};
|
||||||
mutable ReadStatement selectIconStatement{
|
mutable ReadStatement selectIconStatement{
|
||||||
"SELECT icon FROM images WHERE name=?1 AND mtime >= ?2", database};
|
"SELECT icon FROM icons WHERE name=?1 AND mtime >= ?2", database};
|
||||||
WriteStatement upsertImageStatement{
|
WriteStatement upsertImageStatement{
|
||||||
"INSERT INTO images(name, mtime, image, icon) VALUES (?1, ?2, ?3, ?4) ON "
|
"INSERT INTO images(name, mtime, image, smallImage) VALUES (?1, ?2, ?3, ?4) ON "
|
||||||
"CONFLICT(name) DO UPDATE SET mtime=excluded.mtime, image=excluded.image, "
|
"CONFLICT(name) DO UPDATE SET mtime=excluded.mtime, image=excluded.image, "
|
||||||
"icon=excluded.icon",
|
"smallImage=excluded.smallImage",
|
||||||
|
database};
|
||||||
|
WriteStatement upsertIconStatement{
|
||||||
|
"INSERT INTO icons(name, mtime, icon) VALUES (?1, ?2, ?3) ON "
|
||||||
|
"CONFLICT(name) DO UPDATE SET mtime=excluded.mtime, icon=excluded.icon",
|
||||||
database};
|
database};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QIcon>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
|
||||||
#include <sqlitetimestamp.h>
|
#include <sqlitetimestamp.h>
|
||||||
@@ -32,23 +33,40 @@
|
|||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
class ImageCacheStorageEntry
|
class ImageCacheStorageImageEntry
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QImage image;
|
QImage image;
|
||||||
bool hasEntry = false;
|
bool hasEntry = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ImageCacheStorageIconEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QIcon icon;
|
||||||
|
bool hasEntry = false;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|
||||||
class ImageCacheStorageInterface
|
class ImageCacheStorageInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Entry = Internal::ImageCacheStorageEntry;
|
using ImageEntry = Internal::ImageCacheStorageImageEntry;
|
||||||
|
using IconEntry = Internal::ImageCacheStorageIconEntry;
|
||||||
|
|
||||||
virtual Entry fetchImage(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const = 0;
|
virtual ImageEntry fetchImage(Utils::SmallStringView name,
|
||||||
virtual Entry fetchIcon(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const = 0;
|
Sqlite::TimeStamp minimumTimeStamp) const = 0;
|
||||||
virtual void storeImage(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QImage &image) = 0;
|
virtual ImageEntry fetchSmallImage(Utils::SmallStringView name,
|
||||||
|
Sqlite::TimeStamp minimumTimeStamp) const = 0;
|
||||||
|
virtual IconEntry fetchIcon(Utils::SmallStringView name,
|
||||||
|
Sqlite::TimeStamp minimumTimeStamp) const = 0;
|
||||||
|
virtual void storeImage(Utils::SmallStringView name,
|
||||||
|
Sqlite::TimeStamp newTimeStamp,
|
||||||
|
const QImage &image,
|
||||||
|
const QImage &smallImage)
|
||||||
|
= 0;
|
||||||
|
virtual void storeIcon(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QIcon &icon) = 0;
|
||||||
virtual void walCheckpointFull() = 0;
|
virtual void walCheckpointFull() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "synchronousimagecache.h"
|
||||||
|
|
||||||
|
#include "imagecachecollectorinterface.h"
|
||||||
|
#include "imagecachestorage.h"
|
||||||
|
#include "timestampprovider.h"
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Utils::PathString createId(Utils::PathString filePath, Utils::SmallString extraId)
|
||||||
|
{
|
||||||
|
return extraId.empty() ? Utils::PathString{filePath} : Utils::PathString{filePath, "+", extraId};
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
QImage SynchronousImageCache::image(Utils::PathString filePath,
|
||||||
|
Utils::SmallString extraId,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData)
|
||||||
|
{
|
||||||
|
const auto id = createId(filePath, extraId);
|
||||||
|
|
||||||
|
const auto timeStamp = m_timeStampProvider.timeStamp(filePath);
|
||||||
|
const auto entry = m_storage.fetchImage(id, timeStamp);
|
||||||
|
|
||||||
|
if (entry.hasEntry)
|
||||||
|
return entry.image;
|
||||||
|
|
||||||
|
const auto &[image, smallImage] = m_collector.createImage(filePath, extraId, auxiliaryData);
|
||||||
|
|
||||||
|
m_storage.storeImage(id, timeStamp, image, smallImage);
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage SynchronousImageCache::smallImage(Utils::PathString filePath,
|
||||||
|
Utils::SmallString extraId,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData)
|
||||||
|
{
|
||||||
|
const auto id = createId(filePath, extraId);
|
||||||
|
|
||||||
|
const auto timeStamp = m_timeStampProvider.timeStamp(filePath);
|
||||||
|
const auto entry = m_storage.fetchSmallImage(id, timeStamp);
|
||||||
|
|
||||||
|
if (entry.hasEntry)
|
||||||
|
return entry.image;
|
||||||
|
|
||||||
|
const auto &[image, smallImage] = m_collector.createImage(filePath, extraId, auxiliaryData);
|
||||||
|
|
||||||
|
m_storage.storeImage(id, timeStamp, image, smallImage);
|
||||||
|
|
||||||
|
return smallImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon SynchronousImageCache::icon(Utils::PathString filePath,
|
||||||
|
Utils::SmallString extraId,
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData)
|
||||||
|
{
|
||||||
|
const auto id = createId(filePath, extraId);
|
||||||
|
|
||||||
|
const auto timeStamp = m_timeStampProvider.timeStamp(filePath);
|
||||||
|
const auto entry = m_storage.fetchIcon(id, timeStamp);
|
||||||
|
|
||||||
|
if (entry.hasEntry)
|
||||||
|
return entry.icon;
|
||||||
|
|
||||||
|
const auto icon = m_collector.createIcon(filePath, extraId, auxiliaryData);
|
||||||
|
|
||||||
|
m_storage.storeIcon(id, timeStamp, icon);
|
||||||
|
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "imagecacheinterface.h"
|
#include "asynchronousimagecacheinterface.h"
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -37,70 +37,78 @@ namespace QmlDesigner {
|
|||||||
class TimeStampProviderInterface;
|
class TimeStampProviderInterface;
|
||||||
class ImageCacheStorageInterface;
|
class ImageCacheStorageInterface;
|
||||||
class ImageCacheGeneratorInterface;
|
class ImageCacheGeneratorInterface;
|
||||||
|
class ImageCacheCollectorInterface;
|
||||||
|
|
||||||
class ImageCache final : public ImageCacheInterface
|
class AsynchronousImageCache final : public AsynchronousImageCacheInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using CaptureCallback = std::function<void(const QImage &)>;
|
using CaptureImageCallback = std::function<void(const QImage &)>;
|
||||||
using AbortCallback = std::function<void()>;
|
using AbortCallback = std::function<void()>;
|
||||||
|
|
||||||
~ImageCache();
|
~AsynchronousImageCache();
|
||||||
|
|
||||||
ImageCache(ImageCacheStorageInterface &storage,
|
AsynchronousImageCache(ImageCacheStorageInterface &storage,
|
||||||
ImageCacheGeneratorInterface &generator,
|
ImageCacheGeneratorInterface &generator,
|
||||||
TimeStampProviderInterface &timeStampProvider);
|
TimeStampProviderInterface &timeStampProvider);
|
||||||
|
|
||||||
void requestImage(Utils::PathString name,
|
void requestImage(Utils::PathString name,
|
||||||
CaptureCallback captureCallback,
|
CaptureImageCallback captureCallback,
|
||||||
AbortCallback abortCallback,
|
AbortCallback abortCallback,
|
||||||
Utils::SmallString state = {}) override;
|
Utils::SmallString extraId = {},
|
||||||
void requestIcon(Utils::PathString name,
|
ImageCache::AuxiliaryData auxiliaryData = {}) override;
|
||||||
CaptureCallback captureCallback,
|
void requestSmallImage(Utils::PathString name,
|
||||||
|
CaptureImageCallback captureCallback,
|
||||||
AbortCallback abortCallback,
|
AbortCallback abortCallback,
|
||||||
Utils::SmallString state = {}) override;
|
Utils::SmallString extraId = {},
|
||||||
|
ImageCache::AuxiliaryData auxiliaryData = {}) override;
|
||||||
|
|
||||||
void clean();
|
void clean();
|
||||||
void waitForFinished();
|
void waitForFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class RequestType { Image, Icon };
|
enum class RequestType { Image, SmallImage, Icon };
|
||||||
struct Entry
|
struct Entry
|
||||||
{
|
{
|
||||||
Entry() = default;
|
Entry() = default;
|
||||||
Entry(Utils::PathString name,
|
Entry(Utils::PathString name,
|
||||||
Utils::SmallString state,
|
Utils::SmallString extraId,
|
||||||
CaptureCallback &&captureCallback,
|
CaptureImageCallback &&captureCallback,
|
||||||
AbortCallback &&abortCallback,
|
AbortCallback &&abortCallback,
|
||||||
|
ImageCache::AuxiliaryData &&auxiliaryData,
|
||||||
RequestType requestType)
|
RequestType requestType)
|
||||||
: name{std::move(name)}
|
: name{std::move(name)}
|
||||||
, state{std::move(state)}
|
, extraId{std::move(extraId)}
|
||||||
, captureCallback{std::move(captureCallback)}
|
, captureCallback{std::move(captureCallback)}
|
||||||
, abortCallback{std::move(abortCallback)}
|
, abortCallback{std::move(abortCallback)}
|
||||||
|
, auxiliaryData{std::move(auxiliaryData)}
|
||||||
, requestType{requestType}
|
, requestType{requestType}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Utils::PathString name;
|
Utils::PathString name;
|
||||||
Utils::SmallString state;
|
Utils::SmallString extraId;
|
||||||
CaptureCallback captureCallback;
|
CaptureImageCallback captureCallback;
|
||||||
AbortCallback abortCallback;
|
AbortCallback abortCallback;
|
||||||
|
ImageCache::AuxiliaryData auxiliaryData;
|
||||||
RequestType requestType = RequestType::Image;
|
RequestType requestType = RequestType::Image;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::tuple<bool, Entry> getEntry();
|
std::tuple<bool, Entry> getEntry();
|
||||||
void addEntry(Utils::PathString &&name,
|
void addEntry(Utils::PathString &&name,
|
||||||
Utils::SmallString &&state,
|
Utils::SmallString &&extraId,
|
||||||
CaptureCallback &&captureCallback,
|
CaptureImageCallback &&captureCallback,
|
||||||
AbortCallback &&abortCallback,
|
AbortCallback &&abortCallback,
|
||||||
|
ImageCache::AuxiliaryData &&auxiliaryData,
|
||||||
RequestType requestType);
|
RequestType requestType);
|
||||||
void clearEntries();
|
void clearEntries();
|
||||||
void waitForEntries();
|
void waitForEntries();
|
||||||
void stopThread();
|
void stopThread();
|
||||||
bool isRunning();
|
bool isRunning();
|
||||||
static void request(Utils::SmallStringView name,
|
static void request(Utils::SmallStringView name,
|
||||||
Utils::SmallStringView state,
|
Utils::SmallStringView extraId,
|
||||||
ImageCache::RequestType requestType,
|
AsynchronousImageCache::RequestType requestType,
|
||||||
ImageCache::CaptureCallback captureCallback,
|
AsynchronousImageCache::CaptureImageCallback captureCallback,
|
||||||
ImageCache::AbortCallback abortCallback,
|
AsynchronousImageCache::AbortCallback abortCallback,
|
||||||
|
ImageCache::AuxiliaryData auxiliaryData,
|
||||||
ImageCacheStorageInterface &storage,
|
ImageCacheStorageInterface &storage,
|
||||||
ImageCacheGeneratorInterface &generator,
|
ImageCacheGeneratorInterface &generator,
|
||||||
TimeStampProviderInterface &timeStampProvider);
|
TimeStampProviderInterface &timeStampProvider);
|
||||||
@@ -25,13 +25,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "imagecacheauxiliarydata.h"
|
||||||
|
|
||||||
#include <utils/smallstring.h>
|
#include <utils/smallstring.h>
|
||||||
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class ImageCacheInterface
|
class AsynchronousImageCacheInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using CaptureCallback = std::function<void(const QImage &)>;
|
using CaptureCallback = std::function<void(const QImage &)>;
|
||||||
@@ -40,18 +42,20 @@ public:
|
|||||||
virtual void requestImage(Utils::PathString name,
|
virtual void requestImage(Utils::PathString name,
|
||||||
CaptureCallback captureCallback,
|
CaptureCallback captureCallback,
|
||||||
AbortCallback abortCallback,
|
AbortCallback abortCallback,
|
||||||
Utils::SmallString state = {})
|
Utils::SmallString extraId = {},
|
||||||
|
ImageCache::AuxiliaryData auxiliaryData = {})
|
||||||
= 0;
|
= 0;
|
||||||
virtual void requestIcon(Utils::PathString name,
|
virtual void requestSmallImage(Utils::PathString name,
|
||||||
CaptureCallback captureCallback,
|
CaptureCallback captureCallback,
|
||||||
AbortCallback abortCallback,
|
AbortCallback abortCallback,
|
||||||
Utils::SmallString state = {})
|
Utils::SmallString extraId = {},
|
||||||
|
ImageCache::AuxiliaryData auxiliaryData = {})
|
||||||
= 0;
|
= 0;
|
||||||
|
|
||||||
void clean();
|
void clean();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~ImageCacheInterface() = default;
|
~AsynchronousImageCacheInterface() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 <utils/span.h>
|
||||||
|
#include <utils/variant.h>
|
||||||
|
|
||||||
|
#include <QSize>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
namespace ImageCache {
|
||||||
|
|
||||||
|
class NullAuxiliaryData
|
||||||
|
{};
|
||||||
|
|
||||||
|
class FontCollectorSizeAuxiliaryData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QSize size;
|
||||||
|
QString colorName;
|
||||||
|
QString text;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FontCollectorSizesAuxiliaryData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Utils::span<const QSize> sizes;
|
||||||
|
QString colorName;
|
||||||
|
QString text;
|
||||||
|
};
|
||||||
|
|
||||||
|
using AuxiliaryData = std::variant<NullAuxiliaryData, FontCollectorSizeAuxiliaryData, FontCollectorSizesAuxiliaryData>;
|
||||||
|
|
||||||
|
} // namespace ImageCache
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "imagecacheauxiliarydata.h"
|
||||||
|
|
||||||
|
#include <utils/smallstring.h>
|
||||||
|
|
||||||
|
#include <QImage>
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class TimeStampProviderInterface;
|
||||||
|
class ImageCacheStorageInterface;
|
||||||
|
class ImageCacheGeneratorInterface;
|
||||||
|
class ImageCacheCollectorInterface;
|
||||||
|
|
||||||
|
class SynchronousImageCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using CaptureImageCallback = std::function<void(const QImage &)>;
|
||||||
|
using AbortCallback = std::function<void()>;
|
||||||
|
|
||||||
|
SynchronousImageCache(ImageCacheStorageInterface &storage,
|
||||||
|
TimeStampProviderInterface &timeStampProvider,
|
||||||
|
ImageCacheCollectorInterface &collector)
|
||||||
|
: m_storage(storage)
|
||||||
|
, m_timeStampProvider(timeStampProvider)
|
||||||
|
, m_collector(collector)
|
||||||
|
{}
|
||||||
|
|
||||||
|
QImage image(Utils::PathString filePath,
|
||||||
|
Utils::SmallString extraId = {},
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData = {});
|
||||||
|
QImage smallImage(Utils::PathString filePath,
|
||||||
|
Utils::SmallString extraId = {},
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData = {});
|
||||||
|
QIcon icon(Utils::PathString filePath,
|
||||||
|
Utils::SmallString extraId = {},
|
||||||
|
const ImageCache::AuxiliaryData &auxiliaryData = {});
|
||||||
|
|
||||||
|
private:
|
||||||
|
ImageCacheStorageInterface &m_storage;
|
||||||
|
TimeStampProviderInterface &m_timeStampProvider;
|
||||||
|
ImageCacheCollectorInterface &m_collector;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
||||||
@@ -47,7 +47,7 @@ class Edit3DView;
|
|||||||
namespace Internal { class DesignModeWidget; }
|
namespace Internal { class DesignModeWidget; }
|
||||||
|
|
||||||
class ViewManagerData;
|
class ViewManagerData;
|
||||||
class ImageCache;
|
class AsynchronousImageCache;
|
||||||
|
|
||||||
class QMLDESIGNERCORE_EXPORT ViewManager
|
class QMLDESIGNERCORE_EXPORT ViewManager
|
||||||
{
|
{
|
||||||
@@ -104,7 +104,7 @@ public:
|
|||||||
void disableStandardViews();
|
void disableStandardViews();
|
||||||
void enableStandardViews();
|
void enableStandardViews();
|
||||||
|
|
||||||
ImageCache &imageCache();
|
AsynchronousImageCache &imageCache();
|
||||||
|
|
||||||
private: // functions
|
private: // functions
|
||||||
Q_DISABLE_COPY(ViewManager)
|
Q_DISABLE_COPY(ViewManager)
|
||||||
|
|||||||
@@ -453,7 +453,7 @@ void ViewManager::enableStandardViews()
|
|||||||
attachViewsExceptRewriterAndComponetView();
|
attachViewsExceptRewriterAndComponetView();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageCache &ViewManager::imageCache()
|
AsynchronousImageCache &ViewManager::imageCache()
|
||||||
{
|
{
|
||||||
return d->itemLibraryView.imageCache();
|
return d->itemLibraryView.imageCache();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -567,7 +567,7 @@ void QmlDesignerPlugin::emitUsageStatisticsContextAction(const QString &identifi
|
|||||||
emitUsageStatistics(Constants::EVENT_ACTION_EXECUTED + identifier);
|
emitUsageStatistics(Constants::EVENT_ACTION_EXECUTED + identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageCache &QmlDesignerPlugin::imageCache()
|
AsynchronousImageCache &QmlDesignerPlugin::imageCache()
|
||||||
{
|
{
|
||||||
return m_instance->d->viewManager.imageCache();
|
return m_instance->d->viewManager.imageCache();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace Core {
|
|||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
class QmlDesignerPluginPrivate;
|
class QmlDesignerPluginPrivate;
|
||||||
class ImageCache;
|
class AsynchronousImageCache;
|
||||||
|
|
||||||
namespace Internal { class DesignModeWidget; }
|
namespace Internal { class DesignModeWidget; }
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ public:
|
|||||||
static void emitUsageStatisticsContextAction(const QString &identifier);
|
static void emitUsageStatisticsContextAction(const QString &identifier);
|
||||||
static void emitUsageStatisticsTime(const QString &identifier, int elapsed);
|
static void emitUsageStatisticsTime(const QString &identifier, int elapsed);
|
||||||
|
|
||||||
static ImageCache &imageCache();
|
static AsynchronousImageCache &imageCache();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void usageStatisticsNotifier(const QString &identifier);
|
void usageStatisticsNotifier(const QString &identifier);
|
||||||
|
|||||||
@@ -414,13 +414,15 @@ Project {
|
|||||||
"pluginmanager/widgetpluginmanager.h",
|
"pluginmanager/widgetpluginmanager.h",
|
||||||
"pluginmanager/widgetpluginpath.cpp",
|
"pluginmanager/widgetpluginpath.cpp",
|
||||||
"pluginmanager/widgetpluginpath.h",
|
"pluginmanager/widgetpluginpath.h",
|
||||||
"include/imagecache.h",
|
"include/asynchronousimagecache.h",
|
||||||
"include/imagecacheinterface.h",
|
"include/synchronousimagecache.h",
|
||||||
|
"include/imagecacheauxiliarydata.h",
|
||||||
|
"include/asynchronousimagecacheinterface.h",
|
||||||
"imagecache/imagecachecollector.cpp",
|
"imagecache/imagecachecollector.cpp",
|
||||||
"imagecache/imagecachecollector.h",
|
"imagecache/imagecachecollector.h",
|
||||||
"imagecache/imagecachefontcollector.cpp",
|
"imagecache/imagecachefontcollector.cpp",
|
||||||
"imagecache/imagecachefontcollector.h",
|
"imagecache/imagecachefontcollector.h",
|
||||||
"imagecache/imagecache.cpp",
|
"imagecache/asynchronousimagecache.cpp",
|
||||||
"imagecache/imagecachecollectorinterface.h",
|
"imagecache/imagecachecollectorinterface.h",
|
||||||
"imagecache/imagecacheconnectionmanager.cpp",
|
"imagecache/imagecacheconnectionmanager.cpp",
|
||||||
"imagecache/imagecacheconnectionmanager.h",
|
"imagecache/imagecacheconnectionmanager.h",
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ SOURCES += \
|
|||||||
$$PWD/designercore/model/annotation.cpp \
|
$$PWD/designercore/model/annotation.cpp \
|
||||||
$$PWD/designercore/rewritertransaction.cpp \
|
$$PWD/designercore/rewritertransaction.cpp \
|
||||||
$$PWD/components/listmodeleditor/listmodeleditormodel.cpp \
|
$$PWD/components/listmodeleditor/listmodeleditormodel.cpp \
|
||||||
$$PWD/designercore/imagecache/imagecache.cpp \
|
$$PWD/designercore/imagecache/asynchronousimagecache.cpp \
|
||||||
|
$$PWD/designercore/imagecache/synchronousimagecache.cpp \
|
||||||
$$PWD/designercore/imagecache/imagecachegenerator.cpp
|
$$PWD/designercore/imagecache/imagecachegenerator.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
@@ -42,8 +43,10 @@ HEADERS += \
|
|||||||
$$PWD/designercore/imagecache/imagecachestorageinterface.h \
|
$$PWD/designercore/imagecache/imagecachestorageinterface.h \
|
||||||
$$PWD/designercore/imagecache/imagecachegeneratorinterface.h \
|
$$PWD/designercore/imagecache/imagecachegeneratorinterface.h \
|
||||||
$$PWD/designercore/imagecache/timestampproviderinterface.h \
|
$$PWD/designercore/imagecache/timestampproviderinterface.h \
|
||||||
$$PWD/designercore/include/imagecache.h \
|
$$PWD/designercore/include/asynchronousimagecache.h \
|
||||||
$$PWD/designercore/include/imagecacheinterface.h \
|
$$PWD/designercore/include/synchronousimagecache.h \
|
||||||
|
$$PWD/designercore/include/imagecacheauxiliarydata.h \
|
||||||
|
$$PWD/designercore/include/asynchronousimagecacheinterface.h \
|
||||||
$$PWD/designercore/include/modelnode.h \
|
$$PWD/designercore/include/modelnode.h \
|
||||||
$$PWD/designercore/include/model.h \
|
$$PWD/designercore/include/model.h \
|
||||||
$$PWD/../../../share/qtcreator/qml/qmlpuppet/interfaces/commondefines.h \
|
$$PWD/../../../share/qtcreator/qml/qmlpuppet/interfaces/commondefines.h \
|
||||||
|
|||||||
@@ -179,7 +179,8 @@ add_qtc_test(unittest GTEST
|
|||||||
sqlstatementbuilder-test.cpp
|
sqlstatementbuilder-test.cpp
|
||||||
createtablesqlstatementbuilder-test.cpp
|
createtablesqlstatementbuilder-test.cpp
|
||||||
sqlitevalue-test.cpp
|
sqlitevalue-test.cpp
|
||||||
imagecache-test.cpp
|
asynchronousimagecache-test.cpp
|
||||||
|
synchronousimagecache-test.cpp
|
||||||
imagecachegenerator-test.cpp
|
imagecachegenerator-test.cpp
|
||||||
imagecachestorage-test.cpp
|
imagecachestorage-test.cpp
|
||||||
sqlitedatabasemock.h
|
sqlitedatabasemock.h
|
||||||
@@ -405,8 +406,10 @@ extend_qtc_test(unittest
|
|||||||
model/signalhandlerproperty.cpp include/signalhandlerproperty.h
|
model/signalhandlerproperty.cpp include/signalhandlerproperty.h
|
||||||
model/variantproperty.cpp include/variantproperty.h
|
model/variantproperty.cpp include/variantproperty.h
|
||||||
rewritertransaction.cpp rewritertransaction.h
|
rewritertransaction.cpp rewritertransaction.h
|
||||||
imagecache/imagecache.cpp include/imagecache.h
|
include/imagecacheauxiliarydata.h
|
||||||
include/imagecacheinterface.h
|
imagecache/synchronousimagecache.cpp include/synchronousimagecache.h
|
||||||
|
imagecache/asynchronousimagecache.cpp include/asynchronousimagecache.h
|
||||||
|
include/asynchronousimagecacheinterface.h
|
||||||
imagecache/imagecachecollectorinterface.h
|
imagecache/imagecachecollectorinterface.h
|
||||||
imagecache/imagecachegenerator.cpp imagecache/imagecachegenerator.h
|
imagecache/imagecachegenerator.cpp imagecache/imagecachegenerator.h
|
||||||
imagecache/imagecachegeneratorinterface.h
|
imagecache/imagecachegeneratorinterface.h
|
||||||
|
|||||||
467
tests/unit/unittest/asynchronousimagecache-test.cpp
Normal file
467
tests/unit/unittest/asynchronousimagecache-test.cpp
Normal file
@@ -0,0 +1,467 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2016 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 "googletest.h"
|
||||||
|
|
||||||
|
#include "mockimagecachegenerator.h"
|
||||||
|
#include "mockimagecachestorage.h"
|
||||||
|
#include "mocktimestampprovider.h"
|
||||||
|
#include "notification.h"
|
||||||
|
|
||||||
|
#include <asynchronousimagecache.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class AsynchronousImageCache : public testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
Notification notification;
|
||||||
|
Notification waitInThread;
|
||||||
|
NiceMock<MockFunction<void()>> mockAbortCallback;
|
||||||
|
NiceMock<MockFunction<void(const QImage &image)>> mockCaptureCallback;
|
||||||
|
NiceMock<MockImageCacheStorage> mockStorage;
|
||||||
|
NiceMock<MockImageCacheGenerator> mockGenerator;
|
||||||
|
NiceMock<MockTimeStampProvider> mockTimeStampProvider;
|
||||||
|
QmlDesigner::AsynchronousImageCache cache{mockStorage, mockGenerator, mockTimeStampProvider};
|
||||||
|
QImage image1{10, 10, QImage::Format_ARGB32};
|
||||||
|
QImage smallImage1{1, 1, QImage::Format_ARGB32};
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestImageFetchesImageFromStorage)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _))
|
||||||
|
.WillRepeatedly([&](Utils::SmallStringView, auto) {
|
||||||
|
notification.notify();
|
||||||
|
return QmlDesigner::ImageCacheStorageInterface::ImageEntry{{}, false};
|
||||||
|
});
|
||||||
|
|
||||||
|
cache.requestImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestImageFetchesImageFromStorageWithTimeStamp)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillRepeatedly(Return(Sqlite::TimeStamp{123}));
|
||||||
|
EXPECT_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
|
||||||
|
.WillRepeatedly([&](Utils::SmallStringView, auto) {
|
||||||
|
notification.notify();
|
||||||
|
return QmlDesigner::ImageCacheStorageInterface::ImageEntry{QImage{}, false};
|
||||||
|
});
|
||||||
|
|
||||||
|
cache.requestImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestImageCallsCaptureCallbackWithImageFromStorage)
|
||||||
|
{
|
||||||
|
ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _))
|
||||||
|
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{image1, true}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockCaptureCallback, Call(Eq(image1))).WillRepeatedly([&](const QImage &) {
|
||||||
|
notification.notify();
|
||||||
|
});
|
||||||
|
|
||||||
|
cache.requestImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestImageCallsAbortCallbackWithoutImage)
|
||||||
|
{
|
||||||
|
ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _))
|
||||||
|
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{QImage{}, true}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockAbortCallback, Call()).WillRepeatedly([&] { notification.notify(); });
|
||||||
|
|
||||||
|
cache.requestImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestImageRequestImageFromGenerator)
|
||||||
|
{
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{123}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockGenerator,
|
||||||
|
generateImage(Eq("/path/to/Component.qml"), _, Eq(Sqlite::TimeStamp{123}), _, _, _))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto &&callback, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
|
cache.requestImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestImageCallsCaptureCallbackWithImageFromGenerator)
|
||||||
|
{
|
||||||
|
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _, _))
|
||||||
|
.WillByDefault([&](auto, auto, auto, auto &&callback, auto, auto) {
|
||||||
|
callback(QImage{image1}, QImage{smallImage1});
|
||||||
|
notification.notify();
|
||||||
|
});
|
||||||
|
|
||||||
|
EXPECT_CALL(mockCaptureCallback, Call(Eq(image1)));
|
||||||
|
|
||||||
|
cache.requestImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestImageCallsAbortCallbackFromGenerator)
|
||||||
|
{
|
||||||
|
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _, _))
|
||||||
|
.WillByDefault([&](auto, auto, auto, auto &&, auto &&abortCallback, auto) {
|
||||||
|
abortCallback();
|
||||||
|
notification.notify();
|
||||||
|
});
|
||||||
|
|
||||||
|
EXPECT_CALL(mockAbortCallback, Call());
|
||||||
|
|
||||||
|
cache.requestImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestSmallImageFetchesSmallImageFromStorage)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml"), _))
|
||||||
|
.WillRepeatedly([&](Utils::SmallStringView, auto) {
|
||||||
|
notification.notify();
|
||||||
|
return QmlDesigner::ImageCacheStorageInterface::ImageEntry{{}, false};
|
||||||
|
});
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestSmallImageFetchesSmallImageFromStorageWithTimeStamp)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillRepeatedly(Return(Sqlite::TimeStamp{123}));
|
||||||
|
EXPECT_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
|
||||||
|
.WillRepeatedly([&](Utils::SmallStringView, auto) {
|
||||||
|
notification.notify();
|
||||||
|
return QmlDesigner::ImageCacheStorageInterface::ImageEntry{QImage{}, false};
|
||||||
|
});
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestSmallImageCallsCaptureCallbackWithImageFromStorage)
|
||||||
|
{
|
||||||
|
ON_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml"), _))
|
||||||
|
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{smallImage1, true}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockCaptureCallback, Call(Eq(smallImage1))).WillRepeatedly([&](const QImage &) {
|
||||||
|
notification.notify();
|
||||||
|
});
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestSmallImageCallsAbortCallbackWithoutSmallImage)
|
||||||
|
{
|
||||||
|
ON_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml"), _))
|
||||||
|
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{QImage{}, true}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockAbortCallback, Call()).WillRepeatedly([&] { notification.notify(); });
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestSmallImageRequestImageFromGenerator)
|
||||||
|
{
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{123}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockGenerator,
|
||||||
|
generateImage(Eq("/path/to/Component.qml"), _, Eq(Sqlite::TimeStamp{123}), _, _, _))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto &&callback, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestSmallImageCallsCaptureCallbackWithImageFromGenerator)
|
||||||
|
{
|
||||||
|
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _, _))
|
||||||
|
.WillByDefault([&](auto, auto, auto, auto &&callback, auto, auto) {
|
||||||
|
callback(QImage{image1}, QImage{smallImage1});
|
||||||
|
notification.notify();
|
||||||
|
});
|
||||||
|
|
||||||
|
EXPECT_CALL(mockCaptureCallback, Call(Eq(smallImage1)));
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestSmallImageCallsAbortCallbackFromGenerator)
|
||||||
|
{
|
||||||
|
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _, _))
|
||||||
|
.WillByDefault([&](auto, auto, auto, auto &&, auto &&abortCallback, auto) {
|
||||||
|
abortCallback();
|
||||||
|
notification.notify();
|
||||||
|
});
|
||||||
|
|
||||||
|
EXPECT_CALL(mockAbortCallback, Call());
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, CleanRemovesEntries)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(mockGenerator, generateImage(_, _, _, _, _, _))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto &&captureCallback, auto &&, auto) {
|
||||||
|
captureCallback(QImage{}, QImage{});
|
||||||
|
waitInThread.wait();
|
||||||
|
});
|
||||||
|
cache.requestSmallImage("/path/to/Component1.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
|
||||||
|
EXPECT_CALL(mockCaptureCallback, Call(_)).Times(AtMost(1));
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component3.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
cache.clean();
|
||||||
|
waitInThread.notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, CleanCallsAbort)
|
||||||
|
{
|
||||||
|
ON_CALL(mockGenerator, generateImage(_, _, _, _, _, _))
|
||||||
|
.WillByDefault([&](auto, auto, auto, auto &&mockCaptureCallback, auto &&, auto) {
|
||||||
|
waitInThread.wait();
|
||||||
|
});
|
||||||
|
cache.requestSmallImage("/path/to/Component1.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
cache.requestSmallImage("/path/to/Component2.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
|
||||||
|
EXPECT_CALL(mockAbortCallback, Call()).Times(AtLeast(2));
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component3.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
cache.clean();
|
||||||
|
waitInThread.notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, CleanCallsGeneratorClean)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(mockGenerator, clean()).Times(AtLeast(1));
|
||||||
|
|
||||||
|
cache.clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, AfterCleanNewJobsWorks)
|
||||||
|
{
|
||||||
|
cache.clean();
|
||||||
|
|
||||||
|
EXPECT_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _, _))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto &&, auto &&, auto) { notification.notify(); });
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, WaitForFinished)
|
||||||
|
{
|
||||||
|
ON_CALL(mockStorage, fetchImage(_, _))
|
||||||
|
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{image1, true}));
|
||||||
|
cache.requestImage("/path/to/Component1.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
cache.requestImage("/path/to/Component2.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction());
|
||||||
|
|
||||||
|
EXPECT_CALL(mockCaptureCallback, Call(_)).Times(2);
|
||||||
|
|
||||||
|
cache.waitForFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, WaitForFinishedInGenerator)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(mockGenerator, waitForFinished());
|
||||||
|
|
||||||
|
cache.waitForFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestImageWithExtraIdFetchesImageFromStorage)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml+extraId1"), _))
|
||||||
|
.WillRepeatedly([&](Utils::SmallStringView, auto) {
|
||||||
|
notification.notify();
|
||||||
|
return QmlDesigner::ImageCacheStorageInterface::ImageEntry{{}, false};
|
||||||
|
});
|
||||||
|
|
||||||
|
cache.requestImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction(),
|
||||||
|
"extraId1");
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestSmallImageWithExtraIdFetchesImageFromStorage)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml+extraId1"), _))
|
||||||
|
.WillRepeatedly([&](Utils::SmallStringView, auto) {
|
||||||
|
notification.notify();
|
||||||
|
return QmlDesigner::ImageCacheStorageInterface::ImageEntry{{}, false};
|
||||||
|
});
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction(),
|
||||||
|
"extraId1");
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestImageWithExtraIdRequestImageFromGenerator)
|
||||||
|
{
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{123}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockGenerator,
|
||||||
|
generateImage(
|
||||||
|
Eq("/path/to/Component.qml"), Eq("extraId1"), Eq(Sqlite::TimeStamp{123}), _, _, _))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto &&, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
|
cache.requestImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction(),
|
||||||
|
"extraId1");
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestSmallImageWithExtraIdRequestImageFromGenerator)
|
||||||
|
{
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{123}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockGenerator,
|
||||||
|
generateImage(
|
||||||
|
Eq("/path/to/Component.qml"), Eq("extraId1"), Eq(Sqlite::TimeStamp{123}), _, _, _))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto &&, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction(),
|
||||||
|
"extraId1");
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestImageWithAuxiliaryDataRequestImageFromGenerator)
|
||||||
|
{
|
||||||
|
using QmlDesigner::ImageCache::FontCollectorSizesAuxiliaryData;
|
||||||
|
std::vector<QSize> sizes{{20, 11}};
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{123}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockGenerator,
|
||||||
|
generateImage(Eq("/path/to/Component.qml"),
|
||||||
|
Eq("extraId1"),
|
||||||
|
Eq(Sqlite::TimeStamp{123}),
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
VariantWith<FontCollectorSizesAuxiliaryData>(
|
||||||
|
AllOf(Field(&FontCollectorSizesAuxiliaryData::sizes,
|
||||||
|
ElementsAre(QSize{20, 11})),
|
||||||
|
Field(&FontCollectorSizesAuxiliaryData::colorName,
|
||||||
|
Eq(u"color"))))))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto &&, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
|
cache.requestImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction(),
|
||||||
|
"extraId1",
|
||||||
|
FontCollectorSizesAuxiliaryData{sizes, "color"});
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(AsynchronousImageCache, RequestSmallImageWithAuxiliaryDataRequestImageFromGenerator)
|
||||||
|
{
|
||||||
|
using QmlDesigner::ImageCache::FontCollectorSizesAuxiliaryData;
|
||||||
|
std::vector<QSize> sizes{{20, 11}};
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{123}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockGenerator,
|
||||||
|
generateImage(Eq("/path/to/Component.qml"),
|
||||||
|
Eq("extraId1"),
|
||||||
|
Eq(Sqlite::TimeStamp{123}),
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
VariantWith<FontCollectorSizesAuxiliaryData>(
|
||||||
|
AllOf(Field(&FontCollectorSizesAuxiliaryData::sizes,
|
||||||
|
ElementsAre(QSize{20, 11})),
|
||||||
|
Field(&FontCollectorSizesAuxiliaryData::colorName,
|
||||||
|
Eq(u"color"))))))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto &&, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
|
cache.requestSmallImage("/path/to/Component.qml",
|
||||||
|
mockCaptureCallback.AsStdFunction(),
|
||||||
|
mockAbortCallback.AsStdFunction(),
|
||||||
|
"extraId1",
|
||||||
|
FontCollectorSizesAuxiliaryData{sizes, "color"});
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@@ -1566,11 +1566,16 @@ std::ostream &operator<<(std::ostream &out, const VariantProperty &property)
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
std::ostream &operator<<(std::ostream &out, const ImageCacheStorageEntry &entry)
|
std::ostream &operator<<(std::ostream &out, const ImageCacheStorageImageEntry &entry)
|
||||||
{
|
{
|
||||||
return out << "(" << entry.image << ", " << entry.hasEntry << ")";
|
return out << "(" << entry.image << ", " << entry.hasEntry << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const ImageCacheStorageIconEntry &entry)
|
||||||
|
{
|
||||||
|
return out << "(" << entry.icon << ", " << entry.hasEntry << ")";
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -379,9 +379,11 @@ std::ostream &operator<<(std::ostream &out, const ModelNode &node);
|
|||||||
std::ostream &operator<<(std::ostream &out, const VariantProperty &property);
|
std::ostream &operator<<(std::ostream &out, const VariantProperty &property);
|
||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
class ImageCacheStorageEntry;
|
class ImageCacheStorageImageEntry;
|
||||||
|
class ImageCacheStorageIconEntry;
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const ImageCacheStorageEntry &entry);
|
std::ostream &operator<<(std::ostream &out, const ImageCacheStorageImageEntry &entry);
|
||||||
|
std::ostream &operator<<(std::ostream &out, const ImageCacheStorageIconEntry &entry);
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace QmlDesigner
|
} // namespace QmlDesigner
|
||||||
|
|||||||
@@ -23,9 +23,10 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QIcon>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTextCharFormat>
|
#include <QTextCharFormat>
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
#include <gtest/gtest-printers.h>
|
#include <gtest/gtest-printers.h>
|
||||||
|
|
||||||
@@ -90,6 +91,16 @@ std::ostream &operator<<(std::ostream &out, const QImage &image)
|
|||||||
return out << "(" << image.width() << ", " << image.height() << ", " << image.format() << ")";
|
return out << "(" << image.width() << ", " << image.height() << ", " << image.format() << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &out, const QIcon &icon)
|
||||||
|
{
|
||||||
|
return out << "(";
|
||||||
|
|
||||||
|
for (const QSize &size : icon.availableSizes())
|
||||||
|
out << "(" << size.width() << ", " << size.height() << "), ";
|
||||||
|
|
||||||
|
out << icon.cacheKey() << ")";
|
||||||
|
}
|
||||||
|
|
||||||
void PrintTo(const QString &text, std::ostream *os)
|
void PrintTo(const QString &text, std::ostream *os)
|
||||||
{
|
{
|
||||||
*os << text;
|
*os << text;
|
||||||
|
|||||||
@@ -35,12 +35,14 @@ class QVariant;
|
|||||||
class QString;
|
class QString;
|
||||||
class QTextCharFormat;
|
class QTextCharFormat;
|
||||||
class QImage;
|
class QImage;
|
||||||
|
class QIcon;
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const QVariant &QVariant);
|
std::ostream &operator<<(std::ostream &out, const QVariant &QVariant);
|
||||||
std::ostream &operator<<(std::ostream &out, const QString &text);
|
std::ostream &operator<<(std::ostream &out, const QString &text);
|
||||||
std::ostream &operator<<(std::ostream &out, const QByteArray &byteArray);
|
std::ostream &operator<<(std::ostream &out, const QByteArray &byteArray);
|
||||||
std::ostream &operator<<(std::ostream &out, const QTextCharFormat &format);
|
std::ostream &operator<<(std::ostream &out, const QTextCharFormat &format);
|
||||||
std::ostream &operator<<(std::ostream &out, const QImage &image);
|
std::ostream &operator<<(std::ostream &out, const QImage &image);
|
||||||
|
std::ostream &operator<<(std::ostream &out, const QIcon &icon);
|
||||||
|
|
||||||
void PrintTo(const QString &text, std::ostream *os);
|
void PrintTo(const QString &text, std::ostream *os);
|
||||||
void PrintTo(const QVariant &variant, std::ostream *os);
|
void PrintTo(const QVariant &variant, std::ostream *os);
|
||||||
|
|||||||
@@ -1,391 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2016 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 "googletest.h"
|
|
||||||
|
|
||||||
#include "mockimagecachegenerator.h"
|
|
||||||
#include "mockimagecachestorage.h"
|
|
||||||
#include "mocktimestampprovider.h"
|
|
||||||
#include "notification.h"
|
|
||||||
|
|
||||||
#include <imagecache.h>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class ImageCache : public testing::Test
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
Notification notification;
|
|
||||||
Notification waitInThread;
|
|
||||||
NiceMock<MockFunction<void()>> mockAbortCallback;
|
|
||||||
NiceMock<MockFunction<void(const QImage &image)>> mockCaptureCallback;
|
|
||||||
NiceMock<MockImageCacheStorage> mockStorage;
|
|
||||||
NiceMock<MockImageCacheGenerator> mockGenerator;
|
|
||||||
NiceMock<MockTimeStampProvider> mockTimeStampProvider;
|
|
||||||
QmlDesigner::ImageCache cache{mockStorage, mockGenerator, mockTimeStampProvider};
|
|
||||||
QImage image1{10, 10, QImage::Format_ARGB32};
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestImageFetchesImageFromStorage)
|
|
||||||
{
|
|
||||||
EXPECT_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _))
|
|
||||||
.WillRepeatedly([&](Utils::SmallStringView, auto) {
|
|
||||||
notification.notify();
|
|
||||||
return QmlDesigner::ImageCacheStorageInterface::Entry{{}, false};
|
|
||||||
});
|
|
||||||
|
|
||||||
cache.requestImage("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestImageFetchesImageFromStorageWithTimeStamp)
|
|
||||||
{
|
|
||||||
EXPECT_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
|
||||||
.WillRepeatedly(Return(Sqlite::TimeStamp{123}));
|
|
||||||
EXPECT_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
|
|
||||||
.WillRepeatedly([&](Utils::SmallStringView, auto) {
|
|
||||||
notification.notify();
|
|
||||||
return QmlDesigner::ImageCacheStorageInterface::Entry{QImage{}, false};
|
|
||||||
});
|
|
||||||
|
|
||||||
cache.requestImage("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestImageCallsCaptureCallbackWithImageFromStorage)
|
|
||||||
{
|
|
||||||
ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _))
|
|
||||||
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{image1, true}));
|
|
||||||
|
|
||||||
EXPECT_CALL(mockCaptureCallback, Call(Eq(image1))).WillRepeatedly([&](const QImage &) {
|
|
||||||
notification.notify();
|
|
||||||
});
|
|
||||||
|
|
||||||
cache.requestImage("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestImageCallsAbortCallbackWithoutImage)
|
|
||||||
{
|
|
||||||
ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), _))
|
|
||||||
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{QImage{}, true}));
|
|
||||||
|
|
||||||
EXPECT_CALL(mockAbortCallback, Call()).WillRepeatedly([&] { notification.notify(); });
|
|
||||||
|
|
||||||
cache.requestImage("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestImageRequestImageFromGenerator)
|
|
||||||
{
|
|
||||||
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
|
||||||
.WillByDefault(Return(Sqlite::TimeStamp{123}));
|
|
||||||
|
|
||||||
EXPECT_CALL(mockGenerator,
|
|
||||||
generateImage(Eq("/path/to/Component.qml"), _, Eq(Sqlite::TimeStamp{123}), _, _))
|
|
||||||
.WillRepeatedly([&](auto, auto, auto, auto &&callback, auto) { notification.notify(); });
|
|
||||||
|
|
||||||
cache.requestImage("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestImageCallsCaptureCallbackWithImageFromGenerator)
|
|
||||||
{
|
|
||||||
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _))
|
|
||||||
.WillByDefault([&](auto, auto, auto, auto &&callback, auto) {
|
|
||||||
callback(QImage{image1});
|
|
||||||
notification.notify();
|
|
||||||
});
|
|
||||||
|
|
||||||
EXPECT_CALL(mockCaptureCallback, Call(Eq(image1)));
|
|
||||||
|
|
||||||
cache.requestImage("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestImageCallsAbortCallbackFromGenerator)
|
|
||||||
{
|
|
||||||
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _))
|
|
||||||
.WillByDefault([&](auto, auto, auto, auto &&, auto &&abortCallback) {
|
|
||||||
abortCallback();
|
|
||||||
notification.notify();
|
|
||||||
});
|
|
||||||
|
|
||||||
EXPECT_CALL(mockAbortCallback, Call());
|
|
||||||
|
|
||||||
cache.requestImage("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestIconFetchesIconFromStorage)
|
|
||||||
{
|
|
||||||
EXPECT_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), _))
|
|
||||||
.WillRepeatedly([&](Utils::SmallStringView, auto) {
|
|
||||||
notification.notify();
|
|
||||||
return QmlDesigner::ImageCacheStorageInterface::Entry{{}, false};
|
|
||||||
});
|
|
||||||
|
|
||||||
cache.requestIcon("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestIconFetchesIconFromStorageWithTimeStamp)
|
|
||||||
{
|
|
||||||
EXPECT_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
|
||||||
.WillRepeatedly(Return(Sqlite::TimeStamp{123}));
|
|
||||||
EXPECT_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
|
|
||||||
.WillRepeatedly([&](Utils::SmallStringView, auto) {
|
|
||||||
notification.notify();
|
|
||||||
return QmlDesigner::ImageCacheStorageInterface::Entry{QImage{}, false};
|
|
||||||
});
|
|
||||||
|
|
||||||
cache.requestIcon("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestIconCallsCaptureCallbackWithImageFromStorage)
|
|
||||||
{
|
|
||||||
ON_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), _))
|
|
||||||
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{image1, true}));
|
|
||||||
|
|
||||||
EXPECT_CALL(mockCaptureCallback, Call(Eq(image1))).WillRepeatedly([&](const QImage &) {
|
|
||||||
notification.notify();
|
|
||||||
});
|
|
||||||
|
|
||||||
cache.requestIcon("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestIconCallsAbortCallbackWithoutIcon)
|
|
||||||
{
|
|
||||||
ON_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), _))
|
|
||||||
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{QImage{}, true}));
|
|
||||||
|
|
||||||
EXPECT_CALL(mockAbortCallback, Call()).WillRepeatedly([&] { notification.notify(); });
|
|
||||||
|
|
||||||
cache.requestIcon("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestIconRequestImageFromGenerator)
|
|
||||||
{
|
|
||||||
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
|
||||||
.WillByDefault(Return(Sqlite::TimeStamp{123}));
|
|
||||||
|
|
||||||
EXPECT_CALL(mockGenerator,
|
|
||||||
generateImage(Eq("/path/to/Component.qml"), _, Eq(Sqlite::TimeStamp{123}), _, _))
|
|
||||||
.WillRepeatedly([&](auto, auto, auto, auto &&callback, auto) { notification.notify(); });
|
|
||||||
|
|
||||||
cache.requestIcon("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestIconCallsCaptureCallbackWithImageFromGenerator)
|
|
||||||
{
|
|
||||||
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _))
|
|
||||||
.WillByDefault([&](auto, auto, auto, auto &&callback, auto) {
|
|
||||||
callback(QImage{image1});
|
|
||||||
notification.notify();
|
|
||||||
});
|
|
||||||
|
|
||||||
EXPECT_CALL(mockCaptureCallback, Call(Eq(image1)));
|
|
||||||
|
|
||||||
cache.requestIcon("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestIconCallsAbortCallbackFromGenerator)
|
|
||||||
{
|
|
||||||
ON_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _))
|
|
||||||
.WillByDefault([&](auto, auto, auto, auto &&, auto &&abortCallback) {
|
|
||||||
abortCallback();
|
|
||||||
notification.notify();
|
|
||||||
});
|
|
||||||
|
|
||||||
EXPECT_CALL(mockAbortCallback, Call());
|
|
||||||
|
|
||||||
cache.requestIcon("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, CleanRemovesEntries)
|
|
||||||
{
|
|
||||||
EXPECT_CALL(mockGenerator, generateImage(_, _, _, _, _))
|
|
||||||
.WillRepeatedly([&](auto, auto, auto, auto &&mockCaptureCallback, auto &&) {
|
|
||||||
mockCaptureCallback(QImage{});
|
|
||||||
waitInThread.wait();
|
|
||||||
});
|
|
||||||
cache.requestIcon("/path/to/Component1.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
|
|
||||||
EXPECT_CALL(mockCaptureCallback, Call(_)).Times(AtMost(1));
|
|
||||||
|
|
||||||
cache.requestIcon("/path/to/Component3.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
cache.clean();
|
|
||||||
waitInThread.notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, CleanCallsAbort)
|
|
||||||
{
|
|
||||||
ON_CALL(mockGenerator, generateImage(_, _, _, _, _))
|
|
||||||
.WillByDefault(
|
|
||||||
[&](auto, auto, auto, auto &&mockCaptureCallback, auto &&) { waitInThread.wait(); });
|
|
||||||
cache.requestIcon("/path/to/Component1.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
cache.requestIcon("/path/to/Component2.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
|
|
||||||
EXPECT_CALL(mockAbortCallback, Call()).Times(AtLeast(2));
|
|
||||||
|
|
||||||
cache.requestIcon("/path/to/Component3.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
cache.clean();
|
|
||||||
waitInThread.notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, CleanCallsGeneratorClean)
|
|
||||||
{
|
|
||||||
EXPECT_CALL(mockGenerator, clean()).Times(AtLeast(1));
|
|
||||||
|
|
||||||
cache.clean();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, AfterCleanNewJobsWorks)
|
|
||||||
{
|
|
||||||
cache.clean();
|
|
||||||
|
|
||||||
EXPECT_CALL(mockGenerator, generateImage(Eq("/path/to/Component.qml"), _, _, _, _))
|
|
||||||
.WillRepeatedly([&](auto, auto, auto, auto &&, auto &&) { notification.notify(); });
|
|
||||||
|
|
||||||
cache.requestIcon("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, WaitForFinished)
|
|
||||||
{
|
|
||||||
ON_CALL(mockStorage, fetchImage(_, _))
|
|
||||||
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::Entry{image1, true}));
|
|
||||||
cache.requestImage("/path/to/Component1.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
cache.requestImage("/path/to/Component2.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction());
|
|
||||||
|
|
||||||
EXPECT_CALL(mockCaptureCallback, Call(_)).Times(2);
|
|
||||||
|
|
||||||
cache.waitForFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, WaitForFinishedInGenerator)
|
|
||||||
{
|
|
||||||
EXPECT_CALL(mockGenerator, waitForFinished());
|
|
||||||
|
|
||||||
cache.waitForFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestImageWithStateFetchesImageFromStorage)
|
|
||||||
{
|
|
||||||
EXPECT_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml+state1"), _))
|
|
||||||
.WillRepeatedly([&](Utils::SmallStringView, auto) {
|
|
||||||
notification.notify();
|
|
||||||
return QmlDesigner::ImageCacheStorageInterface::Entry{{}, false};
|
|
||||||
});
|
|
||||||
|
|
||||||
cache.requestImage("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction(),
|
|
||||||
"state1");
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestIconWithStateFetchesImageFromStorage)
|
|
||||||
{
|
|
||||||
EXPECT_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml+state1"), _))
|
|
||||||
.WillRepeatedly([&](Utils::SmallStringView, auto) {
|
|
||||||
notification.notify();
|
|
||||||
return QmlDesigner::ImageCacheStorageInterface::Entry{{}, false};
|
|
||||||
});
|
|
||||||
|
|
||||||
cache.requestIcon("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction(),
|
|
||||||
"state1");
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(ImageCache, RequestImageWithStateRequestImageFromGenerator)
|
|
||||||
{
|
|
||||||
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
|
||||||
.WillByDefault(Return(Sqlite::TimeStamp{123}));
|
|
||||||
|
|
||||||
EXPECT_CALL(mockGenerator,
|
|
||||||
generateImage(Eq("/path/to/Component.qml"), Eq("state1"), Eq(Sqlite::TimeStamp{123}), _, _))
|
|
||||||
.WillRepeatedly([&](auto, auto, auto, auto &&callback, auto) { notification.notify(); });
|
|
||||||
|
|
||||||
cache.requestImage("/path/to/Component.qml",
|
|
||||||
mockCaptureCallback.AsStdFunction(),
|
|
||||||
mockAbortCallback.AsStdFunction(),
|
|
||||||
"state1");
|
|
||||||
notification.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
@@ -36,7 +36,22 @@ public:
|
|||||||
start,
|
start,
|
||||||
(Utils::SmallStringView filePath,
|
(Utils::SmallStringView filePath,
|
||||||
Utils::SmallStringView state,
|
Utils::SmallStringView state,
|
||||||
|
const QmlDesigner::ImageCache::AuxiliaryData &auxiliaryData,
|
||||||
ImageCacheCollectorInterface::CaptureCallback captureCallback,
|
ImageCacheCollectorInterface::CaptureCallback captureCallback,
|
||||||
ImageCacheCollectorInterface::AbortCallback abortCallback),
|
ImageCacheCollectorInterface::AbortCallback abortCallback),
|
||||||
(override));
|
(override));
|
||||||
|
|
||||||
|
MOCK_METHOD(ImagePair,
|
||||||
|
createImage,
|
||||||
|
(Utils::SmallStringView filePath,
|
||||||
|
Utils::SmallStringView state,
|
||||||
|
const QmlDesigner::ImageCache::AuxiliaryData &auxiliaryData),
|
||||||
|
(override));
|
||||||
|
|
||||||
|
MOCK_METHOD(QIcon,
|
||||||
|
createIcon,
|
||||||
|
(Utils::SmallStringView filePath,
|
||||||
|
Utils::SmallStringView state,
|
||||||
|
const QmlDesigner::ImageCache::AuxiliaryData &auxiliaryData),
|
||||||
|
(override));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ protected:
|
|||||||
Notification waitInThread;
|
Notification waitInThread;
|
||||||
Notification notification;
|
Notification notification;
|
||||||
QImage image1{10, 10, QImage::Format_ARGB32};
|
QImage image1{10, 10, QImage::Format_ARGB32};
|
||||||
NiceMock<MockFunction<void(const QImage &)>> imageCallbackMock;
|
QImage smallImage1{1, 1, QImage::Format_ARGB32};
|
||||||
|
NiceMock<MockFunction<void(const QImage &, const QImage &)>> imageCallbackMock;
|
||||||
NiceMock<MockFunction<void()>> abortCallbackMock;
|
NiceMock<MockFunction<void()>> abortCallbackMock;
|
||||||
NiceMock<ImageCacheCollectorMock> collectorMock;
|
NiceMock<ImageCacheCollectorMock> collectorMock;
|
||||||
NiceMock<MockImageCacheStorage> storageMock;
|
NiceMock<MockImageCacheStorage> storageMock;
|
||||||
@@ -63,191 +64,205 @@ protected:
|
|||||||
|
|
||||||
TEST_F(ImageCacheGenerator, CallsCollectorWithCaptureCallback)
|
TEST_F(ImageCacheGenerator, CallsCollectorWithCaptureCallback)
|
||||||
{
|
{
|
||||||
EXPECT_CALL(collectorMock, start(Eq("name"), _, _, _))
|
EXPECT_CALL(collectorMock, start(Eq("name"), _, _, _, _))
|
||||||
.WillRepeatedly(
|
.WillRepeatedly([&](auto, auto, auto, auto captureCallback, auto) {
|
||||||
[&](auto, auto, auto captureCallback, auto) { captureCallback(QImage{image1}); });
|
captureCallback(QImage{image1}, QImage{smallImage1});
|
||||||
EXPECT_CALL(imageCallbackMock, Call(_)).WillRepeatedly([&](const QImage &) {
|
});
|
||||||
|
EXPECT_CALL(imageCallbackMock, Call(_, _)).WillRepeatedly([&](const QImage &, const QImage &) {
|
||||||
notification.notify();
|
notification.notify();
|
||||||
});
|
});
|
||||||
|
|
||||||
generator.generateImage("name", {}, {}, imageCallbackMock.AsStdFunction(), {});
|
generator.generateImage("name", {}, {}, imageCallbackMock.AsStdFunction(), {}, {});
|
||||||
notification.wait();
|
notification.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheGenerator, CallsCollectorOnlyIfNotProcessing)
|
TEST_F(ImageCacheGenerator, CallsCollectorOnlyIfNotProcessing)
|
||||||
{
|
{
|
||||||
EXPECT_CALL(collectorMock, start(Eq("name"), _, _, _)).WillRepeatedly([&](auto, auto, auto, auto) {
|
EXPECT_CALL(collectorMock, start(Eq("name"), _, _, _, _))
|
||||||
notification.notify();
|
.WillRepeatedly([&](auto, auto, auto, auto, auto) { notification.notify(); });
|
||||||
});
|
|
||||||
|
|
||||||
generator.generateImage("name", {}, {}, imageCallbackMock.AsStdFunction(), {});
|
generator.generateImage("name", {}, {}, imageCallbackMock.AsStdFunction(), {}, {});
|
||||||
generator.generateImage("name", {}, {}, imageCallbackMock.AsStdFunction(), {});
|
generator.generateImage("name", {}, {}, imageCallbackMock.AsStdFunction(), {}, {});
|
||||||
notification.wait(2);
|
notification.wait(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheGenerator, ProcessTaskAfterFirstFinished)
|
TEST_F(ImageCacheGenerator, ProcessTaskAfterFirstFinished)
|
||||||
{
|
{
|
||||||
ON_CALL(imageCallbackMock, Call(_)).WillByDefault([&](const QImage &) { notification.notify(); });
|
ON_CALL(imageCallbackMock, Call(_, _)).WillByDefault([&](const QImage &, const QImage &) {
|
||||||
|
notification.notify();
|
||||||
|
});
|
||||||
|
|
||||||
EXPECT_CALL(collectorMock, start(Eq("name"), _, _, _))
|
EXPECT_CALL(collectorMock, start(Eq("name"), _, _, _, _))
|
||||||
.WillOnce([&](auto, auto, auto captureCallback, auto) { captureCallback(QImage{image1}); });
|
.WillOnce([&](auto, auto, auto, auto captureCallback, auto) {
|
||||||
EXPECT_CALL(collectorMock, start(Eq("name2"), _, _, _))
|
captureCallback(QImage{image1}, QImage{smallImage1});
|
||||||
.WillOnce([&](auto, auto, auto captureCallback, auto) { captureCallback(QImage{image1}); });
|
});
|
||||||
|
EXPECT_CALL(collectorMock, start(Eq("name2"), _, _, _, _))
|
||||||
|
.WillOnce([&](auto, auto, auto, auto captureCallback, auto) {
|
||||||
|
captureCallback(QImage{image1}, QImage{smallImage1});
|
||||||
|
});
|
||||||
|
|
||||||
generator.generateImage("name", {}, {}, imageCallbackMock.AsStdFunction(), {});
|
generator.generateImage("name", {}, {}, imageCallbackMock.AsStdFunction(), {}, {});
|
||||||
generator.generateImage("name2", {}, {}, imageCallbackMock.AsStdFunction(), {});
|
generator.generateImage("name2", {}, {}, imageCallbackMock.AsStdFunction(), {}, {});
|
||||||
notification.wait(2);
|
notification.wait(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheGenerator, DontCrashAtDestructingGenerator)
|
TEST_F(ImageCacheGenerator, DontCrashAtDestructingGenerator)
|
||||||
{
|
{
|
||||||
ON_CALL(collectorMock, start(Eq("name"), _, _, _))
|
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
|
||||||
.WillByDefault(
|
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
|
||||||
[&](auto, auto, auto captureCallback, auto) { captureCallback(QImage{image1}); });
|
captureCallback(QImage{image1}, QImage{smallImage1});
|
||||||
|
});
|
||||||
|
|
||||||
generator.generateImage("name",
|
generator.generateImage(
|
||||||
{},
|
"name", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
{},
|
generator.generateImage(
|
||||||
imageCallbackMock.AsStdFunction(),
|
"name2", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
abortCallbackMock.AsStdFunction());
|
generator.generateImage(
|
||||||
generator.generateImage("name2",
|
"name3", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
{},
|
generator.generateImage(
|
||||||
{},
|
"name4", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
imageCallbackMock.AsStdFunction(),
|
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
generator.generateImage("name3",
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
imageCallbackMock.AsStdFunction(),
|
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
generator.generateImage("name4",
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
imageCallbackMock.AsStdFunction(),
|
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheGenerator, StoreImage)
|
TEST_F(ImageCacheGenerator, StoreImage)
|
||||||
{
|
{
|
||||||
ON_CALL(collectorMock, start(Eq("name"), _, _, _))
|
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
|
||||||
.WillByDefault(
|
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
|
||||||
[&](auto, auto, auto captureCallback, auto) { captureCallback(QImage{image1}); });
|
captureCallback(QImage{image1}, QImage{smallImage1});
|
||||||
|
});
|
||||||
|
|
||||||
EXPECT_CALL(storageMock, storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(image1)))
|
EXPECT_CALL(storageMock,
|
||||||
.WillRepeatedly([&](auto, auto, auto) { notification.notify(); });
|
storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(image1), Eq(smallImage1)))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
generator.generateImage("name", {}, {11}, imageCallbackMock.AsStdFunction(), {});
|
generator.generateImage("name", {}, {11}, imageCallbackMock.AsStdFunction(), {}, {});
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheGenerator, StoreImageWithExtraId)
|
||||||
|
{
|
||||||
|
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
|
||||||
|
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
|
||||||
|
captureCallback(QImage{image1}, QImage{smallImage1});
|
||||||
|
});
|
||||||
|
|
||||||
|
EXPECT_CALL(storageMock,
|
||||||
|
storeImage(Eq("name+extraId"), Eq(Sqlite::TimeStamp{11}), Eq(image1), Eq(smallImage1)))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
|
generator.generateImage("name", "extraId", {11}, imageCallbackMock.AsStdFunction(), {}, {});
|
||||||
notification.wait();
|
notification.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheGenerator, StoreNullImage)
|
TEST_F(ImageCacheGenerator, StoreNullImage)
|
||||||
{
|
{
|
||||||
ON_CALL(collectorMock, start(Eq("name"), _, _, _))
|
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
|
||||||
.WillByDefault([&](auto, auto, auto captureCallback, auto) { captureCallback(QImage{}); });
|
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
|
||||||
|
captureCallback(QImage{}, QImage{});
|
||||||
|
});
|
||||||
|
|
||||||
EXPECT_CALL(storageMock, storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{})))
|
EXPECT_CALL(storageMock,
|
||||||
.WillRepeatedly([&](auto, auto, auto) { notification.notify(); });
|
storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{}), Eq(QImage{})))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
|
generator.generateImage(
|
||||||
|
"name", {}, {11}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheGenerator, StoreNullImageWithExtraId)
|
||||||
|
{
|
||||||
|
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
|
||||||
|
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
|
||||||
|
captureCallback(QImage{}, QImage{});
|
||||||
|
});
|
||||||
|
|
||||||
|
EXPECT_CALL(storageMock,
|
||||||
|
storeImage(Eq("name+extraId"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{}), Eq(QImage{})))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
generator.generateImage("name",
|
generator.generateImage("name",
|
||||||
{},
|
"extraId",
|
||||||
{11},
|
{11},
|
||||||
imageCallbackMock.AsStdFunction(),
|
imageCallbackMock.AsStdFunction(),
|
||||||
abortCallbackMock.AsStdFunction());
|
abortCallbackMock.AsStdFunction(),
|
||||||
|
{});
|
||||||
notification.wait();
|
notification.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheGenerator, AbortCallback)
|
TEST_F(ImageCacheGenerator, AbortCallback)
|
||||||
{
|
{
|
||||||
ON_CALL(collectorMock, start(Eq("name"), _, _, _))
|
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
|
||||||
.WillByDefault(
|
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
|
||||||
[&](auto, auto, auto captureCallback, auto) { captureCallback(QImage{image1}); });
|
captureCallback(QImage{image1}, QImage{smallImage1});
|
||||||
ON_CALL(collectorMock, start(Eq("name2"), _, _, _))
|
});
|
||||||
.WillByDefault([&](auto, auto, auto, auto abortCallback) { abortCallback(); });
|
ON_CALL(collectorMock, start(Eq("name2"), _, _, _, _))
|
||||||
|
.WillByDefault([&](auto, auto, auto, auto, auto abortCallback) { abortCallback(); });
|
||||||
|
|
||||||
EXPECT_CALL(imageCallbackMock, Call(_)).WillOnce([&](const QImage &) { notification.notify(); });
|
EXPECT_CALL(imageCallbackMock, Call(_, _)).WillOnce([&](const QImage &, const QImage &) {
|
||||||
|
notification.notify();
|
||||||
|
});
|
||||||
EXPECT_CALL(abortCallbackMock, Call()).WillOnce([&]() { notification.notify(); });
|
EXPECT_CALL(abortCallbackMock, Call()).WillOnce([&]() { notification.notify(); });
|
||||||
|
|
||||||
generator.generateImage("name",
|
generator.generateImage(
|
||||||
{},
|
"name", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
{},
|
generator.generateImage(
|
||||||
imageCallbackMock.AsStdFunction(),
|
"name2", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
generator.generateImage("name2",
|
|
||||||
{},
|
|
||||||
{},
|
|
||||||
imageCallbackMock.AsStdFunction(),
|
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
notification.wait(2);
|
notification.wait(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheGenerator, StoreNullImageForAbortCallback)
|
TEST_F(ImageCacheGenerator, StoreNullImageForAbortCallback)
|
||||||
{
|
{
|
||||||
ON_CALL(collectorMock, start(_, _, _, _)).WillByDefault([&](auto, auto, auto, auto abortCallback) {
|
ON_CALL(collectorMock, start(_, _, _, _, _))
|
||||||
abortCallback();
|
.WillByDefault([&](auto, auto, auto, auto, auto abortCallback) { abortCallback(); });
|
||||||
});
|
|
||||||
|
|
||||||
EXPECT_CALL(storageMock, storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{})))
|
EXPECT_CALL(storageMock,
|
||||||
.WillOnce([&](auto, auto, auto) { notification.notify(); });
|
storeImage(Eq("name"), Eq(Sqlite::TimeStamp{11}), Eq(QImage{}), Eq(QImage{})))
|
||||||
|
.WillOnce([&](auto, auto, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
generator.generateImage("name",
|
generator.generateImage(
|
||||||
{},
|
"name", {}, {11}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
{11},
|
|
||||||
imageCallbackMock.AsStdFunction(),
|
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
notification.wait();
|
notification.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheGenerator, AbortForEmptyImage)
|
TEST_F(ImageCacheGenerator, AbortForEmptyImage)
|
||||||
{
|
{
|
||||||
ON_CALL(collectorMock, start(Eq("name"), _, _, _))
|
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
|
||||||
.WillByDefault([&](auto, auto, auto captureCallback, auto) { captureCallback(QImage{}); });
|
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
|
||||||
|
captureCallback(QImage{}, QImage{});
|
||||||
|
});
|
||||||
|
|
||||||
EXPECT_CALL(abortCallbackMock, Call()).WillOnce([&]() { notification.notify(); });
|
EXPECT_CALL(abortCallbackMock, Call()).WillOnce([&]() { notification.notify(); });
|
||||||
|
|
||||||
generator.generateImage("name",
|
generator.generateImage(
|
||||||
{},
|
"name", {}, {}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
{},
|
|
||||||
imageCallbackMock.AsStdFunction(),
|
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
notification.wait();
|
notification.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheGenerator, CallWalCheckpointFullIfQueueIsEmpty)
|
TEST_F(ImageCacheGenerator, CallWalCheckpointFullIfQueueIsEmpty)
|
||||||
{
|
{
|
||||||
ON_CALL(collectorMock, start(Eq("name"), _, _, _))
|
ON_CALL(collectorMock, start(Eq("name"), _, _, _, _))
|
||||||
.WillByDefault([&](auto, auto, auto captureCallback, auto) { captureCallback({}); });
|
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) { captureCallback({}, {}); });
|
||||||
|
|
||||||
EXPECT_CALL(storageMock, walCheckpointFull()).WillRepeatedly([&]() { notification.notify(); });
|
EXPECT_CALL(storageMock, walCheckpointFull()).WillRepeatedly([&]() { notification.notify(); });
|
||||||
|
|
||||||
generator.generateImage("name",
|
generator.generateImage(
|
||||||
{},
|
"name", {}, {11}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
{11},
|
generator.generateImage(
|
||||||
imageCallbackMock.AsStdFunction(),
|
"name2", {}, {11}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
generator.generateImage("name2",
|
|
||||||
{},
|
|
||||||
{11},
|
|
||||||
imageCallbackMock.AsStdFunction(),
|
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
notification.wait();
|
notification.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheGenerator, CleanIsCallingAbortCallback)
|
TEST_F(ImageCacheGenerator, CleanIsCallingAbortCallback)
|
||||||
{
|
{
|
||||||
ON_CALL(collectorMock, start(_, _, _, _)).WillByDefault([&](auto, auto, auto captureCallback, auto) {
|
ON_CALL(collectorMock, start(_, _, _, _, _))
|
||||||
captureCallback({});
|
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
|
||||||
|
captureCallback({}, {});
|
||||||
waitInThread.wait();
|
waitInThread.wait();
|
||||||
});
|
});
|
||||||
generator.generateImage("name",
|
generator.generateImage(
|
||||||
{},
|
"name", {}, {11}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
{11},
|
generator.generateImage(
|
||||||
imageCallbackMock.AsStdFunction(),
|
"name2", {}, {11}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
generator.generateImage("name2",
|
|
||||||
{},
|
|
||||||
{11},
|
|
||||||
imageCallbackMock.AsStdFunction(),
|
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
|
|
||||||
EXPECT_CALL(abortCallbackMock, Call()).Times(AtLeast(1));
|
EXPECT_CALL(abortCallbackMock, Call()).Times(AtLeast(1));
|
||||||
|
|
||||||
@@ -257,31 +272,51 @@ TEST_F(ImageCacheGenerator, CleanIsCallingAbortCallback)
|
|||||||
|
|
||||||
TEST_F(ImageCacheGenerator, WaitForFinished)
|
TEST_F(ImageCacheGenerator, WaitForFinished)
|
||||||
{
|
{
|
||||||
ON_CALL(collectorMock, start(_, _, _, _)).WillByDefault([&](auto, auto, auto captureCallback, auto) {
|
ON_CALL(collectorMock, start(_, _, _, _, _))
|
||||||
captureCallback(QImage{image1});
|
.WillByDefault([&](auto, auto, auto, auto captureCallback, auto) {
|
||||||
|
captureCallback(QImage{image1}, QImage{smallImage1});
|
||||||
});
|
});
|
||||||
generator.generateImage("name",
|
generator.generateImage(
|
||||||
{},
|
"name", {}, {11}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
{11},
|
generator.generateImage(
|
||||||
imageCallbackMock.AsStdFunction(),
|
"name2", {}, {11}, imageCallbackMock.AsStdFunction(), abortCallbackMock.AsStdFunction(), {});
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
generator.generateImage("name2",
|
|
||||||
{},
|
|
||||||
{11},
|
|
||||||
imageCallbackMock.AsStdFunction(),
|
|
||||||
abortCallbackMock.AsStdFunction());
|
|
||||||
|
|
||||||
EXPECT_CALL(imageCallbackMock, Call(_)).Times(2);
|
EXPECT_CALL(imageCallbackMock, Call(_, _)).Times(2);
|
||||||
|
|
||||||
generator.waitForFinished();
|
generator.waitForFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheGenerator, CallsCollectorWithState)
|
TEST_F(ImageCacheGenerator, CallsCollectorWithExtraId)
|
||||||
{
|
{
|
||||||
EXPECT_CALL(collectorMock, start(Eq("name"), Eq("state1"), _, _))
|
EXPECT_CALL(collectorMock, start(Eq("name"), Eq("extraId1"), _, _, _))
|
||||||
.WillRepeatedly([&](auto, auto, auto, auto) { notification.notify(); });
|
.WillRepeatedly([&](auto, auto, auto, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
generator.generateImage("name", "state1", {}, imageCallbackMock.AsStdFunction(), {});
|
generator.generateImage("name", "extraId1", {}, imageCallbackMock.AsStdFunction(), {}, {});
|
||||||
|
notification.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheGenerator, CallsCollectorWithAuxiliaryData)
|
||||||
|
{
|
||||||
|
using QmlDesigner::ImageCache::FontCollectorSizesAuxiliaryData;
|
||||||
|
std::vector<QSize> sizes{{20, 11}};
|
||||||
|
|
||||||
|
EXPECT_CALL(collectorMock,
|
||||||
|
start(Eq("name"),
|
||||||
|
_,
|
||||||
|
VariantWith<FontCollectorSizesAuxiliaryData>(
|
||||||
|
AllOf(Field(&FontCollectorSizesAuxiliaryData::sizes,
|
||||||
|
ElementsAre(QSize{20, 11})),
|
||||||
|
Field(&FontCollectorSizesAuxiliaryData::colorName, Eq(u"color")))),
|
||||||
|
_,
|
||||||
|
_))
|
||||||
|
.WillRepeatedly([&](auto, auto, auto, auto, auto) { notification.notify(); });
|
||||||
|
|
||||||
|
generator.generateImage("name",
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
imageCallbackMock.AsStdFunction(),
|
||||||
|
{},
|
||||||
|
FontCollectorSizesAuxiliaryData{sizes, "color"});
|
||||||
notification.wait();
|
notification.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,28 +32,28 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
MATCHER_P2(IsEntry,
|
MATCHER_P2(IsImageEntry,
|
||||||
image,
|
image,
|
||||||
hasEntry,
|
hasEntry,
|
||||||
std::string(negation ? "is't" : "is")
|
std::string(negation ? "is't" : "is")
|
||||||
+ PrintToString(QmlDesigner::ImageCacheStorageInterface::Entry{image, hasEntry}))
|
+ PrintToString(QmlDesigner::ImageCacheStorageInterface::ImageEntry{image, hasEntry}))
|
||||||
{
|
{
|
||||||
const QmlDesigner::ImageCacheStorageInterface::Entry &entry = arg;
|
const QmlDesigner::ImageCacheStorageInterface::ImageEntry &entry = arg;
|
||||||
return entry.image == image && entry.hasEntry == hasEntry;
|
return entry.image == image && entry.hasEntry == hasEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MATCHER_P2(IsIconEntry,
|
||||||
|
icon,
|
||||||
|
hasEntry,
|
||||||
|
std::string(negation ? "is't" : "is")
|
||||||
|
+ PrintToString(QmlDesigner::ImageCacheStorageInterface::IconEntry{icon, hasEntry}))
|
||||||
|
{
|
||||||
|
const QmlDesigner::ImageCacheStorageInterface::IconEntry &entry = arg;
|
||||||
|
return entry.icon.availableSizes() == icon.availableSizes() && entry.hasEntry == hasEntry;
|
||||||
|
}
|
||||||
|
|
||||||
class ImageCacheStorageTest : public testing::Test
|
class ImageCacheStorageTest : public testing::Test
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
QImage createImage()
|
|
||||||
{
|
|
||||||
QImage image{150, 150, QImage::Format_ARGB32};
|
|
||||||
image.fill(QColor{128, 64, 0, 11});
|
|
||||||
image.setPixelColor(75, 75, QColor{1, 255, 33, 196});
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using ReadStatement = QmlDesigner::ImageCacheStorage<SqliteDatabaseMock>::ReadStatement;
|
using ReadStatement = QmlDesigner::ImageCacheStorage<SqliteDatabaseMock>::ReadStatement;
|
||||||
using WriteStatement = QmlDesigner::ImageCacheStorage<SqliteDatabaseMock>::WriteStatement;
|
using WriteStatement = QmlDesigner::ImageCacheStorage<SqliteDatabaseMock>::WriteStatement;
|
||||||
@@ -61,9 +61,13 @@ protected:
|
|||||||
NiceMock<SqliteDatabaseMock> databaseMock;
|
NiceMock<SqliteDatabaseMock> databaseMock;
|
||||||
QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
|
QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
|
||||||
ReadStatement &selectImageStatement = storage.selectImageStatement;
|
ReadStatement &selectImageStatement = storage.selectImageStatement;
|
||||||
|
ReadStatement &selectSmallImageStatement = storage.selectSmallImageStatement;
|
||||||
ReadStatement &selectIconStatement = storage.selectIconStatement;
|
ReadStatement &selectIconStatement = storage.selectIconStatement;
|
||||||
WriteStatement &upsertImageStatement = storage.upsertImageStatement;
|
WriteStatement &upsertImageStatement = storage.upsertImageStatement;
|
||||||
QImage image1{createImage()};
|
WriteStatement &upsertIconStatement = storage.upsertIconStatement;
|
||||||
|
QImage image1{10, 10, QImage::Format_ARGB32};
|
||||||
|
QImage smallImage1{10, 10, QImage::Format_ARGB32};
|
||||||
|
QIcon icon1{QPixmap::fromImage(image1)};
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageTest, Initialize)
|
TEST_F(ImageCacheStorageTest, Initialize)
|
||||||
@@ -73,12 +77,17 @@ TEST_F(ImageCacheStorageTest, Initialize)
|
|||||||
EXPECT_CALL(databaseMock, exclusiveBegin());
|
EXPECT_CALL(databaseMock, exclusiveBegin());
|
||||||
EXPECT_CALL(databaseMock,
|
EXPECT_CALL(databaseMock,
|
||||||
execute(Eq("CREATE TABLE IF NOT EXISTS images(id INTEGER PRIMARY KEY, name TEXT "
|
execute(Eq("CREATE TABLE IF NOT EXISTS images(id INTEGER PRIMARY KEY, name TEXT "
|
||||||
"NOT NULL UNIQUE, mtime INTEGER, image BLOB, icon BLOB)")));
|
"NOT NULL UNIQUE, mtime INTEGER, image BLOB, smallImage BLOB)")));
|
||||||
|
EXPECT_CALL(databaseMock,
|
||||||
|
execute(Eq("CREATE TABLE IF NOT EXISTS icons(id INTEGER PRIMARY KEY, name TEXT "
|
||||||
|
"NOT NULL UNIQUE, mtime INTEGER, icon BLOB)")));
|
||||||
EXPECT_CALL(databaseMock, commit());
|
EXPECT_CALL(databaseMock, commit());
|
||||||
EXPECT_CALL(databaseMock, immediateBegin());
|
EXPECT_CALL(databaseMock, immediateBegin());
|
||||||
EXPECT_CALL(databaseMock, prepare(Eq(selectImageStatement.sqlStatement)));
|
EXPECT_CALL(databaseMock, prepare(Eq(selectImageStatement.sqlStatement)));
|
||||||
|
EXPECT_CALL(databaseMock, prepare(Eq(selectSmallImageStatement.sqlStatement)));
|
||||||
EXPECT_CALL(databaseMock, prepare(Eq(selectIconStatement.sqlStatement)));
|
EXPECT_CALL(databaseMock, prepare(Eq(selectIconStatement.sqlStatement)));
|
||||||
EXPECT_CALL(databaseMock, prepare(Eq(upsertImageStatement.sqlStatement)));
|
EXPECT_CALL(databaseMock, prepare(Eq(upsertImageStatement.sqlStatement)));
|
||||||
|
EXPECT_CALL(databaseMock, prepare(Eq(upsertIconStatement.sqlStatement)));
|
||||||
EXPECT_CALL(databaseMock, commit());
|
EXPECT_CALL(databaseMock, commit());
|
||||||
|
|
||||||
QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
|
QmlDesigner::ImageCacheStorage<SqliteDatabaseMock> storage{databaseMock};
|
||||||
@@ -116,6 +125,38 @@ TEST_F(ImageCacheStorageTest, FetchImageCallsIsBusy)
|
|||||||
storage.fetchImage("/path/to/component", {123});
|
storage.fetchImage("/path/to/component", {123});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheStorageTest, FetchSmallImageCalls)
|
||||||
|
{
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
EXPECT_CALL(databaseMock, deferredBegin());
|
||||||
|
EXPECT_CALL(selectSmallImageStatement,
|
||||||
|
valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"),
|
||||||
|
TypedEq<long long>(123)));
|
||||||
|
EXPECT_CALL(databaseMock, commit());
|
||||||
|
|
||||||
|
storage.fetchSmallImage("/path/to/component", {123});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheStorageTest, FetchSmallImageCallsIsBusy)
|
||||||
|
{
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
EXPECT_CALL(databaseMock, deferredBegin());
|
||||||
|
EXPECT_CALL(selectSmallImageStatement,
|
||||||
|
valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"),
|
||||||
|
TypedEq<long long>(123)))
|
||||||
|
.WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
|
||||||
|
EXPECT_CALL(databaseMock, rollback());
|
||||||
|
EXPECT_CALL(databaseMock, deferredBegin());
|
||||||
|
EXPECT_CALL(selectSmallImageStatement,
|
||||||
|
valueReturnBlob(TypedEq<Utils::SmallStringView>("/path/to/component"),
|
||||||
|
TypedEq<long long>(123)));
|
||||||
|
EXPECT_CALL(databaseMock, commit());
|
||||||
|
|
||||||
|
storage.fetchSmallImage("/path/to/component", {123});
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageTest, FetchIconCalls)
|
TEST_F(ImageCacheStorageTest, FetchIconCalls)
|
||||||
{
|
{
|
||||||
InSequence s;
|
InSequence s;
|
||||||
@@ -156,11 +197,11 @@ TEST_F(ImageCacheStorageTest, StoreImageCalls)
|
|||||||
EXPECT_CALL(upsertImageStatement,
|
EXPECT_CALL(upsertImageStatement,
|
||||||
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
|
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
|
||||||
TypedEq<long long>(123),
|
TypedEq<long long>(123),
|
||||||
A<Sqlite::BlobView>(),
|
Not(IsEmpty()),
|
||||||
A<Sqlite::BlobView>()));
|
Not(IsEmpty())));
|
||||||
EXPECT_CALL(databaseMock, commit());
|
EXPECT_CALL(databaseMock, commit());
|
||||||
|
|
||||||
storage.storeImage("/path/to/component", {123}, image1);
|
storage.storeImage("/path/to/component", {123}, image1, smallImage1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageTest, StoreEmptyImageCalls)
|
TEST_F(ImageCacheStorageTest, StoreEmptyImageCalls)
|
||||||
@@ -171,11 +212,11 @@ TEST_F(ImageCacheStorageTest, StoreEmptyImageCalls)
|
|||||||
EXPECT_CALL(upsertImageStatement,
|
EXPECT_CALL(upsertImageStatement,
|
||||||
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
|
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
|
||||||
TypedEq<long long>(123),
|
TypedEq<long long>(123),
|
||||||
A<Sqlite::NullValue>(),
|
IsEmpty(),
|
||||||
A<Sqlite::NullValue>()));
|
IsEmpty()));
|
||||||
EXPECT_CALL(databaseMock, commit());
|
EXPECT_CALL(databaseMock, commit());
|
||||||
|
|
||||||
storage.storeImage("/path/to/component", {123}, QImage{});
|
storage.storeImage("/path/to/component", {123}, QImage{}, QImage{});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageTest, StoreImageCallsIsBusy)
|
TEST_F(ImageCacheStorageTest, StoreImageCallsIsBusy)
|
||||||
@@ -187,11 +228,54 @@ TEST_F(ImageCacheStorageTest, StoreImageCallsIsBusy)
|
|||||||
EXPECT_CALL(upsertImageStatement,
|
EXPECT_CALL(upsertImageStatement,
|
||||||
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
|
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
|
||||||
TypedEq<long long>(123),
|
TypedEq<long long>(123),
|
||||||
A<Sqlite::NullValue>(),
|
IsEmpty(),
|
||||||
A<Sqlite::NullValue>()));
|
IsEmpty()));
|
||||||
EXPECT_CALL(databaseMock, commit());
|
EXPECT_CALL(databaseMock, commit());
|
||||||
|
|
||||||
storage.storeImage("/path/to/component", {123}, QImage{});
|
storage.storeImage("/path/to/component", {123}, QImage{}, QImage{});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheStorageTest, StoreIconCalls)
|
||||||
|
{
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
EXPECT_CALL(databaseMock, immediateBegin());
|
||||||
|
EXPECT_CALL(upsertIconStatement,
|
||||||
|
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
|
||||||
|
TypedEq<long long>(123),
|
||||||
|
A<Sqlite::BlobView>()));
|
||||||
|
EXPECT_CALL(databaseMock, commit());
|
||||||
|
|
||||||
|
storage.storeIcon("/path/to/component", {123}, icon1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheStorageTest, StoreEmptyIconCalls)
|
||||||
|
{
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
EXPECT_CALL(databaseMock, immediateBegin());
|
||||||
|
EXPECT_CALL(upsertIconStatement,
|
||||||
|
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
|
||||||
|
TypedEq<long long>(123),
|
||||||
|
IsEmpty()));
|
||||||
|
EXPECT_CALL(databaseMock, commit());
|
||||||
|
|
||||||
|
storage.storeIcon("/path/to/component", {123}, QIcon{});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheStorageTest, StoreIconCallsIsBusy)
|
||||||
|
{
|
||||||
|
InSequence s;
|
||||||
|
|
||||||
|
EXPECT_CALL(databaseMock, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
|
||||||
|
EXPECT_CALL(databaseMock, immediateBegin());
|
||||||
|
EXPECT_CALL(upsertIconStatement,
|
||||||
|
write(TypedEq<Utils::SmallStringView>("/path/to/component"),
|
||||||
|
TypedEq<long long>(123),
|
||||||
|
IsEmpty()));
|
||||||
|
EXPECT_CALL(databaseMock, commit());
|
||||||
|
|
||||||
|
storage.storeIcon("/path/to/component", {123}, QIcon{});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageTest, CallWalCheckointFull)
|
TEST_F(ImageCacheStorageTest, CallWalCheckointFull)
|
||||||
@@ -227,108 +311,155 @@ protected:
|
|||||||
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
|
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
|
||||||
QmlDesigner::ImageCacheStorage<Sqlite::Database> storage{database};
|
QmlDesigner::ImageCacheStorage<Sqlite::Database> storage{database};
|
||||||
QImage image1{createImage()};
|
QImage image1{createImage()};
|
||||||
QImage image2{10, 10, QImage::Format_ARGB32};
|
QImage smallImage1{image1.scaled(96, 96)};
|
||||||
QImage icon1{image1.scaled(96, 96)};
|
QIcon icon1{QPixmap::fromImage(image1)};
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageSlowTest, StoreImage)
|
TEST_F(ImageCacheStorageSlowTest, StoreImage)
|
||||||
{
|
{
|
||||||
storage.storeImage("/path/to/component", {123}, image1);
|
storage.storeImage("/path/to/component", {123}, image1, smallImage1);
|
||||||
|
|
||||||
ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), IsEntry(image1, true));
|
ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), IsImageEntry(image1, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageSlowTest, StoreEmptyImageAfterEntry)
|
TEST_F(ImageCacheStorageSlowTest, StoreEmptyImageAfterEntry)
|
||||||
{
|
{
|
||||||
storage.storeImage("/path/to/component", {123}, image1);
|
storage.storeImage("/path/to/component", {123}, image1, smallImage1);
|
||||||
|
|
||||||
storage.storeImage("/path/to/component", {123}, QImage{});
|
storage.storeImage("/path/to/component", {123}, QImage{}, QImage{});
|
||||||
|
|
||||||
ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), IsEntry(QImage{}, true));
|
ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), IsImageEntry(QImage{}, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageSlowTest, StoreEmptyEntry)
|
TEST_F(ImageCacheStorageSlowTest, StoreEmptyEntry)
|
||||||
{
|
{
|
||||||
storage.storeImage("/path/to/component", {123}, QImage{});
|
storage.storeImage("/path/to/component", {123}, QImage{}, QImage{});
|
||||||
|
|
||||||
ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), IsEntry(QImage{}, true));
|
ASSERT_THAT(storage.fetchImage("/path/to/component", {123}), IsImageEntry(QImage{}, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageSlowTest, FetchNonExistingImageIsEmpty)
|
TEST_F(ImageCacheStorageSlowTest, FetchNonExistingImageIsEmpty)
|
||||||
{
|
{
|
||||||
auto image = storage.fetchImage("/path/to/component", {123});
|
auto image = storage.fetchImage("/path/to/component", {123});
|
||||||
|
|
||||||
ASSERT_THAT(image, IsEntry(QImage{}, false));
|
ASSERT_THAT(image, IsImageEntry(QImage{}, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageSlowTest, FetchSameTimeImage)
|
TEST_F(ImageCacheStorageSlowTest, FetchSameTimeImage)
|
||||||
{
|
{
|
||||||
storage.storeImage("/path/to/component", {123}, image1);
|
storage.storeImage("/path/to/component", {123}, image1, smallImage1);
|
||||||
|
|
||||||
auto image = storage.fetchImage("/path/to/component", {123});
|
auto image = storage.fetchImage("/path/to/component", {123});
|
||||||
|
|
||||||
ASSERT_THAT(image, IsEntry(image1, true));
|
ASSERT_THAT(image, IsImageEntry(image1, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderImage)
|
TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderImage)
|
||||||
{
|
{
|
||||||
storage.storeImage("/path/to/component", {123}, image1);
|
storage.storeImage("/path/to/component", {123}, image1, smallImage1);
|
||||||
|
|
||||||
auto image = storage.fetchImage("/path/to/component", {124});
|
auto image = storage.fetchImage("/path/to/component", {124});
|
||||||
|
|
||||||
ASSERT_THAT(image, IsEntry(QImage{}, false));
|
ASSERT_THAT(image, IsImageEntry(QImage{}, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageSlowTest, FetchNewerImage)
|
TEST_F(ImageCacheStorageSlowTest, FetchNewerImage)
|
||||||
{
|
{
|
||||||
storage.storeImage("/path/to/component", {123}, image1);
|
storage.storeImage("/path/to/component", {123}, image1, smallImage1);
|
||||||
|
|
||||||
auto image = storage.fetchImage("/path/to/component", {122});
|
auto image = storage.fetchImage("/path/to/component", {122});
|
||||||
|
|
||||||
ASSERT_THAT(image, IsEntry(image1, true));
|
ASSERT_THAT(image, IsImageEntry(image1, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheStorageSlowTest, FetchNonExistingSmallImageIsEmpty)
|
||||||
|
{
|
||||||
|
auto image = storage.fetchSmallImage("/path/to/component", {123});
|
||||||
|
|
||||||
|
ASSERT_THAT(image, IsImageEntry(QImage{}, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheStorageSlowTest, FetchSameTimeSmallImage)
|
||||||
|
{
|
||||||
|
storage.storeImage("/path/to/component", {123}, image1, smallImage1);
|
||||||
|
|
||||||
|
auto image = storage.fetchSmallImage("/path/to/component", {123});
|
||||||
|
|
||||||
|
ASSERT_THAT(image, IsImageEntry(smallImage1, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderSmallImage)
|
||||||
|
{
|
||||||
|
storage.storeImage("/path/to/component", {123}, image1, smallImage1);
|
||||||
|
|
||||||
|
auto image = storage.fetchSmallImage("/path/to/component", {124});
|
||||||
|
|
||||||
|
ASSERT_THAT(image, IsImageEntry(QImage{}, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheStorageSlowTest, FetchNewerSmallImage)
|
||||||
|
{
|
||||||
|
storage.storeImage("/path/to/component", {123}, image1, smallImage1);
|
||||||
|
|
||||||
|
auto image = storage.fetchSmallImage("/path/to/component", {122});
|
||||||
|
|
||||||
|
ASSERT_THAT(image, IsImageEntry(smallImage1, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheStorageSlowTest, StoreIcon)
|
||||||
|
{
|
||||||
|
storage.storeIcon("/path/to/component", {123}, icon1);
|
||||||
|
|
||||||
|
ASSERT_THAT(storage.fetchIcon("/path/to/component", {123}), IsIconEntry(icon1, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheStorageSlowTest, StoreEmptyIconAfterEntry)
|
||||||
|
{
|
||||||
|
storage.storeIcon("/path/to/component", {123}, icon1);
|
||||||
|
|
||||||
|
storage.storeIcon("/path/to/component", {123}, QIcon{});
|
||||||
|
|
||||||
|
ASSERT_THAT(storage.fetchIcon("/path/to/component", {123}), IsIconEntry(QIcon{}, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ImageCacheStorageSlowTest, StoreEmptyIconEntry)
|
||||||
|
{
|
||||||
|
storage.storeIcon("/path/to/component", {123}, QIcon{});
|
||||||
|
|
||||||
|
ASSERT_THAT(storage.fetchIcon("/path/to/component", {123}), IsIconEntry(QIcon{}, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageSlowTest, FetchNonExistingIconIsEmpty)
|
TEST_F(ImageCacheStorageSlowTest, FetchNonExistingIconIsEmpty)
|
||||||
{
|
{
|
||||||
auto image = storage.fetchIcon("/path/to/component", {123});
|
auto image = storage.fetchIcon("/path/to/component", {123});
|
||||||
|
|
||||||
ASSERT_THAT(image, IsEntry(QImage{}, false));
|
ASSERT_THAT(image, IsIconEntry(QIcon{}, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageSlowTest, FetchSameTimeIcon)
|
TEST_F(ImageCacheStorageSlowTest, FetchSameTimeIcon)
|
||||||
{
|
{
|
||||||
storage.storeImage("/path/to/component", {123}, image1);
|
storage.storeIcon("/path/to/component", {123}, icon1);
|
||||||
|
|
||||||
auto image = storage.fetchIcon("/path/to/component", {123});
|
auto image = storage.fetchIcon("/path/to/component", {123});
|
||||||
|
|
||||||
ASSERT_THAT(image, IsEntry(icon1, true));
|
ASSERT_THAT(image, IsIconEntry(icon1, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderIcon)
|
TEST_F(ImageCacheStorageSlowTest, DoNotFetchOlderIcon)
|
||||||
{
|
{
|
||||||
storage.storeImage("/path/to/component", {123}, image1);
|
storage.storeIcon("/path/to/component", {123}, icon1);
|
||||||
|
|
||||||
auto image = storage.fetchIcon("/path/to/component", {124});
|
auto image = storage.fetchIcon("/path/to/component", {124});
|
||||||
|
|
||||||
ASSERT_THAT(image, IsEntry(QImage{}, false));
|
ASSERT_THAT(image, IsIconEntry(QIcon{}, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageSlowTest, FetchNewerIcon)
|
TEST_F(ImageCacheStorageSlowTest, FetchNewerIcon)
|
||||||
{
|
{
|
||||||
storage.storeImage("/path/to/component", {123}, image1);
|
storage.storeIcon("/path/to/component", {123}, icon1);
|
||||||
|
|
||||||
auto image = storage.fetchIcon("/path/to/component", {122});
|
auto image = storage.fetchIcon("/path/to/component", {122});
|
||||||
|
|
||||||
ASSERT_THAT(image, IsEntry(icon1, true));
|
ASSERT_THAT(image, IsIconEntry(icon1, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ImageCacheStorageSlowTest, DontScaleSmallerIcon)
|
|
||||||
{
|
|
||||||
storage.storeImage("/path/to/component", {123}, image2);
|
|
||||||
|
|
||||||
auto image = storage.fetchImage("/path/to/component", {122});
|
|
||||||
|
|
||||||
ASSERT_THAT(image, IsEntry(image2, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ public:
|
|||||||
Utils::SmallStringView state,
|
Utils::SmallStringView state,
|
||||||
Sqlite::TimeStamp timeStamp,
|
Sqlite::TimeStamp timeStamp,
|
||||||
CaptureCallback &&captureCallback,
|
CaptureCallback &&captureCallback,
|
||||||
AbortCallback &&abortCallback),
|
AbortCallback &&abortCallback,
|
||||||
|
QmlDesigner::ImageCache::AuxiliaryData &&auxiliaryData),
|
||||||
(override));
|
(override));
|
||||||
MOCK_METHOD(void, clean, (), (override));
|
MOCK_METHOD(void, clean, (), (override));
|
||||||
MOCK_METHOD(void, waitForFinished, (), (override));
|
MOCK_METHOD(void, waitForFinished, (), (override));
|
||||||
|
|||||||
@@ -32,19 +32,33 @@
|
|||||||
class MockImageCacheStorage : public QmlDesigner::ImageCacheStorageInterface
|
class MockImageCacheStorage : public QmlDesigner::ImageCacheStorageInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MOCK_METHOD(QmlDesigner::ImageCacheStorageInterface::Entry,
|
MOCK_METHOD(QmlDesigner::ImageCacheStorageInterface::ImageEntry,
|
||||||
fetchImage,
|
fetchImage,
|
||||||
(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp),
|
(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp),
|
||||||
(const, override));
|
(const, override));
|
||||||
|
|
||||||
MOCK_METHOD(QmlDesigner::ImageCacheStorageInterface::Entry,
|
MOCK_METHOD(QmlDesigner::ImageCacheStorageInterface::ImageEntry,
|
||||||
|
fetchSmallImage,
|
||||||
|
(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp),
|
||||||
|
(const, override));
|
||||||
|
|
||||||
|
MOCK_METHOD(QmlDesigner::ImageCacheStorageInterface::IconEntry,
|
||||||
fetchIcon,
|
fetchIcon,
|
||||||
(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp),
|
(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp),
|
||||||
(const, override));
|
(const, override));
|
||||||
|
|
||||||
MOCK_METHOD(void,
|
MOCK_METHOD(void,
|
||||||
storeImage,
|
storeImage,
|
||||||
(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QImage &image),
|
(Utils::SmallStringView name,
|
||||||
|
Sqlite::TimeStamp newTimeStamp,
|
||||||
|
const QImage &image,
|
||||||
|
const QImage &smallImage),
|
||||||
(override));
|
(override));
|
||||||
|
|
||||||
|
MOCK_METHOD(void,
|
||||||
|
storeIcon,
|
||||||
|
(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QIcon &icon),
|
||||||
|
(override));
|
||||||
|
|
||||||
MOCK_METHOD(void, walCheckpointFull, (), (override));
|
MOCK_METHOD(void, walCheckpointFull, (), (override));
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundValu
|
|||||||
TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundBlob)
|
TEST_F(SqliteStatement, BindIndexIsToLargeIsThrowingBindingIndexIsOutOfBoundBlob)
|
||||||
{
|
{
|
||||||
SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database);
|
SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT blob FROM T", database);
|
||||||
Sqlite::BlobView bytes;
|
Sqlite::BlobView bytes{QByteArray{"XXX"}};
|
||||||
|
|
||||||
ASSERT_THROW(statement.bind(2, bytes), Sqlite::BindingIndexIsOutOfRange);
|
ASSERT_THROW(statement.bind(2, bytes), Sqlite::BindingIndexIsOutOfRange);
|
||||||
}
|
}
|
||||||
@@ -505,6 +505,18 @@ TEST_F(SqliteStatement, WriteEmptyBlobs)
|
|||||||
ASSERT_THAT(statement.fetchBlobValue(0), IsEmpty());
|
ASSERT_THAT(statement.fetchBlobValue(0), IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SqliteStatement, EmptyBlobsAreNull)
|
||||||
|
{
|
||||||
|
SqliteTestStatement statement("WITH T(blob) AS (VALUES (?)) SELECT ifnull(blob, 1) FROM T",
|
||||||
|
database);
|
||||||
|
|
||||||
|
Sqlite::BlobView bytes;
|
||||||
|
|
||||||
|
statement.write(bytes);
|
||||||
|
|
||||||
|
ASSERT_THAT(statement.fetchType(0), Eq(Sqlite::Type::Null));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(SqliteStatement, WriteBlobs)
|
TEST_F(SqliteStatement, WriteBlobs)
|
||||||
{
|
{
|
||||||
SqliteTestStatement statement("INSERT INTO test VALUES ('blob', 40, ?)", database);
|
SqliteTestStatement statement("INSERT INTO test VALUES ('blob', 40, ?)", database);
|
||||||
|
|||||||
@@ -52,11 +52,8 @@ public:
|
|||||||
MOCK_METHOD(void, write, (Utils::SmallStringView, Utils::SmallStringView, double), ());
|
MOCK_METHOD(void, write, (Utils::SmallStringView, Utils::SmallStringView, double), ());
|
||||||
MOCK_METHOD(void, write, (long long, Utils::SmallStringView, Utils::SmallStringView), ());
|
MOCK_METHOD(void, write, (long long, Utils::SmallStringView, Utils::SmallStringView), ());
|
||||||
MOCK_METHOD(void, write, (long long, Utils::SmallStringView, const Sqlite::Value &), ());
|
MOCK_METHOD(void, write, (long long, Utils::SmallStringView, const Sqlite::Value &), ());
|
||||||
|
MOCK_METHOD(void, write, (Utils::SmallStringView, long long, Sqlite::BlobView), ());
|
||||||
MOCK_METHOD(void, write, (Utils::SmallStringView, long long, Sqlite::BlobView, Sqlite::BlobView), ());
|
MOCK_METHOD(void, write, (Utils::SmallStringView, long long, Sqlite::BlobView, Sqlite::BlobView), ());
|
||||||
MOCK_METHOD(void,
|
|
||||||
write,
|
|
||||||
(Utils::SmallStringView, long long, Sqlite::NullValue, Sqlite::NullValue),
|
|
||||||
());
|
|
||||||
MOCK_METHOD(void,
|
MOCK_METHOD(void,
|
||||||
write,
|
write,
|
||||||
(Utils::SmallStringView,
|
(Utils::SmallStringView,
|
||||||
|
|||||||
269
tests/unit/unittest/synchronousimagecache-test.cpp
Normal file
269
tests/unit/unittest/synchronousimagecache-test.cpp
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "googletest.h"
|
||||||
|
|
||||||
|
#include "imagecachecollectormock.h"
|
||||||
|
#include "mockimagecachestorage.h"
|
||||||
|
#include "mocktimestampprovider.h"
|
||||||
|
|
||||||
|
#include <synchronousimagecache.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
MATCHER_P(IsIcon, icon, std::string(negation ? "isn't " : "is ") + PrintToString(icon))
|
||||||
|
{
|
||||||
|
const QIcon &other = arg;
|
||||||
|
return icon.availableSizes() == other.availableSizes();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SynchronousImageCache : public testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
SynchronousImageCache()
|
||||||
|
{
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{123}));
|
||||||
|
ON_CALL(mockStorage, fetchImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
|
||||||
|
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{image1, true}));
|
||||||
|
ON_CALL(mockStorage,
|
||||||
|
fetchImage(Eq("/path/to/Component.qml+extraId1"), Eq(Sqlite::TimeStamp{123})))
|
||||||
|
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{image2, true}));
|
||||||
|
ON_CALL(mockStorage, fetchSmallImage(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
|
||||||
|
.WillByDefault(
|
||||||
|
Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{smallImage1, true}));
|
||||||
|
ON_CALL(mockStorage,
|
||||||
|
fetchSmallImage(Eq("/path/to/Component.qml+extraId1"), Eq(Sqlite::TimeStamp{123})))
|
||||||
|
.WillByDefault(
|
||||||
|
Return(QmlDesigner::ImageCacheStorageInterface::ImageEntry{smallImage2, true}));
|
||||||
|
ON_CALL(mockStorage, fetchIcon(Eq("/path/to/Component.qml"), Eq(Sqlite::TimeStamp{123})))
|
||||||
|
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::IconEntry{icon1, true}));
|
||||||
|
ON_CALL(mockStorage,
|
||||||
|
fetchIcon(Eq("/path/to/Component.qml+extraId1"), Eq(Sqlite::TimeStamp{123})))
|
||||||
|
.WillByDefault(Return(QmlDesigner::ImageCacheStorageInterface::IconEntry{icon2, true}));
|
||||||
|
ON_CALL(mockCollector, createImage(Eq("/path/to/Component.qml"), Eq("extraId1"), _))
|
||||||
|
.WillByDefault(Return(std::make_pair(image3, smallImage3)));
|
||||||
|
ON_CALL(mockCollector, createIcon(Eq("/path/to/Component.qml"), Eq("extraId1"), _))
|
||||||
|
.WillByDefault(Return(icon3));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
NiceMock<MockFunction<void(const QImage &image)>> mockCaptureCallback;
|
||||||
|
NiceMock<MockImageCacheStorage> mockStorage;
|
||||||
|
NiceMock<ImageCacheCollectorMock> mockCollector;
|
||||||
|
NiceMock<MockTimeStampProvider> mockTimeStampProvider;
|
||||||
|
QmlDesigner::SynchronousImageCache cache{mockStorage, mockTimeStampProvider, mockCollector};
|
||||||
|
QImage image1{1, 1, QImage::Format_ARGB32};
|
||||||
|
QImage image2{2, 2, QImage::Format_ARGB32};
|
||||||
|
QImage image3{3, 3, QImage::Format_ARGB32};
|
||||||
|
QImage smallImage1{1, 1, QImage::Format_ARGB32};
|
||||||
|
QImage smallImage2{2, 1, QImage::Format_ARGB32};
|
||||||
|
QImage smallImage3{3, 1, QImage::Format_ARGB32};
|
||||||
|
QIcon icon1{QPixmap::fromImage(image1)};
|
||||||
|
QIcon icon2{QPixmap::fromImage(image2)};
|
||||||
|
QIcon icon3{QPixmap::fromImage(image3)};
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, GetImageFromStorage)
|
||||||
|
{
|
||||||
|
auto image = cache.image("/path/to/Component.qml");
|
||||||
|
|
||||||
|
ASSERT_THAT(image, image1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, GetImageWithExtraIdFromStorage)
|
||||||
|
{
|
||||||
|
auto image = cache.image("/path/to/Component.qml", "extraId1");
|
||||||
|
|
||||||
|
ASSERT_THAT(image, image2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, GetImageWithOutdatedTimeStampFromCollector)
|
||||||
|
{
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{124}));
|
||||||
|
|
||||||
|
auto image = cache.image("/path/to/Component.qml", "extraId1");
|
||||||
|
|
||||||
|
ASSERT_THAT(image, image3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, GetImageWithOutdatedTimeStampStored)
|
||||||
|
{
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{124}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockStorage,
|
||||||
|
storeImage(Eq("/path/to/Component.qml+extraId1"),
|
||||||
|
Eq(Sqlite::TimeStamp{124}),
|
||||||
|
Eq(image3),
|
||||||
|
Eq(smallImage3)));
|
||||||
|
|
||||||
|
auto image = cache.image("/path/to/Component.qml", "extraId1");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, GetSmallImageFromStorage)
|
||||||
|
{
|
||||||
|
auto image = cache.smallImage("/path/to/Component.qml");
|
||||||
|
|
||||||
|
ASSERT_THAT(image, smallImage1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, GetSmallImageWithExtraIdFromStorage)
|
||||||
|
{
|
||||||
|
auto image = cache.smallImage("/path/to/Component.qml", "extraId1");
|
||||||
|
|
||||||
|
ASSERT_THAT(image, smallImage2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, GetSmallImageWithOutdatedTimeStampFromCollector)
|
||||||
|
{
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{124}));
|
||||||
|
|
||||||
|
auto image = cache.smallImage("/path/to/Component.qml", "extraId1");
|
||||||
|
|
||||||
|
ASSERT_THAT(image, smallImage3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, GetSmallImageWithOutdatedTimeStampStored)
|
||||||
|
{
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{124}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockStorage,
|
||||||
|
storeImage(Eq("/path/to/Component.qml+extraId1"),
|
||||||
|
Eq(Sqlite::TimeStamp{124}),
|
||||||
|
Eq(image3),
|
||||||
|
Eq(smallImage3)));
|
||||||
|
|
||||||
|
auto image = cache.smallImage("/path/to/Component.qml", "extraId1");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, GetIconFromStorage)
|
||||||
|
{
|
||||||
|
auto icon = cache.icon("/path/to/Component.qml");
|
||||||
|
|
||||||
|
ASSERT_THAT(icon, IsIcon(icon1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, GetIconWithExtraIdFromStorage)
|
||||||
|
{
|
||||||
|
auto icon = cache.icon("/path/to/Component.qml", "extraId1");
|
||||||
|
|
||||||
|
ASSERT_THAT(icon, IsIcon(icon2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, GetIconWithOutdatedTimeStampFromCollector)
|
||||||
|
{
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{124}));
|
||||||
|
|
||||||
|
auto icon = cache.icon("/path/to/Component.qml", "extraId1");
|
||||||
|
|
||||||
|
ASSERT_THAT(icon, IsIcon(icon3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, GetIconWithOutdatedTimeStampStored)
|
||||||
|
{
|
||||||
|
using QmlDesigner::ImageCache::FontCollectorSizesAuxiliaryData;
|
||||||
|
std::vector<QSize> sizes{{20, 11}};
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{124}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockStorage,
|
||||||
|
storeIcon(Eq("/path/to/Component.qml+extraId1"),
|
||||||
|
Eq(Sqlite::TimeStamp{124}),
|
||||||
|
IsIcon(icon3)));
|
||||||
|
|
||||||
|
auto icon = cache.icon("/path/to/Component.qml",
|
||||||
|
"extraId1",
|
||||||
|
FontCollectorSizesAuxiliaryData{sizes, "color"});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, IconCallsCollectorWithAuxiliaryData)
|
||||||
|
{
|
||||||
|
using QmlDesigner::ImageCache::FontCollectorSizesAuxiliaryData;
|
||||||
|
std::vector<QSize> sizes{{20, 11}};
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{124}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockCollector,
|
||||||
|
createIcon(Eq("/path/to/Component.qml"),
|
||||||
|
Eq("extraId1"),
|
||||||
|
VariantWith<FontCollectorSizesAuxiliaryData>(
|
||||||
|
AllOf(Field(&FontCollectorSizesAuxiliaryData::sizes,
|
||||||
|
ElementsAre(QSize{20, 11})),
|
||||||
|
Field(&FontCollectorSizesAuxiliaryData::colorName,
|
||||||
|
Eq(u"color"))))));
|
||||||
|
|
||||||
|
auto icon = cache.icon("/path/to/Component.qml",
|
||||||
|
"extraId1",
|
||||||
|
FontCollectorSizesAuxiliaryData{sizes, "color"});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, ImageCallsCollectorWithAuxiliaryData)
|
||||||
|
{
|
||||||
|
using QmlDesigner::ImageCache::FontCollectorSizesAuxiliaryData;
|
||||||
|
std::vector<QSize> sizes{{20, 11}};
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{124}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockCollector,
|
||||||
|
createImage(Eq("/path/to/Component.qml"),
|
||||||
|
Eq("extraId1"),
|
||||||
|
VariantWith<FontCollectorSizesAuxiliaryData>(
|
||||||
|
AllOf(Field(&FontCollectorSizesAuxiliaryData::sizes,
|
||||||
|
ElementsAre(QSize{20, 11})),
|
||||||
|
Field(&FontCollectorSizesAuxiliaryData::colorName,
|
||||||
|
Eq(u"color"))))));
|
||||||
|
|
||||||
|
auto icon = cache.image("/path/to/Component.qml",
|
||||||
|
"extraId1",
|
||||||
|
FontCollectorSizesAuxiliaryData{sizes, "color"});
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SynchronousImageCache, SmallImageCallsCollectorWithAuxiliaryData)
|
||||||
|
{
|
||||||
|
using QmlDesigner::ImageCache::FontCollectorSizesAuxiliaryData;
|
||||||
|
std::vector<QSize> sizes{{20, 11}};
|
||||||
|
ON_CALL(mockTimeStampProvider, timeStamp(Eq("/path/to/Component.qml")))
|
||||||
|
.WillByDefault(Return(Sqlite::TimeStamp{124}));
|
||||||
|
|
||||||
|
EXPECT_CALL(mockCollector,
|
||||||
|
createImage(Eq("/path/to/Component.qml"),
|
||||||
|
Eq("extraId1"),
|
||||||
|
VariantWith<FontCollectorSizesAuxiliaryData>(
|
||||||
|
AllOf(Field(&FontCollectorSizesAuxiliaryData::sizes,
|
||||||
|
ElementsAre(QSize{20, 11})),
|
||||||
|
Field(&FontCollectorSizesAuxiliaryData::colorName,
|
||||||
|
Eq(u"color"))))));
|
||||||
|
|
||||||
|
auto icon = cache.smallImage("/path/to/Component.qml",
|
||||||
|
"extraId1",
|
||||||
|
FontCollectorSizesAuxiliaryData{sizes, "color"});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@@ -66,7 +66,8 @@ SOURCES += \
|
|||||||
filepathview-test.cpp \
|
filepathview-test.cpp \
|
||||||
gtest-creator-printing.cpp \
|
gtest-creator-printing.cpp \
|
||||||
gtest-qt-printing.cpp \
|
gtest-qt-printing.cpp \
|
||||||
imagecache-test.cpp \
|
asynchronousimagecache-test.cpp \
|
||||||
|
synchronousimagecache-test.cpp \
|
||||||
imagecachegenerator-test.cpp \
|
imagecachegenerator-test.cpp \
|
||||||
imagecachestorage-test.cpp \
|
imagecachestorage-test.cpp \
|
||||||
lastchangedrowid-test.cpp \
|
lastchangedrowid-test.cpp \
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
#include <sqliteglobal.h>
|
#include <sqliteglobal.h>
|
||||||
#include <utils/temporarydirectory.h>
|
#include <utils/temporarydirectory.h>
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QGuiApplication>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
#ifdef WITH_BENCHMARKS
|
#ifdef WITH_BENCHMARKS
|
||||||
@@ -54,7 +54,7 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
Sqlite::Database::activateLogging();
|
Sqlite::Database::activateLogging();
|
||||||
|
|
||||||
QCoreApplication application(argc, argv);
|
QGuiApplication application(argc, argv);
|
||||||
|
|
||||||
testing::InitGoogleTest(&argc, argv);
|
testing::InitGoogleTest(&argc, argv);
|
||||||
#ifdef WITH_BENCHMARKS
|
#ifdef WITH_BENCHMARKS
|
||||||
|
|||||||
Reference in New Issue
Block a user