QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgsrelationreferenceconfigdlg.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrelationreferenceconfigdlg.cpp
3  --------------------------------------
4  Date : 21.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 
17 
18 #include "qgseditorwidgetfactory.h"
19 #include "qgsfields.h"
20 #include "qgsproject.h"
21 #include "qgsrelationmanager.h"
22 #include "qgsvectorlayer.h"
25 
27  : QgsEditorConfigWidget( vl, fieldIdx, parent )
28 
29 {
30  setupUi( this );
31  connect( mAddFilterButton, &QToolButton::clicked, this, &QgsRelationReferenceConfigDlg::mAddFilterButton_clicked );
32  connect( mRemoveFilterButton, &QToolButton::clicked, this, &QgsRelationReferenceConfigDlg::mRemoveFilterButton_clicked );
33 
34  mExpressionWidget->registerExpressionContextGenerator( vl );
35 
36  connect( mComboRelation, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRelationReferenceConfigDlg::relationChanged );
37 
38  const auto constReferencingRelations = vl->referencingRelations( fieldIdx );
39  for ( const QgsRelation &relation : constReferencingRelations )
40  {
41  if ( relation.name().isEmpty() )
42  mComboRelation->addItem( QStringLiteral( "%1 (%2)" ).arg( relation.id(), relation.referencedLayerId() ), relation.id() );
43  else
44  mComboRelation->addItem( QStringLiteral( "%1 (%2)" ).arg( relation.name(), relation.referencedLayerId() ), relation.id() );
45 
46  QStandardItemModel *model = qobject_cast<QStandardItemModel *>( mComboRelation->model() );
47  QStandardItem *item = model->item( model->rowCount() - 1 );
48  item->setFlags( relation.type() == QgsRelation::Generated
49  ? item->flags() & ~Qt::ItemIsEnabled
50  : item->flags() | Qt::ItemIsEnabled );
51 
52  if ( auto *lReferencedLayer = relation.referencedLayer() )
53  {
54  mExpressionWidget->setField( lReferencedLayer->displayExpression() );
55  }
56  }
57 
58  connect( mCbxAllowNull, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
59  connect( mCbxOrderByValue, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
60  connect( mCbxShowForm, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
61  connect( mCbxShowOpenFormButton, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
62  connect( mCbxMapIdentification, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
63  connect( mCbxReadOnly, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
64  connect( mComboRelation, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsEditorConfigWidget::changed );
65  connect( mCbxAllowAddFeatures, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
66  connect( mFilterGroupBox, &QGroupBox::toggled, this, &QgsEditorConfigWidget::changed );
67  connect( mFilterFieldsList, &QListWidget::itemChanged, this, &QgsEditorConfigWidget::changed );
68  connect( mCbxChainFilters, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
69  connect( mExpressionWidget, static_cast<void ( QgsFieldExpressionWidget::* )( const QString & )>( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsEditorConfigWidget::changed );
70  connect( mEditExpression, &QAbstractButton::clicked, this, &QgsRelationReferenceConfigDlg::mEditExpression_clicked );
71  connect( mFilterExpression, &QTextEdit::textChanged, this, &QgsEditorConfigWidget::changed );
72 }
73 
74 void QgsRelationReferenceConfigDlg::mEditExpression_clicked()
75 {
76  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer() );
77  if ( !vl )
78  return;
79 
83 
84  context.setHighlightedFunctions( QStringList() << QStringLiteral( "current_value" ) << QStringLiteral( "current_parent_value" ) );
85  context.setHighlightedVariables( QStringList() << QStringLiteral( "current_geometry" )
86  << QStringLiteral( "current_feature" )
87  << QStringLiteral( "form_mode" )
88  << QStringLiteral( "current_parent_geometry" )
89  << QStringLiteral( "current_parent_feature" ) );
90 
91  QgsExpressionBuilderDialog dlg( vl, mFilterExpression->toPlainText(), this, QStringLiteral( "generic" ), context );
92  dlg.setWindowTitle( tr( "Edit Filter Expression" ) );
93 
94  if ( dlg.exec() == QDialog::Accepted )
95  {
96  mFilterExpression->setPlainText( dlg.expressionBuilder()->expressionText() );
97  }
98 }
99 
100 void QgsRelationReferenceConfigDlg::setConfig( const QVariantMap &config )
101 {
102  mCbxAllowNull->setChecked( config.value( QStringLiteral( "AllowNULL" ), false ).toBool() );
103  mCbxOrderByValue->setChecked( config.value( QStringLiteral( "OrderByValue" ), false ).toBool() );
104  mCbxShowForm->setChecked( config.value( QStringLiteral( "ShowForm" ), false ).toBool() );
105  mCbxShowOpenFormButton->setChecked( config.value( QStringLiteral( "ShowOpenFormButton" ), true ).toBool() );
106 
107  if ( config.contains( QStringLiteral( "Relation" ) ) )
108  {
109  mComboRelation->setCurrentIndex( mComboRelation->findData( config.value( QStringLiteral( "Relation" ) ).toString() ) );
110  relationChanged( mComboRelation->currentIndex() );
111  }
112 
113  mCbxMapIdentification->setChecked( config.value( QStringLiteral( "MapIdentification" ), false ).toBool() );
114  mCbxAllowAddFeatures->setChecked( config.value( QStringLiteral( "AllowAddFeatures" ), false ).toBool() );
115  mCbxReadOnly->setChecked( config.value( QStringLiteral( "ReadOnly" ), false ).toBool() );
116  mFilterExpression->setPlainText( config.value( QStringLiteral( "FilterExpression" ) ).toString() );
117 
118  if ( config.contains( QStringLiteral( "FilterFields" ) ) )
119  {
120  mFilterGroupBox->setChecked( true );
121  const auto constToStringList = config.value( "FilterFields" ).toStringList();
122  for ( const QString &fld : constToStringList )
123  {
124  addFilterField( fld );
125  }
126 
127  mCbxChainFilters->setChecked( config.value( QStringLiteral( "ChainFilters" ) ).toBool() );
128  }
129 }
130 
131 void QgsRelationReferenceConfigDlg::relationChanged( int idx )
132 {
133  QString relName = mComboRelation->itemData( idx ).toString();
135 
136  mReferencedLayer = rel.referencedLayer();
137  mExpressionWidget->setLayer( mReferencedLayer ); // set even if 0
138  if ( mReferencedLayer )
139  {
140  mExpressionWidget->setField( mReferencedLayer->displayExpression() );
141  mCbxMapIdentification->setEnabled( mReferencedLayer->isSpatial() );
142  }
143 
144  loadFields();
145 }
146 
147 void QgsRelationReferenceConfigDlg::mAddFilterButton_clicked()
148 {
149  const auto constSelectedItems = mAvailableFieldsList->selectedItems();
150  for ( QListWidgetItem *item : constSelectedItems )
151  {
152  addFilterField( item );
153  }
154 }
155 
156 void QgsRelationReferenceConfigDlg::mRemoveFilterButton_clicked()
157 {
158  const auto constSelectedItems = mFilterFieldsList->selectedItems();
159  for ( QListWidgetItem *item : constSelectedItems )
160  {
161  mFilterFieldsList->takeItem( indexFromListWidgetItem( item ) );
162  mAvailableFieldsList->addItem( item );
163  }
164 }
165 
167 {
168  QVariantMap myConfig;
169  myConfig.insert( QStringLiteral( "AllowNULL" ), mCbxAllowNull->isChecked() );
170  myConfig.insert( QStringLiteral( "OrderByValue" ), mCbxOrderByValue->isChecked() );
171  myConfig.insert( QStringLiteral( "ShowForm" ), mCbxShowForm->isChecked() );
172  myConfig.insert( QStringLiteral( "ShowOpenFormButton" ), mCbxShowOpenFormButton->isChecked() );
173  myConfig.insert( QStringLiteral( "MapIdentification" ), mCbxMapIdentification->isEnabled() && mCbxMapIdentification->isChecked() );
174  myConfig.insert( QStringLiteral( "ReadOnly" ), mCbxReadOnly->isChecked() );
175  myConfig.insert( QStringLiteral( "Relation" ), mComboRelation->currentData() );
176  myConfig.insert( QStringLiteral( "AllowAddFeatures" ), mCbxAllowAddFeatures->isChecked() );
177 
178  if ( mFilterGroupBox->isChecked() )
179  {
180  QStringList filterFields;
181  filterFields.reserve( mFilterFieldsList->count() );
182  for ( int i = 0; i < mFilterFieldsList->count(); i++ )
183  {
184  filterFields << mFilterFieldsList->item( i )->data( Qt::UserRole ).toString();
185  }
186  myConfig.insert( QStringLiteral( "FilterFields" ), filterFields );
187 
188  myConfig.insert( QStringLiteral( "ChainFilters" ), mCbxChainFilters->isChecked() );
189  myConfig.insert( QStringLiteral( "FilterExpression" ), mFilterExpression->toPlainText() );
190  }
191 
192  if ( mReferencedLayer )
193  {
194  // Store referenced layer data source and provider
195  myConfig.insert( QStringLiteral( "ReferencedLayerDataSource" ), mReferencedLayer->publicSource() );
196  myConfig.insert( QStringLiteral( "ReferencedLayerProviderKey" ), mReferencedLayer->providerType() );
197  myConfig.insert( QStringLiteral( "ReferencedLayerId" ), mReferencedLayer->id() );
198  myConfig.insert( QStringLiteral( "ReferencedLayerName" ), mReferencedLayer->name() );
199  mReferencedLayer->setDisplayExpression( mExpressionWidget->currentField() );
200  }
201 
202  return myConfig;
203 }
204 
205 void QgsRelationReferenceConfigDlg::loadFields()
206 {
207  mAvailableFieldsList->clear();
208  mFilterFieldsList->clear();
209 
210  if ( mReferencedLayer )
211  {
212  QgsVectorLayer *l = mReferencedLayer;
213  const QgsFields &flds = l->fields();
214  for ( int i = 0; i < flds.count(); i++ )
215  {
216  mAvailableFieldsList->addItem( flds.at( i ).displayName() );
217  mAvailableFieldsList->item( mAvailableFieldsList->count() - 1 )->setData( Qt::UserRole, flds.at( i ).name() );
218  }
219  }
220 }
221 
222 void QgsRelationReferenceConfigDlg::addFilterField( const QString &field )
223 {
224  for ( int i = 0; i < mAvailableFieldsList->count(); i++ )
225  {
226  if ( mAvailableFieldsList->item( i )->data( Qt::UserRole ).toString() == field )
227  {
228  addFilterField( mAvailableFieldsList->item( i ) );
229  break;
230  }
231  }
232 }
233 
234 void QgsRelationReferenceConfigDlg::addFilterField( QListWidgetItem *item )
235 {
236  mAvailableFieldsList->takeItem( indexFromListWidgetItem( item ) );
237  mFilterFieldsList->addItem( item );
238 }
239 
240 int QgsRelationReferenceConfigDlg::indexFromListWidgetItem( QListWidgetItem *item )
241 {
242  QListWidget *lw = item->listWidget();
243 
244  for ( int i = 0; i < lw->count(); i++ )
245  {
246  if ( lw->item( i ) == item )
247  return i;
248  }
249 
250  return -1;
251 }
This class should be subclassed for every configurable editor widget type.
int field()
Returns the field for which this configuration widget applies.
QgsVectorLayer * layer()
Returns the layer for which this configuration widget applies.
void changed()
Emitted when the configuration of the widget is changed.
A generic dialog for building expression strings.
static QgsExpressionContextScope * parentFormScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current parent attribute form/tab...
static QgsExpressionContextScope * formScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current attribute form/table form...
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
QString name
Definition: qgsfield.h:60
QString displayName() const
Returns the name to use when displaying this field.
Definition: qgsfield.cpp:88
Container of fields for a vector layer.
Definition: qgsfields.h:45
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
QString name
Definition: qgsmaplayer.h:73
QString providerType() const
Returns the provider type (provider key) for this layer.
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
QgsRelationManager * relationManager
Definition: qgsproject.h:109
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:467
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
QgsRelationReferenceConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)
void setConfig(const QVariantMap &config) override
Update the configuration widget to represent the given configuration.
QVariantMap config() override
Create a configuration from the current GUI state.
QgsVectorLayer * referencedLayer
Definition: qgsrelation.h:48
@ Generated
A generated relation is a child of a polymorphic relation.
Definition: qgsrelation.h:62
Represents a vector layer which manages a vector based data sets.
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QList< QgsRelation > referencingRelations(int idx) const
Returns the layer's relations, where the foreign key is on this layer.
void setDisplayExpression(const QString &displayExpression)
Set the preview expression, used to create a human readable preview string.
QString displayExpression
const QgsField & field
Definition: qgsfield.h:463