34 mLayers.insert( layer );
52 if ( layer->isModified() )
63 bool editingStarted =
true;
66 if ( !layer->isValid() )
68 editingStarted =
false;
69 QgsLogger::debug( tr(
"Can't start editing invalid layer '%1'." ).arg( layer->name() ) );
73 if ( !layer->dataProvider() )
75 editingStarted =
false;
76 QgsLogger::debug( tr(
"Can't start editing layer '%1' with invalid data provider." ).arg( layer->name() ) );
81 if ( !layer->supportsEditing() )
83 editingStarted =
false;
84 QgsLogger::debug( tr(
"Can't start editing. Layer '%1' doesn't support editing." ).arg( layer->name() ) );
88 if ( layer->editBuffer() )
91 layer->editBuffer()->setEditBufferGroup(
this );
96 emit layer->beforeEditingStarted();
97 layer->dataProvider()->enterUpdateMode();
98 layer->createEditBuffer();
99 layer->editBuffer()->setEditBufferGroup(
this );
100 layer->updateFields();
101 emit layer->editingStarted();
104 if ( ! editingStarted )
106 QStringList rollbackErrors;
107 if ( !
rollBack( rollbackErrors,
true ) )
108 QgsLogger::debug( tr(
"Can't rollback after start editing failure. Roll back detailed errors: %1" ).arg( rollbackErrors.join(
" / " ) ) );
111 mIsEditing = editingStarted;
119 const QSet<QgsVectorLayer *> constModifiedLayers =
modifiedLayers();
120 if ( constModifiedLayers.isEmpty() )
122 editingFinished( stopEditing );
123 mIsEditing = !stopEditing;
127 QMap<QString, QSet<QgsVectorLayer *> > connectionStringsLayers;
132 QList<QgsVectorLayer *> transactionLayers;
133 QList<std::shared_ptr<QgsTransaction> > openTransactions;
134 const QStringList connectionStrings = connectionStringsLayers.keys();
135 for (
const QString &connectionString : connectionStrings )
137 const QString providerKey = ( *connectionStringsLayers.value( connectionString ).begin() )->providerType();
139 std::shared_ptr<QgsTransaction> transaction;
143 commitErrors << tr(
"ERROR: data source '%1', is not available for transactions." ).arg( connectionString );
149 if ( ! transaction->begin( errorMsg ) )
151 commitErrors << tr(
"ERROR: could not start a transaction on data provider '%1', detailed error: '%2'." ).arg( providerKey, errorMsg );
156 const auto constLayers = connectionStringsLayers.value( connectionString );
159 if ( ! transaction->addLayer( layer,
true ) )
161 commitErrors << tr(
"ERROR: could not add layer '%1' to transaction on data provider '%2'." ).arg( layer->name(), providerKey );
166 transactionLayers.append( layer );
169 openTransactions.append( transaction );
176 const QList<QgsVectorLayer *> orderedLayers = orderLayersParentsToChildren( constModifiedLayers );
177 QList<QgsVectorLayer *>::const_iterator orderedLayersIterator;
182 for ( orderedLayersIterator = orderedLayers.constBegin(); orderedLayersIterator != orderedLayers.constEnd(); ++orderedLayersIterator )
184 success = ( *orderedLayersIterator )->editBuffer()->commitChangesCheckGeometryTypeCompatibility( commitErrors );
190 QSet<QgsVectorLayer *> modifiedLayersOnProviderSide;
195 for ( orderedLayersIterator = orderedLayers.constBegin(); orderedLayersIterator != orderedLayers.constEnd(); ++orderedLayersIterator )
197 QgsFields oldFields = ( *orderedLayersIterator )->fields();
199 bool attributesDeleted =
false;
200 success = ( *orderedLayersIterator )->editBuffer()->commitChangesDeleteAttributes( attributesDeleted, commitErrors );
204 bool attributesRenamed =
false;
205 success = ( *orderedLayersIterator )->editBuffer()->commitChangesRenameAttributes( attributesRenamed, commitErrors );
209 bool attributesAdded =
false;
210 success = ( *orderedLayersIterator )->editBuffer()->commitChangesAddAttributes( attributesAdded, commitErrors );
214 if ( attributesDeleted || attributesRenamed || attributesAdded )
216 if ( ! transactionLayers.contains( ( *orderedLayersIterator ) ) )
217 modifiedLayersOnProviderSide.insert( ( *orderedLayersIterator ) );
219 success = ( *orderedLayersIterator )->editBuffer()->commitChangesCheckAttributesModifications( oldFields, commitErrors );
229 orderedLayersIterator = orderedLayers.
constEnd();
230 while ( orderedLayersIterator != orderedLayers.constBegin() )
232 --orderedLayersIterator;
233 bool featuresDeleted;
234 success = ( *orderedLayersIterator )->editBuffer()->commitChangesDeleteFeatures( featuresDeleted, commitErrors );
238 if ( featuresDeleted && transactionLayers.contains( ( *orderedLayersIterator ) ) )
239 modifiedLayersOnProviderSide.insert( ( *orderedLayersIterator ) );
246 for ( orderedLayersIterator = orderedLayers.constBegin(); orderedLayersIterator != orderedLayers.constEnd(); ++orderedLayersIterator )
249 ( *orderedLayersIterator )->editBuffer()->commitChangesAddFeatures( featuresAdded, commitErrors );
253 if ( featuresAdded && transactionLayers.contains( ( *orderedLayersIterator ) ) )
254 modifiedLayersOnProviderSide.insert( ( *orderedLayersIterator ) );
261 orderedLayersIterator = orderedLayers.constEnd();
262 while ( orderedLayersIterator != orderedLayers.constBegin() )
264 --orderedLayersIterator;
266 bool attributesChanged;
267 success = ( *orderedLayersIterator )->editBuffer()->commitChangesChangeAttributes( attributesChanged, commitErrors );
271 if ( attributesChanged && transactionLayers.contains( ( *orderedLayersIterator ) ) )
272 modifiedLayersOnProviderSide.insert( ( *orderedLayersIterator ) );
279 QList<std::shared_ptr<QgsTransaction> >::iterator openTransactionsIterator = openTransactions.begin();
280 while ( openTransactionsIterator != openTransactions.end() )
283 if ( !( *openTransactionsIterator )->commit( errorMsg ) )
286 commitErrors << tr(
"ERROR: could not commit a transaction, detailed error: '%1'." ).arg( errorMsg );
290 modifiedLayersOnProviderSide += connectionStringsLayers.value( ( *openTransactionsIterator )->connectionString() );
291 openTransactionsIterator = openTransactions.erase( openTransactionsIterator );
299 if ( ! modifiedLayersOnProviderSide.isEmpty() )
301 if ( modifiedLayersOnProviderSide.size() == 1 )
302 commitErrors << tr(
"WARNING: changes to layer '%1' where already sent to data provider and cannot be rolled back." ).arg( ( *modifiedLayersOnProviderSide.begin() )->name() );
305 commitErrors << tr(
"WARNING: changes to following layers where already sent to data provider and cannot be rolled back:" );
306 for (
QgsVectorLayer *layer : std::as_const( modifiedLayersOnProviderSide ) )
307 commitErrors << tr(
"- '%1'" ).arg( layer->name() );
311 QString rollbackError;
312 for (
const std::shared_ptr<QgsTransaction> &transaction : openTransactions )
313 transaction->rollback( rollbackError );
318 editingFinished( stopEditing );
320 if ( success && stopEditing )
330 if ( ! layer->editBuffer() )
333 if ( !layer->dataProvider() )
335 rollbackErrors << tr(
"Layer '%1' doesn't have a valid data provider" ).arg( layer->name() );
339 bool rollbackExtent = !layer->editBuffer()->deletedFeatureIds().isEmpty() ||
340 !layer->editBuffer()->addedFeatures().isEmpty() ||
341 !layer->editBuffer()->changedGeometries().isEmpty();
343 emit layer->beforeRollBack();
345 layer->editBuffer()->rollBack();
347 emit layer->afterRollBack();
349 if ( layer->isModified() )
353 layer->undoStack()->setIndex( 0 );
356 layer->updateFields();
360 layer->clearEditBuffer();
361 layer->undoStack()->clear();
362 emit layer->editingStopped();
365 if ( rollbackExtent )
366 layer->updateExtents();
369 layer->dataProvider()->leaveUpdateMode();
371 layer->triggerRepaint();
374 mIsEditing = ! stopEditing;
383QList<QgsVectorLayer *> QgsVectorLayerEditBufferGroup::orderLayersParentsToChildren( QSet<QgsVectorLayer *> layers )
385 QSet<QgsVectorLayer *> referencingLayers;
386 QSet<QgsVectorLayer *> referencedLayers;
392 referencingLayers.insert( relation.referencingLayer() );
393 referencedLayers.insert( relation.referencedLayer() );
397 QList<QgsVectorLayer *> orderedLayers;
401 QSet<QgsVectorLayer *> onlyParents = referencedLayers - referencingLayers;
402 orderedLayers.append( onlyParents.values() );
407 QSet<QgsVectorLayer *> intersection = referencedLayers;
408 intersection.intersect( referencingLayers );
410 QQueue<QgsVectorLayer *> otherLayersQueue;
411 otherLayersQueue.append( intersection.values() );
412 while ( ! otherLayersQueue.isEmpty() )
416 int insertIndex = -1;
421 int index = orderedLayers.indexOf( referencedLayer );
424 insertIndex = std::max( insertIndex, index + 1 );
429 bool circularRelation =
false;
431 for (
const QgsRelation &backRelation : backRelations )
433 if ( backRelation.referencedLayer() == layer )
435 QgsLogger::warning( tr(
"Circular relation between layers '%1' and '%2'. Correct saving order of layers can't be guaranteed" ).arg( layer->
name(), referencedLayer->
name() ) );
436 insertIndex = orderedLayers.size();
437 circularRelation =
true;
442 if ( !circularRelation )
451 if ( insertIndex == -1 )
453 otherLayersQueue.enqueue( layer );
457 orderedLayers.insert( insertIndex, layer );
463 QSet<QgsVectorLayer *> onlyChildren = referencingLayers - referencedLayers;
464 orderedLayers.append( onlyChildren.values() );
469 QSet<QgsVectorLayer *> layersWithoutRelations =
layers - referencedLayers;
470 layersWithoutRelations -= referencingLayers;
471 orderedLayers.append( layersWithoutRelations.values() );
474 return orderedLayers;
477void QgsVectorLayerEditBufferGroup::editingFinished(
bool stopEditing )
481 if ( !layer->mDeletedFids.empty() )
484 layer->mDeletedFids.clear();
488 layer->clearEditBuffer();
virtual bool leaveUpdateMode()
Leave update mode.
virtual void updateExtents()
Update the extents of the layer.
Container of fields for a vector layer.
const_iterator constEnd() const noexcept
Returns a const STL-style iterator pointing to the imaginary item after the last item in the list.
QStringList names() const
Returns a list with field names.
static void debug(const QString &msg, int debuglevel=1, const char *file=nullptr, const char *function=nullptr, int line=-1)
Goes to qDebug.
static void warning(const QString &msg)
Goes to qWarning.
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
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.
QgsRelationManager * relationManager
static QgsProject * instance()
Returns the QgsProject singleton instance.
QList< QgsRelation > referencingRelations(const QgsVectorLayer *layer=nullptr, int fieldIdx=-2) const
Gets all relations where the specified layer (and field) is the referencing part (i....
QMap< QString, QgsRelation > relations() const
Gets access to the relations managed by this class.
static bool supportsTransaction(const QgsVectorLayer *layer)
Checks if the provider of a given layer supports transactions.
QString connectionString() const
Returns the connection string of the transaction.
static QgsTransaction * create(const QString &connString, const QString &providerKey)
Create a transaction for the specified connection string connString and provider with providerKey.
QgsFields fields() const override=0
Returns the fields associated with this data provider.
bool commitChanges(QStringList &commitErrors, bool stopEditing=true)
Attempts to commit any changes to disk.
bool startEditing()
Start editing.
void clear()
Remove all layers from this edit buffer group.
bool rollBack(QStringList &rollbackErrors, bool stopEditing=true)
Stop editing and discard the edits.
void addLayer(QgsVectorLayer *layer)
Add a layer to this edit buffer group.
QSet< QgsVectorLayer * > layers() const
Gets the set of layers currently managed by this edit buffer group.
QSet< QgsVectorLayer * > modifiedLayers() const
Gets the set of modified layers currently managed by this edit buffer group.
QgsVectorLayerEditBufferGroup(QObject *parent=nullptr)
Constructor for QgsEditBufferGroup.
bool isEditing() const
Returns true if the layers are in editing mode.
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,...
QgsFields fields() const FINAL
Returns the list of fields of this layer.
void featuresDeleted(const QgsFeatureIds &fids)
Emitted when features have been deleted.
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
void afterCommitChanges()
Emitted after changes are committed to the data provider.