Skip to content
Permalink
Browse files

Merge pull request #3467 from pvalsecc/arrays

[FEATURE] Add support for array attributes
  • Loading branch information
nyalldawson committed Sep 15, 2016
2 parents 6f6979a + 57d0094 commit 87469321932c209f7d3ae23a2255e1294ce610ca
Showing with 1,355 additions and 146 deletions.
  1. +21 −1 python/core/qgsfield.sip
  2. +2 −1 python/core/qgsvectordataprovider.sip
  3. +7 −0 python/gui/editorwidgets/core/qgseditorwidgetwrapper.sip
  4. +2 −0 python/gui/gui.sip
  5. +1 −1 python/gui/qgskeyvaluewidget.sip
  6. +32 −0 python/gui/qgslistwidget.sip
  7. +28 −0 python/gui/qgstablewidgetbase.sip
  8. +1 −0 src/app/qgsfieldcalculator.cpp
  9. +4 −1 src/app/qgsfieldcalculator.h
  10. +16 −0 src/core/qgsexpression.cpp
  11. +3 −1 src/core/qgsexpressionfieldbuffer.cpp
  12. +17 −4 src/core/qgsfield.cpp
  13. +21 −1 src/core/qgsfield.h
  14. +7 −1 src/core/qgsfield_p.h
  15. +3 −1 src/core/qgsvectordataprovider.h
  16. +9 −1 src/gui/CMakeLists.txt
  17. +2 −0 src/gui/editorwidgets/core/qgseditorwidgetregistry.cpp
  18. +8 −1 src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp
  19. +7 −0 src/gui/editorwidgets/core/qgseditorwidgetwrapper.h
  20. +7 −9 src/gui/editorwidgets/qgskeyvaluewidgetwrapper.cpp
  21. +3 −0 src/gui/editorwidgets/qgskeyvaluewidgetwrapper.h
  22. +97 −0 src/gui/editorwidgets/qgslistwidgetfactory.cpp
  23. +46 −0 src/gui/editorwidgets/qgslistwidgetfactory.h
  24. +93 −0 src/gui/editorwidgets/qgslistwidgetwrapper.cpp
  25. +59 −0 src/gui/editorwidgets/qgslistwidgetwrapper.h
  26. +2 −36 src/gui/qgskeyvaluewidget.cpp
  27. +2 −20 src/gui/qgskeyvaluewidget.h
  28. +140 −0 src/gui/qgslistwidget.cpp
  29. +92 −0 src/gui/qgslistwidget.h
  30. +56 −0 src/gui/qgstablewidgetbase.cpp
  31. +71 −0 src/gui/qgstablewidgetbase.h
  32. +11 −3 src/providers/memory/qgsmemoryprovider.cpp
  33. +18 −0 src/providers/postgres/qgspostgresconn.cpp
  34. +3 −2 src/providers/postgres/qgspostgresfeatureiterator.cpp
  35. +143 −47 src/providers/postgres/qgspostgresprovider.cpp
  36. +2 −1 src/providers/postgres/qgspostgresprovider.h
  37. +8 −4 src/providers/wfs/qgswfsprovider.cpp
  38. +1 −1 src/ui/{qgskeyvaluewidgetbase.ui → qgstablewidgetbase.ui}
  39. +9 −0 tests/src/core/testqgsexpression.cpp
  40. +12 −0 tests/src/core/testqgsfield.cpp
  41. +1 −1 tests/src/gui/CMakeLists.txt
  42. +7 −0 tests/src/gui/testqgseditorwidgetregistry.cpp
  43. +126 −0 tests/src/gui/testqgslistwidget.cpp
  44. +16 −0 tests/src/providers/testqgspostgresconn.cpp
  45. +39 −4 tests/src/providers/testqgspostgresprovider.cpp
  46. +3 −3 tests/src/python/test_provider_memory.py
  47. +59 −1 tests/src/python/test_provider_postgres.py
  48. +1 −0 tests/testdata/provider/testdata_pg.sh
  49. +37 −0 tests/testdata/provider/testdata_pg_array.sql
