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