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