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