Skip to content

Commit b7465c2

Browse files
authored
Add level constraints to DropDown (#5708)
* Add level constraints to DropDown * Update jaspTestModule
1 parent 818c9db commit b7465c2

File tree

9 files changed

+91
-64
lines changed

9 files changed

+91
-64
lines changed

QMLComponents/components/JASP/Controls/ComboBox.qml

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ ComboBoxBase
2929
property bool showEmptyValueAsNormal: false
3030
property bool addLineAfterEmptyValue: false
3131
property double controlXOffset: 0
32+
property bool alignInGroup: !setLabelAbove
3233

3334
onControlMinWidthChanged: _resetWidth(textMetrics.width)
3435

QMLComponents/components/JASP/Controls/GroupBox.qml

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ GroupBoxBase
105105
for (var i = 0; i < contentArea.children.length; i++)
106106
{
107107
var child = contentArea.children[i];
108-
if (child.hasOwnProperty('controlType') && child.hasOwnProperty('controlXOffset'))//child.controlType === JASPControl.TextField)
108+
if (child.hasOwnProperty('controlType') && child.hasOwnProperty('alignInGroup') && child.alignInGroup)
109109
_allAlignableFields.push(child)
110110
}
111111

QMLComponents/components/JASP/Controls/TextField.qml

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ TextInputBase
5151
property var undoModel
5252

5353
property double controlXOffset: 0
54+
property bool alignInGroup: true
55+
5456

5557
signal editingFinished() ///< To get the entered value use `displayValue` in the slot instead of `value`
5658
signal textEdited()

QMLComponents/controls/comboboxbase.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ void ComboBoxBase::setUp()
148148
connect(this, &ComboBoxBase::activated, this, &ComboBoxBase::activatedSlot);
149149
connect(this, &JASPListControl::addEmptyValueChanged, [this] () { _model->resetTermsFromSources(); } );
150150
connect(this, &ComboBoxBase::currentIndexChanged, [this] () { _setCurrentProperties(currentIndex()); } ); // Case when currentIndex is changed in QML
151+
connect(this, &ComboBoxBase::currentValueChanged, [this] () { if (containsVariables()) checkLevelsConstraints(); } );
151152

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

201+
bool ComboBoxBase::_checkLevelsConstraints()
202+
{
203+
return _checkLevelsConstraintsForVariable(_currentValue);
204+
}
205+
200206
void ComboBoxBase::_resetItemWidth()
201207
{
202208
const Terms& terms = _model->terms();

QMLComponents/controls/comboboxbase.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class ComboBoxBase : public JASPListControl, public BoundControlBase
7373
void fixedWidthChanged();
7474

7575
protected slots:
76-
void termsChangedHandler() override;
76+
void termsChangedHandler() override;
7777
void setCurrentIndex(int index);
7878
void setCurrentValue(QString value);
7979
void setCurrentText(QString text);
@@ -82,6 +82,9 @@ protected slots:
8282
GENERIC_SET_FUNCTION(StartValue, _startValue, startValueChanged, QString )
8383

8484
protected:
85+
bool _checkLevelsConstraints() override;
86+
87+
8588
ListModelLabelValueTerms* _model = nullptr;
8689
QString _currentText,
8790
_currentValue,

QMLComponents/controls/jasplistcontrol.cpp

+72-53
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,11 @@ void JASPListControl::setContainsInteractions()
143143

144144
void JASPListControl::termsChangedHandler()
145145
{
146-
setColumnsTypes(model()->termsTypes());
147-
setColumnsNames(model()->terms().asQList());
146+
if (checkLevelsConstraints())
147+
{
148+
setColumnsTypes(model()->termsTypes());
149+
setColumnsNames(model()->terms().asQList());
150+
}
148151
}
149152

150153
void JASPListControl::_termsChangedHandler()
@@ -180,8 +183,9 @@ void JASPListControl::setUp()
180183
connect(this, &JASPListControl::minNumericLevelsChanged, this, &JASPListControl::checkLevelsConstraints );
181184
connect(DesktopCommunicator::singleton(), &DesktopCommunicator::currentJaspThemeChanged, this, &JASPListControl::_setAllowedVariables );
182185
connect(this, &JASPListControl::allowedColumnsChanged, this, &JASPListControl::_setAllowedVariables );
183-
184-
186+
connect(listModel, &ListModelDraggable::termsChanged, this, &JASPListControl::levelsChanged );
187+
connect(listModel, &ListModelDraggable::filterChanged, this, &JASPListControl::levelsChanged );
188+
connect(listModel, &ListModelDraggable::filterChanged, this, &JASPListControl::checkLevelsConstraints, Qt::QueuedConnection );
185189
}
186190

187191
void JASPListControl::cleanUp()
@@ -332,66 +336,81 @@ columnType JASPListControl::defaultType() const
332336
return _allowedTypesModel->defaultType();
333337
}
334338

