QGIS API Documentation 3.39.0-Master (47f7b3a4989)
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#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 // If ignoreLocked and item is part of a locked group, return the next item below
332 if ( ignoreLocked && layoutItem->parentGroup() && layoutItem->parentGroup()->isLocked() )
333 {
334 return layoutItemAt( position, layoutItem, ignoreLocked, searchTolerance );
335 }
336
337 return layoutItem;
338 }
339 else
340 {
341 if ( layoutItem == belowItem )
342 {
343 //Target item is next in list
344 foundBelowItem = true;
345 }
346 }
347 }
348 }
349 return nullptr;
350}
351
353{
354 return mRenderContext->measurementConverter().convert( measurement, mUnits ).length();
355}
356
358{
359 return mRenderContext->measurementConverter().convert( size, mUnits ).toQSizeF();
360}
361
363{
364 return mRenderContext->measurementConverter().convert( point, mUnits ).toQPointF();
365}
366
368{
369 return mRenderContext->measurementConverter().convert( QgsLayoutMeasurement( length, mUnits ), unit );
370}
371
373{
374 return mRenderContext->measurementConverter().convert( QgsLayoutSize( size.width(), size.height(), mUnits ), unit );
375}
376
378{
379 return mRenderContext->measurementConverter().convert( QgsLayoutPoint( point.x(), point.y(), mUnits ), unit );
380}
381
383{
384 return *mRenderContext;
385}
386
388{
389 return *mRenderContext;
390}
391
393{
394 return *mReportContext;
395}
396
398{
399 return *mReportContext;
400}
401
403{
404 mGridSettings.loadFromSettings();
405 mPageCollection->redraw();
406}
407
409{
410 return mPageCollection->guides();
411}
412
414{
415 return mPageCollection->guides();
416}
417
419{
423 if ( mReportContext->layer() )
424 context.appendScope( QgsExpressionContextUtils::layerScope( mReportContext->layer() ) );
425
427 return context;
428}
429
430void QgsLayout::setCustomProperty( const QString &key, const QVariant &value )
431{
432 mCustomProperties.setValue( key, value );
433
434 if ( key.startsWith( QLatin1String( "variable" ) ) )
435 emit variablesChanged();
436}
437
438QVariant QgsLayout::customProperty( const QString &key, const QVariant &defaultValue ) const
439{
440 return mCustomProperties.value( key, defaultValue );
441}
442
443void QgsLayout::removeCustomProperty( const QString &key )
444{
445 mCustomProperties.remove( key );
446}
447
449{
450 return mCustomProperties.keys();
451}
452
454{
455 // prefer explicitly set reference map
456 if ( QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( itemByUuid( mWorldFileMapId ) ) )
457 return map;
458
459 // else try to find largest map
460 QList< QgsLayoutItemMap * > maps;
461 layoutItems( maps );
462 QgsLayoutItemMap *largestMap = nullptr;
463 double largestMapArea = 0;
464 for ( QgsLayoutItemMap *map : std::as_const( maps ) )
465 {
466 double area = map->rect().width() * map->rect().height();
467 if ( area > largestMapArea )
468 {
469 largestMapArea = area;
470 largestMap = map;
471 }
472 }
473 return largestMap;
474}
475
477{
478 mWorldFileMapId = map ? map->uuid() : QString();
479 mProject->setDirty( true );
480}
481
483{
484 return mPageCollection.get();
485}
486
488{
489 return mPageCollection.get();
490}
491
492QRectF QgsLayout::layoutBounds( bool ignorePages, double margin ) const
493{
494 //start with an empty rectangle
495 QRectF bounds;
496
497 //add all layout items and pages which are in the layout
498 const auto constItems = items();
499 for ( const QGraphicsItem *item : constItems )
500 {
501 const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
502 if ( !layoutItem )
503 continue;
504
505 bool isPage = layoutItem->type() == QgsLayoutItemRegistry::LayoutPage;
506 if ( !isPage || !ignorePages )
507 {
508 //expand bounds with current item's bounds
509 QRectF itemBounds;
510 if ( isPage )
511 {
512 // for pages we only consider the item's rect - not the bounding rect
513 // as the bounding rect contains extra padding
514 itemBounds = layoutItem->mapToScene( layoutItem->rect() ).boundingRect();
515 }
516 else
517 itemBounds = item->sceneBoundingRect();
518
519 if ( bounds.isValid() )
520 bounds = bounds.united( itemBounds );
521 else
522 bounds = itemBounds;
523 }
524 }
525
526 if ( bounds.isValid() && margin > 0.0 )
527 {
528 //finally, expand bounds out by specified margin of page size
529 double maxWidth = mPageCollection->maximumPageWidth();
530 bounds.adjust( -maxWidth * margin, -maxWidth * margin, maxWidth * margin, maxWidth * margin );
531 }
532
533 return bounds;
534
535}
536
537QRectF QgsLayout::pageItemBounds( int page, bool visibleOnly ) const
538{
539 //start with an empty rectangle
540 QRectF bounds;
541
542 //add all QgsLayoutItems on page
543 const QList<QGraphicsItem *> itemList = items();
544 for ( QGraphicsItem *item : itemList )
545 {
546 const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
547 if ( layoutItem && layoutItem->type() != QgsLayoutItemRegistry::LayoutPage && layoutItem->page() == page )
548 {
549 if ( visibleOnly && !layoutItem->isVisible() )
550 continue;
551
552 //expand bounds with current item's bounds
553 if ( bounds.isValid() )
554 bounds = bounds.united( item->sceneBoundingRect() );
555 else
556 bounds = item->sceneBoundingRect();
557 }
558 }
559
560 return bounds;
561}
562
564{
565 addLayoutItemPrivate( item );
566 QString undoText;
567 if ( QgsLayoutItemAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->itemMetadata( item->type() ) )
568 {
569 undoText = tr( "Create %1" ).arg( metadata->visibleName() );
570 }
571 else
572 {
573 undoText = tr( "Create Item" );
574 }
575 if ( !mUndoStack->isBlocked() )
576 mUndoStack->push( new QgsLayoutItemAddItemCommand( item, undoText ) );
577}
578
580{
581 std::unique_ptr< QgsLayoutItemDeleteUndoCommand > deleteCommand;
582 if ( !mUndoStack->isBlocked() )
583 {
584 mUndoStack->beginMacro( tr( "Delete Items" ) );
585 deleteCommand.reset( new QgsLayoutItemDeleteUndoCommand( item, tr( "Delete Item" ) ) );
586 }
587 removeLayoutItemPrivate( item );
588 if ( deleteCommand )
589 {
590 mUndoStack->push( deleteCommand.release() );
591 mUndoStack->endMacro();
592 }
593}
594
596{
597 if ( !multiFrame )
598 return;
599
600 if ( !mMultiFrames.contains( multiFrame ) )
601 mMultiFrames << multiFrame;
602}
603
605{
606 mMultiFrames.removeAll( multiFrame );
607}
608
609QList<QgsLayoutMultiFrame *> QgsLayout::multiFrames() const
610{
611 return mMultiFrames;
612}
613
614bool QgsLayout::saveAsTemplate( const QString &path, const QgsReadWriteContext &context ) const
615{
616 QFile templateFile( path );
617 if ( !templateFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
618 {
619 return false;
620 }
621
622 QDomDocument saveDocument;
623 QDomElement elem = writeXml( saveDocument, context );
624 saveDocument.appendChild( elem );
625
626 if ( templateFile.write( saveDocument.toByteArray() ) == -1 )
627 return false;
628
629 return true;
630}
631
632QList< QgsLayoutItem * > QgsLayout::loadFromTemplate( const QDomDocument &document, const QgsReadWriteContext &context, bool clearExisting, bool *ok )
633{
634 if ( ok )
635 *ok = false;
636
637 QList< QgsLayoutItem * > result;
638
639 if ( clearExisting )
640 {
641 clear();
642 }
643
644 QDomDocument doc;
645
646 // If this is a 2.x composition template, convert it to a layout template
648 {
649 doc = QgsCompositionConverter::convertCompositionTemplate( document, mProject );
650 }
651 else
652 {
653 doc = document;
654 }
655
656 // remove all uuid attributes since we don't want duplicates UUIDS
657 QDomNodeList itemsNodes = doc.elementsByTagName( QStringLiteral( "LayoutItem" ) );
658 for ( int i = 0; i < itemsNodes.count(); ++i )
659 {
660 QDomNode itemNode = itemsNodes.at( i );
661 if ( itemNode.isElement() )
662 {
663 itemNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
664 }
665 }
666 QDomNodeList multiFrameNodes = doc.elementsByTagName( QStringLiteral( "LayoutMultiFrame" ) );
667 for ( int i = 0; i < multiFrameNodes.count(); ++i )
668 {
669 QDomNode multiFrameNode = multiFrameNodes.at( i );
670 if ( multiFrameNode.isElement() )
671 {
672 multiFrameNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
673 QDomNodeList frameNodes = multiFrameNode.toElement().elementsByTagName( QStringLiteral( "childFrame" ) );
674 QDomNode itemNode = frameNodes.at( i );
675 if ( itemNode.isElement() )
676 {
677 itemNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
678 }
679 }
680 }
681
682 //read general settings
683 if ( clearExisting )
684 {
685 QDomElement layoutElem = doc.documentElement();
686 if ( layoutElem.isNull() )
687 {
688 return result;
689 }
690
691 bool loadOk = readXml( layoutElem, doc, context );
692 if ( !loadOk )
693 {
694 return result;
695 }
696 layoutItems( result );
697 }
698 else
699 {
700 result = addItemsFromXml( doc.documentElement(), doc, context );
701 }
702
703 if ( ok )
704 *ok = true;
705
706 return result;
707}
708
710{
711 return mUndoStack.get();
712}
713
715{
716 return mUndoStack.get();
717}
718
720class QgsLayoutUndoCommand: public QgsAbstractLayoutUndoCommand
721{
722 public:
723
724 QgsLayoutUndoCommand( QgsLayout *layout, const QString &text, int id, QUndoCommand *parent SIP_TRANSFERTHIS = nullptr )
725 : QgsAbstractLayoutUndoCommand( text, id, parent )
726 , mLayout( layout )
727 {}
728
729 protected:
730
731 void saveState( QDomDocument &stateDoc ) const override
732 {
733 stateDoc.clear();
734 QDomElement documentElement = stateDoc.createElement( QStringLiteral( "UndoState" ) );
735 mLayout->writeXmlLayoutSettings( documentElement, stateDoc, QgsReadWriteContext() );
736 stateDoc.appendChild( documentElement );
737 }
738
739 void restoreState( QDomDocument &stateDoc ) override
740 {
741 if ( !mLayout )
742 {
743 return;
744 }
745
746 mLayout->readXmlLayoutSettings( stateDoc.documentElement(), stateDoc, QgsReadWriteContext() );
747 mLayout->project()->setDirty( true );
748 }
749
750 private:
751
752 QgsLayout *mLayout = nullptr;
753};
755
756QgsAbstractLayoutUndoCommand *QgsLayout::createCommand( const QString &text, int id, QUndoCommand *parent )
757{
758 return new QgsLayoutUndoCommand( this, text, id, parent );
759}
760
761QgsLayoutItemGroup *QgsLayout::groupItems( const QList<QgsLayoutItem *> &items )
762{
763 if ( items.size() < 2 )
764 {
765 //not enough items for a group
766 return nullptr;
767 }
768
769 mUndoStack->beginMacro( tr( "Group Items" ) );
770 std::unique_ptr< QgsLayoutItemGroup > itemGroup( new QgsLayoutItemGroup( this ) );
771 for ( QgsLayoutItem *item : items )
772 {
773 itemGroup->addItem( item );
774 }
775 QgsLayoutItemGroup *returnGroup = itemGroup.get();
776 addLayoutItem( itemGroup.release() );
777
778 std::unique_ptr< QgsLayoutItemGroupUndoCommand > c( new QgsLayoutItemGroupUndoCommand( QgsLayoutItemGroupUndoCommand::Grouped, returnGroup, this, tr( "Group Items" ) ) );
779 mUndoStack->push( c.release() );
780 mProject->setDirty( true );
781
782 mUndoStack->endMacro();
783
784 // cppcheck-suppress returnDanglingLifetime
785 return returnGroup;
786}
787
788QList<QgsLayoutItem *> QgsLayout::ungroupItems( QgsLayoutItemGroup *group )
789{
790 QList<QgsLayoutItem *> ungroupedItems;
791 if ( !group )
792 {
793 return ungroupedItems;
794 }
795
796 mUndoStack->beginMacro( tr( "Ungroup Items" ) );
797 // Call this before removing group items so it can keep note
798 // of contents
799 std::unique_ptr< QgsLayoutItemGroupUndoCommand > c( new QgsLayoutItemGroupUndoCommand( QgsLayoutItemGroupUndoCommand::Ungrouped, group, this, tr( "Ungroup Items" ) ) );
800 mUndoStack->push( c.release() );
801
802 mProject->setDirty( true );
803
804 ungroupedItems = group->items();
805 group->removeItems();
806
807 removeLayoutItem( group );
808 mUndoStack->endMacro();
809
810 return ungroupedItems;
811}
812
814{
815 const QList< QGraphicsItem * > constItems = items();
816 for ( const QGraphicsItem *item : constItems )
817 {
818 const QgsLayoutItem *layoutItem = dynamic_cast<const QgsLayoutItem *>( item );
819 if ( !layoutItem )
820 continue;
821
822 if ( !layoutItem->accept( visitor ) )
823 return false;
824 }
825 return true;
826}
827
829{
830 mUndoStack->blockCommands( true );
831 mPageCollection->beginPageSizeChange();
832 emit refreshed();
833 mPageCollection->reflow();
834 mPageCollection->endPageSizeChange();
835 mUndoStack->blockCommands( false );
836 update();
837}
838
839void QgsLayout::writeXmlLayoutSettings( QDomElement &element, QDomDocument &document, const QgsReadWriteContext & ) const
840{
841 mCustomProperties.writeXml( element, document );
842 element.setAttribute( QStringLiteral( "units" ), QgsUnitTypes::encodeUnit( mUnits ) );
843 element.setAttribute( QStringLiteral( "worldFileMap" ), mWorldFileMapId );
844 element.setAttribute( QStringLiteral( "printResolution" ), mRenderContext->dpi() );
845}
846
847QDomElement QgsLayout::writeXml( QDomDocument &document, const QgsReadWriteContext &context ) const
848{
849 QDomElement element = document.createElement( QStringLiteral( "Layout" ) );
850 auto save = [&]( const QgsLayoutSerializableObject * object )->bool
851 {
852 return object->writeXml( element, document, context );
853 };
854 save( &mSnapper );
855 save( &mGridSettings );
856 save( mPageCollection.get() );
857
858 //save items except paper items and frame items (they are saved with the corresponding multiframe)
859 const QList<QGraphicsItem *> itemList = items();
860 for ( const QGraphicsItem *graphicsItem : itemList )
861 {
862 if ( const QgsLayoutItem *item = dynamic_cast< const QgsLayoutItem *>( graphicsItem ) )
863 {
864 if ( item->type() == QgsLayoutItemRegistry::LayoutPage )
865 continue;
866
867 item->writeXml( element, document, context );
868 }
869 }
870
871 //save multiframes
872 for ( QgsLayoutMultiFrame *mf : mMultiFrames )
873 {
874 if ( mf->frameCount() > 0 )
875 mf->writeXml( element, document, context );
876 }
877
878 writeXmlLayoutSettings( element, document, context );
879 return element;
880}
881
882bool QgsLayout::readXmlLayoutSettings( const QDomElement &layoutElement, const QDomDocument &, const QgsReadWriteContext & )
883{
884 mCustomProperties.readXml( layoutElement );
885 setUnits( QgsUnitTypes::decodeLayoutUnit( layoutElement.attribute( QStringLiteral( "units" ) ) ) );
886 mWorldFileMapId = layoutElement.attribute( QStringLiteral( "worldFileMap" ) );
887 mRenderContext->setDpi( layoutElement.attribute( QStringLiteral( "printResolution" ), QStringLiteral( "300" ) ).toDouble() );
888 emit changed();
889
890 return true;
891}
892
893void QgsLayout::addLayoutItemPrivate( QgsLayoutItem *item )
894{
895 addItem( item );
896 updateBounds();
897 mItemsModel->rebuildZList();
898 connect( item, &QgsLayoutItem::backgroundTaskCountChanged, this, &QgsLayout::itemBackgroundTaskCountChanged );
899 emit itemAdded( item );
900}
901
902void QgsLayout::removeLayoutItemPrivate( QgsLayoutItem *item )
903{
904 mItemsModel->setItemRemoved( item );
905 // small chance that item is still in a scene - the model may have
906 // rejected the removal for some reason. This is probably not necessary,
907 // but can't hurt...
908 if ( item->scene() )
909 removeItem( item );
910#if 0 //TODO
911 emit itemRemoved( item );
912#endif
913 item->cleanup();
914 item->deleteLater();
915}
916
917void QgsLayout::deleteAndRemoveMultiFrames()
918{
919 qDeleteAll( mMultiFrames );
920 mMultiFrames.clear();
921}
922
923QPointF QgsLayout::minPointFromXml( const QDomElement &elem ) const
924{
925 double minX = std::numeric_limits<double>::max();
926 double minY = std::numeric_limits<double>::max();
927 const QDomNodeList itemList = elem.elementsByTagName( QStringLiteral( "LayoutItem" ) );
928 bool found = false;
929 for ( int i = 0; i < itemList.size(); ++i )
930 {
931 const QDomElement currentItemElem = itemList.at( i ).toElement();
932
933 QgsLayoutPoint pos = QgsLayoutPoint::decodePoint( currentItemElem.attribute( QStringLiteral( "position" ) ) );
934 QPointF layoutPoint = convertToLayoutUnits( pos );
935
936 minX = std::min( minX, layoutPoint.x() );
937 minY = std::min( minY, layoutPoint.y() );
938 found = true;
939 }
940 return found ? QPointF( minX, minY ) : QPointF( 0, 0 );
941}
942
943void QgsLayout::updateZValues( const bool addUndoCommands )
944{
945 int counter = mItemsModel->zOrderListSize();
946 const QList<QgsLayoutItem *> zOrderList = mItemsModel->zOrderList();
947
948 if ( addUndoCommands )
949 {
950 mUndoStack->beginMacro( tr( "Change Item Stacking" ) );
951 }
952 for ( QgsLayoutItem *currentItem : zOrderList )
953 {
954 if ( currentItem )
955 {
956 if ( addUndoCommands )
957 {
958 mUndoStack->beginCommand( currentItem, QString() );
959 }
960 currentItem->setZValue( counter );
961 if ( addUndoCommands )
962 {
963 mUndoStack->endCommand();
964 }
965 }
966 --counter;
967 }
968 if ( addUndoCommands )
969 {
970 mUndoStack->endMacro();
971 }
972}
973
974bool QgsLayout::readXml( const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context )
975{
976 if ( layoutElement.nodeName() != QLatin1String( "Layout" ) )
977 {
978 return false;
979 }
980
981 auto restore = [&]( QgsLayoutSerializableObject * object )->bool
982 {
983 return object->readXml( layoutElement, document, context );
984 };
985
986 std::unique_ptr< QgsScopedRuntimeProfile > profile;
987 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
988 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Read layout settings" ), QStringLiteral( "projectload" ) );
989
990 blockSignals( true ); // defer changed signal to end
991 readXmlLayoutSettings( layoutElement, document, context );
992 blockSignals( false );
993
994 if ( profile )
995 profile->switchTask( tr( "Load pages" ) );
996 restore( mPageCollection.get() );
997 if ( profile )
998 profile->switchTask( tr( "Load snapping settings" ) );
999 restore( &mSnapper );
1000 if ( profile )
1001 profile->switchTask( tr( "Load grid settings" ) );
1002 restore( &mGridSettings );
1003
1004 if ( profile )
1005 profile->switchTask( tr( "Restore items" ) );
1006 addItemsFromXml( layoutElement, document, context );
1007
1008 emit changed();
1009
1010 return true;
1011}
1012
1013QList< QgsLayoutItem * > QgsLayout::addItemsFromXml( const QDomElement &parentElement, const QDomDocument &document, const QgsReadWriteContext &context, QPointF *position, bool pasteInPlace )
1014{
1015 QList< QgsLayoutItem * > newItems;
1016 QList< QgsLayoutMultiFrame * > newMultiFrames;
1017
1018 //if we are adding items to a layout which already contains items, we need to make sure
1019 //these items are placed at the top of the layout and that zValues are not duplicated
1020 //so, calculate an offset which needs to be added to the zValue of created items
1021 int zOrderOffset = mItemsModel->zOrderListSize();
1022
1023 QPointF pasteShiftPos;
1024 int pageNumber = -1;
1025 if ( position )
1026 {
1027 //If we are placing items relative to a certain point, then calculate how much we need
1028 //to shift the items by so that they are placed at this point
1029 //First, calculate the minimum position from the xml
1030 QPointF minItemPos = minPointFromXml( parentElement );
1031 //next, calculate how much each item needs to be shifted from its original position
1032 //so that it's placed at the correct relative position
1033 pasteShiftPos = *position - minItemPos;
1034 if ( pasteInPlace )
1035 {
1036 pageNumber = mPageCollection->pageNumberForPoint( *position );
1037 }
1038 }
1039
1040 std::unique_ptr< QgsScopedRuntimeProfile > profile;
1041 if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
1042 profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Read items" ), QStringLiteral( "projectload" ) );
1043
1044 // multiframes
1045
1046 //TODO - fix this. pasting multiframe frame items has no effect
1047 const QDomNodeList multiFrameList = parentElement.elementsByTagName( QStringLiteral( "LayoutMultiFrame" ) );
1048 for ( int i = 0; i < multiFrameList.size(); ++i )
1049 {
1050 const QDomElement multiFrameElem = multiFrameList.at( i ).toElement();
1051 const int itemType = multiFrameElem.attribute( QStringLiteral( "type" ) ).toInt();
1052
1053 if ( profile )
1054 {
1055 if ( QgsLayoutMultiFrameAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->multiFrameMetadata( itemType ) )
1056 {
1057 profile->switchTask( tr( "Load %1" ).arg( metadata->visibleName() ) );
1058 }
1059 }
1060
1061 std::unique_ptr< QgsLayoutMultiFrame > mf( QgsApplication::layoutItemRegistry()->createMultiFrame( itemType, this ) );
1062 if ( !mf )
1063 {
1064 // e.g. plugin based item which is no longer available
1065 continue;
1066 }
1067 mf->readXml( multiFrameElem, document, context );
1068
1069#if 0 //TODO?
1070 mf->setCreateUndoCommands( true );
1071#endif
1072
1073 QgsLayoutMultiFrame *m = mf.get();
1074 this->addMultiFrame( mf.release() );
1075
1076 //offset z values for frames
1077 //TODO - fix this after fixing multiframe item paste
1078 /*for ( int frameIdx = 0; frameIdx < mf->frameCount(); ++frameIdx )
1079 {
1080 QgsLayoutItemFrame * frame = mf->frame( frameIdx );
1081 frame->setZValue( frame->zValue() + zOrderOffset );
1082
1083 // also need to shift frames according to position/pasteInPlacePt
1084 }*/
1085 newMultiFrames << m;
1086 }
1087
1088 const QDomNodeList layoutItemList = parentElement.childNodes();
1089 for ( int i = 0; i < layoutItemList.size(); ++i )
1090 {
1091 const QDomElement currentItemElem = layoutItemList.at( i ).toElement();
1092 if ( currentItemElem.nodeName() != QLatin1String( "LayoutItem" ) )
1093 continue;
1094
1095 const int itemType = currentItemElem.attribute( QStringLiteral( "type" ) ).toInt();
1096
1097 if ( profile )
1098 {
1099 if ( QgsLayoutItemAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->itemMetadata( itemType ) )
1100 {
1101 profile->switchTask( tr( "Load %1" ).arg( metadata->visibleName() ) );
1102 }
1103 }
1104
1105 std::unique_ptr< QgsLayoutItem > item( QgsApplication::layoutItemRegistry()->createItem( itemType, this ) );
1106 if ( !item )
1107 {
1108 // e.g. plugin based item which is no longer available
1109 continue;
1110 }
1111
1112 item->readXml( currentItemElem, document, context );
1113 if ( position )
1114 {
1115 if ( pasteInPlace )
1116 {
1117 QgsLayoutPoint posOnPage = QgsLayoutPoint::decodePoint( currentItemElem.attribute( QStringLiteral( "positionOnPage" ) ) );
1118 item->attemptMove( posOnPage, true, false, pageNumber );
1119 }
1120 else
1121 {
1122 item->attemptMoveBy( pasteShiftPos.x(), pasteShiftPos.y() );
1123 }
1124 }
1125
1126 // When restoring items on project load saved with QGIS < 3.32, convert HTML-enabled labels into HTML items
1127 if ( !position && QgsProjectVersion( 3, 31, 0 ) > mProject->lastSaveVersion() )
1128 {
1129 if ( QgsLayoutItemLabel *label = qobject_cast<QgsLayoutItemLabel *>( item.get() ) )
1130 {
1131 if ( label->mode() == QgsLayoutItemLabel::ModeHtml )
1132 {
1133 QgsTextFormat textFormat = label->textFormat();
1134 if ( textFormat.lineHeightUnit() == Qgis::RenderUnit::Percentage )
1135 {
1136 // The line-height property handles height differently in webkit, adjust accordingly
1137 textFormat.setLineHeight( textFormat.lineHeight() + 0.22 );
1138 label->setTextFormat( textFormat );
1139 }
1141 addMultiFrame( html );
1142 if ( item->isGroupMember() )
1143 {
1144 QgsLayoutItemGroup *group = item->parentGroup();
1145 QList<QgsLayoutItem *> groupItems = group->items();
1146 groupItems.removeAll( item.get() );
1147 group->removeItems();
1148 for ( QgsLayoutItem *groupItem : std::as_const( groupItems ) )
1149 {
1150 group->addItem( groupItem );
1151 }
1152 group->addItem( html->frame( 0 ) );
1153 }
1154 newMultiFrames << html;
1155 continue;
1156 }
1157 }
1158 }
1159
1160 QgsLayoutItem *layoutItem = item.get();
1161 addLayoutItem( item.release() );
1162 layoutItem->setZValue( layoutItem->zValue() + zOrderOffset );
1163 newItems << layoutItem;
1164 }
1165
1166 // we now allow items to "post-process", e.g. if they need to setup connections
1167 // to other items in the layout, which may not have existed at the time the
1168 // item's state was restored. E.g. a scalebar may have been restored before the map
1169 // it is linked to
1170 std::unique_ptr< QgsScopedRuntimeProfile > itemProfile;
1171 if ( profile )
1172 {
1173 profile->switchTask( tr( "Finalize restore" ) );
1174 }
1175 for ( QgsLayoutItem *item : std::as_const( newItems ) )
1176 {
1177 if ( profile )
1178 itemProfile = std::make_unique< QgsScopedRuntimeProfile >( item->displayName(), QStringLiteral( "projectload" ) );
1179 item->finalizeRestoreFromXml();
1180 if ( itemProfile )
1181 itemProfile.reset();
1182 }
1183 for ( QgsLayoutMultiFrame *mf : std::as_const( newMultiFrames ) )
1184 {
1185 if ( profile )
1186 itemProfile = std::make_unique< QgsScopedRuntimeProfile >( mf->displayName(), QStringLiteral( "projectload" ) );
1187 mf->finalizeRestoreFromXml();
1188 if ( itemProfile )
1189 itemProfile.reset();
1190 }
1191
1192 for ( QgsLayoutItem *item : std::as_const( newItems ) )
1193 {
1194 item->mTemplateUuid.clear();
1195 }
1196 for ( QgsLayoutMultiFrame *mf : std::as_const( newMultiFrames ) )
1197 {
1198 mf->mTemplateUuid.clear();
1199 }
1200
1201 //Since this function adds items in an order which isn't the z-order, and each item is added to end of
1202 //z order list in turn, it will now be inconsistent with the actual order of items in the scene.
1203 //Make sure z order list matches the actual order of items in the scene.
1204
1205 if ( profile )
1206 profile->switchTask( tr( "Update model" ) );
1207 mItemsModel->rebuildZList();
1208
1209 return newItems;
1210}
1211
1213{
1214 setSceneRect( layoutBounds( false, 0.05 ) );
1215}
1216
1217void QgsLayout::itemBackgroundTaskCountChanged( int count )
1218{
1219 QgsLayoutItem *item = qobject_cast<QgsLayoutItem *>( sender() );
1220 if ( !item )
1221 return;
1222
1223 if ( count > 0 )
1224 mBackgroundTaskCount.insert( item, count );
1225 else
1226 mBackgroundTaskCount.remove( item );
1227
1228 // sum up new count of background tasks
1229 int total = 0;
1230 for ( auto it = mBackgroundTaskCount.constBegin(); it != mBackgroundTaskCount.constEnd(); ++it )
1231 {
1232 total += it.value();
1233 }
1234
1235 emit backgroundTaskCountChanged( total );
1236}
LayoutUnit
Layout measurement units.
Definition qgis.h:4514
@ 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...
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.
friend class QgsLayoutItemDeleteUndoCommand
Definition qgslayout.h:774
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: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...
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:322
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.
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:773
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.
Definition qgslayout.cpp:92
void clear()
Clears the layout.
~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 ...
friend class QgsLayoutUndoCommand
Definition qgslayout.h:776
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:778
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:663
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.
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.
QgsExpressionContext createExpressionContext() const override
Creates an expression context relating to the layout's current state.
QgsLayoutReportContext & reportContext()
Returns a reference to the layout's report context, which stores information relating to the current ...
virtual QDomElement writeXml(QDomDocument &document, const QgsReadWriteContext &context) const
Returns the layout's state encapsulated in a DOM element.
void setReferenceMap(QgsLayoutItemMap *map)
Sets the map item which will be used to generate corresponding world files when the layout is exporte...
QList< QgsLayoutMultiFrame * > multiFrames() const
Returns a list of multi frames contained in the layout.
void addLayoutItem(QgsLayoutItem *item)
Adds an item to the layout.
QgsLayoutMultiFrame * multiFrameByUuid(const QString &uuid, bool includeTemplateUuids=false) const
Returns the layout multiframe with matching uuid unique identifier, or nullptr if a matching multifra...
bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
QgsProject * project() const
The project associated with the layout.
void itemAdded(QgsLayoutItem *item)
Emitted when an item was added to the layout.
QRectF pageItemBounds(int page, bool visibleOnly=false) const
Returns the bounding box of the items contained on a specified page.
QgsLayout(QgsProject *project)
Construct a new layout linked to the specified project.
Definition qgslayout.cpp:45
QgsLayoutUndoStack * undoStack()
Returns a pointer to the layout's undo stack, which manages undo/redo states for the layout and it's ...
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).
QgsProjectVersion lastSaveVersion() const
Returns the QGIS version which the project was last saved using.
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.
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:5369
#define SIP_TRANSFERTHIS
Definition qgis_sip.h:53