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