Skip to content

Commit c57dd21

Browse files
claudejgeudens
authored andcommitted
Fix review comments: sync/persist/tab-counter/multi-adapter issues
- adapters/json-rpc-spec.md: add comma after "Otherwise" (grammar) - schemaformwidget.cpp: derive initial conditional branch from the trigger combo's current value instead of the incoming JSON values, preventing visible/values() mismatch on first render - adaptersettings.cpp/h: remove redundant setLayout() call; extract add-tab lambda into named addItemTab() method with monotonic _nextItemTabIndex counter to avoid duplicate tab titles after a tab is closed - settingsdialog.cpp: iterate all adapters (not just the first) when building dynamic settings pages; only persist settings when dialog is accepted (gate acceptAllValues on r == QDialog::Accepted) and remove side-effectful acceptAllValues() call from settingsStackSwitch - tst_schemaformwidget.cpp: use isHidden() instead of isVisible() so the conditional-hide assertion works even when the parent is not shown https://claude.ai/code/session_013ytSJa46akaAHkox9rjeRa
1 parent ba9ec67 commit c57dd21

6 files changed

Lines changed: 46 additions & 40 deletions

File tree

adapters/json-rpc-spec.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ Each property in `schema` includes the following additional fields (standard JSO
120120
| `title` | Standard JSON Schema annotation. UI-friendly label for the field, suitable for use in form inputs and dialog labels |
121121
| `x-enumLabels` | Custom extension. Present on enum properties only. A string array, parallel to `enum`, giving a UI-friendly display name for each allowed value |
122122

123-
The connection schema uses JSON Schema Draft 7 `if`/`then`/`else` to express type-dependent fields. When `type` equals `"tcp"`, the fields in `then.properties` apply (TCP-specific). Otherwise the fields in `else.properties` apply (serial-specific). A UI can use this to enable or disable the relevant fields based on the selected connection type.
123+
The connection schema uses JSON Schema Draft 7 `if`/`then`/`else` to express type-dependent fields. When `type` equals `"tcp"`, the fields in `then.properties` apply (TCP-specific). Otherwise, the fields in `else.properties` apply (serial-specific). A UI can use this to enable or disable the relevant fields based on the selected connection type.
124124

125125
---
126126

src/customwidgets/schemaformwidget.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,20 +104,25 @@ void SchemaFormWidget::setSchema(const QJsonObject& schema, const QJsonObject& v
104104
_pFormLayout->addRow(label + ":", widget);
105105
}
106106

107-
applyConditional(values.value(_conditionalTriggerKey).toVariant().toString());
108-
107+
QComboBox* triggerCombo = nullptr;
109108
for (const auto& [key, widget] : std::as_const(_fields))
110109
{
111110
if (key == _conditionalTriggerKey)
112111
{
113-
auto* combo = qobject_cast<QComboBox*>(widget);
114-
if (combo != nullptr)
115-
{
116-
connect(combo, &QComboBox::currentIndexChanged, this, &SchemaFormWidget::onTriggerChanged);
117-
}
112+
triggerCombo = qobject_cast<QComboBox*>(widget);
118113
break;
119114
}
120115
}
116+
117+
if (triggerCombo != nullptr)
118+
{
119+
applyConditional(triggerCombo->currentData().toString());
120+
connect(triggerCombo, &QComboBox::currentIndexChanged, this, &SchemaFormWidget::onTriggerChanged);
121+
}
122+
else
123+
{
124+
applyConditional(values.value(_conditionalTriggerKey).toVariant().toString());
125+
}
121126
}
122127

123128
QWidget* SchemaFormWidget::createWidgetForProperty(const QJsonObject& propSchema, const QJsonValue& value)

src/dialogs/adaptersettings.cpp

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ AdapterSettings::AdapterSettings(SettingsModel* pSettingsModel,
1515
: QWidget(parent), _pSettingsModel(pSettingsModel), _adapterId(adapterId), _propertyKey(propertyKey)
1616
{
1717
auto* layout = new QVBoxLayout(this);
18-
setLayout(layout);
1918

2019
const AdapterData* pAdapter = pSettingsModel->adapterData(adapterId);
2120
const QJsonObject propSchema = pAdapter->schema().value("properties").toObject().value(propertyKey).toObject();
@@ -63,20 +62,9 @@ void AdapterSettings::buildSection(const QJsonObject& propSchema, const QJsonVal
6362
_pItemTabs->setTabs(pages, names);
6463
}
6564

66-
connect(_pItemTabs, &AddableTabWidget::addTabRequested, this, [this]() {
67-
auto* form = new SchemaFormWidget(_pItemTabs);
68-
QJsonObject defaultValues;
69-
const QJsonArray defaultItems =
70-
_pSettingsModel->adapterData(_adapterId)->defaults().value(_propertyKey).toArray();
71-
if (!defaultItems.isEmpty())
72-
{
73-
defaultValues = defaultItems.first().toObject();
74-
}
75-
form->setSchema(_itemSchema, defaultValues);
76-
const int newIndex = _pItemTabs->count() + 1;
77-
const QString name = QString("%1 %2").arg(_propertyKey[0].toUpper() + _propertyKey.mid(1)).arg(newIndex);
78-
_pItemTabs->addNewTab(name, form);
79-
});
65+
_nextItemTabIndex = itemsArray.size() + 1;
66+
67+
connect(_pItemTabs, &AddableTabWidget::addTabRequested, this, &AdapterSettings::addItemTab);
8068

8169
layout->addWidget(_pItemTabs, 1);
8270
}
@@ -89,6 +77,23 @@ void AdapterSettings::buildSection(const QJsonObject& propSchema, const QJsonVal
8977
}
9078
}
9179

