QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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"
26 
27 QgsFieldModel::QgsFieldModel( QObject *parent )
28  : QAbstractItemModel( parent )
29 {
30 }
31 
32 QModelIndex QgsFieldModel::indexFromName( const QString &fieldName )
33 {
34  QString fldName( fieldName ); // we may need a copy
35 
36  if ( mLayer )
37  {
38  // the name could be an alias
39  // it would be better to have "display name" directly in QgsFields
40  // rather than having to consult layer in various places in code!
41  QString fieldNameWithAlias = mLayer->attributeAliases().key( fldName );
42  if ( !fieldNameWithAlias.isNull() )
43  fldName = fieldNameWithAlias;
44  }
45 
46  if ( mAllowEmpty && fieldName.isEmpty() )
47  return index( 0, 0 );
48 
49  int r = mFields.lookupField( fldName );
50  if ( r >= 0 )
51  {
52  if ( mAllowEmpty )
53  r++;
54 
55  QModelIndex idx = index( r, 0 );
56  if ( idx.isValid() )
57  {
58  return idx;
59  }
60  }
61 
62  if ( mAllowExpression )
63  {
64  int exprIdx = mExpression.indexOf( fldName );
65  if ( exprIdx != -1 )
66  {
67  return index( ( mAllowEmpty ? 1 : 0 ) + mFields.count() + exprIdx, 0 );
68  }
69  }
70 
71  return QModelIndex();
72 }
73 
74 bool QgsFieldModel::isField( const QString &expression ) const
75 {
76  int index = mFields.indexFromName( expression );
77  return index >= 0;
78 }
79 
81 {
82  if ( mLayer )
83  {
85  disconnect( mLayer, &QObject::destroyed, this, &QgsFieldModel::layerDeleted );
86  }
87 
88  mLayer = layer;
89 
90  if ( mLayer )
91  {
93  connect( mLayer, &QObject::destroyed, this, &QgsFieldModel::layerDeleted );
94  }
95 
96  updateModel();
97 }
98 
99 void QgsFieldModel::layerDeleted()
100 {
101  mLayer = nullptr;
102  updateModel();
103 }
104 
106 {
107  int offset = mAllowEmpty ? 1 : 0;
108  if ( mLayer )
109  {
110  QgsFields newFields = mLayer->fields();
111  if ( mFields.toList() != newFields.toList() )
112  {
113  // Try to handle two special cases: addition of a new field and removal of a field.
114  // It would be better to listen directly to attributeAdded/attributeDeleted
115  // so we would not have to check for addition/removal here.
116 
117  if ( mFields.count() == newFields.count() - 1 )
118  {
119  QgsFields tmpNewFields = newFields;
120  tmpNewFields.remove( tmpNewFields.count() - 1 );
121  if ( mFields.toList() == tmpNewFields.toList() )
122  {
123  // the only change is a new field at the end
124  beginInsertRows( QModelIndex(), mFields.count() + offset, mFields.count() + offset );
125  mFields = newFields;
126  endInsertRows();
127  return;
128  }
129  }
130 
131  if ( mFields.count() == newFields.count() + 1 )
132  {
133  QgsFields tmpOldFields = mFields;
134  tmpOldFields.remove( tmpOldFields.count() - 1 );
135  if ( tmpOldFields.toList() == newFields.toList() )
136  {
137  // the only change is a field removed at the end
138  beginRemoveRows( QModelIndex(), mFields.count() - 1 + offset, mFields.count() - 1 + offset );
139  mFields = newFields;
140  endRemoveRows();
141  return;
142  }
143 
144  for ( int i = 0; i < newFields.count(); ++i )
145  {
146  if ( mFields.at( i ) != newFields.at( i ) )
147  {
148  QgsFields tmpOldFields = mFields;
149  tmpOldFields.remove( i );
150  if ( tmpOldFields.toList() != newFields.toList() )
151  break; // the change is more complex - go with general case
152 
153  // the only change is a field removed at index i
154  beginRemoveRows( QModelIndex(), i + offset, i + offset );
155  mFields = newFields;
156  endRemoveRows();
157  return;
158  }
159  }
160  }
161 
162  // general case with reset - not good - resets selections
163  beginResetModel();
164  mFields = mLayer->fields();
165  endResetModel();
166  }
167  else
168  emit dataChanged( index( 0 + offset, 0 ), index( rowCount(), 0 ) );
169  }
170  else
171  {
172  beginResetModel();
173  mFields = QgsFields();
174  endResetModel();
175  }
176 }
177 
179 {
180  if ( allowExpression == mAllowExpression )
181  return;
182 
184 
185  if ( !mAllowExpression )
186  {
187  int start = mFields.count();
188  int end = start + mExpression.count() - 1;
189  beginRemoveRows( QModelIndex(), start, end );
190  mExpression = QList<QString>();
191  endRemoveRows();
192  }
193 }
194 
196 {
197  if ( allowEmpty == mAllowEmpty )
198  return;
199 
200  if ( allowEmpty )
201  {
202  beginInsertRows( QModelIndex(), 0, 0 );
203  mAllowEmpty = true;
204  endInsertRows();
205  }
206  else
207  {
208  beginRemoveRows( QModelIndex(), 0, 0 );
209  mAllowEmpty = false;
210  endRemoveRows();
211  }
212 }
213 
214 
215 void QgsFieldModel::setExpression( const QString &expression )
216 {
217  if ( !mAllowExpression )
218  return;
219 
220  QModelIndex idx = indexFromName( expression );
221  if ( idx.isValid() )
222  return;
223 
224  beginResetModel();
225  mExpression = QList<QString>();
226  if ( !expression.isEmpty() )
227  mExpression << expression;
228  endResetModel();
229 }
230 
232 {
233  beginResetModel();
234  mExpression = QList<QString>();
235  endResetModel();
236 }
237 
238 QModelIndex QgsFieldModel::index( int row, int column, const QModelIndex &parent ) const
239 {
240  if ( hasIndex( row, column, parent ) )
241  {
242  return createIndex( row, column, row );
243  }
244 
245  return QModelIndex();
246 }
247 
248 QModelIndex QgsFieldModel::parent( const QModelIndex &child ) const
249 {
250  Q_UNUSED( child )
251  return QModelIndex();
252 }
253 
254 int QgsFieldModel::rowCount( const QModelIndex &parent ) const
255 {
256  if ( parent.isValid() )
257  {
258  return 0;
259  }
260 
261  return ( mAllowEmpty ? 1 : 0 ) + ( mAllowExpression ? mFields.count() + mExpression.count() : mFields.count() );
262 }
263 
264 int QgsFieldModel::columnCount( const QModelIndex &parent ) const
265 {
266  Q_UNUSED( parent )
267  return 1;
268 }
269 
270 QVariant QgsFieldModel::data( const QModelIndex &index, int role ) const
271 {
272  if ( !index.isValid() )
273  return QVariant();
274 
275  int exprIdx = index.row() - mFields.count();
276  if ( mAllowEmpty )
277  exprIdx--;
278  bool isEmpty = mAllowEmpty && index.row() == 0;
279  int fieldOffset = mAllowEmpty ? 1 : 0;
280 
281  switch ( role )
282  {
283  case FieldNameRole:
284  {
285  if ( isEmpty || exprIdx >= 0 )
286  {
287  return "";
288  }
289  QgsField field = mFields.at( index.row() - fieldOffset );
290  return field.name();
291  }
292 
293  case ExpressionRole:
294  {
295  if ( exprIdx >= 0 )
296  {
297  return mExpression.at( exprIdx );
298  }
299  else if ( isEmpty )
300  {
301  return QVariant();
302  }
303  else
304  {
305  QgsField field = mFields.at( index.row() - fieldOffset );
306  return field.name();
307  }
308  }
309 
310  case FieldIndexRole:
311  {
312  if ( isEmpty || exprIdx >= 0 )
313  {
314  return QVariant();
315  }
316  return index.row() - fieldOffset;
317  }
318 
319  case IsExpressionRole:
320  {
321  return exprIdx >= 0;
322  }
323 
325  {
326  if ( exprIdx >= 0 )
327  {
328  QgsExpression exp( mExpression.at( exprIdx ) );
329  QgsExpressionContext context;
330  if ( mLayer )
331  context.setFields( mLayer->fields() );
332 
333  exp.prepare( &context );
334  return !exp.hasParserError();
335  }
336  return true;
337  }
338 
339  case FieldTypeRole:
340  {
341  if ( exprIdx < 0 && !isEmpty )
342  {
343  QgsField field = mFields.at( index.row() - fieldOffset );
344  return static_cast< int >( field.type() );
345  }
346  return QVariant();
347  }
348 
349  case FieldOriginRole:
350  {
351  if ( exprIdx < 0 && !isEmpty )
352  {
353  return static_cast< int >( mFields.fieldOrigin( index.row() - fieldOffset ) );
354  }
355  return QVariant();
356  }
357 
358  case IsEmptyRole:
359  {
360  return isEmpty;
361  }
362 
363  case EditorWidgetType:
364  {
365  if ( exprIdx < 0 && !isEmpty )
366  {
367  return mFields.at( index.row() - fieldOffset ).editorWidgetSetup().type();
368  }
369  return QVariant();
370  }
371 
373  {
374  if ( exprIdx < 0 && !isEmpty )
375  {
376  if ( mLayer && mFields.fieldOrigin( index.row() - fieldOffset ) == QgsFields::OriginJoin )
377  {
378  int srcFieldIndex;
379  const QgsVectorLayerJoinInfo *info = mLayer->joinBuffer()->joinForFieldIndex( index.row() - fieldOffset, mLayer->fields(), srcFieldIndex );
380 
381  if ( !info || !info->isEditable() )
382  return false;
383 
384  return true;
385  }
386  }
387  return QVariant();
388  }
389 
390  case Qt::DisplayRole:
391  case Qt::EditRole:
392  case Qt::ToolTipRole:
393  {
394  if ( isEmpty )
395  {
396  return QVariant();
397  }
398  else if ( exprIdx >= 0 )
399  {
400  return mExpression.at( exprIdx );
401  }
402  else if ( role == Qt::EditRole )
403  {
404  return mFields.at( index.row() - fieldOffset ).name();
405  }
406  else if ( role == Qt::ToolTipRole )
407  {
408  return fieldToolTip( mFields.at( index.row() - fieldOffset ) );
409  }
410  else if ( mLayer )
411  {
412  return mLayer->attributeDisplayName( index.row() - fieldOffset );
413  }
414  else
415  return QVariant();
416  }
417 
418  case Qt::ForegroundRole:
419  {
420  if ( !isEmpty && exprIdx >= 0 )
421  {
422  // if expression, test validity
423  QgsExpression exp( mExpression.at( exprIdx ) );
424  QgsExpressionContext context;
425  if ( mLayer )
426  context.setFields( mLayer->fields() );
427 
428  exp.prepare( &context );
429  if ( exp.hasParserError() )
430  {
431  return QBrush( QColor( Qt::red ) );
432  }
433  }
434  return QVariant();
435  }
436 
437  case Qt::FontRole:
438  {
439  if ( !isEmpty && exprIdx >= 0 )
440  {
441  // if the line is an expression, set it as italic
442  QFont font = QFont();
443  font.setItalic( true );
444  return font;
445  }
446  return QVariant();
447  }
448 
449  case Qt::DecorationRole:
450  {
451  if ( !isEmpty && exprIdx < 0 )
452  {
453  return mFields.iconForField( index.row() - fieldOffset );
454  }
455  return QIcon();
456  }
457 
458  default:
459  return QVariant();
460  }
461 }
462 
463 QString QgsFieldModel::fieldToolTip( const QgsField &field )
464 {
465  QString toolTip;
466  if ( !field.alias().isEmpty() )
467  {
468  toolTip = QStringLiteral( "<b>%1</b> (%2)" ).arg( field.alias(), field.name() );
469  }
470  else
471  {
472  toolTip = QStringLiteral( "<b>%1</b>" ).arg( field.name() );
473  }
474  QString typeString;
475  if ( field.length() > 0 )
476  {
477  if ( field.precision() > 0 )
478  {
479  typeString = QStringLiteral( "%1 (%2, %3)" ).arg( field.typeName() ).arg( field.length() ).arg( field.precision() );
480  }
481  else
482  {
483  typeString = QStringLiteral( "%1 (%2)" ).arg( field.typeName() ).arg( field.length() );
484  }
485  }
486  else
487  {
488  typeString = field.typeName();
489  }
490  toolTip += QStringLiteral( "<p>%1</p>" ).arg( typeString );
491  return toolTip;
492 }
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:324
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsStringMap attributeAliases() const
Returns a map of field name to attribute alias.
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
Definition: qgsfields.h:50
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:189
QString name
Definition: qgsfield.h:58
int precision
Definition: qgsfield.h:55
QString alias
Definition: qgsfield.h:59
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:275
static QString fieldToolTip(const QgsField &field)
Returns a HTML formatted tooltip string for a field, containing details like the field name...
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:42
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
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
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
int length
Definition: qgsfield.h:54
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
Gets the field index from the field name.
Definition: qgsfields.cpp:202
QgsFields fields() const FINAL
Returns the list of fields of this layer.
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.
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:105
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Defines left outer join from our vector layer to some other vector layer.
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:48
true if a joined field is editable (returns QVariant if not a joined field)
Definition: qgsfieldmodel.h:59
void remove(int fieldIdx)
Removes a field with the given index.
Definition: qgsfields.cpp:101
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
Return field name or expression.
Definition: qgsfieldmodel.h:52
QgsVectorLayerJoinBuffer * joinBuffer()
Returns the join buffer object.
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:212
const QgsVectorLayerJoinInfo * joinForFieldIndex(int index, const QgsFields &fields, int &sourceFieldIndex) const
Finds the vector join for a layer field index.
QgsFields mFields
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QList< QString > mExpression
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer. ...
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.
void updatedFields()
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...
QVariant::Type type
Definition: qgsfield.h:56
bool allowExpression()
Returns true if the model allows custom expressions to be created and displayed.
Definition: qgsfieldmodel.h:83