Skip to content
Permalink
Browse files

Serialize atlas settings

  • Loading branch information
nyalldawson committed Dec 19, 2017
1 parent 83af352 commit f86c2988bb16ea5ba0ce197c90416b5e332e728f
@@ -500,14 +500,14 @@ If ``ok`` is specified, it will be set to true if the load was successful.
Returns a list of loaded items.
%End

QDomElement writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const;
virtual QDomElement writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const;
%Docstring
Returns the layout's state encapsulated in a DOM element.

.. seealso:: :py:func:`readXml()`
%End

bool readXml( const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context );
virtual bool readXml( const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context );
%Docstring
Sets the collection's state from a DOM element. ``layoutElement`` is the DOM node corresponding to the layout.

@@ -8,7 +8,7 @@



class QgsLayoutAtlas : QObject
class QgsLayoutAtlas : QObject, QgsLayoutSerializableObject
{
%Docstring
Class used to render an Atlas, iterating over geometry features.
@@ -34,6 +34,15 @@ QgsLayoutAtlas which is automatically created and attached to the composition.
Constructor for new QgsLayoutAtlas.
%End

virtual QString stringType() const;

virtual QgsLayout *layout();

virtual bool writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const;

virtual bool readXml( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );


bool enabled() const;
%Docstring
Returns whether the atlas generation is enabled
@@ -72,7 +81,7 @@ atlas page.
.. seealso:: :py:func:`filenameExpressionErrorString()`
%End

bool setFilenameExpression( const QString &expression, QString &errorString );
bool setFilenameExpression( const QString &expression, QString &errorString /Out/ );
%Docstring
Sets the filename ``expression`` used for generating output filenames for each
atlas page.
@@ -222,7 +231,7 @@ This property has no effect is filterFeatures() is false.
.. seealso:: :py:func:`filterFeatures()`
%End

bool setFilterExpression( const QString &expression, QString &errorString );
bool setFilterExpression( const QString &expression, QString &errorString /Out/ );
%Docstring
Sets the ``expression`` used for filtering features in the coverage layer.

@@ -31,6 +31,11 @@ Constructor for QgsPrintLayout.
Returns the print layout's atlas.
%End

virtual QDomElement writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const;

virtual bool readXml( const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context );


};

/************************************************************************
@@ -514,13 +514,13 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
* Returns the layout's state encapsulated in a DOM element.
* \see readXml()
*/
QDomElement writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const;
virtual QDomElement writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const;

/**
* Sets the collection's state from a DOM element. \a layoutElement is the DOM node corresponding to the layout.
* \see writeXml()
*/
bool readXml( const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context );
virtual bool readXml( const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context );

