Skip to content

Commit b49da36

Browse files
committed
* Save and restore visiblity state of embedded group layers (fixes #4097)
* Adds support for lists in custom properties
1 parent 3711fd5 commit b49da36

File tree

8 files changed

+87
-22
lines changed

8 files changed

+87
-22
lines changed

python/core/layertree/qgslayertreeutils.sip

+8-5
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ class QgsLayerTreeUtils
1111

1212
public:
1313

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

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

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

37+
38+
//! get invisible layers
39+
static QStringList invisibleLayerList( QgsLayerTreeNode *node );
3740
};

python/core/qgsproject.sip

+2-4
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,11 @@ class QgsProject : QObject
252252
bool createEmbeddedLayer( const QString& layerId, const QString& projectFilePath, QList<QDomNode>& brokenNodes,
253253
QList< QPair< QgsVectorLayer*, QDomElement > >& vectorLayerList, bool saveFlag = true );
254254
*/
255+
255256
/** Create layer group instance defined in an arbitrary project file.
256257
* @note: added in version 2.4
257258
*/
258-
QgsLayerTreeGroup* createEmbeddedGroup( const QString& groupName, const QString& projectFilePath );
259+
QgsLayerTreeGroup* createEmbeddedGroup( const QString& groupName, const QString& projectFilePath, const QStringList &invisibleLayers );
259260

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

308-
//! @note not available in python bindings
309-
// void updateEmbeddedGroupsProjectPath( QgsLayerTreeGroup* group );
310-
311309
signals:
312310
//! emitted when project is being read
313311
void readProject( const QDomDocument & );

src/app/qgisapp.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -7958,7 +7958,7 @@ void QgisApp::embedLayers()
79587958
QStringList::const_iterator groupIt = groups.constBegin();
79597959
for ( ; groupIt != groups.constEnd(); ++groupIt )
79607960
{
7961-
QgsLayerTreeGroup* newGroup = QgsProject::instance()->createEmbeddedGroup( *groupIt, projectFile );
7961+
QgsLayerTreeGroup* newGroup = QgsProject::instance()->createEmbeddedGroup( *groupIt, projectFile, QStringList() );
79627962

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

99379937
QgsLayerTreeNode* clonedRoot = QgsProject::instance()->layerTreeRoot()->clone();
9938-
QgsLayerTreeUtils::removeChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( clonedRoot ) );
9938+
QgsLayerTreeUtils::replaceChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( clonedRoot ) );
99399939
QgsLayerTreeUtils::updateEmbeddedGroupsProjectPath( QgsLayerTree::toGroup( clonedRoot ) ); // convert absolute paths to relative paths if required
99409940
QDomElement oldLegendElem = QgsLayerTreeUtils::writeOldLegend( doc, QgsLayerTree::toGroup( clonedRoot ),
99419941
mLayerTreeCanvasBridge->hasCustomLayerOrder(), mLayerTreeCanvasBridge->customLayerOrder() );

src/core/layertree/qgslayertreeutils.cpp

+29-2
Original file line numberDiff line numberDiff line change
@@ -304,16 +304,43 @@ void QgsLayerTreeUtils::removeInvalidLayers( QgsLayerTreeGroup* group )
304304
group->removeChildNode( node );
305305
}
306306

307-
void QgsLayerTreeUtils::removeChildrenOfEmbeddedGroups( QgsLayerTreeGroup* group )
307+
QStringList QgsLayerTreeUtils::invisibleLayerList( QgsLayerTreeNode *node )
308+
{
309+
QStringList list;
310+
311+
if ( QgsLayerTree::isGroup( node ) )
312+
{
313+
foreach ( QgsLayerTreeNode *child, QgsLayerTree::toGroup( node )->children() )
314+
{
315+
list << invisibleLayerList( child );
316+
}
317+
}
318+
else if ( QgsLayerTree::isLayer( node ) )
319+
{
320+
QgsLayerTreeLayer *layer = QgsLayerTree::toLayer( node );
321+
322+
if ( !layer->isVisible() )
323+
list << layer->layerId();
324+
}
325+
326+
return list;
327+
}
328+
329+
void QgsLayerTreeUtils::replaceChildrenOfEmbeddedGroups( QgsLayerTreeGroup* group )
308330
{
309331
foreach ( QgsLayerTreeNode* child, group->children() )
310332
{
311333
if ( QgsLayerTree::isGroup( child ) )
312334
{
313335
if ( child->customProperty( "embedded" ).toInt() )
336+
{
337+
child->setCustomProperty( "embedded-invisible-layers", invisibleLayerList( child ) );
314338
QgsLayerTree::toGroup( child )->removeAllChildren();
339+
}
315340
else
316-
removeChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( child ) );
341+
{
342+
replaceChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( child ) );
343+
}
317344
}
318345
}
319346
}

