Skip to content

Commit

Permalink
* Save and restore visiblity state of embedded group layers (fixes #4097
Browse files Browse the repository at this point in the history
)

* Adds support for lists in custom properties
  • Loading branch information
jef-n committed Jan 13, 2015
1 parent 3711fd5 commit b49da36
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 22 deletions.
13 changes: 8 additions & 5 deletions python/core/layertree/qgslayertreeutils.sip
Expand Up @@ -11,11 +11,11 @@ class QgsLayerTreeUtils

public:

//! Try to load layer tree from <legend> tag from project files from QGIS 2.2 and below
//! Try to load layer tree from \verbatim <legend> \endverbatim tag from project files from QGIS 2.2 and below
static bool readOldLegend( QgsLayerTreeGroup* root, const QDomElement& legendElem );
//! Try to load custom layer order from <legend> tag from project files from QGIS 2.2 and below
//! Try to load custom layer order from \verbatim <legend> \endverbatim tag from project files from QGIS 2.2 and below
static bool readOldLegendLayerOrder( const QDomElement& legendElem, bool& hasCustomOrder, QStringList& order );
//! Return <legend> tag used in QGIS 2.2 and below
//! Return \verbatim <legend> \endverbatim tag used in QGIS 2.2 and below
static QDomElement writeOldLegend( QDomDocument& doc, QgsLayerTreeGroup* root, bool hasCustomOrder, const QStringList& order );

//! Convert Qt::CheckState to QString
Expand All @@ -31,7 +31,10 @@ class QgsLayerTreeUtils
//! Remove layer nodes that refer to invalid layers
static void removeInvalidLayers( QgsLayerTreeGroup* group );

//! Remove subtree of embedded groups. Useful when saving layer tree
static void removeChildrenOfEmbeddedGroups( QgsLayerTreeGroup* group );
//! Remove subtree of embedded groups and replaces it with a custom property embedded-visible-layers
static void replaceChildrenOfEmbeddedGroups( QgsLayerTreeGroup* group );


//! get invisible layers
static QStringList invisibleLayerList( QgsLayerTreeNode *node );
};
6 changes: 2 additions & 4 deletions python/core/qgsproject.sip
Expand Up @@ -252,10 +252,11 @@ class QgsProject : QObject
bool createEmbeddedLayer( const QString& layerId, const QString& projectFilePath, QList<QDomNode>& brokenNodes,
QList< QPair< QgsVectorLayer*, QDomElement > >& vectorLayerList, bool saveFlag = true );
*/

/** Create layer group instance defined in an arbitrary project file.
* @note: added in version 2.4
*/
QgsLayerTreeGroup* createEmbeddedGroup( const QString& groupName, const QString& projectFilePath );
QgsLayerTreeGroup* createEmbeddedGroup( const QString& groupName, const QString& projectFilePath, const QStringList &invisibleLayers );

/** Convenience function to set snap settings per layer */
void setSnapSettingsForLayer( const QString& layerId, bool enabled, QgsSnapper::SnappingType type, QgsTolerance::UnitType unit, double tolerance,
Expand Down Expand Up @@ -305,9 +306,6 @@ class QgsProject : QObject
//! @note not available in python bindings
// void loadEmbeddedNodes( QgsLayerTreeGroup* group );

//! @note not available in python bindings
// void updateEmbeddedGroupsProjectPath( QgsLayerTreeGroup* group );

signals:
//! emitted when project is being read
void readProject( const QDomDocument & );
Expand Down
4 changes: 2 additions & 2 deletions src/app/qgisapp.cpp
Expand Up @@ -7958,7 +7958,7 @@ void QgisApp::embedLayers()
QStringList::const_iterator groupIt = groups.constBegin();
for ( ; groupIt != groups.constEnd(); ++groupIt )
{
QgsLayerTreeGroup* newGroup = QgsProject::instance()->createEmbeddedGroup( *groupIt, projectFile );
QgsLayerTreeGroup* newGroup = QgsProject::instance()->createEmbeddedGroup( *groupIt, projectFile, QStringList() );

if ( newGroup )
QgsProject::instance()->layerTreeRoot()->addChildNode( newGroup );
Expand Down Expand Up @@ -9935,7 +9935,7 @@ void QgisApp::writeProject( QDomDocument &doc )
// can be opened in older versions of QGIS without loosing information about layer groups.

QgsLayerTreeNode* clonedRoot = QgsProject::instance()->layerTreeRoot()->clone();
QgsLayerTreeUtils::removeChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( clonedRoot ) );
QgsLayerTreeUtils::replaceChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( clonedRoot ) );
QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath( QgsLayerTree::toGroup( clonedRoot ) ); // convert absolute paths to relative paths if required
QDomElement oldLegendElem = QgsLayerTreeUtils::writeOldLegend( doc, QgsLayerTree::toGroup( clonedRoot ),
mLayerTreeCanvasBridge->hasCustomLayerOrder(), mLayerTreeCanvasBridge->customLayerOrder() );
Expand Down
31 changes: 29 additions & 2 deletions src/core/layertree/qgslayertreeutils.cpp
Expand Up @@ -304,16 +304,43 @@ void QgsLayerTreeUtils::removeInvalidLayers( QgsLayerTreeGroup* group )
group->removeChildNode( node );
}

