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

Add level constraints to DropDown #5708

Merged
merged 2 commits into from
Oct 17, 2024
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
2 changes: 1 addition & 1 deletion Modules/jaspTestModule
1 change: 1 addition & 0 deletions QMLComponents/components/JASP/Controls/ComboBox.qml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ ComboBoxBase
property bool showEmptyValueAsNormal: false
property bool addLineAfterEmptyValue: false
property double controlXOffset: 0
property bool alignInGroup: !setLabelAbove

onControlMinWidthChanged: _resetWidth(textMetrics.width)

Expand Down
2 changes: 1 addition & 1 deletion QMLComponents/components/JASP/Controls/GroupBox.qml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ GroupBoxBase
for (var i = 0; i < contentArea.children.length; i++)
{
var child = contentArea.children[i];
if (child.hasOwnProperty('controlType') && child.hasOwnProperty('controlXOffset'))//child.controlType === JASPControl.TextField)
if (child.hasOwnProperty('controlType') && child.hasOwnProperty('alignInGroup') && child.alignInGroup)
_allAlignableFields.push(child)
}

Expand Down
2 changes: 2 additions & 0 deletions QMLComponents/components/JASP/Controls/TextField.qml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ TextInputBase
property var undoModel

property double controlXOffset: 0
property bool alignInGroup: true


signal editingFinished() ///< To get the entered value use `displayValue` in the slot instead of `value`
signal textEdited()
Expand Down
6 changes: 6 additions & 0 deletions QMLComponents/controls/comboboxbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ void ComboBoxBase::setUp()
connect(this, &ComboBoxBase::activated, this, &ComboBoxBase::activatedSlot);
connect(this, &JASPListControl::addEmptyValueChanged, [this] () { _model->resetTermsFromSources(); } );
connect(this, &ComboBoxBase::currentIndexChanged, [this] () { _setCurrentProperties(currentIndex()); } ); // Case when currentIndex is changed in QML
connect(this, &ComboBoxBase::currentValueChanged, [this] () { if (containsVariables()) checkLevelsConstraints(); } );

if (form())
connect(form(), &AnalysisForm::languageChanged, [this] () { _model->resetTermsFromSources(); } );
Expand Down Expand Up @@ -197,6 +198,11 @@ void ComboBoxBase::activatedSlot(int index)
_setCurrentProperties(index);
}

bool ComboBoxBase::_checkLevelsConstraints()
{
return _checkLevelsConstraintsForVariable(_currentValue);
}

void ComboBoxBase::_resetItemWidth()
{
const Terms& terms = _model->terms();
Expand Down
5 changes: 4 additions & 1 deletion QMLComponents/controls/comboboxbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class ComboBoxBase : public JASPListControl, public BoundControlBase
void fixedWidthChanged();

protected slots:
void termsChangedHandler() override;
void termsChangedHandler() override;
void setCurrentIndex(int index);
void setCurrentValue(QString value);
void setCurrentText(QString text);
Expand All @@ -82,6 +82,9 @@ protected slots:
GENERIC_SET_FUNCTION(StartValue, _startValue, startValueChanged, QString )

protected:
bool _checkLevelsConstraints() override;


ListModelLabelValueTerms* _model = nullptr;
QString _currentText,
_currentValue,
Expand Down
125 changes: 72 additions & 53 deletions QMLComponents/controls/jasplistcontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,11 @@ void JASPListControl::setContainsInteractions()

void JASPListControl::termsChangedHandler()
{
setColumnsTypes(model()->termsTypes());
setColumnsNames(model()->terms().asQList());
if (checkLevelsConstraints())
{
setColumnsTypes(model()->termsTypes());
setColumnsNames(model()->terms().asQList());
}
}

void JASPListControl::_termsChangedHandler()
Expand Down Expand Up @@ -180,8 +183,9 @@ void JASPListControl::setUp()
connect(this, &JASPListControl::minNumericLevelsChanged, this, &JASPListControl::checkLevelsConstraints );
connect(DesktopCommunicator::singleton(), &DesktopCommunicator::currentJaspThemeChanged, this, &JASPListControl::_setAllowedVariables );
connect(this, &JASPListControl::allowedColumnsChanged, this, &JASPListControl::_setAllowedVariables );


connect(listModel, &ListModelDraggable::termsChanged, this, &JASPListControl::levelsChanged );
connect(listModel, &ListModelDraggable::filterChanged, this, &JASPListControl::levelsChanged );
connect(listModel, &ListModelDraggable::filterChanged, this, &JASPListControl::checkLevelsConstraints, Qt::QueuedConnection );
}

