QGIS API Documentation 4.1.0-Master (467af3bbe65)
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
53 = new QgsSettingsEntryStringList( u"search-paths-for-templates"_s, QgsSettingsTree::sTreeLayout, QStringList(), QObject::tr( "Search path for templates" ) );
54
56 = new QgsSettingsEntryString( u"default-font"_s, QgsSettingsTree::sTreeLayout, QString(), QObject::tr( "Default font family for new layout items" ) );
57
59 = new QgsSettingsEntryString( u"default-north-arrow"_s, QgsSettingsTree::sTreeLayout, u":/images/north_arrows/layout_default_north_arrow.svg"_s, QObject::tr( "Default north arrow SVG path" ) );
60
62 : mProject( project )
63 , mRenderContext( new QgsLayoutRenderContext( this ) )
64 , mReportContext( new QgsLayoutReportContext( this ) )
65 , mSnapper( QgsLayoutSnapper( this ) )
66 , mGridSettings( this )
67 , mPageCollection( new QgsLayoutPageCollection( this ) )
68 , mUndoStack( new QgsLayoutUndoStack( this ) )
69{
70 // just to make sure - this should be the default, but maybe it'll change in some future Qt version...
71 setBackgroundBrush( Qt::NoBrush );
72 mItemsModel = std::make_unique<QgsLayoutModel>( this );
73}
74
76{
77 // no need for undo commands when we're destroying the layout
78 mUndoStack->blockCommands( true );
79
80 deleteAndRemoveMultiFrames();
81
82 // make sure that all layout items are removed before
83 // this class is deconstructed - to avoid segfaults
84 // when layout items access in destructor layout that isn't valid anymore
85
86 // since deletion of some item types (e.g. groups) trigger deletion
87 // of other items, we have to do this careful, one at a time...
88 QList<QGraphicsItem *> itemList = items();
89 bool deleted = true;
90 while ( deleted )
91 {
92 deleted = false;
93 for ( QGraphicsItem *item : std::as_const( itemList ) )
94 {
95 if ( dynamic_cast< QgsLayoutItem * >( item ) && !dynamic_cast< QgsLayoutItemPage *>( item ) )
96 {
97 delete item;
98 deleted = true;
99 break;
100 }
101 }
102 itemList = items();
103 }
104
105 mItemsModel.reset(); // manually delete, so we can control order of destruction
106}
107
109{
110 QDomDocument currentDoc;
111
112 QgsReadWriteContext context;
113 QDomElement elem = writeXml( currentDoc, context );
114 currentDoc.appendChild( elem );
115
116 auto newLayout = std::make_unique< QgsLayout >( mProject );
117 bool ok = false;
118 newLayout->loadFromTemplate( currentDoc, context, true, &ok );
119 if ( !ok )
120 {
121 return nullptr;
122 }
123
124 return newLayout.release();
125}
126
128{
129 // default to a A4 landscape page
130 QgsLayoutItemPage *page = new QgsLayoutItemPage( this );
132 mPageCollection->addPage( page );
133 mUndoStack->stack()->clear();
134}
135
137{
138 deleteAndRemoveMultiFrames();
139
140 //delete all non paper items
141 const QList<QGraphicsItem *> itemList = items();
142 for ( QGraphicsItem *item : itemList )
143 {
144 QgsLayoutItem *cItem = dynamic_cast<QgsLayoutItem *>( item );
145 QgsLayoutItemPage *pItem = dynamic_cast<QgsLayoutItemPage *>( item );
146 if ( cItem && !pItem )
147 {
148 removeLayoutItemPrivate( cItem );
149 }
150 }
151 mItemsModel->clear();
152
153 mPageCollection->clear();
154 mUndoStack->stack()->clear();
155}
156
158{
159 return mProject;
160}
161
163{
164 return mItemsModel.get();
165}
166
167QList<QgsLayoutItem *> QgsLayout::selectedLayoutItems( const bool includeLockedItems )
168{
169 QList<QgsLayoutItem *> layoutItemList;
170
171 const QList<QGraphicsItem *> graphicsItemList = selectedItems();
172 for ( QGraphicsItem *item : graphicsItemList )
173 {
174 QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item );
175 if ( layoutItem && ( includeLockedItems || !layoutItem->isLocked() ) )
176 {
177 layoutItemList.push_back( layoutItem );
178 }
179 }
180
181 return layoutItemList;
182}
183
185{
186 whileBlocking( this )->deselectAll();
187 if ( item )
188 {
189 item->setSelected( true );
190 }
191 emit selectedItemChanged( item );
192}
193
195{
196 //we can't use QGraphicsScene::clearSelection, as that emits no signals
197 //and we don't know which items are being deselected
198 //accordingly, we can't inform the layout model of selection changes
199 //instead, do the clear selection manually...
200 const QList<QGraphicsItem *> selectedItemList = selectedItems();
201 for ( QGraphicsItem *item : selectedItemList )
202 {
203 if ( QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item ) )
204 {
205 layoutItem->setSelected( false );
206 }
207 }
208 emit selectedItemChanged( nullptr );
209}
210
211bool QgsLayout::raiseItem( QgsLayoutItem *item, bool deferUpdate )
212{
213 //model handles reordering items
214 bool result = mItemsModel->reorderItemUp( item );
215 if ( result && !deferUpdate )
216 {
217 //update all positions
219 update();
220 }
221 return result;
222}
223
224bool QgsLayout::lowerItem( QgsLayoutItem *item, bool deferUpdate )
225{
226 //model handles reordering items
227 bool result = mItemsModel->reorderItemDown( item );
228 if ( result && !deferUpdate )
229 {
230 //update all positions
232 update();
233 }
234 return result;
235}
236
237bool QgsLayout::moveItemToTop( QgsLayoutItem *item, bool deferUpdate )
238{
239 //model handles reordering items
240 bool result = mItemsModel->reorderItemToTop( item );
241 if ( result && !deferUpdate )
242 {
243 //update all positions
245 update();
246 }
247 return result;
248}
249
250bool QgsLayout::moveItemToBottom( QgsLayoutItem *item, bool deferUpdate )
251{
252 //model handles reordering items
253 bool result = mItemsModel->reorderItemToBottom( item );
254 if ( result && !deferUpdate )
255 {
256 //update all positions
258 update();
259 }
260 return result;
261}
262
263QgsLayoutItem *QgsLayout::itemByUuid( const QString &uuid, bool includeTemplateUuids ) const
264{
265 QList<QgsLayoutItem *> itemList;
266 layoutItems( itemList );
267 for ( QgsLayoutItem *item : std::as_const( itemList ) )
268 {
269 if ( item->uuid() == uuid )
270 return item;
271 else if ( includeTemplateUuids && item->mTemplateUuid == uuid )
272 return item;
273 }
274
275 return nullptr;
276}
277
278QgsLayoutItem *QgsLayout::itemByTemplateUuid( const QString &uuid ) const
279{
280 QList<QgsLayoutItem *> itemList;
281 layoutItems( itemList );
282 for ( QgsLayoutItem *item : std::as_const( itemList ) )
283 {
284 if ( item->mTemplateUuid == uuid )
285 return item;
286 }
287
288 return nullptr;
289}
290
291QgsLayoutItem *QgsLayout::itemById( const QString &id ) const
292{
293 const QList<QGraphicsItem *> itemList = items();
294 for ( QGraphicsItem *item : itemList )
295 {
296 QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item );
297 if ( layoutItem && layoutItem->id() == id )
298 {
299 return layoutItem;
300 }
301 }
302 return nullptr;
303}
304
305QgsLayoutMultiFrame *QgsLayout::multiFrameByUuid( const QString &uuid, bool includeTemplateUuids ) const
306{
307 for ( QgsLayoutMultiFrame *mf : mMultiFrames )
308 {
309 if ( mf->uuid() == uuid )
310 return mf;
311 else if ( includeTemplateUuids && mf->mTemplateUuid == uuid )
312 return mf;
313 }
314
315 return nullptr;
316}
317
318QgsLayoutItem *QgsLayout::layoutItemAt( QPointF position, const bool ignoreLocked, double searchTolerance ) const
319{
320 return layoutItemAt( position, nullptr, ignoreLocked, searchTolerance );
321}
322
323QgsLayoutItem *QgsLayout::layoutItemAt( QPointF position, const QgsLayoutItem *belowItem, const bool ignoreLocked, double searchTolerance ) const
324{
325 //get a list of items which intersect the specified position, in descending z order
326 QList<QGraphicsItem *> itemList;
327 if ( searchTolerance == 0 )
328 {
329 itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
330 }
331 else
332 {
333 itemList = items( QRectF( position.x() - searchTolerance, position.y() - searchTolerance, 2 * searchTolerance, 2 * searchTolerance ), Qt::IntersectsItemShape, Qt::DescendingOrder );
334 }
335
336 bool foundBelowItem = false;
337 for ( QGraphicsItem *graphicsItem : std::as_const( itemList ) )
338 {
339 QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( graphicsItem );
340 QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( layoutItem );
341 if ( layoutItem && !paperItem )
342 {
343 // If we are not checking for a an item below a specified item, or if we've
344 // already found that item, then we've found our target
345 if ( ( !belowItem || foundBelowItem ) && ( !ignoreLocked || !layoutItem->isLocked() ) )
346 {
347 // If ignoreLocked and item is part of a locked group, return the next item below
348 if ( ignoreLocked && layoutItem->parentGroup() && layoutItem->parentGroup()->isLocked() )
349 {
350 return layoutItemAt( position, layoutItem, ignoreLocked, searchTolerance );
351 }
352
353 return layoutItem;
354 }
355 else
356 {
357 if ( layoutItem == belowItem )
358 {
359 //Target item is next in list
360 foundBelowItem = true;
361 }
362 }
363 }
364 }
365 return nullptr;
366}
367
369{
370 return mRenderContext->measurementConverter().convert( measurement, mUnits ).length();
371}
372
374{
375 return mRenderContext->measurementConverter().convert( size, mUnits ).toQSizeF();
376}
377
379{
380 return mRenderContext->measurementConverter().convert( point, mUnits ).toQPointF();
381}
382
384{
385 return mRenderContext->measurementConverter().convert( QgsLayoutMeasurement( length, mUnits ), unit );
386}
387
389{
390 return mRenderContext->measurementConverter().convert( QgsLayoutSize( size.width(), size.height(), mUnits ), unit );
391}
392
394{
395 return mRenderContext->measurementConverter().convert( QgsLayoutPoint( point.x(), point.y(), mUnits ), unit );
396}
397
399{
400 return *mRenderContext;
401}
402
404{
405 return *mRenderContext;
406}
407
409{
410 return *mReportContext;
411}
412
414{
415 return *mReportContext;
416}
417
419{
420 mGridSettings.loadFromSettings();
421 mPageCollection->redraw();
422}
423
425{
426 return mPageCollection->guides();
427}
428
430{
431 return mPageCollection->guides();
432}
433
435{
439 if ( mReportContext->layer() )
440 context.appendScope( QgsExpressionContextUtils::layerScope( mReportContext->layer() ) );
441
443 return context;
444}
445
446void QgsLayout::setCustomProperty( const QString &key, const QVariant &value )
447{
448 mCustomProperties.setValue( key, value );
449
450 if ( key.startsWith( "variable"_L1 ) )
451 emit variablesChanged();
452}
453
454QVariant QgsLayout::customProperty( const QString &key, const QVariant &defaultValue ) const
455{
456 return mCustomProperties.value( key, defaultValue );
457}
458
459void QgsLayout::removeCustomProperty( const QString &key )
460{
461 mCustomProperties.remove( key );
462}
463
465{
466 return mCustomProperties.keys();
467}
468
470{
471 // prefer explicitly set reference map
472 if ( QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( itemByUuid( mWorldFileMapId ) ) )
473 return map;
474
475 // else try to find largest map
476 QList< QgsLayoutItemMap * > maps;
477 layoutItems( maps );
478 QgsLayoutItemMap *largestMap = nullptr;
479 double largestMapArea = 0;
480 for ( QgsLayoutItemMap *map : std::as_const( maps ) )
481 {
482 double area = map->rect().width() * map->rect().height();
483 if ( area > largestMapArea )
484 {
485 largestMapArea = area;
486 largestMap = map;
487 }
488 }
489 return largestMap;
490}
491
493{
494 mWorldFileMapId = map ? map->uuid() : QString();
495 mProject->setDirty( true );
496}
497
499{
500 return mPageCollection.get();
501}
502
504{
505 return mPageCollection.get();
506}
507
508QRectF QgsLayout::layoutBounds( bool ignorePages, double margin ) const
509{
510 //start with an empty rectangle
511 QRectF bounds;
512
513 //add all layout items and pages which are in the layout
514 const auto constItems = items();
515 for ( const QGraphicsItem *item : constItems )
516 {
517 const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
518 if ( !layoutItem )
519 continue;
520
521 bool isPage = layoutItem->type() == QgsLayoutItemRegistry::LayoutPage;
522 if ( !isPage || !ignorePages )
523 {
524 //expand bounds with current item's bounds
525 QRectF itemBounds;
526 if ( isPage )
527 {
528 // for pages we only consider the item's rect - not the bounding rect
529 // as the bounding rect contains extra padding
530 itemBounds = layoutItem->mapToScene( layoutItem->rect() ).boundingRect();
531 }
532 else
533 itemBounds = item->sceneBoundingRect();
534
535 if ( bounds.isValid() )
536 bounds = bounds.united( itemBounds );
537 else
538 bounds = itemBounds;
539 }
540 }
541
542 if ( bounds.isValid() && margin > 0.0 )
543 {
544 //finally, expand bounds out by specified margin of page size
545 double maxWidth = mPageCollection->maximumPageWidth();
546 bounds.adjust( -maxWidth * margin, -maxWidth * margin, maxWidth * margin, maxWidth * margin );
547 }
548
549 return bounds;
550}
551
552QRectF QgsLayout::pageItemBounds( int page, bool visibleOnly ) const
553{
554 //start with an empty rectangle
555 QRectF bounds;
556
557 //add all QgsLayoutItems on page
558 const QList<QGraphicsItem *> itemList = items();
559 for ( QGraphicsItem *item : itemList )
560 {
561 const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
562 if ( layoutItem && layoutItem->type() != QgsLayoutItemRegistry::LayoutPage && layoutItem->page() == page )
563 {
564 if ( visibleOnly && !layoutItem->isVisible() )
565 continue;
566
567 //expand bounds with current item's bounds
568 if ( bounds.isValid() )
569 bounds = bounds.united( item->sceneBoundingRect() );
570 else
571 bounds = item->sceneBoundingRect();
572 }
573 }
574
575 return bounds;
576}
577
579{
580 addLayoutItemPrivate( item );
581 QString undoText;
582 if ( QgsLayoutItemAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->itemMetadata( item->type() ) )
583 {
584 undoText = tr( "Create %1" ).arg( metadata->visibleName() );
585 }
586 else
587 {
588 undoText = tr( "Create Item" );
589 }
590 if ( !mUndoStack->isBlocked() )
591 mUndoStack->push( new QgsLayoutItemAddItemCommand( item, undoText ) );
592}
593
595{
596 std::unique_ptr< QgsLayoutItemDeleteUndoCommand > deleteCommand;
597 if ( !mUndoStack->isBlocked() )
598 {
599 mUndoStack->beginMacro( tr( "Delete Items" ) );
600 deleteCommand = std::make_unique<QgsLayoutItemDeleteUndoCommand>( item, tr( "Delete Item" ) );
601 }
602 removeLayoutItemPrivate( item );
603 if ( deleteCommand )
604 {
605 mUndoStack->push( deleteCommand.release() );
606 mUndoStack->endMacro();
607 }
608}
609
611{
612 if ( !multiFrame )
613 return;
614
615 if ( !mMultiFrames.contains( multiFrame ) )
616 mMultiFrames << multiFrame;
617}
618
620{
621 mMultiFrames.removeAll( multiFrame );
622}
623
624QList<QgsLayoutMultiFrame *> QgsLayout::multiFrames() const
625{
626 return mMultiFrames;
627}
628
629bool QgsLayout::saveAsTemplate( const QString &path, const QgsReadWriteContext &context ) const
630{
631 QFile templateFile( path );
632 if ( !templateFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
633 {
634 return false;
635 }
636
637 QDomDocument saveDocument;
638 QDomElement elem = writeXml( saveDocument, context );
639 saveDocument.appendChild( elem );
640
641 if ( templateFile.write( saveDocument.toByteArray() ) == -1 )
642 return false;
643
644 return true;
645}
646
647QList< QgsLayoutItem * > QgsLayout::loadFromTemplate( const QDomDocument &document, const QgsReadWriteContext &context, bool clearExisting, bool *ok )
648{
649 if ( ok )
650 *ok = false;
651
652 QList< QgsLayoutItem * > result;
653
654 if ( clearExisting )
655 {
656 clear();
657 }
658
659 QDomDocument doc;
660
661 // If this is a 2.x composition template, convert it to a layout template
663 {
664 doc = QgsCompositionConverter::convertCompositionTemplate( document, mProject );
665 }
666 else
667 {
668 doc = document;
669 }
670
671 // remove all uuid attributes since we don't want duplicates UUIDS
672 QDomNodeList itemsNodes = doc.elementsByTagName( u"LayoutItem"_s );
673 for ( int i = 0; i < itemsNodes.count(); ++i )
674 {
675 QDomNode itemNode = itemsNodes.at( i );
676 if ( itemNode.isElement() )
677 {
678 itemNode.toElement().removeAttribute( u"uuid"_s );
679 }
680 }
681 QDomNodeList multiFrameNodes = doc.elementsByTagName( u"LayoutMultiFrame"_s );
682 for ( int i = 0; i < multiFrameNodes.count(); ++i )
683 {
684 QDomNode multiFrameNode = multiFrameNodes.at( i );
685 if ( multiFrameNode.isElement() )
686 {
687 multiFrameNode.toElement().removeAttribute( u"uuid"_s );
688 QDomNodeList frameNodes = multiFrameNode.toElement().elementsByTagName( u"childFrame"_s );
689 QDomNode itemNode = frameNodes.at( i );
690 if ( itemNode.isElement() )
691 {
692 itemNode.toElement().removeAttribute( u"uuid"_s );
693 }
694 }
695 }
696
697 //read general settings
698 if ( clearExisting )
699 {
700 QDomElement layoutElem = doc.documentElement();
701 if ( layoutElem.isNull() )
702 {
703 return result;
704 }
705
706 bool loadOk = readXml( layoutElem, doc, context );
707 if ( !loadOk )
708 {
709 return result;
710 }
711 layoutItems( result );
712 }
713 else
714 {
715 result = addItemsFromXml( doc.documentElement(), doc, context );
716 }
717
718 if ( ok )
719 *ok = true;
720
721 return result;
722}
723
725{
726 return mUndoStack.get();
727}
728
730{
731 return mUndoStack.get();
732}
733
735class QgsLayoutUndoCommand : public QgsAbstractLayoutUndoCommand
736{
737 public:
738 QgsLayoutUndoCommand( QgsLayout *layout, const QString &text, int id, QUndoCommand *parent SIP_TRANSFERTHIS = nullptr )
739 : QgsAbstractLayoutUndoCommand( text, id, parent )
740 , mLayout( layout )
741 {}
742
743 protected:
744 void saveState( QDomDocument &stateDoc ) const override
745 {
746 stateDoc.clear();
747 QDomElement documentElement = stateDoc.createElement( u"UndoState"_s );
748 mLayout->writeXmlLayoutSettings( documentElement, stateDoc, QgsReadWriteContext() );
749 stateDoc.appendChild( documentElement );
750 }
751
752 void restoreState( QDomDocument &stateDoc ) override
753 {
754 if ( !mLayout )
755 {
756 return;
757 }
758
759 mLayout->readXmlLayoutSettings( stateDoc.documentElement(), stateDoc, QgsReadWriteContext() );
760 mLayout->project()->setDirty( true );
761 }
762
763 private:
764 QgsLayout *mLayout = nullptr;
765};
767
768QgsAbstractLayoutUndoCommand *QgsLayout::createCommand( const QString &text, int id, QUndoCommand *parent )
769{
770 return new QgsLayoutUndoCommand( this, text, id, parent );
771}
772
773QgsLayoutItemGroup *QgsLayout::groupItems( const QList<QgsLayoutItem *> &items )
774{
775 if ( items.size() < 2 )
776 {
777 //not enough items for a group
778 return nullptr;
779 }
780
781 mUndoStack->beginMacro( tr( "Group Items" ) );
782 auto itemGroup = std::make_unique<QgsLayoutItemGroup>( this );
783 for ( QgsLayoutItem *item : items )
784 {
785 itemGroup->addItem( item );
786 }
787 QgsLayoutItemGroup *returnGroup = itemGroup.get();
788 addLayoutItem( itemGroup.release() );
789
790 auto c = std::make_unique<QgsLayoutItemGroupUndoCommand>( QgsLayoutItemGroupUndoCommand::Grouped, returnGroup, this, tr( "Group Items" ) );
791 mUndoStack->push( c.release() );
792 mProject->setDirty( true );
793
794 mUndoStack->endMacro();
795
796 // cppcheck-suppress returnDanglingLifetime
797 return returnGroup;
798}
799
800QList<QgsLayoutItem *> QgsLayout::ungroupItems( QgsLayoutItemGroup *group )
801{
802 QList<QgsLayoutItem *> ungroupedItems;
803 if ( !group )
804 {
805 return ungroupedItems;
806 }
807
808 mUndoStack->beginMacro( tr( "Ungroup Items" ) );
809 // Call this before removing group items so it can keep note
810 // of contents
811 auto c = std::make_unique<QgsLayoutItemGroupUndoCommand>( QgsLayoutItemGroupUndoCommand::Ungrouped, group, this, tr( "Ungroup Items" ) );
812 mUndoStack->push( c.release() );
813
814 mProject->setDirty( true );
815
816 ungroupedItems = group->items();
817 group->removeItems();
818
819 removeLayoutItem( group );
820 mUndoStack->endMacro();
821
822 return ungroupedItems;
823}
824
826{
827 const QList< QGraphicsItem * > constItems = items();
828 for ( const QGraphicsItem *item : constItems )
829 {
830 const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
831 if ( !layoutItem )
832 continue;
833
834 if ( !layoutItem->accept( visitor ) )
835 return false;
836 }
837 return true;
838}
839
841{
842 mUndoStack->blockCommands( true );
843 mPageCollection->beginPageSizeChange();
844 emit refreshed();
845 mPageCollection->reflow();
846 mPageCollection->endPageSizeChange();
847 mUndoStack->blockCommands( false );
848 update();
849}
850
851void QgsLayout::writeXmlLayoutSettings( QDomElement &element, QDomDocument &document, const QgsReadWriteContext & ) const
852{
853 mCustomProperties.writeXml( element, document );
854 element.setAttribute( u"units"_s, QgsUnitTypes::encodeUnit( mUnits ) );
855 element.setAttribute( u"worldFileMap"_s, mWorldFileMapId );
856 element.setAttribute( u"printResolution"_s, mRenderContext->dpi() );
857}
858
859QDomElement QgsLayout::writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const
860{
861 QDomElement element = document.createElement( u"Layout"_s );
862 auto save = [&]( const QgsLayoutSerializableObject *object ) -> bool { return object->writeXml( element, document, context ); };
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 { return object->readXml( layoutElement, document, context ); };
991
992 std::unique_ptr< QgsScopedRuntimeProfile > profile;
993 if ( QgsApplication::profiler()->groupIsActive( u"projectload"_s ) )
994 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Read layout settings" ), u"projectload"_s );
995
996 blockSignals( true ); // defer changed signal to end
997 readXmlLayoutSettings( layoutElement, document, context );
998 blockSignals( false );
999
1000 if ( profile )
1001 profile->switchTask( tr( "Load pages" ) );
1002 restore( mPageCollection.get() );
1003 if ( profile )
1004 profile->switchTask( tr( "Load snapping settings" ) );
1005 restore( &mSnapper );
1006 if ( profile )
1007 profile->switchTask( tr( "Load grid settings" ) );
1008 restore( &mGridSettings );
1009
1010 if ( profile )
1011 profile->switchTask( tr( "Restore items" ) );
1012 addItemsFromXml( layoutElement, document, context );
1013
1014 emit changed();
1015
1016 return true;
1017}
1018
1019QList< QgsLayoutItem * > QgsLayout::addItemsFromXml( const QDomElement &parentElement, const QDomDocument &document, const QgsReadWriteContext &context, QPointF *position, bool pasteInPlace )
1020{
1021 QList< QgsLayoutItem * > newItems;
1022 QList< QgsLayoutMultiFrame * > newMultiFrames;
1023
1024 //if we are adding items to a layout which already contains items, we need to make sure
1025 //these items are placed at the top of the layout and that zValues are not duplicated
1026 //so, calculate an offset which needs to be added to the zValue of created items
1027 int zOrderOffset = mItemsModel->zOrderListSize();
1028
1029 QPointF pasteShiftPos;
1030 int pageNumber = -1;
1031 if ( position )
1032 {
1033 //If we are placing items relative to a certain point, then calculate how much we need
1034 //to shift the items by so that they are placed at this point
1035 //First, calculate the minimum position from the xml
1036 QPointF minItemPos = minPointFromXml( parentElement );
1037 //next, calculate how much each item needs to be shifted from its original position
1038 //so that it's placed at the correct relative position
1039 pasteShiftPos = *position - minItemPos;
1040 if ( pasteInPlace )
1041 {
1042 pageNumber = mPageCollection->pageNumberForPoint( *position );
1043 }
1044 }
1045
1046 std::unique_ptr< QgsScopedRuntimeProfile > profile;
1047 if ( QgsApplication::profiler()->groupIsActive( u"projectload"_s ) )
1048 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Read items" ), u"projectload"_s );
1049
1050 // multiframes
1051
1052 //TODO - fix this. pasting multiframe frame items has no effect
1053 const QDomNodeList multiFrameList = parentElement.elementsByTagName( u"LayoutMultiFrame"_s );
1054 for ( int i = 0; i < multiFrameList.size(); ++i )
1055 {
1056 const QDomElement multiFrameElem = multiFrameList.at( i ).toElement();
1057 const int itemType = multiFrameElem.attribute( u"type"_s ).toInt();
1058
1059 if ( profile )
1060 {
1061 if ( QgsLayoutMultiFrameAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->multiFrameMetadata( itemType ) )
1062 {
1063 profile->switchTask( tr( "Load %1" ).arg( metadata->visibleName() ) );
1064 }
1065 }
1066
1067 std::unique_ptr< QgsLayoutMultiFrame > mf( QgsApplication::layoutItemRegistry()->createMultiFrame( itemType, this ) );
1068 if ( !mf )
1069 {
1070 // e.g. plugin based item which is no longer available
1071 continue;
1072 }
1073 mf->readXml( multiFrameElem, document, context );
1074
1075#if 0 //TODO?
1076 mf->setCreateUndoCommands( true );
1077#endif
1078
1079 QgsLayoutMultiFrame *m = mf.get();
1080 this->addMultiFrame( mf.release() );
1081
1082 //offset z values for frames
1083 //TODO - fix this after fixing multiframe item paste
1084 /*for ( int frameIdx = 0; frameIdx < mf->frameCount(); ++frameIdx )
1085 {
1086 QgsLayoutItemFrame * frame = mf->frame( frameIdx );
1087 frame->setZValue( frame->zValue() + zOrderOffset );
1088
1089 // also need to shift frames according to position/pasteInPlacePt
1090 }*/
1091 newMultiFrames << m;
1092 }
1093
1094 const QDomNodeList layoutItemList = parentElement.childNodes();
1095 for ( int i = 0; i < layoutItemList.size(); ++i )
1096 {
1097 const QDomElement currentItemElem = layoutItemList.at( i ).toElement();
1098 if ( currentItemElem.nodeName() != "LayoutItem"_L1 )
1099 continue;
1100
1101 const int itemType = currentItemElem.attribute( u"type"_s ).toInt();
1102
1103 if ( profile )
1104 {
1105 if ( QgsLayoutItemAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->itemMetadata( itemType ) )
1106 {
1107 profile->switchTask( tr( "Load %1" ).arg( metadata->visibleName() ) );
1108 }
1109 }
1110
1111 std::unique_ptr< QgsLayoutItem > item( QgsApplication::layoutItemRegistry()->createItem( itemType, this ) );
1112 if ( !item )
1113 {
1114 // e.g. plugin based item which is no longer available
1115 continue;
1116 }
1117
1118 item->readXml( currentItemElem, document, context );
1119 if ( position )
1120 {
1121 if ( pasteInPlace )
1122 {
1123 QgsLayoutPoint posOnPage = QgsLayoutPoint::decodePoint( currentItemElem.attribute( u"positionOnPage"_s ) );
1124 item->attemptMove( posOnPage, true, false, pageNumber );
1125 }
1126 else
1127 {
1128 item->attemptMoveBy( pasteShiftPos.x(), pasteShiftPos.y() );
1129 }
1130 }
1131
1132 // When restoring items on project load saved with QGIS < 3.32, convert HTML-enabled labels into HTML items
1133 if ( !position && QgsProjectVersion( 3, 31, 0 ) > mProject->lastSaveVersion() )
1134 {
1135 if ( QgsLayoutItemLabel *label = qobject_cast<QgsLayoutItemLabel *>( item.get() ) )
1136 {
1137 if ( label->mode() == QgsLayoutItemLabel::ModeHtml )
1138 {
1139 QgsTextFormat textFormat = label->textFormat();
1140 if ( textFormat.lineHeightUnit() == Qgis::RenderUnit::Percentage )
1141 {
1142 // The line-height property handles height differently in webkit, adjust accordingly
1143 textFormat.setLineHeight( textFormat.lineHeight() + 0.22 );
1144 label->setTextFormat( textFormat );
1145 }
1147 addMultiFrame( html );
1148 if ( item->isGroupMember() )
1149 {
1150 if ( QgsLayoutItemGroup *group = item->parentGroup() )
1151 {
1152 QList<QgsLayoutItem *> groupItems = group->items();
1153 groupItems.removeAll( item.get() );
1154 group->removeItems();
1155 for ( QgsLayoutItem *groupItem : std::as_const( groupItems ) )
1156 {
1157 group->addItem( groupItem );
1158 }
1159 group->addItem( html->frame( 0 ) );
1160 }
1161 }
1162 newMultiFrames << html;
1163 continue;
1164 }
1165 }
1166 }
1167
1168 QgsLayoutItem *layoutItem = item.get();
1169 addLayoutItem( item.release() );
1170 layoutItem->setZValue( layoutItem->zValue() + zOrderOffset );
1171 newItems << layoutItem;
1172 }
1173
1174 // we now allow items to "post-process", e.g. if they need to setup connections
1175 // to other items in the layout, which may not have existed at the time the
1176 // item's state was restored. E.g. a scalebar may have been restored before the map
1177 // it is linked to
1178 std::unique_ptr< QgsScopedRuntimeProfile > itemProfile;
1179 if ( profile )
1180 {
1181 profile->switchTask( tr( "Finalize restore" ) );
1182 }
1183 for ( QgsLayoutItem *item : std::as_const( newItems ) )
1184 {
1185 if ( profile )
1186 itemProfile = std::make_unique< QgsScopedRuntimeProfile >( item->displayName(), u"projectload"_s );
1187 item->finalizeRestoreFromXml();
1188 if ( itemProfile )
1189 itemProfile.reset();
1190 }
1191 for ( QgsLayoutMultiFrame *mf : std::as_const( newMultiFrames ) )
1192 {
1193 if ( profile )
1194 itemProfile = std::make_unique< QgsScopedRuntimeProfile >( mf->displayName(), u"projectload"_s );
1195 mf->finalizeRestoreFromXml();
1196 if ( itemProfile )
1197 itemProfile.reset();
1198 }
1199
1200 for ( QgsLayoutItem *item : std::as_const( newItems ) )
1201 {
1202 item->mTemplateUuid.clear();
1203 }
1204 for ( QgsLayoutMultiFrame *mf : std::as_const( newMultiFrames ) )
1205 {
1206 mf->mTemplateUuid.clear();
1207 }
1208
1209 //Since this function adds items in an order which isn't the z-order, and each item is added to end of
1210 //z order list in turn, it will now be inconsistent with the actual order of items in the scene.
1211 //Make sure z order list matches the actual order of items in the scene.
1212
1213 if ( profile )
1214 profile->switchTask( tr( "Update model" ) );
1215 mItemsModel->rebuildZList();
1216
1217 return newItems;
1218}
1219
1221{
1222 setSceneRect( layoutBounds( false, 0.05 ) );
1223}
1224
1225void QgsLayout::itemBackgroundTaskCountChanged( int count )
1226{
1227 QgsLayoutItem *item = qobject_cast<QgsLayoutItem *>( sender() );
1228 if ( !item )
1229 return;
1230
1231 if ( count > 0 )
1232 mBackgroundTaskCount.insert( item, count );
1233 else
1234 mBackgroundTaskCount.remove( item );
1235
1236 // sum up new count of background tasks
1237 int total = 0;
1238 for ( auto it = mBackgroundTaskCount.constBegin(); it != mBackgroundTaskCount.constEnd(); ++it )
1239 {
1240 total += it.value();
1241 }
1242
1243 emit backgroundTaskCountChanged( total );
1244}
LayoutUnit
Layout measurement units.
Definition qgis.h:5459
@ Millimeters
Millimeters.
Definition qgis.h:5460
@ Percentage
Percentage of another measurement (e.g., canvas size, feature size).
Definition qgis.h:5443
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:51
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:789
static const QgsSettingsEntryString * settingsLayoutDefaultNorthArrow
Settings entry for the default north arrow SVG path.
Definition qgslayout.h:674
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:783
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:75
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:786
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:788
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:662
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...
static const QgsSettingsEntryString * settingsLayoutDefaultFont
Settings entry for the default font family used for new layout items.
Definition qgslayout.h:668
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:61
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:113
A container for the context for various read/write operations on objects.
A string list settings entry.
A string 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:6982
#define SIP_TRANSFERTHIS
Definition qgis_sip.h:52