Download icons and metadata of textures at startup

Task-number: QDS-9397
Change-Id: If1bb4a5500896b70b4a9dbb82d2122c1232ee744
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Samuel Ghinet
2023-03-23 20:50:12 +02:00
parent bda4ae301b
commit 2081d1c0bc
6 changed files with 150 additions and 26 deletions

View File

@@ -114,7 +114,7 @@ bool ContentLibraryMaterialsModel::fetchBundleIcons(const QDir &bundleDir)
QString iconsPath = bundleDir.filePath("icons");
QDir iconsDir(iconsPath);
if (iconsDir.exists() && iconsDir.entryList().length() > 0)
if (iconsDir.exists() && iconsDir.entryList(QDir::NoDotAndDotDot).length() > 0)
return true;
QString zipFileUrl = m_baseUrl + "/icons.zip";

View File

@@ -6,9 +6,6 @@
#include "contentlibrarytexturescategory.h"
#include "qmldesignerplugin.h"
#include "utils/filedownloader.h"
#include "utils/fileextractor.h"
#include <qmldesignerbase/qmldesignerbaseplugin.h>
#include <utils/algorithm.h>
@@ -18,6 +15,7 @@
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QJsonDocument>
#include <QQmlEngine>
#include <QSize>
#include <QStandardPaths>
@@ -28,9 +26,6 @@ namespace QmlDesigner {
ContentLibraryTexturesModel::ContentLibraryTexturesModel(const QString &category, QObject *parent)
: QAbstractListModel(parent)
{
qmlRegisterType<QmlDesigner::FileDownloader>("WebFetcher", 1, 0, "FileDownloader");
qmlRegisterType<QmlDesigner::FileExtractor>("WebFetcher", 1, 0, "FileExtractor");
m_category = category; // textures main category (ex: Textures, Environments)
}
@@ -103,28 +98,24 @@ QHash<int, QByteArray> ContentLibraryTexturesModel::roleNames() const
* @param bundlePath local path to the bundle folder and icons
* @param metaData bundle textures metadata
*/
void ContentLibraryTexturesModel::loadTextureBundle(const QString &bundlePath, const QVariantMap &metaData)
void ContentLibraryTexturesModel::loadTextureBundle(const QString &remoteUrl, const QString &bundleIconPath,
const QVariantMap &metaData)
{
if (!m_bundleCategories.isEmpty())
return;
QDir bundleDir = QString("%1/%2").arg(bundlePath, m_category);
QDir bundleDir = QString("%1/%2").arg(bundleIconPath, m_category);
if (!bundleDir.exists()) {
qWarning() << __FUNCTION__ << "textures bundle folder doesn't exist." << bundlePath;
qWarning() << __FUNCTION__ << "textures bundle folder doesn't exist." << bundleDir.absolutePath();
return;
}
QString remoteBaseUrl = QmlDesignerPlugin::settings()
.value(DesignerSettingsKey::DOWNLOADABLE_BUNDLES_URL).toString()
+ "/textures/" + m_category;
const QFileInfoList dirs = bundleDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo &dir : dirs) {
auto category = new ContentLibraryTexturesCategory(this, dir.fileName());
const QFileInfoList texFiles = QDir(dir.filePath() + "/icon").entryInfoList(QDir::Files);
const QFileInfoList texFiles = QDir(dir.filePath()).entryInfoList(QDir::Files);
for (const QFileInfo &tex : texFiles) {
QString fullRemoteUrl = QString("%1/%2/%3.zip").arg(remoteBaseUrl, dir.fileName(),
QString fullRemoteUrl = QString("%1/%2/%3.zip").arg(remoteUrl, dir.fileName(),
tex.baseName());
QString localDownloadPath = QString("%1/%2/%3").arg(QmlDesignerBasePlugin::bundlesPathSetting(),
m_category, dir.fileName());
@@ -145,6 +136,7 @@ void ContentLibraryTexturesModel::loadTextureBundle(const QString &bundlePath, c
m_bundleCategories.append(category);
}
resetModel();
updateIsEmpty();
}

View File

@@ -33,7 +33,8 @@ public:
void setHasSceneEnv(bool b);
void resetModel();
void loadTextureBundle(const QString &bundlePath, const QVariantMap &metaData);
void loadTextureBundle(const QString &remoteUrl, const QString &bundlePath,
const QVariantMap &metaData);
signals:
void isEmptyChanged();

View File

@@ -8,6 +8,9 @@
#include "contentlibrarytexture.h"
#include "contentlibrarytexturesmodel.h"
#include "utils/filedownloader.h"
#include "utils/fileextractor.h"
#include <coreplugin/icore.h>
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
@@ -19,6 +22,7 @@
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
#include <QDir>
#include <QJsonDocument>
#include <QMimeData>
#include <QMouseEvent>
@@ -32,6 +36,8 @@
namespace QmlDesigner {
constexpr int TextureBundleMetadataVersion = 1;
static QString propertyEditorResourcesPath()
{
#ifdef SHARE_QML_PATH
@@ -98,6 +104,9 @@ ContentLibraryWidget::ContentLibraryWidget()
, m_texturesModel(new ContentLibraryTexturesModel("Textures", this))
, m_environmentsModel(new ContentLibraryTexturesModel("Environments", this))
{
qmlRegisterType<QmlDesigner::FileDownloader>("WebFetcher", 1, 0, "FileDownloader");
qmlRegisterType<QmlDesigner::FileExtractor>("WebFetcher", 1, 0, "FileExtractor");
setWindowTitle(tr("Content Library", "Title of content library widget"));
setMinimumWidth(120);
@@ -106,15 +115,17 @@ ContentLibraryWidget::ContentLibraryWidget()
m_quickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
m_quickWidget->setClearColor(Theme::getColor(Theme::Color::DSpanelBackground));
QString textureBundlePath = findTextureBundlePath();
m_baseUrl = QmlDesignerPlugin::settings()
.value(DesignerSettingsKey::DOWNLOADABLE_BUNDLES_URL).toString()
+ "/textures/v1";
QVariantMap metaData;
QFile jsonFile(textureBundlePath + "/texture_bundle.json");
if (jsonFile.open(QIODevice::ReadOnly | QIODevice::Text))
metaData = QJsonDocument::fromJson(jsonFile.readAll()).toVariant().toMap();
m_texturesUrl = m_baseUrl + "/Textures";
m_environmentsUrl = m_baseUrl + "/Environments";
m_texturesModel->loadTextureBundle(textureBundlePath, metaData);
m_environmentsModel->loadTextureBundle(textureBundlePath, metaData);
m_downloadPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)
+ "/QtDesignStudio/bundles";
loadTextureBundle();
Theme::setupTheme(m_quickWidget->engine());
m_quickWidget->quickWidget()->installEventFilter(this);
@@ -144,6 +155,115 @@ ContentLibraryWidget::ContentLibraryWidget()
reloadQmlSource();
}
QVariantMap ContentLibraryWidget::readBundleMetadata()
{
QVariantMap metaData;
QFile jsonFile(m_downloadPath + "/texture_bundle.json");
if (jsonFile.open(QIODevice::ReadOnly | QIODevice::Text))
metaData = QJsonDocument::fromJson(jsonFile.readAll()).toVariant().toMap();
int version = metaData["version"].toInt();
if (version != TextureBundleMetadataVersion) {
qWarning() << "Unrecognized texture metadata file version: " << version;
return {};
}
return metaData;
}
void ContentLibraryWidget::loadTextureBundle()
{
QDir bundleDir{m_downloadPath};
if (fetchTextureBundleMetadata(bundleDir) && fetchTextureBundleIcons(bundleDir)) {
QString bundleIconPath = m_downloadPath + "/TextureBundleIcons";
QVariantMap metaData = readBundleMetadata();
m_texturesModel->loadTextureBundle(m_texturesUrl, bundleIconPath, metaData);
m_environmentsModel->loadTextureBundle(m_environmentsUrl, bundleIconPath, metaData);
}
}
bool ContentLibraryWidget::fetchTextureBundleMetadata(const QDir &bundleDir)
{
QString filePath = bundleDir.filePath("texture_bundle.json");
QFileInfo fi(filePath);
if (fi.exists() && fi.size() > 0)
return true;
QString metaFileUrl = m_baseUrl + "/texture_bundle.zip";
FileDownloader *downloader = new FileDownloader(this);
downloader->setUrl(metaFileUrl);
downloader->setProbeUrl(false);
downloader->setDownloadEnabled(true);
QObject::connect(downloader, &FileDownloader::finishedChanged, this, [=]() {
FileExtractor *extractor = new FileExtractor(this);
extractor->setArchiveName(downloader->completeBaseName());
extractor->setSourceFile(downloader->outputFile());
extractor->setTargetPath(bundleDir.absolutePath());
extractor->setAlwaysCreateDir(false);
extractor->setClearTargetPathContents(false);
QObject::connect(extractor, &FileExtractor::finishedChanged, this, [=]() {
downloader->deleteLater();
extractor->deleteLater();
if (fetchTextureBundleIcons(bundleDir)) {
QString bundleIconPath = m_downloadPath + "/TextureBundleIcons";
QVariantMap metaData = readBundleMetadata();
m_texturesModel->loadTextureBundle(m_texturesUrl, bundleIconPath, metaData);
m_environmentsModel->loadTextureBundle(m_environmentsUrl, bundleIconPath, metaData);
}
});
extractor->extract();
});
downloader->start();
return false;
}
bool ContentLibraryWidget::fetchTextureBundleIcons(const QDir &bundleDir)
{
QString iconsPath = bundleDir.filePath("TextureBundleIcons");
QDir iconsDir(iconsPath);
if (iconsDir.exists() && iconsDir.entryList(QDir::NoDotAndDotDot).length() > 0)
return true;
QString zipFileUrl = m_baseUrl + "/icons.zip";
FileDownloader *downloader = new FileDownloader(this);
downloader->setUrl(zipFileUrl);
downloader->setProbeUrl(false);
downloader->setDownloadEnabled(true);
QObject::connect(downloader, &FileDownloader::finishedChanged, this, [=]() {
FileExtractor *extractor = new FileExtractor(this);
extractor->setArchiveName(downloader->completeBaseName());
extractor->setSourceFile(downloader->outputFile());
extractor->setTargetPath(bundleDir.absolutePath());
extractor->setAlwaysCreateDir(false);
extractor->setClearTargetPathContents(false);
QObject::connect(extractor, &FileExtractor::finishedChanged, this, [=]() {
downloader->deleteLater();
extractor->deleteLater();
QString bundleIconPath = m_downloadPath + "/TextureBundleIcons";
QVariantMap metaData = readBundleMetadata();
m_texturesModel->loadTextureBundle(m_texturesUrl, bundleIconPath, metaData);
m_environmentsModel->loadTextureBundle(m_environmentsUrl, bundleIconPath, metaData);
});
extractor->extract();
});
downloader->start();
return false;
}
QList<QToolButton *> ContentLibraryWidget::createToolBarWidgets()
{
return {};

View File

@@ -9,6 +9,7 @@
#include <QPointer>
QT_BEGIN_NAMESPACE
class QDir;
class QShortcut;
class QToolButton;
QT_END_NAMESPACE
@@ -80,6 +81,10 @@ private:
void updateSearch();
void setIsDragging(bool val);
QString findTextureBundlePath();
void loadTextureBundle();
QVariantMap readBundleMetadata();
bool fetchTextureBundleMetadata(const QDir &bundleDir);
bool fetchTextureBundleIcons(const QDir &bundleDir);
QScopedPointer<StudioQuickWidget> m_quickWidget;
QPointer<ContentLibraryMaterialsModel> m_materialsModel;
@@ -98,6 +103,10 @@ private:
bool m_hasQuick3DImport = false;
bool m_isDragging = false;
bool m_anyTextureBeingDownloaded = false;
QString m_baseUrl;
QString m_texturesUrl;
QString m_environmentsUrl;
QString m_downloadPath;
};
} // namespace QmlDesigner

View File

@@ -8,6 +8,7 @@
#include <QDir>
#include <QQmlEngine>
#include <QRandomGenerator>
namespace QmlDesigner {
@@ -41,7 +42,8 @@ void FileDownloader::start()
{
emit downloadStarting();
QString tempFileName = QDir::tempPath() + "/.qds_download_" + url().fileName();
auto uniqueText = QByteArray::number(QRandomGenerator::global()->generate(), 16);
QString tempFileName = QDir::tempPath() + "/.qds_" + uniqueText + "_download_" + url().fileName();
m_outputFile.setFileName(tempFileName);
m_outputFile.open(QIODevice::WriteOnly);