aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-10-02 15:35:43 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-10-04 11:30:35 +0000
commitf58dca918f12c118046f4f498b05e42da4974607 (patch)
treed41535c2433fc1681cd43163f5d3ad43bccedae4 /src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
parenta0f3ce69bd20aeb77f76186a7773c4b4af5bf984 (diff)
Add import options to asset import dialog
Available import options are queried from the importer and displayed on the import dialog. Change-Id: Id47dde29f41a1c91042623ebbd1156c77434e3a3 Fixes: QDS-1101 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Diffstat (limited to 'src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp')
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp270
1 files changed, 258 insertions, 12 deletions
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
index 0917a22abd..5f72ef3750 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp
@@ -30,15 +30,20 @@
#include "model.h"
#include "utils/outputformatter.h"
+#include "theme.h"
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qtimer.h>
+#include <QtCore/qjsonarray.h>
#include <QtWidgets/qpushbutton.h>
-#include <QtWidgets/qformlayout.h>
+#include <QtWidgets/qgridlayout.h>
#include <QtWidgets/qlabel.h>
+#include <QtWidgets/qcheckbox.h>
+#include <QtWidgets/qspinbox.h>
#include <QtWidgets/qscrollbar.h>
+#include <QtWidgets/qtabbar.h>
namespace QmlDesigner {
@@ -83,8 +88,6 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
if (skipSome)
addWarning("Cannot import 3D and other assets simultaneously. Skipping non-3D assets.");
- // Import button will be used in near future when we add import options. Hide for now.
- ui->buttonBox->button(QDialogButtonBox::Ok)->hide();
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Import"));
connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked,
this, &ItemLibraryAssetImportDialog::onImport);
@@ -137,8 +140,236 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
}
m_quick3DImportPath = candidatePath;
- // Queue import immediately until we have some options
- QTimer::singleShot(0, this, &ItemLibraryAssetImportDialog::onImport);
+ // 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 labelWidth = 210;
+ const int valueWidth = 75;
+ const int groupIndent = 10;
+ const int columnSpacing = 10;
+ 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<QString, QString> optionToGroupMap;
+
+ auto layout = new QGridLayout(ui->optionsAreaContents);
+ layout->setColumnMinimumWidth(0, groupIndent);
+ layout->setColumnMinimumWidth(1, labelWidth);
+ layout->setColumnMinimumWidth(2, valueWidth);
+ layout->setColumnMinimumWidth(3, columnSpacing);
+ layout->setColumnMinimumWidth(4, groupIndent);
+ layout->setColumnMinimumWidth(5, labelWidth);
+ layout->setColumnMinimumWidth(6, valueWidth);
+
+ 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);
+ }
+
+ 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;
+ }
+
+ }
+ optSpin->setRange(min, max);
+ optSpin->setDecimals(decimals);
+ optSpin->setValue(optValue.toDouble());
+ optSpin->setSingleStep(step);
+ 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;
+ }
+
+ 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});
+ }
+
+ // 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);
+ layout->setRowMinimumHeight(rowIndex[col],rowHeight);
+ ++rowIndex[col];
+ for (int j = 1; j < groupWidgets.size(); ++j) {
+ layout->addWidget(groupWidgets[j].first, rowIndex[col], col * 4 + 1);
+ layout->addWidget(groupWidgets[j].second, rowIndex[col], col * 4 + 2);
+ layout->setRowMinimumHeight(rowIndex[col],rowHeight);
+ ++rowIndex[col];
+ }
+ }
+ }
+
+ // Ungrouped options are spread evenly under the groups
+ int totalRowCount = (rowIndex[0] + rowIndex[1] + widgets[0].size() + 1) / 2;
+ for (const auto &widgets : qAsConst(widgets[0])) {
+ int col = rowIndex[0] < totalRowCount ? 0 : 1;
+ layout->addWidget(widgets.first, rowIndex[col], col * 4, 1, 2);
+ layout->addWidget(widgets.second, rowIndex[col], col * 4 + 2);
+ layout->setRowMinimumHeight(rowIndex[col],rowHeight);
+ ++rowIndex[col];
+ }
+
+ // Handle conditions
+ QHash<QString, QJsonArray>::const_iterator it = conditionMap.begin();
+ while (it != conditionMap.end()) {
+ 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);
+ 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->optionsAreaContents->setLayout(layout);
+ ui->optionsAreaContents->resize(
+ groupIndent * 2 + labelWidth * 2 + valueWidth * 2 + columnSpacing,
+ rowHeight * qMax(rowIndex[0], rowIndex[1]));
+ }
+
+ 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);
@@ -155,6 +386,10 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im
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);
}
ItemLibraryAssetImportDialog::~ItemLibraryAssetImportDialog()
@@ -162,9 +397,18 @@ ItemLibraryAssetImportDialog::~ItemLibraryAssetImportDialog()
delete ui;
}
-void ItemLibraryAssetImportDialog::setImportUiState(bool importing)
+void ItemLibraryAssetImportDialog::resizeEvent(QResizeEvent *event)
+{
+ Q_UNUSED(event)
+ int scrollBarHeight = ui->optionsArea->horizontalScrollBar()->isVisible()
+ ? ui->optionsArea->horizontalScrollBar()->height() : 0;
+ ui->tabWidget->setMaximumHeight(ui->optionsAreaContents->height() + scrollBarHeight
+ + ui->tabWidget->tabBar()->height() + 8);
+ ui->optionsArea->resize(ui->tabWidget->currentWidget()->size());
+}
+
+void ItemLibraryAssetImportDialog::setCloseButtonState(bool importing)
{
- ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!importing);
ui->buttonBox->button(QDialogButtonBox::Close)->setEnabled(true);
ui->buttonBox->button(QDialogButtonBox::Close)->setText(importing ? tr("Cancel") : tr("Close"));
}
@@ -186,12 +430,14 @@ void ItemLibraryAssetImportDialog::addInfo(const QString &info, const QString &s
void ItemLibraryAssetImportDialog::onImport()
{
- setImportUiState(true);
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+ setCloseButtonState(true);
ui->progressBar->setValue(0);
- ui->plainTextEdit->clear();
- if (!m_quick3DFiles.isEmpty())
- m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath);
+ if (!m_quick3DFiles.isEmpty()) {
+ m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath,
+ m_importOptions.toVariantMap());
+ }
}
void ItemLibraryAssetImportDialog::setImportProgress(int value, const QString &text)
@@ -212,7 +458,7 @@ void ItemLibraryAssetImportDialog::onImportNearlyFinished()
void ItemLibraryAssetImportDialog::onImportFinished()
{
- setImportUiState(false);
+ setCloseButtonState(false);
if (m_importer.isCancelled()) {
QString interruptStr = tr("Import interrupted.");
addError(interruptStr);