Skip to content

Commit b6e42c7

Browse files
committedAug 28, 2017
Move join intelligence in QgsVectorlayerJoinBuffer
1 parent 500348e commit b6e42c7

File tree

5 files changed

+286
-120
lines changed

5 files changed

+286
-120
lines changed
 

‎python/core/qgsvectorlayerjoinbuffer.sip

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,82 @@ Quick way to test if there is any join at all
132132
:rtype: QgsVectorLayerJoinBuffer
133133
%End
134134

135+
bool addFeature( const QgsFeature &feature ) const;
136+
%Docstring
137+
Adds a feature in joined layers. The feature given in parameter is the
138+
one added in target layer. If a corresponding joined feature yet exists
139+
in a joined layer, then this feature is just updated. Note that if a
140+
corresponding joined feature has only empty fields, then it's not
141+
created nor added.
142+
143+
\param feature The feature added in the target layer.
144+
145+
:return: false if an error happened, true otherwise
146+
147+
.. versionadded:: 3.0
148+
:rtype: bool
149+
%End
150+
151+
bool addFeatures( const QgsFeatureList &features ) const;
152+
%Docstring
153+
Adds a list of features in joined layers. Features given in parameter
154+
are those added in target layer. If a corresponding joined feature yet
155+
exists in a joined layer, then this feature is just updated. Note that
156+
if a corresponding joined feature has only empty fields, then it's not
157+
created nor added.
158+
159+
\param features The list of features added in the target layer
160+
161+
:return: false if an error happened, true otherwise
162+
163+
.. versionadded:: 3.0
164+
:rtype: bool
165+
%End
166+
167+
bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant() ) const;
168+
%Docstring
169+
Changes attribute value in joined layers. The feature id given in
170+
parameter is the one added in target layer. If the corresponding joined
171+
feature does not exist in a joined layer, then it's automatically
172+
created if its fields are not empty.
173+
174+
\param fid The feature id
175+
\param field The field to update
176+
\param newValue The new value of the attribute
177+
\param oldValue The old value of the attribute
178+
179+
:return: false if an error happened, true otherwise
180+
181+
.. versionadded:: 3.0
182+
:rtype: bool
183+
%End
184+
185+
bool deleteFeature( QgsFeatureId fid ) const;
186+
%Docstring
187+
Deletes a feature from joined layers. The feature id given in
188+
parameter is the one coming from the target layer.
189+
190+
\param fid The feature id from the target layer to delete
191+
192+
:return: false if an error happened, true otherwise
193+
194+
.. versionadded:: 3.0
195+
:rtype: bool
196+
%End
197+
198+
bool deleteFeatures( const QgsFeatureIds &fids ) const;
199+
%Docstring
200+
Deletes a list of features from joined layers. Feature ids given
201+
in aprameter are those coming from the target layer.
202+
203+
\param fids Feature ids from the target layer to delete
204+
205+
:return: false if an error happened, true otherwise
206+
207+
.. versionadded:: 3.0
208+
:rtype: bool
209+
%End
210+
135211
signals:
136212
void joinedFieldsChanged();
137213
%Docstring

‎src/core/qgsvectorlayer.cpp

Lines changed: 5 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,7 @@ bool QgsVectorLayer::addFeature( QgsFeature &feature, Flags )
951951
updateExtents();
952952

953953
if ( mJoinBuffer->containsJoins() )
954-
success = addFeaturesToJoinedLayers( QgsFeatureList() << feature );
954+
success = mJoinBuffer->addFeature( feature );
955955
}
956956

