Skip to content

Commit

Permalink
Merge pull request #3467 from pvalsecc/arrays
Browse files Browse the repository at this point in the history
[FEATURE] Add support for array attributes
  • Loading branch information
nyalldawson committed Sep 15, 2016
2 parents 6f6979a + 57d0094 commit 8746932
Show file tree
Hide file tree
Showing 49 changed files with 1,355 additions and 146 deletions.
22 changes: 21 additions & 1 deletion python/core/qgsfield.sip
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion python/core/qgsvectordataprovider.sip
Expand Up @@ -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;
Expand All @@ -311,6 +311,7 @@ class QgsVectorDataProvider : QgsDataProvider
int mMaxLen;
int mMinPrec;
int mMaxPrec;
QVariant::Type mSubType;
};

/**
Expand Down
7 changes: 7 additions & 0 deletions python/gui/editorwidgets/core/qgseditorwidgetwrapper.sip
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions python/gui/gui.sip
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion python/gui/qgskeyvaluewidget.sip
Expand Up @@ -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"
Expand Down
32 changes: 32 additions & 0 deletions python/gui/qgslistwidget.sip
@@ -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;
};
28 changes: 28 additions & 0 deletions python/gui/qgstablewidgetbase.sip
@@ -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();
};
1 change: 1 addition & 0 deletions src/app/qgsfieldcalculator.cpp
Expand Up @@ -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 );
Expand Down
5 changes: 4 additions & 1 deletion src/app/qgsfieldcalculator.h
Expand Up @@ -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*/
Expand Down
16 changes: 16 additions & 0 deletions src/core/qgsexpression.cpp
Expand Up @@ -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();
Expand Down
4 changes: 3 additions & 1 deletion src/core/qgsexpressionfieldbuffer.cpp
Expand Up @@ -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 );
Expand All @@ -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 ) ) );
}
}
}
Expand Down
21 changes: 17 additions & 4 deletions src/core/qgsfield.cpp
Expand Up @@ -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 )
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 );
Expand All @@ -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;
}

Expand Down
22 changes: 21 additions & 1 deletion src/core/qgsfield.h
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
8 changes: 7 additions & 1 deletion src/core/qgsfield_p.h
Expand Up @@ -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 )
Expand All @@ -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 )
Expand All @@ -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 ) );
}
Expand All @@ -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;

Expand Down

0 comments on commit 8746932

Please sign in to comment.