QGIS API Documentation  2.12.0-Lyon
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 
18 #include "qgsfieldmodel.h"
19 #include "qgsmaplayermodel.h"
20 #include "qgsmaplayerproxymodel.h"
21 #include "qgslogger.h"
22 
23 
25  : QAbstractItemModel( parent )
26  , mLayer( NULL )
27  , mAllowExpression( false )
28 {
29 }
30 
32 {
33  QString fldName( fieldName ); // we may need a copy
34 
35  if ( mLayer )
36  {
37  // the name could be an alias
38  // it would be better to have "display name" directly in QgsFields
39  // rather than having to consult layer in various places in code!
40  QString fieldNameWithAlias = mLayer->attributeAliases().key( fldName );
41  if ( !fieldNameWithAlias.isNull() )
42  fldName = fieldNameWithAlias;
43  }
44 
45  int r = mFields.indexFromName( fldName );
46  QModelIndex idx = index( r, 0 );
47  if ( idx.isValid() )
48  {
49  return idx;
50  }
51 
52  if ( mAllowExpression )
53  {
54  int exprIdx = mExpression.indexOf( fldName );
55  if ( exprIdx != -1 )
56  {
57  return index( mFields.count() + exprIdx, 0 );
58  }
59  }
60 
61  return QModelIndex();
62 }
63 
64 bool QgsFieldModel::isField( const QString& expression )
65 {
66  int index = mFields.indexFromName( expression );
67  return index >= 0;
68 }
69 
71 {
72  if ( mLayer )
73  {
74  disconnect( mLayer, SIGNAL( updatedFields() ), this, SLOT( updateModel() ) );
75  disconnect( mLayer, SIGNAL( layerDeleted() ), this, SLOT( layerDeleted() ) );
76  }
77 
78  mLayer = layer;
79 
80  if ( mLayer )
81  {
82  connect( mLayer, SIGNAL( updatedFields() ), this, SLOT( updateModel() ) );
83  connect( mLayer, SIGNAL( layerDeleted() ), this, SLOT( layerDeleted() ) );
84  }
85 
86  updateModel();
87 }
88 
89 void QgsFieldModel::layerDeleted()
90 {
91  mLayer = 0;
92  updateModel();
93 }
94 
96 {
97  if ( mLayer )
98  {
99  QgsFields newFields = mLayer->fields();
100  if ( mFields.toList() != newFields.toList() )
101  {
102  // Try to handle two special cases: addition of a new field and removal of a field.
103  // It would be better to listen directly to attributeAdded/attributeDeleted
104  // so we would not have to check for addition/removal here.
105 
106  if ( mFields.count() == newFields.count() - 1 )
107  {
108  QgsFields tmpNewFields = newFields;
109  tmpNewFields.remove( tmpNewFields.count() - 1 );
110  if ( mFields.toList() == tmpNewFields.toList() )
111  {
112  // the only change is a new field at the end
114  mFields = newFields;
115  endInsertRows();
116  return;
117  }
118  }
119 
120  if ( mFields.count() == newFields.count() + 1 )
121  {
122  QgsFields tmpOldFields = mFields;
123  tmpOldFields.remove( tmpOldFields.count() - 1 );
124  if ( tmpOldFields.toList() == newFields.toList() )
125  {
126  // the only change is a field removed at the end
128  mFields = newFields;
129  endRemoveRows();
130  return;
131  }
132 
133  for ( int i = 0; i < newFields.count(); ++i )
134  {
135  if ( mFields.at( i ) != newFields.at( i ) )
136  {
137  QgsFields tmpOldFields = mFields;
138  tmpOldFields.remove( i );
139  if ( tmpOldFields.toList() != newFields.toList() )
140  break; // the change is more complex - go with general case
141 
142  // the only change is a field removed at index i
143  beginRemoveRows( QModelIndex(), i, i );
144  mFields = newFields;
145  endRemoveRows();
146  return;
147  }
148  }
149  }
150 
151  // general case with reset - not good - resets selections
152  beginResetModel();
153  mFields = mLayer->fields();
154  endResetModel();
155  }
156  else
157  emit dataChanged( index( 0, 0 ), index( rowCount(), 0 ) );
158  }
159  else
160  {
161  beginResetModel();
162  mFields = QgsFields();
163  endResetModel();
164  }
165 }
166 
167 void QgsFieldModel::setAllowExpression( bool allowExpression )
168 {
169  if ( allowExpression == mAllowExpression )
170  return;
171 
173 
174  if ( !mAllowExpression )
175  {
176  int start = mFields.count();
177  int end = start + mExpression.count() - 1;
178  beginRemoveRows( QModelIndex(), start, end );
180  endRemoveRows();
181  }
182 }
183 
184 void QgsFieldModel::setExpression( const QString &expression )
185 {
186  if ( !mAllowExpression )
187  return;
188 
189  QModelIndex idx = indexFromName( expression );
190  if ( idx.isValid() )
191  return;
192 
193  beginResetModel();
195  if ( !expression.isEmpty() )
196  mExpression << expression;
197  endResetModel();
198 }
199 
201 {
202  beginResetModel();
204  endResetModel();
205 }
206 
207 QModelIndex QgsFieldModel::index( int row, int column, const QModelIndex &parent ) const
208 {
209  if ( hasIndex( row, column, parent ) )
210  {
211  return createIndex( row, column, row );
212  }
213 
214  return QModelIndex();
215 }
216 
218 {
219  Q_UNUSED( child );
220  return QModelIndex();
221 }
222 
223 int QgsFieldModel::rowCount( const QModelIndex &parent ) const
224 {
225  if ( parent.isValid() )
226  {
227  return 0;
228  }
229 
231 }
232 
233 int QgsFieldModel::columnCount( const QModelIndex &parent ) const
234 {
235  Q_UNUSED( parent );
236  return 1;
237 }
238 
240 {
241  if ( !index.isValid() )
242  return QVariant();
243 
244  int exprIdx = index.row() - mFields.count();
245 
246  switch ( role )
247  {
248  case FieldNameRole:
249  {
250  if ( exprIdx >= 0 )
251  {
252  return "";
253  }
254  QgsField field = mFields[index.row()];
255  return field.name();
256  }
257 
258  case ExpressionRole:
259  {
260  if ( exprIdx >= 0 )
261  {
262  return mExpression[exprIdx];
263  }
264  else
265  {
266  QgsField field = mFields[index.row()];
267  return field.name();
268  }
269  }
270 
271  case FieldIndexRole:
272  {
273  if ( exprIdx >= 0 )
274  {
275  return QVariant();
276  }
277  return index.row();
278  }
279 
280  case IsExpressionRole:
281  {
282  return exprIdx >= 0;
283  }
284 
286  {
287  if ( exprIdx >= 0 )
288  {
289  QgsExpression exp( mExpression[exprIdx] );
290  QgsExpressionContext context;
291  if ( mLayer )
292  context.setFields( mLayer->fields() );
293 
294  exp.prepare( &context );
295  return !exp.hasParserError();
296  }
297  return true;
298  }
299 
300  case FieldTypeRole:
301  {
302  if ( exprIdx < 0 )
303  {
304  QgsField field = mFields[index.row()];
305  return ( int )field.type();
306  }
307  return QVariant();
308  }
309 
310  case Qt::DisplayRole:
311  case Qt::EditRole:
312  {
313  if ( exprIdx >= 0 )
314  {
315  return mExpression[exprIdx];
316  }
317  else if ( role == Qt::EditRole )
318  {
319  return mFields[index.row()].name();
320  }
321  else if ( mLayer )
322  {
323  return mLayer->attributeDisplayName( index.row() );
324  }
325  else
326  return QVariant();
327  }
328 
329  case Qt::ForegroundRole:
330  {
331  if ( exprIdx >= 0 )
332  {
333  // if expression, test validity
334  QgsExpression exp( mExpression[exprIdx] );
335  QgsExpressionContext context;
336  if ( mLayer )
337  context.setFields( mLayer->fields() );
338 
339  exp.prepare( &context );
340  if ( exp.hasParserError() )
341  {
342  return QBrush( QColor( Qt::red ) );
343  }
344  }
345  return QVariant();
346  }
347 
348  case Qt::FontRole:
349  {
350  if ( exprIdx >= 0 )
351  {
352  // if the line is an expression, set it as italic
353  QFont font = QFont();
354  font.setItalic( true );
355  return font;
356  }
357  return QVariant();
358  }
359 
360  default:
361  return QVariant();
362  }
363 }
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:369
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:92
const QString & name() const
Gets the name of the field.
Definition: qgsfield.cpp:72
static unsigned index
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
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:177
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
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:311
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:40
bool mAllowExpression
Definition: qgsfieldmodel.h:85
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:331
void remove(int fieldIdx)
Remove a field with the given index.
Definition: qgsfield.cpp:285
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's index from name. Returns -1 on error.
Definition: qgsfield.cpp:364
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()
QgsFieldModel(QObject *parent=0)
QgsFieldModel creates a model to display the fields of a given layer.
QgsFields mFields
Definition: qgsfieldmodel.h:81
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
QList< QString > mExpression
Definition: qgsfieldmodel.h:82
QgsVectorLayer * mLayer
Definition: qgsfieldmodel.h:84
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:77
bool allowExpression()
Definition: qgsfieldmodel.h:55