QGIS API Documentation  2.17.0-Master (0497e4a)
qgsattributetablemodel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  QgsAttributeTableModel.cpp
3  --------------------------------------
4  Date : Feb 2009
5  Copyright : (C) 2009 Vita Cizek
6  Email : weetya (at) 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 "qgsapplication.h"
17 #include "qgsattributetablemodel.h"
19 
20 #include "qgsactionmanager.h"
22 #include "qgsexpression.h"
23 #include "qgsconditionalstyle.h"
24 #include "qgsfield.h"
25 #include "qgslogger.h"
26 #include "qgsmapcanvas.h"
28 #include "qgsmaplayerregistry.h"
29 #include "qgsrendererv2.h"
30 #include "qgsvectorlayer.h"
31 #include "qgsvectordataprovider.h"
32 #include "qgssymbollayerv2utils.h"
33 
34 #include <QVariant>
35 
36 #include <limits>
37 
39  : QAbstractTableModel( parent )
40  , mLayerCache( layerCache )
41  , mFieldCount( 0 )
42  , mSortCacheExpression( "" )
43  , mSortFieldIndex( -1 )
44  , mExtraColumns( 0 )
45 {
48  << QgsExpressionContextUtils::layerScope( layerCache->layer() );
49 
50  if ( layerCache->layer()->geometryType() == QGis::NoGeometry )
51  {
52  mFeatureRequest.setFlags( QgsFeatureRequest::NoGeometry );
53  }
54 
56 
57  if ( !layer()->hasGeometryType() )
58  mFeatureRequest.setFlags( QgsFeatureRequest::NoGeometry );
59 
61 
62  connect( mLayerCache, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ), this, SLOT( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ) );
63  connect( layer(), SIGNAL( featuresDeleted( QgsFeatureIds ) ), this, SLOT( featuresDeleted( QgsFeatureIds ) ) );
64  connect( layer(), SIGNAL( attributeDeleted( int ) ), this, SLOT( attributeDeleted( int ) ) );
65  connect( layer(), SIGNAL( updatedFields() ), this, SLOT( updatedFields() ) );
66  connect( layer(), SIGNAL( editCommandEnded() ), this, SLOT( editCommandEnded() ) );
67  connect( mLayerCache, SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( featureAdded( QgsFeatureId ) ) );
68  connect( mLayerCache, SIGNAL( cachedLayerDeleted() ), this, SLOT( layerDeleted() ) );
69 }
70 
71 bool QgsAttributeTableModel::loadFeatureAtId( QgsFeatureId fid ) const
72 {
73  QgsDebugMsgLevel( QString( "loading feature %1" ).arg( fid ), 3 );
74 
75  if ( fid == std::numeric_limits<int>::min() )
76  {
77  return false;
78  }
79 
80  return mLayerCache->featureAtId( fid, mFeat );
81 }
82 
84 {
85  return mExtraColumns;
86 }
87 
89 {
90  mExtraColumns = extraColumns;
92 }
93 
95 {
96  QList<int> rows;
97 
98  Q_FOREACH ( QgsFeatureId fid, fids )
99  {
100  QgsDebugMsgLevel( QString( "(%2) fid: %1, size: %3" ).arg( fid ).arg( mFeatureRequest.filterType() ).arg( mIdRowMap.size() ), 4 );
101 
102  int row = idToRow( fid );
103  if ( row != -1 )
104  rows << row;
105  }
106 
107  qSort( rows );
108 
109  int lastRow = -1;
110  int beginRow = -1;
111  int currentRowCount = 0;
112  int removedRows = 0;
113  bool reset = false;
114 
115  Q_FOREACH ( int row, rows )
116  {
117 #if 0
118  qDebug() << "Row: " << row << ", begin " << beginRow << ", last " << lastRow << ", current " << currentRowCount << ", removed " << removedRows;
119 #endif
120  if ( lastRow == -1 )
121  {
122  beginRow = row;
123  }
124 
125  if ( row != lastRow + 1 && lastRow != -1 )
126  {
127  if ( rows.count() > 100 && currentRowCount < 10 )
128  {
129  reset = true;
130  break;
131  }
132  removeRows( beginRow - removedRows, currentRowCount );
133 
134  beginRow = row;
135  removedRows += currentRowCount;
136  currentRowCount = 0;
137  }
138 
139  currentRowCount++;
140 
141  lastRow = row;
142  }
143 
144  if ( !reset )
145  removeRows( beginRow - removedRows, currentRowCount );
146  else
147  resetModel();
148 }
149 
150 bool QgsAttributeTableModel::removeRows( int row, int count, const QModelIndex &parent )
151 {
152  if ( row < 0 || count < 1 )
153  return false;
154 
155  beginRemoveRows( parent, row, row + count - 1 );
156 #ifdef QGISDEBUG
157  if ( 3 <= QgsLogger::debugLevel() )
158  QgsDebugMsgLevel( QString( "remove %2 rows at %1 (rows %3, ids %4)" ).arg( row ).arg( count ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 3 );
159 #endif
160 
161  // clean old references
162  for ( int i = row; i < row + count; i++ )
163  {
164  mSortCache.remove( mRowIdMap[i] );
165  mIdRowMap.remove( mRowIdMap[i] );
166  mRowIdMap.remove( i );
167  }
168 
169  // update maps
170  int n = mRowIdMap.size() + count;
171  for ( int i = row + count; i < n; i++ )
172  {
173  QgsFeatureId id = mRowIdMap[i];
174  mIdRowMap[id] -= count;
175  mRowIdMap[i-count] = id;
176  mRowIdMap.remove( i );
177  }
178 
179 #ifdef QGISDEBUG
180  if ( 4 <= QgsLogger::debugLevel() )
181  {
182  QgsDebugMsgLevel( QString( "after removal rows %1, ids %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 4 );
183  QgsDebugMsgLevel( "id->row", 4 );
185  QgsDebugMsgLevel( QString( "%1->%2" ).arg( FID_TO_STRING( it.key() ) ).arg( *it ), 4 );
186 
187  QgsDebugMsgLevel( "row->id", 4 );
189  QgsDebugMsgLevel( QString( "%1->%2" ).arg( it.key() ).arg( FID_TO_STRING( *it ) ), 4 );
190  }
191 #endif
192 
193  Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
194 
195  endRemoveRows();
196 
197  return true;
198 }
199 
201 {
202  QgsDebugMsgLevel( QString( "(%2) fid: %1" ).arg( fid ).arg( mFeatureRequest.filterType() ), 4 );
203  bool featOk = true;
204 
205  if ( mFeat.id() != fid )
206  featOk = loadFeatureAtId( fid );
207 
208  if ( featOk && mFeatureRequest.acceptFeature( mFeat ) )
209  {
210  if ( mSortFieldIndex == -1 )
211  {
213  mSortCache[mFeat.id()] = mSortCacheExpression.evaluate( &mExpressionContext );
214  }
215  else
216  {
217  QgsEditorWidgetFactory* widgetFactory = mWidgetFactories.at( mSortFieldIndex );
218  const QVariant& widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
219  const QgsEditorWidgetConfig& widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
220  QVariant sortValue = widgetFactory->representValue( layer(), mSortFieldIndex, widgetConfig, widgetCache, mFeat.attribute( mSortFieldIndex ) );
221  mSortCache.insert( mFeat.id(), sortValue );
222  }
223 
224  int n = mRowIdMap.size();
225  beginInsertRows( QModelIndex(), n, n );
226 
227  mIdRowMap.insert( fid, n );
228  mRowIdMap.insert( n, fid );
229 
230  endInsertRows();
231 
232  reload( index( rowCount() - 1, 0 ), index( rowCount() - 1, columnCount() ) );
233  }
234 }
235 
236 void QgsAttributeTableModel::updatedFields()
237 {
238  loadAttributes();
239  emit modelChanged();
240 }
241 
242 void QgsAttributeTableModel::editCommandEnded()
243 {
244  reload( createIndex( mChangedCellBounds.top(), mChangedCellBounds.left() ),
245  createIndex( mChangedCellBounds.bottom(), mChangedCellBounds.right() ) );
246 
247  mChangedCellBounds = QRect();
248 }
249 
250 void QgsAttributeTableModel::attributeDeleted( int idx )
251 {
252  if ( mSortCacheAttributes.contains( idx ) )
253  prefetchSortData( "" );
254 }
255 
257 {
258  removeRows( 0, rowCount() );
259 
261  mAttributes.clear();
264 }
265 
267 {
268  QgsDebugMsgLevel( QString( "(%4) fid: %1, idx: %2, value: %3" ).arg( fid ).arg( idx ).arg( value.toString() ).arg( mFeatureRequest.filterType() ), 3 );
269 
270  if ( mSortCacheAttributes.contains( idx ) )
271  {
272  if ( mSortFieldIndex == -1 )
273  {
274  loadFeatureAtId( fid );
276  mSortCache[fid] = mSortCacheExpression.evaluate( &mExpressionContext );
277  }
278  else
279  {
280  QgsEditorWidgetFactory* widgetFactory = mWidgetFactories.at( mSortFieldIndex );
281  const QVariant& widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
282  const QgsEditorWidgetConfig& widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
283  QVariant sortValue = widgetFactory->representValue( layer(), mSortFieldIndex, widgetConfig, widgetCache, value );
284  mSortCache.insert( fid, sortValue );
285  }
286  }
287  // No filter request: skip all possibly heavy checks
288  if ( mFeatureRequest.filterType() == QgsFeatureRequest::FilterNone )
289  {
290  setData( index( idToRow( fid ), fieldCol( idx ) ), value, Qt::EditRole );
291  }
292  else
293  {
294  if ( loadFeatureAtId( fid ) )
295  {
296  if ( mFeatureRequest.acceptFeature( mFeat ) )
297  {
298  if ( !mIdRowMap.contains( fid ) )
299  {
300  // Feature changed in such a way, it will be shown now
301  featureAdded( fid );
302  }
303  else
304  {
305  // Update representation
306  setData( index( idToRow( fid ), fieldCol( idx ) ), value, Qt::EditRole );
307  }
308  }
309  else
310  {
311  if ( mIdRowMap.contains( fid ) )
312  {
313  // Feature changed such, that it is no longer shown
314  featuresDeleted( QgsFeatureIds() << fid );
315  }
316  // else: we don't care
317  }
318  }
319  }
320 }
321 
323 {
324  if ( !layer() )
325  {
326  return;
327  }
328 
329  bool ins = false, rm = false;
330 
331  QgsAttributeList attributes;
332  const QgsFields& fields = layer()->fields();
333 
337 
338  for ( int idx = 0; idx < fields.count(); ++idx )
339  {
340  const QString widgetType = layer()->editFormConfig()->widgetType( idx );
341  QgsEditorWidgetFactory* widgetFactory = QgsEditorWidgetRegistry::instance()->factory( widgetType );
342  if ( widgetFactory )
343  {
344  mWidgetFactories.append( widgetFactory );
345  mWidgetConfigs.append( layer()->editFormConfig()->widgetConfig( idx ) );
346  mAttributeWidgetCaches.append( widgetFactory->createCache( layer(), idx, mWidgetConfigs.last() ) );
347 
348  attributes << idx;
349  }
350  }
351 
352  if ( mFieldCount + mExtraColumns < attributes.size() + mExtraColumns )
353  {
354  ins = true;
355  beginInsertColumns( QModelIndex(), mFieldCount + mExtraColumns, attributes.size() - 1 );
356  }
357  else if ( attributes.size() + mExtraColumns < mFieldCount + mExtraColumns )
358  {
359  rm = true;
360  beginRemoveColumns( QModelIndex(), attributes.size(), mFieldCount + mExtraColumns - 1 );
361  }
362 
363  mFieldCount = attributes.size();
364  mAttributes = attributes;
365 
366  if ( mSortFieldIndex >= mAttributes.count() )
367  mSortFieldIndex = -1;
368 
369  if ( ins )
370  {
372  }
373  else if ( rm )
374  {
376  }
377 }
378 
380 {
381  // make sure attributes are properly updated before caching the data
382  // (emit of progress() signal may enter event loop and thus attribute
383  // table view may be updated with inconsistent model which may assume
384  // wrong number of attributes)
385  loadAttributes();
386 
387  beginResetModel();
388 
389  if ( rowCount() != 0 )
390  {
391  removeRows( 0, rowCount() );
392  }
393 
394  QgsFeatureIterator features = mLayerCache->getFeatures( mFeatureRequest );
395 
396  int i = 0;
397 
398  QTime t;
399  t.start();
400 
401  while ( features.nextFeature( mFeat ) )
402  {
403  ++i;
404 
405  if ( t.elapsed() > 1000 )
406  {
407  bool cancel = false;
408  emit progress( i, cancel );
409  if ( cancel )
410  break;
411 
412  t.restart();
413  }
414  featureAdded( mFeat.id() );
415  }
416 
417  emit finished();
418 
419  connect( mLayerCache, SIGNAL( invalidated() ), this, SLOT( loadLayer() ), Qt::UniqueConnection );
420 
421  endResetModel();
422 }
423 
425 {
426  if ( fieldName.isNull() )
427  {
429  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, columnCount() - 1 ) );
430  return;
431  }
432 
433  int fieldIndex = mLayerCache->layer()->fieldNameIndex( fieldName );
434  if ( fieldIndex == -1 )
435  return;
436 
437  //whole column has changed
438  int col = fieldCol( fieldIndex );
439  emit dataChanged( index( 0, col ), index( rowCount() - 1, col ) );
440 }
441 
443 {
444  if ( a == b )
445  return;
446 
447  int rowA = idToRow( a );
448  int rowB = idToRow( b );
449 
450  //emit layoutAboutToBeChanged();
451 
452  mRowIdMap.remove( rowA );
453  mRowIdMap.remove( rowB );
454  mRowIdMap.insert( rowA, b );
455  mRowIdMap.insert( rowB, a );
456 
457  mIdRowMap.remove( a );
458  mIdRowMap.remove( b );
459  mIdRowMap.insert( a, rowB );
460  mIdRowMap.insert( b, rowA );
461 
462  //emit layoutChanged();
463 }
464 
466 {
467  if ( !mIdRowMap.contains( id ) )
468  {
469  QgsDebugMsg( QString( "idToRow: id %1 not in the map" ).arg( id ) );
470  return -1;
471  }
472 
473  return mIdRowMap[id];
474 }
475 
477 {
478  return index( idToRow( id ), 0 );
479 }
480 
482 {
483  QModelIndexList indexes;
484 
485  int row = idToRow( id );
486  int columns = columnCount();
487  indexes.reserve( columns );
488  for ( int column = 0; column < columns; ++column )
489  {
490  indexes.append( index( row, column ) );
491  }
492 
493  return indexes;
494 }
495 
497 {
498  if ( !mRowIdMap.contains( row ) )
499  {
500  QgsDebugMsg( QString( "rowToId: row %1 not in the map" ).arg( row ) );
501  // return negative infinite (to avoid collision with newly added features)
503  }
504 
505  return mRowIdMap[row];
506 }
507 
509 {
510  return mAttributes[col];
511 }
512 
514 {
515  return mAttributes.indexOf( idx );
516 }
517 
519 {
520  Q_UNUSED( parent );
521  return mRowIdMap.size();
522 }
523 
525 {
526  Q_UNUSED( parent );
527  return qMax( 1, mFieldCount + mExtraColumns ); // if there are zero columns all model indices will be considered invalid
528 }
529 
530 QVariant QgsAttributeTableModel::headerData( int section, Qt::Orientation orientation, int role ) const
531 {
532  if ( !layer() )
533  return QVariant();
534 
535  if ( role == Qt::DisplayRole )
536  {
537  if ( orientation == Qt::Vertical ) //row
538  {
539  return QVariant( section );
540  }
541  else if ( section >= 0 && section < mFieldCount )
542  {
543  QString attributeName = layer()->fields().at( mAttributes.at( section ) ).displayName();
544  return QVariant( attributeName );
545  }
546  else
547  {
548  return tr( "extra column" );
549  }
550  }
551  else if ( role == Qt::ToolTipRole )
552  {
553  if ( orientation == Qt::Vertical )
554  {
555  // TODO show DisplayExpression
556  return tr( "Feature ID: %1" ).arg( rowToId( section ) );
557  }
558  else
559  {
560  QgsField field = layer()->fields().at( mAttributes.at( section ) );
561  return field.name();
562  }
563  }
564  else
565  {
566  return QVariant();
567  }
568 }
569 
571 {
572  if ( !index.isValid() ||
573  ( role != Qt::TextAlignmentRole
574  && role != Qt::DisplayRole
575  && role != Qt::EditRole
576  && role != SortRole
577  && role != FeatureIdRole
578  && role != FieldIndexRole
579  && role != Qt::BackgroundColorRole
580  && role != Qt::TextColorRole
581  && role != Qt::DecorationRole
582  && role != Qt::FontRole
583  )
584  )
585  return QVariant();
586 
587  QgsFeatureId rowId = rowToId( index.row() );
588 
589  if ( role == FeatureIdRole )
590  return rowId;
591 
592  if ( index.column() >= mFieldCount )
593  return QVariant();
594 
595  int fieldId = mAttributes.at( index.column() );
596 
597  if ( role == FieldIndexRole )
598  return fieldId;
599 
600  if ( role == SortRole )
601  {
602  return mSortCache[rowId];
603  }
604 
605  QgsField field = layer()->fields().at( fieldId );
606 
607  if ( role == Qt::TextAlignmentRole )
608  {
609  return mWidgetFactories.at( index.column() )->alignmentFlag( layer(), fieldId, mWidgetConfigs.at( index.column() ) );
610  }
611 
612  if ( mFeat.id() != rowId || !mFeat.isValid() )
613  {
614  if ( !loadFeatureAtId( rowId ) )
615  return QVariant( "ERROR" );
616 
617  if ( mFeat.id() != rowId )
618  return QVariant( "ERROR" );
619  }
620 
621  QVariant val = mFeat.attribute( fieldId );
622 
623  switch ( role )
624  {
625  case Qt::DisplayRole:
626  return mWidgetFactories.at( index.column() )->representValue( layer(), fieldId, mWidgetConfigs.at( index.column() ),
627  mAttributeWidgetCaches.at( index.column() ), val );
628 
629  case Qt::EditRole:
630  return val;
631 
632  case Qt::BackgroundColorRole:
633  case Qt::TextColorRole:
634  case Qt::DecorationRole:
635  case Qt::FontRole:
636  {
639  if ( mRowStylesMap.contains( index.row() ) )
640  {
641  styles = mRowStylesMap[index.row()];
642  }
643  else
644  {
645  styles = QgsConditionalStyle::matchingConditionalStyles( layer()->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
646  mRowStylesMap.insert( index.row(), styles );
647 
648  }
649 
651  styles = layer()->conditionalStyles()->fieldStyles( field.name() );
653  styles.insert( 0, rowstyle );
655 
656  if ( style.isValid() )
657  {
658  if ( role == Qt::BackgroundColorRole && style.validBackgroundColor() )
659  return style.backgroundColor();
660  if ( role == Qt::TextColorRole && style.validTextColor() )
661  return style.textColor();
662  if ( role == Qt::DecorationRole )
663  return style.icon();
664  if ( role == Qt::FontRole )
665  return style.font();
666  }
667 
668  return QVariant();
669  }
670  }
671 
672  return QVariant();
673 }
674 
675 bool QgsAttributeTableModel::setData( const QModelIndex &index, const QVariant &value, int role )
676 {
677  Q_UNUSED( value )
678 
679  if ( !index.isValid() || index.column() >= mFieldCount || role != Qt::EditRole || !layer()->isEditable() )
680  return false;
681 
682  if ( !layer()->isModified() )
683  return false;
684 
685  if ( mChangedCellBounds.isNull() )
686  {
687  mChangedCellBounds = QRect( index.column(), index.row(), 1, 1 );
688  }
689  else
690  {
691  if ( index.column() < mChangedCellBounds.left() )
692  {
693  mChangedCellBounds.setLeft( index.column() );
694  }
695  if ( index.row() < mChangedCellBounds.top() )
696  {
697  mChangedCellBounds.setTop( index.row() );
698  }
699  if ( index.column() > mChangedCellBounds.right() )
700  {
701  mChangedCellBounds.setRight( index.column() );
702  }
703  if ( index.row() > mChangedCellBounds.bottom() )
704  {
705  mChangedCellBounds.setBottom( index.row() );
706  }
707  }
708 
709  return true;
710 }
711 
713 {
714  if ( !index.isValid() )
715  return Qt::ItemIsEnabled;
716 
717  if ( index.column() >= mFieldCount )
718  return Qt::NoItemFlags;
719 
721 
722  if ( layer()->isEditable() &&
723  !layer()->editFormConfig()->readOnly( mAttributes[index.column()] ) &&
724  (( layer()->dataProvider() && layer()->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) ||
725  FID_IS_NEW( rowToId( index.row() ) ) ) )
726  flags |= Qt::ItemIsEditable;
727 
728  return flags;
729 }
730 
731 void QgsAttributeTableModel::reload( const QModelIndex &index1, const QModelIndex &index2 )
732 {
734  emit dataChanged( index1, index2 );
735 }
736 
737 
738 void QgsAttributeTableModel::executeAction( int action, const QModelIndex &idx ) const
739 {
740  QgsFeature f = feature( idx );
741  layer()->actions()->doAction( action, f, fieldIdx( idx.column() ) );
742 }
743 
745 {
746  QgsFeature f = feature( idx );
747  action->triggerForFeature( layer(), &f );
748 }
749 
751 {
752  QgsFeature f;
754  f.setFeatureId( rowToId( idx.row() ) );
755  for ( int i = 0; i < mAttributes.size(); i++ )
756  {
757  f.setAttribute( mAttributes[i], data( index( idx.row(), i ), Qt::EditRole ) );
758  }
759 
760  return f;
761 }
762 
764 {
765  if ( column == -1 || column >= mAttributes.count() )
766  {
767  prefetchSortData( "" );
768  }
769  else
770  {
772  }
773 }
774 
775 void QgsAttributeTableModel::prefetchSortData( const QString& expressionString )
776 {
777  mSortCache.clear();
778  mSortCacheAttributes.clear();
779  mSortFieldIndex = -1;
780  mSortCacheExpression = QgsExpression( expressionString );
781 
782  QgsEditorWidgetFactory* widgetFactory = nullptr;
783  QVariant widgetCache;
784  QgsEditorWidgetConfig widgetConfig;
785 
786  if ( mSortCacheExpression.isField() )
787  {
788  QString fieldName = dynamic_cast<const QgsExpression::NodeColumnRef*>( mSortCacheExpression.rootNode() )->name();
789  mSortFieldIndex = mLayerCache->layer()->fieldNameIndex( fieldName );
790  }
791 
792  if ( mSortFieldIndex == -1 )
793  {
794  mSortCacheExpression.prepare( &mExpressionContext );
795 
796  Q_FOREACH ( const QString& col, mSortCacheExpression.referencedColumns() )
797  {
798  mSortCacheAttributes.append( mLayerCache->layer()->fieldNameIndex( col ) );
799  }
800  }
801  else
802  {
803  mSortCacheAttributes.append( mSortFieldIndex );
804 
805  widgetFactory = mWidgetFactories.at( mSortFieldIndex );
806  widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
807  widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
808  }
809 
810  QgsFeatureRequest request = QgsFeatureRequest( mFeatureRequest )
812  .setSubsetOfAttributes( mSortCacheAttributes );
813  QgsFeatureIterator it = mLayerCache->getFeatures( request );
814 
815  QgsFeature f;
816  while ( it.nextFeature( f ) )
817  {
818  if ( mSortFieldIndex == -1 )
819  {
821  mSortCache.insert( f.id(), mSortCacheExpression.evaluate( &mExpressionContext ) );
822  }
823  else
824  {
825  QVariant sortValue = widgetFactory->sortValue( layer(), mSortFieldIndex, widgetConfig, widgetCache, f.attribute( mSortFieldIndex ) );
826  mSortCache.insert( f.id(), sortValue );
827  }
828  }
829 }
830 
832 {
833  if ( mSortCacheExpression.rootNode() )
834  return mSortCacheExpression.expression();
835  else
836  return QString();
837 }
838 
840 {
841  mFeatureRequest = request;
842  if ( layer() && !layer()->hasGeometryType() )
843  mFeatureRequest.setFlags( mFeatureRequest.flags() | QgsFeatureRequest::NoGeometry );
844 }
845 
847 {
848  return mFeatureRequest;
849 }
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:199
void setRequest(const QgsFeatureRequest &request)
Set a request that will be used to fill this attribute table model.
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsActionManager * actions()
Get all layer actions defined on this layer.
void clear()
Wrapper for iterator of features from vector data provider or vector layer.
void setBottom(int y)
QgsVectorLayer * layer() const
Returns the layer this model uses as backend.
int extraColumns() const
Empty extra columns to announce from this model.
bool acceptFeature(const QgsFeature &feature)
Check if a feature is accepted by this requests filter.
virtual void featuresDeleted(const QgsFeatureIds &fids)
Launched when eatures have been deleted.
iterator insert(const Key &key, const T &value)
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before using this model as source for any oth...
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
Q_DECL_DEPRECATED QVariant evaluate(const QgsFeature *f)
Evaluate the feature and return the result.
const Flags & flags() const
QString name
Definition: qgsfield.h:52
QHash< int, QgsFeatureId > mRowIdMap
Get the field index of this column.
void append(const T &value)
int right() const
QgsEditorWidgetFactory * factory(const QString &widgetId)
Get a factory for the given widget type id.
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const
Q_DECL_DEPRECATED bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:439
virtual void layerDeleted()
Launched when layer has been deleted.
QStringList referencedColumns() const
Get list of columns referenced by the expression.
int size() const
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName)
Returns the conditional styles set for the field UI properties.
const T & at(int i) const
T & last()
void reload(const QModelIndex &index1, const QModelIndex &index2)
Reloads the model data between indices.
#define FID_TO_STRING(fid)
Definition: qgsfeature.h:89
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
FilterType filterType() const
Return the filter type which is currently set on this request.
Container of fields for a vector layer.
Definition: qgsfield.h:252
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:222
bool validBackgroundColor() const
Check if the background color is valid for render.
QPixmap icon() const
The icon set for style generated from the set symbol.
void fieldConditionalStyleChanged(const QString &fieldName)
Handles updating the model when the conditional style for a field changes.
QgsVectorLayer * layer()
Returns the layer to which this cache belongs.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
virtual bool isEditable() const override
Returns true if the provider is in editing mode.
static QgsEditorWidgetRegistry * instance()
This class is a singleton and has therefore to be accessed with this method instead of a constructor...
int count() const
Return number of items.
Definition: qgsfield.cpp:402
QString tr(const char *sourceText, const char *disambiguation, int n)
void resetModel()
Resets the model.
virtual QVariant createCache(QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config)
Create a cache for a given field.
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:422
QgsVectorLayerCache * mLayerCache
int size() const
bool isNull() const
QModelIndex idToIndex(QgsFeatureId id) const
QgsEditFormConfig * editFormConfig() const
Get the configuration of the form used to represent this vector layer.
QgsFields fields() const
Returns the list of fields of this layer.
QgsConditionalLayerStyles * conditionalStyles() const
Return the conditional styles that are set for this layer.
virtual void attributeValueChanged(QgsFeatureId fid, int idx, const QVariant &value)
Launched when attribute value has been changed.
virtual QVariant data(const QModelIndex &index, int role) const override
Returns data on the given index.
int indexOf(const T &value, int from) const
Get the feature id of the feature in this row.
const Node * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
QgsFeature feature(const QModelIndex &idx) const
Return the feature attributes at given model index.
const char * name() const
void clear()
bool isValid() const
int elapsed() const
int count(const T &value) const
QVariantMap QgsEditorWidgetConfig
Holds a set of configuration parameters for a editor widget wrapper.
void append(const T &value)
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Returns header data.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
virtual QVariant sortValue(QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config, const QVariant &cache, const QVariant &value) const
If the default sort order should be overwritten for this widget, you can transform the value in here...
Conditional styling for a rule.
const_iterator constEnd() const
void setFeatureId(QgsFeatureId id)
Sets the feature ID for this feature.
Definition: qgsfeature.cpp:101
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
void setExtraColumns(int extraColumns)
Empty extra columns to announce from this model.
void doAction(int index, const QgsFeature &feat, int defaultValueIndex=0)
Does the given values.
int top() const
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of columns.
QVector< QgsEditorWidgetFactory * > mWidgetFactories
QgsExpressionContext mExpressionContext
void setTop(int y)
int left() const
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:213
bool isValid() const
isValid Check if this rule is valid.
static QList< QgsConditionalStyle > matchingConditionalStyles(const QList< QgsConditionalStyle > &styles, const QVariant &value, QgsExpressionContext &context)
Find and return the matching styles for the value and feature.
void beginRemoveRows(const QModelIndex &parent, int first, int last)
int row() const
Every attribute editor widget needs a factory, which inherits this class.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void beginRemoveColumns(const QModelIndex &parent, int first, int last)
virtual QString representValue(QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config, const QVariant &cache, const QVariant &value) const
Create a pretty String representation of the value.
QColor backgroundColor() const
The background color for style.
int restart()
QVector< QgsEditorWidgetConfig > mWidgetConfigs
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
Remove rows.
QHash< QgsFeatureId, int > mIdRowMap
QgsFeatureRequest & setFlags(const QgsFeatureRequest::Flags &flags)
Set flags that affect how features will be fetched.
static QgsConditionalStyle compressStyles(const QList< QgsConditionalStyle > &styles)
Compress a list of styles into a single style.
QGis::GeometryType geometryType() const
Returns point, line or polygon.
const QgsFeatureRequest & request() const
Get the the feature request.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:44
int remove(const Key &key)
void executeAction(int action, const QModelIndex &idx) const
Execute an action.
virtual void featureAdded(QgsFeatureId fid)
Launched when a feature has been added.
QModelIndex createIndex(int row, int column, void *ptr) const
void clear()
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
QModelIndexList idToIndexList(QgsFeatureId id) const
QString expression() const
Return the original, unmodified expression string.
This class caches features of a given QgsVectorLayer.
bool contains(const T &value) const
static int debugLevel()
Reads the environment variable QGIS_DEBUG and converts it to int.
Definition: qgslogger.h:93
void progress(int i, bool &cancel)
void beginInsertRows(const QModelIndex &parent, int first, int last)
void modelChanged()
Model has been changed.
bool isNull() const
void setRight(int x)
QVector< QVariant > mAttributeWidgetCaches
const T & at(int i) const
const_iterator constBegin() const
QColor textColor() const
The text color set for style.
QgsAttributeTableModel(QgsVectorLayerCache *layerCache, QObject *parent=nullptr)
Constructor.
int fieldCol(int idx) const
get column from field index
No filter is applied.
int fieldIdx(int col) const
get field index from column
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of rows.
void insert(int i, const T &value)
bool featureAtId(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id.
bool validTextColor() const
Check if the text color is valid for render.
bool isField() const
Checks whether an expression consists only of a single field reference.
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
void executeMapLayerAction(QgsMapLayerAction *action, const QModelIndex &idx) const
Execute a QgsMapLayerAction.
int bottom() const
virtual void loadAttributes()
Gets mFieldCount, mAttributes and mValueMaps.
int column() const
QgsFeatureId rowToId(int row) const
Maps row to feature id.
qint64 QgsFeatureId
Definition: qgsfeature.h:31
QString sortCacheExpression() const
The expression which was used to fill the sorting cache.
void start()
virtual Qt::ItemFlags flags(const QModelIndex &index) const
#define FID_IS_NEW(fid)
Definition: qgsfeature.h:87
bool contains(const Key &key) const
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
QFont font() const
The font for the style.
double ANALYSIS_EXPORT min(double x, double y)
Returns the minimum of two doubles or the first argument if both are equal.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
void swapRows(QgsFeatureId a, QgsFeatureId b)
Swaps two rows.
bool nextFeature(QgsFeature &f)
QString widgetType(int fieldIdx) const
Get the id for the editor widget used to represent the field at the given index.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:271
QgsFeatureIterator getFeatures(const QgsFeatureRequest &featureRequest=QgsFeatureRequest())
Query this VectorLayerCache for features.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
void setLeft(int x)
void beginInsertColumns(const QModelIndex &parent, int first, int last)
int idToRow(QgsFeatureId id) const
Maps feature id to table row.
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Updates data on given index.
void triggerForFeature(QgsMapLayer *layer, const QgsFeature *feature)
Triggers the action with the specified layer and feature.
Allows modification of attribute values.
An action which can run on map layers.
void prefetchColumnData(int column)
Caches the entire data for one column.
QHash< int, QList< QgsConditionalStyle > > mRowStylesMap
void prefetchSortData(const QString &expression)
Prefetches the entire data for one expression.
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
Qt::ItemFlags flags(const QModelIndex &index) const override
Returns item flags for the index.
typedef ItemFlags