Skip to content

Commit

Permalink
Add API to save/restore QgsLayoutObject properties to XML
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jul 25, 2017
1 parent f121286 commit 09dd6db
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 0 deletions.
20 changes: 20 additions & 0 deletions python/core/layout/qgslayoutobject.sip
Expand Up @@ -168,6 +168,26 @@ class QgsLayoutObject: QObject, QgsExpressionContextGenerator

protected:

bool writeObjectPropertiesToElement( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const;
%Docstring
Stores object properties within an XML DOM element.
\param parentElement is the parent DOM element to store the object's properties in
\param document DOM document
:return: true if write was successful
.. seealso:: readObjectPropertiesFromElement()
:rtype: bool
%End

bool readObjectPropertiesFromElement( const QDomElement &parentElement, const QDomDocument &document, const QgsReadWriteContext &context );
%Docstring
Sets object properties from a DOM element
\param parentElement is the parent DOM element for the object
\param document DOM document
:return: true if read was successful
.. seealso:: writeObjectPropertiesToElement()
:rtype: bool
%End




Expand Down
48 changes: 48 additions & 0 deletions src/core/layout/qgslayoutobject.cpp
Expand Up @@ -122,3 +122,51 @@ QgsExpressionContext QgsLayoutObject::createExpressionContext() const
return QgsExpressionContext() << QgsExpressionContextUtils::globalScope();
}
}

bool QgsLayoutObject::writeObjectPropertiesToElement( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext & ) const
{
if ( parentElement.isNull() )
{
return false;
}

//create object element
QDomElement objectElement = document.createElement( "LayoutObject" );

QDomElement ddPropsElement = document.createElement( QStringLiteral( "dataDefinedProperties" ) );
mDataDefinedProperties.writeXml( ddPropsElement, sPropertyDefinitions );
objectElement.appendChild( ddPropsElement );

//custom properties
mCustomProperties.writeXml( objectElement, document );

parentElement.appendChild( objectElement );
return true;
}

bool QgsLayoutObject::readObjectPropertiesFromElement( const QDomElement &parentElement, const QDomDocument &document, const QgsReadWriteContext & )
{
Q_UNUSED( document );
if ( parentElement.isNull() )
{
return false;
}

QDomNodeList objectNodeList = parentElement.elementsByTagName( "LayoutObject" );
if ( objectNodeList.size() < 1 )
{
return false;
}
QDomElement objectElement = objectNodeList.at( 0 ).toElement();

QDomNode propsNode = objectElement.namedItem( QStringLiteral( "dataDefinedProperties" ) );
if ( !propsNode.isNull() )
{
mDataDefinedProperties.readXml( propsNode.toElement(), sPropertyDefinitions );
}

//custom properties
mCustomProperties.readXml( objectElement );

return true;
}
19 changes: 19 additions & 0 deletions src/core/layout/qgslayoutobject.h
Expand Up @@ -28,6 +28,7 @@

class QgsLayout;
class QPainter;
class QgsReadWriteContext;

