QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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  QgsRelation relation; // invalid relation by default
71  if ( relationName.isValid() )
72  relation = QgsProject::instance()->relationManager()->relation( relationName.toString() );
73  else if ( ! layer()->referencingRelations( fieldIdx() ).isEmpty() )
74  relation = layer()->referencingRelations( fieldIdx() )[0];
75 
76  // If this widget is already embedded by the same relation, reduce functionality
77  do
78  {
79  if ( ctx->relation().id() == relation.id() )
80  {
81  mWidget->setEmbedForm( false );
82  mWidget->setReadOnlySelector( true );
83  mWidget->setAllowMapIdentification( false );
84  mWidget->setOpenFormButtonVisible( false );
85  break;
86  }
87  ctx = ctx->parentContext();
88  }
89  while ( ctx );
90 
91  mWidget->setRelation( relation, config( QStringLiteral( "AllowNULL" ) ).toBool() );
92 
93  connect( mWidget, &QgsRelationReferenceWidget::foreignKeysChanged, this, &QgsRelationReferenceWidgetWrapper::foreignKeysChanged );
94 }
95 
97 {
98  if ( !mWidget )
99  return QVariant( field().type() );
100 
101  const QVariantList fkeys = mWidget->foreignKeys();
102 
103  if ( fkeys.isEmpty() )
104  {
105  return QVariant( field().type() );
106  }
107  else
108  {
109  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
110  Q_ASSERT( fieldPairs.count() == fkeys.count() );
111  for ( int i = 0; i < fieldPairs.count(); i++ )
112  {
113  if ( fieldPairs.at( i ).referencingField() == field().name() )
114  return fkeys.at( i );
115  }
116  return QVariant( field().type() ); // should not happen
117  }
118 }
119 
121 {
122  return mWidget;
123 }
124 
126 {
127  if ( mWidget )
128  {
129  mWidget->showIndeterminateState();
130  }
131  mIndeterminateState = true;
132 }
133 
135 {
136  if ( !mWidget || !mWidget->relation().isValid() )
137  {
138  QVariantList values;
139  for ( int i = 0; i < mWidget->relation().fieldPairs().count(); i++ )
140  {
141  values << QVariant();
142  }
143  return values;
144  }
145  else
146  {
147  QVariantList values = mWidget->foreignKeys();
148  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
149  int fieldCount = std::min( fieldPairs.count(), values.count() );
150  for ( int i = 0; i < fieldCount; i++ )
151  {
152  if ( fieldPairs.at( i ).referencingField() == field().name() )
153  {
154  values.removeAt( i );
155  break;
156  }
157  }
158  return values;
159  }
160 }
161 
163 {
164  if ( !mWidget || !mWidget->relation().isValid() )
165  return QStringList();
166 
167  QStringList fields;
168  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
169  for ( int i = 0; i < fieldPairs.count(); i++ )
170  {
171  if ( fieldPairs.at( i ).referencingField() == field().name() )
172  continue;
173 
174  fields << fieldPairs.at( i ).referencingField();
175  }
176  return fields;
177 }
178 
179 void QgsRelationReferenceWidgetWrapper::updateValues( const QVariant &val, const QVariantList &additionalValues )
180 {
181  if ( !mWidget || ( !mIndeterminateState && val == value() && val.isNull() == value().isNull() ) )
182  return;
183 
184  mIndeterminateState = false;
185 
186  QVariantList values = additionalValues;
187  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
188  for ( int i = 0; i < fieldPairs.count(); i++ )
189  {
190  if ( fieldPairs.at( i ).referencingField() == field().name() )
191  {
192  values.insert( i, val );
193  break;
194  }
195  }
196  Q_ASSERT( values.count() == fieldPairs.count() );
197 
198  mWidget->setForeignKeys( values );
199  mWidget->setFormFeature( formFeature() );
200 }
201 
203 {
204  if ( !mWidget )
205  return;
206 
207  mWidget->setRelationEditable( enabled );
208 }
209 
210 void QgsRelationReferenceWidgetWrapper::foreignKeysChanged( const QVariantList &values )
211 {
212  QVariant mainValue = QVariant( field().type() );
213 
214  if ( !mWidget || !mWidget->relation().isValid() )
215  {
217  emit valueChanged( mainValue );
219  emit valuesChanged( mainValue );
220  return;
221  }
222 
223  QVariantList additionalValues = values;
224  const QList<QgsRelation::FieldPair> fieldPairs = mWidget->relation().fieldPairs();
225  for ( int i = 0; i < fieldPairs.count(); i++ )
226  {
227  if ( fieldPairs.at( i ).referencingField() == field().name() )
228  mainValue = additionalValues.takeAt( i ); // additional values in field pair order remain
229  }
230  Q_ASSERT( additionalValues.count() == values.count() - 1 );
231 
233  emit valueChanged( mainValue );
235  emit valuesChanged( mainValue, additionalValues );
236 }
237 
239 {
240  if ( mWidget )
241  {
242  if ( !constraintResultVisible() )
243  {
244  widget()->setStyleSheet( QString() );
245  }
246  else
247  {
248  switch ( constraintResult() )
249  {
251  mWidget->setStyleSheet( QString() );
252  break;
253 
255  mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #dd7777; }" ) );
256  break;
257 
259  mWidget->setStyleSheet( QStringLiteral( ".QComboBox { background-color: #ffd85d; }" ) );
260  break;
261  }
262  }
263  }
264 }
void setEditorContext(const QgsAttributeEditorContext &context, QgsMapCanvas *canvas, QgsMessageBar *messageBar)
Widget failed at least one soft (non-enforced) constraint.
QVariantList foreignKeys() const
returns the related feature foreign key
QString name
Definition: qgsfield.h:58
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.
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
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:649
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.
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:100
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.
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:650
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:442
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.