99#include < QSpinBox>
1010#include < climits>
1111#include < limits>
12+ #include < utility>
1213
1314SchemaFormWidget::SchemaFormWidget (QWidget* parent) : QWidget(parent), _pFormLayout(new QFormLayout(this ))
1415{
@@ -18,6 +19,11 @@ SchemaFormWidget::SchemaFormWidget(QWidget* parent) : QWidget(parent), _pFormLay
1819void SchemaFormWidget::setSchema (const QJsonObject& schema, const QJsonObject& values)
1920{
2021 _fields.clear ();
22+ _conditionalTriggerKey.clear ();
23+ _conditionalTriggerConst.clear ();
24+ _thenKeys.clear ();
25+ _elseKeys.clear ();
26+ _currentTriggerValue.clear ();
2127
2228 // removeRow() deletes both the label and field widget
2329 while (_pFormLayout->rowCount () > 0 )
@@ -72,6 +78,51 @@ void SchemaFormWidget::setSchema(const QJsonObject& schema, const QJsonObject& v
7278 _fields.append ({ key, widget });
7379 _pFormLayout->addRow (label + " :" , widget);
7480 }
81+
82+ if (!parseConditional (schema))
83+ {
84+ return ;
85+ }
86+
87+ const QJsonObject thenProps = schema.value (" then" ).toObject ().value (" properties" ).toObject ();
88+ for (const QString& key : std::as_const (_thenKeys))
89+ {
90+ QJsonObject propSchema = thenProps.value (key).toObject ();
91+ QString label = propSchema.value (" title" ).toString (key);
92+ QWidget* widget = createWidgetForProperty (propSchema, values.value (key));
93+ _fields.append ({ key, widget });
94+ _pFormLayout->addRow (label + " :" , widget);
95+ }
96+
97+ const QJsonObject elseProps = schema.value (" else" ).toObject ().value (" properties" ).toObject ();
98+ for (const QString& key : std::as_const (_elseKeys))
99+ {
100+ QJsonObject propSchema = elseProps.value (key).toObject ();
101+ QString label = propSchema.value (" title" ).toString (key);
102+ QWidget* widget = createWidgetForProperty (propSchema, values.value (key));
103+ _fields.append ({ key, widget });
104+ _pFormLayout->addRow (label + " :" , widget);
105+ }
106+
107+ QComboBox* triggerCombo = nullptr ;
108+ for (const auto & [key, widget] : std::as_const (_fields))
109+ {
110+ if (key == _conditionalTriggerKey)
111+ {
112+ triggerCombo = qobject_cast<QComboBox*>(widget);
113+ break ;
114+ }
115+ }
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+ }
75126}
76127
77128QWidget* SchemaFormWidget::createWidgetForProperty (const QJsonObject& propSchema, const QJsonValue& value)
@@ -155,11 +206,110 @@ QWidget* SchemaFormWidget::createWidgetForProperty(const QJsonObject& propSchema
155206 }
156207}
157208
209+ bool SchemaFormWidget::parseConditional (const QJsonObject& schema)
210+ {
211+ const QJsonObject ifObj = schema.value (" if" ).toObject ();
212+ const QJsonObject thenObj = schema.value (" then" ).toObject ();
213+ const QJsonObject elseObj = schema.value (" else" ).toObject ();
214+
215+ if (ifObj.isEmpty () || thenObj.isEmpty () || elseObj.isEmpty ())
216+ {
217+ return false ;
218+ }
219+
220+ const QJsonArray required = ifObj.value (" required" ).toArray ();
221+ if (required.size () != 1 )
222+ {
223+ return false ;
224+ }
225+
226+ const QString triggerKey = required.at (0 ).toString ();
227+ if (triggerKey.isEmpty ())
228+ {
229+ return false ;
230+ }
231+
232+ const QJsonObject ifProperties = ifObj.value (" properties" ).toObject ();
233+ const QJsonObject constObj = ifProperties.value (triggerKey).toObject ();
234+ if (!constObj.contains (" const" ))
235+ {
236+ return false ;
237+ }
238+
239+ _conditionalTriggerKey = triggerKey;
240+ _conditionalTriggerConst = constObj.value (" const" ).toVariant ().toString ();
241+
242+ const QJsonObject thenProps = thenObj.value (" properties" ).toObject ();
243+ for (auto it = thenProps.constBegin (); it != thenProps.constEnd (); ++it)
244+ {
245+ _thenKeys.append (it.key ());
246+ }
247+
248+ const QJsonObject elseProps = elseObj.value (" properties" ).toObject ();
249+ for (auto it = elseProps.constBegin (); it != elseProps.constEnd (); ++it)
250+ {
251+ _elseKeys.append (it.key ());
252+ }
253+
254+ return true ;
255+ }
256+
257+ void SchemaFormWidget::applyConditional (const QString& triggerValue)
258+ {
259+ _currentTriggerValue = triggerValue;
260+ const bool conditionMet = (triggerValue == _conditionalTriggerConst);
261+
262+ for (const auto & [key, widget] : std::as_const (_fields))
263+ {
264+ const bool isThen = _thenKeys.contains (key);
265+ const bool isElse = _elseKeys.contains (key);
266+
267+ if (!isThen && !isElse)
268+ {
269+ continue ;
270+ }
271+
272+ const bool visible = isThen ? conditionMet : !conditionMet;
273+ widget->setVisible (visible);
274+
275+ QWidget* label = _pFormLayout->labelForField (widget);
276+ if (label != nullptr )
277+ {
278+ label->setVisible (visible);
279+ }
280+ }
281+ }
282+
283+ void SchemaFormWidget::onTriggerChanged (int /* index*/ )
284+ {
285+ auto * combo = qobject_cast<QComboBox*>(sender ());
286+ if (combo == nullptr )
287+ {
288+ return ;
289+ }
290+
291+ applyConditional (combo->currentData ().toString ());
292+ }
293+
158294QJsonObject SchemaFormWidget::values () const
159295{
296+ const bool conditionMet = !_conditionalTriggerKey.isEmpty () && (_currentTriggerValue == _conditionalTriggerConst);
297+
160298 QJsonObject result;
161299 for (const auto & [key, widget] : _fields)
162300 {
301+ const bool isThen = _thenKeys.contains (key);
302+ const bool isElse = _elseKeys.contains (key);
303+
304+ if (isThen && !conditionMet)
305+ {
306+ continue ;
307+ }
308+ if (isElse && conditionMet)
309+ {
310+ continue ;
311+ }
312+
163313 if (auto * spin = qobject_cast<QSpinBox*>(widget))
164314 {
165315 result[key] = spin->value ();
0 commit comments