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 <mahmoud.badri@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Miikka Heikkinen
2023-03-03 14:02:55 +02:00
parent eb16c66552
commit 9a55bb0fd0
10 changed files with 111 additions and 58 deletions

View File

@@ -238,7 +238,7 @@ Item {
onFinishedChanged: {
mouseArea.enabled = true
modelData.setDownloaded()
root.downloadState = "downloaded"
root.downloadState = modelData.isDownloaded() ? "downloaded" : "failed"
root.downloadStateChanged()
rootView.markNoTextureDownloading()

View File

@@ -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

View File

@@ -5,6 +5,7 @@
#include <QFileInfo>
#include <QObject>
#include <QSize>
#include <QUrl>
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;
};

View File

@@ -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)

View File

@@ -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;

View File

@@ -13,15 +13,18 @@
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QUrl>
#include <QQmlEngine>
#include <QSize>
#include <QStandardPaths>
namespace QmlDesigner {
ContentLibraryTexturesModel::ContentLibraryTexturesModel(const QString &bundleSubpath, QObject *parent)
ContentLibraryTexturesModel::ContentLibraryTexturesModel(const QString &bundleSubPath, QObject *parent)
: QAbstractListModel(parent)
, m_bundleSubPath(bundleSubPath)
{
qmlRegisterType<QmlDesigner::FileDownloader>("WebFetcher", 1, 0, "FileDownloader");
qmlRegisterType<QmlDesigner::FileExtractor>("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<int, QByteArray> 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);
}

View File

@@ -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<ContentLibraryTexturesCategory *> m_bundleCategories;
bool m_isEmpty = true;

View File

@@ -18,6 +18,7 @@
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <QJsonDocument>
#include <QMimeData>
#include <QMouseEvent>
#include <QQmlContext>
@@ -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()

View File

@@ -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

View File

@@ -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 <QSize>
#include <QString>
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