Skip to content

Commit

Permalink
Add not null constraint and visual feedback to widgets
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn authored and pblottiere committed May 31, 2016
1 parent fda06c0 commit 4ae1b55
Show file tree
Hide file tree
Showing 21 changed files with 254 additions and 32 deletions.
11 changes: 10 additions & 1 deletion python/core/qgseditformconfig.sip
Expand Up @@ -474,7 +474,16 @@ class QgsEditFormConfig : QObject
/** /**
* If set to false, the widget at the given index will be read-only. * If set to false, the widget at the given index will be read-only.
*/ */
void setReadOnly(int idx, bool readOnly ); void setReadOnly( int idx, bool readOnly = true );

/**
* Returns if the field at fieldidx should be treated as NOT NULL value
*/
bool notNull( int fieldidx) const;
/**
* Set if the field at fieldidx should be treated as NOT NULL value
*/
void setNotNull( int idx, bool notnull = true );


/** /**
* If this returns true, the widget at the given index will receive its label on the previous line * If this returns true, the widget at the given index will receive its label on the previous line
Expand Down
2 changes: 1 addition & 1 deletion python/core/qgsfield.sip
Expand Up @@ -165,7 +165,7 @@ class QgsField
/* Raise an exception if the arguments couldn't be parsed. */ /* Raise an exception if the arguments couldn't be parsed. */
sipNoMethod(sipParseErr, sipName_QgsField, sipName_convertCompatible, doc_QgsField_convertCompatible); sipNoMethod(sipParseErr, sipName_QgsField, sipName_convertCompatible, doc_QgsField_convertCompatible);


return NULL; return nullptr;
%End %End


//! Allows direct construction of QVariants from fields. //! Allows direct construction of QVariants from fields.
Expand Down
14 changes: 12 additions & 2 deletions src/app/qgsattributetypedialog.cpp
Expand Up @@ -163,16 +163,26 @@ void QgsAttributeTypeDialog::setWidgetV2Config( const QgsEditorWidgetConfig& con
mWidgetV2Config = config; mWidgetV2Config = config;
} }


bool QgsAttributeTypeDialog::fieldEditable() bool QgsAttributeTypeDialog::fieldEditable() const
{ {
return isFieldEditableCheckBox->isChecked(); return isFieldEditableCheckBox->isChecked();
} }


bool QgsAttributeTypeDialog::labelOnTop() void QgsAttributeTypeDialog::setNotNull( bool notnull )
{
notNullCheckBox->setChecked( notnull );
}

bool QgsAttributeTypeDialog::labelOnTop() const
{ {
return labelOnTopCheckBox->isChecked(); return labelOnTopCheckBox->isChecked();
} }


bool QgsAttributeTypeDialog::notNull() const
{
return notNullCheckBox->isChecked();
}