957957
return success;
@@ -2265,27 +2265,7 @@ bool QgsVectorLayer::changeAttributeValue( QgsFeatureId fid, int field, const QV
22652265
{
22662266
if ( fields().fieldOrigin( field ) == QgsFields::OriginJoin )
22672267
{
2268-
int srcFieldIndex;
2269-
const QgsVectorLayerJoinInfo *info = mJoinBuffer->joinForFieldIndex( field, fields(), srcFieldIndex );
2270-
if ( info && info->joinLayer() && info->isEditable() )
2271-
{
2272-
QgsFeature feature = getFeature( fid );
2273-
2274-
if ( !feature.isValid() )
2275-
return false;
2276-
2277-
const QgsFeature joinFeature = mJoinBuffer->joinedFeatureOf( info, feature );
2278-
2279-
if ( joinFeature.isValid() )
2280-
return info->joinLayer()->changeAttributeValue( joinFeature.id(), srcFieldIndex, newValue, oldValue );
2281-
else
2282-
{
2283-
feature.setAttribute( field, newValue );
2284-
return addFeaturesToJoinedLayers( QgsFeatureList() << feature );
2285-
}
2286-
}
2287-
else
2288-
return false;
2268+
return mJoinBuffer->changeAttributeValue( fid, field, newValue, oldValue );
22892269
}
22902270
else
22912271
{
@@ -2442,7 +2422,7 @@ bool QgsVectorLayer::deleteFeature( QgsFeatureId fid )
24422422
return false;
24432423

24442424
if ( mJoinBuffer->containsJoins() )
2445-
deleteFeaturesFromJoinedLayers( QgsFeatureIds() << fid );
2425+
mJoinBuffer->deleteFeature( fid );
24462426

24472427
bool res = mEditBuffer->deleteFeature( fid );
24482428
if ( res )
@@ -2463,7 +2443,7 @@ bool QgsVectorLayer::deleteFeatures( const QgsFeatureIds &fids )
24632443
}
24642444

24652445
if ( mJoinBuffer->containsJoins() )
2466-
deleteFeaturesFromJoinedLayers( fids );
2446+
mJoinBuffer->deleteFeatures( fids );
24672447

24682448
bool res = mEditBuffer->deleteFeatures( fids );
24692449

@@ -2476,26 +2456,6 @@ bool QgsVectorLayer::deleteFeatures( const QgsFeatureIds &fids )
24762456
return res;
24772457
}
24782458

2479-
bool QgsVectorLayer::deleteFeaturesFromJoinedLayers( QgsFeatureIds fids )
2480-
{
2481-
bool rc = false;
2482-
2483-
Q_FOREACH ( const QgsFeatureId &fid, fids )
2484-
{
2485-
Q_FOREACH ( const QgsVectorLayerJoinInfo &info, vectorJoins() )
2486-
{
2487-
if ( info.isEditable() && info.hasCascadedDelete() )
2488-
{
2489-
const QgsFeature joinFeature = mJoinBuffer->joinedFeatureOf( &info, getFeature( fid ) );
2490-
if ( joinFeature.isValid() )
2491-
info.joinLayer()->deleteFeature( joinFeature.id() );
2492-
}
2493-
}
2494-
}
2495-
2496-
return rc;
2497-
}
2498-
24992459
QgsAttributeList QgsVectorLayer::pkAttributeList() const
25002460
{
25012461
QgsAttributeList pkAttributesList;
@@ -2668,83 +2628,11 @@ bool QgsVectorLayer::addFeatures( QgsFeatureList &features, Flags )
26682628
updateExtents();
26692629

26702630
if ( res && mJoinBuffer->containsJoins() )
2671-
res = addFeaturesToJoinedLayers( features );
2631+
res = mJoinBuffer->addFeatures( features );
26722632

26732633
return res;
26742634
}
26752635

2676-
bool QgsVectorLayer::addFeaturesToJoinedLayers( QgsFeatureList &features, Flags )
2677-
{
2678-
// try to add/update a feature in each joined layer
2679-
Q_FOREACH ( const QgsVectorLayerJoinInfo &info, vectorJoins() )
2680-
{
2681-
QgsVectorLayer *joinLayer = info.joinLayer();
2682-
2683-
if ( joinLayer && joinLayer->isEditable() && info.isEditable() && info.hasUpsertOnEdit() )
2684-
{
2685-
QgsFeatureList joinFeatures;
2686-
2687-
Q_FOREACH ( const QgsFeature &feature, features )
2688-
{
2689-
const QgsFeature joinFeature = info.extractJoinedFeature( feature );
2690-
2691-
// we don't want to add a new feature in joined layer when the id
2692-
// column value yet exist, we just want to update the existing one
2693-
const QVariant idFieldValue = feature.attribute( info.targetFieldName() );
2694-
const QString filter = QgsExpression::createFieldEqualityExpression( info.joinFieldName(), idFieldValue.toString() );
2695-
2696-
QgsFeatureRequest request;
2697-
request.setFilterExpression( filter );
2698-
request.setLimit( 1 );
2699-
2700-
QgsFeatureIterator it = info.joinLayer()->getFeatures( request );
2701-
QgsFeature existingFeature;
2702-
it.nextFeature( existingFeature );
2703-
2704-
if ( existingFeature.isValid() )
2705-
{
2706-
const QStringList *subsetFields = info.joinFieldNamesSubset();
2707-
if ( subsetFields )
2708-
{
2709-
Q_FOREACH ( const QString &field, *subsetFields )
2710-
existingFeature.setAttribute( field, joinFeature.attribute( field ) );
2711-
}
2712-
else
2713-
{
2714-
Q_FOREACH ( const QgsField &field, joinFeature.fields() )
2715-
existingFeature.setAttribute( field.name(), joinFeature.attribute( field.name() ) );
2716-
}
2717-
2718-
joinLayer->updateFeature( existingFeature );
2719-
}
2720-
else
2721-
{
2722-
// joined feature is added only if one of its field is not null
2723-
bool notNullFields = false;
2724-
Q_FOREACH ( const QgsField &field, joinFeature.fields() )
2725-
{
2726-
if ( field.name() == info.joinFieldName() )
2727-
continue;
2728-
2729-
if ( !joinFeature.attribute( field.name() ).isNull() )
2730-
{
2731-
notNullFields = true;
2732-
break;
2733-
}
2734-
}
2735-
2736-
if ( notNullFields )
2737-
joinFeatures << joinFeature;
2738-
}
2739-
}
2740-
2741-
joinLayer->addFeatures( joinFeatures );
2742-
}
2743-
}
2744-
2745-
return true;
2746-
}
2747-
27482636
void QgsVectorLayer::setCoordinateSystem()
27492637
{
27502638
QgsDebugMsg( "----- Computing Coordinate System" );

‎src/core/qgsvectorlayer.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,9 +1932,6 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
19321932
//! Read simple labeling from layer's custom properties (QGIS 2.x projects)
19331933
QgsAbstractVectorLayerLabeling *readLabelingFromCustomProperties();
19341934

1935-
bool addFeaturesToJoinedLayers( QgsFeatureList &features, Flags flags = 0 );
1936-
bool deleteFeaturesFromJoinedLayers( QgsFeatureIds fids );
1937-
19381935
#ifdef SIP_RUN
19391936
QgsVectorLayer( const QgsVectorLayer &rhs );
19401937
#endif

‎src/core/qgsvectorlayerjoinbuffer.cpp

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,3 +517,137 @@ void QgsVectorLayerJoinBuffer::connectJoinedLayer( QgsVectorLayer *vl )
517517
connect( vl, &QgsVectorLayer::layerModified, this, &QgsVectorLayerJoinBuffer::joinedLayerModified, Qt::UniqueConnection );
518518
connect( vl, &QgsVectorLayer::willBeDeleted, this, &QgsVectorLayerJoinBuffer::joinedLayerWillBeDeleted, Qt::UniqueConnection );
519519
}
520+
521+
bool QgsVectorLayerJoinBuffer::addFeature( const QgsFeature &feature ) const
522+
{
523+
return addFeatures( QgsFeatureList() << feature );
524+
}
525+
526+
bool QgsVectorLayerJoinBuffer::addFeatures( const QgsFeatureList &features ) const
527+
{
528+
if ( !containsJoins() )
529+
return false;
530+
531+
// try to add/update a feature in each joined layer
532+
Q_FOREACH ( const QgsVectorLayerJoinInfo &info, vectorJoins() )
533+
{
534+
QgsVectorLayer *joinLayer = info.joinLayer();
535+
536+
if ( joinLayer && joinLayer->isEditable() && info.isEditable() && info.hasUpsertOnEdit() )
537+
{
538+
QgsFeatureList joinFeatures;
539+
540+
Q_FOREACH ( const QgsFeature &feature, features )
541+
{
542+
const QgsFeature joinFeature = info.extractJoinedFeature( feature );
543+
544+
// we don't want to add a new feature in joined layer when the id
545+
// column value yet exist, we just want to update the existing one
546+
const QVariant idFieldValue = feature.attribute( info.targetFieldName() );
547+
const QString filter = QgsExpression::createFieldEqualityExpression( info.joinFieldName(), idFieldValue.toString() );
548+
549+
QgsFeatureRequest request;
550+
request.setFilterExpression( filter );
551+
request.setLimit( 1 );
552+
553+
QgsFeatureIterator it = info.joinLayer()->getFeatures( request );
554+
QgsFeature existingFeature;
555+
it.nextFeature( existingFeature );
556+
557+
if ( existingFeature.isValid() )
558+
{
559+
const QStringList *subsetFields = info.joinFieldNamesSubset();
560+
if ( subsetFields )
561+
{
562+
Q_FOREACH ( const QString &field, *subsetFields )
563+
existingFeature.setAttribute( field, joinFeature.attribute( field ) );
564+
}
565+
else
566+
{
567+
Q_FOREACH ( const QgsField &field, joinFeature.fields() )
568+
existingFeature.setAttribute( field.name(), joinFeature.attribute( field.name() ) );
569+
}
570+
571+
joinLayer->updateFeature( existingFeature );
572+
}
573+
else
574+
{
575+
// joined feature is added only if one of its field is not null
576+
bool notNullFields = false;
577+
Q_FOREACH ( const QgsField &field, joinFeature.fields() )
578+
{
579+
if ( field.name() == info.joinFieldName() )
580+
continue;
581+
582+
if ( !joinFeature.attribute( field.name() ).isNull() )
583+
{
584+
notNullFields = true;
585+
break;
586+
}
587+
}
588+
589+
if ( notNullFields )
590+
joinFeatures << joinFeature;
591+
}
592+
}
593+
594+
joinLayer->addFeatures( joinFeatures );
595+
}
596+
}
597+
598+
return true;
599+
}
600+
601+
bool QgsVectorLayerJoinBuffer::changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue ) const
602+
{
603+
if ( mLayer->fields().fieldOrigin( field ) != QgsFields::OriginJoin )
604+
return false;
605+
606+
int srcFieldIndex;
607+
const QgsVectorLayerJoinInfo *info = joinForFieldIndex( field, mLayer->fields(), srcFieldIndex );
608+
if ( info && info->joinLayer() && info->isEditable() )
609+
{
610+
QgsFeature feature = mLayer->getFeature( fid );
611+
612+
if ( !feature.isValid() )
613+
return false;
614+
615+
const QgsFeature joinFeature = joinedFeatureOf( info, feature );
616+
617+
if ( joinFeature.isValid() )
618+
return info->joinLayer()->changeAttributeValue( joinFeature.id(), srcFieldIndex, newValue, oldValue );
619+
else
620+
{
621+
feature.setAttribute( field, newValue );
622+
return addFeatures( QgsFeatureList() << feature );
623+
}
624+
}
625+
else
626+
return false;
627+
}
628+
629+
bool QgsVectorLayerJoinBuffer::deleteFeature( QgsFeatureId fid ) const
630+
{
631+
return deleteFeatures( QgsFeatureIds() << fid );
632+
}
633+
634+
bool QgsVectorLayerJoinBuffer::deleteFeatures( const QgsFeatureIds &fids ) const
635+
{
636+
if ( !containsJoins() )
637+
return false;
638+
639+
Q_FOREACH ( const QgsFeatureId &fid, fids )
640+
{
641+
Q_FOREACH ( const QgsVectorLayerJoinInfo &info, vectorJoins() )
642+
{
643+
if ( info.isEditable() && info.hasCascadedDelete() )
644+
{
645+
const QgsFeature joinFeature = joinedFeatureOf( &info, mLayer->getFeature( fid ) );
646+
if ( joinFeature.isValid() )
647+
info.joinLayer()->deleteFeature( joinFeature.id() );
648+
}
649+
}
650+
}
651+
652+
return true;
653+
}

