Skip to content

Commit f3124f0

Browse files
committed
Fix storing/reading multiframe items (TODO fix undo/redo support)
1 parent 1b96926 commit f3124f0

File tree

9 files changed

+150
-101
lines changed

9 files changed

+150
-101
lines changed

python/core/layout/qgslayoutframe.sip

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ Creates a new QgsLayoutFrame belonging to the specified ``layout``.
3737

3838
virtual QIcon icon() const;
3939

40-
virtual QString uuid() const;
41-
4240

4341
virtual QString displayName() const;
4442

@@ -127,6 +125,10 @@ Returns whether the frame is empty.
127125

128126
virtual void drawBackground( QgsRenderContext &context );
129127

128+
virtual bool writePropertiesToElement( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const;
129+
130+
virtual bool readPropertiesFromElement( const QDomElement &itemElement, const QDomDocument &document, const QgsReadWriteContext &context );
131+
130132

131133
};
132134

src/core/layout/qgslayout.cpp

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -777,8 +777,7 @@ QDomElement QgsLayout::writeXml( QDomDocument &document, const QgsReadWriteConte
777777
{
778778
if ( const QgsLayoutItem *item = dynamic_cast< const QgsLayoutItem *>( graphicsItem ) )
779779
{
780-
if ( item->type() == QgsLayoutItemRegistry::LayoutPage
781-
|| item->type() == QgsLayoutItemRegistry::LayoutFrame )
780+
if ( item->type() == QgsLayoutItemRegistry::LayoutPage )
782781
continue;
783782

784783
item->writeXml( element, document, context );
@@ -937,42 +936,6 @@ QList< QgsLayoutItem * > QgsLayout::addItemsFromXml( const QDomElement &parentEl
937936
pageNumber = mPageCollection->pageNumberForPoint( *position );
938937
}
939938
}
940-
941-
const QDomNodeList layoutItemList = parentElement.childNodes();
942-
for ( int i = 0; i < layoutItemList.size(); ++i )
943-
{
944-
const QDomElement currentItemElem = layoutItemList.at( i ).toElement();
945-
if ( currentItemElem.nodeName() != QStringLiteral( "LayoutItem" ) )
946-
continue;
947-
948-
const int itemType = currentItemElem.attribute( QStringLiteral( "type" ) ).toInt();
949-
std::unique_ptr< QgsLayoutItem > item( QgsApplication::layoutItemRegistry()->createItem( itemType, this ) );
950-
if ( !item )
951-
{
952-
// e.g. plugin based item which is no longer available
953-
continue;
954-
}
955-
956-
item->readXml( currentItemElem, document, context );
957-
if ( position )
958-
{
959-
if ( pasteInPlace )
960-
{
961-
QgsLayoutPoint posOnPage = QgsLayoutPoint::decodePoint( currentItemElem.attribute( QStringLiteral( "positionOnPage" ) ) );
962-
item->attemptMove( posOnPage, true, false, pageNumber );
963-
}
964-
else
965-
{
966-
item->attemptMoveBy( pasteShiftPos.x(), pasteShiftPos.y() );
967-
}
968-
}
969-
970-
QgsLayoutItem *layoutItem = item.get();
971-
addLayoutItem( item.release() );
972-
layoutItem->setZValue( layoutItem->zValue() + zOrderOffset );
973-
newItems << layoutItem;
974-
}
975-
976939
// multiframes
977940

978941
//TODO - fix this. pasting multiframe frame items has no effect
@@ -1008,6 +971,40 @@ QList< QgsLayoutItem * > QgsLayout::addItemsFromXml( const QDomElement &parentEl
1008971
newMultiFrames << m;
1009972
}
1010973

974+
const QDomNodeList layoutItemList = parentElement.childNodes();
975+
for ( int i = 0; i < layoutItemList.size(); ++i )
976+
{
977+
const QDomElement currentItemElem = layoutItemList.at( i ).toElement();
978+
if ( currentItemElem.nodeName() != QStringLiteral( "LayoutItem" ) )
979+
continue;
980+
981+
const int itemType = currentItemElem.attribute( QStringLiteral( "type" ) ).toInt();
982+
std::unique_ptr< QgsLayoutItem > item( QgsApplication::layoutItemRegistry()->createItem( itemType, this ) );
983+
if ( !item )
984+
{
985+
// e.g. plugin based item which is no longer available
986+
continue;
987+
}
988+
989+
item->readXml( currentItemElem, document, context );
990+
if ( position )
991+
{
992+
if ( pasteInPlace )
993+
{
994+
QgsLayoutPoint posOnPage = QgsLayoutPoint::decodePoint( currentItemElem.attribute( QStringLiteral( "positionOnPage" ) ) );
995+
item->attemptMove( posOnPage, true, false, pageNumber );
996+
}
997+
else
998+
{
999+
item->attemptMoveBy( pasteShiftPos.x(), pasteShiftPos.y() );
1000+
}
1001+
}
1002+
1003+
QgsLayoutItem *layoutItem = item.get();
1004+
addLayoutItem( item.release() );
1005+
layoutItem->setZValue( layoutItem->zValue() + zOrderOffset );
1006+
newItems << layoutItem;
1007+
}
10111008

10121009
// we now allow items to "post-process", e.g. if they need to setup connections
10131010
// to other items in the layout, which may not have existed at the time the

src/core/layout/qgslayoutframe.cpp

Lines changed: 27 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -72,39 +72,6 @@ QgsLayoutSize QgsLayoutFrame::fixedSize() const
7272
return QgsLayoutSize( mMultiFrame->fixedFrameSize( frameIndex ), QgsUnitTypes::LayoutMillimeters );
7373
}
7474

75-
#if 0// TODO - save/restore multiframe uuid!
76-
bool QgsLayoutFrame::writeXml( QDomElement &elem, QDomDocument &doc ) const
77-
{
78-
QDomElement frameElem = doc.createElement( QStringLiteral( "ComposerFrame" ) );
79-
frameElem.setAttribute( QStringLiteral( "sectionX" ), QString::number( mSection.x() ) );
80-
frameElem.setAttribute( QStringLiteral( "sectionY" ), QString::number( mSection.y() ) );
81-
frameElem.setAttribute( QStringLiteral( "sectionWidth" ), QString::number( mSection.width() ) );
82-
frameElem.setAttribute( QStringLiteral( "sectionHeight" ), QString::number( mSection.height() ) );
83-
frameElem.setAttribute( QStringLiteral( "hidePageIfEmpty" ), mHidePageIfEmpty );
84-
frameElem.setAttribute( QStringLiteral( "hideBackgroundIfEmpty" ), mHideBackgroundIfEmpty );
85-
elem.appendChild( frameElem );
86-
87-
return _writeXml( frameElem, doc );
88-
}
89-
90-
bool QgsLayoutFrame::readXml( const QDomElement &itemElem, const QDomDocument &doc )
91-
{
92-
double x = itemElem.attribute( QStringLiteral( "sectionX" ) ).toDouble();
93-
double y = itemElem.attribute( QStringLiteral( "sectionY" ) ).toDouble();
94-
double width = itemElem.attribute( QStringLiteral( "sectionWidth" ) ).toDouble();
95-
double height = itemElem.attribute( QStringLiteral( "sectionHeight" ) ).toDouble();
96-
mSection = QRectF( x, y, width, height );
97-
mHidePageIfEmpty = itemElem.attribute( QStringLiteral( "hidePageIfEmpty" ), QStringLiteral( "0" ) ).toInt();
98-
mHideBackgroundIfEmpty = itemElem.attribute( QStringLiteral( "hideBackgroundIfEmpty" ), QStringLiteral( "0" ) ).toInt();
99-
QDomElement composerItem = itemElem.firstChildElement( QStringLiteral( "ComposerItem" ) );
100-
if ( composerItem.isNull() )
101-
{
102-
return false;
103-
}
104-
return _readXml( composerItem, doc );
105-
}
106-
#endif
107-
10875
int QgsLayoutFrame::type() const
10976
{
11077
return QgsLayoutItemRegistry::LayoutFrame;
@@ -118,14 +85,6 @@ QIcon QgsLayoutFrame::icon() const
11885
return QIcon();
11986
}
12087

121-
QString QgsLayoutFrame::uuid() const
122-
{
123-
if ( mMultiFrame )
124-
return mMultiFrame->uuid() + ':' + mMultiFrame->frameIndex( const_cast< QgsLayoutFrame * >( this ) );
125-
else
126-
return QgsLayoutItem::uuid();
127-
}
128-
12988
void QgsLayoutFrame::setHidePageIfEmpty( const bool hidePageIfEmpty )
13089
{
13190
mHidePageIfEmpty = hidePageIfEmpty;
@@ -168,10 +127,8 @@ QgsExpressionContext QgsLayoutFrame::createExpressionContext() const
168127
//start with multiframe's context
169128
QgsExpressionContext context = mMultiFrame->createExpressionContext();
170129

171-
#if 0 //TODO
172130
//add frame's individual context
173131
context.appendScope( QgsExpressionContextUtils::layoutItemScope( this ) );
174-
#endif
175132

176133
return context;
177134
}
@@ -226,6 +183,33 @@ void QgsLayoutFrame::drawBackground( QgsRenderContext &context )
226183
}
227184
}
228185