void QgsAttributeTypeDialog::setFieldEditable( bool editable ) void QgsAttributeTypeDialog::setFieldEditable( bool editable )
{ {
isFieldEditableCheckBox->setChecked( editable ); isFieldEditableCheckBox->setChecked( editable );
Expand Down
16 changes: 13 additions & 3 deletions src/app/qgsattributetypedialog.h
Expand Up @@ -69,6 +69,11 @@ class APP_EXPORT QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttribut
*/ */
void setLabelOnTop( bool onTop ); void setLabelOnTop( bool onTop );


/**
* Getter for checkbox for label on top of field
*/
bool labelOnTop() const;

/** /**
* Setter for checkbox for editable state of field * Setter for checkbox for editable state of field
*/ */
Expand All @@ -77,12 +82,17 @@ class APP_EXPORT QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttribut
/** /**
* Getter for checkbox for editable state of field * Getter for checkbox for editable state of field
*/ */
bool fieldEditable(); bool fieldEditable() const;


/** /**
* Getter for checkbox for label on top of field * Getter for checkbox for not null
*/
void setNotNull( bool notnull );

/**
* Getter for checkbox for not null
*/ */
bool labelOnTop(); bool notNull() const;


private slots: private slots:
/** /**
Expand Down
5 changes: 5 additions & 0 deletions src/app/qgsfieldsproperties.cpp
Expand Up @@ -527,6 +527,7 @@ void QgsFieldsProperties::attributeTypeDialog()


attributeTypeDialog.setFieldEditable( cfg.mEditable ); attributeTypeDialog.setFieldEditable( cfg.mEditable );
attributeTypeDialog.setLabelOnTop( cfg.mLabelOnTop ); attributeTypeDialog.setLabelOnTop( cfg.mLabelOnTop );
attributeTypeDialog.setNotNull( cfg.mNotNull );


attributeTypeDialog.setWidgetV2Config( cfg.mEditorWidgetV2Config ); attributeTypeDialog.setWidgetV2Config( cfg.mEditorWidgetV2Config );
attributeTypeDialog.setWidgetV2Type( cfg.mEditorWidgetV2Type ); attributeTypeDialog.setWidgetV2Type( cfg.mEditorWidgetV2Type );
Expand All @@ -536,6 +537,7 @@ void QgsFieldsProperties::attributeTypeDialog()


cfg.mEditable = attributeTypeDialog.fieldEditable(); cfg.mEditable = attributeTypeDialog.fieldEditable();
cfg.mLabelOnTop = attributeTypeDialog.labelOnTop(); cfg.mLabelOnTop = attributeTypeDialog.labelOnTop();
cfg.mNotNull = attributeTypeDialog.notNull();


cfg.mEditorWidgetV2Type = attributeTypeDialog.editorWidgetV2Type(); cfg.mEditorWidgetV2Type = attributeTypeDialog.editorWidgetV2Type();
cfg.mEditorWidgetV2Config = attributeTypeDialog.editorWidgetV2Config(); cfg.mEditorWidgetV2Config = attributeTypeDialog.editorWidgetV2Config();
Expand Down Expand Up @@ -908,6 +910,7 @@ void QgsFieldsProperties::apply()


mLayer->editFormConfig()->setReadOnly( i, !cfg.mEditable ); mLayer->editFormConfig()->setReadOnly( i, !cfg.mEditable );
mLayer->editFormConfig()->setLabelOnTop( i, cfg.mLabelOnTop ); mLayer->editFormConfig()->setLabelOnTop( i, cfg.mLabelOnTop );
mLayer->editFormConfig()->setNotNull( i, cfg.mNotNull );


mLayer->editFormConfig()->setWidgetType( idx, cfg.mEditorWidgetV2Type ); mLayer->editFormConfig()->setWidgetType( idx, cfg.mEditorWidgetV2Type );
mLayer->editFormConfig()->setWidgetConfig( idx, cfg.mEditorWidgetV2Config ); mLayer->editFormConfig()->setWidgetConfig( idx, cfg.mEditorWidgetV2Config );
Expand Down Expand Up @@ -974,6 +977,7 @@ QgsFieldsProperties::FieldConfig::FieldConfig()
: mEditable( true ) : mEditable( true )
, mEditableEnabled( true ) , mEditableEnabled( true )
, mLabelOnTop( false ) , mLabelOnTop( false )
, mNotNull( false )
, mButton( nullptr ) , mButton( nullptr )
{ {
} }
Expand All @@ -985,6 +989,7 @@ QgsFieldsProperties::FieldConfig::FieldConfig( QgsVectorLayer* layer, int idx )
mEditableEnabled = layer->fields().fieldOrigin( idx ) != QgsFields::OriginJoin mEditableEnabled = layer->fields().fieldOrigin( idx ) != QgsFields::OriginJoin
&& layer->fields().fieldOrigin( idx ) != QgsFields::OriginExpression; && layer->fields().fieldOrigin( idx ) != QgsFields::OriginExpression;
mLabelOnTop = layer->editFormConfig()->labelOnTop( idx ); mLabelOnTop = layer->editFormConfig()->labelOnTop( idx );
mNotNull = layer->editFormConfig()->notNull( idx );
mEditorWidgetV2Type = layer->editFormConfig()->widgetType( idx ); mEditorWidgetV2Type = layer->editFormConfig()->widgetType( idx );
mEditorWidgetV2Config = layer->editFormConfig()->widgetConfig( idx ); mEditorWidgetV2Config = layer->editFormConfig()->widgetConfig( idx );


Expand Down
1 change: 1 addition & 0 deletions src/app/qgsfieldsproperties.h
Expand Up @@ -92,6 +92,7 @@ class APP_EXPORT QgsFieldsProperties : public QWidget, private Ui_QgsFieldsPrope
bool mEditable; bool mEditable;
bool mEditableEnabled; bool mEditableEnabled;
bool mLabelOnTop; bool mLabelOnTop;
bool mNotNull;
QPushButton* mButton; QPushButton* mButton;
QString mEditorWidgetV2Type; QString mEditorWidgetV2Type;
QMap<QString, QVariant> mEditorWidgetV2Config; QMap<QString, QVariant> mEditorWidgetV2Config;
Expand Down
16 changes: 15 additions & 1 deletion src/core/qgseditformconfig.cpp
Expand Up @@ -119,6 +119,14 @@ bool QgsEditFormConfig::labelOnTop( int idx ) const
return false; return false;
} }


bool QgsEditFormConfig::notNull( int idx ) const
{
if ( idx >= 0 && idx < mFields.count() )
return mNotNull.value( mFields.at( idx ).name(), false );
else
return false;
}

void QgsEditFormConfig::setReadOnly( int idx, bool readOnly ) void QgsEditFormConfig::setReadOnly( int idx, bool readOnly )
{ {
if ( idx >= 0 && idx < mFields.count() ) if ( idx >= 0 && idx < mFields.count() )
Expand All @@ -131,6 +139,12 @@ void QgsEditFormConfig::setLabelOnTop( int idx, bool onTop )
mLabelOnTop[ mFields.at( idx ).name()] = onTop; mLabelOnTop[ mFields.at( idx ).name()] = onTop;
} }


void QgsEditFormConfig::setNotNull( int idx, bool notnull )
{
if ( idx >= 0 && idx < mFields.count() )
mNotNull[ mFields.at( idx ).name()] = notnull;
}

void QgsEditFormConfig::readXml( const QDomNode& node ) void QgsEditFormConfig::readXml( const QDomNode& node )
{ {
QDomNode editFormNode = node.namedItem( "editform" ); QDomNode editFormNode = node.namedItem( "editform" );
Expand Down Expand Up @@ -280,7 +294,6 @@ void QgsEditFormConfig::writeXml( QDomNode& node ) const
efifpField.appendChild( doc.createTextNode( QgsProject::instance()->writePath( initFilePath() ) ) ); efifpField.appendChild( doc.createTextNode( QgsProject::instance()->writePath( initFilePath() ) ) );
node.appendChild( efifpField ); node.appendChild( efifpField );



QDomElement eficField = doc.createElement( "editforminitcode" ); QDomElement eficField = doc.createElement( "editforminitcode" );
eficField.appendChild( doc.createCDATASection( initCode() ) ); eficField.appendChild( doc.createCDATASection( initCode() ) );
node.appendChild( eficField ); node.appendChild( eficField );
Expand Down Expand Up @@ -337,6 +350,7 @@ void QgsEditFormConfig::writeXml( QDomNode& node ) const
{ {
QDomElement widgetElem = doc.createElement( "widget" ); QDomElement widgetElem = doc.createElement( "widget" );
widgetElem.setAttribute( "name", configIt.key() ); widgetElem.setAttribute( "name", configIt.key() );
// widgetElem.setAttribute( "notNull", );


QDomElement configElem = doc.createElement( "config" ); QDomElement configElem = doc.createElement( "config" );
widgetElem.appendChild( configElem ); widgetElem.appendChild( configElem );
Expand Down
10 changes: 10 additions & 0 deletions src/core/qgseditformconfig.h
Expand Up @@ -512,6 +512,15 @@ class CORE_EXPORT QgsEditFormConfig : public QObject
*/ */
void setReadOnly( int idx, bool readOnly = true ); void setReadOnly( int idx, bool readOnly = true );


/**
* Returns if the field at fieldidx should be treated as NOT NULL value
*/
bool notNull( int fieldidx ) const;
/**
* Set if the field at fieldidx should be treated as NOT NULL value
*/
void setNotNull( int idx, bool notnull = true );

/** /**
* If this returns true, the widget at the given index will receive its label on the previous line * If this returns true, the widget at the given index will receive its label on the previous line
* while if it returns false, the widget will receive its label on the left hand side. * while if it returns false, the widget will receive its label on the left hand side.
Expand Down Expand Up @@ -633,6 +642,7 @@ class CORE_EXPORT QgsEditFormConfig : public QObject


QMap< QString, bool> mFieldEditables; QMap< QString, bool> mFieldEditables;
QMap< QString, bool> mLabelOnTop; QMap< QString, bool> mLabelOnTop;
QMap< QString, bool> mNotNull;


QMap<QString, QString> mEditorWidgetV2Types; QMap<QString, QString> mEditorWidgetV2Types;
QMap<QString, QgsEditorWidgetConfig > mWidgetConfigs; QMap<QString, QgsEditorWidgetConfig > mWidgetConfigs;
Expand Down
6 changes: 5 additions & 1 deletion src/core/qgseditorwidgetconfig.h
Expand Up @@ -16,6 +16,8 @@
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>


#ifndef QGSEDITORWIDGETCONFIG_H
#define QGSEDITORWIDGETCONFIG_H


/** /**
* Holds a set of configuration parameters for a editor widget wrapper. * Holds a set of configuration parameters for a editor widget wrapper.
Expand All @@ -30,4 +32,6 @@
* You get these passed, for every new widget wrapper. * You get these passed, for every new widget wrapper.
*/ */


typedef QMap<QString, QVariant> QgsEditorWidgetConfig; typedef QVariantMap QgsEditorWidgetConfig;

#endif // QGSEDITORWIDGETCONFIG_H
6 changes: 6 additions & 0 deletions src/core/qgsfeature.cpp
Expand Up @@ -288,6 +288,12 @@ int QgsFeature::fieldNameIndex( const QString& fieldName ) const
return d->fields.fieldNameIndex( fieldName ); return d->fields.fieldNameIndex( fieldName );
} }


