28template <
class Key,
class T>
void mapToReversedLists(
const QMap< Key, T > &map, QList<Key> &ks, QList<T> &vs )
30 ks.reserve( map.size() );
31 vs.reserve( map.size() );
32 typename QMap<Key, T>::const_iterator i = map.constEnd();
33 while ( i != map.constBegin() )
37 vs.append( i.value() );
56 QgsDebugMsgLevel( QStringLiteral(
"undo index changed %1" ).arg( index ), 4 );
74 fields.
rename( renameIt.key(), renameIt.value() );
118 for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
119 attrs[it.key()] = it.value();
153 for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
168 QgsDebugMsg( QStringLiteral(
"Cannot delete features (missing DeleteFeature capability)" ) );
176 QgsDebugMsg( QStringLiteral(
"Cannot delete features (in the list of added features)" ) );
184 QgsDebugMsg( QStringLiteral(
"Cannot delete features (in the list of deleted features)" ) );
197 QgsDebugMsg( QStringLiteral(
"Cannot delete features (missing DeleteFeatures capability)" ) );
202 const auto constFids = fids;
234 for (
auto it = newValues.constBegin() ; it != newValues.constEnd(); ++it )
236 const int field = it.key();
237 const QVariant newValue = it.value();
240 if ( oldValues.contains(
field ) )
241 oldValue = oldValues[
field];
280 for (
const QgsField &updatedField : fields )
282 if ( updatedField.name() ==
field.
name() )
321 if ( newName.isEmpty() )
328 for (
const QgsField &updatedField : fields )
330 if ( updatedField.name() == newName )
341 commitErrors.clear();
353 success &= commitChangesCheckGeometryTypeCompatibility( commitErrors );
360 bool attributesChanged =
false;
363 bool attributesDeleted =
false;
364 success &= commitChangesDeleteAttributes( attributesDeleted, commitErrors );
365 attributesChanged |= attributesDeleted;
371 bool attributesRenamed =
false;
372 success &= commitChangesRenameAttributes( attributesRenamed, commitErrors );
373 attributesChanged |= attributesRenamed;
381 bool attributesAdded =
false;
382 success &= commitChangesAddAttributes( attributesAdded, commitErrors );
383 attributesChanged |= attributesAdded;
389 if ( success && attributesChanged )
390 success &= commitChangesCheckAttributesModifications( oldFields, commitErrors );
397 bool attributesChanged;
398 success &= commitChangesChangeAttributes( attributesChanged, commitErrors );
406 bool featuresDeleted;
407 success &= commitChangesDeleteFeatures( featuresDeleted, commitErrors );
416 success &= commitChangesAddFeatures( featuresAdded, commitErrors );
422 commitErrors << tr(
"\n Provider errors:" );
423 const auto constErrors = provider->
errors();
424 for ( QString e : constErrors )
426 commitErrors <<
" " + e.replace(
'\n', QLatin1String(
"\n " ) );
457QString QgsVectorLayerEditBuffer::dumpEditBuffer()
462 msg +=
"CHANGED GEOMETRIES:\n";
466 msg += QString(
"- FID %1: %2" ).arg( it.key() ).arg( it.value().to );
487 attrs.insert( index, QVariant() );
488 featureIt->setAttributes( attrs );
494 std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end(), std::greater< int >() );
495 const auto constSortedRenamedIndices = sortedRenamedIndices;
496 for (
int renameIndex : constSortedRenamedIndices )
498 if ( renameIndex >= index )
515 if ( attrMap.contains( index ) )
516 attrMap.remove( index );
527 attrs.remove( index );
528 featureIt->setAttributes( attrs );
534 std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end() );
537 const auto constSortedRenamedIndices = sortedRenamedIndices;
538 for (
int renameIndex : constSortedRenamedIndices )
540 if ( renameIndex > index )
556 for ( QgsAttributeMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
558 int attrIndex = it.key();
559 updatedMap.insert( attrIndex < index ? attrIndex : attrIndex + offset, it.value() );
571bool QgsVectorLayerEditBuffer::commitChangesCheckGeometryTypeCompatibility( QStringList &commitErrors )
582 if ( ( ! f.hasGeometry() ) ||
588 commitErrors << tr(
"ERROR: %n feature(s) not added - geometry type is not compatible with the current layer.",
"not added features count",
mAddedFeatures.size() );
596 commitErrors << tr(
"ERROR: %n feature(s) not added - provider doesn't support adding features.",
"not added features count",
mAddedFeatures.size() );
603bool QgsVectorLayerEditBuffer::commitChangesDeleteAttributes(
bool &attributesDeleted, QStringList &commitErrors )
605 attributesDeleted =
false;
612 commitErrors << tr(
"SUCCESS: %n attribute(s) deleted.",
"deleted attributes count",
mDeletedAttributeIds.size() );
617 attributesDeleted =
true;
621 commitErrors << tr(
"ERROR: %n attribute(s) not deleted.",
"not deleted attributes count",
mDeletedAttributeIds.size() );
623 QString list =
"ERROR: Pending attribute deletes:";
625 for (
int idx : constMDeletedAttributeIds )
629 commitErrors << list;
637bool QgsVectorLayerEditBuffer::commitChangesRenameAttributes(
bool &attributesRenamed, QStringList &commitErrors )
639 attributesRenamed =
false;
646 commitErrors << tr(
"SUCCESS: %n attribute(s) renamed.",
"renamed attributes count",
mRenamedAttributes.size() );
651 attributesRenamed =
true;
655 commitErrors << tr(
"ERROR: %n attribute(s) not renamed",
"not renamed attributes count",
mRenamedAttributes.size() );
662bool QgsVectorLayerEditBuffer::commitChangesAddAttributes(
bool &attributesAdded, QStringList &commitErrors )
664 attributesAdded =
false;
671 commitErrors << tr(
"SUCCESS: %n attribute(s) added.",
"added attributes count",
mAddedAttributes.size() );
674 attributesAdded =
true;
678 commitErrors << tr(
"ERROR: %n new attribute(s) not added",
"not added attributes count",
mAddedAttributes.size() );
680 QString list =
"ERROR: Pending adds:";
682 for (
QgsField f : constMAddedAttributes )
684 list.append(
' ' + f.name() );
686 commitErrors << list;
694bool QgsVectorLayerEditBuffer::commitChangesCheckAttributesModifications(
const QgsFields oldFields, QStringList &commitErrors )
701 commitErrors << tr(
"ERROR: the count of fields is incorrect after addition/removal of fields!" );
705 for (
int i = 0; i < std::min( oldFields.
count(), newFields.
count() ); ++i )
709 if ( oldField != newField )
712 << tr(
"ERROR: field with index %1 is not the same!" ).arg( i )
715 << QStringLiteral(
"%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
716 .arg( tr(
"expected field" ),
718 QVariant::typeToName( oldField.
type() ),
722 << QStringLiteral(
"%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
723 .arg( tr(
"retrieved field" ),
725 QVariant::typeToName( newField.
type() ),
736bool QgsVectorLayerEditBuffer::commitChangesChangeAttributes(
bool &attributesChanged, QStringList &commitErrors )
738 attributesChanged =
false;
747 attributesChanged =
true;
766 commitErrors << tr(
"ERROR: %1 geometries not changed. Data provider '%2' does not have ChangeFeatures or ChangeGeometries capabilities",
"not changed geometries count" )
774 commitErrors << tr(
"SUCCESS: %n geometries were changed.",
"changed geometries count",
mChangedGeometries.size() );
775 attributesChanged =
true;
781 commitErrors << tr(
"ERROR: %n geometries not changed.",
"not changed geometries count",
mChangedGeometries.size() );
791 commitErrors << tr(
"ERROR: %1 attribute value change(s) not applied. Data provider '%2' does not have ChangeFeatures or ChangeAttributeValues capabilities",
"not changed attribute values count" )
799 commitErrors << tr(
"SUCCESS: %n attribute value(s) changed.",
"changed attribute values count",
mChangedAttributeValues.size() );
800 attributesChanged =
true;
806 commitErrors << tr(
"ERROR: %n attribute value change(s) not applied.",
"not changed attribute values count",
mChangedAttributeValues.size() );
808 QString list =
"ERROR: pending changes:";
814 for (
int idx : constKeys )
820 commitErrors << list;
829bool QgsVectorLayerEditBuffer::commitChangesDeleteFeatures(
bool &featuresDeleted, QStringList &commitErrors )
831 featuresDeleted =
false;
838 commitErrors << tr(
"SUCCESS: %n feature(s) deleted.",
"deleted features count",
mDeletedFeatureIds.size() );
839 featuresDeleted =
true;
853 commitErrors << tr(
"ERROR: %n feature(s) not deleted.",
"not deleted features count",
mDeletedFeatureIds.size() );
855 QString list =
"ERROR: pending deletes:";
861 commitErrors << list;
869bool QgsVectorLayerEditBuffer::commitChangesAddFeatures(
bool &featuresAdded, QStringList &commitErrors )
871 featuresAdded =
false;
878 QList<QgsFeatureId> ids;
886 for (
int i = 0; i < featuresToAdd.count(); ++i )
893 commitErrors << tr(
"SUCCESS: %n feature(s) added.",
"added features count", featuresToAdd.size() );
894 featuresAdded =
true;
898 for (
int i = 0; i < featuresToAdd.count(); ++i )
900 if ( featuresToAdd[i].
id() != ids[i] )
903 if (
L->mSelectedFeatureIds.contains( ids[i] ) )
905 L->mSelectedFeatureIds.remove( ids[i] );
906 L->mSelectedFeatureIds.insert( featuresToAdd[i].
id() );
917 commitErrors << tr(
"ERROR: %n feature(s) not added.",
"not added features count",
mAddedFeatures.size() );
919 QString list =
"ERROR: pending adds:";
924 for (
int i = 0; i <
L->
fields().size(); i++ )
926 list.append( QString(
" %1:%2" ).arg(
L->
fields().
at( i ).
name() ).arg( f.attributes()[i].toString() ) );
930 commitErrors << list;
937 commitErrors << tr(
"ERROR: %n feature(s) not added - provider doesn't support adding features.",
"not added features count",
mAddedFeatures.size() );
virtual QString name() const =0
Returns a provider name.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
Encapsulate a field in an attribute table or data source.
QString typeName() const
Gets the field type.
Container of fields for a vector layer.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
void remove(int fieldIdx)
Removes the field with the given index.
@ OriginExpression
Field is calculated from an expression.
@ OriginEdit
Field has been temporarily added in editing mode (originIndex = index in the list of added attributes...
@ OriginJoin
Field comes from a joined layer (originIndex / 1000 = index of the join, originIndex % 1000 = index w...
@ OriginProvider
Field comes from the underlying data provider of the vector layer (originIndex = index in provider's ...
int count() const
Returns number of items.
FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
int fieldOriginIndex(int fieldIdx) const
Returns the field's origin index (its meaning is specific to each type of origin).
bool rename(int fieldIdx, const QString &name)
Renames a name of field.
A geometry is the spatial representation of a feature.
QString providerType() const
Returns the provider type (provider key) for this layer.
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
QUndoStack * undoStack()
Returns pointer to layer's undo stack.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
This is the base class for vector data providers.
@ ChangeFeatures
Supports joint updates for attributes and geometry. Providers supporting this should still define Cha...
@ ChangeGeometries
Allows modifications of geometries.
@ DeleteAttributes
Allows deletion of attributes (fields)
@ DeleteFeatures
Allows deletion of features.
@ AddAttributes
Allows addition of new attributes (fields)
@ RenameAttributes
Supports renaming attributes (fields). Since QGIS 2.16.
@ ChangeAttributeValues
Allows modification of attribute values.
@ AddFeatures
Allows adding features.
QgsWkbTypes::Type wkbType() const override=0
Returns the geometry type which is returned by this layer.
bool supportedType(const QgsField &field) const
check if provider supports type of field
virtual bool changeGeometryValues(const QgsGeometryMap &geometry_map)
Changes geometries of existing features.
void clearErrors()
Clear recorded errors.
QStringList errors() const
Gets recorded errors.
virtual bool doesStrictFeatureTypeCheck() const
Returns true if the provider is strict about the type of inserted features (e.g.
QgsGeometry convertToProviderType(const QgsGeometry &geom) const
Converts the geometry to the provider type if possible / necessary.
virtual bool changeFeatures(const QgsChangedAttributesMap &attr_map, const QgsGeometryMap &geometry_map)
Changes attribute values and geometries of existing features.
virtual bool changeAttributeValues(const QgsChangedAttributesMap &attr_map)
Changes attribute values of existing features.
virtual bool deleteFeatures(const QgsFeatureIds &id)
Deletes one or more features from the provider.
bool addFeatures(QgsFeatureList &flist, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) override
Adds a list of features to the sink.
QgsFields fields() const override=0
Returns the fields associated with this data provider.
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes to the provider.
virtual Q_INVOKABLE QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
virtual bool renameAttributes(const QgsFieldNameMap &renamedAttributes)
Renames existing attributes.
virtual bool deleteAttributes(const QgsAttributeIds &attributes)
Deletes existing attributes from the provider.
bool hasErrors() const
Provider has errors to report.
The edit buffer group manages a group of edit buffers.
void committedAttributesDeleted(const QString &layerId, const QgsAttributeList &deletedAttributes)
Signals emitted after committing changes.
virtual bool deleteFeature(QgsFeatureId fid)
Delete a feature from the layer (but does not commit it)
QgsFeatureMap mAddedFeatures
New features which are not committed.
void setEditBufferGroup(QgsVectorLayerEditBufferGroup *editBufferGroup)
Set the parent edit buffer group for this edit buffer.
void committedAttributeValuesChanges(const QString &layerId, const QgsChangedAttributesMap &changedAttributesValues)
friend class QgsVectorLayerUndoCommandAddFeature
virtual bool renameAttribute(int attr, const QString &newName)
Renames an attribute field (but does not commit it)
void updateFeatureGeometry(QgsFeature &f)
Update feature with uncommitted geometry updates.
virtual bool deleteFeatures(const QgsFeatureIds &fid)
Deletes a set of features from the layer (but does not commit it)
void handleAttributeDeleted(int index)
Update added and changed features after removal of an attribute.
virtual bool addAttribute(const QgsField &field)
Adds an attribute field (but does not commit it) returns true if the field was added.
void committedAttributesAdded(const QString &layerId, const QList< QgsField > &addedAttributes)
virtual bool addFeatures(QgsFeatureList &features)
Insert a copy of the given features into the layer (but does not commit it)
QgsVectorLayerEditBuffer()=default
Constructor for QgsVectorLayerEditBuffer.
QgsFieldNameMap mRenamedAttributes
Renamed attributes which are not committed.
QgsFeatureIds allAddedOrEditedFeatures() const
Returns a list of the features IDs for all newly added or edited features in the buffer.
QgsGeometryMap mChangedGeometries
Changed geometries which are not committed.
void committedAttributesRenamed(const QString &layerId, const QgsFieldNameMap &renamedAttributes)
Emitted after committing an attribute rename.
virtual bool changeAttributeValues(QgsFeatureId fid, const QgsAttributeMap &newValues, const QgsAttributeMap &oldValues)
Changes values of attributes (but does not commit it).
QgsAttributeList mDeletedAttributeIds
Deleted attributes fields which are not committed. The list is kept sorted.
QgsFeatureIds mDeletedFeatureIds
Deleted feature IDs which are not committed.
virtual bool isModified() const
Returns true if the provider has been modified since the last commit.
void updateFields(QgsFields &fields)
Updates fields.
void committedFeaturesAdded(const QString &layerId, const QgsFeatureList &addedFeatures)
void featureDeleted(QgsFeatureId fid)
QgsVectorLayerEditBufferGroup * editBufferGroup() const
Returns the parent edit buffer group for this edit buffer, or nullptr if not part of a group.
void committedGeometriesChanges(const QString &layerId, const QgsGeometryMap &changedGeometries)
virtual bool addFeature(QgsFeature &f)
Adds a feature.
virtual void rollBack()
Stop editing and discard the edits.
friend class QgsVectorLayerUndoCommandRenameAttribute
friend class QgsVectorLayerUndoCommandChangeGeometry
void undoIndexChanged(int index)
QgsVectorLayerEditBufferGroup * mEditBufferGroup
friend class QgsVectorLayerUndoCommandDeleteAttribute
void featureAdded(QgsFeatureId fid)
QgsChangedAttributesMap mChangedAttributeValues
Changed attributes values which are not committed.
virtual bool commitChanges(QStringList &commitErrors)
Attempts to commit any changes to disk.
friend class QgsVectorLayerUndoCommandChangeAttribute
friend class QgsVectorLayerUndoCommandAddAttribute
void handleAttributeAdded(int index)
Update added and changed features after addition of an attribute.
virtual bool deleteAttribute(int attr)
Deletes an attribute field (but does not commit it)
virtual bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant())
Changed an attribute value (but does not commit it)
void updateAttributeMapIndex(QgsAttributeMap &attrs, int index, int offset) const
Updates an index in an attribute map to a new value (for updates of changed attributes)
QList< QgsField > mAddedAttributes
Added attributes fields which are not committed.
virtual bool changeGeometry(QgsFeatureId fid, const QgsGeometry &geom)
Change feature's geometry.
void layerModified()
Emitted when modifications has been done on layer.
void updateChangedAttributes(QgsFeature &f)
Update feature with uncommitted attribute updates.
void committedFeaturesRemoved(const QString &layerId, const QgsFeatureIds &deletedFeatureIds)
friend class QgsVectorLayerUndoCommandDeleteFeature
static void matchAttributesToFields(QgsFeature &feature, const QgsFields &fields)
Matches the attributes in feature to the specified fields.
Represents a vector layer which manages a vector based data sets.
void updateFields()
Will regenerate the fields property of this layer by obtaining all fields from the dataProvider,...
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QString storageType() const
Returns the permanent storage type for this layer as a friendly name.
virtual void updateExtents(bool force=false)
Update the extents for the layer.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
QMap< int, QVariant > QgsAttributeMap
QList< QgsFeature > QgsFeatureList
QSet< QgsFeatureId > QgsFeatureIds
#define FID_TO_STRING(fid)
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
#define QgsDebugMsgLevel(str, level)
void mapToReversedLists(const QMap< Key, T > &map, QList< Key > &ks, QList< T > &vs)
populate two lists (ks, vs) from map - in reverse order