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