QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
qgsquickfeatureslistmodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsquickfeatureslistmodel.cpp
3  ---------------------------
4  Date : Sep 2020
5  Copyright : (C) 2020 by Tomas Mizera
6  Email : tomas.mizera2 at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
18 #include "qgslogger.h"
19 
21  : QAbstractListModel( parent ),
22  mCurrentLayer( nullptr )
23 {
24 }
25 
26 int QgsQuickFeaturesListModel::rowCount( const QModelIndex &parent ) const
27 {
28  // For list models only the root node (an invalid parent) should return the list's size. For all
29  // other (valid) parents, rowCount() should return 0 so that it does not become a tree model.
30  if ( parent.isValid() )
31  return 0;
32 
33  return mFeatures.count();
34 }
35 
36 QVariant QgsQuickFeaturesListModel::featureTitle( const QgsQuickFeatureLayerPair &featurePair ) const
37 {
38  QString title;
39 
40  if ( !mFeatureTitleField.isEmpty() )
41  {
42  title = featurePair.feature().attribute( mFeatureTitleField ).toString();
43  if ( !title.isEmpty() )
44  return title;
45  }
46 
48  context.setFeature( featurePair.feature() );
49  QgsExpression expr( featurePair.layer()->displayExpression() );
50  title = expr.evaluate( &context ).toString();
51 
52  if ( title.isEmpty() )
53  return featurePair.feature().id();
54 
55  return title;
56 }
57 
58 QVariant QgsQuickFeaturesListModel::data( const QModelIndex &index, int role ) const
59 {
60  int row = index.row();
61  if ( row < 0 || row >= mFeatures.count() )
62  return QVariant();
63 
64  if ( !index.isValid() )
65  return QVariant();
66 
67  const QgsQuickFeatureLayerPair pair = mFeatures.at( index.row() );
68 
69  switch ( role )
70  {
71  case FeatureTitle: return featureTitle( pair );
72  case FeatureId: return QVariant( pair.feature().id() );
73  case Feature: return QVariant::fromValue<QgsFeature>( pair.feature() );
74  case Description: return QVariant( QString( "Feature ID %1" ).arg( pair.feature().id() ) );
75  case KeyColumn: return mKeyField.isEmpty() ? QVariant() : pair.feature().attribute( mKeyField );
76  case FoundPair: return foundPair( pair );
77  case Qt::DisplayRole: return featureTitle( pair );
78  }
79 
80  return QVariant();
81 }
82 
83 QString QgsQuickFeaturesListModel::foundPair( const QgsQuickFeatureLayerPair &pair ) const
84 {
85  if ( mFilterExpression.isEmpty() )
86  return QString();
87 
88  QgsFields fields = pair.feature().fields();
89 
90  for ( const QgsField &field : fields )
91  {
92  QString attrValue = pair.feature().attribute( field.name() ).toString();
93 
94  if ( attrValue.toLower().indexOf( mFilterExpression.toLower() ) != -1 )
95  return field.name() + ": " + attrValue;
96  }
97  return QString();
98 }
99 
100 QString QgsQuickFeaturesListModel::buildFilterExpression()
101 {
102  if ( mFilterExpression.isEmpty() || !mCurrentLayer )
103  return QString();
104 
105  const QgsFields fields = mCurrentLayer->fields();
106  QStringList expressionParts;
107 
108  bool filterExpressionIsNumeric;
109  int filterInt = mFilterExpression.toInt( &filterExpressionIsNumeric );
110  Q_UNUSED( filterInt ); // we only need to know if expression is numeric, int value is not used
111 
112  for ( const QgsField &field : fields )
113  {
114  if ( field.isNumeric() && filterExpressionIsNumeric )
115  expressionParts << QStringLiteral( "%1 ~ '%2.*'" ).arg( QgsExpression::quotedColumnRef( field.name() ), mFilterExpression );
116  else if ( field.type() == QVariant::String )
117  expressionParts << QStringLiteral( "%1 ILIKE '%%2%'" ).arg( QgsExpression::quotedColumnRef( field.name() ), mFilterExpression );
118  }
119 
120  QString expression = QStringLiteral( "(%1)" ).arg( expressionParts.join( QLatin1String( " ) OR ( " ) ) );
121 
122  return expression;
123 }
124 
125 void QgsQuickFeaturesListModel::loadFeaturesFromLayer( QgsVectorLayer *layer )
126 {
127  if ( layer && layer->isValid() )
128  mCurrentLayer = layer;
129 
130  if ( mCurrentLayer )
131  {
132  beginResetModel();
133 
134  mFeatures.clear();
135  QgsFeatureRequest req;
136  if ( !mFilterExpression.isEmpty() )
137  req.setFilterExpression( buildFilterExpression() );
138  req.setLimit( FEATURES_LIMIT );
139 
140  QgsFeatureIterator it = mCurrentLayer->getFeatures( req );
141  QgsFeature f;
142 
143  while ( it.nextFeature( f ) )
144  {
145  mFeatures << QgsQuickFeatureLayerPair( f, mCurrentLayer );
146  }
148  endResetModel();
149  }
150 }
151 
152 void QgsQuickFeaturesListModel::setupValueRelation( const QVariantMap &config )
153 {
154  beginResetModel();
155  emptyData();
156 
158 
159  if ( layer )
160  {
161  // save key and value field
162  QgsFields fields = layer->fields();
163 
164  setKeyField( fields.field( config.value( QStringLiteral( "Key" ) ).toString() ).name() );
165  setFeatureTitleField( fields.field( config.value( QStringLiteral( "Value" ) ).toString() ).name() );
166 
167  loadFeaturesFromLayer( layer );
168  }
169 
170  endResetModel();
171 }
172 
174 {
175  beginResetModel();
176  emptyData();
177 
178  loadFeaturesFromLayer( layer );
179  endResetModel();
180 }
181 
183 {
184  loadFeaturesFromLayer();
185 }
186 
187 void QgsQuickFeaturesListModel::emptyData()
188 {
189  mFeatures.clear();
190  mCurrentLayer = nullptr;
191  mKeyField.clear();
192  mFeatureTitleField.clear();
193  mFilterExpression.clear();
194 }
195 
196 QHash<int, QByteArray> QgsQuickFeaturesListModel::roleNames() const
197 {
198  QHash<int, QByteArray> roleNames = QAbstractListModel::roleNames();
199  roleNames[FeatureTitle] = QStringLiteral( "FeatureTitle" ).toLatin1();
200  roleNames[FeatureId] = QStringLiteral( "FeatureId" ).toLatin1();
201  roleNames[Feature] = QStringLiteral( "Feature" ).toLatin1();
202  roleNames[Description] = QStringLiteral( "Description" ).toLatin1();
203  roleNames[FoundPair] = QStringLiteral( "FoundPair" ).toLatin1();
204  roleNames[KeyColumn] = QStringLiteral( "KeyColumn" ).toLatin1();
205  return roleNames;
206 }
207 
209 {
210  if ( mCurrentLayer )
211  return mCurrentLayer->featureCount();
212  return 0;
213 }
214 
216 {
217  return mFilterExpression;
218 }
219 
220 void QgsQuickFeaturesListModel::setFilterExpression( const QString &filterExpression )
221 {
222  mFilterExpression = filterExpression;
223  emit filterExpressionChanged( mFilterExpression );
224 
225  loadFeaturesFromLayer();
226 }
227 
228 void QgsQuickFeaturesListModel::setFeatureTitleField( const QString &attribute )
229 {
230  mFeatureTitleField = attribute;
231 }
232 
233 void QgsQuickFeaturesListModel::setKeyField( const QString &attribute )
234 {
235  mKeyField = attribute;
236 }
237 
239 {
240  return FEATURES_LIMIT;
241 }
242 
243 int QgsQuickFeaturesListModel::rowFromAttribute( const int role, const QVariant &value ) const
244 {
245  for ( int i = 0; i < mFeatures.count(); ++i )
246  {
247  QVariant d = data( index( i, 0 ), role );
248  if ( d == value )
249  {
250  return i;
251  }
252  }
253  return -1;
254 }
255 
256 int QgsQuickFeaturesListModel::keyFromAttribute( const int role, const QVariant &value ) const
257 {
258  for ( int i = 0; i < mFeatures.count(); ++i )
259  {
260  QVariant d = data( index( i, 0 ), role );
261  if ( d == value )
262  {
263  QVariant key = data( index( i, 0 ), KeyColumn );
264  return key.toInt();
265  }
266  }
267  return -1;
268 }
269 
271 {
272  for ( const QgsQuickFeatureLayerPair &i : mFeatures )
273  {
274  if ( i.feature().id() == featureId )
275  return i;
276  }
277  return QgsQuickFeatureLayerPair();
278 }
QgsVectorLayer::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Definition: qgsvectorlayer.cpp:993
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:370
qgsexpressioncontextutils.h
QgsFeature::id
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
QgsQuickFeaturesListModel::featuresCountChanged
void featuresCountChanged(int featuresCount)
featuresCountChanged Signal emitted when features are reloaded or layer is changed
QgsQuickFeaturesListModel::setKeyField
void setKeyField(const QString &attribute)
Sets name of attribute used as "key" in value relation.
Definition: qgsquickfeatureslistmodel.cpp:233
qgsquickfeatureslistmodel.h
QgsQuickFeaturesListModel::rowCount
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Definition: qgsquickfeatureslistmodel.cpp:26
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:45
QgsField::isNumeric
Q_GADGET bool isNumeric
Definition: qgsfield.h:53
QgsQuickFeaturesListModel::setFilterExpression
void setFilterExpression(const QString &filterExpression)
setFilterExpression Sets filter expression, upon setting also reloads features from current layer wit...
Definition: qgsquickfeatureslistmodel.cpp:220
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:468
QgsExpressionContextUtils::globalProjectLayerScopes
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Definition: qgsexpressioncontextutils.cpp:307
QgsMapLayer::isValid
bool isValid
Definition: qgsmaplayer.h:91
field
const QgsField & field
Definition: qgsfield.h:456
QgsVectorLayer::featureCount
long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
Definition: qgsvectorlayer.cpp:751
QgsField::name
QString name
Definition: qgsfield.h:59
QgsQuickFeaturesListModel::filterExpression
QString filterExpression
Filter Expression represents filter used when querying for data in current layer.
Definition: qgsquickfeatureslistmodel.h:49
QgsQuickFeaturesListModel::Description
@ Description
Definition: qgsquickfeatureslistmodel.h:65
QgsQuickFeaturesListModel::featuresLimit
int featuresLimit
Property limiting maximum number of features queried from layer Read only property.
Definition: qgsquickfeatureslistmodel.h:55
QgsFeatureRequest::setFilterExpression
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Definition: qgsfeaturerequest.cpp:124
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3283
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:76
QgsQuickFeaturesListModel::QgsQuickFeaturesListModel
QgsQuickFeaturesListModel(QObject *parent=nullptr)
Create features list model.
Definition: qgsquickfeatureslistmodel.cpp:20
QgsQuickFeatureLayerPair::layer
Q_GADGET QgsVectorLayer * layer
Vector layer to which the feature belongs.
Definition: qgsquickfeaturelayerpair.h:49
QgsQuickFeaturesListModel::keyFromAttribute
Q_INVOKABLE int keyFromAttribute(const int role, const QVariant &value) const
keyFromAttribute finds feature with requested role and value, returns keycolumn
Definition: qgsquickfeatureslistmodel.cpp:256
QgsQuickFeaturesListModel::Feature
@ Feature
Definition: qgsquickfeatureslistmodel.h:64
QgsFeature::attribute
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:264
QgsQuickFeaturesListModel::filterExpressionChanged
void filterExpressionChanged(QString filterExpression)
Signal emitted when filter expression has changed.
QgsQuickFeatureLayerPair::feature
QgsFeature feature
Feature that belongs to layer.
Definition: qgsquickfeaturelayerpair.h:56
QgsQuickFeaturesListModel::featureLayerPair
Q_INVOKABLE QgsQuickFeatureLayerPair featureLayerPair(const int &featureId)
Function to get QgsQuickFeatureLayerPair by feature id.
Definition: qgsquickfeatureslistmodel.cpp:270
QgsFields::field
QgsField field(int fieldIdx) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:168
QgsValueRelationFieldFormatter::resolveLayer
static QgsVectorLayer * resolveLayer(const QVariantMap &config, const QgsProject *project)
Returns the (possibly NULL) layer from the widget's config and project.
Definition: qgsvaluerelationfieldformatter.cpp:395
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:374
QgsQuickFeaturesListModel::KeyColumn
@ KeyColumn
secondary text in list view
Definition: qgsquickfeatureslistmodel.h:66
QgsQuickFeaturesListModel::reloadFeatures
Q_INVOKABLE void reloadFeatures()
reloadFeatures reloads features from current layer
Definition: qgsquickfeatureslistmodel.cpp:182
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsFeatureRequest::setLimit
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
Definition: qgsfeaturerequest.cpp:173
QgsQuickFeaturesListModel::featuresCount
int featuresCount
Read only property holding true number of features in layer - not only requested features Changing fi...
Definition: qgsquickfeatureslistmodel.h:43
QgsQuickFeaturesListModel::setupValueRelation
Q_INVOKABLE void setupValueRelation(const QVariantMap &config)
setupValueRelation populates model with value relation data from config
Definition: qgsquickfeatureslistmodel.cpp:152
QgsQuickFeatureLayerPair
Pair of QgsFeature and QgsVectorLayer.
Definition: qgsquickfeaturelayerpair.h:41
QgsQuickFeaturesListModel::FoundPair
@ FoundPair
key in value relation
Definition: qgsquickfeatureslistmodel.h:67
QgsExpression::quotedColumnRef
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Definition: qgsexpression.cpp:65
QgsFeature::fields
QgsFields fields
Definition: qgsfeature.h:66
QgsQuickFeaturesListModel::FeatureId
@ FeatureId
Definition: qgsquickfeatureslistmodel.h:63
QgsFeature
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:56
QgsQuickFeaturesListModel::FeatureTitle
@ FeatureTitle
Definition: qgsquickfeatureslistmodel.h:62
qgslogger.h
QgsQuickFeaturesListModel::data
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
Definition: qgsquickfeatureslistmodel.cpp:58
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:105
QgsVectorLayer::displayExpression
QString displayExpression
Definition: qgsvectorlayer.h:391
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:265
QgsQuickFeaturesListModel::populateFromLayer
Q_INVOKABLE void populateFromLayer(QgsVectorLayer *layer)
populateFromLayer populates model with features from layer
Definition: qgsquickfeatureslistmodel.cpp:173
QgsField::type
QVariant::Type type
Definition: qgsfield.h:57
QgsQuickFeaturesListModel::rowFromAttribute
Q_INVOKABLE int rowFromAttribute(const int role, const QVariant &value) const
rowFromAttribute finds feature with requested role and value, returns its row
Definition: qgsquickfeatureslistmodel.cpp:243
QgsQuickFeaturesListModel::roleNames
QHash< int, QByteArray > roleNames() const override
Definition: qgsquickfeatureslistmodel.cpp:196
QgsQuickFeaturesListModel::setFeatureTitleField
void setFeatureTitleField(const QString &attribute)
setFeatureTitleField Sets name of attribute that will be used for FeatureTitle and Qt::DisplayRole
Definition: qgsquickfeatureslistmodel.cpp:228
QgsField
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:50