QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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  bool showForm = config( QStringLiteral( "ShowForm" ), false ).toBool();
52  bool mapIdent = config( QStringLiteral( "MapIdentification" ), false ).toBool();
53  bool readOnlyWidget = config( QStringLiteral( "ReadOnly" ), false ).toBool();
54  bool orderByValue = config( QStringLiteral( "OrderByValue" ), false ).toBool();
55  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  mWidget->setFilterExpression( config( QStringLiteral( "FilterExpression" ) ).toString() );
67  }
68  mWidget->setAllowAddFeatures( config( QStringLiteral( "AllowAddFeatures" ), false ).toBool() );
69 
70  const QVariant relationName = config( QStringLiteral( "Relation" ) );
71 
72  // Store relation data source and provider key
73  mWidget->setReferencedLayerDataSource( config( QStringLiteral( "ReferencedLayerDataSource" ) ).toString() );
74  mWidget->setReferencedLayerProviderKey( config( QStringLiteral( "ReferencedLayerProviderKey" ) ).toString() );
75  mWidget->setReferencedLayerId( config( QStringLiteral( "ReferencedLayerId" ) ).toString() );
76  mWidget->setReferencedLayerName( config( QStringLiteral( "ReferencedLayerName" ) ).toString() );
77 
78  QgsRelation relation; // invalid relation by default
79  if ( relationName.isValid() )
80  relation = QgsProject::instance()->relationManager()->relation( relationName.toString() );
81  if ( !relation.isValid() && !layer()->referencingRelations( fieldIdx() ).isEmpty() )
82  relation = layer()->referencingRelations( fieldIdx() )[0];
83 
84  // If this widget is already embedded by the same relation, reduce functionality
85  do
86  {
87  if ( ctx->relation().id() == relation.id() )
88  {
89  mWidget->setEmbedForm( false );
90  mWidget->setReadOnlySelector( true );
91  mWidget->setAllowMapIdentification( false );
92  mWidget->setOpenFormButtonVisible( false );
93  mWidget->setAllowAddFeatures( false );
94  break;
95  }
96  ctx = ctx->parentContext();
97  }
98  while ( ctx );
99 
100  mWidget->setRelation( relation, config( QStringLiteral( "AllowNULL" ) ).toBool() );
101 
102  connect( mWidget, &QgsRelationReferenceWidget::foreignKeysChanged, this, &QgsRelationReferenceWidgetWrapper::foreignKeysChanged );
103 }
104 
106 {
107  if ( !mWidget )
108  return QVariant( field().type() );
109 
110  const QVariantList fkeys = mWidget->foreignKeys();
111 
112  if ( fkeys.isEmpty() )
113  {
114  return QVariant( field().type() );
115  }
116  else
117  {
118  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
119  Q_ASSERT( fieldPairs.count() == fkeys.count() );
120  for ( int i = 0; i < fieldPairs.count(); i++ )
121  {
122  if ( fieldPairs.at( i ).referencingField() == field().name() )
123  return fkeys.at( i );
124  }
125  return QVariant( field().type() ); // should not happen
126  }
127 }
128 
130 {
131  return mWidget;
132 }
133 
135 {
136  if ( mWidget )
137  {
138  mWidget->showIndeterminateState();
139  }
140  mIndeterminateState = true;
141 }
142 
144 {
145  if ( !mWidget || !mWidget->relation().isValid() )
146  {
147  QVariantList values;
148  for ( int i = 0; i < mWidget->relation().fieldPairs().count(); i++ )
149  {
150  values << QVariant();
151  }
152  return values;
153  }
154  else
155  {
156  QVariantList values = mWidget->foreignKeys();
157  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
158  int fieldCount = std::min( fieldPairs.count(), values.count() );
159  for ( int i = 0; i < fieldCount; i++ )
160  {
161  if ( fieldPairs.at( i ).referencingField() == field().name() )
162  {
163  values.removeAt( i );
164  break;
165  }
166  }
167  return values;
168  }
169 }
170 
172 {
173  if ( !mWidget || !mWidget->relation().isValid() )
174  return QStringList();
175 
176  QStringList fields;
177  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
178  for ( int i = 0; i < fieldPairs.count(); i++ )
179  {
180  if ( fieldPairs.at( i ).referencingField() == field().name() )
181  continue;
182 
183  fields << fieldPairs.at( i ).referencingField();
184  }
185  return fields;
186 }
187 
188 void QgsRelationReferenceWidgetWrapper::updateValues( const QVariant &val, const QVariantList &additionalValues )
189 {
190  if ( !mWidget || ( !mIndeterminateState && val == value() && val.isNull() == value().isNull() ) )
191  return;
192 
193  mIndeterminateState = false;
194 
195  QVariantList values = additionalValues;
196  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
197  for ( int i = 0; i < fieldPairs.count(); i++ )
198  {
199  if ( fieldPairs.at( i ).referencingField() == field().name() )
200  {
201  values.insert( i, val );
202  break;
203  }
204  }
205  Q_ASSERT( values.count() == fieldPairs.count() );
206 
207  mWidget->setForeignKeys( values );
208  mWidget->setFormFeature( formFeature() );
209 }
210 
212 {
213  if ( !mWidget )
214  return;
215 
216  mWidget->setRelationEditable( enabled );
217 }
218 
219 void QgsRelationReferenceWidgetWrapper::foreignKeysChanged( const QVariantList &values )
220 {
221  QVariant mainValue = QVariant( field().type() );
222 
223  if ( !mWidget || !mWidget->relation().isValid() )
224  {
226  emit valueChanged( mainValue );
228  emit valuesChanged( mainValue );
229  return;
230  }
231 
232  QVariantList additionalValues = values;
233  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
234  for ( int i = 0; i < fieldPairs.count(); i++ )
235  {
236  if ( fieldPairs.at( i ).referencingField() == field().name() )
237  mainValue = additionalValues.takeAt( i ); // additional values in field pair order remain
238  }
239  Q_ASSERT( additionalValues.count() == values.count() - 1 );
240 
242  emit valueChanged( mainValue );
244  emit valuesChanged( mainValue, additionalValues );
245 }
246 
248 {
249  if ( mWidget )
250  {
251  if ( !constraintResultVisible() )
252  {
253  widget()->setStyleSheet( QString() );
254  }
255  else
256  {
257  switch ( constraintResult() )
258  {
260  mWidget->setStyleSheet( QString() );
261  break;
262 
264  mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #dd7777; }" ) );
265  break;
266 
268  mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #ffd85d; }" ) );
269  break;
270  }
271  }
272  }
273 }
QgsRelationReferenceWidget
Definition: qgsrelationreferencewidget.h:58
QgsProject::relationManager
QgsRelationManager * relationManager
Definition: qgsproject.h:105
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:476
QgsRelationReferenceWidget::showIndeterminateState
void showIndeterminateState()
Sets the widget to display in an indeterminate "mixed value" state.
Definition: qgsrelationreferencewidget.cpp:392
QgsEditorWidgetWrapper::constraintResult
ConstraintResult constraintResult
Definition: qgseditorwidgetwrapper.h:52
QgsMapCanvas
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:85
QgsRelationReferenceWidgetWrapper::updateConstraintWidgetStatus
void updateConstraintWidgetStatus() override
This should update the widget with a visual cue if a constraint status changed.
Definition: qgsrelationreferencewidgetwrapper.cpp:247
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
QgsRelationManager::relation
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
Definition: qgsrelationmanager.cpp:96
QgsRelation::id
Q_GADGET QString id
Definition: qgsrelation.h:45
QgsRelationReferenceWidget::setRelationEditable
void setRelationEditable(bool editable)
Definition: qgsrelationreferencewidget.cpp:230
QgsRelationReferenceWidgetWrapper::value
QVariant value() const override
Will be used to access the widget's value.
Definition: qgsrelationreferencewidgetwrapper.cpp:105
QgsRelationReferenceWidgetWrapper::valid
bool valid() const override
Returns true if the widget has been properly initialized.
Definition: qgsrelationreferencewidgetwrapper.cpp:129
QgsWidgetWrapper::context
const QgsAttributeEditorContext & context() const
Returns information about the context in which this widget is shown.
Definition: qgswidgetwrapper.cpp:86
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:1092
QgsRelationReferenceWidget::setForeignKeys
void setForeignKeys(const QVariantList &values)
Sets the related feature using the foreign keys.
Definition: qgsrelationreferencewidget.cpp:250
QgsWidgetWrapper::widget
QWidget * widget()
Access the widget managed by this wrapper.
Definition: qgswidgetwrapper.cpp:46
QgsEditorWidgetWrapper
Manages an editor widget Widget and wrapper share the same parent.
Definition: qgseditorwidgetwrapper.h:48
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
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:797
QgsRelationReferenceWidget::setAllowMapIdentification
void setAllowMapIdentification(bool allowMapIdentification)
Definition: qgsrelationreferencewidget.cpp:464
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:134
QgsRelationReferenceWidget::setAllowAddFeatures
void setAllowAddFeatures(bool allowAddFeatures)
Determines if a button for adding new features should be shown.
Definition: qgsrelationreferencewidget.cpp:751
QgsWidgetWrapper::layer
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
Definition: qgswidgetwrapper.cpp:91
QgsRelationReferenceWidget::setEditorContext
void setEditorContext(const QgsAttributeEditorContext &context, QgsMapCanvas *canvas, QgsMessageBar *messageBar)
Sets the editor context.
Definition: qgsrelationreferencewidget.cpp:427
QgsRelationReferenceWidget::foreignKeysChanged
void foreignKeysChanged(const QVariantList &)
Emitted when the foreign keys changed.
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
QgsMessageBar
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
QgsVectorLayer::referencingRelations
QList< QgsRelation > referencingRelations(int idx) const
Returns the layer's relations, where the foreign key is on this layer.
Definition: qgsvectorlayer.cpp:5177
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:143
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:171
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:292
QgsRelationReferenceWidget::relation
QgsRelation relation() const
Returns the current relation, which might be invalid.
Definition: qgsrelationreferencewidget.cpp:757
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:81
QgsRelationReferenceWidget::foreignKeys
QVariantList foreignKeys() const
returns the related feature foreign key
Definition: qgsrelationreferencewidget.cpp:415
QgsRelationReferenceWidget::setRelation
void setRelation(const QgsRelation &relation, bool allowNullValue)
Definition: qgsrelationreferencewidget.cpp:176
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
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: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
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
QgsRelationReferenceWidgetWrapper::setEnabled
void setEnabled(bool enabled) override
Definition: qgsrelationreferencewidgetwrapper.cpp:211
qgsrelationreferencewidgetwrapper.h
QgsRelationReferenceWidget::setOpenFormButtonVisible
void setOpenFormButtonVisible(bool openFormButtonVisible)
Definition: qgsrelationreferencewidget.cpp:481
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:492
QgsAttributeEditorContext
This class contains context information for attribute editor widgets.
Definition: qgsattributeeditorcontext.h:41
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:796
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
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