void QgsLayerTreeUtils::removeChildrenOfEmbeddedGroups( QgsLayerTreeGroup* group )
QStringList QgsLayerTreeUtils::invisibleLayerList( QgsLayerTreeNode *node )
{
QStringList list;

if ( QgsLayerTree::isGroup( node ) )
{
foreach ( QgsLayerTreeNode *child, QgsLayerTree::toGroup( node )->children() )
{
list << invisibleLayerList( child );
}
}
else if ( QgsLayerTree::isLayer( node ) )
{
QgsLayerTreeLayer *layer = QgsLayerTree::toLayer( node );

if ( !layer->isVisible() )
list << layer->layerId();
}

return list;
}

void QgsLayerTreeUtils::replaceChildrenOfEmbeddedGroups( QgsLayerTreeGroup* group )
{
foreach ( QgsLayerTreeNode* child, group->children() )
{
if ( QgsLayerTree::isGroup( child ) )
{
if ( child->customProperty( "embedded" ).toInt() )
{
child->setCustomProperty( "embedded-invisible-layers", invisibleLayerList( child ) );
QgsLayerTree::toGroup( child )->removeAllChildren();
}
else
removeChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( child ) );
{
replaceChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( child ) );
}
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions src/core/layertree/qgslayertreeutils.h
Expand Up @@ -23,6 +23,7 @@ class QDomElement;
class QDomDocument;
class QStringList;

class QgsLayerTreeNode;
class QgsLayerTreeGroup;
class QgsLayerTreeLayer;

Expand Down Expand Up @@ -55,12 +56,14 @@ class CORE_EXPORT QgsLayerTreeUtils
//! Remove layer nodes that refer to invalid layers
static void removeInvalidLayers( QgsLayerTreeGroup* group );

//! Remove subtree of embedded groups. Useful when saving layer tree
static void removeChildrenOfEmbeddedGroups( QgsLayerTreeGroup* group );
//! Remove subtree of embedded groups and replaces it with a custom property embedded-visible-layers
static void replaceChildrenOfEmbeddedGroups( QgsLayerTreeGroup* group );

//! @note not available in python bindings
static void updateEmbeddedGroupsProjectPath( QgsLayerTreeGroup* group );

//! get invisible layers
static QStringList invisibleLayerList( QgsLayerTreeNode *node );
};

#endif // QGSLAYERTREEUTILS_H
34 changes: 31 additions & 3 deletions src/core/qgsobjectcustomproperties.cpp
Expand Up @@ -88,8 +88,24 @@ void QgsObjectCustomProperties::readXml( const QDomNode& parentNode, const QStri
QString key = propElement.attribute( "key" );
if ( key.isEmpty() || key.startsWith( keyStartsWith ) )
{
QString value = propElement.attribute( "value" );
mMap[key] = QVariant( value );
if ( propElement.hasAttribute( "value" ) )
{
QString value = propElement.attribute( "value" );
mMap[key] = QVariant( value );
}
else
{
QStringList list;

for ( QDomElement itemElement = propElement.firstChildElement( "value" );
!itemElement.isNull();
itemElement = itemElement.nextSiblingElement( "value" ) )
{
list << itemElement.text();
}

mMap[key] = QVariant( list );
}
}
}

