QGIS API Documentation  2.99.0-Master (8ec3eaf)
qgsfieldmodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfieldmodel.cpp
3  --------------------------------------
4  Date : 01.04.2014
5  Copyright : (C) 2014 Denis Rouzaud
6  Email : [email protected]
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 
16 #include <QFont>
17 #include <QIcon>
18 
19 #include "qgsfieldmodel.h"
20 #include "qgsmaplayermodel.h"
21 #include "qgsmaplayerproxymodel.h"
22 #include "qgslogger.h"
23 #include "qgsapplication.h"
24 #include "qgsvectorlayer.h"
25 
26 QgsFieldModel::QgsFieldModel( QObject *parent )
27  : QAbstractItemModel( parent )
28  , mLayer( nullptr )
29  , mAllowExpression( false )
30  , mAllowEmpty( false )
31 {
32 }
33 
34 QModelIndex QgsFieldModel::indexFromName( const QString &fieldName )
35 {
36  QString fldName( fieldName ); // we may need a copy
37 
38  if ( mLayer )
39  {
40  // the name could be an alias
41  // it would be better to have "display name" directly in QgsFields
42  // rather than having to consult layer in various places in code!
43  QString fieldNameWithAlias = mLayer->attributeAliases().key( fldName );
44  if ( !fieldNameWithAlias.isNull() )
45  fldName = fieldNameWithAlias;
46  }
47 
48  if ( mAllowEmpty && fieldName.isEmpty() )
49  return index( 0, 0 );
50 
51  int r = mFields.indexFromName( fldName );
52  if ( r >= 0 )
53  {
54  if ( mAllowEmpty )
55  r++;
56 
57  QModelIndex idx = index( r, 0 );
58  if ( idx.isValid() )
59  {
60  return idx;
61  }
62  }
63 
64  if ( mAllowExpression )
65  {
66  int exprIdx = mExpression.indexOf( fldName );
67  if ( exprIdx != -1 )
68  {
69  return index(( mAllowEmpty ? 1 : 0 ) + mFields.count() + exprIdx, 0 );
70  }
71  }
72 
73  return QModelIndex();
74 }
75 
76 bool QgsFieldModel::isField( const QString& expression ) const
77 {
78  int index = mFields.indexFromName( expression );
79  return index >= 0;
80 }
81 
83 {
84  if ( mLayer )
85  {
86  disconnect( mLayer, SIGNAL( updatedFields() ), this, SLOT( updateModel() ) );
87  disconnect( mLayer, SIGNAL( destroyed() ), this, SLOT( layerDeleted() ) );
88  }
89 
90  mLayer = layer;
91 
92  if ( mLayer )
93  {
94  connect( mLayer, SIGNAL( updatedFields() ), this, SLOT( updateModel() ) );
95  connect( mLayer, SIGNAL( destroyed() ), this, SLOT( layerDeleted() ) );
96  }
97 
98  updateModel();
99 }
100 
101 void QgsFieldModel::layerDeleted()
102 {
103  mLayer = nullptr;
104  updateModel();
105 }
106 
108 {
109  int offset = mAllowEmpty ? 1 : 0;
110  if ( mLayer )
111  {
112  QgsFields newFields = mLayer->fields();
113  if ( mFields.toList() != newFields.toList() )
114  {
115  // Try to handle two special cases: addition of a new field and removal of a field.
116  // It would be better to listen directly to attributeAdded/attributeDeleted
117  // so we would not have to check for addition/removal here.
118 
119  if ( mFields.count() == newFields.count() - 1 )
120  {
121  QgsFields tmpNewFields = newFields;
122  tmpNewFields.remove( tmpNewFields.count() - 1 );
123  if ( mFields.toList() == tmpNewFields.toList() )
124  {
125  // the only change is a new field at the end
126  beginInsertRows( QModelIndex(), mFields.count() + offset, mFields.count() + offset );
127  mFields = newFields;
128  endInsertRows();
129  return;
130  }
131  }
132 
133  if ( mFields.count() == newFields.count() + 1 )
134  {
135  QgsFields tmpOldFields = mFields;
136  tmpOldFields.remove( tmpOldFields.count() - 1 );
137  if ( tmpOldFields.toList() == newFields.toList() )
138  {
139  // the only change is a field removed at the end
140  beginRemoveRows( QModelIndex(), mFields.count() - 1 + offset, mFields.count() - 1 + offset );
141  mFields = newFields;
142  endRemoveRows();
143  return;
144  }
145 
146  for ( int i = 0; i < newFields.count(); ++i )
147  {
148  if ( mFields.at( i ) != newFields.at( i ) )
149  {
150  QgsFields tmpOldFields = mFields;
151  tmpOldFields.remove( i );
152  if ( tmpOldFields.toList() != newFields.toList() )
153  break; // the change is more complex - go with general case
154 
155  // the only change is a field removed at index i
156  beginRemoveRows( QModelIndex(), i + offset, i + offset );
157  mFields = newFields;
158  endRemoveRows();
159  return;
160  }
161  }
162  }
163 
164  // general case with reset - not good - resets selections
165  beginResetModel();
166  mFields = mLayer->fields();
167  endResetModel();
168  }
169  else
170  emit dataChanged( index( 0 + offset, 0 ), index( rowCount(), 0 ) );
171  }
172  else
173  {
174  beginResetModel();
175  mFields = QgsFields();
176  endResetModel();
177  }
178 }
179 
181 {
182  if ( allowExpression == mAllowExpression )
183  return;
184 
186 
187  if ( !mAllowExpression )
188  {
189  int start = mFields.count();
190  int end = start + mExpression.count() - 1;
191  beginRemoveRows( QModelIndex(), start, end );
192  mExpression = QList<QString>();
193  endRemoveRows();
194  }
195 }
196 
198 {
199  if ( allowEmpty == mAllowEmpty )
200  return;
201 
202  if ( allowEmpty )
203  {
204  beginInsertRows( QModelIndex(), 0, 0 );
205  mAllowEmpty = true;
206  endInsertRows();
207  }
208  else
209  {
210  beginRemoveRows( QModelIndex(), 0, 0 );
211  mAllowEmpty = false;
212  endRemoveRows();
213  }
214 }
215 
216 
217 void QgsFieldModel::setExpression( const QString &expression )
218 {
219  if ( !mAllowExpression )
220  return;
221 
222  QModelIndex idx = indexFromName( expression );
223  if ( idx.isValid() )
224  return;
225 
226  beginResetModel();
227  mExpression = QList<QString>();
228  if ( !expression.isEmpty() )
229  mExpression << expression;
230  endResetModel();
231 }
232 
234 {
235  beginResetModel();
236  mExpression = QList<QString>();
237  endResetModel();
238 }
239 
240 QModelIndex QgsFieldModel::index( int row, int column, const QModelIndex &parent ) const
241 {
242  if ( hasIndex( row, column, parent ) )
243  {
244  return createIndex( row, column, row );
245  }
246 
247  return QModelIndex();
248 }
249 
250 QModelIndex QgsFieldModel::parent( const QModelIndex &child ) const
251 {
252  Q_UNUSED( child );
253  return QModelIndex();
254 }
255 
256 int QgsFieldModel::rowCount( const QModelIndex &parent ) const
257 {
258  if ( parent.isValid() )
259  {
260  return 0;
261  }
262 
263  return ( mAllowEmpty ? 1 : 0 ) + ( mAllowExpression ? mFields.count() + mExpression.count() : mFields.count() );
264 }
265 
266 int QgsFieldModel::columnCount( const QModelIndex &parent ) const
267 {
268  Q_UNUSED( parent );
269  return 1;
270 }
271 
272 QVariant QgsFieldModel::data( const QModelIndex &index, int role ) const
273 {
274  if ( !index.isValid() )
275  return QVariant();
276 
277  int exprIdx = index.row() - mFields.count();
278  if ( mAllowEmpty )
279  exprIdx--;
280  bool isEmpty = mAllowEmpty && index.row() == 0;
281  int fieldOffset = mAllowEmpty ? 1 : 0;
282 
283  switch ( role )
284  {
285  case FieldNameRole:
286  {
287  if ( isEmpty || exprIdx >= 0 )
288  {
289  return "";
290  }
291  QgsField field = mFields.at( index.row() - fieldOffset );
292  return field.name();
293  }
294 
295  case ExpressionRole:
296  {
297  if ( exprIdx >= 0 )
298  {
299  return mExpression.at( exprIdx );
300  }
301  else if ( isEmpty )
302  {
303  return QVariant();
304  }
305  else
306  {
307  QgsField field = mFields.at( index.row() - fieldOffset );
308  return field.name();
309  }
310  }
311 
312  case FieldIndexRole:
313  {
314  if ( isEmpty || exprIdx >= 0 )
315  {
316  return QVariant();
317  }
318  return index.row() - fieldOffset;
319  }
320 
321  case IsExpressionRole:
322  {
323  return exprIdx >= 0;
324  }
325 
327  {
328  if ( exprIdx >= 0 )
329  {
330  QgsExpression exp( mExpression.at( exprIdx ) );
331  QgsExpressionContext context;
332  if ( mLayer )
333  context.setFields( mLayer->fields() );
334 
335  exp.prepare( &context );
336  return !exp.hasParserError();
337  }
338  return true;
339  }
340 
341  case FieldTypeRole:
342  {
343  if ( exprIdx < 0 && !isEmpty )
344  {
345  QgsField field = mFields.at( index.row() - fieldOffset );
346  return static_cast< int >( field.type() );
347  }
348  return QVariant();
349  }
350 
351  case FieldOriginRole:
352  {
353  if ( exprIdx < 0 && !isEmpty )
354  {
355  return static_cast< int >( mFields.fieldOrigin( index.row() - fieldOffset ) );
356  }
357  return QVariant();
358  }
359 
360  case IsEmptyRole:
361  {
362  return isEmpty;
363  }
364 
365  case Qt::DisplayRole:
366  case Qt::EditRole:
367  {
368  if ( isEmpty )
369  {
370  return QVariant();
371  }
372  else if ( exprIdx >= 0 )
373  {
374  return mExpression.at( exprIdx );
375  }
376  else if ( role == Qt::EditRole )
377  {
378  return mFields.at( index.row() - fieldOffset ).name();
379  }
380  else if ( mLayer )
381  {
382  return mLayer->attributeDisplayName( index.row() - fieldOffset );
383  }
384  else
385  return QVariant();
386  }
387 
388  case Qt::ForegroundRole:
389  {
390  if ( !isEmpty && exprIdx >= 0 )
391  {
392  // if expression, test validity
393  QgsExpression exp( mExpression.at( exprIdx ) );
394  QgsExpressionContext context;
395  if ( mLayer )
396  context.setFields( mLayer->fields() );
397 
398  exp.prepare( &context );
399  if ( exp.hasParserError() )
400  {
401  return QBrush( QColor( Qt::red ) );
402  }
403  }
404  return QVariant();
405  }
406 
407  case Qt::FontRole:
408  {
409  if ( !isEmpty && exprIdx >= 0 )
410  {
411  // if the line is an expression, set it as italic
412  QFont font = QFont();
413  font.setItalic( true );
414  return font;
415  }
416  return QVariant();
417  }
418 
419  case Qt::DecorationRole:
420  {
421  if ( !isEmpty && exprIdx < 0 )
422  {
423  return mFields.iconForField( index.row() - fieldOffset );
424  }
425  return QIcon();
426  }
427 
428  default:
429  return QVariant();
430  }
431 }
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsStringMap attributeAliases() const
Returns a map of field name to attribute alias.
FieldOrigin fieldOrigin(int fieldIdx) const
Get field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:163
QString name
Definition: qgsfield.h:55
QIcon iconForField(int fieldIdx) const
Returns an icon corresponding to a field index, based on the field&#39;s type and source.
Definition: qgsfields.cpp:249
void setExpression(const QString &expression)
Sets a single expression to be added after the fields at the end of the model.
Return field index if index corresponds to a field.
Definition: qgsfieldmodel.h:47
Container of fields for a vector layer.
Definition: qgsfields.h:36
int count() const
Return number of items.
Definition: qgsfields.cpp:117
QgsVectorLayer * layer()
Returns the layer associated with the model.
Return field name if index corresponds to a field.
Definition: qgsfieldmodel.h:46
Return the field origin (if a field, returns QVariant if expression)
Definition: qgsfieldmodel.h:52
QgsFields fields() const
Returns the list of fields of this layer.
QgsField at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:137
QVariant data(const QModelIndex &index, int role) const override
QModelIndex parent(const QModelIndex &child) const override
QgsFieldModel(QObject *parent=nullptr)
Constructor for QgsFieldModel - creates a model to display the fields of a given layer.
int indexFromName(const QString &fieldName) const
Get the field index from the field name.
Definition: qgsfields.cpp:176
void setAllowEmptyFieldName(bool allowEmpty)
Sets whether an optional empty field ("not set") option is present in the model.
void removeExpression()
Removes any custom expression from the model.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setLayer(QgsVectorLayer *layer)
Set the layer from which fields are displayed.
Return if expression is valid or not.
Definition: qgsfieldmodel.h:50
void setAllowExpression(bool allowExpression)
Sets whether custom expressions are accepted and displayed in the model.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Return the field type (if a field, return QVariant if expression)
Definition: qgsfieldmodel.h:51
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:47
void remove(int fieldIdx)
Remove a field with the given index.
Definition: qgsfields.cpp:85
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
Return field name or expression.
Definition: qgsfieldmodel.h:48
int columnCount(const QModelIndex &parent) const override
Return if index corresponds to an expression.
Definition: qgsfieldmodel.h:49
Return if the index corresponds to the empty value.
Definition: qgsfieldmodel.h:53
bool isField(const QString &expression) const
Returns true if a string represents a field reference, or false if it is an expression consisting of ...
virtual void updateModel()
Called when the model must be updated.
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfields.cpp:186
QgsFields mFields
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QList< QString > mExpression
QgsVectorLayer * mLayer
QModelIndex indexFromName(const QString &fieldName)
Returns the index corresponding to a given fieldName.
Represents a vector layer which manages a vector based data sets.
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
Definition: qgsfield.cpp:98
QString attributeDisplayName(int index) const
Convenience function that returns the attribute alias if defined or the field name else...
bool allowExpression()
Returns true if the model allows custom expressions to be created and displayed.
Definition: qgsfieldmodel.h:77