Skip to content

Commit 8746932

Browse files
authored
Merge pull request #3467 from pvalsecc/arrays
[FEATURE] Add support for array attributes
2 parents 6f6979a + 57d0094 commit 8746932

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1355
-146
lines changed

python/core/qgsfield.sip

+21-1
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,17 @@ class QgsField
2424
* @param prec Field precision. Usually decimal places but may also be
2525
* used in conjunction with other fields types (eg. variable character fields)
2626
* @param comment Comment for the field
27+
* @param subType If the field is a collection, its element's type. When
28+
* all the elements don't need to have the same type, leave
29+
* this to QVariant::Invalid.
2730
*/
2831
QgsField( const QString& name = QString(),
2932
QVariant::Type type = QVariant::Invalid,
3033
const QString& typeName = QString(),
3134
int len = 0,
3235
int prec = 0,
33-
const QString& comment = QString() );
36+
const QString& comment = QString(),
37+
QVariant::Type subType = QVariant::Invalid );
3438

3539
/** Copy constructor
3640
*/
@@ -59,6 +63,14 @@ class QgsField
5963
//! Gets variant type of the field as it will be retrieved from data source
6064
QVariant::Type type() const;
6165

66+
/**
67+
* If the field is a collection, gets its element's type.
68+
* When all the elements don't need to have the same type, this returns
69+
* QVariant::Invalid.
70+
* @note added in QGIS 3.0
71+
*/
72+
QVariant::Type subType() const;
73+
6274
/**
6375
* Gets the field type. Field types vary depending on the data source. Examples
6476
* are char, int, double, blob, geometry, etc. The type is stored exactly as
@@ -103,6 +115,14 @@ class QgsField
103115
*/
104116
void setType( QVariant::Type type );
105117

118+
/**
119+
* If the field is a collection, set its element's type.
120+
* When all the elements don't need to have the same type, set this to
121+
* QVariant::Invalid.
122+
* @note added in QGIS 3.0
123+
*/
124+
void setSubType( QVariant::Type subType );
125+
106126
/**
107127
* Set the field type.
108128
* @param typeName Field type

python/core/qgsvectordataprovider.sip

+2-1
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ class QgsVectorDataProvider : QgsDataProvider
302302

303303
struct NativeType
304304
{
305-
NativeType( const QString& typeDesc, const QString& typeName, QVariant::Type type, int minLen = 0, int maxLen = 0, int minPrec = 0, int maxPrec = 0 );
305+
NativeType( const QString& typeDesc, const QString& typeName, QVariant::Type type, int minLen = 0, int maxLen = 0, int minPrec = 0, int maxPrec = 0, QVariant::Type subType = QVariant::Invalid );
306306

307307
QString mTypeDesc;
308308
QString mTypeName;
@@ -311,6 +311,7 @@ class QgsVectorDataProvider : QgsDataProvider
311311
int mMaxLen;
312312
int mMinPrec;
313313
int mMaxPrec;
314+
QVariant::Type mSubType;
314315
};
315316

316317
/**

python/gui/editorwidgets/core/qgseditorwidgetwrapper.sip

+7
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ class QgsEditorWidgetWrapper : QgsWidgetWrapper
7575
*/
7676
static QgsEditorWidgetWrapper* fromWidget( QWidget* widget );
7777

