16#include "moc_qgsvectorlayereditbuffer.cpp"
29template <
class Key,
class T>
void mapToReversedLists(
const QMap< Key, T > &map, QList<Key> &ks, QList<T> &vs )
31 ks.reserve( map.size() );
32 vs.reserve( map.size() );
33 typename QMap<Key, T>::const_iterator i = map.constEnd();
34 while ( i != map.constBegin() )
38 vs.append( i.value() );
60 QgsDebugMsgLevel( QStringLiteral(
"undo index changed %1" ).arg( index ), 4 );
79 fields.
rename( renameIt.key(), renameIt.value() );
123 for ( QgsAttributeMap::const_iterator it = map.begin(); it != map.end(); ++it )
124 attrs[it.key()] = it.value();
161 bool anyAdded =
false;
162 for ( QgsFeatureList::iterator iter = features.begin(); iter != features.end(); ++iter )
164 const bool thisFeatureResult =
addFeature( *iter );
165 result = result && thisFeatureResult;
166 anyAdded |= thisFeatureResult;
187 QgsDebugError( QStringLiteral(
"Cannot delete features (missing DeleteFeature capability)" ) );
195 QgsDebugError( QStringLiteral(
"Cannot delete features (in the list of added features)" ) );
203 QgsDebugError( QStringLiteral(
"Cannot delete features (in the list of deleted features)" ) );
216 QgsDebugError( QStringLiteral(
"Cannot delete features (missing DeleteFeatures capability)" ) );
263 for (
auto it = newValues.constBegin() ; it != newValues.constEnd(); ++it )
265 const int field = it.key();
266 const QVariant newValue = it.value();
269 if ( oldValues.contains( field ) )
270 oldValue = oldValues[field];
311 if ( field.
name().isEmpty() )
315 for (
const QgsField &updatedField : fields )
317 if ( updatedField.name() == field.
name() )
356 if ( newName.isEmpty() )
363 for (
const QgsField &updatedField : fields )
365 if ( updatedField.name() == newName )
376 commitErrors.clear();
388 success &= commitChangesCheckGeometryTypeCompatibility( commitErrors );
395 bool attributesChanged =
false;
398 bool attributesDeleted =
false;
399 success &= commitChangesDeleteAttributes( attributesDeleted, commitErrors );
400 attributesChanged |= attributesDeleted;
406 bool attributesRenamed =
false;
407 success &= commitChangesRenameAttributes( attributesRenamed, commitErrors );
408 attributesChanged |= attributesRenamed;
416 bool attributesAdded =
false;
417 success &= commitChangesAddAttributes( attributesAdded, commitErrors );
418 attributesChanged |= attributesAdded;
424 if ( success && attributesChanged )
425 success &= commitChangesCheckAttributesModifications( oldFields, commitErrors );
432 bool attributesChanged;
433 success &= commitChangesChangeAttributes( attributesChanged, commitErrors );
441 bool featuresDeleted;
442 success &= commitChangesDeleteFeatures( featuresDeleted, commitErrors );
451 success &= commitChangesAddFeatures( featuresAdded, commitErrors );
457 commitErrors << tr(
"\n Provider errors:" );
458 const auto constErrors = provider->
errors();
459 for ( QString e : constErrors )
461 commitErrors <<
" " + e.replace(
'\n', QLatin1String(
"\n " ) );
492QString QgsVectorLayerEditBuffer::dumpEditBuffer()
497 msg +=
"CHANGED GEOMETRIES:\n";
501 msg += QString(
"- FID %1: %2" ).arg( it.key() ).arg( it.value().to );
522 attrs.insert( index, QVariant() );
523 featureIt->setAttributes( attrs );
525 const QgsFields oldFields = featureIt->fields();
526 for (
int i = 0; i < oldFields.
size(); i++ )
534 if ( index == oldFields.
size() )
538 featureIt->setFields( fields,
false );
544 std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end(), std::greater< int >() );
545 const auto constSortedRenamedIndices = sortedRenamedIndices;
546 for (
int renameIndex : constSortedRenamedIndices )
548 if ( renameIndex >= index )
565 if ( attrMap.contains( index ) )
566 attrMap.remove( index );
577 attrs.remove( index );
578 featureIt->setAttributes( attrs );
581 featureIt->setFields( fields,
false );
587 std::sort( sortedRenamedIndices.begin(), sortedRenamedIndices.end() );
590 const auto constSortedRenamedIndices = sortedRenamedIndices;
591 for (
int renameIndex : constSortedRenamedIndices )
593 if ( renameIndex > index )
609 for ( QgsAttributeMap::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
611 int attrIndex = it.key();
612 updatedMap.insert( attrIndex < index ? attrIndex : attrIndex + offset, it.value() );
624bool QgsVectorLayerEditBuffer::commitChangesCheckGeometryTypeCompatibility( QStringList &commitErrors )
635 if ( ( ! f.hasGeometry() ) ||
641 commitErrors << tr(
"ERROR: %n feature(s) not added - geometry type is not compatible with the current layer.",
"not added features count",
mAddedFeatures.size() );
649 commitErrors << tr(
"ERROR: %n feature(s) not added - provider doesn't support adding features.",
"not added features count",
mAddedFeatures.size() );
656bool QgsVectorLayerEditBuffer::commitChangesDeleteAttributes(
bool &attributesDeleted, QStringList &commitErrors )
658 attributesDeleted =
false;
665 commitErrors << tr(
"SUCCESS: %n attribute(s) deleted.",
"deleted attributes count",
mDeletedAttributeIds.size() );
670 attributesDeleted =
true;
674 commitErrors << tr(
"ERROR: %n attribute(s) not deleted.",
"not deleted attributes count",
mDeletedAttributeIds.size() );
676 QString list =
"ERROR: Pending attribute deletes:";
678 for (
int idx : constMDeletedAttributeIds )
682 commitErrors << list;
690bool QgsVectorLayerEditBuffer::commitChangesRenameAttributes(
bool &attributesRenamed, QStringList &commitErrors )
692 attributesRenamed =
false;
699 commitErrors << tr(
"SUCCESS: %n attribute(s) renamed.",
"renamed attributes count",
mRenamedAttributes.size() );
704 attributesRenamed =
true;
708 commitErrors << tr(
"ERROR: %n attribute(s) not renamed",
"not renamed attributes count",
mRenamedAttributes.size() );
715bool QgsVectorLayerEditBuffer::commitChangesAddAttributes(
bool &attributesAdded, QStringList &commitErrors )
717 attributesAdded =
false;
724 commitErrors << tr(
"SUCCESS: %n attribute(s) added.",
"added attributes count",
mAddedAttributes.size() );
727 attributesAdded =
true;
731 commitErrors << tr(
"ERROR: %n new attribute(s) not added",
"not added attributes count",
mAddedAttributes.size() );
733 QString list =
"ERROR: Pending adds:";
735 for (
QgsField f : constMAddedAttributes )
737 list.append(
' ' + f.name() );
739 commitErrors << list;
747bool QgsVectorLayerEditBuffer::commitChangesCheckAttributesModifications(
const QgsFields oldFields, QStringList &commitErrors )
754 commitErrors << tr(
"ERROR: the count of fields is incorrect after addition/removal of fields!" );
758 for (
int i = 0; i < std::min( oldFields.
count(), newFields.
count() ); ++i )
762 if ( oldField != newField )
765 << tr(
"ERROR: field with index %1 is not the same!" ).arg( i )
768 << QStringLiteral(
"%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
769 .arg( tr(
"expected field" ),
771 QVariant::typeToName( oldField.
type() ),
775 << QStringLiteral(
"%1: name=%2 type=%3 typeName=%4 len=%5 precision=%6" )
776 .arg( tr(
"retrieved field" ),
778 QVariant::typeToName( newField.
type() ),
789bool QgsVectorLayerEditBuffer::commitChangesChangeAttributes(
bool &attributesChanged, QStringList &commitErrors )
791 attributesChanged =
false;
801 attributesChanged =
true;
820 commitErrors << tr(
"ERROR: %1 geometries not changed. Data provider '%2' does not have ChangeFeatures or ChangeGeometries capabilities",
"not changed geometries count" )
828 commitErrors << tr(
"SUCCESS: %n geometries were changed.",
"changed geometries count",
mChangedGeometries.size() );
829 attributesChanged =
true;
835 commitErrors << tr(
"ERROR: %n geometries not changed.",
"not changed geometries count",
mChangedGeometries.size() );
845 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" )
853 commitErrors << tr(
"SUCCESS: %n attribute value(s) changed.",
"changed attribute values count",
mChangedAttributeValues.size() );
854 attributesChanged =
true;
860 commitErrors << tr(
"ERROR: %n attribute value change(s) not applied.",
"not changed attribute values count",
mChangedAttributeValues.size() );
862 QString list =
"ERROR: pending changes:";
868 for (
int idx : constKeys )
874 commitErrors << list;
883bool QgsVectorLayerEditBuffer::commitChangesDeleteFeatures(
bool &featuresDeleted, QStringList &commitErrors )
885 featuresDeleted =
false;
892 commitErrors << tr(
"SUCCESS: %n feature(s) deleted.",
"deleted features count",
mDeletedFeatureIds.size() );
893 featuresDeleted =
true;
907 commitErrors << tr(
"ERROR: %n feature(s) not deleted.",
"not deleted features count",
mDeletedFeatureIds.size() );
909 QString list =
"ERROR: pending deletes:";
915 commitErrors << list;
923bool QgsVectorLayerEditBuffer::commitChangesAddFeatures(
bool &featuresAdded, QStringList &commitErrors )
925 featuresAdded =
false;
932 QList<QgsFeatureId> ids;
940 for (
int i = 0; i < featuresToAdd.count(); ++i )
948 commitErrors << tr(
"SUCCESS: %n feature(s) added.",
"added features count", featuresToAdd.size() );
949 featuresAdded =
true;
953 for (
int i = 0; i < featuresToAdd.count(); ++i )
955 if ( featuresToAdd[i].
id() != ids[i] )
958 if (
L->mSelectedFeatureIds.contains( ids[i] ) )
960 L->mSelectedFeatureIds.remove( ids[i] );
961 L->mSelectedFeatureIds.insert( featuresToAdd[i].
id() );
972 commitErrors << tr(
"ERROR: %n feature(s) not added.",
"not added features count",
mAddedFeatures.size() );
974 QString list =
"ERROR: pending adds:";
979 for (
int i = 0; i <
L->
fields().size(); i++ )
981 list.append( QString(
" %1:%2" ).arg(
L->
fields().
at( i ).
name() ).arg( f.attributes()[i].toString() ) );
985 commitErrors << list;
992 commitErrors << tr(
"ERROR: %n feature(s) not added - provider doesn't support adding features.",
"not added features count",
mAddedFeatures.size() );
@ ChangeFeatures
Supports joint updates for attributes and geometry. Providers supporting this should still define Cha...
@ AddFeatures
Allows adding features.
@ ChangeGeometries
Allows modifications of geometries.
@ AddAttributes
Allows addition of new attributes (fields)
@ RenameAttributes
Supports renaming attributes (fields)
@ DeleteFeatures
Allows deletion of features.
@ DeleteAttributes
Allows deletion of attributes (fields)
@ ChangeAttributeValues
Allows modification of attribute values.
@ Provider
Field originates from the underlying data provider of the vector layer.
@ Edit
Field has been temporarily added in editing mode.
@ Expression
Field is calculated from an expression.
@ Join
Field originates from a joined layer.
virtual QString name() const =0
Returns a provider name.
@ RollBackOnErrors
Roll back the whole transaction if a single add feature operation fails.
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.
int attributeCount() const
Returns the number of attributes attached to the feature.
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, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Q_INVOKABLE int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
void remove(int fieldIdx)
Removes the field with the given index.
Qgis::FieldOrigin fieldOrigin(int fieldIdx) const
Returns the field's origin (value from an enumeration).
int size() const
Returns number of items.
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.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
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, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
This is the base class for vector data providers.
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 Q_INVOKABLE Qgis::VectorProviderCapabilities capabilities() const
Returns flags containing the supported capabilities.
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.
Qgis::WkbType wkbType() const override=0
Returns the geometry type which is returned by this layer.
virtual bool addAttributes(const QList< QgsField > &attributes)
Adds new attributes to the provider.
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)
Emitted after attribute deletion has been committed to the layer.
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)
Emitted after feature attribute value changes have been committed to the layer.
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)
Emitted after attribute addition has been committed to the layer.
virtual bool addFeatures(QgsFeatureList &features)
Insert a copy of the given features into the layer (but does not commit it)
QgsVectorLayerEditBuffer()=default
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)
Emitted after feature addition has been committed to the layer.
void featureDeleted(QgsFeatureId fid)
Emitted when a feature was deleted from the buffer.
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)
Emitted after feature geometry changes have been committed to the layer.
virtual bool addFeature(QgsFeature &f)
Adds a feature.
virtual void rollBack()
Stop editing and discard the edits.
friend class QgsVectorLayerUndoCommandRenameAttribute
void handleAttributeAdded(int index, const QgsField &field)
Update added and changed features after addition of an attribute.
friend class QgsVectorLayerUndoCommandChangeGeometry
void undoIndexChanged(int index)
QgsVectorLayerEditBufferGroup * mEditBufferGroup
friend class QgsVectorLayerUndoCommandDeleteAttribute
void featureAdded(QgsFeatureId fid)
Emitted when a feature has been added to the buffer.
QgsChangedAttributesMap mChangedAttributeValues
Changed attributes values which are not committed.
int mBlockModifiedSignals
virtual bool commitChanges(QStringList &commitErrors)
Attempts to commit any changes to disk.
friend class QgsVectorLayerUndoCommandChangeAttribute
friend class QgsVectorLayerUndoCommandAddAttribute
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)
Emitted after feature removal has been committed to the layer.
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...
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)
#define QgsDebugError(str)
void mapToReversedLists(const QMap< Key, T > &map, QList< Key > &ks, QList< T > &vs)
populate two lists (ks, vs) from map - in reverse order