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,46 @@ 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+ applyConditional (values.value (_conditionalTriggerKey).toString ());
108+
109+ for (const auto & [key, widget] : std::as_const (_fields))
110+ {
111+ if (key == _conditionalTriggerKey)
112+ {
113+ auto * combo = qobject_cast<QComboBox*>(widget);
114+ if (combo != nullptr )
115+ {
116+ connect (combo, &QComboBox::currentIndexChanged, this , &SchemaFormWidget::onTriggerChanged);
117+ }
118+ break ;
119+ }
120+ }
75121}
76122
77123QWidget* SchemaFormWidget::createWidgetForProperty (const QJsonObject& propSchema, const QJsonValue& value)
@@ -155,11 +201,110 @@ QWidget* SchemaFormWidget::createWidgetForProperty(const QJsonObject& propSchema
155201 }
156202}
157203
204+ bool SchemaFormWidget::parseConditional (const QJsonObject& schema)
205+ {
206+ const QJsonObject ifObj = schema.value (" if" ).toObject ();
207+ const QJsonObject thenObj = schema.value (" then" ).toObject ();
208+ const QJsonObject elseObj = schema.value (" else" ).toObject ();
209+
210+ if (ifObj.isEmpty () || thenObj.isEmpty () || elseObj.isEmpty ())
211+ {
212+ return false ;
213+ }
214+
215+ const QJsonArray required = ifObj.value (" required" ).toArray ();
216+ if (required.size () != 1 )
217+ {
218+ return false ;
219+ }
220+
221+ const QString triggerKey = required.at (0 ).toString ();
222+ if (triggerKey.isEmpty ())
223+ {
224+ return false ;
225+ }
226+
227+ const QJsonObject ifProperties = ifObj.value (" properties" ).toObject ();
228+ const QJsonObject constObj = ifProperties.value (triggerKey).toObject ();
229+ if (!constObj.contains (" const" ))
230+ {
231+ return false ;
232+ }
233+
234+ _conditionalTriggerKey = triggerKey;
235+ _conditionalTriggerConst = constObj.value (" const" ).toString ();
236+
237+ const QJsonObject thenProps = thenObj.value (" properties" ).toObject ();
238+ for (auto it = thenProps.constBegin (); it != thenProps.constEnd (); ++it)
239+ {
240+ _thenKeys.append (it.key ());
241+ }
242+
243+ const QJsonObject elseProps = elseObj.value (" properties" ).toObject ();
244+ for (auto it = elseProps.constBegin (); it != elseProps.constEnd (); ++it)
245+ {
246+ _elseKeys.append (it.key ());
247+ }
248+
249+ return true ;
250+ }
251+
252+ void SchemaFormWidget::applyConditional (const QString& triggerValue)
253+ {
254+ _currentTriggerValue = triggerValue;
255+ const bool conditionMet = (triggerValue == _conditionalTriggerConst);
256+
257+ for (const auto & [key, widget] : std::as_const (_fields))
258+ {
259+ const bool isThen = _thenKeys.contains (key);
260+ const bool isElse = _elseKeys.contains (key);
261+
262+ if (!isThen && !isElse)
263+ {
264+ continue ;
265+ }
266+
267+ const bool visible = isThen ? conditionMet : !conditionMet;
268+ widget->setVisible (visible);
269+
270+ QWidget* label = _pFormLayout->labelForField (widget);
271+ if (label != nullptr )
272+ {
273+ label->setVisible (visible);
274+ }
275+ }
276+ }
277+
278+ void SchemaFormWidget::onTriggerChanged (int /* index*/ )
279+ {
280+ auto * combo = qobject_cast<QComboBox*>(sender ());
281+ if (combo == nullptr )
282+ {
283+ return ;
284+ }
285+
286+ applyConditional (combo->currentData ().toString ());
287+ }
288+
158289QJsonObject SchemaFormWidget::values () const
159290{
291+ const bool conditionMet = !_conditionalTriggerKey.isEmpty () && (_currentTriggerValue == _conditionalTriggerConst);
292+
160293 QJsonObject result;
161294 for (const auto & [key, widget] : _fields)
162295 {
296+ const bool isThen = _thenKeys.contains (key);
297+ const bool isElse = _elseKeys.contains (key);
298+
299+ if (isThen && !conditionMet)
300+ {
301+ continue ;
302+ }
303+ if (isElse && conditionMet)
304+ {
305+ continue ;
306+ }
307+
163308 if (auto * spin = qobject_cast<QSpinBox*>(widget))
164309 {
165310 result[key] = spin->value ();
0 commit comments