335-
void JASPListControl::checkLevelsConstraints()
339+
340+
bool JASPListControl::_checkLevelsConstraintsForVariable(const QString& variable)
336341
{
337-
JASPListControl::termsChangedHandler();
342+
if (variable.isEmpty())
343+
return true;
338344

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

341-
if (_minLevels >= 0 || _maxLevels >= 0 || _minNumericLevels >= 0 || _maxNumericLevels >= 0 || noScaleAllowed)
349+
int nbLevels = model()->requestInfo(VariableInfo::TotalLevels, variable).toInt(),
350+
nbNumValues = model()->requestInfo(VariableInfo::TotalNumericValues, variable).toInt(),
351+
maxScaleLevels = PreferencesModelBase::preferences()->maxScaleLevels();
352+
bool noScaleAllowed = !_allowedTypesModel->hasType(columnType::scale);
353+
354+
if (_minLevels >= 0 && nbLevels < _minLevels)
355+
{
356+
addControlErrorPermanent(tr("Minimum number of levels is %1. Variable %2 has only %3 levels").arg(_minLevels).arg(variable).arg(nbLevels));
357+
return false;
358+
}
359+
else if (_maxLevels >= 0 && nbLevels > _maxLevels)
360+
{
361+
addControlErrorPermanent(tr("Maximum number of levels is %1. Variable %2 has %3 levels.").arg(_maxLevels).arg(variable).arg(nbLevels));
362+
return false;
363+
}
364+
else if (_maxLevels < 0 && noScaleAllowed && type == columnType::scale && nbLevels > maxScaleLevels)
365+
{
366+
// 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
367+
// This should not be checked if maxLevels is explicitly set (that is if _maxLevels >= 0)
368+
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")
369+
.arg(variable).arg(columnTypeToQString(_allowedTypesModel->defaultType())).arg(nbLevels).arg(maxScaleLevels));
370+
return false;
371+
}
372+
else if (_minNumericLevels >= 0 && nbNumValues < _minNumericLevels)
373+
{
374+
addControlErrorPermanent(tr("Minimum number of numeric values is %1. Variable %2 has only %3 different numeric values").arg(_minNumericLevels).arg(variable).arg(nbNumValues));
375+
return false;
376+
}
377+
else if (_maxNumericLevels >= 0 && nbNumValues > _maxNumericLevels)
342378
{
343-
bool hasError = false;
344-
int maxScaleLevels = PreferencesModelBase::preferences()->maxScaleLevels();
379+
addControlErrorPermanent(tr("Maximum number of numeric values is %1. Variable %2 has %3 different numeric values").arg(_maxNumericLevels).arg(variable).arg(nbNumValues));
380+
return false;
381+
}
382+
383+
return true;
384+
}
385+
386+
bool JASPListControl::_checkLevelsConstraints()
387+
{
388+
bool checked = true;
345389

346-
for (const Term& term : model()->terms())
390+
for (const Term& term : model()->terms())
391+
{
392+
if (!_checkLevelsConstraintsForVariable(term.asQString()))
347393
{
348-
QString termStr = term.asQString();
349-
if (termStr.isEmpty())
350-
continue;
394+
checked = false;
395+
break;
396+
}
397+
}
351398

352-
columnType termType = (columnType)model()->requestInfo(VariableInfo::VariableType, termStr).toInt();
353-
if (termType == columnType::unknown)
354-
continue;
399+
return checked;
400+
}
355401

