forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -44,6 +44,7 @@
|
|||||||
#include <QtWidgets/qspinbox.h>
|
#include <QtWidgets/qspinbox.h>
|
||||||
#include <QtWidgets/qscrollbar.h>
|
#include <QtWidgets/qscrollbar.h>
|
||||||
#include <QtWidgets/qtabbar.h>
|
#include <QtWidgets/qtabbar.h>
|
||||||
|
#include <QtWidgets/qscrollarea.h>
|
||||||
|
|
||||||
namespace QmlDesigner {
|
namespace QmlDesigner {
|
||||||
|
|
||||||
@@ -62,6 +63,8 @@ static void addFormattedMessage(Utils::OutputFormatter *formatter, const QString
|
|||||||
formatter->plainTextEdit()->verticalScrollBar()->maximum());
|
formatter->plainTextEdit()->verticalScrollBar()->maximum());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const int rowHeight = 26;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &importFiles,
|
ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &importFiles,
|
||||||
@@ -140,20 +143,107 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
|
|||||||
}
|
}
|
||||||
m_quick3DImportPath = candidatePath;
|
m_quick3DImportPath = candidatePath;
|
||||||
|
|
||||||
// Create UI controls for options
|
if (!m_quick3DFiles.isEmpty()) {
|
||||||
if (!importFiles.isEmpty()) {
|
const QHash<QString, QVariantMap> allOptions = m_importer.allOptions();
|
||||||
QJsonObject supportedOptions = QJsonObject::fromVariantMap(
|
const QHash<QString, QStringList> supportedExtensions = m_importer.supportedExtensions();
|
||||||
m_importer.supportedOptions(importFiles[0]));
|
QVector<QJsonObject> groups;
|
||||||
m_importOptions = supportedOptions.value("options").toObject();
|
|
||||||
const QJsonObject groups = supportedOptions.value("groups").toObject();
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
++extIt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->tabWidget->clear();
|
||||||
|
auto tabIt = tabMap.constBegin();
|
||||||
|
while (tabIt != tabMap.constEnd()) {
|
||||||
|
createTab(tabIt.key(), tabIt.value(), groups[tabIt.value()]);
|
||||||
|
++tabIt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->tabWidget->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
connect(&m_importer, &ItemLibraryAssetImporter::warningReported,
|
||||||
|
this, &ItemLibraryAssetImportDialog::addWarning);
|
||||||
|
connect(&m_importer, &ItemLibraryAssetImporter::infoReported,
|
||||||
|
this, &ItemLibraryAssetImportDialog::addInfo);
|
||||||
|
connect(&m_importer, &ItemLibraryAssetImporter::importNearlyFinished,
|
||||||
|
this, &ItemLibraryAssetImportDialog::onImportNearlyFinished);
|
||||||
|
connect(&m_importer, &ItemLibraryAssetImporter::importFinished,
|
||||||
|
this, &ItemLibraryAssetImportDialog::onImportFinished);
|
||||||
|
connect(&m_importer, &ItemLibraryAssetImporter::progressChanged,
|
||||||
|
this, &ItemLibraryAssetImportDialog::setImportProgress);
|
||||||
|
|
||||||
|
addInfo(tr("Select import options and press \"Import\" to import the following files:"));
|
||||||
|
for (const auto &file : m_quick3DFiles)
|
||||||
|
addInfo(file);
|
||||||
|
|
||||||
|
QTimer::singleShot(0, [this]() {
|
||||||
|
ui->tabWidget->setMaximumHeight(m_optionsHeight + ui->tabWidget->tabBar()->height() + 10);
|
||||||
|
updateUi();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemLibraryAssetImportDialog::~ItemLibraryAssetImportDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int optionsIndex,
|
||||||
|
const QJsonObject &groups)
|
||||||
|
{
|
||||||
const int checkBoxColWidth = 18;
|
const int checkBoxColWidth = 18;
|
||||||
const int labelMinWidth = 130;
|
const int labelMinWidth = 130;
|
||||||
const int controlMinWidth = 65;
|
const int controlMinWidth = 65;
|
||||||
const int columnSpacing = 16;
|
const int columnSpacing = 16;
|
||||||
const int rowHeight = 26;
|
|
||||||
int rowIndex[2] = {0, 0};
|
int rowIndex[2] = {0, 0};
|
||||||
|
|
||||||
|
QJsonObject &options = m_importOptions[optionsIndex];
|
||||||
|
|
||||||
// First index has ungrouped widgets, rest are groups
|
// First index has ungrouped widgets, rest are groups
|
||||||
// First item in each real group is group label
|
// First item in each real group is group label
|
||||||
QVector<QVector<QPair<QWidget *, QWidget *>>> widgets;
|
QVector<QVector<QPair<QWidget *, QWidget *>>> widgets;
|
||||||
@@ -163,7 +253,11 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
|
|||||||
QHash<QWidget *, QWidget *> conditionalWidgetMap;
|
QHash<QWidget *, QWidget *> conditionalWidgetMap;
|
||||||
QHash<QString, QString> optionToGroupMap;
|
QHash<QString, QString> optionToGroupMap;
|
||||||
|
|
||||||
auto layout = new QGridLayout(ui->optionsAreaContents);
|
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(0, checkBoxColWidth);
|
||||||
layout->setColumnMinimumWidth(1, labelMinWidth);
|
layout->setColumnMinimumWidth(1, labelMinWidth);
|
||||||
layout->setColumnMinimumWidth(2, controlMinWidth);
|
layout->setColumnMinimumWidth(2, controlMinWidth);
|
||||||
@@ -186,7 +280,7 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
|
|||||||
const QJsonArray items = group.toObject().value("items").toArray();
|
const QJsonArray items = group.toObject().value("items").toArray();
|
||||||
for (const auto item : items)
|
for (const auto item : items)
|
||||||
optionToGroupMap.insert(item.toString(), name);
|
optionToGroupMap.insert(item.toString(), name);
|
||||||
auto groupLabel = new QLabel(name, ui->optionsAreaContents);
|
auto groupLabel = new QLabel(name, optionsAreaContents);
|
||||||
QFont labelFont = groupLabel->font();
|
QFont labelFont = groupLabel->font();
|
||||||
labelFont.setBold(true);
|
labelFont.setBold(true);
|
||||||
groupLabel->setFont(labelFont);
|
groupLabel->setFont(labelFont);
|
||||||
@@ -194,9 +288,9 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
|
|||||||
groupIndexMap.insert(name, widgets.size() - 1);
|
groupIndexMap.insert(name, widgets.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto optKeys = m_importOptions.keys();
|
const auto optKeys = options.keys();
|
||||||
for (const auto &optKey : optKeys) {
|
for (const auto &optKey : optKeys) {
|
||||||
QJsonObject optObj = m_importOptions.value(optKey).toObject();
|
QJsonObject optObj = options.value(optKey).toObject();
|
||||||
const QString optName = optObj.value("name").toString();
|
const QString optName = optObj.value("name").toString();
|
||||||
const QString optDesc = optObj.value("description").toString();
|
const QString optDesc = optObj.value("description").toString();
|
||||||
const QString optType = optObj.value("type").toString();
|
const QString optType = optObj.value("type").toString();
|
||||||
@@ -206,17 +300,18 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
|
|||||||
|
|
||||||
QWidget *optControl = nullptr;
|
QWidget *optControl = nullptr;
|
||||||
if (optType == "Boolean") {
|
if (optType == "Boolean") {
|
||||||
auto *optCheck = new QCheckBox(ui->optionsAreaContents);
|
auto *optCheck = new QCheckBox(optionsAreaContents);
|
||||||
optCheck->setChecked(optValue.toBool());
|
optCheck->setChecked(optValue.toBool());
|
||||||
optControl = optCheck;
|
optControl = optCheck;
|
||||||
QObject::connect(optCheck, &QCheckBox::toggled, [this, optCheck, optKey]() {
|
QObject::connect(optCheck, &QCheckBox::toggled,
|
||||||
QJsonObject optObj = m_importOptions.value(optKey).toObject();
|
[this, optCheck, optKey, optionsIndex]() {
|
||||||
|
QJsonObject optObj = m_importOptions[optionsIndex].value(optKey).toObject();
|
||||||
QJsonValue value(optCheck->isChecked());
|
QJsonValue value(optCheck->isChecked());
|
||||||
optObj.insert("value", value);
|
optObj.insert("value", value);
|
||||||
m_importOptions.insert(optKey, optObj);
|
m_importOptions[optionsIndex].insert(optKey, optObj);
|
||||||
});
|
});
|
||||||
} else if (optType == "Real") {
|
} else if (optType == "Real") {
|
||||||
auto *optSpin = new QDoubleSpinBox(ui->optionsAreaContents);
|
auto *optSpin = new QDoubleSpinBox(optionsAreaContents);
|
||||||
double min = -999999999.;
|
double min = -999999999.;
|
||||||
double max = 999999999.;
|
double max = 999999999.;
|
||||||
double step = 1.;
|
double step = 1.;
|
||||||
@@ -241,11 +336,11 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
|
|||||||
optSpin->setMinimumWidth(controlMinWidth);
|
optSpin->setMinimumWidth(controlMinWidth);
|
||||||
optControl = optSpin;
|
optControl = optSpin;
|
||||||
QObject::connect(optSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
QObject::connect(optSpin, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
|
||||||
[this, optSpin, optKey]() {
|
[this, optSpin, optKey, optionsIndex]() {
|
||||||
QJsonObject optObj = m_importOptions.value(optKey).toObject();
|
QJsonObject optObj = m_importOptions[optionsIndex].value(optKey).toObject();
|
||||||
QJsonValue value(optSpin->value());
|
QJsonValue value(optSpin->value());
|
||||||
optObj.insert("value", value);
|
optObj.insert("value", value);
|
||||||
m_importOptions.insert(optKey, optObj);
|
m_importOptions[optionsIndex].insert(optKey, optObj);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
qWarning() << __FUNCTION__ << "Unsupported option type:" << optType;
|
qWarning() << __FUNCTION__ << "Unsupported option type:" << optType;
|
||||||
@@ -255,7 +350,7 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
|
|||||||
if (!conditions.isEmpty())
|
if (!conditions.isEmpty())
|
||||||
conditionMap.insert(optKey, conditions);
|
conditionMap.insert(optKey, conditions);
|
||||||
|
|
||||||
auto *optLabel = new QLabel(ui->optionsAreaContents);
|
auto *optLabel = new QLabel(optionsAreaContents);
|
||||||
optLabel->setText(optName);
|
optLabel->setText(optName);
|
||||||
optLabel->setToolTip(optDesc);
|
optLabel->setToolTip(optDesc);
|
||||||
optControl->setToolTip(optDesc);
|
optControl->setToolTip(optDesc);
|
||||||
@@ -356,7 +451,8 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
|
|||||||
auto &groupWidgets = widgets[i];
|
auto &groupWidgets = widgets[i];
|
||||||
auto widgetIt = groupWidgets.begin();
|
auto widgetIt = groupWidgets.begin();
|
||||||
while (widgetIt != groupWidgets.end()) {
|
while (widgetIt != groupWidgets.end()) {
|
||||||
if (widgetIt->second == condIt.value()) {
|
if (widgetIt->second == condIt.value()
|
||||||
|
&& !qobject_cast<QCheckBox *>(condIt.value())) {
|
||||||
if (widgetIt->first)
|
if (widgetIt->first)
|
||||||
widgetIt->first->hide();
|
widgetIt->first->hide();
|
||||||
groupWidgets.erase(widgetIt);
|
groupWidgets.erase(widgetIt);
|
||||||
@@ -395,6 +491,13 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
|
|||||||
incrementColIndex(col);
|
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
|
// Add option widgets to layout. Grouped options are added to the tops of the columns
|
||||||
for (int i = 1; i < widgets.size(); ++i) {
|
for (int i = 1; i < widgets.size(); ++i) {
|
||||||
int col = rowIndex[1] < rowIndex[0] ? 1 : 0;
|
int col = rowIndex[1] < rowIndex[0] ? 1 : 0;
|
||||||
@@ -406,7 +509,7 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
|
|||||||
for (int j = 1; j < groupWidgets.size(); ++j)
|
for (int j = 1; j < groupWidgets.size(); ++j)
|
||||||
insertOptionToLayout(col, groupWidgets[j]);
|
insertOptionToLayout(col, groupWidgets[j]);
|
||||||
// Add a separator line after each group
|
// Add a separator line after each group
|
||||||
auto *separator = new QFrame(ui->optionsAreaContents);
|
auto *separator = new QFrame(optionsAreaContents);
|
||||||
separator->setMaximumHeight(1);
|
separator->setMaximumHeight(1);
|
||||||
separator->setFrameShape(QFrame::HLine);
|
separator->setFrameShape(QFrame::HLine);
|
||||||
separator->setFrameShadow(QFrame::Sunken);
|
separator->setFrameShadow(QFrame::Sunken);
|
||||||
@@ -423,56 +526,40 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
|
|||||||
insertOptionToLayout(col, rowWidgets);
|
insertOptionToLayout(col, rowWidgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->optionsAreaContents->setLayout(layout);
|
int optionRows = qMax(rowIndex[0], rowIndex[1]);
|
||||||
ui->optionsAreaContents->setMinimumSize(
|
m_optionsRows = qMax(m_optionsRows, optionRows);
|
||||||
checkBoxColWidth * 2 + labelMinWidth * 2 + controlMinWidth * 2 + columnSpacing,
|
m_optionsHeight = qMax(rowHeight * optionRows + 16, m_optionsHeight);
|
||||||
rowHeight * qMax(rowIndex[0], rowIndex[1]));
|
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
|
||||||
|
|
||||||
ui->optionsArea->setStyleSheet("QScrollArea {background-color: transparent}");
|
optionsArea->setWidget(optionsAreaContents);
|
||||||
ui->optionsAreaContents->setStyleSheet(
|
optionsArea->setStyleSheet("QScrollArea {background-color: transparent}");
|
||||||
|
optionsAreaContents->setStyleSheet(
|
||||||
"QWidget#optionsAreaContents {background-color: transparent}");
|
"QWidget#optionsAreaContents {background-color: transparent}");
|
||||||
|
|
||||||
connect(ui->buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked,
|
ui->tabWidget->addTab(optionsArea, tr("%1 options").arg(tabLabel));
|
||||||
this, &ItemLibraryAssetImportDialog::onClose);
|
|
||||||
|
|
||||||
connect(&m_importer, &ItemLibraryAssetImporter::errorReported,
|
|
||||||
this, &ItemLibraryAssetImportDialog::addError);
|
|
||||||
connect(&m_importer, &ItemLibraryAssetImporter::warningReported,
|
|
||||||
this, &ItemLibraryAssetImportDialog::addWarning);
|
|
||||||
connect(&m_importer, &ItemLibraryAssetImporter::infoReported,
|
|
||||||
this, &ItemLibraryAssetImportDialog::addInfo);
|
|
||||||
connect(&m_importer, &ItemLibraryAssetImporter::importNearlyFinished,
|
|
||||||
this, &ItemLibraryAssetImportDialog::onImportNearlyFinished);
|
|
||||||
connect(&m_importer, &ItemLibraryAssetImporter::importFinished,
|
|
||||||
this, &ItemLibraryAssetImportDialog::onImportFinished);
|
|
||||||
connect(&m_importer, &ItemLibraryAssetImporter::progressChanged,
|
|
||||||
this, &ItemLibraryAssetImportDialog::setImportProgress);
|
|
||||||
|
|
||||||
addInfo(tr("Select import options and press \"Import\" to import the following files:"));
|
|
||||||
for (const auto &file : m_quick3DFiles)
|
|
||||||
addInfo(file);
|
|
||||||
|
|
||||||
QTimer::singleShot(0, [this]() {
|
|
||||||
resizeEvent(nullptr);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemLibraryAssetImportDialog::~ItemLibraryAssetImportDialog()
|
void ItemLibraryAssetImportDialog::updateUi()
|
||||||
{
|
{
|
||||||
delete ui;
|
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)
|
void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(event)
|
Q_UNUSED(event)
|
||||||
int scrollBarWidth = ui->optionsArea->verticalScrollBar()->isVisible()
|
updateUi();
|
||||||
? 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ItemLibraryAssetImportDialog::setCloseButtonState(bool importing)
|
void ItemLibraryAssetImportDialog::setCloseButtonState(bool importing)
|
||||||
@@ -504,7 +591,7 @@ void ItemLibraryAssetImportDialog::onImport()
|
|||||||
|
|
||||||
if (!m_quick3DFiles.isEmpty()) {
|
if (!m_quick3DFiles.isEmpty()) {
|
||||||
m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath,
|
m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath,
|
||||||
m_importOptions.toVariantMap());
|
m_importOptions, m_extToImportOptionsMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,4 +636,5 @@ void ItemLibraryAssetImportDialog::onClose()
|
|||||||
deleteLater();
|
deleteLater();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -66,12 +66,18 @@ private:
|
|||||||
void onImportFinished();
|
void onImportFinished();
|
||||||
void onClose();
|
void onClose();
|
||||||
|
|
||||||
|
void createTab(const QString &tabLabel, int optionsIndex, const QJsonObject &groups);
|
||||||
|
void updateUi();
|
||||||
|
|
||||||
Ui::ItemLibraryAssetImportDialog *ui = nullptr;
|
Ui::ItemLibraryAssetImportDialog *ui = nullptr;
|
||||||
Utils::OutputFormatter *m_outputFormatter = nullptr;
|
Utils::OutputFormatter *m_outputFormatter = nullptr;
|
||||||
|
|
||||||
QStringList m_quick3DFiles;
|
QStringList m_quick3DFiles;
|
||||||
QString m_quick3DImportPath;
|
QString m_quick3DImportPath;
|
||||||
ItemLibraryAssetImporter m_importer;
|
ItemLibraryAssetImporter m_importer;
|
||||||
QJsonObject m_importOptions;
|
QVector<QJsonObject> m_importOptions;
|
||||||
|
QHash<QString, int> m_extToImportOptionsMap;
|
||||||
|
int m_optionsHeight = 0;
|
||||||
|
int m_optionsRows = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>631</width>
|
<width>631</width>
|
||||||
<height>740</height>
|
<height>750</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -32,47 +32,6 @@
|
|||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Import Options</string>
|
<string>Import Options</string>
|
||||||
</attribute>
|
</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>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include <QtCore/qdir.h>
|
#include <QtCore/qdir.h>
|
||||||
#include <QtCore/qdiriterator.h>
|
#include <QtCore/qdiriterator.h>
|
||||||
#include <QtCore/qsavefile.h>
|
#include <QtCore/qsavefile.h>
|
||||||
|
#include <QtCore/qfile.h>
|
||||||
#include <QtCore/qloggingcategory.h>
|
#include <QtCore/qloggingcategory.h>
|
||||||
#include <QtCore/qtemporarydir.h>
|
#include <QtCore/qtemporarydir.h>
|
||||||
#include <QtWidgets/qapplication.h>
|
#include <QtWidgets/qapplication.h>
|
||||||
@@ -63,7 +64,8 @@ ItemLibraryAssetImporter::~ItemLibraryAssetImporter() {
|
|||||||
|
|
||||||
void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
|
void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
|
||||||
const QString &importPath,
|
const QString &importPath,
|
||||||
const QVariantMap &options)
|
const QVector<QJsonObject> &options,
|
||||||
|
const QHash<QString, int> &extToImportOptionsMap)
|
||||||
{
|
{
|
||||||
if (m_isImporting)
|
if (m_isImporting)
|
||||||
cancelImport();
|
cancelImport();
|
||||||
@@ -79,7 +81,7 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
|
|||||||
|
|
||||||
m_importPath = importPath;
|
m_importPath = importPath;
|
||||||
|
|
||||||
parseFiles(inputFiles, options);
|
parseFiles(inputFiles, options, extToImportOptionsMap);
|
||||||
|
|
||||||
if (!isCancelled()) {
|
if (!isCancelled()) {
|
||||||
// Don't allow cancel anymore as existing asset overwrites are not trivially recoverable.
|
// Don't allow cancel anymore as existing asset overwrites are not trivially recoverable.
|
||||||
@@ -221,7 +223,9 @@ void ItemLibraryAssetImporter::reset()
|
|||||||
#endif
|
#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())
|
if (isCancelled())
|
||||||
return;
|
return;
|
||||||
@@ -236,8 +240,11 @@ void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths, const QV
|
|||||||
for (const QString &file : filePaths) {
|
for (const QString &file : filePaths) {
|
||||||
if (isCancelled())
|
if (isCancelled())
|
||||||
return;
|
return;
|
||||||
if (isQuick3DAsset(file))
|
if (isQuick3DAsset(file)) {
|
||||||
parseQuick3DAsset(file, options);
|
QVariantMap varOpts;
|
||||||
|
int index = extToImportOptionsMap.value(QFileInfo(file).suffix());
|
||||||
|
parseQuick3DAsset(file, options[index].toVariantMap());
|
||||||
|
}
|
||||||
notifyProgress(qRound(++count * quota), progressTitle);
|
notifyProgress(qRound(++count * quota), progressTitle);
|
||||||
}
|
}
|
||||||
notifyProgress(100, progressTitle);
|
notifyProgress(100, progressTitle);
|
||||||
@@ -296,31 +303,70 @@ void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVar
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate qmldir file
|
// Generate qmldir file if importer doesn't already make one
|
||||||
outDir.setNameFilters({QStringLiteral("*.qml")});
|
|
||||||
const QFileInfoList qmlFiles = outDir.entryInfoList(QDir::Files);
|
|
||||||
|
|
||||||
if (!qmlFiles.isEmpty()) {
|
|
||||||
QString qmldirFileName = outDir.absoluteFilePath(QStringLiteral("qmldir"));
|
QString qmldirFileName = outDir.absoluteFilePath(QStringLiteral("qmldir"));
|
||||||
|
if (!QFileInfo(qmldirFileName).exists()) {
|
||||||
QSaveFile qmldirFile(qmldirFileName);
|
QSaveFile qmldirFile(qmldirFileName);
|
||||||
QString version = QStringLiteral("1.0");
|
QString version = QStringLiteral("1.0");
|
||||||
|
|
||||||
|
// 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)) {
|
if (qmldirFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||||
for (const auto &fi : qmlFiles) {
|
|
||||||
QString qmlInfo;
|
QString qmlInfo;
|
||||||
|
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(fi.baseName());
|
||||||
qmlInfo.append(QLatin1Char(' '));
|
qmlInfo.append(' ');
|
||||||
qmlInfo.append(version);
|
qmlInfo.append(version);
|
||||||
qmlInfo.append(QLatin1Char(' '));
|
qmlInfo.append(' ');
|
||||||
qmlInfo.append(fi.fileName());
|
qmlInfo.append(outDir.relativeFilePath(qmlIt.filePath()));
|
||||||
qmldirFile.write(qmlInfo.toUtf8());
|
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();
|
qmldirFile.commit();
|
||||||
} else {
|
} else {
|
||||||
addError(tr("Failed to create qmldir file for asset: \"%1\"").arg(assetName));
|
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();
|
const int outDirPathSize = outDir.path().size();
|
||||||
QDirIterator dirIt(outDir.path(), QDir::Files, QDirIterator::Subdirectories);
|
QDirIterator dirIt(outDir.path(), QDir::Files, QDirIterator::Subdirectories);
|
||||||
QHash<QString, QString> assetFiles;
|
QHash<QString, QString> assetFiles;
|
||||||
@@ -334,7 +380,7 @@ void ItemLibraryAssetImporter::parseQuick3DAsset(const QString &file, const QVar
|
|||||||
|
|
||||||
// Copy the original asset into a subdirectory
|
// Copy the original asset into a subdirectory
|
||||||
assetFiles.insert(sourceInfo.absoluteFilePath(),
|
assetFiles.insert(sourceInfo.absoluteFilePath(),
|
||||||
targetDirPath + QStringLiteral("/source model/") + sourceInfo.fileName());
|
targetDirPath + QStringLiteral("/source scene/") + sourceInfo.fileName());
|
||||||
m_importFiles.insert(assetFiles);
|
m_importFiles.insert(assetFiles);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
#include <QtCore/qobject.h>
|
#include <QtCore/qobject.h>
|
||||||
#include <QtCore/qstringlist.h>
|
#include <QtCore/qstringlist.h>
|
||||||
#include <QtCore/qhash.h>
|
#include <QtCore/qhash.h>
|
||||||
|
#include <QtCore/qjsonobject.h>
|
||||||
|
|
||||||
#include "import.h"
|
#include "import.h"
|
||||||
|
|
||||||
@@ -46,7 +47,8 @@ public:
|
|||||||
~ItemLibraryAssetImporter();
|
~ItemLibraryAssetImporter();
|
||||||
|
|
||||||
void importQuick3D(const QStringList &inputFiles, const QString &importPath,
|
void importQuick3D(const QStringList &inputFiles, const QString &importPath,
|
||||||
const QVariantMap &options);
|
const QVector<QJsonObject> &options,
|
||||||
|
const QHash<QString, int> &extToImportOptionsMap);
|
||||||
|
|
||||||
bool isImporting() const;
|
bool isImporting() const;
|
||||||
void cancelImport();
|
void cancelImport();
|
||||||
@@ -72,7 +74,8 @@ signals:
|
|||||||
private:
|
private:
|
||||||
void notifyFinished();
|
void notifyFinished();
|
||||||
void reset();
|
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 parseQuick3DAsset(const QString &file, const QVariantMap &options);
|
||||||
void copyImportedFiles();
|
void copyImportedFiles();
|
||||||
|
|
||||||
|
@@ -209,20 +209,28 @@ ItemLibraryWidget::ItemLibraryWidget(QWidget *parent) :
|
|||||||
QSSGAssetImportManager importManager;
|
QSSGAssetImportManager importManager;
|
||||||
QHash<QString, QStringList> supportedExtensions = importManager.getSupportedExtensions();
|
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
|
||||||
const QList<AddResourceHandler> handlers = actionManager->addResourceHandler();
|
// so we don't get multiple separate import dialogs when different file types are imported.
|
||||||
QSet<QString> handlerCats;
|
const QString category = tr("3D Assets");
|
||||||
for (const auto &h : handlers)
|
|
||||||
handlerCats.insert(h.category);
|
|
||||||
|
|
||||||
const auto categories = supportedExtensions.keys();
|
// Skip if 3D asset handlers have already been added
|
||||||
for (const auto &category : categories) {
|
const QList<AddResourceHandler> handlers = actionManager->addResourceHandler();
|
||||||
if (handlerCats.contains(category))
|
bool categoryAlreadyAdded = false;
|
||||||
continue;
|
for (const auto &handler : handlers) {
|
||||||
const auto extensions = supportedExtensions[category];
|
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)
|
for (const auto &ext : extensions)
|
||||||
add3DHandler(category, ext);
|
add3DHandler(category, ext);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// init the first load of the QML UI elements
|
// init the first load of the QML UI elements
|
||||||
|
@@ -35,6 +35,7 @@
|
|||||||
#include <coreplugin/messagebox.h>
|
#include <coreplugin/messagebox.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QDirIterator>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
@@ -387,21 +388,31 @@ void SubComponentManager::parseQuick3DAssetDir(const QString &assetPath)
|
|||||||
for (auto &import : qAsConst(m_imports)) {
|
for (auto &import : qAsConst(m_imports)) {
|
||||||
if (import.isLibraryImport() && assets.contains(import.url())) {
|
if (import.isLibraryImport() && assets.contains(import.url())) {
|
||||||
assets.removeOne(import.url());
|
assets.removeOne(import.url());
|
||||||
ItemLibraryEntry itemLibraryEntry;
|
QDirIterator qmlIt(assetDir.filePath(import.url().split('.').last()),
|
||||||
const QString name = import.url().mid(import.url().indexOf(QLatin1Char('.')) + 1);
|
{QStringLiteral("*.qml")}, QDir::Files);
|
||||||
|
while (qmlIt.hasNext()) {
|
||||||
|
qmlIt.next();
|
||||||
|
const QString name = qmlIt.fileInfo().baseName();
|
||||||
const QString type = import.url() + QLatin1Char('.') + name;
|
const QString type = import.url() + QLatin1Char('.') + name;
|
||||||
// For now we assume version is always 1.0 as that's what importer hardcodes
|
// For now we assume version is always 1.0 as that's what importer hardcodes
|
||||||
|
ItemLibraryEntry itemLibraryEntry;
|
||||||
itemLibraryEntry.setType(type.toUtf8(), 1, 0);
|
itemLibraryEntry.setType(type.toUtf8(), 1, 0);
|
||||||
itemLibraryEntry.setName(name);
|
itemLibraryEntry.setName(name);
|
||||||
itemLibraryEntry.setCategory(tr("My Quick3D Components"));
|
itemLibraryEntry.setCategory(tr("My Quick3D Components"));
|
||||||
itemLibraryEntry.setRequiredImport(import.url());
|
itemLibraryEntry.setRequiredImport(import.url());
|
||||||
itemLibraryEntry.setLibraryEntryIconPath(iconPath);
|
QString iconName = qmlIt.fileInfo().absolutePath() + '/'
|
||||||
itemLibraryEntry.setTypeIcon(QIcon(iconPath));
|
+ 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))
|
if (!model()->metaInfo().itemLibraryInfo()->containsEntry(itemLibraryEntry))
|
||||||
model()->metaInfo().itemLibraryInfo()->addEntries({itemLibraryEntry});
|
model()->metaInfo().itemLibraryInfo()->addEntries({itemLibraryEntry});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create flow tags for the rest, if they are possible imports
|
// Create flow tags for the rest, if they are possible imports
|
||||||
if (!assets.isEmpty()) {
|
if (!assets.isEmpty()) {
|
||||||
|
@@ -51,6 +51,8 @@ const char EXPORT_AS_IMAGE[] = "QmlDesigner.ExportAsImage";
|
|||||||
|
|
||||||
const char QML_DESIGNER_SUBFOLDER[] = "/designer/";
|
const char QML_DESIGNER_SUBFOLDER[] = "/designer/";
|
||||||
const char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets";
|
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 DEFAULT_ASSET_IMPORT_FOLDER[] = "/asset_imports";
|
||||||
const char QT_QUICK_3D_MODULE_NAME[] = "QtQuick3D";
|
const char QT_QUICK_3D_MODULE_NAME[] = "QtQuick3D";
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user