void JASPListControl::cleanUp()
Expand Down Expand Up @@ -332,66 +336,81 @@ columnType JASPListControl::defaultType() const
return _allowedTypesModel->defaultType();
}

void JASPListControl::checkLevelsConstraints()

bool JASPListControl::_checkLevelsConstraintsForVariable(const QString& variable)
{
JASPListControl::termsChangedHandler();
if (variable.isEmpty())
return true;

bool noScaleAllowed = !_allowedTypesModel->hasType(columnType::scale);
columnType type = (columnType)model()->requestInfo(VariableInfo::VariableType, variable).toInt();
if (type == columnType::unknown)
return true;

if (_minLevels >= 0 || _maxLevels >= 0 || _minNumericLevels >= 0 || _maxNumericLevels >= 0 || noScaleAllowed)
int nbLevels = model()->requestInfo(VariableInfo::TotalLevels, variable).toInt(),
nbNumValues = model()->requestInfo(VariableInfo::TotalNumericValues, variable).toInt(),
maxScaleLevels = PreferencesModelBase::preferences()->maxScaleLevels();
bool noScaleAllowed = !_allowedTypesModel->hasType(columnType::scale);

if (_minLevels >= 0 && nbLevels < _minLevels)
{
addControlErrorPermanent(tr("Minimum number of levels is %1. Variable %2 has only %3 levels").arg(_minLevels).arg(variable).arg(nbLevels));
return false;
}
else if (_maxLevels >= 0 && nbLevels > _maxLevels)
{
addControlErrorPermanent(tr("Maximum number of levels is %1. Variable %2 has %3 levels.").arg(_maxLevels).arg(variable).arg(nbLevels));
return false;
}
else if (_maxLevels < 0 && noScaleAllowed && type == columnType::scale && nbLevels > maxScaleLevels)
{
// This is the case when a scale variable is transformed into a nominal or ordinal, and the variable has more than the default maximum number of levels
// This should not be checked if maxLevels is explicitly set (that is if _maxLevels >= 0)
addControlErrorPermanent(tr("Attempt to transform scale variable %1 into a %2 variable, but its number of levels %3 exceeds the maximum %4. If you still want to use this variable, either change its type, or change 'Maximum allowed levels for scale' in Preferences / Data menu")
.arg(variable).arg(columnTypeToQString(_allowedTypesModel->defaultType())).arg(nbLevels).arg(maxScaleLevels));
return false;
}
else if (_minNumericLevels >= 0 && nbNumValues < _minNumericLevels)
{
addControlErrorPermanent(tr("Minimum number of numeric values is %1. Variable %2 has only %3 different numeric values").arg(_minNumericLevels).arg(variable).arg(nbNumValues));
return false;
}
else if (_maxNumericLevels >= 0 && nbNumValues > _maxNumericLevels)
{
bool hasError = false;
int maxScaleLevels = PreferencesModelBase::preferences()->maxScaleLevels();
addControlErrorPermanent(tr("Maximum number of numeric values is %1. Variable %2 has %3 different numeric values").arg(_maxNumericLevels).arg(variable).arg(nbNumValues));
return false;
}

return true;
}

bool JASPListControl::_checkLevelsConstraints()
{
bool checked = true;

for (const Term& term : model()->terms())
for (const Term& term : model()->terms())
{
if (!_checkLevelsConstraintsForVariable(term.asQString()))
{
QString termStr = term.asQString();
if (termStr.isEmpty())
continue;
checked = false;
break;
}
}

columnType termType = (columnType)model()->requestInfo(VariableInfo::VariableType, termStr).toInt();
if (termType == columnType::unknown)
continue;
return checked;
}