/***************************************************************************
* This class is considered CRITICAL and any change MUST be accompanied with
* full unit tests in testqgsfeature.cpp.
* See details in QEP #17
****************************************************************************/

QDataStream& operator<<( QDataStream& out, const QgsFeature& feature ) QDataStream& operator<<( QDataStream& out, const QgsFeature& feature )
{ {
out << feature.id(); out << feature.id();
Expand Down
4 changes: 2 additions & 2 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -1105,13 +1105,13 @@ QgsFeatureIterator QgsVectorLayer::getFeatures( const QgsFeatureRequest& request
} }




bool QgsVectorLayer::addFeature( QgsFeature& f, bool alsoUpdateExtent ) bool QgsVectorLayer::addFeature( QgsFeature& feature, bool alsoUpdateExtent )
{ {
Q_UNUSED( alsoUpdateExtent ); // TODO[MD] Q_UNUSED( alsoUpdateExtent ); // TODO[MD]
if ( !mValid || !mEditBuffer || !mDataProvider ) if ( !mValid || !mEditBuffer || !mDataProvider )
return false; return false;


bool success = mEditBuffer->addFeature( f ); bool success = mEditBuffer->addFeature( feature );


if ( success ) if ( success )
updateExtents(); updateExtents();
Expand Down
4 changes: 2 additions & 2 deletions src/core/qgsvectorlayer.h
Expand Up @@ -975,11 +975,11 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
QgsFeatureIterator getFeatures( const QgsFeatureRequest& request = QgsFeatureRequest() ); QgsFeatureIterator getFeatures( const QgsFeatureRequest& request = QgsFeatureRequest() );


/** Adds a feature /** Adds a feature
@param f feature to add @param feature feature to add
@param alsoUpdateExtent If True, will also go to the effort of e.g. updating the extents. @param alsoUpdateExtent If True, will also go to the effort of e.g. updating the extents.
@return True in case of success and False in case of error @return True in case of success and False in case of error
*/ */
bool addFeature( QgsFeature& f, bool alsoUpdateExtent = true ); bool addFeature( QgsFeature& feature, bool alsoUpdateExtent = true );


/** Updates an existing feature. This method needs to query the datasource /** Updates an existing feature. This method needs to query the datasource
on every call. Consider using {@link changeAttributeValue()} or on every call. Consider using {@link changeAttributeValue()} or
Expand Down
2 changes: 2 additions & 0 deletions src/gui/editorwidgets/core/qgseditorwidgetregistry.cpp
Expand Up @@ -251,6 +251,7 @@ void QgsEditorWidgetRegistry::readMapLayer( QgsMapLayer* mapLayer, const QDomEle


vectorLayer->editFormConfig()->setReadOnly( idx, ewv2CfgElem.attribute( "fieldEditable", "1" ) != "1" ); vectorLayer->editFormConfig()->setReadOnly( idx, ewv2CfgElem.attribute( "fieldEditable", "1" ) != "1" );
vectorLayer->editFormConfig()->setLabelOnTop( idx, ewv2CfgElem.attribute( "labelOnTop", "0" ) == "1" ); vectorLayer->editFormConfig()->setLabelOnTop( idx, ewv2CfgElem.attribute( "labelOnTop", "0" ) == "1" );
vectorLayer->editFormConfig()->setNotNull( idx, ewv2CfgElem.attribute( "notNull", "0" ) == "1" );
vectorLayer->editFormConfig()->setWidgetConfig( idx, cfg ); vectorLayer->editFormConfig()->setWidgetConfig( idx, cfg );
} }
else else
Expand Down Expand Up @@ -307,6 +308,7 @@ void QgsEditorWidgetRegistry::writeMapLayer( QgsMapLayer* mapLayer, QDomElement&
QDomElement ewv2CfgElem = doc.createElement( "widgetv2config" ); QDomElement ewv2CfgElem = doc.createElement( "widgetv2config" );
ewv2CfgElem.setAttribute( "fieldEditable", !vectorLayer->editFormConfig()->readOnly( idx ) ); ewv2CfgElem.setAttribute( "fieldEditable", !vectorLayer->editFormConfig()->readOnly( idx ) );
ewv2CfgElem.setAttribute( "labelOnTop", vectorLayer->editFormConfig()->labelOnTop( idx ) ); ewv2CfgElem.setAttribute( "labelOnTop", vectorLayer->editFormConfig()->labelOnTop( idx ) );
ewv2CfgElem.setAttribute( "notNull", vectorLayer->editFormConfig()->notNull( idx ) );


mWidgetFactories[widgetType]->writeConfig( vectorLayer->editFormConfig()->widgetConfig( idx ), ewv2CfgElem, doc, vectorLayer, idx ); mWidgetFactories[widgetType]->writeConfig( vectorLayer->editFormConfig()->widgetConfig( idx ), ewv2CfgElem, doc, vectorLayer, idx );


Expand Down
27 changes: 27 additions & 0 deletions src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp
Expand Up @@ -24,6 +24,7 @@ QgsEditorWidgetWrapper::QgsEditorWidgetWrapper( QgsVectorLayer* vl, int fieldIdx
: QgsWidgetWrapper( vl, editor, parent ) : QgsWidgetWrapper( vl, editor, parent )
, mFieldIdx( fieldIdx ) , mFieldIdx( fieldIdx )
{ {
connect( this, SIGNAL( valueChanged( QVariant ) ), this, SLOT( onValueChanged( QVariant ) ) );
} }


int QgsEditorWidgetWrapper::fieldIdx() const int QgsEditorWidgetWrapper::fieldIdx() const
Expand Down Expand Up @@ -61,6 +62,7 @@ void QgsEditorWidgetWrapper::setEnabled( bool enabled )
void QgsEditorWidgetWrapper::setFeature( const QgsFeature& feature ) void QgsEditorWidgetWrapper::setFeature( const QgsFeature& feature )
{ {
setValue( feature.attribute( mFieldIdx ) ); setValue( feature.attribute( mFieldIdx ) );
onValueChanged( value() );
} }


void QgsEditorWidgetWrapper::valueChanged( const QString& value ) void QgsEditorWidgetWrapper::valueChanged( const QString& value )
Expand Down Expand Up @@ -92,3 +94,28 @@ void QgsEditorWidgetWrapper::valueChanged()
{ {
emit valueChanged( value() ); emit valueChanged( value() );
} }

void QgsEditorWidgetWrapper::updateConstraintsOk( bool constraintStatus )
{
if ( constraintStatus )
{
widget()->setStyleSheet( "" );
}
else
{
widget()->setStyleSheet( "QWidget{ background-color: '#dd7777': }" );
}
}

void QgsEditorWidgetWrapper::onValueChanged( const QVariant& value )
{
if ( layer()->editFormConfig()->notNull( mFieldIdx ) )
{
if ( value.isNull() != mIsNull )
{
updateConstraintsOk( value.isNull() );
emit constraintStatusChanged( "NotNull", !value.isNull() );
mIsNull = value.isNull();
}
}
}
27 changes: 27 additions & 0 deletions src/gui/editorwidgets/core/qgseditorwidgetwrapper.h
Expand Up @@ -118,6 +118,13 @@ class GUI_EXPORT QgsEditorWidgetWrapper : public QgsWidgetWrapper
*/ */
void valueChanged( const QVariant& value ); void valueChanged( const QVariant& value );


/**
* @brief constraintStatusChanged
* @param constraint
* @param status
*/
void constraintStatusChanged( const QString& constraint, bool status );

public slots: public slots:
/** /**
* Will be called when the feature changes * Will be called when the feature changes
Expand Down Expand Up @@ -185,8 +192,28 @@ class GUI_EXPORT QgsEditorWidgetWrapper : public QgsWidgetWrapper
*/ */
void valueChanged(); void valueChanged();


private:
/**
* This should update the widget with a visual cue if a constraint status
* changed.
*
* By default a stylesheet will be applied on the widget that changes the
* background color to red.
*
* This can be overwritten in subclasses to allow individual widgets to
* change the visual cue.
*/
virtual void updateConstraintsOk( bool constraintStatus );

private slots:
/**
* @brief mFieldIdx
*/
void onValueChanged( const QVariant& value );

private: private:
int mFieldIdx; int mFieldIdx;
bool mIsNull;
}; };


// We'll use this class inside a QVariant in the widgets properties // We'll use this class inside a QVariant in the widgets properties
Expand Down
2 changes: 1 addition & 1 deletion src/gui/editorwidgets/qgsrangewidgetfactory.cpp
Expand Up @@ -38,7 +38,7 @@ QgsEditorWidgetConfig QgsRangeWidgetFactory::readConfig( const QDomElement& conf
{ {
Q_UNUSED( layer ); Q_UNUSED( layer );
Q_UNUSED( fieldIdx ); Q_UNUSED( fieldIdx );
QMap<QString, QVariant> cfg; QgsEditorWidgetConfig cfg;


cfg.insert( "Style", configElement.attribute( "Style" ) ); cfg.insert( "Style", configElement.attribute( "Style" ) );
cfg.insert( "Min", configElement.attribute( "Min" ) ); cfg.insert( "Min", configElement.attribute( "Min" ) );
Expand Down
2 changes: 1 addition & 1 deletion src/gui/editorwidgets/qgsrelationreferenceconfigdlg.cpp
Expand Up @@ -55,7 +55,7 @@ QgsRelationReferenceConfigDlg::QgsRelationReferenceConfigDlg( QgsVectorLayer* vl
} }
} }


void QgsRelationReferenceConfigDlg::setConfig( const QMap<QString, QVariant>& config ) void QgsRelationReferenceConfigDlg::setConfig( const QgsEditorWidgetConfig& config )
{ {
if ( config.contains( "AllowNULL" ) ) if ( config.contains( "AllowNULL" ) )
{ {
Expand Down
2 changes: 1 addition & 1 deletion src/gui/editorwidgets/qgsrelationreferencefactory.cpp
Expand Up @@ -46,7 +46,7 @@ QgsEditorWidgetConfig QgsRelationReferenceFactory::readConfig( const QDomElement
{ {
Q_UNUSED( layer ); Q_UNUSED( layer );
Q_UNUSED( fieldIdx ); Q_UNUSED( fieldIdx );
QMap<QString, QVariant> cfg; QgsEditorWidgetConfig cfg;


cfg.insert( "AllowNULL", configElement.attribute( "AllowNULL" ) == "1" ); cfg.insert( "AllowNULL", configElement.attribute( "AllowNULL" ) == "1" );
cfg.insert( "OrderByValue", configElement.attribute( "OrderByValue" ) == "1" ); cfg.insert( "OrderByValue", configElement.attribute( "OrderByValue" ) == "1" );
Expand Down

0 comments on commit 4ae1b55

Please sign in to comment.