QGIS API Documentation  2.14.0-Essen
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  static QIcon intIcon;
244  if ( intIcon.isNull() )
245  intIcon = QgsApplication::getThemeIcon( "/mIconFieldInteger.svg" );
246  static QIcon floatIcon;
247  if ( floatIcon.isNull() )
248  floatIcon = QgsApplication::getThemeIcon( "/mIconFieldFloat.svg" );
249  static QIcon stringIcon;
250  if ( stringIcon.isNull() )
251  stringIcon = QgsApplication::getThemeIcon( "/mIconFieldText.svg" );
252  static QIcon dateIcon;
253  if ( dateIcon.isNull() )
254  dateIcon = QgsApplication::getThemeIcon( "/mIconFieldDate.svg" );
255  static QIcon dateTimeIcon;
256  if ( dateTimeIcon.isNull() )
257  dateTimeIcon = QgsApplication::getThemeIcon( "/mIconFieldDateTime.svg" );
258  static QIcon timeIcon;
259  if ( timeIcon.isNull() )
260  timeIcon = QgsApplication::getThemeIcon( "/mIconFieldTime.svg" );
261 
262  if ( !index.isValid() )
263  return QVariant();
264 
265  int exprIdx = index.row() - mFields.count();
266 
267  switch ( role )
268  {
269  case FieldNameRole:
270  {
271  if ( exprIdx >= 0 )
272  {
273  return "";
274  }
275  QgsField field = mFields[index.row()];
276  return field.name();
277  }
278 
279  case ExpressionRole:
280  {
281  if ( exprIdx >= 0 )
282  {
283  return mExpression[exprIdx];
284  }
285  else
286  {
287  QgsField field = mFields[index.row()];
288  return field.name();
289  }
290  }
291 
292  case FieldIndexRole:
293  {
294  if ( exprIdx >= 0 )
295  {
296  return QVariant();
297  }
298  return index.row();
299  }
300 
301  case IsExpressionRole:
302  {
303  return exprIdx >= 0;
304  }
305 
307  {
308  if ( exprIdx >= 0 )
309  {
310  QgsExpression exp( mExpression[exprIdx] );
311  QgsExpressionContext context;
312  if ( mLayer )
313  context.setFields( mLayer->fields() );
314 
315  exp.prepare( &context );
316  return !exp.hasParserError();
317  }
318  return true;
319  }
320 
321  case FieldTypeRole:
322  {
323  if ( exprIdx < 0 )
324  {
325  QgsField field = mFields[index.row()];
326  return static_cast< int >( field.type() );
327  }
328  return QVariant();
329  }
330 
331  case Qt::DisplayRole:
332  case Qt::EditRole:
333  {
334  if ( exprIdx >= 0 )
335  {
336  return mExpression[exprIdx];
337  }
338  else if ( role == Qt::EditRole )
339  {
340  return mFields[index.row()].name();
341  }
342  else if ( mLayer )
343  {
344  return mLayer->attributeDisplayName( index.row() );
345  }
346  else
347  return QVariant();
348  }
349 
350  case Qt::ForegroundRole:
351  {
352  if ( exprIdx >= 0 )
353  {
354  // if expression, test validity
355  QgsExpression exp( mExpression[exprIdx] );
356  QgsExpressionContext context;
357  if ( mLayer )
358  context.setFields( mLayer->fields() );
359 
360  exp.prepare( &context );
361  if ( exp.hasParserError() )
362  {
363  return QBrush( QColor( Qt::red ) );
364  }
365  }
366  return QVariant();
367  }
368 
369  case Qt::FontRole:
370  {
371  if ( exprIdx >= 0 )
372  {
373  // if the line is an expression, set it as italic
374  QFont font = QFont();
375  font.setItalic( true );
376  return font;
377  }
378  return QVariant();
379  }
380 
381  case Qt::DecorationRole:
382  {
383  if ( exprIdx < 0 )
384  {
385  return mFields.iconForField( index.row() );
386  }
387  return QIcon();
388  }
389 
390  default:
391  return QVariant();
392  }
393 }
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:442
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.
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
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
bool isNull() const
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