Skip to content
Permalink
Browse files
Add QgsMemoryProviderUtils.createMemoryLayer for easy creation
of new memory layers from QgsFields/QgsCoordinateReferenceSystem/etc

Since memory provider cannot use QgsVectorLayerImport we need
another centeralized function for creating new memory layers
without the need to manually create the uri string.
  • Loading branch information
nyalldawson committed May 6, 2017
1 parent 5511b07 commit 767cb12
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 12 deletions.
@@ -107,6 +107,8 @@ INCLUDE_DIRECTORIES(
../src/core/layertree
../src/core/metadata
../src/core/processing
../src/core/providers
../src/core/providers/memory
../src/core/raster
../src/core/scalebar
../src/core/symbology-ng
@@ -286,6 +286,8 @@
%Include processing/qgsprocessingregistry.sip
%Include processing/qgsprocessingutils.sip

%Include providers/memory/qgsmemoryproviderutils.sip

%Include raster/qgsbilinearrasterresampler.sip
%Include raster/qgsbrightnesscontrastfilter.sip
%Include raster/qgscliptominmaxenhancement.sip
@@ -9,6 +9,7 @@




class QgsMemoryProviderUtils
{
%Docstring
@@ -21,6 +22,19 @@ class QgsMemoryProviderUtils
%End
public:

static QgsVectorLayer *createMemoryLayer( const QString &name,
const QgsFields &fields,
QgsWkbTypes::Type geometryType = QgsWkbTypes::NoGeometry,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ) /Factory/;
%Docstring
Creates a new memory layer using the specified parameters. The caller takes responsibility
for deleting the newly created layer.
\param name layer name
\param fields fields for layer
\param geometryType optional layer geometry type
\param crs optional layer CRS for layers with geometry
:rtype: QgsVectorLayer
%End
};


@@ -500,6 +500,7 @@ INCLUDE_DIRECTORIES(
../core/dxf
../core/geometry
../core/layertree
../core/providers/memory
../core/raster
../core/scalebar
../core/symbology-ng
@@ -94,6 +94,7 @@ SET(QGIS_CORE_SRCS

providers/memory/qgsmemoryfeatureiterator.cpp
providers/memory/qgsmemoryprovider.cpp
providers/memory/qgsmemoryproviderutils.cpp

scalebar/qgsdoubleboxscalebarrenderer.cpp
scalebar/qgsnumericscalebarrenderer.cpp
@@ -872,6 +873,7 @@ SET(QGIS_CORE_HDRS
processing/qgsprocessingutils.h

providers/memory/qgsmemoryfeatureiterator.h
providers/memory/qgsmemoryproviderutils.h

raster/qgsbilinearrasterresampler.h
raster/qgsbrightnesscontrastfilter.h
@@ -16,3 +16,68 @@
***************************************************************************/

#include "qgsmemoryproviderutils.h"
#include "qgsfields.h"
#include "qgsvectorlayer.h"

QString memoryLayerFieldType( QVariant::Type type )
{
switch ( type )
{
case QVariant::Int:
return QStringLiteral( "integer" );

case QVariant::LongLong:
return QStringLiteral( "long" );

case QVariant::Double:
return QStringLiteral( "double" );

case QVariant::String:
return QStringLiteral( "string" );

case QVariant::Date:
return QStringLiteral( "date" );

case QVariant::Time:
return QStringLiteral( "time" );

case QVariant::DateTime:
return QStringLiteral( "datetime" );

default:
return QStringLiteral( "string" );
}
return QStringLiteral( "string" ); // no warnings
}

QgsVectorLayer *QgsMemoryProviderUtils::createMemoryLayer( const QString &name, const QgsFields &fields, QgsWkbTypes::Type geometryType, const QgsCoordinateReferenceSystem &crs )
{
QString geomType = QgsWkbTypes::displayString( geometryType );
if ( geomType.isNull() )
geomType = "none";

QString uri = geomType + '?';

bool first = true;
if ( crs.isValid() )
{
uri += QStringLiteral( "crs=" ) + crs.authid();
first = false;
}

QStringList fieldsStrings;
Q_FOREACH ( const QgsField &field, fields )
{
fieldsStrings << QStringLiteral( "field=%1:%2" ).arg( field.name(), memoryLayerFieldType( field.type() ) );
}

if ( !fieldsStrings.isEmpty() )
{
if ( !first )
uri += '&';
first = false;
uri += fieldsStrings.join( '&' );
}

return new QgsVectorLayer( uri, name, QStringLiteral( "memory" ) );
}
@@ -19,6 +19,13 @@
#define QGSMEMORYPROVIDERUTILS_H

#include "qgis_core.h"
#include "qgis.h"
#include "qgscoordinatereferencesystem.h"
#include <QString>
#include <QVariant>

class QgsVectorLayer;
class QgsFields;

/**
* \class QgsMemoryProviderUtils
@@ -31,6 +38,18 @@ class CORE_EXPORT QgsMemoryProviderUtils

public:

/**
* Creates a new memory layer using the specified parameters. The caller takes responsibility
* for deleting the newly created layer.
* \param name layer name
* \param fields fields for layer
* \param geometryType optional layer geometry type
* \param crs optional layer CRS for layers with geometry
*/
static QgsVectorLayer *createMemoryLayer( const QString &name,
const QgsFields &fields,
QgsWkbTypes::Type geometryType = QgsWkbTypes::NoGeometry,
const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ) SIP_FACTORY;
};

#endif // QGSMEMORYPROVIDERUTILS_H
@@ -748,6 +748,7 @@ INCLUDE_DIRECTORIES(
../core/geometry
../core/layertree
../core/metadata
../core/providers/memory
../core/raster
../core/scalebar
../core/symbology-ng
@@ -23,6 +23,7 @@
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include "qgssettings.h"
#include "qgsmemoryproviderutils.h"

#include <QPushButton>
#include <QComboBox>
@@ -40,18 +41,8 @@ QgsVectorLayer *QgsNewMemoryLayerDialog::runAndCreateLayer( QWidget *parent, con
}

QgsWkbTypes::Type geometrytype = dialog.selectedType();

QString geomType = QgsWkbTypes::displayString( geometrytype );
if ( geomType.isNull() )
geomType = "none";

QString layerProperties = QStringLiteral( "%1?" ).arg( geomType );
if ( QgsWkbTypes::NoGeometry != geometrytype )
layerProperties.append( QStringLiteral( "crs=%1&" ).arg( dialog.crs().authid() ) );
layerProperties.append( QStringLiteral( "memoryid=%1" ).arg( QUuid::createUuid().toString() ) );

QString name = dialog.layerName().isEmpty() ? tr( "New scratch layer" ) : dialog.layerName();
QgsVectorLayer *newLayer = new QgsVectorLayer( layerProperties, name, QStringLiteral( "memory" ) );
QgsVectorLayer *newLayer = QgsMemoryProviderUtils::createMemoryLayer( name, QgsFields(), geometrytype, dialog.crs() );
return newLayer;
}

@@ -15,6 +15,7 @@

from qgis.core import (
QgsField,
QgsFields,
QgsLayerDefinition,
QgsPoint,
QgsPathResolver,
@@ -23,7 +24,9 @@
QgsFeature,
QgsGeometry,
QgsWkbTypes,
NULL
NULL,
QgsMemoryProviderUtils,
QgsCoordinateReferenceSystem
)

from qgis.testing import (
@@ -335,6 +338,58 @@ def testRenameAttributes(self):
self.assertEqual(fet.fields()[1].name(), 'mapinfo_is_the_stone_age')
self.assertEqual(fet.fields()[2].name(), 'super_size')

def testCreateMemoryLayer(self):
"""
Test QgsMemoryProviderUtils.createMemoryLayer()
"""

# no fields
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields())
self.assertTrue(layer.isValid())
self.assertEqual(layer.name(), 'my name')
self.assertTrue(layer.fields().isEmpty())

# geometry type
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.Point)
self.assertTrue(layer.isValid())
self.assertEqual(layer.wkbType(), QgsWkbTypes.Point)
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.PolygonZM)
self.assertTrue(layer.isValid())
self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM)

