QGIS API Documentation 3.41.0-Master (3440c17df1d)
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 "moc_qgsrelationreferencewidgetwrapper.cpp"
19#include "qgsproject.h"
20#include "qgsrelationmanager.h"
22#include "qgsattributeform.h"
23
24QgsRelationReferenceWidgetWrapper::QgsRelationReferenceWidgetWrapper( QgsVectorLayer *vl, int fieldIdx, QWidget *editor, QgsMapCanvas *canvas, QgsMessageBar *messageBar, QWidget *parent )
25 : QgsEditorWidgetWrapper( vl, fieldIdx, editor, parent )
26 , mCanvas( canvas )
27 , mMessageBar( messageBar )
28 , mIndeterminateState( false )
29{
30}
31
33{
35 return w;
36}
37
39{
40 QgsRelationReferenceWidget *w = qobject_cast<QgsRelationReferenceWidget *>( editor );
41 if ( !w )
42 {
43 w = new QgsRelationReferenceWidget( editor );
44 }
45
46 mWidget = w;
47
48 const QgsAttributeEditorContext *ctx = &context();
49
50 mWidget->setEditorContext( *ctx, mCanvas, mMessageBar );
51
52 const bool showForm = config( QStringLiteral( "ShowForm" ), false ).toBool();
53 const bool mapIdent = config( QStringLiteral( "MapIdentification" ), false ).toBool();
54 const bool readOnlyWidget = config( QStringLiteral( "ReadOnly" ), 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->setOpenFormButtonVisible( showOpenFormButton );
61
62 const bool fetchLimitActive = config( QStringLiteral( "FetchLimitActive" ), QgsSettings().value( QStringLiteral( "maxEntriesRelationWidget" ), 100, QgsSettings::Gui ).toInt() > 0 ).toBool();
63 if ( fetchLimitActive )
64 {
65 mWidget->setFetchLimit( config( QStringLiteral( "FetchLimitNumber" ), QgsSettings().value( QStringLiteral( "maxEntriesRelationWidget" ), 100, QgsSettings::Gui ) ).toInt() );
66 }
67
68 if ( config( QStringLiteral( "FilterFields" ), QVariant() ).isValid() )
69 {
70 mWidget->setFilterFields( config( QStringLiteral( "FilterFields" ) ).toStringList() );
71 mWidget->setChainFilters( config( QStringLiteral( "ChainFilters" ) ).toBool() );
72 }
73 if ( !config( QStringLiteral( "FilterExpression" ) ).toString().isEmpty() )
74 {
75 mWidget->setFilterExpression( config( QStringLiteral( "FilterExpression" ) ).toString() );
76 }
77 mWidget->setAllowAddFeatures( config( QStringLiteral( "AllowAddFeatures" ), false ).toBool() );
78
79 const QVariant relationName = config( QStringLiteral( "Relation" ) );
80
81 // Store relation data source and provider key
82 mWidget->setReferencedLayerDataSource( config( QStringLiteral( "ReferencedLayerDataSource" ) ).toString() );
83 mWidget->setReferencedLayerProviderKey( config( QStringLiteral( "ReferencedLayerProviderKey" ) ).toString() );
84 mWidget->setReferencedLayerId( config( QStringLiteral( "ReferencedLayerId" ) ).toString() );
85 mWidget->setReferencedLayerName( config( QStringLiteral( "ReferencedLayerName" ) ).toString() );
86
87 QgsRelation relation; // invalid relation by default
88 if ( relationName.isValid() )
89 relation = QgsProject::instance()->relationManager()->relation( relationName.toString() );
90 if ( !relation.isValid() && !layer()->referencingRelations( fieldIdx() ).isEmpty() )
91 relation = layer()->referencingRelations( fieldIdx() )[0];
92
93 // If this widget is already embedded by the same relation, reduce functionality
94 do
95 {
96 if ( ctx->relation().id() == relation.id() )
97 {
98 mWidget->setEmbedForm( false );
99 mWidget->setReadOnlySelector( true );
100 mWidget->setAllowMapIdentification( false );
101 mWidget->setOpenFormButtonVisible( false );
102 mWidget->setAllowAddFeatures( false );
103 break;
104 }
105 ctx = ctx->parentContext();
106 }
107 while ( ctx );
108
109 // If AllowNULL is not set in the config, provide a default value based on the
110 // constraints of the referencing fields
111 if ( !config( QStringLiteral( "AllowNULL" ) ).isValid() )
112 {
113 mWidget->setRelation( relation, relation.referencingFieldsAllowNull() );
114 }
115 else
116 {
117 mWidget->setRelation( relation, config( QStringLiteral( "AllowNULL" ) ).toBool() );
118 }
119
120 connect( mWidget, &QgsRelationReferenceWidget::foreignKeysChanged, this, &QgsRelationReferenceWidgetWrapper::foreignKeysChanged );
121}
122
124{
125 if ( !mWidget )
126 return QgsVariantUtils::createNullVariant( field().type() );
127
128 const QVariantList fkeys = mWidget->foreignKeys();
129
130 if ( fkeys.isEmpty() )
131 {
132 return QgsVariantUtils::createNullVariant( field().type() );
133 }
134 else
135 {
136 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
137 Q_ASSERT( fieldPairs.count() == fkeys.count() );
138 for ( int i = 0; i < fieldPairs.count(); i++ )
139 {
140 if ( fieldPairs.at( i ).referencingField() == field().name() )
141 return fkeys.at( i );
142 }
143 return QgsVariantUtils::createNullVariant( field().type() ); // should not happen
144 }
145}
146
148{
149 return mWidget;
150}
151
153{
154 if ( mWidget )
155 {
156 mWidget->showIndeterminateState();
157 }
158 mIndeterminateState = true;
159}
160
162{
163 if ( !mWidget )
164 return {};
165
166 if ( !mWidget->relation().isValid() )
167 {
168 QVariantList values;
169 for ( int i = 0; i < mWidget->relation().fieldPairs().count(); i++ )
170 {
171 values << QVariant();
172 }
173 return values;
174 }
175 else
176 {
177 QVariantList values = mWidget->foreignKeys();
178 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
179 const int fieldCount = std::min( fieldPairs.count(), values.count() );
180 for ( int i = 0; i < fieldCount; i++ )
181 {
182 if ( fieldPairs.at( i ).referencingField() == field().name() )
183 {
184 values.removeAt( i );
185 break;
186 }
187 }
188 return values;
189 }
190}
191
193{
194 if ( !mWidget || !mWidget->relation().isValid() )
195 return QStringList();
196
197 QStringList fields;
198 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
199 for ( int i = 0; i < fieldPairs.count(); i++ )
200 {
201 if ( fieldPairs.at( i ).referencingField() == field().name() )
202 continue;
203
204 fields << fieldPairs.at( i ).referencingField();
205 }
206 return fields;
207}
208
209void QgsRelationReferenceWidgetWrapper::updateValues( const QVariant &val, const QVariantList &additionalValues )
210{
211 if ( !mWidget || ( !mIndeterminateState && val == value() && QgsVariantUtils::isNull( val ) == QgsVariantUtils::isNull( value() ) ) )
212 return;
213
214 mIndeterminateState = false;
215
216 QVariantList values = additionalValues;
217 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
218 for ( int i = 0; i < fieldPairs.count(); i++ )
219 {
220 if ( fieldPairs.at( i ).referencingField() == field().name() )
221 {
222 values.insert( i, val );
223 break;
224 }
225 }
226 Q_ASSERT( values.count() == fieldPairs.count() );
227
228 mBlockChanges++;
229 mWidget->setForeignKeys( values );
230 mWidget->setFormFeature( formFeature() );
231 mBlockChanges--;
232}
233
235{
236 if ( !mWidget )
237 return;
238
239 mWidget->setRelationEditable( enabled );
240}
241
242void QgsRelationReferenceWidgetWrapper::foreignKeysChanged( const QVariantList &values )
243{
244 if ( mBlockChanges != 0 ) // initial value is being set, we can ignore this signal
245 return;
246
247 QVariant mainValue = QgsVariantUtils::createNullVariant( field().type() );
248
249 if ( !mWidget || !mWidget->relation().isValid() )
250 {
252 emit valueChanged( mainValue );
254 emit valuesChanged( mainValue );
255 return;
256 }
257
258 QVariantList additionalValues = values;
259 const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
260 for ( int i = 0; i < fieldPairs.count(); i++ )
261 {
262 if ( fieldPairs.at( i ).referencingField() == field().name() )
263 mainValue = additionalValues.takeAt( i ); // additional values in field pair order remain
264 }
265 Q_ASSERT( additionalValues.count() == values.count() - 1 );
266
268 emit valueChanged( mainValue );
270 emit valuesChanged( mainValue, additionalValues );
271}
272
274{
275 if ( mWidget )
276 {
278 {
279 widget()->setStyleSheet( QString() );
280 }
281 else
282 {
283 switch ( constraintResult() )
284 {
286 mWidget->setStyleSheet( QString() );
287 break;
288
290 mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #dd7777; }" ) );
291 break;
292
294 mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #ffd85d; }" ) );
295 break;
296 }
297 }
298 }
299}
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:117
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 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 foreignKeysChanged(const QVariantList &keys)
Emitted when the foreign keys changed.
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)
Represents a relationship between two vector layers.
Definition qgsrelation.h:44
QString id
Definition qgsrelation.h:47
QList< QgsRelation::FieldPair > fieldPairs() const
Returns the field pairs which form this relation The first element of each pair are the field names o...
bool referencingFieldsAllowNull() const
Returns true if none of the referencing fields has a NOT NULL constraint.
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.
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
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:6535
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:6534