QGIS API Documentation  2.17.0-Master (3a3b9ab7)
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.at( index.row() );
257  return field.name();
258  }
259 
260  case ExpressionRole:
261  {
262  if ( exprIdx >= 0 )
263  {
264  return mExpression.at( exprIdx );
265  }
266  else
267  {
268  QgsField field = mFields.at( 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.at( 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.at( index.row() );
307  return static_cast< int >( field.type() );
308  }
309  return QVariant();
310  }
311 
312  case FieldOriginRole:
313  {
314  if ( exprIdx < 0 )
315  {
316  return static_cast< int >( mFields.fieldOrigin( index.row() ) );
317  }
318  return QVariant();
319  }
320 
321  case Qt::DisplayRole:
322  case Qt::EditRole:
323  {
324  if ( exprIdx >= 0 )
325  {
326  return mExpression.at( exprIdx );
327  }
328  else if ( role == Qt::EditRole )
329  {
330  return mFields.at( index.row() ).name();
331  }
332  else if ( mLayer )
333  {
334  return mLayer->attributeDisplayName( index.row() );
335  }
336  else
337  return QVariant();
338  }
339 
340  case Qt::ForegroundRole:
341  {
342  if ( exprIdx >= 0 )
343  {
344  // if expression, test validity
345  QgsExpression exp( mExpression.at( exprIdx ) );
346  QgsExpressionContext context;
347  if ( mLayer )
348  context.setFields( mLayer->fields() );
349 
350  exp.prepare( &context );
351  if ( exp.hasParserError() )
352  {
353  return QBrush( QColor( Qt::red ) );
354  }
355  }
356  return QVariant();
357  }
358 
359  case Qt::FontRole:
360  {
361  if ( exprIdx >= 0 )
362  {
363  // if the line is an expression, set it as italic
364  QFont font = QFont();
365  font.setItalic( true );
366  return font;
367  }
368  return QVariant();
369  }
370 
371  case Qt::DecorationRole:
372  {
373  if ( exprIdx < 0 )
374  {
375  return mFields.iconForField( index.row() );
376  }
377  return QIcon();
378  }
379 
380  default:
381  return QVariant();
382  }
383 }
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:434
QObject * child(const char *objName, const char *inheritsClass, bool recursiveSearch) const
Class for parsing and evaluation of expressions (formerly called "search strings").
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:497
QString name
Definition: qgsfield.h:52
QgsFields fields() const
Returns the list of fields of this layer.
const T & at(int i) const
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:209
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
QgsVectorLayer * layer()
returns the currently used layer
Definition: qgsfieldmodel.h:69
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.
const char * name() const
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...
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:370
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:44
bool mAllowExpression
Definition: qgsfieldmodel.h:93
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:390
void remove(int fieldIdx)
Remove a field with the given index.
Definition: qgsfield.cpp:338
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:429
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()
FieldOrigin fieldOrigin(int fieldIdx) const
Get field&#39;s origin (value from an enumeration)
Definition: qgsfield.cpp:416
QgsFields mFields
Definition: qgsfieldmodel.h:89
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QList< QString > mExpression
Definition: qgsfieldmodel.h:90
QgsVectorLayer * mLayer
Definition: qgsfieldmodel.h:92
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:56