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:
@@ -509,8 +509,10 @@ extend_qtc_plugin(QmlDesigner
|
||||
include/textmodifier.h
|
||||
include/variantproperty.h
|
||||
include/viewmanager.h
|
||||
include/imagecache.h
|
||||
include/imagecacheinterface.h
|
||||
include/asynchronousimagecache.h
|
||||
include/synchronousimagecache.h
|
||||
include/imagecacheauxiliarydata.h
|
||||
include/asynchronousimagecacheinterface.h
|
||||
)
|
||||
|
||||
extend_qtc_plugin(QmlDesigner
|
||||
@@ -601,7 +603,8 @@ extend_qtc_plugin(QmlDesigner
|
||||
imagecache/imagecachecollector.cpp
|
||||
imagecache/imagecachefontcollector.h
|
||||
imagecache/imagecachefontcollector.cpp
|
||||
imagecache/imagecache.cpp
|
||||
imagecache/asynchronousimagecache.cpp
|
||||
imagecache/synchronousimagecache.cpp
|
||||
imagecache/imagecachecollectorinterface.h
|
||||
imagecache/imagecacheconnectionmanager.cpp
|
||||
imagecache/imagecacheconnectionmanager.h
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
#include "customfilesystemmodel.h"
|
||||
|
||||
#include <synchronousimagecache.h>
|
||||
#include <theme.h>
|
||||
#include <imagecache.h>
|
||||
|
||||
#include <utils/filesystemwatcher.h>
|
||||
|
||||
@@ -98,7 +98,7 @@ QString fontFamily(const QFileInfo &info)
|
||||
class ItemLibraryFileIconProvider : public QFileIconProvider
|
||||
{
|
||||
public:
|
||||
ItemLibraryFileIconProvider(ImageCache &fontImageCache)
|
||||
ItemLibraryFileIconProvider(SynchronousImageCache &fontImageCache)
|
||||
: QFileIconProvider()
|
||||
, m_fontImageCache(fontImageCache)
|
||||
{
|
||||
@@ -138,71 +138,29 @@ public:
|
||||
|
||||
QIcon generateFontIcons(const QString &filePath) const
|
||||
{
|
||||
QIcon 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,
|
||||
[&images, &condition, &count, &mutex, iconSize](const QImage &image) {
|
||||
int currentCount;
|
||||
{
|
||||
std::unique_lock lock{mutex};
|
||||
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;
|
||||
return m_fontImageCache.icon(
|
||||
filePath,
|
||||
{},
|
||||
ImageCache::FontCollectorSizesAuxiliaryData{Utils::span{iconSizes},
|
||||
Theme::getColor(Theme::DStextColor).name(),
|
||||
"Abc"});
|
||||
}
|
||||
|
||||
// Generated icon sizes should contain all ItemLibraryResourceView needed icon sizes, and their
|
||||
// x2 versions for HDPI sceens
|
||||
QList<QSize> iconSizes = {{384, 384}, {192, 192}, // Large
|
||||
{256, 256}, {128, 128}, // Drag
|
||||
{96, 96}, // Medium
|
||||
{48, 48}, // Small
|
||||
{64, 64}, {32, 32}}; // List
|
||||
std::vector<QSize> iconSizes = {{384, 384},
|
||||
{192, 192}, // Large
|
||||
{256, 256},
|
||||
{128, 128}, // Drag
|
||||
{96, 96}, // Medium
|
||||
{48, 48}, // Small
|
||||
{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)
|
||||
, m_fileSystemModel(new QFileSystemModel(this))
|
||||
, m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
|
||||
|
||||
@@ -39,13 +39,14 @@ namespace Utils { class FileSystemWatcher; }
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ImageCache;
|
||||
class SynchronousImageCache;
|
||||
|
||||
class CustomFileSystemModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CustomFileSystemModel(ImageCache &fontImageCache, QObject *parent = nullptr);
|
||||
CustomFileSystemModel(QmlDesigner::SynchronousImageCache &fontImageCache,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
void setFilter(QDir::Filters filters);
|
||||
QString rootPath() const;
|
||||
|
||||
@@ -66,7 +66,7 @@ QQuickImageResponse *ItemLibraryIconImageProvider::requestImageResponse(const QS
|
||||
{
|
||||
auto response = std::make_unique<ImageRespose>();
|
||||
|
||||
m_cache.requestIcon(
|
||||
m_cache.requestSmallImage(
|
||||
id,
|
||||
[response = QPointer<ImageRespose>(response.get())](const QImage &image) {
|
||||
QMetaObject::invokeMethod(
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <rewriterview.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <imagecache.h>
|
||||
#include <asynchronousimagecache.h>
|
||||
#include <imagecache/imagecachecollector.h>
|
||||
#include <imagecache/imagecacheconnectionmanager.h>
|
||||
#include <imagecache/imagecachegenerator.h>
|
||||
@@ -45,14 +45,14 @@ namespace QmlDesigner {
|
||||
class ItemLibraryIconImageProvider : public QQuickAsyncImageProvider
|
||||
{
|
||||
public:
|
||||
ItemLibraryIconImageProvider(ImageCache &imageCache)
|
||||
ItemLibraryIconImageProvider(AsynchronousImageCache &imageCache)
|
||||
: m_cache{imageCache}
|
||||
{}
|
||||
|
||||
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
|
||||
|
||||
private:
|
||||
ImageCache &m_cache;
|
||||
AsynchronousImageCache &m_cache;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "customfilesystemmodel.h"
|
||||
|
||||
#include <theme.h>
|
||||
#include <imagecache.h>
|
||||
#include <asynchronousimagecache.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
@@ -62,8 +62,9 @@ void ItemLibraryResourceView::addSizeAction(QActionGroup *group, const QString &
|
||||
});
|
||||
}
|
||||
|
||||
ItemLibraryResourceView::ItemLibraryResourceView(ImageCache &fontImageCache, QWidget *parent) :
|
||||
QListView(parent)
|
||||
ItemLibraryResourceView::ItemLibraryResourceView(AsynchronousImageCache &fontImageCache,
|
||||
QWidget *parent)
|
||||
: QListView(parent)
|
||||
{
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
@@ -113,13 +114,12 @@ ItemLibraryResourceView::ItemLibraryResourceView(ImageCache &fontImageCache, QWi
|
||||
// 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
|
||||
// suffice for preview. Font family name is inserted into %1 at render time.
|
||||
m_fontPreviewTooltipBackend->setState(QStringLiteral("%1@%2@%3")
|
||||
.arg(QString::number(300),
|
||||
Theme::getColor(Theme::DStextColor).name(),
|
||||
QStringLiteral("%1\n\n"
|
||||
"The quick brown fox jumps\n"
|
||||
"over the lazy dog\n"
|
||||
"1234567890")));
|
||||
m_fontPreviewTooltipBackend->setAuxiliaryData(
|
||||
ImageCache::FontCollectorSizeAuxiliaryData{QSize{300, 300},
|
||||
Theme::getColor(Theme::DStextColor).name(),
|
||||
QStringLiteral("The quick brown fox jumps\n"
|
||||
"over the lazy dog\n"
|
||||
"1234567890")});
|
||||
}
|
||||
|
||||
void ItemLibraryResourceView::startDrag(Qt::DropActions /* supportedActions */)
|
||||
|
||||
@@ -35,13 +35,14 @@ QT_END_NAMESPACE
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ImageCache;
|
||||
class AsynchronousImageCache;
|
||||
|
||||
class ItemLibraryResourceView : public QListView {
|
||||
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ItemLibraryResourceView(ImageCache &fontImageCache, QWidget *parent = nullptr);
|
||||
explicit ItemLibraryResourceView(AsynchronousImageCache &fontImageCache,
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
void startDrag(Qt::DropActions supportedActions) override;
|
||||
bool viewportEvent(QEvent *event) override;
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
#include "itemlibraryview.h"
|
||||
#include "itemlibrarywidget.h"
|
||||
#include "metainfo.h"
|
||||
#include <asynchronousimagecache.h>
|
||||
#include <bindingproperty.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <imagecache.h>
|
||||
#include <imagecache/imagecachecollector.h>
|
||||
#include <imagecache/imagecachefontcollector.h>
|
||||
#include <imagecache/imagecacheconnectionmanager.h>
|
||||
#include <imagecache/imagecachefontcollector.h>
|
||||
#include <imagecache/imagecachegenerator.h>
|
||||
#include <imagecache/imagecachestorage.h>
|
||||
#include <imagecache/timestampprovider.h>
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <projectexplorer/target.h>
|
||||
#include <rewriterview.h>
|
||||
#include <sqlitedatabase.h>
|
||||
#include <synchronousimagecache.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
#include <qmlitemnode.h>
|
||||
@@ -52,7 +53,7 @@ class ImageCacheData
|
||||
{
|
||||
public:
|
||||
Sqlite::Database database{
|
||||
Utils::PathString{Core::ICore::cacheResourcePath() + "/imagecache-v1.db"}};
|
||||
Utils::PathString{Core::ICore::cacheResourcePath() + "/imagecache-v2.db"}};
|
||||
ImageCacheStorage<Sqlite::Database> storage{database};
|
||||
ImageCacheConnectionManager connectionManager;
|
||||
ImageCacheCollector collector{connectionManager};
|
||||
@@ -60,8 +61,9 @@ public:
|
||||
ImageCacheGenerator generator{collector, storage};
|
||||
ImageCacheGenerator fontGenerator{fontCollector, storage};
|
||||
TimeStampProvider timeStampProvider;
|
||||
ImageCache cache{storage, generator, timeStampProvider};
|
||||
ImageCache fontImageCache{storage, fontGenerator, timeStampProvider};
|
||||
AsynchronousImageCache cache{storage, generator, timeStampProvider};
|
||||
AsynchronousImageCache asynchronousFontImageCache{storage, fontGenerator, timeStampProvider};
|
||||
SynchronousImageCache synchronousFontImageCache{storage, timeStampProvider, fontCollector};
|
||||
};
|
||||
|
||||
ItemLibraryView::ItemLibraryView(QObject* parent)
|
||||
@@ -82,7 +84,9 @@ bool ItemLibraryView::hasWidget() const
|
||||
WidgetInfo ItemLibraryView::widgetInfo()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -159,12 +163,14 @@ void ItemLibraryView::importsChanged(const QList<Import> &addedImports, const QL
|
||||
void ItemLibraryView::setResourcePath(const QString &resourcePath)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
ImageCache &ItemLibraryView::imageCache()
|
||||
AsynchronousImageCache &ItemLibraryView::imageCache()
|
||||
{
|
||||
return m_imageCacheData->cache;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace QmlDesigner {
|
||||
class ItemLibraryWidget;
|
||||
class ImportManagerView;
|
||||
class ImageCacheData;
|
||||
class ImageCache;
|
||||
class AsynchronousImageCache;
|
||||
|
||||
class ItemLibraryView : public AbstractView
|
||||
{
|
||||
@@ -56,7 +56,7 @@ public:
|
||||
|
||||
void setResourcePath(const QString &resourcePath);
|
||||
|
||||
ImageCache &imageCache();
|
||||
AsynchronousImageCache &imageCache();
|
||||
|
||||
protected:
|
||||
void updateImports();
|
||||
|
||||
@@ -82,10 +82,12 @@ static QString propertyEditorResourcesPath() {
|
||||
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_itemViewQuickWidget(new QQuickWidget(this))
|
||||
, m_resourcesView(new ItemLibraryResourceView(fontImageCache, this))
|
||||
, m_resourcesView(new ItemLibraryResourceView(asynchronousFontImageCache, this))
|
||||
, m_importTagsWidget(new QWidget(this))
|
||||
, m_addResourcesWidget(new QWidget(this))
|
||||
, m_imageCache{imageCache}
|
||||
@@ -118,7 +120,7 @@ ItemLibraryWidget::ItemLibraryWidget(ImageCache &imageCache, ImageCache &fontIma
|
||||
Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
|
||||
|
||||
/* create Resources view and its model */
|
||||
m_resourcesFileSystemModel = new CustomFileSystemModel(fontImageCache, this);
|
||||
m_resourcesFileSystemModel = new CustomFileSystemModel(synchronousFontImageCache, this);
|
||||
m_resourcesView->setModel(m_resourcesFileSystemModel.data());
|
||||
|
||||
/* create image provider for loading item icons */
|
||||
|
||||
@@ -56,7 +56,8 @@ class CustomFileSystemModel;
|
||||
|
||||
class ItemLibraryModel;
|
||||
class ItemLibraryResourceView;
|
||||
class ImageCache;
|
||||
class SynchronousImageCache;
|
||||
class AsynchronousImageCache;
|
||||
class ImageCacheCollector;
|
||||
|
||||
class ItemLibraryWidget : public QFrame
|
||||
@@ -69,7 +70,9 @@ class ItemLibraryWidget : public QFrame
|
||||
};
|
||||
|
||||
public:
|
||||
ItemLibraryWidget(ImageCache &imageCache, ImageCache &fontImageCache);
|
||||
ItemLibraryWidget(AsynchronousImageCache &imageCache,
|
||||
AsynchronousImageCache &asynchronousFontImageCache,
|
||||
SynchronousImageCache &synchronousFontImageCache);
|
||||
~ItemLibraryWidget();
|
||||
|
||||
void setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo);
|
||||
@@ -126,7 +129,7 @@ private:
|
||||
std::unique_ptr<PreviewTooltipBackend> m_previewTooltipBackend;
|
||||
|
||||
QShortcut *m_qmlSourceUpdateShortcut;
|
||||
ImageCache &m_imageCache;
|
||||
AsynchronousImageCache &m_imageCache;
|
||||
QPointer<Model> m_model;
|
||||
FilterChangeFlag m_filterFlag;
|
||||
ItemLibraryEntry m_currentitemLibraryEntry;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include "previewimagetooltip.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <imagecache.h>
|
||||
#include <asynchronousimagecache.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMetaObject>
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
PreviewTooltipBackend::PreviewTooltipBackend(ImageCache &cache)
|
||||
PreviewTooltipBackend::PreviewTooltipBackend(AsynchronousImageCache &cache)
|
||||
: m_cache{cache}
|
||||
{}
|
||||
|
||||
@@ -64,8 +64,8 @@ void PreviewTooltipBackend::showTooltip()
|
||||
});
|
||||
},
|
||||
[] {},
|
||||
m_state
|
||||
);
|
||||
m_extraId,
|
||||
m_auxiliaryData);
|
||||
|
||||
reposition();
|
||||
}
|
||||
@@ -155,17 +155,17 @@ void PreviewTooltipBackend::setInfo(const QString &info)
|
||||
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.
|
||||
void PreviewTooltipBackend::setState(const QString &state)
|
||||
// Sets the imageCache extraId hint. Valid content depends on image cache collector used.
|
||||
void PreviewTooltipBackend::setExtraId(const QString &extraId)
|
||||
{
|
||||
m_state = state;
|
||||
if (m_state != state)
|
||||
emit stateChanged();
|
||||
m_extraId = extraId;
|
||||
if (m_extraId != extraId)
|
||||
emit extraIdChanged();
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <imagecacheauxiliarydata.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
|
||||
@@ -33,7 +35,7 @@
|
||||
namespace QmlDesigner {
|
||||
|
||||
class PreviewImageTooltip;
|
||||
class ImageCache;
|
||||
class AsynchronousImageCache;
|
||||
|
||||
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 path READ path WRITE setPath NOTIFY pathChanged)
|
||||
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:
|
||||
PreviewTooltipBackend(ImageCache &cache);
|
||||
PreviewTooltipBackend(AsynchronousImageCache &cache);
|
||||
~PreviewTooltipBackend();
|
||||
|
||||
Q_INVOKABLE void showTooltip();
|
||||
@@ -58,24 +60,30 @@ public:
|
||||
void setPath(const QString &path);
|
||||
QString info() const;
|
||||
void setInfo(const QString &info);
|
||||
QString state() const;
|
||||
void setState(const QString &state);
|
||||
QString extraId() const;
|
||||
void setExtraId(const QString &extraId);
|
||||
|
||||
bool isVisible() const;
|
||||
|
||||
void setAuxiliaryData(ImageCache::AuxiliaryData auxiliaryData)
|
||||
{
|
||||
m_auxiliaryData = std::move(auxiliaryData);
|
||||
}
|
||||
|
||||
signals:
|
||||
void nameChanged();
|
||||
void pathChanged();
|
||||
void infoChanged();
|
||||
void stateChanged();
|
||||
void extraIdChanged();
|
||||
|
||||
private:
|
||||
QString m_name;
|
||||
QString m_path;
|
||||
QString m_info;
|
||||
QString m_state;
|
||||
QString m_extraId;
|
||||
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/annotation.cpp \
|
||||
$$PWD/model/stylesheetmerger.cpp \
|
||||
$$PWD/imagecache/imagecache.cpp \
|
||||
$$PWD/imagecache/asynchronousimagecache.cpp \
|
||||
$$PWD/imagecache/synchronousimagecache.cpp \
|
||||
$$PWD/imagecache/imagecacheconnectionmanager.cpp \
|
||||
$$PWD/imagecache/imagecachegenerator.cpp \
|
||||
$$PWD/imagecache/timestampprovider.cpp
|
||||
@@ -174,7 +175,9 @@ HEADERS += $$PWD/include/qmldesignercorelib_global.h \
|
||||
$$PWD/include/qmltimelinekeyframegroup.h \
|
||||
$$PWD/include/annotation.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/imagecacheconnectionmanager.h \
|
||||
$$PWD/imagecache/imagecachegeneratorinterface.h \
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "imagecache.h"
|
||||
#include "asynchronousimagecache.h"
|
||||
|
||||
#include "imagecachegenerator.h"
|
||||
#include "imagecachestorage.h"
|
||||
@@ -33,9 +33,9 @@
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
ImageCache::ImageCache(ImageCacheStorageInterface &storage,
|
||||
ImageCacheGeneratorInterface &generator,
|
||||
TimeStampProviderInterface &timeStampProvider)
|
||||
AsynchronousImageCache::AsynchronousImageCache(ImageCacheStorageInterface &storage,
|
||||
ImageCacheGeneratorInterface &generator,
|
||||
TimeStampProviderInterface &timeStampProvider)
|
||||
: m_storage(storage)
|
||||
, m_generator(generator)
|
||||
, m_timeStampProvider(timeStampProvider)
|
||||
@@ -44,10 +44,11 @@ ImageCache::ImageCache(ImageCacheStorageInterface &storage,
|
||||
while (isRunning()) {
|
||||
if (auto [hasEntry, entry] = getEntry(); hasEntry) {
|
||||
request(entry.name,
|
||||
entry.state,
|
||||
entry.extraId,
|
||||
entry.requestType,
|
||||
std::move(entry.captureCallback),
|
||||
std::move(entry.abortCallback),
|
||||
std::move(entry.auxiliaryData),
|
||||
m_storage,
|
||||
m_generator,
|
||||
m_timeStampProvider);
|
||||
@@ -58,26 +59,27 @@ ImageCache::ImageCache(ImageCacheStorageInterface &storage,
|
||||
}};
|
||||
}
|
||||
|
||||
ImageCache::~ImageCache()
|
||||
AsynchronousImageCache::~AsynchronousImageCache()
|
||||
{
|
||||
clean();
|
||||
wait();
|
||||
}
|
||||
|
||||
void ImageCache::request(Utils::SmallStringView name,
|
||||
Utils::SmallStringView state,
|
||||
ImageCache::RequestType requestType,
|
||||
ImageCache::CaptureCallback captureCallback,
|
||||
ImageCache::AbortCallback abortCallback,
|
||||
ImageCacheStorageInterface &storage,
|
||||
ImageCacheGeneratorInterface &generator,
|
||||
TimeStampProviderInterface &timeStampProvider)
|
||||
void AsynchronousImageCache::request(Utils::SmallStringView name,
|
||||
Utils::SmallStringView extraId,
|
||||
AsynchronousImageCache::RequestType requestType,
|
||||
AsynchronousImageCache::CaptureImageCallback captureCallback,
|
||||
AsynchronousImageCache::AbortCallback abortCallback,
|
||||
ImageCache::AuxiliaryData auxiliaryData,
|
||||
ImageCacheStorageInterface &storage,
|
||||
ImageCacheGeneratorInterface &generator,
|
||||
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 entry = requestType == RequestType::Image ? storage.fetchImage(id, timeStamp)
|
||||
: storage.fetchIcon(id, timeStamp);
|
||||
: storage.fetchSmallImage(id, timeStamp);
|
||||
|
||||
if (entry.hasEntry) {
|
||||
if (entry.image.isNull())
|
||||
@@ -85,15 +87,20 @@ void ImageCache::request(Utils::SmallStringView name,
|
||||
else
|
||||
captureCallback(entry.image);
|
||||
} else {
|
||||
auto callback = [captureCallback = std::move(captureCallback),
|
||||
requestType](const QImage &image, const QImage &smallImage) {
|
||||
captureCallback(requestType == RequestType::Image ? image : smallImage);
|
||||
};
|
||||
generator.generateImage(name,
|
||||
state,
|
||||
extraId,
|
||||
timeStamp,
|
||||
std::move(captureCallback),
|
||||
std::move(abortCallback));
|
||||
std::move(callback),
|
||||
std::move(abortCallback),
|
||||
std::move(auxiliaryData));
|
||||
}
|
||||
}
|
||||
|
||||
void ImageCache::wait()
|
||||
void AsynchronousImageCache::wait()
|
||||
{
|
||||
stopThread();
|
||||
m_condition.notify_all();
|
||||
@@ -101,46 +108,50 @@ void ImageCache::wait()
|
||||
m_backgroundThread.join();
|
||||
}
|
||||
|
||||
void ImageCache::requestImage(Utils::PathString name,
|
||||
ImageCache::CaptureCallback captureCallback,
|
||||
AbortCallback abortCallback,
|
||||
Utils::SmallString state)
|
||||
void AsynchronousImageCache::requestImage(Utils::PathString name,
|
||||
AsynchronousImageCache::CaptureImageCallback captureCallback,
|
||||
AbortCallback abortCallback,
|
||||
Utils::SmallString extraId,
|
||||
ImageCache::AuxiliaryData auxiliaryData)
|
||||
{
|
||||
addEntry(std::move(name),
|
||||
std::move(state),
|
||||
std::move(extraId),
|
||||
std::move(captureCallback),
|
||||
std::move(abortCallback),
|
||||
std::move(auxiliaryData),
|
||||
RequestType::Image);
|
||||
m_condition.notify_all();
|
||||
}
|
||||
|
||||
void ImageCache::requestIcon(Utils::PathString name,
|
||||
ImageCache::CaptureCallback captureCallback,
|
||||
ImageCache::AbortCallback abortCallback,
|
||||
Utils::SmallString state)
|
||||
void AsynchronousImageCache::requestSmallImage(Utils::PathString name,
|
||||
AsynchronousImageCache::CaptureImageCallback captureCallback,
|
||||
AsynchronousImageCache::AbortCallback abortCallback,
|
||||
Utils::SmallString extraId,
|
||||
ImageCache::AuxiliaryData auxiliaryData)
|
||||
{
|
||||
addEntry(std::move(name),
|
||||
std::move(state),
|
||||
std::move(extraId),
|
||||
std::move(captureCallback),
|
||||
std::move(abortCallback),
|
||||
RequestType::Icon);
|
||||
std::move(auxiliaryData),
|
||||
RequestType::SmallImage);
|
||||
m_condition.notify_all();
|
||||
}
|
||||
|
||||
void ImageCache::clean()
|
||||
void AsynchronousImageCache::clean()
|
||||
{
|
||||
clearEntries();
|
||||
m_generator.clean();
|
||||
}
|
||||
|
||||
void ImageCache::waitForFinished()
|
||||
void AsynchronousImageCache::waitForFinished()
|
||||
{
|
||||
wait();
|
||||
|
||||
m_generator.waitForFinished();
|
||||
}
|
||||
|
||||
std::tuple<bool, ImageCache::Entry> ImageCache::getEntry()
|
||||
std::tuple<bool, AsynchronousImageCache::Entry> AsynchronousImageCache::getEntry()
|
||||
{
|
||||
std::unique_lock lock{m_mutex};
|
||||
|
||||
@@ -153,22 +164,24 @@ std::tuple<bool, ImageCache::Entry> ImageCache::getEntry()
|
||||
return {true, entry};
|
||||
}
|
||||
|
||||
void ImageCache::addEntry(Utils::PathString &&name,
|
||||
Utils::SmallString &&state,
|
||||
ImageCache::CaptureCallback &&captureCallback,
|
||||
AbortCallback &&abortCallback,
|
||||
RequestType requestType)
|
||||
void AsynchronousImageCache::addEntry(Utils::PathString &&name,
|
||||
Utils::SmallString &&extraId,
|
||||
AsynchronousImageCache::CaptureImageCallback &&captureCallback,
|
||||
AbortCallback &&abortCallback,
|
||||
ImageCache::AuxiliaryData &&auxiliaryData,
|
||||
RequestType requestType)
|
||||
{
|
||||
std::unique_lock lock{m_mutex};
|
||||
|
||||
m_entries.emplace_back(std::move(name),
|
||||
std::move(state),
|
||||
std::move(extraId),
|
||||
std::move(captureCallback),
|
||||
std::move(abortCallback),
|
||||
std::move(auxiliaryData),
|
||||
requestType);
|
||||
}
|
||||
|
||||
void ImageCache::clearEntries()
|
||||
void AsynchronousImageCache::clearEntries()
|
||||
{
|
||||
std::unique_lock lock{m_mutex};
|
||||
for (Entry &entry : m_entries)
|
||||
@@ -176,20 +189,20 @@ void ImageCache::clearEntries()
|
||||
m_entries.clear();
|
||||
}
|
||||
|
||||
void ImageCache::waitForEntries()
|
||||
void AsynchronousImageCache::waitForEntries()
|
||||
{
|
||||
std::unique_lock lock{m_mutex};
|
||||
if (m_entries.empty())
|
||||
m_condition.wait(lock, [&] { return m_entries.size() || m_finishing; });
|
||||
}
|
||||
|
||||
void ImageCache::stopThread()
|
||||
void AsynchronousImageCache::stopThread()
|
||||
{
|
||||
std::unique_lock lock{m_mutex};
|
||||
m_finishing = true;
|
||||
}
|
||||
|
||||
bool ImageCache::isRunning()
|
||||
bool AsynchronousImageCache::isRunning()
|
||||
{
|
||||
std::unique_lock lock{m_mutex};
|
||||
return !m_finishing || m_entries.size();
|
||||
@@ -68,6 +68,7 @@ ImageCacheCollector::~ImageCacheCollector() = default;
|
||||
|
||||
void ImageCacheCollector::start(Utils::SmallStringView name,
|
||||
Utils::SmallStringView state,
|
||||
const ImageCache::AuxiliaryData &auxiliaryData,
|
||||
CaptureCallback captureCallback,
|
||||
AbortCallback abortCallback)
|
||||
{
|
||||
@@ -97,7 +98,15 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
|
||||
if (stateNode.isValid())
|
||||
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.setCrashCallback(abortCallback);
|
||||
@@ -115,6 +124,20 @@ void ImageCacheCollector::start(Utils::SmallStringView name,
|
||||
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)
|
||||
{
|
||||
m_target = target;
|
||||
|
||||
@@ -54,9 +54,18 @@ public:
|
||||
|
||||
void start(Utils::SmallStringView filePath,
|
||||
Utils::SmallStringView state,
|
||||
const ImageCache::AuxiliaryData &auxiliaryData,
|
||||
CaptureCallback captureCallback,
|
||||
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);
|
||||
|
||||
private:
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <imagecacheauxiliarydata.h>
|
||||
#include <utils/smallstringview.h>
|
||||
|
||||
#include <QImage>
|
||||
@@ -34,15 +35,26 @@ namespace QmlDesigner {
|
||||
class ImageCacheCollectorInterface
|
||||
{
|
||||
public:
|
||||
using CaptureCallback = std::function<void(QImage &&image)>;
|
||||
using CaptureCallback = std::function<void(QImage &&image, QImage &&smallImage)>;
|
||||
using AbortCallback = std::function<void()>;
|
||||
using ImagePair = std::pair<QImage, QImage>;
|
||||
|
||||
virtual void start(Utils::SmallStringView filePath,
|
||||
Utils::SmallStringView state,
|
||||
Utils::SmallStringView extraId,
|
||||
const ImageCache::AuxiliaryData &auxiliaryData,
|
||||
CaptureCallback captureCallback,
|
||||
AbortCallback abortCallback)
|
||||
= 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:
|
||||
~ImageCacheCollectorInterface() = default;
|
||||
};
|
||||
|
||||
@@ -42,6 +42,8 @@ ImageCacheFontCollector::ImageCacheFontCollector() = default;
|
||||
|
||||
ImageCacheFontCollector::~ImageCacheFontCollector() = default;
|
||||
|
||||
namespace {
|
||||
|
||||
QByteArray fileToByteArray(QString const &filename)
|
||||
{
|
||||
QFile file(filename);
|
||||
@@ -53,29 +55,17 @@ QByteArray fileToByteArray(QString const &filename)
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void ImageCacheFontCollector::start(Utils::SmallStringView name,
|
||||
Utils::SmallStringView state,
|
||||
Utils::SmallStringView,
|
||||
const ImageCache::AuxiliaryData &auxiliaryDataValue,
|
||||
CaptureCallback captureCallback,
|
||||
AbortCallback abortCallback)
|
||||
{
|
||||
// State contains size, text color, and sample text
|
||||
QStringList hints = QString(state).split('@');
|
||||
int dim(300);
|
||||
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);
|
||||
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)));
|
||||
@@ -86,8 +76,7 @@ void ImageCacheFontCollector::start(Utils::SmallStringView name,
|
||||
const QStringList families = QFontDatabase::applicationFontFamilies(fontId);
|
||||
if (!families.isEmpty()) {
|
||||
QString fontFamily = families.first();
|
||||
if (text.contains("%1"))
|
||||
text = text.arg(fontFamily);
|
||||
QString text = fontFamily + "\n\n" + auxiliaryData.text;
|
||||
QFont font(fontFamily);
|
||||
font.setStyle(rawFont.style());
|
||||
font.setStyleName(rawFont.styleName());
|
||||
@@ -120,7 +109,7 @@ void ImageCacheFontCollector::start(Utils::SmallStringView name,
|
||||
painter.setFont(font);
|
||||
painter.drawText(rect, flags, text);
|
||||
|
||||
captureCallback(std::move(image));
|
||||
captureCallback(std::move(image), {});
|
||||
return;
|
||||
}
|
||||
QFontDatabase::removeApplicationFont(fontId);
|
||||
@@ -129,4 +118,133 @@ void ImageCacheFontCollector::start(Utils::SmallStringView name,
|
||||
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
|
||||
|
||||
@@ -37,9 +37,18 @@ public:
|
||||
~ImageCacheFontCollector();
|
||||
|
||||
void start(Utils::SmallStringView filePath,
|
||||
Utils::SmallStringView state,
|
||||
Utils::SmallStringView extraId,
|
||||
const ImageCache::AuxiliaryData &auxiliaryData,
|
||||
CaptureCallback captureCallback,
|
||||
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
|
||||
|
||||
@@ -47,17 +47,18 @@ ImageCacheGenerator::~ImageCacheGenerator()
|
||||
waitForFinished();
|
||||
}
|
||||
|
||||
void ImageCacheGenerator::generateImage(
|
||||
Utils::SmallStringView name,
|
||||
Utils::SmallStringView state,
|
||||
Sqlite::TimeStamp timeStamp,
|
||||
ImageCacheGeneratorInterface::CaptureCallback &&captureCallback,
|
||||
AbortCallback &&abortCallback)
|
||||
void ImageCacheGenerator::generateImage(Utils::SmallStringView name,
|
||||
Utils::SmallStringView extraId,
|
||||
Sqlite::TimeStamp timeStamp,
|
||||
ImageCacheGeneratorInterface::CaptureCallback &&captureCallback,
|
||||
AbortCallback &&abortCallback,
|
||||
ImageCache::AuxiliaryData &&auxiliaryData)
|
||||
{
|
||||
{
|
||||
std::lock_guard lock{m_mutex};
|
||||
m_tasks.emplace_back(name,
|
||||
state,
|
||||
extraId,
|
||||
std::move(auxiliaryData),
|
||||
timeStamp,
|
||||
std::move(captureCallback),
|
||||
std::move(abortCallback));
|
||||
@@ -82,6 +83,12 @@ void ImageCacheGenerator::waitForFinished()
|
||||
if (m_backgroundThread)
|
||||
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()
|
||||
{
|
||||
@@ -105,18 +112,22 @@ void ImageCacheGenerator::startGeneration()
|
||||
|
||||
m_collector.start(
|
||||
task.filePath,
|
||||
task.state,
|
||||
[this, task](QImage &&image) {
|
||||
task.extraId,
|
||||
std::move(task.auxiliaryData),
|
||||
[this, task](QImage &&image, QImage &&smallImage) {
|
||||
if (image.isNull())
|
||||
task.abortCallback();
|
||||
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] {
|
||||
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};
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "imagecachegeneratorinterface.h"
|
||||
|
||||
#include <imagecacheauxiliarydata.h>
|
||||
#include <utils/smallstring.h>
|
||||
|
||||
#include <QThread>
|
||||
@@ -51,10 +52,11 @@ public:
|
||||
~ImageCacheGenerator();
|
||||
|
||||
void generateImage(Utils::SmallStringView filePath,
|
||||
Utils::SmallStringView state,
|
||||
Utils::SmallStringView extraId,
|
||||
Sqlite::TimeStamp timeStamp,
|
||||
CaptureCallback &&captureCallback,
|
||||
AbortCallback &&abortCallback) override;
|
||||
AbortCallback &&abortCallback,
|
||||
ImageCache::AuxiliaryData &&auxiliaryData) override;
|
||||
void clean() override;
|
||||
|
||||
void waitForFinished() override;
|
||||
@@ -64,19 +66,22 @@ private:
|
||||
{
|
||||
Task() = default;
|
||||
Task(Utils::SmallStringView filePath,
|
||||
Utils::SmallStringView state,
|
||||
Utils::SmallStringView extraId,
|
||||
ImageCache::AuxiliaryData &&auxiliaryData,
|
||||
Sqlite::TimeStamp timeStamp,
|
||||
CaptureCallback &&captureCallback,
|
||||
AbortCallback &&abortCallback)
|
||||
: filePath(filePath)
|
||||
, state(std::move(state))
|
||||
, extraId(std::move(extraId))
|
||||
, auxiliaryData(std::move(auxiliaryData))
|
||||
, captureCallback(std::move(captureCallback))
|
||||
, abortCallback(std::move(abortCallback))
|
||||
, timeStamp(timeStamp)
|
||||
{}
|
||||
|
||||
Utils::PathString filePath;
|
||||
Utils::SmallString state;
|
||||
Utils::SmallString extraId;
|
||||
ImageCache::AuxiliaryData auxiliaryData;
|
||||
CaptureCallback captureCallback;
|
||||
AbortCallback abortCallback;
|
||||
Sqlite::TimeStamp timeStamp;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <imagecacheauxiliarydata.h>
|
||||
#include <sqlitetimestamp.h>
|
||||
#include <utils/smallstringview.h>
|
||||
|
||||
@@ -35,14 +36,15 @@ namespace QmlDesigner {
|
||||
class ImageCacheGeneratorInterface
|
||||
{
|
||||
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()>;
|
||||
|
||||
virtual void generateImage(Utils::SmallStringView name,
|
||||
Utils::SmallStringView state,
|
||||
Utils::SmallStringView extraId,
|
||||
Sqlite::TimeStamp timeStamp,
|
||||
CaptureCallback &&captureCallback,
|
||||
AbortCallback &&abortCallback)
|
||||
AbortCallback &&abortCallback,
|
||||
ImageCache::AuxiliaryData &&auxiliaryData)
|
||||
= 0;
|
||||
|
||||
virtual void clean() = 0;
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
#include <sqlitewritestatement.h>
|
||||
|
||||
#include <QBuffer>
|
||||
#include <QImageReader>
|
||||
#include <QImageWriter>
|
||||
#include <QIcon>
|
||||
#include <QImage>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
Entry fetchImage(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
|
||||
ImageEntry fetchImage(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
|
||||
{
|
||||
try {
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
@@ -62,21 +62,37 @@ public:
|
||||
|
||||
transaction.commit();
|
||||
|
||||
if (optionalBlob) {
|
||||
QBuffer buffer{&optionalBlob->byteArray};
|
||||
QImageReader reader{&buffer, "PNG"};
|
||||
|
||||
return Entry{reader.read(), true};
|
||||
}
|
||||
if (optionalBlob)
|
||||
return {readImage(optionalBlob->byteArray), true};
|
||||
|
||||
return {};
|
||||
|
||||
} catch (const Sqlite::StatementIsBusy &) {
|
||||
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 {
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
@@ -86,12 +102,8 @@ public:
|
||||
|
||||
transaction.commit();
|
||||
|
||||
if (optionalBlob) {
|
||||
QBuffer buffer{&optionalBlob->byteArray};
|
||||
QImageReader reader{&buffer, "PNG"};
|
||||
|
||||
return Entry{reader.read(), true};
|
||||
}
|
||||
if (optionalBlob)
|
||||
return {readIcon(optionalBlob->byteArray), true};
|
||||
|
||||
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 {
|
||||
Sqlite::ImmediateTransaction transaction{database};
|
||||
|
||||
if (image.isNull()) {
|
||||
upsertImageStatement.write(name,
|
||||
newTimeStamp.value,
|
||||
Sqlite::NullValue{},
|
||||
Sqlite::NullValue{});
|
||||
} 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()});
|
||||
}
|
||||
auto imageBuffer = createBuffer(image);
|
||||
auto smallImageBuffer = createBuffer(smallImage);
|
||||
upsertImageStatement.write(name,
|
||||
newTimeStamp.value,
|
||||
createBlobView(imageBuffer.get()),
|
||||
createBlobView(smallImageBuffer.get()));
|
||||
|
||||
transaction.commit();
|
||||
|
||||
} 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)
|
||||
{
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
table.setName("images");
|
||||
table.addColumn("id", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||
table.addColumn("name", Sqlite::ColumnType::Text, {Sqlite::NotNull{}, Sqlite::Unique{}});
|
||||
table.addColumn("mtime", Sqlite::ColumnType::Integer);
|
||||
table.addColumn("image", Sqlite::ColumnType::Blob);
|
||||
table.addColumn("icon", Sqlite::ColumnType::Blob);
|
||||
Sqlite::Table imageTable;
|
||||
imageTable.setUseIfNotExists(true);
|
||||
imageTable.setName("images");
|
||||
imageTable.addColumn("id", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||
imageTable.addColumn("name",
|
||||
Sqlite::ColumnType::Text,
|
||||
{Sqlite::NotNull{}, Sqlite::Unique{}});
|
||||
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>();
|
||||
buffer->open(QIODevice::WriteOnly);
|
||||
QImageWriter writer{buffer.get(), "PNG"};
|
||||
writer.write(image);
|
||||
QDataStream out{buffer.get()};
|
||||
|
||||
out << image;
|
||||
|
||||
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:
|
||||
DatabaseType &database;
|
||||
Initializer initializer{database};
|
||||
Sqlite::ImmediateNonThrowingDestructorTransaction transaction{database};
|
||||
mutable ReadStatement selectImageStatement{
|
||||
"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{
|
||||
"SELECT icon FROM images WHERE name=?1 AND mtime >= ?2", database};
|
||||
"SELECT icon FROM icons WHERE name=?1 AND mtime >= ?2", database};
|
||||
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, "
|
||||
"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};
|
||||
};
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QIcon>
|
||||
#include <QImage>
|
||||
|
||||
#include <sqlitetimestamp.h>
|
||||
@@ -32,23 +33,40 @@
|
||||
|
||||
namespace QmlDesigner {
|
||||
namespace Internal {
|
||||
class ImageCacheStorageEntry
|
||||
class ImageCacheStorageImageEntry
|
||||
{
|
||||
public:
|
||||
public:
|
||||
QImage image;
|
||||
bool hasEntry = false;
|
||||
};
|
||||
|
||||
class ImageCacheStorageIconEntry
|
||||
{
|
||||
public:
|
||||
QIcon icon;
|
||||
bool hasEntry = false;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
class ImageCacheStorageInterface
|
||||
{
|
||||
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 Entry fetchIcon(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const = 0;
|
||||
virtual void storeImage(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QImage &image) = 0;
|
||||
virtual ImageEntry fetchImage(Utils::SmallStringView name,
|
||||
Sqlite::TimeStamp minimumTimeStamp) const = 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;
|
||||
|
||||
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
|
||||
|
||||
#include "imagecacheinterface.h"
|
||||
#include "asynchronousimagecacheinterface.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
@@ -37,70 +37,78 @@ namespace QmlDesigner {
|
||||
class TimeStampProviderInterface;
|
||||
class ImageCacheStorageInterface;
|
||||
class ImageCacheGeneratorInterface;
|
||||
class ImageCacheCollectorInterface;
|
||||
|
||||
class ImageCache final : public ImageCacheInterface
|
||||
class AsynchronousImageCache final : public AsynchronousImageCacheInterface
|
||||
{
|
||||
public:
|
||||
using CaptureCallback = std::function<void(const QImage &)>;
|
||||
using CaptureImageCallback = std::function<void(const QImage &)>;
|
||||
using AbortCallback = std::function<void()>;
|
||||
|
||||
~ImageCache();
|
||||
~AsynchronousImageCache();
|
||||
|
||||
ImageCache(ImageCacheStorageInterface &storage,
|
||||
ImageCacheGeneratorInterface &generator,
|
||||
TimeStampProviderInterface &timeStampProvider);
|
||||
AsynchronousImageCache(ImageCacheStorageInterface &storage,
|
||||
ImageCacheGeneratorInterface &generator,
|
||||
TimeStampProviderInterface &timeStampProvider);
|
||||
|
||||
void requestImage(Utils::PathString name,
|
||||
CaptureCallback captureCallback,
|
||||
CaptureImageCallback captureCallback,
|
||||
AbortCallback abortCallback,
|
||||
Utils::SmallString state = {}) override;
|
||||
void requestIcon(Utils::PathString name,
|
||||
CaptureCallback captureCallback,
|
||||
AbortCallback abortCallback,
|
||||
Utils::SmallString state = {}) override;
|
||||
Utils::SmallString extraId = {},
|
||||
ImageCache::AuxiliaryData auxiliaryData = {}) override;
|
||||
void requestSmallImage(Utils::PathString name,
|
||||
CaptureImageCallback captureCallback,
|
||||
AbortCallback abortCallback,
|
||||
Utils::SmallString extraId = {},
|
||||
ImageCache::AuxiliaryData auxiliaryData = {}) override;
|
||||
|
||||
void clean();
|
||||
void waitForFinished();
|
||||
|
||||
private:
|
||||
enum class RequestType { Image, Icon };
|
||||
enum class RequestType { Image, SmallImage, Icon };
|
||||
struct Entry
|
||||
{
|
||||
Entry() = default;
|
||||
Entry(Utils::PathString name,
|
||||
Utils::SmallString state,
|
||||
CaptureCallback &&captureCallback,
|
||||
Utils::SmallString extraId,
|
||||
CaptureImageCallback &&captureCallback,
|
||||
AbortCallback &&abortCallback,
|
||||
ImageCache::AuxiliaryData &&auxiliaryData,
|
||||
RequestType requestType)
|
||||
: name{std::move(name)}
|
||||
, state{std::move(state)}
|
||||
, extraId{std::move(extraId)}
|
||||
, captureCallback{std::move(captureCallback)}
|
||||
, abortCallback{std::move(abortCallback)}
|
||||
, auxiliaryData{std::move(auxiliaryData)}
|
||||
, requestType{requestType}
|
||||
{}
|
||||
|
||||
Utils::PathString name;
|
||||
Utils::SmallString state;
|
||||
CaptureCallback captureCallback;
|
||||
Utils::SmallString extraId;
|
||||
CaptureImageCallback captureCallback;
|
||||
AbortCallback abortCallback;
|
||||
ImageCache::AuxiliaryData auxiliaryData;
|
||||
RequestType requestType = RequestType::Image;
|
||||
};
|
||||
|
||||
std::tuple<bool, Entry> getEntry();
|
||||
void addEntry(Utils::PathString &&name,
|
||||
Utils::SmallString &&state,
|
||||
CaptureCallback &&captureCallback,
|
||||
Utils::SmallString &&extraId,
|
||||
CaptureImageCallback &&captureCallback,
|
||||
AbortCallback &&abortCallback,
|
||||
ImageCache::AuxiliaryData &&auxiliaryData,
|
||||
RequestType requestType);
|
||||
void clearEntries();
|
||||
void waitForEntries();
|
||||
void stopThread();
|
||||
bool isRunning();
|
||||
static void request(Utils::SmallStringView name,
|
||||
Utils::SmallStringView state,
|
||||
ImageCache::RequestType requestType,
|
||||
ImageCache::CaptureCallback captureCallback,
|
||||
ImageCache::AbortCallback abortCallback,
|
||||
Utils::SmallStringView extraId,
|
||||
AsynchronousImageCache::RequestType requestType,
|
||||
AsynchronousImageCache::CaptureImageCallback captureCallback,
|
||||
AsynchronousImageCache::AbortCallback abortCallback,
|
||||
ImageCache::AuxiliaryData auxiliaryData,
|
||||
ImageCacheStorageInterface &storage,
|
||||
ImageCacheGeneratorInterface &generator,
|
||||
TimeStampProviderInterface &timeStampProvider);
|
||||
@@ -25,13 +25,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "imagecacheauxiliarydata.h"
|
||||
|
||||
#include <utils/smallstring.h>
|
||||
|
||||
#include <QImage>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class ImageCacheInterface
|
||||
class AsynchronousImageCacheInterface
|
||||
{
|
||||
public:
|
||||
using CaptureCallback = std::function<void(const QImage &)>;
|
||||
@@ -40,18 +42,20 @@ public:
|
||||
virtual void requestImage(Utils::PathString name,
|
||||
CaptureCallback captureCallback,
|
||||
AbortCallback abortCallback,
|
||||
Utils::SmallString state = {})
|
||||
Utils::SmallString extraId = {},
|
||||
ImageCache::AuxiliaryData auxiliaryData = {})
|
||||
= 0;
|
||||
virtual void requestIcon(Utils::PathString name,
|
||||
CaptureCallback captureCallback,
|
||||
AbortCallback abortCallback,
|
||||
Utils::SmallString state = {})
|
||||
virtual void requestSmallImage(Utils::PathString name,
|
||||
CaptureCallback captureCallback,
|
||||
AbortCallback abortCallback,
|
||||
Utils::SmallString extraId = {},
|
||||
ImageCache::AuxiliaryData auxiliaryData = {})
|
||||
= 0;
|
||||
|
||||
void clean();
|
||||
|
||||
protected:
|
||||
~ImageCacheInterface() = default;
|
||||
~AsynchronousImageCacheInterface() = default;
|
||||
};
|
||||
|
||||
} // 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; }
|
||||
|
||||
class ViewManagerData;
|
||||
class ImageCache;
|
||||
class AsynchronousImageCache;
|
||||
|
||||
class QMLDESIGNERCORE_EXPORT ViewManager
|
||||
{
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
void disableStandardViews();
|
||||
void enableStandardViews();
|
||||
|
||||
ImageCache &imageCache();
|
||||
AsynchronousImageCache &imageCache();
|
||||
|
||||
private: // functions
|
||||
Q_DISABLE_COPY(ViewManager)
|
||||
|
||||
@@ -453,7 +453,7 @@ void ViewManager::enableStandardViews()
|
||||
attachViewsExceptRewriterAndComponetView();
|
||||
}
|
||||
|
||||
ImageCache &ViewManager::imageCache()
|
||||
AsynchronousImageCache &ViewManager::imageCache()
|
||||
{
|
||||
return d->itemLibraryView.imageCache();
|
||||
}
|
||||
|
||||
@@ -567,7 +567,7 @@ void QmlDesignerPlugin::emitUsageStatisticsContextAction(const QString &identifi
|
||||
emitUsageStatistics(Constants::EVENT_ACTION_EXECUTED + identifier);
|
||||
}
|
||||
|
||||
ImageCache &QmlDesignerPlugin::imageCache()
|
||||
AsynchronousImageCache &QmlDesignerPlugin::imageCache()
|
||||
{
|
||||
return m_instance->d->viewManager.imageCache();
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Core {
|
||||
namespace QmlDesigner {
|
||||
|
||||
class QmlDesignerPluginPrivate;
|
||||
class ImageCache;
|
||||
class AsynchronousImageCache;
|
||||
|
||||
namespace Internal { class DesignModeWidget; }
|
||||
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
static void emitUsageStatisticsContextAction(const QString &identifier);
|
||||
static void emitUsageStatisticsTime(const QString &identifier, int elapsed);
|
||||
|
||||
static ImageCache &imageCache();
|
||||
static AsynchronousImageCache &imageCache();
|
||||
|
||||
signals:
|
||||
void usageStatisticsNotifier(const QString &identifier);
|
||||
|
||||
@@ -414,13 +414,15 @@ Project {
|
||||
"pluginmanager/widgetpluginmanager.h",
|
||||
"pluginmanager/widgetpluginpath.cpp",
|
||||
"pluginmanager/widgetpluginpath.h",
|
||||
"include/imagecache.h",
|
||||
"include/imagecacheinterface.h",
|
||||
"include/asynchronousimagecache.h",
|
||||
"include/synchronousimagecache.h",
|
||||
"include/imagecacheauxiliarydata.h",
|
||||
"include/asynchronousimagecacheinterface.h",
|
||||
"imagecache/imagecachecollector.cpp",
|
||||
"imagecache/imagecachecollector.h",
|
||||
"imagecache/imagecachefontcollector.cpp",
|
||||
"imagecache/imagecachefontcollector.h",
|
||||
"imagecache/imagecache.cpp",
|
||||
"imagecache/asynchronousimagecache.cpp",
|
||||
"imagecache/imagecachecollectorinterface.h",
|
||||
"imagecache/imagecacheconnectionmanager.cpp",
|
||||
"imagecache/imagecacheconnectionmanager.h",
|
||||
|
||||
@@ -32,7 +32,8 @@ SOURCES += \
|
||||
$$PWD/designercore/model/annotation.cpp \
|
||||
$$PWD/designercore/rewritertransaction.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
|
||||
|
||||
HEADERS += \
|
||||
@@ -42,8 +43,10 @@ HEADERS += \
|
||||
$$PWD/designercore/imagecache/imagecachestorageinterface.h \
|
||||
$$PWD/designercore/imagecache/imagecachegeneratorinterface.h \
|
||||
$$PWD/designercore/imagecache/timestampproviderinterface.h \
|
||||
$$PWD/designercore/include/imagecache.h \
|
||||
$$PWD/designercore/include/imagecacheinterface.h \
|
||||
$$PWD/designercore/include/asynchronousimagecache.h \
|
||||
$$PWD/designercore/include/synchronousimagecache.h \
|
||||
$$PWD/designercore/include/imagecacheauxiliarydata.h \
|
||||
$$PWD/designercore/include/asynchronousimagecacheinterface.h \
|
||||
$$PWD/designercore/include/modelnode.h \
|
||||
$$PWD/designercore/include/model.h \
|
||||
$$PWD/../../../share/qtcreator/qml/qmlpuppet/interfaces/commondefines.h \
|
||||
|
||||
Reference in New Issue
Block a user