Skip to content

Commit 7b4f69e

Browse files
elpasonyalldawson
authored andcommitted
[layout] Automatic conversion of 2.x composition templates to layouts
(cherry-picked from 3bdb6c2)
1 parent 06181e6 commit 7b4f69e

File tree

17 files changed

+111
-4
lines changed

17 files changed

+111
-4
lines changed

src/core/layout/qgscompositionconverter.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,29 @@ QList<QgsLayoutObject *> QgsCompositionConverter::addItemsFromCompositionXml( Qg
452452
return newItems;
453453
}
454454

455+
bool QgsCompositionConverter::isCompositionTemplate( const QDomDocument &document )
456+
{
457+
return document.elementsByTagName( QStringLiteral( "Composition" ) ).count() > 0;
458+
}
459+
460+
QDomDocument QgsCompositionConverter::convertCompositionTemplate( const QDomDocument &document, QgsProject *project )
461+
{
462+
QDomDocument doc;
463+
QgsReadWriteContext context;
464+
if ( project )
465+
context.setPathResolver( project->pathResolver() );
466+
if ( document.elementsByTagName( QStringLiteral( "Composition" ) ).count( ) > 0 )
467+
{
468+
QDomElement composerElem = document.elementsByTagName( QStringLiteral( "Composition" ) ).at( 0 ).toElement( );
469+
470+
std::unique_ptr<QgsLayout> layout = createLayoutFromCompositionXml( composerElem,
471+
project );
472+
QDomElement elem = layout->writeXml( doc, context );
473+
doc.appendChild( elem );
474+
}
475+
return doc;
476+
}
477+
455478
bool QgsCompositionConverter::readLabelXml( QgsLayoutItemLabel *layoutItem, const QDomElement &itemElem, const QgsProject *project )
456479
{
457480
Q_UNUSED( project );

src/core/layout/qgscompositionconverter.h

+17
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,23 @@ class CORE_EXPORT QgsCompositionConverter
144144
QPointF *position = nullptr,
145145
bool pasteInPlace = false );
146146

147+
/**
148+
* Check if the given \a document is a composition template
149+
* \param document a dom document
150+
* \return true if the document is a composition template
151+
*/
152+
static bool isCompositionTemplate( const QDomDocument &document );
153+
154+
/**
155+
* Convert a composition template \a document to a layout template
156+
* \param document containing a composition
157+
* \param project
158+
* \return dom document with the converted template
159+
*/
160+
static QDomDocument convertCompositionTemplate( const QDomDocument
161+
&document, QgsProject *project );
162+
163+
147164
private:
148165

149166

src/core/layout/qgslayout.cpp

+12-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "qgslayoutmultiframe.h"
2828
#include "qgslayoutitemmap.h"
2929
#include "qgslayoutundostack.h"
30+
#include "qgscompositionconverter.h"
3031

3132
QgsLayout::QgsLayout( QgsProject *project )
3233
: mProject( project )
@@ -609,7 +610,17 @@ QList< QgsLayoutItem * > QgsLayout::loadFromTemplate( const QDomDocument &docume
609610
clear();
610611
}
611612

612-
QDomDocument doc = document;
613+
QDomDocument doc;
614+
615+
// If this is a 2.x composition template, convert it to a layout template
616+
if ( QgsCompositionConverter::isCompositionTemplate( document ) )
617+
{
618+
doc = QgsCompositionConverter::convertCompositionTemplate( document, mProject );
619+
}
620+
else
621+
{
622+
doc = document;
623+
}
613624

614625
// remove all uuid attributes since we don't want duplicates UUIDS
615626
QDomNodeList itemsNodes = doc.elementsByTagName( QStringLiteral( "LayoutItem" ) );

tests/src/core/testqgscompositionconverter.cpp

+59-3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@
4444
#include "qgslayoutitemattributetable.h"
4545

4646

