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
16 #include "qgsrelationreferenceconfigdlg.h"
17
18 #include "qgseditorwidgetfactory.h"
19 #include "qgsfields.h"
20 #include "qgsproject.h"
21 #include "qgsrelationmanager.h"
22 #include "qgsvectorlayer.h"
23 #include "qgsexpressionbuilderdialog.h"
24 #include "qgsexpressioncontextutils.h"
25
QgsRelationReferenceConfigDlg(QgsVectorLayer * vl,int fieldIdx,QWidget * parent)26 QgsRelationReferenceConfigDlg::QgsRelationReferenceConfigDlg( QgsVectorLayer *vl, int fieldIdx, QWidget *parent )
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 if ( auto *lReferencedLayer = relation.referencedLayer() )
46 {
47 mExpressionWidget->setField( lReferencedLayer->displayExpression() );
48 }
49 }
50
51 connect( mCbxAllowNull, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
52 connect( mCbxOrderByValue, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
53 connect( mCbxShowForm, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
54 connect( mCbxShowOpenFormButton, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
55 connect( mCbxMapIdentification, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
56 connect( mCbxReadOnly, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
57 connect( mComboRelation, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsEditorConfigWidget::changed );
58 connect( mCbxAllowAddFeatures, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
59 connect( mFilterGroupBox, &QGroupBox::toggled, this, &QgsEditorConfigWidget::changed );
60 connect( mFilterFieldsList, &QListWidget::itemChanged, this, &QgsEditorConfigWidget::changed );
61 connect( mCbxChainFilters, &QAbstractButton::toggled, this, &QgsEditorConfigWidget::changed );
62 connect( mExpressionWidget, static_cast<void ( QgsFieldExpressionWidget::* )( const QString & )>( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsEditorConfigWidget::changed );
63 connect( mEditExpression, &QAbstractButton::clicked, this, &QgsRelationReferenceConfigDlg::mEditExpression_clicked );
64 connect( mFilterExpression, &QTextEdit::textChanged, this, &QgsEditorConfigWidget::changed );
65 }
66
mEditExpression_clicked()67 void QgsRelationReferenceConfigDlg::mEditExpression_clicked()
68 {
69 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer() );
70 if ( !vl )
71 return;
72
73 QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( vl ) );
74 context << QgsExpressionContextUtils::formScope( );
75 context << QgsExpressionContextUtils::parentFormScope( );
76
77 context.setHighlightedFunctions( QStringList() << QStringLiteral( "current_value" ) << QStringLiteral( "current_parent_value" ) );
78 context.setHighlightedVariables( QStringList() << QStringLiteral( "current_geometry" )
79 << QStringLiteral( "current_feature" )
80 << QStringLiteral( "form_mode" )
81 << QStringLiteral( "current_parent_geometry" )
82 << QStringLiteral( "current_parent_feature" ) );
83
84 QgsExpressionBuilderDialog dlg( vl, mFilterExpression->toPlainText(), this, QStringLiteral( "generic" ), context );
85 dlg.setWindowTitle( tr( "Edit Filter Expression" ) );
86
87 if ( dlg.exec() == QDialog::Accepted )
88 {
89 mFilterExpression->setPlainText( dlg.expressionBuilder()->expressionText() );
90 }
91 }
92
setConfig(const QVariantMap & config)93 void QgsRelationReferenceConfigDlg::setConfig( const QVariantMap &config )
94 {
95 mCbxAllowNull->setChecked( config.value( QStringLiteral( "AllowNULL" ), false ).toBool() );
96 mCbxOrderByValue->setChecked( config.value( QStringLiteral( "OrderByValue" ), false ).toBool() );
97 mCbxShowForm->setChecked( config.value( QStringLiteral( "ShowForm" ), false ).toBool() );
98 mCbxShowOpenFormButton->setChecked( config.value( QStringLiteral( "ShowOpenFormButton" ), true ).toBool() );
99
100 if ( config.contains( QStringLiteral( "Relation" ) ) )
101 {
102 mComboRelation->setCurrentIndex( mComboRelation->findData( config.value( QStringLiteral( "Relation" ) ).toString() ) );
103 relationChanged( mComboRelation->currentIndex() );
104 }
105
106 mCbxMapIdentification->setChecked( config.value( QStringLiteral( "MapIdentification" ), false ).toBool() );
107 mCbxAllowAddFeatures->setChecked( config.value( QStringLiteral( "AllowAddFeatures" ), false ).toBool() );
108 mCbxReadOnly->setChecked( config.value( QStringLiteral( "ReadOnly" ), false ).toBool() );
109 mFilterExpression->setPlainText( config.value( QStringLiteral( "FilterExpression" ) ).toString() );
110
111 if ( config.contains( QStringLiteral( "FilterFields" ) ) )
112 {
113 mFilterGroupBox->setChecked( true );
114 const auto constToStringList = config.value( "FilterFields" ).toStringList();
115 for ( const QString &fld : constToStringList )
116 {
117 addFilterField( fld );
118 }
119
120 mCbxChainFilters->setChecked( config.value( QStringLiteral( "ChainFilters" ) ).toBool() );
121 }
122 }
123
relationChanged(int idx)124 void QgsRelationReferenceConfigDlg::relationChanged( int idx )
125 {
126 QString relName = mComboRelation->itemData( idx ).toString();
127 QgsRelation rel = QgsProject::instance()->relationManager()->relation( relName );
128
129 mReferencedLayer = rel.referencedLayer();
130 mExpressionWidget->setLayer( mReferencedLayer ); // set even if 0
131 if ( mReferencedLayer )
132 {
133 mExpressionWidget->setField( mReferencedLayer->displayExpression() );
134 mCbxMapIdentification->setEnabled( mReferencedLayer->isSpatial() );
135 }
136
137 loadFields();
138 }
139
mAddFilterButton_clicked()140 void QgsRelationReferenceConfigDlg::mAddFilterButton_clicked()
141 {
142 const auto constSelectedItems = mAvailableFieldsList->selectedItems();
143 for ( QListWidgetItem *item : constSelectedItems )
144 {
145 addFilterField( item );
146 }
147 }
148
mRemoveFilterButton_clicked()149 void QgsRelationReferenceConfigDlg::mRemoveFilterButton_clicked()
150 {
151 const auto constSelectedItems = mFilterFieldsList->selectedItems();
152 for ( QListWidgetItem *item : constSelectedItems )
153 {
154 mFilterFieldsList->takeItem( indexFromListWidgetItem( item ) );
155 mAvailableFieldsList->addItem( item );
156 }
157 }
158
config()159 QVariantMap QgsRelationReferenceConfigDlg::config()
160 {
161 QVariantMap myConfig;
162 myConfig.insert( QStringLiteral( "AllowNULL" ), mCbxAllowNull->isChecked() );
163 myConfig.insert( QStringLiteral( "OrderByValue" ), mCbxOrderByValue->isChecked() );
164 myConfig.insert( QStringLiteral( "ShowForm" ), mCbxShowForm->isChecked() );
165 myConfig.insert( QStringLiteral( "ShowOpenFormButton" ), mCbxShowOpenFormButton->isChecked() );
166 myConfig.insert( QStringLiteral( "MapIdentification" ), mCbxMapIdentification->isEnabled() && mCbxMapIdentification->isChecked() );
167 myConfig.insert( QStringLiteral( "ReadOnly" ), mCbxReadOnly->isChecked() );
168 myConfig.insert( QStringLiteral( "Relation" ), mComboRelation->currentData() );
169 myConfig.insert( QStringLiteral( "AllowAddFeatures" ), mCbxAllowAddFeatures->isChecked() );
170
171 if ( mFilterGroupBox->isChecked() )
172 {
173 QStringList filterFields;
174 filterFields.reserve( mFilterFieldsList->count() );
175 for ( int i = 0; i < mFilterFieldsList->count(); i++ )
176 {
177 filterFields << mFilterFieldsList->item( i )->data( Qt::UserRole ).toString();
178 }
179 myConfig.insert( QStringLiteral( "FilterFields" ), filterFields );
180
181 myConfig.insert( QStringLiteral( "ChainFilters" ), mCbxChainFilters->isChecked() );
182 myConfig.insert( QStringLiteral( "FilterExpression" ), mFilterExpression->toPlainText() );
183 }
184
185 if ( mReferencedLayer )
186 {
187 // Store referenced layer data source and provider
188 myConfig.insert( QStringLiteral( "ReferencedLayerDataSource" ), mReferencedLayer->publicSource() );
189 myConfig.insert( QStringLiteral( "ReferencedLayerProviderKey" ), mReferencedLayer->providerType() );
190 myConfig.insert( QStringLiteral( "ReferencedLayerId" ), mReferencedLayer->id() );
191 myConfig.insert( QStringLiteral( "ReferencedLayerName" ), mReferencedLayer->name() );
192 mReferencedLayer->setDisplayExpression( mExpressionWidget->currentField() );
193 }
194
195 return myConfig;
196 }
197
loadFields()198 void QgsRelationReferenceConfigDlg::loadFields()
199 {
200 mAvailableFieldsList->clear();
201 mFilterFieldsList->clear();
202
203 if ( mReferencedLayer )
204 {
205 QgsVectorLayer *l = mReferencedLayer;
206 const QgsFields &flds = l->fields();
207 for ( int i = 0; i < flds.count(); i++ )
208 {
209 mAvailableFieldsList->addItem( flds.at( i ).displayName() );
210 mAvailableFieldsList->item( mAvailableFieldsList->count() - 1 )->setData( Qt::UserRole, flds.at( i ).name() );
211 }
212 }
213 }
214
addFilterField(const QString & field)215 void QgsRelationReferenceConfigDlg::addFilterField( const QString &field )
216 {
217 for ( int i = 0; i < mAvailableFieldsList->count(); i++ )
218 {
219 if ( mAvailableFieldsList->item( i )->data( Qt::UserRole ).toString() == field )
220 {
221 addFilterField( mAvailableFieldsList->item( i ) );
222 break;
223 }
224 }
225 }
226
addFilterField(QListWidgetItem * item)227 void QgsRelationReferenceConfigDlg::addFilterField( QListWidgetItem *item )
228 {
229 mAvailableFieldsList->takeItem( indexFromListWidgetItem( item ) );
230 mFilterFieldsList->addItem( item );
231 }
232
indexFromListWidgetItem(QListWidgetItem * item)233 int QgsRelationReferenceConfigDlg::indexFromListWidgetItem( QListWidgetItem *item )
234 {
235 QListWidget *lw = item->listWidget();
236
237 for ( int i = 0; i < lw->count(); i++ )
238 {
239 if ( lw->item( i ) == item )
240 return i;
241 }
242
243 return -1;
244 }
245