/**
* \ingroup core
Expand Down Expand Up @@ -188,6 +189,24 @@ class CORE_EXPORT QgsLayoutObject: public QObject, public QgsExpressionContextGe

protected:

/**
* Stores object properties within an XML DOM element.
* \param parentElement is the parent DOM element to store the object's properties in
* \param document DOM document
* \returns true if write was successful
* \see readObjectPropertiesFromElement()
*/
bool writeObjectPropertiesToElement( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const;

/**
* Sets object properties from a DOM element
* \param parentElement is the parent DOM element for the object
* \param document DOM document
* \returns true if read was successful
* \see writeObjectPropertiesToElement()
*/
bool readObjectPropertiesFromElement( const QDomElement &parentElement, const QDomDocument &document, const QgsReadWriteContext &context );

QgsLayout *mLayout = nullptr;

QgsPropertyCollection mDataDefinedProperties;
Expand Down
126 changes: 126 additions & 0 deletions tests/src/core/testqgslayoutobject.cpp
Expand Up @@ -19,6 +19,7 @@
#include "qgslayout.h"
#include "qgstest.h"
#include "qgsproject.h"
#include "qgsreadwritecontext.h"

class TestQgsLayoutObject: public QObject
{
Expand All @@ -33,6 +34,10 @@ class TestQgsLayoutObject: public QObject
void layout(); //test fetching layout from QgsLayoutObject
void customProperties();
void context();
void writeReadXml();
void writeRetrieveDDProperty(); //test writing and retrieving dd properties from xml
void writeRetrieveCustomProperties(); //test writing/retreiving custom properties from xml


private:
QString mReport;
Expand Down Expand Up @@ -138,6 +143,127 @@ void TestQgsLayoutObject::context()
delete object;
}

void TestQgsLayoutObject::writeReadXml()
{
QgsProject p;
QgsLayout l( &p );

QgsLayoutObject *object = new QgsLayoutObject( &l );
QDomImplementation DomImplementation;
QDomDocumentType documentType =
DomImplementation.createDocumentType(
"qgis", "http://mrcc.com/qgis.dtd", "SYSTEM" );
QDomDocument doc( documentType );

//test writing with no parent node
QDomElement rootNode = doc.createElement( "qgis" );
QDomElement noNode;
QCOMPARE( object->writeObjectPropertiesToElement( noNode, doc, QgsReadWriteContext() ), false );

//test writing with node
QDomElement layoutObjectElem = doc.createElement( "item" );
rootNode.appendChild( layoutObjectElem );
QVERIFY( object->writeObjectPropertiesToElement( layoutObjectElem, doc, QgsReadWriteContext() ) );

//check if object node was written
QDomNodeList evalNodeList = rootNode.elementsByTagName( "LayoutObject" );
QCOMPARE( evalNodeList.count(), 1 );

//test reading node
QgsLayoutObject *readObject = new QgsLayoutObject( &l );

//test reading with no node
QCOMPARE( readObject->readObjectPropertiesFromElement( noNode, doc, QgsReadWriteContext() ), false );

//test node with no layout object child
QDomElement badLayoutObjectElem = doc.createElement( "item" );
rootNode.appendChild( badLayoutObjectElem );
QCOMPARE( readObject->readObjectPropertiesFromElement( badLayoutObjectElem, doc, QgsReadWriteContext() ), false );

//test reading node
QVERIFY( readObject->readObjectPropertiesFromElement( layoutObjectElem, doc, QgsReadWriteContext() ) );

delete object;
delete readObject;
}

void TestQgsLayoutObject::writeRetrieveDDProperty()
{
QgsProject p;
QgsLayout l( &p );

QgsLayoutObject *object = new QgsLayoutObject( &l );
object->dataDefinedProperties().setProperty( QgsLayoutObject::TestProperty, QgsProperty::fromExpression( QStringLiteral( "10 + 40" ) ) );

//test writing object with dd settings
QDomImplementation DomImplementation;
QDomDocumentType documentType =
DomImplementation.createDocumentType(
QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
QDomDocument doc( documentType );
QDomElement rootNode = doc.createElement( QStringLiteral( "qgis" ) );
QVERIFY( object->writeObjectPropertiesToElement( rootNode, doc, QgsReadWriteContext() ) );

//check if object node was written
QDomNodeList evalNodeList = rootNode.elementsByTagName( QStringLiteral( "LayoutObject" ) );
QCOMPARE( evalNodeList.count(), 1 );

//test reading node containing dd settings
QgsLayoutObject *readObject = new QgsLayoutObject( &l );
QVERIFY( readObject->readObjectPropertiesFromElement( rootNode, doc, QgsReadWriteContext() ) );

//test getting not set dd from restored object
QgsProperty dd = readObject->dataDefinedProperties().property( QgsLayoutObject::BlendMode );
QVERIFY( !dd );

//test getting good property
dd = readObject->dataDefinedProperties().property( QgsLayoutObject::TestProperty );
QVERIFY( dd );
QVERIFY( dd.isActive() );
QCOMPARE( dd.propertyType(), QgsProperty::ExpressionBasedProperty );

delete object;
delete readObject;
}

void TestQgsLayoutObject::writeRetrieveCustomProperties()
{
QgsProject p;
QgsLayout l( &p );

QgsLayoutObject *object = new QgsLayoutObject( &l );

object->setCustomProperty( QStringLiteral( "testprop" ), "testval" );
object->setCustomProperty( QStringLiteral( "testprop2" ), 5 );

//test writing object with custom properties
QDomImplementation DomImplementation;
QDomDocumentType documentType =
DomImplementation.createDocumentType(
QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
QDomDocument doc( documentType );
QDomElement rootNode = doc.createElement( QStringLiteral( "qgis" ) );
QVERIFY( object->writeObjectPropertiesToElement( rootNode, doc, QgsReadWriteContext() ) );

//check if object node was written
QDomNodeList evalNodeList = rootNode.elementsByTagName( QStringLiteral( "LayoutObject" ) );
QCOMPARE( evalNodeList.count(), 1 );

//test reading node containing custom properties
QgsLayoutObject *readObject = new QgsLayoutObject( &l );
QVERIFY( readObject->readObjectPropertiesFromElement( rootNode, doc, QgsReadWriteContext() ) );

//test retrieved custom properties
QCOMPARE( readObject->customProperties().length(), 2 );
QVERIFY( readObject->customProperties().contains( QString( "testprop" ) ) );
QVERIFY( readObject->customProperties().contains( QString( "testprop2" ) ) );
QCOMPARE( readObject->customProperty( "testprop" ).toString(), QString( "testval" ) );
QCOMPARE( readObject->customProperty( "testprop2" ).toInt(), 5 );

delete object;
delete readObject;
}


QGSTEST_MAIN( TestQgsLayoutObject )
#include "testqgslayoutobject.moc"

0 comments on commit 09dd6db

Please sign in to comment.