QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsabstractrelationeditorwidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsabstractrelationeditorwidget.cpp
3 ----------------------
4 begin : October 2020
5 copyright : (C) 2020 by Ivan Ivanov
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include "qgsexpression.h"
22#include "qgsfeature.h"
23#include "qgsfeatureiterator.h"
26#include "qgsproject.h"
27#include "qgsrelation.h"
28#include "qgsrelationmanager.h"
29#include "qgstransactiongroup.h"
30#include "qgsvectorlayertools.h"
31#include "qgsvectorlayerutils.h"
32
33#include <QMessageBox>
34#include <QPushButton>
35
36#include "moc_qgsabstractrelationeditorwidget.cpp"
37
39 : QWidget( parent )
40{
41 Q_UNUSED( config );
42}
43
45{
47
49 mFeatureList.clear();
50 mFeatureList.append( feature );
51
52 setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
53
55 updateUi();
56}
57
59{
60 beforeSetRelations( relation, nmrelation );
61
63 mNmRelation = nmrelation;
64
65 if ( !mRelation.isValid() )
66 {
68 return;
69 }
70
72
73 const auto transactionGroups = QgsProject::instance()->transactionGroups();
74 for ( auto it = transactionGroups.constBegin(); it != transactionGroups.constEnd(); ++it )
75 {
76 if ( mNmRelation.isValid() )
77 {
78 if ( it.value()->layers().contains( mRelation.referencedLayer() ) && it.value()->layers().contains( mRelation.referencingLayer() ) && it.value()->layers().contains( mNmRelation.referencedLayer() ) )
80 }
81 else
82 {
83 if ( it.value()->layers().contains( mRelation.referencedLayer() ) && it.value()->layers().contains( mRelation.referencingLayer() ) )
85 }
86 }
87
88 setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
89
91 updateUi();
92}
93
98
103
105{
106 mFeatureList.clear();
107 mFeatureList.append( feature );
108
109 mEditorContext.setFormFeature( feature );
110
111 if ( update )
112 updateUi();
113}
114
116{
117 mFeatureList.clear();
118
119 QgsFeatureIterator featureIterator = mRelation.referencedLayer()->getFeatures( QgsFeatureRequest().setFilterFids( fids ) );
121 while ( featureIterator.nextFeature( feature ) )
122 mFeatureList.append( feature );
123
124 if ( !mFeatureList.isEmpty() )
125 mEditorContext.setFormFeature( mFeatureList.first() );
126}
127
129{
130 const QgsRelation nmrelation = QgsProject::instance()->relationManager()->relation( nmRelationId.toString() );
131 beforeSetRelations( mRelation, nmrelation );
132 mNmRelation = nmrelation;
134 updateUi();
135}
136
138{
139 return mNmRelation.id();
140}
141
143{
144 return QString();
145}
146
148{
149 Q_UNUSED( label )
150}
151
153{
154 return false;
155}
156
161
166
171
175
177{
178 return mFeatureList.size() > 1;
179}
180
182{
183 if ( !mFeatureList.isEmpty() )
184 return mFeatureList.first();
185
186 return QgsFeature();
187}
188
190{
191 return mFeatureList;
192}
193
195{
196 if ( state )
197 {
198 mEditorContext.vectorLayerTools()->startEditing( mRelation.referencingLayer() );
199 if ( mNmRelation.isValid() )
200 mEditorContext.vectorLayerTools()->startEditing( mNmRelation.referencedLayer() );
201 }
202 else
203 {
204 mEditorContext.vectorLayerTools()->stopEditing( mRelation.referencingLayer() );
205 if ( mNmRelation.isValid() )
206 mEditorContext.vectorLayerTools()->stopEditing( mNmRelation.referencedLayer() );
207 }
208}
209
211{
212 mEditorContext.vectorLayerTools()->saveEdits( mRelation.referencingLayer() );
213 if ( mNmRelation.isValid() )
214 mEditorContext.vectorLayerTools()->saveEdits( mNmRelation.referencedLayer() );
215}
216
218{
219 QgsAttributeMap keyAttrs;
220
221 const QgsVectorLayerTools *vlTools = mEditorContext.vectorLayerTools();
222
223 // Fields of the linking table
224 const QgsFields fields = mRelation.referencingLayer()->fields();
225
226 QgsFeatureIds addedFeatureIds;
227
228 // For generated relations insert the referenced layer field
229 switch ( mRelation.type() )
230 {
232 {
233 const QgsPolymorphicRelation polyRel = mRelation.polymorphicRelation();
234 keyAttrs.insert( fields.indexFromName( polyRel.referencedLayerField() ), polyRel.layerRepresentation( mRelation.referencedLayer() ) );
235 break;
236 }
237
239 break;
240 }
241
242 if ( mNmRelation.isValid() )
243 {
244 // only normal relations support m:n relation
245 Q_ASSERT( mNmRelation.type() == Qgis::RelationshipType::Normal );
246
247 // n:m Relation: first let the user create a new feature on the other table
248 // and autocreate a new linking feature.
249 QgsFeature finalFeature;
250 if ( !vlTools->addFeature( mNmRelation.referencedLayer(), QgsAttributeMap(), geometry, &finalFeature, this, false, true ) )
251 return QgsFeatureIds();
252
253 addedFeatureIds.insert( finalFeature.id() );
254
255 // Expression context for the linking table
256 QgsExpressionContext context = mRelation.referencingLayer()->createExpressionContext();
257
258 QgsAttributeMap linkAttributes = keyAttrs;
259 const auto constFieldPairs = mRelation.fieldPairs();
260
262 for ( const QgsFeature &editingFeature : std::as_const( mFeatureList ) )
263 {
264 for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
265 {
266 const int index = fields.indexOf( fieldPair.first );
267 linkAttributes.insert( index, editingFeature.attribute( fieldPair.second ) );
268 }
269
270 const auto constNmFieldPairs = mNmRelation.fieldPairs();
271 for ( const QgsRelation::FieldPair &fieldPair : constNmFieldPairs )
272 {
273 const int index = fields.indexOf( fieldPair.first );
274 linkAttributes.insert( index, finalFeature.attribute( fieldPair.second ) );
275 }
276
277 linkFeatureDataList.append( QgsVectorLayerUtils::QgsFeatureData( QgsGeometry(), linkAttributes ) );
278 }
279 QgsFeatureList linkFeatureList = QgsVectorLayerUtils::createFeatures( mRelation.referencingLayer(), linkFeatureDataList, &context );
280 mRelation.referencingLayer()->addFeatures( linkFeatureList );
281 }
282 else
283 {
284 const auto constFieldPairs = mRelation.fieldPairs();
285 for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
286 keyAttrs.insert( fields.indexFromName( fieldPair.referencingField() ), mFeatureList.first().attribute( fieldPair.referencedField() ) );
287
289 context.setParentWidget( this );
290 context.setShowModal( false );
291 context.setHideParent( true );
292 std::unique_ptr<QgsExpressionContextScope> scope( QgsExpressionContextUtils::parentFormScope( mFeatureList.first(), mEditorContext.attributeFormModeString() ) );
293 context.setAdditionalExpressionContextScope( scope.get() );
295 if ( !vlTools->addFeatureV2( mRelation.referencingLayer(), keyAttrs, geometry, &linkFeature, context ) )
296 return QgsFeatureIds();
297
298 addedFeatureIds.insert( linkFeature.id() );
299
300 // In multiedit add to other features to but without dialog
301 for ( const QgsFeature &feature : std::as_const( mFeatureList ) )
302 {
303 // First feature already added
304 if ( mFeatureList.first() == feature )
305 continue;
306
307 for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
308 linkFeature.setAttribute( fields.indexFromName( fieldPair.referencingField() ), feature.attribute( fieldPair.referencedField() ) );
309
310 mRelation.referencingLayer()->addFeature( linkFeature );
311 addedFeatureIds.insert( linkFeature.id() );
312 }
313 }
314
315 updateUi();
316
318
319 return addedFeatureIds;
320}
321
328
330{
331 bool deleteFeatures = true;
332
333 QgsVectorLayer *layer;
334 if ( mNmRelation.isValid() )
335 {
336 // only normal relations support m:n relation
337 Q_ASSERT( mNmRelation.type() == Qgis::RelationshipType::Normal );
338
339 layer = mNmRelation.referencedLayer();
340
341 // When deleting a linked feature within an N:M relation,
342 // check if the feature is linked to more than just one feature.
343 // In case it is linked more than just once, ask the user for confirmation
344 // as it is likely he was not aware of the implications and might delete
345 // there may be several linking entries deleted along.
346
347 QgsFeatureRequest deletedFeaturesRequest;
348 deletedFeaturesRequest.setFilterFids( fids );
349 deletedFeaturesRequest.setFlags( Qgis::FeatureRequestFlag::NoGeometry );
350 deletedFeaturesRequest.setSubsetOfAttributes( QgsAttributeList() << mNmRelation.referencedFields().first() );
351
352 QgsFeatureIterator deletedFeatures = layer->getFeatures( deletedFeaturesRequest );
353 QStringList deletedFeaturesPks;
355 while ( deletedFeatures.nextFeature( feature ) )
356 {
357 deletedFeaturesPks.append( QgsExpression::quotedValue( feature.attribute( mNmRelation.referencedFields().first() ) ) );
358 }
359
360 QgsFeatureRequest linkingFeaturesRequest;
361 linkingFeaturesRequest.setFlags( Qgis::FeatureRequestFlag::NoGeometry );
362 linkingFeaturesRequest.setNoAttributes();
363
364 QString linkingFeaturesRequestExpression;
365 if ( !deletedFeaturesPks.empty() )
366 {
367 linkingFeaturesRequestExpression = QStringLiteral( "%1 IN (%2)" ).arg( QgsExpression::quotedColumnRef( mNmRelation.fieldPairs().first().first ), deletedFeaturesPks.join( ',' ) );
368 linkingFeaturesRequest.setFilterExpression( linkingFeaturesRequestExpression );
369
370 QgsFeatureIterator relatedLinkingFeatures = mNmRelation.referencingLayer()->getFeatures( linkingFeaturesRequest );
371
372 int relatedLinkingFeaturesCount = 0;
373 while ( relatedLinkingFeatures.nextFeature( feature ) )
374 {
375 relatedLinkingFeaturesCount++;
376 }
377
378 if ( deletedFeaturesPks.size() == 1 && relatedLinkingFeaturesCount > 1 )
379 {
380 QMessageBox messageBox( QMessageBox::Question, tr( "Really delete entry?" ), tr( "The entry on %1 is still linked to %2 features on %3. Do you want to delete it?" ).arg( mNmRelation.referencedLayer()->name(), QLocale().toString( relatedLinkingFeaturesCount ), mRelation.referencedLayer()->name() ), QMessageBox::NoButton, this );
381 messageBox.addButton( QMessageBox::Cancel );
382 QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
383
384 messageBox.exec();
385 if ( messageBox.clickedButton() != deleteButton )
386 deleteFeatures = false;
387 }
388 else if ( deletedFeaturesPks.size() > 1 && relatedLinkingFeaturesCount > deletedFeaturesPks.size() )
389 {
390 QMessageBox messageBox( QMessageBox::Question, tr( "Really delete entries?" ), tr( "The %1 entries on %2 are still linked to %3 features on %4. Do you want to delete them?" ).arg( QLocale().toString( deletedFeaturesPks.size() ), mNmRelation.referencedLayer()->name(), QLocale().toString( relatedLinkingFeaturesCount ), mRelation.referencedLayer()->name() ), QMessageBox::NoButton, this );
391 messageBox.addButton( QMessageBox::Cancel );
392 QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
393
394 messageBox.exec();
395 if ( messageBox.clickedButton() != deleteButton )
396 deleteFeatures = false;
397 }
398 }
399 }
400 else
401 {
402 layer = mRelation.referencingLayer();
403 }
404
406 if ( QgsVectorLayerUtils::impactsCascadeFeatures( layer, fids, QgsProject::instance(), infoContext ) )
407 {
408 QString childrenInfo;
409 int childrenCount = 0;
410 const auto infoContextLayers = infoContext.layers();
411 for ( QgsVectorLayer *chl : infoContextLayers )
412 {
413 childrenCount += infoContext.duplicatedFeatures( chl ).size();
414 childrenInfo += ( tr( "%n feature(s) on layer \"%1\", ", nullptr, infoContext.duplicatedFeatures( chl ).size() ).arg( chl->name() ) );
415 }
416
417 // for extra safety to make sure we know that the delete can have impact on children and joins
418 const int res = QMessageBox::question( this, tr( "Delete at least %n feature(s) on other layer(s)", nullptr, childrenCount ), tr( "Delete %n feature(s) on layer \"%1\", %2 as well and all of its other descendants.\nDelete these features?", nullptr, fids.count() ).arg( layer->name() ).arg( childrenInfo ), QMessageBox::Yes | QMessageBox::No );
419 if ( res != QMessageBox::Yes )
420 deleteFeatures = false;
421 }
422
423 if ( deleteFeatures )
424 {
426 layer->deleteFeatures( fids, &context );
427 const auto contextLayers = context.handledLayers();
428 if ( contextLayers.size() > 1 )
429 {
430 int deletedCount = 0;
431 QString feedbackMessage;
432 for ( QgsVectorLayer *contextLayer : contextLayers )
433 {
434 feedbackMessage += tr( "%1 on layer %2. " ).arg( context.handledFeatures( contextLayer ).size() ).arg( contextLayer->name() );
435 deletedCount += context.handledFeatures( contextLayer ).size();
436 }
437 mEditorContext.mainMessageBar()->pushMessage( tr( "%n feature(s) deleted: %2", nullptr, deletedCount ).arg( feedbackMessage ), Qgis::MessageLevel::Success );
438 }
439
440 updateUi();
441
443 }
444}
445
446void QgsAbstractRelationEditorWidget::linkFeature( const QString &filterExpression )
447{
448 QgsVectorLayer *layer = nullptr;
449
450 if ( mNmRelation.isValid() )
451 {
452 // only normal relations support m:n relation
453 Q_ASSERT( mNmRelation.type() == Qgis::RelationshipType::Normal );
454
455 layer = mNmRelation.referencedLayer();
456 }
457 else
458 {
459 if ( multiEditModeActive() )
460 {
461 QgsLogger::warning( tr( "For 1:n relations is not possible to link to multiple features" ) );
462 return;
463 }
464
465 layer = mRelation.referencingLayer();
466 }
467
468 QgsFeatureSelectionDlg *selectionDlg = new QgsFeatureSelectionDlg( layer, mEditorContext, this );
469 selectionDlg->setAttribute( Qt::WA_DeleteOnClose );
470
471 const QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( mRelation.referencedLayer(), mFeatureList.first() );
472 selectionDlg->setWindowTitle( tr( "Link existing child features for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString ) );
473 selectionDlg->setFilterExpression( filterExpression, QgsAttributeForm::ReplaceFilter );
474
475 connect( selectionDlg, &QDialog::accepted, this, &QgsAbstractRelationEditorWidget::onLinkFeatureDlgAccepted );
476 selectionDlg->show();
477}
478
480{
481 QgsFeatureSelectionDlg *selectionDlg = qobject_cast<QgsFeatureSelectionDlg *>( sender() );
482
483 if ( mNmRelation.isValid() )
484 {
485 // only normal relations support m:n relation
486 Q_ASSERT( mNmRelation.type() == Qgis::RelationshipType::Normal );
487
488 // Fields of the linking table
489 const QgsFields fields = mRelation.referencingLayer()->fields();
490
491 QgsAttributeMap linkAttributes;
492
493 switch ( mRelation.type() )
494 {
496 {
497 const QgsPolymorphicRelation polyRel = mRelation.polymorphicRelation();
498 Q_ASSERT( polyRel.isValid() );
499
500 linkAttributes.insert( fields.indexFromName( polyRel.referencedLayerField() ), polyRel.layerRepresentation( mRelation.referencedLayer() ) );
501 break;
502 }
504 break;
505 }
506
508 QgsFeature relatedFeature;
509 QgsFeatureIterator it = mNmRelation.referencedLayer()->getFeatures(
511 .setFilterFids( selectionDlg->selectedFeatures() )
512 .setSubsetOfAttributes( mNmRelation.referencedFields() )
513 );
514 while ( it.nextFeature( relatedFeature ) )
515 {
516 for ( const QgsFeature &editFeature : std::as_const( mFeatureList ) )
517 {
518 {
519 const auto constFieldPairs = mRelation.fieldPairs();
520 for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
521 {
522 const int index = fields.indexOf( fieldPair.first );
523 linkAttributes.insert( index, editFeature.attribute( fieldPair.second ) );
524 }
525 }
526
527 const auto constFieldPairs = mNmRelation.fieldPairs();
528 for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
529 {
530 const int index = fields.indexOf( fieldPair.first );
531 linkAttributes.insert( index, relatedFeature.attribute( fieldPair.second ) );
532 }
533
534 linkFeatureDataList.append( QgsVectorLayerUtils::QgsFeatureData( QgsGeometry(), linkAttributes ) );
535 }
536 }
537
538 // Expression context for the linking table
539 QgsExpressionContext context = mRelation.referencingLayer()->createExpressionContext();
540
541 QgsFeatureList linkFeaturesList = QgsVectorLayerUtils::createFeatures( mRelation.referencingLayer(), linkFeatureDataList, &context );
542
543 mRelation.referencingLayer()->addFeatures( linkFeaturesList );
544 QgsFeatureIds ids;
545 const auto constNewFeatures = linkFeaturesList;
546 for ( const QgsFeature &f : constNewFeatures )
547 ids << f.id();
548 mRelation.referencingLayer()->selectByIds( ids );
549 }
550 else
551 {
552 if ( multiEditModeActive() )
553 {
554 QgsLogger::warning( tr( "For 1:n relations is not possible to link to multiple features" ) );
555 return;
556 }
557
558 QMap<int, QVariant> keys;
559 const auto constFieldPairs = mRelation.fieldPairs();
560 for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
561 {
562 const int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
563 const QVariant val = mFeatureList.first().attribute( fieldPair.referencedField() );
564 keys.insert( idx, val );
565 }
566
567 const auto constSelectedFeatures = selectionDlg->selectedFeatures();
568 for ( const QgsFeatureId fid : constSelectedFeatures )
569 {
570 QgsVectorLayer *referencingLayer = mRelation.referencingLayer();
571 switch ( mRelation.type() )
572 {
574 {
575 const QgsPolymorphicRelation polyRel = mRelation.polymorphicRelation();
576
577 Q_ASSERT( polyRel.isValid() );
578
579 mRelation.referencingLayer()->changeAttributeValue( fid, referencingLayer->fields().indexFromName( polyRel.referencedLayerField() ), polyRel.layerRepresentation( mRelation.referencedLayer() ) );
580 break;
581 }
583 break;
584 }
585
586 QMapIterator<int, QVariant> it( keys );
587 while ( it.hasNext() )
588 {
589 it.next();
590 referencingLayer->changeAttributeValue( fid, it.key(), it.value() );
591 }
592 }
593 }
594
595 updateUi();
596
598}
599
604
606{
607 if ( mNmRelation.isValid() )
608 {
609 // only normal relations support m:n relation
610 Q_ASSERT( mNmRelation.type() == Qgis::RelationshipType::Normal );
611
612 QgsFeatureIterator selectedIterator = mNmRelation.referencedLayer()->getFeatures(
614 .setFilterFids( fids )
615 .setSubsetOfAttributes( mNmRelation.referencedFields() )
616 );
617
618 QgsFeature f;
619
620 QStringList filters;
621
622 while ( selectedIterator.nextFeature( f ) )
623 {
624 filters << '(' + mNmRelation.getRelatedFeaturesRequest( f ).filterExpression()->expression() + ')';
625 }
626
627 QStringList featureFilters;
628 for ( const QgsFeature &editingFeature : std::as_const( mFeatureList ) )
629 {
630 featureFilters.append( mRelation.getRelatedFeaturesRequest( editingFeature ).filterExpression()->expression() );
631 }
632
633 const QString filter = QStringLiteral( "(%1) AND (%2)" ).arg( featureFilters.join( QLatin1String( " OR " ) ), filters.join( QLatin1String( " OR " ) ) );
634
635 QgsFeatureIterator linkedIterator = mRelation.referencingLayer()->getFeatures( QgsFeatureRequest()
636 .setNoAttributes()
637 .setFilterExpression( filter ) );
638
639 QgsFeatureIds fids;
640
641 while ( linkedIterator.nextFeature( f ) )
642 {
643 fids << f.id();
644 QgsDebugMsgLevel( FID_TO_STRING( f.id() ), 4 );
645 }
646
647 mRelation.referencingLayer()->deleteFeatures( fids );
648 }
649 else
650 {
651 QMap<int, QgsField> keyFields;
652 const auto constFieldPairs = mRelation.fieldPairs();
653 for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
654 {
655 const int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
656 if ( idx < 0 )
657 {
658 QgsDebugError( QStringLiteral( "referencing field %1 not found" ).arg( fieldPair.referencingField() ) );
659 return;
660 }
661 const QgsField fld = mRelation.referencingLayer()->fields().at( idx );
662 keyFields.insert( idx, fld );
663 }
664
665 const auto constFeatureids = fids;
666 for ( const QgsFeatureId fid : constFeatureids )
667 {
668 QgsVectorLayer *referencingLayer = mRelation.referencingLayer();
669 switch ( mRelation.type() )
670 {
672 {
673 const QgsPolymorphicRelation polyRel = mRelation.polymorphicRelation();
674
675 Q_ASSERT( mRelation.polymorphicRelation().isValid() );
676
677 mRelation.referencingLayer()->changeAttributeValue( fid, referencingLayer->fields().indexFromName( polyRel.referencedLayerField() ), QgsVariantUtils::createNullVariant( referencingLayer->fields().field( polyRel.referencedLayerField() ).type() ) );
678 break;
679 }
681 break;
682 }
683
684 QMapIterator<int, QgsField> it( keyFields );
685 while ( it.hasNext() )
686 {
687 it.next();
688 mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), QgsVariantUtils::createNullVariant( it.value().type() ) );
689 }
690 }
691 }
692
693 updateUi();
694
696}
697
700
702{
703 Q_UNUSED( title )
704}
705
707{
708 Q_UNUSED( newRelation )
709 Q_UNUSED( newFeature )
710}
711
714
716{
717 Q_UNUSED( newRelation )
718 Q_UNUSED( newNmRelation )
719}
720
723
730
732{
733 QgsVectorLayer *layer = mRelation.referencingLayer();
734
735 QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterFids( fids ) );
736 QgsFeature f;
737 while ( fit.nextFeature( f ) )
738 {
740 QgsVectorLayerUtils::duplicateFeature( layer, f, QgsProject::instance(), duplicatedFeatureContext );
741 }
742
744}
745
747{
748 updateUi();
749}
750
751
753
754
756 : QWidget( parent )
757 , mRelation( relation )
758{
759}
760
765
767{
768 return mRelation;
769}
770
775
777{
778 return mNmRelation;
779}
780
781
783
784
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
Definition qgis.h:2196
@ Success
Used for reporting a successful operation.
Definition qgis.h:160
@ Generated
A generated relation is a child of a polymorphic relation.
Definition qgis.h:4393
@ Normal
A normal relation.
Definition qgis.h:4392
virtual void setNmRelation(const QgsRelation &nmRelation)
Set the nm relation for this widget.
QgsRelation relation() const
Returns the relation for which this configuration widget applies.
virtual QgsRelation nmRelation() const
Returns the nm relation for which this configuration widget applies.
QgsAbstractRelationEditorConfigWidget(const QgsRelation &relation, QWidget *parent)
Create a new configuration widget.
QgsVectorLayer * layer()
Returns the layer for which this configuration widget applies.
QgsAbstractRelationEditorWidgetFactory()
Creates a new relation widget factory with given name.
void setMultiEditFeatureIds(const QgsFeatureIds &fids)
Set multiple feature to edit simultaneously.
void toggleEditing(bool state)
Toggles editing state of the widget.
QgsFeatureIds addFeature(const QgsGeometry &geometry=QgsGeometry())
Adds new features with given geometry Returns the Id of added features.
void deleteFeatures(const QgsFeatureIds &fids)
Deletes the features with fids.
void onLinkFeatureDlgAccepted()
Called when the link feature dialog is confirmed by the user.
bool forceSuppressFormPopup() const
Determines the force suppress form popup status that is configured for this widget.
virtual void afterSetRelations()
A hook called right after setRelations() is executed, but before updateUi() is called.
QList< QgsFeature > features() const
Returns the widget's current features.
void setRelationFeature(const QgsRelation &relation, const QgsFeature &feature)
Sets the relation and the feature.
virtual void setEditorContext(const QgsAttributeEditorContext &context)
Sets the editor context.
virtual Q_DECL_DEPRECATED void setTitle(const QString &title)
Sets the title of the widget, if it is wrapped within a QgsCollapsibleGroupBox.
void linkFeature(const QString &filterExpression=QString())
Links a new feature to the relation.
Q_DECL_DEPRECATED QString label() const
Determines the label of this element.
void setLabel(const QString &label=QString())
Sets label for this element If it's empty it takes the relation id as label.
Q_DECL_DEPRECATED void updateTitle()
Updates the title contents to reflect the current state of the widget.
void showEvent(QShowEvent *) override
Refresh the UI when the widget becomes visible.
QgsAbstractRelationEditorWidget(const QVariantMap &config, QWidget *parent=nullptr)
Constructor.
void relatedFeaturesChanged()
Emit this signal, whenever the related features changed.
void setRelations(const QgsRelation &relation, const QgsRelation &nmrelation)
Sets the relation(s) for this widget If only one relation is set, it will act as a simple 1:N relatio...
virtual void beforeSetRelations(const QgsRelation &newRelation, const QgsRelation &newNmRelation)
A hook called right before setRelations() is executed.
QgsAttributeEditorContext editorContext() const
Returns the attribute editor context.
Q_DECL_DEPRECATED bool showLabel() const
Defines if a title label should be shown for this widget.
virtual void updateUi()
A hook called every time the state of the relation editor widget has changed via calling its set* met...
QgsRelation relation() const
Returns the relation.
virtual QVariantMap config() const =0
Returns the widget configuration.
virtual void beforeSetRelationFeature(const QgsRelation &newRelation, const QgsFeature &newFeature)
A hook called right before setRelationFeature() is executed.
void setFeature(const QgsFeature &feature, bool update=true)
Sets the feature being edited and updates the UI unless update is set to false.
void unlinkFeatures(const QgsFeatureIds &fids)
Unlinks the features with fids.
void deleteFeature(QgsFeatureId fid=QgsFeatureId())
Delete a feature with given fid.
QgsFeature feature() const
Returns the widget's current feature If the widget is in multiedit mode only the first is returned.
QVariant nmRelationId() const
Determines the relation id of the second relation involved in an N:M relation.
virtual void afterSetRelationFeature()
A hook called right after setRelationFeature() is executed, but before updateUi() is called.
bool multiEditModeActive() const
Returns true if editing multiple features at a time.
Q_DECL_DEPRECATED void setShowLabel(bool showLabel)
Defines if a title label should be shown for this widget.
void saveEdits()
Saves the current modifications in the relation.
void unlinkFeature(QgsFeatureId fid=QgsFeatureId())
Unlinks a feature with given fid.
void duplicateFeature(const QgsFeatureId &fid)
Duplicates a feature.
void duplicateFeatures(const QgsFeatureIds &fids)
Duplicates features.
void setForceSuppressFormPopup(bool forceSuppressFormPopup)
Sets force suppress form popup status with forceSuppressFormPopup configured for this widget.
void setNmRelationId(const QVariant &nmRelationId=QVariant())
Sets nmRelationId for the relation id of the second relation involved in an N:M relation.
Contains context information for attribute editor widgets.
@ ReplaceFilter
Filter should replace any existing filter.
static QgsExpressionContextScope * parentFormScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current parent attribute form/tab...
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required.
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes).
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
A dialog for selecting features from a vector layer.
const QgsFeatureIds & selectedFeatures()
Gets the selected features.
void setFilterExpression(const QString &filter, QgsAttributeForm::FilterType type)
Set form filter expression.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsFeatureId id
Definition qgsfeature.h:66
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:54
QMetaType::Type type
Definition qgsfield.h:61
Container of fields for a vector layer.
Definition qgsfields.h:46
Q_INVOKABLE int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Q_INVOKABLE int indexOf(const QString &fieldName) const
Gets the field index from the field name.
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
A geometry is the spatial representation of a feature.
static void warning(const QString &msg)
Goes to qWarning.
QString name
Definition qgsmaplayer.h:84
A relation where the referenced (parent) layer is calculated based on fields from the referencing (ch...
QString layerRepresentation(const QgsVectorLayer *layer) const
Returns layer representation as evaluated string.
QgsRelationManager * relationManager
Definition qgsproject.h:120
static QgsProject * instance()
Returns the QgsProject singleton instance.
QMap< QPair< QString, QString >, QgsTransactionGroup * > transactionGroups()
Map of transaction groups.
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
Defines a relation between matching fields of the two involved tables of a relation.
Definition qgsrelation.h:72
Represents a relationship between two vector layers.
Definition qgsrelation.h:42
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
Contains settings which reflect the context in which vector layer tool operations should be considere...
void setParentWidget(QWidget *parent)
Sets the widget which should be parented to tools' dialogues.
void setHideParent(bool hide)
Sets whether the parent widget should be hidden when showing tools' dialogues.
void setAdditionalExpressionContextScope(const QgsExpressionContextScope *scope)
Sets an additional expression context scope to be made available when calculating expressions.
void setShowModal(bool modal)
Sets whether tools' dialogues should be modal.
Used to handle basic editing operations on vector layers.
virtual bool addFeature(QgsVectorLayer *layer, const QgsAttributeMap &defaultValues=QgsAttributeMap(), const QgsGeometry &defaultGeometry=QgsGeometry(), QgsFeature *feature=nullptr, QWidget *parentWidget=nullptr, bool showModal=true, bool hideParent=false) const
This method should/will be called, whenever a new feature will be added to the layer.
virtual bool addFeatureV2(QgsVectorLayer *layer, const QgsAttributeMap &defaultValues=QgsAttributeMap(), const QgsGeometry &defaultGeometry=QgsGeometry(), QgsFeature *feature=nullptr, const QgsVectorLayerToolsContext &context=QgsVectorLayerToolsContext()) const
This method should/will be called, whenever a new feature will be added to the layer.
Contains mainly the QMap with QgsVectorLayer and QgsFeatureIds which list all the duplicated features...
QgsFeatureIds duplicatedFeatures(QgsVectorLayer *layer) const
Returns the duplicated features in the given layer.
QList< QgsVectorLayer * > layers() const
Returns all the layers on which features have been duplicated.
Encapsulate geometry and attributes for new features, to be passed to createFeatures.
static QgsFeature duplicateFeature(QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, QgsDuplicateFeatureContext &duplicateFeatureContext, const int maxDepth=0, int depth=0, QList< QgsVectorLayer * > referencedLayersBranch=QList< QgsVectorLayer * >())
Duplicates a feature and it's children (one level deep).
QList< QgsVectorLayerUtils::QgsFeatureData > QgsFeaturesDataList
Alias for list of QgsFeatureData.
static QString getFeatureDisplayString(const QgsVectorLayer *layer, const QgsFeature &feature)
Returns a descriptive string for a feature, suitable for displaying to the user.
static QgsFeatureList createFeatures(const QgsVectorLayer *layer, const QgsFeaturesDataList &featuresData, QgsExpressionContext *context=nullptr)
Creates a set of new features ready for insertion into a layer.
static bool impactsCascadeFeatures(const QgsVectorLayer *layer, const QgsFeatureIds &fids, const QgsProject *project, QgsDuplicateFeatureContext &context, QgsVectorLayerUtils::CascadedFeatureFlags flags=QgsVectorLayerUtils::CascadedFeatureFlags())
Returns true if at least one feature of the fids on layer is connected as parent in at least one comp...
Represents a vector layer which manages a vector based dataset.
Q_INVOKABLE bool deleteFeatures(const QgsFeatureIds &fids, QgsVectorLayer::DeleteContext *context=nullptr)
Deletes a set of features from the layer (but does not commit it).
Q_INVOKABLE bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false, QgsVectorLayerToolsContext *context=nullptr)
Changes an attribute value for a feature (but does not immediately commit the changes).
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
QMap< int, QVariant > QgsAttributeMap
QList< QgsFeature > QgsFeatureList
QSet< QgsFeatureId > QgsFeatureIds
#define FID_TO_STRING(fid)
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
QList< int > QgsAttributeList
Definition qgsfield.h:28
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:61
#define QgsDebugError(str)
Definition qgslogger.h:57
Context for cascade delete features.
QList< QgsVectorLayer * > handledLayers(bool includeAuxiliaryLayers=true) const
Returns a list of all layers affected by the delete operation.
QgsFeatureIds handledFeatures(QgsVectorLayer *layer) const
Returns a list of feature IDs from the specified layer affected by the delete operation.