int nbLevels = model()->requestInfo(VariableInfo::TotalLevels, termStr).toInt(),
nbNumValues = model()->requestInfo(VariableInfo::TotalNumericValues, termStr).toInt();
bool JASPListControl::checkLevelsConstraints()
{
bool checked = true,
noScaleAllowed = !_allowedTypesModel->hasType(columnType::scale);

if (_minLevels >= 0 && nbLevels < _minLevels)
{
addControlErrorPermanent(tr("Minimum number of levels is %1. Variable %2 has only %3 levels").arg(_minLevels).arg(termStr).arg(nbLevels));
hasError = true;
}
else if (_maxLevels >= 0 && nbLevels > _maxLevels)
{
addControlErrorPermanent(tr("Maximum number of levels is %1. Variable %2 has %3 levels.").arg(_maxLevels).arg(termStr).arg(nbLevels));
hasError = true;
}
else if (_maxLevels < 0 && noScaleAllowed && termType == columnType::scale && nbLevels > maxScaleLevels)
{
// This is the case when a scale variable is transformed into a nominal or ordinal, and the variable has more than the default maximum number of levels
// This should not be checked if maxLevels is explicitly set (that is if _maxLevels >= 0)
addControlErrorPermanent(tr("Attempt to transform scale variable %1 into a %2 variable, but its number of levels %3 exceeds the maximum %4. If you still want to use this variable, either change its type, or change 'Maximum allowed levels for scale' in Preferences / Data menu")
.arg(termStr).arg(columnTypeToQString(_allowedTypesModel->defaultType())).arg(nbLevels).arg(maxScaleLevels));
hasError = true;
}
else if (_minNumericLevels >= 0 && nbNumValues < _minNumericLevels)
{
addControlErrorPermanent(tr("Minimum number of numeric values is %1. Variable %2 has only %3 different numeric values").arg(_minNumericLevels).arg(termStr).arg(nbNumValues));
hasError = true;
}
else if (_maxNumericLevels >= 0 && nbNumValues > _maxNumericLevels)
{
addControlErrorPermanent(tr("Maximum number of numeric values is %1. Variable %2 has %3 different numeric values").arg(_maxNumericLevels).arg(termStr).arg(nbNumValues));
hasError = true;
}
if (_minLevels >= 0 || _maxLevels >= 0 || _minNumericLevels >= 0 || _maxNumericLevels >= 0 || noScaleAllowed)
checked = _checkLevelsConstraints();

if (hasError)
break;
}
if (checked)
clearControlError();

if (!hasError)
clearControlError();
}
return checked;
}

QStringList JASPListControl::levels() const
Expand Down
4 changes: 3 additions & 1 deletion QMLComponents/controls/jasplistcontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,13 @@ protected slots:
void sourceChangedHandler();

void setOptionKey(const QString& optionKey) { _optionKey = optionKey; }
void checkLevelsConstraints();
bool checkLevelsConstraints();

protected:
void _setInitialized(const Json::Value& value = Json::nullValue) override;
void _setAllowedVariables();
virtual bool _checkLevelsConstraints();
bool _checkLevelsConstraintsForVariable(const QString& variable);

GENERIC_SET_FUNCTION(Source, _source, sourceChanged, QVariant )
GENERIC_SET_FUNCTION(RSource, _rSource, sourceChanged, QVariant )
Expand Down
8 changes: 1 addition & 7 deletions QMLComponents/controls/variableslistbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,6 @@ void VariablesListBase::setUp()
//We use macros here because the signals come from QML
QQuickItem::connect(this, SIGNAL(itemDoubleClicked(int)), this, SLOT(itemDoubleClickedHandler(int)));
QQuickItem::connect(this, SIGNAL(itemsDropped(QVariant, QVariant, int)), this, SLOT(itemsDroppedHandler(QVariant, QVariant, int)));
connect(_draggableModel, &ListModelDraggable::termsChanged, this, &VariablesListBase::levelsChanged );
connect(_draggableModel, &ListModelDraggable::filterChanged, this, &VariablesListBase::levelsChanged );
connect(_draggableModel, &ListModelDraggable::filterChanged, this, &VariablesListBase::checkLevelsConstraints );
}

void VariablesListBase::_setInitialized(const Json::Value &value)
Expand Down Expand Up @@ -309,10 +306,7 @@ void VariablesListBase::setVariableType(int index, int type)

void VariablesListBase::termsChangedHandler()
{
setColumnsTypes(model()->termsTypes());
setColumnsNames(model()->terms().asQList());

checkLevelsConstraints();
JASPListControl::termsChangedHandler();

if (_boundControl) _boundControl->resetBoundValue();
}
Expand Down
Loading