# crs
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', QgsFields(), QgsWkbTypes.PolygonZM, QgsCoordinateReferenceSystem.fromEpsgId(3111))
self.assertTrue(layer.isValid())
self.assertEqual(layer.wkbType(), QgsWkbTypes.PolygonZM)
self.assertTrue(layer.crs().isValid())
self.assertEqual(layer.crs().authid(), 'EPSG:3111')

# fields
fields = QgsFields()
fields.append(QgsField("string", QVariant.String))
fields.append(QgsField("long", QVariant.LongLong))
fields.append(QgsField("double", QVariant.Double))
fields.append(QgsField("integer", QVariant.Int))
fields.append(QgsField("date", QVariant.Date))
fields.append(QgsField("datetime", QVariant.DateTime))
fields.append(QgsField("time", QVariant.Time))
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields)
self.assertTrue(layer.isValid())
self.assertFalse(layer.fields().isEmpty())
self.assertEqual(len(layer.fields()), len(fields))
for i in range(len(fields)):
self.assertEqual(layer.fields()[i].name(), fields[i].name())
self.assertEqual(layer.fields()[i].type(), fields[i].type())

# unsupported field type
fields = QgsFields()
fields.append(QgsField("rect", QVariant.RectF))
layer = QgsMemoryProviderUtils.createMemoryLayer('my name', fields)
self.assertTrue(layer.isValid())
self.assertFalse(layer.fields().isEmpty())
self.assertEqual(layer.fields()[0].name(), 'rect')
self.assertEqual(layer.fields()[0].type(), QVariant.String) # should be mapped to string


class TestPyQgsMemoryProviderIndexed(unittest.TestCase, ProviderTestCase):

0 comments on commit 767cb12

Please sign in to comment.