@@ -24,13 +24,17 @@ class QgsField
* @param prec Field precision. Usually decimal places but may also be
* used in conjunction with other fields types (eg. variable character fields)
* @param comment Comment for the field
* @param subType If the field is a collection, its element's type. When
* all the elements don't need to have the same type, leave
* this to QVariant::Invalid.
*/
QgsField( const QString& name = QString(),
QVariant::Type type = QVariant::Invalid,
const QString& typeName = QString(),
int len = 0,
int prec = 0,
const QString& comment = QString() );
const QString& comment = QString(),
QVariant::Type subType = QVariant::Invalid );

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

/**
* If the field is a collection, gets its element's type.
* When all the elements don't need to have the same type, this returns
* QVariant::Invalid.
* @note added in QGIS 3.0
*/
QVariant::Type subType() const;

/**
* Gets the field type. Field types vary depending on the data source. Examples
* are char, int, double, blob, geometry, etc. The type is stored exactly as
@@ -103,6 +115,14 @@ class QgsField
*/
void setType( QVariant::Type type );

/**
* If the field is a collection, set its element's type.
* When all the elements don't need to have the same type, set this to
* QVariant::Invalid.
* @note added in QGIS 3.0
*/
void setSubType( QVariant::Type subType );

/**
* Set the field type.
* @param typeName Field type
@@ -302,7 +302,7 @@ class QgsVectorDataProvider : QgsDataProvider

struct NativeType
{
NativeType( const QString& typeDesc, const QString& typeName, QVariant::Type type, int minLen = 0, int maxLen = 0, int minPrec = 0, int maxPrec = 0 );
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 );

QString mTypeDesc;
QString mTypeName;
@@ -311,6 +311,7 @@ class QgsVectorDataProvider : QgsDataProvider
int mMaxLen;
int mMinPrec;
int mMaxPrec;
QVariant::Type mSubType;
};

/**
@@ -75,6 +75,13 @@ class QgsEditorWidgetWrapper : QgsWidgetWrapper
*/
static QgsEditorWidgetWrapper* fromWidget( QWidget* widget );

/**
* Check if the given widget or one of its parent is a QTableView.
* @param parent the widget to check
* @return true if yes
*/
static bool isInTable( const QWidget* parent );

/**
* Is used to enable or disable the edit functionality of the managed widget.
* By default this will enable or disable the whole widget
@@ -96,6 +96,7 @@
%Include qgshtmlannotationitem.sip
%Include qgsidentifymenu.sip
%Include qgskeyvaluewidget.sip
%Include qgslistwidget.sip
%Include qgslegendfilterbutton.sip
%Include qgslegendinterface.sip
%Include qgslimitedrandomcolorrampdialog.sip
@@ -161,6 +162,7 @@
%Include qgssourceselectdialog.sip
%Include qgssublayersdialog.sip
%Include qgssvgannotationitem.sip
%Include qgstablewidgetbase.sip
%Include qgstabwidget.sip
%Include qgstablewidgetitem.sip
%Include qgstextannotationitem.sip
@@ -2,7 +2,7 @@
* Widget allowing to edit a QVariantMap, using a table.
* @note added in QGIS 3.0
*/
class QgsKeyValueWidget : public QWidget
class QgsKeyValueWidget : public QgsTableWidgetBase
{
%TypeHeaderCode
#include "qgskeyvaluewidget.h"
@@ -0,0 +1,32 @@
/** \ingroup gui
* Widget allowing to edit a QVariantList, using a table.
* @note added in QGIS 3.0
*/
class QgsListWidget : public QgsTableWidgetBase
{
%TypeHeaderCode
#include "qgslistwidget.h"
%End
public:
/**
* Constructor.
*/
explicit QgsListWidget( QVariant::Type subType, QWidget* parent = nullptr );

/**
* Set the initial value of the widget.
*/
void setList( const QVariantList& list );

/**
* Get the edit value.
* @return the QVariantList
*/
QVariantList list() const;

/**
* Check the content is valid
* @return true if valid
*/
bool valid() const;
};
@@ -0,0 +1,28 @@
/** \ingroup gui
* Base widget allowing to edit a collection, using a table.
* @note added in QGIS 3.0
*/
class QgsTableWidgetBase: public QWidget
{
%TypeHeaderCode
#include "qgstablewidgetbase.h"
%End
public:
/**
* Constructor.
*/
explicit QgsTableWidgetBase( QWidget* parent );

protected:
/**
* Initialise the table with the given model.
* Must be called once in the child class' constructor.
*/
void init( QAbstractTableModel* model );

signals:
/**
* Emitted each time a key or a value is changed.
*/
void valueChanged();
};
@@ -346,6 +346,7 @@ void QgsFieldCalculator::populateOutputFieldTypes()
mOutputFieldTypeComboBox->setItemData( i, typelist[i].mMaxLen, Qt::UserRole + 3 );
mOutputFieldTypeComboBox->setItemData( i, typelist[i].mMinPrec, Qt::UserRole + 4 );
mOutputFieldTypeComboBox->setItemData( i, typelist[i].mMaxPrec, Qt::UserRole + 5 );
mOutputFieldTypeComboBox->setItemData( i, static_cast<int>( typelist[i].mSubType ), Qt::UserRole + 6 );
}
mOutputFieldTypeComboBox->blockSignals( false );
mOutputFieldTypeComboBox->setCurrentIndex( 0 );
@@ -67,7 +67,10 @@ class APP_EXPORT QgsFieldCalculator: public QDialog, private Ui::QgsFieldCalcula
static_cast< QVariant::Type >( mOutputFieldTypeComboBox->itemData( mOutputFieldTypeComboBox->currentIndex(), Qt::UserRole ).toInt() ),
mOutputFieldTypeComboBox->itemData( mOutputFieldTypeComboBox->currentIndex(), Qt::UserRole + 1 ).toString(),
mOutputFieldWidthSpinBox->value(),
mOutputFieldPrecisionSpinBox->value() );
mOutputFieldPrecisionSpinBox->value(),
QString(),
static_cast< QVariant::Type >( mOutputFieldTypeComboBox->itemData( mOutputFieldTypeComboBox->currentIndex(), Qt::UserRole + 6 ).toInt() )
);
}

