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