78+
/**
79+
* Check if the given widget or one of its parent is a QTableView.
80+
* @param parent the widget to check
81+
* @return true if yes
82+
*/
83+
static bool isInTable( const QWidget* parent );
84+
7885
/**
7986
* Is used to enable or disable the edit functionality of the managed widget.
8087
* By default this will enable or disable the whole widget

python/gui/gui.sip

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
%Include qgshtmlannotationitem.sip
9797
%Include qgsidentifymenu.sip
9898
%Include qgskeyvaluewidget.sip
99+
%Include qgslistwidget.sip
99100
%Include qgslegendfilterbutton.sip
100101
%Include qgslegendinterface.sip
101102
%Include qgslimitedrandomcolorrampdialog.sip
@@ -161,6 +162,7 @@
161162
%Include qgssourceselectdialog.sip
162163
%Include qgssublayersdialog.sip
163164
%Include qgssvgannotationitem.sip
165+
%Include qgstablewidgetbase.sip
164166
%Include qgstabwidget.sip
165167
%Include qgstablewidgetitem.sip
166168
%Include qgstextannotationitem.sip

python/gui/qgskeyvaluewidget.sip

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Widget allowing to edit a QVariantMap, using a table.
33
* @note added in QGIS 3.0
44
*/
5-
class QgsKeyValueWidget : public QWidget
5+
class QgsKeyValueWidget : public QgsTableWidgetBase
66
{
77
%TypeHeaderCode
88
#include "qgskeyvaluewidget.h"

python/gui/qgslistwidget.sip

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/** \ingroup gui
2+
* Widget allowing to edit a QVariantList, using a table.
3+
* @note added in QGIS 3.0
4+
*/
5+
class QgsListWidget : public QgsTableWidgetBase
6+
{
7+
%TypeHeaderCode
8+
#include "qgslistwidget.h"
9+
%End
10+
public:
11+
/**
12+
* Constructor.
13+
*/
14+
explicit QgsListWidget( QVariant::Type subType, QWidget* parent = nullptr );
15+
16+
/**
17+
* Set the initial value of the widget.
18+
*/
19+
void setList( const QVariantList& list );
20+
21+
/**
22+
* Get the edit value.
23+
* @return the QVariantList
24+
*/
25+
QVariantList list() const;
26+
27+
/**
28+
* Check the content is valid
29+
* @return true if valid
30+
*/
31+
bool valid() const;
32+
};

python/gui/qgstablewidgetbase.sip

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/** \ingroup gui
2+
* Base widget allowing to edit a collection, using a table.
3+
* @note added in QGIS 3.0
4+
*/
5+
class QgsTableWidgetBase: public QWidget
6+
{
7+
%TypeHeaderCode
8+
#include "qgstablewidgetbase.h"
9+
%End
10+
public:
11+
/**
12+
* Constructor.
13+
*/
14+
explicit QgsTableWidgetBase( QWidget* parent );
15+
16+
protected:
17+
/**
18+
* Initialise the table with the given model.
19+
* Must be called once in the child class' constructor.
20+
*/
21+
void init( QAbstractTableModel* model );
22+
23+
signals:
24+
/**
25+
* Emitted each time a key or a value is changed.
26+
*/
27+
void valueChanged();
28+
};

src/app/qgsfieldcalculator.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ void QgsFieldCalculator::populateOutputFieldTypes()
346346
mOutputFieldTypeComboBox->setItemData( i, typelist[i].mMaxLen, Qt::UserRole + 3 );
347347
mOutputFieldTypeComboBox->setItemData( i, typelist[i].mMinPrec, Qt::UserRole + 4 );
348348
mOutputFieldTypeComboBox->setItemData( i, typelist[i].mMaxPrec, Qt::UserRole + 5 );
349+
mOutputFieldTypeComboBox->setItemData( i, static_cast<int>( typelist[i].mSubType ), Qt::UserRole + 6 );
349350
}
350351
mOutputFieldTypeComboBox->blockSignals( false );
351352
mOutputFieldTypeComboBox->setCurrentIndex( 0 );

src/app/qgsfieldcalculator.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,10 @@ class APP_EXPORT QgsFieldCalculator: public QDialog, private Ui::QgsFieldCalcula
6767
static_cast< QVariant::Type >( mOutputFieldTypeComboBox->itemData( mOutputFieldTypeComboBox->currentIndex(), Qt::UserRole ).toInt() ),
6868
mOutputFieldTypeComboBox->itemData( mOutputFieldTypeComboBox->currentIndex(), Qt::UserRole + 1 ).toString(),
6969
mOutputFieldWidthSpinBox->value(),
70-
mOutputFieldPrecisionSpinBox->value() );
70+
mOutputFieldPrecisionSpinBox->value(),
71+
QString(),
72+
static_cast< QVariant::Type >( mOutputFieldTypeComboBox->itemData( mOutputFieldTypeComboBox->currentIndex(), Qt::UserRole + 6 ).toInt() )
73+
);
7174
}
7275

7376
/** Idx of changed attribute*/