/** Idx of changed attribute*/
@@ -5074,6 +5074,22 @@ QString QgsExpression::formatPreviewString( const QVariant& value )
}
return tr( "<i>&lt;map: %1&gt;</i>" ).arg( mapStr );
}
else if ( value.type() == QVariant::List || value.type() == QVariant::StringList )
{
QString listStr;
const QVariantList list = value.toList();
for ( QVariantList::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
{
if ( !listStr.isEmpty() ) listStr.append( ", " );
listStr.append( formatPreviewString( *it ) );
if ( listStr.length() > MAX_PREVIEW + 3 )
{
listStr = QString( tr( "%1..." ) ).arg( listStr.left( MAX_PREVIEW ) );
break;
}
}
return tr( "<i>&lt;list: %1&gt;</i>" ).arg( listStr );
}
else
{
return value.toString();
@@ -54,6 +54,7 @@ void QgsExpressionFieldBuffer::writeXml( QDomNode& layerNode, QDomDocument& docu
fldElem.setAttribute( "comment", fld.field.comment() );
fldElem.setAttribute( "length", fld.field.length() );
fldElem.setAttribute( "type", fld.field.type() );
fldElem.setAttribute( "subType", fld.field.subType() );
fldElem.setAttribute( "typeName", fld.field.typeName() );

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

mExpressions.append( ExpressionField( exp, QgsField( name, type, typeName, length, precision, comment ) ) );
mExpressions.append( ExpressionField( exp, QgsField( name, type, typeName, length, precision, comment, subType ) ) );
}
}
}
@@ -44,9 +44,10 @@ QgsField::QgsField( QString nam, QString typ, int len, int prec, bool num,
}
#endif
QgsField::QgsField( const QString& name, QVariant::Type type,
const QString& typeName, int len, int prec, const QString& comment )
const QString& typeName, int len, int prec, const QString& comment,
QVariant::Type subType )
{
d = new QgsFieldPrivate( name, type, typeName, len, prec, comment );
d = new QgsFieldPrivate( name, type, subType, typeName, len, prec, comment );
}

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

QVariant::Type QgsField::subType() const
{
return d->subType;
}

