1 /***************************************************************************
2     testqgsvaluerelationwidgetwrapper.cpp
3      --------------------------------------
4     Date                 : 21 07 2017
5     Copyright            : (C) 2017 Paul Blottiere
6     Email                : paul dot blottiere at oslandia dot com
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 
17 #include "qgstest.h"
18 #include <QScrollBar>
19 #include <QSignalSpy>
20 
21 #include <editorwidgets/core/qgseditorwidgetregistry.h>
22 #include <qgsapplication.h>
23 #include <qgsproject.h>
24 #include <qgsvectorlayer.h>
25 #include "qgseditorwidgetwrapper.h"
26 #include <editorwidgets/qgsvaluerelationwidgetwrapper.h>
27 #include <QTableWidget>
28 #include <QComboBox>
29 #include "qgsgui.h"
30 #include <gdal_version.h>
31 #include <nlohmann/json.hpp>
32 
33 class TestQgsValueRelationWidgetWrapper : public QObject
34 {
35     Q_OBJECT
36   public:
37     TestQgsValueRelationWidgetWrapper() = default;
38 
39   private:
40     QTemporaryDir tempDir;
41 
42   private slots:
43     void initTestCase(); // will be called before the first testfunction is executed.
44     void cleanupTestCase(); // will be called after the last testfunction was executed.
45     void init(); // will be called before each testfunction is executed.
46     void cleanup(); // will be called after every testfunction.
47 
48     void testScrollBarUnlocked();
49     void testDrillDown();
50     void testDrillDownMulti();
51     //! Checks that a related value of 0 is not interpreted as a NULL
52     void testZeroIndexInRelatedTable();
53     void testWithJsonInPostgres();
54     void testWithJsonInGPKG();
55     void testWithTextInGPKG();
56     void testWithTextInGPKGTextFk();
57     void testWithTextInGPKGWeirdTextFk();
58     void testWithJsonInSpatialite();
59     void testWithJsonInSpatialiteTextFk();
60     void testMatchLayerName();
61     //! Check that setFeature works correctly after regression #42003
62     void testRegressionGH42003();
63 };
64 
initTestCase()65 void TestQgsValueRelationWidgetWrapper::initTestCase()
66 {
67   QgsApplication::init();
68   QgsApplication::initQgis();
69   QgsGui::editorWidgetRegistry()->initEditors();
70 }
71 
cleanupTestCase()72 void TestQgsValueRelationWidgetWrapper::cleanupTestCase()
73 {
74   QgsApplication::exitQgis();
75 }
76 
init()77 void TestQgsValueRelationWidgetWrapper::init()
78 {
79 }
80 
cleanup()81 void TestQgsValueRelationWidgetWrapper::cleanup()
82 {
83 
84 }
85 
testScrollBarUnlocked()86 void TestQgsValueRelationWidgetWrapper::testScrollBarUnlocked()
87 {
88   // create a vector layer
89   QgsVectorLayer vl1( QStringLiteral( "LineString?crs=epsg:3111&field=pk:int&field=fk|:int" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) );
90   QgsProject::instance()->addMapLayer( &vl1, false, false );
91 
92   // build a value relation widget wrapper
93   QgsValueRelationWidgetWrapper w( &vl1, 0, nullptr, nullptr );
94 
95   QVariantMap config;
96   config.insert( QStringLiteral( "AllowMulti" ), true );
97   w.setConfig( config );
98   w.widget();
99   w.setEnabled( true );
100 
101   // add an item virtually
102   QTableWidgetItem item;
103   item.setText( QStringLiteral( "MyText" ) );
104   w.mTableWidget->setItem( 0, 0, &item );
105 
106   QCOMPARE( w.mTableWidget->item( 0, 0 )->text(), QString( "MyText" ) );
107 
108   // when the widget wrapper is enabled, the container should be enabled
109   // as well as items
110   w.setEnabled( true );
111 
112   QCOMPARE( w.widget()->isEnabled(), true );
113 
114   bool itemEnabled = w.mTableWidget->item( 0, 0 )->flags() & Qt::ItemIsEnabled;
115   QCOMPARE( itemEnabled, true );
116 
117   // when the widget wrapper is disabled, the container should still be enabled
118   // to keep the scrollbar available but items should be disabled to avoid
119   // edition
120   w.setEnabled( false );
121 
122   itemEnabled = w.mTableWidget->item( 0, 0 )->flags() & Qt::ItemIsEnabled;
123   QCOMPARE( itemEnabled, false );
124 
125   QCOMPARE( w.widget()->isEnabled(), true );
126 
127   // recheck after re-enabled
128   w.setEnabled( true );
129 
130   QCOMPARE( w.widget()->isEnabled(), true );
131   itemEnabled = w.mTableWidget->item( 0, 0 )->flags() & Qt::ItemIsEnabled;
132   QCOMPARE( itemEnabled, true );
133 }
134 
testDrillDown()135 void TestQgsValueRelationWidgetWrapper::testDrillDown()
136 {
137   // create a vector layer
138   QgsVectorLayer vl1( QStringLiteral( "Polygon?crs=epsg:4326&field=pk:int&field=province:int&field=municipality:string" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) );
139   QgsVectorLayer vl2( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=fk_province:int&field=fk_municipality:int" ), QStringLiteral( "vl2" ), QStringLiteral( "memory" ) );
140   QgsProject::instance()->addMapLayer( &vl1, false, false );
141   QgsProject::instance()->addMapLayer( &vl2, false, false );
142 
143   // insert some features
144   QgsFeature f1( vl1.fields() );
145   f1.setAttribute( QStringLiteral( "pk" ), 1 );
146   f1.setAttribute( QStringLiteral( "province" ), 123 );
147   f1.setAttribute( QStringLiteral( "municipality" ), QStringLiteral( "Some Place By The River" ) );
148   f1.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POLYGON(( 0 0, 0 1, 1 1, 1 0, 0 0 ))" ) ) );
149   QVERIFY( f1.isValid() );
150   QgsFeature f2( vl1.fields() );
151   f2.setAttribute( QStringLiteral( "pk" ), 2 );
152   f2.setAttribute( QStringLiteral( "province" ), 245 );
153   f2.setAttribute( QStringLiteral( "municipality" ), QStringLiteral( "Dreamland By The Clouds" ) );
154   f2.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POLYGON(( 1 0, 1 1, 2 1, 2 0, 1 0 ))" ) ) );
155   QVERIFY( f2.isValid() );
156   QVERIFY( vl1.dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 ) );
157 
158   QgsFeature f3( vl2.fields() );
159   f3.setAttribute( QStringLiteral( "fk_province" ), 123 );
160   f3.setAttribute( QStringLiteral( "fk_municipality" ), 1 );
161   f3.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POINT( 0.5 0.5)" ) ) );
162   QVERIFY( f3.isValid() );
163   QVERIFY( f3.geometry().isGeosValid() );
164   QVERIFY( vl2.dataProvider()->addFeature( f3 ) );
165 
166   // build a value relation widget wrapper for municipality
167   QgsValueRelationWidgetWrapper w_municipality( &vl2, vl2.fields().indexOf( QLatin1String( "fk_municipality" ) ), nullptr, nullptr );
168   QVariantMap cfg_municipality;
169   cfg_municipality.insert( QStringLiteral( "Layer" ), vl1.id() );
170   cfg_municipality.insert( QStringLiteral( "Key" ),  QStringLiteral( "pk" ) );
171   cfg_municipality.insert( QStringLiteral( "Value" ), QStringLiteral( "municipality" ) );
172   cfg_municipality.insert( QStringLiteral( "AllowMulti" ), false );
173   cfg_municipality.insert( QStringLiteral( "NofColumns" ), 1 );
174   cfg_municipality.insert( QStringLiteral( "AllowNull" ), false );
175   cfg_municipality.insert( QStringLiteral( "OrderByValue" ), true );
176   cfg_municipality.insert( QStringLiteral( "FilterExpression" ), QStringLiteral( "\"province\" = current_value('fk_province')" ) );
177   cfg_municipality.insert( QStringLiteral( "UseCompleter" ), false );
178   w_municipality.setConfig( cfg_municipality );
179   w_municipality.widget();
180   w_municipality.setEnabled( true );
181 
182   QCOMPARE( w_municipality.mCache.size(), 2 );
183   QCOMPARE( w_municipality.mComboBox->count(), 2 );
184 
185   // Set a feature
186   w_municipality.setFeature( vl2.getFeature( 1 ) );
187   QCOMPARE( w_municipality.mCache.size(), 1 );
188   QCOMPARE( w_municipality.mComboBox->count(), 1 );
189 
190   // check that valueChanged signal is correctly triggered
191   const QSignalSpy spy( &w_municipality, &QgsEditorWidgetWrapper::valuesChanged );
192 
193   w_municipality.setFeature( f3 );
194   QCOMPARE( spy.count(), 1 );
195   QCOMPARE( w_municipality.mCache.size(), 1 );
196 
197   // Check first is selected
198   QCOMPARE( w_municipality.mComboBox->count(), 1 );
199   QCOMPARE( w_municipality.mComboBox->itemText( 0 ), QStringLiteral( "Some Place By The River" ) );
200   QCOMPARE( w_municipality.value().toString(), QStringLiteral( "1" ) );
201 
202   // Filter by geometry
203   cfg_municipality[ QStringLiteral( "FilterExpression" ) ] = QStringLiteral( "contains(buffer(@current_geometry, 1 ), $geometry)" );
204   w_municipality.setConfig( cfg_municipality );
205   w_municipality.setFeature( f3 );
206   QCOMPARE( w_municipality.mComboBox->count(), 1 );
207   QCOMPARE( w_municipality.mComboBox->itemText( 0 ), QStringLiteral( "Some Place By The River" ) );
208 
209   // Move the point to 1.5 0.5
210   f3.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POINT( 1.5 0.5)" ) ) );
211   w_municipality.setFeature( f3 );
212   QCOMPARE( w_municipality.mComboBox->count(), 1 );
213   QCOMPARE( w_municipality.mComboBox->itemText( 0 ), QStringLiteral( "Dreamland By The Clouds" ) );
214 
215   // Enlarge the buffer
216   cfg_municipality[ QStringLiteral( "FilterExpression" ) ] = QStringLiteral( "contains(buffer(@current_geometry, 3 ), $geometry)" );
217   w_municipality.setConfig( cfg_municipality );
218   w_municipality.setFeature( f3 );
219   QCOMPARE( w_municipality.mComboBox->count(), 2 );
220   QCOMPARE( w_municipality.mComboBox->itemText( 0 ), QStringLiteral( "Dreamland By The Clouds" ) );
221   QCOMPARE( w_municipality.mComboBox->itemText( 1 ), QStringLiteral( "Some Place By The River" ) );
222 
223   // Check with allow null
224   cfg_municipality[QStringLiteral( "AllowNull" )] = true;
225   w_municipality.setConfig( cfg_municipality );
226   w_municipality.setFeature( QgsFeature() );
227 
228   // Check null is selected
229   QCOMPARE( w_municipality.mComboBox->count(), 3 );
230   QCOMPARE( w_municipality.mComboBox->itemText( 0 ), QStringLiteral( "(no selection)" ) );
231   QVERIFY( w_municipality.value().isNull() );
232   QCOMPARE( w_municipality.value().toString(), QString() );
233 
234   // Check order by value false
235   cfg_municipality[QStringLiteral( "AllowNull" )] = false;
236   cfg_municipality[QStringLiteral( "OrderByValue" )] = false;
237   w_municipality.setConfig( cfg_municipality );
238   w_municipality.setFeature( f3 );
239   QCOMPARE( w_municipality.mComboBox->itemText( 1 ), QStringLiteral( "Dreamland By The Clouds" ) );
240   QCOMPARE( w_municipality.mComboBox->itemText( 0 ), QStringLiteral( "Some Place By The River" ) );
241 
242 }
243 
testDrillDownMulti()244 void TestQgsValueRelationWidgetWrapper::testDrillDownMulti()
245 {
246   // create a vector layer
247   QgsVectorLayer vl1( QStringLiteral( "Polygon?crs=epsg:4326&field=pk:int&field=province:int&field=municipality:string" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) );
248   QgsVectorLayer vl2( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=fk_province:int&field=fk_municipality:string" ), QStringLiteral( "vl2" ), QStringLiteral( "memory" ) );
249   QgsProject::instance()->addMapLayer( &vl1, false, false );
250   QgsProject::instance()->addMapLayer( &vl2, false, false );
251 
252   // insert some features
253   QgsFeature f1( vl1.fields() );
254   f1.setAttribute( QStringLiteral( "pk" ), 1 );
255   f1.setAttribute( QStringLiteral( "province" ), 123 );
256   f1.setAttribute( QStringLiteral( "municipality" ), QStringLiteral( "Some Place By The River" ) );
257   f1.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POLYGON(( 0 0, 0 1, 1 1, 1 0, 0 0 ))" ) ) );
258   QVERIFY( f1.isValid() );
259   QgsFeature f2( vl1.fields() );
260   f2.setAttribute( QStringLiteral( "pk" ), 2 );
261   f2.setAttribute( QStringLiteral( "province" ), 245 );
262   f2.setAttribute( QStringLiteral( "municipality" ), QStringLiteral( "Dreamland By The Clouds" ) );
263   f2.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POLYGON(( 1 0, 1 1, 2 1, 2 0, 1 0 ))" ) ) );
264   QVERIFY( f2.isValid() );
265   QVERIFY( vl1.dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 ) );
266 
267   QgsFeature f3( vl2.fields() );
268   f3.setAttribute( QStringLiteral( "fk_province" ), 123 );
269   f3.setAttribute( QStringLiteral( "fk_municipality" ), QStringLiteral( "{1}" ) );
270   f3.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POINT( 0.5 0.5)" ) ) );
271   QVERIFY( f3.isValid() );
272   QVERIFY( f3.geometry().isGeosValid() );
273   QVERIFY( vl2.dataProvider()->addFeature( f3 ) );
274 
275   // build a value relation widget wrapper for municipality
276   QgsValueRelationWidgetWrapper w_municipality( &vl2, vl2.fields().indexOf( QLatin1String( "fk_municipality" ) ), nullptr, nullptr );
277   QVariantMap cfg_municipality;
278   cfg_municipality.insert( QStringLiteral( "Layer" ), vl1.id() );
279   cfg_municipality.insert( QStringLiteral( "Key" ),  QStringLiteral( "pk" ) );
280   cfg_municipality.insert( QStringLiteral( "Value" ), QStringLiteral( "municipality" ) );
281   cfg_municipality.insert( QStringLiteral( "AllowMulti" ), true );
282   cfg_municipality.insert( QStringLiteral( "NofColumns" ), 1 );
283   cfg_municipality.insert( QStringLiteral( "AllowNull" ), false );
284   cfg_municipality.insert( QStringLiteral( "OrderByValue" ), true );
285   cfg_municipality.insert( QStringLiteral( "FilterExpression" ), QStringLiteral( "\"province\" =  current_value('fk_province')" ) );
286   cfg_municipality.insert( QStringLiteral( "UseCompleter" ), false );
287   w_municipality.setConfig( cfg_municipality );
288   w_municipality.widget();
289   w_municipality.setEnabled( true );
290 
291   QCOMPARE( w_municipality.mCache.size(), 2 );
292   QCOMPARE( w_municipality.mTableWidget->rowCount(), 2 );
293   w_municipality.setFeature( f3 );
294   QCOMPARE( w_municipality.mCache.size(), 1 );
295 
296   QCOMPARE( w_municipality.mTableWidget->rowCount(), 1 );
297   QCOMPARE( w_municipality.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Some Place By The River" ) );
298   QCOMPARE( w_municipality.value(), QVariant( QStringLiteral( "{1}" ) ) );
299 
300   // Filter by geometry
301   cfg_municipality[ QStringLiteral( "FilterExpression" ) ] = QStringLiteral( "contains(buffer(@current_geometry, 1 ), $geometry)" );
302   w_municipality.setConfig( cfg_municipality );
303   w_municipality.setFeature( f3 );
304   QCOMPARE( w_municipality.mTableWidget->rowCount(), 1 );
305   QCOMPARE( w_municipality.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Some Place By The River" ) );
306 
307   // Move the point to 1.5 0.5
308   f3.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POINT( 1.5 0.5)" ) ) );
309   w_municipality.setFeature( f3 );
310   QCOMPARE( w_municipality.mTableWidget->rowCount(), 1 );
311   QCOMPARE( w_municipality.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Dreamland By The Clouds" ) );
312 
313   // Enlarge the buffer
314   cfg_municipality[ QStringLiteral( "FilterExpression" ) ] = QStringLiteral( "contains(buffer(@current_geometry, 3 ), $geometry)" );
315   w_municipality.setConfig( cfg_municipality );
316   w_municipality.setFeature( f3 );
317   QCOMPARE( w_municipality.mTableWidget->rowCount(), 2 );
318   QCOMPARE( w_municipality.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Dreamland By The Clouds" ) );
319   QCOMPARE( w_municipality.mTableWidget->item( 0, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "2" ) );
320   QCOMPARE( w_municipality.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Some Place By The River" ) );
321   QCOMPARE( w_municipality.mTableWidget->item( 1, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "1" ) );
322   QCOMPARE( w_municipality.value(), QVariant( QStringLiteral( "{1}" ) ) );
323   QCOMPARE( w_municipality.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
324   QCOMPARE( w_municipality.mTableWidget->item( 1, 0 )->checkState(), Qt::Checked );
325   w_municipality.setValues( QStringLiteral( "{1,2}" ), QVariantList() );
326   QCOMPARE( w_municipality.value(), QVariant( QStringLiteral( "{2,1}" ) ) );
327   QCOMPARE( w_municipality.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
328   QCOMPARE( w_municipality.mTableWidget->item( 1, 0 )->checkState(), Qt::Checked );
329 
330   // Check with passing a variant list
331   w_municipality.setValues( QVariantList( {1, 2} ), QVariantList() );
332   QCOMPARE( w_municipality.value(), QVariant( QStringLiteral( "{2,1}" ) ) );
333 
334   // Check values are checked
335   f3.setAttribute( QStringLiteral( "fk_municipality" ), QStringLiteral( "{1,2}" ) );
336   w_municipality.setFeature( f3 );
337   QCOMPARE( w_municipality.mTableWidget->rowCount(), 2 );
338   QCOMPARE( w_municipality.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Dreamland By The Clouds" ) );
339   QCOMPARE( w_municipality.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Some Place By The River" ) );
340   QCOMPARE( w_municipality.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
341   QCOMPARE( w_municipality.mTableWidget->item( 1, 0 )->checkState(), Qt::Checked );
342   QCOMPARE( w_municipality.value(), QVariant( QStringLiteral( "{2,1}" ) ) );
343 }
344 
testZeroIndexInRelatedTable()345 void TestQgsValueRelationWidgetWrapper::testZeroIndexInRelatedTable()
346 {
347   // findData fails to tell a 0 from a NULL
348   // See: "Value relation, value 0 = NULL" - https://github.com/qgis/QGIS/issues/27803
349 
350   // create a vector layer
351   QgsVectorLayer vl1( QStringLiteral( "Polygon?crs=epsg:4326&field=pk:int&field=province:int&field=municipality:string" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) );
352   QgsVectorLayer vl2( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=fk_province:int&field=fk_municipality:int" ), QStringLiteral( "vl2" ), QStringLiteral( "memory" ) );
353   QgsProject::instance()->addMapLayer( &vl1, false, false );
354   QgsProject::instance()->addMapLayer( &vl2, false, false );
355 
356   // insert some features
357   QgsFeature f1( vl1.fields() );
358   f1.setAttribute( QStringLiteral( "pk" ), 0 );  // !!! Notice: pk 0
359   f1.setAttribute( QStringLiteral( "province" ), 123 );
360   f1.setAttribute( QStringLiteral( "municipality" ), QStringLiteral( "Some Place By The River" ) );
361   f1.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POLYGON(( 0 0, 0 1, 1 1, 1 0, 0 0 ))" ) ) );
362   QVERIFY( f1.isValid() );
363   QgsFeature f2( vl1.fields() );
364   f2.setAttribute( QStringLiteral( "pk" ), 2 );
365   f2.setAttribute( QStringLiteral( "province" ), 245 );
366   f2.setAttribute( QStringLiteral( "municipality" ), QStringLiteral( "Dreamland By The Clouds" ) );
367   f2.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POLYGON(( 1 0, 1 1, 2 1, 2 0, 1 0 ))" ) ) );
368   QVERIFY( f2.isValid() );
369   QVERIFY( vl1.dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 ) );
370 
371   QgsFeature f3( vl2.fields() );
372   f3.setAttribute( QStringLiteral( "fk_province" ), 123 );
373   f3.setAttribute( QStringLiteral( "fk_municipality" ), QStringLiteral( "0" ) );
374   f3.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POINT( 0.5 0.5)" ) ) );
375   QVERIFY( f3.isValid() );
376   QVERIFY( f3.geometry().isGeosValid() );
377   QVERIFY( vl2.dataProvider()->addFeature( f3 ) );
378 
379   // build a value relation widget wrapper for municipality
380   QgsValueRelationWidgetWrapper w_municipality( &vl2, vl2.fields().indexOf( QLatin1String( "fk_municipality" ) ), nullptr, nullptr );
381   QVariantMap cfg_municipality;
382   cfg_municipality.insert( QStringLiteral( "Layer" ), vl1.id() );
383   cfg_municipality.insert( QStringLiteral( "Key" ),  QStringLiteral( "pk" ) );
384   cfg_municipality.insert( QStringLiteral( "Value" ), QStringLiteral( "municipality" ) );
385   cfg_municipality.insert( QStringLiteral( "AllowMulti" ), false );
386   cfg_municipality.insert( QStringLiteral( "NofColumns" ), 1 );
387   cfg_municipality.insert( QStringLiteral( "AllowNull" ), true );
388   cfg_municipality.insert( QStringLiteral( "OrderByValue" ), false );
389   cfg_municipality.insert( QStringLiteral( "UseCompleter" ), false );
390   w_municipality.setConfig( cfg_municipality );
391   w_municipality.widget();
392   w_municipality.setEnabled( true );
393 
394   w_municipality.setValues( 0, QVariantList() );
395   QCOMPARE( w_municipality.mComboBox->currentIndex(), 1 );
396   QCOMPARE( w_municipality.mComboBox->currentText(), QStringLiteral( "Some Place By The River" ) );
397 }
398 
testWithJsonInPostgres()399 void TestQgsValueRelationWidgetWrapper::testWithJsonInPostgres()
400 {
401 #ifdef ENABLE_PGTEST
402   //this is only reading
403 
404   // create pg layers
405   QString dbConn = getenv( "QGIS_PGTEST_DB" );
406   if ( dbConn.isEmpty() )
407   {
408     dbConn = "service=\"qgis_test\"";
409   }
410   QgsVectorLayer *vl_json = new QgsVectorLayer( QStringLiteral( "%1 sslmode=disable key=\"pk\" table=\"qgis_test\".\"json\" sql=" ).arg( dbConn ), QStringLiteral( "json" ), QStringLiteral( "postgres" ) );
411   QgsVectorLayer *vl_authors = new QgsVectorLayer( QStringLiteral( "%1 sslmode=disable key='pk' table=\"qgis_test\".\"authors\" sql=" ).arg( dbConn ), QStringLiteral( "authors" ), QStringLiteral( "postgres" ) );
412   QVERIFY( vl_json->isValid() );
413   QVERIFY( vl_authors->isValid() );
414 
415   QgsProject::instance()->addMapLayer( vl_json, false, false );
416   QgsProject::instance()->addMapLayer( vl_authors, false, false );
417 
418   QCOMPARE( vl_json->fields().at( 1 ).type(), QVariant::Map );
419 
420   // build a value relation widget wrapper for json field
421   QgsValueRelationWidgetWrapper w_favoriteauthors( vl_json, vl_json->fields().indexOf( QLatin1String( "jvalue" ) ), nullptr, nullptr );
422   QVariantMap cfg_favoriteauthors;
423   cfg_favoriteauthors.insert( QStringLiteral( "Layer" ), vl_authors->id() );
424   cfg_favoriteauthors.insert( QStringLiteral( "Key" ),  QStringLiteral( "pk" ) );
425   cfg_favoriteauthors.insert( QStringLiteral( "Value" ), QStringLiteral( "name" ) );
426   cfg_favoriteauthors.insert( QStringLiteral( "AllowMulti" ), true );
427   cfg_favoriteauthors.insert( QStringLiteral( "NofColumns" ), 1 );
428   cfg_favoriteauthors.insert( QStringLiteral( "AllowNull" ), false );
429   cfg_favoriteauthors.insert( QStringLiteral( "OrderByValue" ), false );
430   cfg_favoriteauthors.insert( QStringLiteral( "UseCompleter" ), false );
431   w_favoriteauthors.setConfig( cfg_favoriteauthors );
432   w_favoriteauthors.widget();
433   w_favoriteauthors.setEnabled( true );
434 
435   //check if set up nice
436   QCOMPARE( w_favoriteauthors.mTableWidget->rowCount(), 7 );
437   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
438   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "1" ) );
439   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
440   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "2" ) );
441   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
442   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "3" ) );
443   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
444   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "4" ) );
445   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
446   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "5" ) );
447   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
448   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "6" ) );
449 
450   //check if first feature checked correctly (should be 1,2,3 and the rest is not)
451   w_favoriteauthors.setFeature( vl_json->getFeature( 1 ) );
452   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
453   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
454   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
455   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Checked );
456   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
457   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
458   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
459   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
460   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
461   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
462   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
463   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
464 
465   // build a value relation widget wrapper for jsonb field
466   QgsValueRelationWidgetWrapper w_favoriteauthors_b( vl_json, vl_json->fields().indexOf( QLatin1String( "jbvalue" ) ), nullptr, nullptr );
467   QVariantMap cfg_favoriteauthors_b;
468   cfg_favoriteauthors_b.insert( QStringLiteral( "Layer" ), vl_authors->id() );
469   cfg_favoriteauthors_b.insert( QStringLiteral( "Key" ),  QStringLiteral( "pk" ) );
470   cfg_favoriteauthors_b.insert( QStringLiteral( "Value" ), QStringLiteral( "name" ) );
471   cfg_favoriteauthors_b.insert( QStringLiteral( "AllowMulti" ), true );
472   cfg_favoriteauthors_b.insert( QStringLiteral( "NofColumns" ), 1 );
473   cfg_favoriteauthors_b.insert( QStringLiteral( "AllowNull" ), false );
474   cfg_favoriteauthors_b.insert( QStringLiteral( "OrderByValue" ), false );
475   cfg_favoriteauthors_b.insert( QStringLiteral( "UseCompleter" ), false );
476   w_favoriteauthors_b.setConfig( cfg_favoriteauthors_b );
477   w_favoriteauthors_b.widget();
478   w_favoriteauthors_b.setEnabled( true );
479 
480   //check if set up nice
481   QCOMPARE( w_favoriteauthors_b.mTableWidget->rowCount(), 7 );
482   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
483   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 0, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "1" ) );
484   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
485   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 1, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "2" ) );
486   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
487   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 2, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "3" ) );
488   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
489   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 3, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "4" ) );
490   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
491   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 4, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "5" ) );
492   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
493   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 5, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "6" ) );
494 
495   //check if second feature checked correctly (should be 4,5,6 and the rest is not)
496   w_favoriteauthors_b.setFeature( vl_json->getFeature( 1 ) );
497   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
498   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
499   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
500   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
501   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
502   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
503   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
504   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 3, 0 )->checkState(), Qt::Checked );
505   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
506   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
507   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
508   QCOMPARE( w_favoriteauthors_b.mTableWidget->item( 5, 0 )->checkState(), Qt::Checked );
509 
510   // check value from widget wrapper
511   QCOMPARE( w_favoriteauthors_b.value().toStringList(), QStringList() << "4" << "5" << "6" );
512 #endif
513 }
514 
testWithJsonInGPKG()515 void TestQgsValueRelationWidgetWrapper::testWithJsonInGPKG()
516 {
517   // create ogr gpkg layers
518   const QString myFileName( TEST_DATA_DIR ); //defined in CmakeLists.txt
519   const QString myTempDirName = tempDir.path();
520   QFile::copy( myFileName + "/provider/test_json.gpkg", myTempDirName + "/test_json.gpkg" );
521   const QString myTempFileName = myTempDirName + "/test_json.gpkg";
522   const QFileInfo myMapFileInfo( myTempFileName );
523   QgsVectorLayer *vl_json = new QgsVectorLayer( myMapFileInfo.filePath() + "|layername=foo", "test", QStringLiteral( "ogr" ) );
524   QgsVectorLayer *vl_authors = new QgsVectorLayer( myMapFileInfo.filePath() + "|layername=author", "test", QStringLiteral( "ogr" ) );
525   QVERIFY( vl_json->isValid() );
526   QVERIFY( vl_authors->isValid() );
527 
528   QgsProject::instance()->addMapLayer( vl_json, false, false );
529   QgsProject::instance()->addMapLayer( vl_authors, false, false );
530   vl_json->startEditing();
531 
532   // build a value relation widget wrapper for authors
533   QgsValueRelationWidgetWrapper w_favoriteauthors( vl_json, vl_json->fields().indexOf( QLatin1String( "json_content" ) ), nullptr, nullptr );
534   QVariantMap cfg_favoriteauthors;
535   cfg_favoriteauthors.insert( QStringLiteral( "Layer" ), vl_authors->id() );
536   cfg_favoriteauthors.insert( QStringLiteral( "Key" ),  QStringLiteral( "fid" ) );
537   cfg_favoriteauthors.insert( QStringLiteral( "Value" ), QStringLiteral( "NAME" ) );
538   cfg_favoriteauthors.insert( QStringLiteral( "AllowMulti" ), true );
539   cfg_favoriteauthors.insert( QStringLiteral( "NofColumns" ), 1 );
540   cfg_favoriteauthors.insert( QStringLiteral( "AllowNull" ), false );
541   cfg_favoriteauthors.insert( QStringLiteral( "OrderByValue" ), false );
542   cfg_favoriteauthors.insert( QStringLiteral( "UseCompleter" ), false );
543   w_favoriteauthors.setConfig( cfg_favoriteauthors );
544   w_favoriteauthors.widget();
545   w_favoriteauthors.setEnabled( true );
546 
547   //check if set up nice
548   QCOMPARE( w_favoriteauthors.mTableWidget->rowCount(), 6 );
549   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
550   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "1" ) );
551   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
552   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "2" ) );
553   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
554   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "3" ) );
555   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
556   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "4" ) );
557   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
558   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "5" ) );
559   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
560   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "6" ) );
561 
562   w_favoriteauthors.setFeature( vl_json->getFeature( 1 ) );
563 
564   //check if first feature checked correctly (none)
565   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
566   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
567   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
568   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
569   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
570   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
571   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
572   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
573   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
574   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
575   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
576   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
577 
578   //check other authors
579   w_favoriteauthors.mTableWidget->item( 0, 0 )->setCheckState( Qt::Checked );
580   w_favoriteauthors.mTableWidget->item( 2, 0 )->setCheckState( Qt::Checked );
581   w_favoriteauthors.mTableWidget->item( 4, 0 )->setCheckState( Qt::Checked );
582 
583   //check if first feature checked correctly 0, 2, 4 (means the fids 1, 3, 5)
584   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
585   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
586   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
587   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
588   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
589   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
590   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
591   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
592   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
593   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
594   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
595   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
596 
597   //we do jump over the part with QgsAttributeForm::saveEdits
598   vl_json->changeAttributeValue( 1, 4, w_favoriteauthors.value() );
599 
600   w_favoriteauthors.setFeature( vl_json->getFeature( 2 ) );
601   //check if second feature checked correctly (none)
602   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
603   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
604   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
605   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
606   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
607   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
608   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
609   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
610   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
611   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
612   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
613   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
614 
615   w_favoriteauthors.setFeature( vl_json->getFeature( 1 ) );
616   //check if first feature checked correctly 0, 2, 4
617   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
618   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
619   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
620   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
621   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
622   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
623   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
624   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
625   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
626   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
627   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
628   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
629 
630   // check if stored correctly
631   vl_json->commitChanges();
632   QVariantList expected_vl;
633   expected_vl << "1" << "3" << "5";
634 
635   const QgsFeature f = vl_json->getFeature( 1 );
636   const QVariant attribute = f.attribute( QStringLiteral( "json_content" ) );
637   const QList<QVariant> value = attribute.toList();
638   QCOMPARE( value, expected_vl );
639 }
640 
641 // Same test procedure like in testWithJsonInGPKG to check the non-json way of storing multi-selections into formatted strings
testWithTextInGPKG()642 void TestQgsValueRelationWidgetWrapper::testWithTextInGPKG()
643 {
644   // create ogr gpkg layers
645   const QString myFileName( TEST_DATA_DIR ); //defined in CmakeLists.txt
646   const QString myTempDirName = tempDir.path();
647   QFile::copy( myFileName + "/provider/test_json.gpkg", myTempDirName + "/test_json.gpkg" );
648   const QString myTempFileName = myTempDirName + "/test_json.gpkg";
649   const QFileInfo myMapFileInfo( myTempFileName );
650   QgsVectorLayer *vl_text = new QgsVectorLayer( myMapFileInfo.filePath() + "|layername=foo", "test", QStringLiteral( "ogr" ) );
651   QgsVectorLayer *vl_authors = new QgsVectorLayer( myMapFileInfo.filePath() + "|layername=author", "test", QStringLiteral( "ogr" ) );
652   QVERIFY( vl_text->isValid() );
653   QVERIFY( vl_authors->isValid() );
654 
655   QgsProject::instance()->addMapLayer( vl_text, false, false );
656   QgsProject::instance()->addMapLayer( vl_authors, false, false );
657   vl_text->startEditing();
658 
659   // build a value relation widget wrapper for authors
660   QgsValueRelationWidgetWrapper w_favoriteauthors( vl_text, vl_text->fields().indexOf( QLatin1String( "PRFEDEA" ) ), nullptr, nullptr );
661   QVariantMap cfg_favoriteauthors;
662   cfg_favoriteauthors.insert( QStringLiteral( "Layer" ), vl_authors->id() );
663   cfg_favoriteauthors.insert( QStringLiteral( "Key" ),  QStringLiteral( "fid" ) );
664   cfg_favoriteauthors.insert( QStringLiteral( "Value" ), QStringLiteral( "NAME" ) );
665   cfg_favoriteauthors.insert( QStringLiteral( "AllowMulti" ), true );
666   cfg_favoriteauthors.insert( QStringLiteral( "NofColumns" ), 1 );
667   cfg_favoriteauthors.insert( QStringLiteral( "AllowNull" ), false );
668   cfg_favoriteauthors.insert( QStringLiteral( "OrderByValue" ), false );
669   cfg_favoriteauthors.insert( QStringLiteral( "UseCompleter" ), false );
670   w_favoriteauthors.setConfig( cfg_favoriteauthors );
671   w_favoriteauthors.widget();
672   w_favoriteauthors.setEnabled( true );
673 
674   //check if set up nice
675   QCOMPARE( w_favoriteauthors.mTableWidget->rowCount(), 6 );
676   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
677   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "1" ) );
678   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
679   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "2" ) );
680   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
681   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "3" ) );
682   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
683   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "4" ) );
684   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
685   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "5" ) );
686   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
687   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "6" ) );
688 
689   w_favoriteauthors.setFeature( vl_text->getFeature( 1 ) );
690 
691   //check if first feature checked correctly (none)
692   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
693   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
694   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
695   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
696   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
697   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
698   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
699   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
700   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
701   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
702   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
703   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
704 
705   //check other authors
706   w_favoriteauthors.mTableWidget->item( 0, 0 )->setCheckState( Qt::Checked );
707   w_favoriteauthors.mTableWidget->item( 2, 0 )->setCheckState( Qt::Checked );
708   w_favoriteauthors.mTableWidget->item( 4, 0 )->setCheckState( Qt::Checked );
709 
710   //check if first feature checked correctly 0, 2, 4 (means the fids 1, 3, 5)
711   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
712   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
713   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
714   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
715   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
716   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
717   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
718   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
719   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
720   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
721   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
722   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
723 
724   //we do jump over the part with QgsAttributeForm::saveEdits
725   vl_text->changeAttributeValue( 1, 3, w_favoriteauthors.value() );
726 
727   w_favoriteauthors.setFeature( vl_text->getFeature( 2 ) );
728   //check if second feature checked correctly (none)
729   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
730   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
731   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
732   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
733   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
734   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
735   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
736   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
737   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
738   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
739   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
740   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
741 
742   w_favoriteauthors.setFeature( vl_text->getFeature( 1 ) );
743   //check if first feature checked correctly 0, 2, 4
744   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
745   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
746   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
747   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
748   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
749   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
750   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
751   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
752   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
753   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
754   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
755   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
756 
757   // check if stored correctly
758 
759   vl_text->commitChanges();
760   const QString expected_string QStringLiteral( "{1,3,5}" );
761 
762   const QgsFeature f = vl_text->getFeature( 1 );
763   const QVariant attribute = f.attribute( QStringLiteral( "PRFEDEA" ) );
764   const QString value = attribute.toString();
765   QCOMPARE( value, expected_string );
766 
767   w_favoriteauthors.setFeature( vl_text->getFeature( 1 ) );
768 
769   //check if first feature checked correctly 0, 2, 4 (means the fids 1, 3, 5) after the commit
770   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
771   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
772   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
773   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
774   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
775   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
776   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
777   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
778   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
779   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
780   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
781   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
782 
783   //reread completely
784   QgsVectorLayer *vl_text_reread = new QgsVectorLayer( myMapFileInfo.filePath() + "|layername=foo", "test", QStringLiteral( "ogr" ) );
785   QVERIFY( vl_text_reread->isValid() );
786 
787   QgsProject::instance()->addMapLayer( vl_text_reread, false, false );
788   vl_text_reread->startEditing();
789 
790   // build a value relation widget wrapper for authors
791   QgsValueRelationWidgetWrapper w_favoriteauthors_reread( vl_text_reread, vl_text->fields().indexOf( QLatin1String( "PRFEDEA" ) ), nullptr, nullptr );
792   w_favoriteauthors_reread.setConfig( cfg_favoriteauthors );
793   w_favoriteauthors_reread.widget();
794   w_favoriteauthors_reread.setEnabled( true );
795 
796   w_favoriteauthors_reread.setFeature( vl_text_reread->getFeature( 1 ) );
797 
798   //check if first feature on new layer checked correctly 0, 2, 4 (means the fids 1, 3, 5) after the reread
799   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
800   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
801   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
802   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
803   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
804   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
805   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
806   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
807   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
808   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
809   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
810   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
811 }
812 
813 // Storing of strings as key and handle the quotes
testWithTextInGPKGTextFk()814 void TestQgsValueRelationWidgetWrapper::testWithTextInGPKGTextFk()
815 {
816   // create ogr gpkg layers
817   const QString myFileName( TEST_DATA_DIR ); //defined in CmakeLists.txt
818   const QString myTempDirName = tempDir.path();
819   QFile::copy( myFileName + "/provider/test_json.gpkg", myTempDirName + "/test_json.gpkg" );
820   const QString myTempFileName = myTempDirName + "/test_json.gpkg";
821   const QFileInfo myMapFileInfo( myTempFileName );
822   QgsVectorLayer *vl_text = new QgsVectorLayer( myMapFileInfo.filePath() + "|layername=foo", "test", QStringLiteral( "ogr" ) );
823   QgsVectorLayer *vl_authors = new QgsVectorLayer( myMapFileInfo.filePath() + "|layername=author", "test", QStringLiteral( "ogr" ) );
824   QVERIFY( vl_text->isValid() );
825   QVERIFY( vl_authors->isValid() );
826 
827   QgsProject::instance()->addMapLayer( vl_text, false, false );
828   QgsProject::instance()->addMapLayer( vl_authors, false, false );
829   vl_text->startEditing();
830 
831   // build a value relation widget wrapper for authors
832   QgsValueRelationWidgetWrapper w_favoriteauthors( vl_text, vl_text->fields().indexOf( QLatin1String( "PRFEDEA" ) ), nullptr, nullptr );
833   QVariantMap cfg_favoriteauthors;
834   cfg_favoriteauthors.insert( QStringLiteral( "Layer" ), vl_authors->id() );
835   cfg_favoriteauthors.insert( QStringLiteral( "Key" ),  QStringLiteral( "NAME" ) );
836   cfg_favoriteauthors.insert( QStringLiteral( "Value" ), QStringLiteral( "NAME" ) );
837   cfg_favoriteauthors.insert( QStringLiteral( "AllowMulti" ), true );
838   cfg_favoriteauthors.insert( QStringLiteral( "NofColumns" ), 1 );
839   cfg_favoriteauthors.insert( QStringLiteral( "AllowNull" ), false );
840   cfg_favoriteauthors.insert( QStringLiteral( "OrderByValue" ), false );
841   cfg_favoriteauthors.insert( QStringLiteral( "UseCompleter" ), false );
842   w_favoriteauthors.setConfig( cfg_favoriteauthors );
843   w_favoriteauthors.widget();
844   w_favoriteauthors.setEnabled( true );
845 
846   //check if set up nice
847   QCOMPARE( w_favoriteauthors.mTableWidget->rowCount(), 6 );
848   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
849   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "Douglas Adams" ) );
850   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
851   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "Erich Gamma" ) );
852   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "John Vlissides" ) );
853   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "John Vlissides" ) );
854   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "Ken Follett" ) );
855   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "Ken Follett" ) );
856   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
857   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "Ralph Johnson" ) );
858   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Richard Helm" ) );
859   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "Richard Helm" ) );
860 
861   w_favoriteauthors.setFeature( vl_text->getFeature( 1 ) );
862 
863   //check if first feature checked correctly (none)
864   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
865   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
866   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
867   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
868   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "John Vlissides" ) );
869   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
870   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "Ken Follett" ) );
871   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
872   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
873   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
874   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Richard Helm" ) );
875   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
876 
877   //check other authors 0, 2, 4 (means the names "Douglas Adams", "John Vliessides", "Ralph Johnson")
878   w_favoriteauthors.mTableWidget->item( 0, 0 )->setCheckState( Qt::Checked );
879   w_favoriteauthors.mTableWidget->item( 2, 0 )->setCheckState( Qt::Checked );
880   w_favoriteauthors.mTableWidget->item( 4, 0 )->setCheckState( Qt::Checked );
881 
882   //check if first feature checked correctly 0, 2, 4 (means the names "Douglas Adams", "John Vliessides", "Ralph Johnson")
883   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
884   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
885   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
886   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
887   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "John Vlissides" ) );
888   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
889   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "Ken Follett" ) );
890   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
891   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
892   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
893   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Richard Helm" ) );
894   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
895 
896   //we do jump over the part with QgsAttributeForm::saveEdits
897   vl_text->changeAttributeValue( 1, 3, w_favoriteauthors.value() );
898 
899   w_favoriteauthors.setFeature( vl_text->getFeature( 2 ) );
900   //check if second feature checked correctly (none)
901   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
902   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
903   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
904   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
905   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "John Vlissides" ) );
906   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
907   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "Ken Follett" ) );
908   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
909   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
910   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
911   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Richard Helm" ) );
912   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
913 
914   w_favoriteauthors.setFeature( vl_text->getFeature( 1 ) );
915   //check if first feature checked correctly 0, 2, 4
916   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
917   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
918   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
919   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
920   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "John Vlissides" ) );
921   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
922   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "Ken Follett" ) );
923   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
924   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
925   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
926   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Richard Helm" ) );
927   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
928 
929   // check if stored correctly
930   vl_text->commitChanges();
931   QString expected_string = QStringLiteral( "{\"Douglas Adams\",\"John Vlissides\",\"Ralph Johnson\"}" );
932 
933   QgsFeature f = vl_text->getFeature( 1 );
934   QVariant attribute = f.attribute( QStringLiteral( "PRFEDEA" ) );
935   QString value = attribute.toString();
936   QCOMPARE( value, expected_string );
937 
938   w_favoriteauthors.setFeature( vl_text->getFeature( 1 ) );
939 
940   //check if first feature checked correctly 0, 2, 4 (means the names "Douglas Adams", "John Vliessides", "Ralph Johnson") after the commit
941   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
942   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
943   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
944   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
945   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "John Vlissides" ) );
946   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
947   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "Ken Follett" ) );
948   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
949   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
950   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
951   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Richard Helm" ) );
952   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
953 
954   //reread completely
955   QgsVectorLayer *vl_text_reread = new QgsVectorLayer( myMapFileInfo.filePath() + "|layername=foo", "test", QStringLiteral( "ogr" ) );
956   QVERIFY( vl_text_reread->isValid() );
957 
958   QgsProject::instance()->addMapLayer( vl_text_reread, false, false );
959   vl_text_reread->startEditing();
960 
961   // build a value relation widget wrapper for authors
962   QgsValueRelationWidgetWrapper w_favoriteauthors_reread( vl_text_reread, vl_text_reread->fields().indexOf( QLatin1String( "PRFEDEA" ) ), nullptr, nullptr );
963   w_favoriteauthors_reread.setConfig( cfg_favoriteauthors );
964   w_favoriteauthors_reread.widget();
965   w_favoriteauthors_reread.setEnabled( true );
966 
967   w_favoriteauthors_reread.setFeature( vl_text_reread->getFeature( 1 ) );
968 
969   //check if first feature on new layer checked correctly 0, 2, 4(means the names "Douglas Adams", "John Vliessides", "Ralph Johnson") after the reread
970   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
971   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
972   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
973   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
974   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "John Vlissides" ) );
975   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
976   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "Ken Follett" ) );
977   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
978   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
979   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
980   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Richard Helm" ) );
981   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
982 
983   //we store data wrongly (like it has possibly been on legacy systems)
984   vl_text_reread->changeAttributeValue( 1, 3, "{Douglas Adams,John Vlissides,Ralph Johnson}" );
985 
986   // check if stored correctly
987   vl_text_reread->commitChanges();
988   expected_string = QStringLiteral( "{Douglas Adams,John Vlissides,Ralph Johnson}" );
989 
990   f = vl_text_reread->getFeature( 1 );
991   attribute = f.attribute( QStringLiteral( "PRFEDEA" ) );
992   value = attribute.toString();
993   QCOMPARE( value, expected_string );
994 
995   w_favoriteauthors.setFeature( vl_text_reread->getFeature( 1 ) );
996 
997   //check if first feature checked correctly 0, 2, 4 (means the names "Douglas Adams", "John Vlissides", "Ralph Johnson") after the commit
998   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
999   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
1000   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
1001   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
1002   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "John Vlissides" ) );
1003   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
1004   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "Ken Follett" ) );
1005   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1006   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
1007   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
1008   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Richard Helm" ) );
1009   QCOMPARE( w_favoriteauthors_reread.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1010 
1011   //reread completely
1012   QgsVectorLayer *vl_text_reread2 = new QgsVectorLayer( myMapFileInfo.filePath() + "|layername=foo", "test", QStringLiteral( "ogr" ) );
1013   QVERIFY( vl_text_reread2->isValid() );
1014 
1015   QgsProject::instance()->addMapLayer( vl_text_reread2, false, false );
1016   vl_text_reread2->startEditing();
1017 
1018   // build a value relation widget wrapper for authors
1019   QgsValueRelationWidgetWrapper w_favoriteauthors_reread2( vl_text_reread2, vl_text_reread2->fields().indexOf( QLatin1String( "PRFEDEA" ) ), nullptr, nullptr );
1020   w_favoriteauthors_reread2.setConfig( cfg_favoriteauthors );
1021   w_favoriteauthors_reread2.widget();
1022   w_favoriteauthors_reread2.setEnabled( true );
1023 
1024   w_favoriteauthors_reread2.setFeature( vl_text_reread2->getFeature( 1 ) );
1025 
1026   //check if first feature on new layer checked correctly 0, 2, 4(means the names "Douglas Adams", "John Vliessides", "Ralph Johnson") after the reread
1027   QCOMPARE( w_favoriteauthors_reread2.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
1028   QCOMPARE( w_favoriteauthors_reread2.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
1029   QCOMPARE( w_favoriteauthors_reread2.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
1030   QCOMPARE( w_favoriteauthors_reread2.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
1031   QCOMPARE( w_favoriteauthors_reread2.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "John Vlissides" ) );
1032   QCOMPARE( w_favoriteauthors_reread2.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
1033   QCOMPARE( w_favoriteauthors_reread2.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "Ken Follett" ) );
1034   QCOMPARE( w_favoriteauthors_reread2.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1035   QCOMPARE( w_favoriteauthors_reread2.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
1036   QCOMPARE( w_favoriteauthors_reread2.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
1037   QCOMPARE( w_favoriteauthors_reread2.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Richard Helm" ) );
1038   QCOMPARE( w_favoriteauthors_reread2.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1039 }
1040 
1041 // Storing of strings as key and handle the quotes
testWithTextInGPKGWeirdTextFk()1042 void TestQgsValueRelationWidgetWrapper::testWithTextInGPKGWeirdTextFk()
1043 {
1044   // create ogr gpkg layer for foo (vl_text)
1045   const QString myFileName( TEST_DATA_DIR ); //defined in CmakeLists.txt
1046   const QString myTempDirName = tempDir.path();
1047   QString myTempFileName = myTempDirName + "/test_json.gpkg";
1048   QFile::copy( myFileName + "/provider/test_json.gpkg", myTempFileName );
1049   const QFileInfo myMapFileInfoFoo( myTempFileName );
1050   QgsVectorLayer *vl_text = new QgsVectorLayer( myMapFileInfoFoo.filePath() + "|layername=foo", "test", QStringLiteral( "ogr" ) );
1051   QVERIFY( vl_text->isValid() );
1052 
1053   // create ogr spatialite layer for authors with weird signs (vl_authors)
1054   myTempFileName = myTempDirName + QStringLiteral( "/valuerelation_widget_wrapper_test.spatialite.sqlite" );
1055   QFile::copy( myFileName + QStringLiteral( "/valuerelation_widget_wrapper_test.spatialite.sqlite" ),
1056                myTempFileName );
1057   const QFileInfo myMapFileInfoAuthor( myTempFileName );
1058   QgsVectorLayer *vl_authors = new QgsVectorLayer( QStringLiteral( R"(dbname='%1' table="%2")" )
1059       .arg( myMapFileInfoAuthor.filePath() ).arg( QLatin1String( "authors" ) ),
1060       QStringLiteral( "test" ),
1061       QStringLiteral( "spatialite" ) );
1062   QVERIFY( vl_authors->isValid() );
1063 
1064   QgsProject::instance()->addMapLayer( vl_text, false, false );
1065   QgsProject::instance()->addMapLayer( vl_authors, false, false );
1066   vl_text->startEditing();
1067 
1068   // build a value relation widget wrapper for authors
1069   QgsValueRelationWidgetWrapper w_favoriteauthors( vl_text, vl_text->fields().indexOf( QLatin1String( "PRFEDEA" ) ), nullptr, nullptr );
1070   QVariantMap cfg_favoriteauthors;
1071   cfg_favoriteauthors.insert( QStringLiteral( "Layer" ), vl_authors->id() );
1072   cfg_favoriteauthors.insert( QStringLiteral( "Key" ),  QStringLiteral( "pk_text" ) );
1073   cfg_favoriteauthors.insert( QStringLiteral( "Value" ), QStringLiteral( "name" ) );
1074   cfg_favoriteauthors.insert( QStringLiteral( "AllowMulti" ), true );
1075   cfg_favoriteauthors.insert( QStringLiteral( "NofColumns" ), 1 );
1076   cfg_favoriteauthors.insert( QStringLiteral( "AllowNull" ), false );
1077   cfg_favoriteauthors.insert( QStringLiteral( "OrderByValue" ), false );
1078   cfg_favoriteauthors.insert( QStringLiteral( "UseCompleter" ), false );
1079   w_favoriteauthors.setConfig( cfg_favoriteauthors );
1080   w_favoriteauthors.widget();
1081   w_favoriteauthors.setEnabled( true );
1082 
1083   //check if set up nice
1084   QCOMPARE( w_favoriteauthors.mTableWidget->rowCount(), 7 );
1085   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
1086   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "1gamma" ) );
1087   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
1088   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "2helm,comma" ) );
1089   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
1090   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "3johnson\"quote" ) );
1091   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
1092   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "4vlissides" ) );
1093   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
1094   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "5adams'singlequote" ) );
1095   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
1096   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "6follett{}" ) );
1097   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->text(), QStringLiteral( "Gabriel Garc%1a M%2rquez" ).arg( QChar( 0x00ED ) ).arg( QChar( 0x00E1 ) ) );
1098   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "7garc%1a][" ).arg( QChar( 0x00EC ) ) );
1099 
1100   w_favoriteauthors.setFeature( vl_text->getFeature( 1 ) );
1101 
1102   //check if first feature checked correctly (none)
1103   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
1104   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
1105   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
1106   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
1107   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
1108   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
1109   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
1110   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1111   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
1112   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
1113   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
1114   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1115   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->text(), QStringLiteral( "Gabriel Garc%1a M%2rquez" ).arg( QChar( 0x00ED ) ).arg( QChar( 0x00E1 ) ) );
1116   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1117 
1118   //check authors 1,2,4,5,6 means all the super weird ones: "2helm,comma", "3johnson\"quote", "5adams'singlequote", "6follett{}", "7garcìa]["
1119   w_favoriteauthors.mTableWidget->item( 1, 0 )->setCheckState( Qt::Checked );
1120   w_favoriteauthors.mTableWidget->item( 2, 0 )->setCheckState( Qt::Checked );
1121   w_favoriteauthors.mTableWidget->item( 4, 0 )->setCheckState( Qt::Checked );
1122   w_favoriteauthors.mTableWidget->item( 5, 0 )->setCheckState( Qt::Checked );
1123   w_favoriteauthors.mTableWidget->item( 6, 0 )->setCheckState( Qt::Checked );
1124 
1125   //check if first feature checked correctly 1,2,4,5,6
1126   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
1127   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
1128   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
1129   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Checked );
1130   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
1131   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
1132   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
1133   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1134   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
1135   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
1136   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
1137   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Checked );
1138   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->text(), QStringLiteral( "Gabriel Garc%1a M%2rquez" ).arg( QChar( 0x00ED ) ).arg( QChar( 0x00E1 ) ) );
1139   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Checked );
1140 
1141   //we do jump over the part with QgsAttributeForm::saveEdits
1142   vl_text->changeAttributeValue( 1, 3, w_favoriteauthors.value() );
1143 
1144   //check if everything set correctly
1145   QCOMPARE( w_favoriteauthors.value(), QVariant( QStringLiteral( "{\"2helm,comma\",\"3johnson\\\"quote\",\"5adams'singlequote\",\"6follett{}\",\"7garc%1a][\"}" ).arg( QChar( 0x00EC ) ) ) );
1146 
1147   w_favoriteauthors.setFeature( vl_text->getFeature( 2 ) );
1148   //check if second feature checked correctly (none)
1149   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
1150   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
1151   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
1152   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
1153   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
1154   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
1155   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
1156   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1157   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
1158   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
1159   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
1160   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1161   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->text(), QStringLiteral( "Gabriel Garc%1a M%2rquez" ).arg( QChar( 0x00ED ) ).arg( QChar( 0x00E1 ) ) );
1162   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1163 
1164   w_favoriteauthors.setFeature( vl_text->getFeature( 1 ) );
1165   //check if first feature checked correctly 1,2,4,5,6
1166   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
1167   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
1168   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
1169   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Checked );
1170   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
1171   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
1172   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
1173   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1174   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
1175   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
1176   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
1177   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Checked );
1178   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->text(), QStringLiteral( "Gabriel Garc%1a M%2rquez" ).arg( QChar( 0x00ED ) ).arg( QChar( 0x00E1 ) ) );
1179   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Checked );
1180 
1181   // check if stored correctly
1182   vl_text->commitChanges();
1183   const QString expected_string = QStringLiteral( "{\"2helm,comma\",\"3johnson\\\"quote\",\"5adams'singlequote\",\"6follett{}\",\"7garc%1a][\"}" ).arg( QChar( 0x00EC ) );
1184 
1185   const QgsFeature f = vl_text->getFeature( 1 );
1186   const QVariant attribute = f.attribute( QStringLiteral( "PRFEDEA" ) );
1187   const QString value = attribute.toString();
1188   QCOMPARE( value, expected_string );
1189 
1190   //reread completely
1191   QgsVectorLayer *vl_text_reread = new QgsVectorLayer( myMapFileInfoFoo.filePath() + "|layername=foo", "test", QStringLiteral( "ogr" ) );
1192   QVERIFY( vl_text_reread->isValid() );
1193 
1194   QgsProject::instance()->addMapLayer( vl_text_reread, false, false );
1195   vl_text_reread->startEditing();
1196 
1197   // build a value relation widget wrapper for authors
1198   QgsValueRelationWidgetWrapper w_favoriteauthors_reread( vl_text_reread, vl_text_reread->fields().indexOf( QLatin1String( "PRFEDEA" ) ), nullptr, nullptr );
1199   w_favoriteauthors_reread.setConfig( cfg_favoriteauthors );
1200   w_favoriteauthors_reread.widget();
1201   w_favoriteauthors_reread.setEnabled( true );
1202 
1203   w_favoriteauthors_reread.setFeature( vl_text_reread->getFeature( 1 ) );
1204 
1205   //check if first feature on new layer checked correctly 1,2,4,5,6 after reread
1206   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
1207   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
1208   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
1209   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Checked );
1210   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
1211   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
1212   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
1213   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1214   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
1215   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
1216   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
1217   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Checked );
1218   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->text(), QStringLiteral( "Gabriel Garc%1a M%2rquez" ).arg( QChar( 0x00ED ) ).arg( QChar( 0x00E1 ) ) );
1219   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Checked );
1220 }
1221 
testWithJsonInSpatialite()1222 void TestQgsValueRelationWidgetWrapper::testWithJsonInSpatialite()
1223 {
1224   const auto fk_field { QStringLiteral( "json_content" ) };
1225   // create ogr gpkg layers
1226   const QString myFileName( TEST_DATA_DIR ); //defined in CmakeLists.txt
1227   const QString myTempDirName = tempDir.path();
1228   const QString myTempFileName = myTempDirName + QStringLiteral( "/valuerelation_widget_wrapper_test.spatialite.sqlite" );
1229   QFile::copy( myFileName + QStringLiteral( "/valuerelation_widget_wrapper_test.spatialite.sqlite" ),
1230                myTempFileName );
1231   const QFileInfo myMapFileInfo( myTempFileName );
1232   QgsVectorLayer *vl_json = new QgsVectorLayer( QStringLiteral( R"(dbname='%1' table="%2")" )
1233       .arg( myMapFileInfo.filePath() ).arg( QLatin1String( "json" ) ),
1234       QStringLiteral( "test" ),
1235       QStringLiteral( "spatialite" ) );
1236   QgsVectorLayer *vl_authors = new QgsVectorLayer( QStringLiteral( R"(dbname='%1' table="%2")" )
1237       .arg( myMapFileInfo.filePath() ).arg( QLatin1String( "authors" ) ),
1238       QStringLiteral( "test" ),
1239       QStringLiteral( "spatialite" ) );
1240   const auto fk_field_idx { vl_json->fields().indexOf( fk_field ) };
1241 
1242   QVERIFY( vl_json->isValid() );
1243   QVERIFY( vl_authors->isValid() );
1244 
1245   QgsProject::instance()->addMapLayer( vl_json, false, false );
1246   QgsProject::instance()->addMapLayer( vl_authors, false, false );
1247   vl_json->startEditing();
1248 
1249   // build a value relation widget wrapper for authors
1250   // fk_field is a json array type
1251   QgsValueRelationWidgetWrapper w_favoriteauthors( vl_json, fk_field_idx, nullptr, nullptr );
1252   QVariantMap cfg_favoriteauthors;
1253   cfg_favoriteauthors.insert( QStringLiteral( "Layer" ), vl_authors->id() );
1254   cfg_favoriteauthors.insert( QStringLiteral( "Key" ),  QStringLiteral( "pk" ) );
1255   cfg_favoriteauthors.insert( QStringLiteral( "Value" ), QStringLiteral( "name" ) );
1256   cfg_favoriteauthors.insert( QStringLiteral( "AllowMulti" ), true );
1257   cfg_favoriteauthors.insert( QStringLiteral( "NofColumns" ), 1 );
1258   cfg_favoriteauthors.insert( QStringLiteral( "AllowNull" ), false );
1259   cfg_favoriteauthors.insert( QStringLiteral( "OrderByValue" ), false );
1260   cfg_favoriteauthors.insert( QStringLiteral( "UseCompleter" ), false );
1261   w_favoriteauthors.setConfig( cfg_favoriteauthors );
1262   w_favoriteauthors.widget();
1263   w_favoriteauthors.setEnabled( true );
1264 
1265   //check if set up nice
1266   QCOMPARE( w_favoriteauthors.mTableWidget->rowCount(), 7 );
1267   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
1268   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "1" ) );
1269   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
1270   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "2" ) );
1271   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
1272   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "3" ) );
1273   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
1274   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "4" ) );
1275   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
1276   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "5" ) );
1277   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
1278   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "6" ) );
1279   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->text(), QStringLiteral( "Gabriel Garc%1a M%2rquez" ).arg( QChar( 0x00ED ) ).arg( QChar( 0x00E1 ) ) );
1280   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->checkState(), Qt::Unchecked );
1281 
1282   /* Test data:
1283   pk: 1 [1,3]
1284   pk: 2 [2,5]
1285   pk: 3 [4,6,7]
1286   pk: 4 NULL
1287   pk: 5 blank
1288   */
1289 
1290   // FEATURE 1
1291   w_favoriteauthors.setFeature( vl_json->getFeature( 1 ) );
1292   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariantList( { 1, 3 } ) ) );
1293   //check if first feature checked correctly (1,3)                                          pk
1294   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );   // 1
1295   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked ); // 2
1296   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );   // 3
1297   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked ); // 4
1298   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked ); // 5
1299   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked ); // 6
1300   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->checkState(), Qt::Unchecked ); // 7
1301 
1302   //check other authors
1303   w_favoriteauthors.mTableWidget->item( 1, 0 )->setCheckState( Qt::Checked );
1304   w_favoriteauthors.mTableWidget->item( 4, 0 )->setCheckState( Qt::Checked );
1305 
1306   //check if first feature checked correctly (1,2,3,5)
1307   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariantList( {1, 2, 3, 5} ) ) );
1308   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
1309   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Checked );
1310   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
1311   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1312   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
1313   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1314   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->checkState(), Qt::Unchecked );
1315 
1316   vl_json->changeAttributeValue( 1, fk_field_idx, w_favoriteauthors.value() );
1317   // check if stored correctly
1318   vl_json->commitChanges();
1319   QVariantList expected_vl;
1320   expected_vl << "1" << "2" << "3" << "5";
1321   const QgsFeature f = vl_json->getFeature( 1 );
1322   const QVariant attribute = f.attribute( fk_field );
1323   const QList<QVariant> value = attribute.toList();
1324   QCOMPARE( value, expected_vl );
1325 
1326   // FEATURE 2
1327   w_favoriteauthors.setFeature( vl_json->getFeature( 2 ) );
1328   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariantList( {2, 5} ) ) );
1329   //check if second feature checked correctly
1330   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
1331   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Checked );
1332   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
1333   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1334   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
1335   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1336   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->checkState(), Qt::Unchecked );
1337 
1338   // FEATURE 4
1339   w_favoriteauthors.setFeature( vl_json->getFeature( 4 ) );
1340   // Because allowNull is false we have a NULL variant here
1341   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariant::Type::List ) );
1342   cfg_favoriteauthors[ QStringLiteral( "AllowNull" ) ] = true;
1343   w_favoriteauthors.setConfig( cfg_favoriteauthors );
1344   //check if first feature checked correctly (empty list)
1345   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariantList() ) );
1346   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
1347   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
1348   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
1349   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1350   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
1351   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1352   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->checkState(), Qt::Unchecked );
1353   cfg_favoriteauthors[ QStringLiteral( "AllowNull" ) ] = false;
1354   w_favoriteauthors.setConfig( cfg_favoriteauthors );
1355 
1356   // FEATURE 5
1357   w_favoriteauthors.setFeature( vl_json->getFeature( 5 ) );
1358   // Because allowNull is false we have a NULL variant here
1359   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariant::Type::List ) );
1360 
1361   cfg_favoriteauthors[ QStringLiteral( "AllowNull" ) ] = true;
1362   w_favoriteauthors.setConfig( cfg_favoriteauthors );
1363   //check if first feature checked correctly (empty list)
1364   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariantList( ) ) );
1365   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
1366   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
1367   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
1368   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1369   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
1370   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1371   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->checkState(), Qt::Unchecked );
1372 }
1373 
1374 
testWithJsonInSpatialiteTextFk()1375 void TestQgsValueRelationWidgetWrapper::testWithJsonInSpatialiteTextFk()
1376 {
1377   const auto fk_field { QStringLiteral( "json_content_text" ) };
1378   // create ogr gpkg layers
1379   const QString myFileName( TEST_DATA_DIR ); //defined in CmakeLists.txt
1380   const QString myTempDirName = tempDir.path();
1381   const QString myTempFileName = myTempDirName + QStringLiteral( "/valuerelation_widget_wrapper_test.spatialite.sqlite" );
1382   QFile::copy( myFileName + QStringLiteral( "/valuerelation_widget_wrapper_test.spatialite.sqlite" ),
1383                myTempFileName );
1384   const QFileInfo myMapFileInfo( myTempFileName );
1385   QgsVectorLayer *vl_json = new QgsVectorLayer( QStringLiteral( R"(dbname='%1' table="%2")" )
1386       .arg( myMapFileInfo.filePath() ).arg( QLatin1String( "json" ) ),
1387       QStringLiteral( "test" ),
1388       QStringLiteral( "spatialite" ) );
1389   QgsVectorLayer *vl_authors = new QgsVectorLayer( QStringLiteral( R"(dbname='%1' table="%2")" )
1390       .arg( myMapFileInfo.filePath() ).arg( QLatin1String( "authors" ) ),
1391       QStringLiteral( "test" ),
1392       QStringLiteral( "spatialite" ) );
1393   const auto fk_field_idx { vl_json->fields().indexOf( fk_field ) };
1394 
1395   QVERIFY( vl_json->isValid() );
1396   QVERIFY( vl_authors->isValid() );
1397 
1398   QgsProject::instance()->addMapLayer( vl_json, false, false );
1399   QgsProject::instance()->addMapLayer( vl_authors, false, false );
1400   vl_json->startEditing();
1401 
1402   // build a value relation widget wrapper for authors
1403   // fk_field is a json array type
1404   QgsValueRelationWidgetWrapper w_favoriteauthors( vl_json, fk_field_idx, nullptr, nullptr );
1405   QVariantMap cfg_favoriteauthors;
1406   cfg_favoriteauthors.insert( QStringLiteral( "Layer" ), vl_authors->id() );
1407   cfg_favoriteauthors.insert( QStringLiteral( "Key" ),  QStringLiteral( "pk_text" ) );
1408   cfg_favoriteauthors.insert( QStringLiteral( "Value" ), QStringLiteral( "name" ) );
1409   cfg_favoriteauthors.insert( QStringLiteral( "AllowMulti" ), true );
1410   cfg_favoriteauthors.insert( QStringLiteral( "NofColumns" ), 1 );
1411   cfg_favoriteauthors.insert( QStringLiteral( "AllowNull" ), false );
1412   cfg_favoriteauthors.insert( QStringLiteral( "OrderByValue" ), false );
1413   cfg_favoriteauthors.insert( QStringLiteral( "UseCompleter" ), false );
1414   w_favoriteauthors.setConfig( cfg_favoriteauthors );
1415   w_favoriteauthors.widget();
1416   w_favoriteauthors.setEnabled( true );
1417 
1418   //check if set up nice
1419   QCOMPARE( w_favoriteauthors.mTableWidget->rowCount(), 7 );
1420   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->text(), QStringLiteral( "Erich Gamma" ) );
1421   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "1gamma" ) );
1422   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->text(), QStringLiteral( "Richard Helm" ) );
1423   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "2helm,comma" ) );
1424   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->text(), QStringLiteral( "Ralph Johnson" ) );
1425   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "3johnson\"quote" ) );
1426   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->text(), QStringLiteral( "John Vlissides" ) );
1427   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "4vlissides" ) );
1428   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->text(), QStringLiteral( "Douglas Adams" ) );
1429   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "5adams'singlequote" ) );
1430   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->text(), QStringLiteral( "Ken Follett" ) );
1431   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "6follett{}" ) );
1432   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->text(), QStringLiteral( "Gabriel Garc%1a M%2rquez" ).arg( QChar( 0x00ED ) ).arg( QChar( 0x00E1 ) ) );
1433   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->data( Qt::UserRole ).toString(), QStringLiteral( "7garc%1a][" ).arg( QChar( 0x00EC ) ) );
1434   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->checkState(), Qt::Unchecked );
1435 
1436   /* Test data:
1437 
1438     Keys:
1439     "1gamma"
1440     "2helm,comma"
1441     "3johnson""quote"
1442     "4vlissides"
1443     "5adams'singlequote"
1444     "6follett{}"
1445     "7garcìa]["
1446 
1447     Data:
1448     1 "[1,3]" "[""1gamma"", ""3johnson\""quote""]
1449     2 "[2,5]" "[""2helm,comma"", ""5adams'singlequote""]"
1450     3 "[4,6,7]" "[""4vlissides"", ""6follett{}"" , ""7garca][""]"
1451     5
1452     7 ""  ""
1453 
1454   */
1455 
1456   // FEATURE 1
1457   w_favoriteauthors.setFeature( vl_json->getFeature( 1 ) );
1458   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariantList( { "1gamma", "3johnson\"quote" } ) ) );
1459 
1460   //check if first feature checked correctly (1,3)                                          pk
1461   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );   // 1
1462   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked ); // 2
1463   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );   // 3
1464   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked ); // 4
1465   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked ); // 5
1466   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked ); // 6
1467   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->checkState(), Qt::Unchecked ); // 7
1468 
1469   //check other authors
1470   w_favoriteauthors.mTableWidget->item( 1, 0 )->setCheckState( Qt::Checked );
1471   w_favoriteauthors.mTableWidget->item( 4, 0 )->setCheckState( Qt::Checked );
1472 
1473   //check if first feature checked correctly (1,2,3,5) ) );
1474   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariantList( { "1gamma", "2helm,comma", "3johnson\"quote", "5adams'singlequote" } ) ) );
1475 
1476   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Checked );
1477   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Checked );
1478   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Checked );
1479   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1480   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
1481   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1482   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->checkState(), Qt::Unchecked );
1483 
1484   vl_json->changeAttributeValue( 1, fk_field_idx, w_favoriteauthors.value() );
1485   // check if stored correctly
1486   vl_json->commitChanges();
1487   const QgsFeature f = vl_json->getFeature( 1 );
1488   const QVariant attribute = f.attribute( fk_field );
1489   const QVariantList value = attribute.toList();
1490 
1491   QCOMPARE( value, QVariantList( { "1gamma", "2helm,comma", "3johnson\"quote", "5adams'singlequote" } ) );
1492 
1493   // FEATURE 2
1494   w_favoriteauthors.setFeature( vl_json->getFeature( 2 ) );
1495   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariantList( { "2helm,comma", "5adams'singlequote" } ) ) );
1496 
1497   //check if second feature checked correctly
1498   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
1499   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Checked );
1500   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
1501   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1502   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Checked );
1503   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1504   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->checkState(), Qt::Unchecked );
1505 
1506   // FEATURE 4
1507   w_favoriteauthors.setFeature( vl_json->getFeature( 4 ) );
1508 
1509   // Because allowNull is false we have a NULL variant here
1510   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariant::Type::List ) );
1511   cfg_favoriteauthors[ QStringLiteral( "AllowNull" ) ] = true;
1512   w_favoriteauthors.setConfig( cfg_favoriteauthors );
1513 
1514   //check if first feature checked correctly (NULL)
1515   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariantList( ) ) );
1516 
1517   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
1518   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
1519   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
1520   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1521   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
1522   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1523   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->checkState(), Qt::Unchecked );
1524   cfg_favoriteauthors[ QStringLiteral( "AllowNull" ) ] = false;
1525   w_favoriteauthors.setConfig( cfg_favoriteauthors );
1526 
1527   // FEATURE 5
1528   w_favoriteauthors.setFeature( vl_json->getFeature( 5 ) );
1529 
1530   // Because allowNull is false we have a NULL variant here
1531   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariant::Type::List ) );
1532   cfg_favoriteauthors[ QStringLiteral( "AllowNull" ) ] = true;
1533   w_favoriteauthors.setConfig( cfg_favoriteauthors );
1534 
1535   //check if first feature checked correctly (empty list)
1536   QCOMPARE( w_favoriteauthors.value(), QVariant( QVariantList() ) );
1537 
1538   QCOMPARE( w_favoriteauthors.mTableWidget->item( 0, 0 )->checkState(), Qt::Unchecked );
1539   QCOMPARE( w_favoriteauthors.mTableWidget->item( 1, 0 )->checkState(), Qt::Unchecked );
1540   QCOMPARE( w_favoriteauthors.mTableWidget->item( 2, 0 )->checkState(), Qt::Unchecked );
1541   QCOMPARE( w_favoriteauthors.mTableWidget->item( 3, 0 )->checkState(), Qt::Unchecked );
1542   QCOMPARE( w_favoriteauthors.mTableWidget->item( 4, 0 )->checkState(), Qt::Unchecked );
1543   QCOMPARE( w_favoriteauthors.mTableWidget->item( 5, 0 )->checkState(), Qt::Unchecked );
1544   QCOMPARE( w_favoriteauthors.mTableWidget->item( 6, 0 )->checkState(), Qt::Unchecked );
1545 }
1546 
testMatchLayerName()1547 void TestQgsValueRelationWidgetWrapper::testMatchLayerName()
1548 {
1549   // create a vector layer
1550   QgsVectorLayer vl1( QStringLiteral( "Polygon?crs=epsg:4326&field=pk:int&field=province:int&field=municipality:string" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) );
1551   QgsVectorLayer vl2( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=fk_province:int&field=fk_municipality:int" ), QStringLiteral( "vl2" ), QStringLiteral( "memory" ) );
1552   QgsProject::instance()->addMapLayer( &vl1, false, false );
1553   QgsProject::instance()->addMapLayer( &vl2, false, false );
1554 
1555   // insert some features
1556   QgsFeature f1( vl1.fields() );
1557   f1.setAttribute( QStringLiteral( "pk" ), 0 );  // !!! Notice: pk 0
1558   f1.setAttribute( QStringLiteral( "province" ), 123 );
1559   f1.setAttribute( QStringLiteral( "municipality" ), QStringLiteral( "Some Place By The River" ) );
1560   f1.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POLYGON(( 0 0, 0 1, 1 1, 1 0, 0 0 ))" ) ) );
1561   QVERIFY( f1.isValid() );
1562   QgsFeature f2( vl1.fields() );
1563   f2.setAttribute( QStringLiteral( "pk" ), 2 );
1564   f2.setAttribute( QStringLiteral( "province" ), 245 );
1565   f2.setAttribute( QStringLiteral( "municipality" ), QStringLiteral( "Dreamland By The Clouds" ) );
1566   f2.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POLYGON(( 1 0, 1 1, 2 1, 2 0, 1 0 ))" ) ) );
1567   QVERIFY( f2.isValid() );
1568   QVERIFY( vl1.dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 ) );
1569 
1570   QgsFeature f3( vl2.fields() );
1571   f3.setAttribute( QStringLiteral( "fk_province" ), 123 );
1572   f3.setAttribute( QStringLiteral( "fk_municipality" ), QStringLiteral( "0" ) );
1573   f3.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POINT( 0.5 0.5)" ) ) );
1574   QVERIFY( f3.isValid() );
1575   QVERIFY( f3.geometry().isGeosValid() );
1576   QVERIFY( vl2.dataProvider()->addFeature( f3 ) );
1577 
1578   // build a value relation widget wrapper for municipality
1579   QgsValueRelationWidgetWrapper w_municipality( &vl2, vl2.fields().indexOf( QLatin1String( "fk_municipality" ) ), nullptr, nullptr );
1580   QVariantMap cfg_municipality;
1581   cfg_municipality.insert( QStringLiteral( "Layer" ), QStringLiteral( "wrong_id_here_hope_name_is_good" ) );
1582   cfg_municipality.insert( QStringLiteral( "LayerName" ), vl1.name() );
1583   cfg_municipality.insert( QStringLiteral( "Key" ),  QStringLiteral( "pk" ) );
1584   cfg_municipality.insert( QStringLiteral( "Value" ), QStringLiteral( "municipality" ) );
1585   cfg_municipality.insert( QStringLiteral( "AllowMulti" ), false );
1586   cfg_municipality.insert( QStringLiteral( "NofColumns" ), 1 );
1587   cfg_municipality.insert( QStringLiteral( "AllowNull" ), true );
1588   cfg_municipality.insert( QStringLiteral( "OrderByValue" ), false );
1589   cfg_municipality.insert( QStringLiteral( "UseCompleter" ), false );
1590   w_municipality.setConfig( cfg_municipality );
1591   w_municipality.widget();
1592   w_municipality.setEnabled( true );
1593 
1594   w_municipality.setValues( 0, QVariantList() );
1595   QCOMPARE( w_municipality.mComboBox->currentIndex(), 1 );
1596   QCOMPARE( w_municipality.mComboBox->currentText(), QStringLiteral( "Some Place By The River" ) );
1597 }
1598 
testRegressionGH42003()1599 void TestQgsValueRelationWidgetWrapper::testRegressionGH42003()
1600 {
1601   // create a vector layer
1602   QgsVectorLayer vl1( QStringLiteral( "Polygon?crs=epsg:4326&field=pk:int&field=province:int&field=municipality:string" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) );
1603   QgsVectorLayer vl2( QStringLiteral( "Point?crs=epsg:4326&field=pk:int&field=fk_province:int&field=fk_municipality:int" ), QStringLiteral( "vl2" ), QStringLiteral( "memory" ) );
1604   QgsProject::instance()->addMapLayer( &vl1, false, false );
1605   QgsProject::instance()->addMapLayer( &vl2, false, false );
1606 
1607   // insert some features
1608   QgsFeature f1( vl1.fields() );
1609   f1.setAttribute( QStringLiteral( "pk" ), 1 );
1610   f1.setAttribute( QStringLiteral( "province" ), 123 );
1611   f1.setAttribute( QStringLiteral( "municipality" ), QStringLiteral( "Some Place By The River" ) );
1612   f1.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POLYGON(( 0 0, 0 1, 1 1, 1 0, 0 0 ))" ) ) );
1613   QVERIFY( f1.isValid() );
1614   QgsFeature f2( vl1.fields() );
1615   f2.setAttribute( QStringLiteral( "pk" ), 2 );
1616   f2.setAttribute( QStringLiteral( "province" ), 245 );
1617   f2.setAttribute( QStringLiteral( "municipality" ), QStringLiteral( "Dreamland By The Clouds" ) );
1618   f2.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POLYGON(( 1 0, 1 1, 2 1, 2 0, 1 0 ))" ) ) );
1619   QVERIFY( f2.isValid() );
1620   QVERIFY( vl1.dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 ) );
1621 
1622   QgsFeature f3( vl2.fields() );
1623   f3.setAttribute( QStringLiteral( "fk_province" ), 123 );
1624   f3.setAttribute( QStringLiteral( "fk_municipality" ), 1 );
1625   f3.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "POINT( 0.5 0.5)" ) ) );
1626   QVERIFY( f3.isValid() );
1627   QVERIFY( f3.geometry().isGeosValid() );
1628   QVERIFY( vl2.dataProvider()->addFeature( f3 ) );
1629 
1630   // build a value relation widget wrapper for municipality
1631   QgsValueRelationWidgetWrapper w_municipality( &vl2, vl2.fields().indexOf( QLatin1String( "fk_municipality" ) ), nullptr, nullptr );
1632   QVariantMap cfg_municipality;
1633   cfg_municipality.insert( QStringLiteral( "Layer" ), vl1.id() );
1634   cfg_municipality.insert( QStringLiteral( "Key" ),  QStringLiteral( "pk" ) );
1635   cfg_municipality.insert( QStringLiteral( "Value" ), QStringLiteral( "municipality" ) );
1636   cfg_municipality.insert( QStringLiteral( "AllowMulti" ), false );
1637   cfg_municipality.insert( QStringLiteral( "NofColumns" ), 1 );
1638   cfg_municipality.insert( QStringLiteral( "AllowNull" ), false );
1639   cfg_municipality.insert( QStringLiteral( "OrderByValue" ), true );
1640   cfg_municipality.insert( QStringLiteral( "UseCompleter" ), false );
1641   w_municipality.setConfig( cfg_municipality );
1642   w_municipality.widget();
1643   w_municipality.setEnabled( true );
1644 
1645   w_municipality.setFeature( QgsFeature( vl2.fields() ) );
1646   QCoreApplication::processEvents();
1647 
1648   // Check first is selected (fid 2 because of OrderByValue)
1649   QCOMPARE( w_municipality.mComboBox->currentIndex(), 0 );
1650   QCOMPARE( w_municipality.mComboBox->count(), 2 );
1651   QCOMPARE( w_municipality.mComboBox->itemText( 0 ), QStringLiteral( "Dreamland By The Clouds" ) );
1652   QCOMPARE( w_municipality.value().toString(), QStringLiteral( "2" ) );
1653 
1654   // Simulate what happens in the attribute form initialization
1655   w_municipality.setFeature( QgsFeature( vl2.fields() ) );
1656   w_municipality.setFeature( vl2.getFeature( 1 ) );
1657   QCoreApplication::processEvents();
1658 
1659   // Check fid 1 is selected
1660   QCOMPARE( w_municipality.mComboBox->currentIndex(), 1 );
1661   QCOMPARE( w_municipality.mComboBox->currentText(), QStringLiteral( "Some Place By The River" ) );
1662   QCOMPARE( w_municipality.value().toString(), QStringLiteral( "1" ) );
1663 
1664 }
1665 
1666 QGSTEST_MAIN( TestQgsValueRelationWidgetWrapper )
1667 #include "testqgsvaluerelationwidgetwrapper.moc"
1668