QGIS API Documentation  2.14.11-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 : denis.rouzaud@gmail.com
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
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.
Q_DECL_DEPRECATED bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
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
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)
int count() const
Return number of items.
Definition: qgsfield.cpp:365
QgsVectorLayer * layer()
returns the currently used layer
Definition: qgsfieldmodel.h:68
QString name() const
Gets the name of the field.
Definition: qgsfield.cpp:84
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:385
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.
bool isValid() const
int count(const T &value) const
const QMap< QString, QString > & attributeAliases() 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:92
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
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:424
int columnCount(const QModelIndex &parent) const override
bool isNull() const
virtual void updateModel()
QList< QgsField > toList() const
Utility function to return a list of QgsField instances.
Definition: qgsfield.cpp:429
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
QString attributeDisplayName(int attributeIndex) const
Convenience function that returns the attribute alias if defined or the field name else...
bool allowExpression()
Definition: qgsfieldmodel.h:55