80+
void AdapterSettings::addItemTab()
81+
{
82+
auto* form = new SchemaFormWidget(_pItemTabs);
83+
QJsonObject defaultValues;
84+
const QJsonArray defaultItems =
85+
_pSettingsModel->adapterData(_adapterId)->defaults().value(_propertyKey).toArray();
86+
if (!defaultItems.isEmpty())
87+
{
88+
defaultValues = defaultItems.first().toObject();
89+
}
90+
form->setSchema(_itemSchema, defaultValues);
91+
const QString name =
92+
QString("%1 %2").arg(_propertyKey[0].toUpper() + _propertyKey.mid(1)).arg(_nextItemTabIndex);
93+
_nextItemTabIndex++;
94+
_pItemTabs->addNewTab(name, form);
95+
}
96+
9297
void AdapterSettings::acceptValues()
9398
{
9499
QJsonObject config = _pSettingsModel->adapterData(_adapterId)->effectiveConfig();

src/dialogs/adaptersettings.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class AdapterSettings : public QWidget
4646

4747
private:
4848
void buildSection(const QJsonObject& propSchema, const QJsonValue& configValue, QVBoxLayout* layout);
49+
void addItemTab();
4950

5051
SettingsModel* _pSettingsModel;
5152
QString _adapterId;
@@ -55,6 +56,7 @@ class AdapterSettings : public QWidget
5556
SchemaFormWidget* _pForm{ nullptr };
5657

5758
QJsonObject _itemSchema;
59+
int _nextItemTabIndex{ 1 };
5860
};
5961

6062
#endif // ADAPTERSETTINGS_H

src/dialogs/settingsdialog.cpp

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,16 @@ SettingsDialog::SettingsDialog(SettingsModel* pSettingsModel, QWidget* parent)
2828
_pUi->settingsStack->removeWidget(_pUi->settingsStack->widget(0));
2929
}
3030

31-
// Find first adapter with a populated schema
32-
QString adapterId;
31+
// Build dynamic pages from schema.properties of all adapters (all keys except "devices")
3332
const QStringList adapterIds = pSettingsModel->adapterIds();
3433
for (const auto& id : adapterIds)
3534
{
36-
if (!pSettingsModel->adapterData(id)->schema().isEmpty())
35+
if (pSettingsModel->adapterData(id)->schema().isEmpty())
3736
{
38-
adapterId = id;
39-
break;
37+
continue;
4038
}
41-
}
4239

43-
// Build dynamic pages from schema.properties (all keys except "devices")
44-
if (!adapterId.isEmpty())
45-
{
46-
const QJsonObject schemaProps = pSettingsModel->adapterData(adapterId)->schema().value("properties").toObject();
40+
const QJsonObject schemaProps = pSettingsModel->adapterData(id)->schema().value("properties").toObject();
4741

4842
for (auto it = schemaProps.constBegin(); it != schemaProps.constEnd(); ++it)
4943
{
@@ -65,7 +59,7 @@ SettingsDialog::SettingsDialog(SettingsModel* pSettingsModel, QWidget* parent)
6559
listItem->setIcon(QIcon(":/menu_icon/icons/settings.svg"));
6660
_pUi->settingsList->addItem(listItem);
6761

68-
auto* page = new AdapterSettings(pSettingsModel, adapterId, key, this);
62+
auto* page = new AdapterSettings(pSettingsModel, id, key, this);
6963
_dynamicSettings.append(page);
7064
_pUi->settingsStack->addWidget(page);
7165
}
@@ -107,15 +101,15 @@ void SettingsDialog::acceptAllValues()
107101

108102
void SettingsDialog::done(int r)
109103
{
110-
Q_UNUSED(r);
111-
112-
acceptAllValues();
104+
if (r == QDialog::Accepted)
105+
{
106+
acceptAllValues();
107+
}
113108

114-
QDialog::done(QDialog::Accepted);
109+
QDialog::done(r);
115110
}
116111

117112
void SettingsDialog::settingsStackSwitch(int newRow)
118113
{
119-
acceptAllValues();
120114
_pUi->settingsStack->setCurrentIndex(newRow);
121115
}

tests/customwidgets/tst_schemaformwidget.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ void TestSchemaFormWidget::labelHiddenWithWidget()
414414
if (lbl->text() == QStringLiteral("Port Name:"))
415415
{
416416
portNameLabelFound = true;
417-
QVERIFY(!lbl->isVisible());
417+
QVERIFY(lbl->isHidden());
418418
}
419419
}
420420
QVERIFY(portNameLabelFound);

0 commit comments

Comments
 (0)