QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsrelationreferencewidgetwrapper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrelationreferencewidgetwrapper.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 
16 
18 #include "qgsproject.h"
19 #include "qgsrelationmanager.h"
21 #include "qgsattributeform.h"
22 
23 QgsRelationReferenceWidgetWrapper::QgsRelationReferenceWidgetWrapper( QgsVectorLayer *vl, int fieldIdx, QWidget *editor, QgsMapCanvas *canvas, QgsMessageBar *messageBar, QWidget *parent )
24  : QgsEditorWidgetWrapper( vl, fieldIdx, editor, parent )
25  , mCanvas( canvas )
26  , mMessageBar( messageBar )
27  , mIndeterminateState( false )
28 {
29 }
30 
32 {
34  return w;
35 }
36 
38 {
39  QgsRelationReferenceWidget *w = qobject_cast<QgsRelationReferenceWidget *>( editor );
40  if ( !w )
41  {
42  w = new QgsRelationReferenceWidget( editor );
43  }
44 
45  mWidget = w;
46 
47  const QgsAttributeEditorContext *ctx = &context();
48 
49  mWidget->setEditorContext( *ctx, mCanvas, mMessageBar );
50 
51  const bool showForm = config( QStringLiteral( "ShowForm" ), false ).toBool();
52  const bool mapIdent = config( QStringLiteral( "MapIdentification" ), false ).toBool();
53  const bool readOnlyWidget = config( QStringLiteral( "ReadOnly" ), false ).toBool();
54  const bool orderByValue = config( QStringLiteral( "OrderByValue" ), false ).toBool();
55  const bool showOpenFormButton = config( QStringLiteral( "ShowOpenFormButton" ), true ).toBool();
56 
57  mWidget->setEmbedForm( showForm );
58  mWidget->setReadOnlySelector( readOnlyWidget );
59  mWidget->setAllowMapIdentification( mapIdent );
60  mWidget->setOrderByValue( orderByValue );
61  mWidget->setOpenFormButtonVisible( showOpenFormButton );
62  if ( config( QStringLiteral( "FilterFields" ), QVariant() ).isValid() )
63  {
64  mWidget->setFilterFields( config( QStringLiteral( "FilterFields" ) ).toStringList() );
65  mWidget->setChainFilters( config( QStringLiteral( "ChainFilters" ) ).toBool() );
66  }
67  if ( !config( QStringLiteral( "FilterExpression" ) ).toString().isEmpty() )
68  {
69  mWidget->setFilterExpression( config( QStringLiteral( "FilterExpression" ) ).toString() );
70  }
71  mWidget->setAllowAddFeatures( config( QStringLiteral( "AllowAddFeatures" ), false ).toBool() );
72 
73  const QVariant relationName = config( QStringLiteral( "Relation" ) );
74 
75  // Store relation data source and provider key
76  mWidget->setReferencedLayerDataSource( config( QStringLiteral( "ReferencedLayerDataSource" ) ).toString() );
77  mWidget->setReferencedLayerProviderKey( config( QStringLiteral( "ReferencedLayerProviderKey" ) ).toString() );
78  mWidget->setReferencedLayerId( config( QStringLiteral( "ReferencedLayerId" ) ).toString() );
79  mWidget->setReferencedLayerName( config( QStringLiteral( "ReferencedLayerName" ) ).toString() );
80 
81  QgsRelation relation; // invalid relation by default
82  if ( relationName.isValid() )
83  relation = QgsProject::instance()->relationManager()->relation( relationName.toString() );
84  if ( !relation.isValid() && !layer()->referencingRelations( fieldIdx() ).isEmpty() )
85  relation = layer()->referencingRelations( fieldIdx() )[0];
86 
87  // If this widget is already embedded by the same relation, reduce functionality
88  do
89  {
90  if ( ctx->relation().id() == relation.id() )
91  {
92  mWidget->setEmbedForm( false );
93  mWidget->setReadOnlySelector( true );
94  mWidget->setAllowMapIdentification( false );
95  mWidget->setOpenFormButtonVisible( false );
96  mWidget->setAllowAddFeatures( false );
97  break;
98  }
99  ctx = ctx->parentContext();
100  }
101  while ( ctx );
102 
103  mWidget->setRelation( relation, config( QStringLiteral( "AllowNULL" ) ).toBool() );
104 
105  connect( mWidget, &QgsRelationReferenceWidget::foreignKeysChanged, this, &QgsRelationReferenceWidgetWrapper::foreignKeysChanged );
106 }
107 
109 {
110  if ( !mWidget )
111  return QVariant( field().type() );
112 
113  const QVariantList fkeys = mWidget->foreignKeys();
114 
115  if ( fkeys.isEmpty() )
116  {
117  return QVariant( field().type() );
118  }
119  else
120  {
121  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
122  Q_ASSERT( fieldPairs.count() == fkeys.count() );
123  for ( int i = 0; i < fieldPairs.count(); i++ )
124  {
125  if ( fieldPairs.at( i ).referencingField() == field().name() )
126  return fkeys.at( i );
127  }
128  return QVariant( field().type() ); // should not happen
129  }
130 }
131 
133 {
134  return mWidget;
135 }
136 
138 {
139  if ( mWidget )
140  {
141  mWidget->showIndeterminateState();
142  }
143  mIndeterminateState = true;
144 }
145 
147 {
148  if ( !mWidget || !mWidget->relation().isValid() )
149  {
150  QVariantList values;
151  for ( int i = 0; i < mWidget->relation().fieldPairs().count(); i++ )
152  {
153  values << QVariant();
154  }
155  return values;
156  }
157  else
158  {
159  QVariantList values = mWidget->foreignKeys();
160  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
161  const int fieldCount = std::min( fieldPairs.count(), values.count() );
162  for ( int i = 0; i < fieldCount; i++ )
163  {
164  if ( fieldPairs.at( i ).referencingField() == field().name() )
165  {
166  values.removeAt( i );
167  break;
168  }
169  }
170  return values;
171  }
172 }
173 
175 {
176  if ( !mWidget || !mWidget->relation().isValid() )
177  return QStringList();
178 
179  QStringList fields;
180  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
181  for ( int i = 0; i < fieldPairs.count(); i++ )
182  {
183  if ( fieldPairs.at( i ).referencingField() == field().name() )
184  continue;
185 
186  fields << fieldPairs.at( i ).referencingField();
187  }
188  return fields;
189 }
190 
191 void QgsRelationReferenceWidgetWrapper::updateValues( const QVariant &val, const QVariantList &additionalValues )
192 {
193  if ( !mWidget || ( !mIndeterminateState && val == value() && val.isNull() == value().isNull() ) )
194  return;
195 
196  mIndeterminateState = false;
197 
198  QVariantList values = additionalValues;
199  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
200  for ( int i = 0; i < fieldPairs.count(); i++ )
201  {
202  if ( fieldPairs.at( i ).referencingField() == field().name() )
203  {
204  values.insert( i, val );
205  break;
206  }
207  }
208  Q_ASSERT( values.count() == fieldPairs.count() );
209 
210  mBlockChanges++;
211  mWidget->setForeignKeys( values );
212  mWidget->setFormFeature( formFeature() );
213  mBlockChanges--;
214 }
215 
217 {
218  if ( !mWidget )
219  return;
220 
221  mWidget->setRelationEditable( enabled );
222 }
223 
224 void QgsRelationReferenceWidgetWrapper::foreignKeysChanged( const QVariantList &values )
225 {
226  if ( mBlockChanges != 0 ) // initial value is being set, we can ignore this signal
227  return;
228 
229  QVariant mainValue = QVariant( field().type() );
230 
231  if ( !mWidget || !mWidget->relation().isValid() )
232  {
234  emit valueChanged( mainValue );
236  emit valuesChanged( mainValue );
237  return;
238  }
239 
240  QVariantList additionalValues = values;
241  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
242  for ( int i = 0; i < fieldPairs.count(); i++ )
243  {
244  if ( fieldPairs.at( i ).referencingField() == field().name() )
245  mainValue = additionalValues.takeAt( i ); // additional values in field pair order remain
246  }
247  Q_ASSERT( additionalValues.count() == values.count() - 1 );
248 
250  emit valueChanged( mainValue );
252  emit valuesChanged( mainValue, additionalValues );
253 }
254 
256 {
257  if ( mWidget )
258  {
259  if ( !constraintResultVisible() )
260  {
261  widget()->setStyleSheet( QString() );
262  }
263  else
264  {
265  switch ( constraintResult() )
266  {
268  mWidget->setStyleSheet( QString() );
269  break;
270 
272  mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #dd7777; }" ) );
273  break;
274 
276  mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #ffd85d; }" ) );
277  break;
278  }
279  }
280  }
281 }
QgsRelationReferenceWidget
Definition: qgsrelationreferencewidget.h:57
QgsProject::relationManager
QgsRelationManager relationManager
Definition: qgsproject.h:114
QgsRelationReferenceWidgetWrapper::initWidget
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
Definition: qgsrelationreferencewidgetwrapper.cpp:37
qgsattributeform.h
QgsEditorWidgetWrapper::ConstraintResultFailHard
@ ConstraintResultFailHard
Widget failed at least one hard (enforced) constraint.
Definition: qgseditorwidgetwrapper.h:63
QgsRelationReferenceWidget::setFilterFields
void setFilterFields(const QStringList &filterFields)
Sets the fields for which filter comboboxes will be created.
Definition: qgsrelationreferencewidget.cpp:381
QgsRelationReferenceWidget::showIndeterminateState
void showIndeterminateState()
Sets the widget to display in an indeterminate "mixed value" state.
Definition: qgsrelationreferencewidget.cpp:312
QgsMapCanvas
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:89
QgsRelationReferenceWidgetWrapper::updateConstraintWidgetStatus
void updateConstraintWidgetStatus() override
This should update the widget with a visual cue if a constraint status changed.
Definition: qgsrelationreferencewidgetwrapper.cpp:255
QgsRelationReferenceWidget::setReferencedLayerProviderKey
void setReferencedLayerProviderKey(const QString &referencedLayerProviderKey)
Set the data provider key of the referenced layer to referencedLayerProviderKey.
Definition: qgsrelationreferencewidget.cpp:994
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:480
QgsRelationManager::relation
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
Definition: qgsrelationmanager.cpp:95
QgsRelationReferenceWidget::setRelationEditable
void setRelationEditable(bool editable)
Definition: qgsrelationreferencewidget.cpp:224
QgsRelationReferenceWidgetWrapper::value
QVariant value() const override
Will be used to access the widget's value.
Definition: qgsrelationreferencewidgetwrapper.cpp:108
QgsRelationReferenceWidgetWrapper::valid
bool valid() const override
Returns true if the widget has been properly initialized.
Definition: qgsrelationreferencewidgetwrapper.cpp:132
QgsWidgetWrapper::context
const QgsAttributeEditorContext & context() const
Returns information about the context in which this widget is shown.
Definition: qgswidgetwrapper.cpp:87
QgsEditorWidgetWrapper::constraintResultVisible
bool constraintResultVisible
Definition: qgseditorwidgetwrapper.h:51
QgsRelationReferenceWidget::setReferencedLayerName
void setReferencedLayerName(const QString &referencedLayerName)
Set the name of the referenced layer to referencedLayerName.
Definition: qgsrelationreferencewidget.cpp:974
QgsRelationReferenceWidget::setForeignKeys
void setForeignKeys(const QVariantList &values)
Sets the related feature using the foreign keys.
Definition: qgsrelationreferencewidget.cpp:244
QgsWidgetWrapper::widget
QWidget * widget()
Access the widget managed by this wrapper.
Definition: qgswidgetwrapper.cpp:47
QgsEditorWidgetWrapper
Manages an editor widget Widget and wrapper share the same parent.
Definition: qgseditorwidgetwrapper.h:47
QgsAttributeEditorContext::relation
const QgsRelation & relation() const
Returns the attribute relation.
Definition: qgsattributeeditorcontext.h:190
QgsEditorWidgetWrapper::fieldIdx
int fieldIdx() const
Access the field index.
Definition: qgseditorwidgetwrapper.cpp:34
QgsRelation::id
QString id
Definition: qgsrelation.h:46
QgsEditorWidgetWrapper::valueChanged
Q_DECL_DEPRECATED void valueChanged(const QVariant &value)
Emit this signal, whenever the value changed.
Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2820
QgsRelationReferenceWidget::setAllowMapIdentification
void setAllowMapIdentification(bool allowMapIdentification)
Definition: qgsrelationreferencewidget.cpp:369
QgsEditorWidgetWrapper::ConstraintResultPass
@ ConstraintResultPass
Widget passed constraints successfully.
Definition: qgseditorwidgetwrapper.h:62
QgsRelationReferenceWidgetWrapper::showIndeterminateState
void showIndeterminateState() override
Sets the widget to display in an indeterminate "mixed value" state.
Definition: qgsrelationreferencewidgetwrapper.cpp:137
QgsRelationReferenceWidget::setAllowAddFeatures
void setAllowAddFeatures(bool allowAddFeatures)
Determines if a button for adding new features should be shown.
Definition: qgsrelationreferencewidget.cpp:655
QgsWidgetWrapper::layer
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
Definition: qgswidgetwrapper.cpp:92
QgsRelationReferenceWidget::setEditorContext
void setEditorContext(const QgsAttributeEditorContext &context, QgsMapCanvas *canvas, QgsMessageBar *messageBar)
Sets the editor context.
Definition: qgsrelationreferencewidget.cpp:333
QgsRelationReferenceWidget::foreignKeysChanged
void foreignKeysChanged(const QVariantList &)
Emitted when the foreign keys changed.
QgsRelationReferenceWidget::setEmbedForm
void setEmbedForm(bool display)
Definition: qgsrelationreferencewidget.cpp:350
QgsRelationReferenceWidget::setReferencedLayerDataSource
void setReferencedLayerDataSource(const QString &referencedLayerDataSource)
Set the public data source of the referenced layer to referencedLayerDataSource.
Definition: qgsrelationreferencewidget.cpp:1004
QgsMessageBar
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:60
QgsVectorLayer::referencingRelations
QList< QgsRelation > referencingRelations(int idx) const
Returns the layer's relations, where the foreign key is on this layer.
Definition: qgsvectorlayer.cpp:5409
QgsRelationReferenceWidgetWrapper::additionalFieldValues
QVariantList additionalFieldValues() const override
Will be used to access the widget's values for potential additional fields handled by the widget.
Definition: qgsrelationreferencewidgetwrapper.cpp:146
QgsEditorWidgetWrapper::field
QgsField field() const
Access the field.
Definition: qgseditorwidgetwrapper.cpp:39
QgsRelationReferenceWidgetWrapper::additionalFields
QStringList additionalFields() const override
Returns the list of additional fields which the editor handles.
Definition: qgsrelationreferencewidgetwrapper.cpp:174
qgsrelationmanager.h
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:330
QgsRelationReferenceWidget::relation
QgsRelation relation() const
Returns the current relation, which might be invalid.
Definition: qgsrelationreferencewidget.cpp:661
QgsEditorWidgetWrapper::valuesChanged
void valuesChanged(const QVariant &value, const QVariantList &additionalFieldValues=QVariantList())
Emit this signal, whenever the value changed.
QgsWidgetWrapper::config
QVariantMap config() const
Returns the whole config.
Definition: qgswidgetwrapper.cpp:82
QgsRelationReferenceWidget::foreignKeys
QVariantList foreignKeys() const
returns the related feature foreign key
Definition: qgsrelationreferencewidget.cpp:328
QgsRelationReferenceWidget::setRelation
void setRelation(const QgsRelation &relation, bool allowNullValue)
Definition: qgsrelationreferencewidget.cpp:170
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsEditorWidgetWrapper::ConstraintResultFailSoft
@ ConstraintResultFailSoft
Widget failed at least one soft (non-enforced) constraint.
Definition: qgseditorwidgetwrapper.h:64
QgsRelationReferenceWidget::setChainFilters
void setChainFilters(bool chainFilters)
Set if filters are chained.
Definition: qgsrelationreferencewidget.cpp:392
QgsRelation::isValid
bool isValid
Definition: qgsrelation.h:50
QgsRelationReferenceWidget::setOrderByValue
void setOrderByValue(bool orderByValue)
Sets if the widget will order the combobox entries by value.
Definition: qgsrelationreferencewidget.cpp:376
QgsRelationReferenceWidget::setReferencedLayerId
void setReferencedLayerId(const QString &referencedLayerId)
Set the id of the referenced layer to referencedLayerId.
Definition: qgsrelationreferencewidget.cpp:984
QgsRelation
Definition: qgsrelation.h:42
QgsEditorWidgetWrapper::constraintResult
ConstraintResult constraintResult
Definition: qgseditorwidgetwrapper.h:52
QgsRelationReferenceWidgetWrapper::setEnabled
void setEnabled(bool enabled) override
Definition: qgsrelationreferencewidgetwrapper.cpp:216
qgsrelationreferencewidgetwrapper.h
QgsRelationReferenceWidget::setOpenFormButtonVisible
void setOpenFormButtonVisible(bool openFormButtonVisible)
Definition: qgsrelationreferencewidget.cpp:386
qgsrelationreferencewidget.h
QgsAttributeEditorContext::parentContext
const QgsAttributeEditorContext * parentContext() const
Definition: qgsattributeeditorcontext.h:230
QgsRelationReferenceWidget::setFilterExpression
void setFilterExpression(const QString &filterExpression)
If not empty, will be used as filter expression.
Definition: qgsrelationreferencewidget.cpp:397
QgsAttributeEditorContext
This class contains context information for attribute editor widgets. It will be passed to embedded w...
Definition: qgsattributeeditorcontext.h:40
QgsRelationReferenceWidgetWrapper::QgsRelationReferenceWidgetWrapper
QgsRelationReferenceWidgetWrapper(QgsVectorLayer *vl, int fieldIdx, QWidget *editor, QgsMapCanvas *canvas, QgsMessageBar *messageBar, QWidget *parent=nullptr)
Constructor for QgsRelationReferenceWidgetWrapper.
Definition: qgsrelationreferencewidgetwrapper.cpp:23
Q_NOWARN_DEPRECATED_PUSH
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2819
QgsRelationReferenceWidget::setReadOnlySelector
void setReadOnlySelector(bool readOnly)
Definition: qgsrelationreferencewidget.cpp:362
QgsRelationReferenceWidget::setFormFeature
void setFormFeature(const QgsFeature &formFeature)
Set the current form feature (from the referencing layer)
Definition: qgsrelationreferencewidget.cpp:1010
QgsRelationReferenceWidgetWrapper::createWidget
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
Definition: qgsrelationreferencewidgetwrapper.cpp:31
qgsproject.h
QgsEditorWidgetWrapper::formFeature
QgsFeature formFeature() const
The feature currently being edited, in its current state.
Definition: qgseditorwidgetwrapper.h:346