src/core/qgsexpression.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -5074,6 +5074,22 @@ QString QgsExpression::formatPreviewString( const QVariant& value )
50745074
}
50755075
return tr( "<i>&lt;map: %1&gt;</i>" ).arg( mapStr );
50765076
}
5077+
else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
5078+
{
5079+
QString listStr;
5080+
const QVariantList list = value.toList();
5081+
for ( QVariantList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
5082+
{
5083+
if ( !listStr.isEmpty() ) listStr.append( ", " );
5084+
listStr.append( formatPreviewString( *it ) );
5085+
if ( listStr.length() > MAX_PREVIEW + 3 )
5086+
{
5087+
listStr = QString( tr( "%1..." ) ).arg( listStr.left( MAX_PREVIEW ) );
5088+
break;
5089+
}
5090+
}
5091+
return tr( "<i>&lt;list: %1&gt;</i>" ).arg( listStr );
5092+
}
50775093
else
50785094
{
50795095
return value.toString();

src/core/qgsexpressionfieldbuffer.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ void QgsExpressionFieldBuffer::writeXml( QDomNode& layerNode, QDomDocument& docu
5454
fldElem.setAttribute( "comment", fld.field.comment() );
5555
fldElem.setAttribute( "length", fld.field.length() );
5656
fldElem.setAttribute( "type", fld.field.type() );
57+
fldElem.setAttribute( "subType", fld.field.subType() );
5758
fldElem.setAttribute( "typeName", fld.field.typeName() );
5859

5960
expressionFieldsElem.appendChild( fldElem );
@@ -79,9 +80,10 @@ void QgsExpressionFieldBuffer::readXml( const QDomNode& layerNode )
7980
int precision = field.attribute( "precision" ).toInt();
8081
int length = field.attribute( "length" ).toInt();
8182
QVariant::Type type = static_cast< QVariant::Type >( field.attribute( "type" ).toInt() );
83+
QVariant::Type subType = static_cast< QVariant::Type >( field.attribute( "subType", 0 ).toInt() );
8284
QString typeName = field.attribute( "typeName" );
8385

84-
mExpressions.append( ExpressionField( exp, QgsField( name, type, typeName, length, precision, comment ) ) );
86+
mExpressions.append( ExpressionField( exp, QgsField( name, type, typeName, length, precision, comment, subType ) ) );
8587
}
8688
}
8789
}

src/core/qgsfield.cpp

+17-4
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ QgsField::QgsField( QString nam, QString typ, int len, int prec, bool num,
4444
}
4545
#endif
4646
QgsField::QgsField( const QString& name, QVariant::Type type,
47-
const QString& typeName, int len, int prec, const QString& comment )
47+
const QString& typeName, int len, int prec, const QString& comment,
48+
QVariant::Type subType )
4849
{
49-
d = new QgsFieldPrivate( name, type, typeName, len, prec, comment );
50+
d = new QgsFieldPrivate( name, type, subType, typeName, len, prec, comment );
5051
}
5152

5253
QgsField::QgsField( const QgsField &other )
@@ -99,6 +100,11 @@ QVariant::Type QgsField::type() const
99100
return d->type;
100101
}
101102

103+
QVariant::Type QgsField::subType() const
104+
{
105+
return d->subType;
106+
}
107+
102108
QString QgsField::typeName() const
103109
{
104110
return d->typeName;
@@ -140,6 +146,11 @@ void QgsField::setType( QVariant::Type type )
140146
d->type = type;
141147
}
142148

149+
void QgsField::setSubType( QVariant::Type subType )
150+
{
151+
d->subType = subType;
152+
}
153+
143154
void QgsField::setTypeName( const QString& typeName )
144155
{
145156
d->typeName = typeName;
@@ -292,14 +303,15 @@ QDataStream& operator<<( QDataStream& out, const QgsField& field )
292303
out << field.comment();
293304
out << field.alias();
294305
out << field.defaultValueExpression();
306+
out << static_cast< quint32 >( field.subType() );
295307
return out;
296308
}
297309

