QGIS API Documentation  2.17.0-Master (6f7b933)
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()->attributeAlias( mAttributes.at( section ) );
544  if ( attributeName.isEmpty() )
545  {
546  QgsField field = layer()->fields().at( mAttributes.at( section ) );
547  attributeName = field.name();
548  }
549  return QVariant( attributeName );
550  }
551  else
552  {
553  return tr( "extra column" );
554  }
555  }
556  else if ( role == Qt::ToolTipRole )
557  {
558  if ( orientation == Qt::Vertical )
559  {
560  // TODO show DisplayExpression
561  return tr( "Feature ID: %1" ).arg( rowToId( section ) );
562  }
563  else
564  {
565  QgsField field = layer()->fields().at( mAttributes.at( section ) );
566  return field.name();
567  }
568  }
569  else
570  {
571  return QVariant();
572  }
573 }
574 
576 {
577  if ( !index.isValid() ||
578  ( role != Qt::TextAlignmentRole
579  && role != Qt::DisplayRole
580  && role != Qt::EditRole
581  && role != SortRole
582  && role != FeatureIdRole
583  && role != FieldIndexRole
584  && role != Qt::BackgroundColorRole
585  && role != Qt::TextColorRole
586  && role != Qt::DecorationRole
587  && role != Qt::FontRole
588  )
589  )
590  return QVariant();
591 
592  QgsFeatureId rowId = rowToId( index.row() );
593 
594  if ( role == FeatureIdRole )
595  return rowId;
596 
597  if ( index.column() >= mFieldCount )
598  return QVariant();
599 
600  int fieldId = mAttributes.at( index.column() );
601 
602  if ( role == FieldIndexRole )
603  return fieldId;
604 
605  if ( role == SortRole )
606  {
607  return mSortCache[rowId];
608  }
609 
610  QgsField field = layer()->fields().at( fieldId );
611 
612  if ( role == Qt::TextAlignmentRole )
613  {
614  return mWidgetFactories.at( index.column() )->alignmentFlag( layer(), fieldId, mWidgetConfigs.at( index.column() ) );
615  }
616 
617  if ( mFeat.id() != rowId || !mFeat.isValid() )
618  {
619  if ( !loadFeatureAtId( rowId ) )
620  return QVariant( "ERROR" );
621 
622  if ( mFeat.id() != rowId )
623  return QVariant( "ERROR" );
624  }
625 
626  QVariant val = mFeat.attribute( fieldId );
627 
628  switch ( role )
629  {
630  case Qt::DisplayRole:
631  return mWidgetFactories.at( index.column() )->representValue( layer(), fieldId, mWidgetConfigs.at( index.column() ),
632  mAttributeWidgetCaches.at( index.column() ), val );
633 
634  case Qt::EditRole:
635  return val;
636 
637  case Qt::BackgroundColorRole:
638  case Qt::TextColorRole:
639  case Qt::DecorationRole:
640  case Qt::FontRole:
641  {
644  if ( mRowStylesMap.contains( index.row() ) )
645  {
646  styles = mRowStylesMap[index.row()];
647  }
648  else
649  {
650  styles = QgsConditionalStyle::matchingConditionalStyles( layer()->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
651  mRowStylesMap.insert( index.row(), styles );
652 
653  }
654 
656  styles = layer()->conditionalStyles()->fieldStyles( field.name() );
658  styles.insert( 0, rowstyle );
660 
661  if ( style.isValid() )
662  {
663  if ( role == Qt::BackgroundColorRole && style.validBackgroundColor() )
664  return style.backgroundColor();
665  if ( role == Qt::TextColorRole && style.validTextColor() )
666  return style.textColor();
667  if ( role == Qt::DecorationRole )
668  return style.icon();
669  if ( role == Qt::FontRole )
670  return style.font();
671  }
672 
673  return QVariant();
674  }
675  }
676 
677  return QVariant();
678 }
679 
680 bool QgsAttributeTableModel::setData( const QModelIndex &index, const QVariant &value, int role )
681 {
682  Q_UNUSED( value )
683 
684  if ( !index.isValid() || index.column() >= mFieldCount || role != Qt::EditRole || !layer()->isEditable() )
685  return false;
686 
687  if ( !layer()->isModified() )
688  return false;
689 
690  if ( mChangedCellBounds.isNull() )
691  {
692  mChangedCellBounds = QRect( index.column(), index.row(), 1, 1 );
693  }
694  else
695  {
696  if ( index.column() < mChangedCellBounds.left() )
697  {
698  mChangedCellBounds.setLeft( index.column() );
699  }
700  if ( index.row() < mChangedCellBounds.top() )
701  {
702  mChangedCellBounds.setTop( index.row() );
703  }
704  if ( index.column() > mChangedCellBounds.right() )
705  {
706  mChangedCellBounds.setRight( index.column() );
707  }
708  if ( index.row() > mChangedCellBounds.bottom() )
709  {
710  mChangedCellBounds.setBottom( index.row() );
711  }
712  }
713 
714  return true;
715 }
716 
718 {
719  if ( !index.isValid() )
720  return Qt::ItemIsEnabled;
721 
722  if ( index.column() >= mFieldCount )
723  return Qt::NoItemFlags;
724 
726 
727  if ( layer()->isEditable() &&
728  !layer()->editFormConfig()->readOnly( mAttributes[index.column()] ) &&
729  (( layer()->dataProvider() && layer()->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) ||
730  FID_IS_NEW( rowToId( index.row() ) ) ) )
731  flags |= Qt::ItemIsEditable;
732 
733  return flags;
734 }
735 
736 void QgsAttributeTableModel::reload( const QModelIndex &index1, const QModelIndex &index2 )
737 {
739  emit dataChanged( index1, index2 );
740 }
741 
742 
743 void QgsAttributeTableModel::executeAction( int action, const QModelIndex &idx ) const
744 {
745  QgsFeature f = feature( idx );
746  layer()->actions()->doAction( action, f, fieldIdx( idx.column() ) );
747 }
748 
750 {
751  QgsFeature f = feature( idx );
752  action->triggerForFeature( layer(), &f );
753 }
754 
756 {
757  QgsFeature f;
759  f.setFeatureId( rowToId( idx.row() ) );
760  for ( int i = 0; i < mAttributes.size(); i++ )
761  {
762  f.setAttribute( mAttributes[i], data( index( idx.row(), i ), Qt::EditRole ) );
763  }
764 
765  return f;
766 }
767 
769 {
770  if ( column == -1 || column >= mAttributes.count() )
771  {
772  prefetchSortData( "" );
773  }
774  else
775  {
777  }
778 }
779 
780 void QgsAttributeTableModel::prefetchSortData( const QString& expressionString )
781 {
782  mSortCache.clear();
783  mSortCacheAttributes.clear();
784  mSortFieldIndex = -1;
785  mSortCacheExpression = QgsExpression( expressionString );
786 
787  QgsEditorWidgetFactory* widgetFactory = nullptr;
788  QVariant widgetCache;
789  QgsEditorWidgetConfig widgetConfig;
790 
791  if ( mSortCacheExpression.isField() )
792  {
793  QString fieldName = dynamic_cast<const QgsExpression::NodeColumnRef*>( mSortCacheExpression.rootNode() )->name();
794  mSortFieldIndex = mLayerCache->layer()->fieldNameIndex( fieldName );
795  }
796 
797  if ( mSortFieldIndex == -1 )
798  {
799  mSortCacheExpression.prepare( &mExpressionContext );
800 
801  Q_FOREACH ( const QString& col, mSortCacheExpression.referencedColumns() )
802  {
803  mSortCacheAttributes.append( mLayerCache->layer()->fieldNameIndex( col ) );
804  }
805  }
806  else
807  {
808  mSortCacheAttributes.append( mSortFieldIndex );
809 
810  widgetFactory = mWidgetFactories.at( mSortFieldIndex );
811  widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
812  widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
813  }
814 
815  QgsFeatureRequest request = QgsFeatureRequest( mFeatureRequest )
817  .setSubsetOfAttributes( mSortCacheAttributes );
818  QgsFeatureIterator it = mLayerCache->getFeatures( request );
819 
820  QgsFeature f;
821  while ( it.nextFeature( f ) )
822  {
823  if ( mSortFieldIndex == -1 )
824  {
826  mSortCache.insert( f.id(), mSortCacheExpression.evaluate( &mExpressionContext ) );
827  }
828  else
829  {
830  QVariant sortValue = widgetFactory->sortValue( layer(), mSortFieldIndex, widgetConfig, widgetCache, f.attribute( mSortFieldIndex ) );
831  mSortCache.insert( f.id(), sortValue );
832  }
833  }
834 }
835 
837 {
838  if ( mSortCacheExpression.rootNode() )
839  return mSortCacheExpression.expression();
840  else
841  return QString();
842 }
843 
845 {
846  mFeatureRequest = request;
847  if ( layer() && !layer()->hasGeometryType() )
848  mFeatureRequest.setFlags( mFeatureRequest.flags() | QgsFeatureRequest::NoGeometry );
849 }
850 
852 {
853  return mFeatureRequest;
854 }
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
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)
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)
const Flags & flags() const
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before using this model as source for any oth...
QModelIndexList idToIndexList(QgsFeatureId id) const
QStringList referencedColumns() const
Get list of columns referenced by the expression.
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.
bool validTextColor() const
Check if the text color is valid for render.
QString name
Definition: qgsfield.h:52
QHash< int, QgsFeatureId > mRowIdMap
Get the field index of this column.
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:199
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
QColor textColor() const
The text color set for style.
bool validBackgroundColor() const
Check if the background color is valid for render.
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
QgsFields fields() const
Returns the list of fields of this layer.
int extraColumns() const
Empty extra columns to announce from this model.
virtual void layerDeleted()
Launched when layer has been deleted.
QFont font() const
The font for the style.
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.
QgsConditionalLayerStyles * conditionalStyles() const
Return the conditional styles that are set for this layer.
QModelIndex idToIndex(QgsFeatureId id) const
Container of fields for a vector layer.
Definition: qgsfield.h:209
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:222
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.
const QgsFeatureRequest & request() const
Get the the feature request.
QString sortCacheExpression() const
The expression which was used to fill the sorting cache.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
QString widgetType(int fieldIdx) const
Get the id for the editor widget used to represent the field at the given index.
QgsEditFormConfig * editFormConfig() const
Get the configuration of the form used to represent this vector layer.
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...
QString tr(const char *sourceText, const char *disambiguation, int n)
const Node * rootNode() const
Returns root node of the expression. Root node is null is parsing has failed.
void resetModel()
Resets the model.
virtual QVariant createCache(QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config)
Create a cache for a given field.
QgsVectorLayerCache * mLayerCache
int size() const
bool isNull() const
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 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...
QPixmap icon() const
The icon set for style generated from the set symbol.
Conditional styling for a rule.
void executeMapLayerAction(QgsMapLayerAction *action, const QModelIndex &idx) const
Execute a QgsMapLayerAction.
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
static QList< QgsConditionalStyle > matchingConditionalStyles(const QList< QgsConditionalStyle > &styles, const QVariant &value, QgsExpressionContext &context)
Find and return the matching styles for the value and feature.
bool isEmpty() const
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)
int restart()
QVector< QgsEditorWidgetConfig > mWidgetConfigs
QColor backgroundColor() const
The background color for style.
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
Remove rows.
bool isField() const
Checks whether an expression consists only of a single field reference.
int count() const
Return number of items.
Definition: qgsfield.cpp:370
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
QGis::GeometryType geometryType() const
Returns point, line or polygon.
QHash< QgsFeatureId, int > mIdRowMap
FilterType filterType() const
Return the filter type which is currently set on this request.
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.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:44
int remove(const Key &key)
QString attributeAlias(int attributeIndex) const
Returns the alias of an attribute name or a null string if there is no alias.
void executeAction(int action, const QModelIndex &idx) const
Execute an action.
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:390
virtual void featureAdded(QgsFeatureId fid)
Launched when a feature has been added.
QModelIndex createIndex(int row, int column, void *ptr) const
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...
void clear()
QgsFeature feature(const QModelIndex &idx) const
Return the feature attributes at given model index.
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
QgsAttributeTableModel(QgsVectorLayerCache *layerCache, QObject *parent=nullptr)
Constructor.
No filter is applied.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:271
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of rows.
void insert(int i, const T &value)
int fieldCol(int idx) const
get column from field index
bool featureAtId(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id.
QgsVectorLayer * layer() const
Returns the layer this model uses as backend.
int bottom() const
virtual void loadAttributes()
Gets mFieldCount, mAttributes and mValueMaps.
int column() const
int idToRow(QgsFeatureId id) const
Maps feature id to table row.
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.
qint64 QgsFeatureId
Definition: qgsfeature.h:31
QString expression() const
Return the original, unmodified expression string.
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
int fieldIdx(int col) const
get field index from column
bool isValid() const
isValid Check if this rule is valid.
QgsFeatureId rowToId(int row) const
Maps row to feature id.
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
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)
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
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
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)
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.
Qt::ItemFlags flags(const QModelIndex &index) const override
Returns item flags for the index.
typedef ItemFlags