src/core/layertree/qgslayertreeutils.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class QDomElement;
2323
class QDomDocument;
2424
class QStringList;
2525

26+
class QgsLayerTreeNode;
2627
class QgsLayerTreeGroup;
2728
class QgsLayerTreeLayer;
2829

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

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

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

65+
//! get invisible layers
66+
static QStringList invisibleLayerList( QgsLayerTreeNode *node );
6467
};
6568

6669
#endif // QGSLAYERTREEUTILS_H

src/core/qgsobjectcustomproperties.cpp

+31-3
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,24 @@ void QgsObjectCustomProperties::readXml( const QDomNode& parentNode, const QStri
8888
QString key = propElement.attribute( "key" );
8989
if ( key.isEmpty() || key.startsWith( keyStartsWith ) )
9090
{
91-
QString value = propElement.attribute( "value" );
92-
mMap[key] = QVariant( value );
91+
if ( propElement.hasAttribute( "value" ) )
92+
{
93+
QString value = propElement.attribute( "value" );
94+
mMap[key] = QVariant( value );
95+
}
96+
else
97+
{
98+
QStringList list;
99+
100+
for ( QDomElement itemElement = propElement.firstChildElement( "value" );
101+
!itemElement.isNull();
102+
itemElement = itemElement.nextSiblingElement( "value" ) )
103+
{
104+
list << itemElement.text();
105+
}
106+
107+
mMap[key] = QVariant( list );
108+
}
93109
}
94110
}
95111

@@ -110,7 +126,19 @@ void QgsObjectCustomProperties::writeXml( QDomNode& parentNode, QDomDocument& do
110126
{
111127
QDomElement propElement = doc.createElement( "property" );
112128
propElement.setAttribute( "key", it.key() );
113-
propElement.setAttribute( "value", it.value().toString() );
129+
if ( it.value().canConvert<QString>() )
130+
{
131+
propElement.setAttribute( "value", it.value().toString() );
132+
}
133+
else if ( it.value().canConvert<QStringList>() )
134+
{
135+
foreach ( QString value, it.value().toStringList() )
136+
{
137+
QDomElement itemElement = doc.createElement( "value" );
138+
itemElement.appendChild( doc.createTextNode( value ) );
139+
propElement.appendChild( itemElement );
140+
}
141+
}
114142
propsElement.appendChild( propElement );
115143
}
116144

src/core/qgsproject.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,7 @@ void QgsProject::loadEmbeddedNodes( QgsLayerTreeGroup* group )
974974
QString projectPath = readPath( childGroup->customProperty( "embedded_project" ).toString() );
975975
childGroup->setCustomProperty( "embedded_project", projectPath );
976976

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

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

17961796

1797-
QgsLayerTreeGroup* QgsProject::createEmbeddedGroup( const QString& groupName, const QString& projectFilePath )
1797+
QgsLayerTreeGroup* QgsProject::createEmbeddedGroup( const QString& groupName, const QString& projectFilePath, const QStringList &invisibleLayers )
17981798
{
17991799
//open project file, get layer ids in group, add the layers
18001800
QFile projectFile( projectFilePath );
@@ -1863,6 +1863,12 @@ QgsLayerTreeGroup* QgsProject::createEmbeddedGroup( const QString& groupName, co
18631863
thisProjectIdentifyDisabledLayers.append( layerId );
18641864
QgsProject::instance()->writeEntry( "Identify", "/disabledLayers", thisProjectIdentifyDisabledLayers );
18651865
}
1866+
1867+
QgsLayerTreeLayer *layer = newGroup->findLayer( layerId );
1868+
if ( layer )
1869+
{
1870+
layer->setVisible( invisibleLayers.contains( layerId ) ? Qt::Unchecked : Qt::Checked );
1871+
}
18661872
}
18671873

18681874
return newGroup;

src/core/qgsproject.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ class CORE_EXPORT QgsProject : public QObject
299299
/** Create layer group instance defined in an arbitrary project file.
300300
* @note: added in version 2.4
301301
*/
302-
QgsLayerTreeGroup* createEmbeddedGroup( const QString& groupName, const QString& projectFilePath );
302+
QgsLayerTreeGroup* createEmbeddedGroup( const QString& groupName, const QString& projectFilePath, const QStringList &invisibleLayers );
303303

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

0 commit comments

Comments
 (0)