QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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  mBlockChanges++;
208  mWidget->setForeignKeys( values );
209  mWidget->setFormFeature( formFeature() );
210  mBlockChanges--;
211 }
212 
214 {
215  if ( !mWidget )
216  return;
217 
218  mWidget->setRelationEditable( enabled );
219 }
220 
221 void QgsRelationReferenceWidgetWrapper::foreignKeysChanged( const QVariantList &values )
222 {
223  if ( mBlockChanges != 0 ) // initial value is being set, we can ignore this signal
224  return;
225 
226  QVariant mainValue = QVariant( field().type() );
227 
228  if ( !mWidget || !mWidget->relation().isValid() )
229  {
231  emit valueChanged( mainValue );
233  emit valuesChanged( mainValue );
234  return;
235  }
236 
237  QVariantList additionalValues = values;
238  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
239  for ( int i = 0; i < fieldPairs.count(); i++ )
240  {
241  if ( fieldPairs.at( i ).referencingField() == field().name() )
242  mainValue = additionalValues.takeAt( i ); // additional values in field pair order remain
243  }
244  Q_ASSERT( additionalValues.count() == values.count() - 1 );
245 
247  emit valueChanged( mainValue );
249  emit valuesChanged( mainValue, additionalValues );
250 }
251 
253 {
254  if ( mWidget )
255  {
256  if ( !constraintResultVisible() )
257  {
258  widget()->setStyleSheet( QString() );
259  }
260  else
261  {
262  switch ( constraintResult() )
263  {
265  mWidget->setStyleSheet( QString() );
266  break;
267 
269  mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #dd7777; }" ) );
270  break;
271 
273  mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #ffd85d; }" ) );
274  break;
275  }
276  }
277  }
278 }
This class contains context information for attribute editor widgets.
const QgsAttributeEditorContext * parentContext() const
const QgsRelation & relation() const
Returns the attribute relation.
Manages an editor widget Widget and wrapper share the same parent.
QgsFeature formFeature() const
The feature currently being edited, in its current state.
Q_DECL_DEPRECATED void valueChanged(const QVariant &value)
Emit this signal, whenever the value changed.
int fieldIdx() const
Access the field index.
ConstraintResult constraintResult
void valuesChanged(const QVariant &value, const QVariantList &additionalFieldValues=QVariantList())
Emit this signal, whenever the value changed.
QgsField field() const
Access the field.
@ ConstraintResultFailSoft
Widget failed at least one soft (non-enforced) constraint.
@ ConstraintResultPass
Widget passed constraints successfully.
@ ConstraintResultFailHard
Widget failed at least one hard (enforced) constraint.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:86
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
QgsRelationManager * relationManager
Definition: qgsproject.h:109
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:501
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
bool valid() const override
Returns true if the widget has been properly initialized.
QVariant value() const override
Will be used to access the widget's value.
void showIndeterminateState() override
Sets the widget to display in an indeterminate "mixed value" state.
QgsRelationReferenceWidgetWrapper(QgsVectorLayer *vl, int fieldIdx, QWidget *editor, QgsMapCanvas *canvas, QgsMessageBar *messageBar, QWidget *parent=nullptr)
Constructor for QgsRelationReferenceWidgetWrapper.
void updateConstraintWidgetStatus() override
This should update the widget with a visual cue if a constraint status changed.
QVariantList additionalFieldValues() const override
Will be used to access the widget's values for potential additional fields handled by the widget.
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
QStringList additionalFields() const override
Returns the list of additional fields which the editor handles.
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
void setFilterExpression(const QString &filterExpression)
If not empty, will be used as filter expression.
void setReferencedLayerProviderKey(const QString &referencedLayerProviderKey)
Set the data provider key of the referenced layer to referencedLayerProviderKey.
void foreignKeysChanged(const QVariantList &)
Emitted when the foreign keys changed.
void setChainFilters(bool chainFilters)
Set if filters are chained.
void setEditorContext(const QgsAttributeEditorContext &context, QgsMapCanvas *canvas, QgsMessageBar *messageBar)
Sets the editor context.
void setReferencedLayerName(const QString &referencedLayerName)
Set the name of the referenced layer to referencedLayerName.
void showIndeterminateState()
Sets the widget to display in an indeterminate "mixed value" state.
void setReferencedLayerDataSource(const QString &referencedLayerDataSource)
Set the public data source of the referenced layer to referencedLayerDataSource.
void setFilterFields(const QStringList &filterFields)
Sets the fields for which filter comboboxes will be created.
void setAllowMapIdentification(bool allowMapIdentification)
QgsRelation relation() const
Returns the current relation, which might be invalid.
void setReferencedLayerId(const QString &referencedLayerId)
Set the id of the referenced layer to referencedLayerId.
QVariantList foreignKeys() const
returns the related feature foreign key
void setForeignKeys(const QVariantList &values)
Sets the related feature using the foreign keys.
void setOrderByValue(bool orderByValue)
Sets if the widget will order the combobox entries by value.
void setRelation(const QgsRelation &relation, bool allowNullValue)
void setOpenFormButtonVisible(bool openFormButtonVisible)
void setAllowAddFeatures(bool allowAddFeatures)
Determines if a button for adding new features should be shown.
void setFormFeature(const QgsFeature &formFeature)
Set the current form feature (from the referencing layer)
QList< QgsRelation::FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
Q_GADGET QString id
Definition: qgsrelation.h:46
bool isValid
Definition: qgsrelation.h:50
Represents a vector layer which manages a vector based data sets.
QList< QgsRelation > referencingRelations(int idx) const
Returns the layer's relations, where the foreign key is on this layer.
QWidget * widget()
Access the widget managed by this wrapper.
const QgsAttributeEditorContext & context() const
Returns information about the context in which this widget is shown.
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
QVariantMap config() const
Returns the whole config.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:798
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:797