From ff9c170053588999670df83457df5b912ea1d996 Mon Sep 17 00:00:00 2001 From: Samuel Ghinet Date: Thu, 15 Dec 2022 23:20:43 +0200 Subject: [PATCH] QmlDesigner: Show metadata of assets when being hovered on This change does not affect font files. For all other assets, the file type is now also shown in tooltips For image assets, the image size is also displayed. Task-number: QDS-8177 Change-Id: Iceb93a0ffe1cb284a87cc93f1da2060f6f4f1529 Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../itemLibraryQmlSources/AssetDelegate.qml | 34 +++++++- .../assetslibraryiconprovider.cpp | 81 ++++++++++++++----- .../assetslibrary/assetslibraryiconprovider.h | 18 ++++- .../assetslibrary/assetslibrarymodel.cpp | 5 ++ .../assetslibrary/assetslibrarymodel.h | 1 + .../assetslibrary/assetslibrarywidget.cpp | 16 ++++ .../assetslibrary/assetslibrarywidget.h | 4 + .../propertyeditorimageprovider.cpp | 2 +- src/plugins/qmldesigner/utils/asset.cpp | 5 ++ src/plugins/qmldesigner/utils/asset.h | 3 +- 10 files changed, 143 insertions(+), 26 deletions(-) diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetDelegate.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetDelegate.qml index 2bbfff5223c..3e8f346fdeb 100644 --- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetDelegate.qml +++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetDelegate.qml @@ -182,9 +182,36 @@ TreeViewDelegate { } ToolTip { + id: assetTooltip visible: !root.isFont && mouseArea.containsMouse && !root.assetsView.contextMenu.visible - text: model.filePath + text: assetTooltip.__computeText() delay: 1000 + + function __computeText() + { + let filePath = model.filePath.replace(assetsModel.contentDirPath(), "") + let fileSize = rootView.assetFileSize(model.filePath) + let fileExtMatches = model.filePath.match(/\.(.*)$/) + let fileExt = fileExtMatches ? "(" + fileExtMatches[1] + ")" : "" + + if (rootView.assetIsImage(model.filePath)) { + let size = rootView.imageSize(model.filePath) + + return filePath + "\n" + + size.width + " x " + size.height + + "\n" + fileSize + + " " + fileExt + } else { + return filePath + "\n" + + fileSize + + " " + fileExt + } + } + + function refresh() + { + text = assetTooltip.__computeText() + } } Timer { @@ -293,5 +320,10 @@ TreeViewDelegate { : "image://qmldesigner_assets/" + model.filePath } + onStatusChanged: { + if (thumbnailImage.status === Image.Ready) + assetTooltip.refresh() + } + } // Image } // TreeViewDelegate diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp index 14a433e8602..0dc73120f1f 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.cpp @@ -22,20 +22,13 @@ QPixmap AssetsLibraryIconProvider::requestPixmap(const QString &id, QSize *size, QPixmap pixmap; if (m_thumbnails.contains(id)) { - pixmap = m_thumbnails[id]; + pixmap = m_thumbnails[id].pixmap; } else { - pixmap = fetchPixmap(id, requestedSize); - bool haveValidImage = true; - if (pixmap.isNull()) { - pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/assets_default.png"); - haveValidImage = false; - } + Thumbnail thumbnail = createThumbnail(id, requestedSize); + pixmap = thumbnail.pixmap; - if (requestedSize.isValid()) - pixmap = pixmap.scaled(requestedSize, Qt::KeepAspectRatio); - - if (haveValidImage) - m_thumbnails[id] = pixmap; + if (thumbnail.assetType != Asset::MissingImage) + m_thumbnails[id] = thumbnail; } if (size) { @@ -46,6 +39,25 @@ QPixmap AssetsLibraryIconProvider::requestPixmap(const QString &id, QSize *size, return pixmap; } +Thumbnail AssetsLibraryIconProvider::createThumbnail(const QString &id, const QSize &requestedSize) +{ + auto [pixmap, fileSize] = fetchPixmap(id, requestedSize); + QSize originalSize = pixmap.size(); + Asset::Type assetType = Asset(id).type(); + + if (pixmap.isNull()) { + pixmap = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/assets_default.png"); + + if (assetType == Asset::Image) + assetType = Asset::MissingImage; + } + + if (requestedSize.isValid()) + pixmap = pixmap.scaled(requestedSize, Qt::KeepAspectRatio); + + return Thumbnail{pixmap, originalSize, assetType, fileSize}; +} + QPixmap AssetsLibraryIconProvider::generateFontIcons(const QString &filePath, const QSize &requestedSize) const { QSize reqSize = requestedSize.isValid() ? requestedSize : QSize{48, 48}; @@ -55,18 +67,25 @@ QPixmap AssetsLibraryIconProvider::generateFontIcons(const QString &filePath, co "Abc"}).pixmap(reqSize); } -QPixmap AssetsLibraryIconProvider::fetchPixmap(const QString &id, const QSize &requestedSize) const +QPair AssetsLibraryIconProvider::fetchPixmap(const QString &id, const QSize &requestedSize) const { Asset asset(id); if (id == "browse") { - return Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/browse.png"); + QString filePath = Utils::StyleHelper::dpiSpecificImageFile(":/AssetsLibrary/images/browse.png"); + return {QPixmap{filePath}, 0}; } else if (asset.isFont()) { - return generateFontIcons(id, requestedSize); + qint64 size = QFileInfo(id).size(); + QPixmap pixmap = generateFontIcons(id, requestedSize); + return {pixmap, size}; } else if (asset.isImage()) { - return Utils::StyleHelper::dpiSpecificImageFile(id); - } else if (asset.isTexture3D()) { - return HdrImage{id}.toPixmap(); + QString filePath = Utils::StyleHelper::dpiSpecificImageFile(id); + qint64 size = QFileInfo(filePath).size(); + return {QPixmap{filePath}, size}; + } else if (asset.isHdrFile()) { + qint64 size = QFileInfo(id).size(); + QPixmap pixmap = HdrImage{id}.toPixmap(); + return {pixmap, size}; } else { QString type; if (asset.isShader()) @@ -81,9 +100,11 @@ QPixmap AssetsLibraryIconProvider::fetchPixmap(const QString &id, const QSize &r QString pathTemplate = QString(":/AssetsLibrary/images/asset_%1%2.png").arg(type); QString path = pathTemplate.arg('_' + QString::number(requestedSize.width())); - return Utils::StyleHelper::dpiSpecificImageFile(QFileInfo::exists(path) - ? path - : pathTemplate.arg("")); + QString filePath = Utils::StyleHelper::dpiSpecificImageFile(QFileInfo::exists(path) + ? path + : pathTemplate.arg("")); + qint64 size = QFileInfo(filePath).size(); + return {QPixmap{filePath}, size}; } } @@ -97,5 +118,23 @@ void AssetsLibraryIconProvider::invalidateThumbnail(const QString &id) m_thumbnails.remove(id); } +QSize AssetsLibraryIconProvider::imageSize(const QString &id) +{ + static QSize invalidSize = {}; + return m_thumbnails.contains(id) ? m_thumbnails[id].originalSize : invalidSize; +} + +qint64 AssetsLibraryIconProvider::fileSize(const QString &id) +{ + return m_thumbnails.contains(id) ? m_thumbnails[id].fileSize : 0; +} + +bool AssetsLibraryIconProvider::assetIsImage(const QString &id) +{ + return m_thumbnails.contains(id) + ? (m_thumbnails[id].assetType == Asset::Type::Image || Asset(id).isHdrFile()) + : false; +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h index b18d8e70111..b089af4c89a 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryiconprovider.h @@ -7,8 +7,18 @@ #include +#include "asset.h" + namespace QmlDesigner { +struct Thumbnail +{ + QPixmap pixmap; + QSize originalSize; + Asset::Type assetType; + qint64 fileSize; +}; + class AssetsLibraryIconProvider : public QQuickImageProvider { public: @@ -17,10 +27,14 @@ public: QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override; void clearCache(); void invalidateThumbnail(const QString &id); + QSize imageSize(const QString &id); + qint64 fileSize(const QString &id); + bool assetIsImage(const QString &id); private: QPixmap generateFontIcons(const QString &filePath, const QSize &requestedSize) const; - QPixmap fetchPixmap(const QString &id, const QSize &requestedSize) const; + QPair fetchPixmap(const QString &id, const QSize &requestedSize) const; + Thumbnail createThumbnail(const QString &id, const QSize &requestedSize); SynchronousImageCache &m_fontImageCache; @@ -29,7 +43,7 @@ private: std::vector iconSizes = {{128, 128}, // Drag {96, 96}, // list @2x {48, 48}}; // list - QHash m_thumbnails; + QHash m_thumbnails; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp index 0953eff9eb1..940a0b85fe1 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp @@ -91,6 +91,11 @@ QString AssetsLibraryModel::currentProjectDirPath() const return DocumentManager::currentProjectDirPath().toString().append('/'); } +QString AssetsLibraryModel::contentDirPath() const +{ + return DocumentManager::currentResourcePath().toString().append('/'); +} + bool AssetsLibraryModel::requestDeleteFiles(const QStringList &filePaths) { bool askBeforeDelete = QmlDesignerPlugin::settings() diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h index 0538bedf42b..71d5c6fa457 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h @@ -40,6 +40,7 @@ public: Q_INVOKABLE QList parentIndices(const QModelIndex &index) const; Q_INVOKABLE bool indexIsValid(const QModelIndex &index) const; Q_INVOKABLE QString currentProjectDirPath() const; + Q_INVOKABLE QString contentDirPath() const; Q_INVOKABLE bool requestDeleteFiles(const QStringList &filePaths); Q_INVOKABLE void deleteFiles(const QStringList &filePaths, bool dontAskAgain); Q_INVOKABLE bool renameFolder(const QString &folderPath, const QString &newName); diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index cc9263eda46..032317eb4db 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -165,6 +165,22 @@ void AssetsLibraryWidget::invalidateThumbnail(const QString &id) m_assetsIconProvider->invalidateThumbnail(id); } +QSize AssetsLibraryWidget::imageSize(const QString &id) +{ + return m_assetsIconProvider->imageSize(id); +} + +QString AssetsLibraryWidget::assetFileSize(const QString &id) +{ + qint64 fileSize = m_assetsIconProvider->fileSize(id); + return QLocale::system().formattedDataSize(fileSize, 2, QLocale::DataSizeTraditionalFormat); +} + +bool AssetsLibraryWidget::assetIsImage(const QString &id) +{ + return m_assetsIconProvider->assetIsImage(id); +} + QList AssetsLibraryWidget::createToolBarWidgets() { return {}; diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h index 90a7038b5db..2ef59ac9584 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h @@ -74,6 +74,10 @@ public: Q_INVOKABLE void openEffectMaker(const QString &filePath); Q_INVOKABLE bool qtVersionIsAtLeast6_4() const; Q_INVOKABLE void invalidateThumbnail(const QString &id); + Q_INVOKABLE QSize imageSize(const QString &id); + Q_INVOKABLE QString assetFileSize(const QString &id); + Q_INVOKABLE bool assetIsImage(const QString &id); + Q_INVOKABLE void addTextures(const QStringList &filePaths); Q_INVOKABLE void addLightProbe(const QString &filePaths); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp index fc5a09818ca..fb17f6dee82 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorimageprovider.cpp @@ -36,7 +36,7 @@ QQuickImageResponse *PropertyEditorImageProvider::requestImageResponse(const QSt response->setImage(image.scaled(requestedSize, Qt::KeepAspectRatio)); return; } - } else if (asset.isTexture3D()) { + } else if (asset.isHdrFile()) { HdrImage hdr{asset.id()}; if (!hdr.image().isNull()) { response->setImage(hdr.image().scaled(requestedSize, Qt::KeepAspectRatio)); diff --git a/src/plugins/qmldesigner/utils/asset.cpp b/src/plugins/qmldesigner/utils/asset.cpp index 6a0a4658429..0dc66eeb3c6 100644 --- a/src/plugins/qmldesigner/utils/asset.cpp +++ b/src/plugins/qmldesigner/utils/asset.cpp @@ -154,6 +154,11 @@ bool Asset::isTexture3D() const return type() == Asset::Type::Texture3D; } +bool Asset::isHdrFile() const +{ + return m_suffix == "*.hdr"; +} + bool Asset::isEffect() const { return type() == Asset::Type::Effect; diff --git a/src/plugins/qmldesigner/utils/asset.h b/src/plugins/qmldesigner/utils/asset.h index 279edb93e1b..e673f102387 100644 --- a/src/plugins/qmldesigner/utils/asset.h +++ b/src/plugins/qmldesigner/utils/asset.h @@ -8,7 +8,7 @@ namespace QmlDesigner { class Asset { public: - enum Type { Unknown, Image, FragmentShader, Font, Audio, Video, Texture3D, Effect, Shader }; + enum Type { Unknown, Image, MissingImage, FragmentShader, Font, Audio, Video, Texture3D, Effect, Shader }; Asset(const QString &filePath); @@ -34,6 +34,7 @@ public: bool isAudio() const; bool isVideo() const; bool isTexture3D() const; + bool isHdrFile() const; bool isEffect() const; bool isSupported() const;