get rid of model types and cache

This commit is contained in:
tomasMizera 2020-09-11 11:51:16 +02:00 committed by Martin Dobias
parent 7c005d7c07
commit 265740fd5a
3 changed files with 102 additions and 126 deletions

View File

@ -48,22 +48,21 @@ Item {
property var currentEditorValue: value
comboStyle: customStyle.fields
textRole: 'display'
textRole: 'FeatureTitle'
height: parent.height
model: QgsQuick.FeaturesListModel {
id: vrModel
modelType: QgsQuick.FeaturesListModel.ValueRelation
// recalculate index when model changes
onModelReset: {
combobox.currentIndex = vrModel.rowModelIndexFromKey( value )
combobox.currentIndex = vrModel.rowFromAttribute( QgsQuick.FeaturesListModel.KeyColumn, value )
}
}
Component.onCompleted: {
vrModel.populate(config)
currentIndex = vrModel.rowModelIndexFromKey( value )
vrModel.setupValueRelation( config )
currentIndex = vrModel.rowFromAttribute( QgsQuick.FeaturesListModel.KeyColumn, value )
}
onPressedChanged: {
@ -76,13 +75,13 @@ Item {
// Called when user makes selection in the combo box
onItemClicked: {
currentIndex = vrModel.rowModelIndexFromKey( index )
valueChanged( index, false )
currentIndex = vrModel.rowFromAttribute( QgsQuick.FeaturesListModel.FeatureId, index )
valueChanged( vrModel.keyFromAttribute( QgsQuick.FeaturesListModel.FeatureId, index ), false )
}
// Called when the same form is used for a different feature
onCurrentEditorValueChanged: {
currentIndex = vrModel.rowModelIndexFromKey( value );
currentIndex = vrModel.rowFromAttribute( QgsQuick.FeaturesListModel.KeyColumn, value );
}
}
}

View File

@ -19,21 +19,10 @@
QgsQuickFeaturesListModel::QgsQuickFeaturesListModel( QObject *parent )
: QAbstractListModel( parent ),
mCurrentLayer( nullptr ),
mModelType( modelTypes::FeatureListing )
mCurrentLayer( nullptr )
{
}
QgsQuickFeatureLayerPair QgsQuickFeaturesListModel::featureLayerPair( const int &featureId )
{
for ( const QgsQuickFeatureLayerPair &i : mFeatures )
{
if ( i.feature().id() == featureId )
return i;
}
return QgsQuickFeatureLayerPair();
}
int QgsQuickFeaturesListModel::rowCount( const QModelIndex &parent ) const
{
// For list models only the root node (an invalid parent) should return the list's size. For all
@ -46,15 +35,24 @@ int QgsQuickFeaturesListModel::rowCount( const QModelIndex &parent ) const
QVariant QgsQuickFeaturesListModel::featureTitle( const QgsQuickFeatureLayerPair &featurePair ) const
{
QString title;
if ( !mFeatureTitleField.isEmpty() )
{
title = featurePair.feature().attribute( mFeatureTitleField ).toString();
if ( !title.isEmpty() )
return title;
}
QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( featurePair.layer() ) );
context.setFeature( featurePair.feature() );
QgsExpression expr( featurePair.layer()->displayExpression() );
const QString title = expr.evaluate( &context ).toString();
title = expr.evaluate( &context ).toString();
if ( title.isEmpty() )
return QVariant( featurePair.feature().id() );
return featurePair.feature().id();
return QVariant( title );
return title;
}
QVariant QgsQuickFeaturesListModel::data( const QModelIndex &index, int role ) const
@ -74,21 +72,9 @@ QVariant QgsQuickFeaturesListModel::data( const QModelIndex &index, int role ) c
case FeatureId: return QVariant( pair.feature().id() );
case Feature: return QVariant::fromValue<QgsFeature>( pair.feature() );
case Description: return QVariant( QString( "Feature ID %1" ).arg( pair.feature().id() ) );
case EmitableIndex:
{
if ( mModelType == modelTypes::ValueRelation )
return pair.feature().attribute( mKeyFieldName );
return pair.feature().id();
}
case KeyColumn: return mKeyField.isEmpty() ? QVariant() : pair.feature().attribute( mKeyField );
case FoundPair: return foundPair( pair );
case Qt::DisplayRole:
{
if ( row >= 0 && row < mCache.count() )
{
int r = rowIndexFromKey( pair.feature().attribute( mKeyFieldName ) );
return mCache[r].value;
}
}
case Qt::DisplayRole: return featureTitle( pair );
}
return QVariant();
@ -163,19 +149,20 @@ void QgsQuickFeaturesListModel::loadFeaturesFromLayer( QgsVectorLayer *layer )
}
}
void QgsQuickFeaturesListModel::populate( const QVariantMap &config )
void QgsQuickFeaturesListModel::setupValueRelation( const QVariantMap &config )
{
beginResetModel();
emptyData();
mCache = QgsValueRelationFieldFormatter::createCache( config );
QgsVectorLayer *layer = QgsValueRelationFieldFormatter::resolveLayer( config, QgsProject::instance() );
if ( layer )
{
// save key field
// save key and value field
QgsFields fields = layer->fields();
mKeyFieldName = fields.field( config.value( QStringLiteral( "Key" ) ).toString() ).name();
setKeyField( fields.field( config.value( QStringLiteral( "Key" ) ).toString() ).name() );
setFeatureTitleField( fields.field( config.value( QStringLiteral( "Value" ) ).toString() ).name() );
loadFeaturesFromLayer( layer );
}
@ -201,8 +188,8 @@ void QgsQuickFeaturesListModel::emptyData()
{
mFeatures.clear();
mCurrentLayer = nullptr;
mCache.clear();
mKeyFieldName.clear();
mKeyField.clear();
mFeatureTitleField.clear();
mFilterExpression.clear();
}
@ -214,7 +201,7 @@ QHash<int, QByteArray> QgsQuickFeaturesListModel::roleNames() const
roleNames[Feature] = QStringLiteral( "Feature" ).toLatin1();
roleNames[Description] = QStringLiteral( "Description" ).toLatin1();
roleNames[FoundPair] = QStringLiteral( "FoundPair" ).toLatin1();
roleNames[EmitableIndex] = QStringLiteral( "EmitableIndex" ).toLatin1();
roleNames[KeyColumn] = QStringLiteral( "KeyColumn" ).toLatin1();
return roleNames;
}
@ -238,39 +225,54 @@ void QgsQuickFeaturesListModel::setFilterExpression( const QString &filterExpres
loadFeaturesFromLayer();
}
void QgsQuickFeaturesListModel::setFeatureTitleField( const QString &attribute )
{
mFeatureTitleField = attribute;
}
void QgsQuickFeaturesListModel::setKeyField( const QString &attribute )
{
mKeyField = attribute;
}
int QgsQuickFeaturesListModel::featuresLimit() const
{
return FEATURES_LIMIT;
}
QgsQuickFeaturesListModel::modelTypes QgsQuickFeaturesListModel::modelType() const
{
return mModelType;
}
void QgsQuickFeaturesListModel::setModelType( modelTypes modelType )
{
mModelType = modelType;
}
int QgsQuickFeaturesListModel::rowIndexFromKey( const QVariant &key ) const
{
for ( int i = 0; i < mCache.count(); ++i )
{
if ( mCache[i].key == key )
return i;
}
QgsDebugMsg( "rowIndexFromKey: key not found: " + key.toString() );
return -1;
}
int QgsQuickFeaturesListModel::rowModelIndexFromKey( const QVariant &key ) const
int QgsQuickFeaturesListModel::rowFromAttribute( const int role, const QVariant &value ) const
{
for ( int i = 0; i < mFeatures.count(); ++i )
{
if ( mFeatures[i].feature().attribute( mKeyFieldName ) == key )
QVariant d = data( index( i, 0 ), role );
if ( d == value )
{
return i;
}
}
QgsDebugMsg( "rowModelIndexFromKey: Could not find index in features model, index: " + key.toString() );
return -1;
}
int QgsQuickFeaturesListModel::keyFromAttribute( const int role, const QVariant &value ) const
{
for ( int i = 0; i < mFeatures.count(); ++i )
{
QVariant d = data( index( i, 0 ), role );
if ( d == value )
{
QVariant key = data( index( i, 0 ), KeyColumn );
return key.toInt();
}
}
return -1;
}
QgsQuickFeatureLayerPair QgsQuickFeaturesListModel::featureLayerPair( const int &featureId )
{
for ( const QgsQuickFeatureLayerPair &i : mFeatures )
{
if ( i.feature().id() == featureId )
return i;
}
return QgsQuickFeatureLayerPair();
}

