Skip to content

Commit f3bfcc3

Browse files
committedOct 6, 2017
Save/restore frame properties, add unit tests for undo/redo
1 parent 616aec1 commit f3bfcc3

File tree

2 files changed

+222
-0
lines changed

2 files changed

+222
-0
lines changed
 

‎src/core/layout/qgslayoutitem.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "qgspagesizeregistry.h"
2121
#include "qgslayoutitemundocommand.h"
2222
#include "qgslayoutmodel.h"
23+
#include "qgssymbollayerutils.h"
2324
#include <QPainter>
2425
#include <QStyleOptionGraphicsItem>
2526
#include <QUuid>
@@ -661,6 +662,44 @@ bool QgsLayoutItem::writePropertiesToElement( QDomElement &element, QDomDocument
661662
element.setAttribute( "positionLock", "false" );
662663
}
663664

665+
//frame
666+
if ( mFrame )
667+
{
668+
element.setAttribute( QStringLiteral( "frame" ), QStringLiteral( "true" ) );
669+
}
670+
else
671+
{
672+
element.setAttribute( QStringLiteral( "frame" ), QStringLiteral( "false" ) );
673+
}
674+
675+
//background
676+
if ( mBackground )
677+
{
678+
element.setAttribute( QStringLiteral( "background" ), QStringLiteral( "true" ) );
679+
}
680+
else
681+
{
682+
element.setAttribute( QStringLiteral( "background" ), QStringLiteral( "false" ) );
683+
}
684+
685+
//frame color
686+
QDomElement frameColorElem = document.createElement( QStringLiteral( "FrameColor" ) );
687+
frameColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mFrameColor.red() ) );
688+
frameColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mFrameColor.green() ) );
689+
frameColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mFrameColor.blue() ) );
690+
frameColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mFrameColor.alpha() ) );
691+
element.appendChild( frameColorElem );
692+
element.setAttribute( QStringLiteral( "outlineWidthM" ), mFrameWidth.encodeMeasurement() );
693+
element.setAttribute( QStringLiteral( "frameJoinStyle" ), QgsSymbolLayerUtils::encodePenJoinStyle( mFrameJoinStyle ) );
694+
695+
//background color
696+
QDomElement bgColorElem = document.createElement( QStringLiteral( "BackgroundColor" ) );
697+
bgColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mBackgroundColor.red() ) );
698+
bgColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mBackgroundColor.green() ) );
699+
bgColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mBackgroundColor.blue() ) );
700+
bgColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mBackgroundColor.alpha() ) );
701+
element.appendChild( bgColorElem );
702+
664703
//TODO
665704
#if 0
666705
//blend mode
@@ -706,6 +745,78 @@ bool QgsLayoutItem::readPropertiesFromElement( const QDomElement &element, const
706745
//visibility
707746
setVisible( element.attribute( "visibility", "1" ) != "0" );
708747
setZValue( element.attribute( "zValue" ).toDouble() );
748+
749+
//frame
750+
QString frame = element.attribute( QStringLiteral( "frame" ) );
751+
if ( frame.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
752+
{
753+
mFrame = true;
754+
}
755+
else
756+
{
757+
mFrame = false;
758+
}
759+
760+
//frame
761+
QString background = element.attribute( QStringLiteral( "background" ) );
762+
if ( background.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
763+
{
764+
mBackground = true;
765+
}
766+
else
767+
{
768+
mBackground = false;
769+
}
770+
771+
//pen
772+
mFrameWidth = QgsLayoutMeasurement::decodeMeasurement( element.attribute( QStringLiteral( "outlineWidthM" ) ) );
773+
mFrameJoinStyle = QgsSymbolLayerUtils::decodePenJoinStyle( element.attribute( QStringLiteral( "frameJoinStyle" ), QStringLiteral( "miter" ) ) );
774+
QDomNodeList frameColorList = element.elementsByTagName( QStringLiteral( "FrameColor" ) );
775+
if ( !frameColorList.isEmpty() )
776+
{
777+
QDomElement frameColorElem = frameColorList.at( 0 ).toElement();
778+
bool redOk = false;
779+
bool greenOk = false;
780+
bool blueOk = false;
781+
bool alphaOk = false;
782+
int penRed, penGreen, penBlue, penAlpha;
783+
784+
#if 0 // TODO, old style
785+
double penWidth;
786+
penWidth = element.attribute( QStringLiteral( "outlineWidth" ) ).toDouble( &widthOk );
787+
#endif
788+
penRed = frameColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
789+
penGreen = frameColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
790+
penBlue = frameColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
791+
penAlpha = frameColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
792+
793+
if ( redOk && greenOk && blueOk && alphaOk )
794+
{
795+
mFrameColor = QColor( penRed, penGreen, penBlue, penAlpha );
796+
}
797+
}
798+
refreshFrame( false );
799+
800+
//brush
801+
QDomNodeList bgColorList = element.elementsByTagName( QStringLiteral( "BackgroundColor" ) );
802+
if ( !bgColorList.isEmpty() )
803+
{
804+
QDomElement bgColorElem = bgColorList.at( 0 ).toElement();
805+
bool redOk, greenOk, blueOk, alphaOk;
806+
int bgRed, bgGreen, bgBlue, bgAlpha;
807+
bgRed = bgColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
808+
bgGreen = bgColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
809+
bgBlue = bgColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
810+
bgAlpha = bgColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
811+
if ( redOk && greenOk && blueOk && alphaOk )
812+
{
813+
mBackgroundColor = QColor( bgRed, bgGreen, bgBlue, bgAlpha );
814+
setBrush( QBrush( mBackgroundColor, Qt::SolidPattern ) );
815+
}
816+
//apply any data defined settings
817+
refreshBackgroundColor( false );
818+
}
819+
709820
#if 0 //TODO
710821
//blend mode
711822
setBlendMode( QgsMapRenderer::getCompositionMode( ( QgsMapRenderer::BlendMode ) itemElem.attribute( "blendMode", "0" ).toUInt() ) );
@@ -794,6 +905,7 @@ void QgsLayoutItem::refreshFrame( bool updateItem )
794905
{
795906
itemPen.setColor( mFrameColor );
796907
}
908+
itemPen.setJoinStyle( mFrameJoinStyle );
797909

798910
if ( mLayout )
799911
itemPen.setWidthF( mLayout->convertToLayoutUnits( mFrameWidth ) );

‎tests/src/core/testqgslayoutitem.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#include "qgstest.h"
2323
#include "qgsproject.h"
2424
#include "qgsreadwritecontext.h"
25+
#include "qgslayoutitemundocommand.h"
26+
#include "qgslayoutitemmap.h"
27+
#include "qgslayoutitemshape.h"
2528
#include <QObject>
2629
#include <QPainter>
2730
#include <QImage>
@@ -144,6 +147,7 @@ class TestQgsLayoutItem: public QObject
144147
void writeXml();
145148
void readXml();
146149
void writeReadXmlProperties();
150+
void undoRedo();
147151

148152
private:
149153

@@ -1324,6 +1328,12 @@ void TestQgsLayoutItem::writeReadXmlProperties()
13241328
original->setLocked( true );
13251329
original->setZValue( 55 );
13261330
original->setVisible( false );
1331+
original->setFrameEnabled( true );
1332+
original->setFrameStrokeColor( QColor( 100, 150, 200 ) );
1333+
original->setFrameStrokeWidth( QgsLayoutMeasurement( 5, QgsUnitTypes::LayoutCentimeters ) );
1334+
original->setFrameJoinStyle( Qt::MiterJoin );
1335+
original->setBackgroundEnabled( false );
1336+
original->setBackgroundColor( QColor( 200, 150, 100 ) );
13271337

13281338
QgsLayoutItem *copy = createCopyViaXml( &l, original );
13291339

@@ -1340,11 +1350,111 @@ void TestQgsLayoutItem::writeReadXmlProperties()
13401350
QVERIFY( copy->isLocked() );
13411351
QCOMPARE( copy->zValue(), 55.0 );
13421352
QVERIFY( !copy->isVisible() );
1353+
QVERIFY( copy->hasFrame() );
1354+
QCOMPARE( copy->frameStrokeColor(), QColor( 100, 150, 200 ) );
1355+
QCOMPARE( copy->frameStrokeWidth(), QgsLayoutMeasurement( 5, QgsUnitTypes::LayoutCentimeters ) );
1356+
QCOMPARE( copy->frameJoinStyle(), Qt::MiterJoin );
1357+
QVERIFY( !copy->hasBackground() );
1358+
QCOMPARE( copy->backgroundColor(), QColor( 200, 150, 100 ) );
13431359

13441360
delete copy;
13451361
delete original;
13461362
}
13471363

1364+
void TestQgsLayoutItem::undoRedo()
1365+
{
1366+
QgsProject proj;
1367+
QgsLayout l( &proj );
1368+
1369+
QgsLayoutItemRectangularShape *item = new QgsLayoutItemRectangularShape( &l );
1370+
QString uuid = item->uuid();
1371+
QPointer< QgsLayoutItemRectangularShape > pItem( item ); // for testing deletion
1372+
item->setFrameStrokeColor( QColor( 255, 100, 200 ) );
1373+
l.addLayoutItem( item );
1374+
1375+
l.undoStack()->stack()->push( new QgsLayoutItemAddItemCommand( item, QString() ) );
1376+
QVERIFY( pItem );
1377+
QVERIFY( l.items().contains( item ) );
1378+
QCOMPARE( l.itemByUuid( uuid ), item );
1379+
1380+
// undo should delete item
1381+
l.undoStack()->stack()->undo();
1382+
QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1383+
QVERIFY( !pItem );
1384+
QVERIFY( !l.items().contains( item ) );
1385+
QVERIFY( !l.itemByUuid( uuid ) );
1386+
1387+
// redo should restore
1388+
l.undoStack()->stack()->redo();
1389+
QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1390+
item = dynamic_cast< QgsLayoutItemRectangularShape * >( l.itemByUuid( uuid ) );
1391+
QVERIFY( item );
1392+
QVERIFY( l.items().contains( item ) );
1393+
pItem = item;
1394+
QCOMPARE( item->frameStrokeColor().name(), QColor( 255, 100, 200 ).name() );
1395+
1396+
//... and repeat!
1397+
1398+
// undo should delete item
1399+
l.undoStack()->stack()->undo();
1400+
QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1401+
QVERIFY( !pItem );
1402+
QVERIFY( !l.items().contains( item ) );
1403+
QVERIFY( !l.itemByUuid( uuid ) );
1404+
1405+
// redo should restore
1406+
l.undoStack()->stack()->redo();
1407+
QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1408+
item = dynamic_cast< QgsLayoutItemRectangularShape * >( l.itemByUuid( uuid ) );
1409+
QVERIFY( item );
1410+
QVERIFY( l.items().contains( item ) );
1411+
pItem = item;
1412+
QCOMPARE( item->frameStrokeColor().name(), QColor( 255, 100, 200 ).name() );
1413+
1414+
// delete item
1415+
QgsLayoutItemDeleteUndoCommand *deleteCommand = new QgsLayoutItemDeleteUndoCommand( item, QString() );
1416+
l.removeLayoutItem( item );
1417+
l.undoStack()->stack()->push( deleteCommand );
1418+
1419+
QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1420+
QVERIFY( !pItem );
1421+
QVERIFY( !l.items().contains( item ) );
1422+
QVERIFY( !l.itemByUuid( uuid ) );
1423+
1424+
// undo should restore
1425+
l.undoStack()->stack()->undo();
1426+
QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1427+
item = dynamic_cast< QgsLayoutItemRectangularShape * >( l.itemByUuid( uuid ) );
1428+
QVERIFY( item );
1429+
QVERIFY( l.items().contains( item ) );
1430+
pItem = item;
1431+
QCOMPARE( item->frameStrokeColor().name(), QColor( 255, 100, 200 ).name() );
1432+
1433+
// another undo should delete item
1434+
l.undoStack()->stack()->undo();
1435+
QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1436+
QVERIFY( !pItem );
1437+
QVERIFY( !l.items().contains( item ) );
1438+
QVERIFY( !l.itemByUuid( uuid ) );
1439+
1440+
// redo should restore
1441+
l.undoStack()->stack()->redo();
1442+
QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1443+
item = dynamic_cast< QgsLayoutItemRectangularShape * >( l.itemByUuid( uuid ) );
1444+
QVERIFY( item );
1445+
QVERIFY( l.items().contains( item ) );
1446+
pItem = item;
1447+
QCOMPARE( item->frameStrokeColor().name(), QColor( 255, 100, 200 ).name() );
1448+
1449+
// another redo should delete item
1450+
l.undoStack()->stack()->redo();
1451+
QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
1452+
QVERIFY( !pItem );
1453+
QVERIFY( !l.items().contains( item ) );
1454+
QVERIFY( !l.itemByUuid( uuid ) );
1455+
1456+
}
1457+
13481458
QgsLayoutItem *TestQgsLayoutItem::createCopyViaXml( QgsLayout *layout, QgsLayoutItem *original )
13491459
{
13501460
//save original item to xml

0 commit comments

Comments
 (0)
Please sign in to comment.