Skip to content

Commit

Permalink
on deleting a feature, it deletes the relating children, when "cascad…
Browse files Browse the repository at this point in the history
…e" parameter is true, the relation strength is a composition.

"cascade" parameter is true on every "normal" delete fired by the user interface. It's not true, on functions like merge feature or offline editing synchronization etc.
  • Loading branch information
signedav committed May 7, 2020
1 parent 9cc2496 commit f352793
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 32 deletions.
13 changes: 10 additions & 3 deletions python/core/auto_generated/qgsvectorlayer.sip.in
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1259,10 +1259,13 @@ Deletes a vertex from a feature.
.. versionadded:: 2.14 .. versionadded:: 2.14
%End %End


bool deleteSelectedFeatures( int *deletedCount = 0 ); bool deleteSelectedFeatures( int *deletedCount = 0, const bool cascade = false );
%Docstring %Docstring
Deletes the selected features Deletes the selected features


:param deleteCount: The number of successfully deleted features
:param cascade: If the decendants of the feature should be deleted as well

:return: ``True`` in case of success and ``False`` otherwise :return: ``True`` in case of success and ``False`` otherwise
%End %End


Expand Down Expand Up @@ -1941,10 +1944,13 @@ Deletes a list of attribute fields (but does not commit it)
virtual bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 ) ${SIP_FINAL}; virtual bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 ) ${SIP_FINAL};




bool deleteFeature( QgsFeatureId fid ); bool deleteFeature( QgsFeatureId fid, const bool cascade = false );
%Docstring %Docstring
Deletes a feature from the layer (but does not commit it). Deletes a feature from the layer (but does not commit it).


:param fid: The feature id to delete
:param cascade: If the decendants of the feature should be deleted as well

.. note:: .. note::


Calls to deleteFeature() are only valid for layers in which edits have been enabled Calls to deleteFeature() are only valid for layers in which edits have been enabled
Expand All @@ -1953,11 +1959,12 @@ Deletes a feature from the layer (but does not commit it).
changes can be discarded by calling rollBack(). changes can be discarded by calling rollBack().
%End %End


bool deleteFeatures( const QgsFeatureIds &fids ); bool deleteFeatures( const QgsFeatureIds &fids, const bool cascade = false );
%Docstring %Docstring
Deletes a set of features from the layer (but does not commit it) Deletes a set of features from the layer (but does not commit it)


:param fids: The feature ids to delete :param fids: The feature ids to delete
:param cascade: If the decendants of the feature should be deleted as well


:return: ``False`` if the layer is not in edit mode or does not support deleting :return: ``False`` if the layer is not in edit mode or does not support deleting
in case of an active transaction depends on the provider implementation in case of an active transaction depends on the provider implementation
Expand Down
4 changes: 2 additions & 2 deletions python/core/auto_generated/qgsvectorlayerjoinbuffer.sip.in
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ created if its fields are not empty.
.. versionadded:: 3.0 .. versionadded:: 3.0
%End %End


bool deleteFeature( QgsFeatureId fid ) const; bool deleteFeature( QgsFeatureId fid, const bool cascade = false ) const;
%Docstring %Docstring
Deletes a feature from joined layers. The feature id given in Deletes a feature from joined layers. The feature id given in
parameter is the one coming from the target layer. parameter is the one coming from the target layer.
Expand All @@ -220,7 +220,7 @@ parameter is the one coming from the target layer.
.. versionadded:: 3.0 .. versionadded:: 3.0
%End %End


