Skip to content

Commit

Permalink
[layertree] Fix #10347 - save also old <legend> tag
Browse files Browse the repository at this point in the history
QGIS server does not use QgsProject for loading of QGIS project.
In order to allow reading of new projects, let's also write the original <legend> tag to the project.
Ideally the server should be ported to new layer tree implementation, but that requires
non-trivial changes to the server components.
The <legend> tag is ignored by QGIS application in >= 2.4 and this way also the new project files
can be opened in older versions of QGIS without loosing information about layer groups.
  • Loading branch information
wonder-sk committed May 27, 2014
1 parent bba9a99 commit 2df8f8c
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 19 deletions.
14 changes: 14 additions & 0 deletions src/app/qgisapp.cpp
Expand Up @@ -9546,6 +9546,20 @@ void QgisApp::projectChanged( const QDomDocument &doc )

void QgisApp::writeProject( QDomDocument &doc )
{
// QGIS server does not use QgsProject for loading of QGIS project.
// In order to allow reading of new projects, let's also write the original <legend> tag to the project.
// Ideally the server should be ported to new layer tree implementation, but that requires
// non-trivial changes to the server components.
// The <legend> tag is ignored by QGIS application in >= 2.4 and this way also the new project files
// 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 ) );
QDomElement oldLegendElem = QgsLayerTreeUtils::writeOldLegend( doc, QgsLayerTree::toGroup( clonedRoot ),
mLayerTreeCanvasBridge->hasCustomLayerOrder(), mLayerTreeCanvasBridge->customLayerOrder() );
delete clonedRoot;
doc.firstChildElement( "qgis" ).appendChild( oldLegendElem );

projectChanged( doc );
}

Expand Down
87 changes: 87 additions & 0 deletions src/core/layertree/qgslayertreeutils.cpp
Expand Up @@ -99,6 +99,79 @@ bool QgsLayerTreeUtils::readOldLegendLayerOrder( const QDomElement& legendElem,
}


static QDomElement _writeOldLegendLayer( QDomDocument& doc, QgsLayerTreeLayer* nodeLayer, bool hasCustomOrder, const QStringList& order )
{
int drawingOrder = -1;
if ( hasCustomOrder )
drawingOrder = order.indexOf( nodeLayer->layerId() );

QDomElement layerElem = doc.createElement( "legendlayer" );
layerElem.setAttribute( "drawingOrder", drawingOrder );
layerElem.setAttribute( "open", nodeLayer->isExpanded() ? "true" : "false" );
layerElem.setAttribute( "checked", QgsLayerTreeUtils::checkStateToXml( nodeLayer->isVisible() ) );
layerElem.setAttribute( "name", nodeLayer->layerName() );
layerElem.setAttribute( "showFeatureCount", nodeLayer->customProperty( "showFeatureCount" ).toInt() );

QDomElement fileGroupElem = doc.createElement( "filegroup" );
fileGroupElem.setAttribute( "open", nodeLayer->isExpanded() ? "true" : "false" );
fileGroupElem.setAttribute( "hidden", "false" );

QDomElement layerFileElem = doc.createElement( "legendlayerfile" );
layerFileElem.setAttribute( "isInOverview", nodeLayer->customProperty( "overview" ).toInt() );
layerFileElem.setAttribute( "layerid", nodeLayer->layerId() );
layerFileElem.setAttribute( "visible", nodeLayer->isVisible() == Qt::Checked ? 1 : 0 );

layerElem.appendChild( fileGroupElem );
fileGroupElem.appendChild( layerFileElem );
return layerElem;
}

// need forward declaration as write[..]Group and write[..]GroupChildren call each other
static void _writeOldLegendGroupChildren( QDomDocument& doc, QDomElement& groupElem, QgsLayerTreeGroup* nodeGroup, bool hasCustomOrder, const QStringList& order );

static QDomElement _writeOldLegendGroup( QDomDocument& doc, QgsLayerTreeGroup* nodeGroup, bool hasCustomOrder, const QStringList& order )
{
QDomElement groupElem = doc.createElement( "legendgroup" );
groupElem.setAttribute( "open", nodeGroup->isExpanded() ? "true" : "false" );
groupElem.setAttribute( "name", nodeGroup->name() );
groupElem.setAttribute( "checked", QgsLayerTreeUtils::checkStateToXml( nodeGroup->isVisible() ) );

if ( nodeGroup->customProperty( "embedded" ).toInt() )
{
groupElem.setAttribute( "embedded", 1 );
groupElem.setAttribute( "project", nodeGroup->customProperty( "embedded_project" ).toString() );
}

_writeOldLegendGroupChildren( doc, groupElem, nodeGroup, hasCustomOrder, order );
return groupElem;
}


