QGIS API Documentation  2.17.0-Master (0497e4a)
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
QObject * child(const char *objName, const char *inheritsClass, bool recursiveSearch) const
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: qgsfield.cpp:448
QString name
Definition: qgsfield.h:52
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:529
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:252
bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
int count() const
Return number of items.
Definition: qgsfield.cpp:402
QgsVectorLayer * layer()
returns the currently used layer
Definition: qgsfieldmodel.h:69
bool isField(const QString &expression)
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:422
bool isNull() const
QgsFields fields() const
Returns the list of fields of this layer.
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
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
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:44
bool mAllowExpression
Definition: qgsfieldmodel.h:93
void remove(int fieldIdx)
Remove a field with the given index.
Definition: qgsfield.cpp:370
void setFields(const QgsFields &fields)
Convenience function for setting a fields for the context.
QModelIndex createIndex(int row, int column, void *ptr) const
void setItalic(bool enable)
void beginInsertRows(const QModelIndex &parent, int first, int last)
const Key key(const T &value) const
int indexFromName(const QString &name) const
Look up field&#39;s index from name. Returns -1 on error.
Definition: qgsfield.cpp:461
int columnCount(const QModelIndex &parent) const override
virtual void updateModel()
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfield.cpp:466
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:97
QString attributeDisplayName(int attributeIndex) const
Convenience function that returns the attribute alias if defined or the field name else...
bool allowExpression()
Definition: qgsfieldmodel.h:56