bool deleteFeatures( const QgsFeatureIds &fids ) const; bool deleteFeatures( const QgsFeatureIds &fids, const bool cascade = false ) const;
%Docstring %Docstring
Deletes a list of features from joined layers. Feature ids given Deletes a list of features from joined layers. Feature ids given
in a parameter are those coming from the target layer. in a parameter are those coming from the target layer.
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgisapp.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -9003,7 +9003,7 @@ void QgisApp::deleteSelected( QgsMapLayer *layer, QWidget *parent, bool checkFea


vlayer->beginEditCommand( tr( "Features deleted" ) ); vlayer->beginEditCommand( tr( "Features deleted" ) );
int deletedCount = 0; int deletedCount = 0;
if ( !vlayer->deleteSelectedFeatures( &deletedCount ) ) if ( !vlayer->deleteSelectedFeatures( &deletedCount, true ) )
{ {
visibleMessageBar()->pushMessage( tr( "Problem deleting features" ), visibleMessageBar()->pushMessage( tr( "Problem deleting features" ),
tr( "A problem occurred during deletion from layer \"%1\". %n feature(s) not deleted.", nullptr, numberOfSelectedFeatures - deletedCount ).arg( vlayer->name() ), tr( "A problem occurred during deletion from layer \"%1\". %n feature(s) not deleted.", nullptr, numberOfSelectedFeatures - deletedCount ).arg( vlayer->name() ),
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsattributetabledialog.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -864,7 +864,7 @@ void QgsAttributeTableDialog::setFilterExpression( const QString &filterString,
void QgsAttributeTableDialog::deleteFeature( const QgsFeatureId fid ) void QgsAttributeTableDialog::deleteFeature( const QgsFeatureId fid )
{ {
QgsDebugMsg( QStringLiteral( "Delete %1" ).arg( fid ) ); QgsDebugMsg( QStringLiteral( "Delete %1" ).arg( fid ) );
mLayer->deleteFeature( fid ); mLayer->deleteFeature( fid, true );
} }


void QgsAttributeTableDialog::showContextMenu( QgsActionMenu *menu, const QgsFeatureId fid ) void QgsAttributeTableDialog::showContextMenu( QgsActionMenu *menu, const QgsFeatureId fid )
Expand Down
42 changes: 34 additions & 8 deletions src/core/qgsvectorlayer.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1140,7 +1140,7 @@ QgsVectorLayer::EditResult QgsVectorLayer::deleteVertex( QgsFeatureId featureId,
} }




bool QgsVectorLayer::deleteSelectedFeatures( int *deletedCount ) bool QgsVectorLayer::deleteSelectedFeatures( int *deletedCount, const bool cascade )
{ {
if ( !mValid || !mDataProvider || !( mDataProvider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) ) if ( !mValid || !mDataProvider || !( mDataProvider->capabilities() & QgsVectorDataProvider::DeleteFeatures ) )
{ {
Expand All @@ -1159,7 +1159,7 @@ bool QgsVectorLayer::deleteSelectedFeatures( int *deletedCount )
const auto constSelectedFeatures = selectedFeatures; const auto constSelectedFeatures = selectedFeatures;
for ( QgsFeatureId fid : constSelectedFeatures ) for ( QgsFeatureId fid : constSelectedFeatures )
{ {
deleted += deleteFeature( fid ); // removes from selection deleted += deleteFeature( fid, cascade ); // removes from selection
} }


triggerRepaint(); triggerRepaint();
Expand Down Expand Up @@ -3164,25 +3164,51 @@ bool QgsVectorLayer::deleteAttributes( const QList<int> &attrs )
return deleted; return deleted;
} }


bool QgsVectorLayer::deleteFeatureWithDependencies( QgsFeatureId fid ) bool QgsVectorLayer::deleteFeatureWithDependencies( QgsFeatureId fid, const bool cascade )
{ {
if ( !mEditBuffer ) if ( !mEditBuffer )
return false; return false;


if ( cascade )
{

const QList<QgsRelation> relations = QgsProject::instance()->relationManager()->referencedRelations( this );

for ( const QgsRelation &relation : relations )
{
//check if composition (and not association)
if ( relation.strength() == QgsRelation::Composition )
{
//get features connected over this relation
QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( getFeature( fid ) );
QgsFeatureIds childFeatureIds;
QgsFeature childFeature;
while ( relatedFeaturesIt.nextFeature( childFeature ) )
{
childFeatureIds.insert( childFeature.id() );
}

//set childlayer editable
relation.referencingLayer()->startEditing();
relation.referencingLayer()->deleteFeatures( childFeatureIds );
}
}
}

if ( mJoinBuffer->containsJoins() ) if ( mJoinBuffer->containsJoins() )
mJoinBuffer->deleteFeature( fid ); mJoinBuffer->deleteFeature( fid, cascade );


bool res = mEditBuffer->deleteFeature( fid ); bool res = mEditBuffer->deleteFeature( fid );


return res; return res;
} }


bool QgsVectorLayer::deleteFeature( QgsFeatureId fid ) bool QgsVectorLayer::deleteFeature( QgsFeatureId fid, const bool cascade )
{ {
if ( !mEditBuffer ) if ( !mEditBuffer )
return false; return false;


bool res = deleteFeatureWithDependencies( fid ); bool res = deleteFeatureWithDependencies( fid, cascade );


if ( res ) if ( res )
{ {
Expand All @@ -3193,12 +3219,12 @@ bool QgsVectorLayer::deleteFeature( QgsFeatureId fid )
return res; return res;
} }


bool QgsVectorLayer::deleteFeatures( const QgsFeatureIds &fids ) bool QgsVectorLayer::deleteFeatures( const QgsFeatureIds &fids, const bool cascade )
{ {
bool res = true; bool res = true;
const auto constFids = fids; const auto constFids = fids;
for ( QgsFeatureId fid : constFids ) for ( QgsFeatureId fid : constFids )
res = deleteFeatureWithDependencies( fid ) && res; res = deleteFeatureWithDependencies( fid, cascade ) && res;


if ( res ) if ( res )
{ {
Expand Down
16 changes: 11 additions & 5 deletions src/core/qgsvectorlayer.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1278,9 +1278,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte


/** /**
* Deletes the selected features * Deletes the selected features
* \returns TRUE in case of success and FALSE otherwise * \param deleteCount The number of successfully deleted features
* \param cascade If the decendants of the feature should be deleted as well
*
* \returns TRUE in case of success and FALSE otherwise
*/ */
Q_INVOKABLE bool deleteSelectedFeatures( int *deletedCount = nullptr ); Q_INVOKABLE bool deleteSelectedFeatures( int *deletedCount = nullptr, const bool cascade = false );


/** /**
* Adds a ring to polygon/multipolygon features * Adds a ring to polygon/multipolygon features
Expand Down Expand Up @@ -1812,17 +1815,20 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte


/** /**
* Deletes a feature from the layer (but does not commit it). * Deletes a feature from the layer (but does not commit it).
* \param fid The feature id to delete
* \param cascade If the decendants of the feature should be deleted as well
* *
* \note Calls to deleteFeature() are only valid for layers in which edits have been enabled * \note Calls to deleteFeature() are only valid for layers in which edits have been enabled
* by a call to startEditing(). Changes made to features using this method are not committed * by a call to startEditing(). Changes made to features using this method are not committed
* to the underlying data provider until a commitChanges() call is made. Any uncommitted * to the underlying data provider until a commitChanges() call is made. Any uncommitted
* changes can be discarded by calling rollBack(). * changes can be discarded by calling rollBack().
*/ */
bool deleteFeature( QgsFeatureId fid ); bool deleteFeature( QgsFeatureId fid, const bool cascade = false );


/** /**
* Deletes a set of features from the layer (but does not commit it) * Deletes a set of features from the layer (but does not commit it)
* \param fids The feature ids to delete * \param fids The feature ids to delete
* \param cascade If the decendants of the feature should be deleted as well
* *
* \returns FALSE if the layer is not in edit mode or does not support deleting * \returns FALSE if the layer is not in edit mode or does not support deleting
* in case of an active transaction depends on the provider implementation * in case of an active transaction depends on the provider implementation
Expand All @@ -1832,7 +1838,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
* to the underlying data provider until a commitChanges() call is made. Any uncommitted * to the underlying data provider until a commitChanges() call is made. Any uncommitted
* changes can be discarded by calling rollBack(). * changes can be discarded by calling rollBack().
*/ */
bool deleteFeatures( const QgsFeatureIds &fids ); bool deleteFeatures( const QgsFeatureIds &fids, const bool cascade = false );


/** /**
* Attempts to commit to the underlying data provider any buffered changes made since the * Attempts to commit to the underlying data provider any buffered changes made since the
Expand Down Expand Up @@ -2689,7 +2695,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
//! Read simple labeling from layer's custom properties (QGIS 2.x projects) //! Read simple labeling from layer's custom properties (QGIS 2.x projects)
QgsAbstractVectorLayerLabeling *readLabelingFromCustomProperties(); QgsAbstractVectorLayerLabeling *readLabelingFromCustomProperties();


bool deleteFeatureWithDependencies( QgsFeatureId fid ); bool deleteFeatureWithDependencies( QgsFeatureId fid, const bool cascade = false );


#ifdef SIP_RUN #ifdef SIP_RUN
QgsVectorLayer( const QgsVectorLayer &rhs ); QgsVectorLayer( const QgsVectorLayer &rhs );
Expand Down
8 changes: 4 additions & 4 deletions src/core/qgsvectorlayerjoinbuffer.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -663,12 +663,12 @@ bool QgsVectorLayerJoinBuffer::changeAttributeValues( QgsFeatureId fid, const Qg
return success; return success;
} }


bool QgsVectorLayerJoinBuffer::deleteFeature( QgsFeatureId fid ) const bool QgsVectorLayerJoinBuffer::deleteFeature( QgsFeatureId fid, const bool cascade ) const
{ {
return deleteFeatures( QgsFeatureIds() << fid ); return deleteFeatures( QgsFeatureIds() << fid, cascade );
} }


bool QgsVectorLayerJoinBuffer::deleteFeatures( const QgsFeatureIds &fids ) const bool QgsVectorLayerJoinBuffer::deleteFeatures( const QgsFeatureIds &fids, const bool cascade ) const
{ {
if ( !containsJoins() ) if ( !containsJoins() )
return false; return false;
Expand All @@ -683,7 +683,7 @@ bool QgsVectorLayerJoinBuffer::deleteFeatures( const QgsFeatureIds &fids ) const
{ {
const QgsFeature joinFeature = joinedFeatureOf( &info, mLayer->getFeature( fid ) ); const QgsFeature joinFeature = joinedFeatureOf( &info, mLayer->getFeature( fid ) );
if ( joinFeature.isValid() ) if ( joinFeature.isValid() )
info.joinLayer()->deleteFeature( joinFeature.id() ); info.joinLayer()->deleteFeature( joinFeature.id(), cascade );
} }
} }
} }
Expand Down
4 changes: 2 additions & 2 deletions src/core/qgsvectorlayerjoinbuffer.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ class CORE_EXPORT QgsVectorLayerJoinBuffer : public QObject, public QgsFeatureSi
* *
* \since QGIS 3.0 * \since QGIS 3.0
*/ */
bool deleteFeature( QgsFeatureId fid ) const; bool deleteFeature( QgsFeatureId fid, const bool cascade = false ) const;


/** /**
* Deletes a list of features from joined layers. Feature ids given * Deletes a list of features from joined layers. Feature ids given
Expand All @@ -214,7 +214,7 @@ class CORE_EXPORT QgsVectorLayerJoinBuffer : public QObject, public QgsFeatureSi
* *
* \since QGIS 3.0 * \since QGIS 3.0
*/ */
bool deleteFeatures( const QgsFeatureIds &fids ) const; bool deleteFeatures( const QgsFeatureIds &fids, const bool cascade = false ) const;


signals: signals:


Expand Down
10 changes: 4 additions & 6 deletions src/gui/qgsrelationeditorwidget.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -667,10 +667,8 @@ void QgsRelationEditorWidget::deleteFeatures( const QgsFeatureIds &featureids )
// When deleting a linked feature within an N:M relation, // When deleting a linked feature within an N:M relation,
// check if the feature is linked to more than just one feature. // check if the feature is linked to more than just one feature.
// In case it is linked more than just once, ask the user for confirmation // In case it is linked more than just once, ask the user for confirmation
// as it is likely he was not aware of the implications and might either // as it is likely he was not aware of the implications and might delete
// leave the dataset in a corrupted state (referential integrity) or if // there may be several linking entries deleted along.
// the fk constraint is ON CASCADE DELETE, there may be several linking
// entries deleted along.


QgsFeatureRequest deletedFeaturesRequest; QgsFeatureRequest deletedFeaturesRequest;
deletedFeaturesRequest.setFilterFids( featureids ); deletedFeaturesRequest.setFilterFids( featureids );
Expand Down Expand Up @@ -732,7 +730,7 @@ void QgsRelationEditorWidget::deleteFeatures( const QgsFeatureIds &featureids )


if ( deleteFeatures ) if ( deleteFeatures )
{ {
layer->deleteFeatures( featureids ); layer->deleteFeatures( featureids, true );
updateUi(); updateUi();
} }
} }
Expand Down Expand Up @@ -793,7 +791,7 @@ void QgsRelationEditorWidget::unlinkFeatures( const QgsFeatureIds &featureids )
QgsDebugMsgLevel( FID_TO_STRING( f.id() ), 4 ); QgsDebugMsgLevel( FID_TO_STRING( f.id() ), 4 );
} }


mRelation.referencingLayer()->deleteFeatures( fids ); mRelation.referencingLayer()->deleteFeatures( fids, false );


updateUi(); updateUi();
} }
Expand Down

0 comments on commit f352793

Please sign in to comment.