aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp662
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h8
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui43
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp92
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h7
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp32
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp37
-rw-r--r--src/plugins/qmldesigner/qmldesignerconstants.h2
8 files changed, 503 insertions, 380 deletions
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
index f1eb737aed..bfdbfe5c22 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
@@ -44,6 +44,7 @@
#include <QtWidgets/qspinbox.h>
#include <QtWidgets/qscrollbar.h>
#include <QtWidgets/qtabbar.h>
+#include <QtWidgets/qscrollarea.h>
namespace QmlDesigner {
@@ -62,6 +63,8 @@ static void addFormattedMessage(Utils::OutputFormatter *formatter, const QString
formatter->plainTextEdit()->verticalScrollBar()->maximum());
}
+static const int rowHeight = 26;
+
}
ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &importFiles,
@@ -140,301 +143,67 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
}
m_quick3DImportPath = candidatePath;
- // Create UI controls for options
- if (!importFiles.isEmpty()) {
- QJsonObject supportedOptions = QJsonObject::fromVariantMap(
- m_importer.supportedOptions(importFiles[0]));
- m_importOptions = supportedOptions.value("options").toObject();
- const QJsonObject groups = supportedOptions.value("groups").toObject();
-
- const int checkBoxColWidth = 18;
- const int labelMinWidth = 130;
- const int controlMinWidth = 65;
- const int columnSpacing = 16;
- const int rowHeight = 26;
- int rowIndex[2] = {0, 0};
-
- // First index has ungrouped widgets, rest are groups
- // First item in each real group is group label
- QVector<QVector<QPair<QWidget *, QWidget *>>> widgets;
- QHash<QString, int> groupIndexMap;
- QHash<QString, QPair<QWidget *, QWidget *>> optionToWidgetsMap;
- QHash<QString, QJsonArray> conditionMap;
- QHash<QWidget *, QWidget *> conditionalWidgetMap;
- QHash<QString, QString> optionToGroupMap;
-
- auto layout = new QGridLayout(ui->optionsAreaContents);
- layout->setColumnMinimumWidth(0, checkBoxColWidth);
- layout->setColumnMinimumWidth(1, labelMinWidth);
- layout->setColumnMinimumWidth(2, controlMinWidth);
- layout->setColumnMinimumWidth(3, columnSpacing);
- layout->setColumnMinimumWidth(4, checkBoxColWidth);
- layout->setColumnMinimumWidth(5, labelMinWidth);
- layout->setColumnMinimumWidth(6, controlMinWidth);
- layout->setColumnStretch(0, 0);
- layout->setColumnStretch(1, 4);
- layout->setColumnStretch(2, 2);
- layout->setColumnStretch(3, 0);
- layout->setColumnStretch(4, 0);
- layout->setColumnStretch(5, 4);
- layout->setColumnStretch(6, 2);
-
- widgets.append(QVector<QPair<QWidget *, QWidget *>>());
-
- for (const auto group : groups) {
- const QString name = group.toObject().value("name").toString();
- const QJsonArray items = group.toObject().value("items").toArray();
- for (const auto item : items)
- optionToGroupMap.insert(item.toString(), name);
- auto groupLabel = new QLabel(name, ui->optionsAreaContents);
- QFont labelFont = groupLabel->font();
- labelFont.setBold(true);
- groupLabel->setFont(labelFont);
- widgets.append({{groupLabel, nullptr}});
- groupIndexMap.insert(name, widgets.size() - 1);
+ if (!m_quick3DFiles.isEmpty()) {
+ const QHash<QString, QVariantMap> allOptions = m_importer.allOptions();
+ const QHash<QString, QStringList> supportedExtensions = m_importer.supportedExtensions();
+ QVector<QJsonObject> groups;
+
+ auto optIt = allOptions.constBegin();
+ int optIndex = 0;
+ while (optIt != allOptions.constEnd()) {
+ QJsonObject options = QJsonObject::fromVariantMap(optIt.value());
+ m_importOptions << options.value("options").toObject();
+ groups << options.value("groups").toObject();
+ const auto &exts = optIt.key().split(':');
+ for (const auto &ext : exts)
+ m_extToImportOptionsMap.insert(ext, optIndex);
+ ++optIt;
+ ++optIndex;
}
- const auto optKeys = m_importOptions.keys();
- for (const auto &optKey : optKeys) {
- QJsonObject optObj = m_importOptions.value(optKey).toObject();
- const QString optName = optObj.value("name").toString();
- const QString optDesc = optObj.value("description").toString();
- const QString optType = optObj.value("type").toString();
- QJsonObject optRange = optObj.value("range").toObject();
- QJsonValue optValue = optObj.value("value");
- QJsonArray conditions = optObj.value("conditions").toArray();
-
- QWidget *optControl = nullptr;
- if (optType == "Boolean") {
- auto *optCheck = new QCheckBox(ui->optionsAreaContents);
- optCheck->setChecked(optValue.toBool());
- optControl = optCheck;
- QObject::connect(optCheck, &QCheckBox::toggled, [this, optCheck, optKey]() {
- QJsonObject optObj = m_importOptions.value(optKey).toObject();
- QJsonValue value(optCheck->isChecked());
- optObj.insert("value", value);
- m_importOptions.insert(optKey, optObj);
- });
- } else if (optType == "Real") {
- auto *optSpin = new QDoubleSpinBox(ui->optionsAreaContents);
- double min = -999999999.;
- double max = 999999999.;
- double step = 1.;
- int decimals = 3;
- if (!optRange.isEmpty()) {
- min = optRange.value("minimum").toDouble();
- max = optRange.value("maximum").toDouble();
- // Ensure step is reasonable for small ranges
- double range = max - min;
- while (range <= 10.) {
- step /= 10.;
- range *= 10.;
- if (step < 0.02)
- ++decimals;
- }
-
+ // Create tab for each supported extension group that also has files included in the import
+ QMap<QString, int> tabMap; // QMap used for alphabetical order
+ for (const auto &file : qAsConst(m_quick3DFiles)) {
+ auto extIt = supportedExtensions.constBegin();
+ QString ext = QFileInfo(file).suffix();
+ while (extIt != supportedExtensions.constEnd()) {
+ if (!tabMap.contains(extIt.key()) && extIt.value().contains(ext)) {
+ tabMap.insert(extIt.key(), m_extToImportOptionsMap.value(ext));
+ break;
}
- optSpin->setRange(min, max);
- optSpin->setDecimals(decimals);
- optSpin->setValue(optValue.toDouble());
- optSpin->setSingleStep(step);
- optSpin->setMinimumWidth(controlMinWidth);
- optControl = optSpin;
- QObject::connect(optSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
- [this, optSpin, optKey]() {
- QJsonObject optObj = m_importOptions.value(optKey).toObject();
- QJsonValue value(optSpin->value());
- optObj.insert("value", value);
- m_importOptions.insert(optKey, optObj);
- });
- } else {
- qWarning() << __FUNCTION__ << "Unsupported option type:" << optType;
- continue;
+ ++extIt;
}
-
- if (!conditions.isEmpty())
- conditionMap.insert(optKey, conditions);
-
- auto *optLabel = new QLabel(ui->optionsAreaContents);
- optLabel->setText(optName);
- optLabel->setToolTip(optDesc);
- optControl->setToolTip(optDesc);
-
- const QString &groupName = optionToGroupMap.value(optKey);
- if (!groupName.isEmpty() && groupIndexMap.contains(groupName))
- widgets[groupIndexMap[groupName]].append({optLabel, optControl});
- else
- widgets[0].append({optLabel, optControl});
- optionToWidgetsMap.insert(optKey, {optLabel, optControl});
}
- // Handle conditions
- auto it = conditionMap.constBegin();
- while (it != conditionMap.constEnd()) {
- const QString &option = it.key();
- const QJsonArray &conditions = it.value();
- const auto &conWidgets = optionToWidgetsMap.value(option);
- QWidget *conLabel = conWidgets.first;
- QWidget *conControl = conWidgets.second;
- // Currently we only support single condition per option, though the schema allows for
- // multiple, as no real life option currently has multiple conditions and connections
- // get complicated if we need to comply to multiple conditions.
- if (!conditions.isEmpty() && conLabel && conControl) {
- const auto &conObj = conditions[0].toObject();
- const QString optItem = conObj.value("property").toString();
- const auto &optWidgets = optionToWidgetsMap.value(optItem);
- const QString optMode = conObj.value("mode").toString();
- const QVariant optValue = conObj.value("value").toVariant();
- enum class Mode { equals, notEquals, greaterThan, lessThan };
- Mode mode;
- if (optMode == "NotEquals")
- mode = Mode::notEquals;
- else if (optMode == "GreaterThan")
- mode = Mode::greaterThan;
- else if (optMode == "LessThan")
- mode = Mode::lessThan;
- else
- mode = Mode::equals; // Default to equals
-
- if (optWidgets.first && optWidgets.second) {
- auto optCb = qobject_cast<QCheckBox *>(optWidgets.second);
- auto optSpin = qobject_cast<QDoubleSpinBox *>(optWidgets.second);
- if (optCb) {
- auto enableConditionally = [optValue](QCheckBox *cb, QWidget *w1,
- QWidget *w2, Mode mode) {
- bool equals = (mode == Mode::equals) == optValue.toBool();
- bool enable = cb->isChecked() == equals;
- w1->setEnabled(enable);
- w2->setEnabled(enable);
- };
- enableConditionally(optCb, conLabel, conControl, mode);
- if (conditionalWidgetMap.contains(optCb))
- conditionalWidgetMap.insert(optCb, nullptr);
- else
- conditionalWidgetMap.insert(optCb, conControl);
- QObject::connect(
- optCb, &QCheckBox::toggled,
- [optCb, conLabel, conControl, mode, enableConditionally]() {
- enableConditionally(optCb, conLabel, conControl, mode);
- });
- }
- if (optSpin) {
- auto enableConditionally = [optValue](QDoubleSpinBox *sb, QWidget *w1,
- QWidget *w2, Mode mode) {
- bool enable = false;
- double value = optValue.toDouble();
- if (mode == Mode::equals)
- enable = qFuzzyCompare(value, sb->value());
- else if (mode == Mode::notEquals)
- enable = !qFuzzyCompare(value, sb->value());
- else if (mode == Mode::greaterThan)
- enable = sb->value() > value;
- else if (mode == Mode::lessThan)
- enable = sb->value() < value;
- w1->setEnabled(enable);
- w2->setEnabled(enable);
- };
- enableConditionally(optSpin, conLabel, conControl, mode);
- QObject::connect(
- optSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
- [optSpin, conLabel, conControl, mode, enableConditionally]() {
- enableConditionally(optSpin, conLabel, conControl, mode);
- });
- }
- }
- }
- ++it;
+ ui->tabWidget->clear();
+ auto tabIt = tabMap.constBegin();
+ while (tabIt != tabMap.constEnd()) {
+ createTab(tabIt.key(), tabIt.value(), groups[tabIt.value()]);
+ ++tabIt;
}
- // Combine options where a non-boolean option depends on a boolean option that no other
- // option depends on
- auto condIt = conditionalWidgetMap.constBegin();
- while (condIt != conditionalWidgetMap.constEnd()) {
- if (condIt.value()) {
- // Find and fix widget pairs
- for (int i = 0; i < widgets.size(); ++i) {
- auto &groupWidgets = widgets[i];
- auto widgetIt = groupWidgets.begin();
- while (widgetIt != groupWidgets.end()) {
- if (widgetIt->second == condIt.value()) {
- if (widgetIt->first)
- widgetIt->first->hide();
- groupWidgets.erase(widgetIt);
- } else {
- ++widgetIt;
- }
- }
- // If group was left with less than two actual members, disband the group
- // and move the remaining member to ungrouped options
- // Note: <= 2 instead of < 2 because each group has group label member
- if (i != 0 && groupWidgets.size() <= 2) {
- widgets[0].prepend(groupWidgets[1]);
- groupWidgets[0].first->hide(); // hide group label
- groupWidgets.clear();
+ // Pad all tabs to same height
+ for (int i = 0; i < ui->tabWidget->count(); ++i) {
+ auto optionsArea = qobject_cast<QScrollArea *>(ui->tabWidget->widget(i));
+ if (optionsArea && optionsArea->widget()) {
+ auto grid = qobject_cast<QGridLayout *>(optionsArea->widget()->layout());
+ if (grid) {
+ int rows = grid->rowCount();
+ for (int j = rows; j < m_optionsRows; ++j) {
+ grid->addWidget(new QWidget(optionsArea->widget()), j, 0);
+ grid->setRowMinimumHeight(j, rowHeight);
}
}
}
- ++condIt;
}
- auto incrementColIndex = [&](int col) {
- layout->setRowMinimumHeight(rowIndex[col], rowHeight);
- ++rowIndex[col];
- };
-
- auto insertOptionToLayout = [&](int col, const QPair<QWidget *, QWidget *> &optionWidgets) {
- layout->addWidget(optionWidgets.first, rowIndex[col], col * 4 + 1, 1, 2);
- int adj = qobject_cast<QCheckBox *>(optionWidgets.second) ? 0 : 2;
- layout->addWidget(optionWidgets.second, rowIndex[col], col * 4 + adj);
- if (!adj) {
- // Check box option may have additional conditional value field
- QWidget *condWidget = conditionalWidgetMap.value(optionWidgets.second);
- if (condWidget)
- layout->addWidget(condWidget, rowIndex[col], col * 4 + 2);
- }
- incrementColIndex(col);
- };
-
- // Add option widgets to layout. Grouped options are added to the tops of the columns
- for (int i = 1; i < widgets.size(); ++i) {
- int col = rowIndex[1] < rowIndex[0] ? 1 : 0;
- const auto &groupWidgets = widgets[i];
- if (!groupWidgets.isEmpty()) {
- // First widget in each group is the group label
- layout->addWidget(groupWidgets[0].first, rowIndex[col], col * 4, 1, 3);
- incrementColIndex(col);
- for (int j = 1; j < groupWidgets.size(); ++j)
- insertOptionToLayout(col, groupWidgets[j]);
- // Add a separator line after each group
- auto *separator = new QFrame(ui->optionsAreaContents);
- separator->setMaximumHeight(1);
- separator->setFrameShape(QFrame::HLine);
- separator->setFrameShadow(QFrame::Sunken);
- separator->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
- layout->addWidget(separator, rowIndex[col], col * 4, 1, 3);
- incrementColIndex(col);
- }
- }
-
- // Ungrouped options are spread evenly under the groups
- int totalRowCount = (rowIndex[0] + rowIndex[1] + widgets[0].size() + 1) / 2;
- for (const auto &rowWidgets : qAsConst(widgets[0])) {
- int col = rowIndex[0] < totalRowCount ? 0 : 1;
- insertOptionToLayout(col, rowWidgets);
- }
-
- ui->optionsAreaContents->setLayout(layout);
- ui->optionsAreaContents->setMinimumSize(
- checkBoxColWidth * 2 + labelMinWidth * 2 + controlMinWidth * 2 + columnSpacing,
- rowHeight * qMax(rowIndex[0], rowIndex[1]));
+ ui->tabWidget->setCurrentIndex(0);
}
- ui->optionsArea->setStyleSheet("QScrollArea {background-color: transparent}");
- ui->optionsAreaContents->setStyleSheet(
- "QWidget#optionsAreaContents {background-color: transparent}");
-
connect(ui->buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked,
this, &ItemLibraryAssetImportDialog::onClose);
+ connect(ui->tabWidget, &QTabWidget::currentChanged,
+ this, &ItemLibraryAssetImportDialog::updateUi);
connect(&m_importer, &ItemLibraryAssetImporter::errorReported,
this, &ItemLibraryAssetImportDialog::addError);
@@ -454,7 +223,8 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
addInfo(file);
QTimer::singleShot(0, [this]() {
- resizeEvent(nullptr);
+ ui->tabWidget->setMaximumHeight(m_optionsHeight + ui->tabWidget->tabBar()->height() + 10);
+ updateUi();
});
}
@@ -463,16 +233,333 @@ ItemLibraryAssetImportDialog::~ItemLibraryAssetImportDialog()
delete ui;
}
+void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int optionsIndex,
+ const QJsonObject &groups)
+{
+ const int checkBoxColWidth = 18;
+ const int labelMinWidth = 130;
+ const int controlMinWidth = 65;
+ const int columnSpacing = 16;
+ int rowIndex[2] = {0, 0};
+
+ QJsonObject &options = m_importOptions[optionsIndex];
+
+ // First index has ungrouped widgets, rest are groups
+ // First item in each real group is group label
+ QVector<QVector<QPair<QWidget *, QWidget *>>> widgets;
+ QHash<QString, int> groupIndexMap;
+ QHash<QString, QPair<QWidget *, QWidget *>> optionToWidgetsMap;
+ QHash<QString, QJsonArray> conditionMap;
+ QHash<QWidget *, QWidget *> conditionalWidgetMap;
+ QHash<QString, QString> optionToGroupMap;
+
+ auto optionsArea = new QScrollArea(ui->tabWidget);
+ optionsArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ auto optionsAreaContents = new QWidget(optionsArea);
+
+ auto layout = new QGridLayout(optionsAreaContents);
+ layout->setColumnMinimumWidth(0, checkBoxColWidth);
+ layout->setColumnMinimumWidth(1, labelMinWidth);
+ layout->setColumnMinimumWidth(2, controlMinWidth);
+ layout->setColumnMinimumWidth(3, columnSpacing);
+ layout->setColumnMinimumWidth(4, checkBoxColWidth);
+ layout->setColumnMinimumWidth(5, labelMinWidth);
+ layout->setColumnMinimumWidth(6, controlMinWidth);
+ layout->setColumnStretch(0, 0);
+ layout->setColumnStretch(1, 4);
+ layout->setColumnStretch(2, 2);
+ layout->setColumnStretch(3, 0);
+ layout->setColumnStretch(4, 0);
+ layout->setColumnStretch(5, 4);
+ layout->setColumnStretch(6, 2);
+
+ widgets.append(QVector<QPair<QWidget *, QWidget *>>());
+
+ for (const auto group : groups) {
+ const QString name = group.toObject().value("name").toString();
+ const QJsonArray items = group.toObject().value("items").toArray();
+ for (const auto item : items)
+ optionToGroupMap.insert(item.toString(), name);
+ auto groupLabel = new QLabel(name, optionsAreaContents);
+ QFont labelFont = groupLabel->font();
+ labelFont.setBold(true);
+ groupLabel->setFont(labelFont);
+ widgets.append({{groupLabel, nullptr}});
+ groupIndexMap.insert(name, widgets.size() - 1);
+ }
+
+ const auto optKeys = options.keys();
+ for (const auto &optKey : optKeys) {
+ QJsonObject optObj = options.value(optKey).toObject();
+ const QString optName = optObj.value("name").toString();
+ const QString optDesc = optObj.value("description").toString();
+ const QString optType = optObj.value("type").toString();
+ QJsonObject optRange = optObj.value("range").toObject();
+ QJsonValue optValue = optObj.value("value");
+ QJsonArray conditions = optObj.value("conditions").toArray();
+
+ QWidget *optControl = nullptr;
+ if (optType == "Boolean") {
+ auto *optCheck = new QCheckBox(optionsAreaContents);
+ optCheck->setChecked(optValue.toBool());
+ optControl = optCheck;
+ QObject::connect(optCheck, &QCheckBox::toggled,
+ [this, optCheck, optKey, optionsIndex]() {
+ QJsonObject optObj = m_importOptions[optionsIndex].value(optKey).toObject();
+ QJsonValue value(optCheck->isChecked());
+ optObj.insert("value", value);
+ m_importOptions[optionsIndex].insert(optKey, optObj);
+ });
+ } else if (optType == "Real") {
+ auto *optSpin = new QDoubleSpinBox(optionsAreaContents);
+ double min = -999999999.;
+ double max = 999999999.;
+ double step = 1.;
+ int decimals = 3;
+ if (!optRange.isEmpty()) {
+ min = optRange.value("minimum").toDouble();
+ max = optRange.value("maximum").toDouble();
+ // Ensure step is reasonable for small ranges
+ double range = max - min;
+ while (range <= 10.) {
+ step /= 10.;
+ range *= 10.;
+ if (step < 0.02)
+ ++decimals;
+ }
+
+ }
+ optSpin->setRange(min, max);
+ optSpin->setDecimals(decimals);
+ optSpin->setValue(optValue.toDouble());
+ optSpin->setSingleStep(step);
+ optSpin->setMinimumWidth(controlMinWidth);
+ optControl = optSpin;
+ QObject::connect(optSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
+ [this, optSpin, optKey, optionsIndex]() {
+ QJsonObject optObj = m_importOptions[optionsIndex].value(optKey).toObject();
+ QJsonValue value(optSpin->value());
+ optObj.insert("value", value);
+ m_importOptions[optionsIndex].insert(optKey, optObj);
+ });
+ } else {
+ qWarning() << __FUNCTION__ << "Unsupported option type:" << optType;
+ continue;
+ }
+
+ if (!conditions.isEmpty())
+ conditionMap.insert(optKey, conditions);
+
+ auto *optLabel = new QLabel(optionsAreaContents);
+ optLabel->setText(optName);
+ optLabel->setToolTip(optDesc);
+ optControl->setToolTip(optDesc);
+
+ const QString &groupName = optionToGroupMap.value(optKey);
+ if (!groupName.isEmpty() && groupIndexMap.contains(groupName))
+ widgets[groupIndexMap[groupName]].append({optLabel, optControl});
+ else
+ widgets[0].append({optLabel, optControl});
+ optionToWidgetsMap.insert(optKey, {optLabel, optControl});
+ }
+
+ // Handle conditions
+ auto it = conditionMap.constBegin();
+ while (it != conditionMap.constEnd()) {
+ const QString &option = it.key();
+ const QJsonArray &conditions = it.value();
+ const auto &conWidgets = optionToWidgetsMap.value(option);
+ QWidget *conLabel = conWidgets.first;
+ QWidget *conControl = conWidgets.second;
+ // Currently we only support single condition per option, though the schema allows for
+ // multiple, as no real life option currently has multiple conditions and connections
+ // get complicated if we need to comply to multiple conditions.
+ if (!conditions.isEmpty() && conLabel && conControl) {
+ const auto &conObj = conditions[0].toObject();
+ const QString optItem = conObj.value("property").toString();
+ const auto &optWidgets = optionToWidgetsMap.value(optItem);
+ const QString optMode = conObj.value("mode").toString();
+ const QVariant optValue = conObj.value("value").toVariant();
+ enum class Mode { equals, notEquals, greaterThan, lessThan };
+ Mode mode;
+ if (optMode == "NotEquals")
+ mode = Mode::notEquals;
+ else if (optMode == "GreaterThan")
+ mode = Mode::greaterThan;
+ else if (optMode == "LessThan")
+ mode = Mode::lessThan;
+ else
+ mode = Mode::equals; // Default to equals
+
+ if (optWidgets.first && optWidgets.second) {
+ auto optCb = qobject_cast<QCheckBox *>(optWidgets.second);
+ auto optSpin = qobject_cast<QDoubleSpinBox *>(optWidgets.second);
+ if (optCb) {
+ auto enableConditionally = [optValue](QCheckBox *cb, QWidget *w1,
+ QWidget *w2, Mode mode) {
+ bool equals = (mode == Mode::equals) == optValue.toBool();
+ bool enable = cb->isChecked() == equals;
+ w1->setEnabled(enable);
+ w2->setEnabled(enable);
+ };
+ enableConditionally(optCb, conLabel, conControl, mode);
+ if (conditionalWidgetMap.contains(optCb))
+ conditionalWidgetMap.insert(optCb, nullptr);
+ else
+ conditionalWidgetMap.insert(optCb, conControl);
+ QObject::connect(
+ optCb, &QCheckBox::toggled,
+ [optCb, conLabel, conControl, mode, enableConditionally]() {
+ enableConditionally(optCb, conLabel, conControl, mode);
+ });
+ }
+ if (optSpin) {
+ auto enableConditionally = [optValue](QDoubleSpinBox *sb, QWidget *w1,
+ QWidget *w2, Mode mode) {
+ bool enable = false;
+ double value = optValue.toDouble();
+ if (mode == Mode::equals)
+ enable = qFuzzyCompare(value, sb->value());
+ else if (mode == Mode::notEquals)
+ enable = !qFuzzyCompare(value, sb->value());
+ else if (mode == Mode::greaterThan)
+ enable = sb->value() > value;
+ else if (mode == Mode::lessThan)
+ enable = sb->value() < value;
+ w1->setEnabled(enable);
+ w2->setEnabled(enable);
+ };
+ enableConditionally(optSpin, conLabel, conControl, mode);
+ QObject::connect(
+ optSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
+ [optSpin, conLabel, conControl, mode, enableConditionally]() {
+ enableConditionally(optSpin, conLabel, conControl, mode);
+ });
+ }
+ }
+ }
+ ++it;
+ }
+
+ // Combine options where a non-boolean option depends on a boolean option that no other
+ // option depends on
+ auto condIt = conditionalWidgetMap.constBegin();
+ while (condIt != conditionalWidgetMap.constEnd()) {
+ if (condIt.value()) {
+ // Find and fix widget pairs
+ for (int i = 0; i < widgets.size(); ++i) {
+ auto &groupWidgets = widgets[i];
+ auto widgetIt = groupWidgets.begin();
+ while (widgetIt != groupWidgets.end()) {
+ if (widgetIt->second == condIt.value()
+ && !qobject_cast<QCheckBox *>(condIt.value())) {
+ if (widgetIt->first)
+ widgetIt->first->hide();
+ groupWidgets.erase(widgetIt);
+ } else {
+ ++widgetIt;
+ }
+ }
+ // If group was left with less than two actual members, disband the group
+ // and move the remaining member to ungrouped options
+ // Note: <= 2 instead of < 2 because each group has group label member
+ if (i != 0 && groupWidgets.size() <= 2) {
+ widgets[0].prepend(groupWidgets[1]);
+ groupWidgets[0].first->hide(); // hide group label
+ groupWidgets.clear();
+ }
+ }
+ }
+ ++condIt;
+ }
+
+ auto incrementColIndex = [&](int col) {
+ layout->setRowMinimumHeight(rowIndex[col], rowHeight);
+ ++rowIndex[col];
+ };
+
+ auto insertOptionToLayout = [&](int col, const QPair<QWidget *, QWidget *> &optionWidgets) {
+ layout->addWidget(optionWidgets.first, rowIndex[col], col * 4 + 1, 1, 2);
+ int adj = qobject_cast<QCheckBox *>(optionWidgets.second) ? 0 : 2;
+ layout->addWidget(optionWidgets.second, rowIndex[col], col * 4 + adj);
+ if (!adj) {
+ // Check box option may have additional conditional value field
+ QWidget *condWidget = conditionalWidgetMap.value(optionWidgets.second);
+ if (condWidget)
+ layout->addWidget(condWidget, rowIndex[col], col * 4 + 2);
+ }
+ incrementColIndex(col);
+ };
+
+ if (widgets.size() == 1 && widgets[0].isEmpty()) {
+ layout->addWidget(new QLabel(tr("No options available for this type."),
+ optionsAreaContents), 0, 0, 2, 7, Qt::AlignCenter);
+ incrementColIndex(0);
+ incrementColIndex(0);
+ }
+
+ // Add option widgets to layout. Grouped options are added to the tops of the columns
+ for (int i = 1; i < widgets.size(); ++i) {
+ int col = rowIndex[1] < rowIndex[0] ? 1 : 0;
+ const auto &groupWidgets = widgets[i];
+ if (!groupWidgets.isEmpty()) {
+ // First widget in each group is the group label
+ layout->addWidget(groupWidgets[0].first, rowIndex[col], col * 4, 1, 3);
+ incrementColIndex(col);
+ for (int j = 1; j < groupWidgets.size(); ++j)
+ insertOptionToLayout(col, groupWidgets[j]);
+ // Add a separator line after each group
+ auto *separator = new QFrame(optionsAreaContents);
+ separator->setMaximumHeight(1);
+ separator->setFrameShape(QFrame::HLine);
+ separator->setFrameShadow(QFrame::Sunken);
+ separator->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ layout->addWidget(separator, rowIndex[col], col * 4, 1, 3);
+ incrementColIndex(col);
+ }
+ }
+
+ // Ungrouped options are spread evenly under the groups
+ int totalRowCount = (rowIndex[0] + rowIndex[1] + widgets[0].size() + 1) / 2;
+ for (const auto &rowWidgets : qAsConst(widgets[0])) {
+ int col = rowIndex[0] < totalRowCount ? 0 : 1;
+ insertOptionToLayout(col, rowWidgets);
+ }
+
+ int optionRows = qMax(rowIndex[0], rowIndex[1]);
+ m_optionsRows = qMax(m_optionsRows, optionRows);
+ m_optionsHeight = qMax(rowHeight * optionRows + 16, m_optionsHeight);
+ layout->setContentsMargins(8, 8, 8, 8);
+ optionsAreaContents->setContentsMargins(0, 0, 0, 0);
+ optionsAreaContents->setLayout(layout);
+ optionsAreaContents->setMinimumWidth(
+ (checkBoxColWidth + labelMinWidth + controlMinWidth) * 2 + columnSpacing);
+ optionsAreaContents->setObjectName("optionsAreaContents"); // For stylesheet
+
+ optionsArea->setWidget(optionsAreaContents);
+ optionsArea->setStyleSheet("QScrollArea {background-color: transparent}");
+ optionsAreaContents->setStyleSheet(
+ "QWidget#optionsAreaContents {background-color: transparent}");
+
+ ui->tabWidget->addTab(optionsArea, tr("%1 options").arg(tabLabel));
+}
+
+void ItemLibraryAssetImportDialog::updateUi()
+{
+ auto optionsArea = qobject_cast<QScrollArea *>(ui->tabWidget->currentWidget());
+ if (optionsArea) {
+ auto optionsAreaContents = optionsArea->widget();
+ int scrollBarWidth = optionsArea->verticalScrollBar()->isVisible()
+ ? optionsArea->verticalScrollBar()->width() : 0;
+ optionsAreaContents->resize(optionsArea->contentsRect().width()
+ - scrollBarWidth - 8, m_optionsHeight);
+ }
+}
+
void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
{
Q_UNUSED(event)
- int scrollBarWidth = ui->optionsArea->verticalScrollBar()->isVisible()
- ? ui->optionsArea->verticalScrollBar()->width() : 0;
- ui->tabWidget->setMaximumHeight(ui->optionsAreaContents->height()
- + ui->tabWidget->tabBar()->height() + 10);
- ui->optionsArea->resize(ui->tabWidget->currentWidget()->size());
- ui->optionsAreaContents->resize(ui->optionsArea->contentsRect().width()
- - scrollBarWidth - 8, 0);
+ updateUi();
}
void ItemLibraryAssetImportDialog::setCloseButtonState(bool importing)
@@ -504,7 +591,7 @@ void ItemLibraryAssetImportDialog::onImport()
if (!m_quick3DFiles.isEmpty()) {
m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath,
- m_importOptions.toVariantMap());
+ m_importOptions, m_extToImportOptionsMap);
}
}
@@ -549,4 +636,5 @@ void ItemLibraryAssetImportDialog::onClose()
deleteLater();
}
}
+
}
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h
index 52fbcc0999..713e3fd20b 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h
@@ -66,12 +66,18 @@ private:
void onImportFinished();
void onClose();
+ void createTab(const QString &tabLabel, int optionsIndex, const QJsonObject &groups);
+ void updateUi();
+
Ui::ItemLibraryAssetImportDialog *ui = nullptr;
Utils::OutputFormatter *m_outputFormatter = nullptr;
QStringList m_quick3DFiles;
QString m_quick3DImportPath;
ItemLibraryAssetImporter m_importer;
- QJsonObject m_importOptions;
+ QVector<QJsonObject> m_importOptions;
+ QHash<QString, int> m_extToImportOptionsMap;
+ int m_optionsHeight = 0;
+ int m_optionsRows = 0;
};
}
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui
index 710135ad04..e6b0286357 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>631</width>
- <height>740</height>
+ <height>750</height>
</rect>
</property>
<property name="windowTitle">
@@ -32,47 +32,6 @@
<attribute name="title">
<string>Import Options</string>
</attribute>
- <widget class="QScrollArea" name="optionsArea">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>611</width>
- <height>351</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>2</verstretch>
- </sizepolicy>
- </property>
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAlwaysOff</enum>
- </property>
- <property name="widgetResizable">
- <bool>false</bool>
- </property>
- <widget class="QWidget" name="optionsAreaContents">
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>0</width>
- <height>0</height>
- </rect>
- </property>
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="autoFillBackground">
- <bool>false</bool>
- </property>
- </widget>
- </widget>
</widget>
</widget>
</item>
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
index deb50e0a66..c67b527abb 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
@@ -32,6 +32,7 @@
#include <QtCore/qdir.h>
#include <QtCore/qdiriterator.h>
#include <QtCore/qsavefile.h>
+#include <QtCore/qfile.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qtemporarydir.h>
#include <QtWidgets/qapplication.h>
@@ -63,7 +64,8 @@ ItemLibraryAssetImporter::~ItemLibraryAssetImporter() {
void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
const QString &importPath,
- const QVariantMap &options)
+ const QVector<QJsonObject> &options,
+ const QHash<QString, int> &extToImportOptionsMap)
{
if (m_isImporting)
cancelImport();
@@ -79,7 +81,7 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
m_importPath = importPath;
- parseFiles(inputFiles, options);
+ parseFiles(inputFiles, options, extToImportOptionsMap);
if (!isCancelled()) {
// Don't allow cancel anymore as existing asset overwrites are not trivially recoverable.
@@ -221,7 +223,9 @@ void ItemLibraryAssetImporter::reset()
#endif
}
-void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths, const QVariantMap &options)
+void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths,
+ const QVector<QJsonObject> &options,
+ const QHash<QString, int> &extToImportOptionsMap)
{
if (isCancelled())
return;
@@ -236,8 +240,11 @@ void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths, const QV
for (const QString &file : filePaths) {
if (isCancelled())
return;
- if (isQuick3DAsset(file))
- parseQuick3DAsset(file, options);
+ if (isQuick3DAsset(file)) {
+ QVariantMap varOpts;
+ int index = extToImportOptionsMap.value(QFileInfo(file).suffix());
+ parseQuick3DAsset(file, options[index].toVariantMap());
+ }
notifyProgress(qRound(++count * quota), progressTitle);
}
notifyProgress(100, progressTitle);
@@ -296,31 +303,70 @@ void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVar
return;
}
- // Generate qmldir file
- outDir.setNameFilters({QStringLiteral("*.qml")});
- const QFileInfoList qmlFiles = outDir.entryInfoList(QDir::Files);
-
- if (!qmlFiles.isEmpty()) {
- QString qmldirFileName = outDir.absoluteFilePath(QStringLiteral("qmldir"));
+ // Generate qmldir file if importer doesn't already make one
+ QString qmldirFileName = outDir.absoluteFilePath(QStringLiteral("qmldir"));
+ if (!QFileInfo(qmldirFileName).exists()) {
QSaveFile qmldirFile(qmldirFileName);
QString version = QStringLiteral("1.0");
- if (qmldirFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
- for (const auto &fi : qmlFiles) {
+
+ // Note: Currently Quick3D importers only generate externally usable qml files on the top
+ // level of the import directory, so we don't search subdirectories. The qml files in
+ // subdirs assume they are used within the context of the toplevel qml files.
+ QDirIterator qmlIt(outDir.path(), {QStringLiteral("*.qml")}, QDir::Files);
+ if (qmlIt.hasNext()) {
+ outDir.mkdir(Constants::QUICK_3D_ASSET_ICON_DIR);
+ if (qmldirFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QString qmlInfo;
- qmlInfo.append(fi.baseName());
- qmlInfo.append(QLatin1Char(' '));
- qmlInfo.append(version);
- qmlInfo.append(QLatin1Char(' '));
- qmlInfo.append(fi.fileName());
+ qmlInfo.append("module ");
+ qmlInfo.append(m_importPath.split('/').last());
+ qmlInfo.append(".");
+ qmlInfo.append(assetName);
+ qmlInfo.append('\n');
+ while (qmlIt.hasNext()) {
+ qmlIt.next();
+ QFileInfo fi = QFileInfo(qmlIt.filePath());
+ qmlInfo.append(fi.baseName());
+ qmlInfo.append(' ');
+ qmlInfo.append(version);
+ qmlInfo.append(' ');
+ qmlInfo.append(outDir.relativeFilePath(qmlIt.filePath()));
+ qmlInfo.append('\n');
+
+ // Generate item library icon for qml file based on root component
+ QFile qmlFile(qmlIt.filePath());
+ if (qmlFile.open(QIODevice::ReadOnly)) {
+ QString iconFileName = outDir.path() + '/'
+ + Constants::QUICK_3D_ASSET_ICON_DIR + '/' + fi.baseName()
+ + Constants::QUICK_3D_ASSET_LIBRARY_ICON_SUFFIX;
+ QString iconFileName2x = iconFileName + "@2x";
+ QByteArray content = qmlFile.readAll();
+ int braceIdx = content.indexOf('{');
+ if (braceIdx != -1) {
+ int nlIdx = content.lastIndexOf('\n', braceIdx);
+ QByteArray rootItem = content.mid(nlIdx, braceIdx - nlIdx).trimmed();
+ if (rootItem == "Node") {
+ QFile::copy(":/ItemLibrary/images/item-3D_model-icon.png",
+ iconFileName);
+ QFile::copy(":/ItemLibrary/images/item-3D_model-icon@2x.png",
+ iconFileName2x);
+ } else {
+ QFile::copy(":/ItemLibrary/images/item-default-icon.png",
+ iconFileName);
+ QFile::copy(":/ItemLibrary/images/item-default-icon@2x.png",
+ iconFileName2x);
+ }
+ }
+ }
+ }
qmldirFile.write(qmlInfo.toUtf8());
+ qmldirFile.commit();
+ } else {
+ addError(tr("Failed to create qmldir file for asset: \"%1\"").arg(assetName));
}
- qmldirFile.commit();
- } else {
- addError(tr("Failed to create qmldir file for asset: \"%1\"").arg(assetName));
}
}
- // Gather generated files
+ // Gather all generated files
const int outDirPathSize = outDir.path().size();
QDirIterator dirIt(outDir.path(), QDir::Files, QDirIterator::Subdirectories);
QHash<QString, QString> assetFiles;
@@ -334,7 +380,7 @@ void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVar
// Copy the original asset into a subdirectory
assetFiles.insert(sourceInfo.absoluteFilePath(),
- targetDirPath + QStringLiteral("/source model/") + sourceInfo.fileName());
+ targetDirPath + QStringLiteral("/source scene/") + sourceInfo.fileName());
m_importFiles.insert(assetFiles);
#else
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h
index 6c6b4f972b..76af5b8013 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h
@@ -27,6 +27,7 @@
#include <QtCore/qobject.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qhash.h>
+#include <QtCore/qjsonobject.h>
#include "import.h"
@@ -46,7 +47,8 @@ public:
~ItemLibraryAssetImporter();
void importQuick3D(const QStringList &inputFiles, const QString &importPath,
- const QVariantMap &options);
+ const QVector<QJsonObject> &options,
+ const QHash<QString, int> &extToImportOptionsMap);
bool isImporting() const;
void cancelImport();
@@ -72,7 +74,8 @@ signals:
private:
void notifyFinished();
void reset();
- void parseFiles(const QStringList &filePaths, const QVariantMap &options);
+ void parseFiles(const QStringList &filePaths, const QVector<QJsonObject> &options,
+ const QHash<QString, int> &extToImportOptionsMap);
void parseQuick3DAsset(const QString &file, const QVariantMap &options);
void copyImportedFiles();
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
index da056aaf6b..8010ed6107 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
@@ -209,19 +209,27 @@ ItemLibraryWidget::ItemLibraryWidget(QWidget *parent) :
QSSGAssetImportManager importManager;
QHash<QString, QStringList> supportedExtensions = importManager.getSupportedExtensions();
- // Skip if 3D model handlers have already been added
+ // All things importable by QSSGAssetImportManager are considered to be in the same category
+ // so we don't get multiple separate import dialogs when different file types are imported.
+ const QString category = tr("3D Assets");
+
+ // Skip if 3D asset handlers have already been added
const QList<AddResourceHandler> handlers = actionManager->addResourceHandler();
- QSet<QString> handlerCats;
- for (const auto &h : handlers)
- handlerCats.insert(h.category);
-
- const auto categories = supportedExtensions.keys();
- for (const auto &category : categories) {
- if (handlerCats.contains(category))
- continue;
- const auto extensions = supportedExtensions[category];
- for (const auto &ext : extensions)
- add3DHandler(category, ext);
+ bool categoryAlreadyAdded = false;
+ for (const auto &handler : handlers) {
+ if (handler.category == category) {
+ categoryAlreadyAdded = true;
+ break;
+ }
+ }
+
+ if (!categoryAlreadyAdded) {
+ const auto groups = supportedExtensions.keys();
+ for (const auto &group : groups) {
+ const auto extensions = supportedExtensions[group];
+ for (const auto &ext : extensions)
+ add3DHandler(category, ext);
+ }
}
#endif
diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
index 0c707ff837..d173a83749 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
@@ -35,6 +35,7 @@
#include <coreplugin/messagebox.h>
#include <QDir>
+#include <QDirIterator>
#include <QMessageBox>
#include <QUrl>
@@ -387,19 +388,29 @@ void SubComponentManager::parseQuick3DAssetDir(const QString &assetPath)
for (auto &import : qAsConst(m_imports)) {
if (import.isLibraryImport() && assets.contains(import.url())) {
assets.removeOne(import.url());
- ItemLibraryEntry itemLibraryEntry;
- const QString name = import.url().mid(import.url().indexOf(QLatin1Char('.')) + 1);
- const QString type = import.url() + QLatin1Char('.') + name;
- // For now we assume version is always 1.0 as that's what importer hardcodes
- itemLibraryEntry.setType(type.toUtf8(), 1, 0);
- itemLibraryEntry.setName(name);
- itemLibraryEntry.setCategory(tr("My Quick3D Components"));
- itemLibraryEntry.setRequiredImport(import.url());
- itemLibraryEntry.setLibraryEntryIconPath(iconPath);
- itemLibraryEntry.setTypeIcon(QIcon(iconPath));
-
- if (!model()->metaInfo().itemLibraryInfo()->containsEntry(itemLibraryEntry))
- model()->metaInfo().itemLibraryInfo()->addEntries({itemLibraryEntry});
+ QDirIterator qmlIt(assetDir.filePath(import.url().split('.').last()),
+ {QStringLiteral("*.qml")}, QDir::Files);
+ while (qmlIt.hasNext()) {
+ qmlIt.next();
+ const QString name = qmlIt.fileInfo().baseName();
+ const QString type = import.url() + QLatin1Char('.') + name;
+ // For now we assume version is always 1.0 as that's what importer hardcodes
+ ItemLibraryEntry itemLibraryEntry;
+ itemLibraryEntry.setType(type.toUtf8(), 1, 0);
+ itemLibraryEntry.setName(name);
+ itemLibraryEntry.setCategory(tr("My Quick3D Components"));
+ itemLibraryEntry.setRequiredImport(import.url());
+ QString iconName = qmlIt.fileInfo().absolutePath() + '/'
+ + Constants::QUICK_3D_ASSET_ICON_DIR + '/' + name
+ + Constants::QUICK_3D_ASSET_LIBRARY_ICON_SUFFIX;
+ if (!QFileInfo(iconName).exists())
+ iconName = iconPath;
+ itemLibraryEntry.setLibraryEntryIconPath(iconName);
+ itemLibraryEntry.setTypeIcon(QIcon(iconName));
+
+ if (!model()->metaInfo().itemLibraryInfo()->containsEntry(itemLibraryEntry))
+ model()->metaInfo().itemLibraryInfo()->addEntries({itemLibraryEntry});
+ }
}
}
diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h
index 7d4079e75f..82445f4e78 100644
--- a/src/plugins/qmldesigner/qmldesignerconstants.h
+++ b/src/plugins/qmldesigner/qmldesignerconstants.h
@@ -51,6 +51,8 @@ const char EXPORT_AS_IMAGE[] = "QmlDesigner.ExportAsImage";
const char QML_DESIGNER_SUBFOLDER[] = "/designer/";
const char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets";
+const char QUICK_3D_ASSET_LIBRARY_ICON_SUFFIX[] = "_libicon";
+const char QUICK_3D_ASSET_ICON_DIR[] = "_icons";
const char DEFAULT_ASSET_IMPORT_FOLDER[] = "/asset_imports";
const char QT_QUICK_3D_MODULE_NAME[] = "QtQuick3D";