QString QgsField::typeName() const
{
return d->typeName;
@@ -140,6 +146,11 @@ void QgsField::setType( QVariant::Type type )
d->type = type;
}

void QgsField::setSubType( QVariant::Type subType )
{
d->subType = subType;
}

void QgsField::setTypeName( const QString& typeName )
{
d->typeName = typeName;
@@ -292,14 +303,15 @@ QDataStream& operator<<( QDataStream& out, const QgsField& field )
out << field.comment();
out << field.alias();
out << field.defaultValueExpression();
out << static_cast< quint32 >( field.subType() );
return out;
}

QDataStream& operator>>( QDataStream& in, QgsField& field )
{
quint32 type, length, precision;
quint32 type, subType, length, precision;
QString name, typeName, comment, alias, defaultValueExpression;
in >> name >> type >> typeName >> length >> precision >> comment >> alias >> defaultValueExpression;
in >> name >> type >> typeName >> length >> precision >> comment >> alias >> defaultValueExpression >> subType;
field.setName( name );
field.setType( static_cast< QVariant::Type >( type ) );
field.setTypeName( typeName );
@@ -308,6 +320,7 @@ QDataStream& operator>>( QDataStream& in, QgsField& field )
field.setComment( comment );
field.setAlias( alias );
field.setDefaultValueExpression( defaultValueExpression );
field.setSubType( static_cast< QVariant::Type >( subType ) );
return in;
}

@@ -66,13 +66,17 @@ class CORE_EXPORT QgsField
* @param prec Field precision. Usually decimal places but may also be
* used in conjunction with other fields types (eg. variable character fields)
* @param comment Comment for the field
* @param subType If the field is a collection, its element's type. When
* all the elements don't need to have the same type, leave
* this to QVariant::Invalid.
*/
QgsField( const QString& name = QString(),
QVariant::Type type = QVariant::Invalid,
const QString& typeName = QString(),
int len = 0,
int prec = 0,
const QString& comment = QString() );
const QString& comment = QString(),
QVariant::Type subType = QVariant::Invalid );

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

/**
* If the field is a collection, gets its element's type.
* When all the elements don't need to have the same type, this returns
* QVariant::Invalid.
* @note added in QGIS 3.0
*/
QVariant::Type subType() const;

/**
* Gets the field type. Field types vary depending on the data source. Examples
* are char, int, double, blob, geometry, etc. The type is stored exactly as
@@ -149,6 +161,14 @@ class CORE_EXPORT QgsField
*/
void setType( QVariant::Type type );

/**
* If the field is a collection, set its element's type.
* When all the elements don't need to have the same type, set this to
* QVariant::Invalid.
* @note added in QGIS 3.0
*/
void setSubType( QVariant::Type subType );

/**
* Set the field type.
* @param typeName Field type
@@ -44,12 +44,14 @@ class QgsFieldPrivate : public QSharedData

QgsFieldPrivate( const QString& name = QString(),
QVariant::Type type = QVariant::Invalid,
QVariant::Type subType = QVariant::Invalid,
const QString& typeName = QString(),
int len = 0,
int prec = 0,
const QString& comment = QString() )
: name( name )
, type( type )
, subType( subType )
, typeName( typeName )
, length( len )
, precision( prec )
@@ -61,6 +63,7 @@ class QgsFieldPrivate : public QSharedData
: QSharedData( other )
, name( other.name )
, type( other.type )
, subType( other.subType )
, typeName( other.typeName )
, length( other.length )
, precision( other.precision )
@@ -74,7 +77,7 @@ class QgsFieldPrivate : public QSharedData

bool operator==( const QgsFieldPrivate& other ) const
{
return (( name == other.name ) && ( type == other.type )
return (( name == other.name ) && ( type == other.type ) && ( subType == other.subType )
&& ( length == other.length ) && ( precision == other.precision )
&& ( alias == other.alias ) && ( defaultValueExpression == other.defaultValueExpression ) );
}
@@ -85,6 +88,9 @@ class QgsFieldPrivate : public QSharedData
//! Variant type
QVariant::Type type;

//! If the variant is a collection, its element's type
QVariant::Type subType;

//! Type name from provider
QString typeName;

0 comments on commit 8746932

Please sign in to comment.
You can’t perform that action at this time.