/**
* Add items from an XML representation to the layout. Used for project file reading and pasting items from clipboard.
@@ -31,6 +31,84 @@ QgsLayoutAtlas::QgsLayoutAtlas( QgsLayout *layout )
connect( mLayout->project(), static_cast < void ( QgsProject::* )( const QStringList & ) >( &QgsProject::layersWillBeRemoved ), this, &QgsLayoutAtlas::removeLayers );
}

QString QgsLayoutAtlas::stringType() const
{
return QStringLiteral( "atlas" );
}

QgsLayout *QgsLayoutAtlas::layout()
{
return mLayout;
}

bool QgsLayoutAtlas::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext & ) const
{
QDomElement atlasElem = document.createElement( QStringLiteral( "Atlas" ) );
atlasElem.setAttribute( QStringLiteral( "enabled" ), mEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );

if ( mCoverageLayer )
{
atlasElem.setAttribute( QStringLiteral( "coverageLayer" ), mCoverageLayer.layerId );
atlasElem.setAttribute( QStringLiteral( "coverageLayerName" ), mCoverageLayer.name );
atlasElem.setAttribute( QStringLiteral( "coverageLayerSource" ), mCoverageLayer.source );
atlasElem.setAttribute( QStringLiteral( "coverageLayerProvider" ), mCoverageLayer.provider );
}
else
{
atlasElem.setAttribute( QStringLiteral( "coverageLayer" ), QString() );
}

atlasElem.setAttribute( QStringLiteral( "hideCoverage" ), mHideCoverage ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
atlasElem.setAttribute( QStringLiteral( "filenamePattern" ), mFilenameExpressionString );
atlasElem.setAttribute( QStringLiteral( "pageNameExpression" ), mPageNameExpression );

atlasElem.setAttribute( QStringLiteral( "sortFeatures" ), mSortFeatures ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
if ( mSortFeatures )
{
atlasElem.setAttribute( QStringLiteral( "sortKey" ), mSortExpression );
atlasElem.setAttribute( QStringLiteral( "sortAscending" ), mSortAscending ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
}
atlasElem.setAttribute( QStringLiteral( "filterFeatures" ), mFilterFeatures ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
if ( mFilterFeatures )
{
atlasElem.setAttribute( QStringLiteral( "featureFilter" ), mFilterExpression );
}

parentElement.appendChild( atlasElem );

return true;
}

bool QgsLayoutAtlas::readXml( const QDomElement &atlasElem, const QDomDocument &, const QgsReadWriteContext & )
{
mEnabled = atlasElem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt();

// look for stored layer name
QString layerId = atlasElem.attribute( QStringLiteral( "coverageLayer" ) );
QString layerName = atlasElem.attribute( QStringLiteral( "coverageLayerName" ) );
QString layerSource = atlasElem.attribute( QStringLiteral( "coverageLayerSource" ) );
QString layerProvider = atlasElem.attribute( QStringLiteral( "coverageLayerProvider" ) );

mCoverageLayer = QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
mCoverageLayer.resolveWeakly( mLayout->project() );

mPageNameExpression = atlasElem.attribute( QStringLiteral( "pageNameExpression" ), QString() );
QString error;
setFilenameExpression( atlasElem.attribute( QStringLiteral( "filenamePattern" ), QString() ), error );

mSortFeatures = atlasElem.attribute( QStringLiteral( "sortFeatures" ), QStringLiteral( "0" ) ).toInt();
mSortExpression = atlasElem.attribute( QStringLiteral( "sortKey" ) );
mSortAscending = atlasElem.attribute( QStringLiteral( "sortAscending" ), QStringLiteral( "1" ) ).toInt();
mFilterFeatures = atlasElem.attribute( QStringLiteral( "filterFeatures" ), QStringLiteral( "0" ) ).toInt();
mFilterExpression = atlasElem.attribute( QStringLiteral( "featureFilter" ) );

mHideCoverage = atlasElem.attribute( QStringLiteral( "hideCoverage" ), QStringLiteral( "0" ) ).toInt();

emit toggled( mEnabled );
emit changed();
return true;
}

void QgsLayoutAtlas::setEnabled( bool enabled )
{
if ( enabled == mEnabled )
@@ -18,6 +18,7 @@

#include "qgis_core.h"
#include "qgsvectorlayerref.h"
#include "qgslayoutserializableobject.h"
#include <QObject>

class QgsLayout;
@@ -32,7 +33,7 @@ class QgsLayout;
* QgsLayoutAtlas which is automatically created and attached to the composition.
* \since QGIS 3.0
*/
class CORE_EXPORT QgsLayoutAtlas : public QObject
class CORE_EXPORT QgsLayoutAtlas : public QObject, public QgsLayoutSerializableObject
{
Q_OBJECT
public:
@@ -42,6 +43,11 @@ class CORE_EXPORT QgsLayoutAtlas : public QObject
*/
QgsLayoutAtlas( QgsLayout *layout SIP_TRANSFERTHIS );

QString stringType() const override;
QgsLayout *layout() override;
bool writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const override;
bool readXml( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context ) override;

/**
* Returns whether the atlas generation is enabled
* \see setEnabled()
@@ -81,7 +87,7 @@ class CORE_EXPORT QgsLayoutAtlas : public QObject
* will be set to the expression error.
* \see filenameExpression()
*/
bool setFilenameExpression( const QString &expression, QString &errorString );
bool setFilenameExpression( const QString &expression, QString &errorString SIP_OUT );

/**
* Returns the coverage layer used for the atlas features.
@@ -209,7 +215,7 @@ class CORE_EXPORT QgsLayoutAtlas : public QObject
* \see filterExpression()
* \see setFilterFeatures()
*/
bool setFilterExpression( const QString &expression, QString &errorString );
bool setFilterExpression( const QString &expression, QString &errorString SIP_OUT );

public slots:

@@ -27,3 +27,20 @@ QgsLayoutAtlas *QgsPrintLayout::atlas()
{
return mAtlas;
}

QDomElement QgsPrintLayout::writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const
{
QDomElement layoutElem = QgsLayout::writeXml( document, context );
mAtlas->writeXml( layoutElem, document, context );
return layoutElem;
}

bool QgsPrintLayout::readXml( const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context )
{
if ( !QgsLayout::readXml( layoutElement, document, context ) )
return false;

QDomElement atlasElem = layoutElement.firstChildElement( QStringLiteral( "Atlas" ) );
mAtlas->readXml( atlasElem, document, context );
return true;
}
@@ -43,6 +43,9 @@ class CORE_EXPORT QgsPrintLayout : public QgsLayout
*/
QgsLayoutAtlas *atlas();

QDomElement writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const override;
bool readXml( const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context ) override;

private:

QgsLayoutAtlas *mAtlas = nullptr;
@@ -84,6 +84,7 @@ ADD_PYTHON_TEST(PyQgsLayerTreeMapCanvasBridge test_qgslayertreemapcanvasbridge.p
ADD_PYTHON_TEST(PyQgsLayerTree test_qgslayertree.py)
ADD_PYTHON_TEST(PyQgsLayout test_qgslayout.py)
ADD_PYTHON_TEST(PyQgsLayoutAlign test_qgslayoutaligner.py)
ADD_PYTHON_TEST(PyQgsLayoutAtlas test_qgslayoutatlas.py)
ADD_PYTHON_TEST(PyQgsLayoutExporter test_qgslayoutexporter.py)
ADD_PYTHON_TEST(PyQgsLayoutFrame test_qgslayoutframe.py)
ADD_PYTHON_TEST(PyQgsLayoutManager test_qgslayoutmanager.py)
@@ -0,0 +1,91 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsLayoutAtlas
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Nyall Dawson'
__date__ = '19/12/2017'
__copyright__ = 'Copyright 2017, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

import qgis # NOQA
import sip
import tempfile
import shutil
import os

from qgis.core import (QgsUnitTypes,
QgsLayout,
QgsPrintLayout,
QgsLayoutAtlas,
QgsLayoutItemPage,
QgsLayoutGuide,
QgsLayoutObject,
QgsProject,
QgsLayoutItemGroup,
QgsLayoutItem,
QgsProperty,
QgsLayoutPageCollection,
QgsLayoutMeasurement,
QgsFillSymbol,
QgsReadWriteContext,
QgsLayoutItemMap,
QgsLayoutItemLabel,
QgsLayoutSize,
QgsLayoutPoint,
QgsVectorLayer)
from qgis.PyQt.QtCore import QFileInfo
from qgis.PyQt.QtTest import QSignalSpy
from qgis.PyQt.QtXml import QDomDocument
from utilities import unitTestDataPath
from qgis.testing import start_app, unittest

start_app()


class TestQgsLayoutAtlas(unittest.TestCase):

def testReadWriteXml(self):
p = QgsProject()
vectorFileInfo = QFileInfo(unitTestDataPath() + "/france_parts.shp")
vector_layer = QgsVectorLayer(vectorFileInfo.filePath(), vectorFileInfo.completeBaseName(), "ogr")
self.assertTrue(vector_layer.isValid())
p.addMapLayer(vector_layer)

l = QgsPrintLayout(p)
atlas = l.atlas()
atlas.setEnabled(True)
atlas.setHideCoverage(True)
atlas.setFilenameExpression('filename exp')
atlas.setCoverageLayer(vector_layer)
atlas.setPageNameExpression('page name')
atlas.setSortFeatures(True)
atlas.setSortAscending(False)
atlas.setSortExpression('sort exp')
atlas.setFilterFeatures(True)
atlas.setFilterExpression('filter exp')

doc = QDomDocument("testdoc")
elem = l.writeXml(doc, QgsReadWriteContext())

l2 = QgsPrintLayout(p)
self.assertTrue(l2.readXml(elem, doc, QgsReadWriteContext()))
atlas2 = l2.atlas()
self.assertTrue(atlas2.enabled())
self.assertTrue(atlas2.hideCoverage())
self.assertEqual(atlas2.filenameExpression(), 'filename exp')
self.assertEqual(atlas2.coverageLayer(), vector_layer)
self.assertEqual(atlas2.pageNameExpression(), 'page name')
self.assertTrue(atlas2.sortFeatures())
self.assertFalse(atlas2.sortAscending())
self.assertEqual(atlas2.sortExpression(), 'sort exp')
self.assertTrue(atlas2.filterFeatures())
self.assertEqual(atlas2.filterExpression(), 'filter exp')


if __name__ == '__main__':
unittest.main()

0 comments on commit f86c298

Please sign in to comment.
You can’t perform that action at this time.