QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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  const QString relName = mComboRelation->itemData( idx ).toString();
134  const QgsRelation rel = QgsProject::instance()->relationManager()->relation( relName );
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 }
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
QgsProject::relationManager
QgsRelationManager relationManager
Definition: qgsproject.h:114
qgsfields.h
qgsexpressioncontextutils.h
QgsEditorConfigWidget
This class should be subclassed for every configurable editor widget type.
Definition: qgseditorconfigwidget.h:38
QgsExpressionContextUtils::formScope
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...
Definition: qgsexpressioncontextutils.cpp:270
QgsFields::count
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsFields
Container of fields for a vector layer.
Definition: qgsfields.h:44
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:480
QgsRelationManager::relation
Q_INVOKABLE QgsRelation relation(const QString &id) const
Gets access to a relation by its id.
Definition: qgsrelationmanager.cpp:95
QgsVectorLayer::isSpatial
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
Definition: qgsvectorlayer.cpp:3733
QgsExpressionContextUtils::globalProjectLayerScopes
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Definition: qgsexpressioncontextutils.cpp:377
field
const QgsField & field
Definition: qgsfield.h:463
QgsField::name
QString name
Definition: qgsfield.h:60
QgsMapLayer::providerType
QString providerType() const
Returns the provider type (provider key) for this layer.
Definition: qgsmaplayer.cpp:1864
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3436
QgsEditorConfigWidget::field
int field()
Returns the field for which this configuration widget applies.
Definition: qgseditorconfigwidget.cpp:28
QgsEditorConfigWidget::layer
QgsVectorLayer * layer()
Returns the layer for which this configuration widget applies.
Definition: qgseditorconfigwidget.cpp:33
QgsExpressionBuilderDialog
A generic dialog for building expression strings.
Definition: qgsexpressionbuilderdialog.h:30
QgsRelation::referencedLayer
QgsVectorLayer referencedLayer
Definition: qgsrelation.h:48
QgsFieldExpressionWidget::fieldChanged
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
QgsExpressionContextUtils::parentFormScope
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...
Definition: qgsexpressioncontextutils.cpp:281
QgsVectorLayer::referencingRelations
QList< QgsRelation > referencingRelations(int idx) const
Returns the layer's relations, where the foreign key is on this layer.
Definition: qgsvectorlayer.cpp:5409
QgsMapLayer::id
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
Definition: qgsmaplayer.cpp:169
QgsRelationReferenceConfigDlg::setConfig
void setConfig(const QVariantMap &config) override
Update the configuration widget to represent the given configuration.
Definition: qgsrelationreferenceconfigdlg.cpp:100
QgsVectorLayer::setDisplayExpression
void setDisplayExpression(const QString &displayExpression)
Set the preview expression, used to create a human readable preview string.
Definition: qgsvectorlayer.cpp:3699
qgsrelationmanager.h
qgsvectorlayer.h
QgsMapLayer::publicSource
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
Definition: qgsmaplayer.cpp:292
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
qgseditorwidgetfactory.h
QgsRelationReferenceConfigDlg::config
QVariantMap config() override
Create a configuration from the current GUI state.
Definition: qgsrelationreferenceconfigdlg.cpp:166
QgsMapLayer::name
QString name
Definition: qgsmaplayer.h:76
QgsRelation
Definition: qgsrelation.h:42
QgsEditorConfigWidget::changed
void changed()
Emitted when the configuration of the widget is changed.
QgsField::displayName
QString displayName() const
Returns the name to use when displaying this field.
Definition: qgsfield.cpp:89
QgsFields::at
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
QgsVectorLayer::displayExpression
QString displayExpression
Definition: qgsvectorlayer.h:396
QgsFieldExpressionWidget
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
Definition: qgsfieldexpressionwidget.h:46
qgsrelationreferenceconfigdlg.h
qgsproject.h
QgsRelation::Generated
@ Generated
A generated relation is a child of a polymorphic relation.
Definition: qgsrelation.h:62
QgsRelationReferenceConfigDlg::QgsRelationReferenceConfigDlg
QgsRelationReferenceConfigDlg(QgsVectorLayer *vl, int fieldIdx, QWidget *parent)
Definition: qgsrelationreferenceconfigdlg.cpp:26
qgsexpressionbuilderdialog.h