static void _writeOldLegendGroupChildren( QDomDocument& doc, QDomElement& groupElem, QgsLayerTreeGroup* nodeGroup, bool hasCustomOrder, const QStringList& order )
{
foreach ( QgsLayerTreeNode* node, nodeGroup->children() )
{
if ( QgsLayerTree::isGroup( node ) )
{
groupElem.appendChild( _writeOldLegendGroup( doc, QgsLayerTree::toGroup( node ), hasCustomOrder, order ) );
}
else if ( QgsLayerTree::isLayer( node ) )
{
groupElem.appendChild( _writeOldLegendLayer( doc, QgsLayerTree::toLayer( node ), hasCustomOrder, order ) );
}
}
}


QDomElement QgsLayerTreeUtils::writeOldLegend( QDomDocument& doc, QgsLayerTreeGroup* root, bool hasCustomOrder, const QStringList& order )
{
QDomElement legendElem = doc.createElement( "legend" );
legendElem.setAttribute( "updateDrawingOrder", hasCustomOrder ? "false" : "true" );

_writeOldLegendGroupChildren( doc, legendElem, root, hasCustomOrder, order );

return legendElem;
}


QString QgsLayerTreeUtils::checkStateToXml( Qt::CheckState state )
Expand Down Expand Up @@ -223,3 +296,17 @@ void QgsLayerTreeUtils::removeInvalidLayers( QgsLayerTreeGroup* group )
foreach ( QgsLayerTreeNode* node, nodesToRemove )
group->removeChildNode( node );
}

void QgsLayerTreeUtils::removeChildrenOfEmbeddedGroups( QgsLayerTreeGroup* group )
{
foreach ( QgsLayerTreeNode* child, group->children() )
{
if ( QgsLayerTree::isGroup( child ) )
{
if ( child->customProperty( "embedded" ).toInt() )
QgsLayerTree::toGroup( child )->removeAllChildren();
else
removeChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( child ) );
}
}
}
7 changes: 6 additions & 1 deletion src/core/layertree/qgslayertreeutils.h
Expand Up @@ -20,6 +20,7 @@
#include <QList>

class QDomElement;
class QDomDocument;
class QStringList;

class QgsLayerTreeGroup;
Expand All @@ -38,14 +39,18 @@ class CORE_EXPORT QgsLayerTreeUtils
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
static bool readOldLegendLayerOrder( const QDomElement& legendElem, bool& hasCustomOrder, QStringList& order );
//! Return <legend> tag used in QGIS 2.2 and below
static QDomElement writeOldLegend( QDomDocument& doc, QgsLayerTreeGroup* root, bool hasCustomOrder, const QStringList& order );

static QString checkStateToXml( Qt::CheckState state );
static Qt::CheckState checkStateFromXml( QString txt );

static bool layersEditable( const QList<QgsLayerTreeLayer*>& layerNodes );
static bool layersModified( const QList<QgsLayerTreeLayer*>& layerNodes );

static void removeInvalidLayers(QgsLayerTreeGroup* group );
static void removeInvalidLayers( QgsLayerTreeGroup* group );

static void removeChildrenOfEmbeddedGroups( QgsLayerTreeGroup* group );

protected:
static void addLegendGroupToTreeWidget( const QDomElement& groupElem, QgsLayerTreeGroup* parent );
Expand Down
17 changes: 1 addition & 16 deletions src/core/qgsproject.cpp
Expand Up @@ -995,21 +995,6 @@ void QgsProject::loadEmbeddedNodes( QgsLayerTreeGroup* group )
}
}

void QgsProject::removeChildrenOfEmbeddedGroups( QgsLayerTreeGroup* group )
{
foreach ( QgsLayerTreeNode* child, group->children() )
{
if ( QgsLayerTree::isGroup( child ) )
{
if ( child->customProperty( "embedded" ).toInt() )
QgsLayerTree::toGroup( child )->removeAllChildren();
else
removeChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( child ) );
}
}
}



bool QgsProject::read( QDomNode & layerNode )
{
Expand Down Expand Up @@ -1090,7 +1075,7 @@ bool QgsProject::write()

// write layer tree - make sure it is without embedded subgroups
QgsLayerTreeNode* clonedRoot = mRootGroup->clone();
removeChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( clonedRoot ) );
QgsLayerTreeUtils::removeChildrenOfEmbeddedGroups( QgsLayerTree::toGroup( clonedRoot ) );
clonedRoot->writeXML( qgisNode );
delete clonedRoot;

Expand Down
2 changes: 0 additions & 2 deletions src/core/qgsproject.h
Expand Up @@ -357,8 +357,6 @@ class CORE_EXPORT QgsProject : public QObject

void loadEmbeddedNodes( QgsLayerTreeGroup* group );

void removeChildrenOfEmbeddedGroups( QgsLayerTreeGroup* group );

signals:
//! emitted when project is being read
void readProject( const QDomDocument & );
Expand Down

0 comments on commit 2df8f8c

Please sign in to comment.