Skip to content

Commit

Permalink
fix duplication of feature being stopped at 1 level deep (#39623)
Browse files Browse the repository at this point in the history
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
qgis-bot and github-actions[bot] committed Oct 28, 2020
1 parent 8d7f8ed commit c7aa269
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 11 deletions.
7 changes: 5 additions & 2 deletions python/core/auto_generated/qgsvectorlayerutils.sip.in
Expand Up @@ -204,18 +204,21 @@ automatically inserted into the layer.
.. versionadded:: 3.6
%End

static QgsFeature duplicateFeature( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext /Out/ );
static QgsFeature duplicateFeature( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, QgsDuplicateFeatureContext &duplicateFeatureContext /Out/, const int maxDepth = 0 );
%Docstring
Duplicates a feature and it's children (one level deep). It calls CreateFeature, so
default values and constraints (e.g., unique constraints) will automatically be handled.
The duplicated feature will be automatically inserted into the layer.
``depth`` the higher this number the deeper the level - With depth > 0 the children of the feature are not duplicated
``duplicateFeatureContext`` stores all the layers and the featureids of the duplicated features (incl. children)
``maxDepth`` the maximum depth to duplicate children in relations, 0 is unlimited depth (in any case, limited to 100)
``depth`` the current depth, not exposed in Python
``referencedLayersBranch`` the current branch of layers across the relations, not exposed in Python, taken by copy not reference, used to avoid infinite loop

.. versionadded:: 3.0
%End



static void matchAttributesToFields( QgsFeature &feature, const QgsFields &fields );
%Docstring
Matches the attributes in ``feature`` to the specified ``fields``.
Expand Down
4 changes: 2 additions & 2 deletions src/app/qgisapp.cpp
Expand Up @@ -16478,7 +16478,7 @@ QgsFeature QgisApp::duplicateFeatures( QgsMapLayer *mlayer, const QgsFeature &fe
{
QgsVectorLayerUtils::QgsDuplicateFeatureContext duplicateFeatureContext;

QgsVectorLayerUtils::duplicateFeature( layer, f, QgsProject::instance(), 0, duplicateFeatureContext );
QgsVectorLayerUtils::duplicateFeature( layer, f, QgsProject::instance(), duplicateFeatureContext );
featureCount += 1;

const auto duplicatedFeatureContextLayers = duplicateFeatureContext.layers();
Expand Down Expand Up @@ -16529,7 +16529,7 @@ QgsFeature QgisApp::duplicateFeatureDigitized( QgsMapLayer *mlayer, const QgsFea

QgsFeature newFeature = feature;
newFeature.setGeometry( digitizedFeature.geometry() );
QgsVectorLayerUtils::duplicateFeature( layer, newFeature, QgsProject::instance(), 0, duplicateFeatureContext );
QgsVectorLayerUtils::duplicateFeature( layer, newFeature, QgsProject::instance(), duplicateFeatureContext );

QString childrenInfo;
const auto duplicateFeatureContextLayers = duplicateFeatureContext.layers();
Expand Down
16 changes: 12 additions & 4 deletions src/core/qgsvectorlayerutils.cpp
Expand Up @@ -42,6 +42,7 @@
#include "qgsstyle.h"
#include "qgsauxiliarystorage.h"


QgsFeatureIterator QgsVectorLayerUtils::getValuesIterator( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly )
{
std::unique_ptr<QgsExpression> expression;
Expand Down Expand Up @@ -622,7 +623,7 @@ QgsFeatureList QgsVectorLayerUtils::createFeatures( const QgsVectorLayer *layer,
return result;
}

QgsFeature QgsVectorLayerUtils::duplicateFeature( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext )
QgsFeature QgsVectorLayerUtils::duplicateFeature( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, QgsDuplicateFeatureContext &duplicateFeatureContext, const int maxDepth, int depth, QList<QgsVectorLayer *> referencedLayersBranch )
{
if ( !layer )
return QgsFeature();
Expand All @@ -639,12 +640,16 @@ QgsFeature QgsVectorLayerUtils::duplicateFeature( QgsVectorLayer *layer, const Q

const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );

const int effectiveMaxDepth = maxDepth > 0 ? maxDepth : 100;

for ( const QgsRelation &relation : relations )
{
//check if composition (and not association)
if ( relation.strength() == QgsRelation::Composition && depth < 1 )
if ( relation.strength() == QgsRelation::Composition && !referencedLayersBranch.contains( relation.referencedLayer() ) && depth < effectiveMaxDepth )
{
depth++;
referencedLayersBranch << layer;

//get features connected over this relation
QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( feature );
QgsFeatureIds childFeatureIds;
Expand All @@ -660,7 +665,7 @@ QgsFeature QgsVectorLayerUtils::duplicateFeature( QgsVectorLayer *layer, const Q
childFeature.setAttribute( fieldPair.first, newFeature.attribute( fieldPair.second ) );
}
//call the function for the child
childFeatureIds.insert( duplicateFeature( relation.referencingLayer(), childFeature, project, depth, duplicateFeatureContext ).id() );
childFeatureIds.insert( duplicateFeature( relation.referencingLayer(), childFeature, project, duplicateFeatureContext, maxDepth, depth, referencedLayersBranch ).id() );
}

//store for feedback
Expand Down Expand Up @@ -827,7 +832,10 @@ QgsFeatureIds QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicatedFeature

void QgsVectorLayerUtils::QgsDuplicateFeatureContext::setDuplicatedFeatures( QgsVectorLayer *layer, const QgsFeatureIds &ids )
{
mDuplicatedFeatures.insert( layer, ids );
if ( mDuplicatedFeatures.contains( layer ) )
mDuplicatedFeatures[layer] += ids;
else
mDuplicatedFeatures.insert( layer, ids );
}
/*
QMap<QgsVectorLayer *, QgsFeatureIds> QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicateFeatureContext() const
Expand Down
7 changes: 5 additions & 2 deletions src/core/qgsvectorlayerutils.h
Expand Up @@ -205,11 +205,14 @@ class CORE_EXPORT QgsVectorLayerUtils
* Duplicates a feature and it's children (one level deep). It calls CreateFeature, so
* default values and constraints (e.g., unique constraints) will automatically be handled.
* The duplicated feature will be automatically inserted into the layer.
* \a depth the higher this number the deeper the level - With depth > 0 the children of the feature are not duplicated
* \a duplicateFeatureContext stores all the layers and the featureids of the duplicated features (incl. children)
* \a maxDepth the maximum depth to duplicate children in relations, 0 is unlimited depth (in any case, limited to 100)
* \a depth the current depth, not exposed in Python
* \a referencedLayersBranch the current branch of layers across the relations, not exposed in Python, taken by copy not reference, used to avoid infinite loop
* \since QGIS 3.0
*/
static QgsFeature duplicateFeature( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext SIP_OUT );
static QgsFeature duplicateFeature( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, QgsDuplicateFeatureContext &duplicateFeatureContext SIP_OUT, const int maxDepth = 0, int depth SIP_PYARGREMOVE = 0, QList<QgsVectorLayer *> referencedLayersBranch SIP_PYARGREMOVE = QList<QgsVectorLayer *>() );


/**
* Gets the feature source from a QgsVectorLayer pointer.
Expand Down
2 changes: 1 addition & 1 deletion src/gui/qgsrelationeditorwidget.cpp
Expand Up @@ -637,7 +637,7 @@ void QgsRelationEditorWidget::duplicateFeature()
while ( fit.nextFeature( f ) )
{
QgsVectorLayerUtils::QgsDuplicateFeatureContext duplicatedFeatureContext;
QgsVectorLayerUtils::duplicateFeature( layer, f, QgsProject::instance(), 0, duplicatedFeatureContext );
QgsVectorLayerUtils::duplicateFeature( layer, f, QgsProject::instance(), duplicatedFeatureContext );
}
}

Expand Down

0 comments on commit c7aa269

Please sign in to comment.