Use QgsMapLayerStore within QgsProject

This commit is contained in:
Nyall Dawson 2017-05-02 10:59:34 +10:00
parent f9bd83c035
commit 26afb2e5b6
6 changed files with 81 additions and 143 deletions

View File

@ -77,7 +77,8 @@ class QgsMapLayerStore : QObject
%End
QList<QgsMapLayer *> addMapLayers( const QList<QgsMapLayer *> &layers /Transfer/ );
QList<QgsMapLayer *> addMapLayers( const QList<QgsMapLayer *> &layers /Transfer/);
%Docstring
\brief
Add a list of ``layers`` to the store. Ownership of the layers is transferred
@ -86,6 +87,9 @@ class QgsMapLayerStore : QObject
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,
@ -95,7 +99,8 @@ class QgsMapLayerStore : QObject
:rtype: list of QgsMapLayer
%End
QgsMapLayer *addMapLayer( QgsMapLayer *layer /Transfer/ );
QgsMapLayer *addMapLayer( QgsMapLayer *layer /Transfer/);
%Docstring
\brief
Add a ``layer`` to the store. Ownership of the layer is transferred to the
@ -106,6 +111,9 @@ class QgsMapLayerStore : QObject
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
@ -137,6 +145,19 @@ class QgsMapLayerStore : QObject
%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

View File

@ -50,8 +50,7 @@ QList<QgsMapLayer *> QgsMapLayerStore::mapLayersByName( const QString &layerName
return myResultList;
}
QList<QgsMapLayer *> QgsMapLayerStore::addMapLayers(
const QList<QgsMapLayer *> &layers )
QList<QgsMapLayer *> QgsMapLayerStore::addMapLayers( const QList<QgsMapLayer *> &layers, bool takeOwnership )
{
QList<QgsMapLayer *> myResultList;
Q_FOREACH ( QgsMapLayer *myLayer, layers )
@ -66,7 +65,10 @@ QList<QgsMapLayer *> QgsMapLayerStore::addMapLayers(
{
mMapLayers[myLayer->id()] = myLayer;
myResultList << mMapLayers[myLayer->id()];
myLayer->setParent( this );
if ( takeOwnership )
{
myLayer->setParent( this );
}
connect( myLayer, &QObject::destroyed, this, &QgsMapLayerStore::onMapLayerDeleted );
emit layerWasAdded( myLayer );
}
@ -79,10 +81,10 @@ QList<QgsMapLayer *> QgsMapLayerStore::addMapLayers(
}
QgsMapLayer *
QgsMapLayerStore::addMapLayer( QgsMapLayer *layer )
QgsMapLayerStore::addMapLayer( QgsMapLayer *layer, bool takeOwnership )
{
QList<QgsMapLayer *> addedLayers;
addedLayers = addMapLayers( QList<QgsMapLayer *>() << layer );
addedLayers = addMapLayers( QList<QgsMapLayer *>() << layer, takeOwnership );
return addedLayers.isEmpty() ? nullptr : addedLayers[0];
}

View File

@ -124,6 +124,9 @@ class CORE_EXPORT QgsMapLayerStore : public QObject
* 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,
@ -131,7 +134,8 @@ class CORE_EXPORT QgsMapLayerStore : public QObject
*
* \see addMapLayer()
*/
QList<QgsMapLayer *> addMapLayers( const QList<QgsMapLayer *> &layers SIP_TRANSFER );
QList<QgsMapLayer *> addMapLayers( const QList<QgsMapLayer *> &layers SIP_TRANSFER,
bool takeOwnership SIP_PYARGREMOVE = true );
/**
* \brief
@ -143,6 +147,9 @@ class CORE_EXPORT QgsMapLayerStore : public QObject
* 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
*
@ -151,7 +158,8 @@ class CORE_EXPORT QgsMapLayerStore : public QObject
* \note Use addMapLayers() if adding more than one layer at a time.
* \see addMapLayers()
*/
QgsMapLayer *addMapLayer( QgsMapLayer *layer SIP_TRANSFER );
QgsMapLayer *addMapLayer( QgsMapLayer *layer SIP_TRANSFER,
bool takeOwnership SIP_PYARGREMOVE = true );
/**
* \brief
@ -182,7 +190,6 @@ class CORE_EXPORT QgsMapLayerStore : public QObject
* \see removeMapLayer()
* \see removeAllMapLayers()
*/
//TODO QGIS 3.0 - add PyName alias to avoid list type conversion error
void removeMapLayers( const QList<QgsMapLayer *> &layers );
/**

View File

@ -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 );
@ -2066,31 +2084,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 +2108,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 +2129,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();
}

View File

@ -38,6 +38,7 @@
#include "qgscoordinatereferencesystem.h"
#include "qgsprojectproperty.h"
#include "qgsmaplayer.h"
#include "qgsmaplayerstore.h"
class QFileInfo;
class QDomDocument;
@ -567,17 +568,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
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;
return mLayerStore->layers<T>();
}
/**
@ -968,8 +959,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;
@ -1002,7 +991,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
//! \note not available in Python bindings
void loadEmbeddedNodes( QgsLayerTreeGroup *group );
QMap<QString, QgsMapLayer *> mMapLayers;
std::unique_ptr< QgsMapLayerStore > mLayerStore;
QString mErrorMessage;

View File

@ -511,7 +511,7 @@ class TestQgsProjectMapLayers(unittest.TestCase):
# add one layer to project
p.addMapLayer(l1)
self.assertEqual(p.mapLayers(), {l1.id(): l1})
self.assertEqual(l1.parent(), p)
self.assertEqual(l1.parent().parent(), p)
# try taking some layers which don't exist in project
self.assertFalse(p.takeMapLayer(None))