47+
// Debug output for dom nodes
48+
QDebug operator<<( QDebug dbg, const QDomNode &node )
49+
{
50+
QString s;
51+
QTextStream str( &s, QIODevice::WriteOnly );
52+
node.save( str, 2 );
53+
dbg << qPrintable( s );
54+
return dbg;
55+
}
56+
4757
class TestQgsCompositionConverter: public QObject
4858
{
4959
Q_OBJECT
@@ -125,7 +135,17 @@ class TestQgsCompositionConverter: public QObject
125135
/**
126136
* Test automatic conversion from a composer template
127137
*/
128-
void convertComposerTemplate();
138+
void convertComposition();
139+
140+
/**
141+
* Test if a composition template can be detected from a dom document
142+
*/
143+
void isCompositionTemplate();
144+
145+
/**
146+
* Test if a composition template can be converted to a layout template
147+
*/
148+
void convertCompositionTemplate();
129149

130150

131151
private:
@@ -523,7 +543,7 @@ void TestQgsCompositionConverter::importComposerTemplateScaleBar()
523543
}
524544

525545

526-
void TestQgsCompositionConverter::convertComposerTemplate()
546+
void TestQgsCompositionConverter::convertComposition()
527547
{
528548

529549
QgsProject project;
@@ -541,6 +561,42 @@ void TestQgsCompositionConverter::convertComposerTemplate()
541561

542562
}
543563

564+
void TestQgsCompositionConverter::isCompositionTemplate()
565+
{
566+
QString templatePath( QStringLiteral( TEST_DATA_DIR ) + "/layouts/2x_template.qpt" );
567+
QDomDocument doc( "mydocument" );
568+
QFile file( templatePath );
569+
file.open( QIODevice::ReadOnly );
570+
doc.setContent( &file );
571+
file.close();
572+
573+
QVERIFY( QgsCompositionConverter::isCompositionTemplate( doc ) );
574+
575+
}
576+
577+
void TestQgsCompositionConverter::convertCompositionTemplate()
578+
{
579+
QString templatePath( QStringLiteral( TEST_DATA_DIR ) + "/layouts/2x_template.qpt" );
580+
QDomDocument doc( "mydocument" );
581+
QFile file( templatePath );
582+
file.open( QIODevice::ReadOnly );
583+
doc.setContent( &file );
584+
file.close();
585+
586+
QgsProject project;
587+
588+
QDomDocument layoutDoc = QgsCompositionConverter::convertCompositionTemplate( doc, &project );
589+
//qDebug() << layoutDoc;
590+
QCOMPARE( layoutDoc.elementsByTagName( QStringLiteral( "Layout" ) ).count(), 1 );
591+
592+
std::unique_ptr<QgsLayout> layout = qgis::make_unique<QgsLayout>( &project );
593+
QgsReadWriteContext context;
594+
context.setPathResolver( project.pathResolver() );
595+
layout->readXml( layoutDoc.elementsByTagName( QStringLiteral( "Layout" ) ).at( 0 ).toElement(), layoutDoc, context );
596+
QVERIFY( layout.get() );
597+
QCOMPARE( layout->pageCollection()->pageCount(), 2 );
598+
}
599+
544600
void TestQgsCompositionConverter::importComposerTemplate()
545601
{
546602
QDomElement composerElem( loadComposer( "2x_template.qpt" ) );
@@ -646,7 +702,7 @@ void TestQgsCompositionConverter::checkRenderedImage( QgsLayout *layout, const Q
646702
QSize size( layout->pageCollection()->page( pageNumber )->sizeWithUnits().width() * 3.77, layout->pageCollection()->page( pageNumber )->sizeWithUnits().height() * 3.77 );
647703
checker.setSize( size );
648704
checker.setControlPathPrefix( QStringLiteral( "compositionconverter" ) );
649-
QVERIFY( checker.testLayout( mReport, pageNumber, 0, true ) );
705+
QVERIFY( checker.testLayout( mReport, pageNumber, 0, false ) );
650706
}
651707

652708

0 commit comments

Comments
 (0)