QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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  , mSortFieldIndex( -1 )
43  , mExtraColumns( 0 )
44 {
47  << QgsExpressionContextUtils::layerScope( layerCache->layer() );
48 
49  if ( layerCache->layer()->geometryType() == QGis::NoGeometry )
50  {
51  mFeatureRequest.setFlags( QgsFeatureRequest::NoGeometry );
52  }
53 
55 
56  if ( !layer()->hasGeometryType() )
57  mFeatureRequest.setFlags( QgsFeatureRequest::NoGeometry );
58 
60 
61  connect( mLayerCache, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ), this, SLOT( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ) );
62  connect( layer(), SIGNAL( featuresDeleted( QgsFeatureIds ) ), this, SLOT( featuresDeleted( QgsFeatureIds ) ) );
63  connect( layer(), SIGNAL( attributeDeleted( int ) ), this, SLOT( attributeDeleted( int ) ) );
64  connect( layer(), SIGNAL( updatedFields() ), this, SLOT( updatedFields() ) );
65  connect( layer(), SIGNAL( editCommandEnded() ), this, SLOT( editCommandEnded() ) );
66  connect( mLayerCache, SIGNAL( featureAdded( QgsFeatureId ) ), this, SLOT( featureAdded( QgsFeatureId ) ) );
67  connect( mLayerCache, SIGNAL( cachedLayerDeleted() ), this, SLOT( layerDeleted() ) );
68 }
69 
70 bool QgsAttributeTableModel::loadFeatureAtId( QgsFeatureId fid ) const
71 {
72  QgsDebugMsgLevel( QString( "loading feature %1" ).arg( fid ), 3 );
73 
74  if ( fid == std::numeric_limits<int>::min() )
75  {
76  return false;
77  }
78 
79  return mLayerCache->featureAtId( fid, mFeat );
80 }
81 
83 {
84  return mExtraColumns;
85 }
86 
88 {
89  mExtraColumns = extraColumns;
91 }
92 
94 {
95  QList<int> rows;
96 
97  Q_FOREACH ( QgsFeatureId fid, fids )
98  {
99  QgsDebugMsgLevel( QString( "(%2) fid: %1, size: %3" ).arg( fid ).arg( mFeatureRequest.filterType() ).arg( mIdRowMap.size() ), 4 );
100 
101  int row = idToRow( fid );
102  if ( row != -1 )
103  rows << row;
104  }
105 
106  qSort( rows );
107 
108  int lastRow = -1;
109  int beginRow = -1;
110  int currentRowCount = 0;
111  int removedRows = 0;
112  bool reset = false;
113 
114  Q_FOREACH ( int row, rows )
115  {
116 #if 0
117  qDebug() << "Row: " << row << ", begin " << beginRow << ", last " << lastRow << ", current " << currentRowCount << ", removed " << removedRows;
118 #endif
119  if ( lastRow == -1 )
120  {
121  beginRow = row;
122  }
123 
124  if ( row != lastRow + 1 && lastRow != -1 )
125  {
126  if ( rows.count() > 100 && currentRowCount < 10 )
127  {
128  reset = true;
129  break;
130  }
131  removeRows( beginRow - removedRows, currentRowCount );
132 
133  beginRow = row;
134  removedRows += currentRowCount;
135  currentRowCount = 0;
136  }
137 
138  currentRowCount++;
139 
140  lastRow = row;
141  }
142 
143  if ( !reset )
144  removeRows( beginRow - removedRows, currentRowCount );
145  else
146  resetModel();
147 }
148 
149 bool QgsAttributeTableModel::removeRows( int row, int count, const QModelIndex &parent )
150 {
151  if ( row < 0 || count < 1 )
152  return false;
153 
154  beginRemoveRows( parent, row, row + count - 1 );
155 #ifdef QGISDEBUG
156  if ( 3 <= QgsLogger::debugLevel() )
157  QgsDebugMsgLevel( QString( "remove %2 rows at %1 (rows %3, ids %4)" ).arg( row ).arg( count ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 3 );
158 #endif
159 
160  // clean old references
161  for ( int i = row; i < row + count; i++ )
162  {
163  mSortCache.remove( mRowIdMap[i] );
164  mIdRowMap.remove( mRowIdMap[i] );
165  mRowIdMap.remove( i );
166  }
167 
168  // update maps
169  int n = mRowIdMap.size() + count;
170  for ( int i = row + count; i < n; i++ )
171  {
172  QgsFeatureId id = mRowIdMap[i];
173  mIdRowMap[id] -= count;
174  mRowIdMap[i-count] = id;
175  mRowIdMap.remove( i );
176  }
177 
178 #ifdef QGISDEBUG
179  if ( 4 <= QgsLogger::debugLevel() )
180  {
181  QgsDebugMsgLevel( QString( "after removal rows %1, ids %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 4 );
182  QgsDebugMsgLevel( "id->row", 4 );
184  QgsDebugMsgLevel( QString( "%1->%2" ).arg( FID_TO_STRING( it.key() ) ).arg( *it ), 4 );
185 
186  QgsDebugMsgLevel( "row->id", 4 );
188  QgsDebugMsgLevel( QString( "%1->%2" ).arg( it.key() ).arg( FID_TO_STRING( *it ) ), 4 );
189  }
190 #endif
191 
192  Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
193 
194  endRemoveRows();
195 
196  return true;
197 }
198 
199 void QgsAttributeTableModel::featureAdded( QgsFeatureId fid , bool resettingModel )
200 {
201  QgsDebugMsgLevel( QString( "(%2) fid: %1" ).arg( fid ).arg( mFeatureRequest.filterType() ), 4 );
202  bool featOk = true;
203 
204  if ( mFeat.id() != fid )
205  featOk = loadFeatureAtId( fid );
206 
207  if ( featOk && mFeatureRequest.acceptFeature( mFeat ) )
208  {
209 
210  if ( mSortFieldIndex >= 0 )
211  {
212  QgsEditorWidgetFactory* widgetFactory = mWidgetFactories.at( mSortFieldIndex );
213  const QVariant& widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
214  const QgsEditorWidgetConfig& widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
215  QVariant sortValue = widgetFactory->representValue( layer(), mSortFieldIndex, widgetConfig, widgetCache, mFeat.attribute( mSortFieldIndex ) );
216  mSortCache.insert( mFeat.id(), sortValue );
217  }
218  else if ( mSortCacheExpression.isValid() )
219  {
221  mSortCache[mFeat.id()] = mSortCacheExpression.evaluate( &mExpressionContext );
222  }
223 
224  // Skip if the fid is already in the map (do not add twice)!
225  if ( ! mIdRowMap.contains( fid ) )
226  {
227  int n = mRowIdMap.size();
228  if ( !resettingModel )
229  beginInsertRows( QModelIndex(), n, n );
230  mIdRowMap.insert( fid, n );
231  mRowIdMap.insert( n, fid );
232  if ( !resettingModel )
233  endInsertRows();
234  reload( index( rowCount() - 1, 0 ), index( rowCount() - 1, columnCount() ) );
235  }
236  }
237 }
238 
239 void QgsAttributeTableModel::updatedFields()
240 {
241  loadAttributes();
242  emit modelChanged();
243 }
244 
245 void QgsAttributeTableModel::editCommandEnded()
246 {
247  // do not do releoad(...) due would trigger (dataChanged) row sort
248  // giving issue: https://issues.qgis.org/issues/15976
249  mChangedCellBounds = QRect();
250 }
251 
252 void QgsAttributeTableModel::attributeDeleted( int idx )
253 {
254  if ( mSortCacheAttributes.contains( idx ) )
256 }
257 
259 {
260  removeRows( 0, rowCount() );
261 
263  mAttributes.clear();
266 }
267 
269 {
270  QgsDebugMsgLevel( QString( "(%4) fid: %1, idx: %2, value: %3" ).arg( fid ).arg( idx ).arg( value.toString() ).arg( mFeatureRequest.filterType() ), 3 );
271 
272  if ( mSortCacheAttributes.contains( idx ) )
273  {
274  if ( mSortFieldIndex == -1 )
275  {
276  loadFeatureAtId( fid );
278  mSortCache[fid] = mSortCacheExpression.evaluate( &mExpressionContext );
279  }
280  else
281  {
282  QgsEditorWidgetFactory* widgetFactory = mWidgetFactories.at( mSortFieldIndex );
283  const QVariant& widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
284  const QgsEditorWidgetConfig& widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
285  QVariant sortValue = widgetFactory->representValue( layer(), mSortFieldIndex, widgetConfig, widgetCache, value );
286  mSortCache.insert( fid, sortValue );
287  }
288  }
289  // No filter request: skip all possibly heavy checks
290  if ( mFeatureRequest.filterType() == QgsFeatureRequest::FilterNone )
291  {
292  if ( loadFeatureAtId( fid ) )
293  setData( index( idToRow( fid ), fieldCol( idx ) ), value, Qt::EditRole );
294  }
295  else
296  {
297  if ( loadFeatureAtId( fid ) )
298  {
299  if ( mFeatureRequest.acceptFeature( mFeat ) )
300  {
301  if ( !mIdRowMap.contains( fid ) )
302  {
303  // Feature changed in such a way, it will be shown now
304  featureAdded( fid );
305  }
306  else
307  {
308  // Update representation
309  setData( index( idToRow( fid ), fieldCol( idx ) ), value, Qt::EditRole );
310  }
311  }
312  else
313  {
314  if ( mIdRowMap.contains( fid ) )
315  {
316  // Feature changed such, that it is no longer shown
317  featuresDeleted( QgsFeatureIds() << fid );
318  }
319  // else: we don't care
320  }
321  }
322  }
323 }
324 
326 {
327  if ( !layer() )
328  {
329  return;
330  }
331 
332  bool ins = false, rm = false;
333 
334  QgsAttributeList attributes;
335  const QgsFields& fields = layer()->fields();
336 
340 
341  for ( int idx = 0; idx < fields.count(); ++idx )
342  {
343  const QString widgetType = layer()->editFormConfig()->widgetType( idx );
344  QgsEditorWidgetFactory* widgetFactory = QgsEditorWidgetRegistry::instance()->factory( widgetType );
345  if ( widgetFactory )
346  {
347  mWidgetFactories.append( widgetFactory );
348  mWidgetConfigs.append( layer()->editFormConfig()->widgetConfig( idx ) );
349  mAttributeWidgetCaches.append( widgetFactory->createCache( layer(), idx, mWidgetConfigs.last() ) );
350 
351  attributes << idx;
352  }
353  }
354 
355  if ( mFieldCount + mExtraColumns < attributes.size() + mExtraColumns )
356  {
357  ins = true;
358  beginInsertColumns( QModelIndex(), mFieldCount + mExtraColumns, attributes.size() - 1 );
359  }
360  else if ( attributes.size() + mExtraColumns < mFieldCount + mExtraColumns )
361  {
362  rm = true;
363  beginRemoveColumns( QModelIndex(), attributes.size(), mFieldCount + mExtraColumns - 1 );
364  }
365 
366  mFieldCount = attributes.size();
367  mAttributes = attributes;
368 
369  if ( mSortFieldIndex >= mAttributes.count() )
370  mSortFieldIndex = -1;
371 
372  if ( ins )
373  {
375  }
376  else if ( rm )
377  {
379  }
380 }
381 
383 {
384  // make sure attributes are properly updated before caching the data
385  // (emit of progress() signal may enter event loop and thus attribute
386  // table view may be updated with inconsistent model which may assume
387  // wrong number of attributes)
388  loadAttributes();
389 
390  beginResetModel();
391 
392  if ( rowCount() != 0 )
393  {
394  removeRows( 0, rowCount() );
395  }
396 
397  QgsFeatureIterator features = mLayerCache->getFeatures( mFeatureRequest );
398 
399  int i = 0;
400 
401  QTime t;
402  t.start();
403 
404  while ( features.nextFeature( mFeat ) )
405  {
406  ++i;
407 
408  if ( t.elapsed() > 1000 )
409  {
410  bool cancel = false;
411  emit progress( i, cancel );
412  if ( cancel )
413  break;
414 
415  t.restart();
416  }
417  featureAdded( mFeat.id(), true );
418  }
419 
420  emit finished();
421 
422  connect( mLayerCache, SIGNAL( invalidated() ), this, SLOT( loadLayer() ), Qt::UniqueConnection );
423 
424  endResetModel();
425 }
426 
428 {
429  if ( fieldName.isNull() )
430  {
432  emit dataChanged( index( 0, 0 ), index( rowCount() - 1, columnCount() - 1 ) );
433  return;
434  }
435 
436  int fieldIndex = mLayerCache->layer()->fieldNameIndex( fieldName );
437  if ( fieldIndex == -1 )
438  return;
439 
440  //whole column has changed
441  int col = fieldCol( fieldIndex );
442  emit dataChanged( index( 0, col ), index( rowCount() - 1, col ) );
443 }
444 
446 {
447  if ( a == b )
448  return;
449 
450  int rowA = idToRow( a );
451  int rowB = idToRow( b );
452 
453  //emit layoutAboutToBeChanged();
454 
455  mRowIdMap.remove( rowA );
456  mRowIdMap.remove( rowB );
457  mRowIdMap.insert( rowA, b );
458  mRowIdMap.insert( rowB, a );
459 
460  mIdRowMap.remove( a );
461  mIdRowMap.remove( b );
462  mIdRowMap.insert( a, rowB );
463  mIdRowMap.insert( b, rowA );
464 
465  //emit layoutChanged();
466 }
467 
469 {
470  if ( !mIdRowMap.contains( id ) )
471  {
472  QgsDebugMsg( QString( "idToRow: id %1 not in the map" ).arg( id ) );
473  return -1;
474  }
475 
476  return mIdRowMap[id];
477 }
478 
480 {
481  return index( idToRow( id ), 0 );
482 }
483 
485 {
486  QModelIndexList indexes;
487 
488  int row = idToRow( id );
489  int columns = columnCount();
490  indexes.reserve( columns );
491  for ( int column = 0; column < columns; ++column )
492  {
493  indexes.append( index( row, column ) );
494  }
495 
496  return indexes;
497 }
498 
500 {
501  if ( !mRowIdMap.contains( row ) )
502  {
503  QgsDebugMsg( QString( "rowToId: row %1 not in the map" ).arg( row ) );
504  // return negative infinite (to avoid collision with newly added features)
506  }
507 
508  return mRowIdMap[row];
509 }
510 
512 {
513  return mAttributes[col];
514 }
515 
517 {
518  return mAttributes.indexOf( idx );
519 }
520 
522 {
523  Q_UNUSED( parent );
524  return mRowIdMap.size();
525 }
526 
528 {
529  Q_UNUSED( parent );
530  return qMax( 1, mFieldCount + mExtraColumns ); // if there are zero columns all model indices will be considered invalid
531 }
532 
533 QVariant QgsAttributeTableModel::headerData( int section, Qt::Orientation orientation, int role ) const
534 {
535  if ( !layer() )
536  return QVariant();
537 
538  if ( role == Qt::DisplayRole )
539  {
540  if ( orientation == Qt::Vertical ) //row
541  {
542  return QVariant( section );
543  }
544  else if ( section >= 0 && section < mFieldCount )
545  {
546  QString attributeName = layer()->fields().at( mAttributes.at( section ) ).displayName();
547  return QVariant( attributeName );
548  }
549  else
550  {
551  return tr( "extra column" );
552  }
553  }
554  else if ( role == Qt::ToolTipRole )
555  {
556  if ( orientation == Qt::Vertical )
557  {
558  // TODO show DisplayExpression
559  return tr( "Feature ID: %1" ).arg( rowToId( section ) );
560  }
561  else
562  {
563  QgsField field = layer()->fields().at( mAttributes.at( section ) );
564  return field.name();
565  }
566  }
567  else
568  {
569  return QVariant();
570  }
571 }
572 
574 {
575  if ( !index.isValid() ||
576  ( role != Qt::TextAlignmentRole
577  && role != Qt::DisplayRole
578  && role != Qt::EditRole
579  && role != SortRole
580  && role != FeatureIdRole
581  && role != FieldIndexRole
582  && role != Qt::BackgroundColorRole
583  && role != Qt::TextColorRole
584  && role != Qt::DecorationRole
585  && role != Qt::FontRole
586  )
587  )
588  return QVariant();
589 
590  QgsFeatureId rowId = rowToId( index.row() );
591 
592  if ( role == FeatureIdRole )
593  return rowId;
594 
595  if ( index.column() >= mFieldCount )
596  return QVariant();
597 
598  int fieldId = mAttributes.at( index.column() );
599 
600  if ( role == FieldIndexRole )
601  return fieldId;
602 
603  if ( role == SortRole )
604  {
605  return mSortCache[rowId];
606  }
607 
608  QgsField field = layer()->fields().at( fieldId );
609 
610  if ( role == Qt::TextAlignmentRole )
611  {
612  return QVariant( mWidgetFactories.at( index.column() )->alignmentFlag( layer(), fieldId, mWidgetConfigs.at( index.column() ) ) | Qt::AlignVCenter );
613  }
614 
615  if ( mFeat.id() != rowId || !mFeat.isValid() )
616  {
617  if ( !loadFeatureAtId( rowId ) )
618  return QVariant( "ERROR" );
619 
620  if ( mFeat.id() != rowId )
621  return QVariant( "ERROR" );
622  }
623 
624  QVariant val = mFeat.attribute( fieldId );
625 
626  switch ( role )
627  {
628  case Qt::DisplayRole:
629  return mWidgetFactories.at( index.column() )->representValue( layer(), fieldId, mWidgetConfigs.at( index.column() ),
630  mAttributeWidgetCaches.at( index.column() ), val );
631 
632  case Qt::EditRole:
633  return val;
634 
635  case Qt::BackgroundColorRole:
636  case Qt::TextColorRole:
637  case Qt::DecorationRole:
638  case Qt::FontRole:
639  {
642  if ( mRowStylesMap.contains( index.row() ) )
643  {
644  styles = mRowStylesMap[index.row()];
645  }
646  else
647  {
648  styles = QgsConditionalStyle::matchingConditionalStyles( layer()->conditionalStyles()->rowStyles(), QVariant(), mExpressionContext );
649  mRowStylesMap.insert( index.row(), styles );
650 
651  }
652 
654  styles = layer()->conditionalStyles()->fieldStyles( field.name() );
656  styles.insert( 0, rowstyle );
658 
659  if ( style.isValid() )
660  {
661  if ( role == Qt::BackgroundColorRole && style.validBackgroundColor() )
662  return style.backgroundColor();
663  if ( role == Qt::TextColorRole && style.validTextColor() )
664  return style.textColor();
665  if ( role == Qt::DecorationRole )
666  return style.icon();
667  if ( role == Qt::FontRole )
668  return style.font();
669  }
670 
671  return QVariant();
672  }
673  }
674 
675  return QVariant();
676 }
677 
678 bool QgsAttributeTableModel::setData( const QModelIndex &index, const QVariant &value, int role )
679 {
680  Q_UNUSED( value )
681 
682  if ( !index.isValid() || index.column() >= mFieldCount || role != Qt::EditRole || !layer()->isEditable() )
683  return false;
684 
685  if ( !layer()->isModified() )
686  return false;
687 
688  if ( mChangedCellBounds.isNull() )
689  {
690  mChangedCellBounds = QRect( index.column(), index.row(), 1, 1 );
691  }
692  else
693  {
694  if ( index.column() < mChangedCellBounds.left() )
695  {
696  mChangedCellBounds.setLeft( index.column() );
697  }
698  if ( index.row() < mChangedCellBounds.top() )
699  {
700  mChangedCellBounds.setTop( index.row() );
701  }
702  if ( index.column() > mChangedCellBounds.right() )
703  {
704  mChangedCellBounds.setRight( index.column() );
705  }
706  if ( index.row() > mChangedCellBounds.bottom() )
707  {
708  mChangedCellBounds.setBottom( index.row() );
709  }
710  }
711 
712  return true;
713 }
714 
716 {
717  if ( !index.isValid() )
718  return Qt::ItemIsEnabled;
719 
720  if ( index.column() >= mFieldCount )
721  return Qt::NoItemFlags;
722 
724 
725  if ( layer()->isEditable() &&
726  !layer()->editFormConfig()->readOnly( mAttributes[index.column()] ) &&
727  (( layer()->dataProvider() && layer()->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues ) ||
728  FID_IS_NEW( rowToId( index.row() ) ) ) )
729  flags |= Qt::ItemIsEditable;
730 
731  return flags;
732 }
733 
734 void QgsAttributeTableModel::reload( const QModelIndex &index1, const QModelIndex &index2 )
735 {
737  emit dataChanged( index1, index2 );
738 }
739 
740 
741 void QgsAttributeTableModel::executeAction( int action, const QModelIndex &idx ) const
742 {
743  QgsFeature f = feature( idx );
744  layer()->actions()->doAction( action, f, fieldIdx( idx.column() ) );
745 }
746 
748 {
749  QgsFeature f = feature( idx );
750  action->triggerForFeature( layer(), &f );
751 }
752 
754 {
755  QgsFeature f;
757  f.setFeatureId( rowToId( idx.row() ) );
758  for ( int i = 0; i < mAttributes.size(); i++ )
759  {
760  f.setAttribute( mAttributes[i], data( index( idx.row(), i ), Qt::EditRole ) );
761  }
762 
763  return f;
764 }
765 
767 {
768  if ( column == -1 || column >= mAttributes.count() )
769  {
771  }
772  else
773  {
775  }
776 }
777 
778 void QgsAttributeTableModel::prefetchSortData( const QString& expressionString )
779 {
780  mSortCache.clear();
781  mSortCacheAttributes.clear();
782  mSortFieldIndex = -1;
783  if ( !expressionString.isEmpty() )
784  mSortCacheExpression = QgsExpression( expressionString );
785  else
786  {
787  // no sorting
788  mSortCacheExpression = QgsExpression();
789  return;
790  }
791 
792  QgsEditorWidgetFactory* widgetFactory = nullptr;
793  QVariant widgetCache;
794  QgsEditorWidgetConfig widgetConfig;
795 
796  if ( mSortCacheExpression.isField() )
797  {
798  QString fieldName = dynamic_cast<const QgsExpression::NodeColumnRef*>( mSortCacheExpression.rootNode() )->name();
799  mSortFieldIndex = mLayerCache->layer()->fieldNameIndex( fieldName );
800  }
801 
802  if ( mSortFieldIndex == -1 )
803  {
804  mSortCacheExpression.prepare( &mExpressionContext );
805 
806  Q_FOREACH ( const QString& col, mSortCacheExpression.referencedColumns() )
807  {
808  mSortCacheAttributes.append( mLayerCache->layer()->fieldNameIndex( col ) );
809  }
810  }
811  else
812  {
813  mSortCacheAttributes.append( mSortFieldIndex );
814 
815  widgetFactory = mWidgetFactories.at( mSortFieldIndex );
816  widgetCache = mAttributeWidgetCaches.at( mSortFieldIndex );
817  widgetConfig = mWidgetConfigs.at( mSortFieldIndex );
818  }
819 
820  QgsFeatureRequest request = QgsFeatureRequest( mFeatureRequest )
822  .setSubsetOfAttributes( mSortCacheAttributes );
823  QgsFeatureIterator it = mLayerCache->getFeatures( request );
824 
825  QgsFeature f;
826  while ( it.nextFeature( f ) )
827  {
828  if ( mSortFieldIndex == -1 )
829  {
831  mSortCache.insert( f.id(), mSortCacheExpression.evaluate( &mExpressionContext ) );
832  }
833  else
834  {
835  QVariant sortValue = widgetFactory->sortValue( layer(), mSortFieldIndex, widgetConfig, widgetCache, f.attribute( mSortFieldIndex ) );
836  mSortCache.insert( f.id(), sortValue );
837  }
838  }
839 }
840 
842 {
843  if ( mSortCacheExpression.isValid() )
844  return mSortCacheExpression.expression();
845  else
846  return QString();
847 }
848 
850 {
851  mFeatureRequest = request;
852  if ( layer() && !layer()->hasGeometryType() )
853  mFeatureRequest.setFlags( mFeatureRequest.flags() | QgsFeatureRequest::NoGeometry );
854 }
855 
857 {
858  return mFeatureRequest;
859 }
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.
int top() const
bool isValid() const
Checks if this expression is valid.
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.
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)
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.
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)
virtual void featureAdded(QgsFeatureId fid, bool resettingModel=false)
Launched when a feature has been added.
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)
void doAction(int index, const QgsFeature &feat, int defaultValueIndex=0, const QgsExpressionContextScope &scope=QgsExpressionContextScope())
Does the given action.
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