QGIS API Documentation  3.25.0-Master (10b47c2603)
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  return mFeatureList;
193 }
194 
196 {
197  if ( state )
198  {
200  if ( mNmRelation.isValid() )
202  }
203  else
204  {
206  if ( mNmRelation.isValid() )
208  }
209 }
210 
212 {
214  if ( mNmRelation.isValid() )
216 }
217 
219 {
220  QgsAttributeMap keyAttrs;
221 
223 
224  // Fields of the linking table
225  const QgsFields fields = mRelation.referencingLayer()->fields();
226 
227  QgsFeatureIds addedFeatureIds;
228 
229  // For generated relations insert the referenced layer field
231  {
233  keyAttrs.insert( fields.indexFromName( polyRel.referencedLayerField() ), polyRel.layerRepresentation( mRelation.referencedLayer() ) );
234  }
235 
236  if ( mNmRelation.isValid() )
237  {
238  // only normal relations support m:n relation
239  Q_ASSERT( mNmRelation.type() == QgsRelation::Normal );
240 
241  // n:m Relation: first let the user create a new feature on the other table
242  // and autocreate a new linking feature.
243  QgsFeature finalFeature;
244  if ( !vlTools->addFeature( mNmRelation.referencedLayer(), QgsAttributeMap(), geometry, &finalFeature, this, false, true ) )
245  return QgsFeatureIds();
246 
247  addedFeatureIds.insert( finalFeature.id() );
248 
249  // Expression context for the linking table
251 
252  QgsAttributeMap linkAttributes = keyAttrs;
253  const auto constFieldPairs = mRelation.fieldPairs();
254 
255  QgsVectorLayerUtils::QgsFeaturesDataList linkFeatureDataList;
256  for ( const QgsFeature &editingFeature : std::as_const( mFeatureList ) )
257  {
258  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
259  {
260  const int index = fields.indexOf( fieldPair.first );
261  linkAttributes.insert( index, editingFeature.attribute( fieldPair.second ) );
262  }
263 
264  const auto constNmFieldPairs = mNmRelation.fieldPairs();
265  for ( const QgsRelation::FieldPair &fieldPair : constNmFieldPairs )
266  {
267  const int index = fields.indexOf( fieldPair.first );
268  linkAttributes.insert( index, finalFeature.attribute( fieldPair.second ) );
269  }
270 
271  linkFeatureDataList.append( QgsVectorLayerUtils::QgsFeatureData( QgsGeometry(), linkAttributes ) );
272  }
273  QgsFeatureList linkFeatureList = QgsVectorLayerUtils::createFeatures( mRelation.referencingLayer(), linkFeatureDataList, &context );
274  mRelation.referencingLayer()->addFeatures( linkFeatureList );
275  }
276  else
277  {
278  const auto constFieldPairs = mRelation.fieldPairs();
279  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
280  keyAttrs.insert( fields.indexFromName( fieldPair.referencingField() ), mFeatureList.first().attribute( fieldPair.referencedField() ) );
281 
283  if ( !vlTools->addFeature( mRelation.referencingLayer(), keyAttrs, geometry, &linkFeature, this, false, true ) )
284  return QgsFeatureIds();
285 
286  addedFeatureIds.insert( linkFeature.id() );
287 
288  // In multiedit add to other features to but whitout dialog
289  for ( const QgsFeature &feature : std::as_const( mFeatureList ) )
290  {
291  // First feature already added
292  if ( mFeatureList.first() == feature )
293  continue;
294 
295  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
296  linkFeature.setAttribute( fields.indexFromName( fieldPair.referencingField() ), feature.attribute( fieldPair.referencedField() ) );
297 
299  addedFeatureIds.insert( linkFeature.id() );
300  }
301  }
302 
303  updateUi();
304 
305  emit relatedFeaturesChanged();
306 
307  return addedFeatureIds;
308 }
309 
311 {
312  deleteFeatures( QgsFeatureIds() << fid );
313 
314  emit relatedFeaturesChanged();
315 }
316 
318 {
319  bool deleteFeatures = true;
320 
321  QgsVectorLayer *layer;
322  if ( mNmRelation.isValid() )
323  {
324  // only normal relations support m:n relation
325  Q_ASSERT( mNmRelation.type() == QgsRelation::Normal );
326 
327  layer = mNmRelation.referencedLayer();
328 
329  // When deleting a linked feature within an N:M relation,
330  // check if the feature is linked to more than just one feature.
331  // In case it is linked more than just once, ask the user for confirmation
332  // as it is likely he was not aware of the implications and might delete
333  // there may be several linking entries deleted along.
334 
335  QgsFeatureRequest deletedFeaturesRequest;
336  deletedFeaturesRequest.setFilterFids( fids );
337  deletedFeaturesRequest.setFlags( QgsFeatureRequest::NoGeometry );
338  deletedFeaturesRequest.setSubsetOfAttributes( QgsAttributeList() << mNmRelation.referencedFields().first() );
339 
340  QgsFeatureIterator deletedFeatures = layer->getFeatures( deletedFeaturesRequest );
341  QStringList deletedFeaturesPks;
343  while ( deletedFeatures.nextFeature( feature ) )
344  {
345  deletedFeaturesPks.append( QgsExpression::quotedValue( feature.attribute( mNmRelation.referencedFields().first() ) ) );
346  }
347 
348  QgsFeatureRequest linkingFeaturesRequest;
349  linkingFeaturesRequest.setFlags( QgsFeatureRequest::NoGeometry );
350  linkingFeaturesRequest.setNoAttributes();
351 
352  QString linkingFeaturesRequestExpression;
353  if ( !deletedFeaturesPks.empty() )
354  {
355  linkingFeaturesRequestExpression = QStringLiteral( "%1 IN (%2)" ).arg( QgsExpression::quotedColumnRef( mNmRelation.fieldPairs().first().first ), deletedFeaturesPks.join( ',' ) );
356  linkingFeaturesRequest.setFilterExpression( linkingFeaturesRequestExpression );
357 
358  QgsFeatureIterator relatedLinkingFeatures = mNmRelation.referencingLayer()->getFeatures( linkingFeaturesRequest );
359 
360  int relatedLinkingFeaturesCount = 0;
361  while ( relatedLinkingFeatures.nextFeature( feature ) )
362  {
363  relatedLinkingFeaturesCount++;
364  }
365 
366  if ( deletedFeaturesPks.size() == 1 && relatedLinkingFeaturesCount > 1 )
367  {
368  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 );
369  messageBox.addButton( QMessageBox::Cancel );
370  QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
371 
372  messageBox.exec();
373  if ( messageBox.clickedButton() != deleteButton )
374  deleteFeatures = false;
375  }
376  else if ( deletedFeaturesPks.size() > 1 && relatedLinkingFeaturesCount > deletedFeaturesPks.size() )
377  {
378  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 );
379  messageBox.addButton( QMessageBox::Cancel );
380  QAbstractButton *deleteButton = messageBox.addButton( tr( "Delete" ), QMessageBox::AcceptRole );
381 
382  messageBox.exec();
383  if ( messageBox.clickedButton() != deleteButton )
384  deleteFeatures = false;
385  }
386  }
387  }
388  else
389  {
390  layer = mRelation.referencingLayer();
391  }
392 
394  if ( QgsVectorLayerUtils::impactsCascadeFeatures( layer, fids, QgsProject::instance(), infoContext ) )
395  {
396  QString childrenInfo;
397  int childrenCount = 0;
398  const auto infoContextLayers = infoContext.layers();
399  for ( QgsVectorLayer *chl : infoContextLayers )
400  {
401  childrenCount += infoContext.duplicatedFeatures( chl ).size();
402  childrenInfo += ( tr( "%n feature(s) on layer \"%1\", ", nullptr, infoContext.duplicatedFeatures( chl ).size() ).arg( chl->name() ) );
403  }
404 
405  // for extra safety to make sure we know that the delete can have impact on children and joins
406  const int res = QMessageBox::question( this, tr( "Delete at least %1 feature(s) on other layer(s)" ).arg( childrenCount ),
407  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 ),
408  QMessageBox::Yes | QMessageBox::No );
409  if ( res != QMessageBox::Yes )
410  deleteFeatures = false;
411  }
412 
413  if ( deleteFeatures )
414  {
416  layer->deleteFeatures( fids, &context );
417  const auto contextLayers = context.handledLayers();
418  if ( contextLayers.size() > 1 )
419  {
420  int deletedCount = 0;
421  QString feedbackMessage;
422  for ( QgsVectorLayer *contextLayer : contextLayers )
423  {
424  feedbackMessage += tr( "%1 on layer %2. " ).arg( context.handledFeatures( contextLayer ).size() ).arg( contextLayer->name() );
425  deletedCount += context.handledFeatures( contextLayer ).size();
426  }
427  mEditorContext.mainMessageBar()->pushMessage( tr( "%n feature(s) deleted: %2", nullptr, deletedCount ).arg( feedbackMessage ), Qgis::MessageLevel::Success );
428  }
429 
430  updateUi();
431 
432  emit relatedFeaturesChanged();
433  }
434 }
435 
437 {
438  QgsVectorLayer *layer = nullptr;
439 
440  if ( mNmRelation.isValid() )
441  {
442  // only normal relations support m:n relation
443  Q_ASSERT( mNmRelation.type() == QgsRelation::Normal );
444 
445  layer = mNmRelation.referencedLayer();
446  }
447  else
448  {
449  if ( multiEditModeActive() )
450  {
451  QgsLogger::warning( tr( "For 1:n relations is not possible to link to multiple features" ) );
452  return;
453  }
454 
455  layer = mRelation.referencingLayer();
456  }
457 
458  QgsFeatureSelectionDlg *selectionDlg = new QgsFeatureSelectionDlg( layer, mEditorContext, this );
459  selectionDlg->setAttribute( Qt::WA_DeleteOnClose );
460 
461  const QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( mRelation.referencedLayer(), mFeatureList.first() );
462  selectionDlg->setWindowTitle( tr( "Link existing child features for parent %1 \"%2\"" ).arg( mRelation.referencedLayer()->name(), displayString ) );
463 
464  connect( selectionDlg, &QDialog::accepted, this, &QgsAbstractRelationEditorWidget::onLinkFeatureDlgAccepted );
465  selectionDlg->show();
466 }
467 
469 {
470  QgsFeatureSelectionDlg *selectionDlg = qobject_cast<QgsFeatureSelectionDlg *>( sender() );
471 
472  if ( mNmRelation.isValid() )
473  {
474  // only normal relations support m:n relation
475  Q_ASSERT( mNmRelation.type() == QgsRelation::Normal );
476 
477  // Fields of the linking table
478  const QgsFields fields = mRelation.referencingLayer()->fields();
479 
480  QgsAttributeMap linkAttributes;
481 
483  {
485  Q_ASSERT( polyRel.isValid() );
486 
487  linkAttributes.insert( fields.indexFromName( polyRel.referencedLayerField() ),
489  }
490 
491  QgsVectorLayerUtils::QgsFeaturesDataList linkFeatureDataList;
492  QgsFeature relatedFeature;
495  .setFilterFids( selectionDlg->selectedFeatures() )
497  while ( it.nextFeature( relatedFeature ) )
498  {
499  for ( const QgsFeature &editFeature : std::as_const( mFeatureList ) )
500  {
501  {
502  const auto constFieldPairs = mRelation.fieldPairs();
503  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
504  {
505  const int index = fields.indexOf( fieldPair.first );
506  linkAttributes.insert( index, editFeature.attribute( fieldPair.second ) );
507  }
508  }
509 
510  const auto constFieldPairs = mNmRelation.fieldPairs();
511  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
512  {
513  const int index = fields.indexOf( fieldPair.first );
514  linkAttributes.insert( index, relatedFeature.attribute( fieldPair.second ) );
515  }
516 
517  linkFeatureDataList.append( QgsVectorLayerUtils::QgsFeatureData( QgsGeometry(), linkAttributes ) );
518  }
519  }
520 
521  // Expression context for the linking table
523 
524  QgsFeatureList linkFeaturesList = QgsVectorLayerUtils::createFeatures( mRelation.referencingLayer(), linkFeatureDataList, &context );
525 
526  mRelation.referencingLayer()->addFeatures( linkFeaturesList );
527  QgsFeatureIds ids;
528  const auto constNewFeatures = linkFeaturesList;
529  for ( const QgsFeature &f : constNewFeatures )
530  ids << f.id();
532  }
533  else
534  {
535  if ( multiEditModeActive() )
536  {
537  QgsLogger::warning( tr( "For 1:n relations is not possible to link to multiple features" ) );
538  return;
539  }
540 
541  QMap<int, QVariant> keys;
542  const auto constFieldPairs = mRelation.fieldPairs();
543  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
544  {
545  const int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
546  const QVariant val = mFeatureList.first().attribute( fieldPair.referencedField() );
547  keys.insert( idx, val );
548  }
549 
550  const auto constSelectedFeatures = selectionDlg->selectedFeatures();
551  for ( const QgsFeatureId fid : constSelectedFeatures )
552  {
553  QgsVectorLayer *referencingLayer = mRelation.referencingLayer();
555  {
557 
558  Q_ASSERT( polyRel.isValid() );
559 
561  referencingLayer->fields().indexFromName( polyRel.referencedLayerField() ),
563  }
564 
565  QMapIterator<int, QVariant> it( keys );
566  while ( it.hasNext() )
567  {
568  it.next();
569  referencingLayer->changeAttributeValue( fid, it.key(), it.value() );
570  }
571  }
572  }
573 
574  updateUi();
575 
576  emit relatedFeaturesChanged();
577 }
578 
580 {
581  unlinkFeatures( QgsFeatureIds() << fid );
582 }
583 
585 {
586  if ( mNmRelation.isValid() )
587  {
588  // only normal relations support m:n relation
589  Q_ASSERT( mNmRelation.type() == QgsRelation::Normal );
590 
593  .setFilterFids( fids )
594  .setSubsetOfAttributes( mNmRelation.referencedFields() ) );
595 
596  QgsFeature f;
597 
598  QStringList filters;
599 
600  while ( selectedIterator.nextFeature( f ) )
601  {
602  filters << '(' + mNmRelation.getRelatedFeaturesRequest( f ).filterExpression()->expression() + ')';
603  }
604 
605  QStringList featureFilters;
606  for ( const QgsFeature &editingFeature : std::as_const( mFeatureList ) )
607  {
608  featureFilters.append( mRelation.getRelatedFeaturesRequest( editingFeature ).filterExpression()->expression() );
609  }
610 
611  const QString filter = QStringLiteral( "(%1) AND (%2)" ).arg(
612  featureFilters.join( QLatin1String( " OR " ) ),
613  filters.join( QLatin1String( " OR " ) ) );
614 
616  .setNoAttributes()
617  .setFilterExpression( filter ) );
618 
619  QgsFeatureIds fids;
620 
621  while ( linkedIterator.nextFeature( f ) )
622  {
623  fids << f.id();
624  QgsDebugMsgLevel( FID_TO_STRING( f.id() ), 4 );
625  }
626 
628  }
629  else
630  {
631  QMap<int, QgsField> keyFields;
632  const auto constFieldPairs = mRelation.fieldPairs();
633  for ( const QgsRelation::FieldPair &fieldPair : constFieldPairs )
634  {
635  const int idx = mRelation.referencingLayer()->fields().lookupField( fieldPair.referencingField() );
636  if ( idx < 0 )
637  {
638  QgsDebugMsg( QStringLiteral( "referencing field %1 not found" ).arg( fieldPair.referencingField() ) );
639  return;
640  }
641  const QgsField fld = mRelation.referencingLayer()->fields().at( idx );
642  keyFields.insert( idx, fld );
643  }
644 
645  const auto constFeatureids = fids;
646  for ( const QgsFeatureId fid : constFeatureids )
647  {
648  QgsVectorLayer *referencingLayer = mRelation.referencingLayer();
650  {
652 
653  Q_ASSERT( mRelation.polymorphicRelation().isValid() );
654 
656  referencingLayer->fields().indexFromName( polyRel.referencedLayerField() ),
657  referencingLayer->fields().field( polyRel.referencedLayerField() ).type() );
658  }
659 
660  QMapIterator<int, QgsField> it( keyFields );
661  while ( it.hasNext() )
662  {
663  it.next();
664  mRelation.referencingLayer()->changeAttributeValue( fid, it.key(), QVariant( it.value().type() ) );
665  }
666  }
667  }
668 
669  updateUi();
670 
671  emit relatedFeaturesChanged();
672 }
673 
675 {}
676 
677 void QgsAbstractRelationEditorWidget::setTitle( const QString &title )
678 {
679  Q_UNUSED( title )
680 }
681 
683 {
684  Q_UNUSED( newRelation )
685  Q_UNUSED( newFeature )
686 }
687 
689 {}
690 
691 void QgsAbstractRelationEditorWidget::beforeSetRelations( const QgsRelation &newRelation, const QgsRelation &newNmRelation )
692 {
693  Q_UNUSED( newRelation )
694  Q_UNUSED( newNmRelation )
695 }
696 
698 {}
699 
701 {
702  duplicateFeatures( QgsFeatureIds() << fid );
703 
704  emit relatedFeaturesChanged();
705 }
706 
708 {
710 
711  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterFids( fids ) );
712  QgsFeature f;
713  while ( fit.nextFeature( f ) )
714  {
715  QgsVectorLayerUtils::QgsDuplicateFeatureContext duplicatedFeatureContext;
716  QgsVectorLayerUtils::duplicateFeature( layer, f, QgsProject::instance(), duplicatedFeatureContext );
717  }
718 
719  emit relatedFeaturesChanged();
720 }
721 
723 {
724  updateUi();
725 }
726 
727 
729 
730 
732  : QWidget( parent )
733  , mRelation( relation )
734 {
735 }
736 
738 {
739  return mLayer;
740 }
741 
743 {
744  return mRelation;
745 }
746 
748 {
749  mNmRelation = nmRelation;
750 }
751 
753 {
754  return mNmRelation;
755 }
756 
757 
759 
760 
762 {
763 }
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.
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 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.
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:320
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:349
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:114
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:479
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, QWidget *parentWidget=nullptr, bool showModal=true, bool hideParent=false) 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:882
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.