Skip to content

Commit

Permalink
Allow to declare layer dependencies on a vector layer
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugo Mercier committed Jan 7, 2016
1 parent f8f056e commit 020dac0
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 2 deletions.
5 changes: 5 additions & 0 deletions python/core/qgsvectordataprovider.sip
Expand Up @@ -322,6 +322,11 @@ class QgsVectorDataProvider : QgsDataProvider

virtual void forceReload();

/**
* Get the list of layer ids on which this layer depends. This in particular determines the order of layer loading.
*/
virtual QSet<QString> layerDependencies() const;

protected:
void clearMinMaxCache();
void fillMinMaxCache();
Expand Down
5 changes: 5 additions & 0 deletions python/core/qgsvectorlayer.sip
Expand Up @@ -441,6 +441,11 @@ class QgsVectorLayer : QgsMapLayer

const QList<QgsVectorJoinInfo> vectorJoins() const;

/**
* Get the list of layer ids on which this layer depends. This in particular determines the order of layer loading.
*/
virtual QSet<QString> layerDependencies() const;

/**
* Add a new field which is calculated by the expression specified
*
Expand Down
74 changes: 72 additions & 2 deletions src/core/qgsproject.cpp
Expand Up @@ -672,12 +672,82 @@ QPair< bool, QList<QDomNode> > QgsProject::_getMapLayers( QDomDocument const &do

emit layerLoaded( 0, nl.count() );

// Determine a loading order of layers based on a graph of dependencies
QMap< QString, QVector< QString > > dependencies;
QVector<QString> sortedLayers;
QMap<QString, int> layerIdIdx;
QList<QString> layersToSort;

for ( int i = 0; i < nl.count(); i++ )
{
QVector<QString> deps;
QDomNode node = nl.item( i );
QDomElement element = node.toElement();

QString id = node.namedItem( "id" ).toElement().text();

// dependencies for this layer
QDomElement layerDependenciesElem = node.firstChildElement( "layerDependencies" );
if ( !layerDependenciesElem.isNull() )
{
QDomNodeList dependencyList = layerDependenciesElem.elementsByTagName( "layer" );
for ( int j = 0; j < dependencyList.size(); ++j )
{
QDomElement depElem = dependencyList.at( j ).toElement();
deps << depElem.attribute( "id" );
}
}
dependencies[id] = deps;

if ( deps.empty() )
sortedLayers << id;
else
layersToSort << id;
layerIdIdx[id] = i;
}

bool hasCycle = false;
while ( !layersToSort.empty() && !hasCycle )
{
QList<QString>::iterator it = layersToSort.begin();
while ( it != layersToSort.end() )
{
hasCycle = true;
bool resolved = true;
foreach ( QString dep, dependencies[*it] )
{
if ( !sortedLayers.contains( dep ) )
{
resolved = false;
break;
}
}
if ( resolved ) // dependencies for this layer are resolved
{
sortedLayers << *it;
it = layersToSort.erase( it ); // erase and go to the next
hasCycle = false;
}
else
{
it++;
}
}
}

if ( hasCycle )
{
// should not happen, since layers with cyclic dependencies may only be created by
// manually modifying the project file
return qMakePair( false, QList<QDomNode>() );
}

// Collect vector layers with joins.
// They need to refresh join caches and symbology infos after all layers are loaded
QList< QPair< QgsVectorLayer*, QDomElement > > vLayerList;

for ( int i = 0; i < nl.count(); i++ )
foreach ( QString id, sortedLayers )
{
int i = layerIdIdx[id];
QDomNode node = nl.item( i );
QDomElement element = node.toElement();

Expand Down
5 changes: 5 additions & 0 deletions src/core/qgsvectordataprovider.cpp
Expand Up @@ -548,4 +548,9 @@ void QgsVectorDataProvider::pushError( const QString& msg )
mErrors << msg;
}

QSet<QString> QgsVectorDataProvider::layerDependencies() const
{
return QSet<QString>();
}

QStringList QgsVectorDataProvider::smEncodings;
5 changes: 5 additions & 0 deletions src/core/qgsvectordataprovider.h
Expand Up @@ -383,6 +383,11 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
emit dataChanged();
}

/**
* Get the list of layer ids on which this layer depends. This in particular determines the order of layer loading.
*/
virtual QSet<QString> layerDependencies() const;

protected:
void clearMinMaxCache();
void fillMinMaxCache();
Expand Down
19 changes: 19 additions & 0 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -1620,6 +1620,16 @@ bool QgsVectorLayer::writeXml( QDomNode & layer_node,
//save joins
mJoinBuffer->writeXml( layer_node, document );

// dependencies
QDomElement dependenciesElement = document.createElement( "layerDependencies" );
foreach ( QString layerId, layerDependencies() )
{
QDomElement depElem = document.createElement( "layer" );
depElem.setAttribute( "id", layerId );
dependenciesElement.appendChild( depElem );
}
layer_node.appendChild( dependenciesElement );

// save expression fields
mExpressionFieldBuffer->writeXml( layer_node, document );

Expand Down Expand Up @@ -3911,3 +3921,12 @@ bool QgsAttributeEditorRelation::init( QgsRelationManager* relationManager )
mRelation = relationManager->relation( mRelationId );
return mRelation.isValid();
}

QSet<QString> QgsVectorLayer::layerDependencies() const
{
if ( mDataProvider )
{
return mDataProvider->layerDependencies();
}
return QSet<QString>();
}
5 changes: 5 additions & 0 deletions src/core/qgsvectorlayer.h
Expand Up @@ -548,6 +548,11 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer

const QList<QgsVectorJoinInfo> vectorJoins() const;

/**
* Get the list of layer ids on which this layer depends. This in particular determines the order of layer loading.
*/
virtual QSet<QString> layerDependencies() const;

/**
* Add a new field which is calculated by the expression specified
*
Expand Down

0 comments on commit 020dac0

Please sign in to comment.