QGIS API Documentation  3.23.0-Master (eb871beae0)
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
6  email : [email protected]
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 "qgsfeatureiterator.h"
21 #include "qgsexpression.h"
22 #include "qgsfeature.h"
23 #include "qgsfeatureselectiondlg.h"
24 #include "qgsrelation.h"
25 #include "qgsrelationmanager.h"
26 #include "qgspolymorphicrelation.h"
27 #include "qgsvectorlayertools.h"
28 #include "qgsproject.h"
29 #include "qgstransactiongroup.h"
30 #include "qgsvectorlayerutils.h"
31 
32 #include <QMessageBox>
33 #include <QPushButton>
34 
35 QgsAbstractRelationEditorWidget::QgsAbstractRelationEditorWidget( const QVariantMap &config, QWidget *parent )
36  : QWidget( parent )
37 {
38  Q_UNUSED( config );
39 }
40 
42 {
44 
46  mFeatureList.clear();
47  mFeatureList.append( feature );
48 
49  setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
50 
52  updateUi();
53 }
54 
55 void QgsAbstractRelationEditorWidget::setRelations( const QgsRelation &relation, const QgsRelation &nmrelation )
56 {
57 
58  beforeSetRelations( relation, nmrelation );
59 
61  mNmRelation = nmrelation;
62 
63  if ( !mRelation.isValid() )
64  {
66  return;
67  }
68 
70 
71  const auto transactionGroups = QgsProject::instance()->transactionGroups();
72  for ( auto it = transactionGroups.constBegin(); it != transactionGroups.constEnd(); ++it )
73  {
74  if ( mNmRelation.isValid() )
75  {
76  if ( it.value()->layers().contains( mRelation.referencedLayer() ) &&
77  it.value()->layers().contains( mRelation.referencingLayer() ) &&
78  it.value()->layers().contains( mNmRelation.referencedLayer() ) )
80  }
81  else
82  {
83  if ( it.value()->layers().contains( mRelation.referencedLayer() ) &&
84  it.value()->layers().contains( mRelation.referencingLayer() ) )
86  }
87  }
88 
89  setObjectName( QStringLiteral( "referenced/" ) + mRelation.name() );
90 
92  updateUi();
93 }
94 
96 {
97  mEditorContext = context;
98 }
99 
101 {
102  return mEditorContext;
103 }
104 
105 void QgsAbstractRelationEditorWidget::setFeature( const QgsFeature &feature, bool update )
106 {
107  mFeatureList.clear();
108  mFeatureList.append( feature );
109 
111 
112  if ( update )
113  updateUi();
114 }
115 
117 {
118  mFeatureList.clear();
119 
120  QgsFeatureIterator featureIterator = mRelation.referencedLayer()->getFeatures( QgsFeatureRequest().setFilterFids( fids ) );
122  while ( featureIterator.nextFeature( feature ) )
123  mFeatureList.append( feature );
124 
125  if ( ! mFeatureList.isEmpty() )
127 }
128 
129 void QgsAbstractRelationEditorWidget::setNmRelationId( const QVariant &nmRelationId )
130 {
131  const QgsRelation nmrelation = QgsProject::instance()->relationManager()->relation( nmRelationId.toString() );
132  beforeSetRelations( mRelation, nmrelation );
133  mNmRelation = nmrelation;
135  updateUi();
136 }
137 
139 {
140  return mNmRelation.id();
141 }
142 
144 {
145  return QString();
146 }
147 
148 void QgsAbstractRelationEditorWidget::setLabel( const QString &label )
149 {
150  Q_UNUSED( label )
151 }
152 
154 {
155  return false;
156 }
157 
159 {
160  Q_UNUSED( showLabel )
161 }
162 
164 {
166 }
167 
169 {
171 }
172 
174 {
175 }
176 
178 {
179  return mFeatureList.size() > 1;
180 }
181 
183 {
184  if ( !mFeatureList.isEmpty() )
185  return mFeatureList.first();
186 
187  return QgsFeature();
188 }
189 
191 {
192  if ( state )
193  {
195  if ( mNmRelation.isValid() )
197  }
198  else
199  {
201  if ( mNmRelation.isValid() )
203  }
204 }
205 
207 {
209  if ( mNmRelation.isValid() )
211 }
212 
214 {
215  QgsAttributeMap keyAttrs;
216 
218 
219  // Fields of the linking table
220  const QgsFields fields = mRelation.referencingLayer()->fields();
221 
222  QgsFeatureIds addedFeatureIds;
223 
224  // For generated relations insert the referenced layer field
226  {
228  keyAttrs.insert( fields.indexFromName( polyRel.referencedLayerField() ), polyRel.layerRepresentation( mRelation.referencedLayer() ) );
229  }
230 
231  if ( mNmRelation.isValid() )
232  {
233  // only normal relations support m:n relation
234  Q_ASSERT( mNmRelation.type() == QgsRelation::Normal );
235 
236  // n:m Relation: first let the user create a new feature on the other table
237  // and autocreate a new linking feature.
238  QgsFeature finalFeature;
239  if ( !vlTools->addFeature( mNmRelation.referencedLayer(), QgsAttributeMap(), geometry, &finalFeature ) )
240  return QgsFeatureIds();
241 
242  addedFeatureIds.insert( finalFeature.id() );
243 
244  // Expression context for the linking table
246 
247  QgsAttributeMap linkAttributes = keyAttrs;
248  const auto constFieldPairs = mRelation.fieldPairs();
249 
250  QgsVectorLayerUtils::QgsFeaturesDataList linkFeatureDataList;
251  for ( const QgsFeature &editingFeature : std::as_const( mFeatureList ) )
252  {
253  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
254  {
255  const int index = fields.indexOf( fieldPair.first );
256  linkAttributes.insert( index, editingFeature.attribute( fieldPair.second ) );
257  }
258 
259  const auto constNmFieldPairs = mNmRelation.fieldPairs();
260  for ( const QgsRelation::FieldPair &fieldPair : constNmFieldPairs )
261  {
262  const int index = fields.indexOf( fieldPair.first );
263  linkAttributes.insert( index, finalFeature.attribute( fieldPair.second ) );
264  }
265 
266  linkFeatureDataList.append( QgsVectorLayerUtils::QgsFeatureData( QgsGeometry(), linkAttributes ) );
267  }
268  QgsFeatureList linkFeatureList = QgsVectorLayerUtils::createFeatures( mRelation.referencingLayer(), linkFeatureDataList, &context );
269  mRelation.referencingLayer()->addFeatures( linkFeatureList );
270  }
271  else
272  {
273  const auto constFieldPairs = mRelation.fieldPairs();
274  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
275  keyAttrs.insert( fields.indexFromName( fieldPair.referencingField() ), mFeatureList.first().attribute( fieldPair.referencedField() ) );
276 
278  if ( !vlTools->addFeature( mRelation.referencingLayer(), keyAttrs, geometry, &linkFeature ) )
279  return QgsFeatureIds();
280 
281  addedFeatureIds.insert( linkFeature.id() );
282 
283  // In multiedit add to other features to but whitout dialog
284  for ( const QgsFeature &feature : std::as_const( mFeatureList ) )
285  {
286  // First feature already added
287  if ( mFeatureList.first() == feature )
288  continue;
289 
290  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
291  linkFeature.setAttribute( fields.indexFromName( fieldPair.referencingField() ), feature.attribute( fieldPair.referencedField() ) );
292 
294  addedFeatureIds.insert( linkFeature.id() );
295  }
296  }
297 
298  updateUi();
299 
300  return addedFeatureIds;
301 }
302 
304 {
305  deleteFeatures( QgsFeatureIds() << fid );
306 }
307 
309 {
310  bool deleteFeatures = true;
311 
312  QgsVectorLayer *layer;
313  if ( mNmRelation.isValid() )
314  {
315  // only normal relations support m:n relation
316  Q_ASSERT( mNmRelation.type() == QgsRelation::Normal );
317 
318  layer = mNmRelation.referencedLayer();
319 
320  // When deleting a linked feature within an N:M relation,
321  // check if the feature is linked to more than just one feature.
322  // In case it is linked more than just once, ask the user for confirmation
323  // as it is likely he was not aware of the implications and might delete
324  // there may be several linking entries deleted along.
325 
326  QgsFeatureRequest deletedFeaturesRequest;
327  deletedFeaturesRequest.setFilterFids( fids );
328  deletedFeaturesRequest.setFlags( QgsFeatureRequest::NoGeometry );
329  deletedFeaturesRequest.setSubsetOfAttributes( QgsAttributeList() << mNmRelation.referencedFields().first() );
330 
331  QgsFeatureIterator deletedFeatures = layer->getFeatures( deletedFeaturesRequest );
332  QStringList deletedFeaturesPks;
334  while ( deletedFeatures.nextFeature( feature ) )
335  {
336  deletedFeaturesPks.append( QgsExpression::quotedValue( feature.attribute( mNmRelation.referencedFields().first() ) ) );
337  }
338 
339  QgsFeatureRequest linkingFeaturesRequest;
340  linkingFeaturesRequest.setFlags( QgsFeatureRequest::NoGeometry );
341  linkingFeaturesRequest.setNoAttributes();
342 
343  QString linkingFeaturesRequestExpression;
344  if ( !deletedFeaturesPks.empty() )
345  {
346  linkingFeaturesRequestExpression = QStringLiteral( "%1 IN (%2)" ).arg( QgsExpression::quotedColumnRef( mNmRelation.fieldPairs().first().first ), deletedFeaturesPks.join( ',' ) );
347  linkingFeaturesRequest.setFilterExpression( linkingFeaturesRequestExpression );
348 
349  QgsFeatureIterator relatedLinkingFeatures = mNmRelation.referencingLayer()->getFeatures( linkingFeaturesRequest );
350 
351  int relatedLinkingFeaturesCount = 0;
352  while ( relatedLinkingFeatures.nextFeature( feature ) )
353  {
354  relatedLinkingFeaturesCount++;
355  }
356 
357  if ( deletedFeaturesPks.size() == 1 && relatedLinkingFeaturesCount > 1 )
358  {
359  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 );
360  messageBox.addButton( QMessageBox::Cancel );
361  QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
362 
363  messageBox.exec();
364  if ( messageBox.clickedButton() != deleteButton )
365  deleteFeatures = false;
366  }
367  else if ( deletedFeaturesPks.size() > 1 && relatedLinkingFeaturesCount > deletedFeaturesPks.size() )
368  {
369  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 );
370  messageBox.addButton( QMessageBox::Cancel );
371  QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
372 
373  messageBox.exec();
374  if ( messageBox.clickedButton() != deleteButton )
375  deleteFeatures = false;
376  }
377  }
378  }
379  else
380  {
381  layer = mRelation.referencingLayer();
382  }
383 
385  if ( QgsVectorLayerUtils::impactsCascadeFeatures( layer, fids, QgsProject::instance(), infoContext ) )
386  {
387  QString childrenInfo;
388  int childrenCount = 0;
389  const auto infoContextLayers = infoContext.layers();
390  for ( QgsVectorLayer *chl : infoContextLayers )
391  {
392  childrenCount += infoContext.duplicatedFeatures( chl ).size();
393  childrenInfo += ( tr( "%1 feature(s) on layer \"%2\", " ).arg( infoContext.duplicatedFeatures( chl ).size() ).arg( chl->name() ) );
394  }
395 
396  // for extra safety to make sure we know that the delete can have impact on children and joins
397  const int res = QMessageBox::question( this, tr( "Delete at least %1 feature(s) on other layer(s)" ).arg( childrenCount ),
398  tr( "Delete %1 feature(s) on layer \"%2\", %3 as well\nand all of its other descendants.\nDelete these features?" ).arg( fids.count() ).arg( layer->name() ).arg( childrenInfo ),
399  QMessageBox::Yes | QMessageBox::No );
400  if ( res != QMessageBox::Yes )
401  deleteFeatures = false;
402  }
403 
404  if ( deleteFeatures )
405  {
407  layer->deleteFeatures( fids, &context );
408  const auto contextLayers = context.handledLayers();
409  if ( contextLayers.size() > 1 )
410  {
411  int deletedCount = 0;
412  QString feedbackMessage;
413  for ( QgsVectorLayer *contextLayer : contextLayers )
414  {
415  feedbackMessage += tr( "%1 on layer %2. " ).arg( context.handledFeatures( contextLayer ).size() ).arg( contextLayer->name() );
416  deletedCount += context.handledFeatures( contextLayer ).size();
417  }
418  mEditorContext.mainMessageBar()->pushMessage( tr( "%1 features deleted: %2" ).arg( deletedCount ).arg( feedbackMessage ), Qgis::MessageLevel::Success );
419  }
420 
421  updateUi();
422  }
423 }
424 
426 {
427  QgsVectorLayer *layer = nullptr;
428 
429  if ( mNmRelation.isValid() )
430  {
431  // only normal relations support m:n relation
432  Q_ASSERT( mNmRelation.type() == QgsRelation::Normal );
433 
434  layer = mNmRelation.referencedLayer();
435  }
436  else
437  {
438  if ( multiEditModeActive() )
439  {
440  QgsLogger::warning( tr( "For 1:n relations is not possible to link to multiple features" ) );
441  return;
442  }
443 
444  layer = mRelation.referencingLayer();
445  }
446 
447  QgsFeatureSelectionDlg *selectionDlg = new QgsFeatureSelectionDlg( layer, mEditorContext, this );
448  selectionDlg->setAttribute( Qt::WA_DeleteOnClose );
449 
450  const QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( mRelation.referencedLayer(), mFeatureList.first() );
451  selectionDlg->setWindowTitle( tr( "Link existing child features for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString ) );
452 
453  connect( selectionDlg, &QDialog::accepted, this, &QgsAbstractRelationEditorWidget::onLinkFeatureDlgAccepted );
454  selectionDlg->show();
455 }
456 
458 {
459  QgsFeatureSelectionDlg *selectionDlg = qobject_cast<QgsFeatureSelectionDlg *>( sender() );
460 
461  if ( mNmRelation.isValid() )
462  {
463  // only normal relations support m:n relation
464  Q_ASSERT( mNmRelation.type() == QgsRelation::Normal );
465 
466  // Fields of the linking table
467  const QgsFields fields = mRelation.referencingLayer()->fields();
468 
469  QgsAttributeMap linkAttributes;
470 
472  {
474  Q_ASSERT( polyRel.isValid() );
475 
476  linkAttributes.insert( fields.indexFromName( polyRel.referencedLayerField() ),
478  }
479 
480  QgsVectorLayerUtils::QgsFeaturesDataList linkFeatureDataList;
481  QgsFeature relatedFeature;
484  .setFilterFids( selectionDlg->selectedFeatures() )
486  while ( it.nextFeature( relatedFeature ) )
487  {
488  for ( const QgsFeature &editFeature : std::as_const( mFeatureList ) )
489  {
490  {
491  const auto constFieldPairs = mRelation.fieldPairs();
492  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
493  {
494  const int index = fields.indexOf( fieldPair.first );
495  linkAttributes.insert( index, editFeature.attribute( fieldPair.second ) );
496  }
497  }
498 
499  const auto constFieldPairs = mNmRelation.fieldPairs();
500  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
501  {
502  const int index = fields.indexOf( fieldPair.first );
503  linkAttributes.insert( index, relatedFeature.attribute( fieldPair.second ) );
504  }
505 
506  linkFeatureDataList.append( QgsVectorLayerUtils::QgsFeatureData( QgsGeometry(), linkAttributes ) );
507  }
508  }
509 
510  // Expression context for the linking table
512 
513  QgsFeatureList linkFeaturesList = QgsVectorLayerUtils::createFeatures( mRelation.referencingLayer(), linkFeatureDataList, &context );
514 
515  mRelation.referencingLayer()->addFeatures( linkFeaturesList );
516  QgsFeatureIds ids;
517  const auto constNewFeatures = linkFeaturesList;
518  for ( const QgsFeature &f : constNewFeatures )
519  ids << f.id();
521  }
522  else
523  {
524  if ( multiEditModeActive() )
525  {
526  QgsLogger::warning( tr( "For 1:n relations is not possible to link to multiple features" ) );
527  return;
528  }
529 
530  QMap<int, QVariant> keys;
531  const auto constFieldPairs = mRelation.fieldPairs();
532  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
533  {
534  const int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
535  const QVariant val = mFeatureList.first().attribute( fieldPair.referencedField() );
536  keys.insert( idx, val );
537  }
538 
539  const auto constSelectedFeatures = selectionDlg->selectedFeatures();
540  for ( const QgsFeatureId fid : constSelectedFeatures )
541  {
542  QgsVectorLayer *referencingLayer = mRelation.referencingLayer();
544  {
546 
547  Q_ASSERT( polyRel.isValid() );
548 
550  referencingLayer->fields().indexFromName( polyRel.referencedLayerField() ),
552  }
553 
554  QMapIterator<int, QVariant> it( keys );
555  while ( it.hasNext() )
556  {
557  it.next();
558  referencingLayer->changeAttributeValue( fid, it.key(), it.value() );
559  }
560  }
561  }
562 
563  updateUi();
564 }
565 
567 {
568  unlinkFeatures( QgsFeatureIds() << fid );
569 }
570 
572 {
573  if ( mNmRelation.isValid() )
574  {
575  // only normal relations support m:n relation
576  Q_ASSERT( mNmRelation.type() == QgsRelation::Normal );
577 
580  .setFilterFids( fids )
581  .setSubsetOfAttributes( mNmRelation.referencedFields() ) );
582 
583  QgsFeature f;
584 
585  QStringList filters;
586 
587  while ( selectedIterator.nextFeature( f ) )
588  {
589  filters << '(' + mNmRelation.getRelatedFeaturesRequest( f ).filterExpression()->expression() + ')';
590  }
591 
592  QStringList featureFilters;
593  for ( const QgsFeature &editingFeature : std::as_const( mFeatureList ) )
594  {
595  featureFilters.append( mRelation.getRelatedFeaturesRequest( editingFeature ).filterExpression()->expression() );
596  }
597 
598  const QString filter = QStringLiteral( "(%1) AND (%2)" ).arg(
599  featureFilters.join( QLatin1String( " OR " ) ),
600  filters.join( QLatin1String( " OR " ) ) );
601 
603  .setNoAttributes()
604  .setFilterExpression( filter ) );
605 
606  QgsFeatureIds fids;
607 
608  while ( linkedIterator.nextFeature( f ) )
609  {
610  fids << f.id();
611  QgsDebugMsgLevel( FID_TO_STRING( f.id() ), 4 );
612  }
613 
615  }
616  else
617  {
618  QMap<int, QgsField> keyFields;
619  const auto constFieldPairs = mRelation.fieldPairs();
620  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
621  {
622  const int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
623  if ( idx < 0 )
624  {
625  QgsDebugMsg( QStringLiteral( "referencing field %1 not found" ).arg( fieldPair.referencingField() ) );
626  return;
627  }
628  const QgsField fld = mRelation.referencingLayer()->fields().at( idx );
629  keyFields.insert( idx, fld );
630  }
631 
632  const auto constFeatureids = fids;
633  for ( const QgsFeatureId fid : constFeatureids )
634  {
635  QgsVectorLayer *referencingLayer = mRelation.referencingLayer();
637  {
639 
640  Q_ASSERT( mRelation.polymorphicRelation().isValid() );
641 
643  referencingLayer->fields().indexFromName( polyRel.referencedLayerField() ),
644  referencingLayer->fields().field( polyRel.referencedLayerField() ).type() );
645  }
646 
647  QMapIterator<int, QgsField> it( keyFields );
648  while ( it.hasNext() )
649  {
650  it.next();
651  mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), QVariant( it.value().type() ) );
652  }
653  }
654  }
655 
656  updateUi();
657 }
658 
660 {}
661 
662 void QgsAbstractRelationEditorWidget::setTitle( const QString &title )
663 {
664  Q_UNUSED( title )
665 }
666 
668 {
669  Q_UNUSED( newRelation )
670  Q_UNUSED( newFeature )
671 }
672 
674 {}
675 
676 void QgsAbstractRelationEditorWidget::beforeSetRelations( const QgsRelation &newRelation, const QgsRelation &newNmRelation )
677 {
678  Q_UNUSED( newRelation )
679  Q_UNUSED( newNmRelation )
680 }
681 
683 {}
684 
686 {
687  duplicateFeatures( QgsFeatureIds() << fid );
688 }
689 
691 {
693 
694  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterFids( fids ) );
695  QgsFeature f;
696  while ( fit.nextFeature( f ) )
697  {
698  QgsVectorLayerUtils::QgsDuplicateFeatureContext duplicatedFeatureContext;
699  QgsVectorLayerUtils::duplicateFeature( layer, f, QgsProject::instance(), duplicatedFeatureContext );
700  }
701 }
702 
704 {
705  updateUi();
706 }
707 
708 
710 
711 
713  : QWidget( parent )
714  , mRelation( relation )
715 {
716 }
717 
719 {
720  return mLayer;
721 }
722 
724 {
725  return mRelation;
726 }
727 
729 {
730  mNmRelation = nmRelation;
731 }
732 
734 {
735  return mNmRelation;
736 }
737 
738 
740 
741 
743 {
744 }
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.
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.
Q_DECL_DEPRECATED QString label() const
Determines the label of this element.
void showEvent(QShowEvent *)
Refresh the UI when the widget becomes visible.
void setLabel(const QString &label=QString())
Sets label for this element If it's empty it takes the relation id as label.
void linkFeature()
Links a new feature to the relation.
Q_DECL_DEPRECATED void updateTitle()
Updates the title contents to reflect the current state of the widget.
QgsAbstractRelationEditorWidget(const QVariantMap &config, QWidget *parent=nullptr)
Constructor.
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.
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.
This class contains context information for attribute editor widgets.
void setFormFeature(const QgsFeature &feature)
Set current feature for the currently edited form or table row.
QgsMessageBar * mainMessageBar()
Returns the main message bar.
const QgsVectorLayerTools * vectorLayerTools() const
Returns the associated vector layer tools.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QString expression() const
Returns the original, unmodified expression string.
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)
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsExpression * filterExpression() const
Returns the filter expression (if set).
QgsFeatureRequest & setFilterFids(const QgsFeatureIds &fids)
Sets the feature IDs that should be fetched.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will 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.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
const QgsFeatureIds & selectedFeatures()
Gets the selected features.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Definition: qgsfeature.cpp:302
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QVariant::Type type
Definition: qgsfield.h:58
Container of fields for a vector layer.
Definition: qgsfields.h:45
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:202
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:207
QgsField field(int fieldIdx) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:168
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:344
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:122
QString name
Definition: qgsmaplayer.h:76
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
A polymorphic relation consists of the same properties like a normal relation except for the referenc...
QString layerRepresentation(const QgsVectorLayer *layer) const
Returns layer representation as evaluated string.
QgsRelationManager * relationManager
Definition: qgsproject.h:111
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:468
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:89
QString name
Definition: qgsrelation.h:49
QgsVectorLayer * referencedLayer
Definition: qgsrelation.h:48
@ Generated
A generated relation is a child of a polymorphic relation.
Definition: qgsrelation.h:62
@ Normal
A normal relation.
Definition: qgsrelation.h:61
QList< QgsRelation::FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
Q_GADGET QString id
Definition: qgsrelation.h:46
RelationType type() const
Returns the type of the relation.
QgsPolymorphicRelation polymorphicRelation
Definition: qgsrelation.h:52
QgsAttributeList referencedFields() const
Returns a list of attributes used to form the referenced fields (most likely primary key) on the refe...
QgsVectorLayer * referencingLayer
Definition: qgsrelation.h:47
bool isValid
Definition: qgsrelation.h:50
QgsFeatureRequest getRelatedFeaturesRequest(const QgsFeature &feature) const
Creates a request to return all the features on the referencing (child) layer which have a foreign ke...
Methods in this class are used to handle basic operations on vector layers.
virtual bool startEditing(QgsVectorLayer *layer) const =0
This will be called, whenever a vector layer should be switched to edit mode.
virtual bool saveEdits(QgsVectorLayer *layer) const =0
Should be called, when the features should be committed but the editing session is not ended.
virtual bool addFeature(QgsVectorLayer *layer, const QgsAttributeMap &defaultValues=QgsAttributeMap(), const QgsGeometry &defaultGeometry=QgsGeometry(), QgsFeature *feature=nullptr) const =0
This method should/will be called, whenever a new feature will be added to the layer.
virtual bool stopEditing(QgsVectorLayer *layer, bool allowCancel=true) const =0
Will be called, when an editing session is ended and the features should be committed.
Contains mainly the QMap with QgsVectorLayer and QgsFeatureIds do 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)
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())
Represents a vector layer which manages a vector based data sets.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
bool addFeatures(QgsFeatureList &features, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a list of features to the sink.
bool deleteFeatures(const QgsFeatureIds &fids, DeleteContext *context=nullptr)
Deletes a set of features from the layer (but does not commit it)
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Q_INVOKABLE void selectByIds(const QgsFeatureIds &ids, Qgis::SelectBehavior behavior=Qgis::SelectBehavior::SetSelection)
Selects matching features using a list of feature IDs.
bool changeAttributeValue(QgsFeatureId fid, int field, const QVariant &newValue, const QVariant &oldValue=QVariant(), bool skipDefaultValues=false)
Changes an attribute value for a feature (but does not immediately commit the changes).
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=QgsFeatureSink::Flags()) FINAL
Adds a single feature to the sink.
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:834
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:37
#define FID_TO_STRING(fid)
Definition: qgsfeatureid.h:33
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QList< int > QgsAttributeList
Definition: qgsfield.h:26
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
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.