Skip to content

Commit

Permalink
Add group support for QLR files
Browse files Browse the repository at this point in the history
Add class for handling QLR files. Add sip bindings

Funded by Nicholas Duggan
  • Loading branch information
NathanW2 committed Jan 19, 2015
1 parent 2011951 commit 8944ff7
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 17 deletions.
11 changes: 11 additions & 0 deletions python/core/qgslayerdefinition.sip
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class CORE_EXPORT QgsLayerDefinition
{
%TypeHeaderCode
#include <qgslayerdefinition.h>
%End
public:
static bool openLayerDefinition( const QString & path, QgsLayerTreeGroup* rootGroup, QString &errorMessage /Out/ );
static bool openLayerDefinition( QDomDocument doc, QgsLayerTreeGroup* rootGroup, QString &errorMessage /Out/ );
static bool exportLayerDefinition( QString path, QList<QgsLayerTreeNode*> selectedTreeNodes, QString &errorMessage /Out/ );
};

27 changes: 12 additions & 15 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
#include "qgsgpsinformationwidget.h"
#include "qgsguivectorlayertools.h"
#include "qgslabelinggui.h"
#include "qgslayerdefinition.h"
#include "qgslayertree.h"
#include "qgslayertreemapcanvasbridge.h"
#include "qgslayertreemodel.h"
Expand Down Expand Up @@ -4124,8 +4125,13 @@ void QgisApp::dxfExport()

void QgisApp::openLayerDefinition( const QString & path )
{
QList<QgsMapLayer*> layers = QgsMapLayer::fromLayerDefinitionFile( path );
QgsMapLayerRegistry::instance()->addMapLayers( layers );
QString errorMessage;
bool loaded = QgsLayerDefinition::loadLayerDefinition( path, QgsProject::instance()->layerTreeRoot(), errorMessage );
if ( !loaded )
{
QgsDebugMsg( errorMessage );
messageBar()->pushMessage( tr( "Error loading layer definition" ), errorMessage, QgsMessageBar::WARNING );
}
}

// Open the project file corresponding to the
Expand Down Expand Up @@ -5038,26 +5044,17 @@ void QgisApp::saveAsFile()

