Merge pull request #6470 from elpaso/template-convert
[layout] Automatic conversion of 2.x composition templates to layouts
@ -452,6 +452,29 @@ QList<QgsLayoutObject *> QgsCompositionConverter::addItemsFromCompositionXml( Qg
|
|||||||
return newItems;
|
return newItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QgsCompositionConverter::isCompositionTemplate( const QDomDocument &document )
|
||||||
|
{
|
||||||
|
return document.elementsByTagName( QStringLiteral( "Composition" ) ).count() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDomDocument QgsCompositionConverter::convertCompositionTemplate( const QDomDocument &document, QgsProject *project )
|
||||||
|
{
|
||||||
|
QDomDocument doc;
|
||||||
|
QgsReadWriteContext context;
|
||||||
|
if ( project )
|
||||||
|
context.setPathResolver( project->pathResolver() );
|
||||||
|
if ( document.elementsByTagName( QStringLiteral( "Composition" ) ).count( ) > 0 )
|
||||||
|
{
|
||||||
|
QDomElement composerElem = document.elementsByTagName( QStringLiteral( "Composition" ) ).at( 0 ).toElement( );
|
||||||
|
|
||||||
|
std::unique_ptr<QgsLayout> layout = createLayoutFromCompositionXml( composerElem,
|
||||||
|
project );
|
||||||
|
QDomElement elem = layout->writeXml( doc, context );
|
||||||
|
doc.appendChild( elem );
|
||||||
|
}
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
bool QgsCompositionConverter::readLabelXml( QgsLayoutItemLabel *layoutItem, const QDomElement &itemElem, const QgsProject *project )
|
bool QgsCompositionConverter::readLabelXml( QgsLayoutItemLabel *layoutItem, const QDomElement &itemElem, const QgsProject *project )
|
||||||
{
|
{
|
||||||
Q_UNUSED( project );
|
Q_UNUSED( project );
|
||||||
|
@ -144,6 +144,24 @@ class CORE_EXPORT QgsCompositionConverter
|
|||||||
QPointF *position = nullptr,
|
QPointF *position = nullptr,
|
||||||
bool pasteInPlace = false );
|
bool pasteInPlace = false );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given \a document is a composition template
|
||||||
|
* \return true if the document is a composition template
|
||||||
|
* \since QGIS 3.0.1
|
||||||
|
*/
|
||||||
|
static bool isCompositionTemplate( const QDomDocument &document );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a composition template \a document to a layout template
|
||||||
|
* \param document containing a composition
|
||||||
|
* \param project
|
||||||
|
* \return dom document with the converted template
|
||||||
|
* \since QGIS 3.0.1
|
||||||
|
*/
|
||||||
|
static QDomDocument convertCompositionTemplate( const QDomDocument
|
||||||
|
&document, QgsProject *project );
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "qgslayoutmultiframe.h"
|
#include "qgslayoutmultiframe.h"
|
||||||
#include "qgslayoutitemmap.h"
|
#include "qgslayoutitemmap.h"
|
||||||
#include "qgslayoutundostack.h"
|
#include "qgslayoutundostack.h"
|
||||||
|
#include "qgscompositionconverter.h"
|
||||||
|
|
||||||
QgsLayout::QgsLayout( QgsProject *project )
|
QgsLayout::QgsLayout( QgsProject *project )
|
||||||
: mProject( project )
|
: mProject( project )
|
||||||
@ -609,7 +610,17 @@ QList< QgsLayoutItem * > QgsLayout::loadFromTemplate( const QDomDocument &docume
|
|||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QDomDocument doc = document;
|
QDomDocument doc;
|
||||||
|
|
||||||
|
// If this is a 2.x composition template, convert it to a layout template
|
||||||
|
if ( QgsCompositionConverter::isCompositionTemplate( document ) )
|
||||||
|
{
|
||||||
|
doc = QgsCompositionConverter::convertCompositionTemplate( document, mProject );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
doc = document;
|
||||||
|
}
|
||||||
|
|
||||||
// remove all uuid attributes since we don't want duplicates UUIDS
|
// remove all uuid attributes since we don't want duplicates UUIDS
|
||||||
QDomNodeList itemsNodes = doc.elementsByTagName( QStringLiteral( "LayoutItem" ) );
|
QDomNodeList itemsNodes = doc.elementsByTagName( QStringLiteral( "LayoutItem" ) );
|
||||||
|
@ -44,6 +44,16 @@
|
|||||||
#include "qgslayoutitemattributetable.h"
|
#include "qgslayoutitemattributetable.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Debug output for dom nodes
|
||||||
|
QDebug operator<<( QDebug dbg, const QDomNode &node )
|
||||||
|
{
|
||||||
|
QString s;
|
||||||
|
QTextStream str( &s, QIODevice::WriteOnly );
|
||||||
|
node.save( str, 2 );
|
||||||
|
dbg << qPrintable( s );
|
||||||
|
return dbg;
|
||||||
|
}
|
||||||
|
|
||||||
class TestQgsCompositionConverter: public QObject
|
class TestQgsCompositionConverter: public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -125,7 +135,17 @@ class TestQgsCompositionConverter: public QObject
|
|||||||
/**
|
/**
|
||||||
* Test automatic conversion from a composer template
|
* Test automatic conversion from a composer template
|
||||||
*/
|
*/
|
||||||
void convertComposerTemplate();
|
void convertComposition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if a composition template can be detected from a dom document
|
||||||
|
*/
|
||||||
|
void isCompositionTemplate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if a composition template can be converted to a layout template
|
||||||
|
*/
|
||||||
|
void convertCompositionTemplate();
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -523,7 +543,7 @@ void TestQgsCompositionConverter::importComposerTemplateScaleBar()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TestQgsCompositionConverter::convertComposerTemplate()
|
void TestQgsCompositionConverter::convertComposition()
|
||||||
{
|
{
|
||||||
|
|
||||||
QgsProject project;
|
QgsProject project;
|
||||||
@ -541,6 +561,42 @@ void TestQgsCompositionConverter::convertComposerTemplate()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestQgsCompositionConverter::isCompositionTemplate()
|
||||||
|
{
|
||||||
|
QString templatePath( QStringLiteral( TEST_DATA_DIR ) + "/layouts/2x_template.qpt" );
|
||||||
|
QDomDocument doc( "mydocument" );
|
||||||
|
QFile file( templatePath );
|
||||||
|
file.open( QIODevice::ReadOnly );
|
||||||
|
doc.setContent( &file );
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
QVERIFY( QgsCompositionConverter::isCompositionTemplate( doc ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestQgsCompositionConverter::convertCompositionTemplate()
|
||||||
|
{
|
||||||
|
QString templatePath( QStringLiteral( TEST_DATA_DIR ) + "/layouts/2x_template.qpt" );
|
||||||
|
QDomDocument doc( "mydocument" );
|
||||||
|
QFile file( templatePath );
|
||||||
|
file.open( QIODevice::ReadOnly );
|
||||||
|
doc.setContent( &file );
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
QgsProject project;
|
||||||
|
|
||||||
|
QDomDocument layoutDoc = QgsCompositionConverter::convertCompositionTemplate( doc, &project );
|
||||||
|
//qDebug() << layoutDoc;
|
||||||
|
QCOMPARE( layoutDoc.elementsByTagName( QStringLiteral( "Layout" ) ).count(), 1 );
|
||||||
|
|
||||||
|
std::unique_ptr<QgsLayout> layout = qgis::make_unique<QgsLayout>( &project );
|
||||||
|
QgsReadWriteContext context;
|
||||||
|
context.setPathResolver( project.pathResolver() );
|
||||||
|
layout->readXml( layoutDoc.elementsByTagName( QStringLiteral( "Layout" ) ).at( 0 ).toElement(), layoutDoc, context );
|
||||||
|
QVERIFY( layout.get() );
|
||||||
|
QCOMPARE( layout->pageCollection()->pageCount(), 2 );
|
||||||
|
}
|
||||||
|
|
||||||
void TestQgsCompositionConverter::importComposerTemplate()
|
void TestQgsCompositionConverter::importComposerTemplate()
|
||||||
{
|
{
|
||||||
QDomElement composerElem( loadComposer( "2x_template.qpt" ) );
|
QDomElement composerElem( loadComposer( "2x_template.qpt" ) );
|
||||||
@ -646,7 +702,7 @@ void TestQgsCompositionConverter::checkRenderedImage( QgsLayout *layout, const Q
|
|||||||
QSize size( layout->pageCollection()->page( pageNumber )->sizeWithUnits().width() * 3.77, layout->pageCollection()->page( pageNumber )->sizeWithUnits().height() * 3.77 );
|
QSize size( layout->pageCollection()->page( pageNumber )->sizeWithUnits().width() * 3.77, layout->pageCollection()->page( pageNumber )->sizeWithUnits().height() * 3.77 );
|
||||||
checker.setSize( size );
|
checker.setSize( size );
|
||||||
checker.setControlPathPrefix( QStringLiteral( "compositionconverter" ) );
|
checker.setControlPathPrefix( QStringLiteral( "compositionconverter" ) );
|
||||||
QVERIFY( checker.testLayout( mReport, pageNumber, 0, true ) );
|
QVERIFY( checker.testLayout( mReport, pageNumber, 0, false ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 183 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 22 KiB |