QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
23QgsRelationReferenceWidgetWrapper::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 showOpenFormButton = config( QStringLiteral( "ShowOpenFormButton" ), true ).toBool();
55
56 mWidget->setEmbedForm( showForm );
57 mWidget->setReadOnlySelector( readOnlyWidget );
58 mWidget->setAllowMapIdentification( mapIdent );
59 mWidget->setOpenFormButtonVisible( showOpenFormButton );
60
61 const bool fetchLimitActive = config( QStringLiteral( "FetchLimitActive" ), QgsSettings().value( QStringLiteral( "maxEntriesRelationWidget" ), 100, QgsSettings::Gui ).toInt() > 0 ).toBool();
62 if ( fetchLimitActive )
63 {
64 mWidget->setFetchLimit( config( QStringLiteral( "FetchLimitNumber" ), QgsSettings().value( QStringLiteral( "maxEntriesRelationWidget" ), 100, QgsSettings::Gui ) ).toInt() );
65 }
66
67 if ( config( QStringLiteral( "FilterFields" ), QVariant() ).isValid() )
68 {
69 mWidget->setFilterFields( config( QStringLiteral( "FilterFields" ) ).toStringList() );
70 mWidget->setChainFilters( config( QStringLiteral( "ChainFilters" ) ).toBool() );
71 }
72 if ( !config( QStringLiteral( "FilterExpression" ) ).toString().isEmpty() )
73 {
74 mWidget->setFilterExpression( config( QStringLiteral( "FilterExpression" ) ).toString() );
75 }
76 mWidget->setAllowAddFeatures( config( QStringLiteral( "AllowAddFeatures" ), false ).toBool() );
77
78 const QVariant relationName = config( QStringLiteral( "Relation" ) );
79
80 // Store relation data source and provider key
81 mWidget->setReferencedLayerDataSource( config( QStringLiteral( "ReferencedLayerDataSource" ) ).toString() );
82 mWidget->setReferencedLayerProviderKey( config( QStringLiteral( "ReferencedLayerProviderKey" ) ).toString() );
83 mWidget->setReferencedLayerId( config( QStringLiteral( "ReferencedLayerId" ) ).toString() );
84 mWidget->setReferencedLayerName( config( QStringLiteral( "ReferencedLayerName" ) ).toString() );
85
86 QgsRelation relation; // invalid relation by default
87 if ( relationName.isValid() )
88 relation = QgsProject::instance()->relationManager()->relation( relationName.toString() );
89 if ( !relation.isValid() && !layer()->referencingRelations( fieldIdx() ).isEmpty() )
90 relation = layer()->referencingRelations( fieldIdx() )[0];
91
92 // If this widget is already embedded by the same relation, reduce functionality
93 do
94 {
95 if ( ctx->relation().id() == relation.id() )
96 {
97 mWidget->setEmbedForm( false );
98 mWidget->setReadOnlySelector( true );
99 mWidget->setAllowMapIdentification( false );
100 mWidget->setOpenFormButtonVisible( false );
101 mWidget->setAllowAddFeatures( false );
102 break;
103 }
104 ctx = ctx->parentContext();
105 }
106 while ( ctx );
107
108 mWidget->setRelation( relation, config( QStringLiteral( "AllowNULL" ) ).toBool() );
109
110 connect( mWidget, &QgsRelationReferenceWidget::foreignKeysChanged, this, &QgsRelationReferenceWidgetWrapper::foreignKeysChanged );
111}
112
114{
115 if ( !mWidget )
116 return QVariant( field().type() );
117
118 const QVariantList fkeys = mWidget->foreignKeys();
119
120 if ( fkeys.isEmpty() )
121 {
122 return QVariant( field().type() );
123 }
124 else
125 {
126 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
127 Q_ASSERT( fieldPairs.count() == fkeys.count() );
128 for ( int i = 0; i < fieldPairs.count(); i++ )
129 {
130 if ( fieldPairs.at( i ).referencingField() == field().name() )
131 return fkeys.at( i );
132 }
133 return QVariant( field().type() ); // should not happen
134 }
135}
136
138{
139 return mWidget;
140}
141
143{
144 if ( mWidget )
145 {
146 mWidget->showIndeterminateState();
147 }
148 mIndeterminateState = true;
149}
150
152{
153 if ( !mWidget )
154 return {};
155
156 if ( !mWidget->relation().isValid() )
157 {
158 QVariantList values;
159 for ( int i = 0; i < mWidget->relation().fieldPairs().count(); i++ )
160 {
161 values << QVariant();
162 }
163 return values;
164 }
165 else
166 {
167 QVariantList values = mWidget->foreignKeys();
168 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
169 const int fieldCount = std::min( fieldPairs.count(), values.count() );
170 for ( int i = 0; i < fieldCount; i++ )
171 {
172 if ( fieldPairs.at( i ).referencingField() == field().name() )
173 {
174 values.removeAt( i );
175 break;
176 }
177 }
178 return values;
179 }
180}
181
183{
184 if ( !mWidget || !mWidget->relation().isValid() )
185 return QStringList();
186
187 QStringList fields;
188 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
189 for ( int i = 0; i < fieldPairs.count(); i++ )
190 {
191 if ( fieldPairs.at( i ).referencingField() == field().name() )
192 continue;
193
194 fields << fieldPairs.at( i ).referencingField();
195 }
196 return fields;
197}
198
199void QgsRelationReferenceWidgetWrapper::updateValues( const QVariant &val, const QVariantList &additionalValues )
200{
201 if ( !mWidget || ( !mIndeterminateState && val == value() && QgsVariantUtils::isNull( val ) == QgsVariantUtils::isNull( value() ) ) )
202 return;
203
204 mIndeterminateState = false;
205
206 QVariantList values = additionalValues;
207 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
208 for ( int i = 0; i < fieldPairs.count(); i++ )
209 {
210 if ( fieldPairs.at( i ).referencingField() == field().name() )
211 {
212 values.insert( i, val );
213 break;
214 }
215 }
216 Q_ASSERT( values.count() == fieldPairs.count() );
217
218 mBlockChanges++;
219 mWidget->setForeignKeys( values );
220 mWidget->setFormFeature( formFeature() );
221 mBlockChanges--;
222}
223
225{
226 if ( !mWidget )
227 return;
228
229 mWidget->setRelationEditable( enabled );
230}
231
232void QgsRelationReferenceWidgetWrapper::foreignKeysChanged( const QVariantList &values )
233{
234 if ( mBlockChanges != 0 ) // initial value is being set, we can ignore this signal
235 return;
236
237 QVariant mainValue = QVariant( field().type() );
238
239 if ( !mWidget || !mWidget->relation().isValid() )
240 {
242 emit valueChanged( mainValue );
244 emit valuesChanged( mainValue );
245 return;
246 }
247
248 QVariantList additionalValues = values;
249 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
250 for ( int i = 0; i < fieldPairs.count(); i++ )
251 {
252 if ( fieldPairs.at( i ).referencingField() == field().name() )
253 mainValue = additionalValues.takeAt( i ); // additional values in field pair order remain
254 }
255 Q_ASSERT( additionalValues.count() == values.count() - 1 );
256
258 emit valueChanged( mainValue );
260 emit valuesChanged( mainValue, additionalValues );
261}
262
264{
265 if ( mWidget )
266 {
268 {
269 widget()->setStyleSheet( QString() );
270 }
271 else
272 {
273 switch ( constraintResult() )
274 {
276 mWidget->setStyleSheet( QString() );
277 break;
278
280 mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #dd7777; }" ) );
281 break;
282
284 mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #ffd85d; }" ) );
285 break;
286 }
287 }
288 }
289}
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:93
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
QgsRelationManager * relationManager
Definition: qgsproject.h:117
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:481
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 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 setFetchLimit(int fetchLimit)
Set the limit of fetched features (0 means all features)
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:45
bool isValid
Definition: qgsrelation.h:49
This class is a composition of two QSettings instances:
Definition: qgssettings.h:64
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
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:5776
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:5775