Serialize atlas settings

This commit is contained in:
Nyall Dawson 2017-12-19 15:31:15 +10:00
parent 83af35275e
commit f86c2988bb
10 changed files with 220 additions and 10 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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 );
};
/************************************************************************

View File

@ -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.

View File

@ -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 )

View File

@ -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:

View File

@ -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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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()