186+
bool QgsLayoutFrame::writePropertiesToElement( QDomElement &parentElement, QDomDocument &, const QgsReadWriteContext & ) const
187+
{
188+
parentElement.setAttribute( QStringLiteral( "multiFrame" ), mMultiFrameUuid );
189+
parentElement.setAttribute( QStringLiteral( "sectionX" ), QString::number( mSection.x() ) );
190+
parentElement.setAttribute( QStringLiteral( "sectionY" ), QString::number( mSection.y() ) );
191+
parentElement.setAttribute( QStringLiteral( "sectionWidth" ), QString::number( mSection.width() ) );
192+
parentElement.setAttribute( QStringLiteral( "sectionHeight" ), QString::number( mSection.height() ) );
193+
parentElement.setAttribute( QStringLiteral( "hidePageIfEmpty" ), mHidePageIfEmpty );
194+
parentElement.setAttribute( QStringLiteral( "hideBackgroundIfEmpty" ), mHideBackgroundIfEmpty );
195+
return true;
196+
}
197+
198+
bool QgsLayoutFrame::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext & )
199+
{
200+
double x = itemElem.attribute( QStringLiteral( "sectionX" ) ).toDouble();
201+
double y = itemElem.attribute( QStringLiteral( "sectionY" ) ).toDouble();
202+
double width = itemElem.attribute( QStringLiteral( "sectionWidth" ) ).toDouble();
203+
double height = itemElem.attribute( QStringLiteral( "sectionHeight" ) ).toDouble();
204+
mSection = QRectF( x, y, width, height );
205+
mHidePageIfEmpty = itemElem.attribute( QStringLiteral( "hidePageIfEmpty" ), QStringLiteral( "0" ) ).toInt();
206+
mHideBackgroundIfEmpty = itemElem.attribute( QStringLiteral( "hideBackgroundIfEmpty" ), QStringLiteral( "0" ) ).toInt();
207+
208+
mMultiFrameUuid = itemElem.attribute( QStringLiteral( "multiFrame" ) );
209+
mMultiFrame = mLayout->multiFrameByUuid( mMultiFrameUuid );
210+
return true;
211+
}
212+
229213
#if 0 //TODO
230214
void QgsLayoutFrame::beginItemCommand( const QString &text )
231215
{

src/core/layout/qgslayoutframe.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ class CORE_EXPORT QgsLayoutFrame: public QgsLayoutItem
4747

4848
int type() const override;
4949
QIcon icon() const override;
50-
QString uuid() const override;
5150

5251
//Overridden to allow multiframe to set display name
5352
QString displayName() const override;
@@ -72,8 +71,6 @@ class CORE_EXPORT QgsLayoutFrame: public QgsLayoutItem
7271
#if 0 //TODO
7372
void beginItemCommand( const QString &text ) override;
7473
void endItemCommand() override;
75-
bool writeXml( QDomElement &elem, QDomDocument &doc ) const override;
76-
bool readXml( const QDomElement &itemElem, const QDomDocument &doc ) override;
7774
#endif
7875

7976
/**
@@ -124,6 +121,8 @@ class CORE_EXPORT QgsLayoutFrame: public QgsLayoutItem
124121
void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = nullptr ) override;
125122
void drawFrame( QgsRenderContext &context ) override;
126123
void drawBackground( QgsRenderContext &context ) override;
124+
bool writePropertiesToElement( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const override;
125+
bool readPropertiesFromElement( const QDomElement &itemElement, const QDomDocument &document, const QgsReadWriteContext &context ) override;
127126

128127
private:
129128
QgsLayoutFrame() = delete;

src/core/layout/qgslayoutitemgroup.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -260,18 +260,12 @@ bool QgsLayoutItemGroup::readPropertiesFromElement( const QDomElement &itemEleme
260260

261261
void QgsLayoutItemGroup::finalizeRestoreFromXml()
262262
{
263-
QList<QgsLayoutItem *> items;
264-
mLayout->layoutItems( items );
265-
266263
for ( const QString &uuid : qgis::as_const( mItemUuids ) )
267264
{
268-
for ( QgsLayoutItem *item : qgis::as_const( items ) )
265+
QgsLayoutItem *item = mLayout->itemByUuid( uuid, true );
266+
if ( item )
269267
{
270-
if ( item && ( item->mUuid == uuid /* TODO || item->mTemplateUuid == uuid */ ) )
271-
{
272-
addItem( item );
273-
break;
274-
}
268+
addItem( item );
275269
}
276270
}
277271