View File

@ -28,10 +28,6 @@
*
* Model allows searching by any string or number attribute.
*
* Note that the model can run in several modes:
* (1) as a features list - usable in listing features from specifig layer
* (2) as a value relation model - filling value-relation widget with data from config
*
* \note QML Type: FeaturesListModel
*
* \since QGIS 3.16
@ -58,37 +54,19 @@ class QUICK_EXPORT QgsQuickFeaturesListModel : public QAbstractListModel
*/
Q_PROPERTY( int featuresLimit READ featuresLimit NOTIFY featuresLimitChanged )
/**
* Property determining type of Feature Model.
*
* \note ValueRelation type provides different attribute when opting for data with EmitableIndex role, it returns "key" attribute
*/
Q_PROPERTY( modelTypes modelType READ modelType WRITE setModelType )
public:
enum roleNames
//! Roles for FeaturesListModel
enum modelRoles
{
FeatureTitle = Qt::UserRole + 1,
FeatureId,
Feature,
Description, //! secondary text in list view
EmitableIndex, //! key in value relation
KeyColumn, //! key in value relation
FoundPair //! pair of attribute and its value by which the feature was found, empty if mFilterExpression is empty
};
public:
/**
* \brief The modelTypes enum
* ValueRelation type provides different attribute when opting for data with EmitableIndex role, it returns "key" attribute.
*
* Default type is FeatureListing
*/
enum modelTypes
{
FeatureListing,
ValueRelation
};
Q_ENUM( modelTypes );
Q_ENUM( modelRoles );
//! Create features list model
explicit QgsQuickFeaturesListModel( QObject *parent = nullptr );
@ -102,10 +80,10 @@ class QUICK_EXPORT QgsQuickFeaturesListModel : public QAbstractListModel
QHash<int, QByteArray> roleNames() const override;
/**
* \brief populate populates model with value relation data from config
* \brief setupValueRelation populates model with value relation data from config
* \param config to be used
*/
Q_INVOKABLE void populate( const QVariantMap &config );
Q_INVOKABLE void setupValueRelation( const QVariantMap &config );
/**
* \brief populateFromLayer populates model with features from layer
@ -119,25 +97,27 @@ class QUICK_EXPORT QgsQuickFeaturesListModel : public QAbstractListModel
Q_INVOKABLE void reloadFeatures();
/**
* \brief rowIndexFromKey translates value relation key into index from cache
* \param key value relation key
* \return index from cache (loaded from config)
* \brief rowFromAttribute finds feature with requested role and value, returns its row
* \param role to find from modelRoles
* \param value to find
* \return Row index for found feature, returns -1 if no feature is found. If more features
* match requested role and value, index of first is returned.
*/
Q_INVOKABLE int rowIndexFromKey( const QVariant &key ) const;
Q_INVOKABLE int rowFromAttribute( const int role, const QVariant &value ) const;
/**
* \brief rowModelIndexFromKey translates value relation key into model index
* \param key value relation key
* \return model index (row) for corresponding feature (from mFeatures)
* \brief keyFromAttribute finds feature with requested role and value, returns keycolumn
* \param role role to find from modelRoles
* \param value value to find
* \return KeyColumn role for found feature, returns -1 if no feature is found. If more features
* match requested role and value, KeyColumn for first is returned.
*/
Q_INVOKABLE int rowModelIndexFromKey( const QVariant &key ) const;
Q_INVOKABLE int keyFromAttribute( const int role, const QVariant &value ) const;
//! Returns maximum amount of features that can be queried from layer
int featuresLimit() const;
//! Returns number of features in layer, not number of loaded features
int featuresCount() const;
//! Returns type of this model
modelTypes modelType() const;
//! Returns filter expression, empty string represents no filter
QString filterExpression() const;
@ -147,9 +127,14 @@ class QUICK_EXPORT QgsQuickFeaturesListModel : public QAbstractListModel
*/
void setFilterExpression( const QString &filterExpression );
public slots:
//! Sets corresponding type of model from modelTypes enum
void setModelType( modelTypes modelType );
/**
* \brief setFeatureTitleField Sets name of attribute that will be used for FeatureTitle and Qt::DisplayRole
* \param attribute Name of attribute to use. If empty, displayExpression will be used.
*/
void setFeatureTitleField( const QString &attribute );
//! Sets name of attribute used as "key" in value relation
void setKeyField( const QString &attribute );
signals:
@ -167,10 +152,7 @@ class QUICK_EXPORT QgsQuickFeaturesListModel : public QAbstractListModel
private:
/**
* \brief loadFeaturesFromLayer
* \param layer
*/
//! Reloads features from layer, if layer is not provided, uses current layer, If layer is provided, saves it as current.
void loadFeaturesFromLayer( QgsVectorLayer *layer = nullptr );
//! Empty data when resetting model
@ -190,7 +172,7 @@ class QUICK_EXPORT QgsQuickFeaturesListModel : public QAbstractListModel
* Hold maximum of FEATURES_LIMIT features
* \note mFeatures.size() is not always the same as mFeaturesCount
*/
QList<QgsQuickFeatureLayerPair> mFeatures;
QgsQuickFeatureLayerPairs mFeatures;
//! Number of maximum features loaded from layer
const int FEATURES_LIMIT = 10000;
@ -201,18 +183,11 @@ class QUICK_EXPORT QgsQuickFeaturesListModel : public QAbstractListModel
//! Pointer to layer that is currently loaded
QgsVectorLayer *mCurrentLayer = nullptr;
/**
* Data from config for value relations
* mCache is not affected by reloading features when filter expression is changed and
* is kept until next call of emptyData.
*/
QgsValueRelationFieldFormatter::ValueRelationCache mCache;
//! Type of a model - Listing (browsing) features or use in value relation widget
modelTypes mModelType;
//! Field that is used as a "key" in value relation
QString mKeyFieldName;
QString mKeyField;
//! Field that represents field used as a feature title, if not set, display expression is used
QString mFeatureTitleField;
};
#endif // QGSQUICKFEATURESMODEL_H