void QgisApp::saveAsLayerDefinition()
{
QList<QgsMapLayer*> layers = mLayerTreeView->selectedLayers();

if ( layers.isEmpty() )
return;

QString path = QFileDialog::getSaveFileName( this, "Save as Layer Definition File", QDir::home().path(), "*.qlr" );
QgsDebugMsg( path );
if ( path.isEmpty() )
return;

if ( !path.endsWith( ".qlr" ) )
path = path.append( ".qlr" );

QFile file( path );
QFileInfo fileinfo( file );
QDomDocument doc = QgsMapLayer::asLayerDefinition( layers, fileinfo.canonicalFilePath() );
if ( file.open( QFile::WriteOnly | QFile::Truncate ) )
QString errorMessage;
bool saved = QgsLayerDefinition::exportLayerDefinition( path, mLayerTreeView->selectedNodes(), errorMessage );
if ( !saved )
{
QTextStream qlayerstream( &file );
doc.save( qlayerstream, 2 );
messageBar()->pushMessage( tr( "Error saving layer definintion file" ), errorMessage, QgsMessageBar::WARNING );
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/app/qgsapplayertreeviewmenuprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ QMenu* QgsAppLayerTreeViewMenuProvider::createContextMenu()
if ( mView->selectedNodes( true ).count() >= 2 )
menu->addAction( actions->actionGroupSelected( menu ) );

menu->addAction( tr( "Save As Layer Definition File..." ), QgisApp::instance(), SLOT( saveAsLayerDefinition() ) );

menu->addAction( actions->actionAddGroup( menu ) );
}
else if ( QgsLayerTree::isLayer( node ) )
Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ SET(QGIS_CORE_SRCS
qgsgeometryvalidator.cpp
qgsgml.cpp
qgsgmlschema.cpp
qgslayerdefinition.cpp
qgslabel.cpp
qgslabelattributes.cpp
qgslabelsearchtree.cpp
Expand Down Expand Up @@ -480,6 +481,7 @@ SET(QGIS_CORE_HDRS
qgsfontutils.h
qgsgeometry.h
qgsgeometrycache.h
qgslayerdefinition.h
qgslabel.h
qgslabelattributes.h
qgslabelsearchtree.h
Expand Down
122 changes: 122 additions & 0 deletions src/core/qgslayerdefinition.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#include <QDomNode>
#include <QFileInfo>
#include <QFile>
#include <QDir>
#include <QTextStream>

#include "qgslogger.h"
#include "qgsmaplayer.h"
#include "qgslayertree.h"
#include "qgsmaplayerregistry.h"
#include "qgslayerdefinition.h"

bool QgsLayerDefinition::loadLayerDefinition( const QString &path, QgsLayerTreeGroup *rootGroup, QString &errorMessage )
{
QFile file( path );
if ( !file.open( QIODevice::ReadOnly ) )
{
errorMessage = QString( "Can not open file" );
return false;
}

QDomDocument doc;
QString message;
if ( !doc.setContent( &file, &message ) )
{
errorMessage = message;
return false;
}

QFileInfo fileinfo( file );
QDir::setCurrent( fileinfo.absoluteDir().path() );

return loadLayerDefinition( doc, rootGroup, errorMessage );
}

bool QgsLayerDefinition::loadLayerDefinition( QDomDocument doc, QgsLayerTreeGroup *rootGroup, QString &errorMessage )
{
QgsLayerTreeGroup* root = new QgsLayerTreeGroup;
// We have to replace the IDs before we load them because it's too late once they are loaded
QDomNodeList ids = doc.elementsByTagName( "id" );
for ( int i = 0; i < ids.size(); ++i )
{
QDomNode idnode = ids.at( i );
QDomElement idElem = idnode.toElement();
QString oldid = idElem.text();
// Strip the date part because we will replace it.
QString layername = oldid.left( oldid.length() - 17 );
QDateTime dt = QDateTime::currentDateTime();
QString newid = layername + dt.toString( "yyyyMMddhhmmsszzz" );
idElem.firstChild().setNodeValue( newid );
QDomNodeList treeLayerNodes = doc.elementsByTagName( "layer-tree-layer" );

for ( int i = 0; i < treeLayerNodes.count(); ++i )
{
QDomNode layerNode = treeLayerNodes.at( i );
QDomElement layerElem = layerNode.toElement();
if ( layerElem.attribute( "id" ) == oldid )
{
layerNode.toElement().setAttribute( "id", newid );
}
}
}

QDomElement layerTreeElem = doc.documentElement().firstChildElement( "layer-tree-group" );
bool loadInLegend = true;
if ( !layerTreeElem.isNull() )
{
root->readChildrenFromXML( layerTreeElem );
loadInLegend = false;
}

QList<QgsMapLayer*> layers = QgsMapLayer::fromLayerDefinition( doc );
QgsMapLayerRegistry::instance()->addMapLayers( layers, loadInLegend );

QList<QgsLayerTreeNode*> nodes = root->children();
rootGroup->insertChildNodes( -1, nodes );
return true;

}

bool QgsLayerDefinition::exportLayerDefinition( QString path, QList<QgsLayerTreeNode*> selectedTreeNodes, QString &errorMessage )
{
if ( !path.endsWith( ".qlr" ) )
path = path.append( ".qlr" );

QFile file( path );
QFileInfo fileinfo( file );

QDomDocument doc( "qgis-layer-definition" );
QDomElement qgiselm = doc.createElement( "qlr" );
doc.appendChild( qgiselm );
QList<QgsLayerTreeNode*> nodes = selectedTreeNodes;
QgsLayerTreeGroup* root = new QgsLayerTreeGroup;
foreach ( QgsLayerTreeNode* node, nodes )
{
QgsLayerTreeNode* newnode = node->clone();
root->addChildNode( newnode );
}
root->writeXML( qgiselm );

QDomElement layerselm = doc.createElement( "maplayers" );
QList<QgsLayerTreeLayer*> layers = root->findLayers();
foreach ( QgsLayerTreeLayer* layer, layers )
{
QDomElement layerelm = doc.createElement( "maplayer" );
layer->layer()->writeLayerXML( layerelm, doc, fileinfo.canonicalFilePath() );
layerselm.appendChild( layerelm );
}
qgiselm.appendChild( layerselm );

if ( file.open( QFile::WriteOnly | QFile::Truncate ) )
{
QTextStream qlayerstream( &file );
doc.save( qlayerstream, 2 );
return true;
}
else
{
errorMessage = file.errorString();
return false;
}
}
20 changes: 20 additions & 0 deletions src/core/qgslayerdefinition.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef QGSLAYERDEFINITION_H
#define QGSLAYERDEFINITION_H

#include "qgslayertreegroup.h"

/**
* @brief The QgsLayerDefinition class holds generic methods for loading/exporting QLR files.
*/
class CORE_EXPORT QgsLayerDefinition
{
public:
/* Loads the QLR at path into QGIS. New layers are added to rootGroup and the map layer registry*/
static bool loadLayerDefinition( const QString & path, QgsLayerTreeGroup* rootGroup, QString &errorMessage);
/* Loads the QLR from the XML document. New layers are added to rootGroup and the map layer registry */
static bool loadLayerDefinition( QDomDocument doc, QgsLayerTreeGroup* rootGroup, QString &errorMessage);
/* Export the selected layer tree nodes to a QLR file */
static bool exportLayerDefinition( QString path, QList<QgsLayerTreeNode*> selectedTreeNodes, QString &errorMessage );
};

#endif // QGSLAYERDEFINITION_H
5 changes: 3 additions & 2 deletions src/core/qgsmaplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -617,15 +617,16 @@ bool QgsMapLayer::writeLayerXML( QDomElement& layerElement, QDomDocument& docume
QDomDocument QgsMapLayer::asLayerDefinition( QList<QgsMapLayer *> layers, QString relativeBasePath )
{
QDomDocument doc( "qgis-layer-definition" );
QDomElement qgiselm = doc.createElement( "qlr" );
doc.appendChild( qgiselm );
QDomElement layerselm = doc.createElement( "maplayers" );
foreach ( QgsMapLayer* layer, layers )
{
QDomElement layerelm = doc.createElement( "maplayer" );
layer->writeLayerXML( layerelm, doc, relativeBasePath );
layerelm.removeChild( layerelm.firstChildElement( "id" ) );
layerselm.appendChild( layerelm );
}
doc.appendChild( layerselm );
qgiselm.appendChild( layerselm );
return doc;
}

Expand Down

0 comments on commit 8944ff7

Please sign in to comment.