diff --git a/python/core/auto_generated/qgsvectorlayer.sip.in b/python/core/auto_generated/qgsvectorlayer.sip.in index b62e1074a332..c66f7e6e3cc5 100644 --- a/python/core/auto_generated/qgsvectorlayer.sip.in +++ b/python/core/auto_generated/qgsvectorlayer.sip.in @@ -391,8 +391,18 @@ Constructor for LayerOptions. Constructor for DeleteContext. %End - QList handledLayers() const; + QList handledLayers( bool includeAuxiliaryLayers = true ) const; +%Docstring +Returns a list of all layers affected by the delete operation. + +If ``includeAuxiliaryLayers`` is ``False`` then auxiliary layers will not be included in the +returned list. +%End + QgsFeatureIds handledFeatures( QgsVectorLayer *layer ) const; +%Docstring +Returns a list of feature IDs from the specified ``layer`` affected by the delete operation. +%End bool cascade; QgsProject *project; diff --git a/python/core/auto_generated/qgsvectorlayerutils.sip.in b/python/core/auto_generated/qgsvectorlayerutils.sip.in index b6feb3a8dd10..9059f63e03ae 100644 --- a/python/core/auto_generated/qgsvectorlayerutils.sip.in +++ b/python/core/auto_generated/qgsvectorlayerutils.sip.in @@ -299,7 +299,14 @@ The following operations will be performed to convert the input features: .. versionadded:: 3.12 %End - static bool impactsCascadeFeatures( const QgsVectorLayer *layer, const QgsFeatureIds &fids, const QgsProject *project, QgsDuplicateFeatureContext &context /Out/ ); + enum CascadedFeatureFlag + { + IgnoreAuxiliaryLayers, + }; + typedef QFlags CascadedFeatureFlags; + + + static bool impactsCascadeFeatures( const QgsVectorLayer *layer, const QgsFeatureIds &fids, const QgsProject *project, QgsDuplicateFeatureContext &context /Out/, CascadedFeatureFlags flags = CascadedFeatureFlags() ); %Docstring :return: ``True`` if at least one feature of the ``fids`` on ``layer`` is connected as parent in at diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index fc47dae0486c..7fb46c21db5b 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -9245,7 +9245,7 @@ void QgisApp::deleteSelected( QgsMapLayer *layer, QWidget *parent, bool checkFea } QgsVectorLayerUtils::QgsDuplicateFeatureContext infoContext; - if ( QgsVectorLayerUtils::impactsCascadeFeatures( vlayer, vlayer->selectedFeatureIds(), QgsProject::instance(), infoContext ) ) + if ( QgsVectorLayerUtils::impactsCascadeFeatures( vlayer, vlayer->selectedFeatureIds(), QgsProject::instance(), infoContext, QgsVectorLayerUtils::IgnoreAuxiliaryLayers ) ) { QString childrenInfo; int childrenCount = 0; @@ -9275,8 +9275,8 @@ void QgisApp::deleteSelected( QgsMapLayer *layer, QWidget *parent, bool checkFea } else { - const auto contextLayers = context.handledLayers(); - // if it affects more than one layer, print feedback for all descendants + const QList contextLayers = context.handledLayers( false ); + // if it affects more than one non-auxiliary layer, print feedback for all descendants if ( contextLayers.size() > 1 ) { deletedCount = 0; diff --git a/src/app/qgsattributetabledialog.cpp b/src/app/qgsattributetabledialog.cpp index 01be8b3278fa..eeb2302a3699 100644 --- a/src/app/qgsattributetabledialog.cpp +++ b/src/app/qgsattributetabledialog.cpp @@ -926,7 +926,7 @@ void QgsAttributeTableDialog::deleteFeature( const QgsFeatureId fid ) QgsDebugMsg( QStringLiteral( "Delete %1" ).arg( fid ) ); QgsVectorLayerUtils::QgsDuplicateFeatureContext infoContext; - if ( QgsVectorLayerUtils::impactsCascadeFeatures( mLayer, QgsFeatureIds() << fid, QgsProject::instance(), infoContext ) ) + if ( QgsVectorLayerUtils::impactsCascadeFeatures( mLayer, QgsFeatureIds() << fid, QgsProject::instance(), infoContext, QgsVectorLayerUtils::IgnoreAuxiliaryLayers ) ) { QString childrenInfo; int childrenCount = 0; @@ -947,7 +947,7 @@ void QgsAttributeTableDialog::deleteFeature( const QgsFeatureId fid ) QgsVectorLayer::DeleteContext context( true, QgsProject::instance() ); mLayer->deleteFeature( fid, &context ); - const auto contextLayers = context.handledLayers(); + const QList contextLayers = context.handledLayers( false ); //if it effected more than one layer, print feedback for all descendants if ( contextLayers.size() > 1 ) { diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index a89af89b75c9..e8e41debfe43 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -5614,12 +5614,15 @@ void QgsVectorLayer::onDirtyTransaction( const QString &sql, const QString &name } } -QList QgsVectorLayer::DeleteContext::handledLayers() const +QList QgsVectorLayer::DeleteContext::handledLayers( bool includeAuxiliaryLayers ) const { QList layers; QMap::const_iterator i; for ( i = mHandledFeatures.begin(); i != mHandledFeatures.end(); ++i ) - layers.append( i.key() ); + { + if ( includeAuxiliaryLayers || !qobject_cast< QgsAuxiliaryLayer * >( i.key() ) ) + layers.append( i.key() ); + } return layers; } diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h index ccc53c58cb92..aef973405dd1 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -516,7 +516,17 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte */ explicit DeleteContext( bool cascade = false, QgsProject *project = nullptr ): cascade( cascade ), project( project ) {} - QList handledLayers() const; + /** + * Returns a list of all layers affected by the delete operation. + * + * If \a includeAuxiliaryLayers is FALSE then auxiliary layers will not be included in the + * returned list. + */ + QList handledLayers( bool includeAuxiliaryLayers = true ) const; + + /** + * Returns a list of feature IDs from the specified \a layer affected by the delete operation. + */ QgsFeatureIds handledFeatures( QgsVectorLayer *layer ) const; QMap mHandledFeatures SIP_SKIP; diff --git a/src/core/qgsvectorlayerutils.cpp b/src/core/qgsvectorlayerutils.cpp index 031aa1ef0e32..6fcb5404ec44 100644 --- a/src/core/qgsvectorlayerutils.cpp +++ b/src/core/qgsvectorlayerutils.cpp @@ -40,6 +40,7 @@ #include "qgssymbollayer.h" #include "qgsstyleentityvisitor.h" #include "qgsstyle.h" +#include "qgsauxiliarystorage.h" QgsFeatureIterator QgsVectorLayerUtils::getValuesIterator( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly ) { @@ -971,7 +972,7 @@ QString QgsVectorLayerUtils::getFeatureDisplayString( const QgsVectorLayer *laye return displayString; } -bool QgsVectorLayerUtils::impactsCascadeFeatures( const QgsVectorLayer *layer, const QgsFeatureIds &fids, const QgsProject *project, QgsDuplicateFeatureContext &context ) +bool QgsVectorLayerUtils::impactsCascadeFeatures( const QgsVectorLayer *layer, const QgsFeatureIds &fids, const QgsProject *project, QgsDuplicateFeatureContext &context, CascadedFeatureFlags flags ) { if ( !layer ) return false; @@ -1015,9 +1016,12 @@ bool QgsVectorLayerUtils::impactsCascadeFeatures( const QgsVectorLayer *layer, c if ( layer->joinBuffer()->containsJoins() ) { - const auto constVectorJoins = layer->joinBuffer()->vectorJoins(); - for ( const QgsVectorLayerJoinInfo &info : constVectorJoins ) + const QgsVectorJoinList joins = layer->joinBuffer()->vectorJoins(); + for ( const QgsVectorLayerJoinInfo &info : joins ) { + if ( qobject_cast< QgsAuxiliaryLayer * >( info.joinLayer() ) && flags & IgnoreAuxiliaryLayers ) + continue; + if ( info.isEditable() && info.hasCascadedDelete() ) { QgsFeatureIds joinFeatureIds; diff --git a/src/core/qgsvectorlayerutils.h b/src/core/qgsvectorlayerutils.h index 15a5311d7120..9ecc40a476f9 100644 --- a/src/core/qgsvectorlayerutils.h +++ b/src/core/qgsvectorlayerutils.h @@ -322,13 +322,24 @@ class CORE_EXPORT QgsVectorLayerUtils */ static QString getFeatureDisplayString( const QgsVectorLayer *layer, const QgsFeature &feature ); + /** + * Flags that can be used when determining cascaded features. + * + * \since QGIS 3.4 + */ + enum CascadedFeatureFlag + { + IgnoreAuxiliaryLayers = 1 << 1, //!< Ignore auxiliary layers + }; + Q_DECLARE_FLAGS( CascadedFeatureFlags, CascadedFeatureFlag ) + /** * \returns TRUE if at least one feature of the \a fids on \a layer is connected as parent in at * least one composition relation of the \a project or contains joins, where cascade delete is set. * Details about cascading effects will be written to \a context. * \since QGIS 3.14 */ - static bool impactsCascadeFeatures( const QgsVectorLayer *layer, const QgsFeatureIds &fids, const QgsProject *project, QgsDuplicateFeatureContext &context SIP_OUT ); + static bool impactsCascadeFeatures( const QgsVectorLayer *layer, const QgsFeatureIds &fids, const QgsProject *project, QgsDuplicateFeatureContext &context SIP_OUT, CascadedFeatureFlags flags = CascadedFeatureFlags() ); };