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