QGIS API Documentation 3.28.14-Firenze (exported)
Loading...
Searching...
No Matches
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 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 )
149 return {};
150
151 if ( !mWidget->relation().isValid() )
152 {
153 QVariantList values;
154 for ( int i = 0; i < mWidget->relation().fieldPairs().count(); i++ )
155 {
156 values << QVariant();
157 }
158 return values;
159 }
160 else
161 {
162 QVariantList values = mWidget->foreignKeys();
163 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
164 const int fieldCount = std::min( fieldPairs.count(), values.count() );
165 for ( int i = 0; i < fieldCount; i++ )
166 {
167 if ( fieldPairs.at( i ).referencingField() == field().name() )
168 {
169 values.removeAt( i );
170 break;
171 }
172 }
173 return values;
174 }
175}
176
178{
179 if ( !mWidget || !mWidget->relation().isValid() )
180 return QStringList();
181
182 QStringList fields;
183 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
184 for ( int i = 0; i < fieldPairs.count(); i++ )
185 {
186 if ( fieldPairs.at( i ).referencingField() == field().name() )
187 continue;
188
189 fields << fieldPairs.at( i ).referencingField();
190 }
191 return fields;
192}
193
194void QgsRelationReferenceWidgetWrapper::updateValues( const QVariant &val, const QVariantList &additionalValues )
195{
196 if ( !mWidget || ( !mIndeterminateState && val == value() && QgsVariantUtils::isNull( val ) == QgsVariantUtils::isNull( value() ) ) )
197 return;
198
199 mIndeterminateState = false;
200
201 QVariantList values = additionalValues;
202 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
203 for ( int i = 0; i < fieldPairs.count(); i++ )
204 {
205 if ( fieldPairs.at( i ).referencingField() == field().name() )
206 {
207 values.insert( i, val );
208 break;
209 }
210 }
211 Q_ASSERT( values.count() == fieldPairs.count() );
212
213 mBlockChanges++;
214 mWidget->setForeignKeys( values );
215 mWidget->setFormFeature( formFeature() );
216 mBlockChanges--;
217}
218
220{
221 if ( !mWidget )
222 return;
223
224 mWidget->setRelationEditable( enabled );
225}
226
227void QgsRelationReferenceWidgetWrapper::foreignKeysChanged( const QVariantList &values )
228{
229 if ( mBlockChanges != 0 ) // initial value is being set, we can ignore this signal
230 return;
231
232 QVariant mainValue = QVariant( field().type() );
233
234 if ( !mWidget || !mWidget->relation().isValid() )
235 {
237 emit valueChanged( mainValue );
239 emit valuesChanged( mainValue );
240 return;
241 }
242
243 QVariantList additionalValues = values;
244 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
245 for ( int i = 0; i < fieldPairs.count(); i++ )
246 {
247 if ( fieldPairs.at( i ).referencingField() == field().name() )
248 mainValue = additionalValues.takeAt( i ); // additional values in field pair order remain
249 }
250 Q_ASSERT( additionalValues.count() == values.count() - 1 );
251
253 emit valueChanged( mainValue );
255 emit valuesChanged( mainValue, additionalValues );
256}
257
259{
260 if ( mWidget )
261 {
263 {
264 widget()->setStyleSheet( QString() );
265 }
266 else
267 {
268 switch ( constraintResult() )
269 {
271 mWidget->setStyleSheet( QString() );
272 break;
273
275 mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #dd7777; }" ) );
276 break;
277
279 mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #ffd85d; }" ) );
280 break;
281 }
282 }
283 }
284}
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.
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.
A bar for displaying non-blocking messages to the user.
QgsRelationManager * relationManager
Definition qgsproject.h:114
static QgsProject * instance()
Returns the QgsProject singleton instance.
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)
QString id
Definition qgsrelation.h:45
QList< QgsRelation::FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
static bool isNull(const QVariant &variant)
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:3061
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:3060