From 9a55bb0fd00a5d3bb1e6054db0eb0bdf3846dc89 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 3 Mar 2023 14:02:55 +0200 Subject: [PATCH] QmlDesigner: Take content library texture metadata file in use Metadata file texture_bundle.json will be included with bundle icons, and it contains details about the texture (format, dimensions, and size) that are useful to know before downloading the texture. Metadata is used to generate proper tooltip for non-downloaded textures in content library. Also removed default suffix from displayed filename in case metadata is missing, as it was misleading. Fixes: QDS-9230 Change-Id: Icbe0bbb7f1e663e0adc41d379231b7f41dc79e31 Reviewed-by: Mahmoud Badri Reviewed-by: --- .../ContentLibraryTexture.qml | 2 +- .../contentlibrary/contentlibrarytexture.cpp | 63 +++++++++++-------- .../contentlibrary/contentlibrarytexture.h | 11 +++- .../contentlibrarytexturescategory.cpp | 6 +- .../contentlibrarytexturescategory.h | 4 +- .../contentlibrarytexturesmodel.cpp | 29 +++++++-- .../contentlibrarytexturesmodel.h | 4 +- .../contentlibrary/contentlibrarywidget.cpp | 24 ++++--- src/plugins/qmldesigner/utils/imageutils.cpp | 22 ++++--- src/plugins/qmldesigner/utils/imageutils.h | 4 +- 10 files changed, 111 insertions(+), 58 deletions(-) diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml index 148ecd90ac6..6b2e3fe264e 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml @@ -238,7 +238,7 @@ Item { onFinishedChanged: { mouseArea.enabled = true modelData.setDownloaded() - root.downloadState = "downloaded" + root.downloadState = modelData.isDownloaded() ? "downloaded" : "failed" root.downloadStateChanged() rootView.markNoTextureDownloading() diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp index 1f9cbe2ceda..16e646405b1 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.cpp @@ -12,16 +12,20 @@ namespace QmlDesigner { ContentLibraryTexture::ContentLibraryTexture(QObject *parent, const QFileInfo &iconFileInfo, - const QString &downloadPath, const QUrl &icon, const QString &webUrl) + const QString &downloadPath, const QUrl &icon, + const QString &webUrl, const QString &fileExt, + const QSize &dimensions, const qint64 sizeInBytes) : QObject(parent) , m_iconPath(iconFileInfo.filePath()) , m_downloadPath(downloadPath) , m_webUrl(webUrl) , m_baseName{iconFileInfo.baseName()} + , m_fileExt(fileExt) , m_icon(icon) + , m_dimensions(dimensions) + , m_sizeInBytes(sizeInBytes) { - m_fileExt = resolveFileExt(); - m_toolTip = resolveToolTipText(); + doSetDownloaded(); } bool ContentLibraryTexture::filter(const QString &searchText) @@ -61,49 +65,56 @@ QString ContentLibraryTexture::resolveFileExt() }); } - return QString{"."} + textureFiles.at(0).completeSuffix(); + return '.' + textureFiles.at(0).completeSuffix(); } QString ContentLibraryTexture::resolveToolTipText() { - QString fileName; - QString imageInfo; - if (m_fileExt.isEmpty()) { - imageInfo = ImageUtils::imageInfo(m_iconPath, false); - fileName = m_baseName + m_defaultExt; - } else { - fileName = m_baseName + m_fileExt; - QString fullDownloadPath = m_downloadPath + "/" + fileName; - imageInfo = ImageUtils::imageInfo(fullDownloadPath, true); + // No supplied or resolved extension means we have just the icon and no other data + return m_baseName; } - return QLatin1String("%1\n%2").arg(fileName, imageInfo); + QString fileName = m_baseName + m_fileExt; + QString imageInfo; + + if (!m_isDownloaded && m_sizeInBytes > 0 && !m_dimensions.isNull()) { + imageInfo = ImageUtils::imageInfo(m_dimensions, m_sizeInBytes); + } else { + QString fullDownloadPath = m_downloadPath + '/' + fileName; + imageInfo = ImageUtils::imageInfo(fullDownloadPath); + } + + return QStringLiteral("%1\n%2").arg(fileName, imageInfo); } bool ContentLibraryTexture::isDownloaded() const { - if (m_fileExt.isEmpty()) - return false; - - QString fullPath = realTexturePath(); - return QFileInfo(fullPath).isFile(); + return m_isDownloaded; } -QString ContentLibraryTexture::realTexturePath() const +QString ContentLibraryTexture::downloadedTexturePath() const { - return m_downloadPath + "/" + m_baseName + m_fileExt; + return m_downloadPath + '/' + m_baseName + m_fileExt; } void ContentLibraryTexture::setDownloaded() { - m_fileExt = resolveFileExt(); - QString toolTip = resolveToolTipText(); + QString toolTip = m_toolTip; - if (toolTip != m_toolTip) { - m_toolTip = toolTip; + doSetDownloaded(); + + if (toolTip != m_toolTip) emit textureToolTipChanged(); - } +} + +void ContentLibraryTexture::doSetDownloaded() +{ + if (m_fileExt.isEmpty()) + m_fileExt = resolveFileExt(); + + m_isDownloaded = QFileInfo::exists(downloadedTexturePath()); + m_toolTip = resolveToolTipText(); } QString ContentLibraryTexture::parentDirPath() const diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h index 383aed750bc..f6b6cfddd88 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexture.h @@ -5,6 +5,7 @@ #include #include +#include #include namespace QmlDesigner { @@ -22,7 +23,8 @@ class ContentLibraryTexture : public QObject public: ContentLibraryTexture(QObject *parent, const QFileInfo &iconFileInfo, - const QString &downloadPath, const QUrl &icon, const QString &webUrl); + const QString &downloadPath, const QUrl &icon, const QString &webUrl, + const QString &fileExt, const QSize &dimensions, const qint64 sizeInBytes); Q_INVOKABLE bool isDownloaded() const; Q_INVOKABLE void setDownloaded(); @@ -31,7 +33,7 @@ public: QUrl icon() const; QString iconPath() const; - QString realTexturePath() const; + QString downloadedTexturePath() const; QString parentDirPath() const; signals: @@ -39,9 +41,9 @@ signals: void textureToolTipChanged(); private: - inline static const QString m_defaultExt = ".png"; QString resolveFileExt(); QString resolveToolTipText(); + void doSetDownloaded(); QString m_iconPath; QString m_downloadPath; @@ -50,6 +52,9 @@ private: QString m_baseName; QString m_fileExt; QUrl m_icon; + QSize m_dimensions; + qint64 m_sizeInBytes = -1; + bool m_isDownloaded = false; bool m_visible = true; }; diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp index 62553b753be..534395abb83 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.cpp @@ -13,11 +13,13 @@ ContentLibraryTexturesCategory::ContentLibraryTexturesCategory(QObject *parent, : QObject(parent), m_name(name) {} void ContentLibraryTexturesCategory::addTexture(const QFileInfo &tex, const QString &downloadPath, - const QString &webUrl) + const QString &webUrl, const QString &fileExt, + const QSize &dimensions, const qint64 sizeInBytes) { QUrl icon = QUrl::fromLocalFile(tex.absoluteFilePath()); - m_categoryTextures.append(new ContentLibraryTexture(this, tex, downloadPath, icon, webUrl)); + m_categoryTextures.append(new ContentLibraryTexture(this, tex, downloadPath, icon, webUrl, + fileExt, dimensions, sizeInBytes)); } bool ContentLibraryTexturesCategory::filter(const QString &searchText) diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h index 0c4e9abb160..5883feb0015 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturescategory.h @@ -7,6 +7,7 @@ QT_BEGIN_NAMESPACE class QFileInfo; +class QSize; QT_END_NAMESPACE namespace QmlDesigner { @@ -26,7 +27,8 @@ class ContentLibraryTexturesCategory : public QObject public: ContentLibraryTexturesCategory(QObject *parent, const QString &name); - void addTexture(const QFileInfo &tex, const QString &subPath, const QString &webUrl); + void addTexture(const QFileInfo &tex, const QString &subPath, const QString &webUrl, + const QString &fileExt, const QSize &dimensions, const qint64 sizeInBytes); bool filter(const QString &searchText); QString name() const; diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp index 220149bfbc3..52c01065f76 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp @@ -13,15 +13,18 @@ #include #include +#include #include #include #include +#include #include namespace QmlDesigner { -ContentLibraryTexturesModel::ContentLibraryTexturesModel(const QString &bundleSubpath, QObject *parent) +ContentLibraryTexturesModel::ContentLibraryTexturesModel(const QString &bundleSubPath, QObject *parent) : QAbstractListModel(parent) + , m_bundleSubPath(bundleSubPath) { qmlRegisterType("WebFetcher", 1, 0, "FileDownloader"); qmlRegisterType("WebFetcher", 1, 0, "FileExtractor"); @@ -30,7 +33,7 @@ ContentLibraryTexturesModel::ContentLibraryTexturesModel(const QString &bundleSu QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/QtDesignStudio/bundles"; - m_downloadPath = baseDownloadPath + "/" + bundleSubpath; + m_downloadPath = baseDownloadPath + '/' + bundleSubPath; } int ContentLibraryTexturesModel::rowCount(const QModelIndex &) const @@ -96,7 +99,8 @@ QHash ContentLibraryTexturesModel::roleNames() const return roles; } -void ContentLibraryTexturesModel::loadTextureBundle(const QString &bundlePath, const QString &baseUrl) +void ContentLibraryTexturesModel::loadTextureBundle(const QString &bundlePath, const QString &baseUrl, + const QVariantMap &metaData) { QDir bundleDir = QDir(bundlePath); if (!bundleDir.exists()) { @@ -112,9 +116,22 @@ void ContentLibraryTexturesModel::loadTextureBundle(const QString &bundlePath, c auto category = new ContentLibraryTexturesCategory(this, dir.fileName()); const QFileInfoList texFiles = QDir(dir.filePath() + "/icon").entryInfoList(QDir::Files); for (const QFileInfo &tex : texFiles) { - QString urlPath = baseUrl + "/" + dir.fileName() + "/" + tex.baseName() + ".zip"; - QString downloadPath = m_downloadPath + "/" + dir.fileName(); - category->addTexture(tex, downloadPath, urlPath); + QString zipPath = '/' + dir.fileName() + '/' + tex.baseName() + ".zip"; + QString urlPath = baseUrl + zipPath; + QString downloadPath = m_downloadPath + '/' + dir.fileName(); + QString fullZipPath = m_bundleSubPath + zipPath; + QString fileExt; + QSize dimensions; + qint64 sizeInBytes = -1; + + if (metaData.contains(fullZipPath)) { + QVariantMap dataMap = metaData[fullZipPath].toMap(); + fileExt = '.' + dataMap.value("format").toString(); + dimensions = QSize(dataMap.value("width").toInt(), dataMap.value("height").toInt()); + sizeInBytes = dataMap.value("size").toLongLong(); + } + + category->addTexture(tex, downloadPath, urlPath, fileExt, dimensions, sizeInBytes); } m_bundleCategories.append(category); } diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h index 7c0691cff5d..f73d7b632a3 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.h @@ -33,7 +33,8 @@ public: void setHasSceneEnv(bool b); void resetModel(); - void loadTextureBundle(const QString &bundlePath, const QString &baseUrl); + void loadTextureBundle(const QString &bundlePath, const QString &baseUrl, + const QVariantMap &metaData); signals: void isEmptyChanged(); @@ -46,6 +47,7 @@ private: QString m_searchText; QString m_downloadPath; + QString m_bundleSubPath; QList m_bundleCategories; bool m_isEmpty = true; diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp index 146e2de7541..cacff6bf06e 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -69,10 +70,11 @@ bool ContentLibraryWidget::eventFilter(QObject *obj, QEvent *event) if ((me->globalPos() - m_dragStartPoint).manhattanLength() > 20 && m_textureToDrag->isDownloaded()) { QMimeData *mimeData = new QMimeData; - mimeData->setData(Constants::MIME_TYPE_BUNDLE_TEXTURE, {m_textureToDrag->realTexturePath().toUtf8()}); + mimeData->setData(Constants::MIME_TYPE_BUNDLE_TEXTURE, + {m_textureToDrag->downloadedTexturePath().toUtf8()}); // Allows standard file drag-n-drop. As of now needed to drop on Assets view - mimeData->setUrls({QUrl::fromLocalFile(m_textureToDrag->realTexturePath())}); + mimeData->setUrls({QUrl::fromLocalFile(m_textureToDrag->downloadedTexturePath())}); emit bundleTextureDragStarted(m_textureToDrag); model->startDrag(mimeData, m_textureToDrag->icon().toLocalFile()); @@ -106,8 +108,16 @@ ContentLibraryWidget::ContentLibraryWidget() QString baseUrl = QmlDesignerPlugin::settings() .value(DesignerSettingsKey::DOWNLOADABLE_BUNDLES_URL) .toString(); - m_texturesModel->loadTextureBundle(textureBundlePath + "/Textures", baseUrl + "/Textures"); - m_environmentsModel->loadTextureBundle(textureBundlePath + "/Environments", baseUrl + "/Environments"); + + QVariantMap metaData; + QFile jsonFile(textureBundlePath + "/texture_bundle.json"); + if (jsonFile.open(QIODevice::ReadOnly | QIODevice::Text)) + metaData = QJsonDocument::fromJson(jsonFile.readAll()).toVariant().toMap(); + + m_texturesModel->loadTextureBundle(textureBundlePath + "/Textures", + baseUrl + "/Textures", metaData); + m_environmentsModel->loadTextureBundle(textureBundlePath + "/Environments", + baseUrl + "/Environments", metaData); m_quickWidget->rootContext()->setContextProperties({ {"rootView", QVariant::fromValue(this)}, @@ -271,7 +281,7 @@ void ContentLibraryWidget::addImage(ContentLibraryTexture *tex) if (!tex->isDownloaded()) return; - emit addTextureRequested(tex->realTexturePath(), AddTextureMode::Image); + emit addTextureRequested(tex->downloadedTexturePath(), AddTextureMode::Image); } void ContentLibraryWidget::addTexture(ContentLibraryTexture *tex) @@ -279,7 +289,7 @@ void ContentLibraryWidget::addTexture(ContentLibraryTexture *tex) if (!tex->isDownloaded()) return; - emit addTextureRequested(tex->realTexturePath(), AddTextureMode::Texture); + emit addTextureRequested(tex->downloadedTexturePath(), AddTextureMode::Texture); } void ContentLibraryWidget::addLightProbe(ContentLibraryTexture *tex) @@ -287,7 +297,7 @@ void ContentLibraryWidget::addLightProbe(ContentLibraryTexture *tex) if (!tex->isDownloaded()) return; - emit addTextureRequested(tex->realTexturePath(), AddTextureMode::LightProbe); + emit addTextureRequested(tex->downloadedTexturePath(), AddTextureMode::LightProbe); } void ContentLibraryWidget::updateSceneEnvState() diff --git a/src/plugins/qmldesigner/utils/imageutils.cpp b/src/plugins/qmldesigner/utils/imageutils.cpp index 63f57d8a946..e83cb1262a7 100644 --- a/src/plugins/qmldesigner/utils/imageutils.cpp +++ b/src/plugins/qmldesigner/utils/imageutils.cpp @@ -11,15 +11,21 @@ namespace QmlDesigner { -QString QmlDesigner::ImageUtils::imageInfo(const QString &path, bool fetchSizeInfo) +QString ImageUtils::imageInfo(const QSize &dimensions, qint64 sizeInBytes) +{ + return QLatin1String("%1 x %2\n%3") + .arg(QString::number(dimensions.width()), + QString::number(dimensions.height()), + QLocale::system().formattedDataSize( + sizeInBytes, 2, QLocale::DataSizeTraditionalFormat)); +} + +QString QmlDesigner::ImageUtils::imageInfo(const QString &path) { QFileInfo info(path); if (!info.exists()) return {}; - if (!fetchSizeInfo) - return QLatin1String("(%1)").arg(info.suffix()); - int width = 0; int height = 0; const QString suffix = info.suffix(); @@ -43,14 +49,10 @@ QString QmlDesigner::ImageUtils::imageInfo(const QString &path, bool fetchSizeIn height = size.height(); } - if (width == 0 && height == 0) + if (width <= 0 || height <= 0) return {}; - return QLatin1String("%1 x %2\n%3 (%4)") - .arg(QString::number(width), - QString::number(height), - QLocale::system().formattedDataSize(info.size(), 2, QLocale::DataSizeTraditionalFormat), - info.suffix()); + return imageInfo(QSize(width, height), info.size()); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/utils/imageutils.h b/src/plugins/qmldesigner/utils/imageutils.h index 2cc58e8817d..a8deaeebff6 100644 --- a/src/plugins/qmldesigner/utils/imageutils.h +++ b/src/plugins/qmldesigner/utils/imageutils.h @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #pragma once +#include #include namespace QmlDesigner { @@ -11,7 +12,8 @@ class ImageUtils public: ImageUtils(); - static QString imageInfo(const QString &path, bool sizeInfo = true); + static QString imageInfo(const QSize &dimensions, qint64 sizeInBytes); + static QString imageInfo(const QString &path); }; } // namespace QmlDesigner