Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Backport release-3_16] fix duplication of feature being stopped at 1 level deep #39623

Merged
merged 1 commit into from
Oct 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions python/core/auto_generated/qgsvectorlayerutils.sip.in
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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