QmlDesigner: Add generated components when adding to content lib

Also few relevant fixes and tweaks.

Fixes: QDS-13746
Change-Id: I2a22d535591d6908ca3960145cb01682844aee38
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Ali Kianian <ali.kianian@qt.io>
This commit is contained in:
Mahmoud Badri
2024-10-23 17:27:25 +03:00
parent 6d0bb3d119
commit 5e3c0ffcc5
5 changed files with 43 additions and 43 deletions

View File

@@ -38,6 +38,11 @@ Utils::FilePath AssetPath::absFilPath() const
return basePath.pathAppended(relativePath);
}
QByteArray AssetPath::fileContent() const
{
return absFilPath().fileContents().value_or("");
}
BundleHelper::BundleHelper(AbstractView *view, QWidget *widget)
: m_view(view)
, m_widget(widget)
@@ -186,7 +191,7 @@ void BundleHelper::importBundleToProject()
}
QString typePrefix = compUtils.userBundleType(bundleId);
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.section('.', 0, 0)).toLatin1();
QString err = m_importer->importComponent(bundlePath.toFSPathString(), type, qml, files);
@@ -211,12 +216,6 @@ void BundleHelper::exportComponent(const ModelNode &node)
if (exportPath.isEmpty())
return;
// targetPath is a temp path for collecting and zipping assets, actual export target is where
// the user chose to export (i.e. exportPath)
QTemporaryDir tempDir;
QTC_ASSERT(tempDir.isValid(), return);
auto targetPath = Utils::FilePath::fromString(tempDir.path());
m_zipWriter = std::make_unique<ZipWriter>(exportPath);
Utils::FilePath compFilePath = Utils::FilePath::fromString(ModelUtils::componentFilePath(node));
@@ -224,14 +223,14 @@ void BundleHelper::exportComponent(const ModelNode &node)
QString compBaseName = compFilePath.completeBaseName();
QString compFileName = compFilePath.fileName();
QString iconPath = QLatin1String("icons/%1").arg(UniqueName::generateId(compBaseName) + ".png");
m_iconPath = QLatin1String("icons/%1").arg(UniqueName::generateId(compBaseName) + ".png");
const QSet<AssetPath> compDependencies = getComponentDependencies(compFilePath, compDir);
QStringList filesList;
for (const AssetPath &asset : compDependencies) {
Utils::FilePath assetAbsPath = asset.absFilPath();
QByteArray assetContent = assetAbsPath.fileContents().value_or("");
QByteArray assetContent = asset.fileContent();
// remove imports of sub components
for (const QString &import : std::as_const(asset.importsToRemove)) {
@@ -252,7 +251,7 @@ void BundleHelper::exportComponent(const ModelNode &node)
itemsArr.append(QJsonObject {
{"name", node.simplifiedTypeName()},
{"qml", compFileName},
{"icon", iconPath},
{"icon", m_iconPath},
{"files", QJsonArray::fromStringList(filesList)}
});
@@ -262,12 +261,9 @@ void BundleHelper::exportComponent(const ModelNode &node)
jsonObj["id"] = compUtils.user3DBundleId();
jsonObj["version"] = BUNDLE_VERSION;
Utils::FilePath jsonFilePath = targetPath.pathAppended(Constants::BUNDLE_JSON_FILENAME);
m_zipWriter->addFile(jsonFilePath.fileName(), QJsonDocument(jsonObj).toJson());
m_zipWriter->addFile(Constants::BUNDLE_JSON_FILENAME, QJsonDocument(jsonObj).toJson());
// add icon
m_iconSavePath = targetPath.pathAppended(iconPath);
m_iconSavePath.parentDir().ensureWritableDir();
getImageFromCache(compFilePath.path(), [&](const QImage &image) {
addIconAndCloseZip(image);
});
@@ -293,6 +289,7 @@ void BundleHelper::exportNode(const ModelNode &node, const QPixmap &iconPixmap)
QString qml = nodeNameToComponentFileName(name);
QString iconBaseName = UniqueName::generateId(name);
m_iconPath = QLatin1String("icons/%1.png").arg(iconBaseName);
// generate and save Qml file
auto [qmlString, depAssets] = modelNodeToQmlString(node);
@@ -307,15 +304,13 @@ void BundleHelper::exportNode(const ModelNode &node, const QPixmap &iconPixmap)
QTC_ASSERT_EXPECTED(result, return);
m_zipWriter->addFile(qmlFilePath.fileName(), qmlString.toUtf8());
QString iconPath = QLatin1String("icons/%1.png").arg(iconBaseName);
// add the item to the bundle json
QJsonObject jsonObj;
QJsonArray itemsArr;
itemsArr.append(QJsonObject {
{"name", name},
{"qml", qml},
{"icon", iconPath},
{"icon", m_iconPath},
{"files", QJsonArray::fromStringList(depAssetsRelativePaths)}
});
@@ -331,7 +326,7 @@ void BundleHelper::exportNode(const ModelNode &node, const QPixmap &iconPixmap)
// add item's dependency assets to the bundle zip and target path (for icon generation)
for (const AssetPath &assetPath : depAssetsList) {
auto assetContent = assetPath.absFilPath().fileContents().value_or("");
QByteArray assetContent = assetPath.fileContent();
m_zipWriter->addFile(assetPath.relativePath, assetContent);
Utils::FilePath assetTargetPath = targetPath.pathAppended(assetPath.relativePath);
@@ -352,7 +347,6 @@ void BundleHelper::exportNode(const ModelNode &node, const QPixmap &iconPixmap)
iconPixmapToSave = iconPixmap;
}
m_iconSavePath = targetPath.pathAppended(iconPath);
if (iconPixmapToSave.isNull()) {
getImageFromCache(qmlFilePath.toFSPathString(), [&](const QImage &image) {
addIconAndCloseZip(image);
@@ -556,7 +550,7 @@ void BundleHelper::addIconAndCloseZip(const auto &image) { // auto: QImage or QP
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "PNG");
m_zipWriter->addFile("icons/" + m_iconSavePath.fileName(), iconByteArray);
m_zipWriter->addFile(m_iconPath, iconByteArray);
m_zipWriter->close();
};
@@ -664,7 +658,7 @@ Utils::FilePath getComponentFilePath(const QString &nodeType, const Utils::FileP
} // namespace
QSet<AssetPath> BundleHelper::getComponentDependencies(const Utils::FilePath &filePath,
const Utils::FilePath &mainCompDir)
const Utils::FilePath &mainCompDir) const
{
QSet<AssetPath> depList;
AssetPath compAssetPath = {mainCompDir, filePath.relativePathFrom(mainCompDir).toFSPathString()};

View File

@@ -32,6 +32,7 @@ public:
{}
Utils::FilePath absFilPath() const;
QByteArray fileContent() const;
bool operator==(const AssetPath &other) const
{
@@ -62,6 +63,8 @@ public:
QString nodeNameToComponentFileName(const QString &name) const;
QPair<QString, QSet<AssetPath>> modelNodeToQmlString(const ModelNode &node, int depth = 0);
QString getImportPath() const;
QSet<AssetPath> getComponentDependencies(const Utils::FilePath &filePath,
const Utils::FilePath &mainCompDir) const;
private:
void createImporter();
@@ -71,8 +74,6 @@ private:
void addIconAndCloseZip(const auto &image);
Utils::FilePath componentPath(const NodeMetaInfo &metaInfo) const;
QSet<AssetPath> getBundleComponentDependencies(const ModelNode &node) const;
QSet<AssetPath> getComponentDependencies(const Utils::FilePath &filePath,
const Utils::FilePath &mainCompDir);
void exportComponent(const ModelNode &node);
void exportNode(const ModelNode &node, const QPixmap &iconPixmap = QPixmap());
@@ -81,7 +82,7 @@ private:
Utils::UniqueObjectPtr<BundleImporter> m_importer;
std::unique_ptr<ZipWriter> m_zipWriter;
std::unique_ptr<QTemporaryDir> m_tempDir;
Utils::FilePath m_iconSavePath;
QString m_iconPath;
static constexpr char BUNDLE_VERSION[] = "1.0";
};

View File

@@ -84,7 +84,7 @@ void ContentLibraryUserModel::addItem(const QString &bundleId, const QString &na
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
QString typePrefix = compUtils.userBundleType(bundleId);
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.section('.', 0, 0)).toLatin1();
SectionIndex sectionIndex = bundleIdToSectionIndex(bundleId);
@@ -308,7 +308,7 @@ void ContentLibraryUserModel::updateImportedState(const QStringList &importedIte
bool changed = false;
for (QObject *item : items) {
ContentLibraryItem *castedItem = qobject_cast<ContentLibraryItem *>(item);
changed |= castedItem->setImported(importedItems.contains(castedItem->qml().chopped(4)));
changed |= castedItem->setImported(importedItems.contains(castedItem->qml().section('.', 0, 0)));
}
if (changed)

View File

@@ -570,17 +570,18 @@ void ContentLibraryView::addLibAssets(const QStringList &paths)
m_widget->userModel()->addTextures(targetPathsToAdd);
}
// TODO: combine this method with BundleHelper::exportComponent()
void ContentLibraryView::addLib3DComponent(const ModelNode &node)
{
auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils();
auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d/");
m_bundleId = compUtils.user3DBundleId();
QString compBaseName = node.simplifiedTypeName();
QString compFileName = compBaseName + ".qml";
auto compDir = Utils::FilePath::fromString(ModelUtils::componentFilePath(node)).parentDir();
auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/3d/");
Utils::FilePath compFilePath = Utils::FilePath::fromString(ModelUtils::componentFilePath(node));
Utils::FilePath compDir = compFilePath.parentDir();
QString compBaseName = compFilePath.completeBaseName();
QString compFileName = compFilePath.fileName();
// confirm overwrite if an item with same name exists
if (bundlePath.pathAppended(compFileName).exists()) {
@@ -599,24 +600,28 @@ void ContentLibraryView::addLib3DComponent(const ModelNode &node)
m_iconSavePath = bundlePath.pathAppended(iconPath);
m_iconSavePath.parentDir().ensureWritableDir();
const Utils::FilePaths sourceFiles = compDir.dirEntries({{}, QDir::Files, QDirIterator::Subdirectories});
const QStringList ignoreList {"_importdata.json", "qmldir", compBaseName + ".hints"};
const QSet<AssetPath> compDependencies = m_bundleHelper->getComponentDependencies(compFilePath, compDir);
QStringList filesList; // 3D component's assets (dependencies)
for (const AssetPath &asset : compDependencies) {
Utils::FilePath assetAbsPath = asset.absFilPath();
QByteArray assetContent = asset.fileContent();
for (const Utils::FilePath &sourcePath : sourceFiles) {
Utils::FilePath relativePath = sourcePath.relativePathFrom(compDir);
if (ignoreList.contains(sourcePath.fileName()) || relativePath.startsWith("source scene"))
continue;
// remove imports of sub components
for (const QString &import : std::as_const(asset.importsToRemove)) {
int removeIdx = assetContent.indexOf(QByteArray("import " + import.toLatin1()));
int removeLen = assetContent.indexOf('\n', removeIdx) - removeIdx;
assetContent.remove(removeIdx, removeLen);
}
Utils::FilePath targetPath = bundlePath.pathAppended(relativePath.path());
Utils::FilePath targetPath = bundlePath.pathAppended(asset.relativePath);
targetPath.parentDir().ensureWritableDir();
// copy item from project to user bundle
auto result = sourcePath.copyFile(targetPath);
auto result = targetPath.writeFileContents(assetContent);
QTC_ASSERT_EXPECTED(result,);
if (sourcePath.fileName() != compFileName) // skip component file (only collect dependencies)
filesList.append(relativePath.path());
if (assetAbsPath.fileName() != compFileName) // skip component file (only collect dependencies)
filesList.append(asset.relativePath);
}
// add the item to the bundle json

View File

@@ -78,7 +78,7 @@ void UserItemCategory::loadBundle(bool force)
QString name = itemObj.value("name").toString();
QString qml = itemObj.value("qml").toString();
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.chopped(4)).toLatin1();
TypeName type = QLatin1String("%1.%2").arg(typePrefix, qml.section('.', 0, 0)).toLatin1();
QUrl icon = m_bundlePath.pathAppended(itemObj.value("icon").toString()).toUrl();
QStringList files = itemObj.value("files").toVariant().toStringList();