Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Condition on source using components #5314

Merged
merged 1 commit into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 80 additions & 35 deletions QMLComponents/controls/sourceitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,69 +517,92 @@ Terms SourceItem::_readAllTerms()
return terms;
}

Terms SourceItem::filterTermsWithCondition(ListModel* model, const Terms& terms, const QString& condition, const QVector<ConditionVariable>& conditionVariables)
Terms SourceItem::filterTermsWithCondition(ListModel* model, const Terms& terms, const QString& condition, const QVector<ConditionVariable>& conditionVariables, const QMap<QString, QStringList>& termsMap)
{
Terms filteredTerms;
JASPListControl* listControl = model->listView();
QJSEngine* jsEngine = qmlEngine(listControl);

for (const Term& term : terms)
{
QString value = term.asQString();
// There might be several original values: see jaspTestModule, "Test Sources with special attributes" analysis, "Source with controls" section
QStringList originalValues = termsMap.contains(value) ? termsMap[value] : QStringList{value};

if (conditionVariables.length() > 0)
{
// If condition variables are used, use them
for (const ConditionVariable& conditionVariable : conditionVariables)
{
JASPControl* control = model->getRowControl(term.asQString(), conditionVariable.controlName);
if (control)
QJSValue value;
for (const QString& originalValue : originalValues)
{
QJSValue value;
QVariant valueVar = control->property(conditionVariable.propertyName.toStdString().c_str());

switch (valueVar.typeId())
JASPControl* control = model->getRowControl(originalValue, conditionVariable.controlName);
if (control)
{
case QMetaType::Int:
case QMetaType::UInt: value = valueVar.toInt(); break;
case QMetaType::Double: value = valueVar.toDouble(); break;
case QMetaType::Bool: value = valueVar.toBool(); break;
default: value = valueVar.toString(); break;
}
QVariant valueVar = control->property(conditionVariable.propertyName.toStdString().c_str());

switch (valueVar.typeId())
{
case QMetaType::Int:
case QMetaType::UInt: value = valueVar.toInt(); break;
case QMetaType::Double: value = valueVar.toDouble(); break;
// If at least one of the control is true, then the condition should be true. We can think of adding an extra attribute in the source property to be able to change this rule,
// but yeah, I cannot come up already with an understandable attribute name for the user, so it means that this situation is really really peculiar.
// Again, to understand the situation, look at the jaspTestModule, "Test Sources with special attributes" analysis, "Source with controls" section
case QMetaType::Bool: value = (value.isBool() ? value.toBool() : false) || valueVar.toBool(); break;
default: value = valueVar.toString(); break;
}

jsEngine->globalObject().setProperty(conditionVariable.name, value);
}
}
jsEngine->globalObject().setProperty(conditionVariable.name, value);
}
}
else
{
// If no condition variables are used, then set the values of the row controls in variables
RowControls* rowControls = model->getRowControls(term.asQString());
if (!rowControls)
continue;
QMap<QString, QJSValue> conditionValues;

for (const QString& variable : rowControls->getJASPControlsMap().keys())
for (const QString& originalValue : originalValues)
{
JASPControl * control = rowControls->getJASPControl(variable);
BoundControl* boundControl = control ? control->boundControl() : nullptr;
RowControls* rowControls = model->getRowControls(originalValue);
if (!rowControls)
continue;

if (boundControl)
for (const QString& variable : rowControls->getJASPControlsMap().keys())
{
QJSValue value;
bool addValue = true;
const Json::Value & jsonValue = boundControl->boundValue();
JASPControl * control = rowControls->getJASPControl(variable);
BoundControl* boundControl = control ? control->boundControl() : nullptr;

switch (jsonValue.type())
if (boundControl)
{
case Json::booleanValue: value = jsonValue.asBool(); break;
case Json::uintValue: value = jsonValue.asUInt(); break;
case Json::intValue: value = jsonValue.asInt(); break;
case Json::realValue: value = jsonValue.asDouble(); break;
case Json::stringValue: value = tq(jsonValue.asString()); break;
default: addValue = false; break;
QJSValue value;
bool addValue = true;
const Json::Value & jsonValue = boundControl->boundValue();

switch (jsonValue.type())
{
case Json::booleanValue: value = jsonValue.asBool(); break;
case Json::uintValue: value = jsonValue.asUInt(); break;
case Json::intValue: value = jsonValue.asInt(); break;
case Json::realValue: value = jsonValue.asDouble(); break;
case Json::stringValue: value = tq(jsonValue.asString()); break;
default: addValue = false; break;
}

if (addValue)
{
// Same remark as above, when condition variables are used
if (value.isBool() && conditionValues.contains(variable) && conditionValues[variable].isBool())
value = value.toBool() || conditionValues[variable].toBool();
conditionValues[variable] = value;
}
}

if (addValue)
jsEngine->globalObject().setProperty(variable, value);
}

for (const QString& variable : conditionValues.keys())
jsEngine->globalObject().setProperty(variable, conditionValues[variable]);
}
}

Expand All @@ -603,7 +626,29 @@ Terms SourceItem::getTerms()
sourceTerms.discardWhatDoesContainTheseComponents(discardModel->_readAllTerms());

if (!_conditionExpression.isEmpty() && _listModel)
sourceTerms = filterTermsWithCondition(_listModel, sourceTerms, _conditionExpression, _conditionVariables);
{
QMap<QString, QStringList> map;
if (!_controlName.isEmpty()) //The sourceTerms are the values of this control, but to filter we need the values of the source
{
QStringList controlValues = sourceTerms.asQList();
for (const QString& sourceValue : _listModel->terms().asQList())
{
JASPControl* control = _listModel->getRowControl(sourceValue, _controlName);
if (control)
{
QString controlValue = control->property("value").toString();
if (controlValues.contains(controlValue))
{
QStringList list = map[controlValue];
list.push_back(sourceValue);
map[controlValue] = list;
}
}
}
}

sourceTerms = filterTermsWithCondition(_listModel, sourceTerms, _conditionExpression, _conditionVariables, map);
}

return sourceTerms;
}
Expand Down
2 changes: 1 addition & 1 deletion QMLComponents/controls/sourceitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class SourceItem : public QObject, public VariableInfoConsumer
void disconnectModels();
static QVector<SourceItem*> readAllSources(JASPListControl* _listControl);
static QList<QVariant> getListVariant(QVariant var);
static Terms filterTermsWithCondition(ListModel* model, const Terms& terms, const QString& condition, const QVector<ConditionVariable>& conditionVariables = {});
static Terms filterTermsWithCondition(ListModel* model, const Terms& terms, const QString& condition, const QVector<ConditionVariable>& conditionVariables = {}, const QMap<QString, QStringList> &termsMap = {});


private:
Expand Down
Loading