Expand All @@ -110,7 +126,19 @@ void QgsObjectCustomProperties::writeXml( QDomNode& parentNode, QDomDocument& do
{
QDomElement propElement = doc.createElement( "property" );
propElement.setAttribute( "key", it.key() );
propElement.setAttribute( "value", it.value().toString() );
if ( it.value().canConvert<QString>() )
{
propElement.setAttribute( "value", it.value().toString() );
}
else if ( it.value().canConvert<QStringList>() )
{
foreach ( QString value, it.value().toStringList() )
{
QDomElement itemElement = doc.createElement( "value" );
itemElement.appendChild( doc.createTextNode( value ) );
propElement.appendChild( itemElement );
}
}
propsElement.appendChild( propElement );
}

Expand Down
12 changes: 9 additions & 3 deletions src/core/qgsproject.cpp
Expand Up @@ -974,7 +974,7 @@ void QgsProject::loadEmbeddedNodes( QgsLayerTreeGroup* group )
QString projectPath = readPath( childGroup->customProperty( "embedded_project" ).toString() );
childGroup->setCustomProperty( "embedded_project", projectPath );

QgsLayerTreeGroup* newGroup = createEmbeddedGroup( childGroup->name(), projectPath );
QgsLayerTreeGroup* newGroup = createEmbeddedGroup( childGroup->name(), projectPath, childGroup->customProperty( "embedded-invisible-layers" ).toStringList() );
if ( newGroup )
{
QList<QgsLayerTreeNode*> clonedChildren;
Expand Down Expand Up @@ -1083,7 +1083,7 @@ bool QgsProject::write()

// write layer tree - make sure it is without embedded subgroups
QgsLayerTreeNode* clonedRoot = mRootGroup->clone();
QgsLayerTreeUtils::removeChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( clonedRoot ) );
QgsLayerTreeUtils::replaceChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( clonedRoot ) );
QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath( QgsLayerTree::toGroup( clonedRoot ) ); // convert absolute paths to relative paths if required
clonedRoot->writeXML( qgisNode );
delete clonedRoot;
Expand Down Expand Up @@ -1794,7 +1794,7 @@ bool QgsProject::createEmbeddedLayer( const QString& layerId, const QString& pro
}


QgsLayerTreeGroup* QgsProject::createEmbeddedGroup( const QString& groupName, const QString& projectFilePath )
QgsLayerTreeGroup* QgsProject::createEmbeddedGroup( const QString& groupName, const QString& projectFilePath, const QStringList &invisibleLayers )
{
//open project file, get layer ids in group, add the layers
QFile projectFile( projectFilePath );
Expand Down Expand Up @@ -1863,6 +1863,12 @@ QgsLayerTreeGroup* QgsProject::createEmbeddedGroup( const QString& groupName, co
thisProjectIdentifyDisabledLayers.append( layerId );
QgsProject::instance()->writeEntry( "Identify", "/disabledLayers", thisProjectIdentifyDisabledLayers );
}

QgsLayerTreeLayer *layer = newGroup->findLayer( layerId );
if ( layer )
{
layer->setVisible( invisibleLayers.contains( layerId ) ? Qt::Unchecked : Qt::Checked );
}
}

return newGroup;
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsproject.h
Expand Up @@ -299,7 +299,7 @@ class CORE_EXPORT QgsProject : public QObject
/** Create layer group instance defined in an arbitrary project file.
* @note: added in version 2.4
*/
QgsLayerTreeGroup* createEmbeddedGroup( const QString& groupName, const QString& projectFilePath );
QgsLayerTreeGroup* createEmbeddedGroup( const QString& groupName, const QString& projectFilePath, const QStringList &invisibleLayers );

/** Convenience function to set snap settings per layer */
void setSnapSettingsForLayer( const QString& layerId, bool enabled, QgsSnapper::SnappingType type, QgsTolerance::UnitType unit, double tolerance,
Expand Down

0 comments on commit b49da36

Please sign in to comment.