QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
qgslayout.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayout.cpp
3 -------------------
4 begin : June 2017
5 copyright : (C) 2017 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8/***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
17#include "qgslayout.h"
18#include "qgslayoutitem.h"
19#include "qgslayoutitemhtml.h"
20#include "qgslayoutitemlabel.h"
21#include "qgslayoutmodel.h"
24#include "qgsreadwritecontext.h"
25#include "qgsproject.h"
27#include "qgslayoutitemgroup.h"
29#include "qgslayoutmultiframe.h"
30#include "qgslayoutitemmap.h"
31#include "qgslayoutundostack.h"
35#include "qgsruntimeprofiler.h"
37#include "qgssettingstree.h"
40#include "qgsunittypes.h"
41
42const QgsSettingsEntryStringList *QgsLayout::settingsSearchPathForTemplates = new QgsSettingsEntryStringList( QStringLiteral( "search-paths-for-templates" ), QgsSettingsTree::sTreeLayout, QStringList(), QObject::tr( "Search path for templates" ) );
43
45 : mProject( project )
46 , mRenderContext( new QgsLayoutRenderContext( this ) )
47 , mReportContext( new QgsLayoutReportContext( this ) )
48 , mSnapper( QgsLayoutSnapper( this ) )
49 , mGridSettings( this )
50 , mPageCollection( new QgsLayoutPageCollection( this ) )
51 , mUndoStack( new QgsLayoutUndoStack( this ) )
52{
53 // just to make sure - this should be the default, but maybe it'll change in some future Qt version...
54 setBackgroundBrush( Qt::NoBrush );
55 mItemsModel.reset( new QgsLayoutModel( this ) );
56}
57
59{
60 // no need for undo commands when we're destroying the layout
61 mUndoStack->blockCommands( true );
62
63 deleteAndRemoveMultiFrames();
64
65 // make sure that all layout items are removed before
66 // this class is deconstructed - to avoid segfaults
67 // when layout items access in destructor layout that isn't valid anymore
68
69 // since deletion of some item types (e.g. groups) trigger deletion
70 // of other items, we have to do this careful, one at a time...
71 QList<QGraphicsItem *> itemList = items();
72 bool deleted = true;
73 while ( deleted )
74 {
75 deleted = false;
76 for ( QGraphicsItem *item : std::as_const( itemList ) )
77 {
78 if ( dynamic_cast< QgsLayoutItem * >( item ) && !dynamic_cast< QgsLayoutItemPage *>( item ) )
79 {
80 delete item;
81 deleted = true;
82 break;
83 }
84 }
85 itemList = items();
86 }
87
88 mItemsModel.reset(); // manually delete, so we can control order of destruction
89}
90
92{
93 QDomDocument currentDoc;
94
95 QgsReadWriteContext context;
96 QDomElement elem = writeXml( currentDoc, context );
97 currentDoc.appendChild( elem );
98
99 std::unique_ptr< QgsLayout > newLayout = std::make_unique< QgsLayout >( mProject );
100 bool ok = false;
101 newLayout->loadFromTemplate( currentDoc, context, true, &ok );
102 if ( !ok )
103 {
104 return nullptr;
105 }
106
107 return newLayout.release();
108}
109
111{
112 // default to a A4 landscape page
113 QgsLayoutItemPage *page = new QgsLayoutItemPage( this );
114 page->setPageSize( QgsLayoutSize( 297, 210, Qgis::LayoutUnit::Millimeters ) );
115 mPageCollection->addPage( page );
116 mUndoStack->stack()->clear();
117}
118
120{
121 deleteAndRemoveMultiFrames();
122
123 //delete all non paper items
124 const QList<QGraphicsItem *> itemList = items();
125 for ( QGraphicsItem *item : itemList )
126 {
127 QgsLayoutItem *cItem = dynamic_cast<QgsLayoutItem *>( item );
128 QgsLayoutItemPage *pItem = dynamic_cast<QgsLayoutItemPage *>( item );
129 if ( cItem && !pItem )
130 {
131 removeLayoutItemPrivate( cItem );
132 }
133 }
134 mItemsModel->clear();
135
136 mPageCollection->clear();
137 mUndoStack->stack()->clear();
138}
139
141{
142 return mProject;
143}
144
146{
147 return mItemsModel.get();
148}
149
150QList<QgsLayoutItem *> QgsLayout::selectedLayoutItems( const bool includeLockedItems )
151{
152 QList<QgsLayoutItem *> layoutItemList;
153
154 const QList<QGraphicsItem *> graphicsItemList = selectedItems();
155 for ( QGraphicsItem *item : graphicsItemList )
156 {
157 QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item );
158 if ( layoutItem && ( includeLockedItems || !layoutItem->isLocked() ) )
159 {
160 layoutItemList.push_back( layoutItem );
161 }
162 }
163
164 return layoutItemList;
165}
166
168{
169 whileBlocking( this )->deselectAll();
170 if ( item )
171 {
172 item->setSelected( true );
173 }
174 emit selectedItemChanged( item );
175}
176
178{
179 //we can't use QGraphicsScene::clearSelection, as that emits no signals
180 //and we don't know which items are being deselected
181 //accordingly, we can't inform the layout model of selection changes
182 //instead, do the clear selection manually...
183 const QList<QGraphicsItem *> selectedItemList = selectedItems();
184 for ( QGraphicsItem *item : selectedItemList )
185 {
186 if ( QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item ) )
187 {
188 layoutItem->setSelected( false );
189 }
190 }
191 emit selectedItemChanged( nullptr );
192}
193
194bool QgsLayout::raiseItem( QgsLayoutItem *item, bool deferUpdate )
195{
196 //model handles reordering items
197 bool result = mItemsModel->reorderItemUp( item );
198 if ( result && !deferUpdate )
199 {
200 //update all positions
202 update();
203 }
204 return result;
205}
206
207bool QgsLayout::lowerItem( QgsLayoutItem *item, bool deferUpdate )
208{
209 //model handles reordering items
210 bool result = mItemsModel->reorderItemDown( item );
211 if ( result && !deferUpdate )
212 {
213 //update all positions
215 update();
216 }
217 return result;
218}
219
220bool QgsLayout::moveItemToTop( QgsLayoutItem *item, bool deferUpdate )
221{
222 //model handles reordering items
223 bool result = mItemsModel->reorderItemToTop( item );
224 if ( result && !deferUpdate )
225 {
226 //update all positions
228 update();
229 }
230 return result;
231}
232
233bool QgsLayout::moveItemToBottom( QgsLayoutItem *item, bool deferUpdate )
234{
235 //model handles reordering items
236 bool result = mItemsModel->reorderItemToBottom( item );
237 if ( result && !deferUpdate )
238 {
239 //update all positions
241 update();
242 }
243 return result;
244}
245
246QgsLayoutItem *QgsLayout::itemByUuid( const QString &uuid, bool includeTemplateUuids ) const
247{
248 QList<QgsLayoutItem *> itemList;
249 layoutItems( itemList );
250 for ( QgsLayoutItem *item : std::as_const( itemList ) )
251 {
252 if ( item->uuid() == uuid )
253 return item;
254 else if ( includeTemplateUuids && item->mTemplateUuid == uuid )
255 return item;
256 }
257
258 return nullptr;
259}
260
261QgsLayoutItem *QgsLayout::itemByTemplateUuid( const QString &uuid ) const
262{
263 QList<QgsLayoutItem *> itemList;
264 layoutItems( itemList );
265 for ( QgsLayoutItem *item : std::as_const( itemList ) )
266 {
267 if ( item->mTemplateUuid == uuid )
268 return item;
269 }
270
271 return nullptr;
272}
273
274QgsLayoutItem *QgsLayout::itemById( const QString &id ) const
275{
276 const QList<QGraphicsItem *> itemList = items();
277 for ( QGraphicsItem *item : itemList )
278 {
279 QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item );
280 if ( layoutItem && layoutItem->id() == id )
281 {
282 return layoutItem;
283 }
284 }
285 return nullptr;
286}
287
288QgsLayoutMultiFrame *QgsLayout::multiFrameByUuid( const QString &uuid, bool includeTemplateUuids ) const
289{
290 for ( QgsLayoutMultiFrame *mf : mMultiFrames )
291 {
292 if ( mf->uuid() == uuid )
293 return mf;
294 else if ( includeTemplateUuids && mf->mTemplateUuid == uuid )
295 return mf;
296 }
297
298 return nullptr;
299}
300
301QgsLayoutItem *QgsLayout::layoutItemAt( QPointF position, const bool ignoreLocked ) const
302{
303 return layoutItemAt( position, nullptr, ignoreLocked );
304}
305
306QgsLayoutItem *QgsLayout::layoutItemAt( QPointF position, const QgsLayoutItem *belowItem, const bool ignoreLocked ) const
307{
308 //get a list of items which intersect the specified position, in descending z order
309 const QList<QGraphicsItem *> itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
310
311 bool foundBelowItem = false;
312 for ( QGraphicsItem *graphicsItem : itemList )
313 {
314 QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( graphicsItem );
315 QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( layoutItem );
316 if ( layoutItem && !paperItem )
317 {
318 // If we are not checking for a an item below a specified item, or if we've
319 // already found that item, then we've found our target
320 if ( ( ! belowItem || foundBelowItem ) && ( !ignoreLocked || !layoutItem->isLocked() ) )
321 {
322 return layoutItem;
323 }
324 else
325 {
326 if ( layoutItem == belowItem )
327 {
328 //Target item is next in list
329 foundBelowItem = true;
330 }
331 }
332 }
333 }
334 return nullptr;
335}
336
338{
339 return mRenderContext->measurementConverter().convert( measurement, mUnits ).length();
340}
341
343{
344 return mRenderContext->measurementConverter().convert( size, mUnits ).toQSizeF();
345}
346
348{
349 return mRenderContext->measurementConverter().convert( point, mUnits ).toQPointF();
350}
351
353{
354 return mRenderContext->measurementConverter().convert( QgsLayoutMeasurement( length, mUnits ), unit );
355}
356
358{
359 return mRenderContext->measurementConverter().convert( QgsLayoutSize( size.width(), size.height(), mUnits ), unit );
360}
361
363{
364 return mRenderContext->measurementConverter().convert( QgsLayoutPoint( point.x(), point.y(), mUnits ), unit );
365}
366
368{
369 return *mRenderContext;
370}
371
373{
374 return *mRenderContext;
375}
376
378{
379 return *mReportContext;
380}
381
383{
384 return *mReportContext;
385}
386
388{
389 mGridSettings.loadFromSettings();
390 mPageCollection->redraw();
391}
392
394{
395 return mPageCollection->guides();
396}
397
399{
400 return mPageCollection->guides();
401}
402
404{
408 if ( mReportContext->layer() )
409 context.appendScope( QgsExpressionContextUtils::layerScope( mReportContext->layer() ) );
410
412 return context;
413}
414
415void QgsLayout::setCustomProperty( const QString &key, const QVariant &value )
416{
417 mCustomProperties.setValue( key, value );
418
419 if ( key.startsWith( QLatin1String( "variable" ) ) )
420 emit variablesChanged();
421}
422
423QVariant QgsLayout::customProperty( const QString &key, const QVariant &defaultValue ) const
424{
425 return mCustomProperties.value( key, defaultValue );
426}
427
428void QgsLayout::removeCustomProperty( const QString &key )
429{
430 mCustomProperties.remove( key );
431}
432
434{
435 return mCustomProperties.keys();
436}
437
439{
440 // prefer explicitly set reference map
441 if ( QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( itemByUuid( mWorldFileMapId ) ) )
442 return map;
443
444 // else try to find largest map
445 QList< QgsLayoutItemMap * > maps;
446 layoutItems( maps );
447 QgsLayoutItemMap *largestMap = nullptr;
448 double largestMapArea = 0;
449 for ( QgsLayoutItemMap *map : std::as_const( maps ) )
450 {
451 double area = map->rect().width() * map->rect().height();
452 if ( area > largestMapArea )
453 {
454 largestMapArea = area;
455 largestMap = map;
456 }
457 }
458 return largestMap;
459}
460
462{
463 mWorldFileMapId = map ? map->uuid() : QString();
464 mProject->setDirty( true );
465}
466
468{
469 return mPageCollection.get();
470}
471
473{
474 return mPageCollection.get();
475}
476
477QRectF QgsLayout::layoutBounds( bool ignorePages, double margin ) const
478{
479 //start with an empty rectangle
480 QRectF bounds;
481
482 //add all layout items and pages which are in the layout
483 const auto constItems = items();
484 for ( const QGraphicsItem *item : constItems )
485 {
486 const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
487 if ( !layoutItem )
488 continue;
489
490 bool isPage = layoutItem->type() == QgsLayoutItemRegistry::LayoutPage;
491 if ( !isPage || !ignorePages )
492 {
493 //expand bounds with current item's bounds
494 QRectF itemBounds;
495 if ( isPage )
496 {
497 // for pages we only consider the item's rect - not the bounding rect
498 // as the bounding rect contains extra padding
499 itemBounds = layoutItem->mapToScene( layoutItem->rect() ).boundingRect();
500 }
501 else
502 itemBounds = item->sceneBoundingRect();
503
504 if ( bounds.isValid() )
505 bounds = bounds.united( itemBounds );
506 else
507 bounds = itemBounds;
508 }
509 }
510
511 if ( bounds.isValid() && margin > 0.0 )
512 {
513 //finally, expand bounds out by specified margin of page size
514 double maxWidth = mPageCollection->maximumPageWidth();
515 bounds.adjust( -maxWidth * margin, -maxWidth * margin, maxWidth * margin, maxWidth * margin );
516 }
517
518 return bounds;
519
520}
521
522QRectF QgsLayout::pageItemBounds( int page, bool visibleOnly ) const
523{
524 //start with an empty rectangle
525 QRectF bounds;
526
527 //add all QgsLayoutItems on page
528 const QList<QGraphicsItem *> itemList = items();
529 for ( QGraphicsItem *item : itemList )
530 {
531 const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
532 if ( layoutItem && layoutItem->type() != QgsLayoutItemRegistry::LayoutPage && layoutItem->page() == page )
533 {
534 if ( visibleOnly && !layoutItem->isVisible() )
535 continue;
536
537 //expand bounds with current item's bounds
538 if ( bounds.isValid() )
539 bounds = bounds.united( item->sceneBoundingRect() );
540 else
541 bounds = item->sceneBoundingRect();
542 }
543 }
544
545 return bounds;
546}
547
549{
550 addLayoutItemPrivate( item );
551 QString undoText;
552 if ( QgsLayoutItemAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->itemMetadata( item->type() ) )
553 {
554 undoText = tr( "Create %1" ).arg( metadata->visibleName() );
555 }
556 else
557 {
558 undoText = tr( "Create Item" );
559 }
560 if ( !mUndoStack->isBlocked() )
561 mUndoStack->push( new QgsLayoutItemAddItemCommand( item, undoText ) );
562}
563
565{
566 std::unique_ptr< QgsLayoutItemDeleteUndoCommand > deleteCommand;
567 if ( !mUndoStack->isBlocked() )
568 {
569 mUndoStack->beginMacro( tr( "Delete Items" ) );
570 deleteCommand.reset( new QgsLayoutItemDeleteUndoCommand( item, tr( "Delete Item" ) ) );
571 }
572 removeLayoutItemPrivate( item );
573 if ( deleteCommand )
574 {
575 mUndoStack->push( deleteCommand.release() );
576 mUndoStack->endMacro();
577 }
578}
579
581{
582 if ( !multiFrame )
583 return;
584
585 if ( !mMultiFrames.contains( multiFrame ) )
586 mMultiFrames << multiFrame;
587}
588
590{
591 mMultiFrames.removeAll( multiFrame );
592}
593
594QList<QgsLayoutMultiFrame *> QgsLayout::multiFrames() const
595{
596 return mMultiFrames;
597}
598
599bool QgsLayout::saveAsTemplate( const QString &path, const QgsReadWriteContext &context ) const
600{
601 QFile templateFile( path );
602 if ( !templateFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
603 {
604 return false;
605 }
606
607 QDomDocument saveDocument;
608 QDomElement elem = writeXml( saveDocument, context );
609 saveDocument.appendChild( elem );
610
611 if ( templateFile.write( saveDocument.toByteArray() ) == -1 )
612 return false;
613
614 return true;
615}
616
617QList< QgsLayoutItem * > QgsLayout::loadFromTemplate( const QDomDocument &document, const QgsReadWriteContext &context, bool clearExisting, bool *ok )
618{
619 if ( ok )
620 *ok = false;
621
622 QList< QgsLayoutItem * > result;
623
624 if ( clearExisting )
625 {
626 clear();
627 }
628
629 QDomDocument doc;
630
631 // If this is a 2.x composition template, convert it to a layout template
633 {
634 doc = QgsCompositionConverter::convertCompositionTemplate( document, mProject );
635 }
636 else
637 {
638 doc = document;
639 }
640
641 // remove all uuid attributes since we don't want duplicates UUIDS
642 QDomNodeList itemsNodes = doc.elementsByTagName( QStringLiteral( "LayoutItem" ) );
643 for ( int i = 0; i < itemsNodes.count(); ++i )
644 {
645 QDomNode itemNode = itemsNodes.at( i );
646 if ( itemNode.isElement() )
647 {
648 itemNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
649 }
650 }
651 QDomNodeList multiFrameNodes = doc.elementsByTagName( QStringLiteral( "LayoutMultiFrame" ) );
652 for ( int i = 0; i < multiFrameNodes.count(); ++i )
653 {
654 QDomNode multiFrameNode = multiFrameNodes.at( i );
655 if ( multiFrameNode.isElement() )
656 {
657 multiFrameNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
658 QDomNodeList frameNodes = multiFrameNode.toElement().elementsByTagName( QStringLiteral( "childFrame" ) );
659 QDomNode itemNode = frameNodes.at( i );
660 if ( itemNode.isElement() )
661 {
662 itemNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
663 }
664 }
665 }
666
667 //read general settings
668 if ( clearExisting )
669 {
670 QDomElement layoutElem = doc.documentElement();
671 if ( layoutElem.isNull() )
672 {
673 return result;
674 }
675
676 bool loadOk = readXml( layoutElem, doc, context );
677 if ( !loadOk )
678 {
679 return result;
680 }
681 layoutItems( result );
682 }
683 else
684 {
685 result = addItemsFromXml( doc.documentElement(), doc, context );
686 }
687
688 if ( ok )
689 *ok = true;
690
691 return result;
692}
693
695{
696 return mUndoStack.get();
697}
698
700{
701 return mUndoStack.get();
702}
703
705class QgsLayoutUndoCommand: public QgsAbstractLayoutUndoCommand
706{
707 public:
708
709 QgsLayoutUndoCommand( QgsLayout *layout, const QString &text, int id, QUndoCommand *parent SIP_TRANSFERTHIS = nullptr )
710 : QgsAbstractLayoutUndoCommand( text, id, parent )
711 , mLayout( layout )
712 {}
713
714 protected:
715
716 void saveState( QDomDocument &stateDoc ) const override
717 {
718 stateDoc.clear();
719 QDomElement documentElement = stateDoc.createElement( QStringLiteral( "UndoState" ) );
720 mLayout->writeXmlLayoutSettings( documentElement, stateDoc, QgsReadWriteContext() );
721 stateDoc.appendChild( documentElement );
722 }
723
724 void restoreState( QDomDocument &stateDoc ) override
725 {
726 if ( !mLayout )
727 {
728 return;
729 }
730
731 mLayout->readXmlLayoutSettings( stateDoc.documentElement(), stateDoc, QgsReadWriteContext() );
732 mLayout->project()->setDirty( true );
733 }
734
735 private:
736
737 QgsLayout *mLayout = nullptr;
738};
740
741QgsAbstractLayoutUndoCommand *QgsLayout::createCommand( const QString &text, int id, QUndoCommand *parent )
742{
743 return new QgsLayoutUndoCommand( this, text, id, parent );
744}
745
746QgsLayoutItemGroup *QgsLayout::groupItems( const QList<QgsLayoutItem *> &items )
747{
748 if ( items.size() < 2 )
749 {
750 //not enough items for a group
751 return nullptr;
752 }
753
754 mUndoStack->beginMacro( tr( "Group Items" ) );
755 std::unique_ptr< QgsLayoutItemGroup > itemGroup( new QgsLayoutItemGroup( this ) );
756 for ( QgsLayoutItem *item : items )
757 {
758 itemGroup->addItem( item );
759 }
760 QgsLayoutItemGroup *returnGroup = itemGroup.get();
761 addLayoutItem( itemGroup.release() );
762
763 std::unique_ptr< QgsLayoutItemGroupUndoCommand > c( new QgsLayoutItemGroupUndoCommand( QgsLayoutItemGroupUndoCommand::Grouped, returnGroup, this, tr( "Group Items" ) ) );
764 mUndoStack->push( c.release() );
765 mProject->setDirty( true );
766
767 mUndoStack->endMacro();
768
769 // cppcheck-suppress returnDanglingLifetime
770 return returnGroup;
771}
772
773QList<QgsLayoutItem *> QgsLayout::ungroupItems( QgsLayoutItemGroup *group )
774{
775 QList<QgsLayoutItem *> ungroupedItems;
776 if ( !group )
777 {
778 return ungroupedItems;
779 }
780
781 mUndoStack->beginMacro( tr( "Ungroup Items" ) );
782 // Call this before removing group items so it can keep note
783 // of contents
784 std::unique_ptr< QgsLayoutItemGroupUndoCommand > c( new QgsLayoutItemGroupUndoCommand( QgsLayoutItemGroupUndoCommand::Ungrouped, group, this, tr( "Ungroup Items" ) ) );
785 mUndoStack->push( c.release() );
786
787 mProject->setDirty( true );
788
789 ungroupedItems = group->items();
790 group->removeItems();
791
792 removeLayoutItem( group );
793 mUndoStack->endMacro();
794
795 return ungroupedItems;
796}
797
799{
800 const QList< QGraphicsItem * > constItems = items();
801 for ( const QGraphicsItem *item : constItems )
802 {
803 const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
804 if ( !layoutItem )
805 continue;
806
807 if ( !layoutItem->accept( visitor ) )
808 return false;
809 }
810 return true;
811}
812
814{
815 mUndoStack->blockCommands( true );
816 mPageCollection->beginPageSizeChange();
817 emit refreshed();
818 mPageCollection->reflow();
819 mPageCollection->endPageSizeChange();
820 mUndoStack->blockCommands( false );
821 update();
822}
823
824void QgsLayout::writeXmlLayoutSettings( QDomElement &element, QDomDocument &document, const QgsReadWriteContext & ) const
825{
826 mCustomProperties.writeXml( element, document );
827 element.setAttribute( QStringLiteral( "units" ), QgsUnitTypes::encodeUnit( mUnits ) );
828 element.setAttribute( QStringLiteral( "worldFileMap" ), mWorldFileMapId );
829 element.setAttribute( QStringLiteral( "printResolution" ), mRenderContext->dpi() );
830}
831
832QDomElement QgsLayout::writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const
833{
834 QDomElement element = document.createElement( QStringLiteral( "Layout" ) );
835 auto save = [&]( const QgsLayoutSerializableObject * object )->bool
836 {
837 return object->writeXml( element, document, context );
838 };
839 save( &mSnapper );
840 save( &mGridSettings );
841 save( mPageCollection.get() );
842
843 //save items except paper items and frame items (they are saved with the corresponding multiframe)
844 const QList<QGraphicsItem *> itemList = items();
845 for ( const QGraphicsItem *graphicsItem : itemList )
846 {
847 if ( const QgsLayoutItem *item = dynamic_cast< const QgsLayoutItem *>( graphicsItem ) )
848 {
849 if ( item->type() == QgsLayoutItemRegistry::LayoutPage )
850 continue;
851
852 item->writeXml( element, document, context );
853 }
854 }
855
856 //save multiframes
857 for ( QgsLayoutMultiFrame *mf : mMultiFrames )
858 {
859 if ( mf->frameCount() > 0 )
860 mf->writeXml( element, document, context );
861 }
862
863 writeXmlLayoutSettings( element, document, context );
864 return element;
865}
866
867bool QgsLayout::readXmlLayoutSettings( const QDomElement &layoutElement, const QDomDocument &, const QgsReadWriteContext & )
868{
869 mCustomProperties.readXml( layoutElement );
870 setUnits( QgsUnitTypes::decodeLayoutUnit( layoutElement.attribute( QStringLiteral( "units" ) ) ) );
871 mWorldFileMapId = layoutElement.attribute( QStringLiteral( "worldFileMap" ) );
872 mRenderContext->setDpi( layoutElement.attribute( QStringLiteral( "printResolution" ), QStringLiteral( "300" ) ).toDouble() );
873 emit changed();
874
875 return true;
876}
877
878void QgsLayout::addLayoutItemPrivate( QgsLayoutItem *item )
879{
880 addItem( item );
881 updateBounds();
882 mItemsModel->rebuildZList();
883 connect( item, &QgsLayoutItem::backgroundTaskCountChanged, this, &QgsLayout::itemBackgroundTaskCountChanged );
884 emit itemAdded( item );
885}
886
887void QgsLayout::removeLayoutItemPrivate( QgsLayoutItem *item )
888{
889 mItemsModel->setItemRemoved( item );
890 // small chance that item is still in a scene - the model may have
891 // rejected the removal for some reason. This is probably not necessary,
892 // but can't hurt...
893 if ( item->scene() )
894 removeItem( item );
895#if 0 //TODO
896 emit itemRemoved( item );
897#endif
898 item->cleanup();
899 item->deleteLater();
900}
901
902void QgsLayout::deleteAndRemoveMultiFrames()
903{
904 qDeleteAll( mMultiFrames );
905 mMultiFrames.clear();
906}
907
908QPointF QgsLayout::minPointFromXml( const QDomElement &elem ) const
909{
910 double minX = std::numeric_limits<double>::max();
911 double minY = std::numeric_limits<double>::max();
912 const QDomNodeList itemList = elem.elementsByTagName( QStringLiteral( "LayoutItem" ) );
913 bool found = false;
914 for ( int i = 0; i < itemList.size(); ++i )
915 {
916 const QDomElement currentItemElem = itemList.at( i ).toElement();
917
918 QgsLayoutPoint pos = QgsLayoutPoint::decodePoint( currentItemElem.attribute( QStringLiteral( "position" ) ) );
919 QPointF layoutPoint = convertToLayoutUnits( pos );
920
921 minX = std::min( minX, layoutPoint.x() );
922 minY = std::min( minY, layoutPoint.y() );
923 found = true;
924 }
925 return found ? QPointF( minX, minY ) : QPointF( 0, 0 );
926}
927
928void QgsLayout::updateZValues( const bool addUndoCommands )
929{
930 int counter = mItemsModel->zOrderListSize();
931 const QList<QgsLayoutItem *> zOrderList = mItemsModel->zOrderList();
932
933 if ( addUndoCommands )
934 {
935 mUndoStack->beginMacro( tr( "Change Item Stacking" ) );
936 }
937 for ( QgsLayoutItem *currentItem : zOrderList )
938 {
939 if ( currentItem )
940 {
941 if ( addUndoCommands )
942 {
943 mUndoStack->beginCommand( currentItem, QString() );
944 }
945 currentItem->setZValue( counter );
946 if ( addUndoCommands )
947 {
948 mUndoStack->endCommand();
949 }
950 }
951 --counter;
952 }
953 if ( addUndoCommands )
954 {
955 mUndoStack->endMacro();
956 }
957}
958
959bool QgsLayout::readXml( const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context )
960{
961 if ( layoutElement.nodeName() != QLatin1String( "Layout" ) )
962 {
963 return false;
964 }
965
966 auto restore = [&]( QgsLayoutSerializableObject * object )->bool
967 {
968 return object->readXml( layoutElement, document, context );
969 };
970
971 std::unique_ptr< QgsScopedRuntimeProfile > profile;
972 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
973 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Read layout settings" ), QStringLiteral( "projectload" ) );
974
975 blockSignals( true ); // defer changed signal to end
976 readXmlLayoutSettings( layoutElement, document, context );
977 blockSignals( false );
978
979 if ( profile )
980 profile->switchTask( tr( "Load pages" ) );
981 restore( mPageCollection.get() );
982 if ( profile )
983 profile->switchTask( tr( "Load snapping settings" ) );
984 restore( &mSnapper );
985 if ( profile )
986 profile->switchTask( tr( "Load grid settings" ) );
987 restore( &mGridSettings );
988
989 if ( profile )
990 profile->switchTask( tr( "Restore items" ) );
991 addItemsFromXml( layoutElement, document, context );
992
993 emit changed();
994
995 return true;
996}
997
998QList< QgsLayoutItem * > QgsLayout::addItemsFromXml( const QDomElement &parentElement, const QDomDocument &document, const QgsReadWriteContext &context, QPointF *position, bool pasteInPlace )
999{
1000 QList< QgsLayoutItem * > newItems;
1001 QList< QgsLayoutMultiFrame * > newMultiFrames;
1002
1003 //if we are adding items to a layout which already contains items, we need to make sure
1004 //these items are placed at the top of the layout and that zValues are not duplicated
1005 //so, calculate an offset which needs to be added to the zValue of created items
1006 int zOrderOffset = mItemsModel->zOrderListSize();
1007
1008 QPointF pasteShiftPos;
1009 int pageNumber = -1;
1010 if ( position )
1011 {
1012 //If we are placing items relative to a certain point, then calculate how much we need
1013 //to shift the items by so that they are placed at this point
1014 //First, calculate the minimum position from the xml
1015 QPointF minItemPos = minPointFromXml( parentElement );
1016 //next, calculate how much each item needs to be shifted from its original position
1017 //so that it's placed at the correct relative position
1018 pasteShiftPos = *position - minItemPos;
1019 if ( pasteInPlace )
1020 {
1021 pageNumber = mPageCollection->pageNumberForPoint( *position );
1022 }
1023 }
1024
1025 std::unique_ptr< QgsScopedRuntimeProfile > profile;
1026 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
1027 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Read items" ), QStringLiteral( "projectload" ) );
1028
1029 // multiframes
1030
1031 //TODO - fix this. pasting multiframe frame items has no effect
1032 const QDomNodeList multiFrameList = parentElement.elementsByTagName( QStringLiteral( "LayoutMultiFrame" ) );
1033 for ( int i = 0; i < multiFrameList.size(); ++i )
1034 {
1035 const QDomElement multiFrameElem = multiFrameList.at( i ).toElement();
1036 const int itemType = multiFrameElem.attribute( QStringLiteral( "type" ) ).toInt();
1037
1038 if ( profile )
1039 {
1040 if ( QgsLayoutMultiFrameAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->multiFrameMetadata( itemType ) )
1041 {
1042 profile->switchTask( tr( "Load %1" ).arg( metadata->visibleName() ) );
1043 }
1044 }
1045
1046 std::unique_ptr< QgsLayoutMultiFrame > mf( QgsApplication::layoutItemRegistry()->createMultiFrame( itemType, this ) );
1047 if ( !mf )
1048 {
1049 // e.g. plugin based item which is no longer available
1050 continue;
1051 }
1052 mf->readXml( multiFrameElem, document, context );
1053
1054#if 0 //TODO?
1055 mf->setCreateUndoCommands( true );
1056#endif
1057
1058 QgsLayoutMultiFrame *m = mf.get();
1059 this->addMultiFrame( mf.release() );
1060
1061 //offset z values for frames
1062 //TODO - fix this after fixing multiframe item paste
1063 /*for ( int frameIdx = 0; frameIdx < mf->frameCount(); ++frameIdx )
1064 {
1065 QgsLayoutItemFrame * frame = mf->frame( frameIdx );
1066 frame->setZValue( frame->zValue() + zOrderOffset );
1067
1068 // also need to shift frames according to position/pasteInPlacePt
1069 }*/
1070 newMultiFrames << m;
1071 }
1072
1073 const QDomNodeList layoutItemList = parentElement.childNodes();
1074 for ( int i = 0; i < layoutItemList.size(); ++i )
1075 {
1076 const QDomElement currentItemElem = layoutItemList.at( i ).toElement();
1077 if ( currentItemElem.nodeName() != QLatin1String( "LayoutItem" ) )
1078 continue;
1079
1080 const int itemType = currentItemElem.attribute( QStringLiteral( "type" ) ).toInt();
1081
1082 if ( profile )
1083 {
1084 if ( QgsLayoutItemAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->itemMetadata( itemType ) )
1085 {
1086 profile->switchTask( tr( "Load %1" ).arg( metadata->visibleName() ) );
1087 }
1088 }
1089
1090 std::unique_ptr< QgsLayoutItem > item( QgsApplication::layoutItemRegistry()->createItem( itemType, this ) );
1091 if ( !item )
1092 {
1093 // e.g. plugin based item which is no longer available
1094 continue;
1095 }
1096
1097 item->readXml( currentItemElem, document, context );
1098 if ( position )
1099 {
1100 if ( pasteInPlace )
1101 {
1102 QgsLayoutPoint posOnPage = QgsLayoutPoint::decodePoint( currentItemElem.attribute( QStringLiteral( "positionOnPage" ) ) );
1103 item->attemptMove( posOnPage, true, false, pageNumber );
1104 }
1105 else
1106 {
1107 item->attemptMoveBy( pasteShiftPos.x(), pasteShiftPos.y() );
1108 }
1109 }
1110
1111 // When restoring items on project load saved with QGIS < 3.32, convert HTML-enabled labels into HTML items
1112 if ( !position && QgsProjectVersion( 3, 31, 0 ) > mProject->lastSaveVersion() )
1113 {
1114 if ( QgsLayoutItemLabel *label = qobject_cast<QgsLayoutItemLabel *>( item.get() ) )
1115 {
1116 if ( label->mode() == QgsLayoutItemLabel::ModeHtml )
1117 {
1119 addMultiFrame( html );
1120 newMultiFrames << html;
1121 continue;
1122 }
1123 }
1124 }
1125
1126 QgsLayoutItem *layoutItem = item.get();
1127 addLayoutItem( item.release() );
1128 layoutItem->setZValue( layoutItem->zValue() + zOrderOffset );
1129 newItems << layoutItem;
1130 }
1131
1132 // we now allow items to "post-process", e.g. if they need to setup connections
1133 // to other items in the layout, which may not have existed at the time the
1134 // item's state was restored. E.g. a scalebar may have been restored before the map
1135 // it is linked to
1136 std::unique_ptr< QgsScopedRuntimeProfile > itemProfile;
1137 if ( profile )
1138 {
1139 profile->switchTask( tr( "Finalize restore" ) );
1140 }
1141 for ( QgsLayoutItem *item : std::as_const( newItems ) )
1142 {
1143 if ( profile )
1144 itemProfile = std::make_unique< QgsScopedRuntimeProfile >( item->displayName(), QStringLiteral( "projectload" ) );
1145 item->finalizeRestoreFromXml();
1146 if ( itemProfile )
1147 itemProfile.reset();
1148 }
1149 for ( QgsLayoutMultiFrame *mf : std::as_const( newMultiFrames ) )
1150 {
1151 if ( profile )
1152 itemProfile = std::make_unique< QgsScopedRuntimeProfile >( mf->displayName(), QStringLiteral( "projectload" ) );
1153 mf->finalizeRestoreFromXml();
1154 if ( itemProfile )
1155 itemProfile.reset();
1156 }
1157
1158 for ( QgsLayoutItem *item : std::as_const( newItems ) )
1159 {
1160 item->mTemplateUuid.clear();
1161 }
1162 for ( QgsLayoutMultiFrame *mf : std::as_const( newMultiFrames ) )
1163 {
1164 mf->mTemplateUuid.clear();
1165 }
1166
1167 //Since this function adds items in an order which isn't the z-order, and each item is added to end of
1168 //z order list in turn, it will now be inconsistent with the actual order of items in the scene.
1169 //Make sure z order list matches the actual order of items in the scene.
1170
1171 if ( profile )
1172 profile->switchTask( tr( "Update model" ) );
1173 mItemsModel->rebuildZList();
1174
1175 return newItems;
1176}
1177
1179{
1180 setSceneRect( layoutBounds( false, 0.05 ) );
1181}
1182
1183void QgsLayout::itemBackgroundTaskCountChanged( int count )
1184{
1185 QgsLayoutItem *item = qobject_cast<QgsLayoutItem *>( sender() );
1186 if ( !item )
1187 return;
1188
1189 if ( count > 0 )
1190 mBackgroundTaskCount.insert( item, count );
1191 else
1192 mBackgroundTaskCount.remove( item );
1193
1194 // sum up new count of background tasks
1195 int total = 0;
1196 for ( auto it = mBackgroundTaskCount.constBegin(); it != mBackgroundTaskCount.constEnd(); ++it )
1197 {
1198 total += it.value();
1199 }
1200
1201 emit backgroundTaskCountChanged( total );
1202}
LayoutUnit
Layout measurement units.
Definition: qgis.h:3461
Base class for commands to undo/redo layout and layout object changes.
virtual void saveState(QDomDocument &stateDoc) const =0
Saves the state of the object to the specified stateDoc.
virtual void restoreState(QDomDocument &stateDoc)=0
Restores the state of the object from the specified stateDoc.
static QgsLayoutItemRegistry * layoutItemRegistry()
Returns the application's layout item registry, used for layout item types.
static QgsRuntimeProfiler * profiler()
Returns the application runtime profiler.
static bool isCompositionTemplate(const QDomDocument &document)
Check if the given document is a composition template.
static QDomDocument convertCompositionTemplate(const QDomDocument &document, QgsProject *project)
Convert a composition template document to a layout template.
static QgsExpressionContextScope * layoutScope(const QgsLayout *layout)
Creates a new scope which contains variables and functions relating to a QgsLayout layout.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void loadFromSettings()
Loads grid settings from the application layout settings.
Stores and manages the snap guides used by a layout.
Stores metadata about one layout item class.
A container for grouping several QgsLayoutItems.
void removeItems()
Removes all items from the group (but does not delete them).
QList< QgsLayoutItem * > items() const
Returns a list of items contained by the group.
static QgsLayoutItemHtml * createFromLabel(QgsLayoutItemLabel *label)
Returns a new QgsLayoutItemHtml matching the content and rendering of a given label.
A layout item subclass for text labels.
@ ModeHtml
Label displays rendered HTML content.
Layout graphical items for displaying a map.
Item representing the paper in a layout.
void setPageSize(const QgsLayoutSize &size)
Sets the size of the page.
Base class for graphical items within a QgsLayout.
virtual void cleanup()
Called just before a batch of items are deleted, allowing them to run cleanup tasks.
virtual bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
virtual void setSelected(bool selected)
Sets whether the item should be selected.
bool isLocked() const
Returns true if the item is locked, and cannot be interacted with using the mouse.
int page() const
Returns the page the item is currently on, with the first page returning 0.
virtual void finalizeRestoreFromXml()
Called after all pending items have been restored from XML.
int type() const override
Returns a unique graphics item type identifier.
virtual QString displayName() const
Gets item display name.
virtual QString uuid() const
Returns the item identification string.
QString id() const
Returns the item's ID name.
void backgroundTaskCountChanged(int count)
Emitted whenever the number of background tasks an item is executing changes.
QgsLayoutMeasurement convert(QgsLayoutMeasurement measurement, Qgis::LayoutUnit targetUnits) const
Converts a measurement from one unit to another.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
double length() const
Returns the length of the measurement.
A model for items attached to a layout.
Stores metadata about one layout multiframe class.
Abstract base class for layout items with the ability to distribute the content to several frames (Qg...
A manager for a collection of pages in a layout.
This class provides a method of storing points, consisting of an x and y coordinate,...
static QgsLayoutPoint decodePoint(const QString &string)
Decodes a point from a string.
Stores information relating to the current rendering settings for a layout.
void setDpi(double dpi)
Sets the dpi for outputting the layout.
double dpi() const
Returns the dpi for outputting the layout.
const QgsLayoutMeasurementConverter & measurementConverter() const
Returns the layout measurement converter to be used in the layout.
Stores information relating to the current reporting context for a layout.
QgsVectorLayer * layer() const
Returns the vector layer associated with the layout's context.
An interface for layout objects which can be stored and read from DOM elements.
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
Definition: qgslayoutsize.h:41
Manages snapping grids and preset snap lines in a layout, and handles snapping points to the nearest ...
An undo stack for QgsLayouts.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:50
QgsLayoutItem * itemById(const QString &id) const
Returns a layout item given its id.
Definition: qgslayout.cpp:274
friend class QgsLayoutItemDeleteUndoCommand
Definition: qgslayout.h:773
void removeMultiFrame(QgsLayoutMultiFrame *multiFrame)
Removes a multiFrame from the layout (but does not delete it).
Definition: qgslayout.cpp:589
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for the layout.
Definition: qgslayout.cpp:415
void updateBounds()
Updates the scene bounds of the layout.
Definition: qgslayout.cpp:1178
bool saveAsTemplate(const QString &path, const QgsReadWriteContext &context) const
Saves the layout as a template at the given file path.
Definition: qgslayout.cpp:599
QgsAbstractLayoutUndoCommand * createCommand(const QString &text, int id=0, QUndoCommand *parent=nullptr) override
Creates a new layout undo command with the specified text and parent.
Definition: qgslayout.cpp:741
void initializeDefaults()
Initializes an empty layout, e.g.
Definition: qgslayout.cpp:110
QgsLayoutRenderContext & renderContext()
Returns a reference to the layout's render context, which stores information relating to the current ...
Definition: qgslayout.cpp:367
void removeCustomProperty(const QString &key)
Remove a custom property from the layout.
Definition: qgslayout.cpp:428
QgsLayoutModel * itemsModel()
Returns the items model attached to the layout.
Definition: qgslayout.cpp:145
QgsLayoutPageCollection * pageCollection()
Returns a pointer to the layout's page collection, which stores and manages page items in the layout.
Definition: qgslayout.cpp:467
void variablesChanged()
Emitted whenever the expression variables stored in the layout have been changed.
void layoutItems(QList< T * > &itemList) const
Returns a list of layout items of a specific type.
Definition: qgslayout.h:121
QgsLayoutItem * itemByUuid(const QString &uuid, bool includeTemplateUuids=false) const
Returns the layout item with matching uuid unique identifier, or nullptr if a matching item could not...
Definition: qgslayout.cpp:246
void addMultiFrame(QgsLayoutMultiFrame *multiFrame)
Adds a multiFrame to the layout.
Definition: qgslayout.cpp:580
void setUnits(Qgis::LayoutUnit units)
Sets the native measurement units for the layout.
Definition: qgslayout.h:321
QgsLayoutGuideCollection & guides()
Returns a reference to the layout's guide collection, which manages page snap guides.
Definition: qgslayout.cpp:393
QList< QgsLayoutItem * > ungroupItems(QgsLayoutItemGroup *group)
Ungroups items by removing them from an item group and removing the group from the layout.
Definition: qgslayout.cpp:773
bool moveItemToTop(QgsLayoutItem *item, bool deferUpdate=false)
Raises an item up to the top of the z-order.
Definition: qgslayout.cpp:220
QgsLayoutItemMap * referenceMap() const
Returns the map item which will be used to generate corresponding world files when the layout is expo...
Definition: qgslayout.cpp:438
void changed()
Emitted when properties of the layout change.
bool moveItemToBottom(QgsLayoutItem *item, bool deferUpdate=false)
Lowers an item down to the bottom of the z-order.
Definition: qgslayout.cpp:233
QgsLayoutItemGroup * groupItems(const QList< QgsLayoutItem * > &items)
Creates a new group from a list of layout items and adds the group to the layout.
Definition: qgslayout.cpp:746
QList< QgsLayoutItem * > addItemsFromXml(const QDomElement &parentElement, const QDomDocument &document, const QgsReadWriteContext &context, QPointF *position=nullptr, bool pasteInPlace=false)
Add items from an XML representation to the layout.
Definition: qgslayout.cpp:998
friend class QgsLayoutItemAddItemCommand
Definition: qgslayout.h:772
void reloadSettings()
Refreshes the layout when global layout related options change.
Definition: qgslayout.cpp:387
double convertToLayoutUnits(QgsLayoutMeasurement measurement) const
Converts a measurement into the layout's native units.
Definition: qgslayout.cpp:337
virtual bool readXml(const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context)
Sets the collection's state from a DOM element.
Definition: qgslayout.cpp:959
QStringList customProperties() const
Returns list of keys stored in custom properties for the layout.
Definition: qgslayout.cpp:433
QgsLayout * clone() const
Creates a clone of the layout.
Definition: qgslayout.cpp:91
QgsLayoutItem * layoutItemAt(QPointF position, bool ignoreLocked=false) const
Returns the topmost layout item at a specified position.
Definition: qgslayout.cpp:301
void clear()
Clears the layout.
Definition: qgslayout.cpp:119
~QgsLayout() override
Definition: qgslayout.cpp:58
QgsLayoutItem * itemByTemplateUuid(const QString &uuid) const
Returns the layout item with matching template uuid unique identifier, or nullptr if a matching item ...
Definition: qgslayout.cpp:261
friend class QgsLayoutUndoCommand
Definition: qgslayout.h:775
bool lowerItem(QgsLayoutItem *item, bool deferUpdate=false)
Lowers an item down the z-order.
Definition: qgslayout.cpp:207
QgsLayoutMeasurement convertFromLayoutUnits(double length, Qgis::LayoutUnit unit) const
Converts a length measurement from the layout's native units to a specified target unit.
Definition: qgslayout.cpp:352
friend class QgsLayoutModel
Definition: qgslayout.h:777
QList< QgsLayoutItem * > loadFromTemplate(const QDomDocument &document, const QgsReadWriteContext &context, bool clearExisting=true, bool *ok=nullptr)
Load a layout template document.
Definition: qgslayout.cpp:617
static const QgsSettingsEntryStringList * settingsSearchPathForTemplates
Settings entry search path for templates.
Definition: qgslayout.h:662
bool raiseItem(QgsLayoutItem *item, bool deferUpdate=false)
Raises an item up the z-order.
Definition: qgslayout.cpp:194
QList< QgsLayoutItem * > selectedLayoutItems(bool includeLockedItems=true)
Returns list of selected layout items.
Definition: qgslayout.cpp:150
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from the layout.
Definition: qgslayout.cpp:423
void selectedItemChanged(QgsLayoutItem *selected)
Emitted whenever the selected item changes.
void deselectAll()
Clears any selected items in the layout.
Definition: qgslayout.cpp:177
void setSelectedItem(QgsLayoutItem *item)
Clears any selected items and sets item as the current selection.
Definition: qgslayout.cpp:167
QRectF layoutBounds(bool ignorePages=false, double margin=0.0) const
Calculates the bounds of all non-gui items in the layout.
Definition: qgslayout.cpp:477
void refresh()
Forces the layout, and all items contained within it, to refresh.
Definition: qgslayout.cpp:813
void backgroundTaskCountChanged(int total)
Emitted whenever the total number of background tasks running in items from the layout changes.
void removeLayoutItem(QgsLayoutItem *item)
Removes an item from the layout.
Definition: qgslayout.cpp:564
void refreshed()
Emitted when the layout has been refreshed and items should also be refreshed and updated.
friend class QgsLayoutItemGroupUndoCommand
Definition: qgslayout.h:776
void updateZValues(bool addUndoCommands=true)
Resets the z-values of items based on their position in the internal z order list.
Definition: qgslayout.cpp:928
QgsExpressionContext createExpressionContext() const override
Creates an expression context relating to the layout's current state.
Definition: qgslayout.cpp:403
QgsLayoutReportContext & reportContext()
Returns a reference to the layout's report context, which stores information relating to the current ...
Definition: qgslayout.cpp:377
virtual QDomElement writeXml(QDomDocument &document, const QgsReadWriteContext &context) const
Returns the layout's state encapsulated in a DOM element.
Definition: qgslayout.cpp:832
void setReferenceMap(QgsLayoutItemMap *map)
Sets the map item which will be used to generate corresponding world files when the layout is exporte...
Definition: qgslayout.cpp:461
QList< QgsLayoutMultiFrame * > multiFrames() const
Returns a list of multi frames contained in the layout.
Definition: qgslayout.cpp:594
void addLayoutItem(QgsLayoutItem *item)
Adds an item to the layout.
Definition: qgslayout.cpp:548
QgsLayoutMultiFrame * multiFrameByUuid(const QString &uuid, bool includeTemplateUuids=false) const
Returns the layout multiframe with matching uuid unique identifier, or nullptr if a matching multifra...
Definition: qgslayout.cpp:288
bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
Definition: qgslayout.cpp:798
QgsProject * project() const
The project associated with the layout.
Definition: qgslayout.cpp:140
void itemAdded(QgsLayoutItem *item)
Emitted when an item was added to the layout.
QRectF pageItemBounds(int page, bool visibleOnly=false) const
Returns the bounding box of the items contained on a specified page.
Definition: qgslayout.cpp:522
QgsLayout(QgsProject *project)
Construct a new layout linked to the specified project.
Definition: qgslayout.cpp:44
QgsLayoutUndoStack * undoStack()
Returns a pointer to the layout's undo stack, which manages undo/redo states for the layout and it's ...
Definition: qgslayout.cpp:694
void setValue(const QString &key, const QVariant &value)
Add an entry to the store with the specified key.
QStringList keys() const
Returns a list of all stored keys.
void writeXml(QDomNode &parentNode, QDomDocument &doc) const
Writes the store contents to an XML node.
void remove(const QString &key)
Removes a key (entry) from the store.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Returns the value for the given key.
void readXml(const QDomNode &parentNode, const QString &keyStartsWith=QString())
Read store contents from an XML node.
A class to describe the version of a project.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:107
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:603
QgsProjectVersion lastSaveVersion() const
Returns the QGIS version which the project was last saved using.
Definition: qgsproject.cpp:589
The class is used as a container of context for various read/write operations on other objects.
bool groupIsActive(const QString &group) const
Returns true if the specified group is currently being logged, i.e.
A string list settings entry.
static QgsSettingsTreeNode * sTreeLayout
An interface for classes which can visit style entity (e.g.
static Q_INVOKABLE Qgis::LayoutUnit decodeLayoutUnit(const QString &string, bool *ok=nullptr)
Decodes a layout unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:3914
#define SIP_TRANSFERTHIS
Definition: qgis_sip.h:53