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