src/core/layout/qgslayoutmultiframe.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ void QgsLayoutMultiFrame::addFrame( QgsLayoutFrame *frame, bool recalcFrameSizes
6464
{
6565
handleFrameRemoval( frame );
6666
} );
67-
if ( mLayout )
67+
if ( mLayout && !frame->scene() )
6868
{
6969
mLayout->addLayoutItem( frame );
7070
}
@@ -301,6 +301,14 @@ void QgsLayoutMultiFrame::cancelCommand()
301301

302302
void QgsLayoutMultiFrame::finalizeRestoreFromXml()
303303
{
304+
for ( const QString &uuid : qgis::as_const( mFrameUuids ) )
305+
{
306+
QgsLayoutItem *item = mLayout->itemByUuid( uuid, true );
307+
if ( QgsLayoutFrame *frame = qobject_cast< QgsLayoutFrame * >( item ) )
308+
{
309+
addFrame( frame );
310+
}
311+
}
304312
}
305313

306314
void QgsLayoutMultiFrame::refresh()
@@ -466,6 +474,16 @@ bool QgsLayoutMultiFrame::writeXml( QDomElement &parentElement, QDomDocument &do
466474
Q_UNUSED( ignoreFrames );
467475
#endif
468476

477+
for ( QgsLayoutFrame *frame : mFrameItems )
478+
{
479+
if ( !frame )
480+
continue;
481+
482+
QDomElement childItem = doc.createElement( QStringLiteral( "childFrame" ) );
483+
childItem.setAttribute( QStringLiteral( "uuid" ), frame->uuid() );
484+
element.appendChild( childItem );
485+
}
486+
469487
writeObjectPropertiesToElement( element, doc, context );
470488
writePropertiesToElement( element, doc, context );
471489
parentElement.appendChild( element );
@@ -510,6 +528,18 @@ bool QgsLayoutMultiFrame::readXml( const QDomElement &element, const QDomDocumen
510528
Q_UNUSED( ignoreFrames );
511529
#endif
512530

531+
deleteFrames();
532+
mFrameUuids.clear();
533+
QDomNodeList elementNodes = element.elementsByTagName( QStringLiteral( "childFrame" ) );
534+
for ( int i = 0; i < elementNodes.count(); ++i )
535+
{
536+
QDomNode elementNode = elementNodes.at( i );
537+
if ( !elementNode.isElement() )
538+
continue;
539+
540+
QString uuid = elementNode.toElement().attribute( QStringLiteral( "uuid" ) );
541+
mFrameUuids << uuid;
542+
}
513543

514544
bool result = readPropertiesFromElement( element, doc, context );
515545

src/core/layout/qgslayoutmultiframe.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,8 @@ class CORE_EXPORT QgsLayoutMultiFrame: public QgsLayoutObject, public QgsLayoutU
392392
bool mBlockUpdates = false;
393393
bool mBlockUndoCommands = false;
394394

395+
QList< QString > mFrameUuids;
396+
395397
//! Unique id
396398
QString mUuid;
397399
friend class QgsLayoutFrame;

tests/src/core/testqgslayout.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class TestQgsLayout: public QObject
6565
void clone();
6666
void legendRestoredFromTemplate();
6767
void legendRestoredFromTemplateAutoUpdate();
68-
// void attributeTableRestoredFromTemplate();
68+
void attributeTableRestoredFromTemplate();
6969
void mapLayersRestoredFromTemplate();
7070
void mapLayersStyleOverrideRestoredFromTemplate();
7171
void atlasLayerRestoredFromTemplate();
@@ -1064,7 +1064,6 @@ void TestQgsLayout::legendRestoredFromTemplateAutoUpdate()
10641064
QCOMPARE( model2->data( model->node2index( layerNode2 ), Qt::DisplayRole ).toString(), QString( "points" ) );
10651065
}
10661066

1067-
#if 0 //TODO
10681067
void TestQgsLayout::attributeTableRestoredFromTemplate()
10691068
{
10701069
// load some layers
@@ -1112,7 +1111,6 @@ void TestQgsLayout::attributeTableRestoredFromTemplate()
11121111

11131112
QCOMPARE( table2->vectorLayer(), layer3 );
11141113
}
1115-
#endif
11161114

11171115
void TestQgsLayout::mapLayersRestoredFromTemplate()
11181116
{

0 commit comments

Comments
 (0)