298310
QDataStream& operator>>( QDataStream& in, QgsField& field )
299311
{
300-
quint32 type, length, precision;
312+
quint32 type, subType, length, precision;
301313
QString name, typeName, comment, alias, defaultValueExpression;
302-
in >> name >> type >> typeName >> length >> precision >> comment >> alias >> defaultValueExpression;
314+
in >> name >> type >> typeName >> length >> precision >> comment >> alias >> defaultValueExpression >> subType;
303315
field.setName( name );
304316
field.setType( static_cast< QVariant::Type >( type ) );
305317
field.setTypeName( typeName );
@@ -308,6 +320,7 @@ QDataStream& operator>>( QDataStream& in, QgsField& field )
308320
field.setComment( comment );
309321
field.setAlias( alias );
310322
field.setDefaultValueExpression( defaultValueExpression );
323+
field.setSubType( static_cast< QVariant::Type >( subType ) );
311324
return in;
312325
}
313326

src/core/qgsfield.h

+21-1
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,17 @@ class CORE_EXPORT QgsField
6666
* @param prec Field precision. Usually decimal places but may also be
6767
* used in conjunction with other fields types (eg. variable character fields)
6868
* @param comment Comment for the field
69+
* @param subType If the field is a collection, its element's type. When
70+
* all the elements don't need to have the same type, leave
71+
* this to QVariant::Invalid.
6972
*/
7073
QgsField( const QString& name = QString(),
7174
QVariant::Type type = QVariant::Invalid,
7275
const QString& typeName = QString(),
7376
int len = 0,
7477
int prec = 0,
75-
const QString& comment = QString() );
78+
const QString& comment = QString(),
79+
QVariant::Type subType = QVariant::Invalid );
7680

7781
/** Copy constructor
7882
*/
@@ -105,6 +109,14 @@ class CORE_EXPORT QgsField
105109
//! Gets variant type of the field as it will be retrieved from data source
106110
QVariant::Type type() const;
107111

112+
/**
113+
* If the field is a collection, gets its element's type.
114+
* When all the elements don't need to have the same type, this returns
115+
* QVariant::Invalid.
116+
* @note added in QGIS 3.0
117+
*/
118+
QVariant::Type subType() const;
119+
108120
/**
109121
* Gets the field type. Field types vary depending on the data source. Examples
110122
* are char, int, double, blob, geometry, etc. The type is stored exactly as
@@ -149,6 +161,14 @@ class CORE_EXPORT QgsField
149161
*/
150162
void setType( QVariant::Type type );
151163

164+
/**
165+
* If the field is a collection, set its element's type.
166+
* When all the elements don't need to have the same type, set this to
167+
* QVariant::Invalid.
168+
* @note added in QGIS 3.0
169+
*/
170+
void setSubType( QVariant::Type subType );
171+
152172
/**
153173
* Set the field type.
154174
* @param typeName Field type

src/core/qgsfield_p.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ class QgsFieldPrivate : public QSharedData
4444

4545
QgsFieldPrivate( const QString& name = QString(),
4646
QVariant::Type type = QVariant::Invalid,
47+
QVariant::Type subType = QVariant::Invalid,
4748
const QString& typeName = QString(),
4849
int len = 0,
4950
int prec = 0,
5051
const QString& comment = QString() )
5152
: name( name )
5253
, type( type )
54+
, subType( subType )
5355
, typeName( typeName )
5456
, length( len )
5557
, precision( prec )
@@ -61,6 +63,7 @@ class QgsFieldPrivate : public QSharedData
6163
: QSharedData( other )
6264
, name( other.name )
6365
, type( other.type )
66+
, subType( other.subType )
6467
, typeName( other.typeName )
6568
, length( other.length )
6669
, precision( other.precision )
@@ -74,7 +77,7 @@ class QgsFieldPrivate : public QSharedData
7477

7578
bool operator==( const QgsFieldPrivate& other ) const
7679
{
77-
return (( name == other.name ) && ( type == other.type )
80+
return (( name == other.name ) && ( type == other.type ) && ( subType == other.subType )
7881
&& ( length == other.length ) && ( precision == other.precision )
7982
&& ( alias == other.alias ) && ( defaultValueExpression == other.defaultValueExpression ) );
8083
}
@@ -85,6 +88,9 @@ class QgsFieldPrivate : public QSharedData
8588
//! Variant type
8689
QVariant::Type type;
8790

91+
//! If the variant is a collection, its element's type
92+
QVariant::Type subType;
93+
8894
//! Type name from provider
8995
QString typeName;
9096

0 commit comments

Comments
 (0)