‎src/core/qgsvectorlayerjoinbuffer.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,77 @@ class CORE_EXPORT QgsVectorLayerJoinBuffer : public QObject
109109
//! \since QGIS 2.6
110110
QgsVectorLayerJoinBuffer *clone() const SIP_FACTORY;
111111

112+
/**
113+
* Adds a feature in joined layers. The feature given in parameter is the
114+
* one added in target layer. If a corresponding joined feature yet exists
115+
* in a joined layer, then this feature is just updated. Note that if a
116+
* corresponding joined feature has only empty fields, then it's not
117+
* created nor added.
118+
*
119+
* \param feature The feature added in the target layer.
120+
*
121+
* \returns false if an error happened, true otherwise
122+
*
123+
* \since QGIS 3.0
124+
*/
125+
bool addFeature( const QgsFeature &feature ) const;
126+
127+
/**
128+
* Adds a list of features in joined layers. Features given in parameter
129+
* are those added in target layer. If a corresponding joined feature yet
130+
* exists in a joined layer, then this feature is just updated. Note that
131+
* if a corresponding joined feature has only empty fields, then it's not
132+
* created nor added.
133+
*
134+
* \param features The list of features added in the target layer
135+
*
136+
* \returns false if an error happened, true otherwise
137+
*
138+
* \since QGIS 3.0
139+
*/
140+
bool addFeatures( const QgsFeatureList &features ) const;
141+
142+
/**
143+
* Changes attribute value in joined layers. The feature id given in
144+
* parameter is the one added in target layer. If the corresponding joined
145+
* feature does not exist in a joined layer, then it's automatically
146+
* created if its fields are not empty.
147+
*
148+
* \param fid The feature id
149+
* \param field The field to update
150+
* \param newValue The new value of the attribute
151+
* \param oldValue The old value of the attribute
152+
*
153+
* \returns false if an error happened, true otherwise
154+
*
155+
* \since QGIS 3.0
156+
*/
157+
bool changeAttributeValue( QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue = QVariant() ) const;
158+
159+
/**
160+
* Deletes a feature from joined layers. The feature id given in
161+
* parameter is the one coming from the target layer.
162+
*
163+
* \param fid The feature id from the target layer to delete
164+
*
165+
* \returns false if an error happened, true otherwise
166+
*
167+
* \since QGIS 3.0
168+
*/
169+
bool deleteFeature( QgsFeatureId fid ) const;
170+
171+
/**
172+
* Deletes a list of features from joined layers. Feature ids given
173+
* in aprameter are those coming from the target layer.
174+
*
175+
* \param fids Feature ids from the target layer to delete
176+
*
177+
* \returns false if an error happened, true otherwise
178+
*
179+
* \since QGIS 3.0
180+
*/
181+
bool deleteFeatures( const QgsFeatureIds &fids ) const;
182+
112183
signals:
113184
//! Emitted whenever the list of joined fields changes (e.g. added join or joined layer's fields change)
114185
//! \since QGIS 2.6

0 commit comments

Comments
 (0)
Please sign in to comment.