Skip to content

Commit

Permalink
Merge pull request #45321 from troopa81/fix_array_expr_builder
Browse files Browse the repository at this point in the history
Fix array display in expression builder
  • Loading branch information
troopa81 committed Sep 30, 2021
2 parents aa00c9f + cd2f4f9 commit 5ebf9e1
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 1 deletion.
13 changes: 13 additions & 0 deletions src/core/qgsfield.cpp
Expand Up @@ -342,6 +342,19 @@ QString QgsField::displayString( const QVariant &v ) const
{
return QObject::tr( "BLOB" );
}
else if ( d->type == QVariant::StringList || d->type == QVariant::List )
{
QString result;
const QVariantList list = v.toList();
for ( const QVariant &var : list )
{
if ( !result.isEmpty() )
result.append( QStringLiteral( ", " ) );
result.append( var.toString() );
}
return result;
}

// Fallback if special rules do not apply
return v.toString();
}
Expand Down
17 changes: 16 additions & 1 deletion src/gui/qgsexpressionbuilderwidget.cpp
Expand Up @@ -542,15 +542,30 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString &fieldName, int
for ( const QVariant &value : std::as_const( values ) )
{
QString strValue;
bool forceRepresentedValue = false;
if ( value.isNull() )
strValue = QStringLiteral( "NULL" );
else if ( value.type() == QVariant::Int || value.type() == QVariant::Double || value.type() == QVariant::LongLong )
strValue = value.toString();
else if ( value.type() == QVariant::StringList )
{
QString result;
const QStringList strList = value.toStringList();
for ( QString str : strList )
{
if ( !result.isEmpty() )
result.append( QStringLiteral( ", " ) );

result.append( '\'' + str.replace( '\'', QLatin1String( "''" ) ) + '\'' );
}
strValue = QStringLiteral( "array(%1)" ).arg( result );
forceRepresentedValue = true;
}
else
strValue = '\'' + value.toString().replace( '\'', QLatin1String( "''" ) ) + '\'';

QString representedValue = formatter->representValue( mLayer, fieldIndex, setup.config(), QVariant(), value );
if ( representedValue != value.toString() )
if ( forceRepresentedValue || representedValue != value.toString() )
representedValue = representedValue + QStringLiteral( " [" ) + strValue + ']';

QStandardItem *item = new QStandardItem( representedValue );
Expand Down
6 changes: 6 additions & 0 deletions tests/src/core/testqgsfield.cpp
Expand Up @@ -448,6 +448,12 @@ void TestQgsField::displayString()
const QString testBAString( QStringLiteral( "test string" ) );
const QByteArray testBA( testBAString.toLocal8Bit() );
QCOMPARE( binaryField.displayString( testBA ), QStringLiteral( "BLOB" ) );

// array field
const QgsField stringArrayField( QStringLiteral( "stringArray" ), QVariant::StringList, QStringLiteral( "StringArray" ) );
QCOMPARE( stringArrayField.displayString( QStringList() << "A" << "B" << "C" ), QStringLiteral( "A, B, C" ) );
const QgsField intArrayField( QStringLiteral( "intArray" ), QVariant::List, QStringLiteral( "IntArray" ) );
QCOMPARE( intArrayField.displayString( QVariantList() << 1 << 2 << 3 ), QStringLiteral( "1, 2, 3" ) );
}

void TestQgsField::convertCompatible()
Expand Down
83 changes: 83 additions & 0 deletions tests/src/python/test_qgsexpressionbuilderwidget.py
Expand Up @@ -13,6 +13,7 @@
import qgis # NOQA

from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import QListView
from qgis.testing import start_app, unittest
from qgis.gui import QgsExpressionBuilderWidget
from qgis.core import (QgsExpressionContext,
Expand Down Expand Up @@ -214,6 +215,88 @@ def testLayerVariables(self):

p.removeMapLayer(layer)

def testValuesList(self):
"""
Test the content of values list widget
"""

w = QgsExpressionBuilderWidget()

valuesList = w.findChild(QListView, 'mValuesListView')
self.assertTrue(valuesList)

valuesModel = valuesList.model()
self.assertTrue(valuesModel)

layer = QgsVectorLayer(
"None?field=myarray:string[]&field=mystr:string&field=myint:integer",
"arraylayer", "memory")

self.assertTrue(layer.isValid())

# add some features, one has invalid geometry
pr = layer.dataProvider()
f1 = QgsFeature(1)
f1.setAttributes([["one 'item'", 'B'], "another 'item'", 0])
f2 = QgsFeature(2)
f2.setAttributes([['C'], "", 1])
f3 = QgsFeature(3)
f3.setAttributes([[], "test", 2])
f4 = QgsFeature(4)
self.assertTrue(pr.addFeatures([f1, f2, f3, f4]))

w.setLayer(layer)

# test array
items = w.expressionTree().findExpressions("myarray")
self.assertEqual(len(items), 1)
currentIndex = w.expressionTree().model().mapFromSource(items[0].index())
self.assertTrue(currentIndex.isValid())
w.expressionTree().setCurrentIndex(currentIndex)
self.assertTrue(w.expressionTree().currentItem())

w.loadAllValues()

datas = sorted([(valuesModel.data(valuesModel.index(i, 0), Qt.DisplayRole), valuesModel.data(valuesModel.index(i, 0), Qt.UserRole + 1)) for i in range(4)])
self.assertEqual(datas, [(" [array()]", "array()"),
("C [array('C')]", "array('C')"),
("NULL [NULL]", "NULL"),
("one 'item', B [array('one ''item''', 'B')]", "array('one ''item''', 'B')")])

# test string
items = w.expressionTree().findExpressions("mystr")
self.assertEqual(len(items), 1)
currentIndex = w.expressionTree().model().mapFromSource(items[0].index())
self.assertTrue(currentIndex.isValid())
w.expressionTree().setCurrentIndex(currentIndex)
self.assertTrue(w.expressionTree().currentItem())

w.loadAllValues()

datas = sorted([(valuesModel.data(valuesModel.index(i, 0), Qt.DisplayRole), valuesModel.data(valuesModel.index(i, 0), Qt.UserRole + 1)) for i in range(4)])

self.assertEqual(datas, [("", "''"),
("NULL [NULL]", "NULL"),
("another 'item'", "'another ''item'''"),
("test", "'test'")])

# test int
items = w.expressionTree().findExpressions("myint")
self.assertEqual(len(items), 1)
currentIndex = w.expressionTree().model().mapFromSource(items[0].index())
self.assertTrue(currentIndex.isValid())
w.expressionTree().setCurrentIndex(currentIndex)
self.assertTrue(w.expressionTree().currentItem())

w.loadAllValues()

datas = sorted([(valuesModel.data(valuesModel.index(i, 0), Qt.DisplayRole), valuesModel.data(valuesModel.index(i, 0), Qt.UserRole + 1)) for i in range(4)])

self.assertEqual(datas, [("0", "0"),
("1", "1"),
("2", "2"),
("NULL [NULL]", "NULL")])


if __name__ == '__main__':
unittest.main()

0 comments on commit 5ebf9e1

Please sign in to comment.