356-
int nbLevels = model()->requestInfo(VariableInfo::TotalLevels, termStr).toInt(),
357-
nbNumValues = model()->requestInfo(VariableInfo::TotalNumericValues, termStr).toInt();
402+
bool JASPListControl::checkLevelsConstraints()
403+
{
404+
bool checked = true,
405+
noScaleAllowed = !_allowedTypesModel->hasType(columnType::scale);
358406

359-
if (_minLevels >= 0 && nbLevels < _minLevels)
360-
{
361-
addControlErrorPermanent(tr("Minimum number of levels is %1. Variable %2 has only %3 levels").arg(_minLevels).arg(termStr).arg(nbLevels));
362-
hasError = true;
363-
}
364-
else if (_maxLevels >= 0 && nbLevels > _maxLevels)
365-
{
366-
addControlErrorPermanent(tr("Maximum number of levels is %1. Variable %2 has %3 levels.").arg(_maxLevels).arg(termStr).arg(nbLevels));
367-
hasError = true;
368-
}
369-
else if (_maxLevels < 0 && noScaleAllowed && termType == columnType::scale && nbLevels > maxScaleLevels)
370-
{
371-
// 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
372-
// This should not be checked if maxLevels is explicitly set (that is if _maxLevels >= 0)
373-
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")
374-
.arg(termStr).arg(columnTypeToQString(_allowedTypesModel->defaultType())).arg(nbLevels).arg(maxScaleLevels));
375-
hasError = true;
376-
}
377-
else if (_minNumericLevels >= 0 && nbNumValues < _minNumericLevels)
378-
{
379-
addControlErrorPermanent(tr("Minimum number of numeric values is %1. Variable %2 has only %3 different numeric values").arg(_minNumericLevels).arg(termStr).arg(nbNumValues));
380-
hasError = true;
381-
}
382-
else if (_maxNumericLevels >= 0 && nbNumValues > _maxNumericLevels)
383-
{
384-
addControlErrorPermanent(tr("Maximum number of numeric values is %1. Variable %2 has %3 different numeric values").arg(_maxNumericLevels).arg(termStr).arg(nbNumValues));
385-
hasError = true;
386-
}
407+
if (_minLevels >= 0 || _maxLevels >= 0 || _minNumericLevels >= 0 || _maxNumericLevels >= 0 || noScaleAllowed)
408+
checked = _checkLevelsConstraints();
387409

388-
if (hasError)
389-
break;
390-
}
410+
if (checked)
411+
clearControlError();
391412

392-
if (!hasError)
393-
clearControlError();
394-
}
413+
return checked;
395414
}
396415

397416
QStringList JASPListControl::levels() const

QMLComponents/controls/jasplistcontrol.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,13 @@ protected slots:
158158
void sourceChangedHandler();
159159

160160
void setOptionKey(const QString& optionKey) { _optionKey = optionKey; }
161-
void checkLevelsConstraints();
161+
bool checkLevelsConstraints();
162162

163163
protected:
164164
void _setInitialized(const Json::Value& value = Json::nullValue) override;
165165
void _setAllowedVariables();
166+
virtual bool _checkLevelsConstraints();
167+
bool _checkLevelsConstraintsForVariable(const QString& variable);
166168

167169
GENERIC_SET_FUNCTION(Source, _source, sourceChanged, QVariant )
168170
GENERIC_SET_FUNCTION(RSource, _rSource, sourceChanged, QVariant )

QMLComponents/controls/variableslistbase.cpp

+1-7
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,6 @@ void VariablesListBase::setUp()
8181
//We use macros here because the signals come from QML
8282
QQuickItem::connect(this, SIGNAL(itemDoubleClicked(int)), this, SLOT(itemDoubleClickedHandler(int)));
8383
QQuickItem::connect(this, SIGNAL(itemsDropped(QVariant, QVariant, int)), this, SLOT(itemsDroppedHandler(QVariant, QVariant, int)));
84-
connect(_draggableModel, &ListModelDraggable::termsChanged, this, &VariablesListBase::levelsChanged );
85-
connect(_draggableModel, &ListModelDraggable::filterChanged, this, &VariablesListBase::levelsChanged );
86-
connect(_draggableModel, &ListModelDraggable::filterChanged, this, &VariablesListBase::checkLevelsConstraints );
8784
}
8885

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

310307
void VariablesListBase::termsChangedHandler()
311308
{
312-
setColumnsTypes(model()->termsTypes());
313-
setColumnsNames(model()->terms().asQList());
314-
315-
checkLevelsConstraints();
309+
JASPListControl::termsChangedHandler();
316310

317311
if (_boundControl) _boundControl->resetBoundValue();
318312
}

0 commit comments

Comments
 (0)