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