QGIS API Documentation
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 
25 
27  : QAbstractItemModel( parent )
28  , mLayer( nullptr )
29  , mAllowExpression( false )
30 {
31 }
32 
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  int r = mFields.indexFromName( fldName );
48  QModelIndex idx = index( r, 0 );
49  if ( idx.isValid() )
50  {
51  return idx;
52  }
53 
54  if ( mAllowExpression )
55  {
56  int exprIdx = mExpression.indexOf( fldName );
57  if ( exprIdx != -1 )
58  {
59  return index( mFields.count() + exprIdx, 0 );
60  }
61  }
62 
63  return QModelIndex();
64 }
65 
66 bool QgsFieldModel::isField( const QString& expression )
67 {
68  int index = mFields.indexFromName( expression );
69  return index >= 0;
70 }
71 
73 {
74  if ( mLayer )
75  {
76  disconnect( mLayer, SIGNAL( updatedFields() ), this, SLOT( updateModel() ) );
77  disconnect( mLayer, SIGNAL( layerDeleted() ), this, SLOT( layerDeleted() ) );
78  }
79 
80  mLayer = layer;
81 
82  if ( mLayer )
83  {
84  connect( mLayer, SIGNAL( updatedFields() ), this, SLOT( updateModel() ) );
85  connect( mLayer, SIGNAL( layerDeleted() ), this, SLOT( layerDeleted() ) );
86  }
87 
88  updateModel();
89 }
90 
91 void QgsFieldModel::layerDeleted()
92 {
93  mLayer = nullptr;
94  updateModel();
95 }
96 
98 {
99  if ( mLayer )
100  {
101  QgsFields newFields = mLayer->fields();
102  if ( mFields.toList() != newFields.toList() )
103  {
104  // Try to handle two special cases: addition of a new field and removal of a field.
105  // It would be better to listen directly to attributeAdded/attributeDeleted
106  // so we would not have to check for addition/removal here.
107 
108  if ( mFields.count() == newFields.count() - 1 )
109  {
110  QgsFields tmpNewFields = newFields;
111  tmpNewFields.remove( tmpNewFields.count() - 1 );
112  if ( mFields.toList() == tmpNewFields.toList() )
113  {
114  // the only change is a new field at the end
116  mFields = newFields;
117  endInsertRows();
118  return;
119  }
120  }
121 
122  if ( mFields.count() == newFields.count() + 1 )
123  {
124  QgsFields tmpOldFields = mFields;
125  tmpOldFields.remove( tmpOldFields.count() - 1 );
126  if ( tmpOldFields.toList() == newFields.toList() )
127  {
128  // the only change is a field removed at the end
130  mFields = newFields;
131  endRemoveRows();
132  return;
133  }
134 
135  for ( int i = 0; i < newFields.count(); ++i )
136  {
137  if ( mFields.at( i ) != newFields.at( i ) )
138  {
139  QgsFields tmpOldFields = mFields;
140  tmpOldFields.remove( i );
141  if ( tmpOldFields.toList() != newFields.toList() )
142  break; // the change is more complex - go with general case
143 
144  // the only change is a field removed at index i
145  beginRemoveRows( QModelIndex(), i, i );
146  mFields = newFields;
147  endRemoveRows();
148  return;
149  }
150  }
151  }
152 
153  // general case with reset - not good - resets selections
154  beginResetModel();
155  mFields = mLayer->fields();
156  endResetModel();
157  }
158  else
159  emit dataChanged( index( 0, 0 ), index( rowCount(), 0 ) );
160  }
161  else
162  {
163  beginResetModel();
164  mFields = QgsFields();
165  endResetModel();
166  }
167 }
168 
170 {
171  if ( allowExpression == mAllowExpression )
172  return;
173 
175 
176  if ( !mAllowExpression )
177  {
178  int start = mFields.count();
179  int end = start + mExpression.count() - 1;
180  beginRemoveRows( QModelIndex(), start, end );
182  endRemoveRows();
183  }
184 }
185 
186 void QgsFieldModel::setExpression( const QString &expression )
187 {
188  if ( !mAllowExpression )
189  return;
190 
191  QModelIndex idx = indexFromName( expression );
192  if ( idx.isValid() )
193  return;
194 
195  beginResetModel();
197  if ( !expression.isEmpty() )
198  mExpression << expression;
199  endResetModel();
200 }
201 
203 {
204  beginResetModel();
206  endResetModel();
207 }
208 
209 QModelIndex QgsFieldModel::index( int row, int column, const QModelIndex &parent ) const
210 {
211  if ( hasIndex( row, column, parent ) )
212  {
213  return createIndex( row, column, row );
214  }
215 
216  return QModelIndex();
217 }
218 
220 {
221  Q_UNUSED( child );
222  return QModelIndex();
223 }
224 
226 {
227  if ( parent.isValid() )
228  {
229  return 0;
230  }
231 
233 }
234 
236 {
237  Q_UNUSED( parent );
238  return 1;
239 }
240 
242 {
243  if ( !index.isValid() )
244  return QVariant();
245 
246  int exprIdx = index.row() - mFields.count();
247 
248  switch ( role )
249  {
250  case FieldNameRole:
251  {
252  if ( exprIdx >= 0 )
253  {
254  return "";
255  }
256  QgsField field = mFields[index.row()];
257  return field.name();
258  }
259 
260  case ExpressionRole:
261  {
262  if ( exprIdx >= 0 )
263  {
264  return mExpression[exprIdx];
265  }
266  else
267  {
268  QgsField field = mFields[index.row()];
269  return field.name();
270  }
271  }
272 
273  case FieldIndexRole:
274  {
275  if ( exprIdx >= 0 )
276  {
277  return QVariant();
278  }
279  return index.row();
280  }
281 
282  case IsExpressionRole:
283  {
284  return exprIdx >= 0;
285  }
286 
288  {
289  if ( exprIdx >= 0 )
290  {
291  QgsExpression exp( mExpression[exprIdx] );
292  QgsExpressionContext context;
293  if ( mLayer )
294  context.setFields( mLayer->fields() );
295 
296  exp.prepare( &context );
297  return !exp.hasParserError();
298  }
299  return true;
300  }
301 
302  case FieldTypeRole:
303  {
304  if ( exprIdx < 0 )
305  {
306  QgsField field = mFields[index.row()];
307  return static_cast< int >( field.type() );
308  }
309  return QVariant();
310  }
311 
312  case Qt::DisplayRole:
313  case Qt::EditRole:
314  {
315  if ( exprIdx >= 0 )
316  {
317  return mExpression[exprIdx];
318  }
319  else if ( role == Qt::EditRole )
320  {
321  return mFields[index.row()].name();
322  }
323  else if ( mLayer )
324  {
325  return mLayer->attributeDisplayName( index.row() );
326  }
327  else
328  return QVariant();
329  }
330 
331  case Qt::ForegroundRole:
332  {
333  if ( exprIdx >= 0 )
334  {
335  // if expression, test validity
336  QgsExpression exp( mExpression[exprIdx] );
337  QgsExpressionContext context;
338  if ( mLayer )
339  context.setFields( mLayer->fields() );
340 
341  exp.prepare( &context );
342  if ( exp.hasParserError() )
343  {
344  return QBrush( QColor( Qt::red ) );
345  }
346  }
347  return QVariant();
348  }
349 
350  case Qt::FontRole:
351  {
352  if ( exprIdx >= 0 )
353  {
354  // if the line is an expression, set it as italic
355  QFont font = QFont();
356  font.setItalic( true );
357  return font;
358  }
359  return QVariant();
360  }
361 
362  case Qt::DecorationRole:
363  {
364  if ( exprIdx < 0 )
365  {
366  return mFields.iconForField( index.row() );
367  }
368  return QIcon();
369  }
370 
371  default:
372  return QVariant();
373  }
374 }
bool hasIndex(int row, int column, const QModelIndex &parent) const
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfield.cpp:429
QObject * child(const char *objName, const char *inheritsClass, bool recursiveSearch) const
Class for parsing and evaluation of expressions (formerly called "search strings").
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
QIcon iconForField(int fieldIdx) const
Returns an icon corresponding to a field index, based on the field&#39;s type and source.
Definition: qgsfield.cpp:492
Q_DECL_DEPRECATED bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
QgsFields fields() const
Returns the list of fields of this layer.
void setExpression(const QString &expression)
setExpression sets a single expression to be added after the fields at the end of the model ...
Container of fields for a vector layer.
Definition: qgsfield.h:187
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QgsVectorLayer * layer()
returns the currently used layer
Definition: qgsfieldmodel.h:68
bool isField(const QString &expression)
bool isNull() const
int indexOf(const T &value, int from) const
QVariant data(const QModelIndex &index, int role) const override
QgsFieldModel(QObject *parent=nullptr)
QgsFieldModel creates a model to display the fields of a given layer.
bool isValid() const
int count(const T &value) const
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
void removeExpression()
remove expressions from the model
QString attributeDisplayName(int attributeIndex) const
Convenience function that returns the attribute alias if defined or the field name else...
QString name() const
Gets the name of the field.
Definition: qgsfield.cpp:84
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
bool isEmpty() const
void beginRemoveRows(const QModelIndex &parent, int first, int last)
void setLayer(QgsVectorLayer *layer)
set the layer of whch fields are displayed
int row() const
void setAllowExpression(bool allowExpression)
returns the currently used layer
int rowCount(const QModelIndex &parent=QModelIndex()) const override
int count() const
Return number of items.
Definition: qgsfield.cpp:365
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:44
bool mAllowExpression
Definition: qgsfieldmodel.h:92
const QMap< QString, QString > & attributeAliases() const
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:385
void remove(int fieldIdx)
Remove a field with the given index.
Definition: qgsfield.cpp:333
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
QModelIndex createIndex(int row, int column, void *ptr) const
int indexFromName(const QString &name) const
Look up field&#39;s index from name. Returns -1 on error.
Definition: qgsfield.cpp:424
void setItalic(bool enable)
void beginInsertRows(const QModelIndex &parent, int first, int last)
const Key key(const T &value) const
int columnCount(const QModelIndex &parent) const override
virtual void updateModel()
QgsFields mFields
Definition: qgsfieldmodel.h:88
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QList< QString > mExpression
Definition: qgsfieldmodel.h:89
QgsVectorLayer * mLayer
Definition: qgsfieldmodel.h:91
QModelIndex indexFromName(const QString &fieldName)
return the index corresponding to a given fieldName
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
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:89
bool allowExpression()
Definition: qgsfieldmodel.h:55