aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-10-10 12:18:38 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-10-15 13:19:16 +0000
commit062a0a9dbd8391accdefccd2f9a43d4190b08424 (patch)
tree2ba55dd77dda83bda2a14c8f59060bf61ee141ae
parent1278c01c1cc4e42aa52b410523b5d4aedab2e38b (diff)
Implement support for UIA/UIP importing
Each different type of import file gets its own options tab in import dialog. Item library icon for each imported component is generated at import time depending on component root element type. Change-Id: I95824b43d251d02d8e032b6a3e45a18d1d509b80 Fixes: QDS-1152 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
-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";