52 : QAbstractTableModel( parent )
53 , mLayer( layerCache->layer() )
54 , mLayerCache( layerCache )
63 mFeat.
setId( std::numeric_limits<int>::min() );
84 bool QgsAttributeTableModel::loadFeatureAtId(
QgsFeatureId fid )
const
88 if ( fid == std::numeric_limits<int>::min() )
107 void QgsAttributeTableModel::featuresDeleted(
const QgsFeatureIds &fids )
111 const auto constFids = fids;
114 QgsDebugMsgLevel( QStringLiteral(
"(%2) fid: %1, size: %3" ).arg( fid ).arg( mFeatureRequest.
filterType() ).arg( mIdRowMap.size() ), 4 );
121 std::sort( rows.begin(), rows.end() );
125 int currentRowCount = 0;
129 const auto constRows = rows;
130 for (
int row : constRows )
133 qDebug() <<
"Row: " << row <<
", begin " << beginRow <<
", last " << lastRow <<
", current " << currentRowCount <<
", removed " << removedRows;
140 if ( row != lastRow + 1 && lastRow != -1 )
142 if ( rows.count() > 100 && currentRowCount < 10 )
147 removeRows( beginRow - removedRows, currentRowCount );
150 removedRows += currentRowCount;
160 removeRows( beginRow - removedRows, currentRowCount );
168 if ( row < 0 || count < 1 )
171 if ( !mResettingModel )
172 beginRemoveRows( parent, row, row + count - 1 );
176 QgsDebugMsgLevel( QStringLiteral(
"remove %2 rows at %1 (rows %3, ids %4)" ).arg( row ).arg( count ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 3 );
180 for (
int i = row; i < row + count; i++ )
182 for ( SortCache &cache : mSortCaches )
183 cache.sortCache.remove( mRowIdMap[i] );
184 mIdRowMap.remove( mRowIdMap[i] );
185 mRowIdMap.remove( i );
189 int n = mRowIdMap.size() + count;
190 for (
int i = row + count; i < n; i++ )
193 mIdRowMap[id] -= count;
194 mRowIdMap[i - count] = id;
195 mRowIdMap.remove( i );
201 QgsDebugMsgLevel( QStringLiteral(
"after removal rows %1, ids %2" ).arg( mRowIdMap.size() ).arg( mIdRowMap.size() ), 4 );
203 for ( QHash<QgsFeatureId, int>::const_iterator it = mIdRowMap.constBegin(); it != mIdRowMap.constEnd(); ++it )
207 for ( QHash<int, QgsFeatureId>::const_iterator it = mRowIdMap.constBegin(); it != mRowIdMap.constEnd(); ++it )
212 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
214 if ( !mResettingModel )
220 void QgsAttributeTableModel::featureAdded(
QgsFeatureId fid )
225 if ( mFeat.
id() != fid )
226 featOk = loadFeatureAtId( fid );
230 for ( SortCache &cache : mSortCaches )
232 if ( cache.sortFieldIndex >= 0 )
235 const QVariant &widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
236 const QVariantMap &widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
237 QVariant sortValue = fieldFormatter->
representValue( mLayer, cache.sortFieldIndex, widgetConfig, widgetCache, mFeat.
attribute( cache.sortFieldIndex ) );
238 cache.sortCache.insert( mFeat.
id(), sortValue );
240 else if ( cache.sortCacheExpression.isValid() )
243 cache.sortCache[mFeat.
id()] = cache.sortCacheExpression.evaluate( &mExpressionContext );
248 if ( ! mIdRowMap.contains( fid ) )
250 int n = mRowIdMap.size();
251 if ( !mResettingModel )
252 beginInsertRows( QModelIndex(), n, n );
253 mIdRowMap.insert( fid, n );
254 mRowIdMap.insert( n, fid );
255 if ( !mResettingModel )
262 void QgsAttributeTableModel::updatedFields()
268 void QgsAttributeTableModel::editCommandEnded()
272 bulkEditCommandEnded( );
275 void QgsAttributeTableModel::attributeDeleted(
int idx )
278 for (
const SortCache &cache : mSortCaches )
280 if ( cache.sortCacheAttributes.contains( idx ) )
288 void QgsAttributeTableModel::layerDeleted()
290 mLayerCache =
nullptr;
294 mAttributeWidgetCaches.clear();
296 mWidgetFactories.clear();
297 mWidgetConfigs.clear();
298 mFieldFormatters.clear();
301 void QgsAttributeTableModel::fieldFormatterRemoved(
QgsFieldFormatter *fieldFormatter )
303 for (
int i = 0; i < mFieldFormatters.size(); ++i )
305 if ( mFieldFormatters.at( i ) == fieldFormatter )
310 void QgsAttributeTableModel::attributeValueChanged(
QgsFeatureId fid,
int idx,
const QVariant &value )
313 if ( mBulkEditCommandRunning )
315 mAttributeValueChanges.insert( QPair<QgsFeatureId, int>( fid, idx ), value );
318 QgsDebugMsgLevel( QStringLiteral(
"(%4) fid: %1, idx: %2, value: %3" ).arg( fid ).arg( idx ).arg( value.toString() ).arg( mFeatureRequest.
filterType() ), 2 );
320 for ( SortCache &cache : mSortCaches )
322 if ( cache.sortCacheAttributes.contains( idx ) )
324 if ( cache.sortFieldIndex == -1 )
326 if ( loadFeatureAtId( fid ) )
329 cache.sortCache[fid] = cache.sortCacheExpression.evaluate( &mExpressionContext );
335 const QVariant &widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
336 const QVariantMap &widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
337 QVariant sortValue = fieldFormatter->
representValue( mLayer, cache.sortFieldIndex, widgetConfig, widgetCache, value );
338 cache.sortCache.insert( fid, sortValue );
345 if ( loadFeatureAtId( fid ) )
350 if ( loadFeatureAtId( fid ) )
354 if ( !mIdRowMap.contains( fid ) )
367 if ( mIdRowMap.contains( fid ) )
378 void QgsAttributeTableModel::loadAttributes()
385 bool ins =
false, rm =
false;
390 mWidgetFactories.clear();
391 mAttributeWidgetCaches.clear();
392 mWidgetConfigs.clear();
394 for (
int idx = 0; idx < fields.
count(); ++idx )
400 mWidgetFactories.append( widgetFactory );
401 mWidgetConfigs.append( setup.
config() );
402 mAttributeWidgetCaches.append( fieldFormatter->
createCache( mLayer, idx, setup.
config() ) );
403 mFieldFormatters.append( fieldFormatter );
408 if ( mFieldCount + mExtraColumns < attributes.size() + mExtraColumns )
411 beginInsertColumns( QModelIndex(), mFieldCount + mExtraColumns, attributes.size() - 1 );
413 else if ( attributes.size() + mExtraColumns < mFieldCount + mExtraColumns )
416 beginRemoveColumns( QModelIndex(), attributes.size(), mFieldCount + mExtraColumns - 1 );
419 mFieldCount = attributes.size();
420 mAttributes = attributes;
422 for ( SortCache &cache : mSortCaches )
424 if ( cache.sortFieldIndex >= mAttributes.count() )
425 cache.sortFieldIndex = -1;
447 mResettingModel =
true;
469 if ( t.elapsed() > 1000 )
478 featureAdded( mFeat.
id() );
487 mResettingModel =
false;
493 if ( fieldName.isNull() )
495 mRowStylesMap.clear();
501 if ( fieldIndex == -1 )
506 emit dataChanged( index( 0, col ), index(
rowCount() - 1, col ) );
519 mRowIdMap.remove( rowA );
520 mRowIdMap.remove( rowB );
521 mRowIdMap.insert( rowA, b );
522 mRowIdMap.insert( rowB, a );
524 mIdRowMap.remove( a );
525 mIdRowMap.remove( b );
526 mIdRowMap.insert( a, rowB );
527 mIdRowMap.insert( b, rowA );
528 Q_ASSERT( mRowIdMap.size() == mIdRowMap.size() );
536 if ( !mIdRowMap.contains(
id ) )
538 QgsDebugMsg( QStringLiteral(
"idToRow: id %1 not in the map" ).arg(
id ) );
542 return mIdRowMap[id];
547 return index(
idToRow(
id ), 0 );
552 QModelIndexList indexes;
556 indexes.reserve( columns );
557 for (
int column = 0; column < columns; ++column )
559 indexes.append( index( row, column ) );
567 if ( !mRowIdMap.contains( row ) )
569 QgsDebugMsg( QStringLiteral(
"rowToId: row %1 not in the map" ).arg( row ) );
571 return std::numeric_limits<int>::min();
574 return mRowIdMap[row];
579 return mAttributes[col];
584 return mAttributes.indexOf( idx );
590 return mRowIdMap.size();
596 return std::max( 1, mFieldCount + mExtraColumns );
604 if ( role == Qt::DisplayRole )
606 if ( orientation == Qt::Vertical )
608 return QVariant( section );
610 else if ( section >= 0 && section < mFieldCount )
613 return QVariant( attributeName );
617 return tr(
"extra column" );
620 else if ( role == Qt::ToolTipRole )
622 if ( orientation == Qt::Vertical )
625 return tr(
"Feature ID: %1" ).arg(
rowToId( section ) );
641 if ( !index.isValid() || !mLayer ||
642 ( role != Qt::TextAlignmentRole
643 && role != Qt::DisplayRole
644 && role != Qt::ToolTipRole
645 && role != Qt::EditRole
648 #
if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
649 && role != Qt::BackgroundColorRole
650 && role != Qt::TextColorRole
652 && role != Qt::BackgroundRole
653 && role != Qt::ForegroundRole
655 && role != Qt::DecorationRole
656 && role != Qt::FontRole
667 if ( index.column() >= mFieldCount )
670 int fieldId = mAttributes.at( index.column() );
677 unsigned long cacheIndex = role -
SortRole;
678 if ( cacheIndex < mSortCaches.size() )
679 return mSortCaches.at( cacheIndex ).sortCache.value( rowId );
686 if ( role == Qt::TextAlignmentRole )
688 return QVariant( mFieldFormatters.at( index.column() )->alignmentFlag( mLayer, fieldId, mWidgetConfigs.at( index.column() ) ) | Qt::AlignVCenter );
691 if ( mFeat.
id() != rowId || !mFeat.
isValid() )
693 if ( !loadFeatureAtId( rowId ) )
694 return QVariant(
"ERROR" );
696 if ( mFeat.
id() != rowId )
697 return QVariant(
"ERROR" );
700 QVariant val = mFeat.
attribute( fieldId );
704 case Qt::DisplayRole:
705 case Qt::ToolTipRole:
706 return mFieldFormatters.at( index.column() )->representValue( mLayer,
708 mWidgetConfigs.at( index.column() ),
709 mAttributeWidgetCaches.at( index.column() ),
715 case Qt::BackgroundRole:
716 #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
717 case Qt::TextColorRole:
719 case Qt::ForegroundRole:
721 case Qt::DecorationRole:
725 QList<QgsConditionalStyle> styles;
726 if ( mRowStylesMap.contains( mFeat.
id() ) )
728 styles = mRowStylesMap[mFeat.
id()];
733 mRowStylesMap.insert( mFeat.
id(), styles );
739 styles.insert( 0, rowstyle );
746 #if QT_VERSION < QT_VERSION_CHECK(5, 13, 0)
752 if ( role == Qt::DecorationRole )
754 if ( role == Qt::FontRole )
769 if ( !index.isValid() || index.column() >= mFieldCount || role != Qt::EditRole || !mLayer->
isEditable() )
772 mRowStylesMap.remove( mFeat.
id() );
782 if ( !index.isValid() )
783 return Qt::ItemIsEnabled;
785 if ( index.column() >= mFieldCount || !mLayer )
786 return Qt::NoItemFlags;
788 Qt::ItemFlags
flags = QAbstractTableModel::flags( index );
790 const int fieldIndex = mAttributes[index.column()];
794 flags |= Qt::ItemIsEditable;
799 void QgsAttributeTableModel::bulkEditCommandStarted()
801 mBulkEditCommandRunning =
true;
802 mAttributeValueChanges.clear();
805 void QgsAttributeTableModel::bulkEditCommandEnded()
807 mBulkEditCommandRunning =
false;
810 int changeCount( mAttributeValueChanges.count() );
811 bool fullModelUpdate = changeCount > mLayerCache->
cacheSize() ||
814 QgsDebugMsgLevel( QStringLiteral(
"Bulk edit command ended with %1 modified rows over (%4), cache size is %2, starting %3 update." )
817 .arg( fullModelUpdate ? QStringLiteral(
"full" ) : QStringLiteral(
"incremental" ) )
821 if ( fullModelUpdate )
833 const auto keys = mAttributeValueChanges.keys();
834 for (
const auto &key : keys )
836 attributeValueChanged( key.first, key.second, mAttributeValueChanges.value( key ) );
837 int row(
idToRow( key.first ) );
839 minRow = std::min<int>( row, minRow );
840 minCol = std::min<int>( col, minCol );
841 maxRow = std::max<int>( row, maxRow );
842 maxCol = std::max<int>( col, maxCol );
844 emit dataChanged( createIndex( minRow, minCol ), createIndex( maxRow, maxCol ) );
846 mAttributeValueChanges.clear();
851 mFeat.
setId( std::numeric_limits<int>::min() );
852 emit dataChanged( index1, index2 );
873 for (
int i = 0; i < mAttributes.size(); i++ )
875 f.
setAttribute( mAttributes[i],
data( index( idx.row(), i ), Qt::EditRole ) );
883 if ( column == -1 || column >= mAttributes.count() )
895 if ( cacheIndex >= mSortCaches.size() )
897 mSortCaches.resize( cacheIndex + 1 );
899 SortCache &cache = mSortCaches[cacheIndex];
900 cache.sortCache.clear();
901 cache.sortCacheAttributes.clear();
902 cache.sortFieldIndex = -1;
903 if ( !expressionString.isEmpty() )
904 cache.sortCacheExpression =
QgsExpression( expressionString );
913 QVariant widgetCache;
914 QVariantMap widgetConfig;
916 if ( cache.sortCacheExpression.isField() )
922 if ( cache.sortFieldIndex == -1 )
924 cache.sortCacheExpression.prepare( &mExpressionContext );
926 const QSet<QString> &referencedColumns = cache.sortCacheExpression.referencedColumns();
928 for (
const QString &col : referencedColumns )
935 cache.sortCacheAttributes.append( cache.sortFieldIndex );
937 widgetCache = mAttributeWidgetCaches.at( cache.sortFieldIndex );
938 widgetConfig = mWidgetConfigs.at( cache.sortFieldIndex );
939 fieldFormatter = mFieldFormatters.at( cache.sortFieldIndex );
950 if ( cache.sortFieldIndex == -1 )
953 const QVariant cacheValue = cache.sortCacheExpression.evaluate( &mExpressionContext );
954 cache.sortCache.insert( f.
id(), cacheValue );
958 QVariant sortValue = fieldFormatter->
sortValue( mLayer, cache.sortFieldIndex, widgetConfig, widgetCache, f.
attribute( cache.sortFieldIndex ) );
959 cache.sortCache.insert( f.
id(), sortValue );
966 QString expressionString;
968 if ( cacheIndex >= mSortCaches.size() )
969 return expressionString;
971 const QgsExpression &expression = mSortCaches[cacheIndex].sortCacheExpression;
976 expressionString = QString();
978 return expressionString;
990 return mFeatureRequest;
void doAction(QUuid actionId, const QgsFeature &feature, int defaultValueIndex=0, const QgsExpressionContextScope &scope=QgsExpressionContextScope())
Does the given action.
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
const QgsFeatureRequest & request() const
Gets the the feature request.
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
Remove rows.
Qt::ItemFlags flags(const QModelIndex &index) const override
Returns item flags for the index.
QgsFeature feature(const QModelIndex &idx) const
Returns the feature attributes at given model index.
void resetModel()
Resets the model.
void fieldConditionalStyleChanged(const QString &fieldName)
Handles updating the model when the conditional style for a field changes.
QString sortCacheExpression(unsigned long cacheIndex=0) const
The expression which was used to fill the sorting cache at index cacheIndex.
int fieldIdx(int col) const
Gets field index from column.
QgsAttributeTableModel(QgsVectorLayerCache *layerCache, QObject *parent=nullptr)
Constructor.
void swapRows(QgsFeatureId a, QgsFeatureId b)
Swaps two rows.
void modelChanged()
Model has been changed.
void progress(int i, bool &cancel)
void setRequest(const QgsFeatureRequest &request)
Set a request that will be used to fill this attribute table model.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Updates data on given index.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of rows.
QModelIndex idToIndex(QgsFeatureId id) const
QgsVectorLayerCache * layerCache() const
Returns the layer cache this model uses as backend.
int extraColumns() const
Empty extra columns to announce from this model.
void executeMapLayerAction(QgsMapLayerAction *action, const QModelIndex &idx) const
Execute a QgsMapLayerAction.
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Returns the number of columns.
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Returns header data.
QModelIndexList idToIndexList(QgsFeatureId id) const
void prefetchSortData(const QString &expression, unsigned long cacheIndex=0)
Prefetches the entire data for an expression.
QgsFeatureId rowToId(int row) const
Maps row to feature id.
int idToRow(QgsFeatureId id) const
Maps feature id to table row.
virtual void loadLayer()
Loads the layer into the model Preferably to be called, before using this model as source for any oth...
@ SortRole
Role used for sorting start here.
@ FeatureIdRole
Get the feature id of the feature in this row.
@ FieldIndexRole
Get the field index of this column.
void setExtraColumns(int extraColumns)
Empty extra columns to announce from this model.
void prefetchColumnData(int column)
Caches the entire data for one column.
int fieldCol(int idx) const
Gets column from field index.
void reload(const QModelIndex &index1, const QModelIndex &index2)
Reloads the model data between indices.
void executeAction(QUuid action, const QModelIndex &idx) const
Execute an action.
QVariant data(const QModelIndex &index, int role) const override
Returns data on the given index.
QgsConditionalStyles rowStyles() const
Returns a list of row styles associated with the layer.
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName) const
Returns the conditional styles set for the field with matching fieldName.
Conditional styling for a rule.
static QgsConditionalStyle compressStyles(const QList< QgsConditionalStyle > &styles)
Compress a list of styles into a single style.
static QList< QgsConditionalStyle > matchingConditionalStyles(const QList< QgsConditionalStyle > &styles, const QVariant &value, QgsExpressionContext &context)
Find and return the matching styles for the value and feature.
QColor backgroundColor() const
The background color for style.
QColor textColor() const
The text color set for style.
QFont font() const
The font for the style.
bool validTextColor() const
Check if the text color is valid for render.
bool isValid() const
isValid Check if this rule is valid.
QPixmap icon() const
The icon set for style generated from the set symbol.
bool validBackgroundColor() const
Check if the background color is valid for render.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
An expression node which takes it value from a feature's field.
Class for parsing and evaluation of expressions (formerly called "search strings").
QString expression() const
Returns the original, unmodified expression string.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
bool isValid() const
Checks if this expression is valid.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
bool acceptFeature(const QgsFeature &feature)
Check if a feature is accepted by this requests filter.
FilterType filterType() const
Returns the filter type which is currently set on this request.
@ FilterNone
No filter is applied.
const Flags & flags() const
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
void setId(QgsFeatureId id)
Sets the feature id for this feature.
bool isValid() const
Returns the validity of this feature.
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
static QString fieldToolTipExtended(const QgsField &field, const QgsVectorLayer *layer)
Returns a HTML formatted tooltip string for a field, containing details like the field name,...
Encapsulate a field in an attribute table or data source.
QString displayName() const
Returns the name to use when displaying this field.
Container of fields for a vector layer.
int count() const
Returns number of items.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
static QgsEditorWidgetRegistry * editorWidgetRegistry()
Returns the global editor widget registry, used for managing all known edit widget factories.
static int debugLevel()
Reads the environment variable QGIS_DEBUG and converts it to int.
An action which can run on map layers The class can be used in two manners:
virtual void triggerForFeature(QgsMapLayer *layer, const QgsFeature &feature)
Triggers the action with the specified layer and feature.
void dataChanged()
Data of layer changed.
This class caches features of a given QgsVectorLayer.
void invalidated()
The cache has been invalidated and cleared.
void featureAdded(QgsFeatureId fid)
Emitted when a new feature has been added to the layer and this cache.
void cachedLayerDeleted()
Is emitted when the cached layer is deleted.
void attributeValueChanged(QgsFeatureId fid, int field, const QVariant &value)
Emitted when an attribute is changed.
QgsVectorLayer * layer()
Returns the layer to which this cache belongs.
int cacheSize()
Returns the maximum number of features this cache will hold.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &featureRequest=QgsFeatureRequest())
Query this VectorLayerCache for features.
bool featureAtId(QgsFeatureId featureId, QgsFeature &feature, bool skipCache=false)
Gets the feature at the given feature id.
static bool fieldIsEditable(const QgsVectorLayer *layer, int fieldIndex, const QgsFeature &feature)
Tests whether a field is editable for a particular feature.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
void editCommandStarted(const QString &text)
Signal emitted when a new edit command has been started.
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
void featuresDeleted(const QgsFeatureIds &fids)
Emitted when features have been deleted.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
void attributeDeleted(int idx)
Will be emitted, when an attribute has been deleted from this vector layer.
QgsActionManager * actions()
Returns all layer actions defined on this layer.
void editCommandEnded()
Signal emitted, when an edit command successfully ended.
void afterRollBack()
Emitted after changes are rolled back.
void updatedFields()
Emitted whenever the fields available from this layer have been changed.
QgsConditionalLayerStyles * conditionalStyles() const
Returns the conditional styles that are set for this layer.
void beforeRollBack()
Emitted before changes are rolled back.
QSet< QgsFeatureId > QgsFeatureIds
#define FID_TO_STRING(fid)
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
QList< int > QgsAttributeList
#define QgsDebugMsgLevel(str, level)