QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
qgsrelationreferencewidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrelationreferencewidget.cpp
3  --------------------------------------
4  Date : 20.4.2013
5  Copyright : (C) 2013 Matthias Kuhn
6  Email : matthias at opengis dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 
18 #include <QPushButton>
19 #include <QDialog>
20 #include <QHBoxLayout>
21 #include <QTimer>
22 #include <QCompleter>
23 
24 #include "qgsattributeform.h"
26 #include "qgsattributedialog.h"
27 #include "qgsapplication.h"
28 #include "qgscollapsiblegroupbox.h"
29 #include "qgseditorwidgetfactory.h"
30 #include "qgsexpression.h"
31 #include "qgsfeaturelistmodel.h"
32 #include "qgsfields.h"
33 #include "qgsgeometry.h"
34 #include "qgshighlight.h"
35 #include "qgsmapcanvas.h"
36 #include "qgsmessagebar.h"
38 #include "qgsvectorlayer.h"
39 #include "qgsattributetablemodel.h"
42 #include "qgsfeatureiterator.h"
43 #include "qgsfeaturelistcombobox.h"
45 #include "qgsfeaturefiltermodel.h"
46 #include "qgsidentifymenu.h"
47 #include "qgsvectorlayerutils.h"
48 
49 
50 bool qVariantListIsNull( const QVariantList &list )
51 {
52  if ( list.isEmpty() )
53  return true;
54 
55  for ( int i = 0; i < list.size(); ++i )
56  {
57  if ( !list.at( i ).isNull() )
58  return false;
59  }
60  return true;
61 }
62 
63 
65  : QWidget( parent )
66 {
67  mTopLayout = new QVBoxLayout( this );
68  mTopLayout->setContentsMargins( 0, 0, 0, 0 );
69 
70  setSizePolicy( sizePolicy().horizontalPolicy(), QSizePolicy::Fixed );
71 
72  setLayout( mTopLayout );
73 
74  QHBoxLayout *editLayout = new QHBoxLayout();
75  editLayout->setContentsMargins( 0, 0, 0, 0 );
76  editLayout->setSpacing( 2 );
77 
78  // Prepare the container and layout for the filter comboboxes
79  mChooserContainer = new QWidget;
80  editLayout->addWidget( mChooserContainer );
81  QHBoxLayout *chooserLayout = new QHBoxLayout;
82  chooserLayout->setContentsMargins( 0, 0, 0, 0 );
83  mFilterLayout = new QHBoxLayout;
84  mFilterLayout->setContentsMargins( 0, 0, 0, 0 );
85  mFilterContainer = new QWidget;
86  mFilterContainer->setLayout( mFilterLayout );
87  mChooserContainer->setLayout( chooserLayout );
88  chooserLayout->addWidget( mFilterContainer );
89 
90  mComboBox = new QgsFeatureListComboBox();
91  mChooserContainer->layout()->addWidget( mComboBox );
92 
93  // read-only line edit
94  mLineEdit = new QLineEdit();
95  mLineEdit->setReadOnly( true );
96  editLayout->addWidget( mLineEdit );
97 
98  // open form button
99  mOpenFormButton = new QToolButton();
100  mOpenFormButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionPropertyItem.svg" ) ) );
101  mOpenFormButton->setText( tr( "Open Related Feature Form" ) );
102  editLayout->addWidget( mOpenFormButton );
103 
104  mAddEntryButton = new QToolButton();
105  mAddEntryButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionAdd.svg" ) ) );
106  mAddEntryButton->setText( tr( "Add New Entry" ) );
107  editLayout->addWidget( mAddEntryButton );
108 
109  // highlight button
110  mHighlightFeatureButton = new QToolButton( this );
111  mHighlightFeatureButton->setPopupMode( QToolButton::MenuButtonPopup );
112  mHighlightFeatureAction = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionHighlightFeature.svg" ) ), tr( "Highlight feature" ), this );
113  mScaleHighlightFeatureAction = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionScaleHighlightFeature.svg" ) ), tr( "Scale and highlight feature" ), this );
114  mPanHighlightFeatureAction = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionPanHighlightFeature.svg" ) ), tr( "Pan and highlight feature" ), this );
115  mHighlightFeatureButton->addAction( mHighlightFeatureAction );
116  mHighlightFeatureButton->addAction( mScaleHighlightFeatureAction );
117  mHighlightFeatureButton->addAction( mPanHighlightFeatureAction );
118  mHighlightFeatureButton->setDefaultAction( mHighlightFeatureAction );
119  editLayout->addWidget( mHighlightFeatureButton );
120 
121  // map identification button
122  mMapIdentificationButton = new QToolButton( this );
123  mMapIdentificationButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionMapIdentification.svg" ) ) );
124  mMapIdentificationButton->setText( tr( "Select on Map" ) );
125  mMapIdentificationButton->setCheckable( true );
126  editLayout->addWidget( mMapIdentificationButton );
127 
128  // remove foreign key button
129  mRemoveFKButton = new QToolButton( this );
130  mRemoveFKButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionRemove.svg" ) ) );
131  mRemoveFKButton->setText( tr( "No Selection" ) );
132  editLayout->addWidget( mRemoveFKButton );
133 
134  // add line to top layout
135  mTopLayout->addLayout( editLayout );
136 
137  // embed form
138  mAttributeEditorFrame = new QgsCollapsibleGroupBox( this );
139  mAttributeEditorLayout = new QVBoxLayout( mAttributeEditorFrame );
140  mAttributeEditorFrame->setLayout( mAttributeEditorLayout );
141  mAttributeEditorFrame->setSizePolicy( mAttributeEditorFrame->sizePolicy().horizontalPolicy(), QSizePolicy::Expanding );
142  mTopLayout->addWidget( mAttributeEditorFrame );
143 
144  // invalid label
145  mInvalidLabel = new QLabel( tr( "The relation is not valid. Please make sure your relation definitions are OK." ) );
146  mInvalidLabel->setWordWrap( true );
147  QFont font = mInvalidLabel->font();
148  font.setItalic( true );
149  mInvalidLabel->setStyleSheet( QStringLiteral( "QLabel { color: red; } " ) );
150  mInvalidLabel->setFont( font );
151  mTopLayout->addWidget( mInvalidLabel );
152 
153  // default mode is combobox, no geometric relation and no embed form
154  mLineEdit->hide();
155  mMapIdentificationButton->hide();
156  mHighlightFeatureButton->hide();
157  mAttributeEditorFrame->hide();
158  mInvalidLabel->hide();
159  mAddEntryButton->hide();
160 
161  // connect buttons
162  connect( mOpenFormButton, &QAbstractButton::clicked, this, &QgsRelationReferenceWidget::openForm );
163  connect( mHighlightFeatureButton, &QToolButton::triggered, this, &QgsRelationReferenceWidget::highlightActionTriggered );
164  connect( mMapIdentificationButton, &QAbstractButton::clicked, this, &QgsRelationReferenceWidget::mapIdentification );
165  connect( mRemoveFKButton, &QAbstractButton::clicked, this, &QgsRelationReferenceWidget::deleteForeignKeys );
166  connect( mAddEntryButton, &QAbstractButton::clicked, this, &QgsRelationReferenceWidget::addEntry );
167  connect( mComboBox, &QComboBox::editTextChanged, this, &QgsRelationReferenceWidget::updateAddEntryButton );
168  connect( mComboBox, &QgsFeatureListComboBox::modelUpdated, this, &QgsRelationReferenceWidget::updateIndex );
169 }
170 
172 {
173  deleteHighlight();
174  unsetMapTool();
175 }
176 
177 void QgsRelationReferenceWidget::updateIndex()
178 {
179  if ( mChainFilters && mComboBox->count() > 0 )
180  {
181  int index = -1;
182 
183  // uninitialized filter
184  if ( ! mFilterComboBoxes.isEmpty()
185  && mFilterComboBoxes[0]->currentIndex() == 0 && mAllowNull )
186  {
187  index = mComboBox->nullIndex();
188  }
189  else if ( mComboBox->count() > mComboBox->nullIndex() )
190  {
191  index = mComboBox->nullIndex() + 1;
192  }
193  else if ( mAllowNull )
194  {
195  index = mComboBox->nullIndex();
196  }
197  else
198  {
199  index = 0;
200  }
201 
202  if ( mComboBox->count() > index )
203  {
204  mComboBox->setCurrentIndex( index );
205  }
206  }
207 }
208 
210 {
211  mAllowNull = allowNullValue;
212  mRemoveFKButton->setVisible( allowNullValue && mReadOnlySelector );
213 
214  if ( relation.isValid() )
215  {
216  mReferencedLayerId = relation.referencedLayerId();
217  mReferencedLayerName = relation.referencedLayer()->name();
219  mReferencedLayerProviderKey = relation.referencedLayer()->providerType();
220  mInvalidLabel->hide();
221 
222  mRelation = relation;
223  mReferencingLayer = relation.referencingLayer();
224  mReferencedLayer = relation.referencedLayer();
225  const QList<QgsRelation::FieldPair> fieldPairs = relation.fieldPairs();
226  for ( const QgsRelation::FieldPair &fieldPair : fieldPairs )
227  {
228  mReferencedFields << fieldPair.referencedField();
229  }
230  if ( mComboBox )
231  {
232  mComboBox->setSourceLayer( mReferencedLayer );
233  mComboBox->setIdentifierFields( mReferencedFields );
234  }
235  mAttributeEditorFrame->setObjectName( QStringLiteral( "referencing/" ) + relation.name() );
236 
237  if ( mEmbedForm )
238  {
240  mAttributeEditorFrame->setTitle( mReferencedLayer->name() );
241  mReferencedAttributeForm = new QgsAttributeForm( relation.referencedLayer(), QgsFeature(), context, this );
242  mAttributeEditorLayout->addWidget( mReferencedAttributeForm );
243  }
244 
245  connect( mReferencedLayer, &QgsVectorLayer::editingStarted, this, &QgsRelationReferenceWidget::updateAddEntryButton );
246  connect( mReferencedLayer, &QgsVectorLayer::editingStopped, this, &QgsRelationReferenceWidget::updateAddEntryButton );
247  updateAddEntryButton();
248  }
249  else
250  {
251  mInvalidLabel->show();
252  }
253 
254  if ( mShown && isVisible() )
255  {
256  init();
257  }
258 }
259 
261 {
262  if ( !editable )
263  {
264  unsetMapTool();
265  }
266 
267  mFilterContainer->setEnabled( editable );
268  mComboBox->setEnabled( editable );
269  mComboBox->setEditable( true );
270  mMapIdentificationButton->setEnabled( editable );
271  mRemoveFKButton->setEnabled( editable );
272  mIsEditable = editable;
273 }
274 
275 void QgsRelationReferenceWidget::setForeignKey( const QVariant &value )
276 {
277  setForeignKeys( QVariantList() << value );
278 }
279 
280 void QgsRelationReferenceWidget::setForeignKeys( const QVariantList &values )
281 {
282  if ( values.isEmpty() )
283  {
284  return;
285  }
286  if ( qVariantListIsNull( values ) )
287  {
289  return;
290  }
291 
292  if ( !mReferencedLayer )
293  return;
294 
295  if ( mReadOnlySelector )
296  {
297  // Attributes from the referencing layer
298  QgsAttributes attrs = QgsAttributes( mReferencingLayer->fields().count() );
299  // Set the value on the foreign key fields of the referencing record
300 
301  const QList<QgsRelation::FieldPair> fieldPairs = mRelation.fieldPairs();
302  int fieldCount = std::min( fieldPairs.count(), values.count() );
303  for ( int i = 0; i < fieldCount; i++ )
304  {
305  int idx = mReferencingLayer->fields().lookupField( fieldPairs.at( i ).referencingField() );
306  attrs[idx] = values.at( i );
307  }
308 
309  QgsFeatureRequest request = mRelation.getReferencedFeatureRequest( attrs );
310 
311  mReferencedLayer->getFeatures( request ).nextFeature( mFeature );
312 
313  if ( !mFeature.isValid() )
314  {
315  return;
316  }
317 
318  mForeignKeys.clear();
319  for ( const QString &fieldName : qgis::as_const( mReferencedFields ) )
320  mForeignKeys << mFeature.attribute( fieldName );
321 
322  QgsExpression expr( mReferencedLayer->displayExpression() );
324  context.setFeature( mFeature );
325  QString title = expr.evaluate( &context ).toString();
326  if ( expr.hasEvalError() )
327  {
328  QStringList titleFields;
329  for ( const QString &fieldName : qgis::as_const( mReferencedFields ) )
330  titleFields << mFeature.attribute( fieldName ).toString();
331  title = titleFields.join( QStringLiteral( " " ) );
332  }
333  mLineEdit->setText( title );
334  }
335  else
336  {
337  mComboBox->setIdentifierValues( values );
338 
339  if ( mChainFilters )
340  {
341  QVariant nullValue = QgsApplication::nullRepresentation();
342 
343  QgsFeatureRequest request = mComboBox->currentFeatureRequest();
344 
345  mReferencedLayer->getFeatures( request ).nextFeature( mFeature );
346 
347  const int count = std::min( mFilterComboBoxes.size(), mFilterFields.size() );
348  for ( int i = 0; i < count; i++ )
349  {
350  QVariant v = mFeature.attribute( mFilterFields[i] );
351  QString f = v.isNull() ? nullValue.toString() : v.toString();
352  mFilterComboBoxes.at( i )->setCurrentIndex( mFilterComboBoxes.at( i )->findText( f ) );
353  }
354  }
355  }
356 
357  mRemoveFKButton->setEnabled( mIsEditable );
358  highlightFeature( mFeature ); // TODO : make this async
359  updateAttributeEditorFrame( mFeature );
360 
361  emitForeignKeysChanged( foreignKeys() );
362 }
363 
365 {
366  // deactivate filter comboboxes
367  if ( mChainFilters && !mFilterComboBoxes.isEmpty() )
368  {
369  QComboBox *cb = mFilterComboBoxes.first();
370  cb->setCurrentIndex( 0 );
371  disableChainedComboBoxes( cb );
372  }
373 
374  if ( mReadOnlySelector )
375  {
376  const QString nullValue = QgsApplication::nullRepresentation();
377 
378  QString nullText;
379  if ( mAllowNull )
380  {
381  nullText = tr( "%1 (no selection)" ).arg( nullValue );
382  }
383  mLineEdit->setText( nullText );
384  QVariantList nullAttributes;
385  for ( const QString &fieldName : qgis::as_const( mReferencedFields ) )
386  {
387  Q_UNUSED( fieldName );
388  nullAttributes << QVariant( QVariant::Int );
389  }
390  mForeignKeys = nullAttributes;
391  mFeature.setValid( false );
392  }
393  else
394  {
395  mComboBox->setIdentifierValuesToNull();
396  }
397  mRemoveFKButton->setEnabled( false );
398  updateAttributeEditorFrame( QgsFeature() );
399 
400  emitForeignKeysChanged( foreignKeys() );
401 }
402 
404 {
405  QgsFeature f;
406  if ( mReferencedLayer )
407  {
408  QgsFeatureRequest request;
409  if ( mReadOnlySelector )
410  {
411  request = QgsFeatureRequest().setFilterFid( mFeature.id() );
412  }
413  else
414  {
415  request = mComboBox->currentFeatureRequest();
416  }
417  mReferencedLayer->getFeatures( request ).nextFeature( f );
418  }
419  return f;
420 }
421 
423 {
424  if ( mReadOnlySelector )
425  {
426  whileBlocking( mLineEdit )->setText( QString() );
427  }
428  else
429  {
430  whileBlocking( mComboBox )->setIdentifierValuesToNull();
431  }
432  mRemoveFKButton->setEnabled( false );
433  updateAttributeEditorFrame( QgsFeature() );
434 }
435 
437 {
438  QVariantList fkeys;
439  if ( fkeys.isEmpty() )
440  return QVariant( QVariant::Int );
441  else
442  return fkeys.at( 0 );
443 }
444 
446 {
447  if ( mReadOnlySelector )
448  {
449  return mForeignKeys;
450  }
451  else
452  {
453  return mComboBox->identifierValues();
454  }
455 }
456 
458 {
459  mEditorContext = context;
460  mCanvas = canvas;
461  mMessageBar = messageBar;
462 
463  mMapToolIdentify.reset( new QgsMapToolIdentifyFeature( mCanvas ) );
464  mMapToolIdentify->setButton( mMapIdentificationButton );
465 
466  if ( mEditorContext.cadDockWidget() )
467  {
468  mMapToolDigitize.reset( new QgsMapToolDigitizeFeature( mCanvas, mEditorContext.cadDockWidget() ) );
469  mMapToolDigitize->setButton( mAddEntryButton );
470  updateAddEntryButton();
471  }
472 }
473 
475 {
476  if ( display )
477  {
478  setSizePolicy( sizePolicy().horizontalPolicy(), QSizePolicy::MinimumExpanding );
479  mTopLayout->setAlignment( Qt::AlignTop );
480  }
481 
482  mAttributeEditorFrame->setVisible( display );
483  mEmbedForm = display;
484 }
485 
487 {
488  mChooserContainer->setHidden( readOnly );
489  mLineEdit->setVisible( readOnly );
490  mRemoveFKButton->setVisible( mAllowNull && readOnly );
491  mReadOnlySelector = readOnly;
492 }
493 
495 {
496  mHighlightFeatureButton->setVisible( allowMapIdentification );
497  mMapIdentificationButton->setVisible( allowMapIdentification );
498  mAllowMapIdentification = allowMapIdentification;
499 }
500 
502 {
503  mOrderByValue = orderByValue;
504 }
505 
506 void QgsRelationReferenceWidget::setFilterFields( const QStringList &filterFields )
507 {
508  mFilterFields = filterFields;
509 }
510 
512 {
513  mOpenFormButton->setVisible( openFormButtonVisible );
514  mOpenFormButtonVisible = openFormButtonVisible;
515 }
516 
518 {
519  mChainFilters = chainFilters;
520 }
521 
523 {
524  Q_UNUSED( e )
525 
526  mShown = true;
527  if ( !mInitialized )
528  init();
529 }
530 
532 {
533  if ( !mReadOnlySelector && mReferencedLayer )
534  {
535  QApplication::setOverrideCursor( Qt::WaitCursor );
536 
537  QSet<QString> requestedAttrs;
538 
539  if ( !mFilterFields.isEmpty() )
540  {
541  for ( const QString &fieldName : qgis::as_const( mFilterFields ) )
542  {
543  int idx = mReferencedLayer->fields().lookupField( fieldName );
544 
545  if ( idx == -1 )
546  continue;
547 
548  QComboBox *cb = new QComboBox();
549  cb->setProperty( "Field", fieldName );
550  cb->setProperty( "FieldAlias", mReferencedLayer->attributeDisplayName( idx ) );
551  mFilterComboBoxes << cb;
552  QVariantList uniqueValues = mReferencedLayer->uniqueValues( idx ).toList();
553  cb->addItem( mReferencedLayer->attributeDisplayName( idx ) );
554  QVariant nullValue = QgsApplication::nullRepresentation();
555  cb->addItem( nullValue.toString(), QVariant( mReferencedLayer->fields().at( idx ).type() ) );
556 
557  std::sort( uniqueValues.begin(), uniqueValues.end(), qgsVariantLessThan );
558  const auto constUniqueValues = uniqueValues;
559  for ( const QVariant &v : constUniqueValues )
560  {
561  cb->addItem( v.toString(), v );
562  }
563 
564  connect( cb, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRelationReferenceWidget::filterChanged );
565 
566  // Request this attribute for caching
567  requestedAttrs << fieldName;
568 
569  mFilterLayout->addWidget( cb );
570  }
571 
572  if ( mChainFilters )
573  {
574  QVariant nullValue = QgsApplication::nullRepresentation();
575 
576  QgsFeature ft;
577  QgsFeatureIterator fit = mReferencedLayer->getFeatures();
578  while ( fit.nextFeature( ft ) )
579  {
580  const int count = std::min( mFilterComboBoxes.count(), mFilterFields.count() );
581  for ( int i = 0; i < count - 1; i++ )
582  {
583  QVariant cv = ft.attribute( mFilterFields.at( i ) );
584  QVariant nv = ft.attribute( mFilterFields.at( i + 1 ) );
585  QString cf = cv.isNull() ? nullValue.toString() : cv.toString();
586  QString nf = nv.isNull() ? nullValue.toString() : nv.toString();
587  mFilterCache[mFilterFields[i]][cf] << nf;
588  }
589  }
590 
591  if ( !mFilterComboBoxes.isEmpty() )
592  {
593  QComboBox *cb = mFilterComboBoxes.first();
594  cb->setCurrentIndex( 0 );
595  disableChainedComboBoxes( cb );
596  }
597  }
598  }
599  else
600  {
601  mFilterContainer->hide();
602  }
603 
604  mComboBox->setSourceLayer( mReferencedLayer );
605  mComboBox->setDisplayExpression( mReferencedLayer->displayExpression() );
606  mComboBox->setAllowNull( mAllowNull );
607  mComboBox->setIdentifierFields( mReferencedFields );
608 
609  QVariant nullValue = QgsApplication::nullRepresentation();
610 
611  if ( mChainFilters && mFeature.isValid() )
612  {
613  for ( int i = 0; i < mFilterFields.size(); i++ )
614  {
615  QVariant v = mFeature.attribute( mFilterFields[i] );
616  QString f = v.isNull() ? nullValue.toString() : v.toString();
617  mFilterComboBoxes.at( i )->setCurrentIndex( mFilterComboBoxes.at( i )->findText( f ) );
618  }
619  }
620 
621  // Only connect after iterating, to have only one iterator on the referenced table at once
622  connect( mComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRelationReferenceWidget::comboReferenceChanged );
623  //call it for the first time
624  emit mComboBox->currentIndexChanged( mComboBox->currentIndex() );
625 
626  QApplication::restoreOverrideCursor();
627 
628  mInitialized = true;
629  }
630 }
631 
632 void QgsRelationReferenceWidget::highlightActionTriggered( QAction *action )
633 {
634  if ( action == mHighlightFeatureAction )
635  {
636  highlightFeature();
637  }
638  else if ( action == mScaleHighlightFeatureAction )
639  {
640  highlightFeature( QgsFeature(), Scale );
641  }
642  else if ( action == mPanHighlightFeatureAction )
643  {
644  highlightFeature( QgsFeature(), Pan );
645  }
646 }
647 
649 {
650  QgsFeature feat = referencedFeature();
651 
652  if ( !feat.isValid() )
653  return;
654 
656  QgsAttributeDialog attributeDialog( mReferencedLayer, new QgsFeature( feat ), true, this, true, context );
657  attributeDialog.exec();
658 }
659 
660 void QgsRelationReferenceWidget::highlightFeature( QgsFeature f, CanvasExtent canvasExtent )
661 {
662  if ( !mCanvas )
663  return;
664 
665  if ( !f.isValid() )
666  {
667  f = referencedFeature();
668  if ( !f.isValid() )
669  return;
670  }
671 
672  if ( !f.hasGeometry() )
673  {
674  return;
675  }
676 
677  QgsGeometry geom = f.geometry();
678 
679  // scale or pan
680  if ( canvasExtent == Scale )
681  {
682  QgsRectangle featBBox = geom.boundingBox();
683  featBBox = mCanvas->mapSettings().layerToMapCoordinates( mReferencedLayer, featBBox );
684  QgsRectangle extent = mCanvas->extent();
685  if ( !extent.contains( featBBox ) )
686  {
687  extent.combineExtentWith( featBBox );
688  extent.scale( 1.1 );
689  mCanvas->setExtent( extent );
690  mCanvas->refresh();
691  }
692  }
693  else if ( canvasExtent == Pan )
694  {
695  QgsGeometry centroid = geom.centroid();
696  QgsPointXY center = centroid.asPoint();
697  center = mCanvas->mapSettings().layerToMapCoordinates( mReferencedLayer, center );
698  mCanvas->zoomByFactor( 1.0, &center ); // refresh is done in this method
699  }
700 
701  // highlight
702  deleteHighlight();
703  mHighlight = new QgsHighlight( mCanvas, f, mReferencedLayer );
704  QgsIdentifyMenu::styleHighlight( mHighlight );
705  mHighlight->show();
706 
707  QTimer *timer = new QTimer( this );
708  timer->setSingleShot( true );
709  connect( timer, &QTimer::timeout, this, &QgsRelationReferenceWidget::deleteHighlight );
710  timer->start( 3000 );
711 }
712 
713 void QgsRelationReferenceWidget::deleteHighlight()
714 {
715  if ( mHighlight )
716  {
717  mHighlight->hide();
718  delete mHighlight;
719  }
720  mHighlight = nullptr;
721 }
722 
724 {
725  if ( !mAllowMapIdentification || !mReferencedLayer )
726  return;
727 
728  const QgsVectorLayerTools *tools = mEditorContext.vectorLayerTools();
729  if ( !tools )
730  return;
731  if ( !mCanvas )
732  return;
733 
734  mMapToolIdentify->setLayer( mReferencedLayer );
735  setMapTool( mMapToolIdentify );
736 
737  connect( mMapToolIdentify, qgis::overload<const QgsFeature &>::of( &QgsMapToolIdentifyFeature::featureIdentified ), this, &QgsRelationReferenceWidget::featureIdentified );
738 
739  if ( mMessageBar )
740  {
741  QString title = tr( "Relation %1 for %2." ).arg( mRelation.name(), mReferencingLayer->name() );
742  QString msg = tr( "Identify a feature of %1 to be associated. Press &lt;ESC&gt; to cancel." ).arg( mReferencedLayer->name() );
743  mMessageBarItem = QgsMessageBar::createMessage( title, msg, this );
744  mMessageBar->pushItem( mMessageBarItem );
745  }
746 }
747 
748 void QgsRelationReferenceWidget::comboReferenceChanged( int index )
749 {
750  Q_UNUSED( index )
751  mReferencedLayer->getFeatures( mComboBox->currentFeatureRequest() ).nextFeature( mFeature );
752  highlightFeature( mFeature );
753  updateAttributeEditorFrame( mFeature );
754 
755  emitForeignKeysChanged( mComboBox->identifierValues() );
756 }
757 
758 void QgsRelationReferenceWidget::updateAttributeEditorFrame( const QgsFeature &feature )
759 {
760  mOpenFormButton->setEnabled( feature.isValid() );
761  // Check if we're running with an embedded frame we need to update
762  if ( mAttributeEditorFrame && mReferencedAttributeForm )
763  {
764  mReferencedAttributeForm->setFeature( feature );
765  }
766 }
767 
769 {
770  return mAllowAddFeatures;
771 }
772 
774 {
775  mAllowAddFeatures = allowAddFeatures;
776  updateAddEntryButton();
777 }
778 
780 {
781  return mRelation;
782 }
783 
784 void QgsRelationReferenceWidget::featureIdentified( const QgsFeature &feature )
785 {
786  if ( mReadOnlySelector )
787  {
788  QgsExpression expr( mReferencedLayer->displayExpression() );
790  context.setFeature( feature );
791  QString title = expr.evaluate( &context ).toString();
792  if ( expr.hasEvalError() )
793  {
794  QStringList titleFields;
795  for ( const QString &fieldName : qgis::as_const( mReferencedFields ) )
796  titleFields << mFeature.attribute( fieldName ).toString();
797  title = titleFields.join( QStringLiteral( " " ) );
798  }
799  mLineEdit->setText( title );
800  mForeignKeys.clear();
801  mFeature = feature;
802  for ( const QString &fieldName : qgis::as_const( mReferencedFields ) )
803  mForeignKeys << mFeature.attribute( fieldName );
804  }
805  else
806  {
807  mComboBox->setCurrentFeature( feature );
808  mFeature = feature;
809  }
810 
811  mRemoveFKButton->setEnabled( mIsEditable );
812  highlightFeature( feature );
813  updateAttributeEditorFrame( feature );
814  emitForeignKeysChanged( foreignKeys(), true );
815 
816  unsetMapTool();
817 }
818 
819 void QgsRelationReferenceWidget::setMapTool( QgsMapTool *mapTool )
820 {
821  mCurrentMapTool = mapTool;
822  mCanvas->setMapTool( mapTool );
823 
824  mWindowWidget = window();
825 
826  mCanvas->window()->raise();
827  mCanvas->activateWindow();
828  mCanvas->setFocus();
829  connect( mapTool, &QgsMapTool::deactivated, this, &QgsRelationReferenceWidget::mapToolDeactivated );
830 }
831 
832 void QgsRelationReferenceWidget::unsetMapTool()
833 {
834  // deactivate map tools if activated
835  if ( mCurrentMapTool )
836  {
837  /* this will call mapToolDeactivated */
838  mCanvas->unsetMapTool( mCurrentMapTool );
839 
840  if ( mCurrentMapTool == mMapToolDigitize )
841  {
842  disconnect( mCanvas, &QgsMapCanvas::keyPressed, this, &QgsRelationReferenceWidget::onKeyPressed );
843  disconnect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsRelationReferenceWidget::entryAdded );
844  }
845  else
846  {
847  disconnect( mMapToolIdentify, qgis::overload<const QgsFeature &>::of( &QgsMapToolIdentifyFeature::featureIdentified ), this, &QgsRelationReferenceWidget::featureIdentified );
848  }
849  }
850 }
851 
852 void QgsRelationReferenceWidget::onKeyPressed( QKeyEvent *e )
853 {
854  if ( e->key() == Qt::Key_Escape )
855  {
856  unsetMapTool();
857  }
858 }
859 
860 void QgsRelationReferenceWidget::mapToolDeactivated()
861 {
862  if ( mWindowWidget )
863  {
864  mWindowWidget->raise();
865  mWindowWidget->activateWindow();
866  }
867 
868  if ( mMessageBar && mMessageBarItem )
869  {
870  mMessageBar->popWidget( mMessageBarItem );
871  }
872  mMessageBarItem = nullptr;
873 }
874 
875 void QgsRelationReferenceWidget::filterChanged()
876 {
877  QVariant nullValue = QgsApplication::nullRepresentation();
878 
879  QMap<QString, QString> filters;
880  QgsAttributeList attrs;
881 
882  QComboBox *scb = qobject_cast<QComboBox *>( sender() );
883 
884  Q_ASSERT( scb );
885 
886  QgsFeature f;
887  QgsFeatureIds featureIds;
888  QString filterExpression;
889 
890  // comboboxes have to be disabled before building filters
891  if ( mChainFilters )
892  disableChainedComboBoxes( scb );
893 
894  // build filters
895  const auto constMFilterComboBoxes = mFilterComboBoxes;
896  for ( QComboBox *cb : constMFilterComboBoxes )
897  {
898  if ( cb->currentIndex() != 0 )
899  {
900  const QString fieldName = cb->property( "Field" ).toString();
901 
902  if ( cb->currentText() == nullValue.toString() )
903  {
904  filters[fieldName] = QStringLiteral( "\"%1\" IS NULL" ).arg( fieldName );
905  }
906  else
907  {
908  filters[fieldName] = QgsExpression::createFieldEqualityExpression( fieldName, cb->currentText() );
909  }
910  attrs << mReferencedLayer->fields().lookupField( fieldName );
911  }
912  }
913 
914  if ( mChainFilters )
915  {
916  QComboBox *ccb = nullptr;
917  const auto constMFilterComboBoxes = mFilterComboBoxes;
918  for ( QComboBox *cb : constMFilterComboBoxes )
919  {
920  if ( !ccb )
921  {
922  if ( cb == scb )
923  ccb = cb;
924 
925  continue;
926  }
927 
928  if ( ccb->currentIndex() != 0 )
929  {
930  const QString fieldName = cb->property( "Field" ).toString();
931 
932  cb->blockSignals( true );
933  cb->clear();
934  cb->addItem( cb->property( "FieldAlias" ).toString() );
935 
936  // ccb = scb
937  // cb = scb + 1
938  QStringList texts;
939  const auto txts { mFilterCache[ccb->property( "Field" ).toString()][ccb->currentText()] };
940  for ( const QString &txt : txts )
941  {
942  QMap<QString, QString> filtersAttrs = filters;
943  filtersAttrs[fieldName] = QgsExpression::createFieldEqualityExpression( fieldName, txt );
944  QString expression = filtersAttrs.values().join( QStringLiteral( " AND " ) );
945 
946  QgsAttributeList subset = attrs;
947  subset << mReferencedLayer->fields().lookupField( fieldName );
948 
949  QgsFeatureIterator it( mReferencedLayer->getFeatures( QgsFeatureRequest().setFilterExpression( expression ).setSubsetOfAttributes( subset ) ) );
950 
951  bool found = false;
952  while ( it.nextFeature( f ) )
953  {
954  if ( !featureIds.contains( f.id() ) )
955  featureIds << f.id();
956 
957  found = true;
958  }
959 
960  // item is only provided if at least 1 feature exists
961  if ( found )
962  texts << txt;
963  }
964 
965  texts.sort();
966  cb->addItems( texts );
967 
968  cb->setEnabled( true );
969  cb->blockSignals( false );
970 
971  ccb = cb;
972  }
973  }
974  }
975  filterExpression = filters.values().join( QStringLiteral( " AND " ) );
976  mComboBox->setFilterExpression( filterExpression );
977 }
978 
979 void QgsRelationReferenceWidget::addEntry()
980 {
981  if ( !mReferencedLayer )
982  return;
983 
984  const QgsVectorLayerTools *tools = mEditorContext.vectorLayerTools();
985  if ( !tools )
986  return;
987  if ( !mCanvas )
988  return;
989 
990  // no geometry, skip the digitizing
991  if ( mReferencedLayer->geometryType() == QgsWkbTypes::UnknownGeometry || mReferencedLayer->geometryType() == QgsWkbTypes::NullGeometry )
992  {
993  QgsFeature f( mReferencedLayer->fields() );
994  entryAdded( f );
995  return;
996  }
997 
998  mMapToolDigitize->setLayer( mReferencedLayer );
999  setMapTool( mMapToolDigitize );
1000 
1001  connect( mMapToolDigitize, &QgsMapToolDigitizeFeature::digitizingCompleted, this, &QgsRelationReferenceWidget::entryAdded );
1002  connect( mCanvas, &QgsMapCanvas::keyPressed, this, &QgsRelationReferenceWidget::onKeyPressed );
1003 
1004  if ( mMessageBar )
1005  {
1006  QString title = tr( "Relation %1 for %2." ).arg( mRelation.name(), mReferencingLayer->name() );
1007 
1008  QString displayString = QgsVectorLayerUtils::getFeatureDisplayString( mReferencingLayer, mFormFeature );
1009  QString msg = tr( "Link feature to %1 \"%2\" : Digitize the geometry for the new feature on layer %3. Press &lt;ESC&gt; to cancel." )
1010  .arg( mReferencingLayer->name(), displayString, mReferencedLayer->name() );
1011  mMessageBarItem = QgsMessageBar::createMessage( title, msg, this );
1012  mMessageBar->pushItem( mMessageBarItem );
1013  }
1014 
1015 }
1016 
1017 void QgsRelationReferenceWidget::entryAdded( const QgsFeature &feat )
1018 {
1019  QgsFeature f( feat );
1020  QgsAttributeMap attributes;
1021 
1022  // if custom text is in the combobox and the displayExpression is simply a field, use the current text for the new feature
1023  if ( mComboBox->itemText( mComboBox->currentIndex() ) != mComboBox->currentText() )
1024  {
1025  int fieldIdx = mReferencedLayer->fields().lookupField( mReferencedLayer->displayExpression() );
1026 
1027  if ( fieldIdx != -1 )
1028  {
1029  attributes.insert( fieldIdx, mComboBox->currentText() );
1030  }
1031  }
1032 
1033  if ( mEditorContext.vectorLayerTools()->addFeature( mReferencedLayer, attributes, f.geometry(), &f ) )
1034  {
1035  QVariantList attrs;
1036  for ( const QString &fieldName : qgis::as_const( mReferencedFields ) )
1037  attrs << f.attribute( fieldName );
1038 
1039  mComboBox->setIdentifierValues( attrs );
1040 
1041  mAddEntryButton->setEnabled( false );
1042  }
1043 
1044  unsetMapTool();
1045 }
1046 
1047 void QgsRelationReferenceWidget::updateAddEntryButton()
1048 {
1049  mAddEntryButton->setVisible( mAllowAddFeatures && mMapToolDigitize );
1050  mAddEntryButton->setEnabled( mReferencedLayer && mReferencedLayer->isEditable() );
1051 }
1052 
1053 void QgsRelationReferenceWidget::disableChainedComboBoxes( const QComboBox *scb )
1054 {
1055  QComboBox *ccb = nullptr;
1056  const auto constMFilterComboBoxes = mFilterComboBoxes;
1057  for ( QComboBox *cb : constMFilterComboBoxes )
1058  {
1059  if ( !ccb )
1060  {
1061  if ( cb == scb )
1062  {
1063  ccb = cb;
1064  }
1065 
1066  continue;
1067  }
1068 
1069  cb->setCurrentIndex( 0 );
1070  if ( ccb->currentIndex() == 0 )
1071  {
1072  cb->setEnabled( false );
1073  }
1074 
1075  ccb = cb;
1076  }
1077 }
1078 
1079 void QgsRelationReferenceWidget::emitForeignKeysChanged( const QVariantList &foreignKeys, bool force )
1080 {
1081  if ( foreignKeys == mForeignKeys && force == false )
1082  return;
1083 
1084  mForeignKeys = foreignKeys;
1086  emit foreignKeyChanged( foreignKeys.at( 0 ) );
1089 }
1090 
1092 {
1093  return mReferencedLayerName;
1094 }
1095 
1096 void QgsRelationReferenceWidget::setReferencedLayerName( const QString &relationLayerName )
1097 {
1098  mReferencedLayerName = relationLayerName;
1099 }
1100 
1102 {
1103  return mReferencedLayerId;
1104 }
1105 
1106 void QgsRelationReferenceWidget::setReferencedLayerId( const QString &relationLayerId )
1107 {
1108  mReferencedLayerId = relationLayerId;
1109 }
1110 
1112 {
1113  return mReferencedLayerProviderKey;
1114 }
1115 
1116 void QgsRelationReferenceWidget::setReferencedLayerProviderKey( const QString &relationProviderKey )
1117 {
1118  mReferencedLayerProviderKey = relationProviderKey;
1119 }
1120 
1122 {
1123  return mReferencedLayerDataSource;
1124 }
1125 
1126 void QgsRelationReferenceWidget::setReferencedLayerDataSource( const QString &relationDataSource )
1127 {
1128  const QgsPathResolver resolver { QgsProject::instance()->pathResolver() };
1129  mReferencedLayerDataSource = resolver.writePath( relationDataSource );
1130 }
1131 
1133 {
1134  mFormFeature = formFeature;
1135 }
void unsetMapTool(QgsMapTool *mapTool)
Unset the current map tool or last non zoom tool.
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:324
Methods in this class are used to handle basic operations on vector layers.
void setEditorContext(const QgsAttributeEditorContext &context, QgsMapCanvas *canvas, QgsMessageBar *messageBar)
Sets the editor context.
When showing a single feature (e.g. district information when looking at the form of a house) ...
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:183
Class for parsing and evaluation of expressions (formerly called "search strings").
const QgsVectorLayerTools * vectorLayerTools() const
Returns the associated vector layer tools.
QString name
Definition: qgsrelation.h:48
QgsFeatureId id
Definition: qgsfeature.h:64
Q_DECL_DEPRECATED QVariant foreignKey() const
returns the related feature foreign key
Wrapper for iterator of features from vector data provider or vector layer.
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
Definition: qgsrectangle.h:342
This offers a combobox with autocompleter that allows selecting features from a layer.
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsFeatureRequest currentFeatureRequest() const
Shorthand for getting a feature request to query the currently selected feature.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
int nullIndex() const
Returns the current index of the NULL value, or -1 if NULL values are not allowed.
void setIdentifierValues(const QVariantList &identifierValues)
The identifier values of the currently selected feature.
QVariantList foreignKeys() const
returns the related feature foreign key
void setLayer(QgsVectorLayer *vl)
change the layer used by the map tool to identify
QgsFeature referencedFeature() const
Returns the related feature (from the referenced layer) if no feature is related, it returns an inval...
bool chainFilters() const
Determines if the filters are chained.
A groupbox that collapses/expands when toggled and can save its collapsed and checked states...
void setFormFeature(const QgsFeature &formFeature)
Set the current form feature (from the referencing layer)
void setFilterFields(const QStringList &filterFields)
Sets the fields for which filter comboboxes will be created.
void setReferencedLayerId(const QString &referencedLayerId)
Set the id of the referenced layer to referencedLayerId.
This class contains context information for attribute editor widgets.
A class to represent a 2D point.
Definition: qgspointxy.h:43
void scale(double scaleFactor, const QgsPointXY *c=nullptr)
Scale the rectangle around its center point.
Definition: qgsrectangle.h:235
void setOpenFormButtonVisible(bool openFormButtonVisible)
void setIdentifierFields(const QStringList &identifierFields)
Field name that will be used to uniquely identify the current feature.
QString providerType() const
Returns the provider type (provider key) for this layer.
QgsVectorLayer referencingLayer
Definition: qgsrelation.h:46
void digitizingCompleted(const QgsFeature &feature)
Emitted whenever the digitizing has been successfully completed.
QString referencedLayerDataSource() const
Returns the public data source of the referenced layer.
void setReferencedLayerProviderKey(const QString &referencedLayerProviderKey)
Set the data provider key of the referenced layer to referencedLayerProviderKey.
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:731
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:45
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QgsRelation relation() const
Returns the current relation, which might be invalid.
bool allowAddFeatures() const
Determines if a button for adding new features should be shown.
void refresh()
Repaints the canvas map.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:122
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
QgsGeometry centroid() const
Returns the center of mass of a geometry.
void setReferencedLayerDataSource(const QString &referencedLayerDataSource)
Set the public data source of the referenced layer to referencedLayerDataSource.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
bool orderByValue()
If the widget will order the combobox entries by value.
void setSourceLayer(QgsVectorLayer *sourceLayer)
The layer from which features should be listed.
static QString getFeatureDisplayString(const QgsVectorLayer *layer, const QgsFeature &feature)
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:197
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:75
void reset(T *p=nullptr)
Will reset the managed pointer to p.
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
Definition: qgis.cpp:121
void setAllowMapIdentification(bool allowMapIdentification)
bool allowMapIdentification()
determines if the widget offers the possibility to select the related feature on the map (using a ded...
void setButton(QAbstractButton *button)
Use this to associate a button to this maptool.
Definition: qgsmaptool.cpp:139
Q_DECL_DEPRECATED void setForeignKey(const QVariant &value)
this sets the related feature using from the foreign key
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
void setOrderByValue(bool orderByValue)
Sets if the widget will order the combobox entries by value.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
QgsFeatureRequest & setFilterFid(QgsFeatureId fid)
Sets feature ID that should be fetched.
static QgsMessageBarItem * createMessage(const QString &text, QWidget *parent=nullptr)
make out a widget containing a message to be displayed on the bar
void setMapTool(QgsMapTool *mapTool, bool clean=false)
Sets the map tool currently being used on the canvas.
QgsFeatureRequest getReferencedFeatureRequest(const QgsAttributes &attributes) const
Creates a request to return the feature on the referenced (parent) layer which is referenced by the p...
QgsFields fields() const FINAL
Returns the list of fields of this layer.
void setLayer(QgsMapLayer *vl)
Change the layer edited by the map tool.
Defines a relation between matching fields of the two involved tables of a relation.
Definition: qgsrelation.h:74
void setIdentifierValuesToNull()
Sets the identifier values of the currently selected feature to NULL value(s).
QgsPathResolver pathResolver() const
Returns path resolver object with considering whether the project uses absolute or relative paths and...
void setFeature(const QgsFeature &feature)
Update all editors to correspond to a different feature.
bool popWidget(QgsMessageBarItem *item)
Remove the passed widget from the bar (if previously added), then display the next one in the stack i...
void setAllowNull(bool allowNull)
Determines if a NULL value should be available in the list.
void showEvent(QShowEvent *e) override
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
void editingStopped()
Emitted when edited changes have been successfully written to the data provider.
A class for highlight features on the map.
Definition: qgshighlight.h:56
This class wraps a request for features to a vector layer (or directly its vector data provider)...
static QString nullRepresentation()
This string is used to represent the value NULL throughout QGIS.
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example...
QString referencedLayerName() const
Returns the name of the referenced layer.
QgsVectorLayer referencedLayer
Definition: qgsrelation.h:47
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
void setRelation(const QgsRelation &relation, bool allowNullValue)
void editingStarted()
Emitted when editing on this layer has started.
static QString createFieldEqualityExpression(const QString &fieldName, const QVariant &value)
Create an expression allowing to evaluate if a field is equal to a value.
QString displayExpression
void keyPressed(QKeyEvent *e)
Emit key press event.
QgsAdvancedDigitizingDockWidget * cadDockWidget() const
Returns the associated CAD dock widget (e.g.
void zoomByFactor(double scaleFactor, const QgsPointXY *center=nullptr)
Zoom with the factor supplied.
QList< QgsRelation::FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
void setReferencedLayerName(const QString &referencedLayerName)
Set the name of the referenced layer to referencedLayerName.
void setCurrentFeature(const QgsFeature &feature)
Sets the current index by using the given feature.
bool qVariantListIsNull(const QVariantList &list)
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle...
Definition: qgsrectangle.h:359
Abstract base class for all map tools.
Definition: qgsmaptool.h:62
The QgsMapToolIdentifyFeature class is a map tool to identify a feature on a chosen layer...
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:732
void setFilterExpression(const QString &filterExpression)
An additional expression to further restrict the available features.
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:188
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:262
void deactivated()
signal emitted once the map tool is deactivated
void pushItem(QgsMessageBarItem *item)
Display a message item on the bar after hiding the currently visible one and putting it in a stack...
bool isValid
Definition: qgsrelation.h:49
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
void featureIdentified(const QgsFeature &)
QgsPointXY layerToMapCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from layer&#39;s CRS to output CRS
void setAllowAddFeatures(bool allowAddFeatures)
Determines if a button for adding new features should be shown.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:450
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
void showIndeterminateState()
Sets the widget to display in an indeterminate "mixed value" state.
QString referencedLayerId() const
Returns the id of the referenced layer.
void setForeignKeys(const QVariantList &values)
Sets the related feature using the foreign keys.
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.
This tool digitizes geometry of new point/line/polygon features on already existing vector layers Onc...
void setExtent(const QgsRectangle &r, bool magnified=false)
Sets the extent of the map canvas.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QString name
Definition: qgsmaplayer.h:83
static void styleHighlight(QgsHighlight *highlight)
Applies style from the settings to the highlight.
QgsGeometry geometry
Definition: qgsfeature.h:67
QList< int > QgsAttributeList
Definition: qgsfield.h:26
void foreignKeysChanged(const QVariantList &)
Emitted when the foreign keys changed.
bool nextFeature(QgsFeature &f)
QString referencedLayerProviderKey() const
Returns the data provider key of the referenced layer.
Resolves relative paths into absolute paths and vice versa.
A vector of attributes.
Definition: qgsattributes.h:57
Q_DECL_DEPRECATED void foreignKeyChanged(const QVariant &)
Emitted when the foreign key changed.
void setDisplayExpression(const QString &displayExpression)
The display expression will be used to display features as well as the value to match the typed text ...
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
QString referencedLayerId() const
Access the referenced (parent) layer&#39;s id.
void mapIdentification()
activate the map tool to select a new related feature on the map
QString attributeDisplayName(int index) const
Convenience function that returns the attribute alias if defined or the field name else...
void modelUpdated()
The underlying model has been updated.
QVariant::Type type
Definition: qgsfield.h:57
bool openFormButtonVisible()
determines the open form button is visible in the widget
void openForm()
open the form of the related feature in a new dialog
void setChainFilters(bool chainFilters)
Set if filters are chained.
A form was embedded as a widget on another form.
void deleteForeignKeys()
unset the currently related feature