mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
Merge pull request #4478 from nyalldawson/layer_store
Split off map layer storage handling from QgsProject to QgsMapLayerStore
This commit is contained in:
commit
b5ae888b60
@ -92,6 +92,7 @@
|
||||
%Include qgsmaplayermodel.sip
|
||||
%Include qgsmaplayerproxymodel.sip
|
||||
%Include qgsmaplayerrenderer.sip
|
||||
%Include qgsmaplayerstore.sip
|
||||
%Include qgsmaplayerstylemanager.sip
|
||||
%Include qgsmaprenderercache.sip
|
||||
%Include qgsmaprenderercustompainterjob.sip
|
||||
|
@ -75,11 +75,11 @@ class QgsProcessingContext
|
||||
Sets the expression ``context``.
|
||||
%End
|
||||
|
||||
QgsProject &temporaryLayerStore();
|
||||
QgsMapLayerStore *temporaryLayerStore();
|
||||
%Docstring
|
||||
Returns a reference to the project used for storing temporary layers during
|
||||
Returns a reference to the layer store used for storing temporary layers during
|
||||
algorithm execution.
|
||||
:rtype: QgsProject
|
||||
:rtype: QgsMapLayerStore
|
||||
%End
|
||||
|
||||
QgsFeatureRequest::InvalidGeometryCheck invalidGeometryCheck() const;
|
||||
|
313
python/core/qgsmaplayerstore.sip
Normal file
313
python/core/qgsmaplayerstore.sip
Normal file
@ -0,0 +1,313 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/qgsmaplayerstore.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsMapLayerStore : QObject
|
||||
{
|
||||
%Docstring
|
||||
A storage object for map layers, in which the layers are owned by the
|
||||
store and have their lifetime bound to the store.
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsmaplayerstore.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
explicit QgsMapLayerStore( QObject *parent /TransferThis/ = 0 );
|
||||
%Docstring
|
||||
Constructor for QgsMapLayerStore.
|
||||
%End
|
||||
|
||||
~QgsMapLayerStore();
|
||||
|
||||
int count() const;
|
||||
%Docstring
|
||||
Returns the number of layers contained in the store.
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
|
||||
int __len__() const;
|
||||
%Docstring
|
||||
Returns the number of layers contained in the store.
|
||||
:rtype: int
|
||||
%End
|
||||
%MethodCode
|
||||
sipRes = sipCpp->count();
|
||||
%End
|
||||
|
||||
QgsMapLayer *mapLayer( const QString &id ) const;
|
||||
%Docstring
|
||||
Retrieve a pointer to a layer by layer ``id``.
|
||||
\param id ID of layer to retrieve
|
||||
:return: matching layer, or None if no matching layer found
|
||||
.. seealso:: mapLayersByName()
|
||||
.. seealso:: mapLayers()
|
||||
:rtype: QgsMapLayer
|
||||
%End
|
||||
|
||||
QList<QgsMapLayer *> mapLayersByName( const QString &name ) const;
|
||||
%Docstring
|
||||
Retrieve a list of matching layers by layer ``name``.
|
||||
\param name name of layers to match
|
||||
:return: list of matching layers
|
||||
.. seealso:: mapLayer()
|
||||
.. seealso:: mapLayers()
|
||||
:rtype: list of QgsMapLayer
|
||||
%End
|
||||
|
||||
QMap<QString, QgsMapLayer *> mapLayers() const;
|
||||
%Docstring
|
||||
Returns a map of all layers by layer ID.
|
||||
.. seealso:: mapLayer()
|
||||
.. seealso:: mapLayersByName()
|
||||
.. seealso:: layers()
|
||||
:rtype: QMap<str, QgsMapLayer *>
|
||||
%End
|
||||
|
||||
|
||||
QList<QgsMapLayer *> addMapLayers( const QList<QgsMapLayer *> &layers /Transfer/);
|
||||
|
||||
%Docstring
|
||||
\brief
|
||||
Add a list of ``layers`` to the store. Ownership of the layers is transferred
|
||||
to the store.
|
||||
|
||||
The layersAdded() and layerWasAdded() signals will always be emitted.
|
||||
|
||||
\param layers A list of layer which should be added to the store.
|
||||
\param takeOwnership Ownership will be transferred to the layer store.
|
||||
If you specify false here you have take care of deleting
|
||||
the layers yourself. Not available in Python.
|
||||
|
||||
:return: a list of the map layers that were added
|
||||
successfully. If a layer is invalid, or already exists in the store,
|
||||
it will not be part of the returned list.
|
||||
|
||||
.. seealso:: addMapLayer()
|
||||
:rtype: list of QgsMapLayer
|
||||
%End
|
||||
|
||||
QgsMapLayer *addMapLayer( QgsMapLayer *layer /Transfer/);
|
||||
|
||||
%Docstring
|
||||
\brief
|
||||
Add a ``layer`` to the store. Ownership of the layer is transferred to the
|
||||
store.
|
||||
|
||||
The layersAdded() and layerWasAdded() signals will always be emitted.
|
||||
If you are adding multiple layers at once, you should use
|
||||
addMapLayers() instead.
|
||||
|
||||
\param layer A layer to add to the store
|
||||
\param takeOwnership Ownership will be transferred to the layer store.
|
||||
If you specify false here you have take care of deleting
|
||||
the layers yourself. Not available in Python.
|
||||
|
||||
:return: None if unable to add layer, otherwise pointer to newly added layer
|
||||
|
||||
.. seealso:: addMapLayers
|
||||
|
||||
.. note::
|
||||
|
||||
Use addMapLayers() if adding more than one layer at a time.
|
||||
.. seealso:: addMapLayers()
|
||||
:rtype: QgsMapLayer
|
||||
%End
|
||||
|
||||
void removeMapLayers( const QStringList &layerIds ) /PyName=removeMapLayersById/;
|
||||
%Docstring
|
||||
\brief
|
||||
Remove a set of layers from the store by layer ID.
|
||||
|
||||
The specified layers will be removed from the store.
|
||||
These layers will also be deleted.
|
||||
|
||||
\param layerIds list of IDs of the layers to remove
|
||||
|
||||
.. seealso:: takeMapLayer()
|
||||
.. seealso:: removeMapLayer()
|
||||
.. seealso:: removeAllMapLayers()
|
||||
.. note::
|
||||
|
||||
available in Python bindings as removeMapLayersById.
|
||||
%End
|
||||
|
||||
void removeMapLayers( const QList<QgsMapLayer *> &layers );
|
||||
%Docstring
|
||||
\brief
|
||||
Remove a set of ``layers`` from the store.
|
||||
|
||||
The specified layers will be removed from the store.
|
||||
These layers will also be deleted.
|
||||
|
||||
\param layers A list of layers to remove. Null pointers are ignored.
|
||||
|
||||
.. seealso:: takeMapLayer()
|
||||
.. seealso:: removeMapLayer()
|
||||
.. seealso:: removeAllMapLayers()
|
||||
%End
|
||||
|
||||
void removeMapLayer( const QString &id );
|
||||
%Docstring
|
||||
\brief
|
||||
Remove a layer from the store by layer ``id``.
|
||||
|
||||
The specified layer will be removed from the store. The layer will also be deleted.
|
||||
|
||||
\param id ID of the layer to remove
|
||||
|
||||
.. seealso:: takeMapLayer()
|
||||
.. seealso:: removeMapLayers()
|
||||
.. seealso:: removeAllMapLayers()
|
||||
%End
|
||||
|
||||
void removeMapLayer( QgsMapLayer *layer );
|
||||
%Docstring
|
||||
\brief
|
||||
Remove a ``layer`` from the store.
|
||||
|
||||
The specified layer will be removed from the store. The layer will also be deleted.
|
||||
|
||||
\param layer The layer to remove. Null pointers are ignored.
|
||||
|
||||
.. seealso:: takeMapLayer()
|
||||
.. seealso:: removeMapLayers()
|
||||
.. seealso:: removeAllMapLayers()
|
||||
%End
|
||||
|
||||
QgsMapLayer *takeMapLayer( QgsMapLayer *layer ) /TransferBack/;
|
||||
%Docstring
|
||||
Takes a ``layer`` from the store. If the layer was owned by the store, the
|
||||
layer will be returned without deleting it. The caller takes ownership of
|
||||
the layer and is responsible for deleting it.
|
||||
.. seealso:: removeMapLayer()
|
||||
:rtype: QgsMapLayer
|
||||
%End
|
||||
|
||||
void removeAllMapLayers();
|
||||
%Docstring
|
||||
Removes all registered layers. These layers will also be deleted.
|
||||
|
||||
.. note::
|
||||
|
||||
Calling this method will cause the removeAll() signal to
|
||||
be emitted.
|
||||
.. seealso:: removeMapLayer()
|
||||
.. seealso:: removeMapLayers()
|
||||
%End
|
||||
|
||||
signals:
|
||||
|
||||
void layersWillBeRemoved( const QStringList &layerIds );
|
||||
%Docstring
|
||||
Emitted when one or more layers are about to be removed from the store.
|
||||
|
||||
\param layerIds A list of IDs for the layers which are to be removed.
|
||||
.. seealso:: layerWillBeRemoved()
|
||||
.. seealso:: layersRemoved()
|
||||
%End
|
||||
|
||||
void layersWillBeRemoved( const QList<QgsMapLayer *> &layers );
|
||||
%Docstring
|
||||
Emitted when one or more layers are about to be removed from the store.
|
||||
|
||||
\param layers A list of layers which are to be removed.
|
||||
.. seealso:: layerWillBeRemoved()
|
||||
.. seealso:: layersRemoved()
|
||||
%End
|
||||
|
||||
void layerWillBeRemoved( const QString &layerId );
|
||||
%Docstring
|
||||
Emitted when a layer is about to be removed from the store.
|
||||
|
||||
\param layerId The ID of the layer to be removed.
|
||||
|
||||
.. note::
|
||||
|
||||
Consider using layersWillBeRemoved() instead.
|
||||
.. seealso:: layersWillBeRemoved()
|
||||
.. seealso:: layerRemoved()
|
||||
%End
|
||||
|
||||
void layerWillBeRemoved( QgsMapLayer *layer );
|
||||
%Docstring
|
||||
Emitted when a layer is about to be removed from the store.
|
||||
|
||||
\param layer The layer to be removed.
|
||||
|
||||
.. note::
|
||||
|
||||
Consider using layersWillBeRemoved() instead.
|
||||
.. seealso:: layersWillBeRemoved()
|
||||
.. seealso:: layerRemoved()
|
||||
%End
|
||||
|
||||
void layersRemoved( const QStringList &layerIds );
|
||||
%Docstring
|
||||
Emitted after one or more layers were removed from the store.
|
||||
|
||||
\param layerIds A list of IDs of the layers which were removed.
|
||||
.. seealso:: layersWillBeRemoved()
|
||||
%End
|
||||
|
||||
void layerRemoved( const QString &layerId );
|
||||
%Docstring
|
||||
Emitted after a layer was removed from the store.
|
||||
|
||||
\param layerId The ID of the layer removed.
|
||||
|
||||
.. note::
|
||||
|
||||
Consider using layersRemoved() instead
|
||||
.. seealso:: layerWillBeRemoved()
|
||||
%End
|
||||
|
||||
void allLayersRemoved();
|
||||
%Docstring
|
||||
Emitted when all layers are removed, before layersWillBeRemoved() and
|
||||
layerWillBeRemoved() signals are emitted. The layersWillBeRemoved() and
|
||||
layerWillBeRemoved() signals will still be emitted following this signal.
|
||||
You can use this signal to do easy (and fast) cleanup.
|
||||
%End
|
||||
|
||||
void layersAdded( const QList<QgsMapLayer *> &layers );
|
||||
%Docstring
|
||||
Emitted when one or more layers were added to the store.
|
||||
|
||||
\param layers List of layers which have been added.
|
||||
|
||||
.. seealso:: legendLayersAdded()
|
||||
.. seealso:: layerWasAdded()
|
||||
%End
|
||||
|
||||
void layerWasAdded( QgsMapLayer *layer );
|
||||
%Docstring
|
||||
Emitted when a ``layer`` was added to the store.
|
||||
|
||||
.. note::
|
||||
|
||||
Consider using layersAdded() instead
|
||||
.. seealso:: layersAdded()
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/qgsmaplayerstore.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -422,6 +422,8 @@ class QgsProject : QObject, QgsExpressionContextGenerator
|
||||
*/
|
||||
const QgsLabelingEngineSettings &labelingEngineSettings() const;
|
||||
|
||||
QgsMapLayerStore *layerStore();
|
||||
|
||||
int count() const;
|
||||
|
||||
QgsMapLayer *mapLayer( const QString &layerId ) const;
|
||||
|
@ -481,7 +481,7 @@ def createVectorWriter(destination, encoding, fields, geometryType, crs, context
|
||||
|
||||
layer = QgsVectorLayer(uri, destination, 'memory')
|
||||
sink = layer.dataProvider()
|
||||
context.temporaryLayerStore().addMapLayer(layer, False)
|
||||
context.temporaryLayerStore().addMapLayer(layer)
|
||||
destination = layer.id()
|
||||
elif destination.startswith(POSTGIS_LAYER_PREFIX):
|
||||
uri = QgsDataSourceUri(destination[len(POSTGIS_LAYER_PREFIX):])
|
||||
@ -518,7 +518,7 @@ def createVectorWriter(destination, encoding, fields, geometryType, crs, context
|
||||
|
||||
layer = QgsVectorLayer(uri.uri(), uri.table(), "postgres")
|
||||
sink = layer.dataProvider()
|
||||
context.temporaryLayerStore().addMapLayer(layer, False)
|
||||
context.temporaryLayerStore().addMapLayer(layer)
|
||||
elif destination.startswith(SPATIALITE_LAYER_PREFIX):
|
||||
uri = QgsDataSourceUri(destination[len(SPATIALITE_LAYER_PREFIX):])
|
||||
try:
|
||||
@ -548,7 +548,7 @@ def createVectorWriter(destination, encoding, fields, geometryType, crs, context
|
||||
|
||||
layer = QgsVectorLayer(uri.uri(), uri.table(), "spatialite")
|
||||
sink = layer.dataProvider()
|
||||
context.temporaryLayerStore().addMapLayer(layer, False)
|
||||
context.temporaryLayerStore().addMapLayer(layer)
|
||||
else:
|
||||
formats = QgsVectorFileWriter.supportedFiltersAndFormats()
|
||||
OGRCodes = {}
|
||||
|
@ -178,6 +178,7 @@ SET(QGIS_CORE_SRCS
|
||||
qgsmaplayerlegend.cpp
|
||||
qgsmaplayermodel.cpp
|
||||
qgsmaplayerproxymodel.cpp
|
||||
qgsmaplayerstore.cpp
|
||||
qgsmaplayerstylemanager.cpp
|
||||
qgsmaprenderercache.cpp
|
||||
qgsmaprenderercustompainterjob.cpp
|
||||
@ -527,6 +528,7 @@ SET(QGIS_CORE_MOC_HDRS
|
||||
qgsmaplayerlegend.h
|
||||
qgsmaplayermodel.h
|
||||
qgsmaplayerproxymodel.h
|
||||
qgsmaplayerstore.h
|
||||
qgsmaplayerstylemanager.h
|
||||
qgsmaprenderercache.h
|
||||
qgsmaprenderercustompainterjob.h
|
||||
|
@ -90,10 +90,10 @@ class CORE_EXPORT QgsProcessingContext
|
||||
void setExpressionContext( const QgsExpressionContext &context ) { mExpressionContext = context; }
|
||||
|
||||
/**
|
||||
* Returns a reference to the project used for storing temporary layers during
|
||||
* Returns a reference to the layer store used for storing temporary layers during
|
||||
* algorithm execution.
|
||||
*/
|
||||
QgsProject &temporaryLayerStore() { return tempProject; }
|
||||
QgsMapLayerStore *temporaryLayerStore() { return &tempLayerStore; }
|
||||
|
||||
/**
|
||||
* Returns the behavior used for checking invalid geometries in input layers.
|
||||
@ -147,7 +147,7 @@ class CORE_EXPORT QgsProcessingContext
|
||||
QgsProcessingContext::Flags mFlags = 0;
|
||||
QPointer< QgsProject > mProject;
|
||||
//! Temporary project owned by the context, used for storing temporarily loaded map layers
|
||||
QgsProject tempProject;
|
||||
QgsMapLayerStore tempLayerStore;
|
||||
QgsExpressionContext mExpressionContext;
|
||||
QgsFeatureRequest::InvalidGeometryCheck mInvalidGeometryCheck = QgsFeatureRequest::GeometryNoCheck;
|
||||
std::function< void( const QgsFeature & ) > mInvalidGeometryCallback;
|
||||
|
@ -85,12 +85,27 @@ QList<QgsMapLayer *> QgsProcessingUtils::compatibleLayers( QgsProject *project,
|
||||
return layers;
|
||||
}
|
||||
|
||||
QgsMapLayer *QgsProcessingUtils::mapLayerFromProject( const QString &string, QgsProject *project )
|
||||
QgsMapLayer *QgsProcessingUtils::mapLayerFromStore( const QString &string, QgsMapLayerStore *store )
|
||||
{
|
||||
if ( string.isEmpty() )
|
||||
if ( !store || string.isEmpty() )
|
||||
return nullptr;
|
||||
|
||||
QList< QgsMapLayer * > layers = compatibleLayers( project, false );
|
||||
QList< QgsMapLayer * > layers = store->mapLayers().values();
|
||||
|
||||
layers.erase( std::remove_if( layers.begin(), layers.end(), []( QgsMapLayer * layer )
|
||||
{
|
||||
switch ( layer->type() )
|
||||
{
|
||||
case QgsMapLayer::VectorLayer:
|
||||
return !canUseLayer( qobject_cast< QgsVectorLayer * >( layer ) );
|
||||
case QgsMapLayer::RasterLayer:
|
||||
return !canUseLayer( qobject_cast< QgsRasterLayer * >( layer ) );
|
||||
case QgsMapLayer::PluginLayer:
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
} ), layers.end() );
|
||||
|
||||
Q_FOREACH ( QgsMapLayer *l, layers )
|
||||
{
|
||||
if ( l->id() == string )
|
||||
@ -108,6 +123,7 @@ QgsMapLayer *QgsProcessingUtils::mapLayerFromProject( const QString &string, Qgs
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
///@cond PRIVATE
|
||||
class ProjectionSettingRestorer
|
||||
{
|
||||
@ -159,11 +175,15 @@ QgsMapLayer *QgsProcessingUtils::mapLayerFromString( const QString &string, QgsP
|
||||
return nullptr;
|
||||
|
||||
// prefer project layers
|
||||
QgsMapLayer *layer = mapLayerFromProject( string, context.project() );
|
||||
if ( layer )
|
||||
return layer;
|
||||
QgsMapLayer *layer = nullptr;
|
||||
if ( context.project() )
|
||||
{
|
||||
QgsMapLayer *layer = mapLayerFromStore( string, context.project()->layerStore() );
|
||||
if ( layer )
|
||||
return layer;
|
||||
}
|
||||
|
||||
layer = mapLayerFromProject( string, &context.temporaryLayerStore() );
|
||||
layer = mapLayerFromStore( string, context.temporaryLayerStore() );
|
||||
if ( layer )
|
||||
return layer;
|
||||
|
||||
@ -173,7 +193,7 @@ QgsMapLayer *QgsProcessingUtils::mapLayerFromString( const QString &string, QgsP
|
||||
layer = loadMapLayerFromString( string );
|
||||
if ( layer )
|
||||
{
|
||||
context.temporaryLayerStore().addMapLayer( layer );
|
||||
context.temporaryLayerStore()->addMapLayer( layer );
|
||||
return layer;
|
||||
}
|
||||
else
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
class QgsProject;
|
||||
class QgsProcessingContext;
|
||||
class QgsMapLayerStore;
|
||||
|
||||
#include <QString>
|
||||
|
||||
@ -134,19 +135,19 @@ class CORE_EXPORT QgsProcessingUtils
|
||||
|
||||
static bool canUseLayer( const QgsRasterLayer *layer );
|
||||
static bool canUseLayer( const QgsVectorLayer *layer,
|
||||
const QList< QgsWkbTypes::GeometryType > &geometryTypes );
|
||||
const QList< QgsWkbTypes::GeometryType > &geometryTypes = QList< QgsWkbTypes::GeometryType >() );
|
||||
|
||||
/**
|
||||
* Interprets a \a string as a map layer from a project.
|
||||
* Interprets a \a string as a map layer from a store.
|
||||
*
|
||||
* This method attempts to match a string to a project map layer, using
|
||||
* This method attempts to match a string to a store map layer, using
|
||||
* first the layer ID, then layer names, and finally layer source.
|
||||
* If the string matches a normalized version of any layer source
|
||||
* for layers in the specified \a project, then those matching layers will be
|
||||
* for layers in the specified \a store, then those matching layers will be
|
||||
* returned.
|
||||
* \see mapLayerFromString()
|
||||
*/
|
||||
static QgsMapLayer *mapLayerFromProject( const QString &string, QgsProject *project );
|
||||
static QgsMapLayer *mapLayerFromStore( const QString &string, QgsMapLayerStore *store );
|
||||
|
||||
/**
|
||||
* Interprets a string as a map layer. The method will attempt to
|
||||
|
197
src/core/qgsmaplayerstore.cpp
Normal file
197
src/core/qgsmaplayerstore.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
/***************************************************************************
|
||||
qgsmaplayerstore.cpp
|
||||
--------------------
|
||||
begin : May 2017
|
||||
copyright : (C) 2017 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsmaplayerstore.h"
|
||||
#include "qgslogger.h"
|
||||
|
||||
QgsMapLayerStore::QgsMapLayerStore( QObject *parent )
|
||||
: QObject( parent )
|
||||
{}
|
||||
|
||||
QgsMapLayerStore::~QgsMapLayerStore()
|
||||
{
|
||||
removeAllMapLayers();
|
||||
}
|
||||
|
||||
int QgsMapLayerStore::count() const
|
||||
{
|
||||
return mMapLayers.size();
|
||||
}
|
||||
|
||||
QgsMapLayer *QgsMapLayerStore::mapLayer( const QString &layerId ) const
|
||||
{
|
||||
return mMapLayers.value( layerId );
|
||||
}
|
||||
|
||||
QList<QgsMapLayer *> QgsMapLayerStore::mapLayersByName( const QString &layerName ) const
|
||||
{
|
||||
QList<QgsMapLayer *> myResultList;
|
||||
Q_FOREACH ( QgsMapLayer *layer, mMapLayers )
|
||||
{
|
||||
if ( layer->name() == layerName )
|
||||
{
|
||||
myResultList << layer;
|
||||
}
|
||||
}
|
||||
return myResultList;
|
||||
}
|
||||
|
||||
QList<QgsMapLayer *> QgsMapLayerStore::addMapLayers( const QList<QgsMapLayer *> &layers, bool takeOwnership )
|
||||
{
|
||||
QList<QgsMapLayer *> myResultList;
|
||||
Q_FOREACH ( QgsMapLayer *myLayer, layers )
|
||||
{
|
||||
if ( !myLayer || !myLayer->isValid() )
|
||||
{
|
||||
QgsDebugMsg( "Cannot add invalid layers" );
|
||||
continue;
|
||||
}
|
||||
//check the layer is not already registered!
|
||||
if ( !mMapLayers.contains( myLayer->id() ) )
|
||||
{
|
||||
mMapLayers[myLayer->id()] = myLayer;
|
||||
myResultList << mMapLayers[myLayer->id()];
|
||||
if ( takeOwnership )
|
||||
{
|
||||
myLayer->setParent( this );
|
||||
}
|
||||
connect( myLayer, &QObject::destroyed, this, &QgsMapLayerStore::onMapLayerDeleted );
|
||||
emit layerWasAdded( myLayer );
|
||||
}
|
||||
}
|
||||
if ( !myResultList.isEmpty() )
|
||||
{
|
||||
emit layersAdded( myResultList );
|
||||
}
|
||||
return myResultList;
|
||||
}
|
||||
|
||||
QgsMapLayer *
|
||||
QgsMapLayerStore::addMapLayer( QgsMapLayer *layer, bool takeOwnership )
|
||||
{
|
||||
QList<QgsMapLayer *> addedLayers;
|
||||
addedLayers = addMapLayers( QList<QgsMapLayer *>() << layer, takeOwnership );
|
||||
return addedLayers.isEmpty() ? nullptr : addedLayers[0];
|
||||
}
|
||||
|
||||
void QgsMapLayerStore::removeMapLayers( const QStringList &layerIds )
|
||||
{
|
||||
QList<QgsMapLayer *> layers;
|
||||
Q_FOREACH ( const QString &myId, layerIds )
|
||||
{
|
||||
layers << mMapLayers.value( myId );
|
||||
}
|
||||
|
||||
removeMapLayers( layers );
|
||||
}
|
||||
|
||||
void QgsMapLayerStore::removeMapLayers( const QList<QgsMapLayer *> &layers )
|
||||
{
|
||||
if ( layers.isEmpty() )
|
||||
return;
|
||||
|
||||
QStringList layerIds;
|
||||
QList<QgsMapLayer *> layerList;
|
||||
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
{
|
||||
// check layer and the store contains it
|
||||
if ( layer && mMapLayers.contains( layer->id() ) )
|
||||
{
|
||||
layerIds << layer->id();
|
||||
layerList << layer;
|
||||
}
|
||||
}
|
||||
|
||||
if ( layerIds.isEmpty() )
|
||||
return;
|
||||
|
||||
emit layersWillBeRemoved( layerIds );
|
||||
emit layersWillBeRemoved( layerList );
|
||||
|
||||
Q_FOREACH ( QgsMapLayer *lyr, layerList )
|
||||
{
|
||||
QString myId( lyr->id() );
|
||||
emit layerWillBeRemoved( myId );
|
||||
emit layerWillBeRemoved( lyr );
|
||||
mMapLayers.remove( myId );
|
||||
if ( lyr->parent() == this )
|
||||
{
|
||||
delete lyr;
|
||||
}
|
||||
emit layerRemoved( myId );
|
||||
}
|
||||
|
||||
emit layersRemoved( layerIds );
|
||||
}
|
||||
|
||||
void QgsMapLayerStore::removeMapLayer( const QString &layerId )
|
||||
{
|
||||
removeMapLayers( QList<QgsMapLayer *>() << mMapLayers.value( layerId ) );
|
||||
}
|
||||
|
||||
void QgsMapLayerStore::removeMapLayer( QgsMapLayer *layer )
|
||||
{
|
||||
if ( layer )
|
||||
removeMapLayers( QList<QgsMapLayer *>() << layer );
|
||||
}
|
||||
|
||||
QgsMapLayer *QgsMapLayerStore::takeMapLayer( QgsMapLayer *layer )
|
||||
{
|
||||
if ( !layer )
|
||||
return nullptr;
|
||||
|
||||
if ( mMapLayers.contains( layer->id() ) )
|
||||
{
|
||||
emit layersWillBeRemoved( QStringList() << layer->id() );
|
||||
emit layersWillBeRemoved( QList<QgsMapLayer *>() << layer );
|
||||
emit layerWillBeRemoved( layer->id() );
|
||||
emit layerWillBeRemoved( layer );
|
||||
|
||||
mMapLayers.remove( layer->id() );
|
||||
layer->setParent( nullptr );
|
||||
emit layerRemoved( layer->id() );
|
||||
emit layersRemoved( QStringList() << layer->id() );
|
||||
return layer;
|
||||
}
|
||||
return nullptr; //don't return layer - it wasn't owned and accordingly we aren't transferring ownership
|
||||
}
|
||||
|
||||
void QgsMapLayerStore::removeAllMapLayers()
|
||||
{
|
||||
emit allLayersRemoved();
|
||||
// now let all observers know to clear themselves,
|
||||
// and then consequently any of their map legends
|
||||
removeMapLayers( mMapLayers.keys() );
|
||||
mMapLayers.clear();
|
||||
}
|
||||
|
||||
void QgsMapLayerStore::onMapLayerDeleted( QObject *obj )
|
||||
{
|
||||
QString id = mMapLayers.key( static_cast<QgsMapLayer *>( obj ) );
|
||||
|
||||
if ( !id.isNull() )
|
||||
{
|
||||
QgsDebugMsg( QString( "Map layer deleted without unregistering! %1" ).arg( id ) );
|
||||
mMapLayers.remove( id );
|
||||
}
|
||||
}
|
||||
|
||||
QMap<QString, QgsMapLayer *> QgsMapLayerStore::mapLayers() const
|
||||
{
|
||||
return mMapLayers;
|
||||
}
|
337
src/core/qgsmaplayerstore.h
Normal file
337
src/core/qgsmaplayerstore.h
Normal file
@ -0,0 +1,337 @@
|
||||
/***************************************************************************
|
||||
qgsmaplayerstore.h
|
||||
------------------
|
||||
begin : May 2017
|
||||
copyright : (C) 2017 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef QGSMAPLAYERSTORE_H
|
||||
#define QGSMAPLAYERSTORE_H
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgis.h"
|
||||
#include "qgsmaplayer.h"
|
||||
#include <QObject>
|
||||
|
||||
/**
|
||||
* \class QgsMapLayerStore
|
||||
* \ingroup core
|
||||
* A storage object for map layers, in which the layers are owned by the
|
||||
* store and have their lifetime bound to the store.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
|
||||
class CORE_EXPORT QgsMapLayerStore : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsMapLayerStore.
|
||||
*/
|
||||
explicit QgsMapLayerStore( QObject *parent SIP_TRANSFERTHIS = nullptr );
|
||||
|
||||
~QgsMapLayerStore();
|
||||
|
||||
/**
|
||||
* Returns the number of layers contained in the store.
|
||||
*/
|
||||
int count() const;
|
||||
|
||||
#ifdef SIP_RUN
|
||||
|
||||
/**
|
||||
* Returns the number of layers contained in the store.
|
||||
*/
|
||||
int __len__() const;
|
||||
% MethodCode
|
||||
sipRes = sipCpp->count();
|
||||
% End
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Retrieve a pointer to a layer by layer \a id.
|
||||
* \param id ID of layer to retrieve
|
||||
* \returns matching layer, or nullptr if no matching layer found
|
||||
* \see mapLayersByName()
|
||||
* \see mapLayers()
|
||||
*/
|
||||
QgsMapLayer *mapLayer( const QString &id ) const;
|
||||
|
||||
/**
|
||||
* Retrieve a list of matching layers by layer \a name.
|
||||
* \param name name of layers to match
|
||||
* \returns list of matching layers
|
||||
* \see mapLayer()
|
||||
* \see mapLayers()
|
||||
*/
|
||||
QList<QgsMapLayer *> mapLayersByName( const QString &name ) const;
|
||||
|
||||
/**
|
||||
* Returns a map of all layers by layer ID.
|
||||
* \see mapLayer()
|
||||
* \see mapLayersByName()
|
||||
* \see layers()
|
||||
*/
|
||||
QMap<QString, QgsMapLayer *> mapLayers() const;
|
||||
|
||||
#ifndef SIP_RUN
|
||||
|
||||
/**
|
||||
* Returns a list of registered map layers with a specified layer type.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* QVector<QgsVectorLayer*> vectorLayers = store->layers<QgsVectorLayer*>();
|
||||
*
|
||||
* \note not available in Python bindings
|
||||
* \see mapLayers()
|
||||
*/
|
||||
template <typename T>
|
||||
QVector<T> layers() const
|
||||
{
|
||||
QVector<T> layers;
|
||||
QMap<QString, QgsMapLayer *>::const_iterator layerIt = mMapLayers.constBegin();
|
||||
for ( ; layerIt != mMapLayers.constEnd(); ++layerIt )
|
||||
{
|
||||
T tLayer = qobject_cast<T>( layerIt.value() );
|
||||
if ( tLayer )
|
||||
{
|
||||
layers << tLayer;
|
||||
}
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* Add a list of \a layers to the store. Ownership of the layers is transferred
|
||||
* to the store.
|
||||
*
|
||||
* The layersAdded() and layerWasAdded() signals will always be emitted.
|
||||
*
|
||||
* \param layers A list of layer which should be added to the store.
|
||||
* \param takeOwnership Ownership will be transferred to the layer store.
|
||||
* If you specify false here you have take care of deleting
|
||||
* the layers yourself. Not available in Python.
|
||||
*
|
||||
* \returns a list of the map layers that were added
|
||||
* successfully. If a layer is invalid, or already exists in the store,
|
||||
* it will not be part of the returned list.
|
||||
*
|
||||
* \see addMapLayer()
|
||||
*/
|
||||
QList<QgsMapLayer *> addMapLayers( const QList<QgsMapLayer *> &layers SIP_TRANSFER,
|
||||
bool takeOwnership SIP_PYARGREMOVE = true );
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* Add a \a layer to the store. Ownership of the layer is transferred to the
|
||||
* store.
|
||||
*
|
||||
* The layersAdded() and layerWasAdded() signals will always be emitted.
|
||||
* If you are adding multiple layers at once, you should use
|
||||
* addMapLayers() instead.
|
||||
*
|
||||
* \param layer A layer to add to the store
|
||||
* \param takeOwnership Ownership will be transferred to the layer store.
|
||||
* If you specify false here you have take care of deleting
|
||||
* the layers yourself. Not available in Python.
|
||||
*
|
||||
* \returns nullptr if unable to add layer, otherwise pointer to newly added layer
|
||||
*
|
||||
* \see addMapLayers
|
||||
*
|
||||
* \note Use addMapLayers() if adding more than one layer at a time.
|
||||
* \see addMapLayers()
|
||||
*/
|
||||
QgsMapLayer *addMapLayer( QgsMapLayer *layer SIP_TRANSFER,
|
||||
bool takeOwnership SIP_PYARGREMOVE = true );
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* Remove a set of layers from the store by layer ID.
|
||||
*
|
||||
* The specified layers will be removed from the store.
|
||||
* These layers will also be deleted.
|
||||
*
|
||||
* \param layerIds list of IDs of the layers to remove
|
||||
*
|
||||
* \see takeMapLayer()
|
||||
* \see removeMapLayer()
|
||||
* \see removeAllMapLayers()
|
||||
* \note available in Python bindings as removeMapLayersById.
|
||||
*/
|
||||
void removeMapLayers( const QStringList &layerIds ) SIP_PYNAME( removeMapLayersById );
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* Remove a set of \a layers from the store.
|
||||
*
|
||||
* The specified layers will be removed from the store.
|
||||
* These layers will also be deleted.
|
||||
*
|
||||
* \param layers A list of layers to remove. Null pointers are ignored.
|
||||
*
|
||||
* \see takeMapLayer()
|
||||
* \see removeMapLayer()
|
||||
* \see removeAllMapLayers()
|
||||
*/
|
||||
void removeMapLayers( const QList<QgsMapLayer *> &layers );
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* Remove a layer from the store by layer \a id.
|
||||
*
|
||||
* The specified layer will be removed from the store. The layer will also be deleted.
|
||||
*
|
||||
* \param id ID of the layer to remove
|
||||
*
|
||||
* \see takeMapLayer()
|
||||
* \see removeMapLayers()
|
||||
* \see removeAllMapLayers()
|
||||
*/
|
||||
void removeMapLayer( const QString &id );
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* Remove a \a layer from the store.
|
||||
*
|
||||
* The specified layer will be removed from the store. The layer will also be deleted.
|
||||
*
|
||||
* \param layer The layer to remove. Null pointers are ignored.
|
||||
*
|
||||
* \see takeMapLayer()
|
||||
* \see removeMapLayers()
|
||||
* \see removeAllMapLayers()
|
||||
*/
|
||||
void removeMapLayer( QgsMapLayer *layer );
|
||||
|
||||
/**
|
||||
* Takes a \a layer from the store. If the layer was owned by the store, the
|
||||
* layer will be returned without deleting it. The caller takes ownership of
|
||||
* the layer and is responsible for deleting it.
|
||||
* \see removeMapLayer()
|
||||
*/
|
||||
QgsMapLayer *takeMapLayer( QgsMapLayer *layer ) SIP_TRANSFERBACK;
|
||||
|
||||
/**
|
||||
* Removes all registered layers. These layers will also be deleted.
|
||||
*
|
||||
* \note Calling this method will cause the removeAll() signal to
|
||||
* be emitted.
|
||||
* \see removeMapLayer()
|
||||
* \see removeMapLayers()
|
||||
*/
|
||||
void removeAllMapLayers();
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
* Emitted when one or more layers are about to be removed from the store.
|
||||
*
|
||||
* \param layerIds A list of IDs for the layers which are to be removed.
|
||||
* \see layerWillBeRemoved()
|
||||
* \see layersRemoved()
|
||||
*/
|
||||
void layersWillBeRemoved( const QStringList &layerIds );
|
||||
|
||||
/**
|
||||
* Emitted when one or more layers are about to be removed from the store.
|
||||
*
|
||||
* \param layers A list of layers which are to be removed.
|
||||
* \see layerWillBeRemoved()
|
||||
* \see layersRemoved()
|
||||
*/
|
||||
void layersWillBeRemoved( const QList<QgsMapLayer *> &layers );
|
||||
|
||||
/**
|
||||
* Emitted when a layer is about to be removed from the store.
|
||||
*
|
||||
* \param layerId The ID of the layer to be removed.
|
||||
*
|
||||
* \note Consider using layersWillBeRemoved() instead.
|
||||
* \see layersWillBeRemoved()
|
||||
* \see layerRemoved()
|
||||
*/
|
||||
void layerWillBeRemoved( const QString &layerId );
|
||||
|
||||
/**
|
||||
* Emitted when a layer is about to be removed from the store.
|
||||
*
|
||||
* \param layer The layer to be removed.
|
||||
*
|
||||
* \note Consider using layersWillBeRemoved() instead.
|
||||
* \see layersWillBeRemoved()
|
||||
* \see layerRemoved()
|
||||
*/
|
||||
void layerWillBeRemoved( QgsMapLayer *layer );
|
||||
|
||||
/**
|
||||
* Emitted after one or more layers were removed from the store.
|
||||
*
|
||||
* \param layerIds A list of IDs of the layers which were removed.
|
||||
* \see layersWillBeRemoved()
|
||||
*/
|
||||
void layersRemoved( const QStringList &layerIds );
|
||||
|
||||
/**
|
||||
* Emitted after a layer was removed from the store.
|
||||
*
|
||||
* \param layerId The ID of the layer removed.
|
||||
*
|
||||
* \note Consider using layersRemoved() instead
|
||||
* \see layerWillBeRemoved()
|
||||
*/
|
||||
void layerRemoved( const QString &layerId );
|
||||
|
||||
/**
|
||||
* Emitted when all layers are removed, before layersWillBeRemoved() and
|
||||
* layerWillBeRemoved() signals are emitted. The layersWillBeRemoved() and
|
||||
* layerWillBeRemoved() signals will still be emitted following this signal.
|
||||
* You can use this signal to do easy (and fast) cleanup.
|
||||
*/
|
||||
void allLayersRemoved();
|
||||
|
||||
/**
|
||||
* Emitted when one or more layers were added to the store.
|
||||
*
|
||||
* \param layers List of layers which have been added.
|
||||
*
|
||||
* \see legendLayersAdded()
|
||||
* \see layerWasAdded()
|
||||
*/
|
||||
void layersAdded( const QList<QgsMapLayer *> &layers );
|
||||
|
||||
/**
|
||||
* Emitted when a \a layer was added to the store.
|
||||
*
|
||||
* \note Consider using layersAdded() instead
|
||||
* \see layersAdded()
|
||||
*/
|
||||
void layerWasAdded( QgsMapLayer *layer );
|
||||
|
||||
private slots:
|
||||
|
||||
void onMapLayerDeleted( QObject *obj );
|
||||
|
||||
private:
|
||||
|
||||
QMap<QString, QgsMapLayer *> mMapLayers;
|
||||
|
||||
};
|
||||
|
||||
#endif //QGSMAPLAYERSTORE_H
|
@ -46,6 +46,7 @@
|
||||
#include "qgssettings.h"
|
||||
#include "qgsmaplayerlistutils.h"
|
||||
#include "qgslayoutmanager.h"
|
||||
#include "qgsmaplayerstore.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFileInfo>
|
||||
@ -322,6 +323,7 @@ void removeKey_( const QString &scope,
|
||||
|
||||
QgsProject::QgsProject( QObject *parent )
|
||||
: QObject( parent )
|
||||
, mLayerStore( new QgsMapLayerStore( this ) )
|
||||
, mBadLayerHandler( new QgsProjectBadLayerHandler() )
|
||||
, mSnappingConfig( this )
|
||||
, mRelationManager( new QgsRelationManager( this ) )
|
||||
@ -343,6 +345,21 @@ QgsProject::QgsProject( QObject *parent )
|
||||
connect( this, &QgsProject::layersAdded, this, &QgsProject::onMapLayersAdded );
|
||||
connect( this, &QgsProject::layersRemoved, this, [ = ] { cleanTransactionGroups(); } );
|
||||
connect( this, static_cast < void ( QgsProject::* )( const QList<QgsMapLayer *> & ) >( &QgsProject::layersWillBeRemoved ), this, &QgsProject::onMapLayersRemoved );
|
||||
|
||||
// proxy map layer store signals to this
|
||||
connect( mLayerStore.get(), static_cast<void ( QgsMapLayerStore::* )( const QStringList & )>( &QgsMapLayerStore::layersWillBeRemoved ),
|
||||
this, static_cast<void ( QgsProject::* )( const QStringList & )>( &QgsProject::layersWillBeRemoved ) );
|
||||
connect( mLayerStore.get(), static_cast<void ( QgsMapLayerStore::* )( const QList<QgsMapLayer *> & )>( &QgsMapLayerStore::layersWillBeRemoved ),
|
||||
this, static_cast<void ( QgsProject::* )( const QList<QgsMapLayer *> & )>( &QgsProject::layersWillBeRemoved ) );
|
||||
connect( mLayerStore.get(), static_cast<void ( QgsMapLayerStore::* )( const QString & )>( &QgsMapLayerStore::layerWillBeRemoved ),
|
||||
this, static_cast<void ( QgsProject::* )( const QString & )>( &QgsProject::layerWillBeRemoved ) );
|
||||
connect( mLayerStore.get(), static_cast<void ( QgsMapLayerStore::* )( QgsMapLayer * )>( &QgsMapLayerStore::layerWillBeRemoved ),
|
||||
this, static_cast<void ( QgsProject::* )( QgsMapLayer * )>( &QgsProject::layerWillBeRemoved ) );
|
||||
connect( mLayerStore.get(), static_cast<void ( QgsMapLayerStore::* )( const QStringList & )>( &QgsMapLayerStore::layersRemoved ), this, &QgsProject::layersRemoved );
|
||||
connect( mLayerStore.get(), &QgsMapLayerStore::layerRemoved, this, &QgsProject::layerRemoved );
|
||||
connect( mLayerStore.get(), &QgsMapLayerStore::allLayersRemoved, this, &QgsProject::removeAll );
|
||||
connect( mLayerStore.get(), &QgsMapLayerStore::layersAdded, this, &QgsProject::layersAdded );
|
||||
connect( mLayerStore.get(), &QgsMapLayerStore::layerWasAdded, this, &QgsProject::layerWasAdded );
|
||||
}
|
||||
|
||||
|
||||
@ -884,7 +901,8 @@ bool QgsProject::read()
|
||||
|
||||
// Resolve references to other vector layers
|
||||
// Needs to be done here once all dependent layers are loaded
|
||||
for ( QMap<QString, QgsMapLayer *>::iterator it = mMapLayers.begin(); it != mMapLayers.end(); it++ )
|
||||
QMap<QString, QgsMapLayer *> layers = mLayerStore->mapLayers();
|
||||
for ( QMap<QString, QgsMapLayer *>::iterator it = layers.begin(); it != layers.end(); it++ )
|
||||
{
|
||||
if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() ) )
|
||||
vl->resolveReferences( this );
|
||||
@ -1049,6 +1067,16 @@ const QgsLabelingEngineSettings &QgsProject::labelingEngineSettings() const
|
||||
return *mLabelingEngineSettings;
|
||||
}
|
||||
|
||||
QgsMapLayerStore *QgsProject::layerStore()
|
||||
{
|
||||
return mLayerStore.get();
|
||||
}
|
||||
|
||||
const QgsMapLayerStore *QgsProject::layerStore() const
|
||||
{
|
||||
return mLayerStore.get();
|
||||
}
|
||||
|
||||
QList<QgsVectorLayer *> QgsProject::avoidIntersectionsLayers() const
|
||||
{
|
||||
QList<QgsVectorLayer *> layers;
|
||||
@ -2066,31 +2094,23 @@ QMap<QPair<QString, QString>, QgsTransactionGroup *> QgsProject::transactionGrou
|
||||
|
||||
|
||||
//
|
||||
// QgsMapLayerRegistry methods
|
||||
// QgsMapLayerStore methods
|
||||
//
|
||||
|
||||
|
||||
int QgsProject::count() const
|
||||
{
|
||||
return mMapLayers.size();
|
||||
return mLayerStore->count();
|
||||
}
|
||||
|
||||
QgsMapLayer *QgsProject::mapLayer( const QString &layerId ) const
|
||||
{
|
||||
return mMapLayers.value( layerId );
|
||||
return mLayerStore->mapLayer( layerId );
|
||||
}
|
||||
|
||||
QList<QgsMapLayer *> QgsProject::mapLayersByName( const QString &layerName ) const
|
||||
{
|
||||
QList<QgsMapLayer *> myResultList;
|
||||
Q_FOREACH ( QgsMapLayer *layer, mMapLayers )
|
||||
{
|
||||
if ( layer->name() == layerName )
|
||||
{
|
||||
myResultList << layer;
|
||||
}
|
||||
}
|
||||
return myResultList;
|
||||
return mLayerStore->mapLayersByName( layerName );
|
||||
}
|
||||
|
||||
QList<QgsMapLayer *> QgsProject::addMapLayers(
|
||||
@ -2098,31 +2118,9 @@ QList<QgsMapLayer *> QgsProject::addMapLayers(
|
||||
bool addToLegend,
|
||||
bool takeOwnership )
|
||||
{
|
||||
QList<QgsMapLayer *> myResultList;
|
||||
Q_FOREACH ( QgsMapLayer *myLayer, layers )
|
||||
{
|
||||
if ( !myLayer || !myLayer->isValid() )
|
||||
{
|
||||
QgsDebugMsg( "Cannot add invalid layers" );
|
||||
continue;
|
||||
}
|
||||
//check the layer is not already registered!
|
||||
if ( !mMapLayers.contains( myLayer->id() ) )
|
||||
{
|
||||
mMapLayers[myLayer->id()] = myLayer;
|
||||
myResultList << mMapLayers[myLayer->id()];
|
||||
if ( takeOwnership )
|
||||
{
|
||||
myLayer->setParent( this );
|
||||
}
|
||||
connect( myLayer, &QObject::destroyed, this, &QgsProject::onMapLayerDeleted );
|
||||
emit layerWasAdded( myLayer );
|
||||
}
|
||||
}
|
||||
QList<QgsMapLayer *> myResultList = mLayerStore->addMapLayers( layers, takeOwnership );
|
||||
if ( !myResultList.isEmpty() )
|
||||
{
|
||||
emit layersAdded( myResultList );
|
||||
|
||||
if ( addToLegend )
|
||||
emit legendLayersAdded( myResultList );
|
||||
}
|
||||
@ -2141,116 +2139,47 @@ QgsProject::addMapLayer( QgsMapLayer *layer,
|
||||
|
||||
void QgsProject::removeMapLayers( const QStringList &layerIds )
|
||||
{
|
||||
QList<QgsMapLayer *> layers;
|
||||
Q_FOREACH ( const QString &myId, layerIds )
|
||||
{
|
||||
layers << mMapLayers.value( myId );
|
||||
}
|
||||
|
||||
removeMapLayers( layers );
|
||||
mLayerStore->removeMapLayers( layerIds );
|
||||
}
|
||||
|
||||
void QgsProject::removeMapLayers( const QList<QgsMapLayer *> &layers )
|
||||
{
|
||||
if ( layers.isEmpty() )
|
||||
return;
|
||||
|
||||
QStringList layerIds;
|
||||
QList<QgsMapLayer *> layerList;
|
||||
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
{
|
||||
// check layer and the registry contains it
|
||||
if ( layer && mMapLayers.contains( layer->id() ) )
|
||||
{
|
||||
layerIds << layer->id();
|
||||
layerList << layer;
|
||||
}
|
||||
}
|
||||
|
||||
if ( layerIds.isEmpty() )
|
||||
return;
|
||||
|
||||
emit layersWillBeRemoved( layerIds );
|
||||
emit layersWillBeRemoved( layerList );
|
||||
|
||||
Q_FOREACH ( QgsMapLayer *lyr, layerList )
|
||||
{
|
||||
QString myId( lyr->id() );
|
||||
emit layerWillBeRemoved( myId );
|
||||
emit layerWillBeRemoved( lyr );
|
||||
mMapLayers.remove( myId );
|
||||
if ( lyr->parent() == this )
|
||||
{
|
||||
delete lyr;
|
||||
}
|
||||
emit layerRemoved( myId );
|
||||
}
|
||||
|
||||
emit layersRemoved( layerIds );
|
||||
mLayerStore->removeMapLayers( layers );
|
||||
}
|
||||
|
||||
void QgsProject::removeMapLayer( const QString &layerId )
|
||||
{
|
||||
removeMapLayers( QList<QgsMapLayer *>() << mMapLayers.value( layerId ) );
|
||||
mLayerStore->removeMapLayer( layerId );
|
||||
}
|
||||
|
||||
void QgsProject::removeMapLayer( QgsMapLayer *layer )
|
||||
{
|
||||
if ( layer )
|
||||
removeMapLayers( QList<QgsMapLayer *>() << layer );
|
||||
mLayerStore->removeMapLayer( layer );
|
||||
}
|
||||
|
||||
QgsMapLayer *QgsProject::takeMapLayer( QgsMapLayer *layer )
|
||||
{
|
||||
if ( !layer )
|
||||
return nullptr;
|
||||
|
||||
if ( mMapLayers.contains( layer->id() ) )
|
||||
{
|
||||
emit layersWillBeRemoved( QStringList() << layer->id() );
|
||||
emit layersWillBeRemoved( QList<QgsMapLayer *>() << layer );
|
||||
emit layerWillBeRemoved( layer->id() );
|
||||
emit layerWillBeRemoved( layer );
|
||||
|
||||
mMapLayers.remove( layer->id() );
|
||||
layer->setParent( nullptr );
|
||||
emit layerRemoved( layer->id() );
|
||||
emit layersRemoved( QStringList() << layer->id() );
|
||||
return layer;
|
||||
}
|
||||
return nullptr; //don't return layer - it wasn't owned and accordingly we aren't transferring ownership
|
||||
return mLayerStore->takeMapLayer( layer );
|
||||
}
|
||||
|
||||
void QgsProject::removeAllMapLayers()
|
||||
{
|
||||
emit removeAll();
|
||||
// now let all observers know to clear themselves,
|
||||
// and then consequently any of their map legends
|
||||
removeMapLayers( mMapLayers.keys() );
|
||||
mMapLayers.clear();
|
||||
mLayerStore->removeAllMapLayers();
|
||||
}
|
||||
|
||||
void QgsProject::reloadAllLayers()
|
||||
{
|
||||
Q_FOREACH ( QgsMapLayer *layer, mMapLayers )
|
||||
QMap<QString, QgsMapLayer *> layers = mLayerStore->mapLayers();
|
||||
QMap<QString, QgsMapLayer *>::const_iterator it = layers.constBegin();
|
||||
for ( ; it != layers.constEnd(); ++it )
|
||||
{
|
||||
layer->reload();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsProject::onMapLayerDeleted( QObject *obj )
|
||||
{
|
||||
QString id = mMapLayers.key( static_cast<QgsMapLayer *>( obj ) );
|
||||
|
||||
if ( !id.isNull() )
|
||||
{
|
||||
QgsDebugMsg( QString( "Map layer deleted without unregistering! %1" ).arg( id ) );
|
||||
mMapLayers.remove( id );
|
||||
it.value()->reload();
|
||||
}
|
||||
}
|
||||
|
||||
QMap<QString, QgsMapLayer *> QgsProject::mapLayers() const
|
||||
{
|
||||
return mMapLayers;
|
||||
return mLayerStore->mapLayers();
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgsprojectproperty.h"
|
||||
#include "qgsmaplayer.h"
|
||||
#include "qgsmaplayerstore.h"
|
||||
|
||||
class QFileInfo;
|
||||
class QDomDocument;
|
||||
@ -529,6 +530,18 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
// Functionality from QgsMapLayerRegistry
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns a pointer to the project's internal layer store.
|
||||
* /since QGIS 3.0
|
||||
*/
|
||||
QgsMapLayerStore *layerStore();
|
||||
|
||||
/**
|
||||
* Returns a pointer to the project's internal layer store.
|
||||
* /since QGIS 3.0
|
||||
*/
|
||||
SIP_SKIP const QgsMapLayerStore *layerStore() const;
|
||||
|
||||
//! Returns the number of registered layers.
|
||||
int count() const;
|
||||
|
||||
@ -568,17 +581,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
template <typename T> SIP_SKIP
|
||||
QVector<T> layers() const
|
||||
{
|
||||
QVector<T> layers;
|
||||
QMap<QString, QgsMapLayer *>::const_iterator layerIt = mMapLayers.constBegin();
|
||||
for ( ; layerIt != mMapLayers.constEnd(); ++layerIt )
|
||||
{
|
||||
T tLayer = qobject_cast<T>( layerIt.value() );
|
||||
if ( tLayer )
|
||||
{
|
||||
layers << tLayer;
|
||||
}
|
||||
}
|
||||
return layers;
|
||||
return mLayerStore->layers<T>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -969,8 +972,6 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
void onMapLayersRemoved( const QList<QgsMapLayer *> &layers );
|
||||
void cleanTransactionGroups( bool force = false );
|
||||
|
||||
void onMapLayerDeleted( QObject *obj );
|
||||
|
||||
private:
|
||||
|
||||
static QgsProject *sProject;
|
||||
@ -1003,7 +1004,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
//! \note not available in Python bindings
|
||||
void loadEmbeddedNodes( QgsLayerTreeGroup *group ) SIP_SKIP;
|
||||
|
||||
QMap<QString, QgsMapLayer *> mMapLayers;
|
||||
std::unique_ptr< QgsMapLayerStore > mLayerStore;
|
||||
|
||||
QString mErrorMessage;
|
||||
|
||||
|
@ -105,6 +105,7 @@ class TestQgsProcessing: public QObject
|
||||
void compatibleLayers();
|
||||
void normalizeLayerSource();
|
||||
void mapLayers();
|
||||
void mapLayerFromStore();
|
||||
void mapLayerFromString();
|
||||
void algorithm();
|
||||
void features();
|
||||
@ -335,9 +336,37 @@ void TestQgsProcessing::normalizeLayerSource()
|
||||
|
||||
void TestQgsProcessing::mapLayers()
|
||||
{
|
||||
// test mapLayerFromProject
|
||||
QString testDataDir = QStringLiteral( TEST_DATA_DIR ) + '/'; //defined in CmakeLists.txt
|
||||
QString raster = testDataDir + "landsat.tif";
|
||||
QString vector = testDataDir + "points.shp";
|
||||
|
||||
QgsProject p;
|
||||
// test loadMapLayerFromString with raster
|
||||
QgsMapLayer *l = QgsProcessingUtils::loadMapLayerFromString( raster );
|
||||
QVERIFY( l->isValid() );
|
||||
QCOMPARE( l->type(), QgsMapLayer::RasterLayer );
|
||||
delete l;
|
||||
|
||||
//test with vector
|
||||
l = QgsProcessingUtils::loadMapLayerFromString( vector );
|
||||
QVERIFY( l->isValid() );
|
||||
QCOMPARE( l->type(), QgsMapLayer::VectorLayer );
|
||||
delete l;
|
||||
|
||||
l = QgsProcessingUtils::loadMapLayerFromString( QString() );
|
||||
QVERIFY( !l );
|
||||
l = QgsProcessingUtils::loadMapLayerFromString( QStringLiteral( "so much room for activities!" ) );
|
||||
QVERIFY( !l );
|
||||
l = QgsProcessingUtils::loadMapLayerFromString( testDataDir + "multipoint.shp" );
|
||||
QVERIFY( l->isValid() );
|
||||
QCOMPARE( l->type(), QgsMapLayer::VectorLayer );
|
||||
delete l;
|
||||
}
|
||||
|
||||
void TestQgsProcessing::mapLayerFromStore()
|
||||
{
|
||||
// test mapLayerFromStore
|
||||
|
||||
QgsMapLayerStore store;
|
||||
|
||||
// add a bunch of layers to a project
|
||||
QString testDataDir = QStringLiteral( TEST_DATA_DIR ) + '/'; //defined in CmakeLists.txt
|
||||
@ -352,33 +381,19 @@ void TestQgsProcessing::mapLayers()
|
||||
|
||||
QgsVectorLayer *v1 = new QgsVectorLayer( "Polygon", "V4", "memory" );
|
||||
QgsVectorLayer *v2 = new QgsVectorLayer( "Point", "v1", "memory" );
|
||||
p.addMapLayers( QList<QgsMapLayer *>() << r1 << r2 << v1 << v2 );
|
||||
store.addMapLayers( QList<QgsMapLayer *>() << r1 << r2 << v1 << v2 );
|
||||
|
||||
QVERIFY( ! QgsProcessingUtils::mapLayerFromProject( QString(), nullptr ) );
|
||||
QVERIFY( ! QgsProcessingUtils::mapLayerFromProject( QStringLiteral( "v1" ), nullptr ) );
|
||||
QVERIFY( ! QgsProcessingUtils::mapLayerFromProject( QString(), &p ) );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromProject( raster1, &p ), r1 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromProject( raster2, &p ), r2 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromProject( "R1", &p ), r1 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromProject( "ar2", &p ), r2 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromProject( "V4", &p ), v1 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromProject( "v1", &p ), v2 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromProject( r1->id(), &p ), r1 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromProject( v1->id(), &p ), v1 );
|
||||
|
||||
// test loadMapLayerFromString
|
||||
QgsMapLayer *l = QgsProcessingUtils::loadMapLayerFromString( raster2 );
|
||||
QVERIFY( l->isValid() );
|
||||
QCOMPARE( l->type(), QgsMapLayer::RasterLayer );
|
||||
delete l;
|
||||
l = QgsProcessingUtils::loadMapLayerFromString( QString() );
|
||||
QVERIFY( !l );
|
||||
l = QgsProcessingUtils::loadMapLayerFromString( QStringLiteral( "so much room for activities!" ) );
|
||||
QVERIFY( !l );
|
||||
l = QgsProcessingUtils::loadMapLayerFromString( testDataDir + "multipoint.shp" );
|
||||
QVERIFY( l->isValid() );
|
||||
QCOMPARE( l->type(), QgsMapLayer::VectorLayer );
|
||||
delete l;
|
||||
QVERIFY( ! QgsProcessingUtils::mapLayerFromStore( QString(), nullptr ) );
|
||||
QVERIFY( ! QgsProcessingUtils::mapLayerFromStore( QStringLiteral( "v1" ), nullptr ) );
|
||||
QVERIFY( ! QgsProcessingUtils::mapLayerFromStore( QString(), &store ) );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromStore( raster1, &store ), r1 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromStore( raster2, &store ), r2 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromStore( "R1", &store ), r1 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromStore( "ar2", &store ), r2 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromStore( "V4", &store ), v1 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromStore( "v1", &store ), v2 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromStore( r1->id(), &store ), r1 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromStore( v1->id(), &store ), v1 );
|
||||
}
|
||||
|
||||
void TestQgsProcessing::mapLayerFromString()
|
||||
@ -423,7 +438,7 @@ void TestQgsProcessing::mapLayerFromString()
|
||||
// check that layers in context temporary store are used
|
||||
QgsVectorLayer *v5 = new QgsVectorLayer( "Polygon", "V5", "memory" );
|
||||
QgsVectorLayer *v6 = new QgsVectorLayer( "Point", "v6", "memory" );
|
||||
c.temporaryLayerStore().addMapLayers( QList<QgsMapLayer *>() << v5 << v6 );
|
||||
c.temporaryLayerStore()->addMapLayers( QList<QgsMapLayer *>() << v5 << v6 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromString( "V5", c ), v5 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromString( "v6", c ), v6 );
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromString( v5->id(), c ), v5 );
|
||||
@ -440,7 +455,7 @@ void TestQgsProcessing::mapLayerFromString()
|
||||
QVERIFY( loadedLayer->isValid() );
|
||||
QCOMPARE( loadedLayer->type(), QgsMapLayer::RasterLayer );
|
||||
// should now be in temporary store
|
||||
QCOMPARE( c.temporaryLayerStore().mapLayer( loadedLayer->id() ), loadedLayer );
|
||||
QCOMPARE( c.temporaryLayerStore()->mapLayer( loadedLayer->id() ), loadedLayer );
|
||||
|
||||
// since it's now in temporary store, should be accessible even if we deny loading new layers
|
||||
QCOMPARE( QgsProcessingUtils::mapLayerFromString( newRaster, c, false ), loadedLayer );
|
||||
|
@ -76,6 +76,7 @@ ADD_PYTHON_TEST(PyQgsMapCanvas test_qgsmapcanvas.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapCanvasAnnotationItem test_qgsmapcanvasannotationitem.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapLayer test_qgsmaplayer.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapLayerModel test_qgsmaplayermodel.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapLayerStore test_qgsmaplayerstore.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapRenderer test_qgsmaprenderer.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapRendererCache test_qgsmaprenderercache.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapThemeCollection test_qgsmapthemecollection.py)
|
||||
@ -145,7 +146,6 @@ ADD_PYTHON_TEST(PyQgsVectorLayer test_qgsvectorlayer.py)
|
||||
ADD_PYTHON_TEST(PyQgsVectorLayerEditBuffer test_qgsvectorlayereditbuffer.py)
|
||||
ADD_PYTHON_TEST(PyQgsVectorLayerUtils test_qgsvectorlayerutils.py)
|
||||
ADD_PYTHON_TEST(PyQgsZonalStatistics test_qgszonalstatistics.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapLayerRegistry test_qgsmaplayerregistry.py)
|
||||
ADD_PYTHON_TEST(PyQgsVirtualLayerProvider test_provider_virtual.py)
|
||||
ADD_PYTHON_TEST(PyQgsVirtualLayerDefinition test_qgsvirtuallayerdefinition.py)
|
||||
ADD_PYTHON_TEST(PyQgsLayerDefinition test_qgslayerdefinition.py)
|
||||
|
@ -1,536 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""QGIS Unit tests for QgsProject.
|
||||
|
||||
.. note:: This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
"""
|
||||
__author__ = 'Alessandro Pasotti'
|
||||
__date__ = '04/12/2015'
|
||||
__copyright__ = 'Copyright 2015, The QGIS Project'
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import QgsProject, QgsVectorLayer, QgsMapLayer
|
||||
from qgis.testing import start_app, unittest
|
||||
from qgis.PyQt.QtCore import QT_VERSION_STR
|
||||
import sip
|
||||
|
||||
try:
|
||||
from qgis.PyQt.QtTest import QSignalSpy
|
||||
use_signal_spy = True
|
||||
except:
|
||||
use_signal_spy = False
|
||||
|
||||
start_app()
|
||||
|
||||
|
||||
def createLayer(name):
|
||||
return QgsVectorLayer("Point?field=x:string", name, "memory")
|
||||
|
||||
|
||||
class TestQgsProjectMapLayers(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def testInstance(self):
|
||||
""" test retrieving global instance """
|
||||
self.assertTrue(QgsProject.instance())
|
||||
|
||||
# register a layer to the singleton
|
||||
QgsProject.instance().addMapLayer(createLayer('test'))
|
||||
|
||||
# check that the same instance is returned
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayer(self):
|
||||
""" test adding individual map layers to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
l1 = createLayer('test')
|
||||
self.assertEqual(QgsProject.instance().addMapLayer(l1), l1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
|
||||
# adding a second layer should leave existing layers intact
|
||||
l2 = createLayer('test2')
|
||||
self.assertEqual(QgsProject.instance().addMapLayer(l2), l2)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test2')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayerAlreadyAdded(self):
|
||||
""" test that already added layers can't be readded to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
l1 = createLayer('test')
|
||||
QgsProject.instance().addMapLayer(l1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
self.assertEqual(QgsProject.instance().addMapLayer(l1), None)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayerInvalid(self):
|
||||
""" test that invalid map layersd can't be added to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
self.assertEqual(QgsProject.instance().addMapLayer(QgsVectorLayer("Point?field=x:string", 'test', "xxx")), None)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 0)
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
@unittest.skipIf(not use_signal_spy, "No QSignalSpy available")
|
||||
def test_addMapLayerSignals(self):
|
||||
""" test that signals are correctly emitted when adding map layer"""
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
layer_was_added_spy = QSignalSpy(QgsProject.instance().layerWasAdded)
|
||||
layers_added_spy = QSignalSpy(QgsProject.instance().layersAdded)
|
||||
legend_layers_added_spy = QSignalSpy(QgsProject.instance().legendLayersAdded)
|
||||
|
||||
l1 = createLayer('test')
|
||||
QgsProject.instance().addMapLayer(l1)
|
||||
|
||||
# can't seem to actually test the data which was emitted, so best we can do is test
|
||||
# the signal count
|
||||
self.assertEqual(len(layer_was_added_spy), 1)
|
||||
self.assertEqual(len(layers_added_spy), 1)
|
||||
self.assertEqual(len(legend_layers_added_spy), 1)
|
||||
|
||||
# layer not added to legend
|
||||
QgsProject.instance().addMapLayer(createLayer('test2'), False)
|
||||
self.assertEqual(len(layer_was_added_spy), 2)
|
||||
self.assertEqual(len(layers_added_spy), 2)
|
||||
self.assertEqual(len(legend_layers_added_spy), 1)
|
||||
|
||||
# try readding a layer already in the registry
|
||||
QgsProject.instance().addMapLayer(l1)
|
||||
# should be no extra signals emitted
|
||||
self.assertEqual(len(layer_was_added_spy), 2)
|
||||
self.assertEqual(len(layers_added_spy), 2)
|
||||
self.assertEqual(len(legend_layers_added_spy), 1)
|
||||
|
||||
def test_addMapLayers(self):
|
||||
""" test adding multiple map layers to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
self.assertEqual(set(QgsProject.instance().addMapLayers([l1, l2])), set([l1, l2]))
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test2')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
# adding more layers should leave existing layers intact
|
||||
l3 = createLayer('test3')
|
||||
l4 = createLayer('test4')
|
||||
self.assertEqual(set(QgsProject.instance().addMapLayers([l3, l4])), set([l3, l4]))
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test2')), 1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test3')), 1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test4')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 4)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayersInvalid(self):
|
||||
""" test that invalid map layersd can't be added to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
self.assertEqual(QgsProject.instance().addMapLayers([QgsVectorLayer("Point?field=x:string", 'test', "xxx")]), [])
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 0)
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayersAlreadyAdded(self):
|
||||
""" test that already added layers can't be readded to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
l1 = createLayer('test')
|
||||
self.assertEqual(QgsProject.instance().addMapLayers([l1]), [l1])
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
self.assertEqual(QgsProject.instance().addMapLayers([l1]), [])
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
@unittest.skipIf(not use_signal_spy, "No QSignalSpy available")
|
||||
def test_addMapLayersSignals(self):
|
||||
""" test that signals are correctly emitted when adding map layers"""
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
layer_was_added_spy = QSignalSpy(QgsProject.instance().layerWasAdded)
|
||||
layers_added_spy = QSignalSpy(QgsProject.instance().layersAdded)
|
||||
legend_layers_added_spy = QSignalSpy(QgsProject.instance().legendLayersAdded)
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
|
||||
# can't seem to actually test the data which was emitted, so best we can do is test
|
||||
# the signal count
|
||||
self.assertEqual(len(layer_was_added_spy), 2)
|
||||
self.assertEqual(len(layers_added_spy), 1)
|
||||
self.assertEqual(len(legend_layers_added_spy), 1)
|
||||
|
||||
# layer not added to legend
|
||||
QgsProject.instance().addMapLayers([createLayer('test3'), createLayer('test4')], False)
|
||||
self.assertEqual(len(layer_was_added_spy), 4)
|
||||
self.assertEqual(len(layers_added_spy), 2)
|
||||
self.assertEqual(len(legend_layers_added_spy), 1)
|
||||
|
||||
# try readding a layer already in the registry
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
# should be no extra signals emitted
|
||||
self.assertEqual(len(layer_was_added_spy), 4)
|
||||
self.assertEqual(len(layers_added_spy), 2)
|
||||
self.assertEqual(len(legend_layers_added_spy), 1)
|
||||
|
||||
def test_mapLayerById(self):
|
||||
""" test retrieving map layer by ID """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
self.assertEqual(QgsProject.instance().mapLayer('bad'), None)
|
||||
self.assertEqual(QgsProject.instance().mapLayer(None), None)
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
|
||||
self.assertEqual(QgsProject.instance().mapLayer('bad'), None)
|
||||
self.assertEqual(QgsProject.instance().mapLayer(None), None)
|
||||
self.assertEqual(QgsProject.instance().mapLayer(l1.id()), l1)
|
||||
self.assertEqual(QgsProject.instance().mapLayer(l2.id()), l2)
|
||||
|
||||
def test_mapLayersByName(self):
|
||||
""" test retrieving map layer by name """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
self.assertEqual(QgsProject.instance().mapLayersByName('bad'), [])
|
||||
self.assertEqual(QgsProject.instance().mapLayersByName(None), [])
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
|
||||
self.assertEqual(QgsProject.instance().mapLayersByName('bad'), [])
|
||||
self.assertEqual(QgsProject.instance().mapLayersByName(None), [])
|
||||
self.assertEqual(QgsProject.instance().mapLayersByName('test'), [l1])
|
||||
self.assertEqual(QgsProject.instance().mapLayersByName('test2'), [l2])
|
||||
|
||||
#duplicate name
|
||||
l3 = createLayer('test')
|
||||
QgsProject.instance().addMapLayer(l3)
|
||||
self.assertEqual(set(QgsProject.instance().mapLayersByName('test')), set([l1, l3]))
|
||||
|
||||
def test_mapLayers(self):
|
||||
""" test retrieving map layers list """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
self.assertEqual(QgsProject.instance().mapLayers(), {})
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
|
||||
self.assertEqual(QgsProject.instance().mapLayers(), {l1.id(): l1, l2.id(): l2})
|
||||
|
||||
def test_removeMapLayersById(self):
|
||||
""" test removing map layers by ID """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
QgsProject.instance().removeMapLayers(['bad'])
|
||||
QgsProject.instance().removeMapLayers([None])
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
l3 = createLayer('test3')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2, l3])
|
||||
self.assertEqual(QgsProject.instance().count(), 3)
|
||||
|
||||
#remove bad layers
|
||||
QgsProject.instance().removeMapLayers(['bad'])
|
||||
self.assertEqual(QgsProject.instance().count(), 3)
|
||||
QgsProject.instance().removeMapLayers([None])
|
||||
self.assertEqual(QgsProject.instance().count(), 3)
|
||||
|
||||
# remove valid layers
|
||||
l1_id = l1.id()
|
||||
QgsProject.instance().removeMapLayers([l1_id])
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
# double remove
|
||||
QgsProject.instance().removeMapLayers([l1_id])
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
# test that layer has been deleted
|
||||
self.assertTrue(sip.isdeleted(l1))
|
||||
|
||||
# remove multiple
|
||||
QgsProject.instance().removeMapLayers([l2.id(), l3.id()])
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
self.assertTrue(sip.isdeleted(l2))
|
||||
|
||||
# try removing a layer not in the registry
|
||||
l4 = createLayer('test4')
|
||||
QgsProject.instance().removeMapLayers([l4.id()])
|
||||
self.assertFalse(sip.isdeleted(l4))
|
||||
|
||||
# fails on qt5 due to removeMapLayers list type conversion - needs a PyName alias
|
||||
# added to removeMapLayers for QGIS 3.0
|
||||
@unittest.expectedFailure(QT_VERSION_STR[0] == '5')
|
||||
def test_removeMapLayersByLayer(self):
|
||||
""" test removing map layers by layer"""
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
QgsProject.instance().removeMapLayers([None])
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
l3 = createLayer('test3')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2, l3])
|
||||
self.assertEqual(QgsProject.instance().count(), 3)
|
||||
|
||||
#remove bad layers
|
||||
QgsProject.instance().removeMapLayers([None])
|
||||
self.assertEqual(QgsProject.instance().count(), 3)
|
||||
|
||||
# remove valid layers
|
||||
QgsProject.instance().removeMapLayers([l1])
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
# test that layer has been deleted
|
||||
self.assertTrue(sip.isdeleted(l1))
|
||||
|
||||
# remove multiple
|
||||
QgsProject.instance().removeMapLayers([l2, l3])
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
self.assertTrue(sip.isdeleted(l2))
|
||||
self.assertTrue(sip.isdeleted(l3))
|
||||
|
||||
def test_removeMapLayerById(self):
|
||||
""" test removing a map layer by ID """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
QgsProject.instance().removeMapLayer('bad')
|
||||
QgsProject.instance().removeMapLayer(None)
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
#remove bad layers
|
||||
QgsProject.instance().removeMapLayer('bad')
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
QgsProject.instance().removeMapLayer(None)
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
# remove valid layers
|
||||
l1_id = l1.id()
|
||||
QgsProject.instance().removeMapLayer(l1_id)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
# double remove
|
||||
QgsProject.instance().removeMapLayer(l1_id)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
|
||||
# test that layer has been deleted
|
||||
self.assertTrue(sip.isdeleted(l1))
|
||||
|
||||
# remove second layer
|
||||
QgsProject.instance().removeMapLayer(l2.id())
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
self.assertTrue(sip.isdeleted(l2))
|
||||
|
||||
# try removing a layer not in the registry
|
||||
l3 = createLayer('test3')
|
||||
QgsProject.instance().removeMapLayer(l3.id())
|
||||
self.assertFalse(sip.isdeleted(l3))
|
||||
|
||||
def test_removeMapLayerByLayer(self):
|
||||
""" test removing a map layer by layer """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
QgsProject.instance().removeMapLayer('bad')
|
||||
QgsProject.instance().removeMapLayer(None)
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
#remove bad layers
|
||||
QgsProject.instance().removeMapLayer(None)
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
l3 = createLayer('test3')
|
||||
QgsProject.instance().removeMapLayer(l3)
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
# remove valid layers
|
||||
QgsProject.instance().removeMapLayer(l1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
|
||||
# test that layer has been deleted
|
||||
self.assertTrue(sip.isdeleted(l1))
|
||||
|
||||
# remove second layer
|
||||
QgsProject.instance().removeMapLayer(l2)
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
self.assertTrue(sip.isdeleted(l2))
|
||||
|
||||
# try removing a layer not in the registry
|
||||
l3 = createLayer('test3')
|
||||
QgsProject.instance().removeMapLayer(l3)
|
||||
self.assertFalse(sip.isdeleted(l3))
|
||||
|
||||
def test_removeAllMapLayers(self):
|
||||
""" test removing all map layers from registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
self.assertEqual(QgsProject.instance().mapLayersByName('test'), [])
|
||||
self.assertEqual(QgsProject.instance().mapLayersByName('test2'), [])
|
||||
|
||||
@unittest.skipIf(not use_signal_spy, "No QSignalSpy available")
|
||||
def test_addRemoveLayersSignals(self):
|
||||
""" test that signals are correctly emitted when removing map layers"""
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
layers_will_be_removed_spy = QSignalSpy(QgsProject.instance().layersWillBeRemoved)
|
||||
layer_will_be_removed_spy_str = QSignalSpy(QgsProject.instance().layerWillBeRemoved[str])
|
||||
layer_will_be_removed_spy_layer = QSignalSpy(QgsProject.instance().layerWillBeRemoved[QgsMapLayer])
|
||||
layers_removed_spy = QSignalSpy(QgsProject.instance().layersRemoved)
|
||||
layer_removed_spy = QSignalSpy(QgsProject.instance().layerRemoved)
|
||||
remove_all_spy = QSignalSpy(QgsProject.instance().removeAll)
|
||||
|
||||
l1 = createLayer('l1')
|
||||
l2 = createLayer('l2')
|
||||
l3 = createLayer('l3')
|
||||
l4 = createLayer('l4')
|
||||
QgsProject.instance().addMapLayers([l1, l2, l3, l4])
|
||||
|
||||
# remove 1 layer
|
||||
QgsProject.instance().removeMapLayer(l1)
|
||||
# can't seem to actually test the data which was emitted, so best we can do is test
|
||||
# the signal count
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 1)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 1)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 1)
|
||||
self.assertEqual(len(layers_removed_spy), 1)
|
||||
self.assertEqual(len(layer_removed_spy), 1)
|
||||
self.assertEqual(len(remove_all_spy), 0)
|
||||
self.assertEqual(QgsProject.instance().count(), 3)
|
||||
|
||||
# remove 2 layers at once
|
||||
QgsProject.instance().removeMapLayers([l2.id(), l3.id()])
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 2)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 3)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 3)
|
||||
self.assertEqual(len(layers_removed_spy), 2)
|
||||
self.assertEqual(len(layer_removed_spy), 3)
|
||||
self.assertEqual(len(remove_all_spy), 0)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
|
||||
# remove all
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 3)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 4)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 4)
|
||||
self.assertEqual(len(layers_removed_spy), 3)
|
||||
self.assertEqual(len(layer_removed_spy), 4)
|
||||
self.assertEqual(len(remove_all_spy), 1)
|
||||
|
||||
#remove some layers which aren't in the registry
|
||||
QgsProject.instance().removeMapLayers(['asdasd'])
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 3)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 4)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 4)
|
||||
self.assertEqual(len(layers_removed_spy), 3)
|
||||
self.assertEqual(len(layer_removed_spy), 4)
|
||||
self.assertEqual(len(remove_all_spy), 1)
|
||||
|
||||
l5 = createLayer('test5')
|
||||
QgsProject.instance().removeMapLayer(l5)
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 3)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 4)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 4)
|
||||
self.assertEqual(len(layers_removed_spy), 3)
|
||||
self.assertEqual(len(layer_removed_spy), 4)
|
||||
self.assertEqual(len(remove_all_spy), 1)
|
||||
|
||||
def test_RemoveLayerShouldNotSegFault(self):
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
reg = QgsProject.instance()
|
||||
# Should not segfault
|
||||
reg.removeMapLayers(['not_exists'])
|
||||
reg.removeMapLayer('not_exists2')
|
||||
|
||||
# check also that the removal of an unexistent layer does not insert a null layer
|
||||
for k, layer in list(reg.mapLayers().items()):
|
||||
assert(layer is not None)
|
||||
|
||||
def testTakeLayer(self):
|
||||
# test taking ownership of a layer from the project
|
||||
l1 = createLayer('l1')
|
||||
l2 = createLayer('l2')
|
||||
p = QgsProject()
|
||||
|
||||
# add one layer to project
|
||||
p.addMapLayer(l1)
|
||||
self.assertEqual(p.mapLayers(), {l1.id(): l1})
|
||||
self.assertEqual(l1.parent(), p)
|
||||
|
||||
# try taking some layers which don't exist in project
|
||||
self.assertFalse(p.takeMapLayer(None))
|
||||
self.assertFalse(p.takeMapLayer(l2))
|
||||
# but l2 should still exist..
|
||||
self.assertTrue(l2.isValid())
|
||||
|
||||
# take layer from project
|
||||
self.assertEqual(p.takeMapLayer(l1), l1)
|
||||
self.assertFalse(p.mapLayers()) # no layers left
|
||||
# but l1 should still exist
|
||||
self.assertTrue(l1.isValid())
|
||||
# layer should have no parent now
|
||||
self.assertFalse(l1.parent())
|
||||
|
||||
# destroy project
|
||||
p = None
|
||||
self.assertTrue(l1.isValid())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
495
tests/src/python/test_qgsmaplayerstore.py
Normal file
495
tests/src/python/test_qgsmaplayerstore.py
Normal file
@ -0,0 +1,495 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""QGIS Unit tests for QgsMapLayerStore.
|
||||
|
||||
.. note:: This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
"""
|
||||
__author__ = 'Nyall Dawson'
|
||||
__date__ = '2017-05'
|
||||
__copyright__ = 'Copyright 2017, The QGIS Project'
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
from qgis.core import QgsMapLayerStore, QgsVectorLayer, QgsMapLayer
|
||||
from qgis.testing import start_app, unittest
|
||||
from qgis.PyQt.QtCore import QT_VERSION_STR
|
||||
import sip
|
||||
from qgis.PyQt.QtTest import QSignalSpy
|
||||
|
||||
start_app()
|
||||
|
||||
|
||||
def createLayer(name):
|
||||
return QgsVectorLayer("Point?field=x:string", name, "memory")
|
||||
|
||||
|
||||
class TestQgsMapLayerStore(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pass
|
||||
|
||||
def test_addMapLayer(self):
|
||||
""" test adding individual map layers to store"""
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
l1 = createLayer('test')
|
||||
self.assertEqual(store.addMapLayer(l1), l1)
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 1)
|
||||
self.assertEqual(store.count(), 1)
|
||||
self.assertEqual(len(store), 1)
|
||||
|
||||
# adding a second layer should leave existing layers intact
|
||||
l2 = createLayer('test2')
|
||||
self.assertEqual(store.addMapLayer(l2), l2)
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 1)
|
||||
self.assertEqual(len(store.mapLayersByName('test2')), 1)
|
||||
self.assertEqual(store.count(), 2)
|
||||
self.assertEqual(len(store), 2)
|
||||
|
||||
def test_addMapLayerAlreadyAdded(self):
|
||||
""" test that already added layers can't be readded to store """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
l1 = createLayer('test')
|
||||
store.addMapLayer(l1)
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 1)
|
||||
self.assertEqual(store.count(), 1)
|
||||
self.assertEqual(store.addMapLayer(l1), None)
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 1)
|
||||
self.assertEqual(store.count(), 1)
|
||||
self.assertEqual(len(store), 1)
|
||||
|
||||
def test_addMapLayerInvalid(self):
|
||||
""" test that invalid map layers can't be added to store """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
self.assertEqual(store.addMapLayer(QgsVectorLayer("Point?field=x:string", 'test', "xxx")), None)
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 0)
|
||||
self.assertEqual(store.count(), 0)
|
||||
|
||||
def test_addMapLayerSignals(self):
|
||||
""" test that signals are correctly emitted when adding map layer"""
|
||||
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
layer_was_added_spy = QSignalSpy(store.layerWasAdded)
|
||||
layers_added_spy = QSignalSpy(store.layersAdded)
|
||||
|
||||
l1 = createLayer('test')
|
||||
store.addMapLayer(l1)
|
||||
|
||||
# can't seem to actually test the data which was emitted, so best we can do is test
|
||||
# the signal count
|
||||
self.assertEqual(len(layer_was_added_spy), 1)
|
||||
self.assertEqual(len(layers_added_spy), 1)
|
||||
|
||||
store.addMapLayer(createLayer('test2'))
|
||||
self.assertEqual(len(layer_was_added_spy), 2)
|
||||
self.assertEqual(len(layers_added_spy), 2)
|
||||
|
||||
# try readding a layer already in the store
|
||||
store.addMapLayer(l1)
|
||||
# should be no extra signals emitted
|
||||
self.assertEqual(len(layer_was_added_spy), 2)
|
||||
self.assertEqual(len(layers_added_spy), 2)
|
||||
|
||||
def test_addMapLayers(self):
|
||||
""" test adding multiple map layers to store """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
self.assertEqual(set(store.addMapLayers([l1, l2])), {l1, l2})
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 1)
|
||||
self.assertEqual(len(store.mapLayersByName('test2')), 1)
|
||||
self.assertEqual(store.count(), 2)
|
||||
|
||||
# adding more layers should leave existing layers intact
|
||||
l3 = createLayer('test3')
|
||||
l4 = createLayer('test4')
|
||||
self.assertEqual(set(store.addMapLayers([l3, l4])), {l3, l4})
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 1)
|
||||
self.assertEqual(len(store.mapLayersByName('test2')), 1)
|
||||
self.assertEqual(len(store.mapLayersByName('test3')), 1)
|
||||
self.assertEqual(len(store.mapLayersByName('test4')), 1)
|
||||
self.assertEqual(store.count(), 4)
|
||||
|
||||
store.removeAllMapLayers()
|
||||
|
||||
def test_addMapLayersInvalid(self):
|
||||
""" test that invalid map layersd can't be added to store """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
self.assertEqual(store.addMapLayers([QgsVectorLayer("Point?field=x:string", 'test', "xxx")]), [])
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 0)
|
||||
self.assertEqual(store.count(), 0)
|
||||
|
||||
def test_addMapLayersAlreadyAdded(self):
|
||||
""" test that already added layers can't be readded to store """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
l1 = createLayer('test')
|
||||
self.assertEqual(store.addMapLayers([l1]), [l1])
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 1)
|
||||
self.assertEqual(store.count(), 1)
|
||||
self.assertEqual(store.addMapLayers([l1]), [])
|
||||
self.assertEqual(len(store.mapLayersByName('test')), 1)
|
||||
self.assertEqual(store.count(), 1)
|
||||
|
||||
def test_addMapLayersSignals(self):
|
||||
""" test that signals are correctly emitted when adding map layers"""
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
layer_was_added_spy = QSignalSpy(store.layerWasAdded)
|
||||
layers_added_spy = QSignalSpy(store.layersAdded)
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
store.addMapLayers([l1, l2])
|
||||
|
||||
# can't seem to actually test the data which was emitted, so best we can do is test
|
||||
# the signal count
|
||||
self.assertEqual(len(layer_was_added_spy), 2)
|
||||
self.assertEqual(len(layers_added_spy), 1)
|
||||
|
||||
store.addMapLayers([createLayer('test3'), createLayer('test4')])
|
||||
self.assertEqual(len(layer_was_added_spy), 4)
|
||||
self.assertEqual(len(layers_added_spy), 2)
|
||||
|
||||
# try readding a layer already in the store
|
||||
store.addMapLayers([l1, l2])
|
||||
# should be no extra signals emitted
|
||||
self.assertEqual(len(layer_was_added_spy), 4)
|
||||
self.assertEqual(len(layers_added_spy), 2)
|
||||
|
||||
def test_mapLayerById(self):
|
||||
""" test retrieving map layer by ID """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
# test no crash with empty store
|
||||
self.assertEqual(store.mapLayer('bad'), None)
|
||||
self.assertEqual(store.mapLayer(None), None)
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
store.addMapLayers([l1, l2])
|
||||
|
||||
self.assertEqual(store.mapLayer('bad'), None)
|
||||
self.assertEqual(store.mapLayer(None), None)
|
||||
self.assertEqual(store.mapLayer(l1.id()), l1)
|
||||
self.assertEqual(store.mapLayer(l2.id()), l2)
|
||||
|
||||
def test_mapLayersByName(self):
|
||||
""" test retrieving map layer by name """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
# test no crash with empty store
|
||||
self.assertEqual(store.mapLayersByName('bad'), [])
|
||||
self.assertEqual(store.mapLayersByName(None), [])
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
store.addMapLayers([l1, l2])
|
||||
|
||||
self.assertEqual(store.mapLayersByName('bad'), [])
|
||||
self.assertEqual(store.mapLayersByName(None), [])
|
||||
self.assertEqual(store.mapLayersByName('test'), [l1])
|
||||
self.assertEqual(store.mapLayersByName('test2'), [l2])
|
||||
|
||||
#duplicate name
|
||||
l3 = createLayer('test')
|
||||
store.addMapLayer(l3)
|
||||
self.assertEqual(set(store.mapLayersByName('test')), {l1, l3})
|
||||
|
||||
def test_mapLayers(self):
|
||||
""" test retrieving map layers list """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
# test no crash with empty store
|
||||
self.assertEqual(store.mapLayers(), {})
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
store.addMapLayers([l1, l2])
|
||||
|
||||
self.assertEqual(store.mapLayers(), {l1.id(): l1, l2.id(): l2})
|
||||
|
||||
def test_removeMapLayersById(self):
|
||||
""" test removing map layers by ID """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
# test no crash with empty store
|
||||
store.removeMapLayersById(['bad'])
|
||||
store.removeMapLayersById([None])
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
l3 = createLayer('test3')
|
||||
|
||||
store.addMapLayers([l1, l2, l3])
|
||||
self.assertEqual(store.count(), 3)
|
||||
|
||||
#remove bad layers
|
||||
store.removeMapLayersById(['bad'])
|
||||
self.assertEqual(store.count(), 3)
|
||||
store.removeMapLayersById([None])
|
||||
self.assertEqual(store.count(), 3)
|
||||
|
||||
# remove valid layers
|
||||
l1_id = l1.id()
|
||||
store.removeMapLayersById([l1_id])
|
||||
self.assertEqual(store.count(), 2)
|
||||
# double remove
|
||||
store.removeMapLayersById([l1_id])
|
||||
self.assertEqual(store.count(), 2)
|
||||
|
||||
# test that layer has been deleted
|
||||
self.assertTrue(sip.isdeleted(l1))
|
||||
|
||||
# remove multiple
|
||||
store.removeMapLayersById([l2.id(), l3.id()])
|
||||
self.assertEqual(store.count(), 0)
|
||||
self.assertTrue(sip.isdeleted(l2))
|
||||
|
||||
# try removing a layer not in the store
|
||||
l4 = createLayer('test4')
|
||||
store.removeMapLayersById([l4.id()])
|
||||
self.assertFalse(sip.isdeleted(l4))
|
||||
|
||||
def test_removeMapLayersByLayer(self):
|
||||
""" test removing map layers by layer"""
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
# test no crash with empty store
|
||||
store.removeMapLayers([None])
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
l3 = createLayer('test3')
|
||||
|
||||
store.addMapLayers([l1, l2, l3])
|
||||
self.assertEqual(store.count(), 3)
|
||||
|
||||
#remove bad layers
|
||||
store.removeMapLayers([None])
|
||||
self.assertEqual(store.count(), 3)
|
||||
|
||||
# remove valid layers
|
||||
store.removeMapLayers([l1])
|
||||
self.assertEqual(store.count(), 2)
|
||||
|
||||
# test that layer has been deleted
|
||||
self.assertTrue(sip.isdeleted(l1))
|
||||
|
||||
# remove multiple
|
||||
store.removeMapLayers([l2, l3])
|
||||
self.assertEqual(store.count(), 0)
|
||||
self.assertTrue(sip.isdeleted(l2))
|
||||
self.assertTrue(sip.isdeleted(l3))
|
||||
|
||||
def test_removeMapLayerById(self):
|
||||
""" test removing a map layer by ID """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
# test no crash with empty store
|
||||
store.removeMapLayer('bad')
|
||||
store.removeMapLayer(None)
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
store.addMapLayers([l1, l2])
|
||||
self.assertEqual(store.count(), 2)
|
||||
|
||||
#remove bad layers
|
||||
store.removeMapLayer('bad')
|
||||
self.assertEqual(store.count(), 2)
|
||||
store.removeMapLayer(None)
|
||||
self.assertEqual(store.count(), 2)
|
||||
|
||||
# remove valid layers
|
||||
l1_id = l1.id()
|
||||
store.removeMapLayer(l1_id)
|
||||
self.assertEqual(store.count(), 1)
|
||||
# double remove
|
||||
store.removeMapLayer(l1_id)
|
||||
self.assertEqual(store.count(), 1)
|
||||
|
||||
# test that layer has been deleted
|
||||
self.assertTrue(sip.isdeleted(l1))
|
||||
|
||||
# remove second layer
|
||||
store.removeMapLayer(l2.id())
|
||||
self.assertEqual(store.count(), 0)
|
||||
self.assertTrue(sip.isdeleted(l2))
|
||||
|
||||
# try removing a layer not in the store
|
||||
l3 = createLayer('test3')
|
||||
store.removeMapLayer(l3.id())
|
||||
self.assertFalse(sip.isdeleted(l3))
|
||||
|
||||
def test_removeMapLayerByLayer(self):
|
||||
""" test removing a map layer by layer """
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
# test no crash with empty store
|
||||
store.removeMapLayer('bad')
|
||||
store.removeMapLayer(None)
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
store.addMapLayers([l1, l2])
|
||||
self.assertEqual(store.count(), 2)
|
||||
|
||||
#remove bad layers
|
||||
store.removeMapLayer(None)
|
||||
self.assertEqual(store.count(), 2)
|
||||
l3 = createLayer('test3')
|
||||
store.removeMapLayer(l3)
|
||||
self.assertEqual(store.count(), 2)
|
||||
|
||||
# remove valid layers
|
||||
store.removeMapLayer(l1)
|
||||
self.assertEqual(store.count(), 1)
|
||||
|
||||
# test that layer has been deleted
|
||||
self.assertTrue(sip.isdeleted(l1))
|
||||
|
||||
# remove second layer
|
||||
store.removeMapLayer(l2)
|
||||
self.assertEqual(store.count(), 0)
|
||||
self.assertTrue(sip.isdeleted(l2))
|
||||
|
||||
# try removing a layer not in the store
|
||||
l3 = createLayer('test3')
|
||||
store.removeMapLayer(l3)
|
||||
self.assertFalse(sip.isdeleted(l3))
|
||||
|
||||
def test_removeAllMapLayers(self):
|
||||
""" test removing all map layers from store """
|
||||
store = QgsMapLayerStore()
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
store.addMapLayers([l1, l2])
|
||||
self.assertEqual(store.count(), 2)
|
||||
store.removeAllMapLayers()
|
||||
self.assertEqual(store.count(), 0)
|
||||
self.assertEqual(store.mapLayersByName('test'), [])
|
||||
self.assertEqual(store.mapLayersByName('test2'), [])
|
||||
|
||||
def test_addRemoveLayersSignals(self):
|
||||
""" test that signals are correctly emitted when removing map layers"""
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
layers_will_be_removed_spy = QSignalSpy(store.layersWillBeRemoved)
|
||||
layer_will_be_removed_spy_str = QSignalSpy(store.layerWillBeRemoved[str])
|
||||
layer_will_be_removed_spy_layer = QSignalSpy(store.layerWillBeRemoved[QgsMapLayer])
|
||||
layers_removed_spy = QSignalSpy(store.layersRemoved)
|
||||
layer_removed_spy = QSignalSpy(store.layerRemoved)
|
||||
remove_all_spy = QSignalSpy(store.allLayersRemoved)
|
||||
|
||||
l1 = createLayer('l1')
|
||||
l2 = createLayer('l2')
|
||||
l3 = createLayer('l3')
|
||||
l4 = createLayer('l4')
|
||||
store.addMapLayers([l1, l2, l3, l4])
|
||||
|
||||
# remove 1 layer
|
||||
store.removeMapLayer(l1)
|
||||
# can't seem to actually test the data which was emitted, so best we can do is test
|
||||
# the signal count
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 1)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 1)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 1)
|
||||
self.assertEqual(len(layers_removed_spy), 1)
|
||||
self.assertEqual(len(layer_removed_spy), 1)
|
||||
self.assertEqual(len(remove_all_spy), 0)
|
||||
self.assertEqual(store.count(), 3)
|
||||
|
||||
# remove 2 layers at once
|
||||
store.removeMapLayersById([l2.id(), l3.id()])
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 2)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 3)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 3)
|
||||
self.assertEqual(len(layers_removed_spy), 2)
|
||||
self.assertEqual(len(layer_removed_spy), 3)
|
||||
self.assertEqual(len(remove_all_spy), 0)
|
||||
self.assertEqual(store.count(), 1)
|
||||
|
||||
# remove all
|
||||
store.removeAllMapLayers()
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 3)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 4)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 4)
|
||||
self.assertEqual(len(layers_removed_spy), 3)
|
||||
self.assertEqual(len(layer_removed_spy), 4)
|
||||
self.assertEqual(len(remove_all_spy), 1)
|
||||
|
||||
#remove some layers which aren't in the store
|
||||
store.removeMapLayersById(['asdasd'])
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 3)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 4)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 4)
|
||||
self.assertEqual(len(layers_removed_spy), 3)
|
||||
self.assertEqual(len(layer_removed_spy), 4)
|
||||
self.assertEqual(len(remove_all_spy), 1)
|
||||
|
||||
l5 = createLayer('test5')
|
||||
store.removeMapLayer(l5)
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 3)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 4)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 4)
|
||||
self.assertEqual(len(layers_removed_spy), 3)
|
||||
self.assertEqual(len(layer_removed_spy), 4)
|
||||
self.assertEqual(len(remove_all_spy), 1)
|
||||
|
||||
def test_RemoveLayerShouldNotSegFault(self):
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
# Should not segfault
|
||||
store.removeMapLayersById(['not_exists'])
|
||||
store.removeMapLayer('not_exists2')
|
||||
|
||||
# check also that the removal of an unexistent layer does not insert a null layer
|
||||
for k, layer in list(store.mapLayers().items()):
|
||||
assert(layer is not None)
|
||||
|
||||
def testTakeLayer(self):
|
||||
# test taking ownership of a layer from the store
|
||||
l1 = createLayer('l1')
|
||||
l2 = createLayer('l2')
|
||||
store = QgsMapLayerStore()
|
||||
|
||||
# add one layer to store
|
||||
store.addMapLayer(l1)
|
||||
self.assertEqual(store.mapLayers(), {l1.id(): l1})
|
||||
self.assertEqual(l1.parent(), store)
|
||||
|
||||
# try taking some layers which don't exist in store
|
||||
self.assertFalse(store.takeMapLayer(None))
|
||||
self.assertFalse(store.takeMapLayer(l2))
|
||||
# but l2 should still exist..
|
||||
self.assertTrue(l2.isValid())
|
||||
|
||||
# take layer from store
|
||||
self.assertEqual(store.takeMapLayer(l1), l1)
|
||||
self.assertFalse(store.mapLayers()) # no layers left
|
||||
# but l1 should still exist
|
||||
self.assertTrue(l1.isValid())
|
||||
# layer should have no parent now
|
||||
self.assertFalse(l1.parent())
|
||||
|
||||
# destroy store
|
||||
store = None
|
||||
self.assertTrue(l1.isValid())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -22,9 +22,15 @@ from qgis.core import (QgsProject,
|
||||
QgsApplication,
|
||||
QgsUnitTypes,
|
||||
QgsCoordinateReferenceSystem,
|
||||
QgsVectorLayer)
|
||||
QgsVectorLayer,
|
||||
QgsMapLayer)
|
||||
from qgis.gui import (QgsLayerTreeMapCanvasBridge,
|
||||
QgsMapCanvas)
|
||||
|
||||
from qgis.PyQt.QtTest import QSignalSpy
|
||||
from qgis.PyQt.QtCore import QT_VERSION_STR
|
||||
import sip
|
||||
|
||||
from qgis.testing import start_app, unittest
|
||||
from utilities import (unitTestDataPath)
|
||||
|
||||
@ -32,6 +38,10 @@ app = start_app()
|
||||
TEST_DATA_DIR = unitTestDataPath()
|
||||
|
||||
|
||||
def createLayer(name):
|
||||
return QgsVectorLayer("Point?field=x:string", name, "memory")
|
||||
|
||||
|
||||
class TestQgsProject(unittest.TestCase):
|
||||
|
||||
def __init__(self, methodName):
|
||||
@ -181,6 +191,499 @@ class TestQgsProject(unittest.TestCase):
|
||||
expected = ['polys', 'lines']
|
||||
self.assertEqual(sorted(layers_names), sorted(expected))
|
||||
|
||||
def testInstance(self):
|
||||
""" test retrieving global instance """
|
||||
self.assertTrue(QgsProject.instance())
|
||||
|
||||
# register a layer to the singleton
|
||||
QgsProject.instance().addMapLayer(createLayer('test'))
|
||||
|
||||
# check that the same instance is returned
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayer(self):
|
||||
""" test adding individual map layers to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
l1 = createLayer('test')
|
||||
self.assertEqual(QgsProject.instance().addMapLayer(l1), l1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
|
||||
# adding a second layer should leave existing layers intact
|
||||
l2 = createLayer('test2')
|
||||
self.assertEqual(QgsProject.instance().addMapLayer(l2), l2)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test2')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayerAlreadyAdded(self):
|
||||
""" test that already added layers can't be readded to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
l1 = createLayer('test')
|
||||
QgsProject.instance().addMapLayer(l1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
self.assertEqual(QgsProject.instance().addMapLayer(l1), None)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayerInvalid(self):
|
||||
""" test that invalid map layersd can't be added to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
self.assertEqual(QgsProject.instance().addMapLayer(QgsVectorLayer("Point?field=x:string", 'test', "xxx")), None)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 0)
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayerSignals(self):
|
||||
""" test that signals are correctly emitted when adding map layer"""
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
layer_was_added_spy = QSignalSpy(QgsProject.instance().layerWasAdded)
|
||||
layers_added_spy = QSignalSpy(QgsProject.instance().layersAdded)
|
||||
legend_layers_added_spy = QSignalSpy(QgsProject.instance().legendLayersAdded)
|
||||
|
||||
l1 = createLayer('test')
|
||||
QgsProject.instance().addMapLayer(l1)
|
||||
|
||||
# can't seem to actually test the data which was emitted, so best we can do is test
|
||||
# the signal count
|
||||
self.assertEqual(len(layer_was_added_spy), 1)
|
||||
self.assertEqual(len(layers_added_spy), 1)
|
||||
self.assertEqual(len(legend_layers_added_spy), 1)
|
||||
|
||||
# layer not added to legend
|
||||
QgsProject.instance().addMapLayer(createLayer('test2'), False)
|
||||
self.assertEqual(len(layer_was_added_spy), 2)
|
||||
self.assertEqual(len(layers_added_spy), 2)
|
||||
self.assertEqual(len(legend_layers_added_spy), 1)
|
||||
|
||||
# try readding a layer already in the registry
|
||||
QgsProject.instance().addMapLayer(l1)
|
||||
# should be no extra signals emitted
|
||||
self.assertEqual(len(layer_was_added_spy), 2)
|
||||
self.assertEqual(len(layers_added_spy), 2)
|
||||
self.assertEqual(len(legend_layers_added_spy), 1)
|
||||
|
||||
def test_addMapLayers(self):
|
||||
""" test adding multiple map layers to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
self.assertEqual(set(QgsProject.instance().addMapLayers([l1, l2])), set([l1, l2]))
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test2')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
# adding more layers should leave existing layers intact
|
||||
l3 = createLayer('test3')
|
||||
l4 = createLayer('test4')
|
||||
self.assertEqual(set(QgsProject.instance().addMapLayers([l3, l4])), set([l3, l4]))
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test2')), 1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test3')), 1)
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test4')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 4)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayersInvalid(self):
|
||||
""" test that invalid map layersd can't be added to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
self.assertEqual(QgsProject.instance().addMapLayers([QgsVectorLayer("Point?field=x:string", 'test', "xxx")]), [])
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 0)
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayersAlreadyAdded(self):
|
||||
""" test that already added layers can't be readded to registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
l1 = createLayer('test')
|
||||
self.assertEqual(QgsProject.instance().addMapLayers([l1]), [l1])
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
self.assertEqual(QgsProject.instance().addMapLayers([l1]), [])
|
||||
self.assertEqual(len(QgsProject.instance().mapLayersByName('test')), 1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
def test_addMapLayersSignals(self):
|
||||
""" test that signals are correctly emitted when adding map layers"""
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
layer_was_added_spy = QSignalSpy(QgsProject.instance().layerWasAdded)
|
||||
layers_added_spy = QSignalSpy(QgsProject.instance().layersAdded)
|
||||
legend_layers_added_spy = QSignalSpy(QgsProject.instance().legendLayersAdded)
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
|
||||
# can't seem to actually test the data which was emitted, so best we can do is test
|
||||
# the signal count
|
||||
self.assertEqual(len(layer_was_added_spy), 2)
|
||||
self.assertEqual(len(layers_added_spy), 1)
|
||||
self.assertEqual(len(legend_layers_added_spy), 1)
|
||||
|
||||
# layer not added to legend
|
||||
QgsProject.instance().addMapLayers([createLayer('test3'), createLayer('test4')], False)
|
||||
self.assertEqual(len(layer_was_added_spy), 4)
|
||||
self.assertEqual(len(layers_added_spy), 2)
|
||||
self.assertEqual(len(legend_layers_added_spy), 1)
|
||||
|
||||
# try readding a layer already in the registry
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
# should be no extra signals emitted
|
||||
self.assertEqual(len(layer_was_added_spy), 4)
|
||||
self.assertEqual(len(layers_added_spy), 2)
|
||||
self.assertEqual(len(legend_layers_added_spy), 1)
|
||||
|
||||
def test_mapLayerById(self):
|
||||
""" test retrieving map layer by ID """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
self.assertEqual(QgsProject.instance().mapLayer('bad'), None)
|
||||
self.assertEqual(QgsProject.instance().mapLayer(None), None)
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
|
||||
self.assertEqual(QgsProject.instance().mapLayer('bad'), None)
|
||||
self.assertEqual(QgsProject.instance().mapLayer(None), None)
|
||||
self.assertEqual(QgsProject.instance().mapLayer(l1.id()), l1)
|
||||
self.assertEqual(QgsProject.instance().mapLayer(l2.id()), l2)
|
||||
|
||||
def test_mapLayersByName(self):
|
||||
""" test retrieving map layer by name """
|
||||
p = QgsProject()
|
||||
|
||||
# test no crash with empty registry
|
||||
self.assertEqual(p.mapLayersByName('bad'), [])
|
||||
self.assertEqual(p.mapLayersByName(None), [])
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
p.addMapLayers([l1, l2])
|
||||
|
||||
self.assertEqual(p.mapLayersByName('bad'), [])
|
||||
self.assertEqual(p.mapLayersByName(None), [])
|
||||
self.assertEqual(p.mapLayersByName('test'), [l1])
|
||||
self.assertEqual(p.mapLayersByName('test2'), [l2])
|
||||
|
||||
#duplicate name
|
||||
l3 = createLayer('test')
|
||||
p.addMapLayer(l3)
|
||||
self.assertEqual(set(p.mapLayersByName('test')), set([l1, l3]))
|
||||
|
||||
def test_mapLayers(self):
|
||||
""" test retrieving map layers list """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
self.assertEqual(QgsProject.instance().mapLayers(), {})
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
|
||||
self.assertEqual(QgsProject.instance().mapLayers(), {l1.id(): l1, l2.id(): l2})
|
||||
|
||||
def test_removeMapLayersById(self):
|
||||
""" test removing map layers by ID """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
QgsProject.instance().removeMapLayers(['bad'])
|
||||
QgsProject.instance().removeMapLayers([None])
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
l3 = createLayer('test3')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2, l3])
|
||||
self.assertEqual(QgsProject.instance().count(), 3)
|
||||
|
||||
#remove bad layers
|
||||
QgsProject.instance().removeMapLayers(['bad'])
|
||||
self.assertEqual(QgsProject.instance().count(), 3)
|
||||
QgsProject.instance().removeMapLayers([None])
|
||||
self.assertEqual(QgsProject.instance().count(), 3)
|
||||
|
||||
# remove valid layers
|
||||
l1_id = l1.id()
|
||||
QgsProject.instance().removeMapLayers([l1_id])
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
# double remove
|
||||
QgsProject.instance().removeMapLayers([l1_id])
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
# test that layer has been deleted
|
||||
self.assertTrue(sip.isdeleted(l1))
|
||||
|
||||
# remove multiple
|
||||
QgsProject.instance().removeMapLayers([l2.id(), l3.id()])
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
self.assertTrue(sip.isdeleted(l2))
|
||||
|
||||
# try removing a layer not in the registry
|
||||
l4 = createLayer('test4')
|
||||
QgsProject.instance().removeMapLayers([l4.id()])
|
||||
self.assertFalse(sip.isdeleted(l4))
|
||||
|
||||
# fails on qt5 due to removeMapLayers list type conversion - needs a PyName alias
|
||||
# added to removeMapLayers for QGIS 3.0
|
||||
@unittest.expectedFailure(QT_VERSION_STR[0] == '5')
|
||||
def test_removeMapLayersByLayer(self):
|
||||
""" test removing map layers by layer"""
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
QgsProject.instance().removeMapLayers([None])
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
l3 = createLayer('test3')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2, l3])
|
||||
self.assertEqual(QgsProject.instance().count(), 3)
|
||||
|
||||
#remove bad layers
|
||||
QgsProject.instance().removeMapLayers([None])
|
||||
self.assertEqual(QgsProject.instance().count(), 3)
|
||||
|
||||
# remove valid layers
|
||||
QgsProject.instance().removeMapLayers([l1])
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
# test that layer has been deleted
|
||||
self.assertTrue(sip.isdeleted(l1))
|
||||
|
||||
# remove multiple
|
||||
QgsProject.instance().removeMapLayers([l2, l3])
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
self.assertTrue(sip.isdeleted(l2))
|
||||
self.assertTrue(sip.isdeleted(l3))
|
||||
|
||||
def test_removeMapLayerById(self):
|
||||
""" test removing a map layer by ID """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
QgsProject.instance().removeMapLayer('bad')
|
||||
QgsProject.instance().removeMapLayer(None)
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
#remove bad layers
|
||||
QgsProject.instance().removeMapLayer('bad')
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
QgsProject.instance().removeMapLayer(None)
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
# remove valid layers
|
||||
l1_id = l1.id()
|
||||
QgsProject.instance().removeMapLayer(l1_id)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
# double remove
|
||||
QgsProject.instance().removeMapLayer(l1_id)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
|
||||
# test that layer has been deleted
|
||||
self.assertTrue(sip.isdeleted(l1))
|
||||
|
||||
# remove second layer
|
||||
QgsProject.instance().removeMapLayer(l2.id())
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
self.assertTrue(sip.isdeleted(l2))
|
||||
|
||||
# try removing a layer not in the registry
|
||||
l3 = createLayer('test3')
|
||||
QgsProject.instance().removeMapLayer(l3.id())
|
||||
self.assertFalse(sip.isdeleted(l3))
|
||||
|
||||
def test_removeMapLayerByLayer(self):
|
||||
""" test removing a map layer by layer """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
# test no crash with empty registry
|
||||
QgsProject.instance().removeMapLayer('bad')
|
||||
QgsProject.instance().removeMapLayer(None)
|
||||
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
#remove bad layers
|
||||
QgsProject.instance().removeMapLayer(None)
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
l3 = createLayer('test3')
|
||||
QgsProject.instance().removeMapLayer(l3)
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
|
||||
# remove valid layers
|
||||
QgsProject.instance().removeMapLayer(l1)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
|
||||
# test that layer has been deleted
|
||||
self.assertTrue(sip.isdeleted(l1))
|
||||
|
||||
# remove second layer
|
||||
QgsProject.instance().removeMapLayer(l2)
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
self.assertTrue(sip.isdeleted(l2))
|
||||
|
||||
# try removing a layer not in the registry
|
||||
l3 = createLayer('test3')
|
||||
QgsProject.instance().removeMapLayer(l3)
|
||||
self.assertFalse(sip.isdeleted(l3))
|
||||
|
||||
def test_removeAllMapLayers(self):
|
||||
""" test removing all map layers from registry """
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
l1 = createLayer('test')
|
||||
l2 = createLayer('test2')
|
||||
|
||||
QgsProject.instance().addMapLayers([l1, l2])
|
||||
self.assertEqual(QgsProject.instance().count(), 2)
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
self.assertEqual(QgsProject.instance().count(), 0)
|
||||
self.assertEqual(QgsProject.instance().mapLayersByName('test'), [])
|
||||
self.assertEqual(QgsProject.instance().mapLayersByName('test2'), [])
|
||||
|
||||
def test_addRemoveLayersSignals(self):
|
||||
""" test that signals are correctly emitted when removing map layers"""
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
layers_will_be_removed_spy = QSignalSpy(QgsProject.instance().layersWillBeRemoved)
|
||||
layer_will_be_removed_spy_str = QSignalSpy(QgsProject.instance().layerWillBeRemoved[str])
|
||||
layer_will_be_removed_spy_layer = QSignalSpy(QgsProject.instance().layerWillBeRemoved[QgsMapLayer])
|
||||
layers_removed_spy = QSignalSpy(QgsProject.instance().layersRemoved)
|
||||
layer_removed_spy = QSignalSpy(QgsProject.instance().layerRemoved)
|
||||
remove_all_spy = QSignalSpy(QgsProject.instance().removeAll)
|
||||
|
||||
l1 = createLayer('l1')
|
||||
l2 = createLayer('l2')
|
||||
l3 = createLayer('l3')
|
||||
l4 = createLayer('l4')
|
||||
QgsProject.instance().addMapLayers([l1, l2, l3, l4])
|
||||
|
||||
# remove 1 layer
|
||||
QgsProject.instance().removeMapLayer(l1)
|
||||
# can't seem to actually test the data which was emitted, so best we can do is test
|
||||
# the signal count
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 1)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 1)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 1)
|
||||
self.assertEqual(len(layers_removed_spy), 1)
|
||||
self.assertEqual(len(layer_removed_spy), 1)
|
||||
self.assertEqual(len(remove_all_spy), 0)
|
||||
self.assertEqual(QgsProject.instance().count(), 3)
|
||||
|
||||
# remove 2 layers at once
|
||||
QgsProject.instance().removeMapLayers([l2.id(), l3.id()])
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 2)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 3)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 3)
|
||||
self.assertEqual(len(layers_removed_spy), 2)
|
||||
self.assertEqual(len(layer_removed_spy), 3)
|
||||
self.assertEqual(len(remove_all_spy), 0)
|
||||
self.assertEqual(QgsProject.instance().count(), 1)
|
||||
|
||||
# remove all
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 3)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 4)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 4)
|
||||
self.assertEqual(len(layers_removed_spy), 3)
|
||||
self.assertEqual(len(layer_removed_spy), 4)
|
||||
self.assertEqual(len(remove_all_spy), 1)
|
||||
|
||||
#remove some layers which aren't in the registry
|
||||
QgsProject.instance().removeMapLayers(['asdasd'])
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 3)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 4)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 4)
|
||||
self.assertEqual(len(layers_removed_spy), 3)
|
||||
self.assertEqual(len(layer_removed_spy), 4)
|
||||
self.assertEqual(len(remove_all_spy), 1)
|
||||
|
||||
l5 = createLayer('test5')
|
||||
QgsProject.instance().removeMapLayer(l5)
|
||||
self.assertEqual(len(layers_will_be_removed_spy), 3)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_str), 4)
|
||||
self.assertEqual(len(layer_will_be_removed_spy_layer), 4)
|
||||
self.assertEqual(len(layers_removed_spy), 3)
|
||||
self.assertEqual(len(layer_removed_spy), 4)
|
||||
self.assertEqual(len(remove_all_spy), 1)
|
||||
|
||||
def test_RemoveLayerShouldNotSegFault(self):
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
reg = QgsProject.instance()
|
||||
# Should not segfault
|
||||
reg.removeMapLayers(['not_exists'])
|
||||
reg.removeMapLayer('not_exists2')
|
||||
|
||||
# check also that the removal of an unexistent layer does not insert a null layer
|
||||
for k, layer in list(reg.mapLayers().items()):
|
||||
assert(layer is not None)
|
||||
|
||||
def testTakeLayer(self):
|
||||
# test taking ownership of a layer from the project
|
||||
l1 = createLayer('l1')
|
||||
l2 = createLayer('l2')
|
||||
p = QgsProject()
|
||||
|
||||
# add one layer to project
|
||||
p.addMapLayer(l1)
|
||||
self.assertEqual(p.mapLayers(), {l1.id(): l1})
|
||||
self.assertEqual(l1.parent().parent(), p)
|
||||
|
||||
# try taking some layers which don't exist in project
|
||||
self.assertFalse(p.takeMapLayer(None))
|
||||
self.assertFalse(p.takeMapLayer(l2))
|
||||
# but l2 should still exist..
|
||||
self.assertTrue(l2.isValid())
|
||||
|
||||
# take layer from project
|
||||
self.assertEqual(p.takeMapLayer(l1), l1)
|
||||
self.assertFalse(p.mapLayers()) # no layers left
|
||||
# but l1 should still exist
|
||||
self.assertTrue(l1.isValid())
|
||||
# layer should have no parent now
|
||||
self.assertFalse(l1.parent())
|
||||
|
||||
# destroy project
|
||||
p = None
|
||||
self.assertTrue(l1.isValid())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user